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