diff options
author | Alan Stern <stern@rowland.harvard.edu> | 2014-07-18 16:25:36 -0400 |
---|---|---|
committer | Greg Kroah-Hartman <gregkh@linuxfoundation.org> | 2014-07-18 19:30:45 -0400 |
commit | 95d9a01d727fdb6d2b667ac374341c48777cc41e (patch) | |
tree | 36f1c672f3dca5b67f510ecf9f3ea90574808673 | |
parent | a40178b2fa6ad87670fb1e5fa4024db00c149629 (diff) |
USB: OHCI: revert the ZF Micro orphan-TD quirk
This patch reverts the important parts of commit 89a0fd18a96e (USB:
OHCI handles more ZFMicro quirks), namely, the parts related to
handling orphan TDs for interrupt endpoints. A later patch in this
series will introduce a more general mechanism that applies to all
endpoint types and all controllers.
Signed-off-by: Alan Stern <stern@rowland.harvard.edu>
Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
-rw-r--r-- | drivers/usb/host/ohci-hcd.c | 134 | ||||
-rw-r--r-- | drivers/usb/host/ohci-q.c | 25 | ||||
-rw-r--r-- | drivers/usb/host/ohci.h | 6 |
3 files changed, 5 insertions, 160 deletions
diff --git a/drivers/usb/host/ohci-hcd.c b/drivers/usb/host/ohci-hcd.c index 7570098b1cfa..a8f0e1b00e7d 100644 --- a/drivers/usb/host/ohci-hcd.c +++ b/drivers/usb/host/ohci-hcd.c | |||
@@ -355,8 +355,6 @@ rescan: | |||
355 | if (ohci->rh_state != OHCI_RH_RUNNING) { | 355 | if (ohci->rh_state != OHCI_RH_RUNNING) { |
356 | sanitize: | 356 | sanitize: |
357 | ed->state = ED_IDLE; | 357 | ed->state = ED_IDLE; |
358 | if (quirk_zfmicro(ohci) && ed->type == PIPE_INTERRUPT) | ||
359 | ohci->eds_scheduled--; | ||
360 | finish_unlinks (ohci, 0); | 358 | finish_unlinks (ohci, 0); |
361 | } | 359 | } |
362 | 360 | ||
@@ -365,11 +363,6 @@ sanitize: | |||
365 | /* major IRQ delivery trouble loses INTR_SF too... */ | 363 | /* major IRQ delivery trouble loses INTR_SF too... */ |
366 | if (limit-- == 0) { | 364 | if (limit-- == 0) { |
367 | ohci_warn(ohci, "ED unlink timeout\n"); | 365 | ohci_warn(ohci, "ED unlink timeout\n"); |
368 | if (quirk_zfmicro(ohci)) { | ||
369 | ohci_warn(ohci, "Attempting ZF TD recovery\n"); | ||
370 | ohci->ed_to_check = ed; | ||
371 | ohci->zf_delay = 2; | ||
372 | } | ||
373 | goto sanitize; | 366 | goto sanitize; |
374 | } | 367 | } |
375 | spin_unlock_irqrestore (&ohci->lock, flags); | 368 | spin_unlock_irqrestore (&ohci->lock, flags); |
@@ -431,93 +424,6 @@ ohci_shutdown (struct usb_hcd *hcd) | |||
431 | ohci_writel(ohci, ohci->fminterval, &ohci->regs->fminterval); | 424 | ohci_writel(ohci, ohci->fminterval, &ohci->regs->fminterval); |
432 | } | 425 | } |
433 | 426 | ||
434 | static int check_ed(struct ohci_hcd *ohci, struct ed *ed) | ||
435 | { | ||
436 | return (hc32_to_cpu(ohci, ed->hwINFO) & ED_IN) != 0 | ||
437 | && (hc32_to_cpu(ohci, ed->hwHeadP) & TD_MASK) | ||
438 | == (hc32_to_cpu(ohci, ed->hwTailP) & TD_MASK) | ||
439 | && !list_empty(&ed->td_list); | ||
440 | } | ||
441 | |||
442 | /* ZF Micro watchdog timer callback. The ZF Micro chipset sometimes completes | ||
443 | * an interrupt TD but neglects to add it to the donelist. On systems with | ||
444 | * this chipset, we need to periodically check the state of the queues to look | ||
445 | * for such "lost" TDs. | ||
446 | */ | ||
447 | static void unlink_watchdog_func(unsigned long _ohci) | ||
448 | { | ||
449 | unsigned long flags; | ||
450 | unsigned max; | ||
451 | unsigned seen_count = 0; | ||
452 | unsigned i; | ||
453 | struct ed **seen = NULL; | ||
454 | struct ohci_hcd *ohci = (struct ohci_hcd *) _ohci; | ||
455 | |||
456 | spin_lock_irqsave(&ohci->lock, flags); | ||
457 | max = ohci->eds_scheduled; | ||
458 | if (!max) | ||
459 | goto done; | ||
460 | |||
461 | if (ohci->ed_to_check) | ||
462 | goto out; | ||
463 | |||
464 | seen = kcalloc(max, sizeof *seen, GFP_ATOMIC); | ||
465 | if (!seen) | ||
466 | goto out; | ||
467 | |||
468 | for (i = 0; i < NUM_INTS; i++) { | ||
469 | struct ed *ed = ohci->periodic[i]; | ||
470 | |||
471 | while (ed) { | ||
472 | unsigned temp; | ||
473 | |||
474 | /* scan this branch of the periodic schedule tree */ | ||
475 | for (temp = 0; temp < seen_count; temp++) { | ||
476 | if (seen[temp] == ed) { | ||
477 | /* we've checked it and what's after */ | ||
478 | ed = NULL; | ||
479 | break; | ||
480 | } | ||
481 | } | ||
482 | if (!ed) | ||
483 | break; | ||
484 | seen[seen_count++] = ed; | ||
485 | if (!check_ed(ohci, ed)) { | ||
486 | ed = ed->ed_next; | ||
487 | continue; | ||
488 | } | ||
489 | |||
490 | /* HC's TD list is empty, but HCD sees at least one | ||
491 | * TD that's not been sent through the donelist. | ||
492 | */ | ||
493 | ohci->ed_to_check = ed; | ||
494 | ohci->zf_delay = 2; | ||
495 | |||
496 | /* The HC may wait until the next frame to report the | ||
497 | * TD as done through the donelist and INTR_WDH. (We | ||
498 | * just *assume* it's not a multi-TD interrupt URB; | ||
499 | * those could defer the IRQ more than one frame, using | ||
500 | * DI...) Check again after the next INTR_SF. | ||
501 | */ | ||
502 | ohci_writel(ohci, OHCI_INTR_SF, | ||
503 | &ohci->regs->intrstatus); | ||
504 | ohci_writel(ohci, OHCI_INTR_SF, | ||
505 | &ohci->regs->intrenable); | ||
506 | |||
507 | /* flush those writes */ | ||
508 | (void) ohci_readl(ohci, &ohci->regs->control); | ||
509 | |||
510 | goto out; | ||
511 | } | ||
512 | } | ||
513 | out: | ||
514 | kfree(seen); | ||
515 | if (ohci->eds_scheduled) | ||
516 | mod_timer(&ohci->unlink_watchdog, round_jiffies(jiffies + HZ)); | ||
517 | done: | ||
518 | spin_unlock_irqrestore(&ohci->lock, flags); | ||
519 | } | ||
520 | |||
521 | /*-------------------------------------------------------------------------* | 427 | /*-------------------------------------------------------------------------* |
522 | * HC functions | 428 | * HC functions |
523 | *-------------------------------------------------------------------------*/ | 429 | *-------------------------------------------------------------------------*/ |
@@ -761,15 +667,6 @@ retry: | |||
761 | // POTPGT delay is bits 24-31, in 2 ms units. | 667 | // POTPGT delay is bits 24-31, in 2 ms units. |
762 | mdelay ((val >> 23) & 0x1fe); | 668 | mdelay ((val >> 23) & 0x1fe); |
763 | 669 | ||
764 | if (quirk_zfmicro(ohci)) { | ||
765 | /* Create timer to watch for bad queue state on ZF Micro */ | ||
766 | setup_timer(&ohci->unlink_watchdog, unlink_watchdog_func, | ||
767 | (unsigned long) ohci); | ||
768 | |||
769 | ohci->eds_scheduled = 0; | ||
770 | ohci->ed_to_check = NULL; | ||
771 | } | ||
772 | |||
773 | ohci_dump(ohci); | 670 | ohci_dump(ohci); |
774 | 671 | ||
775 | return 0; | 672 | return 0; |
@@ -895,31 +792,6 @@ static irqreturn_t ohci_irq (struct usb_hcd *hcd) | |||
895 | spin_unlock (&ohci->lock); | 792 | spin_unlock (&ohci->lock); |
896 | } | 793 | } |
897 | 794 | ||
898 | if (quirk_zfmicro(ohci) && (ints & OHCI_INTR_SF)) { | ||
899 | spin_lock(&ohci->lock); | ||
900 | if (ohci->ed_to_check) { | ||
901 | struct ed *ed = ohci->ed_to_check; | ||
902 | |||
903 | if (check_ed(ohci, ed)) { | ||
904 | /* HC thinks the TD list is empty; HCD knows | ||
905 | * at least one TD is outstanding | ||
906 | */ | ||
907 | if (--ohci->zf_delay == 0) { | ||
908 | struct td *td = list_entry( | ||
909 | ed->td_list.next, | ||
910 | struct td, td_list); | ||
911 | ohci_warn(ohci, | ||
912 | "Reclaiming orphan TD %p\n", | ||
913 | td); | ||
914 | takeback_td(ohci, td); | ||
915 | ohci->ed_to_check = NULL; | ||
916 | } | ||
917 | } else | ||
918 | ohci->ed_to_check = NULL; | ||
919 | } | ||
920 | spin_unlock(&ohci->lock); | ||
921 | } | ||
922 | |||
923 | /* could track INTR_SO to reduce available PCI/... bandwidth */ | 795 | /* could track INTR_SO to reduce available PCI/... bandwidth */ |
924 | 796 | ||
925 | /* handle any pending URB/ED unlinks, leaving INTR_SF enabled | 797 | /* handle any pending URB/ED unlinks, leaving INTR_SF enabled |
@@ -928,9 +800,7 @@ static irqreturn_t ohci_irq (struct usb_hcd *hcd) | |||
928 | spin_lock (&ohci->lock); | 800 | spin_lock (&ohci->lock); |
929 | if (ohci->ed_rm_list) | 801 | if (ohci->ed_rm_list) |
930 | finish_unlinks (ohci, ohci_frame_no(ohci)); | 802 | finish_unlinks (ohci, ohci_frame_no(ohci)); |
931 | if ((ints & OHCI_INTR_SF) != 0 | 803 | if ((ints & OHCI_INTR_SF) != 0 && !ohci->ed_rm_list |
932 | && !ohci->ed_rm_list | ||
933 | && !ohci->ed_to_check | ||
934 | && ohci->rh_state == OHCI_RH_RUNNING) | 804 | && ohci->rh_state == OHCI_RH_RUNNING) |
935 | ohci_writel (ohci, OHCI_INTR_SF, ®s->intrdisable); | 805 | ohci_writel (ohci, OHCI_INTR_SF, ®s->intrdisable); |
936 | spin_unlock (&ohci->lock); | 806 | spin_unlock (&ohci->lock); |
@@ -961,8 +831,6 @@ static void ohci_stop (struct usb_hcd *hcd) | |||
961 | free_irq(hcd->irq, hcd); | 831 | free_irq(hcd->irq, hcd); |
962 | hcd->irq = 0; | 832 | hcd->irq = 0; |
963 | 833 | ||
964 | if (quirk_zfmicro(ohci)) | ||
965 | del_timer(&ohci->unlink_watchdog); | ||
966 | if (quirk_amdiso(ohci)) | 834 | if (quirk_amdiso(ohci)) |
967 | usb_amd_dev_put(); | 835 | usb_amd_dev_put(); |
968 | 836 | ||
diff --git a/drivers/usb/host/ohci-q.c b/drivers/usb/host/ohci-q.c index a6376f3e55cb..a9f4f04c3fad 100644 --- a/drivers/usb/host/ohci-q.c +++ b/drivers/usb/host/ohci-q.c | |||
@@ -187,10 +187,6 @@ static int ed_schedule (struct ohci_hcd *ohci, struct ed *ed) | |||
187 | ed->ed_prev = NULL; | 187 | ed->ed_prev = NULL; |
188 | ed->ed_next = NULL; | 188 | ed->ed_next = NULL; |
189 | ed->hwNextED = 0; | 189 | ed->hwNextED = 0; |
190 | if (quirk_zfmicro(ohci) | ||
191 | && (ed->type == PIPE_INTERRUPT) | ||
192 | && !(ohci->eds_scheduled++)) | ||
193 | mod_timer(&ohci->unlink_watchdog, round_jiffies(jiffies + HZ)); | ||
194 | wmb (); | 190 | wmb (); |
195 | 191 | ||
196 | /* we care about rm_list when setting CLE/BLE in case the HC was at | 192 | /* we care about rm_list when setting CLE/BLE in case the HC was at |
@@ -977,19 +973,13 @@ skip_ed: | |||
977 | TD_MASK; | 973 | TD_MASK; |
978 | 974 | ||
979 | /* INTR_WDH may need to clean up first */ | 975 | /* INTR_WDH may need to clean up first */ |
980 | if (td->td_dma != head) { | 976 | if (td->td_dma != head) |
981 | if (ed == ohci->ed_to_check) | 977 | goto skip_ed; |
982 | ohci->ed_to_check = NULL; | ||
983 | else | ||
984 | goto skip_ed; | ||
985 | } | ||
986 | } | 978 | } |
987 | } | 979 | } |
988 | 980 | ||
989 | /* ED's now officially unlinked, hc doesn't see */ | 981 | /* ED's now officially unlinked, hc doesn't see */ |
990 | ed->state = ED_IDLE; | 982 | ed->state = ED_IDLE; |
991 | if (quirk_zfmicro(ohci) && ed->type == PIPE_INTERRUPT) | ||
992 | ohci->eds_scheduled--; | ||
993 | ed->hwHeadP &= ~cpu_to_hc32(ohci, ED_H); | 983 | ed->hwHeadP &= ~cpu_to_hc32(ohci, ED_H); |
994 | ed->hwNextED = 0; | 984 | ed->hwNextED = 0; |
995 | wmb(); | 985 | wmb(); |
@@ -1122,12 +1112,7 @@ rescan_this: | |||
1122 | 1112 | ||
1123 | /*-------------------------------------------------------------------------*/ | 1113 | /*-------------------------------------------------------------------------*/ |
1124 | 1114 | ||
1125 | /* | 1115 | /* Take back a TD from the host controller */ |
1126 | * Used to take back a TD from the host controller. This would normally be | ||
1127 | * called from within dl_done_list, however it may be called directly if the | ||
1128 | * HC no longer sees the TD and it has not appeared on the donelist (after | ||
1129 | * two frames). This bug has been observed on ZF Micro systems. | ||
1130 | */ | ||
1131 | static void takeback_td(struct ohci_hcd *ohci, struct td *td) | 1116 | static void takeback_td(struct ohci_hcd *ohci, struct td *td) |
1132 | { | 1117 | { |
1133 | struct urb *urb = td->urb; | 1118 | struct urb *urb = td->urb; |
@@ -1174,9 +1159,7 @@ static void takeback_td(struct ohci_hcd *ohci, struct td *td) | |||
1174 | * | 1159 | * |
1175 | * This is the main path for handing urbs back to drivers. The only other | 1160 | * This is the main path for handing urbs back to drivers. The only other |
1176 | * normal path is finish_unlinks(), which unlinks URBs using ed_rm_list, | 1161 | * normal path is finish_unlinks(), which unlinks URBs using ed_rm_list, |
1177 | * instead of scanning the (re-reversed) donelist as this does. There's | 1162 | * instead of scanning the (re-reversed) donelist as this does. |
1178 | * an abnormal path too, handling a quirk in some Compaq silicon: URBs | ||
1179 | * with TDs that appear to be orphaned are directly reclaimed. | ||
1180 | */ | 1163 | */ |
1181 | static void | 1164 | static void |
1182 | dl_done_list (struct ohci_hcd *ohci) | 1165 | dl_done_list (struct ohci_hcd *ohci) |
diff --git a/drivers/usb/host/ohci.h b/drivers/usb/host/ohci.h index 05e02a709d4f..392932dd6318 100644 --- a/drivers/usb/host/ohci.h +++ b/drivers/usb/host/ohci.h | |||
@@ -411,12 +411,6 @@ struct ohci_hcd { | |||
411 | 411 | ||
412 | struct work_struct nec_work; /* Worker for NEC quirk */ | 412 | struct work_struct nec_work; /* Worker for NEC quirk */ |
413 | 413 | ||
414 | /* Needed for ZF Micro quirk */ | ||
415 | struct timer_list unlink_watchdog; | ||
416 | unsigned eds_scheduled; | ||
417 | struct ed *ed_to_check; | ||
418 | unsigned zf_delay; | ||
419 | |||
420 | struct dentry *debug_dir; | 414 | struct dentry *debug_dir; |
421 | struct dentry *debug_async; | 415 | struct dentry *debug_async; |
422 | struct dentry *debug_periodic; | 416 | struct dentry *debug_periodic; |