diff --git a/repos/dde_linux/patches/usb_host_isoc_bei.patch b/repos/dde_linux/patches/usb_host_isoc_bei.patch new file mode 100644 index 0000000000..a79589754c --- /dev/null +++ b/repos/dde_linux/patches/usb_host_isoc_bei.patch @@ -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 +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 + Tested-by: Alistair Grant + Cc: stable@vger.kernel.org + Signed-off-by: Mathias Nyman + Signed-off-by: Greg Kroah-Hartman + +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 +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 + +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 */ diff --git a/repos/dde_linux/ports/dde_linux.hash b/repos/dde_linux/ports/dde_linux.hash index a57d7d98eb..1f59075817 100644 --- a/repos/dde_linux/ports/dde_linux.hash +++ b/repos/dde_linux/ports/dde_linux.hash @@ -1 +1 @@ -f18ed96081c46c0bef2a9db80253d51b48a4f07d +6f2e873679a79e8c85bdf62c2f81910b357f8abe diff --git a/repos/dde_linux/ports/dde_linux.port b/repos/dde_linux/ports/dde_linux.port index 0326b99a96..014e31a1d4 100644 --- a/repos/dde_linux/ports/dde_linux.port +++ b/repos/dde_linux/ports/dde_linux.port @@ -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)