Back to home page

OSCL-LXR

 
 

    


0001 /*
0002  * Copyright (c) 2013 Qualcomm Atheros, Inc.
0003  *
0004  * Permission to use, copy, modify, and/or distribute this software for any
0005  * purpose with or without fee is hereby granted, provided that the above
0006  * copyright notice and this permission notice appear in all copies.
0007  *
0008  * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
0009  * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
0010  * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
0011  * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
0012  * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
0013  * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
0014  * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
0015  */
0016 
0017 #include <linux/relay.h>
0018 #include <linux/random.h>
0019 #include "ath9k.h"
0020 
0021 static s8 fix_rssi_inv_only(u8 rssi_val)
0022 {
0023     if (rssi_val == 128)
0024         rssi_val = 0;
0025     return (s8) rssi_val;
0026 }
0027 
0028 static void ath_debug_send_fft_sample(struct ath_spec_scan_priv *spec_priv,
0029                       struct fft_sample_tlv *fft_sample_tlv)
0030 {
0031     int length;
0032     if (!spec_priv->rfs_chan_spec_scan)
0033         return;
0034 
0035     length = __be16_to_cpu(fft_sample_tlv->length) +
0036          sizeof(*fft_sample_tlv);
0037     relay_write(spec_priv->rfs_chan_spec_scan, fft_sample_tlv, length);
0038 }
0039 
0040 typedef int (ath_cmn_fft_idx_validator) (u8 *sample_end, int bytes_read);
0041 
0042 static int
0043 ath_cmn_max_idx_verify_ht20_fft(u8 *sample_end, int bytes_read)
0044 {
0045     struct ath_ht20_mag_info *mag_info;
0046     u8 *sample;
0047     u16 max_magnitude;
0048     u8 max_index;
0049     u8 max_exp;
0050 
0051     /* Sanity check so that we don't read outside the read
0052      * buffer
0053      */
0054     if (bytes_read < SPECTRAL_HT20_SAMPLE_LEN - 1)
0055         return -1;
0056 
0057     mag_info = (struct ath_ht20_mag_info *) (sample_end -
0058                 sizeof(struct ath_ht20_mag_info) + 1);
0059 
0060     sample = sample_end - SPECTRAL_HT20_SAMPLE_LEN + 1;
0061 
0062     max_index = spectral_max_index_ht20(mag_info->all_bins);
0063     max_magnitude = spectral_max_magnitude(mag_info->all_bins);
0064 
0065     max_exp = mag_info->max_exp & 0xf;
0066 
0067     /* Don't try to read something outside the read buffer
0068      * in case of a missing byte (so bins[0] will be outside
0069      * the read buffer)
0070      */
0071     if (bytes_read < SPECTRAL_HT20_SAMPLE_LEN && max_index < 1)
0072         return -1;
0073 
0074     if ((sample[max_index] & 0xf8) != ((max_magnitude >> max_exp) & 0xf8))
0075         return -1;
0076     else
0077         return 0;
0078 }
0079 
0080 static int
0081 ath_cmn_max_idx_verify_ht20_40_fft(u8 *sample_end, int bytes_read)
0082 {
0083     struct ath_ht20_40_mag_info *mag_info;
0084     u8 *sample;
0085     u16 lower_mag, upper_mag;
0086     u8 lower_max_index, upper_max_index;
0087     u8 max_exp;
0088     int dc_pos = SPECTRAL_HT20_40_NUM_BINS / 2;
0089 
0090     /* Sanity check so that we don't read outside the read
0091      * buffer
0092      */
0093     if (bytes_read < SPECTRAL_HT20_40_SAMPLE_LEN - 1)
0094         return -1;
0095 
0096     mag_info = (struct ath_ht20_40_mag_info *) (sample_end -
0097                 sizeof(struct ath_ht20_40_mag_info) + 1);
0098 
0099     sample = sample_end - SPECTRAL_HT20_40_SAMPLE_LEN + 1;
0100 
0101     lower_mag = spectral_max_magnitude(mag_info->lower_bins);
0102     lower_max_index = spectral_max_index_ht40(mag_info->lower_bins);
0103 
0104     upper_mag = spectral_max_magnitude(mag_info->upper_bins);
0105     upper_max_index = spectral_max_index_ht40(mag_info->upper_bins);
0106 
0107     max_exp = mag_info->max_exp & 0xf;
0108 
0109     /* Don't try to read something outside the read buffer
0110      * in case of a missing byte (so bins[0] will be outside
0111      * the read buffer)
0112      */
0113     if (bytes_read < SPECTRAL_HT20_40_SAMPLE_LEN &&
0114        ((upper_max_index < 1) || (lower_max_index < 1)))
0115         return -1;
0116 
0117     if (((sample[upper_max_index + dc_pos] & 0xf8) !=
0118          ((upper_mag >> max_exp) & 0xf8)) ||
0119         ((sample[lower_max_index] & 0xf8) !=
0120          ((lower_mag >> max_exp) & 0xf8)))
0121         return -1;
0122     else
0123         return 0;
0124 }
0125 
0126 typedef int (ath_cmn_fft_sample_handler) (struct ath_rx_status *rs,
0127             struct ath_spec_scan_priv *spec_priv,
0128             u8 *sample_buf, u64 tsf, u16 freq, int chan_type);
0129 
0130 static int
0131 ath_cmn_process_ht20_fft(struct ath_rx_status *rs,
0132             struct ath_spec_scan_priv *spec_priv,
0133             u8 *sample_buf,
0134             u64 tsf, u16 freq, int chan_type)
0135 {
0136     struct fft_sample_ht20 fft_sample_20;
0137     struct ath_common *common = ath9k_hw_common(spec_priv->ah);
0138     struct ath_hw *ah = spec_priv->ah;
0139     struct ath_ht20_mag_info *mag_info;
0140     struct fft_sample_tlv *tlv;
0141     int i = 0;
0142     int ret = 0;
0143     int dc_pos = SPECTRAL_HT20_NUM_BINS / 2;
0144     u16 magnitude, tmp_mag, length;
0145     u8 max_index, bitmap_w, max_exp;
0146 
0147     length = sizeof(fft_sample_20) - sizeof(struct fft_sample_tlv);
0148     fft_sample_20.tlv.type = ATH_FFT_SAMPLE_HT20;
0149     fft_sample_20.tlv.length = __cpu_to_be16(length);
0150     fft_sample_20.freq = __cpu_to_be16(freq);
0151     fft_sample_20.rssi = fix_rssi_inv_only(rs->rs_rssi_ctl[0]);
0152     fft_sample_20.noise = ah->noise;
0153 
0154     mag_info = (struct ath_ht20_mag_info *) (sample_buf +
0155                     SPECTRAL_HT20_NUM_BINS);
0156 
0157     magnitude = spectral_max_magnitude(mag_info->all_bins);
0158     fft_sample_20.max_magnitude = __cpu_to_be16(magnitude);
0159 
0160     max_index = spectral_max_index_ht20(mag_info->all_bins);
0161     fft_sample_20.max_index = max_index;
0162 
0163     bitmap_w = spectral_bitmap_weight(mag_info->all_bins);
0164     fft_sample_20.bitmap_weight = bitmap_w;
0165 
0166     max_exp = mag_info->max_exp & 0xf;
0167     fft_sample_20.max_exp = max_exp;
0168 
0169     fft_sample_20.tsf = __cpu_to_be64(tsf);
0170 
0171     memcpy(fft_sample_20.data, sample_buf, SPECTRAL_HT20_NUM_BINS);
0172 
0173     ath_dbg(common, SPECTRAL_SCAN, "FFT HT20 frame: max mag 0x%X,"
0174                     "max_mag_idx %i\n",
0175                     magnitude >> max_exp,
0176                     max_index);
0177 
0178     if ((fft_sample_20.data[max_index] & 0xf8) !=
0179         ((magnitude >> max_exp) & 0xf8)) {
0180         ath_dbg(common, SPECTRAL_SCAN, "Magnitude mismatch !\n");
0181         ret = -1;
0182     }
0183 
0184     /* DC value (value in the middle) is the blind spot of the spectral
0185      * sample and invalid, interpolate it.
0186      */
0187     fft_sample_20.data[dc_pos] = (fft_sample_20.data[dc_pos + 1] +
0188                     fft_sample_20.data[dc_pos - 1]) / 2;
0189 
0190     /* Check if the maximum magnitude is indeed maximum,
0191      * also if the maximum value was at dc_pos, calculate
0192      * a new one (since value at dc_pos is invalid).
0193      */
0194     if (max_index == dc_pos) {
0195         tmp_mag = 0;
0196         for (i = 0; i < dc_pos; i++) {
0197             if (fft_sample_20.data[i] > tmp_mag) {
0198                 tmp_mag = fft_sample_20.data[i];
0199                 fft_sample_20.max_index = i;
0200             }
0201         }
0202 
0203         magnitude = tmp_mag << max_exp;
0204         fft_sample_20.max_magnitude = __cpu_to_be16(magnitude);
0205 
0206         ath_dbg(common, SPECTRAL_SCAN,
0207             "Calculated new lower max 0x%X at %i\n",
0208             tmp_mag, fft_sample_20.max_index);
0209     } else
0210     for (i = 0; i < SPECTRAL_HT20_NUM_BINS; i++) {
0211         if (fft_sample_20.data[i] == (magnitude >> max_exp))
0212             ath_dbg(common, SPECTRAL_SCAN,
0213                 "Got max: 0x%X at index %i\n",
0214                 fft_sample_20.data[i], i);
0215 
0216         if (fft_sample_20.data[i] > (magnitude >> max_exp)) {
0217             ath_dbg(common, SPECTRAL_SCAN,
0218                 "Got bin %i greater than max: 0x%X\n",
0219                 i, fft_sample_20.data[i]);
0220             ret = -1;
0221         }
0222     }
0223 
0224     if (ret < 0)
0225         return ret;
0226 
0227     tlv = (struct fft_sample_tlv *)&fft_sample_20;
0228 
0229     ath_debug_send_fft_sample(spec_priv, tlv);
0230 
0231     return 0;
0232 }
0233 
0234 static int
0235 ath_cmn_process_ht20_40_fft(struct ath_rx_status *rs,
0236             struct ath_spec_scan_priv *spec_priv,
0237             u8 *sample_buf,
0238             u64 tsf, u16 freq, int chan_type)
0239 {
0240     struct fft_sample_ht20_40 fft_sample_40;
0241     struct ath_common *common = ath9k_hw_common(spec_priv->ah);
0242     struct ath_hw *ah = spec_priv->ah;
0243     struct ath9k_hw_cal_data *caldata = ah->caldata;
0244     struct ath_ht20_40_mag_info *mag_info;
0245     struct fft_sample_tlv *tlv;
0246     int dc_pos = SPECTRAL_HT20_40_NUM_BINS / 2;
0247     int i = 0;
0248     int ret = 0;
0249     s16 ext_nf;
0250     u16 lower_mag, upper_mag, tmp_mag, length;
0251     s8 lower_rssi, upper_rssi;
0252     u8 lower_max_index, upper_max_index;
0253     u8 lower_bitmap_w, upper_bitmap_w, max_exp;
0254 
0255     if (caldata)
0256         ext_nf = ath9k_hw_getchan_noise(ah, ah->curchan,
0257                 caldata->nfCalHist[3].privNF);
0258     else
0259         ext_nf = ATH_DEFAULT_NOISE_FLOOR;
0260 
0261     length = sizeof(fft_sample_40) - sizeof(struct fft_sample_tlv);
0262     fft_sample_40.tlv.type = ATH_FFT_SAMPLE_HT20_40;
0263     fft_sample_40.tlv.length = __cpu_to_be16(length);
0264     fft_sample_40.freq = __cpu_to_be16(freq);
0265     fft_sample_40.channel_type = chan_type;
0266 
0267     if (chan_type == NL80211_CHAN_HT40PLUS) {
0268         lower_rssi = fix_rssi_inv_only(rs->rs_rssi_ctl[0]);
0269         upper_rssi = fix_rssi_inv_only(rs->rs_rssi_ext[0]);
0270 
0271         fft_sample_40.lower_noise = ah->noise;
0272         fft_sample_40.upper_noise = ext_nf;
0273     } else {
0274         lower_rssi = fix_rssi_inv_only(rs->rs_rssi_ext[0]);
0275         upper_rssi = fix_rssi_inv_only(rs->rs_rssi_ctl[0]);
0276 
0277         fft_sample_40.lower_noise = ext_nf;
0278         fft_sample_40.upper_noise = ah->noise;
0279     }
0280 
0281     fft_sample_40.lower_rssi = lower_rssi;
0282     fft_sample_40.upper_rssi = upper_rssi;
0283 
0284     mag_info = (struct ath_ht20_40_mag_info *) (sample_buf +
0285                     SPECTRAL_HT20_40_NUM_BINS);
0286 
0287     lower_mag = spectral_max_magnitude(mag_info->lower_bins);
0288     fft_sample_40.lower_max_magnitude = __cpu_to_be16(lower_mag);
0289 
0290     upper_mag = spectral_max_magnitude(mag_info->upper_bins);
0291     fft_sample_40.upper_max_magnitude = __cpu_to_be16(upper_mag);
0292 
0293     lower_max_index = spectral_max_index_ht40(mag_info->lower_bins);
0294     fft_sample_40.lower_max_index = lower_max_index;
0295 
0296     upper_max_index = spectral_max_index_ht40(mag_info->upper_bins);
0297     fft_sample_40.upper_max_index = upper_max_index;
0298 
0299     lower_bitmap_w = spectral_bitmap_weight(mag_info->lower_bins);
0300     fft_sample_40.lower_bitmap_weight = lower_bitmap_w;
0301 
0302     upper_bitmap_w = spectral_bitmap_weight(mag_info->upper_bins);
0303     fft_sample_40.upper_bitmap_weight = upper_bitmap_w;
0304 
0305     max_exp = mag_info->max_exp & 0xf;
0306     fft_sample_40.max_exp = max_exp;
0307 
0308     fft_sample_40.tsf = __cpu_to_be64(tsf);
0309 
0310     memcpy(fft_sample_40.data, sample_buf, SPECTRAL_HT20_40_NUM_BINS);
0311 
0312     ath_dbg(common, SPECTRAL_SCAN, "FFT HT20/40 frame: lower mag 0x%X,"
0313                     "lower_mag_idx %i, upper mag 0x%X,"
0314                     "upper_mag_idx %i\n",
0315                     lower_mag >> max_exp,
0316                     lower_max_index,
0317                     upper_mag >> max_exp,
0318                     upper_max_index);
0319 
0320     /* Check if we got the expected magnitude values at
0321      * the expected bins
0322      */
0323     if (((fft_sample_40.data[upper_max_index + dc_pos] & 0xf8)
0324         != ((upper_mag >> max_exp) & 0xf8)) ||
0325        ((fft_sample_40.data[lower_max_index] & 0xf8)
0326         != ((lower_mag >> max_exp) & 0xf8))) {
0327         ath_dbg(common, SPECTRAL_SCAN, "Magnitude mismatch !\n");
0328         ret = -1;
0329     }
0330 
0331     /* DC value (value in the middle) is the blind spot of the spectral
0332      * sample and invalid, interpolate it.
0333      */
0334     fft_sample_40.data[dc_pos] = (fft_sample_40.data[dc_pos + 1] +
0335                     fft_sample_40.data[dc_pos - 1]) / 2;
0336 
0337     /* Check if the maximum magnitudes are indeed maximum,
0338      * also if the maximum value was at dc_pos, calculate
0339      * a new one (since value at dc_pos is invalid).
0340      */
0341     if (lower_max_index == dc_pos) {
0342         tmp_mag = 0;
0343         for (i = 0; i < dc_pos; i++) {
0344             if (fft_sample_40.data[i] > tmp_mag) {
0345                 tmp_mag = fft_sample_40.data[i];
0346                 fft_sample_40.lower_max_index = i;
0347             }
0348         }
0349 
0350         lower_mag = tmp_mag << max_exp;
0351         fft_sample_40.lower_max_magnitude = __cpu_to_be16(lower_mag);
0352 
0353         ath_dbg(common, SPECTRAL_SCAN,
0354             "Calculated new lower max 0x%X at %i\n",
0355             tmp_mag, fft_sample_40.lower_max_index);
0356     } else
0357     for (i = 0; i < dc_pos; i++) {
0358         if (fft_sample_40.data[i] == (lower_mag >> max_exp))
0359             ath_dbg(common, SPECTRAL_SCAN,
0360                 "Got lower mag: 0x%X at index %i\n",
0361                 fft_sample_40.data[i], i);
0362 
0363         if (fft_sample_40.data[i] > (lower_mag >> max_exp)) {
0364             ath_dbg(common, SPECTRAL_SCAN,
0365                 "Got lower bin %i higher than max: 0x%X\n",
0366                 i, fft_sample_40.data[i]);
0367             ret = -1;
0368         }
0369     }
0370 
0371     if (upper_max_index == dc_pos) {
0372         tmp_mag = 0;
0373         for (i = dc_pos; i < SPECTRAL_HT20_40_NUM_BINS; i++) {
0374             if (fft_sample_40.data[i] > tmp_mag) {
0375                 tmp_mag = fft_sample_40.data[i];
0376                 fft_sample_40.upper_max_index = i;
0377             }
0378         }
0379         upper_mag = tmp_mag << max_exp;
0380         fft_sample_40.upper_max_magnitude = __cpu_to_be16(upper_mag);
0381 
0382         ath_dbg(common, SPECTRAL_SCAN,
0383             "Calculated new upper max 0x%X at %i\n",
0384             tmp_mag, fft_sample_40.upper_max_index);
0385     } else
0386     for (i = dc_pos; i < SPECTRAL_HT20_40_NUM_BINS; i++) {
0387         if (fft_sample_40.data[i] == (upper_mag >> max_exp))
0388             ath_dbg(common, SPECTRAL_SCAN,
0389                 "Got upper mag: 0x%X at index %i\n",
0390                 fft_sample_40.data[i], i);
0391 
0392         if (fft_sample_40.data[i] > (upper_mag >> max_exp)) {
0393             ath_dbg(common, SPECTRAL_SCAN,
0394                 "Got upper bin %i higher than max: 0x%X\n",
0395                 i, fft_sample_40.data[i]);
0396 
0397             ret = -1;
0398         }
0399     }
0400 
0401     if (ret < 0)
0402         return ret;
0403 
0404     tlv = (struct fft_sample_tlv *)&fft_sample_40;
0405 
0406     ath_debug_send_fft_sample(spec_priv, tlv);
0407 
0408     return 0;
0409 }
0410 
0411 static inline void
0412 ath_cmn_copy_fft_frame(u8 *in, u8 *out, int sample_len, int sample_bytes)
0413 {
0414     switch (sample_bytes - sample_len) {
0415     case -1:
0416         /* First byte missing */
0417         memcpy(&out[1], in,
0418                sample_len - 1);
0419         break;
0420     case 0:
0421         /* Length correct, nothing to do. */
0422         memcpy(out, in, sample_len);
0423         break;
0424     case 1:
0425         /* MAC added 2 extra bytes AND first byte
0426          * is missing.
0427          */
0428         memcpy(&out[1], in, 30);
0429         out[31] = in[31];
0430         memcpy(&out[32], &in[33],
0431                sample_len - 32);
0432         break;
0433     case 2:
0434         /* MAC added 2 extra bytes at bin 30 and 32,
0435          * remove them.
0436          */
0437         memcpy(out, in, 30);
0438         out[30] = in[31];
0439         memcpy(&out[31], &in[33],
0440                sample_len - 31);
0441         break;
0442     default:
0443         break;
0444     }
0445 }
0446 
0447 static int
0448 ath_cmn_is_fft_buf_full(struct ath_spec_scan_priv *spec_priv)
0449 {
0450     int i = 0;
0451     int ret = 0;
0452     struct rchan_buf *buf;
0453     struct rchan *rc = spec_priv->rfs_chan_spec_scan;
0454 
0455     for_each_possible_cpu(i) {
0456         if ((buf = *per_cpu_ptr(rc->buf, i))) {
0457             ret += relay_buf_full(buf);
0458         }
0459     }
0460 
0461     if (ret)
0462         return 1;
0463     else
0464         return 0;
0465 }
0466 
0467 /* returns 1 if this was a spectral frame, even if not handled. */
0468 int ath_cmn_process_fft(struct ath_spec_scan_priv *spec_priv, struct ieee80211_hdr *hdr,
0469             struct ath_rx_status *rs, u64 tsf)
0470 {
0471     u8 sample_buf[SPECTRAL_SAMPLE_MAX_LEN] = {0};
0472     struct ath_hw *ah = spec_priv->ah;
0473     struct ath_common *common = ath9k_hw_common(spec_priv->ah);
0474     struct ath_softc *sc = (struct ath_softc *)common->priv;
0475     u8 num_bins, *vdata = (u8 *)hdr;
0476     struct ath_radar_info *radar_info;
0477     int len = rs->rs_datalen;
0478     int i;
0479     int got_slen = 0;
0480     u8  *sample_start;
0481     int sample_bytes = 0;
0482     int ret = 0;
0483     u16 fft_len, sample_len, freq = ah->curchan->chan->center_freq;
0484     enum nl80211_channel_type chan_type;
0485     ath_cmn_fft_idx_validator *fft_idx_validator;
0486     ath_cmn_fft_sample_handler *fft_handler;
0487 
0488     /* AR9280 and before report via ATH9K_PHYERR_RADAR, AR93xx and newer
0489      * via ATH9K_PHYERR_SPECTRAL. Haven't seen ATH9K_PHYERR_FALSE_RADAR_EXT
0490      * yet, but this is supposed to be possible as well.
0491      */
0492     if (rs->rs_phyerr != ATH9K_PHYERR_RADAR &&
0493         rs->rs_phyerr != ATH9K_PHYERR_FALSE_RADAR_EXT &&
0494         rs->rs_phyerr != ATH9K_PHYERR_SPECTRAL)
0495         return 0;
0496 
0497     /* check if spectral scan bit is set. This does not have to be checked
0498      * if received through a SPECTRAL phy error, but shouldn't hurt.
0499      */
0500     radar_info = ((struct ath_radar_info *)&vdata[len]) - 1;
0501     if (!(radar_info->pulse_bw_info & SPECTRAL_SCAN_BITMASK))
0502         return 0;
0503 
0504     if (!spec_priv->rfs_chan_spec_scan)
0505         return 1;
0506 
0507     /* Output buffers are full, no need to process anything
0508      * since there is no space to put the result anyway
0509      */
0510     ret = ath_cmn_is_fft_buf_full(spec_priv);
0511     if (ret == 1) {
0512         ath_dbg(common, SPECTRAL_SCAN, "FFT report ignored, no space "
0513                         "left on output buffers\n");
0514         return 1;
0515     }
0516 
0517     chan_type = cfg80211_get_chandef_type(&common->hw->conf.chandef);
0518     if ((chan_type == NL80211_CHAN_HT40MINUS) ||
0519         (chan_type == NL80211_CHAN_HT40PLUS)) {
0520         fft_len = SPECTRAL_HT20_40_TOTAL_DATA_LEN;
0521         sample_len = SPECTRAL_HT20_40_SAMPLE_LEN;
0522         num_bins = SPECTRAL_HT20_40_NUM_BINS;
0523         fft_idx_validator = &ath_cmn_max_idx_verify_ht20_40_fft;
0524         fft_handler = &ath_cmn_process_ht20_40_fft;
0525     } else {
0526         fft_len = SPECTRAL_HT20_TOTAL_DATA_LEN;
0527         sample_len = SPECTRAL_HT20_SAMPLE_LEN;
0528         num_bins = SPECTRAL_HT20_NUM_BINS;
0529         fft_idx_validator = ath_cmn_max_idx_verify_ht20_fft;
0530         fft_handler = &ath_cmn_process_ht20_fft;
0531     }
0532 
0533     ath_dbg(common, SPECTRAL_SCAN, "Got radar dump bw_info: 0x%X,"
0534                     "len: %i fft_len: %i\n",
0535                     radar_info->pulse_bw_info,
0536                     len,
0537                     fft_len);
0538     sample_start = vdata;
0539     for (i = 0; i < len - 2; i++) {
0540         sample_bytes++;
0541 
0542         /* Only a single sample received, no need to look
0543          * for the sample's end, do the correction based
0544          * on the packet's length instead. Note that hw
0545          * will always put the radar_info structure on
0546          * the end.
0547          */
0548         if (len <= fft_len + 2) {
0549             sample_bytes = len - sizeof(struct ath_radar_info);
0550             got_slen = 1;
0551         }
0552 
0553         /* Search for the end of the FFT frame between
0554          * sample_len - 1 and sample_len + 2. exp_max is 3
0555          * bits long and it's the only value on the last
0556          * byte of the frame so since it'll be smaller than
0557          * the next byte (the first bin of the next sample)
0558          * 90% of the time, we can use it as a separator.
0559          */
0560         if (vdata[i] <= 0x7 && sample_bytes >= sample_len - 1) {
0561 
0562             /* Got a frame length within boundaries, there are
0563              * four scenarios here:
0564              *
0565              * a) sample_len -> We got the correct length
0566              * b) sample_len + 2 -> 2 bytes added around bin[31]
0567              * c) sample_len - 1 -> The first byte is missing
0568              * d) sample_len + 1 -> b + c at the same time
0569              *
0570              * When MAC adds 2 extra bytes, bin[31] and bin[32]
0571              * have the same value, so we can use that for further
0572              * verification in cases b and d.
0573              */
0574 
0575             /* Did we go too far ? If so we couldn't determine
0576              * this sample's boundaries, discard any further
0577              * data
0578              */
0579             if ((sample_bytes > sample_len + 2) ||
0580                ((sample_bytes > sample_len) &&
0581                (sample_start[31] != sample_start[32])))
0582                 break;
0583 
0584             /* See if we got a valid frame by checking the
0585              * consistency of mag_info fields. This is to
0586              * prevent from "fixing" a correct frame.
0587              * Failure is non-fatal, later frames may
0588              * be valid.
0589              */
0590             if (!fft_idx_validator(&vdata[i], i)) {
0591                 ath_dbg(common, SPECTRAL_SCAN,
0592                     "Found valid fft frame at %i\n", i);
0593                 got_slen = 1;
0594             }
0595 
0596             /* We expect 1 - 2 more bytes */
0597             else if ((sample_start[31] == sample_start[32]) &&
0598                 (sample_bytes >= sample_len) &&
0599                 (sample_bytes < sample_len + 2) &&
0600                 (vdata[i + 1] <= 0x7))
0601                 continue;
0602 
0603             /* Try to distinguish cases a and c */
0604             else if ((sample_bytes == sample_len - 1) &&
0605                 (vdata[i + 1] <= 0x7))
0606                 continue;
0607 
0608             got_slen = 1;
0609         }
0610 
0611         if (got_slen) {
0612             ath_dbg(common, SPECTRAL_SCAN, "FFT frame len: %i\n",
0613                 sample_bytes);
0614 
0615             /* Only try to fix a frame if it's the only one
0616              * on the report, else just skip it.
0617              */
0618             if (sample_bytes != sample_len && len <= fft_len + 2) {
0619                 ath_cmn_copy_fft_frame(sample_start,
0620                                sample_buf, sample_len,
0621                                sample_bytes);
0622 
0623                 ret = fft_handler(rs, spec_priv, sample_buf,
0624                           tsf, freq, chan_type);
0625 
0626                 if (ret == 0)
0627                     RX_STAT_INC(sc, rx_spectral_sample_good);
0628                 else
0629                     RX_STAT_INC(sc, rx_spectral_sample_err);
0630 
0631                 memset(sample_buf, 0, SPECTRAL_SAMPLE_MAX_LEN);
0632 
0633                 /* Mix the received bins to the /dev/random
0634                  * pool
0635                  */
0636                 add_device_randomness(sample_buf, num_bins);
0637             }
0638 
0639             /* Process a normal frame */
0640             if (sample_bytes == sample_len) {
0641                 ret = fft_handler(rs, spec_priv, sample_start,
0642                           tsf, freq, chan_type);
0643 
0644                 if (ret == 0)
0645                     RX_STAT_INC(sc, rx_spectral_sample_good);
0646                 else
0647                     RX_STAT_INC(sc, rx_spectral_sample_err);
0648 
0649                 /* Mix the received bins to the /dev/random
0650                  * pool
0651                  */
0652                 add_device_randomness(sample_start, num_bins);
0653             }
0654 
0655             /* Short report processed, break out of the
0656              * loop.
0657              */
0658             if (len <= fft_len + 2)
0659                 return 1;
0660 
0661             sample_start = &vdata[i + 1];
0662 
0663             /* -1 to grab sample_len -1, -2 since
0664              * they 'll get increased by one. In case
0665              * of failure try to recover by going byte
0666              * by byte instead.
0667              */
0668             if (ret == 0) {
0669                 i += num_bins - 2;
0670                 sample_bytes = num_bins - 2;
0671             }
0672             got_slen = 0;
0673         }
0674     }
0675 
0676     i -= num_bins - 2;
0677     if (len - i != sizeof(struct ath_radar_info))
0678         ath_dbg(common, SPECTRAL_SCAN, "FFT report truncated"
0679                         "(bytes left: %i)\n",
0680                         len - i);
0681     return 1;
0682 }
0683 EXPORT_SYMBOL(ath_cmn_process_fft);
0684 
0685 /*********************/
0686 /* spectral_scan_ctl */
0687 /*********************/
0688 
0689 static ssize_t read_file_spec_scan_ctl(struct file *file, char __user *user_buf,
0690                        size_t count, loff_t *ppos)
0691 {
0692     struct ath_spec_scan_priv *spec_priv = file->private_data;
0693     char *mode = "";
0694     unsigned int len;
0695 
0696     switch (spec_priv->spectral_mode) {
0697     case SPECTRAL_DISABLED:
0698         mode = "disable";
0699         break;
0700     case SPECTRAL_BACKGROUND:
0701         mode = "background";
0702         break;
0703     case SPECTRAL_CHANSCAN:
0704         mode = "chanscan";
0705         break;
0706     case SPECTRAL_MANUAL:
0707         mode = "manual";
0708         break;
0709     }
0710     len = strlen(mode);
0711     return simple_read_from_buffer(user_buf, count, ppos, mode, len);
0712 }
0713 
0714 void ath9k_cmn_spectral_scan_trigger(struct ath_common *common,
0715                  struct ath_spec_scan_priv *spec_priv)
0716 {
0717     struct ath_hw *ah = spec_priv->ah;
0718     u32 rxfilter;
0719 
0720     if (IS_ENABLED(CONFIG_ATH9K_TX99))
0721         return;
0722 
0723     if (!ath9k_hw_ops(ah)->spectral_scan_trigger) {
0724         ath_err(common, "spectrum analyzer not implemented on this hardware\n");
0725         return;
0726     }
0727 
0728     if (!spec_priv->spec_config.enabled)
0729         return;
0730 
0731     ath_ps_ops(common)->wakeup(common);
0732     rxfilter = ath9k_hw_getrxfilter(ah);
0733     ath9k_hw_setrxfilter(ah, rxfilter |
0734                  ATH9K_RX_FILTER_PHYRADAR |
0735                  ATH9K_RX_FILTER_PHYERR);
0736 
0737     /* TODO: usually this should not be neccesary, but for some reason
0738      * (or in some mode?) the trigger must be called after the
0739      * configuration, otherwise the register will have its values reset
0740      * (on my ar9220 to value 0x01002310)
0741      */
0742     ath9k_cmn_spectral_scan_config(common, spec_priv, spec_priv->spectral_mode);
0743     ath9k_hw_ops(ah)->spectral_scan_trigger(ah);
0744     ath_ps_ops(common)->restore(common);
0745 }
0746 EXPORT_SYMBOL(ath9k_cmn_spectral_scan_trigger);
0747 
0748 int ath9k_cmn_spectral_scan_config(struct ath_common *common,
0749                    struct ath_spec_scan_priv *spec_priv,
0750                    enum spectral_mode spectral_mode)
0751 {
0752     struct ath_hw *ah = spec_priv->ah;
0753 
0754     if (!ath9k_hw_ops(ah)->spectral_scan_trigger) {
0755         ath_err(common, "spectrum analyzer not implemented on this hardware\n");
0756         return -1;
0757     }
0758 
0759     switch (spectral_mode) {
0760     case SPECTRAL_DISABLED:
0761         spec_priv->spec_config.enabled = 0;
0762         break;
0763     case SPECTRAL_BACKGROUND:
0764         /* send endless samples.
0765          * TODO: is this really useful for "background"?
0766          */
0767         spec_priv->spec_config.endless = 1;
0768         spec_priv->spec_config.enabled = 1;
0769         break;
0770     case SPECTRAL_CHANSCAN:
0771     case SPECTRAL_MANUAL:
0772         spec_priv->spec_config.endless = 0;
0773         spec_priv->spec_config.enabled = 1;
0774         break;
0775     default:
0776         return -1;
0777     }
0778 
0779     ath_ps_ops(common)->wakeup(common);
0780     ath9k_hw_ops(ah)->spectral_scan_config(ah, &spec_priv->spec_config);
0781     ath_ps_ops(common)->restore(common);
0782 
0783     spec_priv->spectral_mode = spectral_mode;
0784 
0785     return 0;
0786 }
0787 EXPORT_SYMBOL(ath9k_cmn_spectral_scan_config);
0788 
0789 static ssize_t write_file_spec_scan_ctl(struct file *file,
0790                     const char __user *user_buf,
0791                     size_t count, loff_t *ppos)
0792 {
0793     struct ath_spec_scan_priv *spec_priv = file->private_data;
0794     struct ath_common *common = ath9k_hw_common(spec_priv->ah);
0795     char buf[32];
0796     ssize_t len;
0797 
0798     if (IS_ENABLED(CONFIG_ATH9K_TX99))
0799         return -EOPNOTSUPP;
0800 
0801     len = min(count, sizeof(buf) - 1);
0802     if (copy_from_user(buf, user_buf, len))
0803         return -EFAULT;
0804 
0805     buf[len] = '\0';
0806 
0807     if (strncmp("trigger", buf, 7) == 0) {
0808         ath9k_cmn_spectral_scan_trigger(common, spec_priv);
0809     } else if (strncmp("background", buf, 10) == 0) {
0810         ath9k_cmn_spectral_scan_config(common, spec_priv, SPECTRAL_BACKGROUND);
0811         ath_dbg(common, CONFIG, "spectral scan: background mode enabled\n");
0812     } else if (strncmp("chanscan", buf, 8) == 0) {
0813         ath9k_cmn_spectral_scan_config(common, spec_priv, SPECTRAL_CHANSCAN);
0814         ath_dbg(common, CONFIG, "spectral scan: channel scan mode enabled\n");
0815     } else if (strncmp("manual", buf, 6) == 0) {
0816         ath9k_cmn_spectral_scan_config(common, spec_priv, SPECTRAL_MANUAL);
0817         ath_dbg(common, CONFIG, "spectral scan: manual mode enabled\n");
0818     } else if (strncmp("disable", buf, 7) == 0) {
0819         ath9k_cmn_spectral_scan_config(common, spec_priv, SPECTRAL_DISABLED);
0820         ath_dbg(common, CONFIG, "spectral scan: disabled\n");
0821     } else {
0822         return -EINVAL;
0823     }
0824 
0825     return count;
0826 }
0827 
0828 static const struct file_operations fops_spec_scan_ctl = {
0829     .read = read_file_spec_scan_ctl,
0830     .write = write_file_spec_scan_ctl,
0831     .open = simple_open,
0832     .owner = THIS_MODULE,
0833     .llseek = default_llseek,
0834 };
0835 
0836 /*************************/
0837 /* spectral_short_repeat */
0838 /*************************/
0839 
0840 static ssize_t read_file_spectral_short_repeat(struct file *file,
0841                            char __user *user_buf,
0842                            size_t count, loff_t *ppos)
0843 {
0844     struct ath_spec_scan_priv *spec_priv = file->private_data;
0845     char buf[32];
0846     unsigned int len;
0847 
0848     len = sprintf(buf, "%d\n", spec_priv->spec_config.short_repeat);
0849     return simple_read_from_buffer(user_buf, count, ppos, buf, len);
0850 }
0851 
0852 static ssize_t write_file_spectral_short_repeat(struct file *file,
0853                         const char __user *user_buf,
0854                         size_t count, loff_t *ppos)
0855 {
0856     struct ath_spec_scan_priv *spec_priv = file->private_data;
0857     unsigned long val;
0858     char buf[32];
0859     ssize_t len;
0860 
0861     len = min(count, sizeof(buf) - 1);
0862     if (copy_from_user(buf, user_buf, len))
0863         return -EFAULT;
0864 
0865     buf[len] = '\0';
0866     if (kstrtoul(buf, 0, &val))
0867         return -EINVAL;
0868 
0869     if (val > 1)
0870         return -EINVAL;
0871 
0872     spec_priv->spec_config.short_repeat = val;
0873     return count;
0874 }
0875 
0876 static const struct file_operations fops_spectral_short_repeat = {
0877     .read = read_file_spectral_short_repeat,
0878     .write = write_file_spectral_short_repeat,
0879     .open = simple_open,
0880     .owner = THIS_MODULE,
0881     .llseek = default_llseek,
0882 };
0883 
0884 /******************/
0885 /* spectral_count */
0886 /******************/
0887 
0888 static ssize_t read_file_spectral_count(struct file *file,
0889                     char __user *user_buf,
0890                     size_t count, loff_t *ppos)
0891 {
0892     struct ath_spec_scan_priv *spec_priv = file->private_data;
0893     char buf[32];
0894     unsigned int len;
0895 
0896     len = sprintf(buf, "%d\n", spec_priv->spec_config.count);
0897     return simple_read_from_buffer(user_buf, count, ppos, buf, len);
0898 }
0899 
0900 static ssize_t write_file_spectral_count(struct file *file,
0901                      const char __user *user_buf,
0902                      size_t count, loff_t *ppos)
0903 {
0904     struct ath_spec_scan_priv *spec_priv = file->private_data;
0905     unsigned long val;
0906     char buf[32];
0907     ssize_t len;
0908 
0909     len = min(count, sizeof(buf) - 1);
0910     if (copy_from_user(buf, user_buf, len))
0911         return -EFAULT;
0912 
0913     buf[len] = '\0';
0914     if (kstrtoul(buf, 0, &val))
0915         return -EINVAL;
0916 
0917     if (val > 255)
0918         return -EINVAL;
0919 
0920     spec_priv->spec_config.count = val;
0921     return count;
0922 }
0923 
0924 static const struct file_operations fops_spectral_count = {
0925     .read = read_file_spectral_count,
0926     .write = write_file_spectral_count,
0927     .open = simple_open,
0928     .owner = THIS_MODULE,
0929     .llseek = default_llseek,
0930 };
0931 
0932 /*******************/
0933 /* spectral_period */
0934 /*******************/
0935 
0936 static ssize_t read_file_spectral_period(struct file *file,
0937                      char __user *user_buf,
0938                      size_t count, loff_t *ppos)
0939 {
0940     struct ath_spec_scan_priv *spec_priv = file->private_data;
0941     char buf[32];
0942     unsigned int len;
0943 
0944     len = sprintf(buf, "%d\n", spec_priv->spec_config.period);
0945     return simple_read_from_buffer(user_buf, count, ppos, buf, len);
0946 }
0947 
0948 static ssize_t write_file_spectral_period(struct file *file,
0949                       const char __user *user_buf,
0950                       size_t count, loff_t *ppos)
0951 {
0952     struct ath_spec_scan_priv *spec_priv = file->private_data;
0953     unsigned long val;
0954     char buf[32];
0955     ssize_t len;
0956 
0957     len = min(count, sizeof(buf) - 1);
0958     if (copy_from_user(buf, user_buf, len))
0959         return -EFAULT;
0960 
0961     buf[len] = '\0';
0962     if (kstrtoul(buf, 0, &val))
0963         return -EINVAL;
0964 
0965     if (val > 255)
0966         return -EINVAL;
0967 
0968     spec_priv->spec_config.period = val;
0969     return count;
0970 }
0971 
0972 static const struct file_operations fops_spectral_period = {
0973     .read = read_file_spectral_period,
0974     .write = write_file_spectral_period,
0975     .open = simple_open,
0976     .owner = THIS_MODULE,
0977     .llseek = default_llseek,
0978 };
0979 
0980 /***********************/
0981 /* spectral_fft_period */
0982 /***********************/
0983 
0984 static ssize_t read_file_spectral_fft_period(struct file *file,
0985                          char __user *user_buf,
0986                          size_t count, loff_t *ppos)
0987 {
0988     struct ath_spec_scan_priv *spec_priv = file->private_data;
0989     char buf[32];
0990     unsigned int len;
0991 
0992     len = sprintf(buf, "%d\n", spec_priv->spec_config.fft_period);
0993     return simple_read_from_buffer(user_buf, count, ppos, buf, len);
0994 }
0995 
0996 static ssize_t write_file_spectral_fft_period(struct file *file,
0997                           const char __user *user_buf,
0998                           size_t count, loff_t *ppos)
0999 {
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 
1020 static 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 
1032 static 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 
1049 static int remove_buf_file_handler(struct dentry *dentry)
1050 {
1051     debugfs_remove(dentry);
1052 
1053     return 0;
1054 }
1055 
1056 static 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 
1065 void 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 }
1072 EXPORT_SYMBOL(ath9k_cmn_spectral_deinit_debug);
1073 
1074 void 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 }
1105 EXPORT_SYMBOL(ath9k_cmn_spectral_init_debug);