* [patch]reset_resume for cdc-ether
@ 2009-11-24 10:59 Oliver Neukum
2009-11-29 8:18 ` David Miller
2009-12-03 6:16 ` David Miller
0 siblings, 2 replies; 16+ messages in thread
From: Oliver Neukum @ 2009-11-24 10:59 UTC (permalink / raw)
To: David Brownell, netdev, USB list, David S. Miller
Hi,
this is quite trivial but might be convenient to many users.
Regards
Oliver
Signed-off-by: Oliver Neukum <oliver@neukum.org>
--
commit 31deb426ccea8faf91f4373c1f12c98bb0d82c73
Author: Oliver Neukum <oliver@neukum.org>
Date: Tue Nov 24 08:30:41 2009 +0100
cdc-ether:imlement reset_resume()
Normal resume can do double duty as reset_resume() for this driver
diff --git a/drivers/net/usb/cdc_ether.c b/drivers/net/usb/cdc_ether.c
index ed55024..11f73dd 100644
--- a/drivers/net/usb/cdc_ether.c
+++ b/drivers/net/usb/cdc_ether.c
@@ -617,6 +617,7 @@ static struct usb_driver cdc_driver = {
.disconnect = usbnet_disconnect,
.suspend = usbnet_suspend,
.resume = usbnet_resume,
+ .reset_resume = usbnet_resume,
.supports_autosuspend = 1,
};
^ permalink raw reply related [flat|nested] 16+ messages in thread* Re: [patch]reset_resume for cdc-ether 2009-11-24 10:59 [patch]reset_resume for cdc-ether Oliver Neukum @ 2009-11-29 8:18 ` David Miller 2009-12-03 6:16 ` David Miller 1 sibling, 0 replies; 16+ messages in thread From: David Miller @ 2009-11-29 8:18 UTC (permalink / raw) To: oliver; +Cc: david-b, netdev, linux-usb From: Oliver Neukum <oliver@neukum.org> Date: Tue, 24 Nov 2009 11:59:02 +0100 > commit 31deb426ccea8faf91f4373c1f12c98bb0d82c73 > Author: Oliver Neukum <oliver@neukum.org> > Date: Tue Nov 24 08:30:41 2009 +0100 > > cdc-ether:imlement reset_resume() > > Normal resume can do double duty as reset_resume() for this driver David B., ACK, NACK, indifferent? ^ permalink raw reply [flat|nested] 16+ messages in thread
* Re: [patch]reset_resume for cdc-ether 2009-11-24 10:59 [patch]reset_resume for cdc-ether Oliver Neukum 2009-11-29 8:18 ` David Miller @ 2009-12-03 6:16 ` David Miller [not found] ` <20091202.221627.133392199.davem-fT/PcQaiUtIeIZ0/mPfg9Q@public.gmane.org> 1 sibling, 1 reply; 16+ messages in thread From: David Miller @ 2009-12-03 6:16 UTC (permalink / raw) To: oliver; +Cc: david-b, netdev, linux-usb From: Oliver Neukum <oliver@neukum.org> Date: Tue, 24 Nov 2009 11:59:02 +0100 > Hi, > > this is quite trivial but might be convenient to many users. > > Regards > Oliver > > Signed-off-by: Oliver Neukum <oliver@neukum.org> I'm going to apply this patch and the USB autosuspend one too. If David B. has some problems with it, we can revert. But as it stands these patches have been posted for some time and there's no reason for them to miss the merge window so I'm adding them to net-next-2.6 Thanks Oliver. ^ permalink raw reply [flat|nested] 16+ messages in thread
[parent not found: <20091202.221627.133392199.davem-fT/PcQaiUtIeIZ0/mPfg9Q@public.gmane.org>]
* Re: [patch]reset_resume for cdc-ether [not found] ` <20091202.221627.133392199.davem-fT/PcQaiUtIeIZ0/mPfg9Q@public.gmane.org> @ 2009-12-03 6:22 ` David Miller [not found] ` <20091202.222254.61468873.davem-fT/PcQaiUtIeIZ0/mPfg9Q@public.gmane.org> 0 siblings, 1 reply; 16+ messages in thread From: David Miller @ 2009-12-03 6:22 UTC (permalink / raw) To: oliver-GvhC2dPhHPQdnm+yROfE0A Cc: david-b-yBeKhBN/0LDR7s880joybQ, netdev-u79uwXL29TY76Z2rM5mHXA, linux-usb-u79uwXL29TY76Z2rM5mHXA From: David Miller <davem-fT/PcQaiUtIeIZ0/mPfg9Q@public.gmane.org> Date: Wed, 02 Dec 2009 22:16:27 -0800 (PST) > From: Oliver Neukum <oliver-GvhC2dPhHPQdnm+yROfE0A@public.gmane.org> > Date: Tue, 24 Nov 2009 11:59:02 +0100 > >> Hi, >> >> this is quite trivial but might be convenient to many users. >> >> Regards >> Oliver >> >> Signed-off-by: Oliver Neukum <oliver-GvhC2dPhHPQdnm+yROfE0A@public.gmane.org> > > I'm going to apply this patch and the USB autosuspend one too. Actually, neither patch applies to net-next-2.6 Oliver can you respin your changes and add a proper signoff to the autosuspend patch? Thanks. -- To unsubscribe from this list: send the line "unsubscribe linux-usb" in the body of a message to majordomo-u79uwXL29TY76Z2rM5mHXA@public.gmane.org More majordomo info at http://vger.kernel.org/majordomo-info.html ^ permalink raw reply [flat|nested] 16+ messages in thread
[parent not found: <20091202.222254.61468873.davem-fT/PcQaiUtIeIZ0/mPfg9Q@public.gmane.org>]
* Re: [patch]reset_resume for cdc-ether [not found] ` <20091202.222254.61468873.davem-fT/PcQaiUtIeIZ0/mPfg9Q@public.gmane.org> @ 2009-12-03 9:56 ` Oliver Neukum 2009-12-03 10:14 ` David Miller [not found] ` <200912031056.17103.oliver-GvhC2dPhHPQdnm+yROfE0A@public.gmane.org> 2009-12-03 10:02 ` Oliver Neukum 1 sibling, 2 replies; 16+ messages in thread From: Oliver Neukum @ 2009-12-03 9:56 UTC (permalink / raw) To: David Miller Cc: david-b-yBeKhBN/0LDR7s880joybQ, netdev-u79uwXL29TY76Z2rM5mHXA, linux-usb-u79uwXL29TY76Z2rM5mHXA Am Donnerstag, 3. Dezember 2009 07:22:54 schrieb David Miller: > > I'm going to apply this patch and the USB autosuspend one too. > > Actually, neither patch applies to net-next-2.6 > > Oliver can you respin your changes and add a proper signoff > to the autosuspend patch? Hi, here's autosuspend again. Regards Oliver Signed-off-by: Oliver Neukum <oliver-GvhC2dPhHPQdnm+yROfE0A@public.gmane.org> -- commit 276405340ff17a79f6847174d1e737242df60cb5 Author: Oliver Neukum <oliver-GvhC2dPhHPQdnm+yROfE0A@public.gmane.org> Date: Thu Dec 3 10:53:21 2009 +0100 usbnet & cdc-ether: autosuspend for online devices using remote wakeup and delayed transmission to allow online device to go into usb autosuspend minimal alternate support for devices that don't support remote wakeup Signed-off-by: Oliver Neukum <oliver-GvhC2dPhHPQdnm+yROfE0A@public.gmane.org> diff --git a/drivers/net/usb/cdc_ether.c b/drivers/net/usb/cdc_ether.c index 71e65fc..b9493ef 100644 --- a/drivers/net/usb/cdc_ether.c +++ b/drivers/net/usb/cdc_ether.c @@ -411,6 +411,12 @@ static int cdc_bind(struct usbnet *dev, struct usb_interface *intf) return 0; } +static int cdc_manage_power(struct usbnet *dev, int on) +{ + dev->intf->needs_remote_wakeup = on; + return 0; +} + static const struct driver_info cdc_info = { .description = "CDC Ethernet Device", .flags = FLAG_ETHER, @@ -418,6 +424,7 @@ static const struct driver_info cdc_info = { .bind = cdc_bind, .unbind = usbnet_cdc_unbind, .status = cdc_status, + .manage_power = cdc_manage_power, }; static const struct driver_info mbm_info = { @@ -578,6 +585,7 @@ static struct usb_driver cdc_driver = { .disconnect = usbnet_disconnect, .suspend = usbnet_suspend, .resume = usbnet_resume, + .supports_autosuspend = 1, }; diff --git a/drivers/net/usb/usbnet.c b/drivers/net/usb/usbnet.c index 378da8c..83cdd46 100644 --- a/drivers/net/usb/usbnet.c +++ b/drivers/net/usb/usbnet.c @@ -353,7 +353,8 @@ static void rx_submit (struct usbnet *dev, struct urb *urb, gfp_t flags) if (netif_running (dev->net) && netif_device_present (dev->net) - && !test_bit (EVENT_RX_HALT, &dev->flags)) { + && !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); @@ -611,15 +612,39 @@ 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); + if (netif_msg_ifdown(dev)) + devdbg(dev, "waited for %d urb completions", + 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); @@ -641,25 +666,8 @@ int usbnet_stop (struct net_device *net) 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 +680,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; } @@ -753,6 +764,12 @@ int usbnet_open (struct net_device *net) // 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); @@ -881,11 +898,16 @@ 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); + usb_autopm_put_interface(dev->intf); if (status < 0 && status != -EPIPE && status != -ESHUTDOWN) { if (netif_msg_tx_err (dev)) +fail_pipe: deverr (dev, "can't clear tx halt, status %d", status); } else { @@ -896,11 +918,16 @@ 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); + usb_autopm_put_interface(dev->intf); if (status < 0 && status != -EPIPE && status != -ESHUTDOWN) { if (netif_msg_rx_err (dev)) +fail_halt: deverr (dev, "can't clear rx halt, status %d", status); } else { @@ -919,7 +946,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,11 +961,18 @@ 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) { + usb_autopm_put_interface(dev->intf); +skip_reset: devinfo(dev, "link reset failed (%d) usbnet usb-%s-%s, %s", retval, dev->udev->bus->bus_name, dev->udev->devpath, info->description); + } else { + usb_autopm_put_interface(dev->intf); } } @@ -971,6 +1010,7 @@ 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); @@ -987,6 +1027,7 @@ static void tx_complete (struct urb *urb) } } + usb_autopm_put_interface_async(dev->intf); urb->dev = NULL; entry->state = tx_done; defer_bh(dev, skb, &dev->txq); @@ -1057,14 +1098,34 @@ 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); + devdbg(dev, "Delaying transmission for resumption"); + 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: + usb_autopm_put_interface_async(dev->intf); if (netif_msg_tx_err (dev)) devdbg (dev, "tx: submit urb err %d", retval); break; @@ -1088,6 +1149,7 @@ drop: devdbg (dev, "> tx, len %d, type 0x%x", length, skb->protocol); } +deferred: return NETDEV_TX_OK; } EXPORT_SYMBOL_GPL(usbnet_start_xmit); @@ -1263,6 +1325,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); @@ -1380,13 +1443,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 @@ -1400,10 +1473,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); diff --git a/include/linux/usb/usbnet.h b/include/linux/usb/usbnet.h index 86c31b7..a7b92d6 100644 --- a/include/linux/usb/usbnet.h +++ b/include/linux/usb/usbnet.h @@ -55,6 +55,7 @@ struct usbnet { struct sk_buff_head done; struct sk_buff_head rxq_pause; struct urb *interrupt; + struct usb_anchor deferred; struct tasklet_struct bh; struct work_struct kevent; @@ -65,6 +66,8 @@ struct usbnet { # define EVENT_STS_SPLIT 3 # define EVENT_LINK_RESET 4 # define EVENT_RX_PAUSED 5 +# define EVENT_DEV_WAKING 6 +# define EVENT_DEV_ASLEEP 7 }; static inline struct usb_driver *driver_of(struct usb_interface *intf) @@ -108,6 +111,9 @@ struct driver_info { /* see if peer is connected ... can sleep */ int (*check_connect)(struct usbnet *); + /* (dis)activate runtime power management */ + int (*manage_power)(struct usbnet *, int); + /* for status polling */ void (*status)(struct usbnet *, struct urb *); -- To unsubscribe from this list: send the line "unsubscribe linux-usb" in the body of a message to majordomo-u79uwXL29TY76Z2rM5mHXA@public.gmane.org More majordomo info at http://vger.kernel.org/majordomo-info.html ^ permalink raw reply related [flat|nested] 16+ messages in thread
* Re: [patch]reset_resume for cdc-ether 2009-12-03 9:56 ` Oliver Neukum @ 2009-12-03 10:14 ` David Miller 2009-12-03 10:26 ` Oliver Neukum ` (2 more replies) [not found] ` <200912031056.17103.oliver-GvhC2dPhHPQdnm+yROfE0A@public.gmane.org> 1 sibling, 3 replies; 16+ messages in thread From: David Miller @ 2009-12-03 10:14 UTC (permalink / raw) To: oliver; +Cc: david-b, netdev, linux-usb From: Oliver Neukum <oliver@neukum.org> Date: Thu, 3 Dec 2009 10:56:17 +0100 > Am Donnerstag, 3. Dezember 2009 07:22:54 schrieb David Miller: >> > I'm going to apply this patch and the USB autosuspend one too. >> >> Actually, neither patch applies to net-next-2.6 >> >> Oliver can you respin your changes and add a proper signoff >> to the autosuspend patch? > > Hi, > > here's autosuspend again. It doesn't apply to my tree still: davem@sunset:~/src/GIT/net-next-2.6$ git apply --check --whitespace=error-all diff error: patch failed: drivers/net/usb/cdc_ether.c:411 error: drivers/net/usb/cdc_ether.c: patch does not apply davem@sunset:~/src/GIT/net-next-2.6$ ^ permalink raw reply [flat|nested] 16+ messages in thread
* Re: [patch]reset_resume for cdc-ether 2009-12-03 10:14 ` David Miller @ 2009-12-03 10:26 ` Oliver Neukum 2009-12-03 10:33 ` David Miller 2009-12-03 13:01 ` Oliver Neukum 2009-12-03 13:02 ` Oliver Neukum 2 siblings, 1 reply; 16+ messages in thread From: Oliver Neukum @ 2009-12-03 10:26 UTC (permalink / raw) To: David Miller; +Cc: david-b, netdev, linux-usb Am Donnerstag, 3. Dezember 2009 11:14:56 schrieb David Miller: > From: Oliver Neukum <oliver@neukum.org> > Date: Thu, 3 Dec 2009 10:56:17 +0100 > > > Am Donnerstag, 3. Dezember 2009 07:22:54 schrieb David Miller: > >> > I'm going to apply this patch and the USB autosuspend one too. > >> > >> Actually, neither patch applies to net-next-2.6 > >> > >> Oliver can you respin your changes and add a proper signoff > >> to the autosuspend patch? > > > > Hi, > > > > here's autosuspend again. > > It doesn't apply to my tree still: > > davem@sunset:~/src/GIT/net-next-2.6$ git apply --check > --whitespace=error-all diff error: patch failed: > drivers/net/usb/cdc_ether.c:411 > error: drivers/net/usb/cdc_ether.c: patch does not apply > davem@sunset:~/src/GIT/net-next-2.6$ Am I making patches against the wrong tree? Can you tell me exactly which tree I need to clone? Regards Oliver ^ permalink raw reply [flat|nested] 16+ messages in thread
* Re: [patch]reset_resume for cdc-ether 2009-12-03 10:26 ` Oliver Neukum @ 2009-12-03 10:33 ` David Miller 0 siblings, 0 replies; 16+ messages in thread From: David Miller @ 2009-12-03 10:33 UTC (permalink / raw) To: oliver; +Cc: david-b, netdev, linux-usb From: Oliver Neukum <oliver@neukum.org> Date: Thu, 3 Dec 2009 11:26:03 +0100 > Can you tell me exactly which tree I need to clone? git://git.kernel.org/pub/scm/linux/kernel/git/davem/net-2.6.git ^ permalink raw reply [flat|nested] 16+ messages in thread
* Re: [patch]reset_resume for cdc-ether 2009-12-03 10:14 ` David Miller 2009-12-03 10:26 ` Oliver Neukum @ 2009-12-03 13:01 ` Oliver Neukum 2009-12-03 13:02 ` Oliver Neukum 2 siblings, 0 replies; 16+ messages in thread From: Oliver Neukum @ 2009-12-03 13:01 UTC (permalink / raw) To: David Miller; +Cc: david-b, netdev, linux-usb Am Donnerstag, 3. Dezember 2009 11:14:56 schrieb David Miller: > > Hi, > > > > here's autosuspend again. > > It doesn't apply to my tree still: > Ok, this time against the correct tree comes reset_resume() Regards Oliver Signed-off-by: Oliver Neukum <oliver@neukum.org> -- commit a0516662d1d281c321410a8792603ba02c14293b Author: Oliver Neukum <oliver@neukum.org> Date: Thu Dec 3 13:54:49 2009 +0100 cdc-ether:imlement reset_resume() Normal resume can do double duty as reset_resume() for this driver as it keeps no state in the device Signed-off-by: Oliver Neukum <oliver@neukum.org> diff --git a/drivers/net/usb/cdc_ether.c b/drivers/net/usb/cdc_ether.c index 21e1ba1..075e33f 100644 --- a/drivers/net/usb/cdc_ether.c +++ b/drivers/net/usb/cdc_ether.c @@ -610,6 +610,7 @@ static struct usb_driver cdc_driver = { .disconnect = usbnet_disconnect, .suspend = usbnet_suspend, .resume = usbnet_resume, + .reset_resume = usbnet_resume, }; ^ permalink raw reply related [flat|nested] 16+ messages in thread
* Re: [patch]reset_resume for cdc-ether 2009-12-03 10:14 ` David Miller 2009-12-03 10:26 ` Oliver Neukum 2009-12-03 13:01 ` Oliver Neukum @ 2009-12-03 13:02 ` Oliver Neukum 2009-12-03 20:31 ` David Miller 2 siblings, 1 reply; 16+ messages in thread From: Oliver Neukum @ 2009-12-03 13:02 UTC (permalink / raw) To: David Miller, Torgny Johansson; +Cc: david-b, netdev, linux-usb Am Donnerstag, 3. Dezember 2009 11:14:56 schrieb David Miller: > It doesn't apply to my tree still: And this is autosuspend. Regards Oliver Signed-off-by: Oliver Neukum <oliver@neukum.org> -- commit 8c2dc91a80eca9c2bd7f8074ba2afbd1251ede99 Author: Oliver Neukum <oliver@neukum.org> Date: Thu Dec 3 13:58:59 2009 +0100 usbnet & cdc-ether: autosuspend for online devices using remote wakeup and delayed transmission to allow online device to go into usb autosuspend minimal alternate support for devices that don't support remote wakeup Signed-off-by: Oliver Neukum <oliver@neukum.org> diff --git a/drivers/net/usb/cdc_ether.c b/drivers/net/usb/cdc_ether.c index 075e33f..11f73dd 100644 --- a/drivers/net/usb/cdc_ether.c +++ b/drivers/net/usb/cdc_ether.c @@ -411,6 +411,12 @@ static int cdc_bind(struct usbnet *dev, struct usb_interface *intf) return 0; } +static int cdc_manage_power(struct usbnet *dev, int on) +{ + dev->intf->needs_remote_wakeup = on; + return 0; +} + static const struct driver_info cdc_info = { .description = "CDC Ethernet Device", .flags = FLAG_ETHER, @@ -418,6 +424,7 @@ static const struct driver_info cdc_info = { .bind = cdc_bind, .unbind = usbnet_cdc_unbind, .status = cdc_status, + .manage_power = cdc_manage_power, }; /*-------------------------------------------------------------------------*/ @@ -611,6 +618,7 @@ static struct usb_driver cdc_driver = { .suspend = usbnet_suspend, .resume = usbnet_resume, .reset_resume = usbnet_resume, + .supports_autosuspend = 1, }; diff --git a/drivers/net/usb/usbnet.c b/drivers/net/usb/usbnet.c index ca5ca5a..4a555b6 100644 --- a/drivers/net/usb/usbnet.c +++ b/drivers/net/usb/usbnet.c @@ -353,7 +353,8 @@ static void rx_submit (struct usbnet *dev, struct urb *urb, gfp_t flags) if (netif_running (dev->net) && netif_device_present (dev->net) - && !test_bit (EVENT_RX_HALT, &dev->flags)) { + && !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); @@ -611,15 +612,39 @@ 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); + if (netif_msg_ifdown(dev)) + devdbg(dev, "waited for %d urb completions", + 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); @@ -641,25 +666,8 @@ int usbnet_stop (struct net_device *net) 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 +680,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; } @@ -753,6 +764,12 @@ int usbnet_open (struct net_device *net) // 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); @@ -881,11 +898,16 @@ 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); + usb_autopm_put_interface(dev->intf); if (status < 0 && status != -EPIPE && status != -ESHUTDOWN) { if (netif_msg_tx_err (dev)) +fail_pipe: deverr (dev, "can't clear tx halt, status %d", status); } else { @@ -896,11 +918,16 @@ 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); + usb_autopm_put_interface(dev->intf); if (status < 0 && status != -EPIPE && status != -ESHUTDOWN) { if (netif_msg_rx_err (dev)) +fail_halt: deverr (dev, "can't clear rx halt, status %d", status); } else { @@ -919,7 +946,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,11 +961,18 @@ 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) { + usb_autopm_put_interface(dev->intf); +skip_reset: devinfo(dev, "link reset failed (%d) usbnet usb-%s-%s, %s", retval, dev->udev->bus->bus_name, dev->udev->devpath, info->description); + } else { + usb_autopm_put_interface(dev->intf); } } @@ -971,6 +1010,7 @@ 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); @@ -987,6 +1027,7 @@ static void tx_complete (struct urb *urb) } } + usb_autopm_put_interface_async(dev->intf); urb->dev = NULL; entry->state = tx_done; defer_bh(dev, skb, &dev->txq); @@ -1057,14 +1098,34 @@ 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); + devdbg(dev, "Delaying transmission for resumption"); + 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: + usb_autopm_put_interface_async(dev->intf); if (netif_msg_tx_err (dev)) devdbg (dev, "tx: submit urb err %d", retval); break; @@ -1088,6 +1149,7 @@ drop: devdbg (dev, "> tx, len %d, type 0x%x", length, skb->protocol); } +deferred: return NETDEV_TX_OK; } EXPORT_SYMBOL_GPL(usbnet_start_xmit); @@ -1255,6 +1317,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); @@ -1363,13 +1426,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 +1456,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); diff --git a/include/linux/usb/usbnet.h b/include/linux/usb/usbnet.h index f814730..aa174df 100644 --- a/include/linux/usb/usbnet.h +++ b/include/linux/usb/usbnet.h @@ -55,6 +55,7 @@ struct usbnet { struct sk_buff_head done; struct sk_buff_head rxq_pause; struct urb *interrupt; + struct usb_anchor deferred; struct tasklet_struct bh; struct work_struct kevent; @@ -65,6 +66,8 @@ struct usbnet { # define EVENT_STS_SPLIT 3 # define EVENT_LINK_RESET 4 # define EVENT_RX_PAUSED 5 +# define EVENT_DEV_WAKING 6 +# define EVENT_DEV_ASLEEP 7 }; static inline struct usb_driver *driver_of(struct usb_interface *intf) @@ -107,6 +110,9 @@ struct driver_info { /* see if peer is connected ... can sleep */ int (*check_connect)(struct usbnet *); + /* (dis)activate runtime power management */ + int (*manage_power)(struct usbnet *, int); + /* for status polling */ void (*status)(struct usbnet *, struct urb *); ^ permalink raw reply related [flat|nested] 16+ messages in thread
* Re: [patch]reset_resume for cdc-ether 2009-12-03 13:02 ` Oliver Neukum @ 2009-12-03 20:31 ` David Miller [not found] ` <20091203.123150.182603807.davem-fT/PcQaiUtIeIZ0/mPfg9Q@public.gmane.org> 0 siblings, 1 reply; 16+ messages in thread From: David Miller @ 2009-12-03 20:31 UTC (permalink / raw) To: oliver; +Cc: torgny.johansson, david-b, netdev, linux-usb From: Oliver Neukum <oliver@neukum.org> Date: Thu, 3 Dec 2009 14:02:48 +0100 > Am Donnerstag, 3. Dezember 2009 11:14:56 schrieb David Miller: > >> It doesn't apply to my tree still: > > And this is autosuspend. Oliver, when you send two patches to the same files you have to make it so that when the first one is applied the second one applies cleanly on top. That's not what happens here: davem@sunset:~/src/GIT/net-next-2.6$ git am --signoff bundle-732.mbox Applying: cdc-ether: Implement reset_resume() Applying: usbnet & cdc-ether: autosuspend for online devices error: patch failed: drivers/net/usb/cdc_ether.c:411 error: drivers/net/usb/cdc_ether.c: patch does not apply Patch failed at 0002 usbnet & cdc-ether: autosuspend for online devices When you have resolved this problem run "git am --resolved". If you would prefer to skip this patch, instead run "git am --skip". To restore the original branch and stop patching run "git am --abort". Also, please compose your patch emails correctly, I always have to edit them. The commit message header line should be your subject (with something like "[PATCH 01/02] " or similar prefixed). The body of your email should be the commit message contents and then the patch. If you want to make some extra comments that are not meant to go into the commit message, put a line with just "---" after the commit message (and before the patch), and then add what you want to say. Finally, please capitalize and properly spell words when appropriate. F.e. "imlement" should be "Implement" in the commit header line of the reset_resume() commit. ^ permalink raw reply [flat|nested] 16+ messages in thread
[parent not found: <20091203.123150.182603807.davem-fT/PcQaiUtIeIZ0/mPfg9Q@public.gmane.org>]
* Re: [patch]reset_resume for cdc-ether [not found] ` <20091203.123150.182603807.davem-fT/PcQaiUtIeIZ0/mPfg9Q@public.gmane.org> @ 2009-12-03 21:11 ` Oliver Neukum 2009-12-03 21:12 ` David Miller 0 siblings, 1 reply; 16+ messages in thread From: Oliver Neukum @ 2009-12-03 21:11 UTC (permalink / raw) To: David Miller Cc: torgny.johansson-IzeFyvvaP7pWk0Htik3J/w, david-b-yBeKhBN/0LDR7s880joybQ, netdev-u79uwXL29TY76Z2rM5mHXA, linux-usb-u79uwXL29TY76Z2rM5mHXA Am Donnerstag, 3. Dezember 2009 21:31:50 schrieb David Miller: > The body of your email should be the commit message contents > and then the patch. > > If you want to make some extra comments that are not meant to > go into the commit message, put a line with just "---" after > the commit message (and before the patch), and then add what > you want to say. > > Finally, please capitalize and properly spell words when appropriate. > F.e. "imlement" should be "Implement" in the commit header line of the > reset_resume() commit. > Sorry, I hope the versions I just sent you are OK. Regards Oliver -- To unsubscribe from this list: send the line "unsubscribe linux-usb" in the body of a message to majordomo-u79uwXL29TY76Z2rM5mHXA@public.gmane.org More majordomo info at http://vger.kernel.org/majordomo-info.html ^ permalink raw reply [flat|nested] 16+ messages in thread
* Re: [patch]reset_resume for cdc-ether 2009-12-03 21:11 ` Oliver Neukum @ 2009-12-03 21:12 ` David Miller 0 siblings, 0 replies; 16+ messages in thread From: David Miller @ 2009-12-03 21:12 UTC (permalink / raw) To: oliver; +Cc: torgny.johansson, david-b, netdev, linux-usb From: Oliver Neukum <oliver@neukum.org> Date: Thu, 3 Dec 2009 22:11:34 +0100 > Sorry, I hope the versions I just sent you are OK. Thanks for fixing things up, I'll take a look right now. ^ permalink raw reply [flat|nested] 16+ messages in thread
[parent not found: <200912031056.17103.oliver-GvhC2dPhHPQdnm+yROfE0A@public.gmane.org>]
* RE: [patch]reset_resume for cdc-ether [not found] ` <200912031056.17103.oliver-GvhC2dPhHPQdnm+yROfE0A@public.gmane.org> @ 2009-12-03 14:52 ` Torgny Johansson 0 siblings, 0 replies; 16+ messages in thread From: Torgny Johansson @ 2009-12-03 14:52 UTC (permalink / raw) To: Oliver Neukum, David Miller Cc: david-b-yBeKhBN/0LDR7s880joybQ, netdev-u79uwXL29TY76Z2rM5mHXA, linux-usb-u79uwXL29TY76Z2rM5mHXA Tested-by: Torgny Johansson <torgny.johansson-IzeFyvvaP7pWk0Htik3J/w@public.gmane.org> > -----Original Message----- > From: netdev-owner-u79uwXL29TY76Z2rM5mHXA@public.gmane.org > [mailto:netdev-owner-u79uwXL29TY76Z2rM5mHXA@public.gmane.org] On Behalf Of Oliver Neukum > Sent: den 3 december 2009 10:56 > To: David Miller > Cc: david-b-yBeKhBN/0LDR7s880joybQ@public.gmane.org; netdev-u79uwXL29TY76Z2rM5mHXA@public.gmane.org; > linux-usb-u79uwXL29TY76Z2rM5mHXA@public.gmane.org > Subject: Re: [patch]reset_resume for cdc-ether > > Am Donnerstag, 3. Dezember 2009 07:22:54 schrieb David Miller: > > > I'm going to apply this patch and the USB autosuspend one too. > > > > Actually, neither patch applies to net-next-2.6 > > > > Oliver can you respin your changes and add a proper signoff to the > > autosuspend patch? > > Hi, > > here's autosuspend again. > > Regards > Oliver > > Signed-off-by: Oliver Neukum <oliver-GvhC2dPhHPQdnm+yROfE0A@public.gmane.org> > > -- > > commit 276405340ff17a79f6847174d1e737242df60cb5 > Author: Oliver Neukum <oliver-GvhC2dPhHPQdnm+yROfE0A@public.gmane.org> > Date: Thu Dec 3 10:53:21 2009 +0100 > > usbnet & cdc-ether: autosuspend for online devices > > using remote wakeup and delayed transmission to allow > online device to go into usb autosuspend > minimal alternate support for devices that don't support > remote wakeup > > Signed-off-by: Oliver Neukum <oliver-GvhC2dPhHPQdnm+yROfE0A@public.gmane.org> > > diff --git a/drivers/net/usb/cdc_ether.c > b/drivers/net/usb/cdc_ether.c index 71e65fc..b9493ef 100644 > --- a/drivers/net/usb/cdc_ether.c > +++ b/drivers/net/usb/cdc_ether.c > @@ -411,6 +411,12 @@ static int cdc_bind(struct usbnet *dev, > struct usb_interface *intf) > return 0; > } > > +static int cdc_manage_power(struct usbnet *dev, int on) { > + dev->intf->needs_remote_wakeup = on; > + return 0; > +} > + > static const struct driver_info cdc_info = { > .description = "CDC Ethernet Device", > .flags = FLAG_ETHER, > @@ -418,6 +424,7 @@ static const struct driver_info cdc_info = { > .bind = cdc_bind, > .unbind = usbnet_cdc_unbind, > .status = cdc_status, > + .manage_power = cdc_manage_power, > }; > > static const struct driver_info mbm_info = { @@ -578,6 > +585,7 @@ static struct usb_driver cdc_driver = { > .disconnect = usbnet_disconnect, > .suspend = usbnet_suspend, > .resume = usbnet_resume, > + .supports_autosuspend = 1, > }; > > > diff --git a/drivers/net/usb/usbnet.c > b/drivers/net/usb/usbnet.c index 378da8c..83cdd46 100644 > --- a/drivers/net/usb/usbnet.c > +++ b/drivers/net/usb/usbnet.c > @@ -353,7 +353,8 @@ static void rx_submit (struct usbnet > *dev, struct urb *urb, gfp_t flags) > > if (netif_running (dev->net) > && netif_device_present (dev->net) > - && !test_bit (EVENT_RX_HALT, &dev->flags)) { > + && !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); @@ -611,15 +612,39 @@ > 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); > + if (netif_msg_ifdown(dev)) > + devdbg(dev, "waited for %d urb > completions", > + 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); > > @@ -641,25 +666,8 @@ int usbnet_stop (struct net_device *net) > 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 +680,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; > } > @@ -753,6 +764,12 @@ int usbnet_open (struct net_device *net) > > // 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); > @@ -881,11 +898,16 @@ 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); > + usb_autopm_put_interface(dev->intf); > if (status < 0 > && status != -EPIPE > && status != -ESHUTDOWN) { > if (netif_msg_tx_err (dev)) > +fail_pipe: > deverr (dev, "can't clear tx > halt, status %d", > status); > } else { > @@ -896,11 +918,16 @@ 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); > + usb_autopm_put_interface(dev->intf); > if (status < 0 > && status != -EPIPE > && status != -ESHUTDOWN) { > if (netif_msg_rx_err (dev)) > +fail_halt: > deverr (dev, "can't clear rx > halt, status %d", > status); > } else { > @@ -919,7 +946,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,11 +961,18 @@ 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) { > + usb_autopm_put_interface(dev->intf); > +skip_reset: > devinfo(dev, "link reset failed (%d) > usbnet usb-%s-%s, %s", > retval, > dev->udev->bus->bus_name, > dev->udev->devpath, > info->description); > + } else { > + usb_autopm_put_interface(dev->intf); > } > } > > @@ -971,6 +1010,7 @@ 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); > @@ -987,6 +1027,7 @@ static void tx_complete (struct urb *urb) > } > } > > + usb_autopm_put_interface_async(dev->intf); > urb->dev = NULL; > entry->state = tx_done; > defer_bh(dev, skb, &dev->txq); > @@ -1057,14 +1098,34 @@ 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); > + devdbg(dev, "Delaying transmission for resumption"); > + 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: > + usb_autopm_put_interface_async(dev->intf); > if (netif_msg_tx_err (dev)) > devdbg (dev, "tx: submit urb err %d", retval); > break; > @@ -1088,6 +1149,7 @@ drop: > devdbg (dev, "> tx, len %d, type 0x%x", > length, skb->protocol); > } > +deferred: > return NETDEV_TX_OK; > } > EXPORT_SYMBOL_GPL(usbnet_start_xmit); > @@ -1263,6 +1325,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); > @@ -1380,13 +1443,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 > @@ -1400,10 +1473,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); > diff --git a/include/linux/usb/usbnet.h > b/include/linux/usb/usbnet.h index 86c31b7..a7b92d6 100644 > --- a/include/linux/usb/usbnet.h > +++ b/include/linux/usb/usbnet.h > @@ -55,6 +55,7 @@ struct usbnet { > struct sk_buff_head done; > struct sk_buff_head rxq_pause; > struct urb *interrupt; > + struct usb_anchor deferred; > struct tasklet_struct bh; > > struct work_struct kevent; > @@ -65,6 +66,8 @@ struct usbnet { > # define EVENT_STS_SPLIT 3 > # define EVENT_LINK_RESET 4 > # define EVENT_RX_PAUSED 5 > +# define EVENT_DEV_WAKING 6 > +# define EVENT_DEV_ASLEEP 7 > }; > > static inline struct usb_driver *driver_of(struct > usb_interface *intf) @@ -108,6 +111,9 @@ struct driver_info { > /* see if peer is connected ... can sleep */ > int (*check_connect)(struct usbnet *); > > + /* (dis)activate runtime power management */ > + int (*manage_power)(struct usbnet *, int); > + > /* for status polling */ > void (*status)(struct usbnet *, struct urb *); > > -- > To unsubscribe from this list: send the line "unsubscribe > netdev" in the body of a message to majordomo-u79uwXL29TY76Z2rM5mHXA@public.gmane.org > More majordomo info at http://vger.kernel.org/majordomo-info.html > -- To unsubscribe from this list: send the line "unsubscribe linux-usb" in the body of a message to majordomo-u79uwXL29TY76Z2rM5mHXA@public.gmane.org More majordomo info at http://vger.kernel.org/majordomo-info.html ^ permalink raw reply [flat|nested] 16+ messages in thread
* Re: [patch]reset_resume for cdc-ether [not found] ` <20091202.222254.61468873.davem-fT/PcQaiUtIeIZ0/mPfg9Q@public.gmane.org> 2009-12-03 9:56 ` Oliver Neukum @ 2009-12-03 10:02 ` Oliver Neukum [not found] ` <200912031102.56903.oliver-GvhC2dPhHPQdnm+yROfE0A@public.gmane.org> 1 sibling, 1 reply; 16+ messages in thread From: Oliver Neukum @ 2009-12-03 10:02 UTC (permalink / raw) To: David Miller Cc: david-b-yBeKhBN/0LDR7s880joybQ, netdev-u79uwXL29TY76Z2rM5mHXA, linux-usb-u79uwXL29TY76Z2rM5mHXA Am Donnerstag, 3. Dezember 2009 07:22:54 schrieb David Miller: > > I'm going to apply this patch and the USB autosuspend one too. > > Actually, neither patch applies to net-next-2.6 > > Oliver can you respin your changes and add a proper signoff > to the autosuspend patch? Hi, here's reset_resume() again. Regards Oliver Signed-off-by: Oliver Neukum <oliver-GvhC2dPhHPQdnm+yROfE0A@public.gmane.org> -- commit 0cf82130a576e01d516fcd81a0a6976ab7c49c23 Author: Oliver Neukum <oliver-GvhC2dPhHPQdnm+yROfE0A@public.gmane.org> Date: Thu Dec 3 10:59:20 2009 +0100 cdc-ether:imlement reset_resume() Normal resume can do double duty as reset_resume() for this driver as it keeps no state in the device Signed-off-by: Oliver Neukum <oliver-GvhC2dPhHPQdnm+yROfE0A@public.gmane.org> diff --git a/drivers/net/usb/cdc_ether.c b/drivers/net/usb/cdc_ether.c index b9493ef..50b8aa9 100644 --- a/drivers/net/usb/cdc_ether.c +++ b/drivers/net/usb/cdc_ether.c @@ -585,6 +585,7 @@ static struct usb_driver cdc_driver = { .disconnect = usbnet_disconnect, .suspend = usbnet_suspend, .resume = usbnet_resume, + .reset_resume = usbnet_resume, .supports_autosuspend = 1, }; -- To unsubscribe from this list: send the line "unsubscribe linux-usb" in the body of a message to majordomo-u79uwXL29TY76Z2rM5mHXA@public.gmane.org More majordomo info at http://vger.kernel.org/majordomo-info.html ^ permalink raw reply related [flat|nested] 16+ messages in thread
[parent not found: <200912031102.56903.oliver-GvhC2dPhHPQdnm+yROfE0A@public.gmane.org>]
* Re: [patch]reset_resume for cdc-ether [not found] ` <200912031102.56903.oliver-GvhC2dPhHPQdnm+yROfE0A@public.gmane.org> @ 2009-12-03 10:15 ` David Miller 0 siblings, 0 replies; 16+ messages in thread From: David Miller @ 2009-12-03 10:15 UTC (permalink / raw) To: oliver-GvhC2dPhHPQdnm+yROfE0A Cc: david-b-yBeKhBN/0LDR7s880joybQ, netdev-u79uwXL29TY76Z2rM5mHXA, linux-usb-u79uwXL29TY76Z2rM5mHXA From: Oliver Neukum <oliver-GvhC2dPhHPQdnm+yROfE0A@public.gmane.org> Date: Thu, 3 Dec 2009 11:02:56 +0100 > here's reset_resume() again. Also doesn't apply. davem@sunset:~/src/GIT/net-next-2.6$ git apply --check --whitespace=error-all diff error: patch failed: drivers/net/usb/cdc_ether.c:585 error: drivers/net/usb/cdc_ether.c: patch does not apply You have new mail in /var/mail/davem davem@sunset:~/src/GIT/net-next-2.6$ -- To unsubscribe from this list: send the line "unsubscribe linux-usb" in the body of a message to majordomo-u79uwXL29TY76Z2rM5mHXA@public.gmane.org More majordomo info at http://vger.kernel.org/majordomo-info.html ^ permalink raw reply [flat|nested] 16+ messages in thread
end of thread, other threads:[~2009-12-03 21:12 UTC | newest]
Thread overview: 16+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2009-11-24 10:59 [patch]reset_resume for cdc-ether Oliver Neukum
2009-11-29 8:18 ` David Miller
2009-12-03 6:16 ` David Miller
[not found] ` <20091202.221627.133392199.davem-fT/PcQaiUtIeIZ0/mPfg9Q@public.gmane.org>
2009-12-03 6:22 ` David Miller
[not found] ` <20091202.222254.61468873.davem-fT/PcQaiUtIeIZ0/mPfg9Q@public.gmane.org>
2009-12-03 9:56 ` Oliver Neukum
2009-12-03 10:14 ` David Miller
2009-12-03 10:26 ` Oliver Neukum
2009-12-03 10:33 ` David Miller
2009-12-03 13:01 ` Oliver Neukum
2009-12-03 13:02 ` Oliver Neukum
2009-12-03 20:31 ` David Miller
[not found] ` <20091203.123150.182603807.davem-fT/PcQaiUtIeIZ0/mPfg9Q@public.gmane.org>
2009-12-03 21:11 ` Oliver Neukum
2009-12-03 21:12 ` David Miller
[not found] ` <200912031056.17103.oliver-GvhC2dPhHPQdnm+yROfE0A@public.gmane.org>
2009-12-03 14:52 ` Torgny Johansson
2009-12-03 10:02 ` Oliver Neukum
[not found] ` <200912031102.56903.oliver-GvhC2dPhHPQdnm+yROfE0A@public.gmane.org>
2009-12-03 10:15 ` David Miller
This is a public inbox, see mirroring instructions for how to clone and mirror all data and code used for this inbox