]> Git Repo - J-linux.git/blob - drivers/net/wireless/intel/iwlwifi/fw/regulatory.c
Merge tag 'kbuild-v6.9' of git://git.kernel.org/pub/scm/linux/kernel/git/masahiroy...
[J-linux.git] / drivers / net / wireless / intel / iwlwifi / fw / regulatory.c
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);
This page took 0.059336 seconds and 4 git commands to generate.