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
_______________________________________________
[email protected]
To unsubscribe, use the last form field at:
https://lists.sourceforge.net/lists/listinfo/linux-usb-devel