aboutsummaryrefslogtreecommitdiffstats
path: root/drivers
diff options
context:
space:
mode:
Diffstat (limited to 'drivers')
-rw-r--r--drivers/usb/host/ehci-hcd.c2
-rw-r--r--drivers/usb/host/ehci-pci.c4
-rw-r--r--drivers/usb/host/ehci-sched.c69
-rw-r--r--drivers/usb/host/ehci-timer.c80
-rw-r--r--drivers/usb/host/ehci.h7
5 files changed, 101 insertions, 61 deletions
diff --git a/drivers/usb/host/ehci-hcd.c b/drivers/usb/host/ehci-hcd.c
index f8fed163a23a..7e00ca095cea 100644
--- a/drivers/usb/host/ehci-hcd.c
+++ b/drivers/usb/host/ehci-hcd.c
@@ -546,7 +546,7 @@ static void ehci_work (struct ehci_hcd *ehci)
546 */ 546 */
547 if (ehci->rh_state == EHCI_RH_RUNNING && 547 if (ehci->rh_state == EHCI_RH_RUNNING &&
548 (ehci->async->qh_next.ptr != NULL || 548 (ehci->async->qh_next.ptr != NULL ||
549 ehci->periodic_sched != 0)) 549 ehci->periodic_count != 0))
550 timer_action (ehci, TIMER_IO_WATCHDOG); 550 timer_action (ehci, TIMER_IO_WATCHDOG);
551} 551}
552 552
diff --git a/drivers/usb/host/ehci-pci.c b/drivers/usb/host/ehci-pci.c
index 21e5f963f331..2cb7d370c4ef 100644
--- a/drivers/usb/host/ehci-pci.c
+++ b/drivers/usb/host/ehci-pci.c
@@ -104,10 +104,6 @@ static int ehci_pci_setup(struct usb_hcd *hcd)
104 break; 104 break;
105 case PCI_VENDOR_ID_INTEL: 105 case PCI_VENDOR_ID_INTEL:
106 ehci->fs_i_thresh = 1; 106 ehci->fs_i_thresh = 1;
107 if (pdev->device == 0x27cc) {
108 ehci->broken_periodic = 1;
109 ehci_info(ehci, "using broken periodic workaround\n");
110 }
111 if (pdev->device == PCI_DEVICE_ID_INTEL_CE4100_USB) 107 if (pdev->device == PCI_DEVICE_ID_INTEL_CE4100_USB)
112 hcd->has_tt = 1; 108 hcd->has_tt = 1;
113 break; 109 break;
diff --git a/drivers/usb/host/ehci-sched.c b/drivers/usb/host/ehci-sched.c
index 3429b8a33c58..f5c15880c65a 100644
--- a/drivers/usb/host/ehci-sched.c
+++ b/drivers/usb/host/ehci-sched.c
@@ -481,67 +481,26 @@ 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 int status; 484 if (ehci->periodic_count++)
485
486 if (ehci->periodic_sched++)
487 return 0; 485 return 0;
488 486
489 /* did clearing PSE did take effect yet? 487 /* Stop waiting to turn off the periodic schedule */
490 * takes effect only at frame boundaries... 488 ehci->enabled_hrtimer_events &= ~BIT(EHCI_HRTIMER_DISABLE_PERIODIC);
491 */
492 status = handshake_on_error_set_halt(ehci, &ehci->regs->status,
493 STS_PSS, 0, 9 * 125);
494 if (status) {
495 usb_hc_died(ehci_to_hcd(ehci));
496 return status;
497 }
498
499 ehci->command |= CMD_PSE;
500 ehci_writel(ehci, ehci->command, &ehci->regs->command);
501 /* posted write ... PSS happens later */
502 489
503 /* make sure ehci_work scans these */ 490 /* Don't start the schedule until PSS is 0 */
504 ehci->next_uframe = ehci_read_frame_index(ehci) 491 ehci_poll_PSS(ehci);
505 % (ehci->periodic_size << 3);
506 if (unlikely(ehci->broken_periodic))
507 ehci->last_periodic_enable = ktime_get_real();
508 return 0; 492 return 0;
509} 493}
510 494
511static int disable_periodic (struct ehci_hcd *ehci) 495static int disable_periodic (struct ehci_hcd *ehci)
512{ 496{
513 int status; 497 if (--ehci->periodic_count)
514
515 if (--ehci->periodic_sched)
516 return 0; 498 return 0;
517 499
518 if (unlikely(ehci->broken_periodic)) { 500 ehci->next_uframe = -1; /* the periodic schedule is empty */
519 /* delay experimentally determined */
520 ktime_t safe = ktime_add_us(ehci->last_periodic_enable, 1000);
521 ktime_t now = ktime_get_real();
522 s64 delay = ktime_us_delta(safe, now);
523
524 if (unlikely(delay > 0))
525 udelay(delay);
526 }
527
528 /* did setting PSE not take effect yet?
529 * takes effect only at frame boundaries...
530 */
531 status = handshake_on_error_set_halt(ehci, &ehci->regs->status,
532 STS_PSS, STS_PSS, 9 * 125);
533 if (status) {
534 usb_hc_died(ehci_to_hcd(ehci));
535 return status;
536 }
537
538 ehci->command &= ~CMD_PSE;
539 ehci_writel(ehci, ehci->command, &ehci->regs->command);
540 /* posted write ... */
541
542 free_cached_lists(ehci);
543 501
544 ehci->next_uframe = -1; 502 /* Don't turn off the schedule until PSS is 1 */
503 ehci_poll_PSS(ehci);
545 return 0; 504 return 0;
546} 505}
547 506
@@ -650,8 +609,7 @@ static int qh_unlink_periodic(struct ehci_hcd *ehci, struct ehci_qh *qh)
650 qh->qh_state = QH_STATE_UNLINK; 609 qh->qh_state = QH_STATE_UNLINK;
651 qh->qh_next.ptr = NULL; 610 qh->qh_next.ptr = NULL;
652 611
653 /* maybe turn off periodic schedule */ 612 return 0;
654 return disable_periodic(ehci);
655} 613}
656 614
657static void intr_deschedule (struct ehci_hcd *ehci, struct ehci_qh *qh) 615static void intr_deschedule (struct ehci_hcd *ehci, struct ehci_qh *qh)
@@ -706,6 +664,9 @@ static void intr_deschedule (struct ehci_hcd *ehci, struct ehci_qh *qh)
706 ehci_err(ehci, "can't reschedule qh %p, err %d\n", 664 ehci_err(ehci, "can't reschedule qh %p, err %d\n",
707 qh, rc); 665 qh, rc);
708 } 666 }
667
668 /* maybe turn off periodic schedule */
669 disable_periodic(ehci);
709} 670}
710 671
711/*-------------------------------------------------------------------------*/ 672/*-------------------------------------------------------------------------*/
@@ -2447,7 +2408,7 @@ restart:
2447 2408
2448 /* assume completion callbacks modify the queue */ 2409 /* assume completion callbacks modify the queue */
2449 if (unlikely (modified)) { 2410 if (unlikely (modified)) {
2450 if (likely(ehci->periodic_sched > 0)) 2411 if (likely(ehci->periodic_count > 0))
2451 goto restart; 2412 goto restart;
2452 /* short-circuit this scan */ 2413 /* short-circuit this scan */
2453 now_uframe = clock; 2414 now_uframe = clock;
@@ -2476,7 +2437,7 @@ restart:
2476 unsigned now; 2437 unsigned now;
2477 2438
2478 if (ehci->rh_state < EHCI_RH_RUNNING 2439 if (ehci->rh_state < EHCI_RH_RUNNING
2479 || ehci->periodic_sched == 0) 2440 || ehci->periodic_count == 0)
2480 break; 2441 break;
2481 ehci->next_uframe = now_uframe; 2442 ehci->next_uframe = now_uframe;
2482 now = ehci_read_frame_index(ehci) & (mod - 1); 2443 now = ehci_read_frame_index(ehci) & (mod - 1);
diff --git a/drivers/usb/host/ehci-timer.c b/drivers/usb/host/ehci-timer.c
index f6279e2883a8..ecd3296157c6 100644
--- a/drivers/usb/host/ehci-timer.c
+++ b/drivers/usb/host/ehci-timer.c
@@ -16,6 +16,28 @@
16 16
17/*-------------------------------------------------------------------------*/ 17/*-------------------------------------------------------------------------*/
18 18
19/* Set a bit in the USBCMD register */
20static void ehci_set_command_bit(struct ehci_hcd *ehci, u32 bit)
21{
22 ehci->command |= bit;
23 ehci_writel(ehci, ehci->command, &ehci->regs->command);
24
25 /* unblock posted write */
26 ehci_readl(ehci, &ehci->regs->command);
27}
28
29/* Clear a bit in the USBCMD register */
30static void ehci_clear_command_bit(struct ehci_hcd *ehci, u32 bit)
31{
32 ehci->command &= ~bit;
33 ehci_writel(ehci, ehci->command, &ehci->regs->command);
34
35 /* unblock posted write */
36 ehci_readl(ehci, &ehci->regs->command);
37}
38
39/*-------------------------------------------------------------------------*/
40
19/* 41/*
20 * EHCI timer support... Now using hrtimers. 42 * EHCI timer support... Now using hrtimers.
21 * 43 *
@@ -45,6 +67,8 @@
45 * the event types indexed by enum ehci_hrtimer_event in ehci.h. 67 * the event types indexed by enum ehci_hrtimer_event in ehci.h.
46 */ 68 */
47static unsigned event_delays_ns[] = { 69static unsigned event_delays_ns[] = {
70 1 * NSEC_PER_MSEC, /* EHCI_HRTIMER_POLL_PSS */
71 10 * NSEC_PER_MSEC, /* EHCI_HRTIMER_DISABLE_PERIODIC */
48}; 72};
49 73
50/* Enable a pending hrtimer event */ 74/* Enable a pending hrtimer event */
@@ -67,12 +91,68 @@ static void ehci_enable_event(struct ehci_hcd *ehci, unsigned event,
67} 91}
68 92
69 93
94/* Poll the STS_PSS status bit; see when it agrees with CMD_PSE */
95static void ehci_poll_PSS(struct ehci_hcd *ehci)
96{
97 unsigned actual, want;
98
99 /* Don't do anything if the controller isn't running (e.g., died) */
100 if (ehci->rh_state != EHCI_RH_RUNNING)
101 return;
102
103 want = (ehci->command & CMD_PSE) ? STS_PSS : 0;
104 actual = ehci_readl(ehci, &ehci->regs->status) & STS_PSS;
105
106 if (want != actual) {
107
108 /* Poll again later, but give up after about 20 ms */
109 if (ehci->PSS_poll_count++ < 20) {
110 ehci_enable_event(ehci, EHCI_HRTIMER_POLL_PSS, true);
111 return;
112 }
113 ehci_warn(ehci, "Waited too long for the periodic schedule status, giving up\n");
114 }
115 ehci->PSS_poll_count = 0;
116
117 /* The status is up-to-date; restart or stop the schedule as needed */
118 if (want == 0) { /* Stopped */
119 free_cached_lists(ehci);
120 if (ehci->periodic_count > 0) {
121
122 /* make sure ehci_work scans these */
123 ehci->next_uframe = ehci_read_frame_index(ehci)
124 & ((ehci->periodic_size << 3) - 1);
125 ehci_set_command_bit(ehci, CMD_PSE);
126 }
127
128 } else { /* Running */
129 if (ehci->periodic_count == 0) {
130
131 /* Turn off the schedule after a while */
132 ehci_enable_event(ehci, EHCI_HRTIMER_DISABLE_PERIODIC,
133 true);
134 }
135 }
136}
137
138/* Turn off the periodic schedule after a brief delay */
139static void ehci_disable_PSE(struct ehci_hcd *ehci)
140{
141 ehci_clear_command_bit(ehci, CMD_PSE);
142
143 /* Poll to see when it actually stops */
144 ehci_enable_event(ehci, EHCI_HRTIMER_POLL_PSS, true);
145}
146
147
70/* 148/*
71 * Handler functions for the hrtimer event types. 149 * Handler functions for the hrtimer event types.
72 * Keep this array in the same order as the event types indexed by 150 * Keep this array in the same order as the event types indexed by
73 * enum ehci_hrtimer_event in ehci.h. 151 * enum ehci_hrtimer_event in ehci.h.
74 */ 152 */
75static void (*event_handlers[])(struct ehci_hcd *) = { 153static void (*event_handlers[])(struct ehci_hcd *) = {
154 ehci_poll_PSS, /* EHCI_HRTIMER_POLL_PSS */
155 ehci_disable_PSE, /* EHCI_HRTIMER_DISABLE_PERIODIC */
76}; 156};
77 157
78static enum hrtimer_restart ehci_hrtimer_func(struct hrtimer *t) 158static enum hrtimer_restart ehci_hrtimer_func(struct hrtimer *t)
diff --git a/drivers/usb/host/ehci.h b/drivers/usb/host/ehci.h
index 070be83028d5..da2e0ab23850 100644
--- a/drivers/usb/host/ehci.h
+++ b/drivers/usb/host/ehci.h
@@ -79,6 +79,8 @@ enum ehci_rh_state {
79 * ehci-timer.c) in parallel with this list. 79 * ehci-timer.c) in parallel with this list.
80 */ 80 */
81enum ehci_hrtimer_event { 81enum ehci_hrtimer_event {
82 EHCI_HRTIMER_POLL_PSS, /* Poll for periodic schedule off */
83 EHCI_HRTIMER_DISABLE_PERIODIC, /* Wait to disable periodic sched */
82 EHCI_HRTIMER_NUM_EVENTS /* Must come last */ 84 EHCI_HRTIMER_NUM_EVENTS /* Must come last */
83}; 85};
84#define EHCI_HRTIMER_NO_EVENT 99 86#define EHCI_HRTIMER_NO_EVENT 99
@@ -90,6 +92,8 @@ struct ehci_hcd { /* one per controller */
90 ktime_t hr_timeouts[EHCI_HRTIMER_NUM_EVENTS]; 92 ktime_t hr_timeouts[EHCI_HRTIMER_NUM_EVENTS];
91 struct hrtimer hrtimer; 93 struct hrtimer hrtimer;
92 94
95 int PSS_poll_count;
96
93 /* glue to PCI and HCD framework */ 97 /* glue to PCI and HCD framework */
94 struct ehci_caps __iomem *caps; 98 struct ehci_caps __iomem *caps;
95 struct ehci_regs __iomem *regs; 99 struct ehci_regs __iomem *regs;
@@ -116,7 +120,7 @@ struct ehci_hcd { /* one per controller */
116 120
117 union ehci_shadow *pshadow; /* mirror hw periodic table */ 121 union ehci_shadow *pshadow; /* mirror hw periodic table */
118 int next_uframe; /* scan periodic, start here */ 122 int next_uframe; /* scan periodic, start here */
119 unsigned periodic_sched; /* periodic activity count */ 123 unsigned periodic_count; /* periodic activity count */
120 unsigned uframe_periodic_max; /* max periodic time per uframe */ 124 unsigned uframe_periodic_max; /* max periodic time per uframe */
121 125
122 126
@@ -165,7 +169,6 @@ struct ehci_hcd { /* one per controller */
165 unsigned big_endian_capbase:1; 169 unsigned big_endian_capbase:1;
166 unsigned has_amcc_usb23:1; 170 unsigned has_amcc_usb23:1;
167 unsigned need_io_watchdog:1; 171 unsigned need_io_watchdog:1;
168 unsigned broken_periodic:1;
169 unsigned amd_pll_fix:1; 172 unsigned amd_pll_fix:1;
170 unsigned fs_i_thresh:1; /* Intel iso scheduling */ 173 unsigned fs_i_thresh:1; /* Intel iso scheduling */
171 unsigned use_dummy_qh:1; /* AMD Frame List table quirk*/ 174 unsigned use_dummy_qh:1; /* AMD Frame List table quirk*/