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