/** * 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); INIT_LIST_HEAD(&ring->cancelled_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); UBI_DMA_FLUSH(&prev->trbs[TRBS_PER_SEGMENT-1], sizeof(prev->trbs[TRBS_PER_SEGMENT-1])); xhci_dbg(xhci, "Wrote link toggle flag to" " segment %p (virtual), 0x%llx (DMA)\n", prev, (unsigned long long)prev->dma); } /* The ring is empty, so the enqueue pointer == dequeue pointer */ ring->enqueue = ring->first_seg->trbs; ring->enq_seg = ring->first_seg; ring->dequeue = ring->enqueue; ring->deq_seg = ring->first_seg; /* The ring is initialized to 0. The producer must write 1 to the cycle * bit to handover ownership of the TRB, so PCS = 1. The consumer must * compare CCS to the cycle bit to check ownership, so CCS = 1. */ ring->cycle_state = 1; return ring; fail: xhci_ring_free(xhci, ring); return 0; }
/** * 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; }
/** * 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; }