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 <hdego...@redhat.com>
Signed-off-by: Sarah Sharp <sarah.a.sh...@linux.intel.com>
---
 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 4908c79..38f64d2 100644
--- a/drivers/usb/host/xhci-ring.c
+++ b/drivers/usb/host/xhci-ring.c
@@ -1087,12 +1087,14 @@ static void xhci_handle_cmd_set_deq(struct xhci_hcd 
*xhci, int slot_id,
        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;
 
        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) {
@@ -1144,12 +1146,19 @@ static void xhci_handle_cmd_set_deq(struct xhci_hcd 
*xhci, int slot_id,
                 * cancelling URBs, which might not be an error...
                 */
        } else {
+               u64 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.
                         */
@@ -1159,8 +1168,7 @@ static void xhci_handle_cmd_set_deq(struct xhci_hcd 
*xhci, int slot_id,
                        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 81bafb9..d411c88 100644
--- a/drivers/usb/host/xhci.h
+++ b/drivers/usb/host/xhci.h
@@ -703,6 +703,7 @@ struct xhci_ep_ctx {
 
 /* deq bitmasks */
 #define EP_CTX_CYCLE_MASK              (1 << 0)
+#define SCTX_DEQ_MASK                  (~0xfL)
 
 
 /**
-- 
1.8.4.2

--
To unsubscribe from this list: send the line "unsubscribe linux-usb" in
the body of a message to majord...@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html

Reply via email to