Skip to content

Commit 6ddde3e

Browse files
matnymangregkh
authored andcommitted
usb: hub: Fix flushing of delayed work used for post resume purposes
commit 9bd9c80 upstream. Delayed work that prevents USB3 hubs from runtime-suspending too early needed to be flushed in hub_quiesce() to resolve issues detected on QC SC8280XP CRD board during suspend resume testing. This flushing did however trigger new issues on Raspberry Pi 3B+, which doesn't have USB3 ports, and doesn't queue any post resume delayed work. The flushed 'hub->init_work' item is used for several purposes, and is originally initialized with a 'NULL' work function. The work function is also changed on the fly, which may contribute to the issue. Solve this by creating a dedicated delayed work item for post resume work, and flush that delayed work in hub_quiesce() Cc: stable <stable@kernel.org> Fixes: a49e1e2 ("usb: hub: Fix flushing and scheduling of delayed work that tunes runtime pm") Reported-by: Mark Brown <broonie@kernel.org> Closes: https://lore.kernel.org/linux-usb/aF5rNp1l0LWITnEB@finisterre.sirena.org.uk Signed-off-by: Mathias Nyman <mathias.nyman@linux.intel.com> Tested-by: Konrad Dybcio <konrad.dybcio@oss.qualcomm.com> # SC8280XP CRD Tested-by: Mark Brown <broonie@kernel.org> Link: https://lore.kernel.org/r/20250627164348.3982628-2-mathias.nyman@linux.intel.com [florian: adjust for lack of hub_{get,put} and timer_delete_sync] Signed-off-by: Florian Fainelli <florian.fainelli@broadcom.com> Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
1 parent 08c21a7 commit 6ddde3e

File tree

2 files changed

+9
-13
lines changed

2 files changed

+9
-13
lines changed

drivers/usb/core/hub.c

Lines changed: 8 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -1030,12 +1030,11 @@ int usb_remove_device(struct usb_device *udev)
10301030

10311031
enum hub_activation_type {
10321032
HUB_INIT, HUB_INIT2, HUB_INIT3, /* INITs must come first */
1033-
HUB_POST_RESET, HUB_RESUME, HUB_RESET_RESUME, HUB_POST_RESUME,
1033+
HUB_POST_RESET, HUB_RESUME, HUB_RESET_RESUME,
10341034
};
10351035

10361036
static void hub_init_func2(struct work_struct *ws);
10371037
static void hub_init_func3(struct work_struct *ws);
1038-
static void hub_post_resume(struct work_struct *ws);
10391038

10401039
static void hub_activate(struct usb_hub *hub, enum hub_activation_type type)
10411040
{
@@ -1059,12 +1058,6 @@ static void hub_activate(struct usb_hub *hub, enum hub_activation_type type)
10591058
goto init3;
10601059
}
10611060

1062-
if (type == HUB_POST_RESUME) {
1063-
usb_autopm_put_interface_async(to_usb_interface(hub->intfdev));
1064-
kref_put(&hub->kref, hub_release);
1065-
return;
1066-
}
1067-
10681061
kref_get(&hub->kref);
10691062

10701063
/* The superspeed hub except for root hub has to use Hub Depth
@@ -1318,8 +1311,8 @@ static void hub_activate(struct usb_hub *hub, enum hub_activation_type type)
13181311
usb_autopm_get_interface_no_resume(
13191312
to_usb_interface(hub->intfdev));
13201313

1321-
INIT_DELAYED_WORK(&hub->init_work, hub_post_resume);
1322-
queue_delayed_work(system_power_efficient_wq, &hub->init_work,
1314+
queue_delayed_work(system_power_efficient_wq,
1315+
&hub->post_resume_work,
13231316
msecs_to_jiffies(USB_SS_PORT_U0_WAKE_TIME));
13241317
return;
13251318
}
@@ -1344,9 +1337,10 @@ static void hub_init_func3(struct work_struct *ws)
13441337

13451338
static void hub_post_resume(struct work_struct *ws)
13461339
{
1347-
struct usb_hub *hub = container_of(ws, struct usb_hub, init_work.work);
1340+
struct usb_hub *hub = container_of(ws, struct usb_hub, post_resume_work.work);
13481341

1349-
hub_activate(hub, HUB_POST_RESUME);
1342+
usb_autopm_put_interface_async(to_usb_interface(hub->intfdev));
1343+
kref_put(&hub->kref, hub_release);
13501344
}
13511345

13521346
enum hub_quiescing_type {
@@ -1374,7 +1368,7 @@ static void hub_quiesce(struct usb_hub *hub, enum hub_quiescing_type type)
13741368

13751369
/* Stop hub_wq and related activity */
13761370
del_timer_sync(&hub->irq_urb_retry);
1377-
flush_delayed_work(&hub->init_work);
1371+
flush_delayed_work(&hub->post_resume_work);
13781372
usb_kill_urb(hub->urb);
13791373
if (hub->has_indicators)
13801374
cancel_delayed_work_sync(&hub->leds);
@@ -1921,6 +1915,7 @@ static int hub_probe(struct usb_interface *intf, const struct usb_device_id *id)
19211915
hub->hdev = hdev;
19221916
INIT_DELAYED_WORK(&hub->leds, led_work);
19231917
INIT_DELAYED_WORK(&hub->init_work, NULL);
1918+
INIT_DELAYED_WORK(&hub->post_resume_work, hub_post_resume);
19241919
INIT_WORK(&hub->events, hub_event);
19251920
spin_lock_init(&hub->irq_urb_lock);
19261921
timer_setup(&hub->irq_urb_retry, hub_retry_irq_urb, 0);

drivers/usb/core/hub.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -69,6 +69,7 @@ struct usb_hub {
6969
u8 indicator[USB_MAXCHILDREN];
7070
struct delayed_work leds;
7171
struct delayed_work init_work;
72+
struct delayed_work post_resume_work;
7273
struct work_struct events;
7374
spinlock_t irq_urb_lock;
7475
struct timer_list irq_urb_retry;

0 commit comments

Comments
 (0)