1 /* 2 * Copyright (c) 2016-2019 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 if (!dp_is_soc_reinit(soc)) { 39 rx_desc_pool->array = 40 qdf_mem_malloc(pool_size * 41 sizeof(union dp_rx_desc_list_elem_t)); 42 43 if (!(rx_desc_pool->array)) { 44 QDF_TRACE(QDF_MODULE_ID_DP, QDF_TRACE_LEVEL_FATAL, 45 "%s: RX Desc Pool[%d] allocation failed", 46 __func__, pool_id); 47 return QDF_STATUS_E_NOMEM; 48 } 49 } 50 51 /* Initialize the lock */ 52 qdf_spinlock_create(&rx_desc_pool->lock); 53 54 qdf_spin_lock_bh(&rx_desc_pool->lock); 55 rx_desc_pool->pool_size = pool_size; 56 57 /* link SW rx descs into a freelist */ 58 rx_desc_pool->freelist = &rx_desc_pool->array[0]; 59 for (i = 0; i < rx_desc_pool->pool_size-1; i++) { 60 rx_desc_pool->array[i].next = &rx_desc_pool->array[i+1]; 61 rx_desc_pool->array[i].rx_desc.cookie = i | (pool_id << 18); 62 rx_desc_pool->array[i].rx_desc.pool_id = pool_id; 63 rx_desc_pool->array[i].rx_desc.in_use = 0; 64 } 65 66 rx_desc_pool->array[i].next = NULL; 67 rx_desc_pool->array[i].rx_desc.cookie = i | (pool_id << 18); 68 rx_desc_pool->array[i].rx_desc.pool_id = pool_id; 69 qdf_spin_unlock_bh(&rx_desc_pool->lock); 70 return QDF_STATUS_SUCCESS; 71 } 72 73 /* 74 * dp_rx_desc_pool_free() - free the sw rx desc pool called during 75 * de-initialization of wifi module. 76 * 77 * @soc: core txrx main context 78 * @pool_id: pool_id which is one of 3 mac_ids 79 * @rx_desc_pool: rx descriptor pool pointer 80 */ 81 void dp_rx_desc_pool_free(struct dp_soc *soc, uint32_t pool_id, 82 struct rx_desc_pool *rx_desc_pool) 83 { 84 int i; 85 86 qdf_spin_lock_bh(&rx_desc_pool->lock); 87 for (i = 0; i < rx_desc_pool->pool_size; i++) { 88 if (rx_desc_pool->array[i].rx_desc.in_use) { 89 if (!(rx_desc_pool->array[i].rx_desc.unmapped)) 90 qdf_nbuf_unmap_single(soc->osdev, 91 rx_desc_pool->array[i].rx_desc.nbuf, 92 QDF_DMA_BIDIRECTIONAL); 93 qdf_nbuf_free(rx_desc_pool->array[i].rx_desc.nbuf); 94 } 95 } 96 qdf_mem_free(rx_desc_pool->array); 97 qdf_spin_unlock_bh(&rx_desc_pool->lock); 98 qdf_spinlock_destroy(&rx_desc_pool->lock); 99 } 100 101 /* 102 * dp_rx_desc_pool_free_nbuf() - free the sw rx desc nbufs called during 103 * de-initialization of wifi module. 104 * 105 * @soc: core txrx main context 106 * @pool_id: pool_id which is one of 3 mac_ids 107 * @rx_desc_pool: rx descriptor pool pointer 108 */ 109 void dp_rx_desc_nbuf_pool_free(struct dp_soc *soc, 110 struct rx_desc_pool *rx_desc_pool) 111 { 112 int i; 113 114 qdf_spin_lock_bh(&rx_desc_pool->lock); 115 for (i = 0; i < rx_desc_pool->pool_size; i++) { 116 if (rx_desc_pool->array[i].rx_desc.in_use) { 117 if (!(rx_desc_pool->array[i].rx_desc.unmapped)) 118 qdf_nbuf_unmap_single(soc->osdev, 119 rx_desc_pool->array[i].rx_desc.nbuf, 120 QDF_DMA_BIDIRECTIONAL); 121 qdf_nbuf_free(rx_desc_pool->array[i].rx_desc.nbuf); 122 } 123 } 124 qdf_spin_unlock_bh(&rx_desc_pool->lock); 125 qdf_spinlock_destroy(&rx_desc_pool->lock); 126 } 127 128 /* 129 * dp_rx_get_free_desc_list() - provide a list of descriptors from 130 * the free rx desc pool. 131 * 132 * @soc: core txrx main context 133 * @pool_id: pool_id which is one of 3 mac_ids 134 * @rx_desc_pool: rx descriptor pool pointer 135 * @num_descs: number of descs requested from freelist 136 * @desc_list: attach the descs to this list (output parameter) 137 * @tail: attach the point to last desc of free list (output parameter) 138 * 139 * Return: number of descs allocated from free list. 140 */ 141 uint16_t dp_rx_get_free_desc_list(struct dp_soc *soc, uint32_t pool_id, 142 struct rx_desc_pool *rx_desc_pool, 143 uint16_t num_descs, 144 union dp_rx_desc_list_elem_t **desc_list, 145 union dp_rx_desc_list_elem_t **tail) 146 { 147 uint16_t count; 148 149 qdf_spin_lock_bh(&rx_desc_pool->lock); 150 151 *desc_list = *tail = rx_desc_pool->freelist; 152 153 for (count = 0; count < num_descs; count++) { 154 155 if (qdf_unlikely(!rx_desc_pool->freelist)) { 156 qdf_spin_unlock_bh(&rx_desc_pool->lock); 157 return count; 158 } 159 *tail = rx_desc_pool->freelist; 160 rx_desc_pool->freelist = rx_desc_pool->freelist->next; 161 } 162 (*tail)->next = NULL; 163 qdf_spin_unlock_bh(&rx_desc_pool->lock); 164 return count; 165 } 166 167 /* 168 * dp_rx_add_desc_list_to_free_list() - append unused desc_list back to 169 * freelist. 170 * 171 * @soc: core txrx main context 172 * @local_desc_list: local desc list provided by the caller 173 * @tail: attach the point to last desc of local desc list 174 * @pool_id: pool_id which is one of 3 mac_ids 175 * @rx_desc_pool: rx descriptor pool pointer 176 */ 177 void dp_rx_add_desc_list_to_free_list(struct dp_soc *soc, 178 union dp_rx_desc_list_elem_t **local_desc_list, 179 union dp_rx_desc_list_elem_t **tail, 180 uint16_t pool_id, 181 struct rx_desc_pool *rx_desc_pool) 182 { 183 union dp_rx_desc_list_elem_t *temp_list = NULL; 184 185 qdf_spin_lock_bh(&rx_desc_pool->lock); 186 187 188 temp_list = rx_desc_pool->freelist; 189 QDF_TRACE(QDF_MODULE_ID_DP, QDF_TRACE_LEVEL_DEBUG, 190 "temp_list: %pK, *local_desc_list: %pK, *tail: %pK (*tail)->next: %pK", 191 temp_list, *local_desc_list, *tail, (*tail)->next); 192 rx_desc_pool->freelist = *local_desc_list; 193 (*tail)->next = temp_list; 194 195 qdf_spin_unlock_bh(&rx_desc_pool->lock); 196 } 197