1ad40d3daSJanusz Dziedzic /*
2ad40d3daSJanusz Dziedzic * Copyright (c) 2012 Neratec Solutions AG
3ad40d3daSJanusz Dziedzic *
4ad40d3daSJanusz Dziedzic * Permission to use, copy, modify, and/or distribute this software for any
5ad40d3daSJanusz Dziedzic * purpose with or without fee is hereby granted, provided that the above
6ad40d3daSJanusz Dziedzic * copyright notice and this permission notice appear in all copies.
7ad40d3daSJanusz Dziedzic *
8ad40d3daSJanusz Dziedzic * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
9ad40d3daSJanusz Dziedzic * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
10ad40d3daSJanusz Dziedzic * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
11ad40d3daSJanusz Dziedzic * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
12ad40d3daSJanusz Dziedzic * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
13ad40d3daSJanusz Dziedzic * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
14ad40d3daSJanusz Dziedzic * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
15ad40d3daSJanusz Dziedzic */
16ad40d3daSJanusz Dziedzic
17ad40d3daSJanusz Dziedzic #include <linux/slab.h>
18ad40d3daSJanusz Dziedzic #include <linux/spinlock.h>
19ad40d3daSJanusz Dziedzic
20ad40d3daSJanusz Dziedzic #include "ath.h"
21ad40d3daSJanusz Dziedzic #include "dfs_pattern_detector.h"
22ad40d3daSJanusz Dziedzic #include "dfs_pri_detector.h"
23ad40d3daSJanusz Dziedzic
24ad40d3daSJanusz Dziedzic struct ath_dfs_pool_stats global_dfs_pool_stats = {};
25ad40d3daSJanusz Dziedzic
26ad40d3daSJanusz Dziedzic #define DFS_POOL_STAT_INC(c) (global_dfs_pool_stats.c++)
27ad40d3daSJanusz Dziedzic #define DFS_POOL_STAT_DEC(c) (global_dfs_pool_stats.c--)
2844acedb0SPeter Oh #define GET_PRI_TO_USE(MIN, MAX, RUNTIME) \
2944acedb0SPeter Oh (MIN + PRI_TOLERANCE == MAX - PRI_TOLERANCE ? \
3044acedb0SPeter Oh MIN + PRI_TOLERANCE : RUNTIME)
31ad40d3daSJanusz Dziedzic
32*748d2507SLee Jones /*
33ad40d3daSJanusz Dziedzic * struct pulse_elem - elements in pulse queue
34ad40d3daSJanusz Dziedzic */
35ad40d3daSJanusz Dziedzic struct pulse_elem {
36ad40d3daSJanusz Dziedzic struct list_head head;
37ad40d3daSJanusz Dziedzic u64 ts;
38ad40d3daSJanusz Dziedzic };
39ad40d3daSJanusz Dziedzic
40*748d2507SLee Jones /*
41ad40d3daSJanusz Dziedzic * pde_get_multiple() - get number of multiples considering a given tolerance
42*748d2507SLee Jones * Return value: factor if abs(val - factor*fraction) <= tolerance, 0 otherwise
43ad40d3daSJanusz Dziedzic */
pde_get_multiple(u32 val,u32 fraction,u32 tolerance)44ad40d3daSJanusz Dziedzic static u32 pde_get_multiple(u32 val, u32 fraction, u32 tolerance)
45ad40d3daSJanusz Dziedzic {
46ad40d3daSJanusz Dziedzic u32 remainder;
47ad40d3daSJanusz Dziedzic u32 factor;
48ad40d3daSJanusz Dziedzic u32 delta;
49ad40d3daSJanusz Dziedzic
50ad40d3daSJanusz Dziedzic if (fraction == 0)
51ad40d3daSJanusz Dziedzic return 0;
52ad40d3daSJanusz Dziedzic
53ad40d3daSJanusz Dziedzic delta = (val < fraction) ? (fraction - val) : (val - fraction);
54ad40d3daSJanusz Dziedzic
55ad40d3daSJanusz Dziedzic if (delta <= tolerance)
56ad40d3daSJanusz Dziedzic /* val and fraction are within tolerance */
57ad40d3daSJanusz Dziedzic return 1;
58ad40d3daSJanusz Dziedzic
59ad40d3daSJanusz Dziedzic factor = val / fraction;
60ad40d3daSJanusz Dziedzic remainder = val % fraction;
61ad40d3daSJanusz Dziedzic if (remainder > tolerance) {
62ad40d3daSJanusz Dziedzic /* no exact match */
63ad40d3daSJanusz Dziedzic if ((fraction - remainder) <= tolerance)
64ad40d3daSJanusz Dziedzic /* remainder is within tolerance */
65ad40d3daSJanusz Dziedzic factor++;
66ad40d3daSJanusz Dziedzic else
67ad40d3daSJanusz Dziedzic factor = 0;
68ad40d3daSJanusz Dziedzic }
69ad40d3daSJanusz Dziedzic return factor;
70ad40d3daSJanusz Dziedzic }
71ad40d3daSJanusz Dziedzic
72*748d2507SLee Jones /*
73ad40d3daSJanusz Dziedzic * DOC: Singleton Pulse and Sequence Pools
74ad40d3daSJanusz Dziedzic *
75ad40d3daSJanusz Dziedzic * Instances of pri_sequence and pulse_elem are kept in singleton pools to
76ad40d3daSJanusz Dziedzic * reduce the number of dynamic allocations. They are shared between all
77ad40d3daSJanusz Dziedzic * instances and grow up to the peak number of simultaneously used objects.
78ad40d3daSJanusz Dziedzic *
79ad40d3daSJanusz Dziedzic * Memory is freed after all references to the pools are released.
80ad40d3daSJanusz Dziedzic */
81ad40d3daSJanusz Dziedzic static u32 singleton_pool_references;
82ad40d3daSJanusz Dziedzic static LIST_HEAD(pulse_pool);
83ad40d3daSJanusz Dziedzic static LIST_HEAD(pseq_pool);
84ad40d3daSJanusz Dziedzic static DEFINE_SPINLOCK(pool_lock);
85ad40d3daSJanusz Dziedzic
pool_register_ref(void)86ad40d3daSJanusz Dziedzic static void pool_register_ref(void)
87ad40d3daSJanusz Dziedzic {
88ad40d3daSJanusz Dziedzic spin_lock_bh(&pool_lock);
89ad40d3daSJanusz Dziedzic singleton_pool_references++;
90ad40d3daSJanusz Dziedzic DFS_POOL_STAT_INC(pool_reference);
91ad40d3daSJanusz Dziedzic spin_unlock_bh(&pool_lock);
92ad40d3daSJanusz Dziedzic }
93ad40d3daSJanusz Dziedzic
pool_deregister_ref(void)94ad40d3daSJanusz Dziedzic static void pool_deregister_ref(void)
95ad40d3daSJanusz Dziedzic {
96ad40d3daSJanusz Dziedzic spin_lock_bh(&pool_lock);
97ad40d3daSJanusz Dziedzic singleton_pool_references--;
98ad40d3daSJanusz Dziedzic DFS_POOL_STAT_DEC(pool_reference);
99ad40d3daSJanusz Dziedzic if (singleton_pool_references == 0) {
100ad40d3daSJanusz Dziedzic /* free singleton pools with no references left */
101ad40d3daSJanusz Dziedzic struct pri_sequence *ps, *ps0;
102ad40d3daSJanusz Dziedzic struct pulse_elem *p, *p0;
103ad40d3daSJanusz Dziedzic
104ad40d3daSJanusz Dziedzic list_for_each_entry_safe(p, p0, &pulse_pool, head) {
105ad40d3daSJanusz Dziedzic list_del(&p->head);
106ad40d3daSJanusz Dziedzic DFS_POOL_STAT_DEC(pulse_allocated);
107ad40d3daSJanusz Dziedzic kfree(p);
108ad40d3daSJanusz Dziedzic }
109ad40d3daSJanusz Dziedzic list_for_each_entry_safe(ps, ps0, &pseq_pool, head) {
110ad40d3daSJanusz Dziedzic list_del(&ps->head);
111ad40d3daSJanusz Dziedzic DFS_POOL_STAT_DEC(pseq_allocated);
112ad40d3daSJanusz Dziedzic kfree(ps);
113ad40d3daSJanusz Dziedzic }
114ad40d3daSJanusz Dziedzic }
115ad40d3daSJanusz Dziedzic spin_unlock_bh(&pool_lock);
116ad40d3daSJanusz Dziedzic }
117ad40d3daSJanusz Dziedzic
pool_put_pulse_elem(struct pulse_elem * pe)118ad40d3daSJanusz Dziedzic static void pool_put_pulse_elem(struct pulse_elem *pe)
119ad40d3daSJanusz Dziedzic {
120ad40d3daSJanusz Dziedzic spin_lock_bh(&pool_lock);
121ad40d3daSJanusz Dziedzic list_add(&pe->head, &pulse_pool);
122ad40d3daSJanusz Dziedzic DFS_POOL_STAT_DEC(pulse_used);
123ad40d3daSJanusz Dziedzic spin_unlock_bh(&pool_lock);
124ad40d3daSJanusz Dziedzic }
125ad40d3daSJanusz Dziedzic
pool_put_pseq_elem(struct pri_sequence * pse)126ad40d3daSJanusz Dziedzic static void pool_put_pseq_elem(struct pri_sequence *pse)
127ad40d3daSJanusz Dziedzic {
128ad40d3daSJanusz Dziedzic spin_lock_bh(&pool_lock);
129ad40d3daSJanusz Dziedzic list_add(&pse->head, &pseq_pool);
130ad40d3daSJanusz Dziedzic DFS_POOL_STAT_DEC(pseq_used);
131ad40d3daSJanusz Dziedzic spin_unlock_bh(&pool_lock);
132ad40d3daSJanusz Dziedzic }
133ad40d3daSJanusz Dziedzic
pool_get_pseq_elem(void)134ad40d3daSJanusz Dziedzic static struct pri_sequence *pool_get_pseq_elem(void)
135ad40d3daSJanusz Dziedzic {
136ad40d3daSJanusz Dziedzic struct pri_sequence *pse = NULL;
137ad40d3daSJanusz Dziedzic spin_lock_bh(&pool_lock);
138ad40d3daSJanusz Dziedzic if (!list_empty(&pseq_pool)) {
139ad40d3daSJanusz Dziedzic pse = list_first_entry(&pseq_pool, struct pri_sequence, head);
140ad40d3daSJanusz Dziedzic list_del(&pse->head);
141ad40d3daSJanusz Dziedzic DFS_POOL_STAT_INC(pseq_used);
142ad40d3daSJanusz Dziedzic }
143ad40d3daSJanusz Dziedzic spin_unlock_bh(&pool_lock);
144ad40d3daSJanusz Dziedzic return pse;
145ad40d3daSJanusz Dziedzic }
146ad40d3daSJanusz Dziedzic
pool_get_pulse_elem(void)147ad40d3daSJanusz Dziedzic static struct pulse_elem *pool_get_pulse_elem(void)
148ad40d3daSJanusz Dziedzic {
149ad40d3daSJanusz Dziedzic struct pulse_elem *pe = NULL;
150ad40d3daSJanusz Dziedzic spin_lock_bh(&pool_lock);
151ad40d3daSJanusz Dziedzic if (!list_empty(&pulse_pool)) {
152ad40d3daSJanusz Dziedzic pe = list_first_entry(&pulse_pool, struct pulse_elem, head);
153ad40d3daSJanusz Dziedzic list_del(&pe->head);
154ad40d3daSJanusz Dziedzic DFS_POOL_STAT_INC(pulse_used);
155ad40d3daSJanusz Dziedzic }
156ad40d3daSJanusz Dziedzic spin_unlock_bh(&pool_lock);
157ad40d3daSJanusz Dziedzic return pe;
158ad40d3daSJanusz Dziedzic }
159ad40d3daSJanusz Dziedzic
pulse_queue_get_tail(struct pri_detector * pde)160ad40d3daSJanusz Dziedzic static struct pulse_elem *pulse_queue_get_tail(struct pri_detector *pde)
161ad40d3daSJanusz Dziedzic {
162ad40d3daSJanusz Dziedzic struct list_head *l = &pde->pulses;
163ad40d3daSJanusz Dziedzic if (list_empty(l))
164ad40d3daSJanusz Dziedzic return NULL;
165ad40d3daSJanusz Dziedzic return list_entry(l->prev, struct pulse_elem, head);
166ad40d3daSJanusz Dziedzic }
167ad40d3daSJanusz Dziedzic
pulse_queue_dequeue(struct pri_detector * pde)168ad40d3daSJanusz Dziedzic static bool pulse_queue_dequeue(struct pri_detector *pde)
169ad40d3daSJanusz Dziedzic {
170ad40d3daSJanusz Dziedzic struct pulse_elem *p = pulse_queue_get_tail(pde);
171ad40d3daSJanusz Dziedzic if (p != NULL) {
172ad40d3daSJanusz Dziedzic list_del_init(&p->head);
173ad40d3daSJanusz Dziedzic pde->count--;
174ad40d3daSJanusz Dziedzic /* give it back to pool */
175ad40d3daSJanusz Dziedzic pool_put_pulse_elem(p);
176ad40d3daSJanusz Dziedzic }
177ad40d3daSJanusz Dziedzic return (pde->count > 0);
178ad40d3daSJanusz Dziedzic }
179ad40d3daSJanusz Dziedzic
180ad40d3daSJanusz Dziedzic /* remove pulses older than window */
pulse_queue_check_window(struct pri_detector * pde)181ad40d3daSJanusz Dziedzic static void pulse_queue_check_window(struct pri_detector *pde)
182ad40d3daSJanusz Dziedzic {
183ad40d3daSJanusz Dziedzic u64 min_valid_ts;
184ad40d3daSJanusz Dziedzic struct pulse_elem *p;
185ad40d3daSJanusz Dziedzic
186ad40d3daSJanusz Dziedzic /* there is no delta time with less than 2 pulses */
187ad40d3daSJanusz Dziedzic if (pde->count < 2)
188ad40d3daSJanusz Dziedzic return;
189ad40d3daSJanusz Dziedzic
190ad40d3daSJanusz Dziedzic if (pde->last_ts <= pde->window_size)
191ad40d3daSJanusz Dziedzic return;
192ad40d3daSJanusz Dziedzic
193ad40d3daSJanusz Dziedzic min_valid_ts = pde->last_ts - pde->window_size;
194ad40d3daSJanusz Dziedzic while ((p = pulse_queue_get_tail(pde)) != NULL) {
195ad40d3daSJanusz Dziedzic if (p->ts >= min_valid_ts)
196ad40d3daSJanusz Dziedzic return;
197ad40d3daSJanusz Dziedzic pulse_queue_dequeue(pde);
198ad40d3daSJanusz Dziedzic }
199ad40d3daSJanusz Dziedzic }
200ad40d3daSJanusz Dziedzic
pulse_queue_enqueue(struct pri_detector * pde,u64 ts)201ad40d3daSJanusz Dziedzic static bool pulse_queue_enqueue(struct pri_detector *pde, u64 ts)
202ad40d3daSJanusz Dziedzic {
203ad40d3daSJanusz Dziedzic struct pulse_elem *p = pool_get_pulse_elem();
204ad40d3daSJanusz Dziedzic if (p == NULL) {
205ad40d3daSJanusz Dziedzic p = kmalloc(sizeof(*p), GFP_ATOMIC);
206ad40d3daSJanusz Dziedzic if (p == NULL) {
207ad40d3daSJanusz Dziedzic DFS_POOL_STAT_INC(pulse_alloc_error);
208ad40d3daSJanusz Dziedzic return false;
209ad40d3daSJanusz Dziedzic }
210ad40d3daSJanusz Dziedzic DFS_POOL_STAT_INC(pulse_allocated);
211ad40d3daSJanusz Dziedzic DFS_POOL_STAT_INC(pulse_used);
212ad40d3daSJanusz Dziedzic }
213ad40d3daSJanusz Dziedzic INIT_LIST_HEAD(&p->head);
214ad40d3daSJanusz Dziedzic p->ts = ts;
215ad40d3daSJanusz Dziedzic list_add(&p->head, &pde->pulses);
216ad40d3daSJanusz Dziedzic pde->count++;
217ad40d3daSJanusz Dziedzic pde->last_ts = ts;
218ad40d3daSJanusz Dziedzic pulse_queue_check_window(pde);
219ad40d3daSJanusz Dziedzic if (pde->count >= pde->max_count)
220ad40d3daSJanusz Dziedzic pulse_queue_dequeue(pde);
221ad40d3daSJanusz Dziedzic return true;
222ad40d3daSJanusz Dziedzic }
223ad40d3daSJanusz Dziedzic
pseq_handler_create_sequences(struct pri_detector * pde,u64 ts,u32 min_count)224ad40d3daSJanusz Dziedzic static bool pseq_handler_create_sequences(struct pri_detector *pde,
225ad40d3daSJanusz Dziedzic u64 ts, u32 min_count)
226ad40d3daSJanusz Dziedzic {
227ad40d3daSJanusz Dziedzic struct pulse_elem *p;
228ad40d3daSJanusz Dziedzic list_for_each_entry(p, &pde->pulses, head) {
229ad40d3daSJanusz Dziedzic struct pri_sequence ps, *new_ps;
230ad40d3daSJanusz Dziedzic struct pulse_elem *p2;
231ad40d3daSJanusz Dziedzic u32 tmp_false_count;
232ad40d3daSJanusz Dziedzic u64 min_valid_ts;
233ad40d3daSJanusz Dziedzic u32 delta_ts = ts - p->ts;
234ad40d3daSJanusz Dziedzic
235ad40d3daSJanusz Dziedzic if (delta_ts < pde->rs->pri_min)
236ad40d3daSJanusz Dziedzic /* ignore too small pri */
237ad40d3daSJanusz Dziedzic continue;
238ad40d3daSJanusz Dziedzic
239ad40d3daSJanusz Dziedzic if (delta_ts > pde->rs->pri_max)
240ad40d3daSJanusz Dziedzic /* stop on too large pri (sorted list) */
241ad40d3daSJanusz Dziedzic break;
242ad40d3daSJanusz Dziedzic
243ad40d3daSJanusz Dziedzic /* build a new sequence with new potential pri */
244ad40d3daSJanusz Dziedzic ps.count = 2;
245ad40d3daSJanusz Dziedzic ps.count_falses = 0;
246ad40d3daSJanusz Dziedzic ps.first_ts = p->ts;
247ad40d3daSJanusz Dziedzic ps.last_ts = ts;
24844acedb0SPeter Oh ps.pri = GET_PRI_TO_USE(pde->rs->pri_min,
24944acedb0SPeter Oh pde->rs->pri_max, ts - p->ts);
250ad40d3daSJanusz Dziedzic ps.dur = ps.pri * (pde->rs->ppb - 1)
251ad40d3daSJanusz Dziedzic + 2 * pde->rs->max_pri_tolerance;
252ad40d3daSJanusz Dziedzic
253ad40d3daSJanusz Dziedzic p2 = p;
254ad40d3daSJanusz Dziedzic tmp_false_count = 0;
255ad40d3daSJanusz Dziedzic min_valid_ts = ts - ps.dur;
256ad40d3daSJanusz Dziedzic /* check which past pulses are candidates for new sequence */
257ad40d3daSJanusz Dziedzic list_for_each_entry_continue(p2, &pde->pulses, head) {
258ad40d3daSJanusz Dziedzic u32 factor;
259ad40d3daSJanusz Dziedzic if (p2->ts < min_valid_ts)
260ad40d3daSJanusz Dziedzic /* stop on crossing window border */
261ad40d3daSJanusz Dziedzic break;
262ad40d3daSJanusz Dziedzic /* check if pulse match (multi)PRI */
263ad40d3daSJanusz Dziedzic factor = pde_get_multiple(ps.last_ts - p2->ts, ps.pri,
264ad40d3daSJanusz Dziedzic pde->rs->max_pri_tolerance);
265ad40d3daSJanusz Dziedzic if (factor > 0) {
266ad40d3daSJanusz Dziedzic ps.count++;
267ad40d3daSJanusz Dziedzic ps.first_ts = p2->ts;
268ad40d3daSJanusz Dziedzic /*
269ad40d3daSJanusz Dziedzic * on match, add the intermediate falses
270ad40d3daSJanusz Dziedzic * and reset counter
271ad40d3daSJanusz Dziedzic */
272ad40d3daSJanusz Dziedzic ps.count_falses += tmp_false_count;
273ad40d3daSJanusz Dziedzic tmp_false_count = 0;
274ad40d3daSJanusz Dziedzic } else {
275ad40d3daSJanusz Dziedzic /* this is a potential false one */
276ad40d3daSJanusz Dziedzic tmp_false_count++;
277ad40d3daSJanusz Dziedzic }
278ad40d3daSJanusz Dziedzic }
279b24fc6fcSZefir Kurtisi if (ps.count <= min_count)
280ad40d3daSJanusz Dziedzic /* did not reach minimum count, drop sequence */
281ad40d3daSJanusz Dziedzic continue;
282ad40d3daSJanusz Dziedzic
283ad40d3daSJanusz Dziedzic /* this is a valid one, add it */
284ad40d3daSJanusz Dziedzic ps.deadline_ts = ps.first_ts + ps.dur;
285ad40d3daSJanusz Dziedzic new_ps = pool_get_pseq_elem();
286ad40d3daSJanusz Dziedzic if (new_ps == NULL) {
287ad40d3daSJanusz Dziedzic new_ps = kmalloc(sizeof(*new_ps), GFP_ATOMIC);
288ad40d3daSJanusz Dziedzic if (new_ps == NULL) {
289ad40d3daSJanusz Dziedzic DFS_POOL_STAT_INC(pseq_alloc_error);
290ad40d3daSJanusz Dziedzic return false;
291ad40d3daSJanusz Dziedzic }
292ad40d3daSJanusz Dziedzic DFS_POOL_STAT_INC(pseq_allocated);
293ad40d3daSJanusz Dziedzic DFS_POOL_STAT_INC(pseq_used);
294ad40d3daSJanusz Dziedzic }
295ad40d3daSJanusz Dziedzic memcpy(new_ps, &ps, sizeof(ps));
296ad40d3daSJanusz Dziedzic INIT_LIST_HEAD(&new_ps->head);
297ad40d3daSJanusz Dziedzic list_add(&new_ps->head, &pde->sequences);
298ad40d3daSJanusz Dziedzic }
299ad40d3daSJanusz Dziedzic return true;
300ad40d3daSJanusz Dziedzic }
301ad40d3daSJanusz Dziedzic
302ad40d3daSJanusz Dziedzic /* check new ts and add to all matching existing sequences */
303ad40d3daSJanusz Dziedzic static u32
pseq_handler_add_to_existing_seqs(struct pri_detector * pde,u64 ts)304ad40d3daSJanusz Dziedzic pseq_handler_add_to_existing_seqs(struct pri_detector *pde, u64 ts)
305ad40d3daSJanusz Dziedzic {
306ad40d3daSJanusz Dziedzic u32 max_count = 0;
307ad40d3daSJanusz Dziedzic struct pri_sequence *ps, *ps2;
308ad40d3daSJanusz Dziedzic list_for_each_entry_safe(ps, ps2, &pde->sequences, head) {
309ad40d3daSJanusz Dziedzic u32 delta_ts;
310ad40d3daSJanusz Dziedzic u32 factor;
311ad40d3daSJanusz Dziedzic
312ad40d3daSJanusz Dziedzic /* first ensure that sequence is within window */
313ad40d3daSJanusz Dziedzic if (ts > ps->deadline_ts) {
314ad40d3daSJanusz Dziedzic list_del_init(&ps->head);
315ad40d3daSJanusz Dziedzic pool_put_pseq_elem(ps);
316ad40d3daSJanusz Dziedzic continue;
317ad40d3daSJanusz Dziedzic }
318ad40d3daSJanusz Dziedzic
319ad40d3daSJanusz Dziedzic delta_ts = ts - ps->last_ts;
320ad40d3daSJanusz Dziedzic factor = pde_get_multiple(delta_ts, ps->pri,
321ad40d3daSJanusz Dziedzic pde->rs->max_pri_tolerance);
322ad40d3daSJanusz Dziedzic if (factor > 0) {
323ad40d3daSJanusz Dziedzic ps->last_ts = ts;
324ad40d3daSJanusz Dziedzic ps->count++;
325ad40d3daSJanusz Dziedzic
326ad40d3daSJanusz Dziedzic if (max_count < ps->count)
327ad40d3daSJanusz Dziedzic max_count = ps->count;
328ad40d3daSJanusz Dziedzic } else {
329ad40d3daSJanusz Dziedzic ps->count_falses++;
330ad40d3daSJanusz Dziedzic }
331ad40d3daSJanusz Dziedzic }
332ad40d3daSJanusz Dziedzic return max_count;
333ad40d3daSJanusz Dziedzic }
334ad40d3daSJanusz Dziedzic
335ad40d3daSJanusz Dziedzic static struct pri_sequence *
pseq_handler_check_detection(struct pri_detector * pde)336ad40d3daSJanusz Dziedzic pseq_handler_check_detection(struct pri_detector *pde)
337ad40d3daSJanusz Dziedzic {
338ad40d3daSJanusz Dziedzic struct pri_sequence *ps;
339ad40d3daSJanusz Dziedzic
340ad40d3daSJanusz Dziedzic if (list_empty(&pde->sequences))
341ad40d3daSJanusz Dziedzic return NULL;
342ad40d3daSJanusz Dziedzic
343ad40d3daSJanusz Dziedzic list_for_each_entry(ps, &pde->sequences, head) {
344ad40d3daSJanusz Dziedzic /*
345ad40d3daSJanusz Dziedzic * we assume to have enough matching confidence if we
346ad40d3daSJanusz Dziedzic * 1) have enough pulses
347ad40d3daSJanusz Dziedzic * 2) have more matching than false pulses
348ad40d3daSJanusz Dziedzic */
349ad40d3daSJanusz Dziedzic if ((ps->count >= pde->rs->ppb_thresh) &&
350ad40d3daSJanusz Dziedzic (ps->count * pde->rs->num_pri >= ps->count_falses))
351ad40d3daSJanusz Dziedzic return ps;
352ad40d3daSJanusz Dziedzic }
353ad40d3daSJanusz Dziedzic return NULL;
354ad40d3daSJanusz Dziedzic }
355ad40d3daSJanusz Dziedzic
356ad40d3daSJanusz Dziedzic
357ad40d3daSJanusz Dziedzic /* free pulse queue and sequences list and give objects back to pools */
pri_detector_reset(struct pri_detector * pde,u64 ts)358ad40d3daSJanusz Dziedzic static void pri_detector_reset(struct pri_detector *pde, u64 ts)
359ad40d3daSJanusz Dziedzic {
360ad40d3daSJanusz Dziedzic struct pri_sequence *ps, *ps0;
361ad40d3daSJanusz Dziedzic struct pulse_elem *p, *p0;
362ad40d3daSJanusz Dziedzic list_for_each_entry_safe(ps, ps0, &pde->sequences, head) {
363ad40d3daSJanusz Dziedzic list_del_init(&ps->head);
364ad40d3daSJanusz Dziedzic pool_put_pseq_elem(ps);
365ad40d3daSJanusz Dziedzic }
366ad40d3daSJanusz Dziedzic list_for_each_entry_safe(p, p0, &pde->pulses, head) {
367ad40d3daSJanusz Dziedzic list_del_init(&p->head);
368ad40d3daSJanusz Dziedzic pool_put_pulse_elem(p);
369ad40d3daSJanusz Dziedzic }
370ad40d3daSJanusz Dziedzic pde->count = 0;
371ad40d3daSJanusz Dziedzic pde->last_ts = ts;
372ad40d3daSJanusz Dziedzic }
373ad40d3daSJanusz Dziedzic
pri_detector_exit(struct pri_detector * de)374ad40d3daSJanusz Dziedzic static void pri_detector_exit(struct pri_detector *de)
375ad40d3daSJanusz Dziedzic {
376ad40d3daSJanusz Dziedzic pri_detector_reset(de, 0);
377ad40d3daSJanusz Dziedzic pool_deregister_ref();
378ad40d3daSJanusz Dziedzic kfree(de);
379ad40d3daSJanusz Dziedzic }
380ad40d3daSJanusz Dziedzic
pri_detector_add_pulse(struct pri_detector * de,struct pulse_event * event)381ad40d3daSJanusz Dziedzic static struct pri_sequence *pri_detector_add_pulse(struct pri_detector *de,
382ad40d3daSJanusz Dziedzic struct pulse_event *event)
383ad40d3daSJanusz Dziedzic {
384ad40d3daSJanusz Dziedzic u32 max_updated_seq;
385ad40d3daSJanusz Dziedzic struct pri_sequence *ps;
386ad40d3daSJanusz Dziedzic u64 ts = event->ts;
387ad40d3daSJanusz Dziedzic const struct radar_detector_specs *rs = de->rs;
388ad40d3daSJanusz Dziedzic
389ad40d3daSJanusz Dziedzic /* ignore pulses not within width range */
390ad40d3daSJanusz Dziedzic if ((rs->width_min > event->width) || (rs->width_max < event->width))
391ad40d3daSJanusz Dziedzic return NULL;
392ad40d3daSJanusz Dziedzic
393ad40d3daSJanusz Dziedzic if ((ts - de->last_ts) < rs->max_pri_tolerance)
394ad40d3daSJanusz Dziedzic /* if delta to last pulse is too short, don't use this pulse */
395ad40d3daSJanusz Dziedzic return NULL;
396dab74cdeSPeter Oh /* radar detector spec needs chirp, but not detected */
397dab74cdeSPeter Oh if (rs->chirp && rs->chirp != event->chirp)
398dab74cdeSPeter Oh return NULL;
399dab74cdeSPeter Oh
400ad40d3daSJanusz Dziedzic de->last_ts = ts;
401ad40d3daSJanusz Dziedzic
402ad40d3daSJanusz Dziedzic max_updated_seq = pseq_handler_add_to_existing_seqs(de, ts);
403ad40d3daSJanusz Dziedzic
404ad40d3daSJanusz Dziedzic if (!pseq_handler_create_sequences(de, ts, max_updated_seq)) {
405ad40d3daSJanusz Dziedzic pri_detector_reset(de, ts);
406ad40d3daSJanusz Dziedzic return NULL;
407ad40d3daSJanusz Dziedzic }
408ad40d3daSJanusz Dziedzic
409ad40d3daSJanusz Dziedzic ps = pseq_handler_check_detection(de);
410ad40d3daSJanusz Dziedzic
411ad40d3daSJanusz Dziedzic if (ps == NULL)
412ad40d3daSJanusz Dziedzic pulse_queue_enqueue(de, ts);
413ad40d3daSJanusz Dziedzic
414ad40d3daSJanusz Dziedzic return ps;
415ad40d3daSJanusz Dziedzic }
416ad40d3daSJanusz Dziedzic
pri_detector_init(const struct radar_detector_specs * rs)417ad40d3daSJanusz Dziedzic struct pri_detector *pri_detector_init(const struct radar_detector_specs *rs)
418ad40d3daSJanusz Dziedzic {
419ad40d3daSJanusz Dziedzic struct pri_detector *de;
420ad40d3daSJanusz Dziedzic
421ad40d3daSJanusz Dziedzic de = kzalloc(sizeof(*de), GFP_ATOMIC);
422ad40d3daSJanusz Dziedzic if (de == NULL)
423ad40d3daSJanusz Dziedzic return NULL;
424ad40d3daSJanusz Dziedzic de->exit = pri_detector_exit;
425ad40d3daSJanusz Dziedzic de->add_pulse = pri_detector_add_pulse;
426ad40d3daSJanusz Dziedzic de->reset = pri_detector_reset;
427ad40d3daSJanusz Dziedzic
428ad40d3daSJanusz Dziedzic INIT_LIST_HEAD(&de->sequences);
429ad40d3daSJanusz Dziedzic INIT_LIST_HEAD(&de->pulses);
430ad40d3daSJanusz Dziedzic de->window_size = rs->pri_max * rs->ppb * rs->num_pri;
431ad40d3daSJanusz Dziedzic de->max_count = rs->ppb * 2;
432ad40d3daSJanusz Dziedzic de->rs = rs;
433ad40d3daSJanusz Dziedzic
434ad40d3daSJanusz Dziedzic pool_register_ref();
435ad40d3daSJanusz Dziedzic return de;
436ad40d3daSJanusz Dziedzic }
437