Skip to content

Commit e5fa8db

Browse files
pawellcdnsgregkh
authored andcommitted
usb: xhci: fix loss of data on Cadence xHC
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: 3d82904 ("usb: cdnsp: cdns3 Add main part of Cadence USBSSP DRD Driver") cc: [email protected] Signed-off-by: Pawel Laszczak <[email protected]> Reviewed-by: Peter Chen <[email protected]> Link: https://lore.kernel.org/r/PH7PR07MB95386A40146E3EC64086F409DD9D2@PH7PR07MB9538.namprd07.prod.outlook.com Signed-off-by: Greg Kroah-Hartman <[email protected]>
1 parent 118ecef commit e5fa8db

File tree

4 files changed

+25
-1
lines changed

4 files changed

+25
-1
lines changed

drivers/usb/cdns3/host.c

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -62,7 +62,9 @@ static const struct xhci_plat_priv xhci_plat_cdns3_xhci = {
6262
.resume_quirk = xhci_cdns3_resume_quirk,
6363
};
6464

65-
static const struct xhci_plat_priv xhci_plat_cdnsp_xhci;
65+
static const struct xhci_plat_priv xhci_plat_cdnsp_xhci = {
66+
.quirks = XHCI_CDNS_SCTX_QUIRK,
67+
};
6668

6769
static int __cdns_host_init(struct cdns *cdns)
6870
{

drivers/usb/host/xhci-pci.c

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -81,6 +81,9 @@
8181
#define PCI_DEVICE_ID_ASMEDIA_2142_XHCI 0x2142
8282
#define PCI_DEVICE_ID_ASMEDIA_3242_XHCI 0x3242
8383

84+
#define PCI_DEVICE_ID_CADENCE 0x17CD
85+
#define PCI_DEVICE_ID_CADENCE_SSP 0x0200
86+
8487
static const char hcd_name[] = "xhci_hcd";
8588

8689
static struct hc_driver __read_mostly xhci_pci_hc_driver;
@@ -474,6 +477,10 @@ static void xhci_pci_quirks(struct device *dev, struct xhci_hcd *xhci)
474477
xhci->quirks |= XHCI_ZHAOXIN_TRB_FETCH;
475478
}
476479

480+
if (pdev->vendor == PCI_DEVICE_ID_CADENCE &&
481+
pdev->device == PCI_DEVICE_ID_CADENCE_SSP)
482+
xhci->quirks |= XHCI_CDNS_SCTX_QUIRK;
483+
477484
/* xHC spec requires PCI devices to support D3hot and D3cold */
478485
if (xhci->hci_version >= 0x120)
479486
xhci->quirks |= XHCI_DEFAULT_PM_RUNTIME_ALLOW;

drivers/usb/host/xhci-ring.c

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1399,6 +1399,20 @@ static void xhci_handle_cmd_set_deq(struct xhci_hcd *xhci, int slot_id,
13991399
struct xhci_stream_ctx *ctx =
14001400
&ep->stream_info->stream_ctx_array[stream_id];
14011401
deq = le64_to_cpu(ctx->stream_ring) & SCTX_DEQ_MASK;
1402+
1403+
/*
1404+
* Cadence xHCI controllers store some endpoint state
1405+
* information within Rsvd0 fields of Stream Endpoint
1406+
* context. This field is not cleared during Set TR
1407+
* Dequeue Pointer command which causes XDMA to skip
1408+
* over transfer ring and leads to data loss on stream
1409+
* pipe.
1410+
* To fix this issue driver must clear Rsvd0 field.
1411+
*/
1412+
if (xhci->quirks & XHCI_CDNS_SCTX_QUIRK) {
1413+
ctx->reserved[0] = 0;
1414+
ctx->reserved[1] = 0;
1415+
}
14021416
} else {
14031417
deq = le64_to_cpu(ep_ctx->deq) & ~EP_CTX_CYCLE_MASK;
14041418
}

drivers/usb/host/xhci.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1623,6 +1623,7 @@ struct xhci_hcd {
16231623
#define XHCI_ZHAOXIN_TRB_FETCH BIT_ULL(45)
16241624
#define XHCI_ZHAOXIN_HOST BIT_ULL(46)
16251625
#define XHCI_WRITE_64_HI_LO BIT_ULL(47)
1626+
#define XHCI_CDNS_SCTX_QUIRK BIT_ULL(48)
16261627

16271628
unsigned int num_active_eps;
16281629
unsigned int limit_active_eps;

0 commit comments

Comments
 (0)