]> git.ipfire.org Git - thirdparty/kernel/stable.git/commitdiff
usb: xhci: fix loss of data on Cadence xHC
authorPawel Laszczak <pawell@cadence.com>
Thu, 5 Sep 2024 07:03:28 +0000 (07:03 +0000)
committerGreg Kroah-Hartman <gregkh@linuxfoundation.org>
Fri, 4 Oct 2024 14:38:40 +0000 (16:38 +0200)
commit e5fa8db0be3e8757e8641600c518425a4589b85c upstream.

Streams should flush their TRB cache, re-read TRBs, and start executing
TRBs from the beginning of the new dequeue pointer after a 'Set TR Dequeue
Pointer' command.

Cadence controllers may fail to start from the beginning of the dequeue
TRB as it doesn't clear the Opaque 'RsvdO' field of the stream context
during 'Set TR Dequeue' command. This stream context area is where xHC
stores information about the last partially executed TD when a stream
is stopped. xHC uses this information to resume the transfer where it left
mid TD, when the stream is restarted.

Patch fixes this by clearing out all RsvdO fields before initializing new
Stream transfer using a 'Set TR Dequeue Pointer' command.

Fixes: 3d82904559f4 ("usb: cdnsp: cdns3 Add main part of Cadence USBSSP DRD Driver")
cc: stable@vger.kernel.org
Signed-off-by: Pawel Laszczak <pawell@cadence.com>
Reviewed-by: Peter Chen <peter.chen@kernel.org>
Link: https://lore.kernel.org/r/PH7PR07MB95386A40146E3EC64086F409DD9D2@PH7PR07MB9538.namprd07.prod.outlook.com
Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
drivers/usb/cdns3/host.c
drivers/usb/host/xhci-pci.c
drivers/usb/host/xhci-ring.c
drivers/usb/host/xhci.h

index ceca4d839dfd42b87167f4de3019ab63776fa6c2..7ba760ee62e3310e9c678d269d7675c9cb952ec6 100644 (file)
@@ -62,7 +62,9 @@ static const struct xhci_plat_priv xhci_plat_cdns3_xhci = {
        .resume_quirk = xhci_cdns3_resume_quirk,
 };
 
-static const struct xhci_plat_priv xhci_plat_cdnsp_xhci;
+static const struct xhci_plat_priv xhci_plat_cdnsp_xhci = {
+       .quirks = XHCI_CDNS_SCTX_QUIRK,
+};
 
 static int __cdns_host_init(struct cdns *cdns)
 {
index dc1e345ab67ea8d71725541be44683f1db349fcc..608ce926f71429d8d7e2b697aea555e9f7076abf 100644 (file)
@@ -78,6 +78,9 @@
 #define PCI_DEVICE_ID_ASMEDIA_2142_XHCI                        0x2142
 #define PCI_DEVICE_ID_ASMEDIA_3242_XHCI                        0x3242
 
+#define PCI_DEVICE_ID_CADENCE                          0x17CD
+#define PCI_DEVICE_ID_CADENCE_SSP                      0x0200
+
 static const char hcd_name[] = "xhci_hcd";
 
 static struct hc_driver __read_mostly xhci_pci_hc_driver;
@@ -473,6 +476,10 @@ static void xhci_pci_quirks(struct device *dev, struct xhci_hcd *xhci)
                        xhci->quirks |= XHCI_ZHAOXIN_TRB_FETCH;
        }
 
+       if (pdev->vendor == PCI_DEVICE_ID_CADENCE &&
+           pdev->device == PCI_DEVICE_ID_CADENCE_SSP)
+               xhci->quirks |= XHCI_CDNS_SCTX_QUIRK;
+
        /* xHC spec requires PCI devices to support D3hot and D3cold */
        if (xhci->hci_version >= 0x120)
                xhci->quirks |= XHCI_DEFAULT_PM_RUNTIME_ALLOW;
index 4ea2c3e072a9e3d6f77e48f6154c3a3f9bb9a848..90726899bc5bcc4b3d2e3759145c682ed2129223 100644 (file)
@@ -1399,6 +1399,20 @@ static void xhci_handle_cmd_set_deq(struct xhci_hcd *xhci, int slot_id,
                        struct xhci_stream_ctx *ctx =
                                &ep->stream_info->stream_ctx_array[stream_id];
                        deq = le64_to_cpu(ctx->stream_ring) & SCTX_DEQ_MASK;
+
+                       /*
+                        * Cadence xHCI controllers store some endpoint state
+                        * information within Rsvd0 fields of Stream Endpoint
+                        * context. This field is not cleared during Set TR
+                        * Dequeue Pointer command which causes XDMA to skip
+                        * over transfer ring and leads to data loss on stream
+                        * pipe.
+                        * To fix this issue driver must clear Rsvd0 field.
+                        */
+                       if (xhci->quirks & XHCI_CDNS_SCTX_QUIRK) {
+                               ctx->reserved[0] = 0;
+                               ctx->reserved[1] = 0;
+                       }
                } else {
                        deq = le64_to_cpu(ep_ctx->deq) & ~EP_CTX_CYCLE_MASK;
                }
index ebd0afd59a60be205f692de03029bcfe6969c86c..0ea95ad4cb90227fec74dfb3d639c7c1d9224042 100644 (file)
@@ -1628,6 +1628,7 @@ struct xhci_hcd {
 #define XHCI_ZHAOXIN_TRB_FETCH BIT_ULL(45)
 #define XHCI_ZHAOXIN_HOST      BIT_ULL(46)
 #define XHCI_WRITE_64_HI_LO    BIT_ULL(47)
+#define XHCI_CDNS_SCTX_QUIRK   BIT_ULL(48)
 
        unsigned int            num_active_eps;
        unsigned int            limit_active_eps;