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