1 // SPDX-License-Identifier: ISC
3 * Copyright (c) 2013-2017 Qualcomm Atheros, Inc.
6 #include <linux/relay.h>
11 static void send_fft_sample(struct ath10k
*ar
,
12 const struct fft_sample_tlv
*fft_sample_tlv
)
16 if (!ar
->spectral
.rfs_chan_spec_scan
)
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
);
24 static uint8_t get_max_exp(s8 max_index
, u16 max_magnitude
, size_t bin_len
,
32 /* peak index outside of bins */
33 if (dc_pos
< max_index
|| -dc_pos
>= max_index
)
36 for (max_exp
= 0; max_exp
< 8; max_exp
++) {
37 if (data
[dc_pos
+ max_index
] == (max_magnitude
>> max_exp
))
41 /* max_exp not found */
42 if (data
[dc_pos
+ max_index
] != (max_magnitude
>> max_exp
))
48 static inline size_t ath10k_spectral_fix_bin_size(struct ath10k
*ar
,
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.
57 if (!is_power_of_2(bin_len
))
58 bin_len
-= ar
->hw_params
.spectral_bin_discard
;
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
)
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
;
75 fft_sample
= (struct fft_sample_ath10k
*)&buf
;
77 bin_len
= ath10k_spectral_fix_bin_size(ar
, bin_len
);
79 if (bin_len
< 64 || bin_len
> SPECTRAL_ATH10K_MAX_NUM_BINS
)
82 reg0
= __le32_to_cpu(fftr
->reg0
);
83 reg1
= __le32_to_cpu(fftr
->reg1
);
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
);
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.
92 switch (phyerr
->chan_width_mhz
) {
94 fft_sample
->chan_width_mhz
= 22;
97 fft_sample
->chan_width_mhz
= 44;
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.
108 fft_sample
->chan_width_mhz
= 88;
111 fft_sample
->chan_width_mhz
= phyerr
->chan_width_mhz
;
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
);
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
;
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
);
127 freq1
= phyerr
->freq1
;
128 freq2
= phyerr
->freq2
;
129 fft_sample
->freq1
= __cpu_to_be16(freq1
);
130 fft_sample
->freq2
= __cpu_to_be16(freq2
);
132 chain_idx
= MS(reg0
, SEARCH_FFT_REPORT_REG0_FFT_CHN_IDX
);
134 fft_sample
->noise
= __cpu_to_be16(phyerr
->nf_chains
[chain_idx
]);
137 bins
+= sizeof(*fftr
) + ar
->hw_params
.spectral_bin_offset
;
139 fft_sample
->tsf
= __cpu_to_be64(tsf
);
141 /* max_exp has been directly reported by previous hardware (ath9k),
142 * maybe its possible to get it by other means?
144 fft_sample
->max_exp
= get_max_exp(fft_sample
->max_index
, peak_mag
,
147 memcpy(fft_sample
->data
, bins
, bin_len
);
149 /* DC value (value in the middle) is the blind spot of the spectral
150 * sample and invalid, interpolate it.
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;
156 send_fft_sample(ar
, &fft_sample
->tlv
);
161 static struct ath10k_vif
*ath10k_get_spectral_vdev(struct ath10k
*ar
)
163 struct ath10k_vif
*arvif
;
165 lockdep_assert_held(&ar
->conf_mutex
);
167 if (list_empty(&ar
->arvifs
))
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
)
175 /* otherwise, return the first vif. */
176 return list_first_entry(&ar
->arvifs
, typeof(*arvif
), list
);
179 static int ath10k_spectral_scan_trigger(struct ath10k
*ar
)
181 struct ath10k_vif
*arvif
;
185 lockdep_assert_held(&ar
->conf_mutex
);
187 arvif
= ath10k_get_spectral_vdev(ar
);
190 vdev_id
= arvif
->vdev_id
;
192 if (ar
->spectral
.mode
== SPECTRAL_DISABLED
)
195 res
= ath10k_wmi_vdev_spectral_enable(ar
, vdev_id
,
196 WMI_SPECTRAL_TRIGGER_CMD_CLEAR
,
197 WMI_SPECTRAL_ENABLE_CMD_ENABLE
);
201 res
= ath10k_wmi_vdev_spectral_enable(ar
, vdev_id
,
202 WMI_SPECTRAL_TRIGGER_CMD_TRIGGER
,
203 WMI_SPECTRAL_ENABLE_CMD_ENABLE
);
210 static int ath10k_spectral_scan_config(struct ath10k
*ar
,
211 enum ath10k_spectral_mode mode
)
213 struct wmi_vdev_spectral_conf_arg arg
;
214 struct ath10k_vif
*arvif
;
215 int vdev_id
, count
, res
= 0;
217 lockdep_assert_held(&ar
->conf_mutex
);
219 arvif
= ath10k_get_spectral_vdev(ar
);
223 vdev_id
= arvif
->vdev_id
;
225 arvif
->spectral_enabled
= (mode
!= SPECTRAL_DISABLED
);
226 ar
->spectral
.mode
= mode
;
228 res
= ath10k_wmi_vdev_spectral_enable(ar
, vdev_id
,
229 WMI_SPECTRAL_TRIGGER_CMD_CLEAR
,
230 WMI_SPECTRAL_ENABLE_CMD_DISABLE
);
232 ath10k_warn(ar
, "failed to enable spectral scan: %d\n", res
);
236 if (mode
== SPECTRAL_DISABLED
)
239 if (mode
== SPECTRAL_BACKGROUND
)
240 count
= WMI_SPECTRAL_COUNT_DEFAULT
;
242 count
= max_t(u8
, 1, ar
->spectral
.config
.count
);
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
;
264 res
= ath10k_wmi_vdev_spectral_conf(ar
, &arg
);
266 ath10k_warn(ar
, "failed to configure spectral scan: %d\n", res
);
273 static ssize_t
read_file_spec_scan_ctl(struct file
*file
, char __user
*user_buf
,
274 size_t count
, loff_t
*ppos
)
276 struct ath10k
*ar
= file
->private_data
;
279 enum ath10k_spectral_mode spectral_mode
;
281 mutex_lock(&ar
->conf_mutex
);
282 spectral_mode
= ar
->spectral
.mode
;
283 mutex_unlock(&ar
->conf_mutex
);
285 switch (spectral_mode
) {
286 case SPECTRAL_DISABLED
:
289 case SPECTRAL_BACKGROUND
:
292 case SPECTRAL_MANUAL
:
298 return simple_read_from_buffer(user_buf
, count
, ppos
, mode
, len
);
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
)
305 struct ath10k
*ar
= file
->private_data
;
310 len
= min(count
, sizeof(buf
) - 1);
311 if (copy_from_user(buf
, user_buf
, len
))
316 mutex_lock(&ar
->conf_mutex
);
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
324 res
= ath10k_spectral_scan_config(ar
,
327 ath10k_warn(ar
, "failed to reconfigure spectral scan: %d\n",
330 res
= ath10k_spectral_scan_trigger(ar
);
332 ath10k_warn(ar
, "failed to trigger spectral scan: %d\n",
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
);
348 mutex_unlock(&ar
->conf_mutex
);
356 static const struct file_operations fops_spec_scan_ctl
= {
357 .read
= read_file_spec_scan_ctl
,
358 .write
= write_file_spec_scan_ctl
,
360 .owner
= THIS_MODULE
,
361 .llseek
= default_llseek
,
364 static ssize_t
read_file_spectral_count(struct file
*file
,
365 char __user
*user_buf
,
366 size_t count
, loff_t
*ppos
)
368 struct ath10k
*ar
= file
->private_data
;
373 mutex_lock(&ar
->conf_mutex
);
374 spectral_count
= ar
->spectral
.config
.count
;
375 mutex_unlock(&ar
->conf_mutex
);
377 len
= sprintf(buf
, "%d\n", spectral_count
);
378 return simple_read_from_buffer(user_buf
, count
, ppos
, buf
, len
);
381 static ssize_t
write_file_spectral_count(struct file
*file
,
382 const char __user
*user_buf
,
383 size_t count
, loff_t
*ppos
)
385 struct ath10k
*ar
= file
->private_data
;
390 len
= min(count
, sizeof(buf
) - 1);
391 if (copy_from_user(buf
, user_buf
, len
))
395 if (kstrtoul(buf
, 0, &val
))
401 mutex_lock(&ar
->conf_mutex
);
402 ar
->spectral
.config
.count
= val
;
403 mutex_unlock(&ar
->conf_mutex
);
408 static const struct file_operations fops_spectral_count
= {
409 .read
= read_file_spectral_count
,
410 .write
= write_file_spectral_count
,
412 .owner
= THIS_MODULE
,
413 .llseek
= default_llseek
,
416 static ssize_t
read_file_spectral_bins(struct file
*file
,
417 char __user
*user_buf
,
418 size_t count
, loff_t
*ppos
)
420 struct ath10k
*ar
= file
->private_data
;
422 unsigned int bins
, fft_size
, bin_scale
;
425 mutex_lock(&ar
->conf_mutex
);
427 fft_size
= ar
->spectral
.config
.fft_size
;
428 bin_scale
= WMI_SPECTRAL_BIN_SCALE_DEFAULT
;
429 bins
= 1 << (fft_size
- bin_scale
);
431 mutex_unlock(&ar
->conf_mutex
);
433 len
= sprintf(buf
, "%d\n", bins
);
434 return simple_read_from_buffer(user_buf
, count
, ppos
, buf
, len
);
437 static ssize_t
write_file_spectral_bins(struct file
*file
,
438 const char __user
*user_buf
,
439 size_t count
, loff_t
*ppos
)
441 struct ath10k
*ar
= file
->private_data
;
446 len
= min(count
, sizeof(buf
) - 1);
447 if (copy_from_user(buf
, user_buf
, len
))
451 if (kstrtoul(buf
, 0, &val
))
454 if (val
< 64 || val
> SPECTRAL_ATH10K_MAX_NUM_BINS
)
457 if (!is_power_of_2(val
))
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
);
468 static const struct file_operations fops_spectral_bins
= {
469 .read
= read_file_spectral_bins
,
470 .write
= write_file_spectral_bins
,
472 .owner
= THIS_MODULE
,
473 .llseek
= default_llseek
,
476 static struct dentry
*create_buf_file_handler(const char *filename
,
477 struct dentry
*parent
,
479 struct rchan_buf
*buf
,
482 struct dentry
*buf_file
;
484 buf_file
= debugfs_create_file(filename
, mode
, parent
, buf
,
485 &relay_file_operations
);
486 if (IS_ERR(buf_file
))
493 static int remove_buf_file_handler(struct dentry
*dentry
)
495 debugfs_remove(dentry
);
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
,
505 int ath10k_spectral_start(struct ath10k
*ar
)
507 struct ath10k_vif
*arvif
;
509 lockdep_assert_held(&ar
->conf_mutex
);
511 list_for_each_entry(arvif
, &ar
->arvifs
, list
)
512 arvif
->spectral_enabled
= 0;
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
;
521 int ath10k_spectral_vif_stop(struct ath10k_vif
*arvif
)
523 if (!arvif
->spectral_enabled
)
526 return ath10k_spectral_scan_config(arvif
->ar
, SPECTRAL_DISABLED
);
529 int ath10k_spectral_create(struct ath10k
*ar
)
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.
534 ar
->spectral
.rfs_chan_spec_scan
= relay_open("spectral_scan",
535 ar
->debug
.debugfs_phy
,
537 &rfs_spec_scan_cb
, NULL
);
538 debugfs_create_file("spectral_scan_ctl",
540 ar
->debug
.debugfs_phy
, ar
,
541 &fops_spec_scan_ctl
);
542 debugfs_create_file("spectral_count",
544 ar
->debug
.debugfs_phy
, ar
,
545 &fops_spectral_count
);
546 debugfs_create_file("spectral_bins",
548 ar
->debug
.debugfs_phy
, ar
,
549 &fops_spectral_bins
);
554 void ath10k_spectral_destroy(struct ath10k
*ar
)
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
;