aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorClemens Ladisch <clemens@ladisch.de>2011-12-03 17:41:31 -0500
committerGreg Kroah-Hartman <gregkh@suse.de>2011-12-09 19:18:19 -0500
commitbc677d5b64644c399cd3db6a905453e611f402ab (patch)
treed973a02c33f0e0d407e9ec7c6054220e15d5c72f
parent8ad028bd973ec1ead4982e21ab0400c956aff4b5 (diff)
usb: fix number of mapped SG DMA entries
Add a new field num_mapped_sgs to struct urb so that we have a place to store the number of mapped entries and can also retain the original value of entries in num_sgs. Previously, usb_hcd_map_urb_for_dma() would overwrite this with the number of mapped entries, which would break dma_unmap_sg() because it requires the original number of entries. This fixes warnings like the following when using USB storage devices: ------------[ cut here ]------------ WARNING: at lib/dma-debug.c:902 check_unmap+0x4e4/0x695() ehci_hcd 0000:00:12.2: DMA-API: device driver frees DMA sg list with different entry count [map count=4] [unmap count=1] Modules linked in: ohci_hcd ehci_hcd Pid: 0, comm: kworker/0:1 Not tainted 3.2.0-rc2+ #319 Call Trace: <IRQ> [<ffffffff81036d3b>] warn_slowpath_common+0x80/0x98 [<ffffffff81036de7>] warn_slowpath_fmt+0x41/0x43 [<ffffffff811fa5ae>] check_unmap+0x4e4/0x695 [<ffffffff8105e92c>] ? trace_hardirqs_off+0xd/0xf [<ffffffff8147208b>] ? _raw_spin_unlock_irqrestore+0x33/0x50 [<ffffffff811fa84a>] debug_dma_unmap_sg+0xeb/0x117 [<ffffffff8137b02f>] usb_hcd_unmap_urb_for_dma+0x71/0x188 [<ffffffff8137b166>] unmap_urb_for_dma+0x20/0x22 [<ffffffff8137b1c5>] usb_hcd_giveback_urb+0x5d/0xc0 [<ffffffffa0000d02>] ehci_urb_done+0xf7/0x10c [ehci_hcd] [<ffffffffa0001140>] qh_completions+0x429/0x4bd [ehci_hcd] [<ffffffffa000340a>] ehci_work+0x95/0x9c0 [ehci_hcd] ... ---[ end trace f29ac88a5a48c580 ]--- Mapped at: [<ffffffff811faac4>] debug_dma_map_sg+0x45/0x139 [<ffffffff8137bc0b>] usb_hcd_map_urb_for_dma+0x22e/0x478 [<ffffffff8137c494>] usb_hcd_submit_urb+0x63f/0x6fa [<ffffffff8137d01c>] usb_submit_urb+0x2c7/0x2de [<ffffffff8137dcd4>] usb_sg_wait+0x55/0x161 Signed-off-by: Clemens Ladisch <clemens@ladisch.de> Cc: stable <stable@vger.kernel.org> Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de>
-rw-r--r--drivers/usb/core/hcd.c5
-rw-r--r--drivers/usb/host/ehci-q.c2
-rw-r--r--drivers/usb/host/uhci-q.c2
-rw-r--r--drivers/usb/host/whci/qset.c4
-rw-r--r--drivers/usb/host/xhci-ring.c4
-rw-r--r--include/linux/usb.h1
6 files changed, 9 insertions, 9 deletions
diff --git a/drivers/usb/core/hcd.c b/drivers/usb/core/hcd.c
index 43a89e4ba92..2cec49d1773 100644
--- a/drivers/usb/core/hcd.c
+++ b/drivers/usb/core/hcd.c
@@ -1398,11 +1398,10 @@ int usb_hcd_map_urb_for_dma(struct usb_hcd *hcd, struct urb *urb,
1398 ret = -EAGAIN; 1398 ret = -EAGAIN;
1399 else 1399 else
1400 urb->transfer_flags |= URB_DMA_MAP_SG; 1400 urb->transfer_flags |= URB_DMA_MAP_SG;
1401 if (n != urb->num_sgs) { 1401 urb->num_mapped_sgs = n;
1402 urb->num_sgs = n; 1402 if (n != urb->num_sgs)
1403 urb->transfer_flags |= 1403 urb->transfer_flags |=
1404 URB_DMA_SG_COMBINED; 1404 URB_DMA_SG_COMBINED;
1405 }
1406 } else if (urb->sg) { 1405 } else if (urb->sg) {
1407 struct scatterlist *sg = urb->sg; 1406 struct scatterlist *sg = urb->sg;
1408 urb->transfer_dma = dma_map_page( 1407 urb->transfer_dma = dma_map_page(
diff --git a/drivers/usb/host/ehci-q.c b/drivers/usb/host/ehci-q.c
index f136f7f1c4f..36ca5077cdf 100644
--- a/drivers/usb/host/ehci-q.c
+++ b/drivers/usb/host/ehci-q.c
@@ -658,7 +658,7 @@ qh_urb_transaction (
658 /* 658 /*
659 * data transfer stage: buffer setup 659 * data transfer stage: buffer setup
660 */ 660 */
661 i = urb->num_sgs; 661 i = urb->num_mapped_sgs;
662 if (len > 0 && i > 0) { 662 if (len > 0 && i > 0) {
663 sg = urb->sg; 663 sg = urb->sg;
664 buf = sg_dma_address(sg); 664 buf = sg_dma_address(sg);
diff --git a/drivers/usb/host/uhci-q.c b/drivers/usb/host/uhci-q.c
index f6ca80ee4ce..d2c6f5ac462 100644
--- a/drivers/usb/host/uhci-q.c
+++ b/drivers/usb/host/uhci-q.c
@@ -943,7 +943,7 @@ static int uhci_submit_common(struct uhci_hcd *uhci, struct urb *urb,
943 if (usb_pipein(urb->pipe)) 943 if (usb_pipein(urb->pipe))
944 status |= TD_CTRL_SPD; 944 status |= TD_CTRL_SPD;
945 945
946 i = urb->num_sgs; 946 i = urb->num_mapped_sgs;
947 if (len > 0 && i > 0) { 947 if (len > 0 && i > 0) {
948 sg = urb->sg; 948 sg = urb->sg;
949 data = sg_dma_address(sg); 949 data = sg_dma_address(sg);
diff --git a/drivers/usb/host/whci/qset.c b/drivers/usb/host/whci/qset.c
index d6e17542861..a91712c8bff 100644
--- a/drivers/usb/host/whci/qset.c
+++ b/drivers/usb/host/whci/qset.c
@@ -443,7 +443,7 @@ static int qset_add_urb_sg(struct whc *whc, struct whc_qset *qset, struct urb *u
443 443
444 remaining = urb->transfer_buffer_length; 444 remaining = urb->transfer_buffer_length;
445 445
446 for_each_sg(urb->sg, sg, urb->num_sgs, i) { 446 for_each_sg(urb->sg, sg, urb->num_mapped_sgs, i) {
447 dma_addr_t dma_addr; 447 dma_addr_t dma_addr;
448 size_t dma_remaining; 448 size_t dma_remaining;
449 dma_addr_t sp, ep; 449 dma_addr_t sp, ep;
@@ -561,7 +561,7 @@ static int qset_add_urb_sg_linearize(struct whc *whc, struct whc_qset *qset,
561 561
562 remaining = urb->transfer_buffer_length; 562 remaining = urb->transfer_buffer_length;
563 563
564 for_each_sg(urb->sg, sg, urb->num_sgs, i) { 564 for_each_sg(urb->sg, sg, urb->num_mapped_sgs, i) {
565 size_t len; 565 size_t len;
566 size_t sg_remaining; 566 size_t sg_remaining;
567 void *orig; 567 void *orig;
diff --git a/drivers/usb/host/xhci-ring.c b/drivers/usb/host/xhci-ring.c
index 133ce302c86..d030f0b2bfa 100644
--- a/drivers/usb/host/xhci-ring.c
+++ b/drivers/usb/host/xhci-ring.c
@@ -2551,7 +2551,7 @@ static unsigned int count_sg_trbs_needed(struct xhci_hcd *xhci, struct urb *urb)
2551 struct scatterlist *sg; 2551 struct scatterlist *sg;
2552 2552
2553 sg = NULL; 2553 sg = NULL;
2554 num_sgs = urb->num_sgs; 2554 num_sgs = urb->num_mapped_sgs;
2555 temp = urb->transfer_buffer_length; 2555 temp = urb->transfer_buffer_length;
2556 2556
2557 xhci_dbg(xhci, "count sg list trbs: \n"); 2557 xhci_dbg(xhci, "count sg list trbs: \n");
@@ -2735,7 +2735,7 @@ static int queue_bulk_sg_tx(struct xhci_hcd *xhci, gfp_t mem_flags,
2735 return -EINVAL; 2735 return -EINVAL;
2736 2736
2737 num_trbs = count_sg_trbs_needed(xhci, urb); 2737 num_trbs = count_sg_trbs_needed(xhci, urb);
2738 num_sgs = urb->num_sgs; 2738 num_sgs = urb->num_mapped_sgs;
2739 total_packet_count = roundup(urb->transfer_buffer_length, 2739 total_packet_count = roundup(urb->transfer_buffer_length,
2740 usb_endpoint_maxp(&urb->ep->desc)); 2740 usb_endpoint_maxp(&urb->ep->desc));
2741 2741
diff --git a/include/linux/usb.h b/include/linux/usb.h
index 2f05a7fa1ec..4269c3f8814 100644
--- a/include/linux/usb.h
+++ b/include/linux/usb.h
@@ -1221,6 +1221,7 @@ struct urb {
1221 void *transfer_buffer; /* (in) associated data buffer */ 1221 void *transfer_buffer; /* (in) associated data buffer */
1222 dma_addr_t transfer_dma; /* (in) dma addr for transfer_buffer */ 1222 dma_addr_t transfer_dma; /* (in) dma addr for transfer_buffer */
1223 struct scatterlist *sg; /* (in) scatter gather buffer list */ 1223 struct scatterlist *sg; /* (in) scatter gather buffer list */
1224 int num_mapped_sgs; /* (internal) mapped sg entries */
1224 int num_sgs; /* (in) number of entries in the sg list */ 1225 int num_sgs; /* (in) number of entries in the sg list */
1225 u32 transfer_buffer_length; /* (in) data buffer length */ 1226 u32 transfer_buffer_length; /* (in) data buffer length */
1226 u32 actual_length; /* (return) actual transfer length */ 1227 u32 actual_length; /* (return) actual transfer length */