1 // SPDX-License-Identifier: GPL-2.0 OR BSD-3-Clause
3 * Copyright (C) 2017 Intel Deutschland GmbH
4 * Copyright (C) 2019-2024 Intel Corporation
6 #include <linux/uuid.h>
10 #include "fw/runtime.h"
12 const guid_t iwl_guid
= GUID_INIT(0xF21202BF, 0x8F78, 0x4DC6,
13 0xA5, 0xB3, 0x1F, 0x73,
14 0x8E, 0x28, 0x5A, 0xDE);
16 static const size_t acpi_dsm_size
[DSM_FUNC_NUM_FUNCS
] = {
17 [DSM_FUNC_QUERY
] = sizeof(u32
),
18 [DSM_FUNC_DISABLE_SRD
] = sizeof(u8
),
19 [DSM_FUNC_ENABLE_INDONESIA_5G2
] = sizeof(u8
),
20 [DSM_FUNC_ENABLE_6E
] = sizeof(u32
),
21 [DSM_FUNC_REGULATORY_CONFIG
] = sizeof(u32
),
22 /* Not supported in driver */
24 [DSM_FUNC_11AX_ENABLEMENT
] = sizeof(u32
),
25 [DSM_FUNC_ENABLE_UNII4_CHAN
] = sizeof(u32
),
26 [DSM_FUNC_ACTIVATE_CHANNEL
] = sizeof(u32
),
27 [DSM_FUNC_FORCE_DISABLE_CHANNELS
] = sizeof(u32
),
28 [DSM_FUNC_ENERGY_DETECTION_THRESHOLD
] = sizeof(u32
),
29 [DSM_FUNC_RFI_CONFIG
] = sizeof(u32
),
30 [DSM_FUNC_ENABLE_11BE
] = sizeof(u32
),
33 static int iwl_acpi_get_handle(struct device
*dev
, acpi_string method
,
34 acpi_handle
*ret_handle
)
36 acpi_handle root_handle
;
39 root_handle
= ACPI_HANDLE(dev
);
41 IWL_DEBUG_DEV_RADIO(dev
,
42 "ACPI: Could not retrieve root port handle\n");
46 status
= acpi_get_handle(root_handle
, method
, ret_handle
);
47 if (ACPI_FAILURE(status
)) {
48 IWL_DEBUG_DEV_RADIO(dev
,
49 "ACPI: %s method not found\n", method
);
55 static void *iwl_acpi_get_object(struct device
*dev
, acpi_string method
)
57 struct acpi_buffer buf
= {ACPI_ALLOCATE_BUFFER
, NULL
};
62 ret
= iwl_acpi_get_handle(dev
, method
, &handle
);
64 return ERR_PTR(-ENOENT
);
66 /* Call the method with no arguments */
67 status
= acpi_evaluate_object(handle
, NULL
, NULL
, &buf
);
68 if (ACPI_FAILURE(status
)) {
69 IWL_DEBUG_DEV_RADIO(dev
,
70 "ACPI: %s method invocation failed (status: 0x%x)\n",
72 return ERR_PTR(-ENOENT
);
78 * Generic function for evaluating a method defined in the device specific
79 * method (DSM) interface. The returned acpi object must be freed by calling
82 union acpi_object
*iwl_acpi_get_dsm_object(struct device
*dev
, int rev
,
83 int func
, union acpi_object
*args
,
86 union acpi_object
*obj
;
88 obj
= acpi_evaluate_dsm(ACPI_HANDLE(dev
), guid
, rev
, func
,
91 IWL_DEBUG_DEV_RADIO(dev
,
92 "ACPI: DSM method invocation failed (rev: %d, func:%d)\n",
94 return ERR_PTR(-ENOENT
);
100 * Generic function to evaluate a DSM with no arguments
101 * and an integer return value,
102 * (as an integer object or inside a buffer object),
103 * verify and assign the value in the "value" parameter.
104 * return 0 in success and the appropriate errno otherwise.
106 static int iwl_acpi_get_dsm_integer(struct device
*dev
, int rev
, int func
,
107 const guid_t
*guid
, u64
*value
,
108 size_t expected_size
)
110 union acpi_object
*obj
;
113 obj
= iwl_acpi_get_dsm_object(dev
, rev
, func
, NULL
, guid
);
115 IWL_DEBUG_DEV_RADIO(dev
,
116 "Failed to get DSM object. func= %d\n",
121 if (obj
->type
== ACPI_TYPE_INTEGER
) {
122 *value
= obj
->integer
.value
;
123 } else if (obj
->type
== ACPI_TYPE_BUFFER
) {
126 if (WARN_ON_ONCE(expected_size
> sizeof(le_value
))) {
131 /* if the buffer size doesn't match the expected size */
132 if (obj
->buffer
.length
!= expected_size
)
133 IWL_DEBUG_DEV_RADIO(dev
,
134 "ACPI: DSM invalid buffer size, padding or truncating (%d)\n",
137 /* assuming LE from Intel BIOS spec */
138 memcpy(&le_value
, obj
->buffer
.pointer
,
139 min_t(size_t, expected_size
, (size_t)obj
->buffer
.length
));
140 *value
= le64_to_cpu(le_value
);
142 IWL_DEBUG_DEV_RADIO(dev
,
143 "ACPI: DSM method did not return a valid object, type=%d\n",
149 IWL_DEBUG_DEV_RADIO(dev
,
150 "ACPI: DSM method evaluated: func=%d, value=%lld\n",
159 * This function receives a DSM function number, calculates its expected size
160 * according to Intel BIOS spec, and fills in the value in a 32-bit field.
161 * In case the expected size is smaller than 32-bit, padding will be added.
163 int iwl_acpi_get_dsm(struct iwl_fw_runtime
*fwrt
,
164 enum iwl_dsm_funcs func
, u32
*value
)
166 size_t expected_size
;
170 BUILD_BUG_ON(ARRAY_SIZE(acpi_dsm_size
) != DSM_FUNC_NUM_FUNCS
);
172 if (WARN_ON(func
>= ARRAY_SIZE(acpi_dsm_size
)))
175 expected_size
= acpi_dsm_size
[func
];
177 /* Currently all ACPI DSMs are either 8-bit or 32-bit */
178 if (expected_size
!= sizeof(u8
) && expected_size
!= sizeof(u32
))
181 ret
= iwl_acpi_get_dsm_integer(fwrt
->dev
, ACPI_DSM_REV
, func
,
182 &iwl_guid
, &tmp
, expected_size
);
186 if ((expected_size
== sizeof(u8
) && tmp
!= (u8
)tmp
) ||
187 (expected_size
== sizeof(u32
) && tmp
!= (u32
)tmp
))
188 IWL_DEBUG_RADIO(fwrt
,
189 "DSM value overflows the expected size, truncating\n");
195 static union acpi_object
*
196 iwl_acpi_get_wifi_pkg_range(struct device
*dev
,
197 union acpi_object
*data
,
203 union acpi_object
*wifi_pkg
;
206 * We need at least one entry in the wifi package that
207 * describes the domain, and one more entry, otherwise there's
208 * no point in reading it.
210 if (WARN_ON_ONCE(min_data_size
< 2 || min_data_size
> max_data_size
))
211 return ERR_PTR(-EINVAL
);
214 * We need at least two packages, one for the revision and one
215 * for the data itself. Also check that the revision is valid
216 * (i.e. it is an integer (each caller has to check by itself
217 * if the returned revision is supported)).
219 if (data
->type
!= ACPI_TYPE_PACKAGE
||
220 data
->package
.count
< 2 ||
221 data
->package
.elements
[0].type
!= ACPI_TYPE_INTEGER
) {
222 IWL_DEBUG_DEV_RADIO(dev
, "Invalid packages structure\n");
223 return ERR_PTR(-EINVAL
);
226 *tbl_rev
= data
->package
.elements
[0].integer
.value
;
228 /* loop through all the packages to find the one for WiFi */
229 for (i
= 1; i
< data
->package
.count
; i
++) {
230 union acpi_object
*domain
;
232 wifi_pkg
= &data
->package
.elements
[i
];
234 /* skip entries that are not a package with the right size */
235 if (wifi_pkg
->type
!= ACPI_TYPE_PACKAGE
||
236 wifi_pkg
->package
.count
< min_data_size
||
237 wifi_pkg
->package
.count
> max_data_size
)
240 domain
= &wifi_pkg
->package
.elements
[0];
241 if (domain
->type
== ACPI_TYPE_INTEGER
&&
242 domain
->integer
.value
== ACPI_WIFI_DOMAIN
)
246 return ERR_PTR(-ENOENT
);
252 static union acpi_object
*
253 iwl_acpi_get_wifi_pkg(struct device
*dev
,
254 union acpi_object
*data
,
255 int data_size
, int *tbl_rev
)
257 return iwl_acpi_get_wifi_pkg_range(dev
, data
, data_size
, data_size
,
261 int iwl_acpi_get_tas_table(struct iwl_fw_runtime
*fwrt
,
262 struct iwl_tas_data
*tas_data
)
264 union acpi_object
*wifi_pkg
, *data
;
265 int ret
, tbl_rev
, block_list_size
, enabled
;
268 data
= iwl_acpi_get_object(fwrt
->dev
, ACPI_WTAS_METHOD
);
270 return PTR_ERR(data
);
272 /* try to read wtas table */
273 wifi_pkg
= iwl_acpi_get_wifi_pkg(fwrt
->dev
, data
,
274 ACPI_WTAS_WIFI_DATA_SIZE
,
276 if (IS_ERR(wifi_pkg
)) {
277 ret
= PTR_ERR(wifi_pkg
);
281 if (tbl_rev
< 0 || tbl_rev
> 2 ||
282 wifi_pkg
->package
.elements
[1].type
!= ACPI_TYPE_INTEGER
) {
287 tas_selection
= (u32
)wifi_pkg
->package
.elements
[1].integer
.value
;
288 enabled
= tas_selection
& IWL_WTAS_ENABLED_MSK
;
290 IWL_DEBUG_RADIO(fwrt
, "TAS selection as read from BIOS: 0x%x\n",
292 tas_data
->table_source
= BIOS_SOURCE_ACPI
;
293 tas_data
->table_revision
= tbl_rev
;
294 tas_data
->tas_selection
= tas_selection
;
296 IWL_DEBUG_RADIO(fwrt
, "TAS %s enabled\n",
297 enabled
? "is" : "not");
299 IWL_DEBUG_RADIO(fwrt
, "Reading TAS table revision %d\n", tbl_rev
);
300 if (wifi_pkg
->package
.elements
[2].type
!= ACPI_TYPE_INTEGER
||
301 wifi_pkg
->package
.elements
[2].integer
.value
>
302 IWL_WTAS_BLACK_LIST_MAX
) {
303 IWL_DEBUG_RADIO(fwrt
, "TAS invalid array size %llu\n",
304 wifi_pkg
->package
.elements
[2].integer
.value
);
309 block_list_size
= wifi_pkg
->package
.elements
[2].integer
.value
;
310 tas_data
->block_list_size
= block_list_size
;
312 IWL_DEBUG_RADIO(fwrt
, "TAS array size %u\n", block_list_size
);
314 for (int i
= 0; i
< block_list_size
; i
++) {
317 if (wifi_pkg
->package
.elements
[3 + i
].type
!=
319 IWL_DEBUG_RADIO(fwrt
,
320 "TAS invalid array elem %d\n", 3 + i
);
325 country
= wifi_pkg
->package
.elements
[3 + i
].integer
.value
;
326 tas_data
->block_list_array
[i
] = country
;
327 IWL_DEBUG_RADIO(fwrt
, "TAS block list country %d\n", country
);
336 int iwl_acpi_get_mcc(struct iwl_fw_runtime
*fwrt
, char *mcc
)
338 union acpi_object
*wifi_pkg
, *data
;
342 data
= iwl_acpi_get_object(fwrt
->dev
, ACPI_WRDD_METHOD
);
344 return PTR_ERR(data
);
346 wifi_pkg
= iwl_acpi_get_wifi_pkg(fwrt
->dev
, data
,
347 ACPI_WRDD_WIFI_DATA_SIZE
,
349 if (IS_ERR(wifi_pkg
)) {
350 ret
= PTR_ERR(wifi_pkg
);
354 if (wifi_pkg
->package
.elements
[1].type
!= ACPI_TYPE_INTEGER
||
360 mcc_val
= wifi_pkg
->package
.elements
[1].integer
.value
;
361 if (mcc_val
!= BIOS_MCC_CHINA
) {
363 IWL_DEBUG_RADIO(fwrt
, "ACPI WRDD is supported only for CN\n");
367 mcc
[0] = (mcc_val
>> 8) & 0xff;
368 mcc
[1] = mcc_val
& 0xff;
377 int iwl_acpi_get_pwr_limit(struct iwl_fw_runtime
*fwrt
, u64
*dflt_pwr_limit
)
379 union acpi_object
*data
, *wifi_pkg
;
380 int tbl_rev
, ret
= -EINVAL
;
383 data
= iwl_acpi_get_object(fwrt
->dev
, ACPI_SPLC_METHOD
);
387 wifi_pkg
= iwl_acpi_get_wifi_pkg(fwrt
->dev
, data
,
388 ACPI_SPLC_WIFI_DATA_SIZE
, &tbl_rev
);
389 if (IS_ERR(wifi_pkg
) || tbl_rev
!= 0 ||
390 wifi_pkg
->package
.elements
[1].integer
.value
!= ACPI_TYPE_INTEGER
)
393 *dflt_pwr_limit
= wifi_pkg
->package
.elements
[1].integer
.value
;
401 int iwl_acpi_get_eckv(struct iwl_fw_runtime
*fwrt
, u32
*extl_clk
)
403 union acpi_object
*wifi_pkg
, *data
;
406 data
= iwl_acpi_get_object(fwrt
->dev
, ACPI_ECKV_METHOD
);
408 return PTR_ERR(data
);
410 wifi_pkg
= iwl_acpi_get_wifi_pkg(fwrt
->dev
, data
,
411 ACPI_ECKV_WIFI_DATA_SIZE
,
413 if (IS_ERR(wifi_pkg
)) {
414 ret
= PTR_ERR(wifi_pkg
);
418 if (wifi_pkg
->package
.elements
[1].type
!= ACPI_TYPE_INTEGER
||
424 *extl_clk
= wifi_pkg
->package
.elements
[1].integer
.value
;
434 iwl_acpi_parse_chains_table(union acpi_object
*table
,
435 struct iwl_sar_profile_chain
*chains
,
436 u8 num_chains
, u8 num_sub_bands
)
438 for (u8 chain
= 0; chain
< num_chains
; chain
++) {
439 for (u8 subband
= 0; subband
< BIOS_SAR_MAX_SUB_BANDS_NUM
;
441 /* if we don't have the values, use the default */
442 if (subband
>= num_sub_bands
) {
443 chains
[chain
].subbands
[subband
] = 0;
444 } else if (table
->type
!= ACPI_TYPE_INTEGER
||
445 table
->integer
.value
> U8_MAX
) {
448 chains
[chain
].subbands
[subband
] =
449 table
->integer
.value
;
458 int iwl_acpi_get_wrds_table(struct iwl_fw_runtime
*fwrt
)
460 union acpi_object
*wifi_pkg
, *table
, *data
;
463 u8 num_chains
, num_sub_bands
;
465 data
= iwl_acpi_get_object(fwrt
->dev
, ACPI_WRDS_METHOD
);
467 return PTR_ERR(data
);
469 /* start by trying to read revision 2 */
470 wifi_pkg
= iwl_acpi_get_wifi_pkg(fwrt
->dev
, data
,
471 ACPI_WRDS_WIFI_DATA_SIZE_REV2
,
473 if (!IS_ERR(wifi_pkg
)) {
479 num_chains
= ACPI_SAR_NUM_CHAINS_REV2
;
480 num_sub_bands
= ACPI_SAR_NUM_SUB_BANDS_REV2
;
485 /* then try revision 1 */
486 wifi_pkg
= iwl_acpi_get_wifi_pkg(fwrt
->dev
, data
,
487 ACPI_WRDS_WIFI_DATA_SIZE_REV1
,
489 if (!IS_ERR(wifi_pkg
)) {
495 num_chains
= ACPI_SAR_NUM_CHAINS_REV1
;
496 num_sub_bands
= ACPI_SAR_NUM_SUB_BANDS_REV1
;
501 /* then finally revision 0 */
502 wifi_pkg
= iwl_acpi_get_wifi_pkg(fwrt
->dev
, data
,
503 ACPI_WRDS_WIFI_DATA_SIZE_REV0
,
505 if (!IS_ERR(wifi_pkg
)) {
511 num_chains
= ACPI_SAR_NUM_CHAINS_REV0
;
512 num_sub_bands
= ACPI_SAR_NUM_SUB_BANDS_REV0
;
517 ret
= PTR_ERR(wifi_pkg
);
521 if (wifi_pkg
->package
.elements
[1].type
!= ACPI_TYPE_INTEGER
) {
526 IWL_DEBUG_RADIO(fwrt
, "Reading WRDS tbl_rev=%d\n", tbl_rev
);
528 flags
= wifi_pkg
->package
.elements
[1].integer
.value
;
529 fwrt
->reduced_power_flags
= flags
>> IWL_REDUCE_POWER_FLAGS_POS
;
531 /* position of the actual table */
532 table
= &wifi_pkg
->package
.elements
[2];
534 /* The profile from WRDS is officially profile 1, but goes
535 * into sar_profiles[0] (because we don't have a profile 0).
537 ret
= iwl_acpi_parse_chains_table(table
, fwrt
->sar_profiles
[0].chains
,
538 num_chains
, num_sub_bands
);
539 if (!ret
&& flags
& IWL_SAR_ENABLE_MSK
)
540 fwrt
->sar_profiles
[0].enabled
= true;
547 int iwl_acpi_get_ewrd_table(struct iwl_fw_runtime
*fwrt
)
549 union acpi_object
*wifi_pkg
, *data
;
551 int i
, n_profiles
, tbl_rev
, pos
;
555 data
= iwl_acpi_get_object(fwrt
->dev
, ACPI_EWRD_METHOD
);
557 return PTR_ERR(data
);
559 /* start by trying to read revision 2 */
560 wifi_pkg
= iwl_acpi_get_wifi_pkg(fwrt
->dev
, data
,
561 ACPI_EWRD_WIFI_DATA_SIZE_REV2
,
563 if (!IS_ERR(wifi_pkg
)) {
569 num_sub_bands
= ACPI_SAR_NUM_SUB_BANDS_REV2
;
574 /* then try revision 1 */
575 wifi_pkg
= iwl_acpi_get_wifi_pkg(fwrt
->dev
, data
,
576 ACPI_EWRD_WIFI_DATA_SIZE_REV1
,
578 if (!IS_ERR(wifi_pkg
)) {
584 num_sub_bands
= ACPI_SAR_NUM_SUB_BANDS_REV1
;
589 /* then finally revision 0 */
590 wifi_pkg
= iwl_acpi_get_wifi_pkg(fwrt
->dev
, data
,
591 ACPI_EWRD_WIFI_DATA_SIZE_REV0
,
593 if (!IS_ERR(wifi_pkg
)) {
599 num_sub_bands
= ACPI_SAR_NUM_SUB_BANDS_REV0
;
604 ret
= PTR_ERR(wifi_pkg
);
608 if (wifi_pkg
->package
.elements
[1].type
!= ACPI_TYPE_INTEGER
||
609 wifi_pkg
->package
.elements
[2].type
!= ACPI_TYPE_INTEGER
) {
614 enabled
= !!(wifi_pkg
->package
.elements
[1].integer
.value
);
615 n_profiles
= wifi_pkg
->package
.elements
[2].integer
.value
;
618 * Check the validity of n_profiles. The EWRD profiles start
619 * from index 1, so the maximum value allowed here is
620 * ACPI_SAR_PROFILES_NUM - 1.
622 if (n_profiles
>= BIOS_SAR_MAX_PROFILE_NUM
) {
627 /* the tables start at element 3 */
630 BUILD_BUG_ON(ACPI_SAR_NUM_CHAINS_REV0
!= ACPI_SAR_NUM_CHAINS_REV1
);
631 BUILD_BUG_ON(ACPI_SAR_NUM_CHAINS_REV2
!= 2 * ACPI_SAR_NUM_CHAINS_REV0
);
633 /* parse non-cdb chains for all profiles */
634 for (i
= 0; i
< n_profiles
; i
++) {
635 union acpi_object
*table
= &wifi_pkg
->package
.elements
[pos
];
637 /* The EWRD profiles officially go from 2 to 4, but we
638 * save them in sar_profiles[1-3] (because we don't
639 * have profile 0). So in the array we start from 1.
641 ret
= iwl_acpi_parse_chains_table(table
,
642 fwrt
->sar_profiles
[i
+ 1].chains
,
643 ACPI_SAR_NUM_CHAINS_REV0
,
648 /* go to the next table */
649 pos
+= ACPI_SAR_NUM_CHAINS_REV0
* num_sub_bands
;
652 /* non-cdb table revisions */
656 /* parse cdb chains for all profiles */
657 for (i
= 0; i
< n_profiles
; i
++) {
658 struct iwl_sar_profile_chain
*chains
;
659 union acpi_object
*table
;
661 table
= &wifi_pkg
->package
.elements
[pos
];
662 chains
= &fwrt
->sar_profiles
[i
+ 1].chains
[ACPI_SAR_NUM_CHAINS_REV0
];
663 ret
= iwl_acpi_parse_chains_table(table
,
665 ACPI_SAR_NUM_CHAINS_REV0
,
670 /* go to the next table */
671 pos
+= ACPI_SAR_NUM_CHAINS_REV0
* num_sub_bands
;
675 for (i
= 0; i
< n_profiles
; i
++)
676 fwrt
->sar_profiles
[i
+ 1].enabled
= enabled
;
683 int iwl_acpi_get_wgds_table(struct iwl_fw_runtime
*fwrt
)
685 union acpi_object
*wifi_pkg
, *data
;
686 int i
, j
, k
, ret
, tbl_rev
;
687 u8 num_bands
, num_profiles
;
688 static const struct {
696 .bands
= ACPI_GEO_NUM_BANDS_REV2
,
697 .profiles
= ACPI_NUM_GEO_PROFILES_REV3
,
698 .min_profiles
= BIOS_GEO_MIN_PROFILE_NUM
,
702 .bands
= ACPI_GEO_NUM_BANDS_REV2
,
703 .profiles
= ACPI_NUM_GEO_PROFILES
,
706 .revisions
= BIT(0) | BIT(1),
707 .bands
= ACPI_GEO_NUM_BANDS_REV0
,
708 .profiles
= ACPI_NUM_GEO_PROFILES
,
712 /* start from one to skip the domain */
715 BUILD_BUG_ON(ACPI_NUM_GEO_PROFILES_REV3
!= IWL_NUM_GEO_PROFILES_V3
);
716 BUILD_BUG_ON(ACPI_NUM_GEO_PROFILES
!= IWL_NUM_GEO_PROFILES
);
718 data
= iwl_acpi_get_object(fwrt
->dev
, ACPI_WGDS_METHOD
);
720 return PTR_ERR(data
);
722 /* read the highest revision we understand first */
723 for (idx
= 0; idx
< ARRAY_SIZE(rev_data
); idx
++) {
724 /* min_profiles != 0 requires num_profiles header */
725 u32 hdr_size
= 1 + !!rev_data
[idx
].min_profiles
;
726 u32 profile_size
= ACPI_GEO_PER_CHAIN_SIZE
*
728 u32 max_size
= hdr_size
+ profile_size
* rev_data
[idx
].profiles
;
731 if (!rev_data
[idx
].min_profiles
)
734 min_size
= hdr_size
+
735 profile_size
* rev_data
[idx
].min_profiles
;
737 wifi_pkg
= iwl_acpi_get_wifi_pkg_range(fwrt
->dev
, data
,
740 if (!IS_ERR(wifi_pkg
)) {
741 if (!(BIT(tbl_rev
) & rev_data
[idx
].revisions
))
744 num_bands
= rev_data
[idx
].bands
;
745 num_profiles
= rev_data
[idx
].profiles
;
747 if (rev_data
[idx
].min_profiles
) {
748 /* read header that says # of profiles */
749 union acpi_object
*entry
;
751 entry
= &wifi_pkg
->package
.elements
[entry_idx
];
753 if (entry
->type
!= ACPI_TYPE_INTEGER
||
754 entry
->integer
.value
> num_profiles
||
755 entry
->integer
.value
<
756 rev_data
[idx
].min_profiles
) {
762 * Check to see if we received package count
763 * same as max # of profiles
765 if (wifi_pkg
->package
.count
!=
766 hdr_size
+ profile_size
* num_profiles
) {
771 /* Number of valid profiles */
772 num_profiles
= entry
->integer
.value
;
778 if (idx
< ARRAY_SIZE(rev_data
))
779 ret
= PTR_ERR(wifi_pkg
);
785 fwrt
->geo_rev
= tbl_rev
;
786 for (i
= 0; i
< num_profiles
; i
++) {
787 for (j
= 0; j
< BIOS_GEO_MAX_NUM_BANDS
; j
++) {
788 union acpi_object
*entry
;
791 * num_bands is either 2 or 3, if it's only 2 then
792 * fill the third band (6 GHz) with the values from
793 * 5 GHz (second band)
795 if (j
>= num_bands
) {
796 fwrt
->geo_profiles
[i
].bands
[j
].max
=
797 fwrt
->geo_profiles
[i
].bands
[1].max
;
799 entry
= &wifi_pkg
->package
.elements
[entry_idx
];
801 if (entry
->type
!= ACPI_TYPE_INTEGER
||
802 entry
->integer
.value
> U8_MAX
) {
807 fwrt
->geo_profiles
[i
].bands
[j
].max
=
808 entry
->integer
.value
;
811 for (k
= 0; k
< BIOS_GEO_NUM_CHAINS
; k
++) {
812 /* same here as above */
813 if (j
>= num_bands
) {
814 fwrt
->geo_profiles
[i
].bands
[j
].chains
[k
] =
815 fwrt
->geo_profiles
[i
].bands
[1].chains
[k
];
817 entry
= &wifi_pkg
->package
.elements
[entry_idx
];
819 if (entry
->type
!= ACPI_TYPE_INTEGER
||
820 entry
->integer
.value
> U8_MAX
) {
825 fwrt
->geo_profiles
[i
].bands
[j
].chains
[k
] =
826 entry
->integer
.value
;
832 fwrt
->geo_num_profiles
= num_profiles
;
833 fwrt
->geo_enabled
= true;
840 int iwl_acpi_get_ppag_table(struct iwl_fw_runtime
*fwrt
)
842 union acpi_object
*wifi_pkg
, *data
, *flags
;
843 int i
, j
, ret
, tbl_rev
, num_sub_bands
= 0;
846 data
= iwl_acpi_get_object(fwrt
->dev
, ACPI_PPAG_METHOD
);
848 return PTR_ERR(data
);
850 /* try to read ppag table rev 3, 2 or 1 (all have the same data size) */
851 wifi_pkg
= iwl_acpi_get_wifi_pkg(fwrt
->dev
, data
,
852 ACPI_PPAG_WIFI_DATA_SIZE_V2
, &tbl_rev
);
854 if (!IS_ERR(wifi_pkg
)) {
855 if (tbl_rev
>= 1 && tbl_rev
<= 3) {
856 num_sub_bands
= IWL_NUM_SUB_BANDS_V2
;
857 IWL_DEBUG_RADIO(fwrt
,
858 "Reading PPAG table (tbl_rev=%d)\n",
867 /* try to read ppag table revision 0 */
868 wifi_pkg
= iwl_acpi_get_wifi_pkg(fwrt
->dev
, data
,
869 ACPI_PPAG_WIFI_DATA_SIZE_V1
, &tbl_rev
);
871 if (!IS_ERR(wifi_pkg
)) {
876 num_sub_bands
= IWL_NUM_SUB_BANDS_V1
;
877 IWL_DEBUG_RADIO(fwrt
, "Reading PPAG table v1 (tbl_rev=0)\n");
881 ret
= PTR_ERR(wifi_pkg
);
885 fwrt
->ppag_ver
= tbl_rev
;
886 flags
= &wifi_pkg
->package
.elements
[1];
888 if (flags
->type
!= ACPI_TYPE_INTEGER
) {
893 fwrt
->ppag_flags
= iwl_bios_get_ppag_flags(flags
->integer
.value
,
897 * read, verify gain values and save them into the PPAG table.
898 * first sub-band (j=0) corresponds to Low-Band (2.4GHz), and the
899 * following sub-bands to High-Band (5GHz).
901 for (i
= 0; i
< IWL_NUM_CHAIN_LIMITS
; i
++) {
902 for (j
= 0; j
< num_sub_bands
; j
++) {
903 union acpi_object
*ent
;
905 ent
= &wifi_pkg
->package
.elements
[idx
++];
906 if (ent
->type
!= ACPI_TYPE_INTEGER
) {
911 fwrt
->ppag_chains
[i
].subbands
[j
] = ent
->integer
.value
;
922 void iwl_acpi_get_phy_filters(struct iwl_fw_runtime
*fwrt
,
923 struct iwl_phy_specific_cfg
*filters
)
925 struct iwl_phy_specific_cfg tmp
= {};
926 union acpi_object
*wifi_pkg
, *data
;
929 data
= iwl_acpi_get_object(fwrt
->dev
, ACPI_WPFC_METHOD
);
933 wifi_pkg
= iwl_acpi_get_wifi_pkg(fwrt
->dev
, data
,
934 ACPI_WPFC_WIFI_DATA_SIZE
,
936 if (IS_ERR(wifi_pkg
))
942 BUILD_BUG_ON(ARRAY_SIZE(filters
->filter_cfg_chains
) !=
943 ACPI_WPFC_WIFI_DATA_SIZE
- 1);
945 for (i
= 0; i
< ARRAY_SIZE(filters
->filter_cfg_chains
); i
++) {
946 if (wifi_pkg
->package
.elements
[i
+ 1].type
!= ACPI_TYPE_INTEGER
)
948 tmp
.filter_cfg_chains
[i
] =
949 cpu_to_le32(wifi_pkg
->package
.elements
[i
+ 1].integer
.value
);
952 IWL_DEBUG_RADIO(fwrt
, "Loaded WPFC filter config from ACPI\n");
957 IWL_EXPORT_SYMBOL(iwl_acpi_get_phy_filters
);
959 void iwl_acpi_get_guid_lock_status(struct iwl_fw_runtime
*fwrt
)
961 union acpi_object
*wifi_pkg
, *data
;
964 data
= iwl_acpi_get_object(fwrt
->dev
, ACPI_GLAI_METHOD
);
968 wifi_pkg
= iwl_acpi_get_wifi_pkg(fwrt
->dev
, data
,
969 ACPI_GLAI_WIFI_DATA_SIZE
,
971 if (IS_ERR(wifi_pkg
))
975 IWL_DEBUG_RADIO(fwrt
, "Invalid GLAI revision: %d\n", tbl_rev
);
979 if (wifi_pkg
->package
.elements
[1].type
!= ACPI_TYPE_INTEGER
||
980 wifi_pkg
->package
.elements
[1].integer
.value
> ACPI_GLAI_MAX_STATUS
)
983 fwrt
->uefi_tables_lock_status
=
984 wifi_pkg
->package
.elements
[1].integer
.value
;
986 IWL_DEBUG_RADIO(fwrt
,
987 "Loaded UEFI WIFI GUID lock status: %d from ACPI\n",
988 fwrt
->uefi_tables_lock_status
);
992 IWL_EXPORT_SYMBOL(iwl_acpi_get_guid_lock_status
);
994 int iwl_acpi_get_wbem(struct iwl_fw_runtime
*fwrt
, u32
*value
)
996 union acpi_object
*wifi_pkg
, *data
;
1000 data
= iwl_acpi_get_object(fwrt
->dev
, ACPI_WBEM_METHOD
);
1004 wifi_pkg
= iwl_acpi_get_wifi_pkg(fwrt
->dev
, data
,
1005 ACPI_WBEM_WIFI_DATA_SIZE
,
1007 if (IS_ERR(wifi_pkg
))
1010 if (tbl_rev
!= IWL_ACPI_WBEM_REVISION
) {
1011 IWL_DEBUG_RADIO(fwrt
, "Unsupported ACPI WBEM revision:%d\n",
1016 if (wifi_pkg
->package
.elements
[1].type
!= ACPI_TYPE_INTEGER
)
1019 *value
= wifi_pkg
->package
.elements
[1].integer
.value
&
1020 IWL_ACPI_WBEM_REV0_MASK
;
1021 IWL_DEBUG_RADIO(fwrt
, "Loaded WBEM config from ACPI\n");
1028 int iwl_acpi_get_dsbr(struct iwl_fw_runtime
*fwrt
, u32
*value
)
1030 union acpi_object
*wifi_pkg
, *data
;
1034 data
= iwl_acpi_get_object(fwrt
->dev
, ACPI_DSBR_METHOD
);
1038 wifi_pkg
= iwl_acpi_get_wifi_pkg(fwrt
->dev
, data
,
1039 ACPI_DSBR_WIFI_DATA_SIZE
,
1041 if (IS_ERR(wifi_pkg
))
1044 if (tbl_rev
!= ACPI_DSBR_WIFI_DATA_REV
) {
1045 IWL_DEBUG_RADIO(fwrt
, "Unsupported ACPI DSBR revision:%d\n",
1050 if (wifi_pkg
->package
.elements
[1].type
!= ACPI_TYPE_INTEGER
)
1053 *value
= wifi_pkg
->package
.elements
[1].integer
.value
;
1054 IWL_DEBUG_RADIO(fwrt
, "Loaded DSBR config from ACPI value: 0x%x\n",