summaryrefslogtreecommitdiffstats
path: root/drivers/usb/host/ehci-sched.c
diff options
context:
space:
mode:
Diffstat (limited to 'drivers/usb/host/ehci-sched.c')
-rw-r--r--drivers/usb/host/ehci-sched.c167
1 files changed, 84 insertions, 83 deletions
diff --git a/drivers/usb/host/ehci-sched.c b/drivers/usb/host/ehci-sched.c
index 37e97a70894a..1fafcda0ae81 100644
--- a/drivers/usb/host/ehci-sched.c
+++ b/drivers/usb/host/ehci-sched.c
@@ -121,11 +121,11 @@ periodic_usecs (struct ehci_hcd *ehci, unsigned frame, unsigned uframe)
hw = q->qh->hw;
/* is it in the S-mask? */
if (hw->hw_info2 & cpu_to_hc32(ehci, 1 << uframe))
- usecs += q->qh->usecs;
+ usecs += q->qh->ps.usecs;
/* ... 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;
@@ -142,7 +142,7 @@ periodic_usecs (struct ehci_hcd *ehci, unsigned frame, unsigned 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;
@@ -152,7 +152,7 @@ periodic_usecs (struct ehci_hcd *ehci, unsigned frame, unsigned uframe)
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);
}
@@ -161,7 +161,7 @@ periodic_usecs (struct ehci_hcd *ehci, unsigned frame, unsigned uframe)
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;
@@ -258,9 +258,9 @@ periodic_tt_usecs (
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);
- 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;
@@ -268,7 +268,7 @@ periodic_tt_usecs (
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;
@@ -391,7 +391,7 @@ static int tt_no_collision (
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,
@@ -471,19 +471,19 @@ static void disable_periodic(struct ehci_hcd *ehci)
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),
- 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;
- 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;
@@ -503,7 +503,7 @@ static void qh_link_periodic(struct ehci_hcd *ehci, struct ehci_qh *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;
@@ -523,10 +523,10 @@ static void qh_link_periodic(struct ehci_hcd *ehci, struct ehci_qh *qh)
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);
@@ -556,22 +556,21 @@ static void qh_unlink_periodic(struct ehci_hcd *ehci, struct ehci_qh *qh)
*/
/* 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);
- /* 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",
- qh->period,
+ qh->ps.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);
/* qh->qh_next still "live" to HC */
qh->qh_state = QH_STATE_UNLINK;
@@ -744,26 +743,26 @@ static int check_intr_schedule (
int retval = -ENOSPC;
u8 mask = 0;
- if (qh->c_usecs && uframe >= 6) /* FSTN territory? */
+ if (qh->ps.c_usecs && uframe >= 6) /* FSTN territory? */
goto done;
- if (!check_period (ehci, frame, uframe, qh->period, qh->usecs))
+ if (!check_period(ehci, frame, uframe, qh->ps.period, qh->ps.usecs))
goto done;
- if (!qh->c_usecs) {
+ if (!qh->ps.c_usecs) {
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++)
- 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;
@@ -784,12 +783,12 @@ static int check_intr_schedule (
*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))
goto done;
- 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))
goto done;
retval = 0;
}
@@ -810,7 +809,7 @@ static int qh_schedule(struct ehci_hcd *ehci, struct ehci_qh *qh)
struct ehci_qh_hw *hw = qh->hw;
hw->hw_next = EHCI_LIST_END(ehci);
- frame = qh->start;
+ frame = qh->ps.phase;
/* reuse the previous schedule slots, if we can */
if (frame != NO_FRAME) {
@@ -828,11 +827,11 @@ static int qh_schedule(struct ehci_hcd *ehci, struct ehci_qh *qh)
*/
if (status) {
/* "normal" case, uframing flexible except with splits */
- if (qh->period) {
+ if (qh->ps.period) {
int i;
- 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,
@@ -842,18 +841,18 @@ static int qh_schedule(struct ehci_hcd *ehci, struct ehci_qh *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;
- qh->start = frame;
+ qh->ps.phase = frame;
/* 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;
@@ -978,25 +977,24 @@ static void
iso_stream_init (
struct ehci_hcd *ehci,
struct ehci_iso_stream *stream,
- struct usb_device *dev,
- int pipe,
- unsigned interval
+ struct urb *urb
)
{
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;
- long bandwidth;
/*
* 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 {
@@ -1020,9 +1018,11 @@ iso_stream_init (
/* 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;
} else {
u32 addr;
@@ -1036,17 +1036,17 @@ iso_stream_init (
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;
- 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;
- 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 */
@@ -1054,18 +1054,20 @@ iso_stream_init (
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->bandwidth = bandwidth;
- stream->udev = dev;
+ stream->ps.udev = dev;
+ stream->ps.ep = urb->ep;
stream->bEndpointAddress = is_input | epnum;
- stream->interval = interval;
stream->maxp = maxp;
}
@@ -1090,9 +1092,7 @@ iso_stream_find (struct ehci_hcd *ehci, struct urb *urb)
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 */
@@ -1137,7 +1137,7 @@ itd_sched_init(
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.
@@ -1304,14 +1304,14 @@ sitd_slot_ok (
*/
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,
- stream->udev, frame, mask))
+ stream->ps.udev, frame, mask))
return 0;
#endif
@@ -1325,16 +1325,17 @@ sitd_slot_ok (
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 */
- if (stream->c_usecs) {
+ if (stream->ps.c_usecs) {
uf = uframe & 7;
- 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;
@@ -1428,7 +1429,7 @@ iso_stream_schedule (
/* 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)
@@ -1668,7 +1669,7 @@ static void itd_link_urb(
itd_patch(ehci, itd, iso_sched, packet, uframe);
- next_uframe += stream->interval;
+ next_uframe += stream->uperiod;
next_uframe &= mod - 1;
packet++;
@@ -1808,9 +1809,9 @@ static int itd_submit (struct ehci_hcd *ehci, struct urb *urb,
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",
- stream->interval, urb->interval);
+ stream->uperiod, urb->interval);
goto done;
}
@@ -1875,7 +1876,7 @@ sitd_sched_init(
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.
@@ -2069,7 +2070,7 @@ static void sitd_link_urb(
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);
@@ -2188,9 +2189,9 @@ static int sitd_submit (struct ehci_hcd *ehci, struct urb *urb,
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",
- stream->interval, urb->interval);
+ stream->ps.period, urb->interval);
goto done;
}