USB: EHCI: fix remote-wakeup support for ARC/TDI core
This patch (as1147) fixes the remote-wakeup support for EHCI controllers using the ARC/TDI "embedded-TT" core. These controllers turn off the RESUME bit by themselves when a port resume is complete; hence we need to keep separate track of which ports are suspended or in the process of resuming. The patch also makes a couple of small improvements in ehci_irq(), replacing reads of the command register with the value already stored in a local variable. Signed-off-by: Alan Stern <stern@rowland.harvard.edu> Tested-by: Thomas Reitmayr <treitmayr@devbase.at> CC: David Brownell <david-b@pacbell.net> Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de>
This commit is contained in:
committed by
Greg Kroah-Hartman
parent
2da41d5f6c
commit
eafe5b99f2
@@ -706,7 +706,7 @@ static irqreturn_t ehci_irq (struct usb_hcd *hcd)
|
|||||||
pcd_status = status;
|
pcd_status = status;
|
||||||
|
|
||||||
/* resume root hub? */
|
/* resume root hub? */
|
||||||
if (!(ehci_readl(ehci, &ehci->regs->command) & CMD_RUN))
|
if (!(cmd & CMD_RUN))
|
||||||
usb_hcd_resume_root_hub(hcd);
|
usb_hcd_resume_root_hub(hcd);
|
||||||
|
|
||||||
while (i--) {
|
while (i--) {
|
||||||
@@ -715,8 +715,11 @@ static irqreturn_t ehci_irq (struct usb_hcd *hcd)
|
|||||||
|
|
||||||
if (pstatus & PORT_OWNER)
|
if (pstatus & PORT_OWNER)
|
||||||
continue;
|
continue;
|
||||||
if (!(pstatus & PORT_RESUME)
|
if (!(test_bit(i, &ehci->suspended_ports) &&
|
||||||
|| ehci->reset_done [i] != 0)
|
((pstatus & PORT_RESUME) ||
|
||||||
|
!(pstatus & PORT_SUSPEND)) &&
|
||||||
|
(pstatus & PORT_PE) &&
|
||||||
|
ehci->reset_done[i] == 0))
|
||||||
continue;
|
continue;
|
||||||
|
|
||||||
/* start 20 msec resume signaling from this port,
|
/* start 20 msec resume signaling from this port,
|
||||||
@@ -731,9 +734,8 @@ static irqreturn_t ehci_irq (struct usb_hcd *hcd)
|
|||||||
|
|
||||||
/* PCI errors [4.15.2.4] */
|
/* PCI errors [4.15.2.4] */
|
||||||
if (unlikely ((status & STS_FATAL) != 0)) {
|
if (unlikely ((status & STS_FATAL) != 0)) {
|
||||||
dbg_cmd (ehci, "fatal", ehci_readl(ehci,
|
dbg_cmd(ehci, "fatal", cmd);
|
||||||
&ehci->regs->command));
|
dbg_status(ehci, "fatal", status);
|
||||||
dbg_status (ehci, "fatal", status);
|
|
||||||
if (status & STS_HALT) {
|
if (status & STS_HALT) {
|
||||||
ehci_err (ehci, "fatal error\n");
|
ehci_err (ehci, "fatal error\n");
|
||||||
dead:
|
dead:
|
||||||
|
@@ -236,10 +236,8 @@ static int ehci_bus_resume (struct usb_hcd *hcd)
|
|||||||
temp = ehci_readl(ehci, &ehci->regs->port_status [i]);
|
temp = ehci_readl(ehci, &ehci->regs->port_status [i]);
|
||||||
temp &= ~(PORT_RWC_BITS | PORT_WAKE_BITS);
|
temp &= ~(PORT_RWC_BITS | PORT_WAKE_BITS);
|
||||||
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);
|
|
||||||
temp |= PORT_RESUME;
|
temp |= PORT_RESUME;
|
||||||
}
|
|
||||||
ehci_writel(ehci, temp, &ehci->regs->port_status [i]);
|
ehci_writel(ehci, temp, &ehci->regs->port_status [i]);
|
||||||
}
|
}
|
||||||
i = HCS_N_PORTS (ehci->hcs_params);
|
i = HCS_N_PORTS (ehci->hcs_params);
|
||||||
@@ -482,10 +480,9 @@ ehci_hub_status_data (struct usb_hcd *hcd, char *buf)
|
|||||||
* controller by the user.
|
* controller by the user.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
if ((temp & mask) != 0
|
if ((temp & mask) != 0 || test_bit(i, &ehci->port_c_suspend)
|
||||||
|| ((temp & PORT_RESUME) != 0
|
|| (ehci->reset_done[i] && time_after_eq(
|
||||||
&& time_after_eq(jiffies,
|
jiffies, ehci->reset_done[i]))) {
|
||||||
ehci->reset_done[i]))) {
|
|
||||||
if (i < 7)
|
if (i < 7)
|
||||||
buf [0] |= 1 << (i + 1);
|
buf [0] |= 1 << (i + 1);
|
||||||
else
|
else
|
||||||
@@ -688,6 +685,7 @@ static int ehci_hub_control (
|
|||||||
/* resume completed? */
|
/* resume completed? */
|
||||||
else if (time_after_eq(jiffies,
|
else if (time_after_eq(jiffies,
|
||||||
ehci->reset_done[wIndex])) {
|
ehci->reset_done[wIndex])) {
|
||||||
|
clear_bit(wIndex, &ehci->suspended_ports);
|
||||||
set_bit(wIndex, &ehci->port_c_suspend);
|
set_bit(wIndex, &ehci->port_c_suspend);
|
||||||
ehci->reset_done[wIndex] = 0;
|
ehci->reset_done[wIndex] = 0;
|
||||||
|
|
||||||
@@ -734,6 +732,9 @@ static int ehci_hub_control (
|
|||||||
ehci_readl(ehci, status_reg));
|
ehci_readl(ehci, status_reg));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (!(temp & (PORT_RESUME|PORT_RESET)))
|
||||||
|
ehci->reset_done[wIndex] = 0;
|
||||||
|
|
||||||
/* transfer dedicated ports to the companion hc */
|
/* transfer dedicated ports to the companion hc */
|
||||||
if ((temp & PORT_CONNECT) &&
|
if ((temp & PORT_CONNECT) &&
|
||||||
test_bit(wIndex, &ehci->companion_ports)) {
|
test_bit(wIndex, &ehci->companion_ports)) {
|
||||||
@@ -757,8 +758,17 @@ static int ehci_hub_control (
|
|||||||
}
|
}
|
||||||
if (temp & PORT_PE)
|
if (temp & PORT_PE)
|
||||||
status |= 1 << USB_PORT_FEAT_ENABLE;
|
status |= 1 << USB_PORT_FEAT_ENABLE;
|
||||||
if (temp & (PORT_SUSPEND|PORT_RESUME))
|
|
||||||
|
/* maybe the port was unsuspended without our knowledge */
|
||||||
|
if (temp & (PORT_SUSPEND|PORT_RESUME)) {
|
||||||
status |= 1 << USB_PORT_FEAT_SUSPEND;
|
status |= 1 << USB_PORT_FEAT_SUSPEND;
|
||||||
|
} else if (test_bit(wIndex, &ehci->suspended_ports)) {
|
||||||
|
clear_bit(wIndex, &ehci->suspended_ports);
|
||||||
|
ehci->reset_done[wIndex] = 0;
|
||||||
|
if (temp & PORT_PE)
|
||||||
|
set_bit(wIndex, &ehci->port_c_suspend);
|
||||||
|
}
|
||||||
|
|
||||||
if (temp & PORT_OC)
|
if (temp & PORT_OC)
|
||||||
status |= 1 << USB_PORT_FEAT_OVER_CURRENT;
|
status |= 1 << USB_PORT_FEAT_OVER_CURRENT;
|
||||||
if (temp & PORT_RESET)
|
if (temp & PORT_RESET)
|
||||||
@@ -803,6 +813,7 @@ static int ehci_hub_control (
|
|||||||
|| (temp & PORT_RESET) != 0)
|
|| (temp & PORT_RESET) != 0)
|
||||||
goto error;
|
goto error;
|
||||||
ehci_writel(ehci, temp | PORT_SUSPEND, status_reg);
|
ehci_writel(ehci, temp | PORT_SUSPEND, status_reg);
|
||||||
|
set_bit(wIndex, &ehci->suspended_ports);
|
||||||
break;
|
break;
|
||||||
case USB_PORT_FEAT_POWER:
|
case USB_PORT_FEAT_POWER:
|
||||||
if (HCS_PPC (ehci->hcs_params))
|
if (HCS_PPC (ehci->hcs_params))
|
||||||
|
@@ -99,6 +99,8 @@ struct ehci_hcd { /* one per controller */
|
|||||||
owned by the companion during a bus suspend */
|
owned by the companion during a bus suspend */
|
||||||
unsigned long port_c_suspend; /* which ports have
|
unsigned long port_c_suspend; /* which ports have
|
||||||
the change-suspend feature turned on */
|
the change-suspend feature turned on */
|
||||||
|
unsigned long suspended_ports; /* which ports are
|
||||||
|
suspended */
|
||||||
|
|
||||||
/* per-HC memory pools (could be per-bus, but ...) */
|
/* per-HC memory pools (could be per-bus, but ...) */
|
||||||
struct dma_pool *qh_pool; /* qh per active urb */
|
struct dma_pool *qh_pool; /* qh per active urb */
|
||||||
|
Reference in New Issue
Block a user