From xiphmont@gmail.com Thu Sep 28 00:24:05 2006 Message-ID: <806dafc20609280024ied01f82j8f46981aafebc409@mail.gmail.com> Date: Thu, 28 Sep 2006 03:24:04 -0400 From: "Christopher \"Monty\" Montgomery" To: linux-usb-devel@lists.sourceforge.net Subject: [PATCH 11/15] USB: ehci-hcd: activate shadow budget tracking Cc: greg@kroah.com, david-b@pacbell.net, xiphmont@gmail.com Content-Disposition: inline patch 11: adds necessary calls such that the shadow budget is actively maintained, but the rest of the scheduler is not yet using the shadow budget to make any decisions. Signed-off-by: Christopher "Monty" Montgomery Cc: David Brownell Signed-off-by: Greg Kroah-Hartman --- drivers/usb/host/ehci-hcd.c | 2 + drivers/usb/host/ehci-mem.c | 9 +++++ drivers/usb/host/ehci-q.c | 18 +++++++++- drivers/usb/host/ehci-sched.c | 73 +++++++++++++++++++++++++++++++++++++++--- 4 files changed, 95 insertions(+), 7 deletions(-) --- gregkh-2.6.orig/drivers/usb/host/ehci-hcd.c +++ gregkh-2.6/drivers/usb/host/ehci-hcd.c @@ -260,6 +260,8 @@ static void ehci_quiesce (struct ehci_hc /*-------------------------------------------------------------------------*/ static void ehci_work(struct ehci_hcd *ehci); +static void budget_unlink_entries_by_owner(struct ehci_hcd *ehci,void *owner); +static unsigned sched_verbose = 0; #include "ehci-hub.c" #include "ehci-mem.c" --- gregkh-2.6.orig/drivers/usb/host/ehci-mem.c +++ gregkh-2.6/drivers/usb/host/ehci-mem.c @@ -73,6 +73,15 @@ static void qh_destroy (struct kref *kre ehci_dbg (ehci, "unused qh not empty!\n"); BUG (); } + + /* remove from shadow budget */ + if(sched_verbose) + ehci_info(ehci, "Removing QH %p from budget:\n", qh); + + if(qh->budget) + budget_unlink_entries_by_owner(ehci,qh); + qh->budget = NULL; + if (qh->dummy) ehci_qtd_free (ehci, qh->dummy); dma_pool_free (ehci->qh_pool, qh, qh->qh_dma); --- gregkh-2.6.orig/drivers/usb/host/ehci-q.c +++ gregkh-2.6/drivers/usb/host/ehci-q.c @@ -682,7 +682,22 @@ qh_make ( } else { struct usb_tt *tt = urb->dev->tt; - int think_time; + int think_time, think_bytes; + + think_time = tt ? tt->think_time : 0; + think_bytes = (think_time+665)/666; + + if(urb->dev->speed == USB_SPEED_FULL) + /* full speed bytes + + think time [TT host delay] + + FS non-iso protocol overhead */ + qh->tt_bytes = think_bytes + maxp + 14; + else + /* low speed bytes + + think time [TT host delay] + + low speed protocol overhead */ + /* expressed in full speed bytes */ + qh->tt_bytes = think_bytes + maxp*8 + 98; /* gap is f(FS/LS transfer times) */ qh->gap_uf = 1 + usb_calc_bus_time (urb->dev->speed, @@ -697,7 +712,6 @@ qh_make ( qh->c_usecs = HS_USECS (0); } - think_time = tt ? tt->think_time : 0; qh->tt_usecs = NS_TO_US (think_time + usb_calc_bus_time (urb->dev->speed, is_input, 0, max_packet (maxp))); --- gregkh-2.6.orig/drivers/usb/host/ehci-sched.c +++ gregkh-2.6/drivers/usb/host/ehci-sched.c @@ -104,7 +104,6 @@ /* enable/disable shedule-specific debugging output */ -static unsigned sched_verbose = 0; module_param (sched_verbose, uint, S_IRUGO); MODULE_PARM_DESC (sched_verbose, "schedule verbose: dump additional scheduling-specific " @@ -1938,6 +1937,15 @@ static int periodic_qh_schedule (struct qh->hw_next = EHCI_LIST_END; frame = qh->start; + /* budget the qh if not already budgeted */ + if(!qh->budget){ + + status = budget_add_endpoint (ehci, qh, BUDGET_TYPE_QH, + qh->period); + if(status) + return status; + } + /* reuse the previous schedule slots, if we can */ if (frame < period) { uframe = ffs (le32_to_cpup (&qh->hw_info2) & QH_SMASK); @@ -1987,6 +1995,10 @@ static int periodic_qh_schedule (struct /* stuff into the periodic schedule */ status = periodic_qh_link (ehci, qh); done: + if(status){ + budget_unlink_entries_by_owner(ehci,qh); + qh->budget = NULL; + } return status; } @@ -2167,7 +2179,7 @@ iso_stream_init ( } else { u32 addr; - int think_time; + int think_time, think_bytes; int hs_transfers; addr = dev->ttport << 24; @@ -2178,23 +2190,60 @@ iso_stream_init ( addr |= epnum << 8; addr |= dev->devnum; stream->usecs = HS_USECS_ISO (maxp); + think_time = dev->tt ? dev->tt->think_time : 0; + think_bytes = (think_time+665)/666; + stream->tt_usecs = NS_TO_US (think_time + usb_calc_bus_time ( dev->speed, is_input, 1, maxp)); hs_transfers = max (1u, (maxp + 187) / 188); + if (is_input) { u32 tmp; addr |= 1 << 31; - stream->c_usecs = stream->usecs; + + stream->c_usecs = stream->usecs + HS_USECS_ISO (1); stream->usecs = HS_USECS_ISO (1); + + if(dev->speed == USB_SPEED_FULL){ + /* full speed bytes + think time [TT + * host delay] + FS non-iso protocol + * overhead */ + stream->tt_bytes = think_bytes + maxp + 11; + }else{ + /* low speed bytes + think time [TT + * host delay] + low speed protocol + * overhead */ + /* expressed in full speed bytes */ + stream->tt_bytes = think_bytes + maxp*8 + 98; + } + stream->raw_mask = 1; /* c-mask as specified in USB 2.0 11.18.4 3.c */ tmp = (1 << (hs_transfers + 2)) - 1; stream->raw_mask |= tmp << (8 + 2); - } else + } else { + /* out */ + + stream->usecs += HS_USECS_ISO (1); + + if(dev->speed == USB_SPEED_FULL){ + /* full speed bytes + think time [TT + * host delay] + FS non-iso protocol + * overhead */ + stream->tt_bytes = think_bytes + maxp + 10; + }else{ + /* low speed bytes + think time [TT + * host delay] + low speed protocol + * overhead */ + /* expressed in full speed bytes */ + stream->tt_bytes = think_bytes + maxp*8 + 98; + } + stream->raw_mask = smask_out [hs_transfers - 1]; + } bandwidth = stream->usecs + stream->c_usecs; bandwidth /= 1 << (interval + 2); @@ -2268,6 +2317,13 @@ iso_stream_put(struct ehci_hcd *ehci, st ); } + /* eliminate this stream from the shadow budget */ + if(sched_verbose) + ehci_info(ehci, "Releasing bandwidth for ISO %p\n", + stream); + budget_unlink_entries_by_owner(ehci,stream); + stream->budget_state = 0; + /* potentially shut off periodic schedule */ deref_periodic(ehci); @@ -2486,9 +2542,16 @@ static int iso_stream_schedule ( goto fail; } - /* first scheduling attempt? */ + /* has this endpoint already been submitted into the shadow budget? */ if(!stream->budget_state){ + /* no, budget this endpoint */ + + status = budget_add_endpoint(ehci, stream, BUDGET_TYPE_ITD, + stream->interval); + + if(status)goto fail; + /* potentially turn on the periodic hardware */ status=enable_periodic (ehci); if(status)goto fail;