Skip to content

Commit

Permalink
---
Browse files Browse the repository at this point in the history
yaml
---
r: 41331
b: refs/heads/master
c: 8c03356
h: refs/heads/master
i:
  41329: a1ea58c
  41327: e7d04e7
v: v3
  • Loading branch information
Alan Stern authored and Greg Kroah-Hartman committed Dec 1, 2006
1 parent 0d20c93 commit 40db7f8
Show file tree
Hide file tree
Showing 5 changed files with 62 additions and 54 deletions.
2 changes: 1 addition & 1 deletion [refs]
Original file line number Diff line number Diff line change
@@ -1,2 +1,2 @@
---
refs/heads/master: c066475e1fe3b3afbd613ddf5f1eca9be4fb6de0
refs/heads/master: 8c03356a559ced6fa78931f498193f776d67e445
6 changes: 2 additions & 4 deletions trunk/drivers/usb/host/ehci-hcd.c
Original file line number Diff line number Diff line change
Expand Up @@ -619,9 +619,8 @@ static irqreturn_t ehci_irq (struct usb_hcd *hcd)
unsigned i = HCS_N_PORTS (ehci->hcs_params);

/* resume root hub? */
status = readl (&ehci->regs->command);
if (!(status & CMD_RUN))
writel (status | CMD_RUN, &ehci->regs->command);
if (!(readl(&ehci->regs->command) & CMD_RUN))
usb_hcd_resume_root_hub(hcd);

while (i--) {
int pstatus = readl (&ehci->regs->port_status [i]);
Expand All @@ -638,7 +637,6 @@ static irqreturn_t ehci_irq (struct usb_hcd *hcd)
*/
ehci->reset_done [i] = jiffies + msecs_to_jiffies (20);
ehci_dbg (ehci, "port %d remote wakeup\n", i + 1);
usb_hcd_resume_root_hub(hcd);
}
}

