Commit 71c731a2 (usb: host: xhci: Fix Compliance Mode on SN65LVPE502CP Hardware) was a workaround for systems using the SN65LVPE502CP controller, but it introduced a bug where resume from hibernate would add the comp_mode_recovery_timer to the timer queue while it was already active when saved to disk on hibernate. This caused list_add corruption leading to a crash when resuming from hibernate. The original patch erroneously assumed that the timer would be deleted by a call to xhci_suspend() or xhci_stop(), but neither of these calls is made during the hibernate sequence. When returning from hibernate, the timer was still active, and the attempt to list_add the same timer corrupted the list. We can avoid this problem when resuming from hibernate by first deleting the timer and then initializing it and adding it to the timer list. Removed extraneous parenthesis from conditional statements of the original commit. Signed-off-by: Tony Camuso <tcamuso@xxxxxxxxxx> Acked-by: Don Zickus <dzickus@xxxxxxxxxx> --- drivers/usb/host/xhci.c | 13 ++++++++++--- 1 files changed, 10 insertions(+), 3 deletions(-) diff --git a/drivers/usb/host/xhci.c b/drivers/usb/host/xhci.c index f1f01a8..267a7b1 100644 --- a/drivers/usb/host/xhci.c +++ b/drivers/usb/host/xhci.c @@ -732,7 +732,7 @@ void xhci_stop(struct usb_hcd *hcd) /* Deleting Compliance Mode Recovery Timer */ if ((xhci->quirks & XHCI_COMP_MODE_QUIRK) && - (!(xhci_all_ports_seen_u0(xhci)))) + !(xhci_all_ports_seen_u0(xhci))) del_timer_sync(&xhci->comp_mode_recovery_timer); if (xhci->quirks & XHCI_AMD_PLL_FIX) @@ -927,7 +927,7 @@ int xhci_suspend(struct xhci_hcd *xhci) * is about to be suspended. */ if ((xhci->quirks & XHCI_COMP_MODE_QUIRK) && - (!(xhci_all_ports_seen_u0(xhci)))) { + !(xhci_all_ports_seen_u0(xhci))) { del_timer_sync(&xhci->comp_mode_recovery_timer); xhci_dbg(xhci, "Compliance Mode Recovery Timer Deleted!\n"); } @@ -988,6 +988,13 @@ int xhci_resume(struct xhci_hcd *xhci, bool hibernated) /* If restore operation fails, re-initialize the HC during resume */ if ((temp & STS_SRE) || hibernated) { + + if ((xhci->quirks & XHCI_COMP_MODE_QUIRK) && + !(xhci_all_ports_seen_u0(xhci))) { + del_timer_sync(&xhci->comp_mode_recovery_timer); + xhci_dbg(xhci, "Compliance Mode Recovery Timer deleted!\n"); + } + /* Let the USB core know _both_ roothubs lost power. */ usb_root_hub_lost_power(xhci->main_hcd->self.root_hub); usb_root_hub_lost_power(xhci->shared_hcd->self.root_hub); @@ -1071,7 +1078,7 @@ int xhci_resume(struct xhci_hcd *xhci, bool hibernated) * to suffer the Compliance Mode issue again. It doesn't matter if * ports have entered previously to U0 before system's suspension. */ - if (xhci->quirks & XHCI_COMP_MODE_QUIRK) + if ((xhci->quirks & XHCI_COMP_MODE_QUIRK) && !hibernated) compliance_mode_recovery_timer_init(xhci); /* Re-enable port polling. */ -- 1.7.1 -- To unsubscribe from this list: send the line "unsubscribe linux-usb" in the body of a message to majordomo@xxxxxxxxxxxxxxx More majordomo info at http://vger.kernel.org/majordomo-info.html