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 /** 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_info( 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 /* acquire the wakelock when there are pending mgmt tx frames */ 128 qdf_wake_lock_timeout_acquire(&mgmt_txrx_pdev_ctx->wakelock_tx_cmp, 129 MGMT_TXRX_WAKELOCK_TIMEOUT_TX_CMP); 130 131 qdf_spin_unlock_bh(&mgmt_txrx_pdev_ctx->mgmt_desc_pool.desc_pool_lock); 132 133 return mgmt_txrx_desc; 134 } 135 136 void wlan_mgmt_txrx_desc_put( 137 struct mgmt_txrx_priv_pdev_context *mgmt_txrx_pdev_ctx, 138 uint32_t desc_id) 139 { 140 struct mgmt_txrx_desc_elem_t *desc; 141 142 desc = &mgmt_txrx_pdev_ctx->mgmt_desc_pool.pool[desc_id]; 143 qdf_spin_lock_bh(&mgmt_txrx_pdev_ctx->mgmt_desc_pool.desc_pool_lock); 144 if (!desc->in_use) { 145 qdf_spin_unlock_bh(&mgmt_txrx_pdev_ctx->mgmt_desc_pool. 146 desc_pool_lock); 147 mgmt_txrx_err("desc %d is freed", desc_id); 148 return; 149 } 150 desc->in_use = false; 151 qdf_list_insert_front(&mgmt_txrx_pdev_ctx->mgmt_desc_pool.free_list, 152 &desc->entry); 153 154 /* release the wakelock if there are no pending mgmt tx frames */ 155 if (mgmt_txrx_pdev_ctx->mgmt_desc_pool.free_list.count == 156 mgmt_txrx_pdev_ctx->mgmt_desc_pool.free_list.max_size) 157 qdf_wake_lock_release(&mgmt_txrx_pdev_ctx->wakelock_tx_cmp, 158 MGMT_TXRX_WAKELOCK_REASON_TX_CMP); 159 160 qdf_spin_unlock_bh(&mgmt_txrx_pdev_ctx->mgmt_desc_pool.desc_pool_lock); 161 162 } 163