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

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

[PATCH] OHCI PM updates



This simplifies the OHCI root hub suspend logic:

 - Uses new usbcore root hub calls to make autosuspend work again:
	* Uses a newish usbcore root hub wakeup mechanism,
	  making requests to khubd not keventd.
	* Uses an even newer sibling suspend hook.

 - Expect someone always made usbcore call ohci_hub_suspend() before bus
   glue fires; and that ohci_hub_resume() is only called after that bus
   glue ran.  Previously, only CONFIG_USB_SUSPEND promised those things.
   (Includes updates to PCI and OMAP bus glue.)

 - Handle a not-noticed-before special case during resume from one of
   the swsusp snapshots when using "usb-handoff":  the controller isn't
   left in RESET state.  (A bug to fix in the usb-handoff code...)

Also cleans up a minor debug printk glitch, and switches an mdelay over
to an msleep (how did that stick around for so long?).

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

 drivers/usb/host/ohci-dbg.c  |    4 ----
 drivers/usb/host/ohci-hcd.c  |    2 +-
 drivers/usb/host/ohci-hub.c  |   42 ++++++++++++------------------------------
 drivers/usb/host/ohci-mem.c  |    1 -
 drivers/usb/host/ohci-omap.c |   36 ++++++++++++------------------------
 drivers/usb/host/ohci-pci.c  |   40 ++++++++--------------------------------
 drivers/usb/host/ohci.h      |    1 -
 7 files changed, 33 insertions(+), 93 deletions(-)
parent 5f827ea3
Loading
Loading
Loading
Loading
+0 −4
Original line number Diff line number Diff line
@@ -193,10 +193,6 @@ ohci_dump_status (struct ohci_hcd *controller, char **next, unsigned *size)

	maybe_print_eds (controller, "donehead",
			ohci_readl (controller, &regs->donehead), next, size);

	/* broken fminterval means traffic won't flow! */ 
	ohci_dbg (controller, "fminterval %08x\n", 
			ohci_readl (controller, &regs->fminterval));
}

#define dbg_port_sw(hc,num,value,next,size) \
+1 −1
Original line number Diff line number Diff line
@@ -723,7 +723,7 @@ static irqreturn_t ohci_irq (struct usb_hcd *hcd, struct pt_regs *ptregs)
		ohci_vdbg (ohci, "resume detect\n");
		ohci_writel (ohci, OHCI_INTR_RD, &regs->intrstatus);
		if (hcd->state != HC_STATE_QUIESCING)
			schedule_work(&ohci->rh_resume);
			usb_hcd_resume_root_hub(hcd);
	}

	if (ints & OHCI_INTR_WDH) {
+12 −30
Original line number Diff line number Diff line
@@ -73,7 +73,6 @@ static int ohci_hub_suspend (struct usb_hcd *hcd)
	ohci_dbg (ohci, "suspend root hub\n");

	/* First stop any processing */
	hcd->state = HC_STATE_QUIESCING;
	if (ohci->hc_control & OHCI_SCHED_ENABLES) {
		int		limit;

@@ -108,7 +107,9 @@ static int ohci_hub_suspend (struct usb_hcd *hcd)
	else
		ohci->hc_control &= ~OHCI_CTRL_RWE;

	/* Suspend hub */
	/* Suspend hub ... this is the "global (to this bus) suspend" mode,
	 * which doesn't imply ports will first be individually suspended.
	 */
	ohci->hc_control &= ~OHCI_CTRL_HCFS;
	ohci->hc_control |= OHCI_USB_SUSPEND;
	ohci_writel (ohci, ohci->hc_control, &ohci->regs->control);
@@ -118,8 +119,9 @@ static int ohci_hub_suspend (struct usb_hcd *hcd)
	ohci->next_statechange = jiffies + msecs_to_jiffies (5);

done:
	/* external suspend vs self autosuspend ... same effect */
	if (status == 0)
		hcd->state = HC_STATE_SUSPENDED;
		usb_hcd_suspend_root_hub(hcd);
	spin_unlock_irqrestore (&ohci->lock, flags);
	return status;
}
@@ -146,7 +148,7 @@ static int ohci_hub_resume (struct usb_hcd *hcd)
	ohci->hc_control = ohci_readl (ohci, &ohci->regs->control);

	if (ohci->hc_control & (OHCI_CTRL_IR | OHCI_SCHED_ENABLES)) {
		/* this can happen after suspend-to-disk */
		/* this can happen after resuming a swsusp snapshot */
		if (hcd->state == HC_STATE_RESUMING) {
			ohci_dbg (ohci, "BIOS/SMM active, control %03x\n",
					ohci->hc_control);
@@ -169,11 +171,12 @@ static int ohci_hub_resume (struct usb_hcd *hcd)
		ohci_info (ohci, "wakeup\n");
		break;
	case OHCI_USB_OPER:
		ohci_dbg (ohci, "already resumed\n");
		status = 0;
		/* this can happen after resuming a swsusp snapshot */
		ohci_dbg (ohci, "snapshot resume? reinit\n");
		status = -EBUSY;
		break;
	default:		/* RESET, we lost power */
		ohci_dbg (ohci, "root hub hardware reset\n");
		ohci_dbg (ohci, "lost power\n");
		status = -EBUSY;
	}
	spin_unlock_irq (&ohci->lock);
@@ -198,8 +201,7 @@ static int ohci_hub_resume (struct usb_hcd *hcd)
	}

	/* Some controllers (lucent erratum) need extra-long delays */
	hcd->state = HC_STATE_RESUMING;
	mdelay (20 /* usb 11.5.1.10 */ + 15);
	msleep (20 /* usb 11.5.1.10 */ + 12 /* 32 msec counter */ + 1);

	temp = ohci_readl (ohci, &ohci->regs->control);
	temp &= OHCI_CTRL_HCFS;
@@ -273,27 +275,9 @@ static int ohci_hub_resume (struct usb_hcd *hcd)
		(void) ohci_readl (ohci, &ohci->regs->control);
	}

	hcd->state = HC_STATE_RUNNING;
	return 0;
}

