Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux

xhci: dbc: poll at different rate depending on data transfer activity

DbC driver starts polling for events immediately when DbC is enabled.
The current polling interval is 1ms, which keeps the CPU busy, impacting
power management even when there are no active data transfers.

Solve this by polling at a slower rate, with a 64ms interval as default
until a transfer request is queued, or if there are still are pending
unhandled transfers at event completion.

Tested-by: Uday M Bhat <uday.m.bhat@intel.com>
Signed-off-by: Mathias Nyman <mathias.nyman@linux.intel.com>
Link: https://lore.kernel.org/r/20240229141438.619372-9-mathias.nyman@linux.intel.com
Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>

authored by

Mathias Nyman and committed by
Greg Kroah-Hartman
fb18e5bb fd9d55d1

+13 -2
+11 -2
drivers/usb/host/xhci-dbgcap.c
··· 634 634 return ret; 635 635 } 636 636 637 - return mod_delayed_work(system_wq, &dbc->event_work, 1); 637 + return mod_delayed_work(system_wq, &dbc->event_work, 638 + msecs_to_jiffies(dbc->poll_interval)); 638 639 } 639 640 640 641 static void xhci_dbc_stop(struct xhci_dbc *dbc) ··· 900 899 enum evtreturn evtr; 901 900 struct xhci_dbc *dbc; 902 901 unsigned long flags; 902 + unsigned int poll_interval; 903 903 904 904 dbc = container_of(to_delayed_work(work), struct xhci_dbc, event_work); 905 + poll_interval = dbc->poll_interval; 905 906 906 907 spin_lock_irqsave(&dbc->lock, flags); 907 908 evtr = xhci_dbc_do_handle_events(dbc); ··· 919 916 dbc->driver->disconnect(dbc); 920 917 break; 921 918 case EVT_DONE: 919 + /* set fast poll rate if there are pending data transfers */ 920 + if (!list_empty(&dbc->eps[BULK_OUT].list_pending) || 921 + !list_empty(&dbc->eps[BULK_IN].list_pending)) 922 + poll_interval = 1; 922 923 break; 923 924 default: 924 925 dev_info(dbc->dev, "stop handling dbc events\n"); 925 926 return; 926 927 } 927 928 928 - mod_delayed_work(system_wq, &dbc->event_work, 1); 929 + mod_delayed_work(system_wq, &dbc->event_work, 930 + msecs_to_jiffies(poll_interval)); 929 931 } 930 932 931 933 static const char * const dbc_state_strings[DS_MAX] = { ··· 1183 1175 dbc->idVendor = DBC_VENDOR_ID; 1184 1176 dbc->bcdDevice = DBC_DEVICE_REV; 1185 1177 dbc->bInterfaceProtocol = DBC_PROTOCOL; 1178 + dbc->poll_interval = DBC_POLL_INTERVAL_DEFAULT; 1186 1179 1187 1180 if (readl(&dbc->regs->control) & DBC_CTRL_DBC_ENABLE) 1188 1181 goto err;
+2
drivers/usb/host/xhci-dbgcap.h
··· 94 94 95 95 #define DBC_QUEUE_SIZE 16 96 96 #define DBC_WRITE_BUF_SIZE 8192 97 + #define DBC_POLL_INTERVAL_DEFAULT 64 /* milliseconds */ 97 98 98 99 /* 99 100 * Private structure for DbC hardware state: ··· 141 140 142 141 enum dbc_state state; 143 142 struct delayed_work event_work; 143 + unsigned int poll_interval; /* ms */ 144 144 unsigned resume_required:1; 145 145 struct dbc_ep eps[2]; 146 146