Skip to content

Commit d72b5be

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 db901d5 commit d72b5be

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
@@ -695,8 +695,11 @@ static int xhci_move_dequeue_past_td(struct xhci_hcd *xhci,
695695
struct xhci_ring *ep_ring;
696696
struct xhci_command *cmd;
697697
struct xhci_segment *new_seg;
698+
struct xhci_segment *halted_seg = NULL;
698699
union xhci_trb *new_deq;
699700
int new_cycle;
701+
union xhci_trb *halted_trb;
702+
int index = 0;
700703
dma_addr_t addr;
701704
u64 hw_dequeue;
702705
bool hw_dequeue_found = false;
@@ -715,7 +718,25 @@ static int xhci_move_dequeue_past_td(struct xhci_hcd *xhci,
715718
hw_dequeue = xhci_get_hw_deq(xhci, dev, ep_index, stream_id);
716719
new_seg = ep_ring->deq_seg;
717720
new_deq = ep_ring->dequeue;
718-
new_cycle = le32_to_cpu(td->end_trb->generic.field[3]) & TRB_CYCLE;
721+
722+
/*
723+
* Quirk: xHC write-back of the DCS field in the hardware dequeue
724+
* pointer is wrong - use the cycle state of the TRB pointed to by
725+
* the dequeue pointer.
726+
*/
727+
if (xhci->quirks & XHCI_EP_CTX_BROKEN_DCS &&
728+
!(ep->ep_state & EP_HAS_STREAMS))
729+
halted_seg = trb_in_td(td, hw_dequeue & ~0xf);
730+
if (halted_seg) {
731+
index = ((dma_addr_t)(hw_dequeue & ~0xf) - halted_seg->dma) /
732+
sizeof(*halted_trb);
733+
halted_trb = &halted_seg->trbs[index];
734+
new_cycle = halted_trb->generic.field[3] & 0x1;
735+
xhci_dbg(xhci, "Endpoint DCS = %d TRB index = %d cycle = %d\n",
736+
(u8)(hw_dequeue & 0x1), index, new_cycle);
737+
} else {
738+
new_cycle = le32_to_cpu(td->end_trb->generic.field[3]) & TRB_CYCLE;
739+
}
719740

720741
/*
721742
* Walk the ring until both the next TRB and hw_dequeue are found (don't

0 commit comments

Comments
 (0)