diff options
author | Alan Stern <stern@rowland.harvard.edu> | 2012-07-11 11:22:44 -0400 |
---|---|---|
committer | Greg Kroah-Hartman <gregkh@linuxfoundation.org> | 2012-07-16 19:56:46 -0400 |
commit | 9d9387475af261949f61a5ec465e1f762d7be08a (patch) | |
tree | 7aa6688962bde78fba655b791612e60cc1b50adf /drivers/usb/host | |
parent | 8c5bf7be56f1a8aecc1f802f132d53f556a9bc45 (diff) |
USB: EHCI: use hrtimer for the IAA watchdog
This patch (as1581) replaces the iaa_watchdog kernel timer used by
ehci-hcd with an hrtimer event, in keeping with the general conversion
to high-res timers.
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-hcd.c | 66 | ||||
-rw-r--r-- | drivers/usb/host/ehci-hub.c | 1 | ||||
-rw-r--r-- | drivers/usb/host/ehci-q.c | 4 | ||||
-rw-r--r-- | drivers/usb/host/ehci-timer.c | 45 | ||||
-rw-r--r-- | drivers/usb/host/ehci.h | 16 |
5 files changed, 61 insertions, 71 deletions
diff --git a/drivers/usb/host/ehci-hcd.c b/drivers/usb/host/ehci-hcd.c index fb1966cf5649..f74ba277c22d 100644 --- a/drivers/usb/host/ehci-hcd.c +++ b/drivers/usb/host/ehci-hcd.c | |||
@@ -93,7 +93,6 @@ static const char hcd_name [] = "ehci_hcd"; | |||
93 | */ | 93 | */ |
94 | #define EHCI_TUNE_FLS 1 /* (medium) 512-frame schedule */ | 94 | #define EHCI_TUNE_FLS 1 /* (medium) 512-frame schedule */ |
95 | 95 | ||
96 | #define EHCI_IAA_MSECS 10 /* arbitrary */ | ||
97 | #define EHCI_IO_JIFFIES (HZ/10) /* io watchdog > irq_thresh */ | 96 | #define EHCI_IO_JIFFIES (HZ/10) /* io watchdog > irq_thresh */ |
98 | #define EHCI_SHRINK_JIFFIES (DIV_ROUND_UP(HZ, 200) + 1) | 97 | #define EHCI_SHRINK_JIFFIES (DIV_ROUND_UP(HZ, 200) + 1) |
99 | /* 5-ms async qh unlink delay */ | 98 | /* 5-ms async qh unlink delay */ |
@@ -322,51 +321,6 @@ static void end_unlink_intr(struct ehci_hcd *ehci, struct ehci_qh *qh); | |||
322 | 321 | ||
323 | /*-------------------------------------------------------------------------*/ | 322 | /*-------------------------------------------------------------------------*/ |
324 | 323 | ||
325 | static void ehci_iaa_watchdog(unsigned long param) | ||
326 | { | ||
327 | struct ehci_hcd *ehci = (struct ehci_hcd *) param; | ||
328 | unsigned long flags; | ||
329 | |||
330 | spin_lock_irqsave (&ehci->lock, flags); | ||
331 | |||
332 | /* Lost IAA irqs wedge things badly; seen first with a vt8235. | ||
333 | * So we need this watchdog, but must protect it against both | ||
334 | * (a) SMP races against real IAA firing and retriggering, and | ||
335 | * (b) clean HC shutdown, when IAA watchdog was pending. | ||
336 | */ | ||
337 | if (ehci->async_unlink | ||
338 | && !timer_pending(&ehci->iaa_watchdog) | ||
339 | && ehci->rh_state == EHCI_RH_RUNNING) { | ||
340 | u32 cmd, status; | ||
341 | |||
342 | /* If we get here, IAA is *REALLY* late. It's barely | ||
343 | * conceivable that the system is so busy that CMD_IAAD | ||
344 | * is still legitimately set, so let's be sure it's | ||
345 | * clear before we read STS_IAA. (The HC should clear | ||
346 | * CMD_IAAD when it sets STS_IAA.) | ||
347 | */ | ||
348 | cmd = ehci_readl(ehci, &ehci->regs->command); | ||
349 | |||
350 | /* If IAA is set here it either legitimately triggered | ||
351 | * before we cleared IAAD above (but _way_ late, so we'll | ||
352 | * still count it as lost) ... or a silicon erratum: | ||
353 | * - VIA seems to set IAA without triggering the IRQ; | ||
354 | * - IAAD potentially cleared without setting IAA. | ||
355 | */ | ||
356 | status = ehci_readl(ehci, &ehci->regs->status); | ||
357 | if ((status & STS_IAA) || !(cmd & CMD_IAAD)) { | ||
358 | COUNT (ehci->stats.lost_iaa); | ||
359 | ehci_writel(ehci, STS_IAA, &ehci->regs->status); | ||
360 | } | ||
361 | |||
362 | ehci_vdbg(ehci, "IAA watchdog: status %x cmd %x\n", | ||
363 | status, cmd); | ||
364 | end_unlink_async(ehci); | ||
365 | } | ||
366 | |||
367 | spin_unlock_irqrestore(&ehci->lock, flags); | ||
368 | } | ||
369 | |||
370 | static void ehci_watchdog(unsigned long param) | 324 | static void ehci_watchdog(unsigned long param) |
371 | { | 325 | { |
372 | struct ehci_hcd *ehci = (struct ehci_hcd *) param; | 326 | struct ehci_hcd *ehci = (struct ehci_hcd *) param; |
@@ -418,7 +372,6 @@ static void ehci_shutdown(struct usb_hcd *hcd) | |||
418 | struct ehci_hcd *ehci = hcd_to_ehci(hcd); | 372 | struct ehci_hcd *ehci = hcd_to_ehci(hcd); |
419 | 373 | ||
420 | del_timer_sync(&ehci->watchdog); | 374 | del_timer_sync(&ehci->watchdog); |
421 | del_timer_sync(&ehci->iaa_watchdog); | ||
422 | 375 | ||
423 | spin_lock_irq(&ehci->lock); | 376 | spin_lock_irq(&ehci->lock); |
424 | ehci->rh_state = EHCI_RH_STOPPING; | 377 | ehci->rh_state = EHCI_RH_STOPPING; |
@@ -491,7 +444,6 @@ static void ehci_stop (struct usb_hcd *hcd) | |||
491 | 444 | ||
492 | /* no more interrupts ... */ | 445 | /* no more interrupts ... */ |
493 | del_timer_sync (&ehci->watchdog); | 446 | del_timer_sync (&ehci->watchdog); |
494 | del_timer_sync(&ehci->iaa_watchdog); | ||
495 | 447 | ||
496 | spin_lock_irq(&ehci->lock); | 448 | spin_lock_irq(&ehci->lock); |
497 | ehci->enabled_hrtimer_events = 0; | 449 | ehci->enabled_hrtimer_events = 0; |
@@ -547,10 +499,6 @@ static int ehci_init(struct usb_hcd *hcd) | |||
547 | ehci->watchdog.function = ehci_watchdog; | 499 | ehci->watchdog.function = ehci_watchdog; |
548 | ehci->watchdog.data = (unsigned long) ehci; | 500 | ehci->watchdog.data = (unsigned long) ehci; |
549 | 501 | ||
550 | init_timer(&ehci->iaa_watchdog); | ||
551 | ehci->iaa_watchdog.function = ehci_iaa_watchdog; | ||
552 | ehci->iaa_watchdog.data = (unsigned long) ehci; | ||
553 | |||
554 | hrtimer_init(&ehci->hrtimer, CLOCK_MONOTONIC, HRTIMER_MODE_ABS); | 502 | hrtimer_init(&ehci->hrtimer, CLOCK_MONOTONIC, HRTIMER_MODE_ABS); |
555 | ehci->hrtimer.function = ehci_hrtimer_func; | 503 | ehci->hrtimer.function = ehci_hrtimer_func; |
556 | ehci->next_hrtimer_event = EHCI_HRTIMER_NO_EVENT; | 504 | ehci->next_hrtimer_event = EHCI_HRTIMER_NO_EVENT; |
@@ -830,6 +778,20 @@ static irqreturn_t ehci_irq (struct usb_hcd *hcd) | |||
830 | 778 | ||
831 | /* complete the unlinking of some qh [4.15.2.3] */ | 779 | /* complete the unlinking of some qh [4.15.2.3] */ |
832 | if (status & STS_IAA) { | 780 | if (status & STS_IAA) { |
781 | |||
782 | /* Turn off the IAA watchdog */ | ||
783 | ehci->enabled_hrtimer_events &= ~BIT(EHCI_HRTIMER_IAA_WATCHDOG); | ||
784 | |||
785 | /* | ||
786 | * Mild optimization: Allow another IAAD to reset the | ||
787 | * hrtimer, if one occurs before the next expiration. | ||
788 | * In theory we could always cancel the hrtimer, but | ||
789 | * tests show that about half the time it will be reset | ||
790 | * for some other event anyway. | ||
791 | */ | ||
792 | if (ehci->next_hrtimer_event == EHCI_HRTIMER_IAA_WATCHDOG) | ||
793 | ++ehci->next_hrtimer_event; | ||
794 | |||
833 | /* guard against (alleged) silicon errata */ | 795 | /* guard against (alleged) silicon errata */ |
834 | if (cmd & CMD_IAAD) | 796 | if (cmd & CMD_IAAD) |
835 | ehci_dbg(ehci, "IAA with IAAD still set?\n"); | 797 | ehci_dbg(ehci, "IAA with IAAD still set?\n"); |
diff --git a/drivers/usb/host/ehci-hub.c b/drivers/usb/host/ehci-hub.c index 6ad806bbe468..3097872b1e74 100644 --- a/drivers/usb/host/ehci-hub.c +++ b/drivers/usb/host/ehci-hub.c | |||
@@ -209,7 +209,6 @@ static int ehci_bus_suspend (struct usb_hcd *hcd) | |||
209 | if (time_before (jiffies, ehci->next_statechange)) | 209 | if (time_before (jiffies, ehci->next_statechange)) |
210 | msleep(5); | 210 | msleep(5); |
211 | del_timer_sync(&ehci->watchdog); | 211 | del_timer_sync(&ehci->watchdog); |
212 | del_timer_sync(&ehci->iaa_watchdog); | ||
213 | 212 | ||
214 | spin_lock_irq (&ehci->lock); | 213 | spin_lock_irq (&ehci->lock); |
215 | 214 | ||
diff --git a/drivers/usb/host/ehci-q.c b/drivers/usb/host/ehci-q.c index d68764ef4476..7b35933d91a6 100644 --- a/drivers/usb/host/ehci-q.c +++ b/drivers/usb/host/ehci-q.c | |||
@@ -1173,8 +1173,6 @@ static void end_unlink_async (struct ehci_hcd *ehci) | |||
1173 | struct ehci_qh *qh = ehci->async_unlink; | 1173 | struct ehci_qh *qh = ehci->async_unlink; |
1174 | struct ehci_qh *next; | 1174 | struct ehci_qh *next; |
1175 | 1175 | ||
1176 | iaa_watchdog_done(ehci); | ||
1177 | |||
1178 | // qh->hw_next = cpu_to_hc32(qh->qh_dma); | 1176 | // qh->hw_next = cpu_to_hc32(qh->qh_dma); |
1179 | qh->qh_state = QH_STATE_IDLE; | 1177 | qh->qh_state = QH_STATE_IDLE; |
1180 | qh->qh_next.qh = NULL; | 1178 | qh->qh_next.qh = NULL; |
@@ -1243,7 +1241,7 @@ static void start_unlink_async (struct ehci_hcd *ehci, struct ehci_qh *qh) | |||
1243 | 1241 | ||
1244 | ehci_writel(ehci, ehci->command | CMD_IAAD, &ehci->regs->command); | 1242 | ehci_writel(ehci, ehci->command | CMD_IAAD, &ehci->regs->command); |
1245 | (void)ehci_readl(ehci, &ehci->regs->command); | 1243 | (void)ehci_readl(ehci, &ehci->regs->command); |
1246 | iaa_watchdog_start(ehci); | 1244 | ehci_enable_event(ehci, EHCI_HRTIMER_IAA_WATCHDOG, true); |
1247 | } | 1245 | } |
1248 | 1246 | ||
1249 | /*-------------------------------------------------------------------------*/ | 1247 | /*-------------------------------------------------------------------------*/ |
diff --git a/drivers/usb/host/ehci-timer.c b/drivers/usb/host/ehci-timer.c index 8feb60ff4228..aab042064226 100644 --- a/drivers/usb/host/ehci-timer.c +++ b/drivers/usb/host/ehci-timer.c | |||
@@ -72,6 +72,7 @@ static unsigned event_delays_ns[] = { | |||
72 | 1 * NSEC_PER_MSEC, /* EHCI_HRTIMER_POLL_DEAD */ | 72 | 1 * NSEC_PER_MSEC, /* EHCI_HRTIMER_POLL_DEAD */ |
73 | 1125 * NSEC_PER_USEC, /* EHCI_HRTIMER_UNLINK_INTR */ | 73 | 1125 * NSEC_PER_USEC, /* EHCI_HRTIMER_UNLINK_INTR */ |
74 | 2 * NSEC_PER_MSEC, /* EHCI_HRTIMER_FREE_ITDS */ | 74 | 2 * NSEC_PER_MSEC, /* EHCI_HRTIMER_FREE_ITDS */ |
75 | 10 * NSEC_PER_MSEC, /* EHCI_HRTIMER_IAA_WATCHDOG */ | ||
75 | 10 * NSEC_PER_MSEC, /* EHCI_HRTIMER_DISABLE_PERIODIC */ | 76 | 10 * NSEC_PER_MSEC, /* EHCI_HRTIMER_DISABLE_PERIODIC */ |
76 | 15 * NSEC_PER_MSEC, /* EHCI_HRTIMER_DISABLE_ASYNC */ | 77 | 15 * NSEC_PER_MSEC, /* EHCI_HRTIMER_DISABLE_ASYNC */ |
77 | }; | 78 | }; |
@@ -291,6 +292,49 @@ static void end_free_itds(struct ehci_hcd *ehci) | |||
291 | } | 292 | } |
292 | 293 | ||
293 | 294 | ||
295 | /* Handle lost (or very late) IAA interrupts */ | ||
296 | static void ehci_iaa_watchdog(struct ehci_hcd *ehci) | ||
297 | { | ||
298 | if (ehci->rh_state != EHCI_RH_RUNNING) | ||
299 | return; | ||
300 | |||
301 | /* | ||
302 | * Lost IAA irqs wedge things badly; seen first with a vt8235. | ||
303 | * So we need this watchdog, but must protect it against both | ||
304 | * (a) SMP races against real IAA firing and retriggering, and | ||
305 | * (b) clean HC shutdown, when IAA watchdog was pending. | ||
306 | */ | ||
307 | if (ehci->async_unlink) { | ||
308 | u32 cmd, status; | ||
309 | |||
310 | /* If we get here, IAA is *REALLY* late. It's barely | ||
311 | * conceivable that the system is so busy that CMD_IAAD | ||
312 | * is still legitimately set, so let's be sure it's | ||
313 | * clear before we read STS_IAA. (The HC should clear | ||
314 | * CMD_IAAD when it sets STS_IAA.) | ||
315 | */ | ||
316 | cmd = ehci_readl(ehci, &ehci->regs->command); | ||
317 | |||
318 | /* | ||
319 | * If IAA is set here it either legitimately triggered | ||
320 | * after the watchdog timer expired (_way_ late, so we'll | ||
321 | * still count it as lost) ... or a silicon erratum: | ||
322 | * - VIA seems to set IAA without triggering the IRQ; | ||
323 | * - IAAD potentially cleared without setting IAA. | ||
324 | */ | ||
325 | status = ehci_readl(ehci, &ehci->regs->status); | ||
326 | if ((status & STS_IAA) || !(cmd & CMD_IAAD)) { | ||
327 | COUNT(ehci->stats.lost_iaa); | ||
328 | ehci_writel(ehci, STS_IAA, &ehci->regs->status); | ||
329 | } | ||
330 | |||
331 | ehci_vdbg(ehci, "IAA watchdog: status %x cmd %x\n", | ||
332 | status, cmd); | ||
333 | end_unlink_async(ehci); | ||
334 | } | ||
335 | } | ||
336 | |||
337 | |||
294 | /* | 338 | /* |
295 | * Handler functions for the hrtimer event types. | 339 | * Handler functions for the hrtimer event types. |
296 | * Keep this array in the same order as the event types indexed by | 340 | * Keep this array in the same order as the event types indexed by |
@@ -302,6 +346,7 @@ static void (*event_handlers[])(struct ehci_hcd *) = { | |||
302 | ehci_handle_controller_death, /* EHCI_HRTIMER_POLL_DEAD */ | 346 | ehci_handle_controller_death, /* EHCI_HRTIMER_POLL_DEAD */ |
303 | ehci_handle_intr_unlinks, /* EHCI_HRTIMER_UNLINK_INTR */ | 347 | ehci_handle_intr_unlinks, /* EHCI_HRTIMER_UNLINK_INTR */ |
304 | end_free_itds, /* EHCI_HRTIMER_FREE_ITDS */ | 348 | end_free_itds, /* EHCI_HRTIMER_FREE_ITDS */ |
349 | ehci_iaa_watchdog, /* EHCI_HRTIMER_IAA_WATCHDOG */ | ||
305 | ehci_disable_PSE, /* EHCI_HRTIMER_DISABLE_PERIODIC */ | 350 | ehci_disable_PSE, /* EHCI_HRTIMER_DISABLE_PERIODIC */ |
306 | ehci_disable_ASE, /* EHCI_HRTIMER_DISABLE_ASYNC */ | 351 | ehci_disable_ASE, /* EHCI_HRTIMER_DISABLE_ASYNC */ |
307 | }; | 352 | }; |
diff --git a/drivers/usb/host/ehci.h b/drivers/usb/host/ehci.h index 755e30b0000b..d9414aae610f 100644 --- a/drivers/usb/host/ehci.h +++ b/drivers/usb/host/ehci.h | |||
@@ -84,6 +84,7 @@ enum ehci_hrtimer_event { | |||
84 | EHCI_HRTIMER_POLL_DEAD, /* Wait for dead controller to stop */ | 84 | EHCI_HRTIMER_POLL_DEAD, /* Wait for dead controller to stop */ |
85 | EHCI_HRTIMER_UNLINK_INTR, /* Wait for interrupt QH unlink */ | 85 | EHCI_HRTIMER_UNLINK_INTR, /* Wait for interrupt QH unlink */ |
86 | EHCI_HRTIMER_FREE_ITDS, /* Wait for unused iTDs and siTDs */ | 86 | EHCI_HRTIMER_FREE_ITDS, /* Wait for unused iTDs and siTDs */ |
87 | EHCI_HRTIMER_IAA_WATCHDOG, /* Handle lost IAA interrupts */ | ||
87 | EHCI_HRTIMER_DISABLE_PERIODIC, /* Wait to disable periodic sched */ | 88 | EHCI_HRTIMER_DISABLE_PERIODIC, /* Wait to disable periodic sched */ |
88 | EHCI_HRTIMER_DISABLE_ASYNC, /* Wait to disable async sched */ | 89 | EHCI_HRTIMER_DISABLE_ASYNC, /* Wait to disable async sched */ |
89 | EHCI_HRTIMER_NUM_EVENTS /* Must come last */ | 90 | EHCI_HRTIMER_NUM_EVENTS /* Must come last */ |
@@ -168,7 +169,6 @@ struct ehci_hcd { /* one per controller */ | |||
168 | struct dma_pool *itd_pool; /* itd per iso urb */ | 169 | struct dma_pool *itd_pool; /* itd per iso urb */ |
169 | struct dma_pool *sitd_pool; /* sitd per split iso urb */ | 170 | struct dma_pool *sitd_pool; /* sitd per split iso urb */ |
170 | 171 | ||
171 | struct timer_list iaa_watchdog; | ||
172 | struct timer_list watchdog; | 172 | struct timer_list watchdog; |
173 | unsigned long actions; | 173 | unsigned long actions; |
174 | unsigned periodic_stamp; | 174 | unsigned periodic_stamp; |
@@ -228,20 +228,6 @@ static inline struct usb_hcd *ehci_to_hcd (struct ehci_hcd *ehci) | |||
228 | return container_of ((void *) ehci, struct usb_hcd, hcd_priv); | 228 | return container_of ((void *) ehci, struct usb_hcd, hcd_priv); |
229 | } | 229 | } |
230 | 230 | ||
231 | |||
232 | static inline void | ||
233 | iaa_watchdog_start(struct ehci_hcd *ehci) | ||
234 | { | ||
235 | WARN_ON(timer_pending(&ehci->iaa_watchdog)); | ||
236 | mod_timer(&ehci->iaa_watchdog, | ||
237 | jiffies + msecs_to_jiffies(EHCI_IAA_MSECS)); | ||
238 | } | ||
239 | |||
240 | static inline void iaa_watchdog_done(struct ehci_hcd *ehci) | ||
241 | { | ||
242 | del_timer(&ehci->iaa_watchdog); | ||
243 | } | ||
244 | |||
245 | enum ehci_timer_action { | 231 | enum ehci_timer_action { |
246 | TIMER_IO_WATCHDOG, | 232 | TIMER_IO_WATCHDOG, |
247 | TIMER_ASYNC_SHRINK, | 233 | TIMER_ASYNC_SHRINK, |