Commit 21254908 authored by Gregory Greenman's avatar Gregory Greenman Committed by Luca Coelho
Browse files

iwlwifi: mvm: add RFI-M support



RF Interference Mitigation is a new feature targeted to handle the
problem of interference between DDR memory and WiFi. The role of
the driver is to configure FW with the table holding a mapping
between problematic channels/bands and the corresponding frequencies.

This patch adds RFI infrastructure and adds two debugfs hooks:
- send RFI configuration command (currently with a default table) which
  will reset feature in the FW
- read the table, used by the FW (which can be a subset of the table
  that driver sent).

Signed-off-by: default avatarGregory Greenman <gregory.greenman@intel.com>
Signed-off-by: default avatarLuca Coelho <luciano.coelho@intel.com>
Link: https://lore.kernel.org/r/iwlwifi.20210210171218.2cea55a09bc7.I634b79795abad499ce442631d6672ffef8fc6d41@changeid


Signed-off-by: default avatarLuca Coelho <luciano.coelho@intel.com>
parent 3ce88247
Loading
Loading
Loading
Loading
+10 −0
Original line number Diff line number Diff line
@@ -606,6 +606,16 @@ enum iwl_system_subcmd_ids {
	 * @FW_ERROR_RECOVERY_CMD: &struct iwl_fw_error_recovery_cmd
	 */
	FW_ERROR_RECOVERY_CMD = 0x7,

	/**
	 * @RFI_CONFIG_CMD: &struct iwl_rfi_config_cmd
	 */
	RFI_CONFIG_CMD = 0xb,

	/**
	 * @RFI_GET_FREQ_TABLE_CMD: &struct iwl_rfi_config_cmd
	 */
	RFI_GET_FREQ_TABLE_CMD = 0xc,
};

#endif /* __iwl_fw_api_commands_h__ */
+60 −0
Original line number Diff line number Diff line
/* SPDX-License-Identifier: GPL-2.0 OR BSD-3-Clause */
/*
 * Copyright (C) 2020 Intel Corporation
 */
#ifndef __iwl_fw_api_rfi_h__
#define __iwl_fw_api_rfi_h__

#define IWL_RFI_LUT_ENTRY_CHANNELS_NUM 15
#define IWL_RFI_LUT_SIZE 24
#define IWL_RFI_LUT_INSTALLED_SIZE 4

/**
 * struct iwl_rfi_lut_entry - an entry in the RFI frequency LUT.
 *
 * @freq: frequency
 * @channels: channels that can be interfered at frequency freq (at most 15)
 * @bands: the corresponding bands
 */
struct iwl_rfi_lut_entry {
	__le16 freq;
	u8 channels[IWL_RFI_LUT_ENTRY_CHANNELS_NUM];
	u8 bands[IWL_RFI_LUT_ENTRY_CHANNELS_NUM];
} __packed;

/**
 * struct iwl_rfi_config_cmd - RFI configuration table
 *
 * @entry: a table can have 24 frequency/channel mappings
 * @oem: specifies if this is the default table or set by OEM
 */
struct iwl_rfi_config_cmd {
	struct iwl_rfi_lut_entry table[IWL_RFI_LUT_SIZE];
	u8 oem;
	u8 reserved[3];
} __packed; /* RFI_CONFIG_CMD_API_S_VER_1 */

/**
 * iwl_rfi_freq_table_status - status of the frequency table query
 * @RFI_FREQ_TABLE_OK: can be used
 * @RFI_FREQ_TABLE_DVFS_NOT_READY: DVFS is not ready yet, should try later
 * @RFI_FREQ_TABLE_DISABLED: the feature is disabled in FW
 */
enum iwl_rfi_freq_table_status {
	RFI_FREQ_TABLE_OK,
	RFI_FREQ_TABLE_DVFS_NOT_READY,
	RFI_FREQ_TABLE_DISABLED,
};

/**
 * struct iwl_rfi_freq_table_resp_cmd - get the rfi freq table used by FW
 *
 * @table: table used by FW
 * @status: see &iwl_rfi_freq_table_status
 */
struct iwl_rfi_freq_table_resp_cmd {
	struct iwl_rfi_lut_entry table[IWL_RFI_LUT_INSTALLED_SIZE];
	__le32 status;
} __packed; /* RFI_CONFIG_CMD_API_S_VER_1 */

