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
wlan_mgmt_txrx_desc_pool_init(struct mgmt_txrx_priv_pdev_context * mgmt_txrx_pdev_ctx)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
wlan_mgmt_txrx_desc_pool_deinit(struct mgmt_txrx_priv_pdev_context * mgmt_txrx_pdev_ctx)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
wlan_mgmt_txrx_desc_get(struct mgmt_txrx_priv_pdev_context * mgmt_txrx_pdev_ctx)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
wlan_mgmt_txrx_desc_put(struct mgmt_txrx_priv_pdev_context * mgmt_txrx_pdev_ctx,uint32_t desc_id)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
iot_sim_mgmt_tx_update(struct wlan_objmgr_psoc * psoc,struct wlan_objmgr_vdev * vdev,qdf_nbuf_t buf)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
iot_sim_mgmt_tx_update(struct wlan_objmgr_psoc * psoc,struct wlan_objmgr_vdev * vdev,qdf_nbuf_t buf)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