xref: /wlan-dirver/qca-wifi-host-cmn/umac/cmn_services/mgmt_txrx/core/src/wlan_mgmt_txrx_main.c (revision 2e17c21b55b6194b51cf3bca4b0f31ea64d81a24)
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