* [PATCH 6.6.y 2/5] xhci: dbc: Allow users to modify DbC poll interval via sysfs
2025-10-27 16:29 ` [PATCH 6.6.y 1/5] xhci: dbc: poll at different rate depending on data transfer activity Sasha Levin
@ 2025-10-27 16:29 ` Sasha Levin
2025-10-27 16:29 ` [PATCH 6.6.y 3/5] xhci: dbc: Improve performance by removing delay in transfer event polling Sasha Levin
` (2 subsequent siblings)
3 siblings, 0 replies; 6+ messages in thread
From: Sasha Levin @ 2025-10-27 16:29 UTC (permalink / raw)
To: stable
Cc: Uday M Bhat, Samuel Jacob, Mathias Nyman, Greg Kroah-Hartman,
Sasha Levin
From: Uday M Bhat <uday.m.bhat@intel.com>
[ Upstream commit de3edd47a18fe05a560847cc3165871474e08196 ]
xhci DbC driver polls the host controller for DbC events at a reduced
rate when DbC is enabled but there are no active data transfers.
Allow users to modify this reduced poll interval via dbc_poll_interval_ms
sysfs entry. Unit is milliseconds and accepted range is 0 to 5000.
Max interval of 5000 ms is selected as it matches the common 5 second
timeout used in usb stack.
Default value is 64 milliseconds.
A long interval is useful when users know there won't be any activity
on systems connected via DbC for long periods, and want to avoid
battery drainage due to unnecessary CPU usage.
Example being Android Debugger (ADB) usage over DbC on ChromeOS systems
running Android Runtime.
[minor changes and rewording -Mathias]
Co-developed-by: Samuel Jacob <samjaco@google.com>
Signed-off-by: Samuel Jacob <samjaco@google.com>
Signed-off-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/20240626124835.1023046-5-mathias.nyman@linux.intel.com
Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
Stable-dep-of: f3d12ec847b9 ("xhci: dbc: fix bogus 1024 byte prefix if ttyDBC read races with stall event")
Signed-off-by: Sasha Levin <sashal@kernel.org>
---
.../testing/sysfs-bus-pci-drivers-xhci_hcd | 10 +++++
drivers/usb/host/xhci-dbgcap.c | 38 +++++++++++++++++++
drivers/usb/host/xhci-dbgcap.h | 2 +-
3 files changed, 49 insertions(+), 1 deletion(-)
diff --git a/Documentation/ABI/testing/sysfs-bus-pci-drivers-xhci_hcd b/Documentation/ABI/testing/sysfs-bus-pci-drivers-xhci_hcd
index 5a775b8f65435..fc82aa4e54b00 100644
--- a/Documentation/ABI/testing/sysfs-bus-pci-drivers-xhci_hcd
+++ b/Documentation/ABI/testing/sysfs-bus-pci-drivers-xhci_hcd
@@ -75,3 +75,13 @@ Description:
The default value is 1 (GNU Remote Debug command).
Other permissible value is 0 which is for vendor defined debug
target.
+
+What: /sys/bus/pci/drivers/xhci_hcd/.../dbc_poll_interval_ms
+Date: February 2024
+Contact: Mathias Nyman <mathias.nyman@linux.intel.com>
+Description:
+ This attribute adjust the polling interval used to check for
+ DbC events. Unit is milliseconds. Accepted values range from 0
+ up to 5000. The default value is 64 ms.
+ This polling interval is used while DbC is enabled but has no
+ active data transfers.
diff --git a/drivers/usb/host/xhci-dbgcap.c b/drivers/usb/host/xhci-dbgcap.c
index 79d70e5aaa92c..643afd3ab0988 100644
--- a/drivers/usb/host/xhci-dbgcap.c
+++ b/drivers/usb/host/xhci-dbgcap.c
@@ -1214,11 +1214,48 @@ static ssize_t dbc_bInterfaceProtocol_store(struct device *dev,
return size;
}
+static ssize_t dbc_poll_interval_ms_show(struct device *dev,
+ struct device_attribute *attr,
+ char *buf)
+{
+ struct xhci_dbc *dbc;
+ struct xhci_hcd *xhci;
+
+ xhci = hcd_to_xhci(dev_get_drvdata(dev));
+ dbc = xhci->dbc;
+
+ return sysfs_emit(buf, "%u\n", dbc->poll_interval);
+}
+
+static ssize_t dbc_poll_interval_ms_store(struct device *dev,
+ struct device_attribute *attr,
+ const char *buf, size_t size)
+{
+ struct xhci_dbc *dbc;
+ struct xhci_hcd *xhci;
+ u32 value;
+ int ret;
+
+ ret = kstrtou32(buf, 0, &value);
+ if (ret || value > DBC_POLL_INTERVAL_MAX)
+ return -EINVAL;
+
+ xhci = hcd_to_xhci(dev_get_drvdata(dev));
+ dbc = xhci->dbc;
+
+ dbc->poll_interval = value;
+
+ mod_delayed_work(system_wq, &dbc->event_work, 0);
+
+ return size;
+}
+
static DEVICE_ATTR_RW(dbc);
static DEVICE_ATTR_RW(dbc_idVendor);
static DEVICE_ATTR_RW(dbc_idProduct);
static DEVICE_ATTR_RW(dbc_bcdDevice);
static DEVICE_ATTR_RW(dbc_bInterfaceProtocol);
+static DEVICE_ATTR_RW(dbc_poll_interval_ms);
static struct attribute *dbc_dev_attributes[] = {
&dev_attr_dbc.attr,
@@ -1226,6 +1263,7 @@ static struct attribute *dbc_dev_attributes[] = {
&dev_attr_dbc_idProduct.attr,
&dev_attr_dbc_bcdDevice.attr,
&dev_attr_dbc_bInterfaceProtocol.attr,
+ &dev_attr_dbc_poll_interval_ms.attr,
NULL
};
diff --git a/drivers/usb/host/xhci-dbgcap.h b/drivers/usb/host/xhci-dbgcap.h
index d165bafecd98f..313b5e97a4672 100644
--- a/drivers/usb/host/xhci-dbgcap.h
+++ b/drivers/usb/host/xhci-dbgcap.h
@@ -94,7 +94,7 @@ struct dbc_ep {
#define DBC_QUEUE_SIZE 16
#define DBC_WRITE_BUF_SIZE 8192
#define DBC_POLL_INTERVAL_DEFAULT 64 /* milliseconds */
-
+#define DBC_POLL_INTERVAL_MAX 5000 /* milliseconds */
/*
* Private structure for DbC hardware state:
*/
--
2.51.0
^ permalink raw reply related [flat|nested] 6+ messages in thread* [PATCH 6.6.y 3/5] xhci: dbc: Improve performance by removing delay in transfer event polling.
2025-10-27 16:29 ` [PATCH 6.6.y 1/5] xhci: dbc: poll at different rate depending on data transfer activity Sasha Levin
2025-10-27 16:29 ` [PATCH 6.6.y 2/5] xhci: dbc: Allow users to modify DbC poll interval via sysfs Sasha Levin
@ 2025-10-27 16:29 ` Sasha Levin
2025-10-27 16:29 ` [PATCH 6.6.y 4/5] xhci: dbc: Avoid event polling busyloop if pending rx transfers are inactive Sasha Levin
2025-10-27 16:29 ` [PATCH 6.6.y 5/5] xhci: dbc: fix bogus 1024 byte prefix if ttyDBC read races with stall event Sasha Levin
3 siblings, 0 replies; 6+ messages in thread
From: Sasha Levin @ 2025-10-27 16:29 UTC (permalink / raw)
To: stable; +Cc: Mathias Nyman, Łukasz Bartosik, Greg Kroah-Hartman,
Sasha Levin
From: Mathias Nyman <mathias.nyman@linux.intel.com>
[ Upstream commit 03e3d9c2bd85cda941b3cf78e895c1498ac05c5f ]
Queue event polling work with 0 delay in case there are pending transfers
queued up. This is part 2 of a 3 part series that roughly triples dbc
performace when using adb push and pull over dbc.
Max/min push rate after patches is 210/118 MB/s, pull rate 171/133 MB/s,
tested with large files (300MB-9GB) by Łukasz Bartosik
First performance improvement patch was commit 31128e7492dc
("xhci: dbc: add dbgtty request to end of list once it completes")
Cc: Łukasz Bartosik <ukaszb@chromium.org>
Signed-off-by: Mathias Nyman <mathias.nyman@linux.intel.com>
Link: https://lore.kernel.org/r/20241227120142.1035206-2-mathias.nyman@linux.intel.com
Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
Stable-dep-of: f3d12ec847b9 ("xhci: dbc: fix bogus 1024 byte prefix if ttyDBC read races with stall event")
Signed-off-by: Sasha Levin <sashal@kernel.org>
---
drivers/usb/host/xhci-dbgcap.c | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/drivers/usb/host/xhci-dbgcap.c b/drivers/usb/host/xhci-dbgcap.c
index 643afd3ab0988..177382632614e 100644
--- a/drivers/usb/host/xhci-dbgcap.c
+++ b/drivers/usb/host/xhci-dbgcap.c
@@ -987,7 +987,7 @@ static void xhci_dbc_handle_events(struct work_struct *work)
/* 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;
+ poll_interval = 0;
break;
default:
dev_info(dbc->dev, "stop handling dbc events\n");
--
2.51.0
^ permalink raw reply related [flat|nested] 6+ messages in thread* [PATCH 6.6.y 4/5] xhci: dbc: Avoid event polling busyloop if pending rx transfers are inactive.
2025-10-27 16:29 ` [PATCH 6.6.y 1/5] xhci: dbc: poll at different rate depending on data transfer activity Sasha Levin
2025-10-27 16:29 ` [PATCH 6.6.y 2/5] xhci: dbc: Allow users to modify DbC poll interval via sysfs Sasha Levin
2025-10-27 16:29 ` [PATCH 6.6.y 3/5] xhci: dbc: Improve performance by removing delay in transfer event polling Sasha Levin
@ 2025-10-27 16:29 ` Sasha Levin
2025-10-27 16:29 ` [PATCH 6.6.y 5/5] xhci: dbc: fix bogus 1024 byte prefix if ttyDBC read races with stall event Sasha Levin
3 siblings, 0 replies; 6+ messages in thread
From: Sasha Levin @ 2025-10-27 16:29 UTC (permalink / raw)
To: stable; +Cc: Mathias Nyman, Łukasz Bartosik, Greg Kroah-Hartman,
Sasha Levin
From: Mathias Nyman <mathias.nyman@linux.intel.com>
[ Upstream commit cab63934c33b12c0d1e9f4da7450928057f2c142 ]
Event polling delay is set to 0 if there are any pending requests in
either rx or tx requests lists. Checking for pending requests does
not work well for "IN" transfers as the tty driver always queues
requests to the list and TRBs to the ring, preparing to receive data
from the host.
This causes unnecessary busylooping and cpu hogging.
Only set the event polling delay to 0 if there are pending tx "write"
transfers, or if it was less than 10ms since last active data transfer
in any direction.
Cc: Łukasz Bartosik <ukaszb@chromium.org>
Fixes: fb18e5bb9660 ("xhci: dbc: poll at different rate depending on data transfer activity")
Cc: stable@vger.kernel.org
Signed-off-by: Mathias Nyman <mathias.nyman@linux.intel.com>
Link: https://lore.kernel.org/r/20250505125630.561699-3-mathias.nyman@linux.intel.com
Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
Stable-dep-of: f3d12ec847b9 ("xhci: dbc: fix bogus 1024 byte prefix if ttyDBC read races with stall event")
Signed-off-by: Sasha Levin <sashal@kernel.org>
---
drivers/usb/host/xhci-dbgcap.c | 19 ++++++++++++++++---
drivers/usb/host/xhci-dbgcap.h | 3 +++
2 files changed, 19 insertions(+), 3 deletions(-)
diff --git a/drivers/usb/host/xhci-dbgcap.c b/drivers/usb/host/xhci-dbgcap.c
index 177382632614e..ca541914f7035 100644
--- a/drivers/usb/host/xhci-dbgcap.c
+++ b/drivers/usb/host/xhci-dbgcap.c
@@ -855,6 +855,7 @@ static enum evtreturn xhci_dbc_do_handle_events(struct xhci_dbc *dbc)
{
dma_addr_t deq;
union xhci_trb *evt;
+ enum evtreturn ret = EVT_DONE;
u32 ctrl, portsc;
bool update_erdp = false;
@@ -939,6 +940,7 @@ static enum evtreturn xhci_dbc_do_handle_events(struct xhci_dbc *dbc)
break;
case TRB_TYPE(TRB_TRANSFER):
dbc_handle_xfer_event(dbc, evt);
+ ret = EVT_XFER_DONE;
break;
default:
break;
@@ -957,7 +959,7 @@ static enum evtreturn xhci_dbc_do_handle_events(struct xhci_dbc *dbc)
lo_hi_writeq(deq, &dbc->regs->erdp);
}
- return EVT_DONE;
+ return ret;
}
static void xhci_dbc_handle_events(struct work_struct *work)
@@ -966,6 +968,7 @@ static void xhci_dbc_handle_events(struct work_struct *work)
struct xhci_dbc *dbc;
unsigned long flags;
unsigned int poll_interval;
+ unsigned long busypoll_timelimit;
dbc = container_of(to_delayed_work(work), struct xhci_dbc, event_work);
poll_interval = dbc->poll_interval;
@@ -984,11 +987,21 @@ 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 */
+ /*
+ * Set fast poll rate if there are pending out transfers, or
+ * a transfer was recently processed
+ */
+ busypoll_timelimit = dbc->xfer_timestamp +
+ msecs_to_jiffies(DBC_XFER_INACTIVITY_TIMEOUT);
+
if (!list_empty(&dbc->eps[BULK_OUT].list_pending) ||
- !list_empty(&dbc->eps[BULK_IN].list_pending))
+ time_is_after_jiffies(busypoll_timelimit))
poll_interval = 0;
break;
+ case EVT_XFER_DONE:
+ dbc->xfer_timestamp = jiffies;
+ poll_interval = 0;
+ break;
default:
dev_info(dbc->dev, "stop handling dbc events\n");
return;
diff --git a/drivers/usb/host/xhci-dbgcap.h b/drivers/usb/host/xhci-dbgcap.h
index 313b5e97a4672..1fab3eb9c831d 100644
--- a/drivers/usb/host/xhci-dbgcap.h
+++ b/drivers/usb/host/xhci-dbgcap.h
@@ -95,6 +95,7 @@ struct dbc_ep {
#define DBC_WRITE_BUF_SIZE 8192
#define DBC_POLL_INTERVAL_DEFAULT 64 /* milliseconds */
#define DBC_POLL_INTERVAL_MAX 5000 /* milliseconds */
+#define DBC_XFER_INACTIVITY_TIMEOUT 10 /* milliseconds */
/*
* Private structure for DbC hardware state:
*/
@@ -141,6 +142,7 @@ struct xhci_dbc {
enum dbc_state state;
struct delayed_work event_work;
unsigned int poll_interval; /* ms */
+ unsigned long xfer_timestamp;
unsigned resume_required:1;
struct dbc_ep eps[2];
@@ -186,6 +188,7 @@ struct dbc_request {
enum evtreturn {
EVT_ERR = -1,
EVT_DONE,
+ EVT_XFER_DONE,
EVT_GSER,
EVT_DISC,
};
--
2.51.0
^ permalink raw reply related [flat|nested] 6+ messages in thread* [PATCH 6.6.y 5/5] xhci: dbc: fix bogus 1024 byte prefix if ttyDBC read races with stall event
2025-10-27 16:29 ` [PATCH 6.6.y 1/5] xhci: dbc: poll at different rate depending on data transfer activity Sasha Levin
` (2 preceding siblings ...)
2025-10-27 16:29 ` [PATCH 6.6.y 4/5] xhci: dbc: Avoid event polling busyloop if pending rx transfers are inactive Sasha Levin
@ 2025-10-27 16:29 ` Sasha Levin
3 siblings, 0 replies; 6+ messages in thread
From: Sasha Levin @ 2025-10-27 16:29 UTC (permalink / raw)
To: stable
Cc: Mathias Nyman, stable, Łukasz Bartosik, Greg Kroah-Hartman,
Sasha Levin
From: Mathias Nyman <mathias.nyman@linux.intel.com>
[ Upstream commit f3d12ec847b945d5d65846c85f062d07d5e73164 ]
DbC may add 1024 bogus bytes to the beginneing of the receiving endpoint
if DbC hw triggers a STALL event before any Transfer Blocks (TRBs) for
incoming data are queued, but driver handles the event after it queued
the TRBs.
This is possible as xHCI DbC hardware may trigger spurious STALL transfer
events even if endpoint is empty. The STALL event contains a pointer
to the stalled TRB, and "remaining" untransferred data length.
As there are no TRBs queued yet the STALL event will just point to first
TRB position of the empty ring, with '0' bytes remaining untransferred.
DbC driver is polling for events, and may not handle the STALL event
before /dev/ttyDBC0 is opened and incoming data TRBs are queued.
The DbC event handler will now assume the first queued TRB (length 1024)
has stalled with '0' bytes remaining untransferred, and copies the data
This race situation can be practically mitigated by making sure the event
handler handles all pending transfer events when DbC reaches configured
state, and only then create dev/ttyDbC0, and start queueing transfers.
The event handler can this way detect the STALL events on empty rings
and discard them before any transfers are queued.
This does in practice solve the issue, but still leaves a small possible
gap for the race to trigger.
We still need a way to distinguish spurious STALLs on empty rings with '0'
bytes remaing, from actual STALL events with all bytes transmitted.
Cc: stable <stable@kernel.org>
Fixes: dfba2174dc42 ("usb: xhci: Add DbC support in xHCI driver")
Tested-by: Łukasz Bartosik <ukaszb@chromium.org>
Signed-off-by: Mathias Nyman <mathias.nyman@linux.intel.com>
Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
Signed-off-by: Sasha Levin <sashal@kernel.org>
---
drivers/usb/host/xhci-dbgcap.c | 6 ++++--
1 file changed, 4 insertions(+), 2 deletions(-)
diff --git a/drivers/usb/host/xhci-dbgcap.c b/drivers/usb/host/xhci-dbgcap.c
index ca541914f7035..92c2c083e1232 100644
--- a/drivers/usb/host/xhci-dbgcap.c
+++ b/drivers/usb/host/xhci-dbgcap.c
@@ -880,7 +880,8 @@ static enum evtreturn xhci_dbc_do_handle_events(struct xhci_dbc *dbc)
dev_info(dbc->dev, "DbC configured\n");
portsc = readl(&dbc->regs->portsc);
writel(portsc, &dbc->regs->portsc);
- return EVT_GSER;
+ ret = EVT_GSER;
+ break;
}
return EVT_DONE;
@@ -940,7 +941,8 @@ static enum evtreturn xhci_dbc_do_handle_events(struct xhci_dbc *dbc)
break;
case TRB_TYPE(TRB_TRANSFER):
dbc_handle_xfer_event(dbc, evt);
- ret = EVT_XFER_DONE;
+ if (ret != EVT_GSER)
+ ret = EVT_XFER_DONE;
break;
default:
break;
--
2.51.0
^ permalink raw reply related [flat|nested] 6+ messages in thread