aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/net
diff options
context:
space:
mode:
authorZefir Kurtisi <zefir.kurtisi@neratec.com>2012-04-03 11:15:49 -0400
committerJohn W. Linville <linville@tuxdriver.com>2012-04-11 16:23:52 -0400
commit6ee159e26f1bb0177b37ebc858693932465839a3 (patch)
tree98dcf4ea060ab48de93ce5d8028f580cabf02f2c /drivers/net
parent4d6c36fa227afc7b76b85ee48e3ef3972fe0ca23 (diff)
ath9k: add DFS pattern detector
This adds a DFS pattern detector to ath9k. It is fed with pulse events by the radar pulse detector and reports in place whether a pattern was detected. On detection, the result is reported as radar event to the DFS management component in the upper layer. Currently the ETSI DFS domain is supported with detector lines for the patterns defined by EN-301-893 v1.5.1. Support for FCC and JP will be added gradually. To include the pattern detector, ath9k must be built with support for DFS certified config flag set (CONFIG_ATH9K_DFS_CERTIFIED). Signed-off-by: Zefir Kurtisi <zefir.kurtisi@neratec.com> Signed-off-by: John W. Linville <linville@tuxdriver.com>
Diffstat (limited to 'drivers/net')
-rw-r--r--drivers/net/wireless/ath/ath9k/Makefile5
-rw-r--r--drivers/net/wireless/ath/ath9k/dfs_pattern_detector.c300
-rw-r--r--drivers/net/wireless/ath/ath9k/dfs_pattern_detector.h104
-rw-r--r--drivers/net/wireless/ath/ath9k/dfs_pri_detector.c390
-rw-r--r--drivers/net/wireless/ath/ath9k/dfs_pri_detector.h52
5 files changed, 850 insertions, 1 deletions
diff --git a/drivers/net/wireless/ath/ath9k/Makefile b/drivers/net/wireless/ath/ath9k/Makefile
index 27d95fe5ade0..3f0b84723789 100644
--- a/drivers/net/wireless/ath/ath9k/Makefile
+++ b/drivers/net/wireless/ath/ath9k/Makefile
@@ -11,7 +11,10 @@ ath9k-$(CONFIG_ATH9K_PCI) += pci.o
11ath9k-$(CONFIG_ATH9K_AHB) += ahb.o 11ath9k-$(CONFIG_ATH9K_AHB) += ahb.o
12ath9k-$(CONFIG_ATH9K_DEBUGFS) += debug.o 12ath9k-$(CONFIG_ATH9K_DEBUGFS) += debug.o
13ath9k-$(CONFIG_ATH9K_DFS_DEBUGFS) += dfs_debug.o 13ath9k-$(CONFIG_ATH9K_DFS_DEBUGFS) += dfs_debug.o
14ath9k-$(CONFIG_ATH9K_DFS_CERTIFIED) += dfs.o 14ath9k-$(CONFIG_ATH9K_DFS_CERTIFIED) += \
15 dfs.o \
16 dfs_pattern_detector.o \
17 dfs_pri_detector.o
15 18
16obj-$(CONFIG_ATH9K) += ath9k.o 19obj-$(CONFIG_ATH9K) += ath9k.o
17 20
diff --git a/drivers/net/wireless/ath/ath9k/dfs_pattern_detector.c b/drivers/net/wireless/ath/ath9k/dfs_pattern_detector.c
new file mode 100644
index 000000000000..ea2a6cf7ef23
--- /dev/null
+++ b/drivers/net/wireless/ath/ath9k/dfs_pattern_detector.c
@@ -0,0 +1,300 @@
1/*
2 * Copyright (c) 2012 Neratec Solutions AG
3 *
4 * Permission to use, copy, modify, and/or distribute this software for any
5 * purpose with or without fee is hereby granted, provided that the above
6 * copyright notice and this permission notice appear in all copies.
7 *
8 * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
9 * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
10 * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
11 * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
12 * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
13 * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
14 * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
15 */
16
17#include <linux/slab.h>
18#include <linux/export.h>
19
20#include "dfs_pattern_detector.h"
21#include "dfs_pri_detector.h"
22
23/*
24 * tolerated deviation of radar time stamp in usecs on both sides
25 * TODO: this might need to be HW-dependent
26 */
27#define PRI_TOLERANCE 16
28
29/**
30 * struct radar_types - contains array of patterns defined for one DFS domain
31 * @domain: DFS regulatory domain
32 * @num_radar_types: number of radar types to follow
33 * @radar_types: radar types array
34 */
35struct radar_types {
36 enum nl80211_dfs_regions region;
37 u32 num_radar_types;
38 const struct radar_detector_specs *radar_types;
39};
40
41/* percentage on ppb threshold to trigger detection */
42#define MIN_PPB_THRESH 50
43#define PPB_THRESH(PPB) ((PPB * MIN_PPB_THRESH + 50) / 100)
44#define PRF2PRI(PRF) ((1000000 + PRF / 2) / PRF)
45
46#define ETSI_PATTERN(ID, WMIN, WMAX, PMIN, PMAX, PRF, PPB) \
47{ \
48 ID, WMIN, WMAX, (PRF2PRI(PMAX) - PRI_TOLERANCE), \
49 (PRF2PRI(PMIN) * PRF + PRI_TOLERANCE), PRF, PPB * PRF, \
50 PPB_THRESH(PPB), PRI_TOLERANCE, \
51}
52
53/* radar types as defined by ETSI EN-301-893 v1.5.1 */
54static const struct radar_detector_specs etsi_radar_ref_types_v15[] = {
55 ETSI_PATTERN(0, 0, 1, 700, 700, 1, 18),
56 ETSI_PATTERN(1, 0, 5, 200, 1000, 1, 10),
57 ETSI_PATTERN(2, 0, 15, 200, 1600, 1, 15),
58 ETSI_PATTERN(3, 0, 15, 2300, 4000, 1, 25),
59 ETSI_PATTERN(4, 20, 30, 2000, 4000, 1, 20),
60 ETSI_PATTERN(5, 0, 2, 300, 400, 3, 10),
61 ETSI_PATTERN(6, 0, 2, 400, 1200, 3, 15),
62};
63
64static const struct radar_types etsi_radar_types_v15 = {
65 .region = NL80211_DFS_ETSI,
66 .num_radar_types = ARRAY_SIZE(etsi_radar_ref_types_v15),
67 .radar_types = etsi_radar_ref_types_v15,
68};
69
70/* for now, we support ETSI radar types, FCC and JP are TODO */
71static const struct radar_types *dfs_domains[] = {
72 &etsi_radar_types_v15,
73};
74
75/**
76 * get_dfs_domain_radar_types() - get radar types for a given DFS domain
77 * @param domain DFS domain
78 * @return radar_types ptr on success, NULL if DFS domain is not supported
79 */
80static const struct radar_types *
81get_dfs_domain_radar_types(enum nl80211_dfs_regions region)
82{
83 u32 i;
84 for (i = 0; i < ARRAY_SIZE(dfs_domains); i++) {
85 if (dfs_domains[i]->region == region)
86 return dfs_domains[i];
87 }
88 return NULL;
89}
90
91/**
92 * struct channel_detector - detector elements for a DFS channel
93 * @head: list_head
94 * @freq: frequency for this channel detector in MHz
95 * @detectors: array of dynamically created detector elements for this freq
96 *
97 * Channel detectors are required to provide multi-channel DFS detection, e.g.
98 * to support off-channel scanning. A pattern detector has a list of channels
99 * radar pulses have been reported for in the past.
100 */
101struct channel_detector {
102 struct list_head head;
103 u16 freq;
104 struct pri_detector **detectors;
105};
106
107/* channel_detector_reset() - reset detector lines for a given channel */
108static void channel_detector_reset(struct dfs_pattern_detector *dpd,
109 struct channel_detector *cd)
110{
111 u32 i;
112 if (cd == NULL)
113 return;
114 for (i = 0; i < dpd->num_radar_types; i++)
115 cd->detectors[i]->reset(cd->detectors[i], dpd->last_pulse_ts);
116}
117
118/* channel_detector_exit() - destructor */
119static void channel_detector_exit(struct dfs_pattern_detector *dpd,
120 struct channel_detector *cd)
121{
122 u32 i;
123 if (cd == NULL)
124 return;
125 list_del(&cd->head);
126 for (i = 0; i < dpd->num_radar_types; i++) {
127 struct pri_detector *de = cd->detectors[i];
128 if (de != NULL)
129 de->exit(de);
130 }
131 kfree(cd->detectors);
132 kfree(cd);
133}
134
135static struct channel_detector *
136channel_detector_create(struct dfs_pattern_detector *dpd, u16 freq)
137{
138 u32 sz, i;
139 struct channel_detector *cd;
140
141 cd = kmalloc(sizeof(*cd), GFP_KERNEL);
142 if (cd == NULL)
143 goto fail;
144
145 INIT_LIST_HEAD(&cd->head);
146 cd->freq = freq;
147 sz = sizeof(cd->detectors) * dpd->num_radar_types;
148 cd->detectors = kzalloc(sz, GFP_KERNEL);
149 if (cd->detectors == NULL)
150 goto fail;
151
152 for (i = 0; i < dpd->num_radar_types; i++) {
153 const struct radar_detector_specs *rs = &dpd->radar_spec[i];
154 struct pri_detector *de = pri_detector_init(rs);
155 if (de == NULL)
156 goto fail;
157 cd->detectors[i] = de;
158 }
159 list_add(&cd->head, &dpd->channel_detectors);
160 return cd;
161
162fail:
163 pr_err("failed to allocate channel_detector for freq=%d\n", freq);
164 channel_detector_exit(dpd, cd);
165 return NULL;
166}
167
168/**
169 * channel_detector_get() - get channel detector for given frequency
170 * @param dpd instance pointer
171 * @param freq frequency in MHz
172 * @return pointer to channel detector on success, NULL otherwise
173 *
174 * Return existing channel detector for the given frequency or return a
175 * newly create one.
176 */
177static struct channel_detector *
178channel_detector_get(struct dfs_pattern_detector *dpd, u16 freq)
179{
180 struct channel_detector *cd;
181 list_for_each_entry(cd, &dpd->channel_detectors, head) {
182 if (cd->freq == freq)
183 return cd;
184 }
185 return channel_detector_create(dpd, freq);
186}
187
188/*
189 * DFS Pattern Detector
190 */
191
192/* dpd_reset(): reset all channel detectors */
193static void dpd_reset(struct dfs_pattern_detector *dpd)
194{
195 struct channel_detector *cd;
196 if (!list_empty(&dpd->channel_detectors))
197 list_for_each_entry(cd, &dpd->channel_detectors, head)
198 channel_detector_reset(dpd, cd);
199
200}
201static void dpd_exit(struct dfs_pattern_detector *dpd)
202{
203 struct channel_detector *cd, *cd0;
204 if (!list_empty(&dpd->channel_detectors))
205 list_for_each_entry_safe(cd, cd0, &dpd->channel_detectors, head)
206 channel_detector_exit(dpd, cd);
207 kfree(dpd);
208}
209
210static bool
211dpd_add_pulse(struct dfs_pattern_detector *dpd, struct pulse_event *event)
212{
213 u32 i;
214 bool ts_wraparound;
215 struct channel_detector *cd;
216
217 if (dpd->region == NL80211_DFS_UNSET) {
218 /*
219 * pulses received for a non-supported or un-initialized
220 * domain are treated as detected radars
221 */
222 return true;
223 }
224
225 cd = channel_detector_get(dpd, event->freq);
226 if (cd == NULL)
227 return false;
228
229 ts_wraparound = (event->ts < dpd->last_pulse_ts);
230 dpd->last_pulse_ts = event->ts;
231 if (ts_wraparound) {
232 /*
233 * reset detector on time stamp wraparound
234 * with monotonic time stamps, this should never happen
235 */
236 pr_warn("DFS: time stamp wraparound detected, resetting\n");
237 dpd_reset(dpd);
238 }
239 /* do type individual pattern matching */
240 for (i = 0; i < dpd->num_radar_types; i++) {
241 if (cd->detectors[i]->add_pulse(cd->detectors[i], event) != 0) {
242 channel_detector_reset(dpd, cd);
243 return true;
244 }
245 }
246 return false;
247}
248
249static bool dpd_set_domain(struct dfs_pattern_detector *dpd,
250 enum nl80211_dfs_regions region)
251{
252 const struct radar_types *rt;
253 struct channel_detector *cd, *cd0;
254
255 if (dpd->region == region)
256 return true;
257
258 dpd->region = NL80211_DFS_UNSET;
259
260 rt = get_dfs_domain_radar_types(region);
261 if (rt == NULL)
262 return false;
263
264 /* delete all channel detectors for previous DFS domain */
265 if (!list_empty(&dpd->channel_detectors))
266 list_for_each_entry_safe(cd, cd0, &dpd->channel_detectors, head)
267 channel_detector_exit(dpd, cd);
268 dpd->radar_spec = rt->radar_types;
269 dpd->num_radar_types = rt->num_radar_types;
270
271 dpd->region = region;
272 return true;
273}
274
275static struct dfs_pattern_detector default_dpd = {
276 .exit = dpd_exit,
277 .set_domain = dpd_set_domain,
278 .add_pulse = dpd_add_pulse,
279 .region = NL80211_DFS_UNSET,
280};
281
282struct dfs_pattern_detector *
283dfs_pattern_detector_init(enum nl80211_dfs_regions region)
284{
285 struct dfs_pattern_detector *dpd;
286 dpd = kmalloc(sizeof(*dpd), GFP_KERNEL);
287 if (dpd == NULL) {
288 pr_err("allocation of dfs_pattern_detector failed\n");
289 return NULL;
290 }
291 *dpd = default_dpd;
292 INIT_LIST_HEAD(&dpd->channel_detectors);
293
294 if (dpd->set_domain(dpd, region))
295 return dpd;
296
297 pr_err("Could not set DFS domain to %d. ", region);
298 return NULL;
299}
300EXPORT_SYMBOL(dfs_pattern_detector_init);
diff --git a/drivers/net/wireless/ath/ath9k/dfs_pattern_detector.h b/drivers/net/wireless/ath/ath9k/dfs_pattern_detector.h
new file mode 100644
index 000000000000..fd0328a30995
--- /dev/null
+++ b/drivers/net/wireless/ath/ath9k/dfs_pattern_detector.h
@@ -0,0 +1,104 @@
1/*
2 * Copyright (c) 2012 Neratec Solutions AG
3 *
4 * Permission to use, copy, modify, and/or distribute this software for any
5 * purpose with or without fee is hereby granted, provided that the above
6 * copyright notice and this permission notice appear in all copies.
7 *
8 * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
9 * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
10 * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
11 * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
12 * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
13 * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
14 * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
15 */
16
17#ifndef DFS_PATTERN_DETECTOR_H
18#define DFS_PATTERN_DETECTOR_H
19
20#include <linux/types.h>
21#include <linux/list.h>
22#include <linux/nl80211.h>
23
24/**
25 * struct pulse_event - describing pulses reported by PHY
26 * @ts: pulse time stamp in us
27 * @freq: channel frequency in MHz
28 * @width: pulse duration in us
29 * @rssi: rssi of radar event
30 */
31struct pulse_event {
32 u64 ts;
33 u16 freq;
34 u8 width;
35 u8 rssi;
36};
37
38/**
39 * struct radar_detector_specs - detector specs for a radar pattern type
40 * @type_id: pattern type, as defined by regulatory
41 * @width_min: minimum radar pulse width in [us]
42 * @width_max: maximum radar pulse width in [us]
43 * @pri_min: minimum pulse repetition interval in [us] (including tolerance)
44 * @pri_max: minimum pri in [us] (including tolerance)
45 * @num_pri: maximum number of different pri for this type
46 * @ppb: pulses per bursts for this type
47 * @ppb_thresh: number of pulses required to trigger detection
48 * @max_pri_tolerance: pulse time stamp tolerance on both sides [us]
49 */
50struct radar_detector_specs {
51 u8 type_id;
52 u8 width_min;
53 u8 width_max;
54 u16 pri_min;
55 u16 pri_max;
56 u8 num_pri;
57 u8 ppb;
58 u8 ppb_thresh;
59 u8 max_pri_tolerance;
60};
61
62/**
63 * struct dfs_pattern_detector - DFS pattern detector
64 * @exit(): destructor
65 * @set_domain(): set DFS domain, resets detector lines upon domain changes
66 * @add_pulse(): add radar pulse to detector, returns true on detection
67 * @region: active DFS region, NL80211_DFS_UNSET until set
68 * @num_radar_types: number of different radar types
69 * @last_pulse_ts: time stamp of last valid pulse in usecs
70 * @radar_detector_specs: array of radar detection specs
71 * @channel_detectors: list connecting channel_detector elements
72 */
73struct dfs_pattern_detector {
74 void (*exit)(struct dfs_pattern_detector *dpd);
75 bool (*set_domain)(struct dfs_pattern_detector *dpd,
76 enum nl80211_dfs_regions region);
77 bool (*add_pulse)(struct dfs_pattern_detector *dpd,
78 struct pulse_event *pe);
79
80 enum nl80211_dfs_regions region;
81 u8 num_radar_types;
82 u64 last_pulse_ts;
83
84 const struct radar_detector_specs *radar_spec;
85 struct list_head channel_detectors;
86};
87
88/**
89 * dfs_pattern_detector_init() - constructor for pattern detector class
90 * @param region: DFS domain to be used, can be NL80211_DFS_UNSET at creation
91 * @return instance pointer on success, NULL otherwise
92 */
93#if defined(CONFIG_ATH9K_DFS_CERTIFIED)
94extern struct dfs_pattern_detector *
95dfs_pattern_detector_init(enum nl80211_dfs_regions region);
96#else
97static inline struct dfs_pattern_detector *
98dfs_pattern_detector_init(enum nl80211_dfs_regions region)
99{
100 return NULL;
101}
102#endif /* CONFIG_ATH9K_DFS_CERTIFIED */
103
104#endif /* DFS_PATTERN_DETECTOR_H */
diff --git a/drivers/net/wireless/ath/ath9k/dfs_pri_detector.c b/drivers/net/wireless/ath/ath9k/dfs_pri_detector.c
new file mode 100644
index 000000000000..025e88a64fa4
--- /dev/null
+++ b/drivers/net/wireless/ath/ath9k/dfs_pri_detector.c
@@ -0,0 +1,390 @@
1/*
2 * Copyright (c) 2012 Neratec Solutions AG
3 *
4 * Permission to use, copy, modify, and/or distribute this software for any
5 * purpose with or without fee is hereby granted, provided that the above
6 * copyright notice and this permission notice appear in all copies.
7 *
8 * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
9 * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
10 * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
11 * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
12 * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
13 * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
14 * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
15 */
16
17#include <linux/slab.h>
18
19#include "dfs_pattern_detector.h"
20#include "dfs_pri_detector.h"
21
22/**
23 * struct pri_sequence - sequence of pulses matching one PRI
24 * @head: list_head
25 * @pri: pulse repetition interval (PRI) in usecs
26 * @dur: duration of sequence in usecs
27 * @count: number of pulses in this sequence
28 * @count_falses: number of not matching pulses in this sequence
29 * @first_ts: time stamp of first pulse in usecs
30 * @last_ts: time stamp of last pulse in usecs
31 * @deadline_ts: deadline when this sequence becomes invalid (first_ts + dur)
32 */
33struct pri_sequence {
34 struct list_head head;
35 u32 pri;
36 u32 dur;
37 u32 count;
38 u32 count_falses;
39 u64 first_ts;
40 u64 last_ts;
41 u64 deadline_ts;
42};
43
44/**
45 * struct pulse_elem - elements in pulse queue
46 * @ts: time stamp in usecs
47 */
48struct pulse_elem {
49 struct list_head head;
50 u64 ts;
51};
52
53/**
54 * pde_get_multiple() - get number of multiples considering a given tolerance
55 * @return factor if abs(val - factor*fraction) <= tolerance, 0 otherwise
56 */
57static u32 pde_get_multiple(u32 val, u32 fraction, u32 tolerance)
58{
59 u32 remainder;
60 u32 factor;
61 u32 delta;
62
63 if (fraction == 0)
64 return 0;
65
66 delta = (val < fraction) ? (fraction - val) : (val - fraction);
67
68 if (delta <= tolerance)
69 /* val and fraction are within tolerance */
70 return 1;
71
72 factor = val / fraction;
73 remainder = val % fraction;
74 if (remainder > tolerance) {
75 /* no exact match */
76 if ((fraction - remainder) <= tolerance)
77 /* remainder is within tolerance */
78 factor++;
79 else
80 factor = 0;
81 }
82 return factor;
83}
84
85/**
86 * DOC: Singleton Pulse and Sequence Pools
87 *
88 * Instances of pri_sequence and pulse_elem are kept in singleton pools to
89 * reduce the number of dynamic allocations. They are shared between all
90 * instances and grow up to the peak number of simultaneously used objects.
91 *
92 * Memory is freed after all references to the pools are released.
93 */
94static u32 singleton_pool_references;
95static LIST_HEAD(pulse_pool);
96static LIST_HEAD(pseq_pool);
97
98static struct pulse_elem *pulse_queue_get_tail(struct pri_detector *pde)
99{
100 struct list_head *l = &pde->pulses;
101 if (list_empty(l))
102 return NULL;
103 return list_entry(l->prev, struct pulse_elem, head);
104}
105
106static bool pulse_queue_dequeue(struct pri_detector *pde)
107{
108 struct pulse_elem *p = pulse_queue_get_tail(pde);
109 if (p != NULL) {
110 list_del_init(&p->head);
111 pde->count--;
112 /* give it back to pool */
113 list_add(&p->head, &pulse_pool);
114 }
115 return (pde->count > 0);
116}
117
118/* remove pulses older than window */
119static void pulse_queue_check_window(struct pri_detector *pde)
120{
121 u64 min_valid_ts;
122 struct pulse_elem *p;
123
124 /* there is no delta time with less than 2 pulses */
125 if (pde->count < 2)
126 return;
127
128 if (pde->last_ts <= pde->window_size)
129 return;
130
131 min_valid_ts = pde->last_ts - pde->window_size;
132 while ((p = pulse_queue_get_tail(pde)) != NULL) {
133 if (p->ts >= min_valid_ts)
134 return;
135 pulse_queue_dequeue(pde);
136 }
137}
138
139static bool pulse_queue_enqueue(struct pri_detector *pde, u64 ts)
140{
141 struct pulse_elem *p;
142 if (!list_empty(&pulse_pool)) {
143 p = list_first_entry(&pulse_pool, struct pulse_elem, head);
144 list_del(&p->head);
145 } else {
146 p = kmalloc(sizeof(*p), GFP_KERNEL);
147 if (p == NULL) {
148 pr_err("failed to allocate pulse_elem\n");
149 return false;
150 }
151 }
152 INIT_LIST_HEAD(&p->head);
153 p->ts = ts;
154 list_add(&p->head, &pde->pulses);
155 pde->count++;
156 pde->last_ts = ts;
157 pulse_queue_check_window(pde);
158 if (pde->count >= pde->max_count)
159 pulse_queue_dequeue(pde);
160 return true;
161}
162
163static bool pseq_handler_create_sequences(struct pri_detector *pde,
164 u64 ts, u32 min_count)
165{
166 struct pulse_elem *p;
167 list_for_each_entry(p, &pde->pulses, head) {
168 struct pri_sequence ps, *new_ps;
169 struct pulse_elem *p2;
170 u32 tmp_false_count;
171 u64 min_valid_ts;
172 u32 delta_ts = ts - p->ts;
173
174 if (delta_ts < pde->rs->pri_min)
175 /* ignore too small pri */
176 continue;
177
178 if (delta_ts > pde->rs->pri_max)
179 /* stop on too large pri (sorted list) */
180 break;
181
182 /* build a new sequence with new potential pri */
183 ps.count = 2;
184 ps.count_falses = 0;
185 ps.first_ts = p->ts;
186 ps.last_ts = ts;
187 ps.pri = ts - p->ts;
188 ps.dur = ps.pri * (pde->rs->ppb - 1)
189 + 2 * pde->rs->max_pri_tolerance;
190
191 p2 = p;
192 tmp_false_count = 0;
193 min_valid_ts = ts - ps.dur;
194 /* check which past pulses are candidates for new sequence */
195 list_for_each_entry_continue(p2, &pde->pulses, head) {
196 u32 factor;
197 if (p2->ts < min_valid_ts)
198 /* stop on crossing window border */
199 break;
200 /* check if pulse match (multi)PRI */
201 factor = pde_get_multiple(ps.last_ts - p2->ts, ps.pri,
202 pde->rs->max_pri_tolerance);
203 if (factor > 0) {
204 ps.count++;
205 ps.first_ts = p2->ts;
206 /*
207 * on match, add the intermediate falses
208 * and reset counter
209 */
210 ps.count_falses += tmp_false_count;
211 tmp_false_count = 0;
212 } else {
213 /* this is a potential false one */
214 tmp_false_count++;
215 }
216 }
217 if (ps.count < min_count)
218 /* did not reach minimum count, drop sequence */
219 continue;
220
221 /* this is a valid one, add it */
222 ps.deadline_ts = ps.first_ts + ps.dur;
223
224 if (!list_empty(&pseq_pool)) {
225 new_ps = list_first_entry(&pseq_pool,
226 struct pri_sequence, head);
227 list_del(&new_ps->head);
228 } else {
229 new_ps = kmalloc(sizeof(*new_ps), GFP_KERNEL);
230 if (new_ps == NULL)
231 return false;
232 }
233 memcpy(new_ps, &ps, sizeof(ps));
234 INIT_LIST_HEAD(&new_ps->head);
235 list_add(&new_ps->head, &pde->sequences);
236 }
237 return true;
238}
239
240/* check new ts and add to all matching existing sequences */
241static u32
242pseq_handler_add_to_existing_seqs(struct pri_detector *pde, u64 ts)
243{
244 u32 max_count = 0;
245 struct pri_sequence *ps, *ps2;
246 list_for_each_entry_safe(ps, ps2, &pde->sequences, head) {
247 u32 delta_ts;
248 u32 factor;
249
250 /* first ensure that sequence is within window */
251 if (ts > ps->deadline_ts) {
252 list_del_init(&ps->head);
253 list_add(&ps->head, &pseq_pool);
254 continue;
255 }
256
257 delta_ts = ts - ps->last_ts;
258 factor = pde_get_multiple(delta_ts, ps->pri,
259 pde->rs->max_pri_tolerance);
260 if (factor > 0) {
261 ps->last_ts = ts;
262 ps->count++;
263
264 if (max_count < ps->count)
265 max_count = ps->count;
266 } else {
267 ps->count_falses++;
268 }
269 }
270 return max_count;
271}
272
273static struct pri_sequence *
274pseq_handler_check_detection(struct pri_detector *pde)
275{
276 struct pri_sequence *ps;
277
278 if (list_empty(&pde->sequences))
279 return NULL;
280
281 list_for_each_entry(ps, &pde->sequences, head) {
282 /*
283 * we assume to have enough matching confidence if we
284 * 1) have enough pulses
285 * 2) have more matching than false pulses
286 */
287 if ((ps->count >= pde->rs->ppb_thresh) &&
288 (ps->count * pde->rs->num_pri >= ps->count_falses))
289 return ps;
290 }
291 return NULL;
292}
293
294
295/* free pulse queue and sequences list and give objects back to pools */
296static void pri_detector_reset(struct pri_detector *pde, u64 ts)
297{
298 struct pri_sequence *ps, *ps0;
299 struct pulse_elem *p, *p0;
300 list_for_each_entry_safe(ps, ps0, &pde->sequences, head) {
301 list_del_init(&ps->head);
302 list_add(&ps->head, &pseq_pool);
303 }
304 list_for_each_entry_safe(p, p0, &pde->pulses, head) {
305 list_del_init(&p->head);
306 list_add(&p->head, &pulse_pool);
307 }
308 pde->count = 0;
309 pde->last_ts = ts;
310}
311
312static void pri_detector_exit(struct pri_detector *de)
313{
314 pri_detector_reset(de, 0);
315
316 singleton_pool_references--;
317 if (singleton_pool_references == 0) {
318 /* free singleton pools with no references left */
319 struct pri_sequence *ps, *ps0;
320 struct pulse_elem *p, *p0;
321
322 list_for_each_entry_safe(p, p0, &pulse_pool, head) {
323 list_del(&p->head);
324 kfree(p);
325 }
326 list_for_each_entry_safe(ps, ps0, &pseq_pool, head) {
327 list_del(&ps->head);
328 kfree(ps);
329 }
330 }
331 kfree(de);
332}
333
334static bool pri_detector_add_pulse(struct pri_detector *de,
335 struct pulse_event *event)
336{
337 u32 max_updated_seq;
338 struct pri_sequence *ps;
339 u64 ts = event->ts;
340 const struct radar_detector_specs *rs = de->rs;
341
342 /* ignore pulses not within width range */
343 if ((rs->width_min > event->width) || (rs->width_max < event->width))
344 return false;
345
346 if ((ts - de->last_ts) < rs->max_pri_tolerance)
347 /* if delta to last pulse is too short, don't use this pulse */
348 return false;
349 de->last_ts = ts;
350
351 max_updated_seq = pseq_handler_add_to_existing_seqs(de, ts);
352
353 if (!pseq_handler_create_sequences(de, ts, max_updated_seq)) {
354 pr_err("failed to create pulse sequences\n");
355 pri_detector_reset(de, ts);
356 return false;
357 }
358
359 ps = pseq_handler_check_detection(de);
360
361 if (ps != NULL) {
362 pr_info("DFS: radar found: pri=%d, count=%d, count_false=%d\n",
363 ps->pri, ps->count, ps->count_falses);
364 pri_detector_reset(de, ts);
365 return true;
366 }
367 pulse_queue_enqueue(de, ts);
368 return false;
369}
370
371struct pri_detector *
372pri_detector_init(const struct radar_detector_specs *rs)
373{
374 struct pri_detector *de;
375 de = kzalloc(sizeof(*de), GFP_KERNEL);
376 if (de == NULL)
377 return NULL;
378 de->exit = pri_detector_exit;
379 de->add_pulse = pri_detector_add_pulse;
380 de->reset = pri_detector_reset;
381
382 INIT_LIST_HEAD(&de->sequences);
383 INIT_LIST_HEAD(&de->pulses);
384 de->window_size = rs->pri_max * rs->ppb * rs->num_pri;
385 de->max_count = rs->ppb * 2;
386 de->rs = rs;
387
388 singleton_pool_references++;
389 return de;
390}
diff --git a/drivers/net/wireless/ath/ath9k/dfs_pri_detector.h b/drivers/net/wireless/ath/ath9k/dfs_pri_detector.h
new file mode 100644
index 000000000000..81cde9f28e44
--- /dev/null
+++ b/drivers/net/wireless/ath/ath9k/dfs_pri_detector.h
@@ -0,0 +1,52 @@
1/*
2 * Copyright (c) 2012 Neratec Solutions AG
3 *
4 * Permission to use, copy, modify, and/or distribute this software for any
5 * purpose with or without fee is hereby granted, provided that the above
6 * copyright notice and this permission notice appear in all copies.
7 *
8 * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
9 * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
10 * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
11 * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
12 * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
13 * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
14 * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
15 */
16
17#ifndef DFS_PRI_DETECTOR_H
18#define DFS_PRI_DETECTOR_H
19
20#include <linux/list.h>
21
22/**
23 * struct pri_detector - PRI detector element for a dedicated radar type
24 * @exit(): destructor
25 * @add_pulse(): add pulse event, returns true if pattern was detected
26 * @reset(): clear states and reset to given time stamp
27 * @rs: detector specs for this detector element
28 * @last_ts: last pulse time stamp considered for this element in usecs
29 * @sequences: list_head holding potential pulse sequences
30 * @pulses: list connecting pulse_elem objects
31 * @count: number of pulses in queue
32 * @max_count: maximum number of pulses to be queued
33 * @window_size: window size back from newest pulse time stamp in usecs
34 */
35struct pri_detector {
36 void (*exit) (struct pri_detector *de);
37 bool (*add_pulse)(struct pri_detector *de, struct pulse_event *e);
38 void (*reset) (struct pri_detector *de, u64 ts);
39
40/* private: internal use only */
41 const struct radar_detector_specs *rs;
42 u64 last_ts;
43 struct list_head sequences;
44 struct list_head pulses;
45 u32 count;
46 u32 max_count;
47 u32 window_size;
48};
49
50struct pri_detector *pri_detector_init(const struct radar_detector_specs *rs);
51
52#endif /* DFS_PRI_DETECTOR_H */