diff options
Diffstat (limited to 'drivers/usb/core/message.c')
-rw-r--r-- | drivers/usb/core/message.c | 20 |
1 files changed, 16 insertions, 4 deletions
diff --git a/drivers/usb/core/message.c b/drivers/usb/core/message.c index 1a15392326fc..bfa5eda0cc26 100644 --- a/drivers/usb/core/message.c +++ b/drivers/usb/core/message.c @@ -269,10 +269,11 @@ static void sg_clean(struct usb_sg_request *io) static void sg_complete(struct urb *urb) { + unsigned long flags; struct usb_sg_request *io = urb->context; int status = urb->status; - spin_lock(&io->lock); + spin_lock_irqsave(&io->lock, flags); /* In 2.5 we require hcds' endpoint queues not to progress after fault * reports, until the completion callback (this!) returns. That lets @@ -306,7 +307,7 @@ static void sg_complete(struct urb *urb) * unlink pending urbs so they won't rx/tx bad data. * careful: unlink can sometimes be synchronous... */ - spin_unlock(&io->lock); + spin_unlock_irqrestore(&io->lock, flags); for (i = 0, found = 0; i < io->entries; i++) { if (!io->urbs[i]) continue; @@ -323,7 +324,7 @@ static void sg_complete(struct urb *urb) } else if (urb == io->urbs[i]) found = 1; } - spin_lock(&io->lock); + spin_lock_irqsave(&io->lock, flags); } /* on the last completion, signal usb_sg_wait() */ @@ -332,7 +333,7 @@ static void sg_complete(struct urb *urb) if (!io->count) complete(&io->complete); - spin_unlock(&io->lock); + spin_unlock_irqrestore(&io->lock, flags); } @@ -1340,6 +1341,11 @@ void usb_enable_interface(struct usb_device *dev, * is submitted that needs that bandwidth. Some other operating systems * allocate bandwidth early, when a configuration is chosen. * + * xHCI reserves bandwidth and configures the alternate setting in + * usb_hcd_alloc_bandwidth(). If it fails the original interface altsetting + * may be disabled. Drivers cannot rely on any particular alternate + * setting being in effect after a failure. + * * This call is synchronous, and may not be used in an interrupt context. * Also, drivers must not change altsettings while urbs are scheduled for * endpoints in that interface; all such urbs must first be completed @@ -1375,6 +1381,12 @@ int usb_set_interface(struct usb_device *dev, int interface, int alternate) alternate); return -EINVAL; } + /* + * usb3 hosts configure the interface in usb_hcd_alloc_bandwidth, + * including freeing dropped endpoint ring buffers. + * Make sure the interface endpoints are flushed before that + */ + usb_disable_interface(dev, iface, false); /* Make sure we have enough bandwidth for this alternate interface. * Remove the current alt setting and add the new alt setting. |