/** * Create a new ring with zero or more segments. * * Link each segment together into a ring. * Set the end flag and the cycle toggle bit on the last segment. * See section 4.9.1 and figures 15 and 16. */ static struct xhci_ring *xhci_ring_alloc(struct xhci_hcd *xhci, unsigned int num_segs, bool link_trbs, gfp_t flags) { struct xhci_ring *ring; struct xhci_segment *prev; ring = kzalloc(sizeof *(ring), flags); xhci_dbg(xhci, "Allocating ring at %p\n", ring); if (!ring) return 0; INIT_LIST_HEAD(&ring->td_list); if (num_segs == 0) return ring; ring->first_seg = xhci_segment_alloc(xhci, flags); if (!ring->first_seg) goto fail; num_segs--; prev = ring->first_seg; while (num_segs > 0) { struct xhci_segment *next; next = xhci_segment_alloc(xhci, flags); if (!next) goto fail; xhci_link_segments(xhci, prev, next, link_trbs); prev = next; num_segs--; } xhci_link_segments(xhci, prev, ring->first_seg, link_trbs); if (link_trbs) { /* See section 4.9.2.1 and 6.4.4.1 */ prev->trbs[TRBS_PER_SEGMENT-1].link.control |= (LINK_TOGGLE); xhci_dbg(xhci, "Wrote link toggle flag to" " segment %p (virtual), 0x%llx (DMA)\n", prev, (unsigned long long)prev->dma); } xhci_initialize_ring_info(ring); return ring; fail: xhci_ring_free(xhci, ring); return 0; }
/* Zero an endpoint ring (except for link TRBs) and move the enqueue and dequeue * pointers to the beginning of the ring. */ static void xhci_reinit_cached_ring(struct xhci_hcd *xhci, struct xhci_ring *ring) { struct xhci_segment *seg = ring->first_seg; do { memset(seg->trbs, 0, sizeof(union xhci_trb)*TRBS_PER_SEGMENT); /* All endpoint rings have link TRBs */ xhci_link_segments(xhci, seg, seg->next, 1); seg = seg->next; } while (seg != ring->first_seg); xhci_initialize_ring_info(ring); /* td list should be empty since all URBs have been cancelled, * but just in case... */ INIT_LIST_HEAD(&ring->td_list); }
/** * Create a new ring with zero or more segments. * TODO: current code only uses one-time-allocated single-segment rings * of 1KB anyway, so we might as well get rid of all the segment and * linking code (and maybe increase the size a bit, e.g. 4KB). * * * Link each segment together into a ring. * Set the end flag and the cycle toggle bit on the last segment. * See section 4.9.2 and figures 15 and 16 of XHCI spec rev1.0. * * @param num_segs number of segments in the ring * @param link_trbs flag to indicate whether to link the trbs or NOT * @return pointer to the newly created RING */ struct xhci_ring *xhci_ring_alloc(unsigned int num_segs, bool link_trbs) { struct xhci_ring *ring; struct xhci_segment *prev; ring = (struct xhci_ring *)malloc(sizeof(struct xhci_ring)); BUG_ON(!ring); if (num_segs == 0) return ring; ring->first_seg = xhci_segment_alloc(); BUG_ON(!ring->first_seg); num_segs--; prev = ring->first_seg; while (num_segs > 0) { struct xhci_segment *next; next = xhci_segment_alloc(); BUG_ON(!next); xhci_link_segments(prev, next, link_trbs); prev = next; num_segs--; } xhci_link_segments(prev, ring->first_seg, link_trbs); if (link_trbs) { /* See section 4.9.2.1 and 6.4.4.1 */ prev->trbs[TRBS_PER_SEGMENT-1].link.control |= cpu_to_le32(LINK_TOGGLE); } xhci_initialize_ring_info(ring); return ring; }