aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/usb/host/ohci-q.c
diff options
context:
space:
mode:
authorMike Nuss <mike@terascala.com>2007-08-01 16:24:30 -0400
committerGreg Kroah-Hartman <gregkh@suse.de>2007-10-12 17:54:59 -0400
commit89a0fd18a96eb1f8732714b575073f8a8d69c009 (patch)
tree166d14fc49ad7fd646e1e7aa7decf6b3bea6d381 /drivers/usb/host/ohci-q.c
parente8fa0ce65c58dbb60be279c4e33534650dcacc31 (diff)
USB: OHCI handles more ZFMicro quirks
The ZF Micro OHCI controller exhibits unexpected behavior that seems to be related to high load. Under certain conditions, the controller will complete a TD, remove it from the endpoint's queue, and fail to add it to the donelist. This causes the endpoint to appear to stop responding. Worse, if the device is removed while in that state, OHCI will hang while waiting for the orphaned TD to complete. The situation is not recoverable without rebooting. This fix enhances the scope of the existing OHCI_QUIRK_ZFMICRO flag: 1. A watchdog routine periodically scans the OHCI structures to check for orphaned TDs. In these cases the TD is taken back from the controller and completed normally. 2. If a device is removed while the endpoint is hung but before the watchdog catches the situation, any outstanding TDs are taken back from the controller in the 'sanitize' phase. The ohci-hcd driver used to print "INTR_SF lossage" in this situation; this changes it to the universally accurate "ED unlink timeout". Other instances of this message presumably have different root causes. Both this Compaq quirk and a NEC quirk are now properly compiled out for non-PCI builds of this driver. Signed-off-by: Mike Nuss <mike@terascala.com> Signed-off-by: David Brownell <dbrownell@users.sourceforge.net> Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de>
Diffstat (limited to 'drivers/usb/host/ohci-q.c')
-rw-r--r--drivers/usb/host/ohci-q.c113
1 files changed, 67 insertions, 46 deletions
diff --git a/drivers/usb/host/ohci-q.c b/drivers/usb/host/ohci-q.c
index 830a3fe8615e..547d39be3eb9 100644
--- a/drivers/usb/host/ohci-q.c
+++ b/drivers/usb/host/ohci-q.c
@@ -179,6 +179,10 @@ static int ed_schedule (struct ohci_hcd *ohci, struct ed *ed)
179 ed->ed_prev = NULL; 179 ed->ed_prev = NULL;
180 ed->ed_next = NULL; 180 ed->ed_next = NULL;
181 ed->hwNextED = 0; 181 ed->hwNextED = 0;
182 if (quirk_zfmicro(ohci)
183 && (ed->type == PIPE_INTERRUPT)
184 && !(ohci->eds_scheduled++))
185 mod_timer(&ohci->unlink_watchdog, round_jiffies_relative(HZ));
182 wmb (); 186 wmb ();
183 187
184 /* we care about rm_list when setting CLE/BLE in case the HC was at 188 /* we care about rm_list when setting CLE/BLE in case the HC was at
@@ -940,8 +944,12 @@ skip_ed:
940 TD_MASK; 944 TD_MASK;
941 945
942 /* INTR_WDH may need to clean up first */ 946 /* INTR_WDH may need to clean up first */
943 if (td->td_dma != head) 947 if (td->td_dma != head) {
944 goto skip_ed; 948 if (ed == ohci->ed_to_check)
949 ohci->ed_to_check = NULL;
950 else
951 goto skip_ed;
952 }
945 } 953 }
946 } 954 }
947 955
@@ -998,6 +1006,8 @@ rescan_this:
998 1006
999 /* ED's now officially unlinked, hc doesn't see */ 1007 /* ED's now officially unlinked, hc doesn't see */
1000 ed->state = ED_IDLE; 1008 ed->state = ED_IDLE;
1009 if (quirk_zfmicro(ohci) && ed->type == PIPE_INTERRUPT)
1010 ohci->eds_scheduled--;
1001 ed->hwHeadP &= ~cpu_to_hc32(ohci, ED_H); 1011 ed->hwHeadP &= ~cpu_to_hc32(ohci, ED_H);
1002 ed->hwNextED = 0; 1012 ed->hwNextED = 0;
1003 wmb (); 1013 wmb ();
@@ -1021,7 +1031,7 @@ rescan_this:
1021 1031
1022 if (ohci->ed_controltail) { 1032 if (ohci->ed_controltail) {
1023 command |= OHCI_CLF; 1033 command |= OHCI_CLF;
1024 if (ohci->flags & OHCI_QUIRK_ZFMICRO) 1034 if (quirk_zfmicro(ohci))
1025 mdelay(1); 1035 mdelay(1);
1026 if (!(ohci->hc_control & OHCI_CTRL_CLE)) { 1036 if (!(ohci->hc_control & OHCI_CTRL_CLE)) {
1027 control |= OHCI_CTRL_CLE; 1037 control |= OHCI_CTRL_CLE;
@@ -1031,7 +1041,7 @@ rescan_this:
1031 } 1041 }
1032 if (ohci->ed_bulktail) { 1042 if (ohci->ed_bulktail) {
1033 command |= OHCI_BLF; 1043 command |= OHCI_BLF;
1034 if (ohci->flags & OHCI_QUIRK_ZFMICRO) 1044 if (quirk_zfmicro(ohci))
1035 mdelay(1); 1045 mdelay(1);
1036 if (!(ohci->hc_control & OHCI_CTRL_BLE)) { 1046 if (!(ohci->hc_control & OHCI_CTRL_BLE)) {
1037 control |= OHCI_CTRL_BLE; 1047 control |= OHCI_CTRL_BLE;
@@ -1043,13 +1053,13 @@ rescan_this:
1043 /* CLE/BLE to enable, CLF/BLF to (maybe) kickstart */ 1053 /* CLE/BLE to enable, CLF/BLF to (maybe) kickstart */
1044 if (control) { 1054 if (control) {
1045 ohci->hc_control |= control; 1055 ohci->hc_control |= control;
1046 if (ohci->flags & OHCI_QUIRK_ZFMICRO) 1056 if (quirk_zfmicro(ohci))
1047 mdelay(1); 1057 mdelay(1);
1048 ohci_writel (ohci, ohci->hc_control, 1058 ohci_writel (ohci, ohci->hc_control,
1049 &ohci->regs->control); 1059 &ohci->regs->control);
1050 } 1060 }
1051 if (command) { 1061 if (command) {
1052 if (ohci->flags & OHCI_QUIRK_ZFMICRO) 1062 if (quirk_zfmicro(ohci))
1053 mdelay(1); 1063 mdelay(1);
1054 ohci_writel (ohci, command, &ohci->regs->cmdstatus); 1064 ohci_writel (ohci, command, &ohci->regs->cmdstatus);
1055 } 1065 }
@@ -1061,11 +1071,59 @@ rescan_this:
1061/*-------------------------------------------------------------------------*/ 1071/*-------------------------------------------------------------------------*/
1062 1072
1063/* 1073/*
1074 * Used to take back a TD from the host controller. This would normally be
1075 * called from within dl_done_list, however it may be called directly if the
1076 * HC no longer sees the TD and it has not appeared on the donelist (after
1077 * two frames). This bug has been observed on ZF Micro systems.
1078 */
1079static void takeback_td(struct ohci_hcd *ohci, struct td *td)
1080{
1081 struct urb *urb = td->urb;
1082 urb_priv_t *urb_priv = urb->hcpriv;
1083 struct ed *ed = td->ed;
1084
1085 /* update URB's length and status from TD */
1086 td_done(ohci, urb, td);
1087 urb_priv->td_cnt++;
1088
1089 /* If all this urb's TDs are done, call complete() */
1090 if (urb_priv->td_cnt == urb_priv->length)
1091 finish_urb(ohci, urb);
1092
1093 /* clean schedule: unlink EDs that are no longer busy */
1094 if (list_empty(&ed->td_list)) {
1095 if (ed->state == ED_OPER)
1096 start_ed_unlink(ohci, ed);
1097
1098 /* ... reenabling halted EDs only after fault cleanup */
1099 } else if ((ed->hwINFO & cpu_to_hc32(ohci, ED_SKIP | ED_DEQUEUE))
1100 == cpu_to_hc32(ohci, ED_SKIP)) {
1101 td = list_entry(ed->td_list.next, struct td, td_list);
1102 if (!(td->hwINFO & cpu_to_hc32(ohci, TD_DONE))) {
1103 ed->hwINFO &= ~cpu_to_hc32(ohci, ED_SKIP);
1104 /* ... hc may need waking-up */
1105 switch (ed->type) {
1106 case PIPE_CONTROL:
1107 ohci_writel(ohci, OHCI_CLF,
1108 &ohci->regs->cmdstatus);
1109 break;
1110 case PIPE_BULK:
1111 ohci_writel(ohci, OHCI_BLF,
1112 &ohci->regs->cmdstatus);
1113 break;
1114 }
1115 }
1116 }
1117}
1118
1119/*
1064 * Process normal completions (error or success) and clean the schedules. 1120 * Process normal completions (error or success) and clean the schedules.
1065 * 1121 *
1066 * This is the main path for handing urbs back to drivers. The only other 1122 * This is the main path for handing urbs back to drivers. The only other
1067 * path is finish_unlinks(), which unlinks URBs using ed_rm_list, instead of 1123 * normal path is finish_unlinks(), which unlinks URBs using ed_rm_list,
1068 * scanning the (re-reversed) donelist as this does. 1124 * instead of scanning the (re-reversed) donelist as this does. There's
1125 * an abnormal path too, handling a quirk in some Compaq silicon: URBs
1126 * with TDs that appear to be orphaned are directly reclaimed.
1069 */ 1127 */
1070static void 1128static void
1071dl_done_list (struct ohci_hcd *ohci) 1129dl_done_list (struct ohci_hcd *ohci)
@@ -1074,44 +1132,7 @@ dl_done_list (struct ohci_hcd *ohci)
1074 1132
1075 while (td) { 1133 while (td) {
1076 struct td *td_next = td->next_dl_td; 1134 struct td *td_next = td->next_dl_td;
1077 struct urb *urb = td->urb; 1135 takeback_td(ohci, td);
1078 urb_priv_t *urb_priv = urb->hcpriv;
1079 struct ed *ed = td->ed;
1080
1081 /* update URB's length and status from TD */
1082 td_done (ohci, urb, td);
1083 urb_priv->td_cnt++;
1084
1085 /* If all this urb's TDs are done, call complete() */
1086 if (urb_priv->td_cnt == urb_priv->length)
1087 finish_urb (ohci, urb);
1088
1089 /* clean schedule: unlink EDs that are no longer busy */
1090 if (list_empty (&ed->td_list)) {
1091 if (ed->state == ED_OPER)
1092 start_ed_unlink (ohci, ed);
1093
1094 /* ... reenabling halted EDs only after fault cleanup */
1095 } else if ((ed->hwINFO & cpu_to_hc32 (ohci,
1096 ED_SKIP | ED_DEQUEUE))
1097 == cpu_to_hc32 (ohci, ED_SKIP)) {
1098 td = list_entry (ed->td_list.next, struct td, td_list);
1099 if (!(td->hwINFO & cpu_to_hc32 (ohci, TD_DONE))) {
1100 ed->hwINFO &= ~cpu_to_hc32 (ohci, ED_SKIP);
1101 /* ... hc may need waking-up */
1102 switch (ed->type) {
1103 case PIPE_CONTROL:
1104 ohci_writel (ohci, OHCI_CLF,
1105 &ohci->regs->cmdstatus);
1106 break;
1107 case PIPE_BULK:
1108 ohci_writel (ohci, OHCI_BLF,
1109 &ohci->regs->cmdstatus);
1110 break;
1111 }
1112 }
1113 }
1114
1115 td = td_next; 1136 td = td_next;
1116 } 1137 }
1117} 1138}