1 /* 2 * Copyright (c) 2016-2018 The Linux Foundation. All rights reserved. 3 * 4 * Permission to use, copy, modify, and/or distribute this software for 5 * any purpose with or without fee is hereby granted, provided that the 6 * above copyright notice and this permission notice appear in all 7 * copies. 8 * 9 * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL 10 * WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED 11 * WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE 12 * AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL 13 * DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR 14 * PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER 15 * TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR 16 * PERFORMANCE OF THIS SOFTWARE. 17 */ 18 19 #include "dp_types.h" 20 #include "dp_rx.h" 21 22 /* 23 * dp_rx_desc_pool_alloc() - create a pool of software rx_descs 24 * at the time of dp rx initialization 25 * 26 * @soc: core txrx main context 27 * @pool_id: pool_id which is one of 3 mac_ids 28 * @pool_size: number of Rx descriptor in the pool 29 * @rx_desc_pool: rx descriptor pool pointer 30 * 31 * return success or failure 32 */ 33 QDF_STATUS dp_rx_desc_pool_alloc(struct dp_soc *soc, uint32_t pool_id, 34 uint32_t pool_size, struct rx_desc_pool *rx_desc_pool) 35 { 36 uint32_t i; 37 38 rx_desc_pool->array = 39 qdf_mem_malloc(pool_size*sizeof(union dp_rx_desc_list_elem_t)); 40 41 if (!(rx_desc_pool->array)) { 42 QDF_TRACE(QDF_MODULE_ID_DP, QDF_TRACE_LEVEL_FATAL, 43 "%s: RX Desc Pool[%d] allocation failed", 44 __func__, pool_id); 45 46 return QDF_STATUS_E_NOMEM; 47 } 48 49 /* Initialize the lock */ 50 qdf_spinlock_create(&rx_desc_pool->lock); 51 52 qdf_spin_lock_bh(&rx_desc_pool->lock); 53 rx_desc_pool->pool_size = pool_size; 54 55 /* link SW rx descs into a freelist */ 56 rx_desc_pool->freelist = &rx_desc_pool->array[0]; 57 for (i = 0; i < rx_desc_pool->pool_size-1; i++) { 58 rx_desc_pool->array[i].next = &rx_desc_pool->array[i+1]; 59 rx_desc_pool->array[i].rx_desc.cookie = i | (pool_id << 18); 60 rx_desc_pool->array[i].rx_desc.pool_id = pool_id; 61 rx_desc_pool->array[i].rx_desc.in_use = 0; 62 } 63 64 rx_desc_pool->array[i].next = NULL; 65 rx_desc_pool->array[i].rx_desc.cookie = i | (pool_id << 18); 66 rx_desc_pool->array[i].rx_desc.pool_id = pool_id; 67 qdf_spin_unlock_bh(&rx_desc_pool->lock); 68 return QDF_STATUS_SUCCESS; 69 } 70 71 /* 72 * dp_rx_desc_pool_free() - free the sw rx desc pool called during 73 * de-initialization of wifi module. 74 * 75 * @soc: core txrx main context 76 * @pool_id: pool_id which is one of 3 mac_ids 77 * @rx_desc_pool: rx descriptor pool pointer 78 */ 79 void dp_rx_desc_pool_free(struct dp_soc *soc, uint32_t pool_id, 80 struct rx_desc_pool *rx_desc_pool) 81 { 82 int i; 83 84 qdf_spin_lock_bh(&rx_desc_pool->lock); 85 for (i = 0; i < rx_desc_pool->pool_size; i++) { 86 if (rx_desc_pool->array[i].rx_desc.in_use) { 87 if (!(rx_desc_pool->array[i].rx_desc.unmapped)) 88 qdf_nbuf_unmap_single(soc->osdev, 89 rx_desc_pool->array[i].rx_desc.nbuf, 90 QDF_DMA_BIDIRECTIONAL); 91 qdf_nbuf_free(rx_desc_pool->array[i].rx_desc.nbuf); 92 } 93 } 94 qdf_mem_free(rx_desc_pool->array); 95 qdf_spin_unlock_bh(&rx_desc_pool->lock); 96 qdf_spinlock_destroy(&rx_desc_pool->lock); 97 } 98 99 /* 100 * dp_rx_get_free_desc_list() - provide a list of descriptors from 101 * the free rx desc pool. 102 * 103 * @soc: core txrx main context 104 * @pool_id: pool_id which is one of 3 mac_ids 105 * @rx_desc_pool: rx descriptor pool pointer 106 * @num_descs: number of descs requested from freelist 107 * @desc_list: attach the descs to this list (output parameter) 108 * @tail: attach the point to last desc of free list (output parameter) 109 * 110 * Return: number of descs allocated from free list. 111 */ 112 uint16_t dp_rx_get_free_desc_list(struct dp_soc *soc, uint32_t pool_id, 113 struct rx_desc_pool *rx_desc_pool, 114 uint16_t num_descs, 115 union dp_rx_desc_list_elem_t **desc_list, 116 union dp_rx_desc_list_elem_t **tail) 117 { 118 uint16_t count; 119 120 qdf_spin_lock_bh(&rx_desc_pool->lock); 121 122 *desc_list = *tail = rx_desc_pool->freelist; 123 124 for (count = 0; count < num_descs; count++) { 125 126 if (qdf_unlikely(!rx_desc_pool->freelist)) { 127 qdf_spin_unlock_bh(&rx_desc_pool->lock); 128 return count; 129 } 130 *tail = rx_desc_pool->freelist; 131 rx_desc_pool->freelist = rx_desc_pool->freelist->next; 132 } 133 (*tail)->next = NULL; 134 qdf_spin_unlock_bh(&rx_desc_pool->lock); 135 return count; 136 } 137 138 /* 139 * dp_rx_add_desc_list_to_free_list() - append unused desc_list back to 140 * freelist. 141 * 142 * @soc: core txrx main context 143 * @local_desc_list: local desc list provided by the caller 144 * @tail: attach the point to last desc of local desc list 145 * @pool_id: pool_id which is one of 3 mac_ids 146 * @rx_desc_pool: rx descriptor pool pointer 147 */ 148 void dp_rx_add_desc_list_to_free_list(struct dp_soc *soc, 149 union dp_rx_desc_list_elem_t **local_desc_list, 150 union dp_rx_desc_list_elem_t **tail, 151 uint16_t pool_id, 152 struct rx_desc_pool *rx_desc_pool) 153 { 154 union dp_rx_desc_list_elem_t *temp_list = NULL; 155 156 qdf_spin_lock_bh(&rx_desc_pool->lock); 157 158 159 temp_list = rx_desc_pool->freelist; 160 QDF_TRACE(QDF_MODULE_ID_DP, QDF_TRACE_LEVEL_DEBUG, 161 "temp_list: %pK, *local_desc_list: %pK, *tail: %pK (*tail)->next: %pK", 162 temp_list, *local_desc_list, *tail, (*tail)->next); 163 rx_desc_pool->freelist = *local_desc_list; 164 (*tail)->next = temp_list; 165 166 qdf_spin_unlock_bh(&rx_desc_pool->lock); 167 } 168