aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/usb/host
diff options
context:
space:
mode:
authorAlan Stern <stern@rowland.harvard.edu>2012-07-11 11:22:44 -0400
committerGreg Kroah-Hartman <gregkh@linuxfoundation.org>2012-07-16 19:56:46 -0400
commit9d9387475af261949f61a5ec465e1f762d7be08a (patch)
tree7aa6688962bde78fba655b791612e60cc1b50adf /drivers/usb/host
parent8c5bf7be56f1a8aecc1f802f132d53f556a9bc45 (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.c66
-rw-r--r--drivers/usb/host/ehci-hub.c1
-rw-r--r--drivers/usb/host/ehci-q.c4
-rw-r--r--drivers/usb/host/ehci-timer.c45
-rw-r--r--drivers/usb/host/ehci.h16
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
325static 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
370static void ehci_watchdog(unsigned long param) 324static 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 */
296static 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
232static inline void
233iaa_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
240static inline void iaa_watchdog_done(struct ehci_hcd *ehci)
241{
242 del_timer(&ehci->iaa_watchdog);
243}
244
245enum ehci_timer_action { 231enum ehci_timer_action {
246 TIMER_IO_WATCHDOG, 232 TIMER_IO_WATCHDOG,
247 TIMER_ASYNC_SHRINK, 233 TIMER_ASYNC_SHRINK,