Path: blob/main/sys/contrib/dev/iwlwifi/fw/regulatory.c
48287 views
// SPDX-License-Identifier: GPL-2.0 OR BSD-3-Clause1/*2* Copyright (C) 2023, 2025 Intel Corporation3*/4#if defined(__FreeBSD__)5#include <linux/bitfield.h>6#endif7#include <linux/dmi.h>8#include "iwl-drv.h"9#include "iwl-debug.h"10#include "regulatory.h"11#include "fw/runtime.h"12#include "fw/uefi.h"1314#define GET_BIOS_TABLE(__name, ...) \15do { \16int ret = -ENOENT; \17if (fwrt->uefi_tables_lock_status > UEFI_WIFI_GUID_UNLOCKED) \18ret = iwl_uefi_get_ ## __name(__VA_ARGS__); \19if (ret < 0) \20ret = iwl_acpi_get_ ## __name(__VA_ARGS__); \21return ret; \22} while (0)2324#define IWL_BIOS_TABLE_LOADER(__name) \25int iwl_bios_get_ ## __name(struct iwl_fw_runtime *fwrt) \26{GET_BIOS_TABLE(__name, fwrt); } \27IWL_EXPORT_SYMBOL(iwl_bios_get_ ## __name)2829#define IWL_BIOS_TABLE_LOADER_DATA(__name, data_type) \30int iwl_bios_get_ ## __name(struct iwl_fw_runtime *fwrt, \31data_type * data) \32{GET_BIOS_TABLE(__name, fwrt, data); } \33IWL_EXPORT_SYMBOL(iwl_bios_get_ ## __name)3435IWL_BIOS_TABLE_LOADER(wrds_table);36IWL_BIOS_TABLE_LOADER(ewrd_table);37IWL_BIOS_TABLE_LOADER(wgds_table);38IWL_BIOS_TABLE_LOADER(ppag_table);39IWL_BIOS_TABLE_LOADER(phy_filters);40IWL_BIOS_TABLE_LOADER_DATA(tas_table, struct iwl_tas_data);41IWL_BIOS_TABLE_LOADER_DATA(pwr_limit, u64);42IWL_BIOS_TABLE_LOADER_DATA(mcc, char);43IWL_BIOS_TABLE_LOADER_DATA(eckv, u32);44IWL_BIOS_TABLE_LOADER_DATA(wbem, u32);45IWL_BIOS_TABLE_LOADER_DATA(dsbr, u32);464748static const struct dmi_system_id dmi_ppag_approved_list[] = {49{ .ident = "HP",50.matches = {51DMI_MATCH(DMI_SYS_VENDOR, "HP"),52},53},54{ .ident = "SAMSUNG",55.matches = {56DMI_MATCH(DMI_SYS_VENDOR, "SAMSUNG ELECTRONICS CO., LTD"),57},58},59{ .ident = "MSFT",60.matches = {61DMI_MATCH(DMI_SYS_VENDOR, "Microsoft Corporation"),62},63},64{ .ident = "ASUS",65.matches = {66DMI_MATCH(DMI_SYS_VENDOR, "ASUSTeK COMPUTER INC."),67},68},69{ .ident = "GOOGLE-HP",70.matches = {71DMI_MATCH(DMI_SYS_VENDOR, "Google"),72DMI_MATCH(DMI_BOARD_VENDOR, "HP"),73},74},75{ .ident = "GOOGLE-ASUS",76.matches = {77DMI_MATCH(DMI_SYS_VENDOR, "Google"),78DMI_MATCH(DMI_BOARD_VENDOR, "ASUSTek COMPUTER INC."),79},80},81{ .ident = "GOOGLE-SAMSUNG",82.matches = {83DMI_MATCH(DMI_SYS_VENDOR, "Google"),84DMI_MATCH(DMI_BOARD_VENDOR, "SAMSUNG ELECTRONICS CO., LTD"),85},86},87{ .ident = "DELL",88.matches = {89DMI_MATCH(DMI_SYS_VENDOR, "Dell Inc."),90},91},92{ .ident = "DELL",93.matches = {94DMI_MATCH(DMI_SYS_VENDOR, "Alienware"),95},96},97{ .ident = "RAZER",98.matches = {99DMI_MATCH(DMI_SYS_VENDOR, "Razer"),100},101},102{ .ident = "Honor",103.matches = {104DMI_MATCH(DMI_SYS_VENDOR, "HONOR"),105},106},107{ .ident = "WIKO",108.matches = {109DMI_MATCH(DMI_SYS_VENDOR, "WIKO"),110},111},112{}113};114115static const struct dmi_system_id dmi_tas_approved_list[] = {116{ .ident = "HP",117.matches = {118DMI_MATCH(DMI_SYS_VENDOR, "HP"),119},120},121{ .ident = "SAMSUNG",122.matches = {123DMI_MATCH(DMI_SYS_VENDOR, "SAMSUNG ELECTRONICS CO., LTD"),124},125},126{ .ident = "LENOVO",127.matches = {128DMI_MATCH(DMI_SYS_VENDOR, "LENOVO"),129},130},131{ .ident = "DELL",132.matches = {133DMI_MATCH(DMI_SYS_VENDOR, "Dell Inc."),134},135},136{ .ident = "MSFT",137.matches = {138DMI_MATCH(DMI_SYS_VENDOR, "Microsoft Corporation"),139},140},141{ .ident = "Acer",142.matches = {143DMI_MATCH(DMI_SYS_VENDOR, "Acer"),144},145},146{ .ident = "ASUS",147.matches = {148DMI_MATCH(DMI_SYS_VENDOR, "ASUSTeK COMPUTER INC."),149},150},151{ .ident = "GOOGLE-HP",152.matches = {153DMI_MATCH(DMI_SYS_VENDOR, "Google"),154DMI_MATCH(DMI_BOARD_VENDOR, "HP"),155},156},157{ .ident = "MSI",158.matches = {159DMI_MATCH(DMI_SYS_VENDOR, "Micro-Star International Co., Ltd."),160},161},162{ .ident = "Honor",163.matches = {164DMI_MATCH(DMI_SYS_VENDOR, "HONOR"),165},166},167/* keep last */168{}169};170171bool iwl_sar_geo_support(struct iwl_fw_runtime *fwrt)172{173/*174* The PER_CHAIN_LIMIT_OFFSET_CMD command is not supported on175* earlier firmware versions. Unfortunately, we don't have a176* TLV API flag to rely on, so rely on the major version which177* is in the first byte of ucode_ver. This was implemented178* initially on version 38 and then backported to 17. It was179* also backported to 29, but only for 7265D devices. The180* intention was to have it in 36 as well, but not all 8000181* family got this feature enabled. The 8000 family is the182* only one using version 36, so skip this version entirely.183*/184return IWL_UCODE_SERIAL(fwrt->fw->ucode_ver) >= 38 ||185(IWL_UCODE_SERIAL(fwrt->fw->ucode_ver) == 17 &&186fwrt->trans->info.hw_rev != CSR_HW_REV_TYPE_3160) ||187(IWL_UCODE_SERIAL(fwrt->fw->ucode_ver) == 29 &&188((fwrt->trans->info.hw_rev & CSR_HW_REV_TYPE_MSK) ==189CSR_HW_REV_TYPE_7265D));190}191IWL_EXPORT_SYMBOL(iwl_sar_geo_support);192193int iwl_sar_geo_fill_table(struct iwl_fw_runtime *fwrt,194struct iwl_per_chain_offset *table,195u32 n_bands, u32 n_profiles)196{197int i, j;198199if (!fwrt->geo_enabled)200return -ENODATA;201202if (!iwl_sar_geo_support(fwrt))203return -EOPNOTSUPP;204205for (i = 0; i < n_profiles; i++) {206for (j = 0; j < n_bands; j++) {207struct iwl_per_chain_offset *chain =208&table[i * n_bands + j];209210chain->max_tx_power =211cpu_to_le16(fwrt->geo_profiles[i].bands[j].max);212chain->chain_a =213fwrt->geo_profiles[i].bands[j].chains[0];214chain->chain_b =215fwrt->geo_profiles[i].bands[j].chains[1];216IWL_DEBUG_RADIO(fwrt,217"SAR geographic profile[%d] Band[%d]: chain A = %d chain B = %d max_tx_power = %d\n",218i, j,219fwrt->geo_profiles[i].bands[j].chains[0],220fwrt->geo_profiles[i].bands[j].chains[1],221fwrt->geo_profiles[i].bands[j].max);222}223}224225return 0;226}227IWL_EXPORT_SYMBOL(iwl_sar_geo_fill_table);228229static int iwl_sar_fill_table(struct iwl_fw_runtime *fwrt,230__le16 *per_chain, u32 n_subbands,231int prof_a, int prof_b)232{233int profs[BIOS_SAR_NUM_CHAINS] = { prof_a, prof_b };234int i, j;235236for (i = 0; i < BIOS_SAR_NUM_CHAINS; i++) {237struct iwl_sar_profile *prof;238239/* don't allow SAR to be disabled (profile 0 means disable) */240if (profs[i] == 0)241return -EPERM;242243/* we are off by one, so allow up to BIOS_SAR_MAX_PROFILE_NUM */244if (profs[i] > BIOS_SAR_MAX_PROFILE_NUM)245return -EINVAL;246247/* profiles go from 1 to 4, so decrement to access the array */248prof = &fwrt->sar_profiles[profs[i] - 1];249250/* if the profile is disabled, do nothing */251if (!prof->enabled) {252IWL_DEBUG_RADIO(fwrt, "SAR profile %d is disabled.\n",253profs[i]);254/*255* if one of the profiles is disabled, we256* ignore all of them and return 1 to257* differentiate disabled from other failures.258*/259return 1;260}261262IWL_DEBUG_INFO(fwrt,263"SAR EWRD: chain %d profile index %d\n",264i, profs[i]);265IWL_DEBUG_RADIO(fwrt, " Chain[%d]:\n", i);266for (j = 0; j < n_subbands; j++) {267per_chain[i * n_subbands + j] =268cpu_to_le16(prof->chains[i].subbands[j]);269IWL_DEBUG_RADIO(fwrt, " Band[%d] = %d * .125dBm\n",270j, prof->chains[i].subbands[j]);271}272}273274return 0;275}276277int iwl_sar_fill_profile(struct iwl_fw_runtime *fwrt,278__le16 *per_chain, u32 n_tables, u32 n_subbands,279int prof_a, int prof_b)280{281int i, ret = 0;282283for (i = 0; i < n_tables; i++) {284ret = iwl_sar_fill_table(fwrt,285&per_chain[i * n_subbands * BIOS_SAR_NUM_CHAINS],286n_subbands, prof_a, prof_b);287if (ret)288break;289}290291return ret;292}293IWL_EXPORT_SYMBOL(iwl_sar_fill_profile);294295static bool iwl_ppag_value_valid(struct iwl_fw_runtime *fwrt, int chain,296int subband)297{298s8 ppag_val = fwrt->ppag_chains[chain].subbands[subband];299300if ((subband == 0 &&301(ppag_val > IWL_PPAG_MAX_LB || ppag_val < IWL_PPAG_MIN_LB)) ||302(subband != 0 &&303(ppag_val > IWL_PPAG_MAX_HB || ppag_val < IWL_PPAG_MIN_HB))) {304IWL_DEBUG_RADIO(fwrt, "Invalid PPAG value: %d\n", ppag_val);305return false;306}307return true;308}309310int iwl_fill_ppag_table(struct iwl_fw_runtime *fwrt,311union iwl_ppag_table_cmd *cmd, int *cmd_size)312{313u8 cmd_ver;314int i, j, num_sub_bands;315s8 *gain;316bool send_ppag_always;317318/* many firmware images for JF lie about this */319if (CSR_HW_RFID_TYPE(fwrt->trans->info.hw_rf_id) ==320CSR_HW_RFID_TYPE(CSR_HW_RF_ID_TYPE_JF))321return -EOPNOTSUPP;322323if (!fw_has_capa(&fwrt->fw->ucode_capa, IWL_UCODE_TLV_CAPA_SET_PPAG)) {324IWL_DEBUG_RADIO(fwrt,325"PPAG capability not supported by FW, command not sent.\n");326return -EINVAL;327}328329cmd_ver = iwl_fw_lookup_cmd_ver(fwrt->fw,330WIDE_ID(PHY_OPS_GROUP,331PER_PLATFORM_ANT_GAIN_CMD), 1);332/*333* Starting from ver 4, driver needs to send the PPAG CMD regardless334* if PPAG is enabled/disabled or valid/invalid.335*/336send_ppag_always = cmd_ver > 3;337338/* Don't send PPAG if it is disabled */339if (!send_ppag_always && !fwrt->ppag_flags) {340IWL_DEBUG_RADIO(fwrt, "PPAG not enabled, command not sent.\n");341return -EINVAL;342}343344IWL_DEBUG_RADIO(fwrt, "PPAG cmd ver is %d\n", cmd_ver);345if (cmd_ver == 1) {346num_sub_bands = IWL_NUM_SUB_BANDS_V1;347gain = cmd->v1.gain[0];348*cmd_size = sizeof(cmd->v1);349cmd->v1.flags = cpu_to_le32(fwrt->ppag_flags);350if (fwrt->ppag_bios_rev >= 1) {351/* in this case FW supports revision 0 */352IWL_DEBUG_RADIO(fwrt,353"PPAG table rev is %d, send truncated table\n",354fwrt->ppag_bios_rev);355}356} else if (cmd_ver >= 2 && cmd_ver <= 6) {357num_sub_bands = IWL_NUM_SUB_BANDS_V2;358gain = cmd->v2.gain[0];359*cmd_size = sizeof(cmd->v2);360cmd->v2.flags = cpu_to_le32(fwrt->ppag_flags);361if (fwrt->ppag_bios_rev == 0) {362/* in this case FW supports revisions 1,2 or 3 */363IWL_DEBUG_RADIO(fwrt,364"PPAG table rev is 0, send padded table\n");365}366} else if (cmd_ver == 7) {367num_sub_bands = IWL_NUM_SUB_BANDS_V2;368gain = cmd->v3.gain[0];369*cmd_size = sizeof(cmd->v3);370cmd->v3.ppag_config_info.table_source = fwrt->ppag_bios_source;371cmd->v3.ppag_config_info.table_revision = fwrt->ppag_bios_rev;372cmd->v3.ppag_config_info.value = cpu_to_le32(fwrt->ppag_flags);373} else {374IWL_DEBUG_RADIO(fwrt, "Unsupported PPAG command version\n");375return -EINVAL;376}377378/* ppag mode */379IWL_DEBUG_RADIO(fwrt,380"PPAG MODE bits were read from bios: %d\n",381fwrt->ppag_flags);382383if (cmd_ver == 6)384cmd->v1.flags &= cpu_to_le32(IWL_PPAG_CMD_V6_MASK);385else if (cmd_ver == 5)386cmd->v1.flags &= cpu_to_le32(IWL_PPAG_CMD_V5_MASK);387else if (cmd_ver < 5)388cmd->v1.flags &= cpu_to_le32(IWL_PPAG_CMD_V4_MASK);389390if ((cmd_ver == 1 &&391!fw_has_capa(&fwrt->fw->ucode_capa,392IWL_UCODE_TLV_CAPA_PPAG_CHINA_BIOS_SUPPORT)) ||393(cmd_ver == 2 && fwrt->ppag_bios_rev >= 2)) {394cmd->v1.flags &= cpu_to_le32(IWL_PPAG_ETSI_MASK);395IWL_DEBUG_RADIO(fwrt, "masking ppag China bit\n");396} else {397IWL_DEBUG_RADIO(fwrt, "isn't masking ppag China bit\n");398}399400/* The 'flags' field is the same in v1 and v2 so we can just401* use v1 to access it.402*/403IWL_DEBUG_RADIO(fwrt,404"PPAG MODE bits going to be sent: %d\n",405(cmd_ver < 7) ? le32_to_cpu(cmd->v1.flags) :406le32_to_cpu(cmd->v3.ppag_config_info.value));407408for (i = 0; i < IWL_NUM_CHAIN_LIMITS; i++) {409for (j = 0; j < num_sub_bands; j++) {410if (!send_ppag_always &&411!iwl_ppag_value_valid(fwrt, i, j))412return -EINVAL;413414gain[i * num_sub_bands + j] =415fwrt->ppag_chains[i].subbands[j];416IWL_DEBUG_RADIO(fwrt,417"PPAG table: chain[%d] band[%d]: gain = %d\n",418i, j, gain[i * num_sub_bands + j]);419}420}421422return 0;423}424IWL_EXPORT_SYMBOL(iwl_fill_ppag_table);425426bool iwl_is_ppag_approved(struct iwl_fw_runtime *fwrt)427{428if (!dmi_check_system(dmi_ppag_approved_list)) {429IWL_DEBUG_RADIO(fwrt,430"System vendor '%s' is not in the approved list, disabling PPAG.\n",431dmi_get_system_info(DMI_SYS_VENDOR) ?: "<unknown>");432fwrt->ppag_flags = 0;433return false;434}435436return true;437}438IWL_EXPORT_SYMBOL(iwl_is_ppag_approved);439440bool iwl_is_tas_approved(void)441{442return dmi_check_system(dmi_tas_approved_list);443}444IWL_EXPORT_SYMBOL(iwl_is_tas_approved);445446struct iwl_tas_selection_data447iwl_parse_tas_selection(const u32 tas_selection_in, const u8 tbl_rev)448{449struct iwl_tas_selection_data tas_selection_out = {};450u8 override_iec = u32_get_bits(tas_selection_in,451IWL_WTAS_OVERRIDE_IEC_MSK);452u8 canada_tas_uhb = u32_get_bits(tas_selection_in,453IWL_WTAS_CANADA_UHB_MSK);454u8 enabled_iec = u32_get_bits(tas_selection_in,455IWL_WTAS_ENABLE_IEC_MSK);456u8 usa_tas_uhb = u32_get_bits(tas_selection_in,457IWL_WTAS_USA_UHB_MSK);458459if (tbl_rev > 0) {460tas_selection_out.usa_tas_uhb_allowed = usa_tas_uhb;461tas_selection_out.override_tas_iec = override_iec;462tas_selection_out.enable_tas_iec = enabled_iec;463}464465if (tbl_rev > 1)466tas_selection_out.canada_tas_uhb_allowed = canada_tas_uhb;467468return tas_selection_out;469}470IWL_EXPORT_SYMBOL(iwl_parse_tas_selection);471472bool iwl_add_mcc_to_tas_block_list(u16 *list, u8 *size, u16 mcc)473{474for (int i = 0; i < *size; i++) {475if (list[i] == mcc)476return true;477}478479/* Verify that there is room for another country480* If *size == IWL_WTAS_BLACK_LIST_MAX, then the table is full.481*/482if (*size >= IWL_WTAS_BLACK_LIST_MAX)483return false;484485list[*size++] = mcc;486return true;487}488IWL_EXPORT_SYMBOL(iwl_add_mcc_to_tas_block_list);489490__le32 iwl_get_lari_config_bitmap(struct iwl_fw_runtime *fwrt)491{492int ret;493u32 val;494__le32 config_bitmap = 0;495496switch (CSR_HW_RFID_TYPE(fwrt->trans->info.hw_rf_id)) {497case IWL_CFG_RF_TYPE_HR1:498case IWL_CFG_RF_TYPE_HR2:499case IWL_CFG_RF_TYPE_JF1:500case IWL_CFG_RF_TYPE_JF2:501ret = iwl_bios_get_dsm(fwrt, DSM_FUNC_ENABLE_INDONESIA_5G2,502&val);503504if (!ret && val == DSM_VALUE_INDONESIA_ENABLE)505config_bitmap |=506cpu_to_le32(LARI_CONFIG_ENABLE_5G2_IN_INDONESIA_MSK);507break;508default:509break;510}511512ret = iwl_bios_get_dsm(fwrt, DSM_FUNC_DISABLE_SRD, &val);513if (!ret) {514if (val == DSM_VALUE_SRD_PASSIVE)515config_bitmap |=516cpu_to_le32(LARI_CONFIG_CHANGE_ETSI_TO_PASSIVE_MSK);517else if (val == DSM_VALUE_SRD_DISABLE)518config_bitmap |=519cpu_to_le32(LARI_CONFIG_CHANGE_ETSI_TO_DISABLED_MSK);520}521522if (fw_has_capa(&fwrt->fw->ucode_capa,523IWL_UCODE_TLV_CAPA_CHINA_22_REG_SUPPORT)) {524ret = iwl_bios_get_dsm(fwrt, DSM_FUNC_REGULATORY_CONFIG,525&val);526/*527* China 2022 enable if the BIOS object does not exist or528* if it is enabled in BIOS.529*/530if (ret < 0 || val & DSM_MASK_CHINA_22_REG)531config_bitmap |=532cpu_to_le32(LARI_CONFIG_ENABLE_CHINA_22_REG_SUPPORT_MSK);533}534535return config_bitmap;536}537IWL_EXPORT_SYMBOL(iwl_get_lari_config_bitmap);538539static size_t iwl_get_lari_config_cmd_size(u8 cmd_ver)540{541size_t cmd_size;542543switch (cmd_ver) {544case 12:545case 11:546cmd_size = sizeof(struct iwl_lari_config_change_cmd);547break;548case 10:549cmd_size = sizeof(struct iwl_lari_config_change_cmd_v10);550break;551case 9:552case 8:553case 7:554cmd_size = sizeof(struct iwl_lari_config_change_cmd_v7);555break;556case 6:557cmd_size = sizeof(struct iwl_lari_config_change_cmd_v6);558break;559case 5:560cmd_size = sizeof(struct iwl_lari_config_change_cmd_v5);561break;562case 4:563cmd_size = sizeof(struct iwl_lari_config_change_cmd_v4);564break;565case 3:566cmd_size = sizeof(struct iwl_lari_config_change_cmd_v3);567break;568case 2:569cmd_size = sizeof(struct iwl_lari_config_change_cmd_v2);570break;571default:572cmd_size = sizeof(struct iwl_lari_config_change_cmd_v1);573break;574}575return cmd_size;576}577578int iwl_fill_lari_config(struct iwl_fw_runtime *fwrt,579struct iwl_lari_config_change_cmd *cmd,580size_t *cmd_size)581{582int ret;583u32 value;584bool has_raw_dsm_capa = fw_has_capa(&fwrt->fw->ucode_capa,585IWL_UCODE_TLV_CAPA_FW_ACCEPTS_RAW_DSM_TABLE);586u8 cmd_ver = iwl_fw_lookup_cmd_ver(fwrt->fw,587WIDE_ID(REGULATORY_AND_NVM_GROUP,588LARI_CONFIG_CHANGE), 1);589590if (WARN_ONCE(cmd_ver > 12,591"Don't add newer versions to this function\n"))592return -EINVAL;593594memset(cmd, 0, sizeof(*cmd));595*cmd_size = iwl_get_lari_config_cmd_size(cmd_ver);596597cmd->config_bitmap = iwl_get_lari_config_bitmap(fwrt);598599ret = iwl_bios_get_dsm(fwrt, DSM_FUNC_11AX_ENABLEMENT, &value);600if (!ret) {601if (!has_raw_dsm_capa)602value &= DSM_11AX_ALLOW_BITMAP;603cmd->oem_11ax_allow_bitmap = cpu_to_le32(value);604}605606ret = iwl_bios_get_dsm(fwrt, DSM_FUNC_ENABLE_UNII4_CHAN, &value);607if (!ret) {608if (!has_raw_dsm_capa)609value &= DSM_UNII4_ALLOW_BITMAP;610611/* Since version 9, bits 4 and 5 are supported612* regardless of this capability, By pass this masking613* if firmware has capability of accepting raw DSM table.614*/615if (!has_raw_dsm_capa && cmd_ver < 9 &&616!fw_has_capa(&fwrt->fw->ucode_capa,617IWL_UCODE_TLV_CAPA_BIOS_OVERRIDE_5G9_FOR_CA))618value &= ~(DSM_VALUE_UNII4_CANADA_OVERRIDE_MSK |619DSM_VALUE_UNII4_CANADA_EN_MSK);620621cmd->oem_unii4_allow_bitmap = cpu_to_le32(value);622}623624ret = iwl_bios_get_dsm(fwrt, DSM_FUNC_ACTIVATE_CHANNEL, &value);625if (!ret) {626if (!has_raw_dsm_capa)627value &= CHAN_STATE_ACTIVE_BITMAP_CMD_V12;628629if (!has_raw_dsm_capa && cmd_ver < 8)630value &= ~ACTIVATE_5G2_IN_WW_MASK;631632/* Since version 12, bits 5 and 6 are supported633* regardless of this capability, By pass this masking634* if firmware has capability of accepting raw DSM table.635*/636if (!has_raw_dsm_capa && cmd_ver < 12 &&637!fw_has_capa(&fwrt->fw->ucode_capa,638IWL_UCODE_TLV_CAPA_BIOS_OVERRIDE_UNII4_US_CA))639value &= CHAN_STATE_ACTIVE_BITMAP_CMD_V11;640641cmd->chan_state_active_bitmap = cpu_to_le32(value);642}643644ret = iwl_bios_get_dsm(fwrt, DSM_FUNC_ENABLE_6E, &value);645if (!ret)646cmd->oem_uhb_allow_bitmap = cpu_to_le32(value);647648ret = iwl_bios_get_dsm(fwrt, DSM_FUNC_FORCE_DISABLE_CHANNELS, &value);649if (!ret) {650if (!has_raw_dsm_capa)651value &= DSM_FORCE_DISABLE_CHANNELS_ALLOWED_BITMAP;652cmd->force_disable_channels_bitmap = cpu_to_le32(value);653}654655ret = iwl_bios_get_dsm(fwrt, DSM_FUNC_ENERGY_DETECTION_THRESHOLD,656&value);657if (!ret) {658if (!has_raw_dsm_capa)659value &= DSM_EDT_ALLOWED_BITMAP;660cmd->edt_bitmap = cpu_to_le32(value);661}662663ret = iwl_bios_get_wbem(fwrt, &value);664if (!ret)665cmd->oem_320mhz_allow_bitmap = cpu_to_le32(value);666667ret = iwl_bios_get_dsm(fwrt, DSM_FUNC_ENABLE_11BE, &value);668if (!ret)669cmd->oem_11be_allow_bitmap = cpu_to_le32(value);670671if (cmd->config_bitmap ||672cmd->oem_uhb_allow_bitmap ||673cmd->oem_11ax_allow_bitmap ||674cmd->oem_unii4_allow_bitmap ||675cmd->chan_state_active_bitmap ||676cmd->force_disable_channels_bitmap ||677cmd->edt_bitmap ||678cmd->oem_320mhz_allow_bitmap ||679cmd->oem_11be_allow_bitmap) {680IWL_DEBUG_RADIO(fwrt,681"sending LARI_CONFIG_CHANGE, config_bitmap=0x%x, oem_11ax_allow_bitmap=0x%x\n",682le32_to_cpu(cmd->config_bitmap),683le32_to_cpu(cmd->oem_11ax_allow_bitmap));684IWL_DEBUG_RADIO(fwrt,685"sending LARI_CONFIG_CHANGE, oem_unii4_allow_bitmap=0x%x, chan_state_active_bitmap=0x%x, cmd_ver=%d\n",686le32_to_cpu(cmd->oem_unii4_allow_bitmap),687le32_to_cpu(cmd->chan_state_active_bitmap),688cmd_ver);689IWL_DEBUG_RADIO(fwrt,690"sending LARI_CONFIG_CHANGE, oem_uhb_allow_bitmap=0x%x, force_disable_channels_bitmap=0x%x\n",691le32_to_cpu(cmd->oem_uhb_allow_bitmap),692le32_to_cpu(cmd->force_disable_channels_bitmap));693IWL_DEBUG_RADIO(fwrt,694"sending LARI_CONFIG_CHANGE, edt_bitmap=0x%x, oem_320mhz_allow_bitmap=0x%x\n",695le32_to_cpu(cmd->edt_bitmap),696le32_to_cpu(cmd->oem_320mhz_allow_bitmap));697IWL_DEBUG_RADIO(fwrt,698"sending LARI_CONFIG_CHANGE, oem_11be_allow_bitmap=0x%x\n",699le32_to_cpu(cmd->oem_11be_allow_bitmap));700} else {701return 1;702}703704return 0;705}706IWL_EXPORT_SYMBOL(iwl_fill_lari_config);707708int iwl_bios_get_dsm(struct iwl_fw_runtime *fwrt, enum iwl_dsm_funcs func,709u32 *value)710{711GET_BIOS_TABLE(dsm, fwrt, func, value);712}713IWL_EXPORT_SYMBOL(iwl_bios_get_dsm);714715bool iwl_puncturing_is_allowed_in_bios(u32 puncturing, u16 mcc)716{717/* Some kind of regulatory mess means we need to currently disallow718* puncturing in the US and Canada unless enabled in BIOS.719*/720switch (mcc) {721case IWL_MCC_US:722return puncturing & IWL_UEFI_CNV_PUNCTURING_USA_EN_MSK;723case IWL_MCC_CANADA:724return puncturing & IWL_UEFI_CNV_PUNCTURING_CANADA_EN_MSK;725default:726return true;727}728}729IWL_EXPORT_SYMBOL(iwl_puncturing_is_allowed_in_bios);730731bool iwl_rfi_is_enabled_in_bios(struct iwl_fw_runtime *fwrt)732{733/* default behaviour is disabled */734u32 value = 0;735int ret = iwl_bios_get_dsm(fwrt, DSM_FUNC_RFI_CONFIG, &value);736737if (ret < 0) {738IWL_DEBUG_RADIO(fwrt, "Failed to get DSM RFI, ret=%d\n", ret);739return false;740}741742value &= DSM_VALUE_RFI_DISABLE;743/* RFI BIOS CONFIG value can be 0 or 3 only.744* i.e 0 means DDR and DLVR enabled. 3 means DDR and DLVR disabled.745* 1 and 2 are invalid BIOS configurations, So, it's not possible to746* disable ddr/dlvr separately.747*/748if (!value) {749IWL_DEBUG_RADIO(fwrt, "DSM RFI is evaluated to enable\n");750return true;751} else if (value == DSM_VALUE_RFI_DISABLE) {752IWL_DEBUG_RADIO(fwrt, "DSM RFI is evaluated to disable\n");753} else {754IWL_DEBUG_RADIO(fwrt,755"DSM RFI got invalid value, value=%d\n", value);756}757758return false;759}760IWL_EXPORT_SYMBOL(iwl_rfi_is_enabled_in_bios);761762763