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