aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/usb/host/ehci-timer.c
diff options
context:
space:
mode:
Diffstat (limited to 'drivers/usb/host/ehci-timer.c')
-rw-r--r--drivers/usb/host/ehci-timer.c80
1 files changed, 80 insertions, 0 deletions
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)