Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit 5f827ea3 authored by David Brownell's avatar David Brownell Committed by Greg Kroah-Hartman
Browse files

[PATCH] usbcore PCI glue updates for PM



This updates the PCI glue to address the new and simplified usbcore suspend
semantics, where CONFIG_USB_SUSPEND becomes irrelevant to HCDs because
hcd->hub_suspend() will always be called.

  - Removes now-unneeded recursion support

  - Go back to ignoring faults reported by the wakeup calls; we expect them
    to fail sometimes, and that's just fine.

The PCI HCDs will need simple changes to catch up to this, like being able
to ignore the setting of CONFIG_USB_SUSPEND.

Signed-off-by: default avatarDavid Brownell <dbrownell@users.sourceforge.net>
Signed-off-by: default avatarGreg Kroah-Hartman <gregkh@suse.de>

 drivers/usb/core/hcd-pci.c |  106 +++++++++++++++++++++------------------------
 drivers/usb/core/hcd.h     |    6 +-
 2 files changed, 53 insertions(+), 59 deletions(-)
parent f3f3253d
Loading
Loading
Loading
Loading
+50 −56
Original line number Diff line number Diff line
@@ -30,6 +30,8 @@
#include <asm/io.h>
#include <asm/irq.h>
#include <linux/usb.h>

#include "usb.h"
#include "hcd.h"


@@ -197,6 +199,26 @@ int usb_hcd_pci_suspend (struct pci_dev *dev, pm_message_t message)

	hcd = pci_get_drvdata(dev);

	/* Root hub suspend should have stopped all downstream traffic,
	 * and all bus master traffic.  And done so for both the interface
	 * and the stub usb_device (which we check here).  But maybe it
	 * didn't; writing sysfs power/state files ignores such rules...
	 *
	 * We must ignore the FREEZE vs SUSPEND distinction here, because
	 * otherwise the swsusp will save (and restore) garbage state.
	 */
	if (hcd->self.root_hub->dev.power.power_state.event == PM_EVENT_ON)
		return -EBUSY;

	if (hcd->driver->suspend) {
		retval = hcd->driver->suspend(hcd, message);
		if (retval) {
			dev_dbg (&dev->dev, "PCI pre-suspend fail, %d\n",
				retval);
			goto done;
		}
	}

	/* FIXME until the generic PM interfaces change a lot more, this
	 * can't use PCI D1 and D2 states.  For example, the confusion
	 * between messages and states will need to vanish, and messages
@@ -215,31 +237,13 @@ int usb_hcd_pci_suspend (struct pci_dev *dev, pm_message_t message)
	 */
	has_pci_pm = pci_find_capability(dev, PCI_CAP_ID_PM);

	switch (hcd->state) {

	/* entry if root hub wasn't yet suspended ... from sysfs,
	 * without autosuspend, or if USB_SUSPEND isn't configured.
	/* 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.
	 */
	case HC_STATE_RUNNING:
		hcd->state = HC_STATE_QUIESCING;
		retval = hcd->driver->suspend (hcd, message);
		if (retval) {
			dev_dbg (hcd->self.controller, 
					"suspend fail, retval %d\n",
					retval);
			break;
		}
		hcd->state = HC_STATE_SUSPENDED;
		/* FALLTHROUGH */
	if (hcd->state == HC_STATE_SUSPENDED) {

	/* entry with CONFIG_USB_SUSPEND, or hcds that autosuspend: the
	 * controller and/or root hub will already have been suspended,
	 * but it won't be ready for a PCI resume call.
	 *
	 * FIXME only CONFIG_USB_SUSPEND guarantees hub_suspend() will
	 * have been called, otherwise root hub timers still run ...
	 */
	case HC_STATE_SUSPENDED:
		/* no DMA or IRQs except when HC is active */
		if (dev->current_state == PCI_D0) {
			pci_save_state (dev);
@@ -248,7 +252,7 @@ int usb_hcd_pci_suspend (struct pci_dev *dev, pm_message_t message)

		if (!has_pci_pm) {
			dev_dbg (hcd->self.controller, "--> PCI D0/legacy\n");
			break;
			goto done;
		}

		/* NOTE:  dev->current_state becomes nonzero only here, and
@@ -259,28 +263,29 @@ int usb_hcd_pci_suspend (struct pci_dev *dev, pm_message_t message)
		retval = pci_set_power_state (dev, PCI_D3hot);
		if (retval == 0) {
			dev_dbg (hcd->self.controller, "--> PCI D3\n");
			retval = pci_enable_wake (dev, PCI_D3hot, hcd->remote_wakeup);
			if (retval)
				break;
			retval = pci_enable_wake (dev, PCI_D3cold, hcd->remote_wakeup);
		} else if (retval < 0) {

			/* Ignore these return values.  We rely on pci code to
			 * reject requests the hardware can't implement, rather
			 * than coding the same thing.
			 */
			(void) pci_enable_wake (dev, PCI_D3hot, hcd->remote_wakeup);
			(void) pci_enable_wake (dev, PCI_D3cold, hcd->remote_wakeup);
		} else {
			dev_dbg (&dev->dev, "PCI D3 suspend fail, %d\n",
					retval);
			(void) usb_hcd_pci_resume (dev);
			break;
		}
		break;
	default:

	} else {
		dev_dbg (hcd->self.controller, "hcd state %d; not suspended\n",
			hcd->state);
		WARN_ON(1);
		retval = -EINVAL;
		break;
	}

	/* update power_state **ONLY** to make sysfs happier */
done:
	if (retval == 0)
		dev->dev.power.power_state = message;
		dev->dev.power.power_state = PMSG_SUSPEND;
	return retval;
}
EXPORT_SYMBOL (usb_hcd_pci_suspend);
@@ -336,20 +341,9 @@ int usb_hcd_pci_resume (struct pci_dev *dev)
				dev->current_state);
		}
