Commit fb18e5bb authored by Mathias Nyman's avatar Mathias Nyman Committed by Greg Kroah-Hartman
Browse files

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: default avatarUday M Bhat <uday.m.bhat@intel.com>
Signed-off-by: default avatarMathias Nyman <mathias.nyman@linux.intel.com>
Link: https://lore.kernel.org/r/20240229141438.619372-9-mathias.nyman@linux.intel.com


Signed-off-by: default avatarGreg Kroah-Hartman <gregkh@linuxfoundation.org>
parent fd9d55d1
Loading
Loading
Loading
Loading
+11 −2
Original line number Diff line number Diff line
@@ -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)
@@ -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);
@@ -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] = {
@@ -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;
+2 −0
Original line number Diff line number Diff line
@@ -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:
@@ -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];