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

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@changeidSigned-off-by: default avatarLuca Coelho <luciano.coelho@intel.com>
parent e8fe3b41
...@@ -181,14 +181,13 @@ union acpi_object *iwl_acpi_get_wifi_pkg(struct device *dev, ...@@ -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 * We need at least two packages, one for the revision and one
* for the data itself. Also check that the revision is valid * 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 * (i.e. it is an integer (each caller has to check by itself
* 2 revisions). * if the returned revision is supported)).
*/ */
if (data->type != ACPI_TYPE_PACKAGE || if (data->type != ACPI_TYPE_PACKAGE ||
data->package.count < 2 || data->package.count < 2 ||
data->package.elements[0].type != ACPI_TYPE_INTEGER || data->package.elements[0].type != ACPI_TYPE_INTEGER) {
data->package.elements[0].integer.value > 1) { IWL_DEBUG_DEV_RADIO(dev, "Invalid packages structure\n");
IWL_DEBUG_DEV_RADIO(dev, "Unsupported packages structure\n");
return ERR_PTR(-EINVAL); return ERR_PTR(-EINVAL);
} }
......
...@@ -53,8 +53,8 @@ ...@@ -53,8 +53,8 @@
#define ACPI_WGDS_TABLE_SIZE 3 #define ACPI_WGDS_TABLE_SIZE 3
#define ACPI_PPAG_WIFI_DATA_SIZE ((IWL_NUM_CHAIN_LIMITS * \ #define ACPI_PPAG_WIFI_DATA_SIZE_V1 ((IWL_NUM_CHAIN_LIMITS * \
IWL_NUM_SUB_BANDS) + 2) IWL_NUM_SUB_BANDS_V1) + 2)
#define ACPI_PPAG_WIFI_DATA_SIZE_V2 ((IWL_NUM_CHAIN_LIMITS * \ #define ACPI_PPAG_WIFI_DATA_SIZE_V2 ((IWL_NUM_CHAIN_LIMITS * \
IWL_NUM_SUB_BANDS_V2) + 2) IWL_NUM_SUB_BANDS_V2) + 2)
......
...@@ -274,7 +274,7 @@ enum iwl_dev_tx_power_cmd_mode { ...@@ -274,7 +274,7 @@ enum iwl_dev_tx_power_cmd_mode {
#define IWL_NUM_CHAIN_TABLES 1 #define IWL_NUM_CHAIN_TABLES 1
#define IWL_NUM_CHAIN_TABLES_V2 2 #define IWL_NUM_CHAIN_TABLES_V2 2
#define IWL_NUM_CHAIN_LIMITS 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 #define IWL_NUM_SUB_BANDS_V2 11
/** /**
...@@ -300,7 +300,7 @@ struct iwl_dev_tx_power_common { ...@@ -300,7 +300,7 @@ struct iwl_dev_tx_power_common {
* @per_chain: per chain restrictions * @per_chain: per chain restrictions
*/ */
struct iwl_dev_tx_power_cmd_v3 { 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 */ } __packed; /* TX_REDUCED_POWER_API_S_VER_3 */
#define IWL_DEV_MAX_TX_POWER 0x7FFF #define IWL_DEV_MAX_TX_POWER 0x7FFF
...@@ -313,7 +313,7 @@ struct iwl_dev_tx_power_cmd_v3 { ...@@ -313,7 +313,7 @@ struct iwl_dev_tx_power_cmd_v3 {
* @reserved: reserved (padding) * @reserved: reserved (padding)
*/ */
struct iwl_dev_tx_power_cmd_v4 { 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 enable_ack_reduction;
u8 reserved[3]; u8 reserved[3];
} __packed; /* TX_REDUCED_POWER_API_S_VER_4 */ } __packed; /* TX_REDUCED_POWER_API_S_VER_4 */
...@@ -332,7 +332,7 @@ struct iwl_dev_tx_power_cmd_v4 { ...@@ -332,7 +332,7 @@ struct iwl_dev_tx_power_cmd_v4 {
* BIOS values. relevant if setMode is IWL_TX_POWER_MODE_SET_SAR_TIMER * BIOS values. relevant if setMode is IWL_TX_POWER_MODE_SET_SAR_TIMER
*/ */
struct iwl_dev_tx_power_cmd_v5 { 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 enable_ack_reduction;
u8 per_chain_restriction_changed; u8 per_chain_restriction_changed;
u8 reserved[2]; u8 reserved[2];
...@@ -454,21 +454,23 @@ struct iwl_geo_tx_power_profiles_resp { ...@@ -454,21 +454,23 @@ struct iwl_geo_tx_power_profiles_resp {
/** /**
* union iwl_ppag_table_cmd - union for all versions of PPAG command * union iwl_ppag_table_cmd - union for all versions of PPAG command
* @v1: version 1, table revision = 0 * @v1: version 1
* @v2: version 2, table revision = 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 * @gain: table of antenna gain values per chain and sub-band
* @reserved: reserved * @reserved: reserved
*/ */
union iwl_ppag_table_cmd { union iwl_ppag_table_cmd {
struct { struct {
__le32 enabled; __le32 flags;
s8 gain[IWL_NUM_CHAIN_LIMITS][IWL_NUM_SUB_BANDS]; s8 gain[IWL_NUM_CHAIN_LIMITS][IWL_NUM_SUB_BANDS_V1];
s8 reserved[2]; s8 reserved[2];
} v1; } v1;
struct { struct {
__le32 enabled; __le32 flags;
s8 gain[IWL_NUM_CHAIN_LIMITS][IWL_NUM_SUB_BANDS_V2]; s8 gain[IWL_NUM_CHAIN_LIMITS][IWL_NUM_SUB_BANDS_V2];
s8 reserved[2]; s8 reserved[2];
} v2; } v2;
......
...@@ -29,6 +29,9 @@ ...@@ -29,6 +29,9 @@
#define UCODE_VALID_OK cpu_to_le32(0x1) #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 { struct iwl_mvm_alive_data {
bool valid; bool valid;
u32 scd_base_addr; u32 scd_base_addr;
...@@ -773,16 +776,16 @@ int iwl_mvm_sar_select_profile(struct iwl_mvm *mvm, int prof_a, int prof_b) ...@@ -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, } else if (fw_has_api(&mvm->fw->ucode_capa,
IWL_UCODE_TLV_API_REDUCE_TX_POWER)) { IWL_UCODE_TLV_API_REDUCE_TX_POWER)) {
len = sizeof(cmd.v5); 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]; per_chain = cmd.v5.per_chain[0][0];
} else if (fw_has_capa(&mvm->fw->ucode_capa, } else if (fw_has_capa(&mvm->fw->ucode_capa,
IWL_UCODE_TLV_CAPA_TX_POWER_ACK)) { IWL_UCODE_TLV_CAPA_TX_POWER_ACK)) {
len = sizeof(cmd.v4); 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]; per_chain = cmd.v4.per_chain[0][0];
} else { } else {
len = sizeof(cmd.v3); 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]; per_chain = cmd.v3.per_chain[0][0];
} }
...@@ -909,46 +912,50 @@ static int iwl_mvm_sar_geo_init(struct iwl_mvm *mvm) ...@@ -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) 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 i, j, ret, tbl_rev, num_sub_bands;
int idx = 2; int idx = 2;
s8 *gain; 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. * 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); data = iwl_acpi_get_object(mvm->dev, ACPI_PPAG_METHOD);
if (IS_ERR(data)) if (IS_ERR(data))
return PTR_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, wifi_pkg = iwl_acpi_get_wifi_pkg(mvm->dev, data,
ACPI_PPAG_WIFI_DATA_SIZE_V2, &tbl_rev); ACPI_PPAG_WIFI_DATA_SIZE_V2, &tbl_rev);
if (!IS_ERR(wifi_pkg)) { 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; ret = -EINVAL;
goto out_free; 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 */ /* try to read ppag table revision 0 */
wifi_pkg = iwl_acpi_get_wifi_pkg(mvm->dev, data, 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 (!IS_ERR(wifi_pkg)) {
if (tbl_rev != 0) { if (tbl_rev != 0) {
ret = -EINVAL; ret = -EINVAL;
goto out_free; 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]; 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"); IWL_DEBUG_RADIO(mvm, "Reading PPAG table v1 (tbl_rev=0)\n");
goto read_table; goto read_table;
} }
...@@ -956,15 +963,17 @@ static int iwl_mvm_get_ppag_table(struct iwl_mvm *mvm) ...@@ -956,15 +963,17 @@ static int iwl_mvm_get_ppag_table(struct iwl_mvm *mvm)
goto out_free; goto out_free;
read_table: read_table:
enabled = &wifi_pkg->package.elements[1]; flags = &wifi_pkg->package.elements[1];
if (enabled->type != ACPI_TYPE_INTEGER ||
(enabled->integer.value != 0 && enabled->integer.value != 1)) { if (flags->type != ACPI_TYPE_INTEGER) {
ret = -EINVAL; ret = -EINVAL;
goto out_free; goto out_free;
} }
mvm->fwrt.ppag_table.v1.enabled = cpu_to_le32(enabled->integer.value); mvm->fwrt.ppag_table.v1.flags = cpu_to_le32(flags->integer.value &
if (!mvm->fwrt.ppag_table.v1.enabled) { IWL_PPAG_MASK);
if (!mvm->fwrt.ppag_table.v1.flags) {
ret = 0; ret = 0;
goto out_free; goto out_free;
} }
...@@ -992,12 +1001,13 @@ static int iwl_mvm_get_ppag_table(struct iwl_mvm *mvm) ...@@ -992,12 +1001,13 @@ static int iwl_mvm_get_ppag_table(struct iwl_mvm *mvm)
(j != 0 && (j != 0 &&
(gain[i * num_sub_bands + j] > ACPI_PPAG_MAX_HB || (gain[i * num_sub_bands + j] > ACPI_PPAG_MAX_HB ||
gain[i * num_sub_bands + j] < ACPI_PPAG_MIN_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; ret = -EINVAL;
goto out_free; goto out_free;
} }
} }
} }
ret = 0; ret = 0;
out_free: out_free:
kfree(data); kfree(data);
...@@ -1015,7 +1025,7 @@ int iwl_mvm_ppag_send_cmd(struct iwl_mvm *mvm) ...@@ -1015,7 +1025,7 @@ int iwl_mvm_ppag_send_cmd(struct iwl_mvm *mvm)
"PPAG capability not supported by FW, command not sent.\n"); "PPAG capability not supported by FW, command not sent.\n");
return 0; 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"); IWL_DEBUG_RADIO(mvm, "PPAG not enabled, command not sent.\n");
return 0; return 0;
} }
...@@ -1024,20 +1034,28 @@ int iwl_mvm_ppag_send_cmd(struct iwl_mvm *mvm) ...@@ -1024,20 +1034,28 @@ int iwl_mvm_ppag_send_cmd(struct iwl_mvm *mvm)
PER_PLATFORM_ANT_GAIN_CMD, PER_PLATFORM_ANT_GAIN_CMD,
IWL_FW_CMD_VER_UNKNOWN); IWL_FW_CMD_VER_UNKNOWN);
if (cmd_ver == 1) { 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]; gain = mvm->fwrt.ppag_table.v1.gain[0];
cmd_size = sizeof(mvm->fwrt.ppag_table.v1); 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, 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; num_sub_bands = IWL_NUM_SUB_BANDS_V2;
gain = mvm->fwrt.ppag_table.v2.gain[0]; gain = mvm->fwrt.ppag_table.v2.gain[0];
cmd_size = sizeof(mvm->fwrt.ppag_table.v2); cmd_size = sizeof(mvm->fwrt.ppag_table.v2);
if (mvm->fwrt.ppag_ver == 1) { if (mvm->fwrt.ppag_ver == 0) {
IWL_DEBUG_RADIO(mvm, IWL_DEBUG_RADIO(mvm,
"PPAG table is v1 but FW supports v2, sending padded table\n"); "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 { } else {
IWL_DEBUG_RADIO(mvm, "Unsupported PPAG command version\n"); IWL_DEBUG_RADIO(mvm, "Unsupported PPAG command version\n");
...@@ -1102,7 +1120,7 @@ static int iwl_mvm_ppag_init(struct iwl_mvm *mvm) ...@@ -1102,7 +1120,7 @@ static int iwl_mvm_ppag_init(struct iwl_mvm *mvm)
IWL_DEBUG_RADIO(mvm, IWL_DEBUG_RADIO(mvm,
"System vendor '%s' is not in the approved list, disabling PPAG.\n", "System vendor '%s' is not in the approved list, disabling PPAG.\n",
dmi_get_system_info(DMI_SYS_VENDOR)); 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; return 0;
} }
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment