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