提交 5c15c9a6 编写于 作者: G Greg Kroah-Hartman

Merge tag 'for-usb-linus-2012-04-11' of...

Merge tag 'for-usb-linus-2012-04-11' of git://git.kernel.org/pub/scm/linux/kernel/git/sarah/xhci into usb-linus

Hi Greg,

Here's 11 xHCI bug fixes for 3.4.

Some of the patches fix issues with crashes on system resume related to
VIA xHCI host controllers accessing bad memory addresses.  The patches
change the register restore ordering, so I had several vendors confirm
that the patches don't break their xHCI hosts.

Elric Fu confirms this patchset fixes the VIA issue, Alex He confirms
the changes does not break suspend/resume on AMD xHCI systems, and I've
made sure it doesn't break Intel host controllers.  I have not heard
back from Felipe about the TI host, so at this point, I'm just going to
send them off.

Several of the patches are marked for stable.  Please pull.

Sarah Sharp
...@@ -3163,6 +3163,22 @@ hub_port_init (struct usb_hub *hub, struct usb_device *udev, int port1, ...@@ -3163,6 +3163,22 @@ hub_port_init (struct usb_hub *hub, struct usb_device *udev, int port1,
if (retval) if (retval)
goto fail; goto fail;
/*
* Some superspeed devices have finished the link training process
* and attached to a superspeed hub port, but the device descriptor
* got from those devices show they aren't superspeed devices. Warm
* reset the port attached by the devices can fix them.
*/
if ((udev->speed == USB_SPEED_SUPER) &&
(le16_to_cpu(udev->descriptor.bcdUSB) < 0x0300)) {
dev_err(&udev->dev, "got a wrong device descriptor, "
"warm reset device\n");
hub_port_reset(hub, port1, udev,
HUB_BH_RESET_TIME, true);
retval = -EINVAL;
goto fail;
}
if (udev->descriptor.bMaxPacketSize0 == 0xff || if (udev->descriptor.bMaxPacketSize0 == 0xff ||
udev->speed == USB_SPEED_SUPER) udev->speed == USB_SPEED_SUPER)
i = 512; i = 512;
......
...@@ -825,9 +825,13 @@ static void __devinit quirk_usb_handoff_xhci(struct pci_dev *pdev) ...@@ -825,9 +825,13 @@ static void __devinit quirk_usb_handoff_xhci(struct pci_dev *pdev)
} }
} }
/* Disable any BIOS SMIs */ val = readl(base + ext_cap_offset + XHCI_LEGACY_CONTROL_OFFSET);
writel(XHCI_LEGACY_DISABLE_SMI, /* Mask off (turn off) any enabled SMIs */
base + ext_cap_offset + XHCI_LEGACY_CONTROL_OFFSET); val &= XHCI_LEGACY_DISABLE_SMI;
/* Mask all SMI events bits, RW1C */
val |= XHCI_LEGACY_SMI_EVENTS;
/* Disable any BIOS SMIs and clear all SMI events*/
writel(val, base + ext_cap_offset + XHCI_LEGACY_CONTROL_OFFSET);
if (usb_is_intel_switchable_xhci(pdev)) if (usb_is_intel_switchable_xhci(pdev))
usb_enable_xhci_ports(pdev); usb_enable_xhci_ports(pdev);
......
...@@ -119,7 +119,7 @@ static void xhci_print_command_reg(struct xhci_hcd *xhci) ...@@ -119,7 +119,7 @@ static void xhci_print_command_reg(struct xhci_hcd *xhci)
xhci_dbg(xhci, " Event Interrupts %s\n", xhci_dbg(xhci, " Event Interrupts %s\n",
(temp & CMD_EIE) ? "enabled " : "disabled"); (temp & CMD_EIE) ? "enabled " : "disabled");
xhci_dbg(xhci, " Host System Error Interrupts %s\n", xhci_dbg(xhci, " Host System Error Interrupts %s\n",
(temp & CMD_EIE) ? "enabled " : "disabled"); (temp & CMD_HSEIE) ? "enabled " : "disabled");
xhci_dbg(xhci, " HC has %sfinished light reset\n", xhci_dbg(xhci, " HC has %sfinished light reset\n",
(temp & CMD_LRESET) ? "not " : ""); (temp & CMD_LRESET) ? "not " : "");
} }
......
...@@ -62,8 +62,9 @@ ...@@ -62,8 +62,9 @@
/* USB Legacy Support Control and Status Register - section 7.1.2 */ /* USB Legacy Support Control and Status Register - section 7.1.2 */
/* Add this offset, plus the value of xECP in HCCPARAMS to the base address */ /* Add this offset, plus the value of xECP in HCCPARAMS to the base address */
#define XHCI_LEGACY_CONTROL_OFFSET (0x04) #define XHCI_LEGACY_CONTROL_OFFSET (0x04)
/* bits 1:2, 5:12, and 17:19 need to be preserved; bits 21:28 should be zero */ /* bits 1:3, 5:12, and 17:19 need to be preserved; bits 21:28 should be zero */
#define XHCI_LEGACY_DISABLE_SMI ((0x3 << 1) + (0xff << 5) + (0x7 << 17)) #define XHCI_LEGACY_DISABLE_SMI ((0x7 << 1) + (0xff << 5) + (0x7 << 17))
#define XHCI_LEGACY_SMI_EVENTS (0x7 << 29)
/* USB 2.0 xHCI 0.96 L1C capability - section 7.2.2.1.3.2 */ /* USB 2.0 xHCI 0.96 L1C capability - section 7.2.2.1.3.2 */
#define XHCI_L1C (1 << 16) #define XHCI_L1C (1 << 16)
......
...@@ -1796,11 +1796,6 @@ void xhci_mem_cleanup(struct xhci_hcd *xhci) ...@@ -1796,11 +1796,6 @@ void xhci_mem_cleanup(struct xhci_hcd *xhci)
int i; int i;
/* Free the Event Ring Segment Table and the actual Event Ring */ /* Free the Event Ring Segment Table and the actual Event Ring */
if (xhci->ir_set) {
xhci_writel(xhci, 0, &xhci->ir_set->erst_size);
xhci_write_64(xhci, 0, &xhci->ir_set->erst_base);
xhci_write_64(xhci, 0, &xhci->ir_set->erst_dequeue);
}
size = sizeof(struct xhci_erst_entry)*(xhci->erst.num_entries); size = sizeof(struct xhci_erst_entry)*(xhci->erst.num_entries);
if (xhci->erst.entries) if (xhci->erst.entries)
dma_free_coherent(&pdev->dev, size, dma_free_coherent(&pdev->dev, size,
...@@ -1812,7 +1807,6 @@ void xhci_mem_cleanup(struct xhci_hcd *xhci) ...@@ -1812,7 +1807,6 @@ void xhci_mem_cleanup(struct xhci_hcd *xhci)
xhci->event_ring = NULL; xhci->event_ring = NULL;
xhci_dbg(xhci, "Freed event ring\n"); xhci_dbg(xhci, "Freed event ring\n");
xhci_write_64(xhci, 0, &xhci->op_regs->cmd_ring);
if (xhci->cmd_ring) if (xhci->cmd_ring)
xhci_ring_free(xhci, xhci->cmd_ring); xhci_ring_free(xhci, xhci->cmd_ring);
xhci->cmd_ring = NULL; xhci->cmd_ring = NULL;
...@@ -1841,7 +1835,6 @@ void xhci_mem_cleanup(struct xhci_hcd *xhci) ...@@ -1841,7 +1835,6 @@ void xhci_mem_cleanup(struct xhci_hcd *xhci)
xhci->medium_streams_pool = NULL; xhci->medium_streams_pool = NULL;
xhci_dbg(xhci, "Freed medium stream array pool\n"); xhci_dbg(xhci, "Freed medium stream array pool\n");
xhci_write_64(xhci, 0, &xhci->op_regs->dcbaa_ptr);
if (xhci->dcbaa) if (xhci->dcbaa)
dma_free_coherent(&pdev->dev, sizeof(*xhci->dcbaa), dma_free_coherent(&pdev->dev, sizeof(*xhci->dcbaa),
xhci->dcbaa, xhci->dcbaa->dma); xhci->dcbaa, xhci->dcbaa->dma);
...@@ -2459,6 +2452,8 @@ int xhci_mem_init(struct xhci_hcd *xhci, gfp_t flags) ...@@ -2459,6 +2452,8 @@ int xhci_mem_init(struct xhci_hcd *xhci, gfp_t flags)
fail: fail:
xhci_warn(xhci, "Couldn't initialize memory\n"); xhci_warn(xhci, "Couldn't initialize memory\n");
xhci_halt(xhci);
xhci_reset(xhci);
xhci_mem_cleanup(xhci); xhci_mem_cleanup(xhci);
return -ENOMEM; return -ENOMEM;
} }
...@@ -95,6 +95,8 @@ static void xhci_pci_quirks(struct device *dev, struct xhci_hcd *xhci) ...@@ -95,6 +95,8 @@ static void xhci_pci_quirks(struct device *dev, struct xhci_hcd *xhci)
xhci->quirks |= XHCI_RESET_ON_RESUME; xhci->quirks |= XHCI_RESET_ON_RESUME;
xhci_dbg(xhci, "QUIRK: Resetting on resume\n"); xhci_dbg(xhci, "QUIRK: Resetting on resume\n");
} }
if (pdev->vendor == PCI_VENDOR_ID_VIA)
xhci->quirks |= XHCI_RESET_ON_RESUME;
} }
/* called during probe() after chip reset completes */ /* called during probe() after chip reset completes */
...@@ -326,7 +328,7 @@ int __init xhci_register_pci(void) ...@@ -326,7 +328,7 @@ int __init xhci_register_pci(void)
return pci_register_driver(&xhci_pci_driver); return pci_register_driver(&xhci_pci_driver);
} }
void __exit xhci_unregister_pci(void) void xhci_unregister_pci(void)
{ {
pci_unregister_driver(&xhci_pci_driver); pci_unregister_driver(&xhci_pci_driver);
} }
...@@ -2417,7 +2417,7 @@ irqreturn_t xhci_irq(struct usb_hcd *hcd) ...@@ -2417,7 +2417,7 @@ irqreturn_t xhci_irq(struct usb_hcd *hcd)
u32 irq_pending; u32 irq_pending;
/* Acknowledge the PCI interrupt */ /* Acknowledge the PCI interrupt */
irq_pending = xhci_readl(xhci, &xhci->ir_set->irq_pending); irq_pending = xhci_readl(xhci, &xhci->ir_set->irq_pending);
irq_pending |= 0x3; irq_pending |= IMAN_IP;
xhci_writel(xhci, irq_pending, &xhci->ir_set->irq_pending); xhci_writel(xhci, irq_pending, &xhci->ir_set->irq_pending);
} }
...@@ -2734,7 +2734,7 @@ int xhci_queue_intr_tx(struct xhci_hcd *xhci, gfp_t mem_flags, ...@@ -2734,7 +2734,7 @@ int xhci_queue_intr_tx(struct xhci_hcd *xhci, gfp_t mem_flags,
urb->dev->speed == USB_SPEED_FULL) urb->dev->speed == USB_SPEED_FULL)
urb->interval /= 8; urb->interval /= 8;
} }
return xhci_queue_bulk_tx(xhci, GFP_ATOMIC, urb, slot_id, ep_index); return xhci_queue_bulk_tx(xhci, mem_flags, urb, slot_id, ep_index);
} }
/* /*
...@@ -3514,7 +3514,7 @@ int xhci_queue_isoc_tx_prepare(struct xhci_hcd *xhci, gfp_t mem_flags, ...@@ -3514,7 +3514,7 @@ int xhci_queue_isoc_tx_prepare(struct xhci_hcd *xhci, gfp_t mem_flags,
} }
ep_ring->num_trbs_free_temp = ep_ring->num_trbs_free; ep_ring->num_trbs_free_temp = ep_ring->num_trbs_free;
return xhci_queue_isoc_tx(xhci, GFP_ATOMIC, urb, slot_id, ep_index); return xhci_queue_isoc_tx(xhci, mem_flags, urb, slot_id, ep_index);
} }
/**** Command Ring Operations ****/ /**** Command Ring Operations ****/
......
...@@ -106,6 +106,9 @@ int xhci_halt(struct xhci_hcd *xhci) ...@@ -106,6 +106,9 @@ int xhci_halt(struct xhci_hcd *xhci)
STS_HALT, STS_HALT, XHCI_MAX_HALT_USEC); STS_HALT, STS_HALT, XHCI_MAX_HALT_USEC);
if (!ret) if (!ret)
xhci->xhc_state |= XHCI_STATE_HALTED; xhci->xhc_state |= XHCI_STATE_HALTED;
else
xhci_warn(xhci, "Host not halted after %u microseconds.\n",
XHCI_MAX_HALT_USEC);
return ret; return ret;
} }
...@@ -664,11 +667,11 @@ static void xhci_save_registers(struct xhci_hcd *xhci) ...@@ -664,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.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.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.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_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_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.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) static void xhci_restore_registers(struct xhci_hcd *xhci)
...@@ -677,10 +680,11 @@ static void xhci_restore_registers(struct xhci_hcd *xhci) ...@@ -677,10 +680,11 @@ static void xhci_restore_registers(struct xhci_hcd *xhci)
xhci_writel(xhci, xhci->s3.dev_nt, &xhci->op_regs->dev_notification); 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_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.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_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_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) static void xhci_set_cmd_ring_deq(struct xhci_hcd *xhci)
......
...@@ -205,6 +205,10 @@ struct xhci_op_regs { ...@@ -205,6 +205,10 @@ struct xhci_op_regs {
#define CMD_PM_INDEX (1 << 11) #define CMD_PM_INDEX (1 << 11)
/* bits 12:31 are reserved (and should be preserved on writes). */ /* bits 12:31 are reserved (and should be preserved on writes). */
/* IMAN - Interrupt Management Register */
#define IMAN_IP (1 << 1)
#define IMAN_IE (1 << 0)
/* USBSTS - USB status - status bitmasks */ /* USBSTS - USB status - status bitmasks */
/* HC not running - set to 1 when run/stop bit is cleared. */ /* HC not running - set to 1 when run/stop bit is cleared. */
#define STS_HALT XHCI_STS_HALT #define STS_HALT XHCI_STS_HALT
......
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册