aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/usb/host/xhci-ring.c
diff options
context:
space:
mode:
Diffstat (limited to 'drivers/usb/host/xhci-ring.c')
-rw-r--r--drivers/usb/host/xhci-ring.c98
1 files changed, 94 insertions, 4 deletions
diff --git a/drivers/usb/host/xhci-ring.c b/drivers/usb/host/xhci-ring.c
index 5bdcf9ab2b99..8c72182b3fb8 100644
--- a/drivers/usb/host/xhci-ring.c
+++ b/drivers/usb/host/xhci-ring.c
@@ -566,6 +566,19 @@ void xhci_ring_ep_doorbell(struct xhci_hcd *xhci,
trace_xhci_ring_ep_doorbell(slot_id, DB_VALUE(ep_index, stream_id));
+ /*
+ * For non-coherent systems with PCIe DMA (such as Pi 4, Pi 5) there
+ * is a theoretical race between the TRB write and barrier, which
+ * is reported complete as soon as the write leaves the CPU domain,
+ * the doorbell write, which may be reported as complete by the RC
+ * at some arbitrary point, and the visibility of new TRBs in system
+ * RAM by the endpoint DMA engine.
+ *
+ * This read before the write positively serialises the CPU state
+ * by incurring a round-trip across the link.
+ */
+ readl(db_addr);
+
writel(DB_VALUE(ep_index, stream_id), db_addr);
/* flush the write */
readl(db_addr);
@@ -694,8 +707,11 @@ static int xhci_move_dequeue_past_td(struct xhci_hcd *xhci,
struct xhci_ring *ep_ring;
struct xhci_command *cmd;
struct xhci_segment *new_seg;
+ struct xhci_segment *halted_seg = NULL;
union xhci_trb *new_deq;
int new_cycle;
+ union xhci_trb *halted_trb;
+ int index = 0;
dma_addr_t addr;
u64 hw_dequeue;
bool hw_dequeue_found = false;
@@ -714,7 +730,25 @@ static int xhci_move_dequeue_past_td(struct xhci_hcd *xhci,
hw_dequeue = xhci_get_hw_deq(xhci, dev, ep_index, stream_id) & TR_DEQ_PTR_MASK;
new_seg = ep_ring->deq_seg;
new_deq = ep_ring->dequeue;
- new_cycle = le32_to_cpu(td->end_trb->generic.field[3]) & TRB_CYCLE;
+
+ /*
+ * Quirk: xHC write-back of the DCS field in the hardware dequeue
+ * pointer is wrong - use the cycle state of the TRB pointed to by
+ * the dequeue pointer.
+ */
+ if (xhci->quirks & XHCI_EP_CTX_BROKEN_DCS &&
+ !(ep->ep_state & EP_HAS_STREAMS))
+ halted_seg = trb_in_td(td, hw_dequeue & ~0xf);
+ if (halted_seg) {
+ index = ((dma_addr_t)(hw_dequeue & ~0xf) - halted_seg->dma) /
+ sizeof(*halted_trb);
+ halted_trb = &halted_seg->trbs[index];
+ new_cycle = halted_trb->generic.field[3] & 0x1;
+ xhci_dbg(xhci, "Endpoint DCS = %d TRB index = %d cycle = %d\n",
+ (u8)(hw_dequeue & 0x1), index, new_cycle);
+ } else {
+ new_cycle = le32_to_cpu(td->end_trb->generic.field[3]) & TRB_CYCLE;
+ }
/*
* Walk the ring until both the next TRB and hw_dequeue are found (don't
@@ -745,6 +779,16 @@ static int xhci_move_dequeue_past_td(struct xhci_hcd *xhci,
} while (!hw_dequeue_found || !td_last_trb_found);
+ /*
+ * Quirk: the xHC does not correctly parse link TRBs if the HW Dequeue
+ * pointer is set to one. Advance to the next TRB (and next segment).
+ */
+ if (xhci->quirks & XHCI_AVOID_DQ_ON_LINK && trb_is_link(new_deq)) {
+ if (link_trb_toggles_cycle(new_deq))
+ new_cycle ^= 0x1;
+ next_trb(&new_seg, &new_deq);
+ }
+
/* Don't update the ring cycle state for the producer (us). */
addr = xhci_trb_virt_to_dma(new_seg, new_deq);
if (addr == 0) {
@@ -754,9 +798,9 @@ static int xhci_move_dequeue_past_td(struct xhci_hcd *xhci,
}
if ((ep->ep_state & SET_DEQ_PENDING)) {
- xhci_warn(xhci, "Set TR Deq already pending, don't submit for 0x%pad\n",
- &addr);
- return -EBUSY;
+ xhci_warn(xhci, "WARN A Set TR Deq Ptr command is pending for slot %u ep %u\n",
+ slot_id, ep_index);
+ ep->ep_state &= ~SET_DEQ_PENDING;
}
/* This function gets called from contexts where it cannot sleep */
@@ -3630,6 +3674,48 @@ static int xhci_align_td(struct xhci_hcd *xhci, struct urb *urb, u32 enqd_len,
return 1;
}
+static void xhci_vl805_hub_tt_quirk(struct xhci_hcd *xhci, struct urb *urb,
+ struct xhci_ring *ring)
+{
+ struct list_head *tmp;
+ struct usb_device *udev = urb->dev;
+ unsigned int timeout = 0;
+ unsigned int single_td = 0;
+
+ /*
+ * Adding a TD to an Idle ring for a FS nonperiodic endpoint
+ * that is behind the internal hub's TT will run the risk of causing a
+ * downstream port babble if submitted late in uFrame 7.
+ * Wait until we've moved on into at least uFrame 0
+ * (MFINDEX references the next SOF to be transmitted).
+ *
+ * Rings for IN endpoints in the Running state also risk causing
+ * babble if the returned data is large, but there's not much we can do
+ * about it here.
+ */
+ if (udev->route & 0xffff0 || udev->speed != USB_SPEED_FULL)
+ return;
+
+ list_for_each(tmp, &ring->td_list) {
+ single_td++;
+ if (single_td == 2) {
+ single_td = 0;
+ break;
+ }
+ }
+ if (single_td) {
+ while (timeout < 20 &&
+ (readl(&xhci->run_regs->microframe_index) & 0x7) == 0) {
+ udelay(10);
+ timeout++;
+ }
+ if (timeout >= 20)
+ xhci_warn(xhci, "MFINDEX didn't advance - %u.%u dodged\n",
+ readl(&xhci->run_regs->microframe_index) >> 3,
+ readl(&xhci->run_regs->microframe_index) & 7);
+ }
+}
+
/* This is very similar to what ehci-q.c qtd_fill() does */
int xhci_queue_bulk_tx(struct xhci_hcd *xhci, gfp_t mem_flags,
struct urb *urb, int slot_id, unsigned int ep_index)
@@ -3784,6 +3870,8 @@ int xhci_queue_bulk_tx(struct xhci_hcd *xhci, gfp_t mem_flags,
}
check_trb_math(urb, enqd_len);
+ if (xhci->quirks & XHCI_VLI_HUB_TT_QUIRK)
+ xhci_vl805_hub_tt_quirk(xhci, urb, ring);
giveback_first_trb(xhci, slot_id, ep_index, urb->stream_id,
start_cycle, start_trb);
return 0;
@@ -3932,6 +4020,8 @@ int xhci_queue_ctrl_tx(struct xhci_hcd *xhci, gfp_t mem_flags,
/* Event on completion */
field | TRB_IOC | TRB_TYPE(TRB_STATUS) | ep_ring->cycle_state);
+ if (xhci->quirks & XHCI_VLI_HUB_TT_QUIRK)
+ xhci_vl805_hub_tt_quirk(xhci, urb, ep_ring);
giveback_first_trb(xhci, slot_id, ep_index, 0,
start_cycle, start_trb);
return 0;