#endif /* __iwl_fw_api_rfi_h__ */
+1 −0
Original line number Diff line number Diff line
@@ -441,6 +441,7 @@ enum iwl_ucode_tlv_capa {
	IWL_UCODE_TLV_CAPA_PSC_CHAN_SUPPORT		= (__force iwl_ucode_tlv_capa_t)98,

	IWL_UCODE_TLV_CAPA_BIGTK_SUPPORT		= (__force iwl_ucode_tlv_capa_t)100,
	IWL_UCODE_TLV_CAPA_RFIM_SUPPORT			= (__force iwl_ucode_tlv_capa_t)102,

	NUM_IWL_UCODE_TLV_CAPA
#ifdef __CHECKER__
+1 −0
Original line number Diff line number Diff line
@@ -6,6 +6,7 @@ iwlmvm-y += scan.o time-event.o rs.o rs-fw.o
iwlmvm-y += power.o coex.o
iwlmvm-y += tt.o offloading.o tdls.o
iwlmvm-y += ftm-responder.o ftm-initiator.o
iwlmvm-y += rfi.o
iwlmvm-$(CONFIG_IWLWIFI_DEBUGFS) += debugfs.o debugfs-vif.o
iwlmvm-$(CONFIG_IWLWIFI_LEDS) += led.o
iwlmvm-$(CONFIG_PM) += d3.o
+65 −0
Original line number Diff line number Diff line
@@ -1776,6 +1776,69 @@ iwl_dbgfs_ltr_config_write(struct iwl_mvm *mvm,
	return ret ?: count;
}

static ssize_t iwl_dbgfs_rfi_freq_table_write(struct iwl_mvm *mvm, char *buf,
					      size_t count, loff_t *ppos)
{
	int ret = 0;
	u16 op_id;

	if (kstrtou16(buf, 10, &op_id))
		return -EINVAL;

	/* value zero triggers re-sending the default table to the device */
	if (!op_id)
		ret = iwl_rfi_send_config_cmd(mvm, NULL);
	else
		ret = -EOPNOTSUPP; /* in the future a new table will be added */

	return ret ?: count;
}

/* The size computation is as follows:
 * each number needs at most 3 characters, number of rows is the size of
 * the table; So, need 5 chars for the "freq: " part and each tuple afterwards
 * needs 6 characters for numbers and 5 for the punctuation around.
 */
#define IWL_RFI_BUF_SIZE (IWL_RFI_LUT_INSTALLED_SIZE *\
				(5 + IWL_RFI_LUT_ENTRY_CHANNELS_NUM * (6 + 5)))

static ssize_t iwl_dbgfs_rfi_freq_table_read(struct file *file,
					     char __user *user_buf,
					     size_t count, loff_t *ppos)
{
	struct iwl_mvm *mvm = file->private_data;
	struct iwl_rfi_freq_table_resp_cmd *resp;
	u32 status;
	char buf[IWL_RFI_BUF_SIZE];
	int i, j, pos = 0;

	resp = iwl_rfi_get_freq_table(mvm);
	if (IS_ERR(resp))
		return PTR_ERR(resp);

	status = le32_to_cpu(resp->status);
	if (status != RFI_FREQ_TABLE_OK) {
		scnprintf(buf, IWL_RFI_BUF_SIZE, "status = %d\n", status);
		goto out;
	}

	for (i = 0; i < ARRAY_SIZE(resp->table); i++) {
		pos += scnprintf(buf + pos, IWL_RFI_BUF_SIZE - pos, "%d: ",
				 resp->table[i].freq);

		for (j = 0; j < ARRAY_SIZE(resp->table[i].channels); j++)
			pos += scnprintf(buf + pos, IWL_RFI_BUF_SIZE - pos,
					 "(%d, %d) ",
					 resp->table[i].channels[j],
					 resp->table[i].bands[j]);
		pos += scnprintf(buf + pos, IWL_RFI_BUF_SIZE - pos, "\n");
	}

out:
	kfree(resp);
	return simple_read_from_buffer(user_buf, count, ppos, buf, pos);
}

MVM_DEBUGFS_READ_WRITE_FILE_OPS(prph_reg, 64);

/* Device wide debugfs entries */
@@ -1827,6 +1890,7 @@ MVM_DEBUGFS_READ_WRITE_STA_FILE_OPS(amsdu_len, 16);
MVM_DEBUGFS_READ_WRITE_FILE_OPS(he_sniffer_params, 32);

MVM_DEBUGFS_WRITE_FILE_OPS(ltr_config, 512);
MVM_DEBUGFS_READ_WRITE_FILE_OPS(rfi_freq_table, 16);

static ssize_t iwl_dbgfs_mem_read(struct file *file, char __user *user_buf,
				  size_t count, loff_t *ppos)
@@ -2010,6 +2074,7 @@ void iwl_mvm_dbgfs_register(struct iwl_mvm *mvm, struct dentry *dbgfs_dir)
	MVM_DEBUGFS_ADD_FILE(inject_packet, mvm->debugfs_dir, 0200);
	MVM_DEBUGFS_ADD_FILE(inject_beacon_ie, mvm->debugfs_dir, 0200);
	MVM_DEBUGFS_ADD_FILE(inject_beacon_ie_restore, mvm->debugfs_dir, 0200);
	MVM_DEBUGFS_ADD_FILE(rfi_freq_table, mvm->debugfs_dir, 0600);

	if (mvm->fw->phy_integration_ver)
		MVM_DEBUGFS_ADD_FILE(phy_integration_ver, mvm->debugfs_dir, 0400);
Loading