Commit 43fe3a99d9caf10b25f9c596e9854cdae30db418
Committed by
Greg Kroah-Hartman
1 parent
c4f3476436
Exists in
smarc-l5.0.0_1.0.0-ga
and in
5 other branches
USB: EHCI: resolve some unlikely races
This patch (as1589) resolves some unlikely races involving system shutdown or controller death in ehci-hcd: Shutdown races with both root-hub resume and controller resume. Controller death races with root-hub suspend. A new bitflag is added to indicate that the controller has been shut down (whether for system shutdown or because it died). Tests are added in the suspend and resume pathways to avoid reactivating the controller after any sort of shutdown. Signed-off-by: Alan Stern <stern@rowland.harvard.edu> Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
Showing 3 changed files with 43 additions and 5 deletions Side-by-side Diff
drivers/usb/host/ehci-hcd.c
... | ... | @@ -343,6 +343,7 @@ |
343 | 343 | struct ehci_hcd *ehci = hcd_to_ehci(hcd); |
344 | 344 | |
345 | 345 | spin_lock_irq(&ehci->lock); |
346 | + ehci->shutdown = true; | |
346 | 347 | ehci->rh_state = EHCI_RH_STOPPING; |
347 | 348 | ehci->enabled_hrtimer_events = 0; |
348 | 349 | spin_unlock_irq(&ehci->lock); |
... | ... | @@ -823,6 +824,7 @@ |
823 | 824 | usb_hc_died(hcd); |
824 | 825 | |
825 | 826 | /* Don't let the controller do anything more */ |
827 | + ehci->shutdown = true; | |
826 | 828 | ehci->rh_state = EHCI_RH_STOPPING; |
827 | 829 | ehci->command &= ~(CMD_RUN | CMD_ASE | CMD_PSE); |
828 | 830 | ehci_writel(ehci, ehci->command, &ehci->regs->command); |
... | ... | @@ -1129,6 +1131,9 @@ |
1129 | 1131 | /* Mark hardware accessible again as we are back to full power by now */ |
1130 | 1132 | set_bit(HCD_FLAG_HW_ACCESSIBLE, &hcd->flags); |
1131 | 1133 | |
1134 | + if (ehci->shutdown) | |
1135 | + return 0; /* Controller is dead */ | |
1136 | + | |
1132 | 1137 | /* |
1133 | 1138 | * If CF is still set and we aren't resuming from hibernation |
1134 | 1139 | * then we maintained suspend power. |
1135 | 1140 | |
... | ... | @@ -1139,10 +1144,17 @@ |
1139 | 1144 | int mask = INTR_MASK; |
1140 | 1145 | |
1141 | 1146 | ehci_prepare_ports_for_controller_resume(ehci); |
1147 | + | |
1148 | + spin_lock_irq(&ehci->lock); | |
1149 | + if (ehci->shutdown) | |
1150 | + goto skip; | |
1151 | + | |
1142 | 1152 | if (!hcd->self.root_hub->do_remote_wakeup) |
1143 | 1153 | mask &= ~STS_PCD; |
1144 | 1154 | ehci_writel(ehci, mask, &ehci->regs->intr_enable); |
1145 | 1155 | ehci_readl(ehci, &ehci->regs->intr_enable); |
1156 | + skip: | |
1157 | + spin_unlock_irq(&ehci->lock); | |
1146 | 1158 | return 0; |
1147 | 1159 | } |
1148 | 1160 | |
1149 | 1161 | |
1150 | 1162 | |
... | ... | @@ -1154,14 +1166,20 @@ |
1154 | 1166 | (void) ehci_halt(ehci); |
1155 | 1167 | (void) ehci_reset(ehci); |
1156 | 1168 | |
1169 | + spin_lock_irq(&ehci->lock); | |
1170 | + if (ehci->shutdown) | |
1171 | + goto skip; | |
1172 | + | |
1157 | 1173 | ehci_writel(ehci, ehci->command, &ehci->regs->command); |
1158 | 1174 | ehci_writel(ehci, FLAG_CF, &ehci->regs->configured_flag); |
1159 | 1175 | ehci_readl(ehci, &ehci->regs->command); /* unblock posted writes */ |
1160 | 1176 | |
1177 | + ehci->rh_state = EHCI_RH_SUSPENDED; | |
1178 | + spin_unlock_irq(&ehci->lock); | |
1179 | + | |
1161 | 1180 | /* here we "know" root ports should always stay powered */ |
1162 | 1181 | ehci_port_power(ehci, 1); |
1163 | 1182 | |
1164 | - ehci->rh_state = EHCI_RH_SUSPENDED; | |
1165 | 1183 | return 1; |
1166 | 1184 | } |
1167 | 1185 |
drivers/usb/host/ehci-hub.c
... | ... | @@ -221,6 +221,8 @@ |
221 | 221 | ehci_quiesce(ehci); |
222 | 222 | |
223 | 223 | spin_lock_irq (&ehci->lock); |
224 | + if (ehci->rh_state < EHCI_RH_RUNNING) | |
225 | + goto done; | |
224 | 226 | |
225 | 227 | /* Once the controller is stopped, port resumes that are already |
226 | 228 | * in progress won't complete. Hence if remote wakeup is enabled |
... | ... | @@ -306,6 +308,10 @@ |
306 | 308 | ehci_halt (ehci); |
307 | 309 | |
308 | 310 | spin_lock_irq(&ehci->lock); |
311 | + if (ehci->enabled_hrtimer_events & BIT(EHCI_HRTIMER_POLL_DEAD)) | |
312 | + ehci_handle_controller_death(ehci); | |
313 | + if (ehci->rh_state != EHCI_RH_RUNNING) | |
314 | + goto done; | |
309 | 315 | ehci->rh_state = EHCI_RH_SUSPENDED; |
310 | 316 | |
311 | 317 | end_unlink_async(ehci); |
... | ... | @@ -320,6 +326,7 @@ |
320 | 326 | ehci_writel(ehci, mask, &ehci->regs->intr_enable); |
321 | 327 | ehci_readl(ehci, &ehci->regs->intr_enable); |
322 | 328 | |
329 | + done: | |
323 | 330 | ehci->next_statechange = jiffies + msecs_to_jiffies(10); |
324 | 331 | ehci->enabled_hrtimer_events = 0; |
325 | 332 | ehci->next_hrtimer_event = EHCI_HRTIMER_NO_EVENT; |
... | ... | @@ -342,10 +349,8 @@ |
342 | 349 | if (time_before (jiffies, ehci->next_statechange)) |
343 | 350 | msleep(5); |
344 | 351 | spin_lock_irq (&ehci->lock); |
345 | - if (!HCD_HW_ACCESSIBLE(hcd)) { | |
346 | - spin_unlock_irq(&ehci->lock); | |
347 | - return -ESHUTDOWN; | |
348 | - } | |
352 | + if (!HCD_HW_ACCESSIBLE(hcd) || ehci->shutdown) | |
353 | + goto shutdown; | |
349 | 354 | |
350 | 355 | if (unlikely(ehci->debug)) { |
351 | 356 | if (!dbgp_reset_prep()) |
... | ... | @@ -384,6 +389,8 @@ |
384 | 389 | spin_unlock_irq(&ehci->lock); |
385 | 390 | msleep(8); |
386 | 391 | spin_lock_irq(&ehci->lock); |
392 | + if (ehci->shutdown) | |
393 | + goto shutdown; | |
387 | 394 | |
388 | 395 | /* clear phy low-power mode before resume */ |
389 | 396 | if (ehci->bus_suspended && ehci->has_hostpc) { |
... | ... | @@ -401,6 +408,8 @@ |
401 | 408 | spin_unlock_irq(&ehci->lock); |
402 | 409 | msleep(5); |
403 | 410 | spin_lock_irq(&ehci->lock); |
411 | + if (ehci->shutdown) | |
412 | + goto shutdown; | |
404 | 413 | } |
405 | 414 | |
406 | 415 | /* manually resume the ports we suspended during bus_suspend() */ |
... | ... | @@ -421,6 +430,8 @@ |
421 | 430 | spin_unlock_irq(&ehci->lock); |
422 | 431 | msleep(20); |
423 | 432 | spin_lock_irq(&ehci->lock); |
433 | + if (ehci->shutdown) | |
434 | + goto shutdown; | |
424 | 435 | } |
425 | 436 | |
426 | 437 | i = HCS_N_PORTS (ehci->hcs_params); |
427 | 438 | |
428 | 439 | |
... | ... | @@ -439,10 +450,18 @@ |
439 | 450 | ehci_handover_companion_ports(ehci); |
440 | 451 | |
441 | 452 | /* Now we can safely re-enable irqs */ |
453 | + spin_lock_irq(&ehci->lock); | |
454 | + if (ehci->shutdown) | |
455 | + goto shutdown; | |
442 | 456 | ehci_writel(ehci, INTR_MASK, &ehci->regs->intr_enable); |
443 | 457 | (void) ehci_readl(ehci, &ehci->regs->intr_enable); |
458 | + spin_unlock_irq(&ehci->lock); | |
444 | 459 | |
445 | 460 | return 0; |
461 | + | |
462 | + shutdown: | |
463 | + spin_unlock_irq(&ehci->lock); | |
464 | + return -ESHUTDOWN; | |
446 | 465 | } |
447 | 466 | |
448 | 467 | #else |