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