/* 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]; __le32 *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 = NULL; return 1; }
/* caller must hold ehci->lock */ static void periodic_unlink (struct ehci_hcd *ehci, unsigned frame, void *ptr) { union ehci_shadow *prev_p = &ehci->pshadow [frame]; __le32 *hw_p = &ehci->periodic [frame]; union ehci_shadow here = *prev_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.hw_next; here = *prev_p; } /* an interrupt entry (at list end) could have been shared */ if (!here.ptr) return; /* update shadow and hardware lists ... the old "next" pointers * from ptr may still be in use, the caller updates them. */ *prev_p = *periodic_next_shadow (&here, Q_NEXT_TYPE (*hw_p)); *hw_p = *here.hw_next; }
static void periodic_tt_usecs ( struct ehci_hcd *ehci, struct usb_device *dev, unsigned frame, unsigned short tt_usecs[8] ) { __hc32 *hw_p = &ehci->periodic [frame]; union ehci_shadow *q = &ehci->pshadow [frame]; unsigned char uf; memset(tt_usecs, 0, 16); while (q->ptr) { switch (hc32_to_cpu(ehci, Q_NEXT_TYPE(ehci, *hw_p))) { case Q_TYPE_ITD: hw_p = &q->itd->hw_next; q = &q->itd->itd_next; continue; case Q_TYPE_QH: if (same_tt(dev, q->qh->dev)) { uf = tt_start_uframe(ehci, q->qh->hw->hw_info2); tt_usecs[uf] += q->qh->tt_usecs; } hw_p = &q->qh->hw->hw_next; q = &q->qh->qh_next; continue; 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; } hw_p = &q->sitd->hw_next; q = &q->sitd->sitd_next; continue; default: ehci_dbg(ehci, "ignoring periodic frame %d FSTN\n", frame); hw_p = &q->fstn->hw_next; q = &q->fstn->fstn_next; } } carryover_tt_bandwidth(tt_usecs); if (max_tt_usecs[7] < tt_usecs[7]) ehci_err(ehci, "frame %d tt sched overrun: %d usecs\n", frame, tt_usecs[7] - max_tt_usecs[7]); }
static void periodic_unlink (struct ehci_hcd *ehci, unsigned frame, void *ptr) { union ehci_shadow *prev_p = &ehci->pshadow[frame]; __hc32 *hw_p = &ehci->periodic[frame]; union ehci_shadow here = *prev_p; while (here.ptr && here.ptr != ptr) { prev_p = periodic_next_shadow(ehci, prev_p, Q_NEXT_TYPE(ehci, *hw_p)); hw_p = shadow_next_periodic(ehci, &here, Q_NEXT_TYPE(ehci, *hw_p)); here = *prev_p; } if (!here.ptr) return; *prev_p = *periodic_next_shadow(ehci, &here, Q_NEXT_TYPE(ehci, *hw_p)); *hw_p = *shadow_next_periodic(ehci, &here, Q_NEXT_TYPE(ehci, *hw_p)); }
/* how many of the uframe's 125 usecs are allocated? */ static unsigned short periodic_usecs (struct ehci_hcd *ehci, unsigned frame, unsigned uframe) { __le32 *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; hw_p = &q->qh->hw_next; 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) { ehci_dbg (ehci, "ignoring FSTN cost ...\n"); } hw_p = &q->fstn->hw_next; q = &q->fstn->fstn_next; break; case Q_TYPE_ITD: usecs += q->itd->usecs [uframe]; hw_p = &q->itd->hw_next; q = &q->itd->itd_next; break; case Q_TYPE_SITD: /* is it in the S-mask? (count SPLIT, DATA) */ if (q->sitd->hw_uframe & cpu_to_le32 (1 << uframe)) { if (q->sitd->hw_fullspeed_ep & __constant_cpu_to_le32 (1<<31)) usecs += q->sitd->stream->usecs; else /* worst case for OUT start-split */ usecs += HS_USECS_ISO (188); } /* ... C-mask? (count CSPLIT, DATA) */ if (q->sitd->hw_uframe & cpu_to_le32 (1 << (8 + uframe))) { /* worst case for IN complete-split */ usecs += q->sitd->stream->c_usecs; } hw_p = &q->sitd->hw_next; q = &q->sitd->sitd_next; break; default: BUG (); } } #ifdef DEBUG if (usecs > 100) err ("overallocated uframe %d, periodic is %d usecs", frame * 8 + uframe, usecs); #endif return usecs; }
/* return true iff the device's transaction translator is available * for a periodic transfer starting at the specified frame, using * all the uframes in the mask. */ static int tt_no_collision ( struct ehci_hcd *ehci, unsigned period, struct usb_device *dev, unsigned frame, u32 uf_mask ) { if (period == 0) /* error */ return 0; /* note bandwidth wastage: split never follows csplit * (different dev or endpoint) until the next uframe. * calling convention doesn't make that distinction. */ for (; frame < ehci->periodic_size; frame += period) { union ehci_shadow here; __le32 type; here = ehci->pshadow [frame]; type = Q_NEXT_TYPE (ehci->periodic [frame]); while (here.ptr) { switch (type) { case Q_TYPE_ITD: type = Q_NEXT_TYPE (here.itd->hw_next); here = here.itd->itd_next; continue; case Q_TYPE_QH: if (same_tt (dev, here.qh->dev)) { u32 mask; mask = le32_to_cpu (here.qh->hw_info2); /* "knows" no gap is needed */ mask |= mask >> 8; if (mask & uf_mask) break; } type = Q_NEXT_TYPE (here.qh->hw_next); here = here.qh->qh_next; continue; case Q_TYPE_SITD: if (same_tt (dev, here.itd->urb->dev)) { u16 mask; mask = le32_to_cpu (here.sitd ->hw_uframe); /* FIXME assumes no gap for IN! */ mask |= mask >> 8; if (mask & uf_mask) break; } type = Q_NEXT_TYPE (here.qh->hw_next); here = here.sitd->sitd_next; continue; // case Q_TYPE_FSTN: default: ehci_dbg (ehci, "periodic frame %d bogus type %d\n", frame, type); } /* collision or error */ return 0; }
static unsigned short periodic_usecs (struct ehci_hcd *ehci, unsigned frame, unsigned uframe) { __hc32 *hw_p = &ehci->periodic [frame]; union ehci_shadow *q = &ehci->pshadow [frame]; unsigned usecs = 0; struct ehci_qh_hw *hw; while (q->ptr) { switch (hc32_to_cpu(ehci, Q_NEXT_TYPE(ehci, *hw_p))) { case Q_TYPE_QH: hw = q->qh->hw; if (hw->hw_info2 & cpu_to_hc32(ehci, 1 << uframe)) usecs += q->qh->usecs; if (hw->hw_info2 & cpu_to_hc32(ehci, 1 << (8 + uframe))) usecs += q->qh->c_usecs; hw_p = &hw->hw_next; q = &q->qh->qh_next; break; default: if (q->fstn->hw_prev != EHCI_LIST_END(ehci)) { ehci_dbg (ehci, "ignoring FSTN cost ...\n"); } hw_p = &q->fstn->hw_next; q = &q->fstn->fstn_next; break; case Q_TYPE_ITD: if (q->itd->hw_transaction[uframe]) usecs += q->itd->stream->usecs; hw_p = &q->itd->hw_next; q = &q->itd->itd_next; break; case Q_TYPE_SITD: if (q->sitd->hw_uframe & cpu_to_hc32(ehci, 1 << uframe)) { if (q->sitd->hw_fullspeed_ep & cpu_to_hc32(ehci, 1<<31)) usecs += q->sitd->stream->usecs; else usecs += HS_USECS_ISO (188); } if (q->sitd->hw_uframe & cpu_to_hc32(ehci, 1 << (8 + uframe))) { usecs += q->sitd->stream->c_usecs; } hw_p = &q->sitd->hw_next; q = &q->sitd->sitd_next; break; } } #ifdef DEBUG if (usecs > 100) ehci_err (ehci, "uframe %d sched overrun: %d usecs\n", frame * 8 + uframe, usecs); #endif return usecs; }
static int tt_no_collision ( struct ehci_hcd *ehci, unsigned period, struct usb_device *dev, unsigned frame, u32 uf_mask ) { if (period == 0) return 0; for (; frame < ehci->periodic_size; frame += period) { union ehci_shadow here; __hc32 type; struct ehci_qh_hw *hw; here = ehci->pshadow [frame]; type = Q_NEXT_TYPE(ehci, ehci->periodic [frame]); while (here.ptr) { switch (hc32_to_cpu(ehci, type)) { case Q_TYPE_ITD: type = Q_NEXT_TYPE(ehci, here.itd->hw_next); here = here.itd->itd_next; continue; case Q_TYPE_QH: hw = here.qh->hw; if (same_tt (dev, here.qh->dev)) { u32 mask; mask = hc32_to_cpu(ehci, hw->hw_info2); mask |= mask >> 8; if (mask & uf_mask) break; } type = Q_NEXT_TYPE(ehci, hw->hw_next); here = here.qh->qh_next; continue; case Q_TYPE_SITD: if (same_tt (dev, here.sitd->urb->dev)) { u16 mask; mask = hc32_to_cpu(ehci, here.sitd ->hw_uframe); mask |= mask >> 8; if (mask & uf_mask) break; } type = Q_NEXT_TYPE(ehci, here.sitd->hw_next); here = here.sitd->sitd_next; continue; default: ehci_dbg (ehci, "periodic frame %d bogus type %d\n", frame, type); } return 0; }