162306a36Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0 262306a36Sopenharmony_ci/* 362306a36Sopenharmony_ci * Cadence CDNSP DRD Driver. 462306a36Sopenharmony_ci * 562306a36Sopenharmony_ci * Copyright (C) 2020 Cadence. 662306a36Sopenharmony_ci * 762306a36Sopenharmony_ci * Author: Pawel Laszczak <pawell@cadence.com> 862306a36Sopenharmony_ci * 962306a36Sopenharmony_ci * Code based on Linux XHCI driver. 1062306a36Sopenharmony_ci * Origin: Copyright (C) 2008 Intel Corp. 1162306a36Sopenharmony_ci */ 1262306a36Sopenharmony_ci 1362306a36Sopenharmony_ci#include <linux/dma-mapping.h> 1462306a36Sopenharmony_ci#include <linux/dmapool.h> 1562306a36Sopenharmony_ci#include <linux/slab.h> 1662306a36Sopenharmony_ci#include <linux/usb.h> 1762306a36Sopenharmony_ci 1862306a36Sopenharmony_ci#include "cdnsp-gadget.h" 1962306a36Sopenharmony_ci#include "cdnsp-trace.h" 2062306a36Sopenharmony_ci 2162306a36Sopenharmony_cistatic void cdnsp_free_stream_info(struct cdnsp_device *pdev, 2262306a36Sopenharmony_ci struct cdnsp_ep *pep); 2362306a36Sopenharmony_ci/* 2462306a36Sopenharmony_ci * Allocates a generic ring segment from the ring pool, sets the dma address, 2562306a36Sopenharmony_ci * initializes the segment to zero, and sets the private next pointer to NULL. 2662306a36Sopenharmony_ci * 2762306a36Sopenharmony_ci * "All components of all Command and Transfer TRBs shall be initialized to '0'" 2862306a36Sopenharmony_ci */ 2962306a36Sopenharmony_cistatic struct cdnsp_segment *cdnsp_segment_alloc(struct cdnsp_device *pdev, 3062306a36Sopenharmony_ci unsigned int cycle_state, 3162306a36Sopenharmony_ci unsigned int max_packet, 3262306a36Sopenharmony_ci gfp_t flags) 3362306a36Sopenharmony_ci{ 3462306a36Sopenharmony_ci struct cdnsp_segment *seg; 3562306a36Sopenharmony_ci dma_addr_t dma; 3662306a36Sopenharmony_ci int i; 3762306a36Sopenharmony_ci 3862306a36Sopenharmony_ci seg = kzalloc(sizeof(*seg), flags); 3962306a36Sopenharmony_ci if (!seg) 4062306a36Sopenharmony_ci return NULL; 4162306a36Sopenharmony_ci 4262306a36Sopenharmony_ci seg->trbs = dma_pool_zalloc(pdev->segment_pool, flags, &dma); 4362306a36Sopenharmony_ci if (!seg->trbs) { 4462306a36Sopenharmony_ci kfree(seg); 4562306a36Sopenharmony_ci return NULL; 4662306a36Sopenharmony_ci } 4762306a36Sopenharmony_ci 4862306a36Sopenharmony_ci if (max_packet) { 4962306a36Sopenharmony_ci seg->bounce_buf = kzalloc(max_packet, flags | GFP_DMA); 5062306a36Sopenharmony_ci if (!seg->bounce_buf) 5162306a36Sopenharmony_ci goto free_dma; 5262306a36Sopenharmony_ci } 5362306a36Sopenharmony_ci 5462306a36Sopenharmony_ci /* If the cycle state is 0, set the cycle bit to 1 for all the TRBs. */ 5562306a36Sopenharmony_ci if (cycle_state == 0) { 5662306a36Sopenharmony_ci for (i = 0; i < TRBS_PER_SEGMENT; i++) 5762306a36Sopenharmony_ci seg->trbs[i].link.control |= cpu_to_le32(TRB_CYCLE); 5862306a36Sopenharmony_ci } 5962306a36Sopenharmony_ci seg->dma = dma; 6062306a36Sopenharmony_ci seg->next = NULL; 6162306a36Sopenharmony_ci 6262306a36Sopenharmony_ci return seg; 6362306a36Sopenharmony_ci 6462306a36Sopenharmony_cifree_dma: 6562306a36Sopenharmony_ci dma_pool_free(pdev->segment_pool, seg->trbs, dma); 6662306a36Sopenharmony_ci kfree(seg); 6762306a36Sopenharmony_ci 6862306a36Sopenharmony_ci return NULL; 6962306a36Sopenharmony_ci} 7062306a36Sopenharmony_ci 7162306a36Sopenharmony_cistatic void cdnsp_segment_free(struct cdnsp_device *pdev, 7262306a36Sopenharmony_ci struct cdnsp_segment *seg) 7362306a36Sopenharmony_ci{ 7462306a36Sopenharmony_ci if (seg->trbs) 7562306a36Sopenharmony_ci dma_pool_free(pdev->segment_pool, seg->trbs, seg->dma); 7662306a36Sopenharmony_ci 7762306a36Sopenharmony_ci kfree(seg->bounce_buf); 7862306a36Sopenharmony_ci kfree(seg); 7962306a36Sopenharmony_ci} 8062306a36Sopenharmony_ci 8162306a36Sopenharmony_cistatic void cdnsp_free_segments_for_ring(struct cdnsp_device *pdev, 8262306a36Sopenharmony_ci struct cdnsp_segment *first) 8362306a36Sopenharmony_ci{ 8462306a36Sopenharmony_ci struct cdnsp_segment *seg; 8562306a36Sopenharmony_ci 8662306a36Sopenharmony_ci seg = first->next; 8762306a36Sopenharmony_ci 8862306a36Sopenharmony_ci while (seg != first) { 8962306a36Sopenharmony_ci struct cdnsp_segment *next = seg->next; 9062306a36Sopenharmony_ci 9162306a36Sopenharmony_ci cdnsp_segment_free(pdev, seg); 9262306a36Sopenharmony_ci seg = next; 9362306a36Sopenharmony_ci } 9462306a36Sopenharmony_ci 9562306a36Sopenharmony_ci cdnsp_segment_free(pdev, first); 9662306a36Sopenharmony_ci} 9762306a36Sopenharmony_ci 9862306a36Sopenharmony_ci/* 9962306a36Sopenharmony_ci * Make the prev segment point to the next segment. 10062306a36Sopenharmony_ci * 10162306a36Sopenharmony_ci * Change the last TRB in the prev segment to be a Link TRB which points to the 10262306a36Sopenharmony_ci * DMA address of the next segment. The caller needs to set any Link TRB 10362306a36Sopenharmony_ci * related flags, such as End TRB, Toggle Cycle, and no snoop. 10462306a36Sopenharmony_ci */ 10562306a36Sopenharmony_cistatic void cdnsp_link_segments(struct cdnsp_device *pdev, 10662306a36Sopenharmony_ci struct cdnsp_segment *prev, 10762306a36Sopenharmony_ci struct cdnsp_segment *next, 10862306a36Sopenharmony_ci enum cdnsp_ring_type type) 10962306a36Sopenharmony_ci{ 11062306a36Sopenharmony_ci struct cdnsp_link_trb *link; 11162306a36Sopenharmony_ci u32 val; 11262306a36Sopenharmony_ci 11362306a36Sopenharmony_ci if (!prev || !next) 11462306a36Sopenharmony_ci return; 11562306a36Sopenharmony_ci 11662306a36Sopenharmony_ci prev->next = next; 11762306a36Sopenharmony_ci if (type != TYPE_EVENT) { 11862306a36Sopenharmony_ci link = &prev->trbs[TRBS_PER_SEGMENT - 1].link; 11962306a36Sopenharmony_ci link->segment_ptr = cpu_to_le64(next->dma); 12062306a36Sopenharmony_ci 12162306a36Sopenharmony_ci /* 12262306a36Sopenharmony_ci * Set the last TRB in the segment to have a TRB type ID 12362306a36Sopenharmony_ci * of Link TRB 12462306a36Sopenharmony_ci */ 12562306a36Sopenharmony_ci val = le32_to_cpu(link->control); 12662306a36Sopenharmony_ci val &= ~TRB_TYPE_BITMASK; 12762306a36Sopenharmony_ci val |= TRB_TYPE(TRB_LINK); 12862306a36Sopenharmony_ci link->control = cpu_to_le32(val); 12962306a36Sopenharmony_ci } 13062306a36Sopenharmony_ci} 13162306a36Sopenharmony_ci 13262306a36Sopenharmony_ci/* 13362306a36Sopenharmony_ci * Link the ring to the new segments. 13462306a36Sopenharmony_ci * Set Toggle Cycle for the new ring if needed. 13562306a36Sopenharmony_ci */ 13662306a36Sopenharmony_cistatic void cdnsp_link_rings(struct cdnsp_device *pdev, 13762306a36Sopenharmony_ci struct cdnsp_ring *ring, 13862306a36Sopenharmony_ci struct cdnsp_segment *first, 13962306a36Sopenharmony_ci struct cdnsp_segment *last, 14062306a36Sopenharmony_ci unsigned int num_segs) 14162306a36Sopenharmony_ci{ 14262306a36Sopenharmony_ci struct cdnsp_segment *next; 14362306a36Sopenharmony_ci 14462306a36Sopenharmony_ci if (!ring || !first || !last) 14562306a36Sopenharmony_ci return; 14662306a36Sopenharmony_ci 14762306a36Sopenharmony_ci next = ring->enq_seg->next; 14862306a36Sopenharmony_ci cdnsp_link_segments(pdev, ring->enq_seg, first, ring->type); 14962306a36Sopenharmony_ci cdnsp_link_segments(pdev, last, next, ring->type); 15062306a36Sopenharmony_ci ring->num_segs += num_segs; 15162306a36Sopenharmony_ci ring->num_trbs_free += (TRBS_PER_SEGMENT - 1) * num_segs; 15262306a36Sopenharmony_ci 15362306a36Sopenharmony_ci if (ring->type != TYPE_EVENT && ring->enq_seg == ring->last_seg) { 15462306a36Sopenharmony_ci ring->last_seg->trbs[TRBS_PER_SEGMENT - 1].link.control &= 15562306a36Sopenharmony_ci ~cpu_to_le32(LINK_TOGGLE); 15662306a36Sopenharmony_ci last->trbs[TRBS_PER_SEGMENT - 1].link.control |= 15762306a36Sopenharmony_ci cpu_to_le32(LINK_TOGGLE); 15862306a36Sopenharmony_ci ring->last_seg = last; 15962306a36Sopenharmony_ci } 16062306a36Sopenharmony_ci} 16162306a36Sopenharmony_ci 16262306a36Sopenharmony_ci/* 16362306a36Sopenharmony_ci * We need a radix tree for mapping physical addresses of TRBs to which stream 16462306a36Sopenharmony_ci * ID they belong to. We need to do this because the device controller won't 16562306a36Sopenharmony_ci * tell us which stream ring the TRB came from. We could store the stream ID 16662306a36Sopenharmony_ci * in an event data TRB, but that doesn't help us for the cancellation case, 16762306a36Sopenharmony_ci * since the endpoint may stop before it reaches that event data TRB. 16862306a36Sopenharmony_ci * 16962306a36Sopenharmony_ci * The radix tree maps the upper portion of the TRB DMA address to a ring 17062306a36Sopenharmony_ci * segment that has the same upper portion of DMA addresses. For example, 17162306a36Sopenharmony_ci * say I have segments of size 1KB, that are always 1KB aligned. A segment may 17262306a36Sopenharmony_ci * start at 0x10c91000 and end at 0x10c913f0. If I use the upper 10 bits, the 17362306a36Sopenharmony_ci * key to the stream ID is 0x43244. I can use the DMA address of the TRB to 17462306a36Sopenharmony_ci * pass the radix tree a key to get the right stream ID: 17562306a36Sopenharmony_ci * 17662306a36Sopenharmony_ci * 0x10c90fff >> 10 = 0x43243 17762306a36Sopenharmony_ci * 0x10c912c0 >> 10 = 0x43244 17862306a36Sopenharmony_ci * 0x10c91400 >> 10 = 0x43245 17962306a36Sopenharmony_ci * 18062306a36Sopenharmony_ci * Obviously, only those TRBs with DMA addresses that are within the segment 18162306a36Sopenharmony_ci * will make the radix tree return the stream ID for that ring. 18262306a36Sopenharmony_ci * 18362306a36Sopenharmony_ci * Caveats for the radix tree: 18462306a36Sopenharmony_ci * 18562306a36Sopenharmony_ci * The radix tree uses an unsigned long as a key pair. On 32-bit systems, an 18662306a36Sopenharmony_ci * unsigned long will be 32-bits; on a 64-bit system an unsigned long will be 18762306a36Sopenharmony_ci * 64-bits. Since we only request 32-bit DMA addresses, we can use that as the 18862306a36Sopenharmony_ci * key on 32-bit or 64-bit systems (it would also be fine if we asked for 64-bit 18962306a36Sopenharmony_ci * PCI DMA addresses on a 64-bit system). There might be a problem on 32-bit 19062306a36Sopenharmony_ci * extended systems (where the DMA address can be bigger than 32-bits), 19162306a36Sopenharmony_ci * if we allow the PCI dma mask to be bigger than 32-bits. So don't do that. 19262306a36Sopenharmony_ci */ 19362306a36Sopenharmony_cistatic int cdnsp_insert_segment_mapping(struct radix_tree_root *trb_address_map, 19462306a36Sopenharmony_ci struct cdnsp_ring *ring, 19562306a36Sopenharmony_ci struct cdnsp_segment *seg, 19662306a36Sopenharmony_ci gfp_t mem_flags) 19762306a36Sopenharmony_ci{ 19862306a36Sopenharmony_ci unsigned long key; 19962306a36Sopenharmony_ci int ret; 20062306a36Sopenharmony_ci 20162306a36Sopenharmony_ci key = (unsigned long)(seg->dma >> TRB_SEGMENT_SHIFT); 20262306a36Sopenharmony_ci 20362306a36Sopenharmony_ci /* Skip any segments that were already added. */ 20462306a36Sopenharmony_ci if (radix_tree_lookup(trb_address_map, key)) 20562306a36Sopenharmony_ci return 0; 20662306a36Sopenharmony_ci 20762306a36Sopenharmony_ci ret = radix_tree_maybe_preload(mem_flags); 20862306a36Sopenharmony_ci if (ret) 20962306a36Sopenharmony_ci return ret; 21062306a36Sopenharmony_ci 21162306a36Sopenharmony_ci ret = radix_tree_insert(trb_address_map, key, ring); 21262306a36Sopenharmony_ci radix_tree_preload_end(); 21362306a36Sopenharmony_ci 21462306a36Sopenharmony_ci return ret; 21562306a36Sopenharmony_ci} 21662306a36Sopenharmony_ci 21762306a36Sopenharmony_cistatic void cdnsp_remove_segment_mapping(struct radix_tree_root *trb_address_map, 21862306a36Sopenharmony_ci struct cdnsp_segment *seg) 21962306a36Sopenharmony_ci{ 22062306a36Sopenharmony_ci unsigned long key; 22162306a36Sopenharmony_ci 22262306a36Sopenharmony_ci key = (unsigned long)(seg->dma >> TRB_SEGMENT_SHIFT); 22362306a36Sopenharmony_ci if (radix_tree_lookup(trb_address_map, key)) 22462306a36Sopenharmony_ci radix_tree_delete(trb_address_map, key); 22562306a36Sopenharmony_ci} 22662306a36Sopenharmony_ci 22762306a36Sopenharmony_cistatic int cdnsp_update_stream_segment_mapping(struct radix_tree_root *trb_address_map, 22862306a36Sopenharmony_ci struct cdnsp_ring *ring, 22962306a36Sopenharmony_ci struct cdnsp_segment *first_seg, 23062306a36Sopenharmony_ci struct cdnsp_segment *last_seg, 23162306a36Sopenharmony_ci gfp_t mem_flags) 23262306a36Sopenharmony_ci{ 23362306a36Sopenharmony_ci struct cdnsp_segment *failed_seg; 23462306a36Sopenharmony_ci struct cdnsp_segment *seg; 23562306a36Sopenharmony_ci int ret; 23662306a36Sopenharmony_ci 23762306a36Sopenharmony_ci seg = first_seg; 23862306a36Sopenharmony_ci do { 23962306a36Sopenharmony_ci ret = cdnsp_insert_segment_mapping(trb_address_map, ring, seg, 24062306a36Sopenharmony_ci mem_flags); 24162306a36Sopenharmony_ci if (ret) 24262306a36Sopenharmony_ci goto remove_streams; 24362306a36Sopenharmony_ci if (seg == last_seg) 24462306a36Sopenharmony_ci return 0; 24562306a36Sopenharmony_ci seg = seg->next; 24662306a36Sopenharmony_ci } while (seg != first_seg); 24762306a36Sopenharmony_ci 24862306a36Sopenharmony_ci return 0; 24962306a36Sopenharmony_ci 25062306a36Sopenharmony_ciremove_streams: 25162306a36Sopenharmony_ci failed_seg = seg; 25262306a36Sopenharmony_ci seg = first_seg; 25362306a36Sopenharmony_ci do { 25462306a36Sopenharmony_ci cdnsp_remove_segment_mapping(trb_address_map, seg); 25562306a36Sopenharmony_ci if (seg == failed_seg) 25662306a36Sopenharmony_ci return ret; 25762306a36Sopenharmony_ci seg = seg->next; 25862306a36Sopenharmony_ci } while (seg != first_seg); 25962306a36Sopenharmony_ci 26062306a36Sopenharmony_ci return ret; 26162306a36Sopenharmony_ci} 26262306a36Sopenharmony_ci 26362306a36Sopenharmony_cistatic void cdnsp_remove_stream_mapping(struct cdnsp_ring *ring) 26462306a36Sopenharmony_ci{ 26562306a36Sopenharmony_ci struct cdnsp_segment *seg; 26662306a36Sopenharmony_ci 26762306a36Sopenharmony_ci seg = ring->first_seg; 26862306a36Sopenharmony_ci do { 26962306a36Sopenharmony_ci cdnsp_remove_segment_mapping(ring->trb_address_map, seg); 27062306a36Sopenharmony_ci seg = seg->next; 27162306a36Sopenharmony_ci } while (seg != ring->first_seg); 27262306a36Sopenharmony_ci} 27362306a36Sopenharmony_ci 27462306a36Sopenharmony_cistatic int cdnsp_update_stream_mapping(struct cdnsp_ring *ring) 27562306a36Sopenharmony_ci{ 27662306a36Sopenharmony_ci return cdnsp_update_stream_segment_mapping(ring->trb_address_map, ring, 27762306a36Sopenharmony_ci ring->first_seg, ring->last_seg, GFP_ATOMIC); 27862306a36Sopenharmony_ci} 27962306a36Sopenharmony_ci 28062306a36Sopenharmony_cistatic void cdnsp_ring_free(struct cdnsp_device *pdev, struct cdnsp_ring *ring) 28162306a36Sopenharmony_ci{ 28262306a36Sopenharmony_ci if (!ring) 28362306a36Sopenharmony_ci return; 28462306a36Sopenharmony_ci 28562306a36Sopenharmony_ci trace_cdnsp_ring_free(ring); 28662306a36Sopenharmony_ci 28762306a36Sopenharmony_ci if (ring->first_seg) { 28862306a36Sopenharmony_ci if (ring->type == TYPE_STREAM) 28962306a36Sopenharmony_ci cdnsp_remove_stream_mapping(ring); 29062306a36Sopenharmony_ci 29162306a36Sopenharmony_ci cdnsp_free_segments_for_ring(pdev, ring->first_seg); 29262306a36Sopenharmony_ci } 29362306a36Sopenharmony_ci 29462306a36Sopenharmony_ci kfree(ring); 29562306a36Sopenharmony_ci} 29662306a36Sopenharmony_ci 29762306a36Sopenharmony_civoid cdnsp_initialize_ring_info(struct cdnsp_ring *ring) 29862306a36Sopenharmony_ci{ 29962306a36Sopenharmony_ci ring->enqueue = ring->first_seg->trbs; 30062306a36Sopenharmony_ci ring->enq_seg = ring->first_seg; 30162306a36Sopenharmony_ci ring->dequeue = ring->enqueue; 30262306a36Sopenharmony_ci ring->deq_seg = ring->first_seg; 30362306a36Sopenharmony_ci 30462306a36Sopenharmony_ci /* 30562306a36Sopenharmony_ci * The ring is initialized to 0. The producer must write 1 to the cycle 30662306a36Sopenharmony_ci * bit to handover ownership of the TRB, so PCS = 1. The consumer must 30762306a36Sopenharmony_ci * compare CCS to the cycle bit to check ownership, so CCS = 1. 30862306a36Sopenharmony_ci * 30962306a36Sopenharmony_ci * New rings are initialized with cycle state equal to 1; if we are 31062306a36Sopenharmony_ci * handling ring expansion, set the cycle state equal to the old ring. 31162306a36Sopenharmony_ci */ 31262306a36Sopenharmony_ci ring->cycle_state = 1; 31362306a36Sopenharmony_ci 31462306a36Sopenharmony_ci /* 31562306a36Sopenharmony_ci * Each segment has a link TRB, and leave an extra TRB for SW 31662306a36Sopenharmony_ci * accounting purpose 31762306a36Sopenharmony_ci */ 31862306a36Sopenharmony_ci ring->num_trbs_free = ring->num_segs * (TRBS_PER_SEGMENT - 1) - 1; 31962306a36Sopenharmony_ci} 32062306a36Sopenharmony_ci 32162306a36Sopenharmony_ci/* Allocate segments and link them for a ring. */ 32262306a36Sopenharmony_cistatic int cdnsp_alloc_segments_for_ring(struct cdnsp_device *pdev, 32362306a36Sopenharmony_ci struct cdnsp_segment **first, 32462306a36Sopenharmony_ci struct cdnsp_segment **last, 32562306a36Sopenharmony_ci unsigned int num_segs, 32662306a36Sopenharmony_ci unsigned int cycle_state, 32762306a36Sopenharmony_ci enum cdnsp_ring_type type, 32862306a36Sopenharmony_ci unsigned int max_packet, 32962306a36Sopenharmony_ci gfp_t flags) 33062306a36Sopenharmony_ci{ 33162306a36Sopenharmony_ci struct cdnsp_segment *prev; 33262306a36Sopenharmony_ci 33362306a36Sopenharmony_ci /* Allocate first segment. */ 33462306a36Sopenharmony_ci prev = cdnsp_segment_alloc(pdev, cycle_state, max_packet, flags); 33562306a36Sopenharmony_ci if (!prev) 33662306a36Sopenharmony_ci return -ENOMEM; 33762306a36Sopenharmony_ci 33862306a36Sopenharmony_ci num_segs--; 33962306a36Sopenharmony_ci *first = prev; 34062306a36Sopenharmony_ci 34162306a36Sopenharmony_ci /* Allocate all other segments. */ 34262306a36Sopenharmony_ci while (num_segs > 0) { 34362306a36Sopenharmony_ci struct cdnsp_segment *next; 34462306a36Sopenharmony_ci 34562306a36Sopenharmony_ci next = cdnsp_segment_alloc(pdev, cycle_state, 34662306a36Sopenharmony_ci max_packet, flags); 34762306a36Sopenharmony_ci if (!next) { 34862306a36Sopenharmony_ci cdnsp_free_segments_for_ring(pdev, *first); 34962306a36Sopenharmony_ci return -ENOMEM; 35062306a36Sopenharmony_ci } 35162306a36Sopenharmony_ci 35262306a36Sopenharmony_ci cdnsp_link_segments(pdev, prev, next, type); 35362306a36Sopenharmony_ci 35462306a36Sopenharmony_ci prev = next; 35562306a36Sopenharmony_ci num_segs--; 35662306a36Sopenharmony_ci } 35762306a36Sopenharmony_ci 35862306a36Sopenharmony_ci cdnsp_link_segments(pdev, prev, *first, type); 35962306a36Sopenharmony_ci *last = prev; 36062306a36Sopenharmony_ci 36162306a36Sopenharmony_ci return 0; 36262306a36Sopenharmony_ci} 36362306a36Sopenharmony_ci 36462306a36Sopenharmony_ci/* 36562306a36Sopenharmony_ci * Create a new ring with zero or more segments. 36662306a36Sopenharmony_ci * 36762306a36Sopenharmony_ci * Link each segment together into a ring. 36862306a36Sopenharmony_ci * Set the end flag and the cycle toggle bit on the last segment. 36962306a36Sopenharmony_ci */ 37062306a36Sopenharmony_cistatic struct cdnsp_ring *cdnsp_ring_alloc(struct cdnsp_device *pdev, 37162306a36Sopenharmony_ci unsigned int num_segs, 37262306a36Sopenharmony_ci enum cdnsp_ring_type type, 37362306a36Sopenharmony_ci unsigned int max_packet, 37462306a36Sopenharmony_ci gfp_t flags) 37562306a36Sopenharmony_ci{ 37662306a36Sopenharmony_ci struct cdnsp_ring *ring; 37762306a36Sopenharmony_ci int ret; 37862306a36Sopenharmony_ci 37962306a36Sopenharmony_ci ring = kzalloc(sizeof *(ring), flags); 38062306a36Sopenharmony_ci if (!ring) 38162306a36Sopenharmony_ci return NULL; 38262306a36Sopenharmony_ci 38362306a36Sopenharmony_ci ring->num_segs = num_segs; 38462306a36Sopenharmony_ci ring->bounce_buf_len = max_packet; 38562306a36Sopenharmony_ci INIT_LIST_HEAD(&ring->td_list); 38662306a36Sopenharmony_ci ring->type = type; 38762306a36Sopenharmony_ci 38862306a36Sopenharmony_ci if (num_segs == 0) 38962306a36Sopenharmony_ci return ring; 39062306a36Sopenharmony_ci 39162306a36Sopenharmony_ci ret = cdnsp_alloc_segments_for_ring(pdev, &ring->first_seg, 39262306a36Sopenharmony_ci &ring->last_seg, num_segs, 39362306a36Sopenharmony_ci 1, type, max_packet, flags); 39462306a36Sopenharmony_ci if (ret) 39562306a36Sopenharmony_ci goto fail; 39662306a36Sopenharmony_ci 39762306a36Sopenharmony_ci /* Only event ring does not use link TRB. */ 39862306a36Sopenharmony_ci if (type != TYPE_EVENT) 39962306a36Sopenharmony_ci ring->last_seg->trbs[TRBS_PER_SEGMENT - 1].link.control |= 40062306a36Sopenharmony_ci cpu_to_le32(LINK_TOGGLE); 40162306a36Sopenharmony_ci 40262306a36Sopenharmony_ci cdnsp_initialize_ring_info(ring); 40362306a36Sopenharmony_ci trace_cdnsp_ring_alloc(ring); 40462306a36Sopenharmony_ci return ring; 40562306a36Sopenharmony_cifail: 40662306a36Sopenharmony_ci kfree(ring); 40762306a36Sopenharmony_ci return NULL; 40862306a36Sopenharmony_ci} 40962306a36Sopenharmony_ci 41062306a36Sopenharmony_civoid cdnsp_free_endpoint_rings(struct cdnsp_device *pdev, struct cdnsp_ep *pep) 41162306a36Sopenharmony_ci{ 41262306a36Sopenharmony_ci cdnsp_ring_free(pdev, pep->ring); 41362306a36Sopenharmony_ci pep->ring = NULL; 41462306a36Sopenharmony_ci cdnsp_free_stream_info(pdev, pep); 41562306a36Sopenharmony_ci} 41662306a36Sopenharmony_ci 41762306a36Sopenharmony_ci/* 41862306a36Sopenharmony_ci * Expand an existing ring. 41962306a36Sopenharmony_ci * Allocate a new ring which has same segment numbers and link the two rings. 42062306a36Sopenharmony_ci */ 42162306a36Sopenharmony_ciint cdnsp_ring_expansion(struct cdnsp_device *pdev, 42262306a36Sopenharmony_ci struct cdnsp_ring *ring, 42362306a36Sopenharmony_ci unsigned int num_trbs, 42462306a36Sopenharmony_ci gfp_t flags) 42562306a36Sopenharmony_ci{ 42662306a36Sopenharmony_ci unsigned int num_segs_needed; 42762306a36Sopenharmony_ci struct cdnsp_segment *first; 42862306a36Sopenharmony_ci struct cdnsp_segment *last; 42962306a36Sopenharmony_ci unsigned int num_segs; 43062306a36Sopenharmony_ci int ret; 43162306a36Sopenharmony_ci 43262306a36Sopenharmony_ci num_segs_needed = (num_trbs + (TRBS_PER_SEGMENT - 1) - 1) / 43362306a36Sopenharmony_ci (TRBS_PER_SEGMENT - 1); 43462306a36Sopenharmony_ci 43562306a36Sopenharmony_ci /* Allocate number of segments we needed, or double the ring size. */ 43662306a36Sopenharmony_ci num_segs = max(ring->num_segs, num_segs_needed); 43762306a36Sopenharmony_ci 43862306a36Sopenharmony_ci ret = cdnsp_alloc_segments_for_ring(pdev, &first, &last, num_segs, 43962306a36Sopenharmony_ci ring->cycle_state, ring->type, 44062306a36Sopenharmony_ci ring->bounce_buf_len, flags); 44162306a36Sopenharmony_ci if (ret) 44262306a36Sopenharmony_ci return -ENOMEM; 44362306a36Sopenharmony_ci 44462306a36Sopenharmony_ci if (ring->type == TYPE_STREAM) 44562306a36Sopenharmony_ci ret = cdnsp_update_stream_segment_mapping(ring->trb_address_map, 44662306a36Sopenharmony_ci ring, first, 44762306a36Sopenharmony_ci last, flags); 44862306a36Sopenharmony_ci 44962306a36Sopenharmony_ci if (ret) { 45062306a36Sopenharmony_ci cdnsp_free_segments_for_ring(pdev, first); 45162306a36Sopenharmony_ci 45262306a36Sopenharmony_ci return ret; 45362306a36Sopenharmony_ci } 45462306a36Sopenharmony_ci 45562306a36Sopenharmony_ci cdnsp_link_rings(pdev, ring, first, last, num_segs); 45662306a36Sopenharmony_ci trace_cdnsp_ring_expansion(ring); 45762306a36Sopenharmony_ci 45862306a36Sopenharmony_ci return 0; 45962306a36Sopenharmony_ci} 46062306a36Sopenharmony_ci 46162306a36Sopenharmony_cistatic int cdnsp_init_device_ctx(struct cdnsp_device *pdev) 46262306a36Sopenharmony_ci{ 46362306a36Sopenharmony_ci int size = HCC_64BYTE_CONTEXT(pdev->hcc_params) ? 2048 : 1024; 46462306a36Sopenharmony_ci 46562306a36Sopenharmony_ci pdev->out_ctx.type = CDNSP_CTX_TYPE_DEVICE; 46662306a36Sopenharmony_ci pdev->out_ctx.size = size; 46762306a36Sopenharmony_ci pdev->out_ctx.ctx_size = CTX_SIZE(pdev->hcc_params); 46862306a36Sopenharmony_ci pdev->out_ctx.bytes = dma_pool_zalloc(pdev->device_pool, GFP_ATOMIC, 46962306a36Sopenharmony_ci &pdev->out_ctx.dma); 47062306a36Sopenharmony_ci 47162306a36Sopenharmony_ci if (!pdev->out_ctx.bytes) 47262306a36Sopenharmony_ci return -ENOMEM; 47362306a36Sopenharmony_ci 47462306a36Sopenharmony_ci pdev->in_ctx.type = CDNSP_CTX_TYPE_INPUT; 47562306a36Sopenharmony_ci pdev->in_ctx.ctx_size = pdev->out_ctx.ctx_size; 47662306a36Sopenharmony_ci pdev->in_ctx.size = size + pdev->out_ctx.ctx_size; 47762306a36Sopenharmony_ci pdev->in_ctx.bytes = dma_pool_zalloc(pdev->device_pool, GFP_ATOMIC, 47862306a36Sopenharmony_ci &pdev->in_ctx.dma); 47962306a36Sopenharmony_ci 48062306a36Sopenharmony_ci if (!pdev->in_ctx.bytes) { 48162306a36Sopenharmony_ci dma_pool_free(pdev->device_pool, pdev->out_ctx.bytes, 48262306a36Sopenharmony_ci pdev->out_ctx.dma); 48362306a36Sopenharmony_ci return -ENOMEM; 48462306a36Sopenharmony_ci } 48562306a36Sopenharmony_ci 48662306a36Sopenharmony_ci return 0; 48762306a36Sopenharmony_ci} 48862306a36Sopenharmony_ci 48962306a36Sopenharmony_cistruct cdnsp_input_control_ctx 49062306a36Sopenharmony_ci *cdnsp_get_input_control_ctx(struct cdnsp_container_ctx *ctx) 49162306a36Sopenharmony_ci{ 49262306a36Sopenharmony_ci if (ctx->type != CDNSP_CTX_TYPE_INPUT) 49362306a36Sopenharmony_ci return NULL; 49462306a36Sopenharmony_ci 49562306a36Sopenharmony_ci return (struct cdnsp_input_control_ctx *)ctx->bytes; 49662306a36Sopenharmony_ci} 49762306a36Sopenharmony_ci 49862306a36Sopenharmony_cistruct cdnsp_slot_ctx *cdnsp_get_slot_ctx(struct cdnsp_container_ctx *ctx) 49962306a36Sopenharmony_ci{ 50062306a36Sopenharmony_ci if (ctx->type == CDNSP_CTX_TYPE_DEVICE) 50162306a36Sopenharmony_ci return (struct cdnsp_slot_ctx *)ctx->bytes; 50262306a36Sopenharmony_ci 50362306a36Sopenharmony_ci return (struct cdnsp_slot_ctx *)(ctx->bytes + ctx->ctx_size); 50462306a36Sopenharmony_ci} 50562306a36Sopenharmony_ci 50662306a36Sopenharmony_cistruct cdnsp_ep_ctx *cdnsp_get_ep_ctx(struct cdnsp_container_ctx *ctx, 50762306a36Sopenharmony_ci unsigned int ep_index) 50862306a36Sopenharmony_ci{ 50962306a36Sopenharmony_ci /* Increment ep index by offset of start of ep ctx array. */ 51062306a36Sopenharmony_ci ep_index++; 51162306a36Sopenharmony_ci if (ctx->type == CDNSP_CTX_TYPE_INPUT) 51262306a36Sopenharmony_ci ep_index++; 51362306a36Sopenharmony_ci 51462306a36Sopenharmony_ci return (struct cdnsp_ep_ctx *)(ctx->bytes + (ep_index * ctx->ctx_size)); 51562306a36Sopenharmony_ci} 51662306a36Sopenharmony_ci 51762306a36Sopenharmony_cistatic void cdnsp_free_stream_ctx(struct cdnsp_device *pdev, 51862306a36Sopenharmony_ci struct cdnsp_ep *pep) 51962306a36Sopenharmony_ci{ 52062306a36Sopenharmony_ci dma_pool_free(pdev->device_pool, pep->stream_info.stream_ctx_array, 52162306a36Sopenharmony_ci pep->stream_info.ctx_array_dma); 52262306a36Sopenharmony_ci} 52362306a36Sopenharmony_ci 52462306a36Sopenharmony_ci/* The stream context array must be a power of 2. */ 52562306a36Sopenharmony_cistatic struct cdnsp_stream_ctx 52662306a36Sopenharmony_ci *cdnsp_alloc_stream_ctx(struct cdnsp_device *pdev, struct cdnsp_ep *pep) 52762306a36Sopenharmony_ci{ 52862306a36Sopenharmony_ci size_t size = sizeof(struct cdnsp_stream_ctx) * 52962306a36Sopenharmony_ci pep->stream_info.num_stream_ctxs; 53062306a36Sopenharmony_ci 53162306a36Sopenharmony_ci if (size > CDNSP_CTX_SIZE) 53262306a36Sopenharmony_ci return NULL; 53362306a36Sopenharmony_ci 53462306a36Sopenharmony_ci /** 53562306a36Sopenharmony_ci * Driver uses intentionally the device_pool to allocated stream 53662306a36Sopenharmony_ci * context array. Device Pool has 2048 bytes of size what gives us 53762306a36Sopenharmony_ci * 128 entries. 53862306a36Sopenharmony_ci */ 53962306a36Sopenharmony_ci return dma_pool_zalloc(pdev->device_pool, GFP_DMA32 | GFP_ATOMIC, 54062306a36Sopenharmony_ci &pep->stream_info.ctx_array_dma); 54162306a36Sopenharmony_ci} 54262306a36Sopenharmony_ci 54362306a36Sopenharmony_cistruct cdnsp_ring *cdnsp_dma_to_transfer_ring(struct cdnsp_ep *pep, u64 address) 54462306a36Sopenharmony_ci{ 54562306a36Sopenharmony_ci if (pep->ep_state & EP_HAS_STREAMS) 54662306a36Sopenharmony_ci return radix_tree_lookup(&pep->stream_info.trb_address_map, 54762306a36Sopenharmony_ci address >> TRB_SEGMENT_SHIFT); 54862306a36Sopenharmony_ci 54962306a36Sopenharmony_ci return pep->ring; 55062306a36Sopenharmony_ci} 55162306a36Sopenharmony_ci 55262306a36Sopenharmony_ci/* 55362306a36Sopenharmony_ci * Change an endpoint's internal structure so it supports stream IDs. 55462306a36Sopenharmony_ci * The number of requested streams includes stream 0, which cannot be used by 55562306a36Sopenharmony_ci * driver. 55662306a36Sopenharmony_ci * 55762306a36Sopenharmony_ci * The number of stream contexts in the stream context array may be bigger than 55862306a36Sopenharmony_ci * the number of streams the driver wants to use. This is because the number of 55962306a36Sopenharmony_ci * stream context array entries must be a power of two. 56062306a36Sopenharmony_ci */ 56162306a36Sopenharmony_ciint cdnsp_alloc_stream_info(struct cdnsp_device *pdev, 56262306a36Sopenharmony_ci struct cdnsp_ep *pep, 56362306a36Sopenharmony_ci unsigned int num_stream_ctxs, 56462306a36Sopenharmony_ci unsigned int num_streams) 56562306a36Sopenharmony_ci{ 56662306a36Sopenharmony_ci struct cdnsp_stream_info *stream_info; 56762306a36Sopenharmony_ci struct cdnsp_ring *cur_ring; 56862306a36Sopenharmony_ci u32 cur_stream; 56962306a36Sopenharmony_ci u64 addr; 57062306a36Sopenharmony_ci int ret; 57162306a36Sopenharmony_ci int mps; 57262306a36Sopenharmony_ci 57362306a36Sopenharmony_ci stream_info = &pep->stream_info; 57462306a36Sopenharmony_ci stream_info->num_streams = num_streams; 57562306a36Sopenharmony_ci stream_info->num_stream_ctxs = num_stream_ctxs; 57662306a36Sopenharmony_ci 57762306a36Sopenharmony_ci /* Initialize the array of virtual pointers to stream rings. */ 57862306a36Sopenharmony_ci stream_info->stream_rings = kcalloc(num_streams, 57962306a36Sopenharmony_ci sizeof(struct cdnsp_ring *), 58062306a36Sopenharmony_ci GFP_ATOMIC); 58162306a36Sopenharmony_ci if (!stream_info->stream_rings) 58262306a36Sopenharmony_ci return -ENOMEM; 58362306a36Sopenharmony_ci 58462306a36Sopenharmony_ci /* Initialize the array of DMA addresses for stream rings for the HW. */ 58562306a36Sopenharmony_ci stream_info->stream_ctx_array = cdnsp_alloc_stream_ctx(pdev, pep); 58662306a36Sopenharmony_ci if (!stream_info->stream_ctx_array) 58762306a36Sopenharmony_ci goto cleanup_stream_rings; 58862306a36Sopenharmony_ci 58962306a36Sopenharmony_ci memset(stream_info->stream_ctx_array, 0, 59062306a36Sopenharmony_ci sizeof(struct cdnsp_stream_ctx) * num_stream_ctxs); 59162306a36Sopenharmony_ci INIT_RADIX_TREE(&stream_info->trb_address_map, GFP_ATOMIC); 59262306a36Sopenharmony_ci mps = usb_endpoint_maxp(pep->endpoint.desc); 59362306a36Sopenharmony_ci 59462306a36Sopenharmony_ci /* 59562306a36Sopenharmony_ci * Allocate rings for all the streams that the driver will use, 59662306a36Sopenharmony_ci * and add their segment DMA addresses to the radix tree. 59762306a36Sopenharmony_ci * Stream 0 is reserved. 59862306a36Sopenharmony_ci */ 59962306a36Sopenharmony_ci for (cur_stream = 1; cur_stream < num_streams; cur_stream++) { 60062306a36Sopenharmony_ci cur_ring = cdnsp_ring_alloc(pdev, 2, TYPE_STREAM, mps, 60162306a36Sopenharmony_ci GFP_ATOMIC); 60262306a36Sopenharmony_ci stream_info->stream_rings[cur_stream] = cur_ring; 60362306a36Sopenharmony_ci 60462306a36Sopenharmony_ci if (!cur_ring) 60562306a36Sopenharmony_ci goto cleanup_rings; 60662306a36Sopenharmony_ci 60762306a36Sopenharmony_ci cur_ring->stream_id = cur_stream; 60862306a36Sopenharmony_ci cur_ring->trb_address_map = &stream_info->trb_address_map; 60962306a36Sopenharmony_ci 61062306a36Sopenharmony_ci /* Set deq ptr, cycle bit, and stream context type. */ 61162306a36Sopenharmony_ci addr = cur_ring->first_seg->dma | SCT_FOR_CTX(SCT_PRI_TR) | 61262306a36Sopenharmony_ci cur_ring->cycle_state; 61362306a36Sopenharmony_ci 61462306a36Sopenharmony_ci stream_info->stream_ctx_array[cur_stream].stream_ring = 61562306a36Sopenharmony_ci cpu_to_le64(addr); 61662306a36Sopenharmony_ci 61762306a36Sopenharmony_ci trace_cdnsp_set_stream_ring(cur_ring); 61862306a36Sopenharmony_ci 61962306a36Sopenharmony_ci ret = cdnsp_update_stream_mapping(cur_ring); 62062306a36Sopenharmony_ci if (ret) 62162306a36Sopenharmony_ci goto cleanup_rings; 62262306a36Sopenharmony_ci } 62362306a36Sopenharmony_ci 62462306a36Sopenharmony_ci return 0; 62562306a36Sopenharmony_ci 62662306a36Sopenharmony_cicleanup_rings: 62762306a36Sopenharmony_ci for (cur_stream = 1; cur_stream < num_streams; cur_stream++) { 62862306a36Sopenharmony_ci cur_ring = stream_info->stream_rings[cur_stream]; 62962306a36Sopenharmony_ci if (cur_ring) { 63062306a36Sopenharmony_ci cdnsp_ring_free(pdev, cur_ring); 63162306a36Sopenharmony_ci stream_info->stream_rings[cur_stream] = NULL; 63262306a36Sopenharmony_ci } 63362306a36Sopenharmony_ci } 63462306a36Sopenharmony_ci 63562306a36Sopenharmony_cicleanup_stream_rings: 63662306a36Sopenharmony_ci kfree(pep->stream_info.stream_rings); 63762306a36Sopenharmony_ci 63862306a36Sopenharmony_ci return -ENOMEM; 63962306a36Sopenharmony_ci} 64062306a36Sopenharmony_ci 64162306a36Sopenharmony_ci/* Frees all stream contexts associated with the endpoint. */ 64262306a36Sopenharmony_cistatic void cdnsp_free_stream_info(struct cdnsp_device *pdev, 64362306a36Sopenharmony_ci struct cdnsp_ep *pep) 64462306a36Sopenharmony_ci{ 64562306a36Sopenharmony_ci struct cdnsp_stream_info *stream_info = &pep->stream_info; 64662306a36Sopenharmony_ci struct cdnsp_ring *cur_ring; 64762306a36Sopenharmony_ci int cur_stream; 64862306a36Sopenharmony_ci 64962306a36Sopenharmony_ci if (!(pep->ep_state & EP_HAS_STREAMS)) 65062306a36Sopenharmony_ci return; 65162306a36Sopenharmony_ci 65262306a36Sopenharmony_ci for (cur_stream = 1; cur_stream < stream_info->num_streams; 65362306a36Sopenharmony_ci cur_stream++) { 65462306a36Sopenharmony_ci cur_ring = stream_info->stream_rings[cur_stream]; 65562306a36Sopenharmony_ci if (cur_ring) { 65662306a36Sopenharmony_ci cdnsp_ring_free(pdev, cur_ring); 65762306a36Sopenharmony_ci stream_info->stream_rings[cur_stream] = NULL; 65862306a36Sopenharmony_ci } 65962306a36Sopenharmony_ci } 66062306a36Sopenharmony_ci 66162306a36Sopenharmony_ci if (stream_info->stream_ctx_array) 66262306a36Sopenharmony_ci cdnsp_free_stream_ctx(pdev, pep); 66362306a36Sopenharmony_ci 66462306a36Sopenharmony_ci kfree(stream_info->stream_rings); 66562306a36Sopenharmony_ci pep->ep_state &= ~EP_HAS_STREAMS; 66662306a36Sopenharmony_ci} 66762306a36Sopenharmony_ci 66862306a36Sopenharmony_ci/* All the cdnsp_tds in the ring's TD list should be freed at this point.*/ 66962306a36Sopenharmony_cistatic void cdnsp_free_priv_device(struct cdnsp_device *pdev) 67062306a36Sopenharmony_ci{ 67162306a36Sopenharmony_ci pdev->dcbaa->dev_context_ptrs[1] = 0; 67262306a36Sopenharmony_ci 67362306a36Sopenharmony_ci cdnsp_free_endpoint_rings(pdev, &pdev->eps[0]); 67462306a36Sopenharmony_ci 67562306a36Sopenharmony_ci if (pdev->in_ctx.bytes) 67662306a36Sopenharmony_ci dma_pool_free(pdev->device_pool, pdev->in_ctx.bytes, 67762306a36Sopenharmony_ci pdev->in_ctx.dma); 67862306a36Sopenharmony_ci 67962306a36Sopenharmony_ci if (pdev->out_ctx.bytes) 68062306a36Sopenharmony_ci dma_pool_free(pdev->device_pool, pdev->out_ctx.bytes, 68162306a36Sopenharmony_ci pdev->out_ctx.dma); 68262306a36Sopenharmony_ci 68362306a36Sopenharmony_ci pdev->in_ctx.bytes = NULL; 68462306a36Sopenharmony_ci pdev->out_ctx.bytes = NULL; 68562306a36Sopenharmony_ci} 68662306a36Sopenharmony_ci 68762306a36Sopenharmony_cistatic int cdnsp_alloc_priv_device(struct cdnsp_device *pdev) 68862306a36Sopenharmony_ci{ 68962306a36Sopenharmony_ci int ret; 69062306a36Sopenharmony_ci 69162306a36Sopenharmony_ci ret = cdnsp_init_device_ctx(pdev); 69262306a36Sopenharmony_ci if (ret) 69362306a36Sopenharmony_ci return ret; 69462306a36Sopenharmony_ci 69562306a36Sopenharmony_ci /* Allocate endpoint 0 ring. */ 69662306a36Sopenharmony_ci pdev->eps[0].ring = cdnsp_ring_alloc(pdev, 2, TYPE_CTRL, 0, GFP_ATOMIC); 69762306a36Sopenharmony_ci if (!pdev->eps[0].ring) 69862306a36Sopenharmony_ci goto fail; 69962306a36Sopenharmony_ci 70062306a36Sopenharmony_ci /* Point to output device context in dcbaa. */ 70162306a36Sopenharmony_ci pdev->dcbaa->dev_context_ptrs[1] = cpu_to_le64(pdev->out_ctx.dma); 70262306a36Sopenharmony_ci pdev->cmd.in_ctx = &pdev->in_ctx; 70362306a36Sopenharmony_ci 70462306a36Sopenharmony_ci trace_cdnsp_alloc_priv_device(pdev); 70562306a36Sopenharmony_ci return 0; 70662306a36Sopenharmony_cifail: 70762306a36Sopenharmony_ci dma_pool_free(pdev->device_pool, pdev->out_ctx.bytes, 70862306a36Sopenharmony_ci pdev->out_ctx.dma); 70962306a36Sopenharmony_ci dma_pool_free(pdev->device_pool, pdev->in_ctx.bytes, 71062306a36Sopenharmony_ci pdev->in_ctx.dma); 71162306a36Sopenharmony_ci 71262306a36Sopenharmony_ci return ret; 71362306a36Sopenharmony_ci} 71462306a36Sopenharmony_ci 71562306a36Sopenharmony_civoid cdnsp_copy_ep0_dequeue_into_input_ctx(struct cdnsp_device *pdev) 71662306a36Sopenharmony_ci{ 71762306a36Sopenharmony_ci struct cdnsp_ep_ctx *ep0_ctx = pdev->eps[0].in_ctx; 71862306a36Sopenharmony_ci struct cdnsp_ring *ep_ring = pdev->eps[0].ring; 71962306a36Sopenharmony_ci dma_addr_t dma; 72062306a36Sopenharmony_ci 72162306a36Sopenharmony_ci dma = cdnsp_trb_virt_to_dma(ep_ring->enq_seg, ep_ring->enqueue); 72262306a36Sopenharmony_ci ep0_ctx->deq = cpu_to_le64(dma | ep_ring->cycle_state); 72362306a36Sopenharmony_ci} 72462306a36Sopenharmony_ci 72562306a36Sopenharmony_ci/* Setup an controller private device for a Set Address command. */ 72662306a36Sopenharmony_ciint cdnsp_setup_addressable_priv_dev(struct cdnsp_device *pdev) 72762306a36Sopenharmony_ci{ 72862306a36Sopenharmony_ci struct cdnsp_slot_ctx *slot_ctx; 72962306a36Sopenharmony_ci struct cdnsp_ep_ctx *ep0_ctx; 73062306a36Sopenharmony_ci u32 max_packets, port; 73162306a36Sopenharmony_ci 73262306a36Sopenharmony_ci ep0_ctx = cdnsp_get_ep_ctx(&pdev->in_ctx, 0); 73362306a36Sopenharmony_ci slot_ctx = cdnsp_get_slot_ctx(&pdev->in_ctx); 73462306a36Sopenharmony_ci 73562306a36Sopenharmony_ci /* Only the control endpoint is valid - one endpoint context. */ 73662306a36Sopenharmony_ci slot_ctx->dev_info |= cpu_to_le32(LAST_CTX(1)); 73762306a36Sopenharmony_ci 73862306a36Sopenharmony_ci switch (pdev->gadget.speed) { 73962306a36Sopenharmony_ci case USB_SPEED_SUPER_PLUS: 74062306a36Sopenharmony_ci slot_ctx->dev_info |= cpu_to_le32(SLOT_SPEED_SSP); 74162306a36Sopenharmony_ci max_packets = MAX_PACKET(512); 74262306a36Sopenharmony_ci break; 74362306a36Sopenharmony_ci case USB_SPEED_SUPER: 74462306a36Sopenharmony_ci slot_ctx->dev_info |= cpu_to_le32(SLOT_SPEED_SS); 74562306a36Sopenharmony_ci max_packets = MAX_PACKET(512); 74662306a36Sopenharmony_ci break; 74762306a36Sopenharmony_ci case USB_SPEED_HIGH: 74862306a36Sopenharmony_ci slot_ctx->dev_info |= cpu_to_le32(SLOT_SPEED_HS); 74962306a36Sopenharmony_ci max_packets = MAX_PACKET(64); 75062306a36Sopenharmony_ci break; 75162306a36Sopenharmony_ci case USB_SPEED_FULL: 75262306a36Sopenharmony_ci slot_ctx->dev_info |= cpu_to_le32(SLOT_SPEED_FS); 75362306a36Sopenharmony_ci max_packets = MAX_PACKET(64); 75462306a36Sopenharmony_ci break; 75562306a36Sopenharmony_ci default: 75662306a36Sopenharmony_ci /* Speed was not set , this shouldn't happen. */ 75762306a36Sopenharmony_ci return -EINVAL; 75862306a36Sopenharmony_ci } 75962306a36Sopenharmony_ci 76062306a36Sopenharmony_ci port = DEV_PORT(pdev->active_port->port_num); 76162306a36Sopenharmony_ci slot_ctx->dev_port |= cpu_to_le32(port); 76262306a36Sopenharmony_ci slot_ctx->dev_state = cpu_to_le32((pdev->device_address & 76362306a36Sopenharmony_ci DEV_ADDR_MASK)); 76462306a36Sopenharmony_ci ep0_ctx->tx_info = cpu_to_le32(EP_AVG_TRB_LENGTH(0x8)); 76562306a36Sopenharmony_ci ep0_ctx->ep_info2 = cpu_to_le32(EP_TYPE(CTRL_EP)); 76662306a36Sopenharmony_ci ep0_ctx->ep_info2 |= cpu_to_le32(MAX_BURST(0) | ERROR_COUNT(3) | 76762306a36Sopenharmony_ci max_packets); 76862306a36Sopenharmony_ci 76962306a36Sopenharmony_ci ep0_ctx->deq = cpu_to_le64(pdev->eps[0].ring->first_seg->dma | 77062306a36Sopenharmony_ci pdev->eps[0].ring->cycle_state); 77162306a36Sopenharmony_ci 77262306a36Sopenharmony_ci trace_cdnsp_setup_addressable_priv_device(pdev); 77362306a36Sopenharmony_ci 77462306a36Sopenharmony_ci return 0; 77562306a36Sopenharmony_ci} 77662306a36Sopenharmony_ci 77762306a36Sopenharmony_ci/* 77862306a36Sopenharmony_ci * Convert interval expressed as 2^(bInterval - 1) == interval into 77962306a36Sopenharmony_ci * straight exponent value 2^n == interval. 78062306a36Sopenharmony_ci */ 78162306a36Sopenharmony_cistatic unsigned int cdnsp_parse_exponent_interval(struct usb_gadget *g, 78262306a36Sopenharmony_ci struct cdnsp_ep *pep) 78362306a36Sopenharmony_ci{ 78462306a36Sopenharmony_ci unsigned int interval; 78562306a36Sopenharmony_ci 78662306a36Sopenharmony_ci interval = clamp_val(pep->endpoint.desc->bInterval, 1, 16) - 1; 78762306a36Sopenharmony_ci if (interval != pep->endpoint.desc->bInterval - 1) 78862306a36Sopenharmony_ci dev_warn(&g->dev, "ep %s - rounding interval to %d %sframes\n", 78962306a36Sopenharmony_ci pep->name, 1 << interval, 79062306a36Sopenharmony_ci g->speed == USB_SPEED_FULL ? "" : "micro"); 79162306a36Sopenharmony_ci 79262306a36Sopenharmony_ci /* 79362306a36Sopenharmony_ci * Full speed isoc endpoints specify interval in frames, 79462306a36Sopenharmony_ci * not microframes. We are using microframes everywhere, 79562306a36Sopenharmony_ci * so adjust accordingly. 79662306a36Sopenharmony_ci */ 79762306a36Sopenharmony_ci if (g->speed == USB_SPEED_FULL) 79862306a36Sopenharmony_ci interval += 3; /* 1 frame = 2^3 uframes */ 79962306a36Sopenharmony_ci 80062306a36Sopenharmony_ci /* Controller handles only up to 512ms (2^12). */ 80162306a36Sopenharmony_ci if (interval > 12) 80262306a36Sopenharmony_ci interval = 12; 80362306a36Sopenharmony_ci 80462306a36Sopenharmony_ci return interval; 80562306a36Sopenharmony_ci} 80662306a36Sopenharmony_ci 80762306a36Sopenharmony_ci/* 80862306a36Sopenharmony_ci * Convert bInterval expressed in microframes (in 1-255 range) to exponent of 80962306a36Sopenharmony_ci * microframes, rounded down to nearest power of 2. 81062306a36Sopenharmony_ci */ 81162306a36Sopenharmony_cistatic unsigned int cdnsp_microframes_to_exponent(struct usb_gadget *g, 81262306a36Sopenharmony_ci struct cdnsp_ep *pep, 81362306a36Sopenharmony_ci unsigned int desc_interval, 81462306a36Sopenharmony_ci unsigned int min_exponent, 81562306a36Sopenharmony_ci unsigned int max_exponent) 81662306a36Sopenharmony_ci{ 81762306a36Sopenharmony_ci unsigned int interval; 81862306a36Sopenharmony_ci 81962306a36Sopenharmony_ci interval = fls(desc_interval) - 1; 82062306a36Sopenharmony_ci return clamp_val(interval, min_exponent, max_exponent); 82162306a36Sopenharmony_ci} 82262306a36Sopenharmony_ci 82362306a36Sopenharmony_ci/* 82462306a36Sopenharmony_ci * Return the polling interval. 82562306a36Sopenharmony_ci * 82662306a36Sopenharmony_ci * The polling interval is expressed in "microframes". If controllers's Interval 82762306a36Sopenharmony_ci * field is set to N, it will service the endpoint every 2^(Interval)*125us. 82862306a36Sopenharmony_ci */ 82962306a36Sopenharmony_cistatic unsigned int cdnsp_get_endpoint_interval(struct usb_gadget *g, 83062306a36Sopenharmony_ci struct cdnsp_ep *pep) 83162306a36Sopenharmony_ci{ 83262306a36Sopenharmony_ci unsigned int interval = 0; 83362306a36Sopenharmony_ci 83462306a36Sopenharmony_ci switch (g->speed) { 83562306a36Sopenharmony_ci case USB_SPEED_HIGH: 83662306a36Sopenharmony_ci case USB_SPEED_SUPER_PLUS: 83762306a36Sopenharmony_ci case USB_SPEED_SUPER: 83862306a36Sopenharmony_ci if (usb_endpoint_xfer_int(pep->endpoint.desc) || 83962306a36Sopenharmony_ci usb_endpoint_xfer_isoc(pep->endpoint.desc)) 84062306a36Sopenharmony_ci interval = cdnsp_parse_exponent_interval(g, pep); 84162306a36Sopenharmony_ci break; 84262306a36Sopenharmony_ci case USB_SPEED_FULL: 84362306a36Sopenharmony_ci if (usb_endpoint_xfer_isoc(pep->endpoint.desc)) { 84462306a36Sopenharmony_ci interval = cdnsp_parse_exponent_interval(g, pep); 84562306a36Sopenharmony_ci } else if (usb_endpoint_xfer_int(pep->endpoint.desc)) { 84662306a36Sopenharmony_ci interval = pep->endpoint.desc->bInterval << 3; 84762306a36Sopenharmony_ci interval = cdnsp_microframes_to_exponent(g, pep, 84862306a36Sopenharmony_ci interval, 84962306a36Sopenharmony_ci 3, 10); 85062306a36Sopenharmony_ci } 85162306a36Sopenharmony_ci 85262306a36Sopenharmony_ci break; 85362306a36Sopenharmony_ci default: 85462306a36Sopenharmony_ci WARN_ON(1); 85562306a36Sopenharmony_ci } 85662306a36Sopenharmony_ci 85762306a36Sopenharmony_ci return interval; 85862306a36Sopenharmony_ci} 85962306a36Sopenharmony_ci 86062306a36Sopenharmony_ci/* 86162306a36Sopenharmony_ci * The "Mult" field in the endpoint context is only set for SuperSpeed isoc eps. 86262306a36Sopenharmony_ci * High speed endpoint descriptors can define "the number of additional 86362306a36Sopenharmony_ci * transaction opportunities per microframe", but that goes in the Max Burst 86462306a36Sopenharmony_ci * endpoint context field. 86562306a36Sopenharmony_ci */ 86662306a36Sopenharmony_cistatic u32 cdnsp_get_endpoint_mult(struct usb_gadget *g, struct cdnsp_ep *pep) 86762306a36Sopenharmony_ci{ 86862306a36Sopenharmony_ci if (g->speed < USB_SPEED_SUPER || 86962306a36Sopenharmony_ci !usb_endpoint_xfer_isoc(pep->endpoint.desc)) 87062306a36Sopenharmony_ci return 0; 87162306a36Sopenharmony_ci 87262306a36Sopenharmony_ci return pep->endpoint.comp_desc->bmAttributes; 87362306a36Sopenharmony_ci} 87462306a36Sopenharmony_ci 87562306a36Sopenharmony_cistatic u32 cdnsp_get_endpoint_max_burst(struct usb_gadget *g, 87662306a36Sopenharmony_ci struct cdnsp_ep *pep) 87762306a36Sopenharmony_ci{ 87862306a36Sopenharmony_ci /* Super speed and Plus have max burst in ep companion desc */ 87962306a36Sopenharmony_ci if (g->speed >= USB_SPEED_SUPER) 88062306a36Sopenharmony_ci return pep->endpoint.comp_desc->bMaxBurst; 88162306a36Sopenharmony_ci 88262306a36Sopenharmony_ci if (g->speed == USB_SPEED_HIGH && 88362306a36Sopenharmony_ci (usb_endpoint_xfer_isoc(pep->endpoint.desc) || 88462306a36Sopenharmony_ci usb_endpoint_xfer_int(pep->endpoint.desc))) 88562306a36Sopenharmony_ci return usb_endpoint_maxp_mult(pep->endpoint.desc) - 1; 88662306a36Sopenharmony_ci 88762306a36Sopenharmony_ci return 0; 88862306a36Sopenharmony_ci} 88962306a36Sopenharmony_ci 89062306a36Sopenharmony_cistatic u32 cdnsp_get_endpoint_type(const struct usb_endpoint_descriptor *desc) 89162306a36Sopenharmony_ci{ 89262306a36Sopenharmony_ci int in; 89362306a36Sopenharmony_ci 89462306a36Sopenharmony_ci in = usb_endpoint_dir_in(desc); 89562306a36Sopenharmony_ci 89662306a36Sopenharmony_ci switch (usb_endpoint_type(desc)) { 89762306a36Sopenharmony_ci case USB_ENDPOINT_XFER_CONTROL: 89862306a36Sopenharmony_ci return CTRL_EP; 89962306a36Sopenharmony_ci case USB_ENDPOINT_XFER_BULK: 90062306a36Sopenharmony_ci return in ? BULK_IN_EP : BULK_OUT_EP; 90162306a36Sopenharmony_ci case USB_ENDPOINT_XFER_ISOC: 90262306a36Sopenharmony_ci return in ? ISOC_IN_EP : ISOC_OUT_EP; 90362306a36Sopenharmony_ci case USB_ENDPOINT_XFER_INT: 90462306a36Sopenharmony_ci return in ? INT_IN_EP : INT_OUT_EP; 90562306a36Sopenharmony_ci } 90662306a36Sopenharmony_ci 90762306a36Sopenharmony_ci return 0; 90862306a36Sopenharmony_ci} 90962306a36Sopenharmony_ci 91062306a36Sopenharmony_ci/* 91162306a36Sopenharmony_ci * Return the maximum endpoint service interval time (ESIT) payload. 91262306a36Sopenharmony_ci * Basically, this is the maxpacket size, multiplied by the burst size 91362306a36Sopenharmony_ci * and mult size. 91462306a36Sopenharmony_ci */ 91562306a36Sopenharmony_cistatic u32 cdnsp_get_max_esit_payload(struct usb_gadget *g, 91662306a36Sopenharmony_ci struct cdnsp_ep *pep) 91762306a36Sopenharmony_ci{ 91862306a36Sopenharmony_ci int max_packet; 91962306a36Sopenharmony_ci int max_burst; 92062306a36Sopenharmony_ci 92162306a36Sopenharmony_ci /* Only applies for interrupt or isochronous endpoints*/ 92262306a36Sopenharmony_ci if (usb_endpoint_xfer_control(pep->endpoint.desc) || 92362306a36Sopenharmony_ci usb_endpoint_xfer_bulk(pep->endpoint.desc)) 92462306a36Sopenharmony_ci return 0; 92562306a36Sopenharmony_ci 92662306a36Sopenharmony_ci /* SuperSpeedPlus Isoc ep sending over 48k per EIST. */ 92762306a36Sopenharmony_ci if (g->speed >= USB_SPEED_SUPER_PLUS && 92862306a36Sopenharmony_ci USB_SS_SSP_ISOC_COMP(pep->endpoint.desc->bmAttributes)) 92962306a36Sopenharmony_ci return le16_to_cpu(pep->endpoint.comp_desc->wBytesPerInterval); 93062306a36Sopenharmony_ci /* SuperSpeed or SuperSpeedPlus Isoc ep with less than 48k per esit */ 93162306a36Sopenharmony_ci else if (g->speed >= USB_SPEED_SUPER) 93262306a36Sopenharmony_ci return le16_to_cpu(pep->endpoint.comp_desc->wBytesPerInterval); 93362306a36Sopenharmony_ci 93462306a36Sopenharmony_ci max_packet = usb_endpoint_maxp(pep->endpoint.desc); 93562306a36Sopenharmony_ci max_burst = usb_endpoint_maxp_mult(pep->endpoint.desc); 93662306a36Sopenharmony_ci 93762306a36Sopenharmony_ci /* A 0 in max burst means 1 transfer per ESIT */ 93862306a36Sopenharmony_ci return max_packet * max_burst; 93962306a36Sopenharmony_ci} 94062306a36Sopenharmony_ci 94162306a36Sopenharmony_ciint cdnsp_endpoint_init(struct cdnsp_device *pdev, 94262306a36Sopenharmony_ci struct cdnsp_ep *pep, 94362306a36Sopenharmony_ci gfp_t mem_flags) 94462306a36Sopenharmony_ci{ 94562306a36Sopenharmony_ci enum cdnsp_ring_type ring_type; 94662306a36Sopenharmony_ci struct cdnsp_ep_ctx *ep_ctx; 94762306a36Sopenharmony_ci unsigned int err_count = 0; 94862306a36Sopenharmony_ci unsigned int avg_trb_len; 94962306a36Sopenharmony_ci unsigned int max_packet; 95062306a36Sopenharmony_ci unsigned int max_burst; 95162306a36Sopenharmony_ci unsigned int interval; 95262306a36Sopenharmony_ci u32 max_esit_payload; 95362306a36Sopenharmony_ci unsigned int mult; 95462306a36Sopenharmony_ci u32 endpoint_type; 95562306a36Sopenharmony_ci int ret; 95662306a36Sopenharmony_ci 95762306a36Sopenharmony_ci ep_ctx = pep->in_ctx; 95862306a36Sopenharmony_ci 95962306a36Sopenharmony_ci endpoint_type = cdnsp_get_endpoint_type(pep->endpoint.desc); 96062306a36Sopenharmony_ci if (!endpoint_type) 96162306a36Sopenharmony_ci return -EINVAL; 96262306a36Sopenharmony_ci 96362306a36Sopenharmony_ci ring_type = usb_endpoint_type(pep->endpoint.desc); 96462306a36Sopenharmony_ci 96562306a36Sopenharmony_ci /* 96662306a36Sopenharmony_ci * Get values to fill the endpoint context, mostly from ep descriptor. 96762306a36Sopenharmony_ci * The average TRB buffer length for bulk endpoints is unclear as we 96862306a36Sopenharmony_ci * have no clue on scatter gather list entry size. For Isoc and Int, 96962306a36Sopenharmony_ci * set it to max available. 97062306a36Sopenharmony_ci */ 97162306a36Sopenharmony_ci max_esit_payload = cdnsp_get_max_esit_payload(&pdev->gadget, pep); 97262306a36Sopenharmony_ci interval = cdnsp_get_endpoint_interval(&pdev->gadget, pep); 97362306a36Sopenharmony_ci mult = cdnsp_get_endpoint_mult(&pdev->gadget, pep); 97462306a36Sopenharmony_ci max_packet = usb_endpoint_maxp(pep->endpoint.desc); 97562306a36Sopenharmony_ci max_burst = cdnsp_get_endpoint_max_burst(&pdev->gadget, pep); 97662306a36Sopenharmony_ci avg_trb_len = max_esit_payload; 97762306a36Sopenharmony_ci 97862306a36Sopenharmony_ci /* Allow 3 retries for everything but isoc, set CErr = 3. */ 97962306a36Sopenharmony_ci if (!usb_endpoint_xfer_isoc(pep->endpoint.desc)) 98062306a36Sopenharmony_ci err_count = 3; 98162306a36Sopenharmony_ci if (usb_endpoint_xfer_bulk(pep->endpoint.desc) && 98262306a36Sopenharmony_ci pdev->gadget.speed == USB_SPEED_HIGH) 98362306a36Sopenharmony_ci max_packet = 512; 98462306a36Sopenharmony_ci /* Controller spec indicates that ctrl ep avg TRB Length should be 8. */ 98562306a36Sopenharmony_ci if (usb_endpoint_xfer_control(pep->endpoint.desc)) 98662306a36Sopenharmony_ci avg_trb_len = 8; 98762306a36Sopenharmony_ci 98862306a36Sopenharmony_ci /* Set up the endpoint ring. */ 98962306a36Sopenharmony_ci pep->ring = cdnsp_ring_alloc(pdev, 2, ring_type, max_packet, mem_flags); 99062306a36Sopenharmony_ci if (!pep->ring) 99162306a36Sopenharmony_ci return -ENOMEM; 99262306a36Sopenharmony_ci 99362306a36Sopenharmony_ci pep->skip = false; 99462306a36Sopenharmony_ci 99562306a36Sopenharmony_ci /* Fill the endpoint context */ 99662306a36Sopenharmony_ci ep_ctx->ep_info = cpu_to_le32(EP_MAX_ESIT_PAYLOAD_HI(max_esit_payload) | 99762306a36Sopenharmony_ci EP_INTERVAL(interval) | EP_MULT(mult)); 99862306a36Sopenharmony_ci ep_ctx->ep_info2 = cpu_to_le32(EP_TYPE(endpoint_type) | 99962306a36Sopenharmony_ci MAX_PACKET(max_packet) | MAX_BURST(max_burst) | 100062306a36Sopenharmony_ci ERROR_COUNT(err_count)); 100162306a36Sopenharmony_ci ep_ctx->deq = cpu_to_le64(pep->ring->first_seg->dma | 100262306a36Sopenharmony_ci pep->ring->cycle_state); 100362306a36Sopenharmony_ci 100462306a36Sopenharmony_ci ep_ctx->tx_info = cpu_to_le32(EP_MAX_ESIT_PAYLOAD_LO(max_esit_payload) | 100562306a36Sopenharmony_ci EP_AVG_TRB_LENGTH(avg_trb_len)); 100662306a36Sopenharmony_ci 100762306a36Sopenharmony_ci if (usb_endpoint_xfer_bulk(pep->endpoint.desc) && 100862306a36Sopenharmony_ci pdev->gadget.speed > USB_SPEED_HIGH) { 100962306a36Sopenharmony_ci ret = cdnsp_alloc_streams(pdev, pep); 101062306a36Sopenharmony_ci if (ret < 0) 101162306a36Sopenharmony_ci return ret; 101262306a36Sopenharmony_ci } 101362306a36Sopenharmony_ci 101462306a36Sopenharmony_ci return 0; 101562306a36Sopenharmony_ci} 101662306a36Sopenharmony_ci 101762306a36Sopenharmony_civoid cdnsp_endpoint_zero(struct cdnsp_device *pdev, struct cdnsp_ep *pep) 101862306a36Sopenharmony_ci{ 101962306a36Sopenharmony_ci pep->in_ctx->ep_info = 0; 102062306a36Sopenharmony_ci pep->in_ctx->ep_info2 = 0; 102162306a36Sopenharmony_ci pep->in_ctx->deq = 0; 102262306a36Sopenharmony_ci pep->in_ctx->tx_info = 0; 102362306a36Sopenharmony_ci} 102462306a36Sopenharmony_ci 102562306a36Sopenharmony_cistatic int cdnsp_alloc_erst(struct cdnsp_device *pdev, 102662306a36Sopenharmony_ci struct cdnsp_ring *evt_ring, 102762306a36Sopenharmony_ci struct cdnsp_erst *erst) 102862306a36Sopenharmony_ci{ 102962306a36Sopenharmony_ci struct cdnsp_erst_entry *entry; 103062306a36Sopenharmony_ci struct cdnsp_segment *seg; 103162306a36Sopenharmony_ci unsigned int val; 103262306a36Sopenharmony_ci size_t size; 103362306a36Sopenharmony_ci 103462306a36Sopenharmony_ci size = sizeof(struct cdnsp_erst_entry) * evt_ring->num_segs; 103562306a36Sopenharmony_ci erst->entries = dma_alloc_coherent(pdev->dev, size, 103662306a36Sopenharmony_ci &erst->erst_dma_addr, GFP_KERNEL); 103762306a36Sopenharmony_ci if (!erst->entries) 103862306a36Sopenharmony_ci return -ENOMEM; 103962306a36Sopenharmony_ci 104062306a36Sopenharmony_ci erst->num_entries = evt_ring->num_segs; 104162306a36Sopenharmony_ci 104262306a36Sopenharmony_ci seg = evt_ring->first_seg; 104362306a36Sopenharmony_ci for (val = 0; val < evt_ring->num_segs; val++) { 104462306a36Sopenharmony_ci entry = &erst->entries[val]; 104562306a36Sopenharmony_ci entry->seg_addr = cpu_to_le64(seg->dma); 104662306a36Sopenharmony_ci entry->seg_size = cpu_to_le32(TRBS_PER_SEGMENT); 104762306a36Sopenharmony_ci entry->rsvd = 0; 104862306a36Sopenharmony_ci seg = seg->next; 104962306a36Sopenharmony_ci } 105062306a36Sopenharmony_ci 105162306a36Sopenharmony_ci return 0; 105262306a36Sopenharmony_ci} 105362306a36Sopenharmony_ci 105462306a36Sopenharmony_cistatic void cdnsp_free_erst(struct cdnsp_device *pdev, struct cdnsp_erst *erst) 105562306a36Sopenharmony_ci{ 105662306a36Sopenharmony_ci size_t size = sizeof(struct cdnsp_erst_entry) * (erst->num_entries); 105762306a36Sopenharmony_ci struct device *dev = pdev->dev; 105862306a36Sopenharmony_ci 105962306a36Sopenharmony_ci if (erst->entries) 106062306a36Sopenharmony_ci dma_free_coherent(dev, size, erst->entries, 106162306a36Sopenharmony_ci erst->erst_dma_addr); 106262306a36Sopenharmony_ci 106362306a36Sopenharmony_ci erst->entries = NULL; 106462306a36Sopenharmony_ci} 106562306a36Sopenharmony_ci 106662306a36Sopenharmony_civoid cdnsp_mem_cleanup(struct cdnsp_device *pdev) 106762306a36Sopenharmony_ci{ 106862306a36Sopenharmony_ci struct device *dev = pdev->dev; 106962306a36Sopenharmony_ci 107062306a36Sopenharmony_ci cdnsp_free_priv_device(pdev); 107162306a36Sopenharmony_ci cdnsp_free_erst(pdev, &pdev->erst); 107262306a36Sopenharmony_ci 107362306a36Sopenharmony_ci if (pdev->event_ring) 107462306a36Sopenharmony_ci cdnsp_ring_free(pdev, pdev->event_ring); 107562306a36Sopenharmony_ci 107662306a36Sopenharmony_ci pdev->event_ring = NULL; 107762306a36Sopenharmony_ci 107862306a36Sopenharmony_ci if (pdev->cmd_ring) 107962306a36Sopenharmony_ci cdnsp_ring_free(pdev, pdev->cmd_ring); 108062306a36Sopenharmony_ci 108162306a36Sopenharmony_ci pdev->cmd_ring = NULL; 108262306a36Sopenharmony_ci 108362306a36Sopenharmony_ci dma_pool_destroy(pdev->segment_pool); 108462306a36Sopenharmony_ci pdev->segment_pool = NULL; 108562306a36Sopenharmony_ci dma_pool_destroy(pdev->device_pool); 108662306a36Sopenharmony_ci pdev->device_pool = NULL; 108762306a36Sopenharmony_ci 108862306a36Sopenharmony_ci dma_free_coherent(dev, sizeof(*pdev->dcbaa), 108962306a36Sopenharmony_ci pdev->dcbaa, pdev->dcbaa->dma); 109062306a36Sopenharmony_ci 109162306a36Sopenharmony_ci pdev->dcbaa = NULL; 109262306a36Sopenharmony_ci 109362306a36Sopenharmony_ci pdev->usb2_port.exist = 0; 109462306a36Sopenharmony_ci pdev->usb3_port.exist = 0; 109562306a36Sopenharmony_ci pdev->usb2_port.port_num = 0; 109662306a36Sopenharmony_ci pdev->usb3_port.port_num = 0; 109762306a36Sopenharmony_ci pdev->active_port = NULL; 109862306a36Sopenharmony_ci} 109962306a36Sopenharmony_ci 110062306a36Sopenharmony_cistatic void cdnsp_set_event_deq(struct cdnsp_device *pdev) 110162306a36Sopenharmony_ci{ 110262306a36Sopenharmony_ci dma_addr_t deq; 110362306a36Sopenharmony_ci u64 temp; 110462306a36Sopenharmony_ci 110562306a36Sopenharmony_ci deq = cdnsp_trb_virt_to_dma(pdev->event_ring->deq_seg, 110662306a36Sopenharmony_ci pdev->event_ring->dequeue); 110762306a36Sopenharmony_ci 110862306a36Sopenharmony_ci /* Update controller event ring dequeue pointer */ 110962306a36Sopenharmony_ci temp = cdnsp_read_64(&pdev->ir_set->erst_dequeue); 111062306a36Sopenharmony_ci temp &= ERST_PTR_MASK; 111162306a36Sopenharmony_ci 111262306a36Sopenharmony_ci /* 111362306a36Sopenharmony_ci * Don't clear the EHB bit (which is RW1C) because 111462306a36Sopenharmony_ci * there might be more events to service. 111562306a36Sopenharmony_ci */ 111662306a36Sopenharmony_ci temp &= ~ERST_EHB; 111762306a36Sopenharmony_ci 111862306a36Sopenharmony_ci cdnsp_write_64(((u64)deq & (u64)~ERST_PTR_MASK) | temp, 111962306a36Sopenharmony_ci &pdev->ir_set->erst_dequeue); 112062306a36Sopenharmony_ci} 112162306a36Sopenharmony_ci 112262306a36Sopenharmony_cistatic void cdnsp_add_in_port(struct cdnsp_device *pdev, 112362306a36Sopenharmony_ci struct cdnsp_port *port, 112462306a36Sopenharmony_ci __le32 __iomem *addr) 112562306a36Sopenharmony_ci{ 112662306a36Sopenharmony_ci u32 temp, port_offset, port_count; 112762306a36Sopenharmony_ci 112862306a36Sopenharmony_ci temp = readl(addr); 112962306a36Sopenharmony_ci port->maj_rev = CDNSP_EXT_PORT_MAJOR(temp); 113062306a36Sopenharmony_ci port->min_rev = CDNSP_EXT_PORT_MINOR(temp); 113162306a36Sopenharmony_ci 113262306a36Sopenharmony_ci /* Port offset and count in the third dword.*/ 113362306a36Sopenharmony_ci temp = readl(addr + 2); 113462306a36Sopenharmony_ci port_offset = CDNSP_EXT_PORT_OFF(temp); 113562306a36Sopenharmony_ci port_count = CDNSP_EXT_PORT_COUNT(temp); 113662306a36Sopenharmony_ci 113762306a36Sopenharmony_ci trace_cdnsp_port_info(addr, port_offset, port_count, port->maj_rev); 113862306a36Sopenharmony_ci 113962306a36Sopenharmony_ci port->port_num = port_offset; 114062306a36Sopenharmony_ci port->exist = 1; 114162306a36Sopenharmony_ci} 114262306a36Sopenharmony_ci 114362306a36Sopenharmony_ci/* 114462306a36Sopenharmony_ci * Scan the Extended Capabilities for the "Supported Protocol Capabilities" that 114562306a36Sopenharmony_ci * specify what speeds each port is supposed to be. 114662306a36Sopenharmony_ci */ 114762306a36Sopenharmony_cistatic int cdnsp_setup_port_arrays(struct cdnsp_device *pdev) 114862306a36Sopenharmony_ci{ 114962306a36Sopenharmony_ci void __iomem *base; 115062306a36Sopenharmony_ci u32 offset; 115162306a36Sopenharmony_ci int i; 115262306a36Sopenharmony_ci 115362306a36Sopenharmony_ci base = &pdev->cap_regs->hc_capbase; 115462306a36Sopenharmony_ci offset = cdnsp_find_next_ext_cap(base, 0, 115562306a36Sopenharmony_ci EXT_CAP_CFG_DEV_20PORT_CAP_ID); 115662306a36Sopenharmony_ci pdev->port20_regs = base + offset; 115762306a36Sopenharmony_ci 115862306a36Sopenharmony_ci offset = cdnsp_find_next_ext_cap(base, 0, D_XEC_CFG_3XPORT_CAP); 115962306a36Sopenharmony_ci pdev->port3x_regs = base + offset; 116062306a36Sopenharmony_ci 116162306a36Sopenharmony_ci offset = 0; 116262306a36Sopenharmony_ci base = &pdev->cap_regs->hc_capbase; 116362306a36Sopenharmony_ci 116462306a36Sopenharmony_ci /* Driver expects max 2 extended protocol capability. */ 116562306a36Sopenharmony_ci for (i = 0; i < 2; i++) { 116662306a36Sopenharmony_ci u32 temp; 116762306a36Sopenharmony_ci 116862306a36Sopenharmony_ci offset = cdnsp_find_next_ext_cap(base, offset, 116962306a36Sopenharmony_ci EXT_CAPS_PROTOCOL); 117062306a36Sopenharmony_ci temp = readl(base + offset); 117162306a36Sopenharmony_ci 117262306a36Sopenharmony_ci if (CDNSP_EXT_PORT_MAJOR(temp) == 0x03 && 117362306a36Sopenharmony_ci !pdev->usb3_port.port_num) 117462306a36Sopenharmony_ci cdnsp_add_in_port(pdev, &pdev->usb3_port, 117562306a36Sopenharmony_ci base + offset); 117662306a36Sopenharmony_ci 117762306a36Sopenharmony_ci if (CDNSP_EXT_PORT_MAJOR(temp) == 0x02 && 117862306a36Sopenharmony_ci !pdev->usb2_port.port_num) 117962306a36Sopenharmony_ci cdnsp_add_in_port(pdev, &pdev->usb2_port, 118062306a36Sopenharmony_ci base + offset); 118162306a36Sopenharmony_ci } 118262306a36Sopenharmony_ci 118362306a36Sopenharmony_ci if (!pdev->usb2_port.exist || !pdev->usb3_port.exist) { 118462306a36Sopenharmony_ci dev_err(pdev->dev, "Error: Only one port detected\n"); 118562306a36Sopenharmony_ci return -ENODEV; 118662306a36Sopenharmony_ci } 118762306a36Sopenharmony_ci 118862306a36Sopenharmony_ci trace_cdnsp_init("Found USB 2.0 ports and USB 3.0 ports."); 118962306a36Sopenharmony_ci 119062306a36Sopenharmony_ci pdev->usb2_port.regs = (struct cdnsp_port_regs __iomem *) 119162306a36Sopenharmony_ci (&pdev->op_regs->port_reg_base + NUM_PORT_REGS * 119262306a36Sopenharmony_ci (pdev->usb2_port.port_num - 1)); 119362306a36Sopenharmony_ci 119462306a36Sopenharmony_ci pdev->usb3_port.regs = (struct cdnsp_port_regs __iomem *) 119562306a36Sopenharmony_ci (&pdev->op_regs->port_reg_base + NUM_PORT_REGS * 119662306a36Sopenharmony_ci (pdev->usb3_port.port_num - 1)); 119762306a36Sopenharmony_ci 119862306a36Sopenharmony_ci return 0; 119962306a36Sopenharmony_ci} 120062306a36Sopenharmony_ci 120162306a36Sopenharmony_ci/* 120262306a36Sopenharmony_ci * Initialize memory for CDNSP (one-time init). 120362306a36Sopenharmony_ci * 120462306a36Sopenharmony_ci * Program the PAGESIZE register, initialize the device context array, create 120562306a36Sopenharmony_ci * device contexts, set up a command ring segment, create event 120662306a36Sopenharmony_ci * ring (one for now). 120762306a36Sopenharmony_ci */ 120862306a36Sopenharmony_ciint cdnsp_mem_init(struct cdnsp_device *pdev) 120962306a36Sopenharmony_ci{ 121062306a36Sopenharmony_ci struct device *dev = pdev->dev; 121162306a36Sopenharmony_ci int ret = -ENOMEM; 121262306a36Sopenharmony_ci unsigned int val; 121362306a36Sopenharmony_ci dma_addr_t dma; 121462306a36Sopenharmony_ci u32 page_size; 121562306a36Sopenharmony_ci u64 val_64; 121662306a36Sopenharmony_ci 121762306a36Sopenharmony_ci /* 121862306a36Sopenharmony_ci * Use 4K pages, since that's common and the minimum the 121962306a36Sopenharmony_ci * controller supports 122062306a36Sopenharmony_ci */ 122162306a36Sopenharmony_ci page_size = 1 << 12; 122262306a36Sopenharmony_ci 122362306a36Sopenharmony_ci val = readl(&pdev->op_regs->config_reg); 122462306a36Sopenharmony_ci val |= ((val & ~MAX_DEVS) | CDNSP_DEV_MAX_SLOTS) | CONFIG_U3E; 122562306a36Sopenharmony_ci writel(val, &pdev->op_regs->config_reg); 122662306a36Sopenharmony_ci 122762306a36Sopenharmony_ci /* 122862306a36Sopenharmony_ci * Doorbell array must be physically contiguous 122962306a36Sopenharmony_ci * and 64-byte (cache line) aligned. 123062306a36Sopenharmony_ci */ 123162306a36Sopenharmony_ci pdev->dcbaa = dma_alloc_coherent(dev, sizeof(*pdev->dcbaa), 123262306a36Sopenharmony_ci &dma, GFP_KERNEL); 123362306a36Sopenharmony_ci if (!pdev->dcbaa) 123462306a36Sopenharmony_ci return -ENOMEM; 123562306a36Sopenharmony_ci 123662306a36Sopenharmony_ci pdev->dcbaa->dma = dma; 123762306a36Sopenharmony_ci 123862306a36Sopenharmony_ci cdnsp_write_64(dma, &pdev->op_regs->dcbaa_ptr); 123962306a36Sopenharmony_ci 124062306a36Sopenharmony_ci /* 124162306a36Sopenharmony_ci * Initialize the ring segment pool. The ring must be a contiguous 124262306a36Sopenharmony_ci * structure comprised of TRBs. The TRBs must be 16 byte aligned, 124362306a36Sopenharmony_ci * however, the command ring segment needs 64-byte aligned segments 124462306a36Sopenharmony_ci * and our use of dma addresses in the trb_address_map radix tree needs 124562306a36Sopenharmony_ci * TRB_SEGMENT_SIZE alignment, so driver pick the greater alignment 124662306a36Sopenharmony_ci * need. 124762306a36Sopenharmony_ci */ 124862306a36Sopenharmony_ci pdev->segment_pool = dma_pool_create("CDNSP ring segments", dev, 124962306a36Sopenharmony_ci TRB_SEGMENT_SIZE, TRB_SEGMENT_SIZE, 125062306a36Sopenharmony_ci page_size); 125162306a36Sopenharmony_ci if (!pdev->segment_pool) 125262306a36Sopenharmony_ci goto release_dcbaa; 125362306a36Sopenharmony_ci 125462306a36Sopenharmony_ci pdev->device_pool = dma_pool_create("CDNSP input/output contexts", dev, 125562306a36Sopenharmony_ci CDNSP_CTX_SIZE, 64, page_size); 125662306a36Sopenharmony_ci if (!pdev->device_pool) 125762306a36Sopenharmony_ci goto destroy_segment_pool; 125862306a36Sopenharmony_ci 125962306a36Sopenharmony_ci 126062306a36Sopenharmony_ci /* Set up the command ring to have one segments for now. */ 126162306a36Sopenharmony_ci pdev->cmd_ring = cdnsp_ring_alloc(pdev, 1, TYPE_COMMAND, 0, GFP_KERNEL); 126262306a36Sopenharmony_ci if (!pdev->cmd_ring) 126362306a36Sopenharmony_ci goto destroy_device_pool; 126462306a36Sopenharmony_ci 126562306a36Sopenharmony_ci /* Set the address in the Command Ring Control register */ 126662306a36Sopenharmony_ci val_64 = cdnsp_read_64(&pdev->op_regs->cmd_ring); 126762306a36Sopenharmony_ci val_64 = (val_64 & (u64)CMD_RING_RSVD_BITS) | 126862306a36Sopenharmony_ci (pdev->cmd_ring->first_seg->dma & (u64)~CMD_RING_RSVD_BITS) | 126962306a36Sopenharmony_ci pdev->cmd_ring->cycle_state; 127062306a36Sopenharmony_ci cdnsp_write_64(val_64, &pdev->op_regs->cmd_ring); 127162306a36Sopenharmony_ci 127262306a36Sopenharmony_ci val = readl(&pdev->cap_regs->db_off); 127362306a36Sopenharmony_ci val &= DBOFF_MASK; 127462306a36Sopenharmony_ci pdev->dba = (void __iomem *)pdev->cap_regs + val; 127562306a36Sopenharmony_ci 127662306a36Sopenharmony_ci /* Set ir_set to interrupt register set 0 */ 127762306a36Sopenharmony_ci pdev->ir_set = &pdev->run_regs->ir_set[0]; 127862306a36Sopenharmony_ci 127962306a36Sopenharmony_ci /* 128062306a36Sopenharmony_ci * Event ring setup: Allocate a normal ring, but also setup 128162306a36Sopenharmony_ci * the event ring segment table (ERST). 128262306a36Sopenharmony_ci */ 128362306a36Sopenharmony_ci pdev->event_ring = cdnsp_ring_alloc(pdev, ERST_NUM_SEGS, TYPE_EVENT, 128462306a36Sopenharmony_ci 0, GFP_KERNEL); 128562306a36Sopenharmony_ci if (!pdev->event_ring) 128662306a36Sopenharmony_ci goto free_cmd_ring; 128762306a36Sopenharmony_ci 128862306a36Sopenharmony_ci ret = cdnsp_alloc_erst(pdev, pdev->event_ring, &pdev->erst); 128962306a36Sopenharmony_ci if (ret) 129062306a36Sopenharmony_ci goto free_event_ring; 129162306a36Sopenharmony_ci 129262306a36Sopenharmony_ci /* Set ERST count with the number of entries in the segment table. */ 129362306a36Sopenharmony_ci val = readl(&pdev->ir_set->erst_size); 129462306a36Sopenharmony_ci val &= ERST_SIZE_MASK; 129562306a36Sopenharmony_ci val |= ERST_NUM_SEGS; 129662306a36Sopenharmony_ci writel(val, &pdev->ir_set->erst_size); 129762306a36Sopenharmony_ci 129862306a36Sopenharmony_ci /* Set the segment table base address. */ 129962306a36Sopenharmony_ci val_64 = cdnsp_read_64(&pdev->ir_set->erst_base); 130062306a36Sopenharmony_ci val_64 &= ERST_PTR_MASK; 130162306a36Sopenharmony_ci val_64 |= (pdev->erst.erst_dma_addr & (u64)~ERST_PTR_MASK); 130262306a36Sopenharmony_ci cdnsp_write_64(val_64, &pdev->ir_set->erst_base); 130362306a36Sopenharmony_ci 130462306a36Sopenharmony_ci /* Set the event ring dequeue address. */ 130562306a36Sopenharmony_ci cdnsp_set_event_deq(pdev); 130662306a36Sopenharmony_ci 130762306a36Sopenharmony_ci ret = cdnsp_setup_port_arrays(pdev); 130862306a36Sopenharmony_ci if (ret) 130962306a36Sopenharmony_ci goto free_erst; 131062306a36Sopenharmony_ci 131162306a36Sopenharmony_ci ret = cdnsp_alloc_priv_device(pdev); 131262306a36Sopenharmony_ci if (ret) { 131362306a36Sopenharmony_ci dev_err(pdev->dev, 131462306a36Sopenharmony_ci "Could not allocate cdnsp_device data structures\n"); 131562306a36Sopenharmony_ci goto free_erst; 131662306a36Sopenharmony_ci } 131762306a36Sopenharmony_ci 131862306a36Sopenharmony_ci return 0; 131962306a36Sopenharmony_ci 132062306a36Sopenharmony_cifree_erst: 132162306a36Sopenharmony_ci cdnsp_free_erst(pdev, &pdev->erst); 132262306a36Sopenharmony_cifree_event_ring: 132362306a36Sopenharmony_ci cdnsp_ring_free(pdev, pdev->event_ring); 132462306a36Sopenharmony_cifree_cmd_ring: 132562306a36Sopenharmony_ci cdnsp_ring_free(pdev, pdev->cmd_ring); 132662306a36Sopenharmony_cidestroy_device_pool: 132762306a36Sopenharmony_ci dma_pool_destroy(pdev->device_pool); 132862306a36Sopenharmony_cidestroy_segment_pool: 132962306a36Sopenharmony_ci dma_pool_destroy(pdev->segment_pool); 133062306a36Sopenharmony_cirelease_dcbaa: 133162306a36Sopenharmony_ci dma_free_coherent(dev, sizeof(*pdev->dcbaa), pdev->dcbaa, 133262306a36Sopenharmony_ci pdev->dcbaa->dma); 133362306a36Sopenharmony_ci 133462306a36Sopenharmony_ci cdnsp_reset(pdev); 133562306a36Sopenharmony_ci 133662306a36Sopenharmony_ci return ret; 133762306a36Sopenharmony_ci} 1338