This patch begins the process of unifying the scheduling parameters
that ehci-hcd uses for interrupt and isochronous transfers. It
creates an ehci_per_sched structure, which will be stored in both
ehci_qh and ehci_iso_stream structures, and will contain the common
scheduling information needed for both.
Initially we merely create the new structure and move some existing
fields into it. Later patches will add more fields and utilize these
structures in improved scheduling algorithms.
Signed-off-by: Alan Stern <stern@rowland.harvard.edu>
Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
case Q_TYPE_QH:
hw = p.qh->hw;
temp = scnprintf (next, size, " qh%d-%04x/%p",
case Q_TYPE_QH:
hw = p.qh->hw;
temp = scnprintf (next, size, " qh%d-%04x/%p",
hc32_to_cpup(ehci,
&hw->hw_info2)
/* uframe masks */
hc32_to_cpup(ehci,
&hw->hw_info2)
/* uframe masks */
speed_char (scratch),
scratch & 0x007f,
(scratch >> 8) & 0x000f, type,
speed_char (scratch),
scratch & 0x007f,
(scratch >> 8) & 0x000f, type,
- p.qh->usecs, p.qh->c_usecs,
+ p.qh->ps.usecs,
+ p.qh->ps.c_usecs,
temp,
0x7ff & (scratch >> 16));
temp,
0x7ff & (scratch >> 16));
case Q_TYPE_SITD:
temp = scnprintf (next, size,
" sitd%d-%04x/%p",
case Q_TYPE_SITD:
temp = scnprintf (next, size,
" sitd%d-%04x/%p",
- p.sitd->stream->interval,
+ p.sitd->stream->ps.period,
hc32_to_cpup(ehci, &p.sitd->hw_uframe)
& 0x0000ffff,
p.sitd);
hc32_to_cpup(ehci, &p.sitd->hw_uframe)
& 0x0000ffff,
p.sitd);
* while the QH is active. Unlink it now;
* re-linking will call qh_refresh().
*/
* while the QH is active. Unlink it now;
* re-linking will call qh_refresh().
*/
- usb_settoggle(qh->dev, epnum, is_out, 0);
+ usb_settoggle(qh->ps.udev, epnum, is_out, 0);
qh->exception = 1;
if (eptype == USB_ENDPOINT_XFER_BULK)
start_unlink_async(ehci, qh);
qh->exception = 1;
if (eptype == USB_ENDPOINT_XFER_BULK)
start_unlink_async(ehci, qh);
is_out = qh->is_out;
epnum = (hc32_to_cpup(ehci, &hw->hw_info1) >> 8) & 0x0f;
is_out = qh->is_out;
epnum = (hc32_to_cpup(ehci, &hw->hw_info1) >> 8) & 0x0f;
- if (unlikely (!usb_gettoggle (qh->dev, epnum, is_out))) {
+ if (unlikely(!usb_gettoggle(qh->ps.udev, epnum, is_out))) {
hw->hw_token &= ~cpu_to_hc32(ehci, QTD_TOGGLE);
hw->hw_token &= ~cpu_to_hc32(ehci, QTD_TOGGLE);
- usb_settoggle (qh->dev, epnum, is_out, 1);
+ usb_settoggle(qh->ps.udev, epnum, is_out, 1);
* For control/bulk requests, the HC or TT handles these.
*/
if (type == PIPE_INTERRUPT) {
* For control/bulk requests, the HC or TT handles these.
*/
if (type == PIPE_INTERRUPT) {
- qh->usecs = NS_TO_US(usb_calc_bus_time(USB_SPEED_HIGH,
+ qh->ps.usecs = NS_TO_US(usb_calc_bus_time(USB_SPEED_HIGH,
is_input, 0,
hb_mult(maxp) * max_packet(maxp)));
is_input, 0,
hb_mult(maxp) * max_packet(maxp)));
+ qh->ps.phase = NO_FRAME;
if (urb->dev->speed == USB_SPEED_HIGH) {
if (urb->dev->speed == USB_SPEED_HIGH) {
- qh->period = urb->interval >> 3;
- if (qh->period == 0 && urb->interval != 1) {
+ if (urb->interval > 1 && urb->interval < 8) {
/* NOTE interval 2 or 4 uframes could work.
* But interval 1 scheduling is simpler, and
* includes high bandwidth.
*/
urb->interval = 1;
/* NOTE interval 2 or 4 uframes could work.
* But interval 1 scheduling is simpler, and
* includes high bandwidth.
*/
urb->interval = 1;
- } else if (qh->period > ehci->periodic_size) {
- qh->period = ehci->periodic_size;
- urb->interval = qh->period << 3;
+ } else if (urb->interval > ehci->periodic_size << 3) {
+ urb->interval = ehci->periodic_size << 3;
+ qh->ps.period = urb->interval >> 3;
/* FIXME this just approximates SPLIT/CSPLIT times */
if (is_input) { // SPLIT, gap, CSPLIT+DATA
/* FIXME this just approximates SPLIT/CSPLIT times */
if (is_input) { // SPLIT, gap, CSPLIT+DATA
- qh->c_usecs = qh->usecs + HS_USECS (0);
- qh->usecs = HS_USECS (1);
+ qh->ps.c_usecs = qh->ps.usecs + HS_USECS(0);
+ qh->ps.usecs = HS_USECS(1);
} else { // SPLIT+DATA, gap, CSPLIT
} else { // SPLIT+DATA, gap, CSPLIT
- qh->usecs += HS_USECS (1);
- qh->c_usecs = HS_USECS (0);
+ qh->ps.usecs += HS_USECS(1);
+ qh->ps.c_usecs = HS_USECS(0);
}
think_time = tt ? tt->think_time : 0;
}
think_time = tt ? tt->think_time : 0;
- qh->tt_usecs = NS_TO_US (think_time +
+ qh->ps.tt_usecs = NS_TO_US(think_time +
usb_calc_bus_time (urb->dev->speed,
is_input, 0, max_packet (maxp)));
usb_calc_bus_time (urb->dev->speed,
is_input, 0, max_packet (maxp)));
- qh->period = urb->interval;
- if (qh->period > ehci->periodic_size) {
- qh->period = ehci->periodic_size;
- urb->interval = qh->period;
- }
+ if (urb->interval > ehci->periodic_size)
+ urb->interval = ehci->periodic_size;
+ qh->ps.period = urb->interval;
}
}
/* support for tt scheduling, and access to toggles */
}
}
/* support for tt scheduling, and access to toggles */
+ qh->ps.udev = urb->dev;
+ qh->ps.ep = urb->ep;
/* using TT? */
switch (urb->dev->speed) {
/* using TT? */
switch (urb->dev->speed) {
hw = q->qh->hw;
/* is it in the S-mask? */
if (hw->hw_info2 & cpu_to_hc32(ehci, 1 << uframe))
hw = q->qh->hw;
/* is it in the S-mask? */
if (hw->hw_info2 & cpu_to_hc32(ehci, 1 << uframe))
+ usecs += q->qh->ps.usecs;
/* ... or C-mask? */
if (hw->hw_info2 & cpu_to_hc32(ehci,
1 << (8 + uframe)))
/* ... or C-mask? */
if (hw->hw_info2 & cpu_to_hc32(ehci,
1 << (8 + uframe)))
- usecs += q->qh->c_usecs;
+ usecs += q->qh->ps.c_usecs;
hw_p = &hw->hw_next;
q = &q->qh->qh_next;
break;
hw_p = &hw->hw_next;
q = &q->qh->qh_next;
break;
break;
case Q_TYPE_ITD:
if (q->itd->hw_transaction[uframe])
break;
case Q_TYPE_ITD:
if (q->itd->hw_transaction[uframe])
- usecs += q->itd->stream->usecs;
+ usecs += q->itd->stream->ps.usecs;
hw_p = &q->itd->hw_next;
q = &q->itd->itd_next;
break;
hw_p = &q->itd->hw_next;
q = &q->itd->itd_next;
break;
1 << uframe)) {
if (q->sitd->hw_fullspeed_ep &
cpu_to_hc32(ehci, 1<<31))
1 << uframe)) {
if (q->sitd->hw_fullspeed_ep &
cpu_to_hc32(ehci, 1<<31))
- usecs += q->sitd->stream->usecs;
+ usecs += q->sitd->stream->ps.usecs;
else /* worst case for OUT start-split */
usecs += HS_USECS_ISO (188);
}
else /* worst case for OUT start-split */
usecs += HS_USECS_ISO (188);
}
if (q->sitd->hw_uframe &
cpu_to_hc32(ehci, 1 << (8 + uframe))) {
/* worst case for IN complete-split */
if (q->sitd->hw_uframe &
cpu_to_hc32(ehci, 1 << (8 + uframe))) {
/* worst case for IN complete-split */
- usecs += q->sitd->stream->c_usecs;
+ usecs += q->sitd->stream->ps.c_usecs;
}
hw_p = &q->sitd->hw_next;
}
hw_p = &q->sitd->hw_next;
q = &q->itd->itd_next;
continue;
case Q_TYPE_QH:
q = &q->itd->itd_next;
continue;
case Q_TYPE_QH:
- if (same_tt(dev, q->qh->dev)) {
+ if (same_tt(dev, q->qh->ps.udev)) {
uf = tt_start_uframe(ehci, q->qh->hw->hw_info2);
uf = tt_start_uframe(ehci, q->qh->hw->hw_info2);
- tt_usecs[uf] += q->qh->tt_usecs;
+ tt_usecs[uf] += q->qh->ps.tt_usecs;
}
hw_p = &q->qh->hw->hw_next;
q = &q->qh->qh_next;
}
hw_p = &q->qh->hw->hw_next;
q = &q->qh->qh_next;
case Q_TYPE_SITD:
if (same_tt(dev, q->sitd->urb->dev)) {
uf = tt_start_uframe(ehci, q->sitd->hw_uframe);
case Q_TYPE_SITD:
if (same_tt(dev, q->sitd->urb->dev)) {
uf = tt_start_uframe(ehci, q->sitd->hw_uframe);
- tt_usecs[uf] += q->sitd->stream->tt_usecs;
+ tt_usecs[uf] += q->sitd->stream->ps.tt_usecs;
}
hw_p = &q->sitd->hw_next;
q = &q->sitd->sitd_next;
}
hw_p = &q->sitd->hw_next;
q = &q->sitd->sitd_next;
continue;
case Q_TYPE_QH:
hw = here.qh->hw;
continue;
case Q_TYPE_QH:
hw = here.qh->hw;
- if (same_tt (dev, here.qh->dev)) {
+ if (same_tt(dev, here.qh->ps.udev)) {
u32 mask;
mask = hc32_to_cpu(ehci,
u32 mask;
mask = hc32_to_cpu(ehci,
static void qh_link_periodic(struct ehci_hcd *ehci, struct ehci_qh *qh)
{
unsigned i;
static void qh_link_periodic(struct ehci_hcd *ehci, struct ehci_qh *qh)
{
unsigned i;
- unsigned period = qh->period;
+ unsigned period = qh->ps.period;
- dev_dbg (&qh->dev->dev,
+ dev_dbg(&qh->ps.udev->dev,
"link qh%d-%04x/%p start %d [%d/%d us]\n",
period, hc32_to_cpup(ehci, &qh->hw->hw_info2)
& (QH_CMASK | QH_SMASK),
"link qh%d-%04x/%p start %d [%d/%d us]\n",
period, hc32_to_cpup(ehci, &qh->hw->hw_info2)
& (QH_CMASK | QH_SMASK),
- qh, qh->start, qh->usecs, qh->c_usecs);
+ qh, qh->ps.phase, qh->ps.usecs, qh->ps.c_usecs);
/* high bandwidth, or otherwise every microframe */
if (period == 0)
period = 1;
/* high bandwidth, or otherwise every microframe */
if (period == 0)
period = 1;
- for (i = qh->start; i < ehci->periodic_size; i += period) {
+ for (i = qh->ps.phase; i < ehci->periodic_size; i += period) {
union ehci_shadow *prev = &ehci->pshadow[i];
__hc32 *hw_p = &ehci->periodic[i];
union ehci_shadow here = *prev;
union ehci_shadow *prev = &ehci->pshadow[i];
__hc32 *hw_p = &ehci->periodic[i];
union ehci_shadow here = *prev;
* enables sharing interior tree nodes
*/
while (here.ptr && qh != here.qh) {
* enables sharing interior tree nodes
*/
while (here.ptr && qh != here.qh) {
- if (qh->period > here.qh->period)
+ if (qh->ps.period > here.qh->ps.period)
break;
prev = &here.qh->qh_next;
hw_p = &here.qh->hw->hw_next;
break;
prev = &here.qh->qh_next;
hw_p = &here.qh->hw->hw_next;
qh->xacterrs = 0;
qh->exception = 0;
qh->xacterrs = 0;
qh->exception = 0;
- /* 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);
+ /* update per-qh bandwidth for debugfs */
+ ehci_to_hcd(ehci)->self.bandwidth_allocated += qh->ps.period
+ ? ((qh->ps.usecs + qh->ps.c_usecs) / qh->ps.period)
+ : (qh->ps.usecs * 8);
list_add(&qh->intr_node, &ehci->intr_qh_list);
list_add(&qh->intr_node, &ehci->intr_qh_list);
*/
/* high bandwidth, or otherwise part of every microframe */
*/
/* high bandwidth, or otherwise part of every microframe */
- if ((period = qh->period) == 0)
- period = 1;
+ period = qh->ps.period ? : 1;
- for (i = qh->start; i < ehci->periodic_size; i += period)
+ for (i = qh->ps.phase; i < ehci->periodic_size; i += period)
periodic_unlink (ehci, i, qh);
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);
+ /* update per-qh bandwidth for debugfs */
+ ehci_to_hcd(ehci)->self.bandwidth_allocated -= qh->ps.period
+ ? ((qh->ps.usecs + qh->ps.c_usecs) / qh->ps.period)
+ : (qh->ps.usecs * 8);
- dev_dbg (&qh->dev->dev,
+ dev_dbg(&qh->ps.udev->dev,
"unlink qh%d-%04x/%p start %d [%d/%d us]\n",
"unlink qh%d-%04x/%p start %d [%d/%d us]\n",
hc32_to_cpup(ehci, &qh->hw->hw_info2) & (QH_CMASK | QH_SMASK),
hc32_to_cpup(ehci, &qh->hw->hw_info2) & (QH_CMASK | QH_SMASK),
- qh, qh->start, qh->usecs, qh->c_usecs);
+ qh, qh->ps.phase, qh->ps.usecs, qh->ps.c_usecs);
/* qh->qh_next still "live" to HC */
qh->qh_state = QH_STATE_UNLINK;
/* qh->qh_next still "live" to HC */
qh->qh_state = QH_STATE_UNLINK;
int retval = -ENOSPC;
u8 mask = 0;
int retval = -ENOSPC;
u8 mask = 0;
- if (qh->c_usecs && uframe >= 6) /* FSTN territory? */
+ if (qh->ps.c_usecs && uframe >= 6) /* FSTN territory? */
- if (!check_period (ehci, frame, uframe, qh->period, qh->usecs))
+ if (!check_period(ehci, frame, uframe, qh->ps.period, qh->ps.usecs))
retval = 0;
*c_maskp = 0;
goto done;
}
#ifdef CONFIG_USB_EHCI_TT_NEWSCHED
retval = 0;
*c_maskp = 0;
goto done;
}
#ifdef CONFIG_USB_EHCI_TT_NEWSCHED
- if (tt_available (ehci, qh->period, qh->dev, frame, uframe,
- qh->tt_usecs)) {
+ if (tt_available(ehci, qh->ps.period, qh->ps.udev, frame, uframe,
+ qh->ps.tt_usecs)) {
unsigned i;
/* TODO : this may need FSTN for SSPLIT in uframe 5. */
for (i = uframe+2; i < 8 && i <= uframe+4; i++)
unsigned i;
/* TODO : this may need FSTN for SSPLIT in uframe 5. */
for (i = uframe+2; i < 8 && i <= uframe+4; i++)
- if (!check_period (ehci, frame, i,
- qh->period, qh->c_usecs))
+ if (!check_period(ehci, frame, i,
+ qh->ps.period, qh->ps.c_usecs))
goto done;
else
mask |= 1 << i;
goto done;
else
mask |= 1 << i;
*c_maskp = cpu_to_hc32(ehci, mask << 8);
mask |= 1 << uframe;
*c_maskp = cpu_to_hc32(ehci, mask << 8);
mask |= 1 << uframe;
- if (tt_no_collision (ehci, qh->period, qh->dev, frame, mask)) {
- if (!check_period (ehci, frame, uframe + qh->gap_uf + 1,
- qh->period, qh->c_usecs))
+ if (tt_no_collision(ehci, qh->ps.period, qh->ps.udev, frame, mask)) {
+ if (!check_period(ehci, frame, uframe + qh->gap_uf + 1,
+ qh->ps.period, qh->ps.c_usecs))
- if (!check_period (ehci, frame, uframe + qh->gap_uf,
- qh->period, qh->c_usecs))
+ if (!check_period(ehci, frame, uframe + qh->gap_uf,
+ qh->ps.period, qh->ps.c_usecs))
struct ehci_qh_hw *hw = qh->hw;
hw->hw_next = EHCI_LIST_END(ehci);
struct ehci_qh_hw *hw = qh->hw;
hw->hw_next = EHCI_LIST_END(ehci);
/* reuse the previous schedule slots, if we can */
if (frame != NO_FRAME) {
/* reuse the previous schedule slots, if we can */
if (frame != NO_FRAME) {
*/
if (status) {
/* "normal" case, uframing flexible except with splits */
*/
if (status) {
/* "normal" case, uframing flexible except with splits */
- for (i = qh->period; status && i > 0; --i) {
- frame = ++ehci->random_frame % qh->period;
+ for (i = qh->ps.period; status && i > 0; --i) {
+ frame = ++ehci->random_frame % qh->ps.period;
for (uframe = 0; uframe < 8; uframe++) {
status = check_intr_schedule (ehci,
frame, uframe, qh,
for (uframe = 0; uframe < 8; uframe++) {
status = check_intr_schedule (ehci,
frame, uframe, qh,
- /* qh->period == 0 means every uframe */
+ /* qh->ps.period == 0 means every uframe */
} else {
frame = 0;
status = check_intr_schedule (ehci, 0, 0, qh, &c_mask);
}
if (status)
goto done;
} else {
frame = 0;
status = check_intr_schedule (ehci, 0, 0, qh, &c_mask);
}
if (status)
goto done;
/* reset S-frame and (maybe) C-frame masks */
hw->hw_info2 &= cpu_to_hc32(ehci, ~(QH_CMASK | QH_SMASK));
/* reset S-frame and (maybe) C-frame masks */
hw->hw_info2 &= cpu_to_hc32(ehci, ~(QH_CMASK | QH_SMASK));
- hw->hw_info2 |= qh->period
+ hw->hw_info2 |= qh->ps.period
? cpu_to_hc32(ehci, 1 << uframe)
: cpu_to_hc32(ehci, QH_SMASK);
hw->hw_info2 |= c_mask;
? cpu_to_hc32(ehci, 1 << uframe)
: cpu_to_hc32(ehci, QH_SMASK);
hw->hw_info2 |= c_mask;
iso_stream_init (
struct ehci_hcd *ehci,
struct ehci_iso_stream *stream,
iso_stream_init (
struct ehci_hcd *ehci,
struct ehci_iso_stream *stream,
- struct usb_device *dev,
- int pipe,
- unsigned interval
)
{
static const u8 smask_out [] = { 0x01, 0x03, 0x07, 0x0f, 0x1f, 0x3f };
)
{
static const u8 smask_out [] = { 0x01, 0x03, 0x07, 0x0f, 0x1f, 0x3f };
+ struct usb_device *dev = urb->dev;
+ unsigned interval = urb->interval;
u32 buf1;
unsigned epnum, maxp;
int is_input;
u32 buf1;
unsigned epnum, maxp;
int is_input;
/*
* this might be a "high bandwidth" highspeed endpoint,
* as encoded in the ep descriptor's wMaxPacket field
*/
/*
* this might be a "high bandwidth" highspeed endpoint,
* as encoded in the ep descriptor's wMaxPacket field
*/
- epnum = usb_pipeendpoint (pipe);
- is_input = usb_pipein (pipe) ? USB_DIR_IN : 0;
- maxp = usb_maxpacket(dev, pipe, !is_input);
+ epnum = usb_pipeendpoint(urb->pipe);
+ is_input = usb_pipein(urb->pipe) ? USB_DIR_IN : 0;
+ maxp = usb_endpoint_maxp(&urb->ep->desc);
if (is_input) {
buf1 = (1 << 11);
} else {
if (is_input) {
buf1 = (1 << 11);
} else {
/* usbfs wants to report the average usecs per frame tied up
* when transfers on this endpoint are scheduled ...
*/
/* usbfs wants to report the average usecs per frame tied up
* when transfers on this endpoint are scheduled ...
*/
- stream->usecs = HS_USECS_ISO (maxp);
- bandwidth = stream->usecs * 8;
- bandwidth /= interval;
+ stream->ps.usecs = HS_USECS_ISO(maxp);
+
+ stream->bandwidth = stream->ps.usecs * 8 / interval;
+ stream->uperiod = interval;
+ stream->ps.period = interval >> 3;
addr |= dev->tt->hub->devnum << 16;
addr |= epnum << 8;
addr |= dev->devnum;
addr |= dev->tt->hub->devnum << 16;
addr |= epnum << 8;
addr |= dev->devnum;
- stream->usecs = HS_USECS_ISO (maxp);
+ stream->ps.usecs = HS_USECS_ISO(maxp);
think_time = dev->tt ? dev->tt->think_time : 0;
think_time = dev->tt ? dev->tt->think_time : 0;
- stream->tt_usecs = NS_TO_US (think_time + usb_calc_bus_time (
+ stream->ps.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;
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->usecs = HS_USECS_ISO (1);
+ stream->ps.c_usecs = stream->ps.usecs;
+ stream->ps.usecs = HS_USECS_ISO(1);
stream->raw_mask = 1;
/* c-mask as specified in USB 2.0 11.18.4 3.c */
stream->raw_mask = 1;
/* c-mask as specified in USB 2.0 11.18.4 3.c */
stream->raw_mask |= tmp << (8 + 2);
} else
stream->raw_mask = smask_out [hs_transfers - 1];
stream->raw_mask |= tmp << (8 + 2);
} else
stream->raw_mask = smask_out [hs_transfers - 1];
- bandwidth = stream->usecs + stream->c_usecs;
- bandwidth /= interval;
+
+ stream->bandwidth = (stream->ps.usecs + stream->ps.c_usecs) /
+ interval;
+ stream->uperiod = interval << 3;
+ stream->ps.period = interval;
/* stream->splits gets created from raw_mask later */
stream->address = cpu_to_hc32(ehci, addr);
}
/* stream->splits gets created from raw_mask later */
stream->address = cpu_to_hc32(ehci, addr);
}
- stream->bandwidth = bandwidth;
+ stream->ps.udev = dev;
+ stream->ps.ep = urb->ep;
stream->bEndpointAddress = is_input | epnum;
stream->bEndpointAddress = is_input | epnum;
- stream->interval = interval;
stream = iso_stream_alloc(GFP_ATOMIC);
if (likely (stream != NULL)) {
ep->hcpriv = stream;
stream = iso_stream_alloc(GFP_ATOMIC);
if (likely (stream != NULL)) {
ep->hcpriv = stream;
- stream->ep = ep;
- iso_stream_init(ehci, stream, urb->dev, urb->pipe,
- urb->interval);
+ iso_stream_init(ehci, stream, urb);
}
/* if dev->ep [epnum] is a QH, hw is set */
}
/* if dev->ep [epnum] is a QH, hw is set */
dma_addr_t dma = urb->transfer_dma;
/* how many uframes are needed for these transfers */
dma_addr_t dma = urb->transfer_dma;
/* how many uframes are needed for these transfers */
- iso_sched->span = urb->number_of_packets * stream->interval;
+ iso_sched->span = urb->number_of_packets * stream->uperiod;
/* figure out per-uframe itd fields that we'll need later
* when we fit new itds into the schedule.
/* figure out per-uframe itd fields that we'll need later
* when we fit new itds into the schedule.
*/
uf = uframe & 7;
if (!tt_available(ehci, period_uframes >> 3,
*/
uf = uframe & 7;
if (!tt_available(ehci, period_uframes >> 3,
- stream->udev, frame, uf, stream->tt_usecs))
+ stream->ps.udev, frame, uf, stream->ps.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,
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,
- stream->udev, frame, mask))
+ stream->ps.udev, frame, mask))
uf = uframe & 7;
/* check starts (OUT uses more than one) */
uf = uframe & 7;
/* check starts (OUT uses more than one) */
- max_used = ehci->uframe_periodic_max - stream->usecs;
+ max_used = ehci->uframe_periodic_max - stream->ps.usecs;
for (tmp = stream->raw_mask & 0xff; tmp; tmp >>= 1, uf++) {
if (periodic_usecs (ehci, frame, uf) > max_used)
return 0;
}
/* for IN, check CSPLIT */
for (tmp = stream->raw_mask & 0xff; tmp; tmp >>= 1, uf++) {
if (periodic_usecs (ehci, frame, uf) > max_used)
return 0;
}
/* for IN, check CSPLIT */
+ if (stream->ps.c_usecs) {
- max_used = ehci->uframe_periodic_max - stream->c_usecs;
+ max_used = ehci->uframe_periodic_max -
+ stream->ps.c_usecs;
do {
tmp = 1 << uf;
tmp <<= 8;
do {
tmp = 1 << uf;
tmp <<= 8;
/* check schedule: enough space? */
if (stream->highspeed) {
if (itd_slot_ok(ehci, mod, start,
/* check schedule: enough space? */
if (stream->highspeed) {
if (itd_slot_ok(ehci, mod, start,
- stream->usecs, period))
+ stream->ps.usecs, period))
done = 1;
} else {
if ((start % 8) >= 6)
done = 1;
} else {
if ((start % 8) >= 6)
itd_patch(ehci, itd, iso_sched, packet, uframe);
itd_patch(ehci, itd, iso_sched, packet, uframe);
- next_uframe += stream->interval;
+ next_uframe += stream->uperiod;
next_uframe &= mod - 1;
packet++;
next_uframe &= mod - 1;
packet++;
ehci_dbg (ehci, "can't get iso stream\n");
return -ENOMEM;
}
ehci_dbg (ehci, "can't get iso stream\n");
return -ENOMEM;
}
- if (unlikely (urb->interval != stream->interval)) {
+ if (unlikely(urb->interval != stream->uperiod)) {
ehci_dbg (ehci, "can't change iso interval %d --> %d\n",
ehci_dbg (ehci, "can't change iso interval %d --> %d\n",
- stream->interval, urb->interval);
+ stream->uperiod, urb->interval);
dma_addr_t dma = urb->transfer_dma;
/* how many frames are needed for these transfers */
dma_addr_t dma = urb->transfer_dma;
/* how many frames are needed for these transfers */
- iso_sched->span = urb->number_of_packets * stream->interval;
+ iso_sched->span = urb->number_of_packets * stream->ps.period;
/* figure out per-frame sitd fields that we'll need later
* when we fit new sitds into the schedule.
/* figure out per-frame sitd fields that we'll need later
* when we fit new sitds into the schedule.
sitd_link(ehci, (next_uframe >> 3) & (ehci->periodic_size - 1),
sitd);
sitd_link(ehci, (next_uframe >> 3) & (ehci->periodic_size - 1),
sitd);
- next_uframe += stream->interval << 3;
+ next_uframe += stream->uperiod;
}
stream->next_uframe = next_uframe & (mod - 1);
}
stream->next_uframe = next_uframe & (mod - 1);
ehci_dbg (ehci, "can't get iso stream\n");
return -ENOMEM;
}
ehci_dbg (ehci, "can't get iso stream\n");
return -ENOMEM;
}
- if (urb->interval != stream->interval) {
+ if (urb->interval != stream->ps.period) {
ehci_dbg (ehci, "can't change iso interval %d --> %d\n",
ehci_dbg (ehci, "can't change iso interval %d --> %d\n",
- stream->interval, urb->interval);
+ stream->ps.period, urb->interval);
+/*
+ * Scheduling and budgeting information for periodic transfers, for both
+ * high-speed devices and full/low-speed devices lying behind a TT.
+ */
+struct ehci_per_sched {
+ struct usb_device *udev; /* access to the TT */
+ struct usb_host_endpoint *ep;
+ u16 tt_usecs; /* time on the FS/LS bus */
+ u16 period; /* actual period in frames */
+ u16 phase; /* actual phase, frame part */
+ u8 phase_uf; /* uframe part of the phase */
+ u8 usecs, c_usecs; /* times on the HS bus */
+};
#define NO_FRAME 29999 /* frame not assigned yet */
/* ehci_hcd->lock guards shared data against other CPUs:
#define NO_FRAME 29999 /* frame not assigned yet */
/* ehci_hcd->lock guards shared data against other CPUs:
struct list_head intr_node; /* list of intr QHs */
struct ehci_qtd *dummy;
struct list_head unlink_node;
struct list_head intr_node; /* list of intr QHs */
struct ehci_qtd *dummy;
struct list_head unlink_node;
+ struct ehci_per_sched ps; /* scheduling info */
u8 xacterrs; /* XactErr retry counter */
#define QH_XACTERR_MAX 32 /* XactErr retry limit */
u8 xacterrs; /* XactErr retry counter */
#define QH_XACTERR_MAX 32 /* XactErr retry limit */
- /* periodic schedule info */
- u8 usecs; /* intr bandwidth */
u8 gap_uf; /* uframes split/csplit gap */
u8 gap_uf; /* uframes split/csplit gap */
- u8 c_usecs; /* ... split completion bw */
- u16 tt_usecs; /* tt downstream bandwidth */
- unsigned short period; /* polling interval */
- unsigned short start; /* where polling starts */
- struct usb_device *dev; /* access to TT */
unsigned is_out:1; /* bulk or intr OUT */
unsigned clearing_tt:1; /* Clear-TT-Buf in progress */
unsigned dequeue_during_giveback:1;
unsigned is_out:1; /* bulk or intr OUT */
unsigned clearing_tt:1; /* Clear-TT-Buf in progress */
unsigned dequeue_during_giveback:1;
u8 highspeed;
struct list_head td_list; /* queued itds/sitds */
struct list_head free_list; /* list of unused itds/sitds */
u8 highspeed;
struct list_head td_list; /* queued itds/sitds */
struct list_head free_list; /* list of unused itds/sitds */
- struct usb_device *udev;
- struct usb_host_endpoint *ep;
/* output of (re)scheduling */
/* output of (re)scheduling */
+ struct ehci_per_sched ps; /* scheduling info */
unsigned next_uframe;
__hc32 splits;
/* the rest is derived from the endpoint descriptor,
unsigned next_uframe;
__hc32 splits;
/* the rest is derived from the endpoint descriptor,
- * trusting urb->interval == f(epdesc->bInterval) and
* including the extra info for hw_bufp[0..2]
*/
* including the extra info for hw_bufp[0..2]
*/
- u8 usecs, c_usecs;
- u16 interval;
- u16 tt_usecs;
+ u16 uperiod; /* period in uframes */
u16 maxp;
u16 raw_mask;
unsigned bandwidth;
u16 maxp;
u16 raw_mask;
unsigned bandwidth;