0001
0002
0003
0004
0005
0006 #include <linux/relay.h>
0007 #include "core.h"
0008 #include "debug.h"
0009
0010 #define ATH11K_SPECTRAL_NUM_RESP_PER_EVENT 2
0011 #define ATH11K_SPECTRAL_EVENT_TIMEOUT_MS 1
0012
0013 #define ATH11K_SPECTRAL_DWORD_SIZE 4
0014 #define ATH11K_SPECTRAL_MIN_BINS 32
0015 #define ATH11K_SPECTRAL_MIN_IB_BINS (ATH11K_SPECTRAL_MIN_BINS >> 1)
0016 #define ATH11K_SPECTRAL_MAX_IB_BINS(x) ((x)->hw_params.spectral.max_fft_bins >> 1)
0017
0018 #define ATH11K_SPECTRAL_SCAN_COUNT_MAX 4095
0019
0020
0021 #define ATH11K_SPECTRAL_TOTAL_CHANNEL 41
0022 #define ATH11K_SPECTRAL_SAMPLES_PER_CHANNEL 70
0023 #define ATH11K_SPECTRAL_PER_SAMPLE_SIZE(x) (sizeof(struct fft_sample_ath11k) + \
0024 ATH11K_SPECTRAL_MAX_IB_BINS(x))
0025 #define ATH11K_SPECTRAL_TOTAL_SAMPLE (ATH11K_SPECTRAL_TOTAL_CHANNEL * \
0026 ATH11K_SPECTRAL_SAMPLES_PER_CHANNEL)
0027 #define ATH11K_SPECTRAL_SUB_BUFF_SIZE(x) ATH11K_SPECTRAL_PER_SAMPLE_SIZE(x)
0028 #define ATH11K_SPECTRAL_NUM_SUB_BUF ATH11K_SPECTRAL_TOTAL_SAMPLE
0029
0030 #define ATH11K_SPECTRAL_20MHZ 20
0031 #define ATH11K_SPECTRAL_40MHZ 40
0032 #define ATH11K_SPECTRAL_80MHZ 80
0033
0034 #define ATH11K_SPECTRAL_SIGNATURE 0xFA
0035
0036 #define ATH11K_SPECTRAL_TAG_RADAR_SUMMARY 0x0
0037 #define ATH11K_SPECTRAL_TAG_RADAR_FFT 0x1
0038 #define ATH11K_SPECTRAL_TAG_SCAN_SUMMARY 0x2
0039 #define ATH11K_SPECTRAL_TAG_SCAN_SEARCH 0x3
0040
0041 #define SPECTRAL_TLV_HDR_LEN GENMASK(15, 0)
0042 #define SPECTRAL_TLV_HDR_TAG GENMASK(23, 16)
0043 #define SPECTRAL_TLV_HDR_SIGN GENMASK(31, 24)
0044
0045 #define SPECTRAL_SUMMARY_INFO0_AGC_TOTAL_GAIN GENMASK(7, 0)
0046 #define SPECTRAL_SUMMARY_INFO0_OB_FLAG BIT(8)
0047 #define SPECTRAL_SUMMARY_INFO0_GRP_IDX GENMASK(16, 9)
0048 #define SPECTRAL_SUMMARY_INFO0_RECENT_RFSAT BIT(17)
0049 #define SPECTRAL_SUMMARY_INFO0_INBAND_PWR_DB GENMASK(27, 18)
0050 #define SPECTRAL_SUMMARY_INFO0_FALSE_SCAN BIT(28)
0051 #define SPECTRAL_SUMMARY_INFO0_DETECTOR_ID GENMASK(30, 29)
0052 #define SPECTRAL_SUMMARY_INFO0_PRI80 BIT(31)
0053
0054 #define SPECTRAL_SUMMARY_INFO2_PEAK_SIGNED_IDX GENMASK(11, 0)
0055 #define SPECTRAL_SUMMARY_INFO2_PEAK_MAGNITUDE GENMASK(21, 12)
0056 #define SPECTRAL_SUMMARY_INFO2_NARROWBAND_MASK GENMASK(29, 22)
0057 #define SPECTRAL_SUMMARY_INFO2_GAIN_CHANGE BIT(30)
0058
0059 struct spectral_tlv {
0060 __le32 timestamp;
0061 __le32 header;
0062 } __packed;
0063
0064 struct spectral_summary_fft_report {
0065 __le32 timestamp;
0066 __le32 tlv_header;
0067 __le32 info0;
0068 __le32 reserve0;
0069 __le32 info2;
0070 __le32 reserve1;
0071 } __packed;
0072
0073 struct ath11k_spectral_summary_report {
0074 struct wmi_dma_buf_release_meta_data meta;
0075 u32 timestamp;
0076 u8 agc_total_gain;
0077 u8 grp_idx;
0078 u16 inb_pwr_db;
0079 s16 peak_idx;
0080 u16 peak_mag;
0081 u8 detector_id;
0082 bool out_of_band_flag;
0083 bool rf_saturation;
0084 bool primary80;
0085 bool gain_change;
0086 bool false_scan;
0087 };
0088
0089 #define SPECTRAL_FFT_REPORT_INFO0_DETECTOR_ID GENMASK(1, 0)
0090 #define SPECTRAL_FFT_REPORT_INFO0_FFT_NUM GENMASK(4, 2)
0091 #define SPECTRAL_FFT_REPORT_INFO0_RADAR_CHECK GENMASK(16, 5)
0092 #define SPECTRAL_FFT_REPORT_INFO0_PEAK_SIGNED_IDX GENMASK(27, 17)
0093 #define SPECTRAL_FFT_REPORT_INFO0_CHAIN_IDX GENMASK(30, 28)
0094
0095 #define SPECTRAL_FFT_REPORT_INFO1_BASE_PWR_DB GENMASK(8, 0)
0096 #define SPECTRAL_FFT_REPORT_INFO1_TOTAL_GAIN_DB GENMASK(16, 9)
0097
0098 #define SPECTRAL_FFT_REPORT_INFO2_NUM_STRONG_BINS GENMASK(7, 0)
0099 #define SPECTRAL_FFT_REPORT_INFO2_PEAK_MAGNITUDE GENMASK(17, 8)
0100 #define SPECTRAL_FFT_REPORT_INFO2_AVG_PWR_DB GENMASK(24, 18)
0101 #define SPECTRAL_FFT_REPORT_INFO2_REL_PWR_DB GENMASK(31, 25)
0102
0103 struct spectral_search_fft_report {
0104 __le32 timestamp;
0105 __le32 tlv_header;
0106 __le32 info0;
0107 __le32 info1;
0108 __le32 info2;
0109 __le32 reserve0;
0110 u8 bins[];
0111 } __packed;
0112
0113 struct ath11k_spectral_search_report {
0114 u32 timestamp;
0115 u8 detector_id;
0116 u8 fft_count;
0117 u16 radar_check;
0118 s16 peak_idx;
0119 u8 chain_idx;
0120 u16 base_pwr_db;
0121 u8 total_gain_db;
0122 u8 strong_bin_count;
0123 u16 peak_mag;
0124 u8 avg_pwr_db;
0125 u8 rel_pwr_db;
0126 };
0127
0128 static struct dentry *create_buf_file_handler(const char *filename,
0129 struct dentry *parent,
0130 umode_t mode,
0131 struct rchan_buf *buf,
0132 int *is_global)
0133 {
0134 struct dentry *buf_file;
0135
0136 buf_file = debugfs_create_file(filename, mode, parent, buf,
0137 &relay_file_operations);
0138 *is_global = 1;
0139 return buf_file;
0140 }
0141
0142 static int remove_buf_file_handler(struct dentry *dentry)
0143 {
0144 debugfs_remove(dentry);
0145
0146 return 0;
0147 }
0148
0149 static const struct rchan_callbacks rfs_scan_cb = {
0150 .create_buf_file = create_buf_file_handler,
0151 .remove_buf_file = remove_buf_file_handler,
0152 };
0153
0154 static struct ath11k_vif *ath11k_spectral_get_vdev(struct ath11k *ar)
0155 {
0156 struct ath11k_vif *arvif;
0157
0158 lockdep_assert_held(&ar->conf_mutex);
0159
0160 if (list_empty(&ar->arvifs))
0161 return NULL;
0162
0163
0164 list_for_each_entry(arvif, &ar->arvifs, list)
0165 if (arvif->spectral_enabled)
0166 return arvif;
0167
0168
0169 return list_first_entry(&ar->arvifs, typeof(*arvif), list);
0170 }
0171
0172 static int ath11k_spectral_scan_trigger(struct ath11k *ar)
0173 {
0174 struct ath11k_vif *arvif;
0175 int ret;
0176
0177 lockdep_assert_held(&ar->conf_mutex);
0178
0179 arvif = ath11k_spectral_get_vdev(ar);
0180 if (!arvif)
0181 return -ENODEV;
0182
0183 if (ar->spectral.mode == ATH11K_SPECTRAL_DISABLED)
0184 return 0;
0185
0186 ret = ath11k_wmi_vdev_spectral_enable(ar, arvif->vdev_id,
0187 ATH11K_WMI_SPECTRAL_TRIGGER_CMD_CLEAR,
0188 ATH11K_WMI_SPECTRAL_ENABLE_CMD_ENABLE);
0189 if (ret)
0190 return ret;
0191
0192 ret = ath11k_wmi_vdev_spectral_enable(ar, arvif->vdev_id,
0193 ATH11K_WMI_SPECTRAL_TRIGGER_CMD_TRIGGER,
0194 ATH11K_WMI_SPECTRAL_ENABLE_CMD_ENABLE);
0195 if (ret)
0196 return ret;
0197
0198 return 0;
0199 }
0200
0201 static int ath11k_spectral_scan_config(struct ath11k *ar,
0202 enum ath11k_spectral_mode mode)
0203 {
0204 struct ath11k_wmi_vdev_spectral_conf_param param = { 0 };
0205 struct ath11k_vif *arvif;
0206 int ret, count;
0207
0208 lockdep_assert_held(&ar->conf_mutex);
0209
0210 arvif = ath11k_spectral_get_vdev(ar);
0211 if (!arvif)
0212 return -ENODEV;
0213
0214 arvif->spectral_enabled = (mode != ATH11K_SPECTRAL_DISABLED);
0215
0216 spin_lock_bh(&ar->spectral.lock);
0217 ar->spectral.mode = mode;
0218 spin_unlock_bh(&ar->spectral.lock);
0219
0220 ret = ath11k_wmi_vdev_spectral_enable(ar, arvif->vdev_id,
0221 ATH11K_WMI_SPECTRAL_TRIGGER_CMD_CLEAR,
0222 ATH11K_WMI_SPECTRAL_ENABLE_CMD_DISABLE);
0223 if (ret) {
0224 ath11k_warn(ar->ab, "failed to enable spectral scan: %d\n", ret);
0225 return ret;
0226 }
0227
0228 if (mode == ATH11K_SPECTRAL_DISABLED)
0229 return 0;
0230
0231 if (mode == ATH11K_SPECTRAL_BACKGROUND)
0232 count = ATH11K_WMI_SPECTRAL_COUNT_DEFAULT;
0233 else
0234 count = max_t(u16, 1, ar->spectral.count);
0235
0236 param.vdev_id = arvif->vdev_id;
0237 param.scan_count = count;
0238 param.scan_fft_size = ar->spectral.fft_size;
0239 param.scan_period = ATH11K_WMI_SPECTRAL_PERIOD_DEFAULT;
0240 param.scan_priority = ATH11K_WMI_SPECTRAL_PRIORITY_DEFAULT;
0241 param.scan_gc_ena = ATH11K_WMI_SPECTRAL_GC_ENA_DEFAULT;
0242 param.scan_restart_ena = ATH11K_WMI_SPECTRAL_RESTART_ENA_DEFAULT;
0243 param.scan_noise_floor_ref = ATH11K_WMI_SPECTRAL_NOISE_FLOOR_REF_DEFAULT;
0244 param.scan_init_delay = ATH11K_WMI_SPECTRAL_INIT_DELAY_DEFAULT;
0245 param.scan_nb_tone_thr = ATH11K_WMI_SPECTRAL_NB_TONE_THR_DEFAULT;
0246 param.scan_str_bin_thr = ATH11K_WMI_SPECTRAL_STR_BIN_THR_DEFAULT;
0247 param.scan_wb_rpt_mode = ATH11K_WMI_SPECTRAL_WB_RPT_MODE_DEFAULT;
0248 param.scan_rssi_rpt_mode = ATH11K_WMI_SPECTRAL_RSSI_RPT_MODE_DEFAULT;
0249 param.scan_rssi_thr = ATH11K_WMI_SPECTRAL_RSSI_THR_DEFAULT;
0250 param.scan_pwr_format = ATH11K_WMI_SPECTRAL_PWR_FORMAT_DEFAULT;
0251 param.scan_rpt_mode = ATH11K_WMI_SPECTRAL_RPT_MODE_DEFAULT;
0252 param.scan_bin_scale = ATH11K_WMI_SPECTRAL_BIN_SCALE_DEFAULT;
0253 param.scan_dbm_adj = ATH11K_WMI_SPECTRAL_DBM_ADJ_DEFAULT;
0254 param.scan_chn_mask = ATH11K_WMI_SPECTRAL_CHN_MASK_DEFAULT;
0255
0256 ret = ath11k_wmi_vdev_spectral_conf(ar, ¶m);
0257 if (ret) {
0258 ath11k_warn(ar->ab, "failed to configure spectral scan: %d\n", ret);
0259 return ret;
0260 }
0261
0262 return 0;
0263 }
0264
0265 static ssize_t ath11k_read_file_spec_scan_ctl(struct file *file,
0266 char __user *user_buf,
0267 size_t count, loff_t *ppos)
0268 {
0269 struct ath11k *ar = file->private_data;
0270 char *mode = "";
0271 size_t len;
0272 enum ath11k_spectral_mode spectral_mode;
0273
0274 mutex_lock(&ar->conf_mutex);
0275 spectral_mode = ar->spectral.mode;
0276 mutex_unlock(&ar->conf_mutex);
0277
0278 switch (spectral_mode) {
0279 case ATH11K_SPECTRAL_DISABLED:
0280 mode = "disable";
0281 break;
0282 case ATH11K_SPECTRAL_BACKGROUND:
0283 mode = "background";
0284 break;
0285 case ATH11K_SPECTRAL_MANUAL:
0286 mode = "manual";
0287 break;
0288 }
0289
0290 len = strlen(mode);
0291 return simple_read_from_buffer(user_buf, count, ppos, mode, len);
0292 }
0293
0294 static ssize_t ath11k_write_file_spec_scan_ctl(struct file *file,
0295 const char __user *user_buf,
0296 size_t count, loff_t *ppos)
0297 {
0298 struct ath11k *ar = file->private_data;
0299 char buf[32];
0300 ssize_t len;
0301 int ret;
0302
0303 len = min(count, sizeof(buf) - 1);
0304 if (copy_from_user(buf, user_buf, len))
0305 return -EFAULT;
0306
0307 buf[len] = '\0';
0308
0309 mutex_lock(&ar->conf_mutex);
0310
0311 if (strncmp("trigger", buf, 7) == 0) {
0312 if (ar->spectral.mode == ATH11K_SPECTRAL_MANUAL ||
0313 ar->spectral.mode == ATH11K_SPECTRAL_BACKGROUND) {
0314
0315
0316
0317 ret = ath11k_spectral_scan_config(ar, ar->spectral.mode);
0318 if (ret) {
0319 ath11k_warn(ar->ab, "failed to reconfigure spectral scan: %d\n",
0320 ret);
0321 goto unlock;
0322 }
0323
0324 ret = ath11k_spectral_scan_trigger(ar);
0325 if (ret) {
0326 ath11k_warn(ar->ab, "failed to trigger spectral scan: %d\n",
0327 ret);
0328 }
0329 } else {
0330 ret = -EINVAL;
0331 }
0332 } else if (strncmp("background", buf, 10) == 0) {
0333 ret = ath11k_spectral_scan_config(ar, ATH11K_SPECTRAL_BACKGROUND);
0334 } else if (strncmp("manual", buf, 6) == 0) {
0335 ret = ath11k_spectral_scan_config(ar, ATH11K_SPECTRAL_MANUAL);
0336 } else if (strncmp("disable", buf, 7) == 0) {
0337 ret = ath11k_spectral_scan_config(ar, ATH11K_SPECTRAL_DISABLED);
0338 } else {
0339 ret = -EINVAL;
0340 }
0341
0342 unlock:
0343 mutex_unlock(&ar->conf_mutex);
0344
0345 if (ret)
0346 return ret;
0347
0348 return count;
0349 }
0350
0351 static const struct file_operations fops_scan_ctl = {
0352 .read = ath11k_read_file_spec_scan_ctl,
0353 .write = ath11k_write_file_spec_scan_ctl,
0354 .open = simple_open,
0355 .owner = THIS_MODULE,
0356 .llseek = default_llseek,
0357 };
0358
0359 static ssize_t ath11k_read_file_spectral_count(struct file *file,
0360 char __user *user_buf,
0361 size_t count, loff_t *ppos)
0362 {
0363 struct ath11k *ar = file->private_data;
0364 char buf[32];
0365 size_t len;
0366 u16 spectral_count;
0367
0368 mutex_lock(&ar->conf_mutex);
0369 spectral_count = ar->spectral.count;
0370 mutex_unlock(&ar->conf_mutex);
0371
0372 len = sprintf(buf, "%d\n", spectral_count);
0373 return simple_read_from_buffer(user_buf, count, ppos, buf, len);
0374 }
0375
0376 static ssize_t ath11k_write_file_spectral_count(struct file *file,
0377 const char __user *user_buf,
0378 size_t count, loff_t *ppos)
0379 {
0380 struct ath11k *ar = file->private_data;
0381 unsigned long val;
0382 char buf[32];
0383 ssize_t len;
0384
0385 len = min(count, sizeof(buf) - 1);
0386 if (copy_from_user(buf, user_buf, len))
0387 return -EFAULT;
0388
0389 buf[len] = '\0';
0390 if (kstrtoul(buf, 0, &val))
0391 return -EINVAL;
0392
0393 if (val > ATH11K_SPECTRAL_SCAN_COUNT_MAX)
0394 return -EINVAL;
0395
0396 mutex_lock(&ar->conf_mutex);
0397 ar->spectral.count = val;
0398 mutex_unlock(&ar->conf_mutex);
0399
0400 return count;
0401 }
0402
0403 static const struct file_operations fops_scan_count = {
0404 .read = ath11k_read_file_spectral_count,
0405 .write = ath11k_write_file_spectral_count,
0406 .open = simple_open,
0407 .owner = THIS_MODULE,
0408 .llseek = default_llseek,
0409 };
0410
0411 static ssize_t ath11k_read_file_spectral_bins(struct file *file,
0412 char __user *user_buf,
0413 size_t count, loff_t *ppos)
0414 {
0415 struct ath11k *ar = file->private_data;
0416 char buf[32];
0417 unsigned int bins, fft_size;
0418 size_t len;
0419
0420 mutex_lock(&ar->conf_mutex);
0421
0422 fft_size = ar->spectral.fft_size;
0423 bins = 1 << fft_size;
0424
0425 mutex_unlock(&ar->conf_mutex);
0426
0427 len = sprintf(buf, "%d\n", bins);
0428 return simple_read_from_buffer(user_buf, count, ppos, buf, len);
0429 }
0430
0431 static ssize_t ath11k_write_file_spectral_bins(struct file *file,
0432 const char __user *user_buf,
0433 size_t count, loff_t *ppos)
0434 {
0435 struct ath11k *ar = file->private_data;
0436 unsigned long val;
0437 char buf[32];
0438 ssize_t len;
0439
0440 len = min(count, sizeof(buf) - 1);
0441 if (copy_from_user(buf, user_buf, len))
0442 return -EFAULT;
0443
0444 buf[len] = '\0';
0445 if (kstrtoul(buf, 0, &val))
0446 return -EINVAL;
0447
0448 if (val < ATH11K_SPECTRAL_MIN_BINS ||
0449 val > ar->ab->hw_params.spectral.max_fft_bins)
0450 return -EINVAL;
0451
0452 if (!is_power_of_2(val))
0453 return -EINVAL;
0454
0455 mutex_lock(&ar->conf_mutex);
0456 ar->spectral.fft_size = ilog2(val);
0457 mutex_unlock(&ar->conf_mutex);
0458
0459 return count;
0460 }
0461
0462 static const struct file_operations fops_scan_bins = {
0463 .read = ath11k_read_file_spectral_bins,
0464 .write = ath11k_write_file_spectral_bins,
0465 .open = simple_open,
0466 .owner = THIS_MODULE,
0467 .llseek = default_llseek,
0468 };
0469
0470 static int ath11k_spectral_pull_summary(struct ath11k *ar,
0471 struct wmi_dma_buf_release_meta_data *meta,
0472 struct spectral_summary_fft_report *summary,
0473 struct ath11k_spectral_summary_report *report)
0474 {
0475 report->timestamp = __le32_to_cpu(summary->timestamp);
0476 report->agc_total_gain = FIELD_GET(SPECTRAL_SUMMARY_INFO0_AGC_TOTAL_GAIN,
0477 __le32_to_cpu(summary->info0));
0478 report->out_of_band_flag = FIELD_GET(SPECTRAL_SUMMARY_INFO0_OB_FLAG,
0479 __le32_to_cpu(summary->info0));
0480 report->grp_idx = FIELD_GET(SPECTRAL_SUMMARY_INFO0_GRP_IDX,
0481 __le32_to_cpu(summary->info0));
0482 report->rf_saturation = FIELD_GET(SPECTRAL_SUMMARY_INFO0_RECENT_RFSAT,
0483 __le32_to_cpu(summary->info0));
0484 report->inb_pwr_db = FIELD_GET(SPECTRAL_SUMMARY_INFO0_INBAND_PWR_DB,
0485 __le32_to_cpu(summary->info0));
0486 report->false_scan = FIELD_GET(SPECTRAL_SUMMARY_INFO0_FALSE_SCAN,
0487 __le32_to_cpu(summary->info0));
0488 report->detector_id = FIELD_GET(SPECTRAL_SUMMARY_INFO0_DETECTOR_ID,
0489 __le32_to_cpu(summary->info0));
0490 report->primary80 = FIELD_GET(SPECTRAL_SUMMARY_INFO0_PRI80,
0491 __le32_to_cpu(summary->info0));
0492 report->peak_idx = FIELD_GET(SPECTRAL_SUMMARY_INFO2_PEAK_SIGNED_IDX,
0493 __le32_to_cpu(summary->info2));
0494 report->peak_mag = FIELD_GET(SPECTRAL_SUMMARY_INFO2_PEAK_MAGNITUDE,
0495 __le32_to_cpu(summary->info2));
0496 report->gain_change = FIELD_GET(SPECTRAL_SUMMARY_INFO2_GAIN_CHANGE,
0497 __le32_to_cpu(summary->info2));
0498
0499 memcpy(&report->meta, meta, sizeof(*meta));
0500
0501 return 0;
0502 }
0503
0504 static int ath11k_spectral_pull_search(struct ath11k *ar,
0505 struct spectral_search_fft_report *search,
0506 struct ath11k_spectral_search_report *report)
0507 {
0508 report->timestamp = __le32_to_cpu(search->timestamp);
0509 report->detector_id = FIELD_GET(SPECTRAL_FFT_REPORT_INFO0_DETECTOR_ID,
0510 __le32_to_cpu(search->info0));
0511 report->fft_count = FIELD_GET(SPECTRAL_FFT_REPORT_INFO0_FFT_NUM,
0512 __le32_to_cpu(search->info0));
0513 report->radar_check = FIELD_GET(SPECTRAL_FFT_REPORT_INFO0_RADAR_CHECK,
0514 __le32_to_cpu(search->info0));
0515 report->peak_idx = FIELD_GET(SPECTRAL_FFT_REPORT_INFO0_PEAK_SIGNED_IDX,
0516 __le32_to_cpu(search->info0));
0517 report->chain_idx = FIELD_GET(SPECTRAL_FFT_REPORT_INFO0_CHAIN_IDX,
0518 __le32_to_cpu(search->info0));
0519 report->base_pwr_db = FIELD_GET(SPECTRAL_FFT_REPORT_INFO1_BASE_PWR_DB,
0520 __le32_to_cpu(search->info1));
0521 report->total_gain_db = FIELD_GET(SPECTRAL_FFT_REPORT_INFO1_TOTAL_GAIN_DB,
0522 __le32_to_cpu(search->info1));
0523 report->strong_bin_count = FIELD_GET(SPECTRAL_FFT_REPORT_INFO2_NUM_STRONG_BINS,
0524 __le32_to_cpu(search->info2));
0525 report->peak_mag = FIELD_GET(SPECTRAL_FFT_REPORT_INFO2_PEAK_MAGNITUDE,
0526 __le32_to_cpu(search->info2));
0527 report->avg_pwr_db = FIELD_GET(SPECTRAL_FFT_REPORT_INFO2_AVG_PWR_DB,
0528 __le32_to_cpu(search->info2));
0529 report->rel_pwr_db = FIELD_GET(SPECTRAL_FFT_REPORT_INFO2_REL_PWR_DB,
0530 __le32_to_cpu(search->info2));
0531
0532 return 0;
0533 }
0534
0535 static u8 ath11k_spectral_get_max_exp(s8 max_index, u8 max_magnitude,
0536 int bin_len, u8 *bins)
0537 {
0538 int dc_pos;
0539 u8 max_exp;
0540
0541 dc_pos = bin_len / 2;
0542
0543
0544 if (dc_pos <= max_index || -dc_pos >= max_index)
0545 return 0;
0546
0547 for (max_exp = 0; max_exp < 8; max_exp++) {
0548 if (bins[dc_pos + max_index] == (max_magnitude >> max_exp))
0549 break;
0550 }
0551
0552
0553 if (bins[dc_pos + max_index] != (max_magnitude >> max_exp))
0554 return 0;
0555
0556 return max_exp;
0557 }
0558
0559 static void ath11k_spectral_parse_fft(u8 *outbins, u8 *inbins, int num_bins, u8 fft_sz)
0560 {
0561 int i, j;
0562
0563 i = 0;
0564 j = 0;
0565 while (i < num_bins) {
0566 outbins[i] = inbins[j];
0567 i++;
0568 j += fft_sz;
0569 }
0570 }
0571
0572 static
0573 int ath11k_spectral_process_fft(struct ath11k *ar,
0574 struct ath11k_spectral_summary_report *summary,
0575 void *data,
0576 struct fft_sample_ath11k *fft_sample,
0577 u32 data_len)
0578 {
0579 struct ath11k_base *ab = ar->ab;
0580 struct spectral_search_fft_report *fft_report = data;
0581 struct ath11k_spectral_search_report search;
0582 struct spectral_tlv *tlv;
0583 int tlv_len, bin_len, num_bins;
0584 u16 length, freq;
0585 u8 chan_width_mhz, bin_sz;
0586 int ret;
0587 u32 check_length;
0588
0589 lockdep_assert_held(&ar->spectral.lock);
0590
0591 if (!ab->hw_params.spectral.fft_sz) {
0592 ath11k_warn(ab, "invalid bin size type for hw rev %d\n",
0593 ab->hw_rev);
0594 return -EINVAL;
0595 }
0596
0597 tlv = (struct spectral_tlv *)data;
0598 tlv_len = FIELD_GET(SPECTRAL_TLV_HDR_LEN, __le32_to_cpu(tlv->header));
0599
0600 tlv_len *= ATH11K_SPECTRAL_DWORD_SIZE;
0601 bin_len = tlv_len - ab->hw_params.spectral.fft_hdr_len;
0602
0603 if (data_len < (bin_len + sizeof(*fft_report))) {
0604 ath11k_warn(ab, "mismatch in expected bin len %d and data len %d\n",
0605 bin_len, data_len);
0606 return -EINVAL;
0607 }
0608
0609 bin_sz = ab->hw_params.spectral.fft_sz + ab->hw_params.spectral.fft_pad_sz;
0610 num_bins = bin_len / bin_sz;
0611
0612 num_bins >>= 1;
0613
0614 if (num_bins < ATH11K_SPECTRAL_MIN_IB_BINS ||
0615 num_bins > ATH11K_SPECTRAL_MAX_IB_BINS(ab) ||
0616 !is_power_of_2(num_bins)) {
0617 ath11k_warn(ab, "Invalid num of bins %d\n", num_bins);
0618 return -EINVAL;
0619 }
0620
0621 check_length = sizeof(*fft_report) + (num_bins * ab->hw_params.spectral.fft_sz);
0622 ret = ath11k_dbring_validate_buffer(ar, data, check_length);
0623 if (ret) {
0624 ath11k_warn(ar->ab, "found magic value in fft data, dropping\n");
0625 return ret;
0626 }
0627
0628 ret = ath11k_spectral_pull_search(ar, data, &search);
0629 if (ret) {
0630 ath11k_warn(ab, "failed to pull search report %d\n", ret);
0631 return ret;
0632 }
0633
0634 chan_width_mhz = summary->meta.ch_width;
0635
0636 switch (chan_width_mhz) {
0637 case ATH11K_SPECTRAL_20MHZ:
0638 case ATH11K_SPECTRAL_40MHZ:
0639 case ATH11K_SPECTRAL_80MHZ:
0640 fft_sample->chan_width_mhz = chan_width_mhz;
0641 break;
0642 default:
0643 ath11k_warn(ab, "invalid channel width %d\n", chan_width_mhz);
0644 return -EINVAL;
0645 }
0646
0647 length = sizeof(*fft_sample) - sizeof(struct fft_sample_tlv) + num_bins;
0648 fft_sample->tlv.type = ATH_FFT_SAMPLE_ATH11K;
0649 fft_sample->tlv.length = __cpu_to_be16(length);
0650
0651 fft_sample->tsf = __cpu_to_be32(search.timestamp);
0652 fft_sample->max_magnitude = __cpu_to_be16(search.peak_mag);
0653 fft_sample->max_index = FIELD_GET(SPECTRAL_FFT_REPORT_INFO0_PEAK_SIGNED_IDX,
0654 __le32_to_cpu(fft_report->info0));
0655
0656 summary->inb_pwr_db >>= 1;
0657 fft_sample->rssi = __cpu_to_be16(summary->inb_pwr_db);
0658 fft_sample->noise = __cpu_to_be32(summary->meta.noise_floor[search.chain_idx]);
0659
0660 freq = summary->meta.freq1;
0661 fft_sample->freq1 = __cpu_to_be16(freq);
0662
0663 freq = summary->meta.freq2;
0664 fft_sample->freq2 = __cpu_to_be16(freq);
0665
0666 ath11k_spectral_parse_fft(fft_sample->data, fft_report->bins, num_bins,
0667 ab->hw_params.spectral.fft_sz);
0668
0669 fft_sample->max_exp = ath11k_spectral_get_max_exp(fft_sample->max_index,
0670 search.peak_mag,
0671 num_bins,
0672 fft_sample->data);
0673
0674 if (ar->spectral.rfs_scan)
0675 relay_write(ar->spectral.rfs_scan, fft_sample,
0676 length + sizeof(struct fft_sample_tlv));
0677
0678 return 0;
0679 }
0680
0681 static int ath11k_spectral_process_data(struct ath11k *ar,
0682 struct ath11k_dbring_data *param)
0683 {
0684 struct ath11k_base *ab = ar->ab;
0685 struct spectral_tlv *tlv;
0686 struct spectral_summary_fft_report *summary = NULL;
0687 struct ath11k_spectral_summary_report summ_rpt;
0688 struct fft_sample_ath11k *fft_sample = NULL;
0689 u8 *data;
0690 u32 data_len, i;
0691 u8 sign, tag;
0692 int tlv_len, sample_sz;
0693 int ret;
0694 bool quit = false;
0695
0696 spin_lock_bh(&ar->spectral.lock);
0697
0698 if (!ar->spectral.enabled) {
0699 ret = -EINVAL;
0700 goto unlock;
0701 }
0702
0703 sample_sz = sizeof(*fft_sample) + ATH11K_SPECTRAL_MAX_IB_BINS(ab);
0704 fft_sample = kmalloc(sample_sz, GFP_ATOMIC);
0705 if (!fft_sample) {
0706 ret = -ENOBUFS;
0707 goto unlock;
0708 }
0709
0710 data = param->data;
0711 data_len = param->data_sz;
0712 i = 0;
0713 while (!quit && (i < data_len)) {
0714 if ((i + sizeof(*tlv)) > data_len) {
0715 ath11k_warn(ab, "failed to parse spectral tlv hdr at bytes %d\n",
0716 i);
0717 ret = -EINVAL;
0718 goto err;
0719 }
0720
0721 tlv = (struct spectral_tlv *)&data[i];
0722 sign = FIELD_GET(SPECTRAL_TLV_HDR_SIGN,
0723 __le32_to_cpu(tlv->header));
0724 if (sign != ATH11K_SPECTRAL_SIGNATURE) {
0725 ath11k_warn(ab, "Invalid sign 0x%x at bytes %d\n",
0726 sign, i);
0727 ret = -EINVAL;
0728 goto err;
0729 }
0730
0731 tlv_len = FIELD_GET(SPECTRAL_TLV_HDR_LEN,
0732 __le32_to_cpu(tlv->header));
0733
0734 tlv_len *= ATH11K_SPECTRAL_DWORD_SIZE;
0735 if ((i + sizeof(*tlv) + tlv_len) > data_len) {
0736 ath11k_warn(ab, "failed to parse spectral tlv payload at bytes %d tlv_len:%d data_len:%d\n",
0737 i, tlv_len, data_len);
0738 ret = -EINVAL;
0739 goto err;
0740 }
0741
0742 tag = FIELD_GET(SPECTRAL_TLV_HDR_TAG,
0743 __le32_to_cpu(tlv->header));
0744 switch (tag) {
0745 case ATH11K_SPECTRAL_TAG_SCAN_SUMMARY:
0746
0747
0748
0749
0750
0751 tlv_len = sizeof(*summary) - sizeof(*tlv) +
0752 ab->hw_params.spectral.summary_pad_sz;
0753
0754 if (tlv_len < (sizeof(*summary) - sizeof(*tlv))) {
0755 ath11k_warn(ab, "failed to parse spectral summary at bytes %d tlv_len:%d\n",
0756 i, tlv_len);
0757 ret = -EINVAL;
0758 goto err;
0759 }
0760
0761 ret = ath11k_dbring_validate_buffer(ar, data, tlv_len);
0762 if (ret) {
0763 ath11k_warn(ar->ab, "found magic value in spectral summary, dropping\n");
0764 goto err;
0765 }
0766
0767 summary = (struct spectral_summary_fft_report *)tlv;
0768 ath11k_spectral_pull_summary(ar, ¶m->meta,
0769 summary, &summ_rpt);
0770 break;
0771 case ATH11K_SPECTRAL_TAG_SCAN_SEARCH:
0772 if (tlv_len < (sizeof(struct spectral_search_fft_report) -
0773 sizeof(*tlv))) {
0774 ath11k_warn(ab, "failed to parse spectral search fft at bytes %d\n",
0775 i);
0776 ret = -EINVAL;
0777 goto err;
0778 }
0779
0780 memset(fft_sample, 0, sample_sz);
0781 ret = ath11k_spectral_process_fft(ar, &summ_rpt, tlv,
0782 fft_sample,
0783 data_len - i);
0784 if (ret) {
0785 ath11k_warn(ab, "failed to process spectral fft at bytes %d\n",
0786 i);
0787 goto err;
0788 }
0789 quit = true;
0790 break;
0791 }
0792
0793 i += sizeof(*tlv) + tlv_len;
0794 }
0795
0796 ret = 0;
0797
0798 err:
0799 kfree(fft_sample);
0800 unlock:
0801 spin_unlock_bh(&ar->spectral.lock);
0802 return ret;
0803 }
0804
0805 static int ath11k_spectral_ring_alloc(struct ath11k *ar,
0806 struct ath11k_dbring_cap *db_cap)
0807 {
0808 struct ath11k_spectral *sp = &ar->spectral;
0809 int ret;
0810
0811 ret = ath11k_dbring_srng_setup(ar, &sp->rx_ring,
0812 0, db_cap->min_elem);
0813 if (ret) {
0814 ath11k_warn(ar->ab, "failed to setup db ring\n");
0815 return ret;
0816 }
0817
0818 ath11k_dbring_set_cfg(ar, &sp->rx_ring,
0819 ATH11K_SPECTRAL_NUM_RESP_PER_EVENT,
0820 ATH11K_SPECTRAL_EVENT_TIMEOUT_MS,
0821 ath11k_spectral_process_data);
0822
0823 ret = ath11k_dbring_buf_setup(ar, &sp->rx_ring, db_cap);
0824 if (ret) {
0825 ath11k_warn(ar->ab, "failed to setup db ring buffer\n");
0826 goto srng_cleanup;
0827 }
0828
0829 ret = ath11k_dbring_wmi_cfg_setup(ar, &sp->rx_ring,
0830 WMI_DIRECT_BUF_SPECTRAL);
0831 if (ret) {
0832 ath11k_warn(ar->ab, "failed to setup db ring cfg\n");
0833 goto buffer_cleanup;
0834 }
0835
0836 return 0;
0837
0838 buffer_cleanup:
0839 ath11k_dbring_buf_cleanup(ar, &sp->rx_ring);
0840 srng_cleanup:
0841 ath11k_dbring_srng_cleanup(ar, &sp->rx_ring);
0842 return ret;
0843 }
0844
0845 static inline void ath11k_spectral_ring_free(struct ath11k *ar)
0846 {
0847 struct ath11k_spectral *sp = &ar->spectral;
0848
0849 ath11k_dbring_srng_cleanup(ar, &sp->rx_ring);
0850 ath11k_dbring_buf_cleanup(ar, &sp->rx_ring);
0851 }
0852
0853 static inline void ath11k_spectral_debug_unregister(struct ath11k *ar)
0854 {
0855 debugfs_remove(ar->spectral.scan_bins);
0856 ar->spectral.scan_bins = NULL;
0857
0858 debugfs_remove(ar->spectral.scan_count);
0859 ar->spectral.scan_count = NULL;
0860
0861 debugfs_remove(ar->spectral.scan_ctl);
0862 ar->spectral.scan_ctl = NULL;
0863
0864 if (ar->spectral.rfs_scan) {
0865 relay_close(ar->spectral.rfs_scan);
0866 ar->spectral.rfs_scan = NULL;
0867 }
0868 }
0869
0870 int ath11k_spectral_vif_stop(struct ath11k_vif *arvif)
0871 {
0872 if (!arvif->spectral_enabled)
0873 return 0;
0874
0875 return ath11k_spectral_scan_config(arvif->ar, ATH11K_SPECTRAL_DISABLED);
0876 }
0877
0878 void ath11k_spectral_reset_buffer(struct ath11k *ar)
0879 {
0880 if (!ar->spectral.enabled)
0881 return;
0882
0883 if (ar->spectral.rfs_scan)
0884 relay_reset(ar->spectral.rfs_scan);
0885 }
0886
0887 void ath11k_spectral_deinit(struct ath11k_base *ab)
0888 {
0889 struct ath11k *ar;
0890 struct ath11k_spectral *sp;
0891 int i;
0892
0893 for (i = 0; i < ab->num_radios; i++) {
0894 ar = ab->pdevs[i].ar;
0895 sp = &ar->spectral;
0896
0897 if (!sp->enabled)
0898 continue;
0899
0900 mutex_lock(&ar->conf_mutex);
0901 ath11k_spectral_scan_config(ar, ATH11K_SPECTRAL_DISABLED);
0902 mutex_unlock(&ar->conf_mutex);
0903
0904 spin_lock_bh(&sp->lock);
0905 sp->enabled = false;
0906 spin_unlock_bh(&sp->lock);
0907
0908 ath11k_spectral_debug_unregister(ar);
0909 ath11k_spectral_ring_free(ar);
0910 }
0911 }
0912
0913 static inline int ath11k_spectral_debug_register(struct ath11k *ar)
0914 {
0915 int ret;
0916
0917 ar->spectral.rfs_scan = relay_open("spectral_scan",
0918 ar->debug.debugfs_pdev,
0919 ATH11K_SPECTRAL_SUB_BUFF_SIZE(ar->ab),
0920 ATH11K_SPECTRAL_NUM_SUB_BUF,
0921 &rfs_scan_cb, NULL);
0922 if (!ar->spectral.rfs_scan) {
0923 ath11k_warn(ar->ab, "failed to open relay in pdev %d\n",
0924 ar->pdev_idx);
0925 return -EINVAL;
0926 }
0927
0928 ar->spectral.scan_ctl = debugfs_create_file("spectral_scan_ctl",
0929 0600,
0930 ar->debug.debugfs_pdev, ar,
0931 &fops_scan_ctl);
0932 if (!ar->spectral.scan_ctl) {
0933 ath11k_warn(ar->ab, "failed to open debugfs in pdev %d\n",
0934 ar->pdev_idx);
0935 ret = -EINVAL;
0936 goto debug_unregister;
0937 }
0938
0939 ar->spectral.scan_count = debugfs_create_file("spectral_count",
0940 0600,
0941 ar->debug.debugfs_pdev, ar,
0942 &fops_scan_count);
0943 if (!ar->spectral.scan_count) {
0944 ath11k_warn(ar->ab, "failed to open debugfs in pdev %d\n",
0945 ar->pdev_idx);
0946 ret = -EINVAL;
0947 goto debug_unregister;
0948 }
0949
0950 ar->spectral.scan_bins = debugfs_create_file("spectral_bins",
0951 0600,
0952 ar->debug.debugfs_pdev, ar,
0953 &fops_scan_bins);
0954 if (!ar->spectral.scan_bins) {
0955 ath11k_warn(ar->ab, "failed to open debugfs in pdev %d\n",
0956 ar->pdev_idx);
0957 ret = -EINVAL;
0958 goto debug_unregister;
0959 }
0960
0961 return 0;
0962
0963 debug_unregister:
0964 ath11k_spectral_debug_unregister(ar);
0965 return ret;
0966 }
0967
0968 int ath11k_spectral_init(struct ath11k_base *ab)
0969 {
0970 struct ath11k *ar;
0971 struct ath11k_spectral *sp;
0972 struct ath11k_dbring_cap db_cap;
0973 int ret;
0974 int i;
0975
0976 if (!test_bit(WMI_TLV_SERVICE_FREQINFO_IN_METADATA,
0977 ab->wmi_ab.svc_map))
0978 return 0;
0979
0980 if (!ab->hw_params.spectral.fft_sz)
0981 return 0;
0982
0983 for (i = 0; i < ab->num_radios; i++) {
0984 ar = ab->pdevs[i].ar;
0985 sp = &ar->spectral;
0986
0987 ret = ath11k_dbring_get_cap(ar->ab, ar->pdev_idx,
0988 WMI_DIRECT_BUF_SPECTRAL,
0989 &db_cap);
0990 if (ret)
0991 continue;
0992
0993 idr_init(&sp->rx_ring.bufs_idr);
0994 spin_lock_init(&sp->rx_ring.idr_lock);
0995 spin_lock_init(&sp->lock);
0996
0997 ret = ath11k_spectral_ring_alloc(ar, &db_cap);
0998 if (ret) {
0999 ath11k_warn(ab, "failed to init spectral ring for pdev %d\n",
1000 i);
1001 goto deinit;
1002 }
1003
1004 spin_lock_bh(&sp->lock);
1005
1006 sp->mode = ATH11K_SPECTRAL_DISABLED;
1007 sp->count = ATH11K_WMI_SPECTRAL_COUNT_DEFAULT;
1008 sp->fft_size = ATH11K_WMI_SPECTRAL_FFT_SIZE_DEFAULT;
1009 sp->enabled = true;
1010
1011 spin_unlock_bh(&sp->lock);
1012
1013 ret = ath11k_spectral_debug_register(ar);
1014 if (ret) {
1015 ath11k_warn(ab, "failed to register spectral for pdev %d\n",
1016 i);
1017 goto deinit;
1018 }
1019 }
1020
1021 return 0;
1022
1023 deinit:
1024 ath11k_spectral_deinit(ab);
1025 return ret;
1026 }
1027
1028 enum ath11k_spectral_mode ath11k_spectral_get_mode(struct ath11k *ar)
1029 {
1030 if (ar->spectral.enabled)
1031 return ar->spectral.mode;
1032 else
1033 return ATH11K_SPECTRAL_DISABLED;
1034 }
1035
1036 struct ath11k_dbring *ath11k_spectral_get_dbring(struct ath11k *ar)
1037 {
1038 if (ar->spectral.enabled)
1039 return &ar->spectral.rx_ring;
1040 else
1041 return NULL;
1042 }