aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/usb
diff options
context:
space:
mode:
authorAlan Stern <stern@rowland.harvard.edu>2010-05-12 18:21:35 -0400
committerGreg Kroah-Hartman <gregkh@suse.de>2010-05-20 16:21:45 -0400
commit16032c4f5b291af541e9114a09ea20ff5a0dc474 (patch)
tree8f7a6b98859220410bdde08671039ec888635ffe /drivers/usb
parenteab80de01cb398419ef3305f35abcb367c647c8b (diff)
USB: EHCI: fix controller wakeup flag settings during suspend
This patch (as1380) fixes a bug in the wakeup settings for EHCI host controllers. When the controller is suspended, if it isn't enabled for remote wakeup then we have to turn off all the port wakeup flags. Disabling PCI PME# isn't good enough, because some systems (Intel) evidently use alternate wakeup signalling paths. In addition, the patch improves the handling of the Intel Moorestown hardware by performing various power-up and power-down delays just once instead of once for each port (i.e., the delays are moved outside of the port loops). This requires extra code, but the total delay time is reduced. There are also a few additional minor cleanups. Signed-off-by: Alan Stern <stern@rowland.harvard.edu> Reported-by: Ondrej Zary <linux@rainbow-software.org> CC: Alek Du <alek.du@intel.com> CC: stable <stable@kernel.org> Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de>
Diffstat (limited to 'drivers/usb')
-rw-r--r--drivers/usb/host/ehci-au1xxx.c16
-rw-r--r--drivers/usb/host/ehci-fsl.c2
-rw-r--r--drivers/usb/host/ehci-hub.c173
-rw-r--r--drivers/usb/host/ehci-pci.c15
-rw-r--r--drivers/usb/host/ehci.h10
5 files changed, 145 insertions, 71 deletions
diff --git a/drivers/usb/host/ehci-au1xxx.c b/drivers/usb/host/ehci-au1xxx.c
index 7a27b7c4ee84..faa61748db70 100644
--- a/drivers/usb/host/ehci-au1xxx.c
+++ b/drivers/usb/host/ehci-au1xxx.c
@@ -224,26 +224,17 @@ static int ehci_hcd_au1xxx_drv_suspend(struct device *dev)
224 msleep(10); 224 msleep(10);
225 225
226 /* Root hub was already suspended. Disable irq emission and 226 /* Root hub was already suspended. Disable irq emission and
227 * mark HW unaccessible, bail out if RH has been resumed. Use 227 * mark HW unaccessible. The PM and USB cores make sure that
228 * the spinlock to properly synchronize with possible pending 228 * the root hub is either suspended or stopped.
229 * RH suspend or resume activity.
230 *
231 * This is still racy as hcd->state is manipulated outside of
232 * any locks =P But that will be a different fix.
233 */ 229 */
234 spin_lock_irqsave(&ehci->lock, flags); 230 spin_lock_irqsave(&ehci->lock, flags);
235 if (hcd->state != HC_STATE_SUSPENDED) { 231 ehci_prepare_ports_for_controller_suspend(ehci);
236 rc = -EINVAL;
237 goto bail;
238 }
239 ehci_writel(ehci, 0, &ehci->regs->intr_enable); 232 ehci_writel(ehci, 0, &ehci->regs->intr_enable);
240 (void)ehci_readl(ehci, &ehci->regs->intr_enable); 233 (void)ehci_readl(ehci, &ehci->regs->intr_enable);
241 234
242 clear_bit(HCD_FLAG_HW_ACCESSIBLE, &hcd->flags); 235 clear_bit(HCD_FLAG_HW_ACCESSIBLE, &hcd->flags);
243 236
244 au1xxx_stop_ehc(); 237 au1xxx_stop_ehc();
245
246bail:
247 spin_unlock_irqrestore(&ehci->lock, flags); 238 spin_unlock_irqrestore(&ehci->lock, flags);
248 239
249 // could save FLADJ in case of Vaux power loss 240 // could save FLADJ in case of Vaux power loss
@@ -273,6 +264,7 @@ static int ehci_hcd_au1xxx_drv_resume(struct device *dev)
273 if (ehci_readl(ehci, &ehci->regs->configured_flag) == FLAG_CF) { 264 if (ehci_readl(ehci, &ehci->regs->configured_flag) == FLAG_CF) {
274 int mask = INTR_MASK; 265 int mask = INTR_MASK;
275 266
267 ehci_prepare_ports_for_controller_resume(ehci);
276 if (!hcd->self.root_hub->do_remote_wakeup) 268 if (!hcd->self.root_hub->do_remote_wakeup)
277 mask &= ~STS_PCD; 269 mask &= ~STS_PCD;
278 ehci_writel(ehci, mask, &ehci->regs->intr_enable); 270 ehci_writel(ehci, mask, &ehci->regs->intr_enable);
diff --git a/drivers/usb/host/ehci-fsl.c b/drivers/usb/host/ehci-fsl.c
index 0e26aa13f158..5cd967d28938 100644
--- a/drivers/usb/host/ehci-fsl.c
+++ b/drivers/usb/host/ehci-fsl.c
@@ -313,6 +313,7 @@ static int ehci_fsl_drv_suspend(struct device *dev)
313 struct ehci_fsl *ehci_fsl = hcd_to_ehci_fsl(hcd); 313 struct ehci_fsl *ehci_fsl = hcd_to_ehci_fsl(hcd);
314 void __iomem *non_ehci = hcd->regs; 314 void __iomem *non_ehci = hcd->regs;
315 315
316 ehci_prepare_ports_for_controller_suspend(hcd_to_ehci(hcd));
316 if (!fsl_deep_sleep()) 317 if (!fsl_deep_sleep())
317 return 0; 318 return 0;
318 319
@@ -327,6 +328,7 @@ static int ehci_fsl_drv_resume(struct device *dev)
327 struct ehci_hcd *ehci = hcd_to_ehci(hcd); 328 struct ehci_hcd *ehci = hcd_to_ehci(hcd);
328 void __iomem *non_ehci = hcd->regs; 329 void __iomem *non_ehci = hcd->regs;
329 330
331 ehci_prepare_ports_for_controller_resume(ehci);
330 if (!fsl_deep_sleep()) 332 if (!fsl_deep_sleep())
331 return 0; 333 return 0;
332 334
diff --git a/drivers/usb/host/ehci-hub.c b/drivers/usb/host/ehci-hub.c
index ef956220f854..e7d3d8def282 100644
--- a/drivers/usb/host/ehci-hub.c
+++ b/drivers/usb/host/ehci-hub.c
@@ -106,12 +106,75 @@ static void ehci_handover_companion_ports(struct ehci_hcd *ehci)
106 ehci->owned_ports = 0; 106 ehci->owned_ports = 0;
107} 107}
108 108
109static void ehci_adjust_port_wakeup_flags(struct ehci_hcd *ehci,
110 bool suspending)
111{
112 int port;
113 u32 temp;
114
115 /* If remote wakeup is enabled for the root hub but disabled
116 * for the controller, we must adjust all the port wakeup flags
117 * when the controller is suspended or resumed. In all other
118 * cases they don't need to be changed.
119 */
120 if (!ehci_to_hcd(ehci)->self.root_hub->do_remote_wakeup ||
121 device_may_wakeup(ehci_to_hcd(ehci)->self.controller))
122 return;
123
124 /* clear phy low-power mode before changing wakeup flags */
125 if (ehci->has_hostpc) {
126 port = HCS_N_PORTS(ehci->hcs_params);
127 while (port--) {
128 u32 __iomem *hostpc_reg;
129
130 hostpc_reg = (u32 __iomem *)((u8 *) ehci->regs
131 + HOSTPC0 + 4 * port);
132 temp = ehci_readl(ehci, hostpc_reg);
133 ehci_writel(ehci, temp & ~HOSTPC_PHCD, hostpc_reg);
134 }
135 msleep(5);
136 }
137
138 port = HCS_N_PORTS(ehci->hcs_params);
139 while (port--) {
140 u32 __iomem *reg = &ehci->regs->port_status[port];
141 u32 t1 = ehci_readl(ehci, reg) & ~PORT_RWC_BITS;
142 u32 t2 = t1 & ~PORT_WAKE_BITS;
143
144 /* If we are suspending the controller, clear the flags.
145 * If we are resuming the controller, set the wakeup flags.
146 */
147 if (!suspending) {
148 if (t1 & PORT_CONNECT)
149 t2 |= PORT_WKOC_E | PORT_WKDISC_E;
150 else
151 t2 |= PORT_WKOC_E | PORT_WKCONN_E;
152 }
153 ehci_vdbg(ehci, "port %d, %08x -> %08x\n",
154 port + 1, t1, t2);
155 ehci_writel(ehci, t2, reg);
156 }
157
158 /* enter phy low-power mode again */
159 if (ehci->has_hostpc) {
160 port = HCS_N_PORTS(ehci->hcs_params);
161 while (port--) {
162 u32 __iomem *hostpc_reg;
163
164 hostpc_reg = (u32 __iomem *)((u8 *) ehci->regs
165 + HOSTPC0 + 4 * port);
166 temp = ehci_readl(ehci, hostpc_reg);
167 ehci_writel(ehci, temp | HOSTPC_PHCD, hostpc_reg);
168 }
169 }
170}
171
109static int ehci_bus_suspend (struct usb_hcd *hcd) 172static int ehci_bus_suspend (struct usb_hcd *hcd)
110{ 173{
111 struct ehci_hcd *ehci = hcd_to_ehci (hcd); 174 struct ehci_hcd *ehci = hcd_to_ehci (hcd);
112 int port; 175 int port;
113 int mask; 176 int mask;
114 u32 __iomem *hostpc_reg = NULL; 177 int changed;
115 178
116 ehci_dbg(ehci, "suspend root hub\n"); 179 ehci_dbg(ehci, "suspend root hub\n");
117 180
@@ -155,15 +218,13 @@ static int ehci_bus_suspend (struct usb_hcd *hcd)
155 */ 218 */
156 ehci->bus_suspended = 0; 219 ehci->bus_suspended = 0;
157 ehci->owned_ports = 0; 220 ehci->owned_ports = 0;
221 changed = 0;
158 port = HCS_N_PORTS(ehci->hcs_params); 222 port = HCS_N_PORTS(ehci->hcs_params);
159 while (port--) { 223 while (port--) {
160 u32 __iomem *reg = &ehci->regs->port_status [port]; 224 u32 __iomem *reg = &ehci->regs->port_status [port];
161 u32 t1 = ehci_readl(ehci, reg) & ~PORT_RWC_BITS; 225 u32 t1 = ehci_readl(ehci, reg) & ~PORT_RWC_BITS;
162 u32 t2 = t1; 226 u32 t2 = t1 & ~PORT_WAKE_BITS;
163 227
164 if (ehci->has_hostpc)
165 hostpc_reg = (u32 __iomem *)((u8 *)ehci->regs
166 + HOSTPC0 + 4 * (port & 0xff));
167 /* keep track of which ports we suspend */ 228 /* keep track of which ports we suspend */
168 if (t1 & PORT_OWNER) 229 if (t1 & PORT_OWNER)
169 set_bit(port, &ehci->owned_ports); 230 set_bit(port, &ehci->owned_ports);
@@ -172,40 +233,45 @@ static int ehci_bus_suspend (struct usb_hcd *hcd)
172 set_bit(port, &ehci->bus_suspended); 233 set_bit(port, &ehci->bus_suspended);
173 } 234 }
174 235
175 /* enable remote wakeup on all ports */ 236 /* enable remote wakeup on all ports, if told to do so */
176 if (hcd->self.root_hub->do_remote_wakeup) { 237 if (hcd->self.root_hub->do_remote_wakeup) {
177 /* only enable appropriate wake bits, otherwise the 238 /* only enable appropriate wake bits, otherwise the
178 * hardware can not go phy low power mode. If a race 239 * hardware can not go phy low power mode. If a race
179 * condition happens here(connection change during bits 240 * condition happens here(connection change during bits
180 * set), the port change detection will finally fix it. 241 * set), the port change detection will finally fix it.
181 */ 242 */
182 if (t1 & PORT_CONNECT) { 243 if (t1 & PORT_CONNECT)
183 t2 |= PORT_WKOC_E | PORT_WKDISC_E; 244 t2 |= PORT_WKOC_E | PORT_WKDISC_E;
184 t2 &= ~PORT_WKCONN_E; 245 else
185 } else {
186 t2 |= PORT_WKOC_E | PORT_WKCONN_E; 246 t2 |= PORT_WKOC_E | PORT_WKCONN_E;
187 t2 &= ~PORT_WKDISC_E; 247 }
188 }
189 } else
190 t2 &= ~PORT_WAKE_BITS;
191 248
192 if (t1 != t2) { 249 if (t1 != t2) {
193 ehci_vdbg (ehci, "port %d, %08x -> %08x\n", 250 ehci_vdbg (ehci, "port %d, %08x -> %08x\n",
194 port + 1, t1, t2); 251 port + 1, t1, t2);
195 ehci_writel(ehci, t2, reg); 252 ehci_writel(ehci, t2, reg);
196 if (hostpc_reg) { 253 changed = 1;
197 u32 t3; 254 }
255 }
198 256
199 spin_unlock_irq(&ehci->lock); 257 if (changed && ehci->has_hostpc) {
200 msleep(5);/* 5ms for HCD enter low pwr mode */ 258 spin_unlock_irq(&ehci->lock);
201 spin_lock_irq(&ehci->lock); 259 msleep(5); /* 5 ms for HCD to enter low-power mode */
202 t3 = ehci_readl(ehci, hostpc_reg); 260 spin_lock_irq(&ehci->lock);
203 ehci_writel(ehci, t3 | HOSTPC_PHCD, hostpc_reg); 261
204 t3 = ehci_readl(ehci, hostpc_reg); 262 port = HCS_N_PORTS(ehci->hcs_params);
205 ehci_dbg(ehci, "Port%d phy low pwr mode %s\n", 263 while (port--) {
264 u32 __iomem *hostpc_reg;
265 u32 t3;
266
267 hostpc_reg = (u32 __iomem *)((u8 *) ehci->regs
268 + HOSTPC0 + 4 * port);
269 t3 = ehci_readl(ehci, hostpc_reg);
270 ehci_writel(ehci, t3 | HOSTPC_PHCD, hostpc_reg);
271 t3 = ehci_readl(ehci, hostpc_reg);
272 ehci_dbg(ehci, "Port %d phy low-power mode %s\n",
206 port, (t3 & HOSTPC_PHCD) ? 273 port, (t3 & HOSTPC_PHCD) ?
207 "succeeded" : "failed"); 274 "succeeded" : "failed");
208 }
209 } 275 }
210 } 276 }
211 277
@@ -291,19 +357,28 @@ static int ehci_bus_resume (struct usb_hcd *hcd)
291 msleep(8); 357 msleep(8);
292 spin_lock_irq(&ehci->lock); 358 spin_lock_irq(&ehci->lock);
293 359
360 /* clear phy low-power mode before resume */
361 if (ehci->bus_suspended && ehci->has_hostpc) {
362 i = HCS_N_PORTS(ehci->hcs_params);
363 while (i--) {
364 if (test_bit(i, &ehci->bus_suspended)) {
365 u32 __iomem *hostpc_reg;
366
367 hostpc_reg = (u32 __iomem *)((u8 *) ehci->regs
368 + HOSTPC0 + 4 * i);
369 temp = ehci_readl(ehci, hostpc_reg);
370 ehci_writel(ehci, temp & ~HOSTPC_PHCD,
371 hostpc_reg);
372 }
373 }
374 spin_unlock_irq(&ehci->lock);
375 msleep(5);
376 spin_lock_irq(&ehci->lock);
377 }
378
294 /* manually resume the ports we suspended during bus_suspend() */ 379 /* manually resume the ports we suspended during bus_suspend() */
295 i = HCS_N_PORTS (ehci->hcs_params); 380 i = HCS_N_PORTS (ehci->hcs_params);
296 while (i--) { 381 while (i--) {
297 /* clear phy low power mode before resume */
298 if (ehci->has_hostpc) {
299 u32 __iomem *hostpc_reg =
300 (u32 __iomem *)((u8 *)ehci->regs
301 + HOSTPC0 + 4 * (i & 0xff));
302 temp = ehci_readl(ehci, hostpc_reg);
303 ehci_writel(ehci, temp & ~HOSTPC_PHCD,
304 hostpc_reg);
305 mdelay(5);
306 }
307 temp = ehci_readl(ehci, &ehci->regs->port_status [i]); 382 temp = ehci_readl(ehci, &ehci->regs->port_status [i]);
308 temp &= ~(PORT_RWC_BITS | PORT_WAKE_BITS); 383 temp &= ~(PORT_RWC_BITS | PORT_WAKE_BITS);
309 if (test_bit(i, &ehci->bus_suspended) && 384 if (test_bit(i, &ehci->bus_suspended) &&
@@ -685,23 +760,25 @@ static int ehci_hub_control (
685 goto error; 760 goto error;
686 if (ehci->no_selective_suspend) 761 if (ehci->no_selective_suspend)
687 break; 762 break;
688 if (temp & PORT_SUSPEND) { 763 if (!(temp & PORT_SUSPEND))
689 if ((temp & PORT_PE) == 0) 764 break;
690 goto error; 765 if ((temp & PORT_PE) == 0)
691 /* clear phy low power mode before resume */ 766 goto error;
692 if (hostpc_reg) { 767
693 temp1 = ehci_readl(ehci, hostpc_reg); 768 /* clear phy low-power mode before resume */
694 ehci_writel(ehci, temp1 & ~HOSTPC_PHCD, 769 if (hostpc_reg) {
770 temp1 = ehci_readl(ehci, hostpc_reg);
771 ehci_writel(ehci, temp1 & ~HOSTPC_PHCD,
695 hostpc_reg); 772 hostpc_reg);
696 mdelay(5); 773 spin_unlock_irqrestore(&ehci->lock, flags);
697 } 774 msleep(5);/* wait to leave low-power mode */
698 /* resume signaling for 20 msec */ 775 spin_lock_irqsave(&ehci->lock, flags);
699 temp &= ~(PORT_RWC_BITS | PORT_WAKE_BITS);
700 ehci_writel(ehci, temp | PORT_RESUME,
701 status_reg);
702 ehci->reset_done [wIndex] = jiffies
703 + msecs_to_jiffies (20);
704 } 776 }
777 /* resume signaling for 20 msec */
778 temp &= ~(PORT_RWC_BITS | PORT_WAKE_BITS);
779 ehci_writel(ehci, temp | PORT_RESUME, status_reg);
780 ehci->reset_done[wIndex] = jiffies
781 + msecs_to_jiffies(20);
705 break; 782 break;
706 case USB_PORT_FEAT_C_SUSPEND: 783 case USB_PORT_FEAT_C_SUSPEND:
707 clear_bit(wIndex, &ehci->port_c_suspend); 784 clear_bit(wIndex, &ehci->port_c_suspend);
diff --git a/drivers/usb/host/ehci-pci.c b/drivers/usb/host/ehci-pci.c
index d120059bbbf7..d43d176161aa 100644
--- a/drivers/usb/host/ehci-pci.c
+++ b/drivers/usb/host/ehci-pci.c
@@ -287,23 +287,15 @@ static int ehci_pci_suspend(struct usb_hcd *hcd)
287 msleep(10); 287 msleep(10);
288 288
289 /* Root hub was already suspended. Disable irq emission and 289 /* Root hub was already suspended. Disable irq emission and
290 * mark HW unaccessible, bail out if RH has been resumed. Use 290 * mark HW unaccessible. The PM and USB cores make sure that
291 * the spinlock to properly synchronize with possible pending 291 * the root hub is either suspended or stopped.
292 * RH suspend or resume activity.
293 *
294 * This is still racy as hcd->state is manipulated outside of
295 * any locks =P But that will be a different fix.
296 */ 292 */
297 spin_lock_irqsave (&ehci->lock, flags); 293 spin_lock_irqsave (&ehci->lock, flags);
298 if (hcd->state != HC_STATE_SUSPENDED) { 294 ehci_prepare_ports_for_controller_suspend(ehci);
299 rc = -EINVAL;
300 goto bail;
301 }
302 ehci_writel(ehci, 0, &ehci->regs->intr_enable); 295 ehci_writel(ehci, 0, &ehci->regs->intr_enable);
303 (void)ehci_readl(ehci, &ehci->regs->intr_enable); 296 (void)ehci_readl(ehci, &ehci->regs->intr_enable);
304 297
305 clear_bit(HCD_FLAG_HW_ACCESSIBLE, &hcd->flags); 298 clear_bit(HCD_FLAG_HW_ACCESSIBLE, &hcd->flags);
306 bail:
307 spin_unlock_irqrestore (&ehci->lock, flags); 299 spin_unlock_irqrestore (&ehci->lock, flags);
308 300
309 // could save FLADJ in case of Vaux power loss 301 // could save FLADJ in case of Vaux power loss
@@ -333,6 +325,7 @@ static int ehci_pci_resume(struct usb_hcd *hcd, bool hibernated)
333 !hibernated) { 325 !hibernated) {
334 int mask = INTR_MASK; 326 int mask = INTR_MASK;
335 327
328 ehci_prepare_ports_for_controller_resume(ehci);
336 if (!hcd->self.root_hub->do_remote_wakeup) 329 if (!hcd->self.root_hub->do_remote_wakeup)
337 mask &= ~STS_PCD; 330 mask &= ~STS_PCD;
338 ehci_writel(ehci, mask, &ehci->regs->intr_enable); 331 ehci_writel(ehci, mask, &ehci->regs->intr_enable);
diff --git a/drivers/usb/host/ehci.h b/drivers/usb/host/ehci.h
index 4ebe9ad209e4..650a687f2854 100644
--- a/drivers/usb/host/ehci.h
+++ b/drivers/usb/host/ehci.h
@@ -536,6 +536,16 @@ struct ehci_fstn {
536 536
537/*-------------------------------------------------------------------------*/ 537/*-------------------------------------------------------------------------*/
538 538
539/* Prepare the PORTSC wakeup flags during controller suspend/resume */
540
541#define ehci_prepare_ports_for_controller_suspend(ehci) \
542 ehci_adjust_port_wakeup_flags(ehci, true);
543
544#define ehci_prepare_ports_for_controller_resume(ehci) \
545 ehci_adjust_port_wakeup_flags(ehci, false);
546
547/*-------------------------------------------------------------------------*/
548
539#ifdef CONFIG_USB_EHCI_ROOT_HUB_TT 549#ifdef CONFIG_USB_EHCI_ROOT_HUB_TT
540 550
541/* 551/*