Commit e12cfc7b authored by Miri Korenblit's avatar Miri Korenblit Committed by Luca Coelho
Browse files

iwlwifi: mvm: enable PPAG in China



Add support for ppag in China by reading revision 2 of the ppag table
from ACPI, and passing the data to the FW.
This is needed to enable OEMs to control ppag enablement
in China.

Signed-off-by: default avatarMiri Korenblit <miriam.rachel.korenblit@intel.com>
Signed-off-by: default avatarLuca Coelho <luciano.coelho@intel.com>
Link: https://lore.kernel.org/r/iwlwifi.20210331121101.69af388d0dce.I8cfddf9e6837bf394b00390181b4b774ded19acd@changeid


Signed-off-by: default avatarLuca Coelho <luciano.coelho@intel.com>
parent e8fe3b41
Loading
Loading
Loading
Loading
+4 −5
Original line number Diff line number Diff line
@@ -181,14 +181,13 @@ union acpi_object *iwl_acpi_get_wifi_pkg(struct device *dev,
	/*
	 * We need at least two packages, one for the revision and one
	 * for the data itself.  Also check that the revision is valid
	 * (i.e. it is an integer smaller than 2, as we currently support only
	 * 2 revisions).
	 * (i.e. it is an integer (each caller has to check by itself
	 * if the returned revision is supported)).
	 */
	if (data->type != ACPI_TYPE_PACKAGE ||
	    data->package.count < 2 ||
	    data->package.elements[0].type != ACPI_TYPE_INTEGER ||
	    data->package.elements[0].integer.value > 1) {
		IWL_DEBUG_DEV_RADIO(dev, "Unsupported packages structure\n");
	    data->package.elements[0].type != ACPI_TYPE_INTEGER) {
		IWL_DEBUG_DEV_RADIO(dev, "Invalid packages structure\n");
		return ERR_PTR(-EINVAL);
	}

+2 −2
Original line number Diff line number Diff line
@@ -53,8 +53,8 @@

#define ACPI_WGDS_TABLE_SIZE		3

#define ACPI_PPAG_WIFI_DATA_SIZE	((IWL_NUM_CHAIN_LIMITS * \
					  IWL_NUM_SUB_BANDS) + 2)
#define ACPI_PPAG_WIFI_DATA_SIZE_V1	((IWL_NUM_CHAIN_LIMITS * \
					  IWL_NUM_SUB_BANDS_V1) + 2)
#define ACPI_PPAG_WIFI_DATA_SIZE_V2	((IWL_NUM_CHAIN_LIMITS * \
					  IWL_NUM_SUB_BANDS_V2) + 2)

