mirror of
https://github.com/genodelabs/genode.git
synced 2025-04-16 07:27:35 +00:00
usb_host: improve isochronous performance on Intel
This patch takes advantage of block transfer interrupts on Intel XHCI controllers which is used during isochronous transfers. Because of a bug in hardware (see usb_host_isoc_bei.patch header), this feature has been disabled for Intel leading to up to 8000 interrupts/s for isochronous transfer causing severe CPU consumption on Genode. With this commit we lower host driver consumption to normal levels. issue #4149
This commit is contained in:
parent
9543161827
commit
a24224ffc3
107
repos/dde_linux/patches/usb_host_isoc_bei.patch
Normal file
107
repos/dde_linux/patches/usb_host_isoc_bei.patch
Normal file
@ -0,0 +1,107 @@
|
||||
For Intel host controllers an interrupt is raised for every isochronous packet,
|
||||
because of the "AVOID_BEI" quirk. The reasoning for this is found in the
|
||||
following commit:
|
||||
|
||||
commit 227a4fd801c8a9fa2c4700ab98ec1aec06e3b44d
|
||||
Author: Lu Baolu <baolu.lu@linux.intel.com>
|
||||
Date: Mon Mar 23 18:27:42 2015 +0200
|
||||
|
||||
usb: xhci: apply XHCI_AVOID_BEI quirk to all Intel xHCI controllers
|
||||
|
||||
When a device with an isochronous endpoint is plugged into the Intel
|
||||
xHCI host controller, and the driver submits multiple frames per URB,
|
||||
the xHCI driver will set the Block Event Interrupt (BEI) flag on all
|
||||
but the last TD for the URB. This causes the host controller to place
|
||||
an event on the event ring, but not send an interrupt. When the last
|
||||
TD for the URB completes, BEI is cleared, and we get an interrupt for
|
||||
the whole URB.
|
||||
|
||||
However, under Intel xHCI host controllers, if the event ring is full
|
||||
of events from transfers with BEI set, an "Event Ring is Full" event
|
||||
will be posted to the last entry of the event ring, but no interrupt
|
||||
is generated. Host will cease all transfer and command executions and
|
||||
wait until software completes handling the pending events in the event
|
||||
ring. That means xHC stops, but event of "event ring is full" is not
|
||||
notified. As the result, the xHC looks like dead to user.
|
||||
|
||||
This patch is to apply XHCI_AVOID_BEI quirk to Intel xHC devices. And
|
||||
it should be backported to kernels as old as 3.0, that contains the
|
||||
commit 69e848c2090a ("Intel xhci: Support EHCI/xHCI port switching.").
|
||||
|
||||
Signed-off-by: Lu Baolu <baolu.lu@linux.intel.com>
|
||||
Tested-by: Alistair Grant <akgrant0710@gmail.com>
|
||||
Cc: stable@vger.kernel.org
|
||||
Signed-off-by: Mathias Nyman <mathias.nyman@linux.intel.com>
|
||||
Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
|
||||
|
||||
Because this behavior up to 8000 interrupts/s can be raised by the host
|
||||
controller during isochronous transfer. Since 2020 there exists a patch that
|
||||
relaxes this burden and which we will apply.
|
||||
|
||||
Author: Mathias Nyman <mathias.nyman@linux.intel.com>
|
||||
Date: Fr Sep 18 2020 13:17:24 2020 +0200
|
||||
|
||||
xhci: Tune interrupt blocking for isochronous transfers
|
||||
|
||||
controllers with XHCI_AVOID_BEI quirk cause too frequent interrupts
|
||||
and affect power management.
|
||||
|
||||
To avoid interrupting on every isochronous interval the BEI (Block
|
||||
Event Interrupt) flag is set for all except the last Isoch TRB in a URB.
|
||||
This lead to event ring filling up in case several isoc URB were
|
||||
queued and cancelled rapidly, which some controllers didn't
|
||||
handle well, and thus the XHCI_AVOID_BEI quirk was introduced.
|
||||
see commit 227a4fd801c8 ("usb: xhci: apply XHCI_AVOID_BEI quirk to all
|
||||
Intel xHCI controllers")
|
||||
|
||||
With the XHCI_AVOID_BEI quirk each Isoch TRB will trigger an interrupt.
|
||||
This can cause up to 8000 interrupts per second for isochronous transfers
|
||||
with HD USB3 cameras, affecting power saving.
|
||||
|
||||
The event ring fits 256 events, instead of interrupting on every
|
||||
isochronous TRB if XHCI_AVOID_BEI is set we make sure at least every
|
||||
8th Isochronous TRB asserts an interrupt, clearing the event ring.
|
||||
|
||||
Signed-off-by: Mathias Nyman <mathias.nyman@linux.intel.com>
|
||||
|
||||
diff --git a/drivers/usb/host/xhci-ring.c b/drivers/usb/host/xhci-ring.c
|
||||
index 028891a..31f6bd3 100644
|
||||
--- a/drivers/usb/host/xhci-ring.c
|
||||
+++ b/drivers/usb/host/xhci-ring.c
|
||||
@@ -3608,6 +3608,24 @@ static int xhci_get_isoc_frame_id(struct xhci_hcd *xhci,
|
||||
return start_frame;
|
||||
}
|
||||
|
||||
+/* Check if we should generate event interrupt for a TD in an isoc URB */
|
||||
+static bool trb_block_event_intr(struct xhci_hcd *xhci, int num_tds, int i)
|
||||
+{
|
||||
+ if (xhci->hci_version < 0x100)
|
||||
+ return false;
|
||||
+ /* always generate an event interrupt for the last TD */
|
||||
+ if (i == num_tds - 1)
|
||||
+ return false;
|
||||
+ /*
|
||||
+ * If AVOID_BEI is set the host handles full event rings poorly,
|
||||
+ * generate an event at least every 8th TD to clear the event ring
|
||||
+ */
|
||||
+ if (i && xhci->quirks & XHCI_AVOID_BEI)
|
||||
+ return !!(i % 8);
|
||||
+
|
||||
+ return true;
|
||||
+}
|
||||
+
|
||||
/* This is for isoc transfer */
|
||||
static int xhci_queue_isoc_tx(struct xhci_hcd *xhci, gfp_t mem_flags,
|
||||
struct urb *urb, int slot_id, unsigned int ep_index)
|
||||
@@ -3715,10 +3733,7 @@ static int xhci_queue_isoc_tx(struct xhci_hcd *xhci, gfp_t mem_flags,
|
||||
more_trbs_coming = false;
|
||||
td->last_trb = ep_ring->enqueue;
|
||||
field |= TRB_IOC;
|
||||
- /* set BEI, except for the last TD */
|
||||
- if (xhci->hci_version >= 0x100 &&
|
||||
- !(xhci->quirks & XHCI_AVOID_BEI) &&
|
||||
- i < num_tds - 1)
|
||||
+ if (trb_block_event_intr(xhci, num_tds, i))
|
||||
field |= TRB_BEI;
|
||||
}
|
||||
/* Calculate TRB length */
|
@ -1 +1 @@
|
||||
f18ed96081c46c0bef2a9db80253d51b48a4f07d
|
||||
6f2e873679a79e8c85bdf62c2f81910b357f8abe
|
||||
|
@ -210,6 +210,7 @@ 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)
|
||||
|
||||
# USB HID
|
||||
USB_HID_OPT = -p1 -d$(SRC_DIR_USB_HID)
|
||||
|
Loading…
x
Reference in New Issue
Block a user