Matthew, Can you help to test if this patch fix your xhci suspend and remove issue? Thanks. From: Andiry Xu Date: Mon, 6 Dec 2010 16:58:16 +0800 Subject: [PATCH] xHCI: synchronize interrupts in xhci_suspend() Matthew Garrett reports a interrupt double free in xHCI code when the host is suspended and then the card removed. Synchronize the interrupts instead of free them in xhci_suspned(). Reported-by: Matthew Garrett Signed-off-by: Andiry Xu --- drivers/usb/host/xhci.c | 37 +++++++++---------------------------- 1 file changed, 9 insertions(+), 28 deletions(-) Index: linux-2.6/drivers/usb/host/xhci.c =================================================================== --- linux-2.6.orig/drivers/usb/host/xhci.c +++ linux-2.6/drivers/usb/host/xhci.c @@ -646,7 +646,9 @@ int xhci_suspend(struct xhci_hcd *xhci) { int rc = 0; struct usb_hcd *hcd = xhci_to_hcd(xhci); + struct pci_dev *pdev = to_pci_dev(hcd->self.controller); u32 command; + int i; spin_lock_irq(&xhci->lock); clear_bit(HCD_FLAG_HW_ACCESSIBLE, &hcd->flags); @@ -678,9 +680,14 @@ int xhci_suspend(struct xhci_hcd *xhci) return -ETIMEDOUT; } /* step 5: remove core well power */ - xhci_cleanup_msix(xhci); spin_unlock_irq(&xhci->lock); + if (xhci->msix_entries) { + for (i = 0; i < xhci->msix_count; i++) + synchronize_irq(xhci->msix_entries[i].vector); + } else if (pdev->irq >= 0) + synchronize_irq(pdev->irq); + return rc; } @@ -694,7 +701,6 @@ int xhci_resume(struct xhci_hcd *xhci, b { u32 command, temp = 0; struct usb_hcd *hcd = xhci_to_hcd(xhci); - struct pci_dev *pdev = to_pci_dev(hcd->self.controller); int old_state, retval; old_state = hcd->state; @@ -729,8 +735,7 @@ int xhci_resume(struct xhci_hcd *xhci, b xhci_dbg(xhci, "Stop HCD\n"); xhci_halt(xhci); xhci_reset(xhci); - if (hibernated) - xhci_cleanup_msix(xhci); + xhci_cleanup_msix(xhci); spin_unlock_irq(&xhci->lock); #ifdef CONFIG_USB_XHCI_HCD_DEBUGGING @@ -765,30 +770,6 @@ int xhci_resume(struct xhci_hcd *xhci, b return retval; } - spin_unlock_irq(&xhci->lock); - /* Re-setup MSI-X */ - if (hcd->irq) - free_irq(hcd->irq, hcd); - hcd->irq = -1; - - retval = xhci_setup_msix(xhci); - if (retval) - /* fall back to msi*/ - retval = xhci_setup_msi(xhci); - - if (retval) { - /* fall back to legacy interrupt*/ - retval = request_irq(pdev->irq, &usb_hcd_irq, IRQF_SHARED, - hcd->irq_descr, hcd); - if (retval) { - xhci_err(xhci, "request interrupt %d failed\n", - pdev->irq); - return retval; - } - hcd->irq = pdev->irq; - } - - spin_lock_irq(&xhci->lock); /* step 4: set Run/Stop bit */ command = xhci_readl(xhci, &xhci->op_regs->command); command |= CMD_RUN;