root/drivers/net/wireless/ath/dfs_pri_detector.c

/* [<][>][^][v][top][bottom][index][help] */

DEFINITIONS

This source file includes following definitions.
  1. pde_get_multiple
  2. pool_register_ref
  3. pool_deregister_ref
  4. pool_put_pulse_elem
  5. pool_put_pseq_elem
  6. pool_get_pseq_elem
  7. pool_get_pulse_elem
  8. pulse_queue_get_tail
  9. pulse_queue_dequeue
  10. pulse_queue_check_window
  11. pulse_queue_enqueue
  12. pseq_handler_create_sequences
  13. pseq_handler_add_to_existing_seqs
  14. pseq_handler_check_detection
  15. pri_detector_reset
  16. pri_detector_exit
  17. pri_detector_add_pulse
  18. pri_detector_init

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

/* [<][>][^][v][top][bottom][index][help] */