xref: /linux/drivers/net/wireless/intel/iwlwifi/fw/acpi.c (revision 91ec2035134982b98fab0609a9fd8480e8217dc1)
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