1 /* 2 * Copyright (c) 2016-2020 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_pdev_context *mgmt_txrx_pdev_ctx) 30 { 31 uint32_t i; 32 33 mgmt_txrx_debug( 34 "mgmt_txrx ctx: %pK pdev: %pK mgmt desc pool size %d", 35 mgmt_txrx_pdev_ctx, mgmt_txrx_pdev_ctx->pdev, 36 MGMT_DESC_POOL_MAX); 37 mgmt_txrx_pdev_ctx->mgmt_desc_pool.pool = qdf_mem_malloc( 38 MGMT_DESC_POOL_MAX * 39 sizeof(struct mgmt_txrx_desc_elem_t)); 40 41 if (!mgmt_txrx_pdev_ctx->mgmt_desc_pool.pool) 42 return QDF_STATUS_E_NOMEM; 43 44 qdf_list_create(&mgmt_txrx_pdev_ctx->mgmt_desc_pool.free_list, 45 MGMT_DESC_POOL_MAX); 46 47 for (i = 0; i < MGMT_DESC_POOL_MAX; i++) { 48 mgmt_txrx_pdev_ctx->mgmt_desc_pool.pool[i].desc_id = i; 49 mgmt_txrx_pdev_ctx->mgmt_desc_pool.pool[i].in_use = false; 50 qdf_list_insert_front( 51 &mgmt_txrx_pdev_ctx->mgmt_desc_pool.free_list, 52 &mgmt_txrx_pdev_ctx->mgmt_desc_pool.pool[i].entry); 53 } 54 55 qdf_spinlock_create( 56 &mgmt_txrx_pdev_ctx->mgmt_desc_pool.desc_pool_lock); 57 58 return QDF_STATUS_SUCCESS; 59 } 60 61 void wlan_mgmt_txrx_desc_pool_deinit( 62 struct mgmt_txrx_priv_pdev_context *mgmt_txrx_pdev_ctx) 63 { 64 uint32_t i; 65 uint32_t pool_size; 66 QDF_STATUS status; 67 68 if (!mgmt_txrx_pdev_ctx->mgmt_desc_pool.pool) { 69 mgmt_txrx_err("Empty mgmt descriptor pool"); 70 qdf_assert_always(0); 71 return; 72 } 73 74 pool_size = mgmt_txrx_pdev_ctx->mgmt_desc_pool.free_list.max_size; 75 for (i = 0; i < pool_size; i++) { 76 status = qdf_list_remove_node( 77 &mgmt_txrx_pdev_ctx->mgmt_desc_pool.free_list, 78 &mgmt_txrx_pdev_ctx->mgmt_desc_pool.pool[i].entry); 79 if (status != QDF_STATUS_SUCCESS) 80 mgmt_txrx_err( 81 "Failed to get mgmt desc from freelist, desc id: %d: status %d", 82 i, status); 83 } 84 85 qdf_list_destroy(&mgmt_txrx_pdev_ctx->mgmt_desc_pool.free_list); 86 qdf_mem_free(mgmt_txrx_pdev_ctx->mgmt_desc_pool.pool); 87 mgmt_txrx_pdev_ctx->mgmt_desc_pool.pool = NULL; 88 89 qdf_spinlock_destroy( 90 &mgmt_txrx_pdev_ctx->mgmt_desc_pool.desc_pool_lock); 91 } 92 93 struct mgmt_txrx_desc_elem_t *wlan_mgmt_txrx_desc_get( 94 struct mgmt_txrx_priv_pdev_context *mgmt_txrx_pdev_ctx) 95 { 96 QDF_STATUS status; 97 qdf_list_node_t *desc_node; 98 struct mgmt_txrx_desc_elem_t *mgmt_txrx_desc; 99 100 qdf_spin_lock_bh(&mgmt_txrx_pdev_ctx->mgmt_desc_pool.desc_pool_lock); 101 if (qdf_list_peek_front(&mgmt_txrx_pdev_ctx->mgmt_desc_pool.free_list, 102 &desc_node) 103 != QDF_STATUS_SUCCESS) { 104 qdf_spin_unlock_bh( 105 &mgmt_txrx_pdev_ctx->mgmt_desc_pool.desc_pool_lock); 106 mgmt_txrx_err("Descriptor freelist empty for mgmt_txrx_ctx %pK", 107 mgmt_txrx_pdev_ctx); 108 return NULL; 109 } 110 111 status = qdf_list_remove_node( 112 &mgmt_txrx_pdev_ctx->mgmt_desc_pool.free_list, 113 desc_node); 114 if (status != QDF_STATUS_SUCCESS) { 115 qdf_spin_unlock_bh( 116 &mgmt_txrx_pdev_ctx->mgmt_desc_pool.desc_pool_lock); 117 mgmt_txrx_err("Failed to get descriptor from list: status %d", 118 status); 119 qdf_assert_always(0); 120 } 121 122 mgmt_txrx_desc = qdf_container_of(desc_node, 123 struct mgmt_txrx_desc_elem_t, 124 entry); 125 mgmt_txrx_desc->in_use = true; 126 127 qdf_spin_unlock_bh(&mgmt_txrx_pdev_ctx->mgmt_desc_pool.desc_pool_lock); 128 129 /* acquire the wakelock when there are pending mgmt tx frames */ 130 qdf_wake_lock_timeout_acquire(&mgmt_txrx_pdev_ctx->wakelock_tx_cmp, 131 MGMT_TXRX_WAKELOCK_TIMEOUT_TX_CMP); 132 qdf_runtime_pm_prevent_suspend( 133 &mgmt_txrx_pdev_ctx->wakelock_tx_runtime_cmp); 134 135 136 return mgmt_txrx_desc; 137 } 138 139 void wlan_mgmt_txrx_desc_put( 140 struct mgmt_txrx_priv_pdev_context *mgmt_txrx_pdev_ctx, 141 uint32_t desc_id) 142 { 143 struct mgmt_txrx_desc_elem_t *desc; 144 bool release_wakelock = false; 145 146 desc = &mgmt_txrx_pdev_ctx->mgmt_desc_pool.pool[desc_id]; 147 qdf_spin_lock_bh(&mgmt_txrx_pdev_ctx->mgmt_desc_pool.desc_pool_lock); 148 if (!desc->in_use) { 149 qdf_spin_unlock_bh(&mgmt_txrx_pdev_ctx->mgmt_desc_pool. 150 desc_pool_lock); 151 mgmt_txrx_err("desc %d is freed", desc_id); 152 return; 153 } 154 desc->in_use = false; 155 desc->context = NULL; 156 desc->peer = NULL; 157 desc->nbuf = NULL; 158 desc->tx_dwnld_cmpl_cb = NULL; 159 desc->tx_ota_cmpl_cb = NULL; 160 desc->vdev_id = WLAN_UMAC_VDEV_ID_MAX; 161 162 qdf_list_insert_front(&mgmt_txrx_pdev_ctx->mgmt_desc_pool.free_list, 163 &desc->entry); 164 165 /* release the wakelock if there are no pending mgmt tx frames */ 166 if (mgmt_txrx_pdev_ctx->mgmt_desc_pool.free_list.count == 167 mgmt_txrx_pdev_ctx->mgmt_desc_pool.free_list.max_size) 168 release_wakelock = true; 169 170 qdf_spin_unlock_bh(&mgmt_txrx_pdev_ctx->mgmt_desc_pool.desc_pool_lock); 171 172 if (release_wakelock) { 173 qdf_runtime_pm_allow_suspend( 174 &mgmt_txrx_pdev_ctx->wakelock_tx_runtime_cmp); 175 qdf_wake_lock_release(&mgmt_txrx_pdev_ctx->wakelock_tx_cmp, 176 MGMT_TXRX_WAKELOCK_REASON_TX_CMP); 177 } 178 } 179 180 #ifdef WLAN_IOT_SIM_SUPPORT 181 QDF_STATUS iot_sim_mgmt_tx_update(struct wlan_objmgr_psoc *psoc, 182 struct wlan_objmgr_vdev *vdev, 183 qdf_nbuf_t buf) 184 { 185 struct wlan_lmac_if_rx_ops *rx_ops; 186 QDF_STATUS status; 187 188 rx_ops = wlan_psoc_get_lmac_if_rxops(psoc); 189 if (!rx_ops) { 190 mgmt_txrx_err("rx_ops is NULL"); 191 return QDF_STATUS_E_NULL_VALUE; 192 } 193 if (rx_ops->iot_sim_rx_ops.iot_sim_cmd_handler) { 194 status = rx_ops->iot_sim_rx_ops.iot_sim_cmd_handler(vdev, 195 buf, 196 NULL, 197 true, 198 NULL); 199 if (QDF_IS_STATUS_ERROR(status)) 200 mgmt_txrx_err("iot_sim_cmd_handler returned failure"); 201 } 202 203 return QDF_STATUS_SUCCESS; 204 } 205 #else 206 QDF_STATUS iot_sim_mgmt_tx_update(struct wlan_objmgr_psoc *psoc, 207 struct wlan_objmgr_vdev *vdev, 208 qdf_nbuf_t buf) 209 { 210 return QDF_STATUS_SUCCESS; 211 } 212 #endif 213