aboutsummaryrefslogtreecommitdiffstats
path: root/package/kernel/mac80211/patches/304-ath9k-DFS-add-pulse-chirp-detection-for-FCC.patch
diff options
context:
space:
mode:
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.patch211
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 0000000000..3437f139f7
--- /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",