aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/usb/host/ehci-hub.c
diff options
context:
space:
mode:
authorAlan Stern <stern@rowland.harvard.edu>2006-11-09 14:42:16 -0500
committerGreg Kroah-Hartman <gregkh@suse.de>2006-12-01 17:25:52 -0500
commit8c03356a559ced6fa78931f498193f776d67e445 (patch)
tree56539740dea1febc7cac7a83bde1a56e48e9d5ec /drivers/usb/host/ehci-hub.c
parentc066475e1fe3b3afbd613ddf5f1eca9be4fb6de0 (diff)
EHCI: Fix root-hub and port suspend/resume problems
This patch (as738b) fixes numerous problems in the controller/root-hub suspend/resume/remote-wakeup support in ehci-hcd: The bus_resume() routine should wake up only the ports that were suspended by bus_suspend(). Ports that were already suspended should remain that way. The interrupt mask is used to detect loss of power in the bus_resume() routine (if the mask is 0 then power was lost). However bus_suspend() always sets the mask to 0. Instead the mask should retain its normal value, with port-change-detect interrupts disabled if remote wakeup is turned off. The interrupt mask should be reset to its correct value at the end of bus_resume() regardless of whether power was lost. bus_resume() reinitializes the operational registers if power was lost. However those registers are not in the aux power well, hence they can lose their values whenever the controller is put into D3. They should always be reinitialized. When a port-change interrupt occurs and the root hub is suspended, the interrupt handler should request a root-hub resume instead of starting up the controller all by itself. There's no need for the interrupt handler to request a root-hub resume every time a suspended port sends a remote-wakeup request. The pci_resume() method doesn't need to check for connected ports when deciding whether or not to reset the controller. It can make that decision based on whether Vaux power was maintained. Even when the controller does not need to be reset, pci_resume() must undo the effect of pci_suspend() by re-enabling the interrupt mask. If power was lost, pci_resume() must not call ehci_run(). At this point the root hub is still supposed to be suspended, not running. It's enough to rewrite the command register and set the configured_flag. Signed-off-by: Alan Stern <stern@rowland.harvard.edu> Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de>
Diffstat (limited to 'drivers/usb/host/ehci-hub.c')
-rw-r--r--drivers/usb/host/ehci-hub.c67
1 files changed, 42 insertions, 25 deletions
diff --git a/drivers/usb/host/ehci-hub.c b/drivers/usb/host/ehci-hub.c
index 0a56dfa2745d..bfe5f307cba6 100644
--- a/drivers/usb/host/ehci-hub.c
+++ b/drivers/usb/host/ehci-hub.c
@@ -34,6 +34,7 @@ static int ehci_bus_suspend (struct usb_hcd *hcd)
34{ 34{
35 struct ehci_hcd *ehci = hcd_to_ehci (hcd); 35 struct ehci_hcd *ehci = hcd_to_ehci (hcd);
36 int port; 36 int port;
37 int mask;
37 38
38 if (time_before (jiffies, ehci->next_statechange)) 39 if (time_before (jiffies, ehci->next_statechange))
39 msleep(5); 40 msleep(5);
@@ -51,14 +52,25 @@ static int ehci_bus_suspend (struct usb_hcd *hcd)
51 ehci->reclaim_ready = 1; 52 ehci->reclaim_ready = 1;
52 ehci_work(ehci); 53 ehci_work(ehci);
53 54
54 /* suspend any active/unsuspended ports, maybe allow wakeup */ 55 /* Unlike other USB host controller types, EHCI doesn't have
56 * any notion of "global" or bus-wide suspend. The driver has
57 * to manually suspend all the active unsuspended ports, and
58 * then manually resume them in the bus_resume() routine.
59 */
60 ehci->bus_suspended = 0;
55 while (port--) { 61 while (port--) {
56 u32 __iomem *reg = &ehci->regs->port_status [port]; 62 u32 __iomem *reg = &ehci->regs->port_status [port];
57 u32 t1 = readl (reg) & ~PORT_RWC_BITS; 63 u32 t1 = readl (reg) & ~PORT_RWC_BITS;
58 u32 t2 = t1; 64 u32 t2 = t1;
59 65
60 if ((t1 & PORT_PE) && !(t1 & PORT_OWNER)) 66 /* keep track of which ports we suspend */
67 if ((t1 & PORT_PE) && !(t1 & PORT_OWNER) &&
68 !(t1 & PORT_SUSPEND)) {
61 t2 |= PORT_SUSPEND; 69 t2 |= PORT_SUSPEND;
70 set_bit(port, &ehci->bus_suspended);
71 }
72
73 /* enable remote wakeup on all ports */
62 if (device_may_wakeup(&hcd->self.root_hub->dev)) 74 if (device_may_wakeup(&hcd->self.root_hub->dev))
63 t2 |= PORT_WKOC_E|PORT_WKDISC_E|PORT_WKCONN_E; 75 t2 |= PORT_WKOC_E|PORT_WKDISC_E|PORT_WKCONN_E;
64 else 76 else
@@ -76,6 +88,13 @@ static int ehci_bus_suspend (struct usb_hcd *hcd)
76 ehci_halt (ehci); 88 ehci_halt (ehci);
77 hcd->state = HC_STATE_SUSPENDED; 89 hcd->state = HC_STATE_SUSPENDED;
78 90
91 /* allow remote wakeup */
92 mask = INTR_MASK;
93 if (!device_may_wakeup(&hcd->self.root_hub->dev))
94 mask &= ~STS_PCD;
95 writel(mask, &ehci->regs->intr_enable);
96 readl(&ehci->regs->intr_enable);
97
79 ehci->next_statechange = jiffies + msecs_to_jiffies(10); 98 ehci->next_statechange = jiffies + msecs_to_jiffies(10);
80 spin_unlock_irq (&ehci->lock); 99 spin_unlock_irq (&ehci->lock);
81 return 0; 100 return 0;
@@ -88,7 +107,6 @@ static int ehci_bus_resume (struct usb_hcd *hcd)
88 struct ehci_hcd *ehci = hcd_to_ehci (hcd); 107 struct ehci_hcd *ehci = hcd_to_ehci (hcd);
89 u32 temp; 108 u32 temp;
90 int i; 109 int i;
91 int intr_enable;
92 110
93 if (time_before (jiffies, ehci->next_statechange)) 111 if (time_before (jiffies, ehci->next_statechange))
94 msleep(5); 112 msleep(5);
@@ -100,31 +118,30 @@ static int ehci_bus_resume (struct usb_hcd *hcd)
100 * the last user of the controller, not reset/pm hardware keeping 118 * the last user of the controller, not reset/pm hardware keeping
101 * state we gave to it. 119 * state we gave to it.
102 */ 120 */
121 temp = readl(&ehci->regs->intr_enable);
122 ehci_dbg(ehci, "resume root hub%s\n", temp ? "" : " after power loss");
103 123
104 /* re-init operational registers in case we lost power */ 124 /* at least some APM implementations will try to deliver
105 if (readl (&ehci->regs->intr_enable) == 0) { 125 * IRQs right away, so delay them until we're ready.
106 /* at least some APM implementations will try to deliver 126 */
107 * IRQs right away, so delay them until we're ready. 127 writel(0, &ehci->regs->intr_enable);
108 */ 128
109 intr_enable = 1; 129 /* re-init operational registers */
110 writel (0, &ehci->regs->segment); 130 writel(0, &ehci->regs->segment);
111 writel (ehci->periodic_dma, &ehci->regs->frame_list); 131 writel(ehci->periodic_dma, &ehci->regs->frame_list);
112 writel ((u32)ehci->async->qh_dma, &ehci->regs->async_next); 132 writel((u32) ehci->async->qh_dma, &ehci->regs->async_next);
113 } else
114 intr_enable = 0;
115 ehci_dbg(ehci, "resume root hub%s\n",
116 intr_enable ? " after power loss" : "");
117 133
118 /* restore CMD_RUN, framelist size, and irq threshold */ 134 /* restore CMD_RUN, framelist size, and irq threshold */
119 writel (ehci->command, &ehci->regs->command); 135 writel (ehci->command, &ehci->regs->command);
120 136
121 /* take ports out of suspend */ 137 /* manually resume the ports we suspended during bus_suspend() */
122 i = HCS_N_PORTS (ehci->hcs_params); 138 i = HCS_N_PORTS (ehci->hcs_params);
123 while (i--) { 139 while (i--) {
124 temp = readl (&ehci->regs->port_status [i]); 140 temp = readl (&ehci->regs->port_status [i]);
125 temp &= ~(PORT_RWC_BITS 141 temp &= ~(PORT_RWC_BITS
126 | PORT_WKOC_E | PORT_WKDISC_E | PORT_WKCONN_E); 142 | PORT_WKOC_E | PORT_WKDISC_E | PORT_WKCONN_E);
127 if (temp & PORT_SUSPEND) { 143 if (test_bit(i, &ehci->bus_suspended) &&
144 (temp & PORT_SUSPEND)) {
128 ehci->reset_done [i] = jiffies + msecs_to_jiffies (20); 145 ehci->reset_done [i] = jiffies + msecs_to_jiffies (20);
129 temp |= PORT_RESUME; 146 temp |= PORT_RESUME;
130 } 147 }
@@ -134,11 +151,12 @@ static int ehci_bus_resume (struct usb_hcd *hcd)
134 mdelay (20); 151 mdelay (20);
135 while (i--) { 152 while (i--) {
136 temp = readl (&ehci->regs->port_status [i]); 153 temp = readl (&ehci->regs->port_status [i]);
137 if ((temp & PORT_SUSPEND) == 0) 154 if (test_bit(i, &ehci->bus_suspended) &&
138 continue; 155 (temp & PORT_SUSPEND)) {
139 temp &= ~(PORT_RWC_BITS | PORT_RESUME); 156 temp &= ~(PORT_RWC_BITS | PORT_RESUME);
140 writel (temp, &ehci->regs->port_status [i]); 157 writel (temp, &ehci->regs->port_status [i]);
141 ehci_vdbg (ehci, "resumed port %d\n", i + 1); 158 ehci_vdbg (ehci, "resumed port %d\n", i + 1);
159 }
142 } 160 }
143 (void) readl (&ehci->regs->command); 161 (void) readl (&ehci->regs->command);
144 162
@@ -157,8 +175,7 @@ static int ehci_bus_resume (struct usb_hcd *hcd)
157 hcd->state = HC_STATE_RUNNING; 175 hcd->state = HC_STATE_RUNNING;
158 176
159 /* Now we can safely re-enable irqs */ 177 /* Now we can safely re-enable irqs */
160 if (intr_enable) 178 writel(INTR_MASK, &ehci->regs->intr_enable);
161 writel (INTR_MASK, &ehci->regs->intr_enable);
162 179
163 spin_unlock_irq (&ehci->lock); 180 spin_unlock_irq (&ehci->lock);
164 return 0; 181 return 0;