diff options
author | Alan Stern <stern@rowland.harvard.edu> | 2012-07-11 11:23:10 -0400 |
---|---|---|
committer | Greg Kroah-Hartman <gregkh@linuxfoundation.org> | 2012-07-16 19:56:48 -0400 |
commit | c4f3476436f7452b97c8accb5dd7d53219a11a3f (patch) | |
tree | 95711a24bb4357dab53d4641aae5a09292974fb8 | |
parent | f42890782241a60d107f23d08089a4a12b507a11 (diff) |
USB: EHCI: fix up locking
This patch (as1588) adjusts the locking in ehci-hcd's various halt,
shutdown, and suspend/resume pathways. We want to hold the spinlock
while writing device registers and accessing shared variables, but not
while polling in a loop.
In addition, there's no need to call ehci_work() at times when no URBs
can be active, i.e., in ehci_stop() and ehci_bus_suspend().
Finally, ehci_adjust_port_wakeup_flags() is called only in situations
where interrupts are enabled; therefore it can use spin_lock_irq
rather than spin_lock_irqsave.
Signed-off-by: Alan Stern <stern@rowland.harvard.edu>
Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
-rw-r--r-- | drivers/usb/host/ehci-hcd.c | 48 | ||||
-rw-r--r-- | drivers/usb/host/ehci-hub.c | 41 | ||||
-rw-r--r-- | drivers/usb/host/ehci-tegra.c | 5 |
3 files changed, 64 insertions, 30 deletions
diff --git a/drivers/usb/host/ehci-hcd.c b/drivers/usb/host/ehci-hcd.c index 340c9c4894bf..ac4c8ddde20a 100644 --- a/drivers/usb/host/ehci-hcd.c +++ b/drivers/usb/host/ehci-hcd.c | |||
@@ -167,21 +167,24 @@ static int tdi_in_host_mode (struct ehci_hcd *ehci) | |||
167 | return (tmp & 3) == USBMODE_CM_HC; | 167 | return (tmp & 3) == USBMODE_CM_HC; |
168 | } | 168 | } |
169 | 169 | ||
170 | /* force HC to halt state from unknown (EHCI spec section 2.3) */ | 170 | /* |
171 | * Force HC to halt state from unknown (EHCI spec section 2.3). | ||
172 | * Must be called with interrupts enabled and the lock not held. | ||
173 | */ | ||
171 | static int ehci_halt (struct ehci_hcd *ehci) | 174 | static int ehci_halt (struct ehci_hcd *ehci) |
172 | { | 175 | { |
173 | u32 temp = ehci_readl(ehci, &ehci->regs->status); | 176 | u32 temp; |
177 | |||
178 | spin_lock_irq(&ehci->lock); | ||
174 | 179 | ||
175 | /* disable any irqs left enabled by previous code */ | 180 | /* disable any irqs left enabled by previous code */ |
176 | ehci_writel(ehci, 0, &ehci->regs->intr_enable); | 181 | ehci_writel(ehci, 0, &ehci->regs->intr_enable); |
177 | 182 | ||
178 | if (ehci_is_TDI(ehci) && tdi_in_host_mode(ehci) == 0) { | 183 | if (ehci_is_TDI(ehci) && !tdi_in_host_mode(ehci)) { |
184 | spin_unlock_irq(&ehci->lock); | ||
179 | return 0; | 185 | return 0; |
180 | } | 186 | } |
181 | 187 | ||
182 | if ((temp & STS_HALT) != 0) | ||
183 | return 0; | ||
184 | |||
185 | /* | 188 | /* |
186 | * This routine gets called during probe before ehci->command | 189 | * This routine gets called during probe before ehci->command |
187 | * has been initialized, so we can't rely on its value. | 190 | * has been initialized, so we can't rely on its value. |
@@ -190,7 +193,11 @@ static int ehci_halt (struct ehci_hcd *ehci) | |||
190 | temp = ehci_readl(ehci, &ehci->regs->command); | 193 | temp = ehci_readl(ehci, &ehci->regs->command); |
191 | temp &= ~(CMD_RUN | CMD_IAAD); | 194 | temp &= ~(CMD_RUN | CMD_IAAD); |
192 | ehci_writel(ehci, temp, &ehci->regs->command); | 195 | ehci_writel(ehci, temp, &ehci->regs->command); |
193 | return handshake (ehci, &ehci->regs->status, | 196 | |
197 | spin_unlock_irq(&ehci->lock); | ||
198 | synchronize_irq(ehci_to_hcd(ehci)->irq); | ||
199 | |||
200 | return handshake(ehci, &ehci->regs->status, | ||
194 | STS_HALT, STS_HALT, 16 * 125); | 201 | STS_HALT, STS_HALT, 16 * 125); |
195 | } | 202 | } |
196 | 203 | ||
@@ -210,7 +217,10 @@ static void tdi_reset (struct ehci_hcd *ehci) | |||
210 | ehci_writel(ehci, tmp, &ehci->regs->usbmode); | 217 | ehci_writel(ehci, tmp, &ehci->regs->usbmode); |
211 | } | 218 | } |
212 | 219 | ||
213 | /* reset a non-running (STS_HALT == 1) controller */ | 220 | /* |
221 | * Reset a non-running (STS_HALT == 1) controller. | ||
222 | * Must be called with interrupts enabled and the lock not held. | ||
223 | */ | ||
214 | static int ehci_reset (struct ehci_hcd *ehci) | 224 | static int ehci_reset (struct ehci_hcd *ehci) |
215 | { | 225 | { |
216 | int retval; | 226 | int retval; |
@@ -248,7 +258,10 @@ static int ehci_reset (struct ehci_hcd *ehci) | |||
248 | return retval; | 258 | return retval; |
249 | } | 259 | } |
250 | 260 | ||
251 | /* idle the controller (from running) */ | 261 | /* |
262 | * Idle the controller (turn off the schedules). | ||
263 | * Must be called with interrupts enabled and the lock not held. | ||
264 | */ | ||
252 | static void ehci_quiesce (struct ehci_hcd *ehci) | 265 | static void ehci_quiesce (struct ehci_hcd *ehci) |
253 | { | 266 | { |
254 | u32 temp; | 267 | u32 temp; |
@@ -261,8 +274,10 @@ static void ehci_quiesce (struct ehci_hcd *ehci) | |||
261 | handshake(ehci, &ehci->regs->status, STS_ASS | STS_PSS, temp, 16 * 125); | 274 | handshake(ehci, &ehci->regs->status, STS_ASS | STS_PSS, temp, 16 * 125); |
262 | 275 | ||
263 | /* then disable anything that's still active */ | 276 | /* then disable anything that's still active */ |
277 | spin_lock_irq(&ehci->lock); | ||
264 | ehci->command &= ~(CMD_ASE | CMD_PSE); | 278 | ehci->command &= ~(CMD_ASE | CMD_PSE); |
265 | ehci_writel(ehci, ehci->command, &ehci->regs->command); | 279 | ehci_writel(ehci, ehci->command, &ehci->regs->command); |
280 | spin_unlock_irq(&ehci->lock); | ||
266 | 281 | ||
267 | /* hardware can take 16 microframes to turn off ... */ | 282 | /* hardware can take 16 microframes to turn off ... */ |
268 | handshake(ehci, &ehci->regs->status, STS_ASS | STS_PSS, 0, 16 * 125); | 283 | handshake(ehci, &ehci->regs->status, STS_ASS | STS_PSS, 0, 16 * 125); |
@@ -301,11 +316,14 @@ static void ehci_turn_off_all_ports(struct ehci_hcd *ehci) | |||
301 | 316 | ||
302 | /* | 317 | /* |
303 | * Halt HC, turn off all ports, and let the BIOS use the companion controllers. | 318 | * Halt HC, turn off all ports, and let the BIOS use the companion controllers. |
304 | * Should be called with ehci->lock held. | 319 | * Must be called with interrupts enabled and the lock not held. |
305 | */ | 320 | */ |
306 | static void ehci_silence_controller(struct ehci_hcd *ehci) | 321 | static void ehci_silence_controller(struct ehci_hcd *ehci) |
307 | { | 322 | { |
308 | ehci_halt(ehci); | 323 | ehci_halt(ehci); |
324 | |||
325 | spin_lock_irq(&ehci->lock); | ||
326 | ehci->rh_state = EHCI_RH_HALTED; | ||
309 | ehci_turn_off_all_ports(ehci); | 327 | ehci_turn_off_all_ports(ehci); |
310 | 328 | ||
311 | /* make BIOS/etc use companion controller during reboot */ | 329 | /* make BIOS/etc use companion controller during reboot */ |
@@ -313,6 +331,7 @@ static void ehci_silence_controller(struct ehci_hcd *ehci) | |||
313 | 331 | ||
314 | /* unblock posted writes */ | 332 | /* unblock posted writes */ |
315 | ehci_readl(ehci, &ehci->regs->configured_flag); | 333 | ehci_readl(ehci, &ehci->regs->configured_flag); |
334 | spin_unlock_irq(&ehci->lock); | ||
316 | } | 335 | } |
317 | 336 | ||
318 | /* ehci_shutdown kick in for silicon on any bus (not just pci, etc). | 337 | /* ehci_shutdown kick in for silicon on any bus (not just pci, etc). |
@@ -325,10 +344,11 @@ static void ehci_shutdown(struct usb_hcd *hcd) | |||
325 | 344 | ||
326 | spin_lock_irq(&ehci->lock); | 345 | spin_lock_irq(&ehci->lock); |
327 | ehci->rh_state = EHCI_RH_STOPPING; | 346 | ehci->rh_state = EHCI_RH_STOPPING; |
328 | ehci_silence_controller(ehci); | ||
329 | ehci->enabled_hrtimer_events = 0; | 347 | ehci->enabled_hrtimer_events = 0; |
330 | spin_unlock_irq(&ehci->lock); | 348 | spin_unlock_irq(&ehci->lock); |
331 | 349 | ||
350 | ehci_silence_controller(ehci); | ||
351 | |||
332 | hrtimer_cancel(&ehci->hrtimer); | 352 | hrtimer_cancel(&ehci->hrtimer); |
333 | } | 353 | } |
334 | 354 | ||
@@ -400,11 +420,11 @@ static void ehci_stop (struct usb_hcd *hcd) | |||
400 | 420 | ||
401 | spin_lock_irq(&ehci->lock); | 421 | spin_lock_irq(&ehci->lock); |
402 | ehci->enabled_hrtimer_events = 0; | 422 | ehci->enabled_hrtimer_events = 0; |
403 | ehci_quiesce(ehci); | 423 | spin_unlock_irq(&ehci->lock); |
404 | 424 | ||
425 | ehci_quiesce(ehci); | ||
405 | ehci_silence_controller(ehci); | 426 | ehci_silence_controller(ehci); |
406 | ehci_reset (ehci); | 427 | ehci_reset (ehci); |
407 | spin_unlock_irq(&ehci->lock); | ||
408 | 428 | ||
409 | hrtimer_cancel(&ehci->hrtimer); | 429 | hrtimer_cancel(&ehci->hrtimer); |
410 | remove_sysfs_files(ehci); | 430 | remove_sysfs_files(ehci); |
@@ -412,8 +432,6 @@ static void ehci_stop (struct usb_hcd *hcd) | |||
412 | 432 | ||
413 | /* root hub is shut down separately (first, when possible) */ | 433 | /* root hub is shut down separately (first, when possible) */ |
414 | spin_lock_irq (&ehci->lock); | 434 | spin_lock_irq (&ehci->lock); |
415 | if (ehci->async) | ||
416 | ehci_work (ehci); | ||
417 | end_free_itds(ehci); | 435 | end_free_itds(ehci); |
418 | spin_unlock_irq (&ehci->lock); | 436 | spin_unlock_irq (&ehci->lock); |
419 | ehci_mem_cleanup (ehci); | 437 | ehci_mem_cleanup (ehci); |
diff --git a/drivers/usb/host/ehci-hub.c b/drivers/usb/host/ehci-hub.c index 05490d387fd2..ffc5f27df725 100644 --- a/drivers/usb/host/ehci-hub.c +++ b/drivers/usb/host/ehci-hub.c | |||
@@ -59,6 +59,7 @@ static void ehci_handover_companion_ports(struct ehci_hcd *ehci) | |||
59 | /* Give the connections some time to appear */ | 59 | /* Give the connections some time to appear */ |
60 | msleep(20); | 60 | msleep(20); |
61 | 61 | ||
62 | spin_lock_irq(&ehci->lock); | ||
62 | port = HCS_N_PORTS(ehci->hcs_params); | 63 | port = HCS_N_PORTS(ehci->hcs_params); |
63 | while (port--) { | 64 | while (port--) { |
64 | if (test_bit(port, &ehci->owned_ports)) { | 65 | if (test_bit(port, &ehci->owned_ports)) { |
@@ -70,23 +71,30 @@ static void ehci_handover_companion_ports(struct ehci_hcd *ehci) | |||
70 | clear_bit(port, &ehci->owned_ports); | 71 | clear_bit(port, &ehci->owned_ports); |
71 | else if (test_bit(port, &ehci->companion_ports)) | 72 | else if (test_bit(port, &ehci->companion_ports)) |
72 | ehci_writel(ehci, status & ~PORT_PE, reg); | 73 | ehci_writel(ehci, status & ~PORT_PE, reg); |
73 | else | 74 | else { |
75 | spin_unlock_irq(&ehci->lock); | ||
74 | ehci_hub_control(hcd, SetPortFeature, | 76 | ehci_hub_control(hcd, SetPortFeature, |
75 | USB_PORT_FEAT_RESET, port + 1, | 77 | USB_PORT_FEAT_RESET, port + 1, |
76 | NULL, 0); | 78 | NULL, 0); |
79 | spin_lock_irq(&ehci->lock); | ||
80 | } | ||
77 | } | 81 | } |
78 | } | 82 | } |
83 | spin_unlock_irq(&ehci->lock); | ||
79 | 84 | ||
80 | if (!ehci->owned_ports) | 85 | if (!ehci->owned_ports) |
81 | return; | 86 | return; |
82 | msleep(90); /* Wait for resets to complete */ | 87 | msleep(90); /* Wait for resets to complete */ |
83 | 88 | ||
89 | spin_lock_irq(&ehci->lock); | ||
84 | port = HCS_N_PORTS(ehci->hcs_params); | 90 | port = HCS_N_PORTS(ehci->hcs_params); |
85 | while (port--) { | 91 | while (port--) { |
86 | if (test_bit(port, &ehci->owned_ports)) { | 92 | if (test_bit(port, &ehci->owned_ports)) { |
93 | spin_unlock_irq(&ehci->lock); | ||
87 | ehci_hub_control(hcd, GetPortStatus, | 94 | ehci_hub_control(hcd, GetPortStatus, |
88 | 0, port + 1, | 95 | 0, port + 1, |
89 | (char *) &buf, sizeof(buf)); | 96 | (char *) &buf, sizeof(buf)); |
97 | spin_lock_irq(&ehci->lock); | ||
90 | 98 | ||
91 | /* The companion should now own the port, | 99 | /* The companion should now own the port, |
92 | * but if something went wrong the port must not | 100 | * but if something went wrong the port must not |
@@ -105,6 +113,7 @@ static void ehci_handover_companion_ports(struct ehci_hcd *ehci) | |||
105 | } | 113 | } |
106 | 114 | ||
107 | ehci->owned_ports = 0; | 115 | ehci->owned_ports = 0; |
116 | spin_unlock_irq(&ehci->lock); | ||
108 | } | 117 | } |
109 | 118 | ||
110 | static int ehci_port_change(struct ehci_hcd *ehci) | 119 | static int ehci_port_change(struct ehci_hcd *ehci) |
@@ -133,7 +142,6 @@ static void ehci_adjust_port_wakeup_flags(struct ehci_hcd *ehci, | |||
133 | { | 142 | { |
134 | int port; | 143 | int port; |
135 | u32 temp; | 144 | u32 temp; |
136 | unsigned long flags; | ||
137 | 145 | ||
138 | /* If remote wakeup is enabled for the root hub but disabled | 146 | /* If remote wakeup is enabled for the root hub but disabled |
139 | * for the controller, we must adjust all the port wakeup flags | 147 | * for the controller, we must adjust all the port wakeup flags |
@@ -143,7 +151,7 @@ static void ehci_adjust_port_wakeup_flags(struct ehci_hcd *ehci, | |||
143 | if (!ehci_to_hcd(ehci)->self.root_hub->do_remote_wakeup || do_wakeup) | 151 | if (!ehci_to_hcd(ehci)->self.root_hub->do_remote_wakeup || do_wakeup) |
144 | return; | 152 | return; |
145 | 153 | ||
146 | spin_lock_irqsave(&ehci->lock, flags); | 154 | spin_lock_irq(&ehci->lock); |
147 | 155 | ||
148 | /* clear phy low-power mode before changing wakeup flags */ | 156 | /* clear phy low-power mode before changing wakeup flags */ |
149 | if (ehci->has_hostpc) { | 157 | if (ehci->has_hostpc) { |
@@ -154,9 +162,9 @@ static void ehci_adjust_port_wakeup_flags(struct ehci_hcd *ehci, | |||
154 | temp = ehci_readl(ehci, hostpc_reg); | 162 | temp = ehci_readl(ehci, hostpc_reg); |
155 | ehci_writel(ehci, temp & ~HOSTPC_PHCD, hostpc_reg); | 163 | ehci_writel(ehci, temp & ~HOSTPC_PHCD, hostpc_reg); |
156 | } | 164 | } |
157 | spin_unlock_irqrestore(&ehci->lock, flags); | 165 | spin_unlock_irq(&ehci->lock); |
158 | msleep(5); | 166 | msleep(5); |
159 | spin_lock_irqsave(&ehci->lock, flags); | 167 | spin_lock_irq(&ehci->lock); |
160 | } | 168 | } |
161 | 169 | ||
162 | port = HCS_N_PORTS(ehci->hcs_params); | 170 | port = HCS_N_PORTS(ehci->hcs_params); |
@@ -194,7 +202,7 @@ static void ehci_adjust_port_wakeup_flags(struct ehci_hcd *ehci, | |||
194 | if (!suspending && ehci_port_change(ehci)) | 202 | if (!suspending && ehci_port_change(ehci)) |
195 | usb_hcd_resume_root_hub(ehci_to_hcd(ehci)); | 203 | usb_hcd_resume_root_hub(ehci_to_hcd(ehci)); |
196 | 204 | ||
197 | spin_unlock_irqrestore(&ehci->lock, flags); | 205 | spin_unlock_irq(&ehci->lock); |
198 | } | 206 | } |
199 | 207 | ||
200 | static int ehci_bus_suspend (struct usb_hcd *hcd) | 208 | static int ehci_bus_suspend (struct usb_hcd *hcd) |
@@ -209,6 +217,9 @@ static int ehci_bus_suspend (struct usb_hcd *hcd) | |||
209 | if (time_before (jiffies, ehci->next_statechange)) | 217 | if (time_before (jiffies, ehci->next_statechange)) |
210 | msleep(5); | 218 | msleep(5); |
211 | 219 | ||
220 | /* stop the schedules */ | ||
221 | ehci_quiesce(ehci); | ||
222 | |||
212 | spin_lock_irq (&ehci->lock); | 223 | spin_lock_irq (&ehci->lock); |
213 | 224 | ||
214 | /* Once the controller is stopped, port resumes that are already | 225 | /* Once the controller is stopped, port resumes that are already |
@@ -224,10 +235,6 @@ static int ehci_bus_suspend (struct usb_hcd *hcd) | |||
224 | } | 235 | } |
225 | } | 236 | } |
226 | 237 | ||
227 | /* stop schedules, clean any completed work */ | ||
228 | ehci_quiesce(ehci); | ||
229 | ehci_work(ehci); | ||
230 | |||
231 | /* Unlike other USB host controller types, EHCI doesn't have | 238 | /* Unlike other USB host controller types, EHCI doesn't have |
232 | * any notion of "global" or bus-wide suspend. The driver has | 239 | * any notion of "global" or bus-wide suspend. The driver has |
233 | * to manually suspend all the active unsuspended ports, and | 240 | * to manually suspend all the active unsuspended ports, and |
@@ -289,6 +296,7 @@ static int ehci_bus_suspend (struct usb_hcd *hcd) | |||
289 | "succeeded" : "failed"); | 296 | "succeeded" : "failed"); |
290 | } | 297 | } |
291 | } | 298 | } |
299 | spin_unlock_irq(&ehci->lock); | ||
292 | 300 | ||
293 | /* Apparently some devices need a >= 1-uframe delay here */ | 301 | /* Apparently some devices need a >= 1-uframe delay here */ |
294 | if (ehci->bus_suspended) | 302 | if (ehci->bus_suspended) |
@@ -296,6 +304,8 @@ static int ehci_bus_suspend (struct usb_hcd *hcd) | |||
296 | 304 | ||
297 | /* turn off now-idle HC */ | 305 | /* turn off now-idle HC */ |
298 | ehci_halt (ehci); | 306 | ehci_halt (ehci); |
307 | |||
308 | spin_lock_irq(&ehci->lock); | ||
299 | ehci->rh_state = EHCI_RH_SUSPENDED; | 309 | ehci->rh_state = EHCI_RH_SUSPENDED; |
300 | 310 | ||
301 | end_unlink_async(ehci); | 311 | end_unlink_async(ehci); |
@@ -424,13 +434,14 @@ static int ehci_bus_resume (struct usb_hcd *hcd) | |||
424 | } | 434 | } |
425 | 435 | ||
426 | ehci->next_statechange = jiffies + msecs_to_jiffies(5); | 436 | ehci->next_statechange = jiffies + msecs_to_jiffies(5); |
437 | spin_unlock_irq(&ehci->lock); | ||
438 | |||
439 | ehci_handover_companion_ports(ehci); | ||
427 | 440 | ||
428 | /* Now we can safely re-enable irqs */ | 441 | /* Now we can safely re-enable irqs */ |
429 | ehci_writel(ehci, INTR_MASK, &ehci->regs->intr_enable); | 442 | ehci_writel(ehci, INTR_MASK, &ehci->regs->intr_enable); |
430 | (void) ehci_readl(ehci, &ehci->regs->intr_enable); | 443 | (void) ehci_readl(ehci, &ehci->regs->intr_enable); |
431 | 444 | ||
432 | spin_unlock_irq (&ehci->lock); | ||
433 | ehci_handover_companion_ports(ehci); | ||
434 | return 0; | 445 | return 0; |
435 | } | 446 | } |
436 | 447 | ||
@@ -1018,7 +1029,9 @@ static int ehci_hub_control ( | |||
1018 | case USB_PORT_FEAT_TEST: | 1029 | case USB_PORT_FEAT_TEST: |
1019 | if (!selector || selector > 5) | 1030 | if (!selector || selector > 5) |
1020 | goto error; | 1031 | goto error; |
1032 | spin_unlock_irqrestore(&ehci->lock, flags); | ||
1021 | ehci_quiesce(ehci); | 1033 | ehci_quiesce(ehci); |
1034 | spin_lock_irqsave(&ehci->lock, flags); | ||
1022 | 1035 | ||
1023 | /* Put all enabled ports into suspend */ | 1036 | /* Put all enabled ports into suspend */ |
1024 | while (ports--) { | 1037 | while (ports--) { |
@@ -1030,7 +1043,11 @@ static int ehci_hub_control ( | |||
1030 | ehci_writel(ehci, temp | PORT_SUSPEND, | 1043 | ehci_writel(ehci, temp | PORT_SUSPEND, |
1031 | sreg); | 1044 | sreg); |
1032 | } | 1045 | } |
1046 | |||
1047 | spin_unlock_irqrestore(&ehci->lock, flags); | ||
1033 | ehci_halt(ehci); | 1048 | ehci_halt(ehci); |
1049 | spin_lock_irqsave(&ehci->lock, flags); | ||
1050 | |||
1034 | temp = ehci_readl(ehci, status_reg); | 1051 | temp = ehci_readl(ehci, status_reg); |
1035 | temp |= selector << 16; | 1052 | temp |= selector << 16; |
1036 | ehci_writel(ehci, temp, status_reg); | 1053 | ehci_writel(ehci, temp, status_reg); |
diff --git a/drivers/usb/host/ehci-tegra.c b/drivers/usb/host/ehci-tegra.c index f7f3ce3275b8..65360945df78 100644 --- a/drivers/usb/host/ehci-tegra.c +++ b/drivers/usb/host/ehci-tegra.c | |||
@@ -445,12 +445,11 @@ static int controller_suspend(struct device *dev) | |||
445 | if (time_before(jiffies, ehci->next_statechange)) | 445 | if (time_before(jiffies, ehci->next_statechange)) |
446 | msleep(10); | 446 | msleep(10); |
447 | 447 | ||
448 | spin_lock_irqsave(&ehci->lock, flags); | 448 | ehci_halt(ehci); |
449 | 449 | ||
450 | spin_lock_irqsave(&ehci->lock, flags); | ||
450 | tegra->port_speed = (readl(&hw->port_status[0]) >> 26) & 0x3; | 451 | tegra->port_speed = (readl(&hw->port_status[0]) >> 26) & 0x3; |
451 | ehci_halt(ehci); | ||
452 | clear_bit(HCD_FLAG_HW_ACCESSIBLE, &hcd->flags); | 452 | clear_bit(HCD_FLAG_HW_ACCESSIBLE, &hcd->flags); |
453 | |||
454 | spin_unlock_irqrestore(&ehci->lock, flags); | 453 | spin_unlock_irqrestore(&ehci->lock, flags); |
455 | 454 | ||
456 | tegra_ehci_power_down(hcd); | 455 | tegra_ehci_power_down(hcd); |