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 /** 20 * DOC: wlan_mgmt_txrx_main.c 21 * This file contains mgmt txrx private API definitions for 22 * mgmt txrx component. 23 */ 24 25 #include "wlan_mgmt_txrx_main_i.h" 26 #include "qdf_nbuf.h" 27 28 QDF_STATUS wlan_mgmt_txrx_desc_pool_init( 29 struct mgmt_txrx_priv_context *mgmt_txrx_ctx, 30 uint32_t pool_size) 31 { 32 uint32_t i; 33 34 if (!pool_size) { 35 mgmt_txrx_err("Invalid pool size %u given", pool_size); 36 qdf_assert_always(pool_size); 37 return QDF_STATUS_E_INVAL; 38 } 39 40 mgmt_txrx_info("mgmt_txrx ctx: %p psoc: %p, initialize mgmt desc pool of size %d", 41 mgmt_txrx_ctx, mgmt_txrx_ctx->psoc, pool_size); 42 mgmt_txrx_ctx->mgmt_desc_pool.pool = qdf_mem_malloc(pool_size * 43 sizeof(struct mgmt_txrx_desc_elem_t)); 44 45 if (!mgmt_txrx_ctx->mgmt_desc_pool.pool) { 46 mgmt_txrx_err("Failed to allocate desc pool"); 47 return QDF_STATUS_E_NOMEM; 48 } 49 qdf_list_create(&mgmt_txrx_ctx->mgmt_desc_pool.free_list, pool_size); 50 51 for (i = 0; i < pool_size; i++) { 52 mgmt_txrx_ctx->mgmt_desc_pool.pool[i].desc_id = i; 53 mgmt_txrx_ctx->mgmt_desc_pool.pool[i].in_use = false; 54 qdf_list_insert_front(&mgmt_txrx_ctx->mgmt_desc_pool.free_list, 55 &mgmt_txrx_ctx->mgmt_desc_pool.pool[i].entry); 56 } 57 58 qdf_spinlock_create( 59 &mgmt_txrx_ctx->mgmt_desc_pool.desc_pool_lock); 60 61 return QDF_STATUS_SUCCESS; 62 } 63 64 void wlan_mgmt_txrx_desc_pool_deinit( 65 struct mgmt_txrx_priv_context *mgmt_txrx_ctx) 66 { 67 uint8_t i; 68 uint32_t pool_size; 69 QDF_STATUS status; 70 71 if (!mgmt_txrx_ctx->mgmt_desc_pool.pool) { 72 mgmt_txrx_err("Empty mgmt descriptor pool"); 73 qdf_assert_always(0); 74 return; 75 } 76 77 pool_size = mgmt_txrx_ctx->mgmt_desc_pool.free_list.max_size; 78 for (i = 0; i < pool_size; i++) { 79 status = qdf_list_remove_node( 80 &mgmt_txrx_ctx->mgmt_desc_pool.free_list, 81 &mgmt_txrx_ctx->mgmt_desc_pool.pool[i].entry); 82 if (status != QDF_STATUS_SUCCESS) 83 mgmt_txrx_err("Failed to get mgmt descriptor from freelist, desc id: %d with status %d", 84 i, status); 85 } 86 87 qdf_list_destroy(&mgmt_txrx_ctx->mgmt_desc_pool.free_list); 88 qdf_mem_free(mgmt_txrx_ctx->mgmt_desc_pool.pool); 89 mgmt_txrx_ctx->mgmt_desc_pool.pool = NULL; 90 91 qdf_spinlock_destroy( 92 &mgmt_txrx_ctx->mgmt_desc_pool.desc_pool_lock); 93 } 94 95 struct mgmt_txrx_desc_elem_t *wlan_mgmt_txrx_desc_get( 96 struct mgmt_txrx_priv_context *mgmt_txrx_ctx) 97 { 98 QDF_STATUS status; 99 qdf_list_node_t *desc_node; 100 struct mgmt_txrx_desc_elem_t *mgmt_txrx_desc; 101 102 qdf_spin_lock_bh(&mgmt_txrx_ctx->mgmt_desc_pool.desc_pool_lock); 103 if (qdf_list_peek_front(&mgmt_txrx_ctx->mgmt_desc_pool.free_list, 104 &desc_node) 105 != QDF_STATUS_SUCCESS) { 106 qdf_spin_unlock_bh( 107 &mgmt_txrx_ctx->mgmt_desc_pool.desc_pool_lock); 108 mgmt_txrx_err("Descriptor freelist empty for mgmt_txrx_ctx %p", 109 mgmt_txrx_ctx); 110 return NULL; 111 } 112 113 status = qdf_list_remove_node(&mgmt_txrx_ctx->mgmt_desc_pool.free_list, 114 desc_node); 115 if (status != QDF_STATUS_SUCCESS) { 116 qdf_spin_unlock_bh( 117 &mgmt_txrx_ctx->mgmt_desc_pool.desc_pool_lock); 118 mgmt_txrx_err("Failed to get descriptor from list: status %d", 119 status); 120 qdf_assert_always(0); 121 return NULL; 122 } 123 124 mgmt_txrx_desc = qdf_container_of(desc_node, 125 struct mgmt_txrx_desc_elem_t, 126 entry); 127 mgmt_txrx_desc->in_use = true; 128 129 /* acquire the wakelock when there are pending mgmt tx frames */ 130 qdf_wake_lock_timeout_acquire(&mgmt_txrx_ctx->wakelock_tx_cmp, 131 MGMT_TXRX_WAKELOCK_TIMEOUT_TX_CMP); 132 133 qdf_spin_unlock_bh(&mgmt_txrx_ctx->mgmt_desc_pool.desc_pool_lock); 134 135 mgmt_txrx_info("retrieved mgmt desc: %p with desc id: %d", 136 mgmt_txrx_desc, mgmt_txrx_desc->desc_id); 137 return mgmt_txrx_desc; 138 } 139 140 void wlan_mgmt_txrx_desc_put(struct mgmt_txrx_priv_context *mgmt_txrx_ctx, 141 uint32_t desc_id) 142 { 143 struct mgmt_txrx_desc_elem_t *desc; 144 145 desc = &mgmt_txrx_ctx->mgmt_desc_pool.pool[desc_id]; 146 qdf_spin_lock_bh(&mgmt_txrx_ctx->mgmt_desc_pool.desc_pool_lock); 147 desc->in_use = false; 148 qdf_list_insert_front(&mgmt_txrx_ctx->mgmt_desc_pool.free_list, 149 &desc->entry); 150 151 /* release the wakelock if there are no pending mgmt tx frames */ 152 if (mgmt_txrx_ctx->mgmt_desc_pool.free_list.count == 153 mgmt_txrx_ctx->mgmt_desc_pool.free_list.max_size) 154 qdf_wake_lock_release(&mgmt_txrx_ctx->wakelock_tx_cmp, 155 MGMT_TXRX_WAKELOCK_REASON_TX_CMP); 156 157 qdf_spin_unlock_bh(&mgmt_txrx_ctx->mgmt_desc_pool.desc_pool_lock); 158 159 mgmt_txrx_info("put mgmt desc: %p with desc id: %d into freelist", 160 desc, desc->desc_id); 161 } 162