Skip to content

Commit

Permalink
OHCI: make autostop conditional on CONFIG_PM
Browse files Browse the repository at this point in the history
Unlike UHCI, OHCI does not exert any DMA load on the system when no
devices are connected.  Consequently there is no advantage to doing
an autostop other than the power savings, so we shouldn't compile the
necessary code unless CONFIG_PM is enabled.

This patch (as820) makes the root-hub suspend and resume routines
conditional on CONFIG_PM.  It also prevents autostop from activating
if the device_may_wakeup flag isn't set; some people use this flag to
alert the driver about Resume-Detect bugs in the hardware.

Signed-off-by: Alan Stern <stern@rowland.harvard.edu>
Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de>
  • Loading branch information
Alan Stern authored and Greg Kroah-Hartman committed Dec 1, 2006
1 parent 40f122f commit 1f9fc88
Showing 1 changed file with 79 additions and 54 deletions.
133 changes: 79 additions & 54 deletions drivers/usb/host/ohci-hub.c
Original file line number Diff line number Diff line change
Expand Up @@ -56,7 +56,6 @@ static void finish_unlinks (struct ohci_hcd *, u16);

#ifdef CONFIG_PM
static int ohci_restart(struct ohci_hcd *ohci);
#endif

static int ohci_rh_suspend (struct ohci_hcd *ohci, int autostop)
__releases(ohci->lock)
Expand Down Expand Up @@ -187,7 +186,6 @@ __acquires(ohci->lock)
ohci_dbg (ohci, "lost power\n");
status = -EBUSY;
}
#ifdef CONFIG_PM
if (status == -EBUSY) {
if (!autostopped) {
spin_unlock_irq (&ohci->lock);
Expand All @@ -197,7 +195,6 @@ __acquires(ohci->lock)
}
return status;
}
#endif
if (status != -EINPROGRESS)
return status;
if (autostopped)
Expand Down Expand Up @@ -291,8 +288,6 @@ __acquires(ohci->lock)
return 0;
}

#ifdef CONFIG_PM

static int ohci_bus_suspend (struct usb_hcd *hcd)
{
struct ohci_hcd *ohci = hcd_to_ohci (hcd);
Expand Down Expand Up @@ -330,6 +325,83 @@ static int ohci_bus_resume (struct usb_hcd *hcd)
return rc;
}

/* Carry out polling-, autostop-, and autoresume-related state changes */
static int ohci_root_hub_state_changes(struct ohci_hcd *ohci, int changed,
int any_connected)
{
int poll_rh = 1;

switch (ohci->hc_control & OHCI_CTRL_HCFS) {

case OHCI_USB_OPER:
/* keep on polling until we know a device is connected
* and RHSC is enabled */
if (!ohci->autostop) {
if (any_connected ||
!device_may_wakeup(&ohci_to_hcd(ohci)
->self.root_hub->dev)) {
if (ohci_readl(ohci, &ohci->regs->intrenable) &
OHCI_INTR_RHSC)
poll_rh = 0;
} else {
ohci->autostop = 1;
ohci->next_statechange = jiffies + HZ;
}

/* if no devices have been attached for one second, autostop */
} else {
if (changed || any_connected) {
ohci->autostop = 0;
ohci->next_statechange = jiffies +
STATECHANGE_DELAY;
} else if (time_after_eq(jiffies,
ohci->next_statechange)
&& !ohci->ed_rm_list
&& !(ohci->hc_control &
OHCI_SCHED_ENABLES)) {
ohci_rh_suspend(ohci, 1);
}
}
break;

/* if there is a port change, autostart or ask to be resumed */
case OHCI_USB_SUSPEND:
case OHCI_USB_RESUME:
if (changed) {
if (ohci->autostop)
ohci_rh_resume(ohci);
else
usb_hcd_resume_root_hub(ohci_to_hcd(ohci));
} else {
/* everything is idle, no need for polling */
poll_rh = 0;
}
break;
}
return poll_rh;
}

#else /* CONFIG_PM */

static inline int ohci_rh_resume(struct ohci_hcd *ohci)
{
return 0;
}

/* Carry out polling-related state changes.
* autostop isn't used when CONFIG_PM is turned off.
*/
static int ohci_root_hub_state_changes(struct ohci_hcd *ohci, int changed,
int any_connected)
{
int poll_rh = 1;

/* keep on polling until RHSC is enabled */
if (ohci_readl(ohci, &ohci->regs->intrenable) & OHCI_INTR_RHSC)
poll_rh = 0;
return poll_rh;
}

#endif /* CONFIG_PM */

/*-------------------------------------------------------------------------*/
Expand Down Expand Up @@ -382,55 +454,8 @@ ohci_hub_status_data (struct usb_hcd *hcd, char *buf)
}
}

hcd->poll_rh = 1;

/* carry out appropriate state changes */
switch (ohci->hc_control & OHCI_CTRL_HCFS) {

case OHCI_USB_OPER:
/* keep on polling until we know a device is connected
* and RHSC is enabled */
if (!ohci->autostop) {
if (any_connected) {
if (ohci_readl(ohci, &ohci->regs->intrenable) &
OHCI_INTR_RHSC)
hcd->poll_rh = 0;
} else {
ohci->autostop = 1;
ohci->next_statechange = jiffies + HZ;
}

/* if no devices have been attached for one second, autostop */
} else {
if (changed || any_connected) {
ohci->autostop = 0;
ohci->next_statechange = jiffies +
STATECHANGE_DELAY;
} else if (device_may_wakeup(&hcd->self.root_hub->dev)
&& time_after_eq(jiffies,
ohci->next_statechange)
&& !ohci->ed_rm_list
&& !(ohci->hc_control &
OHCI_SCHED_ENABLES)) {
ohci_rh_suspend (ohci, 1);
}
}
break;

/* if there is a port change, autostart or ask to be resumed */
case OHCI_USB_SUSPEND:
case OHCI_USB_RESUME:
if (changed) {
if (ohci->autostop)
ohci_rh_resume (ohci);
else
usb_hcd_resume_root_hub (hcd);
} else {
/* everything is idle, no need for polling */
hcd->poll_rh = 0;
}
break;
}
hcd->poll_rh = ohci_root_hub_state_changes(ohci, changed,
any_connected);

done:
spin_unlock_irqrestore (&ohci->lock, flags);
Expand Down

0 comments on commit 1f9fc88

Please sign in to comment.