xref: /linux/drivers/net/wireless/ath/ath9k/common-spectral.c (revision 8be4d31cb8aaeea27bde4b7ddb26e28a89062ebf)
1 /*
2  * Copyright (c) 2013 Qualcomm Atheros, Inc.
3  *
4  * Permission to use, copy, modify, and/or distribute this software for any
5  * purpose with or without fee is hereby granted, provided that the above
6  * copyright notice and this permission notice appear in all copies.
7  *
8  * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
9  * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
10  * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
11  * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
12  * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
13  * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
14  * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
15  */
16 
17 #include <linux/export.h>
18 #include <linux/relay.h>
19 #include <linux/random.h>
20 #include "ath9k.h"
21 
fix_rssi_inv_only(u8 rssi_val)22 static s8 fix_rssi_inv_only(u8 rssi_val)
23 {
24 	if (rssi_val == 128)
25 		rssi_val = 0;
26 	return (s8) rssi_val;
27 }
28 
ath_debug_send_fft_sample(struct ath_spec_scan_priv * spec_priv,struct fft_sample_tlv * fft_sample_tlv)29 static void ath_debug_send_fft_sample(struct ath_spec_scan_priv *spec_priv,
30 				      struct fft_sample_tlv *fft_sample_tlv)
31 {
32 	int length;
33 	if (!spec_priv->rfs_chan_spec_scan)
34 		return;
35 
36 	length = __be16_to_cpu(fft_sample_tlv->length) +
37 		 sizeof(*fft_sample_tlv);
38 	relay_write(spec_priv->rfs_chan_spec_scan, fft_sample_tlv, length);
39 }
40 
41 typedef int (ath_cmn_fft_idx_validator) (u8 *sample_end, int bytes_read);
42 
43 static int
ath_cmn_max_idx_verify_ht20_fft(u8 * sample_end,int bytes_read)44 ath_cmn_max_idx_verify_ht20_fft(u8 *sample_end, int bytes_read)
45 {
46 	struct ath_ht20_mag_info *mag_info;
47 	u8 *sample;
48 	u16 max_magnitude;
49 	u8 max_index;
50 	u8 max_exp;
51 
52 	/* Sanity check so that we don't read outside the read
53 	 * buffer
54 	 */
55 	if (bytes_read < SPECTRAL_HT20_SAMPLE_LEN - 1)
56 		return -1;
57 
58 	mag_info = (struct ath_ht20_mag_info *) (sample_end -
59 				sizeof(struct ath_ht20_mag_info) + 1);
60 
61 	sample = sample_end - SPECTRAL_HT20_SAMPLE_LEN + 1;
62 
63 	max_index = spectral_max_index_ht20(mag_info->all_bins);
64 	max_magnitude = spectral_max_magnitude(mag_info->all_bins);
65 
66 	max_exp = mag_info->max_exp & 0xf;
67 
68 	/* Don't try to read something outside the read buffer
69 	 * in case of a missing byte (so bins[0] will be outside
70 	 * the read buffer)
71 	 */
72 	if (bytes_read < SPECTRAL_HT20_SAMPLE_LEN && max_index < 1)
73 		return -1;
74 
75 	if ((sample[max_index] & 0xf8) != ((max_magnitude >> max_exp) & 0xf8))
76 		return -1;
77 	else
78 		return 0;
79 }
80 
81 static int
ath_cmn_max_idx_verify_ht20_40_fft(u8 * sample_end,int bytes_read)82 ath_cmn_max_idx_verify_ht20_40_fft(u8 *sample_end, int bytes_read)
83 {
84 	struct ath_ht20_40_mag_info *mag_info;
85 	u8 *sample;
86 	u16 lower_mag, upper_mag;
87 	u8 lower_max_index, upper_max_index;
88 	u8 max_exp;
89 	int dc_pos = SPECTRAL_HT20_40_NUM_BINS / 2;
90 
91 	/* Sanity check so that we don't read outside the read
92 	 * buffer
93 	 */
94 	if (bytes_read < SPECTRAL_HT20_40_SAMPLE_LEN - 1)
95 		return -1;
96 
97 	mag_info = (struct ath_ht20_40_mag_info *) (sample_end -
98 				sizeof(struct ath_ht20_40_mag_info) + 1);
99 
100 	sample = sample_end - SPECTRAL_HT20_40_SAMPLE_LEN + 1;
101 
102 	lower_mag = spectral_max_magnitude(mag_info->lower_bins);
103 	lower_max_index = spectral_max_index_ht40(mag_info->lower_bins);
104 
105 	upper_mag = spectral_max_magnitude(mag_info->upper_bins);
106 	upper_max_index = spectral_max_index_ht40(mag_info->upper_bins);
107 
108 	max_exp = mag_info->max_exp & 0xf;
109 
110 	/* Don't try to read something outside the read buffer
111 	 * in case of a missing byte (so bins[0] will be outside
112 	 * the read buffer)
113 	 */
114 	if (bytes_read < SPECTRAL_HT20_40_SAMPLE_LEN &&
115 	   ((upper_max_index < 1) || (lower_max_index < 1)))
116 		return -1;
117 
118 	if (((sample[upper_max_index + dc_pos] & 0xf8) !=
119 	     ((upper_mag >> max_exp) & 0xf8)) ||
120 	    ((sample[lower_max_index] & 0xf8) !=
121 	     ((lower_mag >> max_exp) & 0xf8)))
122 		return -1;
123 	else
124 		return 0;
125 }
126 
127 typedef int (ath_cmn_fft_sample_handler) (struct ath_rx_status *rs,
128 			struct ath_spec_scan_priv *spec_priv,
129 			u8 *sample_buf, u64 tsf, u16 freq, int chan_type);
130 
131 static int
ath_cmn_process_ht20_fft(struct ath_rx_status * rs,struct ath_spec_scan_priv * spec_priv,u8 * sample_buf,u64 tsf,u16 freq,int chan_type)132 ath_cmn_process_ht20_fft(struct ath_rx_status *rs,
133 			struct ath_spec_scan_priv *spec_priv,
134 			u8 *sample_buf,
135 			u64 tsf, u16 freq, int chan_type)
136 {
137 	struct fft_sample_ht20 fft_sample_20;
138 	struct ath_common *common = ath9k_hw_common(spec_priv->ah);
139 	struct ath_hw *ah = spec_priv->ah;
140 	struct ath_ht20_mag_info *mag_info;
141 	struct fft_sample_tlv *tlv;
142 	int i = 0;
143 	int ret = 0;
144 	int dc_pos = SPECTRAL_HT20_NUM_BINS / 2;
145 	u16 magnitude, tmp_mag, length;
146 	u8 max_index, bitmap_w, max_exp;
147 
148 	length = sizeof(fft_sample_20) - sizeof(struct fft_sample_tlv);
149 	fft_sample_20.tlv.type = ATH_FFT_SAMPLE_HT20;
150 	fft_sample_20.tlv.length = __cpu_to_be16(length);
151 	fft_sample_20.freq = __cpu_to_be16(freq);
152 	fft_sample_20.rssi = fix_rssi_inv_only(rs->rs_rssi_ctl[0]);
153 	fft_sample_20.noise = ah->noise;
154 
155 	mag_info = (struct ath_ht20_mag_info *) (sample_buf +
156 					SPECTRAL_HT20_NUM_BINS);
157 
158 	magnitude = spectral_max_magnitude(mag_info->all_bins);
159 	fft_sample_20.max_magnitude = __cpu_to_be16(magnitude);
160 
161 	max_index = spectral_max_index_ht20(mag_info->all_bins);
162 	fft_sample_20.max_index = max_index;
163 
164 	bitmap_w = spectral_bitmap_weight(mag_info->all_bins);
165 	fft_sample_20.bitmap_weight = bitmap_w;
166 
167 	max_exp = mag_info->max_exp & 0xf;
168 	fft_sample_20.max_exp = max_exp;
169 
170 	fft_sample_20.tsf = __cpu_to_be64(tsf);
171 
172 	memcpy(fft_sample_20.data, sample_buf, SPECTRAL_HT20_NUM_BINS);
173 
174 	ath_dbg(common, SPECTRAL_SCAN, "FFT HT20 frame: max mag 0x%X,"
175 					"max_mag_idx %i\n",
176 					magnitude >> max_exp,
177 					max_index);
178 
179 	if ((fft_sample_20.data[max_index] & 0xf8) !=
180 	    ((magnitude >> max_exp) & 0xf8)) {
181 		ath_dbg(common, SPECTRAL_SCAN, "Magnitude mismatch !\n");
182 		ret = -1;
183 	}
184 
185 	/* DC value (value in the middle) is the blind spot of the spectral
186 	 * sample and invalid, interpolate it.
187 	 */
188 	fft_sample_20.data[dc_pos] = (fft_sample_20.data[dc_pos + 1] +
189 					fft_sample_20.data[dc_pos - 1]) / 2;
190 
191 	/* Check if the maximum magnitude is indeed maximum,
192 	 * also if the maximum value was at dc_pos, calculate
193 	 * a new one (since value at dc_pos is invalid).
194 	 */
195 	if (max_index == dc_pos) {
196 		tmp_mag = 0;
197 		for (i = 0; i < dc_pos; i++) {
198 			if (fft_sample_20.data[i] > tmp_mag) {
199 				tmp_mag = fft_sample_20.data[i];
200 				fft_sample_20.max_index = i;
201 			}
202 		}
203 
204 		magnitude = tmp_mag << max_exp;
205 		fft_sample_20.max_magnitude = __cpu_to_be16(magnitude);
206 
207 		ath_dbg(common, SPECTRAL_SCAN,
208 			"Calculated new lower max 0x%X at %i\n",
209 			tmp_mag, fft_sample_20.max_index);
210 	} else
211 	for (i = 0; i < SPECTRAL_HT20_NUM_BINS; i++) {
212 		if (fft_sample_20.data[i] == (magnitude >> max_exp))
213 			ath_dbg(common, SPECTRAL_SCAN,
214 				"Got max: 0x%X at index %i\n",
215 				fft_sample_20.data[i], i);
216 
217 		if (fft_sample_20.data[i] > (magnitude >> max_exp)) {
218 			ath_dbg(common, SPECTRAL_SCAN,
219 				"Got bin %i greater than max: 0x%X\n",
220 				i, fft_sample_20.data[i]);
221 			ret = -1;
222 		}
223 	}
224 
225 	if (ret < 0)
226 		return ret;
227 
228 	tlv = (struct fft_sample_tlv *)&fft_sample_20;
229 
230 	ath_debug_send_fft_sample(spec_priv, tlv);
231 
232 	return 0;
233 }
234 
235 static int
ath_cmn_process_ht20_40_fft(struct ath_rx_status * rs,struct ath_spec_scan_priv * spec_priv,u8 * sample_buf,u64 tsf,u16 freq,int chan_type)236 ath_cmn_process_ht20_40_fft(struct ath_rx_status *rs,
237 			struct ath_spec_scan_priv *spec_priv,
238 			u8 *sample_buf,
239 			u64 tsf, u16 freq, int chan_type)
240 {
241 	struct fft_sample_ht20_40 fft_sample_40;
242 	struct ath_common *common = ath9k_hw_common(spec_priv->ah);
243 	struct ath_hw *ah = spec_priv->ah;
244 	struct ath9k_hw_cal_data *caldata = ah->caldata;
245 	struct ath_ht20_40_mag_info *mag_info;
246 	struct fft_sample_tlv *tlv;
247 	int dc_pos = SPECTRAL_HT20_40_NUM_BINS / 2;
248 	int i = 0;
249 	int ret = 0;
250 	s16 ext_nf;
251 	u16 lower_mag, upper_mag, tmp_mag, length;
252 	s8 lower_rssi, upper_rssi;
253 	u8 lower_max_index, upper_max_index;
254 	u8 lower_bitmap_w, upper_bitmap_w, max_exp;
255 
256 	if (caldata)
257 		ext_nf = ath9k_hw_getchan_noise(ah, ah->curchan,
258 				caldata->nfCalHist[3].privNF);
259 	else
260 		ext_nf = ATH_DEFAULT_NOISE_FLOOR;
261 
262 	length = sizeof(fft_sample_40) - sizeof(struct fft_sample_tlv);
263 	fft_sample_40.tlv.type = ATH_FFT_SAMPLE_HT20_40;
264 	fft_sample_40.tlv.length = __cpu_to_be16(length);
265 	fft_sample_40.freq = __cpu_to_be16(freq);
266 	fft_sample_40.channel_type = chan_type;
267 
268 	if (chan_type == NL80211_CHAN_HT40PLUS) {
269 		lower_rssi = fix_rssi_inv_only(rs->rs_rssi_ctl[0]);
270 		upper_rssi = fix_rssi_inv_only(rs->rs_rssi_ext[0]);
271 
272 		fft_sample_40.lower_noise = ah->noise;
273 		fft_sample_40.upper_noise = ext_nf;
274 	} else {
275 		lower_rssi = fix_rssi_inv_only(rs->rs_rssi_ext[0]);
276 		upper_rssi = fix_rssi_inv_only(rs->rs_rssi_ctl[0]);
277 
278 		fft_sample_40.lower_noise = ext_nf;
279 		fft_sample_40.upper_noise = ah->noise;
280 	}
281 
282 	fft_sample_40.lower_rssi = lower_rssi;
283 	fft_sample_40.upper_rssi = upper_rssi;
284 
285 	mag_info = (struct ath_ht20_40_mag_info *) (sample_buf +
286 					SPECTRAL_HT20_40_NUM_BINS);
287 
288 	lower_mag = spectral_max_magnitude(mag_info->lower_bins);
289 	fft_sample_40.lower_max_magnitude = __cpu_to_be16(lower_mag);
290 
291 	upper_mag = spectral_max_magnitude(mag_info->upper_bins);
292 	fft_sample_40.upper_max_magnitude = __cpu_to_be16(upper_mag);
293 
294 	lower_max_index = spectral_max_index_ht40(mag_info->lower_bins);
295 	fft_sample_40.lower_max_index = lower_max_index;
296 
297 	upper_max_index = spectral_max_index_ht40(mag_info->upper_bins);
298 	fft_sample_40.upper_max_index = upper_max_index;
299 
300 	lower_bitmap_w = spectral_bitmap_weight(mag_info->lower_bins);
301 	fft_sample_40.lower_bitmap_weight = lower_bitmap_w;
302 
303 	upper_bitmap_w = spectral_bitmap_weight(mag_info->upper_bins);
304 	fft_sample_40.upper_bitmap_weight = upper_bitmap_w;
305 
306 	max_exp = mag_info->max_exp & 0xf;
307 	fft_sample_40.max_exp = max_exp;
308 
309 	fft_sample_40.tsf = __cpu_to_be64(tsf);
310 
311 	memcpy(fft_sample_40.data, sample_buf, SPECTRAL_HT20_40_NUM_BINS);
312 
313 	ath_dbg(common, SPECTRAL_SCAN, "FFT HT20/40 frame: lower mag 0x%X,"
314 					"lower_mag_idx %i, upper mag 0x%X,"
315 					"upper_mag_idx %i\n",
316 					lower_mag >> max_exp,
317 					lower_max_index,
318 					upper_mag >> max_exp,
319 					upper_max_index);
320 
321 	/* Check if we got the expected magnitude values at
322 	 * the expected bins
323 	 */
324 	if (((fft_sample_40.data[upper_max_index + dc_pos] & 0xf8)
325 	    != ((upper_mag >> max_exp) & 0xf8)) ||
326 	   ((fft_sample_40.data[lower_max_index] & 0xf8)
327 	    != ((lower_mag >> max_exp) & 0xf8))) {
328 		ath_dbg(common, SPECTRAL_SCAN, "Magnitude mismatch !\n");
329 		ret = -1;
330 	}
331 
332 	/* DC value (value in the middle) is the blind spot of the spectral
333 	 * sample and invalid, interpolate it.
334 	 */
335 	fft_sample_40.data[dc_pos] = (fft_sample_40.data[dc_pos + 1] +
336 					fft_sample_40.data[dc_pos - 1]) / 2;
337 
338 	/* Check if the maximum magnitudes are indeed maximum,
339 	 * also if the maximum value was at dc_pos, calculate
340 	 * a new one (since value at dc_pos is invalid).
341 	 */
342 	if (lower_max_index == dc_pos) {
343 		tmp_mag = 0;
344 		for (i = 0; i < dc_pos; i++) {
345 			if (fft_sample_40.data[i] > tmp_mag) {
346 				tmp_mag = fft_sample_40.data[i];
347 				fft_sample_40.lower_max_index = i;
348 			}
349 		}
350 
351 		lower_mag = tmp_mag << max_exp;
352 		fft_sample_40.lower_max_magnitude = __cpu_to_be16(lower_mag);
353 
354 		ath_dbg(common, SPECTRAL_SCAN,
355 			"Calculated new lower max 0x%X at %i\n",
356 			tmp_mag, fft_sample_40.lower_max_index);
357 	} else
358 	for (i = 0; i < dc_pos; i++) {
359 		if (fft_sample_40.data[i] == (lower_mag >> max_exp))
360 			ath_dbg(common, SPECTRAL_SCAN,
361 				"Got lower mag: 0x%X at index %i\n",
362 				fft_sample_40.data[i], i);
363 
364 		if (fft_sample_40.data[i] > (lower_mag >> max_exp)) {
365 			ath_dbg(common, SPECTRAL_SCAN,
366 				"Got lower bin %i higher than max: 0x%X\n",
367 				i, fft_sample_40.data[i]);
368 			ret = -1;
369 		}
370 	}
371 
372 	if (upper_max_index == dc_pos) {
373 		tmp_mag = 0;
374 		for (i = dc_pos; i < SPECTRAL_HT20_40_NUM_BINS; i++) {
375 			if (fft_sample_40.data[i] > tmp_mag) {
376 				tmp_mag = fft_sample_40.data[i];
377 				fft_sample_40.upper_max_index = i;
378 			}
379 		}
380 		upper_mag = tmp_mag << max_exp;
381 		fft_sample_40.upper_max_magnitude = __cpu_to_be16(upper_mag);
382 
383 		ath_dbg(common, SPECTRAL_SCAN,
384 			"Calculated new upper max 0x%X at %i\n",
385 			tmp_mag, fft_sample_40.upper_max_index);
386 	} else
387 	for (i = dc_pos; i < SPECTRAL_HT20_40_NUM_BINS; i++) {
388 		if (fft_sample_40.data[i] == (upper_mag >> max_exp))
389 			ath_dbg(common, SPECTRAL_SCAN,
390 				"Got upper mag: 0x%X at index %i\n",
391 				fft_sample_40.data[i], i);
392 
393 		if (fft_sample_40.data[i] > (upper_mag >> max_exp)) {
394 			ath_dbg(common, SPECTRAL_SCAN,
395 				"Got upper bin %i higher than max: 0x%X\n",
396 				i, fft_sample_40.data[i]);
397 
398 			ret = -1;
399 		}
400 	}
401 
402 	if (ret < 0)
403 		return ret;
404 
405 	tlv = (struct fft_sample_tlv *)&fft_sample_40;
406 
407 	ath_debug_send_fft_sample(spec_priv, tlv);
408 
409 	return 0;
410 }
411 
412 static inline void
ath_cmn_copy_fft_frame(u8 * in,u8 * out,int sample_len,int sample_bytes)413 ath_cmn_copy_fft_frame(u8 *in, u8 *out, int sample_len, int sample_bytes)
414 {
415 	switch (sample_bytes - sample_len) {
416 	case -1:
417 		/* First byte missing */
418 		memcpy(&out[1], in,
419 		       sample_len - 1);
420 		break;
421 	case 0:
422 		/* Length correct, nothing to do. */
423 		memcpy(out, in, sample_len);
424 		break;
425 	case 1:
426 		/* MAC added 2 extra bytes AND first byte
427 		 * is missing.
428 		 */
429 		memcpy(&out[1], in, 30);
430 		out[31] = in[31];
431 		memcpy(&out[32], &in[33],
432 		       sample_len - 32);
433 		break;
434 	case 2:
435 		/* MAC added 2 extra bytes at bin 30 and 32,
436 		 * remove them.
437 		 */
438 		memcpy(out, in, 30);
439 		out[30] = in[31];
440 		memcpy(&out[31], &in[33],
441 		       sample_len - 31);
442 		break;
443 	default:
444 		break;
445 	}
446 }
447 
448 static int
ath_cmn_is_fft_buf_full(struct ath_spec_scan_priv * spec_priv)449 ath_cmn_is_fft_buf_full(struct ath_spec_scan_priv *spec_priv)
450 {
451 	int i = 0;
452 	int ret = 0;
453 	struct rchan_buf *buf;
454 	struct rchan *rc = spec_priv->rfs_chan_spec_scan;
455 
456 	for_each_possible_cpu(i) {
457 		if ((buf = *per_cpu_ptr(rc->buf, i))) {
458 			ret += relay_buf_full(buf);
459 		}
460 	}
461 
462 	if (ret)
463 		return 1;
464 	else
465 		return 0;
466 }
467 
468 /* returns 1 if this was a spectral frame, even if not handled. */
ath_cmn_process_fft(struct ath_spec_scan_priv * spec_priv,struct ieee80211_hdr * hdr,struct ath_rx_status * rs,u64 tsf)469 int ath_cmn_process_fft(struct ath_spec_scan_priv *spec_priv, struct ieee80211_hdr *hdr,
470 		    struct ath_rx_status *rs, u64 tsf)
471 {
472 	u8 sample_buf[SPECTRAL_SAMPLE_MAX_LEN] = {0};
473 	struct ath_hw *ah = spec_priv->ah;
474 	struct ath_common *common = ath9k_hw_common(spec_priv->ah);
475 	struct ath_softc *sc = common->priv;
476 	u8 num_bins, *vdata = (u8 *)hdr;
477 	struct ath_radar_info *radar_info;
478 	int len = rs->rs_datalen;
479 	int i;
480 	int got_slen = 0;
481 	u8  *sample_start;
482 	int sample_bytes = 0;
483 	int ret = 0;
484 	u16 fft_len, sample_len, freq = ah->curchan->chan->center_freq;
485 	enum nl80211_channel_type chan_type;
486 	ath_cmn_fft_idx_validator *fft_idx_validator;
487 	ath_cmn_fft_sample_handler *fft_handler;
488 
489 	/* AR9280 and before report via ATH9K_PHYERR_RADAR, AR93xx and newer
490 	 * via ATH9K_PHYERR_SPECTRAL. Haven't seen ATH9K_PHYERR_FALSE_RADAR_EXT
491 	 * yet, but this is supposed to be possible as well.
492 	 */
493 	if (rs->rs_phyerr != ATH9K_PHYERR_RADAR &&
494 	    rs->rs_phyerr != ATH9K_PHYERR_FALSE_RADAR_EXT &&
495 	    rs->rs_phyerr != ATH9K_PHYERR_SPECTRAL)
496 		return 0;
497 
498 	/* check if spectral scan bit is set. This does not have to be checked
499 	 * if received through a SPECTRAL phy error, but shouldn't hurt.
500 	 */
501 	radar_info = ((struct ath_radar_info *)&vdata[len]) - 1;
502 	if (!(radar_info->pulse_bw_info & SPECTRAL_SCAN_BITMASK))
503 		return 0;
504 
505 	if (!spec_priv->rfs_chan_spec_scan)
506 		return 1;
507 
508 	/* Output buffers are full, no need to process anything
509 	 * since there is no space to put the result anyway
510 	 */
511 	ret = ath_cmn_is_fft_buf_full(spec_priv);
512 	if (ret == 1) {
513 		ath_dbg(common, SPECTRAL_SCAN, "FFT report ignored, no space "
514 						"left on output buffers\n");
515 		return 1;
516 	}
517 
518 	chan_type = cfg80211_get_chandef_type(&common->hw->conf.chandef);
519 	if ((chan_type == NL80211_CHAN_HT40MINUS) ||
520 	    (chan_type == NL80211_CHAN_HT40PLUS)) {
521 		fft_len = SPECTRAL_HT20_40_TOTAL_DATA_LEN;
522 		sample_len = SPECTRAL_HT20_40_SAMPLE_LEN;
523 		num_bins = SPECTRAL_HT20_40_NUM_BINS;
524 		fft_idx_validator = &ath_cmn_max_idx_verify_ht20_40_fft;
525 		fft_handler = &ath_cmn_process_ht20_40_fft;
526 	} else {
527 		fft_len = SPECTRAL_HT20_TOTAL_DATA_LEN;
528 		sample_len = SPECTRAL_HT20_SAMPLE_LEN;
529 		num_bins = SPECTRAL_HT20_NUM_BINS;
530 		fft_idx_validator = ath_cmn_max_idx_verify_ht20_fft;
531 		fft_handler = &ath_cmn_process_ht20_fft;
532 	}
533 
534 	ath_dbg(common, SPECTRAL_SCAN, "Got radar dump bw_info: 0x%X,"
535 					"len: %i fft_len: %i\n",
536 					radar_info->pulse_bw_info,
537 					len,
538 					fft_len);
539 	sample_start = vdata;
540 	for (i = 0; i < len - 2; i++) {
541 		sample_bytes++;
542 
543 		/* Only a single sample received, no need to look
544 		 * for the sample's end, do the correction based
545 		 * on the packet's length instead. Note that hw
546 		 * will always put the radar_info structure on
547 		 * the end.
548 		 */
549 		if (len <= fft_len + 2) {
550 			sample_bytes = len - sizeof(struct ath_radar_info);
551 			got_slen = 1;
552 		}
553 
554 		/* Search for the end of the FFT frame between
555 		 * sample_len - 1 and sample_len + 2. exp_max is 3
556 		 * bits long and it's the only value on the last
557 		 * byte of the frame so since it'll be smaller than
558 		 * the next byte (the first bin of the next sample)
559 		 * 90% of the time, we can use it as a separator.
560 		 */
561 		if (vdata[i] <= 0x7 && sample_bytes >= sample_len - 1) {
562 
563 			/* Got a frame length within boundaries, there are
564 			 * four scenarios here:
565 			 *
566 			 * a) sample_len -> We got the correct length
567 			 * b) sample_len + 2 -> 2 bytes added around bin[31]
568 			 * c) sample_len - 1 -> The first byte is missing
569 			 * d) sample_len + 1 -> b + c at the same time
570 			 *
571 			 * When MAC adds 2 extra bytes, bin[31] and bin[32]
572 			 * have the same value, so we can use that for further
573 			 * verification in cases b and d.
574 			 */
575 
576 			/* Did we go too far ? If so we couldn't determine
577 			 * this sample's boundaries, discard any further
578 			 * data
579 			 */
580 			if ((sample_bytes > sample_len + 2) ||
581 			   ((sample_bytes > sample_len) &&
582 			   (sample_start[31] != sample_start[32])))
583 				break;
584 
585 			/* See if we got a valid frame by checking the
586 			 * consistency of mag_info fields. This is to
587 			 * prevent from "fixing" a correct frame.
588 			 * Failure is non-fatal, later frames may
589 			 * be valid.
590 			 */
591 			if (!fft_idx_validator(&vdata[i], i)) {
592 				ath_dbg(common, SPECTRAL_SCAN,
593 					"Found valid fft frame at %i\n", i);
594 				got_slen = 1;
595 			}
596 
597 			/* We expect 1 - 2 more bytes */
598 			else if ((sample_start[31] == sample_start[32]) &&
599 				(sample_bytes >= sample_len) &&
600 				(sample_bytes < sample_len + 2) &&
601 				(vdata[i + 1] <= 0x7))
602 				continue;
603 
604 			/* Try to distinguish cases a and c */
605 			else if ((sample_bytes == sample_len - 1) &&
606 				(vdata[i + 1] <= 0x7))
607 				continue;
608 
609 			got_slen = 1;
610 		}
611 
612 		if (got_slen) {
613 			ath_dbg(common, SPECTRAL_SCAN, "FFT frame len: %i\n",
614 				sample_bytes);
615 
616 			/* Only try to fix a frame if it's the only one
617 			 * on the report, else just skip it.
618 			 */
619 			if (sample_bytes != sample_len && len <= fft_len + 2) {
620 				ath_cmn_copy_fft_frame(sample_start,
621 						       sample_buf, sample_len,
622 						       sample_bytes);
623 
624 				ret = fft_handler(rs, spec_priv, sample_buf,
625 						  tsf, freq, chan_type);
626 
627 				if (ret == 0)
628 					RX_STAT_INC(sc, rx_spectral_sample_good);
629 				else
630 					RX_STAT_INC(sc, rx_spectral_sample_err);
631 
632 				/* Mix the received bins to the /dev/random
633 				 * pool
634 				 */
635 				add_device_randomness(sample_buf, num_bins);
636 
637 				memset(sample_buf, 0, SPECTRAL_SAMPLE_MAX_LEN);
638 			}
639 
640 			/* Process a normal frame */
641 			if (sample_bytes == sample_len) {
642 				ret = fft_handler(rs, spec_priv, sample_start,
643 						  tsf, freq, chan_type);
644 
645 				if (ret == 0)
646 					RX_STAT_INC(sc, rx_spectral_sample_good);
647 				else
648 					RX_STAT_INC(sc, rx_spectral_sample_err);
649 
650 				/* Mix the received bins to the /dev/random
651 				 * pool
652 				 */
653 				add_device_randomness(sample_start, num_bins);
654 			}
655 
656 			/* Short report processed, break out of the
657 			 * loop.
658 			 */
659 			if (len <= fft_len + 2)
660 				return 1;
661 
662 			sample_start = &vdata[i + 1];
663 
664 			/* -1 to grab sample_len -1, -2 since
665 			 * they 'll get increased by one. In case
666 			 * of failure try to recover by going byte
667 			 * by byte instead.
668 			 */
669 			if (ret == 0) {
670 				i += num_bins - 2;
671 				sample_bytes = num_bins - 2;
672 			}
673 			got_slen = 0;
674 		}
675 	}
676 
677 	i -= num_bins - 2;
678 	if (len - i != sizeof(struct ath_radar_info))
679 		ath_dbg(common, SPECTRAL_SCAN, "FFT report truncated"
680 						"(bytes left: %i)\n",
681 						len - i);
682 	return 1;
683 }
684 EXPORT_SYMBOL(ath_cmn_process_fft);
685 
686 /*********************/
687 /* spectral_scan_ctl */
688 /*********************/
689 
read_file_spec_scan_ctl(struct file * file,char __user * user_buf,size_t count,loff_t * ppos)690 static ssize_t read_file_spec_scan_ctl(struct file *file, char __user *user_buf,
691 				       size_t count, loff_t *ppos)
692 {
693 	struct ath_spec_scan_priv *spec_priv = file->private_data;
694 	char *mode = "";
695 	unsigned int len;
696 
697 	switch (spec_priv->spectral_mode) {
698 	case SPECTRAL_DISABLED:
699 		mode = "disable";
700 		break;
701 	case SPECTRAL_BACKGROUND:
702 		mode = "background";
703 		break;
704 	case SPECTRAL_CHANSCAN:
705 		mode = "chanscan";
706 		break;
707 	case SPECTRAL_MANUAL:
708 		mode = "manual";
709 		break;
710 	}
711 	len = strlen(mode);
712 	return simple_read_from_buffer(user_buf, count, ppos, mode, len);
713 }
714 
ath9k_cmn_spectral_scan_trigger(struct ath_common * common,struct ath_spec_scan_priv * spec_priv)715 void ath9k_cmn_spectral_scan_trigger(struct ath_common *common,
716 				 struct ath_spec_scan_priv *spec_priv)
717 {
718 	struct ath_hw *ah = spec_priv->ah;
719 	u32 rxfilter;
720 
721 	if (IS_ENABLED(CONFIG_ATH9K_TX99))
722 		return;
723 
724 	if (!ath9k_hw_ops(ah)->spectral_scan_trigger) {
725 		ath_err(common, "spectrum analyzer not implemented on this hardware\n");
726 		return;
727 	}
728 
729 	if (!spec_priv->spec_config.enabled)
730 		return;
731 
732 	ath_ps_ops(common)->wakeup(common);
733 	rxfilter = ath9k_hw_getrxfilter(ah);
734 	ath9k_hw_setrxfilter(ah, rxfilter |
735 				 ATH9K_RX_FILTER_PHYRADAR |
736 				 ATH9K_RX_FILTER_PHYERR);
737 
738 	/* TODO: usually this should not be necessary, but for some reason
739 	 * (or in some mode?) the trigger must be called after the
740 	 * configuration, otherwise the register will have its values reset
741 	 * (on my ar9220 to value 0x01002310)
742 	 */
743 	ath9k_cmn_spectral_scan_config(common, spec_priv, spec_priv->spectral_mode);
744 	ath9k_hw_ops(ah)->spectral_scan_trigger(ah);
745 	ath_ps_ops(common)->restore(common);
746 }
747 EXPORT_SYMBOL(ath9k_cmn_spectral_scan_trigger);
748 
ath9k_cmn_spectral_scan_config(struct ath_common * common,struct ath_spec_scan_priv * spec_priv,enum spectral_mode spectral_mode)749 int ath9k_cmn_spectral_scan_config(struct ath_common *common,
750 			       struct ath_spec_scan_priv *spec_priv,
751 			       enum spectral_mode spectral_mode)
752 {
753 	struct ath_hw *ah = spec_priv->ah;
754 
755 	if (!ath9k_hw_ops(ah)->spectral_scan_trigger) {
756 		ath_err(common, "spectrum analyzer not implemented on this hardware\n");
757 		return -1;
758 	}
759 
760 	switch (spectral_mode) {
761 	case SPECTRAL_DISABLED:
762 		spec_priv->spec_config.enabled = 0;
763 		break;
764 	case SPECTRAL_BACKGROUND:
765 		/* send endless samples.
766 		 * TODO: is this really useful for "background"?
767 		 */
768 		spec_priv->spec_config.endless = 1;
769 		spec_priv->spec_config.enabled = 1;
770 		break;
771 	case SPECTRAL_CHANSCAN:
772 	case SPECTRAL_MANUAL:
773 		spec_priv->spec_config.endless = 0;
774 		spec_priv->spec_config.enabled = 1;
775 		break;
776 	default:
777 		return -1;
778 	}
779 
780 	ath_ps_ops(common)->wakeup(common);
781 	ath9k_hw_ops(ah)->spectral_scan_config(ah, &spec_priv->spec_config);
782 	ath_ps_ops(common)->restore(common);
783 
784 	spec_priv->spectral_mode = spectral_mode;
785 
786 	return 0;
787 }
788 EXPORT_SYMBOL(ath9k_cmn_spectral_scan_config);
789 
write_file_spec_scan_ctl(struct file * file,const char __user * user_buf,size_t count,loff_t * ppos)790 static ssize_t write_file_spec_scan_ctl(struct file *file,
791 					const char __user *user_buf,
792 					size_t count, loff_t *ppos)
793 {
794 	struct ath_spec_scan_priv *spec_priv = file->private_data;
795 	struct ath_common *common = ath9k_hw_common(spec_priv->ah);
796 	char buf[32];
797 	ssize_t len;
798 
799 	if (IS_ENABLED(CONFIG_ATH9K_TX99))
800 		return -EOPNOTSUPP;
801 
802 	len = min(count, sizeof(buf) - 1);
803 	if (copy_from_user(buf, user_buf, len))
804 		return -EFAULT;
805 
806 	buf[len] = '\0';
807 
808 	if (strncmp("trigger", buf, 7) == 0) {
809 		ath9k_cmn_spectral_scan_trigger(common, spec_priv);
810 	} else if (strncmp("background", buf, 10) == 0) {
811 		ath9k_cmn_spectral_scan_config(common, spec_priv, SPECTRAL_BACKGROUND);
812 		ath_dbg(common, CONFIG, "spectral scan: background mode enabled\n");
813 	} else if (strncmp("chanscan", buf, 8) == 0) {
814 		ath9k_cmn_spectral_scan_config(common, spec_priv, SPECTRAL_CHANSCAN);
815 		ath_dbg(common, CONFIG, "spectral scan: channel scan mode enabled\n");
816 	} else if (strncmp("manual", buf, 6) == 0) {
817 		ath9k_cmn_spectral_scan_config(common, spec_priv, SPECTRAL_MANUAL);
818 		ath_dbg(common, CONFIG, "spectral scan: manual mode enabled\n");
819 	} else if (strncmp("disable", buf, 7) == 0) {
820 		ath9k_cmn_spectral_scan_config(common, spec_priv, SPECTRAL_DISABLED);
821 		ath_dbg(common, CONFIG, "spectral scan: disabled\n");
822 	} else {
823 		return -EINVAL;
824 	}
825 
826 	return count;
827 }
828 
829 static const struct file_operations fops_spec_scan_ctl = {
830 	.read = read_file_spec_scan_ctl,
831 	.write = write_file_spec_scan_ctl,
832 	.open = simple_open,
833 	.owner = THIS_MODULE,
834 	.llseek = default_llseek,
835 };
836 
837 /*************************/
838 /* spectral_short_repeat */
839 /*************************/
840 
read_file_spectral_short_repeat(struct file * file,char __user * user_buf,size_t count,loff_t * ppos)841 static ssize_t read_file_spectral_short_repeat(struct file *file,
842 					       char __user *user_buf,
843 					       size_t count, loff_t *ppos)
844 {
845 	struct ath_spec_scan_priv *spec_priv = file->private_data;
846 	char buf[32];
847 	unsigned int len;
848 
849 	len = sprintf(buf, "%d\n", spec_priv->spec_config.short_repeat);
850 	return simple_read_from_buffer(user_buf, count, ppos, buf, len);
851 }
852 
write_file_spectral_short_repeat(struct file * file,const char __user * user_buf,size_t count,loff_t * ppos)853 static ssize_t write_file_spectral_short_repeat(struct file *file,
854 						const char __user *user_buf,
855 						size_t count, loff_t *ppos)
856 {
857 	struct ath_spec_scan_priv *spec_priv = file->private_data;
858 	unsigned long val;
859 	ssize_t ret;
860 
861 	ret = kstrtoul_from_user(user_buf, count, 0, &val);
862 	if (ret)
863 		return ret;
864 
865 	if (val > 1)
866 		return -EINVAL;
867 
868 	spec_priv->spec_config.short_repeat = val;
869 	return count;
870 }
871 
872 static const struct file_operations fops_spectral_short_repeat = {
873 	.read = read_file_spectral_short_repeat,
874 	.write = write_file_spectral_short_repeat,
875 	.open = simple_open,
876 	.owner = THIS_MODULE,
877 	.llseek = default_llseek,
878 };
879 
880 /******************/
881 /* spectral_count */
882 /******************/
883 
read_file_spectral_count(struct file * file,char __user * user_buf,size_t count,loff_t * ppos)884 static ssize_t read_file_spectral_count(struct file *file,
885 					char __user *user_buf,
886 					size_t count, loff_t *ppos)
887 {
888 	struct ath_spec_scan_priv *spec_priv = file->private_data;
889 	char buf[32];
890 	unsigned int len;
891 
892 	len = sprintf(buf, "%d\n", spec_priv->spec_config.count);
893 	return simple_read_from_buffer(user_buf, count, ppos, buf, len);
894 }
895 
write_file_spectral_count(struct file * file,const char __user * user_buf,size_t count,loff_t * ppos)896 static ssize_t write_file_spectral_count(struct file *file,
897 					 const char __user *user_buf,
898 					 size_t count, loff_t *ppos)
899 {
900 	struct ath_spec_scan_priv *spec_priv = file->private_data;
901 	unsigned long val;
902 	ssize_t ret;
903 
904 	ret = kstrtoul_from_user(user_buf, count, 0, &val);
905 	if (ret)
906 		return ret;
907 	if (val > 255)
908 		return -EINVAL;
909 
910 	spec_priv->spec_config.count = val;
911 	return count;
912 }
913 
914 static const struct file_operations fops_spectral_count = {
915 	.read = read_file_spectral_count,
916 	.write = write_file_spectral_count,
917 	.open = simple_open,
918 	.owner = THIS_MODULE,
919 	.llseek = default_llseek,
920 };
921 
922 /*******************/
923 /* spectral_period */
924 /*******************/
925 
read_file_spectral_period(struct file * file,char __user * user_buf,size_t count,loff_t * ppos)926 static ssize_t read_file_spectral_period(struct file *file,
927 					 char __user *user_buf,
928 					 size_t count, loff_t *ppos)
929 {
930 	struct ath_spec_scan_priv *spec_priv = file->private_data;
931 	char buf[32];
932 	unsigned int len;
933 
934 	len = sprintf(buf, "%d\n", spec_priv->spec_config.period);
935 	return simple_read_from_buffer(user_buf, count, ppos, buf, len);
936 }
937 
write_file_spectral_period(struct file * file,const char __user * user_buf,size_t count,loff_t * ppos)938 static ssize_t write_file_spectral_period(struct file *file,
939 					  const char __user *user_buf,
940 					  size_t count, loff_t *ppos)
941 {
942 	struct ath_spec_scan_priv *spec_priv = file->private_data;
943 	unsigned long val;
944 	ssize_t ret;
945 
946 	ret = kstrtoul_from_user(user_buf, count, 0, &val);
947 	if (ret)
948 		return ret;
949 
950 	if (val > 255)
951 		return -EINVAL;
952 
953 	spec_priv->spec_config.period = val;
954 	return count;
955 }
956 
957 static const struct file_operations fops_spectral_period = {
958 	.read = read_file_spectral_period,
959 	.write = write_file_spectral_period,
960 	.open = simple_open,
961 	.owner = THIS_MODULE,
962 	.llseek = default_llseek,
963 };
964 
965 /***********************/
966 /* spectral_fft_period */
967 /***********************/
968 
read_file_spectral_fft_period(struct file * file,char __user * user_buf,size_t count,loff_t * ppos)969 static ssize_t read_file_spectral_fft_period(struct file *file,
970 					     char __user *user_buf,
971 					     size_t count, loff_t *ppos)
972 {
973 	struct ath_spec_scan_priv *spec_priv = file->private_data;
974 	char buf[32];
975 	unsigned int len;
976 
977 	len = sprintf(buf, "%d\n", spec_priv->spec_config.fft_period);
978 	return simple_read_from_buffer(user_buf, count, ppos, buf, len);
979 }
980 
write_file_spectral_fft_period(struct file * file,const char __user * user_buf,size_t count,loff_t * ppos)981 static ssize_t write_file_spectral_fft_period(struct file *file,
982 					      const char __user *user_buf,
983 					      size_t count, loff_t *ppos)
984 {
985 	struct ath_spec_scan_priv *spec_priv = file->private_data;
986 	unsigned long val;
987 	ssize_t ret;
988 
989 	ret = kstrtoul_from_user(user_buf, count, 0, &val);
990 	if (ret)
991 		return ret;
992 
993 	if (val > 15)
994 		return -EINVAL;
995 
996 	spec_priv->spec_config.fft_period = val;
997 	return count;
998 }
999 
1000 static const struct file_operations fops_spectral_fft_period = {
1001 	.read = read_file_spectral_fft_period,
1002 	.write = write_file_spectral_fft_period,
1003 	.open = simple_open,
1004 	.owner = THIS_MODULE,
1005 	.llseek = default_llseek,
1006 };
1007 
1008 /*******************/
1009 /* Relay interface */
1010 /*******************/
1011 
create_buf_file_handler(const char * filename,struct dentry * parent,umode_t mode,struct rchan_buf * buf,int * is_global)1012 static struct dentry *create_buf_file_handler(const char *filename,
1013 					      struct dentry *parent,
1014 					      umode_t mode,
1015 					      struct rchan_buf *buf,
1016 					      int *is_global)
1017 {
1018 	struct dentry *buf_file;
1019 
1020 	buf_file = debugfs_create_file(filename, mode, parent, buf,
1021 				       &relay_file_operations);
1022 	if (IS_ERR(buf_file))
1023 		return NULL;
1024 
1025 	*is_global = 1;
1026 	return buf_file;
1027 }
1028 
remove_buf_file_handler(struct dentry * dentry)1029 static int remove_buf_file_handler(struct dentry *dentry)
1030 {
1031 	debugfs_remove(dentry);
1032 
1033 	return 0;
1034 }
1035 
1036 static const struct rchan_callbacks rfs_spec_scan_cb = {
1037 	.create_buf_file = create_buf_file_handler,
1038 	.remove_buf_file = remove_buf_file_handler,
1039 };
1040 
1041 /*********************/
1042 /* Debug Init/Deinit */
1043 /*********************/
1044 
ath9k_cmn_spectral_deinit_debug(struct ath_spec_scan_priv * spec_priv)1045 void ath9k_cmn_spectral_deinit_debug(struct ath_spec_scan_priv *spec_priv)
1046 {
1047 	if (spec_priv->rfs_chan_spec_scan) {
1048 		relay_close(spec_priv->rfs_chan_spec_scan);
1049 		spec_priv->rfs_chan_spec_scan = NULL;
1050 	}
1051 }
1052 EXPORT_SYMBOL(ath9k_cmn_spectral_deinit_debug);
1053 
ath9k_cmn_spectral_init_debug(struct ath_spec_scan_priv * spec_priv,struct dentry * debugfs_phy)1054 void ath9k_cmn_spectral_init_debug(struct ath_spec_scan_priv *spec_priv,
1055 				   struct dentry *debugfs_phy)
1056 {
1057 	spec_priv->rfs_chan_spec_scan = relay_open("spectral_scan",
1058 					    debugfs_phy,
1059 					    1024, 256, &rfs_spec_scan_cb,
1060 					    NULL);
1061 	if (!spec_priv->rfs_chan_spec_scan)
1062 		return;
1063 
1064 	debugfs_create_file("spectral_scan_ctl",
1065 			    0600,
1066 			    debugfs_phy, spec_priv,
1067 			    &fops_spec_scan_ctl);
1068 	debugfs_create_file("spectral_short_repeat",
1069 			    0600,
1070 			    debugfs_phy, spec_priv,
1071 			    &fops_spectral_short_repeat);
1072 	debugfs_create_file("spectral_count",
1073 			    0600,
1074 			    debugfs_phy, spec_priv,
1075 			    &fops_spectral_count);
1076 	debugfs_create_file("spectral_period",
1077 			    0600,
1078 			    debugfs_phy, spec_priv,
1079 			    &fops_spectral_period);
1080 	debugfs_create_file("spectral_fft_period",
1081 			    0600,
1082 			    debugfs_phy, spec_priv,
1083 			    &fops_spectral_fft_period);
1084 }
1085 EXPORT_SYMBOL(ath9k_cmn_spectral_init_debug);
1086