USB: OHCI: revert the ZF Micro orphan-TD quirk
authorAlan Stern <stern@rowland.harvard.edu>
Fri, 18 Jul 2014 20:25:36 +0000 (16:25 -0400)
committerGreg Kroah-Hartman <gregkh@linuxfoundation.org>
Fri, 18 Jul 2014 23:30:45 +0000 (16:30 -0700)
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>
drivers/usb/host/ohci-hcd.c
drivers/usb/host/ohci-q.c
drivers/usb/host/ohci.h

index 7570098b1cfa3b3211800c183634851b934cba26..a8f0e1b00e7dddbc0cb9157263802e9d98dce126 100644 (file)
@@ -355,8 +355,6 @@ rescan:
        if (ohci->rh_state != OHCI_RH_RUNNING) {
 sanitize:
                ed->state = ED_IDLE;
-               if (quirk_zfmicro(ohci) && ed->type == PIPE_INTERRUPT)
-                       ohci->eds_scheduled--;
                finish_unlinks (ohci, 0);
        }
 
@@ -365,11 +363,6 @@ sanitize:
                /* major IRQ delivery trouble loses INTR_SF too... */
                if (limit-- == 0) {
                        ohci_warn(ohci, "ED unlink timeout\n");
-                       if (quirk_zfmicro(ohci)) {
-                               ohci_warn(ohci, "Attempting ZF TD recovery\n");
-                               ohci->ed_to_check = ed;
-                               ohci->zf_delay = 2;
-                       }
                        goto sanitize;
                }
                spin_unlock_irqrestore (&ohci->lock, flags);
@@ -431,93 +424,6 @@ ohci_shutdown (struct usb_hcd *hcd)
        ohci_writel(ohci, ohci->fminterval, &ohci->regs->fminterval);
 }
 
-static int check_ed(struct ohci_hcd *ohci, struct ed *ed)
-{
-       return (hc32_to_cpu(ohci, ed->hwINFO) & ED_IN) != 0
-               && (hc32_to_cpu(ohci, ed->hwHeadP) & TD_MASK)
-                       == (hc32_to_cpu(ohci, ed->hwTailP) & TD_MASK)
-               && !list_empty(&ed->td_list);
-}
-
-/* ZF Micro watchdog timer callback. The ZF Micro chipset sometimes completes
- * an interrupt TD but neglects to add it to the donelist.  On systems with
- * this chipset, we need to periodically check the state of the queues to look
- * for such "lost" TDs.
- */
-static void unlink_watchdog_func(unsigned long _ohci)
-{
-       unsigned long   flags;
-       unsigned        max;
-       unsigned        seen_count = 0;
-       unsigned        i;
-       struct ed       **seen = NULL;
-       struct ohci_hcd *ohci = (struct ohci_hcd *) _ohci;
-
-       spin_lock_irqsave(&ohci->lock, flags);
-       max = ohci->eds_scheduled;
-       if (!max)
-               goto done;
-
-       if (ohci->ed_to_check)
-               goto out;
-
-       seen = kcalloc(max, sizeof *seen, GFP_ATOMIC);
-       if (!seen)
-               goto out;
-
-       for (i = 0; i < NUM_INTS; i++) {
-               struct ed       *ed = ohci->periodic[i];
-
-               while (ed) {
-                       unsigned        temp;
-
-                       /* scan this branch of the periodic schedule tree */
-                       for (temp = 0; temp < seen_count; temp++) {
-                               if (seen[temp] == ed) {
-                                       /* we've checked it and what's after */
-                                       ed = NULL;
-                                       break;
-                               }
-                       }
-                       if (!ed)
-                               break;
-                       seen[seen_count++] = ed;
-                       if (!check_ed(ohci, ed)) {
-                               ed = ed->ed_next;
-                               continue;
-                       }
-
-                       /* HC's TD list is empty, but HCD sees at least one
-                        * TD that's not been sent through the donelist.
-                        */
-                       ohci->ed_to_check = ed;
-                       ohci->zf_delay = 2;
-
-                       /* The HC may wait until the next frame to report the
-                        * TD as done through the donelist and INTR_WDH.  (We
-                        * just *assume* it's not a multi-TD interrupt URB;
-                        * those could defer the IRQ more than one frame, using
-                        * DI...)  Check again after the next INTR_SF.
-                        */
-                       ohci_writel(ohci, OHCI_INTR_SF,
-                                       &ohci->regs->intrstatus);
-                       ohci_writel(ohci, OHCI_INTR_SF,
-                                       &ohci->regs->intrenable);
-
-                       /* flush those writes */
-                       (void) ohci_readl(ohci, &ohci->regs->control);
-
-                       goto out;
-               }
-       }
-out:
-       kfree(seen);
-       if (ohci->eds_scheduled)
-               mod_timer(&ohci->unlink_watchdog, round_jiffies(jiffies + HZ));
-done:
-       spin_unlock_irqrestore(&ohci->lock, flags);
-}
-
 /*-------------------------------------------------------------------------*
  * HC functions
  *-------------------------------------------------------------------------*/
@@ -761,15 +667,6 @@ retry:
        // POTPGT delay is bits 24-31, in 2 ms units.
        mdelay ((val >> 23) & 0x1fe);
 
-       if (quirk_zfmicro(ohci)) {
-               /* Create timer to watch for bad queue state on ZF Micro */
-               setup_timer(&ohci->unlink_watchdog, unlink_watchdog_func,
-                               (unsigned long) ohci);
-
-               ohci->eds_scheduled = 0;
-               ohci->ed_to_check = NULL;
-       }
-
        ohci_dump(ohci);
 
        return 0;
