Commit 09059c67 authored by Miri Korenblit's avatar Miri Korenblit Committed by Johannes Berg

wifi: iwlwifi: prepare for reading PPAG table from UEFI

As PPAG table is going to be read from UEFI, there are some
cleanups required:
Move functions/definitions that are common to both UEFI and ACPI to
regulatory.h/c.
In addition, rename the functions/macros names so it will be clear which
one is ACPI specific, and which is common for ACPI and UEFI.
Signed-off-by: default avatarMiri Korenblit <miriam.rachel.korenblit@intel.com>
Reviewed-by: default avatarGregory Greenman <gregory.greenman@intel.com>
Link: https://msgid.link/20240131091413.25623670b422.I8132af7517e4faf0ea8cbeb2efe9651edd319b98@changeidSigned-off-by: default avatarJohannes Berg <johannes.berg@intel.com>
parent be3a8cbb
......@@ -4,7 +4,6 @@
* Copyright (C) 2019-2023 Intel Corporation
*/
#include <linux/uuid.h>
#include <linux/dmi.h>
#include "iwl-drv.h"
#include "iwl-debug.h"
#include "acpi.h"
......@@ -20,63 +19,6 @@ const guid_t iwl_rfi_guid = GUID_INIT(0x7266172C, 0x220B, 0x4B29,
0xDD, 0x26, 0xB5, 0xFD);
IWL_EXPORT_SYMBOL(iwl_rfi_guid);
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."),
},
},
{ .ident = "GOOGLE-HP",
.matches = {
DMI_MATCH(DMI_SYS_VENDOR, "Google"),
DMI_MATCH(DMI_BOARD_VENDOR, "HP"),
},
},
{ .ident = "GOOGLE-ASUS",
.matches = {
DMI_MATCH(DMI_SYS_VENDOR, "Google"),
DMI_MATCH(DMI_BOARD_VENDOR, "ASUSTek COMPUTER INC."),
},
},
{ .ident = "GOOGLE-SAMSUNG",
.matches = {
DMI_MATCH(DMI_SYS_VENDOR, "Google"),
DMI_MATCH(DMI_BOARD_VENDOR, "SAMSUNG ELECTRONICS CO., LTD"),
},
},
{ .ident = "DELL",
.matches = {
DMI_MATCH(DMI_SYS_VENDOR, "Dell Inc."),
},
},
{ .ident = "DELL",
.matches = {
DMI_MATCH(DMI_SYS_VENDOR, "Alienware"),
},
},
{ .ident = "RAZER",
.matches = {
DMI_MATCH(DMI_SYS_VENDOR, "Razer"),
},
},
{}
};
static int iwl_acpi_get_handle(struct device *dev, acpi_string method,
acpi_handle *ret_handle)
{
......@@ -1002,7 +944,7 @@ int iwl_acpi_get_ppag_table(struct iwl_fw_runtime *fwrt)
goto out_free;
}
fwrt->ppag_flags = flags->integer.value & ACPI_PPAG_MASK;
fwrt->ppag_flags = flags->integer.value & IWL_PPAG_ETSI_CHINA_MASK;
cmd_ver = iwl_fw_lookup_cmd_ver(fwrt->fw,
WIDE_ID(PHY_OPS_GROUP,
PER_PLATFORM_ANT_GAIN_CMD),
......@@ -1036,11 +978,11 @@ int iwl_acpi_get_ppag_table(struct iwl_fw_runtime *fwrt)
if (cmd_ver >= 4)
continue;
if ((j == 0 &&
(fwrt->ppag_chains[i].subbands[j] > ACPI_PPAG_MAX_LB ||
fwrt->ppag_chains[i].subbands[j] < ACPI_PPAG_MIN_LB)) ||
(fwrt->ppag_chains[i].subbands[j] > IWL_PPAG_MAX_LB ||
fwrt->ppag_chains[i].subbands[j] < IWL_PPAG_MIN_LB)) ||
(j != 0 &&
(fwrt->ppag_chains[i].subbands[j] > ACPI_PPAG_MAX_HB ||
fwrt->ppag_chains[i].subbands[j] < ACPI_PPAG_MIN_HB))) {
(fwrt->ppag_chains[i].subbands[j] > IWL_PPAG_MAX_HB ||
fwrt->ppag_chains[i].subbands[j] < IWL_PPAG_MIN_HB))) {
ret = -EINVAL;
goto out_free;
}
......@@ -1056,110 +998,6 @@ int iwl_acpi_get_ppag_table(struct iwl_fw_runtime *fwrt)
}
IWL_EXPORT_SYMBOL(iwl_acpi_get_ppag_table);
int iwl_fill_ppag_table(struct iwl_fw_runtime *fwrt,
union iwl_ppag_table_cmd *cmd,
int *cmd_size)
{
u8 cmd_ver;
int i, j, num_sub_bands;
s8 *gain;
/* many firmware images for JF lie about this */
if (CSR_HW_RFID_TYPE(fwrt->trans->hw_rf_id) ==
CSR_HW_RFID_TYPE(CSR_HW_RF_ID_TYPE_JF))
return -EOPNOTSUPP;
if (!fw_has_capa(&fwrt->fw->ucode_capa, IWL_UCODE_TLV_CAPA_SET_PPAG)) {
IWL_DEBUG_RADIO(fwrt,
"PPAG capability not supported by FW, command not sent.\n");
return -EINVAL;
}
cmd_ver = iwl_fw_lookup_cmd_ver(fwrt->fw,
WIDE_ID(PHY_OPS_GROUP,
PER_PLATFORM_ANT_GAIN_CMD),
IWL_FW_CMD_VER_UNKNOWN);
if (!fwrt->ppag_table_valid || (cmd_ver <= 3 && !fwrt->ppag_flags)) {
IWL_DEBUG_RADIO(fwrt, "PPAG not enabled, command not sent.\n");
return -EINVAL;
}
/* The 'flags' field is the same in v1 and in v2 so we can just
* use v1 to access it.
*/
cmd->v1.flags = cpu_to_le32(fwrt->ppag_flags);
IWL_DEBUG_RADIO(fwrt, "PPAG cmd ver is %d\n", cmd_ver);
if (cmd_ver == 1) {
num_sub_bands = IWL_NUM_SUB_BANDS_V1;
gain = cmd->v1.gain[0];
*cmd_size = sizeof(cmd->v1);
if (fwrt->ppag_ver == 1 || fwrt->ppag_ver == 2) {
/* in this case FW supports revision 0 */
IWL_DEBUG_RADIO(fwrt,
"PPAG table rev is %d, send truncated table\n",
fwrt->ppag_ver);
}
} else if (cmd_ver >= 2 && cmd_ver <= 4) {
num_sub_bands = IWL_NUM_SUB_BANDS_V2;
gain = cmd->v2.gain[0];
*cmd_size = sizeof(cmd->v2);
if (fwrt->ppag_ver == 0) {
/* in this case FW supports revisions 1 or 2 */
IWL_DEBUG_RADIO(fwrt,
"PPAG table rev is 0, send padded table\n");
}
} else {
IWL_DEBUG_RADIO(fwrt, "Unsupported PPAG command version\n");
return -EINVAL;
}
/* ppag mode */
IWL_DEBUG_RADIO(fwrt,
"PPAG MODE bits were read from bios: %d\n",
cmd->v1.flags);
if ((cmd_ver == 1 && !fw_has_capa(&fwrt->fw->ucode_capa,
IWL_UCODE_TLV_CAPA_PPAG_CHINA_BIOS_SUPPORT)) ||
(cmd_ver == 2 && fwrt->ppag_ver == 2)) {
cmd->v1.flags &= cpu_to_le32(IWL_PPAG_ETSI_MASK);
IWL_DEBUG_RADIO(fwrt, "masking ppag China bit\n");
} else {
IWL_DEBUG_RADIO(fwrt, "isn't masking ppag China bit\n");
}
IWL_DEBUG_RADIO(fwrt,
"PPAG MODE bits going to be sent: %d\n",
cmd->v1.flags);
for (i = 0; i < IWL_NUM_CHAIN_LIMITS; i++) {
for (j = 0; j < num_sub_bands; j++) {
gain[i * num_sub_bands + j] =
fwrt->ppag_chains[i].subbands[j];
IWL_DEBUG_RADIO(fwrt,
"PPAG table: chain[%d] band[%d]: gain = %d\n",
i, j, gain[i * num_sub_bands + j]);
}
}
return 0;
}
IWL_EXPORT_SYMBOL(iwl_fill_ppag_table);
bool iwl_acpi_is_ppag_approved(struct iwl_fw_runtime *fwrt)
{
if (!dmi_check_system(dmi_ppag_approved_list)) {
IWL_DEBUG_RADIO(fwrt,
"System vendor '%s' is not in the approved list, disabling PPAG.\n",
dmi_get_system_info(DMI_SYS_VENDOR));
fwrt->ppag_flags = 0;
return false;
}
return true;
}
IWL_EXPORT_SYMBOL(iwl_acpi_is_ppag_approved);
void iwl_acpi_get_phy_filters(struct iwl_fw_runtime *fwrt,
struct iwl_phy_specific_cfg *filters)
{
......
......@@ -94,29 +94,12 @@
#define ACPI_PPAG_WIFI_DATA_SIZE_V2 ((IWL_NUM_CHAIN_LIMITS * \
IWL_NUM_SUB_BANDS_V2) + 2)
/* PPAG gain value bounds in 1/8 dBm */
#define ACPI_PPAG_MIN_LB -16
#define ACPI_PPAG_MAX_LB 24
#define ACPI_PPAG_MIN_HB -16
#define ACPI_PPAG_MAX_HB 40
#define ACPI_PPAG_MASK 3
#define IWL_PPAG_ETSI_MASK BIT(0)
#define IWL_SAR_ENABLE_MSK BIT(0)
#define IWL_REDUCE_POWER_FLAGS_POS 1
/* The Inidcator whether UEFI WIFI GUID tables are locked is read from ACPI */
#define UEFI_WIFI_GUID_UNLOCKED 0
/*
* The profile for revision 2 is a superset of revision 1, which is in
* turn a superset of revision 0. So we can store all revisions
* inside revision 2, which is what we represent here.
*/
struct iwl_ppag_chain {
s8 subbands[ACPI_SAR_NUM_SUB_BANDS_REV2];
};
enum iwl_dsm_funcs_rev_0 {
DSM_FUNC_QUERY = 0,
DSM_FUNC_DISABLE_SRD = 1,
......@@ -207,12 +190,6 @@ __le32 iwl_acpi_get_lari_config_bitmap(struct iwl_fw_runtime *fwrt);
int iwl_acpi_get_ppag_table(struct iwl_fw_runtime *fwrt);
int iwl_fill_ppag_table(struct iwl_fw_runtime *fwrt,
union iwl_ppag_table_cmd *cmd,
int *cmd_size);
bool iwl_acpi_is_ppag_approved(struct iwl_fw_runtime *fwrt);
void iwl_acpi_get_phy_filters(struct iwl_fw_runtime *fwrt,
struct iwl_phy_specific_cfg *filters);
......@@ -284,18 +261,6 @@ static inline int iwl_acpi_get_ppag_table(struct iwl_fw_runtime *fwrt)
return -ENOENT;
}
static inline int iwl_fill_ppag_table(struct iwl_fw_runtime *fwrt,
union iwl_ppag_table_cmd *cmd,
int *cmd_size)
{
return -ENOENT;
}
static inline bool iwl_acpi_is_ppag_approved(struct iwl_fw_runtime *fwrt)
{
return false;
}
static inline void iwl_acpi_get_phy_filters(struct iwl_fw_runtime *fwrt,
struct iwl_phy_specific_cfg *filters)
{
......
......@@ -2,6 +2,7 @@
/*
* Copyright (C) 2023 Intel Corporation
*/
#include <linux/dmi.h>
#include "iwl-drv.h"
#include "iwl-debug.h"
#include "regulatory.h"
......@@ -24,6 +25,63 @@ IWL_BIOS_TABLE_LOADER(wrds);
IWL_BIOS_TABLE_LOADER(ewrd);
IWL_BIOS_TABLE_LOADER(wgds);
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."),
},
},
{ .ident = "GOOGLE-HP",
.matches = {
DMI_MATCH(DMI_SYS_VENDOR, "Google"),
DMI_MATCH(DMI_BOARD_VENDOR, "HP"),
},
},
{ .ident = "GOOGLE-ASUS",
.matches = {
DMI_MATCH(DMI_SYS_VENDOR, "Google"),
DMI_MATCH(DMI_BOARD_VENDOR, "ASUSTek COMPUTER INC."),
},
},
{ .ident = "GOOGLE-SAMSUNG",
.matches = {
DMI_MATCH(DMI_SYS_VENDOR, "Google"),
DMI_MATCH(DMI_BOARD_VENDOR, "SAMSUNG ELECTRONICS CO., LTD"),
},
},
{ .ident = "DELL",
.matches = {
DMI_MATCH(DMI_SYS_VENDOR, "Dell Inc."),
},
},
{ .ident = "DELL",
.matches = {
DMI_MATCH(DMI_SYS_VENDOR, "Alienware"),
},
},
{ .ident = "RAZER",
.matches = {
DMI_MATCH(DMI_SYS_VENDOR, "Razer"),
},
},
{}
};
bool iwl_sar_geo_support(struct iwl_fw_runtime *fwrt)
{
/*
......@@ -147,3 +205,106 @@ int iwl_sar_fill_profile(struct iwl_fw_runtime *fwrt,
return ret;
}
IWL_EXPORT_SYMBOL(iwl_sar_fill_profile);
int iwl_fill_ppag_table(struct iwl_fw_runtime *fwrt,
union iwl_ppag_table_cmd *cmd, int *cmd_size)
{
u8 cmd_ver;
int i, j, num_sub_bands;
s8 *gain;
/* many firmware images for JF lie about this */
if (CSR_HW_RFID_TYPE(fwrt->trans->hw_rf_id) ==
CSR_HW_RFID_TYPE(CSR_HW_RF_ID_TYPE_JF))
return -EOPNOTSUPP;
if (!fw_has_capa(&fwrt->fw->ucode_capa, IWL_UCODE_TLV_CAPA_SET_PPAG)) {
IWL_DEBUG_RADIO(fwrt,
"PPAG capability not supported by FW, command not sent.\n");
return -EINVAL;
}
cmd_ver = iwl_fw_lookup_cmd_ver(fwrt->fw,
WIDE_ID(PHY_OPS_GROUP,
PER_PLATFORM_ANT_GAIN_CMD),
IWL_FW_CMD_VER_UNKNOWN);
if (!fwrt->ppag_table_valid || (cmd_ver <= 3 && !fwrt->ppag_flags)) {
IWL_DEBUG_RADIO(fwrt, "PPAG not enabled, command not sent.\n");
return -EINVAL;
}
/* The 'flags' field is the same in v1 and in v2 so we can just
* use v1 to access it.
*/
cmd->v1.flags = cpu_to_le32(fwrt->ppag_flags);
IWL_DEBUG_RADIO(fwrt, "PPAG cmd ver is %d\n", cmd_ver);
if (cmd_ver == 1) {
num_sub_bands = IWL_NUM_SUB_BANDS_V1;
gain = cmd->v1.gain[0];
*cmd_size = sizeof(cmd->v1);
if (fwrt->ppag_ver == 1 || fwrt->ppag_ver == 2) {
/* in this case FW supports revision 0 */
IWL_DEBUG_RADIO(fwrt,
"PPAG table rev is %d, send truncated table\n",
fwrt->ppag_ver);
}
} else if (cmd_ver >= 2 && cmd_ver <= 4) {
num_sub_bands = IWL_NUM_SUB_BANDS_V2;
gain = cmd->v2.gain[0];
*cmd_size = sizeof(cmd->v2);
if (fwrt->ppag_ver == 0) {
/* in this case FW supports revisions 1 or 2 */
IWL_DEBUG_RADIO(fwrt,
"PPAG table rev is 0, send padded table\n");
}
} else {
IWL_DEBUG_RADIO(fwrt, "Unsupported PPAG command version\n");
return -EINVAL;
}
/* ppag mode */
IWL_DEBUG_RADIO(fwrt,
"PPAG MODE bits were read from bios: %d\n",
cmd->v1.flags);
if ((cmd_ver == 1 &&
!fw_has_capa(&fwrt->fw->ucode_capa,
IWL_UCODE_TLV_CAPA_PPAG_CHINA_BIOS_SUPPORT)) ||
(cmd_ver == 2 && fwrt->ppag_ver == 2)) {
cmd->v1.flags &= cpu_to_le32(IWL_PPAG_ETSI_MASK);
IWL_DEBUG_RADIO(fwrt, "masking ppag China bit\n");
} else {
IWL_DEBUG_RADIO(fwrt, "isn't masking ppag China bit\n");
}
IWL_DEBUG_RADIO(fwrt,
"PPAG MODE bits going to be sent: %d\n",
cmd->v1.flags);
for (i = 0; i < IWL_NUM_CHAIN_LIMITS; i++) {
for (j = 0; j < num_sub_bands; j++) {
gain[i * num_sub_bands + j] =
fwrt->ppag_chains[i].subbands[j];
IWL_DEBUG_RADIO(fwrt,
"PPAG table: chain[%d] band[%d]: gain = %d\n",
i, j, gain[i * num_sub_bands + j]);
}
}
return 0;
}
IWL_EXPORT_SYMBOL(iwl_fill_ppag_table);
bool iwl_is_ppag_approved(struct iwl_fw_runtime *fwrt)
{
if (!dmi_check_system(dmi_ppag_approved_list)) {
IWL_DEBUG_RADIO(fwrt,
"System vendor '%s' is not in the approved list, disabling PPAG.\n",
dmi_get_system_info(DMI_SYS_VENDOR));
fwrt->ppag_flags = 0;
return false;
}
return true;
}
IWL_EXPORT_SYMBOL(iwl_is_ppag_approved);
......@@ -31,6 +31,15 @@
#define IWL_SAR_ENABLE_MSK BIT(0)
/* PPAG gain value bounds in 1/8 dBm */
#define IWL_PPAG_MIN_LB -16
#define IWL_PPAG_MAX_LB 24
#define IWL_PPAG_MIN_HB -16
#define IWL_PPAG_MAX_HB 40
#define IWL_PPAG_ETSI_CHINA_MASK 3
#define IWL_PPAG_ETSI_MASK BIT(0)
/*
* The profile for revision 2 is a superset of revision 1, which is in
* turn a superset of revision 0. So we can store all revisions
......@@ -75,6 +84,11 @@ struct iwl_geo_profile {
struct iwl_geo_profile_band bands[BIOS_GEO_MAX_NUM_BANDS];
};
/* Same thing as with SAR, all revisions fit in revision 2 */
struct iwl_ppag_chain {
s8 subbands[BIOS_SAR_MAX_SUB_BANDS_NUM];
};
struct iwl_fw_runtime;
bool iwl_sar_geo_support(struct iwl_fw_runtime *fwrt);
......@@ -87,6 +101,12 @@ int iwl_sar_fill_profile(struct iwl_fw_runtime *fwrt,
__le16 *per_chain, u32 n_tables, u32 n_subbands,
int prof_a, int prof_b);
int iwl_fill_ppag_table(struct iwl_fw_runtime *fwrt,
union iwl_ppag_table_cmd *cmd,
int *cmd_size);
bool iwl_is_ppag_approved(struct iwl_fw_runtime *fwrt);
int iwl_bios_get_wrds_table(struct iwl_fw_runtime *fwrt);
int iwl_bios_get_ewrd_table(struct iwl_fw_runtime *fwrt);
......
......@@ -1104,7 +1104,7 @@ int iwl_mvm_ppag_send_cmd(struct iwl_mvm *mvm)
static int iwl_mvm_ppag_init(struct iwl_mvm *mvm)
{
/* no need to read the table, done in INIT stage */
if (!(iwl_acpi_is_ppag_approved(&mvm->fwrt)))
if (!(iwl_is_ppag_approved(&mvm->fwrt)))
return 0;
return iwl_mvm_ppag_send_cmd(mvm);
......
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