* [PATCH v2] usbnet: enable more aggressive autosuspend
@ 2008-10-23 13:49 Per Hallsmark
2008-10-23 18:57 ` Alan Stern
[not found] ` <490080F1.1060107-8A+B91M1NdOzQB+pC5nmwQ@public.gmane.org>
0 siblings, 2 replies; 11+ messages in thread
From: Per Hallsmark @ 2008-10-23 13:49 UTC (permalink / raw)
To: linux-usb-u79uwXL29TY76Z2rM5mHXA
Cc: netdev-u79uwXL29TY76Z2rM5mHXA, david-b-yBeKhBN/0LDR7s880joybQ
[-- Attachment #1: Type: text/plain, Size: 156 bytes --]
Enable more aggressive autosuspend in usbnet.
Some commenting and cleanups done.
Signed-off-by: Per Hallsmark <per-46Ss7X5r2El6nIa31vAvqA@public.gmane.org>
[-- Attachment #2: usbnet_autosuspend_v2.patch --]
[-- Type: text/plain, Size: 7751 bytes --]
diff --git a/drivers/net/usb/usbnet.c b/drivers/net/usb/usbnet.c
index 8463efb..a2f0c8b 100644
--- a/drivers/net/usb/usbnet.c
+++ b/drivers/net/usb/usbnet.c
@@ -87,6 +87,8 @@ static int msg_level = -1;
module_param (msg_level, int, 0);
MODULE_PARM_DESC (msg_level, "Override default message level");
+static void waker(struct work_struct *work);
+
/*-------------------------------------------------------------------------*/
/* handles CDC Ethernet and many other network "bulk data" interfaces */
@@ -325,6 +327,7 @@ 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)) {
+ usb_mark_last_busy(dev->udev);
switch (retval = usb_submit_urb (urb, GFP_ATOMIC)) {
case -EPIPE:
usbnet_defer_kevent (dev, EVENT_RX_HALT);
@@ -496,6 +499,7 @@ static void intr_complete (struct urb *urb)
return;
memset(urb->transfer_buffer, 0, urb->transfer_buffer_length);
+ usb_mark_last_busy(dev->udev);
status = usb_submit_urb (urb, GFP_ATOMIC);
if (status != 0 && netif_msg_timer (dev))
deverr(dev, "intr resubmit --> %d", status);
@@ -589,6 +593,10 @@ static int usbnet_stop (struct net_device *net)
dev->flags = 0;
del_timer_sync (&dev->delay);
tasklet_kill (&dev->bh);
+
+ dev->used--;
+
+ dev->intf->needs_remote_wakeup = 0;
usb_autopm_put_interface(dev->intf);
return 0;
@@ -669,6 +677,11 @@ static int usbnet_open (struct net_device *net)
// delay posting reads until we're fully open
tasklet_schedule (&dev->bh);
+
+ dev->used++;
+
+ dev->intf->needs_remote_wakeup = 1;
+ usb_autopm_put_interface(dev->intf);
return retval;
done:
usb_autopm_put_interface(dev->intf);
@@ -921,7 +934,7 @@ static void usbnet_tx_timeout (struct net_device *net)
/*-------------------------------------------------------------------------*/
-static int usbnet_start_xmit (struct sk_buff *skb, struct net_device *net)
+static int __usbnet_start_xmit (struct sk_buff *skb, struct net_device *net)
{
struct usbnet *dev = netdev_priv(net);
int length;
@@ -955,6 +968,7 @@ static int usbnet_start_xmit (struct sk_buff *skb, struct net_device *net)
entry->state = tx_start;
entry->length = length;
+ dev->tx_goingon = 1;
usb_fill_bulk_urb (urb, dev->udev, dev->out,
skb->data, skb->len, tx_complete, skb);
@@ -972,6 +986,7 @@ static int usbnet_start_xmit (struct sk_buff *skb, struct net_device *net)
spin_lock_irqsave (&dev->txq.lock, flags);
+ usb_mark_last_busy(dev->udev);
switch ((retval = usb_submit_urb (urb, GFP_ATOMIC))) {
case -EPIPE:
netif_stop_queue (net);
@@ -1005,6 +1020,28 @@ drop:
return retval;
}
+static int usbnet_start_xmit(struct sk_buff *skb, struct net_device *net)
+{
+ struct usbnet *dev = netdev_priv(net);
+ int retval;
+ unsigned long flags;
+
+ spin_lock_irqsave(&dev->txq.lock, flags);
+ if (dev->suspend_count) {
+ netif_stop_queue(net);
+ dev->tx_skb = skb;
+ if (!schedule_work (&dev->waker))
+ deverr(dev, "waker may have been dropped");
+ else
+ devdbg(dev, "waker scheduled");
+ spin_unlock_irqrestore(&dev->txq.lock, flags);
+ return NET_XMIT_SUCCESS;
+ }
+ spin_unlock_irqrestore(&dev->txq.lock, flags);
+
+ retval = __usbnet_start_xmit(skb, net);
+ return retval;
+}
/*-------------------------------------------------------------------------*/
@@ -1024,6 +1061,8 @@ static void usbnet_bh (unsigned long param)
rx_process (dev, skb);
continue;
case tx_done:
+ dev->tx_goingon = 0;
+ /* fall through */
case rx_cleanup:
usb_free_urb (entry->urb);
dev_kfree_skb (skb);
@@ -1043,6 +1082,7 @@ static void usbnet_bh (unsigned long param)
} else if (netif_running (dev->net)
&& netif_device_present (dev->net)
&& !timer_pending (&dev->delay)
+ && !dev->suspend_count
&& !test_bit (EVENT_RX_HALT, &dev->flags)) {
int temp = dev->rxq.qlen;
int qlen = RX_QLEN (dev);
@@ -1161,6 +1201,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_WORK (&dev->waker, waker);
dev->delay.function = usbnet_bh;
dev->delay.data = (unsigned long) dev;
init_timer (&dev->delay);
@@ -1269,24 +1313,66 @@ EXPORT_SYMBOL_GPL(usbnet_probe);
* resume only when the last interface is resumed
*/
+static void waker(struct work_struct *work)
+{
+ struct usbnet *dev = container_of(work, struct usbnet, waker);
+
+ if (!usb_autopm_get_interface(dev->intf)) {
+ usb_autopm_put_interface(dev->intf);
+ } else {
+ devdbg(dev, "autoresume failed");
+ }
+}
+
+static void stop_traffic(struct usbnet *dev)
+{
+ int temp;
+ DECLARE_WAIT_QUEUE_HEAD_ONSTACK (unlink_wakeup);
+ DECLARE_WAITQUEUE (wait, current);
+
+ /* 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);
+
+ usb_kill_urb(dev->interrupt);
+}
+
int usbnet_suspend (struct usb_interface *intf, pm_message_t message)
{
- struct usbnet *dev = usb_get_intfdata(intf);
+ struct usbnet *dev = usb_get_intfdata(intf);
- if (!dev->suspend_count++) {
- /*
- * 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);
- /*
- * reattach so runtime management can use and
- * wake the device
- */
- netif_device_attach (dev->net);
+ devdbg(dev, "%s: begin", __FUNCTION__);
+
+ if (dev->suspend_count++)
+ return 0;
+
+ /* check for ongoing tx traffic */
+ if (dev->tx_goingon && dev->udev->auto_pm) {
+ dev->suspend_count--;
+ return -EBUSY;
}
+
+ stop_traffic(dev);
+
+ /* cancel work */
+ dev->flags = 0;
+ del_timer_sync(&dev->delay);
+ cancel_work_sync(&dev->kevent);
+
+ devdbg(dev, "%s: end", __FUNCTION__);
+
return 0;
}
EXPORT_SYMBOL_GPL(usbnet_suspend);
@@ -1294,9 +1380,32 @@ EXPORT_SYMBOL_GPL(usbnet_suspend);
int usbnet_resume (struct usb_interface *intf)
{
struct usbnet *dev = usb_get_intfdata(intf);
+ int status;
+
+ devdbg(dev, "%s: begin", __FUNCTION__);
+
+ if (--dev->suspend_count)
+ return 0;
+
+ status = init_status (dev, dev->intf);
+ if (dev->interrupt) {
+ status = usb_submit_urb (dev->interrupt, GFP_KERNEL);
+ if (status < 0) {
+ devdbg(dev, "failed restarting interrupt urb");
+ }
+ }
+
+ tasklet_schedule(&dev->bh);
+
+ /* transmit package that triggered resume */
+ if (dev->tx_skb) {
+ status = __usbnet_start_xmit(dev->tx_skb, dev->net);
+ dev->tx_skb = NULL;
+ }
+
+ netif_wake_queue(dev->net);
- if (!--dev->suspend_count)
- tasklet_schedule (&dev->bh);
+ devdbg(dev, "%s: end", __FUNCTION__);
return 0;
}
diff --git a/include/linux/usb/usbnet.h b/include/linux/usb/usbnet.h
index ba09fe8..93f3625 100644
--- a/include/linux/usb/usbnet.h
+++ b/include/linux/usb/usbnet.h
@@ -64,6 +64,12 @@ struct usbnet {
# define EVENT_RX_MEMORY 2
# define EVENT_STS_SPLIT 3
# define EVENT_LINK_RESET 4
+
+ /* autosuspend helpers */
+ struct work_struct waker;
+ int used;
+ int tx_goingon;
+ struct sk_buff *tx_skb; /* skb queued during suspend */
};
static inline struct usb_driver *driver_of(struct usb_interface *intf)
^ permalink raw reply related [flat|nested] 11+ messages in thread* Re: [PATCH v2] usbnet: enable more aggressive autosuspend 2008-10-23 13:49 [PATCH v2] usbnet: enable more aggressive autosuspend Per Hallsmark @ 2008-10-23 18:57 ` Alan Stern [not found] ` <Pine.LNX.4.44L0.0810231455020.18234-100000-IYeN2dnnYyZXsRXLowluHWD2FQJk+8+b@public.gmane.org> [not found] ` <490080F1.1060107-8A+B91M1NdOzQB+pC5nmwQ@public.gmane.org> 1 sibling, 1 reply; 11+ messages in thread From: Alan Stern @ 2008-10-23 18:57 UTC (permalink / raw) To: Per Hallsmark; +Cc: USB list, netdev, David Brownell On Thu, 23 Oct 2008, Per Hallsmark wrote: > Enable more aggressive autosuspend in usbnet. > Some commenting and cleanups done. > Signed-off-by: Per Hallsmark <per@hallsmark.se> I've been considering submitting the patch below. It would help your work; you could remove all the "waker" stuff. Do you think it would be worthwhile? Alan Stern Index: usb-2.6/Documentation/usb/power-management.txt =================================================================== --- usb-2.6.orig/Documentation/usb/power-management.txt +++ usb-2.6/Documentation/usb/power-management.txt @@ -313,11 +313,13 @@ three of the methods listed above. In a that it supports autosuspend by setting the .supports_autosuspend flag in its usb_driver structure. It is then responsible for informing the USB core whenever one of its interfaces becomes busy or idle. The -driver does so by calling these three functions: +driver does so by calling these five functions: int usb_autopm_get_interface(struct usb_interface *intf); void usb_autopm_put_interface(struct usb_interface *intf); int usb_autopm_set_interface(struct usb_interface *intf); + int usb_autopm_get_interface_async(struct usb_interface *intf); + void usb_autopm_put_interface_async(struct usb_interface *intf); The functions work by maintaining a counter in the usb_interface structure. When intf->pm_usage_count is > 0 then the interface is @@ -330,10 +332,12 @@ associated with the device itself rather This field is used only by the USB core.) The driver owns intf->pm_usage_count; it can modify the value however -and whenever it likes. A nice aspect of the usb_autopm_* routines is -that the changes they make are protected by the usb_device structure's -PM mutex (udev->pm_mutex); however drivers may change pm_usage_count -without holding the mutex. +and whenever it likes. A nice aspect of the non-async usb_autopm_* +routines is that the changes they make are protected by the usb_device +structure's PM mutex (udev->pm_mutex); however drivers may change +pm_usage_count without holding the mutex. Drivers using the async +routines are responsible for their own synchronization and mutual +exclusion. usb_autopm_get_interface() increments pm_usage_count and attempts an autoresume if the new value is > 0 and the @@ -348,6 +352,14 @@ without holding the mutex. is suspended, and it attempts an autosuspend if the value is <= 0 and the device isn't suspended. + usb_autopm_get_interface_async() and + usb_autopm_put_interface_async() do almost the same things as + their non-async counterparts. The differences are: they do + not acquire the PM mutex, and they use a workqueue to do their + jobs. As a result they can be called in an atomic context, + such as an URB's completion handler, but when they return the + device will not generally not yet be in the desired state. + There also are a couple of utility routines drivers can use: usb_autopm_enable() sets pm_usage_cnt to 0 and then calls Index: usb-2.6/include/linux/usb.h =================================================================== --- usb-2.6.orig/include/linux/usb.h +++ usb-2.6/include/linux/usb.h @@ -396,6 +396,7 @@ struct usb_tt; * @urbnum: number of URBs submitted for the whole device * @active_duration: total time device is not suspended * @autosuspend: for delayed autosuspends + * @autoresume: for autoresumes requested while in_interrupt * @pm_mutex: protects PM operations * @last_busy: time of last use * @autosuspend_delay: in jiffies @@ -474,6 +475,7 @@ struct usb_device { #ifdef CONFIG_PM struct delayed_work autosuspend; + struct work_struct autoresume; struct mutex pm_mutex; unsigned long last_busy; @@ -511,6 +513,8 @@ extern struct usb_device *usb_find_devic extern int usb_autopm_set_interface(struct usb_interface *intf); extern int usb_autopm_get_interface(struct usb_interface *intf); extern void usb_autopm_put_interface(struct usb_interface *intf); +extern int usb_autopm_get_interface_async(struct usb_interface *intf); +extern void usb_autopm_put_interface_async(struct usb_interface *intf); static inline void usb_autopm_enable(struct usb_interface *intf) { @@ -537,8 +541,13 @@ static inline int usb_autopm_set_interfa static inline int usb_autopm_get_interface(struct usb_interface *intf) { return 0; } +static inline int usb_autopm_get_interface_async(struct usb_interface *intf) +{ return 0; } + static inline void usb_autopm_put_interface(struct usb_interface *intf) { } +static inline void usb_autopm_put_interface_async(struct usb_interface *intf) +{ } static inline void usb_autopm_enable(struct usb_interface *intf) { } static inline void usb_autopm_disable(struct usb_interface *intf) Index: usb-2.6/drivers/usb/core/usb.h =================================================================== --- usb-2.6.orig/drivers/usb/core/usb.h +++ usb-2.6/drivers/usb/core/usb.h @@ -45,6 +45,7 @@ extern int usb_suspend(struct device *de extern int usb_resume(struct device *dev); extern void usb_autosuspend_work(struct work_struct *work); +extern void usb_autoresume_work(struct work_struct *work); extern int usb_port_suspend(struct usb_device *dev); extern int usb_port_resume(struct usb_device *dev); extern int usb_external_suspend_device(struct usb_device *udev, Index: usb-2.6/drivers/usb/core/usb.c =================================================================== --- usb-2.6.orig/drivers/usb/core/usb.c +++ usb-2.6/drivers/usb/core/usb.c @@ -402,6 +402,7 @@ struct usb_device *usb_alloc_dev(struct #ifdef CONFIG_PM mutex_init(&dev->pm_mutex); INIT_DELAYED_WORK(&dev->autosuspend, usb_autosuspend_work); + INIT_WORK(&dev->autoresume, usb_autoresume_work); dev->autosuspend_delay = usb_autosuspend_delay * HZ; dev->connect_time = jiffies; dev->active_duration = -jiffies; Index: usb-2.6/drivers/usb/core/hub.c =================================================================== --- usb-2.6.orig/drivers/usb/core/hub.c +++ usb-2.6/drivers/usb/core/hub.c @@ -1362,8 +1362,9 @@ static void usb_stop_pm(struct usb_devic usb_autosuspend_device(udev->parent); usb_pm_unlock(udev); - /* Stop any autosuspend requests already submitted */ - cancel_rearming_delayed_work(&udev->autosuspend); + /* Stop any autosuspend or autoresume requests already submitted */ + cancel_delayed_work_sync(&udev->autosuspend); + cancel_work_sync(&udev->autoresume); } #else Index: usb-2.6/drivers/usb/core/driver.c =================================================================== --- usb-2.6.orig/drivers/usb/core/driver.c +++ usb-2.6/drivers/usb/core/driver.c @@ -1339,6 +1339,19 @@ void usb_autosuspend_work(struct work_st usb_autopm_do_device(udev, 0); } +/* usb_autoresume_work - callback routine to autoresume a USB device */ +void usb_autoresume_work(struct work_struct *work) +{ + struct usb_device *udev = + container_of(work, struct usb_device, autoresume); + + /* Wake it up, let the drivers do their thing, and then put it + * back to sleep. + */ + if (usb_autopm_do_device(udev, 1) == 0) + usb_autopm_do_device(udev, -1); +} + /** * usb_autosuspend_device - delayed autosuspend of a USB device and its interfaces * @udev: the usb_device to autosuspend @@ -1490,6 +1503,45 @@ void usb_autopm_put_interface(struct usb EXPORT_SYMBOL_GPL(usb_autopm_put_interface); /** + * usb_autopm_put_interface_async - decrement a USB interface's PM-usage counter + * @intf: the usb_interface whose counter should be decremented + * + * This routine does essentially the same thing as + * usb_autopm_put_interface(): it decrements @intf's usage counter and + * queues a delayed autosuspend request if the counter is <= 0. The + * difference is that it does not acquire the device's pm_mutex; + * callers must handle all synchronization issues themselves. + * + * Typically a driver would call this routine during an URB's completion + * handler, if no more URBs were pending. + * + * This routine can run in atomic context. + */ +void usb_autopm_put_interface_async(struct usb_interface *intf) +{ + struct usb_device *udev = interface_to_usbdev(intf); + int status = 0; + + if (intf->condition == USB_INTERFACE_UNBOUND) { + status = -ENODEV; + } else { + udev->last_busy = jiffies; + --intf->pm_usage_cnt; + if (udev->autosuspend_disabled || udev->autosuspend_delay < 0) + status = -EPERM; + else if (intf->pm_usage_cnt <= 0 && + !timer_pending(&udev->autosuspend.timer)) { + queue_delayed_work(ksuspend_usb_wq, &udev->autosuspend, + round_jiffies_relative( + udev->autosuspend_delay)); + } + } + dev_vdbg(&intf->dev, "%s: status %d cnt %d\n", + __func__, status, intf->pm_usage_cnt); +} +EXPORT_SYMBOL_GPL(usb_autopm_put_interface_async); + +/** * usb_autopm_get_interface - increment a USB interface's PM-usage counter * @intf: the usb_interface whose counter should be incremented * @@ -1535,6 +1587,37 @@ int usb_autopm_get_interface(struct usb_ EXPORT_SYMBOL_GPL(usb_autopm_get_interface); /** + * usb_autopm_get_interface_async - increment a USB interface's PM-usage counter + * @intf: the usb_interface whose counter should be incremented + * + * This routine does much the same thing as + * usb_autopm_get_interface(): it increments @intf's usage counter and + * queues an autoresume request if the result is > 0. The differences + * are that it does not acquire the device's pm_mutex (callers must + * handle all synchronization issues themselves), and it does not + * autoresume the device directly (it only queues a request). After a + * successful call, the device will generally not yet be resumed. + * + * This routine can run in atomic context. + */ +int usb_autopm_get_interface_async(struct usb_interface *intf) +{ + struct usb_device *udev = interface_to_usbdev(intf); + int status = 0; + + if (intf->condition == USB_INTERFACE_UNBOUND) + status = -ENODEV; + else if (udev->autoresume_disabled) + status = -EPERM; + else if (++intf->pm_usage_cnt > 0 && udev->state == USB_STATE_SUSPENDED) + queue_work(ksuspend_usb_wq, &udev->autoresume); + dev_vdbg(&intf->dev, "%s: status %d cnt %d\n", + __func__, status, intf->pm_usage_cnt); + return status; +} +EXPORT_SYMBOL_GPL(usb_autopm_get_interface_async); + +/** * usb_autopm_set_interface - set a USB interface's autosuspend state * @intf: the usb_interface whose state should be set * ^ permalink raw reply [flat|nested] 11+ messages in thread
[parent not found: <Pine.LNX.4.44L0.0810231455020.18234-100000-IYeN2dnnYyZXsRXLowluHWD2FQJk+8+b@public.gmane.org>]
* Re: [PATCH v2] usbnet: enable more aggressive autosuspend [not found] ` <Pine.LNX.4.44L0.0810231455020.18234-100000-IYeN2dnnYyZXsRXLowluHWD2FQJk+8+b@public.gmane.org> @ 2008-10-24 9:21 ` Per Hallsmark 2008-10-24 14:12 ` Alan Stern 0 siblings, 1 reply; 11+ messages in thread From: Per Hallsmark @ 2008-10-24 9:21 UTC (permalink / raw) To: Alan Stern; +Cc: USB list, netdev-u79uwXL29TY76Z2rM5mHXA, David Brownell Alan Stern wrote: > On Thu, 23 Oct 2008, Per Hallsmark wrote: > > >> Enable more aggressive autosuspend in usbnet. >> Some commenting and cleanups done. >> Signed-off-by: Per Hallsmark <per-46Ss7X5r2El6nIa31vAvqA@public.gmane.org> >> > > I've been considering submitting the patch below. It would help your > work; you could remove all the "waker" stuff. > So, if I understand the patch correctly, the waker's in cdc-acm, cdc-wdm and usbnet could then be removed and a change to use *_async() should be done? I work with a module that have usb interfaces driven by above three drivers so it could be a good testing case I guess. Generic solutions are the best so if this approach would work then of course a change should be made I think. I have no time to test it in near time though, perhaps later next week. > Do you think it would be worthwhile? > > Alan Stern > > > > Index: usb-2.6/Documentation/usb/power-management.txt > =================================================================== > --- usb-2.6.orig/Documentation/usb/power-management.txt > +++ usb-2.6/Documentation/usb/power-management.txt > @@ -313,11 +313,13 @@ three of the methods listed above. In a > that it supports autosuspend by setting the .supports_autosuspend flag > in its usb_driver structure. It is then responsible for informing the > USB core whenever one of its interfaces becomes busy or idle. The > -driver does so by calling these three functions: > +driver does so by calling these five functions: > > int usb_autopm_get_interface(struct usb_interface *intf); > void usb_autopm_put_interface(struct usb_interface *intf); > int usb_autopm_set_interface(struct usb_interface *intf); > + int usb_autopm_get_interface_async(struct usb_interface *intf); > + void usb_autopm_put_interface_async(struct usb_interface *intf); > > The functions work by maintaining a counter in the usb_interface > structure. When intf->pm_usage_count is > 0 then the interface is > @@ -330,10 +332,12 @@ associated with the device itself rather > This field is used only by the USB core.) > > The driver owns intf->pm_usage_count; it can modify the value however > -and whenever it likes. A nice aspect of the usb_autopm_* routines is > -that the changes they make are protected by the usb_device structure's > -PM mutex (udev->pm_mutex); however drivers may change pm_usage_count > -without holding the mutex. > +and whenever it likes. A nice aspect of the non-async usb_autopm_* > +routines is that the changes they make are protected by the usb_device > +structure's PM mutex (udev->pm_mutex); however drivers may change > +pm_usage_count without holding the mutex. Drivers using the async > +routines are responsible for their own synchronization and mutual > +exclusion. > > usb_autopm_get_interface() increments pm_usage_count and > attempts an autoresume if the new value is > 0 and the > @@ -348,6 +352,14 @@ without holding the mutex. > is suspended, and it attempts an autosuspend if the value is > <= 0 and the device isn't suspended. > > + usb_autopm_get_interface_async() and > + usb_autopm_put_interface_async() do almost the same things as > + their non-async counterparts. The differences are: they do > + not acquire the PM mutex, and they use a workqueue to do their > + jobs. As a result they can be called in an atomic context, > + such as an URB's completion handler, but when they return the > + device will not generally not yet be in the desired state. > + > There also are a couple of utility routines drivers can use: > > usb_autopm_enable() sets pm_usage_cnt to 0 and then calls > Index: usb-2.6/include/linux/usb.h > =================================================================== > --- usb-2.6.orig/include/linux/usb.h > +++ usb-2.6/include/linux/usb.h > @@ -396,6 +396,7 @@ struct usb_tt; > * @urbnum: number of URBs submitted for the whole device > * @active_duration: total time device is not suspended > * @autosuspend: for delayed autosuspends > + * @autoresume: for autoresumes requested while in_interrupt > * @pm_mutex: protects PM operations > * @last_busy: time of last use > * @autosuspend_delay: in jiffies > @@ -474,6 +475,7 @@ struct usb_device { > > #ifdef CONFIG_PM > struct delayed_work autosuspend; > + struct work_struct autoresume; > struct mutex pm_mutex; > > unsigned long last_busy; > @@ -511,6 +513,8 @@ extern struct usb_device *usb_find_devic > extern int usb_autopm_set_interface(struct usb_interface *intf); > extern int usb_autopm_get_interface(struct usb_interface *intf); > extern void usb_autopm_put_interface(struct usb_interface *intf); > +extern int usb_autopm_get_interface_async(struct usb_interface *intf); > +extern void usb_autopm_put_interface_async(struct usb_interface *intf); > > static inline void usb_autopm_enable(struct usb_interface *intf) > { > @@ -537,8 +541,13 @@ static inline int usb_autopm_set_interfa > static inline int usb_autopm_get_interface(struct usb_interface *intf) > { return 0; } > > +static inline int usb_autopm_get_interface_async(struct usb_interface *intf) > +{ return 0; } > + > static inline void usb_autopm_put_interface(struct usb_interface *intf) > { } > +static inline void usb_autopm_put_interface_async(struct usb_interface *intf) > +{ } > static inline void usb_autopm_enable(struct usb_interface *intf) > { } > static inline void usb_autopm_disable(struct usb_interface *intf) > Index: usb-2.6/drivers/usb/core/usb.h > =================================================================== > --- usb-2.6.orig/drivers/usb/core/usb.h > +++ usb-2.6/drivers/usb/core/usb.h > @@ -45,6 +45,7 @@ extern int usb_suspend(struct device *de > extern int usb_resume(struct device *dev); > > extern void usb_autosuspend_work(struct work_struct *work); > +extern void usb_autoresume_work(struct work_struct *work); > extern int usb_port_suspend(struct usb_device *dev); > extern int usb_port_resume(struct usb_device *dev); > extern int usb_external_suspend_device(struct usb_device *udev, > Index: usb-2.6/drivers/usb/core/usb.c > =================================================================== > --- usb-2.6.orig/drivers/usb/core/usb.c > +++ usb-2.6/drivers/usb/core/usb.c > @@ -402,6 +402,7 @@ struct usb_device *usb_alloc_dev(struct > #ifdef CONFIG_PM > mutex_init(&dev->pm_mutex); > INIT_DELAYED_WORK(&dev->autosuspend, usb_autosuspend_work); > + INIT_WORK(&dev->autoresume, usb_autoresume_work); > dev->autosuspend_delay = usb_autosuspend_delay * HZ; > dev->connect_time = jiffies; > dev->active_duration = -jiffies; > Index: usb-2.6/drivers/usb/core/hub.c > =================================================================== > --- usb-2.6.orig/drivers/usb/core/hub.c > +++ usb-2.6/drivers/usb/core/hub.c > @@ -1362,8 +1362,9 @@ static void usb_stop_pm(struct usb_devic > usb_autosuspend_device(udev->parent); > usb_pm_unlock(udev); > > - /* Stop any autosuspend requests already submitted */ > - cancel_rearming_delayed_work(&udev->autosuspend); > + /* Stop any autosuspend or autoresume requests already submitted */ > + cancel_delayed_work_sync(&udev->autosuspend); > + cancel_work_sync(&udev->autoresume); > } > > #else > Index: usb-2.6/drivers/usb/core/driver.c > =================================================================== > --- usb-2.6.orig/drivers/usb/core/driver.c > +++ usb-2.6/drivers/usb/core/driver.c > @@ -1339,6 +1339,19 @@ void usb_autosuspend_work(struct work_st > usb_autopm_do_device(udev, 0); > } > > +/* usb_autoresume_work - callback routine to autoresume a USB device */ > +void usb_autoresume_work(struct work_struct *work) > +{ > + struct usb_device *udev = > + container_of(work, struct usb_device, autoresume); > + > + /* Wake it up, let the drivers do their thing, and then put it > + * back to sleep. > + */ > + if (usb_autopm_do_device(udev, 1) == 0) > + usb_autopm_do_device(udev, -1); > +} > + > /** > * usb_autosuspend_device - delayed autosuspend of a USB device and its interfaces > * @udev: the usb_device to autosuspend > @@ -1490,6 +1503,45 @@ void usb_autopm_put_interface(struct usb > EXPORT_SYMBOL_GPL(usb_autopm_put_interface); > > /** > + * usb_autopm_put_interface_async - decrement a USB interface's PM-usage counter > + * @intf: the usb_interface whose counter should be decremented > + * > + * This routine does essentially the same thing as > + * usb_autopm_put_interface(): it decrements @intf's usage counter and > + * queues a delayed autosuspend request if the counter is <= 0. The > + * difference is that it does not acquire the device's pm_mutex; > + * callers must handle all synchronization issues themselves. > + * > + * Typically a driver would call this routine during an URB's completion > + * handler, if no more URBs were pending. > + * > + * This routine can run in atomic context. > + */ > +void usb_autopm_put_interface_async(struct usb_interface *intf) > +{ > + struct usb_device *udev = interface_to_usbdev(intf); > + int status = 0; > + > + if (intf->condition == USB_INTERFACE_UNBOUND) { > + status = -ENODEV; > + } else { > + udev->last_busy = jiffies; > + --intf->pm_usage_cnt; > + if (udev->autosuspend_disabled || udev->autosuspend_delay < 0) > + status = -EPERM; > + else if (intf->pm_usage_cnt <= 0 && > + !timer_pending(&udev->autosuspend.timer)) { > + queue_delayed_work(ksuspend_usb_wq, &udev->autosuspend, > + round_jiffies_relative( > + udev->autosuspend_delay)); > + } > + } > + dev_vdbg(&intf->dev, "%s: status %d cnt %d\n", > + __func__, status, intf->pm_usage_cnt); > +} > +EXPORT_SYMBOL_GPL(usb_autopm_put_interface_async); > + > +/** > * usb_autopm_get_interface - increment a USB interface's PM-usage counter > * @intf: the usb_interface whose counter should be incremented > * > @@ -1535,6 +1587,37 @@ int usb_autopm_get_interface(struct usb_ > EXPORT_SYMBOL_GPL(usb_autopm_get_interface); > > /** > + * usb_autopm_get_interface_async - increment a USB interface's PM-usage counter > + * @intf: the usb_interface whose counter should be incremented > + * > + * This routine does much the same thing as > + * usb_autopm_get_interface(): it increments @intf's usage counter and > + * queues an autoresume request if the result is > 0. The differences > + * are that it does not acquire the device's pm_mutex (callers must > + * handle all synchronization issues themselves), and it does not > + * autoresume the device directly (it only queues a request). After a > + * successful call, the device will generally not yet be resumed. > + * > + * This routine can run in atomic context. > + */ > +int usb_autopm_get_interface_async(struct usb_interface *intf) > +{ > + struct usb_device *udev = interface_to_usbdev(intf); > + int status = 0; > + > + if (intf->condition == USB_INTERFACE_UNBOUND) > + status = -ENODEV; > + else if (udev->autoresume_disabled) > + status = -EPERM; > + else if (++intf->pm_usage_cnt > 0 && udev->state == USB_STATE_SUSPENDED) > + queue_work(ksuspend_usb_wq, &udev->autoresume); > + dev_vdbg(&intf->dev, "%s: status %d cnt %d\n", > + __func__, status, intf->pm_usage_cnt); > + return status; > +} > +EXPORT_SYMBOL_GPL(usb_autopm_get_interface_async); > + > +/** > * usb_autopm_set_interface - set a USB interface's autosuspend state > * @intf: the usb_interface whose state should be set > * > > -- 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] 11+ messages in thread
* Re: [PATCH v2] usbnet: enable more aggressive autosuspend 2008-10-24 9:21 ` Per Hallsmark @ 2008-10-24 14:12 ` Alan Stern 0 siblings, 0 replies; 11+ messages in thread From: Alan Stern @ 2008-10-24 14:12 UTC (permalink / raw) To: Per Hallsmark; +Cc: USB list, netdev, David Brownell On Fri, 24 Oct 2008, Per Hallsmark wrote: > Alan Stern wrote: > > On Thu, 23 Oct 2008, Per Hallsmark wrote: > > > > > >> Enable more aggressive autosuspend in usbnet. > >> Some commenting and cleanups done. > >> Signed-off-by: Per Hallsmark <per@hallsmark.se> > >> > > > > I've been considering submitting the patch below. It would help your > > work; you could remove all the "waker" stuff. > > > So, if I understand the patch correctly, the waker's in cdc-acm, cdc-wdm > and usbnet > could then be removed and a change to use *_async() should be done? That's right. There are a few races you have to worry about (maybe they're already taken into account -- I'm not familiar with these drivers): What happens if a new URB has to be submitted at about the same time as an autosuspend occurs? What happens if you call one of the *_async() routines at the same time as some other CPU updates intf->pm_usage_count? > I work with a module that have usb interfaces driven by above three > drivers so it > could be a good testing case I guess. > Generic solutions are the best so if this approach would work then of > course a > change should be made I think. I have no time to test it in near time > though, > perhaps later next week. Okay, let me know how it turns out. Alan Stern ^ permalink raw reply [flat|nested] 11+ messages in thread
[parent not found: <490080F1.1060107-8A+B91M1NdOzQB+pC5nmwQ@public.gmane.org>]
* Re: [PATCH v2] usbnet: enable more aggressive autosuspend [not found] ` <490080F1.1060107-8A+B91M1NdOzQB+pC5nmwQ@public.gmane.org> @ 2008-11-07 8:26 ` Jeff Garzik 2008-11-07 11:44 ` Oliver Neukum 0 siblings, 1 reply; 11+ messages in thread From: Jeff Garzik @ 2008-11-07 8:26 UTC (permalink / raw) To: Per Hallsmark Cc: linux-usb-u79uwXL29TY76Z2rM5mHXA, netdev-u79uwXL29TY76Z2rM5mHXA, david-b-yBeKhBN/0LDR7s880joybQ Per Hallsmark wrote: > Enable more aggressive autosuspend in usbnet. > Some commenting and cleanups done. > Signed-off-by: Per Hallsmark <per-46Ss7X5r2El6nIa31vAvqA@public.gmane.org> Actually, this breaks the !CONFIG_PM build: drivers/net/usb/usbnet.c: In function 'usbnet_suspend': drivers/net/usb/usbnet.c:1357: error: 'struct usb_device' has no member named 'auto_pm' I pondered taking the easy route of fixing this by surrounding the auto_pm reference with an ifdef, but it seems like usbnet could use a bit more thought -- it is questionable whether usbnet_suspend/resume should be built at all, if !CONFIG_PM, even though they are exported. Jeff -- 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] 11+ messages in thread
* Re: [PATCH v2] usbnet: enable more aggressive autosuspend 2008-11-07 8:26 ` Jeff Garzik @ 2008-11-07 11:44 ` Oliver Neukum 2008-11-07 12:00 ` Jeff Garzik 0 siblings, 1 reply; 11+ messages in thread From: Oliver Neukum @ 2008-11-07 11:44 UTC (permalink / raw) To: Jeff Garzik; +Cc: Per Hallsmark, linux-usb, netdev, david-b Am Freitag, 7. November 2008 09:26:33 schrieb Jeff Garzik: > I pondered taking the easy route of fixing this by surrounding the > auto_pm reference with an ifdef, but it seems like usbnet could use a > bit more thought -- it is questionable whether usbnet_suspend/resume > should be built at all, if !CONFIG_PM, even though they are exported. As this is a generic problem, shouldn't we get the compiler to do this for us? Regards Oliver ^ permalink raw reply [flat|nested] 11+ messages in thread
* Re: [PATCH v2] usbnet: enable more aggressive autosuspend 2008-11-07 11:44 ` Oliver Neukum @ 2008-11-07 12:00 ` Jeff Garzik [not found] ` <49142DC5.8080803-o2qLIJkoznsdnm+yROfE0A@public.gmane.org> 0 siblings, 1 reply; 11+ messages in thread From: Jeff Garzik @ 2008-11-07 12:00 UTC (permalink / raw) To: Oliver Neukum; +Cc: Per Hallsmark, linux-usb, netdev, david-b Oliver Neukum wrote: > Am Freitag, 7. November 2008 09:26:33 schrieb Jeff Garzik: >> I pondered taking the easy route of fixing this by surrounding the >> auto_pm reference with an ifdef, but it seems like usbnet could use a >> bit more thought -- it is questionable whether usbnet_suspend/resume >> should be built at all, if !CONFIG_PM, even though they are exported. > > As this is a generic problem, shouldn't we get the compiler to do > this for us? Can you be more specific? Jeff ^ permalink raw reply [flat|nested] 11+ messages in thread
[parent not found: <49142DC5.8080803-o2qLIJkoznsdnm+yROfE0A@public.gmane.org>]
* Re: [PATCH v2] usbnet: enable more aggressive autosuspend [not found] ` <49142DC5.8080803-o2qLIJkoznsdnm+yROfE0A@public.gmane.org> @ 2008-11-07 12:24 ` Oliver Neukum [not found] ` <200811071324.18697.oliver-GvhC2dPhHPQdnm+yROfE0A@public.gmane.org> 0 siblings, 1 reply; 11+ messages in thread From: Oliver Neukum @ 2008-11-07 12:24 UTC (permalink / raw) To: Jeff Garzik Cc: Per Hallsmark, linux-usb-u79uwXL29TY76Z2rM5mHXA, netdev-u79uwXL29TY76Z2rM5mHXA, david-b-yBeKhBN/0LDR7s880joybQ Am Freitag, 7. November 2008 13:00:05 schrieb Jeff Garzik: > Oliver Neukum wrote: > > Am Freitag, 7. November 2008 09:26:33 schrieb Jeff Garzik: > >> I pondered taking the easy route of fixing this by surrounding the > >> auto_pm reference with an ifdef, but it seems like usbnet could use a > >> bit more thought -- it is questionable whether usbnet_suspend/resume > >> should be built at all, if !CONFIG_PM, even though they are exported. > > > > As this is a generic problem, shouldn't we get the compiler to do > > this for us? > > Can you be more specific? As these methods are static the compiler is able to tell whether they are referenced by anything but the tables. We should be able to set an attribute in the header file that tells the compiler that these methods won't be called and can be omitted in the build. Otherwise we have to ifdef all those methods. 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] 11+ messages in thread
[parent not found: <200811071324.18697.oliver-GvhC2dPhHPQdnm+yROfE0A@public.gmane.org>]
* Re: [PATCH v2] usbnet: enable more aggressive autosuspend [not found] ` <200811071324.18697.oliver-GvhC2dPhHPQdnm+yROfE0A@public.gmane.org> @ 2008-11-07 20:22 ` David Miller [not found] ` <20081107.122236.08276398.davem-fT/PcQaiUtIeIZ0/mPfg9Q@public.gmane.org> 0 siblings, 1 reply; 11+ messages in thread From: David Miller @ 2008-11-07 20:22 UTC (permalink / raw) To: oliver-GvhC2dPhHPQdnm+yROfE0A Cc: jeff-o2qLIJkoznsdnm+yROfE0A, per.hallsmark-8A+B91M1NdOzQB+pC5nmwQ, linux-usb-u79uwXL29TY76Z2rM5mHXA, netdev-u79uwXL29TY76Z2rM5mHXA, david-b-yBeKhBN/0LDR7s880joybQ From: Oliver Neukum <oliver-GvhC2dPhHPQdnm+yROfE0A@public.gmane.org> Date: Fri, 7 Nov 2008 13:24:17 +0100 > Am Freitag, 7. November 2008 13:00:05 schrieb Jeff Garzik: > > Oliver Neukum wrote: > > > Am Freitag, 7. November 2008 09:26:33 schrieb Jeff Garzik: > > >> I pondered taking the easy route of fixing this by surrounding the > > >> auto_pm reference with an ifdef, but it seems like usbnet could use a > > >> bit more thought -- it is questionable whether usbnet_suspend/resume > > >> should be built at all, if !CONFIG_PM, even though they are exported. > > > > > > As this is a generic problem, shouldn't we get the compiler to do > > > this for us? > > > > Can you be more specific? > > As these methods are static the compiler is able to tell whether they > are referenced by anything but the tables. We should be able to set > an attribute in the header file that tells the compiler that these methods > won't be called and can be omitted in the build. Otherwise we have to ifdef > all those methods. The problem is that the content of these functions still needs to be parsed, so references to ifdef'd out structure members are still going to throw errors. For the time being please add the necessary CONFIG_PM wrappers around the suspend and resume methods, as this is what we do tree wide and I don't think you want these usbnet changes blocked by some fancy compiler facility that hasn't been implemented yet. -- 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] 11+ messages in thread
[parent not found: <20081107.122236.08276398.davem-fT/PcQaiUtIeIZ0/mPfg9Q@public.gmane.org>]
* Re: [PATCH v2] usbnet: enable more aggressive autosuspend [not found] ` <20081107.122236.08276398.davem-fT/PcQaiUtIeIZ0/mPfg9Q@public.gmane.org> @ 2008-11-12 9:01 ` Per Hallsmark [not found] ` <491A9B59.9080208-8A+B91M1NdOzQB+pC5nmwQ@public.gmane.org> 0 siblings, 1 reply; 11+ messages in thread From: Per Hallsmark @ 2008-11-12 9:01 UTC (permalink / raw) To: David Miller Cc: oliver-GvhC2dPhHPQdnm+yROfE0A, jeff-o2qLIJkoznsdnm+yROfE0A, linux-usb-u79uwXL29TY76Z2rM5mHXA, netdev-u79uwXL29TY76Z2rM5mHXA, david-b-yBeKhBN/0LDR7s880joybQ David Miller wrote: > From: Oliver Neukum <oliver-GvhC2dPhHPQdnm+yROfE0A@public.gmane.org> > Date: Fri, 7 Nov 2008 13:24:17 +0100 > > >> Am Freitag, 7. November 2008 13:00:05 schrieb Jeff Garzik: >> >>> Oliver Neukum wrote: >>> >>>> Am Freitag, 7. November 2008 09:26:33 schrieb Jeff Garzik: >>>> >>>>> I pondered taking the easy route of fixing this by surrounding the >>>>> auto_pm reference with an ifdef, but it seems like usbnet could use a >>>>> bit more thought -- it is questionable whether usbnet_suspend/resume >>>>> should be built at all, if !CONFIG_PM, even though they are exported. >>>>> >>>> As this is a generic problem, shouldn't we get the compiler to do >>>> this for us? >>>> >>> Can you be more specific? >>> >> As these methods are static the compiler is able to tell whether they >> are referenced by anything but the tables. We should be able to set >> an attribute in the header file that tells the compiler that these methods >> won't be called and can be omitted in the build. Otherwise we have to ifdef >> all those methods. >> > > The problem is that the content of these functions still needs to be > parsed, so references to ifdef'd out structure members are still going > to throw errors. > > For the time being please add the necessary CONFIG_PM wrappers around > the suspend and resume methods, as this is what we do tree wide and > I don't think you want these usbnet changes blocked by some fancy > compiler facility that hasn't been implemented yet. > Ok, this news I've missed. Should I regenerate the patch or is it handled anyway? Best regards, Per -- 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] 11+ messages in thread
[parent not found: <491A9B59.9080208-8A+B91M1NdOzQB+pC5nmwQ@public.gmane.org>]
* Re: [PATCH v2] usbnet: enable more aggressive autosuspend [not found] ` <491A9B59.9080208-8A+B91M1NdOzQB+pC5nmwQ@public.gmane.org> @ 2008-11-12 9:36 ` Jeff Garzik 0 siblings, 0 replies; 11+ messages in thread From: Jeff Garzik @ 2008-11-12 9:36 UTC (permalink / raw) To: Per Hallsmark Cc: David Miller, oliver-GvhC2dPhHPQdnm+yROfE0A, linux-usb-u79uwXL29TY76Z2rM5mHXA, netdev-u79uwXL29TY76Z2rM5mHXA, david-b-yBeKhBN/0LDR7s880joybQ Per Hallsmark wrote: > David Miller wrote: >> From: Oliver Neukum <oliver-GvhC2dPhHPQdnm+yROfE0A@public.gmane.org> >> Date: Fri, 7 Nov 2008 13:24:17 +0100 >> >> >>> Am Freitag, 7. November 2008 13:00:05 schrieb Jeff Garzik: >>> >>>> Oliver Neukum wrote: >>>> >>>>> Am Freitag, 7. November 2008 09:26:33 schrieb Jeff Garzik: >>>>> >>>>>> I pondered taking the easy route of fixing this by surrounding the >>>>>> auto_pm reference with an ifdef, but it seems like usbnet could >>>>>> use a bit more thought -- it is questionable whether >>>>>> usbnet_suspend/resume should be built at all, if !CONFIG_PM, even >>>>>> though they are exported. >>>>>> >>>>> As this is a generic problem, shouldn't we get the compiler to do >>>>> this for us? >>>>> >>>> Can you be more specific? >>>> >>> As these methods are static the compiler is able to tell whether they >>> are referenced by anything but the tables. We should be able to set >>> an attribute in the header file that tells the compiler that these >>> methods >>> won't be called and can be omitted in the build. Otherwise we have to >>> ifdef >>> all those methods. >>> >> >> The problem is that the content of these functions still needs to be >> parsed, so references to ifdef'd out structure members are still going >> to throw errors. >> >> For the time being please add the necessary CONFIG_PM wrappers around >> the suspend and resume methods, as this is what we do tree wide and >> I don't think you want these usbnet changes blocked by some fancy >> compiler facility that hasn't been implemented yet. >> > Ok, this news I've missed. Should I regenerate the patch or is it > handled anyway? regenerate, please -- 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] 11+ messages in thread
end of thread, other threads:[~2008-11-12 9:36 UTC | newest]
Thread overview: 11+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2008-10-23 13:49 [PATCH v2] usbnet: enable more aggressive autosuspend Per Hallsmark
2008-10-23 18:57 ` Alan Stern
[not found] ` <Pine.LNX.4.44L0.0810231455020.18234-100000-IYeN2dnnYyZXsRXLowluHWD2FQJk+8+b@public.gmane.org>
2008-10-24 9:21 ` Per Hallsmark
2008-10-24 14:12 ` Alan Stern
[not found] ` <490080F1.1060107-8A+B91M1NdOzQB+pC5nmwQ@public.gmane.org>
2008-11-07 8:26 ` Jeff Garzik
2008-11-07 11:44 ` Oliver Neukum
2008-11-07 12:00 ` Jeff Garzik
[not found] ` <49142DC5.8080803-o2qLIJkoznsdnm+yROfE0A@public.gmane.org>
2008-11-07 12:24 ` Oliver Neukum
[not found] ` <200811071324.18697.oliver-GvhC2dPhHPQdnm+yROfE0A@public.gmane.org>
2008-11-07 20:22 ` David Miller
[not found] ` <20081107.122236.08276398.davem-fT/PcQaiUtIeIZ0/mPfg9Q@public.gmane.org>
2008-11-12 9:01 ` Per Hallsmark
[not found] ` <491A9B59.9080208-8A+B91M1NdOzQB+pC5nmwQ@public.gmane.org>
2008-11-12 9:36 ` Jeff Garzik
This is a public inbox, see mirroring instructions for how to clone and mirror all data and code used for this inbox; as well as URLs for NNTP newsgroup(s).