static int vlan_dev_neigh_setup(struct net_device *dev, struct neigh_parms *pa) { struct net_device *real_dev = vlan_dev_priv(dev)->real_dev; const struct net_device_ops *ops = real_dev->netdev_ops; int err = 0; if (netif_device_present(real_dev) && ops->ndo_neigh_setup) err = ops->ndo_neigh_setup(real_dev, pa); return err; }
static struct net_device_stats *au1000_get_stats(struct net_device *dev) { struct au1000_private *aup = (struct au1000_private *) dev->priv; if (au1000_debug > 4) printk("%s: au1000_get_stats: dev=%p\n", dev->name, dev); if (netif_device_present(dev)) { return &aup->stats; } return 0; }
static struct net_device_stats *cp_get_stats(struct net_device *dev) { struct cp_private *cp = netdev_priv(dev); unsigned long flags; /* The chip only need report frame silently dropped. */ spin_lock_irqsave(&cp->lock, flags); if (netif_running(dev) && netif_device_present(dev)) __cp_get_stats(cp); spin_unlock_irqrestore(&cp->lock, flags); return &cp->net_stats; }
static void write_bulk_callback(struct urb *urb) { rtl8150_t *dev; dev = urb->context; if (!dev) return; if (!netif_device_present(dev->netdev)) return; if (urb->status) info("%s: Tx status %d", dev->netdev->name, urb->status); dev->netdev->trans_start = jiffies; netif_wake_queue(dev->netdev); }
static void read_bulk_callback(struct urb *urb) { rtl8150_t *dev; int pkt_len, res; struct sk_buff *skb; struct net_device *netdev; u16 rx_stat; dev = urb->context; if (!dev) { warn("!dev"); return; } netdev = dev->netdev; if (!netif_device_present(netdev)) { warn("netdev is not present"); return; } switch (urb->status) { case 0: break; case -ENOENT: return; case -ETIMEDOUT: warn("need a device reset?.."); goto goon; default: warn("Rx status %d", urb->status); goto goon; } pkt_len = urb->actual_length - 4; rx_stat = le16_to_cpu(*(u16 *) (dev->rx_buff + pkt_len)); if (!(skb = dev_alloc_skb(pkt_len + 2))) goto goon; skb->dev = netdev; skb_reserve(skb, 2); eth_copy_and_sum(skb, dev->rx_buff, pkt_len, 0); skb_put(skb, pkt_len); skb->protocol = eth_type_trans(skb, netdev); netif_rx(skb); dev->stats.rx_packets++; dev->stats.rx_bytes += pkt_len; goon: FILL_BULK_URB(dev->rx_urb, dev->udev, usb_rcvbulkpipe(dev->udev, 1), dev->rx_buff, RTL8150_MAX_MTU, read_bulk_callback, dev); if ((res = usb_submit_urb(dev->rx_urb))) warn("%s: Rx urb submission failed %d", netdev->name, res); }
static struct iw_statistics *orinoco_get_wireless_stats(struct net_device *dev) { struct orinoco_private *priv = ndev_priv(dev); hermes_t *hw = &priv->hw; struct iw_statistics *wstats = &priv->wstats; int err; unsigned long flags; if (!netif_device_present(dev)) { printk(KERN_WARNING "%s: get_wireless_stats() called while device not present\n", dev->name); return NULL; /* FIXME: Can we do better than this? */ } /* If busy, return the old stats. Returning NULL may cause * the interface to disappear from /proc/net/wireless */ if (orinoco_lock(priv, &flags) != 0) return wstats; /* We can't really wait for the tallies inquiry command to * complete, so we just use the previous results and trigger * a new tallies inquiry command for next time - Jean II */ /* FIXME: Really we should wait for the inquiry to come back - * as it is the stats we give don't make a whole lot of sense. * Unfortunately, it's not clear how to do that within the * wireless extensions framework: I think we're in user * context, but a lock seems to be held by the time we get in * here so we're not safe to sleep here. */ hermes_inquire(hw, HERMES_INQ_TALLIES); if (priv->iw_mode == NL80211_IFTYPE_ADHOC) { memset(&wstats->qual, 0, sizeof(wstats->qual)); /* If a spy address is defined, we report stats of the * first spy address - Jean II */ if (SPY_NUMBER(priv)) { wstats->qual.qual = priv->spy_data.spy_stat[0].qual; wstats->qual.level = priv->spy_data.spy_stat[0].level; wstats->qual.noise = priv->spy_data.spy_stat[0].noise; wstats->qual.updated = priv->spy_data.spy_stat[0].updated; } } else { struct { __le16 qual, signal, noise, unused; <<<<<<< HEAD } __packed cq; ======= } __attribute__ ((packed)) cq;
static void netpoll_send_skb(struct netpoll *np, struct sk_buff *skb) { int status = NETDEV_TX_BUSY; unsigned long tries; struct net_device *dev = np->dev; struct netpoll_info *npinfo = np->dev->npinfo; if (!npinfo || !netif_running(dev) || !netif_device_present(dev)) { __kfree_skb(skb); return; } /* don't get messages out of order, and no recursion */ if (skb_queue_len(&npinfo->txq) == 0 && npinfo->poll_owner != smp_processor_id()) { unsigned long flags; local_irq_save(flags); /* try until next clock tick */ for (tries = jiffies_to_usecs(1)/USEC_PER_POLL; tries > 0; --tries) { if (netif_tx_trylock(dev)) { if (!netif_queue_stopped(dev)) status = dev->hard_start_xmit(skb, dev); netif_tx_unlock(dev); if (status == NETDEV_TX_OK) break; } /* tickle device maybe there is some cleanup */ netpoll_poll(np); udelay(USEC_PER_POLL); } local_irq_restore(flags); } if (status != NETDEV_TX_OK) { skb_queue_tail(&npinfo->txq, skb); schedule_delayed_work(&npinfo->tx_work,0); } }
/* Initiate a packet transmission. We use one channel per CPU * (sharing when we have more CPUs than channels). On Falcon, the TX * completion events will be directed back to the CPU that transmitted * the packet, which should be cache-efficient. * * Context: non-blocking. * Note that returning anything other than NETDEV_TX_OK will cause the * OS to free the skb. */ netdev_tx_t efx_hard_start_xmit(struct sk_buff *skb, struct net_device *net_dev) { struct efx_nic *efx = netdev_priv(net_dev); struct efx_tx_queue *tx_queue; unsigned index, type; EFX_WARN_ON_PARANOID(!netif_device_present(net_dev)); index = skb_get_queue_mapping(skb); type = skb->ip_summed == CHECKSUM_PARTIAL ? EFX_TXQ_TYPE_OFFLOAD : 0; if (index >= efx->n_tx_channels) { index -= efx->n_tx_channels; type |= EFX_TXQ_TYPE_HIGHPRI; } tx_queue = efx_get_tx_queue(efx, index, type); return efx_enqueue_skb(tx_queue, skb); }
static void dev_watchdog(struct timer_list *t) { struct net_device *dev = from_timer(dev, t, watchdog_timer); netif_tx_lock(dev); if (!qdisc_tx_is_noop(dev)) { if (netif_device_present(dev) && netif_running(dev) && netif_carrier_ok(dev)) { int some_queue_timedout = 0; unsigned int i; unsigned long trans_start; for (i = 0; i < dev->num_tx_queues; i++) { struct netdev_queue *txq; txq = netdev_get_tx_queue(dev, i); trans_start = txq->trans_start; if (netif_xmit_stopped(txq) && time_after(jiffies, (trans_start + dev->watchdog_timeo))) { some_queue_timedout = 1; txq->trans_timeout++; break; } } if (some_queue_timedout) { WARN_ONCE(1, KERN_INFO "NETDEV WATCHDOG: %s (%s): transmit queue %u timed out\n", dev->name, netdev_drivername(dev), i); dev->netdev_ops->ndo_tx_timeout(dev); } if (!mod_timer(&dev->watchdog_timer, round_jiffies(jiffies + dev->watchdog_timeo))) dev_hold(dev); } } netif_tx_unlock(dev); dev_put(dev); }
static void dev_watchdog(unsigned long arg) { struct net_device *dev = (struct net_device *)arg; netif_tx_lock(dev); if (!qdisc_tx_is_noop(dev)) { if (netif_device_present(dev) && netif_running(dev) && netif_carrier_ok(dev)) { int some_queue_timedout = 0; unsigned int i; unsigned long trans_start; for (i = 0; i < dev->num_tx_queues; i++) { struct netdev_queue *txq; txq = netdev_get_tx_queue(dev, i); /* * old device drivers set dev->trans_start */ trans_start = txq->trans_start ? : dev->trans_start; if (netif_tx_queue_stopped(txq) && time_after(jiffies, (trans_start + dev->watchdog_timeo))) { some_queue_timedout = 1; break; } } if (some_queue_timedout) { char drivername[64]; WARN_ONCE(1, KERN_INFO "NETDEV WATCHDOG: %s (%s): transmit queue %u timed out\n", dev->name, netdev_drivername(dev, drivername, 64), i); dev->netdev_ops->ndo_tx_timeout(dev); } if (!mod_timer(&dev->watchdog_timer, round_jiffies(jiffies + dev->watchdog_timeo))) dev_hold(dev); } }
/* * Main IOCTl dispatcher. * Check the type of IOCTL and call the appropriate wrapper... */ static int wireless_process_ioctl(struct net *net, struct ifreq *ifr, unsigned int cmd) { struct net_device *dev; iw_handler handler; /* Permissions are already checked in dev_ioctl() before calling us. * The copy_to/from_user() of ifr is also dealt with in there */ /* Make sure the device exist */ if ((dev = __dev_get_by_name(net, ifr->ifr_name)) == NULL) return -ENODEV; /* A bunch of special cases, then the generic case... * Note that 'cmd' is already filtered in dev_ioctl() with * (cmd >= SIOCIWFIRST && cmd <= SIOCIWLAST) */ if (cmd == SIOCGIWSTATS) return ioctl_standard_call(dev, ifr, cmd, &iw_handler_get_iwstats); if (cmd == SIOCGIWPRIV && dev->wireless_handlers) return ioctl_standard_call(dev, ifr, cmd, &iw_handler_get_private); /* Basic check */ if (!netif_device_present(dev)) return -ENODEV; /* New driver API : try to find the handler */ handler = get_handler(dev, cmd); if (handler) { /* Standard and private are not the same */ if (cmd < SIOCIWFIRSTPRIV) return ioctl_standard_call(dev, ifr, cmd, handler); else return ioctl_private_call(dev, ifr, cmd, handler); } /* Old driver API : call driver ioctl handler */ if (dev->do_ioctl) return dev->do_ioctl(dev, ifr, cmd); return -EOPNOTSUPP; }
static void __dev_mc_upload(struct net_device *dev) { /* Don't do anything till we up the interface * [dev_open will call this function so the list will * stay sane] */ if (!(dev->flags&IFF_UP)) return; /* * Devices with no set multicast or which have been * detached don't get set. */ if (dev->set_multicast_list == NULL || !netif_device_present(dev)) return; dev->set_multicast_list(dev); }
static void gs_usb_xmit_callback(struct urb *urb) { struct gs_tx_context *txc = urb->context; struct gs_can *dev = txc->dev; struct net_device *netdev = dev->netdev; if (urb->status) netdev_info(netdev, "usb xmit fail %d\n", txc->echo_id); usb_free_coherent(urb->dev, urb->transfer_buffer_length, urb->transfer_buffer, urb->transfer_dma); atomic_dec(&dev->active_tx_urbs); if (!netif_device_present(netdev)) return; if (netif_queue_stopped(netdev)) netif_wake_queue(netdev); }
static void dev_watchdog(unsigned long arg) { struct net_device *dev = (struct net_device *)arg; spin_lock(&dev->xmit_lock); if (dev->qdisc != &noop_qdisc) { if (netif_device_present(dev) && netif_running(dev) && netif_carrier_ok(dev)) { if (netif_queue_stopped(dev) && (jiffies - dev->trans_start) > dev->watchdog_timeo) { printk(KERN_INFO "NETDEV WATCHDOG: %s: transmit timed out\n", dev->name); dev->tx_timeout(dev); } if (!mod_timer(&dev->watchdog_timer, jiffies + dev->watchdog_timeo)) dev_hold(dev); } } spin_unlock(&dev->xmit_lock); dev_put(dev); }
/* * IOCTLs : Extra out-of-band network commands... */ static int kingsun_net_ioctl(struct net_device *netdev, struct ifreq *rq, int cmd) { struct if_irda_req *irq = (struct if_irda_req *) rq; struct kingsun_cb *kingsun = netdev_priv(netdev); int ret = 0; switch (cmd) { case SIOCSBANDWIDTH: /* Set bandwidth */ if (!capable(CAP_NET_ADMIN)) return -EPERM; /* Check if the device is still there */ if (netif_device_present(kingsun->netdev)) /* No observed commands for speed change */ ret = -EOPNOTSUPP; break; case SIOCSMEDIABUSY: /* Set media busy */ if (!capable(CAP_NET_ADMIN)) return -EPERM; /* Check if the IrDA stack is still there */ if (netif_running(kingsun->netdev)) irda_device_set_media_busy(kingsun->netdev, TRUE); break; case SIOCGRECEIVING: /* Only approximately true */ irq->ifr_receiving = kingsun->receiving; break; default: ret = -EOPNOTSUPP; } return ret; }
static int kingsun_net_ioctl(struct net_device *netdev, struct ifreq *rq, int cmd) { struct if_irda_req *irq = (struct if_irda_req *) rq; struct kingsun_cb *kingsun = netdev_priv(netdev); int ret = 0; switch (cmd) { case SIOCSBANDWIDTH: if (!capable(CAP_NET_ADMIN)) return -EPERM; if (netif_device_present(kingsun->netdev)) ret = -EOPNOTSUPP; break; case SIOCSMEDIABUSY: if (!capable(CAP_NET_ADMIN)) return -EPERM; if (netif_running(kingsun->netdev)) irda_device_set_media_busy(kingsun->netdev, TRUE); break; case SIOCGRECEIVING: irq->ifr_receiving = kingsun->receiving; break; default: ret = -EOPNOTSUPP; } return ret; }
/* * callback for bulk IN urb */ static void ems_usb_write_bulk_callback(struct urb *urb) { struct ems_tx_urb_context *context = urb->context; struct ems_usb *dev; struct net_device *netdev; BUG_ON(!context); dev = context->dev; netdev = dev->netdev; /* free up our allocated buffer */ usb_free_coherent(urb->dev, urb->transfer_buffer_length, urb->transfer_buffer, urb->transfer_dma); atomic_dec(&dev->active_tx_urbs); if (!netif_device_present(netdev)) return; if (urb->status) dev_info(netdev->dev.parent, "Tx URB aborted (%d)\n", urb->status); netdev->trans_start = jiffies; /* transmission complete interrupt */ netdev->stats.tx_packets++; netdev->stats.tx_bytes += context->dlc; can_get_echo_skb(netdev, context->echo_index); /* Release context */ context->echo_index = MAX_TX_URBS; if (netif_queue_stopped(netdev)) netif_wake_queue(netdev); }
int vlan_dev_ioctl(struct net_device *dev, struct ifreq *ifr, int cmd) { struct net_device *real_dev = VLAN_DEV_INFO(dev)->real_dev; struct ifreq ifrr; int err = -EOPNOTSUPP; strncpy(ifrr.ifr_name, real_dev->name, IFNAMSIZ); ifrr.ifr_ifru = ifr->ifr_ifru; switch(cmd) { case SIOCGMIIPHY: case SIOCGMIIREG: case SIOCSMIIREG: if (real_dev->do_ioctl && netif_device_present(real_dev)) err = real_dev->do_ioctl(real_dev, &ifrr, cmd); break; } if (!err) ifr->ifr_ifru = ifrr.ifr_ifru; return err; }
int ethtool_ioctl(struct ifreq *ifr){ struct net_device *netdev=__dev_get_by_name(ifr->ifr_name); void *useraddr=(void *)ifr->ifr_data; uint32_t ethcmd; if(!capable(CAP_NET_ADMIN)) return -EPERM; if(!netdev || !netif_device_present(netdev)) return -ENODEV; if(copy_from_user(ðcmd, useraddr, sizeof(ethcmd))) return -EFAULT; switch (ethcmd){ case ETHTOOL_GSET: return ethtool_get_settings(netdev,useraddr); case ETHTOOL_SSET: return ethtool_set_settings(netdev,useraddr); default: return -EOPNOTSUPP; } return -EOPNOTSUPP; }
static int au1000_close(struct net_device *dev) { u32 flags; struct au1000_private *aup = (struct au1000_private *) dev->priv; if (au1000_debug > 4) printk("%s: close: dev=%p\n", dev->name, dev); spin_lock_irqsave(&aup->lock, flags); /* stop the device */ if (netif_device_present(dev)) { netif_stop_queue(dev); } /* disable the interrupt */ free_irq(dev->irq, dev); spin_unlock_irqrestore(&aup->lock, flags); reset_mac(dev); MOD_DEC_USE_COUNT; return 0; }
static void linkwatch_do_dev(struct net_device *dev) { /* * Make sure the above read is complete since it can be * rewritten as soon as we clear the bit below. */ smp_mb__before_atomic(); /* We are about to handle this device, * so new events can be accepted */ clear_bit(__LINK_STATE_LINKWATCH_PENDING, &dev->state); rfc2863_policy(dev); if (dev->flags & IFF_UP && netif_device_present(dev)) { if (netif_carrier_ok(dev)) dev_activate(dev); else dev_deactivate(dev); netdev_state_change(dev); } dev_put(dev); }
static int vlan_dev_ioctl(struct net_device *dev, struct ifreq *ifr, int cmd) { struct net_device *real_dev = vlan_dev_info(dev)->real_dev; const struct net_device_ops *ops = real_dev->netdev_ops; struct ifreq ifrr; int err = -EOPNOTSUPP; strncpy(ifrr.ifr_name, real_dev->name, IFNAMSIZ); ifrr.ifr_ifru = ifr->ifr_ifru; switch (cmd) { case SIOCGMIIPHY: case SIOCGMIIREG: case SIOCSMIIREG: if (netif_device_present(real_dev) && ops->ndo_do_ioctl) err = ops->ndo_do_ioctl(real_dev, &ifrr, cmd); break; } if (!err) ifr->ifr_ifru = ifrr.ifr_ifru; return err; }
int ethtool_ioctl(struct ifreq *ifr) { struct net_device *dev = __dev_get_by_name(ifr->ifr_name); void *useraddr = (void *) ifr->ifr_data; uint32_t ethcmd; /* * XXX: This can be pushed down into the ethtool_* handlers that * need it. Keep existing behaviour for the moment. */ if (!capable(CAP_NET_ADMIN)) return -EPERM; if (!dev || !netif_device_present(dev)) return -ENODEV; if (copy_from_user(ðcmd, useraddr, sizeof (ethcmd))) return -EFAULT; switch (ethcmd) { case ETHTOOL_GSET: return ethtool_get_settings(dev, useraddr); case ETHTOOL_SSET: return ethtool_set_settings(dev, useraddr); case ETHTOOL_GDRVINFO: return ethtool_get_drvinfo(dev, useraddr); case ETHTOOL_GREGS: return ethtool_get_regs(dev, useraddr); case ETHTOOL_GWOL: return ethtool_get_wol(dev, useraddr); case ETHTOOL_SWOL: return ethtool_set_wol(dev, useraddr); case ETHTOOL_GMSGLVL: return ethtool_get_msglevel(dev, useraddr); case ETHTOOL_SMSGLVL: return ethtool_set_msglevel(dev, useraddr); case ETHTOOL_NWAY_RST: return ethtool_nway_reset(dev); case ETHTOOL_GLINK: return ethtool_get_link(dev, useraddr); case ETHTOOL_GEEPROM: return ethtool_get_eeprom(dev, useraddr); case ETHTOOL_SEEPROM: return ethtool_set_eeprom(dev, useraddr); case ETHTOOL_GCOALESCE: return ethtool_get_coalesce(dev, useraddr); case ETHTOOL_SCOALESCE: return ethtool_set_coalesce(dev, useraddr); case ETHTOOL_GRINGPARAM: return ethtool_get_ringparam(dev, useraddr); case ETHTOOL_SRINGPARAM: return ethtool_set_ringparam(dev, useraddr); case ETHTOOL_GPAUSEPARAM: return ethtool_get_pauseparam(dev, useraddr); case ETHTOOL_SPAUSEPARAM: return ethtool_set_pauseparam(dev, useraddr); case ETHTOOL_GRXCSUM: return ethtool_get_rx_csum(dev, useraddr); case ETHTOOL_SRXCSUM: return ethtool_set_rx_csum(dev, useraddr); case ETHTOOL_GTXCSUM: return ethtool_get_tx_csum(dev, useraddr); case ETHTOOL_STXCSUM: return ethtool_set_tx_csum(dev, useraddr); case ETHTOOL_GSG: return ethtool_get_sg(dev, useraddr); case ETHTOOL_SSG: return ethtool_set_sg(dev, useraddr); case ETHTOOL_GTSO: return ethtool_get_tso(dev, useraddr); case ETHTOOL_STSO: return ethtool_set_tso(dev, useraddr); case ETHTOOL_TEST: return ethtool_self_test(dev, useraddr); case ETHTOOL_GSTRINGS: return ethtool_get_strings(dev, useraddr); case ETHTOOL_PHYS_ID: return ethtool_phys_id(dev, useraddr); case ETHTOOL_GSTATS: return ethtool_get_stats(dev, useraddr); default: return -EOPNOTSUPP; } return -EOPNOTSUPP; }
static int rx_submit (struct usbnet *dev, struct urb *urb, gfp_t flags) { struct sk_buff *skb; struct skb_data *entry; int retval = 0; unsigned long lockflags; size_t size = dev->rx_urb_size; if ((skb = alloc_skb (size + NET_IP_ALIGN, flags)) == NULL) { netif_dbg(dev, rx_err, dev->net, "no rx skb\n"); usbnet_defer_kevent (dev, EVENT_RX_MEMORY); usb_free_urb (urb); return -ENOMEM; } skb_reserve (skb, NET_IP_ALIGN); entry = (struct skb_data *) skb->cb; entry->urb = urb; entry->dev = dev; entry->length = 0; usb_fill_bulk_urb (urb, dev->udev, dev->in, skb->data, size, rx_complete, skb); spin_lock_irqsave (&dev->rxq.lock, lockflags); if (netif_running (dev->net) && netif_device_present (dev->net) && !test_bit (EVENT_RX_HALT, &dev->flags) && !test_bit (EVENT_DEV_ASLEEP, &dev->flags)) { switch (retval = usb_submit_urb (urb, GFP_ATOMIC)) { case -EPIPE: usbnet_defer_kevent (dev, EVENT_RX_HALT); break; case -ENOMEM: usbnet_defer_kevent (dev, EVENT_RX_MEMORY); break; case -ENODEV: netif_dbg(dev, ifdown, dev->net, "device gone\n"); netif_device_detach (dev->net); break; case -EHOSTUNREACH: retval = -ENOLINK; break; default: netif_dbg(dev, rx_err, dev->net, "rx submit, %d\n", retval); tasklet_schedule (&dev->bh); break; case 0: __usbnet_queue_skb(&dev->rxq, skb, rx_start); } } else { netif_dbg(dev, ifdown, dev->net, "rx: stopped\n"); retval = -ENOLINK; } spin_unlock_irqrestore (&dev->rxq.lock, lockflags); if (retval) { dev_kfree_skb_any (skb); usb_free_urb (urb); } return retval; }
/* Send close command to device */ static int usb_8dev_cmd_close(struct usb_8dev_priv *priv) { struct usb_8dev_cmd_msg inmsg; struct usb_8dev_cmd_msg outmsg = { .channel = 0, .command = USB_8DEV_CLOSE, .opt1 = 0, .opt2 = 0 }; return usb_8dev_send_cmd(priv, &outmsg, &inmsg); } /* Get firmware and hardware version */ static int usb_8dev_cmd_version(struct usb_8dev_priv *priv, u32 *res) { struct usb_8dev_cmd_msg inmsg; struct usb_8dev_cmd_msg outmsg = { .channel = 0, .command = USB_8DEV_GET_SOFTW_HARDW_VER, .opt1 = 0, .opt2 = 0 }; int err = usb_8dev_send_cmd(priv, &outmsg, &inmsg); if (err) return err; *res = be32_to_cpup((__be32 *)inmsg.data); return err; } /* Set network device mode * * Maybe we should leave this function empty, because the device * set mode variable with open command. */ static int usb_8dev_set_mode(struct net_device *netdev, enum can_mode mode) { struct usb_8dev_priv *priv = netdev_priv(netdev); int err = 0; switch (mode) { case CAN_MODE_START: err = usb_8dev_cmd_open(priv); if (err) netdev_warn(netdev, "couldn't start device"); break; default: return -EOPNOTSUPP; } return err; } /* Read error/status frames */ static void usb_8dev_rx_err_msg(struct usb_8dev_priv *priv, struct usb_8dev_rx_msg *msg) { struct can_frame *cf; struct sk_buff *skb; struct net_device_stats *stats = &priv->netdev->stats; /* Error message: * byte 0: Status * byte 1: bit 7: Receive Passive * byte 1: bit 0-6: Receive Error Counter * byte 2: Transmit Error Counter * byte 3: Always 0 (maybe reserved for future use) */ u8 state = msg->data[0]; u8 rxerr = msg->data[1] & USB_8DEV_RP_MASK; u8 txerr = msg->data[2]; int rx_errors = 0; int tx_errors = 0; skb = alloc_can_err_skb(priv->netdev, &cf); if (!skb) return; switch (state) { case USB_8DEV_STATUSMSG_OK: priv->can.state = CAN_STATE_ERROR_ACTIVE; cf->can_id |= CAN_ERR_PROT; cf->data[2] = CAN_ERR_PROT_ACTIVE; break; case USB_8DEV_STATUSMSG_BUSOFF: priv->can.state = CAN_STATE_BUS_OFF; cf->can_id |= CAN_ERR_BUSOFF; can_bus_off(priv->netdev); break; case USB_8DEV_STATUSMSG_OVERRUN: case USB_8DEV_STATUSMSG_BUSLIGHT: case USB_8DEV_STATUSMSG_BUSHEAVY: cf->can_id |= CAN_ERR_CRTL; break; default: priv->can.state = CAN_STATE_ERROR_WARNING; cf->can_id |= CAN_ERR_PROT | CAN_ERR_BUSERROR; priv->can.can_stats.bus_error++; break; } switch (state) { case USB_8DEV_STATUSMSG_OK: case USB_8DEV_STATUSMSG_BUSOFF: break; case USB_8DEV_STATUSMSG_ACK: cf->can_id |= CAN_ERR_ACK; tx_errors = 1; break; case USB_8DEV_STATUSMSG_CRC: cf->data[2] |= CAN_ERR_PROT_UNSPEC; cf->data[3] |= CAN_ERR_PROT_LOC_CRC_SEQ | CAN_ERR_PROT_LOC_CRC_DEL; rx_errors = 1; break; case USB_8DEV_STATUSMSG_BIT0: cf->data[2] |= CAN_ERR_PROT_BIT0; tx_errors = 1; break; case USB_8DEV_STATUSMSG_BIT1: cf->data[2] |= CAN_ERR_PROT_BIT1; tx_errors = 1; break; case USB_8DEV_STATUSMSG_FORM: cf->data[2] |= CAN_ERR_PROT_FORM; rx_errors = 1; break; case USB_8DEV_STATUSMSG_STUFF: cf->data[2] |= CAN_ERR_PROT_STUFF; rx_errors = 1; break; case USB_8DEV_STATUSMSG_OVERRUN: cf->data[1] = CAN_ERR_CRTL_RX_OVERFLOW; stats->rx_over_errors++; rx_errors = 1; break; case USB_8DEV_STATUSMSG_BUSLIGHT: priv->can.state = CAN_STATE_ERROR_WARNING; cf->data[1] = (txerr > rxerr) ? CAN_ERR_CRTL_TX_WARNING : CAN_ERR_CRTL_RX_WARNING; priv->can.can_stats.error_warning++; break; case USB_8DEV_STATUSMSG_BUSHEAVY: priv->can.state = CAN_STATE_ERROR_PASSIVE; cf->data[1] = (txerr > rxerr) ? CAN_ERR_CRTL_TX_PASSIVE : CAN_ERR_CRTL_RX_PASSIVE; priv->can.can_stats.error_passive++; break; default: netdev_warn(priv->netdev, "Unknown status/error message (%d)\n", state); break; } if (tx_errors) { cf->data[2] |= CAN_ERR_PROT_TX; stats->tx_errors++; } if (rx_errors) stats->rx_errors++; cf->data[6] = txerr; cf->data[7] = rxerr; priv->bec.txerr = txerr; priv->bec.rxerr = rxerr; netif_rx(skb); stats->rx_packets++; stats->rx_bytes += cf->can_dlc; } /* Read data and status frames */ static void usb_8dev_rx_can_msg(struct usb_8dev_priv *priv, struct usb_8dev_rx_msg *msg) { struct can_frame *cf; struct sk_buff *skb; struct net_device_stats *stats = &priv->netdev->stats; if (msg->type == USB_8DEV_TYPE_ERROR_FRAME && msg->flags == USB_8DEV_ERR_FLAG) { usb_8dev_rx_err_msg(priv, msg); } else if (msg->type == USB_8DEV_TYPE_CAN_FRAME) { skb = alloc_can_skb(priv->netdev, &cf); if (!skb) return; cf->can_id = be32_to_cpu(msg->id); cf->can_dlc = get_can_dlc(msg->dlc & 0xF); if (msg->flags & USB_8DEV_EXTID) cf->can_id |= CAN_EFF_FLAG; if (msg->flags & USB_8DEV_RTR) cf->can_id |= CAN_RTR_FLAG; else memcpy(cf->data, msg->data, cf->can_dlc); netif_rx(skb); stats->rx_packets++; stats->rx_bytes += cf->can_dlc; can_led_event(priv->netdev, CAN_LED_EVENT_RX); } else { netdev_warn(priv->netdev, "frame type %d unknown", msg->type); } } /* Callback for reading data from device * * Check urb status, call read function and resubmit urb read operation. */ static void usb_8dev_read_bulk_callback(struct urb *urb) { struct usb_8dev_priv *priv = urb->context; struct net_device *netdev; int retval; int pos = 0; netdev = priv->netdev; if (!netif_device_present(netdev)) return; switch (urb->status) { case 0: /* success */ break; case -ENOENT: case -ESHUTDOWN: return; default: netdev_info(netdev, "Rx URB aborted (%d)\n", urb->status); goto resubmit_urb; } while (pos < urb->actual_length) { struct usb_8dev_rx_msg *msg; if (pos + sizeof(struct usb_8dev_rx_msg) > urb->actual_length) { netdev_err(priv->netdev, "format error\n"); break; } msg = (struct usb_8dev_rx_msg *)(urb->transfer_buffer + pos); usb_8dev_rx_can_msg(priv, msg); pos += sizeof(struct usb_8dev_rx_msg); } resubmit_urb: usb_fill_bulk_urb(urb, priv->udev, usb_rcvbulkpipe(priv->udev, USB_8DEV_ENDP_DATA_RX), urb->transfer_buffer, RX_BUFFER_SIZE, usb_8dev_read_bulk_callback, priv); retval = usb_submit_urb(urb, GFP_ATOMIC); if (retval == -ENODEV) netif_device_detach(netdev); else if (retval) netdev_err(netdev, "failed resubmitting read bulk urb: %d\n", retval); } /* Callback handler for write operations * * Free allocated buffers, check transmit status and * calculate statistic. */ static void usb_8dev_write_bulk_callback(struct urb *urb) { struct usb_8dev_tx_urb_context *context = urb->context; struct usb_8dev_priv *priv; struct net_device *netdev; BUG_ON(!context); priv = context->priv; netdev = priv->netdev; /* free up our allocated buffer */ usb_free_coherent(urb->dev, urb->transfer_buffer_length, urb->transfer_buffer, urb->transfer_dma); atomic_dec(&priv->active_tx_urbs); if (!netif_device_present(netdev)) return; if (urb->status) netdev_info(netdev, "Tx URB aborted (%d)\n", urb->status); netdev->stats.tx_packets++; netdev->stats.tx_bytes += context->dlc; can_get_echo_skb(netdev, context->echo_index); can_led_event(netdev, CAN_LED_EVENT_TX); /* Release context */ context->echo_index = MAX_TX_URBS; netif_wake_queue(netdev); } /* Send data to device */ static netdev_tx_t usb_8dev_start_xmit(struct sk_buff *skb, struct net_device *netdev) { struct usb_8dev_priv *priv = netdev_priv(netdev); struct net_device_stats *stats = &netdev->stats; struct can_frame *cf = (struct can_frame *) skb->data; struct usb_8dev_tx_msg *msg; struct urb *urb; struct usb_8dev_tx_urb_context *context = NULL; u8 *buf; int i, err; size_t size = sizeof(struct usb_8dev_tx_msg); if (can_dropped_invalid_skb(netdev, skb)) return NETDEV_TX_OK; /* create a URB, and a buffer for it, and copy the data to the URB */ urb = usb_alloc_urb(0, GFP_ATOMIC); if (!urb) { netdev_err(netdev, "No memory left for URBs\n"); goto nomem; } buf = usb_alloc_coherent(priv->udev, size, GFP_ATOMIC, &urb->transfer_dma); if (!buf) { netdev_err(netdev, "No memory left for USB buffer\n"); goto nomembuf; } memset(buf, 0, size); msg = (struct usb_8dev_tx_msg *)buf; msg->begin = USB_8DEV_DATA_START; msg->flags = 0x00; if (cf->can_id & CAN_RTR_FLAG) msg->flags |= USB_8DEV_RTR; if (cf->can_id & CAN_EFF_FLAG) msg->flags |= USB_8DEV_EXTID; msg->id = cpu_to_be32(cf->can_id & CAN_ERR_MASK); msg->dlc = cf->can_dlc; memcpy(msg->data, cf->data, cf->can_dlc); msg->end = USB_8DEV_DATA_END; for (i = 0; i < MAX_TX_URBS; i++) { if (priv->tx_contexts[i].echo_index == MAX_TX_URBS) { context = &priv->tx_contexts[i]; break; } } /* May never happen! When this happens we'd more URBs in flight as * allowed (MAX_TX_URBS). */ if (!context) goto nofreecontext; context->priv = priv; context->echo_index = i; context->dlc = cf->can_dlc; usb_fill_bulk_urb(urb, priv->udev, usb_sndbulkpipe(priv->udev, USB_8DEV_ENDP_DATA_TX), buf, size, usb_8dev_write_bulk_callback, context); urb->transfer_flags |= URB_NO_TRANSFER_DMA_MAP; usb_anchor_urb(urb, &priv->tx_submitted); can_put_echo_skb(skb, netdev, context->echo_index); atomic_inc(&priv->active_tx_urbs); err = usb_submit_urb(urb, GFP_ATOMIC); if (unlikely(err)) goto failed; else if (atomic_read(&priv->active_tx_urbs) >= MAX_TX_URBS) /* Slow down tx path */ netif_stop_queue(netdev); /* Release our reference to this URB, the USB core will eventually free * it entirely. */ usb_free_urb(urb); return NETDEV_TX_OK; nofreecontext: usb_free_coherent(priv->udev, size, buf, urb->transfer_dma); usb_free_urb(urb); netdev_warn(netdev, "couldn't find free context"); return NETDEV_TX_BUSY; failed: can_free_echo_skb(netdev, context->echo_index); usb_unanchor_urb(urb); usb_free_coherent(priv->udev, size, buf, urb->transfer_dma); atomic_dec(&priv->active_tx_urbs); if (err == -ENODEV) netif_device_detach(netdev); else netdev_warn(netdev, "failed tx_urb %d\n", err); nomembuf: usb_free_urb(urb); nomem: dev_kfree_skb(skb); stats->tx_dropped++; return NETDEV_TX_OK; } static int usb_8dev_get_berr_counter(const struct net_device *netdev, struct can_berr_counter *bec) { struct usb_8dev_priv *priv = netdev_priv(netdev); bec->txerr = priv->bec.txerr; bec->rxerr = priv->bec.rxerr; return 0; } /* Start USB device */ static int usb_8dev_start(struct usb_8dev_priv *priv) { struct net_device *netdev = priv->netdev; int err, i; for (i = 0; i < MAX_RX_URBS; i++) { struct urb *urb = NULL; u8 *buf; /* create a URB, and a buffer for it */ urb = usb_alloc_urb(0, GFP_KERNEL); if (!urb) { netdev_err(netdev, "No memory left for URBs\n"); err = -ENOMEM; break; } buf = usb_alloc_coherent(priv->udev, RX_BUFFER_SIZE, GFP_KERNEL, &urb->transfer_dma); if (!buf) { netdev_err(netdev, "No memory left for USB buffer\n"); usb_free_urb(urb); err = -ENOMEM; break; } usb_fill_bulk_urb(urb, priv->udev, usb_rcvbulkpipe(priv->udev, USB_8DEV_ENDP_DATA_RX), buf, RX_BUFFER_SIZE, usb_8dev_read_bulk_callback, priv); urb->transfer_flags |= URB_NO_TRANSFER_DMA_MAP; usb_anchor_urb(urb, &priv->rx_submitted); err = usb_submit_urb(urb, GFP_KERNEL); if (err) { usb_unanchor_urb(urb); usb_free_coherent(priv->udev, RX_BUFFER_SIZE, buf, urb->transfer_dma); usb_free_urb(urb); break; } /* Drop reference, USB core will take care of freeing it */ usb_free_urb(urb); } /* Did we submit any URBs */ if (i == 0) { netdev_warn(netdev, "couldn't setup read URBs\n"); return err; } /* Warn if we've couldn't transmit all the URBs */ if (i < MAX_RX_URBS) netdev_warn(netdev, "rx performance may be slow\n"); err = usb_8dev_cmd_open(priv); if (err) goto failed; priv->can.state = CAN_STATE_ERROR_ACTIVE; return 0; failed: if (err == -ENODEV) netif_device_detach(priv->netdev); netdev_warn(netdev, "couldn't submit control: %d\n", err); return err; } /* Open USB device */ static int usb_8dev_open(struct net_device *netdev) { struct usb_8dev_priv *priv = netdev_priv(netdev); int err; /* common open */ err = open_candev(netdev); if (err) return err; can_led_event(netdev, CAN_LED_EVENT_OPEN); /* finally start device */ err = usb_8dev_start(priv); if (err) { if (err == -ENODEV) netif_device_detach(priv->netdev); netdev_warn(netdev, "couldn't start device: %d\n", err); close_candev(netdev); return err; } netif_start_queue(netdev); return 0; } static void unlink_all_urbs(struct usb_8dev_priv *priv) { int i; usb_kill_anchored_urbs(&priv->rx_submitted); usb_kill_anchored_urbs(&priv->tx_submitted); atomic_set(&priv->active_tx_urbs, 0); for (i = 0; i < MAX_TX_URBS; i++) priv->tx_contexts[i].echo_index = MAX_TX_URBS; } /* Close USB device */ static int usb_8dev_close(struct net_device *netdev) { struct usb_8dev_priv *priv = netdev_priv(netdev); int err = 0; /* Send CLOSE command to CAN controller */ err = usb_8dev_cmd_close(priv); if (err) netdev_warn(netdev, "couldn't stop device"); priv->can.state = CAN_STATE_STOPPED; netif_stop_queue(netdev); /* Stop polling */ unlink_all_urbs(priv); close_candev(netdev); can_led_event(netdev, CAN_LED_EVENT_STOP); return err; } static const struct net_device_ops usb_8dev_netdev_ops = { .ndo_open = usb_8dev_open, .ndo_stop = usb_8dev_close, .ndo_start_xmit = usb_8dev_start_xmit, .ndo_change_mtu = can_change_mtu, }; static const struct can_bittiming_const usb_8dev_bittiming_const = { .name = "usb_8dev", .tseg1_min = 1, .tseg1_max = 16, .tseg2_min = 1, .tseg2_max = 8, .sjw_max = 4, .brp_min = 1, .brp_max = 1024, .brp_inc = 1, }; /* Probe USB device * * Check device and firmware. * Set supported modes and bittiming constants. * Allocate some memory. */ static int usb_8dev_probe(struct usb_interface *intf, const struct usb_device_id *id) { struct net_device *netdev; struct usb_8dev_priv *priv; int i, err = -ENOMEM; u32 version; char buf[18]; struct usb_device *usbdev = interface_to_usbdev(intf); /* product id looks strange, better we also check iProduct string */ if (usb_string(usbdev, usbdev->descriptor.iProduct, buf, sizeof(buf)) > 0 && strcmp(buf, "USB2CAN converter")) { dev_info(&usbdev->dev, "ignoring: not an USB2CAN converter\n"); return -ENODEV; } netdev = alloc_candev(sizeof(struct usb_8dev_priv), MAX_TX_URBS); if (!netdev) { dev_err(&intf->dev, "Couldn't alloc candev\n"); return -ENOMEM; } priv = netdev_priv(netdev); priv->udev = usbdev; priv->netdev = netdev; priv->can.state = CAN_STATE_STOPPED; priv->can.clock.freq = USB_8DEV_ABP_CLOCK; priv->can.bittiming_const = &usb_8dev_bittiming_const; priv->can.do_set_mode = usb_8dev_set_mode; priv->can.do_get_berr_counter = usb_8dev_get_berr_counter; priv->can.ctrlmode_supported = CAN_CTRLMODE_LOOPBACK | CAN_CTRLMODE_LISTENONLY | CAN_CTRLMODE_ONE_SHOT; netdev->netdev_ops = &usb_8dev_netdev_ops; netdev->flags |= IFF_ECHO; /* we support local echo */ init_usb_anchor(&priv->rx_submitted); init_usb_anchor(&priv->tx_submitted); atomic_set(&priv->active_tx_urbs, 0); for (i = 0; i < MAX_TX_URBS; i++) priv->tx_contexts[i].echo_index = MAX_TX_URBS; priv->cmd_msg_buffer = kzalloc(sizeof(struct usb_8dev_cmd_msg), GFP_KERNEL); if (!priv->cmd_msg_buffer) goto cleanup_candev; usb_set_intfdata(intf, priv); SET_NETDEV_DEV(netdev, &intf->dev); mutex_init(&priv->usb_8dev_cmd_lock); err = register_candev(netdev); if (err) { netdev_err(netdev, "couldn't register CAN device: %d\n", err); goto cleanup_cmd_msg_buffer; } err = usb_8dev_cmd_version(priv, &version); if (err) { netdev_err(netdev, "can't get firmware version\n"); goto cleanup_unregister_candev; } else { netdev_info(netdev, "firmware: %d.%d, hardware: %d.%d\n", (version>>24) & 0xff, (version>>16) & 0xff, (version>>8) & 0xff, version & 0xff); } devm_can_led_init(netdev); return 0; cleanup_unregister_candev: unregister_netdev(priv->netdev); cleanup_cmd_msg_buffer: kfree(priv->cmd_msg_buffer); cleanup_candev: free_candev(netdev); return err; } /* Called by the usb core when driver is unloaded or device is removed */ static void usb_8dev_disconnect(struct usb_interface *intf) { struct usb_8dev_priv *priv = usb_get_intfdata(intf); usb_set_intfdata(intf, NULL); if (priv) { netdev_info(priv->netdev, "device disconnected\n"); unregister_netdev(priv->netdev); free_candev(priv->netdev); unlink_all_urbs(priv); } } static struct usb_driver usb_8dev_driver = { .name = "usb_8dev", .probe = usb_8dev_probe, .disconnect = usb_8dev_disconnect, .id_table = usb_8dev_table, }; module_usb_driver(usb_8dev_driver); MODULE_AUTHOR("Bernd Krumboeck <*****@*****.**>"); MODULE_DESCRIPTION("CAN driver for 8 devices USB2CAN interfaces"); MODULE_LICENSE("GPL v2");
static int do_setlink(struct sk_buff *skb, struct nlmsghdr *nlh, void *arg) { struct ifinfomsg *ifm = NLMSG_DATA(nlh); struct rtattr **ida = arg; struct net_device *dev; int err, send_addr_notify = 0; if (ifm->ifi_index >= 0) dev = dev_get_by_index(ifm->ifi_index); else if (ida[IFLA_IFNAME - 1]) { char ifname[IFNAMSIZ]; if (rtattr_strlcpy(ifname, ida[IFLA_IFNAME - 1], IFNAMSIZ) >= IFNAMSIZ) return -EINVAL; dev = dev_get_by_name(ifname); } else return -EINVAL; if (!dev) return -ENODEV; err = -EINVAL; if (ifm->ifi_flags) dev_change_flags(dev, ifm->ifi_flags); if (ida[IFLA_MAP - 1]) { struct rtnl_link_ifmap *u_map; struct ifmap k_map; if (!dev->set_config) { err = -EOPNOTSUPP; goto out; } if (!netif_device_present(dev)) { err = -ENODEV; goto out; } if (ida[IFLA_MAP - 1]->rta_len != RTA_LENGTH(sizeof(*u_map))) goto out; u_map = RTA_DATA(ida[IFLA_MAP - 1]); k_map.mem_start = (unsigned long) u_map->mem_start; k_map.mem_end = (unsigned long) u_map->mem_end; k_map.base_addr = (unsigned short) u_map->base_addr; k_map.irq = (unsigned char) u_map->irq; k_map.dma = (unsigned char) u_map->dma; k_map.port = (unsigned char) u_map->port; err = dev->set_config(dev, &k_map); if (err) goto out; } if (ida[IFLA_ADDRESS - 1]) { if (!dev->set_mac_address) { err = -EOPNOTSUPP; goto out; } if (!netif_device_present(dev)) { err = -ENODEV; goto out; } if (ida[IFLA_ADDRESS - 1]->rta_len != RTA_LENGTH(dev->addr_len)) goto out; err = dev->set_mac_address(dev, RTA_DATA(ida[IFLA_ADDRESS - 1])); if (err) goto out; send_addr_notify = 1; } if (ida[IFLA_BROADCAST - 1]) { if (ida[IFLA_BROADCAST - 1]->rta_len != RTA_LENGTH(dev->addr_len)) goto out; memcpy(dev->broadcast, RTA_DATA(ida[IFLA_BROADCAST - 1]), dev->addr_len); send_addr_notify = 1; } if (ida[IFLA_MTU - 1]) { if (ida[IFLA_MTU - 1]->rta_len != RTA_LENGTH(sizeof(u32))) goto out; err = dev_set_mtu(dev, *((u32 *) RTA_DATA(ida[IFLA_MTU - 1]))); if (err) goto out; } if (ida[IFLA_TXQLEN - 1]) { if (ida[IFLA_TXQLEN - 1]->rta_len != RTA_LENGTH(sizeof(u32))) goto out; dev->tx_queue_len = *((u32 *) RTA_DATA(ida[IFLA_TXQLEN - 1])); } if (ida[IFLA_WEIGHT - 1]) { if (ida[IFLA_WEIGHT - 1]->rta_len != RTA_LENGTH(sizeof(u32))) goto out; dev->weight = *((u32 *) RTA_DATA(ida[IFLA_WEIGHT - 1])); } if (ifm->ifi_index >= 0 && ida[IFLA_IFNAME - 1]) { char ifname[IFNAMSIZ]; if (rtattr_strlcpy(ifname, ida[IFLA_IFNAME - 1], IFNAMSIZ) >= IFNAMSIZ) goto out; err = dev_change_name(dev, ifname); if (err) goto out; } err = 0; out: if (send_addr_notify) call_netdevice_notifiers(NETDEV_CHANGEADDR, dev); dev_put(dev); return err; }
static void usbnet_bh (unsigned long param) { struct usbnet *dev = (struct usbnet *) param; struct sk_buff *skb; struct skb_data *entry; while ((skb = skb_dequeue (&dev->done))) { entry = (struct skb_data *) skb->cb; switch (entry->state) { case rx_done: entry->state = rx_cleanup; rx_process (dev, skb); continue; case tx_done: case rx_cleanup: usb_free_urb (entry->urb); dev_kfree_skb (skb); continue; default: netdev_dbg(dev->net, "bogus skb state %d\n", entry->state); } } // waiting for all pending urbs to complete? if (dev->wait) { if ((dev->txq.qlen + dev->rxq.qlen + dev->done.qlen) == 0) { wake_up (dev->wait); } // or are we maybe short a few urbs? } else if (netif_running (dev->net) && netif_device_present (dev->net) && !timer_pending (&dev->delay) && !test_bit (EVENT_RX_HALT, &dev->flags)) { int temp = dev->rxq.qlen; int qlen = RX_QLEN (dev); if (temp < qlen) { struct urb *urb; int i; // don't refill the queue all at once for (i = 0; i < 10 && dev->rxq.qlen < qlen; i++) { urb = usb_alloc_urb (0, GFP_ATOMIC); if (urb != NULL) { if (rx_submit (dev, urb, GFP_ATOMIC) == -ENOLINK) return; } } if (temp != dev->rxq.qlen) netif_dbg(dev, link, dev->net, "rxqlen %d --> %d\n", temp, dev->rxq.qlen); if (dev->rxq.qlen < qlen) tasklet_schedule (&dev->bh); } if (dev->txq.qlen < TX_QLEN (dev)) netif_wake_queue (dev->net); } }
static void media_check(unsigned long arg) { struct net_device *dev = (struct net_device *)(arg); struct el3_private *lp = netdev_priv(dev); unsigned int ioaddr = dev->base_addr; u16 media, errs; unsigned long flags; if (!netif_device_present(dev)) goto reschedule; /* Check for pending interrupt with expired latency timer: with this, we can limp along even if the interrupt is blocked */ if ((inw(ioaddr + EL3_STATUS) & IntLatch) && (inb(ioaddr + EL3_TIMER) == 0xff)) { if (!lp->fast_poll) netdev_warn(dev, "interrupt(s) dropped!\n"); local_irq_save(flags); el3_interrupt(dev->irq, dev); local_irq_restore(flags); lp->fast_poll = HZ; } if (lp->fast_poll) { lp->fast_poll--; lp->media.expires = jiffies + HZ/100; add_timer(&lp->media); return; } /* lp->lock guards the EL3 window. Window should always be 1 except when the lock is held */ spin_lock_irqsave(&lp->lock, flags); EL3WINDOW(4); media = inw(ioaddr+WN4_MEDIA) & 0xc810; /* Ignore collisions unless we've had no irq's recently */ if (time_before(jiffies, lp->last_irq + HZ)) { media &= ~0x0010; } else { /* Try harder to detect carrier errors */ EL3WINDOW(6); outw(StatsDisable, ioaddr + EL3_CMD); errs = inb(ioaddr + 0); outw(StatsEnable, ioaddr + EL3_CMD); dev->stats.tx_carrier_errors += errs; if (errs || (lp->media_status & 0x0010)) media |= 0x0010; } if (media != lp->media_status) { if ((media & lp->media_status & 0x8000) && ((lp->media_status ^ media) & 0x0800)) netdev_info(dev, "%s link beat\n", (lp->media_status & 0x0800 ? "lost" : "found")); else if ((media & lp->media_status & 0x4000) && ((lp->media_status ^ media) & 0x0010)) netdev_info(dev, "coax cable %s\n", (lp->media_status & 0x0010 ? "ok" : "problem")); if (dev->if_port == 0) { if (media & 0x8000) { if (media & 0x0800) netdev_info(dev, "flipped to 10baseT\n"); else tc589_set_xcvr(dev, 2); } else if (media & 0x4000) { if (media & 0x0010) tc589_set_xcvr(dev, 1); else netdev_info(dev, "flipped to 10base2\n"); } } lp->media_status = media; } EL3WINDOW(1); spin_unlock_irqrestore(&lp->lock, flags); reschedule: lp->media.expires = jiffies + HZ; add_timer(&lp->media); }
/* The EL3 interrupt handler. */ static irqreturn_t el3_interrupt(int irq, void *dev_id) { struct net_device *dev = (struct net_device *) dev_id; struct el3_private *lp = netdev_priv(dev); unsigned int ioaddr; __u16 status; int i = 0, handled = 1; if (!netif_device_present(dev)) return IRQ_NONE; ioaddr = dev->base_addr; netdev_dbg(dev, "interrupt, status %4.4x.\n", inw(ioaddr + EL3_STATUS)); spin_lock(&lp->lock); while ((status = inw(ioaddr + EL3_STATUS)) & (IntLatch | RxComplete | StatsFull)) { if ((status & 0xe000) != 0x2000) { netdev_dbg(dev, "interrupt from dead card\n"); handled = 0; break; } if (status & RxComplete) el3_rx(dev); if (status & TxAvailable) { netdev_dbg(dev, " TX room bit was handled.\n"); /* There's room in the FIFO for a full-sized packet. */ outw(AckIntr | TxAvailable, ioaddr + EL3_CMD); netif_wake_queue(dev); } if (status & TxComplete) pop_tx_status(dev); if (status & (AdapterFailure | RxEarly | StatsFull)) { /* Handle all uncommon interrupts. */ if (status & StatsFull) /* Empty statistics. */ update_stats(dev); if (status & RxEarly) { /* Rx early is unused. */ el3_rx(dev); outw(AckIntr | RxEarly, ioaddr + EL3_CMD); } if (status & AdapterFailure) { u16 fifo_diag; EL3WINDOW(4); fifo_diag = inw(ioaddr + 4); EL3WINDOW(1); netdev_warn(dev, "adapter failure, FIFO diagnostic register %04x.\n", fifo_diag); if (fifo_diag & 0x0400) { /* Tx overrun */ tc589_wait_for_completion(dev, TxReset); outw(TxEnable, ioaddr + EL3_CMD); } if (fifo_diag & 0x2000) { /* Rx underrun */ tc589_wait_for_completion(dev, RxReset); set_rx_mode(dev); outw(RxEnable, ioaddr + EL3_CMD); } outw(AckIntr | AdapterFailure, ioaddr + EL3_CMD); } } if (++i > 10) { netdev_err(dev, "infinite loop in interrupt, status %4.4x.\n", status); /* Clear all interrupts */ outw(AckIntr | 0xFF, ioaddr + EL3_CMD); break; } /* Acknowledge the IRQ. */ outw(AckIntr | IntReq | IntLatch, ioaddr + EL3_CMD); } lp->last_irq = jiffies; spin_unlock(&lp->lock); netdev_dbg(dev, "exiting interrupt, status %4.4x.\n", inw(ioaddr + EL3_STATUS)); return IRQ_RETVAL(handled); }
/* ---------------------------------------------------------------------------- mace_interrupt The interrupt handler. ---------------------------------------------------------------------------- */ static irqreturn_t mace_interrupt(int irq, void *dev_id) { struct net_device *dev = (struct net_device *) dev_id; mace_private *lp = netdev_priv(dev); kio_addr_t ioaddr; int status; int IntrCnt = MACE_MAX_IR_ITERATIONS; if (dev == NULL) { DEBUG(2, "mace_interrupt(): irq 0x%X for unknown device.\n", irq); return IRQ_NONE; } ioaddr = dev->base_addr; if (lp->tx_irq_disabled) { printk( (lp->tx_irq_disabled? KERN_NOTICE "%s: Interrupt with tx_irq_disabled " "[isr=%02X, imr=%02X]\n": KERN_NOTICE "%s: Re-entering the interrupt handler " "[isr=%02X, imr=%02X]\n"), dev->name, inb(ioaddr + AM2150_MACE_BASE + MACE_IR), inb(ioaddr + AM2150_MACE_BASE + MACE_IMR) ); /* WARNING: MACE_IR has been read! */ return IRQ_NONE; } if (!netif_device_present(dev)) { DEBUG(2, "%s: interrupt from dead card\n", dev->name); return IRQ_NONE; } do { /* WARNING: MACE_IR is a READ/CLEAR port! */ status = inb(ioaddr + AM2150_MACE_BASE + MACE_IR); DEBUG(3, "mace_interrupt: irq 0x%X status 0x%X.\n", irq, status); if (status & MACE_IR_RCVINT) { mace_rx(dev, MACE_MAX_RX_ITERATIONS); } if (status & MACE_IR_XMTINT) { unsigned char fifofc; unsigned char xmtrc; unsigned char xmtfs; fifofc = inb(ioaddr + AM2150_MACE_BASE + MACE_FIFOFC); if ((fifofc & MACE_FIFOFC_XMTFC)==0) { lp->linux_stats.tx_errors++; outb(0xFF, ioaddr + AM2150_XMT_SKIP); } /* Transmit Retry Count (XMTRC, reg 4) */ xmtrc = inb(ioaddr + AM2150_MACE_BASE + MACE_XMTRC); if (xmtrc & MACE_XMTRC_EXDEF) lp->mace_stats.exdef++; lp->mace_stats.xmtrc += (xmtrc & MACE_XMTRC_XMTRC); if ( (xmtfs = inb(ioaddr + AM2150_MACE_BASE + MACE_XMTFS)) & MACE_XMTFS_XMTSV /* Transmit Status Valid */ ) { lp->mace_stats.xmtsv++; if (xmtfs & ~MACE_XMTFS_XMTSV) { if (xmtfs & MACE_XMTFS_UFLO) { /* Underflow. Indicates that the Transmit FIFO emptied before the end of frame was reached. */ lp->mace_stats.uflo++; } if (xmtfs & MACE_XMTFS_LCOL) { /* Late Collision */ lp->mace_stats.lcol++; } if (xmtfs & MACE_XMTFS_MORE) { /* MORE than one retry was needed */ lp->mace_stats.more++; } if (xmtfs & MACE_XMTFS_ONE) { /* Exactly ONE retry occurred */ lp->mace_stats.one++; } if (xmtfs & MACE_XMTFS_DEFER) { /* Transmission was defered */ lp->mace_stats.defer++; } if (xmtfs & MACE_XMTFS_LCAR) { /* Loss of carrier */ lp->mace_stats.lcar++; } if (xmtfs & MACE_XMTFS_RTRY) { /* Retry error: transmit aborted after 16 attempts */ lp->mace_stats.rtry++; } } /* if (xmtfs & ~MACE_XMTFS_XMTSV) */ } /* if (xmtfs & MACE_XMTFS_XMTSV) */ lp->linux_stats.tx_packets++; lp->tx_free_frames++; netif_wake_queue(dev); } /* if (status & MACE_IR_XMTINT) */ if (status & ~MACE_IMR_DEFAULT & ~MACE_IR_RCVINT & ~MACE_IR_XMTINT) { if (status & MACE_IR_JAB) { /* Jabber Error. Excessive transmit duration (20-150ms). */ lp->mace_stats.jab++; } if (status & MACE_IR_BABL) { /* Babble Error. >1518 bytes transmitted. */ lp->mace_stats.babl++; } if (status & MACE_IR_CERR) { /* Collision Error. CERR indicates the absence of the Signal Quality Error Test message after a packet transmission. */ lp->mace_stats.cerr++; } if (status & MACE_IR_RCVCCO) { /* Receive Collision Count Overflow; */ lp->mace_stats.rcvcco++; } if (status & MACE_IR_RNTPCO) { /* Runt Packet Count Overflow */ lp->mace_stats.rntpco++; } if (status & MACE_IR_MPCO) { /* Missed Packet Count Overflow */ lp->mace_stats.mpco++; } } /* if (status & ~MACE_IMR_DEFAULT & ~MACE_IR_RCVINT & ~MACE_IR_XMTINT) */ } while ((status & ~MACE_IMR_DEFAULT) && (--IntrCnt)); return IRQ_HANDLED; } /* mace_interrupt */