aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/usb/host
diff options
context:
space:
mode:
authorAlan Stern <stern@rowland.harvard.edu>2012-04-23 13:54:36 -0400
committerGreg Kroah-Hartman <gregkh@linuxfoundation.org>2012-04-23 15:05:44 -0400
commit3d9545cc375d117554a9b35dfddadf9189c62775 (patch)
treeb01707d2e0901665f20bae0f0c5a0930af69651a /drivers/usb/host
parent09091a4d5f2dd378dcf71de50b48cdacc58a8ac0 (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.c6
-rw-r--r--drivers/usb/host/ehci-hcd.c16
-rw-r--r--drivers/usb/host/ehci-hub.c2
-rw-r--r--drivers/usb/host/ehci-q.c16
-rw-r--r--drivers/usb/host/ehci-sched.c10
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
1205static void start_unlink_async (struct ehci_hcd *ehci, struct ehci_qh *qh) 1203static 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
482static int enable_periodic (struct ehci_hcd *ehci) 482static 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
512static int disable_periodic (struct ehci_hcd *ehci) 511static 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);