#endif
		retval = pci_enable_wake (dev, dev->current_state, 0);
		if (retval) {
			dev_err(hcd->self.controller,
				"can't enable_wake to %d, %d!\n",
				dev->current_state, retval);
			return retval;
		}
		retval = pci_enable_wake (dev, PCI_D3cold, 0);
		if (retval) {
			dev_err(hcd->self.controller,
				"can't enable_wake to %d, %d!\n",
				PCI_D3cold, retval);
			return retval;
		}
		/* yes, ignore these results too... */
		(void) pci_enable_wake (dev, dev->current_state, 0);
		(void) pci_enable_wake (dev, PCI_D3cold, 0);
	} else {
		/* Same basic cases: clean (powered/not), dirty */
		dev_dbg(hcd->self.controller, "PCI legacy resume\n");
@@ -371,17 +365,17 @@ int usb_hcd_pci_resume (struct pci_dev *dev)

	dev->dev.power.power_state = PMSG_ON;

	hcd->state = HC_STATE_RESUMING;
	hcd->saw_irq = 0;

	if (hcd->driver->resume) {
		retval = hcd->driver->resume(hcd);
	if (!HC_IS_RUNNING (hcd->state)) {
		dev_dbg (hcd->self.controller, 
				"resume fail, retval %d\n", retval);
		if (retval) {
			dev_err (hcd->self.controller,
				"PCI post-resume error %d!\n", retval);
			usb_hc_died (hcd);
		}
	}

	retval = pci_enable_device(dev);
	return retval;
}
EXPORT_SYMBOL (usb_hcd_pci_resume);
+3 −3
Original line number Diff line number Diff line
@@ -182,12 +182,12 @@ struct hc_driver {
	int	(*start) (struct usb_hcd *hcd);

	/* NOTE:  these suspend/resume calls relate to the HC as
	 * a whole, not just the root hub; they're for bus glue.
	 * a whole, not just the root hub; they're for PCI bus glue.
	 */
	/* called after all devices were suspended */
	/* called after suspending the hub, before entering D3 etc */
	int	(*suspend) (struct usb_hcd *hcd, pm_message_t message);

	/* called before any devices get resumed */
	/* called after entering D0 (etc), before resuming the hub */
	int	(*resume) (struct usb_hcd *hcd);

	/* cleanly make HCD stop writing memory and doing I/O */