aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorMathias Nyman <mathias.nyman@linux.intel.com>2014-09-11 13:55:50 +0300
committerGreg Kroah-Hartman <gregkh@linuxfoundation.org>2014-10-05 14:54:10 -0700
commit1fdbb939b8b3fb23fd03ba617baca64458449966 (patch)
tree2f7fe02dc7220ba12bfa7654a6d1343a7badbc50
parent7aeede98bdbcbca2956822ce7a871e875663c6b6 (diff)
xhci: fix oops when xhci resumes from hibernate with hw lpm capable devices
commit 96044694b8511bc2b04df0776b4ba295cfe005c0 upstream. 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: Imre Deak <imre.deak@intel.com> Tested-by: Imre Deak <imre.deak@intel.com> Signed-off-by: Mathias Nyman <mathias.nyman@linux.intel.com> Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
-rw-r--r--drivers/usb/host/xhci.c12
1 files changed, 10 insertions, 2 deletions
diff --git a/drivers/usb/host/xhci.c b/drivers/usb/host/xhci.c
index 9a7088bc634d..10223f2b18d2 100644
--- a/drivers/usb/host/xhci.c
+++ b/drivers/usb/host/xhci.c
@@ -4407,13 +4407,21 @@ static int xhci_change_max_exit_latency(struct xhci_hcd *xhci,
int ret;
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);
return 0;
}
/* Attempt to issue an Evaluate Context command to change the MEL. */
- virt_dev = xhci->devs[udev->slot_id];
command = xhci->lpm_command;
xhci_slot_copy(xhci, command->in_ctx, virt_dev->out_ctx);
spin_unlock_irqrestore(&xhci->lock, flags);