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
wlan_cfr_is_ini_disabled(struct wlan_objmgr_pdev * pdev)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
wlan_cfr_get_dbr_num_entries(struct wlan_objmgr_pdev * pdev)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  */
cfr_wakelock_init(struct pdev_cfr * pcfr)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  */
cfr_wakelock_deinit(struct pdev_cfr * pcfr)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
cfr_wakelock_init(struct pdev_cfr * pcfr)153 static inline void cfr_wakelock_init(struct pdev_cfr *pcfr)
154 {
155 }
156 
cfr_wakelock_deinit(struct pdev_cfr * pcfr)157 static inline void cfr_wakelock_deinit(struct pdev_cfr *pcfr)
158 {
159 }
160 #endif
161 
162 QDF_STATUS
wlan_cfr_psoc_obj_create_handler(struct wlan_objmgr_psoc * psoc,void * arg)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
wlan_cfr_psoc_obj_destroy_handler(struct wlan_objmgr_psoc * psoc,void * arg)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 #ifdef WLAN_RCC_ENHANCED_AOA_SUPPORT
wlan_cfr_get_aoa_caps(struct pdev_cfr * pa)199 static QDF_STATUS wlan_cfr_get_aoa_caps(struct pdev_cfr *pa)
200 {
201 	struct wlan_objmgr_pdev *pdev = pa->pdev_obj;
202 	struct wlan_objmgr_psoc *psoc;
203 	struct target_psoc_info *tgt_psoc_info;
204 	struct wlan_psoc_host_rcc_enh_aoa_caps_ext2 *aoa_caps;
205 	uint32_t i, max_agc_gain_tbl_sz;
206 
207 	if (!pdev) {
208 		cfr_err("Invalid pdev");
209 		return QDF_STATUS_E_INVAL;
210 	}
211 
212 	psoc = wlan_pdev_get_psoc(pdev);
213 	if (!psoc) {
214 		cfr_err("psoc is null");
215 		return QDF_STATUS_E_INVAL;
216 	}
217 
218 	tgt_psoc_info = wlan_psoc_get_tgt_if_handle(psoc);
219 	if (!tgt_psoc_info) {
220 		cfr_err("target_psoc_info is null");
221 		return QDF_STATUS_E_INVAL;
222 	}
223 
224 	pa->is_enh_aoa_data = false;
225 
226 	aoa_caps = target_psoc_get_aoa_caps(tgt_psoc_info);
227 
228 	if (!aoa_caps) {
229 		cfr_info("NO enhanced AoA cap advertised");
230 		return QDF_STATUS_SUCCESS;
231 	}
232 
233 	max_agc_gain_tbl_sz = sizeof(uint16_t) * PSOC_MAX_NUM_AGC_GAIN_TBLS;
234 	pa->max_entries_all_table = 0;
235 	pa->max_agc_gain_tbls = aoa_caps->max_agc_gain_tbls;
236 
237 	if (pa->max_agc_gain_tbls > PSOC_MAX_NUM_AGC_GAIN_TBLS) {
238 		cfr_err("Invalid num of tables advertised");
239 		return QDF_STATUS_E_INVAL;
240 	}
241 
242 	qdf_mem_copy(pa->max_agc_gain_per_tbl_2g,
243 		     aoa_caps->max_agc_gain_per_tbl_2g,
244 		     max_agc_gain_tbl_sz);
245 	qdf_mem_copy(pa->max_agc_gain_per_tbl_5g,
246 		     aoa_caps->max_agc_gain_per_tbl_5g,
247 		     max_agc_gain_tbl_sz);
248 	qdf_mem_copy(pa->max_agc_gain_per_tbl_6g,
249 		     aoa_caps->max_agc_gain_per_tbl_6g,
250 		     max_agc_gain_tbl_sz);
251 	qdf_mem_copy(pa->max_bdf_entries_per_tbl,
252 		     aoa_caps->max_bdf_entries_per_tbl,
253 		     (sizeof(uint8_t) * PSOC_MAX_NUM_AGC_GAIN_TBLS));
254 
255 	/* table 0's data always starts at offset 0 */
256 	pa->start_ent[0] = 0;
257 	for (i = 0; i < pa->max_agc_gain_tbls; i++) {
258 		pa->max_entries_all_table +=
259 			pa->max_bdf_entries_per_tbl[i];
260 		if ((i + 1) < pa->max_agc_gain_tbls) {
261 			pa->start_ent[i + 1] = (pa->max_bdf_entries_per_tbl[i] +
262 					pa->start_ent[i]);
263 		}
264 	}
265 
266 	pa->gain_stop_index_array = qdf_mem_malloc(sizeof(uint16_t) *
267 					pa->max_entries_all_table *
268 					HOST_MAX_CHAINS);
269 	if (!pa->gain_stop_index_array) {
270 		qdf_err("Failed to allocate gain stop array");
271 		return QDF_STATUS_E_NOMEM;
272 	}
273 
274 	pa->enh_phase_delta_array = qdf_mem_malloc(sizeof(uint16_t) *
275 					pa->max_entries_all_table *
276 					HOST_MAX_CHAINS);
277 	if (!pa->enh_phase_delta_array) {
278 		qdf_err("Failed to allocate phase delta array");
279 		qdf_mem_free(pa->gain_stop_index_array);
280 		return QDF_STATUS_E_NOMEM;
281 	}
282 
283 	pa->is_enh_aoa_data = true;
284 
285 	return QDF_STATUS_SUCCESS;
286 }
287 #else
wlan_cfr_get_aoa_caps(struct pdev_cfr * pa)288 static QDF_STATUS wlan_cfr_get_aoa_caps(struct pdev_cfr *pa)
289 {
290 	return QDF_STATUS_SUCCESS;
291 }
292 #endif /* WLAN_RCC_ENHANCED_AOA_SUPPORT */
293 
294 QDF_STATUS
wlan_cfr_pdev_obj_create_handler(struct wlan_objmgr_pdev * pdev,void * arg)295 wlan_cfr_pdev_obj_create_handler(struct wlan_objmgr_pdev *pdev, void *arg)
296 {
297 	struct pdev_cfr *pa = NULL;
298 	uint32_t idx;
299 	QDF_STATUS status;
300 
301 	if (!pdev) {
302 		cfr_err("PDEV is NULL\n");
303 		return QDF_STATUS_E_FAILURE;
304 	}
305 
306 	if (wlan_cfr_is_ini_disabled(pdev)) {
307 		wlan_pdev_nif_feat_ext_cap_clear(pdev, WLAN_PDEV_FEXT_CFR_EN);
308 		return QDF_STATUS_E_NOSUPPORT;
309 	}
310 
311 	wlan_pdev_nif_feat_ext_cap_set(pdev, WLAN_PDEV_FEXT_CFR_EN);
312 
313 	pa = (struct pdev_cfr *)qdf_mem_malloc(sizeof(struct pdev_cfr));
314 	if (!pa) {
315 		cfr_err("Failed to allocate pdev_cfr object\n");
316 		return QDF_STATUS_E_NOMEM;
317 	}
318 	pa->pdev_obj = pdev;
319 	pa->lut_num = wlan_cfr_get_dbr_num_entries(pdev);
320 	if (!pa->lut_num) {
321 		cfr_err("lut num is 0");
322 		qdf_mem_free(pa);
323 		return QDF_STATUS_E_INVAL;
324 	}
325 	pa->lut = (struct look_up_table **)qdf_mem_malloc(pa->lut_num *
326 			sizeof(struct look_up_table *));
327 	if (!pa->lut) {
328 		cfr_err("Failed to allocate lut, lut num %d", pa->lut_num);
329 		qdf_mem_free(pa);
330 		return QDF_STATUS_E_NOMEM;
331 	}
332 	for (idx = 0; idx < pa->lut_num; idx++)
333 		pa->lut[idx] = (struct look_up_table *)qdf_mem_malloc(
334 			sizeof(struct look_up_table));
335 
336 	/* Allocate AoA related variables here based on FW capability */
337 	status = wlan_cfr_get_aoa_caps(pa);
338 	if (QDF_IS_STATUS_ERROR(status)) {
339 		cfr_err("Failed to get aoa caps");
340 		for (idx = 0; idx < pa->lut_num; idx++)
341 			qdf_mem_free(pa->lut[idx]);
342 		qdf_mem_free(pa);
343 		return status;
344 	}
345 
346 	cfr_wakelock_init(pa);
347 	wlan_objmgr_pdev_component_obj_attach(pdev, WLAN_UMAC_COMP_CFR,
348 					      (void *)pa, QDF_STATUS_SUCCESS);
349 
350 	return QDF_STATUS_SUCCESS;
351 }
352 
353 #ifdef WLAN_RCC_ENHANCED_AOA_SUPPORT
354 static inline
wlan_cfr_cleanup_enhanced_aoa(struct pdev_cfr * pa)355 void wlan_cfr_cleanup_enhanced_aoa(struct pdev_cfr *pa)
356 {
357 	/**
358 	 * Free enahced AoA related allocations here.
359 	 * Caller of this API should ensure pa is not NULL
360 	 */
361 	if (pa->gain_stop_index_array)
362 		qdf_mem_free(pa->gain_stop_index_array);
363 
364 	if (pa->enh_phase_delta_array)
365 		qdf_mem_free(pa->enh_phase_delta_array);
366 }
367 #else
368 static inline
wlan_cfr_cleanup_enhanced_aoa(struct pdev_cfr * pa)369 void wlan_cfr_cleanup_enhanced_aoa(struct pdev_cfr *pa)
370 {
371 }
372 #endif /* WLAN_RCC_ENHANCED_AOA_SUPPORT */
373 
374 QDF_STATUS
wlan_cfr_pdev_obj_destroy_handler(struct wlan_objmgr_pdev * pdev,void * arg)375 wlan_cfr_pdev_obj_destroy_handler(struct wlan_objmgr_pdev *pdev, void *arg)
376 {
377 	struct pdev_cfr *pa = NULL;
378 	uint32_t idx;
379 
380 	if (!pdev) {
381 		cfr_err("PDEV is NULL\n");
382 		return QDF_STATUS_E_FAILURE;
383 	}
384 
385 	if (wlan_cfr_is_feature_disabled(pdev)) {
386 		cfr_info("cfr is disabled");
387 		return QDF_STATUS_E_NOSUPPORT;
388 	}
389 
390 	pa = wlan_objmgr_pdev_get_comp_private_obj(pdev, WLAN_UMAC_COMP_CFR);
391 	if (pa) {
392 		cfr_wakelock_deinit(pa);
393 		wlan_objmgr_pdev_component_obj_detach(pdev, WLAN_UMAC_COMP_CFR,
394 						      (void *)pa);
395 		if (pa->lut) {
396 			for (idx = 0; idx < pa->lut_num; idx++)
397 				qdf_mem_free(pa->lut[idx]);
398 			qdf_mem_free(pa->lut);
399 		}
400 
401 		wlan_cfr_cleanup_enhanced_aoa(pa);
402 		qdf_mem_free(pa);
403 	}
404 
405 	return QDF_STATUS_SUCCESS;
406 }
407 
408 QDF_STATUS
wlan_cfr_peer_obj_create_handler(struct wlan_objmgr_peer * peer,void * arg)409 wlan_cfr_peer_obj_create_handler(struct wlan_objmgr_peer *peer, void *arg)
410 {
411 	struct peer_cfr *pe = NULL;
412 	struct wlan_objmgr_vdev *vdev;
413 	struct wlan_objmgr_pdev *pdev = NULL;
414 
415 	if (!peer) {
416 		cfr_err("PEER is NULL\n");
417 		return QDF_STATUS_E_FAILURE;
418 	}
419 
420 	vdev = wlan_peer_get_vdev(peer);
421 	if (vdev)
422 		pdev = wlan_vdev_get_pdev(vdev);
423 
424 	if (!pdev) {
425 		cfr_err("PDEV is NULL\n");
426 		return QDF_STATUS_E_FAILURE;
427 	}
428 
429 	if (wlan_cfr_is_feature_disabled(pdev)) {
430 		cfr_debug("cfr is disabled");
431 		return QDF_STATUS_E_NOSUPPORT;
432 	}
433 
434 	pe = (struct peer_cfr *)qdf_mem_malloc(sizeof(struct peer_cfr));
435 	if (!pe) {
436 		cfr_err("Failed to allocate peer_cfr object\n");
437 		return QDF_STATUS_E_FAILURE;
438 	}
439 
440 	pe->peer_obj = peer;
441 
442 	/* Remaining will be populated when we give CFR capture command */
443 	wlan_objmgr_peer_component_obj_attach(peer, WLAN_UMAC_COMP_CFR,
444 					      (void *)pe, QDF_STATUS_SUCCESS);
445 	return QDF_STATUS_SUCCESS;
446 }
447 
448 QDF_STATUS
wlan_cfr_peer_obj_destroy_handler(struct wlan_objmgr_peer * peer,void * arg)449 wlan_cfr_peer_obj_destroy_handler(struct wlan_objmgr_peer *peer, void *arg)
450 {
451 	struct peer_cfr *pe = NULL;
452 	struct wlan_objmgr_vdev *vdev;
453 	struct wlan_objmgr_pdev *pdev = NULL;
454 	struct pdev_cfr *pa = NULL;
455 
456 	if (!peer) {
457 		cfr_err("PEER is NULL\n");
458 		return QDF_STATUS_E_FAILURE;
459 	}
460 
461 	vdev = wlan_peer_get_vdev(peer);
462 	if (vdev)
463 		pdev = wlan_vdev_get_pdev(vdev);
464 
465 	if (wlan_cfr_is_feature_disabled(pdev)) {
466 		cfr_info("cfr is disabled");
467 		return QDF_STATUS_E_NOSUPPORT;
468 	}
469 
470 	if (pdev)
471 		pa = wlan_objmgr_pdev_get_comp_private_obj(pdev,
472 							   WLAN_UMAC_COMP_CFR);
473 
474 	pe = wlan_objmgr_peer_get_comp_private_obj(peer, WLAN_UMAC_COMP_CFR);
475 
476 	if (pa && pe) {
477 		if (pe->period && pe->request)
478 			pa->cfr_current_sta_count--;
479 	}
480 
481 	if (pe) {
482 		wlan_objmgr_peer_component_obj_detach(peer, WLAN_UMAC_COMP_CFR,
483 						      (void *)pe);
484 		qdf_mem_free(pe);
485 	}
486 
487 	return QDF_STATUS_SUCCESS;
488 }
489 
490 #ifdef CFR_USE_FIXED_FOLDER
cfr_get_dev_name(struct wlan_objmgr_pdev * pdev)491 static char *cfr_get_dev_name(struct wlan_objmgr_pdev *pdev)
492 {
493 	char *default_name = "wlan";
494 
495 	return default_name;
496 }
497 #else
498 /**
499  * cfr_get_dev_name() - Get net device name from pdev
500  *  @pdev: objmgr pdev
501  *
502  *  Return: netdev name
503  */
cfr_get_dev_name(struct wlan_objmgr_pdev * pdev)504 static char *cfr_get_dev_name(struct wlan_objmgr_pdev *pdev)
505 {
506 	struct pdev_osif_priv *pdev_ospriv;
507 	struct qdf_net_if *nif;
508 
509 	pdev_ospriv = wlan_pdev_get_ospriv(pdev);
510 	if (!pdev_ospriv) {
511 		cfr_err("pdev_ospriv is NULL\n");
512 		return NULL;
513 	}
514 
515 	nif = pdev_ospriv->nif;
516 	if (!nif) {
517 		cfr_err("pdev nif is NULL\n");
518 		return NULL;
519 	}
520 
521 	return  qdf_net_if_get_devname(nif);
522 }
523 #endif
524 
cfr_streamfs_init(struct wlan_objmgr_pdev * pdev)525 QDF_STATUS cfr_streamfs_init(struct wlan_objmgr_pdev *pdev)
526 {
527 	struct pdev_cfr *pa = NULL;
528 	char *devname;
529 	char folder[32];
530 
531 	if (!pdev) {
532 		cfr_err("PDEV is NULL\n");
533 		return QDF_STATUS_E_FAILURE;
534 	}
535 
536 	if (wlan_cfr_is_feature_disabled(pdev)) {
537 		cfr_info("cfr is disabled");
538 		return QDF_STATUS_COMP_DISABLED;
539 	}
540 
541 	pa = wlan_objmgr_pdev_get_comp_private_obj(pdev, WLAN_UMAC_COMP_CFR);
542 
543 	if (pa == NULL) {
544 		cfr_err("pdev_cfr is NULL\n");
545 		return QDF_STATUS_E_FAILURE;
546 	}
547 
548 	if (!pa->is_cfr_capable) {
549 		cfr_err("CFR IS NOT SUPPORTED\n");
550 		return QDF_STATUS_E_FAILURE;
551 	}
552 
553 	devname = cfr_get_dev_name(pdev);
554 	if (!devname) {
555 		cfr_err("devname is NULL\n");
556 		return QDF_STATUS_E_FAILURE;
557 	}
558 
559 	snprintf(folder, sizeof(folder), "cfr%s", devname);
560 
561 	pa->dir_ptr = qdf_streamfs_create_dir((const char *)folder, NULL);
562 
563 	if (!pa->dir_ptr) {
564 		cfr_err("Directory create failed");
565 		return QDF_STATUS_E_FAILURE;
566 	}
567 
568 	pa->chan_ptr = qdf_streamfs_open("cfr_dump", pa->dir_ptr,
569 					 pa->subbuf_size,
570 					 pa->num_subbufs, NULL);
571 
572 	if (!pa->chan_ptr) {
573 		cfr_err("Chan create failed");
574 		qdf_streamfs_remove_dir_recursive(pa->dir_ptr);
575 		pa->dir_ptr = NULL;
576 		return QDF_STATUS_E_FAILURE;
577 	}
578 
579 	return QDF_STATUS_SUCCESS;
580 }
581 
cfr_streamfs_remove(struct wlan_objmgr_pdev * pdev)582 QDF_STATUS cfr_streamfs_remove(struct wlan_objmgr_pdev *pdev)
583 {
584 	struct pdev_cfr *pa = NULL;
585 
586 	if (wlan_cfr_is_feature_disabled(pdev)) {
587 		cfr_info("cfr is disabled");
588 		return QDF_STATUS_COMP_DISABLED;
589 	}
590 
591 	pa = wlan_objmgr_pdev_get_comp_private_obj(pdev, WLAN_UMAC_COMP_CFR);
592 	if (pa) {
593 		if (pa->chan_ptr) {
594 			qdf_streamfs_close(pa->chan_ptr);
595 			pa->chan_ptr = NULL;
596 		}
597 
598 		if (pa->dir_ptr) {
599 			qdf_streamfs_remove_dir_recursive(pa->dir_ptr);
600 			pa->dir_ptr = NULL;
601 		}
602 
603 	} else
604 		return QDF_STATUS_E_FAILURE;
605 
606 	return QDF_STATUS_SUCCESS;
607 }
608 
cfr_streamfs_write(struct pdev_cfr * pa,const void * write_data,size_t write_len)609 QDF_STATUS cfr_streamfs_write(struct pdev_cfr *pa, const void *write_data,
610 			      size_t write_len)
611 {
612 	if (pa->chan_ptr) {
613 	/* write to channel buffer */
614 		qdf_streamfs_write(pa->chan_ptr, (const void *)write_data,
615 				   write_len);
616 	} else
617 		return QDF_STATUS_E_FAILURE;
618 
619 	return QDF_STATUS_SUCCESS;
620 }
621 
cfr_streamfs_flush(struct pdev_cfr * pa)622 QDF_STATUS cfr_streamfs_flush(struct pdev_cfr *pa)
623 {
624 	if (pa->chan_ptr) {
625 
626 	/* Flush the data write to channel buffer */
627 		qdf_streamfs_flush(pa->chan_ptr);
628 	} else
629 		return QDF_STATUS_E_FAILURE;
630 
631 	return QDF_STATUS_SUCCESS;
632 }
633 
cfr_stop_indication(struct wlan_objmgr_vdev * vdev)634 QDF_STATUS cfr_stop_indication(struct wlan_objmgr_vdev *vdev)
635 {
636 	struct pdev_cfr *pa;
637 	uint32_t status;
638 	struct wlan_objmgr_pdev *pdev;
639 
640 	pdev = wlan_vdev_get_pdev(vdev);
641 	pa = wlan_objmgr_pdev_get_comp_private_obj(pdev, WLAN_UMAC_COMP_CFR);
642 	if (!pa) {
643 		cfr_err("pdev_cfr is NULL\n");
644 		return QDF_STATUS_E_INVAL;
645 	}
646 
647 	/* Don't write stop string if there is valid cfr_nl_cb. Since
648 	 * userspace needn't stop event string
649 	 */
650 	if (pa->nl_cb.cfr_nl_cb)
651 		return QDF_STATUS_SUCCESS;
652 
653 	status = cfr_streamfs_write(pa, (const void *)CFR_STOP_STR,
654 				    sizeof(CFR_STOP_STR));
655 
656 	status = cfr_streamfs_flush(pa);
657 	cfr_debug("stop indication done");
658 
659 	return status;
660 }
661 
662 #ifdef WLAN_CFR_PM
cfr_prevent_suspend(struct pdev_cfr * pcfr)663 QDF_STATUS cfr_prevent_suspend(struct pdev_cfr *pcfr)
664 {
665 	if (!pcfr) {
666 		cfr_debug("NULL pcfr");
667 		return QDF_STATUS_E_INVAL;
668 	}
669 
670 	if (pcfr->is_prevent_suspend) {
671 		cfr_debug("acquired wake lock");
672 		return QDF_STATUS_E_AGAIN;
673 	}
674 	qdf_wake_lock_acquire(&pcfr->wake_lock,
675 			      WIFI_POWER_EVENT_WAKELOCK_CFR);
676 	qdf_runtime_pm_prevent_suspend(&pcfr->runtime_lock);
677 	pcfr->is_prevent_suspend = true;
678 
679 	return QDF_STATUS_SUCCESS;
680 }
681 
cfr_allow_suspend(struct pdev_cfr * pcfr)682 QDF_STATUS cfr_allow_suspend(struct pdev_cfr *pcfr)
683 {
684 	if (!pcfr) {
685 		cfr_debug("NULL pcfr");
686 		return QDF_STATUS_E_INVAL;
687 	}
688 
689 	if (!pcfr->is_prevent_suspend) {
690 		cfr_debug("wake lock not acquired");
691 		return QDF_STATUS_E_INVAL;
692 	}
693 	qdf_wake_lock_release(&pcfr->wake_lock,
694 			      WIFI_POWER_EVENT_WAKELOCK_CFR);
695 	qdf_runtime_pm_allow_suspend(&pcfr->runtime_lock);
696 	pcfr->is_prevent_suspend = false;
697 
698 	return QDF_STATUS_SUCCESS;
699 }
700 #endif
701