Commit ffa0248e authored by Alan Stern's avatar Alan Stern Committed by Greg Kroah-Hartman

USB: EHCI: create a "periodic schedule info" struct

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: default avatarAlan Stern <stern@rowland.harvard.edu>
Signed-off-by: default avatarGreg Kroah-Hartman <gregkh@linuxfoundation.org>
parent 91a99b5e
......@@ -571,7 +571,7 @@ static ssize_t fill_periodic_buffer(struct debug_buffer *buf)
case Q_TYPE_QH:
hw = p.qh->hw;
temp = scnprintf (next, size, " qh%d-%04x/%p",
p.qh->period,
p.qh->ps.period,
hc32_to_cpup(ehci,
&hw->hw_info2)
/* uframe masks */
......@@ -618,7 +618,8 @@ static ssize_t fill_periodic_buffer(struct debug_buffer *buf)
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));
......@@ -645,7 +646,7 @@ static ssize_t fill_periodic_buffer(struct debug_buffer *buf)
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);
......
......@@ -1029,7 +1029,7 @@ ehci_endpoint_reset(struct usb_hcd *hcd, struct usb_host_endpoint *ep)
* 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);
......
......@@ -105,9 +105,9 @@ qh_update (struct ehci_hcd *ehci, struct ehci_qh *qh, struct ehci_qtd *qtd)
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);
usb_settoggle (qh->dev, epnum, is_out, 1);
usb_settoggle(qh->ps.udev, epnum, is_out, 1);
}
}
......@@ -797,26 +797,25 @@ qh_make (
* 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)));
qh->start = NO_FRAME;
qh->ps.phase = NO_FRAME;
if (urb->dev->speed == USB_SPEED_HIGH) {
qh->c_usecs = 0;
qh->ps.c_usecs = 0;
qh->gap_uf = 0;
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;
} 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;
} else {
int think_time;
......@@ -826,27 +825,26 @@ qh_make (
/* 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
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;
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)));
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 */
qh->dev = urb->dev;
qh->ps.udev = urb->dev;
qh->ps.ep = urb->ep;
/* using TT? */
switch (urb->dev->speed) {
......
This diff is collapsed.
......@@ -54,6 +54,19 @@ struct ehci_stats {
unsigned long unlink;
};
/*
* 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:
......@@ -387,6 +400,7 @@ struct ehci_qh {
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 */
unsigned unlink_cycle;
......@@ -400,15 +414,8 @@ struct ehci_qh {
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 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;
......@@ -451,20 +458,16 @@ struct ehci_iso_stream {
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 */
struct ehci_per_sched ps; /* scheduling info */
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]
*/
u8 usecs, c_usecs;
u16 interval;
u16 tt_usecs;
u16 uperiod; /* period in uframes */
u16 maxp;
u16 raw_mask;
unsigned bandwidth;
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment