xref: /wlan-dirver/qca-wifi-host-cmn/umac/cfr/core/src/cfr_common.c (revision 8cfe6b10058a04cafb17eed051f2ddf11bee8931)
1 /*
2  * Copyright (c) 2019-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
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 #include <cfr_defs_i.h>
21 #include <qdf_types.h>
22 #include <wlan_objmgr_pdev_obj.h>
23 #include <wlan_objmgr_vdev_obj.h>
24 #include <wlan_objmgr_peer_obj.h>
25 #include <wlan_cfr_tgt_api.h>
26 #include <qdf_streamfs.h>
27 #include <target_if.h>
28 #include <target_if_direct_buf_rx_api.h>
29 #include <wlan_osif_priv.h>
30 #include <cfg_ucfg_api.h>
31 #include "cfr_cfg.h"
32 #ifdef WLAN_CFR_PM
33 #include "host_diag_core_event.h"
34 #endif
35 
36 /**
37  * wlan_cfr_is_ini_disabled() - Check if cfr feature is disabled
38  * @pdev: the physical device object.
39  *
40  * Return : true if cfr is disabled, else false.
41  */
42 static bool
43 wlan_cfr_is_ini_disabled(struct wlan_objmgr_pdev *pdev)
44 {
45 	struct wlan_objmgr_psoc *psoc;
46 	uint8_t cfr_disable_bitmap;
47 
48 	psoc = wlan_pdev_get_psoc(pdev);
49 	if (!psoc) {
50 		cfr_err("psoc is null");
51 		return true;
52 	}
53 
54 	cfr_disable_bitmap = cfg_get(psoc, CFG_CFR_DISABLE);
55 
56 	if (cfr_disable_bitmap & (1 << wlan_objmgr_pdev_get_pdev_id(pdev))) {
57 		cfr_info("cfr is disabled for pdev[%d]",
58 			 wlan_objmgr_pdev_get_pdev_id(pdev));
59 		return true;
60 	}
61 
62 	return false;
63 }
64 
65 /**
66  * wlan_cfr_get_dbr_num_entries() - Get entry number of DBR ring
67  * @pdev: the physical device object.
68  *
69  * Return : Entry number of DBR ring.
70  */
71 static uint32_t
72 wlan_cfr_get_dbr_num_entries(struct wlan_objmgr_pdev *pdev)
73 {
74 	struct wlan_objmgr_psoc *psoc;
75 	struct wlan_psoc_host_dbr_ring_caps *dbr_ring_cap;
76 	uint8_t num_dbr_ring_caps, cap_idx, pdev_id;
77 	struct target_psoc_info *tgt_psoc_info;
78 	uint32_t num_entries = MAX_LUT_ENTRIES;
79 
80 	if (!pdev) {
81 		cfr_err("Invalid pdev");
82 		return num_entries;
83 	}
84 
85 	psoc = wlan_pdev_get_psoc(pdev);
86 	if (!psoc) {
87 		cfr_err("psoc is null");
88 		return num_entries;
89 	}
90 
91 	tgt_psoc_info = wlan_psoc_get_tgt_if_handle(psoc);
92 	if (!tgt_psoc_info) {
93 		cfr_err("target_psoc_info is null");
94 		return num_entries;
95 	}
96 
97 	num_dbr_ring_caps = target_psoc_get_num_dbr_ring_caps(tgt_psoc_info);
98 	dbr_ring_cap = target_psoc_get_dbr_ring_caps(tgt_psoc_info);
99 	pdev_id = wlan_objmgr_pdev_get_pdev_id(pdev);
100 
101 	for (cap_idx = 0; cap_idx < num_dbr_ring_caps; cap_idx++) {
102 		if (dbr_ring_cap[cap_idx].pdev_id == pdev_id &&
103 		    dbr_ring_cap[cap_idx].mod_id == DBR_MODULE_CFR)
104 			num_entries = dbr_ring_cap[cap_idx].ring_elems_min;
105 	}
106 
107 	num_entries = QDF_MIN(num_entries, MAX_LUT_ENTRIES);
108 	cfr_debug("pdev id %d, num_entries %d", pdev_id, num_entries);
109 
110 	return num_entries;
111 }
112 
113 #ifdef WLAN_CFR_PM
114 /**
115  * cfr_wakelock_init(): Create/init wake lock for CFR
116  * @pcfr: CFR pdev context
117  *
118  * Create/init wake lock for CFR
119  *
120  * Return None
121  */
122 static void cfr_wakelock_init(struct pdev_cfr *pcfr)
123 {
124 	if (!pcfr) {
125 		cfr_debug("NULL pa");
126 		return;
127 	}
128 
129 	pcfr->is_prevent_suspend = false;
130 	qdf_wake_lock_create(&pcfr->wake_lock, "wlan_cfr");
131 	qdf_runtime_lock_init(&pcfr->runtime_lock);
132 }
133 
134 /**
135  * cfr_wakelock_deinit(): Destroy/deinit wake lock for CFR
136  * @pcfr: CFR pdev context
137  *
138  * Destroy/deinit wake lock for CFR
139  *
140  * Return None
141  */
142 static void cfr_wakelock_deinit(struct pdev_cfr *pcfr)
143 {
144 	if (!pcfr) {
145 		cfr_debug("NULL pa");
146 		return;
147 	}
148 
149 	qdf_runtime_lock_deinit(&pcfr->runtime_lock);
150 	qdf_wake_lock_destroy(&pcfr->wake_lock);
151 }
152 #else
153 static inline void cfr_wakelock_init(struct pdev_cfr *pcfr)
154 {
155 }
156 
157 static inline void cfr_wakelock_deinit(struct pdev_cfr *pcfr)
158 {
159 }
160 #endif
161 
162 QDF_STATUS
163 wlan_cfr_psoc_obj_create_handler(struct wlan_objmgr_psoc *psoc, void *arg)
164 {
165 	struct psoc_cfr *cfr_sc = NULL;
166 
167 	cfr_sc = (struct psoc_cfr *)qdf_mem_malloc(sizeof(struct psoc_cfr));
168 	if (!cfr_sc) {
169 		cfr_err("Failed to allocate cfr_ctx object\n");
170 		return QDF_STATUS_E_NOMEM;
171 	}
172 
173 	cfr_sc->psoc_obj = psoc;
174 
175 	wlan_objmgr_psoc_component_obj_attach(psoc, WLAN_UMAC_COMP_CFR,
176 					      (void *)cfr_sc,
177 					      QDF_STATUS_SUCCESS);
178 
179 	return QDF_STATUS_SUCCESS;
180 }
181 
182 QDF_STATUS
183 wlan_cfr_psoc_obj_destroy_handler(struct wlan_objmgr_psoc *psoc, void *arg)
184 {
185 	struct psoc_cfr *cfr_sc = NULL;
186 
187 	cfr_sc = wlan_objmgr_psoc_get_comp_private_obj(psoc,
188 						       WLAN_UMAC_COMP_CFR);
189 	if (cfr_sc) {
190 		wlan_objmgr_psoc_component_obj_detach(psoc, WLAN_UMAC_COMP_CFR,
191 						      (void *)cfr_sc);
192 		qdf_mem_free(cfr_sc);
193 	}
194 
195 	return QDF_STATUS_SUCCESS;
196 }
197 
198 QDF_STATUS
199 wlan_cfr_pdev_obj_create_handler(struct wlan_objmgr_pdev *pdev, void *arg)
200 {
201 	struct pdev_cfr *pa = NULL;
202 	uint32_t idx;
203 
204 	if (!pdev) {
205 		cfr_err("PDEV is NULL\n");
206 		return QDF_STATUS_E_FAILURE;
207 	}
208 
209 	if (wlan_cfr_is_ini_disabled(pdev)) {
210 		wlan_pdev_nif_feat_ext_cap_clear(pdev, WLAN_PDEV_FEXT_CFR_EN);
211 		return QDF_STATUS_E_NOSUPPORT;
212 	}
213 
214 	wlan_pdev_nif_feat_ext_cap_set(pdev, WLAN_PDEV_FEXT_CFR_EN);
215 
216 	pa = (struct pdev_cfr *)qdf_mem_malloc(sizeof(struct pdev_cfr));
217 	if (!pa) {
218 		cfr_err("Failed to allocate pdev_cfr object\n");
219 		return QDF_STATUS_E_NOMEM;
220 	}
221 	pa->pdev_obj = pdev;
222 	pa->lut_num = wlan_cfr_get_dbr_num_entries(pdev);
223 	if (!pa->lut_num) {
224 		cfr_err("lut num is 0");
225 		qdf_mem_free(pa);
226 		return QDF_STATUS_E_INVAL;
227 	}
228 	pa->lut = (struct look_up_table **)qdf_mem_malloc(pa->lut_num *
229 			sizeof(struct look_up_table *));
230 	if (!pa->lut) {
231 		cfr_err("Failed to allocate lut, lut num %d", pa->lut_num);
232 		qdf_mem_free(pa);
233 		return QDF_STATUS_E_NOMEM;
234 	}
235 	for (idx = 0; idx < pa->lut_num; idx++)
236 		pa->lut[idx] = (struct look_up_table *)qdf_mem_malloc(
237 			sizeof(struct look_up_table));
238 
239 	cfr_wakelock_init(pa);
240 	wlan_objmgr_pdev_component_obj_attach(pdev, WLAN_UMAC_COMP_CFR,
241 					      (void *)pa, QDF_STATUS_SUCCESS);
242 
243 	return QDF_STATUS_SUCCESS;
244 }
245 
246 QDF_STATUS
247 wlan_cfr_pdev_obj_destroy_handler(struct wlan_objmgr_pdev *pdev, void *arg)
248 {
249 	struct pdev_cfr *pa = NULL;
250 	uint32_t idx;
251 
252 	if (!pdev) {
253 		cfr_err("PDEV is NULL\n");
254 		return QDF_STATUS_E_FAILURE;
255 	}
256 
257 	if (wlan_cfr_is_feature_disabled(pdev)) {
258 		cfr_info("cfr is disabled");
259 		return QDF_STATUS_E_NOSUPPORT;
260 	}
261 
262 	pa = wlan_objmgr_pdev_get_comp_private_obj(pdev, WLAN_UMAC_COMP_CFR);
263 	if (pa) {
264 		cfr_wakelock_deinit(pa);
265 		wlan_objmgr_pdev_component_obj_detach(pdev, WLAN_UMAC_COMP_CFR,
266 						      (void *)pa);
267 		if (pa->lut) {
268 			for (idx = 0; idx < pa->lut_num; idx++)
269 				qdf_mem_free(pa->lut[idx]);
270 			qdf_mem_free(pa->lut);
271 		}
272 		qdf_mem_free(pa);
273 	}
274 
275 	return QDF_STATUS_SUCCESS;
276 }
277 
278 QDF_STATUS
279 wlan_cfr_peer_obj_create_handler(struct wlan_objmgr_peer *peer, void *arg)
280 {
281 	struct peer_cfr *pe = NULL;
282 	struct wlan_objmgr_vdev *vdev;
283 	struct wlan_objmgr_pdev *pdev = NULL;
284 
285 	if (!peer) {
286 		cfr_err("PEER is NULL\n");
287 		return QDF_STATUS_E_FAILURE;
288 	}
289 
290 	vdev = wlan_peer_get_vdev(peer);
291 	if (vdev)
292 		pdev = wlan_vdev_get_pdev(vdev);
293 
294 	if (!pdev) {
295 		cfr_err("PDEV is NULL\n");
296 		return QDF_STATUS_E_FAILURE;
297 	}
298 
299 	if (wlan_cfr_is_feature_disabled(pdev)) {
300 		cfr_debug("cfr is disabled");
301 		return QDF_STATUS_E_NOSUPPORT;
302 	}
303 
304 	pe = (struct peer_cfr *)qdf_mem_malloc(sizeof(struct peer_cfr));
305 	if (!pe) {
306 		cfr_err("Failed to allocate peer_cfr object\n");
307 		return QDF_STATUS_E_FAILURE;
308 	}
309 
310 	pe->peer_obj = peer;
311 
312 	/* Remaining will be populated when we give CFR capture command */
313 	wlan_objmgr_peer_component_obj_attach(peer, WLAN_UMAC_COMP_CFR,
314 					      (void *)pe, QDF_STATUS_SUCCESS);
315 	return QDF_STATUS_SUCCESS;
316 }
317 
318 QDF_STATUS
319 wlan_cfr_peer_obj_destroy_handler(struct wlan_objmgr_peer *peer, void *arg)
320 {
321 	struct peer_cfr *pe = NULL;
322 	struct wlan_objmgr_vdev *vdev;
323 	struct wlan_objmgr_pdev *pdev = NULL;
324 	struct pdev_cfr *pa = NULL;
325 
326 	if (!peer) {
327 		cfr_err("PEER is NULL\n");
328 		return QDF_STATUS_E_FAILURE;
329 	}
330 
331 	vdev = wlan_peer_get_vdev(peer);
332 	if (vdev)
333 		pdev = wlan_vdev_get_pdev(vdev);
334 
335 	if (wlan_cfr_is_feature_disabled(pdev)) {
336 		cfr_info("cfr is disabled");
337 		return QDF_STATUS_E_NOSUPPORT;
338 	}
339 
340 	if (pdev)
341 		pa = wlan_objmgr_pdev_get_comp_private_obj(pdev,
342 							   WLAN_UMAC_COMP_CFR);
343 
344 	pe = wlan_objmgr_peer_get_comp_private_obj(peer, WLAN_UMAC_COMP_CFR);
345 
346 	if (pa && pe) {
347 		if (pe->period && pe->request)
348 			pa->cfr_current_sta_count--;
349 	}
350 
351 	if (pe) {
352 		wlan_objmgr_peer_component_obj_detach(peer, WLAN_UMAC_COMP_CFR,
353 						      (void *)pe);
354 		qdf_mem_free(pe);
355 	}
356 
357 	return QDF_STATUS_SUCCESS;
358 }
359 
360 #ifdef CFR_USE_FIXED_FOLDER
361 static char *cfr_get_dev_name(struct wlan_objmgr_pdev *pdev)
362 {
363 	char *default_name = "wlan";
364 
365 	return default_name;
366 }
367 #else
368 /**
369  * cfr_get_dev_name() - Get net device name from pdev
370  *  @pdev: objmgr pdev
371  *
372  *  Return: netdev name
373  */
374 static char *cfr_get_dev_name(struct wlan_objmgr_pdev *pdev)
375 {
376 	struct pdev_osif_priv *pdev_ospriv;
377 	struct qdf_net_if *nif;
378 
379 	pdev_ospriv = wlan_pdev_get_ospriv(pdev);
380 	if (!pdev_ospriv) {
381 		cfr_err("pdev_ospriv is NULL\n");
382 		return NULL;
383 	}
384 
385 	nif = pdev_ospriv->nif;
386 	if (!nif) {
387 		cfr_err("pdev nif is NULL\n");
388 		return NULL;
389 	}
390 
391 	return  qdf_net_if_get_devname(nif);
392 }
393 #endif
394 
395 QDF_STATUS cfr_streamfs_init(struct wlan_objmgr_pdev *pdev)
396 {
397 	struct pdev_cfr *pa = NULL;
398 	char *devname;
399 	char folder[32];
400 
401 	if (!pdev) {
402 		cfr_err("PDEV is NULL\n");
403 		return QDF_STATUS_E_FAILURE;
404 	}
405 
406 	if (wlan_cfr_is_feature_disabled(pdev)) {
407 		cfr_info("cfr is disabled");
408 		return QDF_STATUS_COMP_DISABLED;
409 	}
410 
411 	pa = wlan_objmgr_pdev_get_comp_private_obj(pdev, WLAN_UMAC_COMP_CFR);
412 
413 	if (pa == NULL) {
414 		cfr_err("pdev_cfr is NULL\n");
415 		return QDF_STATUS_E_FAILURE;
416 	}
417 
418 	if (!pa->is_cfr_capable) {
419 		cfr_err("CFR IS NOT SUPPORTED\n");
420 		return QDF_STATUS_E_FAILURE;
421 	}
422 
423 	devname = cfr_get_dev_name(pdev);
424 	if (!devname) {
425 		cfr_err("devname is NULL\n");
426 		return QDF_STATUS_E_FAILURE;
427 	}
428 
429 	snprintf(folder, sizeof(folder), "cfr%s", devname);
430 
431 	pa->dir_ptr = qdf_streamfs_create_dir((const char *)folder, NULL);
432 
433 	if (!pa->dir_ptr) {
434 		cfr_err("Directory create failed");
435 		return QDF_STATUS_E_FAILURE;
436 	}
437 
438 	pa->chan_ptr = qdf_streamfs_open("cfr_dump", pa->dir_ptr,
439 					 pa->subbuf_size,
440 					 pa->num_subbufs, NULL);
441 
442 	if (!pa->chan_ptr) {
443 		cfr_err("Chan create failed");
444 		qdf_streamfs_remove_dir_recursive(pa->dir_ptr);
445 		pa->dir_ptr = NULL;
446 		return QDF_STATUS_E_FAILURE;
447 	}
448 
449 	return QDF_STATUS_SUCCESS;
450 }
451 
452 QDF_STATUS cfr_streamfs_remove(struct wlan_objmgr_pdev *pdev)
453 {
454 	struct pdev_cfr *pa = NULL;
455 
456 	if (wlan_cfr_is_feature_disabled(pdev)) {
457 		cfr_info("cfr is disabled");
458 		return QDF_STATUS_COMP_DISABLED;
459 	}
460 
461 	pa = wlan_objmgr_pdev_get_comp_private_obj(pdev, WLAN_UMAC_COMP_CFR);
462 	if (pa) {
463 		if (pa->chan_ptr) {
464 			qdf_streamfs_close(pa->chan_ptr);
465 			pa->chan_ptr = NULL;
466 		}
467 
468 		if (pa->dir_ptr) {
469 			qdf_streamfs_remove_dir_recursive(pa->dir_ptr);
470 			pa->dir_ptr = NULL;
471 		}
472 
473 	} else
474 		return QDF_STATUS_E_FAILURE;
475 
476 	return QDF_STATUS_SUCCESS;
477 }
478 
479 QDF_STATUS cfr_streamfs_write(struct pdev_cfr *pa, const void *write_data,
480 			      size_t write_len)
481 {
482 	if (pa->chan_ptr) {
483 	/* write to channel buffer */
484 		qdf_streamfs_write(pa->chan_ptr, (const void *)write_data,
485 				   write_len);
486 	} else
487 		return QDF_STATUS_E_FAILURE;
488 
489 	return QDF_STATUS_SUCCESS;
490 }
491 
492 QDF_STATUS cfr_streamfs_flush(struct pdev_cfr *pa)
493 {
494 	if (pa->chan_ptr) {
495 
496 	/* Flush the data write to channel buffer */
497 		qdf_streamfs_flush(pa->chan_ptr);
498 	} else
499 		return QDF_STATUS_E_FAILURE;
500 
501 	return QDF_STATUS_SUCCESS;
502 }
503 
504 QDF_STATUS cfr_stop_indication(struct wlan_objmgr_vdev *vdev)
505 {
506 	struct pdev_cfr *pa;
507 	uint32_t status;
508 	struct wlan_objmgr_pdev *pdev;
509 
510 	pdev = wlan_vdev_get_pdev(vdev);
511 	pa = wlan_objmgr_pdev_get_comp_private_obj(pdev, WLAN_UMAC_COMP_CFR);
512 	if (!pa) {
513 		cfr_err("pdev_cfr is NULL\n");
514 		return QDF_STATUS_E_INVAL;
515 	}
516 
517 	/* Don't write stop string if there is valid cfr_nl_cb. Since
518 	 * userspace needn't stop event string
519 	 */
520 	if (pa->nl_cb.cfr_nl_cb)
521 		return QDF_STATUS_SUCCESS;
522 
523 	status = cfr_streamfs_write(pa, (const void *)CFR_STOP_STR,
524 				    sizeof(CFR_STOP_STR));
525 
526 	status = cfr_streamfs_flush(pa);
527 	cfr_debug("stop indication done");
528 
529 	return status;
530 }
531 
532 #ifdef WLAN_CFR_PM
533 QDF_STATUS cfr_prevent_suspend(struct pdev_cfr *pcfr)
534 {
535 	if (!pcfr) {
536 		cfr_debug("NULL pcfr");
537 		return QDF_STATUS_E_INVAL;
538 	}
539 
540 	if (pcfr->is_prevent_suspend) {
541 		cfr_debug("acquired wake lock");
542 		return QDF_STATUS_E_AGAIN;
543 	}
544 	qdf_wake_lock_acquire(&pcfr->wake_lock,
545 			      WIFI_POWER_EVENT_WAKELOCK_CFR);
546 	qdf_runtime_pm_prevent_suspend(&pcfr->runtime_lock);
547 	pcfr->is_prevent_suspend = true;
548 
549 	return QDF_STATUS_SUCCESS;
550 }
551 
552 QDF_STATUS cfr_allow_suspend(struct pdev_cfr *pcfr)
553 {
554 	if (!pcfr) {
555 		cfr_debug("NULL pcfr");
556 		return QDF_STATUS_E_INVAL;
557 	}
558 
559 	if (!pcfr->is_prevent_suspend) {
560 		cfr_debug("wake lock not acquired");
561 		return QDF_STATUS_E_INVAL;
562 	}
563 	qdf_wake_lock_release(&pcfr->wake_lock,
564 			      WIFI_POWER_EVENT_WAKELOCK_CFR);
565 	qdf_runtime_pm_allow_suspend(&pcfr->runtime_lock);
566 	pcfr->is_prevent_suspend = false;
567 
568 	return QDF_STATUS_SUCCESS;
569 }
570 #endif
571