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>
22 static void send_fft_sample(struct ath10k
*ar
,
23 const struct fft_sample_tlv
*fft_sample_tlv
)
27 if (!ar
->spectral
.rfs_chan_spec_scan
)
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
);
35 static uint8_t get_max_exp(s8 max_index
, u16 max_magnitude
, size_t bin_len
,
43 /* peak index outside of bins */
44 if (dc_pos
< max_index
|| -dc_pos
>= max_index
)
47 for (max_exp
= 0; max_exp
< 8; max_exp
++) {
48 if (data
[dc_pos
+ max_index
] == (max_magnitude
>> max_exp
))
52 /* max_exp not found */
53 if (data
[dc_pos
+ max_index
] != (max_magnitude
>> max_exp
))
59 int ath10k_spectral_process_fft(struct ath10k
*ar
,
60 struct wmi_phyerr_ev_arg
*phyerr
,
61 const struct phyerr_fft_report
*fftr
,
62 size_t bin_len
, u64 tsf
)
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
;
71 fft_sample
= (struct fft_sample_ath10k
*)&buf
;
73 if (bin_len
< 64 || bin_len
> SPECTRAL_ATH10K_MAX_NUM_BINS
)
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
85 reg0
= __le32_to_cpu(fftr
->reg0
);
86 reg1
= __le32_to_cpu(fftr
->reg1
);
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
);
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.
95 switch (phyerr
->chan_width_mhz
) {
97 fft_sample
->chan_width_mhz
= 22;
100 fft_sample
->chan_width_mhz
= 44;
103 /* TODO: As experiments with an analogue sender and various
104 * configuaritions (fft-sizes of 64/128/256 and 20/40/80 Mhz)
105 * show, the particular configuration of 80 MHz/64 bins does
106 * not match with the other smaples at all. Until the reason
107 * for that is found, don't report these samples.
111 fft_sample
->chan_width_mhz
= 88;
114 fft_sample
->chan_width_mhz
= phyerr
->chan_width_mhz
;
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
);
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
);
123 fft_sample
->rssi
= phyerr
->rssi_combined
;
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
);
130 freq1
= phyerr
->freq1
;
131 freq2
= phyerr
->freq2
;
132 fft_sample
->freq1
= __cpu_to_be16(freq1
);
133 fft_sample
->freq2
= __cpu_to_be16(freq2
);
135 chain_idx
= MS(reg0
, SEARCH_FFT_REPORT_REG0_FFT_CHN_IDX
);
137 fft_sample
->noise
= __cpu_to_be16(phyerr
->nf_chains
[chain_idx
]);
140 bins
+= sizeof(*fftr
);
142 fft_sample
->tsf
= __cpu_to_be64(tsf
);
144 /* max_exp has been directly reported by previous hardware (ath9k),
145 * maybe its possible to get it by other means?
147 fft_sample
->max_exp
= get_max_exp(fft_sample
->max_index
, peak_mag
,
150 memcpy(fft_sample
->data
, bins
, bin_len
);
152 /* DC value (value in the middle) is the blind spot of the spectral
153 * sample and invalid, interpolate it.
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;
159 send_fft_sample(ar
, &fft_sample
->tlv
);
164 static struct ath10k_vif
*ath10k_get_spectral_vdev(struct ath10k
*ar
)
166 struct ath10k_vif
*arvif
;
168 lockdep_assert_held(&ar
->conf_mutex
);
170 if (list_empty(&ar
->arvifs
))
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
)
178 /* otherwise, return the first vif. */
179 return list_first_entry(&ar
->arvifs
, typeof(*arvif
), list
);
182 static int ath10k_spectral_scan_trigger(struct ath10k
*ar
)
184 struct ath10k_vif
*arvif
;
188 lockdep_assert_held(&ar
->conf_mutex
);
190 arvif
= ath10k_get_spectral_vdev(ar
);
193 vdev_id
= arvif
->vdev_id
;
195 if (ar
->spectral
.mode
== SPECTRAL_DISABLED
)
198 res
= ath10k_wmi_vdev_spectral_enable(ar
, vdev_id
,
199 WMI_SPECTRAL_TRIGGER_CMD_CLEAR
,
200 WMI_SPECTRAL_ENABLE_CMD_ENABLE
);
204 res
= ath10k_wmi_vdev_spectral_enable(ar
, vdev_id
,
205 WMI_SPECTRAL_TRIGGER_CMD_TRIGGER
,
206 WMI_SPECTRAL_ENABLE_CMD_ENABLE
);
213 static int ath10k_spectral_scan_config(struct ath10k
*ar
,
214 enum ath10k_spectral_mode mode
)
216 struct wmi_vdev_spectral_conf_arg arg
;
217 struct ath10k_vif
*arvif
;
218 int vdev_id
, count
, res
= 0;
220 lockdep_assert_held(&ar
->conf_mutex
);
222 arvif
= ath10k_get_spectral_vdev(ar
);
226 vdev_id
= arvif
->vdev_id
;
228 arvif
->spectral_enabled
= (mode
!= SPECTRAL_DISABLED
);
229 ar
->spectral
.mode
= mode
;
231 res
= ath10k_wmi_vdev_spectral_enable(ar
, vdev_id
,
232 WMI_SPECTRAL_TRIGGER_CMD_CLEAR
,
233 WMI_SPECTRAL_ENABLE_CMD_DISABLE
);
235 ath10k_warn(ar
, "failed to enable spectral scan: %d\n", res
);
239 if (mode
== SPECTRAL_DISABLED
)
242 if (mode
== SPECTRAL_BACKGROUND
)
243 count
= WMI_SPECTRAL_COUNT_DEFAULT
;
245 count
= max_t(u8
, 1, ar
->spectral
.config
.count
);
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
;
267 res
= ath10k_wmi_vdev_spectral_conf(ar
, &arg
);
269 ath10k_warn(ar
, "failed to configure spectral scan: %d\n", res
);
276 static ssize_t
read_file_spec_scan_ctl(struct file
*file
, char __user
*user_buf
,
277 size_t count
, loff_t
*ppos
)
279 struct ath10k
*ar
= file
->private_data
;
282 enum ath10k_spectral_mode spectral_mode
;
284 mutex_lock(&ar
->conf_mutex
);
285 spectral_mode
= ar
->spectral
.mode
;
286 mutex_unlock(&ar
->conf_mutex
);
288 switch (spectral_mode
) {
289 case SPECTRAL_DISABLED
:
292 case SPECTRAL_BACKGROUND
:
295 case SPECTRAL_MANUAL
:
301 return simple_read_from_buffer(user_buf
, count
, ppos
, mode
, len
);
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
)
308 struct ath10k
*ar
= file
->private_data
;
313 len
= min(count
, sizeof(buf
) - 1);
314 if (copy_from_user(buf
, user_buf
, len
))
319 mutex_lock(&ar
->conf_mutex
);
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
327 res
= ath10k_spectral_scan_config(ar
,
330 ath10k_warn(ar
, "failed to reconfigure spectral scan: %d\n",
333 res
= ath10k_spectral_scan_trigger(ar
);
335 ath10k_warn(ar
, "failed to trigger spectral scan: %d\n",
341 } else if (strncmp("background", buf
, 10) == 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
);
351 mutex_unlock(&ar
->conf_mutex
);
359 static const struct file_operations fops_spec_scan_ctl
= {
360 .read
= read_file_spec_scan_ctl
,
361 .write
= write_file_spec_scan_ctl
,
363 .owner
= THIS_MODULE
,
364 .llseek
= default_llseek
,
367 static ssize_t
read_file_spectral_count(struct file
*file
,
368 char __user
*user_buf
,
369 size_t count
, loff_t
*ppos
)
371 struct ath10k
*ar
= file
->private_data
;
376 mutex_lock(&ar
->conf_mutex
);
377 spectral_count
= ar
->spectral
.config
.count
;
378 mutex_unlock(&ar
->conf_mutex
);
380 len
= sprintf(buf
, "%d\n", spectral_count
);
381 return simple_read_from_buffer(user_buf
, count
, ppos
, buf
, len
);
384 static ssize_t
write_file_spectral_count(struct file
*file
,
385 const char __user
*user_buf
,
386 size_t count
, loff_t
*ppos
)
388 struct ath10k
*ar
= file
->private_data
;
393 len
= min(count
, sizeof(buf
) - 1);
394 if (copy_from_user(buf
, user_buf
, len
))
398 if (kstrtoul(buf
, 0, &val
))
401 if (val
< 0 || val
> 255)
404 mutex_lock(&ar
->conf_mutex
);
405 ar
->spectral
.config
.count
= val
;
406 mutex_unlock(&ar
->conf_mutex
);
411 static const struct file_operations fops_spectral_count
= {
412 .read
= read_file_spectral_count
,
413 .write
= write_file_spectral_count
,
415 .owner
= THIS_MODULE
,
416 .llseek
= default_llseek
,
419 static ssize_t
read_file_spectral_bins(struct file
*file
,
420 char __user
*user_buf
,
421 size_t count
, loff_t
*ppos
)
423 struct ath10k
*ar
= file
->private_data
;
425 unsigned int len
, bins
, fft_size
, bin_scale
;
427 mutex_lock(&ar
->conf_mutex
);
429 fft_size
= ar
->spectral
.config
.fft_size
;
430 bin_scale
= WMI_SPECTRAL_BIN_SCALE_DEFAULT
;
431 bins
= 1 << (fft_size
- bin_scale
);
433 mutex_unlock(&ar
->conf_mutex
);
435 len
= sprintf(buf
, "%d\n", bins
);
436 return simple_read_from_buffer(user_buf
, count
, ppos
, buf
, len
);
439 static ssize_t
write_file_spectral_bins(struct file
*file
,
440 const char __user
*user_buf
,
441 size_t count
, loff_t
*ppos
)
443 struct ath10k
*ar
= file
->private_data
;
448 len
= min(count
, sizeof(buf
) - 1);
449 if (copy_from_user(buf
, user_buf
, len
))
453 if (kstrtoul(buf
, 0, &val
))
456 if (val
< 64 || val
> SPECTRAL_ATH10K_MAX_NUM_BINS
)
459 if (!is_power_of_2(val
))
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
);
470 static const struct file_operations fops_spectral_bins
= {
471 .read
= read_file_spectral_bins
,
472 .write
= write_file_spectral_bins
,
474 .owner
= THIS_MODULE
,
475 .llseek
= default_llseek
,
478 static struct dentry
*create_buf_file_handler(const char *filename
,
479 struct dentry
*parent
,
481 struct rchan_buf
*buf
,
484 struct dentry
*buf_file
;
486 buf_file
= debugfs_create_file(filename
, mode
, parent
, buf
,
487 &relay_file_operations
);
492 static int remove_buf_file_handler(struct dentry
*dentry
)
494 debugfs_remove(dentry
);
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
,
504 int ath10k_spectral_start(struct ath10k
*ar
)
506 struct ath10k_vif
*arvif
;
508 lockdep_assert_held(&ar
->conf_mutex
);
510 list_for_each_entry(arvif
, &ar
->arvifs
, list
)
511 arvif
->spectral_enabled
= 0;
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
;
520 int ath10k_spectral_vif_stop(struct ath10k_vif
*arvif
)
522 if (!arvif
->spectral_enabled
)
525 return ath10k_spectral_scan_config(arvif
->ar
, SPECTRAL_DISABLED
);
528 int ath10k_spectral_create(struct ath10k
*ar
)
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.
533 ar
->spectral
.rfs_chan_spec_scan
= relay_open("spectral_scan",
534 ar
->debug
.debugfs_phy
,
536 &rfs_spec_scan_cb
, NULL
);
537 debugfs_create_file("spectral_scan_ctl",
539 ar
->debug
.debugfs_phy
, ar
,
540 &fops_spec_scan_ctl
);
541 debugfs_create_file("spectral_count",
543 ar
->debug
.debugfs_phy
, ar
,
544 &fops_spectral_count
);
545 debugfs_create_file("spectral_bins",
547 ar
->debug
.debugfs_phy
, ar
,
548 &fops_spectral_bins
);
553 void ath10k_spectral_destroy(struct ath10k
*ar
)
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
;