aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorPete Zaitcev <zaitcev@redhat.com>2007-06-08 16:37:49 -0400
committerGreg Kroah-Hartman <gregkh@suse.de>2007-07-12 19:34:31 -0400
commit9f6a93f7bbb6d73ca0e43c000f3bbf521cd4f782 (patch)
tree50b53635eb5ca5b615b33aa3a00c7f155e691484
parent60aac1ec26b960fe77bf600457bc6c06f8aa7db4 (diff)
usb: free DMA mappings if enqueue fails
This patch releases DMA resources if enqueue fails in the HCD. Linux had this bug ever since we converted from virt_to_bus for 2.4. It is difficult to hit. A user would need a significant memory pressure or some other unusual condition. It was reported to me by IBM. They ran a management application for RSA II adapters which sent Bulk requests to an Interrupt endpoint. Submissions got rejected by HCD due to an invalid interval value and the swiotlb pool became depleted in the matter of hours. We fixed the invalid interval issue in devio.c separately, but this seems to be a bug worth fixing as well. Signed-off-by: Pete Zaitcev <zaitcev@redhat.com> Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de>
-rw-r--r--drivers/usb/core/hcd.c47
1 files changed, 20 insertions, 27 deletions
diff --git a/drivers/usb/core/hcd.c b/drivers/usb/core/hcd.c
index e5058fb26a7e..3df538539b48 100644
--- a/drivers/usb/core/hcd.c
+++ b/drivers/usb/core/hcd.c
@@ -903,17 +903,32 @@ EXPORT_SYMBOL (usb_calc_bus_time);
903 903
904/*-------------------------------------------------------------------------*/ 904/*-------------------------------------------------------------------------*/
905 905
906static void urb_unlink (struct urb *urb) 906static void urb_unlink(struct usb_hcd *hcd, struct urb *urb)
907{ 907{
908 unsigned long flags; 908 unsigned long flags;
909 int at_root_hub = (urb->dev == hcd->self.root_hub);
909 910
910 /* clear all state linking urb to this dev (and hcd) */ 911 /* clear all state linking urb to this dev (and hcd) */
911
912 spin_lock_irqsave (&hcd_data_lock, flags); 912 spin_lock_irqsave (&hcd_data_lock, flags);
913 list_del_init (&urb->urb_list); 913 list_del_init (&urb->urb_list);
914 spin_unlock_irqrestore (&hcd_data_lock, flags); 914 spin_unlock_irqrestore (&hcd_data_lock, flags);
915}
916 915
916 if (hcd->self.uses_dma && !at_root_hub) {
917 if (usb_pipecontrol (urb->pipe)
918 && !(urb->transfer_flags & URB_NO_SETUP_DMA_MAP))
919 dma_unmap_single (hcd->self.controller, urb->setup_dma,
920 sizeof (struct usb_ctrlrequest),
921 DMA_TO_DEVICE);
922 if (urb->transfer_buffer_length != 0
923 && !(urb->transfer_flags & URB_NO_TRANSFER_DMA_MAP))
924 dma_unmap_single (hcd->self.controller,
925 urb->transfer_dma,
926 urb->transfer_buffer_length,
927 usb_pipein (urb->pipe)
928 ? DMA_FROM_DEVICE
929 : DMA_TO_DEVICE);
930 }
931}
917 932
918/* may be called in any context with a valid urb->dev usecount 933/* may be called in any context with a valid urb->dev usecount
919 * caller surrenders "ownership" of urb 934 * caller surrenders "ownership" of urb
@@ -1016,7 +1031,7 @@ doit:
1016 status = hcd->driver->urb_enqueue (hcd, ep, urb, mem_flags); 1031 status = hcd->driver->urb_enqueue (hcd, ep, urb, mem_flags);
1017done: 1032done:
1018 if (unlikely (status)) { 1033 if (unlikely (status)) {
1019 urb_unlink (urb); 1034 urb_unlink(hcd, urb);
1020 atomic_dec (&urb->use_count); 1035 atomic_dec (&urb->use_count);
1021 if (urb->reject) 1036 if (urb->reject)
1022 wake_up (&usb_kill_urb_queue); 1037 wake_up (&usb_kill_urb_queue);
@@ -1400,29 +1415,7 @@ EXPORT_SYMBOL (usb_bus_start_enum);
1400 */ 1415 */
1401void usb_hcd_giveback_urb (struct usb_hcd *hcd, struct urb *urb) 1416void usb_hcd_giveback_urb (struct usb_hcd *hcd, struct urb *urb)
1402{ 1417{
1403 int at_root_hub; 1418 urb_unlink(hcd, urb);
1404
1405 at_root_hub = (urb->dev == hcd->self.root_hub);
1406 urb_unlink (urb);
1407
1408 /* lower level hcd code should use *_dma exclusively if the
1409 * host controller does DMA */
1410 if (hcd->self.uses_dma && !at_root_hub) {
1411 if (usb_pipecontrol (urb->pipe)
1412 && !(urb->transfer_flags & URB_NO_SETUP_DMA_MAP))
1413 dma_unmap_single (hcd->self.controller, urb->setup_dma,
1414 sizeof (struct usb_ctrlrequest),
1415 DMA_TO_DEVICE);
1416 if (urb->transfer_buffer_length != 0
1417 && !(urb->transfer_flags & URB_NO_TRANSFER_DMA_MAP))
1418 dma_unmap_single (hcd->self.controller,
1419 urb->transfer_dma,
1420 urb->transfer_buffer_length,
1421 usb_pipein (urb->pipe)
1422 ? DMA_FROM_DEVICE
1423 : DMA_TO_DEVICE);
1424 }
1425
1426 usbmon_urb_complete (&hcd->self, urb); 1419 usbmon_urb_complete (&hcd->self, urb);
1427 usb_unanchor_urb(urb); 1420 usb_unanchor_urb(urb);
1428 1421