1,1123 → 1,1123 |
/* |
* Copyright (c) 2001-2002 by David Brownell |
* |
* This program is free software; you can redistribute it and/or modify it |
* under the terms of the GNU General Public License as published by the |
* Free Software Foundation; either version 2 of the License, or (at your |
* option) any later version. |
* |
* This program is distributed in the hope that it will be useful, but |
* WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY |
* or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License |
* for more details. |
* |
* You should have received a copy of the GNU General Public License |
* along with this program; if not, write to the Free Software Foundation, |
* Inc., 675 Mass Ave, Cambridge, MA 02139, USA. |
*/ |
|
/* this file is part of ehci-hcd.c */ |
|
/*-------------------------------------------------------------------------*/ |
|
/* |
* EHCI scheduled transaction support: interrupt, iso, split iso |
* These are called "periodic" transactions in the EHCI spec. |
* |
* Note that for interrupt transfers, the QH/QTD manipulation is shared |
* with the "asynchronous" transaction support (control/bulk transfers). |
* The only real difference is in how interrupt transfers are scheduled. |
* We get some funky API restrictions from the current URB model, which |
* works notably better for reading transfers than for writing. (And |
* which accordingly needs to change before it'll work inside devices, |
* or with "USB On The Go" additions to USB 2.0 ...) |
*/ |
|
static int ehci_get_frame (struct usb_hcd *hcd); |
|
/*-------------------------------------------------------------------------*/ |
|
/* |
* periodic_next_shadow - return "next" pointer on shadow list |
* @periodic: host pointer to qh/itd/sitd |
* @tag: hardware tag for type of this record |
*/ |
static union ehci_shadow * |
periodic_next_shadow (union ehci_shadow *periodic, int tag) |
{ |
switch (tag) { |
case Q_TYPE_QH: |
return &periodic->qh->qh_next; |
case Q_TYPE_FSTN: |
return &periodic->fstn->fstn_next; |
case Q_TYPE_ITD: |
return &periodic->itd->itd_next; |
#ifdef have_split_iso |
case Q_TYPE_SITD: |
return &periodic->sitd->sitd_next; |
#endif /* have_split_iso */ |
} |
dbg ("BAD shadow %p tag %d", periodic->ptr, tag); |
// BUG (); |
return 0; |
} |
|
/* returns true after successful unlink */ |
/* caller must hold ehci->lock */ |
static int periodic_unlink (struct ehci_hcd *ehci, unsigned frame, void *ptr) |
{ |
union ehci_shadow *prev_p = &ehci->pshadow [frame]; |
u32 *hw_p = &ehci->periodic [frame]; |
union ehci_shadow here = *prev_p; |
union ehci_shadow *next_p; |
|
/* find predecessor of "ptr"; hw and shadow lists are in sync */ |
while (here.ptr && here.ptr != ptr) { |
prev_p = periodic_next_shadow (prev_p, Q_NEXT_TYPE (*hw_p)); |
hw_p = &here.qh->hw_next; |
here = *prev_p; |
} |
/* an interrupt entry (at list end) could have been shared */ |
if (!here.ptr) { |
dbg ("entry %p no longer on frame [%d]", ptr, frame); |
return 0; |
} |
// vdbg ("periodic unlink %p from frame %d", ptr, frame); |
|
/* update hardware list ... HC may still know the old structure, so |
* don't change hw_next until it'll have purged its cache |
*/ |
next_p = periodic_next_shadow (&here, Q_NEXT_TYPE (*hw_p)); |
*hw_p = here.qh->hw_next; |
|
/* unlink from shadow list; HCD won't see old structure again */ |
*prev_p = *next_p; |
next_p->ptr = 0; |
|
return 1; |
} |
|
/* how many of the uframe's 125 usecs are allocated? */ |
static unsigned short |
periodic_usecs (struct ehci_hcd *ehci, unsigned frame, unsigned uframe) |
{ |
u32 *hw_p = &ehci->periodic [frame]; |
union ehci_shadow *q = &ehci->pshadow [frame]; |
unsigned usecs = 0; |
|
while (q->ptr) { |
switch (Q_NEXT_TYPE (*hw_p)) { |
case Q_TYPE_QH: |
/* is it in the S-mask? */ |
if (q->qh->hw_info2 & cpu_to_le32 (1 << uframe)) |
usecs += q->qh->usecs; |
/* ... or C-mask? */ |
if (q->qh->hw_info2 & cpu_to_le32 (1 << (8 + uframe))) |
usecs += q->qh->c_usecs; |
q = &q->qh->qh_next; |
break; |
case Q_TYPE_FSTN: |
/* for "save place" FSTNs, count the relevant INTR |
* bandwidth from the previous frame |
*/ |
if (q->fstn->hw_prev != EHCI_LIST_END) { |
dbg ("not counting FSTN bandwidth yet ..."); |
} |
q = &q->fstn->fstn_next; |
break; |
case Q_TYPE_ITD: |
/* NOTE the "one uframe per itd" policy */ |
if (q->itd->hw_transaction [uframe] != 0) |
usecs += q->itd->usecs; |
q = &q->itd->itd_next; |
break; |
#ifdef have_split_iso |
case Q_TYPE_SITD: |
temp = q->sitd->hw_fullspeed_ep & |
__constant_cpu_to_le32 (1 << 31); |
|
// FIXME: this doesn't count data bytes right... |
|
/* is it in the S-mask? (count SPLIT, DATA) */ |
if (q->sitd->hw_uframe & cpu_to_le32 (1 << uframe)) { |
if (temp) |
usecs += HS_USECS (188); |
else |
usecs += HS_USECS (1); |
} |
|
/* ... C-mask? (count CSPLIT, DATA) */ |
if (q->sitd->hw_uframe & |
cpu_to_le32 (1 << (8 + uframe))) { |
if (temp) |
usecs += HS_USECS (0); |
else |
usecs += HS_USECS (188); |
} |
q = &q->sitd->sitd_next; |
break; |
#endif /* have_split_iso */ |
default: |
BUG (); |
} |
} |
#ifdef DEBUG |
if (usecs > 100) |
err ("overallocated uframe %d, periodic is %d usecs", |
frame * 8 + uframe, usecs); |
#endif |
return usecs; |
} |
|
/*-------------------------------------------------------------------------*/ |
|
static int enable_periodic (struct ehci_hcd *ehci) |
{ |
u32 cmd; |
int status; |
|
/* did clearing PSE did take effect yet? |
* takes effect only at frame boundaries... |
*/ |
status = handshake (&ehci->regs->status, STS_PSS, 0, 9 * 125); |
if (status != 0) { |
ehci->hcd.state = USB_STATE_HALT; |
return status; |
} |
|
cmd = readl (&ehci->regs->command) | CMD_PSE; |
writel (cmd, &ehci->regs->command); |
/* posted write ... PSS happens later */ |
ehci->hcd.state = USB_STATE_RUNNING; |
|
/* make sure ehci_work scans these */ |
ehci->next_uframe = readl (&ehci->regs->frame_index) |
% (ehci->periodic_size << 3); |
return 0; |
} |
|
static int disable_periodic (struct ehci_hcd *ehci) |
{ |
u32 cmd; |
int status; |
|
/* did setting PSE not take effect yet? |
* takes effect only at frame boundaries... |
*/ |
status = handshake (&ehci->regs->status, STS_PSS, STS_PSS, 9 * 125); |
if (status != 0) { |
ehci->hcd.state = USB_STATE_HALT; |
return status; |
} |
|
cmd = readl (&ehci->regs->command) & ~CMD_PSE; |
writel (cmd, &ehci->regs->command); |
/* posted write ... */ |
|
ehci->next_uframe = -1; |
return 0; |
} |
|
/*-------------------------------------------------------------------------*/ |
|
// FIXME microframe periods not yet handled |
|
static void intr_deschedule ( |
struct ehci_hcd *ehci, |
struct ehci_qh *qh, |
int wait |
) { |
int status; |
unsigned frame = qh->start; |
|
do { |
periodic_unlink (ehci, frame, qh); |
qh_put (ehci, qh); |
frame += qh->period; |
} while (frame < ehci->periodic_size); |
|
qh->qh_state = QH_STATE_UNLINK; |
qh->qh_next.ptr = 0; |
ehci->periodic_sched--; |
|
/* maybe turn off periodic schedule */ |
if (!ehci->periodic_sched) |
status = disable_periodic (ehci); |
else { |
status = 0; |
vdbg ("periodic schedule still enabled"); |
} |
|
/* |
* If the hc may be looking at this qh, then delay a uframe |
* (yeech!) to be sure it's done. |
* No other threads may be mucking with this qh. |
*/ |
if (((ehci_get_frame (&ehci->hcd) - frame) % qh->period) == 0) { |
if (wait) { |
udelay (125); |
qh->hw_next = EHCI_LIST_END; |
} else { |
/* we may not be IDLE yet, but if the qh is empty |
* the race is very short. then if qh also isn't |
* rescheduled soon, it won't matter. otherwise... |
*/ |
vdbg ("intr_deschedule..."); |
} |
} else |
qh->hw_next = EHCI_LIST_END; |
|
qh->qh_state = QH_STATE_IDLE; |
|
/* update per-qh bandwidth utilization (for usbfs) */ |
hcd_to_bus (&ehci->hcd)->bandwidth_allocated -= |
(qh->usecs + qh->c_usecs) / qh->period; |
|
dbg ("descheduled qh %p, period = %d frame = %d count = %d, urbs = %d", |
qh, qh->period, frame, |
atomic_read (&qh->refcount), ehci->periodic_sched); |
} |
|
static int check_period ( |
struct ehci_hcd *ehci, |
unsigned frame, |
unsigned uframe, |
unsigned period, |
unsigned usecs |
) { |
/* complete split running into next frame? |
* given FSTN support, we could sometimes check... |
*/ |
if (uframe >= 8) |
return 0; |
|
/* |
* 80% periodic == 100 usec/uframe available |
* convert "usecs we need" to "max already claimed" |
*/ |
usecs = 100 - usecs; |
|
do { |
int claimed; |
|
// FIXME delete when intr_submit handles non-empty queues |
// this gives us a one intr/frame limit (vs N/uframe) |
// ... and also lets us avoid tracking split transactions |
// that might collide at a given TT/hub. |
if (ehci->pshadow [frame].ptr) |
return 0; |
|
claimed = periodic_usecs (ehci, frame, uframe); |
if (claimed > usecs) |
return 0; |
|
// FIXME update to handle sub-frame periods |
} while ((frame += period) < ehci->periodic_size); |
|
// success! |
return 1; |
} |
|
static int check_intr_schedule ( |
struct ehci_hcd *ehci, |
unsigned frame, |
unsigned uframe, |
const struct ehci_qh *qh, |
u32 *c_maskp |
) |
{ |
int retval = -ENOSPC; |
|
if (!check_period (ehci, frame, uframe, qh->period, qh->usecs)) |
goto done; |
if (!qh->c_usecs) { |
retval = 0; |
*c_maskp = cpu_to_le32 (0); |
goto done; |
} |
|
/* This is a split transaction; check the bandwidth available for |
* the completion too. Check both worst and best case gaps: worst |
* case is SPLIT near uframe end, and CSPLIT near start ... best is |
* vice versa. Difference can be almost two uframe times, but we |
* reserve unnecessary bandwidth (waste it) this way. (Actually |
* even better cases exist, like immediate device NAK.) |
* |
* FIXME don't even bother unless we know this TT is idle in that |
* range of uframes ... for now, check_period() allows only one |
* interrupt transfer per frame, so needn't check "TT busy" status |
* when scheduling a split (QH, SITD, or FSTN). |
* |
* FIXME ehci 0.96 and above can use FSTNs |
*/ |
if (!check_period (ehci, frame, uframe + qh->gap_uf + 1, |
qh->period, qh->c_usecs)) |
goto done; |
if (!check_period (ehci, frame, uframe + qh->gap_uf, |
qh->period, qh->c_usecs)) |
goto done; |
|
*c_maskp = cpu_to_le32 (0x03 << (8 + uframe + qh->gap_uf)); |
retval = 0; |
done: |
return retval; |
} |
|
static int qh_schedule (struct ehci_hcd *ehci, struct ehci_qh *qh) |
{ |
int status; |
unsigned uframe; |
u32 c_mask; |
unsigned frame; /* 0..(qh->period - 1), or NO_FRAME */ |
|
qh->hw_next = EHCI_LIST_END; |
frame = qh->start; |
|
/* reuse the previous schedule slots, if we can */ |
if (frame < qh->period) { |
uframe = ffs (le32_to_cpup (&qh->hw_info2) & 0x00ff); |
status = check_intr_schedule (ehci, frame, --uframe, |
qh, &c_mask); |
} else { |
uframe = 0; |
c_mask = 0; |
status = -ENOSPC; |
} |
|
/* else scan the schedule to find a group of slots such that all |
* uframes have enough periodic bandwidth available. |
*/ |
if (status) { |
frame = qh->period - 1; |
do { |
for (uframe = 0; uframe < 8; uframe++) { |
status = check_intr_schedule (ehci, |
frame, uframe, qh, |
&c_mask); |
if (status == 0) |
break; |
} |
} while (status && frame--); |
if (status) |
goto done; |
qh->start = frame; |
|
/* reset S-frame and (maybe) C-frame masks */ |
qh->hw_info2 &= ~0xffff; |
qh->hw_info2 |= cpu_to_le32 (1 << uframe) | c_mask; |
} else |
dbg ("reused previous qh %p schedule", qh); |
|
/* stuff into the periodic schedule */ |
qh->qh_state = QH_STATE_LINKED; |
dbg ("scheduled qh %p usecs %d/%d period %d.0 starting %d.%d (gap %d)", |
qh, qh->usecs, qh->c_usecs, |
qh->period, frame, uframe, qh->gap_uf); |
do { |
if (unlikely (ehci->pshadow [frame].ptr != 0)) { |
|
// FIXME -- just link toward the end, before any qh with a shorter period, |
// AND accommodate it already having been linked here (after some other qh) |
// AS WELL AS updating the schedule checking logic |
|
BUG (); |
} else { |
ehci->pshadow [frame].qh = qh_get (qh); |
ehci->periodic [frame] = |
QH_NEXT (qh->qh_dma); |
} |
wmb (); |
frame += qh->period; |
} while (frame < ehci->periodic_size); |
|
/* update per-qh bandwidth for usbfs */ |
hcd_to_bus (&ehci->hcd)->bandwidth_allocated += |
(qh->usecs + qh->c_usecs) / qh->period; |
|
/* maybe enable periodic schedule processing */ |
if (!ehci->periodic_sched++) |
status = enable_periodic (ehci); |
done: |
return status; |
} |
|
static int intr_submit ( |
struct ehci_hcd *ehci, |
struct urb *urb, |
struct list_head *qtd_list, |
int mem_flags |
) { |
unsigned epnum; |
unsigned long flags; |
struct ehci_qh *qh; |
struct hcd_dev *dev; |
int is_input; |
int status = 0; |
struct list_head empty; |
|
/* get endpoint and transfer/schedule data */ |
epnum = usb_pipeendpoint (urb->pipe); |
is_input = usb_pipein (urb->pipe); |
if (is_input) |
epnum |= 0x10; |
|
spin_lock_irqsave (&ehci->lock, flags); |
dev = (struct hcd_dev *)urb->dev->hcpriv; |
|
/* get qh and force any scheduling errors */ |
INIT_LIST_HEAD (&empty); |
qh = qh_append_tds (ehci, urb, &empty, epnum, &dev->ep [epnum]); |
if (qh == 0) { |
status = -ENOMEM; |
goto done; |
} |
if (qh->qh_state == QH_STATE_IDLE) { |
if ((status = qh_schedule (ehci, qh)) != 0) |
goto done; |
} |
|
/* then queue the urb's tds to the qh */ |
qh = qh_append_tds (ehci, urb, qtd_list, epnum, &dev->ep [epnum]); |
BUG_ON (qh == 0); |
|
/* ... update usbfs periodic stats */ |
hcd_to_bus (&ehci->hcd)->bandwidth_int_reqs++; |
|
done: |
spin_unlock_irqrestore (&ehci->lock, flags); |
if (status) |
qtd_list_free (ehci, urb, qtd_list); |
|
return status; |
} |
|
static unsigned |
intr_complete ( |
struct ehci_hcd *ehci, |
unsigned frame, |
struct ehci_qh *qh, |
struct pt_regs *regs |
) { |
unsigned count; |
|
/* nothing to report? */ |
if (likely ((qh->hw_token & __constant_cpu_to_le32 (QTD_STS_ACTIVE)) |
!= 0)) |
return 0; |
if (unlikely (list_empty (&qh->qtd_list))) { |
dbg ("intr qh %p no TDs?", qh); |
return 0; |
} |
|
/* handle any completions */ |
count = qh_completions (ehci, qh, regs); |
|
if (unlikely (list_empty (&qh->qtd_list))) |
intr_deschedule (ehci, qh, 0); |
|
return count; |
} |
|
/*-------------------------------------------------------------------------*/ |
|
static void |
itd_free_list (struct ehci_hcd *ehci, struct urb *urb) |
{ |
struct ehci_itd *first_itd = urb->hcpriv; |
|
while (!list_empty (&first_itd->itd_list)) { |
struct ehci_itd *itd; |
|
itd = list_entry ( |
first_itd->itd_list.next, |
struct ehci_itd, itd_list); |
list_del (&itd->itd_list); |
pci_pool_free (ehci->itd_pool, itd, itd->itd_dma); |
} |
pci_pool_free (ehci->itd_pool, first_itd, first_itd->itd_dma); |
urb->hcpriv = 0; |
} |
|
static int |
itd_fill ( |
struct ehci_hcd *ehci, |
struct ehci_itd *itd, |
struct urb *urb, |
unsigned index, // urb->iso_frame_desc [index] |
dma_addr_t dma // mapped transfer buffer |
) { |
u64 temp; |
u32 buf1; |
unsigned i, epnum, maxp, multi; |
unsigned length; |
int is_input; |
|
itd->hw_next = EHCI_LIST_END; |
itd->urb = urb; |
itd->index = index; |
|
/* tell itd about its transfer buffer, max 2 pages */ |
length = urb->iso_frame_desc [index].length; |
dma += urb->iso_frame_desc [index].offset; |
temp = dma & ~0x0fff; |
for (i = 0; i < 2; i++) { |
itd->hw_bufp [i] = cpu_to_le32 ((u32) temp); |
itd->hw_bufp_hi [i] = cpu_to_le32 ((u32)(temp >> 32)); |
temp += 0x1000; |
} |
itd->buf_dma = dma; |
|
/* |
* this might be a "high bandwidth" highspeed endpoint, |
* as encoded in the ep descriptor's maxpacket field |
*/ |
epnum = usb_pipeendpoint (urb->pipe); |
is_input = usb_pipein (urb->pipe); |
if (is_input) { |
maxp = urb->dev->epmaxpacketin [epnum]; |
buf1 = (1 << 11); |
} else { |
maxp = urb->dev->epmaxpacketout [epnum]; |
buf1 = 0; |
} |
buf1 |= (maxp & 0x03ff); |
multi = 1; |
multi += (maxp >> 11) & 0x03; |
maxp &= 0x03ff; |
maxp *= multi; |
|
/* transfer can't fit in any uframe? */ |
if (length < 0 || maxp < length) { |
dbg ("BAD iso packet: %d bytes, max %d, urb %p [%d] (of %d)", |
length, maxp, urb, index, |
urb->iso_frame_desc [index].length); |
return -ENOSPC; |
} |
itd->usecs = usb_calc_bus_time (USB_SPEED_HIGH, is_input, 1, length); |
|
/* "plus" info in low order bits of buffer pointers */ |
itd->hw_bufp [0] |= cpu_to_le32 ((epnum << 8) | urb->dev->devnum); |
itd->hw_bufp [1] |= cpu_to_le32 (buf1); |
itd->hw_bufp [2] |= cpu_to_le32 (multi); |
|
/* figure hw_transaction[] value (it's scheduled later) */ |
itd->transaction = EHCI_ISOC_ACTIVE; |
itd->transaction |= dma & 0x0fff; /* offset; buffer=0 */ |
if ((index + 1) == urb->number_of_packets) |
itd->transaction |= EHCI_ITD_IOC; /* end-of-urb irq */ |
itd->transaction |= length << 16; |
cpu_to_le32s (&itd->transaction); |
|
return 0; |
} |
|
static int |
itd_urb_transaction ( |
struct ehci_hcd *ehci, |
struct urb *urb, |
int mem_flags |
) { |
int frame_index; |
struct ehci_itd *first_itd, *itd; |
int status; |
dma_addr_t itd_dma; |
|
/* allocate/init ITDs */ |
for (frame_index = 0, first_itd = 0; |
frame_index < urb->number_of_packets; |
frame_index++) { |
itd = pci_pool_alloc (ehci->itd_pool, mem_flags, &itd_dma); |
if (!itd) { |
status = -ENOMEM; |
goto fail; |
} |
memset (itd, 0, sizeof *itd); |
itd->itd_dma = itd_dma; |
|
status = itd_fill (ehci, itd, urb, frame_index, |
urb->transfer_dma); |
if (status != 0) |
goto fail; |
|
if (first_itd) |
list_add_tail (&itd->itd_list, |
&first_itd->itd_list); |
else { |
INIT_LIST_HEAD (&itd->itd_list); |
urb->hcpriv = first_itd = itd; |
} |
} |
urb->error_count = 0; |
return 0; |
|
fail: |
if (urb->hcpriv) |
itd_free_list (ehci, urb); |
return status; |
} |
|
/*-------------------------------------------------------------------------*/ |
|
static inline void |
itd_link (struct ehci_hcd *ehci, unsigned frame, struct ehci_itd *itd) |
{ |
/* always prepend ITD/SITD ... only QH tree is order-sensitive */ |
itd->itd_next = ehci->pshadow [frame]; |
itd->hw_next = ehci->periodic [frame]; |
ehci->pshadow [frame].itd = itd; |
ehci->periodic [frame] = cpu_to_le32 (itd->itd_dma) | Q_TYPE_ITD; |
} |
|
/* |
* return zero on success, else -errno |
* - start holds first uframe to start scheduling into |
* - max is the first uframe it's NOT (!) OK to start scheduling into |
* math to be done modulo "mod" (ehci->periodic_size << 3) |
*/ |
static int get_iso_range ( |
struct ehci_hcd *ehci, |
struct urb *urb, |
unsigned *start, |
unsigned *max, |
unsigned mod |
) { |
struct list_head *lh; |
struct hcd_dev *dev = urb->dev->hcpriv; |
int last = -1; |
unsigned now, span, end; |
|
span = urb->interval * urb->number_of_packets; |
|
/* first see if we know when the next transfer SHOULD happen */ |
list_for_each (lh, &dev->urb_list) { |
struct urb *u; |
struct ehci_itd *itd; |
unsigned s; |
|
u = list_entry (lh, struct urb, urb_list); |
if (u == urb || u->pipe != urb->pipe) |
continue; |
if (u->interval != urb->interval) { /* must not change! */ |
dbg ("urb %p interval %d ... != %p interval %d", |
u, u->interval, urb, urb->interval); |
return -EINVAL; |
} |
|
/* URB for this endpoint... covers through when? */ |
itd = urb->hcpriv; |
s = itd->uframe + u->interval * u->number_of_packets; |
if (last < 0) |
last = s; |
else { |
/* |
* So far we can only queue two ISO URBs... |
* |
* FIXME do interval math, figure out whether |
* this URB is "before" or not ... also, handle |
* the case where the URB might have completed, |
* but hasn't yet been processed. |
*/ |
dbg ("NYET: queue >2 URBs per ISO endpoint"); |
return -EDOM; |
} |
} |
|
/* calculate the legal range [start,max) */ |
now = readl (&ehci->regs->frame_index) + 1; /* next uframe */ |
if (!ehci->periodic_sched) |
now += 8; /* startup delay */ |
now %= mod; |
end = now + mod; |
if (last < 0) { |
*start = now + ehci->i_thresh + /* paranoia */ 1; |
*max = end - span; |
if (*max < *start + 1) |
*max = *start + 1; |
} else { |
*start = last % mod; |
*max = (last + 1) % mod; |
} |
|
/* explicit start frame? */ |
if (!(urb->transfer_flags & URB_ISO_ASAP)) { |
unsigned temp; |
|
/* sanity check: must be in range */ |
urb->start_frame %= ehci->periodic_size; |
temp = urb->start_frame << 3; |
if (temp < *start) |
temp += mod; |
if (temp > *max) |
return -EDOM; |
|
/* use that explicit start frame */ |
*start = urb->start_frame << 3; |
temp += 8; |
if (temp < *max) |
*max = temp; |
} |
|
// FIXME minimize wraparound to "now" ... insist max+span |
// (and start+span) remains a few frames short of "end" |
|
*max %= ehci->periodic_size; |
if ((*start + span) < end) |
return 0; |
return -EFBIG; |
} |
|
static int |
itd_schedule (struct ehci_hcd *ehci, struct urb *urb) |
{ |
unsigned start, max, i; |
int status; |
unsigned mod = ehci->periodic_size << 3; |
|
for (i = 0; i < urb->number_of_packets; i++) { |
urb->iso_frame_desc [i].status = -EINPROGRESS; |
urb->iso_frame_desc [i].actual_length = 0; |
} |
|
if ((status = get_iso_range (ehci, urb, &start, &max, mod)) != 0) |
return status; |
|
do { |
unsigned uframe; |
unsigned usecs; |
struct ehci_itd *itd; |
|
/* check schedule: enough space? */ |
itd = urb->hcpriv; |
uframe = start; |
for (i = 0, uframe = start; |
i < urb->number_of_packets; |
i++, uframe += urb->interval) { |
uframe %= mod; |
|
/* can't commit more than 80% periodic == 100 usec */ |
if (periodic_usecs (ehci, uframe >> 3, uframe & 0x7) |
> (100 - itd->usecs)) { |
itd = 0; |
break; |
} |
itd = list_entry (itd->itd_list.next, |
struct ehci_itd, itd_list); |
} |
if (!itd) |
continue; |
|
/* that's where we'll schedule this! */ |
itd = urb->hcpriv; |
urb->start_frame = start >> 3; |
vdbg ("ISO urb %p (%d packets period %d) starting %d.%d", |
urb, urb->number_of_packets, urb->interval, |
urb->start_frame, start & 0x7); |
for (i = 0, uframe = start, usecs = 0; |
i < urb->number_of_packets; |
i++, uframe += urb->interval) { |
uframe %= mod; |
|
itd->uframe = uframe; |
itd->hw_transaction [uframe & 0x07] = itd->transaction; |
itd_link (ehci, (uframe >> 3) % ehci->periodic_size, |
itd); |
wmb (); |
usecs += itd->usecs; |
|
itd = list_entry (itd->itd_list.next, |
struct ehci_itd, itd_list); |
} |
|
/* update bandwidth utilization records (for usbfs) |
* |
* FIXME This claims each URB queued to an endpoint, as if |
* transfers were concurrent, not sequential. So bandwidth |
* typically gets double-billed ... comes from tying it to |
* URBs rather than endpoints in the schedule. Luckily we |
* don't use this usbfs data for serious decision making. |
*/ |
usecs /= urb->number_of_packets; |
usecs /= urb->interval; |
usecs >>= 3; |
if (usecs < 1) |
usecs = 1; |
usb_claim_bandwidth (urb->dev, urb, usecs, 1); |
|
/* maybe enable periodic schedule processing */ |
if (!ehci->periodic_sched++) { |
if ((status = enable_periodic (ehci)) != 0) { |
// FIXME deschedule right away |
err ("itd_schedule, enable = %d", status); |
} |
} |
|
return 0; |
|
} while ((start = ++start % mod) != max); |
|
/* no room in the schedule */ |
dbg ("urb %p, CAN'T SCHEDULE", urb); |
return -ENOSPC; |
} |
|
/*-------------------------------------------------------------------------*/ |
|
#define ISO_ERRS (EHCI_ISOC_BUF_ERR | EHCI_ISOC_BABBLE | EHCI_ISOC_XACTERR) |
|
static unsigned |
itd_complete ( |
struct ehci_hcd *ehci, |
struct ehci_itd *itd, |
unsigned uframe, |
struct pt_regs *regs |
) { |
struct urb *urb = itd->urb; |
struct usb_iso_packet_descriptor *desc; |
u32 t; |
|
/* update status for this uframe's transfers */ |
desc = &urb->iso_frame_desc [itd->index]; |
|
t = itd->hw_transaction [uframe]; |
itd->hw_transaction [uframe] = 0; |
if (t & EHCI_ISOC_ACTIVE) |
desc->status = -EXDEV; |
else if (t & ISO_ERRS) { |
urb->error_count++; |
if (t & EHCI_ISOC_BUF_ERR) |
desc->status = usb_pipein (urb->pipe) |
? -ENOSR /* couldn't read */ |
: -ECOMM; /* couldn't write */ |
else if (t & EHCI_ISOC_BABBLE) |
desc->status = -EOVERFLOW; |
else /* (t & EHCI_ISOC_XACTERR) */ |
desc->status = -EPROTO; |
|
/* HC need not update length with this error */ |
if (!(t & EHCI_ISOC_BABBLE)) |
desc->actual_length += EHCI_ITD_LENGTH (t); |
} else { |
desc->status = 0; |
desc->actual_length += EHCI_ITD_LENGTH (t); |
} |
|
vdbg ("itd %p urb %p packet %d/%d trans %x status %d len %d", |
itd, urb, itd->index + 1, urb->number_of_packets, |
t, desc->status, desc->actual_length); |
|
/* handle completion now? */ |
if ((itd->index + 1) != urb->number_of_packets) |
return 0; |
|
/* |
* Always give the urb back to the driver ... expect it to submit |
* a new urb (or resubmit this), and to have another already queued |
* when un-interrupted transfers are needed. |
* |
* NOTE that for now we don't accelerate ISO unlinks; they just |
* happen according to the current schedule. Means a delay of |
* up to about a second (max). |
*/ |
itd_free_list (ehci, urb); |
if (urb->status == -EINPROGRESS) |
urb->status = 0; |
|
/* complete() can reenter this HCD */ |
spin_unlock (&ehci->lock); |
usb_hcd_giveback_urb (&ehci->hcd, urb, regs); |
spin_lock (&ehci->lock); |
|
/* defer stopping schedule; completion can submit */ |
ehci->periodic_sched--; |
if (!ehci->periodic_sched) |
(void) disable_periodic (ehci); |
|
return 1; |
} |
|
/*-------------------------------------------------------------------------*/ |
|
static int itd_submit (struct ehci_hcd *ehci, struct urb *urb, int mem_flags) |
{ |
int status; |
unsigned long flags; |
|
dbg ("itd_submit urb %p", urb); |
|
/* allocate ITDs w/o locking anything */ |
status = itd_urb_transaction (ehci, urb, mem_flags); |
if (status < 0) |
return status; |
|
/* schedule ... need to lock */ |
spin_lock_irqsave (&ehci->lock, flags); |
status = itd_schedule (ehci, urb); |
spin_unlock_irqrestore (&ehci->lock, flags); |
if (status < 0) |
itd_free_list (ehci, urb); |
|
return status; |
} |
|
#ifdef have_split_iso |
|
/*-------------------------------------------------------------------------*/ |
|
/* |
* "Split ISO TDs" ... used for USB 1.1 devices going through |
* the TTs in USB 2.0 hubs. |
* |
* FIXME not yet implemented |
*/ |
|
#endif /* have_split_iso */ |
|
/*-------------------------------------------------------------------------*/ |
|
static void |
scan_periodic (struct ehci_hcd *ehci, struct pt_regs *regs) |
{ |
unsigned frame, clock, now_uframe, mod; |
unsigned count = 0; |
|
mod = ehci->periodic_size << 3; |
|
/* |
* When running, scan from last scan point up to "now" |
* else clean up by scanning everything that's left. |
* Touches as few pages as possible: cache-friendly. |
* Don't scan ISO entries more than once, though. |
*/ |
frame = ehci->next_uframe >> 3; |
if (HCD_IS_RUNNING (ehci->hcd.state)) |
now_uframe = readl (&ehci->regs->frame_index); |
else |
now_uframe = (frame << 3) - 1; |
now_uframe %= mod; |
clock = now_uframe >> 3; |
|
for (;;) { |
union ehci_shadow q, *q_p; |
u32 type, *hw_p; |
unsigned uframes; |
|
restart: |
/* scan schedule to _before_ current frame index */ |
if (frame == clock) |
uframes = now_uframe & 0x07; |
else |
uframes = 8; |
|
q_p = &ehci->pshadow [frame]; |
hw_p = &ehci->periodic [frame]; |
q.ptr = q_p->ptr; |
type = Q_NEXT_TYPE (*hw_p); |
|
/* scan each element in frame's queue for completions */ |
while (q.ptr != 0) { |
int last; |
unsigned uf; |
union ehci_shadow temp; |
|
switch (type) { |
case Q_TYPE_QH: |
last = (q.qh->hw_next == EHCI_LIST_END); |
temp = q.qh->qh_next; |
type = Q_NEXT_TYPE (q.qh->hw_next); |
count += intr_complete (ehci, frame, |
qh_get (q.qh), regs); |
qh_put (ehci, q.qh); |
q = temp; |
break; |
case Q_TYPE_FSTN: |
last = (q.fstn->hw_next == EHCI_LIST_END); |
/* for "save place" FSTNs, look at QH entries |
* in the previous frame for completions. |
*/ |
if (q.fstn->hw_prev != EHCI_LIST_END) { |
dbg ("ignoring completions from FSTNs"); |
} |
type = Q_NEXT_TYPE (q.fstn->hw_next); |
q = q.fstn->fstn_next; |
break; |
case Q_TYPE_ITD: |
last = (q.itd->hw_next == EHCI_LIST_END); |
|
/* Unlink each (S)ITD we see, since the ISO |
* URB model forces constant rescheduling. |
* That complicates sharing uframes in ITDs, |
* and means we need to skip uframes the HC |
* hasn't yet processed. |
*/ |
for (uf = 0; uf < uframes; uf++) { |
if (q.itd->hw_transaction [uf] != 0) { |
temp = q; |
*q_p = q.itd->itd_next; |
*hw_p = q.itd->hw_next; |
type = Q_NEXT_TYPE (*hw_p); |
|
/* might free q.itd ... */ |
count += itd_complete (ehci, |
temp.itd, uf, regs); |
break; |
} |
} |
/* we might skip this ITD's uframe ... */ |
if (uf == uframes) { |
q_p = &q.itd->itd_next; |
hw_p = &q.itd->hw_next; |
type = Q_NEXT_TYPE (q.itd->hw_next); |
} |
|
q = *q_p; |
break; |
#ifdef have_split_iso |
case Q_TYPE_SITD: |
last = (q.sitd->hw_next == EHCI_LIST_END); |
sitd_complete (ehci, q.sitd); |
type = Q_NEXT_TYPE (q.sitd->hw_next); |
|
// FIXME unlink SITD after split completes |
q = q.sitd->sitd_next; |
break; |
#endif /* have_split_iso */ |
default: |
dbg ("corrupt type %d frame %d shadow %p", |
type, frame, q.ptr); |
// BUG (); |
last = 1; |
q.ptr = 0; |
} |
|
/* did completion remove an interior q entry? */ |
if (unlikely (q.ptr == 0 && !last)) |
goto restart; |
} |
|
/* stop when we catch up to the HC */ |
|
// FIXME: this assumes we won't get lapped when |
// latencies climb; that should be rare, but... |
// detect it, and just go all the way around. |
// FLR might help detect this case, so long as latencies |
// don't exceed periodic_size msec (default 1.024 sec). |
|
// FIXME: likewise assumes HC doesn't halt mid-scan |
|
if (frame == clock) { |
unsigned now; |
|
if (!HCD_IS_RUNNING (ehci->hcd.state)) |
break; |
ehci->next_uframe = now_uframe; |
now = readl (&ehci->regs->frame_index) % mod; |
if (now_uframe == now) |
break; |
|
/* rescan the rest of this frame, then ... */ |
now_uframe = now; |
clock = now_uframe >> 3; |
} else |
frame = (frame + 1) % ehci->periodic_size; |
} |
} |
/* |
* Copyright (c) 2001-2002 by David Brownell |
* |
* This program is free software; you can redistribute it and/or modify it |
* under the terms of the GNU General Public License as published by the |
* Free Software Foundation; either version 2 of the License, or (at your |
* option) any later version. |
* |
* This program is distributed in the hope that it will be useful, but |
* WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY |
* or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License |
* for more details. |
* |
* You should have received a copy of the GNU General Public License |
* along with this program; if not, write to the Free Software Foundation, |
* Inc., 675 Mass Ave, Cambridge, MA 02139, USA. |
*/ |
|
/* this file is part of ehci-hcd.c */ |
|
/*-------------------------------------------------------------------------*/ |
|
/* |
* EHCI scheduled transaction support: interrupt, iso, split iso |
* These are called "periodic" transactions in the EHCI spec. |
* |
* Note that for interrupt transfers, the QH/QTD manipulation is shared |
* with the "asynchronous" transaction support (control/bulk transfers). |
* The only real difference is in how interrupt transfers are scheduled. |
* We get some funky API restrictions from the current URB model, which |
* works notably better for reading transfers than for writing. (And |
* which accordingly needs to change before it'll work inside devices, |
* or with "USB On The Go" additions to USB 2.0 ...) |
*/ |
|
static int ehci_get_frame (struct usb_hcd *hcd); |
|
/*-------------------------------------------------------------------------*/ |
|
/* |
* periodic_next_shadow - return "next" pointer on shadow list |
* @periodic: host pointer to qh/itd/sitd |
* @tag: hardware tag for type of this record |
*/ |
static union ehci_shadow * |
periodic_next_shadow (union ehci_shadow *periodic, int tag) |
{ |
switch (tag) { |
case Q_TYPE_QH: |
return &periodic->qh->qh_next; |
case Q_TYPE_FSTN: |
return &periodic->fstn->fstn_next; |
case Q_TYPE_ITD: |
return &periodic->itd->itd_next; |
#ifdef have_split_iso |
case Q_TYPE_SITD: |
return &periodic->sitd->sitd_next; |
#endif /* have_split_iso */ |
} |
dbg ("BAD shadow %p tag %d", periodic->ptr, tag); |
// BUG (); |
return 0; |
} |
|
/* returns true after successful unlink */ |
/* caller must hold ehci->lock */ |
static int periodic_unlink (struct ehci_hcd *ehci, unsigned frame, void *ptr) |
{ |
union ehci_shadow *prev_p = &ehci->pshadow [frame]; |
u32 *hw_p = &ehci->periodic [frame]; |
union ehci_shadow here = *prev_p; |
union ehci_shadow *next_p; |
|
/* find predecessor of "ptr"; hw and shadow lists are in sync */ |
while (here.ptr && here.ptr != ptr) { |
prev_p = periodic_next_shadow (prev_p, Q_NEXT_TYPE (*hw_p)); |
hw_p = &here.qh->hw_next; |
here = *prev_p; |
} |
/* an interrupt entry (at list end) could have been shared */ |
if (!here.ptr) { |
dbg ("entry %p no longer on frame [%d]", ptr, frame); |
return 0; |
} |
// vdbg ("periodic unlink %p from frame %d", ptr, frame); |
|
/* update hardware list ... HC may still know the old structure, so |
* don't change hw_next until it'll have purged its cache |
*/ |
next_p = periodic_next_shadow (&here, Q_NEXT_TYPE (*hw_p)); |
*hw_p = here.qh->hw_next; |
|
/* unlink from shadow list; HCD won't see old structure again */ |
*prev_p = *next_p; |
next_p->ptr = 0; |
|
return 1; |
} |
|
/* how many of the uframe's 125 usecs are allocated? */ |
static unsigned short |
periodic_usecs (struct ehci_hcd *ehci, unsigned frame, unsigned uframe) |
{ |
u32 *hw_p = &ehci->periodic [frame]; |
union ehci_shadow *q = &ehci->pshadow [frame]; |
unsigned usecs = 0; |
|
while (q->ptr) { |
switch (Q_NEXT_TYPE (*hw_p)) { |
case Q_TYPE_QH: |
/* is it in the S-mask? */ |
if (q->qh->hw_info2 & cpu_to_le32 (1 << uframe)) |
usecs += q->qh->usecs; |
/* ... or C-mask? */ |
if (q->qh->hw_info2 & cpu_to_le32 (1 << (8 + uframe))) |
usecs += q->qh->c_usecs; |
q = &q->qh->qh_next; |
break; |
case Q_TYPE_FSTN: |
/* for "save place" FSTNs, count the relevant INTR |
* bandwidth from the previous frame |
*/ |
if (q->fstn->hw_prev != EHCI_LIST_END) { |
dbg ("not counting FSTN bandwidth yet ..."); |
} |
q = &q->fstn->fstn_next; |
break; |
case Q_TYPE_ITD: |
/* NOTE the "one uframe per itd" policy */ |
if (q->itd->hw_transaction [uframe] != 0) |
usecs += q->itd->usecs; |
q = &q->itd->itd_next; |
break; |
#ifdef have_split_iso |
case Q_TYPE_SITD: |
temp = q->sitd->hw_fullspeed_ep & |
__constant_cpu_to_le32 (1 << 31); |
|
// FIXME: this doesn't count data bytes right... |
|
/* is it in the S-mask? (count SPLIT, DATA) */ |
if (q->sitd->hw_uframe & cpu_to_le32 (1 << uframe)) { |
if (temp) |
usecs += HS_USECS (188); |
else |
usecs += HS_USECS (1); |
} |
|
/* ... C-mask? (count CSPLIT, DATA) */ |
if (q->sitd->hw_uframe & |
cpu_to_le32 (1 << (8 + uframe))) { |
if (temp) |
usecs += HS_USECS (0); |
else |
usecs += HS_USECS (188); |
} |
q = &q->sitd->sitd_next; |
break; |
#endif /* have_split_iso */ |
default: |
BUG (); |
} |
} |
#ifdef DEBUG |
if (usecs > 100) |
err ("overallocated uframe %d, periodic is %d usecs", |
frame * 8 + uframe, usecs); |
#endif |
return usecs; |
} |
|
/*-------------------------------------------------------------------------*/ |
|
static int enable_periodic (struct ehci_hcd *ehci) |
{ |
u32 cmd; |
int status; |
|
/* did clearing PSE did take effect yet? |
* takes effect only at frame boundaries... |
*/ |
status = handshake (&ehci->regs->status, STS_PSS, 0, 9 * 125); |
if (status != 0) { |
ehci->hcd.state = USB_STATE_HALT; |
return status; |
} |
|
cmd = readl (&ehci->regs->command) | CMD_PSE; |
writel (cmd, &ehci->regs->command); |
/* posted write ... PSS happens later */ |
ehci->hcd.state = USB_STATE_RUNNING; |
|
/* make sure ehci_work scans these */ |
ehci->next_uframe = readl (&ehci->regs->frame_index) |
% (ehci->periodic_size << 3); |
return 0; |
} |
|
static int disable_periodic (struct ehci_hcd *ehci) |
{ |
u32 cmd; |
int status; |
|
/* did setting PSE not take effect yet? |
* takes effect only at frame boundaries... |
*/ |
status = handshake (&ehci->regs->status, STS_PSS, STS_PSS, 9 * 125); |
if (status != 0) { |
ehci->hcd.state = USB_STATE_HALT; |
return status; |
} |
|
cmd = readl (&ehci->regs->command) & ~CMD_PSE; |
writel (cmd, &ehci->regs->command); |
/* posted write ... */ |
|
ehci->next_uframe = -1; |
return 0; |
} |
|
/*-------------------------------------------------------------------------*/ |
|
// FIXME microframe periods not yet handled |
|
static void intr_deschedule ( |
struct ehci_hcd *ehci, |
struct ehci_qh *qh, |
int wait |
) { |
int status; |
unsigned frame = qh->start; |
|
do { |
periodic_unlink (ehci, frame, qh); |
qh_put (ehci, qh); |
frame += qh->period; |
} while (frame < ehci->periodic_size); |
|
qh->qh_state = QH_STATE_UNLINK; |
qh->qh_next.ptr = 0; |
ehci->periodic_sched--; |
|
/* maybe turn off periodic schedule */ |
if (!ehci->periodic_sched) |
status = disable_periodic (ehci); |
else { |
status = 0; |
vdbg ("periodic schedule still enabled"); |
} |
|
/* |
* If the hc may be looking at this qh, then delay a uframe |
* (yeech!) to be sure it's done. |
* No other threads may be mucking with this qh. |
*/ |
if (((ehci_get_frame (&ehci->hcd) - frame) % qh->period) == 0) { |
if (wait) { |
udelay (125); |
qh->hw_next = EHCI_LIST_END; |
} else { |
/* we may not be IDLE yet, but if the qh is empty |
* the race is very short. then if qh also isn't |
* rescheduled soon, it won't matter. otherwise... |
*/ |
vdbg ("intr_deschedule..."); |
} |
} else |
qh->hw_next = EHCI_LIST_END; |
|
qh->qh_state = QH_STATE_IDLE; |
|
/* update per-qh bandwidth utilization (for usbfs) */ |
hcd_to_bus (&ehci->hcd)->bandwidth_allocated -= |
(qh->usecs + qh->c_usecs) / qh->period; |
|
dbg ("descheduled qh %p, period = %d frame = %d count = %d, urbs = %d", |
qh, qh->period, frame, |
atomic_read (&qh->refcount), ehci->periodic_sched); |
} |
|
static int check_period ( |
struct ehci_hcd *ehci, |
unsigned frame, |
unsigned uframe, |
unsigned period, |
unsigned usecs |
) { |
/* complete split running into next frame? |
* given FSTN support, we could sometimes check... |
*/ |
if (uframe >= 8) |
return 0; |
|
/* |
* 80% periodic == 100 usec/uframe available |
* convert "usecs we need" to "max already claimed" |
*/ |
usecs = 100 - usecs; |
|
do { |
int claimed; |
|
// FIXME delete when intr_submit handles non-empty queues |
// this gives us a one intr/frame limit (vs N/uframe) |
// ... and also lets us avoid tracking split transactions |
// that might collide at a given TT/hub. |
if (ehci->pshadow [frame].ptr) |
return 0; |
|
claimed = periodic_usecs (ehci, frame, uframe); |
if (claimed > usecs) |
return 0; |
|
// FIXME update to handle sub-frame periods |
} while ((frame += period) < ehci->periodic_size); |
|
// success! |
return 1; |
} |
|
static int check_intr_schedule ( |
struct ehci_hcd *ehci, |
unsigned frame, |
unsigned uframe, |
const struct ehci_qh *qh, |
u32 *c_maskp |
) |
{ |
int retval = -ENOSPC; |
|
if (!check_period (ehci, frame, uframe, qh->period, qh->usecs)) |
goto done; |
if (!qh->c_usecs) { |
retval = 0; |
*c_maskp = cpu_to_le32 (0); |
goto done; |
} |
|
/* This is a split transaction; check the bandwidth available for |
* the completion too. Check both worst and best case gaps: worst |
* case is SPLIT near uframe end, and CSPLIT near start ... best is |
* vice versa. Difference can be almost two uframe times, but we |
* reserve unnecessary bandwidth (waste it) this way. (Actually |
* even better cases exist, like immediate device NAK.) |
* |
* FIXME don't even bother unless we know this TT is idle in that |
* range of uframes ... for now, check_period() allows only one |
* interrupt transfer per frame, so needn't check "TT busy" status |
* when scheduling a split (QH, SITD, or FSTN). |
* |
* FIXME ehci 0.96 and above can use FSTNs |
*/ |
if (!check_period (ehci, frame, uframe + qh->gap_uf + 1, |
qh->period, qh->c_usecs)) |
goto done; |
if (!check_period (ehci, frame, uframe + qh->gap_uf, |
qh->period, qh->c_usecs)) |
goto done; |
|
*c_maskp = cpu_to_le32 (0x03 << (8 + uframe + qh->gap_uf)); |
retval = 0; |
done: |
return retval; |
} |
|
static int qh_schedule (struct ehci_hcd *ehci, struct ehci_qh *qh) |
{ |
int status; |
unsigned uframe; |
u32 c_mask; |
unsigned frame; /* 0..(qh->period - 1), or NO_FRAME */ |
|
qh->hw_next = EHCI_LIST_END; |
frame = qh->start; |
|
/* reuse the previous schedule slots, if we can */ |
if (frame < qh->period) { |
uframe = ffs (le32_to_cpup (&qh->hw_info2) & 0x00ff); |
status = check_intr_schedule (ehci, frame, --uframe, |
qh, &c_mask); |
} else { |
uframe = 0; |
c_mask = 0; |
status = -ENOSPC; |
} |
|
/* else scan the schedule to find a group of slots such that all |
* uframes have enough periodic bandwidth available. |
*/ |
if (status) { |
frame = qh->period - 1; |
do { |
for (uframe = 0; uframe < 8; uframe++) { |
status = check_intr_schedule (ehci, |
frame, uframe, qh, |
&c_mask); |
if (status == 0) |
break; |
} |
} while (status && frame--); |
if (status) |
goto done; |
qh->start = frame; |
|
/* reset S-frame and (maybe) C-frame masks */ |
qh->hw_info2 &= ~0xffff; |
qh->hw_info2 |= cpu_to_le32 (1 << uframe) | c_mask; |
} else |
dbg ("reused previous qh %p schedule", qh); |
|
/* stuff into the periodic schedule */ |
qh->qh_state = QH_STATE_LINKED; |
dbg ("scheduled qh %p usecs %d/%d period %d.0 starting %d.%d (gap %d)", |
qh, qh->usecs, qh->c_usecs, |
qh->period, frame, uframe, qh->gap_uf); |
do { |
if (unlikely (ehci->pshadow [frame].ptr != 0)) { |
|
// FIXME -- just link toward the end, before any qh with a shorter period, |
// AND accommodate it already having been linked here (after some other qh) |
// AS WELL AS updating the schedule checking logic |
|
BUG (); |
} else { |
ehci->pshadow [frame].qh = qh_get (qh); |
ehci->periodic [frame] = |
QH_NEXT (qh->qh_dma); |
} |
wmb (); |
frame += qh->period; |
} while (frame < ehci->periodic_size); |
|
/* update per-qh bandwidth for usbfs */ |
hcd_to_bus (&ehci->hcd)->bandwidth_allocated += |
(qh->usecs + qh->c_usecs) / qh->period; |
|
/* maybe enable periodic schedule processing */ |
if (!ehci->periodic_sched++) |
status = enable_periodic (ehci); |
done: |
return status; |
} |
|
static int intr_submit ( |
struct ehci_hcd *ehci, |
struct urb *urb, |
struct list_head *qtd_list, |
int mem_flags |
) { |
unsigned epnum; |
unsigned long flags; |
struct ehci_qh *qh; |
struct hcd_dev *dev; |
int is_input; |
int status = 0; |
struct list_head empty; |
|
/* get endpoint and transfer/schedule data */ |
epnum = usb_pipeendpoint (urb->pipe); |
is_input = usb_pipein (urb->pipe); |
if (is_input) |
epnum |= 0x10; |
|
spin_lock_irqsave (&ehci->lock, flags); |
dev = (struct hcd_dev *)urb->dev->hcpriv; |
|
/* get qh and force any scheduling errors */ |
INIT_LIST_HEAD (&empty); |
qh = qh_append_tds (ehci, urb, &empty, epnum, &dev->ep [epnum]); |
if (qh == 0) { |
status = -ENOMEM; |
goto done; |
} |
if (qh->qh_state == QH_STATE_IDLE) { |
if ((status = qh_schedule (ehci, qh)) != 0) |
goto done; |
} |
|
/* then queue the urb's tds to the qh */ |
qh = qh_append_tds (ehci, urb, qtd_list, epnum, &dev->ep [epnum]); |
BUG_ON (qh == 0); |
|
/* ... update usbfs periodic stats */ |
hcd_to_bus (&ehci->hcd)->bandwidth_int_reqs++; |
|
done: |
spin_unlock_irqrestore (&ehci->lock, flags); |
if (status) |
qtd_list_free (ehci, urb, qtd_list); |
|
return status; |
} |
|
static unsigned |
intr_complete ( |
struct ehci_hcd *ehci, |
unsigned frame, |
struct ehci_qh *qh, |
struct pt_regs *regs |
) { |
unsigned count; |
|
/* nothing to report? */ |
if (likely ((qh->hw_token & __constant_cpu_to_le32 (QTD_STS_ACTIVE)) |
!= 0)) |
return 0; |
if (unlikely (list_empty (&qh->qtd_list))) { |
dbg ("intr qh %p no TDs?", qh); |
return 0; |
} |
|
/* handle any completions */ |
count = qh_completions (ehci, qh, regs); |
|
if (unlikely (list_empty (&qh->qtd_list))) |
intr_deschedule (ehci, qh, 0); |
|
return count; |
} |
|
/*-------------------------------------------------------------------------*/ |
|
static void |
itd_free_list (struct ehci_hcd *ehci, struct urb *urb) |
{ |
struct ehci_itd *first_itd = urb->hcpriv; |
|
while (!list_empty (&first_itd->itd_list)) { |
struct ehci_itd *itd; |
|
itd = list_entry ( |
first_itd->itd_list.next, |
struct ehci_itd, itd_list); |
list_del (&itd->itd_list); |
pci_pool_free (ehci->itd_pool, itd, itd->itd_dma); |
} |
pci_pool_free (ehci->itd_pool, first_itd, first_itd->itd_dma); |
urb->hcpriv = 0; |
} |
|
static int |
itd_fill ( |
struct ehci_hcd *ehci, |
struct ehci_itd *itd, |
struct urb *urb, |
unsigned index, // urb->iso_frame_desc [index] |
dma_addr_t dma // mapped transfer buffer |
) { |
u64 temp; |
u32 buf1; |
unsigned i, epnum, maxp, multi; |
unsigned length; |
int is_input; |
|
itd->hw_next = EHCI_LIST_END; |
itd->urb = urb; |
itd->index = index; |
|
/* tell itd about its transfer buffer, max 2 pages */ |
length = urb->iso_frame_desc [index].length; |
dma += urb->iso_frame_desc [index].offset; |
temp = dma & ~0x0fff; |
for (i = 0; i < 2; i++) { |
itd->hw_bufp [i] = cpu_to_le32 ((u32) temp); |
itd->hw_bufp_hi [i] = cpu_to_le32 ((u32)(temp >> 32)); |
temp += 0x1000; |
} |
itd->buf_dma = dma; |
|
/* |
* this might be a "high bandwidth" highspeed endpoint, |
* as encoded in the ep descriptor's maxpacket field |
*/ |
epnum = usb_pipeendpoint (urb->pipe); |
is_input = usb_pipein (urb->pipe); |
if (is_input) { |
maxp = urb->dev->epmaxpacketin [epnum]; |
buf1 = (1 << 11); |
} else { |
maxp = urb->dev->epmaxpacketout [epnum]; |
buf1 = 0; |
} |
buf1 |= (maxp & 0x03ff); |
multi = 1; |
multi += (maxp >> 11) & 0x03; |
maxp &= 0x03ff; |
maxp *= multi; |
|
/* transfer can't fit in any uframe? */ |
if (length < 0 || maxp < length) { |
dbg ("BAD iso packet: %d bytes, max %d, urb %p [%d] (of %d)", |
length, maxp, urb, index, |
urb->iso_frame_desc [index].length); |
return -ENOSPC; |
} |
itd->usecs = usb_calc_bus_time (USB_SPEED_HIGH, is_input, 1, length); |
|
/* "plus" info in low order bits of buffer pointers */ |
itd->hw_bufp [0] |= cpu_to_le32 ((epnum << 8) | urb->dev->devnum); |
itd->hw_bufp [1] |= cpu_to_le32 (buf1); |
itd->hw_bufp [2] |= cpu_to_le32 (multi); |
|
/* figure hw_transaction[] value (it's scheduled later) */ |
itd->transaction = EHCI_ISOC_ACTIVE; |
itd->transaction |= dma & 0x0fff; /* offset; buffer=0 */ |
if ((index + 1) == urb->number_of_packets) |
itd->transaction |= EHCI_ITD_IOC; /* end-of-urb irq */ |
itd->transaction |= length << 16; |
cpu_to_le32s (&itd->transaction); |
|
return 0; |
} |
|
static int |
itd_urb_transaction ( |
struct ehci_hcd *ehci, |
struct urb *urb, |
int mem_flags |
) { |
int frame_index; |
struct ehci_itd *first_itd, *itd; |
int status; |
dma_addr_t itd_dma; |
|
/* allocate/init ITDs */ |
for (frame_index = 0, first_itd = 0; |
frame_index < urb->number_of_packets; |
frame_index++) { |
itd = pci_pool_alloc_usb (ehci->itd_pool, mem_flags, &itd_dma); |
if (!itd) { |
status = -ENOMEM; |
goto fail; |
} |
memset (itd, 0, sizeof *itd); |
itd->itd_dma = itd_dma; |
|
status = itd_fill (ehci, itd, urb, frame_index, |
urb->transfer_dma); |
if (status != 0) |
goto fail; |
|
if (first_itd) |
list_add_tail (&itd->itd_list, |
&first_itd->itd_list); |
else { |
INIT_LIST_HEAD (&itd->itd_list); |
urb->hcpriv = first_itd = itd; |
} |
} |
urb->error_count = 0; |
return 0; |
|
fail: |
if (urb->hcpriv) |
itd_free_list (ehci, urb); |
return status; |
} |
|
/*-------------------------------------------------------------------------*/ |
|
static inline void |
itd_link (struct ehci_hcd *ehci, unsigned frame, struct ehci_itd *itd) |
{ |
/* always prepend ITD/SITD ... only QH tree is order-sensitive */ |
itd->itd_next = ehci->pshadow [frame]; |
itd->hw_next = ehci->periodic [frame]; |
ehci->pshadow [frame].itd = itd; |
ehci->periodic [frame] = cpu_to_le32 (itd->itd_dma) | Q_TYPE_ITD; |
} |
|
/* |
* return zero on success, else -errno |
* - start holds first uframe to start scheduling into |
* - max is the first uframe it's NOT (!) OK to start scheduling into |
* math to be done modulo "mod" (ehci->periodic_size << 3) |
*/ |
static int get_iso_range ( |
struct ehci_hcd *ehci, |
struct urb *urb, |
unsigned *start, |
unsigned *max, |
unsigned mod |
) { |
struct list_head *lh; |
struct hcd_dev *dev = urb->dev->hcpriv; |
int last = -1; |
unsigned now, span, end; |
|
span = urb->interval * urb->number_of_packets; |
|
/* first see if we know when the next transfer SHOULD happen */ |
list_for_each (lh, &dev->urb_list) { |
struct urb *u; |
struct ehci_itd *itd; |
unsigned s; |
|
u = list_entry (lh, struct urb, urb_list); |
if (u == urb || u->pipe != urb->pipe) |
continue; |
if (u->interval != urb->interval) { /* must not change! */ |
dbg ("urb %p interval %d ... != %p interval %d", |
u, u->interval, urb, urb->interval); |
return -EINVAL; |
} |
|
/* URB for this endpoint... covers through when? */ |
itd = urb->hcpriv; |
s = itd->uframe + u->interval * u->number_of_packets; |
if (last < 0) |
last = s; |
else { |
/* |
* So far we can only queue two ISO URBs... |
* |
* FIXME do interval math, figure out whether |
* this URB is "before" or not ... also, handle |
* the case where the URB might have completed, |
* but hasn't yet been processed. |
*/ |
dbg ("NYET: queue >2 URBs per ISO endpoint"); |
return -EDOM; |
} |
} |
|
/* calculate the legal range [start,max) */ |
now = readl (&ehci->regs->frame_index) + 1; /* next uframe */ |
if (!ehci->periodic_sched) |
now += 8; /* startup delay */ |
now %= mod; |
end = now + mod; |
if (last < 0) { |
*start = now + ehci->i_thresh + /* paranoia */ 1; |
*max = end - span; |
if (*max < *start + 1) |
*max = *start + 1; |
} else { |
*start = last % mod; |
*max = (last + 1) % mod; |
} |
|
/* explicit start frame? */ |
if (!(urb->transfer_flags & URB_ISO_ASAP)) { |
unsigned temp; |
|
/* sanity check: must be in range */ |
urb->start_frame %= ehci->periodic_size; |
temp = urb->start_frame << 3; |
if (temp < *start) |
temp += mod; |
if (temp > *max) |
return -EDOM; |
|
/* use that explicit start frame */ |
*start = urb->start_frame << 3; |
temp += 8; |
if (temp < *max) |
*max = temp; |
} |
|
// FIXME minimize wraparound to "now" ... insist max+span |
// (and start+span) remains a few frames short of "end" |
|
*max %= ehci->periodic_size; |
if ((*start + span) < end) |
return 0; |
return -EFBIG; |
} |
|
static int |
itd_schedule (struct ehci_hcd *ehci, struct urb *urb) |
{ |
unsigned start, max, i; |
int status; |
unsigned mod = ehci->periodic_size << 3; |
|
for (i = 0; i < urb->number_of_packets; i++) { |
urb->iso_frame_desc [i].status = -EINPROGRESS; |
urb->iso_frame_desc [i].actual_length = 0; |
} |
|
if ((status = get_iso_range (ehci, urb, &start, &max, mod)) != 0) |
return status; |
|
do { |
unsigned uframe; |
unsigned usecs; |
struct ehci_itd *itd; |
|
/* check schedule: enough space? */ |
itd = urb->hcpriv; |
uframe = start; |
for (i = 0, uframe = start; |
i < urb->number_of_packets; |
i++, uframe += urb->interval) { |
uframe %= mod; |
|
/* can't commit more than 80% periodic == 100 usec */ |
if (periodic_usecs (ehci, uframe >> 3, uframe & 0x7) |
> (100 - itd->usecs)) { |
itd = 0; |
break; |
} |
itd = list_entry (itd->itd_list.next, |
struct ehci_itd, itd_list); |
} |
if (!itd) |
continue; |
|
/* that's where we'll schedule this! */ |
itd = urb->hcpriv; |
urb->start_frame = start >> 3; |
vdbg ("ISO urb %p (%d packets period %d) starting %d.%d", |
urb, urb->number_of_packets, urb->interval, |
urb->start_frame, start & 0x7); |
for (i = 0, uframe = start, usecs = 0; |
i < urb->number_of_packets; |
i++, uframe += urb->interval) { |
uframe %= mod; |
|
itd->uframe = uframe; |
itd->hw_transaction [uframe & 0x07] = itd->transaction; |
itd_link (ehci, (uframe >> 3) % ehci->periodic_size, |
itd); |
wmb (); |
usecs += itd->usecs; |
|
itd = list_entry (itd->itd_list.next, |
struct ehci_itd, itd_list); |
} |
|
/* update bandwidth utilization records (for usbfs) |
* |
* FIXME This claims each URB queued to an endpoint, as if |
* transfers were concurrent, not sequential. So bandwidth |
* typically gets double-billed ... comes from tying it to |
* URBs rather than endpoints in the schedule. Luckily we |
* don't use this usbfs data for serious decision making. |
*/ |
usecs /= urb->number_of_packets; |
usecs /= urb->interval; |
usecs >>= 3; |
if (usecs < 1) |
usecs = 1; |
usb_claim_bandwidth (urb->dev, urb, usecs, 1); |
|
/* maybe enable periodic schedule processing */ |
if (!ehci->periodic_sched++) { |
if ((status = enable_periodic (ehci)) != 0) { |
// FIXME deschedule right away |
err ("itd_schedule, enable = %d", status); |
} |
} |
|
return 0; |
|
} while ((start = ++start % mod) != max); |
|
/* no room in the schedule */ |
dbg ("urb %p, CAN'T SCHEDULE", urb); |
return -ENOSPC; |
} |
|
/*-------------------------------------------------------------------------*/ |
|
#define ISO_ERRS (EHCI_ISOC_BUF_ERR | EHCI_ISOC_BABBLE | EHCI_ISOC_XACTERR) |
|
static unsigned |
itd_complete ( |
struct ehci_hcd *ehci, |
struct ehci_itd *itd, |
unsigned uframe, |
struct pt_regs *regs |
) { |
struct urb *urb = itd->urb; |
struct usb_iso_packet_descriptor *desc; |
u32 t; |
|
/* update status for this uframe's transfers */ |
desc = &urb->iso_frame_desc [itd->index]; |
|
t = itd->hw_transaction [uframe]; |
itd->hw_transaction [uframe] = 0; |
if (t & EHCI_ISOC_ACTIVE) |
desc->status = -EXDEV; |
else if (t & ISO_ERRS) { |
urb->error_count++; |
if (t & EHCI_ISOC_BUF_ERR) |
desc->status = usb_pipein (urb->pipe) |
? -ENOSR /* couldn't read */ |
: -ECOMM; /* couldn't write */ |
else if (t & EHCI_ISOC_BABBLE) |
desc->status = -EOVERFLOW; |
else /* (t & EHCI_ISOC_XACTERR) */ |
desc->status = -EPROTO; |
|
/* HC need not update length with this error */ |
if (!(t & EHCI_ISOC_BABBLE)) |
desc->actual_length += EHCI_ITD_LENGTH (t); |
} else { |
desc->status = 0; |
desc->actual_length += EHCI_ITD_LENGTH (t); |
} |
|
vdbg ("itd %p urb %p packet %d/%d trans %x status %d len %d", |
itd, urb, itd->index + 1, urb->number_of_packets, |
t, desc->status, desc->actual_length); |
|
/* handle completion now? */ |
if ((itd->index + 1) != urb->number_of_packets) |
return 0; |
|
/* |
* Always give the urb back to the driver ... expect it to submit |
* a new urb (or resubmit this), and to have another already queued |
* when un-interrupted transfers are needed. |
* |
* NOTE that for now we don't accelerate ISO unlinks; they just |
* happen according to the current schedule. Means a delay of |
* up to about a second (max). |
*/ |
itd_free_list (ehci, urb); |
if (urb->status == -EINPROGRESS) |
urb->status = 0; |
|
/* complete() can reenter this HCD */ |
spin_unlock (&ehci->lock); |
usb_hcd_giveback_urb (&ehci->hcd, urb, regs); |
spin_lock (&ehci->lock); |
|
/* defer stopping schedule; completion can submit */ |
ehci->periodic_sched--; |
if (!ehci->periodic_sched) |
(void) disable_periodic (ehci); |
|
return 1; |
} |
|
/*-------------------------------------------------------------------------*/ |
|
static int itd_submit (struct ehci_hcd *ehci, struct urb *urb, int mem_flags) |
{ |
int status; |
unsigned long flags; |
|
dbg ("itd_submit urb %p", urb); |
|
/* allocate ITDs w/o locking anything */ |
status = itd_urb_transaction (ehci, urb, mem_flags); |
if (status < 0) |
return status; |
|
/* schedule ... need to lock */ |
spin_lock_irqsave (&ehci->lock, flags); |
status = itd_schedule (ehci, urb); |
spin_unlock_irqrestore (&ehci->lock, flags); |
if (status < 0) |
itd_free_list (ehci, urb); |
|
return status; |
} |
|
#ifdef have_split_iso |
|
/*-------------------------------------------------------------------------*/ |
|
/* |
* "Split ISO TDs" ... used for USB 1.1 devices going through |
* the TTs in USB 2.0 hubs. |
* |
* FIXME not yet implemented |
*/ |
|
#endif /* have_split_iso */ |
|
/*-------------------------------------------------------------------------*/ |
|
static void |
scan_periodic (struct ehci_hcd *ehci, struct pt_regs *regs) |
{ |
unsigned frame, clock, now_uframe, mod; |
unsigned count = 0; |
|
mod = ehci->periodic_size << 3; |
|
/* |
* When running, scan from last scan point up to "now" |
* else clean up by scanning everything that's left. |
* Touches as few pages as possible: cache-friendly. |
* Don't scan ISO entries more than once, though. |
*/ |
frame = ehci->next_uframe >> 3; |
if (HCD_IS_RUNNING (ehci->hcd.state)) |
now_uframe = readl (&ehci->regs->frame_index); |
else |
now_uframe = (frame << 3) - 1; |
now_uframe %= mod; |
clock = now_uframe >> 3; |
|
for (;;) { |
union ehci_shadow q, *q_p; |
u32 type, *hw_p; |
unsigned uframes; |
|
restart: |
/* scan schedule to _before_ current frame index */ |
if (frame == clock) |
uframes = now_uframe & 0x07; |
else |
uframes = 8; |
|
q_p = &ehci->pshadow [frame]; |
hw_p = &ehci->periodic [frame]; |
q.ptr = q_p->ptr; |
type = Q_NEXT_TYPE (*hw_p); |
|
/* scan each element in frame's queue for completions */ |
while (q.ptr != 0) { |
int last; |
unsigned uf; |
union ehci_shadow temp; |
|
switch (type) { |
case Q_TYPE_QH: |
last = (q.qh->hw_next == EHCI_LIST_END); |
temp = q.qh->qh_next; |
type = Q_NEXT_TYPE (q.qh->hw_next); |
count += intr_complete (ehci, frame, |
qh_get (q.qh), regs); |
qh_put (ehci, q.qh); |
q = temp; |
break; |
case Q_TYPE_FSTN: |
last = (q.fstn->hw_next == EHCI_LIST_END); |
/* for "save place" FSTNs, look at QH entries |
* in the previous frame for completions. |
*/ |
if (q.fstn->hw_prev != EHCI_LIST_END) { |
dbg ("ignoring completions from FSTNs"); |
} |
type = Q_NEXT_TYPE (q.fstn->hw_next); |
q = q.fstn->fstn_next; |
break; |
case Q_TYPE_ITD: |
last = (q.itd->hw_next == EHCI_LIST_END); |
|
/* Unlink each (S)ITD we see, since the ISO |
* URB model forces constant rescheduling. |
* That complicates sharing uframes in ITDs, |
* and means we need to skip uframes the HC |
* hasn't yet processed. |
*/ |
for (uf = 0; uf < uframes; uf++) { |
if (q.itd->hw_transaction [uf] != 0) { |
temp = q; |
*q_p = q.itd->itd_next; |
*hw_p = q.itd->hw_next; |
type = Q_NEXT_TYPE (*hw_p); |
|
/* might free q.itd ... */ |
count += itd_complete (ehci, |
temp.itd, uf, regs); |
break; |
} |
} |
/* we might skip this ITD's uframe ... */ |
if (uf == uframes) { |
q_p = &q.itd->itd_next; |
hw_p = &q.itd->hw_next; |
type = Q_NEXT_TYPE (q.itd->hw_next); |
} |
|
q = *q_p; |
break; |
#ifdef have_split_iso |
case Q_TYPE_SITD: |
last = (q.sitd->hw_next == EHCI_LIST_END); |
sitd_complete (ehci, q.sitd); |
type = Q_NEXT_TYPE (q.sitd->hw_next); |
|
// FIXME unlink SITD after split completes |
q = q.sitd->sitd_next; |
break; |
#endif /* have_split_iso */ |
default: |
dbg ("corrupt type %d frame %d shadow %p", |
type, frame, q.ptr); |
// BUG (); |
last = 1; |
q.ptr = 0; |
} |
|
/* did completion remove an interior q entry? */ |
if (unlikely (q.ptr == 0 && !last)) |
goto restart; |
} |
|
/* stop when we catch up to the HC */ |
|
// FIXME: this assumes we won't get lapped when |
// latencies climb; that should be rare, but... |
// detect it, and just go all the way around. |
// FLR might help detect this case, so long as latencies |
// don't exceed periodic_size msec (default 1.024 sec). |
|
// FIXME: likewise assumes HC doesn't halt mid-scan |
|
if (frame == clock) { |
unsigned now; |
|
if (!HCD_IS_RUNNING (ehci->hcd.state)) |
break; |
ehci->next_uframe = now_uframe; |
now = readl (&ehci->regs->frame_index) % mod; |
if (now_uframe == now) |
break; |
|
/* rescan the rest of this frame, then ... */ |
now_uframe = now; |
clock = now_uframe >> 3; |
} else |
frame = (frame + 1) % ehci->periodic_size; |
} |
} |