aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/usb/host/ehci-hcd.c
diff options
context:
space:
mode:
authorDavid Brownell <david-b@pacbell.net>2006-09-18 20:03:16 -0400
committerGreg Kroah-Hartman <gregkh@suse.de>2006-09-27 14:59:00 -0400
commit26f953fd884ea4879585287917f855c63c6b2666 (patch)
tree78e6bd71dc1bb4089bc8589eb995765d64d4797d /drivers/usb/host/ehci-hcd.c
parent353a4098c61272b33a02ec5802fb3859fec91a0e (diff)
USB: EHCI update VIA workaround
This revamps handling of the hardware "async advance" IRQ, and its watchdog timer. Basically it dis-entangles that important timeout from the others, simplifying the associated state and code to make it more robust. This reportedly improves behavior of EHCI on some systems with VIA chips, and AFAIK won't affect non-VIA hardware. VIA systems need this code to recover from silcon bugs whereby the "async advance" IRQ isn't issued. Signed-off-by: David Brownell <dbrownell@users.sourceforge.net> Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de>
Diffstat (limited to 'drivers/usb/host/ehci-hcd.c')
-rw-r--r--drivers/usb/host/ehci-hcd.c73
1 files changed, 50 insertions, 23 deletions
diff --git a/drivers/usb/host/ehci-hcd.c b/drivers/usb/host/ehci-hcd.c
index 4e1a8c308893..5ac918591131 100644
--- a/drivers/usb/host/ehci-hcd.c
+++ b/drivers/usb/host/ehci-hcd.c
@@ -111,7 +111,7 @@ static const char hcd_name [] = "ehci_hcd";
111#define EHCI_TUNE_MULT_TT 1 111#define EHCI_TUNE_MULT_TT 1
112#define EHCI_TUNE_FLS 2 /* (small) 256 frame schedule */ 112#define EHCI_TUNE_FLS 2 /* (small) 256 frame schedule */
113 113
114#define EHCI_IAA_JIFFIES (HZ/100) /* arbitrary; ~10 msec */ 114#define EHCI_IAA_MSECS 10 /* arbitrary */
115#define EHCI_IO_JIFFIES (HZ/10) /* io watchdog > irq_thresh */ 115#define EHCI_IO_JIFFIES (HZ/10) /* io watchdog > irq_thresh */
116#define EHCI_ASYNC_JIFFIES (HZ/20) /* async idle timeout */ 116#define EHCI_ASYNC_JIFFIES (HZ/20) /* async idle timeout */
117#define EHCI_SHRINK_JIFFIES (HZ/200) /* async qh unlink delay */ 117#define EHCI_SHRINK_JIFFIES (HZ/200) /* async qh unlink delay */
@@ -254,6 +254,7 @@ static void ehci_quiesce (struct ehci_hcd *ehci)
254 254
255/*-------------------------------------------------------------------------*/ 255/*-------------------------------------------------------------------------*/
256 256
257static void end_unlink_async (struct ehci_hcd *ehci, struct pt_regs *regs);
257static void ehci_work(struct ehci_hcd *ehci, struct pt_regs *regs); 258static void ehci_work(struct ehci_hcd *ehci, struct pt_regs *regs);
258 259
259#include "ehci-hub.c" 260#include "ehci-hub.c"
@@ -263,28 +264,39 @@ static void ehci_work(struct ehci_hcd *ehci, struct pt_regs *regs);
263 264
264/*-------------------------------------------------------------------------*/ 265/*-------------------------------------------------------------------------*/
265 266
266static void ehci_watchdog (unsigned long param) 267static void ehci_iaa_watchdog (unsigned long param)
267{ 268{
268 struct ehci_hcd *ehci = (struct ehci_hcd *) param; 269 struct ehci_hcd *ehci = (struct ehci_hcd *) param;
269 unsigned long flags; 270 unsigned long flags;
271 u32 status;
270 272
271 spin_lock_irqsave (&ehci->lock, flags); 273 spin_lock_irqsave (&ehci->lock, flags);
274 WARN_ON(!ehci->reclaim);
272 275
273 /* lost IAA irqs wedge things badly; seen with a vt8235 */ 276 /* lost IAA irqs wedge things badly; seen first with a vt8235 */
274 if (ehci->reclaim) { 277 if (ehci->reclaim) {
275 u32 status = readl (&ehci->regs->status); 278 status = readl (&ehci->regs->status);
276
277 if (status & STS_IAA) { 279 if (status & STS_IAA) {
278 ehci_vdbg (ehci, "lost IAA\n"); 280 ehci_vdbg (ehci, "lost IAA\n");
279 COUNT (ehci->stats.lost_iaa); 281 COUNT (ehci->stats.lost_iaa);
280 writel (STS_IAA, &ehci->regs->status); 282 writel (STS_IAA, &ehci->regs->status);
281 ehci->reclaim_ready = 1; 283 end_unlink_async (ehci, NULL);
282 } 284 }
283 } 285 }
284 286
285 /* stop async processing after it's idled a bit */ 287 spin_unlock_irqrestore (&ehci->lock, flags);
288}
289
290static void ehci_watchdog (unsigned long param)
291{
292 struct ehci_hcd *ehci = (struct ehci_hcd *) param;
293 unsigned long flags;
294
295 spin_lock_irqsave (&ehci->lock, flags);
296
297 /* stop async processing after it's idled a bit */
286 if (test_bit (TIMER_ASYNC_OFF, &ehci->actions)) 298 if (test_bit (TIMER_ASYNC_OFF, &ehci->actions))
287 start_unlink_async (ehci, ehci->async); 299 start_unlink_async (ehci, ehci->async);
288 300
289 /* ehci could run by timer, without IRQs ... */ 301 /* ehci could run by timer, without IRQs ... */
290 ehci_work (ehci, NULL); 302 ehci_work (ehci, NULL);
@@ -333,8 +345,6 @@ static void ehci_port_power (struct ehci_hcd *ehci, int is_on)
333static void ehci_work (struct ehci_hcd *ehci, struct pt_regs *regs) 345static void ehci_work (struct ehci_hcd *ehci, struct pt_regs *regs)
334{ 346{
335 timer_action_done (ehci, TIMER_IO_WATCHDOG); 347 timer_action_done (ehci, TIMER_IO_WATCHDOG);
336 if (ehci->reclaim_ready)
337 end_unlink_async (ehci, regs);
338 348
339 /* another CPU may drop ehci->lock during a schedule scan while 349 /* another CPU may drop ehci->lock during a schedule scan while
340 * it reports urb completions. this flag guards against bogus 350 * it reports urb completions. this flag guards against bogus
@@ -369,6 +379,7 @@ static void ehci_stop (struct usb_hcd *hcd)
369 379
370 /* no more interrupts ... */ 380 /* no more interrupts ... */
371 del_timer_sync (&ehci->watchdog); 381 del_timer_sync (&ehci->watchdog);
382 del_timer_sync (&ehci->iaa_watchdog);
372 383
373 spin_lock_irq(&ehci->lock); 384 spin_lock_irq(&ehci->lock);
374 if (HC_IS_RUNNING (hcd->state)) 385 if (HC_IS_RUNNING (hcd->state))
@@ -415,6 +426,10 @@ static int ehci_init(struct usb_hcd *hcd)
415 ehci->watchdog.function = ehci_watchdog; 426 ehci->watchdog.function = ehci_watchdog;
416 ehci->watchdog.data = (unsigned long) ehci; 427 ehci->watchdog.data = (unsigned long) ehci;
417 428
429 init_timer(&ehci->iaa_watchdog);
430 ehci->iaa_watchdog.function = ehci_iaa_watchdog;
431 ehci->iaa_watchdog.data = (unsigned long) ehci;
432
418 /* 433 /*
419 * hw default: 1K periodic list heads, one per frame. 434 * hw default: 1K periodic list heads, one per frame.
420 * periodic_size can shrink by USBCMD update if hcc_params allows. 435 * periodic_size can shrink by USBCMD update if hcc_params allows.
@@ -431,7 +446,6 @@ static int ehci_init(struct usb_hcd *hcd)
431 ehci->i_thresh = 2 + HCC_ISOC_THRES(hcc_params); 446 ehci->i_thresh = 2 + HCC_ISOC_THRES(hcc_params);
432 447
433 ehci->reclaim = NULL; 448 ehci->reclaim = NULL;
434 ehci->reclaim_ready = 0;
435 ehci->next_uframe = -1; 449 ehci->next_uframe = -1;
436 450
437 /* 451 /*
@@ -605,7 +619,7 @@ static irqreturn_t ehci_irq (struct usb_hcd *hcd, struct pt_regs *regs)
605 /* complete the unlinking of some qh [4.15.2.3] */ 619 /* complete the unlinking of some qh [4.15.2.3] */
606 if (status & STS_IAA) { 620 if (status & STS_IAA) {
607 COUNT (ehci->stats.reclaim); 621 COUNT (ehci->stats.reclaim);
608 ehci->reclaim_ready = 1; 622 end_unlink_async (ehci, regs);
609 bh = 1; 623 bh = 1;
610 } 624 }
611 625
@@ -709,10 +723,14 @@ static int ehci_urb_enqueue (
709 723
710static void unlink_async (struct ehci_hcd *ehci, struct ehci_qh *qh) 724static void unlink_async (struct ehci_hcd *ehci, struct ehci_qh *qh)
711{ 725{
712 /* if we need to use IAA and it's busy, defer */ 726 // BUG_ON(qh->qh_state != QH_STATE_LINKED);
713 if (qh->qh_state == QH_STATE_LINKED 727
714 && ehci->reclaim 728 /* failfast */
715 && HC_IS_RUNNING (ehci_to_hcd(ehci)->state)) { 729 if (!HC_IS_RUNNING (ehci_to_hcd(ehci)->state))
730 end_unlink_async (ehci, NULL);
731
732 /* defer till later if busy */
733 else if (ehci->reclaim) {
716 struct ehci_qh *last; 734 struct ehci_qh *last;
717 735
718 for (last = ehci->reclaim; 736 for (last = ehci->reclaim;
@@ -722,12 +740,8 @@ static void unlink_async (struct ehci_hcd *ehci, struct ehci_qh *qh)
722 qh->qh_state = QH_STATE_UNLINK_WAIT; 740 qh->qh_state = QH_STATE_UNLINK_WAIT;
723 last->reclaim = qh; 741 last->reclaim = qh;
724 742
725 /* bypass IAA if the hc can't care */ 743 /* start IAA cycle */
726 } else if (!HC_IS_RUNNING (ehci_to_hcd(ehci)->state) && ehci->reclaim) 744 } else
727 end_unlink_async (ehci, NULL);
728
729 /* something else might have unlinked the qh by now */
730 if (qh->qh_state == QH_STATE_LINKED)
731 start_unlink_async (ehci, qh); 745 start_unlink_async (ehci, qh);
732} 746}
733 747
@@ -749,7 +763,19 @@ static int ehci_urb_dequeue (struct usb_hcd *hcd, struct urb *urb)
749 qh = (struct ehci_qh *) urb->hcpriv; 763 qh = (struct ehci_qh *) urb->hcpriv;
750 if (!qh) 764 if (!qh)
751 break; 765 break;
752 unlink_async (ehci, qh); 766 switch (qh->qh_state) {
767 case QH_STATE_LINKED:
768 case QH_STATE_COMPLETING:
769 unlink_async (ehci, qh);
770 break;
771 case QH_STATE_UNLINK:
772 case QH_STATE_UNLINK_WAIT:
773 /* already started */
774 break;
775 case QH_STATE_IDLE:
776 WARN_ON(1);
777 break;
778 }
753 break; 779 break;
754 780
755 case PIPE_INTERRUPT: 781 case PIPE_INTERRUPT:
@@ -841,6 +867,7 @@ rescan:
841 unlink_async (ehci, qh); 867 unlink_async (ehci, qh);
842 /* FALL THROUGH */ 868 /* FALL THROUGH */
843 case QH_STATE_UNLINK: /* wait for hw to finish? */ 869 case QH_STATE_UNLINK: /* wait for hw to finish? */
870 case QH_STATE_UNLINK_WAIT:
844idle_timeout: 871idle_timeout:
845 spin_unlock_irqrestore (&ehci->lock, flags); 872 spin_unlock_irqrestore (&ehci->lock, flags);
846 schedule_timeout_uninterruptible(1); 873 schedule_timeout_uninterruptible(1);