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