From bcca06efea883bdf3803a0bb0ffa60f26730387d Mon Sep 17 00:00:00 2001 From: Alan Stern Date: Tue, 13 Jan 2009 11:35:54 -0500 Subject: USB: don't enable wakeup by default for PCI host controllers This patch (as1199) changes the initial wakeup settings for PCI USB host controllers. The controllers are marked as capable of waking the system, but wakeup is not enabled by default. It turns out that enabling wakeup for USB host controllers has a lot of bad consequences. As the simplest example, if a USB mouse or keyboard is unplugged immediately after the computer is put to sleep, the unplug will cause the system to wake back up again! We are better off marking them as wakeup-capable and leaving wakeup disabled. Signed-off-by: Alan Stern Reported-by: Rafael J. Wysocki CC: David Brownell Cc: stable Signed-off-by: Greg Kroah-Hartman --- drivers/usb/core/hcd-pci.c | 1 - 1 file changed, 1 deletion(-) (limited to 'drivers/usb/core/hcd-pci.c') diff --git a/drivers/usb/core/hcd-pci.c b/drivers/usb/core/hcd-pci.c index 507741ed448..99432785f43 100644 --- a/drivers/usb/core/hcd-pci.c +++ b/drivers/usb/core/hcd-pci.c @@ -128,7 +128,6 @@ int usb_hcd_pci_probe(struct pci_dev *dev, const struct pci_device_id *id) } pci_set_master(dev); - device_set_wakeup_enable(&dev->dev, 1); retval = usb_add_hcd(hcd, dev->irq, IRQF_DISABLED | IRQF_SHARED); if (retval != 0) -- cgit v1.2.3 From a15d95a003fae154121733f049dd25e9c13dbef3 Mon Sep 17 00:00:00 2001 From: "Rafael J. Wysocki" Date: Tue, 20 Jan 2009 01:26:56 +0100 Subject: USB: Fix suspend-resume of PCI USB controllers Commit a0d4922da2e4ccb0973095d8d29f36f6b1b5f703 (USB: fix up suspend and resume for PCI host controllers) attempted to fix the suspend-resume of PCI USB controllers, but unfortunately it did that incorrectly and interrupts are left enabled by the USB controllers' ->suspend_late() callback as a result. This leads to serious problems during suspend which are very difficult to debug. Fix the issue by removing the ->suspend_late() callback of PCI USB controllers and moving the code from there to the ->suspend() callback executed with interrupts enabled. Additionally, make the ->resume() callback of PCI USB controllers execute pci_enable_wake(dev, PCI_D0, false) to disable wake-up from the full power state (PCI_D0). Signed-off-by: Rafael J. Wysocki Tested-by: Andrey Borzenkov Tested-by: "Jeff Chua" Cc: Alan Stern Cc: Andrew Morton Cc: Christian Borntraeger Cc: "Zdenek Kabelac" Cc: Ingo Molnar Signed-off-by: Greg Kroah-Hartman --- drivers/usb/core/hcd-pci.c | 116 +++++++++++---------------------------------- 1 file changed, 27 insertions(+), 89 deletions(-) (limited to 'drivers/usb/core/hcd-pci.c') diff --git a/drivers/usb/core/hcd-pci.c b/drivers/usb/core/hcd-pci.c index 99432785f43..c54fc40458b 100644 --- a/drivers/usb/core/hcd-pci.c +++ b/drivers/usb/core/hcd-pci.c @@ -200,6 +200,7 @@ int usb_hcd_pci_suspend(struct pci_dev *dev, pm_message_t message) struct usb_hcd *hcd = pci_get_drvdata(dev); int retval = 0; int wake, w; + int has_pci_pm; /* Root hub suspend should have stopped all downstream traffic, * and all bus master traffic. And done so for both the interface @@ -229,6 +230,15 @@ int usb_hcd_pci_suspend(struct pci_dev *dev, pm_message_t message) synchronize_irq(dev->irq); + /* Downstream ports from this root hub should already be quiesced, so + * there will be no DMA activity. Now we can shut down the upstream + * link (except maybe for PME# resume signaling) and enter some PCI + * low power state, if the hardware allows. + */ + pci_disable_device(dev); + + pci_save_state(dev); + /* Don't fail on error to enable wakeup. We rely on pci code * to reject requests the hardware can't implement, rather * than coding the same thing. @@ -240,35 +250,6 @@ int usb_hcd_pci_suspend(struct pci_dev *dev, pm_message_t message) wake = w; dev_dbg(&dev->dev, "wakeup: %d\n", wake); - /* Downstream ports from this root hub should already be quiesced, so - * there will be no DMA activity. Now we can shut down the upstream - * link (except maybe for PME# resume signaling) and enter some PCI - * low power state, if the hardware allows. - */ - pci_disable_device(dev); - done: - return retval; -} -EXPORT_SYMBOL_GPL(usb_hcd_pci_suspend); - -/** - * usb_hcd_pci_suspend_late - suspend a PCI-based HCD after IRQs are disabled - * @dev: USB Host Controller being suspended - * @message: Power Management message describing this state transition - * - * Store this function in the HCD's struct pci_driver as .suspend_late. - */ -int usb_hcd_pci_suspend_late(struct pci_dev *dev, pm_message_t message) -{ - int retval = 0; - int has_pci_pm; - - /* We might already be suspended (runtime PM -- not yet written) */ - if (dev->current_state != PCI_D0) - goto done; - - pci_save_state(dev); - /* Don't change state if we don't need to */ if (message.event == PM_EVENT_FREEZE || message.event == PM_EVENT_PRETHAW) { @@ -314,7 +295,7 @@ int usb_hcd_pci_suspend_late(struct pci_dev *dev, pm_message_t message) done: return retval; } -EXPORT_SYMBOL_GPL(usb_hcd_pci_suspend_late); +EXPORT_SYMBOL_GPL(usb_hcd_pci_suspend); /** * usb_hcd_pci_resume_early - resume a PCI-based HCD before IRQs are enabled @@ -324,65 +305,8 @@ EXPORT_SYMBOL_GPL(usb_hcd_pci_suspend_late); */ int usb_hcd_pci_resume_early(struct pci_dev *dev) { - int retval = 0; - pci_power_t state = dev->current_state; - -#ifdef CONFIG_PPC_PMAC - /* Reenable ASIC clocks for USB */ - if (machine_is(powermac)) { - struct device_node *of_node; - - of_node = pci_device_to_OF_node(dev); - if (of_node) - pmac_call_feature(PMAC_FTR_USB_ENABLE, - of_node, 0, 1); - } -#endif - - /* NOTE: chip docs cover clean "real suspend" cases (what Linux - * calls "standby", "suspend to RAM", and so on). There are also - * dirty cases when swsusp fakes a suspend in "shutdown" mode. - */ - if (state != PCI_D0) { -#ifdef DEBUG - int pci_pm; - u16 pmcr; - - pci_pm = pci_find_capability(dev, PCI_CAP_ID_PM); - pci_read_config_word(dev, pci_pm + PCI_PM_CTRL, &pmcr); - pmcr &= PCI_PM_CTRL_STATE_MASK; - if (pmcr) { - /* Clean case: power to USB and to HC registers was - * maintained; remote wakeup is easy. - */ - dev_dbg(&dev->dev, "resume from PCI D%d\n", pmcr); - } else { - /* Clean: HC lost Vcc power, D0 uninitialized - * + Vaux may have preserved port and transceiver - * state ... for remote wakeup from D3cold - * + or not; HCD must reinit + re-enumerate - * - * Dirty: D0 semi-initialized cases with swsusp - * + after BIOS init - * + after Linux init (HCD statically linked) - */ - dev_dbg(&dev->dev, "resume from previous PCI D%d\n", - state); - } -#endif - - retval = pci_set_power_state(dev, PCI_D0); - } else { - /* Same basic cases: clean (powered/not), dirty */ - dev_dbg(&dev->dev, "PCI legacy resume\n"); - } - - if (retval < 0) - dev_err(&dev->dev, "can't resume: %d\n", retval); - else - pci_restore_state(dev); - - return retval; + pci_restore_state(dev); + return 0; } EXPORT_SYMBOL_GPL(usb_hcd_pci_resume_early); @@ -397,6 +321,18 @@ int usb_hcd_pci_resume(struct pci_dev *dev) struct usb_hcd *hcd; int retval; +#ifdef CONFIG_PPC_PMAC + /* Reenable ASIC clocks for USB */ + if (machine_is(powermac)) { + struct device_node *of_node; + + of_node = pci_device_to_OF_node(dev); + if (of_node) + pmac_call_feature(PMAC_FTR_USB_ENABLE, + of_node, 0, 1); + } +#endif + hcd = pci_get_drvdata(dev); if (hcd->state != HC_STATE_SUSPENDED) { dev_dbg(hcd->self.controller, @@ -404,6 +340,8 @@ int usb_hcd_pci_resume(struct pci_dev *dev) return 0; } + pci_enable_wake(dev, PCI_D0, false); + retval = pci_enable_device(dev); if (retval < 0) { dev_err(&dev->dev, "can't re-enable after resume, %d!\n", -- cgit v1.2.3