+12 −10
Original line number Diff line number Diff line
@@ -274,7 +274,7 @@ enum iwl_dev_tx_power_cmd_mode {
#define IWL_NUM_CHAIN_TABLES	1
#define IWL_NUM_CHAIN_TABLES_V2	2
#define IWL_NUM_CHAIN_LIMITS	2
#define IWL_NUM_SUB_BANDS	5
#define IWL_NUM_SUB_BANDS_V1	5
#define IWL_NUM_SUB_BANDS_V2	11

/**
@@ -300,7 +300,7 @@ struct iwl_dev_tx_power_common {
 * @per_chain: per chain restrictions
 */
struct iwl_dev_tx_power_cmd_v3 {
	__le16 per_chain[IWL_NUM_CHAIN_TABLES][IWL_NUM_CHAIN_LIMITS][IWL_NUM_SUB_BANDS];
	__le16 per_chain[IWL_NUM_CHAIN_TABLES][IWL_NUM_CHAIN_LIMITS][IWL_NUM_SUB_BANDS_V1];
} __packed; /* TX_REDUCED_POWER_API_S_VER_3 */

#define IWL_DEV_MAX_TX_POWER 0x7FFF
@@ -313,7 +313,7 @@ struct iwl_dev_tx_power_cmd_v3 {
 * @reserved: reserved (padding)
 */
struct iwl_dev_tx_power_cmd_v4 {
	__le16 per_chain[IWL_NUM_CHAIN_TABLES][IWL_NUM_CHAIN_LIMITS][IWL_NUM_SUB_BANDS];
	__le16 per_chain[IWL_NUM_CHAIN_TABLES][IWL_NUM_CHAIN_LIMITS][IWL_NUM_SUB_BANDS_V1];
	u8 enable_ack_reduction;
	u8 reserved[3];
} __packed; /* TX_REDUCED_POWER_API_S_VER_4 */
@@ -332,7 +332,7 @@ struct iwl_dev_tx_power_cmd_v4 {
 *	BIOS values. relevant if setMode is IWL_TX_POWER_MODE_SET_SAR_TIMER
 */
struct iwl_dev_tx_power_cmd_v5 {
	__le16 per_chain[IWL_NUM_CHAIN_TABLES][IWL_NUM_CHAIN_LIMITS][IWL_NUM_SUB_BANDS];
	__le16 per_chain[IWL_NUM_CHAIN_TABLES][IWL_NUM_CHAIN_LIMITS][IWL_NUM_SUB_BANDS_V1];
	u8 enable_ack_reduction;
	u8 per_chain_restriction_changed;
	u8 reserved[2];
@@ -454,21 +454,23 @@ struct iwl_geo_tx_power_profiles_resp {

/**
 * union iwl_ppag_table_cmd - union for all versions of PPAG command
 * @v1: version 1, table revision = 0
 * @v2: version 2, table revision = 1
 * @v1: version 1
 * @v2: version 2
 *
 * @enabled: 1 if PPAG is enabled, 0 otherwise
 * @flags: bit 0 - indicates enablement of PPAG for ETSI
 *         bit 1 - indicates enablement of PPAG for CHINA BIOS
 *         bit 1 can be used only in v3 (identical to v2)
 * @gain: table of antenna gain values per chain and sub-band
 * @reserved: reserved
 */
union iwl_ppag_table_cmd {
	struct {
		__le32 enabled;
		s8 gain[IWL_NUM_CHAIN_LIMITS][IWL_NUM_SUB_BANDS];
		__le32 flags;
		s8 gain[IWL_NUM_CHAIN_LIMITS][IWL_NUM_SUB_BANDS_V1];
		s8 reserved[2];
	} v1;
	struct {
		__le32 enabled;
		__le32 flags;
		s8 gain[IWL_NUM_CHAIN_LIMITS][IWL_NUM_SUB_BANDS_V2];
		s8 reserved[2];
	} v2;
+47 −29
Original line number Diff line number Diff line
@@ -29,6 +29,9 @@

#define UCODE_VALID_OK	cpu_to_le32(0x1)

#define IWL_PPAG_MASK 3
#define IWL_PPAG_ETSI_MASK BIT(0)

struct iwl_mvm_alive_data {
	bool valid;
	u32 scd_base_addr;
@@ -773,16 +776,16 @@ int iwl_mvm_sar_select_profile(struct iwl_mvm *mvm, int prof_a, int prof_b)
	} else if (fw_has_api(&mvm->fw->ucode_capa,
			      IWL_UCODE_TLV_API_REDUCE_TX_POWER)) {
		len = sizeof(cmd.v5);
		n_subbands = IWL_NUM_SUB_BANDS;
		n_subbands = IWL_NUM_SUB_BANDS_V1;
		per_chain = cmd.v5.per_chain[0][0];
	} else if (fw_has_capa(&mvm->fw->ucode_capa,
			       IWL_UCODE_TLV_CAPA_TX_POWER_ACK)) {
		len = sizeof(cmd.v4);
		n_subbands = IWL_NUM_SUB_BANDS;
		n_subbands = IWL_NUM_SUB_BANDS_V1;
		per_chain = cmd.v4.per_chain[0][0];
	} else {
		len = sizeof(cmd.v3);
		n_subbands = IWL_NUM_SUB_BANDS;
		n_subbands = IWL_NUM_SUB_BANDS_V1;
		per_chain = cmd.v3.per_chain[0][0];
	}

@@ -909,46 +912,50 @@ static int iwl_mvm_sar_geo_init(struct iwl_mvm *mvm)

static int iwl_mvm_get_ppag_table(struct iwl_mvm *mvm)
{
	union acpi_object *wifi_pkg, *data, *enabled;
	union acpi_object *wifi_pkg, *data, *flags;
	int i, j, ret, tbl_rev, num_sub_bands;
	int idx = 2;
	s8 *gain;

	/*
	 * The 'enabled' field is the same in v1 and v2 so we can just
	 * The 'flags' field is the same in v1 and in v2 so we can just
	 * use v1 to access it.
	 */
	mvm->fwrt.ppag_table.v1.enabled = cpu_to_le32(0);
	mvm->fwrt.ppag_table.v1.flags = cpu_to_le32(0);

	data = iwl_acpi_get_object(mvm->dev, ACPI_PPAG_METHOD);
	if (IS_ERR(data))
		return PTR_ERR(data);

	/* try to read ppag table revision 1 */
	/* try to read ppag table rev 2 or 1 (both have the same data size) */
	wifi_pkg = iwl_acpi_get_wifi_pkg(mvm->dev, data,
					 ACPI_PPAG_WIFI_DATA_SIZE_V2, &tbl_rev);
	if (!IS_ERR(wifi_pkg)) {
		if (tbl_rev != 1) {
			ret = -EINVAL;
			goto out_free;
		}
		if (tbl_rev == 1 || tbl_rev == 2) {
			num_sub_bands = IWL_NUM_SUB_BANDS_V2;
			gain = mvm->fwrt.ppag_table.v2.gain[0];
		mvm->fwrt.ppag_ver = 2;
		IWL_DEBUG_RADIO(mvm, "Reading PPAG table v2 (tbl_rev=1)\n");
			mvm->fwrt.ppag_ver = tbl_rev;
			IWL_DEBUG_RADIO(mvm,
					"Reading PPAG table v2 (tbl_rev=%d)\n",
					tbl_rev);
			goto read_table;
		} else {
			ret = -EINVAL;
			goto out_free;
		}
	}

	/* try to read ppag table revision 0 */
	wifi_pkg = iwl_acpi_get_wifi_pkg(mvm->dev, data,
					 ACPI_PPAG_WIFI_DATA_SIZE, &tbl_rev);
					 ACPI_PPAG_WIFI_DATA_SIZE_V1, &tbl_rev);
	if (!IS_ERR(wifi_pkg)) {
		if (tbl_rev != 0) {
			ret = -EINVAL;
			goto out_free;
		}
		num_sub_bands = IWL_NUM_SUB_BANDS;
		num_sub_bands = IWL_NUM_SUB_BANDS_V1;
		gain = mvm->fwrt.ppag_table.v1.gain[0];
		mvm->fwrt.ppag_ver = 1;
		mvm->fwrt.ppag_ver = 0;
		IWL_DEBUG_RADIO(mvm, "Reading PPAG table v1 (tbl_rev=0)\n");
		goto read_table;
	}
@@ -956,15 +963,17 @@ static int iwl_mvm_get_ppag_table(struct iwl_mvm *mvm)
	goto out_free;

read_table:
	enabled = &wifi_pkg->package.elements[1];
	if (enabled->type != ACPI_TYPE_INTEGER ||
	    (enabled->integer.value != 0 && enabled->integer.value != 1)) {
	flags = &wifi_pkg->package.elements[1];

	if (flags->type != ACPI_TYPE_INTEGER) {
		ret = -EINVAL;
		goto out_free;
	}

	mvm->fwrt.ppag_table.v1.enabled = cpu_to_le32(enabled->integer.value);
	if (!mvm->fwrt.ppag_table.v1.enabled) {
	mvm->fwrt.ppag_table.v1.flags = cpu_to_le32(flags->integer.value &
						    IWL_PPAG_MASK);

	if (!mvm->fwrt.ppag_table.v1.flags) {
		ret = 0;
		goto out_free;
	}
@@ -992,12 +1001,13 @@ static int iwl_mvm_get_ppag_table(struct iwl_mvm *mvm)
			    (j != 0 &&
			     (gain[i * num_sub_bands + j] > ACPI_PPAG_MAX_HB ||
			      gain[i * num_sub_bands + j] < ACPI_PPAG_MIN_HB))) {
				mvm->fwrt.ppag_table.v1.enabled = cpu_to_le32(0);
				mvm->fwrt.ppag_table.v1.flags = cpu_to_le32(0);
				ret = -EINVAL;
				goto out_free;
			}
		}
	}

	ret = 0;
out_free:
	kfree(data);
@@ -1015,7 +1025,7 @@ int iwl_mvm_ppag_send_cmd(struct iwl_mvm *mvm)
				"PPAG capability not supported by FW, command not sent.\n");
		return 0;
	}
	if (!mvm->fwrt.ppag_table.v1.enabled) {
	if (!mvm->fwrt.ppag_table.v1.flags) {
		IWL_DEBUG_RADIO(mvm, "PPAG not enabled, command not sent.\n");
		return 0;
	}
@@ -1024,20 +1034,28 @@ int iwl_mvm_ppag_send_cmd(struct iwl_mvm *mvm)
					PER_PLATFORM_ANT_GAIN_CMD,
					IWL_FW_CMD_VER_UNKNOWN);
	if (cmd_ver == 1) {
		num_sub_bands = IWL_NUM_SUB_BANDS;
		num_sub_bands = IWL_NUM_SUB_BANDS_V1;
		gain = mvm->fwrt.ppag_table.v1.gain[0];
		cmd_size = sizeof(mvm->fwrt.ppag_table.v1);
		if (mvm->fwrt.ppag_ver == 2) {
		if (mvm->fwrt.ppag_ver == 1 || mvm->fwrt.ppag_ver == 2) {
			IWL_DEBUG_RADIO(mvm,
					"PPAG table is v2 but FW supports v1, sending truncated table\n");
					"PPAG table rev is %d but FW supports v1, sending truncated table\n",
					mvm->fwrt.ppag_ver);
			mvm->fwrt.ppag_table.v1.flags &=
				cpu_to_le32(IWL_PPAG_ETSI_MASK);
		}
	} else if (cmd_ver == 2) {
	} else if (cmd_ver == 2 || cmd_ver == 3) {
		num_sub_bands = IWL_NUM_SUB_BANDS_V2;
		gain = mvm->fwrt.ppag_table.v2.gain[0];
		cmd_size = sizeof(mvm->fwrt.ppag_table.v2);
		if (mvm->fwrt.ppag_ver == 1) {
		if (mvm->fwrt.ppag_ver == 0) {
			IWL_DEBUG_RADIO(mvm,
					"PPAG table is v1 but FW supports v2, sending padded table\n");
		} else if (cmd_ver == 2 && mvm->fwrt.ppag_ver == 2) {
			IWL_DEBUG_RADIO(mvm,
					"PPAG table is v3 but FW supports v2, sending partial bitmap.\n");
			mvm->fwrt.ppag_table.v1.flags &=
				cpu_to_le32(IWL_PPAG_ETSI_MASK);
		}
	} else {
		IWL_DEBUG_RADIO(mvm, "Unsupported PPAG command version\n");
@@ -1102,7 +1120,7 @@ static int iwl_mvm_ppag_init(struct iwl_mvm *mvm)
		IWL_DEBUG_RADIO(mvm,
				"System vendor '%s' is not in the approved list, disabling PPAG.\n",
				dmi_get_system_info(DMI_SYS_VENDOR));
		mvm->fwrt.ppag_table.v1.enabled = cpu_to_le32(0);
		mvm->fwrt.ppag_table.v1.flags = cpu_to_le32(0);
		return 0;
	}