These patches are against kernels 2.6.18 through at least 2.6.18-git7.

patch 3: moves scattered interrupt endpoint (periodic QH) code to one
place.  Also eliminates some vestigal patterning patterning after the
async QH code.  There should be no functional difference after this
patch.

Signed-off-by: Christopher "Monty" Montgomery <[EMAIL PROTECTED]>

---

diff -X b/Documentation/dontdiff -upr a/drivers/usb/host/ehci-hcd.c
b/drivers/usb/host/ehci-hcd.c
--- a/drivers/usb/host/ehci-hcd.c       2006-09-26 22:12:14.000000000 -0400
+++ b/drivers/usb/host/ehci-hcd.c       2006-09-26 22:17:38.000000000 -0400
@@ -764,7 +764,7 @@ static int ehci_urb_dequeue (struct usb_
                        break;
                switch (qh->qh_state) {
                case QH_STATE_LINKED:
-                       intr_deschedule (ehci, qh);
+                       periodic_qh_deschedule (ehci, qh);
                        /* FALL THROUGH */
                case QH_STATE_IDLE:
                        qh_completions (ehci, qh, NULL);
@@ -780,7 +780,7 @@ static int ehci_urb_dequeue (struct usb_
                                && HC_IS_RUNNING (hcd->state)) {
                        int status;

-                       status = qh_schedule (ehci, qh);
+                       status = periodic_qh_schedule (ehci, qh);
                        spin_unlock_irqrestore (&ehci->lock, flags);

                        if (status != 0) {
diff -X b/Documentation/dontdiff -upr a/drivers/usb/host/ehci-q.c
b/drivers/usb/host/ehci-q.c
--- a/drivers/usb/host/ehci-q.c 2006-08-07 00:18:54.000000000 -0400
+++ b/drivers/usb/host/ehci-q.c 2006-09-26 22:17:38.000000000 -0400
@@ -269,8 +269,8 @@ __acquires(ehci->lock)
 static void start_unlink_async (struct ehci_hcd *ehci, struct ehci_qh *qh);
 static void unlink_async (struct ehci_hcd *ehci, struct ehci_qh *qh);

-static void intr_deschedule (struct ehci_hcd *ehci, struct ehci_qh *qh);
-static int qh_schedule (struct ehci_hcd *ehci, struct ehci_qh *qh);
+static void periodic_qh_deschedule (struct ehci_hcd *ehci, struct ehci_qh *qh);
+static int periodic_qh_schedule (struct ehci_hcd *ehci, struct ehci_qh *qh);

 /*
  * Process and free completed qtds for a qh, returning URBs to drivers.
@@ -430,8 +430,10 @@ halt:
                         */
                        if ((__constant_cpu_to_le32 (QH_SMASK)
                                        & qh->hw_info2) != 0) {
-                               intr_deschedule (ehci, qh);
-                               (void) qh_schedule (ehci, qh);
+
+                               periodic_qh_deschedule (ehci, qh);
+                               periodic_qh_schedule (ehci, qh);
+
                        } else
                                unlink_async (ehci, qh);
                        break;
diff -X b/Documentation/dontdiff -upr a/drivers/usb/host/ehci-sched.c
b/drivers/usb/host/ehci-sched.c
--- a/drivers/usb/host/ehci-sched.c     2006-09-26 22:17:28.000000000 -0400
+++ b/drivers/usb/host/ehci-sched.c     2006-09-26 22:17:38.000000000 -0400
@@ -67,29 +67,34 @@ periodic_next_shadow (union ehci_shadow
        }
 }

-/* caller must hold ehci->lock */
-static void periodic_unlink (struct ehci_hcd *ehci, unsigned frame, void *ptr)
+/* find position of a specific entry in the periodic schedule (ie,
+ * returns pointers such that we can update the predecessor's
+ * linkage); here->ptr == NULL indicates the find failed.
+ *
+ * @ehci: pointer to ehci host controller device structure.
+ * @frame: frame number of the shadow/hardware schedule to search
+ * @ptr: entry for which to search
+ * @hw_p: return pointer to hw_next field of preceeding entry
+ */
+static union ehci_shadow *
+periodic_find_entry(struct ehci_hcd *ehci,
+                    unsigned frame,
+                    void *ptr,
+                    __le32 **hw_p)
 {
-       union ehci_shadow       *prev_p = &ehci->pshadow [frame];
-       __le32                  *hw_p = &ehci->periodic [frame];
-       union ehci_shadow       here = *prev_p;
-
-       /* find predecessor of "ptr"; hw and shadow lists are in sync */
-       while (here.ptr && here.ptr != ptr) {
-               prev_p = periodic_next_shadow (prev_p, Q_NEXT_TYPE (*hw_p));
-               hw_p = here.hw_next;
-               here = *prev_p;
+       union ehci_shadow *here = &ehci->pshadow [frame % ehci->periodic_size];
+       __le32 type;
+       
+       *hw_p = &ehci->periodic [frame % ehci->periodic_size];
+       type = Q_NEXT_TYPE (**hw_p);
+       
+       while (here->ptr && here->ptr != ptr) {
+               *hw_p = here->hw_next;
+               here = periodic_next_shadow (here, type);
+               type = Q_NEXT_TYPE (**hw_p);
        }
-       /* an interrupt entry (at list end) could have been shared */
-       if (!here.ptr)
-               return;
-
-       /* update shadow and hardware lists ... the old "next" pointers
-        * from ptr may still be in use, the caller updates them.
-        */
-       *prev_p = *periodic_next_shadow (&here, Q_NEXT_TYPE (*hw_p));
-       *hw_p = *here.hw_next;
-}
+       return here;
+}

 /* how many of the uframe's 125 usecs are allocated? */
 static unsigned short
@@ -535,14 +540,106 @@ static int disable_periodic (struct ehci
 }

 /*-------------------------------------------------------------------------*/
+/* Periodic interrupt (QH) endpoint machinery */
+
+/* periodic_qh_unlink_frame - unlink the passed in QH from the
+ * specified frame
+ *
+ * @ehci: pointer to ehci host controller device structure
+ * @frame: frame number in shadow/hardware schedule
+ * @qh: QH to unlink
+ */
+static void periodic_qh_unlink_frame (struct ehci_hcd *ehci,
+                                     unsigned frame,
+                                     struct ehci_qh *qh)
+{
+       __le32          *hw_p;
+       union ehci_shadow *here = periodic_find_entry(ehci, frame, qh, &hw_p);
+       
+       if (here->ptr){
+
+               *hw_p = *here->hw_next;
+               *here = here->qh->qh_next;
+               wmb ();
+               
+               /*... the old "next" pointers from ptr (and if a qh, the
+                 fstns) may still be in use, the caller updates them. */       
+               
+       }
+       
+}

-/* periodic schedule slots have iso tds (normal or split) first, then a
- * sparse tree for active interrupt transfers.
+/* periodic_qh_deschedule - toplevel entry point for removing a given
+ * interrupt endpoint (rather, its QH) from the shadow/hardware
+ * schedule.
  *
- * this just links in a qh; caller guarantees uframe masks are set right.
- * no FSTN support (yet; ehci 0.96+)
+ * @ehci: pointer to ehci host controller device structure
+ * @qh: QH to remove
  */
-static int qh_link_periodic (struct ehci_hcd *ehci, struct ehci_qh *qh)
+static void periodic_qh_deschedule(struct ehci_hcd *ehci, struct ehci_qh *qh)
+{
+       unsigned        i;
+       unsigned        wait;
+
+       // FIXME:
+       // IF this isn't high speed
+       //   and this qh is active in the current uframe
+       //   (and overlay token SplitXstate is false?)
+       // THEN
+       //   qh->hw_info1 |= __constant_cpu_to_le32 (1 << 7 /* "ignore" */);
+
+       if(sched_verbose)
+               ehci_info(ehci, "Removing QH %p from schedule:\n", qh);
+
+       /* remove from hardware schedule */
+       for (i=0; i < ehci->periodic_size; i++)
+               periodic_qh_unlink_frame (ehci, i, qh);
+
+       /* update per-qh bandwidth for usbfs */
+       ehci_to_hcd(ehci)->self.bandwidth_allocated -= qh->period
+               ? ((qh->usecs + qh->c_usecs) / qh->period)
+               : (qh->usecs * 8);
+
+       dev_dbg (&qh->dev->dev,
+               "unlink qh%d-%04x/%p start %d [%d/%d us]\n",
+               qh->period,
+               le32_to_cpup (&qh->hw_info2) & (QH_CMASK | QH_SMASK),
+               qh, qh->start, qh->usecs, qh->c_usecs);
+
+       /* qh->qh_next still "live" to HC */
+       qh->qh_state = QH_STATE_UNLINK;
+       qh->qh_next.ptr = NULL;
+       qh_put (qh);
+
+       /* maybe turn off periodic schedule */
+       deref_periodic (ehci);
+
+       /* simple/paranoid:  always delay, expecting the HC needs to read
+        * qh->hw_next or finish a writeback after SPLIT/CSPLIT ... and
+        * expect khubd to clean up after any CSPLITs we won't issue.
+        * active high speed queues may need bigger delays...
+        */
+       if (list_empty (&qh->qtd_list)
+                       || (__constant_cpu_to_le32 (QH_CMASK)
+                                       & qh->hw_info2) != 0)
+               wait = 2;
+       else
+               wait = 55;      /* worst case: 3 * 1024 */
+
+       udelay (wait);
+       qh->qh_state = QH_STATE_IDLE;
+       qh->hw_next = EHCI_LIST_END;
+
+       wmb ();
+}
+
+/* periodic_qh_link - link the passed in QH into all relevant frames of the
+ * hardware schedule; assumes QH is already budgeted.
+ *
+ * @ehci: pointer to ehci host controller device structure
+ * @qh: QH to link
+ */
+static int periodic_qh_link (struct ehci_hcd *ehci, struct ehci_qh *qh)
 {
        unsigned        i;
        unsigned        period = qh->period;
@@ -604,69 +701,6 @@ static int qh_link_periodic (struct ehci
        return enable_periodic (ehci);
 }

-static void qh_unlink_periodic (struct ehci_hcd *ehci, struct ehci_qh *qh)
-{
-       unsigned        i;
-       unsigned        period;
-
-       // FIXME:
-       // IF this isn't high speed
-       //   and this qh is active in the current uframe
-       //   (and overlay token SplitXstate is false?)
-       // THEN
-       //   qh->hw_info1 |= __constant_cpu_to_le32 (1 << 7 /* "ignore" */);
-
-       /* high bandwidth, or otherwise part of every microframe */
-       if ((period = qh->period) == 0)
-               period = 1;
-
-       for (i = qh->start; i < ehci->periodic_size; i += period)
-               periodic_unlink (ehci, i, qh);
-
-       /* update per-qh bandwidth for usbfs */
-       ehci_to_hcd(ehci)->self.bandwidth_allocated -= qh->period
-               ? ((qh->usecs + qh->c_usecs) / qh->period)
-               : (qh->usecs * 8);
-
-       dev_dbg (&qh->dev->dev,
-               "unlink qh%d-%04x/%p start %d [%d/%d us]\n",
-               qh->period,
-               le32_to_cpup (&qh->hw_info2) & (QH_CMASK | QH_SMASK),
-               qh, qh->start, qh->usecs, qh->c_usecs);
-
-       /* qh->qh_next still "live" to HC */
-       qh->qh_state = QH_STATE_UNLINK;
-       qh->qh_next.ptr = NULL;
-       qh_put (qh);
-
-       /* maybe turn off periodic schedule */
-       deref_periodic (ehci);
-}
-
-static void intr_deschedule (struct ehci_hcd *ehci, struct ehci_qh *qh)
-{
-       unsigned        wait;
-
-       qh_unlink_periodic (ehci, qh);
-
-       /* simple/paranoid:  always delay, expecting the HC needs to read
-        * qh->hw_next or finish a writeback after SPLIT/CSPLIT ... and
-        * expect khubd to clean up after any CSPLITs we won't issue.
-        * active high speed queues may need bigger delays...
-        */
-       if (list_empty (&qh->qtd_list)
-                       || (__constant_cpu_to_le32 (QH_CMASK)
-                                       & qh->hw_info2) != 0)
-               wait = 2;
-       else
-               wait = 55;      /* worst case: 3 * 1024 */
-
-       udelay (wait);
-       qh->qh_state = QH_STATE_IDLE;
-       qh->hw_next = EHCI_LIST_END;
-       wmb ();
-}
-
 /*-------------------------------------------------------------------------*/

 static int check_period (
@@ -780,10 +814,7 @@ done:
        return retval;
 }

-/* "first fit" scheduling policy used the first time through,
- * or when the previous schedule slot can't be re-used.
- */
-static int qh_schedule (struct ehci_hcd *ehci, struct ehci_qh *qh)
+static int periodic_qh_schedule (struct ehci_hcd *ehci, struct ehci_qh *qh)
 {
        int             status;
        unsigned        uframe;
@@ -841,11 +872,21 @@ static int qh_schedule (struct ehci_hcd
                ehci_dbg (ehci, "reused qh %p schedule\n", qh);

        /* stuff into the periodic schedule */
-       status = qh_link_periodic (ehci, qh);
+       status = periodic_qh_link (ehci, qh);
 done:
        return status;
 }

+/* intr_submit - toplevel entry point for submitting an interrupt
+ * endpoint request.  If needed, performs initial creation, budgeting
+ * and scheduling of a QH for this endpoint.
+ *
+ * @ehci:
+ * @ep:
+ * @urb:
+ * @qtd_list:
+ * @mem_flags
+ */
 static int intr_submit (
        struct ehci_hcd         *ehci,
        struct usb_host_endpoint *ep,
@@ -878,7 +919,7 @@ static int intr_submit (
                goto done;
        }
        if (qh->qh_state == QH_STATE_IDLE) {
-               if ((status = qh_schedule (ehci, qh)) != 0)
+               if ((status = periodic_qh_schedule (ehci, qh)) != 0)
                        goto done;
        }

@@ -2196,7 +2237,7 @@ restart:
                                q = q.qh->qh_next;
                                modified = qh_completions (ehci, temp.qh, regs);
                                if (unlikely (list_empty (&temp.qh->qtd_list)))
-                                       intr_deschedule (ehci, temp.qh);
+                                       periodic_qh_deschedule (ehci, temp.qh);
                                qh_put (temp.qh);
                                break;
                        case Q_TYPE_FSTN:

-------------------------------------------------------------------------
Take Surveys. Earn Cash. Influence the Future of IT
Join SourceForge.net's Techsay panel and you'll get the chance to share your
opinions on IT & business topics through brief surveys -- and earn cash
http://www.techsay.com/default.php?page=join.php&p=sourceforge&CID=DEVDEV
_______________________________________________
linux-usb-devel@lists.sourceforge.net
To unsubscribe, use the last form field at:
https://lists.sourceforge.net/lists/listinfo/linux-usb-devel

Reply via email to