diff options
author | Clemens Ladisch <clemens@ladisch.de> | 2011-12-03 17:41:31 -0500 |
---|---|---|
committer | Greg Kroah-Hartman <gregkh@suse.de> | 2011-12-09 19:18:19 -0500 |
commit | bc677d5b64644c399cd3db6a905453e611f402ab (patch) | |
tree | d973a02c33f0e0d407e9ec7c6054220e15d5c72f | |
parent | 8ad028bd973ec1ead4982e21ab0400c956aff4b5 (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.c | 5 | ||||
-rw-r--r-- | drivers/usb/host/ehci-q.c | 2 | ||||
-rw-r--r-- | drivers/usb/host/uhci-q.c | 2 | ||||
-rw-r--r-- | drivers/usb/host/whci/qset.c | 4 | ||||
-rw-r--r-- | drivers/usb/host/xhci-ring.c | 4 | ||||
-rw-r--r-- | include/linux/usb.h | 1 |
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 */ |