Skip to content

Commit 9bd9c80

Browse files
matnymangregkh
authored andcommitted
usb: hub: Fix flushing of delayed work used for post resume purposes
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 <[email protected]> Fixes: a49e1e2 ("usb: hub: Fix flushing and scheduling of delayed work that tunes runtime pm") Reported-by: Mark Brown <[email protected]> Closes: https://lore.kernel.org/linux-usb/[email protected] Signed-off-by: Mathias Nyman <[email protected]> Tested-by: Konrad Dybcio <[email protected]> # SC8280XP CRD Tested-by: Mark Brown <[email protected]> Link: https://lore.kernel.org/r/[email protected] Signed-off-by: Greg Kroah-Hartman <[email protected]>
1 parent efe3e3a commit 9bd9c80

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
@@ -1074,12 +1074,11 @@ int usb_remove_device(struct usb_device *udev)
10741074

10751075
enum hub_activation_type {
10761076
HUB_INIT, HUB_INIT2, HUB_INIT3, /* INITs must come first */
1077-
HUB_POST_RESET, HUB_RESUME, HUB_RESET_RESUME, HUB_POST_RESUME,
1077+
HUB_POST_RESET, HUB_RESUME, HUB_RESET_RESUME,
10781078
};
10791079

10801080
static void hub_init_func2(struct work_struct *ws);
10811081
static void hub_init_func3(struct work_struct *ws);
1082-
static void hub_post_resume(struct work_struct *ws);
10831082

10841083
static void hub_activate(struct usb_hub *hub, enum hub_activation_type type)
10851084
{
@@ -1103,12 +1102,6 @@ static void hub_activate(struct usb_hub *hub, enum hub_activation_type type)
11031102
goto init3;
11041103
}
11051104

1106-
if (type == HUB_POST_RESUME) {
1107-
usb_autopm_put_interface_async(to_usb_interface(hub->intfdev));
1108-
hub_put(hub);
1109-
return;
1110-
}
1111-
11121105
hub_get(hub);
11131106

11141107
/* The superspeed hub except for root hub has to use Hub Depth
@@ -1362,8 +1355,8 @@ static void hub_activate(struct usb_hub *hub, enum hub_activation_type type)
13621355
usb_autopm_get_interface_no_resume(
13631356
to_usb_interface(hub->intfdev));
13641357

1365-
INIT_DELAYED_WORK(&hub->init_work, hub_post_resume);
1366-
queue_delayed_work(system_power_efficient_wq, &hub->init_work,
1358+
queue_delayed_work(system_power_efficient_wq,
1359+
&hub->post_resume_work,
13671360
msecs_to_jiffies(USB_SS_PORT_U0_WAKE_TIME));
13681361
return;
13691362
}
@@ -1388,9 +1381,10 @@ static void hub_init_func3(struct work_struct *ws)
13881381

13891382
static void hub_post_resume(struct work_struct *ws)
13901383
{
1391-
struct usb_hub *hub = container_of(ws, struct usb_hub, init_work.work);
1384+
struct usb_hub *hub = container_of(ws, struct usb_hub, post_resume_work.work);
13921385

1393-
hub_activate(hub, HUB_POST_RESUME);
1386+
usb_autopm_put_interface_async(to_usb_interface(hub->intfdev));
1387+
hub_put(hub);
13941388
}
13951389

13961390
enum hub_quiescing_type {
@@ -1418,7 +1412,7 @@ static void hub_quiesce(struct usb_hub *hub, enum hub_quiescing_type type)
14181412

14191413
/* Stop hub_wq and related activity */
14201414
timer_delete_sync(&hub->irq_urb_retry);
1421-
flush_delayed_work(&hub->init_work);
1415+
flush_delayed_work(&hub->post_resume_work);
14221416
usb_kill_urb(hub->urb);
14231417
if (hub->has_indicators)
14241418
cancel_delayed_work_sync(&hub->leds);
@@ -1977,6 +1971,7 @@ static int hub_probe(struct usb_interface *intf, const struct usb_device_id *id)
19771971
hub->hdev = hdev;
19781972
INIT_DELAYED_WORK(&hub->leds, led_work);
19791973
INIT_DELAYED_WORK(&hub->init_work, NULL);
1974+
INIT_DELAYED_WORK(&hub->post_resume_work, hub_post_resume);
19801975
INIT_WORK(&hub->events, hub_event);
19811976
INIT_LIST_HEAD(&hub->onboard_devs);
19821977
spin_lock_init(&hub->irq_urb_lock);

drivers/usb/core/hub.h

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

0 commit comments

Comments
 (0)