diff options
author | Alan Stern <stern@rowland.harvard.edu> | 2012-04-23 13:54:36 -0400 |
---|---|---|
committer | Greg Kroah-Hartman <gregkh@linuxfoundation.org> | 2012-04-23 15:05:44 -0400 |
commit | 3d9545cc375d117554a9b35dfddadf9189c62775 (patch) | |
tree | b01707d2e0901665f20bae0f0c5a0930af69651a /drivers/usb/host | |
parent | 09091a4d5f2dd378dcf71de50b48cdacc58a8ac0 (diff) |
EHCI: maintain the ehci->command value properly
The ehci-hcd driver is a little haphazard about keeping track of the
state of the USBCMD register. The ehci->command field is supposed to
hold the register's value (apart from a few special bits) at all
times, but it isn't maintained properly.
This patch (as1543) cleans up the situation. It keeps ehci->command
up-to-date, and uses that value rather than reading the register from
the hardware whenever possible.
Signed-off-by: Alan Stern <stern@rowland.harvard.edu>
Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
Diffstat (limited to 'drivers/usb/host')
-rw-r--r-- | drivers/usb/host/ehci-dbg.c | 6 | ||||
-rw-r--r-- | drivers/usb/host/ehci-hcd.c | 16 | ||||
-rw-r--r-- | drivers/usb/host/ehci-hub.c | 2 | ||||
-rw-r--r-- | drivers/usb/host/ehci-q.c | 16 | ||||
-rw-r--r-- | drivers/usb/host/ehci-sched.c | 10 |
5 files changed, 23 insertions, 27 deletions
diff --git a/drivers/usb/host/ehci-dbg.c b/drivers/usb/host/ehci-dbg.c index 680e1a31fb8..7561966fbdc 100644 --- a/drivers/usb/host/ehci-dbg.c +++ b/drivers/usb/host/ehci-dbg.c | |||
@@ -1025,10 +1025,8 @@ static ssize_t debug_lpm_write(struct file *file, const char __user *user_buf, | |||
1025 | if (strict_strtoul(buf + 5, 16, &hird)) | 1025 | if (strict_strtoul(buf + 5, 16, &hird)) |
1026 | return -EINVAL; | 1026 | return -EINVAL; |
1027 | printk(KERN_INFO "setting hird %s %lu\n", buf + 6, hird); | 1027 | printk(KERN_INFO "setting hird %s %lu\n", buf + 6, hird); |
1028 | temp = ehci_readl(ehci, &ehci->regs->command); | 1028 | ehci->command = (ehci->command & ~CMD_HIRD) | (hird << 24); |
1029 | temp &= ~CMD_HIRD; | 1029 | ehci_writel(ehci, ehci->command, &ehci->regs->command); |
1030 | temp |= hird << 24; | ||
1031 | ehci_writel(ehci, temp, &ehci->regs->command); | ||
1032 | } else if (strncmp(buf, "disable", 7) == 0) { | 1030 | } else if (strncmp(buf, "disable", 7) == 0) { |
1033 | if (strict_strtoul(buf + 8, 10, &port)) | 1031 | if (strict_strtoul(buf + 8, 10, &port)) |
1034 | return -EINVAL; | 1032 | return -EINVAL; |
diff --git a/drivers/usb/host/ehci-hcd.c b/drivers/usb/host/ehci-hcd.c index a87c0573c86..de1e689d3df 100644 --- a/drivers/usb/host/ehci-hcd.c +++ b/drivers/usb/host/ehci-hcd.c | |||
@@ -226,8 +226,13 @@ static int ehci_halt (struct ehci_hcd *ehci) | |||
226 | if ((temp & STS_HALT) != 0) | 226 | if ((temp & STS_HALT) != 0) |
227 | return 0; | 227 | return 0; |
228 | 228 | ||
229 | /* | ||
230 | * This routine gets called during probe before ehci->command | ||
231 | * has been initialized, so we can't rely on its value. | ||
232 | */ | ||
233 | ehci->command &= ~CMD_RUN; | ||
229 | temp = ehci_readl(ehci, &ehci->regs->command); | 234 | temp = ehci_readl(ehci, &ehci->regs->command); |
230 | temp &= ~CMD_RUN; | 235 | temp &= ~(CMD_RUN | CMD_IAAD); |
231 | ehci_writel(ehci, temp, &ehci->regs->command); | 236 | ehci_writel(ehci, temp, &ehci->regs->command); |
232 | return handshake (ehci, &ehci->regs->status, | 237 | return handshake (ehci, &ehci->regs->status, |
233 | STS_HALT, STS_HALT, 16 * 125); | 238 | STS_HALT, STS_HALT, 16 * 125); |
@@ -347,6 +352,7 @@ static int ehci_reset (struct ehci_hcd *ehci) | |||
347 | if (ehci->debug) | 352 | if (ehci->debug) |
348 | dbgp_external_startup(); | 353 | dbgp_external_startup(); |
349 | 354 | ||
355 | ehci->command = ehci_readl(ehci, &ehci->regs->command); | ||
350 | ehci->port_c_suspend = ehci->suspended_ports = | 356 | ehci->port_c_suspend = ehci->suspended_ports = |
351 | ehci->resuming_ports = 0; | 357 | ehci->resuming_ports = 0; |
352 | return retval; | 358 | return retval; |
@@ -363,16 +369,14 @@ static void ehci_quiesce (struct ehci_hcd *ehci) | |||
363 | #endif | 369 | #endif |
364 | 370 | ||
365 | /* wait for any schedule enables/disables to take effect */ | 371 | /* wait for any schedule enables/disables to take effect */ |
366 | temp = ehci_readl(ehci, &ehci->regs->command) << 10; | 372 | temp = (ehci->command << 10) & (STS_ASS | STS_PSS); |
367 | temp &= STS_ASS | STS_PSS; | ||
368 | if (handshake_on_error_set_halt(ehci, &ehci->regs->status, | 373 | if (handshake_on_error_set_halt(ehci, &ehci->regs->status, |
369 | STS_ASS | STS_PSS, temp, 16 * 125)) | 374 | STS_ASS | STS_PSS, temp, 16 * 125)) |
370 | return; | 375 | return; |
371 | 376 | ||
372 | /* then disable anything that's still active */ | 377 | /* then disable anything that's still active */ |
373 | temp = ehci_readl(ehci, &ehci->regs->command); | 378 | ehci->command &= ~(CMD_ASE | CMD_PSE); |
374 | temp &= ~(CMD_ASE | CMD_IAAD | CMD_PSE); | 379 | ehci_writel(ehci, ehci->command, &ehci->regs->command); |
375 | ehci_writel(ehci, temp, &ehci->regs->command); | ||
376 | 380 | ||
377 | /* hardware can take 16 microframes to turn off ... */ | 381 | /* hardware can take 16 microframes to turn off ... */ |
378 | handshake_on_error_set_halt(ehci, &ehci->regs->status, | 382 | handshake_on_error_set_halt(ehci, &ehci->regs->status, |
diff --git a/drivers/usb/host/ehci-hub.c b/drivers/usb/host/ehci-hub.c index 402e766df2f..fc9e7cc6ac9 100644 --- a/drivers/usb/host/ehci-hub.c +++ b/drivers/usb/host/ehci-hub.c | |||
@@ -233,7 +233,6 @@ static int ehci_bus_suspend (struct usb_hcd *hcd) | |||
233 | /* stop schedules, clean any completed work */ | 233 | /* stop schedules, clean any completed work */ |
234 | if (ehci->rh_state == EHCI_RH_RUNNING) | 234 | if (ehci->rh_state == EHCI_RH_RUNNING) |
235 | ehci_quiesce (ehci); | 235 | ehci_quiesce (ehci); |
236 | ehci->command = ehci_readl(ehci, &ehci->regs->command); | ||
237 | ehci_work(ehci); | 236 | ehci_work(ehci); |
238 | 237 | ||
239 | /* Unlike other USB host controller types, EHCI doesn't have | 238 | /* Unlike other USB host controller types, EHCI doesn't have |
@@ -374,6 +373,7 @@ static int ehci_bus_resume (struct usb_hcd *hcd) | |||
374 | ehci_writel(ehci, (u32) ehci->async->qh_dma, &ehci->regs->async_next); | 373 | ehci_writel(ehci, (u32) ehci->async->qh_dma, &ehci->regs->async_next); |
375 | 374 | ||
376 | /* restore CMD_RUN, framelist size, and irq threshold */ | 375 | /* restore CMD_RUN, framelist size, and irq threshold */ |
376 | ehci->command |= CMD_RUN; | ||
377 | ehci_writel(ehci, ehci->command, &ehci->regs->command); | 377 | ehci_writel(ehci, ehci->command, &ehci->regs->command); |
378 | ehci->rh_state = EHCI_RH_RUNNING; | 378 | ehci->rh_state = EHCI_RH_RUNNING; |
379 | 379 | ||
diff --git a/drivers/usb/host/ehci-q.c b/drivers/usb/host/ehci-q.c index 36ca5077cdf..13f4f980841 100644 --- a/drivers/usb/host/ehci-q.c +++ b/drivers/usb/host/ehci-q.c | |||
@@ -981,14 +981,12 @@ static void qh_link_async (struct ehci_hcd *ehci, struct ehci_qh *qh) | |||
981 | head = ehci->async; | 981 | head = ehci->async; |
982 | timer_action_done (ehci, TIMER_ASYNC_OFF); | 982 | timer_action_done (ehci, TIMER_ASYNC_OFF); |
983 | if (!head->qh_next.qh) { | 983 | if (!head->qh_next.qh) { |
984 | u32 cmd = ehci_readl(ehci, &ehci->regs->command); | 984 | if (!(ehci->command & CMD_ASE)) { |
985 | |||
986 | if (!(cmd & CMD_ASE)) { | ||
987 | /* in case a clear of CMD_ASE didn't take yet */ | 985 | /* in case a clear of CMD_ASE didn't take yet */ |
988 | (void)handshake(ehci, &ehci->regs->status, | 986 | (void)handshake(ehci, &ehci->regs->status, |
989 | STS_ASS, 0, 150); | 987 | STS_ASS, 0, 150); |
990 | cmd |= CMD_ASE; | 988 | ehci->command |= CMD_ASE; |
991 | ehci_writel(ehci, cmd, &ehci->regs->command); | 989 | ehci_writel(ehci, ehci->command, &ehci->regs->command); |
992 | /* posted write need not be known to HC yet ... */ | 990 | /* posted write need not be known to HC yet ... */ |
993 | } | 991 | } |
994 | } | 992 | } |
@@ -1204,7 +1202,6 @@ static void end_unlink_async (struct ehci_hcd *ehci) | |||
1204 | 1202 | ||
1205 | static void start_unlink_async (struct ehci_hcd *ehci, struct ehci_qh *qh) | 1203 | static void start_unlink_async (struct ehci_hcd *ehci, struct ehci_qh *qh) |
1206 | { | 1204 | { |
1207 | int cmd = ehci_readl(ehci, &ehci->regs->command); | ||
1208 | struct ehci_qh *prev; | 1205 | struct ehci_qh *prev; |
1209 | 1206 | ||
1210 | #ifdef DEBUG | 1207 | #ifdef DEBUG |
@@ -1222,8 +1219,8 @@ static void start_unlink_async (struct ehci_hcd *ehci, struct ehci_qh *qh) | |||
1222 | if (ehci->rh_state != EHCI_RH_HALTED | 1219 | if (ehci->rh_state != EHCI_RH_HALTED |
1223 | && !ehci->reclaim) { | 1220 | && !ehci->reclaim) { |
1224 | /* ... and CMD_IAAD clear */ | 1221 | /* ... and CMD_IAAD clear */ |
1225 | ehci_writel(ehci, cmd & ~CMD_ASE, | 1222 | ehci->command &= ~CMD_ASE; |
1226 | &ehci->regs->command); | 1223 | ehci_writel(ehci, ehci->command, &ehci->regs->command); |
1227 | wmb (); | 1224 | wmb (); |
1228 | // handshake later, if we need to | 1225 | // handshake later, if we need to |
1229 | timer_action_done (ehci, TIMER_ASYNC_OFF); | 1226 | timer_action_done (ehci, TIMER_ASYNC_OFF); |
@@ -1253,8 +1250,7 @@ static void start_unlink_async (struct ehci_hcd *ehci, struct ehci_qh *qh) | |||
1253 | return; | 1250 | return; |
1254 | } | 1251 | } |
1255 | 1252 | ||
1256 | cmd |= CMD_IAAD; | 1253 | ehci_writel(ehci, ehci->command | CMD_IAAD, &ehci->regs->command); |
1257 | ehci_writel(ehci, cmd, &ehci->regs->command); | ||
1258 | (void)ehci_readl(ehci, &ehci->regs->command); | 1254 | (void)ehci_readl(ehci, &ehci->regs->command); |
1259 | iaa_watchdog_start(ehci); | 1255 | iaa_watchdog_start(ehci); |
1260 | } | 1256 | } |
diff --git a/drivers/usb/host/ehci-sched.c b/drivers/usb/host/ehci-sched.c index a60679cbbf8..ffe8fc3bc7e 100644 --- a/drivers/usb/host/ehci-sched.c +++ b/drivers/usb/host/ehci-sched.c | |||
@@ -481,7 +481,6 @@ static int tt_no_collision ( | |||
481 | 481 | ||
482 | static int enable_periodic (struct ehci_hcd *ehci) | 482 | static int enable_periodic (struct ehci_hcd *ehci) |
483 | { | 483 | { |
484 | u32 cmd; | ||
485 | int status; | 484 | int status; |
486 | 485 | ||
487 | if (ehci->periodic_sched++) | 486 | if (ehci->periodic_sched++) |
@@ -497,8 +496,8 @@ static int enable_periodic (struct ehci_hcd *ehci) | |||
497 | return status; | 496 | return status; |
498 | } | 497 | } |
499 | 498 | ||
500 | cmd = ehci_readl(ehci, &ehci->regs->command) | CMD_PSE; | 499 | ehci->command |= CMD_PSE; |
501 | ehci_writel(ehci, cmd, &ehci->regs->command); | 500 | ehci_writel(ehci, ehci->command, &ehci->regs->command); |
502 | /* posted write ... PSS happens later */ | 501 | /* posted write ... PSS happens later */ |
503 | 502 | ||
504 | /* make sure ehci_work scans these */ | 503 | /* make sure ehci_work scans these */ |
@@ -511,7 +510,6 @@ static int enable_periodic (struct ehci_hcd *ehci) | |||
511 | 510 | ||
512 | static int disable_periodic (struct ehci_hcd *ehci) | 511 | static int disable_periodic (struct ehci_hcd *ehci) |
513 | { | 512 | { |
514 | u32 cmd; | ||
515 | int status; | 513 | int status; |
516 | 514 | ||
517 | if (--ehci->periodic_sched) | 515 | if (--ehci->periodic_sched) |
@@ -537,8 +535,8 @@ static int disable_periodic (struct ehci_hcd *ehci) | |||
537 | return status; | 535 | return status; |
538 | } | 536 | } |
539 | 537 | ||
540 | cmd = ehci_readl(ehci, &ehci->regs->command) & ~CMD_PSE; | 538 | ehci->command &= ~CMD_PSE; |
541 | ehci_writel(ehci, cmd, &ehci->regs->command); | 539 | ehci_writel(ehci, ehci->command, &ehci->regs->command); |
542 | /* posted write ... */ | 540 | /* posted write ... */ |
543 | 541 | ||
544 | free_cached_lists(ehci); | 542 | free_cached_lists(ehci); |