root/drivers/net/wireless/ath/ath9k/common-spectral.c

/* [<][>][^][v][top][bottom][index][help] */

DEFINITIONS

This source file includes following definitions.
  1. fix_rssi_inv_only
  2. ath_debug_send_fft_sample
  3. ath_cmn_max_idx_verify_ht20_fft
  4. ath_cmn_max_idx_verify_ht20_40_fft
  5. ath_cmn_process_ht20_fft
  6. ath_cmn_process_ht20_40_fft
  7. ath_cmn_copy_fft_frame
  8. ath_cmn_is_fft_buf_full
  9. ath_cmn_process_fft
  10. read_file_spec_scan_ctl
  11. ath9k_cmn_spectral_scan_trigger
  12. ath9k_cmn_spectral_scan_config
  13. write_file_spec_scan_ctl
  14. read_file_spectral_short_repeat
  15. write_file_spectral_short_repeat
  16. read_file_spectral_count
  17. write_file_spectral_count
  18. read_file_spectral_period
  19. write_file_spectral_period
  20. read_file_spectral_fft_period
  21. write_file_spectral_fft_period
  22. create_buf_file_handler
  23. remove_buf_file_handler
  24. ath9k_cmn_spectral_deinit_debug
  25. ath9k_cmn_spectral_init_debug

   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 
  21 static 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 
  28 static 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 
  40 typedef int (ath_cmn_fft_idx_validator) (u8 *sample_end, int bytes_read);
  41 
  42 static int
  43 ath_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 
  80 static int
  81 ath_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 
 126 typedef 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 
 130 static int
 131 ath_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 
 234 static int
 235 ath_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 
 411 static inline void
 412 ath_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 
 447 static int
 448 ath_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. */
 468 int 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 }
 683 EXPORT_SYMBOL(ath_cmn_process_fft);
 684 
 685 /*********************/
 686 /* spectral_scan_ctl */
 687 /*********************/
 688 
 689 static 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 
 714 void 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 }
 746 EXPORT_SYMBOL(ath9k_cmn_spectral_scan_trigger);
 747 
 748 int 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 }
 787 EXPORT_SYMBOL(ath9k_cmn_spectral_scan_config);
 788 
 789 static 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 
 828 static 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 
 840 static 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 
 852 static 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 
 876 static 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 
 888 static 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 
 900 static 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 
 924 static 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 
 936 static 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 
 948 static 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 
 972 static 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 
 984 static 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 
 996 static 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 
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 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);

/* [<][>][^][v][top][bottom][index][help] */