cachepc-linux

Fork of AMDESE/linux with modifications for CachePC side-channel attack
git clone https://git.sinitax.com/sinitax/cachepc-linux
Log | Files | Refs | README | LICENSE | sfeed.txt

common-spectral.c (30537B)


      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 = (struct ath_softc *)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	char buf[32];
    859	ssize_t len;
    860
    861	len = min(count, sizeof(buf) - 1);
    862	if (copy_from_user(buf, user_buf, len))
    863		return -EFAULT;
    864
    865	buf[len] = '\0';
    866	if (kstrtoul(buf, 0, &val))
    867		return -EINVAL;
    868
    869	if (val > 1)
    870		return -EINVAL;
    871
    872	spec_priv->spec_config.short_repeat = val;
    873	return count;
    874}
    875
    876static const struct file_operations fops_spectral_short_repeat = {
    877	.read = read_file_spectral_short_repeat,
    878	.write = write_file_spectral_short_repeat,
    879	.open = simple_open,
    880	.owner = THIS_MODULE,
    881	.llseek = default_llseek,
    882};
    883
    884/******************/
    885/* spectral_count */
    886/******************/
    887
    888static ssize_t read_file_spectral_count(struct file *file,
    889					char __user *user_buf,
    890					size_t count, loff_t *ppos)
    891{
    892	struct ath_spec_scan_priv *spec_priv = file->private_data;
    893	char buf[32];
    894	unsigned int len;
    895
    896	len = sprintf(buf, "%d\n", spec_priv->spec_config.count);
    897	return simple_read_from_buffer(user_buf, count, ppos, buf, len);
    898}
    899
    900static ssize_t write_file_spectral_count(struct file *file,
    901					 const char __user *user_buf,
    902					 size_t count, loff_t *ppos)
    903{
    904	struct ath_spec_scan_priv *spec_priv = file->private_data;
    905	unsigned long val;
    906	char buf[32];
    907	ssize_t len;
    908
    909	len = min(count, sizeof(buf) - 1);
    910	if (copy_from_user(buf, user_buf, len))
    911		return -EFAULT;
    912
    913	buf[len] = '\0';
    914	if (kstrtoul(buf, 0, &val))
    915		return -EINVAL;
    916
    917	if (val > 255)
    918		return -EINVAL;
    919
    920	spec_priv->spec_config.count = val;
    921	return count;
    922}
    923
    924static const struct file_operations fops_spectral_count = {
    925	.read = read_file_spectral_count,
    926	.write = write_file_spectral_count,
    927	.open = simple_open,
    928	.owner = THIS_MODULE,
    929	.llseek = default_llseek,
    930};
    931
    932/*******************/
    933/* spectral_period */
    934/*******************/
    935
    936static ssize_t read_file_spectral_period(struct file *file,
    937					 char __user *user_buf,
    938					 size_t count, loff_t *ppos)
    939{
    940	struct ath_spec_scan_priv *spec_priv = file->private_data;
    941	char buf[32];
    942	unsigned int len;
    943
    944	len = sprintf(buf, "%d\n", spec_priv->spec_config.period);
    945	return simple_read_from_buffer(user_buf, count, ppos, buf, len);
    946}
    947
    948static ssize_t write_file_spectral_period(struct file *file,
    949					  const char __user *user_buf,
    950					  size_t count, loff_t *ppos)
    951{
    952	struct ath_spec_scan_priv *spec_priv = file->private_data;
    953	unsigned long val;
    954	char buf[32];
    955	ssize_t len;
    956
    957	len = min(count, sizeof(buf) - 1);
    958	if (copy_from_user(buf, user_buf, len))
    959		return -EFAULT;
    960
    961	buf[len] = '\0';
    962	if (kstrtoul(buf, 0, &val))
    963		return -EINVAL;
    964
    965	if (val > 255)
    966		return -EINVAL;
    967
    968	spec_priv->spec_config.period = val;
    969	return count;
    970}
    971
    972static const struct file_operations fops_spectral_period = {
    973	.read = read_file_spectral_period,
    974	.write = write_file_spectral_period,
    975	.open = simple_open,
    976	.owner = THIS_MODULE,
    977	.llseek = default_llseek,
    978};
    979
    980/***********************/
    981/* spectral_fft_period */
    982/***********************/
    983
    984static ssize_t read_file_spectral_fft_period(struct file *file,
    985					     char __user *user_buf,
    986					     size_t count, loff_t *ppos)
    987{
    988	struct ath_spec_scan_priv *spec_priv = file->private_data;
    989	char buf[32];
    990	unsigned int len;
    991
    992	len = sprintf(buf, "%d\n", spec_priv->spec_config.fft_period);
    993	return simple_read_from_buffer(user_buf, count, ppos, buf, len);
    994}
    995
    996static ssize_t write_file_spectral_fft_period(struct file *file,
    997					      const char __user *user_buf,
    998					      size_t count, loff_t *ppos)
    999{
   1000	struct ath_spec_scan_priv *spec_priv = file->private_data;
   1001	unsigned long val;
   1002	char buf[32];
   1003	ssize_t len;
   1004
   1005	len = min(count, sizeof(buf) - 1);
   1006	if (copy_from_user(buf, user_buf, len))
   1007		return -EFAULT;
   1008
   1009	buf[len] = '\0';
   1010	if (kstrtoul(buf, 0, &val))
   1011		return -EINVAL;
   1012
   1013	if (val > 15)
   1014		return -EINVAL;
   1015
   1016	spec_priv->spec_config.fft_period = val;
   1017	return count;
   1018}
   1019
   1020static const struct file_operations fops_spectral_fft_period = {
   1021	.read = read_file_spectral_fft_period,
   1022	.write = write_file_spectral_fft_period,
   1023	.open = simple_open,
   1024	.owner = THIS_MODULE,
   1025	.llseek = default_llseek,
   1026};
   1027
   1028/*******************/
   1029/* Relay interface */
   1030/*******************/
   1031
   1032static struct dentry *create_buf_file_handler(const char *filename,
   1033					      struct dentry *parent,
   1034					      umode_t mode,
   1035					      struct rchan_buf *buf,
   1036					      int *is_global)
   1037{
   1038	struct dentry *buf_file;
   1039
   1040	buf_file = debugfs_create_file(filename, mode, parent, buf,
   1041				       &relay_file_operations);
   1042	if (IS_ERR(buf_file))
   1043		return NULL;
   1044
   1045	*is_global = 1;
   1046	return buf_file;
   1047}
   1048
   1049static int remove_buf_file_handler(struct dentry *dentry)
   1050{
   1051	debugfs_remove(dentry);
   1052
   1053	return 0;
   1054}
   1055
   1056static const struct rchan_callbacks rfs_spec_scan_cb = {
   1057	.create_buf_file = create_buf_file_handler,
   1058	.remove_buf_file = remove_buf_file_handler,
   1059};
   1060
   1061/*********************/
   1062/* Debug Init/Deinit */
   1063/*********************/
   1064
   1065void ath9k_cmn_spectral_deinit_debug(struct ath_spec_scan_priv *spec_priv)
   1066{
   1067	if (spec_priv->rfs_chan_spec_scan) {
   1068		relay_close(spec_priv->rfs_chan_spec_scan);
   1069		spec_priv->rfs_chan_spec_scan = NULL;
   1070	}
   1071}
   1072EXPORT_SYMBOL(ath9k_cmn_spectral_deinit_debug);
   1073
   1074void ath9k_cmn_spectral_init_debug(struct ath_spec_scan_priv *spec_priv,
   1075				   struct dentry *debugfs_phy)
   1076{
   1077	spec_priv->rfs_chan_spec_scan = relay_open("spectral_scan",
   1078					    debugfs_phy,
   1079					    1024, 256, &rfs_spec_scan_cb,
   1080					    NULL);
   1081	if (!spec_priv->rfs_chan_spec_scan)
   1082		return;
   1083
   1084	debugfs_create_file("spectral_scan_ctl",
   1085			    0600,
   1086			    debugfs_phy, spec_priv,
   1087			    &fops_spec_scan_ctl);
   1088	debugfs_create_file("spectral_short_repeat",
   1089			    0600,
   1090			    debugfs_phy, spec_priv,
   1091			    &fops_spectral_short_repeat);
   1092	debugfs_create_file("spectral_count",
   1093			    0600,
   1094			    debugfs_phy, spec_priv,
   1095			    &fops_spectral_count);
   1096	debugfs_create_file("spectral_period",
   1097			    0600,
   1098			    debugfs_phy, spec_priv,
   1099			    &fops_spectral_period);
   1100	debugfs_create_file("spectral_fft_period",
   1101			    0600,
   1102			    debugfs_phy, spec_priv,
   1103			    &fops_spectral_fft_period);
   1104}
   1105EXPORT_SYMBOL(ath9k_cmn_spectral_init_debug);