1// SPDX-License-Identifier: BSD-3-Clause-Clear 2/* 3 * Copyright (c) 2019-2020 The Linux Foundation. All rights reserved. 4 */ 5 6#include <linux/relay.h> 7#include "core.h" 8#include "debug.h" 9 10#define ATH11K_SPECTRAL_NUM_RESP_PER_EVENT 2 11#define ATH11K_SPECTRAL_EVENT_TIMEOUT_MS 1 12 13#define ATH11K_SPECTRAL_DWORD_SIZE 4 14/* HW bug, expected BIN size is 2 bytes but HW report as 4 bytes */ 15#define ATH11K_SPECTRAL_BIN_SIZE 4 16#define ATH11K_SPECTRAL_ATH11K_MIN_BINS 64 17#define ATH11K_SPECTRAL_ATH11K_MIN_IB_BINS 32 18#define ATH11K_SPECTRAL_ATH11K_MAX_IB_BINS 256 19 20#define ATH11K_SPECTRAL_SCAN_COUNT_MAX 4095 21 22/* Max channel computed by sum of 2g and 5g band channels */ 23#define ATH11K_SPECTRAL_TOTAL_CHANNEL 41 24#define ATH11K_SPECTRAL_SAMPLES_PER_CHANNEL 70 25#define ATH11K_SPECTRAL_PER_SAMPLE_SIZE (sizeof(struct fft_sample_ath11k) + \ 26 ATH11K_SPECTRAL_ATH11K_MAX_IB_BINS) 27#define ATH11K_SPECTRAL_TOTAL_SAMPLE (ATH11K_SPECTRAL_TOTAL_CHANNEL * \ 28 ATH11K_SPECTRAL_SAMPLES_PER_CHANNEL) 29#define ATH11K_SPECTRAL_SUB_BUFF_SIZE ATH11K_SPECTRAL_PER_SAMPLE_SIZE 30#define ATH11K_SPECTRAL_NUM_SUB_BUF ATH11K_SPECTRAL_TOTAL_SAMPLE 31 32#define ATH11K_SPECTRAL_20MHZ 20 33#define ATH11K_SPECTRAL_40MHZ 40 34#define ATH11K_SPECTRAL_80MHZ 80 35 36#define ATH11K_SPECTRAL_SIGNATURE 0xFA 37 38#define ATH11K_SPECTRAL_TAG_RADAR_SUMMARY 0x0 39#define ATH11K_SPECTRAL_TAG_RADAR_FFT 0x1 40#define ATH11K_SPECTRAL_TAG_SCAN_SUMMARY 0x2 41#define ATH11K_SPECTRAL_TAG_SCAN_SEARCH 0x3 42 43#define SPECTRAL_TLV_HDR_LEN GENMASK(15, 0) 44#define SPECTRAL_TLV_HDR_TAG GENMASK(23, 16) 45#define SPECTRAL_TLV_HDR_SIGN GENMASK(31, 24) 46 47#define SPECTRAL_SUMMARY_INFO0_AGC_TOTAL_GAIN GENMASK(7, 0) 48#define SPECTRAL_SUMMARY_INFO0_OB_FLAG BIT(8) 49#define SPECTRAL_SUMMARY_INFO0_GRP_IDX GENMASK(16, 9) 50#define SPECTRAL_SUMMARY_INFO0_RECENT_RFSAT BIT(17) 51#define SPECTRAL_SUMMARY_INFO0_INBAND_PWR_DB GENMASK(27, 18) 52#define SPECTRAL_SUMMARY_INFO0_FALSE_SCAN BIT(28) 53#define SPECTRAL_SUMMARY_INFO0_DETECTOR_ID GENMASK(30, 29) 54#define SPECTRAL_SUMMARY_INFO0_PRI80 BIT(31) 55 56#define SPECTRAL_SUMMARY_INFO2_PEAK_SIGNED_IDX GENMASK(11, 0) 57#define SPECTRAL_SUMMARY_INFO2_PEAK_MAGNITUDE GENMASK(21, 12) 58#define SPECTRAL_SUMMARY_INFO2_NARROWBAND_MASK GENMASK(29, 22) 59#define SPECTRAL_SUMMARY_INFO2_GAIN_CHANGE BIT(30) 60 61struct spectral_tlv { 62 __le32 timestamp; 63 __le32 header; 64} __packed; 65 66struct spectral_summary_fft_report { 67 __le32 timestamp; 68 __le32 tlv_header; 69 __le32 info0; 70 __le32 reserve0; 71 __le32 info2; 72 __le32 reserve1; 73} __packed; 74 75struct ath11k_spectral_summary_report { 76 struct wmi_dma_buf_release_meta_data meta; 77 u32 timestamp; 78 u8 agc_total_gain; 79 u8 grp_idx; 80 u16 inb_pwr_db; 81 s16 peak_idx; 82 u16 peak_mag; 83 u8 detector_id; 84 bool out_of_band_flag; 85 bool rf_saturation; 86 bool primary80; 87 bool gain_change; 88 bool false_scan; 89}; 90 91#define SPECTRAL_FFT_REPORT_INFO0_DETECTOR_ID GENMASK(1, 0) 92#define SPECTRAL_FFT_REPORT_INFO0_FFT_NUM GENMASK(4, 2) 93#define SPECTRAL_FFT_REPORT_INFO0_RADAR_CHECK GENMASK(16, 5) 94#define SPECTRAL_FFT_REPORT_INFO0_PEAK_SIGNED_IDX GENMASK(27, 17) 95#define SPECTRAL_FFT_REPORT_INFO0_CHAIN_IDX GENMASK(30, 28) 96 97#define SPECTRAL_FFT_REPORT_INFO1_BASE_PWR_DB GENMASK(8, 0) 98#define SPECTRAL_FFT_REPORT_INFO1_TOTAL_GAIN_DB GENMASK(16, 9) 99 100#define SPECTRAL_FFT_REPORT_INFO2_NUM_STRONG_BINS GENMASK(7, 0) 101#define SPECTRAL_FFT_REPORT_INFO2_PEAK_MAGNITUDE GENMASK(17, 8) 102#define SPECTRAL_FFT_REPORT_INFO2_AVG_PWR_DB GENMASK(24, 18) 103#define SPECTRAL_FFT_REPORT_INFO2_REL_PWR_DB GENMASK(31, 25) 104 105struct spectral_search_fft_report { 106 __le32 timestamp; 107 __le32 tlv_header; 108 __le32 info0; 109 __le32 info1; 110 __le32 info2; 111 __le32 reserve0; 112 u8 bins[0]; 113} __packed; 114 115struct ath11k_spectral_search_report { 116 u32 timestamp; 117 u8 detector_id; 118 u8 fft_count; 119 u16 radar_check; 120 s16 peak_idx; 121 u8 chain_idx; 122 u16 base_pwr_db; 123 u8 total_gain_db; 124 u8 strong_bin_count; 125 u16 peak_mag; 126 u8 avg_pwr_db; 127 u8 rel_pwr_db; 128}; 129 130static struct dentry *create_buf_file_handler(const char *filename, 131 struct dentry *parent, 132 umode_t mode, 133 struct rchan_buf *buf, 134 int *is_global) 135{ 136 struct dentry *buf_file; 137 138 buf_file = debugfs_create_file(filename, mode, parent, buf, 139 &relay_file_operations); 140 *is_global = 1; 141 return buf_file; 142} 143 144static int remove_buf_file_handler(struct dentry *dentry) 145{ 146 debugfs_remove(dentry); 147 148 return 0; 149} 150 151static struct rchan_callbacks rfs_scan_cb = { 152 .create_buf_file = create_buf_file_handler, 153 .remove_buf_file = remove_buf_file_handler, 154}; 155 156static struct ath11k_vif *ath11k_spectral_get_vdev(struct ath11k *ar) 157{ 158 struct ath11k_vif *arvif; 159 160 lockdep_assert_held(&ar->conf_mutex); 161 162 if (list_empty(&ar->arvifs)) 163 return NULL; 164 165 /* if there already is a vif doing spectral, return that. */ 166 list_for_each_entry(arvif, &ar->arvifs, list) 167 if (arvif->spectral_enabled) 168 return arvif; 169 170 /* otherwise, return the first vif. */ 171 return list_first_entry(&ar->arvifs, typeof(*arvif), list); 172} 173 174static int ath11k_spectral_scan_trigger(struct ath11k *ar) 175{ 176 struct ath11k_vif *arvif; 177 int ret; 178 179 lockdep_assert_held(&ar->conf_mutex); 180 181 arvif = ath11k_spectral_get_vdev(ar); 182 if (!arvif) 183 return -ENODEV; 184 185 if (ar->spectral.mode == ATH11K_SPECTRAL_DISABLED) 186 return 0; 187 188 ret = ath11k_wmi_vdev_spectral_enable(ar, arvif->vdev_id, 189 ATH11K_WMI_SPECTRAL_TRIGGER_CMD_CLEAR, 190 ATH11K_WMI_SPECTRAL_ENABLE_CMD_ENABLE); 191 if (ret) 192 return ret; 193 194 ret = ath11k_wmi_vdev_spectral_enable(ar, arvif->vdev_id, 195 ATH11K_WMI_SPECTRAL_TRIGGER_CMD_TRIGGER, 196 ATH11K_WMI_SPECTRAL_ENABLE_CMD_ENABLE); 197 if (ret) 198 return ret; 199 200 return 0; 201} 202 203static int ath11k_spectral_scan_config(struct ath11k *ar, 204 enum ath11k_spectral_mode mode) 205{ 206 struct ath11k_wmi_vdev_spectral_conf_param param = { 0 }; 207 struct ath11k_vif *arvif; 208 int ret, count; 209 210 lockdep_assert_held(&ar->conf_mutex); 211 212 arvif = ath11k_spectral_get_vdev(ar); 213 if (!arvif) 214 return -ENODEV; 215 216 arvif->spectral_enabled = (mode != ATH11K_SPECTRAL_DISABLED); 217 218 spin_lock_bh(&ar->spectral.lock); 219 ar->spectral.mode = mode; 220 spin_unlock_bh(&ar->spectral.lock); 221 222 ret = ath11k_wmi_vdev_spectral_enable(ar, arvif->vdev_id, 223 ATH11K_WMI_SPECTRAL_TRIGGER_CMD_CLEAR, 224 ATH11K_WMI_SPECTRAL_ENABLE_CMD_DISABLE); 225 if (ret) { 226 ath11k_warn(ar->ab, "failed to enable spectral scan: %d\n", ret); 227 return ret; 228 } 229 230 if (mode == ATH11K_SPECTRAL_DISABLED) 231 return 0; 232 233 if (mode == ATH11K_SPECTRAL_BACKGROUND) 234 count = ATH11K_WMI_SPECTRAL_COUNT_DEFAULT; 235 else 236 count = max_t(u16, 1, ar->spectral.count); 237 238 param.vdev_id = arvif->vdev_id; 239 param.scan_count = count; 240 param.scan_fft_size = ar->spectral.fft_size; 241 param.scan_period = ATH11K_WMI_SPECTRAL_PERIOD_DEFAULT; 242 param.scan_priority = ATH11K_WMI_SPECTRAL_PRIORITY_DEFAULT; 243 param.scan_gc_ena = ATH11K_WMI_SPECTRAL_GC_ENA_DEFAULT; 244 param.scan_restart_ena = ATH11K_WMI_SPECTRAL_RESTART_ENA_DEFAULT; 245 param.scan_noise_floor_ref = ATH11K_WMI_SPECTRAL_NOISE_FLOOR_REF_DEFAULT; 246 param.scan_init_delay = ATH11K_WMI_SPECTRAL_INIT_DELAY_DEFAULT; 247 param.scan_nb_tone_thr = ATH11K_WMI_SPECTRAL_NB_TONE_THR_DEFAULT; 248 param.scan_str_bin_thr = ATH11K_WMI_SPECTRAL_STR_BIN_THR_DEFAULT; 249 param.scan_wb_rpt_mode = ATH11K_WMI_SPECTRAL_WB_RPT_MODE_DEFAULT; 250 param.scan_rssi_rpt_mode = ATH11K_WMI_SPECTRAL_RSSI_RPT_MODE_DEFAULT; 251 param.scan_rssi_thr = ATH11K_WMI_SPECTRAL_RSSI_THR_DEFAULT; 252 param.scan_pwr_format = ATH11K_WMI_SPECTRAL_PWR_FORMAT_DEFAULT; 253 param.scan_rpt_mode = ATH11K_WMI_SPECTRAL_RPT_MODE_DEFAULT; 254 param.scan_bin_scale = ATH11K_WMI_SPECTRAL_BIN_SCALE_DEFAULT; 255 param.scan_dbm_adj = ATH11K_WMI_SPECTRAL_DBM_ADJ_DEFAULT; 256 param.scan_chn_mask = ATH11K_WMI_SPECTRAL_CHN_MASK_DEFAULT; 257 258 ret = ath11k_wmi_vdev_spectral_conf(ar, ¶m); 259 if (ret) { 260 ath11k_warn(ar->ab, "failed to configure spectral scan: %d\n", ret); 261 return ret; 262 } 263 264 return 0; 265} 266 267static ssize_t ath11k_read_file_spec_scan_ctl(struct file *file, 268 char __user *user_buf, 269 size_t count, loff_t *ppos) 270{ 271 struct ath11k *ar = file->private_data; 272 char *mode = ""; 273 size_t len; 274 enum ath11k_spectral_mode spectral_mode; 275 276 mutex_lock(&ar->conf_mutex); 277 spectral_mode = ar->spectral.mode; 278 mutex_unlock(&ar->conf_mutex); 279 280 switch (spectral_mode) { 281 case ATH11K_SPECTRAL_DISABLED: 282 mode = "disable"; 283 break; 284 case ATH11K_SPECTRAL_BACKGROUND: 285 mode = "background"; 286 break; 287 case ATH11K_SPECTRAL_MANUAL: 288 mode = "manual"; 289 break; 290 } 291 292 len = strlen(mode); 293 return simple_read_from_buffer(user_buf, count, ppos, mode, len); 294} 295 296static ssize_t ath11k_write_file_spec_scan_ctl(struct file *file, 297 const char __user *user_buf, 298 size_t count, loff_t *ppos) 299{ 300 struct ath11k *ar = file->private_data; 301 char buf[32]; 302 ssize_t len; 303 int ret; 304 305 len = min(count, sizeof(buf) - 1); 306 if (copy_from_user(buf, user_buf, len)) 307 return -EFAULT; 308 309 buf[len] = '\0'; 310 311 mutex_lock(&ar->conf_mutex); 312 313 if (strncmp("trigger", buf, 7) == 0) { 314 if (ar->spectral.mode == ATH11K_SPECTRAL_MANUAL || 315 ar->spectral.mode == ATH11K_SPECTRAL_BACKGROUND) { 316 /* reset the configuration to adopt possibly changed 317 * debugfs parameters 318 */ 319 ret = ath11k_spectral_scan_config(ar, ar->spectral.mode); 320 if (ret) { 321 ath11k_warn(ar->ab, "failed to reconfigure spectral scan: %d\n", 322 ret); 323 goto unlock; 324 } 325 326 ret = ath11k_spectral_scan_trigger(ar); 327 if (ret) { 328 ath11k_warn(ar->ab, "failed to trigger spectral scan: %d\n", 329 ret); 330 } 331 } else { 332 ret = -EINVAL; 333 } 334 } else if (strncmp("background", buf, 10) == 0) { 335 ret = ath11k_spectral_scan_config(ar, ATH11K_SPECTRAL_BACKGROUND); 336 } else if (strncmp("manual", buf, 6) == 0) { 337 ret = ath11k_spectral_scan_config(ar, ATH11K_SPECTRAL_MANUAL); 338 } else if (strncmp("disable", buf, 7) == 0) { 339 ret = ath11k_spectral_scan_config(ar, ATH11K_SPECTRAL_DISABLED); 340 } else { 341 ret = -EINVAL; 342 } 343 344unlock: 345 mutex_unlock(&ar->conf_mutex); 346 347 if (ret) 348 return ret; 349 350 return count; 351} 352 353static const struct file_operations fops_scan_ctl = { 354 .read = ath11k_read_file_spec_scan_ctl, 355 .write = ath11k_write_file_spec_scan_ctl, 356 .open = simple_open, 357 .owner = THIS_MODULE, 358 .llseek = default_llseek, 359}; 360 361static ssize_t ath11k_read_file_spectral_count(struct file *file, 362 char __user *user_buf, 363 size_t count, loff_t *ppos) 364{ 365 struct ath11k *ar = file->private_data; 366 char buf[32]; 367 size_t len; 368 u16 spectral_count; 369 370 mutex_lock(&ar->conf_mutex); 371 spectral_count = ar->spectral.count; 372 mutex_unlock(&ar->conf_mutex); 373 374 len = sprintf(buf, "%d\n", spectral_count); 375 return simple_read_from_buffer(user_buf, count, ppos, buf, len); 376} 377 378static ssize_t ath11k_write_file_spectral_count(struct file *file, 379 const char __user *user_buf, 380 size_t count, loff_t *ppos) 381{ 382 struct ath11k *ar = file->private_data; 383 unsigned long val; 384 char buf[32]; 385 ssize_t len; 386 387 len = min(count, sizeof(buf) - 1); 388 if (copy_from_user(buf, user_buf, len)) 389 return -EFAULT; 390 391 buf[len] = '\0'; 392 if (kstrtoul(buf, 0, &val)) 393 return -EINVAL; 394 395 if (val > ATH11K_SPECTRAL_SCAN_COUNT_MAX) 396 return -EINVAL; 397 398 mutex_lock(&ar->conf_mutex); 399 ar->spectral.count = val; 400 mutex_unlock(&ar->conf_mutex); 401 402 return count; 403} 404 405static const struct file_operations fops_scan_count = { 406 .read = ath11k_read_file_spectral_count, 407 .write = ath11k_write_file_spectral_count, 408 .open = simple_open, 409 .owner = THIS_MODULE, 410 .llseek = default_llseek, 411}; 412 413static ssize_t ath11k_read_file_spectral_bins(struct file *file, 414 char __user *user_buf, 415 size_t count, loff_t *ppos) 416{ 417 struct ath11k *ar = file->private_data; 418 char buf[32]; 419 unsigned int bins, fft_size; 420 size_t len; 421 422 mutex_lock(&ar->conf_mutex); 423 424 fft_size = ar->spectral.fft_size; 425 bins = 1 << fft_size; 426 427 mutex_unlock(&ar->conf_mutex); 428 429 len = sprintf(buf, "%d\n", bins); 430 return simple_read_from_buffer(user_buf, count, ppos, buf, len); 431} 432 433static ssize_t ath11k_write_file_spectral_bins(struct file *file, 434 const char __user *user_buf, 435 size_t count, loff_t *ppos) 436{ 437 struct ath11k *ar = file->private_data; 438 unsigned long val; 439 char buf[32]; 440 ssize_t len; 441 442 len = min(count, sizeof(buf) - 1); 443 if (copy_from_user(buf, user_buf, len)) 444 return -EFAULT; 445 446 buf[len] = '\0'; 447 if (kstrtoul(buf, 0, &val)) 448 return -EINVAL; 449 450 if (val < ATH11K_SPECTRAL_ATH11K_MIN_BINS || 451 val > SPECTRAL_ATH11K_MAX_NUM_BINS) 452 return -EINVAL; 453 454 if (!is_power_of_2(val)) 455 return -EINVAL; 456 457 mutex_lock(&ar->conf_mutex); 458 ar->spectral.fft_size = ilog2(val); 459 mutex_unlock(&ar->conf_mutex); 460 461 return count; 462} 463 464static const struct file_operations fops_scan_bins = { 465 .read = ath11k_read_file_spectral_bins, 466 .write = ath11k_write_file_spectral_bins, 467 .open = simple_open, 468 .owner = THIS_MODULE, 469 .llseek = default_llseek, 470}; 471 472static int ath11k_spectral_pull_summary(struct ath11k *ar, 473 struct wmi_dma_buf_release_meta_data *meta, 474 struct spectral_summary_fft_report *summary, 475 struct ath11k_spectral_summary_report *report) 476{ 477 report->timestamp = __le32_to_cpu(summary->timestamp); 478 report->agc_total_gain = FIELD_GET(SPECTRAL_SUMMARY_INFO0_AGC_TOTAL_GAIN, 479 __le32_to_cpu(summary->info0)); 480 report->out_of_band_flag = FIELD_GET(SPECTRAL_SUMMARY_INFO0_OB_FLAG, 481 __le32_to_cpu(summary->info0)); 482 report->grp_idx = FIELD_GET(SPECTRAL_SUMMARY_INFO0_GRP_IDX, 483 __le32_to_cpu(summary->info0)); 484 report->rf_saturation = FIELD_GET(SPECTRAL_SUMMARY_INFO0_RECENT_RFSAT, 485 __le32_to_cpu(summary->info0)); 486 report->inb_pwr_db = FIELD_GET(SPECTRAL_SUMMARY_INFO0_INBAND_PWR_DB, 487 __le32_to_cpu(summary->info0)); 488 report->false_scan = FIELD_GET(SPECTRAL_SUMMARY_INFO0_FALSE_SCAN, 489 __le32_to_cpu(summary->info0)); 490 report->detector_id = FIELD_GET(SPECTRAL_SUMMARY_INFO0_DETECTOR_ID, 491 __le32_to_cpu(summary->info0)); 492 report->primary80 = FIELD_GET(SPECTRAL_SUMMARY_INFO0_PRI80, 493 __le32_to_cpu(summary->info0)); 494 report->peak_idx = FIELD_GET(SPECTRAL_SUMMARY_INFO2_PEAK_SIGNED_IDX, 495 __le32_to_cpu(summary->info2)); 496 report->peak_mag = FIELD_GET(SPECTRAL_SUMMARY_INFO2_PEAK_MAGNITUDE, 497 __le32_to_cpu(summary->info2)); 498 report->gain_change = FIELD_GET(SPECTRAL_SUMMARY_INFO2_GAIN_CHANGE, 499 __le32_to_cpu(summary->info2)); 500 501 memcpy(&report->meta, meta, sizeof(*meta)); 502 503 return 0; 504} 505 506static int ath11k_spectral_pull_search(struct ath11k *ar, 507 struct spectral_search_fft_report *search, 508 struct ath11k_spectral_search_report *report) 509{ 510 report->timestamp = __le32_to_cpu(search->timestamp); 511 report->detector_id = FIELD_GET(SPECTRAL_FFT_REPORT_INFO0_DETECTOR_ID, 512 __le32_to_cpu(search->info0)); 513 report->fft_count = FIELD_GET(SPECTRAL_FFT_REPORT_INFO0_FFT_NUM, 514 __le32_to_cpu(search->info0)); 515 report->radar_check = FIELD_GET(SPECTRAL_FFT_REPORT_INFO0_RADAR_CHECK, 516 __le32_to_cpu(search->info0)); 517 report->peak_idx = FIELD_GET(SPECTRAL_FFT_REPORT_INFO0_PEAK_SIGNED_IDX, 518 __le32_to_cpu(search->info0)); 519 report->chain_idx = FIELD_GET(SPECTRAL_FFT_REPORT_INFO0_CHAIN_IDX, 520 __le32_to_cpu(search->info0)); 521 report->base_pwr_db = FIELD_GET(SPECTRAL_FFT_REPORT_INFO1_BASE_PWR_DB, 522 __le32_to_cpu(search->info1)); 523 report->total_gain_db = FIELD_GET(SPECTRAL_FFT_REPORT_INFO1_TOTAL_GAIN_DB, 524 __le32_to_cpu(search->info1)); 525 report->strong_bin_count = FIELD_GET(SPECTRAL_FFT_REPORT_INFO2_NUM_STRONG_BINS, 526 __le32_to_cpu(search->info2)); 527 report->peak_mag = FIELD_GET(SPECTRAL_FFT_REPORT_INFO2_PEAK_MAGNITUDE, 528 __le32_to_cpu(search->info2)); 529 report->avg_pwr_db = FIELD_GET(SPECTRAL_FFT_REPORT_INFO2_AVG_PWR_DB, 530 __le32_to_cpu(search->info2)); 531 report->rel_pwr_db = FIELD_GET(SPECTRAL_FFT_REPORT_INFO2_REL_PWR_DB, 532 __le32_to_cpu(search->info2)); 533 534 return 0; 535} 536 537static u8 ath11k_spectral_get_max_exp(s8 max_index, u8 max_magnitude, 538 int bin_len, u8 *bins) 539{ 540 int dc_pos; 541 u8 max_exp; 542 543 dc_pos = bin_len / 2; 544 545 /* peak index outside of bins */ 546 if (dc_pos <= max_index || -dc_pos >= max_index) 547 return 0; 548 549 for (max_exp = 0; max_exp < 8; max_exp++) { 550 if (bins[dc_pos + max_index] == (max_magnitude >> max_exp)) 551 break; 552 } 553 554 /* max_exp not found */ 555 if (bins[dc_pos + max_index] != (max_magnitude >> max_exp)) 556 return 0; 557 558 return max_exp; 559} 560 561static void ath11k_spectral_parse_fft(u8 *outbins, u8 *inbins, int num_bins, u8 fft_sz) 562{ 563 int i, j; 564 565 i = 0; 566 j = 0; 567 while (i < num_bins) { 568 outbins[i] = inbins[j]; 569 i++; 570 j += fft_sz; 571 } 572} 573 574static 575int ath11k_spectral_process_fft(struct ath11k *ar, 576 struct ath11k_spectral_summary_report *summary, 577 void *data, 578 struct fft_sample_ath11k *fft_sample, 579 u32 data_len) 580{ 581 struct ath11k_base *ab = ar->ab; 582 struct spectral_search_fft_report *fft_report = data; 583 struct ath11k_spectral_search_report search; 584 struct spectral_tlv *tlv; 585 int tlv_len, bin_len, num_bins; 586 u16 length, freq; 587 u8 chan_width_mhz; 588 int ret; 589 590 lockdep_assert_held(&ar->spectral.lock); 591 592 if (!ab->hw_params.spectral_fft_sz) { 593 ath11k_warn(ab, "invalid bin size type for hw rev %d\n", 594 ab->hw_rev); 595 return -EINVAL; 596 } 597 598 tlv = (struct spectral_tlv *)data; 599 tlv_len = FIELD_GET(SPECTRAL_TLV_HDR_LEN, __le32_to_cpu(tlv->header)); 600 /* convert Dword into bytes */ 601 tlv_len *= ATH11K_SPECTRAL_DWORD_SIZE; 602 bin_len = tlv_len - (sizeof(*fft_report) - sizeof(*tlv)); 603 604 if (data_len < (bin_len + sizeof(*fft_report))) { 605 ath11k_warn(ab, "mismatch in expected bin len %d and data len %d\n", 606 bin_len, data_len); 607 return -EINVAL; 608 } 609 610 num_bins = bin_len / ATH11K_SPECTRAL_BIN_SIZE; 611 /* Only In-band bins are useful to user for visualize */ 612 num_bins >>= 1; 613 614 if (num_bins < ATH11K_SPECTRAL_ATH11K_MIN_IB_BINS || 615 num_bins > ATH11K_SPECTRAL_ATH11K_MAX_IB_BINS || 616 !is_power_of_2(num_bins)) { 617 ath11k_warn(ab, "Invalid num of bins %d\n", num_bins); 618 return -EINVAL; 619 } 620 621 ret = ath11k_spectral_pull_search(ar, data, &search); 622 if (ret) { 623 ath11k_warn(ab, "failed to pull search report %d\n", ret); 624 return ret; 625 } 626 627 chan_width_mhz = summary->meta.ch_width; 628 629 switch (chan_width_mhz) { 630 case ATH11K_SPECTRAL_20MHZ: 631 case ATH11K_SPECTRAL_40MHZ: 632 case ATH11K_SPECTRAL_80MHZ: 633 fft_sample->chan_width_mhz = chan_width_mhz; 634 break; 635 default: 636 ath11k_warn(ab, "invalid channel width %d\n", chan_width_mhz); 637 return -EINVAL; 638 } 639 640 length = sizeof(*fft_sample) - sizeof(struct fft_sample_tlv) + num_bins; 641 fft_sample->tlv.type = ATH_FFT_SAMPLE_ATH11K; 642 fft_sample->tlv.length = __cpu_to_be16(length); 643 644 fft_sample->tsf = __cpu_to_be32(search.timestamp); 645 fft_sample->max_magnitude = __cpu_to_be16(search.peak_mag); 646 fft_sample->max_index = FIELD_GET(SPECTRAL_FFT_REPORT_INFO0_PEAK_SIGNED_IDX, 647 __le32_to_cpu(fft_report->info0)); 648 649 summary->inb_pwr_db >>= 1; 650 fft_sample->rssi = __cpu_to_be16(summary->inb_pwr_db); 651 fft_sample->noise = __cpu_to_be32(summary->meta.noise_floor[search.chain_idx]); 652 653 freq = summary->meta.freq1; 654 fft_sample->freq1 = __cpu_to_be16(freq); 655 656 freq = summary->meta.freq2; 657 fft_sample->freq2 = __cpu_to_be16(freq); 658 659 ath11k_spectral_parse_fft(fft_sample->data, fft_report->bins, num_bins, 660 ab->hw_params.spectral_fft_sz); 661 662 fft_sample->max_exp = ath11k_spectral_get_max_exp(fft_sample->max_index, 663 search.peak_mag, 664 num_bins, 665 fft_sample->data); 666 667 if (ar->spectral.rfs_scan) 668 relay_write(ar->spectral.rfs_scan, fft_sample, 669 length + sizeof(struct fft_sample_tlv)); 670 671 return 0; 672} 673 674static int ath11k_spectral_process_data(struct ath11k *ar, 675 struct ath11k_dbring_data *param) 676{ 677 struct ath11k_base *ab = ar->ab; 678 struct spectral_tlv *tlv; 679 struct spectral_summary_fft_report *summary = NULL; 680 struct ath11k_spectral_summary_report summ_rpt; 681 struct fft_sample_ath11k *fft_sample = NULL; 682 u8 *data; 683 u32 data_len, i; 684 u8 sign, tag; 685 int tlv_len, sample_sz; 686 int ret; 687 bool quit = false; 688 689 spin_lock_bh(&ar->spectral.lock); 690 691 if (!ar->spectral.enabled) { 692 ret = -EINVAL; 693 goto unlock; 694 } 695 696 sample_sz = sizeof(*fft_sample) + ATH11K_SPECTRAL_ATH11K_MAX_IB_BINS; 697 fft_sample = kmalloc(sample_sz, GFP_ATOMIC); 698 if (!fft_sample) { 699 ret = -ENOBUFS; 700 goto unlock; 701 } 702 703 data = param->data; 704 data_len = param->data_sz; 705 i = 0; 706 while (!quit && (i < data_len)) { 707 if ((i + sizeof(*tlv)) > data_len) { 708 ath11k_warn(ab, "failed to parse spectral tlv hdr at bytes %d\n", 709 i); 710 ret = -EINVAL; 711 goto err; 712 } 713 714 tlv = (struct spectral_tlv *)&data[i]; 715 sign = FIELD_GET(SPECTRAL_TLV_HDR_SIGN, 716 __le32_to_cpu(tlv->header)); 717 if (sign != ATH11K_SPECTRAL_SIGNATURE) { 718 ath11k_warn(ab, "Invalid sign 0x%x at bytes %d\n", 719 sign, i); 720 ret = -EINVAL; 721 goto err; 722 } 723 724 tlv_len = FIELD_GET(SPECTRAL_TLV_HDR_LEN, 725 __le32_to_cpu(tlv->header)); 726 /* convert Dword into bytes */ 727 tlv_len *= ATH11K_SPECTRAL_DWORD_SIZE; 728 if ((i + sizeof(*tlv) + tlv_len) > data_len) { 729 ath11k_warn(ab, "failed to parse spectral tlv payload at bytes %d tlv_len:%d data_len:%d\n", 730 i, tlv_len, data_len); 731 ret = -EINVAL; 732 goto err; 733 } 734 735 tag = FIELD_GET(SPECTRAL_TLV_HDR_TAG, 736 __le32_to_cpu(tlv->header)); 737 switch (tag) { 738 case ATH11K_SPECTRAL_TAG_SCAN_SUMMARY: 739 /* HW bug in tlv length of summary report, 740 * HW report 3 DWORD size but the data payload 741 * is 4 DWORD size (16 bytes). 742 * Need to remove this workaround once HW bug fixed 743 */ 744 tlv_len = sizeof(*summary) - sizeof(*tlv); 745 746 if (tlv_len < (sizeof(*summary) - sizeof(*tlv))) { 747 ath11k_warn(ab, "failed to parse spectral summary at bytes %d tlv_len:%d\n", 748 i, tlv_len); 749 ret = -EINVAL; 750 goto err; 751 } 752 753 summary = (struct spectral_summary_fft_report *)tlv; 754 ath11k_spectral_pull_summary(ar, ¶m->meta, 755 summary, &summ_rpt); 756 break; 757 case ATH11K_SPECTRAL_TAG_SCAN_SEARCH: 758 if (tlv_len < (sizeof(struct spectral_search_fft_report) - 759 sizeof(*tlv))) { 760 ath11k_warn(ab, "failed to parse spectral search fft at bytes %d\n", 761 i); 762 ret = -EINVAL; 763 goto err; 764 } 765 766 memset(fft_sample, 0, sample_sz); 767 ret = ath11k_spectral_process_fft(ar, &summ_rpt, tlv, 768 fft_sample, 769 data_len - i); 770 if (ret) { 771 ath11k_warn(ab, "failed to process spectral fft at bytes %d\n", 772 i); 773 goto err; 774 } 775 quit = true; 776 break; 777 } 778 779 i += sizeof(*tlv) + tlv_len; 780 } 781 782 ret = 0; 783 784err: 785 kfree(fft_sample); 786unlock: 787 spin_unlock_bh(&ar->spectral.lock); 788 return ret; 789} 790 791static int ath11k_spectral_ring_alloc(struct ath11k *ar, 792 struct ath11k_dbring_cap *db_cap) 793{ 794 struct ath11k_spectral *sp = &ar->spectral; 795 int ret; 796 797 ret = ath11k_dbring_srng_setup(ar, &sp->rx_ring, 798 0, db_cap->min_elem); 799 if (ret) { 800 ath11k_warn(ar->ab, "failed to setup db ring\n"); 801 return ret; 802 } 803 804 ath11k_dbring_set_cfg(ar, &sp->rx_ring, 805 ATH11K_SPECTRAL_NUM_RESP_PER_EVENT, 806 ATH11K_SPECTRAL_EVENT_TIMEOUT_MS, 807 ath11k_spectral_process_data); 808 809 ret = ath11k_dbring_buf_setup(ar, &sp->rx_ring, db_cap); 810 if (ret) { 811 ath11k_warn(ar->ab, "failed to setup db ring buffer\n"); 812 goto srng_cleanup; 813 } 814 815 ret = ath11k_dbring_wmi_cfg_setup(ar, &sp->rx_ring, 816 WMI_DIRECT_BUF_SPECTRAL); 817 if (ret) { 818 ath11k_warn(ar->ab, "failed to setup db ring cfg\n"); 819 goto buffer_cleanup; 820 } 821 822 return 0; 823 824buffer_cleanup: 825 ath11k_dbring_buf_cleanup(ar, &sp->rx_ring); 826srng_cleanup: 827 ath11k_dbring_srng_cleanup(ar, &sp->rx_ring); 828 return ret; 829} 830 831static inline void ath11k_spectral_ring_free(struct ath11k *ar) 832{ 833 struct ath11k_spectral *sp = &ar->spectral; 834 835 ath11k_dbring_srng_cleanup(ar, &sp->rx_ring); 836 ath11k_dbring_buf_cleanup(ar, &sp->rx_ring); 837} 838 839static inline void ath11k_spectral_debug_unregister(struct ath11k *ar) 840{ 841 debugfs_remove(ar->spectral.scan_bins); 842 ar->spectral.scan_bins = NULL; 843 844 debugfs_remove(ar->spectral.scan_count); 845 ar->spectral.scan_count = NULL; 846 847 debugfs_remove(ar->spectral.scan_ctl); 848 ar->spectral.scan_ctl = NULL; 849 850 if (ar->spectral.rfs_scan) { 851 relay_close(ar->spectral.rfs_scan); 852 ar->spectral.rfs_scan = NULL; 853 } 854} 855 856int ath11k_spectral_vif_stop(struct ath11k_vif *arvif) 857{ 858 if (!arvif->spectral_enabled) 859 return 0; 860 861 return ath11k_spectral_scan_config(arvif->ar, ATH11K_SPECTRAL_DISABLED); 862} 863 864void ath11k_spectral_reset_buffer(struct ath11k *ar) 865{ 866 if (!ar->spectral.enabled) 867 return; 868 869 if (ar->spectral.rfs_scan) 870 relay_reset(ar->spectral.rfs_scan); 871} 872 873void ath11k_spectral_deinit(struct ath11k_base *ab) 874{ 875 struct ath11k *ar; 876 struct ath11k_spectral *sp; 877 int i; 878 879 for (i = 0; i < ab->num_radios; i++) { 880 ar = ab->pdevs[i].ar; 881 sp = &ar->spectral; 882 883 if (!sp->enabled) 884 continue; 885 886 mutex_lock(&ar->conf_mutex); 887 ath11k_spectral_scan_config(ar, ATH11K_SPECTRAL_DISABLED); 888 mutex_unlock(&ar->conf_mutex); 889 890 spin_lock_bh(&sp->lock); 891 sp->enabled = false; 892 spin_unlock_bh(&sp->lock); 893 894 ath11k_spectral_debug_unregister(ar); 895 ath11k_spectral_ring_free(ar); 896 } 897} 898 899static inline int ath11k_spectral_debug_register(struct ath11k *ar) 900{ 901 int ret; 902 903 ar->spectral.rfs_scan = relay_open("spectral_scan", 904 ar->debug.debugfs_pdev, 905 ATH11K_SPECTRAL_SUB_BUFF_SIZE, 906 ATH11K_SPECTRAL_NUM_SUB_BUF, 907 &rfs_scan_cb, NULL); 908 if (!ar->spectral.rfs_scan) { 909 ath11k_warn(ar->ab, "failed to open relay in pdev %d\n", 910 ar->pdev_idx); 911 return -EINVAL; 912 } 913 914 ar->spectral.scan_ctl = debugfs_create_file("spectral_scan_ctl", 915 0600, 916 ar->debug.debugfs_pdev, ar, 917 &fops_scan_ctl); 918 if (!ar->spectral.scan_ctl) { 919 ath11k_warn(ar->ab, "failed to open debugfs in pdev %d\n", 920 ar->pdev_idx); 921 ret = -EINVAL; 922 goto debug_unregister; 923 } 924 925 ar->spectral.scan_count = debugfs_create_file("spectral_count", 926 0600, 927 ar->debug.debugfs_pdev, ar, 928 &fops_scan_count); 929 if (!ar->spectral.scan_count) { 930 ath11k_warn(ar->ab, "failed to open debugfs in pdev %d\n", 931 ar->pdev_idx); 932 ret = -EINVAL; 933 goto debug_unregister; 934 } 935 936 ar->spectral.scan_bins = debugfs_create_file("spectral_bins", 937 0600, 938 ar->debug.debugfs_pdev, ar, 939 &fops_scan_bins); 940 if (!ar->spectral.scan_bins) { 941 ath11k_warn(ar->ab, "failed to open debugfs in pdev %d\n", 942 ar->pdev_idx); 943 ret = -EINVAL; 944 goto debug_unregister; 945 } 946 947 return 0; 948 949debug_unregister: 950 ath11k_spectral_debug_unregister(ar); 951 return ret; 952} 953 954int ath11k_spectral_init(struct ath11k_base *ab) 955{ 956 struct ath11k *ar; 957 struct ath11k_spectral *sp; 958 struct ath11k_dbring_cap db_cap; 959 int ret; 960 int i; 961 962 if (!test_bit(WMI_TLV_SERVICE_FREQINFO_IN_METADATA, 963 ab->wmi_ab.svc_map)) 964 return 0; 965 966 if (!ab->hw_params.spectral_fft_sz) 967 return 0; 968 969 for (i = 0; i < ab->num_radios; i++) { 970 ar = ab->pdevs[i].ar; 971 sp = &ar->spectral; 972 973 ret = ath11k_dbring_get_cap(ar->ab, ar->pdev_idx, 974 WMI_DIRECT_BUF_SPECTRAL, 975 &db_cap); 976 if (ret) 977 continue; 978 979 idr_init(&sp->rx_ring.bufs_idr); 980 spin_lock_init(&sp->rx_ring.idr_lock); 981 spin_lock_init(&sp->lock); 982 983 ret = ath11k_spectral_ring_alloc(ar, &db_cap); 984 if (ret) { 985 ath11k_warn(ab, "failed to init spectral ring for pdev %d\n", 986 i); 987 goto deinit; 988 } 989 990 spin_lock_bh(&sp->lock); 991 992 sp->mode = ATH11K_SPECTRAL_DISABLED; 993 sp->count = ATH11K_WMI_SPECTRAL_COUNT_DEFAULT; 994 sp->fft_size = ATH11K_WMI_SPECTRAL_FFT_SIZE_DEFAULT; 995 sp->enabled = true; 996 997 spin_unlock_bh(&sp->lock); 998 999 ret = ath11k_spectral_debug_register(ar); 1000 if (ret) { 1001 ath11k_warn(ab, "failed to register spectral for pdev %d\n", 1002 i); 1003 goto deinit; 1004 } 1005 } 1006 1007 return 0; 1008 1009deinit: 1010 ath11k_spectral_deinit(ab); 1011 return ret; 1012} 1013 1014enum ath11k_spectral_mode ath11k_spectral_get_mode(struct ath11k *ar) 1015{ 1016 if (ar->spectral.enabled) 1017 return ar->spectral.mode; 1018 else 1019 return ATH11K_SPECTRAL_DISABLED; 1020} 1021 1022struct ath11k_dbring *ath11k_spectral_get_dbring(struct ath11k *ar) 1023{ 1024 if (ar->spectral.enabled) 1025 return &ar->spectral.rx_ring; 1026 else 1027 return NULL; 1028} 1029