Path: blob/main/sys/contrib/dev/iwlwifi/mld/regulatory.c
48287 views
// SPDX-License-Identifier: GPL-2.0 OR BSD-3-Clause1/*2* Copyright (C) 2024-2025 Intel Corporation3*/45#include <linux/dmi.h>67#include "fw/regulatory.h"8#include "fw/acpi.h"9#include "fw/uefi.h"1011#include "regulatory.h"12#include "mld.h"13#include "hcmd.h"1415void iwl_mld_get_bios_tables(struct iwl_mld *mld)16{17int ret;1819iwl_acpi_get_guid_lock_status(&mld->fwrt);2021ret = iwl_bios_get_ppag_table(&mld->fwrt);22if (ret < 0) {23IWL_DEBUG_RADIO(mld,24"PPAG BIOS table invalid or unavailable. (%d)\n",25ret);26}2728ret = iwl_bios_get_wrds_table(&mld->fwrt);29if (ret < 0) {30IWL_DEBUG_RADIO(mld,31"WRDS SAR BIOS table invalid or unavailable. (%d)\n",32ret);3334/* If not available, don't fail and don't bother with EWRD and35* WGDS36*/3738if (!iwl_bios_get_wgds_table(&mld->fwrt)) {39/* If basic SAR is not available, we check for WGDS,40* which should *not* be available either. If it is41* available, issue an error, because we can't use SAR42* Geo without basic SAR.43*/44IWL_ERR(mld, "BIOS contains WGDS but no WRDS\n");45}4647} else {48ret = iwl_bios_get_ewrd_table(&mld->fwrt);49/* If EWRD is not available, we can still use50* WRDS, so don't fail.51*/52if (ret < 0)53IWL_DEBUG_RADIO(mld,54"EWRD SAR BIOS table invalid or unavailable. (%d)\n",55ret);5657ret = iwl_bios_get_wgds_table(&mld->fwrt);58if (ret < 0)59IWL_DEBUG_RADIO(mld,60"Geo SAR BIOS table invalid or unavailable. (%d)\n",61ret);62/* we don't fail if the table is not available */63}6465iwl_uefi_get_uats_table(mld->trans, &mld->fwrt);6667iwl_bios_get_phy_filters(&mld->fwrt);68}6970static int iwl_mld_geo_sar_init(struct iwl_mld *mld)71{72u32 cmd_id = WIDE_ID(PHY_OPS_GROUP, PER_CHAIN_LIMIT_OFFSET_CMD);73/* Only set to South Korea if the table revision is 1 */74__le32 sk = cpu_to_le32(mld->fwrt.geo_rev == 1 ? 1 : 0);75union iwl_geo_tx_power_profiles_cmd cmd = {76.v5.ops = cpu_to_le32(IWL_PER_CHAIN_OFFSET_SET_TABLES),77.v5.table_revision = sk,78};79int ret;8081ret = iwl_sar_geo_fill_table(&mld->fwrt, &cmd.v5.table[0][0],82ARRAY_SIZE(cmd.v5.table[0]),83BIOS_GEO_MAX_PROFILE_NUM);8485/* It is a valid scenario to not support SAR, or miss wgds table,86* but in that case there is no need to send the command.87*/88if (ret)89return 0;9091return iwl_mld_send_cmd_pdu(mld, cmd_id, &cmd, sizeof(cmd.v5));92}9394int iwl_mld_config_sar_profile(struct iwl_mld *mld, int prof_a, int prof_b)95{96u32 cmd_id = REDUCE_TX_POWER_CMD;97struct iwl_dev_tx_power_cmd cmd = {98.common.set_mode = cpu_to_le32(IWL_TX_POWER_MODE_SET_CHAINS),99.v10.flags = cpu_to_le32(mld->fwrt.reduced_power_flags),100};101int ret;102103/* TODO: CDB - support IWL_NUM_CHAIN_TABLES_V2 */104ret = iwl_sar_fill_profile(&mld->fwrt, &cmd.v10.per_chain[0][0][0],105IWL_NUM_CHAIN_TABLES, IWL_NUM_SUB_BANDS_V2,106prof_a, prof_b);107/* return on error or if the profile is disabled (positive number) */108if (ret)109return ret;110111return iwl_mld_send_cmd_pdu(mld, cmd_id, &cmd,112sizeof(cmd.common) + sizeof(cmd.v10));113}114115int iwl_mld_init_sar(struct iwl_mld *mld)116{117int chain_a_prof = 1;118int chain_b_prof = 1;119int ret;120121/* If no profile was chosen by the user yet, choose profile 1 (WRDS) as122* default for both chains123*/124if (mld->fwrt.sar_chain_a_profile && mld->fwrt.sar_chain_b_profile) {125chain_a_prof = mld->fwrt.sar_chain_a_profile;126chain_b_prof = mld->fwrt.sar_chain_b_profile;127}128129ret = iwl_mld_config_sar_profile(mld, chain_a_prof, chain_b_prof);130if (ret < 0)131return ret;132133if (ret)134return 0;135136return iwl_mld_geo_sar_init(mld);137}138139int iwl_mld_init_sgom(struct iwl_mld *mld)140{141int ret;142struct iwl_host_cmd cmd = {143.id = WIDE_ID(REGULATORY_AND_NVM_GROUP,144SAR_OFFSET_MAPPING_TABLE_CMD),145.data[0] = &mld->fwrt.sgom_table,146.len[0] = sizeof(mld->fwrt.sgom_table),147.dataflags[0] = IWL_HCMD_DFL_NOCOPY,148};149150if (!mld->fwrt.sgom_enabled) {151IWL_DEBUG_RADIO(mld, "SGOM table is disabled\n");152return 0;153}154155ret = iwl_mld_send_cmd(mld, &cmd);156if (ret)157IWL_ERR(mld,158"failed to send SAR_OFFSET_MAPPING_CMD (%d)\n", ret);159160return ret;161}162163static int iwl_mld_ppag_send_cmd(struct iwl_mld *mld)164{165union iwl_ppag_table_cmd cmd = {};166int ret, len;167168ret = iwl_fill_ppag_table(&mld->fwrt, &cmd, &len);169/* Not supporting PPAG table is a valid scenario */170if (ret < 0)171return 0;172173IWL_DEBUG_RADIO(mld, "Sending PER_PLATFORM_ANT_GAIN_CMD\n");174ret = iwl_mld_send_cmd_pdu(mld, WIDE_ID(PHY_OPS_GROUP,175PER_PLATFORM_ANT_GAIN_CMD),176&cmd, len);177if (ret < 0)178IWL_ERR(mld, "failed to send PER_PLATFORM_ANT_GAIN_CMD (%d)\n",179ret);180181return ret;182}183184int iwl_mld_init_ppag(struct iwl_mld *mld)185{186/* no need to read the table, done in INIT stage */187188if (!(iwl_is_ppag_approved(&mld->fwrt)))189return 0;190191return iwl_mld_ppag_send_cmd(mld);192}193194void iwl_mld_configure_lari(struct iwl_mld *mld)195{196struct iwl_fw_runtime *fwrt = &mld->fwrt;197struct iwl_lari_config_change_cmd cmd = {198.config_bitmap = iwl_get_lari_config_bitmap(fwrt),199};200bool has_raw_dsm_capa = fw_has_capa(&fwrt->fw->ucode_capa,201IWL_UCODE_TLV_CAPA_FW_ACCEPTS_RAW_DSM_TABLE);202int ret;203u32 value;204205ret = iwl_bios_get_dsm(fwrt, DSM_FUNC_11AX_ENABLEMENT, &value);206if (!ret) {207if (!has_raw_dsm_capa)208value &= DSM_11AX_ALLOW_BITMAP;209cmd.oem_11ax_allow_bitmap = cpu_to_le32(value);210}211212ret = iwl_bios_get_dsm(fwrt, DSM_FUNC_ENABLE_UNII4_CHAN, &value);213if (!ret) {214if (!has_raw_dsm_capa)215value &= DSM_UNII4_ALLOW_BITMAP;216cmd.oem_unii4_allow_bitmap = cpu_to_le32(value);217}218219ret = iwl_bios_get_dsm(fwrt, DSM_FUNC_ACTIVATE_CHANNEL, &value);220if (!ret) {221if (!has_raw_dsm_capa)222value &= CHAN_STATE_ACTIVE_BITMAP_CMD_V12;223cmd.chan_state_active_bitmap = cpu_to_le32(value);224}225226ret = iwl_bios_get_dsm(fwrt, DSM_FUNC_ENABLE_6E, &value);227if (!ret)228cmd.oem_uhb_allow_bitmap = cpu_to_le32(value);229230ret = iwl_bios_get_dsm(fwrt, DSM_FUNC_FORCE_DISABLE_CHANNELS, &value);231if (!ret) {232if (!has_raw_dsm_capa)233value &= DSM_FORCE_DISABLE_CHANNELS_ALLOWED_BITMAP;234cmd.force_disable_channels_bitmap = cpu_to_le32(value);235}236237ret = iwl_bios_get_dsm(fwrt, DSM_FUNC_ENERGY_DETECTION_THRESHOLD,238&value);239if (!ret) {240if (!has_raw_dsm_capa)241value &= DSM_EDT_ALLOWED_BITMAP;242cmd.edt_bitmap = cpu_to_le32(value);243}244245ret = iwl_bios_get_wbem(fwrt, &value);246if (!ret)247cmd.oem_320mhz_allow_bitmap = cpu_to_le32(value);248249ret = iwl_bios_get_dsm(fwrt, DSM_FUNC_ENABLE_11BE, &value);250if (!ret)251cmd.oem_11be_allow_bitmap = cpu_to_le32(value);252253if (!cmd.config_bitmap &&254!cmd.oem_uhb_allow_bitmap &&255!cmd.oem_11ax_allow_bitmap &&256!cmd.oem_unii4_allow_bitmap &&257!cmd.chan_state_active_bitmap &&258!cmd.force_disable_channels_bitmap &&259!cmd.edt_bitmap &&260!cmd.oem_320mhz_allow_bitmap &&261!cmd.oem_11be_allow_bitmap)262return;263264IWL_DEBUG_RADIO(mld,265"sending LARI_CONFIG_CHANGE, config_bitmap=0x%x, oem_11ax_allow_bitmap=0x%x\n",266le32_to_cpu(cmd.config_bitmap),267le32_to_cpu(cmd.oem_11ax_allow_bitmap));268IWL_DEBUG_RADIO(mld,269"sending LARI_CONFIG_CHANGE, oem_unii4_allow_bitmap=0x%x, chan_state_active_bitmap=0x%x\n",270le32_to_cpu(cmd.oem_unii4_allow_bitmap),271le32_to_cpu(cmd.chan_state_active_bitmap));272IWL_DEBUG_RADIO(mld,273"sending LARI_CONFIG_CHANGE, oem_uhb_allow_bitmap=0x%x, force_disable_channels_bitmap=0x%x\n",274le32_to_cpu(cmd.oem_uhb_allow_bitmap),275le32_to_cpu(cmd.force_disable_channels_bitmap));276IWL_DEBUG_RADIO(mld,277"sending LARI_CONFIG_CHANGE, edt_bitmap=0x%x, oem_320mhz_allow_bitmap=0x%x\n",278le32_to_cpu(cmd.edt_bitmap),279le32_to_cpu(cmd.oem_320mhz_allow_bitmap));280IWL_DEBUG_RADIO(mld,281"sending LARI_CONFIG_CHANGE, oem_11be_allow_bitmap=0x%x\n",282le32_to_cpu(cmd.oem_11be_allow_bitmap));283284ret = iwl_mld_send_cmd_pdu(mld, WIDE_ID(REGULATORY_AND_NVM_GROUP,285LARI_CONFIG_CHANGE), &cmd);286if (ret)287IWL_DEBUG_RADIO(mld,288"Failed to send LARI_CONFIG_CHANGE (%d)\n",289ret);290}291292void iwl_mld_init_uats(struct iwl_mld *mld)293{294int ret;295struct iwl_host_cmd cmd = {296.id = WIDE_ID(REGULATORY_AND_NVM_GROUP,297MCC_ALLOWED_AP_TYPE_CMD),298.data[0] = &mld->fwrt.uats_table,299.len[0] = sizeof(mld->fwrt.uats_table),300.dataflags[0] = IWL_HCMD_DFL_NOCOPY,301};302303if (!mld->fwrt.uats_valid)304return;305306ret = iwl_mld_send_cmd(mld, &cmd);307if (ret)308IWL_ERR(mld, "failed to send MCC_ALLOWED_AP_TYPE_CMD (%d)\n",309ret);310}311312void iwl_mld_init_tas(struct iwl_mld *mld)313{314int ret;315struct iwl_tas_data data = {};316struct iwl_tas_config_cmd cmd = {};317u32 cmd_id = WIDE_ID(REGULATORY_AND_NVM_GROUP, TAS_CONFIG);318319BUILD_BUG_ON(ARRAY_SIZE(data.block_list_array) !=320IWL_WTAS_BLACK_LIST_MAX);321BUILD_BUG_ON(ARRAY_SIZE(cmd.block_list_array) !=322IWL_WTAS_BLACK_LIST_MAX);323324if (!fw_has_capa(&mld->fw->ucode_capa, IWL_UCODE_TLV_CAPA_TAS_CFG)) {325IWL_DEBUG_RADIO(mld, "TAS not enabled in FW\n");326return;327}328329ret = iwl_bios_get_tas_table(&mld->fwrt, &data);330if (ret < 0) {331IWL_DEBUG_RADIO(mld,332"TAS table invalid or unavailable. (%d)\n",333ret);334return;335}336337if (!iwl_is_tas_approved()) {338IWL_DEBUG_RADIO(mld,339"System vendor '%s' is not in the approved list, disabling TAS in US and Canada.\n",340dmi_get_system_info(DMI_SYS_VENDOR) ?: "<unknown>");341if ((!iwl_add_mcc_to_tas_block_list(data.block_list_array,342&data.block_list_size,343IWL_MCC_US)) ||344(!iwl_add_mcc_to_tas_block_list(data.block_list_array,345&data.block_list_size,346IWL_MCC_CANADA))) {347IWL_DEBUG_RADIO(mld,348"Unable to add US/Canada to TAS block list, disabling TAS\n");349return;350}351} else {352IWL_DEBUG_RADIO(mld,353"System vendor '%s' is in the approved list.\n",354dmi_get_system_info(DMI_SYS_VENDOR) ?: "<unknown>");355}356357cmd.block_list_size = cpu_to_le16(data.block_list_size);358for (u8 i = 0; i < data.block_list_size; i++)359cmd.block_list_array[i] =360cpu_to_le16(data.block_list_array[i]);361cmd.tas_config_info.table_source = data.table_source;362cmd.tas_config_info.table_revision = data.table_revision;363cmd.tas_config_info.value = cpu_to_le32(data.tas_selection);364365ret = iwl_mld_send_cmd_pdu(mld, cmd_id, &cmd);366if (ret)367IWL_DEBUG_RADIO(mld, "failed to send TAS_CONFIG (%d)\n", ret);368}369370371