Linux Audio

Check our new training course

Linux BSP upgrade and security maintenance

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