Skip to content

Commit

Permalink
Merge 3.2-rc1 into usb-linus
Browse files Browse the repository at this point in the history
This is needed to catch the resume bug that was bothering lots of us from
testing some XHCI bug fixes in the suspend/resume path.

Signed-off-by: Greg Kroah-Hartman <[email protected]>
  • Loading branch information
gregkh committed Apr 8, 2012
2 parents 0034102 + a2457ee commit e3fa252
Show file tree
Hide file tree
Showing 7 changed files with 81 additions and 17 deletions.
22 changes: 22 additions & 0 deletions Documentation/usb/URB.txt
Original file line number Diff line number Diff line change
Expand Up @@ -168,6 +168,28 @@ that if the completion handler or anyone else tries to resubmit it
they will get a -EPERM error. Thus you can be sure that when
usb_kill_urb() returns, the URB is totally idle.

There is a lifetime issue to consider. An URB may complete at any
time, and the completion handler may free the URB. If this happens
while usb_unlink_urb or usb_kill_urb is running, it will cause a
memory-access violation. The driver is responsible for avoiding this,
which often means some sort of lock will be needed to prevent the URB
from being deallocated while it is still in use.

On the other hand, since usb_unlink_urb may end up calling the
completion handler, the handler must not take any lock that is held
when usb_unlink_urb is invoked. The general solution to this problem
is to increment the URB's reference count while holding the lock, then
drop the lock and call usb_unlink_urb or usb_kill_urb, and then
decrement the URB's reference count. You increment the reference
count by calling

struct urb *usb_get_urb(struct urb *urb)

(ignore the return value; it is the same as the argument) and
decrement the reference count by calling usb_free_urb. Of course,
none of this is necessary if there's no danger of the URB being freed
by the completion handler.


1.7. What about the completion handler?

Expand Down
6 changes: 3 additions & 3 deletions Documentation/usb/usbmon.txt
Original file line number Diff line number Diff line change
Expand Up @@ -183,10 +183,10 @@ An input control transfer to get a port status.
d5ea89a0 3575914555 S Ci:1:001:0 s a3 00 0000 0003 0004 4 <
d5ea89a0 3575914560 C Ci:1:001:0 0 4 = 01050000

An output bulk transfer to send a SCSI command 0x5E in a 31-byte Bulk wrapper
to a storage device at address 5:
An output bulk transfer to send a SCSI command 0x28 (READ_10) in a 31-byte
Bulk wrapper to a storage device at address 5:

dd65f0e8 4128379752 S Bo:1:005:2 -115 31 = 55534243 5e000000 00000000 00000600 00000000 00000000 00000000 000000
dd65f0e8 4128379752 S Bo:1:005:2 -115 31 = 55534243 ad000000 00800000 80010a28 20000000 20000040 00000000 000000
dd65f0e8 4128379808 C Bo:1:005:2 0 31 >

* Raw binary format and API
Expand Down
16 changes: 8 additions & 8 deletions drivers/usb/Kconfig
Original file line number Diff line number Diff line change
Expand Up @@ -2,14 +2,6 @@
# USB device configuration
#

menuconfig USB_SUPPORT
bool "USB support"
depends on HAS_IOMEM
default y
---help---
This option adds core support for Universal Serial Bus (USB).
You will also need drivers from the following menu to make use of it.

# many non-PCI SOC chips embed OHCI
config USB_ARCH_HAS_OHCI
boolean
Expand Down Expand Up @@ -63,6 +55,14 @@ config USB_ARCH_HAS_XHCI
boolean
default PCI

menuconfig USB_SUPPORT
bool "USB support"
depends on HAS_IOMEM
default y
---help---
This option adds core support for Universal Serial Bus (USB).
You will also need drivers from the following menu to make use of it.

if USB_SUPPORT

config USB_COMMON
Expand Down
11 changes: 6 additions & 5 deletions drivers/usb/core/message.c
Original file line number Diff line number Diff line change
Expand Up @@ -308,7 +308,8 @@ static void sg_complete(struct urb *urb)
retval = usb_unlink_urb(io->urbs [i]);
if (retval != -EINPROGRESS &&
retval != -ENODEV &&
retval != -EBUSY)
retval != -EBUSY &&
retval != -EIDRM)
dev_err(&io->dev->dev,
"%s, unlink --> %d\n",
__func__, retval);
Expand All @@ -317,7 +318,6 @@ static void sg_complete(struct urb *urb)
}
spin_lock(&io->lock);
}
urb->dev = NULL;

/* on the last completion, signal usb_sg_wait() */
io->bytes += urb->actual_length;
Expand Down Expand Up @@ -524,7 +524,6 @@ void usb_sg_wait(struct usb_sg_request *io)
case -ENXIO: /* hc didn't queue this one */
case -EAGAIN:
case -ENOMEM:
io->urbs[i]->dev = NULL;
retval = 0;
yield();
break;
Expand All @@ -542,7 +541,6 @@ void usb_sg_wait(struct usb_sg_request *io)

