1 /* 2 * Copyright (c) 2016-2020 The Linux Foundation. All rights reserved. 3 * Copyright (c) 2023-2024 Qualcomm Innovation Center, Inc. All rights reserved. 4 * 5 * Permission to use, copy, modify, and/or distribute this software for 6 * any purpose with or without fee is hereby granted, provided that the 7 * above copyright notice and this permission notice appear in all 8 * copies. 9 * 10 * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL 11 * WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED 12 * WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE 13 * AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL 14 * DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR 15 * PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER 16 * TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR 17 * PERFORMANCE OF THIS SOFTWARE. 18 */ 19 20 /** 21 * DOC: wlan_mgmt_txrx_main.c 22 * This file contains mgmt txrx private API definitions for 23 * mgmt txrx component. 24 */ 25 26 #include "wlan_mgmt_txrx_main_i.h" 27 #include "qdf_nbuf.h" 28 #include "wlan_objmgr_pdev_obj.h" 29 #include "wlan_objmgr_psoc_obj.h" 30 31 QDF_STATUS wlan_mgmt_txrx_desc_pool_init( 32 struct mgmt_txrx_priv_pdev_context *mgmt_txrx_pdev_ctx) 33 { 34 struct wlan_objmgr_pdev *pdev; 35 struct wlan_objmgr_psoc *psoc; 36 uint32_t i; 37 uint8_t pdev_id; 38 uint8_t psoc_id; 39 40 pdev = mgmt_txrx_pdev_ctx->pdev; 41 if (!pdev) { 42 mgmt_txrx_err("pdev context passed is NULL"); 43 return QDF_STATUS_E_INVAL; 44 } 45 46 psoc = wlan_pdev_get_psoc(pdev); 47 48 if (!psoc) { 49 mgmt_txrx_err("psoc context in pdev is NULL"); 50 return QDF_STATUS_E_INVAL; 51 } 52 53 pdev_id = wlan_objmgr_pdev_get_pdev_id(pdev); 54 55 psoc_id = wlan_psoc_get_id(psoc); 56 57 mgmt_txrx_debug( 58 "mgmt_txrx ctx: %pK pdev: %pK pdev_id: %d psoc_id: %d mgmt desc pool size %d", 59 mgmt_txrx_pdev_ctx, pdev, 60 pdev_id, psoc_id, 61 MGMT_DESC_POOL_MAX); 62 mgmt_txrx_pdev_ctx->mgmt_desc_pool.pool = qdf_mem_malloc( 63 MGMT_DESC_POOL_MAX * 64 sizeof(struct mgmt_txrx_desc_elem_t)); 65 66 if (!mgmt_txrx_pdev_ctx->mgmt_desc_pool.pool) 67 return QDF_STATUS_E_NOMEM; 68 69 qdf_list_create(&mgmt_txrx_pdev_ctx->mgmt_desc_pool.free_list, 70 MGMT_DESC_POOL_MAX); 71 72 for (i = 0; i < MGMT_DESC_POOL_MAX; i++) { 73 mgmt_txrx_pdev_ctx->mgmt_desc_pool.pool[i].desc_id = i; 74 mgmt_txrx_pdev_ctx->mgmt_desc_pool.pool[i].in_use = false; 75 qdf_list_insert_front( 76 &mgmt_txrx_pdev_ctx->mgmt_desc_pool.free_list, 77 &mgmt_txrx_pdev_ctx->mgmt_desc_pool.pool[i].entry); 78 } 79 80 qdf_spinlock_create( 81 &mgmt_txrx_pdev_ctx->mgmt_desc_pool.desc_pool_lock); 82 83 mgmt_txrx_debug("exit pdev_id:%d psoc_id:%d", pdev_id, psoc_id); 84 85 return QDF_STATUS_SUCCESS; 86 } 87 88 void wlan_mgmt_txrx_desc_pool_deinit( 89 struct mgmt_txrx_priv_pdev_context *mgmt_txrx_pdev_ctx) 90 { 91 uint32_t i; 92 uint32_t pool_size; 93 QDF_STATUS status; 94 95 if (!mgmt_txrx_pdev_ctx->mgmt_desc_pool.pool) { 96 mgmt_txrx_err("Empty mgmt descriptor pool"); 97 qdf_assert_always(0); 98 return; 99 } 100 101 pool_size = mgmt_txrx_pdev_ctx->mgmt_desc_pool.free_list.max_size; 102 for (i = 0; i < pool_size; i++) { 103 status = qdf_list_remove_node( 104 &mgmt_txrx_pdev_ctx->mgmt_desc_pool.free_list, 105 &mgmt_txrx_pdev_ctx->mgmt_desc_pool.pool[i].entry); 106 if (status != QDF_STATUS_SUCCESS) 107 mgmt_txrx_err( 108 "Failed to get mgmt desc from freelist, desc id: %d: status %d", 109 i, status); 110 } 111 112 qdf_list_destroy(&mgmt_txrx_pdev_ctx->mgmt_desc_pool.free_list); 113 qdf_mem_free(mgmt_txrx_pdev_ctx->mgmt_desc_pool.pool); 114 mgmt_txrx_pdev_ctx->mgmt_desc_pool.pool = NULL; 115 116 qdf_spinlock_destroy( 117 &mgmt_txrx_pdev_ctx->mgmt_desc_pool.desc_pool_lock); 118 } 119 120 struct mgmt_txrx_desc_elem_t *wlan_mgmt_txrx_desc_get( 121 struct mgmt_txrx_priv_pdev_context *mgmt_txrx_pdev_ctx) 122 { 123 QDF_STATUS status; 124 qdf_list_node_t *desc_node; 125 struct mgmt_txrx_desc_elem_t *mgmt_txrx_desc; 126 127 qdf_spin_lock_bh(&mgmt_txrx_pdev_ctx->mgmt_desc_pool.desc_pool_lock); 128 if (qdf_list_peek_front(&mgmt_txrx_pdev_ctx->mgmt_desc_pool.free_list, 129 &desc_node) 130 != QDF_STATUS_SUCCESS) { 131 qdf_spin_unlock_bh( 132 &mgmt_txrx_pdev_ctx->mgmt_desc_pool.desc_pool_lock); 133 mgmt_txrx_err_rl("Descriptor freelist empty for mgmt_txrx_ctx %pK", 134 mgmt_txrx_pdev_ctx); 135 return NULL; 136 } 137 138 status = qdf_list_remove_node( 139 &mgmt_txrx_pdev_ctx->mgmt_desc_pool.free_list, 140 desc_node); 141 if (status != QDF_STATUS_SUCCESS) { 142 qdf_spin_unlock_bh( 143 &mgmt_txrx_pdev_ctx->mgmt_desc_pool.desc_pool_lock); 144 mgmt_txrx_err("Failed to get descriptor from list: status %d", 145 status); 146 qdf_assert_always(0); 147 } 148 149 mgmt_txrx_desc = qdf_container_of(desc_node, 150 struct mgmt_txrx_desc_elem_t, 151 entry); 152 mgmt_txrx_desc->in_use = true; 153 154 qdf_spin_unlock_bh(&mgmt_txrx_pdev_ctx->mgmt_desc_pool.desc_pool_lock); 155 156 /* acquire the wakelock when there are pending mgmt tx frames */ 157 qdf_wake_lock_timeout_acquire(&mgmt_txrx_pdev_ctx->wakelock_tx_cmp, 158 MGMT_TXRX_WAKELOCK_TIMEOUT_TX_CMP); 159 qdf_runtime_pm_prevent_suspend( 160 &mgmt_txrx_pdev_ctx->wakelock_tx_runtime_cmp); 161 162 163 return mgmt_txrx_desc; 164 } 165 166 void wlan_mgmt_txrx_desc_put( 167 struct mgmt_txrx_priv_pdev_context *mgmt_txrx_pdev_ctx, 168 uint32_t desc_id) 169 { 170 struct mgmt_txrx_desc_elem_t *desc; 171 bool release_wakelock = false; 172 173 desc = &mgmt_txrx_pdev_ctx->mgmt_desc_pool.pool[desc_id]; 174 qdf_spin_lock_bh(&mgmt_txrx_pdev_ctx->mgmt_desc_pool.desc_pool_lock); 175 if (!desc->in_use) { 176 qdf_spin_unlock_bh(&mgmt_txrx_pdev_ctx->mgmt_desc_pool. 177 desc_pool_lock); 178 mgmt_txrx_err("desc %d is freed", desc_id); 179 return; 180 } 181 desc->in_use = false; 182 desc->context = NULL; 183 desc->peer = NULL; 184 desc->nbuf = NULL; 185 desc->tx_dwnld_cmpl_cb = NULL; 186 desc->tx_ota_cmpl_cb = NULL; 187 desc->vdev_id = WLAN_UMAC_VDEV_ID_MAX; 188 189 qdf_list_insert_front(&mgmt_txrx_pdev_ctx->mgmt_desc_pool.free_list, 190 &desc->entry); 191 192 /* release the wakelock if there are no pending mgmt tx frames */ 193 if (mgmt_txrx_pdev_ctx->mgmt_desc_pool.free_list.count == 194 mgmt_txrx_pdev_ctx->mgmt_desc_pool.free_list.max_size) 195 release_wakelock = true; 196 197 qdf_spin_unlock_bh(&mgmt_txrx_pdev_ctx->mgmt_desc_pool.desc_pool_lock); 198 199 if (release_wakelock) { 200 qdf_runtime_pm_allow_suspend( 201 &mgmt_txrx_pdev_ctx->wakelock_tx_runtime_cmp); 202 qdf_wake_lock_release(&mgmt_txrx_pdev_ctx->wakelock_tx_cmp, 203 MGMT_TXRX_WAKELOCK_REASON_TX_CMP); 204 } 205 } 206 207 #ifdef WLAN_IOT_SIM_SUPPORT 208 QDF_STATUS iot_sim_mgmt_tx_update(struct wlan_objmgr_psoc *psoc, 209 struct wlan_objmgr_vdev *vdev, 210 qdf_nbuf_t buf) 211 { 212 struct wlan_lmac_if_rx_ops *rx_ops; 213 QDF_STATUS status = QDF_STATUS_SUCCESS; 214 215 rx_ops = wlan_psoc_get_lmac_if_rxops(psoc); 216 if (!rx_ops) { 217 mgmt_txrx_err("rx_ops is NULL"); 218 return QDF_STATUS_E_NULL_VALUE; 219 } 220 if (rx_ops->iot_sim_rx_ops.iot_sim_cmd_handler) { 221 status = rx_ops->iot_sim_rx_ops.iot_sim_cmd_handler(vdev, 222 buf, 223 NULL, 224 true, 225 NULL); 226 if (status == QDF_STATUS_E_NULL_VALUE) 227 mgmt_txrx_err("iot_sim frame drop"); 228 else 229 status = QDF_STATUS_SUCCESS; 230 } 231 232 return status; 233 } 234 #else 235 QDF_STATUS iot_sim_mgmt_tx_update(struct wlan_objmgr_psoc *psoc, 236 struct wlan_objmgr_vdev *vdev, 237 qdf_nbuf_t buf) 238 { 239 return QDF_STATUS_SUCCESS; 240 } 241 #endif 242