// SPDX-License-Identifier: BSD-3-Clause-Clear
/*
* Copyright (c) 2019-2020 The Linux Foundation. All rights reserved.
* Copyright (c) 2021-2022 Qualcomm Innovation Center, Inc. All rights reserved.
* Copyright (c) Qualcomm Technologies, Inc. and/or its subsidiaries.
*/
#include <linux/relay.h>
#include "core.h"
#include "debug.h"
#define ATH11K_SPECTRAL_NUM_RESP_PER_EVENT 2
#define ATH11K_SPECTRAL_EVENT_TIMEOUT_MS 1
#define ATH11K_SPECTRAL_DWORD_SIZE 4
#define ATH11K_SPECTRAL_MIN_BINS 32
#define ATH11K_SPECTRAL_MIN_IB_BINS (ATH11K_SPECTRAL_MIN_BINS >> 1)
#define ATH11K_SPECTRAL_MAX_IB_BINS(x) ((x)->hw_params.spectral.max_fft_bins >> 1)
#define ATH11K_SPECTRAL_SCAN_COUNT_MAX 4095
/* Max channel computed by sum of 2g and 5g band channels */
#define ATH11K_SPECTRAL_TOTAL_CHANNEL 41
#define ATH11K_SPECTRAL_SAMPLES_PER_CHANNEL 70
#define ATH11K_SPECTRAL_PER_SAMPLE_SIZE(x) (sizeof(struct fft_sample_ath11k) + \
ATH11K_SPECTRAL_MAX_IB_BINS(x))
#define ATH11K_SPECTRAL_TOTAL_SAMPLE (ATH11K_SPECTRAL_TOTAL_CHANNEL * \
ATH11K_SPECTRAL_SAMPLES_PER_CHANNEL)
#define ATH11K_SPECTRAL_SUB_BUFF_SIZE(x) ATH11K_SPECTRAL_PER_SAMPLE_SIZE(x)
#define ATH11K_SPECTRAL_NUM_SUB_BUF ATH11K_SPECTRAL_TOTAL_SAMPLE
#define ATH11K_SPECTRAL_20MHZ 20
#define ATH11K_SPECTRAL_40MHZ 40
#define ATH11K_SPECTRAL_80MHZ 80
#define ATH11K_SPECTRAL_160MHZ 160
#define ATH11K_SPECTRAL_SIGNATURE 0xFA
#define ATH11K_SPECTRAL_TAG_RADAR_SUMMARY 0x0
#define ATH11K_SPECTRAL_TAG_RADAR_FFT 0x1
#define ATH11K_SPECTRAL_TAG_SCAN_SUMMARY 0x2
#define ATH11K_SPECTRAL_TAG_SCAN_SEARCH 0x3
#define SPECTRAL_TLV_HDR_LEN GENMASK(15, 0)
#define SPECTRAL_TLV_HDR_TAG GENMASK(23, 16)
#define SPECTRAL_TLV_HDR_SIGN GENMASK(31, 24)
#define SPECTRAL_SUMMARY_INFO0_AGC_TOTAL_GAIN GENMASK(7, 0)
#define SPECTRAL_SUMMARY_INFO0_OB_FLAG BIT(8)
#define SPECTRAL_SUMMARY_INFO0_GRP_IDX GENMASK(16, 9)
#define SPECTRAL_SUMMARY_INFO0_RECENT_RFSAT BIT(17)
#define SPECTRAL_SUMMARY_INFO0_INBAND_PWR_DB GENMASK(27, 18)
#define SPECTRAL_SUMMARY_INFO0_FALSE_SCAN BIT(28)
#define SPECTRAL_SUMMARY_INFO0_DETECTOR_ID GENMASK(30, 29)
#define SPECTRAL_SUMMARY_INFO0_PRI80 BIT(31)
#define SPECTRAL_SUMMARY_INFO2_PEAK_SIGNED_IDX GENMASK(11, 0)
#define SPECTRAL_SUMMARY_INFO2_PEAK_MAGNITUDE GENMASK(21, 12)
#define SPECTRAL_SUMMARY_INFO2_NARROWBAND_MASK GENMASK(29, 22)
#define SPECTRAL_SUMMARY_INFO2_GAIN_CHANGE BIT(30)
struct spectral_tlv {
__le32 timestamp;
__le32 header;
} __packed;
struct spectral_summary_fft_report {
__le32 timestamp;
__le32 tlv_header;
__le32 info0;
__le32 reserve0;
__le32 info2;
__le32 reserve1;
} __packed;
struct ath11k_spectral_summary_report {
struct wmi_dma_buf_release_meta_data meta;
u32 timestamp;
u8 agc_total_gain;
u8 grp_idx;
u16 inb_pwr_db;
s16 peak_idx;
u16 peak_mag;
u8 detector_id;
bool out_of_band_flag;
bool rf_saturation;
bool primary80;
bool gain_change;
bool false_scan;
};
#define SPECTRAL_FFT_REPORT_INFO0_DETECTOR_ID GENMASK(1, 0)
#define SPECTRAL_FFT_REPORT_INFO0_FFT_NUM GENMASK(4, 2)
#define SPECTRAL_FFT_REPORT_INFO0_RADAR_CHECK GENMASK(16, 5)
#define SPECTRAL_FFT_REPORT_INFO0_PEAK_SIGNED_IDX GENMASK(27, 17)
#define SPECTRAL_FFT_REPORT_INFO0_CHAIN_IDX GENMASK(30, 28)
#define SPECTRAL_FFT_REPORT_INFO1_BASE_PWR_DB GENMASK(8, 0)
#define SPECTRAL_FFT_REPORT_INFO1_TOTAL_GAIN_DB GENMASK(16, 9)
#define SPECTRAL_FFT_REPORT_INFO2_NUM_STRONG_BINS GENMASK(7, 0)
#define SPECTRAL_FFT_REPORT_INFO2_PEAK_MAGNITUDE GENMASK(17, 8)
#define SPECTRAL_FFT_REPORT_INFO2_AVG_PWR_DB GENMASK(24, 18)
#define SPECTRAL_FFT_REPORT_INFO2_REL_PWR_DB GENMASK(31, 25)
struct spectral_search_fft_report {
__le32 timestamp;
__le32 tlv_header;
__le32 info0;
__le32 info1;
__le32 info2;
__le32 reserve0;
u8 bins[];
} __packed;
struct ath11k_spectral_search_report {
u32 timestamp;
u8 detector_id;
u8 fft_count;
u16 radar_check;
s16 peak_idx;
u8 chain_idx;
u16 base_pwr_db;
u8 total_gain_db;
u8 strong_bin_count;
u16 peak_mag;
u8 avg_pwr_db;
u8 rel_pwr_db;
};
static struct dentry *create_buf_file_handler(const char *filename,
struct dentry *parent,
umode_t mode,
struct rchan_buf *buf,
int *is_global)
{
struct dentry *buf_file;
buf_file = debugfs_create_file(filename, mode, parent, buf,
&relay_file_operations);
*is_global = 1;
return buf_file;
}
static int remove_buf_file_handler(struct dentry *dentry)
{
debugfs_remove(dentry);
return 0;
}
static const struct rchan_callbacks rfs_scan_cb = {
.create_buf_file = create_buf_file_handler,
.remove_buf_file = remove_buf_file_handler,
};
static struct ath11k_vif *ath11k_spectral_get_vdev(struct ath11k *ar)
{
struct ath11k_vif *arvif;
lockdep_assert_held(&ar->conf_mutex);
if (list_empty(&ar->arvifs))
return NULL;
/* if there already is a vif doing spectral, return that. */
list_for_each_entry(arvif, &ar->arvifs, list)
if (arvif->spectral_enabled)
return arvif;
/* otherwise, return the first vif. */
return list_first_entry(&ar->arvifs, typeof(*arvif), list);
}
static int ath11k_spectral_scan_trigger(struct ath11k *ar)
{
struct ath11k_vif *arvif;
int ret;
lockdep_assert_held(&ar->conf_mutex);
arvif = ath11k_spectral_get_vdev(ar);
if (!arvif)
return -ENODEV;
if (ar->spectral.mode == ATH11K_SPECTRAL_DISABLED)
return 0;
ar->spectral.is_primary