@@ -895,31 +792,6 @@ static irqreturn_t ohci_irq (struct usb_hcd *hcd)
                spin_unlock (&ohci->lock);
        }
 
-       if (quirk_zfmicro(ohci) && (ints & OHCI_INTR_SF)) {
-               spin_lock(&ohci->lock);
-               if (ohci->ed_to_check) {
-                       struct ed *ed = ohci->ed_to_check;
-
-                       if (check_ed(ohci, ed)) {
-                               /* HC thinks the TD list is empty; HCD knows
-                                * at least one TD is outstanding
-                                */
-                               if (--ohci->zf_delay == 0) {
-                                       struct td *td = list_entry(
-                                               ed->td_list.next,
-                                               struct td, td_list);
-                                       ohci_warn(ohci,
-                                                 "Reclaiming orphan TD %p\n",
-                                                 td);
-                                       takeback_td(ohci, td);
-                                       ohci->ed_to_check = NULL;
-                               }
-                       } else
-                               ohci->ed_to_check = NULL;
-               }
-               spin_unlock(&ohci->lock);
-       }
-
        /* could track INTR_SO to reduce available PCI/... bandwidth */
 
        /* handle any pending URB/ED unlinks, leaving INTR_SF enabled
@@ -928,9 +800,7 @@ static irqreturn_t ohci_irq (struct usb_hcd *hcd)
        spin_lock (&ohci->lock);
        if (ohci->ed_rm_list)
                finish_unlinks (ohci, ohci_frame_no(ohci));
-       if ((ints & OHCI_INTR_SF) != 0
-                       && !ohci->ed_rm_list
-                       && !ohci->ed_to_check
+       if ((ints & OHCI_INTR_SF) != 0 && !ohci->ed_rm_list
                        && ohci->rh_state == OHCI_RH_RUNNING)
                ohci_writel (ohci, OHCI_INTR_SF, &regs->intrdisable);
        spin_unlock (&ohci->lock);
@@ -961,8 +831,6 @@ static void ohci_stop (struct usb_hcd *hcd)
        free_irq(hcd->irq, hcd);
        hcd->irq = 0;
 
-       if (quirk_zfmicro(ohci))
-               del_timer(&ohci->unlink_watchdog);
        if (quirk_amdiso(ohci))
                usb_amd_dev_put();
 
index a6376f3e55cb6a64f570d0d4c4e08d8461f5deca..a9f4f04c3fade762b7e0ebb722f3bed24be0ab21 100644 (file)
@@ -187,10 +187,6 @@ static int ed_schedule (struct ohci_hcd *ohci, struct ed *ed)
        ed->ed_prev = NULL;
        ed->ed_next = NULL;
        ed->hwNextED = 0;
-       if (quirk_zfmicro(ohci)
-                       && (ed->type == PIPE_INTERRUPT)
-                       && !(ohci->eds_scheduled++))
-               mod_timer(&ohci->unlink_watchdog, round_jiffies(jiffies + HZ));
        wmb ();
 
        /* we care about rm_list when setting CLE/BLE in case the HC was at
@@ -977,19 +973,13 @@ skip_ed:
                                                                TD_MASK;
 
                                /* INTR_WDH may need to clean up first */
-                               if (td->td_dma != head) {
-                                       if (ed == ohci->ed_to_check)
-                                               ohci->ed_to_check = NULL;
-                                       else
-                                               goto skip_ed;
-                               }
+                               if (td->td_dma != head)
+                                       goto skip_ed;
                        }
                }
 
                /* ED's now officially unlinked, hc doesn't see */
                ed->state = ED_IDLE;
-               if (quirk_zfmicro(ohci) && ed->type == PIPE_INTERRUPT)
-                       ohci->eds_scheduled--;
                ed->hwHeadP &= ~cpu_to_hc32(ohci, ED_H);
                ed->hwNextED = 0;
                wmb();
@@ -1122,12 +1112,7 @@ rescan_this:
 
 /*-------------------------------------------------------------------------*/
 
-/*
- * Used to take back a TD from the host controller. This would normally be
- * called from within dl_done_list, however it may be called directly if the
- * HC no longer sees the TD and it has not appeared on the donelist (after
- * two frames).  This bug has been observed on ZF Micro systems.
- */
+/* Take back a TD from the host controller */
 static void takeback_td(struct ohci_hcd *ohci, struct td *td)
 {
        struct urb      *urb = td->urb;
@@ -1174,9 +1159,7 @@ static void takeback_td(struct ohci_hcd *ohci, struct td *td)
  *
  * This is the main path for handing urbs back to drivers.  The only other
  * normal path is finish_unlinks(), which unlinks URBs using ed_rm_list,
- * instead of scanning the (re-reversed) donelist as this does.  There's
- * an abnormal path too, handling a quirk in some Compaq silicon:  URBs
- * with TDs that appear to be orphaned are directly reclaimed.
+ * instead of scanning the (re-reversed) donelist as this does.
  */
 static void
 dl_done_list (struct ohci_hcd *ohci)
index 05e02a709d4f110c4a3570eaec4025f097acaa86..392932dd63184ccd7b9ad183f5a81d02f76477bd 100644 (file)
@@ -411,12 +411,6 @@ struct ohci_hcd {
 
        struct work_struct      nec_work;       /* Worker for NEC quirk */
 
-       /* Needed for ZF Micro quirk */
-       struct timer_list       unlink_watchdog;
-       unsigned                eds_scheduled;
-       struct ed               *ed_to_check;
-       unsigned                zf_delay;
-
        struct dentry           *debug_dir;
        struct dentry           *debug_async;
        struct dentry           *debug_periodic;