update madwifi
[linux-2.6/zen-sources.git] / drivers / net / wireless / madwifi / ath / if_ath_radar.c
blob19169015dab06accd1a8c976a640d35cd189873f
1 /*
2 * This software is distributed under the terms of the
3 * GNU General Public License ("GPL") version 2 as published by the Free
4 * Software Foundation.
6 * NO WARRANTY
7 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
8 * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
9 * LIMITED TO, THE IMPLIED WARRANTIES OF NONINFRINGEMENT, MERCHANTIBILITY
10 * AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL
11 * THE COPYRIGHT HOLDERS OR CONTRIBUTORS BE LIABLE FOR SPECIAL, EXEMPLARY,
12 * OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
13 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
14 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER
15 * IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
16 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
17 * THE POSSIBILITY OF SUCH DAMAGES.
19 * $Id: if_ath_radar.c 2464 2007-06-15 22:51:56Z mtaylor $
21 #include "opt_ah.h"
23 #include "if_ath_debug.h"
25 #ifndef AUTOCONF_INCLUDED
26 #include <linux/config.h>
27 #endif
28 #include <linux/version.h>
29 #include <linux/module.h>
30 #include <linux/init.h>
31 #include <linux/skbuff.h>
32 #include <linux/netdevice.h>
33 #include <linux/etherdevice.h>
34 #include <linux/random.h>
35 #include <linux/delay.h>
36 #include <linux/cache.h>
37 #include <linux/sysctl.h>
38 #include <linux/proc_fs.h>
39 #include <linux/if_arp.h>
40 #include <linux/rtnetlink.h>
41 #include <linux/time.h>
42 #include <asm/uaccess.h>
43 #include <linux/param.h>
45 #include "if_ethersubr.h" /* for ETHER_IS_MULTICAST */
46 #include "if_media.h"
47 #include "if_llc.h"
49 #include <net80211/ieee80211_radiotap.h>
50 #include <net80211/ieee80211_var.h>
51 #include <net80211/ieee80211_monitor.h>
52 #include <net80211/ieee80211_rate.h>
54 #ifdef USE_HEADERLEN_RESV
55 #include <net80211/if_llc.h>
56 #endif
58 #include "net80211/if_athproto.h"
59 #include "if_athvar.h"
61 #include "ah_desc.h"
63 #include "ah_devid.h" /* XXX to identify chipset */
65 #ifdef ATH_PCI /* PCI BUS */
66 #include "if_ath_pci.h"
67 #endif /* PCI BUS */
68 #ifdef ATH_AHB /* AHB BUS */
69 #include "if_ath_ahb.h"
70 #endif /* AHB BUS */
72 #undef MAX
73 #define MAX(a, b) (((a) > (b)) ? (a) : (b))
75 #undef MIN
76 #define MIN(a, b) (((a) < (b)) ? (a) : (b))
78 #include "ah.h"
79 #include "if_ath_hal.h"
81 #ifdef ATH_TX99_DIAG
82 #include "ath_tx99.h"
83 #endif
85 #include "ah_os.h"
86 #include "if_ath_radar.h"
88 #define sizetab(t) (sizeof(t)/sizeof(t[0]))
89 #define nofloat_pct(_value, _pct) \
90 ( (_value * (1000 + _pct)) / 1000 )
92 struct radar_pattern_specification {
93 /* The name of the rule/specification (i.e. what did we detect) */
94 const char *name;
95 /* Interval MIN = 1000000 / FREQ - 2%
96 * (a.k.a. Pulse/Burst Repetition Interval) */
97 u_int32_t min_rep_int;
98 /* Interval MAX = 1000000 / FREQ + 2%
99 * (a.k.a. Pulse/Burst Repetition Interval) */
100 u_int32_t max_rep_int;
101 /* Do we adjust the min/max interval values dynamically
102 * based upon running mean interval? */
103 HAL_BOOL dyn_ints;
104 /* Fuzz factor dynamic matching, as unsigned integer percentage
105 * of variation (i.e. 2 for +/- 2% timing) */
106 u_int32_t fuzz_pct;
107 /* Match MIN (Minimum Pulse/Burst events required) */
108 u_int32_t min_pulse;
109 /* Match MIN duration (Minimum Pulse/Burst events
110 * required including missed) */
111 u_int32_t min_evts;
112 /* Match MAX duration (Maximum Pulse/Burst events
113 * required including missed) */
114 u_int32_t max_evts;
115 /* Maximum consecutive missing pulses */
116 u_int32_t max_consecutive_missing;
117 /* Maximum missing pulses */
118 u_int32_t max_missing;
119 /* Match on absolute distance to PRI/PRF midpoint */
120 HAL_BOOL match_midpoint;
123 static struct radar_pattern_specification radar_patterns[] = {
124 #ifdef DFS_DOMAIN_ETSI
125 {"ETSI [ 200]", 4900, 5100, AH_FALSE, 20, 3, 4, 10, 4, 8, AH_TRUE},
126 {"ETSI [ 300]", 3267, 3399, AH_FALSE, 20, 3, 4, 10, 4, 6, AH_TRUE},
127 {"ETSI [ 500]", 1960, 2040, AH_FALSE, 20, 4, 4, 10, 4, 8, AH_TRUE},
128 {"ETSI [ 750]", 1307, 1359, AH_FALSE, 20, 5, 4, 15, 4, 13, AH_TRUE},
129 {"ETSI [ 800]", 1225, 1275, AH_FALSE, 20, 4, 4, 10, 4, 8, AH_TRUE},
130 {"ETSI [1000]", 980, 1020, AH_FALSE, 20, 4, 4, 10, 4, 8, AH_TRUE},
131 {"ETSI [1200]", 817, 849, AH_FALSE, 20, 5, 4, 15, 4, 13, AH_TRUE},
132 {"ETSI [1500]", 653, 679, AH_FALSE, 20, 5, 4, 15, 4, 6, AH_TRUE},
133 {"ETSI [1600]", 613, 637, AH_FALSE, 20, 5, 4, 15, 4, 7, AH_TRUE},
134 {"ETSI [2000]", 490, 510, AH_FALSE, 20, 7, 4, 20, 4, 10, AH_TRUE},
135 {"ETSI [2300]", 426, 442, AH_FALSE, 20, 9, 4, 25, 6, 20, AH_TRUE},
136 {"ETSI [3000]", 327, 339, AH_FALSE, 20, 7, 4, 20, 5, 20, AH_TRUE},
137 {"ETSI [3500]", 280, 290, AH_FALSE, 20, 9, 4, 25, 2, 20, AH_TRUE},
138 {"ETSI [4000]", 245, 255, AH_FALSE, 20, 7, 4, 20, 5, 20, AH_TRUE},
139 #endif
140 #ifdef DFS_DOMAIN_FCC
141 {"FCC [1,1399-1714]", 1399, 1714, AH_TRUE, 10, 5, 10, 18, 4, 6, AH_FALSE},
142 {"FCC [2,147-235]", 147, 235, AH_TRUE, 10, 8, 10, 29, 6, 12, AH_FALSE},
143 {"FCC [3-4,196-273]", 196, 273, AH_TRUE, 10, 8, 8, 18, 2, 16, AH_FALSE},
144 {"FCC [3-4,275-352]", 275, 352, AH_TRUE, 10, 8, 8, 18, 2, 16, AH_FALSE},
145 {"FCC [3-4,354-431]", 354, 431, AH_TRUE, 10, 8, 8, 18, 2, 16, AH_FALSE},
146 {"FCC [3-4,433-510]", 433, 510, AH_TRUE, 10, 8, 8, 18, 2, 16, AH_FALSE},
147 {"FCC [3-4,235-313]", 235, 313, AH_TRUE, 10, 8, 8, 18, 2, 16, AH_FALSE},
148 {"FCC [3-4,314-392]", 314, 392, AH_TRUE, 10, 8, 8, 18, 2, 16, AH_FALSE},
149 {"FCC [3-4,393-471]", 393, 471, AH_TRUE, 10, 8, 8, 18, 2, 16, AH_FALSE}
150 #endif
153 #ifdef AR_DEBUG
154 static u_int32_t interval_to_frequency(u_int32_t pri);
155 #endif /* AR_DEBUG */
157 /* Returns true if radar detection is enabled. */
158 int ath_radar_is_enabled(struct ath_softc *sc)
160 struct ath_hal *ah = sc->sc_ah;
161 if (ar_device(sc->devid) >= 5211)
162 return ((OS_REG_READ(ah, AR5K_AR5212_PHY_ERR_FIL) &
163 AR5K_AR5212_PHY_ERR_FIL_RADAR) &&
164 (sc->sc_imask & HAL_INT_RXPHY) &&
165 (ath_hal_intrget(ah) & HAL_INT_RXPHY));
166 else
167 return ((sc->sc_imask & HAL_INT_RXPHY) &&
168 (ath_hal_intrget(ah) & HAL_INT_RXPHY));
169 return 0;
172 /* Read the radar pulse detection parameters. */
173 void ath_radar_get_params(struct ath_softc *sc, RADAR_PARAM *rp)
175 u_int32_t radar = ath_reg_read(sc, AR5K_PHY_RADAR);
176 rp->rp_fir_filter_output_power_thr =
177 (radar & AR5K_PHY_RADAR_FIRPWROUTTHR) >>
178 AR5K_PHY_RADAR_FIRPWROUTTHR_S;
179 rp->rp_radar_rssi_thr =
180 (radar & AR5K_PHY_RADAR_PULSERSSITHR) >>
181 AR5K_PHY_RADAR_PULSERSSITHR_S;
182 rp->rp_pulse_height_thr =
183 (radar & AR5K_PHY_RADAR_PULSEHEIGHTTHR) >>
184 AR5K_PHY_RADAR_PULSEHEIGHTTHR_S;
185 rp->rp_pulse_rssi_thr =
186 (radar & AR5K_PHY_RADAR_RADARRSSITHR) >>
187 AR5K_PHY_RADAR_RADARRSSITHR_S;
188 rp->rp_inband_thr =
189 (radar & AR5K_PHY_RADAR_INBANDTHR) >>
190 AR5K_PHY_RADAR_INBANDTHR_S;
193 /* Update the radar pulse detection parameters.
194 * If rp is NULL, defaults are used for all fields.
195 * If any member of rp is set to RADAR_PARAM_USE_DEFAULT, the default
196 * is used for that field. */
197 void ath_radar_set_params(struct ath_softc *sc, RADAR_PARAM *rp)
199 #define BUILD_PHY_RADAR_FIELD(_MASK,_SHIFT,_FIELD) \
200 ((NULL == rp || (rp->_FIELD == RADAR_PARAM_USE_DEFAULT)) ? \
201 ((AR5K_PHY_RADAR_ENABLED_AR5213 & (_MASK))) : \
202 ((rp->_FIELD << (_SHIFT)) & (_MASK)))
203 ath_reg_write(sc, AR5K_PHY_RADAR,
204 BUILD_PHY_RADAR_FIELD(AR5K_PHY_RADAR_FIRPWROUTTHR,
205 AR5K_PHY_RADAR_FIRPWROUTTHR_S,
206 rp_fir_filter_output_power_thr) |
207 BUILD_PHY_RADAR_FIELD(AR5K_PHY_RADAR_RADARRSSITHR,
208 AR5K_PHY_RADAR_RADARRSSITHR_S,
209 rp_pulse_rssi_thr) |
210 BUILD_PHY_RADAR_FIELD(AR5K_PHY_RADAR_PULSEHEIGHTTHR,
211 AR5K_PHY_RADAR_PULSEHEIGHTTHR_S,
212 rp_pulse_height_thr) |
213 BUILD_PHY_RADAR_FIELD(AR5K_PHY_RADAR_PULSERSSITHR,
214 AR5K_PHY_RADAR_PULSERSSITHR_S, rp_radar_rssi_thr) |
215 BUILD_PHY_RADAR_FIELD(AR5K_PHY_RADAR_INBANDTHR,
216 AR5K_PHY_RADAR_INBANDTHR_S,
217 rp_inband_thr)
219 #undef BUILD_PHY_RADAR_FIELD
222 /* This is called on channel change to enable radar detection for 5211+ chips.
223 * NOTE: AR5210 doesn't have radar pulse detection support. */
224 int ath_radar_update(struct ath_softc *sc)
227 struct ath_hal *ah = sc->sc_ah;
228 struct ieee80211com *ic = &sc->sc_ic;
229 int required = 0;
231 /* Do not attempt to change radar state when bg scanning is
232 * the cause */
233 if (ic->ic_flags & IEEE80211_F_SCAN)
234 return 1;
236 /* Update the DFS flags (as a sanity check) */
237 if (ath_radar_correct_dfs_flags(sc, &sc->sc_curchan))
238 DPRINTF(sc, ATH_DEBUG_DOTH, "%s: %s: channel required "
239 "corrections to private flags.\n",
240 SC_DEV_NAME(sc), __func__);
241 required = ath_radar_is_dfs_required(sc, &sc->sc_curchan) &&
242 (ic->ic_flags & IEEE80211_F_DOTH);
243 /* configure radar pulse detector register using default values, but do
244 * not toggle the enable bit. XXX: allow tweaking?? */
245 ath_radar_set_params(sc, NULL);
246 if (ar_device(sc->devid) >= 5211) {
247 HAL_INT old_ier = ath_hal_intrget(ah);
248 HAL_INT new_ier = old_ier;
249 unsigned int old_radar = OS_REG_READ(ah, AR5K_PHY_RADAR);
250 unsigned int old_filter =
251 OS_REG_READ(ah, AR5K_AR5212_PHY_ERR_FIL);
252 unsigned int old_rxfilt = ath_hal_getrxfilter(ah);
253 unsigned int old_mask = sc->sc_imask;
254 unsigned int new_radar = old_radar;
255 unsigned int new_filter = old_filter;
256 unsigned int new_mask = old_mask;
257 unsigned int new_rxfilt = old_rxfilt;
259 ath_hal_intrset(ah, old_ier & ~HAL_INT_GLOBAL);
260 if (required) {
261 new_radar |= AR5K_PHY_RADAR_ENABLE;
262 new_filter |= AR5K_AR5212_PHY_ERR_FIL_RADAR;
263 new_rxfilt |= (HAL_RX_FILTER_PHYERR |
264 HAL_RX_FILTER_PHYRADAR);
265 new_mask |= HAL_INT_RXPHY;
266 new_ier |= HAL_INT_RXPHY;
267 } else {
268 new_radar &= ~AR5K_PHY_RADAR_ENABLE;
269 new_filter &= ~AR5K_AR5212_PHY_ERR_FIL_RADAR;
270 new_rxfilt &= ~HAL_RX_FILTER_PHYRADAR;
271 new_mask &= ~HAL_INT_RXPHY;
272 new_ier &= ~HAL_INT_RXPHY;
275 if (old_filter != new_filter)
276 OS_REG_WRITE(ah, AR5K_AR5212_PHY_ERR_FIL, new_filter);
277 if (old_radar != new_radar)
278 OS_REG_WRITE(ah, AR5K_PHY_RADAR, new_radar);
279 if (old_rxfilt != new_rxfilt)
280 ath_hal_setrxfilter(ah, new_rxfilt);
282 sc->sc_imask = new_mask;
283 if (DFLAG_ISSET(sc, ATH_DEBUG_DOTH) &&
284 ((old_radar != new_radar) ||
285 (old_filter != new_filter) ||
286 (old_rxfilt != new_rxfilt) ||
287 (old_mask != new_mask) ||
288 (old_ier != new_ier))) {
289 DPRINTF(sc, ATH_DEBUG_DOTH,
290 "%s: %s: Radar detection %s.\n", SC_DEV_NAME(sc),
291 __func__, required ? "enabled" : "disabled");
293 ath_hal_intrset(ah, new_ier);
296 return (required == ath_radar_is_enabled(sc));
299 /* Update channel's DFS flags based upon whether DFS is required. Return
300 * true if the value was repaired. */
301 int ath_radar_correct_dfs_flags(struct ath_softc *sc, HAL_CHANNEL *hchan)
303 u_int32_t old_channelFlags = hchan->channelFlags;
304 u_int32_t old_privFlags = hchan->privFlags;
305 if (ath_radar_is_dfs_required(sc, hchan)) {
306 hchan->channelFlags |= CHANNEL_PASSIVE;
307 hchan->privFlags |= CHANNEL_DFS;
308 } else {
309 hchan->channelFlags &= ~CHANNEL_PASSIVE;
310 hchan->privFlags &= ~CHANNEL_DFS;
312 return ((old_privFlags != hchan->privFlags) ||
313 (old_channelFlags != hchan->channelFlags));
316 /* Returns true if DFS is required for the regulatory domain, country and
317 * combination in use.
318 * XXX: Need to add regulatory rules in here. This is too conservative! */
319 int ath_radar_is_dfs_required(struct ath_softc *sc, HAL_CHANNEL *hchan)
321 /* For FCC: 5250 to 5350MHz (channel 52 to 60) and for Europe added
322 * 5470 to 5725 MHz (channel 100 to 140).
323 * Being conservative, go with the entire band from 5250-5725 MHz. */
324 return ((hchan->channel >= 5250) && (hchan->channel <= 5725)) ? 1 : 0;
327 static struct ath_rp *pulse_head(struct ath_softc *sc)
329 return list_entry(sc->sc_rp_list.next,
330 struct ath_rp, list);
333 static struct ath_rp *pulse_tail(struct ath_softc *sc)
335 return list_entry(sc->sc_rp_list.prev,
336 struct ath_rp, list);
339 static struct ath_rp *pulse_prev(struct ath_rp *pulse)
341 return list_entry(pulse->list.prev,
342 struct ath_rp, list);
345 #define CR_FALLTHROUGH 0
346 #define CR_NULL 1
347 #define CR_EXCESS_INTERVALS 2
348 #define CR_INTERVALS 3
349 #define CR_EXCESS_DURATION 4
350 #define CR_DURATION 5
351 #define CR_PULSES 6
352 #define CR_MISSES 7
353 #define CR_MIDPOINT_A 8
354 #define CR_MIDPOINT_B 9
355 #define CR_MIDPOINT_C 10
356 #define CR_NOISE 11
358 #define MR_MATCH 0
359 #define MR_FAIL_MIN_INTERVALS 1
360 #define MR_FAIL_REQD_MATCHES 2
361 #define MR_FAIL_MAX_MISSES 3
362 #define MR_FAIL_MIN_PERIOD 4
363 #define MR_FAIL_MAX_PERIOD 5
365 #ifdef AR_DEBUG
366 static const char *get_match_result_desc(u_int32_t code)
368 switch (code) {
369 case MR_MATCH:
370 return "MATCH";
371 case MR_FAIL_MIN_INTERVALS:
372 return "TOO-SHORT";
373 case MR_FAIL_REQD_MATCHES:
374 return "TOO-FEW";
375 case MR_FAIL_MAX_MISSES:
376 return "TOO-LOSSY";
377 case MR_FAIL_MIN_PERIOD:
378 return "PRI<MIN";
379 case MR_FAIL_MAX_PERIOD:
380 return "PRI>MAX";
381 default:
382 return "unknown";
385 #endif /* AR_DEBUG */
387 static int32_t match_radar(
388 u_int32_t matched,
389 u_int32_t missed,
390 u_int32_t mean_period,
391 u_int32_t noise,
392 u_int32_t min_evts,
393 u_int32_t max_evts,
394 u_int32_t min_rep_int,
395 u_int32_t max_rep_int,
396 u_int32_t min_pulse,
397 u_int32_t max_misses)
399 /* Not a match: insufficient overall burst length */
400 if ( (matched + missed) < min_evts)
401 return MR_FAIL_MIN_INTERVALS;
403 /* Not a match: insufficient match count */
404 if (matched < min_pulse)
405 return MR_FAIL_REQD_MATCHES;
407 /* Not a match: too many missies */
408 if (missed > max_misses)
409 return MR_FAIL_MAX_MISSES;
411 /* Not a match, PRI out of range */
412 if (mean_period < min_rep_int)
413 return MR_FAIL_MIN_PERIOD;
415 /* Not a match, PRI out of range */
416 if (mean_period > max_rep_int)
417 return MR_FAIL_MAX_PERIOD;
419 return MR_MATCH;
422 static int32_t compare_radar_matches(
423 int32_t a_matched,
424 int32_t a_missed,
425 int32_t a_mean_period,
426 int32_t a_noise,
427 int32_t a_min_evts,
428 int32_t a_max_evts,
429 int32_t a_min_rep_int,
430 int32_t a_max_rep_int,
431 int32_t a_min_pulse,
432 int32_t a_max_misses,
433 HAL_BOOL a_match_midpoint,
434 int32_t b_matched,
435 int32_t b_missed,
436 int32_t b_mean_period,
437 int32_t b_noise,
438 int32_t b_min_evts,
439 int32_t b_max_evts,
440 int32_t b_min_rep_int,
441 int32_t b_max_rep_int,
442 int32_t b_min_pulse,
443 int32_t b_max_misses,
444 HAL_BOOL b_match_midpoint
447 /* Intermediate calculations */
448 int32_t a_total = a_matched + a_missed;
449 int32_t b_total = b_matched + b_missed;
450 int32_t a_excess_total =
451 MAX((int32_t)(a_total - (int32_t)a_max_evts), 0);
452 int32_t b_excess_total =
453 MAX((int32_t)(b_total - (int32_t)b_max_evts), 0);
454 u_int64_t a_duration = a_total * a_mean_period;
455 u_int64_t b_duration = b_total * b_mean_period;
456 u_int64_t a_excess_duration = a_excess_total * a_mean_period;
457 u_int64_t b_excess_duration = b_excess_total * b_mean_period;
458 u_int64_t a_dist_from_pri_mid = labs(a_mean_period -
459 (a_min_rep_int +
460 ((a_max_rep_int - a_min_rep_int) / 2)));
461 u_int64_t b_dist_from_pri_mid = labs(b_mean_period -
462 (b_min_rep_int +
463 ((b_max_rep_int - b_min_rep_int) / 2)));
464 /* Did one radar have fewer excess total pulse intervals than the
465 * other? */
466 if (a_excess_total != b_excess_total)
467 return ((a_excess_total < b_excess_total) ? 1 : -1) *
468 CR_EXCESS_INTERVALS;
469 /* Was one pulse longer chronologically, even though totals matched? */
470 else if (a_excess_duration != b_excess_duration)
471 return ((a_excess_duration < b_excess_duration) ? 1 : -1) *
472 CR_EXCESS_DURATION;
473 /* Did one get more matches? */
474 if (a_matched != b_matched)
475 return (a_matched > b_matched ? 1 : -1) * CR_PULSES;
476 /* Both waveforms are the same length, same total.
477 * Did one get more misses? */
478 if (a_missed != b_missed)
479 return (a_missed < b_missed ? 1 : -1) * CR_MISSES;
480 /* Did one get more noise? */
481 if (a_noise != b_noise)
482 return (a_noise < b_noise ? 1 : -1) * CR_NOISE;
483 /* If both waveforms were not too long in terms of intervals */
484 if (0 == (a_excess_total+b_excess_total)) {
485 /* Did one waveform have to match more events than the other? */
486 if (a_total != b_total)
487 return ((a_total > b_total) ? 1 : -1) * CR_INTERVALS;
488 /* Was one waveform longer than the other */
489 if (a_duration != b_duration)
490 return ((a_duration > b_duration) ? 1 : -1) * CR_DURATION;
492 /* both durations are legal, but one is closer to the original PRF/PRI */
493 if (a_dist_from_pri_mid != b_dist_from_pri_mid) {
494 if (a_match_midpoint && b_match_midpoint) {
495 /* Which pattern is closer to midpoint? */
496 return ((a_dist_from_pri_mid < b_dist_from_pri_mid) ? 1 : -1) *
497 CR_MIDPOINT_A;
499 else if (a_match_midpoint) {
500 /* If not within spitting distance of midpoint, reject */
501 return ((a_dist_from_pri_mid < 3) ? 1 : -1) *
502 CR_MIDPOINT_B;
505 else if (b_match_midpoint) {
506 /* If not within spitting distance of midpoint, reject */
507 return ((b_dist_from_pri_mid >= 3) ? 1 : -1) *
508 CR_MIDPOINT_C;
511 return -CR_FALLTHROUGH;
514 #ifdef ATH_RADAR_LONG_PULSE
516 struct lp_burst {
517 u_int32_t lpb_num_pulses;
518 u_int32_t lpb_num_noise;
519 u_int32_t lpb_tsf_delta;
520 u_int64_t lpb_tsf_rel;
521 u_int64_t lpb_min_possible_tsf; /* noise vs real pulses */
522 u_int64_t lpb_max_possible_tsf; /* noise vs real pulses */
525 static const u_int32_t LP_MIN_BC = 8;
526 static const u_int32_t LP_MAX_BC = 20;
527 static const u_int32_t LP_NUM_BC = 13; /* (LP_MAX_BC - LP_MIN_BC + 1); */
528 static const u_int64_t LP_TSF_FUZZ_US = 32768; /* (1<<15) because rs_tstamp
529 * rollover errors */
530 static const u_int32_t LP_MIN_PRI = 1000;
531 static const u_int32_t LP_MAX_PRI = 2000;
533 static void rp_analyze_long_pulse_bscan(
534 struct ath_softc *sc,
535 struct ath_rp *last_pulse,
536 u_int32_t *num_bursts,
537 size_t bursts_buflen,
538 struct lp_burst *bursts)
540 int i = 0;
541 struct ath_rp *newer = NULL;
542 struct ath_rp *cur = last_pulse;
543 struct ath_rp *older = pulse_prev(last_pulse);
544 u_int32_t waveform_num_bursts = 0;
546 if (num_bursts)
547 *num_bursts = 0;
549 for (;;) {
550 /* check if we are at the end of the list */
551 if (&cur->list == &sc->sc_rp_head)
552 break;
553 if (!cur->rp_allocated)
554 break;
556 if (NULL != newer) {
557 u_int64_t tsf_delta = 0;
558 u_int64_t tsf_adjustment = 0;
560 /* Figure out TSF delta, taking into account
561 * up to one multiple of (1<<15) of clock jitter
562 * due to interrupt latency */
563 tsf_delta = newer->rp_tsf - cur->rp_tsf;
564 if ((tsf_delta - LP_TSF_FUZZ_US) >= LP_MIN_PRI &&
565 (tsf_delta - LP_TSF_FUZZ_US) <= LP_MAX_PRI) {
566 tsf_adjustment = LP_TSF_FUZZ_US;
567 tsf_delta -= tsf_adjustment;
570 /* If we are in range for pulse, assume it is a pulse. */
571 if ((tsf_delta >= LP_MIN_PRI) && (tsf_delta <= LP_MAX_PRI)) {
572 bursts[waveform_num_bursts].lpb_num_pulses++;
573 bursts[waveform_num_bursts].lpb_min_possible_tsf =
574 cur->rp_tsf - tsf_adjustment;
576 else if (tsf_delta < LP_MIN_PRI) {
577 bursts[waveform_num_bursts].lpb_num_noise++;
578 /* It may have been THE pulse after all... */
579 bursts[waveform_num_bursts].lpb_min_possible_tsf =
580 cur->rp_tsf - tsf_adjustment;
582 else /* tsf_delta > LP_MAX_PRI */ {
583 bursts[waveform_num_bursts].lpb_num_pulses++;
584 bursts[waveform_num_bursts].lpb_min_possible_tsf =
585 cur->rp_tsf;
586 /* Do not overrun bursts_buflen */
587 if ((waveform_num_bursts+1) >= bursts_buflen) {
588 break;
590 waveform_num_bursts++;
591 bursts[waveform_num_bursts].lpb_tsf_delta = tsf_delta;
592 bursts[waveform_num_bursts].lpb_min_possible_tsf =
593 cur->rp_tsf;
594 bursts[waveform_num_bursts].lpb_max_possible_tsf =
595 cur->rp_tsf;
598 else {
599 bursts[waveform_num_bursts].lpb_max_possible_tsf =
600 cur->rp_tsf;
603 /* advance to next pulse */
604 newer = cur;
605 cur = pulse_prev(cur);
606 older = pulse_prev(cur);
608 if (num_bursts) {
609 bursts[waveform_num_bursts].lpb_num_pulses++;
610 waveform_num_bursts++;
611 *num_bursts = waveform_num_bursts;
613 for (i = 0; i < waveform_num_bursts; i++)
614 bursts[i].lpb_tsf_rel =
615 bursts[i].lpb_max_possible_tsf -
616 bursts[waveform_num_bursts-1].lpb_min_possible_tsf;
619 static HAL_BOOL rp_analyze_long_pulse(
620 struct ath_softc *sc, struct ath_rp *last_pulse,
621 u_int32_t *bc,
622 u_int32_t *matched, u_int32_t *missed,
623 u_int32_t *noise, u_int32_t *pulses)
625 int i;
626 int32_t found_radar = 0;
627 int32_t found_burst_count = 0;
628 int32_t matching_burst_count = 0;
629 u_int32_t best_bc = 0;
630 u_int32_t best_matched = 0;
631 u_int32_t best_missed = 0;
632 u_int32_t best_noise = 0;
633 u_int32_t best_pulses = 0;
635 struct lp_burst bursts[LP_MAX_BC];
636 memset(&bursts, 0, sizeof(bursts));
638 if (bc)
639 *bc = 0;
640 if (matched)
641 *matched = 0;
642 if (missed)
643 *missed = 0;
644 if (noise)
645 *noise = 0;
647 rp_analyze_long_pulse_bscan(sc, last_pulse,
648 &found_burst_count,
649 LP_MAX_BC, &bursts[0]);
650 /* Find the matches */
651 for (matching_burst_count = LP_MAX_BC;
652 matching_burst_count >= LP_MIN_BC;
653 matching_burst_count--) {
654 int32_t first_matched_index = -1;
655 int32_t last_matched_index = -1;
656 int32_t match_burst_index = 0;
657 int32_t found_burst_index = 0;
658 int32_t burst_period = (12000000 / matching_burst_count);
659 int32_t waveform_offset = 0;
660 int32_t total_big_gaps = 0;
661 int32_t matched_span = 0;
662 int32_t missed_bursts = 0;
663 int32_t matched_bursts = 0;
664 for (i = 0; i < matching_burst_count; i++) {
665 int32_t d = bursts[i].lpb_tsf_delta;
666 while (d >= burst_period)
667 d -= burst_period;
668 total_big_gaps += d;
669 waveform_offset = MAX(waveform_offset, d);
671 waveform_offset *= -1;
673 found_burst_index = 0;
674 for (match_burst_index = 0;
675 match_burst_index < matching_burst_count;
676 match_burst_index++) {
677 int64_t limit_high = (burst_period *
678 (matching_burst_count - 1 -
679 match_burst_index + 1)) +
680 (2 * LP_TSF_FUZZ_US);
681 int64_t limit_low = (burst_period *
682 (matching_burst_count - 1 -
683 match_burst_index)) -
684 (2 * LP_TSF_FUZZ_US);
685 /* If the burst is too old, skip it... it's noise too... */
686 while ((((int64_t)bursts[found_burst_index].lpb_tsf_rel +
687 waveform_offset) >
688 limit_high)) {
689 if (found_burst_index < (found_burst_count - 1))
690 found_burst_index++;
691 else
692 break;
694 if ((((int64_t)bursts[found_burst_index].lpb_tsf_rel +
695 waveform_offset) <=
696 limit_high) &&
697 (((int64_t)bursts[found_burst_index].lpb_tsf_rel +
698 waveform_offset) >= limit_low)) {
699 if (-1 == first_matched_index) {
700 first_matched_index = match_burst_index;
701 matched_span = 1;
703 if (last_matched_index < match_burst_index) {
704 last_matched_index = match_burst_index;
706 DPRINTF(sc, ATH_DEBUG_DOTHFILT,
707 "LP %2dp] [%2d/%2d] %10lld "
708 "in {%lld:%lld}] PASS\n",
709 matching_burst_count,
710 found_burst_index,
711 match_burst_index,
712 (int64_t)bursts[found_burst_index].lpb_tsf_rel -
713 waveform_offset,
714 limit_low, limit_high);
715 matched_bursts++;
716 found_burst_index++;
718 else {
719 DPRINTF(sc, ATH_DEBUG_DOTHFILT,
720 "LP %2dp] [%2d/%2d] %10lld "
721 "in {%lld:%lld}] MISSED\n",
722 matching_burst_count,
723 match_burst_index,
724 found_burst_index,
725 (int64_t)bursts[found_burst_index].lpb_tsf_rel -
726 waveform_offset,
727 limit_low, limit_high);
728 missed_bursts++;
731 matched_span = last_matched_index - first_matched_index;
732 DPRINTF(sc, ATH_DEBUG_DOTHFILT, "LP %2dp] burst_period=%10d, "
733 "waveform_offset=%10d, matches=%2d/%2d, "
734 "result=%s\n",
735 matching_burst_count, burst_period, waveform_offset,
736 matched_span, matching_burst_count,
737 (matching_burst_count == matched_span) ?
738 "MATCH" : "MISMATCH"
740 /* XXX - Add comparison logic rather than taking first/last
741 * match based upon ATH_DEBUG_DOTHFILTNOSC? */
742 if (matched_span >= (matching_burst_count - 4)) {
743 found_radar++;
744 best_bc = matching_burst_count;
745 best_matched = matched_bursts;
746 best_missed = missed_bursts;
747 best_noise = 0;
748 best_pulses = 0;
749 for (i = 0; i <= found_burst_index; i++) {
750 best_noise += bursts[match_burst_index].lpb_num_noise;
751 best_pulses += bursts[match_burst_index].lpb_num_pulses;
753 if (!DFLAG_ISSET(sc, ATH_DEBUG_DOTHFILTNOSC))
754 break;
758 if (bc)
759 *bc = best_bc;
760 if (matched)
761 *matched = best_matched;
762 if (missed)
763 *missed = best_missed;
764 if (noise)
765 *noise = best_noise;
766 if (pulses)
767 *pulses = best_pulses;
769 return found_radar ? AH_TRUE : AH_FALSE;
771 #endif /* #ifdef ATH_RADAR_LONG_PULSE */
773 static HAL_BOOL rp_analyze_short_pulse(
774 struct ath_softc *sc, struct ath_rp *last_pulse,
775 u_int32_t *index, u_int32_t *pri, u_int32_t *matching_pulses,
776 u_int32_t *missed_pulses, u_int32_t *noise_pulses)
778 int i;
779 int best_index = -1;
780 unsigned int best_matched = 0;
781 unsigned int best_noise = 0;
782 unsigned int best_missed = 0;
783 unsigned int best_pri = 0;
784 unsigned int best_cr = 0;
786 u_int64_t t0_min, t0_max, t1, t_min, t_max;
787 u_int32_t noise = 0, matched = 0, missed = 0, partial_miss = 0;
788 struct ath_rp *pulse;
789 u_int32_t pulse_count_minimum = 0;
790 struct radar_pattern_specification *pattern = NULL;
791 struct radar_pattern_specification *best_pattern = NULL;
793 u_int32_t new_period = 0;
794 u_int64_t last_tsf = 0;
795 u_int32_t last_seen_period = 0;
796 u_int32_t sum_periods = 0;
797 u_int32_t mean_period = 0;
798 u_int32_t adjusted_max_rep_int = 0;
799 u_int32_t adjusted_min_rep_int = 0;
801 if (index)
802 *index = 0;
803 if (pri)
804 *pri = 0;
805 if (noise_pulses)
806 *noise_pulses = 0;
807 if (matching_pulses)
808 *matching_pulses = 0;
809 if (missed_pulses)
810 *missed_pulses = 0;
812 /* we need at least sc_rp_min (>2 pulses) */
813 pulse_count_minimum = sc->sc_rp_min;
814 if ((sc->sc_rp_num < pulse_count_minimum) ||
815 (sc->sc_rp_num < 2))
816 return 0;
818 /* Search algorithm:
820 * - since we have a limited and known number of radar patterns, we
821 * loop on all possible radar pulse period
823 * - we start the search from the last timestamp (t1), going
824 * backward in time, up to the point for the first possible radar
825 * pulse, ie t0_min - PERIOD * BURST_MAX
827 * - on this timescale, we matched the number of hit/missed using T -
828 * PERIOD * n taking into account the 2% error margin (using
829 * min_rep_int, max_rep_int)
831 * At the end, we have a number of pulse hit for each PRF
833 * TSF will roll over after just over 584,542 years of operation
834 * without restart.
836 * This exceeds all known Atheros MTBF so, forget about TSF roll over.
839 /* t1 is the timestamp of the last radar pulse */
840 t1 = (u_int64_t)last_pulse->rp_tsf;
842 /* loop through all patterns */
843 for (i = 0; i < sizetab(radar_patterns); i++) {
844 pattern = &radar_patterns[i];
846 /* underflow */
847 if ((pattern->min_rep_int *
848 (pattern->min_evts - 1)) >= t1) {
849 DPRINTF(sc, ATH_DEBUG_DOTHFILTVBSE,
850 "%s: %s skipped (last pulse isn't old enough to"
851 " match this pattern). %10llu >= %10llu.\n",
852 SC_DEV_NAME(sc), pattern->name,
853 (u_int64_t)(
854 pattern->min_rep_int *
855 pattern->min_evts),
856 (u_int64_t)t1);
857 continue;
860 /* this min formula is to check for underflow. It's the
861 * minimum needed duration to gather specified number of
862 * matches, assuming minimum match interval. */
863 t0_min = (pattern->min_rep_int *
864 pattern->min_evts) < t1 ?
865 t1 - (pattern->min_rep_int *
866 pattern->min_evts) : 0;
868 /* this max formula is to stop when we exceed maximum time
869 * period for the pattern. It's the oldest possible TSF that
870 * could match. */
871 t0_max = (pattern->max_rep_int *
872 pattern->max_evts) < t1 ?
873 t1 - (pattern->max_rep_int *
874 pattern->max_evts) : 0;
876 /* we directly start with the timestamp before t1 */
877 pulse = pulse_prev(last_pulse);
879 /* initial values for t_min, t_max */
880 t_min = pattern->max_rep_int < t1 ?
881 t1 - pattern->max_rep_int : 0;
882 t_max = pattern->min_rep_int < t1 ?
883 t1 - pattern->min_rep_int : 0;
885 last_tsf = t1;
886 last_seen_period = 0;
887 sum_periods = 0;
888 matched = 0;
889 noise = 0;
890 missed = 0;
891 partial_miss = 0;
892 mean_period = 0;
893 adjusted_max_rep_int =
894 pattern->max_rep_int;
895 adjusted_min_rep_int =
896 pattern->min_rep_int;
898 for (;;) {
899 if (mean_period && pattern->dyn_ints) {
900 u_int32_t fuzz_pct = pattern->fuzz_pct;
901 adjusted_max_rep_int =
902 MIN(nofloat_pct(mean_period, fuzz_pct),
903 pattern->max_rep_int);
905 adjusted_min_rep_int =
906 MAX(nofloat_pct(mean_period, -fuzz_pct),
907 pattern->min_rep_int);
909 else {
910 adjusted_max_rep_int = pattern->max_rep_int;
911 adjusted_min_rep_int = pattern->min_rep_int;
914 /* check if we are at the end of the list */
915 if (&pulse->list == &sc->sc_rp_list)
916 break;
917 if (!pulse->rp_allocated)
918 break;
920 /* Do not go too far... this is an optimization to not
921 * keep checking after we hit maximum time span for the
922 * pattern. */
923 if (pulse->rp_tsf < t0_max) {
924 DPRINTF(sc, ATH_DEBUG_DOTHFILTVBSE,
925 "%s: %s matching stopped (pulse->rp_tsf"
926 " < t0_max). t1=%10llu t0_max=%10llu "
927 "t_min=%10llu t_max=%10llu matched=%u "
928 "missed=%u\n", SC_DEV_NAME(sc),
929 pattern->name, t1, t0_max,
930 t_min, t_max, matched, missed);
931 break;
933 /* if we missed more than specified number of pulses,
934 * we stop searching */
935 if (partial_miss >
936 pattern->max_consecutive_missing) {
937 DPRINTF(sc, ATH_DEBUG_DOTHFILTVBSE,
938 "%s: %s matching stopped (too many "
939 "consecutive pulses missing). %d>%d "
940 "matched=%u. missed=%u.\n",
941 SC_DEV_NAME(sc), pattern->name,
942 partial_miss,
943 pattern->max_consecutive_missing,
944 matched, missed);
945 break;
948 new_period = (u_int64_t)
949 (last_tsf && last_tsf > pulse->rp_tsf) ?
950 last_tsf - pulse->rp_tsf : 0;
951 if (pulse->rp_tsf > t_max) {
952 DPRINTF(sc, ATH_DEBUG_DOTHFILTVBSE,
953 "%s: %-17s [%2d] %5s [**:**] tsf: "
954 "%10llu [range: %5llu-%5llu]. width: "
955 "%3d. period: %4llu. last_period: %4llu"
956 ". mean_period: %4llu. last_tsf: %10llu"
957 ".\n",
958 SC_DEV_NAME(sc),
959 pattern->name,
960 pulse->rp_index,
961 "noise",
962 (u_int64_t)pulse->rp_tsf,
963 (u_int64_t)t_min,
964 (u_int64_t)t_max,
965 (u_int8_t)pulse->rp_width,
966 (u_int64_t)new_period,
967 (u_int64_t)last_seen_period,
968 (u_int64_t)mean_period,
969 (u_int64_t)last_tsf);
970 /* this event is noise, ignore it */
971 pulse = pulse_prev(pulse);
972 noise++;
973 } else if (pulse->rp_tsf >= t_min) {
974 /* we found a match */
975 matched++;
976 if (partial_miss)
977 new_period /= (partial_miss + 1);
978 missed += partial_miss;
979 partial_miss = 0;
980 sum_periods += new_period;
981 mean_period = matched ?
982 (sum_periods / matched) :
984 if (mean_period &&
985 pattern->dyn_ints &&
986 (mean_period >
987 pattern->max_rep_int ||
988 mean_period <
989 pattern->min_rep_int)) {
990 DPRINTF(sc, ATH_DEBUG_DOTHFILTVBSE,
991 "%s: %s mean period deviated "
992 "from original range [period: "
993 "%4u, range: %4u-%4u]\n",
994 SC_DEV_NAME(sc),
995 pattern->name,
996 mean_period,
997 pattern->min_rep_int,
998 pattern->max_rep_int);
999 break;
1002 /* Remember we are scanning backwards... */
1003 DPRINTF(sc, ATH_DEBUG_DOTHFILTVBSE,
1004 "%s: %-17s [%2d] %5s [%2d:%-2d] tsf: "
1005 "%10llu [range: %5llu-%5llu]. width: "
1006 "%3d. period: %4llu. last_period: %4llu"
1007 ". mean_period: %4llu. last_tsf: %10llu"
1008 ".\n",
1009 SC_DEV_NAME(sc),
1010 pattern->name,
1011 pulse->rp_index,
1012 "match",
1013 MAX(matched + missed + partial_miss - 1,
1015 (matched + missed + partial_miss),
1016 (u_int64_t)pulse->rp_tsf,
1017 (u_int64_t)t_min,
1018 (u_int64_t)t_max,
1019 (u_int8_t)pulse->rp_width,
1020 (u_int64_t)new_period,
1021 (u_int64_t)last_seen_period,
1022 (u_int64_t)mean_period,
1023 (u_int64_t)last_tsf);
1025 /* record tsf and period */
1026 last_seen_period = new_period;
1027 last_tsf = pulse->rp_tsf;
1029 /* advance to next pulse */
1030 pulse = pulse_prev(pulse);
1032 /* update bounds */
1033 t_min = adjusted_max_rep_int < last_tsf ?
1034 last_tsf - adjusted_max_rep_int :
1036 t_max = adjusted_min_rep_int < last_tsf ?
1037 last_tsf - adjusted_min_rep_int :
1039 } else {
1040 partial_miss++;
1041 /* if we missed more than specified number of
1042 * pulses, we stop searching */
1043 if ((missed + partial_miss) >
1044 pattern->max_missing) {
1045 DPRINTF(sc, ATH_DEBUG_DOTHFILTVBSE,
1046 "%s: %s matching stopped (too "
1047 "many total pulses missing). "
1048 "%d>%d matched=%u. missed=%u."
1049 "\n",
1050 SC_DEV_NAME(sc),
1051 pattern->name,
1052 missed,
1053 pattern->max_missing,
1054 matched,
1055 missed);
1056 break;
1058 /* Default mean period to approximate center
1059 * of range. Remember we are scanning
1060 * backwards... */
1061 DPRINTF(sc, ATH_DEBUG_DOTHFILTVBSE,
1062 "%s: %-17s [**] %5s [%2d:%-2d] tsf: "
1063 "(missing) [range: %5llu-%5llu]. "
1064 "width: ***. period: ****. last_period:"
1065 " %4llu. mean_period: %4llu. last_tsf: "
1066 "%10llu.\n",
1067 SC_DEV_NAME(sc),
1068 pattern->name,
1069 "missed",
1070 MAX(matched + missed + partial_miss - 1,
1072 (matched + missed + partial_miss),
1073 (u_int64_t)t_min,
1074 (u_int64_t)t_max,
1075 (u_int64_t)last_seen_period,
1076 (u_int64_t)mean_period,
1077 (u_int64_t)last_tsf);
1079 /* update bounds */
1080 t_min = adjusted_max_rep_int < t_min ?
1081 t_min - adjusted_max_rep_int :
1083 t_max = adjusted_min_rep_int < t_max ?
1084 t_max - adjusted_min_rep_int :
1089 /* print counters for this PRF */
1090 if (matched > 1) {
1091 int compare_result = CR_FALLTHROUGH;
1092 int match_result = MR_MATCH;
1093 /* we add one to the matched since we counted only the
1094 * time differences */
1095 /* matched++; not sure... */
1097 /* check if PRF counters match a known radar, if we are
1098 * confident enought */
1099 if (MR_MATCH == (match_result = match_radar(
1100 matched,
1101 missed,
1102 mean_period,
1103 noise,
1104 pattern->min_evts,
1105 pattern->max_evts,
1106 pattern->min_rep_int,
1107 pattern->max_rep_int,
1108 pattern->min_pulse,
1109 pattern->max_missing))) {
1110 compare_result = (NULL == best_pattern) ? CR_NULL :
1111 compare_radar_matches(
1112 matched,
1113 missed,
1114 mean_period,
1115 noise,
1116 pattern->min_evts,
1117 pattern->max_evts,
1118 pattern->min_rep_int,
1119 pattern->max_rep_int,
1120 pattern->min_pulse,
1121 pattern->max_missing,
1122 pattern->match_midpoint,
1123 best_matched,
1124 best_missed,
1125 best_pri,
1126 best_noise,
1127 best_pattern->min_evts,
1128 best_pattern->max_evts,
1129 best_pattern->min_rep_int,
1130 best_pattern->max_rep_int,
1131 best_pattern->min_pulse,
1132 best_pattern->max_missing,
1133 best_pattern->match_midpoint);
1135 if (DFLAG_ISSET(sc, ATH_DEBUG_DOTHFILT)) {
1136 DPRINTF(sc, ATH_DEBUG_DOTHFILT,
1137 "%s: [%02d] %13s: %-17s [match=%2u {%2u"
1138 "..%2u},missed=%2u/%2u,dur=%2d {%2u.."
1139 "%2u},noise=%2u/%2u,cr:%d]\n",
1140 SC_DEV_NAME(sc),
1141 last_pulse->rp_index,
1142 compare_result > CR_FALLTHROUGH ?
1143 "NEW-BEST" :
1144 get_match_result_desc(match_result),
1145 pattern->name,
1146 matched,
1147 pattern->min_pulse,
1148 pattern->max_evts,
1149 missed,
1150 pattern->max_missing,
1151 matched + missed,
1152 pattern->min_evts,
1153 pattern->max_evts,
1154 noise,
1155 matched + noise,
1156 compare_result);
1159 if (compare_result > CR_FALLTHROUGH) {
1160 best_matched = matched;
1161 best_missed = missed;
1162 best_index = i;
1163 best_pattern = pattern;
1164 best_pri = mean_period;
1165 best_noise = noise;
1166 best_cr = compare_result;
1168 else if (compare_result <= CR_FALLTHROUGH) {
1169 DPRINTF(sc, ATH_DEBUG_DOTHFILTVBSE,
1170 "%s: %s match not better than best so "
1171 "far. cr: %d matched: %d missed: "
1172 "%d min_evts: %d\n",
1173 SC_DEV_NAME(sc),
1174 pattern->name,
1175 compare_result,
1176 matched,
1177 missed,
1178 pattern->min_evts);
1182 if (-1 != best_index) {
1183 DPRINTF(sc, ATH_DEBUG_DOTHFILTVBSE,
1184 "%s: [%02d] %10s: %-17s [match=%2u {%2u..%2u},missed="
1185 "%2u/%2u,dur=%2d {%2u..%2u},noise=%2u/%2u,cr=%2d] "
1186 "RI=%-9u RF=%-4u\n",
1187 SC_DEV_NAME(sc),
1188 last_pulse->rp_index,
1189 "BEST/PULSE",
1190 best_pattern->name,
1191 best_matched,
1192 best_pattern->min_pulse,
1193 best_pattern->max_evts,
1194 best_missed,
1195 best_pattern->max_missing,
1196 (best_matched + best_missed),
1197 best_pattern->min_evts,
1198 best_pattern->max_evts,
1199 best_noise,
1200 (best_matched + best_noise),
1201 best_cr,
1202 best_pri,
1203 interval_to_frequency(best_pri));
1204 if (index)
1205 *index = best_index;
1206 if (pri)
1207 *pri = best_pri;
1208 if (matching_pulses)
1209 *matching_pulses = best_matched;
1210 if (noise_pulses)
1211 *noise_pulses = best_noise;
1212 if (missed_pulses)
1213 *missed_pulses = best_missed;
1216 return (-1 != best_index) ? AH_TRUE : AH_FALSE;
1219 #ifdef AR_DEBUG
1220 static u_int32_t interval_to_frequency(u_int32_t interval)
1222 /* Calculate BRI from PRI */
1223 u_int32_t frequency = interval ? (1000000 / interval) : 0;
1224 /* Round to nearest multiple of 50 */
1225 return frequency + ((frequency % 50) >= 25 ? 50 : 0) - (frequency % 50);
1227 #endif /* AR_DEBUG */
1229 #ifdef ATH_RADAR_LONG_PULSE
1230 static const char *get_longpulse_desc(int lp)
1232 switch (lp) {
1233 case 8: return "FCC [5, 8 pulses]";
1234 case 9: return "FCC [5, 9 pulses]";
1235 case 10: return "FCC [5, 10 pulses]";
1236 case 11: return "FCC [5, 11 pulses]";
1237 case 12: return "FCC [5, 12 pulses]";
1238 case 13: return "FCC [5, 13 pulses]";
1239 case 14: return "FCC [5, 14 pulses]";
1240 case 15: return "FCC [5, 15 pulses]";
1241 case 16: return "FCC [5, 16 pulses]";
1242 case 17: return "FCC [5, 17 pulses]";
1243 case 18: return "FCC [5, 18 pulses]";
1244 case 19: return "FCC [5, 19 pulses]";
1245 case 20: return "FCC [5, 20 pulses]";
1246 default: return "FCC [5, invalid pulses]";
1249 #endif /* #ifdef ATH_RADAR_LONG_PULSE */
1251 static HAL_BOOL rp_analyze(struct ath_softc *sc)
1253 HAL_BOOL radar = 0;
1254 struct ath_rp *pulse;
1256 /* Best short pulse match */
1257 int32_t best_index = -1;
1258 u_int32_t best_pri = 0;
1259 u_int32_t best_matched = 0;
1260 u_int32_t best_missed = 0;
1261 u_int32_t best_noise = 0;
1262 int32_t best_cr = 0;
1264 #ifdef ATH_RADAR_LONG_PULSE
1265 /* Best long pulse match */
1266 u_int32_t best_lp_bc = 0;
1267 u_int32_t best_lp_matched = 0;
1268 u_int32_t best_lp_missed = 0;
1269 u_int32_t best_lp_noise = 0;
1270 u_int32_t best_lp_pulses = 0;
1271 #endif /* #ifdef ATH_RADAR_LONG_PULSE */
1272 u_int32_t pass = 0;
1273 struct radar_pattern_specification *best_pattern = NULL;
1275 /* start the analysis by the last pulse since it might speed up
1276 * things and then move backward for all non-analyzed pulses.
1277 * For debugging ONLY - we continue to run this scan after radar is
1278 * detected, processing all pulses... even when they come in after an
1279 * iteration of all pulses that were present when this function was
1280 * invoked. This can happen at some radar waveforms where we will
1281 * match the first few pulses and then the rest of the burst will come
1282 * in, but never be analyzed.
1285 while (pulse_tail(sc)->rp_allocated &&
1286 !pulse_tail(sc)->rp_analyzed &&
1287 (AH_FALSE == radar ||
1288 (DFLAG_ISSET(sc, ATH_DEBUG_DOTHFILT) && ++pass <= 3))) {
1290 list_for_each_entry_reverse(pulse, &sc->sc_rp_list, list) {
1291 if (!pulse->rp_allocated)
1292 break;
1293 if (pulse->rp_analyzed)
1294 break;
1296 /* Skip pulse analysis after we have confirmed radar
1297 * presence unless we are debugging and have
1298 * disabled short-circuit logic. In this case,
1299 * we'll go through ALL the signatures and find
1300 * the best match to convince ourselves this code works.
1302 if (AH_FALSE == radar ||
1303 DFLAG_ISSET(sc, ATH_DEBUG_DOTHFILTNOSC)) {
1304 /* short pulse match status */
1305 u_int32_t index = 0;
1306 u_int32_t pri = 0;
1307 u_int32_t matched = 0;
1308 u_int32_t missed = 0;
1309 u_int32_t noise = 0;
1310 #ifdef ATH_RADAR_LONG_PULSE
1312 /* long pulse match status */
1313 u_int32_t lp_bc = 0;
1314 u_int32_t lp_matched = 0;
1315 u_int32_t lp_missed = 0;
1316 u_int32_t lp_noise = 0;
1317 u_int32_t lp_pulses = 0;
1318 #endif /* #ifdef ATH_RADAR_LONG_PULSE */
1319 if (rp_analyze_short_pulse(sc, pulse, &index,
1320 &pri, &matched, &missed,
1321 &noise)) {
1322 int compare_result = (!radar || best_index == -1) ?
1323 CR_NULL :
1324 compare_radar_matches(
1325 matched,
1326 missed,
1327 pri,
1328 noise,
1329 radar_patterns[index].min_evts,
1330 radar_patterns[index].max_evts,
1331 radar_patterns[index].min_rep_int,
1332 radar_patterns[index].max_rep_int,
1333 radar_patterns[index].min_pulse,
1334 radar_patterns[index].max_missing,
1335 radar_patterns[index].match_midpoint,
1336 best_matched,
1337 best_missed,
1338 best_pri,
1339 best_noise,
1340 radar_patterns[best_index].min_evts,
1341 radar_patterns[best_index].max_evts,
1342 radar_patterns[best_index].min_rep_int,
1343 radar_patterns[best_index].max_rep_int,
1344 radar_patterns[best_index].min_pulse,
1345 radar_patterns[best_index].max_missing,
1346 radar_patterns[best_index].match_midpoint
1348 if (compare_result > CR_FALLTHROUGH) {
1349 /* Update best match */
1350 best_matched = matched;
1351 best_missed = missed;
1352 best_index = index;
1353 best_pri = pri;
1354 best_noise = noise;
1355 radar = AH_TRUE;
1356 best_cr = compare_result;
1358 DPRINTF(sc, ATH_DEBUG_DOTHFILT,
1359 "%s: %10s: %-17s [match=%2u "
1360 "{%2u..%2u}, missed=%2u/%2u, "
1361 "dur=%2d {%2u..%2u}, "
1362 "noise=%2u/%2u, cr=%2d] "
1363 "RI=%-9u RF=%-4u\n",
1364 DEV_NAME(sc->sc_dev),
1365 (compare_result > CR_FALLTHROUGH) ?
1366 "BETTER" : "WORSE",
1367 radar_patterns[index].name,
1368 matched,
1369 radar_patterns[index].min_pulse,
1370 radar_patterns[index].max_evts,
1371 missed,
1372 radar_patterns[index].max_missing,
1373 (matched + missed),
1374 radar_patterns[index].min_evts,
1375 radar_patterns[index].max_evts,
1376 noise,
1377 (matched + noise),
1378 compare_result,
1379 pri,
1380 interval_to_frequency(pri));
1382 #ifdef ATH_RADAR_LONG_PULSE
1383 if (rp_analyze_long_pulse(sc, pulse,
1384 &lp_bc,
1385 &lp_matched,
1386 &lp_missed,
1387 &lp_noise,
1388 &lp_pulses)) {
1389 /* XXX: Do we care about best match?? */
1390 radar = AH_TRUE;
1391 best_lp_bc = lp_bc;
1392 best_lp_matched = lp_matched;
1393 best_lp_missed = lp_missed;
1394 best_lp_noise = lp_noise;
1395 best_lp_pulses = lp_pulses;
1397 #endif /* #ifdef ATH_RADAR_LONG_PULSE */
1399 pulse->rp_analyzed = 1;
1402 if (AH_TRUE == radar) {
1403 #ifdef ATH_RADAR_LONG_PULSE
1404 if (!best_lp_bc) {
1405 #endif /* #ifdef ATH_RADAR_LONG_PULSE */
1406 best_pattern =
1407 &radar_patterns[best_index];
1408 DPRINTF(sc, ATH_DEBUG_DOTHFILT,
1409 "%s: %10s: %-17s [match=%2u {%2u..%2u},missed="
1410 "%2u/%2u,dur=%2d {%2u..%2u},noise=%2u/%2u,cr=%2d] "
1411 "RI=%-9u RF=%-4u\n",
1412 DEV_NAME(sc->sc_dev),
1413 "BEST MATCH",
1414 best_pattern->name,
1415 best_matched,
1416 best_pattern->min_pulse,
1417 best_pattern->max_evts,
1418 best_missed,
1419 best_pattern->max_missing,
1420 (best_matched + best_missed),
1421 best_pattern->min_evts,
1422 best_pattern->max_evts,
1423 best_noise,
1424 (best_matched + best_noise),
1425 best_cr,
1426 best_pri,
1427 interval_to_frequency(best_pri));
1428 #ifdef ATH_RADAR_LONG_PULSE
1430 else {
1431 DPRINTF(sc, ATH_DEBUG_DOTHFILT,
1432 "%s: %10s: %-17s [match=%2u {%2u..%2u},missed="
1433 "%2u/%2u,noise=%2u/%2u]\n",
1434 DEV_NAME(sc->sc_dev),
1435 "BEST MATCH",
1436 get_longpulse_desc(best_lp_bc),
1437 best_lp_bc,
1438 (best_lp_bc-4),
1439 best_lp_bc,
1440 best_lp_missed,
1441 (best_lp_bc-(best_lp_bc-4)),
1442 best_lp_noise,
1443 (best_lp_pulses + best_lp_noise)
1446 #endif /* #ifdef ATH_RADAR_LONG_PULSE */
1447 if (DFLAG_ISSET(sc, ATH_DEBUG_DOTHFILT)) {
1448 DPRINTF(sc, ATH_DEBUG_DOTHFILT,
1449 "%s: ========================================\n",
1450 DEV_NAME(sc->sc_dev));
1451 DPRINTF(sc, ATH_DEBUG_DOTHFILT,
1452 "%s: ==BEGIN RADAR SAMPLE====================\n",
1453 DEV_NAME(sc->sc_dev));
1454 DPRINTF(sc, ATH_DEBUG_DOTHFILT,
1455 "%s: ========================================\n",
1456 DEV_NAME(sc->sc_dev));
1458 #ifdef ATH_RADAR_LONG_PULSE
1459 if (!best_lp_bc) {
1460 #endif /* #ifdef ATH_RADAR_LONG_PULSE */
1461 best_pattern =
1462 &radar_patterns[best_index];
1463 DPRINTF(sc, ATH_DEBUG_DOTHPULSES,
1464 "%s: Sample contains data matching %s "
1465 "[match=%2u {%2u..%2u}, "
1466 "missed=%2u/%2u, dur=%2d {%2u..%2u}, "
1467 "noise=%2u/%2u,cr=%d] RI=%-9u RF=%-4u\n",
1468 DEV_NAME(sc->sc_dev),
1469 best_pattern->name,
1470 best_matched,
1471 best_pattern->min_pulse,
1472 best_pattern->max_evts,
1473 best_missed,
1474 best_pattern->max_missing,
1475 best_matched + best_missed,
1476 best_pattern->min_evts,
1477 best_pattern->max_evts,
1478 best_noise,
1479 best_noise + best_matched,
1480 best_cr,
1481 best_pri,
1482 interval_to_frequency(best_pri));
1483 #ifdef ATH_RADAR_LONG_PULSE
1484 } else {
1485 DPRINTF(sc, ATH_DEBUG_DOTHPULSES,
1486 "%s: Sample contains data matching %s\n",
1487 DEV_NAME(sc->sc_dev),
1488 get_longpulse_desc(best_lp_bc));
1490 #endif /* #ifdef ATH_RADAR_LONG_PULSE */
1492 ath_rp_print(sc, 0 /* analyzed pulses only */ );
1493 DPRINTF(sc, ATH_DEBUG_DOTHFILT,
1494 "%s: ========================================\n",
1495 DEV_NAME(sc->sc_dev));
1496 DPRINTF(sc, ATH_DEBUG_DOTHFILT,
1497 "%s: ==END RADAR SAMPLE======================\n",
1498 DEV_NAME(sc->sc_dev));
1499 DPRINTF(sc, ATH_DEBUG_DOTHFILT,
1500 "%s: ========================================\n",
1501 DEV_NAME(sc->sc_dev));
1503 #ifdef ATH_RADAR_LONG_PULSE
1504 if (!best_lp_bc)
1505 #endif /* #ifdef ATH_RADAR_LONG_PULSE */
1506 ath_radar_detected(sc, radar_patterns[best_index].name);
1507 #ifdef ATH_RADAR_LONG_PULSE
1508 else
1509 ath_radar_detected(sc, get_longpulse_desc(best_lp_bc));
1510 #endif /* #ifdef ATH_RADAR_LONG_PULSE */
1512 return radar;
1515 /* initialize ath_softc members so sensible values */
1516 static void ath_rp_clear(struct ath_softc *sc)
1518 sc->sc_rp = NULL;
1519 INIT_LIST_HEAD(&sc->sc_rp_list);
1520 sc->sc_rp_num = 0;
1521 sc->sc_rp_analyze = NULL;
1524 static void ath_rp_tasklet(TQUEUE_ARG data)
1526 struct net_device *dev = (struct net_device *)data;
1527 struct ath_softc *sc = dev->priv;
1529 if (sc->sc_rp_analyze != NULL)
1530 sc->sc_rp_analyze(sc);
1533 void ath_rp_init(struct ath_softc *sc)
1535 struct net_device *dev = sc->sc_dev;
1536 int i;
1538 ath_rp_clear(sc);
1540 sc->sc_rp = (struct ath_rp *)kzalloc(
1541 sizeof(struct ath_rp) *
1542 ATH_RADAR_PULSE_NR, GFP_KERNEL);
1544 if (sc->sc_rp == NULL)
1545 return;
1547 /* initialize the circular list */
1548 INIT_LIST_HEAD(&sc->sc_rp_list);
1549 for (i = 0; i < ATH_RADAR_PULSE_NR; i++) {
1550 sc->sc_rp[i].rp_index = i;
1551 list_add_tail(&sc->sc_rp[i].list,
1552 &sc->sc_rp_list);
1555 sc->sc_rp_num = 0;
1556 sc->sc_rp_analyze = rp_analyze;
1558 /* compute sc_rp_min */
1559 sc->sc_rp_min = 2;
1560 for (i = 0; i < sizetab(radar_patterns); i++)
1561 sc->sc_rp_min =
1562 MIN(sc->sc_rp_min,
1563 radar_patterns[i].min_pulse);
1565 /* default values is properly handle pulses and detected radars */
1566 sc->sc_rp_ignored = 0;
1567 sc->sc_radar_ignored = 0;
1569 ATH_INIT_TQUEUE(&sc->sc_rp_tq, ath_rp_tasklet, dev);
1572 void ath_rp_done(struct ath_softc *sc)
1574 /* free what we allocated in ath_rp_init() */
1575 kfree(sc->sc_rp);
1577 ath_rp_clear(sc);
1580 void ath_rp_record(struct ath_softc *sc, u_int64_t tsf, u_int8_t rssi,
1581 u_int8_t width, HAL_BOOL is_simulated)
1583 struct ath_rp *pulse;
1585 DPRINTF(sc, ATH_DEBUG_DOTHPULSES, "%s: ath_rp_record: "
1586 "tsf=%10llu rssi=%3u width=%3u%s\n",
1587 SC_DEV_NAME(sc), tsf, rssi, width,
1588 sc->sc_rp_ignored ? " (ignored)" : "");
1590 if (sc->sc_rp_ignored) {
1591 return;
1594 /* pulses width 255 seems to trigger false detection of radar. we
1595 * ignored it then. */
1597 if (width == 255) {
1598 /* ignored */
1599 return ;
1602 /* check if the new radar pulse is after the last one recorded, or
1603 * else, we flush the history */
1604 pulse = pulse_tail(sc);
1605 if (tsf < pulse->rp_tsf) {
1606 if (is_simulated == AH_TRUE && 0 == tsf) {
1607 DPRINTF(sc, ATH_DEBUG_DOTHFILTVBSE,
1608 "%s: %s: ath_rp_flush: simulated tsf "
1609 "reset. tsf =%10llu, rptsf =%10llu\n",
1610 SC_DEV_NAME(sc), __func__, tsf, pulse->rp_tsf);
1611 ath_rp_flush(sc);
1612 } else if ((pulse->rp_tsf - tsf) > (1 << 15)) {
1613 DPRINTF(sc, ATH_DEBUG_DOTHFILTVBSE,
1614 "%s: %s: ath_rp_flush: tsf reset. "
1615 "(rp_tsf - tsf > 0x8000) tsf=%10llu, rptsf="
1616 "%10llu\n",
1617 SC_DEV_NAME(sc), __func__, tsf, pulse->rp_tsf);
1618 ath_rp_flush(sc);
1619 } else {
1620 DPRINTF(sc, ATH_DEBUG_DOTHFILT,
1621 "%s: %s: tsf jitter/bug detected: tsf =%10llu, "
1622 "rptsf =%10llu, rp_tsf - tsf = %10llu\n",
1623 SC_DEV_NAME(sc), __func__, tsf, pulse->rp_tsf,
1624 pulse->rp_tsf - tsf);
1628 /* remove the head of the list */
1629 pulse = pulse_head(sc);
1630 list_del(&pulse->list);
1632 pulse->rp_tsf = tsf;
1633 pulse->rp_rssi = rssi;
1634 pulse->rp_width = width;
1635 pulse->rp_allocated = 1;
1636 pulse->rp_analyzed = 0;
1638 /* add at the tail of the list */
1639 list_add_tail(&pulse->list, &sc->sc_rp_list);
1640 if (ATH_RADAR_PULSE_NR > sc->sc_rp_num)
1641 sc->sc_rp_num++;
1644 void ath_rp_print_mem(struct ath_softc *sc, int analyzed_pulses_only)
1646 struct ath_rp *pulse;
1647 u_int64_t oldest_tsf = ~0;
1648 int i;
1649 IPRINTF(sc, "Pulse dump of %spulses using sc_rp containing "
1650 "%d allocated pulses.\n",
1651 analyzed_pulses_only ? "analyzed " : "", sc->sc_rp_num);
1653 /* Find oldest TSF value so we can print relative times */
1654 for (i = 0; i < ATH_RADAR_PULSE_NR; i++) {
1655 pulse = &sc->sc_rp[i];
1656 if (pulse->rp_allocated && pulse->rp_tsf < oldest_tsf)
1657 oldest_tsf = pulse->rp_tsf;
1660 for (i = 0; i < ATH_RADAR_PULSE_NR; i++) {
1661 pulse = &sc->sc_rp[i];
1662 if (!pulse->rp_allocated)
1663 break;
1664 if ((!analyzed_pulses_only) || pulse->rp_analyzed)
1665 IPRINTF(sc, "Pulse [%3d, %p] : relative_tsf=%10llu "
1666 "tsf=%10llu rssi=%3u width=%3u allocated=%d "
1667 "analyzed=%d next=%p prev=%p\n",
1668 pulse->rp_index,
1669 pulse,
1670 pulse->rp_tsf - oldest_tsf,
1671 pulse->rp_tsf,
1672 pulse->rp_rssi,
1673 pulse->rp_width,
1674 pulse->rp_allocated,
1675 pulse->rp_analyzed,
1676 pulse->list.next,
1677 pulse->list.prev);
1681 void ath_rp_print(struct ath_softc *sc, int analyzed_pulses_only)
1683 struct ath_rp *pulse;
1684 u_int64_t oldest_tsf = ~0;
1686 IPRINTF(sc, "Pulse dump of %spulses from ring buffer containing %d "
1687 "pulses.\n",
1688 analyzed_pulses_only ? "analyzed " : "",
1689 sc->sc_rp_num);
1691 /* Find oldest TSF value so we can print relative times */
1692 oldest_tsf = ~0;
1693 list_for_each_entry_reverse(pulse, &sc->sc_rp_list, list)
1694 if (pulse->rp_allocated && pulse->rp_tsf < oldest_tsf)
1695 oldest_tsf = pulse->rp_tsf;
1697 list_for_each_entry_reverse(pulse, &sc->sc_rp_list, list) {
1698 if (!pulse->rp_allocated)
1699 continue;
1700 if ((!analyzed_pulses_only) || pulse->rp_analyzed)
1701 IPRINTF(sc, "Pulse [%3d, %p] : relative_tsf=%10llu "
1702 "tsf=%10llu rssi=%3u width=%3u allocated=%d "
1703 "analyzed=%d next=%p prev=%p\n",
1704 pulse->rp_index,
1705 pulse,
1706 pulse->rp_tsf - oldest_tsf,
1707 pulse->rp_tsf,
1708 pulse->rp_rssi,
1709 pulse->rp_width,
1710 pulse->rp_allocated,
1711 pulse->rp_analyzed,
1712 pulse->list.next,
1713 pulse->list.prev);
1717 void ath_rp_flush(struct ath_softc *sc)
1719 struct ath_rp *pulse;
1720 list_for_each_entry_reverse(pulse, &sc->sc_rp_list, list)
1721 pulse->rp_allocated = 0;
1722 sc->sc_rp_num = 0;