Hi Matthias, thanks for spending the time debugging this :)
On Thu, 2019-05-09 at 18:10 +0300, Mathias Nyman wrote:
> Got the logs off list, thanks
>
> The "Buffer" data in Control transfer Data stage look suspicious.
>
> grep "flags I:" trace_fail | grep Data
> kworker/0:2-124 [000] d..1 63.092399: xhci_queue_trb: CTRL: Buffer
> 0000000018b65000 length 6 TD size 0 intr 0 type 'Data Stage' flags
> I:i:c:s:i:e:C
> ifconfig-1429 [005] d..1 93.181231: xhci_queue_trb: CTRL: Buffer
> 0000000018b65000 length 6 TD size 0 intr 0 type 'Data Stage' flags
> I:i:c:s:i:e:C
> ifconfig-1429 [007] dn.2 93.182050: xhci_queue_trb: CTRL: Buffer
> 0000000000000000 length 8 TD size 0 intr 0 type 'Data Stage' flags
> I:i:c:s:i:e:C
> ifconfig-1429 [007] d..2 93.182499: xhci_queue_trb: CTRL: Buffer
> 0000000080000000 length 8 TD size 0 intr 0 type 'Data Stage' flags
> I:i:c:s:i:e:C
> ifconfig-1429 [007] d..2 93.182736: xhci_queue_trb: CTRL: Buffer
> 0000000080000000 length 8 TD size 0 intr 0 type 'Data Stage' flags
> I:i:c:s:i:e:C
> kworker/0:3-1409 [000] d..3 93.382630: xhci_queue_trb: CTRL: Buffer
> 0000000080000000 length 8 TD size 0 intr 0 type 'Data Stage' flags
> I:i:c:s:i:e:C
>
> First guess would be that in case URB has URB_NO_TRANSFER_DMA_MAP set then
> data
> will be mapped and urb->transfer_dma is already set.
> The IDT patch uses urb->trabfer_dma as a temporary buffer, and copies the
> urb->transfer_buffer there.
> if transfer buffer is already dma mapped the urb->transfer_buffer can be
> garbage,
> (shouldn't, but it can be)
>
> Below code avoids IDT if URB_NO_TRANSFER_DMA_MAP is set, and doesn't touch
> urb->transfer_dma (patch attached)
>
> diff --git a/drivers/usb/host/xhci-ring.c b/drivers/usb/host/xhci-ring.c
> index fed3385..f080054 100644
> --- a/drivers/usb/host/xhci-ring.c
> +++ b/drivers/usb/host/xhci-ring.c
> @@ -3423,11 +3423,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,
> @@ -3440,8 +3443,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);
> }
> diff --git a/drivers/usb/host/xhci.h b/drivers/usb/host/xhci.h
> index a450a99..7f8b950 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)
> {
> 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;
> This could be it, I broadly checked and assumed everyone was playing nice with the transfer_dma pointer, but I guess I might have missed something. > If that doesn't help, then it's possible DATA trbs in control transfer can't > use IDT at all. IDT is supported for Normal TRBs, which have a different trb > type than DATA trbs in control transfers. > > Also xhci specs 4.11.7 limit IDT usage: > > "If the IDT flag is set in one TRB of a TD, then it shall be the only Transfer > TRB of the TD" > > A whole control transfer is one TD, and it already contains a SETUP transfer > TRB > which is using the IDT flag. > > Following disables IDT for control transfers (testpatch attached as well) This one I'm not so sure as the standard defines a control transfer as a 2 or 3 TD operation (see 4.11.2.2): "The Control Transfer Ring may contain Setup Stage and Status Stage TDs, and optionally Data Stage TDs." Also, for what is worth, I spent some time testing that specific case on my intel laptop while preparing the patch. Regards, Nicolas
signature.asc
Description: This is a digitally signed message part
