Skip to content

Commit

Permalink
xhci: dbc: poll at different rate depending on data transfer activity
Browse files Browse the repository at this point in the history
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>
  • Loading branch information
Mathias Nyman authored and Greg Kroah-Hartman committed Mar 2, 2024
1 parent fd9d55d commit fb18e5b
Show file tree
Hide file tree
Showing 2 changed files with 13 additions and 2 deletions.
13 changes: 11 additions & 2 deletions drivers/usb/host/xhci-dbgcap.c
Original file line number Diff line number Diff line change
Expand Up @@ -634,7 +634,8 @@ static int xhci_dbc_start(struct xhci_dbc *dbc)
return ret;
}

return mod_delayed_work(system_wq, &dbc->event_work, 1);
return mod_delayed_work(system_wq, &dbc->event_work,
msecs_to_jiffies(dbc->poll_interval));
}

static void xhci_dbc_stop(struct xhci_dbc *dbc)
Expand Down Expand Up @@ -899,8 +900,10 @@ static void xhci_dbc_handle_events(struct work_struct *work)
enum evtreturn evtr;
struct xhci_dbc *dbc;
unsigned long flags;
unsigned int poll_interval;

dbc = container_of(to_delayed_work(work), struct xhci_dbc, event_work);
poll_interval = dbc->poll_interval;

spin_lock_irqsave(&dbc->lock, flags);
evtr = xhci_dbc_do_handle_events(dbc);
Expand All @@ -916,13 +919,18 @@ static void xhci_dbc_handle_events(struct work_struct *work)
dbc->driver->disconnect(dbc);
break;
case EVT_DONE:
/* set fast poll rate if there are pending data transfers */
if (!list_empty(&dbc->eps[BULK_OUT].list_pending) ||
!list_empty(&dbc->eps[BULK_IN].list_pending))
poll_interval = 1;
break;
default:
dev_info(dbc->dev, "stop handling dbc events\n");
return;
}

mod_delayed_work(system_wq, &dbc->event_work, 1);
mod_delayed_work(system_wq, &dbc->event_work,
msecs_to_jiffies(poll_interval));
}

static const char * const dbc_state_strings[DS_MAX] = {
Expand Down Expand Up @@ -1175,6 +1183,7 @@ xhci_alloc_dbc(struct device *dev, void __iomem *base, const struct dbc_driver *
dbc->idVendor = DBC_VENDOR_ID;
dbc->bcdDevice = DBC_DEVICE_REV;
dbc->bInterfaceProtocol = DBC_PROTOCOL;
dbc->poll_interval = DBC_POLL_INTERVAL_DEFAULT;

if (readl(&dbc->regs->control) & DBC_CTRL_DBC_ENABLE)
goto err;
Expand Down
2 changes: 2 additions & 0 deletions drivers/usb/host/xhci-dbgcap.h
Original file line number Diff line number Diff line change
Expand Up @@ -94,6 +94,7 @@ struct dbc_ep {

#define DBC_QUEUE_SIZE 16
#define DBC_WRITE_BUF_SIZE 8192
#define DBC_POLL_INTERVAL_DEFAULT 64 /* milliseconds */

/*
* Private structure for DbC hardware state:
Expand Down Expand Up @@ -140,6 +141,7 @@ struct xhci_dbc {

enum dbc_state state;
struct delayed_work event_work;
unsigned int poll_interval; /* ms */
unsigned resume_required:1;
struct dbc_ep eps[2];

Expand Down

0 comments on commit fb18e5b

Please sign in to comment.