Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux

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>

authored by

Clemens Ladisch and committed by
Greg Kroah-Hartman
bc677d5b 8ad028bd

+9 -9
+2 -3
drivers/usb/core/hcd.c
··· 1398 1398 ret = -EAGAIN; 1399 1399 else 1400 1400 urb->transfer_flags |= URB_DMA_MAP_SG; 1401 - if (n != urb->num_sgs) { 1402 - urb->num_sgs = n; 1401 + urb->num_mapped_sgs = n; 1402 + if (n != urb->num_sgs) 1403 1403 urb->transfer_flags |= 1404 1404 URB_DMA_SG_COMBINED; 1405 - } 1406 1405 } else if (urb->sg) { 1407 1406 struct scatterlist *sg = urb->sg; 1408 1407 urb->transfer_dma = dma_map_page(
+1 -1
drivers/usb/host/ehci-q.c
··· 658 658 /* 659 659 * data transfer stage: buffer setup 660 660 */ 661 - i = urb->num_sgs; 661 + i = urb->num_mapped_sgs; 662 662 if (len > 0 && i > 0) { 663 663 sg = urb->sg; 664 664 buf = sg_dma_address(sg);
+1 -1
drivers/usb/host/uhci-q.c
··· 943 943 if (usb_pipein(urb->pipe)) 944 944 status |= TD_CTRL_SPD; 945 945 946 - i = urb->num_sgs; 946 + i = urb->num_mapped_sgs; 947 947 if (len > 0 && i > 0) { 948 948 sg = urb->sg; 949 949 data = sg_dma_address(sg);
+2 -2
drivers/usb/host/whci/qset.c
··· 443 443 444 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 447 dma_addr_t dma_addr; 448 448 size_t dma_remaining; 449 449 dma_addr_t sp, ep; ··· 561 561 562 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 565 size_t len; 566 566 size_t sg_remaining; 567 567 void *orig;
+2 -2
drivers/usb/host/xhci-ring.c
··· 2551 2551 struct scatterlist *sg; 2552 2552 2553 2553 sg = NULL; 2554 - num_sgs = urb->num_sgs; 2554 + num_sgs = urb->num_mapped_sgs; 2555 2555 temp = urb->transfer_buffer_length; 2556 2556 2557 2557 xhci_dbg(xhci, "count sg list trbs: \n"); ··· 2735 2735 return -EINVAL; 2736 2736 2737 2737 num_trbs = count_sg_trbs_needed(xhci, urb); 2738 - num_sgs = urb->num_sgs; 2738 + num_sgs = urb->num_mapped_sgs; 2739 2739 total_packet_count = roundup(urb->transfer_buffer_length, 2740 2740 usb_endpoint_maxp(&urb->ep->desc)); 2741 2741
+1
include/linux/usb.h
··· 1221 1221 void *transfer_buffer; /* (in) associated data buffer */ 1222 1222 dma_addr_t transfer_dma; /* (in) dma addr for transfer_buffer */ 1223 1223 struct scatterlist *sg; /* (in) scatter gather buffer list */ 1224 + int num_mapped_sgs; /* (internal) mapped sg entries */ 1224 1225 int num_sgs; /* (in) number of entries in the sg list */ 1225 1226 u32 transfer_buffer_length; /* (in) data buffer length */ 1226 1227 u32 actual_length; /* (return) actual transfer length */