File Index
Files and directories
Sign in
FILE

spectral.c

File preview with syntax highlighting.

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