forked from LorenzoBianconi/ath_spectral
-
Notifications
You must be signed in to change notification settings - Fork 1
/
Copy pathath9k_spectral.patch
327 lines (310 loc) · 10.9 KB
/
ath9k_spectral.patch
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
diff --git a/drivers/net/wireless/ath/ath9k/ath9k.h b/drivers/net/wireless/ath/ath9k/ath9k.h
index 2ee35f6..b44955e 100644
--- a/drivers/net/wireless/ath/ath9k/ath9k.h
+++ b/drivers/net/wireless/ath/ath9k/ath9k.h
@@ -875,32 +875,49 @@ static inline u8 spectral_bitmap_weight(u8 *bins)
* TODO: this might need rework when switching to nl80211-based
* interface.
*/
-enum ath_fft_sample_type {
- ATH_FFT_SAMPLE_HT20 = 1,
+enum fft_sample_type {
+ FFT_SAMPLE_HT20 = 1,
+ FFT_SAMPLE_HT20_40,
};
struct fft_sample_tlv {
- u8 type; /* see ath_fft_sample */
+ enum fft_sample_type type;
__be16 length;
/* type dependent data follows */
} __packed;
-struct fft_sample_ht20 {
+struct fft_sample {
struct fft_sample_tlv tlv;
-
- u8 max_exp;
-
__be16 freq;
- s8 rssi;
- s8 noise;
-
- __be16 max_magnitude;
- u8 max_index;
- u8 bitmap_weight;
-
__be64 tsf;
- u8 data[SPECTRAL_HT20_NUM_BINS];
+ union {
+ struct {
+ s8 rssi;
+ s8 nf;
+
+ u8 data[SPECTRAL_HT20_NUM_BINS];
+ __be16 max_mag;
+ u8 max_idx;
+ u8 bitmap_w;
+ u8 max_exp;
+ } ht20;
+ struct {
+ s8 lower_rssi;
+ s8 upper_rssi;
+ s8 lower_nf;
+ s8 upper_nf;
+
+ u8 data[SPECTRAL_HT20_40_NUM_BINS];
+ __be16 lower_max_mag;
+ __be16 upper_max_mag;
+ u8 lower_max_idx;
+ u8 upper_max_idx;
+ u8 lower_bitmap_w;
+ u8 upper_bitmap_w;
+ u8 max_exp;
+ } ht20_40;
+ };
} __packed;
void ath9k_tasklet(unsigned long data);
diff --git a/drivers/net/wireless/ath/ath9k/calib.c b/drivers/net/wireless/ath/ath9k/calib.c
index 5e8219a..d09eaeb 100644
--- a/drivers/net/wireless/ath/ath9k/calib.c
+++ b/drivers/net/wireless/ath/ath9k/calib.c
@@ -63,13 +63,13 @@ static s16 ath9k_hw_get_default_nf(struct ath_hw *ah,
return ath9k_hw_get_nf_limits(ah, chan)->nominal;
}
-s16 ath9k_hw_getchan_noise(struct ath_hw *ah, struct ath9k_channel *chan)
+s16 ath9k_hw_getchan_noise(struct ath_hw *ah, struct ath9k_channel *chan,
+ s16 nf)
{
s8 noise = ATH_DEFAULT_NOISE_FLOOR;
- if (chan && chan->noisefloor) {
- s8 delta = chan->noisefloor -
- ATH9K_NF_CAL_NOISE_THRESH -
+ if (nf) {
+ s8 delta = nf - ATH9K_NF_CAL_NOISE_THRESH -
ath9k_hw_get_default_nf(ah, chan);
if (delta > 0)
noise += delta;
@@ -394,7 +394,7 @@ bool ath9k_hw_getnf(struct ath_hw *ah, struct ath9k_channel *chan)
caldata->nfcal_pending = false;
ath9k_hw_update_nfcal_hist_buffer(ah, caldata, nfarray);
chan->noisefloor = h[0].privNF;
- ah->noise = ath9k_hw_getchan_noise(ah, chan);
+ ah->noise = ath9k_hw_getchan_noise(ah, chan, chan->noisefloor);
return true;
}
EXPORT_SYMBOL(ath9k_hw_getnf);
diff --git a/drivers/net/wireless/ath/ath9k/calib.h b/drivers/net/wireless/ath/ath9k/calib.h
index 3d70b8c..b8ed95e 100644
--- a/drivers/net/wireless/ath/ath9k/calib.h
+++ b/drivers/net/wireless/ath/ath9k/calib.h
@@ -116,7 +116,8 @@ void ath9k_init_nfcal_hist_buffer(struct ath_hw *ah,
void ath9k_hw_bstuck_nfcal(struct ath_hw *ah);
void ath9k_hw_reset_calibration(struct ath_hw *ah,
struct ath9k_cal_list *currCal);
-s16 ath9k_hw_getchan_noise(struct ath_hw *ah, struct ath9k_channel *chan);
+s16 ath9k_hw_getchan_noise(struct ath_hw *ah, struct ath9k_channel *chan,
+ s16 nf);
#endif /* CALIB_H */
diff --git a/drivers/net/wireless/ath/ath9k/hw.c b/drivers/net/wireless/ath/ath9k/hw.c
index ecc6ec4..2f1427d 100644
--- a/drivers/net/wireless/ath/ath9k/hw.c
+++ b/drivers/net/wireless/ath/ath9k/hw.c
@@ -1882,7 +1882,7 @@ int ath9k_hw_reset(struct ath_hw *ah, struct ath9k_channel *chan,
} else if (caldata) {
caldata->paprd_packet_sent = false;
}
- ah->noise = ath9k_hw_getchan_noise(ah, chan);
+ ah->noise = ath9k_hw_getchan_noise(ah, chan, chan->noisefloor);
if (fastcc) {
r = ath9k_hw_do_fastcc(ah, chan);
diff --git a/drivers/net/wireless/ath/ath9k/link.c b/drivers/net/wireless/ath/ath9k/link.c
index 2f831db..3e747cc 100644
--- a/drivers/net/wireless/ath/ath9k/link.c
+++ b/drivers/net/wireless/ath/ath9k/link.c
@@ -516,7 +516,8 @@ void ath_update_survey_nf(struct ath_softc *sc, int channel)
if (chan->noisefloor) {
survey->filled |= SURVEY_INFO_NOISE_DBM;
- survey->noise = ath9k_hw_getchan_noise(ah, chan);
+ survey->noise = ath9k_hw_getchan_noise(ah, chan,
+ chan->noisefloor);
}
}
diff --git a/drivers/net/wireless/ath/ath9k/recv.c b/drivers/net/wireless/ath/ath9k/recv.c
index 4ee472a..525f07c 100644
--- a/drivers/net/wireless/ath/ath9k/recv.c
+++ b/drivers/net/wireless/ath/ath9k/recv.c
@@ -972,14 +972,13 @@ static int ath_process_fft(struct ath_softc *sc, struct ieee80211_hdr *hdr,
{
#ifdef CONFIG_ATH9K_DEBUGFS
struct ath_hw *ah = sc->sc_ah;
- u8 bins[SPECTRAL_HT20_NUM_BINS];
- u8 *vdata = (u8 *)hdr;
- struct fft_sample_ht20 fft_sample;
+ u8 type, num_bins, *data, *vdata = (u8 *) hdr;
+ struct fft_sample fft_data;
struct ath_radar_info *radar_info;
- struct ath_ht20_mag_info *mag_info;
int len = rs->rs_datalen;
int dc_pos;
- u16 length, max_magnitude;
+ u16 length, fft_len;
+ enum nl80211_channel_type chtype;
/* AR9280 and before report via ATH9K_PHYERR_RADAR, AR93xx and newer
* via ATH9K_PHYERR_SPECTRAL. Haven't seen ATH9K_PHYERR_FALSE_RADAR_EXT
@@ -997,45 +996,53 @@ static int ath_process_fft(struct ath_softc *sc, struct ieee80211_hdr *hdr,
if (!(radar_info->pulse_bw_info & SPECTRAL_SCAN_BITMASK))
return 0;
- /* Variation in the data length is possible and will be fixed later.
- * Note that we only support HT20 for now.
- *
- * TODO: add HT20_40 support as well.
- */
- if ((len > SPECTRAL_HT20_TOTAL_DATA_LEN + 2) ||
- (len < SPECTRAL_HT20_TOTAL_DATA_LEN - 1))
+ chtype = cfg80211_get_chandef_type(&sc->hw->conf.chandef);
+ if ((chtype == NL80211_CHAN_HT40MINUS) ||
+ (chtype == NL80211_CHAN_HT40PLUS)) {
+ type = FFT_SAMPLE_HT20_40;
+ num_bins = SPECTRAL_HT20_40_NUM_BINS;
+ fft_len = SPECTRAL_HT20_40_TOTAL_DATA_LEN;
+ data = (u8 *) fft_data.ht20_40.data;
+ } else {
+ type = FFT_SAMPLE_HT20;
+ num_bins = SPECTRAL_HT20_NUM_BINS;
+ fft_len = SPECTRAL_HT20_TOTAL_DATA_LEN;
+ data = (u8 *) fft_data.ht20.data;
+ }
+
+ /* variation in the data length is possible and will be fixed later */
+ if ((len > fft_len + 2) || (len < fft_len - 1))
return 1;
- fft_sample.tlv.type = ATH_FFT_SAMPLE_HT20;
- length = sizeof(fft_sample) - sizeof(fft_sample.tlv);
- fft_sample.tlv.length = __cpu_to_be16(length);
+ fft_data.tlv.type = __cpu_to_be32(type);
+ length = sizeof(fft_data) - sizeof(fft_data.tlv);
+ fft_data.tlv.length = __cpu_to_be16(length);
- fft_sample.freq = __cpu_to_be16(ah->curchan->chan->center_freq);
- fft_sample.rssi = fix_rssi_inv_only(rs->rs_rssi_ctl0);
- fft_sample.noise = ah->noise;
+ fft_data.freq = __cpu_to_be16(ah->curchan->chan->center_freq);
+ fft_data.tsf = __cpu_to_be64(tsf);
- switch (len - SPECTRAL_HT20_TOTAL_DATA_LEN) {
+ switch (len - fft_len) {
case 0:
/* length correct, nothing to do. */
- memcpy(bins, vdata, SPECTRAL_HT20_NUM_BINS);
+ memcpy(data, vdata, num_bins);
break;
case -1:
/* first byte missing, duplicate it. */
- memcpy(&bins[1], vdata, SPECTRAL_HT20_NUM_BINS - 1);
- bins[0] = vdata[0];
+ memcpy(&data[1], vdata, num_bins - 1);
+ data[0] = vdata[0];
break;
case 2:
/* MAC added 2 extra bytes at bin 30 and 32, remove them. */
- memcpy(bins, vdata, 30);
- bins[30] = vdata[31];
- memcpy(&bins[31], &vdata[33], SPECTRAL_HT20_NUM_BINS - 31);
+ memcpy(data, vdata, 30);
+ data[30] = vdata[31];
+ memcpy(&data[31], &vdata[33], num_bins - 31);
break;
case 1:
/* MAC added 2 extra bytes AND first byte is missing. */
- bins[0] = vdata[0];
- memcpy(&bins[0], vdata, 30);
- bins[31] = vdata[31];
- memcpy(&bins[32], &vdata[33], SPECTRAL_HT20_NUM_BINS - 32);
+ data[0] = vdata[0];
+ memcpy(&data[1], vdata, 30);
+ data[31] = vdata[31];
+ memcpy(&data[32], &vdata[33], num_bins - 32);
break;
default:
return 1;
@@ -1044,23 +1051,68 @@ static int ath_process_fft(struct ath_softc *sc, struct ieee80211_hdr *hdr,
/* DC value (value in the middle) is the blind spot of the spectral
* sample and invalid, interpolate it.
*/
- dc_pos = SPECTRAL_HT20_NUM_BINS / 2;
- bins[dc_pos] = (bins[dc_pos + 1] + bins[dc_pos - 1]) / 2;
-
- /* mag data is at the end of the frame, in front of radar_info */
- mag_info = ((struct ath_ht20_mag_info *)radar_info) - 1;
-
- /* copy raw bins without scaling them */
- memcpy(fft_sample.data, bins, SPECTRAL_HT20_NUM_BINS);
- fft_sample.max_exp = mag_info->max_exp & 0xf;
-
- max_magnitude = spectral_max_magnitude(mag_info->all_bins);
- fft_sample.max_magnitude = __cpu_to_be16(max_magnitude);
- fft_sample.max_index = spectral_max_index(mag_info->all_bins);
- fft_sample.bitmap_weight = spectral_bitmap_weight(mag_info->all_bins);
- fft_sample.tsf = __cpu_to_be64(tsf);
+ dc_pos = num_bins / 2;
+ data[dc_pos] = (data[dc_pos + 1] + data[dc_pos - 1]) / 2;
+
+ if ((chtype == NL80211_CHAN_HT40MINUS) ||
+ (chtype == NL80211_CHAN_HT40PLUS)) {
+ u16 lower_max_mag, upper_max_mag;
+ s16 nf_ext;
+ struct ath_ht20_40_mag_info *mag_info;
+ struct ath9k_hw_cal_data *caldata = ah->caldata;
+
+ if (caldata)
+ nf_ext = ath9k_hw_getchan_noise(ah, ah->curchan,
+ caldata->nfCalHist[3].privNF);
+ else
+ nf_ext = ATH_DEFAULT_NOISE_FLOOR;
+
+ mag_info = ((struct ath_ht20_40_mag_info *)radar_info) - 1;
+ lower_max_mag = spectral_max_magnitude(mag_info->lower_bins);
+ upper_max_mag = spectral_max_magnitude(mag_info->upper_bins);
+
+ if (chtype == NL80211_CHAN_HT40PLUS) {
+ fft_data.ht20_40.lower_rssi =
+ fix_rssi_inv_only(rs->rs_rssi_ctl0);
+ fft_data.ht20_40.upper_rssi =
+ fix_rssi_inv_only(rs->rs_rssi_ext0);
+ fft_data.ht20_40.lower_nf = ah->noise;
+ fft_data.ht20_40.upper_nf = nf_ext;
+ } else {
+ fft_data.ht20_40.lower_rssi =
+ fix_rssi_inv_only(rs->rs_rssi_ext0);
+ fft_data.ht20_40.upper_rssi =
+ fix_rssi_inv_only(rs->rs_rssi_ctl0);
+ fft_data.ht20_40.lower_nf = nf_ext;
+ fft_data.ht20_40.upper_nf = ah->noise;
+ }
+ fft_data.ht20_40.lower_max_mag = __cpu_to_be16(lower_max_mag);
+ fft_data.ht20_40.lower_max_idx =
+ spectral_max_index(mag_info->lower_bins);
+ fft_data.ht20_40.lower_bitmap_w =
+ spectral_bitmap_weight(mag_info->lower_bins);
+ fft_data.ht20_40.upper_max_mag = __cpu_to_be16(upper_max_mag);
+ fft_data.ht20_40.upper_max_idx =
+ spectral_max_index(mag_info->upper_bins);
+ fft_data.ht20_40.upper_bitmap_w =
+ spectral_bitmap_weight(mag_info->upper_bins);
+ fft_data.ht20_40.max_exp = mag_info->max_exp & 0xf;
+ } else {
+ u16 max_mag;
+ struct ath_ht20_mag_info *mag_info;
+
+ mag_info = ((struct ath_ht20_mag_info *)radar_info) - 1;
+ max_mag = spectral_max_magnitude(mag_info->all_bins);
+ fft_data.ht20.rssi = fix_rssi_inv_only(rs->rs_rssi_ctl0);
+ fft_data.ht20.nf = ah->noise;
+ fft_data.ht20.max_mag = __cpu_to_be16(max_mag);
+ fft_data.ht20.max_idx = spectral_max_index(mag_info->all_bins);
+ fft_data.ht20.bitmap_w =
+ spectral_bitmap_weight(mag_info->all_bins);
+ fft_data.ht20.max_exp = mag_info->max_exp & 0xf;
+ }
- ath_debug_send_fft_sample(sc, &fft_sample.tlv);
+ ath_debug_send_fft_sample(sc, &fft_data.tlv);
return 1;
#else
return 0;