summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorMathias Nyman <mathias.nyman@linux.intel.com>2019-05-22 07:34:00 -0400
committerGreg Kroah-Hartman <gregkh@linuxfoundation.org>2019-05-22 08:25:37 -0400
commit13b82b746310b51b064bc855993a1c84bf862726 (patch)
tree34996b462140753e4899d6b8b1c85ff489943673
parent7aa1bb2ffd84d6b9b5f546b079bb15cd0ab6e76e (diff)
xhci: Fix immediate data transfer if buffer is already DMA mapped
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: 33e39350ebd2 ("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>
-rw-r--r--drivers/usb/host/xhci-ring.c9
-rw-r--r--drivers/usb/host/xhci.h3
2 files changed, 8 insertions, 4 deletions
diff --git a/drivers/usb/host/xhci-ring.c b/drivers/usb/host/xhci-ring.c
index ef7c8698772e..88392aa65722 100644
--- a/drivers/usb/host/xhci-ring.c
+++ b/drivers/usb/host/xhci-ring.c
@@ -3432,11 +3432,14 @@ int xhci_queue_ctrl_tx(struct xhci_hcd *xhci, gfp_t mem_flags,
3432 3432
3433 if (urb->transfer_buffer_length > 0) { 3433 if (urb->transfer_buffer_length > 0) {
3434 u32 length_field, remainder; 3434 u32 length_field, remainder;
3435 u64 addr;
3435 3436
3436 if (xhci_urb_suitable_for_idt(urb)) { 3437 if (xhci_urb_suitable_for_idt(urb)) {
3437 memcpy(&urb->transfer_dma, urb->transfer_buffer, 3438 memcpy(&addr, urb->transfer_buffer,
3438 urb->transfer_buffer_length); 3439 urb->transfer_buffer_length);
3439 field |= TRB_IDT; 3440 field |= TRB_IDT;
3441 } else {
3442 addr = (u64) urb->transfer_dma;
3440 } 3443 }
3441 3444
3442 remainder = xhci_td_remainder(xhci, 0, 3445 remainder = xhci_td_remainder(xhci, 0,
@@ -3449,8 +3452,8 @@ int xhci_queue_ctrl_tx(struct xhci_hcd *xhci, gfp_t mem_flags,
3449 if (setup->bRequestType & USB_DIR_IN) 3452 if (setup->bRequestType & USB_DIR_IN)
3450 field |= TRB_DIR_IN; 3453 field |= TRB_DIR_IN;
3451 queue_trb(xhci, ep_ring, true, 3454 queue_trb(xhci, ep_ring, true,
3452 lower_32_bits(urb->transfer_dma), 3455 lower_32_bits(addr),
3453 upper_32_bits(urb->transfer_dma), 3456 upper_32_bits(addr),
3454 length_field, 3457 length_field,
3455 field | ep_ring->cycle_state); 3458 field | ep_ring->cycle_state);
3456 } 3459 }
diff --git a/drivers/usb/host/xhci.h b/drivers/usb/host/xhci.h
index a450a99e90eb..7f8b950d1a73 100644
--- a/drivers/usb/host/xhci.h
+++ b/drivers/usb/host/xhci.h
@@ -2160,7 +2160,8 @@ static inline bool xhci_urb_suitable_for_idt(struct urb *urb)
2160{ 2160{
2161 if (!usb_endpoint_xfer_isoc(&urb->ep->desc) && usb_urb_dir_out(urb) && 2161 if (!usb_endpoint_xfer_isoc(&urb->ep->desc) && usb_urb_dir_out(urb) &&
2162 usb_endpoint_maxp(&urb->ep->desc) >= TRB_IDT_MAX_SIZE && 2162 usb_endpoint_maxp(&urb->ep->desc) >= TRB_IDT_MAX_SIZE &&
2163 urb->transfer_buffer_length <= TRB_IDT_MAX_SIZE) 2163 urb->transfer_buffer_length <= TRB_IDT_MAX_SIZE &&
2164 !(urb->transfer_flags & URB_NO_TRANSFER_DMA_MAP))
2164 return true; 2165 return true;
2165 2166
2166 return false; 2167 return false;