diff options
Diffstat (limited to 'package/kernel/mac80211/patches/304-ath9k-DFS-add-pulse-chirp-detection-for-FCC.patch')
-rw-r--r-- | package/kernel/mac80211/patches/304-ath9k-DFS-add-pulse-chirp-detection-for-FCC.patch | 211 |
1 files changed, 211 insertions, 0 deletions
diff --git a/package/kernel/mac80211/patches/304-ath9k-DFS-add-pulse-chirp-detection-for-FCC.patch b/package/kernel/mac80211/patches/304-ath9k-DFS-add-pulse-chirp-detection-for-FCC.patch new file mode 100644 index 0000000..3437f13 --- /dev/null +++ b/package/kernel/mac80211/patches/304-ath9k-DFS-add-pulse-chirp-detection-for-FCC.patch @@ -0,0 +1,211 @@ +From: Zefir Kurtisi <zefir.kurtisi@neratec.com> +Date: Tue, 16 Jun 2015 12:52:16 +0200 +Subject: [PATCH] ath9k: DFS - add pulse chirp detection for FCC + +FCC long pulse radar (type 5) requires pulses to be +checked for chirping. This patch implements chirp +detection based on the FFT data provided for long +pulses. + +A chirp is detected when a set of criteria defined +by FCC pulse characteristics is met, including +* have at least 4 FFT samples +* max_bin index moves equidistantly between samples +* the gradient is within defined range + +The chirp detection has been tested with reference +radar generating devices and proved to work reliably. + +Signed-off-by: Zefir Kurtisi <zefir.kurtisi@neratec.com> +--- + +--- a/drivers/net/wireless/ath/ath9k/dfs.c ++++ b/drivers/net/wireless/ath/ath9k/dfs.c +@@ -30,6 +30,157 @@ struct ath_radar_data { + u8 pulse_length_pri; + }; + ++/**** begin: CHIRP ************************************************************/ ++ ++/* min and max gradients for defined FCC chirping pulses, given by ++ * - 20MHz chirp width over a pulse width of 50us ++ * - 5MHz chirp width over a pulse width of 100us ++ */ ++static const int BIN_DELTA_MIN = 1; ++static const int BIN_DELTA_MAX = 10; ++ ++/* we need at least 3 deltas / 4 samples for a reliable chirp detection */ ++#define NUM_DIFFS 3 ++static const int FFT_NUM_SAMPLES = (NUM_DIFFS + 1); ++ ++/* Threshold for difference of delta peaks */ ++static const int MAX_DIFF = 2; ++ ++/* width range to be checked for chirping */ ++static const int MIN_CHIRP_PULSE_WIDTH = 20; ++static const int MAX_CHIRP_PULSE_WIDTH = 110; ++ ++struct ath9k_dfs_fft_20 { ++ u8 bin[28]; ++ u8 lower_bins[3]; ++} __packed; ++struct ath9k_dfs_fft_40 { ++ u8 bin[64]; ++ u8 lower_bins[3]; ++ u8 upper_bins[3]; ++} __packed; ++ ++static inline int fft_max_index(u8 *bins) ++{ ++ return (bins[2] & 0xfc) >> 2; ++} ++static inline int fft_max_magnitude(u8 *bins) ++{ ++ return (bins[0] & 0xc0) >> 6 | bins[1] << 2 | (bins[2] & 0x03) << 10; ++} ++static inline u8 fft_bitmap_weight(u8 *bins) ++{ ++ return bins[0] & 0x3f; ++} ++ ++static int ath9k_get_max_index_ht40(struct ath9k_dfs_fft_40 *fft, ++ bool is_ctl, bool is_ext) ++{ ++ const int DFS_UPPER_BIN_OFFSET = 64; ++ /* if detected radar on both channels, select the significant one */ ++ if (is_ctl && is_ext) { ++ /* first check wether channels have 'strong' bins */ ++ is_ctl = fft_bitmap_weight(fft->lower_bins) != 0; ++ is_ext = fft_bitmap_weight(fft->upper_bins) != 0; ++ ++ /* if still unclear, take higher magnitude */ ++ if (is_ctl && is_ext) { ++ int mag_lower = fft_max_magnitude(fft->lower_bins); ++ int mag_upper = fft_max_magnitude(fft->upper_bins); ++ if (mag_upper > mag_lower) ++ is_ctl = false; ++ else ++ is_ext = false; ++ } ++ } ++ if (is_ctl) ++ return fft_max_index(fft->lower_bins); ++ return fft_max_index(fft->upper_bins) + DFS_UPPER_BIN_OFFSET; ++} ++static bool ath9k_check_chirping(struct ath_softc *sc, u8 *data, ++ int datalen, bool is_ctl, bool is_ext) ++{ ++ int i; ++ int max_bin[FFT_NUM_SAMPLES]; ++ struct ath_hw *ah = sc->sc_ah; ++ struct ath_common *common = ath9k_hw_common(ah); ++ int prev_delta; ++ ++ if (IS_CHAN_HT40(ah->curchan)) { ++ struct ath9k_dfs_fft_40 *fft = (struct ath9k_dfs_fft_40 *) data; ++ int num_fft_packets = datalen / sizeof(*fft); ++ if (num_fft_packets == 0) ++ return false; ++ ++ ath_dbg(common, DFS, "HT40: datalen=%d, num_fft_packets=%d\n", ++ datalen, num_fft_packets); ++ if (num_fft_packets < (FFT_NUM_SAMPLES)) { ++ ath_dbg(common, DFS, "not enough packets for chirp\n"); ++ return false; ++ } ++ /* HW sometimes adds 2 garbage bytes in front of FFT samples */ ++ if ((datalen % sizeof(*fft)) == 2) { ++ fft = (struct ath9k_dfs_fft_40 *) (data + 2); ++ ath_dbg(common, DFS, "fixing datalen by 2\n"); ++ } ++ if (IS_CHAN_HT40MINUS(ah->curchan)) { ++ int temp = is_ctl; ++ is_ctl = is_ext; ++ is_ext = temp; ++ } ++ for (i = 0; i < FFT_NUM_SAMPLES; i++) ++ max_bin[i] = ath9k_get_max_index_ht40(fft + i, is_ctl, ++ is_ext); ++ } else { ++ struct ath9k_dfs_fft_20 *fft = (struct ath9k_dfs_fft_20 *) data; ++ int num_fft_packets = datalen / sizeof(*fft); ++ if (num_fft_packets == 0) ++ return false; ++ ath_dbg(common, DFS, "HT20: datalen=%d, num_fft_packets=%d\n", ++ datalen, num_fft_packets); ++ if (num_fft_packets < (FFT_NUM_SAMPLES)) { ++ ath_dbg(common, DFS, "not enough packets for chirp\n"); ++ return false; ++ } ++ /* in ht20, this is a 6-bit signed number => shift it to 0 */ ++ for (i = 0; i < FFT_NUM_SAMPLES; i++) ++ max_bin[i] = fft_max_index(fft[i].lower_bins) ^ 0x20; ++ } ++ ath_dbg(common, DFS, "bin_max = [%d, %d, %d, %d]\n", ++ max_bin[0], max_bin[1], max_bin[2], max_bin[3]); ++ ++ /* Check for chirp attributes within specs ++ * a) delta of adjacent max_bins is within range ++ * b) delta of adjacent deltas are within tolerance ++ */ ++ prev_delta = 0; ++ for (i = 0; i < NUM_DIFFS; i++) { ++ int ddelta = -1; ++ int delta = max_bin[i + 1] - max_bin[i]; ++ ++ /* ensure gradient is within valid range */ ++ if (abs(delta) < BIN_DELTA_MIN || abs(delta) > BIN_DELTA_MAX) { ++ ath_dbg(common, DFS, "CHIRP: invalid delta %d " ++ "in sample %d\n", delta, i); ++ return false; ++ } ++ if (i == 0) ++ goto done; ++ ddelta = delta - prev_delta; ++ if (abs(ddelta) > MAX_DIFF) { ++ ath_dbg(common, DFS, "CHIRP: ddelta %d too high\n", ++ ddelta); ++ return false; ++ } ++done: ++ ath_dbg(common, DFS, "CHIRP - %d: delta=%d, ddelta=%d\n", ++ i, delta, ddelta); ++ prev_delta = delta; ++ } ++ return true; ++} ++/**** end: CHIRP **************************************************************/ ++ + /* convert pulse duration to usecs, considering clock mode */ + static u32 dur_to_usecs(struct ath_hw *ah, u32 dur) + { +@@ -113,12 +264,6 @@ ath9k_postprocess_radar_event(struct ath + return false; + } + +- /* +- * TODO: check chirping pulses +- * checks for chirping are dependent on the DFS regulatory domain +- * used, which is yet TBD +- */ +- + /* convert duration to usecs */ + pe->width = dur_to_usecs(sc->sc_ah, dur); + pe->rssi = rssi; +@@ -190,6 +335,16 @@ void ath9k_dfs_process_phyerr(struct ath + if (!ath9k_postprocess_radar_event(sc, &ard, &pe)) + return; + ++ if (pe.width > MIN_CHIRP_PULSE_WIDTH && ++ pe.width < MAX_CHIRP_PULSE_WIDTH) { ++ bool is_ctl = !!(ard.pulse_bw_info & PRI_CH_RADAR_FOUND); ++ bool is_ext = !!(ard.pulse_bw_info & EXT_CH_RADAR_FOUND); ++ int clen = datalen - 3; ++ pe.chirp = ath9k_check_chirping(sc, data, clen, is_ctl, is_ext); ++ } else { ++ pe.chirp = false; ++ } ++ + ath_dbg(common, DFS, + "ath9k_dfs_process_phyerr: type=%d, freq=%d, ts=%llu, " + "width=%d, rssi=%d, delta_ts=%llu\n", |