USB: HCDs use the do_remote_wakeup flag
When a USB device is suspended, whether or not it is enabled for remote wakeup depends on the device_may_wakeup() setting. The setting is then saved in the do_remote_wakeup flag. Later on, however, the device_may_wakeup() value can change because of user activity. So when testing whether a suspended device is or should be enabled for remote wakeup, we should always test do_remote_wakeup instead of device_may_wakeup(). This patch (as1076) makes that change for root hubs in several places. The patch also adjusts uhci-hcd so that when an autostopped controller is suspended, the remote wakeup setting agrees with the value recorded in the root hub's do_remote_wakeup flag. And the patch adjusts ehci-hcd so that wakeup events on selectively suspended ports (i.e., the bus itself isn't suspended) don't turn on the PME# wakeup signal. Signed-off-by: Alan Stern <stern@rowland.harvard.edu> Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de>
This commit is contained in:
committed by
Greg Kroah-Hartman
parent
b950bdbc67
commit
58a97ffeb2
@@ -932,7 +932,6 @@ static int autosuspend_check(struct usb_device *udev, int reschedule)
|
|||||||
* is disabled. Also fail if any interfaces require remote wakeup
|
* is disabled. Also fail if any interfaces require remote wakeup
|
||||||
* but it isn't available.
|
* but it isn't available.
|
||||||
*/
|
*/
|
||||||
udev->do_remote_wakeup = device_may_wakeup(&udev->dev);
|
|
||||||
if (udev->pm_usage_cnt > 0)
|
if (udev->pm_usage_cnt > 0)
|
||||||
return -EBUSY;
|
return -EBUSY;
|
||||||
if (udev->autosuspend_delay < 0 || udev->autosuspend_disabled)
|
if (udev->autosuspend_delay < 0 || udev->autosuspend_disabled)
|
||||||
|
@@ -30,6 +30,8 @@
|
|||||||
|
|
||||||
#ifdef CONFIG_PM
|
#ifdef CONFIG_PM
|
||||||
|
|
||||||
|
#define PORT_WAKE_BITS (PORT_WKOC_E|PORT_WKDISC_E|PORT_WKCONN_E)
|
||||||
|
|
||||||
static int ehci_hub_control(
|
static int ehci_hub_control(
|
||||||
struct usb_hcd *hcd,
|
struct usb_hcd *hcd,
|
||||||
u16 typeReq,
|
u16 typeReq,
|
||||||
@@ -149,10 +151,10 @@ static int ehci_bus_suspend (struct usb_hcd *hcd)
|
|||||||
}
|
}
|
||||||
|
|
||||||
/* enable remote wakeup on all ports */
|
/* enable remote wakeup on all ports */
|
||||||
if (device_may_wakeup(&hcd->self.root_hub->dev))
|
if (hcd->self.root_hub->do_remote_wakeup)
|
||||||
t2 |= PORT_WKOC_E|PORT_WKDISC_E|PORT_WKCONN_E;
|
t2 |= PORT_WAKE_BITS;
|
||||||
else
|
else
|
||||||
t2 &= ~(PORT_WKOC_E|PORT_WKDISC_E|PORT_WKCONN_E);
|
t2 &= ~PORT_WAKE_BITS;
|
||||||
|
|
||||||
if (t1 != t2) {
|
if (t1 != t2) {
|
||||||
ehci_vdbg (ehci, "port %d, %08x -> %08x\n",
|
ehci_vdbg (ehci, "port %d, %08x -> %08x\n",
|
||||||
@@ -174,7 +176,7 @@ static int ehci_bus_suspend (struct usb_hcd *hcd)
|
|||||||
|
|
||||||
/* allow remote wakeup */
|
/* allow remote wakeup */
|
||||||
mask = INTR_MASK;
|
mask = INTR_MASK;
|
||||||
if (!device_may_wakeup(&hcd->self.root_hub->dev))
|
if (!hcd->self.root_hub->do_remote_wakeup)
|
||||||
mask &= ~STS_PCD;
|
mask &= ~STS_PCD;
|
||||||
ehci_writel(ehci, mask, &ehci->regs->intr_enable);
|
ehci_writel(ehci, mask, &ehci->regs->intr_enable);
|
||||||
ehci_readl(ehci, &ehci->regs->intr_enable);
|
ehci_readl(ehci, &ehci->regs->intr_enable);
|
||||||
@@ -232,8 +234,7 @@ static int ehci_bus_resume (struct usb_hcd *hcd)
|
|||||||
i = HCS_N_PORTS (ehci->hcs_params);
|
i = HCS_N_PORTS (ehci->hcs_params);
|
||||||
while (i--) {
|
while (i--) {
|
||||||
temp = ehci_readl(ehci, &ehci->regs->port_status [i]);
|
temp = ehci_readl(ehci, &ehci->regs->port_status [i]);
|
||||||
temp &= ~(PORT_RWC_BITS
|
temp &= ~(PORT_RWC_BITS | PORT_WAKE_BITS);
|
||||||
| PORT_WKOC_E | PORT_WKDISC_E | PORT_WKCONN_E);
|
|
||||||
if (test_bit(i, &ehci->bus_suspended) &&
|
if (test_bit(i, &ehci->bus_suspended) &&
|
||||||
(temp & PORT_SUSPEND)) {
|
(temp & PORT_SUSPEND)) {
|
||||||
ehci->reset_done [i] = jiffies + msecs_to_jiffies (20);
|
ehci->reset_done [i] = jiffies + msecs_to_jiffies (20);
|
||||||
@@ -534,8 +535,6 @@ ehci_hub_descriptor (
|
|||||||
|
|
||||||
/*-------------------------------------------------------------------------*/
|
/*-------------------------------------------------------------------------*/
|
||||||
|
|
||||||
#define PORT_WAKE_BITS (PORT_WKOC_E|PORT_WKDISC_E|PORT_WKCONN_E)
|
|
||||||
|
|
||||||
static int ehci_hub_control (
|
static int ehci_hub_control (
|
||||||
struct usb_hcd *hcd,
|
struct usb_hcd *hcd,
|
||||||
u16 typeReq,
|
u16 typeReq,
|
||||||
@@ -801,8 +800,6 @@ static int ehci_hub_control (
|
|||||||
if ((temp & PORT_PE) == 0
|
if ((temp & PORT_PE) == 0
|
||||||
|| (temp & PORT_RESET) != 0)
|
|| (temp & PORT_RESET) != 0)
|
||||||
goto error;
|
goto error;
|
||||||
if (device_may_wakeup(&hcd->self.root_hub->dev))
|
|
||||||
temp |= PORT_WAKE_BITS;
|
|
||||||
ehci_writel(ehci, temp | PORT_SUSPEND, status_reg);
|
ehci_writel(ehci, temp | PORT_SUSPEND, status_reg);
|
||||||
break;
|
break;
|
||||||
case USB_PORT_FEAT_POWER:
|
case USB_PORT_FEAT_POWER:
|
||||||
|
@@ -300,7 +300,7 @@ static int ehci_pci_resume(struct usb_hcd *hcd)
|
|||||||
if (ehci_readl(ehci, &ehci->regs->configured_flag) == FLAG_CF) {
|
if (ehci_readl(ehci, &ehci->regs->configured_flag) == FLAG_CF) {
|
||||||
int mask = INTR_MASK;
|
int mask = INTR_MASK;
|
||||||
|
|
||||||
if (!device_may_wakeup(&hcd->self.root_hub->dev))
|
if (!hcd->self.root_hub->do_remote_wakeup)
|
||||||
mask &= ~STS_PCD;
|
mask &= ~STS_PCD;
|
||||||
ehci_writel(ehci, mask, &ehci->regs->intr_enable);
|
ehci_writel(ehci, mask, &ehci->regs->intr_enable);
|
||||||
ehci_readl(ehci, &ehci->regs->intr_enable);
|
ehci_readl(ehci, &ehci->regs->intr_enable);
|
||||||
|
@@ -1400,7 +1400,7 @@ static int isp116x_bus_suspend(struct usb_hcd *hcd)
|
|||||||
spin_unlock_irqrestore(&isp116x->lock, flags);
|
spin_unlock_irqrestore(&isp116x->lock, flags);
|
||||||
val &= (~HCCONTROL_HCFS & ~HCCONTROL_RWE);
|
val &= (~HCCONTROL_HCFS & ~HCCONTROL_RWE);
|
||||||
val |= HCCONTROL_USB_SUSPEND;
|
val |= HCCONTROL_USB_SUSPEND;
|
||||||
if (device_may_wakeup(&hcd->self.root_hub->dev))
|
if (hcd->self.root_hub->do_remote_wakeup)
|
||||||
val |= HCCONTROL_RWE;
|
val |= HCCONTROL_RWE;
|
||||||
/* Wait for usb transfers to finish */
|
/* Wait for usb transfers to finish */
|
||||||
msleep(2);
|
msleep(2);
|
||||||
|
@@ -103,10 +103,9 @@ __acquires(ohci->lock)
|
|||||||
finish_unlinks (ohci, ohci_frame_no(ohci));
|
finish_unlinks (ohci, ohci_frame_no(ohci));
|
||||||
|
|
||||||
/* maybe resume can wake root hub */
|
/* maybe resume can wake root hub */
|
||||||
if (device_may_wakeup(&ohci_to_hcd(ohci)->self.root_hub->dev) ||
|
if (ohci_to_hcd(ohci)->self.root_hub->do_remote_wakeup || autostop) {
|
||||||
autostop)
|
|
||||||
ohci->hc_control |= OHCI_CTRL_RWE;
|
ohci->hc_control |= OHCI_CTRL_RWE;
|
||||||
else {
|
} else {
|
||||||
ohci_writel (ohci, OHCI_INTR_RHSC, &ohci->regs->intrdisable);
|
ohci_writel (ohci, OHCI_INTR_RHSC, &ohci->regs->intrdisable);
|
||||||
ohci->hc_control &= ~OHCI_CTRL_RWE;
|
ohci->hc_control &= ~OHCI_CTRL_RWE;
|
||||||
}
|
}
|
||||||
|
@@ -262,20 +262,12 @@ __acquires(uhci->lock)
|
|||||||
{
|
{
|
||||||
int auto_stop;
|
int auto_stop;
|
||||||
int int_enable, egsm_enable;
|
int int_enable, egsm_enable;
|
||||||
|
struct usb_device *rhdev = uhci_to_hcd(uhci)->self.root_hub;
|
||||||
|
|
||||||
auto_stop = (new_state == UHCI_RH_AUTO_STOPPED);
|
auto_stop = (new_state == UHCI_RH_AUTO_STOPPED);
|
||||||
dev_dbg(&uhci_to_hcd(uhci)->self.root_hub->dev,
|
dev_dbg(&rhdev->dev, "%s%s\n", __func__,
|
||||||
"%s%s\n", __FUNCTION__,
|
|
||||||
(auto_stop ? " (auto-stop)" : ""));
|
(auto_stop ? " (auto-stop)" : ""));
|
||||||
|
|
||||||
/* If we get a suspend request when we're already auto-stopped
|
|
||||||
* then there's nothing to do.
|
|
||||||
*/
|
|
||||||
if (uhci->rh_state == UHCI_RH_AUTO_STOPPED) {
|
|
||||||
uhci->rh_state = new_state;
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Enable resume-detect interrupts if they work.
|
/* Enable resume-detect interrupts if they work.
|
||||||
* Then enter Global Suspend mode if _it_ works, still configured.
|
* Then enter Global Suspend mode if _it_ works, still configured.
|
||||||
*/
|
*/
|
||||||
@@ -285,8 +277,10 @@ __acquires(uhci->lock)
|
|||||||
if (remote_wakeup_is_broken(uhci))
|
if (remote_wakeup_is_broken(uhci))
|
||||||
egsm_enable = 0;
|
egsm_enable = 0;
|
||||||
if (resume_detect_interrupts_are_broken(uhci) || !egsm_enable ||
|
if (resume_detect_interrupts_are_broken(uhci) || !egsm_enable ||
|
||||||
!device_may_wakeup(
|
#ifdef CONFIG_PM
|
||||||
&uhci_to_hcd(uhci)->self.root_hub->dev))
|
(!auto_stop && !rhdev->do_remote_wakeup) ||
|
||||||
|
#endif
|
||||||
|
(auto_stop && !device_may_wakeup(&rhdev->dev)))
|
||||||
uhci->working_RD = int_enable = 0;
|
uhci->working_RD = int_enable = 0;
|
||||||
|
|
||||||
outw(int_enable, uhci->io_addr + USBINTR);
|
outw(int_enable, uhci->io_addr + USBINTR);
|
||||||
@@ -308,8 +302,7 @@ __acquires(uhci->lock)
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
if (!(inw(uhci->io_addr + USBSTS) & USBSTS_HCH))
|
if (!(inw(uhci->io_addr + USBSTS) & USBSTS_HCH))
|
||||||
dev_warn(&uhci_to_hcd(uhci)->self.root_hub->dev,
|
dev_warn(uhci_dev(uhci), "Controller not stopped yet!\n");
|
||||||
"Controller not stopped yet!\n");
|
|
||||||
|
|
||||||
uhci_get_current_frame_number(uhci);
|
uhci_get_current_frame_number(uhci);
|
||||||
|
|
||||||
|
Reference in New Issue
Block a user