Expand Down
67 changes: 42 additions & 25 deletions trunk/drivers/usb/host/ehci-hub.c
Original file line number Diff line number Diff line change
Expand Up @@ -34,6 +34,7 @@ static int ehci_bus_suspend (struct usb_hcd *hcd)
{
struct ehci_hcd *ehci = hcd_to_ehci (hcd);
int port;
int mask;

if (time_before (jiffies, ehci->next_statechange))
msleep(5);
Expand All @@ -51,14 +52,25 @@ static int ehci_bus_suspend (struct usb_hcd *hcd)
ehci->reclaim_ready = 1;
ehci_work(ehci);

/* suspend any active/unsuspended ports, maybe allow wakeup */
/* Unlike other USB host controller types, EHCI doesn't have
* any notion of "global" or bus-wide suspend. The driver has
* to manually suspend all the active unsuspended ports, and
* then manually resume them in the bus_resume() routine.
*/
ehci->bus_suspended = 0;
while (port--) {
u32 __iomem *reg = &ehci->regs->port_status [port];
u32 t1 = readl (reg) & ~PORT_RWC_BITS;
u32 t2 = t1;

if ((t1 & PORT_PE) && !(t1 & PORT_OWNER))
/* keep track of which ports we suspend */
if ((t1 & PORT_PE) && !(t1 & PORT_OWNER) &&
!(t1 & PORT_SUSPEND)) {
t2 |= PORT_SUSPEND;
set_bit(port, &ehci->bus_suspended);
}

/* enable remote wakeup on all ports */
if (device_may_wakeup(&hcd->self.root_hub->dev))
t2 |= PORT_WKOC_E|PORT_WKDISC_E|PORT_WKCONN_E;
else
Expand All @@ -76,6 +88,13 @@ static int ehci_bus_suspend (struct usb_hcd *hcd)
ehci_halt (ehci);
hcd->state = HC_STATE_SUSPENDED;

/* allow remote wakeup */
mask = INTR_MASK;
if (!device_may_wakeup(&hcd->self.root_hub->dev))
mask &= ~STS_PCD;
writel(mask, &ehci->regs->intr_enable);
readl(&ehci->regs->intr_enable);

ehci->next_statechange = jiffies + msecs_to_jiffies(10);
spin_unlock_irq (&ehci->lock);
return 0;
Expand All @@ -88,7 +107,6 @@ static int ehci_bus_resume (struct usb_hcd *hcd)
struct ehci_hcd *ehci = hcd_to_ehci (hcd);
u32 temp;
int i;
int intr_enable;

if (time_before (jiffies, ehci->next_statechange))
msleep(5);
Expand All @@ -100,31 +118,30 @@ static int ehci_bus_resume (struct usb_hcd *hcd)
* the last user of the controller, not reset/pm hardware keeping
* state we gave to it.
*/
temp = readl(&ehci->regs->intr_enable);
ehci_dbg(ehci, "resume root hub%s\n", temp ? "" : " after power loss");

/* re-init operational registers in case we lost power */
if (readl (&ehci->regs->intr_enable) == 0) {
/* at least some APM implementations will try to deliver
* IRQs right away, so delay them until we're ready.
*/
intr_enable = 1;
writel (0, &ehci->regs->segment);
writel (ehci->periodic_dma, &ehci->regs->frame_list);
writel ((u32)ehci->async->qh_dma, &ehci->regs->async_next);
} else
intr_enable = 0;
ehci_dbg(ehci, "resume root hub%s\n",
intr_enable ? " after power loss" : "");
/* at least some APM implementations will try to deliver
* IRQs right away, so delay them until we're ready.
*/
writel(0, &ehci->regs->intr_enable);

/* re-init operational registers */
writel(0, &ehci->regs->segment);
writel(ehci->periodic_dma, &ehci->regs->frame_list);
writel((u32) ehci->async->qh_dma, &ehci->regs->async_next);

/* restore CMD_RUN, framelist size, and irq threshold */
writel (ehci->command, &ehci->regs->command);

/* take ports out of suspend */
/* manually resume the ports we suspended during bus_suspend() */
i = HCS_N_PORTS (ehci->hcs_params);
while (i--) {
temp = readl (&ehci->regs->port_status [i]);
temp &= ~(PORT_RWC_BITS
| PORT_WKOC_E | PORT_WKDISC_E | PORT_WKCONN_E);
if (temp & PORT_SUSPEND) {
if (test_bit(i, &ehci->bus_suspended) &&
(temp & PORT_SUSPEND)) {
ehci->reset_done [i] = jiffies + msecs_to_jiffies (20);
temp |= PORT_RESUME;
}
Expand All @@ -134,11 +151,12 @@ static int ehci_bus_resume (struct usb_hcd *hcd)
mdelay (20);
while (i--) {
temp = readl (&ehci->regs->port_status [i]);
if ((temp & PORT_SUSPEND) == 0)
continue;
temp &= ~(PORT_RWC_BITS | PORT_RESUME);
writel (temp, &ehci->regs->port_status [i]);
ehci_vdbg (ehci, "resumed port %d\n", i + 1);
if (test_bit(i, &ehci->bus_suspended) &&
(temp & PORT_SUSPEND)) {
temp &= ~(PORT_RWC_BITS | PORT_RESUME);
writel (temp, &ehci->regs->port_status [i]);
ehci_vdbg (ehci, "resumed port %d\n", i + 1);
}
}
(void) readl (&ehci->regs->command);

Expand All @@ -157,8 +175,7 @@ static int ehci_bus_resume (struct usb_hcd *hcd)
hcd->state = HC_STATE_RUNNING;

/* Now we can safely re-enable irqs */
if (intr_enable)
writel (INTR_MASK, &ehci->regs->intr_enable);
writel(INTR_MASK, &ehci->regs->intr_enable);

spin_unlock_irq (&ehci->lock);
return 0;
Expand Down
40 changes: 16 additions & 24 deletions trunk/drivers/usb/host/ehci-pci.c
Original file line number Diff line number Diff line change
Expand Up @@ -257,9 +257,7 @@ static int ehci_pci_suspend(struct usb_hcd *hcd, pm_message_t message)
static int ehci_pci_resume(struct usb_hcd *hcd)
{
struct ehci_hcd *ehci = hcd_to_ehci(hcd);
unsigned port;
struct pci_dev *pdev = to_pci_dev(hcd->self.controller);
int retval = -EINVAL;

// maybe restore FLADJ

Expand All @@ -269,27 +267,19 @@ static int ehci_pci_resume(struct usb_hcd *hcd)
/* Mark hardware accessible again as we are out of D3 state by now */
set_bit(HCD_FLAG_HW_ACCESSIBLE, &hcd->flags);

/* If CF is clear, we lost PCI Vaux power and need to restart. */
if (readl(&ehci->regs->configured_flag) != FLAG_CF)
goto restart;

/* If any port is suspended (or owned by the companion),
* we know we can/must resume the HC (and mustn't reset it).
* We just defer that to the root hub code.
/* If CF is still set, we maintained PCI Vaux power.
* Just undo the effect of ehci_pci_suspend().
*/
for (port = HCS_N_PORTS(ehci->hcs_params); port > 0; ) {
u32 status;
port--;
status = readl(&ehci->regs->port_status [port]);
if (!(status & PORT_POWER))
continue;
if (status & (PORT_SUSPEND | PORT_RESUME | PORT_OWNER)) {
usb_hcd_resume_root_hub(hcd);
return 0;
}
if (readl(&ehci->regs->configured_flag) == FLAG_CF) {
int mask = INTR_MASK;

if (!device_may_wakeup(&hcd->self.root_hub->dev))
mask &= ~STS_PCD;
writel(mask, &ehci->regs->intr_enable);
readl(&ehci->regs->intr_enable);
return 0;
}

restart:
ehci_dbg(ehci, "lost power, restarting\n");
usb_root_hub_lost_power(hcd->self.root_hub);

Expand All @@ -307,13 +297,15 @@ static int ehci_pci_resume(struct usb_hcd *hcd)
ehci_work(ehci);
spin_unlock_irq(&ehci->lock);

/* restart; khubd will disconnect devices */
retval = ehci_run(hcd);

/* here we "know" root ports should always stay powered */
ehci_port_power(ehci, 1);

return retval;
writel(ehci->command, &ehci->regs->command);
writel(FLAG_CF, &ehci->regs->configured_flag);
readl(&ehci->regs->command); /* unblock posted writes */

hcd->state = HC_STATE_SUSPENDED;
return 0;
}
#endif

Expand Down
1 change: 1 addition & 0 deletions trunk/drivers/usb/host/ehci.h
Original file line number Diff line number Diff line change
Expand Up @@ -74,6 +74,7 @@ struct ehci_hcd { /* one per controller */

/* per root hub port */
unsigned long reset_done [EHCI_MAX_ROOT_PORTS];
unsigned long bus_suspended;

/* per-HC memory pools (could be per-bus, but ...) */
struct dma_pool *qh_pool; /* qh per active urb */
Expand Down

0 comments on commit 40db7f8

Please sign in to comment.