blob: 2d0a81a3c55ded89d7c8a68f32a095cdd2789bd2 [file] [log] [blame]
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001/*
2 * Copyright (c) 2002-2015 The Linux Foundation. All rights reserved.
3 *
4 * Previously licensed under the ISC license by Qualcomm Atheros, Inc.
5 *
6 *
7 * Permission to use, copy, modify, and/or distribute this software for
8 * any purpose with or without fee is hereby granted, provided that the
9 * above copyright notice and this permission notice appear in all
10 * copies.
11 *
12 * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL
13 * WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED
14 * WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE
15 * AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL
16 * DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR
17 * PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER
18 * TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
19 * PERFORMANCE OF THIS SOFTWARE.
20 */
21
22/*
23 * This file was originally distributed by Qualcomm Atheros, Inc.
24 * under proprietary terms before Copyright ownership was assigned
25 * to the Linux Foundation.
26 */
27
28/*===========================================================================
29
30 dfs.c
31
32 OVERVIEW:
33
34 Source code borrowed from QCA_MAIN DFS module
35
36 DEPENDENCIES:
37
38 Are listed for each API below.
39
40 ===========================================================================*/
41
42/*===========================================================================
43
44 EDIT HISTORY FOR FILE
45
46 This section contains comments describing changes made to the module.
47 Notice that changes are listed in reverse chronological order.
48
49 when who what, where, why
50 ---------- --- --------------------------------------------------------
51
52 ===========================================================================*/
53
54#include <osdep.h>
55
56#ifndef ATH_SUPPORT_DFS
57#define ATH_SUPPORT_DFS 1
58
59/* #include "if_athioctl.h" */
60/* #include "if_athvar.h" */
61#include "dfs_ioctl.h"
62#include "dfs.h"
63
64int domainoverride = DFS_UNINIT_DOMAIN;
65
66/*
67** channel switch announcement (CSA)
68** usenol=1 (default) make CSA and switch to a new channel on radar detect
69** usenol=0, make CSA with next channel same as current on radar detect
70** usenol=2, no CSA and stay on the same channel on radar detect
71**/
72
73int usenol = 1;
74uint32_t dfs_debug_level = ATH_DEBUG_DFS;
75
76#if 0 /* the code to call this is curently commented-out below */
77/*
78 * Mark a channel as having interference detected upon it.
79 *
80 * This adds the interference marker to both the primary and
81 * extension channel.
82 *
83 * XXX TODO: make the NOL and channel interference logic a bit smarter
84 * so only the channel with the radar event is marked, rather than
85 * both the primary and extension.
86 */
87static void
Chandrasekaran, Manishekar22a7e1e2015-11-05 10:38:49 +053088dfs_channel_mark_radar(struct ath_dfs *dfs, struct dfs_ieee80211_channel *chan)
Prakash Dhavali7090c5f2015-11-02 17:55:19 -080089{
90 struct ieee80211_channel_list chan_info;
91 int i;
92
93 /* chan->ic_flagext |= CHANNEL_INTERFERENCE; */
94
95 /*
96 * If radar is detected in 40MHz mode, add both the primary and the
97 * extension channels to the NOL. chan is the channel data we return
98 * to the ath_dev layer which passes it on to the 80211 layer.
99 * As we want the AP to change channels and send out a CSA,
100 * we always pass back the primary channel data to the ath_dev layer.
101 */
102 if ((dfs->dfs_rinfo.rn_use_nol == 1) &&
103 (dfs->ic->ic_opmode == IEEE80211_M_HOSTAP ||
104 dfs->ic->ic_opmode == IEEE80211_M_IBSS)) {
105 chan_info.cl_nchans = 0;
106 dfs->ic->ic_get_ext_chan_info(dfs->ic, &chan_info);
107
108 for (i = 0; i < chan_info.cl_nchans; i++) {
109 if (chan_info.cl_channels[i] == NULL) {
110 DFS_PRINTK("%s: NULL channel\n", __func__);
111 } else {
112 chan_info.cl_channels[i]->ic_flagext |=
113 CHANNEL_INTERFERENCE;
114 dfs_nol_addchan(dfs, chan_info.cl_channels[i],
115 dfs->ath_dfs_nol_timeout);
116 }
117 }
118
119 /*
120 * Update the umac/driver channels with the new NOL information.
121 */
122 dfs_nol_update(dfs);
123 }
124}
125#endif /* #if 0 */
126
127static os_timer_func(dfs_task)
128{
129 struct ieee80211com *ic;
130 struct ath_dfs *dfs = NULL;
131
132 OS_GET_TIMER_ARG(ic, struct ieee80211com *);
133 dfs = (struct ath_dfs *)ic->ic_dfs;
134 /*
135 * XXX no locking?!
136 */
137 if (dfs_process_radarevent(dfs, ic->ic_curchan)) {
138#ifndef ATH_DFS_RADAR_DETECTION_ONLY
139
140 /*
141 * This marks the channel (and the extension channel, if HT40) as
142 * having seen a radar event. It marks CHAN_INTERFERENCE and
143 * will add it to the local NOL implementation.
144 *
145 * This is only done for 'usenol=1', as the other two modes
146 * don't do radar notification or CAC/CSA/NOL; it just notes
147 * there was a radar.
148 */
149
150 if (dfs->dfs_rinfo.rn_use_nol == 1) {
151 /* dfs_channel_mark_radar(dfs, ic->ic_curchan); */
152 }
153#endif /* ATH_DFS_RADAR_DETECTION_ONLY */
154
155 /*
156 * This calls into the umac DFS code, which sets the umac related
157 * radar flags and begins the channel change machinery.
158 *
159 * XXX TODO: the umac NOL code isn't used, but IEEE80211_CHAN_RADAR
160 * still gets set. Since the umac NOL code isn't used, that flag
161 * is never cleared. This needs to be fixed. See EV 105776.
162 */
163 if (dfs->dfs_rinfo.rn_use_nol == 1) {
164 ic->ic_dfs_notify_radar(ic, ic->ic_curchan);
165 } else if (dfs->dfs_rinfo.rn_use_nol == 0) {
166 /*
167 * For the test mode, don't do a CSA here; but setup the
168 * test timer so we get a CSA _back_ to the original channel.
169 */
170 OS_CANCEL_TIMER(&dfs->ath_dfstesttimer);
171 dfs->ath_dfstest = 1;
Edhar, Mahesh Kumarb0319c42015-10-26 16:53:30 +0530172 cdf_spin_lock_bh(&ic->chan_lock);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800173 dfs->ath_dfstest_ieeechan = ic->ic_curchan->ic_ieee;
Edhar, Mahesh Kumarb0319c42015-10-26 16:53:30 +0530174 cdf_spin_unlock_bh(&ic->chan_lock);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800175 dfs->ath_dfstesttime = 1; /* 1ms */
176 OS_SET_TIMER(&dfs->ath_dfstesttimer,
177 dfs->ath_dfstesttime);
178 }
179 }
180 dfs->ath_radar_tasksched = 0;
181}
182
183static os_timer_func(dfs_testtimer_task)
184{
185 struct ieee80211com *ic;
186 struct ath_dfs *dfs = NULL;
187
188 OS_GET_TIMER_ARG(ic, struct ieee80211com *);
189 dfs = (struct ath_dfs *)ic->ic_dfs;
190
191 /* XXX no locking? */
192 dfs->ath_dfstest = 0;
193
194 /*
195 * Flip the channel back to the original channel.
196 * Make sure this is done properly with a CSA.
197 */
198 DFS_PRINTK("%s: go back to channel %d\n",
199 __func__, dfs->ath_dfstest_ieeechan);
200
201 /*
202 * XXX The mere existence of this method indirection
203 * to a umac function means this code belongs in
204 * the driver, _not_ here. Please fix this!
205 */
206 ic->ic_start_csa(ic, dfs->ath_dfstest_ieeechan);
207}
208
209static int dfs_get_debug_info(struct ieee80211com *ic, int type, void *data)
210{
211 struct ath_dfs *dfs = (struct ath_dfs *)ic->ic_dfs;
212 if (data) {
213 *(uint32_t *) data = dfs->dfs_proc_phyerr;
214 }
215 return (int)dfs->dfs_proc_phyerr;
216}
217
218int dfs_attach(struct ieee80211com *ic)
219{
220 int i, n;
221 struct ath_dfs *dfs = (struct ath_dfs *)ic->ic_dfs;
222 struct ath_dfs_radar_tab_info radar_info;
223
224 if (dfs != NULL) {
225 /*DFS_DPRINTK(dfs, ATH_DEBUG_DFS1,
226 "%s: ic_dfs was not NULL\n",
227 __func__);
228 */
229 return 1;
230 }
231
232 dfs =
233 (struct ath_dfs *)os_malloc(NULL, sizeof(struct ath_dfs),
234 GFP_ATOMIC);
235
236 if (dfs == NULL) {
237 /*DFS_DPRINTK(dfs, ATH_DEBUG_DFS1,
238 "%s: ath_dfs allocation failed\n", __func__); */
239 return 1;
240 }
241
242 OS_MEMZERO(dfs, sizeof(struct ath_dfs));
243
244 ic->ic_dfs = (void *)dfs;
245
246 dfs->ic = ic;
247
248 ic->ic_dfs_debug = dfs_get_debug_info;
249#ifndef ATH_DFS_RADAR_DETECTION_ONLY
250 dfs->dfs_nol = NULL;
251#endif
252
253 /*
254 * Zero out radar_info. It's possible that the attach function won't
255 * fetch an initial regulatory configuration; you really do want to
256 * ensure that the contents indicates there aren't any filters.
257 */
258 OS_MEMZERO(&radar_info, sizeof(radar_info));
259 ic->ic_dfs_attach(ic, &dfs->dfs_caps, &radar_info);
260 dfs_clear_stats(ic);
261 dfs->dfs_event_log_on = 0;
262 OS_INIT_TIMER(NULL, &(dfs->ath_dfs_task_timer), dfs_task, (void *)(ic),
263 CDF_TIMER_TYPE_SW);
264#ifndef ATH_DFS_RADAR_DETECTION_ONLY
265 OS_INIT_TIMER(NULL, &(dfs->ath_dfstesttimer), dfs_testtimer_task,
266 (void *)ic, CDF_TIMER_TYPE_SW);
267 dfs->ath_dfs_cac_time = ATH_DFS_WAIT_MS;
268 dfs->ath_dfstesttime = ATH_DFS_TEST_RETURN_PERIOD_MS;
269#endif
270 ATH_DFSQ_LOCK_INIT(dfs);
271 STAILQ_INIT(&dfs->dfs_radarq);
272 ATH_ARQ_LOCK_INIT(dfs);
273 STAILQ_INIT(&dfs->dfs_arq);
274 STAILQ_INIT(&(dfs->dfs_eventq));
275 ATH_DFSEVENTQ_LOCK_INIT(dfs);
276 dfs->events = (struct dfs_event *)os_malloc(NULL,
277 sizeof(struct dfs_event) *
278 DFS_MAX_EVENTS, GFP_ATOMIC);
279 if (dfs->events == NULL) {
280 OS_FREE(dfs);
281 ic->ic_dfs = NULL;
282 DFS_PRINTK("%s: events allocation failed\n", __func__);
283 return 1;
284 }
285 for (i = 0; i < DFS_MAX_EVENTS; i++) {
286 STAILQ_INSERT_TAIL(&(dfs->dfs_eventq), &dfs->events[i],
287 re_list);
288 }
289
290 dfs->pulses =
291 (struct dfs_pulseline *)os_malloc(NULL,
292 sizeof(struct dfs_pulseline),
293 GFP_ATOMIC);
294 if (dfs->pulses == NULL) {
295 OS_FREE(dfs->events);
296 dfs->events = NULL;
297 OS_FREE(dfs);
298 ic->ic_dfs = NULL;
299 DFS_PRINTK("%s: pulse buffer allocation failed\n", __func__);
300 return 1;
301 }
302
303 dfs->pulses->pl_lastelem = DFS_MAX_PULSE_BUFFER_MASK;
304
305 /* Allocate memory for radar filters */
306 for (n = 0; n < DFS_MAX_RADAR_TYPES; n++) {
307 dfs->dfs_radarf[n] =
308 (struct dfs_filtertype *)os_malloc(NULL,
309 sizeof(struct
310 dfs_filtertype),
311 GFP_ATOMIC);
312 if (dfs->dfs_radarf[n] == NULL) {
313 DFS_PRINTK
314 ("%s: cannot allocate memory for radar filter types\n",
315 __func__);
316 goto bad1;
317 }
318 OS_MEMZERO(dfs->dfs_radarf[n], sizeof(struct dfs_filtertype));
319 }
320 /* Allocate memory for radar table */
321 dfs->dfs_radartable =
322 (int8_t * *) os_malloc(NULL, 256 * sizeof(int8_t *), GFP_ATOMIC);
323 if (dfs->dfs_radartable == NULL) {
324 DFS_PRINTK("%s: cannot allocate memory for radar table\n",
325 __func__);
326 goto bad1;
327 }
328 for (n = 0; n < 256; n++) {
329 dfs->dfs_radartable[n] =
330 os_malloc(NULL, DFS_MAX_RADAR_OVERLAP * sizeof(int8_t),
331 GFP_ATOMIC);
332 if (dfs->dfs_radartable[n] == NULL) {
333 DFS_PRINTK
334 ("%s: cannot allocate memory for radar table entry\n",
335 __func__);
336 goto bad2;
337 }
338 }
339
340 if (usenol == 0)
341 DFS_PRINTK("%s: NOL disabled\n", __func__);
342 else if (usenol == 2)
343 DFS_PRINTK("%s: NOL disabled; no CSA\n", __func__);
344
345 dfs->dfs_rinfo.rn_use_nol = usenol;
346
347 /* Init the cached extension channel busy for false alarm reduction */
348 dfs->dfs_rinfo.ext_chan_busy_ts = ic->ic_get_TSF64(ic);
349 dfs->dfs_rinfo.dfs_ext_chan_busy = 0;
350 /* Init the Bin5 chirping related data */
351 dfs->dfs_rinfo.dfs_bin5_chirp_ts = dfs->dfs_rinfo.ext_chan_busy_ts;
352 dfs->dfs_rinfo.dfs_last_bin5_dur = MAX_BIN5_DUR;
353 dfs->dfs_b5radars = NULL;
354
355 /*
356 * If dfs_init_radar_filters() fails, we can abort here and
357 * reconfigure when the first valid channel + radar config
358 * is available.
359 */
360 if (dfs_init_radar_filters(ic, &radar_info)) {
361 DFS_PRINTK(" %s: Radar Filter Intialization Failed \n",
362 __func__);
363 return 1;
364 }
365
366 dfs->ath_dfs_false_rssi_thres = RSSI_POSSIBLY_FALSE;
367 dfs->ath_dfs_peak_mag = SEARCH_FFT_REPORT_PEAK_MAG_THRSH;
368 dfs->dfs_phyerr_freq_min = 0x7fffffff;
369 dfs->dfs_phyerr_freq_max = 0;
370 dfs->dfs_phyerr_queued_count = 0;
371 dfs->dfs_phyerr_w53_counter = 0;
372 dfs->dfs_pri_multiplier = 2;
373
374 dfs->ath_dfs_nol_timeout = DFS_NOL_TIMEOUT_S;
375 return 0;
376
377bad2:
378 OS_FREE(dfs->dfs_radartable);
379 dfs->dfs_radartable = NULL;
380bad1:
381 for (n = 0; n < DFS_MAX_RADAR_TYPES; n++) {
382 if (dfs->dfs_radarf[n] != NULL) {
383 OS_FREE(dfs->dfs_radarf[n]);
384 dfs->dfs_radarf[n] = NULL;
385 }
386 }
387 if (dfs->pulses) {
388 OS_FREE(dfs->pulses);
389 dfs->pulses = NULL;
390 }
391 if (dfs->events) {
392 OS_FREE(dfs->events);
393 dfs->events = NULL;
394 }
395
396 if (ic->ic_dfs) {
397 OS_FREE(ic->ic_dfs);
398 ic->ic_dfs = NULL;
399 }
400 return 1;
401#undef N
402}
403
404void dfs_detach(struct ieee80211com *ic)
405{
406 struct ath_dfs *dfs = (struct ath_dfs *)ic->ic_dfs;
407 int n, empty;
408
409 if (dfs == NULL) {
410 DFS_DPRINTK(dfs, ATH_DEBUG_DFS1, "%s: ic_dfs is NULL\n",
411 __func__);
412 return;
413 }
414
415 /* Bug 29099 make sure all outstanding timers are cancelled */
416
417 if (dfs->ath_radar_tasksched) {
418 OS_CANCEL_TIMER(&dfs->ath_dfs_task_timer);
419 dfs->ath_radar_tasksched = 0;
420 }
421
422 if (dfs->ath_dfstest) {
423 OS_CANCEL_TIMER(&dfs->ath_dfstesttimer);
424 dfs->ath_dfstest = 0;
425 }
426#if 0
427#ifndef ATH_DFS_RADAR_DETECTION_ONLY
428 if (dfs->ic_dfswait) {
429 OS_CANCEL_TIMER(&dfs->ic_dfswaittimer);
430 dfs->ath_dfswait = 0;
431 }
432
433 OS_CANCEL_TIMER(&dfs->sc_dfs_war_timer);
434 if (dfs->dfs_nol != NULL) {
435 struct dfs_nolelem *nol, *next;
436 nol = dfs->dfs_nol;
437 /* Bug 29099 - each NOL element has its own timer, cancel it and
438 free the element */
439 while (nol != NULL) {
440 OS_CANCEL_TIMER(&nol->nol_timer);
441 next = nol->nol_next;
442 OS_FREE(nol);
443 nol = next;
444 }
445 dfs->dfs_nol = NULL;
446 }
447#endif
448#endif
449 /* Return radar events to free q */
450 dfs_reset_radarq(dfs);
451 dfs_reset_alldelaylines(dfs);
452
453 /* Free up pulse log */
454 if (dfs->pulses != NULL) {
455 OS_FREE(dfs->pulses);
456 dfs->pulses = NULL;
457 }
458
459 for (n = 0; n < DFS_MAX_RADAR_TYPES; n++) {
460 if (dfs->dfs_radarf[n] != NULL) {
461 OS_FREE(dfs->dfs_radarf[n]);
462 dfs->dfs_radarf[n] = NULL;
463 }
464 }
465
466 if (dfs->dfs_radartable != NULL) {
467 for (n = 0; n < 256; n++) {
468 if (dfs->dfs_radartable[n] != NULL) {
469 OS_FREE(dfs->dfs_radartable[n]);
470 dfs->dfs_radartable[n] = NULL;
471 }
472 }
473 OS_FREE(dfs->dfs_radartable);
474 dfs->dfs_radartable = NULL;
475#ifndef ATH_DFS_RADAR_DETECTION_ONLY
476 dfs->ath_dfs_isdfsregdomain = 0;
477#endif
478 }
479
480 if (dfs->dfs_b5radars != NULL) {
481 OS_FREE(dfs->dfs_b5radars);
482 dfs->dfs_b5radars = NULL;
483 }
484
485/* Commenting out since all the ar functions are obsolete and
486 * the function definition has been removed as part of dfs_ar.c
487 * dfs_reset_ar(dfs);
488 */
489 ATH_ARQ_LOCK(dfs);
490 empty = STAILQ_EMPTY(&(dfs->dfs_arq));
491 ATH_ARQ_UNLOCK(dfs);
492 if (!empty) {
493/*
494 * Commenting out since all the ar functions are obsolete and
495 * the function definition has been removed as part of dfs_ar.c
496 *
497 * dfs_reset_arq(dfs);
498 */
499 }
500 if (dfs->events != NULL) {
501 OS_FREE(dfs->events);
502 dfs->events = NULL;
503 }
504 dfs_nol_timer_cleanup(dfs);
505 OS_FREE(dfs);
506
507 /* XXX? */
508 ic->ic_dfs = NULL;
509}
510
511/*
512 * This is called each time a channel change occurs, to (potentially) enable
513 * the radar code.
514 */
515int dfs_radar_disable(struct ieee80211com *ic)
516{
517 struct ath_dfs *dfs = (struct ath_dfs *)ic->ic_dfs;
518#ifdef ATH_ENABLE_AR
519 dfs->dfs_proc_phyerr &= ~DFS_AR_EN;
520#endif
521 dfs->dfs_proc_phyerr &= ~DFS_RADAR_EN;
522 return 0;
523}
524
525/*
526 * This is called each time a channel change occurs, to (potentially) enable
527 * the radar code.
528 */
529int dfs_radar_enable(struct ieee80211com *ic,
530 struct ath_dfs_radar_tab_info *radar_info)
531{
532 int is_ext_ch;
533 int is_fastclk = 0;
534 int radar_filters_init_status = 0;
535 /* uint32_t rfilt; */
536 struct ath_dfs *dfs;
537 struct dfs_state *rs_pri, *rs_ext;
Chandrasekaran, Manishekar22a7e1e2015-11-05 10:38:49 +0530538 struct dfs_ieee80211_channel *chan = ic->ic_curchan, *ext_ch = NULL;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800539 is_ext_ch = IEEE80211_IS_CHAN_11N_HT40(ic->ic_curchan);
540 dfs = (struct ath_dfs *)ic->ic_dfs;
541 rs_pri = NULL;
542 rs_ext = NULL;
543#if 0
544 int i;
545#endif
546 if (dfs == NULL) {
547 DFS_DPRINTK(dfs, ATH_DEBUG_DFS, "%s: ic_dfs is NULL\n",
548 __func__);
549
550 return -EIO;
551 }
552 ic->ic_dfs_disable(ic);
553
554 /*
555 * Setting country code might change the DFS domain
556 * so initialize the DFS Radar filters
557 */
558 radar_filters_init_status = dfs_init_radar_filters(ic, radar_info);
559
560 /*
561 * dfs_init_radar_filters() returns 1 on failure and
562 * 0 on success.
563 */
564 if (DFS_STATUS_FAIL == radar_filters_init_status) {
565 CDF_TRACE(CDF_MODULE_ID_SAP, CDF_TRACE_LEVEL_ERROR,
566 "%s[%d]: DFS Radar Filters Initialization Failed",
567 __func__, __LINE__);
568 return -EIO;
569 }
570
571 if ((ic->ic_opmode == IEEE80211_M_HOSTAP
572 || ic->ic_opmode == IEEE80211_M_IBSS)) {
573
574 if (IEEE80211_IS_CHAN_DFS(chan)) {
575
576 uint8_t index_pri, index_ext;
577#ifdef ATH_ENABLE_AR
578 dfs->dfs_proc_phyerr |= DFS_AR_EN;
579#endif
580 dfs->dfs_proc_phyerr |= DFS_RADAR_EN;
581
582 if (is_ext_ch) {
583 ext_ch = ieee80211_get_extchan(ic);
584 }
585 dfs_reset_alldelaylines(dfs);
586
587 rs_pri = dfs_getchanstate(dfs, &index_pri, 0);
588 if (ext_ch) {
589 rs_ext = dfs_getchanstate(dfs, &index_ext, 1);
590 }
591 if (rs_pri != NULL
592 && ((ext_ch == NULL) || (rs_ext != NULL))) {
593 struct ath_dfs_phyerr_param pe;
594
595 OS_MEMSET(&pe, '\0', sizeof(pe));
596
597 if (index_pri != dfs->dfs_curchan_radindex)
598 dfs_reset_alldelaylines(dfs);
599
600 dfs->dfs_curchan_radindex = (int16_t) index_pri;
601 dfs->dfs_pri_multiplier_ini =
602 radar_info->dfs_pri_multiplier;
603
604 if (rs_ext)
605 dfs->dfs_extchan_radindex =
606 (int16_t) index_ext;
607
608 ath_dfs_phyerr_param_copy(&pe,
609 &rs_pri->rs_param);
610 DFS_DPRINTK(dfs, ATH_DEBUG_DFS3,
611 "%s: firpwr=%d, rssi=%d, height=%d, "
612 "prssi=%d, inband=%d, relpwr=%d, "
613 "relstep=%d, maxlen=%d\n",
614 __func__,
615 pe.pe_firpwr,
616 pe.pe_rrssi,
617 pe.pe_height,
618 pe.pe_prssi,
619 pe.pe_inband,
620 pe.pe_relpwr,
621 pe.pe_relstep, pe.pe_maxlen);
622
623 ic->ic_dfs_enable(ic, &is_fastclk, &pe);
624 DFS_DPRINTK(dfs, ATH_DEBUG_DFS,
625 "Enabled radar detection on channel %d\n",
626 chan->ic_freq);
627 dfs->dur_multiplier =
628 is_fastclk ? DFS_FAST_CLOCK_MULTIPLIER :
629 DFS_NO_FAST_CLOCK_MULTIPLIER;
630 DFS_DPRINTK(dfs, ATH_DEBUG_DFS3,
631 "%s: duration multiplier is %d\n",
632 __func__, dfs->dur_multiplier);
633 } else
634 DFS_DPRINTK(dfs, ATH_DEBUG_DFS,
635 "%s: No more radar states left\n",
636 __func__);
637 }
638 }
639
640 return DFS_STATUS_SUCCESS;
641}
642
643int
644dfs_control(struct ieee80211com *ic, u_int id,
645 void *indata, uint32_t insize, void *outdata, uint32_t *outsize)
646{
647 int error = 0;
648 struct ath_dfs_phyerr_param peout;
649 struct ath_dfs *dfs = (struct ath_dfs *)ic->ic_dfs;
650 struct dfs_ioctl_params *dfsparams;
651 uint32_t val = 0;
652#ifndef ATH_DFS_RADAR_DETECTION_ONLY
653 struct dfsreq_nolinfo *nol;
654 uint32_t *data = NULL;
655#endif /* ATH_DFS_RADAR_DETECTION_ONLY */
656 int i;
657
658 if (dfs == NULL) {
659 error = -EINVAL;
660 DFS_DPRINTK(dfs, ATH_DEBUG_DFS1, "%s DFS is null\n", __func__);
661 goto bad;
662 }
663
664 switch (id) {
665 case DFS_SET_THRESH:
666 if (insize < sizeof(struct dfs_ioctl_params) || !indata) {
667 DFS_DPRINTK(dfs, ATH_DEBUG_DFS1,
668 "%s: insize=%d, expected=%zu bytes, indata=%p\n",
669 __func__, insize,
670 sizeof(struct dfs_ioctl_params), indata);
671 error = -EINVAL;
672 break;
673 }
674 dfsparams = (struct dfs_ioctl_params *)indata;
675 if (!dfs_set_thresholds
676 (ic, DFS_PARAM_FIRPWR, dfsparams->dfs_firpwr))
677 error = -EINVAL;
678 if (!dfs_set_thresholds
679 (ic, DFS_PARAM_RRSSI, dfsparams->dfs_rrssi))
680 error = -EINVAL;
681 if (!dfs_set_thresholds
682 (ic, DFS_PARAM_HEIGHT, dfsparams->dfs_height))
683 error = -EINVAL;
684 if (!dfs_set_thresholds
685 (ic, DFS_PARAM_PRSSI, dfsparams->dfs_prssi))
686 error = -EINVAL;
687 if (!dfs_set_thresholds
688 (ic, DFS_PARAM_INBAND, dfsparams->dfs_inband))
689 error = -EINVAL;
690 /* 5413 speicfic */
691 if (!dfs_set_thresholds
692 (ic, DFS_PARAM_RELPWR, dfsparams->dfs_relpwr))
693 error = -EINVAL;
694 if (!dfs_set_thresholds
695 (ic, DFS_PARAM_RELSTEP, dfsparams->dfs_relstep))
696 error = -EINVAL;
697 if (!dfs_set_thresholds
698 (ic, DFS_PARAM_MAXLEN, dfsparams->dfs_maxlen))
699 error = -EINVAL;
700 break;
701 case DFS_GET_THRESH:
702 if (!outdata || !outsize
703 || *outsize < sizeof(struct dfs_ioctl_params)) {
704 error = -EINVAL;
705 break;
706 }
707 *outsize = sizeof(struct dfs_ioctl_params);
708 dfsparams = (struct dfs_ioctl_params *)outdata;
709
710 /*
711 * Fetch the DFS thresholds using the internal representation.
712 */
713 (void)dfs_get_thresholds(ic, &peout);
714
715 /*
716 * Convert them to the dfs IOCTL representation.
717 */
718 ath_dfs_dfsparam_to_ioctlparam(&peout, dfsparams);
719 break;
720 case DFS_RADARDETECTS:
721 if (!outdata || !outsize || *outsize < sizeof(uint32_t)) {
722 error = -EINVAL;
723 break;
724 }
725 *outsize = sizeof(uint32_t);
726 *((uint32_t *) outdata) = dfs->ath_dfs_stats.num_radar_detects;
727 break;
728 case DFS_DISABLE_DETECT:
729 dfs->dfs_proc_phyerr &= ~DFS_RADAR_EN;
730 dfs->ic->ic_dfs_state.ignore_dfs = 1;
731 DFS_PRINTK("%s enable detects, ignore_dfs %d\n",
732 __func__, dfs->ic->ic_dfs_state.ignore_dfs);
733 break;
734 case DFS_ENABLE_DETECT:
735 dfs->dfs_proc_phyerr |= DFS_RADAR_EN;
736 dfs->ic->ic_dfs_state.ignore_dfs = 0;
737 DFS_PRINTK("%s enable detects, ignore_dfs %d\n",
738 __func__, dfs->ic->ic_dfs_state.ignore_dfs);
739 break;
740 case DFS_DISABLE_FFT:
741 /* UMACDFS: TODO: val = ath_hal_dfs_config_fft(sc->sc_ah, false); */
742 DFS_PRINTK("%s TODO disable FFT val=0x%x \n", __func__, val);
743 break;
744 case DFS_ENABLE_FFT:
745 /* UMACDFS TODO: val = ath_hal_dfs_config_fft(sc->sc_ah, true); */
746 DFS_PRINTK("%s TODO enable FFT val=0x%x \n", __func__, val);
747 break;
748 case DFS_SET_DEBUG_LEVEL:
749 if (insize < sizeof(uint32_t) || !indata) {
750 error = -EINVAL;
751 break;
752 }
753 dfs->dfs_debug_mask = *(uint32_t *) indata;
754 DFS_PRINTK("%s debug level now = 0x%x \n",
755 __func__, dfs->dfs_debug_mask);
756 if (dfs->dfs_debug_mask & ATH_DEBUG_DFS3) {
757 /* Enable debug Radar Event */
758 dfs->dfs_event_log_on = 1;
759 } else {
760 dfs->dfs_event_log_on = 0;
761 }
762 break;
763 case DFS_SET_FALSE_RSSI_THRES:
764 if (insize < sizeof(uint32_t) || !indata) {
765 error = -EINVAL;
766 break;
767 }
768 dfs->ath_dfs_false_rssi_thres = *(uint32_t *) indata;
769 DFS_PRINTK("%s false RSSI threshold now = 0x%x \n",
770 __func__, dfs->ath_dfs_false_rssi_thres);
771 break;
772 case DFS_SET_PEAK_MAG:
773 if (insize < sizeof(uint32_t) || !indata) {
774 error = -EINVAL;
775 break;
776 }
777 dfs->ath_dfs_peak_mag = *(uint32_t *) indata;
778 DFS_PRINTK("%s peak_mag now = 0x%x \n",
779 __func__, dfs->ath_dfs_peak_mag);
780 break;
781 case DFS_IGNORE_CAC:
782 if (insize < sizeof(uint32_t) || !indata) {
783 error = -EINVAL;
784 break;
785 }
786 if (*(uint32_t *) indata) {
787 dfs->ic->ic_dfs_state.ignore_cac = 1;
788 } else {
789 dfs->ic->ic_dfs_state.ignore_cac = 0;
790 }
791 DFS_PRINTK("%s ignore cac = 0x%x \n",
792 __func__, dfs->ic->ic_dfs_state.ignore_cac);
793 break;
794 case DFS_SET_NOL_TIMEOUT:
795 if (insize < sizeof(uint32_t) || !indata) {
796 error = -EINVAL;
797 break;
798 }
799 if (*(int *)indata) {
800 dfs->ath_dfs_nol_timeout = *(int *)indata;
801 } else {
802 dfs->ath_dfs_nol_timeout = DFS_NOL_TIMEOUT_S;
803 }
804 DFS_PRINTK("%s nol timeout = %d sec \n",
805 __func__, dfs->ath_dfs_nol_timeout);
806 break;
807#ifndef ATH_DFS_RADAR_DETECTION_ONLY
808 case DFS_MUTE_TIME:
809 if (insize < sizeof(uint32_t) || !indata) {
810 error = -EINVAL;
811 break;
812 }
813 data = (uint32_t *) indata;
814 dfs->ath_dfstesttime = *data;
815 dfs->ath_dfstesttime *= (1000); /* convert sec into ms */
816 break;
817 case DFS_GET_USENOL:
818 if (!outdata || !outsize || *outsize < sizeof(uint32_t)) {
819 error = -EINVAL;
820 break;
821 }
822 *outsize = sizeof(uint32_t);
823 *((uint32_t *) outdata) = dfs->dfs_rinfo.rn_use_nol;
824
825 for (i = 0;
826 (i < DFS_EVENT_LOG_SIZE) && (i < dfs->dfs_event_log_count);
827 i++) {
828 /* DFS_DPRINTK(sc, ATH_DEBUG_DFS,"ts=%llu diff_ts=%u rssi=%u dur=%u\n", dfs->radar_log[i].ts, dfs->radar_log[i].diff_ts, dfs->radar_log[i].rssi, dfs->radar_log[i].dur); */
829
830 }
831 dfs->dfs_event_log_count = 0;
832 dfs->dfs_phyerr_count = 0;
833 dfs->dfs_phyerr_reject_count = 0;
834 dfs->dfs_phyerr_queued_count = 0;
835 dfs->dfs_phyerr_freq_min = 0x7fffffff;
836 dfs->dfs_phyerr_freq_max = 0;
837 break;
838 case DFS_SET_USENOL:
839 if (insize < sizeof(uint32_t) || !indata) {
840 error = -EINVAL;
841 break;
842 }
843 dfs->dfs_rinfo.rn_use_nol = *(uint32_t *) indata;
844 /* iwpriv markdfs in linux can do the same thing... */
845 break;
846 case DFS_GET_NOL:
847 if (!outdata || !outsize
848 || *outsize < sizeof(struct dfsreq_nolinfo)) {
849 error = -EINVAL;
850 break;
851 }
852 *outsize = sizeof(struct dfsreq_nolinfo);
853 nol = (struct dfsreq_nolinfo *)outdata;
854 dfs_get_nol(dfs, (struct dfsreq_nolelem *)nol->dfs_nol,
855 &nol->ic_nchans);
856 dfs_print_nol(dfs);
857 break;
858 case DFS_SET_NOL:
859 if (insize < sizeof(struct dfsreq_nolinfo) || !indata) {
860 error = -EINVAL;
861 break;
862 }
863 nol = (struct dfsreq_nolinfo *)indata;
864 dfs_set_nol(dfs, (struct dfsreq_nolelem *)nol->dfs_nol,
865 nol->ic_nchans);
866 break;
867
868 case DFS_SHOW_NOL:
869 dfs_print_nol(dfs);
870 break;
871 case DFS_BANGRADAR:
872#if 0 /* MERGE_TBD */
873 if (sc->sc_nostabeacons) {
874 printk("No radar detection Enabled \n");
875 break;
876 }
877#endif
878 dfs->dfs_bangradar = 1;
879 dfs->ath_radar_tasksched = 1;
880 OS_SET_TIMER(&dfs->ath_dfs_task_timer, 0);
881 break;
882#endif /* ATH_DFS_RADAR_DETECTION_ONLY */
883 default:
884 error = -EINVAL;
885 }
886bad:
887 return error;
888}
889
890int
891dfs_set_thresholds(struct ieee80211com *ic, const uint32_t threshtype,
892 const uint32_t value)
893{
894 struct ath_dfs *dfs = (struct ath_dfs *)ic->ic_dfs;
895 int16_t chanindex;
896 struct dfs_state *rs;
897 struct ath_dfs_phyerr_param pe;
898 int is_fastclk = 0; /* XXX throw-away */
899
900 if (dfs == NULL) {
901 DFS_DPRINTK(dfs, ATH_DEBUG_DFS1, "%s: ic_dfs is NULL\n",
902 __func__);
903 return 0;
904 }
905
906 chanindex = dfs->dfs_curchan_radindex;
907 if ((chanindex < 0) || (chanindex >= DFS_NUM_RADAR_STATES)) {
908 DFS_DPRINTK(dfs, ATH_DEBUG_DFS1,
909 "%s: chanindex = %d, DFS_NUM_RADAR_STATES=%d\n",
910 __func__, chanindex, DFS_NUM_RADAR_STATES);
911 return 0;
912 }
913
914 DFS_DPRINTK(dfs, ATH_DEBUG_DFS,
915 "%s: threshtype=%d, value=%d\n", __func__, threshtype,
916 value);
917
918 ath_dfs_phyerr_init_noval(&pe);
919
920 rs = &(dfs->dfs_radar[chanindex]);
921 switch (threshtype) {
922 case DFS_PARAM_FIRPWR:
923 rs->rs_param.pe_firpwr = (int32_t) value;
924 pe.pe_firpwr = value;
925 break;
926 case DFS_PARAM_RRSSI:
927 rs->rs_param.pe_rrssi = value;
928 pe.pe_rrssi = value;
929 break;
930 case DFS_PARAM_HEIGHT:
931 rs->rs_param.pe_height = value;
932 pe.pe_height = value;
933 break;
934 case DFS_PARAM_PRSSI:
935 rs->rs_param.pe_prssi = value;
936 pe.pe_prssi = value;
937 break;
938 case DFS_PARAM_INBAND:
939 rs->rs_param.pe_inband = value;
940 pe.pe_inband = value;
941 break;
942 /* 5413 specific */
943 case DFS_PARAM_RELPWR:
944 rs->rs_param.pe_relpwr = value;
945 pe.pe_relpwr = value;
946 break;
947 case DFS_PARAM_RELSTEP:
948 rs->rs_param.pe_relstep = value;
949 pe.pe_relstep = value;
950 break;
951 case DFS_PARAM_MAXLEN:
952 rs->rs_param.pe_maxlen = value;
953 pe.pe_maxlen = value;
954 break;
955 default:
956 DFS_DPRINTK(dfs, ATH_DEBUG_DFS1,
957 "%s: unknown threshtype (%d)\n",
958 __func__, threshtype);
959 break;
960 }
961
962 /*
963 * The driver layer dfs_enable routine is tasked with translating
964 * values from the global format to the per-device (HAL, offload)
965 * format.
966 */
967 ic->ic_dfs_enable(ic, &is_fastclk, &pe);
968 return 1;
969}
970
971int
972dfs_get_thresholds(struct ieee80211com *ic, struct ath_dfs_phyerr_param *param)
973{
974 /* UMACDFS : TODO:ath_hal_getdfsthresh(sc->sc_ah, param); */
975
976 OS_MEMZERO(param, sizeof(*param));
977
978 (void)ic->ic_dfs_get_thresholds(ic, param);
979
980 return 1;
981}
982
983uint16_t dfs_usenol(struct ieee80211com *ic)
984{
985 struct ath_dfs *dfs = (struct ath_dfs *)ic->ic_dfs;
986 return dfs ? (uint16_t) dfs->dfs_rinfo.rn_use_nol : 0;
987}
988
989uint16_t dfs_isdfsregdomain(struct ieee80211com *ic)
990{
991 struct ath_dfs *dfs = (struct ath_dfs *)ic->ic_dfs;
992 return dfs ? dfs->dfsdomain : 0;
993}
994
995#endif /* ATH_UPPORT_DFS */