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