]> git.ipfire.org Git - people/arne_f/kernel.git/commitdiff
xhci: add quirk for host controllers that don't update endpoint DCS
authorJonathan Bell <jonathan@raspberrypi.org>
Fri, 8 Oct 2021 09:25:44 +0000 (12:25 +0300)
committerGreg Kroah-Hartman <gregkh@linuxfoundation.org>
Wed, 27 Oct 2021 07:56:46 +0000 (09:56 +0200)
commit 5255660b208aebfdb71d574f3952cf48392f4306 upstream.

Seen on a VLI VL805 PCIe to USB controller. For non-stream endpoints
at least, if the xHC halts on a particular TRB due to an error then
the DCS field in the Out Endpoint Context maintained by the hardware
is not updated with the current cycle state.

Using the quirk XHCI_EP_CTX_BROKEN_DCS and instead fetch the DCS bit
from the TRB that the xHC stopped on.

[ bjorn: rebased to v5.14-rc2 ]

Link: https://github.com/raspberrypi/linux/issues/3060
Cc: stable@vger.kernel.org
Signed-off-by: Jonathan Bell <jonathan@raspberrypi.org>
Signed-off-by: Bjørn Mork <bjorn@mork.no>
Signed-off-by: Mathias Nyman <mathias.nyman@linux.intel.com>
Link: https://lore.kernel.org/r/20211008092547.3996295-3-mathias.nyman@linux.intel.com
Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
drivers/usb/host/xhci-pci.c
drivers/usb/host/xhci-ring.c
drivers/usb/host/xhci.h

index 2299866dc82ff5e5beb8268b86d470cd40d93ed6..8c65e9476b41fb83bbdf9f4020d823384a92f021 100644 (file)
@@ -276,8 +276,10 @@ static void xhci_pci_quirks(struct device *dev, struct xhci_hcd *xhci)
                        pdev->device == 0x3432)
                xhci->quirks |= XHCI_BROKEN_STREAMS;
 
-       if (pdev->vendor == PCI_VENDOR_ID_VIA && pdev->device == 0x3483)
+       if (pdev->vendor == PCI_VENDOR_ID_VIA && pdev->device == 0x3483) {
                xhci->quirks |= XHCI_LPM_SUPPORT;
+               xhci->quirks |= XHCI_EP_CTX_BROKEN_DCS;
+       }
 
        if (pdev->vendor == PCI_VENDOR_ID_ASMEDIA &&
                pdev->device == PCI_DEVICE_ID_ASMEDIA_1042_XHCI)
index ec8f2910faf97c2d414ea33012c6141738d7609f..4512c4223392a7ce2d552da1fcfcb874aed85bda 100644 (file)
@@ -562,7 +562,10 @@ void xhci_find_new_dequeue_state(struct xhci_hcd *xhci,
        struct xhci_virt_ep *ep = &dev->eps[ep_index];
        struct xhci_ring *ep_ring;
        struct xhci_segment *new_seg;
+       struct xhci_segment *halted_seg = NULL;
        union xhci_trb *new_deq;
+       union xhci_trb *halted_trb;
+       int index = 0;
        dma_addr_t addr;
        u64 hw_dequeue;
        bool cycle_found = false;
@@ -600,7 +603,28 @@ void xhci_find_new_dequeue_state(struct xhci_hcd *xhci,
        hw_dequeue = xhci_get_hw_deq(xhci, dev, ep_index, stream_id);
        new_seg = ep_ring->deq_seg;
        new_deq = ep_ring->dequeue;
-       state->new_cycle_state = hw_dequeue & 0x1;
+
+       /*
+        * Quirk: xHC write-back of the DCS field in the hardware dequeue
+        * pointer is wrong - use the cycle state of the TRB pointed to by
+        * the dequeue pointer.
+        */
+       if (xhci->quirks & XHCI_EP_CTX_BROKEN_DCS &&
+           !(ep->ep_state & EP_HAS_STREAMS))
+               halted_seg = trb_in_td(xhci, cur_td->start_seg,
+                                      cur_td->first_trb, cur_td->last_trb,
+                                      hw_dequeue & ~0xf, false);
+       if (halted_seg) {
+               index = ((dma_addr_t)(hw_dequeue & ~0xf) - halted_seg->dma) /
+                        sizeof(*halted_trb);
+               halted_trb = &halted_seg->trbs[index];
+               state->new_cycle_state = halted_trb->generic.field[3] & 0x1;
+               xhci_dbg(xhci, "Endpoint DCS = %d TRB index = %d cycle = %d\n",
+                        (u8)(hw_dequeue & 0x1), index,
+                        state->new_cycle_state);
+       } else {
+               state->new_cycle_state = hw_dequeue & 0x1;
+       }
        state->stream_id = stream_id;
 
        /*
index 1c97c8d81154d365ac58b942bcb0180b9dca8388..45584a278336645a201f6319e2bd5de5c0c6ce7d 100644 (file)
@@ -1884,6 +1884,7 @@ struct xhci_hcd {
 #define XHCI_DISABLE_SPARSE    BIT_ULL(38)
 #define XHCI_SG_TRB_CACHE_SIZE_QUIRK   BIT_ULL(39)
 #define XHCI_NO_SOFT_RETRY     BIT_ULL(40)
+#define XHCI_EP_CTX_BROKEN_DCS BIT_ULL(42)
 
        unsigned int            num_active_eps;
        unsigned int            limit_active_eps;