xref: /wlan-dirver/qca-wifi-host-cmn/umac/dfs/core/src/misc/dfs_filter_init.c (revision 901120c066e139c7f8a2c8e4820561fdd83c67ef)
1 /*
2  * Copyright (c) 2016-2020 The Linux Foundation. All rights reserved.
3  * Copyright (c) 2022 Qualcomm Innovation Center, Inc. All rights reserved.
4  * Copyright (c) 2002-2006, Atheros Communications Inc.
5  *
6  * Permission to use, copy, modify, and/or distribute this software for any
7  * purpose with or without fee is hereby granted, provided that the above
8  * copyright notice and this permission notice appear in all copies.
9  *
10  * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
11  * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
12  * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
13  * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
14  * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
15  * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
16  * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
17  */
18 
19 /**
20  * DOC: This file contains the dfs_attach() and dfs_detach() functions as well
21  * as the dfs_control() function which is used to process ioctls related to DFS.
22  * For Linux/Mac,  "radartool" is the command line tool that can be used to call
23  * various ioctls to set and get radar detection thresholds.
24  */
25 
26 #include "../dfs_zero_cac.h"
27 #include "wlan_dfs_lmac_api.h"
28 #include "wlan_dfs_mlme_api.h"
29 #include "wlan_dfs_tgt_api.h"
30 #include "../dfs_internal.h"
31 #include "../dfs_filter_init.h"
32 #include "../dfs_partial_offload_radar.h"
33 
34 #ifndef WLAN_DFS_STATIC_MEM_ALLOC
35 /*
36  * dfs_alloc_dfs_events() - allocate dfs events buffer
37  *
38  * Return: events buffer, null on failure.
39  */
40 static inline struct dfs_event *dfs_alloc_dfs_events(void)
41 {
42 	return qdf_mem_malloc(sizeof(struct dfs_event) * DFS_MAX_EVENTS);
43 }
44 
45 /*
46  * dfs_free_dfs_events() - Free events buffer
47  * @events: Events buffer pointer
48  *
49  * Return: None
50  */
51 static inline void dfs_free_dfs_events(struct dfs_event *events)
52 {
53 	qdf_mem_free(events);
54 }
55 
56 /*
57  * dfs_alloc_dfs_pulseline() - allocate buffer for dfs pulses
58  *
59  * Return: events buffer, null on failure.
60  */
61 static inline struct dfs_pulseline *dfs_alloc_dfs_pulseline(void)
62 {
63 	return qdf_mem_malloc(sizeof(struct dfs_pulseline));
64 }
65 
66 /*
67  * dfs_free_dfs_pulseline() - Free pulse buffer
68  * @pulses: Pulses buffer pointer
69  *
70  * Return: None
71  */
72 static inline void dfs_free_dfs_pulseline(struct dfs_pulseline *pulses)
73 {
74 	qdf_mem_free(pulses);
75 }
76 #else
77 /* Static buffers for DFS objects */
78 static struct dfs_event global_dfs_event[DFS_MAX_EVENTS];
79 static struct dfs_pulseline global_dfs_pulseline;
80 
81 static inline struct dfs_event *dfs_alloc_dfs_events(void)
82 {
83 	return global_dfs_event;
84 }
85 
86 static inline void dfs_free_dfs_events(struct dfs_event *events)
87 {
88 }
89 
90 static inline struct dfs_pulseline *dfs_alloc_dfs_pulseline(void)
91 {
92 	return &global_dfs_pulseline;
93 }
94 
95 static inline void dfs_free_dfs_pulseline(struct dfs_pulseline *pulses)
96 {
97 }
98 #endif
99 
100 /*
101  * Channel switch announcement (CSA)
102  * usenol=1 (default) make CSA and switch to a new channel on radar detect
103  * usenol=0, make CSA with next channel same as current on radar detect
104  * usenol=2, no CSA and stay on the same channel on radar detect
105  */
106 
107 /**
108  * dfs_task() - The timer function to process the radar pulses.
109  */
110 static os_timer_func(dfs_task)
111 {
112 	struct wlan_dfs *dfs = NULL;
113 
114 	OS_GET_TIMER_ARG(dfs, struct wlan_dfs *);
115 
116 	if (!dfs) {
117 		dfs_err(dfs, WLAN_DEBUG_DFS_ALWAYS,  "dfs is NULL");
118 		return;
119 	}
120 
121 	/* Need to take a lock here since dfs filtering data structures are
122 	 * freed and re-allocated in dfs_init_radar_filters() during channel
123 	 * change which may happen in the middle of dfs pulse processing.
124 	 */
125 	WLAN_DFS_DATA_STRUCT_LOCK(dfs);
126 	dfs_process_radarevent(dfs, dfs->dfs_curchan);
127 	WLAN_DFS_DATA_STRUCT_UNLOCK(dfs);
128 
129 	dfs->wlan_radar_tasksched = 0;
130 }
131 
132 /**
133  * dfs_main_task_timer_init() - Initialize dfs task timer.
134  * @dfs: Pointer to wlan_dfs structure.
135  */
136 static void dfs_main_task_timer_init(struct wlan_dfs *dfs)
137 {
138 	qdf_timer_init(NULL,
139 			&(dfs->wlan_dfs_task_timer),
140 			dfs_task,
141 			(void *)(dfs),
142 			QDF_TIMER_TYPE_WAKE_APPS);
143 }
144 
145 /**
146  * dfs_free_filter() - free memory allocated for dfs ft_filters
147  * @radarf: pointer holding ft_filters.
148  *
149  * Return: None
150  */
151 static void dfs_free_filter(struct dfs_filtertype *radarf)
152 {
153 	uint8_t i;
154 
155 	for (i = 0; i < DFS_MAX_NUM_RADAR_FILTERS; i++) {
156 		if (radarf->ft_filters[i]) {
157 			qdf_mem_free(radarf->ft_filters[i]);
158 			radarf->ft_filters[i] = NULL;
159 		}
160 	}
161 }
162 
163 /**
164  * dfs_alloc_mem_filter() - allocate memory for dfs ft_filters
165  * @radarf: pointer holding ft_filters.
166  *
167  * Return: QDF_STATUS
168  */
169 static QDF_STATUS dfs_alloc_mem_filter(struct dfs_filtertype *radarf)
170 {
171 	uint8_t i;
172 
173 	for (i = 0; i < DFS_MAX_NUM_RADAR_FILTERS; i++) {
174 		radarf->ft_filters[i] = qdf_mem_malloc(sizeof(struct
175 							      dfs_filter));
176 		if (!radarf->ft_filters[i]) {
177 			/* Free all the filter if malloc failed */
178 			dfs_free_filter(radarf);
179 			return QDF_STATUS_E_FAILURE;
180 		}
181 	}
182 
183 	return QDF_STATUS_SUCCESS;
184 }
185 
186 int dfs_main_attach(struct wlan_dfs *dfs)
187 {
188 	int i, n;
189 	QDF_STATUS status;
190 	struct wlan_dfs_radar_tab_info radar_info;
191 
192 	if (!dfs) {
193 		dfs_err(dfs, WLAN_DEBUG_DFS_ALWAYS,  "dfs is NULL");
194 		return 0;
195 	}
196 
197 	/* If ignore_dfs is set to 1 then Radar detection is disabled. */
198 	if (dfs->dfs_ignore_dfs) {
199 		dfs_debug(dfs, WLAN_DEBUG_DFS1, "ignoring dfs");
200 		return 0;
201 	}
202 
203 	/*
204 	 * Zero out radar_info. It's possible that the attach function
205 	 * won't fetch an initial regulatory configuration; you really
206 	 * do want to ensure that the contents indicates there aren't
207 	 * any filters.
208 	 */
209 	qdf_mem_zero(&radar_info, sizeof(radar_info));
210 
211 	lmac_get_caps(dfs->dfs_pdev_obj, &(dfs->dfs_caps));
212 
213 	dfs_clear_stats(dfs);
214 	dfs->dfs_event_log_on = 1;
215 	dfs_debug(dfs, WLAN_DEBUG_DFS_ALWAYS, "event log enabled by default");
216 
217 	dfs->dfs_enable = 1;
218 
219 	/*Verify : Passing NULL to qdf_timer_init().*/
220 	dfs_main_task_timer_init(dfs);
221 
222 	dfs_allow_hw_pulses(dfs, true);
223 	dfs_host_wait_timer_init(dfs);
224 
225 	WLAN_DFSQ_LOCK_CREATE(dfs);
226 	STAILQ_INIT(&dfs->dfs_radarq);
227 	WLAN_ARQ_LOCK_CREATE(dfs);
228 	STAILQ_INIT(&dfs->dfs_arq);
229 	STAILQ_INIT(&(dfs->dfs_eventq));
230 	WLAN_DFSEVENTQ_LOCK_CREATE(dfs);
231 	WLAN_DFS_DATA_STRUCT_LOCK_CREATE(dfs);
232 
233 	dfs->events = dfs_alloc_dfs_events();
234 	if (!(dfs->events))
235 		return 1;
236 
237 	for (i = 0; i < DFS_MAX_EVENTS; i++)
238 		STAILQ_INSERT_TAIL(&(dfs->dfs_eventq), &dfs->events[i],
239 				re_list);
240 
241 	dfs->pulses = dfs_alloc_dfs_pulseline();
242 	if (!(dfs->pulses)) {
243 		dfs_free_dfs_events(dfs->events);
244 		dfs->events = NULL;
245 		return 1;
246 	}
247 
248 	dfs->pulses->pl_lastelem = DFS_MAX_PULSE_BUFFER_MASK;
249 
250 	/* Allocate memory for radar filters. */
251 	for (n = 0; n < DFS_MAX_RADAR_TYPES; n++) {
252 		dfs->dfs_radarf[n] = (struct dfs_filtertype *)
253 			qdf_mem_malloc(sizeof(struct dfs_filtertype));
254 		if (!(dfs->dfs_radarf[n]))
255 			goto bad1;
256 
257 		qdf_mem_zero(dfs->dfs_radarf[n],
258 			     sizeof(struct dfs_filtertype));
259 		status = dfs_alloc_mem_filter(dfs->dfs_radarf[n]);
260 		if (!QDF_IS_STATUS_SUCCESS(status)) {
261 			dfs_alert(dfs, WLAN_DEBUG_DFS_ALWAYS,
262 				  "mem alloc for dfs_filter failed");
263 			goto bad1;
264 		}
265 	}
266 
267 	/* Allocate memory for radar table. */
268 	dfs->dfs_ftindextable = (int8_t **)qdf_mem_malloc(
269 			DFS_NUM_FT_IDX_TBL_ROWS*sizeof(int8_t *));
270 	if (!(dfs->dfs_ftindextable))
271 		goto bad1;
272 
273 	for (n = 0; n < DFS_NUM_FT_IDX_TBL_ROWS; n++) {
274 		dfs->dfs_ftindextable[n] = qdf_mem_malloc(
275 				DFS_MAX_RADAR_OVERLAP*sizeof(int8_t));
276 		if (!(dfs->dfs_ftindextable[n]))
277 			goto bad2;
278 	}
279 
280 	dfs->dfs_use_nol = 1;
281 
282 	/* Init the cached extension channel busy for false alarm reduction */
283 	dfs->dfs_rinfo.ext_chan_busy_ts = lmac_get_tsf64(dfs->dfs_pdev_obj);
284 	dfs->dfs_rinfo.dfs_ext_chan_busy = 0;
285 	/* Init the Bin5 chirping related data */
286 	dfs->dfs_rinfo.dfs_bin5_chirp_ts = dfs->dfs_rinfo.ext_chan_busy_ts;
287 	dfs->dfs_rinfo.dfs_last_bin5_dur = MAX_BIN5_DUR;
288 	dfs->dfs_b5radars = NULL;
289 
290 	/*
291 	 * If dfs_init_radar_filters() fails, we can abort here and
292 	 * reconfigure when the first valid channel + radar config
293 	 * is available.
294 	 */
295 	if (dfs_init_radar_filters(dfs, &radar_info)) {
296 		dfs_err(dfs, WLAN_DEBUG_DFS_ALWAYS,  "Radar Filter Initialization Failed");
297 		return 1;
298 	}
299 
300 	dfs->wlan_dfs_false_rssi_thres = RSSI_POSSIBLY_FALSE;
301 	dfs->wlan_dfs_peak_mag = SEARCH_FFT_REPORT_PEAK_MAG_THRSH;
302 	dfs->dfs_phyerr_freq_min     = 0x7fffffff;
303 	dfs->dfs_phyerr_freq_max     = 0;
304 	dfs->dfs_phyerr_queued_count = 0;
305 	dfs->dfs_phyerr_w53_counter  = 0;
306 	dfs->dfs_pri_multiplier      = 2;
307 	dfs_get_radars(dfs);
308 
309 	return 0;
310 
311 bad2:
312 	qdf_mem_free(dfs->dfs_ftindextable);
313 	dfs->dfs_ftindextable = NULL;
314 bad1:
315 	for (n = 0; n < DFS_MAX_RADAR_TYPES; n++) {
316 		if (dfs->dfs_radarf[n]) {
317 			dfs_free_filter(dfs->dfs_radarf[n]);
318 			qdf_mem_free(dfs->dfs_radarf[n]);
319 			dfs->dfs_radarf[n] = NULL;
320 		}
321 	}
322 	if (dfs->pulses) {
323 		dfs_free_dfs_pulseline(dfs->pulses);
324 		dfs->pulses = NULL;
325 	}
326 	if (dfs->events) {
327 		dfs_free_dfs_events(dfs->events);
328 		dfs->events = NULL;
329 	}
330 
331 	return 1;
332 }
333 
334 void dfs_main_timer_reset(struct wlan_dfs *dfs)
335 {
336 	if (dfs->wlan_radar_tasksched) {
337 		qdf_timer_sync_cancel(&dfs->wlan_dfs_task_timer);
338 		dfs->wlan_radar_tasksched = 0;
339 	}
340 }
341 
342 void dfs_main_timer_detach(struct wlan_dfs *dfs)
343 {
344 	qdf_timer_free(&dfs->wlan_dfs_task_timer);
345 	dfs->wlan_radar_tasksched = 0;
346 }
347 
348 #if defined(WLAN_DFS_PARTIAL_OFFLOAD) && defined(HOST_DFS_SPOOF_TEST)
349 void dfs_host_wait_timer_detach(struct wlan_dfs *dfs)
350 {
351 	qdf_timer_free(&dfs->dfs_host_wait_timer);
352 }
353 #endif
354 
355 void dfs_main_detach(struct wlan_dfs *dfs)
356 {
357 	int n, empty;
358 
359 	if (!dfs->dfs_enable) {
360 		dfs_info(dfs, WLAN_DEBUG_DFS_ALWAYS, "Already detached");
361 		return;
362 	}
363 
364 	dfs->dfs_enable = 0;
365 
366 	dfs_reset_radarq(dfs);
367 	dfs_reset_alldelaylines(dfs);
368 
369 	if (dfs->pulses) {
370 		dfs_free_dfs_pulseline(dfs->pulses);
371 		dfs->pulses = NULL;
372 	}
373 
374 	for (n = 0; n < DFS_MAX_RADAR_TYPES; n++) {
375 		if (dfs->dfs_radarf[n]) {
376 			dfs_free_filter(dfs->dfs_radarf[n]);
377 			qdf_mem_free(dfs->dfs_radarf[n]);
378 			dfs->dfs_radarf[n] = NULL;
379 		}
380 	}
381 
382 	if (dfs->dfs_ftindextable) {
383 		for (n = 0; n < DFS_NUM_FT_IDX_TBL_ROWS; n++) {
384 			if (dfs->dfs_ftindextable[n]) {
385 				qdf_mem_free(dfs->dfs_ftindextable[n]);
386 				dfs->dfs_ftindextable[n] = NULL;
387 			}
388 		}
389 		qdf_mem_free(dfs->dfs_ftindextable);
390 		dfs->dfs_ftindextable = NULL;
391 		dfs->wlan_dfs_isdfsregdomain = 0;
392 	}
393 
394 	if (dfs->dfs_b5radars) {
395 		qdf_mem_free(dfs->dfs_b5radars);
396 		dfs->dfs_b5radars = NULL;
397 	}
398 
399 	dfs_reset_ar(dfs);
400 
401 	WLAN_ARQ_LOCK(dfs);
402 	empty = STAILQ_EMPTY(&(dfs->dfs_arq));
403 	WLAN_ARQ_UNLOCK(dfs);
404 	if (!empty)
405 		dfs_reset_arq(dfs);
406 
407 	if (dfs->events) {
408 		dfs_free_dfs_events(dfs->events);
409 		dfs->events = NULL;
410 	}
411 
412 	WLAN_DFS_DATA_STRUCT_LOCK_DESTROY(dfs);
413 	WLAN_DFSQ_LOCK_DESTROY(dfs);
414 	WLAN_ARQ_LOCK_DESTROY(dfs);
415 	WLAN_DFSEVENTQ_LOCK_DESTROY(dfs);
416 }
417