aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/net/wireless/intel/iwlwifi/mvm/fw.c
diff options
context:
space:
mode:
Diffstat (limited to '')
-rw-r--r--drivers/net/wireless/intel/iwlwifi/mvm/fw.c151
1 files changed, 124 insertions, 27 deletions
diff --git a/drivers/net/wireless/intel/iwlwifi/mvm/fw.c b/drivers/net/wireless/intel/iwlwifi/mvm/fw.c
index 313e9f106f46..15e2773ce7e7 100644
--- a/drivers/net/wireless/intel/iwlwifi/mvm/fw.c
+++ b/drivers/net/wireless/intel/iwlwifi/mvm/fw.c
@@ -6,6 +6,7 @@
*/
#include <net/mac80211.h>
#include <linux/netdevice.h>
+#include <linux/dmi.h>
#include "iwl-trans.h"
#include "iwl-op-mode.h"
@@ -475,9 +476,13 @@ static int iwl_run_unified_mvm_ucode(struct iwl_mvm *mvm)
/* Load NVM to NIC if needed */
if (mvm->nvm_file_name) {
- iwl_read_external_nvm(mvm->trans, mvm->nvm_file_name,
- mvm->nvm_sections);
- iwl_mvm_load_nvm_to_nic(mvm);
+ ret = iwl_read_external_nvm(mvm->trans, mvm->nvm_file_name,
+ mvm->nvm_sections);
+ if (ret)
+ goto error;
+ ret = iwl_mvm_load_nvm_to_nic(mvm);
+ if (ret)
+ goto error;
}
if (IWL_MVM_PARSE_NVM && !mvm->nvm_data) {
@@ -633,6 +638,8 @@ int iwl_run_init_mvm_ucode(struct iwl_mvm *mvm)
iwl_wait_phy_db_entry,
mvm->phy_db);
+ iwl_dbg_tlv_time_point(&mvm->fwrt, IWL_FW_INI_TIME_POINT_EARLY, NULL);
+
/* Will also start the device */
ret = iwl_mvm_load_ucode_wait_alive(mvm, IWL_UCODE_INIT);
if (ret) {
@@ -656,8 +663,11 @@ int iwl_run_init_mvm_ucode(struct iwl_mvm *mvm)
}
/* In case we read the NVM from external file, load it to the NIC */
- if (mvm->nvm_file_name)
- iwl_mvm_load_nvm_to_nic(mvm);
+ if (mvm->nvm_file_name) {
+ ret = iwl_mvm_load_nvm_to_nic(mvm);
+ if (ret)
+ goto remove_notif;
+ }
WARN_ONCE(mvm->nvm_data->nvm_version < mvm->trans->cfg->nvm_ver,
"Too old NVM version (0x%0x, required = 0x%0x)",
@@ -859,12 +869,10 @@ static int iwl_mvm_sar_geo_init(struct iwl_mvm *mvm)
if (cmd_ver == 3) {
len = sizeof(cmd.v3);
n_bands = ARRAY_SIZE(cmd.v3.table[0]);
- cmd.v3.table_revision = cpu_to_le32(mvm->fwrt.geo_rev);
} else if (fw_has_api(&mvm->fwrt.fw->ucode_capa,
IWL_UCODE_TLV_API_SAR_TABLE_VER)) {
len = sizeof(cmd.v2);
n_bands = ARRAY_SIZE(cmd.v2.table[0]);
- cmd.v2.table_revision = cpu_to_le32(mvm->fwrt.geo_rev);
} else {
len = sizeof(cmd.v1);
n_bands = ARRAY_SIZE(cmd.v1.table[0]);
@@ -884,6 +892,16 @@ static int iwl_mvm_sar_geo_init(struct iwl_mvm *mvm)
if (ret)
return 0;
+ /*
+ * Set the revision on versions that contain it.
+ * This must be done after calling iwl_sar_geo_init().
+ */
+ if (cmd_ver == 3)
+ cmd.v3.table_revision = cpu_to_le32(mvm->fwrt.geo_rev);
+ else if (fw_has_api(&mvm->fwrt.fw->ucode_capa,
+ IWL_UCODE_TLV_API_SAR_TABLE_VER))
+ cmd.v2.table_revision = cpu_to_le32(mvm->fwrt.geo_rev);
+
return iwl_mvm_send_cmd_pdu(mvm,
WIDE_ID(PHY_OPS_GROUP, GEO_TX_POWER_LIMIT),
0, len, &cmd);
@@ -892,7 +910,6 @@ 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 iwl_ppag_table_cmd ppag_table;
int i, j, ret, tbl_rev, num_sub_bands;
int idx = 2;
s8 *gain;
@@ -946,8 +963,8 @@ read_table:
goto out_free;
}
- ppag_table.v1.enabled = cpu_to_le32(enabled->integer.value);
- if (!ppag_table.v1.enabled) {
+ mvm->fwrt.ppag_table.v1.enabled = cpu_to_le32(enabled->integer.value);
+ if (!mvm->fwrt.ppag_table.v1.enabled) {
ret = 0;
goto out_free;
}
@@ -962,16 +979,23 @@ read_table:
union acpi_object *ent;
ent = &wifi_pkg->package.elements[idx++];
- if (ent->type != ACPI_TYPE_INTEGER ||
- (j == 0 && ent->integer.value > ACPI_PPAG_MAX_LB) ||
- (j == 0 && ent->integer.value < ACPI_PPAG_MIN_LB) ||
- (j != 0 && ent->integer.value > ACPI_PPAG_MAX_HB) ||
- (j != 0 && ent->integer.value < ACPI_PPAG_MIN_HB)) {
- ppag_table.v1.enabled = cpu_to_le32(0);
+ if (ent->type != ACPI_TYPE_INTEGER) {
ret = -EINVAL;
goto out_free;
}
+
gain[i * num_sub_bands + j] = ent->integer.value;
+
+ if ((j == 0 &&
+ (gain[i * num_sub_bands + j] > ACPI_PPAG_MAX_LB ||
+ gain[i * num_sub_bands + j] < ACPI_PPAG_MIN_LB)) ||
+ (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);
+ ret = -EINVAL;
+ goto out_free;
+ }
}
}
ret = 0;
@@ -984,7 +1008,6 @@ int iwl_mvm_ppag_send_cmd(struct iwl_mvm *mvm)
{
u8 cmd_ver;
int i, j, ret, num_sub_bands, cmd_size;
- union iwl_ppag_table_cmd ppag_table;
s8 *gain;
if (!fw_has_capa(&mvm->fw->ucode_capa, IWL_UCODE_TLV_CAPA_SET_PPAG)) {
@@ -1003,7 +1026,7 @@ int iwl_mvm_ppag_send_cmd(struct iwl_mvm *mvm)
if (cmd_ver == 1) {
num_sub_bands = IWL_NUM_SUB_BANDS;
gain = mvm->fwrt.ppag_table.v1.gain[0];
- cmd_size = sizeof(ppag_table.v1);
+ cmd_size = sizeof(mvm->fwrt.ppag_table.v1);
if (mvm->fwrt.ppag_ver == 2) {
IWL_DEBUG_RADIO(mvm,
"PPAG table is v2 but FW supports v1, sending truncated table\n");
@@ -1011,7 +1034,7 @@ int iwl_mvm_ppag_send_cmd(struct iwl_mvm *mvm)
} else if (cmd_ver == 2) {
num_sub_bands = IWL_NUM_SUB_BANDS_V2;
gain = mvm->fwrt.ppag_table.v2.gain[0];
- cmd_size = sizeof(ppag_table.v2);
+ cmd_size = sizeof(mvm->fwrt.ppag_table.v2);
if (mvm->fwrt.ppag_ver == 1) {
IWL_DEBUG_RADIO(mvm,
"PPAG table is v1 but FW supports v2, sending padded table\n");
@@ -1031,7 +1054,7 @@ int iwl_mvm_ppag_send_cmd(struct iwl_mvm *mvm)
IWL_DEBUG_RADIO(mvm, "Sending PER_PLATFORM_ANT_GAIN_CMD\n");
ret = iwl_mvm_send_cmd_pdu(mvm, WIDE_ID(PHY_OPS_GROUP,
PER_PLATFORM_ANT_GAIN_CMD),
- 0, cmd_size, &ppag_table);
+ 0, cmd_size, &mvm->fwrt.ppag_table);
if (ret < 0)
IWL_ERR(mvm, "failed to send PER_PLATFORM_ANT_GAIN_CMD (%d)\n",
ret);
@@ -1039,6 +1062,29 @@ int iwl_mvm_ppag_send_cmd(struct iwl_mvm *mvm)
return ret;
}
+static const struct dmi_system_id dmi_ppag_approved_list[] = {
+ { .ident = "HP",
+ .matches = {
+ DMI_MATCH(DMI_SYS_VENDOR, "HP"),
+ },
+ },
+ { .ident = "SAMSUNG",
+ .matches = {
+ DMI_MATCH(DMI_SYS_VENDOR, "SAMSUNG ELECTRONICS CO., LTD"),
+ },
+ },
+ { .ident = "MSFT",
+ .matches = {
+ DMI_MATCH(DMI_SYS_VENDOR, "Microsoft Corporation"),
+ },
+ },
+ { .ident = "ASUS",
+ .matches = {
+ DMI_MATCH(DMI_SYS_VENDOR, "ASUSTek COMPUTER INC."),
+ },
+ },
+};
+
static int iwl_mvm_ppag_init(struct iwl_mvm *mvm)
{
int ret;
@@ -1050,6 +1096,15 @@ static int iwl_mvm_ppag_init(struct iwl_mvm *mvm)
ret);
return 0;
}
+
+ if (!dmi_check_system(dmi_ppag_approved_list)) {
+ 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);
+ return 0;
+ }
+
return iwl_mvm_ppag_send_cmd(mvm);
}
@@ -1093,7 +1148,8 @@ static u8 iwl_mvm_eval_dsm_indonesia_5g2(struct iwl_mvm *mvm)
u8 value;
int ret = iwl_acpi_get_dsm_u8((&mvm->fwrt)->dev, 0,
- DSM_FUNC_ENABLE_INDONESIA_5G2, &value);
+ DSM_FUNC_ENABLE_INDONESIA_5G2,
+ &iwl_guid, &value);
if (ret < 0)
IWL_DEBUG_RADIO(mvm,
@@ -1114,11 +1170,36 @@ static u8 iwl_mvm_eval_dsm_indonesia_5g2(struct iwl_mvm *mvm)
return DSM_VALUE_INDONESIA_DISABLE;
}
+static u8 iwl_mvm_eval_dsm_rfi(struct iwl_mvm *mvm)
+{
+ u8 value;
+ int ret = iwl_acpi_get_dsm_u8((&mvm->fwrt)->dev, 0, DSM_RFI_FUNC_ENABLE,
+ &iwl_rfi_guid, &value);
+
+ if (ret < 0) {
+ IWL_DEBUG_RADIO(mvm, "Failed to get DSM RFI, ret=%d\n", ret);
+
+ } else if (value >= DSM_VALUE_RFI_MAX) {
+ IWL_DEBUG_RADIO(mvm, "DSM RFI got invalid value, ret=%d\n",
+ value);
+
+ } else if (value == DSM_VALUE_RFI_ENABLE) {
+ IWL_DEBUG_RADIO(mvm, "DSM RFI is evaluated to enable\n");
+ return DSM_VALUE_RFI_ENABLE;
+ }
+
+ IWL_DEBUG_RADIO(mvm, "DSM RFI is disabled\n");
+
+ /* default behaviour is disabled */
+ return DSM_VALUE_RFI_DISABLE;
+}
+
static u8 iwl_mvm_eval_dsm_disable_srd(struct iwl_mvm *mvm)
{
u8 value;
int ret = iwl_acpi_get_dsm_u8((&mvm->fwrt)->dev, 0,
- DSM_FUNC_DISABLE_SRD, &value);
+ DSM_FUNC_DISABLE_SRD,
+ &iwl_guid, &value);
if (ret < 0)
IWL_DEBUG_RADIO(mvm,
@@ -1148,7 +1229,7 @@ static void iwl_mvm_lari_cfg(struct iwl_mvm *mvm)
{
u8 ret;
int cmd_ret;
- struct iwl_lari_config_change_cmd cmd = {};
+ struct iwl_lari_config_change_cmd_v2 cmd = {};
if (iwl_mvm_eval_dsm_indonesia_5g2(mvm) == DSM_VALUE_INDONESIA_ENABLE)
cmd.config_bitmap |=
@@ -1166,11 +1247,18 @@ static void iwl_mvm_lari_cfg(struct iwl_mvm *mvm)
/* apply more config masks here */
if (cmd.config_bitmap) {
- IWL_DEBUG_RADIO(mvm, "sending LARI_CONFIG_CHANGE\n");
+ size_t cmd_size = iwl_fw_lookup_cmd_ver(mvm->fw,
+ REGULATORY_AND_NVM_GROUP,
+ LARI_CONFIG_CHANGE, 1) == 2 ?
+ sizeof(struct iwl_lari_config_change_cmd_v2) :
+ sizeof(struct iwl_lari_config_change_cmd_v1);
+ IWL_DEBUG_RADIO(mvm,
+ "sending LARI_CONFIG_CHANGE, config_bitmap=0x%x\n",
+ le32_to_cpu(cmd.config_bitmap));
cmd_ret = iwl_mvm_send_cmd_pdu(mvm,
WIDE_ID(REGULATORY_AND_NVM_GROUP,
LARI_CONFIG_CHANGE),
- 0, sizeof(cmd), &cmd);
+ 0, cmd_size, &cmd);
if (cmd_ret < 0)
IWL_DEBUG_RADIO(mvm,
"Failed to send LARI_CONFIG_CHANGE (%d)\n",
@@ -1212,6 +1300,11 @@ static void iwl_mvm_tas_init(struct iwl_mvm *mvm)
static void iwl_mvm_lari_cfg(struct iwl_mvm *mvm)
{
}
+
+static u8 iwl_mvm_eval_dsm_rfi(struct iwl_mvm *mvm)
+{
+ return DSM_VALUE_RFI_DISABLE;
+}
#endif /* CONFIG_ACPI */
void iwl_mvm_send_recovery_cmd(struct iwl_mvm *mvm, u32 flags)
@@ -1315,8 +1408,6 @@ static int iwl_mvm_load_rt_fw(struct iwl_mvm *mvm)
if (ret)
return ret;
- iwl_dbg_tlv_time_point(&mvm->fwrt, IWL_FW_INI_TIME_POINT_EARLY, NULL);
-
mvm->rfkill_safe_init_done = false;
ret = iwl_mvm_load_ucode_wait_alive(mvm, IWL_UCODE_REGULAR);
if (ret)
@@ -1550,6 +1641,12 @@ int iwl_mvm_up(struct iwl_mvm *mvm)
iwl_mvm_ftm_initiator_smooth_config(mvm);
+ if (fw_has_capa(&mvm->fw->ucode_capa,
+ IWL_UCODE_TLV_CAPA_RFIM_SUPPORT)) {
+ if (iwl_mvm_eval_dsm_rfi(mvm) == DSM_VALUE_RFI_ENABLE)
+ iwl_rfi_send_config_cmd(mvm, NULL);
+ }
+
IWL_DEBUG_INFO(mvm, "RT uCode started.\n");
return 0;
error: