3437f139f79e3b84af1990729d50e495ef7f8c41
[openwrt/staging/chunkeey.git] / package / kernel / mac80211 / patches / 304-ath9k-DFS-add-pulse-chirp-detection-for-FCC.patch
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
4
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
8 pulses.
9
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
15
16 The chirp detection has been tested with reference
17 radar generating devices and proved to work reliably.
18
19 Signed-off-by: Zefir Kurtisi <zefir.kurtisi@neratec.com>
20 ---
21
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 {
25 u8 pulse_length_pri;
26 };
27
28 +/**** begin: CHIRP ************************************************************/
29 +
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
33 + */
34 +static const int BIN_DELTA_MIN = 1;
35 +static const int BIN_DELTA_MAX = 10;
36 +
37 +/* we need at least 3 deltas / 4 samples for a reliable chirp detection */
38 +#define NUM_DIFFS 3
39 +static const int FFT_NUM_SAMPLES = (NUM_DIFFS + 1);
40 +
41 +/* Threshold for difference of delta peaks */
42 +static const int MAX_DIFF = 2;
43 +
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;
47 +
48 +struct ath9k_dfs_fft_20 {
49 + u8 bin[28];
50 + u8 lower_bins[3];
51 +} __packed;
52 +struct ath9k_dfs_fft_40 {
53 + u8 bin[64];
54 + u8 lower_bins[3];
55 + u8 upper_bins[3];
56 +} __packed;
57 +
58 +static inline int fft_max_index(u8 *bins)
59 +{
60 + return (bins[2] & 0xfc) >> 2;
61 +}
62 +static inline int fft_max_magnitude(u8 *bins)
63 +{
64 + return (bins[0] & 0xc0) >> 6 | bins[1] << 2 | (bins[2] & 0x03) << 10;
65 +}
66 +static inline u8 fft_bitmap_weight(u8 *bins)
67 +{
68 + return bins[0] & 0x3f;
69 +}
70 +
71 +static int ath9k_get_max_index_ht40(struct ath9k_dfs_fft_40 *fft,
72 + bool is_ctl, bool is_ext)
73 +{
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;
80 +
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)
86 + is_ctl = false;
87 + else
88 + is_ext = false;
89 + }
90 + }
91 + if (is_ctl)
92 + return fft_max_index(fft->lower_bins);
93 + return fft_max_index(fft->upper_bins) + DFS_UPPER_BIN_OFFSET;
94 +}
95 +static bool ath9k_check_chirping(struct ath_softc *sc, u8 *data,
96 + int datalen, bool is_ctl, bool is_ext)
97 +{
98 + int i;
99 + int max_bin[FFT_NUM_SAMPLES];
100 + struct ath_hw *ah = sc->sc_ah;
101 + struct ath_common *common = ath9k_hw_common(ah);
102 + int prev_delta;
103 +
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)
108 + return false;
109 +
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");
114 + return false;
115 + }
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");
120 + }
121 + if (IS_CHAN_HT40MINUS(ah->curchan)) {
122 + int temp = is_ctl;
123 + is_ctl = is_ext;
124 + is_ext = temp;
125 + }
126 + for (i = 0; i < FFT_NUM_SAMPLES; i++)
127 + max_bin[i] = ath9k_get_max_index_ht40(fft + i, is_ctl,
128 + is_ext);
129 + } else {
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)
133 + return false;
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");
138 + return false;
139 + }
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;
143 + }
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]);
146 +
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
150 + */
151 + prev_delta = 0;
152 + for (i = 0; i < NUM_DIFFS; i++) {
153 + int ddelta = -1;
154 + int delta = max_bin[i + 1] - max_bin[i];
155 +
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);
160 + return false;
161 + }
162 + if (i == 0)
163 + goto done;
164 + ddelta = delta - prev_delta;
165 + if (abs(ddelta) > MAX_DIFF) {
166 + ath_dbg(common, DFS, "CHIRP: ddelta %d too high\n",
167 + ddelta);
168 + return false;
169 + }
170 +done:
171 + ath_dbg(common, DFS, "CHIRP - %d: delta=%d, ddelta=%d\n",
172 + i, delta, ddelta);
173 + prev_delta = delta;
174 + }
175 + return true;
176 +}
177 +/**** end: CHIRP **************************************************************/
178 +
179 /* convert pulse duration to usecs, considering clock mode */
180 static u32 dur_to_usecs(struct ath_hw *ah, u32 dur)
181 {
182 @@ -113,12 +264,6 @@ ath9k_postprocess_radar_event(struct ath
183 return false;
184 }
185
186 - /*
187 - * TODO: check chirping pulses
188 - * checks for chirping are dependent on the DFS regulatory domain
189 - * used, which is yet TBD
190 - */
191 -
192 /* convert duration to usecs */
193 pe->width = dur_to_usecs(sc->sc_ah, dur);
194 pe->rssi = rssi;
195 @@ -190,6 +335,16 @@ void ath9k_dfs_process_phyerr(struct ath
196 if (!ath9k_postprocess_radar_event(sc, &ard, &pe))
197 return;
198
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);
205 + } else {
206 + pe.chirp = false;
207 + }
208 +
209 ath_dbg(common, DFS,
210 "ath9k_dfs_process_phyerr: type=%d, freq=%d, ts=%llu, "
211 "width=%d, rssi=%d, delta_ts=%llu\n",