2 * Copyright (c) 2013 Qualcomm Atheros, Inc.
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.
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.
17 #include <linux/relay.h>
21 static void send_fft_sample(struct ath10k
*ar
,
22 const struct fft_sample_tlv
*fft_sample_tlv
)
26 if (!ar
->spectral
.rfs_chan_spec_scan
)
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
);
34 static uint8_t get_max_exp(s8 max_index
, u16 max_magnitude
, size_t bin_len
,
42 /* peak index outside of bins */
43 if (dc_pos
< max_index
|| -dc_pos
>= max_index
)
46 for (max_exp
= 0; max_exp
< 8; max_exp
++) {
47 if (data
[dc_pos
+ max_index
] == (max_magnitude
>> max_exp
))
51 /* max_exp not found */
52 if (data
[dc_pos
+ max_index
] != (max_magnitude
>> max_exp
))
58 int ath10k_spectral_process_fft(struct ath10k
*ar
,
59 struct wmi_single_phyerr_rx_event
*event
,
60 struct phyerr_fft_report
*fftr
,
61 size_t bin_len
, u64 tsf
)
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
, nf_list1
, nf_list2
;
70 fft_sample
= (struct fft_sample_ath10k
*)&buf
;
72 if (bin_len
< 64 || bin_len
> SPECTRAL_ATH10K_MAX_NUM_BINS
)
75 reg0
= __le32_to_cpu(fftr
->reg0
);
76 reg1
= __le32_to_cpu(fftr
->reg1
);
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
);
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.
85 switch (event
->hdr
.chan_width_mhz
) {
87 fft_sample
->chan_width_mhz
= 22;
90 fft_sample
->chan_width_mhz
= 44;
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.
101 fft_sample
->chan_width_mhz
= 88;
104 fft_sample
->chan_width_mhz
= event
->hdr
.chan_width_mhz
;
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
);
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
= event
->hdr
.rssi_combined
;
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
);
120 freq1
= __le16_to_cpu(event
->hdr
.freq1
);
121 freq2
= __le16_to_cpu(event
->hdr
.freq2
);
122 fft_sample
->freq1
= __cpu_to_be16(freq1
);
123 fft_sample
->freq2
= __cpu_to_be16(freq2
);
125 nf_list1
= __le32_to_cpu(event
->hdr
.nf_list_1
);
126 nf_list2
= __le32_to_cpu(event
->hdr
.nf_list_2
);
127 chain_idx
= MS(reg0
, SEARCH_FFT_REPORT_REG0_FFT_CHN_IDX
);
131 fft_sample
->noise
= __cpu_to_be16(nf_list1
& 0xffffu
);
134 fft_sample
->noise
= __cpu_to_be16((nf_list1
>> 16) & 0xffffu
);
137 fft_sample
->noise
= __cpu_to_be16(nf_list2
& 0xffffu
);
140 fft_sample
->noise
= __cpu_to_be16((nf_list2
>> 16) & 0xffffu
);
145 bins
+= sizeof(*fftr
);
147 fft_sample
->tsf
= __cpu_to_be64(tsf
);
149 /* max_exp has been directly reported by previous hardware (ath9k),
150 * maybe its possible to get it by other means?
152 fft_sample
->max_exp
= get_max_exp(fft_sample
->max_index
, peak_mag
,
155 memcpy(fft_sample
->data
, bins
, bin_len
);
157 /* DC value (value in the middle) is the blind spot of the spectral
158 * sample and invalid, interpolate it.
160 dc_pos
= bin_len
/ 2;
161 fft_sample
->data
[dc_pos
] = (fft_sample
->data
[dc_pos
+ 1] +
162 fft_sample
->data
[dc_pos
- 1]) / 2;
164 send_fft_sample(ar
, &fft_sample
->tlv
);
169 static struct ath10k_vif
*ath10k_get_spectral_vdev(struct ath10k
*ar
)
171 struct ath10k_vif
*arvif
;
173 lockdep_assert_held(&ar
->conf_mutex
);
175 if (list_empty(&ar
->arvifs
))
178 /* if there already is a vif doing spectral, return that. */
179 list_for_each_entry(arvif
, &ar
->arvifs
, list
)
180 if (arvif
->spectral_enabled
)
183 /* otherwise, return the first vif. */
184 return list_first_entry(&ar
->arvifs
, typeof(*arvif
), list
);
187 static int ath10k_spectral_scan_trigger(struct ath10k
*ar
)
189 struct ath10k_vif
*arvif
;
193 lockdep_assert_held(&ar
->conf_mutex
);
195 arvif
= ath10k_get_spectral_vdev(ar
);
198 vdev_id
= arvif
->vdev_id
;
200 if (ar
->spectral
.mode
== SPECTRAL_DISABLED
)
203 res
= ath10k_wmi_vdev_spectral_enable(ar
, vdev_id
,
204 WMI_SPECTRAL_TRIGGER_CMD_CLEAR
,
205 WMI_SPECTRAL_ENABLE_CMD_ENABLE
);
209 res
= ath10k_wmi_vdev_spectral_enable(ar
, vdev_id
,
210 WMI_SPECTRAL_TRIGGER_CMD_TRIGGER
,
211 WMI_SPECTRAL_ENABLE_CMD_ENABLE
);
218 static int ath10k_spectral_scan_config(struct ath10k
*ar
,
219 enum ath10k_spectral_mode mode
)
221 struct wmi_vdev_spectral_conf_arg arg
;
222 struct ath10k_vif
*arvif
;
223 int vdev_id
, count
, res
= 0;
225 lockdep_assert_held(&ar
->conf_mutex
);
227 arvif
= ath10k_get_spectral_vdev(ar
);
231 vdev_id
= arvif
->vdev_id
;
233 arvif
->spectral_enabled
= (mode
!= SPECTRAL_DISABLED
);
234 ar
->spectral
.mode
= mode
;
236 res
= ath10k_wmi_vdev_spectral_enable(ar
, vdev_id
,
237 WMI_SPECTRAL_TRIGGER_CMD_CLEAR
,
238 WMI_SPECTRAL_ENABLE_CMD_DISABLE
);
240 ath10k_warn(ar
, "failed to enable spectral scan: %d\n", res
);
244 if (mode
== SPECTRAL_DISABLED
)
247 if (mode
== SPECTRAL_BACKGROUND
)
248 count
= WMI_SPECTRAL_COUNT_DEFAULT
;
250 count
= max_t(u8
, 1, ar
->spectral
.config
.count
);
252 arg
.vdev_id
= vdev_id
;
253 arg
.scan_count
= count
;
254 arg
.scan_period
= WMI_SPECTRAL_PERIOD_DEFAULT
;
255 arg
.scan_priority
= WMI_SPECTRAL_PRIORITY_DEFAULT
;
256 arg
.scan_fft_size
= ar
->spectral
.config
.fft_size
;
257 arg
.scan_gc_ena
= WMI_SPECTRAL_GC_ENA_DEFAULT
;
258 arg
.scan_restart_ena
= WMI_SPECTRAL_RESTART_ENA_DEFAULT
;
259 arg
.scan_noise_floor_ref
= WMI_SPECTRAL_NOISE_FLOOR_REF_DEFAULT
;
260 arg
.scan_init_delay
= WMI_SPECTRAL_INIT_DELAY_DEFAULT
;
261 arg
.scan_nb_tone_thr
= WMI_SPECTRAL_NB_TONE_THR_DEFAULT
;
262 arg
.scan_str_bin_thr
= WMI_SPECTRAL_STR_BIN_THR_DEFAULT
;
263 arg
.scan_wb_rpt_mode
= WMI_SPECTRAL_WB_RPT_MODE_DEFAULT
;
264 arg
.scan_rssi_rpt_mode
= WMI_SPECTRAL_RSSI_RPT_MODE_DEFAULT
;
265 arg
.scan_rssi_thr
= WMI_SPECTRAL_RSSI_THR_DEFAULT
;
266 arg
.scan_pwr_format
= WMI_SPECTRAL_PWR_FORMAT_DEFAULT
;
267 arg
.scan_rpt_mode
= WMI_SPECTRAL_RPT_MODE_DEFAULT
;
268 arg
.scan_bin_scale
= WMI_SPECTRAL_BIN_SCALE_DEFAULT
;
269 arg
.scan_dbm_adj
= WMI_SPECTRAL_DBM_ADJ_DEFAULT
;
270 arg
.scan_chn_mask
= WMI_SPECTRAL_CHN_MASK_DEFAULT
;
272 res
= ath10k_wmi_vdev_spectral_conf(ar
, &arg
);
274 ath10k_warn(ar
, "failed to configure spectral scan: %d\n", res
);
281 static ssize_t
read_file_spec_scan_ctl(struct file
*file
, char __user
*user_buf
,
282 size_t count
, loff_t
*ppos
)
284 struct ath10k
*ar
= file
->private_data
;
287 enum ath10k_spectral_mode spectral_mode
;
289 mutex_lock(&ar
->conf_mutex
);
290 spectral_mode
= ar
->spectral
.mode
;
291 mutex_unlock(&ar
->conf_mutex
);
293 switch (spectral_mode
) {
294 case SPECTRAL_DISABLED
:
297 case SPECTRAL_BACKGROUND
:
300 case SPECTRAL_MANUAL
:
306 return simple_read_from_buffer(user_buf
, count
, ppos
, mode
, len
);
309 static ssize_t
write_file_spec_scan_ctl(struct file
*file
,
310 const char __user
*user_buf
,
311 size_t count
, loff_t
*ppos
)
313 struct ath10k
*ar
= file
->private_data
;
318 len
= min(count
, sizeof(buf
) - 1);
319 if (copy_from_user(buf
, user_buf
, len
))
324 mutex_lock(&ar
->conf_mutex
);
326 if (strncmp("trigger", buf
, 7) == 0) {
327 if (ar
->spectral
.mode
== SPECTRAL_MANUAL
||
328 ar
->spectral
.mode
== SPECTRAL_BACKGROUND
) {
329 /* reset the configuration to adopt possibly changed
332 res
= ath10k_spectral_scan_config(ar
,
335 ath10k_warn(ar
, "failed to reconfigure spectral scan: %d\n",
338 res
= ath10k_spectral_scan_trigger(ar
);
340 ath10k_warn(ar
, "failed to trigger spectral scan: %d\n",
346 } else if (strncmp("background", buf
, 9) == 0) {
347 res
= ath10k_spectral_scan_config(ar
, SPECTRAL_BACKGROUND
);
348 } else if (strncmp("manual", buf
, 6) == 0) {
349 res
= ath10k_spectral_scan_config(ar
, SPECTRAL_MANUAL
);
350 } else if (strncmp("disable", buf
, 7) == 0) {
351 res
= ath10k_spectral_scan_config(ar
, SPECTRAL_DISABLED
);
356 mutex_unlock(&ar
->conf_mutex
);
364 static const struct file_operations fops_spec_scan_ctl
= {
365 .read
= read_file_spec_scan_ctl
,
366 .write
= write_file_spec_scan_ctl
,
368 .owner
= THIS_MODULE
,
369 .llseek
= default_llseek
,
372 static ssize_t
read_file_spectral_count(struct file
*file
,
373 char __user
*user_buf
,
374 size_t count
, loff_t
*ppos
)
376 struct ath10k
*ar
= file
->private_data
;
381 mutex_lock(&ar
->conf_mutex
);
382 spectral_count
= ar
->spectral
.config
.count
;
383 mutex_unlock(&ar
->conf_mutex
);
385 len
= sprintf(buf
, "%d\n", spectral_count
);
386 return simple_read_from_buffer(user_buf
, count
, ppos
, buf
, len
);
389 static ssize_t
write_file_spectral_count(struct file
*file
,
390 const char __user
*user_buf
,
391 size_t count
, loff_t
*ppos
)
393 struct ath10k
*ar
= file
->private_data
;
398 len
= min(count
, sizeof(buf
) - 1);
399 if (copy_from_user(buf
, user_buf
, len
))
403 if (kstrtoul(buf
, 0, &val
))
406 if (val
< 0 || val
> 255)
409 mutex_lock(&ar
->conf_mutex
);
410 ar
->spectral
.config
.count
= val
;
411 mutex_unlock(&ar
->conf_mutex
);
416 static const struct file_operations fops_spectral_count
= {
417 .read
= read_file_spectral_count
,
418 .write
= write_file_spectral_count
,
420 .owner
= THIS_MODULE
,
421 .llseek
= default_llseek
,
424 static ssize_t
read_file_spectral_bins(struct file
*file
,
425 char __user
*user_buf
,
426 size_t count
, loff_t
*ppos
)
428 struct ath10k
*ar
= file
->private_data
;
430 unsigned int len
, bins
, fft_size
, bin_scale
;
432 mutex_lock(&ar
->conf_mutex
);
434 fft_size
= ar
->spectral
.config
.fft_size
;
435 bin_scale
= WMI_SPECTRAL_BIN_SCALE_DEFAULT
;
436 bins
= 1 << (fft_size
- bin_scale
);
438 mutex_unlock(&ar
->conf_mutex
);
440 len
= sprintf(buf
, "%d\n", bins
);
441 return simple_read_from_buffer(user_buf
, count
, ppos
, buf
, len
);
444 static ssize_t
write_file_spectral_bins(struct file
*file
,
445 const char __user
*user_buf
,
446 size_t count
, loff_t
*ppos
)
448 struct ath10k
*ar
= file
->private_data
;
453 len
= min(count
, sizeof(buf
) - 1);
454 if (copy_from_user(buf
, user_buf
, len
))
458 if (kstrtoul(buf
, 0, &val
))
461 if (val
< 64 || val
> SPECTRAL_ATH10K_MAX_NUM_BINS
)
464 if (!is_power_of_2(val
))
467 mutex_lock(&ar
->conf_mutex
);
468 ar
->spectral
.config
.fft_size
= ilog2(val
);
469 ar
->spectral
.config
.fft_size
+= WMI_SPECTRAL_BIN_SCALE_DEFAULT
;
470 mutex_unlock(&ar
->conf_mutex
);
475 static const struct file_operations fops_spectral_bins
= {
476 .read
= read_file_spectral_bins
,
477 .write
= write_file_spectral_bins
,
479 .owner
= THIS_MODULE
,
480 .llseek
= default_llseek
,
483 static struct dentry
*create_buf_file_handler(const char *filename
,
484 struct dentry
*parent
,
486 struct rchan_buf
*buf
,
489 struct dentry
*buf_file
;
491 buf_file
= debugfs_create_file(filename
, mode
, parent
, buf
,
492 &relay_file_operations
);
497 static int remove_buf_file_handler(struct dentry
*dentry
)
499 debugfs_remove(dentry
);
504 static struct rchan_callbacks rfs_spec_scan_cb
= {
505 .create_buf_file
= create_buf_file_handler
,
506 .remove_buf_file
= remove_buf_file_handler
,
509 int ath10k_spectral_start(struct ath10k
*ar
)
511 struct ath10k_vif
*arvif
;
513 lockdep_assert_held(&ar
->conf_mutex
);
515 list_for_each_entry(arvif
, &ar
->arvifs
, list
)
516 arvif
->spectral_enabled
= 0;
518 ar
->spectral
.mode
= SPECTRAL_DISABLED
;
519 ar
->spectral
.config
.count
= WMI_SPECTRAL_COUNT_DEFAULT
;
520 ar
->spectral
.config
.fft_size
= WMI_SPECTRAL_FFT_SIZE_DEFAULT
;
525 int ath10k_spectral_vif_stop(struct ath10k_vif
*arvif
)
527 if (!arvif
->spectral_enabled
)
530 return ath10k_spectral_scan_config(arvif
->ar
, SPECTRAL_DISABLED
);
533 int ath10k_spectral_create(struct ath10k
*ar
)
535 ar
->spectral
.rfs_chan_spec_scan
= relay_open("spectral_scan",
536 ar
->debug
.debugfs_phy
,
538 &rfs_spec_scan_cb
, NULL
);
539 debugfs_create_file("spectral_scan_ctl",
541 ar
->debug
.debugfs_phy
, ar
,
542 &fops_spec_scan_ctl
);
543 debugfs_create_file("spectral_count",
545 ar
->debug
.debugfs_phy
, ar
,
546 &fops_spectral_count
);
547 debugfs_create_file("spectral_bins",
549 ar
->debug
.debugfs_phy
, ar
,
550 &fops_spectral_bins
);
555 void ath10k_spectral_destroy(struct ath10k
*ar
)
557 if (ar
->spectral
.rfs_chan_spec_scan
) {
558 relay_close(ar
->spectral
.rfs_chan_spec_scan
);
559 ar
->spectral
.rfs_chan_spec_scan
= NULL
;