* [PATCH 0/5] usb: xhci: bandwidth accounting fixes and cleanup
@ 2026-10-06 15:24 Niklas Neronin
2026-10-06 15:24 ` [PATCH 1/5] usb: xhci: clear stale bandwidth data after hibernation Niklas Neronin
` (4 more replies)
0 siblings, 5 replies; 15+ messages in thread
From: Niklas Neronin @ 2026-10-06 15:24 UTC (permalink / raw)
To: mathias.nyman; +Cc: linux-usb, Niklas Neronin
This series contains a small collection of xhci fixes and cleanups.
The main fix addresses a regression where software tracked bandwidth
information could survive hibernation resume after the S4 resume path was
optimized. This could result in incorrect bandwidth accounting when devices
were rediscovered after resume.
While investigating bandwidth accounting, I found a few additional issues:
* Fix endpoint resource accounting on virtual device allocation failure
for controllers using XHCI_EP_LIMIT_QUIRK.
* Remove a redundant TT active endpoint update during virtual device
cleanup.
* Correct an endianness conversion for a 32-bit slot context field.
* Remove two unused xhci structures.
Niklas Neronin (5):
usb: xhci: clear stale bandwidth data after hibernation
usb: xhci: correct num_active_eps accounting on allocation failure
usb: xhci: remove redundant TT active EP update from
xhci_free_virt_device()
usb: xhci: correct variable size conversion
usb: xhci: remove unused structs
drivers/usb/host/xhci-mem.c | 22 +++++++++++++++-------
drivers/usb/host/xhci-trace.h | 2 +-
drivers/usb/host/xhci.c | 6 ++++++
drivers/usb/host/xhci.h | 12 ------------
4 files changed, 22 insertions(+), 20 deletions(-)
--
2.50.1
^ permalink raw reply [flat|nested] 15+ messages in thread
* [PATCH 1/5] usb: xhci: clear stale bandwidth data after hibernation
2026-10-06 15:24 [PATCH 0/5] usb: xhci: bandwidth accounting fixes and cleanup Niklas Neronin
@ 2026-10-06 15:24 ` Niklas Neronin
2026-10-06 16:12 ` Michal Pecio
2026-10-06 16:22 ` sashiko-bot
2026-10-06 15:24 ` [PATCH 2/5] usb: xhci: correct num_active_eps accounting on allocation failure Niklas Neronin
` (3 subsequent siblings)
4 siblings, 2 replies; 15+ messages in thread
From: Niklas Neronin @ 2026-10-06 15:24 UTC (permalink / raw)
To: mathias.nyman; +Cc: linux-usb, Niklas Neronin, Harald Judt, Lovekesh Solanki
Controllers using software managed bandwidth accounting maintain
periodic endpoint bandwidth information in struct 'xhci_interval_bw_table'.
Each root hub port owns a bandwidth table and a list of TT bandwidth
domains, where each TT has its own bandwidth table. Virtual devices
reference the bandwidth table of their current bandwidth domain through
'bw_table' or 'tt_info'.
Historically, resume from S4 re-allocated the entire xHCI driver state,
which implicitly cleared all bandwidth accounting data. After the
hibernation resume path was optimized to preserve parts of the driver
state, virtual devices and TT bandwidth information were freed and
recreated, but the root hub bandwidth tables were left intact.
As a result, stale bandwidth accounting data could remain in the root
hub bandwidth tables across hibernation resume, leading to incorrect
bandwidth calculations after devices were rediscovered.
Fix this by resetting all software bandwidth accounting state in
xhci_rh_bw_cleanup() so that resume starts with a clean bandwidth state.
This includes 'xhci->num_active_eps', which must remain consistent with
the cleared bandwidth tables.
Fixes: <2a70e5dc0301> ("usb: xhci: optimize resuming from S4 (suspend-to-disk)")
Reported-by: Harald Judt <h.judt@gmx.at>
Link: https://bugzilla.kernel.org/show_bug.cgi?id=222071
Suggested-by: Lovekesh Solanki <lovekeshsolanki00@gmail.com>
Tested-by: Harald Judt <h.judt@gmx.at>
Signed-off-by: Niklas Neronin <niklas.neronin@linux.intel.com>
---
drivers/usb/host/xhci-mem.c | 16 +++++++++++++++-
drivers/usb/host/xhci.c | 1 +
2 files changed, 16 insertions(+), 1 deletion(-)
diff --git a/drivers/usb/host/xhci-mem.c b/drivers/usb/host/xhci-mem.c
index af8d4b74c4ba..75577f441cdd 100644
--- a/drivers/usb/host/xhci-mem.c
+++ b/drivers/usb/host/xhci-mem.c
@@ -1903,24 +1903,38 @@ EXPORT_SYMBOL_GPL(xhci_remove_secondary_interrupter);
void xhci_rh_bw_cleanup(struct xhci_hcd *xhci)
{
struct xhci_root_port_bw_info *rh_bw;
+ struct xhci_interval_bw_table *bw_table;
+ struct xhci_interval_bw *interval_bw;
struct xhci_tt_bw_info *tt_info, *tt_next;
struct list_head *eps, *ep, *ep_next;
for (int i = 0; i < xhci->max_ports; i++) {
rh_bw = &xhci->rh_bw[i];
+ rh_bw->num_active_tts = 0;
/* Clear and free all TT bandwidth entries */
list_for_each_entry_safe(tt_info, tt_next, &rh_bw->tts, tt_list) {
list_del(&tt_info->tt_list);
kfree(tt_info);
}
+ bw_table = &rh_bw->bw_table;
+ bw_table->interval0_esit_payload = 0;
+ bw_table->bw_used = 0;
+ bw_table->ss_bw_in = 0;
+ bw_table->ss_bw_out = 0;
+
/* Clear per-interval endpoint lists */
for (int j = 0; j < XHCI_MAX_INTERVAL; j++) {
- eps = &rh_bw->bw_table.interval_bw[j].endpoints;
+ interval_bw = &bw_table->interval_bw[j];
+ eps = &interval_bw->endpoints;
+ interval_bw->num_packets = 0;
list_for_each_safe(ep, ep_next, eps)
list_del_init(ep);
+ interval_bw->overhead[LS_OVERHEAD_TYPE] = 0;
+ interval_bw->overhead[FS_OVERHEAD_TYPE] = 0;
+ interval_bw->overhead[HS_OVERHEAD_TYPE] = 0;
}
}
}
diff --git a/drivers/usb/host/xhci.c b/drivers/usb/host/xhci.c
index a9e47e178c28..4708fabba84a 100644
--- a/drivers/usb/host/xhci.c
+++ b/drivers/usb/host/xhci.c
@@ -1185,6 +1185,7 @@ int xhci_resume(struct xhci_hcd *xhci, bool power_lost, bool is_auto_resume)
for (int i = xhci->max_slots; i > 0; i--)
xhci_free_virt_devices_depth_first(xhci, i);
+ xhci->num_active_eps = 0;
xhci_rh_bw_cleanup(xhci);
xhci->cmd_ring_reserved_trbs = 0;
--
2.50.1
^ permalink raw reply related [flat|nested] 15+ messages in thread
* [PATCH 2/5] usb: xhci: correct num_active_eps accounting on allocation failure
2026-10-06 15:24 [PATCH 0/5] usb: xhci: bandwidth accounting fixes and cleanup Niklas Neronin
2026-10-06 15:24 ` [PATCH 1/5] usb: xhci: clear stale bandwidth data after hibernation Niklas Neronin
@ 2026-10-06 15:24 ` Niklas Neronin
2026-10-06 16:29 ` sashiko-bot
2026-10-06 16:33 ` Michal Pecio
2026-10-06 15:24 ` [PATCH 3/5] usb: xhci: remove redundant TT active EP update from xhci_free_virt_device() Niklas Neronin
` (2 subsequent siblings)
4 siblings, 2 replies; 15+ messages in thread
From: Niklas Neronin @ 2026-10-06 15:24 UTC (permalink / raw)
To: mathias.nyman; +Cc: linux-usb, Niklas Neronin
Some host controllers have a global endpoint limit across all slots,
tracked by 'xhci->num_active_eps' when XHCI_EP_LIMIT_QUIRK is set.
During device allocation, EP0 resources are reserved before
xhci_alloc_virt_device() is called, and 'num_active_eps' is incremented
accordingly. If xhci_alloc_virt_device() subsequently fails, the slot is
disabled but the reserved endpoint resource is not released, leaving
'num_active_eps' permanently increased.
Decreasing 'num_active_eps' happens in xhci_handle_cmd_disable_slot(),
which is called upon a Disable Slot completion command.
This causes the driver to gradually lose available endpoint resources
after allocation failures and may eventually prevent new endpoints from
being allocated.
Fix this by decrementing 'num_active_eps' when virtual device allocation
fails.
Signed-off-by: Niklas Neronin <niklas.neronin@linux.intel.com>
---
drivers/usb/host/xhci.c | 5 +++++
1 file changed, 5 insertions(+)
diff --git a/drivers/usb/host/xhci.c b/drivers/usb/host/xhci.c
index 4708fabba84a..ca56e0b69415 100644
--- a/drivers/usb/host/xhci.c
+++ b/drivers/usb/host/xhci.c
@@ -4279,6 +4279,11 @@ int xhci_alloc_dev(struct usb_hcd *hcd, struct usb_device *udev)
*/
if (!xhci_alloc_virt_device(xhci, slot_id, udev, GFP_NOIO)) {
xhci_warn(xhci, "Could not allocate xHCI USB device data structures\n");
+ if (xhci->quirks & XHCI_EP_LIMIT_QUIRK) {
+ spin_lock_irqsave(&xhci->lock, flags);
+ xhci->num_active_eps -= 1;
+ spin_unlock_irqrestore(&xhci->lock, flags);
+ }
goto disable_slot;
}
vdev = xhci->devs[slot_id];
--
2.50.1
^ permalink raw reply related [flat|nested] 15+ messages in thread
* [PATCH 3/5] usb: xhci: remove redundant TT active EP update from xhci_free_virt_device()
2026-10-06 15:24 [PATCH 0/5] usb: xhci: bandwidth accounting fixes and cleanup Niklas Neronin
2026-10-06 15:24 ` [PATCH 1/5] usb: xhci: clear stale bandwidth data after hibernation Niklas Neronin
2026-10-06 15:24 ` [PATCH 2/5] usb: xhci: correct num_active_eps accounting on allocation failure Niklas Neronin
@ 2026-10-06 15:24 ` Niklas Neronin
2026-10-06 16:41 ` sashiko-bot
2026-10-06 15:24 ` [PATCH 4/5] usb: xhci: correct variable size conversion Niklas Neronin
2026-10-06 15:24 ` [PATCH 5/5] usb: xhci: remove unused structs Niklas Neronin
4 siblings, 1 reply; 15+ messages in thread
From: Niklas Neronin @ 2026-10-06 15:24 UTC (permalink / raw)
To: mathias.nyman; +Cc: linux-usb, Niklas Neronin
Function xhci_free_virt_device() saves 'tt_info->active_eps' and later
calls xhci_update_tt_active_eps().
However, xhci_update_tt_active_eps() only updates TT accounting when the
number of active endpoints changes. xhci_free_virt_device() does not add
or remove endpoints and therefore leaves 'tt_info->active_eps' unchanged.
As a result, the call to xhci_update_tt_active_eps() never modifies any
state.
Remove the unused active endpoint tracking and the redundant call.
In cases where virtual devices are freed without first dropping their
endpoints, xhci_rh_bw_cleanup() resets all bandwidth accounting data,
making the update unnecessary.
Signed-off-by: Niklas Neronin <niklas.neronin@linux.intel.com>
---
drivers/usb/host/xhci-mem.c | 6 ------
1 file changed, 6 deletions(-)
diff --git a/drivers/usb/host/xhci-mem.c b/drivers/usb/host/xhci-mem.c
index 75577f441cdd..d665cad22c10 100644
--- a/drivers/usb/host/xhci-mem.c
+++ b/drivers/usb/host/xhci-mem.c
@@ -870,7 +870,6 @@ void xhci_free_virt_device(struct xhci_hcd *xhci, struct xhci_virt_device *dev,
int slot_id)
{
int i;
- int old_active_eps = 0;
/* Slot ID 0 is reserved */
if (slot_id == 0 || !dev)
@@ -883,9 +882,6 @@ void xhci_free_virt_device(struct xhci_hcd *xhci, struct xhci_virt_device *dev,
trace_xhci_free_virt_device(dev);
- if (dev->tt_info)
- old_active_eps = dev->tt_info->active_eps;
-
for (i = 0; i < 31; i++) {
if (dev->eps[i].ring)
xhci_ring_free(xhci, dev->eps[i].ring);
@@ -908,8 +904,6 @@ void xhci_free_virt_device(struct xhci_hcd *xhci, struct xhci_virt_device *dev,
}
/* If this is a hub, free the TT(s) from the TT list */
xhci_free_tt_info(xhci, dev, slot_id);
- /* If necessary, update the number of active TTs on this root port */
- xhci_update_tt_active_eps(xhci, dev, old_active_eps);
if (dev->in_ctx)
xhci_free_container_ctx(xhci, dev->in_ctx);
--
2.50.1
^ permalink raw reply related [flat|nested] 15+ messages in thread
* [PATCH 4/5] usb: xhci: correct variable size conversion
2026-10-06 15:24 [PATCH 0/5] usb: xhci: bandwidth accounting fixes and cleanup Niklas Neronin
` (2 preceding siblings ...)
2026-10-06 15:24 ` [PATCH 3/5] usb: xhci: remove redundant TT active EP update from xhci_free_virt_device() Niklas Neronin
@ 2026-10-06 15:24 ` Niklas Neronin
2026-10-06 16:46 ` sashiko-bot
2026-10-06 15:24 ` [PATCH 5/5] usb: xhci: remove unused structs Niklas Neronin
4 siblings, 1 reply; 15+ messages in thread
From: Niklas Neronin @ 2026-10-06 15:24 UTC (permalink / raw)
To: mathias.nyman; +Cc: linux-usb, Niklas Neronin
Variable 'ctx->tt_info' is defined as a le32 within the 'xhci_slot_ctx'
structure. Correct the conversion by using le32_to_cpu(), ensuring
proper handling of the 32-bit 'tt_info' variable.
Signed-off-by: Niklas Neronin <niklas.neronin@linux.intel.com>
---
drivers/usb/host/xhci-trace.h | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/drivers/usb/host/xhci-trace.h b/drivers/usb/host/xhci-trace.h
index 724cba2dbb78..f88f320811a3 100644
--- a/drivers/usb/host/xhci-trace.h
+++ b/drivers/usb/host/xhci-trace.h
@@ -392,7 +392,7 @@ DECLARE_EVENT_CLASS(xhci_log_slot_ctx,
TP_fast_assign(
__entry->info = le32_to_cpu(ctx->dev_info);
__entry->info2 = le32_to_cpu(ctx->dev_info2);
- __entry->tt_info = le64_to_cpu(ctx->tt_info);
+ __entry->tt_info = le32_to_cpu(ctx->tt_info);
__entry->state = le32_to_cpu(ctx->dev_state);
),
TP_printk("%s", xhci_decode_slot_context(__get_buf(XHCI_MSG_MAX),
--
2.50.1
^ permalink raw reply related [flat|nested] 15+ messages in thread
* [PATCH 5/5] usb: xhci: remove unused structs
2026-10-06 15:24 [PATCH 0/5] usb: xhci: bandwidth accounting fixes and cleanup Niklas Neronin
` (3 preceding siblings ...)
2026-10-06 15:24 ` [PATCH 4/5] usb: xhci: correct variable size conversion Niklas Neronin
@ 2026-10-06 15:24 ` Niklas Neronin
2026-10-06 16:47 ` sashiko-bot
4 siblings, 1 reply; 15+ messages in thread
From: Niklas Neronin @ 2026-10-06 15:24 UTC (permalink / raw)
To: mathias.nyman; +Cc: linux-usb, Niklas Neronin
Neither structure has any remaining users in the xHCI driver, so
remove them as dead code.
Last time 'xhci_cd' was used [1] in 2014.
Last time 'dev_info' was used [2] in 2013.
Link: https://git.kernel.org/torvalds/c/c311e391a7ef [1]
Link: https://git.kernel.org/torvalds/c/de68bab4fa96 [2]
Signed-off-by: Niklas Neronin <niklas.neronin@linux.intel.com>
---
drivers/usb/host/xhci.h | 12 ------------
1 file changed, 12 deletions(-)
diff --git a/drivers/usb/host/xhci.h b/drivers/usb/host/xhci.h
index c7bfa7f028d3..20abcc5a7acc 100644
--- a/drivers/usb/host/xhci.h
+++ b/drivers/usb/host/xhci.h
@@ -1322,12 +1322,6 @@ struct xhci_td {
*/
#define XHCI_CMD_DEFAULT_TIMEOUT 5000
-/* command descriptor */
-struct xhci_cd {
- struct xhci_command *command;
- union xhci_trb *cmd_trb;
-};
-
enum xhci_ring_type {
TYPE_CTRL = 0,
TYPE_ISOC,
@@ -1424,12 +1418,6 @@ struct s3_save {
u32 config_reg;
};
-/* Use for lpm */
-struct dev_info {
- u32 dev_id;
- struct list_head list;
-};
-
struct xhci_bus_state {
unsigned long bus_suspended;
unsigned long next_statechange;
--
2.50.1
^ permalink raw reply related [flat|nested] 15+ messages in thread
* Re: [PATCH 1/5] usb: xhci: clear stale bandwidth data after hibernation
2026-10-06 15:24 ` [PATCH 1/5] usb: xhci: clear stale bandwidth data after hibernation Niklas Neronin
@ 2026-10-06 16:12 ` Michal Pecio
2026-10-06 16:22 ` sashiko-bot
1 sibling, 0 replies; 15+ messages in thread
From: Michal Pecio @ 2026-10-06 16:12 UTC (permalink / raw)
To: Niklas Neronin; +Cc: mathias.nyman, linux-usb, Harald Judt, Lovekesh Solanki
On Tue, 6 Oct 2026 17:24:23 +0200, Niklas Neronin wrote:
> Controllers using software managed bandwidth accounting maintain
> periodic endpoint bandwidth information in struct 'xhci_interval_bw_table'.
>
> Each root hub port owns a bandwidth table and a list of TT bandwidth
> domains, where each TT has its own bandwidth table. Virtual devices
> reference the bandwidth table of their current bandwidth domain through
> 'bw_table' or 'tt_info'.
>
> Historically, resume from S4 re-allocated the entire xHCI driver state,
> which implicitly cleared all bandwidth accounting data. After the
> hibernation resume path was optimized to preserve parts of the driver
> state, virtual devices and TT bandwidth information were freed and
> recreated, but the root hub bandwidth tables were left intact.
>
> As a result, stale bandwidth accounting data could remain in the root
> hub bandwidth tables across hibernation resume, leading to incorrect
> bandwidth calculations after devices were rediscovered.
>
> Fix this by resetting all software bandwidth accounting state in
> xhci_rh_bw_cleanup() so that resume starts with a clean bandwidth state.
> This includes 'xhci->num_active_eps', which must remain consistent with
> the cleared bandwidth tables.
If that's the case then it would make sense to put this inside
xhci_rh_bw_cleanup() rather than xhci_resume(), wouldn't it?
> Fixes: <2a70e5dc0301> ("usb: xhci: optimize resuming from S4 (suspend-to-disk)")
> Reported-by: Harald Judt <h.judt@gmx.at>
> Link: https://bugzilla.kernel.org/show_bug.cgi?id=222071
> Suggested-by: Lovekesh Solanki <lovekeshsolanki00@gmail.com>
> Tested-by: Harald Judt <h.judt@gmx.at>
> Signed-off-by: Niklas Neronin <niklas.neronin@linux.intel.com>
> ---
> drivers/usb/host/xhci-mem.c | 16 +++++++++++++++-
> drivers/usb/host/xhci.c | 1 +
> 2 files changed, 16 insertions(+), 1 deletion(-)
>
> diff --git a/drivers/usb/host/xhci-mem.c b/drivers/usb/host/xhci-mem.c
> index af8d4b74c4ba..75577f441cdd 100644
> --- a/drivers/usb/host/xhci-mem.c
> +++ b/drivers/usb/host/xhci-mem.c
> @@ -1903,24 +1903,38 @@ EXPORT_SYMBOL_GPL(xhci_remove_secondary_interrupter);
> void xhci_rh_bw_cleanup(struct xhci_hcd *xhci)
> {
> struct xhci_root_port_bw_info *rh_bw;
> + struct xhci_interval_bw_table *bw_table;
> + struct xhci_interval_bw *interval_bw;
> struct xhci_tt_bw_info *tt_info, *tt_next;
> struct list_head *eps, *ep, *ep_next;
>
> for (int i = 0; i < xhci->max_ports; i++) {
> rh_bw = &xhci->rh_bw[i];
>
> + rh_bw->num_active_tts = 0;
> /* Clear and free all TT bandwidth entries */
> list_for_each_entry_safe(tt_info, tt_next, &rh_bw->tts, tt_list) {
> list_del(&tt_info->tt_list);
> kfree(tt_info);
> }
>
> + bw_table = &rh_bw->bw_table;
> + bw_table->interval0_esit_payload = 0;
> + bw_table->bw_used = 0;
> + bw_table->ss_bw_in = 0;
> + bw_table->ss_bw_out = 0;
> +
> /* Clear per-interval endpoint lists */
> for (int j = 0; j < XHCI_MAX_INTERVAL; j++) {
> - eps = &rh_bw->bw_table.interval_bw[j].endpoints;
> + interval_bw = &bw_table->interval_bw[j];
> + eps = &interval_bw->endpoints;
>
> + interval_bw->num_packets = 0;
> list_for_each_safe(ep, ep_next, eps)
> list_del_init(ep);
> + interval_bw->overhead[LS_OVERHEAD_TYPE] = 0;
> + interval_bw->overhead[FS_OVERHEAD_TYPE] = 0;
> + interval_bw->overhead[HS_OVERHEAD_TYPE] = 0;
> }
> }
> }
> diff --git a/drivers/usb/host/xhci.c b/drivers/usb/host/xhci.c
> index a9e47e178c28..4708fabba84a 100644
> --- a/drivers/usb/host/xhci.c
> +++ b/drivers/usb/host/xhci.c
> @@ -1185,6 +1185,7 @@ int xhci_resume(struct xhci_hcd *xhci, bool power_lost, bool is_auto_resume)
> for (int i = xhci->max_slots; i > 0; i--)
> xhci_free_virt_devices_depth_first(xhci, i);
>
> + xhci->num_active_eps = 0;
> xhci_rh_bw_cleanup(xhci);
>
> xhci->cmd_ring_reserved_trbs = 0;
> --
> 2.50.1
>
^ permalink raw reply [flat|nested] 15+ messages in thread
* Re: [PATCH 1/5] usb: xhci: clear stale bandwidth data after hibernation
2026-10-06 15:24 ` [PATCH 1/5] usb: xhci: clear stale bandwidth data after hibernation Niklas Neronin
2026-10-06 16:12 ` Michal Pecio
@ 2026-10-06 16:22 ` sashiko-bot
1 sibling, 0 replies; 15+ messages in thread
From: sashiko-bot @ 2026-10-06 16:22 UTC (permalink / raw)
To: Niklas Neronin; +Cc: linux-usb
> Controllers using software managed bandwidth accounting maintain
> periodic endpoint bandwidth information in struct 'xhci_interval_bw_table'.
>
> Each root hub port owns a bandwidth table and a list of TT bandwidth
> domains, where each TT has its own bandwidth table. Virtual devices
> reference the bandwidth table of their current bandwidth domain through
> 'bw_table' or 'tt_info'.
>
> Historically, resume from S4 re-allocated the entire xHCI driver state,
> which implicitly cleared all bandwidth accounting data. After the
> hibernation resume path was optimized to preserve parts of the driver
> state, virtual devices and TT bandwidth information were freed and
> recreated, but the root hub bandwidth tables were left intact.
>
> As a result, stale bandwidth accounting data could remain in the root
> hub bandwidth tables across hibernation resume, leading to incorrect
> bandwidth calculations after devices were rediscovered.
>
> Fix this by resetting all software bandwidth accounting state in
> xhci_rh_bw_cleanup() so that resume starts with a clean bandwidth state.
> This includes 'xhci->num_active_eps', which must remain consistent with
> the cleared bandwidth tables.
>
> Fixes: <2a70e5dc0301> ("usb: xhci: optimize resuming from S4 (suspend-to-disk)")
> Reported-by: Harald Judt <h.judt@gmx.at>
> Link: https://bugzilla.kernel.org/show_bug.cgi?id=222071
> Suggested-by: Lovekesh Solanki <lovekeshsolanki00@gmail.com>
> Tested-by: Harald Judt <h.judt@gmx.at>
> Signed-off-by: Niklas Neronin <niklas.neronin@linux.intel.com>
Sashiko has reviewed this patch and found no issues. It looks great!
--
Sashiko AI review · https://sashiko.dev/#/patchset/20261006152427.3735383-1-niklas.neronin@linux.intel.com?part=1
^ permalink raw reply [flat|nested] 15+ messages in thread
* Re: [PATCH 2/5] usb: xhci: correct num_active_eps accounting on allocation failure
2026-10-06 15:24 ` [PATCH 2/5] usb: xhci: correct num_active_eps accounting on allocation failure Niklas Neronin
@ 2026-10-06 16:29 ` sashiko-bot
2026-10-06 16:33 ` Michal Pecio
1 sibling, 0 replies; 15+ messages in thread
From: sashiko-bot @ 2026-10-06 16:29 UTC (permalink / raw)
To: Niklas Neronin; +Cc: linux-usb
> Some host controllers have a global endpoint limit across all slots,
> tracked by 'xhci->num_active_eps' when XHCI_EP_LIMIT_QUIRK is set.
>
> During device allocation, EP0 resources are reserved before
> xhci_alloc_virt_device() is called, and 'num_active_eps' is incremented
> accordingly. If xhci_alloc_virt_device() subsequently fails, the slot is
> disabled but the reserved endpoint resource is not released, leaving
> 'num_active_eps' permanently increased.
>
> Decreasing 'num_active_eps' happens in xhci_handle_cmd_disable_slot(),
> which is called upon a Disable Slot completion command.
>
> This causes the driver to gradually lose available endpoint resources
> after allocation failures and may eventually prevent new endpoints from
> being allocated.
>
> Fix this by decrementing 'num_active_eps' when virtual device allocation
> fails.
>
> Signed-off-by: Niklas Neronin <niklas.neronin@linux.intel.com>
Sashiko has reviewed this patch and found no issues. It looks great!
--
Sashiko AI review · https://sashiko.dev/#/patchset/20261006152427.3735383-1-niklas.neronin@linux.intel.com?part=2
^ permalink raw reply [flat|nested] 15+ messages in thread
* Re: [PATCH 2/5] usb: xhci: correct num_active_eps accounting on allocation failure
2026-10-06 15:24 ` [PATCH 2/5] usb: xhci: correct num_active_eps accounting on allocation failure Niklas Neronin
2026-10-06 16:29 ` sashiko-bot
@ 2026-10-06 16:33 ` Michal Pecio
2026-10-06 21:02 ` Michal Pecio
1 sibling, 1 reply; 15+ messages in thread
From: Michal Pecio @ 2026-10-06 16:33 UTC (permalink / raw)
To: Niklas Neronin; +Cc: mathias.nyman, linux-usb
On Tue, 6 Oct 2026 17:24:24 +0200, Niklas Neronin wrote:
> Some host controllers have a global endpoint limit across all slots,
> tracked by 'xhci->num_active_eps' when XHCI_EP_LIMIT_QUIRK is set.
>
> During device allocation, EP0 resources are reserved before
> xhci_alloc_virt_device() is called, and 'num_active_eps' is incremented
> accordingly. If xhci_alloc_virt_device() subsequently fails, the slot is
> disabled but the reserved endpoint resource is not released, leaving
> 'num_active_eps' permanently increased.
>
> Decreasing 'num_active_eps' happens in xhci_handle_cmd_disable_slot(),
> which is called upon a Disable Slot completion command.
Why is 'num_active_eps' not decremented if the slot is disabled and
Disable Slot completion handler is supposed to decrement it?
Does this bug really exist? Can you reproduce it by forcing the quirk
with module parameter and simulating vdev allocation failure here?
And it makes sense that Disable Slot should be queued, because this
code only seems to run after successful Enable Slot and we don't want
to leak the HW slot on allocation error.
> This causes the driver to gradually lose available endpoint resources
> after allocation failures and may eventually prevent new endpoints from
> being allocated.
>
> Fix this by decrementing 'num_active_eps' when virtual device allocation
> fails.
>
> Signed-off-by: Niklas Neronin <niklas.neronin@linux.intel.com>
> ---
> drivers/usb/host/xhci.c | 5 +++++
> 1 file changed, 5 insertions(+)
>
> diff --git a/drivers/usb/host/xhci.c b/drivers/usb/host/xhci.c
> index 4708fabba84a..ca56e0b69415 100644
> --- a/drivers/usb/host/xhci.c
> +++ b/drivers/usb/host/xhci.c
> @@ -4279,6 +4279,11 @@ int xhci_alloc_dev(struct usb_hcd *hcd, struct usb_device *udev)
> */
> if (!xhci_alloc_virt_device(xhci, slot_id, udev, GFP_NOIO)) {
> xhci_warn(xhci, "Could not allocate xHCI USB device data structures\n");
> + if (xhci->quirks & XHCI_EP_LIMIT_QUIRK) {
> + spin_lock_irqsave(&xhci->lock, flags);
> + xhci->num_active_eps -= 1;
> + spin_unlock_irqrestore(&xhci->lock, flags);
> + }
> goto disable_slot;
> }
> vdev = xhci->devs[slot_id];
> --
> 2.50.1
>
^ permalink raw reply [flat|nested] 15+ messages in thread
* Re: [PATCH 3/5] usb: xhci: remove redundant TT active EP update from xhci_free_virt_device()
2026-10-06 15:24 ` [PATCH 3/5] usb: xhci: remove redundant TT active EP update from xhci_free_virt_device() Niklas Neronin
@ 2026-10-06 16:41 ` sashiko-bot
0 siblings, 0 replies; 15+ messages in thread
From: sashiko-bot @ 2026-10-06 16:41 UTC (permalink / raw)
To: Niklas Neronin; +Cc: linux-usb
> Function xhci_free_virt_device() saves 'tt_info->active_eps' and later
> calls xhci_update_tt_active_eps().
>
> However, xhci_update_tt_active_eps() only updates TT accounting when the
> number of active endpoints changes. xhci_free_virt_device() does not add
> or remove endpoints and therefore leaves 'tt_info->active_eps' unchanged.
> As a result, the call to xhci_update_tt_active_eps() never modifies any
> state.
>
> Remove the unused active endpoint tracking and the redundant call.
>
> In cases where virtual devices are freed without first dropping their
> endpoints, xhci_rh_bw_cleanup() resets all bandwidth accounting data,
> making the update unnecessary.
>
> Signed-off-by: Niklas Neronin <niklas.neronin@linux.intel.com>
Sashiko has reviewed this patch and found no issues. It looks great!
--
Sashiko AI review · https://sashiko.dev/#/patchset/20261006152427.3735383-1-niklas.neronin@linux.intel.com?part=3
^ permalink raw reply [flat|nested] 15+ messages in thread
* Re: [PATCH 4/5] usb: xhci: correct variable size conversion
2026-10-06 15:24 ` [PATCH 4/5] usb: xhci: correct variable size conversion Niklas Neronin
@ 2026-10-06 16:46 ` sashiko-bot
0 siblings, 0 replies; 15+ messages in thread
From: sashiko-bot @ 2026-10-06 16:46 UTC (permalink / raw)
To: Niklas Neronin; +Cc: linux-usb
> Variable 'ctx->tt_info' is defined as a le32 within the 'xhci_slot_ctx'
> structure. Correct the conversion by using le32_to_cpu(), ensuring
> proper handling of the 32-bit 'tt_info' variable.
>
> Signed-off-by: Niklas Neronin <niklas.neronin@linux.intel.com>
Sashiko has reviewed this patch and found no issues. It looks great!
--
Sashiko AI review · https://sashiko.dev/#/patchset/20261006152427.3735383-1-niklas.neronin@linux.intel.com?part=4
^ permalink raw reply [flat|nested] 15+ messages in thread
* Re: [PATCH 5/5] usb: xhci: remove unused structs
2026-10-06 15:24 ` [PATCH 5/5] usb: xhci: remove unused structs Niklas Neronin
@ 2026-10-06 16:47 ` sashiko-bot
0 siblings, 0 replies; 15+ messages in thread
From: sashiko-bot @ 2026-10-06 16:47 UTC (permalink / raw)
To: Niklas Neronin; +Cc: linux-usb
> Neither structure has any remaining users in the xHCI driver, so
> remove them as dead code.
>
> Last time 'xhci_cd' was used [1] in 2014.
> Last time 'dev_info' was used [2] in 2013.
>
> Link: https://git.kernel.org/torvalds/c/c311e391a7ef [1]
> Link: https://git.kernel.org/torvalds/c/de68bab4fa96 [2]
> Signed-off-by: Niklas Neronin <niklas.neronin@linux.intel.com>
Sashiko has reviewed this patch and found no issues. It looks great!
--
Sashiko AI review · https://sashiko.dev/#/patchset/20261006152427.3735383-1-niklas.neronin@linux.intel.com?part=5
^ permalink raw reply [flat|nested] 15+ messages in thread
* Re: [PATCH 2/5] usb: xhci: correct num_active_eps accounting on allocation failure
2026-10-06 16:33 ` Michal Pecio
@ 2026-10-06 21:02 ` Michal Pecio
2026-10-07 9:28 ` Neronin, Niklas
0 siblings, 1 reply; 15+ messages in thread
From: Michal Pecio @ 2026-10-06 21:02 UTC (permalink / raw)
To: Niklas Neronin; +Cc: mathias.nyman, linux-usb
On Tue, 6 Oct 2026 18:33:01 +0200, Michal Pecio wrote:
> On Tue, 6 Oct 2026 17:24:24 +0200, Niklas Neronin wrote:
> > Some host controllers have a global endpoint limit across all slots,
> > tracked by 'xhci->num_active_eps' when XHCI_EP_LIMIT_QUIRK is set.
> >
> > During device allocation, EP0 resources are reserved before
> > xhci_alloc_virt_device() is called, and 'num_active_eps' is
> > incremented accordingly. If xhci_alloc_virt_device() subsequently
> > fails, the slot is disabled but the reserved endpoint resource is
> > not released, leaving 'num_active_eps' permanently increased.
> >
> > Decreasing 'num_active_eps' happens in
> > xhci_handle_cmd_disable_slot(), which is called upon a Disable Slot
> > completion command.
>
> Why is 'num_active_eps' not decremented if the slot is disabled and
> Disable Slot completion handler is supposed to decrement it?
>
> Does this bug really exist? Can you reproduce it by forcing the quirk
> with module parameter and simulating vdev allocation failure here?
Never mind, the bug is real and reproducible. Still, commit message
could include a few words of explanation to prevent such questions.
I think it would be cleaner to fix this by allocating vdev before
ep0 reservation, because allocation is easier to undo:
1. we have a helper for this, no need to dig in xhci members manually
2. we are the only user of this slot_id, so locking is not required
Downside: larger diff. But less code in the end.
And there is another bug: disable_slot uses udev->slot_id, which is
uninitialized in this path. Should use the local slot_id variable.
So overall,
diff --git a/drivers/usb/host/xhci.c b/drivers/usb/host/xhci.c
index e5b39be04b92..9beb8b4b485f 100644
--- a/drivers/usb/host/xhci.c
+++ b/drivers/usb/host/xhci.c
@@ -4308,27 +4308,29 @@ int xhci_alloc_dev(struct usb_hcd *hcd, struct usb_device *udev)
xhci_free_command(xhci, command);
+ /* Use GFP_NOIO, since this function can be called from
+ * xhci_discover_or_reset_device(), which may be called as part of
+ * mass storage driver error handling.
+ */
+ if (!xhci_alloc_virt_device(xhci, slot_id, udev, GFP_NOIO)) {
+ xhci_warn(xhci, "Could not allocate xHCI USB device data structures\n");
+ goto disable_slot;
+ }
+ vdev = xhci->devs[slot_id];
+
if ((xhci->quirks & XHCI_EP_LIMIT_QUIRK)) {
spin_lock_irqsave(&xhci->lock, flags);
ret = xhci_reserve_host_control_ep_resources(xhci);
+ spin_unlock_irqrestore(&xhci->lock, flags);
if (ret) {
- spin_unlock_irqrestore(&xhci->lock, flags);
xhci_warn(xhci, "Not enough host resources, "
"active endpoint contexts = %u\n",
xhci->num_active_eps);
+ xhci_free_virt_device(xhci, vdev, slot_id);
+ /* without vdev disable slot won't free ep0 resources */
goto disable_slot;
}
- spin_unlock_irqrestore(&xhci->lock, flags);
}
- /* Use GFP_NOIO, since this function can be called from
- * xhci_discover_or_reset_device(), which may be called as part of
- * mass storage driver error handling.
- */
- if (!xhci_alloc_virt_device(xhci, slot_id, udev, GFP_NOIO)) {
- xhci_warn(xhci, "Could not allocate xHCI USB device data structures\n");
- goto disable_slot;
- }
- vdev = xhci->devs[slot_id];
slot_ctx = xhci_get_slot_ctx(xhci, vdev->out_ctx);
trace_xhci_alloc_dev(slot_ctx);
@@ -4348,7 +4350,7 @@ int xhci_alloc_dev(struct usb_hcd *hcd, struct usb_device *udev)
return 1;
disable_slot:
- xhci_disable_and_free_slot(xhci, udev->slot_id);
+ xhci_disable_slot(xhci, slot_id);
return 0;
}
^ permalink raw reply related [flat|nested] 15+ messages in thread
* Re: [PATCH 2/5] usb: xhci: correct num_active_eps accounting on allocation failure
2026-10-06 21:02 ` Michal Pecio
@ 2026-10-07 9:28 ` Neronin, Niklas
0 siblings, 0 replies; 15+ messages in thread
From: Neronin, Niklas @ 2026-10-07 9:28 UTC (permalink / raw)
To: Michal Pecio; +Cc: mathias.nyman, linux-usb
On 07/10/2026 0.02, Michal Pecio wrote:
> On Tue, 6 Oct 2026 18:33:01 +0200, Michal Pecio wrote:
>> On Tue, 6 Oct 2026 17:24:24 +0200, Niklas Neronin wrote:
>>> Some host controllers have a global endpoint limit across all slots,
>>> tracked by 'xhci->num_active_eps' when XHCI_EP_LIMIT_QUIRK is set.
>>>
>>> During device allocation, EP0 resources are reserved before
>>> xhci_alloc_virt_device() is called, and 'num_active_eps' is
>>> incremented accordingly. If xhci_alloc_virt_device() subsequently
>>> fails, the slot is disabled but the reserved endpoint resource is
>>> not released, leaving 'num_active_eps' permanently increased.
>>>
>>> Decreasing 'num_active_eps' happens in
>>> xhci_handle_cmd_disable_slot(), which is called upon a Disable Slot
>>> completion command.
>>
>> Why is 'num_active_eps' not decremented if the slot is disabled and
>> Disable Slot completion handler is supposed to decrement it?
>>
>> Does this bug really exist? Can you reproduce it by forcing the quirk
>> with module parameter and simulating vdev allocation failure here?
>
> Never mind, the bug is real and reproducible. Still, commit message
> could include a few words of explanation to prevent such questions.
>
> I think it would be cleaner to fix this by allocating vdev before
> ep0 reservation, because allocation is easier to undo:
That's a good point. I found this while working on a separate series
that splits 'vdev' allocation and slot enabling. That series was not
ready for this merge window, so I decided to submit only the simpler
fixes first to keep the future series smaller and less cluttered.
As you suggested, that series moves 'vdev' allocation before EP
reservation.
>
> 1. we have a helper for this, no need to dig in xhci members manually
> 2. we are the only user of this slot_id, so locking is not required
>
> Downside: larger diff. But less code in the end.
>
> And there is another bug: disable_slot uses udev->slot_id, which is
> uninitialized in this path. Should use the local slot_id variable.
Good catch. I found the same issue but apparently forgot to include the
fix in this patch set.
Probably best if this patch is not added to this merge window,
instead I'll re-submit it with all the virtual device changes.
Thanks,
Niklas
>
> So overall,
>
> diff --git a/drivers/usb/host/xhci.c b/drivers/usb/host/xhci.c
> index e5b39be04b92..9beb8b4b485f 100644
> --- a/drivers/usb/host/xhci.c
> +++ b/drivers/usb/host/xhci.c
> @@ -4308,27 +4308,29 @@ int xhci_alloc_dev(struct usb_hcd *hcd, struct usb_device *udev)
>
> xhci_free_command(xhci, command);
>
> + /* Use GFP_NOIO, since this function can be called from
> + * xhci_discover_or_reset_device(), which may be called as part of
> + * mass storage driver error handling.
> + */
> + if (!xhci_alloc_virt_device(xhci, slot_id, udev, GFP_NOIO)) {
> + xhci_warn(xhci, "Could not allocate xHCI USB device data structures\n");
> + goto disable_slot;
> + }
> + vdev = xhci->devs[slot_id];
> +
> if ((xhci->quirks & XHCI_EP_LIMIT_QUIRK)) {
> spin_lock_irqsave(&xhci->lock, flags);
> ret = xhci_reserve_host_control_ep_resources(xhci);
> + spin_unlock_irqrestore(&xhci->lock, flags);
> if (ret) {
> - spin_unlock_irqrestore(&xhci->lock, flags);
> xhci_warn(xhci, "Not enough host resources, "
> "active endpoint contexts = %u\n",
> xhci->num_active_eps);
> + xhci_free_virt_device(xhci, vdev, slot_id);
> + /* without vdev disable slot won't free ep0 resources */
> goto disable_slot;
> }
> - spin_unlock_irqrestore(&xhci->lock, flags);
> }
> - /* Use GFP_NOIO, since this function can be called from
> - * xhci_discover_or_reset_device(), which may be called as part of
> - * mass storage driver error handling.
> - */
> - if (!xhci_alloc_virt_device(xhci, slot_id, udev, GFP_NOIO)) {
> - xhci_warn(xhci, "Could not allocate xHCI USB device data structures\n");
> - goto disable_slot;
> - }
> - vdev = xhci->devs[slot_id];
> slot_ctx = xhci_get_slot_ctx(xhci, vdev->out_ctx);
> trace_xhci_alloc_dev(slot_ctx);
>
> @@ -4348,7 +4350,7 @@ int xhci_alloc_dev(struct usb_hcd *hcd, struct usb_device *udev)
> return 1;
>
> disable_slot:
> - xhci_disable_and_free_slot(xhci, udev->slot_id);
> + xhci_disable_slot(xhci, slot_id);
>
> return 0;
> }
^ permalink raw reply [flat|nested] 15+ messages in thread
end of thread, other threads:[~2026-10-07 9:28 UTC | newest]
Thread overview: 15+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2026-10-06 15:24 [PATCH 0/5] usb: xhci: bandwidth accounting fixes and cleanup Niklas Neronin
2026-10-06 15:24 ` [PATCH 1/5] usb: xhci: clear stale bandwidth data after hibernation Niklas Neronin
2026-10-06 16:12 ` Michal Pecio
2026-10-06 16:22 ` sashiko-bot
2026-10-06 15:24 ` [PATCH 2/5] usb: xhci: correct num_active_eps accounting on allocation failure Niklas Neronin
2026-10-06 16:29 ` sashiko-bot
2026-10-06 16:33 ` Michal Pecio
2026-10-06 21:02 ` Michal Pecio
2026-10-07 9:28 ` Neronin, Niklas
2026-10-06 15:24 ` [PATCH 3/5] usb: xhci: remove redundant TT active EP update from xhci_free_virt_device() Niklas Neronin
2026-10-06 16:41 ` sashiko-bot
2026-10-06 15:24 ` [PATCH 4/5] usb: xhci: correct variable size conversion Niklas Neronin
2026-10-06 16:46 ` sashiko-bot
2026-10-06 15:24 ` [PATCH 5/5] usb: xhci: remove unused structs Niklas Neronin
2026-10-06 16:47 ` sashiko-bot
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox