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