diff options
Diffstat (limited to 'drivers/usb/host/ohci-hcd.c')
-rw-r--r-- | drivers/usb/host/ohci-hcd.c | 166 |
1 files changed, 139 insertions, 27 deletions
diff --git a/drivers/usb/host/ohci-hcd.c b/drivers/usb/host/ohci-hcd.c index 6edf4097d2d2..d673cb9c36b1 100644 --- a/drivers/usb/host/ohci-hcd.c +++ b/drivers/usb/host/ohci-hcd.c | |||
@@ -81,7 +81,6 @@ static void ohci_dump (struct ohci_hcd *ohci, int verbose); | |||
81 | static int ohci_init (struct ohci_hcd *ohci); | 81 | static int ohci_init (struct ohci_hcd *ohci); |
82 | static void ohci_stop (struct usb_hcd *hcd); | 82 | static void ohci_stop (struct usb_hcd *hcd); |
83 | static int ohci_restart (struct ohci_hcd *ohci); | 83 | static int ohci_restart (struct ohci_hcd *ohci); |
84 | static void ohci_quirk_nec_worker (struct work_struct *work); | ||
85 | 84 | ||
86 | #include "ohci-hub.c" | 85 | #include "ohci-hub.c" |
87 | #include "ohci-dbg.c" | 86 | #include "ohci-dbg.c" |
@@ -314,6 +313,8 @@ rescan: | |||
314 | if (!HC_IS_RUNNING (hcd->state)) { | 313 | if (!HC_IS_RUNNING (hcd->state)) { |
315 | sanitize: | 314 | sanitize: |
316 | ed->state = ED_IDLE; | 315 | ed->state = ED_IDLE; |
316 | if (quirk_zfmicro(ohci) && ed->type == PIPE_INTERRUPT) | ||
317 | ohci->eds_scheduled--; | ||
317 | finish_unlinks (ohci, 0); | 318 | finish_unlinks (ohci, 0); |
318 | } | 319 | } |
319 | 320 | ||
@@ -321,7 +322,12 @@ sanitize: | |||
321 | case ED_UNLINK: /* wait for hw to finish? */ | 322 | case ED_UNLINK: /* wait for hw to finish? */ |
322 | /* major IRQ delivery trouble loses INTR_SF too... */ | 323 | /* major IRQ delivery trouble loses INTR_SF too... */ |
323 | if (limit-- == 0) { | 324 | if (limit-- == 0) { |
324 | ohci_warn (ohci, "IRQ INTR_SF lossage\n"); | 325 | ohci_warn(ohci, "ED unlink timeout\n"); |
326 | if (quirk_zfmicro(ohci)) { | ||
327 | ohci_warn(ohci, "Attempting ZF TD recovery\n"); | ||
328 | ohci->ed_to_check = ed; | ||
329 | ohci->zf_delay = 2; | ||
330 | } | ||
325 | goto sanitize; | 331 | goto sanitize; |
326 | } | 332 | } |
327 | spin_unlock_irqrestore (&ohci->lock, flags); | 333 | spin_unlock_irqrestore (&ohci->lock, flags); |
@@ -379,6 +385,93 @@ ohci_shutdown (struct usb_hcd *hcd) | |||
379 | (void) ohci_readl (ohci, &ohci->regs->control); | 385 | (void) ohci_readl (ohci, &ohci->regs->control); |
380 | } | 386 | } |
381 | 387 | ||
388 | static int check_ed(struct ohci_hcd *ohci, struct ed *ed) | ||
389 | { | ||
390 | return (hc32_to_cpu(ohci, ed->hwINFO) & ED_IN) != 0 | ||
391 | && (hc32_to_cpu(ohci, ed->hwHeadP) & TD_MASK) | ||
392 | == (hc32_to_cpu(ohci, ed->hwTailP) & TD_MASK) | ||
393 | && !list_empty(&ed->td_list); | ||
394 | } | ||
395 | |||
396 | /* ZF Micro watchdog timer callback. The ZF Micro chipset sometimes completes | ||
397 | * an interrupt TD but neglects to add it to the donelist. On systems with | ||
398 | * this chipset, we need to periodically check the state of the queues to look | ||
399 | * for such "lost" TDs. | ||
400 | */ | ||
401 | static void unlink_watchdog_func(unsigned long _ohci) | ||
402 | { | ||
403 | long flags; | ||
404 | unsigned max; | ||
405 | unsigned seen_count = 0; | ||
406 | unsigned i; | ||
407 | struct ed **seen = NULL; | ||
408 | struct ohci_hcd *ohci = (struct ohci_hcd *) _ohci; | ||
409 | |||
410 | spin_lock_irqsave(&ohci->lock, flags); | ||
411 | max = ohci->eds_scheduled; | ||
412 | if (!max) | ||
413 | goto done; | ||
414 | |||
415 | if (ohci->ed_to_check) | ||
416 | goto out; | ||
417 | |||
418 | seen = kcalloc(max, sizeof *seen, GFP_ATOMIC); | ||
419 | if (!seen) | ||
420 | goto out; | ||
421 | |||
422 | for (i = 0; i < NUM_INTS; i++) { | ||
423 | struct ed *ed = ohci->periodic[i]; | ||
424 | |||
425 | while (ed) { | ||
426 | unsigned temp; | ||
427 | |||
428 | /* scan this branch of the periodic schedule tree */ | ||
429 | for (temp = 0; temp < seen_count; temp++) { | ||
430 | if (seen[temp] == ed) { | ||
431 | /* we've checked it and what's after */ | ||
432 | ed = NULL; | ||
433 | break; | ||
434 | } | ||
435 | } | ||
436 | if (!ed) | ||
437 | break; | ||
438 | seen[seen_count++] = ed; | ||
439 | if (!check_ed(ohci, ed)) { | ||
440 | ed = ed->ed_next; | ||
441 | continue; | ||
442 | } | ||
443 | |||
444 | /* HC's TD list is empty, but HCD sees at least one | ||
445 | * TD that's not been sent through the donelist. | ||
446 | */ | ||
447 | ohci->ed_to_check = ed; | ||
448 | ohci->zf_delay = 2; | ||
449 | |||
450 | /* The HC may wait until the next frame to report the | ||
451 | * TD as done through the donelist and INTR_WDH. (We | ||
452 | * just *assume* it's not a multi-TD interrupt URB; | ||
453 | * those could defer the IRQ more than one frame, using | ||
454 | * DI...) Check again after the next INTR_SF. | ||
455 | */ | ||
456 | ohci_writel(ohci, OHCI_INTR_SF, | ||
457 | &ohci->regs->intrstatus); | ||
458 | ohci_writel(ohci, OHCI_INTR_SF, | ||
459 | &ohci->regs->intrenable); | ||
460 | |||
461 | /* flush those writes */ | ||
462 | (void) ohci_readl(ohci, &ohci->regs->control); | ||
463 | |||
464 | goto out; | ||
465 | } | ||
466 | } | ||
467 | out: | ||
468 | kfree(seen); | ||
469 | if (ohci->eds_scheduled) | ||
470 | mod_timer(&ohci->unlink_watchdog, round_jiffies_relative(HZ)); | ||
471 | done: | ||
472 | spin_unlock_irqrestore(&ohci->lock, flags); | ||
473 | } | ||
474 | |||
382 | /*-------------------------------------------------------------------------* | 475 | /*-------------------------------------------------------------------------* |
383 | * HC functions | 476 | * HC functions |
384 | *-------------------------------------------------------------------------*/ | 477 | *-------------------------------------------------------------------------*/ |
@@ -616,6 +709,15 @@ retry: | |||
616 | mdelay ((temp >> 23) & 0x1fe); | 709 | mdelay ((temp >> 23) & 0x1fe); |
617 | hcd->state = HC_STATE_RUNNING; | 710 | hcd->state = HC_STATE_RUNNING; |
618 | 711 | ||
712 | if (quirk_zfmicro(ohci)) { | ||
713 | /* Create timer to watch for bad queue state on ZF Micro */ | ||
714 | setup_timer(&ohci->unlink_watchdog, unlink_watchdog_func, | ||
715 | (unsigned long) ohci); | ||
716 | |||
717 | ohci->eds_scheduled = 0; | ||
718 | ohci->ed_to_check = NULL; | ||
719 | } | ||
720 | |||
619 | ohci_dump (ohci, 1); | 721 | ohci_dump (ohci, 1); |
620 | 722 | ||
621 | return 0; | 723 | return 0; |
@@ -629,10 +731,11 @@ static irqreturn_t ohci_irq (struct usb_hcd *hcd) | |||
629 | { | 731 | { |
630 | struct ohci_hcd *ohci = hcd_to_ohci (hcd); | 732 | struct ohci_hcd *ohci = hcd_to_ohci (hcd); |
631 | struct ohci_regs __iomem *regs = ohci->regs; | 733 | struct ohci_regs __iomem *regs = ohci->regs; |
632 | int ints; | 734 | int ints; |
633 | 735 | ||
634 | /* we can eliminate a (slow) ohci_readl() | 736 | /* we can eliminate a (slow) ohci_readl() |
635 | if _only_ WDH caused this irq */ | 737 | * if _only_ WDH caused this irq |
738 | */ | ||
636 | if ((ohci->hcca->done_head != 0) | 739 | if ((ohci->hcca->done_head != 0) |
637 | && ! (hc32_to_cpup (ohci, &ohci->hcca->done_head) | 740 | && ! (hc32_to_cpup (ohci, &ohci->hcca->done_head) |
638 | & 0x01)) { | 741 | & 0x01)) { |
@@ -651,7 +754,7 @@ static irqreturn_t ohci_irq (struct usb_hcd *hcd) | |||
651 | 754 | ||
652 | if (ints & OHCI_INTR_UE) { | 755 | if (ints & OHCI_INTR_UE) { |
653 | // e.g. due to PCI Master/Target Abort | 756 | // e.g. due to PCI Master/Target Abort |
654 | if (ohci->flags & OHCI_QUIRK_NEC) { | 757 | if (quirk_nec(ohci)) { |
655 | /* Workaround for a silicon bug in some NEC chips used | 758 | /* Workaround for a silicon bug in some NEC chips used |
656 | * in Apple's PowerBooks. Adapted from Darwin code. | 759 | * in Apple's PowerBooks. Adapted from Darwin code. |
657 | */ | 760 | */ |
@@ -713,6 +816,31 @@ static irqreturn_t ohci_irq (struct usb_hcd *hcd) | |||
713 | ohci_writel (ohci, OHCI_INTR_WDH, ®s->intrenable); | 816 | ohci_writel (ohci, OHCI_INTR_WDH, ®s->intrenable); |
714 | } | 817 | } |
715 | 818 | ||
819 | if (quirk_zfmicro(ohci) && (ints & OHCI_INTR_SF)) { | ||
820 | spin_lock(&ohci->lock); | ||
821 | if (ohci->ed_to_check) { | ||
822 | struct ed *ed = ohci->ed_to_check; | ||
823 | |||
824 | if (check_ed(ohci, ed)) { | ||
825 | /* HC thinks the TD list is empty; HCD knows | ||
826 | * at least one TD is outstanding | ||
827 | */ | ||
828 | if (--ohci->zf_delay == 0) { | ||
829 | struct td *td = list_entry( | ||
830 | ed->td_list.next, | ||
831 | struct td, td_list); | ||
832 | ohci_warn(ohci, | ||
833 | "Reclaiming orphan TD %p\n", | ||
834 | td); | ||
835 | takeback_td(ohci, td); | ||
836 | ohci->ed_to_check = NULL; | ||
837 | } | ||
838 | } else | ||
839 | ohci->ed_to_check = NULL; | ||
840 | } | ||
841 | spin_unlock(&ohci->lock); | ||
842 | } | ||
843 | |||
716 | /* could track INTR_SO to reduce available PCI/... bandwidth */ | 844 | /* could track INTR_SO to reduce available PCI/... bandwidth */ |
717 | 845 | ||
718 | /* handle any pending URB/ED unlinks, leaving INTR_SF enabled | 846 | /* handle any pending URB/ED unlinks, leaving INTR_SF enabled |
@@ -721,7 +849,9 @@ static irqreturn_t ohci_irq (struct usb_hcd *hcd) | |||
721 | spin_lock (&ohci->lock); | 849 | spin_lock (&ohci->lock); |
722 | if (ohci->ed_rm_list) | 850 | if (ohci->ed_rm_list) |
723 | finish_unlinks (ohci, ohci_frame_no(ohci)); | 851 | finish_unlinks (ohci, ohci_frame_no(ohci)); |
724 | if ((ints & OHCI_INTR_SF) != 0 && !ohci->ed_rm_list | 852 | if ((ints & OHCI_INTR_SF) != 0 |
853 | && !ohci->ed_rm_list | ||
854 | && !ohci->ed_to_check | ||
725 | && HC_IS_RUNNING(hcd->state)) | 855 | && HC_IS_RUNNING(hcd->state)) |
726 | ohci_writel (ohci, OHCI_INTR_SF, ®s->intrdisable); | 856 | ohci_writel (ohci, OHCI_INTR_SF, ®s->intrdisable); |
727 | spin_unlock (&ohci->lock); | 857 | spin_unlock (&ohci->lock); |
@@ -751,6 +881,9 @@ static void ohci_stop (struct usb_hcd *hcd) | |||
751 | free_irq(hcd->irq, hcd); | 881 | free_irq(hcd->irq, hcd); |
752 | hcd->irq = -1; | 882 | hcd->irq = -1; |
753 | 883 | ||
884 | if (quirk_zfmicro(ohci)) | ||
885 | del_timer(&ohci->unlink_watchdog); | ||
886 | |||
754 | remove_debug_files (ohci); | 887 | remove_debug_files (ohci); |
755 | ohci_mem_cleanup (ohci); | 888 | ohci_mem_cleanup (ohci); |
756 | if (ohci->hcca) { | 889 | if (ohci->hcca) { |
@@ -828,27 +961,6 @@ static int ohci_restart (struct ohci_hcd *ohci) | |||
828 | 961 | ||
829 | /*-------------------------------------------------------------------------*/ | 962 | /*-------------------------------------------------------------------------*/ |
830 | 963 | ||
831 | /* NEC workaround */ | ||
832 | static void ohci_quirk_nec_worker(struct work_struct *work) | ||
833 | { | ||
834 | struct ohci_hcd *ohci = container_of(work, struct ohci_hcd, nec_work); | ||
835 | int status; | ||
836 | |||
837 | status = ohci_init(ohci); | ||
838 | if (status != 0) { | ||
839 | ohci_err(ohci, "Restarting NEC controller failed " | ||
840 | "in ohci_init, %d\n", status); | ||
841 | return; | ||
842 | } | ||
843 | |||
844 | status = ohci_restart(ohci); | ||
845 | if (status != 0) | ||
846 | ohci_err(ohci, "Restarting NEC controller failed " | ||
847 | "in ohci_restart, %d\n", status); | ||
848 | } | ||
849 | |||
850 | /*-------------------------------------------------------------------------*/ | ||
851 | |||
852 | #define DRIVER_INFO DRIVER_VERSION " " DRIVER_DESC | 964 | #define DRIVER_INFO DRIVER_VERSION " " DRIVER_DESC |
853 | 965 | ||
854 | MODULE_AUTHOR (DRIVER_AUTHOR); | 966 | MODULE_AUTHOR (DRIVER_AUTHOR); |