xref: /wlan-dirver/qca-wifi-host-cmn/target_if/mlo_mgr/src/target_if_mlo_mgr.c (revision 70a19e16789e308182f63b15c75decec7bf0b342)
1 /*
2  * Copyright (c) 2021-2023 Qualcomm Innovation Center, Inc. All rights reserved.
3  *
4  * Permission to use, copy, modify, and/or distribute this software for any
5  * purpose with or without fee is hereby granted, provided that the above
6  * copyright notice and this permission notice appear in all copies.
7  *
8  * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
9  * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
10  * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
11  * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
12  * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
13  * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
14  * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
15  */
16 
17 /**
18  * DOC: target_if_mlo_mgr.c
19  *
20  * This file provide definition for APIs registered through lmac Tx Ops
21  */
22 
23 #include <wmi_unified_11be_api.h>
24 #include <init_deinit_lmac.h>
25 #include "target_if_mlo_mgr.h"
26 #include <wlan_objmgr_peer_obj.h>
27 #include <wlan_mlo_t2lm.h>
28 
29 /**
30  * target_if_mlo_link_set_active_resp_handler() - function to handle mlo link
31  *  set active response from firmware.
32  * @scn: scn handle
33  * @data: data buffer for event
34  * @datalen: data length
35  *
36  * Return: 0 on success, else error on failure
37  */
38 static int
39 target_if_mlo_link_set_active_resp_handler(ol_scn_t scn, uint8_t *data,
40 					   uint32_t datalen)
41 {
42 	QDF_STATUS status;
43 	struct wlan_objmgr_psoc *psoc;
44 	struct wmi_unified *wmi_handle;
45 	struct wlan_lmac_if_mlo_rx_ops *rx_ops;
46 	struct mlo_link_set_active_resp resp;
47 
48 	if (!scn || !data) {
49 		target_if_err("scn: 0x%pK, data: 0x%pK", scn, data);
50 		return -EINVAL;
51 	}
52 
53 	psoc = target_if_get_psoc_from_scn_hdl(scn);
54 	if (!psoc) {
55 		target_if_err("null psoc");
56 		return -EINVAL;
57 	}
58 
59 	rx_ops = target_if_mlo_get_rx_ops(psoc);
60 	if (!rx_ops || !rx_ops->process_link_set_active_resp) {
61 		target_if_err("callback not registered");
62 		return -EINVAL;
63 	}
64 
65 	wmi_handle = get_wmi_unified_hdl_from_psoc(psoc);
66 	if (!wmi_handle) {
67 		target_if_err("wmi_handle is null");
68 		return -EINVAL;
69 	}
70 
71 	if (wmi_extract_mlo_link_set_active_resp(wmi_handle, data, &resp) !=
72 	    QDF_STATUS_SUCCESS) {
73 		target_if_err("Unable to extract mlo link set active resp");
74 		return -EINVAL;
75 	}
76 
77 	status = rx_ops->process_link_set_active_resp(psoc, &resp);
78 
79 	return qdf_status_to_os_return(status);
80 }
81 
82 /**
83  * target_if_mlo_link_removal_event_handler() - Handler for MLO link removal
84  * event sent by the FW
85  * @scn: scn handle
86  * @data: data buffer for event
87  * @datalen: data length
88  *
89  * Return: 0 on success, else error on failure
90  */
91 static int
92 target_if_mlo_link_removal_event_handler(ol_scn_t scn, uint8_t *data,
93 					 uint32_t datalen)
94 {
95 	struct wlan_objmgr_psoc *psoc;
96 	struct wmi_unified *wmi_handle;
97 	struct wlan_lmac_if_mlo_rx_ops *mlo_rx_ops;
98 	QDF_STATUS status;
99 	struct mlo_link_removal_evt_params evt_params;
100 
101 	if (!scn || !data) {
102 		target_if_err("scn: 0x%pK, data: 0x%pK", scn, data);
103 		return -EINVAL;
104 	}
105 
106 	psoc = target_if_get_psoc_from_scn_hdl(scn);
107 	if (!psoc) {
108 		target_if_err("null psoc");
109 		return -EINVAL;
110 	}
111 
112 	mlo_rx_ops = target_if_mlo_get_rx_ops(psoc);
113 	if (!mlo_rx_ops || !mlo_rx_ops->mlo_link_removal_handler) {
114 		target_if_err("callback not registered");
115 		return -EINVAL;
116 	}
117 
118 	wmi_handle = get_wmi_unified_hdl_from_psoc(psoc);
119 	if (!wmi_handle) {
120 		target_if_err("wmi_handle is null");
121 		return -EINVAL;
122 	}
123 
124 	status = wmi_extract_mlo_link_removal_evt_fixed_param(wmi_handle, data,
125 							      &evt_params);
126 	if (QDF_IS_STATUS_ERROR(status)) {
127 		target_if_err("Unable to extract fixed param, ret = %d",
128 			      status);
129 		goto exit;
130 	}
131 
132 	status = wmi_extract_mlo_link_removal_tbtt_update(
133 			wmi_handle, data, &evt_params.tbtt_info);
134 	if (QDF_IS_STATUS_ERROR(status)) {
135 		target_if_err("Unable to extract TBTT update TLV, ret = %d",
136 			      status);
137 		goto exit;
138 	}
139 
140 	status = mlo_rx_ops->mlo_link_removal_handler(psoc, &evt_params);
141 exit:
142 	return qdf_status_to_os_return(status);
143 }
144 
145 QDF_STATUS
146 target_if_extract_mlo_link_removal_info_mgmt_rx(
147 		wmi_unified_t wmi_handle,
148 		void *evt_buf,
149 		struct mgmt_rx_event_params *rx_event)
150 {
151 	QDF_STATUS status;
152 	struct mgmt_rx_mlo_link_removal_info *link_removal_info;
153 
154 	if (!rx_event) {
155 		target_if_err("Invalid rx_event");
156 		return QDF_STATUS_E_NULL_VALUE;
157 	}
158 
159 	rx_event->link_removal_info = NULL;
160 	if (!rx_event->num_link_removal_info) {
161 		/**
162 		 * This is not an error. Only probe request frames will contain
163 		 * Link removal TLVs, that too only till the link removal TBTT
164 		 * countdown completion.
165 		 */
166 		target_if_debug("Link removal TLVs are not present");
167 		return QDF_STATUS_SUCCESS;
168 	}
169 
170 	link_removal_info = qdf_mem_malloc(rx_event->num_link_removal_info *
171 					   sizeof(*link_removal_info));
172 	if (!link_removal_info) {
173 		target_if_err("Couldn't allocate memory for link_removal_info");
174 		rx_event->num_link_removal_info = 0;
175 		return QDF_STATUS_E_NOMEM;
176 	}
177 
178 	status = wmi_extract_mgmt_rx_mlo_link_removal_info(
179 					wmi_handle, evt_buf,
180 					link_removal_info,
181 					rx_event->num_link_removal_info);
182 	if (QDF_IS_STATUS_ERROR(status)) {
183 		target_if_err("Unable to extract link removal TLVs");
184 		rx_event->num_link_removal_info = 0;
185 		qdf_mem_free(link_removal_info);
186 		return status;
187 	}
188 
189 	rx_event->link_removal_info = link_removal_info;
190 
191 	return QDF_STATUS_SUCCESS;
192 }
193 
194 /**
195  * target_if_mlo_register_event_handler() - function to register handler for
196  *  mlo related wmi event from firmware.
197  * @psoc: psoc pointer
198  *
199  * Return: QDF_STATUS
200  */
201 static QDF_STATUS
202 target_if_mlo_register_event_handler(struct wlan_objmgr_psoc *psoc)
203 {
204 	QDF_STATUS status;
205 	struct wmi_unified *wmi_handle;
206 
207 	if (!psoc) {
208 		target_if_err("PSOC is NULL!");
209 		return QDF_STATUS_E_NULL_VALUE;
210 	}
211 
212 	wmi_handle = get_wmi_unified_hdl_from_psoc(psoc);
213 	if (!wmi_handle) {
214 		target_if_err("wmi_handle is null");
215 		return QDF_STATUS_E_INVAL;
216 	}
217 
218 	status = wmi_unified_register_event(
219 			wmi_handle,
220 			wmi_mlo_link_removal_eventid,
221 			target_if_mlo_link_removal_event_handler);
222 	if (QDF_IS_STATUS_ERROR(status))
223 		target_if_err("Couldn't register handler for Link removal WMI event %d",
224 			      status);
225 
226 	status = wmi_unified_register_event_handler(
227 			wmi_handle,
228 			wmi_mlo_link_set_active_resp_eventid,
229 			target_if_mlo_link_set_active_resp_handler,
230 			WMI_RX_WORK_CTX);
231 	if (QDF_IS_STATUS_ERROR(status)) {
232 		target_if_err("Register mlo link set active resp cb errcode %d",
233 			      status);
234 		if (status ==  QDF_STATUS_E_NOSUPPORT)
235 			status = QDF_STATUS_SUCCESS;
236 	}
237 
238 	target_if_mlo_register_vdev_tid_to_link_map_event(wmi_handle);
239 
240 	return status;
241 }
242 
243 /**
244  * target_if_mlo_unregister_event_handler() - function to unregister handler for
245  *  mlo related wmi event from firmware.
246  * @psoc: psoc pointer
247  *
248  * Return: QDF_STATUS
249  */
250 static QDF_STATUS
251 target_if_mlo_unregister_event_handler(struct wlan_objmgr_psoc *psoc)
252 {
253 	struct wmi_unified *wmi_handle;
254 
255 	if (!psoc) {
256 		target_if_err("PSOC is NULL!");
257 		return QDF_STATUS_E_INVAL;
258 	}
259 
260 	wmi_handle = get_wmi_unified_hdl_from_psoc(psoc);
261 	if (!wmi_handle) {
262 		target_if_err("wmi_handle is null");
263 		return QDF_STATUS_E_INVAL;
264 	}
265 
266 	wmi_unified_unregister_event_handler(wmi_handle,
267 		wmi_mlo_link_set_active_resp_eventid);
268 
269 	wmi_unified_unregister_event(wmi_handle,
270 				     wmi_mlo_link_removal_eventid);
271 
272 	target_if_mlo_unregister_vdev_tid_to_link_map_event(wmi_handle);
273 
274 	return QDF_STATUS_SUCCESS;
275 }
276 
277 /**
278  * target_if_mlo_link_set_active() - Send WMI command for set mlo link active
279  * @psoc: psoc pointer
280  * @param: parameter for setting mlo link active
281  *
282  * Return: QDF_STATUS
283  */
284 static QDF_STATUS
285 target_if_mlo_link_set_active(struct wlan_objmgr_psoc *psoc,
286 			      struct mlo_link_set_active_param *param)
287 {
288 	QDF_STATUS ret;
289 	struct wmi_unified *wmi_handle;
290 
291 	if (!psoc) {
292 		target_if_err("null psoc");
293 		return QDF_STATUS_E_FAILURE;
294 	}
295 
296 	wmi_handle = get_wmi_unified_hdl_from_psoc(psoc);
297 	if (!wmi_handle) {
298 		target_if_err("null handle");
299 		return QDF_STATUS_E_FAILURE;
300 	}
301 
302 	ret = wmi_send_mlo_link_set_active_cmd(wmi_handle, param);
303 	if (QDF_IS_STATUS_ERROR(ret))
304 		target_if_err("wmi mlo link set active send failed: %d", ret);
305 
306 	return ret;
307 }
308 
309 static int target_if_mlo_vdev_tid_to_link_map_event_handler(
310 		ol_scn_t scn, uint8_t *event_buff, uint32_t len)
311 {
312 	struct wlan_objmgr_psoc *psoc;
313 	struct mlo_vdev_host_tid_to_link_map_resp event = {0};
314 	struct wmi_unified *wmi_handle;
315 	struct wlan_lmac_if_mlo_rx_ops *rx_ops;
316 	QDF_STATUS status;
317 
318 	if (!event_buff) {
319 		mlme_err("Received NULL event ptr from FW");
320 		return -EINVAL;
321 	}
322 
323 	psoc = target_if_get_psoc_from_scn_hdl(scn);
324 	if (!psoc) {
325 		mlme_err("PSOC is NULL");
326 		return -EINVAL;
327 	}
328 
329 	rx_ops = target_if_mlo_get_rx_ops(psoc);
330 	if (!rx_ops || !rx_ops->process_mlo_vdev_tid_to_link_map_event) {
331 		target_if_err("callback not registered");
332 		return -EINVAL;
333 	}
334 
335 	wmi_handle = get_wmi_unified_hdl_from_psoc(psoc);
336 	if (!wmi_handle) {
337 		mlme_err("wmi_handle is null");
338 		return -EINVAL;
339 	}
340 
341 	if (wmi_extract_mlo_vdev_tid_to_link_map_event(wmi_handle, event_buff,
342 						       &event)) {
343 		mlme_err("Failed to extract TID-to-link mapping event");
344 		return -EINVAL;
345 	}
346 
347 	status = rx_ops->process_mlo_vdev_tid_to_link_map_event(psoc, &event);
348 
349 	return qdf_status_to_os_return(status);
350 }
351 
352 void target_if_mlo_register_vdev_tid_to_link_map_event(
353 		struct wmi_unified *wmi_handle)
354 {
355 	wmi_unified_register_event_handler(
356 			wmi_handle, wmi_mlo_ap_vdev_tid_to_link_map_eventid,
357 			target_if_mlo_vdev_tid_to_link_map_event_handler,
358 			WMI_RX_EXECUTION_CTX);
359 }
360 
361 void target_if_mlo_unregister_vdev_tid_to_link_map_event(
362 		struct wmi_unified *wmi_handle)
363 {
364 	wmi_unified_unregister_event_handler(
365 			wmi_handle, wmi_mlo_ap_vdev_tid_to_link_map_eventid);
366 }
367 
368 #ifdef WLAN_FEATURE_11BE_MLO_ADV_FEATURE
369 /**
370  * target_if_fill_provisioned_links() - API to fill the provisioned links
371  * @params: Pointer to T2LM params structure
372  * @t2lm: Pointer to T2LM info structure
373  *
374  * Return: none
375  */
376 static inline void target_if_fill_provisioned_links(
377 		struct wmi_host_tid_to_link_map_params *params,
378 		struct wlan_t2lm_info *t2lm)
379 {
380 	qdf_mem_copy(&params->t2lm_info[params->num_dir].t2lm_provisioned_links,
381 		     &t2lm->ieee_link_map_tid,
382 		     sizeof(uint16_t) * T2LM_MAX_NUM_TIDS);
383 }
384 #else
385 static inline void target_if_fill_provisioned_links(
386 		struct wmi_host_tid_to_link_map_params *params,
387 		struct wlan_t2lm_info *t2lm)
388 {
389 	qdf_mem_copy(&params->t2lm_info[params->num_dir].t2lm_provisioned_links,
390 		     &t2lm->hw_link_map_tid,
391 		     sizeof(uint16_t) * T2LM_MAX_NUM_TIDS);
392 }
393 #endif
394 
395 static QDF_STATUS
396 target_if_mlo_send_tid_to_link_mapping(struct wlan_objmgr_vdev *vdev,
397 				       struct wlan_t2lm_info *t2lm)
398 {
399 	struct wmi_unified *wmi_handle = NULL;
400 	struct wmi_host_tid_to_link_map_params params = {0};
401 	struct wlan_objmgr_pdev *pdev = NULL;
402 	int tid = 0;
403 	QDF_STATUS status;
404 
405 	pdev = wlan_vdev_get_pdev(vdev);
406 	if (!pdev) {
407 		t2lm_err("null pdev");
408 		return QDF_STATUS_E_NULL_VALUE;
409 	}
410 
411 	wmi_handle = lmac_get_pdev_wmi_handle(pdev);
412 	if (!wmi_handle) {
413 		t2lm_err("null wmi handle");
414 		return QDF_STATUS_E_NULL_VALUE;
415 	}
416 
417 	params.pdev_id = wlan_objmgr_pdev_get_pdev_id(pdev);
418 	qdf_mem_copy(params.peer_macaddr, vdev->vdev_objmgr.bss_peer->macaddr,
419 		     QDF_MAC_ADDR_SIZE);
420 
421 	t2lm_debug("Fill T2LM WMI info for peer: " QDF_MAC_ADDR_FMT " pdev_id:%d",
422 		   QDF_MAC_ADDR_REF(params.peer_macaddr), params.pdev_id);
423 
424 	params.t2lm_info[params.num_dir].direction = t2lm->direction;
425 	params.t2lm_info[params.num_dir].default_link_mapping =
426 		t2lm->default_link_mapping;
427 
428 	if (!params.t2lm_info[params.num_dir].default_link_mapping)
429 		target_if_fill_provisioned_links(&params, t2lm);
430 
431 	t2lm_debug("num_dir:%d direction:%d default_link_mapping:%d",
432 		   params.num_dir, params.t2lm_info[params.num_dir].direction,
433 		   params.t2lm_info[params.num_dir].default_link_mapping);
434 
435 	for (tid = 0; tid < T2LM_MAX_NUM_TIDS; tid++) {
436 		t2lm_debug("tid:%d hw_link_map:%x ieee_link_map:%x", tid,
437 			   params.t2lm_info[params.num_dir].t2lm_provisioned_links[tid],
438 			   t2lm->ieee_link_map_tid[tid]);
439 	}
440 
441 	params.num_dir++;
442 
443 	status = wmi_send_mlo_peer_tid_to_link_map_cmd(wmi_handle, &params);
444 	if (QDF_IS_STATUS_ERROR(status)) {
445 		t2lm_err("Failed to send T2LM WMI command for pdev_id:%d peer_mac: " QDF_MAC_ADDR_FMT,
446 			 params.pdev_id,
447 			 QDF_MAC_ADDR_REF(params.peer_macaddr));
448 		return status;
449 	}
450 
451 	return status;
452 }
453 
454 QDF_STATUS target_if_mlo_send_link_removal_cmd(
455 		struct wlan_objmgr_psoc *psoc,
456 		const struct mlo_link_removal_cmd_params *param)
457 {
458 	struct wmi_unified *wmi_handle;
459 
460 	if (!psoc) {
461 		target_if_err("null psoc");
462 		return QDF_STATUS_E_NULL_VALUE;
463 	}
464 
465 	wmi_handle = get_wmi_unified_hdl_from_psoc(psoc);
466 	if (!wmi_handle) {
467 		target_if_err("null handle");
468 		return QDF_STATUS_E_FAILURE;
469 	}
470 
471 	return wmi_send_mlo_link_removal_cmd(wmi_handle, param);
472 }
473 
474 /**
475  * target_if_mlo_register_tx_ops() - lmac handler to register mlo tx ops
476  *  callback functions
477  * @tx_ops: wlan_lmac_if_tx_ops object
478  *
479  * Return: QDF_STATUS
480  */
481 QDF_STATUS
482 target_if_mlo_register_tx_ops(struct wlan_lmac_if_tx_ops *tx_ops)
483 {
484 	struct wlan_lmac_if_mlo_tx_ops *mlo_tx_ops;
485 
486 	if (!tx_ops) {
487 		target_if_err("lmac tx ops is NULL!");
488 		return QDF_STATUS_E_INVAL;
489 	}
490 
491 	mlo_tx_ops = &tx_ops->mlo_ops;
492 	if (!mlo_tx_ops) {
493 		target_if_err("lmac tx ops is NULL!");
494 		return QDF_STATUS_E_FAILURE;
495 	}
496 
497 	mlo_tx_ops->register_events =
498 		target_if_mlo_register_event_handler;
499 	mlo_tx_ops->unregister_events =
500 		target_if_mlo_unregister_event_handler;
501 	mlo_tx_ops->link_set_active = target_if_mlo_link_set_active;
502 	mlo_tx_ops->send_tid_to_link_mapping =
503 		target_if_mlo_send_tid_to_link_mapping;
504 	mlo_tx_ops->send_link_removal_cmd = target_if_mlo_send_link_removal_cmd;
505 
506 	return QDF_STATUS_SUCCESS;
507 }
508 
509