Ok here's the biggest patch... :) This adds a function "tt_available" and helper functions that determine if a particular transaction translator is "available" for a periodic transfer. This is similar to the existing "tt_no_collision" but that function simply uses the ssplit/csplit masks to prevent multiple ssplits/csplits during the same uframe, while this new function does downstream bus scheduling, i.e. using the tt_usecs from each ehci_qh or ehci_iso_stream to schedule transfers when the downstream low/full speed bus is available. This adheres to the USB 2.0 spec section 11.18.1 (figure 11-60) and section 11.18.4 requirement #4. This does allow multiple ssplits/csplits during a single uframe, up to 16 as specified by the USB 2.0 spec.
Note this only adds the function, later patches change the driver to use it and remove the tt_no_collision function. Signed-off-by: Dan Streetman <[EMAIL PROTECTED]> diff -urpN a/drivers/usb/host/ehci-sched.c b/drivers/usb/host/ehci-sched.c --- a/drivers/usb/host/ehci-sched.c 2005-08-03 12:25:25.000000000 -0400 +++ b/drivers/usb/host/ehci-sched.c 2005-08-03 12:43:41.000000000 -0400 @@ -163,6 +163,196 @@ static int same_tt (struct usb_device *d return 1; } +static const unsigned char +MAX_TT_USECS[] = { 125, 125, 125, 125, 125, 125, 30, 0 }; + +/* FIXME - can have ssplits in uframe 7 with FSTN */ +static const unsigned char +MAX_TT_SSPLIT[] = { 16, 16, 16, 16, 16, 16, 0, 0 }; + +struct tt_frame_bw { + short usecs[8]; /* used usecs per uframe */ + char ssplits[8]; /* number of ssplits per uframe */ +}; + +static void +update_tt_frame_bw (struct tt_frame_bw *bw, unsigned uf, int tt_usecs) +{ + if (!uf) { + dbg ("%s : no ssplit, is this FSTN?\n", __FUNCTION__); + return; + } + + do { + bw->usecs[uf] += tt_usecs; + tt_usecs = bw->usecs[uf] - MAX_TT_USECS[uf]; + if (0 < tt_usecs) + bw->usecs[uf] = MAX_TT_USECS[uf]; + } while ((0 < tt_usecs) && (++uf < 7)); +} + +/* how many of the tt's periodic downstream 1000 usecs are allocated? */ +static void +calc_periodic_tt_usecs ( + struct ehci_hcd *ehci, + struct usb_device *dev, + unsigned frame, + struct tt_frame_bw *bw +) +{ + union ehci_shadow here; + __le32 type; + + memset(bw, 0, sizeof(*bw)); + + here = ehci->pshadow [frame]; + type = Q_NEXT_TYPE (ehci->periodic [frame]); + while (here.ptr) { + switch (type) { + case Q_TYPE_ITD: + type = Q_NEXT_TYPE (here.itd->hw_next); + here = here.itd->itd_next; + continue; + case Q_TYPE_QH: + if (same_tt (dev, here.qh->dev)) { + unsigned uf = ffs (0x3f & + le32_to_cpu (here.qh->hw_info2)); + + /* the ssplit is 1 uframe before the + * tt downstream transfer + */ + if (uf) + bw->ssplits[uf-1]++; + + update_tt_frame_bw (bw, uf, + here.qh->tt_usecs); + } + type = Q_NEXT_TYPE (here.qh->hw_next); + here = here.qh->qh_next; + continue; + case Q_TYPE_SITD: + if (same_tt (dev, here.sitd->urb->dev)) { + int i; + long smask = le32_to_cpu (here.sitd->hw_uframe); + unsigned uf = ffs (0x3f & smask); + + /* isoc out can have multiple ssplits, + * each ssplit 1 uframe before its + * tt downstream transfer + */ + for (i=0; i<8; i++) + if (test_bit(i, &smask)) + bw->ssplits[i]++; + + update_tt_frame_bw (bw, uf, + here.sitd->stream->tt_usecs); + } + type = Q_NEXT_TYPE (here.sitd->hw_next); + here = here.sitd->sitd_next; + continue; + // case Q_TYPE_FSTN: + default: + ehci_dbg (ehci, + "ignoring periodic frame %d bogus type %d\n", + frame, type); + } + } +} + +/* return true if the device's tt's downstream bus is available + * for a periodic transfer starting at the specified frame/uframe. + * Note that the uframe parameter is when the downstream transfer + * should be executed, which is 1 uframe after the ssplit. + * This checks 2 things: + * 1) if the bus, at the specified starting uframe, + * has the specified bandwidth (max 125 us). + * note no periodic xfers allowed in uframe 7, + * and the max bw in uframe 6 is only (approx calc) ~30 us. + * (USB 2.0 spec section 11.18.1 fig 11-60) + * 2) if the transfer would exceed the max ssplit limit of 16 + * (USB 2.0 spec section 11.18.4 requirement #4). + */ +static int tt_available ( + struct ehci_hcd *ehci, + unsigned period, + struct usb_device *dev, + unsigned frame, + unsigned uframe, + u16 tt_usecs +) +{ + if ((period == 0) || (uframe >= 7)) /* error */ + return 0; + + /* not yet supported : FSTN (ssplit in uframe 7) */ + if (uframe == 0) + return 0; + + for (; frame < ehci->periodic_size; frame += period) { + struct tt_frame_bw bw; + int i; + + calc_periodic_tt_usecs (ehci, dev, frame, &bw); + + ehci_vdbg (ehci, "tt frame %d check %d usecs start uframe %d in" + " schedule %d/%d/%d/%d/%d/%d/%d/%d\n", + frame, tt_usecs, uframe, + bw.usecs[0], bw.usecs[1], bw.usecs[2], bw.usecs[3], + bw.usecs[4], bw.usecs[5], bw.usecs[6], bw.usecs[7]); + + /* reject if desired uframe is already 100% scheduled */ + if (MAX_TT_USECS[uframe] <= bw.usecs[uframe]) { + ehci_dbg (ehci, "frame %d uframe %d fully scheduled\n", + frame, uframe); + return 0; + } + + /* special case for isoc transfers larger than 125us: + * the first and each subsequent fully used uframe + * must be empty, so as to not illegally delay + * already scheduled transactions + */ + if (125 < tt_usecs) { + int ufs = tt_usecs / 125; + for (i = uframe; i < (uframe + ufs) && i < 8; i++) + if (0 < bw.usecs[i]) { + ehci_dbg(ehci, "Isoc transfer would " + "delay existing transfer in " + "frame %d uframe %d\n", + frame, uframe); + return 0; + } + } + + update_tt_frame_bw (&bw, uframe, tt_usecs); + + /* overscheduled if any bw has rolled over into uframe 7 */ + if (bw.usecs[7]) { + ehci_dbg (ehci, + "tt does not have %d usecs available " + "in frame %d uframe %d\n", + tt_usecs, frame, uframe); + return 0; + } + + /* no uframe can have more than MAX_TT_SSPLIT ssplits */ + for (i = 0; i < 8; i++) + if (MAX_TT_SSPLIT[i] < bw.ssplits[i]) { + ehci_dbg (ehci, + "tt max ssplit in frame %d uframe %d\n", + frame, uframe); + return 0; + } + } + + /* tt's downstream bus has available bw */ + ehci_dbg (ehci, + "tt available for %d usec transfer starting " + "in frame %d uframe %d every %d frames\n", + tt_usecs, frame % period, uframe, period); + return 1; +} + /* return true iff the device's transaction translator is available * for a periodic transfer starting at the specified frame, using * all the uframes in the mask. ------------------------------------------------------- SF.Net email is Sponsored by the Better Software Conference & EXPO September 19-22, 2005 * San Francisco, CA * Development Lifecycle Practices Agile & Plan-Driven Development * Managing Projects & Teams * Testing & QA Security * Process Improvement & Measurement * http://www.sqe.com/bsce5sf _______________________________________________ linux-usb-devel@lists.sourceforge.net To unsubscribe, use the last form field at: https://lists.sourceforge.net/lists/listinfo/linux-usb-devel