diff options
author | Mathias Nyman <mathias.nyman@linux.intel.com> | 2021-06-17 18:03:52 +0300 |
---|---|---|
committer | Greg Kroah-Hartman <gregkh@linuxfoundation.org> | 2021-06-17 18:34:29 +0300 |
commit | 90d551a5bc73d34c600507a1ef61f3a7c0840783 (patch) | |
tree | b96536551e298ebd0d6f7fed5a5249908cce137a /drivers/usb/host/xhci-ring.c | |
parent | ebd88cf50729e1891dbd307dec311b8f05ba2462 (diff) | |
download | linux-90d551a5bc73d34c600507a1ef61f3a7c0840783.tar.xz |
xhci: Add adaptive interrupt rate for isoch TRBs with XHCI_AVOID_BEI quirk
Save a bit of power by not interrupting so often by default if
XHCI_AVOID_BEI quirk is set.
In normal cases the xhci driver will only generate an interrupt on the last
isochronous TRB of an URB. In a common UVC webcam usecase there are 32 TRBs
per URB.
if AVOID_BEI flag is set then xhci driver will force an interrupt every 8th
isoc TRB to make sure the event ring doesn't get too full.
This is however way too frequent in common single webcam use cases, causing
1000 interrupts/sec and thus poor powermanagement performance.
Instead start with interrupting every 32 isoc TRB, and halve it in case
event ring becomes half-full. Stop halving when reaching a rate of every
8th trb.
This is a one way solution. If interrupt rate is increased it will stay
high until driver is reloaded. The highest rate is the same as the old
default rate.
Signed-off-by: Mathias Nyman <mathias.nyman@linux.intel.com>
Link: https://lore.kernel.org/r/20210617150354.1512157-3-mathias.nyman@linux.intel.com
Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
Diffstat (limited to 'drivers/usb/host/xhci-ring.c')
-rw-r--r-- | drivers/usb/host/xhci-ring.c | 7 |
1 files changed, 6 insertions, 1 deletions
diff --git a/drivers/usb/host/xhci-ring.c b/drivers/usb/host/xhci-ring.c index 6acd2329e08d..8fea44bbc266 100644 --- a/drivers/usb/host/xhci-ring.c +++ b/drivers/usb/host/xhci-ring.c @@ -3076,6 +3076,11 @@ irqreturn_t xhci_irq(struct usb_hcd *hcd) if (event_loop++ < TRBS_PER_SEGMENT / 2) continue; xhci_update_erst_dequeue(xhci, event_ring_deq); + + /* ring is half-full, force isoc trbs to interrupt more often */ + if (xhci->isoc_bei_interval > AVOID_BEI_INTERVAL_MIN) + xhci->isoc_bei_interval = xhci->isoc_bei_interval / 2; + event_loop = 0; } @@ -3956,7 +3961,7 @@ static bool trb_block_event_intr(struct xhci_hcd *xhci, int num_tds, int i) * generate an event at least every 8th TD to clear the event ring */ if (i && xhci->quirks & XHCI_AVOID_BEI) - return !!(i % 8); + return !!(i % xhci->isoc_bei_interval); return true; } |