diff options
Diffstat (limited to 'sys/contrib/dev/iwlwifi/fw/regulatory.c')
| -rw-r--r-- | sys/contrib/dev/iwlwifi/fw/regulatory.c | 200 | 
1 files changed, 161 insertions, 39 deletions
| diff --git a/sys/contrib/dev/iwlwifi/fw/regulatory.c b/sys/contrib/dev/iwlwifi/fw/regulatory.c index 777564068166..768350086a06 100644 --- a/sys/contrib/dev/iwlwifi/fw/regulatory.c +++ b/sys/contrib/dev/iwlwifi/fw/regulatory.c @@ -1,6 +1,6 @@  // SPDX-License-Identifier: GPL-2.0 OR BSD-3-Clause  /* - * Copyright (C) 2023 Intel Corporation + * Copyright (C) 2023, 2025 Intel Corporation   */  #if defined(__FreeBSD__)  #include <linux/bitfield.h> @@ -37,11 +37,13 @@ IWL_BIOS_TABLE_LOADER(wrds_table);  IWL_BIOS_TABLE_LOADER(ewrd_table);  IWL_BIOS_TABLE_LOADER(wgds_table);  IWL_BIOS_TABLE_LOADER(ppag_table); +IWL_BIOS_TABLE_LOADER(phy_filters);  IWL_BIOS_TABLE_LOADER_DATA(tas_table, struct iwl_tas_data);  IWL_BIOS_TABLE_LOADER_DATA(pwr_limit, u64);  IWL_BIOS_TABLE_LOADER_DATA(mcc, char);  IWL_BIOS_TABLE_LOADER_DATA(eckv, u32);  IWL_BIOS_TABLE_LOADER_DATA(wbem, u32); +IWL_BIOS_TABLE_LOADER_DATA(dsbr, u32);  static const struct dmi_system_id dmi_ppag_approved_list[] = { @@ -103,6 +105,11 @@ static const struct dmi_system_id dmi_ppag_approved_list[] = {  			DMI_MATCH(DMI_SYS_VENDOR, "HONOR"),  		},  	}, +	{ .ident = "WIKO", +	  .matches = { +			DMI_MATCH(DMI_SYS_VENDOR, "WIKO"), +		}, +	},  	{}  }; @@ -177,9 +184,9 @@ bool iwl_sar_geo_support(struct iwl_fw_runtime *fwrt)  	 */  	return IWL_UCODE_SERIAL(fwrt->fw->ucode_ver) >= 38 ||  		(IWL_UCODE_SERIAL(fwrt->fw->ucode_ver) == 17 && -		 fwrt->trans->hw_rev != CSR_HW_REV_TYPE_3160) || +		 fwrt->trans->info.hw_rev != CSR_HW_REV_TYPE_3160) ||  		(IWL_UCODE_SERIAL(fwrt->fw->ucode_ver) == 29 && -		 ((fwrt->trans->hw_rev & CSR_HW_REV_TYPE_MSK) == +		 ((fwrt->trans->info.hw_rev & CSR_HW_REV_TYPE_MSK) ==  		  CSR_HW_REV_TYPE_7265D));  }  IWL_EXPORT_SYMBOL(iwl_sar_geo_support); @@ -310,7 +317,7 @@ int iwl_fill_ppag_table(struct iwl_fw_runtime *fwrt,  	bool send_ppag_always;  	/* many firmware images for JF lie about this */ -	if (CSR_HW_RFID_TYPE(fwrt->trans->hw_rf_id) == +	if (CSR_HW_RFID_TYPE(fwrt->trans->info.hw_rf_id) ==  	    CSR_HW_RFID_TYPE(CSR_HW_RF_ID_TYPE_JF))  		return -EOPNOTSUPP; @@ -335,31 +342,35 @@ int iwl_fill_ppag_table(struct iwl_fw_runtime *fwrt,  		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) { +		cmd->v1.flags = cpu_to_le32(fwrt->ppag_flags); +		if (fwrt->ppag_bios_rev >= 1) {  			/* in this case FW supports revision 0 */  			IWL_DEBUG_RADIO(fwrt,  					"PPAG table rev is %d, send truncated table\n", -					fwrt->ppag_ver); +					fwrt->ppag_bios_rev);  		}  	} else if (cmd_ver >= 2 && cmd_ver <= 6) {  		num_sub_bands = IWL_NUM_SUB_BANDS_V2;  		gain = cmd->v2.gain[0];  		*cmd_size = sizeof(cmd->v2); -		if (fwrt->ppag_ver == 0) { +		cmd->v2.flags = cpu_to_le32(fwrt->ppag_flags); +		if (fwrt->ppag_bios_rev == 0) {  			/* in this case FW supports revisions 1,2 or 3 */  			IWL_DEBUG_RADIO(fwrt,  					"PPAG table rev is 0, send padded table\n");  		} +	} else if (cmd_ver == 7) { +		num_sub_bands = IWL_NUM_SUB_BANDS_V2; +		gain = cmd->v3.gain[0]; +		*cmd_size = sizeof(cmd->v3); +		cmd->v3.ppag_config_info.table_source = fwrt->ppag_bios_source; +		cmd->v3.ppag_config_info.table_revision = fwrt->ppag_bios_rev; +		cmd->v3.ppag_config_info.value = cpu_to_le32(fwrt->ppag_flags);  	} else {  		IWL_DEBUG_RADIO(fwrt, "Unsupported PPAG command version\n");  		return -EINVAL; @@ -368,9 +379,11 @@ int iwl_fill_ppag_table(struct iwl_fw_runtime *fwrt,  	/* ppag mode */  	IWL_DEBUG_RADIO(fwrt,  			"PPAG MODE bits were read from bios: %d\n", -			le32_to_cpu(cmd->v1.flags)); +			fwrt->ppag_flags); -	if (cmd_ver == 5) +	if (cmd_ver == 6) +		cmd->v1.flags &= cpu_to_le32(IWL_PPAG_CMD_V6_MASK); +	else if (cmd_ver == 5)  		cmd->v1.flags &= cpu_to_le32(IWL_PPAG_CMD_V5_MASK);  	else if (cmd_ver < 5)  		cmd->v1.flags &= cpu_to_le32(IWL_PPAG_CMD_V4_MASK); @@ -378,16 +391,20 @@ int iwl_fill_ppag_table(struct iwl_fw_runtime *fwrt,  	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_ver == 2 && fwrt->ppag_bios_rev >= 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");  	} +	/* The 'flags' field is the same in v1 and v2 so we can just +	 * use v1 to access it. +	 */  	IWL_DEBUG_RADIO(fwrt,  			"PPAG MODE bits going to be sent: %d\n", -			le32_to_cpu(cmd->v1.flags)); +			(cmd_ver < 7) ? le32_to_cpu(cmd->v1.flags) : +					le32_to_cpu(cmd->v3.ppag_config_info.value));  	for (i = 0; i < IWL_NUM_CHAIN_LIMITS; i++) {  		for (j = 0; j < num_sub_bands; j++) { @@ -427,33 +444,57 @@ bool iwl_is_tas_approved(void)  }  IWL_EXPORT_SYMBOL(iwl_is_tas_approved); -int iwl_parse_tas_selection(struct iwl_fw_runtime *fwrt, -			    struct iwl_tas_data *tas_data, -			    const u32 tas_selection) +struct iwl_tas_selection_data +iwl_parse_tas_selection(const u32 tas_selection_in, const u8 tbl_rev)  { -	u8 override_iec = u32_get_bits(tas_selection, +	struct iwl_tas_selection_data tas_selection_out = {}; +	u8 override_iec = u32_get_bits(tas_selection_in,  				       IWL_WTAS_OVERRIDE_IEC_MSK); -	u8 enabled_iec = u32_get_bits(tas_selection, IWL_WTAS_ENABLE_IEC_MSK); -	u8 usa_tas_uhb = u32_get_bits(tas_selection, IWL_WTAS_USA_UHB_MSK); -	int enabled = tas_selection & IWL_WTAS_ENABLED_MSK; +	u8 canada_tas_uhb = u32_get_bits(tas_selection_in, +					 IWL_WTAS_CANADA_UHB_MSK); +	u8 enabled_iec = u32_get_bits(tas_selection_in, +				      IWL_WTAS_ENABLE_IEC_MSK); +	u8 usa_tas_uhb = u32_get_bits(tas_selection_in, +				      IWL_WTAS_USA_UHB_MSK); + +	if (tbl_rev > 0) { +		tas_selection_out.usa_tas_uhb_allowed = usa_tas_uhb; +		tas_selection_out.override_tas_iec = override_iec; +		tas_selection_out.enable_tas_iec = enabled_iec; +	} + +	if (tbl_rev > 1) +		tas_selection_out.canada_tas_uhb_allowed = canada_tas_uhb; + +	return tas_selection_out; +} +IWL_EXPORT_SYMBOL(iwl_parse_tas_selection); -	IWL_DEBUG_RADIO(fwrt, "TAS selection as read from BIOS: 0x%x\n", -			tas_selection); +bool iwl_add_mcc_to_tas_block_list(u16 *list, u8 *size, u16 mcc) +{ +	for (int i = 0; i < *size; i++) { +		if (list[i] == mcc) +			return true; +	} -	tas_data->usa_tas_uhb_allowed = usa_tas_uhb; -	tas_data->override_tas_iec = override_iec; -	tas_data->enable_tas_iec = enabled_iec; +	/* Verify that there is room for another country +	 * If *size == IWL_WTAS_BLACK_LIST_MAX, then the table is full. +	 */ +	if (*size >= IWL_WTAS_BLACK_LIST_MAX) +		return false; -	return enabled; +	list[*size++] = mcc; +	return true;  } +IWL_EXPORT_SYMBOL(iwl_add_mcc_to_tas_block_list); -static __le32 iwl_get_lari_config_bitmap(struct iwl_fw_runtime *fwrt) +__le32 iwl_get_lari_config_bitmap(struct iwl_fw_runtime *fwrt)  {  	int ret;  	u32 val;  	__le32 config_bitmap = 0; -	switch (CSR_HW_RFID_TYPE(fwrt->trans->hw_rf_id)) { +	switch (CSR_HW_RFID_TYPE(fwrt->trans->info.hw_rf_id)) {  	case IWL_CFG_RF_TYPE_HR1:  	case IWL_CFG_RF_TYPE_HR2:  	case IWL_CFG_RF_TYPE_JF1: @@ -494,6 +535,7 @@ static __le32 iwl_get_lari_config_bitmap(struct iwl_fw_runtime *fwrt)  	return config_bitmap;  } +IWL_EXPORT_SYMBOL(iwl_get_lari_config_bitmap);  static size_t iwl_get_lari_config_cmd_size(u8 cmd_ver)  { @@ -540,34 +582,61 @@ int iwl_fill_lari_config(struct iwl_fw_runtime *fwrt,  {  	int ret;  	u32 value; +	bool has_raw_dsm_capa = fw_has_capa(&fwrt->fw->ucode_capa, +					    IWL_UCODE_TLV_CAPA_FW_ACCEPTS_RAW_DSM_TABLE);  	u8 cmd_ver = iwl_fw_lookup_cmd_ver(fwrt->fw,  					   WIDE_ID(REGULATORY_AND_NVM_GROUP,  						   LARI_CONFIG_CHANGE), 1); +	if (WARN_ONCE(cmd_ver > 12, +		      "Don't add newer versions to this function\n")) +		return -EINVAL; +  	memset(cmd, 0, sizeof(*cmd));  	*cmd_size = iwl_get_lari_config_cmd_size(cmd_ver);  	cmd->config_bitmap = iwl_get_lari_config_bitmap(fwrt);  	ret = iwl_bios_get_dsm(fwrt, DSM_FUNC_11AX_ENABLEMENT, &value); -	if (!ret) +	if (!ret) { +		if (!has_raw_dsm_capa) +			value &= DSM_11AX_ALLOW_BITMAP;  		cmd->oem_11ax_allow_bitmap = cpu_to_le32(value); +	}  	ret = iwl_bios_get_dsm(fwrt, DSM_FUNC_ENABLE_UNII4_CHAN, &value);  	if (!ret) { -		if (cmd_ver < 9) -			value &= DSM_UNII4_ALLOW_BITMAP_CMD_V8; -		else +		if (!has_raw_dsm_capa)  			value &= DSM_UNII4_ALLOW_BITMAP; +		/* Since version 9, bits 4 and 5 are supported +		 * regardless of this capability, By pass this masking +		 * if firmware has capability of accepting raw DSM table. +		 */ +		if (!has_raw_dsm_capa && cmd_ver < 9 && +		    !fw_has_capa(&fwrt->fw->ucode_capa, +				 IWL_UCODE_TLV_CAPA_BIOS_OVERRIDE_5G9_FOR_CA)) +			value &= ~(DSM_VALUE_UNII4_CANADA_OVERRIDE_MSK | +				   DSM_VALUE_UNII4_CANADA_EN_MSK); +  		cmd->oem_unii4_allow_bitmap = cpu_to_le32(value);  	}  	ret = iwl_bios_get_dsm(fwrt, DSM_FUNC_ACTIVATE_CHANNEL, &value);  	if (!ret) { -		if (cmd_ver < 8) +		if (!has_raw_dsm_capa) +			value &= CHAN_STATE_ACTIVE_BITMAP_CMD_V12; + +		if (!has_raw_dsm_capa && cmd_ver < 8)  			value &= ~ACTIVATE_5G2_IN_WW_MASK; -		if (cmd_ver < 12) + +		/* Since version 12, bits 5 and 6 are supported +		 * regardless of this capability, By pass this masking +		 * if firmware has capability of accepting raw DSM table. +		 */ +		if (!has_raw_dsm_capa && cmd_ver < 12 && +		    !fw_has_capa(&fwrt->fw->ucode_capa, +				 IWL_UCODE_TLV_CAPA_BIOS_OVERRIDE_UNII4_US_CA))  			value &= CHAN_STATE_ACTIVE_BITMAP_CMD_V11;  		cmd->chan_state_active_bitmap = cpu_to_le32(value); @@ -578,13 +647,19 @@ int iwl_fill_lari_config(struct iwl_fw_runtime *fwrt,  		cmd->oem_uhb_allow_bitmap = cpu_to_le32(value);  	ret = iwl_bios_get_dsm(fwrt, DSM_FUNC_FORCE_DISABLE_CHANNELS, &value); -	if (!ret) +	if (!ret) { +		if (!has_raw_dsm_capa) +			value &= DSM_FORCE_DISABLE_CHANNELS_ALLOWED_BITMAP;  		cmd->force_disable_channels_bitmap = cpu_to_le32(value); +	}  	ret = iwl_bios_get_dsm(fwrt, DSM_FUNC_ENERGY_DETECTION_THRESHOLD,  			       &value); -	if (!ret) +	if (!ret) { +		if (!has_raw_dsm_capa) +			value &= DSM_EDT_ALLOWED_BITMAP;  		cmd->edt_bitmap = cpu_to_le32(value); +	}  	ret = iwl_bios_get_wbem(fwrt, &value);  	if (!ret) @@ -637,3 +712,50 @@ int iwl_bios_get_dsm(struct iwl_fw_runtime *fwrt, enum iwl_dsm_funcs func,  	GET_BIOS_TABLE(dsm, fwrt, func, value);  }  IWL_EXPORT_SYMBOL(iwl_bios_get_dsm); + +bool iwl_puncturing_is_allowed_in_bios(u32 puncturing, u16 mcc) +{ +	/* Some kind of regulatory mess means we need to currently disallow +	 * puncturing in the US and Canada unless enabled in BIOS. +	 */ +	switch (mcc) { +	case IWL_MCC_US: +		return puncturing & IWL_UEFI_CNV_PUNCTURING_USA_EN_MSK; +	case IWL_MCC_CANADA: +		return puncturing & IWL_UEFI_CNV_PUNCTURING_CANADA_EN_MSK; +	default: +		return true; +	} +} +IWL_EXPORT_SYMBOL(iwl_puncturing_is_allowed_in_bios); + +bool iwl_rfi_is_enabled_in_bios(struct iwl_fw_runtime *fwrt) +{ +	/* default behaviour is disabled */ +	u32 value = 0; +	int ret = iwl_bios_get_dsm(fwrt, DSM_FUNC_RFI_CONFIG, &value); + +	if (ret < 0) { +		IWL_DEBUG_RADIO(fwrt, "Failed to get DSM RFI, ret=%d\n", ret); +		return false; +	} + +	value &= DSM_VALUE_RFI_DISABLE; +	/* RFI BIOS CONFIG value can be 0 or 3 only. +	 * i.e 0 means DDR and DLVR enabled. 3 means DDR and DLVR disabled. +	 * 1 and 2 are invalid BIOS configurations, So, it's not possible to +	 * disable ddr/dlvr separately. +	 */ +	if (!value) { +		IWL_DEBUG_RADIO(fwrt, "DSM RFI is evaluated to enable\n"); +		return true; +	} else if (value == DSM_VALUE_RFI_DISABLE) { +		IWL_DEBUG_RADIO(fwrt, "DSM RFI is evaluated to disable\n"); +	} else { +		IWL_DEBUG_RADIO(fwrt, +				"DSM RFI got invalid value, value=%d\n", value); +	} + +	return false; +} +IWL_EXPORT_SYMBOL(iwl_rfi_is_enabled_in_bios); | 
