diff options
Diffstat (limited to 'drivers/net/usb/usbnet.c')
-rw-r--r-- | drivers/net/usb/usbnet.c | 449 |
1 files changed, 272 insertions, 177 deletions
diff --git a/drivers/net/usb/usbnet.c b/drivers/net/usb/usbnet.c index ca5ca5ae061d..7177abc78dc6 100644 --- a/drivers/net/usb/usbnet.c +++ b/drivers/net/usb/usbnet.c @@ -43,6 +43,7 @@ #include <linux/mii.h> #include <linux/usb.h> #include <linux/usb/usbnet.h> +#include <linux/slab.h> #define DRIVER_VERSION "22-Aug-2005" @@ -140,8 +141,8 @@ int usbnet_get_endpoints(struct usbnet *dev, struct usb_interface *intf) if (!alt || !in || !out) return -EINVAL; - if (alt->desc.bAlternateSetting != 0 - || !(dev->driver_info->flags & FLAG_NO_SETINT)) { + if (alt->desc.bAlternateSetting != 0 || + !(dev->driver_info->flags & FLAG_NO_SETINT)) { tmp = usb_set_interface (dev->udev, alt->desc.bInterfaceNumber, alt->desc.bAlternateSetting); if (tmp < 0) @@ -242,13 +243,13 @@ void usbnet_skb_return (struct usbnet *dev, struct sk_buff *skb) dev->net->stats.rx_packets++; dev->net->stats.rx_bytes += skb->len; - if (netif_msg_rx_status (dev)) - devdbg (dev, "< rx, len %zu, type 0x%x", - skb->len + sizeof (struct ethhdr), skb->protocol); + netif_dbg(dev, rx_status, dev->net, "< rx, len %zu, type 0x%x\n", + skb->len + sizeof (struct ethhdr), skb->protocol); memset (skb->cb, 0, sizeof (struct skb_data)); status = netif_rx (skb); - if (status != NET_RX_SUCCESS && netif_msg_rx_err (dev)) - devdbg (dev, "netif_rx status %d", status); + if (status != NET_RX_SUCCESS) + netif_dbg(dev, rx_err, dev->net, + "netif_rx status %d\n", status); } EXPORT_SYMBOL_GPL(usbnet_skb_return); @@ -313,9 +314,9 @@ void usbnet_defer_kevent (struct usbnet *dev, int work) { set_bit (work, &dev->flags); if (!schedule_work (&dev->kevent)) - deverr (dev, "kevent %d may have been dropped", work); + netdev_err(dev->net, "kevent %d may have been dropped\n", work); else - devdbg (dev, "kevent %d scheduled", work); + netdev_dbg(dev->net, "kevent %d scheduled\n", work); } EXPORT_SYMBOL_GPL(usbnet_defer_kevent); @@ -332,8 +333,7 @@ static void rx_submit (struct usbnet *dev, struct urb *urb, gfp_t flags) size_t size = dev->rx_urb_size; if ((skb = alloc_skb (size + NET_IP_ALIGN, flags)) == NULL) { - if (netif_msg_rx_err (dev)) - devdbg (dev, "no rx skb"); + netif_dbg(dev, rx_err, dev->net, "no rx skb\n"); usbnet_defer_kevent (dev, EVENT_RX_MEMORY); usb_free_urb (urb); return; @@ -351,9 +351,10 @@ static void rx_submit (struct usbnet *dev, struct urb *urb, gfp_t flags) spin_lock_irqsave (&dev->rxq.lock, lockflags); - if (netif_running (dev->net) - && netif_device_present (dev->net) - && !test_bit (EVENT_RX_HALT, &dev->flags)) { + 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); @@ -362,21 +363,19 @@ static void rx_submit (struct usbnet *dev, struct urb *urb, gfp_t flags) usbnet_defer_kevent (dev, EVENT_RX_MEMORY); break; case -ENODEV: - if (netif_msg_ifdown (dev)) - devdbg (dev, "device gone"); + netif_dbg(dev, ifdown, dev->net, "device gone\n"); netif_device_detach (dev->net); break; default: - if (netif_msg_rx_err (dev)) - devdbg (dev, "rx submit, %d", retval); + netif_dbg(dev, rx_err, dev->net, + "rx submit, %d\n", retval); tasklet_schedule (&dev->bh); break; case 0: __skb_queue_tail (&dev->rxq, skb); } } else { - if (netif_msg_ifdown (dev)) - devdbg (dev, "rx: stopped"); + netif_dbg(dev, ifdown, dev->net, "rx: stopped\n"); retval = -ENOLINK; } spin_unlock_irqrestore (&dev->rxq.lock, lockflags); @@ -391,16 +390,15 @@ static void rx_submit (struct usbnet *dev, struct urb *urb, gfp_t flags) static inline void rx_process (struct usbnet *dev, struct sk_buff *skb) { - if (dev->driver_info->rx_fixup - && !dev->driver_info->rx_fixup (dev, skb)) + if (dev->driver_info->rx_fixup && + !dev->driver_info->rx_fixup (dev, skb)) goto error; // else network stack removes extra byte if we forced a short packet if (skb->len) usbnet_skb_return (dev, skb); else { - if (netif_msg_rx_err (dev)) - devdbg (dev, "drop"); + netif_dbg(dev, rx_err, dev->net, "drop\n"); error: dev->net->stats.rx_errors++; skb_queue_tail (&dev->done, skb); @@ -427,8 +425,8 @@ static void rx_complete (struct urb *urb) entry->state = rx_cleanup; dev->net->stats.rx_errors++; dev->net->stats.rx_length_errors++; - if (netif_msg_rx_err (dev)) - devdbg (dev, "rx length %d", skb->len); + netif_dbg(dev, rx_err, dev->net, + "rx length %d\n", skb->len); } break; @@ -445,8 +443,8 @@ static void rx_complete (struct urb *urb) /* software-driven interface shutdown */ case -ECONNRESET: /* async unlink */ case -ESHUTDOWN: /* hardware gone */ - if (netif_msg_ifdown (dev)) - devdbg (dev, "rx shutdown, code %d", urb_status); + netif_dbg(dev, ifdown, dev->net, + "rx shutdown, code %d\n", urb_status); goto block; /* we get controller i/o faults during khubd disconnect() delays. @@ -459,8 +457,8 @@ static void rx_complete (struct urb *urb) dev->net->stats.rx_errors++; if (!timer_pending (&dev->delay)) { mod_timer (&dev->delay, jiffies + THROTTLE_JIFFIES); - if (netif_msg_link (dev)) - devdbg (dev, "rx throttle %d", urb_status); + netif_dbg(dev, link, dev->net, + "rx throttle %d\n", urb_status); } block: entry->state = rx_cleanup; @@ -476,23 +474,21 @@ block: default: entry->state = rx_cleanup; dev->net->stats.rx_errors++; - if (netif_msg_rx_err (dev)) - devdbg (dev, "rx status %d", urb_status); + netif_dbg(dev, rx_err, dev->net, "rx status %d\n", urb_status); break; } defer_bh(dev, skb, &dev->rxq); if (urb) { - if (netif_running (dev->net) - && !test_bit (EVENT_RX_HALT, &dev->flags)) { + if (netif_running (dev->net) && + !test_bit (EVENT_RX_HALT, &dev->flags)) { rx_submit (dev, urb, GFP_ATOMIC); return; } usb_free_urb (urb); } - if (netif_msg_rx_err (dev)) - devdbg (dev, "no read resubmitted"); + netif_dbg(dev, rx_err, dev->net, "no read resubmitted\n"); } static void intr_complete (struct urb *urb) @@ -509,15 +505,15 @@ static void intr_complete (struct urb *urb) /* software-driven interface shutdown */ case -ENOENT: /* urb killed */ case -ESHUTDOWN: /* hardware gone */ - if (netif_msg_ifdown (dev)) - devdbg (dev, "intr shutdown, code %d", status); + netif_dbg(dev, ifdown, dev->net, + "intr shutdown, code %d\n", status); return; /* NOTE: not throttling like RX/TX, since this endpoint * already polls infrequently */ default: - devdbg (dev, "intr status %d", status); + netdev_dbg(dev->net, "intr status %d\n", status); break; } @@ -526,8 +522,9 @@ static void intr_complete (struct urb *urb) memset(urb->transfer_buffer, 0, urb->transfer_buffer_length); status = usb_submit_urb (urb, GFP_ATOMIC); - if (status != 0 && netif_msg_timer (dev)) - deverr(dev, "intr resubmit --> %d", status); + if (status != 0) + netif_err(dev, timer, dev->net, + "intr resubmit --> %d\n", status); } /*-------------------------------------------------------------------------*/ @@ -535,8 +532,7 @@ void usbnet_pause_rx(struct usbnet *dev) { set_bit(EVENT_RX_PAUSED, &dev->flags); - if (netif_msg_rx_status(dev)) - devdbg(dev, "paused rx queue enabled"); + netif_dbg(dev, rx_status, dev->net, "paused rx queue enabled\n"); } EXPORT_SYMBOL_GPL(usbnet_pause_rx); @@ -554,8 +550,8 @@ void usbnet_resume_rx(struct usbnet *dev) tasklet_schedule(&dev->bh); - if (netif_msg_rx_status(dev)) - devdbg(dev, "paused rx queue disabled, %d skbs requeued", num); + netif_dbg(dev, rx_status, dev->net, + "paused rx queue disabled, %d skbs requeued\n", num); } EXPORT_SYMBOL_GPL(usbnet_resume_rx); @@ -588,7 +584,7 @@ static int unlink_urbs (struct usbnet *dev, struct sk_buff_head *q) // these (async) unlinks complete immediately retval = usb_unlink_urb (urb); if (retval != -EINPROGRESS && retval != 0) - devdbg (dev, "unlink urb err, %d", retval); + netdev_dbg(dev->net, "unlink urb err, %d\n", retval); else count++; } @@ -611,55 +607,60 @@ EXPORT_SYMBOL_GPL(usbnet_unlink_rx_urbs); /*-------------------------------------------------------------------------*/ // precondition: never called in_interrupt +static void usbnet_terminate_urbs(struct usbnet *dev) +{ + DECLARE_WAIT_QUEUE_HEAD_ONSTACK(unlink_wakeup); + DECLARE_WAITQUEUE(wait, current); + int temp; + + /* ensure there are no more active urbs */ + add_wait_queue(&unlink_wakeup, &wait); + set_current_state(TASK_UNINTERRUPTIBLE); + dev->wait = &unlink_wakeup; + temp = unlink_urbs(dev, &dev->txq) + + unlink_urbs(dev, &dev->rxq); + + /* maybe wait for deletions to finish. */ + while (!skb_queue_empty(&dev->rxq) + && !skb_queue_empty(&dev->txq) + && !skb_queue_empty(&dev->done)) { + schedule_timeout(UNLINK_TIMEOUT_MS); + set_current_state(TASK_UNINTERRUPTIBLE); + netif_dbg(dev, ifdown, dev->net, + "waited for %d urb completions\n", temp); + } + set_current_state(TASK_RUNNING); + dev->wait = NULL; + remove_wait_queue(&unlink_wakeup, &wait); +} int usbnet_stop (struct net_device *net) { struct usbnet *dev = netdev_priv(net); struct driver_info *info = dev->driver_info; - int temp; int retval; - DECLARE_WAIT_QUEUE_HEAD_ONSTACK (unlink_wakeup); - DECLARE_WAITQUEUE (wait, current); netif_stop_queue (net); - if (netif_msg_ifdown (dev)) - devinfo (dev, "stop stats: rx/tx %ld/%ld, errs %ld/%ld", - net->stats.rx_packets, net->stats.tx_packets, - net->stats.rx_errors, net->stats.tx_errors - ); + netif_info(dev, ifdown, dev->net, + "stop stats: rx/tx %ld/%ld, errs %ld/%ld\n", + net->stats.rx_packets, net->stats.tx_packets, + net->stats.rx_errors, net->stats.tx_errors); /* allow minidriver to stop correctly (wireless devices to turn off * radio etc) */ if (info->stop) { retval = info->stop(dev); - if (retval < 0 && netif_msg_ifdown(dev)) - devinfo(dev, - "stop fail (%d) usbnet usb-%s-%s, %s", - retval, - dev->udev->bus->bus_name, dev->udev->devpath, - info->description); + if (retval < 0) + netif_info(dev, ifdown, dev->net, + "stop fail (%d) usbnet usb-%s-%s, %s\n", + retval, + dev->udev->bus->bus_name, dev->udev->devpath, + info->description); } - if (!(info->flags & FLAG_AVOID_UNLINK_URBS)) { - /* ensure there are no more active urbs */ - add_wait_queue(&unlink_wakeup, &wait); - dev->wait = &unlink_wakeup; - temp = unlink_urbs(dev, &dev->txq) + - unlink_urbs(dev, &dev->rxq); - - /* maybe wait for deletions to finish. */ - while (!skb_queue_empty(&dev->rxq) - && !skb_queue_empty(&dev->txq) - && !skb_queue_empty(&dev->done)) { - msleep(UNLINK_TIMEOUT_MS); - if (netif_msg_ifdown(dev)) - devdbg(dev, "waited for %d urb completions", - temp); - } - dev->wait = NULL; - remove_wait_queue(&unlink_wakeup, &wait); - } + if (!(info->flags & FLAG_AVOID_UNLINK_URBS)) + usbnet_terminate_urbs(dev); usb_kill_urb(dev->interrupt); @@ -672,7 +673,10 @@ int usbnet_stop (struct net_device *net) dev->flags = 0; del_timer_sync (&dev->delay); tasklet_kill (&dev->bh); - usb_autopm_put_interface(dev->intf); + if (info->manage_power) + info->manage_power(dev, 0); + else + usb_autopm_put_interface(dev->intf); return 0; } @@ -691,30 +695,29 @@ int usbnet_open (struct net_device *net) struct driver_info *info = dev->driver_info; if ((retval = usb_autopm_get_interface(dev->intf)) < 0) { - if (netif_msg_ifup (dev)) - devinfo (dev, - "resumption fail (%d) usbnet usb-%s-%s, %s", - retval, - dev->udev->bus->bus_name, dev->udev->devpath, - info->description); + netif_info(dev, ifup, dev->net, + "resumption fail (%d) usbnet usb-%s-%s, %s\n", + retval, + dev->udev->bus->bus_name, + dev->udev->devpath, + info->description); goto done_nopm; } // put into "known safe" state if (info->reset && (retval = info->reset (dev)) < 0) { - if (netif_msg_ifup (dev)) - devinfo (dev, - "open reset fail (%d) usbnet usb-%s-%s, %s", - retval, - dev->udev->bus->bus_name, dev->udev->devpath, - info->description); + netif_info(dev, ifup, dev->net, + "open reset fail (%d) usbnet usb-%s-%s, %s\n", + retval, + dev->udev->bus->bus_name, + dev->udev->devpath, + info->description); goto done; } // insist peer be connected if (info->check_connect && (retval = info->check_connect (dev)) < 0) { - if (netif_msg_ifup (dev)) - devdbg (dev, "can't open; %d", retval); + netif_dbg(dev, ifup, dev->net, "can't open; %d\n", retval); goto done; } @@ -722,38 +725,34 @@ int usbnet_open (struct net_device *net) if (dev->interrupt) { retval = usb_submit_urb (dev->interrupt, GFP_KERNEL); if (retval < 0) { - if (netif_msg_ifup (dev)) - deverr (dev, "intr submit %d", retval); + netif_err(dev, ifup, dev->net, + "intr submit %d\n", retval); goto done; } } netif_start_queue (net); - if (netif_msg_ifup (dev)) { - char *framing; - - if (dev->driver_info->flags & FLAG_FRAMING_NC) - framing = "NetChip"; - else if (dev->driver_info->flags & FLAG_FRAMING_GL) - framing = "GeneSys"; - else if (dev->driver_info->flags & FLAG_FRAMING_Z) - framing = "Zaurus"; - else if (dev->driver_info->flags & FLAG_FRAMING_RN) - framing = "RNDIS"; - else if (dev->driver_info->flags & FLAG_FRAMING_AX) - framing = "ASIX"; - else - framing = "simple"; - - devinfo (dev, "open: enable queueing " - "(rx %d, tx %d) mtu %d %s framing", - (int)RX_QLEN (dev), (int)TX_QLEN (dev), dev->net->mtu, - framing); - } + netif_info(dev, ifup, dev->net, + "open: enable queueing (rx %d, tx %d) mtu %d %s framing\n", + (int)RX_QLEN(dev), (int)TX_QLEN(dev), + dev->net->mtu, + (dev->driver_info->flags & FLAG_FRAMING_NC) ? "NetChip" : + (dev->driver_info->flags & FLAG_FRAMING_GL) ? "GeneSys" : + (dev->driver_info->flags & FLAG_FRAMING_Z) ? "Zaurus" : + (dev->driver_info->flags & FLAG_FRAMING_RN) ? "RNDIS" : + (dev->driver_info->flags & FLAG_FRAMING_AX) ? "ASIX" : + "simple"); // delay posting reads until we're fully open tasklet_schedule (&dev->bh); + if (info->manage_power) { + retval = info->manage_power(dev, 1); + if (retval < 0) + goto done; + usb_autopm_put_interface(dev->intf); + } return retval; + done: usb_autopm_put_interface(dev->intf); done_nopm: @@ -881,13 +880,18 @@ kevent (struct work_struct *work) /* usb_clear_halt() needs a thread context */ if (test_bit (EVENT_TX_HALT, &dev->flags)) { unlink_urbs (dev, &dev->txq); + status = usb_autopm_get_interface(dev->intf); + if (status < 0) + goto fail_pipe; status = usb_clear_halt (dev->udev, dev->out); - if (status < 0 - && status != -EPIPE - && status != -ESHUTDOWN) { + usb_autopm_put_interface(dev->intf); + if (status < 0 && + status != -EPIPE && + status != -ESHUTDOWN) { if (netif_msg_tx_err (dev)) - deverr (dev, "can't clear tx halt, status %d", - status); +fail_pipe: + netdev_err(dev->net, "can't clear tx halt, status %d\n", + status); } else { clear_bit (EVENT_TX_HALT, &dev->flags); if (status != -ESHUTDOWN) @@ -896,13 +900,18 @@ kevent (struct work_struct *work) } if (test_bit (EVENT_RX_HALT, &dev->flags)) { unlink_urbs (dev, &dev->rxq); + status = usb_autopm_get_interface(dev->intf); + if (status < 0) + goto fail_halt; status = usb_clear_halt (dev->udev, dev->in); - if (status < 0 - && status != -EPIPE - && status != -ESHUTDOWN) { + usb_autopm_put_interface(dev->intf); + if (status < 0 && + status != -EPIPE && + status != -ESHUTDOWN) { if (netif_msg_rx_err (dev)) - deverr (dev, "can't clear rx halt, status %d", - status); +fail_halt: + netdev_err(dev->net, "can't clear rx halt, status %d\n", + status); } else { clear_bit (EVENT_RX_HALT, &dev->flags); tasklet_schedule (&dev->bh); @@ -919,7 +928,12 @@ kevent (struct work_struct *work) clear_bit (EVENT_RX_MEMORY, &dev->flags); if (urb != NULL) { clear_bit (EVENT_RX_MEMORY, &dev->flags); + status = usb_autopm_get_interface(dev->intf); + if (status < 0) + goto fail_lowmem; rx_submit (dev, urb, GFP_KERNEL); + usb_autopm_put_interface(dev->intf); +fail_lowmem: tasklet_schedule (&dev->bh); } } @@ -929,17 +943,24 @@ kevent (struct work_struct *work) int retval = 0; clear_bit (EVENT_LINK_RESET, &dev->flags); + status = usb_autopm_get_interface(dev->intf); + if (status < 0) + goto skip_reset; if(info->link_reset && (retval = info->link_reset(dev)) < 0) { - devinfo(dev, "link reset failed (%d) usbnet usb-%s-%s, %s", - retval, - dev->udev->bus->bus_name, dev->udev->devpath, - info->description); + usb_autopm_put_interface(dev->intf); +skip_reset: + netdev_info(dev->net, "link reset failed (%d) usbnet usb-%s-%s, %s\n", + retval, + dev->udev->bus->bus_name, + dev->udev->devpath, + info->description); + } else { + usb_autopm_put_interface(dev->intf); } } if (dev->flags) - devdbg (dev, "kevent done, flags = 0x%lx", - dev->flags); + netdev_dbg(dev->net, "kevent done, flags = 0x%lx\n", dev->flags); } /*-------------------------------------------------------------------------*/ @@ -971,22 +992,23 @@ static void tx_complete (struct urb *urb) case -EPROTO: case -ETIME: case -EILSEQ: + usb_mark_last_busy(dev->udev); if (!timer_pending (&dev->delay)) { mod_timer (&dev->delay, jiffies + THROTTLE_JIFFIES); - if (netif_msg_link (dev)) - devdbg (dev, "tx throttle %d", - urb->status); + netif_dbg(dev, link, dev->net, + "tx throttle %d\n", urb->status); } netif_stop_queue (dev->net); break; default: - if (netif_msg_tx_err (dev)) - devdbg (dev, "tx err %d", entry->urb->status); + netif_dbg(dev, tx_err, dev->net, + "tx err %d\n", entry->urb->status); break; } } + usb_autopm_put_interface_async(dev->intf); urb->dev = NULL; entry->state = tx_done; defer_bh(dev, skb, &dev->txq); @@ -1023,16 +1045,14 @@ netdev_tx_t usbnet_start_xmit (struct sk_buff *skb, if (info->tx_fixup) { skb = info->tx_fixup (dev, skb, GFP_ATOMIC); if (!skb) { - if (netif_msg_tx_err (dev)) - devdbg (dev, "can't tx_fixup skb"); + netif_dbg(dev, tx_err, dev->net, "can't tx_fixup skb\n"); goto drop; } } length = skb->len; if (!(urb = usb_alloc_urb (0, GFP_ATOMIC))) { - if (netif_msg_tx_err (dev)) - devdbg (dev, "no urb"); + netif_dbg(dev, tx_err, dev->net, "no urb\n"); goto drop; } @@ -1057,16 +1077,36 @@ netdev_tx_t usbnet_start_xmit (struct sk_buff *skb, } } - spin_lock_irqsave (&dev->txq.lock, flags); + spin_lock_irqsave(&dev->txq.lock, flags); + retval = usb_autopm_get_interface_async(dev->intf); + if (retval < 0) { + spin_unlock_irqrestore(&dev->txq.lock, flags); + goto drop; + } + +#ifdef CONFIG_PM + /* if this triggers the device is still a sleep */ + if (test_bit(EVENT_DEV_ASLEEP, &dev->flags)) { + /* transmission will be done in resume */ + usb_anchor_urb(urb, &dev->deferred); + /* no use to process more packets */ + netif_stop_queue(net); + spin_unlock_irqrestore(&dev->txq.lock, flags); + netdev_dbg(dev->net, "Delaying transmission for resumption\n"); + goto deferred; + } +#endif switch ((retval = usb_submit_urb (urb, GFP_ATOMIC))) { case -EPIPE: netif_stop_queue (net); usbnet_defer_kevent (dev, EVENT_TX_HALT); + usb_autopm_put_interface_async(dev->intf); break; default: - if (netif_msg_tx_err (dev)) - devdbg (dev, "tx: submit urb err %d", retval); + usb_autopm_put_interface_async(dev->intf); + netif_dbg(dev, tx_err, dev->net, + "tx: submit urb err %d\n", retval); break; case 0: net->trans_start = jiffies; @@ -1077,17 +1117,18 @@ netdev_tx_t usbnet_start_xmit (struct sk_buff *skb, spin_unlock_irqrestore (&dev->txq.lock, flags); if (retval) { - if (netif_msg_tx_err (dev)) - devdbg (dev, "drop, code %d", retval); + netif_dbg(dev, tx_err, dev->net, "drop, code %d\n", retval); drop: dev->net->stats.tx_dropped++; if (skb) dev_kfree_skb_any (skb); usb_free_urb (urb); - } else if (netif_msg_tx_queued (dev)) { - devdbg (dev, "> tx, len %d, type 0x%x", - length, skb->protocol); - } + } else + netif_dbg(dev, tx_queued, dev->net, + "> tx, len %d, type 0x%x\n", length, skb->protocol); +#ifdef CONFIG_PM +deferred: +#endif return NETDEV_TX_OK; } EXPORT_SYMBOL_GPL(usbnet_start_xmit); @@ -1115,7 +1156,7 @@ static void usbnet_bh (unsigned long param) dev_kfree_skb (skb); continue; default: - devdbg (dev, "bogus skb state %d", entry->state); + netdev_dbg(dev->net, "bogus skb state %d\n", entry->state); } } @@ -1126,10 +1167,10 @@ static void usbnet_bh (unsigned long param) } // 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)) { + } 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); @@ -1143,9 +1184,10 @@ static void usbnet_bh (unsigned long param) if (urb != NULL) rx_submit (dev, urb, GFP_ATOMIC); } - if (temp != dev->rxq.qlen && netif_msg_link (dev)) - devdbg (dev, "rxqlen %d --> %d", - temp, dev->rxq.qlen); + 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); } @@ -1176,11 +1218,10 @@ void usbnet_disconnect (struct usb_interface *intf) xdev = interface_to_usbdev (intf); - if (netif_msg_probe (dev)) - devinfo (dev, "unregister '%s' usb-%s-%s, %s", - intf->dev.driver->name, - xdev->bus->bus_name, xdev->devpath, - dev->driver_info->description); + netif_info(dev, probe, dev->net, "unregister '%s' usb-%s-%s, %s\n", + intf->dev.driver->name, + xdev->bus->bus_name, xdev->devpath, + dev->driver_info->description); net = dev->net; unregister_netdev (net); @@ -1210,6 +1251,14 @@ static const struct net_device_ops usbnet_netdev_ops = { // precondition: never called in_interrupt +static struct device_type wlan_type = { + .name = "wlan", +}; + +static struct device_type wwan_type = { + .name = "wwan", +}; + int usbnet_probe (struct usb_interface *udev, const struct usb_device_id *prod) { @@ -1255,6 +1304,7 @@ usbnet_probe (struct usb_interface *udev, const struct usb_device_id *prod) dev->bh.func = usbnet_bh; dev->bh.data = (unsigned long) dev; INIT_WORK (&dev->kevent, kevent); + init_usb_anchor(&dev->deferred); dev->delay.function = usbnet_bh; dev->delay.data = (unsigned long) dev; init_timer (&dev->delay); @@ -1289,12 +1339,15 @@ usbnet_probe (struct usb_interface *udev, const struct usb_device_id *prod) // heuristic: "usb%d" for links we know are two-host, // else "eth%d" when there's reasonable doubt. userspace // can rename the link if it knows better. - if ((dev->driver_info->flags & FLAG_ETHER) != 0 - && (net->dev_addr [0] & 0x02) == 0) + if ((dev->driver_info->flags & FLAG_ETHER) != 0 && + (net->dev_addr [0] & 0x02) == 0) strcpy (net->name, "eth%d"); /* WLAN devices should always be named "wlan%d" */ if ((dev->driver_info->flags & FLAG_WLAN) != 0) strcpy(net->name, "wlan%d"); + /* WWAN devices should always be named "wwan%d" */ + if ((dev->driver_info->flags & FLAG_WWAN) != 0) + strcpy(net->name, "wwan%d"); /* maybe the remote can't receive an Ethernet MTU */ if (net->mtu > (dev->hard_mtu - net->hard_header_len)) @@ -1322,22 +1375,30 @@ usbnet_probe (struct usb_interface *udev, const struct usb_device_id *prod) dev->maxpacket = usb_maxpacket (dev->udev, dev->out, 1); SET_NETDEV_DEV(net, &udev->dev); + + if ((dev->driver_info->flags & FLAG_WLAN) != 0) + SET_NETDEV_DEVTYPE(net, &wlan_type); + if ((dev->driver_info->flags & FLAG_WWAN) != 0) + SET_NETDEV_DEVTYPE(net, &wwan_type); + status = register_netdev (net); if (status) goto out3; - if (netif_msg_probe (dev)) - devinfo (dev, "register '%s' at usb-%s-%s, %s, %pM", - udev->dev.driver->name, - xdev->bus->bus_name, xdev->devpath, - dev->driver_info->description, - net->dev_addr); + netif_info(dev, probe, dev->net, + "register '%s' at usb-%s-%s, %s, %pM\n", + udev->dev.driver->name, + xdev->bus->bus_name, xdev->devpath, + dev->driver_info->description, + net->dev_addr); // ok, it's ready to go. usb_set_intfdata (udev, dev); - // start as if the link is up netif_device_attach (net); + if (dev->driver_info->flags & FLAG_LINK_INTR) + netif_carrier_off(net); + return 0; out3: @@ -1363,13 +1424,23 @@ int usbnet_suspend (struct usb_interface *intf, pm_message_t message) struct usbnet *dev = usb_get_intfdata(intf); if (!dev->suspend_count++) { + spin_lock_irq(&dev->txq.lock); + /* don't autosuspend while transmitting */ + if (dev->txq.qlen && (message.event & PM_EVENT_AUTO)) { + spin_unlock_irq(&dev->txq.lock); + return -EBUSY; + } else { + set_bit(EVENT_DEV_ASLEEP, &dev->flags); + spin_unlock_irq(&dev->txq.lock); + } /* * accelerate emptying of the rx and queues, to avoid * having everything error out. */ netif_device_detach (dev->net); - (void) unlink_urbs (dev, &dev->rxq); - (void) unlink_urbs (dev, &dev->txq); + usbnet_terminate_urbs(dev); + usb_kill_urb(dev->interrupt); + /* * reattach so runtime management can use and * wake the device @@ -1383,10 +1454,34 @@ EXPORT_SYMBOL_GPL(usbnet_suspend); int usbnet_resume (struct usb_interface *intf) { struct usbnet *dev = usb_get_intfdata(intf); + struct sk_buff *skb; + struct urb *res; + int retval; + + if (!--dev->suspend_count) { + spin_lock_irq(&dev->txq.lock); + while ((res = usb_get_from_anchor(&dev->deferred))) { + + printk(KERN_INFO"%s has delayed data\n", __func__); + skb = (struct sk_buff *)res->context; + retval = usb_submit_urb(res, GFP_ATOMIC); + if (retval < 0) { + dev_kfree_skb_any(skb); + usb_free_urb(res); + usb_autopm_put_interface_async(dev->intf); + } else { + dev->net->trans_start = jiffies; + __skb_queue_tail(&dev->txq, skb); + } + } - if (!--dev->suspend_count) + smp_mb(); + clear_bit(EVENT_DEV_ASLEEP, &dev->flags); + spin_unlock_irq(&dev->txq.lock); + if (!(dev->txq.qlen >= TX_QLEN(dev))) + netif_start_queue(dev->net); tasklet_schedule (&dev->bh); - + } return 0; } EXPORT_SYMBOL_GPL(usbnet_resume); |