Commit 96044694 authored by Mathias Nyman's avatar Mathias Nyman Committed by Greg Kroah-Hartman

xhci: fix oops when xhci resumes from hibernate with hw lpm capable devices

Resuming from hibernate (S4) will restart and re-initialize xHC.
The device contexts are freed and will be re-allocated later during device reset.

Usb core will disable link pm in device resume before device reset, which will
try to change the max exit latency, accessing the device contexts before they are re-allocated.

There is no need to zero (disable) the max exit latency when disabling hw lpm
for a freshly re-initialized xHC. So check that device context exists before
doing anything. The max exit latency will be set again after device reset when usb core
enables the link pm.
Reported-by: default avatarImre Deak <imre.deak@intel.com>
Tested-by: default avatarImre Deak <imre.deak@intel.com>
Cc: stable <stable@vger.kernel.org>
Signed-off-by: default avatarMathias Nyman <mathias.nyman@linux.intel.com>
Signed-off-by: default avatarGreg Kroah-Hartman <gregkh@linuxfoundation.org>
parent 0eda06c7
...@@ -3971,13 +3971,21 @@ static int __maybe_unused xhci_change_max_exit_latency(struct xhci_hcd *xhci, ...@@ -3971,13 +3971,21 @@ static int __maybe_unused xhci_change_max_exit_latency(struct xhci_hcd *xhci,
int ret; int ret;
spin_lock_irqsave(&xhci->lock, flags); spin_lock_irqsave(&xhci->lock, flags);
if (max_exit_latency == xhci->devs[udev->slot_id]->current_mel) {
virt_dev = xhci->devs[udev->slot_id];
/*
* virt_dev might not exists yet if xHC resumed from hibernate (S4) and
* xHC was re-initialized. Exit latency will be set later after
* hub_port_finish_reset() is done and xhci->devs[] are re-allocated
*/
if (!virt_dev || max_exit_latency == virt_dev->current_mel) {
spin_unlock_irqrestore(&xhci->lock, flags); spin_unlock_irqrestore(&xhci->lock, flags);
return 0; return 0;
} }
/* Attempt to issue an Evaluate Context command to change the MEL. */ /* Attempt to issue an Evaluate Context command to change the MEL. */
virt_dev = xhci->devs[udev->slot_id];
command = xhci->lpm_command; command = xhci->lpm_command;
ctrl_ctx = xhci_get_input_control_ctx(xhci, command->in_ctx); ctrl_ctx = xhci_get_input_control_ctx(xhci, command->in_ctx);
if (!ctrl_ctx) { if (!ctrl_ctx) {
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment