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