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 static void *iwl_acpi_get_dsm_object(struct device
*dev
, int rev
, int func
,
83 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
)))
129 /* if the buffer size doesn't match the expected size */
130 if (obj
->buffer
.length
!= expected_size
)
131 IWL_DEBUG_DEV_RADIO(dev
,
132 "ACPI: DSM invalid buffer size, padding or truncating (%d)\n",
135 /* assuming LE from Intel BIOS spec */
136 memcpy(&le_value
, obj
->buffer
.pointer
,
137 min_t(size_t, expected_size
, (size_t)obj
->buffer
.length
));
138 *value
= le64_to_cpu(le_value
);
140 IWL_DEBUG_DEV_RADIO(dev
,
141 "ACPI: DSM method did not return a valid object, type=%d\n",
147 IWL_DEBUG_DEV_RADIO(dev
,
148 "ACPI: DSM method evaluated: func=%d, ret=%d\n",
156 * This function receives a DSM function number, calculates its expected size
157 * according to Intel BIOS spec, and fills in the value in a 32-bit field.
158 * In case the expected size is smaller than 32-bit, padding will be added.
160 int iwl_acpi_get_dsm(struct iwl_fw_runtime
*fwrt
,
161 enum iwl_dsm_funcs func
, u32
*value
)
163 size_t expected_size
;
167 BUILD_BUG_ON(ARRAY_SIZE(acpi_dsm_size
) != DSM_FUNC_NUM_FUNCS
);
169 if (WARN_ON(func
>= ARRAY_SIZE(acpi_dsm_size
)))
172 expected_size
= acpi_dsm_size
[func
];
174 /* Currently all ACPI DSMs are either 8-bit or 32-bit */
175 if (expected_size
!= sizeof(u8
) && expected_size
!= sizeof(u32
))
178 ret
= iwl_acpi_get_dsm_integer(fwrt
->dev
, ACPI_DSM_REV
, func
,
179 &iwl_guid
, &tmp
, expected_size
);
183 if ((expected_size
== sizeof(u8
) && tmp
!= (u8
)tmp
) ||
184 (expected_size
== sizeof(u32
) && tmp
!= (u32
)tmp
))
185 IWL_DEBUG_RADIO(fwrt
,
186 "DSM value overflows the expected size, truncating\n");
192 static union acpi_object
*
193 iwl_acpi_get_wifi_pkg_range(struct device
*dev
,
194 union acpi_object
*data
,
200 union acpi_object
*wifi_pkg
;
203 * We need at least one entry in the wifi package that
204 * describes the domain, and one more entry, otherwise there's
205 * no point in reading it.
207 if (WARN_ON_ONCE(min_data_size
< 2 || min_data_size
> max_data_size
))
208 return ERR_PTR(-EINVAL
);
211 * We need at least two packages, one for the revision and one
212 * for the data itself. Also check that the revision is valid
213 * (i.e. it is an integer (each caller has to check by itself
214 * if the returned revision is supported)).
216 if (data
->type
!= ACPI_TYPE_PACKAGE
||
217 data
->package
.count
< 2 ||
218 data
->package
.elements
[0].type
!= ACPI_TYPE_INTEGER
) {
219 IWL_DEBUG_DEV_RADIO(dev
, "Invalid packages structure\n");
220 return ERR_PTR(-EINVAL
);
223 *tbl_rev
= data
->package
.elements
[0].integer
.value
;
225 /* loop through all the packages to find the one for WiFi */
226 for (i
= 1; i
< data
->package
.count
; i
++) {
227 union acpi_object
*domain
;
229 wifi_pkg
= &data
->package
.elements
[i
];
231 /* skip entries that are not a package with the right size */
232 if (wifi_pkg
->type
!= ACPI_TYPE_PACKAGE
||
233 wifi_pkg
->package
.count
< min_data_size
||
234 wifi_pkg
->package
.count
> max_data_size
)
237 domain
= &wifi_pkg
->package
.elements
[0];
238 if (domain
->type
== ACPI_TYPE_INTEGER
&&
239 domain
->integer
.value
== ACPI_WIFI_DOMAIN
)
243 return ERR_PTR(-ENOENT
);
249 static union acpi_object
*
250 iwl_acpi_get_wifi_pkg(struct device
*dev
,
251 union acpi_object
*data
,
252 int data_size
, int *tbl_rev
)
254 return iwl_acpi_get_wifi_pkg_range(dev
, data
, data_size
, data_size
,
258 int iwl_acpi_get_tas_table(struct iwl_fw_runtime
*fwrt
,
259 struct iwl_tas_data
*tas_data
)
261 union acpi_object
*wifi_pkg
, *data
;
262 int ret
, tbl_rev
, i
, block_list_size
, enabled
;
264 data
= iwl_acpi_get_object(fwrt
->dev
, ACPI_WTAS_METHOD
);
266 return PTR_ERR(data
);
268 /* try to read wtas table revision 1 or revision 0*/
269 wifi_pkg
= iwl_acpi_get_wifi_pkg(fwrt
->dev
, data
,
270 ACPI_WTAS_WIFI_DATA_SIZE
,
272 if (IS_ERR(wifi_pkg
)) {
273 ret
= PTR_ERR(wifi_pkg
);
277 if (tbl_rev
== 1 && wifi_pkg
->package
.elements
[1].type
==
280 (u32
)wifi_pkg
->package
.elements
[1].integer
.value
;
282 enabled
= iwl_parse_tas_selection(fwrt
, tas_data
,
285 } else if (tbl_rev
== 0 &&
286 wifi_pkg
->package
.elements
[1].type
== ACPI_TYPE_INTEGER
) {
287 enabled
= !!wifi_pkg
->package
.elements
[1].integer
.value
;
294 IWL_DEBUG_RADIO(fwrt
, "TAS not enabled\n");
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
);
308 block_list_size
= wifi_pkg
->package
.elements
[2].integer
.value
;
309 tas_data
->block_list_size
= cpu_to_le32(block_list_size
);
311 IWL_DEBUG_RADIO(fwrt
, "TAS array size %u\n", block_list_size
);
313 for (i
= 0; i
< block_list_size
; i
++) {
316 if (wifi_pkg
->package
.elements
[3 + i
].type
!=
318 IWL_DEBUG_RADIO(fwrt
,
319 "TAS invalid array elem %d\n", 3 + i
);
324 country
= wifi_pkg
->package
.elements
[3 + i
].integer
.value
;
325 tas_data
->block_list_array
[i
] = cpu_to_le32(country
);
326 IWL_DEBUG_RADIO(fwrt
, "TAS block list country %d\n", country
);
335 int iwl_acpi_get_mcc(struct iwl_fw_runtime
*fwrt
, char *mcc
)
337 union acpi_object
*wifi_pkg
, *data
;
341 data
= iwl_acpi_get_object(fwrt
->dev
, ACPI_WRDD_METHOD
);
343 return PTR_ERR(data
);
345 wifi_pkg
= iwl_acpi_get_wifi_pkg(fwrt
->dev
, data
,
346 ACPI_WRDD_WIFI_DATA_SIZE
,
348 if (IS_ERR(wifi_pkg
)) {
349 ret
= PTR_ERR(wifi_pkg
);
353 if (wifi_pkg
->package
.elements
[1].type
!= ACPI_TYPE_INTEGER
||
359 mcc_val
= wifi_pkg
->package
.elements
[1].integer
.value
;
360 if (mcc_val
!= BIOS_MCC_CHINA
) {
362 IWL_DEBUG_RADIO(fwrt
, "ACPI WRDD is supported only for CN\n");
366 mcc
[0] = (mcc_val
>> 8) & 0xff;
367 mcc
[1] = mcc_val
& 0xff;
376 int iwl_acpi_get_pwr_limit(struct iwl_fw_runtime
*fwrt
, u64
*dflt_pwr_limit
)
378 union acpi_object
*data
, *wifi_pkg
;
379 int tbl_rev
, ret
= -EINVAL
;
382 data
= iwl_acpi_get_object(fwrt
->dev
, ACPI_SPLC_METHOD
);
386 wifi_pkg
= iwl_acpi_get_wifi_pkg(fwrt
->dev
, data
,
387 ACPI_SPLC_WIFI_DATA_SIZE
, &tbl_rev
);
388 if (IS_ERR(wifi_pkg
) || tbl_rev
!= 0 ||
389 wifi_pkg
->package
.elements
[1].integer
.value
!= ACPI_TYPE_INTEGER
)
392 *dflt_pwr_limit
= wifi_pkg
->package
.elements
[1].integer
.value
;
400 int iwl_acpi_get_eckv(struct iwl_fw_runtime
*fwrt
, u32
*extl_clk
)
402 union acpi_object
*wifi_pkg
, *data
;
405 data
= iwl_acpi_get_object(fwrt
->dev
, ACPI_ECKV_METHOD
);
407 return PTR_ERR(data
);
409 wifi_pkg
= iwl_acpi_get_wifi_pkg(fwrt
->dev
, data
,
410 ACPI_ECKV_WIFI_DATA_SIZE
,
412 if (IS_ERR(wifi_pkg
)) {
413 ret
= PTR_ERR(wifi_pkg
);
417 if (wifi_pkg
->package
.elements
[1].type
!= ACPI_TYPE_INTEGER
||
423 *extl_clk
= wifi_pkg
->package
.elements
[1].integer
.value
;
433 iwl_acpi_parse_chains_table(union acpi_object
*table
,
434 struct iwl_sar_profile_chain
*chains
,
435 u8 num_chains
, u8 num_sub_bands
)
437 for (u8 chain
= 0; chain
< num_chains
; chain
++) {
438 for (u8 subband
= 0; subband
< BIOS_SAR_MAX_SUB_BANDS_NUM
;
440 /* if we don't have the values, use the default */
441 if (subband
>= num_sub_bands
) {
442 chains
[chain
].subbands
[subband
] = 0;
443 } else if (table
->type
!= ACPI_TYPE_INTEGER
||
444 table
->integer
.value
> U8_MAX
) {
447 chains
[chain
].subbands
[subband
] =
448 table
->integer
.value
;
457 int iwl_acpi_get_wrds_table(struct iwl_fw_runtime
*fwrt
)
459 union acpi_object
*wifi_pkg
, *table
, *data
;
462 u8 num_chains
, num_sub_bands
;
464 data
= iwl_acpi_get_object(fwrt
->dev
, ACPI_WRDS_METHOD
);
466 return PTR_ERR(data
);
468 /* start by trying to read revision 2 */
469 wifi_pkg
= iwl_acpi_get_wifi_pkg(fwrt
->dev
, data
,
470 ACPI_WRDS_WIFI_DATA_SIZE_REV2
,
472 if (!IS_ERR(wifi_pkg
)) {
478 num_chains
= ACPI_SAR_NUM_CHAINS_REV2
;
479 num_sub_bands
= ACPI_SAR_NUM_SUB_BANDS_REV2
;
484 /* then try revision 1 */
485 wifi_pkg
= iwl_acpi_get_wifi_pkg(fwrt
->dev
, data
,
486 ACPI_WRDS_WIFI_DATA_SIZE_REV1
,
488 if (!IS_ERR(wifi_pkg
)) {
494 num_chains
= ACPI_SAR_NUM_CHAINS_REV1
;
495 num_sub_bands
= ACPI_SAR_NUM_SUB_BANDS_REV1
;
500 /* then finally revision 0 */
501 wifi_pkg
= iwl_acpi_get_wifi_pkg(fwrt
->dev
, data
,
502 ACPI_WRDS_WIFI_DATA_SIZE_REV0
,
504 if (!IS_ERR(wifi_pkg
)) {
510 num_chains
= ACPI_SAR_NUM_CHAINS_REV0
;
511 num_sub_bands
= ACPI_SAR_NUM_SUB_BANDS_REV0
;
516 ret
= PTR_ERR(wifi_pkg
);
520 if (wifi_pkg
->package
.elements
[1].type
!= ACPI_TYPE_INTEGER
) {
525 IWL_DEBUG_RADIO(fwrt
, "Reading WRDS tbl_rev=%d\n", tbl_rev
);
527 flags
= wifi_pkg
->package
.elements
[1].integer
.value
;
528 fwrt
->reduced_power_flags
= flags
>> IWL_REDUCE_POWER_FLAGS_POS
;
530 /* position of the actual table */
531 table
= &wifi_pkg
->package
.elements
[2];
533 /* The profile from WRDS is officially profile 1, but goes
534 * into sar_profiles[0] (because we don't have a profile 0).
536 ret
= iwl_acpi_parse_chains_table(table
, fwrt
->sar_profiles
[0].chains
,
537 num_chains
, num_sub_bands
);
538 if (!ret
&& flags
& IWL_SAR_ENABLE_MSK
)
539 fwrt
->sar_profiles
[0].enabled
= true;
546 int iwl_acpi_get_ewrd_table(struct iwl_fw_runtime
*fwrt
)
548 union acpi_object
*wifi_pkg
, *data
;
550 int i
, n_profiles
, tbl_rev
, pos
;
554 data
= iwl_acpi_get_object(fwrt
->dev
, ACPI_EWRD_METHOD
);
556 return PTR_ERR(data
);
558 /* start by trying to read revision 2 */
559 wifi_pkg
= iwl_acpi_get_wifi_pkg(fwrt
->dev
, data
,
560 ACPI_EWRD_WIFI_DATA_SIZE_REV2
,
562 if (!IS_ERR(wifi_pkg
)) {
568 num_sub_bands
= ACPI_SAR_NUM_SUB_BANDS_REV2
;
573 /* then try revision 1 */
574 wifi_pkg
= iwl_acpi_get_wifi_pkg(fwrt
->dev
, data
,
575 ACPI_EWRD_WIFI_DATA_SIZE_REV1
,
577 if (!IS_ERR(wifi_pkg
)) {
583 num_sub_bands
= ACPI_SAR_NUM_SUB_BANDS_REV1
;
588 /* then finally revision 0 */
589 wifi_pkg
= iwl_acpi_get_wifi_pkg(fwrt
->dev
, data
,
590 ACPI_EWRD_WIFI_DATA_SIZE_REV0
,
592 if (!IS_ERR(wifi_pkg
)) {
598 num_sub_bands
= ACPI_SAR_NUM_SUB_BANDS_REV0
;
603 ret
= PTR_ERR(wifi_pkg
);
607 if (wifi_pkg
->package
.elements
[1].type
!= ACPI_TYPE_INTEGER
||
608 wifi_pkg
->package
.elements
[2].type
!= ACPI_TYPE_INTEGER
) {
613 enabled
= !!(wifi_pkg
->package
.elements
[1].integer
.value
);
614 n_profiles
= wifi_pkg
->package
.elements
[2].integer
.value
;
617 * Check the validity of n_profiles. The EWRD profiles start
618 * from index 1, so the maximum value allowed here is
619 * ACPI_SAR_PROFILES_NUM - 1.
621 if (n_profiles
>= BIOS_SAR_MAX_PROFILE_NUM
) {
626 /* the tables start at element 3 */
629 BUILD_BUG_ON(ACPI_SAR_NUM_CHAINS_REV0
!= ACPI_SAR_NUM_CHAINS_REV1
);
630 BUILD_BUG_ON(ACPI_SAR_NUM_CHAINS_REV2
!= 2 * ACPI_SAR_NUM_CHAINS_REV0
);
632 /* parse non-cdb chains for all profiles */
633 for (i
= 0; i
< n_profiles
; i
++) {
634 union acpi_object
*table
= &wifi_pkg
->package
.elements
[pos
];
636 /* The EWRD profiles officially go from 2 to 4, but we
637 * save them in sar_profiles[1-3] (because we don't
638 * have profile 0). So in the array we start from 1.
640 ret
= iwl_acpi_parse_chains_table(table
,
641 fwrt
->sar_profiles
[i
+ 1].chains
,
642 ACPI_SAR_NUM_CHAINS_REV0
,
647 /* go to the next table */
648 pos
+= ACPI_SAR_NUM_CHAINS_REV0
* num_sub_bands
;
651 /* non-cdb table revisions */
655 /* parse cdb chains for all profiles */
656 for (i
= 0; i
< n_profiles
; i
++) {
657 struct iwl_sar_profile_chain
*chains
;
658 union acpi_object
*table
;
660 table
= &wifi_pkg
->package
.elements
[pos
];
661 chains
= &fwrt
->sar_profiles
[i
+ 1].chains
[ACPI_SAR_NUM_CHAINS_REV0
];
662 ret
= iwl_acpi_parse_chains_table(table
,
664 ACPI_SAR_NUM_CHAINS_REV0
,
669 /* go to the next table */
670 pos
+= ACPI_SAR_NUM_CHAINS_REV0
* num_sub_bands
;
674 for (i
= 0; i
< n_profiles
; i
++)
675 fwrt
->sar_profiles
[i
+ 1].enabled
= enabled
;
682 int iwl_acpi_get_wgds_table(struct iwl_fw_runtime
*fwrt
)
684 union acpi_object
*wifi_pkg
, *data
;
685 int i
, j
, k
, ret
, tbl_rev
;
686 u8 num_bands
, num_profiles
;
687 static const struct {
695 .bands
= ACPI_GEO_NUM_BANDS_REV2
,
696 .profiles
= ACPI_NUM_GEO_PROFILES_REV3
,
697 .min_profiles
= BIOS_GEO_MIN_PROFILE_NUM
,
701 .bands
= ACPI_GEO_NUM_BANDS_REV2
,
702 .profiles
= ACPI_NUM_GEO_PROFILES
,
705 .revisions
= BIT(0) | BIT(1),
706 .bands
= ACPI_GEO_NUM_BANDS_REV0
,
707 .profiles
= ACPI_NUM_GEO_PROFILES
,
711 /* start from one to skip the domain */
714 BUILD_BUG_ON(ACPI_NUM_GEO_PROFILES_REV3
!= IWL_NUM_GEO_PROFILES_V3
);
715 BUILD_BUG_ON(ACPI_NUM_GEO_PROFILES
!= IWL_NUM_GEO_PROFILES
);
717 data
= iwl_acpi_get_object(fwrt
->dev
, ACPI_WGDS_METHOD
);
719 return PTR_ERR(data
);
721 /* read the highest revision we understand first */
722 for (idx
= 0; idx
< ARRAY_SIZE(rev_data
); idx
++) {
723 /* min_profiles != 0 requires num_profiles header */
724 u32 hdr_size
= 1 + !!rev_data
[idx
].min_profiles
;
725 u32 profile_size
= ACPI_GEO_PER_CHAIN_SIZE
*
727 u32 max_size
= hdr_size
+ profile_size
* rev_data
[idx
].profiles
;
730 if (!rev_data
[idx
].min_profiles
)
733 min_size
= hdr_size
+
734 profile_size
* rev_data
[idx
].min_profiles
;
736 wifi_pkg
= iwl_acpi_get_wifi_pkg_range(fwrt
->dev
, data
,
739 if (!IS_ERR(wifi_pkg
)) {
740 if (!(BIT(tbl_rev
) & rev_data
[idx
].revisions
))
743 num_bands
= rev_data
[idx
].bands
;
744 num_profiles
= rev_data
[idx
].profiles
;
746 if (rev_data
[idx
].min_profiles
) {
747 /* read header that says # of profiles */
748 union acpi_object
*entry
;
750 entry
= &wifi_pkg
->package
.elements
[entry_idx
];
752 if (entry
->type
!= ACPI_TYPE_INTEGER
||
753 entry
->integer
.value
> num_profiles
||
754 entry
->integer
.value
<
755 rev_data
[idx
].min_profiles
) {
761 * Check to see if we received package count
762 * same as max # of profiles
764 if (wifi_pkg
->package
.count
!=
765 hdr_size
+ profile_size
* num_profiles
) {
770 /* Number of valid profiles */
771 num_profiles
= entry
->integer
.value
;
777 if (idx
< ARRAY_SIZE(rev_data
))
778 ret
= PTR_ERR(wifi_pkg
);
784 fwrt
->geo_rev
= tbl_rev
;
785 for (i
= 0; i
< num_profiles
; i
++) {
786 for (j
= 0; j
< BIOS_GEO_MAX_NUM_BANDS
; j
++) {
787 union acpi_object
*entry
;
790 * num_bands is either 2 or 3, if it's only 2 then
791 * fill the third band (6 GHz) with the values from
792 * 5 GHz (second band)
794 if (j
>= num_bands
) {
795 fwrt
->geo_profiles
[i
].bands
[j
].max
=
796 fwrt
->geo_profiles
[i
].bands
[1].max
;
798 entry
= &wifi_pkg
->package
.elements
[entry_idx
];
800 if (entry
->type
!= ACPI_TYPE_INTEGER
||
801 entry
->integer
.value
> U8_MAX
) {
806 fwrt
->geo_profiles
[i
].bands
[j
].max
=
807 entry
->integer
.value
;
810 for (k
= 0; k
< BIOS_GEO_NUM_CHAINS
; k
++) {
811 /* same here as above */
812 if (j
>= num_bands
) {
813 fwrt
->geo_profiles
[i
].bands
[j
].chains
[k
] =
814 fwrt
->geo_profiles
[i
].bands
[1].chains
[k
];
816 entry
= &wifi_pkg
->package
.elements
[entry_idx
];
818 if (entry
->type
!= ACPI_TYPE_INTEGER
||
819 entry
->integer
.value
> U8_MAX
) {
824 fwrt
->geo_profiles
[i
].bands
[j
].chains
[k
] =
825 entry
->integer
.value
;
831 fwrt
->geo_num_profiles
= num_profiles
;
832 fwrt
->geo_enabled
= true;
839 int iwl_acpi_get_ppag_table(struct iwl_fw_runtime
*fwrt
)
841 union acpi_object
*wifi_pkg
, *data
, *flags
;
842 int i
, j
, ret
, tbl_rev
, num_sub_bands
= 0;
845 data
= iwl_acpi_get_object(fwrt
->dev
, ACPI_PPAG_METHOD
);
847 return PTR_ERR(data
);
849 /* try to read ppag table rev 3, 2 or 1 (all have the same data size) */
850 wifi_pkg
= iwl_acpi_get_wifi_pkg(fwrt
->dev
, data
,
851 ACPI_PPAG_WIFI_DATA_SIZE_V2
, &tbl_rev
);
853 if (!IS_ERR(wifi_pkg
)) {
854 if (tbl_rev
>= 1 && tbl_rev
<= 3) {
855 num_sub_bands
= IWL_NUM_SUB_BANDS_V2
;
856 IWL_DEBUG_RADIO(fwrt
,
857 "Reading PPAG table (tbl_rev=%d)\n",
866 /* try to read ppag table revision 0 */
867 wifi_pkg
= iwl_acpi_get_wifi_pkg(fwrt
->dev
, data
,
868 ACPI_PPAG_WIFI_DATA_SIZE_V1
, &tbl_rev
);
870 if (!IS_ERR(wifi_pkg
)) {
875 num_sub_bands
= IWL_NUM_SUB_BANDS_V1
;
876 IWL_DEBUG_RADIO(fwrt
, "Reading PPAG table v1 (tbl_rev=0)\n");
880 ret
= PTR_ERR(wifi_pkg
);
884 fwrt
->ppag_ver
= tbl_rev
;
885 flags
= &wifi_pkg
->package
.elements
[1];
887 if (flags
->type
!= ACPI_TYPE_INTEGER
) {
892 fwrt
->ppag_flags
= iwl_bios_get_ppag_flags(flags
->integer
.value
,
896 * read, verify gain values and save them into the PPAG table.
897 * first sub-band (j=0) corresponds to Low-Band (2.4GHz), and the
898 * following sub-bands to High-Band (5GHz).
900 for (i
= 0; i
< IWL_NUM_CHAIN_LIMITS
; i
++) {
901 for (j
= 0; j
< num_sub_bands
; j
++) {
902 union acpi_object
*ent
;
904 ent
= &wifi_pkg
->package
.elements
[idx
++];
905 if (ent
->type
!= ACPI_TYPE_INTEGER
) {
910 fwrt
->ppag_chains
[i
].subbands
[j
] = ent
->integer
.value
;
921 void iwl_acpi_get_phy_filters(struct iwl_fw_runtime
*fwrt
,
922 struct iwl_phy_specific_cfg
*filters
)
924 struct iwl_phy_specific_cfg tmp
= {};
925 union acpi_object
*wifi_pkg
, *data
;
928 data
= iwl_acpi_get_object(fwrt
->dev
, ACPI_WPFC_METHOD
);
932 wifi_pkg
= iwl_acpi_get_wifi_pkg(fwrt
->dev
, data
,
933 ACPI_WPFC_WIFI_DATA_SIZE
,
935 if (IS_ERR(wifi_pkg
))
941 BUILD_BUG_ON(ARRAY_SIZE(filters
->filter_cfg_chains
) !=
942 ACPI_WPFC_WIFI_DATA_SIZE
- 1);
944 for (i
= 0; i
< ARRAY_SIZE(filters
->filter_cfg_chains
); i
++) {
945 if (wifi_pkg
->package
.elements
[i
+ 1].type
!= ACPI_TYPE_INTEGER
)
947 tmp
.filter_cfg_chains
[i
] =
948 cpu_to_le32(wifi_pkg
->package
.elements
[i
+ 1].integer
.value
);
951 IWL_DEBUG_RADIO(fwrt
, "Loaded WPFC filter config from ACPI\n");
956 IWL_EXPORT_SYMBOL(iwl_acpi_get_phy_filters
);
958 void iwl_acpi_get_guid_lock_status(struct iwl_fw_runtime
*fwrt
)
960 union acpi_object
*wifi_pkg
, *data
;
963 data
= iwl_acpi_get_object(fwrt
->dev
, ACPI_GLAI_METHOD
);
967 wifi_pkg
= iwl_acpi_get_wifi_pkg(fwrt
->dev
, data
,
968 ACPI_GLAI_WIFI_DATA_SIZE
,
970 if (IS_ERR(wifi_pkg
))
974 IWL_DEBUG_RADIO(fwrt
, "Invalid GLAI revision: %d\n", tbl_rev
);
978 if (wifi_pkg
->package
.elements
[1].type
!= ACPI_TYPE_INTEGER
||
979 wifi_pkg
->package
.elements
[1].integer
.value
> ACPI_GLAI_MAX_STATUS
)
982 fwrt
->uefi_tables_lock_status
=
983 wifi_pkg
->package
.elements
[1].integer
.value
;
985 IWL_DEBUG_RADIO(fwrt
,
986 "Loaded UEFI WIFI GUID lock status: %d from ACPI\n",
987 fwrt
->uefi_tables_lock_status
);
991 IWL_EXPORT_SYMBOL(iwl_acpi_get_guid_lock_status
);
993 int iwl_acpi_get_wbem(struct iwl_fw_runtime
*fwrt
, u32
*value
)
995 union acpi_object
*wifi_pkg
, *data
;
999 data
= iwl_acpi_get_object(fwrt
->dev
, ACPI_WBEM_METHOD
);
1003 wifi_pkg
= iwl_acpi_get_wifi_pkg(fwrt
->dev
, data
,
1004 ACPI_WBEM_WIFI_DATA_SIZE
,
1006 if (IS_ERR(wifi_pkg
))
1009 if (tbl_rev
!= IWL_ACPI_WBEM_REVISION
) {
1010 IWL_DEBUG_RADIO(fwrt
, "Unsupported ACPI WBEM revision:%d\n",
1015 if (wifi_pkg
->package
.elements
[1].type
!= ACPI_TYPE_INTEGER
)
1018 *value
= wifi_pkg
->package
.elements
[1].integer
.value
&
1019 IWL_ACPI_WBEM_REV0_MASK
;
1020 IWL_DEBUG_RADIO(fwrt
, "Loaded WBEM config from ACPI\n");