mirror of
https://github.com/genodelabs/genode.git
synced 2025-01-18 10:46:25 +00:00
dde_linux: backport update event ring for usb_host
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.
This commit is contained in:
parent
1d1379430a
commit
8679f32d0b
105
repos/dde_linux/patches/usb_host_update_event_ring.patch
Normal file
105
repos/dde_linux/patches/usb_host_update_event_ring.patch
Normal file
@ -0,0 +1,105 @@
|
||||
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:
|
@ -1 +1 @@
|
||||
017ed559d35da47f9df49d5ac1c3c7ef26b0491e
|
||||
1c5d7ab1a7c3fb9cb594123c46ee861f782c5843
|
||||
|
@ -180,10 +180,11 @@ PATCH_OPT(patches/wpa_supplicant.patch) := -p1 -d ${DIR(wpa_supplicant)}
|
||||
|
||||
# USB HOST
|
||||
USB_HOST_OPT = -p1 -d$(SRC_DIR_USB_HOST)
|
||||
PATCH_OPT(patches/usb_host_mem.patch) := $(USB_HOST_OPT)
|
||||
PATCH_OPT(patches/usb_host_omap.patch) := $(USB_HOST_OPT)
|
||||
PATCH_OPT(patches/usb_host_dwc_otg.patch) := $(USB_HOST_OPT)
|
||||
PATCH_OPT(patches/usb_host_isoc_bei.patch):= $(USB_HOST_OPT)
|
||||
PATCH_OPT(patches/usb_host_mem.patch) := $(USB_HOST_OPT)
|
||||
PATCH_OPT(patches/usb_host_omap.patch) := $(USB_HOST_OPT)
|
||||
PATCH_OPT(patches/usb_host_dwc_otg.patch) := $(USB_HOST_OPT)
|
||||
PATCH_OPT(patches/usb_host_isoc_bei.patch) := $(USB_HOST_OPT)
|
||||
PATCH_OPT(patches/usb_host_update_event_ring.patch) := $(USB_HOST_OPT)
|
||||
|
||||
# USB HID
|
||||
USB_HID_OPT = -p1 -d$(SRC_DIR_USB_HID)
|
||||
|
Loading…
Reference in New Issue
Block a user