1 /*
2  * Copyright (c) 2021, The Linux Foundation. All rights reserved.
3  * Copyright (c) 2021-2023 Qualcomm Innovation Center, Inc. All rights reserved.
4  *
5  * Permission to use, copy, modify, and/or distribute this software for any
6  * purpose with or without fee is hereby granted, provided that the above
7  * copyright notice and this permission notice appear in all copies.
8  *
9  * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
10  * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
11  * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
12  * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
13  * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
14  * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
15  * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
16  */
17 
18 /**
19  *  DOC: wlan_mgmt_txrx_rx_re_tgt_api.c
20  *  This file contains mgmt rx re-ordering tgt layer related function
21  *  definitions
22  */
23 #include <wlan_mgmt_txrx_rx_reo_tgt_api.h>
24 #include <wlan_mlo_mgr_cmn.h>
25 #include "../../core/src/wlan_mgmt_txrx_rx_reo_i.h"
26 #include <../../core/src/wlan_mgmt_txrx_main_i.h>
27 
28 QDF_STATUS
tgt_mgmt_rx_reo_get_num_active_hw_links(struct wlan_objmgr_psoc * psoc,int8_t * num_active_hw_links)29 tgt_mgmt_rx_reo_get_num_active_hw_links(struct wlan_objmgr_psoc *psoc,
30 					int8_t *num_active_hw_links)
31 {
32 	struct wlan_lmac_if_mgmt_rx_reo_tx_ops *mgmt_rx_reo_txops;
33 
34 	mgmt_rx_reo_txops = wlan_psoc_get_mgmt_rx_reo_txops(psoc);
35 	if (!mgmt_rx_reo_txops) {
36 		mgmt_rx_reo_err("mgmt rx reo txops is NULL");
37 		return QDF_STATUS_E_NULL_VALUE;
38 	}
39 
40 	if (!mgmt_rx_reo_txops->get_num_active_hw_links) {
41 		mgmt_rx_reo_err("get num active hw links txops is NULL");
42 		return QDF_STATUS_E_NULL_VALUE;
43 	}
44 
45 	return mgmt_rx_reo_txops->get_num_active_hw_links(psoc,
46 							  num_active_hw_links);
47 }
48 
49 QDF_STATUS
tgt_mgmt_rx_reo_get_valid_hw_link_bitmap(struct wlan_objmgr_psoc * psoc,uint16_t * valid_hw_link_bitmap)50 tgt_mgmt_rx_reo_get_valid_hw_link_bitmap(struct wlan_objmgr_psoc *psoc,
51 					 uint16_t *valid_hw_link_bitmap)
52 {
53 	struct wlan_lmac_if_mgmt_rx_reo_tx_ops *mgmt_rx_reo_txops;
54 
55 	mgmt_rx_reo_txops = wlan_psoc_get_mgmt_rx_reo_txops(psoc);
56 	if (!mgmt_rx_reo_txops) {
57 		mgmt_rx_reo_err("mgmt rx reo txops is NULL");
58 		return QDF_STATUS_E_NULL_VALUE;
59 	}
60 
61 	if (!mgmt_rx_reo_txops->get_valid_hw_link_bitmap) {
62 		mgmt_rx_reo_err("get valid hw link bitmap txops is NULL");
63 		return QDF_STATUS_E_NULL_VALUE;
64 	}
65 
66 	return mgmt_rx_reo_txops->get_valid_hw_link_bitmap(psoc,
67 						valid_hw_link_bitmap);
68 }
69 
70 QDF_STATUS
tgt_mgmt_rx_reo_read_snapshot(struct wlan_objmgr_pdev * pdev,struct mgmt_rx_reo_snapshot_info * snapshot_info,enum mgmt_rx_reo_shared_snapshot_id id,struct mgmt_rx_reo_snapshot_params * value,struct mgmt_rx_reo_shared_snapshot (* raw_snapshot)[MGMT_RX_REO_SNAPSHOT_B2B_READ_SWAR_RETRY_LIMIT])71 tgt_mgmt_rx_reo_read_snapshot(
72 			struct wlan_objmgr_pdev *pdev,
73 			struct mgmt_rx_reo_snapshot_info *snapshot_info,
74 			enum mgmt_rx_reo_shared_snapshot_id id,
75 			struct mgmt_rx_reo_snapshot_params *value,
76 			struct mgmt_rx_reo_shared_snapshot (*raw_snapshot)
77 			[MGMT_RX_REO_SNAPSHOT_B2B_READ_SWAR_RETRY_LIMIT])
78 {
79 	struct wlan_lmac_if_mgmt_rx_reo_tx_ops *mgmt_rx_reo_txops;
80 
81 	mgmt_rx_reo_txops = wlan_pdev_get_mgmt_rx_reo_txops(pdev);
82 	if (!mgmt_rx_reo_txops) {
83 		mgmt_rx_reo_err("mgmt rx reo txops is NULL");
84 		return QDF_STATUS_E_INVAL;
85 	}
86 
87 	if (!mgmt_rx_reo_txops->read_mgmt_rx_reo_snapshot) {
88 		mgmt_rx_reo_err("mgmt rx reo read snapshot txops is NULL");
89 		return QDF_STATUS_E_NULL_VALUE;
90 	}
91 
92 	return mgmt_rx_reo_txops->read_mgmt_rx_reo_snapshot(pdev, snapshot_info,
93 							    id, value,
94 							    raw_snapshot);
95 }
96 
97 /**
98  * tgt_mgmt_rx_reo_enter_algo_without_buffer() - Entry point to the MGMT Rx REO
99  * algorithm when there is no frame buffer
100  * @pdev: pdev for which this frame/event is intended
101  * @reo_params: MGMT Rx REO parameters corresponding to this frame/event
102  * @type: Type of the MGMT Rx REO frame/event descriptor
103  *
104  * Return: QDF_STATUS of operation
105  */
106 static QDF_STATUS
tgt_mgmt_rx_reo_enter_algo_without_buffer(struct wlan_objmgr_pdev * pdev,struct mgmt_rx_reo_params * reo_params,enum mgmt_rx_reo_frame_descriptor_type type)107 tgt_mgmt_rx_reo_enter_algo_without_buffer(
108 				struct wlan_objmgr_pdev *pdev,
109 				struct mgmt_rx_reo_params *reo_params,
110 				enum mgmt_rx_reo_frame_descriptor_type type)
111 {
112 	struct mgmt_rx_event_params mgmt_rx_params = {0};
113 	struct mgmt_rx_reo_frame_descriptor desc = {0};
114 	bool is_frm_queued;
115 	QDF_STATUS status;
116 	int8_t link_id;
117 	uint8_t ml_grp_id;
118 
119 	if (!pdev) {
120 		mgmt_rx_reo_err("pdev is null");
121 		return QDF_STATUS_E_NULL_VALUE;
122 	}
123 
124 	if (!wlan_mgmt_rx_reo_is_feature_enabled_at_pdev(pdev))
125 		return  QDF_STATUS_SUCCESS;
126 
127 	if (!reo_params) {
128 		mgmt_rx_reo_err("mgmt rx reo params are null");
129 		return QDF_STATUS_E_NULL_VALUE;
130 	}
131 
132 	link_id = wlan_get_mlo_link_id_from_pdev(pdev);
133 	if (link_id < 0) {
134 		mgmt_rx_reo_err("Invalid link %d for the pdev", link_id);
135 		return QDF_STATUS_E_INVAL;
136 	}
137 
138 	ml_grp_id = wlan_get_mlo_grp_id_from_pdev(pdev);
139 	if (ml_grp_id > WLAN_MAX_MLO_GROUPS) {
140 		mgmt_rx_reo_err("Invalid MLO Group  %d for the pdev",
141 				ml_grp_id);
142 		return QDF_STATUS_E_INVAL;
143 	}
144 
145 	reo_params->link_id = link_id;
146 	reo_params->mlo_grp_id = ml_grp_id;
147 	mgmt_rx_params.reo_params = reo_params;
148 
149 	desc.nbuf = NULL; /* No frame buffer */
150 	desc.rx_params = &mgmt_rx_params;
151 	desc.reo_params_copy = *mgmt_rx_params.reo_params;
152 	desc.type = type;
153 	desc.ingress_timestamp = qdf_get_log_timestamp();
154 	desc.ingress_list_size_rx = -1;
155 	desc.ingress_list_insertion_pos = -1;
156 	desc.egress_list_size_rx = -1;
157 	desc.egress_list_insertion_pos = -1;
158 	desc.frame_type = IEEE80211_FC0_TYPE_MGT;
159 	desc.frame_subtype = 0xFF;
160 	desc.reo_required = is_mgmt_rx_reo_required(pdev, &desc);
161 	desc.queued_list = MGMT_RX_REO_LIST_TYPE_INVALID;
162 	desc.drop = false;
163 	desc.drop_reason = MGMT_RX_REO_INGRESS_DROP_REASON_INVALID;
164 
165 	/* Enter the REO algorithm */
166 	status = wlan_mgmt_rx_reo_algo_entry(pdev, &desc, &is_frm_queued);
167 	if (QDF_IS_STATUS_ERROR(status))
168 		return status;
169 
170 	if (is_frm_queued) {
171 		mgmt_rx_reo_err("Frame is queued to reo list");
172 		return QDF_STATUS_E_FAILURE;
173 	}
174 
175 	return QDF_STATUS_SUCCESS;
176 }
177 
178 QDF_STATUS
tgt_mgmt_rx_reo_fw_consumed_event_handler(struct wlan_objmgr_pdev * pdev,struct mgmt_rx_reo_params * params)179 tgt_mgmt_rx_reo_fw_consumed_event_handler(struct wlan_objmgr_pdev *pdev,
180 					  struct mgmt_rx_reo_params *params)
181 {
182 	return tgt_mgmt_rx_reo_enter_algo_without_buffer(
183 			pdev, params, MGMT_RX_REO_FRAME_DESC_FW_CONSUMED_FRAME);
184 }
185 
186 QDF_STATUS
tgt_mgmt_rx_reo_host_drop_handler(struct wlan_objmgr_pdev * pdev,struct mgmt_rx_reo_params * params)187 tgt_mgmt_rx_reo_host_drop_handler(struct wlan_objmgr_pdev *pdev,
188 				  struct mgmt_rx_reo_params *params)
189 {
190 	return tgt_mgmt_rx_reo_enter_algo_without_buffer(
191 			pdev, params, MGMT_RX_REO_FRAME_DESC_ERROR_FRAME);
192 }
193 
194 /**
195  * psoc_get_hw_link_id_bmap() - Helper API to get HW link ID bitmap of the
196  * pdevs in a psoc
197  * @psoc: Pointer to psoc object
198  * @obj: Pointer to pdev object
199  * @arg: pointer to void * argument
200  *
201  * Return: void
202  */
203 static void
psoc_get_hw_link_id_bmap(struct wlan_objmgr_psoc * psoc,void * obj,void * arg)204 psoc_get_hw_link_id_bmap(struct wlan_objmgr_psoc *psoc, void *obj, void *arg)
205 {
206 	struct wlan_objmgr_pdev *pdev = (struct wlan_objmgr_pdev *)obj;
207 	uint32_t *link_bitmap = (uint32_t *)arg;
208 	int8_t cur_link;
209 
210 	cur_link = wlan_get_mlo_link_id_from_pdev(pdev);
211 	if (cur_link < 0 || cur_link >= MAX_MLO_LINKS) {
212 		mgmt_rx_reo_err("Invalid link = %d", cur_link);
213 		return;
214 	}
215 
216 	*link_bitmap |= (1 << cur_link);
217 }
218 
219 QDF_STATUS
tgt_mgmt_rx_reo_release_frames(struct wlan_objmgr_psoc * psoc)220 tgt_mgmt_rx_reo_release_frames(struct wlan_objmgr_psoc *psoc)
221 {
222 	uint8_t mlo_grp_id;
223 	uint32_t link_bitmap = 0;
224 
225 	mlo_grp_id = wlan_mlo_get_psoc_group_id(psoc);
226 
227 	wlan_objmgr_iterate_obj_list(psoc, WLAN_PDEV_OP,
228 				     psoc_get_hw_link_id_bmap,
229 				     &link_bitmap, false, WLAN_MGMT_RX_REO_ID);
230 
231 	return wlan_mgmt_rx_reo_release_frames(mlo_grp_id, link_bitmap);
232 }
233 
tgt_mgmt_rx_reo_filter_config(struct wlan_objmgr_pdev * pdev,struct mgmt_rx_reo_filter * filter)234 QDF_STATUS tgt_mgmt_rx_reo_filter_config(struct wlan_objmgr_pdev *pdev,
235 					 struct mgmt_rx_reo_filter *filter)
236 {
237 	struct wlan_lmac_if_mgmt_rx_reo_tx_ops *mgmt_rx_reo_txops;
238 
239 	mgmt_rx_reo_txops = wlan_pdev_get_mgmt_rx_reo_txops(pdev);
240 	if (!mgmt_rx_reo_txops) {
241 		mgmt_rx_reo_err("MGMT Rx REO txops is NULL");
242 		return QDF_STATUS_E_NULL_VALUE;
243 	}
244 
245 	if (!mgmt_rx_reo_txops->mgmt_rx_reo_filter_config) {
246 		mgmt_rx_reo_err("mgmt_rx_reo_filter_config is NULL");
247 		return QDF_STATUS_E_NULL_VALUE;
248 	}
249 
250 	return mgmt_rx_reo_txops->mgmt_rx_reo_filter_config(pdev, filter);
251 }
252 
253 QDF_STATUS
tgt_mgmt_rx_reo_get_snapshot_info(struct wlan_objmgr_pdev * pdev,enum mgmt_rx_reo_shared_snapshot_id id,struct mgmt_rx_reo_snapshot_info * snapshot_info)254 tgt_mgmt_rx_reo_get_snapshot_info
255 			(struct wlan_objmgr_pdev *pdev,
256 			 enum mgmt_rx_reo_shared_snapshot_id id,
257 			 struct mgmt_rx_reo_snapshot_info *snapshot_info)
258 {
259 	struct wlan_lmac_if_mgmt_rx_reo_tx_ops *mgmt_rx_reo_txops;
260 
261 	mgmt_rx_reo_txops = wlan_pdev_get_mgmt_rx_reo_txops(pdev);
262 	if (!mgmt_rx_reo_txops) {
263 		mgmt_rx_reo_err("mgmt rx reo txops is NULL");
264 		return QDF_STATUS_E_NULL_VALUE;
265 	}
266 
267 	if (!mgmt_rx_reo_txops->get_mgmt_rx_reo_snapshot_info) {
268 		mgmt_rx_reo_err("txops entry for get snapshot info is null");
269 		return QDF_STATUS_E_NULL_VALUE;
270 	}
271 
272 	return mgmt_rx_reo_txops->get_mgmt_rx_reo_snapshot_info(pdev, id,
273 								snapshot_info);
274 }
275 
276 bool
wlan_mgmt_rx_reo_check_simulation_in_progress(struct wlan_objmgr_pdev * pdev)277 wlan_mgmt_rx_reo_check_simulation_in_progress(struct wlan_objmgr_pdev *pdev)
278 {
279 	uint8_t ml_grp_id;
280 	struct wlan_objmgr_psoc *psoc;
281 
282 	psoc = wlan_pdev_get_psoc(pdev);
283 	if (!psoc)
284 		return false;
285 
286 	if (!wlan_mlo_get_psoc_capable(psoc))
287 		return false;
288 
289 	ml_grp_id = wlan_get_mlo_grp_id_from_pdev(pdev);
290 	if (ml_grp_id > WLAN_MAX_MLO_GROUPS) {
291 		mgmt_rx_reo_err("INVALID ML Group ID for the PDEV");
292 		return false;
293 	}
294 
295 	if (!wlan_mgmt_rx_reo_is_simulation_in_progress(ml_grp_id))
296 		return false;
297 
298 	return true;
299 }
300 
tgt_mgmt_rx_reo_frame_handler(struct wlan_objmgr_pdev * pdev,qdf_nbuf_t buf,struct mgmt_rx_event_params * mgmt_rx_params)301 QDF_STATUS tgt_mgmt_rx_reo_frame_handler(
302 				struct wlan_objmgr_pdev *pdev,
303 				qdf_nbuf_t buf,
304 				struct mgmt_rx_event_params *mgmt_rx_params)
305 {
306 	QDF_STATUS status;
307 	struct mgmt_rx_reo_frame_descriptor desc = {0};
308 	bool is_queued;
309 	int8_t link_id;
310 	uint8_t ml_grp_id;
311 	uint8_t frame_type;
312 	uint8_t frame_subtype;
313 	struct ieee80211_frame *wh;
314 
315 	if (!pdev) {
316 		mgmt_rx_reo_err("pdev is NULL");
317 		status = QDF_STATUS_E_NULL_VALUE;
318 		goto cleanup;
319 	}
320 
321 	if (!wlan_mgmt_rx_reo_check_simulation_in_progress(pdev) && !buf) {
322 		mgmt_rx_reo_err("nbuf is NULL");
323 		status = QDF_STATUS_E_NULL_VALUE;
324 		goto cleanup;
325 	}
326 
327 	if (!mgmt_rx_params) {
328 		mgmt_rx_reo_err("MGMT rx params is NULL");
329 		status = QDF_STATUS_E_NULL_VALUE;
330 		goto cleanup;
331 	}
332 
333 	if (!wlan_mgmt_rx_reo_is_feature_enabled_at_pdev(pdev))
334 		return tgt_mgmt_txrx_process_rx_frame(pdev, buf,
335 						      mgmt_rx_params);
336 
337 	if (!mgmt_rx_params->reo_params) {
338 		mgmt_rx_reo_err("MGMT rx REO params is NULL");
339 		status = QDF_STATUS_E_NULL_VALUE;
340 		goto cleanup;
341 	}
342 
343 	link_id = wlan_get_mlo_link_id_from_pdev(pdev);
344 	if (link_id < 0) {
345 		mgmt_rx_reo_err("Invalid link %d for the pdev", link_id);
346 		status = QDF_STATUS_E_INVAL;
347 		goto cleanup;
348 	}
349 
350 	ml_grp_id = wlan_get_mlo_grp_id_from_pdev(pdev);
351 	if (ml_grp_id > WLAN_MAX_MLO_GROUPS) {
352 		mgmt_rx_reo_err("Invalid MGMT rx reo Group id");
353 		status = QDF_STATUS_E_INVAL;
354 		goto cleanup;
355 	}
356 
357 	mgmt_rx_params->reo_params->link_id = link_id;
358 	mgmt_rx_params->reo_params->mlo_grp_id = ml_grp_id;
359 
360 	/* Populate frame descriptor */
361 	desc.type = MGMT_RX_REO_FRAME_DESC_HOST_CONSUMED_FRAME;
362 	desc.nbuf = buf;
363 	desc.rx_params = mgmt_rx_params;
364 	desc.reo_params_copy = *mgmt_rx_params->reo_params;
365 	desc.ingress_timestamp = qdf_get_log_timestamp();
366 	desc.ingress_list_size_rx = -1;
367 	desc.ingress_list_insertion_pos = -1;
368 	desc.egress_list_size_rx = -1;
369 	desc.egress_list_insertion_pos = -1;
370 	desc.queued_list = MGMT_RX_REO_LIST_TYPE_INVALID;
371 	desc.drop = false;
372 	desc.drop_reason = MGMT_RX_REO_INGRESS_DROP_REASON_INVALID;
373 
374 	wh = (struct ieee80211_frame *)qdf_nbuf_data(buf);
375 	frame_type = wh->i_fc[0] & IEEE80211_FC0_TYPE_MASK;
376 	frame_subtype = wh->i_fc[0] & IEEE80211_FC0_SUBTYPE_MASK;
377 
378 	desc.frame_type = frame_type;
379 	desc.frame_subtype = frame_subtype;
380 
381 	if (frame_type != IEEE80211_FC0_TYPE_MGT ||
382 	    !is_mgmt_rx_reo_required(pdev, &desc)) {
383 		desc.reo_required = false;
384 		status = wlan_mgmt_rx_reo_algo_entry(pdev, &desc, &is_queued);
385 
386 		if (QDF_IS_STATUS_ERROR(status)) {
387 			mgmt_rx_reo_warn_rl("Failed to execute REO algorithm");
388 			goto cleanup;
389 		}
390 
391 		if (is_queued) {
392 			mgmt_rx_reo_err("Frame is queued to reo list");
393 			return QDF_STATUS_E_FAILURE;
394 		}
395 
396 		return tgt_mgmt_txrx_process_rx_frame(pdev, buf,
397 						      mgmt_rx_params);
398 	} else {
399 		desc.reo_required = true;
400 		status = wlan_mgmt_rx_reo_algo_entry(pdev, &desc, &is_queued);
401 
402 		if (QDF_IS_STATUS_ERROR(status))
403 			mgmt_rx_reo_warn_rl("Failed to execute REO algorithm");
404 
405 		/**
406 		 *  If frame is queued, we shouldn't free up params and
407 		 *  buf pointers.
408 		 */
409 		if (is_queued)
410 			return status;
411 	}
412 cleanup:
413 	qdf_nbuf_free(buf);
414 	free_mgmt_rx_event_params(mgmt_rx_params);
415 
416 	return status;
417 }
418 
419 QDF_STATUS
tgt_mgmt_rx_reo_schedule_delivery(struct wlan_objmgr_psoc * psoc)420 tgt_mgmt_rx_reo_schedule_delivery(struct wlan_objmgr_psoc *psoc)
421 {
422 	struct wlan_lmac_if_mgmt_rx_reo_tx_ops *mgmt_rx_reo_txops;
423 
424 	mgmt_rx_reo_txops = wlan_psoc_get_mgmt_rx_reo_txops(psoc);
425 	if (!mgmt_rx_reo_txops) {
426 		mgmt_rx_reo_err("MGMT Rx REO txops is NULL");
427 		return QDF_STATUS_E_NULL_VALUE;
428 	}
429 
430 	if (!mgmt_rx_reo_txops->schedule_delivery) {
431 		mgmt_rx_reo_err("mgmt_rx_reo_schedule delivery is NULL");
432 		return QDF_STATUS_E_NULL_VALUE;
433 	}
434 
435 	return mgmt_rx_reo_txops->schedule_delivery(psoc);
436 }
437