/* fail any uncompleted urbs */
default:
io->urbs[i]->dev = NULL;
io->urbs[i]->status = retval;
dev_dbg(&io->dev->dev, "%s, submit --> %d\n",
__func__, retval);
Expand Down Expand Up @@ -593,7 +591,10 @@ void usb_sg_cancel(struct usb_sg_request *io)
if (!io->urbs [i]->dev)
continue;
retval = usb_unlink_urb(io->urbs [i]);
if (retval != -EINPROGRESS && retval != -EBUSY)
if (retval != -EINPROGRESS
&& retval != -ENODEV
&& retval != -EBUSY
&& retval != -EIDRM)
dev_warn(&io->dev->dev, "%s, unlink --> %d\n",
__func__, retval);
}
Expand Down
12 changes: 12 additions & 0 deletions drivers/usb/core/urb.c
Original file line number Diff line number Diff line change
Expand Up @@ -539,6 +539,10 @@ EXPORT_SYMBOL_GPL(usb_submit_urb);
* never submitted, or it was unlinked before, or the hardware is already
* finished with it), even if the completion handler has not yet run.
*
* The URB must not be deallocated while this routine is running. In
* particular, when a driver calls this routine, it must insure that the
* completion handler cannot deallocate the URB.
*
* Unlinking and Endpoint Queues:
*
* [The behaviors and guarantees described below do not apply to virtual
Expand Down Expand Up @@ -603,6 +607,10 @@ EXPORT_SYMBOL_GPL(usb_unlink_urb);
* with error -EPERM. Thus even if the URB's completion handler always
* tries to resubmit, it will not succeed and the URB will become idle.
*
* The URB must not be deallocated while this routine is running. In
* particular, when a driver calls this routine, it must insure that the
* completion handler cannot deallocate the URB.
*
* This routine may not be used in an interrupt context (such as a bottom
* half or a completion handler), or when holding a spinlock, or in other
* situations where the caller can't schedule().
Expand Down Expand Up @@ -640,6 +648,10 @@ EXPORT_SYMBOL_GPL(usb_kill_urb);
* with error -EPERM. Thus even if the URB's completion handler always
* tries to resubmit, it will not succeed and the URB will become idle.
*
* The URB must not be deallocated while this routine is running. In
* particular, when a driver calls this routine, it must insure that the
* completion handler cannot deallocate the URB.
*
* This routine may not be used in an interrupt context (such as a bottom
* half or a completion handler), or when holding a spinlock, or in other
* situations where the caller can't schedule().
Expand Down
1 change: 0 additions & 1 deletion drivers/usb/gadget/inode.c
Original file line number Diff line number Diff line change
Expand Up @@ -1574,7 +1574,6 @@ static void destroy_ep_files (struct dev_data *dev)
DBG (dev, "%s %d\n", __func__, dev->state);

/* dev->state must prevent interference */
restart:
spin_lock_irq (&dev->lock);
while (!list_empty(&dev->epfiles)) {
struct ep_data *ep;
Expand Down
30 changes: 30 additions & 0 deletions drivers/usb/storage/usb.c
Original file line number Diff line number Diff line change
Expand Up @@ -132,6 +132,35 @@ static struct us_unusual_dev for_dynamic_ids =
#undef COMPLIANT_DEV
#undef USUAL_DEV

#ifdef CONFIG_LOCKDEP

static struct lock_class_key us_interface_key[USB_MAXINTERFACES];

static void us_set_lock_class(struct mutex *mutex,
struct usb_interface *intf)
{
struct usb_device *udev = interface_to_usbdev(intf);
struct usb_host_config *config = udev->actconfig;
int i;

for (i = 0; i < config->desc.bNumInterfaces; i++) {
if (config->interface[i] == intf)
break;
}

BUG_ON(i == config->desc.bNumInterfaces);

lockdep_set_class(mutex, &us_interface_key[i]);
}

#else

static void us_set_lock_class(struct mutex *mutex,
struct usb_interface *intf)
{
}

#endif

#ifdef CONFIG_PM /* Minimal support for suspend and resume */

Expand Down Expand Up @@ -895,6 +924,7 @@ int usb_stor_probe1(struct us_data **pus,
*pus = us = host_to_us(host);
memset(us, 0, sizeof(struct us_data));
mutex_init(&(us->dev_mutex));
us_set_lock_class(&us->dev_mutex, intf);
init_completion(&us->cmnd_ready);
init_completion(&(us->notify));
init_waitqueue_head(&us->delay_wait);
Expand Down

0 comments on commit e3fa252

Please sign in to comment.