aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/usb/core/urb.c
diff options
context:
space:
mode:
authorLinus Torvalds <torvalds@linux-foundation.org>2010-08-10 18:05:02 -0400
committerLinus Torvalds <torvalds@linux-foundation.org>2010-08-10 18:05:02 -0400
commit9895850b23886e030cd1e7241d5529a57e969c3d (patch)
tree1061626db450aeb72dcfcd247c24b33e5238c8c4 /drivers/usb/core/urb.c
parentfc385c313275b114bc6ad36e60c5177d63250548 (diff)
parentb58af4066d240b18b43f202e07b9ec7461d90b17 (diff)
Merge git://git.kernel.org/pub/scm/linux/kernel/git/gregkh/usb-2.6
* git://git.kernel.org/pub/scm/linux/kernel/git/gregkh/usb-2.6: (148 commits) USB: serial: fix stalled writes USB: remove fake "address-of" expressions USB: fix thread-unsafe anchor utiliy routines USB: usbtest: support test device with only one iso-in or iso-out endpoint USB: usbtest: avoid to free coherent buffer in atomic context USB: xhci: Set DMA mask for host. USB: xhci: Don't flush doorbell writes. USB: xhci: Reduce reads and writes of interrupter registers. USB: xhci: Make xhci_set_hc_event_deq() static. USB: xhci: Minimize HW event ring dequeue pointer writes. USB: xhci: Make xhci_handle_event() static. USB: xhci: Remove unnecessary reads of IRQ_PENDING register. USB: xhci: Performance - move xhci_work() into xhci_irq() USB: xhci: Performance - move interrupt handlers into xhci-ring.c USB: xhci: Performance - move functions that find ep ring. USB:: fix linux/usb.h kernel-doc warnings USB: add USB serial ssu100 driver USB: usb-storage: implement autosuspend USB: ehci: fix remove of ehci debugfs dir USB: Add USB 2.0 to ssb ohci driver ...
Diffstat (limited to 'drivers/usb/core/urb.c')
-rw-r--r--drivers/usb/core/urb.c50
1 files changed, 21 insertions, 29 deletions
diff --git a/drivers/usb/core/urb.c b/drivers/usb/core/urb.c
index 7c0555548ac..419e6b34e2f 100644
--- a/drivers/usb/core/urb.c
+++ b/drivers/usb/core/urb.c
@@ -137,6 +137,16 @@ void usb_anchor_urb(struct urb *urb, struct usb_anchor *anchor)
137} 137}
138EXPORT_SYMBOL_GPL(usb_anchor_urb); 138EXPORT_SYMBOL_GPL(usb_anchor_urb);
139 139
140/* Callers must hold anchor->lock */
141static void __usb_unanchor_urb(struct urb *urb, struct usb_anchor *anchor)
142{
143 urb->anchor = NULL;
144 list_del(&urb->anchor_list);
145 usb_put_urb(urb);
146 if (list_empty(&anchor->urb_list))
147 wake_up(&anchor->wait);
148}
149
140/** 150/**
141 * usb_unanchor_urb - unanchors an URB 151 * usb_unanchor_urb - unanchors an URB
142 * @urb: pointer to the urb to anchor 152 * @urb: pointer to the urb to anchor
@@ -156,17 +166,14 @@ void usb_unanchor_urb(struct urb *urb)
156 return; 166 return;
157 167
158 spin_lock_irqsave(&anchor->lock, flags); 168 spin_lock_irqsave(&anchor->lock, flags);
159 if (unlikely(anchor != urb->anchor)) { 169 /*
160 /* we've lost the race to another thread */ 170 * At this point, we could be competing with another thread which
161 spin_unlock_irqrestore(&anchor->lock, flags); 171 * has the same intention. To protect the urb from being unanchored
162 return; 172 * twice, only the winner of the race gets the job.
163 } 173 */
164 urb->anchor = NULL; 174 if (likely(anchor == urb->anchor))
165 list_del(&urb->anchor_list); 175 __usb_unanchor_urb(urb, anchor);
166 spin_unlock_irqrestore(&anchor->lock, flags); 176 spin_unlock_irqrestore(&anchor->lock, flags);
167 usb_put_urb(urb);
168 if (list_empty(&anchor->urb_list))
169 wake_up(&anchor->wait);
170} 177}
171EXPORT_SYMBOL_GPL(usb_unanchor_urb); 178EXPORT_SYMBOL_GPL(usb_unanchor_urb);
172 179
@@ -749,20 +756,11 @@ EXPORT_SYMBOL_GPL(usb_unpoison_anchored_urbs);
749void usb_unlink_anchored_urbs(struct usb_anchor *anchor) 756void usb_unlink_anchored_urbs(struct usb_anchor *anchor)
750{ 757{
751 struct urb *victim; 758 struct urb *victim;
752 unsigned long flags;
753 759
754 spin_lock_irqsave(&anchor->lock, flags); 760 while ((victim = usb_get_from_anchor(anchor)) != NULL) {
755 while (!list_empty(&anchor->urb_list)) {
756 victim = list_entry(anchor->urb_list.prev, struct urb,
757 anchor_list);
758 usb_get_urb(victim);
759 spin_unlock_irqrestore(&anchor->lock, flags);
760 /* this will unanchor the URB */
761 usb_unlink_urb(victim); 761 usb_unlink_urb(victim);
762 usb_put_urb(victim); 762 usb_put_urb(victim);
763 spin_lock_irqsave(&anchor->lock, flags);
764 } 763 }
765 spin_unlock_irqrestore(&anchor->lock, flags);
766} 764}
767EXPORT_SYMBOL_GPL(usb_unlink_anchored_urbs); 765EXPORT_SYMBOL_GPL(usb_unlink_anchored_urbs);
768 766
@@ -799,12 +797,11 @@ struct urb *usb_get_from_anchor(struct usb_anchor *anchor)
799 victim = list_entry(anchor->urb_list.next, struct urb, 797 victim = list_entry(anchor->urb_list.next, struct urb,
800 anchor_list); 798 anchor_list);
801 usb_get_urb(victim); 799 usb_get_urb(victim);
802 spin_unlock_irqrestore(&anchor->lock, flags); 800 __usb_unanchor_urb(victim, anchor);
803 usb_unanchor_urb(victim);
804 } else { 801 } else {
805 spin_unlock_irqrestore(&anchor->lock, flags);
806 victim = NULL; 802 victim = NULL;
807 } 803 }
804 spin_unlock_irqrestore(&anchor->lock, flags);
808 805
809 return victim; 806 return victim;
810} 807}
@@ -826,12 +823,7 @@ void usb_scuttle_anchored_urbs(struct usb_anchor *anchor)
826 while (!list_empty(&anchor->urb_list)) { 823 while (!list_empty(&anchor->urb_list)) {
827 victim = list_entry(anchor->urb_list.prev, struct urb, 824 victim = list_entry(anchor->urb_list.prev, struct urb,
828 anchor_list); 825 anchor_list);
829 usb_get_urb(victim); 826 __usb_unanchor_urb(victim, anchor);
830 spin_unlock_irqrestore(&anchor->lock, flags);
831 /* this may free the URB */
832 usb_unanchor_urb(victim);
833 usb_put_urb(victim);
834 spin_lock_irqsave(&anchor->lock, flags);
835 } 827 }
836 spin_unlock_irqrestore(&anchor->lock, flags); 828 spin_unlock_irqrestore(&anchor->lock, flags);
837} 829}