Commit 9439eb94 authored by Alan Stern's avatar Alan Stern Committed by Greg Kroah-Hartman

USB: update spinlock usage for root-hub URBs

This patch (as952) adjusts the spinlock usage in the root-hub
emulation part of usbcore, to make it match more closely the pattern
used by regular host controller drivers.  To wit: The private lock
(usb_hcd_root_hub_lock) is held throughout the important parts, and it
is dropped temporarily without re-enabling interrupts around the call
to usb_hcd_giveback_urb().

A nice side effect is that the code now avoids calling
local_irq_save(), thereby becoming more RT-friendly.
Signed-off-by: default avatarAlan Stern <stern@rowland.harvard.edu>
Signed-off-by: default avatarGreg Kroah-Hartman <gregkh@suse.de>
parent d617bc83
...@@ -356,10 +356,11 @@ static int rh_call_control (struct usb_hcd *hcd, struct urb *urb) ...@@ -356,10 +356,11 @@ static int rh_call_control (struct usb_hcd *hcd, struct urb *urb)
const u8 *bufp = tbuf; const u8 *bufp = tbuf;
int len = 0; int len = 0;
int patch_wakeup = 0; int patch_wakeup = 0;
unsigned long flags;
int status = 0; int status = 0;
int n; int n;
might_sleep();
cmd = (struct usb_ctrlrequest *) urb->setup_packet; cmd = (struct usb_ctrlrequest *) urb->setup_packet;
typeReq = (cmd->bRequestType << 8) | cmd->bRequest; typeReq = (cmd->bRequestType << 8) | cmd->bRequest;
wValue = le16_to_cpu (cmd->wValue); wValue = le16_to_cpu (cmd->wValue);
...@@ -523,13 +524,21 @@ static int rh_call_control (struct usb_hcd *hcd, struct urb *urb) ...@@ -523,13 +524,21 @@ static int rh_call_control (struct usb_hcd *hcd, struct urb *urb)
} }
/* any errors get returned through the urb completion */ /* any errors get returned through the urb completion */
local_irq_save (flags); spin_lock_irq(&hcd_root_hub_lock);
spin_lock (&urb->lock); spin_lock(&urb->lock);
if (urb->status == -EINPROGRESS) if (urb->status == -EINPROGRESS)
urb->status = status; urb->status = status;
spin_unlock (&urb->lock); spin_unlock(&urb->lock);
usb_hcd_giveback_urb (hcd, urb);
local_irq_restore (flags); /* This peculiar use of spinlocks echoes what real HC drivers do.
* Avoiding calls to local_irq_disable/enable makes the code
* RT-friendly.
*/
spin_unlock(&hcd_root_hub_lock);
usb_hcd_giveback_urb(hcd, urb);
spin_lock(&hcd_root_hub_lock);
spin_unlock_irq(&hcd_root_hub_lock);
return 0; return 0;
} }
...@@ -559,8 +568,7 @@ void usb_hcd_poll_rh_status(struct usb_hcd *hcd) ...@@ -559,8 +568,7 @@ void usb_hcd_poll_rh_status(struct usb_hcd *hcd)
if (length > 0) { if (length > 0) {
/* try to complete the status urb */ /* try to complete the status urb */
local_irq_save (flags); spin_lock_irqsave(&hcd_root_hub_lock, flags);
spin_lock(&hcd_root_hub_lock);
urb = hcd->status_urb; urb = hcd->status_urb;
if (urb) { if (urb) {
spin_lock(&urb->lock); spin_lock(&urb->lock);
...@@ -574,16 +582,16 @@ void usb_hcd_poll_rh_status(struct usb_hcd *hcd) ...@@ -574,16 +582,16 @@ void usb_hcd_poll_rh_status(struct usb_hcd *hcd)
} else /* urb has been unlinked */ } else /* urb has been unlinked */
length = 0; length = 0;
spin_unlock(&urb->lock); spin_unlock(&urb->lock);
spin_unlock(&hcd_root_hub_lock);
usb_hcd_giveback_urb(hcd, urb);
spin_lock(&hcd_root_hub_lock);
} else } else
length = 0; length = 0;
spin_unlock(&hcd_root_hub_lock);
/* local irqs are always blocked in completions */ if (length <= 0)
if (length > 0)
usb_hcd_giveback_urb (hcd, urb);
else
hcd->poll_pending = 1; hcd->poll_pending = 1;
local_irq_restore (flags); spin_unlock_irqrestore(&hcd_root_hub_lock, flags);
} }
/* The USB 2.0 spec says 256 ms. This is close enough and won't /* The USB 2.0 spec says 256 ms. This is close enough and won't
...@@ -651,25 +659,23 @@ static int usb_rh_urb_dequeue (struct usb_hcd *hcd, struct urb *urb) ...@@ -651,25 +659,23 @@ static int usb_rh_urb_dequeue (struct usb_hcd *hcd, struct urb *urb)
{ {
unsigned long flags; unsigned long flags;
spin_lock_irqsave(&hcd_root_hub_lock, flags);
if (usb_endpoint_num(&urb->ep->desc) == 0) { /* Control URB */ if (usb_endpoint_num(&urb->ep->desc) == 0) { /* Control URB */
; /* Do nothing */ ; /* Do nothing */
} else { /* Status URB */ } else { /* Status URB */
if (!hcd->uses_new_polling) if (!hcd->uses_new_polling)
del_timer (&hcd->rh_timer); del_timer (&hcd->rh_timer);
local_irq_save (flags);
spin_lock (&hcd_root_hub_lock);
if (urb == hcd->status_urb) { if (urb == hcd->status_urb) {
hcd->status_urb = NULL; hcd->status_urb = NULL;
urb->hcpriv = NULL; urb->hcpriv = NULL;
} else
urb = NULL; /* wasn't fully queued */
spin_unlock (&hcd_root_hub_lock);
if (urb)
usb_hcd_giveback_urb (hcd, urb);
local_irq_restore (flags);
}
spin_unlock(&hcd_root_hub_lock);
usb_hcd_giveback_urb(hcd, urb);
spin_lock(&hcd_root_hub_lock);
}
}
spin_unlock_irqrestore(&hcd_root_hub_lock, flags);
return 0; return 0;
} }
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment