lkml.org 
[lkml]   [2012]   [Jan]   [10]   [last100]   RSS Feed
Views: [wrap][no wrap]   [headers]  [forward] 
 
Messages in this thread
    Patch in this message
    /
    Date
    From
    Subject[42/49] usb: fix number of mapped SG DMA entries
    3.2-stable review patch.  If anyone has any objections, please let me know.

    ------------------

    From: Clemens Ladisch <clemens@ladisch.de>

    commit bc677d5b64644c399cd3db6a905453e611f402ab upstream.

    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>
    Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de>

    ---
    drivers/usb/core/hcd.c | 5 ++---
    drivers/usb/host/ehci-q.c | 2 +-
    drivers/usb/host/uhci-q.c | 2 +-
    drivers/usb/host/whci/qset.c | 4 ++--
    drivers/usb/host/xhci-ring.c | 4 ++--
    include/linux/usb.h | 1 +
    6 files changed, 9 insertions(+), 9 deletions(-)

    --- a/drivers/usb/core/hcd.c
    +++ b/drivers/usb/core/hcd.c
    @@ -1412,11 +1412,10 @@ int usb_hcd_map_urb_for_dma(struct usb_h
    ret = -EAGAIN;
    else
    urb->transfer_flags |= URB_DMA_MAP_SG;
    - if (n != urb->num_sgs) {
    - urb->num_sgs = n;
    + urb->num_mapped_sgs = n;
    + if (n != urb->num_sgs)
    urb->transfer_flags |=
    URB_DMA_SG_COMBINED;
    - }
    } else if (urb->sg) {
    struct scatterlist *sg = urb->sg;
    urb->transfer_dma = dma_map_page(
    --- a/drivers/usb/host/ehci-q.c
    +++ b/drivers/usb/host/ehci-q.c
    @@ -647,7 +647,7 @@ qh_urb_transaction (
    /*
    * data transfer stage: buffer setup
    */
    - i = urb->num_sgs;
    + i = urb->num_mapped_sgs;
    if (len > 0 && i > 0) {
    sg = urb->sg;
    buf = sg_dma_address(sg);
    --- a/drivers/usb/host/uhci-q.c
    +++ b/drivers/usb/host/uhci-q.c
    @@ -943,7 +943,7 @@ static int uhci_submit_common(struct uhc
    if (usb_pipein(urb->pipe))
    status |= TD_CTRL_SPD;

    - i = urb->num_sgs;
    + i = urb->num_mapped_sgs;
    if (len > 0 && i > 0) {
    sg = urb->sg;
    data = sg_dma_address(sg);
    --- 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 *w

    remaining = urb->transfer_buffer_length;

    - for_each_sg(urb->sg, sg, urb->num_sgs, i) {
    + for_each_sg(urb->sg, sg, urb->num_mapped_sgs, i) {
    dma_addr_t dma_addr;
    size_t dma_remaining;
    dma_addr_t sp, ep;
    @@ -561,7 +561,7 @@ static int qset_add_urb_sg_linearize(str

    remaining = urb->transfer_buffer_length;

    - for_each_sg(urb->sg, sg, urb->num_sgs, i) {
    + for_each_sg(urb->sg, sg, urb->num_mapped_sgs, i) {
    size_t len;
    size_t sg_remaining;
    void *orig;
    --- a/drivers/usb/host/xhci-ring.c
    +++ b/drivers/usb/host/xhci-ring.c
    @@ -2561,7 +2561,7 @@ static unsigned int count_sg_trbs_needed
    struct scatterlist *sg;

    sg = NULL;
    - num_sgs = urb->num_sgs;
    + num_sgs = urb->num_mapped_sgs;
    temp = urb->transfer_buffer_length;

    xhci_dbg(xhci, "count sg list trbs: \n");
    @@ -2745,7 +2745,7 @@ static int queue_bulk_sg_tx(struct xhci_
    return -EINVAL;

    num_trbs = count_sg_trbs_needed(xhci, urb);
    - num_sgs = urb->num_sgs;
    + num_sgs = urb->num_mapped_sgs;
    total_packet_count = roundup(urb->transfer_buffer_length,
    usb_endpoint_maxp(&urb->ep->desc));

    --- a/include/linux/usb.h
    +++ b/include/linux/usb.h
    @@ -1221,6 +1221,7 @@ struct urb {
    void *transfer_buffer; /* (in) associated data buffer */
    dma_addr_t transfer_dma; /* (in) dma addr for transfer_buffer */
    struct scatterlist *sg; /* (in) scatter gather buffer list */
    + int num_mapped_sgs; /* (internal) mapped sg entries */
    int num_sgs; /* (in) number of entries in the sg list */
    u32 transfer_buffer_length; /* (in) data buffer length */
    u32 actual_length; /* (return) actual transfer length */



    \
     
     \ /
      Last update: 2012-01-11 00:09    [W:0.026 / U:59.076 seconds]
    ©2003-2016 Jasper Spaans. hosted at Digital OceanAdvertise on this site