xref: /linux/drivers/net/wireless/intel/iwlwifi/fw/regulatory.c (revision ae22a94997b8a03dcb3c922857c203246711f9d4)
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 
42 
43 static const struct dmi_system_id dmi_ppag_approved_list[] = {
44 	{ .ident = "HP",
45 	  .matches = {
46 			DMI_MATCH(DMI_SYS_VENDOR, "HP"),
47 		},
48 	},
49 	{ .ident = "SAMSUNG",
50 	  .matches = {
51 			DMI_MATCH(DMI_SYS_VENDOR, "SAMSUNG ELECTRONICS CO., LTD"),
52 		},
53 	},
54 	{ .ident = "MSFT",
55 	  .matches = {
56 			DMI_MATCH(DMI_SYS_VENDOR, "Microsoft Corporation"),
57 		},
58 	},
59 	{ .ident = "ASUS",
60 	  .matches = {
61 			DMI_MATCH(DMI_SYS_VENDOR, "ASUSTeK COMPUTER INC."),
62 		},
63 	},
64 	{ .ident = "GOOGLE-HP",
65 	  .matches = {
66 			DMI_MATCH(DMI_SYS_VENDOR, "Google"),
67 			DMI_MATCH(DMI_BOARD_VENDOR, "HP"),
68 		},
69 	},
70 	{ .ident = "GOOGLE-ASUS",
71 	  .matches = {
72 			DMI_MATCH(DMI_SYS_VENDOR, "Google"),
73 			DMI_MATCH(DMI_BOARD_VENDOR, "ASUSTek COMPUTER INC."),
74 		},
75 	},
76 	{ .ident = "GOOGLE-SAMSUNG",
77 	  .matches = {
78 			DMI_MATCH(DMI_SYS_VENDOR, "Google"),
79 			DMI_MATCH(DMI_BOARD_VENDOR, "SAMSUNG ELECTRONICS CO., LTD"),
80 		},
81 	},
82 	{ .ident = "DELL",
83 	  .matches = {
84 			DMI_MATCH(DMI_SYS_VENDOR, "Dell Inc."),
85 		},
86 	},
87 	{ .ident = "DELL",
88 	  .matches = {
89 			DMI_MATCH(DMI_SYS_VENDOR, "Alienware"),
90 		},
91 	},
92 	{ .ident = "RAZER",
93 	  .matches = {
94 			DMI_MATCH(DMI_SYS_VENDOR, "Razer"),
95 		},
96 	},
97 	{ .ident = "Honor",
98 	  .matches = {
99 			DMI_MATCH(DMI_SYS_VENDOR, "HONOR"),
100 		},
101 	},
102 	{}
103 };
104 
105 static const struct dmi_system_id dmi_tas_approved_list[] = {
106 	{ .ident = "HP",
107 	  .matches = {
108 			DMI_MATCH(DMI_SYS_VENDOR, "HP"),
109 		},
110 	},
111 	{ .ident = "SAMSUNG",
112 	  .matches = {
113 			DMI_MATCH(DMI_SYS_VENDOR, "SAMSUNG ELECTRONICS CO., LTD"),
114 		},
115 	},
116 		{ .ident = "LENOVO",
117 	  .matches = {
118 			DMI_MATCH(DMI_SYS_VENDOR, "LENOVO"),
119 		},
120 	},
121 	{ .ident = "DELL",
122 	  .matches = {
123 			DMI_MATCH(DMI_SYS_VENDOR, "Dell Inc."),
124 		},
125 	},
126 	{ .ident = "MSFT",
127 	  .matches = {
128 			DMI_MATCH(DMI_SYS_VENDOR, "Microsoft Corporation"),
129 		},
130 	},
131 	{ .ident = "Acer",
132 	  .matches = {
133 			DMI_MATCH(DMI_SYS_VENDOR, "Acer"),
134 		},
135 	},
136 	{ .ident = "ASUS",
137 	  .matches = {
138 			DMI_MATCH(DMI_SYS_VENDOR, "ASUSTeK COMPUTER INC."),
139 		},
140 	},
141 	{ .ident = "GOOGLE-HP",
142 	  .matches = {
143 			DMI_MATCH(DMI_SYS_VENDOR, "Google"),
144 			DMI_MATCH(DMI_BOARD_VENDOR, "HP"),
145 		},
146 	},
147 	{ .ident = "MSI",
148 	  .matches = {
149 			DMI_MATCH(DMI_SYS_VENDOR, "Micro-Star International Co., Ltd."),
150 		},
151 	},
152 	{ .ident = "Honor",
153 	  .matches = {
154 			DMI_MATCH(DMI_SYS_VENDOR, "HONOR"),
155 		},
156 	},
157 	/* keep last */
158 	{}
159 };
160 
161 bool iwl_sar_geo_support(struct iwl_fw_runtime *fwrt)
162 {
163 	/*
164 	 * The PER_CHAIN_LIMIT_OFFSET_CMD command is not supported on
165 	 * earlier firmware versions.  Unfortunately, we don't have a
166 	 * TLV API flag to rely on, so rely on the major version which
167 	 * is in the first byte of ucode_ver.  This was implemented
168 	 * initially on version 38 and then backported to 17.  It was
169 	 * also backported to 29, but only for 7265D devices.  The
170 	 * intention was to have it in 36 as well, but not all 8000
171 	 * family got this feature enabled.  The 8000 family is the
172 	 * only one using version 36, so skip this version entirely.
173 	 */
174 	return IWL_UCODE_SERIAL(fwrt->fw->ucode_ver) >= 38 ||
175 		(IWL_UCODE_SERIAL(fwrt->fw->ucode_ver) == 17 &&
176 		 fwrt->trans->hw_rev != CSR_HW_REV_TYPE_3160) ||
177 		(IWL_UCODE_SERIAL(fwrt->fw->ucode_ver) == 29 &&
178 		 ((fwrt->trans->hw_rev & CSR_HW_REV_TYPE_MSK) ==
179 		  CSR_HW_REV_TYPE_7265D));
180 }
181 IWL_EXPORT_SYMBOL(iwl_sar_geo_support);
182 
183 int iwl_sar_geo_fill_table(struct iwl_fw_runtime *fwrt,
184 			   struct iwl_per_chain_offset *table,
185 			   u32 n_bands, u32 n_profiles)
186 {
187 	int i, j;
188 
189 	if (!fwrt->geo_enabled)
190 		return -ENODATA;
191 
192 	if (!iwl_sar_geo_support(fwrt))
193 		return -EOPNOTSUPP;
194 
195 	for (i = 0; i < n_profiles; i++) {
196 		for (j = 0; j < n_bands; j++) {
197 			struct iwl_per_chain_offset *chain =
198 				&table[i * n_bands + j];
199 
200 			chain->max_tx_power =
201 				cpu_to_le16(fwrt->geo_profiles[i].bands[j].max);
202 			chain->chain_a =
203 				fwrt->geo_profiles[i].bands[j].chains[0];
204 			chain->chain_b =
205 				fwrt->geo_profiles[i].bands[j].chains[1];
206 			IWL_DEBUG_RADIO(fwrt,
207 					"SAR geographic profile[%d] Band[%d]: chain A = %d chain B = %d max_tx_power = %d\n",
208 					i, j,
209 					fwrt->geo_profiles[i].bands[j].chains[0],
210 					fwrt->geo_profiles[i].bands[j].chains[1],
211 					fwrt->geo_profiles[i].bands[j].max);
212 		}
213 	}
214 
215 	return 0;
216 }
217 IWL_EXPORT_SYMBOL(iwl_sar_geo_fill_table);
218 
219 static int iwl_sar_fill_table(struct iwl_fw_runtime *fwrt,
220 			      __le16 *per_chain, u32 n_subbands,
221 			      int prof_a, int prof_b)
222 {
223 	int profs[BIOS_SAR_NUM_CHAINS] = { prof_a, prof_b };
224 	int i, j;
225 
226 	for (i = 0; i < BIOS_SAR_NUM_CHAINS; i++) {
227 		struct iwl_sar_profile *prof;
228 
229 		/* don't allow SAR to be disabled (profile 0 means disable) */
230 		if (profs[i] == 0)
231 			return -EPERM;
232 
233 		/* we are off by one, so allow up to BIOS_SAR_MAX_PROFILE_NUM */
234 		if (profs[i] > BIOS_SAR_MAX_PROFILE_NUM)
235 			return -EINVAL;
236 
237 		/* profiles go from 1 to 4, so decrement to access the array */
238 		prof = &fwrt->sar_profiles[profs[i] - 1];
239 
240 		/* if the profile is disabled, do nothing */
241 		if (!prof->enabled) {
242 			IWL_DEBUG_RADIO(fwrt, "SAR profile %d is disabled.\n",
243 					profs[i]);
244 			/*
245 			 * if one of the profiles is disabled, we
246 			 * ignore all of them and return 1 to
247 			 * differentiate disabled from other failures.
248 			 */
249 			return 1;
250 		}
251 
252 		IWL_DEBUG_INFO(fwrt,
253 			       "SAR EWRD: chain %d profile index %d\n",
254 			       i, profs[i]);
255 		IWL_DEBUG_RADIO(fwrt, "  Chain[%d]:\n", i);
256 		for (j = 0; j < n_subbands; j++) {
257 			per_chain[i * n_subbands + j] =
258 				cpu_to_le16(prof->chains[i].subbands[j]);
259 			IWL_DEBUG_RADIO(fwrt, "    Band[%d] = %d * .125dBm\n",
260 					j, prof->chains[i].subbands[j]);
261 		}
262 	}
263 
264 	return 0;
265 }
266 
267 int iwl_sar_fill_profile(struct iwl_fw_runtime *fwrt,
268 			 __le16 *per_chain, u32 n_tables, u32 n_subbands,
269 			 int prof_a, int prof_b)
270 {
271 	int i, ret = 0;
272 
273 	for (i = 0; i < n_tables; i++) {
274 		ret = iwl_sar_fill_table(fwrt,
275 			&per_chain[i * n_subbands * BIOS_SAR_NUM_CHAINS],
276 			n_subbands, prof_a, prof_b);
277 		if (ret)
278 			break;
279 	}
280 
281 	return ret;
282 }
283 IWL_EXPORT_SYMBOL(iwl_sar_fill_profile);
284 
285 static bool iwl_ppag_value_valid(struct iwl_fw_runtime *fwrt, int chain,
286 				 int subband)
287 {
288 	s8 ppag_val = fwrt->ppag_chains[chain].subbands[subband];
289 
290 	if ((subband == 0 &&
291 	     (ppag_val > IWL_PPAG_MAX_LB || ppag_val < IWL_PPAG_MIN_LB)) ||
292 	    (subband != 0 &&
293 	     (ppag_val > IWL_PPAG_MAX_HB || ppag_val < IWL_PPAG_MIN_HB))) {
294 		IWL_DEBUG_RADIO(fwrt, "Invalid PPAG value: %d\n", ppag_val);
295 		return false;
296 	}
297 	return true;
298 }
299 
300 int iwl_fill_ppag_table(struct iwl_fw_runtime *fwrt,
301 			union iwl_ppag_table_cmd *cmd, int *cmd_size)
302 {
303 	u8 cmd_ver;
304 	int i, j, num_sub_bands;
305 	s8 *gain;
306 	bool send_ppag_always;
307 
308 	/* many firmware images for JF lie about this */
309 	if (CSR_HW_RFID_TYPE(fwrt->trans->hw_rf_id) ==
310 	    CSR_HW_RFID_TYPE(CSR_HW_RF_ID_TYPE_JF))
311 		return -EOPNOTSUPP;
312 
313 	if (!fw_has_capa(&fwrt->fw->ucode_capa, IWL_UCODE_TLV_CAPA_SET_PPAG)) {
314 		IWL_DEBUG_RADIO(fwrt,
315 				"PPAG capability not supported by FW, command not sent.\n");
316 		return -EINVAL;
317 	}
318 
319 	cmd_ver = iwl_fw_lookup_cmd_ver(fwrt->fw,
320 					WIDE_ID(PHY_OPS_GROUP,
321 						PER_PLATFORM_ANT_GAIN_CMD), 1);
322 	/*
323 	 * Starting from ver 4, driver needs to send the PPAG CMD regardless
324 	 * if PPAG is enabled/disabled or valid/invalid.
325 	 */
326 	send_ppag_always = cmd_ver > 3;
327 
328 	/* Don't send PPAG if it is disabled */
329 	if (!send_ppag_always && !fwrt->ppag_flags) {
330 		IWL_DEBUG_RADIO(fwrt, "PPAG not enabled, command not sent.\n");
331 		return -EINVAL;
332 	}
333 
334 	/* The 'flags' field is the same in v1 and in v2 so we can just
335 	 * use v1 to access it.
336 	 */
337 	cmd->v1.flags = cpu_to_le32(fwrt->ppag_flags);
338 
339 	IWL_DEBUG_RADIO(fwrt, "PPAG cmd ver is %d\n", cmd_ver);
340 	if (cmd_ver == 1) {
341 		num_sub_bands = IWL_NUM_SUB_BANDS_V1;
342 		gain = cmd->v1.gain[0];
343 		*cmd_size = sizeof(cmd->v1);
344 		if (fwrt->ppag_ver >= 1) {
345 			/* in this case FW supports revision 0 */
346 			IWL_DEBUG_RADIO(fwrt,
347 					"PPAG table rev is %d, send truncated table\n",
348 					fwrt->ppag_ver);
349 		}
350 	} else if (cmd_ver >= 2 && cmd_ver <= 5) {
351 		num_sub_bands = IWL_NUM_SUB_BANDS_V2;
352 		gain = cmd->v2.gain[0];
353 		*cmd_size = sizeof(cmd->v2);
354 		if (fwrt->ppag_ver == 0) {
355 			/* in this case FW supports revisions 1,2 or 3 */
356 			IWL_DEBUG_RADIO(fwrt,
357 					"PPAG table rev is 0, send padded table\n");
358 		}
359 	} else {
360 		IWL_DEBUG_RADIO(fwrt, "Unsupported PPAG command version\n");
361 		return -EINVAL;
362 	}
363 
364 	/* ppag mode */
365 	IWL_DEBUG_RADIO(fwrt,
366 			"PPAG MODE bits were read from bios: %d\n",
367 			le32_to_cpu(cmd->v1.flags));
368 
369 	if (cmd_ver == 5)
370 		cmd->v1.flags &= cpu_to_le32(IWL_PPAG_CMD_V5_MASK);
371 	else if (cmd_ver < 5)
372 		cmd->v1.flags &= cpu_to_le32(IWL_PPAG_CMD_V4_MASK);
373 
374 	if ((cmd_ver == 1 &&
375 	     !fw_has_capa(&fwrt->fw->ucode_capa,
376 			  IWL_UCODE_TLV_CAPA_PPAG_CHINA_BIOS_SUPPORT)) ||
377 	    (cmd_ver == 2 && fwrt->ppag_ver >= 2)) {
378 		cmd->v1.flags &= cpu_to_le32(IWL_PPAG_ETSI_MASK);
379 		IWL_DEBUG_RADIO(fwrt, "masking ppag China bit\n");
380 	} else {
381 		IWL_DEBUG_RADIO(fwrt, "isn't masking ppag China bit\n");
382 	}
383 
384 	IWL_DEBUG_RADIO(fwrt,
385 			"PPAG MODE bits going to be sent: %d\n",
386 			le32_to_cpu(cmd->v1.flags));
387 
388 	for (i = 0; i < IWL_NUM_CHAIN_LIMITS; i++) {
389 		for (j = 0; j < num_sub_bands; j++) {
390 			if (!send_ppag_always &&
391 			    !iwl_ppag_value_valid(fwrt, i, j))
392 				return -EINVAL;
393 
394 			gain[i * num_sub_bands + j] =
395 				fwrt->ppag_chains[i].subbands[j];
396 			IWL_DEBUG_RADIO(fwrt,
397 					"PPAG table: chain[%d] band[%d]: gain = %d\n",
398 					i, j, gain[i * num_sub_bands + j]);
399 		}
400 	}
401 
402 	return 0;
403 }
404 IWL_EXPORT_SYMBOL(iwl_fill_ppag_table);
405 
406 bool iwl_is_ppag_approved(struct iwl_fw_runtime *fwrt)
407 {
408 	if (!dmi_check_system(dmi_ppag_approved_list)) {
409 		IWL_DEBUG_RADIO(fwrt,
410 				"System vendor '%s' is not in the approved list, disabling PPAG.\n",
411 				dmi_get_system_info(DMI_SYS_VENDOR) ?: "<unknown>");
412 		fwrt->ppag_flags = 0;
413 		return false;
414 	}
415 
416 	return true;
417 }
418 IWL_EXPORT_SYMBOL(iwl_is_ppag_approved);
419 
420 bool iwl_is_tas_approved(void)
421 {
422 	return dmi_check_system(dmi_tas_approved_list);
423 }
424 IWL_EXPORT_SYMBOL(iwl_is_tas_approved);
425 
426 int iwl_parse_tas_selection(struct iwl_fw_runtime *fwrt,
427 			    struct iwl_tas_data *tas_data,
428 			    const u32 tas_selection)
429 {
430 	u8 override_iec = u32_get_bits(tas_selection,
431 				       IWL_WTAS_OVERRIDE_IEC_MSK);
432 	u8 enabled_iec = u32_get_bits(tas_selection, IWL_WTAS_ENABLE_IEC_MSK);
433 	u8 usa_tas_uhb = u32_get_bits(tas_selection, IWL_WTAS_USA_UHB_MSK);
434 	int enabled = tas_selection & IWL_WTAS_ENABLED_MSK;
435 
436 	IWL_DEBUG_RADIO(fwrt, "TAS selection as read from BIOS: 0x%x\n",
437 			tas_selection);
438 
439 	tas_data->usa_tas_uhb_allowed = usa_tas_uhb;
440 	tas_data->override_tas_iec = override_iec;
441 	tas_data->enable_tas_iec = enabled_iec;
442 
443 	return enabled;
444 }
445 
446 __le32 iwl_get_lari_config_bitmap(struct iwl_fw_runtime *fwrt)
447 {
448 	int ret;
449 	u32 val;
450 	__le32 config_bitmap = 0;
451 
452 	switch (CSR_HW_RFID_TYPE(fwrt->trans->hw_rf_id)) {
453 	case IWL_CFG_RF_TYPE_HR1:
454 	case IWL_CFG_RF_TYPE_HR2:
455 	case IWL_CFG_RF_TYPE_JF1:
456 	case IWL_CFG_RF_TYPE_JF2:
457 		ret = iwl_bios_get_dsm(fwrt, DSM_FUNC_ENABLE_INDONESIA_5G2,
458 				       &val);
459 
460 		if (!ret && val == DSM_VALUE_INDONESIA_ENABLE)
461 			config_bitmap |=
462 			    cpu_to_le32(LARI_CONFIG_ENABLE_5G2_IN_INDONESIA_MSK);
463 		break;
464 	default:
465 		break;
466 	}
467 
468 	ret = iwl_bios_get_dsm(fwrt, DSM_FUNC_DISABLE_SRD, &val);
469 	if (!ret) {
470 		if (val == DSM_VALUE_SRD_PASSIVE)
471 			config_bitmap |=
472 				cpu_to_le32(LARI_CONFIG_CHANGE_ETSI_TO_PASSIVE_MSK);
473 		else if (val == DSM_VALUE_SRD_DISABLE)
474 			config_bitmap |=
475 				cpu_to_le32(LARI_CONFIG_CHANGE_ETSI_TO_DISABLED_MSK);
476 	}
477 
478 	if (fw_has_capa(&fwrt->fw->ucode_capa,
479 			IWL_UCODE_TLV_CAPA_CHINA_22_REG_SUPPORT)) {
480 		ret = iwl_bios_get_dsm(fwrt, DSM_FUNC_REGULATORY_CONFIG,
481 				       &val);
482 		/*
483 		 * China 2022 enable if the BIOS object does not exist or
484 		 * if it is enabled in BIOS.
485 		 */
486 		if (ret < 0 || val & DSM_MASK_CHINA_22_REG)
487 			config_bitmap |=
488 				cpu_to_le32(LARI_CONFIG_ENABLE_CHINA_22_REG_SUPPORT_MSK);
489 	}
490 
491 	return config_bitmap;
492 }
493 IWL_EXPORT_SYMBOL(iwl_get_lari_config_bitmap);
494 
495 int iwl_bios_get_dsm(struct iwl_fw_runtime *fwrt, enum iwl_dsm_funcs func,
496 		     u32 *value)
497 {
498 	GET_BIOS_TABLE(dsm, fwrt, func, value);
499 }
500 IWL_EXPORT_SYMBOL(iwl_bios_get_dsm);
501