aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/usb/host/ehci-pci.c
diff options
context:
space:
mode:
authorBenjamin Herrenschmidt <benh@kernel.crashing.org>2005-11-24 17:59:46 -0500
committerGreg Kroah-Hartman <gregkh@suse.de>2005-11-30 00:39:23 -0500
commit8de98402652c01839ae321be6cb3054cf5735d83 (patch)
tree6d4856ddb60be0dcd361441f0794596709553dd1 /drivers/usb/host/ehci-pci.c
parentd3420ba4930d61f4ec4abc046765de274182b4ed (diff)
[PATCH] USB: Fix USB suspend/resume crasher (#2)
This patch closes the IRQ race and makes various other OHCI & EHCI code path safer vs. suspend/resume. I've been able to (finally !) successfully suspend and resume various Mac models, with or without USB mouse plugged, or plugging while asleep, or unplugging while asleep etc... all without a crash. Alan, please verify the UHCI bit I did, I only verified that it builds. It's very simple so I wouldn't expect any issue there. If you aren't confident, then just drop the hunks that change uhci-hcd.c I also made the patch a little bit more "safer" by making sure the store to the interrupt register that disables interrupts is not posted before I set the flag and drop the spinlock. Without this patch, you cannot reliably sleep/wakeup any recent Mac, and I suspect PCs have some more sneaky issues too (they don't frankly crash with machine checks because x86 tend to silently swallow PCI errors but that won't last afaik, at least PCI Express will blow up in those situations, but the USB code may still misbehave). Signed-off-by: Benjamin Herrenschmidt <benh@kernel.crashing.org> Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de> Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de>
Diffstat (limited to 'drivers/usb/host/ehci-pci.c')
-rw-r--r--drivers/usb/host/ehci-pci.c27
1 files changed, 26 insertions, 1 deletions
diff --git a/drivers/usb/host/ehci-pci.c b/drivers/usb/host/ehci-pci.c
index 441c26064b44..14fff5714c1e 100644
--- a/drivers/usb/host/ehci-pci.c
+++ b/drivers/usb/host/ehci-pci.c
@@ -228,14 +228,36 @@ static int ehci_pci_reset(struct usb_hcd *hcd)
228static int ehci_pci_suspend(struct usb_hcd *hcd, pm_message_t message) 228static int ehci_pci_suspend(struct usb_hcd *hcd, pm_message_t message)
229{ 229{
230 struct ehci_hcd *ehci = hcd_to_ehci(hcd); 230 struct ehci_hcd *ehci = hcd_to_ehci(hcd);
231 unsigned long flags;
232 int rc = 0;
231 233
232 if (time_before(jiffies, ehci->next_statechange)) 234 if (time_before(jiffies, ehci->next_statechange))
233 msleep(10); 235 msleep(10);
234 236
237 /* Root hub was already suspended. Disable irq emission and
238 * mark HW unaccessible, bail out if RH has been resumed. Use
239 * the spinlock to properly synchronize with possible pending
240 * RH suspend or resume activity.
241 *
242 * This is still racy as hcd->state is manipulated outside of
243 * any locks =P But that will be a different fix.
244 */
245 spin_lock_irqsave (&ehci->lock, flags);
246 if (hcd->state != HC_STATE_SUSPENDED) {
247 rc = -EINVAL;
248 goto bail;
249 }
250 writel (0, &ehci->regs->intr_enable);
251 (void)readl(&ehci->regs->intr_enable);
252
253 clear_bit(HCD_FLAG_HW_ACCESSIBLE, &hcd->flags);
254 bail:
255 spin_unlock_irqrestore (&ehci->lock, flags);
256
235 // could save FLADJ in case of Vaux power loss 257 // could save FLADJ in case of Vaux power loss
236 // ... we'd only use it to handle clock skew 258 // ... we'd only use it to handle clock skew
237 259
238 return 0; 260 return rc;
239} 261}
240 262
241static int ehci_pci_resume(struct usb_hcd *hcd) 263static int ehci_pci_resume(struct usb_hcd *hcd)
@@ -251,6 +273,9 @@ static int ehci_pci_resume(struct usb_hcd *hcd)
251 if (time_before(jiffies, ehci->next_statechange)) 273 if (time_before(jiffies, ehci->next_statechange))
252 msleep(100); 274 msleep(100);
253 275
276 /* Mark hardware accessible again as we are out of D3 state by now */
277 set_bit(HCD_FLAG_HW_ACCESSIBLE, &hcd->flags);
278
254 /* If CF is clear, we lost PCI Vaux power and need to restart. */ 279 /* If CF is clear, we lost PCI Vaux power and need to restart. */
255 if (readl(&ehci->regs->configured_flag) != FLAG_CF) 280 if (readl(&ehci->regs->configured_flag) != FLAG_CF)
256 goto restart; 281 goto restart;