diff options
| author | Greg Kroah-Hartman <gregkh@suse.de> | 2009-07-10 14:51:46 -0700 |
|---|---|---|
| committer | Greg Kroah-Hartman <gregkh@suse.de> | 2009-07-10 14:51:46 -0700 |
| commit | da0168ad6c26fae5cb53775a5ad2c95af0dfa8b7 (patch) | |
| tree | 38aa162f12e37ce1834126e24c94bd9475f5e20e /usb | |
| parent | 24e34cceebec70f8b7d2229c537e66818b0ecad2 (diff) | |
| download | patches-da0168ad6c26fae5cb53775a5ad2c95af0dfa8b7.tar.gz | |
more patches
Diffstat (limited to 'usb')
| -rw-r--r-- | usb/usb-add-api-for-userspace-drivers-to-claim-ports.patch | 317 | ||||
| -rw-r--r-- | usb/usb-at91_udc-at91sam9g20-updates.patch | 88 | ||||
| -rw-r--r-- | usb/usb-make-intf.pm_usage-an-atomic_t.patch | 192 | ||||
| -rw-r--r-- | usb/usb-make-the-usbfs_snoop-log-more-pertinent.patch | 311 | ||||
| -rw-r--r-- | usb/usb-whci-hcd-make-endpoint_reset-method-async.patch | 156 |
5 files changed, 1064 insertions, 0 deletions
diff --git a/usb/usb-add-api-for-userspace-drivers-to-claim-ports.patch b/usb/usb-add-api-for-userspace-drivers-to-claim-ports.patch new file mode 100644 index 00000000000000..120b7b8cbe2edd --- /dev/null +++ b/usb/usb-add-api-for-userspace-drivers-to-claim-ports.patch @@ -0,0 +1,317 @@ +From stern@rowland.harvard.edu Fri Jul 10 14:42:02 2009 +From: Alan Stern <stern@rowland.harvard.edu> +Date: Mon, 29 Jun 2009 10:56:54 -0400 (EDT) +Subject: USB: add API for userspace drivers to "claim" ports +To: Greg KH <greg@kroah.com> +Cc: Pantelis Koukousoulas <pktoss@gmail.com> +Message-ID: <Pine.LNX.4.44L0.0906291049560.16597-100000@iolanthe.rowland.org> + + +This patch (as1258) implements a feature that users have been asking +for: It gives programs the ability to "claim" a port on a hub, via a +new usbfs ioctl. A device plugged into a "claimed" port will not be +touched by the kernel beyond the immediate necessities of +initialization and enumeration. + +In particular, when a device is plugged into a "claimed" port, the +kernel will not select and install a configuration. And when a config +is installed by usbfs or sysfs, the kernel will not probe any drivers +for any of the interfaces. (However the kernel will fetch various +string descriptors during enumeration. One could argue that this +isn't really necessary, but the strings are exported in sysfs.) + +The patch does not guarantee exclusive access to these devices; it is +still possible for more than one program to open the device file +concurrently. Programs are responsible for coordinating access among +themselves. + +A demonstration program showing how to use the new interface can be +found in an attachment to + + http://marc.info/?l=linux-usb&m=124345857431452&w=2 + +The patch also makes a small simplification to the hub driver, +replacing a bunch of more-or-less useless variants of "out of memory" +with a single message. + +Signed-off-by: Alan Stern <stern@rowland.harvard.edu> +Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de> + +--- + drivers/usb/core/devio.c | 35 +++++++++++++++++ + drivers/usb/core/driver.c | 3 + + drivers/usb/core/generic.c | 4 + + drivers/usb/core/hub.c | 88 ++++++++++++++++++++++++++++++++++++++++--- + drivers/usb/core/usb.h | 7 +++ + include/linux/usbdevice_fs.h | 2 + 6 files changed, 133 insertions(+), 6 deletions(-) + +--- a/drivers/usb/core/devio.c ++++ b/drivers/usb/core/devio.c +@@ -52,6 +52,7 @@ + + #include "hcd.h" /* for usbcore internals */ + #include "usb.h" ++#include "hub.h" + + #define USB_MAXBUS 64 + #define USB_DEVICE_MAX USB_MAXBUS * 128 +@@ -655,6 +656,7 @@ static int usbdev_release(struct inode * + struct async *as; + + usb_lock_device(dev); ++ usb_hub_release_all_ports(dev, ps); + + /* Protect against simultaneous open */ + mutex_lock(&usbfs_mutex); +@@ -1546,6 +1548,29 @@ static int proc_ioctl_compat(struct dev_ + } + #endif + ++static int proc_claim_port(struct dev_state *ps, void __user *arg) ++{ ++ unsigned portnum; ++ int rc; ++ ++ if (get_user(portnum, (unsigned __user *) arg)) ++ return -EFAULT; ++ rc = usb_hub_claim_port(ps->dev, portnum, ps); ++ if (rc == 0) ++ snoop(&ps->dev->dev, "port %d claimed by process %d: %s\n", ++ portnum, task_pid_nr(current), current->comm); ++ return rc; ++} ++ ++static int proc_release_port(struct dev_state *ps, void __user *arg) ++{ ++ unsigned portnum; ++ ++ if (get_user(portnum, (unsigned __user *) arg)) ++ return -EFAULT; ++ return usb_hub_release_port(ps->dev, portnum, ps); ++} ++ + /* + * NOTE: All requests here that have interface numbers as parameters + * are assuming that somehow the configuration has been prevented from +@@ -1687,6 +1712,16 @@ static int usbdev_ioctl(struct inode *in + snoop(&dev->dev, "%s: IOCTL\n", __func__); + ret = proc_ioctl_default(ps, p); + break; ++ ++ case USBDEVFS_CLAIM_PORT: ++ snoop(&dev->dev, "%s: CLAIM_PORT\n", __func__); ++ ret = proc_claim_port(ps, p); ++ break; ++ ++ case USBDEVFS_RELEASE_PORT: ++ snoop(&dev->dev, "%s: RELEASE_PORT\n", __func__); ++ ret = proc_release_port(ps, p); ++ break; + } + usb_unlock_device(dev); + if (ret >= 0) +--- a/drivers/usb/core/driver.c ++++ b/drivers/usb/core/driver.c +@@ -207,6 +207,9 @@ static int usb_probe_interface(struct de + + intf->needs_binding = 0; + ++ if (usb_device_is_owned(udev)) ++ return -ENODEV; ++ + if (udev->authorized == 0) { + dev_err(&intf->dev, "Device is not authorized for usage\n"); + return -ENODEV; +--- a/drivers/usb/core/generic.c ++++ b/drivers/usb/core/generic.c +@@ -158,7 +158,9 @@ static int generic_probe(struct usb_devi + /* Choose and set the configuration. This registers the interfaces + * with the driver core and lets interface drivers bind to them. + */ +- if (udev->authorized == 0) ++ if (usb_device_is_owned(udev)) ++ ; /* Don't configure if the device is owned */ ++ else if (udev->authorized == 0) + dev_err(&udev->dev, "Device is not authorized for usage\n"); + else { + c = usb_choose_configuration(udev); +--- a/drivers/usb/core/hub.c ++++ b/drivers/usb/core/hub.c +@@ -78,6 +78,7 @@ struct usb_hub { + u8 indicator[USB_MAXCHILDREN]; + struct delayed_work leds; + struct delayed_work init_work; ++ void **port_owners; + }; + + +@@ -860,19 +861,17 @@ static int hub_configure(struct usb_hub + u16 wHubCharacteristics; + unsigned int pipe; + int maxp, ret; +- char *message; ++ char *message = "out of memory"; + + hub->buffer = usb_buffer_alloc(hdev, sizeof(*hub->buffer), GFP_KERNEL, + &hub->buffer_dma); + if (!hub->buffer) { +- message = "can't allocate hub irq buffer"; + ret = -ENOMEM; + goto fail; + } + + hub->status = kmalloc(sizeof(*hub->status), GFP_KERNEL); + if (!hub->status) { +- message = "can't kmalloc hub status buffer"; + ret = -ENOMEM; + goto fail; + } +@@ -880,7 +879,6 @@ static int hub_configure(struct usb_hub + + hub->descriptor = kmalloc(sizeof(*hub->descriptor), GFP_KERNEL); + if (!hub->descriptor) { +- message = "can't kmalloc hub descriptor"; + ret = -ENOMEM; + goto fail; + } +@@ -904,6 +902,12 @@ static int hub_configure(struct usb_hub + dev_info (hub_dev, "%d port%s detected\n", hdev->maxchild, + (hdev->maxchild == 1) ? "" : "s"); + ++ hub->port_owners = kzalloc(hdev->maxchild * sizeof(void *), GFP_KERNEL); ++ if (!hub->port_owners) { ++ ret = -ENOMEM; ++ goto fail; ++ } ++ + wHubCharacteristics = le16_to_cpu(hub->descriptor->wHubCharacteristics); + + if (wHubCharacteristics & HUB_CHAR_COMPOUND) { +@@ -1082,7 +1086,6 @@ static int hub_configure(struct usb_hub + + hub->urb = usb_alloc_urb(0, GFP_KERNEL); + if (!hub->urb) { +- message = "couldn't allocate interrupt urb"; + ret = -ENOMEM; + goto fail; + } +@@ -1131,11 +1134,13 @@ static void hub_disconnect(struct usb_in + hub_quiesce(hub, HUB_DISCONNECT); + + usb_set_intfdata (intf, NULL); ++ hub->hdev->maxchild = 0; + + if (hub->hdev->speed == USB_SPEED_HIGH) + highspeed_hubs--; + + usb_free_urb(hub->urb); ++ kfree(hub->port_owners); + kfree(hub->descriptor); + kfree(hub->status); + usb_buffer_free(hub->hdev, sizeof(*hub->buffer), hub->buffer, +@@ -1250,6 +1255,79 @@ hub_ioctl(struct usb_interface *intf, un + } + } + ++/* ++ * Allow user programs to claim ports on a hub. When a device is attached ++ * to one of these "claimed" ports, the program will "own" the device. ++ */ ++static int find_port_owner(struct usb_device *hdev, unsigned port1, ++ void ***ppowner) ++{ ++ if (hdev->state == USB_STATE_NOTATTACHED) ++ return -ENODEV; ++ if (port1 == 0 || port1 > hdev->maxchild) ++ return -EINVAL; ++ ++ /* This assumes that devices not managed by the hub driver ++ * will always have maxchild equal to 0. ++ */ ++ *ppowner = &(hdev_to_hub(hdev)->port_owners[port1 - 1]); ++ return 0; ++} ++ ++/* In the following three functions, the caller must hold hdev's lock */ ++int usb_hub_claim_port(struct usb_device *hdev, unsigned port1, void *owner) ++{ ++ int rc; ++ void **powner; ++ ++ rc = find_port_owner(hdev, port1, &powner); ++ if (rc) ++ return rc; ++ if (*powner) ++ return -EBUSY; ++ *powner = owner; ++ return rc; ++} ++ ++int usb_hub_release_port(struct usb_device *hdev, unsigned port1, void *owner) ++{ ++ int rc; ++ void **powner; ++ ++ rc = find_port_owner(hdev, port1, &powner); ++ if (rc) ++ return rc; ++ if (*powner != owner) ++ return -ENOENT; ++ *powner = NULL; ++ return rc; ++} ++ ++void usb_hub_release_all_ports(struct usb_device *hdev, void *owner) ++{ ++ int n; ++ void **powner; ++ ++ n = find_port_owner(hdev, 1, &powner); ++ if (n == 0) { ++ for (; n < hdev->maxchild; (++n, ++powner)) { ++ if (*powner == owner) ++ *powner = NULL; ++ } ++ } ++} ++ ++/* The caller must hold udev's lock */ ++bool usb_device_is_owned(struct usb_device *udev) ++{ ++ struct usb_hub *hub; ++ ++ if (udev->state == USB_STATE_NOTATTACHED || !udev->parent) ++ return false; ++ hub = hdev_to_hub(udev->parent); ++ return !!hub->port_owners[udev->portnum - 1]; ++} ++ + + static void recursively_mark_NOTATTACHED(struct usb_device *udev) + { +--- a/drivers/usb/core/usb.h ++++ b/drivers/usb/core/usb.h +@@ -37,6 +37,13 @@ extern int usb_match_device(struct usb_d + extern void usb_forced_unbind_intf(struct usb_interface *intf); + extern void usb_rebind_intf(struct usb_interface *intf); + ++extern int usb_hub_claim_port(struct usb_device *hdev, unsigned port, ++ void *owner); ++extern int usb_hub_release_port(struct usb_device *hdev, unsigned port, ++ void *owner); ++extern void usb_hub_release_all_ports(struct usb_device *hdev, void *owner); ++extern bool usb_device_is_owned(struct usb_device *udev); ++ + extern int usb_hub_init(void); + extern void usb_hub_cleanup(void); + extern int usb_major_init(void); +--- a/include/linux/usbdevice_fs.h ++++ b/include/linux/usbdevice_fs.h +@@ -175,4 +175,6 @@ struct usbdevfs_ioctl32 { + #define USBDEVFS_CLEAR_HALT _IOR('U', 21, unsigned int) + #define USBDEVFS_DISCONNECT _IO('U', 22) + #define USBDEVFS_CONNECT _IO('U', 23) ++#define USBDEVFS_CLAIM_PORT _IOR('U', 24, unsigned int) ++#define USBDEVFS_RELEASE_PORT _IOR('U', 25, unsigned int) + #endif /* _LINUX_USBDEVICE_FS_H */ diff --git a/usb/usb-at91_udc-at91sam9g20-updates.patch b/usb/usb-at91_udc-at91sam9g20-updates.patch new file mode 100644 index 00000000000000..b4b5e0f2dc869c --- /dev/null +++ b/usb/usb-at91_udc-at91sam9g20-updates.patch @@ -0,0 +1,88 @@ +From david-b@pacbell.net Fri Jul 10 14:33:04 2009 +From: David Brownell <david-b@pacbell.net> +Date: Fri, 19 Jun 2009 02:20:24 -0700 +Subject: USB: at91_udc: at91sam9g20 updates +To: linux-usb@vger.kernel.org +Cc: Manuel Sahm <Manuel.Sahm@feig.de>, Nicolas Ferre <nicolas.ferre@rfo.atmel.com>, Anti Sullin <anti.sullin@artecdesign.ee> +Message-ID: <200906190220.24750.david-b@pacbell.net> +Content-Disposition: inline + + +From: David Brownell <dbrownell@users.sourceforge.net> + +Update the at91_udc driver to improve at91sam9g20 support. This +is a sped-up at91sam9260; the CPU is twice as fast, but clocking +for peripheralsl won't change much. + + - Its endpoint FIFOs have the same larger sizes as the '9260. + + - It's more open to races with data still on its way to the USB + peripheral, while the driver acts as if it already got there. + +Fix the former by adding the relevant cpu_is_*() check, and the +latter by updating some FIFO read/write paths so they wait until +the CPU's write buffer drains ... that's a bit cheaper than just +issuing a controller read. + +Problem noted by Manuel Sahm <Manuel.Sahm@feig.de>, who also +provided a patch for this. One race could be the same as one +noted by Anti Sullin <anti.sullin@artecdesign.ee> after a GCC +upgrade on a sam9261 board. + +Cc: Manuel Sahm <Manuel.Sahm@feig.de> +Cc: Nicolas Ferre <nicolas.ferre@rfo.atmel.com> +Signed-off-by: David Brownell <dbrownell@users.sourceforge.net> +Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de> + +--- + drivers/usb/gadget/at91_udc.c | 11 ++++++++++- + 1 file changed, 10 insertions(+), 1 deletion(-) + +--- a/drivers/usb/gadget/at91_udc.c ++++ b/drivers/usb/gadget/at91_udc.c +@@ -82,6 +82,11 @@ static const char ep0name[] = "ep0"; + #define at91_udp_write(dev, reg, val) \ + __raw_writel((val), (dev)->udp_baseaddr + (reg)) + ++static inline int drain_write_buffer(void) ++{ ++ asm("mcr p15, 0, r0, c7, c10, 4 @ drain write buffer\n"); ++} ++ + /*-------------------------------------------------------------------------*/ + + #ifdef CONFIG_USB_GADGET_DEBUG_FILES +@@ -350,6 +355,7 @@ rescan: + } else + csr &= ~(SET_FX | AT91_UDP_RX_DATA_BK0); + __raw_writel(csr, creg); ++ drain_write_buffer(); + + req->req.actual += count; + is_done = (count < ep->ep.maxpacket); +@@ -434,6 +440,8 @@ static int write_fifo(struct at91_ep *ep + csr &= ~SET_FX; + csr |= CLR_FX | AT91_UDP_TXPKTRDY; + __raw_writel(csr, creg); ++ drain_write_buffer(); ++ + req->req.actual += count; + + PACKET("%s %p in/%d%s\n", ep->ep.name, &req->req, count, +@@ -669,6 +677,7 @@ ep0_in_status: + tmp &= ~SET_FX; + tmp |= CLR_FX | AT91_UDP_TXPKTRDY; + __raw_writel(tmp, ep->creg); ++ drain_write_buffer(); + dev->req_pending = 0; + goto done; + } +@@ -1687,7 +1696,7 @@ static int __init at91udc_probe(struct p + } + + /* newer chips have more FIFO memory than rm9200 */ +- if (cpu_is_at91sam9260()) { ++ if (cpu_is_at91sam9260() || cpu_is_at91sam9g20()) { + udc->ep[0].maxpacket = 64; + udc->ep[3].maxpacket = 64; + udc->ep[4].maxpacket = 512; diff --git a/usb/usb-make-intf.pm_usage-an-atomic_t.patch b/usb/usb-make-intf.pm_usage-an-atomic_t.patch new file mode 100644 index 00000000000000..2d347c3b337d2e --- /dev/null +++ b/usb/usb-make-intf.pm_usage-an-atomic_t.patch @@ -0,0 +1,192 @@ +From stern@rowland.harvard.edu Fri Jul 10 14:43:11 2009 +From: Alan Stern <stern@rowland.harvard.edu> +Date: Mon, 29 Jun 2009 11:00:01 -0400 (EDT) +Subject: USB: make intf.pm_usage an atomic_t +To: Greg KH <greg@kroah.com> +Message-ID: <Pine.LNX.4.44L0.0906291058430.16597-100000@iolanthe.rowland.org> + + +This patch (as1260) changes the pm_usage_cnt field in struct +usb_interface from an int to an atomic_t. This is so that drivers can +invoke the usb_autopm_get_interface_async() and +usb_autopm_put_interface_async() routines without locking and without +fear of corrupting the pm_usage_cnt value. + +Signed-off-by: Alan Stern <stern@rowland.harvard.edu> +Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de> + + +--- + drivers/usb/core/driver.c | 38 ++++++++++++++++++++++---------------- + drivers/usb/core/hub.c | 5 +++-- + include/linux/usb.h | 6 +++--- + 3 files changed, 28 insertions(+), 21 deletions(-) + +--- a/drivers/usb/core/driver.c ++++ b/drivers/usb/core/driver.c +@@ -235,7 +235,7 @@ static int usb_probe_interface(struct de + /* The interface should always appear to be in use + * unless the driver suports autosuspend. + */ +- intf->pm_usage_cnt = !(driver->supports_autosuspend); ++ atomic_set(&intf->pm_usage_cnt, !driver->supports_autosuspend); + + /* Carry out a deferred switch to altsetting 0 */ + if (intf->needs_altsetting0) { +@@ -347,7 +347,7 @@ int usb_driver_claim_interface(struct us + usb_pm_lock(udev); + iface->condition = USB_INTERFACE_BOUND; + mark_active(iface); +- iface->pm_usage_cnt = !(driver->supports_autosuspend); ++ atomic_set(&iface->pm_usage_cnt, !driver->supports_autosuspend); + usb_pm_unlock(udev); + + /* if interface was already added, bind now; else let +@@ -1068,7 +1068,7 @@ static int autosuspend_check(struct usb_ + intf = udev->actconfig->interface[i]; + if (!is_active(intf)) + continue; +- if (intf->pm_usage_cnt > 0) ++ if (atomic_read(&intf->pm_usage_cnt) > 0) + return -EBUSY; + if (intf->needs_remote_wakeup && + !udev->do_remote_wakeup) { +@@ -1464,17 +1464,19 @@ static int usb_autopm_do_interface(struc + status = -ENODEV; + else { + udev->auto_pm = 1; +- intf->pm_usage_cnt += inc_usage_cnt; ++ atomic_add(inc_usage_cnt, &intf->pm_usage_cnt); + udev->last_busy = jiffies; +- if (inc_usage_cnt >= 0 && intf->pm_usage_cnt > 0) { ++ if (inc_usage_cnt >= 0 && ++ atomic_read(&intf->pm_usage_cnt) > 0) { + if (udev->state == USB_STATE_SUSPENDED) + status = usb_resume_both(udev, + PMSG_AUTO_RESUME); + if (status != 0) +- intf->pm_usage_cnt -= inc_usage_cnt; ++ atomic_sub(inc_usage_cnt, &intf->pm_usage_cnt); + else + udev->last_busy = jiffies; +- } else if (inc_usage_cnt <= 0 && intf->pm_usage_cnt <= 0) { ++ } else if (inc_usage_cnt <= 0 && ++ atomic_read(&intf->pm_usage_cnt) <= 0) { + status = usb_suspend_both(udev, PMSG_AUTO_SUSPEND); + } + } +@@ -1519,7 +1521,7 @@ void usb_autopm_put_interface(struct usb + + status = usb_autopm_do_interface(intf, -1); + dev_vdbg(&intf->dev, "%s: status %d cnt %d\n", +- __func__, status, intf->pm_usage_cnt); ++ __func__, status, atomic_read(&intf->pm_usage_cnt)); + } + EXPORT_SYMBOL_GPL(usb_autopm_put_interface); + +@@ -1547,10 +1549,10 @@ void usb_autopm_put_interface_async(stru + status = -ENODEV; + } else { + udev->last_busy = jiffies; +- --intf->pm_usage_cnt; ++ atomic_dec(&intf->pm_usage_cnt); + if (udev->autosuspend_disabled || udev->autosuspend_delay < 0) + status = -EPERM; +- else if (intf->pm_usage_cnt <= 0 && ++ else if (atomic_read(&intf->pm_usage_cnt) <= 0 && + !timer_pending(&udev->autosuspend.timer)) { + queue_delayed_work(ksuspend_usb_wq, &udev->autosuspend, + round_jiffies_up_relative( +@@ -1558,7 +1560,7 @@ void usb_autopm_put_interface_async(stru + } + } + dev_vdbg(&intf->dev, "%s: status %d cnt %d\n", +- __func__, status, intf->pm_usage_cnt); ++ __func__, status, atomic_read(&intf->pm_usage_cnt)); + } + EXPORT_SYMBOL_GPL(usb_autopm_put_interface_async); + +@@ -1602,7 +1604,7 @@ int usb_autopm_get_interface(struct usb_ + + status = usb_autopm_do_interface(intf, 1); + dev_vdbg(&intf->dev, "%s: status %d cnt %d\n", +- __func__, status, intf->pm_usage_cnt); ++ __func__, status, atomic_read(&intf->pm_usage_cnt)); + return status; + } + EXPORT_SYMBOL_GPL(usb_autopm_get_interface); +@@ -1630,10 +1632,14 @@ int usb_autopm_get_interface_async(struc + 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); ++ else { ++ atomic_inc(&intf->pm_usage_cnt); ++ if (atomic_read(&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); ++ __func__, status, atomic_read(&intf->pm_usage_cnt)); + return status; + } + EXPORT_SYMBOL_GPL(usb_autopm_get_interface_async); +@@ -1655,7 +1661,7 @@ int usb_autopm_set_interface(struct usb_ + + status = usb_autopm_do_interface(intf, 0); + dev_vdbg(&intf->dev, "%s: status %d cnt %d\n", +- __func__, status, intf->pm_usage_cnt); ++ __func__, status, atomic_read(&intf->pm_usage_cnt)); + return status; + } + EXPORT_SYMBOL_GPL(usb_autopm_set_interface); +--- a/drivers/usb/core/hub.c ++++ b/drivers/usb/core/hub.c +@@ -373,7 +373,7 @@ static void kick_khubd(struct usb_hub *h + unsigned long flags; + + /* Suppress autosuspend until khubd runs */ +- to_usb_interface(hub->intfdev)->pm_usage_cnt = 1; ++ atomic_set(&to_usb_interface(hub->intfdev)->pm_usage_cnt, 1); + + spin_lock_irqsave(&hub_event_lock, flags); + if (!hub->disconnected && list_empty(&hub->event_list)) { +@@ -678,7 +678,8 @@ static void hub_activate(struct usb_hub + msecs_to_jiffies(delay)); + + /* Suppress autosuspend until init is done */ +- to_usb_interface(hub->intfdev)->pm_usage_cnt = 1; ++ atomic_set(&to_usb_interface(hub->intfdev)-> ++ pm_usage_cnt, 1); + return; /* Continues at init2: below */ + } else { + hub_power_on(hub, true); +--- a/include/linux/usb.h ++++ b/include/linux/usb.h +@@ -195,7 +195,7 @@ struct usb_interface { + + struct device dev; /* interface specific device info */ + struct device *usb_dev; +- int pm_usage_cnt; /* usage counter for autosuspend */ ++ atomic_t pm_usage_cnt; /* usage counter for autosuspend */ + struct work_struct reset_ws; /* for resets in atomic context */ + }; + #define to_usb_interface(d) container_of(d, struct usb_interface, dev) +@@ -551,13 +551,13 @@ extern void usb_autopm_put_interface_asy + + static inline void usb_autopm_enable(struct usb_interface *intf) + { +- intf->pm_usage_cnt = 0; ++ atomic_set(&intf->pm_usage_cnt, 0); + usb_autopm_set_interface(intf); + } + + static inline void usb_autopm_disable(struct usb_interface *intf) + { +- intf->pm_usage_cnt = 1; ++ atomic_set(&intf->pm_usage_cnt, 1); + usb_autopm_set_interface(intf); + } + diff --git a/usb/usb-make-the-usbfs_snoop-log-more-pertinent.patch b/usb/usb-make-the-usbfs_snoop-log-more-pertinent.patch new file mode 100644 index 00000000000000..81bb88b2db20d0 --- /dev/null +++ b/usb/usb-make-the-usbfs_snoop-log-more-pertinent.patch @@ -0,0 +1,311 @@ +From stern@rowland.harvard.edu Fri Jul 10 14:43:26 2009 +From: Alan Stern <stern@rowland.harvard.edu> +Date: Mon, 29 Jun 2009 11:02:04 -0400 (EDT) +Subject: USB: make the "usbfs_snoop" log more pertinent +To: Greg KH <greg@kroah.com> +Message-ID: <Pine.LNX.4.44L0.0906291100070.16597-100000@iolanthe.rowland.org> + + +This patch (as1261) reduces the amount of detailed URB information +logged by usbfs when the usbfs_snoop parameter is enabled. + +Currently we don't display the final status value for a completed URB. +But we do display the entire data buffer twice: both before submission +and after completion. The after-completion display doesn't limit +itself to the actual_length value. But since usbmon is readily +available in virtually all distributions, there's no reason for usbfs +to print out any buffer contents at all! + +So this patch restricts the information to: userspace buffer pointer, +endpoint number, type, and direction, length or actual_length, and +timeout value or status. Now everything fits neatly into a single +line. + +Along with those changes, the patch also fixes the snoop output for +the REAPURBNDELAY and REAPURBNDELAY32 ioctls. The current version +omits the 'N' from the names. + +Signed-off-by: Alan Stern <stern@rowland.harvard.edu> +Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de> + +--- + drivers/usb/core/devio.c | 133 ++++++++++++++++++++++------------------------- + 1 file changed, 63 insertions(+), 70 deletions(-) + +--- a/drivers/usb/core/devio.c ++++ b/drivers/usb/core/devio.c +@@ -100,11 +100,15 @@ MODULE_PARM_DESC(usbfs_snoop, "true to l + dev_info(dev , format , ## arg); \ + } while (0) + +-#define USB_DEVICE_DEV MKDEV(USB_DEVICE_MAJOR, 0) ++enum snoop_when { ++ SUBMIT, COMPLETE ++}; + ++#define USB_DEVICE_DEV MKDEV(USB_DEVICE_MAJOR, 0) + + #define MAX_USBFS_BUFFER_SIZE 16384 + ++ + static int connected(struct dev_state *ps) + { + return (!list_empty(&ps->list) && +@@ -301,24 +305,42 @@ static struct async *async_getpending(st + return NULL; + } + +-static void snoop_urb(struct urb *urb, void __user *userurb) +-{ +- unsigned j; +- unsigned char *data = urb->transfer_buffer; ++static void snoop_urb(struct usb_device *udev, ++ void __user *userurb, int pipe, unsigned length, ++ int timeout_or_status, enum snoop_when when) ++{ ++ static const char *types[] = {"isoc", "int", "ctrl", "bulk"}; ++ static const char *dirs[] = {"out", "in"}; ++ int ep; ++ const char *t, *d; + + if (!usbfs_snoop) + return; + +- dev_info(&urb->dev->dev, "direction=%s\n", +- usb_urb_dir_in(urb) ? "IN" : "OUT"); +- dev_info(&urb->dev->dev, "userurb=%p\n", userurb); +- dev_info(&urb->dev->dev, "transfer_buffer_length=%u\n", +- urb->transfer_buffer_length); +- dev_info(&urb->dev->dev, "actual_length=%u\n", urb->actual_length); +- dev_info(&urb->dev->dev, "data: "); +- for (j = 0; j < urb->transfer_buffer_length; ++j) +- printk("%02x ", data[j]); +- printk("\n"); ++ ep = usb_pipeendpoint(pipe); ++ t = types[usb_pipetype(pipe)]; ++ d = dirs[!!usb_pipein(pipe)]; ++ ++ if (userurb) { /* Async */ ++ if (when == SUBMIT) ++ dev_info(&udev->dev, "userurb %p, ep%d %s-%s, " ++ "length %u\n", ++ userurb, ep, t, d, length); ++ else ++ dev_info(&udev->dev, "userurb %p, ep%d %s-%s, " ++ "actual_length %u status %d\n", ++ userurb, ep, t, d, length, ++ timeout_or_status); ++ } else { ++ if (when == SUBMIT) ++ dev_info(&udev->dev, "ep%d %s-%s, length %u, " ++ "timeout %d\n", ++ ep, t, d, length, timeout_or_status); ++ else ++ dev_info(&udev->dev, "ep%d %s-%s, actual_length %u, " ++ "status %d\n", ++ ep, t, d, length, timeout_or_status); ++ } + } + + static void async_completed(struct urb *urb) +@@ -347,7 +369,8 @@ static void async_completed(struct urb * + secid = as->secid; + } + snoop(&urb->dev->dev, "urb complete\n"); +- snoop_urb(urb, as->userurb); ++ snoop_urb(urb->dev, as->userurb, urb->pipe, urb->actual_length, ++ as->status, COMPLETE); + spin_unlock(&ps->lock); + + if (signr) +@@ -690,7 +713,7 @@ static int proc_control(struct dev_state + unsigned int tmo; + unsigned char *tbuf; + unsigned wLength; +- int i, j, ret; ++ int i, pipe, ret; + + if (copy_from_user(&ctrl, arg, sizeof(ctrl))) + return -EFAULT; +@@ -710,24 +733,17 @@ static int proc_control(struct dev_state + free_page((unsigned long)tbuf); + return -EINVAL; + } +- snoop(&dev->dev, "control read: bRequest=%02x " +- "bRrequestType=%02x wValue=%04x " +- "wIndex=%04x wLength=%04x\n", +- ctrl.bRequest, ctrl.bRequestType, ctrl.wValue, +- ctrl.wIndex, ctrl.wLength); ++ pipe = usb_rcvctrlpipe(dev, 0); ++ snoop_urb(dev, NULL, pipe, ctrl.wLength, tmo, SUBMIT); + + usb_unlock_device(dev); +- i = usb_control_msg(dev, usb_rcvctrlpipe(dev, 0), ctrl.bRequest, ++ i = usb_control_msg(dev, pipe, ctrl.bRequest, + ctrl.bRequestType, ctrl.wValue, ctrl.wIndex, + tbuf, ctrl.wLength, tmo); + usb_lock_device(dev); ++ snoop_urb(dev, NULL, pipe, max(i, 0), min(i, 0), COMPLETE); ++ + if ((i > 0) && ctrl.wLength) { +- if (usbfs_snoop) { +- dev_info(&dev->dev, "control read: data "); +- for (j = 0; j < i; ++j) +- printk("%02x ", (u8)(tbuf)[j]); +- printk("\n"); +- } + if (copy_to_user(ctrl.data, tbuf, i)) { + free_page((unsigned long)tbuf); + return -EFAULT; +@@ -740,22 +756,15 @@ static int proc_control(struct dev_state + return -EFAULT; + } + } +- snoop(&dev->dev, "control write: bRequest=%02x " +- "bRrequestType=%02x wValue=%04x " +- "wIndex=%04x wLength=%04x\n", +- ctrl.bRequest, ctrl.bRequestType, ctrl.wValue, +- ctrl.wIndex, ctrl.wLength); +- if (usbfs_snoop) { +- dev_info(&dev->dev, "control write: data: "); +- for (j = 0; j < ctrl.wLength; ++j) +- printk("%02x ", (unsigned char)(tbuf)[j]); +- printk("\n"); +- } ++ pipe = usb_sndctrlpipe(dev, 0); ++ snoop_urb(dev, NULL, pipe, ctrl.wLength, tmo, SUBMIT); ++ + usb_unlock_device(dev); + i = usb_control_msg(dev, usb_sndctrlpipe(dev, 0), ctrl.bRequest, + ctrl.bRequestType, ctrl.wValue, ctrl.wIndex, + tbuf, ctrl.wLength, tmo); + usb_lock_device(dev); ++ snoop_urb(dev, NULL, pipe, max(i, 0), min(i, 0), COMPLETE); + } + free_page((unsigned long)tbuf); + if (i < 0 && i != -EPIPE) { +@@ -774,7 +783,7 @@ static int proc_bulk(struct dev_state *p + unsigned int tmo, len1, pipe; + int len2; + unsigned char *tbuf; +- int i, j, ret; ++ int i, ret; + + if (copy_from_user(&bulk, arg, sizeof(bulk))) + return -EFAULT; +@@ -801,18 +810,14 @@ static int proc_bulk(struct dev_state *p + kfree(tbuf); + return -EINVAL; + } +- snoop(&dev->dev, "bulk read: len=0x%02x timeout=%04d\n", +- bulk.len, bulk.timeout); ++ snoop_urb(dev, NULL, pipe, len1, tmo, SUBMIT); ++ + usb_unlock_device(dev); + i = usb_bulk_msg(dev, pipe, tbuf, len1, &len2, tmo); + usb_lock_device(dev); ++ snoop_urb(dev, NULL, pipe, len2, i, COMPLETE); ++ + if (!i && len2) { +- if (usbfs_snoop) { +- dev_info(&dev->dev, "bulk read: data "); +- for (j = 0; j < len2; ++j) +- printk("%02x ", (u8)(tbuf)[j]); +- printk("\n"); +- } + if (copy_to_user(bulk.data, tbuf, len2)) { + kfree(tbuf); + return -EFAULT; +@@ -825,17 +830,12 @@ static int proc_bulk(struct dev_state *p + return -EFAULT; + } + } +- snoop(&dev->dev, "bulk write: len=0x%02x timeout=%04d\n", +- bulk.len, bulk.timeout); +- if (usbfs_snoop) { +- dev_info(&dev->dev, "bulk write: data: "); +- for (j = 0; j < len1; ++j) +- printk("%02x ", (unsigned char)(tbuf)[j]); +- printk("\n"); +- } ++ snoop_urb(dev, NULL, pipe, len1, tmo, SUBMIT); ++ + usb_unlock_device(dev); + i = usb_bulk_msg(dev, pipe, tbuf, len1, &len2, tmo); + usb_lock_device(dev); ++ snoop_urb(dev, NULL, pipe, len2, i, COMPLETE); + } + kfree(tbuf); + if (i < 0) +@@ -1053,13 +1053,6 @@ static int proc_do_submiturb(struct dev_ + is_in = 0; + uurb->endpoint &= ~USB_DIR_IN; + } +- snoop(&ps->dev->dev, "control urb: bRequest=%02x " +- "bRrequestType=%02x wValue=%04x " +- "wIndex=%04x wLength=%04x\n", +- dr->bRequest, dr->bRequestType, +- __le16_to_cpup(&dr->wValue), +- __le16_to_cpup(&dr->wIndex), +- __le16_to_cpup(&dr->wLength)); + break; + + case USBDEVFS_URB_TYPE_BULK: +@@ -1072,7 +1065,6 @@ static int proc_do_submiturb(struct dev_ + uurb->number_of_packets = 0; + if (uurb->buffer_length > MAX_USBFS_BUFFER_SIZE) + return -EINVAL; +- snoop(&ps->dev->dev, "bulk urb\n"); + break; + + case USBDEVFS_URB_TYPE_ISO: +@@ -1104,7 +1096,6 @@ static int proc_do_submiturb(struct dev_ + return -EINVAL; + } + uurb->buffer_length = totlen; +- snoop(&ps->dev->dev, "iso urb\n"); + break; + + case USBDEVFS_URB_TYPE_INTERRUPT: +@@ -1113,7 +1104,6 @@ static int proc_do_submiturb(struct dev_ + return -EINVAL; + if (uurb->buffer_length > MAX_USBFS_BUFFER_SIZE) + return -EINVAL; +- snoop(&ps->dev->dev, "interrupt urb\n"); + break; + + default: +@@ -1200,11 +1190,14 @@ static int proc_do_submiturb(struct dev_ + return -EFAULT; + } + } +- snoop_urb(as->urb, as->userurb); ++ snoop_urb(ps->dev, as->userurb, as->urb->pipe, ++ as->urb->transfer_buffer_length, 0, SUBMIT); + async_newpending(as); + if ((ret = usb_submit_urb(as->urb, GFP_KERNEL))) { + dev_printk(KERN_DEBUG, &ps->dev->dev, + "usbfs: usb_submit_urb returned %d\n", ret); ++ snoop_urb(ps->dev, as->userurb, as->urb->pipe, ++ 0, ret, COMPLETE); + async_removepending(as); + free_async(as); + return ret; +@@ -1668,7 +1661,7 @@ static int usbdev_ioctl(struct inode *in + break; + + case USBDEVFS_REAPURBNDELAY32: +- snoop(&dev->dev, "%s: REAPURBDELAY32\n", __func__); ++ snoop(&dev->dev, "%s: REAPURBNDELAY32\n", __func__); + ret = proc_reapurbnonblock_compat(ps, p); + break; + +@@ -1689,7 +1682,7 @@ static int usbdev_ioctl(struct inode *in + break; + + case USBDEVFS_REAPURBNDELAY: +- snoop(&dev->dev, "%s: REAPURBDELAY\n", __func__); ++ snoop(&dev->dev, "%s: REAPURBNDELAY\n", __func__); + ret = proc_reapurbnonblock(ps, p); + break; + diff --git a/usb/usb-whci-hcd-make-endpoint_reset-method-async.patch b/usb/usb-whci-hcd-make-endpoint_reset-method-async.patch new file mode 100644 index 00000000000000..fb907d09fb5623 --- /dev/null +++ b/usb/usb-whci-hcd-make-endpoint_reset-method-async.patch @@ -0,0 +1,156 @@ +From david.vrabel@csr.com Fri Jul 10 14:38:40 2009 +From: David Vrabel <david.vrabel@csr.com> +Date: Wed, 24 Jun 2009 18:26:40 +0100 +Subject: USB: whci-hcd: make endpoint_reset method async +To: Greg KH <greg@kroah.com> +Message-ID: <4A4261D0.9080006@csr.com> + + +usb_hcd_endpoint_reset() may be called in atomic context and must not +sleep. So make whci-hcd's endpoint_reset() asynchronous. URBs +submitted while the reset is in progress will be queued (on the std +list) and transfers will resume once the reset is complete. + +Signed-off-by: David Vrabel <david.vrabel@csr.com> +Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de> + + +--- + drivers/usb/host/whci/asl.c | 12 +++++++++++- + drivers/usb/host/whci/hcd.c | 8 ++++++-- + drivers/usb/host/whci/pzl.c | 12 +++++++++++- + drivers/usb/host/whci/qset.c | 4 ++-- + drivers/usb/host/whci/whci-hc.h | 1 + + 5 files changed, 31 insertions(+), 6 deletions(-) + +--- a/drivers/usb/host/whci/asl.c ++++ b/drivers/usb/host/whci/asl.c +@@ -227,11 +227,21 @@ void scan_async_work(struct work_struct + /* + * Now that the ASL is updated, complete the removal of any + * removed qsets. ++ * ++ * If the qset was to be reset, do so and reinsert it into the ++ * ASL if it has pending transfers. + */ + spin_lock_irq(&whc->lock); + + list_for_each_entry_safe(qset, t, &whc->async_removed_list, list_node) { + qset_remove_complete(whc, qset); ++ if (qset->reset) { ++ qset_reset(whc, qset); ++ if (!list_empty(&qset->stds)) { ++ asl_qset_insert_begin(whc, qset); ++ queue_work(whc->workqueue, &whc->async_work); ++ } ++ } + } + + spin_unlock_irq(&whc->lock); +@@ -267,7 +277,7 @@ int asl_urb_enqueue(struct whc *whc, str + else + err = qset_add_urb(whc, qset, urb, GFP_ATOMIC); + if (!err) { +- if (!qset->in_sw_list) ++ if (!qset->in_sw_list && !qset->remove) + asl_qset_insert_begin(whc, qset); + } else + usb_hcd_unlink_urb_from_ep(&whc->wusbhc.usb_hcd, urb); +--- a/drivers/usb/host/whci/hcd.c ++++ b/drivers/usb/host/whci/hcd.c +@@ -192,19 +192,23 @@ static void whc_endpoint_reset(struct us + struct wusbhc *wusbhc = usb_hcd_to_wusbhc(usb_hcd); + struct whc *whc = wusbhc_to_whc(wusbhc); + struct whc_qset *qset; ++ unsigned long flags; ++ ++ spin_lock_irqsave(&whc->lock, flags); + + qset = ep->hcpriv; + if (qset) { + qset->remove = 1; ++ qset->reset = 1; + + if (usb_endpoint_xfer_bulk(&ep->desc) + || usb_endpoint_xfer_control(&ep->desc)) + queue_work(whc->workqueue, &whc->async_work); + else + queue_work(whc->workqueue, &whc->periodic_work); +- +- qset_reset(whc, qset); + } ++ ++ spin_unlock_irqrestore(&whc->lock, flags); + } + + +--- a/drivers/usb/host/whci/pzl.c ++++ b/drivers/usb/host/whci/pzl.c +@@ -255,11 +255,21 @@ void scan_periodic_work(struct work_stru + /* + * Now that the PZL is updated, complete the removal of any + * removed qsets. ++ * ++ * If the qset was to be reset, do so and reinsert it into the ++ * PZL if it has pending transfers. + */ + spin_lock_irq(&whc->lock); + + list_for_each_entry_safe(qset, t, &whc->periodic_removed_list, list_node) { + qset_remove_complete(whc, qset); ++ if (qset->reset) { ++ qset_reset(whc, qset); ++ if (!list_empty(&qset->stds)) { ++ qset_insert_in_sw_list(whc, qset); ++ queue_work(whc->workqueue, &whc->periodic_work); ++ } ++ } + } + + spin_unlock_irq(&whc->lock); +@@ -295,7 +305,7 @@ int pzl_urb_enqueue(struct whc *whc, str + else + err = qset_add_urb(whc, qset, urb, GFP_ATOMIC); + if (!err) { +- if (!qset->in_sw_list) ++ if (!qset->in_sw_list && !qset->remove) + qset_insert_in_sw_list(whc, qset); + } else + usb_hcd_unlink_urb_from_ep(&whc->wusbhc.usb_hcd, urb); +--- a/drivers/usb/host/whci/qset.c ++++ b/drivers/usb/host/whci/qset.c +@@ -103,7 +103,6 @@ static void qset_fill_qh(struct whc_qset + void qset_clear(struct whc *whc, struct whc_qset *qset) + { + qset->td_start = qset->td_end = qset->ntds = 0; +- qset->remove = 0; + + qset->qh.link = cpu_to_le32(QH_LINK_NTDS(8) | QH_LINK_T); + qset->qh.status = qset->qh.status & QH_STATUS_SEQ_MASK; +@@ -125,7 +124,7 @@ void qset_clear(struct whc *whc, struct + */ + void qset_reset(struct whc *whc, struct whc_qset *qset) + { +- wait_for_completion(&qset->remove_complete); ++ qset->reset = 0; + + qset->qh.status &= ~QH_STATUS_SEQ_MASK; + qset->qh.cur_window = cpu_to_le32((1 << qset->max_burst) - 1); +@@ -156,6 +155,7 @@ struct whc_qset *get_qset(struct whc *wh + + void qset_remove_complete(struct whc *whc, struct whc_qset *qset) + { ++ qset->remove = 0; + list_del_init(&qset->list_node); + complete(&qset->remove_complete); + } +--- a/drivers/usb/host/whci/whci-hc.h ++++ b/drivers/usb/host/whci/whci-hc.h +@@ -264,6 +264,7 @@ struct whc_qset { + unsigned in_sw_list:1; + unsigned in_hw_list:1; + unsigned remove:1; ++ unsigned reset:1; + struct urb *pause_after_urb; + struct completion remove_complete; + int max_burst; |
