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.  |