lkml.org 
[lkml]   [2021]   [Feb]   [8]   [last100]   RSS Feed
Views: [wrap][no wrap]   [headers]  [forward] 
 
Messages in this thread
    Patch in this message
    /
    From
    Subject[PATCH 5.10 069/120] xhci: fix bounce buffer usage for non-sg list case
    Date
    From: Mathias Nyman <mathias.nyman@linux.intel.com>

    commit d4a610635400ccc382792f6be69427078541c678 upstream.

    xhci driver may in some special cases need to copy small amounts
    of payload data to a bounce buffer in order to meet the boundary
    and alignment restrictions set by the xHCI specification.

    In the majority of these cases the data is in a sg list, and
    driver incorrectly assumed data is always in urb->sg when using
    the bounce buffer.

    If data instead is contiguous, and in urb->transfer_buffer, we may still
    need to bounce buffer a small part if data starts very close (less than
    packet size) to a 64k boundary.

    Check if sg list is used before copying data to/from it.

    Fixes: f9c589e142d0 ("xhci: TD-fragment, align the unsplittable case with a bounce buffer")
    Cc: stable@vger.kernel.org
    Reported-by: Andreas Hartmann <andihartmann@01019freenet.de>
    Tested-by: Andreas Hartmann <andihartmann@01019freenet.de>
    Signed-off-by: Mathias Nyman <mathias.nyman@linux.intel.com>
    Link: https://lore.kernel.org/r/20210203113702.436762-2-mathias.nyman@linux.intel.com
    Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
    Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
    ---
    drivers/usb/host/xhci-ring.c | 31 ++++++++++++++++++++-----------
    1 file changed, 20 insertions(+), 11 deletions(-)

    --- a/drivers/usb/host/xhci-ring.c
    +++ b/drivers/usb/host/xhci-ring.c
    @@ -699,11 +699,16 @@ static void xhci_unmap_td_bounce_buffer(
    dma_unmap_single(dev, seg->bounce_dma, ring->bounce_buf_len,
    DMA_FROM_DEVICE);
    /* for in tranfers we need to copy the data from bounce to sg */
    - len = sg_pcopy_from_buffer(urb->sg, urb->num_sgs, seg->bounce_buf,
    - seg->bounce_len, seg->bounce_offs);
    - if (len != seg->bounce_len)
    - xhci_warn(xhci, "WARN Wrong bounce buffer read length: %zu != %d\n",
    - len, seg->bounce_len);
    + if (urb->num_sgs) {
    + len = sg_pcopy_from_buffer(urb->sg, urb->num_sgs, seg->bounce_buf,
    + seg->bounce_len, seg->bounce_offs);
    + if (len != seg->bounce_len)
    + xhci_warn(xhci, "WARN Wrong bounce buffer read length: %zu != %d\n",
    + len, seg->bounce_len);
    + } else {
    + memcpy(urb->transfer_buffer + seg->bounce_offs, seg->bounce_buf,
    + seg->bounce_len);
    + }
    seg->bounce_len = 0;
    seg->bounce_offs = 0;
    }
    @@ -3275,12 +3280,16 @@ static int xhci_align_td(struct xhci_hcd

    /* create a max max_pkt sized bounce buffer pointed to by last trb */
    if (usb_urb_dir_out(urb)) {
    - len = sg_pcopy_to_buffer(urb->sg, urb->num_sgs,
    - seg->bounce_buf, new_buff_len, enqd_len);
    - if (len != new_buff_len)
    - xhci_warn(xhci,
    - "WARN Wrong bounce buffer write length: %zu != %d\n",
    - len, new_buff_len);
    + if (urb->num_sgs) {
    + len = sg_pcopy_to_buffer(urb->sg, urb->num_sgs,
    + seg->bounce_buf, new_buff_len, enqd_len);
    + if (len != new_buff_len)
    + xhci_warn(xhci, "WARN Wrong bounce buffer write length: %zu != %d\n",
    + len, new_buff_len);
    + } else {
    + memcpy(seg->bounce_buf, urb->transfer_buffer + enqd_len, new_buff_len);
    + }
    +
    seg->bounce_dma = dma_map_single(dev, seg->bounce_buf,
    max_pkt, DMA_TO_DEVICE);
    } else {

    \
     
     \ /
      Last update: 2021-02-08 18:34    [W:5.026 / U:0.016 seconds]
    ©2003-2020 Jasper Spaans|hosted at Digital Ocean and TransIP|Read the blog|Advertise on this site