xhci: Fix register save/restore order.

The xHCI 1.0 spec errata released on June 13, 2011, changes the ordering
that the xHCI registers are saved and restored in.  It moves the
interrupt pending (IMAN) and interrupt control (IMOD) registers to be
saved and restored last.  I believe that's because the host controller
may attempt to fetch the event ring table when interrupts are
re-enabled.  Therefore we need to restore the event ring registers
before we re-enable interrupts.

This should be backported to kernels as old as 2.6.37, that contain the
commit 5535b1d5f8 "USB: xHCI: PCI power
management implementation"

Signed-off-by: Sarah Sharp <sarah.a.sharp@linux.intel.com>
Tested-by: Elric Fu <elricfu1@gmail.com>
Cc: Andiry Xu <andiry.xu@amd.com>
Cc: stable@vger.kernel.org
This commit is contained in:
Sarah Sharp 2012-03-16 13:19:35 -07:00
parent fb3d85bc71
commit c7713e7365

View file

@ -667,11 +667,11 @@ static void xhci_save_registers(struct xhci_hcd *xhci)
xhci->s3.dev_nt = xhci_readl(xhci, &xhci->op_regs->dev_notification);
xhci->s3.dcbaa_ptr = xhci_read_64(xhci, &xhci->op_regs->dcbaa_ptr);
xhci->s3.config_reg = xhci_readl(xhci, &xhci->op_regs->config_reg);
xhci->s3.irq_pending = xhci_readl(xhci, &xhci->ir_set->irq_pending);
xhci->s3.irq_control = xhci_readl(xhci, &xhci->ir_set->irq_control);
xhci->s3.erst_size = xhci_readl(xhci, &xhci->ir_set->erst_size);
xhci->s3.erst_base = xhci_read_64(xhci, &xhci->ir_set->erst_base);
xhci->s3.erst_dequeue = xhci_read_64(xhci, &xhci->ir_set->erst_dequeue);
xhci->s3.irq_pending = xhci_readl(xhci, &xhci->ir_set->irq_pending);
xhci->s3.irq_control = xhci_readl(xhci, &xhci->ir_set->irq_control);
}
static void xhci_restore_registers(struct xhci_hcd *xhci)
@ -680,11 +680,11 @@ static void xhci_restore_registers(struct xhci_hcd *xhci)
xhci_writel(xhci, xhci->s3.dev_nt, &xhci->op_regs->dev_notification);
xhci_write_64(xhci, xhci->s3.dcbaa_ptr, &xhci->op_regs->dcbaa_ptr);
xhci_writel(xhci, xhci->s3.config_reg, &xhci->op_regs->config_reg);
xhci_writel(xhci, xhci->s3.irq_pending, &xhci->ir_set->irq_pending);
xhci_writel(xhci, xhci->s3.irq_control, &xhci->ir_set->irq_control);
xhci_writel(xhci, xhci->s3.erst_size, &xhci->ir_set->erst_size);
xhci_write_64(xhci, xhci->s3.erst_base, &xhci->ir_set->erst_base);
xhci_write_64(xhci, xhci->s3.erst_dequeue, &xhci->ir_set->erst_dequeue);
xhci_writel(xhci, xhci->s3.irq_pending, &xhci->ir_set->irq_pending);
xhci_writel(xhci, xhci->s3.irq_control, &xhci->ir_set->irq_control);
}
static void xhci_set_cmd_ring_deq(struct xhci_hcd *xhci)