1 // SPDX-License-Identifier: GPL-2.0 OR BSD-3-Clause
2 /*
3 * Copyright (C) 2017 Intel Deutschland GmbH
4 * Copyright (C) 2019-2026 Intel Corporation
5 */
6 #include <linux/uuid.h>
7 #include "iwl-drv.h"
8 #include "iwl-debug.h"
9 #include "acpi.h"
10 #include "fw/runtime.h"
11
12 static const guid_t iwl_guid = GUID_INIT(0xF21202BF, 0x8F78, 0x4DC6,
13 0xA5, 0xB3, 0x1F, 0x73,
14 0x8E, 0x28, 0x5A, 0xDE);
15
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 */
23 [5] = (size_t)0,
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),
31 [DSM_FUNC_ENABLE_UNII_9] = sizeof(u32),
32 [DSM_FUNC_ENABLE_11BN] = sizeof(u32),
33 };
34
iwl_acpi_get_handle(struct device * dev,acpi_string method,acpi_handle * ret_handle)35 static int iwl_acpi_get_handle(struct device *dev, acpi_string method,
36 acpi_handle *ret_handle)
37 {
38 acpi_handle root_handle;
39 acpi_status status;
40
41 root_handle = ACPI_HANDLE(dev);
42 if (!root_handle) {
43 IWL_DEBUG_DEV_RADIO(dev,
44 "ACPI: Could not retrieve root port handle\n");
45 return -ENOENT;
46 }
47
48 status = acpi_get_handle(root_handle, method, ret_handle);
49 if (ACPI_FAILURE(status)) {
50 IWL_DEBUG_DEV_RADIO(dev,
51 "ACPI: %s method not found\n", method);
52 return -ENOENT;
53 }
54 return 0;
55 }
56
iwl_acpi_get_object(struct device * dev,acpi_string method)57 static void *iwl_acpi_get_object(struct device *dev, acpi_string method)
58 {
59 struct acpi_buffer buf = {ACPI_ALLOCATE_BUFFER, NULL};
60 acpi_handle handle;
61 acpi_status status;
62 int ret;
63
64 ret = iwl_acpi_get_handle(dev, method, &handle);
65 if (ret)
66 return ERR_PTR(-ENOENT);
67
68 /* Call the method with no arguments */
69 status = acpi_evaluate_object(handle, NULL, NULL, &buf);
70 if (ACPI_FAILURE(status)) {
71 IWL_DEBUG_DEV_RADIO(dev,
72 "ACPI: %s method invocation failed (status: 0x%x)\n",
73 method, status);
74 return ERR_PTR(-ENOENT);
75 }
76 return buf.pointer;
77 }
78
79 /*
80 * Generic function for evaluating a method defined in the device specific
81 * method (DSM) interface. The returned acpi object must be freed by calling
82 * function.
83 */
iwl_acpi_get_dsm_object(struct device * dev,int rev,int func,union acpi_object * args,const guid_t * guid)84 union acpi_object *iwl_acpi_get_dsm_object(struct device *dev, int rev,
85 int func, union acpi_object *args,
86 const guid_t *guid)
87 {
88 union acpi_object *obj;
89
90 obj = acpi_evaluate_dsm(ACPI_HANDLE(dev), guid, rev, func,
91 args);
92 if (!obj) {
93 IWL_DEBUG_DEV_RADIO(dev,
94 "ACPI: DSM method invocation failed (rev: %d, func:%d)\n",
95 rev, func);
96 return ERR_PTR(-ENOENT);
97 }
98 return obj;
99 }
100
101 /*
102 * Generic function to evaluate a DSM with no arguments
103 * and an integer return value,
104 * (as an integer object or inside a buffer object),
105 * verify and assign the value in the "value" parameter.
106 * return 0 in success and the appropriate errno otherwise.
107 */
iwl_acpi_get_dsm_integer(struct device * dev,int rev,int func,const guid_t * guid,u64 * value,size_t expected_size)108 static int iwl_acpi_get_dsm_integer(struct device *dev, int rev, int func,
109 const guid_t *guid, u64 *value,
110 size_t expected_size)
111 {
112 union acpi_object *obj;
113 int ret;
114
115 obj = iwl_acpi_get_dsm_object(dev, rev, func, NULL, guid);
116 if (IS_ERR(obj)) {
117 IWL_DEBUG_DEV_RADIO(dev,
118 "Failed to get DSM object. func= %d\n",
119 func);
120 return -ENOENT;
121 }
122
123 if (obj->type == ACPI_TYPE_INTEGER) {
124 *value = obj->integer.value;
125 } else if (obj->type == ACPI_TYPE_BUFFER) {
126 __le64 le_value = 0;
127
128 if (WARN_ON_ONCE(expected_size > sizeof(le_value))) {
129 ret = -EINVAL;
130 goto out;
131 }
132
133 /* if the buffer size doesn't match the expected size */
134 if (obj->buffer.length != expected_size)
135 IWL_DEBUG_DEV_RADIO(dev,
136 "ACPI: DSM invalid buffer size, padding or truncating (%d)\n",
137 obj->buffer.length);
138
139 /* assuming LE from Intel BIOS spec */
140 memcpy(&le_value, obj->buffer.pointer,
141 min_t(size_t, expected_size, (size_t)obj->buffer.length));
142 *value = le64_to_cpu(le_value);
143 } else {
144 IWL_DEBUG_DEV_RADIO(dev,
145 "ACPI: DSM method did not return a valid object, type=%d\n",
146 obj->type);
147 ret = -EINVAL;
148 goto out;
149 }
150
151 IWL_DEBUG_DEV_RADIO(dev,
152 "ACPI: DSM method evaluated: func=%d, value=%lld\n",
153 func, *value);
154 ret = 0;
155 out:
156 ACPI_FREE(obj);
157 return ret;
158 }
159
160 /*
161 * This function loads all the DSM functions, it checks the size and populates
162 * the cache with the values in a 32-bit field.
163 * In case the expected size is smaller than 32-bit, padding will be added.
164 */
iwl_acpi_load_dsm_values(struct iwl_fw_runtime * fwrt)165 static int iwl_acpi_load_dsm_values(struct iwl_fw_runtime *fwrt)
166 {
167 u64 query_func_val;
168 int ret;
169
170 BUILD_BUG_ON(ARRAY_SIZE(acpi_dsm_size) != DSM_FUNC_NUM_FUNCS);
171
172 ret = iwl_acpi_get_dsm_integer(fwrt->dev, ACPI_DSM_REV,
173 DSM_FUNC_QUERY,
174 &iwl_guid, &query_func_val,
175 acpi_dsm_size[DSM_FUNC_QUERY]);
176
177 if (ret) {
178 IWL_DEBUG_RADIO(fwrt, "ACPI QUERY FUNC not valid: %d\n", ret);
179 return ret;
180 }
181
182 fwrt->dsm_revision = ACPI_DSM_REV;
183 fwrt->dsm_source = BIOS_SOURCE_ACPI;
184 fwrt->dsm_values[DSM_FUNC_QUERY] = (u32)query_func_val;
185
186 IWL_DEBUG_RADIO(fwrt, "ACPI DSM validity bitmap 0x%x\n",
187 (u32)query_func_val);
188
189 /* DSM_FUNC_QUERY is 0, start from 1 */
190 for (int func = 1; func < ARRAY_SIZE(fwrt->dsm_values); func++) {
191 size_t expected_size = acpi_dsm_size[func];
192 u64 tmp;
193
194 if (!(query_func_val & BIT(func))) {
195 IWL_DEBUG_RADIO(fwrt,
196 "ACPI DSM %d not indicated as valid\n",
197 func);
198 continue;
199 }
200
201 /* This is an invalid function (5 for example) */
202 if (!expected_size)
203 continue;
204
205 /* Currently all ACPI DSMs are either 8-bit or 32-bit */
206 if (expected_size != sizeof(u8) && expected_size != sizeof(u32))
207 continue;
208
209 ret = iwl_acpi_get_dsm_integer(fwrt->dev, ACPI_DSM_REV, func,
210 &iwl_guid, &tmp, expected_size);
211 if (ret)
212 continue;
213
214 if ((expected_size == sizeof(u8) && tmp != (u8)tmp) ||
215 (expected_size == sizeof(u32) && tmp != (u32)tmp))
216 IWL_DEBUG_RADIO(fwrt,
217 "DSM value overflows the expected size, truncating\n");
218 fwrt->dsm_values[func] = (u32)tmp;
219 fwrt->dsm_funcs_valid |= BIT(func);
220 }
221
222 return 0;
223 }
224
225 /*
226 * This function receives a DSM function number, calculates its expected size
227 * according to Intel BIOS spec, and fills in the value in a 32-bit field.
228 * In case the expected size is smaller than 32-bit, padding will be added.
229 */
iwl_acpi_get_dsm(struct iwl_fw_runtime * fwrt,enum iwl_dsm_funcs func,u32 * value)230 int iwl_acpi_get_dsm(struct iwl_fw_runtime *fwrt,
231 enum iwl_dsm_funcs func, u32 *value)
232 {
233 if (!fwrt->dsm_funcs_valid) {
234 int ret = iwl_acpi_load_dsm_values(fwrt);
235
236 /*
237 * Always set the valid bit for DSM_FUNC_QUERY so that even if
238 * DSM_FUNC_QUERY returns 0 (no DSM function is valid), we will
239 * still consider the cache as valid.
240 */
241 fwrt->dsm_funcs_valid |= BIT(DSM_FUNC_QUERY);
242
243 if (ret)
244 return ret;
245 }
246
247 BUILD_BUG_ON(ARRAY_SIZE(fwrt->dsm_values) != DSM_FUNC_NUM_FUNCS);
248 BUILD_BUG_ON(BITS_PER_TYPE(fwrt->dsm_funcs_valid) < DSM_FUNC_NUM_FUNCS);
249
250 if (WARN_ON(func >= ARRAY_SIZE(fwrt->dsm_values)))
251 return -EINVAL;
252
253 if (!(fwrt->dsm_funcs_valid & BIT(func))) {
254 IWL_DEBUG_RADIO(fwrt, "ACPI DSM %d not indicated as valid\n",
255 func);
256 return -ENODATA;
257 }
258
259 *value = fwrt->dsm_values[func];
260
261 return 0;
262 }
263
264 static union acpi_object *
iwl_acpi_get_wifi_pkg_range(struct device * dev,union acpi_object * data,int min_data_size,int max_data_size,int * tbl_rev)265 iwl_acpi_get_wifi_pkg_range(struct device *dev,
266 union acpi_object *data,
267 int min_data_size,
268 int max_data_size,
269 int *tbl_rev)
270 {
271 int i;
272 union acpi_object *wifi_pkg;
273
274 /*
275 * We need at least one entry in the wifi package that
276 * describes the domain, and one more entry, otherwise there's
277 * no point in reading it.
278 */
279 if (WARN_ON_ONCE(min_data_size < 2 || min_data_size > max_data_size))
280 return ERR_PTR(-EINVAL);
281
282 /*
283 * We need at least two packages, one for the revision and one
284 * for the data itself. Also check that the revision is valid
285 * (i.e. it is an integer (each caller has to check by itself
286 * if the returned revision is supported)).
287 */
288 if (data->type != ACPI_TYPE_PACKAGE ||
289 data->package.count < 2 ||
290 data->package.elements[0].type != ACPI_TYPE_INTEGER) {
291 IWL_DEBUG_DEV_RADIO(dev, "Invalid packages structure\n");
292 return ERR_PTR(-EINVAL);
293 }
294
295 *tbl_rev = data->package.elements[0].integer.value;
296
297 /* loop through all the packages to find the one for WiFi */
298 for (i = 1; i < data->package.count; i++) {
299 union acpi_object *domain;
300
301 wifi_pkg = &data->package.elements[i];
302
303 /* skip entries that are not a package with the right size */
304 if (wifi_pkg->type != ACPI_TYPE_PACKAGE ||
305 wifi_pkg->package.count < min_data_size ||
306 wifi_pkg->package.count > max_data_size)
307 continue;
308
309 domain = &wifi_pkg->package.elements[0];
310 if (domain->type == ACPI_TYPE_INTEGER &&
311 domain->integer.value == ACPI_WIFI_DOMAIN)
312 goto found;
313 }
314
315 return ERR_PTR(-ENOENT);
316
317 found:
318 return wifi_pkg;
319 }
320
321 static union acpi_object *
iwl_acpi_get_wifi_pkg(struct device * dev,union acpi_object * data,int data_size,int * tbl_rev)322 iwl_acpi_get_wifi_pkg(struct device *dev,
323 union acpi_object *data,
324 int data_size, int *tbl_rev)
325 {
326 return iwl_acpi_get_wifi_pkg_range(dev, data, data_size, data_size,
327 tbl_rev);
328 }
329
iwl_acpi_get_tas_table(struct iwl_fw_runtime * fwrt,struct iwl_tas_data * tas_data)330 int iwl_acpi_get_tas_table(struct iwl_fw_runtime *fwrt,
331 struct iwl_tas_data *tas_data)
332 {
333 union acpi_object *wifi_pkg, *data;
334 int ret, tbl_rev, block_list_size, enabled;
335 u32 tas_selection;
336
337 data = iwl_acpi_get_object(fwrt->dev, ACPI_WTAS_METHOD);
338 if (IS_ERR(data))
339 return PTR_ERR(data);
340
341 /* try to read wtas table */
342 wifi_pkg = iwl_acpi_get_wifi_pkg(fwrt->dev, data,
343 ACPI_WTAS_WIFI_DATA_SIZE,
344 &tbl_rev);
345 if (IS_ERR(wifi_pkg)) {
346 ret = PTR_ERR(wifi_pkg);
347 goto out_free;
348 }
349
350 if (tbl_rev < 0 || tbl_rev > 2 ||
351 wifi_pkg->package.elements[1].type != ACPI_TYPE_INTEGER) {
352 ret = -EINVAL;
353 goto out_free;
354 }
355
356 tas_selection = (u32)wifi_pkg->package.elements[1].integer.value;
357 enabled = tas_selection & IWL_WTAS_ENABLED_MSK;
358
359 IWL_DEBUG_RADIO(fwrt, "TAS selection as read from BIOS: 0x%x\n",
360 tas_selection);
361 tas_data->table_source = BIOS_SOURCE_ACPI;
362 tas_data->table_revision = tbl_rev;
363 tas_data->tas_selection = tas_selection;
364
365 IWL_DEBUG_RADIO(fwrt, "TAS %s enabled\n",
366 enabled ? "is" : "not");
367
368 IWL_DEBUG_RADIO(fwrt, "Reading TAS table revision %d\n", tbl_rev);
369 if (wifi_pkg->package.elements[2].type != ACPI_TYPE_INTEGER ||
370 wifi_pkg->package.elements[2].integer.value >
371 IWL_WTAS_BLACK_LIST_MAX) {
372 IWL_DEBUG_RADIO(fwrt, "TAS invalid array size %llu\n",
373 wifi_pkg->package.elements[2].integer.value);
374 ret = -EINVAL;
375 goto out_free;
376 }
377
378 block_list_size = wifi_pkg->package.elements[2].integer.value;
379 tas_data->block_list_size = block_list_size;
380
381 IWL_DEBUG_RADIO(fwrt, "TAS array size %u\n", block_list_size);
382
383 for (int i = 0; i < block_list_size; i++) {
384 u16 country;
385
386 if (wifi_pkg->package.elements[3 + i].type !=
387 ACPI_TYPE_INTEGER) {
388 IWL_DEBUG_RADIO(fwrt,
389 "TAS invalid array elem %d\n", 3 + i);
390 ret = -EINVAL;
391 goto out_free;
392 }
393
394 country = wifi_pkg->package.elements[3 + i].integer.value;
395 tas_data->block_list_array[i] = country;
396 IWL_DEBUG_RADIO(fwrt, "TAS block list country %d\n", country);
397 }
398
399 ret = enabled;
400 out_free:
401 kfree(data);
402 return ret;
403 }
404
iwl_acpi_get_mcc(struct iwl_fw_runtime * fwrt,char * mcc)405 int iwl_acpi_get_mcc(struct iwl_fw_runtime *fwrt, char *mcc)
406 {
407 union acpi_object *wifi_pkg, *data;
408 u32 mcc_val;
409 int ret, tbl_rev;
410
411 data = iwl_acpi_get_object(fwrt->dev, ACPI_WRDD_METHOD);
412 if (IS_ERR(data))
413 return PTR_ERR(data);
414
415 wifi_pkg = iwl_acpi_get_wifi_pkg(fwrt->dev, data,
416 ACPI_WRDD_WIFI_DATA_SIZE,
417 &tbl_rev);
418 if (IS_ERR(wifi_pkg)) {
419 ret = PTR_ERR(wifi_pkg);
420 goto out_free;
421 }
422
423 if (wifi_pkg->package.elements[1].type != ACPI_TYPE_INTEGER ||
424 tbl_rev != 0) {
425 ret = -EINVAL;
426 goto out_free;
427 }
428
429 mcc_val = wifi_pkg->package.elements[1].integer.value;
430 if (mcc_val != BIOS_MCC_CHINA) {
431 ret = -EINVAL;
432 IWL_DEBUG_RADIO(fwrt, "ACPI WRDD is supported only for CN\n");
433 goto out_free;
434 }
435
436 mcc[0] = (mcc_val >> 8) & 0xff;
437 mcc[1] = mcc_val & 0xff;
438 mcc[2] = '\0';
439
440 ret = 0;
441 out_free:
442 kfree(data);
443 return ret;
444 }
445
iwl_acpi_get_pwr_limit(struct iwl_fw_runtime * fwrt,u64 * dflt_pwr_limit)446 int iwl_acpi_get_pwr_limit(struct iwl_fw_runtime *fwrt, u64 *dflt_pwr_limit)
447 {
448 union acpi_object *data, *wifi_pkg;
449 int tbl_rev, ret = -EINVAL;
450
451 *dflt_pwr_limit = 0;
452 data = iwl_acpi_get_object(fwrt->dev, ACPI_SPLC_METHOD);
453 if (IS_ERR(data))
454 goto out;
455
456 wifi_pkg = iwl_acpi_get_wifi_pkg(fwrt->dev, data,
457 ACPI_SPLC_WIFI_DATA_SIZE, &tbl_rev);
458 if (IS_ERR(wifi_pkg) || tbl_rev != 0 ||
459 wifi_pkg->package.elements[1].integer.value != ACPI_TYPE_INTEGER)
460 goto out_free;
461
462 *dflt_pwr_limit = wifi_pkg->package.elements[1].integer.value;
463 ret = 0;
464 out_free:
465 kfree(data);
466 out:
467 return ret;
468 }
469
iwl_acpi_get_eckv(struct iwl_fw_runtime * fwrt,u32 * extl_clk)470 int iwl_acpi_get_eckv(struct iwl_fw_runtime *fwrt, u32 *extl_clk)
471 {
472 union acpi_object *wifi_pkg, *data;
473 int ret, tbl_rev;
474
475 data = iwl_acpi_get_object(fwrt->dev, ACPI_ECKV_METHOD);
476 if (IS_ERR(data))
477 return PTR_ERR(data);
478
479 wifi_pkg = iwl_acpi_get_wifi_pkg(fwrt->dev, data,
480 ACPI_ECKV_WIFI_DATA_SIZE,
481 &tbl_rev);
482 if (IS_ERR(wifi_pkg)) {
483 ret = PTR_ERR(wifi_pkg);
484 goto out_free;
485 }
486
487 if (wifi_pkg->package.elements[1].type != ACPI_TYPE_INTEGER ||
488 tbl_rev != 0) {
489 ret = -EINVAL;
490 goto out_free;
491 }
492
493 *extl_clk = wifi_pkg->package.elements[1].integer.value;
494
495 ret = 0;
496
497 out_free:
498 kfree(data);
499 return ret;
500 }
501
502 static int
iwl_acpi_parse_chains_table(union acpi_object * table,struct iwl_sar_profile_chain * chains,u8 num_chains,u8 num_sub_bands)503 iwl_acpi_parse_chains_table(union acpi_object *table,
504 struct iwl_sar_profile_chain *chains,
505 u8 num_chains, u8 num_sub_bands)
506 {
507 for (u8 chain = 0; chain < num_chains; chain++) {
508 for (u8 subband = 0;
509 subband < ARRAY_SIZE(chains[chain].subbands);
510 subband++) {
511 /* if we don't have the values, use the default */
512 if (subband >= num_sub_bands) {
513 chains[chain].subbands[subband] = 0;
514 } else if (table->type != ACPI_TYPE_INTEGER ||
515 table->integer.value > U8_MAX) {
516 return -EINVAL;
517 } else {
518 chains[chain].subbands[subband] =
519 table->integer.value;
520 table++;
521 }
522 }
523 }
524
525 return 0;
526 }
527
iwl_acpi_get_wrds_table(struct iwl_fw_runtime * fwrt)528 int iwl_acpi_get_wrds_table(struct iwl_fw_runtime *fwrt)
529 {
530 union acpi_object *wifi_pkg, *table, *data;
531 int ret, tbl_rev;
532 u32 flags;
533 u8 num_chains, num_sub_bands;
534
535 data = iwl_acpi_get_object(fwrt->dev, ACPI_WRDS_METHOD);
536 if (IS_ERR(data))
537 return PTR_ERR(data);
538
539 /* start by trying to read revision 3 */
540 wifi_pkg = iwl_acpi_get_wifi_pkg(fwrt->dev, data,
541 ACPI_WRDS_WIFI_DATA_SIZE_REV3,
542 &tbl_rev);
543 if (!IS_ERR(wifi_pkg)) {
544 if (tbl_rev != 3) {
545 ret = -EINVAL;
546 goto out_free;
547 }
548
549 num_chains = ACPI_SAR_NUM_CHAINS_REV2;
550 num_sub_bands = ACPI_SAR_NUM_SUB_BANDS_REV3;
551
552 goto read_table;
553 }
554
555 /* then try revision 2 */
556 wifi_pkg = iwl_acpi_get_wifi_pkg(fwrt->dev, data,
557 ACPI_WRDS_WIFI_DATA_SIZE_REV2,
558 &tbl_rev);
559 if (!IS_ERR(wifi_pkg)) {
560 if (tbl_rev != 2) {
561 ret = -EINVAL;
562 goto out_free;
563 }
564
565 num_chains = ACPI_SAR_NUM_CHAINS_REV2;
566 num_sub_bands = ACPI_SAR_NUM_SUB_BANDS_REV2;
567
568 goto read_table;
569 }
570
571 /* then try revision 1 */
572 wifi_pkg = iwl_acpi_get_wifi_pkg(fwrt->dev, data,
573 ACPI_WRDS_WIFI_DATA_SIZE_REV1,
574 &tbl_rev);
575 if (!IS_ERR(wifi_pkg)) {
576 if (tbl_rev != 1) {
577 ret = -EINVAL;
578 goto out_free;
579 }
580
581 num_chains = ACPI_SAR_NUM_CHAINS_REV1;
582 num_sub_bands = ACPI_SAR_NUM_SUB_BANDS_REV1;
583
584 goto read_table;
585 }
586
587 /* then finally revision 0 */
588 wifi_pkg = iwl_acpi_get_wifi_pkg(fwrt->dev, data,
589 ACPI_WRDS_WIFI_DATA_SIZE_REV0,
590 &tbl_rev);
591 if (!IS_ERR(wifi_pkg)) {
592 if (tbl_rev != 0) {
593 ret = -EINVAL;
594 goto out_free;
595 }
596
597 num_chains = ACPI_SAR_NUM_CHAINS_REV0;
598 num_sub_bands = ACPI_SAR_NUM_SUB_BANDS_REV0;
599
600 goto read_table;
601 }
602
603 ret = PTR_ERR(wifi_pkg);
604 goto out_free;
605
606 read_table:
607 if (wifi_pkg->package.elements[1].type != ACPI_TYPE_INTEGER) {
608 ret = -EINVAL;
609 goto out_free;
610 }
611
612 if (WARN_ON(num_chains * num_sub_bands >
613 ARRAY_SIZE(fwrt->sar_profiles[0].chains) *
614 ARRAY_SIZE(fwrt->sar_profiles[0].chains[0].subbands))) {
615 ret = -EINVAL;
616 goto out_free;
617 }
618
619 IWL_DEBUG_RADIO(fwrt, "Reading WRDS tbl_rev=%d\n", tbl_rev);
620
621 flags = wifi_pkg->package.elements[1].integer.value;
622 fwrt->reduced_power_flags = flags >> IWL_REDUCE_POWER_FLAGS_POS;
623
624 /* position of the actual table */
625 table = &wifi_pkg->package.elements[2];
626
627 /* The profile from WRDS is officially profile 1, but goes
628 * into sar_profiles[0] (because we don't have a profile 0).
629 */
630 ret = iwl_acpi_parse_chains_table(table, fwrt->sar_profiles[0].chains,
631 num_chains, num_sub_bands);
632 if (!ret && flags & IWL_SAR_ENABLE_MSK)
633 fwrt->sar_profiles[0].enabled = true;
634
635 out_free:
636 kfree(data);
637 return ret;
638 }
639
iwl_acpi_get_ewrd_table(struct iwl_fw_runtime * fwrt)640 int iwl_acpi_get_ewrd_table(struct iwl_fw_runtime *fwrt)
641 {
642 union acpi_object *wifi_pkg, *data;
643 bool enabled;
644 int i, n_profiles, tbl_rev, pos;
645 int ret = 0;
646 u8 num_sub_bands;
647
648 data = iwl_acpi_get_object(fwrt->dev, ACPI_EWRD_METHOD);
649 if (IS_ERR(data))
650 return PTR_ERR(data);
651
652 /* start by trying to read revision 3 */
653 wifi_pkg = iwl_acpi_get_wifi_pkg(fwrt->dev, data,
654 ACPI_EWRD_WIFI_DATA_SIZE_REV3,
655 &tbl_rev);
656 if (!IS_ERR(wifi_pkg)) {
657 if (tbl_rev != 3) {
658 ret = -EINVAL;
659 goto out_free;
660 }
661
662 num_sub_bands = ACPI_SAR_NUM_SUB_BANDS_REV3;
663
664 goto read_table;
665 }
666
667 /* then try revision 2 */
668 wifi_pkg = iwl_acpi_get_wifi_pkg(fwrt->dev, data,
669 ACPI_EWRD_WIFI_DATA_SIZE_REV2,
670 &tbl_rev);
671 if (!IS_ERR(wifi_pkg)) {
672 if (tbl_rev != 2) {
673 ret = -EINVAL;
674 goto out_free;
675 }
676
677 num_sub_bands = ACPI_SAR_NUM_SUB_BANDS_REV2;
678
679 goto read_table;
680 }
681
682 /* then try revision 1 */
683 wifi_pkg = iwl_acpi_get_wifi_pkg(fwrt->dev, data,
684 ACPI_EWRD_WIFI_DATA_SIZE_REV1,
685 &tbl_rev);
686 if (!IS_ERR(wifi_pkg)) {
687 if (tbl_rev != 1) {
688 ret = -EINVAL;
689 goto out_free;
690 }
691
692 num_sub_bands = ACPI_SAR_NUM_SUB_BANDS_REV1;
693
694 goto read_table;
695 }
696
697 /* then finally revision 0 */
698 wifi_pkg = iwl_acpi_get_wifi_pkg(fwrt->dev, data,
699 ACPI_EWRD_WIFI_DATA_SIZE_REV0,
700 &tbl_rev);
701 if (!IS_ERR(wifi_pkg)) {
702 if (tbl_rev != 0) {
703 ret = -EINVAL;
704 goto out_free;
705 }
706
707 num_sub_bands = ACPI_SAR_NUM_SUB_BANDS_REV0;
708
709 goto read_table;
710 }
711
712 ret = PTR_ERR(wifi_pkg);
713 goto out_free;
714
715 read_table:
716 if (wifi_pkg->package.elements[1].type != ACPI_TYPE_INTEGER ||
717 wifi_pkg->package.elements[2].type != ACPI_TYPE_INTEGER) {
718 ret = -EINVAL;
719 goto out_free;
720 }
721
722 if (WARN_ON(ACPI_SAR_NUM_CHAINS_REV0 * num_sub_bands >
723 ARRAY_SIZE(fwrt->sar_profiles[0].chains) *
724 ARRAY_SIZE(fwrt->sar_profiles[0].chains[0].subbands))) {
725 ret = -EINVAL;
726 goto out_free;
727 }
728
729 enabled = !!(wifi_pkg->package.elements[1].integer.value);
730 n_profiles = wifi_pkg->package.elements[2].integer.value;
731
732 /*
733 * Check the validity of n_profiles. The EWRD profiles start
734 * from index 1, so the maximum value allowed here is
735 * ACPI_SAR_PROFILES_NUM - 1.
736 */
737 if (n_profiles >= BIOS_SAR_MAX_PROFILE_NUM) {
738 ret = -EINVAL;
739 goto out_free;
740 }
741
742 /* the tables start at element 3 */
743 pos = 3;
744
745 BUILD_BUG_ON(ACPI_SAR_NUM_CHAINS_REV0 != ACPI_SAR_NUM_CHAINS_REV1);
746 BUILD_BUG_ON(ACPI_SAR_NUM_CHAINS_REV2 != 2 * ACPI_SAR_NUM_CHAINS_REV0);
747
748 /* parse non-cdb chains for all profiles */
749 for (i = 0; i < n_profiles; i++) {
750 union acpi_object *table = &wifi_pkg->package.elements[pos];
751
752 /* The EWRD profiles officially go from 2 to 4, but we
753 * save them in sar_profiles[1-3] (because we don't
754 * have profile 0). So in the array we start from 1.
755 */
756 ret = iwl_acpi_parse_chains_table(table,
757 fwrt->sar_profiles[i + 1].chains,
758 ACPI_SAR_NUM_CHAINS_REV0,
759 num_sub_bands);
760 if (ret < 0)
761 goto out_free;
762
763 /* go to the next table */
764 pos += ACPI_SAR_NUM_CHAINS_REV0 * num_sub_bands;
765 }
766
767 /* non-cdb table revisions */
768 if (tbl_rev < 2)
769 goto set_enabled;
770
771 if (WARN_ON(ACPI_SAR_NUM_CHAINS_REV0 * 2 * num_sub_bands >
772 ARRAY_SIZE(fwrt->sar_profiles[0].chains) *
773 ARRAY_SIZE(fwrt->sar_profiles[0].chains[0].subbands))) {
774 ret = -EINVAL;
775 goto out_free;
776 }
777
778 /* parse cdb chains for all profiles */
779 for (i = 0; i < n_profiles; i++) {
780 struct iwl_sar_profile_chain *chains;
781 union acpi_object *table;
782
783 table = &wifi_pkg->package.elements[pos];
784 chains = &fwrt->sar_profiles[i + 1].chains[ACPI_SAR_NUM_CHAINS_REV0];
785 ret = iwl_acpi_parse_chains_table(table,
786 chains,
787 ACPI_SAR_NUM_CHAINS_REV0,
788 num_sub_bands);
789 if (ret < 0)
790 goto out_free;
791
792 /* go to the next table */
793 pos += ACPI_SAR_NUM_CHAINS_REV0 * num_sub_bands;
794 }
795
796 set_enabled:
797 for (i = 0; i < n_profiles; i++)
798 fwrt->sar_profiles[i + 1].enabled = enabled;
799
800 out_free:
801 kfree(data);
802 return ret;
803 }
804
iwl_acpi_get_wgds_table(struct iwl_fw_runtime * fwrt)805 int iwl_acpi_get_wgds_table(struct iwl_fw_runtime *fwrt)
806 {
807 union acpi_object *wifi_pkg, *data;
808 int i, j, k, ret, tbl_rev;
809 u8 num_bands, num_profiles;
810 static const struct {
811 u8 revisions;
812 u8 bands;
813 u8 profiles;
814 u8 min_profiles;
815 } rev_data[] = {
816 {
817 .revisions = BIT(4),
818 .bands = ACPI_GEO_NUM_BANDS_REV4,
819 .profiles = ACPI_NUM_GEO_PROFILES_REV3,
820 .min_profiles = BIOS_GEO_MIN_PROFILE_NUM,
821 },
822 {
823 .revisions = BIT(3),
824 .bands = ACPI_GEO_NUM_BANDS_REV2,
825 .profiles = ACPI_NUM_GEO_PROFILES_REV3,
826 .min_profiles = BIOS_GEO_MIN_PROFILE_NUM,
827 },
828 {
829 .revisions = BIT(2),
830 .bands = ACPI_GEO_NUM_BANDS_REV2,
831 .profiles = ACPI_NUM_GEO_PROFILES,
832 },
833 {
834 .revisions = BIT(0) | BIT(1),
835 .bands = ACPI_GEO_NUM_BANDS_REV0,
836 .profiles = ACPI_NUM_GEO_PROFILES,
837 },
838 };
839 int idx;
840 /* start from one to skip the domain */
841 int entry_idx = 1;
842
843 BUILD_BUG_ON(ACPI_NUM_GEO_PROFILES_REV3 != IWL_NUM_GEO_PROFILES_V3);
844 BUILD_BUG_ON(ACPI_NUM_GEO_PROFILES != IWL_NUM_GEO_PROFILES);
845
846 data = iwl_acpi_get_object(fwrt->dev, ACPI_WGDS_METHOD);
847 if (IS_ERR(data))
848 return PTR_ERR(data);
849
850 /* read the highest revision we understand first */
851 for (idx = 0; idx < ARRAY_SIZE(rev_data); idx++) {
852 /* min_profiles != 0 requires num_profiles header */
853 u32 hdr_size = 1 + !!rev_data[idx].min_profiles;
854 u32 profile_size = ACPI_GEO_PER_CHAIN_SIZE *
855 rev_data[idx].bands;
856 u32 max_size = hdr_size + profile_size * rev_data[idx].profiles;
857 u32 min_size;
858
859 if (!rev_data[idx].min_profiles)
860 min_size = max_size;
861 else
862 min_size = hdr_size +
863 profile_size * rev_data[idx].min_profiles;
864
865 wifi_pkg = iwl_acpi_get_wifi_pkg_range(fwrt->dev, data,
866 min_size, max_size,
867 &tbl_rev);
868 if (!IS_ERR(wifi_pkg)) {
869 if (tbl_rev < 0 ||
870 tbl_rev >= BITS_PER_BYTE *
871 sizeof(rev_data[idx].revisions))
872 continue;
873
874 if (!(BIT(tbl_rev) & rev_data[idx].revisions))
875 continue;
876
877 num_bands = rev_data[idx].bands;
878 num_profiles = rev_data[idx].profiles;
879
880 if (WARN_ON(num_profiles >
881 ARRAY_SIZE(fwrt->geo_profiles))) {
882 ret = -EINVAL;
883 goto out_free;
884 }
885
886 if (WARN_ON(num_bands >
887 ARRAY_SIZE(fwrt->geo_profiles[0].bands))) {
888 ret = -EINVAL;
889 goto out_free;
890 }
891
892 if (rev_data[idx].min_profiles) {
893 /* read header that says # of profiles */
894 union acpi_object *entry;
895
896 entry = &wifi_pkg->package.elements[entry_idx];
897 entry_idx++;
898 if (entry->type != ACPI_TYPE_INTEGER ||
899 entry->integer.value > num_profiles ||
900 entry->integer.value <
901 rev_data[idx].min_profiles) {
902 ret = -EINVAL;
903 goto out_free;
904 }
905
906 /*
907 * Check to see if we received package count
908 * same as max # of profiles
909 */
910 if (wifi_pkg->package.count !=
911 hdr_size + profile_size * num_profiles) {
912 ret = -EINVAL;
913 goto out_free;
914 }
915
916 /* Number of valid profiles */
917 num_profiles = entry->integer.value;
918 }
919 goto read_table;
920 }
921 }
922
923 if (idx < ARRAY_SIZE(rev_data))
924 ret = PTR_ERR(wifi_pkg);
925 else
926 ret = -ENOENT;
927 goto out_free;
928
929 read_table:
930 fwrt->geo_rev = tbl_rev;
931
932 for (i = 0; i < num_profiles; i++) {
933 struct iwl_geo_profile *prof = &fwrt->geo_profiles[i];
934
935 for (j = 0; j < ARRAY_SIZE(prof->bands); j++) {
936 union acpi_object *entry;
937
938 /*
939 * num_bands is either 2 or 3 or 4, if it's lower
940 * than 4, fill the third band (6 GHz) with the values
941 * from 5 GHz (second band)
942 */
943 if (j >= num_bands) {
944 prof->bands[j].max = prof->bands[1].max;
945 } else {
946 entry = &wifi_pkg->package.elements[entry_idx];
947 entry_idx++;
948 if (entry->type != ACPI_TYPE_INTEGER ||
949 entry->integer.value > U8_MAX) {
950 ret = -EINVAL;
951 goto out_free;
952 }
953
954 prof->bands[j].max =
955 entry->integer.value;
956 }
957
958 for (k = 0;
959 k < ARRAY_SIZE(prof->bands[0].chains);
960 k++) {
961 /* same here as above */
962 if (j >= num_bands) {
963 prof->bands[j].chains[k] =
964 prof->bands[1].chains[k];
965 } else {
966 entry = &wifi_pkg->package.elements[entry_idx];
967 entry_idx++;
968 if (entry->type != ACPI_TYPE_INTEGER ||
969 entry->integer.value > U8_MAX) {
970 ret = -EINVAL;
971 goto out_free;
972 }
973
974 prof->bands[j].chains[k] =
975 entry->integer.value;
976 }
977 }
978 }
979 }
980
981 fwrt->geo_num_profiles = num_profiles;
982 fwrt->geo_bios_source = BIOS_SOURCE_ACPI;
983 fwrt->geo_enabled = true;
984 ret = 0;
985 out_free:
986 kfree(data);
987 return ret;
988 }
989
iwl_acpi_get_ppag_table(struct iwl_fw_runtime * fwrt)990 int iwl_acpi_get_ppag_table(struct iwl_fw_runtime *fwrt)
991 {
992 union acpi_object *wifi_pkg, *data, *flags;
993 int i, j, ret, tbl_rev, num_sub_bands = 0;
994 int idx = 2;
995
996 data = iwl_acpi_get_object(fwrt->dev, ACPI_PPAG_METHOD);
997 if (IS_ERR(data))
998 return PTR_ERR(data);
999
1000 /* try to read ppag table rev 5 */
1001 wifi_pkg = iwl_acpi_get_wifi_pkg(fwrt->dev, data,
1002 ACPI_PPAG_WIFI_DATA_SIZE_V3, &tbl_rev);
1003 if (!IS_ERR(wifi_pkg)) {
1004 if (tbl_rev == 5) {
1005 num_sub_bands = IWL_NUM_SUB_BANDS_V3;
1006 IWL_DEBUG_RADIO(fwrt,
1007 "Reading PPAG table (tbl_rev=%d)\n",
1008 tbl_rev);
1009 goto read_table;
1010 } else {
1011 ret = -EINVAL;
1012 goto out_free;
1013 }
1014 }
1015
1016 /* try to read ppag table rev 1 to 4 (all have the same data size) */
1017 wifi_pkg = iwl_acpi_get_wifi_pkg(fwrt->dev, data,
1018 ACPI_PPAG_WIFI_DATA_SIZE_V2, &tbl_rev);
1019
1020 if (!IS_ERR(wifi_pkg)) {
1021 if (tbl_rev >= 1 && tbl_rev <= 4) {
1022 num_sub_bands = IWL_NUM_SUB_BANDS_V2;
1023 IWL_DEBUG_RADIO(fwrt,
1024 "Reading PPAG table (tbl_rev=%d)\n",
1025 tbl_rev);
1026 goto read_table;
1027 } else {
1028 ret = -EINVAL;
1029 goto out_free;
1030 }
1031 }
1032
1033 /* try to read ppag table revision 0 */
1034 wifi_pkg = iwl_acpi_get_wifi_pkg(fwrt->dev, data,
1035 ACPI_PPAG_WIFI_DATA_SIZE_V1, &tbl_rev);
1036
1037 if (!IS_ERR(wifi_pkg)) {
1038 if (tbl_rev != 0) {
1039 ret = -EINVAL;
1040 goto out_free;
1041 }
1042 num_sub_bands = IWL_NUM_SUB_BANDS_V1;
1043 IWL_DEBUG_RADIO(fwrt, "Reading PPAG table v1 (tbl_rev=0)\n");
1044 goto read_table;
1045 }
1046
1047 ret = PTR_ERR(wifi_pkg);
1048 goto out_free;
1049
1050 read_table:
1051 if (WARN_ON_ONCE(num_sub_bands >
1052 ARRAY_SIZE(fwrt->ppag_chains[0].subbands))) {
1053 ret = -EINVAL;
1054 goto out_free;
1055 }
1056
1057 BUILD_BUG_ON(ACPI_PPAG_NUM_CHAINS >
1058 ARRAY_SIZE(fwrt->ppag_chains));
1059
1060 fwrt->ppag_bios_rev = tbl_rev;
1061 flags = &wifi_pkg->package.elements[1];
1062
1063 if (flags->type != ACPI_TYPE_INTEGER) {
1064 ret = -EINVAL;
1065 goto out_free;
1066 }
1067
1068 fwrt->ppag_flags = iwl_bios_get_ppag_flags(flags->integer.value,
1069 fwrt->ppag_bios_rev);
1070
1071 /*
1072 * read, verify gain values and save them into the PPAG table.
1073 * first sub-band (j=0) corresponds to Low-Band (2.4GHz), and the
1074 * following sub-bands to High-Band (5GHz).
1075 */
1076 for (i = 0; i < ACPI_PPAG_NUM_CHAINS; i++) {
1077 for (j = 0; j < num_sub_bands; j++) {
1078 union acpi_object *ent;
1079
1080 ent = &wifi_pkg->package.elements[idx++];
1081 if (ent->type != ACPI_TYPE_INTEGER) {
1082 ret = -EINVAL;
1083 goto out_free;
1084 }
1085
1086 fwrt->ppag_chains[i].subbands[j] = ent->integer.value;
1087 }
1088 }
1089
1090 iwl_bios_print_ppag(fwrt, num_sub_bands);
1091 fwrt->ppag_bios_source = BIOS_SOURCE_ACPI;
1092 ret = 0;
1093
1094 out_free:
1095 kfree(data);
1096 return ret;
1097 }
1098
iwl_acpi_get_phy_filters(struct iwl_fw_runtime * fwrt)1099 int iwl_acpi_get_phy_filters(struct iwl_fw_runtime *fwrt)
1100 {
1101 struct iwl_phy_specific_cfg *filters = &fwrt->phy_filters;
1102 struct iwl_phy_specific_cfg tmp = {};
1103 union acpi_object *wifi_pkg, *data __free(kfree);
1104 int tbl_rev, i;
1105
1106 data = iwl_acpi_get_object(fwrt->dev, ACPI_WPFC_METHOD);
1107 if (IS_ERR(data))
1108 return PTR_ERR(data);
1109
1110 wifi_pkg = iwl_acpi_get_wifi_pkg(fwrt->dev, data,
1111 ACPI_WPFC_WIFI_DATA_SIZE,
1112 &tbl_rev);
1113 if (IS_ERR(wifi_pkg))
1114 return PTR_ERR(wifi_pkg);
1115
1116 if (tbl_rev != 0)
1117 return -EINVAL;
1118
1119 BUILD_BUG_ON(ARRAY_SIZE(filters->filter_cfg_chains) !=
1120 ACPI_WPFC_WIFI_DATA_SIZE - 1);
1121
1122 for (i = 0; i < ARRAY_SIZE(filters->filter_cfg_chains); i++) {
1123 if (wifi_pkg->package.elements[i + 1].type != ACPI_TYPE_INTEGER)
1124 return -EINVAL;
1125 tmp.filter_cfg_chains[i] =
1126 cpu_to_le32(wifi_pkg->package.elements[i + 1].integer.value);
1127 }
1128
1129 IWL_DEBUG_RADIO(fwrt, "Loaded WPFC filter config from ACPI\n");
1130 *filters = tmp;
1131 return 0;
1132 }
1133 IWL_EXPORT_SYMBOL(iwl_acpi_get_phy_filters);
1134
iwl_acpi_get_guid_lock_status(struct iwl_fw_runtime * fwrt)1135 void iwl_acpi_get_guid_lock_status(struct iwl_fw_runtime *fwrt)
1136 {
1137 union acpi_object *wifi_pkg, *data;
1138 int tbl_rev;
1139
1140 data = iwl_acpi_get_object(fwrt->dev, ACPI_GLAI_METHOD);
1141 if (IS_ERR(data))
1142 return;
1143
1144 wifi_pkg = iwl_acpi_get_wifi_pkg(fwrt->dev, data,
1145 ACPI_GLAI_WIFI_DATA_SIZE,
1146 &tbl_rev);
1147 if (IS_ERR(wifi_pkg))
1148 goto out_free;
1149
1150 if (tbl_rev != 0) {
1151 IWL_DEBUG_RADIO(fwrt, "Invalid GLAI revision: %d\n", tbl_rev);
1152 goto out_free;
1153 }
1154
1155 if (wifi_pkg->package.elements[1].type != ACPI_TYPE_INTEGER ||
1156 wifi_pkg->package.elements[1].integer.value > ACPI_GLAI_MAX_STATUS)
1157 goto out_free;
1158
1159 fwrt->uefi_tables_lock_status =
1160 wifi_pkg->package.elements[1].integer.value;
1161
1162 IWL_DEBUG_RADIO(fwrt,
1163 "Loaded UEFI WIFI GUID lock status: %d from ACPI\n",
1164 fwrt->uefi_tables_lock_status);
1165 out_free:
1166 kfree(data);
1167 }
1168 IWL_EXPORT_SYMBOL(iwl_acpi_get_guid_lock_status);
1169
iwl_acpi_get_wbem(struct iwl_fw_runtime * fwrt,u32 * value)1170 int iwl_acpi_get_wbem(struct iwl_fw_runtime *fwrt, u32 *value)
1171 {
1172 union acpi_object *wifi_pkg, *data;
1173 int ret = -ENOENT;
1174 int tbl_rev;
1175
1176 data = iwl_acpi_get_object(fwrt->dev, ACPI_WBEM_METHOD);
1177 if (IS_ERR(data))
1178 return ret;
1179
1180 wifi_pkg = iwl_acpi_get_wifi_pkg(fwrt->dev, data,
1181 ACPI_WBEM_WIFI_DATA_SIZE,
1182 &tbl_rev);
1183 if (IS_ERR(wifi_pkg))
1184 goto out_free;
1185
1186 if (tbl_rev != IWL_ACPI_WBEM_REVISION) {
1187 IWL_DEBUG_RADIO(fwrt, "Unsupported ACPI WBEM revision:%d\n",
1188 tbl_rev);
1189 goto out_free;
1190 }
1191
1192 if (wifi_pkg->package.elements[1].type != ACPI_TYPE_INTEGER)
1193 goto out_free;
1194
1195 *value = wifi_pkg->package.elements[1].integer.value &
1196 IWL_ACPI_WBEM_REV0_MASK;
1197 fwrt->wbem_source = BIOS_SOURCE_ACPI;
1198 fwrt->wbem_revision = tbl_rev;
1199 IWL_DEBUG_RADIO(fwrt, "Loaded WBEM config from ACPI\n");
1200 ret = 0;
1201 out_free:
1202 kfree(data);
1203 return ret;
1204 }
1205
iwl_acpi_get_dsbr(struct iwl_fw_runtime * fwrt,u32 * value)1206 int iwl_acpi_get_dsbr(struct iwl_fw_runtime *fwrt, u32 *value)
1207 {
1208 union acpi_object *wifi_pkg, *data;
1209 int ret = -ENOENT;
1210 int tbl_rev;
1211
1212 data = iwl_acpi_get_object(fwrt->dev, ACPI_DSBR_METHOD);
1213 if (IS_ERR(data))
1214 return ret;
1215
1216 wifi_pkg = iwl_acpi_get_wifi_pkg(fwrt->dev, data,
1217 ACPI_DSBR_WIFI_DATA_SIZE,
1218 &tbl_rev);
1219 if (IS_ERR(wifi_pkg))
1220 goto out_free;
1221
1222 if (tbl_rev != ACPI_DSBR_WIFI_DATA_REV) {
1223 IWL_DEBUG_RADIO(fwrt, "Unsupported ACPI DSBR revision:%d\n",
1224 tbl_rev);
1225 goto out_free;
1226 }
1227
1228 if (wifi_pkg->package.elements[1].type != ACPI_TYPE_INTEGER)
1229 goto out_free;
1230
1231 *value = wifi_pkg->package.elements[1].integer.value;
1232 IWL_DEBUG_RADIO(fwrt, "Loaded DSBR config from ACPI value: 0x%x\n",
1233 *value);
1234 ret = 0;
1235 out_free:
1236 kfree(data);
1237 return ret;
1238 }
1239