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: Miri Korenblit <miriam.rachel.korenblit@intel.com> Signed-off-by: Luca Coelho <luciano.coelho@intel.com> Link: https://lore.kernel.org/r/iwlwifi.20210331121101.69af388d0dce.I8cfddf9e6837bf394b00390181b4b774ded19acd@changeid Signed-off-by: Luca Coelho <luciano.coelho@intel.com>
This commit is contained in:
parent
e8fe3b41c3
commit
e12cfc7bbf
|
@ -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);
|
||||
}
|
||||
|
||||
|
|
|
@ -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)
|
||||
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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) {
|
||||
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 = 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;
|
||||
}
|
||||
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");
|
||||
goto read_table;
|
||||
}
|
||||
|
||||
/* 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 @@ read_table:
|
|||
(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;
|
||||
}
|
||||
|
||||
|
|
Loading…
Reference in New Issue