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