static void ohci_rh_resume (void *_hcd)
{
	struct usb_hcd	*hcd = _hcd;

	usb_lock_device (hcd->self.root_hub);
	(void) ohci_hub_resume (hcd);
	usb_unlock_device (hcd->self.root_hub);
}

#else

static void ohci_rh_resume (void *_hcd)
{
	struct ohci_hcd	*ohci = hcd_to_ohci (_hcd);
	ohci_dbg(ohci, "rh_resume ??\n");
}

#endif	/* CONFIG_PM */

/*-------------------------------------------------------------------------*/
@@ -367,7 +351,6 @@ ohci_hub_status_data (struct usb_hcd *hcd, char *buf)
#ifdef CONFIG_PM
	/* save power by suspending idle root hubs;
	 * INTR_RD wakes us when there's work
	 * NOTE: if we can do this, we don't need a root hub timer!
	 */
	if (can_suspend
			&& !changed
@@ -380,7 +363,6 @@ ohci_hub_status_data (struct usb_hcd *hcd, char *buf)
			) {
		ohci_vdbg (ohci, "autosuspend\n");
		(void) ohci_hub_suspend (hcd);
		hcd->state = HC_STATE_RUNNING;
		usb_unlock_device (hcd->self.root_hub);
	}
#endif
@@ -554,7 +536,7 @@ static int ohci_hub_control (
			temp = RH_PS_POCI;
			if ((ohci->hc_control & OHCI_CTRL_HCFS)
					!= OHCI_USB_OPER)
				schedule_work (&ohci->rh_resume);
				usb_hcd_resume_root_hub(hcd);
			break;
		case USB_PORT_FEAT_C_SUSPEND:
			temp = RH_PS_PSSC;
+0 −1
Original line number Diff line number Diff line
@@ -28,7 +28,6 @@ static void ohci_hcd_init (struct ohci_hcd *ohci)
	ohci->next_statechange = jiffies;
	spin_lock_init (&ohci->lock);
	INIT_LIST_HEAD (&ohci->pending);
	INIT_WORK (&ohci->rh_resume, ohci_rh_resume, ohci_to_hcd(ohci));
	ohci->reboot_notifier.notifier_call = ohci_reboot;
}

+13 −25
Original line number Diff line number Diff line
@@ -458,41 +458,29 @@ static int ohci_hcd_omap_drv_remove(struct device *dev)
static int ohci_omap_suspend(struct device *dev, pm_message_t message)
{
	struct ohci_hcd	*ohci = hcd_to_ohci(dev_get_drvdata(dev));
	int		status = -EINVAL;

	down(&ohci_to_hcd(ohci)->self.root_hub->serialize);
	status = ohci_hub_suspend(ohci_to_hcd(ohci));
	if (status == 0) {
	if (time_before(jiffies, ohci->next_statechange))
		msleep(5);
	ohci->next_statechange = jiffies;

	omap_ohci_clock_power(0);
		ohci_to_hcd(ohci)->self.root_hub->state =
			USB_STATE_SUSPENDED;
	ohci_to_hcd(ohci)->state = HC_STATE_SUSPENDED;
	dev->power.power_state = PMSG_SUSPEND;
	}
	up(&ohci_to_hcd(ohci)->self.root_hub->serialize);
	return status;
	return 0;
}

static int ohci_omap_resume(struct device *dev)
{
	struct ohci_hcd	*ohci = hcd_to_ohci(dev_get_drvdata(dev));
	int		status = 0;

	if (time_before(jiffies, ohci->next_statechange))
		msleep(5);
	ohci->next_statechange = jiffies;

	omap_ohci_clock_power(1);
#ifdef	CONFIG_USB_SUSPEND
	/* get extra cleanup even if remote wakeup isn't in use */
	status = usb_resume_device(ohci_to_hcd(ohci)->self.root_hub);
#else
	down(&ohci_to_hcd(ohci)->self.root_hub->serialize);
	status = ohci_hub_resume(ohci_to_hcd(ohci));
	up(&ohci_to_hcd(ohci)->self.root_hub->serialize);
#endif
	if (status == 0)
	dev->power.power_state = PMSG_ON;
	return status;
	usb_hcd_resume_root_hub(dev_get_drvdata(dev));
	return 0;
}

#endif
Loading