File Index
Files and directories
Sign in
FILE

regulatory.c

File preview with syntax highlighting.

linux-6.19.14/drivers/net/wireless/intel/iwlwifi/fw/regulatory.c C
  1// SPDX-License-Identifier: GPL-2.0 OR BSD-3-Clause
  2/*
  3 * Copyright (C) 2023, 2025 Intel Corporation
  4 */
  5#include <linux/dmi.h>
  6#include "iwl-drv.h"
  7#include "iwl-debug.h"
  8#include "regulatory.h"
  9#include "fw/runtime.h"
 10#include "fw/uefi.h"
 11
 12#define GET_BIOS_TABLE(__name, ...)					\
 13do {									\
 14	int ret = -ENOENT;						\
 15	if (fwrt->uefi_tables_lock_status > UEFI_WIFI_GUID_UNLOCKED)	\
 16		ret = iwl_uefi_get_ ## __name(__VA_ARGS__);		\
 17	if (ret < 0)							\
 18		ret = iwl_acpi_get_ ## __name(__VA_ARGS__);		\
 19	return ret;							\
 20} while (0)
 21
 22#define IWL_BIOS_TABLE_LOADER(__name)					\
 23int iwl_bios_get_ ## __name(struct iwl_fw_runtime *fwrt)		\
 24{GET_BIOS_TABLE(__name, fwrt); }					\
 25IWL_EXPORT_SYMBOL(iwl_bios_get_ ## __name)
 26
 27#define IWL_BIOS_TABLE_LOADER_DATA(__name, data_type)			\
 28int iwl_bios_get_ ## __name(struct iwl_fw_runtime *fwrt,		\
 29			    data_type * data)				\
 30{GET_BIOS_TABLE(__name, fwrt, data); }					\
 31IWL_EXPORT_SYMBOL(iwl_bios_get_ ## __name)
 32
 33IWL_BIOS_TABLE_LOADER(wrds_table);
 34IWL_BIOS_TABLE_LOADER(ewrd_table);
 35IWL_BIOS_TABLE_LOADER(wgds_table);
 36IWL_BIOS_TABLE_LOADER(ppag_table);
 37IWL_BIOS_TABLE_LOADER(phy_filters);
 38IWL_BIOS_TABLE_LOADER_DATA(tas_table, struct iwl_tas_data);
 39IWL_BIOS_TABLE_LOADER_DATA(pwr_limit, u64);
 40IWL_BIOS_TABLE_LOADER_DATA(mcc, char);
 41IWL_BIOS_TABLE_LOADER_DATA(eckv, u32);
 42IWL_BIOS_TABLE_LOADER_DATA(wbem, u32);
 43IWL_BIOS_TABLE_LOADER_DATA(dsbr, u32);
 44
 45
 46static const struct dmi_system_id dmi_ppag_approved_list[] = {
 47	{ .ident = "HP",
 48	  .matches = {
 49			DMI_MATCH(DMI_SYS_VENDOR, "HP"),
 50		},
 51	},
 52	{ .ident = "SAMSUNG",
 53	  .matches = {
 54			DMI_MATCH(DMI_SYS_VENDOR, "SAMSUNG ELECTRONICS CO., LTD"),
 55		},
 56	},
 57	{ .ident = "MSFT",
 58	  .matches = {
 59			DMI_MATCH(DMI_SYS_VENDOR, "Microsoft Corporation"),
 60		},
 61	},
 62	{ .ident = "ASUSTEK",
 63	  .matches = {
 64			DMI_MATCH(DMI_SYS_VENDOR, "ASUSTeK COMPUTER INC."),
 65		},
 66	},
 67	{ .ident = "ASUS",
 68	  .matches = {
 69			DMI_MATCH(DMI_SYS_VENDOR, "ASUS"),
 70		},
 71	},
 72	{ .ident = "GOOGLE-HP",
 73	  .matches = {
 74			DMI_MATCH(DMI_SYS_VENDOR, "Google"),
 75			DMI_MATCH(DMI_BOARD_VENDOR, "HP"),
 76		},
 77	},
 78	{ .ident = "GOOGLE-ASUS",
 79	  .matches = {
 80			DMI_MATCH(DMI_SYS_VENDOR, "Google"),
 81			DMI_MATCH(DMI_BOARD_VENDOR, "ASUSTek COMPUTER INC."),
 82		},
 83	},
 84	{ .ident = "GOOGLE-SAMSUNG",
 85	  .matches = {
 86			DMI_MATCH(DMI_SYS_VENDOR, "Google"),
 87			DMI_MATCH(DMI_BOARD_VENDOR, "SAMSUNG ELECTRONICS CO., LTD"),
 88		},
 89	},
 90	{ .ident = "DELL",
 91	  .matches = {
 92			DMI_MATCH(DMI_SYS_VENDOR, "Dell Inc."),
 93		},
 94	},
 95	{ .ident = "DELL",
 96	  .matches = {
 97			DMI_MATCH(DMI_SYS_VENDOR, "Alienware"),
 98		},
 99	},
100	{ .ident = "RAZER",
101	  .matches = {
102			DMI_MATCH(DMI_SYS_VENDOR, "Razer"),
103		},
104	},
105	{ .ident = "Honor",
106	  .matches = {
107			DMI_MATCH(DMI_SYS_VENDOR, "HONOR"),
108		},
109	},
110	{ .ident = "WIKO",
111	  .matches = {
112			DMI_MATCH(DMI_SYS_VENDOR, "WIKO"),
113		},
114	},
115	{}
116};
117
118static const struct dmi_system_id dmi_tas_approved_list[] = {
119	{ .ident = "HP",
120	  .matches = {
121			DMI_MATCH(DMI_SYS_VENDOR, "HP"),
122		},
123	},
124	{ .ident = "SAMSUNG",
125	  .matches = {
126			DMI_MATCH(DMI_SYS_VENDOR, "SAMSUNG ELECTRONICS CO., LTD"),
127		},
128	},
129		{ .ident = "LENOVO",
130	  .matches = {
131			DMI_MATCH(DMI_SYS_VENDOR, "LENOVO"),
132		},
133	},
134	{ .ident = "DELL",
135	  .matches = {
136			DMI_MATCH(DMI_SYS_VENDOR, "Dell Inc."),
137		},
138	},
139	{ .ident = "MSFT",
140	  .matches = {
141			DMI_MATCH(DMI_SYS_VENDOR, "Microsoft Corporation"),
142		},
143	},
144	{ .ident = "Acer",
145	  .matches = {
146			DMI_MATCH(DMI_SYS_VENDOR, "Acer"),
147		},
148	},
149	{ .ident = "ASUSTEK",
150	  .matches = {
151			DMI_MATCH(DMI_SYS_VENDOR, "ASUSTeK COMPUTER INC."),
152		},
153	},
154	{ .ident = "ASUS",
155	  .matches = {
156			DMI_MATCH(DMI_SYS_VENDOR, "ASUS"),
157		},
158	},
159	{ .ident = "GOOGLE-HP",
160	  .matches = {
161			DMI_MATCH(DMI_SYS_VENDOR, "Google"),
162			DMI_MATCH(DMI_BOARD_VENDOR, "HP"),
163		},
164	},
165	{ .ident = "MSI",
166	  .matches = {
167			DMI_MATCH(DMI_SYS_VENDOR, "Micro-Star International Co., Ltd."),
168		},
169	},
170	{ .ident = "Honor",
171	  .matches = {
172			DMI_MATCH(DMI_SYS_VENDOR, "HONOR"),
173		},
174	},
175	/* keep last */
176	{}
177};
178
179bool iwl_sar_geo_support(struct iwl_fw_runtime *fwrt)
180{
181	/*
182	 * The PER_CHAIN_LIMIT_OFFSET_CMD command is not supported on
183	 * earlier firmware versions.  Unfortunately, we don't have a
184	 * TLV API flag to rely on, so rely on the major version which
185	 * is in the first byte of ucode_ver.  This was implemented
186	 * initially on version 38 and then backported to 17.  It was
187	 * also backported to 29, but only for 7265D devices.  The
188	 * intention was to have it in 36 as well, but not all 8000
189	 * family got this feature enabled.  The 8000 family is the
190	 * only one using version 36, so skip this version entirely.
191	 */
192	return IWL_UCODE_SERIAL(fwrt->fw->ucode_ver) >= 38 ||
193		(IWL_UCODE_SERIAL(fwrt->fw->ucode_ver) == 17 &&
194		 fwrt->trans->info.hw_rev != CSR_HW_REV_TYPE_3160) ||
195		(IWL_UCODE_SERIAL(fwrt->fw->ucode_ver) == 29 &&
196		 ((fwrt->trans->info.hw_rev & CSR_HW_REV_TYPE_MSK) ==
197		  CSR_HW_REV_TYPE_7265D));
198}
199IWL_EXPORT_SYMBOL(iwl_sar_geo_support);
200
201int iwl_sar_geo_fill_table(struct iwl_fw_runtime *fwrt,
202			   struct iwl_per_chain_offset *table,
203			   u32 n_bands, u32 n_profiles)
204{
205	int i, j;
206
207	if (!fwrt->geo_enabled)
208		return -ENODATA;
209
210	if (!iwl_sar_geo_support(fwrt))
211		return -EOPNOTSUPP;
212
213	for (i = 0; i < n_profiles; i++) {
214		for (j = 0; j < n_bands; j++) {
215			struct iwl_per_chain_offset *chain =
216				&table[i * n_bands + j];
217
218			chain->max_tx_power =
219				cpu_to_le16(fwrt->geo_profiles[i].bands[j].max);
220			chain->chain_a =
221				fwrt->geo_profiles[i].bands[j].chains[0];
222			chain->chain_b =
223				fwrt->geo_profiles[i].bands[j].chains[1];
224			IWL_DEBUG_RADIO(fwrt,
225					"SAR geographic profile[%d] Band[%d]: chain A = %d chain B = %d max_tx_power = %d\n",
226					i, j,
227					fwrt->geo_profiles[i].bands[j].chains[0],
228					fwrt->geo_profiles[i].bands[j].chains[1],
229					fwrt->geo_profiles[i].bands[j].max);
230		}
231	}
232
233	return 0;
234}
235IWL_EXPORT_SYMBOL(iwl_sar_geo_fill_table);
236
237static int iwl_sar_fill_table(struct iwl_fw_runtime *fwrt,
238			      __le16 *per_chain, u32 n_subbands,
239			      int prof_a, int prof_b)
240{
241	int profs[BIOS_SAR_NUM_CHAINS] = { prof_a, prof_b };
242	int i, j;
243
244	for (i = 0; i < BIOS_SAR_NUM_CHAINS; i++) {
245		struct iwl_sar_profile *prof;
246
247		/* don't allow SAR to be disabled (profile 0 means disable) */
248		if (profs[i] == 0)
249			return -EPERM;
250
251		/* we are off by one, so allow up to BIOS_SAR_MAX_PROFILE_NUM */
252		if (profs[i] > BIOS_SAR_MAX_PROFILE_NUM)
253			return -EINVAL;
254
255		/* profiles go from 1 to 4, so decrement to access the array */
256		prof = &fwrt->sar_profiles[profs[i] - 1];
257
258		/* if the profile is disabled, do nothing */
259		if (!prof->enabled) {
260			IWL_DEBUG_RADIO(fwrt, "SAR profile %d is disabled.\n",
261					profs[i]);
262			/*
263			 * if one of the profiles is disabled, we
264			 * ignore all of them and return 1 to
265			 * differentiate disabled from other failures.
266			 */
267			return 1;
268		}
269
270		IWL_DEBUG_INFO(fwrt,
271			       "SAR EWRD: chain %d profile index %d\n",
272			       i, profs[i]);
273		IWL_DEBUG_RADIO(fwrt, "  Chain[%d]:\n", i);
274		for (j = 0; j < n_subbands; j++) {
275			per_chain[i * n_subbands + j] =
276				cpu_to_le16(prof->chains[i].subbands[j]);
277			IWL_DEBUG_RADIO(fwrt, "    Band[%d] = %d * .125dBm\n",
278					j, prof->chains[i].subbands[j]);
279		}
280	}
281
282	return 0;
283}
284
285int iwl_sar_fill_profile(struct iwl_fw_runtime *fwrt,
286			 __le16 *per_chain, u32 n_tables, u32 n_subbands,
287			 int prof_a, int prof_b)
288{
289	int i, ret = 0;
290
291	for (i = 0; i < n_tables; i++) {
292		ret = iwl_sar_fill_table(fwrt,
293			&per_chain[i * n_subbands * BIOS_SAR_NUM_CHAINS],
294			n_subbands, prof_a, prof_b);
295		if (ret)
296			break;
297	}
298
299	return ret;
300}
301IWL_EXPORT_SYMBOL(iwl_sar_fill_profile);
302
303static bool iwl_ppag_value_valid(struct iwl_fw_runtime *fwrt, int chain,
304				 int subband)
305{
306	s8 ppag_val = fwrt->ppag_chains[chain].subbands[subband];
307
308	if ((subband == 0 &&
309	     (ppag_val > IWL_PPAG_MAX_LB || ppag_val < IWL_PPAG_MIN_LB)) ||
310	    (subband != 0 &&
311	     (ppag_val > IWL_PPAG_MAX_HB || ppag_val < IWL_PPAG_MIN_HB))) {
312		IWL_DEBUG_RADIO(fwrt, "Invalid PPAG value: %d\n", ppag_val);
313		return false;
314	}
315	return true;
316}
317
318/* Utility function for iwlmvm and iwlxvt */
319int iwl_fill_ppag_table(struct iwl_fw_runtime *fwrt,
320			union iwl_ppag_table_cmd *cmd, int *cmd_size)
321{
322	u8 cmd_ver;
323	int i, j, num_sub_bands;
324	s8 *gain;
325	bool send_ppag_always;
326
327	/* many firmware images for JF lie about this */
328	if (CSR_HW_RFID_TYPE(fwrt->trans->info.hw_rf_id) ==
329	    CSR_HW_RFID_TYPE(CSR_HW_RF_ID_TYPE_JF))
330		return -EOPNOTSUPP;
331
332	if (!fw_has_capa(&fwrt->fw->ucode_capa, IWL_UCODE_TLV_CAPA_SET_PPAG)) {
333		IWL_DEBUG_RADIO(fwrt,
334				"PPAG capability not supported by FW, command not sent.\n");
335		return -EINVAL;
336	}
337
338	cmd_ver = iwl_fw_lookup_cmd_ver(fwrt->fw,
339					WIDE_ID(PHY_OPS_GROUP,
340						PER_PLATFORM_ANT_GAIN_CMD), 1);
341	/*
342	 * Starting from ver 4, driver needs to send the PPAG CMD regardless
343	 * if PPAG is enabled/disabled or valid/invalid.
344	 */
345	send_ppag_always = cmd_ver > 3;
346
347	/* Don't send PPAG if it is disabled */
348	if (!send_ppag_always && !fwrt->ppag_flags) {
349		IWL_DEBUG_RADIO(fwrt, "PPAG not enabled, command not sent.\n");
350		return -EINVAL;
351	}
352
353	IWL_DEBUG_RADIO(fwrt, "PPAG cmd ver is %d\n", cmd_ver);
354	if (cmd_ver == 1) {
355		num_sub_bands = IWL_NUM_SUB_BANDS_V1;
356		gain = cmd->v1.gain[0];
357		*cmd_size = sizeof(cmd->v1);
358		cmd->v1.flags = cpu_to_le32(fwrt->ppag_flags & IWL_PPAG_CMD_V1_MASK);
359		if (fwrt->ppag_bios_rev >= 1) {
360			/* in this case FW supports revision 0 */
361			IWL_DEBUG_RADIO(fwrt,
362					"PPAG table rev is %d, send truncated table\n",
363					fwrt->ppag_bios_rev);
364		}
365	} else if (cmd_ver == 5) {
366		num_sub_bands = IWL_NUM_SUB_BANDS_V2;
367		gain = cmd->v5.gain[0];
368		*cmd_size = sizeof(cmd->v5);
369		cmd->v5.flags = cpu_to_le32(fwrt->ppag_flags & IWL_PPAG_CMD_V5_MASK);
370		if (fwrt->ppag_bios_rev == 0) {
371			/* in this case FW supports revisions 1,2 or 3 */
372			IWL_DEBUG_RADIO(fwrt,
373					"PPAG table rev is 0, send padded table\n");
374		}
375	} else if (cmd_ver == 7) {
376		num_sub_bands = IWL_NUM_SUB_BANDS_V2;
377		gain = cmd->v7.gain[0];
378		*cmd_size = sizeof(cmd->v7);
379		cmd->v7.ppag_config_info.table_source = fwrt->ppag_bios_source;
380		cmd->v7.ppag_config_info.table_revision = fwrt->ppag_bios_rev;
381		cmd->v7.ppag_config_info.value = cpu_to_le32(fwrt->ppag_flags);
382	} else {
383		IWL_DEBUG_RADIO(fwrt, "Unsupported PPAG command version\n");
384		return -EINVAL;
385	}
386
387	/* ppag mode */
388	IWL_DEBUG_RADIO(fwrt,
389			"PPAG MODE bits were read from bios: %d\n",
390			fwrt->ppag_flags);
391
392	if (cmd_ver == 1 &&
393	    !fw_has_capa(&fwrt->fw->ucode_capa,
394			 IWL_UCODE_TLV_CAPA_PPAG_CHINA_BIOS_SUPPORT)) {
395		cmd->v1.flags &= cpu_to_le32(IWL_PPAG_ETSI_MASK);
396		IWL_DEBUG_RADIO(fwrt, "masking ppag China bit\n");
397	} else {
398		IWL_DEBUG_RADIO(fwrt, "isn't masking ppag China bit\n");
399	}
400
401	/* The 'flags' field is the same in v1 and v5 so we can just
402	 * use v1 to access it.
403	 */
404	IWL_DEBUG_RADIO(fwrt,
405			"PPAG MODE bits going to be sent: %d\n",
406			(cmd_ver < 7) ? le32_to_cpu(cmd->v1.flags) :
407					le32_to_cpu(cmd->v7.ppag_config_info.value));
408
409	for (i = 0; i < IWL_NUM_CHAIN_LIMITS; i++) {
410		for (j = 0; j < num_sub_bands; j++) {
411			if (!send_ppag_always &&
412			    !iwl_ppag_value_valid(fwrt, i, j))
413				return -EINVAL;
414
415			gain[i * num_sub_bands + j] =
416				fwrt->ppag_chains[i].subbands[j];
417			IWL_DEBUG_RADIO(fwrt,
418					"PPAG table: chain[%d] band[%d]: gain = %d\n",
419					i, j, gain[i * num_sub_bands + j]);
420		}
421	}
422
423	return 0;
424}
425IWL_EXPORT_SYMBOL(iwl_fill_ppag_table);
426
427bool iwl_is_ppag_approved(struct iwl_fw_runtime *fwrt)
428{
429	if (!dmi_check_system(dmi_ppag_approved_list)) {
430		IWL_DEBUG_RADIO(fwrt,
431				"System vendor '%s' is not in the approved list, disabling PPAG.\n",
432				dmi_get_system_info(DMI_SYS_VENDOR) ?: "<unknown>");
433		fwrt->ppag_flags = 0;
434		return false;
435	}
436
437	return true;
438}
439IWL_EXPORT_SYMBOL(iwl_is_ppag_approved);
440
441bool iwl_is_tas_approved(void)
442{
443	return dmi_check_system(dmi_tas_approved_list);
444}
445IWL_EXPORT_SYMBOL(iwl_is_tas_approved);
446
447struct iwl_tas_selection_data
448iwl_parse_tas_selection(const u32 tas_selection_in, const u8 tbl_rev)
449{
450	struct iwl_tas_selection_data tas_selection_out = {};
451	u8 override_iec = u32_get_bits(tas_selection_in,
452				       IWL_WTAS_OVERRIDE_IEC_MSK);
453	u8 canada_tas_uhb = u32_get_bits(tas_selection_in,
454					 IWL_WTAS_CANADA_UHB_MSK);
455	u8 enabled_iec = u32_get_bits(tas_selection_in,
456				      IWL_WTAS_ENABLE_IEC_MSK);
457	u8 usa_tas_uhb = u32_get_bits(tas_selection_in,
458				      IWL_WTAS_USA_UHB_MSK);
459
460	if (tbl_rev > 0) {
461		tas_selection_out.usa_tas_uhb_allowed = usa_tas_uhb;
462		tas_selection_out.override_tas_iec = override_iec;
463		tas_selection_out.enable_tas_iec = enabled_iec;
464	}
465
466	if (tbl_rev > 1)
467		tas_selection_out.canada_tas_uhb_allowed = canada_tas_uhb;
468
469	return tas_selection_out;
470}
471IWL_EXPORT_SYMBOL(iwl_parse_tas_selection);
472
473bool iwl_add_mcc_to_tas_block_list(u16 *list, u8 *size, u16 mcc)
474{
475	for (int i = 0; i < *size; i++) {
476		if (list[i] == mcc)
477			return true;
478	}
479
480	/* Verify that there is room for another country
481	 * If *size == IWL_WTAS_BLACK_LIST_MAX, then the table is full.
482	 */
483	if (*size >= IWL_WTAS_BLACK_LIST_MAX)
484		return false;
485
486	list[*size++] = mcc;
487	return true;
488}
489IWL_EXPORT_SYMBOL(iwl_add_mcc_to_tas_block_list);
490
491__le32 iwl_get_lari_config_bitmap(struct iwl_fw_runtime *fwrt)
492{
493	int ret;
494	u32 val;
495	__le32 config_bitmap = 0;
496
497	switch (CSR_HW_RFID_TYPE(fwrt->trans->info.hw_rf_id)) {
498	case IWL_CFG_RF_TYPE_HR1:
499	case IWL_CFG_RF_TYPE_HR2:
500	case IWL_CFG_RF_TYPE_JF1:
501	case IWL_CFG_RF_TYPE_JF2:
502		ret = iwl_bios_get_dsm(fwrt, DSM_FUNC_ENABLE_INDONESIA_5G2,
503				       &val);
504
505		if (!ret && val == DSM_VALUE_INDONESIA_ENABLE)
506			config_bitmap |=
507			    cpu_to_le32(LARI_CONFIG_ENABLE_5G2_IN_INDONESIA_MSK);
508		break;
509	default:
510		break;
511	}
512
513	ret = iwl_bios_get_dsm(fwrt, DSM_FUNC_DISABLE_SRD, &val);
514	if (!ret) {
515		if (val == DSM_VALUE_SRD_PASSIVE)
516			config_bitmap |=
517				cpu_to_le32(LARI_CONFIG_CHANGE_ETSI_TO_PASSIVE_MSK);
518		else if (val == DSM_VALUE_SRD_DISABLE)
519			config_bitmap |=
520				cpu_to_le32(LARI_CONFIG_CHANGE_ETSI_TO_DISABLED_MSK);
521	}
522
523	if (fw_has_capa(&fwrt->fw->ucode_capa,
524			IWL_UCODE_TLV_CAPA_CHINA_22_REG_SUPPORT)) {
525		ret = iwl_bios_get_dsm(fwrt, DSM_FUNC_REGULATORY_CONFIG,
526				       &val);
527		/*
528		 * China 2022 enable if the BIOS object does not exist or
529		 * if it is enabled in BIOS.
530		 */
531		if (ret < 0 || val & DSM_MASK_CHINA_22_REG)
532			config_bitmap |=
533				cpu_to_le32(LARI_CONFIG_ENABLE_CHINA_22_REG_SUPPORT_MSK);
534	}
535
536	return config_bitmap;
537}
538IWL_EXPORT_SYMBOL(iwl_get_lari_config_bitmap);
539
540static size_t iwl_get_lari_config_cmd_size(u8 cmd_ver)
541{
542	size_t cmd_size;
543
544	switch (cmd_ver) {
545	case 12:
546		cmd_size = sizeof(struct iwl_lari_config_change_cmd);
547		break;
548	case 8:
549		cmd_size = sizeof(struct iwl_lari_config_change_cmd_v8);
550		break;
551	case 6:
552		cmd_size = sizeof(struct iwl_lari_config_change_cmd_v6);
553		break;
554	default:
555		cmd_size = sizeof(struct iwl_lari_config_change_cmd_v1);
556		break;
557	}
558	return cmd_size;
559}
560
561int iwl_fill_lari_config(struct iwl_fw_runtime *fwrt,
562			 struct iwl_lari_config_change_cmd *cmd,
563			 size_t *cmd_size)
564{
565	int ret;
566	u32 value;
567	bool has_raw_dsm_capa = fw_has_capa(&fwrt->fw->ucode_capa,
568					    IWL_UCODE_TLV_CAPA_FW_ACCEPTS_RAW_DSM_TABLE);
569	u8 cmd_ver = iwl_fw_lookup_cmd_ver(fwrt->fw,
570					   WIDE_ID(REGULATORY_AND_NVM_GROUP,
571						   LARI_CONFIG_CHANGE), 1);
572
573	if (WARN_ONCE(cmd_ver > 12,
574		      "Don't add newer versions to this function\n"))
575		return -EINVAL;
576
577	memset(cmd, 0, sizeof(*cmd));
578	*cmd_size = iwl_get_lari_config_cmd_size(cmd_ver);
579
580	cmd->config_bitmap = iwl_get_lari_config_bitmap(fwrt);
581
582	ret = iwl_bios_get_dsm(fwrt, DSM_FUNC_11AX_ENABLEMENT, &value);
583	if (!ret) {
584		if (!has_raw_dsm_capa)
585			value &= DSM_11AX_ALLOW_BITMAP;
586		cmd->oem_11ax_allow_bitmap = cpu_to_le32(value);
587	}
588
589	ret = iwl_bios_get_dsm(fwrt, DSM_FUNC_ENABLE_UNII4_CHAN, &value);
590	if (!ret) {
591		if (!has_raw_dsm_capa)
592			value &= DSM_UNII4_ALLOW_BITMAP;
593
594		/* Since version 12, bits 4 and 5 are supported
595		 * regardless of this capability, By pass this masking
596		 * if firmware has capability of accepting raw DSM table.
597		 */
598		if (!has_raw_dsm_capa && cmd_ver < 12 &&
599		    !fw_has_capa(&fwrt->fw->ucode_capa,
600				 IWL_UCODE_TLV_CAPA_BIOS_OVERRIDE_5G9_FOR_CA))
601			value &= ~(DSM_VALUE_UNII4_CANADA_OVERRIDE_MSK |
602				   DSM_VALUE_UNII4_CANADA_EN_MSK);
603
604		cmd->oem_unii4_allow_bitmap = cpu_to_le32(value);
605	}
606
607	ret = iwl_bios_get_dsm(fwrt, DSM_FUNC_ACTIVATE_CHANNEL, &value);
608	if (!ret) {
609		if (!has_raw_dsm_capa)
610			value &= CHAN_STATE_ACTIVE_BITMAP_CMD_V12;
611
612		if (!has_raw_dsm_capa && cmd_ver < 8)
613			value &= ~ACTIVATE_5G2_IN_WW_MASK;
614
615		/* Since version 12, bits 5 and 6 are supported
616		 * regardless of this capability, By pass this masking
617		 * if firmware has capability of accepting raw DSM table.
618		 */
619		if (!has_raw_dsm_capa && cmd_ver < 12 &&
620		    !fw_has_capa(&fwrt->fw->ucode_capa,
621				 IWL_UCODE_TLV_CAPA_BIOS_OVERRIDE_UNII4_US_CA))
622			value &= CHAN_STATE_ACTIVE_BITMAP_CMD_V8;
623
624		cmd->chan_state_active_bitmap = cpu_to_le32(value);
625	}
626
627	ret = iwl_bios_get_dsm(fwrt, DSM_FUNC_ENABLE_6E, &value);
628	if (!ret)
629		cmd->oem_uhb_allow_bitmap = cpu_to_le32(value);
630
631	ret = iwl_bios_get_dsm(fwrt, DSM_FUNC_FORCE_DISABLE_CHANNELS, &value);
632	if (!ret) {
633		if (!has_raw_dsm_capa)
634			value &= DSM_FORCE_DISABLE_CHANNELS_ALLOWED_BITMAP;
635		cmd->force_disable_channels_bitmap = cpu_to_le32(value);
636	}
637
638	ret = iwl_bios_get_dsm(fwrt, DSM_FUNC_ENERGY_DETECTION_THRESHOLD,
639			       &value);
640	if (!ret) {
641		if (!has_raw_dsm_capa)
642			value &= DSM_EDT_ALLOWED_BITMAP;
643		cmd->edt_bitmap = cpu_to_le32(value);
644	}
645
646	ret = iwl_bios_get_wbem(fwrt, &value);
647	if (!ret)
648		cmd->oem_320mhz_allow_bitmap = cpu_to_le32(value);
649
650	ret = iwl_bios_get_dsm(fwrt, DSM_FUNC_ENABLE_11BE, &value);
651	if (!ret)
652		cmd->oem_11be_allow_bitmap = cpu_to_le32(value);
653
654	if (cmd->config_bitmap ||
655	    cmd->oem_uhb_allow_bitmap ||
656	    cmd->oem_11ax_allow_bitmap ||
657	    cmd->oem_unii4_allow_bitmap ||
658	    cmd->chan_state_active_bitmap ||
659	    cmd->force_disable_channels_bitmap ||
660	    cmd->edt_bitmap ||
661	    cmd->oem_320mhz_allow_bitmap ||
662	    cmd->oem_11be_allow_bitmap) {
663		IWL_DEBUG_RADIO(fwrt,
664				"sending LARI_CONFIG_CHANGE, config_bitmap=0x%x, oem_11ax_allow_bitmap=0x%x\n",
665				le32_to_cpu(cmd->config_bitmap),
666				le32_to_cpu(cmd->oem_11ax_allow_bitmap));
667		IWL_DEBUG_RADIO(fwrt,
668				"sending LARI_CONFIG_CHANGE, oem_unii4_allow_bitmap=0x%x, chan_state_active_bitmap=0x%x, cmd_ver=%d\n",
669				le32_to_cpu(cmd->oem_unii4_allow_bitmap),
670				le32_to_cpu(cmd->chan_state_active_bitmap),
671				cmd_ver);
672		IWL_DEBUG_RADIO(fwrt,
673				"sending LARI_CONFIG_CHANGE, oem_uhb_allow_bitmap=0x%x, force_disable_channels_bitmap=0x%x\n",
674				le32_to_cpu(cmd->oem_uhb_allow_bitmap),
675				le32_to_cpu(cmd->force_disable_channels_bitmap));
676		IWL_DEBUG_RADIO(fwrt,
677				"sending LARI_CONFIG_CHANGE, edt_bitmap=0x%x, oem_320mhz_allow_bitmap=0x%x\n",
678				le32_to_cpu(cmd->edt_bitmap),
679				le32_to_cpu(cmd->oem_320mhz_allow_bitmap));
680		IWL_DEBUG_RADIO(fwrt,
681				"sending LARI_CONFIG_CHANGE, oem_11be_allow_bitmap=0x%x\n",
682				le32_to_cpu(cmd->oem_11be_allow_bitmap));
683	} else {
684		return 1;
685	}
686
687	return 0;
688}
689IWL_EXPORT_SYMBOL(iwl_fill_lari_config);
690
691int iwl_bios_get_dsm(struct iwl_fw_runtime *fwrt, enum iwl_dsm_funcs func,
692		     u32 *value)
693{
694	GET_BIOS_TABLE(dsm, fwrt, func, value);
695}
696IWL_EXPORT_SYMBOL(iwl_bios_get_dsm);
697
698bool iwl_puncturing_is_allowed_in_bios(u32 puncturing, u16 mcc)
699{
700	/* Some kind of regulatory mess means we need to currently disallow
701	 * puncturing in the US and Canada unless enabled in BIOS.
702	 */
703	switch (mcc) {
704	case IWL_MCC_US:
705		return puncturing & IWL_UEFI_CNV_PUNCTURING_USA_EN_MSK;
706	case IWL_MCC_CANADA:
707		return puncturing & IWL_UEFI_CNV_PUNCTURING_CANADA_EN_MSK;
708	default:
709		return true;
710	}
711}
712IWL_EXPORT_SYMBOL(iwl_puncturing_is_allowed_in_bios);
713
714bool iwl_rfi_is_enabled_in_bios(struct iwl_fw_runtime *fwrt)
715{
716	/* default behaviour is disabled */
717	u32 value = 0;
718	int ret = iwl_bios_get_dsm(fwrt, DSM_FUNC_RFI_CONFIG, &value);
719
720	if (ret < 0) {
721		IWL_DEBUG_RADIO(fwrt, "Failed to get DSM RFI, ret=%d\n", ret);
722		return false;
723	}
724
725	value &= DSM_VALUE_RFI_DISABLE;
726	/* RFI BIOS CONFIG value can be 0 or 3 only.
727	 * i.e 0 means DDR and DLVR enabled. 3 means DDR and DLVR disabled.
728	 * 1 and 2 are invalid BIOS configurations, So, it's not possible to
729	 * disable ddr/dlvr separately.
730	 */
731	if (!value) {
732		IWL_DEBUG_RADIO(fwrt, "DSM RFI is evaluated to enable\n");
733		return true;
734	} else if (value == DSM_VALUE_RFI_DISABLE) {
735		IWL_DEBUG_RADIO(fwrt, "DSM RFI is evaluated to disable\n");
736	} else {
737		IWL_DEBUG_RADIO(fwrt,
738				"DSM RFI got invalid value, value=%d\n", value);
739	}
740
741	return false;
742}
743IWL_EXPORT_SYMBOL(iwl_rfi_is_enabled_in_bios);
~/ Read-only file preview.