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
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
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
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
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 	if (!reo_params->valid) {
139 		mgmt_rx_reo_err_rl("Invalid MGMT rx REO param for link %u",
140 				   link_id);
141 		return QDF_STATUS_E_INVAL;
142 	}
143 
144 	ml_grp_id = wlan_get_mlo_grp_id_from_pdev(pdev);
145 	if (ml_grp_id > WLAN_MAX_MLO_GROUPS) {
146 		mgmt_rx_reo_err("Invalid MLO Group  %d for the pdev",
147 				ml_grp_id);
148 		return QDF_STATUS_E_INVAL;
149 	}
150 
151 	reo_params->link_id = link_id;
152 	reo_params->mlo_grp_id = ml_grp_id;
153 	mgmt_rx_params.reo_params = reo_params;
154 
155 	desc.nbuf = NULL; /* No frame buffer */
156 	desc.rx_params = &mgmt_rx_params;
157 	desc.type = type;
158 	desc.ingress_timestamp = qdf_get_log_timestamp();
159 	desc.ingress_list_size_rx = -1;
160 	desc.ingress_list_insertion_pos = -1;
161 	desc.egress_list_size_rx = -1;
162 	desc.egress_list_insertion_pos = -1;
163 	desc.frame_type = IEEE80211_FC0_TYPE_MGT;
164 	desc.frame_subtype = 0xFF;
165 	desc.reo_required = is_mgmt_rx_reo_required(pdev, &desc);
166 	desc.queued_list = MGMT_RX_REO_LIST_TYPE_INVALID;
167 
168 	/* Enter the REO algorithm */
169 	status = wlan_mgmt_rx_reo_algo_entry(pdev, &desc, &is_frm_queued);
170 
171 	qdf_assert_always(!is_frm_queued);
172 
173 	return status;
174 }
175 
176 QDF_STATUS
177 tgt_mgmt_rx_reo_fw_consumed_event_handler(struct wlan_objmgr_pdev *pdev,
178 					  struct mgmt_rx_reo_params *params)
179 {
180 	return tgt_mgmt_rx_reo_enter_algo_without_buffer(
181 			pdev, params, MGMT_RX_REO_FRAME_DESC_FW_CONSUMED_FRAME);
182 }
183 
184 QDF_STATUS
185 tgt_mgmt_rx_reo_host_drop_handler(struct wlan_objmgr_pdev *pdev,
186 				  struct mgmt_rx_reo_params *params)
187 {
188 	return tgt_mgmt_rx_reo_enter_algo_without_buffer(
189 			pdev, params, MGMT_RX_REO_FRAME_DESC_ERROR_FRAME);
190 }
191 
192 QDF_STATUS tgt_mgmt_rx_reo_filter_config(struct wlan_objmgr_pdev *pdev,
193 					 struct mgmt_rx_reo_filter *filter)
194 {
195 	struct wlan_lmac_if_mgmt_rx_reo_tx_ops *mgmt_rx_reo_txops;
196 
197 	mgmt_rx_reo_txops = wlan_pdev_get_mgmt_rx_reo_txops(pdev);
198 	if (!mgmt_rx_reo_txops) {
199 		mgmt_rx_reo_err("MGMT Rx REO txops is NULL");
200 		return QDF_STATUS_E_NULL_VALUE;
201 	}
202 
203 	if (!mgmt_rx_reo_txops->mgmt_rx_reo_filter_config) {
204 		mgmt_rx_reo_err("mgmt_rx_reo_filter_config is NULL");
205 		return QDF_STATUS_E_NULL_VALUE;
206 	}
207 
208 	return mgmt_rx_reo_txops->mgmt_rx_reo_filter_config(pdev, filter);
209 }
210 
211 QDF_STATUS
212 tgt_mgmt_rx_reo_get_snapshot_info
213 			(struct wlan_objmgr_pdev *pdev,
214 			 enum mgmt_rx_reo_shared_snapshot_id id,
215 			 struct mgmt_rx_reo_snapshot_info *snapshot_info)
216 {
217 	struct wlan_lmac_if_mgmt_rx_reo_tx_ops *mgmt_rx_reo_txops;
218 
219 	mgmt_rx_reo_txops = wlan_pdev_get_mgmt_rx_reo_txops(pdev);
220 	if (!mgmt_rx_reo_txops) {
221 		mgmt_rx_reo_err("mgmt rx reo txops is NULL");
222 		return QDF_STATUS_E_NULL_VALUE;
223 	}
224 
225 	if (!mgmt_rx_reo_txops->get_mgmt_rx_reo_snapshot_info) {
226 		mgmt_rx_reo_err("txops entry for get snapshot info is null");
227 		return QDF_STATUS_E_NULL_VALUE;
228 	}
229 
230 	return mgmt_rx_reo_txops->get_mgmt_rx_reo_snapshot_info(pdev, id,
231 								snapshot_info);
232 }
233 
234 bool
235 wlan_mgmt_rx_reo_check_simulation_in_progress(struct wlan_objmgr_pdev *pdev)
236 {
237 	uint8_t ml_grp_id;
238 	struct wlan_objmgr_psoc *psoc;
239 
240 	psoc = wlan_pdev_get_psoc(pdev);
241 	if (!psoc)
242 		return false;
243 
244 	if (!wlan_mlo_get_psoc_capable(psoc))
245 		return false;
246 
247 	ml_grp_id = wlan_get_mlo_grp_id_from_pdev(pdev);
248 	if (ml_grp_id > WLAN_MAX_MLO_GROUPS) {
249 		mgmt_rx_reo_err("INVALID ML Group ID for the PDEV");
250 		return false;
251 	}
252 
253 	if (!wlan_mgmt_rx_reo_is_simulation_in_progress(ml_grp_id))
254 		return false;
255 
256 	return true;
257 }
258 
259 QDF_STATUS tgt_mgmt_rx_reo_frame_handler(
260 				struct wlan_objmgr_pdev *pdev,
261 				qdf_nbuf_t buf,
262 				struct mgmt_rx_event_params *mgmt_rx_params)
263 {
264 	QDF_STATUS status;
265 	struct mgmt_rx_reo_frame_descriptor desc = {0};
266 	bool is_queued;
267 	int8_t link_id;
268 	uint8_t ml_grp_id;
269 	uint8_t frame_type;
270 	uint8_t frame_subtype;
271 	struct ieee80211_frame *wh;
272 
273 	if (!pdev) {
274 		mgmt_rx_reo_err("pdev is NULL");
275 		status = QDF_STATUS_E_NULL_VALUE;
276 		goto cleanup;
277 	}
278 
279 	if (!wlan_mgmt_rx_reo_check_simulation_in_progress(pdev) && !buf) {
280 		mgmt_rx_reo_err("nbuf is NULL");
281 		status = QDF_STATUS_E_NULL_VALUE;
282 		goto cleanup;
283 	}
284 
285 	if (!mgmt_rx_params) {
286 		mgmt_rx_reo_err("MGMT rx params is NULL");
287 		status = QDF_STATUS_E_NULL_VALUE;
288 		goto cleanup;
289 	}
290 
291 	if (!wlan_mgmt_rx_reo_is_feature_enabled_at_pdev(pdev))
292 		return tgt_mgmt_txrx_process_rx_frame(pdev, buf,
293 						      mgmt_rx_params);
294 
295 	if (!mgmt_rx_params->reo_params) {
296 		mgmt_rx_reo_err("MGMT rx REO params is NULL");
297 		status = QDF_STATUS_E_NULL_VALUE;
298 		goto cleanup;
299 	}
300 
301 	link_id = wlan_get_mlo_link_id_from_pdev(pdev);
302 	if (link_id < 0) {
303 		mgmt_rx_reo_err("Invalid link %d for the pdev", link_id);
304 		status = QDF_STATUS_E_INVAL;
305 		goto cleanup;
306 	}
307 
308 	if (!mgmt_rx_params->reo_params->valid) {
309 		mgmt_rx_reo_err_rl("Invalid MGMT rx REO param for link %u",
310 				   link_id);
311 		status = QDF_STATUS_E_INVAL;
312 		goto cleanup;
313 	}
314 
315 	ml_grp_id = wlan_get_mlo_grp_id_from_pdev(pdev);
316 	if (ml_grp_id > WLAN_MAX_MLO_GROUPS) {
317 		mgmt_rx_reo_err("Invalid MGMT rx reo Group id");
318 		status = QDF_STATUS_E_INVAL;
319 		goto cleanup;
320 	}
321 
322 	mgmt_rx_params->reo_params->link_id = link_id;
323 	mgmt_rx_params->reo_params->mlo_grp_id = ml_grp_id;
324 
325 	/* Populate frame descriptor */
326 	desc.type = MGMT_RX_REO_FRAME_DESC_HOST_CONSUMED_FRAME;
327 	desc.nbuf = buf;
328 	desc.rx_params = mgmt_rx_params;
329 	desc.ingress_timestamp = qdf_get_log_timestamp();
330 	desc.ingress_list_size_rx = -1;
331 	desc.ingress_list_insertion_pos = -1;
332 	desc.egress_list_size_rx = -1;
333 	desc.egress_list_insertion_pos = -1;
334 	desc.queued_list = MGMT_RX_REO_LIST_TYPE_INVALID;
335 
336 	wh = (struct ieee80211_frame *)qdf_nbuf_data(buf);
337 	frame_type = wh->i_fc[0] & IEEE80211_FC0_TYPE_MASK;
338 	frame_subtype = wh->i_fc[0] & IEEE80211_FC0_SUBTYPE_MASK;
339 
340 	desc.frame_type = frame_type;
341 	desc.frame_subtype = frame_subtype;
342 
343 	if (frame_type != IEEE80211_FC0_TYPE_MGT ||
344 	    !is_mgmt_rx_reo_required(pdev, &desc)) {
345 		desc.reo_required = false;
346 		status = wlan_mgmt_rx_reo_algo_entry(pdev, &desc, &is_queued);
347 
348 		if (QDF_IS_STATUS_ERROR(status)) {
349 			mgmt_rx_reo_err_rl("Failed to execute REO algorithm");
350 			goto cleanup;
351 		}
352 
353 		qdf_assert_always(!is_queued);
354 
355 		return tgt_mgmt_txrx_process_rx_frame(pdev, buf,
356 						      mgmt_rx_params);
357 	} else {
358 		desc.reo_required = true;
359 		status = wlan_mgmt_rx_reo_algo_entry(pdev, &desc, &is_queued);
360 
361 		if (QDF_IS_STATUS_ERROR(status))
362 			mgmt_rx_reo_err_rl("Failed to execute REO algorithm");
363 
364 		/**
365 		 *  If frame is queued, we shouldn't free up params and
366 		 *  buf pointers.
367 		 */
368 		if (is_queued)
369 			return status;
370 	}
371 cleanup:
372 	qdf_nbuf_free(buf);
373 	free_mgmt_rx_event_params(mgmt_rx_params);
374 
375 	return status;
376 }
377