[linux-pm] ehci_hcd related S3 lockup on ASUS laptops, again

Alan Stern stern at rowland.harvard.edu
Mon Apr 16 20:07:10 UTC 2012


On Sat, 14 Apr 2012, Andrey Rahmatullin wrote:

> On Fri, Apr 13, 2012 at 10:10:30AM -0400, Alan Stern wrote:
> > Second, if you do
> > 
> > 	echo 0 >/sys/bus/usb/devices/usb1/bConfigurationValue
> > 	echo 0 >/sys/bus/usb/devices/usb2/bConfigurationValue
> > 
> > before suspending (using a vanilla kernel and no script), does it 
> > change the behavior?  I expect it won't, but we should check just to be 
> > thorough.
> No, it still locks up.

Okay.

This is my next attempt to make the driver-bound and driver-unbound
suspend paths as similar as possible.  Apply this to a vanilla kernel;  
it is based on 3.4-rc2 plus a few unrelated changes.  See what happens
when you suspend without unbinding ehci-hcd -- and be sure to include
"no_console_suspend" on the boot command line beforehand.

These changes will prevent the driver from working after resume 
(assuming the computer survives that long).  That's all right; all I 
care about is whether the computer _does_ resume.

Alan Stern




Index: usb-3.4/drivers/pci/pci-driver.c
===================================================================
--- usb-3.4.orig/drivers/pci/pci-driver.c
+++ usb-3.4/drivers/pci/pci-driver.c
@@ -713,6 +713,8 @@ static int pci_pm_suspend_noirq(struct d
 
 	if (!pm) {
 		pci_save_state(pci_dev);
+		pci_prepare_to_sleep(pci_dev);
+		pci_pm_set_unknown_state(pci_dev);
 		return 0;
 	}
 
Index: usb-3.4/drivers/pci/pci.c
===================================================================
--- usb-3.4.orig/drivers/pci/pci.c
+++ usb-3.4/drivers/pci/pci.c
@@ -1348,6 +1348,7 @@ void pci_disable_enabled_device(struct p
 	if (pci_is_enabled(dev))
 		do_pci_disable_device(dev);
 }
+EXPORT_SYMBOL(pci_disable_enabled_device);
 
 /**
  * pci_disable_device - Disable PCI device after use
@@ -1710,6 +1711,7 @@ pci_power_t pci_target_state(struct pci_
  */
 int pci_prepare_to_sleep(struct pci_dev *dev)
 {
+	pci_power_t cur_state = dev->current_state;
 	pci_power_t target_state = pci_target_state(dev);
 	int error;
 
@@ -1723,6 +1725,8 @@ int pci_prepare_to_sleep(struct pci_dev
 	if (error)
 		pci_enable_wake(dev, target_state, false);
 
+	dev_info(&dev->dev, "cur %d target %d error %d\n", cur_state,
+			target_state, error);
 	return error;
 }
 
Index: usb-3.4/drivers/usb/core/hcd-pci.c
===================================================================
--- usb-3.4.orig/drivers/usb/core/hcd-pci.c
+++ usb-3.4/drivers/usb/core/hcd-pci.c
@@ -381,6 +381,8 @@ static int check_root_hub_suspended(stru
 }
 
 #if defined(CONFIG_PM_SLEEP) || defined(CONFIG_PM_RUNTIME)
+extern void pci_disable_enabled_device(struct pci_dev *);
+
 static int suspend_common(struct device *dev, bool do_wakeup)
 {
 	struct pci_dev		*pci_dev = to_pci_dev(dev);
@@ -427,12 +429,17 @@ static int suspend_common(struct device
 	if (!hcd->msix_enabled)
 		synchronize_irq(pci_dev->irq);
 
+	free_irq(hcd->irq, hcd);
+	iounmap(hcd->regs);
+	pci_disable_device(pci_dev);
+
 	/* 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).  We'll enter a
 	 * low power state during suspend_noirq, if the hardware allows.
 	 */
-	pci_disable_device(pci_dev);
+	pci_disable_enabled_device(pci_dev);
+	pci_dev->current_state = PCI_UNKNOWN;
 	return retval;
 }
 
Index: usb-3.4/drivers/usb/host/ehci-pci.c
===================================================================
--- usb-3.4.orig/drivers/usb/host/ehci-pci.c
+++ usb-3.4/drivers/usb/host/ehci-pci.c
@@ -342,7 +342,6 @@ static int ehci_pci_suspend(struct usb_h
 	 * mark HW unaccessible.  The PM and USB cores make sure that
 	 * the root hub is either suspended or stopped.
 	 */
-	ehci_prepare_ports_for_controller_suspend(ehci, do_wakeup);
 	spin_lock_irqsave (&ehci->lock, flags);
 	ehci_writel(ehci, 0, &ehci->regs->intr_enable);
 	(void)ehci_readl(ehci, &ehci->regs->intr_enable);
@@ -350,6 +349,9 @@ static int ehci_pci_suspend(struct usb_h
 	clear_bit(HCD_FLAG_HW_ACCESSIBLE, &hcd->flags);
 	spin_unlock_irqrestore (&ehci->lock, flags);
 
+	ehci_silence_controller(ehci);
+	ehci_reset(ehci);
+
 	// could save FLADJ in case of Vaux power loss
 	// ... we'd only use it to handle clock skew
 



More information about the linux-pm mailing list