1 From: Zefir Kurtisi <zefir.kurtisi@neratec.com>
2 Date: Tue, 16 Jun 2015 12:52:16 +0200
3 Subject: [PATCH] ath9k: DFS - add pulse chirp detection for FCC
5 FCC long pulse radar (type 5) requires pulses to be
6 checked for chirping. This patch implements chirp
7 detection based on the FFT data provided for long
10 A chirp is detected when a set of criteria defined
11 by FCC pulse characteristics is met, including
12 * have at least 4 FFT samples
13 * max_bin index moves equidistantly between samples
14 * the gradient is within defined range
16 The chirp detection has been tested with reference
17 radar generating devices and proved to work reliably.
19 Signed-off-by: Zefir Kurtisi <zefir.kurtisi@neratec.com>
22 --- a/drivers/net/wireless/ath/ath9k/dfs.c
23 +++ b/drivers/net/wireless/ath/ath9k/dfs.c
24 @@ -30,6 +30,157 @@ struct ath_radar_data {
28 +/**** begin: CHIRP ************************************************************/
30 +/* min and max gradients for defined FCC chirping pulses, given by
31 + * - 20MHz chirp width over a pulse width of 50us
32 + * - 5MHz chirp width over a pulse width of 100us
34 +static const int BIN_DELTA_MIN = 1;
35 +static const int BIN_DELTA_MAX = 10;
37 +/* we need at least 3 deltas / 4 samples for a reliable chirp detection */
39 +static const int FFT_NUM_SAMPLES = (NUM_DIFFS + 1);
41 +/* Threshold for difference of delta peaks */
42 +static const int MAX_DIFF = 2;
44 +/* width range to be checked for chirping */
45 +static const int MIN_CHIRP_PULSE_WIDTH = 20;
46 +static const int MAX_CHIRP_PULSE_WIDTH = 110;
48 +struct ath9k_dfs_fft_20 {
52 +struct ath9k_dfs_fft_40 {
58 +static inline int fft_max_index(u8 *bins)
60 + return (bins[2] & 0xfc) >> 2;
62 +static inline int fft_max_magnitude(u8 *bins)
64 + return (bins[0] & 0xc0) >> 6 | bins[1] << 2 | (bins[2] & 0x03) << 10;
66 +static inline u8 fft_bitmap_weight(u8 *bins)
68 + return bins[0] & 0x3f;
71 +static int ath9k_get_max_index_ht40(struct ath9k_dfs_fft_40 *fft,
72 + bool is_ctl, bool is_ext)
74 + const int DFS_UPPER_BIN_OFFSET = 64;
75 + /* if detected radar on both channels, select the significant one */
76 + if (is_ctl && is_ext) {
77 + /* first check wether channels have 'strong' bins */
78 + is_ctl = fft_bitmap_weight(fft->lower_bins) != 0;
79 + is_ext = fft_bitmap_weight(fft->upper_bins) != 0;
81 + /* if still unclear, take higher magnitude */
82 + if (is_ctl && is_ext) {
83 + int mag_lower = fft_max_magnitude(fft->lower_bins);
84 + int mag_upper = fft_max_magnitude(fft->upper_bins);
85 + if (mag_upper > mag_lower)
92 + return fft_max_index(fft->lower_bins);
93 + return fft_max_index(fft->upper_bins) + DFS_UPPER_BIN_OFFSET;
95 +static bool ath9k_check_chirping(struct ath_softc *sc, u8 *data,
96 + int datalen, bool is_ctl, bool is_ext)
99 + int max_bin[FFT_NUM_SAMPLES];
100 + struct ath_hw *ah = sc->sc_ah;
101 + struct ath_common *common = ath9k_hw_common(ah);
104 + if (IS_CHAN_HT40(ah->curchan)) {
105 + struct ath9k_dfs_fft_40 *fft = (struct ath9k_dfs_fft_40 *) data;
106 + int num_fft_packets = datalen / sizeof(*fft);
107 + if (num_fft_packets == 0)
110 + ath_dbg(common, DFS, "HT40: datalen=%d, num_fft_packets=%d\n",
111 + datalen, num_fft_packets);
112 + if (num_fft_packets < (FFT_NUM_SAMPLES)) {
113 + ath_dbg(common, DFS, "not enough packets for chirp\n");
116 + /* HW sometimes adds 2 garbage bytes in front of FFT samples */
117 + if ((datalen % sizeof(*fft)) == 2) {
118 + fft = (struct ath9k_dfs_fft_40 *) (data + 2);
119 + ath_dbg(common, DFS, "fixing datalen by 2\n");
121 + if (IS_CHAN_HT40MINUS(ah->curchan)) {
126 + for (i = 0; i < FFT_NUM_SAMPLES; i++)
127 + max_bin[i] = ath9k_get_max_index_ht40(fft + i, is_ctl,
130 + struct ath9k_dfs_fft_20 *fft = (struct ath9k_dfs_fft_20 *) data;
131 + int num_fft_packets = datalen / sizeof(*fft);
132 + if (num_fft_packets == 0)
134 + ath_dbg(common, DFS, "HT20: datalen=%d, num_fft_packets=%d\n",
135 + datalen, num_fft_packets);
136 + if (num_fft_packets < (FFT_NUM_SAMPLES)) {
137 + ath_dbg(common, DFS, "not enough packets for chirp\n");
140 + /* in ht20, this is a 6-bit signed number => shift it to 0 */
141 + for (i = 0; i < FFT_NUM_SAMPLES; i++)
142 + max_bin[i] = fft_max_index(fft[i].lower_bins) ^ 0x20;
144 + ath_dbg(common, DFS, "bin_max = [%d, %d, %d, %d]\n",
145 + max_bin[0], max_bin[1], max_bin[2], max_bin[3]);
147 + /* Check for chirp attributes within specs
148 + * a) delta of adjacent max_bins is within range
149 + * b) delta of adjacent deltas are within tolerance
152 + for (i = 0; i < NUM_DIFFS; i++) {
154 + int delta = max_bin[i + 1] - max_bin[i];
156 + /* ensure gradient is within valid range */
157 + if (abs(delta) < BIN_DELTA_MIN || abs(delta) > BIN_DELTA_MAX) {
158 + ath_dbg(common, DFS, "CHIRP: invalid delta %d "
159 + "in sample %d\n", delta, i);
164 + ddelta = delta - prev_delta;
165 + if (abs(ddelta) > MAX_DIFF) {
166 + ath_dbg(common, DFS, "CHIRP: ddelta %d too high\n",
171 + ath_dbg(common, DFS, "CHIRP - %d: delta=%d, ddelta=%d\n",
173 + prev_delta = delta;
177 +/**** end: CHIRP **************************************************************/
179 /* convert pulse duration to usecs, considering clock mode */
180 static u32 dur_to_usecs(struct ath_hw *ah, u32 dur)
182 @@ -113,12 +264,6 @@ ath9k_postprocess_radar_event(struct ath
187 - * TODO: check chirping pulses
188 - * checks for chirping are dependent on the DFS regulatory domain
189 - * used, which is yet TBD
192 /* convert duration to usecs */
193 pe->width = dur_to_usecs(sc->sc_ah, dur);
195 @@ -190,6 +335,16 @@ void ath9k_dfs_process_phyerr(struct ath
196 if (!ath9k_postprocess_radar_event(sc, &ard, &pe))
199 + if (pe.width > MIN_CHIRP_PULSE_WIDTH &&
200 + pe.width < MAX_CHIRP_PULSE_WIDTH) {
201 + bool is_ctl = !!(ard.pulse_bw_info & PRI_CH_RADAR_FOUND);
202 + bool is_ext = !!(ard.pulse_bw_info & EXT_CH_RADAR_FOUND);
203 + int clen = datalen - 3;
204 + pe.chirp = ath9k_check_chirping(sc, data, clen, is_ctl, is_ext);
210 "ath9k_dfs_process_phyerr: type=%d, freq=%d, ts=%llu, "
211 "width=%d, rssi=%d, delta_ts=%llu\n",