1 /* 2 * Copyright (c) 2016-2017 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\n", 44 __func__, pool_id); 45 46 return QDF_STATUS_E_NOMEM; 47 } 48 49 qdf_spin_lock_bh(&soc->rx_desc_mutex[pool_id]); 50 rx_desc_pool->pool_size = pool_size; 51 52 /* link SW rx descs into a freelist */ 53 rx_desc_pool->freelist = &rx_desc_pool->array[0]; 54 for (i = 0; i < rx_desc_pool->pool_size-1; i++) { 55 rx_desc_pool->array[i].next = &rx_desc_pool->array[i+1]; 56 rx_desc_pool->array[i].rx_desc.cookie = i | (pool_id << 18); 57 rx_desc_pool->array[i].rx_desc.pool_id = pool_id; 58 rx_desc_pool->array[i].rx_desc.in_use = 0; 59 } 60 61 rx_desc_pool->array[i].next = NULL; 62 rx_desc_pool->array[i].rx_desc.cookie = i | (pool_id << 18); 63 rx_desc_pool->array[i].rx_desc.pool_id = pool_id; 64 qdf_spin_unlock_bh(&soc->rx_desc_mutex[pool_id]); 65 return QDF_STATUS_SUCCESS; 66 } 67 68 /* 69 * dp_rx_desc_pool_free() - free the sw rx desc pool called during 70 * de-initialization of wifi module. 71 * 72 * @soc: core txrx main context 73 * @pool_id: pool_id which is one of 3 mac_ids 74 * @rx_desc_pool: rx descriptor pool pointer 75 */ 76 void dp_rx_desc_pool_free(struct dp_soc *soc, uint32_t pool_id, 77 struct rx_desc_pool *rx_desc_pool) 78 { 79 int i; 80 81 qdf_spin_lock_bh(&soc->rx_desc_mutex[pool_id]); 82 for (i = 0; i < rx_desc_pool->pool_size; i++) { 83 if (rx_desc_pool->array[i].rx_desc.in_use) { 84 qdf_nbuf_unmap_single(soc->osdev, 85 rx_desc_pool->array[i].rx_desc.nbuf, 86 QDF_DMA_BIDIRECTIONAL); 87 qdf_nbuf_free(rx_desc_pool->array[i].rx_desc.nbuf); 88 } 89 } 90 qdf_mem_free(rx_desc_pool->array); 91 qdf_spin_unlock_bh(&soc->rx_desc_mutex[pool_id]); 92 } 93 94 /* 95 * dp_rx_get_free_desc_list() - provide a list of descriptors from 96 * the free rx desc pool. 97 * 98 * @soc: core txrx main context 99 * @pool_id: pool_id which is one of 3 mac_ids 100 * @rx_desc_pool: rx descriptor pool pointer 101 * @num_descs: number of descs requested from freelist 102 * @desc_list: attach the descs to this list (output parameter) 103 * @tail: attach the point to last desc of free list (output parameter) 104 * 105 * Return: number of descs allocated from free list. 106 */ 107 uint16_t dp_rx_get_free_desc_list(struct dp_soc *soc, uint32_t pool_id, 108 struct rx_desc_pool *rx_desc_pool, 109 uint16_t num_descs, 110 union dp_rx_desc_list_elem_t **desc_list, 111 union dp_rx_desc_list_elem_t **tail) 112 { 113 uint16_t count; 114 115 qdf_spin_lock_bh(&soc->rx_desc_mutex[pool_id]); 116 117 *desc_list = rx_desc_pool->freelist; 118 119 if (!(*desc_list)) { 120 qdf_spin_unlock_bh(&soc->rx_desc_mutex[pool_id]); 121 return 0; 122 } 123 124 for (count = 0; count < num_descs; count++) { 125 126 *tail = rx_desc_pool->freelist; 127 rx_desc_pool->freelist = rx_desc_pool->freelist->next; 128 if (qdf_unlikely(!rx_desc_pool->freelist)) { 129 qdf_spin_unlock_bh(&soc->rx_desc_mutex[pool_id]); 130 return count; 131 } 132 } 133 (*tail)->next = NULL; 134 qdf_spin_unlock_bh(&soc->rx_desc_mutex[pool_id]); 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(&soc->rx_desc_mutex[pool_id]); 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\n", 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(&soc->rx_desc_mutex[pool_id]); 167 } 168