Skip to content

Commit 6fea01c

Browse files
pelwellpopcornmix
authored andcommitted
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. [ bjorn: rebased to v5.14-rc2 ] Link: #3060 Cc: [email protected] Signed-off-by: Jonathan Bell <[email protected]> Signed-off-by: Bjørn Mork <[email protected]> Signed-off-by: Mathias Nyman <[email protected]> Link: https://lore.kernel.org/r/[email protected] Signed-off-by: Greg Kroah-Hartman <[email protected]>
1 parent 8ecd77d commit 6fea01c

File tree

3 files changed

+24
-4
lines changed

3 files changed

+24
-4
lines changed

drivers/net/ethernet/broadcom/genet/bcmmii.c

Lines changed: 1 addition & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -304,9 +304,7 @@ int bcmgenet_mii_probe(struct net_device *dev)
304304
struct device_node *dn = kdev->of_node;
305305
phy_interface_t phy_iface = priv->phy_interface;
306306
struct phy_device *phydev;
307-
u32 phy_flags = PHY_BRCM_AUTO_PWRDWN_ENABLE |
308-
PHY_BRCM_DIS_TXCRXC_NOENRGY |
309-
PHY_BRCM_IDDQ_SUSPEND;
307+
u32 phy_flags = 0;
310308
int ret;
311309

312310
/* Communicate the integrated PHY revision */

drivers/usb/host/xhci-pci.c

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -423,6 +423,7 @@ static void xhci_pci_quirks(struct device *dev, struct xhci_hcd *xhci)
423423
if (pdev->vendor == PCI_VENDOR_ID_VIA && pdev->device == PCI_DEVICE_ID_VIA_VL805) {
424424
xhci->quirks |= XHCI_LPM_SUPPORT;
425425
xhci->quirks |= XHCI_TRB_OVERFETCH;
426+
xhci->quirks |= XHCI_EP_CTX_BROKEN_DCS;
426427
}
427428

428429
if (pdev->vendor == PCI_VENDOR_ID_ASMEDIA &&

drivers/usb/host/xhci-ring.c

Lines changed: 22 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -639,8 +639,11 @@ static int xhci_move_dequeue_past_td(struct xhci_hcd *xhci,
639639
struct xhci_ring *ep_ring;
640640
struct xhci_command *cmd;
641641
struct xhci_segment *new_seg;
642+
struct xhci_segment *halted_seg = NULL;
642643
union xhci_trb *new_deq;
643644
int new_cycle;
645+
union xhci_trb *halted_trb;
646+
int index = 0;
644647
dma_addr_t addr;
645648
u64 hw_dequeue;
646649
bool cycle_found = false;
@@ -659,7 +662,25 @@ static int xhci_move_dequeue_past_td(struct xhci_hcd *xhci,
659662
hw_dequeue = xhci_get_hw_deq(xhci, dev, ep_index, stream_id);
660663
new_seg = ep_ring->deq_seg;
661664
new_deq = ep_ring->dequeue;
662-
new_cycle = hw_dequeue & 0x1;
665+
666+
/*
667+
* Quirk: xHC write-back of the DCS field in the hardware dequeue
668+
* pointer is wrong - use the cycle state of the TRB pointed to by
669+
* the dequeue pointer.
670+
*/
671+
if (xhci->quirks & XHCI_EP_CTX_BROKEN_DCS &&
672+
!(ep->ep_state & EP_HAS_STREAMS))
673+
halted_seg = trb_in_td(xhci, td, hw_dequeue & ~0xf, false);
674+
if (halted_seg) {
675+
index = ((dma_addr_t)(hw_dequeue & ~0xf) - halted_seg->dma) /
676+
sizeof(*halted_trb);
677+
halted_trb = &halted_seg->trbs[index];
678+
new_cycle = halted_trb->generic.field[3] & 0x1;
679+
xhci_dbg(xhci, "Endpoint DCS = %d TRB index = %d cycle = %d\n",
680+
(u8)(hw_dequeue & 0x1), index, new_cycle);
681+
} else {
682+
new_cycle = hw_dequeue & 0x1;
683+
}
663684

664685
/*
665686
* We want to find the pointer, segment and cycle state of the new trb

0 commit comments

Comments
 (0)