This fixes TR dequeue validation failing on Intel XHCI controllers with the following warning: Mismatch between completed Set TR Deq Ptr command & xHCI internal state. Interestingly enough reading the deq ptr from the ep ctx after a TR Deq Ptr command does work on a Nec XHCI controller, it seems the Nec writes the ptr to both the ep and stream contexts when streams are used. Signed-off-by: Hans de Goede <hdegoede@xxxxxxxxxx> --- drivers/usb/host/xhci-ring.c | 22 +++++++++++++++------- drivers/usb/host/xhci.h | 1 + 2 files changed, 16 insertions(+), 7 deletions(-) diff --git a/drivers/usb/host/xhci-ring.c b/drivers/usb/host/xhci-ring.c index bed4cfa..1ca1732 100644 --- a/drivers/usb/host/xhci-ring.c +++ b/drivers/usb/host/xhci-ring.c @@ -1080,6 +1080,7 @@ static void handle_set_deq_completion(struct xhci_hcd *xhci, unsigned int stream_id; struct xhci_ring *ep_ring; struct xhci_virt_device *dev; + struct xhci_virt_ep *ep; struct xhci_ep_ctx *ep_ctx; struct xhci_slot_ctx *slot_ctx; @@ -1087,6 +1088,7 @@ static void handle_set_deq_completion(struct xhci_hcd *xhci, ep_index = TRB_TO_EP_INDEX(le32_to_cpu(trb->generic.field[3])); stream_id = TRB_TO_STREAM_ID(le32_to_cpu(trb->generic.field[2])); dev = xhci->devs[slot_id]; + ep = &dev->eps[ep_index]; ep_ring = xhci_stream_id_to_ring(dev, ep_index, stream_id); if (!ep_ring) { @@ -1138,12 +1140,19 @@ static void handle_set_deq_completion(struct xhci_hcd *xhci, * cancelling URBs, which might not be an error... */ } else { + __le64 deq; + /* 4.6.10 deq ptr is written to the stream ctx for streams */ + if (ep->ep_state & EP_HAS_STREAMS) { + struct xhci_stream_ctx *ctx = + &ep->stream_info->stream_ctx_array[stream_id]; + deq = le64_to_cpu(ctx->stream_ring) & SCTX_DEQ_MASK; + } else { + deq = le64_to_cpu(ep_ctx->deq) & ~EP_CTX_CYCLE_MASK; + } xhci_dbg_trace(xhci, trace_xhci_dbg_cancel_urb, - "Successful Set TR Deq Ptr cmd, deq = @%08llx", - le64_to_cpu(ep_ctx->deq)); - if (xhci_trb_virt_to_dma(dev->eps[ep_index].queued_deq_seg, - dev->eps[ep_index].queued_deq_ptr) == - (le64_to_cpu(ep_ctx->deq) & ~(EP_CTX_CYCLE_MASK))) { + "Successful Set TR Deq Ptr cmd, deq = @%08llx", deq); + if (xhci_trb_virt_to_dma(ep->queued_deq_seg, + ep->queued_deq_ptr) == deq) { /* Update the ring's dequeue segment and dequeue pointer * to reflect the new position. */ @@ -1153,8 +1162,7 @@ static void handle_set_deq_completion(struct xhci_hcd *xhci, xhci_warn(xhci, "Mismatch between completed Set TR Deq " "Ptr command & xHCI internal state.\n"); xhci_warn(xhci, "ep deq seg = %p, deq ptr = %p\n", - dev->eps[ep_index].queued_deq_seg, - dev->eps[ep_index].queued_deq_ptr); + ep->queued_deq_seg, ep->queued_deq_ptr); } } diff --git a/drivers/usb/host/xhci.h b/drivers/usb/host/xhci.h index a135f76..108e349 100644 --- a/drivers/usb/host/xhci.h +++ b/drivers/usb/host/xhci.h @@ -702,6 +702,7 @@ struct xhci_ep_ctx { /* deq bitmasks */ #define EP_CTX_CYCLE_MASK (1 << 0) +#define SCTX_DEQ_MASK (~0xfL) /** -- 1.8.3.1 -- To unsubscribe from this list: send the line "unsubscribe linux-usb" in the body of a message to majordomo@xxxxxxxxxxxxxxx More majordomo info at http://vger.kernel.org/majordomo-info.html