aboutsummaryrefslogtreecommitdiffstats
path: root/drivers
diff options
context:
space:
mode:
authorAlan Stern <stern@rowland.harvard.edu>2007-08-02 15:05:45 -0400
committerGreg Kroah-Hartman <gregkh@suse.de>2007-10-12 17:55:01 -0400
commit9439eb94b5c374d5b02699f8897fc43aa3603701 (patch)
tree87e4629b1c9e0f14da4562cd1cb38a809777c311 /drivers
parentd617bc83ff48ebf0df253605529d8b3bef15773a (diff)
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: Alan Stern <stern@rowland.harvard.edu> Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de>
Diffstat (limited to 'drivers')
-rw-r--r--drivers/usb/core/hcd.c52
1 files changed, 29 insertions, 23 deletions
diff --git a/drivers/usb/core/hcd.c b/drivers/usb/core/hcd.c
index 47a055a2acf5..f8e7deb03ee9 100644
--- a/drivers/usb/core/hcd.c
+++ b/drivers/usb/core/hcd.c
@@ -356,10 +356,11 @@ static int rh_call_control (struct usb_hcd *hcd, struct urb *urb)
356 const u8 *bufp = tbuf; 356 const u8 *bufp = tbuf;
357 int len = 0; 357 int len = 0;
358 int patch_wakeup = 0; 358 int patch_wakeup = 0;
359 unsigned long flags;
360 int status = 0; 359 int status = 0;
361 int n; 360 int n;
362 361
362 might_sleep();
363
363 cmd = (struct usb_ctrlrequest *) urb->setup_packet; 364 cmd = (struct usb_ctrlrequest *) urb->setup_packet;
364 typeReq = (cmd->bRequestType << 8) | cmd->bRequest; 365 typeReq = (cmd->bRequestType << 8) | cmd->bRequest;
365 wValue = le16_to_cpu (cmd->wValue); 366 wValue = le16_to_cpu (cmd->wValue);
@@ -523,13 +524,21 @@ error:
523 } 524 }
524 525
525 /* any errors get returned through the urb completion */ 526 /* any errors get returned through the urb completion */
526 local_irq_save (flags); 527 spin_lock_irq(&hcd_root_hub_lock);
527 spin_lock (&urb->lock); 528 spin_lock(&urb->lock);
528 if (urb->status == -EINPROGRESS) 529 if (urb->status == -EINPROGRESS)
529 urb->status = status; 530 urb->status = status;
530 spin_unlock (&urb->lock); 531 spin_unlock(&urb->lock);
531 usb_hcd_giveback_urb (hcd, urb); 532
532 local_irq_restore (flags); 533 /* This peculiar use of spinlocks echoes what real HC drivers do.
534 * Avoiding calls to local_irq_disable/enable makes the code
535 * RT-friendly.
536 */
537 spin_unlock(&hcd_root_hub_lock);
538 usb_hcd_giveback_urb(hcd, urb);
539 spin_lock(&hcd_root_hub_lock);
540
541 spin_unlock_irq(&hcd_root_hub_lock);
533 return 0; 542 return 0;
534} 543}
535 544
@@ -559,8 +568,7 @@ void usb_hcd_poll_rh_status(struct usb_hcd *hcd)
559 if (length > 0) { 568 if (length > 0) {
560 569
561 /* try to complete the status urb */ 570 /* try to complete the status urb */
562 local_irq_save (flags); 571 spin_lock_irqsave(&hcd_root_hub_lock, flags);
563 spin_lock(&hcd_root_hub_lock);
564 urb = hcd->status_urb; 572 urb = hcd->status_urb;
565 if (urb) { 573 if (urb) {
566 spin_lock(&urb->lock); 574 spin_lock(&urb->lock);
@@ -574,16 +582,16 @@ void usb_hcd_poll_rh_status(struct usb_hcd *hcd)
574 } else /* urb has been unlinked */ 582 } else /* urb has been unlinked */
575 length = 0; 583 length = 0;
576 spin_unlock(&urb->lock); 584 spin_unlock(&urb->lock);
585
586 spin_unlock(&hcd_root_hub_lock);
587 usb_hcd_giveback_urb(hcd, urb);
588 spin_lock(&hcd_root_hub_lock);
577 } else 589 } else
578 length = 0; 590 length = 0;
579 spin_unlock(&hcd_root_hub_lock);
580 591
581 /* local irqs are always blocked in completions */ 592 if (length <= 0)
582 if (length > 0)
583 usb_hcd_giveback_urb (hcd, urb);
584 else
585 hcd->poll_pending = 1; 593 hcd->poll_pending = 1;
586 local_irq_restore (flags); 594 spin_unlock_irqrestore(&hcd_root_hub_lock, flags);
587 } 595 }
588 596
589 /* The USB 2.0 spec says 256 ms. This is close enough and won't 597 /* 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{ 659{
652 unsigned long flags; 660 unsigned long flags;
653 661
662 spin_lock_irqsave(&hcd_root_hub_lock, flags);
654 if (usb_endpoint_num(&urb->ep->desc) == 0) { /* Control URB */ 663 if (usb_endpoint_num(&urb->ep->desc) == 0) { /* Control URB */
655 ; /* Do nothing */ 664 ; /* Do nothing */
656 665
657 } else { /* Status URB */ 666 } else { /* Status URB */
658 if (!hcd->uses_new_polling) 667 if (!hcd->uses_new_polling)
659 del_timer (&hcd->rh_timer); 668 del_timer (&hcd->rh_timer);
660 local_irq_save (flags);
661 spin_lock (&hcd_root_hub_lock);
662 if (urb == hcd->status_urb) { 669 if (urb == hcd->status_urb) {
663 hcd->status_urb = NULL; 670 hcd->status_urb = NULL;
664 urb->hcpriv = NULL; 671 urb->hcpriv = NULL;
665 } else
666 urb = NULL; /* wasn't fully queued */
667 spin_unlock (&hcd_root_hub_lock);
668 if (urb)
669 usb_hcd_giveback_urb (hcd, urb);
670 local_irq_restore (flags);
671 }
672 672
673 spin_unlock(&hcd_root_hub_lock);
674 usb_hcd_giveback_urb(hcd, urb);
675 spin_lock(&hcd_root_hub_lock);
676 }
677 }
678 spin_unlock_irqrestore(&hcd_root_hub_lock, flags);
673 return 0; 679 return 0;
674} 680}
675 681