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