History

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).

Alan Stern committed 14 years ago

Commit c2fb8a31 parent 0ef0be16 files · +33 −19Browse files

Unified · Split

6 files
  1. drivers/pci/pci.c +5 −0
  2. drivers/pci/quirks.c +26 −0
  3. drivers/usb/core/hcd-pci.c +0 −9
  4. drivers/usb/host/ehci-pci.c +0 −8
  5. include/linux/pci.h +2 −0
  6. include/linux/usb/hcd.h +0 −2
drivers/pci/pci.c+5−0
@@ -1744,6 +1744,11 @@ int pci_prepare_to_sleep(struct pci_dev *dev) · 1743 unmodified lines
17441744 if (target_state == PCI_POWER_ERROR)
17451745 return -EIO;
17461746
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+
17471752 pci_enable_wake(dev, target_state, device_may_wakeup(&dev->dev));
17481753
17491754 error = pci_set_power_state(dev, target_state);
drivers/pci/quirks.c+26−0
@@ -2929,6 +2929,32 @@ static void __devinit disable_igfx_irq(struct pci_dev *dev) · 2928 unmodified lines
29292929 DECLARE_PCI_FIXUP_FINAL(PCI_VENDOR_ID_INTEL, 0x0102, disable_igfx_irq);
29302930 DECLARE_PCI_FIXUP_FINAL(PCI_VENDOR_ID_INTEL, 0x010a, disable_igfx_irq);
29312931
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+ */
2937+static 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+}
2955+DECLARE_PCI_FIXUP_FINAL(PCI_VENDOR_ID_INTEL, 0x1c26, asus_ehci_no_d3);
2956+DECLARE_PCI_FIXUP_FINAL(PCI_VENDOR_ID_INTEL, 0x1c2d, asus_ehci_no_d3);
2957+
29322958 static void pci_do_fixups(struct pci_dev *dev, struct pci_fixup *f,
29332959 struct pci_fixup *end)
29342960 {
drivers/usb/core/hcd-pci.c+0−9
@@ -493,15 +493,6 @@ static int hcd_pci_suspend_noirq(struct device *dev) · 492 unmodified lines
493493
494494 pci_save_state(pci_dev);
495495
496− /*
497− * Some systems crash if an EHCI controller is in D3 during
498− * a sleep transition. We have to leave such controllers in D0.
499− */
500− if (hcd->broken_pci_sleep) {
501− dev_dbg(dev, "Staying in PCI D0\n");
502− return retval;
503− }
504−
505496 /* If the root hub is dead rather than suspended, disallow remote
506497 * wakeup. usb_hc_died() should ensure that both hosts are marked as
507498 * dying, so we only need to check the primary roothub.
drivers/usb/host/ehci-pci.c+0−8
@@ -144,14 +144,6 @@ static int ehci_pci_setup(struct usb_hcd *hcd) · 143 unmodified lines
144144 hcd->has_tt = 1;
145145 tdi_reset(ehci);
146146 }
147− if (pdev->subsystem_vendor == PCI_VENDOR_ID_ASUSTEK) {
148− /* EHCI #1 or #2 on 6 Series/C200 Series chipset */
149− if (pdev->device == 0x1c26 || pdev->device == 0x1c2d) {
150− ehci_info(ehci, "broken D3 during system sleep on ASUS\n");
151− hcd->broken_pci_sleep = 1;
152− device_set_wakeup_capable(&pdev->dev, false);
153− }
154− }
155147 break;
156148 case PCI_VENDOR_ID_TDI:
157149 if (pdev->device == PCI_DEVICE_ID_TDI_EHCI) {
include/linux/pci.h+2−0
@@ -176,6 +176,8 @@ enum pci_dev_flags { · 175 unmodified lines
176176 PCI_DEV_FLAGS_NO_D3 = (__force pci_dev_flags_t) 2,
177177 /* Provide indication device is assigned by a Virtual Machine Manager */
178178 PCI_DEV_FLAGS_ASSIGNED = (__force pci_dev_flags_t) 4,
179+ /* Device causes system crash if in D3 during S3 sleep */
180+ PCI_DEV_FLAGS_NO_D3_DURING_SLEEP = (__force pci_dev_flags_t) 8,
179181 };
180182
181183 enum pci_irq_reroute_variant {
include/linux/usb/hcd.h+0−2
@@ -126,8 +126,6 @@ struct usb_hcd { · 125 unmodified lines
126126 unsigned wireless:1; /* Wireless USB HCD */
127127 unsigned authorized_default:1;
128128 unsigned has_tt:1; /* Integrated TT in root hub */
129− unsigned broken_pci_sleep:1; /* Don't put the
130− controller in PCI-D3 for system sleep */
131129
132130 unsigned int irq; /* irq allocated */
133131 void __iomem *regs; /* device memory/io */