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

patch 9:

Standardize/unify 'period' and 'interval' values on uFrame granularity
instead of mixing frame and uframe depending on endpoint type (there's
no reason to use urb->interval directly).

Implement QH tree depth limit such that the lowest level of the QH
tree can be smaller than the width of the full periodic schedule;
useful for saving memory upon implementation of save-state FSTNs.

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

---

diff -X b/Documentation/dontdiff -upr a/drivers/usb/host/ehci.h
b/drivers/usb/host/ehci.h
--- a/drivers/usb/host/ehci.h   2006-09-26 22:17:28.000000000 -0400
+++ b/drivers/usb/host/ehci.h   2006-09-26 22:28:17.000000000 -0400
@@ -385,6 +385,11 @@ union ehci_shadow {
  * These appear in both the async and (for interrupt) periodic schedules.
  */

+/* as per ehci spec guidelines, replicate QH tree linkage of a maximum
+   size that is less than the full periodic schedule size. This is
+   also necessary to limit memory usage of FSTN support. */
+#define PERIODIC_QH_MAX_PERIOD 256 // 32 frames * 8 uFrames/Frame
+
 struct ehci_qh {
        /* first part defined by EHCI spec */
        __le32                  hw_next;         /* see EHCI 3.6.1 */
@@ -485,10 +490,9 @@ struct ehci_iso_stream {
         * trusting urb->interval == f(epdesc->bInterval) and
         * including the extra info for hw_bufp[0..2]
         */
-       u8                      interval;
+       u16                     interval;
        u8                      usecs, c_usecs;
        u16                     tt_usecs;
-       u16                     maxp;
        u16                     raw_mask;
        unsigned                bandwidth;

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-09-26 22:19:16.000000000 -0400
+++ b/drivers/usb/host/ehci-q.c 2006-09-26 22:28:17.000000000 -0400
@@ -667,17 +667,19 @@ qh_make (
                if (urb->dev->speed == USB_SPEED_HIGH) {
                        qh->c_usecs = 0;
                        qh->gap_uf = 0;
-
-                       qh->period = urb->interval >> 3;
-                       if (qh->period == 0 && urb->interval != 1) {
+                       qh->period = urb->interval; /* uFrame */
+                       
+                       /* XXX: remove once new budgeting code */
+                        if (urb->interval<8 && urb->interval != 1) {
                                /* NOTE interval 2 or 4 uframes could work.
                                 * But interval 1 scheduling is simpler, and
                                 * includes high bandwidth.
                                 */
-                               dbg ("intr period %d uframes, NYET!",
-                                               urb->interval);
-                               goto done;
-                       }
+                                dbg ("intr period %d uframes, NYET!",
+                                    urb->interval);
+                                goto done;
+                        }
+                       
                } else {
                        struct usb_tt   *tt = urb->dev->tt;
                        int             think_time;
@@ -699,7 +701,7 @@ qh_make (
                        qh->tt_usecs = NS_TO_US (think_time +
                                        usb_calc_bus_time (urb->dev->speed,
                                        is_input, 0, max_packet (maxp)));
-                       qh->period = urb->interval;
+                       qh->period = urb->interval << 3; /* uFrame */
                }
        }

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:28:06.000000000 -0400
+++ b/drivers/usb/host/ehci-sched.c     2006-09-26 22:28:17.000000000 -0400
@@ -96,6 +96,19 @@ periodic_find_entry(struct ehci_hcd *ehc
        return here;
 }

+/* covert a QH's period [expressed in uFrames] to tree level.
+ *
+ * @period: period (uFrames) of a QH
+ */
+static int _period_to_level(int period)
+{
+       if(period<8)return 1;
+       if(period > PERIODIC_QH_MAX_PERIOD){
+               return (PERIODIC_QH_MAX_PERIOD >> 3);
+       }
+       return period>>3;
+}
+
 /* how many of the uframe's 125 usecs are allocated? */
 static unsigned short
 periodic_usecs (struct ehci_hcd *ehci, unsigned frame, unsigned uframe)
@@ -596,9 +609,8 @@ static void periodic_qh_deschedule(struc
                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);
+       ehci_to_hcd(ehci)->self.bandwidth_allocated -=
+               (qh->usecs + qh->c_usecs) / qh->period;

        dev_dbg (&qh->dev->dev,
                "unlink qh%d-%04x/%p start %d [%d/%d us]\n",
@@ -642,17 +654,13 @@ static void periodic_qh_deschedule(struc
 static int periodic_qh_link (struct ehci_hcd *ehci, struct ehci_qh *qh)
 {
        unsigned        i;
-       unsigned        period = qh->period;
+       unsigned        period = _period_to_level(qh->period);

        dev_dbg (&qh->dev->dev,
                "link qh%d-%04x/%p start %d [%d/%d us]\n",
                period, le32_to_cpup (&qh->hw_info2) & (QH_CMASK | QH_SMASK),
                qh, qh->start, qh->usecs, qh->c_usecs);

-       /* high bandwidth, or otherwise every microframe */
-       if (period == 0)
-               period = 1;
-
        for (i = qh->start; i < ehci->periodic_size; i += period) {
                union ehci_shadow       *prev = &ehci->pshadow [i];
                __le32                  *hw_p = &ehci->periodic [i];
@@ -673,7 +681,7 @@ static int periodic_qh_link (struct ehci
                 * enables sharing interior tree nodes
                 */
                while (here.ptr && qh != here.qh) {
-                       if (qh->period > here.qh->period)
+                       if (period > _period_to_level(here.qh->period))
                                break;
                        prev = &here.qh->qh_next;
                        hw_p = &here.qh->hw_next;
@@ -693,9 +701,8 @@ static int periodic_qh_link (struct ehci
        qh_get (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);
+       ehci_to_hcd(ehci)->self.bandwidth_allocated +=
+               (qh->usecs + qh->c_usecs) / qh->period;

        /* maybe enable periodic schedule processing */
        return enable_periodic (ehci);
@@ -711,7 +718,8 @@ static int check_period (
        unsigned        usecs
 ) {
        int             claimed;
-
+       int             level = _period_to_level(period);
+
        /* complete split running into next frame?
         * given FSTN support, we could sometimes check...
         */
@@ -725,9 +733,9 @@ static int check_period (
        usecs = 100 - usecs;

        /* we "know" 2 and 4 uframe intervals were rejected; so
-        * for period 0, check _every_ microframe in the schedule.
+        * for period 1, check _every_ microframe in the schedule.
         */
-       if (unlikely (period == 0)) {
+       if (unlikely (period == 1)) {
                do {
                        for (uframe = 0; uframe < 7; uframe++) {
                                claimed = periodic_usecs (ehci, frame, uframe);
@@ -742,7 +750,7 @@ static int check_period (
                        claimed = periodic_usecs (ehci, frame, uframe);
                        if (claimed > usecs)
                                return 0;
-               } while ((frame += period) < ehci->periodic_size);
+               } while ((frame += level) < ehci->periodic_size);
        }

        // success!
@@ -772,8 +780,8 @@ static int check_intr_schedule (
        }

 #ifdef CONFIG_USB_EHCI_TT_NEWSCHED
-       if (tt_available (ehci, qh->period, qh->dev, frame, uframe,
-                               qh->tt_usecs)) {
+       if (tt_available (ehci, _period_to_level(qh->period),
+                         qh->dev, frame, uframe, qh->tt_usecs)) {
                unsigned i;

                /* TODO : this may need FSTN for SSPLIT in uframe 5. */
@@ -820,13 +828,14 @@ static int periodic_qh_schedule (struct
        unsigned        uframe;
        __le32          c_mask;
        unsigned        frame;          /* 0..(qh->period - 1), or NO_FRAME */
+       int period = _period_to_level(qh->period);

        qh_refresh(ehci, qh);
        qh->hw_next = EHCI_LIST_END;
        frame = qh->start;

        /* reuse the previous schedule slots, if we can */
-       if (frame < qh->period) {
+       if (frame < period) {
                uframe = ffs (le32_to_cpup (&qh->hw_info2) & QH_SMASK);
                status = check_intr_schedule (ehci, frame, --uframe,
                                qh, &c_mask);
@@ -841,8 +850,8 @@ static int periodic_qh_schedule (struct
         */
        if (status) {
                /* "normal" case, uframing flexible except with splits */
-               if (qh->period) {
-                       frame = qh->period - 1;
+               if (qh->period > 1) {
+                       frame = period - 1;
                        do {
                                for (uframe = 0; uframe < 8; uframe++) {
                                        status = check_intr_schedule (ehci,
@@ -853,7 +862,7 @@ static int periodic_qh_schedule (struct
                                }
                        } while (status && frame--);

-               /* qh->period == 0 means every uframe */
+               /* qh->period == 1 means every uframe */
                } else {
                        frame = 0;
                        status = check_intr_schedule (ehci, 0, 0, qh, &c_mask);
@@ -864,7 +873,7 @@ static int periodic_qh_schedule (struct

                /* reset S-frame and (maybe) C-frame masks */
                qh->hw_info2 &= __constant_cpu_to_le32(~(QH_CMASK | QH_SMASK));
-               qh->hw_info2 |= qh->period
+               qh->hw_info2 |= (qh->period>1)
                        ? cpu_to_le32 (1 << uframe)
                        : __constant_cpu_to_le32 (QH_SMASK);
                qh->hw_info2 |= c_mask;
@@ -1048,6 +1057,7 @@ iso_stream_init (
                 * when transfers on this endpoint are scheduled ...
                 */
                stream->usecs = HS_USECS_ISO (maxp);
+               stream->interval = interval;
                bandwidth = stream->usecs * 8;
                bandwidth /= 1 << (interval - 1);

@@ -1086,14 +1096,12 @@ iso_stream_init (

                /* stream->splits gets created from raw_mask later */
                stream->address = cpu_to_le32 (addr);
+               stream->interval = interval<<3;
        }
-       stream->bandwidth = bandwidth;

+       stream->bandwidth = bandwidth;
        stream->udev = dev;
-
        stream->bEndpointAddress = is_input | epnum;
-       stream->interval = interval;
-       stream->maxp = maxp;
 }

 /* iso_stream_put - decrement refcount of passed in ehci_iso_stream
@@ -1286,14 +1294,15 @@ sitd_slot_ok (
                /* The tt's fullspeed bus bandwidth must be available.
                 * tt_available scheduling guarantees 10+% for control/bulk.
                 */
-               if (!tt_available (ehci, period_uframes << 3,
+               /* period_uframes << 3 had always been wrong */
+               if (!tt_available (ehci, period_uframes >> 3,
                                stream->udev, frame, uf, stream->tt_usecs))
                        return 0;
 #else
                /* tt must be idle for start(s), any gap, and csplit.
                 * assume scheduling slop leaves 10+% for control/bulk.
                 */
-               if (!tt_no_collision (ehci, period_uframes << 3,
+               if (!tt_no_collision (ehci, period_uframes >> 3,
                                stream->udev, frame, mask))
                        return 0;
 #endif
@@ -1413,10 +1422,7 @@ static int iso_stream_schedule (
        stream->next_uframe = start;

        /* NOTE:  assumes URB_ISO_ASAP, to limit complexity/bugs */
-
-       period = urb->interval;
-       if (!stream->highspeed)
-               period <<= 3;
+       period = stream->interval;

        /* find a uframe slot with enough bandwidth */
        for (; start < (stream->next_uframe + period); start++) {
@@ -2130,8 +2136,8 @@ sitd_link_urb (
        for (packet = 0; packet < urb->number_of_packets; packet++) {
          sitd_link (ehci, urb, ((next_uframe & (mod-1)) >> 3),
                     stream, sched, packet);
-               next_uframe += stream->interval << 3;
-               stream->depth += stream->interval << 3;
+               next_uframe += stream->interval;
+               stream->depth += stream->interval;
        }
        
        stream->next_uframe = next_uframe % mod;
@@ -2194,7 +2200,7 @@ sitd_complete (
        sitd->urb = NULL;
        sitd->stream = NULL;
        list_move (&sitd->sitd_list, &stream->free_list);
-       stream->depth -= stream->interval << 3;
+       stream->depth -= stream->interval;
        iso_stream_put (ehci, stream);

        /* handle completion now? */
@@ -2247,9 +2253,9 @@ static int sitd_submit (struct ehci_hcd
                ehci_dbg (ehci, "can't get iso stream\n");
                return -ENOMEM;
        }
-       if (urb->interval != stream->interval) {
+       if (urb->interval != ((stream->interval+7)>>3)) {
                ehci_dbg (ehci, "can't change iso interval %d --> %d\n",
-                       stream->interval, urb->interval);
+                        ((stream->interval+7)>>3), urb->interval);
                goto done;
        }

-------------------------------------------------------------------------
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