case USB_PORT_FEAT_SUSPEND:
if (temp & PORT_RESET)
goto error;
+ if (ehci->no_selective_suspend)
+ break;
if (temp & PORT_SUSPEND) {
if ((temp & PORT_PE) == 0)
goto error;
temp &= ~PORT_RWC_BITS;
switch (wValue) {
case USB_PORT_FEAT_SUSPEND:
+ if (ehci->no_selective_suspend)
+ break;
if ((temp & PORT_PE) == 0
|| (temp & PORT_RESET) != 0)
goto error;
}
break;
case PCI_VENDOR_ID_NVIDIA:
+ switch (pdev->device) {
/* NVidia reports that certain chips don't handle
* QH, ITD, or SITD addresses above 2GB. (But TD,
* data buffer, and periodic schedule are normal.)
*/
- switch (pdev->device) {
case 0x003c: /* MCP04 */
case 0x005b: /* CK804 */
case 0x00d8: /* CK8 */
ehci_warn(ehci, "can't enable NVidia "
"workaround for >2GB RAM\n");
break;
+ /* Some NForce2 chips have problems with selective suspend;
+ * fixed in newer silicon.
+ */
+ case 0x0068:
+ pci_read_config_dword(pdev, PCI_REVISION_ID, &temp);
+ if ((temp & 0xff) < 0xa4)
+ ehci->no_selective_suspend = 1;
+ break;
}
break;
}
device_init_wakeup(&pdev->dev, 1);
}
+#ifdef CONFIG_USB_SUSPEND
+ /* REVISIT: the controller works fine for wakeup iff the root hub
+ * itself is "globally" suspended, but usbcore currently doesn't
+ * understand such things.
+ *
+ * System suspend currently expects to be able to suspend the entire
+ * device tree, device-at-a-time. If we failed selective suspend
+ * reports, system suspend would fail; so the root hub code must claim
+ * success. That's lying to usbcore, and it matters for for runtime
+ * PM scenarios with selective suspend and remote wakeup...
+ */
+ if (ehci->no_selective_suspend && device_can_wakeup(&pdev->dev))
+ ehci_warn(ehci, "selective suspend/wakeup unavailable\n");
+#endif
+
retval = ehci_pci_reinit(ehci, pdev);
done:
return retval;
u32 command;
unsigned is_tdi_rh_tt:1; /* TDI roothub with TT */
+ unsigned no_selective_suspend:1;
+ u8 sbrn; /* packed release number */
/* irq statistics */
#ifdef EHCI_STATS
#else
# define COUNT(x) do {} while (0)
#endif
- u8 sbrn; /* packed release number */
};
/* convert between an HCD pointer and the corresponding EHCI_HCD */