* [PATCH] usb: gadget: dummy_hcd: add tick_us module parameter for
@ 2026-08-23 17:15 Mikhail Zubenko
2026-08-23 17:25 ` Greg Kroah-Hartman
` (7 more replies)
0 siblings, 8 replies; 13+ messages in thread
From: Mikhail Zubenko @ 2026-08-23 17:15 UTC (permalink / raw)
To: linux-usb; +Cc: Greg Kroah-Hartman, Alan Stern
From: Mikhail Zubenko <misha.zubenko.01@yandex.ru>
Date: Sun, 23 Aug 2026 17:12:49 +0000
Subject: [PATCH] usb: gadget: dummy_hcd: add tick_us module parameter for
timer-rate tuning
The simulated controller completes URBs on a hrtimer armed at a fixed
125 us (one high-speed microframe). Against a permanently polled HID
interrupt endpoint this creates a self-sustaining pendulum at ~8 kHz:
every completion triggers an immediate resubmit, which rearms the
timer. The rate is unconditional - it does not depend on traffic.
On timer-rate-sensitive platforms (observed: one consumer AM4 board,
BIOS current, stock kernel) this pendulum co-existing with a live
Bluetooth session behind the same xHCI controller results in a hard,
below-software platform hang: printk, SysRq, NMI and both watchdogs
die in the same instant, with no panic, no MCE, and empty pstore.
13 occurrences over 5 days, fully reproducible; the same workload
with the pendulum slowed to 1000 us (this parameter) ran ~8 hours
with zero hangs, and USB-cable sessions (identical gadget traffic,
no BT co-existence) never hung.
Nothing else in the driver's behaviour depends on the exact tick:
the bandwidth model accounts per-frame budget regardless of how
often frames are simulated, so a larger tick trades latency
(1 ms added worst case at tick_us=1000) for interrupt-rate headroom.
Default keeps the current 125 us behaviour bit-for-bit.
Signed-off-by: Mikhail Zubenko <misha.zubenko.01@yandex.ru>
---
drivers/usb/gadget/udc/dummy_hcd.c | 8 +++++++-
1 file changed, 7 insertions(+), 1 deletion(-)
diff --git a/drivers/usb/gadget/udc/dummy_hcd.c b/drivers/usb/gadget/udc/dummy_hcd.c
index c0e40fa..f185b87 100644
--- a/drivers/usb/gadget/udc/dummy_hcd.c
+++ b/drivers/usb/gadget/udc/dummy_hcd.c
@@ -51,7 +51,7 @@
#define POWER_BUDGET 500 /* in mA; use 8 for low-power port testing */
#define POWER_BUDGET_3 900 /* in mA */
-#define DUMMY_TIMER_INT_NSECS 125000 /* 1 microframe */
+#define DUMMY_TIMER_INT_NSECS ((u64)tick_us * NSEC_PER_USEC)
static const char driver_name[] = "dummy_hcd";
static const char driver_desc[] = "USB Host+Gadget Emulator";
@@ -79,6 +79,12 @@ module_param_named(is_high_speed, mod_data.is_high_speed, bool, S_IRUGO);
MODULE_PARM_DESC(is_high_speed, "true to simulate HighSpeed connection");
module_param_named(num, mod_data.num, uint, S_IRUGO);
MODULE_PARM_DESC(num, "number of emulated controllers");
+
+static unsigned int tick_us = 125;
+module_param(tick_us, uint, 0644);
+MODULE_PARM_DESC(tick_us,
+ "enqueue-to-completion latency of the simulated controller, in microseconds (default 125, one high-speed microframe);"
+ " larger values slow the internal timer pendulum and reduce its interrupt-rate pressure on the host platform");
/*-------------------------------------------------------------------------*/
/* gadget side driver data structures */
--
2.43.0
^ permalink raw reply related [flat|nested] 13+ messages in thread
* Re: [PATCH] usb: gadget: dummy_hcd: add tick_us module parameter for
2026-08-23 17:15 [PATCH] usb: gadget: dummy_hcd: add tick_us module parameter for Mikhail Zubenko
@ 2026-08-23 17:25 ` Greg Kroah-Hartman
2026-08-23 19:55 ` Alan Stern
` (6 subsequent siblings)
7 siblings, 0 replies; 13+ messages in thread
From: Greg Kroah-Hartman @ 2026-08-23 17:25 UTC (permalink / raw)
To: Mikhail Zubenko; +Cc: linux-usb, Alan Stern
On Sun, Aug 23, 2026 at 05:15:00PM -0000, Mikhail Zubenko wrote:
> From: Mikhail Zubenko <misha.zubenko.01@yandex.ru>
> Date: Sun, 23 Aug 2026 17:12:49 +0000
> Subject: [PATCH] usb: gadget: dummy_hcd: add tick_us module parameter for
> timer-rate tuning
Why is this here?
thanks,
greg k-h
^ permalink raw reply [flat|nested] 13+ messages in thread
* Re: [PATCH] usb: gadget: dummy_hcd: add tick_us module parameter for
2026-08-23 17:15 [PATCH] usb: gadget: dummy_hcd: add tick_us module parameter for Mikhail Zubenko
2026-08-23 17:25 ` Greg Kroah-Hartman
@ 2026-08-23 19:55 ` Alan Stern
2026-08-24 8:29 ` [PATCH v2] usb: gadget: dummy_hcd: add tick_us module parameter for timer-rate tuning Mikhail Zubenko
` (5 subsequent siblings)
7 siblings, 0 replies; 13+ messages in thread
From: Alan Stern @ 2026-08-23 19:55 UTC (permalink / raw)
To: Mikhail Zubenko; +Cc: linux-usb, Greg Kroah-Hartman
On Sun, Aug 23, 2026 at 05:15:00PM -0000, Mikhail Zubenko wrote:
> From: Mikhail Zubenko <misha.zubenko.01@yandex.ru>
> Date: Sun, 23 Aug 2026 17:12:49 +0000
> Subject: [PATCH] usb: gadget: dummy_hcd: add tick_us module parameter for
> timer-rate tuning
>
> The simulated controller completes URBs on a hrtimer armed at a fixed
> 125 us (one high-speed microframe). Against a permanently polled HID
> interrupt endpoint this creates a self-sustaining pendulum at ~8 kHz:
> every completion triggers an immediate resubmit, which rearms the
> timer. The rate is unconditional - it does not depend on traffic.
That is not a correct description of the situation.
The dummy_hcd timer rearms itself every time it triggers, so long as
there are any active URBs. The rate does depend on the traffic, in the
sense that if there are no pending URBs (and hence no traffic) then the
timer does not run. But if there are any URBs, even if there is no
actual traffic, the timer will run at the same fixed rate.
And you shouldn't call it a pendulum. It's not a pendulum, it's a
timer. (The word "pendulum" implies notions of harmonic -- or nearly
harmonic -- motion which do not apply to a timer.)
> On timer-rate-sensitive platforms (observed: one consumer AM4 board,
> BIOS current, stock kernel) this pendulum co-existing with a live
> Bluetooth session behind the same xHCI controller results in a hard,
What do you mean by "the same xHCI controller"? dummy-hcd does not use
any xHCI controllers.
> below-software platform hang: printk, SysRq, NMI and both watchdogs
> die in the same instant, with no panic, no MCE, and empty pstore.
> 13 occurrences over 5 days, fully reproducible; the same workload
> with the pendulum slowed to 1000 us (this parameter) ran ~8 hours
> with zero hangs, and USB-cable sessions (identical gadget traffic,
> no BT co-existence) never hung.
>
> Nothing else in the driver's behaviour depends on the exact tick:
> the bandwidth model accounts per-frame budget regardless of how
> often frames are simulated, so a larger tick trades latency
> (1 ms added worst case at tick_us=1000) for interrupt-rate headroom.
Slowing down the timer means that the emulation will not act in real
time at the same speed as a physical device would. That's not
necessarily bad; it's just something for users to be aware of.
> Default keeps the current 125 us behaviour bit-for-bit.
>
> Signed-off-by: Mikhail Zubenko <misha.zubenko.01@yandex.ru>
> ---
> drivers/usb/gadget/udc/dummy_hcd.c | 8 +++++++-
> 1 file changed, 7 insertions(+), 1 deletion(-)
>
> diff --git a/drivers/usb/gadget/udc/dummy_hcd.c b/drivers/usb/gadget/udc/dummy_hcd.c
> index c0e40fa..f185b87 100644
> --- a/drivers/usb/gadget/udc/dummy_hcd.c
> +++ b/drivers/usb/gadget/udc/dummy_hcd.c
> @@ -51,7 +51,7 @@
> #define POWER_BUDGET 500 /* in mA; use 8 for low-power port testing */
> #define POWER_BUDGET_3 900 /* in mA */
>
> -#define DUMMY_TIMER_INT_NSECS 125000 /* 1 microframe */
> +#define DUMMY_TIMER_INT_NSECS ((u64)tick_us * NSEC_PER_USEC)
>
> static const char driver_name[] = "dummy_hcd";
> static const char driver_desc[] = "USB Host+Gadget Emulator";
> @@ -79,6 +79,12 @@ module_param_named(is_high_speed, mod_data.is_high_speed, bool, S_IRUGO);
> MODULE_PARM_DESC(is_high_speed, "true to simulate HighSpeed connection");
> module_param_named(num, mod_data.num, uint, S_IRUGO);
> MODULE_PARM_DESC(num, "number of emulated controllers");
> +
> +static unsigned int tick_us = 125;
> +module_param(tick_us, uint, 0644);
Why did you not follow the pattern of the other module parameters and
make tick_us a member of the dummy_hcd_module_parameters structure?
Also, there's no reason for the timer delay to be 125 us when
is_high_speed and is_super_speed are false. The default delay should be
1000 us in that case. More generally, it should depend on the speed of
the attached gadget. However, this is not a very important point;
probably nobody wants to emulate a full-speed (USB 1.1) host controller
these days -- but as long as the is_high_speed parameter exists, we
ought to take it into account.
Furthermore, the entire calculation of "total" (the data transfer limit)
at the start of dummy_timer() is wrong, because the value is calculated
for one frame, not one microframe. Any change to the timer rate ought
to fix this up as well. Maybe as a second patch.
> +MODULE_PARM_DESC(tick_us,
> + "enqueue-to-completion latency of the simulated controller, in microseconds (default 125, one high-speed microframe);"
> + " larger values slow the internal timer pendulum and reduce its interrupt-rate pressure on the host platform");
I don't like this description. It should be something more like "Length
in microseconds of an emulated microframe (default is 125, larger values
reduce the interrupt-rate pressure on the host platform)". No need to
mention latency or pendulums.
(In fact, it might be better to make this parameter a slow-down factor
rather than an absolute number. A percentage, perhaps -- 200 would mean
that an emulated microframe elapses every 250 real us instead of
every 125 us. But that's purely a matter of taste.)
Don't you want to do any checking on the value of the module parameter?
You certainly wouldn't want it to be set to 0! -- and probably not to
any value smaller than 125.
Also, since the value will be variable rather than constant, you should
pre-compute the delay length once and store the result for later use,
instead of asking the computer to figure out
ns_to_ktime(DUMMY_TIMER_INT_NSECS) over and over again. In fact, you
should get rid of the DUMMY_TIMER_INT_NSECS macro entirely.
Alan Stern
^ permalink raw reply [flat|nested] 13+ messages in thread
* Re: [PATCH v2] usb: gadget: dummy_hcd: add tick_us module parameter for timer-rate tuning
2026-08-23 17:15 [PATCH] usb: gadget: dummy_hcd: add tick_us module parameter for Mikhail Zubenko
2026-08-23 17:25 ` Greg Kroah-Hartman
2026-08-23 19:55 ` Alan Stern
@ 2026-08-24 8:29 ` Mikhail Zubenko
2026-08-24 8:29 ` Mikhail Zubenko
` (4 subsequent siblings)
7 siblings, 0 replies; 13+ messages in thread
From: Mikhail Zubenko @ 2026-08-24 8:29 UTC (permalink / raw)
To: linux-usb; +Cc: Greg Kroah-Hartman, Alan Stern
Hello Alan, Greg,
thank you for the review — all comments are addressed in v2 below.
On the mbox headers in v1's body: leftover from the prepared patch
file, my fault for not stripping them; v2 is sent with a fixed flow.
Point by point:
- "not a pendulum / the rate depends on traffic": reworded. The
timer rearms while any URBs are queued; against a permanently
polled HID interrupt endpoint the queue never drains, hence the
fixed ~8 kHz in that scenario. "Pendulum" is gone.
- "dummy-hcd does not use any xHCI controllers": clarified — the
Bluetooth session lives on the machine's real xHCI controller;
the co-existence is at the platform level, not inside dummy_hcd.
- tick_us is now a member of dummy_hcd_module_parameters
(module_param_cb with a setter that rejects values < 125).
- Speed-aware default: 125 us for high/super-speed emulation,
1000 us for full-speed (where the natural unit is the 1-ms frame).
- MODULE_PARM_DESC reworded to "Length in microseconds of an
emulated microframe" per your suggestion.
- Kept absolute microseconds rather than a percentage: with an
absolute value the real interval is directly readable from the
parameter (1000 = 1 ms), which was easier to reason about when
bisecting the platform hang. Happy to switch to a percentage
if you prefer it.
- The delay is pre-computed once per controller into a ktime_t
(timer_interval) at setup (with an explicit (u64) cast on the
tick_us * NSEC_PER_USEC product — 32-bit platforms would otherwise
overflow it); the DUMMY_TIMER_INT_NSECS macro is removed entirely. Consequently the parameter is 0444 (load-time
only): a runtime write would update mod_data.tick_us without
affecting live controllers, which would silently mislead.
- The per-frame vs per-microframe "total" budget computation in
dummy_timer() is indeed wrong for a lengthened microframe — I'll
follow up with a second patch fixing the bandwidth model once
this one settles.
Best regards,
Mikhail Zubenko
^ permalink raw reply [flat|nested] 13+ messages in thread
* Re: [PATCH v2] usb: gadget: dummy_hcd: add tick_us module parameter for timer-rate tuning
2026-08-23 17:15 [PATCH] usb: gadget: dummy_hcd: add tick_us module parameter for Mikhail Zubenko
` (2 preceding siblings ...)
2026-08-24 8:29 ` [PATCH v2] usb: gadget: dummy_hcd: add tick_us module parameter for timer-rate tuning Mikhail Zubenko
@ 2026-08-24 8:29 ` Mikhail Zubenko
2026-08-24 8:43 ` Greg Kroah-Hartman
2026-08-24 9:12 ` [PATCH v3] " Mikhail Zubenko
` (3 subsequent siblings)
7 siblings, 1 reply; 13+ messages in thread
From: Mikhail Zubenko @ 2026-08-24 8:29 UTC (permalink / raw)
To: linux-usb; +Cc: Greg Kroah-Hartman, Alan Stern
dummy_hcd services URB completions from an hrtimer callback that
rearms itself with a fixed 125 us delay (one high-speed microframe)
for as long as any URBs are queued. Against a permanently polled HID
interrupt endpoint the queue never drains, so the timer runs at ~8 kHz
regardless of actual traffic.
On timer-rate-sensitive platforms (observed on one consumer AM4 board
with a current BIOS and a stock kernel) this timer rate co-existing
with a live Bluetooth session on the machine's real xHCI controller
resulted in a hard, below-software platform hang: printk, SysRq, NMI
and both watchdogs died in the same instant, with no panic, no MCE,
and empty pstore. 13 occurrences over 5 days, reliably reproducible
with that configuration (hangs within 20 min to 2.5 h of uptime).
The same workload with the emulated microframe lengthened to 1000 us
(this parameter) ran ~8 hours with zero hangs, and USB-cable sessions
(identical gadget traffic, no Bluetooth co-existence) never hung.
Note that lengthening the emulated microframe makes the emulation run
slower than a physical device would; users of the parameter trade
that emulation fidelity for interrupt-rate headroom.
The per-frame bandwidth budget in dummy_timer() does not scale with
the emulated microframe length; making that accounting microframe-
correct is planned as a follow-up patch. Otherwise nothing in the
driver's behaviour depends on the emulated microframe length.
Default keeps the current 125 us behaviour bit-for-bit (and defaults
to 1000 us for full-speed emulation, where the natural unit is the
1-ms frame). Values below 125 are rejected.
Signed-off-by: Mikhail Zubenko <misha.zubenko.01@yandex.ru>
---
drivers/usb/gadget/udc/dummy_hcd.c | 47 ++++++++++++++++++++++++++++--
1 file changed, 44 insertions(+), 3 deletions(-)
diff --git a/drivers/usb/gadget/udc/dummy_hcd.c b/drivers/usb/gadget/udc/dummy_hcd.c
index c0e40fa..0884090 100644
--- a/drivers/usb/gadget/udc/dummy_hcd.c
+++ b/drivers/usb/gadget/udc/dummy_hcd.c
@@ -51,7 +51,6 @@
#define POWER_BUDGET 500 /* in mA; use 8 for low-power port testing */
#define POWER_BUDGET_3 900 /* in mA */
-#define DUMMY_TIMER_INT_NSECS 125000 /* 1 microframe */
static const char driver_name[] = "dummy_hcd";
static const char driver_desc[] = "USB Host+Gadget Emulator";
@@ -66,6 +65,31 @@ struct dummy_hcd_module_parameters {
bool is_super_speed;
bool is_high_speed;
unsigned int num;
+ unsigned int tick_us;
+};
+
+/*
+ * Length in microseconds of an emulated microframe. The default (125,
+ * one high-speed microframe) preserves the historical timer rate; larger
+ * values slow the emulated controller down and reduce its interrupt-rate
+ * pressure on the host platform. Values below 125 are rejected.
+ */
+static int tick_us_set(const char *val,
+ const struct kernel_param *kp)
+{
+ unsigned int v;
+ int ret = kstrtouint(val, 0, &v);
+
+ if (ret < 0 || v < 125) {
+ pr_err("dummy_hcd: tick_us must be >= 125\n");
+ return -EINVAL;
+ }
+ return param_set_uint(val, kp);
+}
+
+static const struct kernel_param_ops tick_us_ops = {
+ .set = tick_us_set,
+ .get = param_get_uint,
};
static struct dummy_hcd_module_parameters mod_data = {
@@ -79,6 +103,9 @@ module_param_named(is_high_speed, mod_data.is_high_speed, bool, S_IRUGO);
MODULE_PARM_DESC(is_high_speed, "true to simulate HighSpeed connection");
module_param_named(num, mod_data.num, uint, S_IRUGO);
MODULE_PARM_DESC(num, "number of emulated controllers");
+module_param_cb(tick_us, &tick_us_ops, &mod_data.tick_us, 0444);
+MODULE_PARM_DESC(tick_us,
+ "Length in microseconds of an emulated microframe (default 125 for high/super-speed emulation, 1000 for full-speed); larger values reduce the interrupt-rate pressure on the host platform");
/*-------------------------------------------------------------------------*/
/* gadget side driver data structures */
@@ -244,6 +271,7 @@ struct dummy_hcd {
struct dummy *dum;
enum dummy_rh_state rh_state;
struct hrtimer timer;
+ ktime_t timer_interval; /* emulated microframe length */
u32 port_status;
u32 old_status;
unsigned long re_timeout;
@@ -1329,7 +1357,7 @@ static int dummy_urb_enqueue(
/* kick the scheduler, it'll do the rest */
if (!dum_hcd->timer_pending) {
dum_hcd->timer_pending = 1;
- hrtimer_start(&dum_hcd->timer, ns_to_ktime(DUMMY_TIMER_INT_NSECS),
+ hrtimer_start(&dum_hcd->timer, dum_hcd->timer_interval,
HRTIMER_MODE_REL_SOFT);
}
@@ -2029,7 +2057,7 @@ return_urb:
dum_hcd->rh_state == DUMMY_RH_RUNNING) {
/* want a 1 msec delay here */
dum_hcd->timer_pending = 1;
- hrtimer_start(&dum_hcd->timer, ns_to_ktime(DUMMY_TIMER_INT_NSECS),
+ hrtimer_start(&dum_hcd->timer, dum_hcd->timer_interval,
HRTIMER_MODE_REL_SOFT);
}
@@ -2509,6 +2537,7 @@ static DEVICE_ATTR_RO(urbs);
static int dummy_start_ss(struct dummy_hcd *dum_hcd)
{
hrtimer_setup(&dum_hcd->timer, dummy_timer, CLOCK_MONOTONIC, HRTIMER_MODE_REL_SOFT);
+ dum_hcd->timer_interval = ns_to_ktime((u64)mod_data.tick_us * NSEC_PER_USEC);
dum_hcd->rh_state = DUMMY_RH_RUNNING;
dum_hcd->stream_en_ep = 0;
INIT_LIST_HEAD(&dum_hcd->urbp_list);
@@ -2538,6 +2567,7 @@ static int dummy_start(struct usb_hcd *hcd)
spin_lock_init(&dum_hcd->dum->lock);
hrtimer_setup(&dum_hcd->timer, dummy_timer, CLOCK_MONOTONIC, HRTIMER_MODE_REL_SOFT);
+ dum_hcd->timer_interval = ns_to_ktime((u64)mod_data.tick_us * NSEC_PER_USEC);
dum_hcd->rh_state = DUMMY_RH_RUNNING;
INIT_LIST_HEAD(&dum_hcd->urbp_list);
@@ -2828,6 +2858,17 @@ static int __init dummy_hcd_init(void)
return -EINVAL;
}
+ /*
+ * The emulated microframe length defaults to one high-speed
+ * microframe (125 us). When neither is_high_speed nor
+ * is_super_speed is set the emulation is full-speed, where the
+ * natural scheduling unit is the 1-ms frame, so default to
+ * 1000 us instead.
+ */
+ if (!mod_data.tick_us)
+ mod_data.tick_us = (mod_data.is_super_speed ||
+ mod_data.is_high_speed) ? 125 : 1000;
+
for (i = 0; i < mod_data.num; i++) {
the_hcd_pdev[i] = platform_device_alloc(driver_name, i);
if (!the_hcd_pdev[i]) {
--
2.43.0
^ permalink raw reply related [flat|nested] 13+ messages in thread
* Re: [PATCH v2] usb: gadget: dummy_hcd: add tick_us module parameter for timer-rate tuning
2026-08-24 8:29 ` Mikhail Zubenko
@ 2026-08-24 8:43 ` Greg Kroah-Hartman
0 siblings, 0 replies; 13+ messages in thread
From: Greg Kroah-Hartman @ 2026-08-24 8:43 UTC (permalink / raw)
To: Mikhail Zubenko; +Cc: linux-usb, Alan Stern
On Mon, Aug 24, 2026 at 08:29:43AM -0000, Mikhail Zubenko wrote:
> dummy_hcd services URB completions from an hrtimer callback that
> rearms itself with a fixed 125 us delay (one high-speed microframe)
> for as long as any URBs are queued. Against a permanently polled HID
> interrupt endpoint the queue never drains, so the timer runs at ~8 kHz
> regardless of actual traffic.
>
> On timer-rate-sensitive platforms (observed on one consumer AM4 board
> with a current BIOS and a stock kernel) this timer rate co-existing
> with a live Bluetooth session on the machine's real xHCI controller
> resulted in a hard, below-software platform hang: printk, SysRq, NMI
> and both watchdogs died in the same instant, with no panic, no MCE,
> and empty pstore. 13 occurrences over 5 days, reliably reproducible
> with that configuration (hangs within 20 min to 2.5 h of uptime).
> The same workload with the emulated microframe lengthened to 1000 us
> (this parameter) ran ~8 hours with zero hangs, and USB-cable sessions
> (identical gadget traffic, no Bluetooth co-existence) never hung.
>
> Note that lengthening the emulated microframe makes the emulation run
> slower than a physical device would; users of the parameter trade
> that emulation fidelity for interrupt-rate headroom.
>
> The per-frame bandwidth budget in dummy_timer() does not scale with
> the emulated microframe length; making that accounting microframe-
> correct is planned as a follow-up patch. Otherwise nothing in the
> driver's behaviour depends on the emulated microframe length.
>
> Default keeps the current 125 us behaviour bit-for-bit (and defaults
> to 1000 us for full-speed emulation, where the natural unit is the
> 1-ms frame). Values below 125 are rejected.
>
> Signed-off-by: Mikhail Zubenko <misha.zubenko.01@yandex.ru>
> ---
> drivers/usb/gadget/udc/dummy_hcd.c | 47 ++++++++++++++++++++++++++++--
> 1 file changed, 44 insertions(+), 3 deletions(-)
>
> diff --git a/drivers/usb/gadget/udc/dummy_hcd.c b/drivers/usb/gadget/udc/dummy_hcd.c
> index c0e40fa..0884090 100644
> --- a/drivers/usb/gadget/udc/dummy_hcd.c
> +++ b/drivers/usb/gadget/udc/dummy_hcd.c
> @@ -51,7 +51,6 @@
> #define POWER_BUDGET 500 /* in mA; use 8 for low-power port testing */
> #define POWER_BUDGET_3 900 /* in mA */
>
> -#define DUMMY_TIMER_INT_NSECS 125000 /* 1 microframe */
>
> static const char driver_name[] = "dummy_hcd";
> static const char driver_desc[] = "USB Host+Gadget Emulator";
> @@ -66,6 +65,31 @@ struct dummy_hcd_module_parameters {
> bool is_super_speed;
> bool is_high_speed;
> unsigned int num;
> + unsigned int tick_us;
> +};
> +
> +/*
> + * Length in microseconds of an emulated microframe. The default (125,
> + * one high-speed microframe) preserves the historical timer rate; larger
> + * values slow the emulated controller down and reduce its interrupt-rate
> + * pressure on the host platform. Values below 125 are rejected.
> + */
> +static int tick_us_set(const char *val,
> + const struct kernel_param *kp)
> +{
> + unsigned int v;
> + int ret = kstrtouint(val, 0, &v);
> +
> + if (ret < 0 || v < 125) {
> + pr_err("dummy_hcd: tick_us must be >= 125\n");
> + return -EINVAL;
> + }
> + return param_set_uint(val, kp);
> +}
> +
> +static const struct kernel_param_ops tick_us_ops = {
> + .set = tick_us_set,
> + .get = param_get_uint,
> };
>
> static struct dummy_hcd_module_parameters mod_data = {
> @@ -79,6 +103,9 @@ module_param_named(is_high_speed, mod_data.is_high_speed, bool, S_IRUGO);
> MODULE_PARM_DESC(is_high_speed, "true to simulate HighSpeed connection");
> module_param_named(num, mod_data.num, uint, S_IRUGO);
> MODULE_PARM_DESC(num, "number of emulated controllers");
> +module_param_cb(tick_us, &tick_us_ops, &mod_data.tick_us, 0444);
> +MODULE_PARM_DESC(tick_us,
> + "Length in microseconds of an emulated microframe (default 125 for high/super-speed emulation, 1000 for full-speed); larger values reduce the interrupt-rate pressure on the host platform");
> /*-------------------------------------------------------------------------*/
>
> /* gadget side driver data structures */
> @@ -244,6 +271,7 @@ struct dummy_hcd {
> struct dummy *dum;
> enum dummy_rh_state rh_state;
> struct hrtimer timer;
> + ktime_t timer_interval; /* emulated microframe length */
> u32 port_status;
> u32 old_status;
> unsigned long re_timeout;
> @@ -1329,7 +1357,7 @@ static int dummy_urb_enqueue(
> /* kick the scheduler, it'll do the rest */
> if (!dum_hcd->timer_pending) {
> dum_hcd->timer_pending = 1;
> - hrtimer_start(&dum_hcd->timer, ns_to_ktime(DUMMY_TIMER_INT_NSECS),
> + hrtimer_start(&dum_hcd->timer, dum_hcd->timer_interval,
> HRTIMER_MODE_REL_SOFT);
> }
>
> @@ -2029,7 +2057,7 @@ return_urb:
> dum_hcd->rh_state == DUMMY_RH_RUNNING) {
> /* want a 1 msec delay here */
> dum_hcd->timer_pending = 1;
> - hrtimer_start(&dum_hcd->timer, ns_to_ktime(DUMMY_TIMER_INT_NSECS),
> + hrtimer_start(&dum_hcd->timer, dum_hcd->timer_interval,
> HRTIMER_MODE_REL_SOFT);
> }
>
> @@ -2509,6 +2537,7 @@ static DEVICE_ATTR_RO(urbs);
> static int dummy_start_ss(struct dummy_hcd *dum_hcd)
> {
> hrtimer_setup(&dum_hcd->timer, dummy_timer, CLOCK_MONOTONIC, HRTIMER_MODE_REL_SOFT);
> + dum_hcd->timer_interval = ns_to_ktime((u64)mod_data.tick_us * NSEC_PER_USEC);
> dum_hcd->rh_state = DUMMY_RH_RUNNING;
> dum_hcd->stream_en_ep = 0;
> INIT_LIST_HEAD(&dum_hcd->urbp_list);
> @@ -2538,6 +2567,7 @@ static int dummy_start(struct usb_hcd *hcd)
>
> spin_lock_init(&dum_hcd->dum->lock);
> hrtimer_setup(&dum_hcd->timer, dummy_timer, CLOCK_MONOTONIC, HRTIMER_MODE_REL_SOFT);
> + dum_hcd->timer_interval = ns_to_ktime((u64)mod_data.tick_us * NSEC_PER_USEC);
> dum_hcd->rh_state = DUMMY_RH_RUNNING;
>
> INIT_LIST_HEAD(&dum_hcd->urbp_list);
> @@ -2828,6 +2858,17 @@ static int __init dummy_hcd_init(void)
> return -EINVAL;
> }
>
> + /*
> + * The emulated microframe length defaults to one high-speed
> + * microframe (125 us). When neither is_high_speed nor
> + * is_super_speed is set the emulation is full-speed, where the
> + * natural scheduling unit is the 1-ms frame, so default to
> + * 1000 us instead.
> + */
> + if (!mod_data.tick_us)
> + mod_data.tick_us = (mod_data.is_super_speed ||
> + mod_data.is_high_speed) ? 125 : 1000;
> +
> for (i = 0; i < mod_data.num; i++) {
> the_hcd_pdev[i] = platform_device_alloc(driver_name, i);
> if (!the_hcd_pdev[i]) {
> --
> 2.43.0
>
>
Hi,
This is the friendly patch-bot of Greg Kroah-Hartman. You have sent him
a patch that has triggered this response. He used to manually respond
to these common problems, but in order to save his sanity (he kept
writing the same thing over and over, yet to different people), I was
created. Hopefully you will not take offence and will fix the problem
in your patch and resubmit it so that it can be accepted into the Linux
kernel tree.
You are receiving this message because of the following common error(s)
as indicated below:
- This looks like a new version of a previously submitted patch, but you
did not list below the --- line any changes from the previous version.
Please read the section entitled "The canonical patch format" in the
kernel file, Documentation/process/submitting-patches.rst for what
needs to be done here to properly describe this.
If you wish to discuss this problem further, or you have questions about
how to resolve this issue, please feel free to respond to this email and
Greg will reply once he has dug out from the pending patches received
from other developers.
thanks,
greg k-h's patch email bot
^ permalink raw reply [flat|nested] 13+ messages in thread
* [PATCH v3] usb: gadget: dummy_hcd: add tick_us module parameter for timer-rate tuning
2026-08-23 17:15 [PATCH] usb: gadget: dummy_hcd: add tick_us module parameter for Mikhail Zubenko
` (3 preceding siblings ...)
2026-08-24 8:29 ` Mikhail Zubenko
@ 2026-08-24 9:12 ` Mikhail Zubenko
2026-08-24 9:40 ` Greg Kroah-Hartman
2026-08-24 10:42 ` Mikhail Zubenko
` (2 subsequent siblings)
7 siblings, 1 reply; 13+ messages in thread
From: Mikhail Zubenko @ 2026-08-24 9:12 UTC (permalink / raw)
To: linux-usb; +Cc: Greg Kroah-Hartman, Alan Stern
dummy_hcd services URB completions from an hrtimer callback that
rearms itself with a fixed 125 us delay (one high-speed microframe)
for as long as any URBs are queued. Against a permanently polled HID
interrupt endpoint the queue never drains, so the timer runs at ~8 kHz
regardless of actual traffic.
On timer-rate-sensitive platforms (observed on one consumer AM4 board
with a current BIOS and a stock kernel) this timer rate co-existing
with a live Bluetooth session on the machine's real xHCI controller
resulted in a hard, below-software platform hang: printk, SysRq, NMI
and both watchdogs died in the same instant, with no panic, no MCE,
and empty pstore. 13 occurrences over 5 days, reliably reproducible
with that configuration (hangs within 20 min to 2.5 h of uptime).
The same workload with the emulated microframe lengthened to 1000 us
(this parameter) ran ~8 hours with zero hangs, and USB-cable sessions
(identical gadget traffic, no Bluetooth co-existence) never hung.
Note that lengthening the emulated microframe makes the emulation run
slower than a physical device would; users of the parameter trade
that emulation fidelity for interrupt-rate headroom.
The per-frame bandwidth budget in dummy_timer() does not scale with
the emulated microframe length; making that accounting microframe-
correct is planned as a follow-up patch. Otherwise nothing in the
driver's behaviour depends on the emulated microframe length.
Default keeps the current 125 us behaviour bit-for-bit (and defaults
to 1000 us for full-speed emulation, where the natural unit is the
1-ms frame). Values below 125 are rejected.
Signed-off-by: Mikhail Zubenko <misha.zubenko.01@yandex.ru>
Changes in v2 (addressing Alan Stern's review):
- reword the description: the timer rearms while URBs are queued, not
an unconditional "pendulum"; drop the word entirely
- clarify the xHCI wording: the Bluetooth session lives on the
machine's real xHCI controller (platform-level co-existence)
- move tick_us into dummy_hcd_module_parameters with a custom setter
(module_param_cb) that rejects values < 125
- speed-aware default: 125 us for high/super-speed, 1000 us for
full-speed emulation
- reword MODULE_PARM_DESC per review ("length in microseconds of an
emulated microframe")
- pre-compute the delay into a ktime_t (timer_interval) at setup;
remove the DUMMY_TIMER_INT_NSECS macro; explicit (u64) cast so the
tick_us * NSEC_PER_USEC product does not overflow on 32-bit
- parameter is 0444 (load-time only): a runtime write would not
affect live controllers
- note the emulation-fidelity tradeoff and the per-frame budget
follow-up in the commit message
---
drivers/usb/gadget/udc/dummy_hcd.c | 47 ++++++++++++++++++++++++++++--
1 file changed, 44 insertions(+), 3 deletions(-)
diff --git a/drivers/usb/gadget/udc/dummy_hcd.c b/drivers/usb/gadget/udc/dummy_hcd.c
index c0e40fa..0884090 100644
--- a/drivers/usb/gadget/udc/dummy_hcd.c
+++ b/drivers/usb/gadget/udc/dummy_hcd.c
@@ -51,7 +51,6 @@
#define POWER_BUDGET 500 /* in mA; use 8 for low-power port testing */
#define POWER_BUDGET_3 900 /* in mA */
-#define DUMMY_TIMER_INT_NSECS 125000 /* 1 microframe */
static const char driver_name[] = "dummy_hcd";
static const char driver_desc[] = "USB Host+Gadget Emulator";
@@ -66,6 +65,31 @@ struct dummy_hcd_module_parameters {
bool is_super_speed;
bool is_high_speed;
unsigned int num;
+ unsigned int tick_us;
+};
+
+/*
+ * Length in microseconds of an emulated microframe. The default (125,
+ * one high-speed microframe) preserves the historical timer rate; larger
+ * values slow the emulated controller down and reduce its interrupt-rate
+ * pressure on the host platform. Values below 125 are rejected.
+ */
+static int tick_us_set(const char *val,
+ const struct kernel_param *kp)
+{
+ unsigned int v;
+ int ret = kstrtouint(val, 0, &v);
+
+ if (ret < 0 || v < 125) {
+ pr_err("dummy_hcd: tick_us must be >= 125\n");
+ return -EINVAL;
+ }
+ return param_set_uint(val, kp);
+}
+
+static const struct kernel_param_ops tick_us_ops = {
+ .set = tick_us_set,
+ .get = param_get_uint,
};
static struct dummy_hcd_module_parameters mod_data = {
@@ -79,6 +103,9 @@ module_param_named(is_high_speed, mod_data.is_high_speed, bool, S_IRUGO);
MODULE_PARM_DESC(is_high_speed, "true to simulate HighSpeed connection");
module_param_named(num, mod_data.num, uint, S_IRUGO);
MODULE_PARM_DESC(num, "number of emulated controllers");
+module_param_cb(tick_us, &tick_us_ops, &mod_data.tick_us, 0444);
+MODULE_PARM_DESC(tick_us,
+ "Length in microseconds of an emulated microframe (default 125 for high/super-speed emulation, 1000 for full-speed); larger values reduce the interrupt-rate pressure on the host platform");
/*-------------------------------------------------------------------------*/
/* gadget side driver data structures */
@@ -244,6 +271,7 @@ struct dummy_hcd {
struct dummy *dum;
enum dummy_rh_state rh_state;
struct hrtimer timer;
+ ktime_t timer_interval; /* emulated microframe length */
u32 port_status;
u32 old_status;
unsigned long re_timeout;
@@ -1329,7 +1357,7 @@ static int dummy_urb_enqueue(
/* kick the scheduler, it'll do the rest */
if (!dum_hcd->timer_pending) {
dum_hcd->timer_pending = 1;
- hrtimer_start(&dum_hcd->timer, ns_to_ktime(DUMMY_TIMER_INT_NSECS),
+ hrtimer_start(&dum_hcd->timer, dum_hcd->timer_interval,
HRTIMER_MODE_REL_SOFT);
}
@@ -2029,7 +2057,7 @@ return_urb:
dum_hcd->rh_state == DUMMY_RH_RUNNING) {
/* want a 1 msec delay here */
dum_hcd->timer_pending = 1;
- hrtimer_start(&dum_hcd->timer, ns_to_ktime(DUMMY_TIMER_INT_NSECS),
+ hrtimer_start(&dum_hcd->timer, dum_hcd->timer_interval,
HRTIMER_MODE_REL_SOFT);
}
@@ -2509,6 +2537,7 @@ static DEVICE_ATTR_RO(urbs);
static int dummy_start_ss(struct dummy_hcd *dum_hcd)
{
hrtimer_setup(&dum_hcd->timer, dummy_timer, CLOCK_MONOTONIC, HRTIMER_MODE_REL_SOFT);
+ dum_hcd->timer_interval = ns_to_ktime((u64)mod_data.tick_us * NSEC_PER_USEC);
dum_hcd->rh_state = DUMMY_RH_RUNNING;
dum_hcd->stream_en_ep = 0;
INIT_LIST_HEAD(&dum_hcd->urbp_list);
@@ -2538,6 +2567,7 @@ static int dummy_start(struct usb_hcd *hcd)
spin_lock_init(&dum_hcd->dum->lock);
hrtimer_setup(&dum_hcd->timer, dummy_timer, CLOCK_MONOTONIC, HRTIMER_MODE_REL_SOFT);
+ dum_hcd->timer_interval = ns_to_ktime((u64)mod_data.tick_us * NSEC_PER_USEC);
dum_hcd->rh_state = DUMMY_RH_RUNNING;
INIT_LIST_HEAD(&dum_hcd->urbp_list);
@@ -2828,6 +2858,17 @@ static int __init dummy_hcd_init(void)
return -EINVAL;
}
+ /*
+ * The emulated microframe length defaults to one high-speed
+ * microframe (125 us). When neither is_high_speed nor
+ * is_super_speed is set the emulation is full-speed, where the
+ * natural scheduling unit is the 1-ms frame, so default to
+ * 1000 us instead.
+ */
+ if (!mod_data.tick_us)
+ mod_data.tick_us = (mod_data.is_super_speed ||
+ mod_data.is_high_speed) ? 125 : 1000;
+
for (i = 0; i < mod_data.num; i++) {
the_hcd_pdev[i] = platform_device_alloc(driver_name, i);
if (!the_hcd_pdev[i]) {
--
2.43.0
^ permalink raw reply related [flat|nested] 13+ messages in thread
* Re: [PATCH v3] usb: gadget: dummy_hcd: add tick_us module parameter for timer-rate tuning
2026-08-24 9:12 ` [PATCH v3] " Mikhail Zubenko
@ 2026-08-24 9:40 ` Greg Kroah-Hartman
0 siblings, 0 replies; 13+ messages in thread
From: Greg Kroah-Hartman @ 2026-08-24 9:40 UTC (permalink / raw)
To: Mikhail Zubenko; +Cc: linux-usb, Alan Stern
On Mon, Aug 24, 2026 at 09:12:22AM -0000, Mikhail Zubenko wrote:
> dummy_hcd services URB completions from an hrtimer callback that
> rearms itself with a fixed 125 us delay (one high-speed microframe)
> for as long as any URBs are queued. Against a permanently polled HID
> interrupt endpoint the queue never drains, so the timer runs at ~8 kHz
> regardless of actual traffic.
>
> On timer-rate-sensitive platforms (observed on one consumer AM4 board
> with a current BIOS and a stock kernel) this timer rate co-existing
> with a live Bluetooth session on the machine's real xHCI controller
> resulted in a hard, below-software platform hang: printk, SysRq, NMI
> and both watchdogs died in the same instant, with no panic, no MCE,
> and empty pstore. 13 occurrences over 5 days, reliably reproducible
> with that configuration (hangs within 20 min to 2.5 h of uptime).
> The same workload with the emulated microframe lengthened to 1000 us
> (this parameter) ran ~8 hours with zero hangs, and USB-cable sessions
> (identical gadget traffic, no Bluetooth co-existence) never hung.
>
> Note that lengthening the emulated microframe makes the emulation run
> slower than a physical device would; users of the parameter trade
> that emulation fidelity for interrupt-rate headroom.
>
> The per-frame bandwidth budget in dummy_timer() does not scale with
> the emulated microframe length; making that accounting microframe-
> correct is planned as a follow-up patch. Otherwise nothing in the
> driver's behaviour depends on the emulated microframe length.
>
> Default keeps the current 125 us behaviour bit-for-bit (and defaults
> to 1000 us for full-speed emulation, where the natural unit is the
> 1-ms frame). Values below 125 are rejected.
>
> Signed-off-by: Mikhail Zubenko <misha.zubenko.01@yandex.ru>
>
> Changes in v2 (addressing Alan Stern's review):
> - reword the description: the timer rearms while URBs are queued, not
> an unconditional "pendulum"; drop the word entirely
> - clarify the xHCI wording: the Bluetooth session lives on the
> machine's real xHCI controller (platform-level co-existence)
> - move tick_us into dummy_hcd_module_parameters with a custom setter
> (module_param_cb) that rejects values < 125
> - speed-aware default: 125 us for high/super-speed, 1000 us for
> full-speed emulation
> - reword MODULE_PARM_DESC per review ("length in microseconds of an
> emulated microframe")
> - pre-compute the delay into a ktime_t (timer_interval) at setup;
> remove the DUMMY_TIMER_INT_NSECS macro; explicit (u64) cast so the
> tick_us * NSEC_PER_USEC product does not overflow on 32-bit
> - parameter is 0444 (load-time only): a runtime write would not
> affect live controllers
> - note the emulation-fidelity tradeoff and the per-frame budget
> follow-up in the commit message
As per the documentation, the changes go below the --- line, right?
thanks,
greg k-h
^ permalink raw reply [flat|nested] 13+ messages in thread
* Re: [PATCH v3] usb: gadget: dummy_hcd: add tick_us module parameter for timer-rate tuning
2026-08-23 17:15 [PATCH] usb: gadget: dummy_hcd: add tick_us module parameter for Mikhail Zubenko
` (4 preceding siblings ...)
2026-08-24 9:12 ` [PATCH v3] " Mikhail Zubenko
@ 2026-08-24 10:42 ` Mikhail Zubenko
2026-08-24 10:42 ` [PATCH v4] " Mikhail Zubenko
2026-08-24 15:54 ` [PATCH v5] " Mikhail Zubenko
7 siblings, 0 replies; 13+ messages in thread
From: Mikhail Zubenko @ 2026-08-24 10:42 UTC (permalink / raw)
To: linux-usb; +Cc: Greg Kroah-Hartman, Alan Stern
Hi Greg,
yes - my v3 had the changelog above the --- marker. v4 moves it
below, where it gets stripped automatically. Code unchanged.
thanks,
Mikhail
^ permalink raw reply [flat|nested] 13+ messages in thread
* [PATCH v4] usb: gadget: dummy_hcd: add tick_us module parameter for timer-rate tuning
2026-08-23 17:15 [PATCH] usb: gadget: dummy_hcd: add tick_us module parameter for Mikhail Zubenko
` (5 preceding siblings ...)
2026-08-24 10:42 ` Mikhail Zubenko
@ 2026-08-24 10:42 ` Mikhail Zubenko
2026-08-24 14:27 ` Alan Stern
2026-08-24 15:54 ` [PATCH v5] " Mikhail Zubenko
7 siblings, 1 reply; 13+ messages in thread
From: Mikhail Zubenko @ 2026-08-24 10:42 UTC (permalink / raw)
To: linux-usb; +Cc: Greg Kroah-Hartman, Alan Stern
dummy_hcd services URB completions from an hrtimer callback that
rearms itself with a fixed 125 us delay (one high-speed microframe)
for as long as any URBs are queued. Against a permanently polled HID
interrupt endpoint the queue never drains, so the timer runs at ~8 kHz
regardless of actual traffic.
On timer-rate-sensitive platforms (observed on one consumer AM4 board
with a current BIOS and a stock kernel) this timer rate co-existing
with a live Bluetooth session on the machine's real xHCI controller
resulted in a hard, below-software platform hang: printk, SysRq, NMI
and both watchdogs died in the same instant, with no panic, no MCE,
and empty pstore. 13 occurrences over 5 days, reliably reproducible
with that configuration (hangs within 20 min to 2.5 h of uptime).
The same workload with the emulated microframe lengthened to 1000 us
(this parameter) ran ~8 hours with zero hangs, and USB-cable sessions
(identical gadget traffic, no Bluetooth co-existence) never hung.
Note that lengthening the emulated microframe makes the emulation run
slower than a physical device would; users of the parameter trade
that emulation fidelity for interrupt-rate headroom.
The per-frame bandwidth budget in dummy_timer() does not scale with
the emulated microframe length; making that accounting microframe-
correct is planned as a follow-up patch. Otherwise nothing in the
driver's behaviour depends on the emulated microframe length.
Default keeps the current 125 us behaviour bit-for-bit (and defaults
to 1000 us for full-speed emulation, where the natural unit is the
1-ms frame). Values below 125 are rejected.
Signed-off-by: Mikhail Zubenko <misha.zubenko.01@yandex.ru>
---
Changes in v2 (addressing Alan Stern's review):
- reword the description: the timer rearms while URBs are queued, not
an unconditional "pendulum"; drop the word entirely
- clarify the xHCI wording: the Bluetooth session lives on the
machine's real xHCI controller (platform-level co-existence)
- move tick_us into dummy_hcd_module_parameters with a custom setter
(module_param_cb) that rejects values < 125
- speed-aware default: 125 us for high/super-speed, 1000 us for
full-speed emulation
- reword MODULE_PARM_DESC per review ("length in microseconds of an
emulated microframe")
- pre-compute the delay into a ktime_t (timer_interval) at setup;
remove the DUMMY_TIMER_INT_NSECS macro; explicit (u64) cast so the
tick_us * NSEC_PER_USEC product does not overflow on 32-bit
- parameter is 0444 (load-time only): a runtime write would not
affect live controllers
- note the emulation-fidelity tradeoff and the per-frame budget
follow-up in the commit message
drivers/usb/gadget/udc/dummy_hcd.c | 47 ++++++++++++++++++++++++++++--
1 file changed, 44 insertions(+), 3 deletions(-)
diff --git a/drivers/usb/gadget/udc/dummy_hcd.c b/drivers/usb/gadget/udc/dummy_hcd.c
index c0e40fa..0884090 100644
--- a/drivers/usb/gadget/udc/dummy_hcd.c
+++ b/drivers/usb/gadget/udc/dummy_hcd.c
@@ -51,7 +51,6 @@
#define POWER_BUDGET 500 /* in mA; use 8 for low-power port testing */
#define POWER_BUDGET_3 900 /* in mA */
-#define DUMMY_TIMER_INT_NSECS 125000 /* 1 microframe */
static const char driver_name[] = "dummy_hcd";
static const char driver_desc[] = "USB Host+Gadget Emulator";
@@ -66,6 +65,31 @@ struct dummy_hcd_module_parameters {
bool is_super_speed;
bool is_high_speed;
unsigned int num;
+ unsigned int tick_us;
+};
+
+/*
+ * Length in microseconds of an emulated microframe. The default (125,
+ * one high-speed microframe) preserves the historical timer rate; larger
+ * values slow the emulated controller down and reduce its interrupt-rate
+ * pressure on the host platform. Values below 125 are rejected.
+ */
+static int tick_us_set(const char *val,
+ const struct kernel_param *kp)
+{
+ unsigned int v;
+ int ret = kstrtouint(val, 0, &v);
+
+ if (ret < 0 || v < 125) {
+ pr_err("dummy_hcd: tick_us must be >= 125\n");
+ return -EINVAL;
+ }
+ return param_set_uint(val, kp);
+}
+
+static const struct kernel_param_ops tick_us_ops = {
+ .set = tick_us_set,
+ .get = param_get_uint,
};
static struct dummy_hcd_module_parameters mod_data = {
@@ -79,6 +103,9 @@ module_param_named(is_high_speed, mod_data.is_high_speed, bool, S_IRUGO);
MODULE_PARM_DESC(is_high_speed, "true to simulate HighSpeed connection");
module_param_named(num, mod_data.num, uint, S_IRUGO);
MODULE_PARM_DESC(num, "number of emulated controllers");
+module_param_cb(tick_us, &tick_us_ops, &mod_data.tick_us, 0444);
+MODULE_PARM_DESC(tick_us,
+ "Length in microseconds of an emulated microframe (default 125 for high/super-speed emulation, 1000 for full-speed); larger values reduce the interrupt-rate pressure on the host platform");
/*-------------------------------------------------------------------------*/
/* gadget side driver data structures */
@@ -244,6 +271,7 @@ struct dummy_hcd {
struct dummy *dum;
enum dummy_rh_state rh_state;
struct hrtimer timer;
+ ktime_t timer_interval; /* emulated microframe length */
u32 port_status;
u32 old_status;
unsigned long re_timeout;
@@ -1329,7 +1357,7 @@ static int dummy_urb_enqueue(
/* kick the scheduler, it'll do the rest */
if (!dum_hcd->timer_pending) {
dum_hcd->timer_pending = 1;
- hrtimer_start(&dum_hcd->timer, ns_to_ktime(DUMMY_TIMER_INT_NSECS),
+ hrtimer_start(&dum_hcd->timer, dum_hcd->timer_interval,
HRTIMER_MODE_REL_SOFT);
}
@@ -2029,7 +2057,7 @@ return_urb:
dum_hcd->rh_state == DUMMY_RH_RUNNING) {
/* want a 1 msec delay here */
dum_hcd->timer_pending = 1;
- hrtimer_start(&dum_hcd->timer, ns_to_ktime(DUMMY_TIMER_INT_NSECS),
+ hrtimer_start(&dum_hcd->timer, dum_hcd->timer_interval,
HRTIMER_MODE_REL_SOFT);
}
@@ -2509,6 +2537,7 @@ static DEVICE_ATTR_RO(urbs);
static int dummy_start_ss(struct dummy_hcd *dum_hcd)
{
hrtimer_setup(&dum_hcd->timer, dummy_timer, CLOCK_MONOTONIC, HRTIMER_MODE_REL_SOFT);
+ dum_hcd->timer_interval = ns_to_ktime((u64)mod_data.tick_us * NSEC_PER_USEC);
dum_hcd->rh_state = DUMMY_RH_RUNNING;
dum_hcd->stream_en_ep = 0;
INIT_LIST_HEAD(&dum_hcd->urbp_list);
@@ -2538,6 +2567,7 @@ static int dummy_start(struct usb_hcd *hcd)
spin_lock_init(&dum_hcd->dum->lock);
hrtimer_setup(&dum_hcd->timer, dummy_timer, CLOCK_MONOTONIC, HRTIMER_MODE_REL_SOFT);
+ dum_hcd->timer_interval = ns_to_ktime((u64)mod_data.tick_us * NSEC_PER_USEC);
dum_hcd->rh_state = DUMMY_RH_RUNNING;
INIT_LIST_HEAD(&dum_hcd->urbp_list);
@@ -2828,6 +2858,17 @@ static int __init dummy_hcd_init(void)
return -EINVAL;
}
+ /*
+ * The emulated microframe length defaults to one high-speed
+ * microframe (125 us). When neither is_high_speed nor
+ * is_super_speed is set the emulation is full-speed, where the
+ * natural scheduling unit is the 1-ms frame, so default to
+ * 1000 us instead.
+ */
+ if (!mod_data.tick_us)
+ mod_data.tick_us = (mod_data.is_super_speed ||
+ mod_data.is_high_speed) ? 125 : 1000;
+
for (i = 0; i < mod_data.num; i++) {
the_hcd_pdev[i] = platform_device_alloc(driver_name, i);
if (!the_hcd_pdev[i]) {
--
2.43.0
^ permalink raw reply related [flat|nested] 13+ messages in thread
* Re: [PATCH v4] usb: gadget: dummy_hcd: add tick_us module parameter for timer-rate tuning
2026-08-24 10:42 ` [PATCH v4] " Mikhail Zubenko
@ 2026-08-24 14:27 ` Alan Stern
0 siblings, 0 replies; 13+ messages in thread
From: Alan Stern @ 2026-08-24 14:27 UTC (permalink / raw)
To: Mikhail Zubenko; +Cc: linux-usb, Greg Kroah-Hartman
On Mon, Aug 24, 2026 at 10:42:38AM -0000, Mikhail Zubenko wrote:
> dummy_hcd services URB completions from an hrtimer callback that
> rearms itself with a fixed 125 us delay (one high-speed microframe)
> for as long as any URBs are queued. Against a permanently polled HID
> interrupt endpoint the queue never drains, so the timer runs at ~8 kHz
> regardless of actual traffic.
>
> On timer-rate-sensitive platforms (observed on one consumer AM4 board
> with a current BIOS and a stock kernel) this timer rate co-existing
> with a live Bluetooth session on the machine's real xHCI controller
> resulted in a hard, below-software platform hang: printk, SysRq, NMI
> and both watchdogs died in the same instant, with no panic, no MCE,
> and empty pstore. 13 occurrences over 5 days, reliably reproducible
> with that configuration (hangs within 20 min to 2.5 h of uptime).
> The same workload with the emulated microframe lengthened to 1000 us
> (this parameter) ran ~8 hours with zero hangs, and USB-cable sessions
> (identical gadget traffic, no Bluetooth co-existence) never hung.
>
> Note that lengthening the emulated microframe makes the emulation run
> slower than a physical device would; users of the parameter trade
> that emulation fidelity for interrupt-rate headroom.
>
> The per-frame bandwidth budget in dummy_timer() does not scale with
> the emulated microframe length; making that accounting microframe-
> correct is planned as a follow-up patch. Otherwise nothing in the
> driver's behaviour depends on the emulated microframe length.
>
> Default keeps the current 125 us behaviour bit-for-bit (and defaults
> to 1000 us for full-speed emulation, where the natural unit is the
> 1-ms frame). Values below 125 are rejected.
>
> Signed-off-by: Mikhail Zubenko <misha.zubenko.01@yandex.ru>
> ---
> Changes in v2 (addressing Alan Stern's review):
> - reword the description: the timer rearms while URBs are queued, not
> an unconditional "pendulum"; drop the word entirely
> - clarify the xHCI wording: the Bluetooth session lives on the
> machine's real xHCI controller (platform-level co-existence)
> - move tick_us into dummy_hcd_module_parameters with a custom setter
> (module_param_cb) that rejects values < 125
> - speed-aware default: 125 us for high/super-speed, 1000 us for
> full-speed emulation
> - reword MODULE_PARM_DESC per review ("length in microseconds of an
> emulated microframe")
> - pre-compute the delay into a ktime_t (timer_interval) at setup;
> remove the DUMMY_TIMER_INT_NSECS macro; explicit (u64) cast so the
> tick_us * NSEC_PER_USEC product does not overflow on 32-bit
> - parameter is 0444 (load-time only): a runtime write would not
> affect live controllers
> - note the emulation-fidelity tradeoff and the per-frame budget
> follow-up in the commit message
Much, much better. I have just a couple of very minor quibbles below.
> diff --git a/drivers/usb/gadget/udc/dummy_hcd.c b/drivers/usb/gadget/udc/dummy_hcd.c
> index c0e40fa..0884090 100644
> --- a/drivers/usb/gadget/udc/dummy_hcd.c
> +++ b/drivers/usb/gadget/udc/dummy_hcd.c
> @@ -51,7 +51,6 @@
> #define POWER_BUDGET 500 /* in mA; use 8 for low-power port testing */
> #define POWER_BUDGET_3 900 /* in mA */
>
> -#define DUMMY_TIMER_INT_NSECS 125000 /* 1 microframe */
>
Please remove the extra blank line as well.
> static const char driver_name[] = "dummy_hcd";
> static const char driver_desc[] = "USB Host+Gadget Emulator";
> @@ -66,6 +65,31 @@ struct dummy_hcd_module_parameters {
> bool is_super_speed;
> bool is_high_speed;
> unsigned int num;
> + unsigned int tick_us;
> +};
> +
> +/*
> + * Length in microseconds of an emulated microframe. The default (125,
> + * one high-speed microframe) preserves the historical timer rate; larger
> + * values slow the emulated controller down and reduce its interrupt-rate
> + * pressure on the host platform. Values below 125 are rejected.
> + */
> +static int tick_us_set(const char *val,
> + const struct kernel_param *kp)
> +{
> + unsigned int v;
> + int ret = kstrtouint(val, 0, &v);
> +
> + if (ret < 0 || v < 125) {
> + pr_err("dummy_hcd: tick_us must be >= 125\n");
> + return -EINVAL;
> + }
> + return param_set_uint(val, kp);
> +}
> +
> +static const struct kernel_param_ops tick_us_ops = {
> + .set = tick_us_set,
> + .get = param_get_uint,
> };
>
> static struct dummy_hcd_module_parameters mod_data = {
> @@ -79,6 +103,9 @@ module_param_named(is_high_speed, mod_data.is_high_speed, bool, S_IRUGO);
> MODULE_PARM_DESC(is_high_speed, "true to simulate HighSpeed connection");
> module_param_named(num, mod_data.num, uint, S_IRUGO);
> MODULE_PARM_DESC(num, "number of emulated controllers");
> +module_param_cb(tick_us, &tick_us_ops, &mod_data.tick_us, 0444);
> +MODULE_PARM_DESC(tick_us,
> + "Length in microseconds of an emulated microframe (default 125 for high/super-speed emulation, 1000 for full-speed); larger values reduce the interrupt-rate pressure on the host platform");
Since the tick_us value can refer either to microframes or frames,
depending on the speed, write this as "... (micro)frame ...".
Or, if you prefer, make the value always be microframes, with the
default set to 125 always, and change the calculation of timer_interval
so that it is 8 times larger when the emulator is at full speed. In
fact, if you decide to do it this way, you could put the change to
timer_interval in the follow-up patch along with the change to the total
transfer length.
Alan Stern
^ permalink raw reply [flat|nested] 13+ messages in thread
* [PATCH v5] usb: gadget: dummy_hcd: add tick_us module parameter for timer-rate tuning
2026-08-23 17:15 [PATCH] usb: gadget: dummy_hcd: add tick_us module parameter for Mikhail Zubenko
` (6 preceding siblings ...)
2026-08-24 10:42 ` [PATCH v4] " Mikhail Zubenko
@ 2026-08-24 15:54 ` Mikhail Zubenko
2026-08-25 1:42 ` Alan Stern
7 siblings, 1 reply; 13+ messages in thread
From: Mikhail Zubenko @ 2026-08-24 15:54 UTC (permalink / raw)
To: linux-usb; +Cc: Greg Kroah-Hartman, Alan Stern
dummy_hcd services URB completions from an hrtimer callback that
rearms itself with a fixed 125 us delay (one high-speed microframe)
for as long as any URBs are queued. Against a permanently polled HID
interrupt endpoint the queue never drains, so the timer runs at ~8 kHz
regardless of actual traffic.
On timer-rate-sensitive platforms (observed on one consumer AM4 board
with a current BIOS and a stock kernel) this timer rate co-existing
with a live Bluetooth session on the machine's real xHCI controller
resulted in a hard, below-software platform hang: printk, SysRq, NMI
and both watchdogs died in the same instant, with no panic, no MCE,
and empty pstore. 13 occurrences over 5 days, reliably reproducible
with that configuration (hangs within 20 min to 2.5 h of uptime).
The same workload with the emulated microframe lengthened to 1000 us
(this parameter) ran ~8 hours with zero hangs, and USB-cable sessions
(identical gadget traffic, no Bluetooth co-existence) never hung.
Note that lengthening the emulated microframe makes the emulation run
slower than a physical device would; users of the parameter trade
that emulation fidelity for interrupt-rate headroom.
The per-frame bandwidth budget in dummy_timer() does not scale with
the emulated microframe length; making that accounting microframe-
correct is planned as a follow-up patch. Otherwise nothing in the
driver's behaviour depends on the emulated microframe length.
Default keeps the current 125 us behaviour bit-for-bit (and defaults
to 1000 us for full-speed emulation, where the natural unit is the
1-ms frame). Values below 125 are rejected.
Signed-off-by: Mikhail Zubenko <misha.zubenko.01@yandex.ru>
---
Changes in v5:
- remove a leftover blank line where the macro was (review)
- spell "(micro)frame" in the parameter description (review)
Changes in v2 (addressing Alan Stern's review):
- reword the description: the timer rearms while URBs are queued, not
an unconditional "pendulum"; drop the word entirely
- clarify the xHCI wording: the Bluetooth session lives on the
machine's real xHCI controller (platform-level co-existence)
- move tick_us into dummy_hcd_module_parameters with a custom setter
(module_param_cb) that rejects values < 125
- speed-aware default: 125 us for high/super-speed, 1000 us for
full-speed emulation
- reword MODULE_PARM_DESC per review ("length in microseconds of an
emulated microframe")
- pre-compute the delay into a ktime_t (timer_interval) at setup;
remove the DUMMY_TIMER_INT_NSECS macro; explicit (u64) cast so the
tick_us * NSEC_PER_USEC product does not overflow on 32-bit
- parameter is 0444 (load-time only): a runtime write would not
affect live controllers
- note the emulation-fidelity tradeoff and the per-frame budget
follow-up in the commit message
drivers/usb/gadget/udc/dummy_hcd.c | 48 +++++++++++++++++++++++++++---
1 file changed, 44 insertions(+), 4 deletions(-)
diff --git a/drivers/usb/gadget/udc/dummy_hcd.c b/drivers/usb/gadget/udc/dummy_hcd.c
index c0e40fa..3edc4fc 100644
--- a/drivers/usb/gadget/udc/dummy_hcd.c
+++ b/drivers/usb/gadget/udc/dummy_hcd.c
@@ -51,8 +51,6 @@
#define POWER_BUDGET 500 /* in mA; use 8 for low-power port testing */
#define POWER_BUDGET_3 900 /* in mA */
-#define DUMMY_TIMER_INT_NSECS 125000 /* 1 microframe */
-
static const char driver_name[] = "dummy_hcd";
static const char driver_desc[] = "USB Host+Gadget Emulator";
@@ -66,6 +64,31 @@ struct dummy_hcd_module_parameters {
bool is_super_speed;
bool is_high_speed;
unsigned int num;
+ unsigned int tick_us;
+};
+
+/*
+ * Length in microseconds of an emulated microframe. The default (125,
+ * one high-speed microframe) preserves the historical timer rate; larger
+ * values slow the emulated controller down and reduce its interrupt-rate
+ * pressure on the host platform. Values below 125 are rejected.
+ */
+static int tick_us_set(const char *val,
+ const struct kernel_param *kp)
+{
+ unsigned int v;
+ int ret = kstrtouint(val, 0, &v);
+
+ if (ret < 0 || v < 125) {
+ pr_err("dummy_hcd: tick_us must be >= 125\n");
+ return -EINVAL;
+ }
+ return param_set_uint(val, kp);
+}
+
+static const struct kernel_param_ops tick_us_ops = {
+ .set = tick_us_set,
+ .get = param_get_uint,
};
static struct dummy_hcd_module_parameters mod_data = {
@@ -79,6 +102,9 @@ module_param_named(is_high_speed, mod_data.is_high_speed, bool, S_IRUGO);
MODULE_PARM_DESC(is_high_speed, "true to simulate HighSpeed connection");
module_param_named(num, mod_data.num, uint, S_IRUGO);
MODULE_PARM_DESC(num, "number of emulated controllers");
+module_param_cb(tick_us, &tick_us_ops, &mod_data.tick_us, 0444);
+MODULE_PARM_DESC(tick_us,
+ "Length in microseconds of an emulated (micro)frame (default 125 for high/super-speed emulation, 1000 for full-speed); larger values reduce the interrupt-rate pressure on the host platform");
/*-------------------------------------------------------------------------*/
/* gadget side driver data structures */
@@ -244,6 +270,7 @@ struct dummy_hcd {
struct dummy *dum;
enum dummy_rh_state rh_state;
struct hrtimer timer;
+ ktime_t timer_interval; /* emulated microframe length */
u32 port_status;
u32 old_status;
unsigned long re_timeout;
@@ -1329,7 +1356,7 @@ static int dummy_urb_enqueue(
/* kick the scheduler, it'll do the rest */
if (!dum_hcd->timer_pending) {
dum_hcd->timer_pending = 1;
- hrtimer_start(&dum_hcd->timer, ns_to_ktime(DUMMY_TIMER_INT_NSECS),
+ hrtimer_start(&dum_hcd->timer, dum_hcd->timer_interval,
HRTIMER_MODE_REL_SOFT);
}
@@ -2029,7 +2056,7 @@ return_urb:
dum_hcd->rh_state == DUMMY_RH_RUNNING) {
/* want a 1 msec delay here */
dum_hcd->timer_pending = 1;
- hrtimer_start(&dum_hcd->timer, ns_to_ktime(DUMMY_TIMER_INT_NSECS),
+ hrtimer_start(&dum_hcd->timer, dum_hcd->timer_interval,
HRTIMER_MODE_REL_SOFT);
}
@@ -2509,6 +2536,7 @@ static DEVICE_ATTR_RO(urbs);
static int dummy_start_ss(struct dummy_hcd *dum_hcd)
{
hrtimer_setup(&dum_hcd->timer, dummy_timer, CLOCK_MONOTONIC, HRTIMER_MODE_REL_SOFT);
+ dum_hcd->timer_interval = ns_to_ktime((u64)mod_data.tick_us * NSEC_PER_USEC);
dum_hcd->rh_state = DUMMY_RH_RUNNING;
dum_hcd->stream_en_ep = 0;
INIT_LIST_HEAD(&dum_hcd->urbp_list);
@@ -2538,6 +2566,7 @@ static int dummy_start(struct usb_hcd *hcd)
spin_lock_init(&dum_hcd->dum->lock);
hrtimer_setup(&dum_hcd->timer, dummy_timer, CLOCK_MONOTONIC, HRTIMER_MODE_REL_SOFT);
+ dum_hcd->timer_interval = ns_to_ktime((u64)mod_data.tick_us * NSEC_PER_USEC);
dum_hcd->rh_state = DUMMY_RH_RUNNING;
INIT_LIST_HEAD(&dum_hcd->urbp_list);
@@ -2828,6 +2857,17 @@ static int __init dummy_hcd_init(void)
return -EINVAL;
}
+ /*
+ * The emulated microframe length defaults to one high-speed
+ * microframe (125 us). When neither is_high_speed nor
+ * is_super_speed is set the emulation is full-speed, where the
+ * natural scheduling unit is the 1-ms frame, so default to
+ * 1000 us instead.
+ */
+ if (!mod_data.tick_us)
+ mod_data.tick_us = (mod_data.is_super_speed ||
+ mod_data.is_high_speed) ? 125 : 1000;
+
for (i = 0; i < mod_data.num; i++) {
the_hcd_pdev[i] = platform_device_alloc(driver_name, i);
if (!the_hcd_pdev[i]) {
--
2.43.0
^ permalink raw reply related [flat|nested] 13+ messages in thread
* Re: [PATCH v5] usb: gadget: dummy_hcd: add tick_us module parameter for timer-rate tuning
2026-08-24 15:54 ` [PATCH v5] " Mikhail Zubenko
@ 2026-08-25 1:42 ` Alan Stern
0 siblings, 0 replies; 13+ messages in thread
From: Alan Stern @ 2026-08-25 1:42 UTC (permalink / raw)
To: Mikhail Zubenko; +Cc: linux-usb, Greg Kroah-Hartman
On Mon, Aug 24, 2026 at 03:54:28PM -0000, Mikhail Zubenko wrote:
> dummy_hcd services URB completions from an hrtimer callback that
> rearms itself with a fixed 125 us delay (one high-speed microframe)
> for as long as any URBs are queued. Against a permanently polled HID
> interrupt endpoint the queue never drains, so the timer runs at ~8 kHz
> regardless of actual traffic.
>
> On timer-rate-sensitive platforms (observed on one consumer AM4 board
> with a current BIOS and a stock kernel) this timer rate co-existing
> with a live Bluetooth session on the machine's real xHCI controller
> resulted in a hard, below-software platform hang: printk, SysRq, NMI
> and both watchdogs died in the same instant, with no panic, no MCE,
> and empty pstore. 13 occurrences over 5 days, reliably reproducible
> with that configuration (hangs within 20 min to 2.5 h of uptime).
> The same workload with the emulated microframe lengthened to 1000 us
> (this parameter) ran ~8 hours with zero hangs, and USB-cable sessions
> (identical gadget traffic, no Bluetooth co-existence) never hung.
>
> Note that lengthening the emulated microframe makes the emulation run
> slower than a physical device would; users of the parameter trade
> that emulation fidelity for interrupt-rate headroom.
>
> The per-frame bandwidth budget in dummy_timer() does not scale with
> the emulated microframe length; making that accounting microframe-
> correct is planned as a follow-up patch. Otherwise nothing in the
> driver's behaviour depends on the emulated microframe length.
>
> Default keeps the current 125 us behaviour bit-for-bit (and defaults
> to 1000 us for full-speed emulation, where the natural unit is the
> 1-ms frame). Values below 125 are rejected.
>
> Signed-off-by: Mikhail Zubenko <misha.zubenko.01@yandex.ru>
> ---
> Changes in v5:
> - remove a leftover blank line where the macro was (review)
> - spell "(micro)frame" in the parameter description (review)
>
> Changes in v2 (addressing Alan Stern's review):
> - reword the description: the timer rearms while URBs are queued, not
> an unconditional "pendulum"; drop the word entirely
> - clarify the xHCI wording: the Bluetooth session lives on the
> machine's real xHCI controller (platform-level co-existence)
> - move tick_us into dummy_hcd_module_parameters with a custom setter
> (module_param_cb) that rejects values < 125
> - speed-aware default: 125 us for high/super-speed, 1000 us for
> full-speed emulation
> - reword MODULE_PARM_DESC per review ("length in microseconds of an
> emulated microframe")
> - pre-compute the delay into a ktime_t (timer_interval) at setup;
> remove the DUMMY_TIMER_INT_NSECS macro; explicit (u64) cast so the
> tick_us * NSEC_PER_USEC product does not overflow on 32-bit
> - parameter is 0444 (load-time only): a runtime write would not
> affect live controllers
> - note the emulation-fidelity tradeoff and the per-frame budget
> follow-up in the commit message
Reviewed-by: Alan Stern <stern@rowland.harvard.edu>
> drivers/usb/gadget/udc/dummy_hcd.c | 48 +++++++++++++++++++++++++++---
> 1 file changed, 44 insertions(+), 4 deletions(-)
>
> diff --git a/drivers/usb/gadget/udc/dummy_hcd.c b/drivers/usb/gadget/udc/dummy_hcd.c
> index c0e40fa..3edc4fc 100644
> --- a/drivers/usb/gadget/udc/dummy_hcd.c
> +++ b/drivers/usb/gadget/udc/dummy_hcd.c
> @@ -51,8 +51,6 @@
> #define POWER_BUDGET 500 /* in mA; use 8 for low-power port testing */
> #define POWER_BUDGET_3 900 /* in mA */
>
> -#define DUMMY_TIMER_INT_NSECS 125000 /* 1 microframe */
> -
> static const char driver_name[] = "dummy_hcd";
> static const char driver_desc[] = "USB Host+Gadget Emulator";
>
> @@ -66,6 +64,31 @@ struct dummy_hcd_module_parameters {
> bool is_super_speed;
> bool is_high_speed;
> unsigned int num;
> + unsigned int tick_us;
> +};
> +
> +/*
> + * Length in microseconds of an emulated microframe. The default (125,
> + * one high-speed microframe) preserves the historical timer rate; larger
> + * values slow the emulated controller down and reduce its interrupt-rate
> + * pressure on the host platform. Values below 125 are rejected.
> + */
> +static int tick_us_set(const char *val,
> + const struct kernel_param *kp)
> +{
> + unsigned int v;
> + int ret = kstrtouint(val, 0, &v);
> +
> + if (ret < 0 || v < 125) {
> + pr_err("dummy_hcd: tick_us must be >= 125\n");
> + return -EINVAL;
> + }
> + return param_set_uint(val, kp);
> +}
> +
> +static const struct kernel_param_ops tick_us_ops = {
> + .set = tick_us_set,
> + .get = param_get_uint,
> };
>
> static struct dummy_hcd_module_parameters mod_data = {
> @@ -79,6 +102,9 @@ module_param_named(is_high_speed, mod_data.is_high_speed, bool, S_IRUGO);
> MODULE_PARM_DESC(is_high_speed, "true to simulate HighSpeed connection");
> module_param_named(num, mod_data.num, uint, S_IRUGO);
> MODULE_PARM_DESC(num, "number of emulated controllers");
> +module_param_cb(tick_us, &tick_us_ops, &mod_data.tick_us, 0444);
> +MODULE_PARM_DESC(tick_us,
> + "Length in microseconds of an emulated (micro)frame (default 125 for high/super-speed emulation, 1000 for full-speed); larger values reduce the interrupt-rate pressure on the host platform");
> /*-------------------------------------------------------------------------*/
>
> /* gadget side driver data structures */
> @@ -244,6 +270,7 @@ struct dummy_hcd {
> struct dummy *dum;
> enum dummy_rh_state rh_state;
> struct hrtimer timer;
> + ktime_t timer_interval; /* emulated microframe length */
> u32 port_status;
> u32 old_status;
> unsigned long re_timeout;
> @@ -1329,7 +1356,7 @@ static int dummy_urb_enqueue(
> /* kick the scheduler, it'll do the rest */
> if (!dum_hcd->timer_pending) {
> dum_hcd->timer_pending = 1;
> - hrtimer_start(&dum_hcd->timer, ns_to_ktime(DUMMY_TIMER_INT_NSECS),
> + hrtimer_start(&dum_hcd->timer, dum_hcd->timer_interval,
> HRTIMER_MODE_REL_SOFT);
> }
>
> @@ -2029,7 +2056,7 @@ return_urb:
> dum_hcd->rh_state == DUMMY_RH_RUNNING) {
> /* want a 1 msec delay here */
> dum_hcd->timer_pending = 1;
> - hrtimer_start(&dum_hcd->timer, ns_to_ktime(DUMMY_TIMER_INT_NSECS),
> + hrtimer_start(&dum_hcd->timer, dum_hcd->timer_interval,
> HRTIMER_MODE_REL_SOFT);
> }
>
> @@ -2509,6 +2536,7 @@ static DEVICE_ATTR_RO(urbs);
> static int dummy_start_ss(struct dummy_hcd *dum_hcd)
> {
> hrtimer_setup(&dum_hcd->timer, dummy_timer, CLOCK_MONOTONIC, HRTIMER_MODE_REL_SOFT);
> + dum_hcd->timer_interval = ns_to_ktime((u64)mod_data.tick_us * NSEC_PER_USEC);
> dum_hcd->rh_state = DUMMY_RH_RUNNING;
> dum_hcd->stream_en_ep = 0;
> INIT_LIST_HEAD(&dum_hcd->urbp_list);
> @@ -2538,6 +2566,7 @@ static int dummy_start(struct usb_hcd *hcd)
>
> spin_lock_init(&dum_hcd->dum->lock);
> hrtimer_setup(&dum_hcd->timer, dummy_timer, CLOCK_MONOTONIC, HRTIMER_MODE_REL_SOFT);
> + dum_hcd->timer_interval = ns_to_ktime((u64)mod_data.tick_us * NSEC_PER_USEC);
> dum_hcd->rh_state = DUMMY_RH_RUNNING;
>
> INIT_LIST_HEAD(&dum_hcd->urbp_list);
> @@ -2828,6 +2857,17 @@ static int __init dummy_hcd_init(void)
> return -EINVAL;
> }
>
> + /*
> + * The emulated microframe length defaults to one high-speed
> + * microframe (125 us). When neither is_high_speed nor
> + * is_super_speed is set the emulation is full-speed, where the
> + * natural scheduling unit is the 1-ms frame, so default to
> + * 1000 us instead.
> + */
> + if (!mod_data.tick_us)
> + mod_data.tick_us = (mod_data.is_super_speed ||
> + mod_data.is_high_speed) ? 125 : 1000;
> +
> for (i = 0; i < mod_data.num; i++) {
> the_hcd_pdev[i] = platform_device_alloc(driver_name, i);
> if (!the_hcd_pdev[i]) {
> --
> 2.43.0
>
>
^ permalink raw reply [flat|nested] 13+ messages in thread
end of thread, other threads:[~2026-08-25 1:42 UTC | newest]
Thread overview: 13+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2026-08-23 17:15 [PATCH] usb: gadget: dummy_hcd: add tick_us module parameter for Mikhail Zubenko
2026-08-23 17:25 ` Greg Kroah-Hartman
2026-08-23 19:55 ` Alan Stern
2026-08-24 8:29 ` [PATCH v2] usb: gadget: dummy_hcd: add tick_us module parameter for timer-rate tuning Mikhail Zubenko
2026-08-24 8:29 ` Mikhail Zubenko
2026-08-24 8:43 ` Greg Kroah-Hartman
2026-08-24 9:12 ` [PATCH v3] " Mikhail Zubenko
2026-08-24 9:40 ` Greg Kroah-Hartman
2026-08-24 10:42 ` Mikhail Zubenko
2026-08-24 10:42 ` [PATCH v4] " Mikhail Zubenko
2026-08-24 14:27 ` Alan Stern
2026-08-24 15:54 ` [PATCH v5] " Mikhail Zubenko
2026-08-25 1:42 ` Alan Stern
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for NNTP newsgroup(s).