From: William wu Date: Wed, 19 Oct 2016 16:05:26 +0000 (+0800) Subject: CHROMIUM: xhci: stop roothub port polling timer in shutdown X-Git-Tag: firefly_0821_release~1336 X-Git-Url: http://demsky.eecs.uci.edu/git/?a=commitdiff_plain;h=a6d73821f24e8ddcfcdd4f636777518665e85eb9;p=firefly-linux-kernel-4.4.55.git CHROMIUM: xhci: stop roothub port polling timer in shutdown The xhci hcd use the port polling timer (rh_timer) to poll the roothub for port events. But we can't allow the USB core to poll the port events during shutdown because the xhci controller may be disable and can't be accessed in shutdown. If we access xhci port registers with port polling timer after xhci shutdown, it may cause kernel crash or unexpected behavior. So we need to stop the port polling timer while shutdown xhci. I can easily reproduce the issue on rk3399 platform, plug in a Type-C hub and an USB ethernet dongle, then do reboot test, result in a crash with the following backtrace. Unhandled fault: synchronous external abort (0x96000010) at 0xffffff80002f0430 Internal error: : 96000010 [#1] PREEMPT SMP task: ffffffc001092cb0 ti: ffffffc00107c000 task.ti: ffffffc00107c000 PC is at xhci_hub_status_data+0xec/0x1e4 LR is at xhci_hub_status_data+0xb0/0x1e4 [] xhci_hub_status_data+0xec/0x1e4 [] usb_hcd_poll_rh_status+0x54/0x148 [] rh_timer_func+0x20/0x2c [] call_timer_fn+0xa4/0x1c8 [] run_timer_softirq+0x248/0x2cc [] __do_softirq+0x178/0x338 [] irq_exit+0x78/0xc0 [] __handle_domain_irq+0x9c/0xbc [] gic_handle_irq+0xcc/0x188 BUG=chrome-os-partner:59111 TEST=Plug in a Type-C hub, then do reboot test, check if kernel crash during shutdown. Change-Id: I3ca3d12d101241cd78138ea5d995708a2893d1a0 Signed-off-by: William wu Reviewed-on: https://chromium-review.googlesource.com/401121 Commit-Ready: Guenter Roeck Tested-by: Guenter Roeck Reviewed-by: Guenter Roeck --- diff --git a/drivers/usb/host/xhci.c b/drivers/usb/host/xhci.c index 0b48f7d97ddf..6373f159de12 100644 --- a/drivers/usb/host/xhci.c +++ b/drivers/usb/host/xhci.c @@ -744,6 +744,12 @@ void xhci_shutdown(struct usb_hcd *hcd) if (!hcd->rh_registered) return; + /* Don't poll the roothubs on shutdown */ + clear_bit(HCD_FLAG_POLL_RH, &hcd->flags); + del_timer_sync(&hcd->rh_timer); + clear_bit(HCD_FLAG_POLL_RH, &xhci->shared_hcd->flags); + del_timer_sync(&xhci->shared_hcd->rh_timer); + if (xhci->quirks & XHCI_SPURIOUS_REBOOT) usb_disable_xhci_ports(to_pci_dev(hcd->self.controller));