Skip to content

Commit

Permalink
xhci: Fix immediate data transfer if buffer is already DMA mapped
Browse files Browse the repository at this point in the history
xhci immediate data transfer (IDT) support in 5.2-rc1 caused regression
on various Samsung Exynos boards with ASIX USB 2.0 ethernet dongle.

If the transfer buffer in the URB is already DMA mapped then IDT should
not be used. urb->transfer_dma will already contain a valid dma address,
and there is no guarantee the data in urb->transfer_buffer is valid.

The IDT support patch used urb->transfer_dma as a temporary storage,
copying data from urb->transfer_buffer into it.

Issue was solved by preventing IDT if transfer buffer is already dma
mapped, and by not using urb->transfer_dma as temporary storage.

Fixes: 33e3935 ("usb: xhci: add Immediate Data Transfer support")
Reported-by: Marek Szyprowski <m.szyprowski@samsung.com>
Tested-by: Marek Szyprowski <m.szyprowski@samsung.com>
CC: Nicolas Saenz Julienne <nsaenzjulienne@suse.de>
Signed-off-by: Mathias Nyman <mathias.nyman@linux.intel.com>
Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
  • Loading branch information
Mathias Nyman authored and Greg Kroah-Hartman committed May 22, 2019
1 parent 7aa1bb2 commit 13b82b7
Show file tree
Hide file tree
Showing 2 changed files with 8 additions and 4 deletions.
9 changes: 6 additions & 3 deletions drivers/usb/host/xhci-ring.c
Original file line number Diff line number Diff line change
Expand Up @@ -3432,11 +3432,14 @@ int xhci_queue_ctrl_tx(struct xhci_hcd *xhci, gfp_t mem_flags,

if (urb->transfer_buffer_length > 0) {
u32 length_field, remainder;
u64 addr;

if (xhci_urb_suitable_for_idt(urb)) {
memcpy(&urb->transfer_dma, urb->transfer_buffer,
memcpy(&addr, urb->transfer_buffer,
urb->transfer_buffer_length);
field |= TRB_IDT;
} else {
addr = (u64) urb->transfer_dma;
}

remainder = xhci_td_remainder(xhci, 0,
Expand All @@ -3449,8 +3452,8 @@ int xhci_queue_ctrl_tx(struct xhci_hcd *xhci, gfp_t mem_flags,
if (setup->bRequestType & USB_DIR_IN)
field |= TRB_DIR_IN;
queue_trb(xhci, ep_ring, true,
lower_32_bits(urb->transfer_dma),
upper_32_bits(urb->transfer_dma),
lower_32_bits(addr),
upper_32_bits(addr),
length_field,
field | ep_ring->cycle_state);
}
Expand Down
3 changes: 2 additions & 1 deletion drivers/usb/host/xhci.h
Original file line number Diff line number Diff line change
Expand Up @@ -2160,7 +2160,8 @@ static inline bool xhci_urb_suitable_for_idt(struct urb *urb)
{
if (!usb_endpoint_xfer_isoc(&urb->ep->desc) && usb_urb_dir_out(urb) &&
usb_endpoint_maxp(&urb->ep->desc) >= TRB_IDT_MAX_SIZE &&
urb->transfer_buffer_length <= TRB_IDT_MAX_SIZE)
urb->transfer_buffer_length <= TRB_IDT_MAX_SIZE &&
!(urb->transfer_flags & URB_NO_TRANSFER_DMA_MAP))
return true;

return false;
Expand Down

0 comments on commit 13b82b7

Please sign in to comment.