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