cachepc-linux

Fork of AMDESE/linux with modifications for CachePC side-channel attack
git clone https://git.sinitax.com/sinitax/cachepc-linux
Log | Files | Refs | README | LICENSE | sfeed.txt

spectral.c (28215B)


      1// SPDX-License-Identifier: BSD-3-Clause-Clear
      2/*
      3 * Copyright (c) 2019-2020 The Linux Foundation. All rights reserved.
      4 */
      5
      6#include <linux/relay.h>
      7#include "core.h"
      8#include "debug.h"
      9
     10#define ATH11K_SPECTRAL_NUM_RESP_PER_EVENT	2
     11#define ATH11K_SPECTRAL_EVENT_TIMEOUT_MS	1
     12
     13#define ATH11K_SPECTRAL_DWORD_SIZE		4
     14#define ATH11K_SPECTRAL_MIN_BINS		32
     15#define ATH11K_SPECTRAL_MIN_IB_BINS		(ATH11K_SPECTRAL_MIN_BINS >> 1)
     16#define ATH11K_SPECTRAL_MAX_IB_BINS(x)	((x)->hw_params.spectral.max_fft_bins >> 1)
     17
     18#define ATH11K_SPECTRAL_SCAN_COUNT_MAX		4095
     19
     20/* Max channel computed by sum of 2g and 5g band channels */
     21#define ATH11K_SPECTRAL_TOTAL_CHANNEL		41
     22#define ATH11K_SPECTRAL_SAMPLES_PER_CHANNEL	70
     23#define ATH11K_SPECTRAL_PER_SAMPLE_SIZE(x)	(sizeof(struct fft_sample_ath11k) + \
     24						 ATH11K_SPECTRAL_MAX_IB_BINS(x))
     25#define ATH11K_SPECTRAL_TOTAL_SAMPLE		(ATH11K_SPECTRAL_TOTAL_CHANNEL * \
     26						 ATH11K_SPECTRAL_SAMPLES_PER_CHANNEL)
     27#define ATH11K_SPECTRAL_SUB_BUFF_SIZE(x)	ATH11K_SPECTRAL_PER_SAMPLE_SIZE(x)
     28#define ATH11K_SPECTRAL_NUM_SUB_BUF		ATH11K_SPECTRAL_TOTAL_SAMPLE
     29
     30#define ATH11K_SPECTRAL_20MHZ			20
     31#define ATH11K_SPECTRAL_40MHZ			40
     32#define ATH11K_SPECTRAL_80MHZ			80
     33
     34#define ATH11K_SPECTRAL_SIGNATURE		0xFA
     35
     36#define ATH11K_SPECTRAL_TAG_RADAR_SUMMARY	0x0
     37#define ATH11K_SPECTRAL_TAG_RADAR_FFT		0x1
     38#define ATH11K_SPECTRAL_TAG_SCAN_SUMMARY	0x2
     39#define ATH11K_SPECTRAL_TAG_SCAN_SEARCH		0x3
     40
     41#define SPECTRAL_TLV_HDR_LEN				GENMASK(15, 0)
     42#define SPECTRAL_TLV_HDR_TAG				GENMASK(23, 16)
     43#define SPECTRAL_TLV_HDR_SIGN				GENMASK(31, 24)
     44
     45#define SPECTRAL_SUMMARY_INFO0_AGC_TOTAL_GAIN		GENMASK(7, 0)
     46#define SPECTRAL_SUMMARY_INFO0_OB_FLAG			BIT(8)
     47#define SPECTRAL_SUMMARY_INFO0_GRP_IDX			GENMASK(16, 9)
     48#define SPECTRAL_SUMMARY_INFO0_RECENT_RFSAT		BIT(17)
     49#define SPECTRAL_SUMMARY_INFO0_INBAND_PWR_DB		GENMASK(27, 18)
     50#define SPECTRAL_SUMMARY_INFO0_FALSE_SCAN		BIT(28)
     51#define SPECTRAL_SUMMARY_INFO0_DETECTOR_ID		GENMASK(30, 29)
     52#define SPECTRAL_SUMMARY_INFO0_PRI80			BIT(31)
     53
     54#define SPECTRAL_SUMMARY_INFO2_PEAK_SIGNED_IDX		GENMASK(11, 0)
     55#define SPECTRAL_SUMMARY_INFO2_PEAK_MAGNITUDE		GENMASK(21, 12)
     56#define SPECTRAL_SUMMARY_INFO2_NARROWBAND_MASK		GENMASK(29, 22)
     57#define SPECTRAL_SUMMARY_INFO2_GAIN_CHANGE		BIT(30)
     58
     59struct spectral_tlv {
     60	__le32 timestamp;
     61	__le32 header;
     62} __packed;
     63
     64struct spectral_summary_fft_report {
     65	__le32 timestamp;
     66	__le32 tlv_header;
     67	__le32 info0;
     68	__le32 reserve0;
     69	__le32 info2;
     70	__le32 reserve1;
     71} __packed;
     72
     73struct ath11k_spectral_summary_report {
     74	struct wmi_dma_buf_release_meta_data meta;
     75	u32 timestamp;
     76	u8 agc_total_gain;
     77	u8 grp_idx;
     78	u16 inb_pwr_db;
     79	s16 peak_idx;
     80	u16 peak_mag;
     81	u8 detector_id;
     82	bool out_of_band_flag;
     83	bool rf_saturation;
     84	bool primary80;
     85	bool gain_change;
     86	bool false_scan;
     87};
     88
     89#define SPECTRAL_FFT_REPORT_INFO0_DETECTOR_ID		GENMASK(1, 0)
     90#define SPECTRAL_FFT_REPORT_INFO0_FFT_NUM		GENMASK(4, 2)
     91#define SPECTRAL_FFT_REPORT_INFO0_RADAR_CHECK		GENMASK(16, 5)
     92#define SPECTRAL_FFT_REPORT_INFO0_PEAK_SIGNED_IDX	GENMASK(27, 17)
     93#define SPECTRAL_FFT_REPORT_INFO0_CHAIN_IDX		GENMASK(30, 28)
     94
     95#define SPECTRAL_FFT_REPORT_INFO1_BASE_PWR_DB		GENMASK(8, 0)
     96#define SPECTRAL_FFT_REPORT_INFO1_TOTAL_GAIN_DB		GENMASK(16, 9)
     97
     98#define SPECTRAL_FFT_REPORT_INFO2_NUM_STRONG_BINS	GENMASK(7, 0)
     99#define SPECTRAL_FFT_REPORT_INFO2_PEAK_MAGNITUDE	GENMASK(17, 8)
    100#define SPECTRAL_FFT_REPORT_INFO2_AVG_PWR_DB		GENMASK(24, 18)
    101#define SPECTRAL_FFT_REPORT_INFO2_REL_PWR_DB		GENMASK(31, 25)
    102
    103struct spectral_search_fft_report {
    104	__le32 timestamp;
    105	__le32 tlv_header;
    106	__le32 info0;
    107	__le32 info1;
    108	__le32 info2;
    109	__le32 reserve0;
    110	u8 bins[];
    111} __packed;
    112
    113struct ath11k_spectral_search_report {
    114	u32 timestamp;
    115	u8 detector_id;
    116	u8 fft_count;
    117	u16 radar_check;
    118	s16 peak_idx;
    119	u8 chain_idx;
    120	u16 base_pwr_db;
    121	u8 total_gain_db;
    122	u8 strong_bin_count;
    123	u16 peak_mag;
    124	u8 avg_pwr_db;
    125	u8 rel_pwr_db;
    126};
    127
    128static struct dentry *create_buf_file_handler(const char *filename,
    129					      struct dentry *parent,
    130					      umode_t mode,
    131					      struct rchan_buf *buf,
    132					      int *is_global)
    133{
    134	struct dentry *buf_file;
    135
    136	buf_file = debugfs_create_file(filename, mode, parent, buf,
    137				       &relay_file_operations);
    138	*is_global = 1;
    139	return buf_file;
    140}
    141
    142static int remove_buf_file_handler(struct dentry *dentry)
    143{
    144	debugfs_remove(dentry);
    145
    146	return 0;
    147}
    148
    149static const struct rchan_callbacks rfs_scan_cb = {
    150	.create_buf_file = create_buf_file_handler,
    151	.remove_buf_file = remove_buf_file_handler,
    152};
    153
    154static struct ath11k_vif *ath11k_spectral_get_vdev(struct ath11k *ar)
    155{
    156	struct ath11k_vif *arvif;
    157
    158	lockdep_assert_held(&ar->conf_mutex);
    159
    160	if (list_empty(&ar->arvifs))
    161		return NULL;
    162
    163	/* if there already is a vif doing spectral, return that. */
    164	list_for_each_entry(arvif, &ar->arvifs, list)
    165		if (arvif->spectral_enabled)
    166			return arvif;
    167
    168	/* otherwise, return the first vif. */
    169	return list_first_entry(&ar->arvifs, typeof(*arvif), list);
    170}
    171
    172static int ath11k_spectral_scan_trigger(struct ath11k *ar)
    173{
    174	struct ath11k_vif *arvif;
    175	int ret;
    176
    177	lockdep_assert_held(&ar->conf_mutex);
    178
    179	arvif = ath11k_spectral_get_vdev(ar);
    180	if (!arvif)
    181		return -ENODEV;
    182
    183	if (ar->spectral.mode == ATH11K_SPECTRAL_DISABLED)
    184		return 0;
    185
    186	ret = ath11k_wmi_vdev_spectral_enable(ar, arvif->vdev_id,
    187					      ATH11K_WMI_SPECTRAL_TRIGGER_CMD_CLEAR,
    188					      ATH11K_WMI_SPECTRAL_ENABLE_CMD_ENABLE);
    189	if (ret)
    190		return ret;
    191
    192	ret = ath11k_wmi_vdev_spectral_enable(ar, arvif->vdev_id,
    193					      ATH11K_WMI_SPECTRAL_TRIGGER_CMD_TRIGGER,
    194					      ATH11K_WMI_SPECTRAL_ENABLE_CMD_ENABLE);
    195	if (ret)
    196		return ret;
    197
    198	return 0;
    199}
    200
    201static int ath11k_spectral_scan_config(struct ath11k *ar,
    202				       enum ath11k_spectral_mode mode)
    203{
    204	struct ath11k_wmi_vdev_spectral_conf_param param = { 0 };
    205	struct ath11k_vif *arvif;
    206	int ret, count;
    207
    208	lockdep_assert_held(&ar->conf_mutex);
    209
    210	arvif = ath11k_spectral_get_vdev(ar);
    211	if (!arvif)
    212		return -ENODEV;
    213
    214	arvif->spectral_enabled = (mode != ATH11K_SPECTRAL_DISABLED);
    215
    216	spin_lock_bh(&ar->spectral.lock);
    217	ar->spectral.mode = mode;
    218	spin_unlock_bh(&ar->spectral.lock);
    219
    220	ret = ath11k_wmi_vdev_spectral_enable(ar, arvif->vdev_id,
    221					      ATH11K_WMI_SPECTRAL_TRIGGER_CMD_CLEAR,
    222					      ATH11K_WMI_SPECTRAL_ENABLE_CMD_DISABLE);
    223	if (ret) {
    224		ath11k_warn(ar->ab, "failed to enable spectral scan: %d\n", ret);
    225		return ret;
    226	}
    227
    228	if (mode == ATH11K_SPECTRAL_DISABLED)
    229		return 0;
    230
    231	if (mode == ATH11K_SPECTRAL_BACKGROUND)
    232		count = ATH11K_WMI_SPECTRAL_COUNT_DEFAULT;
    233	else
    234		count = max_t(u16, 1, ar->spectral.count);
    235
    236	param.vdev_id = arvif->vdev_id;
    237	param.scan_count = count;
    238	param.scan_fft_size = ar->spectral.fft_size;
    239	param.scan_period = ATH11K_WMI_SPECTRAL_PERIOD_DEFAULT;
    240	param.scan_priority = ATH11K_WMI_SPECTRAL_PRIORITY_DEFAULT;
    241	param.scan_gc_ena = ATH11K_WMI_SPECTRAL_GC_ENA_DEFAULT;
    242	param.scan_restart_ena = ATH11K_WMI_SPECTRAL_RESTART_ENA_DEFAULT;
    243	param.scan_noise_floor_ref = ATH11K_WMI_SPECTRAL_NOISE_FLOOR_REF_DEFAULT;
    244	param.scan_init_delay = ATH11K_WMI_SPECTRAL_INIT_DELAY_DEFAULT;
    245	param.scan_nb_tone_thr = ATH11K_WMI_SPECTRAL_NB_TONE_THR_DEFAULT;
    246	param.scan_str_bin_thr = ATH11K_WMI_SPECTRAL_STR_BIN_THR_DEFAULT;
    247	param.scan_wb_rpt_mode = ATH11K_WMI_SPECTRAL_WB_RPT_MODE_DEFAULT;
    248	param.scan_rssi_rpt_mode = ATH11K_WMI_SPECTRAL_RSSI_RPT_MODE_DEFAULT;
    249	param.scan_rssi_thr = ATH11K_WMI_SPECTRAL_RSSI_THR_DEFAULT;
    250	param.scan_pwr_format = ATH11K_WMI_SPECTRAL_PWR_FORMAT_DEFAULT;
    251	param.scan_rpt_mode = ATH11K_WMI_SPECTRAL_RPT_MODE_DEFAULT;
    252	param.scan_bin_scale = ATH11K_WMI_SPECTRAL_BIN_SCALE_DEFAULT;
    253	param.scan_dbm_adj = ATH11K_WMI_SPECTRAL_DBM_ADJ_DEFAULT;
    254	param.scan_chn_mask = ATH11K_WMI_SPECTRAL_CHN_MASK_DEFAULT;
    255
    256	ret = ath11k_wmi_vdev_spectral_conf(ar, &param);
    257	if (ret) {
    258		ath11k_warn(ar->ab, "failed to configure spectral scan: %d\n", ret);
    259		return ret;
    260	}
    261
    262	return 0;
    263}
    264
    265static ssize_t ath11k_read_file_spec_scan_ctl(struct file *file,
    266					      char __user *user_buf,
    267					      size_t count, loff_t *ppos)
    268{
    269	struct ath11k *ar = file->private_data;
    270	char *mode = "";
    271	size_t len;
    272	enum ath11k_spectral_mode spectral_mode;
    273
    274	mutex_lock(&ar->conf_mutex);
    275	spectral_mode = ar->spectral.mode;
    276	mutex_unlock(&ar->conf_mutex);
    277
    278	switch (spectral_mode) {
    279	case ATH11K_SPECTRAL_DISABLED:
    280		mode = "disable";
    281		break;
    282	case ATH11K_SPECTRAL_BACKGROUND:
    283		mode = "background";
    284		break;
    285	case ATH11K_SPECTRAL_MANUAL:
    286		mode = "manual";
    287		break;
    288	}
    289
    290	len = strlen(mode);
    291	return simple_read_from_buffer(user_buf, count, ppos, mode, len);
    292}
    293
    294static ssize_t ath11k_write_file_spec_scan_ctl(struct file *file,
    295					       const char __user *user_buf,
    296					       size_t count, loff_t *ppos)
    297{
    298	struct ath11k *ar = file->private_data;
    299	char buf[32];
    300	ssize_t len;
    301	int ret;
    302
    303	len = min(count, sizeof(buf) - 1);
    304	if (copy_from_user(buf, user_buf, len))
    305		return -EFAULT;
    306
    307	buf[len] = '\0';
    308
    309	mutex_lock(&ar->conf_mutex);
    310
    311	if (strncmp("trigger", buf, 7) == 0) {
    312		if (ar->spectral.mode == ATH11K_SPECTRAL_MANUAL ||
    313		    ar->spectral.mode == ATH11K_SPECTRAL_BACKGROUND) {
    314			/* reset the configuration to adopt possibly changed
    315			 * debugfs parameters
    316			 */
    317			ret = ath11k_spectral_scan_config(ar, ar->spectral.mode);
    318			if (ret) {
    319				ath11k_warn(ar->ab, "failed to reconfigure spectral scan: %d\n",
    320					    ret);
    321				goto unlock;
    322			}
    323
    324			ret = ath11k_spectral_scan_trigger(ar);
    325			if (ret) {
    326				ath11k_warn(ar->ab, "failed to trigger spectral scan: %d\n",
    327					    ret);
    328			}
    329		} else {
    330			ret = -EINVAL;
    331		}
    332	} else if (strncmp("background", buf, 10) == 0) {
    333		ret = ath11k_spectral_scan_config(ar, ATH11K_SPECTRAL_BACKGROUND);
    334	} else if (strncmp("manual", buf, 6) == 0) {
    335		ret = ath11k_spectral_scan_config(ar, ATH11K_SPECTRAL_MANUAL);
    336	} else if (strncmp("disable", buf, 7) == 0) {
    337		ret = ath11k_spectral_scan_config(ar, ATH11K_SPECTRAL_DISABLED);
    338	} else {
    339		ret = -EINVAL;
    340	}
    341
    342unlock:
    343	mutex_unlock(&ar->conf_mutex);
    344
    345	if (ret)
    346		return ret;
    347
    348	return count;
    349}
    350
    351static const struct file_operations fops_scan_ctl = {
    352	.read = ath11k_read_file_spec_scan_ctl,
    353	.write = ath11k_write_file_spec_scan_ctl,
    354	.open = simple_open,
    355	.owner = THIS_MODULE,
    356	.llseek = default_llseek,
    357};
    358
    359static ssize_t ath11k_read_file_spectral_count(struct file *file,
    360					       char __user *user_buf,
    361					       size_t count, loff_t *ppos)
    362{
    363	struct ath11k *ar = file->private_data;
    364	char buf[32];
    365	size_t len;
    366	u16 spectral_count;
    367
    368	mutex_lock(&ar->conf_mutex);
    369	spectral_count = ar->spectral.count;
    370	mutex_unlock(&ar->conf_mutex);
    371
    372	len = sprintf(buf, "%d\n", spectral_count);
    373	return simple_read_from_buffer(user_buf, count, ppos, buf, len);
    374}
    375
    376static ssize_t ath11k_write_file_spectral_count(struct file *file,
    377						const char __user *user_buf,
    378						size_t count, loff_t *ppos)
    379{
    380	struct ath11k *ar = file->private_data;
    381	unsigned long val;
    382	char buf[32];
    383	ssize_t len;
    384
    385	len = min(count, sizeof(buf) - 1);
    386	if (copy_from_user(buf, user_buf, len))
    387		return -EFAULT;
    388
    389	buf[len] = '\0';
    390	if (kstrtoul(buf, 0, &val))
    391		return -EINVAL;
    392
    393	if (val > ATH11K_SPECTRAL_SCAN_COUNT_MAX)
    394		return -EINVAL;
    395
    396	mutex_lock(&ar->conf_mutex);
    397	ar->spectral.count = val;
    398	mutex_unlock(&ar->conf_mutex);
    399
    400	return count;
    401}
    402
    403static const struct file_operations fops_scan_count = {
    404	.read = ath11k_read_file_spectral_count,
    405	.write = ath11k_write_file_spectral_count,
    406	.open = simple_open,
    407	.owner = THIS_MODULE,
    408	.llseek = default_llseek,
    409};
    410
    411static ssize_t ath11k_read_file_spectral_bins(struct file *file,
    412					      char __user *user_buf,
    413					      size_t count, loff_t *ppos)
    414{
    415	struct ath11k *ar = file->private_data;
    416	char buf[32];
    417	unsigned int bins, fft_size;
    418	size_t len;
    419
    420	mutex_lock(&ar->conf_mutex);
    421
    422	fft_size = ar->spectral.fft_size;
    423	bins = 1 << fft_size;
    424
    425	mutex_unlock(&ar->conf_mutex);
    426
    427	len = sprintf(buf, "%d\n", bins);
    428	return simple_read_from_buffer(user_buf, count, ppos, buf, len);
    429}
    430
    431static ssize_t ath11k_write_file_spectral_bins(struct file *file,
    432					       const char __user *user_buf,
    433					       size_t count, loff_t *ppos)
    434{
    435	struct ath11k *ar = file->private_data;
    436	unsigned long val;
    437	char buf[32];
    438	ssize_t len;
    439
    440	len = min(count, sizeof(buf) - 1);
    441	if (copy_from_user(buf, user_buf, len))
    442		return -EFAULT;
    443
    444	buf[len] = '\0';
    445	if (kstrtoul(buf, 0, &val))
    446		return -EINVAL;
    447
    448	if (val < ATH11K_SPECTRAL_MIN_BINS ||
    449	    val > ar->ab->hw_params.spectral.max_fft_bins)
    450		return -EINVAL;
    451
    452	if (!is_power_of_2(val))
    453		return -EINVAL;
    454
    455	mutex_lock(&ar->conf_mutex);
    456	ar->spectral.fft_size = ilog2(val);
    457	mutex_unlock(&ar->conf_mutex);
    458
    459	return count;
    460}
    461
    462static const struct file_operations fops_scan_bins = {
    463	.read = ath11k_read_file_spectral_bins,
    464	.write = ath11k_write_file_spectral_bins,
    465	.open = simple_open,
    466	.owner = THIS_MODULE,
    467	.llseek = default_llseek,
    468};
    469
    470static int ath11k_spectral_pull_summary(struct ath11k *ar,
    471					struct wmi_dma_buf_release_meta_data *meta,
    472					struct spectral_summary_fft_report *summary,
    473					struct ath11k_spectral_summary_report *report)
    474{
    475	report->timestamp = __le32_to_cpu(summary->timestamp);
    476	report->agc_total_gain = FIELD_GET(SPECTRAL_SUMMARY_INFO0_AGC_TOTAL_GAIN,
    477					   __le32_to_cpu(summary->info0));
    478	report->out_of_band_flag = FIELD_GET(SPECTRAL_SUMMARY_INFO0_OB_FLAG,
    479					     __le32_to_cpu(summary->info0));
    480	report->grp_idx = FIELD_GET(SPECTRAL_SUMMARY_INFO0_GRP_IDX,
    481				    __le32_to_cpu(summary->info0));
    482	report->rf_saturation = FIELD_GET(SPECTRAL_SUMMARY_INFO0_RECENT_RFSAT,
    483					  __le32_to_cpu(summary->info0));
    484	report->inb_pwr_db = FIELD_GET(SPECTRAL_SUMMARY_INFO0_INBAND_PWR_DB,
    485				       __le32_to_cpu(summary->info0));
    486	report->false_scan = FIELD_GET(SPECTRAL_SUMMARY_INFO0_FALSE_SCAN,
    487				       __le32_to_cpu(summary->info0));
    488	report->detector_id = FIELD_GET(SPECTRAL_SUMMARY_INFO0_DETECTOR_ID,
    489					__le32_to_cpu(summary->info0));
    490	report->primary80 = FIELD_GET(SPECTRAL_SUMMARY_INFO0_PRI80,
    491				      __le32_to_cpu(summary->info0));
    492	report->peak_idx = FIELD_GET(SPECTRAL_SUMMARY_INFO2_PEAK_SIGNED_IDX,
    493				     __le32_to_cpu(summary->info2));
    494	report->peak_mag = FIELD_GET(SPECTRAL_SUMMARY_INFO2_PEAK_MAGNITUDE,
    495				     __le32_to_cpu(summary->info2));
    496	report->gain_change = FIELD_GET(SPECTRAL_SUMMARY_INFO2_GAIN_CHANGE,
    497					__le32_to_cpu(summary->info2));
    498
    499	memcpy(&report->meta, meta, sizeof(*meta));
    500
    501	return 0;
    502}
    503
    504static int ath11k_spectral_pull_search(struct ath11k *ar,
    505				       struct spectral_search_fft_report *search,
    506				       struct ath11k_spectral_search_report *report)
    507{
    508	report->timestamp = __le32_to_cpu(search->timestamp);
    509	report->detector_id = FIELD_GET(SPECTRAL_FFT_REPORT_INFO0_DETECTOR_ID,
    510					__le32_to_cpu(search->info0));
    511	report->fft_count = FIELD_GET(SPECTRAL_FFT_REPORT_INFO0_FFT_NUM,
    512				      __le32_to_cpu(search->info0));
    513	report->radar_check = FIELD_GET(SPECTRAL_FFT_REPORT_INFO0_RADAR_CHECK,
    514					__le32_to_cpu(search->info0));
    515	report->peak_idx = FIELD_GET(SPECTRAL_FFT_REPORT_INFO0_PEAK_SIGNED_IDX,
    516				     __le32_to_cpu(search->info0));
    517	report->chain_idx = FIELD_GET(SPECTRAL_FFT_REPORT_INFO0_CHAIN_IDX,
    518				      __le32_to_cpu(search->info0));
    519	report->base_pwr_db = FIELD_GET(SPECTRAL_FFT_REPORT_INFO1_BASE_PWR_DB,
    520					__le32_to_cpu(search->info1));
    521	report->total_gain_db = FIELD_GET(SPECTRAL_FFT_REPORT_INFO1_TOTAL_GAIN_DB,
    522					  __le32_to_cpu(search->info1));
    523	report->strong_bin_count = FIELD_GET(SPECTRAL_FFT_REPORT_INFO2_NUM_STRONG_BINS,
    524					     __le32_to_cpu(search->info2));
    525	report->peak_mag = FIELD_GET(SPECTRAL_FFT_REPORT_INFO2_PEAK_MAGNITUDE,
    526				     __le32_to_cpu(search->info2));
    527	report->avg_pwr_db = FIELD_GET(SPECTRAL_FFT_REPORT_INFO2_AVG_PWR_DB,
    528				       __le32_to_cpu(search->info2));
    529	report->rel_pwr_db = FIELD_GET(SPECTRAL_FFT_REPORT_INFO2_REL_PWR_DB,
    530				       __le32_to_cpu(search->info2));
    531
    532	return 0;
    533}
    534
    535static u8 ath11k_spectral_get_max_exp(s8 max_index, u8 max_magnitude,
    536				      int bin_len, u8 *bins)
    537{
    538	int dc_pos;
    539	u8 max_exp;
    540
    541	dc_pos = bin_len / 2;
    542
    543	/* peak index outside of bins */
    544	if (dc_pos <= max_index || -dc_pos >= max_index)
    545		return 0;
    546
    547	for (max_exp = 0; max_exp < 8; max_exp++) {
    548		if (bins[dc_pos + max_index] == (max_magnitude >> max_exp))
    549			break;
    550	}
    551
    552	/* max_exp not found */
    553	if (bins[dc_pos + max_index] != (max_magnitude >> max_exp))
    554		return 0;
    555
    556	return max_exp;
    557}
    558
    559static void ath11k_spectral_parse_fft(u8 *outbins, u8 *inbins, int num_bins, u8 fft_sz)
    560{
    561	int i, j;
    562
    563	i = 0;
    564	j = 0;
    565	while (i < num_bins) {
    566		outbins[i] = inbins[j];
    567		i++;
    568		j += fft_sz;
    569	}
    570}
    571
    572static
    573int ath11k_spectral_process_fft(struct ath11k *ar,
    574				struct ath11k_spectral_summary_report *summary,
    575				void *data,
    576				struct fft_sample_ath11k *fft_sample,
    577				u32 data_len)
    578{
    579	struct ath11k_base *ab = ar->ab;
    580	struct spectral_search_fft_report *fft_report = data;
    581	struct ath11k_spectral_search_report search;
    582	struct spectral_tlv *tlv;
    583	int tlv_len, bin_len, num_bins;
    584	u16 length, freq;
    585	u8 chan_width_mhz, bin_sz;
    586	int ret;
    587	u32 check_length;
    588
    589	lockdep_assert_held(&ar->spectral.lock);
    590
    591	if (!ab->hw_params.spectral.fft_sz) {
    592		ath11k_warn(ab, "invalid bin size type for hw rev %d\n",
    593			    ab->hw_rev);
    594		return -EINVAL;
    595	}
    596
    597	tlv = (struct spectral_tlv *)data;
    598	tlv_len = FIELD_GET(SPECTRAL_TLV_HDR_LEN, __le32_to_cpu(tlv->header));
    599	/* convert Dword into bytes */
    600	tlv_len *= ATH11K_SPECTRAL_DWORD_SIZE;
    601	bin_len = tlv_len - ab->hw_params.spectral.fft_hdr_len;
    602
    603	if (data_len < (bin_len + sizeof(*fft_report))) {
    604		ath11k_warn(ab, "mismatch in expected bin len %d and data len %d\n",
    605			    bin_len, data_len);
    606		return -EINVAL;
    607	}
    608
    609	bin_sz = ab->hw_params.spectral.fft_sz + ab->hw_params.spectral.fft_pad_sz;
    610	num_bins = bin_len / bin_sz;
    611	/* Only In-band bins are useful to user for visualize */
    612	num_bins >>= 1;
    613
    614	if (num_bins < ATH11K_SPECTRAL_MIN_IB_BINS ||
    615	    num_bins > ATH11K_SPECTRAL_MAX_IB_BINS(ab) ||
    616	    !is_power_of_2(num_bins)) {
    617		ath11k_warn(ab, "Invalid num of bins %d\n", num_bins);
    618		return -EINVAL;
    619	}
    620
    621	check_length = sizeof(*fft_report) + (num_bins * ab->hw_params.spectral.fft_sz);
    622	ret = ath11k_dbring_validate_buffer(ar, data, check_length);
    623	if (ret) {
    624		ath11k_warn(ar->ab, "found magic value in fft data, dropping\n");
    625		return ret;
    626	}
    627
    628	ret = ath11k_spectral_pull_search(ar, data, &search);
    629	if (ret) {
    630		ath11k_warn(ab, "failed to pull search report %d\n", ret);
    631		return ret;
    632	}
    633
    634	chan_width_mhz = summary->meta.ch_width;
    635
    636	switch (chan_width_mhz) {
    637	case ATH11K_SPECTRAL_20MHZ:
    638	case ATH11K_SPECTRAL_40MHZ:
    639	case ATH11K_SPECTRAL_80MHZ:
    640		fft_sample->chan_width_mhz = chan_width_mhz;
    641		break;
    642	default:
    643		ath11k_warn(ab, "invalid channel width %d\n", chan_width_mhz);
    644		return -EINVAL;
    645	}
    646
    647	length = sizeof(*fft_sample) - sizeof(struct fft_sample_tlv) + num_bins;
    648	fft_sample->tlv.type = ATH_FFT_SAMPLE_ATH11K;
    649	fft_sample->tlv.length = __cpu_to_be16(length);
    650
    651	fft_sample->tsf = __cpu_to_be32(search.timestamp);
    652	fft_sample->max_magnitude = __cpu_to_be16(search.peak_mag);
    653	fft_sample->max_index = FIELD_GET(SPECTRAL_FFT_REPORT_INFO0_PEAK_SIGNED_IDX,
    654					  __le32_to_cpu(fft_report->info0));
    655
    656	summary->inb_pwr_db >>= 1;
    657	fft_sample->rssi = __cpu_to_be16(summary->inb_pwr_db);
    658	fft_sample->noise = __cpu_to_be32(summary->meta.noise_floor[search.chain_idx]);
    659
    660	freq = summary->meta.freq1;
    661	fft_sample->freq1 = __cpu_to_be16(freq);
    662
    663	freq = summary->meta.freq2;
    664	fft_sample->freq2 = __cpu_to_be16(freq);
    665
    666	ath11k_spectral_parse_fft(fft_sample->data, fft_report->bins, num_bins,
    667				  ab->hw_params.spectral.fft_sz);
    668
    669	fft_sample->max_exp = ath11k_spectral_get_max_exp(fft_sample->max_index,
    670							  search.peak_mag,
    671							  num_bins,
    672							  fft_sample->data);
    673
    674	if (ar->spectral.rfs_scan)
    675		relay_write(ar->spectral.rfs_scan, fft_sample,
    676			    length + sizeof(struct fft_sample_tlv));
    677
    678	return 0;
    679}
    680
    681static int ath11k_spectral_process_data(struct ath11k *ar,
    682					struct ath11k_dbring_data *param)
    683{
    684	struct ath11k_base *ab = ar->ab;
    685	struct spectral_tlv *tlv;
    686	struct spectral_summary_fft_report *summary = NULL;
    687	struct ath11k_spectral_summary_report summ_rpt;
    688	struct fft_sample_ath11k *fft_sample = NULL;
    689	u8 *data;
    690	u32 data_len, i;
    691	u8 sign, tag;
    692	int tlv_len, sample_sz;
    693	int ret;
    694	bool quit = false;
    695
    696	spin_lock_bh(&ar->spectral.lock);
    697
    698	if (!ar->spectral.enabled) {
    699		ret = -EINVAL;
    700		goto unlock;
    701	}
    702
    703	sample_sz = sizeof(*fft_sample) + ATH11K_SPECTRAL_MAX_IB_BINS(ab);
    704	fft_sample = kmalloc(sample_sz, GFP_ATOMIC);
    705	if (!fft_sample) {
    706		ret = -ENOBUFS;
    707		goto unlock;
    708	}
    709
    710	data = param->data;
    711	data_len = param->data_sz;
    712	i = 0;
    713	while (!quit && (i < data_len)) {
    714		if ((i + sizeof(*tlv)) > data_len) {
    715			ath11k_warn(ab, "failed to parse spectral tlv hdr at bytes %d\n",
    716				    i);
    717			ret = -EINVAL;
    718			goto err;
    719		}
    720
    721		tlv = (struct spectral_tlv *)&data[i];
    722		sign = FIELD_GET(SPECTRAL_TLV_HDR_SIGN,
    723				 __le32_to_cpu(tlv->header));
    724		if (sign != ATH11K_SPECTRAL_SIGNATURE) {
    725			ath11k_warn(ab, "Invalid sign 0x%x at bytes %d\n",
    726				    sign, i);
    727			ret = -EINVAL;
    728			goto err;
    729		}
    730
    731		tlv_len = FIELD_GET(SPECTRAL_TLV_HDR_LEN,
    732				    __le32_to_cpu(tlv->header));
    733		/* convert Dword into bytes */
    734		tlv_len *= ATH11K_SPECTRAL_DWORD_SIZE;
    735		if ((i + sizeof(*tlv) + tlv_len) > data_len) {
    736			ath11k_warn(ab, "failed to parse spectral tlv payload at bytes %d tlv_len:%d data_len:%d\n",
    737				    i, tlv_len, data_len);
    738			ret = -EINVAL;
    739			goto err;
    740		}
    741
    742		tag = FIELD_GET(SPECTRAL_TLV_HDR_TAG,
    743				__le32_to_cpu(tlv->header));
    744		switch (tag) {
    745		case ATH11K_SPECTRAL_TAG_SCAN_SUMMARY:
    746			/* HW bug in tlv length of summary report,
    747			 * HW report 3 DWORD size but the data payload
    748			 * is 4 DWORD size (16 bytes).
    749			 * Need to remove this workaround once HW bug fixed
    750			 */
    751			tlv_len = sizeof(*summary) - sizeof(*tlv) +
    752				  ab->hw_params.spectral.summary_pad_sz;
    753
    754			if (tlv_len < (sizeof(*summary) - sizeof(*tlv))) {
    755				ath11k_warn(ab, "failed to parse spectral summary at bytes %d tlv_len:%d\n",
    756					    i, tlv_len);
    757				ret = -EINVAL;
    758				goto err;
    759			}
    760
    761			ret = ath11k_dbring_validate_buffer(ar, data, tlv_len);
    762			if (ret) {
    763				ath11k_warn(ar->ab, "found magic value in spectral summary, dropping\n");
    764				goto err;
    765			}
    766
    767			summary = (struct spectral_summary_fft_report *)tlv;
    768			ath11k_spectral_pull_summary(ar, &param->meta,
    769						     summary, &summ_rpt);
    770			break;
    771		case ATH11K_SPECTRAL_TAG_SCAN_SEARCH:
    772			if (tlv_len < (sizeof(struct spectral_search_fft_report) -
    773				       sizeof(*tlv))) {
    774				ath11k_warn(ab, "failed to parse spectral search fft at bytes %d\n",
    775					    i);
    776				ret = -EINVAL;
    777				goto err;
    778			}
    779
    780			memset(fft_sample, 0, sample_sz);
    781			ret = ath11k_spectral_process_fft(ar, &summ_rpt, tlv,
    782							  fft_sample,
    783							  data_len - i);
    784			if (ret) {
    785				ath11k_warn(ab, "failed to process spectral fft at bytes %d\n",
    786					    i);
    787				goto err;
    788			}
    789			quit = true;
    790			break;
    791		}
    792
    793		i += sizeof(*tlv) + tlv_len;
    794	}
    795
    796	ret = 0;
    797
    798err:
    799	kfree(fft_sample);
    800unlock:
    801	spin_unlock_bh(&ar->spectral.lock);
    802	return ret;
    803}
    804
    805static int ath11k_spectral_ring_alloc(struct ath11k *ar,
    806				      struct ath11k_dbring_cap *db_cap)
    807{
    808	struct ath11k_spectral *sp = &ar->spectral;
    809	int ret;
    810
    811	ret = ath11k_dbring_srng_setup(ar, &sp->rx_ring,
    812				       0, db_cap->min_elem);
    813	if (ret) {
    814		ath11k_warn(ar->ab, "failed to setup db ring\n");
    815		return ret;
    816	}
    817
    818	ath11k_dbring_set_cfg(ar, &sp->rx_ring,
    819			      ATH11K_SPECTRAL_NUM_RESP_PER_EVENT,
    820			      ATH11K_SPECTRAL_EVENT_TIMEOUT_MS,
    821			      ath11k_spectral_process_data);
    822
    823	ret = ath11k_dbring_buf_setup(ar, &sp->rx_ring, db_cap);
    824	if (ret) {
    825		ath11k_warn(ar->ab, "failed to setup db ring buffer\n");
    826		goto srng_cleanup;
    827	}
    828
    829	ret = ath11k_dbring_wmi_cfg_setup(ar, &sp->rx_ring,
    830					  WMI_DIRECT_BUF_SPECTRAL);
    831	if (ret) {
    832		ath11k_warn(ar->ab, "failed to setup db ring cfg\n");
    833		goto buffer_cleanup;
    834	}
    835
    836	return 0;
    837
    838buffer_cleanup:
    839	ath11k_dbring_buf_cleanup(ar, &sp->rx_ring);
    840srng_cleanup:
    841	ath11k_dbring_srng_cleanup(ar, &sp->rx_ring);
    842	return ret;
    843}
    844
    845static inline void ath11k_spectral_ring_free(struct ath11k *ar)
    846{
    847	struct ath11k_spectral *sp = &ar->spectral;
    848
    849	ath11k_dbring_srng_cleanup(ar, &sp->rx_ring);
    850	ath11k_dbring_buf_cleanup(ar, &sp->rx_ring);
    851}
    852
    853static inline void ath11k_spectral_debug_unregister(struct ath11k *ar)
    854{
    855	debugfs_remove(ar->spectral.scan_bins);
    856	ar->spectral.scan_bins = NULL;
    857
    858	debugfs_remove(ar->spectral.scan_count);
    859	ar->spectral.scan_count = NULL;
    860
    861	debugfs_remove(ar->spectral.scan_ctl);
    862	ar->spectral.scan_ctl = NULL;
    863
    864	if (ar->spectral.rfs_scan) {
    865		relay_close(ar->spectral.rfs_scan);
    866		ar->spectral.rfs_scan = NULL;
    867	}
    868}
    869
    870int ath11k_spectral_vif_stop(struct ath11k_vif *arvif)
    871{
    872	if (!arvif->spectral_enabled)
    873		return 0;
    874
    875	return ath11k_spectral_scan_config(arvif->ar, ATH11K_SPECTRAL_DISABLED);
    876}
    877
    878void ath11k_spectral_reset_buffer(struct ath11k *ar)
    879{
    880	if (!ar->spectral.enabled)
    881		return;
    882
    883	if (ar->spectral.rfs_scan)
    884		relay_reset(ar->spectral.rfs_scan);
    885}
    886
    887void ath11k_spectral_deinit(struct ath11k_base *ab)
    888{
    889	struct ath11k *ar;
    890	struct ath11k_spectral *sp;
    891	int i;
    892
    893	for (i = 0; i <  ab->num_radios; i++) {
    894		ar = ab->pdevs[i].ar;
    895		sp = &ar->spectral;
    896
    897		if (!sp->enabled)
    898			continue;
    899
    900		mutex_lock(&ar->conf_mutex);
    901		ath11k_spectral_scan_config(ar, ATH11K_SPECTRAL_DISABLED);
    902		mutex_unlock(&ar->conf_mutex);
    903
    904		spin_lock_bh(&sp->lock);
    905		sp->enabled = false;
    906		spin_unlock_bh(&sp->lock);
    907
    908		ath11k_spectral_debug_unregister(ar);
    909		ath11k_spectral_ring_free(ar);
    910	}
    911}
    912
    913static inline int ath11k_spectral_debug_register(struct ath11k *ar)
    914{
    915	int ret;
    916
    917	ar->spectral.rfs_scan = relay_open("spectral_scan",
    918					   ar->debug.debugfs_pdev,
    919					   ATH11K_SPECTRAL_SUB_BUFF_SIZE(ar->ab),
    920					   ATH11K_SPECTRAL_NUM_SUB_BUF,
    921					   &rfs_scan_cb, NULL);
    922	if (!ar->spectral.rfs_scan) {
    923		ath11k_warn(ar->ab, "failed to open relay in pdev %d\n",
    924			    ar->pdev_idx);
    925		return -EINVAL;
    926	}
    927
    928	ar->spectral.scan_ctl = debugfs_create_file("spectral_scan_ctl",
    929						    0600,
    930						    ar->debug.debugfs_pdev, ar,
    931						    &fops_scan_ctl);
    932	if (!ar->spectral.scan_ctl) {
    933		ath11k_warn(ar->ab, "failed to open debugfs in pdev %d\n",
    934			    ar->pdev_idx);
    935		ret = -EINVAL;
    936		goto debug_unregister;
    937	}
    938
    939	ar->spectral.scan_count = debugfs_create_file("spectral_count",
    940						      0600,
    941						      ar->debug.debugfs_pdev, ar,
    942						      &fops_scan_count);
    943	if (!ar->spectral.scan_count) {
    944		ath11k_warn(ar->ab, "failed to open debugfs in pdev %d\n",
    945			    ar->pdev_idx);
    946		ret = -EINVAL;
    947		goto debug_unregister;
    948	}
    949
    950	ar->spectral.scan_bins = debugfs_create_file("spectral_bins",
    951						     0600,
    952						     ar->debug.debugfs_pdev, ar,
    953						     &fops_scan_bins);
    954	if (!ar->spectral.scan_bins) {
    955		ath11k_warn(ar->ab, "failed to open debugfs in pdev %d\n",
    956			    ar->pdev_idx);
    957		ret = -EINVAL;
    958		goto debug_unregister;
    959	}
    960
    961	return 0;
    962
    963debug_unregister:
    964	ath11k_spectral_debug_unregister(ar);
    965	return ret;
    966}
    967
    968int ath11k_spectral_init(struct ath11k_base *ab)
    969{
    970	struct ath11k *ar;
    971	struct ath11k_spectral *sp;
    972	struct ath11k_dbring_cap db_cap;
    973	int ret;
    974	int i;
    975
    976	if (!test_bit(WMI_TLV_SERVICE_FREQINFO_IN_METADATA,
    977		      ab->wmi_ab.svc_map))
    978		return 0;
    979
    980	if (!ab->hw_params.spectral.fft_sz)
    981		return 0;
    982
    983	for (i = 0; i < ab->num_radios; i++) {
    984		ar = ab->pdevs[i].ar;
    985		sp = &ar->spectral;
    986
    987		ret = ath11k_dbring_get_cap(ar->ab, ar->pdev_idx,
    988					    WMI_DIRECT_BUF_SPECTRAL,
    989					    &db_cap);
    990		if (ret)
    991			continue;
    992
    993		idr_init(&sp->rx_ring.bufs_idr);
    994		spin_lock_init(&sp->rx_ring.idr_lock);
    995		spin_lock_init(&sp->lock);
    996
    997		ret = ath11k_spectral_ring_alloc(ar, &db_cap);
    998		if (ret) {
    999			ath11k_warn(ab, "failed to init spectral ring for pdev %d\n",
   1000				    i);
   1001			goto deinit;
   1002		}
   1003
   1004		spin_lock_bh(&sp->lock);
   1005
   1006		sp->mode = ATH11K_SPECTRAL_DISABLED;
   1007		sp->count = ATH11K_WMI_SPECTRAL_COUNT_DEFAULT;
   1008		sp->fft_size = ATH11K_WMI_SPECTRAL_FFT_SIZE_DEFAULT;
   1009		sp->enabled = true;
   1010
   1011		spin_unlock_bh(&sp->lock);
   1012
   1013		ret = ath11k_spectral_debug_register(ar);
   1014		if (ret) {
   1015			ath11k_warn(ab, "failed to register spectral for pdev %d\n",
   1016				    i);
   1017			goto deinit;
   1018		}
   1019	}
   1020
   1021	return 0;
   1022
   1023deinit:
   1024	ath11k_spectral_deinit(ab);
   1025	return ret;
   1026}
   1027
   1028enum ath11k_spectral_mode ath11k_spectral_get_mode(struct ath11k *ar)
   1029{
   1030	if (ar->spectral.enabled)
   1031		return ar->spectral.mode;
   1032	else
   1033		return ATH11K_SPECTRAL_DISABLED;
   1034}
   1035
   1036struct ath11k_dbring *ath11k_spectral_get_dbring(struct ath11k *ar)
   1037{
   1038	if (ar->spectral.enabled)
   1039		return &ar->spectral.rx_ring;
   1040	else
   1041		return NULL;
   1042}