aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/pci
diff options
context:
space:
mode:
authorAlan Stern <stern@rowland.harvard.edu>2012-06-13 11:20:19 -0400
committerGreg Kroah-Hartman <gregkh@linuxfoundation.org>2012-06-13 16:11:39 -0400
commitc2fb8a3fa25513de8fedb38509b1f15a5bbee47b (patch)
tree069d6f8ea3851f5fe559fab8712dd55c58a65db5 /drivers/pci
parent0ef0be15fd2564767f114c249fc4af704d8e16f4 (diff)
USB: add NO_D3_DURING_SLEEP flag and revert 151b61284776be2
This patch (as1558) fixes a problem affecting several ASUS computers: The machine crashes or corrupts memory when going into suspend if the ehci-hcd driver is bound to any controllers. Users have been forced to unbind or unload ehci-hcd before putting their systems to sleep. After extensive testing, it was determined that the machines don't like going into suspend when any EHCI controllers are in the PCI D3 power state. Presumably this is a firmware bug, but there's nothing we can do about it except to avoid putting the controllers in D3 during system sleep. The patch adds a new flag to indicate whether the problem is present, and avoids changing the controller's power state if the flag is set. Runtime suspend is unaffected; this matters only for system suspend. However as a side effect, the controller will not respond to remote wakeup requests while the system is asleep. Hence USB wakeup is not functional -- but of course, this is already true in the current state of affairs. A similar patch has already been applied as commit 151b61284776be2d6f02d48c23c3625678960b97 (USB: EHCI: fix crash during suspend on ASUS computers). The patch supersedes that one and reverts it. There are two differences: The old patch added the flag at the USB level; this patch adds it at the PCI level. The old patch applied to all chipsets with the same vendor, subsystem vendor, and product IDs; this patch makes an exception for a known-good system (based on DMI information). Signed-off-by: Alan Stern <stern@rowland.harvard.edu> Tested-by: Dâniel Fraga <fragabr@gmail.com> Tested-by: Andrey Rahmatullin <wrar@wrar.name> Tested-by: Steven Rostedt <rostedt@goodmis.org> Cc: stable <stable@vger.kernel.org> Reviewed-by: Rafael J. Wysocki <rjw@sisk.pl> Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
Diffstat (limited to 'drivers/pci')
-rw-r--r--drivers/pci/pci.c5
-rw-r--r--drivers/pci/quirks.c26
2 files changed, 31 insertions, 0 deletions
diff --git a/drivers/pci/pci.c b/drivers/pci/pci.c
index 447e83472c01..77cb54a65cde 100644
--- a/drivers/pci/pci.c
+++ b/drivers/pci/pci.c
@@ -1744,6 +1744,11 @@ int pci_prepare_to_sleep(struct pci_dev *dev)
1744 if (target_state == PCI_POWER_ERROR) 1744 if (target_state == PCI_POWER_ERROR)
1745 return -EIO; 1745 return -EIO;
1746 1746
1747 /* Some devices mustn't be in D3 during system sleep */
1748 if (target_state == PCI_D3hot &&
1749 (dev->dev_flags & PCI_DEV_FLAGS_NO_D3_DURING_SLEEP))
1750 return 0;
1751
1747 pci_enable_wake(dev, target_state, device_may_wakeup(&dev->dev)); 1752 pci_enable_wake(dev, target_state, device_may_wakeup(&dev->dev));
1748 1753
1749 error = pci_set_power_state(dev, target_state); 1754 error = pci_set_power_state(dev, target_state);
diff --git a/drivers/pci/quirks.c b/drivers/pci/quirks.c
index 2a7521677541..194b243a2817 100644
--- a/drivers/pci/quirks.c
+++ b/drivers/pci/quirks.c
@@ -2929,6 +2929,32 @@ static void __devinit disable_igfx_irq(struct pci_dev *dev)
2929DECLARE_PCI_FIXUP_FINAL(PCI_VENDOR_ID_INTEL, 0x0102, disable_igfx_irq); 2929DECLARE_PCI_FIXUP_FINAL(PCI_VENDOR_ID_INTEL, 0x0102, disable_igfx_irq);
2930DECLARE_PCI_FIXUP_FINAL(PCI_VENDOR_ID_INTEL, 0x010a, disable_igfx_irq); 2930DECLARE_PCI_FIXUP_FINAL(PCI_VENDOR_ID_INTEL, 0x010a, disable_igfx_irq);
2931 2931
2932/*
2933 * The Intel 6 Series/C200 Series chipset's EHCI controllers on many
2934 * ASUS motherboards will cause memory corruption or a system crash
2935 * if they are in D3 while the system is put into S3 sleep.
2936 */
2937static void __devinit asus_ehci_no_d3(struct pci_dev *dev)
2938{
2939 const char *sys_info;
2940 static const char good_Asus_board[] = "P8Z68-V";
2941
2942 if (dev->dev_flags & PCI_DEV_FLAGS_NO_D3_DURING_SLEEP)
2943 return;
2944 if (dev->subsystem_vendor != PCI_VENDOR_ID_ASUSTEK)
2945 return;
2946 sys_info = dmi_get_system_info(DMI_BOARD_NAME);
2947 if (sys_info && memcmp(sys_info, good_Asus_board,
2948 sizeof(good_Asus_board) - 1) == 0)
2949 return;
2950
2951 dev_info(&dev->dev, "broken D3 during system sleep on ASUS\n");
2952 dev->dev_flags |= PCI_DEV_FLAGS_NO_D3_DURING_SLEEP;
2953 device_set_wakeup_capable(&dev->dev, false);
2954}
2955DECLARE_PCI_FIXUP_FINAL(PCI_VENDOR_ID_INTEL, 0x1c26, asus_ehci_no_d3);
2956DECLARE_PCI_FIXUP_FINAL(PCI_VENDOR_ID_INTEL, 0x1c2d, asus_ehci_no_d3);
2957
2932static void pci_do_fixups(struct pci_dev *dev, struct pci_fixup *f, 2958static void pci_do_fixups(struct pci_dev *dev, struct pci_fixup *f,
2933 struct pci_fixup *end) 2959 struct pci_fixup *end)
2934{ 2960{