5db6bff5193b946aa9f78b62e23a82c5a0107bb4
[linux-2.6-microblaze.git] / drivers / net / wireless / ath / ath10k / spectral.c
1 // SPDX-License-Identifier: ISC
2 /*
3  * Copyright (c) 2013-2017 Qualcomm Atheros, Inc.
4  */
5
6 #include <linux/relay.h>
7 #include "core.h"
8 #include "debug.h"
9 #include "wmi-ops.h"
10
11 static void send_fft_sample(struct ath10k *ar,
12                             const struct fft_sample_tlv *fft_sample_tlv)
13 {
14         int length;
15
16         if (!ar->spectral.rfs_chan_spec_scan)
17                 return;
18
19         length = __be16_to_cpu(fft_sample_tlv->length) +
20                  sizeof(*fft_sample_tlv);
21         relay_write(ar->spectral.rfs_chan_spec_scan, fft_sample_tlv, length);
22 }
23
24 static uint8_t get_max_exp(s8 max_index, u16 max_magnitude, size_t bin_len,
25                            u8 *data)
26 {
27         int dc_pos;
28         u8 max_exp;
29
30         dc_pos = bin_len / 2;
31
32         /* peak index outside of bins */
33         if (dc_pos < max_index || -dc_pos >= max_index)
34                 return 0;
35
36         for (max_exp = 0; max_exp < 8; max_exp++) {
37                 if (data[dc_pos + max_index] == (max_magnitude >> max_exp))
38                         break;
39         }
40
41         /* max_exp not found */
42         if (data[dc_pos + max_index] != (max_magnitude >> max_exp))
43                 return 0;
44
45         return max_exp;
46 }
47
48 static inline size_t ath10k_spectral_fix_bin_size(struct ath10k *ar,
49                                                   size_t bin_len)
50 {
51         /* some chipsets reports bin size as 2^n bytes + 'm' bytes in
52          * report mode 2. First 2^n bytes carries inband tones and last
53          * 'm' bytes carries band edge detection data mainly used in
54          * radar detection purpose. Strip last 'm' bytes to make bin size
55          * as a valid one. 'm' can take possible values of 4, 12.
56          */
57         if (!is_power_of_2(bin_len))
58                 bin_len -= ar->hw_params.spectral_bin_discard;
59
60         return bin_len;
61 }
62
63 int ath10k_spectral_process_fft(struct ath10k *ar,
64                                 struct wmi_phyerr_ev_arg *phyerr,
65                                 const struct phyerr_fft_report *fftr,
66                                 size_t bin_len, u64 tsf)
67 {
68         struct fft_sample_ath10k *fft_sample;
69         u8 buf[sizeof(*fft_sample) + SPECTRAL_ATH10K_MAX_NUM_BINS];
70         u16 freq1, freq2, total_gain_db, base_pwr_db, length, peak_mag;
71         u32 reg0, reg1;
72         u8 chain_idx, *bins;
73         int dc_pos;
74
75         fft_sample = (struct fft_sample_ath10k *)&buf;
76
77         bin_len = ath10k_spectral_fix_bin_size(ar, bin_len);
78
79         if (bin_len < 64 || bin_len > SPECTRAL_ATH10K_MAX_NUM_BINS)
80                 return -EINVAL;
81
82         reg0 = __le32_to_cpu(fftr->reg0);
83         reg1 = __le32_to_cpu(fftr->reg1);
84
85         length = sizeof(*fft_sample) - sizeof(struct fft_sample_tlv) + bin_len;
86         fft_sample->tlv.type = ATH_FFT_SAMPLE_ATH10K;
87         fft_sample->tlv.length = __cpu_to_be16(length);
88
89         /* TODO: there might be a reason why the hardware reports 20/40/80 MHz,
90          * but the results/plots suggest that its actually 22/44/88 MHz.
91          */
92         switch (phyerr->chan_width_mhz) {
93         case 20:
94                 fft_sample->chan_width_mhz = 22;
95                 break;
96         case 40:
97                 fft_sample->chan_width_mhz = 44;
98                 break;
99         case 80:
100                 /* TODO: As experiments with an analogue sender and various
101                  * configurations (fft-sizes of 64/128/256 and 20/40/80 Mhz)
102                  * show, the particular configuration of 80 MHz/64 bins does
103                  * not match with the other samples at all. Until the reason
104                  * for that is found, don't report these samples.
105                  */
106                 if (bin_len == 64)
107                         return -EINVAL;
108                 fft_sample->chan_width_mhz = 88;
109                 break;
110         default:
111                 fft_sample->chan_width_mhz = phyerr->chan_width_mhz;
112         }
113
114         fft_sample->relpwr_db = MS(reg1, SEARCH_FFT_REPORT_REG1_RELPWR_DB);
115         fft_sample->avgpwr_db = MS(reg1, SEARCH_FFT_REPORT_REG1_AVGPWR_DB);
116
117         peak_mag = MS(reg1, SEARCH_FFT_REPORT_REG1_PEAK_MAG);
118         fft_sample->max_magnitude = __cpu_to_be16(peak_mag);
119         fft_sample->max_index = MS(reg0, SEARCH_FFT_REPORT_REG0_PEAK_SIDX);
120         fft_sample->rssi = phyerr->rssi_combined;
121
122         total_gain_db = MS(reg0, SEARCH_FFT_REPORT_REG0_TOTAL_GAIN_DB);
123         base_pwr_db = MS(reg0, SEARCH_FFT_REPORT_REG0_BASE_PWR_DB);
124         fft_sample->total_gain_db = __cpu_to_be16(total_gain_db);
125         fft_sample->base_pwr_db = __cpu_to_be16(base_pwr_db);
126
127         freq1 = phyerr->freq1;
128         freq2 = phyerr->freq2;
129         fft_sample->freq1 = __cpu_to_be16(freq1);
130         fft_sample->freq2 = __cpu_to_be16(freq2);
131
132         chain_idx = MS(reg0, SEARCH_FFT_REPORT_REG0_FFT_CHN_IDX);
133
134         fft_sample->noise = __cpu_to_be16(phyerr->nf_chains[chain_idx]);
135
136         bins = (u8 *)fftr;
137         bins += sizeof(*fftr) + ar->hw_params.spectral_bin_offset;
138
139         fft_sample->tsf = __cpu_to_be64(tsf);
140
141         /* max_exp has been directly reported by previous hardware (ath9k),
142          * maybe its possible to get it by other means?
143          */
144         fft_sample->max_exp = get_max_exp(fft_sample->max_index, peak_mag,
145                                           bin_len, bins);
146
147         memcpy(fft_sample->data, bins, bin_len);
148
149         /* DC value (value in the middle) is the blind spot of the spectral
150          * sample and invalid, interpolate it.
151          */
152         dc_pos = bin_len / 2;
153         fft_sample->data[dc_pos] = (fft_sample->data[dc_pos + 1] +
154                                     fft_sample->data[dc_pos - 1]) / 2;
155
156         send_fft_sample(ar, &fft_sample->tlv);
157
158         return 0;
159 }
160
161 static struct ath10k_vif *ath10k_get_spectral_vdev(struct ath10k *ar)
162 {
163         struct ath10k_vif *arvif;
164
165         lockdep_assert_held(&ar->conf_mutex);
166
167         if (list_empty(&ar->arvifs))
168                 return NULL;
169
170         /* if there already is a vif doing spectral, return that. */
171         list_for_each_entry(arvif, &ar->arvifs, list)
172                 if (arvif->spectral_enabled)
173                         return arvif;
174
175         /* otherwise, return the first vif. */
176         return list_first_entry(&ar->arvifs, typeof(*arvif), list);
177 }
178
179 static int ath10k_spectral_scan_trigger(struct ath10k *ar)
180 {
181         struct ath10k_vif *arvif;
182         int res;
183         int vdev_id;
184
185         lockdep_assert_held(&ar->conf_mutex);
186
187         arvif = ath10k_get_spectral_vdev(ar);
188         if (!arvif)
189                 return -ENODEV;
190         vdev_id = arvif->vdev_id;
191
192         if (ar->spectral.mode == SPECTRAL_DISABLED)
193                 return 0;
194
195         res = ath10k_wmi_vdev_spectral_enable(ar, vdev_id,
196                                               WMI_SPECTRAL_TRIGGER_CMD_CLEAR,
197                                               WMI_SPECTRAL_ENABLE_CMD_ENABLE);
198         if (res < 0)
199                 return res;
200
201         res = ath10k_wmi_vdev_spectral_enable(ar, vdev_id,
202                                               WMI_SPECTRAL_TRIGGER_CMD_TRIGGER,
203                                               WMI_SPECTRAL_ENABLE_CMD_ENABLE);
204         if (res < 0)
205                 return res;
206
207         return 0;
208 }
209
210 static int ath10k_spectral_scan_config(struct ath10k *ar,
211                                        enum ath10k_spectral_mode mode)
212 {
213         struct wmi_vdev_spectral_conf_arg arg;
214         struct ath10k_vif *arvif;
215         int vdev_id, count, res = 0;
216
217         lockdep_assert_held(&ar->conf_mutex);
218
219         arvif = ath10k_get_spectral_vdev(ar);
220         if (!arvif)
221                 return -ENODEV;
222
223         vdev_id = arvif->vdev_id;
224
225         arvif->spectral_enabled = (mode != SPECTRAL_DISABLED);
226         ar->spectral.mode = mode;
227
228         res = ath10k_wmi_vdev_spectral_enable(ar, vdev_id,
229                                               WMI_SPECTRAL_TRIGGER_CMD_CLEAR,
230                                               WMI_SPECTRAL_ENABLE_CMD_DISABLE);
231         if (res < 0) {
232                 ath10k_warn(ar, "failed to enable spectral scan: %d\n", res);
233                 return res;
234         }
235
236         if (mode == SPECTRAL_DISABLED)
237                 return 0;
238
239         if (mode == SPECTRAL_BACKGROUND)
240                 count = WMI_SPECTRAL_COUNT_DEFAULT;
241         else
242                 count = max_t(u8, 1, ar->spectral.config.count);
243
244         arg.vdev_id = vdev_id;
245         arg.scan_count = count;
246         arg.scan_period = WMI_SPECTRAL_PERIOD_DEFAULT;
247         arg.scan_priority = WMI_SPECTRAL_PRIORITY_DEFAULT;
248         arg.scan_fft_size = ar->spectral.config.fft_size;
249         arg.scan_gc_ena = WMI_SPECTRAL_GC_ENA_DEFAULT;
250         arg.scan_restart_ena = WMI_SPECTRAL_RESTART_ENA_DEFAULT;
251         arg.scan_noise_floor_ref = WMI_SPECTRAL_NOISE_FLOOR_REF_DEFAULT;
252         arg.scan_init_delay = WMI_SPECTRAL_INIT_DELAY_DEFAULT;
253         arg.scan_nb_tone_thr = WMI_SPECTRAL_NB_TONE_THR_DEFAULT;
254         arg.scan_str_bin_thr = WMI_SPECTRAL_STR_BIN_THR_DEFAULT;
255         arg.scan_wb_rpt_mode = WMI_SPECTRAL_WB_RPT_MODE_DEFAULT;
256         arg.scan_rssi_rpt_mode = WMI_SPECTRAL_RSSI_RPT_MODE_DEFAULT;
257         arg.scan_rssi_thr = WMI_SPECTRAL_RSSI_THR_DEFAULT;
258         arg.scan_pwr_format = WMI_SPECTRAL_PWR_FORMAT_DEFAULT;
259         arg.scan_rpt_mode = WMI_SPECTRAL_RPT_MODE_DEFAULT;
260         arg.scan_bin_scale = WMI_SPECTRAL_BIN_SCALE_DEFAULT;
261         arg.scan_dbm_adj = WMI_SPECTRAL_DBM_ADJ_DEFAULT;
262         arg.scan_chn_mask = WMI_SPECTRAL_CHN_MASK_DEFAULT;
263
264         res = ath10k_wmi_vdev_spectral_conf(ar, &arg);
265         if (res < 0) {
266                 ath10k_warn(ar, "failed to configure spectral scan: %d\n", res);
267                 return res;
268         }
269
270         return 0;
271 }
272
273 static ssize_t read_file_spec_scan_ctl(struct file *file, char __user *user_buf,
274                                        size_t count, loff_t *ppos)
275 {
276         struct ath10k *ar = file->private_data;
277         char *mode = "";
278         size_t len;
279         enum ath10k_spectral_mode spectral_mode;
280
281         mutex_lock(&ar->conf_mutex);
282         spectral_mode = ar->spectral.mode;
283         mutex_unlock(&ar->conf_mutex);
284
285         switch (spectral_mode) {
286         case SPECTRAL_DISABLED:
287                 mode = "disable";
288                 break;
289         case SPECTRAL_BACKGROUND:
290                 mode = "background";
291                 break;
292         case SPECTRAL_MANUAL:
293                 mode = "manual";
294                 break;
295         }
296
297         len = strlen(mode);
298         return simple_read_from_buffer(user_buf, count, ppos, mode, len);
299 }
300
301 static ssize_t write_file_spec_scan_ctl(struct file *file,
302                                         const char __user *user_buf,
303                                         size_t count, loff_t *ppos)
304 {
305         struct ath10k *ar = file->private_data;
306         char buf[32];
307         ssize_t len;
308         int res;
309
310         len = min(count, sizeof(buf) - 1);
311         if (copy_from_user(buf, user_buf, len))
312                 return -EFAULT;
313
314         buf[len] = '\0';
315
316         mutex_lock(&ar->conf_mutex);
317
318         if (strncmp("trigger", buf, 7) == 0) {
319                 if (ar->spectral.mode == SPECTRAL_MANUAL ||
320                     ar->spectral.mode == SPECTRAL_BACKGROUND) {
321                         /* reset the configuration to adopt possibly changed
322                          * debugfs parameters
323                          */
324                         res = ath10k_spectral_scan_config(ar,
325                                                           ar->spectral.mode);
326                         if (res < 0) {
327                                 ath10k_warn(ar, "failed to reconfigure spectral scan: %d\n",
328                                             res);
329                         }
330                         res = ath10k_spectral_scan_trigger(ar);
331                         if (res < 0) {
332                                 ath10k_warn(ar, "failed to trigger spectral scan: %d\n",
333                                             res);
334                         }
335                 } else {
336                         res = -EINVAL;
337                 }
338         } else if (strncmp("background", buf, 10) == 0) {
339                 res = ath10k_spectral_scan_config(ar, SPECTRAL_BACKGROUND);
340         } else if (strncmp("manual", buf, 6) == 0) {
341                 res = ath10k_spectral_scan_config(ar, SPECTRAL_MANUAL);
342         } else if (strncmp("disable", buf, 7) == 0) {
343                 res = ath10k_spectral_scan_config(ar, SPECTRAL_DISABLED);
344         } else {
345                 res = -EINVAL;
346         }
347
348         mutex_unlock(&ar->conf_mutex);
349
350         if (res < 0)
351                 return res;
352
353         return count;
354 }
355
356 static const struct file_operations fops_spec_scan_ctl = {
357         .read = read_file_spec_scan_ctl,
358         .write = write_file_spec_scan_ctl,
359         .open = simple_open,
360         .owner = THIS_MODULE,
361         .llseek = default_llseek,
362 };
363
364 static ssize_t read_file_spectral_count(struct file *file,
365                                         char __user *user_buf,
366                                         size_t count, loff_t *ppos)
367 {
368         struct ath10k *ar = file->private_data;
369         char buf[32];
370         size_t len;
371         u8 spectral_count;
372
373         mutex_lock(&ar->conf_mutex);
374         spectral_count = ar->spectral.config.count;
375         mutex_unlock(&ar->conf_mutex);
376
377         len = sprintf(buf, "%d\n", spectral_count);
378         return simple_read_from_buffer(user_buf, count, ppos, buf, len);
379 }
380
381 static ssize_t write_file_spectral_count(struct file *file,
382                                          const char __user *user_buf,
383                                          size_t count, loff_t *ppos)
384 {
385         struct ath10k *ar = file->private_data;
386         unsigned long val;
387         char buf[32];
388         ssize_t len;
389
390         len = min(count, sizeof(buf) - 1);
391         if (copy_from_user(buf, user_buf, len))
392                 return -EFAULT;
393
394         buf[len] = '\0';
395         if (kstrtoul(buf, 0, &val))
396                 return -EINVAL;
397
398         if (val > 255)
399                 return -EINVAL;
400
401         mutex_lock(&ar->conf_mutex);
402         ar->spectral.config.count = val;
403         mutex_unlock(&ar->conf_mutex);
404
405         return count;
406 }
407
408 static const struct file_operations fops_spectral_count = {
409         .read = read_file_spectral_count,
410         .write = write_file_spectral_count,
411         .open = simple_open,
412         .owner = THIS_MODULE,
413         .llseek = default_llseek,
414 };
415
416 static ssize_t read_file_spectral_bins(struct file *file,
417                                        char __user *user_buf,
418                                        size_t count, loff_t *ppos)
419 {
420         struct ath10k *ar = file->private_data;
421         char buf[32];
422         unsigned int bins, fft_size, bin_scale;
423         size_t len;
424
425         mutex_lock(&ar->conf_mutex);
426
427         fft_size = ar->spectral.config.fft_size;
428         bin_scale = WMI_SPECTRAL_BIN_SCALE_DEFAULT;
429         bins = 1 << (fft_size - bin_scale);
430
431         mutex_unlock(&ar->conf_mutex);
432
433         len = sprintf(buf, "%d\n", bins);
434         return simple_read_from_buffer(user_buf, count, ppos, buf, len);
435 }
436
437 static ssize_t write_file_spectral_bins(struct file *file,
438                                         const char __user *user_buf,
439                                         size_t count, loff_t *ppos)
440 {
441         struct ath10k *ar = file->private_data;
442         unsigned long val;
443         char buf[32];
444         ssize_t len;
445
446         len = min(count, sizeof(buf) - 1);
447         if (copy_from_user(buf, user_buf, len))
448                 return -EFAULT;
449
450         buf[len] = '\0';
451         if (kstrtoul(buf, 0, &val))
452                 return -EINVAL;
453
454         if (val < 64 || val > SPECTRAL_ATH10K_MAX_NUM_BINS)
455                 return -EINVAL;
456
457         if (!is_power_of_2(val))
458                 return -EINVAL;
459
460         mutex_lock(&ar->conf_mutex);
461         ar->spectral.config.fft_size = ilog2(val);
462         ar->spectral.config.fft_size += WMI_SPECTRAL_BIN_SCALE_DEFAULT;
463         mutex_unlock(&ar->conf_mutex);
464
465         return count;
466 }
467
468 static const struct file_operations fops_spectral_bins = {
469         .read = read_file_spectral_bins,
470         .write = write_file_spectral_bins,
471         .open = simple_open,
472         .owner = THIS_MODULE,
473         .llseek = default_llseek,
474 };
475
476 static struct dentry *create_buf_file_handler(const char *filename,
477                                               struct dentry *parent,
478                                               umode_t mode,
479                                               struct rchan_buf *buf,
480                                               int *is_global)
481 {
482         struct dentry *buf_file;
483
484         buf_file = debugfs_create_file(filename, mode, parent, buf,
485                                        &relay_file_operations);
486         if (IS_ERR(buf_file))
487                 return NULL;
488
489         *is_global = 1;
490         return buf_file;
491 }
492
493 static int remove_buf_file_handler(struct dentry *dentry)
494 {
495         debugfs_remove(dentry);
496
497         return 0;
498 }
499
500 static struct rchan_callbacks rfs_spec_scan_cb = {
501         .create_buf_file = create_buf_file_handler,
502         .remove_buf_file = remove_buf_file_handler,
503 };
504
505 int ath10k_spectral_start(struct ath10k *ar)
506 {
507         struct ath10k_vif *arvif;
508
509         lockdep_assert_held(&ar->conf_mutex);
510
511         list_for_each_entry(arvif, &ar->arvifs, list)
512                 arvif->spectral_enabled = 0;
513
514         ar->spectral.mode = SPECTRAL_DISABLED;
515         ar->spectral.config.count = WMI_SPECTRAL_COUNT_DEFAULT;
516         ar->spectral.config.fft_size = WMI_SPECTRAL_FFT_SIZE_DEFAULT;
517
518         return 0;
519 }
520
521 int ath10k_spectral_vif_stop(struct ath10k_vif *arvif)
522 {
523         if (!arvif->spectral_enabled)
524                 return 0;
525
526         return ath10k_spectral_scan_config(arvif->ar, SPECTRAL_DISABLED);
527 }
528
529 int ath10k_spectral_create(struct ath10k *ar)
530 {
531         /* The buffer size covers whole channels in dual bands up to 128 bins.
532          * Scan with bigger than 128 bins needs to be run on single band each.
533          */
534         ar->spectral.rfs_chan_spec_scan = relay_open("spectral_scan",
535                                                      ar->debug.debugfs_phy,
536                                                      1140, 2500,
537                                                      &rfs_spec_scan_cb, NULL);
538         debugfs_create_file("spectral_scan_ctl",
539                             0600,
540                             ar->debug.debugfs_phy, ar,
541                             &fops_spec_scan_ctl);
542         debugfs_create_file("spectral_count",
543                             0600,
544                             ar->debug.debugfs_phy, ar,
545                             &fops_spectral_count);
546         debugfs_create_file("spectral_bins",
547                             0600,
548                             ar->debug.debugfs_phy, ar,
549                             &fops_spectral_bins);
550
551         return 0;
552 }
553
554 void ath10k_spectral_destroy(struct ath10k *ar)
555 {
556         if (ar->spectral.rfs_chan_spec_scan) {
557                 relay_close(ar->spectral.rfs_chan_spec_scan);
558                 ar->spectral.rfs_chan_spec_scan = NULL;
559         }
560 }