1 /*
2 * Copyright (c) 2016-2020 The Linux Foundation. All rights reserved.
3 * Copyright (c) 2022-2023 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 */
dfs_alloc_dfs_events(void)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 */
dfs_free_dfs_events(struct dfs_event * events)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 */
dfs_alloc_dfs_pulseline(void)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 */
dfs_free_dfs_pulseline(struct dfs_pulseline * pulses)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
dfs_alloc_dfs_events(void)81 static inline struct dfs_event *dfs_alloc_dfs_events(void)
82 {
83 return global_dfs_event;
84 }
85
dfs_free_dfs_events(struct dfs_event * events)86 static inline void dfs_free_dfs_events(struct dfs_event *events)
87 {
88 }
89
dfs_alloc_dfs_pulseline(void)90 static inline struct dfs_pulseline *dfs_alloc_dfs_pulseline(void)
91 {
92 return &global_dfs_pulseline;
93 }
94
dfs_free_dfs_pulseline(struct dfs_pulseline * pulses)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 * NB: not using kernel-doc format since the kernel-doc script doesn't
111 * handle the os_timer_func() macro
112 */
os_timer_func(dfs_task)113 static os_timer_func(dfs_task)
114 {
115 struct wlan_dfs *dfs = NULL;
116
117 OS_GET_TIMER_ARG(dfs, struct wlan_dfs *);
118
119 if (!dfs) {
120 dfs_err(dfs, WLAN_DEBUG_DFS_ALWAYS, "dfs is NULL");
121 return;
122 }
123
124 dfs_process_radarevent(dfs, dfs->dfs_curchan);
125
126 dfs->wlan_radar_tasksched = 0;
127 }
128
129 /**
130 * dfs_main_task_timer_init() - Initialize dfs task timer.
131 * @dfs: Pointer to wlan_dfs structure.
132 */
dfs_main_task_timer_init(struct wlan_dfs * dfs)133 static void dfs_main_task_timer_init(struct wlan_dfs *dfs)
134 {
135 qdf_timer_init(NULL,
136 &(dfs->wlan_dfs_task_timer),
137 dfs_task,
138 (void *)(dfs),
139 QDF_TIMER_TYPE_WAKE_APPS);
140 }
141
142 /**
143 * dfs_free_filter() - free memory allocated for dfs ft_filters
144 * @radarf: pointer holding ft_filters.
145 *
146 * Return: None
147 */
dfs_free_filter(struct dfs_filtertype * radarf)148 static void dfs_free_filter(struct dfs_filtertype *radarf)
149 {
150 uint8_t i;
151
152 for (i = 0; i < DFS_MAX_NUM_RADAR_FILTERS; i++) {
153 if (radarf->ft_filters[i]) {
154 qdf_mem_free(radarf->ft_filters[i]);
155 radarf->ft_filters[i] = NULL;
156 }
157 }
158 }
159
160 /**
161 * dfs_alloc_mem_filter() - allocate memory for dfs ft_filters
162 * @radarf: pointer holding ft_filters.
163 *
164 * Return: QDF_STATUS
165 */
dfs_alloc_mem_filter(struct dfs_filtertype * radarf)166 static QDF_STATUS dfs_alloc_mem_filter(struct dfs_filtertype *radarf)
167 {
168 uint8_t i;
169
170 for (i = 0; i < DFS_MAX_NUM_RADAR_FILTERS; i++) {
171 radarf->ft_filters[i] = qdf_mem_malloc(sizeof(struct
172 dfs_filter));
173 if (!radarf->ft_filters[i]) {
174 /* Free all the filter if malloc failed */
175 dfs_free_filter(radarf);
176 return QDF_STATUS_E_FAILURE;
177 }
178 }
179
180 return QDF_STATUS_SUCCESS;
181 }
182
dfs_main_attach(struct wlan_dfs * dfs)183 int dfs_main_attach(struct wlan_dfs *dfs)
184 {
185 int i, n;
186 QDF_STATUS status;
187 struct wlan_dfs_radar_tab_info radar_info;
188
189 if (!dfs) {
190 dfs_err(dfs, WLAN_DEBUG_DFS_ALWAYS, "dfs is NULL");
191 return 0;
192 }
193
194 /* If ignore_dfs is set to 1 then Radar detection is disabled. */
195 if (dfs->dfs_ignore_dfs) {
196 dfs_debug(dfs, WLAN_DEBUG_DFS1, "ignoring dfs");
197 return 0;
198 }
199
200 /*
201 * Zero out radar_info. It's possible that the attach function
202 * won't fetch an initial regulatory configuration; you really
203 * do want to ensure that the contents indicates there aren't
204 * any filters.
205 */
206 qdf_mem_zero(&radar_info, sizeof(radar_info));
207
208 lmac_get_caps(dfs->dfs_pdev_obj, &(dfs->dfs_caps));
209
210 dfs_clear_stats(dfs);
211 dfs->dfs_event_log_on = 1;
212 dfs_debug(dfs, WLAN_DEBUG_DFS_ALWAYS, "event log enabled by default");
213
214 dfs->dfs_enable = 1;
215
216 /*Verify : Passing NULL to qdf_timer_init().*/
217 dfs_main_task_timer_init(dfs);
218
219 dfs_allow_hw_pulses(dfs, true);
220 dfs_host_wait_timer_init(dfs);
221
222 WLAN_DFSQ_LOCK_CREATE(dfs);
223 STAILQ_INIT(&dfs->dfs_radarq);
224 WLAN_ARQ_LOCK_CREATE(dfs);
225 STAILQ_INIT(&dfs->dfs_arq);
226 STAILQ_INIT(&(dfs->dfs_eventq));
227 WLAN_DFSEVENTQ_LOCK_CREATE(dfs);
228 WLAN_DFS_DATA_STRUCT_LOCK_CREATE(dfs);
229
230 dfs->events = dfs_alloc_dfs_events();
231 if (!(dfs->events))
232 return 1;
233
234 for (i = 0; i < DFS_MAX_EVENTS; i++)
235 STAILQ_INSERT_TAIL(&(dfs->dfs_eventq), &dfs->events[i],
236 re_list);
237
238 dfs->pulses = dfs_alloc_dfs_pulseline();
239 if (!(dfs->pulses)) {
240 dfs_free_dfs_events(dfs->events);
241 dfs->events = NULL;
242 return 1;
243 }
244
245 dfs->pulses->pl_lastelem = DFS_MAX_PULSE_BUFFER_MASK;
246
247 /* Allocate memory for radar filters. */
248 for (n = 0; n < DFS_MAX_RADAR_TYPES; n++) {
249 dfs->dfs_radarf[n] = (struct dfs_filtertype *)
250 qdf_mem_malloc(sizeof(struct dfs_filtertype));
251 if (!(dfs->dfs_radarf[n]))
252 goto bad1;
253
254 qdf_mem_zero(dfs->dfs_radarf[n],
255 sizeof(struct dfs_filtertype));
256 status = dfs_alloc_mem_filter(dfs->dfs_radarf[n]);
257 if (!QDF_IS_STATUS_SUCCESS(status)) {
258 dfs_alert(dfs, WLAN_DEBUG_DFS_ALWAYS,
259 "mem alloc for dfs_filter failed");
260 goto bad1;
261 }
262 }
263
264 /* Allocate memory for radar table. */
265 dfs->dfs_ftindextable = (int8_t **)qdf_mem_malloc(
266 DFS_NUM_FT_IDX_TBL_ROWS*sizeof(int8_t *));
267 if (!(dfs->dfs_ftindextable))
268 goto bad1;
269
270 for (n = 0; n < DFS_NUM_FT_IDX_TBL_ROWS; n++) {
271 dfs->dfs_ftindextable[n] = qdf_mem_malloc(
272 DFS_MAX_RADAR_OVERLAP*sizeof(int8_t));
273 if (!(dfs->dfs_ftindextable[n]))
274 goto bad2;
275 }
276
277 dfs->dfs_use_nol = 1;
278
279 /* Init the cached extension channel busy for false alarm reduction */
280 dfs->dfs_rinfo.ext_chan_busy_ts = lmac_get_tsf64(dfs->dfs_pdev_obj);
281 dfs->dfs_rinfo.dfs_ext_chan_busy = 0;
282 /* Init the Bin5 chirping related data */
283 dfs->dfs_rinfo.dfs_bin5_chirp_ts = dfs->dfs_rinfo.ext_chan_busy_ts;
284 dfs->dfs_rinfo.dfs_last_bin5_dur = MAX_BIN5_DUR;
285 dfs->dfs_b5radars = NULL;
286
287 /*
288 * If dfs_init_radar_filters() fails, we can abort here and
289 * reconfigure when the first valid channel + radar config
290 * is available.
291 */
292 if (dfs_init_radar_filters(dfs, &radar_info)) {
293 dfs_err(dfs, WLAN_DEBUG_DFS_ALWAYS, "Radar Filter Initialization Failed");
294 return 1;
295 }
296
297 dfs->wlan_dfs_false_rssi_thres = RSSI_POSSIBLY_FALSE;
298 dfs->wlan_dfs_peak_mag = SEARCH_FFT_REPORT_PEAK_MAG_THRSH;
299 dfs->dfs_phyerr_freq_min = 0x7fffffff;
300 dfs->dfs_phyerr_freq_max = 0;
301 dfs->dfs_phyerr_queued_count = 0;
302 dfs->dfs_phyerr_w53_counter = 0;
303 dfs->dfs_pri_multiplier = 2;
304 dfs_get_radars(dfs);
305
306 return 0;
307
308 bad2:
309 qdf_mem_free(dfs->dfs_ftindextable);
310 dfs->dfs_ftindextable = NULL;
311 bad1:
312 for (n = 0; n < DFS_MAX_RADAR_TYPES; n++) {
313 if (dfs->dfs_radarf[n]) {
314 dfs_free_filter(dfs->dfs_radarf[n]);
315 qdf_mem_free(dfs->dfs_radarf[n]);
316 dfs->dfs_radarf[n] = NULL;
317 }
318 }
319 if (dfs->pulses) {
320 dfs_free_dfs_pulseline(dfs->pulses);
321 dfs->pulses = NULL;
322 }
323 if (dfs->events) {
324 dfs_free_dfs_events(dfs->events);
325 dfs->events = NULL;
326 }
327
328 return 1;
329 }
330
dfs_main_timer_reset(struct wlan_dfs * dfs)331 void dfs_main_timer_reset(struct wlan_dfs *dfs)
332 {
333 if (dfs->wlan_radar_tasksched) {
334 qdf_timer_sync_cancel(&dfs->wlan_dfs_task_timer);
335 dfs->wlan_radar_tasksched = 0;
336 }
337 }
338
dfs_main_timer_detach(struct wlan_dfs * dfs)339 void dfs_main_timer_detach(struct wlan_dfs *dfs)
340 {
341 qdf_timer_free(&dfs->wlan_dfs_task_timer);
342 dfs->wlan_radar_tasksched = 0;
343 }
344
345 #if defined(WLAN_DFS_PARTIAL_OFFLOAD) && defined(HOST_DFS_SPOOF_TEST)
dfs_host_wait_timer_detach(struct wlan_dfs * dfs)346 void dfs_host_wait_timer_detach(struct wlan_dfs *dfs)
347 {
348 qdf_timer_free(&dfs->dfs_host_wait_timer);
349 }
350 #endif
351
dfs_main_detach(struct wlan_dfs * dfs)352 void dfs_main_detach(struct wlan_dfs *dfs)
353 {
354 int n, empty;
355
356 if (!dfs->dfs_enable) {
357 dfs_info(dfs, WLAN_DEBUG_DFS_ALWAYS, "Already detached");
358 return;
359 }
360
361 dfs->dfs_enable = 0;
362
363 dfs_reset_radarq(dfs);
364 dfs_reset_alldelaylines(dfs);
365
366 if (dfs->pulses) {
367 dfs_free_dfs_pulseline(dfs->pulses);
368 dfs->pulses = NULL;
369 }
370
371 for (n = 0; n < DFS_MAX_RADAR_TYPES; n++) {
372 if (dfs->dfs_radarf[n]) {
373 dfs_free_filter(dfs->dfs_radarf[n]);
374 qdf_mem_free(dfs->dfs_radarf[n]);
375 dfs->dfs_radarf[n] = NULL;
376 }
377 }
378
379 if (dfs->dfs_ftindextable) {
380 for (n = 0; n < DFS_NUM_FT_IDX_TBL_ROWS; n++) {
381 if (dfs->dfs_ftindextable[n]) {
382 qdf_mem_free(dfs->dfs_ftindextable[n]);
383 dfs->dfs_ftindextable[n] = NULL;
384 }
385 }
386 qdf_mem_free(dfs->dfs_ftindextable);
387 dfs->dfs_ftindextable = NULL;
388 dfs->wlan_dfs_isdfsregdomain = 0;
389 }
390
391 if (dfs->dfs_b5radars) {
392 qdf_mem_free(dfs->dfs_b5radars);
393 dfs->dfs_b5radars = NULL;
394 }
395
396 dfs_reset_ar(dfs);
397
398 WLAN_ARQ_LOCK(dfs);
399 empty = STAILQ_EMPTY(&(dfs->dfs_arq));
400 WLAN_ARQ_UNLOCK(dfs);
401 if (!empty)
402 dfs_reset_arq(dfs);
403
404 if (dfs->events) {
405 dfs_free_dfs_events(dfs->events);
406 dfs->events = NULL;
407 }
408
409 WLAN_DFS_DATA_STRUCT_LOCK_DESTROY(dfs);
410 WLAN_DFSQ_LOCK_DESTROY(dfs);
411 WLAN_ARQ_LOCK_DESTROY(dfs);
412 WLAN_DFSEVENTQ_LOCK_DESTROY(dfs);
413 }
414