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_get_lari_config_bitmap(struct iwl_fw_runtime * fwrt)459 static __le32 iwl_get_lari_config_bitmap(struct iwl_fw_runtime *fwrt)
460 {
461 int ret;
462 u32 val;
463 __le32 config_bitmap = 0;
464
465 switch (CSR_HW_RFID_TYPE(fwrt->trans->hw_rf_id)) {
466 case IWL_CFG_RF_TYPE_HR1:
467 case IWL_CFG_RF_TYPE_HR2:
468 case IWL_CFG_RF_TYPE_JF1:
469 case IWL_CFG_RF_TYPE_JF2:
470 ret = iwl_bios_get_dsm(fwrt, DSM_FUNC_ENABLE_INDONESIA_5G2,
471 &val);
472
473 if (!ret && val == DSM_VALUE_INDONESIA_ENABLE)
474 config_bitmap |=
475 cpu_to_le32(LARI_CONFIG_ENABLE_5G2_IN_INDONESIA_MSK);
476 break;
477 default:
478 break;
479 }
480
481 ret = iwl_bios_get_dsm(fwrt, DSM_FUNC_DISABLE_SRD, &val);
482 if (!ret) {
483 if (val == DSM_VALUE_SRD_PASSIVE)
484 config_bitmap |=
485 cpu_to_le32(LARI_CONFIG_CHANGE_ETSI_TO_PASSIVE_MSK);
486 else if (val == DSM_VALUE_SRD_DISABLE)
487 config_bitmap |=
488 cpu_to_le32(LARI_CONFIG_CHANGE_ETSI_TO_DISABLED_MSK);
489 }
490
491 if (fw_has_capa(&fwrt->fw->ucode_capa,
492 IWL_UCODE_TLV_CAPA_CHINA_22_REG_SUPPORT)) {
493 ret = iwl_bios_get_dsm(fwrt, DSM_FUNC_REGULATORY_CONFIG,
494 &val);
495 /*
496 * China 2022 enable if the BIOS object does not exist or
497 * if it is enabled in BIOS.
498 */
499 if (ret < 0 || val & DSM_MASK_CHINA_22_REG)
500 config_bitmap |=
501 cpu_to_le32(LARI_CONFIG_ENABLE_CHINA_22_REG_SUPPORT_MSK);
502 }
503
504 return config_bitmap;
505 }
506
iwl_get_lari_config_cmd_size(u8 cmd_ver)507 static size_t iwl_get_lari_config_cmd_size(u8 cmd_ver)
508 {
509 size_t cmd_size;
510
511 switch (cmd_ver) {
512 case 12:
513 case 11:
514 cmd_size = sizeof(struct iwl_lari_config_change_cmd);
515 break;
516 case 10:
517 cmd_size = sizeof(struct iwl_lari_config_change_cmd_v10);
518 break;
519 case 9:
520 case 8:
521 case 7:
522 cmd_size = sizeof(struct iwl_lari_config_change_cmd_v7);
523 break;
524 case 6:
525 cmd_size = sizeof(struct iwl_lari_config_change_cmd_v6);
526 break;
527 case 5:
528 cmd_size = sizeof(struct iwl_lari_config_change_cmd_v5);
529 break;
530 case 4:
531 cmd_size = sizeof(struct iwl_lari_config_change_cmd_v4);
532 break;
533 case 3:
534 cmd_size = sizeof(struct iwl_lari_config_change_cmd_v3);
535 break;
536 case 2:
537 cmd_size = sizeof(struct iwl_lari_config_change_cmd_v2);
538 break;
539 default:
540 cmd_size = sizeof(struct iwl_lari_config_change_cmd_v1);
541 break;
542 }
543 return cmd_size;
544 }
545
iwl_fill_lari_config(struct iwl_fw_runtime * fwrt,struct iwl_lari_config_change_cmd * cmd,size_t * cmd_size)546 int iwl_fill_lari_config(struct iwl_fw_runtime *fwrt,
547 struct iwl_lari_config_change_cmd *cmd,
548 size_t *cmd_size)
549 {
550 int ret;
551 u32 value;
552 u8 cmd_ver = iwl_fw_lookup_cmd_ver(fwrt->fw,
553 WIDE_ID(REGULATORY_AND_NVM_GROUP,
554 LARI_CONFIG_CHANGE), 1);
555
556 memset(cmd, 0, sizeof(*cmd));
557 *cmd_size = iwl_get_lari_config_cmd_size(cmd_ver);
558
559 cmd->config_bitmap = iwl_get_lari_config_bitmap(fwrt);
560
561 ret = iwl_bios_get_dsm(fwrt, DSM_FUNC_11AX_ENABLEMENT, &value);
562 if (!ret)
563 cmd->oem_11ax_allow_bitmap = cpu_to_le32(value);
564
565 ret = iwl_bios_get_dsm(fwrt, DSM_FUNC_ENABLE_UNII4_CHAN, &value);
566 if (!ret) {
567 value &= DSM_UNII4_ALLOW_BITMAP;
568
569 /* Since version 9, bits 4 and 5 are supported
570 * regardless of this capability.
571 */
572 if (cmd_ver < 9 &&
573 !fw_has_capa(&fwrt->fw->ucode_capa,
574 IWL_UCODE_TLV_CAPA_BIOS_OVERRIDE_5G9_FOR_CA))
575 value &= ~(DSM_VALUE_UNII4_CANADA_OVERRIDE_MSK |
576 DSM_VALUE_UNII4_CANADA_EN_MSK);
577
578 cmd->oem_unii4_allow_bitmap = cpu_to_le32(value);
579 }
580
581 ret = iwl_bios_get_dsm(fwrt, DSM_FUNC_ACTIVATE_CHANNEL, &value);
582 if (!ret) {
583 if (cmd_ver < 8)
584 value &= ~ACTIVATE_5G2_IN_WW_MASK;
585
586 /* Since version 12, bits 5 and 6 are supported
587 * regardless of this capability.
588 */
589 if (cmd_ver < 12 &&
590 !fw_has_capa(&fwrt->fw->ucode_capa,
591 IWL_UCODE_TLV_CAPA_BIOS_OVERRIDE_UNII4_US_CA))
592 value &= CHAN_STATE_ACTIVE_BITMAP_CMD_V11;
593
594 cmd->chan_state_active_bitmap = cpu_to_le32(value);
595 }
596
597 ret = iwl_bios_get_dsm(fwrt, DSM_FUNC_ENABLE_6E, &value);
598 if (!ret)
599 cmd->oem_uhb_allow_bitmap = cpu_to_le32(value);
600
601 ret = iwl_bios_get_dsm(fwrt, DSM_FUNC_FORCE_DISABLE_CHANNELS, &value);
602 if (!ret)
603 cmd->force_disable_channels_bitmap = cpu_to_le32(value);
604
605 ret = iwl_bios_get_dsm(fwrt, DSM_FUNC_ENERGY_DETECTION_THRESHOLD,
606 &value);
607 if (!ret)
608 cmd->edt_bitmap = cpu_to_le32(value);
609
610 ret = iwl_bios_get_wbem(fwrt, &value);
611 if (!ret)
612 cmd->oem_320mhz_allow_bitmap = cpu_to_le32(value);
613
614 ret = iwl_bios_get_dsm(fwrt, DSM_FUNC_ENABLE_11BE, &value);
615 if (!ret)
616 cmd->oem_11be_allow_bitmap = cpu_to_le32(value);
617
618 if (cmd->config_bitmap ||
619 cmd->oem_uhb_allow_bitmap ||
620 cmd->oem_11ax_allow_bitmap ||
621 cmd->oem_unii4_allow_bitmap ||
622 cmd->chan_state_active_bitmap ||
623 cmd->force_disable_channels_bitmap ||
624 cmd->edt_bitmap ||
625 cmd->oem_320mhz_allow_bitmap ||
626 cmd->oem_11be_allow_bitmap) {
627 IWL_DEBUG_RADIO(fwrt,
628 "sending LARI_CONFIG_CHANGE, config_bitmap=0x%x, oem_11ax_allow_bitmap=0x%x\n",
629 le32_to_cpu(cmd->config_bitmap),
630 le32_to_cpu(cmd->oem_11ax_allow_bitmap));
631 IWL_DEBUG_RADIO(fwrt,
632 "sending LARI_CONFIG_CHANGE, oem_unii4_allow_bitmap=0x%x, chan_state_active_bitmap=0x%x, cmd_ver=%d\n",
633 le32_to_cpu(cmd->oem_unii4_allow_bitmap),
634 le32_to_cpu(cmd->chan_state_active_bitmap),
635 cmd_ver);
636 IWL_DEBUG_RADIO(fwrt,
637 "sending LARI_CONFIG_CHANGE, oem_uhb_allow_bitmap=0x%x, force_disable_channels_bitmap=0x%x\n",
638 le32_to_cpu(cmd->oem_uhb_allow_bitmap),
639 le32_to_cpu(cmd->force_disable_channels_bitmap));
640 IWL_DEBUG_RADIO(fwrt,
641 "sending LARI_CONFIG_CHANGE, edt_bitmap=0x%x, oem_320mhz_allow_bitmap=0x%x\n",
642 le32_to_cpu(cmd->edt_bitmap),
643 le32_to_cpu(cmd->oem_320mhz_allow_bitmap));
644 IWL_DEBUG_RADIO(fwrt,
645 "sending LARI_CONFIG_CHANGE, oem_11be_allow_bitmap=0x%x\n",
646 le32_to_cpu(cmd->oem_11be_allow_bitmap));
647 } else {
648 return 1;
649 }
650
651 return 0;
652 }
653 IWL_EXPORT_SYMBOL(iwl_fill_lari_config);
654
iwl_bios_get_dsm(struct iwl_fw_runtime * fwrt,enum iwl_dsm_funcs func,u32 * value)655 int iwl_bios_get_dsm(struct iwl_fw_runtime *fwrt, enum iwl_dsm_funcs func,
656 u32 *value)
657 {
658 GET_BIOS_TABLE(dsm, fwrt, func, value);
659 }
660 IWL_EXPORT_SYMBOL(iwl_bios_get_dsm);
661
iwl_puncturing_is_allowed_in_bios(u32 puncturing,u16 mcc)662 bool iwl_puncturing_is_allowed_in_bios(u32 puncturing, u16 mcc)
663 {
664 /* Some kind of regulatory mess means we need to currently disallow
665 * puncturing in the US and Canada unless enabled in BIOS.
666 */
667 switch (mcc) {
668 case IWL_MCC_US:
669 return puncturing & IWL_UEFI_CNV_PUNCTURING_USA_EN_MSK;
670 case IWL_MCC_CANADA:
671 return puncturing & IWL_UEFI_CNV_PUNCTURING_CANADA_EN_MSK;
672 default:
673 return true;
674 }
675 }
676 IWL_EXPORT_SYMBOL(iwl_puncturing_is_allowed_in_bios);
677