2 ******************************************************************************
6 * @brief Functions to handle radar detection
7 * Radar detection is copied (and adapted) from ath driver source code.
9 * Copyright (c) 2012 Neratec Solutions AG
10 * Copyright (C) ESWIN 2015-2020
12 ******************************************************************************
14 #include <linux/list.h>
15 #include <linux/kernel.h>
16 #include <linux/ktime.h>
17 #include <net/mac80211.h>
19 #include "ecrnx_radar.h"
20 #include "ecrnx_defs.h"
21 #include "ecrnx_msg_tx.h"
22 #include "ecrnx_events.h"
23 #include "ecrnx_compat.h"
26 * tolerated deviation of radar time stamp in usecs on both sides
27 * TODO: this might need to be HW-dependent
29 #define PRI_TOLERANCE 16
32 * struct radar_types - contains array of patterns defined for one DFS domain
33 * @domain: DFS regulatory domain
34 * @num_radar_types: number of radar types to follow
35 * @radar_types: radar types array
38 enum nl80211_dfs_regions region;
40 const struct radar_detector_specs *spec_riu;
41 const struct radar_detector_specs *spec_fcu;
45 * Type of radar waveform:
46 * RADAR_WAVEFORM_SHORT : waveform defined by
48 * - pulse interval in a burst (pri)
49 * - number of pulses in a burst (ppb)
51 * RADAR_WAVEFORM_WEATHER :
52 * same than SHORT except that ppb is dependent of pri
54 * RADAR_WAVEFORM_INTERLEAVED :
55 * same than SHORT except there are several value of pri (interleaved)
57 * RADAR_WAVEFORM_LONG :
60 enum radar_waveform_type {
62 RADAR_WAVEFORM_WEATHER,
63 RADAR_WAVEFORM_INTERLEAVED,
68 * struct radar_detector_specs - detector specs for a radar pattern type
69 * @type_id: pattern type, as defined by regulatory
70 * @width_min: minimum radar pulse width in [us]
71 * @width_max: maximum radar pulse width in [us]
72 * @pri_min: minimum pulse repetition interval in [us] (including tolerance)
73 * @pri_max: minimum pri in [us] (including tolerance)
74 * @num_pri: maximum number of different pri for this type
75 * @ppb: pulses per bursts for this type
76 * @ppb_thresh: number of pulses required to trigger detection
77 * @max_pri_tolerance: pulse time stamp tolerance on both sides [us]
78 * @type: Type of radar waveform
80 struct radar_detector_specs {
90 enum radar_waveform_type type;
94 /* percentage on ppb threshold to trigger detection */
95 #define MIN_PPB_THRESH 50
96 #define PPB_THRESH(PPB) ((PPB * MIN_PPB_THRESH + 50) / 100)
97 #define PRF2PRI(PRF) ((1000000 + PRF / 2) / PRF)
100 #define WIDTH_TOLERANCE 2
101 #define WIDTH_LOWER(X) (X)
102 #define WIDTH_UPPER(X) (X)
104 #define ETSI_PATTERN_SHORT(ID, WMIN, WMAX, PMIN, PMAX, PPB) \
106 ID, WIDTH_LOWER(WMIN), WIDTH_UPPER(WMAX), \
107 (PRF2PRI(PMAX) - PRI_TOLERANCE), \
108 (PRF2PRI(PMIN) + PRI_TOLERANCE), 1, PPB, \
109 PPB_THRESH(PPB), PRI_TOLERANCE, RADAR_WAVEFORM_SHORT \
112 #define ETSI_PATTERN_INTERLEAVED(ID, WMIN, WMAX, PMIN, PMAX, PRFMIN, PRFMAX, PPB) \
114 ID, WIDTH_LOWER(WMIN), WIDTH_UPPER(WMAX), \
115 (PRF2PRI(PMAX) * PRFMIN- PRI_TOLERANCE), \
116 (PRF2PRI(PMIN) * PRFMAX + PRI_TOLERANCE), \
117 PRFMAX, PPB * PRFMAX, \
118 PPB_THRESH(PPB), PRI_TOLERANCE, RADAR_WAVEFORM_INTERLEAVED \
121 /* radar types as defined by ETSI EN-301-893 v1.7.1 */
122 static const struct radar_detector_specs etsi_radar_ref_types_v17_riu[] = {
123 ETSI_PATTERN_SHORT(0, 0, 8, 700, 700, 18),
124 ETSI_PATTERN_SHORT(1, 0, 10, 200, 1000, 10),
125 ETSI_PATTERN_SHORT(2, 0, 22, 200, 1600, 15),
126 ETSI_PATTERN_SHORT(3, 0, 22, 2300, 4000, 25),
127 ETSI_PATTERN_SHORT(4, 20, 38, 2000, 4000, 20),
128 ETSI_PATTERN_INTERLEAVED(5, 0, 8, 300, 400, 2, 3, 10),
129 ETSI_PATTERN_INTERLEAVED(6, 0, 8, 400, 1200, 2, 3, 15),
132 static const struct radar_detector_specs etsi_radar_ref_types_v17_fcu[] = {
133 ETSI_PATTERN_SHORT(0, 0, 8, 700, 700, 18),
134 ETSI_PATTERN_SHORT(1, 0, 8, 200, 1000, 10),
135 ETSI_PATTERN_SHORT(2, 0, 16, 200, 1600, 15),
136 ETSI_PATTERN_SHORT(3, 0, 16, 2300, 4000, 25),
137 ETSI_PATTERN_SHORT(4, 20, 34, 2000, 4000, 20),
138 ETSI_PATTERN_INTERLEAVED(5, 0, 8, 300, 400, 2, 3, 10),
139 ETSI_PATTERN_INTERLEAVED(6, 0, 8, 400, 1200, 2, 3, 15),
142 static const struct radar_types etsi_radar_types_v17 = {
143 .region = NL80211_DFS_ETSI,
144 .num_radar_types = ARRAY_SIZE(etsi_radar_ref_types_v17_riu),
145 .spec_riu = etsi_radar_ref_types_v17_riu,
146 .spec_fcu = etsi_radar_ref_types_v17_fcu,
149 #define FCC_PATTERN(ID, WMIN, WMAX, PMIN, PMAX, PRF, PPB, TYPE) \
151 ID, WIDTH_LOWER(WMIN), WIDTH_UPPER(WMAX), \
152 PMIN - PRI_TOLERANCE, \
153 PMAX * PRF + PRI_TOLERANCE, PRF, PPB * PRF, \
154 PPB_THRESH(PPB), PRI_TOLERANCE, TYPE \
157 static const struct radar_detector_specs fcc_radar_ref_types_riu[] = {
158 FCC_PATTERN(0, 0, 8, 1428, 1428, 1, 18, RADAR_WAVEFORM_SHORT),
159 FCC_PATTERN(1, 0, 8, 518, 3066, 1, 102, RADAR_WAVEFORM_WEATHER),
160 FCC_PATTERN(2, 0, 8, 150, 230, 1, 23, RADAR_WAVEFORM_SHORT),
161 FCC_PATTERN(3, 6, 20, 200, 500, 1, 16, RADAR_WAVEFORM_SHORT),
162 FCC_PATTERN(4, 10, 28, 200, 500, 1, 12, RADAR_WAVEFORM_SHORT),
163 FCC_PATTERN(5, 50, 110, 1000, 2000, 1, 8, RADAR_WAVEFORM_LONG),
164 FCC_PATTERN(6, 0, 8, 333, 333, 1, 9, RADAR_WAVEFORM_SHORT),
167 static const struct radar_detector_specs fcc_radar_ref_types_fcu[] = {
168 FCC_PATTERN(0, 0, 8, 1428, 1428, 1, 18, RADAR_WAVEFORM_SHORT),
169 FCC_PATTERN(1, 0, 8, 518, 3066, 1, 102, RADAR_WAVEFORM_WEATHER),
170 FCC_PATTERN(2, 0, 8, 150, 230, 1, 23, RADAR_WAVEFORM_SHORT),
171 FCC_PATTERN(3, 6, 12, 200, 500, 1, 16, RADAR_WAVEFORM_SHORT),
172 FCC_PATTERN(4, 10, 22, 200, 500, 1, 12, RADAR_WAVEFORM_SHORT),
173 FCC_PATTERN(5, 50, 104, 1000, 2000, 1, 8, RADAR_WAVEFORM_LONG),
174 FCC_PATTERN(6, 0, 8, 333, 333, 1, 9, RADAR_WAVEFORM_SHORT),
177 static const struct radar_types fcc_radar_types = {
178 .region = NL80211_DFS_FCC,
179 .num_radar_types = ARRAY_SIZE(fcc_radar_ref_types_riu),
180 .spec_riu = fcc_radar_ref_types_riu,
181 .spec_fcu = fcc_radar_ref_types_fcu,
184 #define JP_PATTERN FCC_PATTERN
185 static const struct radar_detector_specs jp_radar_ref_types_riu[] = {
186 JP_PATTERN(0, 0, 8, 1428, 1428, 1, 18, RADAR_WAVEFORM_SHORT),
187 JP_PATTERN(1, 2, 8, 3846, 3846, 1, 18, RADAR_WAVEFORM_SHORT),
188 JP_PATTERN(2, 0, 8, 1388, 1388, 1, 18, RADAR_WAVEFORM_SHORT),
189 JP_PATTERN(3, 0, 8, 4000, 4000, 1, 18, RADAR_WAVEFORM_SHORT),
190 JP_PATTERN(4, 0, 8, 150, 230, 1, 23, RADAR_WAVEFORM_SHORT),
191 JP_PATTERN(5, 6, 20, 200, 500, 1, 16, RADAR_WAVEFORM_SHORT),
192 JP_PATTERN(6, 10, 28, 200, 500, 1, 12, RADAR_WAVEFORM_SHORT),
193 JP_PATTERN(7, 50, 110, 1000, 2000, 1, 8, RADAR_WAVEFORM_LONG),
194 JP_PATTERN(8, 0, 8, 333, 333, 1, 9, RADAR_WAVEFORM_SHORT),
197 static const struct radar_detector_specs jp_radar_ref_types_fcu[] = {
198 JP_PATTERN(0, 0, 8, 1428, 1428, 1, 18, RADAR_WAVEFORM_SHORT),
199 JP_PATTERN(1, 2, 6, 3846, 3846, 1, 18, RADAR_WAVEFORM_SHORT),
200 JP_PATTERN(2, 0, 8, 1388, 1388, 1, 18, RADAR_WAVEFORM_SHORT),
201 JP_PATTERN(3, 2, 2, 4000, 4000, 1, 18, RADAR_WAVEFORM_SHORT),
202 JP_PATTERN(4, 0, 8, 150, 230, 1, 23, RADAR_WAVEFORM_SHORT),
203 JP_PATTERN(5, 6, 12, 200, 500, 1, 16, RADAR_WAVEFORM_SHORT),
204 JP_PATTERN(6, 10, 22, 200, 500, 1, 12, RADAR_WAVEFORM_SHORT),
205 JP_PATTERN(7, 50, 104, 1000, 2000, 1, 8, RADAR_WAVEFORM_LONG),
206 JP_PATTERN(8, 0, 8, 333, 333, 1, 9, RADAR_WAVEFORM_SHORT),
209 static const struct radar_types jp_radar_types = {
210 .region = NL80211_DFS_JP,
211 .num_radar_types = ARRAY_SIZE(jp_radar_ref_types_riu),
212 .spec_riu = jp_radar_ref_types_riu,
213 .spec_fcu = jp_radar_ref_types_fcu,
216 static const struct radar_types *dfs_domains[] = {
217 &etsi_radar_types_v17,
224 * struct pri_sequence - sequence of pulses matching one PRI
226 * @pri: pulse repetition interval (PRI) in usecs
227 * @dur: duration of sequence in usecs
228 * @count: number of pulses in this sequence
229 * @count_falses: number of not matching pulses in this sequence
230 * @first_ts: time stamp of first pulse in usecs
231 * @last_ts: time stamp of last pulse in usecs
232 * @deadline_ts: deadline when this sequence becomes invalid (first_ts + dur)
233 * @ppb_thresh: Number of pulses to validate detection
234 * (need for weather radar whose value depends of pri)
236 struct pri_sequence {
237 struct list_head head;
250 * struct pulse_elem - elements in pulse queue
251 * @ts: time stamp in usecs
254 struct list_head head;
259 * struct pri_detector - PRI detector element for a dedicated radar type
261 * @rs: detector specs for this detector element
262 * @last_ts: last pulse time stamp considered for this element in usecs
263 * @sequences: list_head holding potential pulse sequences
264 * @pulses: list connecting pulse_elem objects
265 * @count: number of pulses in queue
266 * @max_count: maximum number of pulses to be queued
267 * @window_size: window size back from newest pulse time stamp in usecs
270 struct pri_detector {
271 struct list_head head;
272 const struct radar_detector_specs *rs;
274 struct list_head sequences;
275 struct list_head pulses;
279 struct pri_detector_ops *ops;
284 * struct pri_detector_ops - PRI detector ops (dependent of waveform type)
285 * @init : Initialize pri_detector structure
286 * @add_pulse : Add a pulse to the pri-detector
287 * @reset_on_pri_overflow : Should the pri_detector be resetted when pri overflow
289 struct pri_detector_ops {
290 void (*init)(struct pri_detector *pde);
291 struct pri_sequence * (*add_pulse)(struct pri_detector *pde, u16 len, u64 ts, u16 pri);
292 int reset_on_pri_overflow;
296 /******************************************************************************
297 * PRI (pulse repetition interval) sequence detection
298 *****************************************************************************/
300 * Singleton Pulse and Sequence Pools
302 * Instances of pri_sequence and pulse_elem are kept in singleton pools to
303 * reduce the number of dynamic allocations. They are shared between all
304 * instances and grow up to the peak number of simultaneously used objects.
306 * Memory is freed after all references to the pools are released.
308 static u32 singleton_pool_references;
309 static LIST_HEAD(pulse_pool);
310 static LIST_HEAD(pseq_pool);
311 static DEFINE_SPINLOCK(pool_lock);
313 static void pool_register_ref(void)
315 spin_lock_bh(&pool_lock);
316 singleton_pool_references++;
317 spin_unlock_bh(&pool_lock);
320 static void pool_deregister_ref(void)
322 spin_lock_bh(&pool_lock);
323 singleton_pool_references--;
324 if (singleton_pool_references == 0) {
325 /* free singleton pools with no references left */
326 struct pri_sequence *ps, *ps0;
327 struct pulse_elem *p, *p0;
329 list_for_each_entry_safe(p, p0, &pulse_pool, head) {
333 list_for_each_entry_safe(ps, ps0, &pseq_pool, head) {
338 spin_unlock_bh(&pool_lock);
341 static void pool_put_pulse_elem(struct pulse_elem *pe)
343 spin_lock_bh(&pool_lock);
344 list_add(&pe->head, &pulse_pool);
345 spin_unlock_bh(&pool_lock);
348 static void pool_put_pseq_elem(struct pri_sequence *pse)
350 spin_lock_bh(&pool_lock);
351 list_add(&pse->head, &pseq_pool);
352 spin_unlock_bh(&pool_lock);
355 static struct pri_sequence *pool_get_pseq_elem(void)
357 struct pri_sequence *pse = NULL;
358 spin_lock_bh(&pool_lock);
359 if (!list_empty(&pseq_pool)) {
360 pse = list_first_entry(&pseq_pool, struct pri_sequence, head);
361 list_del(&pse->head);
363 spin_unlock_bh(&pool_lock);
366 pse = kmalloc(sizeof(*pse), GFP_ATOMIC);
372 static struct pulse_elem *pool_get_pulse_elem(void)
374 struct pulse_elem *pe = NULL;
375 spin_lock_bh(&pool_lock);
376 if (!list_empty(&pulse_pool)) {
377 pe = list_first_entry(&pulse_pool, struct pulse_elem, head);
380 spin_unlock_bh(&pool_lock);
384 static struct pulse_elem *pulse_queue_get_tail(struct pri_detector *pde)
386 struct list_head *l = &pde->pulses;
389 return list_entry(l->prev, struct pulse_elem, head);
392 static bool pulse_queue_dequeue(struct pri_detector *pde)
394 struct pulse_elem *p = pulse_queue_get_tail(pde);
396 list_del_init(&p->head);
398 /* give it back to pool */
399 pool_put_pulse_elem(p);
401 return (pde->count > 0);
405 * pulse_queue_check_window - remove pulses older than window
406 * @pde: pointer on pri_detector
408 * dequeue pulse that are too old.
411 void pulse_queue_check_window(struct pri_detector *pde)
414 struct pulse_elem *p;
416 /* there is no delta time with less than 2 pulses */
420 if (pde->last_ts <= pde->window_size)
423 min_valid_ts = pde->last_ts - pde->window_size;
424 while ((p = pulse_queue_get_tail(pde)) != NULL) {
425 if (p->ts >= min_valid_ts)
427 pulse_queue_dequeue(pde);
432 * pulse_queue_enqueue - Queue one pulse
433 * @pde: pointer on pri_detector
435 * Add one pulse to the list. If the maximum number of pulses
436 * if reached, remove oldest one.
439 bool pulse_queue_enqueue(struct pri_detector *pde, u64 ts)
441 struct pulse_elem *p = pool_get_pulse_elem();
443 p = kmalloc(sizeof(*p), GFP_ATOMIC);
448 INIT_LIST_HEAD(&p->head);
450 list_add(&p->head, &pde->pulses);
453 pulse_queue_check_window(pde);
454 if (pde->count >= pde->max_count)
455 pulse_queue_dequeue(pde);
461 /***************************************************************************
463 **************************************************************************/
465 * pde_get_multiple() - get number of multiples considering a given tolerance
466 * @return factor if abs(val - factor*fraction) <= tolerance, 0 otherwise
469 u32 pde_get_multiple(u32 val, u32 fraction, u32 tolerance)
478 delta = (val < fraction) ? (fraction - val) : (val - fraction);
480 if (delta <= tolerance)
481 /* val and fraction are within tolerance */
484 factor = val / fraction;
485 remainder = val % fraction;
486 if (remainder > tolerance) {
488 if ((fraction - remainder) <= tolerance)
489 /* remainder is within tolerance */
498 * pde_short_create_sequences - create_sequences function for
499 * SHORT/WEATHER/INTERLEAVED radar waveform
500 * @pde: pointer on pri_detector
501 * @ts: timestamp of the pulse
502 * @min_count: Minimum number of pulse to be present in the sequence.
503 * (With this pulse there is already a sequence with @min_count
504 * pulse, so if we can't create a sequence with more pulse don't
506 * @return: false if an error occured (memory allocation) true otherwise
508 * For each pulses queued check if we can create a sequence with
509 * pri = (ts - pulse_queued.ts) which contains more than @min_count pulses.
513 bool pde_short_create_sequences(struct pri_detector *pde,
514 u64 ts, u32 min_count)
516 struct pulse_elem *p;
519 list_for_each_entry(p, &pde->pulses, head) {
520 struct pri_sequence ps, *new_ps;
521 struct pulse_elem *p2;
524 u32 delta_ts = ts - p->ts;
527 if (delta_ts < pde->rs->pri_min)
528 /* ignore too small pri */
531 if (delta_ts > pde->rs->pri_max)
532 /* stop on too large pri (sorted list) */
535 /* build a new sequence with new potential pri */
537 ps.count_falses = pulse_idx - 1;
541 ps.dur = ps.pri * (pde->rs->ppb - 1)
542 + 2 * pde->rs->max_pri_tolerance;
549 min_valid_ts = ts - ps.dur;
550 /* check which past pulses are candidates for new sequence */
551 list_for_each_entry_continue(p2, &pde->pulses, head) {
553 if (p2->ts < min_valid_ts)
554 /* stop on crossing window border */
556 /* check if pulse match (multi)PRI */
557 factor = pde_get_multiple(ps.last_ts - p2->ts, ps.pri,
558 pde->rs->max_pri_tolerance);
561 ps.first_ts = p2->ts;
563 * on match, add the intermediate falses
566 ps.count_falses += tmp_false_count;
569 /* this is a potential false one */
573 if (ps.count <= min_count) {
574 /* did not reach minimum count, drop sequence */
577 /* this is a valid one, add it */
578 ps.deadline_ts = ps.first_ts + ps.dur;
579 if (pde->rs->type == RADAR_WAVEFORM_WEATHER) {
580 ps.ppb_thresh = 19000000 / (360 * ps.pri);
581 ps.ppb_thresh = PPB_THRESH(ps.ppb_thresh);
583 ps.ppb_thresh = pde->rs->ppb_thresh;
586 new_ps = pool_get_pseq_elem();
587 if (new_ps == NULL) {
590 memcpy(new_ps, &ps, sizeof(ps));
591 INIT_LIST_HEAD(&new_ps->head);
592 list_add(&new_ps->head, &pde->sequences);
598 * pde_short_add_to_existing_seqs - add_to_existing_seqs function for
599 * SHORT/WEATHER/INTERLEAVED radar waveform
600 * @pde: pointer on pri_detector
601 * @ts: timestamp of the pulse
603 * Check all sequemces created for this pde.
604 * - If the sequence is too old delete it.
605 * - Else if the delta with the previous pulse match the pri of the sequence
606 * add the pulse to this sequence. If the pulse cannot be added it is added
607 * to the false pulses for this sequence
609 * @return the length of the longest sequence in which the pulse has been added
612 u32 pde_short_add_to_existing_seqs(struct pri_detector *pde, u64 ts)
615 struct pri_sequence *ps, *ps2;
616 list_for_each_entry_safe(ps, ps2, &pde->sequences, head) {
620 /* first ensure that sequence is within window */
621 if (ts > ps->deadline_ts) {
622 list_del_init(&ps->head);
623 pool_put_pseq_elem(ps);
627 delta_ts = ts - ps->last_ts;
628 factor = pde_get_multiple(delta_ts, ps->pri,
629 pde->rs->max_pri_tolerance);
635 if (max_count < ps->count)
636 max_count = ps->count;
646 * pde_short_check_detection - check_detection function for
647 * SHORT/WEATHER/INTERLEAVED radar waveform
648 * @pde: pointer on pri_detector
650 * Check all sequemces created for this pde.
651 * - If a sequence contains more pulses than the threshold and more matching
654 * @return The first complete sequence, and NULL if no sequence is complete.
657 struct pri_sequence * pde_short_check_detection(struct pri_detector *pde)
659 struct pri_sequence *ps;
661 if (list_empty(&pde->sequences))
664 list_for_each_entry(ps, &pde->sequences, head) {
666 * we assume to have enough matching confidence if we
667 * 1) have enough pulses
668 * 2) have more matching than false pulses
670 if ((ps->count >= ps->ppb_thresh) &&
671 (ps->count * pde->rs->num_pri > ps->count_falses)) {
679 * pde_short_init - init function for
680 * SHORT/WEATHER/INTERLEAVED radar waveform
681 * @pde: pointer on pri_detector
683 * Initialize pri_detector window size to the maximun size of one burst
684 * for the radar specification associated.
687 void pde_short_init(struct pri_detector *pde)
689 pde->window_size = pde->rs->pri_max * pde->rs->ppb * pde->rs->num_pri;
690 pde->max_count = pde->rs->ppb * 2;
693 static void pri_detector_reset(struct pri_detector *pde, u64 ts);
695 * pde_short_add_pulse - Add pulse to a pri_detector for
696 * SHORT/WEATHER/INTERLEAVED radar waveform
698 * @pde : pointer on pri_detector
699 * @len : width of the pulse
700 * @ts : timestamp of the pulse received
701 * @pri : Delta in us with the previous pulse.
702 * (0 means that delta in bigger than 65535 us)
704 * Process on pulse within this pri_detector
705 * - First try to add it to existing sequence
706 * - Then try to create a new and longest sequence
707 * - Check if this pulse complete a sequence
708 * - If not save this pulse in the list
711 struct pri_sequence *pde_short_add_pulse(struct pri_detector *pde,
712 u16 len, u64 ts, u16 pri)
715 struct pri_sequence *ps;
716 const struct radar_detector_specs *rs = pde->rs;
718 if (pde->count == 0) {
719 /* This is the first pulse after reset, no need to check sequences */
720 pulse_queue_enqueue(pde, ts);
724 if ((ts - pde->last_ts) < rs->max_pri_tolerance) {
725 /* if delta to last pulse is too short, don't use this pulse */
729 max_updated_seq = pde_short_add_to_existing_seqs(pde, ts);
731 if (!pde_short_create_sequences(pde, ts, max_updated_seq)) {
732 pri_detector_reset(pde, ts);
736 ps = pde_short_check_detection(pde);
739 pulse_queue_enqueue(pde, ts);
747 * pri detector ops to detect short radar waveform
748 * A Short waveform is defined by :
749 * The width of pulses.
750 * The interval between two pulses inside a burst (called pri)
751 * (some waveform may have or 2/3 interleaved pri)
752 * The number of pulses per burst (ppb)
754 static struct pri_detector_ops pri_detector_short = {
755 .init = pde_short_init,
756 .add_pulse = pde_short_add_pulse,
757 .reset_on_pri_overflow = 1,
761 /***************************************************************************
763 **************************************************************************/
764 #define LONG_RADAR_DURATION 12000000
765 #define LONG_RADAR_BURST_MIN_DURATION (12000000 / 20)
766 #define LONG_RADAR_MAX_BURST 20
769 * pde_long_init - init function for LONG radar waveform
770 * @pde: pointer on pri_detector
772 * Initialize pri_detector window size to the long waveform radar
773 * waveform (ie. 12s) and max_count
776 void pde_long_init(struct pri_detector *pde)
778 pde->window_size = LONG_RADAR_DURATION;
779 pde->max_count = LONG_RADAR_MAX_BURST; /* only count burst not pulses */
784 * pde_long_add_pulse - Add pulse to a pri_detector for
785 * LONG radar waveform
787 * @pde : pointer on pri_detector
788 * @len : width of the pulse
789 * @ts : timestamp of the pulse received
790 * @pri : Delta in us with the previous pulse.
793 * For long pulse we only handle one sequence. Since each burst
794 * have a different set of parameters (number of pulse, pri) than
795 * the previous one we only use pulse width to add the pulse in the
797 * We only queue one pulse per burst and valid the radar when enough burst
801 struct pri_sequence *pde_long_add_pulse(struct pri_detector *pde,
802 u16 len, u64 ts, u16 pri)
804 struct pri_sequence *ps;
805 const struct radar_detector_specs *rs = pde->rs;
807 if (list_empty(&pde->sequences)) {
808 /* First pulse, create a new sequence */
809 ps = pool_get_pseq_elem();
814 /*For long waveform, "count" represents the number of burst detected */
816 /*"count_false" represents the number of pulse in the current burst */
817 ps->count_falses = 1;
820 ps->deadline_ts = ts + pde->window_size;
822 INIT_LIST_HEAD(&ps->head);
823 list_add(&ps->head, &pde->sequences);
824 pulse_queue_enqueue(pde, ts);
828 ps = (struct pri_sequence *)pde->sequences.next;
830 delta_ts = ts - ps->last_ts;
833 if (delta_ts < rs->pri_max) {
834 /* ignore pulse too close from previous one */
835 } else if ((delta_ts >= rs->pri_min) &&
836 (delta_ts <= rs->pri_max)) {
837 /* this is a new pulse in the current burst, ignore it
838 (i.e don't queue it) */
840 } else if ((ps->count > 2) &&
841 (ps->dur + delta_ts) < LONG_RADAR_BURST_MIN_DURATION) {
842 /* not enough time between burst, ignore pulse */
846 ps->count_falses = 1;
848 /* reset the start of the sequence if deadline reached */
849 if (ts > ps->deadline_ts) {
850 struct pulse_elem *p;
853 min_valid_ts = ts - pde->window_size;
854 while ((p = pulse_queue_get_tail(pde)) != NULL) {
855 if (p->ts >= min_valid_ts) {
856 ps->first_ts = p->ts;
857 ps->deadline_ts = p->ts + pde->window_size;
860 pulse_queue_dequeue(pde);
865 /* valid radar if enough burst detected and delta with first burst
866 is at least duration/2 */
867 if (ps->count > pde->rs->ppb_thresh &&
868 (ts - ps->first_ts) > (pde->window_size / 2)) {
871 pulse_queue_enqueue(pde, ts);
881 * pri detector ops to detect long radar waveform
883 static struct pri_detector_ops pri_detector_long = {
884 .init = pde_long_init,
885 .add_pulse = pde_long_add_pulse,
886 .reset_on_pri_overflow = 0,
890 /***************************************************************************
891 * PRI detector init/reset/exit/get
892 **************************************************************************/
894 * pri_detector_init- Create a new pri_detector
896 * @dpd: dfs_pattern_detector instance pointer
897 * @radar_type: index of radar pattern
898 * @freq: Frequency of the pri detector
900 struct pri_detector *pri_detector_init(struct dfs_pattern_detector *dpd,
901 u16 radar_type, u16 freq)
903 struct pri_detector *pde;
905 pde = kzalloc(sizeof(*pde), GFP_ATOMIC);
909 INIT_LIST_HEAD(&pde->sequences);
910 INIT_LIST_HEAD(&pde->pulses);
911 INIT_LIST_HEAD(&pde->head);
912 list_add(&pde->head, &dpd->detectors[radar_type]);
914 pde->rs = &dpd->radar_spec[radar_type];
917 if (pde->rs->type == RADAR_WAVEFORM_LONG) {
918 /* for LONG WAVEFORM */
919 pde->ops = &pri_detector_long;
921 /* for SHORT, WEATHER and INTERLEAVED */
922 pde->ops = &pri_detector_short;
925 /* Init dependent of specs */
933 * pri_detector_reset - Reset pri_detector
935 * @pde: pointer on pri_detector
936 * @ts: New ts reference for the pri_detector
938 * free pulse queue and sequences list and give objects back to pools
941 void pri_detector_reset(struct pri_detector *pde, u64 ts)
943 struct pri_sequence *ps, *ps0;
944 struct pulse_elem *p, *p0;
945 list_for_each_entry_safe(ps, ps0, &pde->sequences, head) {
946 list_del_init(&ps->head);
947 pool_put_pseq_elem(ps);
949 list_for_each_entry_safe(p, p0, &pde->pulses, head) {
950 list_del_init(&p->head);
951 pool_put_pulse_elem(p);
958 * pri_detector_exit - Delete pri_detector
960 * @pde: pointer on pri_detector
963 void pri_detector_exit(struct pri_detector *pde)
965 pri_detector_reset(pde, 0);
966 pool_deregister_ref();
967 list_del(&pde->head);
972 * pri_detector_get() - get pri detector for a given frequency and type
973 * @dpd: dfs_pattern_detector instance pointer
974 * @freq: frequency in MHz
975 * @radar_type: index of radar pattern
976 * @return pointer to pri detector on success, NULL otherwise
978 * Return existing pri detector for the given frequency or return a
980 * Pri detector are "merged" by frequency so that if a pri detector for a freq
981 * of +/- 2Mhz already exists don't create a new one.
983 * Maybe will need to adapt frequency merge for pattern with chirp.
985 static struct pri_detector *
986 pri_detector_get(struct dfs_pattern_detector *dpd, u16 freq, u16 radar_type)
988 struct pri_detector *pde, *cur = NULL;
989 list_for_each_entry(pde, &dpd->detectors[radar_type], head) {
990 if (pde->freq == freq) {
995 } else if (pde->freq - 2 == freq && pde->count) {
997 } else if (pde->freq + 2 == freq && pde->count) {
1005 return pri_detector_init(dpd, radar_type, freq);
1009 /******************************************************************************
1010 * DFS Pattern Detector
1011 *****************************************************************************/
1013 * dfs_pattern_detector_reset() - reset all channel detectors
1015 * @dpd: dfs_pattern_detector
1017 static void dfs_pattern_detector_reset(struct dfs_pattern_detector *dpd)
1019 struct pri_detector *pde;
1022 for (i = 0; i < dpd->num_radar_types; i++) {
1023 if (!list_empty(&dpd->detectors[i]))
1024 list_for_each_entry(pde, &dpd->detectors[i], head)
1025 pri_detector_reset(pde, dpd->last_pulse_ts);
1028 dpd->last_pulse_ts = 0;
1029 dpd->prev_jiffies = jiffies;
1033 * dfs_pattern_detector_reset() - delete all channel detectors
1035 * @dpd: dfs_pattern_detector
1037 static void dfs_pattern_detector_exit(struct dfs_pattern_detector *dpd)
1039 struct pri_detector *pde, *pde0;
1042 for (i = 0; i < dpd->num_radar_types; i++) {
1043 if (!list_empty(&dpd->detectors[i]))
1044 list_for_each_entry_safe(pde, pde0, &dpd->detectors[i], head)
1045 pri_detector_exit(pde);
1052 * dfs_pattern_detector_pri_overflow - reset all channel detectors on pri
1054 * @dpd: dfs_pattern_detector
1056 static void dfs_pattern_detector_pri_overflow(struct dfs_pattern_detector *dpd)
1058 struct pri_detector *pde;
1061 for (i = 0; i < dpd->num_radar_types; i++) {
1062 if (!list_empty(&dpd->detectors[i]))
1063 list_for_each_entry(pde, &dpd->detectors[i], head)
1064 if (pde->ops->reset_on_pri_overflow)
1065 pri_detector_reset(pde, dpd->last_pulse_ts);
1070 * dfs_pattern_detector_add_pulse - Process one pulse
1072 * @dpd: dfs_pattern_detector
1073 * @chain: Chain that correspond to this pattern_detector (only for debug)
1074 * @freq: frequency of the pulse
1075 * @pri: Delta with previous pulse. (0 if delta is too big for u16)
1076 * @len: width of the pulse
1077 * @now: jiffies value when pulse was received
1079 * Get (or create) the channel_detector for this frequency. Then add the pulse
1080 * in each pri_detector created in this channel_detector.
1083 * @return True is the pulse complete a radar pattern, false otherwise
1085 static bool dfs_pattern_detector_add_pulse(struct dfs_pattern_detector *dpd,
1086 enum ecrnx_radar_chain chain,
1087 u16 freq, u16 pri, u16 len, u32 now)
1092 * pulses received for a non-supported or un-initialized
1093 * domain are treated as detected radars for fail-safety
1095 if (dpd->region == NL80211_DFS_UNSET)
1098 /* Compute pulse time stamp */
1101 if (unlikely(now < dpd->prev_jiffies)) {
1102 delta_jiffie = 0xffffffff - dpd->prev_jiffies + now;
1104 delta_jiffie = now - dpd->prev_jiffies;
1106 dpd->last_pulse_ts += jiffies_to_usecs(delta_jiffie);
1107 dpd->prev_jiffies = now;
1108 dfs_pattern_detector_pri_overflow(dpd);
1110 dpd->last_pulse_ts += pri;
1113 for (i = 0; i < dpd->num_radar_types; i++) {
1114 struct pri_sequence *ps;
1115 struct pri_detector *pde;
1116 const struct radar_detector_specs *rs = &dpd->radar_spec[i];
1118 /* no need to look up for pde if len is not within range */
1119 if ((rs->width_min > len) ||
1120 (rs->width_max < len)) {
1124 pde = pri_detector_get(dpd, freq, i);
1125 ps = pde->ops->add_pulse(pde, len, dpd->last_pulse_ts, pri);
1128 trace_radar_detected(chain, dpd->region, pde->freq, i, ps->pri);
1129 // reset everything instead of just the channel detector
1130 dfs_pattern_detector_reset(dpd);
1139 * get_dfs_domain_radar_types() - get radar types for a given DFS domain
1140 * @param domain DFS domain
1141 * @return radar_types ptr on success, NULL if DFS domain is not supported
1143 static const struct radar_types *
1144 get_dfs_domain_radar_types(enum nl80211_dfs_regions region)
1147 for (i = 0; i < ARRAY_SIZE(dfs_domains); i++) {
1148 if (dfs_domains[i]->region == region)
1149 return dfs_domains[i];
1155 * get_dfs_max_radar_types() - get maximum radar types for all supported domain
1156 * @return the maximum number of radar pattern supported by on region
1158 static u16 get_dfs_max_radar_types(void)
1162 for (i = 0; i < ARRAY_SIZE(dfs_domains); i++) {
1163 if (dfs_domains[i]->num_radar_types > max)
1164 max = dfs_domains[i]->num_radar_types;
1170 * dfs_pattern_detector_set_domain - set DFS domain
1172 * @dpd: dfs_pattern_detector
1173 * @region: DFS region
1175 * set DFS domain, resets detector lines upon domain changes
1178 bool dfs_pattern_detector_set_domain(struct dfs_pattern_detector *dpd,
1179 enum nl80211_dfs_regions region, u8 chain)
1181 const struct radar_types *rt;
1182 struct pri_detector *pde, *pde0;
1185 if (dpd->region == region)
1188 dpd->region = NL80211_DFS_UNSET;
1190 rt = get_dfs_domain_radar_types(region);
1194 /* delete all pri detectors for previous DFS domain */
1195 for (i = 0; i < dpd->num_radar_types; i++) {
1196 if (!list_empty(&dpd->detectors[i]))
1197 list_for_each_entry_safe(pde, pde0, &dpd->detectors[i], head)
1198 pri_detector_exit(pde);
1201 if (chain == ECRNX_RADAR_RIU)
1202 dpd->radar_spec = rt->spec_riu;
1204 dpd->radar_spec = rt->spec_fcu;
1205 dpd->num_radar_types = rt->num_radar_types;
1207 dpd->region = region;
1212 * dfs_pattern_detector_init - Initialize dfs_pattern_detector
1214 * @region: DFS region
1215 * @return: pointer on dfs_pattern_detector
1218 static struct dfs_pattern_detector *
1219 dfs_pattern_detector_init(enum nl80211_dfs_regions region, u8 chain)
1221 struct dfs_pattern_detector *dpd;
1222 u16 i, max_radar_type = get_dfs_max_radar_types();
1224 dpd = kmalloc(sizeof(*dpd) + max_radar_type * sizeof(dpd->detectors[0]),
1229 dpd->region = NL80211_DFS_UNSET;
1230 dpd->enabled = ECRNX_RADAR_DETECT_DISABLE;
1231 dpd->last_pulse_ts = 0;
1232 dpd->prev_jiffies = jiffies;
1233 dpd->num_radar_types = 0;
1234 for (i = 0; i < max_radar_type; i++)
1235 INIT_LIST_HEAD(&dpd->detectors[i]);
1237 if (dfs_pattern_detector_set_domain(dpd, region, chain))
1245 /******************************************************************************
1247 *****************************************************************************/
1248 static u16 ecrnx_radar_get_center_freq(struct ecrnx_hw *ecrnx_hw, u8 chain)
1250 if (chain == ECRNX_RADAR_FCU)
1251 return ecrnx_hw->phy.sec_chan.center1_freq;
1253 if (chain == ECRNX_RADAR_RIU) {
1254 #ifdef CONFIG_ECRNX_SOFTMAC
1255 return ecrnx_hw->cur_freq;
1257 if (!ecrnx_chanctx_valid(ecrnx_hw, ecrnx_hw->cur_chanctx)) {
1258 WARN(1, "Radar pulse without channel information");
1260 return ecrnx_hw->chanctx_table[ecrnx_hw->cur_chanctx].chan_def.center_freq1;
1261 #endif /* CONFIG_ECRNX_SOFTMAC */
1267 static void ecrnx_radar_detected(struct ecrnx_hw *ecrnx_hw)
1269 #ifdef CONFIG_ECRNX_SOFTMAC
1270 ieee80211_radar_detected(ecrnx_hw->hw);
1272 struct cfg80211_chan_def chan_def;
1274 if (!ecrnx_chanctx_valid(ecrnx_hw, ecrnx_hw->cur_chanctx)) {
1275 WARN(1, "Radar detected without channel information");
1280 recopy chan_def in local variable because ecrnx_radar_cancel_cac may
1281 clean the variable (if in CAC and it's the only vif using this context)
1282 and CAC should be aborted before reporting the radar.
1284 chan_def = ecrnx_hw->chanctx_table[ecrnx_hw->cur_chanctx].chan_def;
1286 ecrnx_radar_cancel_cac(&ecrnx_hw->radar);
1287 #if LINUX_VERSION_CODE >= KERNEL_VERSION(3, 10, 0)
1288 cfg80211_radar_event(ecrnx_hw->wiphy, &chan_def, GFP_KERNEL);
1290 #endif /* CONFIG_ECRNX_SOFTMAC */
1293 static void ecrnx_radar_process_pulse(struct work_struct *ws)
1295 struct ecrnx_radar *radar = container_of(ws, struct ecrnx_radar,
1297 struct ecrnx_hw *ecrnx_hw = container_of(radar, struct ecrnx_hw, radar);
1299 u32 pulses[ECRNX_RADAR_LAST][ECRNX_RADAR_PULSE_MAX];
1300 u16 pulses_count[ECRNX_RADAR_LAST];
1301 u32 now = jiffies; /* would be better to store jiffies value in IT handler */
1303 /* recopy pulses locally to avoid too long spin_lock */
1304 spin_lock_bh(&radar->lock);
1305 for (chain = ECRNX_RADAR_RIU; chain < ECRNX_RADAR_LAST; chain++) {
1308 count = radar->pulses[chain].count;
1309 start = radar->pulses[chain].index - count;
1311 start += ECRNX_RADAR_PULSE_MAX;
1313 pulses_count[chain] = count;
1317 if ((start + count) > ECRNX_RADAR_PULSE_MAX) {
1318 u16 count1 = (ECRNX_RADAR_PULSE_MAX - start);
1319 memcpy(&(pulses[chain][0]),
1320 &(radar->pulses[chain].buffer[start]),
1321 count1 * sizeof(struct radar_pulse));
1322 memcpy(&(pulses[chain][count1]),
1323 &(radar->pulses[chain].buffer[0]),
1324 (count - count1) * sizeof(struct radar_pulse));
1326 memcpy(&(pulses[chain][0]),
1327 &(radar->pulses[chain].buffer[start]),
1328 count * sizeof(struct radar_pulse));
1330 radar->pulses[chain].count = 0;
1332 spin_unlock_bh(&radar->lock);
1335 /* now process pulses */
1336 for (chain = ECRNX_RADAR_RIU; chain < ECRNX_RADAR_LAST; chain++) {
1340 if (pulses_count[chain] == 0)
1343 freq = ecrnx_radar_get_center_freq(ecrnx_hw, chain);
1345 for (i = 0; i < pulses_count[chain] ; i++) {
1346 struct radar_pulse *p = (struct radar_pulse *)&pulses[chain][i];
1347 trace_radar_pulse(chain, p);
1348 if (dfs_pattern_detector_add_pulse(radar->dpd[chain], chain,
1349 (s16)freq + (2 * p->freq),
1350 p->rep, (p->len * 2), now)) {
1351 u16 idx = radar->detected[chain].index;
1353 if (chain == ECRNX_RADAR_RIU) {
1354 /* operating chain, inform upper layer to change channel */
1355 if (radar->dpd[chain]->enabled == ECRNX_RADAR_DETECT_REPORT) {
1356 ecrnx_radar_detected(ecrnx_hw);
1357 /* no need to report new radar until upper layer set a
1358 new channel. This prevent warning if a new radar is
1359 detected while mac80211 is changing channel */
1360 ecrnx_radar_detection_enable(radar,
1361 ECRNX_RADAR_DETECT_DISABLE,
1363 /* purge any event received since the beginning of the
1364 function (we are sure not to interfer with tasklet
1365 as we disable detection just before) */
1366 radar->pulses[chain].count = 0;
1369 /* secondary radar detection chain, simply report info in
1373 radar->detected[chain].freq[idx] = (s16)freq + (2 * p->freq);
1374 radar->detected[chain].time[idx] = ktime_get_real_seconds();
1375 radar->detected[chain].index = ((idx + 1 ) %
1376 NX_NB_RADAR_DETECTED);
1377 radar->detected[chain].count++;
1378 /* no need to process next pulses for this chain */
1385 #ifdef CONFIG_ECRNX_FULLMAC
1386 static void ecrnx_radar_cac_work(struct work_struct *ws)
1388 struct delayed_work *dw = container_of(ws, struct delayed_work, work);
1389 struct ecrnx_radar *radar = container_of(dw, struct ecrnx_radar, cac_work);
1390 struct ecrnx_hw *ecrnx_hw = container_of(radar, struct ecrnx_hw, radar);
1391 struct ecrnx_chanctx *ctxt;
1393 if (radar->cac_vif == NULL) {
1394 WARN(1, "CAC finished but no vif set");
1398 ctxt = &ecrnx_hw->chanctx_table[radar->cac_vif->ch_index];
1399 #if LINUX_VERSION_CODE >= KERNEL_VERSION(3, 10, 0)
1400 cfg80211_cac_event(radar->cac_vif->ndev,
1401 #if LINUX_VERSION_CODE >= KERNEL_VERSION(3, 14, 0)
1404 NL80211_RADAR_CAC_FINISHED, GFP_KERNEL);
1406 ecrnx_send_apm_stop_cac_req(ecrnx_hw, radar->cac_vif);
1407 ecrnx_chanctx_unlink(radar->cac_vif);
1409 radar->cac_vif = NULL;
1411 #endif /* CONFIG_ECRNX_FULLMAC */
1413 bool ecrnx_radar_detection_init(struct ecrnx_radar *radar)
1415 spin_lock_init(&radar->lock);
1417 radar->dpd[ECRNX_RADAR_RIU] = dfs_pattern_detector_init(NL80211_DFS_UNSET,
1419 if (radar->dpd[ECRNX_RADAR_RIU] == NULL)
1422 radar->dpd[ECRNX_RADAR_FCU] = dfs_pattern_detector_init(NL80211_DFS_UNSET,
1424 if (radar->dpd[ECRNX_RADAR_FCU] == NULL) {
1425 ecrnx_radar_detection_deinit(radar);
1429 INIT_WORK(&radar->detection_work, ecrnx_radar_process_pulse);
1430 #ifdef CONFIG_ECRNX_FULLMAC
1431 INIT_DELAYED_WORK(&radar->cac_work, ecrnx_radar_cac_work);
1432 radar->cac_vif = NULL;
1433 #endif /* CONFIG_ECRNX_FULLMAC */
1437 void ecrnx_radar_detection_deinit(struct ecrnx_radar *radar)
1439 if (radar->dpd[ECRNX_RADAR_RIU]) {
1440 dfs_pattern_detector_exit(radar->dpd[ECRNX_RADAR_RIU]);
1441 radar->dpd[ECRNX_RADAR_RIU] = NULL;
1443 if (radar->dpd[ECRNX_RADAR_FCU]) {
1444 dfs_pattern_detector_exit(radar->dpd[ECRNX_RADAR_FCU]);
1445 radar->dpd[ECRNX_RADAR_FCU] = NULL;
1449 bool ecrnx_radar_set_domain(struct ecrnx_radar *radar,
1450 enum nl80211_dfs_regions region)
1452 if (radar->dpd[0] == NULL)
1455 trace_radar_set_region(region);
1457 return (dfs_pattern_detector_set_domain(radar->dpd[ECRNX_RADAR_RIU],
1458 region, ECRNX_RADAR_RIU) &&
1459 dfs_pattern_detector_set_domain(radar->dpd[ECRNX_RADAR_FCU],
1460 region, ECRNX_RADAR_FCU));
1463 void ecrnx_radar_detection_enable(struct ecrnx_radar *radar, u8 enable, u8 chain)
1465 if (chain < ECRNX_RADAR_LAST ) {
1466 trace_radar_enable_detection(radar->dpd[chain]->region, enable, chain);
1467 spin_lock_bh(&radar->lock);
1468 radar->dpd[chain]->enabled = enable;
1469 spin_unlock_bh(&radar->lock);
1473 bool ecrnx_radar_detection_is_enable(struct ecrnx_radar *radar, u8 chain)
1475 return radar->dpd[chain]->enabled != ECRNX_RADAR_DETECT_DISABLE;
1478 #ifdef CONFIG_ECRNX_FULLMAC
1479 void ecrnx_radar_start_cac(struct ecrnx_radar *radar, u32 cac_time_ms,
1480 struct ecrnx_vif *vif)
1482 WARN(radar->cac_vif != NULL, "CAC already in progress");
1483 radar->cac_vif = vif;
1484 schedule_delayed_work(&radar->cac_work, msecs_to_jiffies(cac_time_ms));
1487 void ecrnx_radar_cancel_cac(struct ecrnx_radar *radar)
1489 struct ecrnx_hw *ecrnx_hw = container_of(radar, struct ecrnx_hw, radar);
1491 if (radar->cac_vif == NULL) {
1495 if (cancel_delayed_work(&radar->cac_work)) {
1496 struct ecrnx_chanctx *ctxt;
1497 ctxt = &ecrnx_hw->chanctx_table[radar->cac_vif->ch_index];
1498 ecrnx_send_apm_stop_cac_req(ecrnx_hw, radar->cac_vif);
1499 #if LINUX_VERSION_CODE >= KERNEL_VERSION(3, 10, 0)
1500 cfg80211_cac_event(radar->cac_vif->ndev,
1501 #if LINUX_VERSION_CODE >= KERNEL_VERSION(3, 14, 0)
1504 NL80211_RADAR_CAC_ABORTED, GFP_KERNEL);
1506 ecrnx_chanctx_unlink(radar->cac_vif);
1509 radar->cac_vif = NULL;
1512 void ecrnx_radar_detection_enable_on_cur_channel(struct ecrnx_hw *ecrnx_hw)
1514 struct ecrnx_chanctx *ctxt;
1516 /* If no information on current channel do nothing */
1517 if (!ecrnx_chanctx_valid(ecrnx_hw, ecrnx_hw->cur_chanctx))
1520 ctxt = &ecrnx_hw->chanctx_table[ecrnx_hw->cur_chanctx];
1521 if (ctxt->chan_def.chan->flags & IEEE80211_CHAN_RADAR) {
1522 ecrnx_radar_detection_enable(&ecrnx_hw->radar,
1523 ECRNX_RADAR_DETECT_REPORT,
1526 ecrnx_radar_detection_enable(&ecrnx_hw->radar,
1527 ECRNX_RADAR_DETECT_DISABLE,
1531 #endif /* CONFIG_ECRNX_FULLMAC */
1533 /*****************************************************************************
1535 *****************************************************************************/
1537 int ecrnx_radar_dump_pri_detector(char *buf, size_t len,
1538 struct pri_detector *pde)
1540 char freq_info[] = "Freq = %3.dMhz\n";
1541 char seq_info[] = " pri | count | false \n";
1542 struct pri_sequence *seq;
1545 if (list_empty(&pde->sequences)) {
1551 list_for_each_entry(seq, &pde->sequences, head) {
1555 return (sizeof(freq_info) + nb_seq * sizeof(seq_info));
1558 res = scnprintf(buf, len, freq_info, pde->freq);
1562 res = scnprintf(&buf[write], len, "%s", seq_info);
1566 list_for_each_entry(seq, &pde->sequences, head) {
1567 res = scnprintf(&buf[write], len, " %6.d | %2.d | %.2d \n",
1568 seq->pri, seq->count, seq->count_falses);
1576 int ecrnx_radar_dump_pattern_detector(char *buf, size_t len,
1577 struct ecrnx_radar *radar, u8 chain)
1579 struct dfs_pattern_detector *dpd = radar->dpd[chain];
1580 char info[] = "Type = %3.d\n";
1581 struct pri_detector *pde;
1582 int i, res, write = 0;
1584 /* if buf is NULL return size needed for dump */
1586 int size_needed = 0;
1588 for (i = 0; i < dpd->num_radar_types; i++) {
1589 list_for_each_entry(pde, &dpd->detectors[i], head) {
1590 size_needed += ecrnx_radar_dump_pri_detector(NULL, 0, pde);
1592 size_needed += sizeof(info);
1599 for (i = 0; i < dpd->num_radar_types; i++) {
1600 res = scnprintf(&buf[write], len, info, i);
1604 list_for_each_entry(pde, &dpd->detectors[i], head) {
1605 res = ecrnx_radar_dump_pri_detector(&buf[write], len, pde);
1615 int ecrnx_radar_dump_radar_detected(char *buf, size_t len,
1616 struct ecrnx_radar *radar, u8 chain)
1618 struct ecrnx_radar_detected *detect = &(radar->detected[chain]);
1619 char info[] = "2001/02/02 - 02:20 5126MHz\n";
1620 int idx, i, res, write = 0;
1621 int count = detect->count;
1623 if (count > NX_NB_RADAR_DETECTED)
1624 count = NX_NB_RADAR_DETECTED;
1627 return (count * sizeof(info)) + 1;
1630 idx = (detect->index - detect->count) % NX_NB_RADAR_DETECTED;
1632 for (i = 0; i < count; i++) {
1634 time64_to_tm(detect->time[idx], 0, &tm);
1636 res = scnprintf(&buf[write], len,
1637 "%.4d/%.2d/%.2d - %.2d:%.2d %4.4dMHz\n",
1638 (int)tm.tm_year + 1900, tm.tm_mon + 1, tm.tm_mday,
1639 tm.tm_hour, tm.tm_min, detect->freq[idx]);
1643 idx = (idx + 1 ) % NX_NB_RADAR_DETECTED;