mirror of
https://github.com/mmueller41/genode.git
synced 2026-01-21 12:32:56 +01:00
This commit contains a backport of commit [1] that deals with updating
the event ring dequeue pointer more often to prevent unnecessary
'Event Ring Full' errors.
[1] 'usb: host: xhci: update event ring dequeue pointer on purpose'
(dc0ffbea5729a3abafa577ebfce87f18b79e294b)
Fixes #4296.
106 lines
3.6 KiB
Diff
106 lines
3.6 KiB
Diff
This is a backport of commit dc0ffbea5729a3abafa577ebfce87f18b79e294b:
|
|
|
|
Subject: [PATCH] usb: host: xhci: update event ring dequeue pointer on purpose
|
|
|
|
On some situations, the software handles TRB events slower
|
|
than adding TRBs, then xhci_handle_event can't return zero
|
|
long time, the xHC will consider the event ring is full,
|
|
and trigger "Event Ring Full" error, but in fact, the software
|
|
has already finished lots of events, just no chance to
|
|
update ERDP (event ring dequeue pointer).
|
|
|
|
In this commit, we force update ERDP if half of TRBS_PER_SEGMENT
|
|
events have handled to avoid "Event Ring Full" error.
|
|
|
|
Signed-off-by: Peter Chen <peter.chen@nxp.com>
|
|
Signed-off-by: Mathias Nyman <mathias.nyman@linux.intel.com>
|
|
Link: https://lore.kernel.org/r/1573836603-10871-2-git-send-email-mathias.nyman@linux.intel.com
|
|
Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
|
|
--- a/drivers/usb/host/xhci-ring.c
|
|
+++ b/drivers/usb/host/xhci-ring.c
|
|
@@ -2717,6 +2717,42 @@
|
|
}
|
|
|
|
/*
|
|
+ * Update Event Ring Dequeue Pointer:
|
|
+ * - When all events have finished
|
|
+ * - To avoid "Event Ring Full Error" condition
|
|
+ */
|
|
+static void xhci_update_erst_dequeue(struct xhci_hcd *xhci,
|
|
+ union xhci_trb *event_ring_deq)
|
|
+{
|
|
+ u64 temp_64;
|
|
+ dma_addr_t deq;
|
|
+
|
|
+ temp_64 = xhci_read_64(xhci, &xhci->ir_set->erst_dequeue);
|
|
+ /* If necessary, update the HW's version of the event ring deq ptr. */
|
|
+ if (event_ring_deq != xhci->event_ring->dequeue) {
|
|
+ deq = xhci_trb_virt_to_dma(xhci->event_ring->deq_seg,
|
|
+ xhci->event_ring->dequeue);
|
|
+ if (deq == 0)
|
|
+ xhci_warn(xhci, "WARN something wrong with SW event ring dequeue ptr\n");
|
|
+ /*
|
|
+ * Per 4.9.4, Software writes to the ERDP register shall
|
|
+ * always advance the Event Ring Dequeue Pointer value.
|
|
+ */
|
|
+ if ((temp_64 & (u64) ~ERST_PTR_MASK) ==
|
|
+ ((u64) deq & (u64) ~ERST_PTR_MASK))
|
|
+ return;
|
|
+
|
|
+ /* Update HC event ring dequeue pointer */
|
|
+ temp_64 &= ERST_PTR_MASK;
|
|
+ temp_64 |= ((u64) deq & (u64) ~ERST_PTR_MASK);
|
|
+ }
|
|
+
|
|
+ /* Clear the event handler busy flag (RW1C) */
|
|
+ temp_64 |= ERST_EHB;
|
|
+ xhci_write_64(xhci, temp_64, &xhci->ir_set->erst_dequeue);
|
|
+}
|
|
+
|
|
+/*
|
|
* xHCI spec says we can get an interrupt, and if the HC has an error condition,
|
|
* we might get bad data out of the event ring. Section 4.10.2.7 has a list of
|
|
* indicators of an event TRB error, but we check the status *first* to be safe.
|
|
@@ -2727,9 +2763,9 @@
|
|
union xhci_trb *event_ring_deq;
|
|
irqreturn_t ret = IRQ_NONE;
|
|
unsigned long flags;
|
|
- dma_addr_t deq;
|
|
u64 temp_64;
|
|
u32 status;
|
|
+ int event_loop = 0;
|
|
|
|
spin_lock_irqsave(&xhci->lock, flags);
|
|
/* Check if the xHC generated the interrupt, or the irq is shared */
|
|
@@ -2783,24 +2819,14 @@
|
|
/* FIXME this should be a delayed service routine
|
|
* that clears the EHB.
|
|
*/
|
|
- while (xhci_handle_event(xhci) > 0) {}
|
|
-
|
|
- temp_64 = xhci_read_64(xhci, &xhci->ir_set->erst_dequeue);
|
|
- /* If necessary, update the HW's version of the event ring deq ptr. */
|
|
- if (event_ring_deq != xhci->event_ring->dequeue) {
|
|
- deq = xhci_trb_virt_to_dma(xhci->event_ring->deq_seg,
|
|
- xhci->event_ring->dequeue);
|
|
- if (deq == 0)
|
|
- xhci_warn(xhci, "WARN something wrong with SW event "
|
|
- "ring dequeue ptr.\n");
|
|
- /* Update HC event ring dequeue pointer */
|
|
- temp_64 &= ERST_PTR_MASK;
|
|
- temp_64 |= ((u64) deq & (u64) ~ERST_PTR_MASK);
|
|
+ while (xhci_handle_event(xhci) > 0) {
|
|
+ if (event_loop++ < TRBS_PER_SEGMENT / 2)
|
|
+ continue;
|
|
+ xhci_update_erst_dequeue(xhci, event_ring_deq);
|
|
+ event_loop = 0;
|
|
}
|
|
|
|
- /* Clear the event handler busy flag (RW1C); event ring is empty. */
|
|
- temp_64 |= ERST_EHB;
|
|
- xhci_write_64(xhci, temp_64, &xhci->ir_set->erst_dequeue);
|
|
+ xhci_update_erst_dequeue(xhci, event_ring_deq);
|
|
ret = IRQ_HANDLED;
|
|
|
|
out:
|