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
iwl_sar_geo_support(struct iwl_fw_runtime * fwrt)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->info.hw_rev != CSR_HW_REV_TYPE_3160) ||
185 (IWL_UCODE_SERIAL(fwrt->fw->ucode_ver) == 29 &&
186 ((fwrt->trans->info.hw_rev & CSR_HW_REV_TYPE_MSK) ==
187 CSR_HW_REV_TYPE_7265D));
188 }
189 IWL_EXPORT_SYMBOL(iwl_sar_geo_support);
190
iwl_sar_geo_fill_table(struct iwl_fw_runtime * fwrt,struct iwl_per_chain_offset * table,u32 n_bands,u32 n_profiles)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
iwl_sar_fill_table(struct iwl_fw_runtime * fwrt,__le16 * per_chain,u32 n_subbands,int prof_a,int prof_b)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
iwl_sar_fill_profile(struct iwl_fw_runtime * fwrt,__le16 * per_chain,u32 n_tables,u32 n_subbands,int prof_a,int prof_b)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
iwl_ppag_value_valid(struct iwl_fw_runtime * fwrt,int chain,int subband)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
iwl_fill_ppag_table(struct iwl_fw_runtime * fwrt,union iwl_ppag_table_cmd * cmd,int * cmd_size)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->info.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 IWL_DEBUG_RADIO(fwrt, "PPAG cmd ver is %d\n", cmd_ver);
343 if (cmd_ver == 1) {
344 num_sub_bands = IWL_NUM_SUB_BANDS_V1;
345 gain = cmd->v1.gain[0];
346 *cmd_size = sizeof(cmd->v1);
347 cmd->v1.flags = cpu_to_le32(fwrt->ppag_flags);
348 if (fwrt->ppag_bios_rev >= 1) {
349 /* in this case FW supports revision 0 */
350 IWL_DEBUG_RADIO(fwrt,
351 "PPAG table rev is %d, send truncated table\n",
352 fwrt->ppag_bios_rev);
353 }
354 } else if (cmd_ver >= 2 && cmd_ver <= 6) {
355 num_sub_bands = IWL_NUM_SUB_BANDS_V2;
356 gain = cmd->v2.gain[0];
357 *cmd_size = sizeof(cmd->v2);
358 cmd->v2.flags = cpu_to_le32(fwrt->ppag_flags);
359 if (fwrt->ppag_bios_rev == 0) {
360 /* in this case FW supports revisions 1,2 or 3 */
361 IWL_DEBUG_RADIO(fwrt,
362 "PPAG table rev is 0, send padded table\n");
363 }
364 } else if (cmd_ver == 7) {
365 num_sub_bands = IWL_NUM_SUB_BANDS_V2;
366 gain = cmd->v3.gain[0];
367 *cmd_size = sizeof(cmd->v3);
368 cmd->v3.ppag_config_info.table_source = fwrt->ppag_bios_source;
369 cmd->v3.ppag_config_info.table_revision = fwrt->ppag_bios_rev;
370 cmd->v3.ppag_config_info.value = cpu_to_le32(fwrt->ppag_flags);
371 } else {
372 IWL_DEBUG_RADIO(fwrt, "Unsupported PPAG command version\n");
373 return -EINVAL;
374 }
375
376 /* ppag mode */
377 IWL_DEBUG_RADIO(fwrt,
378 "PPAG MODE bits were read from bios: %d\n",
379 fwrt->ppag_flags);
380
381 if (cmd_ver == 6)
382 cmd->v1.flags &= cpu_to_le32(IWL_PPAG_CMD_V6_MASK);
383 else if (cmd_ver == 5)
384 cmd->v1.flags &= cpu_to_le32(IWL_PPAG_CMD_V5_MASK);
385 else if (cmd_ver < 5)
386 cmd->v1.flags &= cpu_to_le32(IWL_PPAG_CMD_V4_MASK);
387
388 if ((cmd_ver == 1 &&
389 !fw_has_capa(&fwrt->fw->ucode_capa,
390 IWL_UCODE_TLV_CAPA_PPAG_CHINA_BIOS_SUPPORT)) ||
391 (cmd_ver == 2 && fwrt->ppag_bios_rev >= 2)) {
392 cmd->v1.flags &= cpu_to_le32(IWL_PPAG_ETSI_MASK);
393 IWL_DEBUG_RADIO(fwrt, "masking ppag China bit\n");
394 } else {
395 IWL_DEBUG_RADIO(fwrt, "isn't masking ppag China bit\n");
396 }
397
398 /* The 'flags' field is the same in v1 and v2 so we can just
399 * use v1 to access it.
400 */
401 IWL_DEBUG_RADIO(fwrt,
402 "PPAG MODE bits going to be sent: %d\n",
403 (cmd_ver < 7) ? le32_to_cpu(cmd->v1.flags) :
404 le32_to_cpu(cmd->v3.ppag_config_info.value));
405
406 for (i = 0; i < IWL_NUM_CHAIN_LIMITS; i++) {
407 for (j = 0; j < num_sub_bands; j++) {
408 if (!send_ppag_always &&
409 !iwl_ppag_value_valid(fwrt, i, j))
410 return -EINVAL;
411
412 gain[i * num_sub_bands + j] =
413 fwrt->ppag_chains[i].subbands[j];
414 IWL_DEBUG_RADIO(fwrt,
415 "PPAG table: chain[%d] band[%d]: gain = %d\n",
416 i, j, gain[i * num_sub_bands + j]);
417 }
418 }
419
420 return 0;
421 }
422 IWL_EXPORT_SYMBOL(iwl_fill_ppag_table);
423
iwl_is_ppag_approved(struct iwl_fw_runtime * fwrt)424 bool iwl_is_ppag_approved(struct iwl_fw_runtime *fwrt)
425 {
426 if (!dmi_check_system(dmi_ppag_approved_list)) {
427 IWL_DEBUG_RADIO(fwrt,
428 "System vendor '%s' is not in the approved list, disabling PPAG.\n",
429 dmi_get_system_info(DMI_SYS_VENDOR) ?: "<unknown>");
430 fwrt->ppag_flags = 0;
431 return false;
432 }
433
434 return true;
435 }
436 IWL_EXPORT_SYMBOL(iwl_is_ppag_approved);
437
iwl_is_tas_approved(void)438 bool iwl_is_tas_approved(void)
439 {
440 return dmi_check_system(dmi_tas_approved_list);
441 }
442 IWL_EXPORT_SYMBOL(iwl_is_tas_approved);
443
444 struct iwl_tas_selection_data
iwl_parse_tas_selection(const u32 tas_selection_in,const u8 tbl_rev)445 iwl_parse_tas_selection(const u32 tas_selection_in, const u8 tbl_rev)
446 {
447 struct iwl_tas_selection_data tas_selection_out = {};
448 u8 override_iec = u32_get_bits(tas_selection_in,
449 IWL_WTAS_OVERRIDE_IEC_MSK);
450 u8 canada_tas_uhb = u32_get_bits(tas_selection_in,
451 IWL_WTAS_CANADA_UHB_MSK);
452 u8 enabled_iec = u32_get_bits(tas_selection_in,
453 IWL_WTAS_ENABLE_IEC_MSK);
454 u8 usa_tas_uhb = u32_get_bits(tas_selection_in,
455 IWL_WTAS_USA_UHB_MSK);
456
457 if (tbl_rev > 0) {
458 tas_selection_out.usa_tas_uhb_allowed = usa_tas_uhb;
459 tas_selection_out.override_tas_iec = override_iec;
460 tas_selection_out.enable_tas_iec = enabled_iec;
461 }
462
463 if (tbl_rev > 1)
464 tas_selection_out.canada_tas_uhb_allowed = canada_tas_uhb;
465
466 return tas_selection_out;
467 }
468 IWL_EXPORT_SYMBOL(iwl_parse_tas_selection);
469
iwl_add_mcc_to_tas_block_list(u16 * list,u8 * size,u16 mcc)470 bool iwl_add_mcc_to_tas_block_list(u16 *list, u8 *size, u16 mcc)
471 {
472 for (int i = 0; i < *size; i++) {
473 if (list[i] == mcc)
474 return true;
475 }
476
477 /* Verify that there is room for another country
478 * If *size == IWL_WTAS_BLACK_LIST_MAX, then the table is full.
479 */
480 if (*size >= IWL_WTAS_BLACK_LIST_MAX)
481 return false;
482
483 list[*size++] = mcc;
484 return true;
485 }
486 IWL_EXPORT_SYMBOL(iwl_add_mcc_to_tas_block_list);
487
iwl_get_lari_config_bitmap(struct iwl_fw_runtime * fwrt)488 __le32 iwl_get_lari_config_bitmap(struct iwl_fw_runtime *fwrt)
489 {
490 int ret;
491 u32 val;
492 __le32 config_bitmap = 0;
493
494 switch (CSR_HW_RFID_TYPE(fwrt->trans->info.hw_rf_id)) {
495 case IWL_CFG_RF_TYPE_HR1:
496 case IWL_CFG_RF_TYPE_HR2:
497 case IWL_CFG_RF_TYPE_JF1:
498 case IWL_CFG_RF_TYPE_JF2:
499 ret = iwl_bios_get_dsm(fwrt, DSM_FUNC_ENABLE_INDONESIA_5G2,
500 &val);
501
502 if (!ret && val == DSM_VALUE_INDONESIA_ENABLE)
503 config_bitmap |=
504 cpu_to_le32(LARI_CONFIG_ENABLE_5G2_IN_INDONESIA_MSK);
505 break;
506 default:
507 break;
508 }
509
510 ret = iwl_bios_get_dsm(fwrt, DSM_FUNC_DISABLE_SRD, &val);
511 if (!ret) {
512 if (val == DSM_VALUE_SRD_PASSIVE)
513 config_bitmap |=
514 cpu_to_le32(LARI_CONFIG_CHANGE_ETSI_TO_PASSIVE_MSK);
515 else if (val == DSM_VALUE_SRD_DISABLE)
516 config_bitmap |=
517 cpu_to_le32(LARI_CONFIG_CHANGE_ETSI_TO_DISABLED_MSK);
518 }
519
520 if (fw_has_capa(&fwrt->fw->ucode_capa,
521 IWL_UCODE_TLV_CAPA_CHINA_22_REG_SUPPORT)) {
522 ret = iwl_bios_get_dsm(fwrt, DSM_FUNC_REGULATORY_CONFIG,
523 &val);
524 /*
525 * China 2022 enable if the BIOS object does not exist or
526 * if it is enabled in BIOS.
527 */
528 if (ret < 0 || val & DSM_MASK_CHINA_22_REG)
529 config_bitmap |=
530 cpu_to_le32(LARI_CONFIG_ENABLE_CHINA_22_REG_SUPPORT_MSK);
531 }
532
533 return config_bitmap;
534 }
535 IWL_EXPORT_SYMBOL(iwl_get_lari_config_bitmap);
536
iwl_get_lari_config_cmd_size(u8 cmd_ver)537 static size_t iwl_get_lari_config_cmd_size(u8 cmd_ver)
538 {
539 size_t cmd_size;
540
541 switch (cmd_ver) {
542 case 12:
543 case 11:
544 cmd_size = sizeof(struct iwl_lari_config_change_cmd);
545 break;
546 case 10:
547 cmd_size = sizeof(struct iwl_lari_config_change_cmd_v10);
548 break;
549 case 9:
550 case 8:
551 case 7:
552 cmd_size = sizeof(struct iwl_lari_config_change_cmd_v7);
553 break;
554 case 6:
555 cmd_size = sizeof(struct iwl_lari_config_change_cmd_v6);
556 break;
557 case 5:
558 cmd_size = sizeof(struct iwl_lari_config_change_cmd_v5);
559 break;
560 case 4:
561 cmd_size = sizeof(struct iwl_lari_config_change_cmd_v4);
562 break;
563 case 3:
564 cmd_size = sizeof(struct iwl_lari_config_change_cmd_v3);
565 break;
566 case 2:
567 cmd_size = sizeof(struct iwl_lari_config_change_cmd_v2);
568 break;
569 default:
570 cmd_size = sizeof(struct iwl_lari_config_change_cmd_v1);
571 break;
572 }
573 return cmd_size;
574 }
575
iwl_fill_lari_config(struct iwl_fw_runtime * fwrt,struct iwl_lari_config_change_cmd * cmd,size_t * cmd_size)576 int iwl_fill_lari_config(struct iwl_fw_runtime *fwrt,
577 struct iwl_lari_config_change_cmd *cmd,
578 size_t *cmd_size)
579 {
580 int ret;
581 u32 value;
582 bool has_raw_dsm_capa = fw_has_capa(&fwrt->fw->ucode_capa,
583 IWL_UCODE_TLV_CAPA_FW_ACCEPTS_RAW_DSM_TABLE);
584 u8 cmd_ver = iwl_fw_lookup_cmd_ver(fwrt->fw,
585 WIDE_ID(REGULATORY_AND_NVM_GROUP,
586 LARI_CONFIG_CHANGE), 1);
587
588 if (WARN_ONCE(cmd_ver > 12,
589 "Don't add newer versions to this function\n"))
590 return -EINVAL;
591
592 memset(cmd, 0, sizeof(*cmd));
593 *cmd_size = iwl_get_lari_config_cmd_size(cmd_ver);
594
595 cmd->config_bitmap = iwl_get_lari_config_bitmap(fwrt);
596
597 ret = iwl_bios_get_dsm(fwrt, DSM_FUNC_11AX_ENABLEMENT, &value);
598 if (!ret) {
599 if (!has_raw_dsm_capa)
600 value &= DSM_11AX_ALLOW_BITMAP;
601 cmd->oem_11ax_allow_bitmap = cpu_to_le32(value);
602 }
603
604 ret = iwl_bios_get_dsm(fwrt, DSM_FUNC_ENABLE_UNII4_CHAN, &value);
605 if (!ret) {
606 if (!has_raw_dsm_capa)
607 value &= DSM_UNII4_ALLOW_BITMAP;
608
609 /* Since version 9, bits 4 and 5 are supported
610 * regardless of this capability, By pass this masking
611 * if firmware has capability of accepting raw DSM table.
612 */
613 if (!has_raw_dsm_capa && cmd_ver < 9 &&
614 !fw_has_capa(&fwrt->fw->ucode_capa,
615 IWL_UCODE_TLV_CAPA_BIOS_OVERRIDE_5G9_FOR_CA))
616 value &= ~(DSM_VALUE_UNII4_CANADA_OVERRIDE_MSK |
617 DSM_VALUE_UNII4_CANADA_EN_MSK);
618
619 cmd->oem_unii4_allow_bitmap = cpu_to_le32(value);
620 }
621
622 ret = iwl_bios_get_dsm(fwrt, DSM_FUNC_ACTIVATE_CHANNEL, &value);
623 if (!ret) {
624 if (!has_raw_dsm_capa)
625 value &= CHAN_STATE_ACTIVE_BITMAP_CMD_V12;
626
627 if (!has_raw_dsm_capa && cmd_ver < 8)
628 value &= ~ACTIVATE_5G2_IN_WW_MASK;
629
630 /* Since version 12, bits 5 and 6 are supported
631 * regardless of this capability, By pass this masking
632 * if firmware has capability of accepting raw DSM table.
633 */
634 if (!has_raw_dsm_capa && cmd_ver < 12 &&
635 !fw_has_capa(&fwrt->fw->ucode_capa,
636 IWL_UCODE_TLV_CAPA_BIOS_OVERRIDE_UNII4_US_CA))
637 value &= CHAN_STATE_ACTIVE_BITMAP_CMD_V11;
638
639 cmd->chan_state_active_bitmap = cpu_to_le32(value);
640 }
641
642 ret = iwl_bios_get_dsm(fwrt, DSM_FUNC_ENABLE_6E, &value);
643 if (!ret)
644 cmd->oem_uhb_allow_bitmap = cpu_to_le32(value);
645
646 ret = iwl_bios_get_dsm(fwrt, DSM_FUNC_FORCE_DISABLE_CHANNELS, &value);
647 if (!ret) {
648 if (!has_raw_dsm_capa)
649 value &= DSM_FORCE_DISABLE_CHANNELS_ALLOWED_BITMAP;
650 cmd->force_disable_channels_bitmap = cpu_to_le32(value);
651 }
652
653 ret = iwl_bios_get_dsm(fwrt, DSM_FUNC_ENERGY_DETECTION_THRESHOLD,
654 &value);
655 if (!ret) {
656 if (!has_raw_dsm_capa)
657 value &= DSM_EDT_ALLOWED_BITMAP;
658 cmd->edt_bitmap = cpu_to_le32(value);
659 }
660
661 ret = iwl_bios_get_wbem(fwrt, &value);
662 if (!ret)
663 cmd->oem_320mhz_allow_bitmap = cpu_to_le32(value);
664
665 ret = iwl_bios_get_dsm(fwrt, DSM_FUNC_ENABLE_11BE, &value);
666 if (!ret)
667 cmd->oem_11be_allow_bitmap = cpu_to_le32(value);
668
669 if (cmd->config_bitmap ||
670 cmd->oem_uhb_allow_bitmap ||
671 cmd->oem_11ax_allow_bitmap ||
672 cmd->oem_unii4_allow_bitmap ||
673 cmd->chan_state_active_bitmap ||
674 cmd->force_disable_channels_bitmap ||
675 cmd->edt_bitmap ||
676 cmd->oem_320mhz_allow_bitmap ||
677 cmd->oem_11be_allow_bitmap) {
678 IWL_DEBUG_RADIO(fwrt,
679 "sending LARI_CONFIG_CHANGE, config_bitmap=0x%x, oem_11ax_allow_bitmap=0x%x\n",
680 le32_to_cpu(cmd->config_bitmap),
681 le32_to_cpu(cmd->oem_11ax_allow_bitmap));
682 IWL_DEBUG_RADIO(fwrt,
683 "sending LARI_CONFIG_CHANGE, oem_unii4_allow_bitmap=0x%x, chan_state_active_bitmap=0x%x, cmd_ver=%d\n",
684 le32_to_cpu(cmd->oem_unii4_allow_bitmap),
685 le32_to_cpu(cmd->chan_state_active_bitmap),
686 cmd_ver);
687 IWL_DEBUG_RADIO(fwrt,
688 "sending LARI_CONFIG_CHANGE, oem_uhb_allow_bitmap=0x%x, force_disable_channels_bitmap=0x%x\n",
689 le32_to_cpu(cmd->oem_uhb_allow_bitmap),
690 le32_to_cpu(cmd->force_disable_channels_bitmap));
691 IWL_DEBUG_RADIO(fwrt,
692 "sending LARI_CONFIG_CHANGE, edt_bitmap=0x%x, oem_320mhz_allow_bitmap=0x%x\n",
693 le32_to_cpu(cmd->edt_bitmap),
694 le32_to_cpu(cmd->oem_320mhz_allow_bitmap));
695 IWL_DEBUG_RADIO(fwrt,
696 "sending LARI_CONFIG_CHANGE, oem_11be_allow_bitmap=0x%x\n",
697 le32_to_cpu(cmd->oem_11be_allow_bitmap));
698 } else {
699 return 1;
700 }
701
702 return 0;
703 }
704 IWL_EXPORT_SYMBOL(iwl_fill_lari_config);
705
iwl_bios_get_dsm(struct iwl_fw_runtime * fwrt,enum iwl_dsm_funcs func,u32 * value)706 int iwl_bios_get_dsm(struct iwl_fw_runtime *fwrt, enum iwl_dsm_funcs func,
707 u32 *value)
708 {
709 GET_BIOS_TABLE(dsm, fwrt, func, value);
710 }
711 IWL_EXPORT_SYMBOL(iwl_bios_get_dsm);
712
iwl_puncturing_is_allowed_in_bios(u32 puncturing,u16 mcc)713 bool iwl_puncturing_is_allowed_in_bios(u32 puncturing, u16 mcc)
714 {
715 /* Some kind of regulatory mess means we need to currently disallow
716 * puncturing in the US and Canada unless enabled in BIOS.
717 */
718 switch (mcc) {
719 case IWL_MCC_US:
720 return puncturing & IWL_UEFI_CNV_PUNCTURING_USA_EN_MSK;
721 case IWL_MCC_CANADA:
722 return puncturing & IWL_UEFI_CNV_PUNCTURING_CANADA_EN_MSK;
723 default:
724 return true;
725 }
726 }
727 IWL_EXPORT_SYMBOL(iwl_puncturing_is_allowed_in_bios);
728
iwl_rfi_is_enabled_in_bios(struct iwl_fw_runtime * fwrt)729 bool iwl_rfi_is_enabled_in_bios(struct iwl_fw_runtime *fwrt)
730 {
731 /* default behaviour is disabled */
732 u32 value = 0;
733 int ret = iwl_bios_get_dsm(fwrt, DSM_FUNC_RFI_CONFIG, &value);
734
735 if (ret < 0) {
736 IWL_DEBUG_RADIO(fwrt, "Failed to get DSM RFI, ret=%d\n", ret);
737 return false;
738 }
739
740 value &= DSM_VALUE_RFI_DISABLE;
741 /* RFI BIOS CONFIG value can be 0 or 3 only.
742 * i.e 0 means DDR and DLVR enabled. 3 means DDR and DLVR disabled.
743 * 1 and 2 are invalid BIOS configurations, So, it's not possible to
744 * disable ddr/dlvr separately.
745 */
746 if (!value) {
747 IWL_DEBUG_RADIO(fwrt, "DSM RFI is evaluated to enable\n");
748 return true;
749 } else if (value == DSM_VALUE_RFI_DISABLE) {
750 IWL_DEBUG_RADIO(fwrt, "DSM RFI is evaluated to disable\n");
751 } else {
752 IWL_DEBUG_RADIO(fwrt,
753 "DSM RFI got invalid value, value=%d\n", value);
754 }
755
756 return false;
757 }
758 IWL_EXPORT_SYMBOL(iwl_rfi_is_enabled_in_bios);
759