Skip to content

Commit 286e6c6

Browse files
author
Jonathan Bell
committed
xhci: add quirk for host controllers that don't update endpoint DCS
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. See: #3060 Signed-off-by: Jonathan Bell <[email protected]>
1 parent 9bf5cd2 commit 286e6c6

File tree

3 files changed

+29
-2
lines changed

3 files changed

+29
-2
lines changed

drivers/usb/host/xhci-pci.c

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -223,8 +223,10 @@ static void xhci_pci_quirks(struct device *dev, struct xhci_hcd *xhci)
223223
xhci->quirks |= XHCI_BROKEN_STREAMS;
224224

225225
if (pdev->vendor == PCI_VENDOR_ID_VIA &&
226-
pdev->device == 0x3483)
226+
pdev->device == 0x3483) {
227227
xhci->quirks |= XHCI_LPM_SUPPORT;
228+
xhci->quirks |= XHCI_EP_CTX_BROKEN_DCS;
229+
}
228230

229231
if (pdev->vendor == PCI_VENDOR_ID_ASMEDIA &&
230232
pdev->device == 0x1042)

drivers/usb/host/xhci-ring.c

Lines changed: 25 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -520,7 +520,10 @@ void xhci_find_new_dequeue_state(struct xhci_hcd *xhci,
520520
struct xhci_virt_ep *ep = &dev->eps[ep_index];
521521
struct xhci_ring *ep_ring;
522522
struct xhci_segment *new_seg;
523+
struct xhci_segment *halted_seg = NULL;
523524
union xhci_trb *new_deq;
525+
union xhci_trb *halted_trb;
526+
int index = 0;
524527
dma_addr_t addr;
525528
u64 hw_dequeue;
526529
bool cycle_found = false;
@@ -541,7 +544,28 @@ void xhci_find_new_dequeue_state(struct xhci_hcd *xhci,
541544
hw_dequeue = xhci_get_hw_deq(xhci, dev, ep_index, stream_id);
542545
new_seg = ep_ring->deq_seg;
543546
new_deq = ep_ring->dequeue;
544-
state->new_cycle_state = hw_dequeue & 0x1;
547+
548+
/*
549+
* Quirk: xHC write-back of the DCS field in the hardware dequeue
550+
* pointer is wrong - use the cycle state of the TRB pointed to by
551+
* the dequeue pointer.
552+
*/
553+
if (xhci->quirks & XHCI_EP_CTX_BROKEN_DCS &&
554+
!(ep->ep_state & EP_HAS_STREAMS))
555+
halted_seg = trb_in_td(xhci, cur_td->start_seg,
556+
cur_td->first_trb, cur_td->last_trb,
557+
hw_dequeue & ~0xf, false);
558+
if (halted_seg) {
559+
index = ((dma_addr_t)(hw_dequeue & ~0xf) - halted_seg->dma) /
560+
sizeof(*halted_trb);
561+
halted_trb = &halted_seg->trbs[index];
562+
state->new_cycle_state = halted_trb->generic.field[3] & 0x1;
563+
xhci_dbg(xhci, "Endpoint DCS = %d TRB index = %d cycle = %d\n",
564+
(u8)(hw_dequeue & 0x1), index,
565+
state->new_cycle_state);
566+
} else {
567+
state->new_cycle_state = hw_dequeue & 0x1;
568+
}
545569
state->stream_id = stream_id;
546570

547571
/*

drivers/usb/host/xhci.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1865,6 +1865,7 @@ struct xhci_hcd {
18651865
#define XHCI_ZERO_64B_REGS BIT_ULL(32)
18661866
#define XHCI_RESET_PLL_ON_DISCONNECT BIT_ULL(34)
18671867
#define XHCI_SNPS_BROKEN_SUSPEND BIT_ULL(35)
1868+
#define XHCI_EP_CTX_BROKEN_DCS BIT_ULL(36)
18681869

18691870
unsigned int num_active_eps;
18701871
unsigned int limit_active_eps;

0 commit comments

Comments
 (0)