2008-01-26 23:48:11 +03:00
|
|
|
/*
|
|
|
|
* This software is distributed under the terms of the
|
|
|
|
* GNU General Public License ("GPL") version 2 as published by the Free
|
|
|
|
* Software Foundation.
|
|
|
|
*
|
|
|
|
* NO WARRANTY
|
|
|
|
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
|
|
|
* ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
|
|
|
* LIMITED TO, THE IMPLIED WARRANTIES OF NONINFRINGEMENT, MERCHANTIBILITY
|
|
|
|
* AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL
|
|
|
|
* THE COPYRIGHT HOLDERS OR CONTRIBUTORS BE LIABLE FOR SPECIAL, EXEMPLARY,
|
|
|
|
* OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
|
|
|
|
* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
|
|
|
|
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER
|
|
|
|
* IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
|
|
|
|
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
|
|
|
|
* THE POSSIBILITY OF SUCH DAMAGES.
|
|
|
|
*
|
|
|
|
* $Id: if_ath_radar.c 2464 2007-06-15 22:51:56Z mtaylor $
|
|
|
|
*/
|
|
|
|
#include "opt_ah.h"
|
|
|
|
|
|
|
|
#include "if_ath_debug.h"
|
|
|
|
|
2011-02-03 00:10:53 +03:00
|
|
|
#if !defined(AUTOCONF_INCLUDED) && !defined(CONFIG_LOCALVERSION)
|
2008-01-26 23:48:11 +03:00
|
|
|
#include <linux/config.h>
|
|
|
|
#endif
|
|
|
|
#include <linux/version.h>
|
|
|
|
#include <linux/module.h>
|
|
|
|
#include <linux/init.h>
|
|
|
|
#include <linux/skbuff.h>
|
|
|
|
#include <linux/netdevice.h>
|
|
|
|
#include <linux/etherdevice.h>
|
|
|
|
#include <linux/random.h>
|
|
|
|
#include <linux/delay.h>
|
|
|
|
#include <linux/cache.h>
|
|
|
|
#include <linux/sysctl.h>
|
|
|
|
#include <linux/proc_fs.h>
|
|
|
|
#include <linux/if_arp.h>
|
|
|
|
#include <linux/rtnetlink.h>
|
|
|
|
#include <linux/time.h>
|
|
|
|
#include <asm/uaccess.h>
|
|
|
|
#include <linux/param.h>
|
|
|
|
|
|
|
|
#include "if_ethersubr.h" /* for ETHER_IS_MULTICAST */
|
|
|
|
#include "if_media.h"
|
|
|
|
#include "if_llc.h"
|
|
|
|
|
|
|
|
#include <net80211/ieee80211_radiotap.h>
|
|
|
|
#include <net80211/ieee80211_var.h>
|
|
|
|
#include <net80211/ieee80211_monitor.h>
|
|
|
|
#include <net80211/ieee80211_rate.h>
|
|
|
|
|
|
|
|
#ifdef USE_HEADERLEN_RESV
|
|
|
|
#include <net80211/if_llc.h>
|
|
|
|
#endif
|
|
|
|
|
|
|
|
#include "net80211/if_athproto.h"
|
|
|
|
#include "if_athvar.h"
|
|
|
|
|
|
|
|
#include "ah_desc.h"
|
|
|
|
|
|
|
|
#include "ah_devid.h" /* XXX to identify chipset */
|
|
|
|
|
|
|
|
#ifdef ATH_PCI /* PCI BUS */
|
|
|
|
#include "if_ath_pci.h"
|
|
|
|
#endif /* PCI BUS */
|
|
|
|
#ifdef ATH_AHB /* AHB BUS */
|
|
|
|
#include "if_ath_ahb.h"
|
|
|
|
#endif /* AHB BUS */
|
|
|
|
|
|
|
|
#undef MAX
|
|
|
|
#define MAX(a, b) (((a) > (b)) ? (a) : (b))
|
|
|
|
|
|
|
|
#undef MIN
|
|
|
|
#define MIN(a, b) (((a) < (b)) ? (a) : (b))
|
|
|
|
|
2009-07-11 21:25:26 +04:00
|
|
|
#undef SQR
|
|
|
|
#define SQR(x) ((x)*(x))
|
|
|
|
|
2008-01-26 23:48:11 +03:00
|
|
|
#include "ah.h"
|
|
|
|
#include "if_ath_hal.h"
|
|
|
|
|
|
|
|
#ifdef ATH_TX99_DIAG
|
|
|
|
#include "ath_tx99.h"
|
|
|
|
#endif
|
|
|
|
|
|
|
|
#include "ah_os.h"
|
|
|
|
#include "if_ath_radar.h"
|
|
|
|
|
|
|
|
#define sizetab(t) (sizeof(t)/sizeof(t[0]))
|
|
|
|
#define nofloat_pct(_value, _pct) \
|
|
|
|
( (_value * (1000 + _pct)) / 1000 )
|
|
|
|
|
2009-07-11 21:25:26 +04:00
|
|
|
/* convert units used for the rp_width into us. This conversion is based on
|
|
|
|
* measure and might not be very accurate */
|
|
|
|
#define WIDTH_TO_TSF(x) (((x) * 200) / 256)
|
|
|
|
|
2008-01-26 23:48:11 +03:00
|
|
|
struct radar_pattern_specification {
|
|
|
|
/* The name of the rule/specification (i.e. what did we detect) */
|
|
|
|
const char *name;
|
2009-07-11 21:25:26 +04:00
|
|
|
/* Interval MIN = 1000000 / FREQ - 0.1%
|
2008-01-26 23:48:11 +03:00
|
|
|
* (a.k.a. Pulse/Burst Repetition Interval) */
|
|
|
|
u_int32_t min_rep_int;
|
2009-07-11 21:25:26 +04:00
|
|
|
/* Interval MAX = 1000000 / FREQ + 0.1%
|
2008-01-26 23:48:11 +03:00
|
|
|
* (a.k.a. Pulse/Burst Repetition Interval) */
|
|
|
|
u_int32_t max_rep_int;
|
2009-07-11 21:25:26 +04:00
|
|
|
/* AH_FALSE for ETSI radars, AH_TRUE for FCC radars. Used to adjust
|
|
|
|
* the timestamp of the pulse using the pulse width */
|
|
|
|
HAL_BOOL is_fcc;
|
2008-01-26 23:48:11 +03:00
|
|
|
/* Fuzz factor dynamic matching, as unsigned integer percentage
|
|
|
|
* of variation (i.e. 2 for +/- 2% timing) */
|
|
|
|
u_int32_t fuzz_pct;
|
|
|
|
/* Match MIN (Minimum Pulse/Burst events required) */
|
|
|
|
u_int32_t min_pulse;
|
|
|
|
/* Match MIN duration (Minimum Pulse/Burst events
|
|
|
|
* required including missed) */
|
|
|
|
u_int32_t min_evts;
|
|
|
|
/* Match MAX duration (Maximum Pulse/Burst events
|
|
|
|
* required including missed) */
|
|
|
|
u_int32_t max_evts;
|
|
|
|
/* Maximum consecutive missing pulses */
|
|
|
|
u_int32_t max_consecutive_missing;
|
|
|
|
/* Maximum missing pulses */
|
|
|
|
u_int32_t max_missing;
|
|
|
|
/* Match on absolute distance to PRI/PRF midpoint */
|
|
|
|
HAL_BOOL match_midpoint;
|
|
|
|
};
|
|
|
|
|
|
|
|
static struct radar_pattern_specification radar_patterns[] = {
|
|
|
|
#ifdef DFS_DOMAIN_ETSI
|
2009-07-11 21:25:26 +04:00
|
|
|
/* ETSI - Type 2 - 1,2,5us - PRF 200 - BURST 10 or
|
|
|
|
ETSI - Type 3 - 10,15us - PRF 200 - BURST 15 */
|
|
|
|
{"ETSI - PRF200", 4995, 5005, AH_FALSE, 20, 4, 4, 15, 4, 8, AH_TRUE},
|
|
|
|
/* ETSI - Type 2 - 1,2,5us - PRF 300 - BURST 10 or
|
|
|
|
ETSI - Type 3 - 10,15us - PRF 300 - BURST 15 */
|
|
|
|
{"ETSI - PRF300", 3329, 3337, AH_FALSE, 20, 4, 4, 15, 4, 6, AH_TRUE},
|
|
|
|
/* ETSI - Type 2 - 1,2,5us - PRF 500 - BURST 10 or
|
|
|
|
ETSI - Type 3 - 10,15us - PRF 500 - BURST 15 */
|
|
|
|
{"ETSI - PRF500", 1998, 2002, AH_FALSE, 20, 4, 4, 15, 4, 8, AH_TRUE},
|
|
|
|
/* ETSI - Type 1 - 1us - PRF 750 - BURST 15 */
|
|
|
|
{"ETSI - PRF750", 1331, 1335, AH_FALSE, 20, 5, 4, 15, 4, 13, AH_TRUE},
|
|
|
|
/* ETSI - Type 2 - 1,2,5us - PRF 800 - BURST 10 or
|
|
|
|
ETSI - Type 3 - 10,15us - PRF 800 - BURST 15 */
|
|
|
|
{"ETSI - PRF800", 1248, 1252, AH_FALSE, 20, 4, 4, 15, 4, 8, AH_TRUE},
|
|
|
|
/* ETSI - Type 2 - 1,2,5us - PRF 1000 - BURST 10 or
|
|
|
|
ETSI - Type 3 - 10,15us - PRF 1000 - BURST 15 */
|
|
|
|
{"ETSI - PRF1000", 999, 1001, AH_FALSE, 20, 4, 4, 15, 4, 8, AH_TRUE},
|
|
|
|
/* ETSI - Type 4 - 1,2,5,10,15us - PRF 1200 - BURST 15 */
|
|
|
|
{"ETSI - PRF1200", 832, 834, AH_FALSE, 20, 5, 4, 15, 4, 13, AH_TRUE},
|
|
|
|
/* ETSI - Type 4 - 1,2,5,10,15us - PRF 1500 - BURST 15 */
|
|
|
|
{"ETSI - PRF1500", 665, 667, AH_FALSE, 20, 5, 4, 15, 4, 6, AH_TRUE},
|
|
|
|
/* ETSI - Type 4 - 1,2,5,10,15us - PRF 1600 - BURST 15 */
|
|
|
|
{"ETSI - PRF1600", 624, 626, AH_FALSE, 20, 5, 4, 15, 4, 7, AH_TRUE},
|
|
|
|
/* ETSI - Type 6 - 20,30us - PRF 2000 - BURST 20 */
|
|
|
|
{"ETSI - PRF2000", 499, 501, AH_FALSE, 20, 6, 4, 20, 4, 10, AH_TRUE},
|
|
|
|
/* ETSI - Type 5 - 1,2,5,10,15us - PRF 2300 - BURST 25 */
|
|
|
|
{"ETSI - PRF2300", 432, 435, AH_FALSE, 20, 8, 4, 25, 6, 20, AH_TRUE},
|
|
|
|
/* ETSI - Type 5 - 1,2,5,10,15us - PRF 3000 - BURST 25 or
|
|
|
|
ETSI - Type 6 - 20,30us - PRF 3000 - BURST 20 */
|
|
|
|
{"ETSI - PRF3000", 332, 334, AH_FALSE, 20, 6, 4, 25, 5, 20, AH_TRUE},
|
|
|
|
/* ETSI - Type 5 - 1,2,5,10,15us - PRF 3500 - BURST 25 */
|
|
|
|
{"ETSI - PRF3500", 284, 286, AH_FALSE, 20, 8, 4, 25, 2, 20, AH_TRUE},
|
|
|
|
/* ETSI - Type 5 - 1,2,5,10,15us - PRF 4000 - BURST 25 or
|
|
|
|
ETSI - Type 6 - 20,30us - PRF 4000 - BURST 20 */
|
|
|
|
{"ETSI - PRF4000", 249, 251, AH_FALSE, 20, 6, 4, 25, 5, 20, AH_TRUE},
|
2008-01-26 23:48:11 +03:00
|
|
|
#endif
|
|
|
|
#ifdef DFS_DOMAIN_FCC
|
2009-07-11 21:25:26 +04:00
|
|
|
/* FCC - Type 1 - 1us - PRI 1428 - BURST 18 */
|
|
|
|
{"FCC - Type 1", 1426, 1430, AH_TRUE, 10, 6, 6, 18, 4, 6, AH_FALSE},
|
|
|
|
/* FCC - Type 2 - 1/5us - PRI 150/230 - BURST 23/29 */
|
|
|
|
{"FCC - Type 2", 149, 231, AH_TRUE, 10, 8, 8, 29, 6, 12, AH_FALSE},
|
|
|
|
/* FCC - Type 3 - 6/10us - PRI 200/500 - BURST 16/18 */
|
|
|
|
{"FCC - Type 3", 199, 501, AH_TRUE, 10, 6, 6, 18, 6, 12, AH_FALSE},
|
|
|
|
/* FCC - Type 4 - 11/20us - PRI 200/500 - BURST 12/16 */
|
|
|
|
{"FCC - Type 4", 199, 501, AH_TRUE, 10, 5, 5, 16, 6, 12, AH_FALSE}
|
2008-01-26 23:48:11 +03:00
|
|
|
#endif
|
|
|
|
};
|
|
|
|
|
2008-04-11 03:48:41 +04:00
|
|
|
#ifdef AR_DEBUG
|
2008-01-26 23:48:11 +03:00
|
|
|
static u_int32_t interval_to_frequency(u_int32_t pri);
|
2008-04-11 03:48:41 +04:00
|
|
|
#endif /* AR_DEBUG */
|
2008-01-26 23:48:11 +03:00
|
|
|
|
|
|
|
/* Returns true if radar detection is enabled. */
|
|
|
|
int ath_radar_is_enabled(struct ath_softc *sc)
|
|
|
|
{
|
|
|
|
struct ath_hal *ah = sc->sc_ah;
|
2009-04-28 09:33:47 +04:00
|
|
|
if (ar_device(sc) >= 5211)
|
2008-01-26 23:48:11 +03:00
|
|
|
return ((OS_REG_READ(ah, AR5K_AR5212_PHY_ERR_FIL) &
|
|
|
|
AR5K_AR5212_PHY_ERR_FIL_RADAR) &&
|
|
|
|
(sc->sc_imask & HAL_INT_RXPHY) &&
|
|
|
|
(ath_hal_intrget(ah) & HAL_INT_RXPHY));
|
|
|
|
else
|
|
|
|
return ((sc->sc_imask & HAL_INT_RXPHY) &&
|
|
|
|
(ath_hal_intrget(ah) & HAL_INT_RXPHY));
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
/* Read the radar pulse detection parameters. */
|
|
|
|
void ath_radar_get_params(struct ath_softc *sc, RADAR_PARAM *rp)
|
|
|
|
{
|
|
|
|
u_int32_t radar = ath_reg_read(sc, AR5K_PHY_RADAR);
|
|
|
|
rp->rp_fir_filter_output_power_thr =
|
|
|
|
(radar & AR5K_PHY_RADAR_FIRPWROUTTHR) >>
|
|
|
|
AR5K_PHY_RADAR_FIRPWROUTTHR_S;
|
|
|
|
rp->rp_radar_rssi_thr =
|
|
|
|
(radar & AR5K_PHY_RADAR_PULSERSSITHR) >>
|
|
|
|
AR5K_PHY_RADAR_PULSERSSITHR_S;
|
|
|
|
rp->rp_pulse_height_thr =
|
|
|
|
(radar & AR5K_PHY_RADAR_PULSEHEIGHTTHR) >>
|
|
|
|
AR5K_PHY_RADAR_PULSEHEIGHTTHR_S;
|
|
|
|
rp->rp_pulse_rssi_thr =
|
|
|
|
(radar & AR5K_PHY_RADAR_RADARRSSITHR) >>
|
|
|
|
AR5K_PHY_RADAR_RADARRSSITHR_S;
|
|
|
|
rp->rp_inband_thr =
|
|
|
|
(radar & AR5K_PHY_RADAR_INBANDTHR) >>
|
|
|
|
AR5K_PHY_RADAR_INBANDTHR_S;
|
|
|
|
}
|
|
|
|
|
|
|
|
/* Update the radar pulse detection parameters.
|
|
|
|
* If rp is NULL, defaults are used for all fields.
|
|
|
|
* If any member of rp is set to RADAR_PARAM_USE_DEFAULT, the default
|
|
|
|
* is used for that field. */
|
|
|
|
void ath_radar_set_params(struct ath_softc *sc, RADAR_PARAM *rp)
|
|
|
|
{
|
|
|
|
#define BUILD_PHY_RADAR_FIELD(_MASK,_SHIFT,_FIELD) \
|
|
|
|
((NULL == rp || (rp->_FIELD == RADAR_PARAM_USE_DEFAULT)) ? \
|
|
|
|
((AR5K_PHY_RADAR_ENABLED_AR5213 & (_MASK))) : \
|
|
|
|
((rp->_FIELD << (_SHIFT)) & (_MASK)))
|
|
|
|
ath_reg_write(sc, AR5K_PHY_RADAR,
|
|
|
|
BUILD_PHY_RADAR_FIELD(AR5K_PHY_RADAR_FIRPWROUTTHR,
|
|
|
|
AR5K_PHY_RADAR_FIRPWROUTTHR_S,
|
|
|
|
rp_fir_filter_output_power_thr) |
|
|
|
|
BUILD_PHY_RADAR_FIELD(AR5K_PHY_RADAR_RADARRSSITHR,
|
|
|
|
AR5K_PHY_RADAR_RADARRSSITHR_S,
|
|
|
|
rp_pulse_rssi_thr) |
|
|
|
|
BUILD_PHY_RADAR_FIELD(AR5K_PHY_RADAR_PULSEHEIGHTTHR,
|
|
|
|
AR5K_PHY_RADAR_PULSEHEIGHTTHR_S,
|
|
|
|
rp_pulse_height_thr) |
|
|
|
|
BUILD_PHY_RADAR_FIELD(AR5K_PHY_RADAR_PULSERSSITHR,
|
|
|
|
AR5K_PHY_RADAR_PULSERSSITHR_S, rp_radar_rssi_thr) |
|
|
|
|
BUILD_PHY_RADAR_FIELD(AR5K_PHY_RADAR_INBANDTHR,
|
|
|
|
AR5K_PHY_RADAR_INBANDTHR_S,
|
|
|
|
rp_inband_thr)
|
|
|
|
);
|
|
|
|
#undef BUILD_PHY_RADAR_FIELD
|
|
|
|
}
|
|
|
|
|
|
|
|
/* This is called on channel change to enable radar detection for 5211+ chips.
|
|
|
|
* NOTE: AR5210 doesn't have radar pulse detection support. */
|
|
|
|
int ath_radar_update(struct ath_softc *sc)
|
|
|
|
{
|
|
|
|
|
|
|
|
struct ath_hal *ah = sc->sc_ah;
|
|
|
|
struct ieee80211com *ic = &sc->sc_ic;
|
|
|
|
int required = 0;
|
|
|
|
|
|
|
|
/* Do not attempt to change radar state when bg scanning is
|
|
|
|
* the cause */
|
|
|
|
if (ic->ic_flags & IEEE80211_F_SCAN)
|
|
|
|
return 1;
|
|
|
|
|
|
|
|
/* Update the DFS flags (as a sanity check) */
|
|
|
|
if (ath_radar_correct_dfs_flags(sc, &sc->sc_curchan))
|
2009-07-11 21:20:58 +04:00
|
|
|
DPRINTF(sc, ATH_DEBUG_DOTH, "channel required "
|
|
|
|
"corrections to private flags.\n");
|
|
|
|
required = ((sc->sc_curchan.privFlags & CHANNEL_DFS) &&
|
|
|
|
(ic->ic_flags & IEEE80211_F_DOTH));
|
2008-01-26 23:48:11 +03:00
|
|
|
/* configure radar pulse detector register using default values, but do
|
|
|
|
* not toggle the enable bit. XXX: allow tweaking?? */
|
|
|
|
ath_radar_set_params(sc, NULL);
|
2009-04-28 09:33:47 +04:00
|
|
|
if (ar_device(sc) >= 5211) {
|
2008-01-26 23:48:11 +03:00
|
|
|
HAL_INT old_ier = ath_hal_intrget(ah);
|
|
|
|
HAL_INT new_ier = old_ier;
|
|
|
|
unsigned int old_radar = OS_REG_READ(ah, AR5K_PHY_RADAR);
|
|
|
|
unsigned int old_filter =
|
|
|
|
OS_REG_READ(ah, AR5K_AR5212_PHY_ERR_FIL);
|
|
|
|
unsigned int old_rxfilt = ath_hal_getrxfilter(ah);
|
|
|
|
unsigned int old_mask = sc->sc_imask;
|
|
|
|
unsigned int new_radar = old_radar;
|
|
|
|
unsigned int new_filter = old_filter;
|
|
|
|
unsigned int new_mask = old_mask;
|
|
|
|
unsigned int new_rxfilt = old_rxfilt;
|
|
|
|
|
|
|
|
ath_hal_intrset(ah, old_ier & ~HAL_INT_GLOBAL);
|
|
|
|
if (required) {
|
|
|
|
new_radar |= AR5K_PHY_RADAR_ENABLE;
|
|
|
|
new_filter |= AR5K_AR5212_PHY_ERR_FIL_RADAR;
|
2009-07-11 21:25:26 +04:00
|
|
|
new_rxfilt |= HAL_RX_FILTER_PHYRADAR;
|
2008-01-26 23:48:11 +03:00
|
|
|
new_mask |= HAL_INT_RXPHY;
|
|
|
|
new_ier |= HAL_INT_RXPHY;
|
|
|
|
} else {
|
|
|
|
new_radar &= ~AR5K_PHY_RADAR_ENABLE;
|
|
|
|
new_filter &= ~AR5K_AR5212_PHY_ERR_FIL_RADAR;
|
|
|
|
new_rxfilt &= ~HAL_RX_FILTER_PHYRADAR;
|
|
|
|
new_mask &= ~HAL_INT_RXPHY;
|
|
|
|
new_ier &= ~HAL_INT_RXPHY;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (old_filter != new_filter)
|
|
|
|
OS_REG_WRITE(ah, AR5K_AR5212_PHY_ERR_FIL, new_filter);
|
|
|
|
if (old_radar != new_radar)
|
|
|
|
OS_REG_WRITE(ah, AR5K_PHY_RADAR, new_radar);
|
|
|
|
if (old_rxfilt != new_rxfilt)
|
|
|
|
ath_hal_setrxfilter(ah, new_rxfilt);
|
|
|
|
|
|
|
|
sc->sc_imask = new_mask;
|
|
|
|
if (DFLAG_ISSET(sc, ATH_DEBUG_DOTH) &&
|
|
|
|
((old_radar != new_radar) ||
|
|
|
|
(old_filter != new_filter) ||
|
|
|
|
(old_rxfilt != new_rxfilt) ||
|
|
|
|
(old_mask != new_mask) ||
|
|
|
|
(old_ier != new_ier))) {
|
|
|
|
DPRINTF(sc, ATH_DEBUG_DOTH,
|
2008-07-17 07:44:41 +04:00
|
|
|
"%s: %s: Radar detection %s.\n", SC_DEV_NAME(sc),
|
2008-01-26 23:48:11 +03:00
|
|
|
__func__, required ? "enabled" : "disabled");
|
|
|
|
}
|
|
|
|
ath_hal_intrset(ah, new_ier);
|
|
|
|
}
|
|
|
|
|
|
|
|
return (required == ath_radar_is_enabled(sc));
|
|
|
|
}
|
|
|
|
|
2009-07-11 21:20:58 +04:00
|
|
|
static
|
|
|
|
int ath_radar_is_indoor_channel(HAL_CHANNEL *hchan)
|
|
|
|
{
|
|
|
|
/* Warning : we use hardcoded values here suited for France */
|
|
|
|
if ((hchan->channel >= 2412) && (hchan->channel <= 2472))
|
|
|
|
return 1;
|
|
|
|
if ((hchan->channel >= 5150) && (hchan->channel <= 5350))
|
|
|
|
return 1;
|
|
|
|
if ((hchan->channel >= 5470) && (hchan->channel <= 5725))
|
|
|
|
return 1;
|
|
|
|
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
static
|
|
|
|
int ath_radar_is_outdoor_channel(HAL_CHANNEL *hchan)
|
|
|
|
{
|
|
|
|
/* Warning : we use hardcoded values here suited for France */
|
|
|
|
if ((hchan->channel >= 2412) && (hchan->channel <= 2472))
|
|
|
|
return 1;
|
|
|
|
if ((hchan->channel >= 5470) && (hchan->channel <= 5725))
|
|
|
|
return 1;
|
|
|
|
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
/* Update channel's DFS flags based upon whether DFS is required. Return true
|
|
|
|
* if the value was repaired. It also add flags to know if a channel can be
|
|
|
|
* used indoor or outdoor or both. Those flags have been added and made
|
|
|
|
* compatible with HAL flags (as defined in <hal/ah.h> */
|
|
|
|
|
|
|
|
#define CHANNEL_INDOOR 0x00004
|
|
|
|
#define CHANNEL_OUTDOOR 0x00008
|
|
|
|
|
2008-01-26 23:48:11 +03:00
|
|
|
int ath_radar_correct_dfs_flags(struct ath_softc *sc, HAL_CHANNEL *hchan)
|
|
|
|
{
|
|
|
|
u_int32_t old_channelFlags = hchan->channelFlags;
|
2009-07-11 21:20:58 +04:00
|
|
|
u_int8_t old_privFlags = hchan->privFlags;
|
|
|
|
int changed;
|
|
|
|
|
2008-01-26 23:48:11 +03:00
|
|
|
if (ath_radar_is_dfs_required(sc, hchan)) {
|
|
|
|
hchan->channelFlags |= CHANNEL_PASSIVE;
|
|
|
|
hchan->privFlags |= CHANNEL_DFS;
|
|
|
|
} else {
|
|
|
|
hchan->channelFlags &= ~CHANNEL_PASSIVE;
|
|
|
|
hchan->privFlags &= ~CHANNEL_DFS;
|
|
|
|
}
|
2009-07-11 21:20:58 +04:00
|
|
|
|
|
|
|
changed = ((old_privFlags != hchan->privFlags) ||
|
|
|
|
(old_channelFlags != hchan->channelFlags));
|
|
|
|
|
|
|
|
hchan->channelFlags &= ~(CHANNEL_INDOOR | CHANNEL_OUTDOOR);
|
|
|
|
|
|
|
|
if (ath_radar_is_indoor_channel(hchan)) {
|
|
|
|
hchan->channelFlags |= CHANNEL_INDOOR;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (ath_radar_is_outdoor_channel(hchan)) {
|
|
|
|
hchan->channelFlags |= CHANNEL_OUTDOOR;
|
|
|
|
}
|
|
|
|
|
|
|
|
return changed;
|
2008-01-26 23:48:11 +03:00
|
|
|
}
|
|
|
|
|
|
|
|
/* Returns true if DFS is required for the regulatory domain, country and
|
|
|
|
* combination in use.
|
|
|
|
* XXX: Need to add regulatory rules in here. This is too conservative! */
|
|
|
|
int ath_radar_is_dfs_required(struct ath_softc *sc, HAL_CHANNEL *hchan)
|
|
|
|
{
|
|
|
|
/* For FCC: 5250 to 5350MHz (channel 52 to 60) and for Europe added
|
|
|
|
* 5470 to 5725 MHz (channel 100 to 140).
|
|
|
|
* Being conservative, go with the entire band from 5250-5725 MHz. */
|
|
|
|
return ((hchan->channel >= 5250) && (hchan->channel <= 5725)) ? 1 : 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
static struct ath_rp *pulse_head(struct ath_softc *sc)
|
|
|
|
{
|
|
|
|
return list_entry(sc->sc_rp_list.next,
|
|
|
|
struct ath_rp, list);
|
|
|
|
}
|
|
|
|
|
|
|
|
static struct ath_rp *pulse_tail(struct ath_softc *sc)
|
|
|
|
{
|
|
|
|
return list_entry(sc->sc_rp_list.prev,
|
|
|
|
struct ath_rp, list);
|
|
|
|
}
|
|
|
|
|
|
|
|
static struct ath_rp *pulse_prev(struct ath_rp *pulse)
|
|
|
|
{
|
|
|
|
return list_entry(pulse->list.prev,
|
|
|
|
struct ath_rp, list);
|
|
|
|
}
|
|
|
|
|
|
|
|
#define CR_FALLTHROUGH 0
|
|
|
|
#define CR_NULL 1
|
|
|
|
#define CR_EXCESS_INTERVALS 2
|
|
|
|
#define CR_INTERVALS 3
|
|
|
|
#define CR_EXCESS_DURATION 4
|
|
|
|
#define CR_DURATION 5
|
|
|
|
#define CR_PULSES 6
|
|
|
|
#define CR_MISSES 7
|
|
|
|
#define CR_MIDPOINT_A 8
|
|
|
|
#define CR_MIDPOINT_B 9
|
|
|
|
#define CR_MIDPOINT_C 10
|
|
|
|
#define CR_NOISE 11
|
|
|
|
|
|
|
|
#define MR_MATCH 0
|
|
|
|
#define MR_FAIL_MIN_INTERVALS 1
|
|
|
|
#define MR_FAIL_REQD_MATCHES 2
|
|
|
|
#define MR_FAIL_MAX_MISSES 3
|
|
|
|
#define MR_FAIL_MIN_PERIOD 4
|
|
|
|
#define MR_FAIL_MAX_PERIOD 5
|
|
|
|
|
2008-04-11 03:48:41 +04:00
|
|
|
#ifdef AR_DEBUG
|
2008-07-17 11:29:42 +04:00
|
|
|
static const char *get_match_result_desc(u_int32_t code)
|
|
|
|
{
|
2008-01-26 23:48:11 +03:00
|
|
|
switch (code) {
|
|
|
|
case MR_MATCH:
|
|
|
|
return "MATCH";
|
|
|
|
case MR_FAIL_MIN_INTERVALS:
|
|
|
|
return "TOO-SHORT";
|
|
|
|
case MR_FAIL_REQD_MATCHES:
|
|
|
|
return "TOO-FEW";
|
|
|
|
case MR_FAIL_MAX_MISSES:
|
|
|
|
return "TOO-LOSSY";
|
|
|
|
case MR_FAIL_MIN_PERIOD:
|
|
|
|
return "PRI<MIN";
|
|
|
|
case MR_FAIL_MAX_PERIOD:
|
|
|
|
return "PRI>MAX";
|
|
|
|
default:
|
|
|
|
return "unknown";
|
|
|
|
}
|
|
|
|
}
|
2008-04-11 03:48:41 +04:00
|
|
|
#endif /* AR_DEBUG */
|
2008-01-26 23:48:11 +03:00
|
|
|
|
|
|
|
static int32_t match_radar(
|
|
|
|
u_int32_t matched,
|
|
|
|
u_int32_t missed,
|
|
|
|
u_int32_t mean_period,
|
|
|
|
u_int32_t noise,
|
|
|
|
u_int32_t min_evts,
|
|
|
|
u_int32_t max_evts,
|
|
|
|
u_int32_t min_rep_int,
|
|
|
|
u_int32_t max_rep_int,
|
|
|
|
u_int32_t min_pulse,
|
|
|
|
u_int32_t max_misses)
|
|
|
|
{
|
|
|
|
/* Not a match: insufficient overall burst length */
|
|
|
|
if ( (matched + missed) < min_evts)
|
|
|
|
return MR_FAIL_MIN_INTERVALS;
|
|
|
|
|
|
|
|
/* Not a match: insufficient match count */
|
|
|
|
if (matched < min_pulse)
|
|
|
|
return MR_FAIL_REQD_MATCHES;
|
|
|
|
|
|
|
|
/* Not a match: too many missies */
|
|
|
|
if (missed > max_misses)
|
|
|
|
return MR_FAIL_MAX_MISSES;
|
|
|
|
|
|
|
|
/* Not a match, PRI out of range */
|
|
|
|
if (mean_period < min_rep_int)
|
|
|
|
return MR_FAIL_MIN_PERIOD;
|
|
|
|
|
|
|
|
/* Not a match, PRI out of range */
|
|
|
|
if (mean_period > max_rep_int)
|
|
|
|
return MR_FAIL_MAX_PERIOD;
|
|
|
|
|
|
|
|
return MR_MATCH;
|
|
|
|
}
|
|
|
|
|
|
|
|
static int32_t compare_radar_matches(
|
|
|
|
int32_t a_matched,
|
|
|
|
int32_t a_missed,
|
|
|
|
int32_t a_mean_period,
|
|
|
|
int32_t a_noise,
|
|
|
|
int32_t a_min_evts,
|
|
|
|
int32_t a_max_evts,
|
|
|
|
int32_t a_min_rep_int,
|
|
|
|
int32_t a_max_rep_int,
|
|
|
|
int32_t a_min_pulse,
|
|
|
|
int32_t a_max_misses,
|
|
|
|
HAL_BOOL a_match_midpoint,
|
|
|
|
int32_t b_matched,
|
|
|
|
int32_t b_missed,
|
|
|
|
int32_t b_mean_period,
|
|
|
|
int32_t b_noise,
|
|
|
|
int32_t b_min_evts,
|
|
|
|
int32_t b_max_evts,
|
|
|
|
int32_t b_min_rep_int,
|
|
|
|
int32_t b_max_rep_int,
|
|
|
|
int32_t b_min_pulse,
|
|
|
|
int32_t b_max_misses,
|
|
|
|
HAL_BOOL b_match_midpoint
|
|
|
|
)
|
|
|
|
{
|
|
|
|
/* Intermediate calculations */
|
|
|
|
int32_t a_total = a_matched + a_missed;
|
|
|
|
int32_t b_total = b_matched + b_missed;
|
|
|
|
int32_t a_excess_total =
|
|
|
|
MAX((int32_t)(a_total - (int32_t)a_max_evts), 0);
|
|
|
|
int32_t b_excess_total =
|
|
|
|
MAX((int32_t)(b_total - (int32_t)b_max_evts), 0);
|
|
|
|
u_int64_t a_duration = a_total * a_mean_period;
|
|
|
|
u_int64_t b_duration = b_total * b_mean_period;
|
|
|
|
u_int64_t a_excess_duration = a_excess_total * a_mean_period;
|
|
|
|
u_int64_t b_excess_duration = b_excess_total * b_mean_period;
|
|
|
|
u_int64_t a_dist_from_pri_mid = labs(a_mean_period -
|
|
|
|
(a_min_rep_int +
|
|
|
|
((a_max_rep_int - a_min_rep_int) / 2)));
|
|
|
|
u_int64_t b_dist_from_pri_mid = labs(b_mean_period -
|
|
|
|
(b_min_rep_int +
|
|
|
|
((b_max_rep_int - b_min_rep_int) / 2)));
|
|
|
|
/* Did one radar have fewer excess total pulse intervals than the
|
|
|
|
* other? */
|
|
|
|
if (a_excess_total != b_excess_total)
|
|
|
|
return ((a_excess_total < b_excess_total) ? 1 : -1) *
|
|
|
|
CR_EXCESS_INTERVALS;
|
|
|
|
/* Was one pulse longer chronologically, even though totals matched? */
|
|
|
|
else if (a_excess_duration != b_excess_duration)
|
|
|
|
return ((a_excess_duration < b_excess_duration) ? 1 : -1) *
|
|
|
|
CR_EXCESS_DURATION;
|
|
|
|
/* Did one get more matches? */
|
|
|
|
if (a_matched != b_matched)
|
|
|
|
return (a_matched > b_matched ? 1 : -1) * CR_PULSES;
|
|
|
|
/* Both waveforms are the same length, same total.
|
|
|
|
* Did one get more misses? */
|
|
|
|
if (a_missed != b_missed)
|
|
|
|
return (a_missed < b_missed ? 1 : -1) * CR_MISSES;
|
|
|
|
/* Did one get more noise? */
|
|
|
|
if (a_noise != b_noise)
|
|
|
|
return (a_noise < b_noise ? 1 : -1) * CR_NOISE;
|
|
|
|
/* If both waveforms were not too long in terms of intervals */
|
|
|
|
if (0 == (a_excess_total+b_excess_total)) {
|
|
|
|
/* Did one waveform have to match more events than the other? */
|
|
|
|
if (a_total != b_total)
|
|
|
|
return ((a_total > b_total) ? 1 : -1) * CR_INTERVALS;
|
|
|
|
/* Was one waveform longer than the other */
|
|
|
|
if (a_duration != b_duration)
|
|
|
|
return ((a_duration > b_duration) ? 1 : -1) * CR_DURATION;
|
|
|
|
}
|
|
|
|
/* both durations are legal, but one is closer to the original PRF/PRI */
|
|
|
|
if (a_dist_from_pri_mid != b_dist_from_pri_mid) {
|
|
|
|
if (a_match_midpoint && b_match_midpoint) {
|
|
|
|
/* Which pattern is closer to midpoint? */
|
|
|
|
return ((a_dist_from_pri_mid < b_dist_from_pri_mid) ? 1 : -1) *
|
|
|
|
CR_MIDPOINT_A;
|
|
|
|
}
|
|
|
|
else if (a_match_midpoint) {
|
|
|
|
/* If not within spitting distance of midpoint, reject */
|
|
|
|
return ((a_dist_from_pri_mid < 3) ? 1 : -1) *
|
|
|
|
CR_MIDPOINT_B;
|
|
|
|
|
|
|
|
}
|
|
|
|
else if (b_match_midpoint) {
|
|
|
|
/* If not within spitting distance of midpoint, reject */
|
|
|
|
return ((b_dist_from_pri_mid >= 3) ? 1 : -1) *
|
|
|
|
CR_MIDPOINT_C;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
return -CR_FALLTHROUGH;
|
|
|
|
}
|
|
|
|
|
|
|
|
#ifdef ATH_RADAR_LONG_PULSE
|
|
|
|
|
|
|
|
struct lp_burst {
|
|
|
|
u_int32_t lpb_num_pulses;
|
|
|
|
u_int32_t lpb_num_noise;
|
|
|
|
u_int32_t lpb_tsf_delta;
|
|
|
|
u_int64_t lpb_tsf_rel;
|
|
|
|
u_int64_t lpb_min_possible_tsf; /* noise vs real pulses */
|
|
|
|
u_int64_t lpb_max_possible_tsf; /* noise vs real pulses */
|
|
|
|
};
|
|
|
|
|
|
|
|
static const u_int32_t LP_MIN_BC = 8;
|
|
|
|
static const u_int32_t LP_MAX_BC = 20;
|
|
|
|
static const u_int32_t LP_NUM_BC = 13; /* (LP_MAX_BC - LP_MIN_BC + 1); */
|
|
|
|
static const u_int64_t LP_TSF_FUZZ_US = 32768; /* (1<<15) because rs_tstamp
|
|
|
|
* rollover errors */
|
|
|
|
static const u_int32_t LP_MIN_PRI = 1000;
|
|
|
|
static const u_int32_t LP_MAX_PRI = 2000;
|
|
|
|
|
|
|
|
static void rp_analyze_long_pulse_bscan(
|
|
|
|
struct ath_softc *sc,
|
|
|
|
struct ath_rp *last_pulse,
|
|
|
|
u_int32_t *num_bursts,
|
|
|
|
size_t bursts_buflen,
|
2008-06-07 00:32:29 +04:00
|
|
|
struct lp_burst *bursts)
|
2008-01-26 23:48:11 +03:00
|
|
|
{
|
|
|
|
int i = 0;
|
|
|
|
struct ath_rp *newer = NULL;
|
|
|
|
struct ath_rp *cur = last_pulse;
|
|
|
|
struct ath_rp *older = pulse_prev(last_pulse);
|
|
|
|
u_int32_t waveform_num_bursts = 0;
|
|
|
|
|
|
|
|
if (num_bursts)
|
|
|
|
*num_bursts = 0;
|
|
|
|
|
|
|
|
for (;;) {
|
|
|
|
/* check if we are at the end of the list */
|
|
|
|
if (&cur->list == &sc->sc_rp_head)
|
|
|
|
break;
|
|
|
|
if (!cur->rp_allocated)
|
|
|
|
break;
|
|
|
|
|
|
|
|
if (NULL != newer) {
|
|
|
|
u_int64_t tsf_delta = 0;
|
|
|
|
u_int64_t tsf_adjustment = 0;
|
|
|
|
|
|
|
|
/* Figure out TSF delta, taking into account
|
|
|
|
* up to one multiple of (1<<15) of clock jitter
|
|
|
|
* due to interrupt latency */
|
|
|
|
tsf_delta = newer->rp_tsf - cur->rp_tsf;
|
|
|
|
if ((tsf_delta - LP_TSF_FUZZ_US) >= LP_MIN_PRI &&
|
|
|
|
(tsf_delta - LP_TSF_FUZZ_US) <= LP_MAX_PRI) {
|
|
|
|
tsf_adjustment = LP_TSF_FUZZ_US;
|
|
|
|
tsf_delta -= tsf_adjustment;
|
|
|
|
}
|
|
|
|
|
2008-06-07 00:32:29 +04:00
|
|
|
/* If we are in range for pulse, assume it is a pulse. */
|
2008-01-26 23:48:11 +03:00
|
|
|
if ((tsf_delta >= LP_MIN_PRI) && (tsf_delta <= LP_MAX_PRI)) {
|
|
|
|
bursts[waveform_num_bursts].lpb_num_pulses++;
|
|
|
|
bursts[waveform_num_bursts].lpb_min_possible_tsf =
|
|
|
|
cur->rp_tsf - tsf_adjustment;
|
|
|
|
}
|
|
|
|
else if (tsf_delta < LP_MIN_PRI) {
|
|
|
|
bursts[waveform_num_bursts].lpb_num_noise++;
|
|
|
|
/* It may have been THE pulse after all... */
|
|
|
|
bursts[waveform_num_bursts].lpb_min_possible_tsf =
|
|
|
|
cur->rp_tsf - tsf_adjustment;
|
|
|
|
}
|
|
|
|
else /* tsf_delta > LP_MAX_PRI */ {
|
|
|
|
bursts[waveform_num_bursts].lpb_num_pulses++;
|
|
|
|
bursts[waveform_num_bursts].lpb_min_possible_tsf =
|
|
|
|
cur->rp_tsf;
|
|
|
|
/* Do not overrun bursts_buflen */
|
|
|
|
if ((waveform_num_bursts+1) >= bursts_buflen) {
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
waveform_num_bursts++;
|
|
|
|
bursts[waveform_num_bursts].lpb_tsf_delta = tsf_delta;
|
|
|
|
bursts[waveform_num_bursts].lpb_min_possible_tsf =
|
|
|
|
cur->rp_tsf;
|
|
|
|
bursts[waveform_num_bursts].lpb_max_possible_tsf =
|
|
|
|
cur->rp_tsf;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
else {
|
|
|
|
bursts[waveform_num_bursts].lpb_max_possible_tsf =
|
|
|
|
cur->rp_tsf;
|
|
|
|
}
|
|
|
|
|
|
|
|
/* advance to next pulse */
|
|
|
|
newer = cur;
|
|
|
|
cur = pulse_prev(cur);
|
|
|
|
older = pulse_prev(cur);
|
|
|
|
}
|
|
|
|
if (num_bursts) {
|
|
|
|
bursts[waveform_num_bursts].lpb_num_pulses++;
|
|
|
|
waveform_num_bursts++;
|
|
|
|
*num_bursts = waveform_num_bursts;
|
|
|
|
}
|
|
|
|
for (i = 0; i < waveform_num_bursts; i++)
|
|
|
|
bursts[i].lpb_tsf_rel =
|
|
|
|
bursts[i].lpb_max_possible_tsf -
|
|
|
|
bursts[waveform_num_bursts-1].lpb_min_possible_tsf;
|
|
|
|
}
|
|
|
|
|
|
|
|
static HAL_BOOL rp_analyze_long_pulse(
|
|
|
|
struct ath_softc *sc, struct ath_rp *last_pulse,
|
2008-06-07 00:32:29 +04:00
|
|
|
u_int32_t *bc,
|
|
|
|
u_int32_t *matched, u_int32_t *missed,
|
|
|
|
u_int32_t *noise, u_int32_t *pulses)
|
2008-01-26 23:48:11 +03:00
|
|
|
{
|
|
|
|
int i;
|
|
|
|
int32_t found_radar = 0;
|
|
|
|
int32_t found_burst_count = 0;
|
|
|
|
int32_t matching_burst_count = 0;
|
|
|
|
u_int32_t best_bc = 0;
|
|
|
|
u_int32_t best_matched = 0;
|
|
|
|
u_int32_t best_missed = 0;
|
|
|
|
u_int32_t best_noise = 0;
|
|
|
|
u_int32_t best_pulses = 0;
|
|
|
|
|
|
|
|
struct lp_burst bursts[LP_MAX_BC];
|
|
|
|
memset(&bursts, 0, sizeof(bursts));
|
|
|
|
|
|
|
|
if (bc)
|
|
|
|
*bc = 0;
|
|
|
|
if (matched)
|
|
|
|
*matched = 0;
|
|
|
|
if (missed)
|
|
|
|
*missed = 0;
|
|
|
|
if (noise)
|
|
|
|
*noise = 0;
|
|
|
|
|
|
|
|
rp_analyze_long_pulse_bscan(sc, last_pulse,
|
|
|
|
&found_burst_count,
|
|
|
|
LP_MAX_BC, &bursts[0]);
|
|
|
|
/* Find the matches */
|
|
|
|
for (matching_burst_count = LP_MAX_BC;
|
|
|
|
matching_burst_count >= LP_MIN_BC;
|
|
|
|
matching_burst_count--) {
|
|
|
|
int32_t first_matched_index = -1;
|
|
|
|
int32_t last_matched_index = -1;
|
|
|
|
int32_t match_burst_index = 0;
|
|
|
|
int32_t found_burst_index = 0;
|
|
|
|
int32_t burst_period = (12000000 / matching_burst_count);
|
|
|
|
int32_t waveform_offset = 0;
|
|
|
|
int32_t total_big_gaps = 0;
|
|
|
|
int32_t matched_span = 0;
|
|
|
|
int32_t missed_bursts = 0;
|
|
|
|
int32_t matched_bursts = 0;
|
|
|
|
for (i = 0; i < matching_burst_count; i++) {
|
|
|
|
int32_t d = bursts[i].lpb_tsf_delta;
|
|
|
|
while (d >= burst_period)
|
|
|
|
d -= burst_period;
|
|
|
|
total_big_gaps += d;
|
|
|
|
waveform_offset = MAX(waveform_offset, d);
|
|
|
|
}
|
|
|
|
waveform_offset *= -1;
|
|
|
|
|
|
|
|
found_burst_index = 0;
|
|
|
|
for (match_burst_index = 0;
|
|
|
|
match_burst_index < matching_burst_count;
|
|
|
|
match_burst_index++) {
|
|
|
|
int64_t limit_high = (burst_period *
|
|
|
|
(matching_burst_count - 1 -
|
|
|
|
match_burst_index + 1)) +
|
|
|
|
(2 * LP_TSF_FUZZ_US);
|
|
|
|
int64_t limit_low = (burst_period *
|
|
|
|
(matching_burst_count - 1 -
|
|
|
|
match_burst_index)) -
|
|
|
|
(2 * LP_TSF_FUZZ_US);
|
|
|
|
/* If the burst is too old, skip it... it's noise too... */
|
|
|
|
while ((((int64_t)bursts[found_burst_index].lpb_tsf_rel +
|
|
|
|
waveform_offset) >
|
|
|
|
limit_high)) {
|
|
|
|
if (found_burst_index < (found_burst_count - 1))
|
|
|
|
found_burst_index++;
|
|
|
|
else
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
if ((((int64_t)bursts[found_burst_index].lpb_tsf_rel +
|
|
|
|
waveform_offset) <=
|
|
|
|
limit_high) &&
|
|
|
|
(((int64_t)bursts[found_burst_index].lpb_tsf_rel +
|
|
|
|
waveform_offset) >= limit_low)) {
|
|
|
|
if (-1 == first_matched_index) {
|
|
|
|
first_matched_index = match_burst_index;
|
|
|
|
matched_span = 1;
|
|
|
|
}
|
|
|
|
if (last_matched_index < match_burst_index) {
|
|
|
|
last_matched_index = match_burst_index;
|
|
|
|
}
|
|
|
|
DPRINTF(sc, ATH_DEBUG_DOTHFILT,
|
|
|
|
"LP %2dp] [%2d/%2d] %10lld "
|
|
|
|
"in {%lld:%lld}] PASS\n",
|
|
|
|
matching_burst_count,
|
|
|
|
found_burst_index,
|
|
|
|
match_burst_index,
|
|
|
|
(int64_t)bursts[found_burst_index].lpb_tsf_rel -
|
|
|
|
waveform_offset,
|
|
|
|
limit_low, limit_high);
|
|
|
|
matched_bursts++;
|
|
|
|
found_burst_index++;
|
|
|
|
}
|
|
|
|
else {
|
|
|
|
DPRINTF(sc, ATH_DEBUG_DOTHFILT,
|
|
|
|
"LP %2dp] [%2d/%2d] %10lld "
|
|
|
|
"in {%lld:%lld}] MISSED\n",
|
|
|
|
matching_burst_count,
|
|
|
|
match_burst_index,
|
|
|
|
found_burst_index,
|
|
|
|
(int64_t)bursts[found_burst_index].lpb_tsf_rel -
|
|
|
|
waveform_offset,
|
|
|
|
limit_low, limit_high);
|
|
|
|
missed_bursts++;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
matched_span = last_matched_index - first_matched_index;
|
|
|
|
DPRINTF(sc, ATH_DEBUG_DOTHFILT, "LP %2dp] burst_period=%10d, "
|
|
|
|
"waveform_offset=%10d, matches=%2d/%2d, "
|
|
|
|
"result=%s\n",
|
|
|
|
matching_burst_count, burst_period, waveform_offset,
|
|
|
|
matched_span, matching_burst_count,
|
|
|
|
(matching_burst_count == matched_span) ?
|
|
|
|
"MATCH" : "MISMATCH"
|
|
|
|
);
|
|
|
|
/* XXX - Add comparison logic rather than taking first/last
|
|
|
|
* match based upon ATH_DEBUG_DOTHFILTNOSC? */
|
|
|
|
if (matched_span >= (matching_burst_count - 4)) {
|
|
|
|
found_radar++;
|
|
|
|
best_bc = matching_burst_count;
|
|
|
|
best_matched = matched_bursts;
|
|
|
|
best_missed = missed_bursts;
|
|
|
|
best_noise = 0;
|
|
|
|
best_pulses = 0;
|
|
|
|
for (i = 0; i <= found_burst_index; i++) {
|
|
|
|
best_noise += bursts[match_burst_index].lpb_num_noise;
|
|
|
|
best_pulses += bursts[match_burst_index].lpb_num_pulses;
|
|
|
|
}
|
|
|
|
if (!DFLAG_ISSET(sc, ATH_DEBUG_DOTHFILTNOSC))
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
if (bc)
|
|
|
|
*bc = best_bc;
|
|
|
|
if (matched)
|
|
|
|
*matched = best_matched;
|
|
|
|
if (missed)
|
|
|
|
*missed = best_missed;
|
|
|
|
if (noise)
|
|
|
|
*noise = best_noise;
|
|
|
|
if (pulses)
|
|
|
|
*pulses = best_pulses;
|
|
|
|
|
|
|
|
return found_radar ? AH_TRUE : AH_FALSE;
|
|
|
|
}
|
|
|
|
#endif /* #ifdef ATH_RADAR_LONG_PULSE */
|
|
|
|
|
2008-07-17 06:26:04 +04:00
|
|
|
static HAL_BOOL rp_analyze_short_pulse(
|
2008-01-26 23:48:11 +03:00
|
|
|
struct ath_softc *sc, struct ath_rp *last_pulse,
|
|
|
|
u_int32_t *index, u_int32_t *pri, u_int32_t *matching_pulses,
|
|
|
|
u_int32_t *missed_pulses, u_int32_t *noise_pulses)
|
2008-04-11 03:48:41 +04:00
|
|
|
{
|
2008-01-26 23:48:11 +03:00
|
|
|
int i;
|
|
|
|
int best_index = -1;
|
|
|
|
unsigned int best_matched = 0;
|
|
|
|
unsigned int best_noise = 0;
|
|
|
|
unsigned int best_missed = 0;
|
|
|
|
unsigned int best_pri = 0;
|
|
|
|
unsigned int best_cr = 0;
|
2009-07-11 21:25:26 +04:00
|
|
|
u_int64_t t0;
|
2008-01-26 23:48:11 +03:00
|
|
|
|
|
|
|
struct ath_rp *pulse;
|
|
|
|
u_int32_t pulse_count_minimum = 0;
|
|
|
|
struct radar_pattern_specification *pattern = NULL;
|
|
|
|
struct radar_pattern_specification *best_pattern = NULL;
|
|
|
|
|
|
|
|
if (index)
|
|
|
|
*index = 0;
|
|
|
|
if (pri)
|
|
|
|
*pri = 0;
|
|
|
|
if (noise_pulses)
|
|
|
|
*noise_pulses = 0;
|
|
|
|
if (matching_pulses)
|
|
|
|
*matching_pulses = 0;
|
|
|
|
if (missed_pulses)
|
|
|
|
*missed_pulses = 0;
|
|
|
|
|
|
|
|
/* we need at least sc_rp_min (>2 pulses) */
|
|
|
|
pulse_count_minimum = sc->sc_rp_min;
|
|
|
|
if ((sc->sc_rp_num < pulse_count_minimum) ||
|
|
|
|
(sc->sc_rp_num < 2))
|
|
|
|
return 0;
|
|
|
|
|
|
|
|
/* Search algorithm:
|
|
|
|
*
|
|
|
|
* - since we have a limited and known number of radar patterns, we
|
|
|
|
* loop on all possible radar pulse period
|
|
|
|
*
|
2009-07-11 21:25:26 +04:00
|
|
|
* - we start the search from the last timestamp (t0), going backward
|
|
|
|
* in time, up to the point for the first possible radar pulse, ie
|
|
|
|
* t0 - PERIOD_MAX * BURST_MAX
|
2008-01-26 23:48:11 +03:00
|
|
|
*
|
2009-07-11 21:25:26 +04:00
|
|
|
* - on this timescale, we matched the number of hit/missed using t0 -
|
2008-06-07 00:32:29 +04:00
|
|
|
* PERIOD * n taking into account the 2% error margin (using
|
2008-01-26 23:48:11 +03:00
|
|
|
* min_rep_int, max_rep_int)
|
|
|
|
*
|
|
|
|
* At the end, we have a number of pulse hit for each PRF
|
|
|
|
*
|
|
|
|
* TSF will roll over after just over 584,542 years of operation
|
|
|
|
* without restart.
|
|
|
|
*
|
|
|
|
* This exceeds all known Atheros MTBF so, forget about TSF roll over.
|
|
|
|
*/
|
|
|
|
|
|
|
|
/* loop through all patterns */
|
|
|
|
for (i = 0; i < sizetab(radar_patterns); i++) {
|
2009-07-11 21:25:26 +04:00
|
|
|
int matched = 1, missed = 0, partial_miss = 0, noise = 0;
|
|
|
|
int64_t t, last_t, t_min, t_avg, t_max, tn_max;
|
|
|
|
int A, B, N, C, D, SUM_SQR;
|
|
|
|
int a, a_min, a_avg, a_max;
|
|
|
|
int b, b_min, b_avg, b_max;
|
|
|
|
int count;
|
|
|
|
int last_matched = 0;
|
2008-01-26 23:48:11 +03:00
|
|
|
|
2009-07-11 21:25:26 +04:00
|
|
|
pattern = &radar_patterns[i];
|
2008-01-26 23:48:11 +03:00
|
|
|
|
2009-07-11 21:25:26 +04:00
|
|
|
/* t0 is the timestamp of the beginning of the last radar
|
|
|
|
* pulse. We assume that the hardware reports the end of the
|
|
|
|
* pulse, so we compute the beginning based on the reported
|
|
|
|
* pulse width, which might larger than the real pulse.
|
|
|
|
*
|
|
|
|
* BIG WARNING : using FCC samples, it seems that this
|
|
|
|
* correction is not needed at all, so we are using the
|
|
|
|
* dyn_ints flag to avoid this correction */
|
|
|
|
t0 = last_pulse->rp_tsf;
|
|
|
|
if (!pattern->is_fcc)
|
|
|
|
t0 -= WIDTH_TO_TSF(last_pulse->rp_width);
|
|
|
|
|
|
|
|
/* initial values for a_min, a_avg, a_max and b_min, b_avg,
|
|
|
|
* b_max */
|
|
|
|
a_min = -10;
|
|
|
|
a_avg = 0;
|
|
|
|
a_max = +10;
|
|
|
|
|
|
|
|
b_min = pattern->min_rep_int;
|
|
|
|
b_avg = (pattern->min_rep_int + pattern->max_rep_int)/2;
|
|
|
|
b_max = pattern->max_rep_int;
|
|
|
|
|
|
|
|
/* initial values for t_min, t_avg, t_max */
|
|
|
|
t_min = a_min + b_min;
|
|
|
|
t_avg = a_avg + b_avg;
|
|
|
|
t_max = a_max + b_max;
|
2008-01-26 23:48:11 +03:00
|
|
|
|
|
|
|
/* this max formula is to stop when we exceed maximum time
|
2009-07-11 21:25:26 +04:00
|
|
|
* period for the pattern. It's the oldest possible value for
|
|
|
|
* t that could match. */
|
|
|
|
tn_max = a_max + b_max*(pattern->max_evts-1);
|
|
|
|
|
|
|
|
last_t = -1;
|
|
|
|
|
|
|
|
A = 0;
|
|
|
|
B = 0;
|
|
|
|
N = 1;
|
|
|
|
C = 0;
|
|
|
|
D = 0;
|
|
|
|
SUM_SQR = 0;
|
2008-01-26 23:48:11 +03:00
|
|
|
|
2009-07-11 21:25:26 +04:00
|
|
|
/* we directly start with the timestamp before t0 */
|
|
|
|
pulse = pulse_prev(last_pulse);
|
2008-01-26 23:48:11 +03:00
|
|
|
|
|
|
|
for (;;) {
|
|
|
|
|
|
|
|
/* check if we are at the end of the list */
|
|
|
|
if (&pulse->list == &sc->sc_rp_list)
|
|
|
|
break;
|
|
|
|
if (!pulse->rp_allocated)
|
|
|
|
break;
|
|
|
|
|
2009-07-11 21:25:26 +04:00
|
|
|
t = t0 - pulse->rp_tsf;
|
|
|
|
if (!pattern->is_fcc)
|
|
|
|
t += WIDTH_TO_TSF(pulse->rp_width);
|
|
|
|
|
2008-01-26 23:48:11 +03:00
|
|
|
/* Do not go too far... this is an optimization to not
|
2009-07-11 21:25:26 +04:00
|
|
|
* keep checking after we hit maximum time span for
|
|
|
|
* the pattern. */
|
|
|
|
if ((t < 0) || (t > tn_max)) {
|
2008-01-26 23:48:11 +03:00
|
|
|
DPRINTF(sc, ATH_DEBUG_DOTHFILTVBSE,
|
2009-07-11 21:25:26 +04:00
|
|
|
"%-17s [%2d] tsf: %10llu width: %3u "
|
|
|
|
"t:%5lld [range: %5lld-%5lld] [%2d] "
|
|
|
|
"%s\n",
|
2009-05-24 05:09:25 +04:00
|
|
|
pattern->name,
|
2009-07-11 21:25:26 +04:00
|
|
|
pulse->rp_index,
|
|
|
|
pulse->rp_tsf,
|
|
|
|
pulse->rp_width,
|
|
|
|
t, t_min, t_max,
|
|
|
|
matched+missed+partial_miss,
|
|
|
|
"overflow");
|
2008-01-26 23:48:11 +03:00
|
|
|
break;
|
|
|
|
}
|
|
|
|
|
2009-07-11 21:25:26 +04:00
|
|
|
/* we want to find the previous pulse in the range
|
|
|
|
* [t_min, t_max] which is closest to t_avg */
|
|
|
|
|
|
|
|
if (t < t_min) {
|
|
|
|
/* t < t_min : this pulse is not matching the
|
|
|
|
* current radar pattern, it is just
|
|
|
|
* noise. Ignore it by going to the next
|
|
|
|
* pulse */
|
|
|
|
|
2008-01-26 23:48:11 +03:00
|
|
|
DPRINTF(sc, ATH_DEBUG_DOTHFILTVBSE,
|
2009-07-11 21:25:26 +04:00
|
|
|
"%-17s [%2d] tsf: %10llu width: %3u "
|
|
|
|
"t:%5lld [range: %5lld-%5lld] [%2d] "
|
|
|
|
"%s\n",
|
2008-01-26 23:48:11 +03:00
|
|
|
pattern->name,
|
|
|
|
pulse->rp_index,
|
2009-07-11 21:25:26 +04:00
|
|
|
pulse->rp_tsf,
|
|
|
|
pulse->rp_width,
|
|
|
|
t, t_min, t_max,
|
|
|
|
matched+missed+partial_miss,
|
|
|
|
"noise");
|
|
|
|
|
2008-01-26 23:48:11 +03:00
|
|
|
/* this event is noise, ignore it */
|
|
|
|
pulse = pulse_prev(pulse);
|
|
|
|
noise++;
|
2009-07-11 21:25:26 +04:00
|
|
|
} else if (t <= t_max) {
|
|
|
|
/* t_min <= t <= t_max : this pulse is
|
|
|
|
* matching the current radar pattern */
|
|
|
|
|
|
|
|
if (last_t == -1) {
|
|
|
|
/* this pulse is the first matching pulse */
|
|
|
|
|
2008-01-26 23:48:11 +03:00
|
|
|
DPRINTF(sc, ATH_DEBUG_DOTHFILTVBSE,
|
2009-07-11 21:25:26 +04:00
|
|
|
"%-17s [%2d] tsf: %10llu width: %3u "
|
|
|
|
"t:%5lld [range: %5lld-%5lld] [%2d] "
|
|
|
|
"%s\n",
|
2009-06-25 04:01:52 +04:00
|
|
|
pattern->name,
|
2009-07-11 21:25:26 +04:00
|
|
|
pulse->rp_index,
|
|
|
|
pulse->rp_tsf,
|
|
|
|
pulse->rp_width,
|
|
|
|
t, t_min, t_max,
|
|
|
|
matched+missed+partial_miss,
|
|
|
|
"first match");
|
|
|
|
|
|
|
|
|
|
|
|
matched ++;
|
|
|
|
missed += partial_miss;
|
|
|
|
partial_miss = 0;
|
|
|
|
last_t = t;
|
|
|
|
|
|
|
|
count = matched+missed+partial_miss-1;
|
|
|
|
A += t;
|
|
|
|
B += t*count;
|
|
|
|
N += 1;
|
|
|
|
C += count;
|
|
|
|
D += count*count;
|
|
|
|
SUM_SQR += SQR( t - (a_avg+b_avg*count));
|
|
|
|
} else {
|
|
|
|
/* this pulse is not the first
|
|
|
|
* matching pulse. Check if it is
|
|
|
|
* closest to t_avg than the existing
|
|
|
|
* pulse */
|
|
|
|
if (labs(t-t_avg) < labs(last_t-t_avg)) {
|
|
|
|
|
|
|
|
/* this pulse is closer to
|
|
|
|
* t_avg. Update computation
|
|
|
|
* and go to the next pulse */
|
|
|
|
|
|
|
|
DPRINTF(sc, ATH_DEBUG_DOTHFILTVBSE,
|
|
|
|
"%-17s [%2d] tsf: %10llu width: %3u "
|
|
|
|
"t:%5lld [range: %5lld-%5lld] [%2d] "
|
|
|
|
"%s\n",
|
|
|
|
pattern->name,
|
|
|
|
pulse->rp_index,
|
|
|
|
pulse->rp_tsf,
|
|
|
|
pulse->rp_width,
|
|
|
|
t, t_min, t_max,
|
|
|
|
matched+missed+partial_miss,
|
|
|
|
"better match");
|
|
|
|
|
|
|
|
count = matched+missed+partial_miss-1;
|
|
|
|
A -= last_t;
|
|
|
|
B -= last_t*count;
|
|
|
|
SUM_SQR -= SQR( last_t - (a_avg+b_avg*count));
|
|
|
|
|
|
|
|
A += t;
|
|
|
|
B += t*count;
|
|
|
|
SUM_SQR += SQR( last_t - (a_avg+b_avg*count));
|
|
|
|
|
|
|
|
noise ++;
|
|
|
|
last_t = t;
|
|
|
|
} else {
|
|
|
|
/* this pulse is further to t_avg. */
|
|
|
|
|
|
|
|
DPRINTF(sc, ATH_DEBUG_DOTHFILTVBSE,
|
|
|
|
"%-17s [%2d] tsf: %10llu width: %3u "
|
|
|
|
"t:%5lld [range: %5lld-%5lld] [%2d] "
|
|
|
|
"%s\n",
|
|
|
|
pattern->name,
|
|
|
|
pulse->rp_index,
|
|
|
|
pulse->rp_tsf,
|
|
|
|
pulse->rp_width,
|
|
|
|
t, t_min, t_max,
|
|
|
|
matched+missed+partial_miss,
|
|
|
|
"worst match");
|
|
|
|
|
|
|
|
noise ++;
|
|
|
|
}
|
2008-01-26 23:48:11 +03:00
|
|
|
}
|
|
|
|
|
2009-07-11 21:25:26 +04:00
|
|
|
|
|
|
|
/* go to the previous pulse */
|
|
|
|
pulse = pulse_prev(pulse);
|
|
|
|
} else {
|
|
|
|
/* t > t_max : this pulse is not matching the
|
|
|
|
* current radar pattern yet. Update range */
|
|
|
|
|
2008-01-26 23:48:11 +03:00
|
|
|
DPRINTF(sc, ATH_DEBUG_DOTHFILTVBSE,
|
2009-07-11 21:25:26 +04:00
|
|
|
"%-17s [%2d] tsf: %10llu width: %3u "
|
|
|
|
"t:%5lld [range: %5lld-%5lld] [%2d] "
|
|
|
|
"%s\n",
|
2008-01-26 23:48:11 +03:00
|
|
|
pattern->name,
|
|
|
|
pulse->rp_index,
|
2009-07-11 21:25:26 +04:00
|
|
|
pulse->rp_tsf,
|
|
|
|
pulse->rp_width,
|
|
|
|
t, t_min, t_max,
|
|
|
|
matched + missed + partial_miss,
|
|
|
|
"range update");
|
|
|
|
|
|
|
|
|
|
|
|
/* we do not found a pulse in the current
|
|
|
|
* range, we increase the number of miss */
|
|
|
|
if (last_t == -1) {
|
|
|
|
partial_miss++;
|
|
|
|
|
|
|
|
/* if we missed more than the
|
|
|
|
* specified partial number of pulses,
|
|
|
|
* we stop searching */
|
|
|
|
if (partial_miss > pattern->max_consecutive_missing) {
|
|
|
|
DPRINTF(sc, ATH_DEBUG_DOTHFILTVBSE,
|
|
|
|
"%-17s matching stopped (too many "
|
|
|
|
"consecutive pulses missing). %d>%d "
|
|
|
|
"matched=%d. missed=%d.\n",
|
|
|
|
pattern->name,
|
|
|
|
partial_miss,
|
|
|
|
pattern->max_consecutive_missing,
|
|
|
|
matched, missed);
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
|
|
|
|
/* if we missed more than the
|
|
|
|
* specified total number of pulses,
|
|
|
|
* we stop searching */
|
|
|
|
if (missed + partial_miss > pattern->max_missing) {
|
|
|
|
DPRINTF(sc, ATH_DEBUG_DOTHFILTVBSE,
|
|
|
|
"%-17s matching stopped (too "
|
|
|
|
"many total pulses missing). "
|
|
|
|
"%d>%d matched=%d. missed=%d."
|
|
|
|
"\n",
|
|
|
|
pattern->name,
|
|
|
|
missed,
|
|
|
|
pattern->max_missing,
|
|
|
|
matched,
|
|
|
|
missed);
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
/* Quick update to b */
|
|
|
|
if ((1 < matched) && (matched < 4) &&
|
|
|
|
(matched!=last_matched)) {
|
|
|
|
int c = a_avg, d = b_avg;
|
|
|
|
|
|
|
|
if (C*C-N*D != 0) {
|
|
|
|
a = a_avg;
|
|
|
|
b = (C*A-N*B)/(C*C-N*D);
|
|
|
|
|
|
|
|
b_avg = b;
|
|
|
|
|
|
|
|
DPRINTF(sc, ATH_DEBUG_DOTHFILTVBSE,
|
|
|
|
"%-17s updating b_avg to %d\n",
|
|
|
|
pattern->name, b_avg);
|
|
|
|
|
|
|
|
SUM_SQR += (SQR(a)-SQR(c))*N+2*(a*b-c*d)*C+(SQR(b)-SQR(d))*D
|
|
|
|
-2*(a-c)*A-2*(b-d)*B;
|
|
|
|
|
|
|
|
last_matched = matched;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
/* Update (a,b) */
|
|
|
|
if ((matched >= 4) &&
|
|
|
|
(matched != last_matched)) {
|
|
|
|
int c = a_avg, d = b_avg;
|
|
|
|
|
|
|
|
if (C*C-N*D != 0) {
|
|
|
|
a=(C*B-A*D)/(C*C-N*D);
|
|
|
|
b=(C*A-N*B)/(C*C-N*D);
|
|
|
|
|
|
|
|
a_min = a-10;
|
|
|
|
a_avg = a;
|
|
|
|
a_max = a+10;
|
|
|
|
|
|
|
|
b_min = b-1;
|
|
|
|
b_avg = b;
|
|
|
|
b_max = b+1;
|
|
|
|
|
|
|
|
DPRINTF(sc, ATH_DEBUG_DOTHFILTVBSE,
|
|
|
|
"%-17s updating a to (%d,%d,%d) and b to (%d,%d,%d)\n",
|
|
|
|
pattern->name,
|
|
|
|
a_min, a_avg, a_max,
|
|
|
|
b_min, b_avg, b_max);
|
|
|
|
|
|
|
|
SUM_SQR += (SQR(a)-SQR(c))*N+2*(a*b-c*d)*C+(SQR(b)-SQR(d))*D
|
|
|
|
-2*(a-c)*A-2*(b-d)*B;
|
|
|
|
|
|
|
|
last_matched = matched;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
/* Update range */
|
|
|
|
count = matched+missed+partial_miss;
|
|
|
|
t_min = a_min + b_min*count;
|
|
|
|
t_avg = a_avg + b_avg*count;
|
|
|
|
t_max = a_max + b_max*count;
|
|
|
|
|
|
|
|
/* Check if we intersect with previous/next range */
|
|
|
|
/* t_min < t_max(count-1) */
|
|
|
|
if ((count>=1) && (t_min < a_max + b_max*(count-1))) {
|
|
|
|
|
|
|
|
t_min = a_avg + b_avg*count - b_avg/2;
|
2008-01-26 23:48:11 +03:00
|
|
|
|
|
|
|
DPRINTF(sc, ATH_DEBUG_DOTHFILTVBSE,
|
2009-07-11 21:25:26 +04:00
|
|
|
"%-17s [%2d] tsf: %10llu width: %3u "
|
|
|
|
"t:%5lld [range: %5lld-%5lld] [%2d] "
|
|
|
|
"%s\n",
|
2009-06-25 04:01:52 +04:00
|
|
|
pattern->name,
|
2009-07-11 21:25:26 +04:00
|
|
|
pulse->rp_index,
|
|
|
|
pulse->rp_tsf,
|
|
|
|
pulse->rp_width,
|
|
|
|
t, t_min, t_max,
|
|
|
|
matched + missed + partial_miss,
|
|
|
|
"updated t_min");
|
2008-01-26 23:48:11 +03:00
|
|
|
}
|
2009-07-11 21:25:26 +04:00
|
|
|
/* t_max > t_min(count+1) */
|
|
|
|
if (t_max > a_min + b_min*(count+1)) {
|
|
|
|
|
|
|
|
t_max = a_avg + b_avg*count + b_avg/2;
|
|
|
|
|
|
|
|
DPRINTF(sc, ATH_DEBUG_DOTHFILTVBSE,
|
|
|
|
"%-17s [%2d] tsf: %10llu width: %3u "
|
|
|
|
"t:%5lld [range: %5lld-%5lld] [%2d] "
|
|
|
|
"%s\n",
|
|
|
|
pattern->name,
|
|
|
|
pulse->rp_index,
|
|
|
|
pulse->rp_tsf,
|
|
|
|
pulse->rp_width,
|
|
|
|
t, t_min, t_max,
|
|
|
|
matched + missed + partial_miss,
|
|
|
|
"updated t_max");
|
|
|
|
}
|
|
|
|
last_t = -1;
|
2008-01-26 23:48:11 +03:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2009-07-11 21:25:26 +04:00
|
|
|
/* print counters for this PRF (we avoid case where the
|
|
|
|
* variance is greater than 100). 100 is based on the fact
|
|
|
|
* that most pulses are less than 10us from the ideal value
|
|
|
|
* and as such, variance should be less than 100 */
|
|
|
|
if ((matched > 1) &&
|
|
|
|
(N != 0) && (SUM_SQR/N<100)) {
|
2008-01-26 23:48:11 +03:00
|
|
|
int compare_result = CR_FALLTHROUGH;
|
|
|
|
int match_result = MR_MATCH;
|
2009-07-11 21:25:26 +04:00
|
|
|
|
|
|
|
DPRINTF(sc, ATH_DEBUG_DOTHFILTVBSE,
|
|
|
|
"%-17s matched %d missed %d mean_period %d noise %d variance %d\n",
|
|
|
|
pattern->name,
|
|
|
|
matched,
|
|
|
|
missed,
|
|
|
|
b_avg,
|
|
|
|
noise,
|
|
|
|
SUM_SQR/N);
|
2008-01-26 23:48:11 +03:00
|
|
|
|
|
|
|
/* check if PRF counters match a known radar, if we are
|
|
|
|
* confident enought */
|
|
|
|
if (MR_MATCH == (match_result = match_radar(
|
|
|
|
matched,
|
|
|
|
missed,
|
2009-07-11 21:25:26 +04:00
|
|
|
b_avg,
|
2008-01-26 23:48:11 +03:00
|
|
|
noise,
|
|
|
|
pattern->min_evts,
|
|
|
|
pattern->max_evts,
|
|
|
|
pattern->min_rep_int,
|
|
|
|
pattern->max_rep_int,
|
|
|
|
pattern->min_pulse,
|
|
|
|
pattern->max_missing))) {
|
|
|
|
compare_result = (NULL == best_pattern) ? CR_NULL :
|
|
|
|
compare_radar_matches(
|
|
|
|
matched,
|
|
|
|
missed,
|
2009-07-11 21:25:26 +04:00
|
|
|
b_avg,
|
2008-01-26 23:48:11 +03:00
|
|
|
noise,
|
|
|
|
pattern->min_evts,
|
|
|
|
pattern->max_evts,
|
|
|
|
pattern->min_rep_int,
|
|
|
|
pattern->max_rep_int,
|
|
|
|
pattern->min_pulse,
|
|
|
|
pattern->max_missing,
|
|
|
|
pattern->match_midpoint,
|
|
|
|
best_matched,
|
|
|
|
best_missed,
|
|
|
|
best_pri,
|
|
|
|
best_noise,
|
|
|
|
best_pattern->min_evts,
|
|
|
|
best_pattern->max_evts,
|
|
|
|
best_pattern->min_rep_int,
|
|
|
|
best_pattern->max_rep_int,
|
|
|
|
best_pattern->min_pulse,
|
|
|
|
best_pattern->max_missing,
|
|
|
|
best_pattern->match_midpoint);
|
|
|
|
}
|
|
|
|
if (DFLAG_ISSET(sc, ATH_DEBUG_DOTHFILT)) {
|
|
|
|
DPRINTF(sc, ATH_DEBUG_DOTHFILT,
|
2009-07-11 21:25:26 +04:00
|
|
|
"[%02d] %13s: %-17s [match=%2u {%2u"
|
2008-01-26 23:48:11 +03:00
|
|
|
"..%2u},missed=%2u/%2u,dur=%2d {%2u.."
|
|
|
|
"%2u},noise=%2u/%2u,cr:%d]\n",
|
|
|
|
last_pulse->rp_index,
|
|
|
|
compare_result > CR_FALLTHROUGH ?
|
|
|
|
"NEW-BEST" :
|
|
|
|
get_match_result_desc(match_result),
|
|
|
|
pattern->name,
|
|
|
|
matched,
|
|
|
|
pattern->min_pulse,
|
|
|
|
pattern->max_evts,
|
|
|
|
missed,
|
|
|
|
pattern->max_missing,
|
|
|
|
matched + missed,
|
|
|
|
pattern->min_evts,
|
|
|
|
pattern->max_evts,
|
|
|
|
noise,
|
|
|
|
matched + noise,
|
|
|
|
compare_result);
|
|
|
|
}
|
|
|
|
|
|
|
|
if (compare_result > CR_FALLTHROUGH) {
|
|
|
|
best_matched = matched;
|
|
|
|
best_missed = missed;
|
|
|
|
best_index = i;
|
|
|
|
best_pattern = pattern;
|
2009-07-11 21:25:26 +04:00
|
|
|
best_pri = b_avg;
|
2008-01-26 23:48:11 +03:00
|
|
|
best_noise = noise;
|
|
|
|
best_cr = compare_result;
|
|
|
|
}
|
|
|
|
else if (compare_result <= CR_FALLTHROUGH) {
|
|
|
|
DPRINTF(sc, ATH_DEBUG_DOTHFILTVBSE,
|
2009-07-11 21:25:26 +04:00
|
|
|
"%-17s match not better than best so "
|
2008-01-26 23:48:11 +03:00
|
|
|
"far. cr: %d matched: %d missed: "
|
|
|
|
"%d min_evts: %d\n",
|
|
|
|
pattern->name,
|
|
|
|
compare_result,
|
|
|
|
matched,
|
|
|
|
missed,
|
|
|
|
pattern->min_evts);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
if (-1 != best_index) {
|
|
|
|
DPRINTF(sc, ATH_DEBUG_DOTHFILTVBSE,
|
2009-07-11 21:25:26 +04:00
|
|
|
"[%02d] %10s: %-17s [match=%2u {%2u..%2u},missed="
|
2008-01-26 23:48:11 +03:00
|
|
|
"%2u/%2u,dur=%2d {%2u..%2u},noise=%2u/%2u,cr=%2d] "
|
|
|
|
"RI=%-9u RF=%-4u\n",
|
|
|
|
last_pulse->rp_index,
|
|
|
|
"BEST/PULSE",
|
|
|
|
best_pattern->name,
|
|
|
|
best_matched,
|
|
|
|
best_pattern->min_pulse,
|
|
|
|
best_pattern->max_evts,
|
|
|
|
best_missed,
|
|
|
|
best_pattern->max_missing,
|
|
|
|
(best_matched + best_missed),
|
|
|
|
best_pattern->min_evts,
|
|
|
|
best_pattern->max_evts,
|
|
|
|
best_noise,
|
|
|
|
(best_matched + best_noise),
|
|
|
|
best_cr,
|
|
|
|
best_pri,
|
|
|
|
interval_to_frequency(best_pri));
|
|
|
|
if (index)
|
|
|
|
*index = best_index;
|
|
|
|
if (pri)
|
|
|
|
*pri = best_pri;
|
|
|
|
if (matching_pulses)
|
|
|
|
*matching_pulses = best_matched;
|
|
|
|
if (noise_pulses)
|
|
|
|
*noise_pulses = best_noise;
|
|
|
|
if (missed_pulses)
|
|
|
|
*missed_pulses = best_missed;
|
|
|
|
}
|
|
|
|
|
|
|
|
return (-1 != best_index) ? AH_TRUE : AH_FALSE;
|
|
|
|
}
|
|
|
|
|
2008-04-11 03:48:41 +04:00
|
|
|
#ifdef AR_DEBUG
|
2008-01-26 23:48:11 +03:00
|
|
|
static u_int32_t interval_to_frequency(u_int32_t interval)
|
|
|
|
{
|
|
|
|
/* Calculate BRI from PRI */
|
|
|
|
u_int32_t frequency = interval ? (1000000 / interval) : 0;
|
|
|
|
/* Round to nearest multiple of 50 */
|
|
|
|
return frequency + ((frequency % 50) >= 25 ? 50 : 0) - (frequency % 50);
|
|
|
|
}
|
2008-04-11 03:48:41 +04:00
|
|
|
#endif /* AR_DEBUG */
|
2008-01-26 23:48:11 +03:00
|
|
|
|
|
|
|
#ifdef ATH_RADAR_LONG_PULSE
|
2008-07-17 11:29:42 +04:00
|
|
|
static const char *get_longpulse_desc(int lp)
|
|
|
|
{
|
2008-01-26 23:48:11 +03:00
|
|
|
switch (lp) {
|
|
|
|
case 8: return "FCC [5, 8 pulses]";
|
|
|
|
case 9: return "FCC [5, 9 pulses]";
|
|
|
|
case 10: return "FCC [5, 10 pulses]";
|
|
|
|
case 11: return "FCC [5, 11 pulses]";
|
|
|
|
case 12: return "FCC [5, 12 pulses]";
|
|
|
|
case 13: return "FCC [5, 13 pulses]";
|
|
|
|
case 14: return "FCC [5, 14 pulses]";
|
|
|
|
case 15: return "FCC [5, 15 pulses]";
|
|
|
|
case 16: return "FCC [5, 16 pulses]";
|
|
|
|
case 17: return "FCC [5, 17 pulses]";
|
|
|
|
case 18: return "FCC [5, 18 pulses]";
|
|
|
|
case 19: return "FCC [5, 19 pulses]";
|
|
|
|
case 20: return "FCC [5, 20 pulses]";
|
|
|
|
default: return "FCC [5, invalid pulses]";
|
|
|
|
}
|
|
|
|
}
|
|
|
|
#endif /* #ifdef ATH_RADAR_LONG_PULSE */
|
|
|
|
|
2008-07-17 06:26:04 +04:00
|
|
|
static HAL_BOOL rp_analyze(struct ath_softc *sc)
|
2008-01-26 23:48:11 +03:00
|
|
|
{
|
2009-07-11 21:20:58 +04:00
|
|
|
struct ieee80211com *ic = &sc->sc_ic;
|
2008-01-26 23:48:11 +03:00
|
|
|
HAL_BOOL radar = 0;
|
|
|
|
struct ath_rp *pulse;
|
|
|
|
|
|
|
|
/* Best short pulse match */
|
|
|
|
int32_t best_index = -1;
|
|
|
|
u_int32_t best_pri = 0;
|
|
|
|
u_int32_t best_matched = 0;
|
|
|
|
u_int32_t best_missed = 0;
|
|
|
|
u_int32_t best_noise = 0;
|
|
|
|
int32_t best_cr = 0;
|
|
|
|
|
|
|
|
#ifdef ATH_RADAR_LONG_PULSE
|
|
|
|
/* Best long pulse match */
|
|
|
|
u_int32_t best_lp_bc = 0;
|
|
|
|
u_int32_t best_lp_matched = 0;
|
|
|
|
u_int32_t best_lp_missed = 0;
|
|
|
|
u_int32_t best_lp_noise = 0;
|
|
|
|
u_int32_t best_lp_pulses = 0;
|
|
|
|
#endif /* #ifdef ATH_RADAR_LONG_PULSE */
|
|
|
|
u_int32_t pass = 0;
|
|
|
|
struct radar_pattern_specification *best_pattern = NULL;
|
|
|
|
|
|
|
|
/* start the analysis by the last pulse since it might speed up
|
|
|
|
* things and then move backward for all non-analyzed pulses.
|
|
|
|
* For debugging ONLY - we continue to run this scan after radar is
|
|
|
|
* detected, processing all pulses... even when they come in after an
|
|
|
|
* iteration of all pulses that were present when this function was
|
|
|
|
* invoked. This can happen at some radar waveforms where we will
|
|
|
|
* match the first few pulses and then the rest of the burst will come
|
|
|
|
* in, but never be analyzed.
|
|
|
|
*/
|
|
|
|
|
|
|
|
while (pulse_tail(sc)->rp_allocated &&
|
|
|
|
!pulse_tail(sc)->rp_analyzed &&
|
|
|
|
(AH_FALSE == radar ||
|
|
|
|
(DFLAG_ISSET(sc, ATH_DEBUG_DOTHFILT) && ++pass <= 3))) {
|
|
|
|
|
|
|
|
list_for_each_entry_reverse(pulse, &sc->sc_rp_list, list) {
|
|
|
|
if (!pulse->rp_allocated)
|
|
|
|
break;
|
|
|
|
if (pulse->rp_analyzed)
|
|
|
|
break;
|
|
|
|
|
|
|
|
/* Skip pulse analysis after we have confirmed radar
|
|
|
|
* presence unless we are debugging and have
|
|
|
|
* disabled short-circuit logic. In this case,
|
|
|
|
* we'll go through ALL the signatures and find
|
|
|
|
* the best match to convince ourselves this code works.
|
|
|
|
*/
|
|
|
|
if (AH_FALSE == radar ||
|
|
|
|
DFLAG_ISSET(sc, ATH_DEBUG_DOTHFILTNOSC)) {
|
|
|
|
/* short pulse match status */
|
|
|
|
u_int32_t index = 0;
|
|
|
|
u_int32_t pri = 0;
|
|
|
|
u_int32_t matched = 0;
|
|
|
|
u_int32_t missed = 0;
|
|
|
|
u_int32_t noise = 0;
|
|
|
|
#ifdef ATH_RADAR_LONG_PULSE
|
|
|
|
|
|
|
|
/* long pulse match status */
|
|
|
|
u_int32_t lp_bc = 0;
|
|
|
|
u_int32_t lp_matched = 0;
|
|
|
|
u_int32_t lp_missed = 0;
|
|
|
|
u_int32_t lp_noise = 0;
|
|
|
|
u_int32_t lp_pulses = 0;
|
|
|
|
#endif /* #ifdef ATH_RADAR_LONG_PULSE */
|
2008-07-17 06:26:04 +04:00
|
|
|
if (rp_analyze_short_pulse(sc, pulse, &index,
|
2008-01-26 23:48:11 +03:00
|
|
|
&pri, &matched, &missed,
|
|
|
|
&noise)) {
|
|
|
|
int compare_result = (!radar || best_index == -1) ?
|
|
|
|
CR_NULL :
|
|
|
|
compare_radar_matches(
|
|
|
|
matched,
|
|
|
|
missed,
|
|
|
|
pri,
|
|
|
|
noise,
|
|
|
|
radar_patterns[index].min_evts,
|
|
|
|
radar_patterns[index].max_evts,
|
|
|
|
radar_patterns[index].min_rep_int,
|
|
|
|
radar_patterns[index].max_rep_int,
|
|
|
|
radar_patterns[index].min_pulse,
|
|
|
|
radar_patterns[index].max_missing,
|
|
|
|
radar_patterns[index].match_midpoint,
|
|
|
|
best_matched,
|
|
|
|
best_missed,
|
|
|
|
best_pri,
|
|
|
|
best_noise,
|
|
|
|
radar_patterns[best_index].min_evts,
|
|
|
|
radar_patterns[best_index].max_evts,
|
|
|
|
radar_patterns[best_index].min_rep_int,
|
|
|
|
radar_patterns[best_index].max_rep_int,
|
|
|
|
radar_patterns[best_index].min_pulse,
|
|
|
|
radar_patterns[best_index].max_missing,
|
|
|
|
radar_patterns[best_index].match_midpoint
|
|
|
|
);
|
|
|
|
if (compare_result > CR_FALLTHROUGH) {
|
|
|
|
/* Update best match */
|
|
|
|
best_matched = matched;
|
|
|
|
best_missed = missed;
|
|
|
|
best_index = index;
|
|
|
|
best_pri = pri;
|
|
|
|
best_noise = noise;
|
|
|
|
radar = AH_TRUE;
|
|
|
|
best_cr = compare_result;
|
|
|
|
}
|
|
|
|
DPRINTF(sc, ATH_DEBUG_DOTHFILT,
|
2009-07-11 21:25:26 +04:00
|
|
|
"%10s: %-17s [match=%2u "
|
2008-01-26 23:48:11 +03:00
|
|
|
"{%2u..%2u}, missed=%2u/%2u, "
|
|
|
|
"dur=%2d {%2u..%2u}, "
|
|
|
|
"noise=%2u/%2u, cr=%2d] "
|
|
|
|
"RI=%-9u RF=%-4u\n",
|
|
|
|
(compare_result > CR_FALLTHROUGH) ?
|
|
|
|
"BETTER" : "WORSE",
|
|
|
|
radar_patterns[index].name,
|
|
|
|
matched,
|
|
|
|
radar_patterns[index].min_pulse,
|
|
|
|
radar_patterns[index].max_evts,
|
|
|
|
missed,
|
|
|
|
radar_patterns[index].max_missing,
|
|
|
|
(matched + missed),
|
|
|
|
radar_patterns[index].min_evts,
|
|
|
|
radar_patterns[index].max_evts,
|
|
|
|
noise,
|
|
|
|
(matched + noise),
|
|
|
|
compare_result,
|
|
|
|
pri,
|
|
|
|
interval_to_frequency(pri));
|
|
|
|
}
|
|
|
|
#ifdef ATH_RADAR_LONG_PULSE
|
|
|
|
if (rp_analyze_long_pulse(sc, pulse,
|
|
|
|
&lp_bc,
|
|
|
|
&lp_matched,
|
|
|
|
&lp_missed,
|
|
|
|
&lp_noise,
|
|
|
|
&lp_pulses)) {
|
|
|
|
/* XXX: Do we care about best match?? */
|
|
|
|
radar = AH_TRUE;
|
|
|
|
best_lp_bc = lp_bc;
|
|
|
|
best_lp_matched = lp_matched;
|
|
|
|
best_lp_missed = lp_missed;
|
|
|
|
best_lp_noise = lp_noise;
|
|
|
|
best_lp_pulses = lp_pulses;
|
|
|
|
}
|
|
|
|
#endif /* #ifdef ATH_RADAR_LONG_PULSE */
|
|
|
|
}
|
|
|
|
pulse->rp_analyzed = 1;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
if (AH_TRUE == radar) {
|
|
|
|
#ifdef ATH_RADAR_LONG_PULSE
|
|
|
|
if (!best_lp_bc) {
|
|
|
|
#endif /* #ifdef ATH_RADAR_LONG_PULSE */
|
|
|
|
best_pattern =
|
|
|
|
&radar_patterns[best_index];
|
|
|
|
DPRINTF(sc, ATH_DEBUG_DOTHFILT,
|
2009-07-11 21:25:26 +04:00
|
|
|
"%10s: %-17s [match=%2u {%2u..%2u},missed="
|
2008-01-26 23:48:11 +03:00
|
|
|
"%2u/%2u,dur=%2d {%2u..%2u},noise=%2u/%2u,cr=%2d] "
|
|
|
|
"RI=%-9u RF=%-4u\n",
|
|
|
|
"BEST MATCH",
|
|
|
|
best_pattern->name,
|
|
|
|
best_matched,
|
|
|
|
best_pattern->min_pulse,
|
|
|
|
best_pattern->max_evts,
|
|
|
|
best_missed,
|
|
|
|
best_pattern->max_missing,
|
|
|
|
(best_matched + best_missed),
|
|
|
|
best_pattern->min_evts,
|
|
|
|
best_pattern->max_evts,
|
|
|
|
best_noise,
|
|
|
|
(best_matched + best_noise),
|
|
|
|
best_cr,
|
|
|
|
best_pri,
|
|
|
|
interval_to_frequency(best_pri));
|
|
|
|
#ifdef ATH_RADAR_LONG_PULSE
|
|
|
|
}
|
|
|
|
else {
|
|
|
|
DPRINTF(sc, ATH_DEBUG_DOTHFILT,
|
2009-07-11 21:25:26 +04:00
|
|
|
"%10s: %-17s [match=%2u {%2u..%2u},missed="
|
2008-01-26 23:48:11 +03:00
|
|
|
"%2u/%2u,noise=%2u/%2u]\n",
|
|
|
|
"BEST MATCH",
|
|
|
|
get_longpulse_desc(best_lp_bc),
|
|
|
|
best_lp_bc,
|
|
|
|
(best_lp_bc-4),
|
|
|
|
best_lp_bc,
|
|
|
|
best_lp_missed,
|
|
|
|
(best_lp_bc-(best_lp_bc-4)),
|
|
|
|
best_lp_noise,
|
|
|
|
(best_lp_pulses + best_lp_noise)
|
|
|
|
);
|
|
|
|
}
|
|
|
|
#endif /* #ifdef ATH_RADAR_LONG_PULSE */
|
2009-07-11 21:25:26 +04:00
|
|
|
if (DFLAG_ISSET(sc, ATH_DEBUG_DOTHPULSES)) {
|
|
|
|
DPRINTF(sc, ATH_DEBUG_DOTHPULSES,
|
|
|
|
"========================================\n");
|
|
|
|
DPRINTF(sc, ATH_DEBUG_DOTHPULSES,
|
|
|
|
"==BEGIN RADAR SAMPLE====================\n");
|
|
|
|
DPRINTF(sc, ATH_DEBUG_DOTHPULSES,
|
|
|
|
"========================================\n");
|
2008-01-26 23:48:11 +03:00
|
|
|
|
|
|
|
#ifdef ATH_RADAR_LONG_PULSE
|
|
|
|
if (!best_lp_bc) {
|
|
|
|
#endif /* #ifdef ATH_RADAR_LONG_PULSE */
|
|
|
|
best_pattern =
|
|
|
|
&radar_patterns[best_index];
|
|
|
|
DPRINTF(sc, ATH_DEBUG_DOTHPULSES,
|
2009-07-11 21:25:26 +04:00
|
|
|
"Sample contains data matching %-17s "
|
2008-01-26 23:48:11 +03:00
|
|
|
"[match=%2u {%2u..%2u}, "
|
|
|
|
"missed=%2u/%2u, dur=%2d {%2u..%2u}, "
|
|
|
|
"noise=%2u/%2u,cr=%d] RI=%-9u RF=%-4u\n",
|
|
|
|
best_pattern->name,
|
|
|
|
best_matched,
|
|
|
|
best_pattern->min_pulse,
|
|
|
|
best_pattern->max_evts,
|
|
|
|
best_missed,
|
|
|
|
best_pattern->max_missing,
|
|
|
|
best_matched + best_missed,
|
|
|
|
best_pattern->min_evts,
|
|
|
|
best_pattern->max_evts,
|
|
|
|
best_noise,
|
|
|
|
best_noise + best_matched,
|
|
|
|
best_cr,
|
|
|
|
best_pri,
|
|
|
|
interval_to_frequency(best_pri));
|
|
|
|
#ifdef ATH_RADAR_LONG_PULSE
|
|
|
|
} else {
|
|
|
|
DPRINTF(sc, ATH_DEBUG_DOTHPULSES,
|
2009-07-11 21:20:58 +04:00
|
|
|
"Sample contains data matching %s\n",
|
2008-01-26 23:48:11 +03:00
|
|
|
get_longpulse_desc(best_lp_bc));
|
|
|
|
}
|
|
|
|
#endif /* #ifdef ATH_RADAR_LONG_PULSE */
|
|
|
|
|
|
|
|
ath_rp_print(sc, 0 /* analyzed pulses only */ );
|
2009-07-11 21:20:58 +04:00
|
|
|
DPRINTF(sc, ATH_DEBUG_DOTHPULSES,
|
|
|
|
"========================================\n");
|
|
|
|
DPRINTF(sc, ATH_DEBUG_DOTHPULSES,
|
|
|
|
"==END RADAR SAMPLE======================\n");
|
|
|
|
DPRINTF(sc, ATH_DEBUG_DOTHPULSES,
|
|
|
|
"========================================\n");
|
2008-01-26 23:48:11 +03:00
|
|
|
}
|
|
|
|
#ifdef ATH_RADAR_LONG_PULSE
|
|
|
|
if (!best_lp_bc)
|
|
|
|
#endif /* #ifdef ATH_RADAR_LONG_PULSE */
|
2009-07-11 21:20:58 +04:00
|
|
|
ic->ic_radar_detected(ic,
|
|
|
|
radar_patterns[best_index].name,
|
|
|
|
0, 0);
|
2008-01-26 23:48:11 +03:00
|
|
|
#ifdef ATH_RADAR_LONG_PULSE
|
|
|
|
else
|
2009-07-11 21:20:58 +04:00
|
|
|
ic->ic_radar_detected(ic,
|
|
|
|
get_longpulse_desc(best_lp_bc),
|
|
|
|
0, 0);
|
2008-01-26 23:48:11 +03:00
|
|
|
#endif /* #ifdef ATH_RADAR_LONG_PULSE */
|
|
|
|
}
|
|
|
|
return radar;
|
|
|
|
}
|
|
|
|
|
|
|
|
/* initialize ath_softc members so sensible values */
|
|
|
|
static void ath_rp_clear(struct ath_softc *sc)
|
|
|
|
{
|
|
|
|
sc->sc_rp = NULL;
|
|
|
|
INIT_LIST_HEAD(&sc->sc_rp_list);
|
|
|
|
sc->sc_rp_num = 0;
|
2008-07-17 06:26:04 +04:00
|
|
|
sc->sc_rp_analyze = NULL;
|
2008-01-26 23:48:11 +03:00
|
|
|
}
|
|
|
|
|
|
|
|
static void ath_rp_tasklet(TQUEUE_ARG data)
|
|
|
|
{
|
2008-06-07 00:32:29 +04:00
|
|
|
struct net_device *dev = (struct net_device *)data;
|
2009-01-14 05:36:53 +03:00
|
|
|
struct ath_softc *sc = netdev_priv(dev);
|
2008-01-26 23:48:11 +03:00
|
|
|
|
2008-07-17 06:26:04 +04:00
|
|
|
if (sc->sc_rp_analyze != NULL)
|
|
|
|
sc->sc_rp_analyze(sc);
|
2008-01-26 23:48:11 +03:00
|
|
|
}
|
|
|
|
|
|
|
|
void ath_rp_init(struct ath_softc *sc)
|
|
|
|
{
|
|
|
|
struct net_device *dev = sc->sc_dev;
|
|
|
|
int i;
|
|
|
|
|
|
|
|
ath_rp_clear(sc);
|
|
|
|
|
2011-08-03 04:18:57 +04:00
|
|
|
sc->sc_rp = kzalloc(sizeof(struct ath_rp) * ATH_RADAR_PULSE_NR,
|
|
|
|
GFP_KERNEL);
|
2008-01-26 23:48:11 +03:00
|
|
|
|
|
|
|
if (sc->sc_rp == NULL)
|
|
|
|
return;
|
|
|
|
|
|
|
|
/* initialize the circular list */
|
|
|
|
INIT_LIST_HEAD(&sc->sc_rp_list);
|
|
|
|
for (i = 0; i < ATH_RADAR_PULSE_NR; i++) {
|
|
|
|
sc->sc_rp[i].rp_index = i;
|
|
|
|
list_add_tail(&sc->sc_rp[i].list,
|
|
|
|
&sc->sc_rp_list);
|
|
|
|
}
|
|
|
|
|
|
|
|
sc->sc_rp_num = 0;
|
2008-07-17 06:26:04 +04:00
|
|
|
sc->sc_rp_analyze = rp_analyze;
|
2008-01-26 23:48:11 +03:00
|
|
|
|
|
|
|
/* compute sc_rp_min */
|
|
|
|
sc->sc_rp_min = 2;
|
|
|
|
for (i = 0; i < sizetab(radar_patterns); i++)
|
|
|
|
sc->sc_rp_min =
|
|
|
|
MIN(sc->sc_rp_min,
|
|
|
|
radar_patterns[i].min_pulse);
|
|
|
|
|
|
|
|
/* default values is properly handle pulses and detected radars */
|
|
|
|
sc->sc_rp_ignored = 0;
|
|
|
|
sc->sc_radar_ignored = 0;
|
|
|
|
|
|
|
|
ATH_INIT_TQUEUE(&sc->sc_rp_tq, ath_rp_tasklet, dev);
|
|
|
|
}
|
|
|
|
|
|
|
|
void ath_rp_done(struct ath_softc *sc)
|
|
|
|
{
|
|
|
|
/* free what we allocated in ath_rp_init() */
|
|
|
|
kfree(sc->sc_rp);
|
|
|
|
|
|
|
|
ath_rp_clear(sc);
|
|
|
|
}
|
|
|
|
|
|
|
|
void ath_rp_record(struct ath_softc *sc, u_int64_t tsf, u_int8_t rssi,
|
|
|
|
u_int8_t width, HAL_BOOL is_simulated)
|
|
|
|
{
|
|
|
|
struct ath_rp *pulse;
|
|
|
|
|
2009-07-11 21:25:26 +04:00
|
|
|
DPRINTF(sc, ATH_DEBUG_DOTHPULSES,
|
2008-01-26 23:48:11 +03:00
|
|
|
"tsf=%10llu rssi=%3u width=%3u%s\n",
|
2009-07-11 21:25:26 +04:00
|
|
|
tsf, rssi, width,
|
2008-01-26 23:48:11 +03:00
|
|
|
sc->sc_rp_ignored ? " (ignored)" : "");
|
|
|
|
|
|
|
|
if (sc->sc_rp_ignored) {
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
2009-07-11 21:25:26 +04:00
|
|
|
#if 0
|
2008-01-26 23:48:11 +03:00
|
|
|
/* pulses width 255 seems to trigger false detection of radar. we
|
|
|
|
* ignored it then. */
|
|
|
|
|
|
|
|
if (width == 255) {
|
|
|
|
/* ignored */
|
|
|
|
return ;
|
|
|
|
}
|
2009-07-11 21:25:26 +04:00
|
|
|
#endif
|
2008-01-26 23:48:11 +03:00
|
|
|
|
|
|
|
/* check if the new radar pulse is after the last one recorded, or
|
|
|
|
* else, we flush the history */
|
|
|
|
pulse = pulse_tail(sc);
|
|
|
|
if (tsf < pulse->rp_tsf) {
|
|
|
|
if (is_simulated == AH_TRUE && 0 == tsf) {
|
|
|
|
DPRINTF(sc, ATH_DEBUG_DOTHFILTVBSE,
|
|
|
|
"%s: %s: ath_rp_flush: simulated tsf "
|
|
|
|
"reset. tsf =%10llu, rptsf =%10llu\n",
|
2009-05-24 05:09:25 +04:00
|
|
|
SC_DEV_NAME(sc), __func__,
|
|
|
|
(unsigned long long)tsf,
|
|
|
|
(unsigned long long)pulse->rp_tsf);
|
2008-01-26 23:48:11 +03:00
|
|
|
ath_rp_flush(sc);
|
|
|
|
} else if ((pulse->rp_tsf - tsf) > (1 << 15)) {
|
|
|
|
DPRINTF(sc, ATH_DEBUG_DOTHFILTVBSE,
|
|
|
|
"%s: %s: ath_rp_flush: tsf reset. "
|
|
|
|
"(rp_tsf - tsf > 0x8000) tsf=%10llu, rptsf="
|
|
|
|
"%10llu\n",
|
2009-05-24 05:09:25 +04:00
|
|
|
SC_DEV_NAME(sc), __func__,
|
|
|
|
(unsigned long long)tsf,
|
|
|
|
(unsigned long long)pulse->rp_tsf);
|
2008-01-26 23:48:11 +03:00
|
|
|
ath_rp_flush(sc);
|
|
|
|
} else {
|
|
|
|
DPRINTF(sc, ATH_DEBUG_DOTHFILT,
|
|
|
|
"%s: %s: tsf jitter/bug detected: tsf =%10llu, "
|
|
|
|
"rptsf =%10llu, rp_tsf - tsf = %10llu\n",
|
2009-05-24 05:09:25 +04:00
|
|
|
SC_DEV_NAME(sc), __func__,
|
|
|
|
(unsigned long long)tsf,
|
|
|
|
(unsigned long long)pulse->rp_tsf,
|
|
|
|
(unsigned long long)(pulse->rp_tsf - tsf));
|
2008-01-26 23:48:11 +03:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
/* remove the head of the list */
|
|
|
|
pulse = pulse_head(sc);
|
|
|
|
list_del(&pulse->list);
|
|
|
|
|
|
|
|
pulse->rp_tsf = tsf;
|
|
|
|
pulse->rp_rssi = rssi;
|
|
|
|
pulse->rp_width = width;
|
|
|
|
pulse->rp_allocated = 1;
|
|
|
|
pulse->rp_analyzed = 0;
|
|
|
|
|
|
|
|
/* add at the tail of the list */
|
|
|
|
list_add_tail(&pulse->list, &sc->sc_rp_list);
|
|
|
|
if (ATH_RADAR_PULSE_NR > sc->sc_rp_num)
|
|
|
|
sc->sc_rp_num++;
|
|
|
|
}
|
|
|
|
|
|
|
|
void ath_rp_print_mem(struct ath_softc *sc, int analyzed_pulses_only)
|
|
|
|
{
|
|
|
|
struct ath_rp *pulse;
|
|
|
|
u_int64_t oldest_tsf = ~0;
|
|
|
|
int i;
|
|
|
|
IPRINTF(sc, "Pulse dump of %spulses using sc_rp containing "
|
|
|
|
"%d allocated pulses.\n",
|
|
|
|
analyzed_pulses_only ? "analyzed " : "", sc->sc_rp_num);
|
|
|
|
|
|
|
|
/* Find oldest TSF value so we can print relative times */
|
|
|
|
for (i = 0; i < ATH_RADAR_PULSE_NR; i++) {
|
|
|
|
pulse = &sc->sc_rp[i];
|
|
|
|
if (pulse->rp_allocated && pulse->rp_tsf < oldest_tsf)
|
|
|
|
oldest_tsf = pulse->rp_tsf;
|
|
|
|
}
|
|
|
|
|
|
|
|
for (i = 0; i < ATH_RADAR_PULSE_NR; i++) {
|
|
|
|
pulse = &sc->sc_rp[i];
|
|
|
|
if (!pulse->rp_allocated)
|
|
|
|
break;
|
|
|
|
if ((!analyzed_pulses_only) || pulse->rp_analyzed)
|
|
|
|
IPRINTF(sc, "Pulse [%3d, %p] : relative_tsf=%10llu "
|
|
|
|
"tsf=%10llu rssi=%3u width=%3u allocated=%d "
|
|
|
|
"analyzed=%d next=%p prev=%p\n",
|
|
|
|
pulse->rp_index,
|
|
|
|
pulse,
|
2009-05-24 05:09:25 +04:00
|
|
|
(unsigned long long)(pulse->rp_tsf - oldest_tsf),
|
|
|
|
(unsigned long long)pulse->rp_tsf,
|
2008-01-26 23:48:11 +03:00
|
|
|
pulse->rp_rssi,
|
|
|
|
pulse->rp_width,
|
|
|
|
pulse->rp_allocated,
|
|
|
|
pulse->rp_analyzed,
|
|
|
|
pulse->list.next,
|
|
|
|
pulse->list.prev);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
void ath_rp_print(struct ath_softc *sc, int analyzed_pulses_only)
|
|
|
|
{
|
|
|
|
struct ath_rp *pulse;
|
|
|
|
|
2009-07-11 21:25:26 +04:00
|
|
|
DPRINTF(sc, ATH_DEBUG_DOTHPULSES,
|
|
|
|
"Pulse dump of %spulses from ring buffer containing %d "
|
|
|
|
"pulses.\n",
|
|
|
|
analyzed_pulses_only ? "analyzed " : "",
|
|
|
|
sc->sc_rp_num);
|
2008-01-26 23:48:11 +03:00
|
|
|
|
|
|
|
list_for_each_entry_reverse(pulse, &sc->sc_rp_list, list) {
|
|
|
|
if (!pulse->rp_allocated)
|
|
|
|
continue;
|
2009-07-11 21:25:26 +04:00
|
|
|
if ((!analyzed_pulses_only) || pulse->rp_analyzed) {
|
|
|
|
DPRINTF(sc, ATH_DEBUG_DOTHPULSES,
|
|
|
|
"tsf=%10llu rssi=%3u width=%3u\n",
|
|
|
|
pulse->rp_tsf, pulse->rp_rssi, pulse->rp_width);
|
|
|
|
}
|
2008-01-26 23:48:11 +03:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
void ath_rp_flush(struct ath_softc *sc)
|
|
|
|
{
|
|
|
|
struct ath_rp *pulse;
|
|
|
|
list_for_each_entry_reverse(pulse, &sc->sc_rp_list, list)
|
|
|
|
pulse->rp_allocated = 0;
|
|
|
|
sc->sc_rp_num = 0;
|
|
|
|
}
|