1 /* 2 * Copyright (c) 2016-2018 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 mgmt_txrx_err("Failed to allocate desc pool"); 43 return QDF_STATUS_E_NOMEM; 44 } 45 qdf_list_create(&mgmt_txrx_pdev_ctx->mgmt_desc_pool.free_list, 46 MGMT_DESC_POOL_MAX); 47 48 for (i = 0; i < MGMT_DESC_POOL_MAX; i++) { 49 mgmt_txrx_pdev_ctx->mgmt_desc_pool.pool[i].desc_id = i; 50 mgmt_txrx_pdev_ctx->mgmt_desc_pool.pool[i].in_use = false; 51 qdf_list_insert_front( 52 &mgmt_txrx_pdev_ctx->mgmt_desc_pool.free_list, 53 &mgmt_txrx_pdev_ctx->mgmt_desc_pool.pool[i].entry); 54 } 55 56 qdf_spinlock_create( 57 &mgmt_txrx_pdev_ctx->mgmt_desc_pool.desc_pool_lock); 58 59 return QDF_STATUS_SUCCESS; 60 } 61 62 void wlan_mgmt_txrx_desc_pool_deinit( 63 struct mgmt_txrx_priv_pdev_context *mgmt_txrx_pdev_ctx) 64 { 65 uint32_t i; 66 uint32_t pool_size; 67 QDF_STATUS status; 68 69 if (!mgmt_txrx_pdev_ctx->mgmt_desc_pool.pool) { 70 mgmt_txrx_err("Empty mgmt descriptor pool"); 71 qdf_assert_always(0); 72 return; 73 } 74 75 pool_size = mgmt_txrx_pdev_ctx->mgmt_desc_pool.free_list.max_size; 76 for (i = 0; i < pool_size; i++) { 77 status = qdf_list_remove_node( 78 &mgmt_txrx_pdev_ctx->mgmt_desc_pool.free_list, 79 &mgmt_txrx_pdev_ctx->mgmt_desc_pool.pool[i].entry); 80 if (status != QDF_STATUS_SUCCESS) 81 mgmt_txrx_err( 82 "Failed to get mgmt desc from freelist, desc id: %d: status %d", 83 i, status); 84 } 85 86 qdf_list_destroy(&mgmt_txrx_pdev_ctx->mgmt_desc_pool.free_list); 87 qdf_mem_free(mgmt_txrx_pdev_ctx->mgmt_desc_pool.pool); 88 mgmt_txrx_pdev_ctx->mgmt_desc_pool.pool = NULL; 89 90 qdf_spinlock_destroy( 91 &mgmt_txrx_pdev_ctx->mgmt_desc_pool.desc_pool_lock); 92 } 93 94 struct mgmt_txrx_desc_elem_t *wlan_mgmt_txrx_desc_get( 95 struct mgmt_txrx_priv_pdev_context *mgmt_txrx_pdev_ctx) 96 { 97 QDF_STATUS status; 98 qdf_list_node_t *desc_node; 99 struct mgmt_txrx_desc_elem_t *mgmt_txrx_desc; 100 101 qdf_spin_lock_bh(&mgmt_txrx_pdev_ctx->mgmt_desc_pool.desc_pool_lock); 102 if (qdf_list_peek_front(&mgmt_txrx_pdev_ctx->mgmt_desc_pool.free_list, 103 &desc_node) 104 != QDF_STATUS_SUCCESS) { 105 qdf_spin_unlock_bh( 106 &mgmt_txrx_pdev_ctx->mgmt_desc_pool.desc_pool_lock); 107 mgmt_txrx_err("Descriptor freelist empty for mgmt_txrx_ctx %pK", 108 mgmt_txrx_pdev_ctx); 109 return NULL; 110 } 111 112 status = qdf_list_remove_node( 113 &mgmt_txrx_pdev_ctx->mgmt_desc_pool.free_list, 114 desc_node); 115 if (status != QDF_STATUS_SUCCESS) { 116 qdf_spin_unlock_bh( 117 &mgmt_txrx_pdev_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 } 122 123 mgmt_txrx_desc = qdf_container_of(desc_node, 124 struct mgmt_txrx_desc_elem_t, 125 entry); 126 mgmt_txrx_desc->in_use = true; 127 128 /* acquire the wakelock when there are pending mgmt tx frames */ 129 qdf_wake_lock_timeout_acquire(&mgmt_txrx_pdev_ctx->wakelock_tx_cmp, 130 MGMT_TXRX_WAKELOCK_TIMEOUT_TX_CMP); 131 132 qdf_spin_unlock_bh(&mgmt_txrx_pdev_ctx->mgmt_desc_pool.desc_pool_lock); 133 134 mgmt_txrx_info("retrieved mgmt desc: %pK with desc id: %d", 135 mgmt_txrx_desc, mgmt_txrx_desc->desc_id); 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 145 desc = &mgmt_txrx_pdev_ctx->mgmt_desc_pool.pool[desc_id]; 146 qdf_spin_lock_bh(&mgmt_txrx_pdev_ctx->mgmt_desc_pool.desc_pool_lock); 147 desc->in_use = false; 148 qdf_list_insert_front(&mgmt_txrx_pdev_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_pdev_ctx->mgmt_desc_pool.free_list.count == 153 mgmt_txrx_pdev_ctx->mgmt_desc_pool.free_list.max_size) 154 qdf_wake_lock_release(&mgmt_txrx_pdev_ctx->wakelock_tx_cmp, 155 MGMT_TXRX_WAKELOCK_REASON_TX_CMP); 156 157 qdf_spin_unlock_bh(&mgmt_txrx_pdev_ctx->mgmt_desc_pool.desc_pool_lock); 158 159 mgmt_txrx_info("put mgmt desc: %pK with desc id: %d into freelist", 160 desc, desc->desc_id); 161 } 162