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