xref: /linux/drivers/net/wireless/intel/iwlwifi/fw/acpi.c (revision 37a93dd5c49b5fda807fd204edf2547c3493319c)
1 // SPDX-License-Identifier: GPL-2.0 OR BSD-3-Clause
2 /*
3  * Copyright (C) 2017 Intel Deutschland GmbH
4  * Copyright (C) 2019-2025 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 
185 	IWL_DEBUG_RADIO(fwrt, "ACPI DSM validity bitmap 0x%x\n",
186 			(u32)query_func_val);
187 
188 	/* DSM_FUNC_QUERY is 0, start from 1 */
189 	for (int func = 1; func < ARRAY_SIZE(fwrt->dsm_values); func++) {
190 		size_t expected_size = acpi_dsm_size[func];
191 		u64 tmp;
192 
193 		if (!(query_func_val & BIT(func))) {
194 			IWL_DEBUG_RADIO(fwrt,
195 					"ACPI DSM %d not indicated as valid\n",
196 					func);
197 			continue;
198 		}
199 
200 		/* This is an invalid function (5 for example) */
201 		if (!expected_size)
202 			continue;
203 
204 		/* Currently all ACPI DSMs are either 8-bit or 32-bit */
205 		if (expected_size != sizeof(u8) && expected_size != sizeof(u32))
206 			continue;
207 
208 		ret = iwl_acpi_get_dsm_integer(fwrt->dev, ACPI_DSM_REV, func,
209 					       &iwl_guid, &tmp, expected_size);
210 		if (ret)
211 			continue;
212 
213 		if ((expected_size == sizeof(u8) && tmp != (u8)tmp) ||
214 		    (expected_size == sizeof(u32) && tmp != (u32)tmp))
215 			IWL_DEBUG_RADIO(fwrt,
216 					"DSM value overflows the expected size, truncating\n");
217 		fwrt->dsm_values[func] = (u32)tmp;
218 		fwrt->dsm_funcs_valid |= BIT(func);
219 	}
220 
221 	return 0;
222 }
223 
224 /*
225  * This function receives a DSM function number, calculates its expected size
226  * according to Intel BIOS spec, and fills in the value in a 32-bit field.
227  * In case the expected size is smaller than 32-bit, padding will be added.
228  */
iwl_acpi_get_dsm(struct iwl_fw_runtime * fwrt,enum iwl_dsm_funcs func,u32 * value)229 int iwl_acpi_get_dsm(struct iwl_fw_runtime *fwrt,
230 		     enum iwl_dsm_funcs func, u32 *value)
231 {
232 	if (!fwrt->dsm_funcs_valid) {
233 		int ret = iwl_acpi_load_dsm_values(fwrt);
234 
235 		/*
236 		 * Always set the valid bit for DSM_FUNC_QUERY so that even if
237 		 * DSM_FUNC_QUERY returns 0 (no DSM function is valid), we will
238 		 * still consider the cache as valid.
239 		 */
240 		fwrt->dsm_funcs_valid |= BIT(DSM_FUNC_QUERY);
241 
242 		if (ret)
243 			return ret;
244 	}
245 
246 	BUILD_BUG_ON(ARRAY_SIZE(fwrt->dsm_values) != DSM_FUNC_NUM_FUNCS);
247 	BUILD_BUG_ON(BITS_PER_TYPE(fwrt->dsm_funcs_valid) < DSM_FUNC_NUM_FUNCS);
248 
249 	if (WARN_ON(func >= ARRAY_SIZE(fwrt->dsm_values) || !func))
250 		return -EINVAL;
251 
252 	if (!(fwrt->dsm_funcs_valid & BIT(func))) {
253 		IWL_DEBUG_RADIO(fwrt, "ACPI DSM %d not indicated as valid\n",
254 				func);
255 		return -ENODATA;
256 	}
257 
258 	*value = fwrt->dsm_values[func];
259 
260 	return 0;
261 }
262 
263 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)264 iwl_acpi_get_wifi_pkg_range(struct device *dev,
265 			    union acpi_object *data,
266 			    int min_data_size,
267 			    int max_data_size,
268 			    int *tbl_rev)
269 {
270 	int i;
271 	union acpi_object *wifi_pkg;
272 
273 	/*
274 	 * We need at least one entry in the wifi package that
275 	 * describes the domain, and one more entry, otherwise there's
276 	 * no point in reading it.
277 	 */
278 	if (WARN_ON_ONCE(min_data_size < 2 || min_data_size > max_data_size))
279 		return ERR_PTR(-EINVAL);
280 
281 	/*
282 	 * We need at least two packages, one for the revision and one
283 	 * for the data itself.  Also check that the revision is valid
284 	 * (i.e. it is an integer (each caller has to check by itself
285 	 * if the returned revision is supported)).
286 	 */
287 	if (data->type != ACPI_TYPE_PACKAGE ||
288 	    data->package.count < 2 ||
289 	    data->package.elements[0].type != ACPI_TYPE_INTEGER) {
290 		IWL_DEBUG_DEV_RADIO(dev, "Invalid packages structure\n");
291 		return ERR_PTR(-EINVAL);
292 	}
293 
294 	*tbl_rev = data->package.elements[0].integer.value;
295 
296 	/* loop through all the packages to find the one for WiFi */
297 	for (i = 1; i < data->package.count; i++) {
298 		union acpi_object *domain;
299 
300 		wifi_pkg = &data->package.elements[i];
301 
302 		/* skip entries that are not a package with the right size */
303 		if (wifi_pkg->type != ACPI_TYPE_PACKAGE ||
304 		    wifi_pkg->package.count < min_data_size ||
305 		    wifi_pkg->package.count > max_data_size)
306 			continue;
307 
308 		domain = &wifi_pkg->package.elements[0];
309 		if (domain->type == ACPI_TYPE_INTEGER &&
310 		    domain->integer.value == ACPI_WIFI_DOMAIN)
311 			goto found;
312 	}
313 
314 	return ERR_PTR(-ENOENT);
315 
316 found:
317 	return wifi_pkg;
318 }
319 
320 static union acpi_object *
iwl_acpi_get_wifi_pkg(struct device * dev,union acpi_object * data,int data_size,int * tbl_rev)321 iwl_acpi_get_wifi_pkg(struct device *dev,
322 		      union acpi_object *data,
323 		      int data_size, int *tbl_rev)
324 {
325 	return iwl_acpi_get_wifi_pkg_range(dev, data, data_size, data_size,
326 					   tbl_rev);
327 }
328 
iwl_acpi_get_tas_table(struct iwl_fw_runtime * fwrt,struct iwl_tas_data * tas_data)329 int iwl_acpi_get_tas_table(struct iwl_fw_runtime *fwrt,
330 			   struct iwl_tas_data *tas_data)
331 {
332 	union acpi_object *wifi_pkg, *data;
333 	int ret, tbl_rev, block_list_size, enabled;
334 	u32 tas_selection;
335 
336 	data = iwl_acpi_get_object(fwrt->dev, ACPI_WTAS_METHOD);
337 	if (IS_ERR(data))
338 		return PTR_ERR(data);
339 
340 	/* try to read wtas table */
341 	wifi_pkg = iwl_acpi_get_wifi_pkg(fwrt->dev, data,
342 					 ACPI_WTAS_WIFI_DATA_SIZE,
343 					 &tbl_rev);
344 	if (IS_ERR(wifi_pkg)) {
345 		ret = PTR_ERR(wifi_pkg);
346 		goto out_free;
347 	}
348 
349 	if (tbl_rev < 0 || tbl_rev > 2 ||
350 	    wifi_pkg->package.elements[1].type != ACPI_TYPE_INTEGER) {
351 		ret = -EINVAL;
352 		goto out_free;
353 	}
354 
355 	tas_selection = (u32)wifi_pkg->package.elements[1].integer.value;
356 	enabled = tas_selection & IWL_WTAS_ENABLED_MSK;
357 
358 	IWL_DEBUG_RADIO(fwrt, "TAS selection as read from BIOS: 0x%x\n",
359 			tas_selection);
360 	tas_data->table_source = BIOS_SOURCE_ACPI;
361 	tas_data->table_revision = tbl_rev;
362 	tas_data->tas_selection = tas_selection;
363 
364 	IWL_DEBUG_RADIO(fwrt, "TAS %s enabled\n",
365 			enabled ? "is" : "not");
366 
367 	IWL_DEBUG_RADIO(fwrt, "Reading TAS table revision %d\n", tbl_rev);
368 	if (wifi_pkg->package.elements[2].type != ACPI_TYPE_INTEGER ||
369 	    wifi_pkg->package.elements[2].integer.value >
370 	    IWL_WTAS_BLACK_LIST_MAX) {
371 		IWL_DEBUG_RADIO(fwrt, "TAS invalid array size %llu\n",
372 				wifi_pkg->package.elements[2].integer.value);
373 		ret = -EINVAL;
374 		goto out_free;
375 	}
376 
377 	block_list_size = wifi_pkg->package.elements[2].integer.value;
378 	tas_data->block_list_size = block_list_size;
379 
380 	IWL_DEBUG_RADIO(fwrt, "TAS array size %u\n", block_list_size);
381 
382 	for (int i = 0; i < block_list_size; i++) {
383 		u16 country;
384 
385 		if (wifi_pkg->package.elements[3 + i].type !=
386 		    ACPI_TYPE_INTEGER) {
387 			IWL_DEBUG_RADIO(fwrt,
388 					"TAS invalid array elem %d\n", 3 + i);
389 			ret = -EINVAL;
390 			goto out_free;
391 		}
392 
393 		country = wifi_pkg->package.elements[3 + i].integer.value;
394 		tas_data->block_list_array[i] = country;
395 		IWL_DEBUG_RADIO(fwrt, "TAS block list country %d\n", country);
396 	}
397 
398 	ret = enabled;
399 out_free:
400 	kfree(data);
401 	return ret;
402 }
403 
iwl_acpi_get_mcc(struct iwl_fw_runtime * fwrt,char * mcc)404 int iwl_acpi_get_mcc(struct iwl_fw_runtime *fwrt, char *mcc)
405 {
406 	union acpi_object *wifi_pkg, *data;
407 	u32 mcc_val;
408 	int ret, tbl_rev;
409 
410 	data = iwl_acpi_get_object(fwrt->dev, ACPI_WRDD_METHOD);
411 	if (IS_ERR(data))
412 		return PTR_ERR(data);
413 
414 	wifi_pkg = iwl_acpi_get_wifi_pkg(fwrt->dev, data,
415 					 ACPI_WRDD_WIFI_DATA_SIZE,
416 					 &tbl_rev);
417 	if (IS_ERR(wifi_pkg)) {
418 		ret = PTR_ERR(wifi_pkg);
419 		goto out_free;
420 	}
421 
422 	if (wifi_pkg->package.elements[1].type != ACPI_TYPE_INTEGER ||
423 	    tbl_rev != 0) {
424 		ret = -EINVAL;
425 		goto out_free;
426 	}
427 
428 	mcc_val = wifi_pkg->package.elements[1].integer.value;
429 	if (mcc_val != BIOS_MCC_CHINA) {
430 		ret = -EINVAL;
431 		IWL_DEBUG_RADIO(fwrt, "ACPI WRDD is supported only for CN\n");
432 		goto out_free;
433 	}
434 
435 	mcc[0] = (mcc_val >> 8) & 0xff;
436 	mcc[1] = mcc_val & 0xff;
437 	mcc[2] = '\0';
438 
439 	ret = 0;
440 out_free:
441 	kfree(data);
442 	return ret;
443 }
444 
iwl_acpi_get_pwr_limit(struct iwl_fw_runtime * fwrt,u64 * dflt_pwr_limit)445 int iwl_acpi_get_pwr_limit(struct iwl_fw_runtime *fwrt, u64 *dflt_pwr_limit)
446 {
447 	union acpi_object *data, *wifi_pkg;
448 	int tbl_rev, ret = -EINVAL;
449 
450 	*dflt_pwr_limit = 0;
451 	data = iwl_acpi_get_object(fwrt->dev, ACPI_SPLC_METHOD);
452 	if (IS_ERR(data))
453 		goto out;
454 
455 	wifi_pkg = iwl_acpi_get_wifi_pkg(fwrt->dev, data,
456 					 ACPI_SPLC_WIFI_DATA_SIZE, &tbl_rev);
457 	if (IS_ERR(wifi_pkg) || tbl_rev != 0 ||
458 	    wifi_pkg->package.elements[1].integer.value != ACPI_TYPE_INTEGER)
459 		goto out_free;
460 
461 	*dflt_pwr_limit = wifi_pkg->package.elements[1].integer.value;
462 	ret = 0;
463 out_free:
464 	kfree(data);
465 out:
466 	return ret;
467 }
468 
iwl_acpi_get_eckv(struct iwl_fw_runtime * fwrt,u32 * extl_clk)469 int iwl_acpi_get_eckv(struct iwl_fw_runtime *fwrt, u32 *extl_clk)
470 {
471 	union acpi_object *wifi_pkg, *data;
472 	int ret, tbl_rev;
473 
474 	data = iwl_acpi_get_object(fwrt->dev, ACPI_ECKV_METHOD);
475 	if (IS_ERR(data))
476 		return PTR_ERR(data);
477 
478 	wifi_pkg = iwl_acpi_get_wifi_pkg(fwrt->dev, data,
479 					 ACPI_ECKV_WIFI_DATA_SIZE,
480 					 &tbl_rev);
481 	if (IS_ERR(wifi_pkg)) {
482 		ret = PTR_ERR(wifi_pkg);
483 		goto out_free;
484 	}
485 
486 	if (wifi_pkg->package.elements[1].type != ACPI_TYPE_INTEGER ||
487 	    tbl_rev != 0) {
488 		ret = -EINVAL;
489 		goto out_free;
490 	}
491 
492 	*extl_clk = wifi_pkg->package.elements[1].integer.value;
493 
494 	ret = 0;
495 
496 out_free:
497 	kfree(data);
498 	return ret;
499 }
500 
501 static int
iwl_acpi_parse_chains_table(union acpi_object * table,struct iwl_sar_profile_chain * chains,u8 num_chains,u8 num_sub_bands)502 iwl_acpi_parse_chains_table(union acpi_object *table,
503 			    struct iwl_sar_profile_chain *chains,
504 			    u8 num_chains, u8 num_sub_bands)
505 {
506 	for (u8 chain = 0; chain < num_chains; chain++) {
507 		for (u8 subband = 0; subband < BIOS_SAR_MAX_SUB_BANDS_NUM;
508 		     subband++) {
509 			/* if we don't have the values, use the default */
510 			if (subband >= num_sub_bands) {
511 				chains[chain].subbands[subband] = 0;
512 			} else if (table->type != ACPI_TYPE_INTEGER ||
513 				   table->integer.value > U8_MAX) {
514 				return -EINVAL;
515 			} else {
516 				chains[chain].subbands[subband] =
517 					table->integer.value;
518 				table++;
519 			}
520 		}
521 	}
522 
523 	return 0;
524 }
525 
iwl_acpi_get_wrds_table(struct iwl_fw_runtime * fwrt)526 int iwl_acpi_get_wrds_table(struct iwl_fw_runtime *fwrt)
527 {
528 	union acpi_object *wifi_pkg, *table, *data;
529 	int ret, tbl_rev;
530 	u32 flags;
531 	u8 num_chains, num_sub_bands;
532 
533 	data = iwl_acpi_get_object(fwrt->dev, ACPI_WRDS_METHOD);
534 	if (IS_ERR(data))
535 		return PTR_ERR(data);
536 
537 	/* start by trying to read revision 2 */
538 	wifi_pkg = iwl_acpi_get_wifi_pkg(fwrt->dev, data,
539 					 ACPI_WRDS_WIFI_DATA_SIZE_REV2,
540 					 &tbl_rev);
541 	if (!IS_ERR(wifi_pkg)) {
542 		if (tbl_rev != 2) {
543 			ret = -EINVAL;
544 			goto out_free;
545 		}
546 
547 		num_chains = ACPI_SAR_NUM_CHAINS_REV2;
548 		num_sub_bands = ACPI_SAR_NUM_SUB_BANDS_REV2;
549 
550 		goto read_table;
551 	}
552 
553 	/* then try revision 1 */
554 	wifi_pkg = iwl_acpi_get_wifi_pkg(fwrt->dev, data,
555 					 ACPI_WRDS_WIFI_DATA_SIZE_REV1,
556 					 &tbl_rev);
557 	if (!IS_ERR(wifi_pkg)) {
558 		if (tbl_rev != 1) {
559 			ret = -EINVAL;
560 			goto out_free;
561 		}
562 
563 		num_chains = ACPI_SAR_NUM_CHAINS_REV1;
564 		num_sub_bands = ACPI_SAR_NUM_SUB_BANDS_REV1;
565 
566 		goto read_table;
567 	}
568 
569 	/* then finally revision 0 */
570 	wifi_pkg = iwl_acpi_get_wifi_pkg(fwrt->dev, data,
571 					 ACPI_WRDS_WIFI_DATA_SIZE_REV0,
572 					 &tbl_rev);
573 	if (!IS_ERR(wifi_pkg)) {
574 		if (tbl_rev != 0) {
575 			ret = -EINVAL;
576 			goto out_free;
577 		}
578 
579 		num_chains = ACPI_SAR_NUM_CHAINS_REV0;
580 		num_sub_bands = ACPI_SAR_NUM_SUB_BANDS_REV0;
581 
582 		goto read_table;
583 	}
584 
585 	ret = PTR_ERR(wifi_pkg);
586 	goto out_free;
587 
588 read_table:
589 	if (wifi_pkg->package.elements[1].type != ACPI_TYPE_INTEGER) {
590 		ret = -EINVAL;
591 		goto out_free;
592 	}
593 
594 	IWL_DEBUG_RADIO(fwrt, "Reading WRDS tbl_rev=%d\n", tbl_rev);
595 
596 	flags = wifi_pkg->package.elements[1].integer.value;
597 	fwrt->reduced_power_flags = flags >> IWL_REDUCE_POWER_FLAGS_POS;
598 
599 	/* position of the actual table */
600 	table = &wifi_pkg->package.elements[2];
601 
602 	/* The profile from WRDS is officially profile 1, but goes
603 	 * into sar_profiles[0] (because we don't have a profile 0).
604 	 */
605 	ret = iwl_acpi_parse_chains_table(table, fwrt->sar_profiles[0].chains,
606 					  num_chains, num_sub_bands);
607 	if (!ret && flags & IWL_SAR_ENABLE_MSK)
608 		fwrt->sar_profiles[0].enabled = true;
609 
610 out_free:
611 	kfree(data);
612 	return ret;
613 }
614 
iwl_acpi_get_ewrd_table(struct iwl_fw_runtime * fwrt)615 int iwl_acpi_get_ewrd_table(struct iwl_fw_runtime *fwrt)
616 {
617 	union acpi_object *wifi_pkg, *data;
618 	bool enabled;
619 	int i, n_profiles, tbl_rev, pos;
620 	int ret = 0;
621 	u8 num_sub_bands;
622 
623 	data = iwl_acpi_get_object(fwrt->dev, ACPI_EWRD_METHOD);
624 	if (IS_ERR(data))
625 		return PTR_ERR(data);
626 
627 	/* start by trying to read revision 2 */
628 	wifi_pkg = iwl_acpi_get_wifi_pkg(fwrt->dev, data,
629 					 ACPI_EWRD_WIFI_DATA_SIZE_REV2,
630 					 &tbl_rev);
631 	if (!IS_ERR(wifi_pkg)) {
632 		if (tbl_rev != 2) {
633 			ret = -EINVAL;
634 			goto out_free;
635 		}
636 
637 		num_sub_bands = ACPI_SAR_NUM_SUB_BANDS_REV2;
638 
639 		goto read_table;
640 	}
641 
642 	/* then try revision 1 */
643 	wifi_pkg = iwl_acpi_get_wifi_pkg(fwrt->dev, data,
644 					 ACPI_EWRD_WIFI_DATA_SIZE_REV1,
645 					 &tbl_rev);
646 	if (!IS_ERR(wifi_pkg)) {
647 		if (tbl_rev != 1) {
648 			ret = -EINVAL;
649 			goto out_free;
650 		}
651 
652 		num_sub_bands = ACPI_SAR_NUM_SUB_BANDS_REV1;
653 
654 		goto read_table;
655 	}
656 
657 	/* then finally revision 0 */
658 	wifi_pkg = iwl_acpi_get_wifi_pkg(fwrt->dev, data,
659 					 ACPI_EWRD_WIFI_DATA_SIZE_REV0,
660 					 &tbl_rev);
661 	if (!IS_ERR(wifi_pkg)) {
662 		if (tbl_rev != 0) {
663 			ret = -EINVAL;
664 			goto out_free;
665 		}
666 
667 		num_sub_bands = ACPI_SAR_NUM_SUB_BANDS_REV0;
668 
669 		goto read_table;
670 	}
671 
672 	ret = PTR_ERR(wifi_pkg);
673 	goto out_free;
674 
675 read_table:
676 	if (wifi_pkg->package.elements[1].type != ACPI_TYPE_INTEGER ||
677 	    wifi_pkg->package.elements[2].type != ACPI_TYPE_INTEGER) {
678 		ret = -EINVAL;
679 		goto out_free;
680 	}
681 
682 	enabled = !!(wifi_pkg->package.elements[1].integer.value);
683 	n_profiles = wifi_pkg->package.elements[2].integer.value;
684 
685 	/*
686 	 * Check the validity of n_profiles.  The EWRD profiles start
687 	 * from index 1, so the maximum value allowed here is
688 	 * ACPI_SAR_PROFILES_NUM - 1.
689 	 */
690 	if (n_profiles >= BIOS_SAR_MAX_PROFILE_NUM) {
691 		ret = -EINVAL;
692 		goto out_free;
693 	}
694 
695 	/* the tables start at element 3 */
696 	pos = 3;
697 
698 	BUILD_BUG_ON(ACPI_SAR_NUM_CHAINS_REV0 != ACPI_SAR_NUM_CHAINS_REV1);
699 	BUILD_BUG_ON(ACPI_SAR_NUM_CHAINS_REV2 != 2 * ACPI_SAR_NUM_CHAINS_REV0);
700 
701 	/* parse non-cdb chains for all profiles */
702 	for (i = 0; i < n_profiles; i++) {
703 		union acpi_object *table = &wifi_pkg->package.elements[pos];
704 
705 		/* The EWRD profiles officially go from 2 to 4, but we
706 		 * save them in sar_profiles[1-3] (because we don't
707 		 * have profile 0).  So in the array we start from 1.
708 		 */
709 		ret = iwl_acpi_parse_chains_table(table,
710 						  fwrt->sar_profiles[i + 1].chains,
711 						  ACPI_SAR_NUM_CHAINS_REV0,
712 						  num_sub_bands);
713 		if (ret < 0)
714 			goto out_free;
715 
716 		/* go to the next table */
717 		pos += ACPI_SAR_NUM_CHAINS_REV0 * num_sub_bands;
718 	}
719 
720 	/* non-cdb table revisions */
721 	if (tbl_rev < 2)
722 		goto set_enabled;
723 
724 	/* parse cdb chains for all profiles */
725 	for (i = 0; i < n_profiles; i++) {
726 		struct iwl_sar_profile_chain *chains;
727 		union acpi_object *table;
728 
729 		table = &wifi_pkg->package.elements[pos];
730 		chains = &fwrt->sar_profiles[i + 1].chains[ACPI_SAR_NUM_CHAINS_REV0];
731 		ret = iwl_acpi_parse_chains_table(table,
732 						  chains,
733 						  ACPI_SAR_NUM_CHAINS_REV0,
734 						  num_sub_bands);
735 		if (ret < 0)
736 			goto out_free;
737 
738 		/* go to the next table */
739 		pos += ACPI_SAR_NUM_CHAINS_REV0 * num_sub_bands;
740 	}
741 
742 set_enabled:
743 	for (i = 0; i < n_profiles; i++)
744 		fwrt->sar_profiles[i + 1].enabled = enabled;
745 
746 out_free:
747 	kfree(data);
748 	return ret;
749 }
750 
iwl_acpi_get_wgds_table(struct iwl_fw_runtime * fwrt)751 int iwl_acpi_get_wgds_table(struct iwl_fw_runtime *fwrt)
752 {
753 	union acpi_object *wifi_pkg, *data;
754 	int i, j, k, ret, tbl_rev;
755 	u8 num_bands, num_profiles;
756 	static const struct {
757 		u8 revisions;
758 		u8 bands;
759 		u8 profiles;
760 		u8 min_profiles;
761 	} rev_data[] = {
762 		{
763 			.revisions = BIT(3),
764 			.bands = ACPI_GEO_NUM_BANDS_REV2,
765 			.profiles = ACPI_NUM_GEO_PROFILES_REV3,
766 			.min_profiles = BIOS_GEO_MIN_PROFILE_NUM,
767 		},
768 		{
769 			.revisions = BIT(2),
770 			.bands = ACPI_GEO_NUM_BANDS_REV2,
771 			.profiles = ACPI_NUM_GEO_PROFILES,
772 		},
773 		{
774 			.revisions = BIT(0) | BIT(1),
775 			.bands = ACPI_GEO_NUM_BANDS_REV0,
776 			.profiles = ACPI_NUM_GEO_PROFILES,
777 		},
778 	};
779 	int idx;
780 	/* start from one to skip the domain */
781 	int entry_idx = 1;
782 
783 	BUILD_BUG_ON(ACPI_NUM_GEO_PROFILES_REV3 != IWL_NUM_GEO_PROFILES_V3);
784 	BUILD_BUG_ON(ACPI_NUM_GEO_PROFILES != IWL_NUM_GEO_PROFILES);
785 
786 	data = iwl_acpi_get_object(fwrt->dev, ACPI_WGDS_METHOD);
787 	if (IS_ERR(data))
788 		return PTR_ERR(data);
789 
790 	/* read the highest revision we understand first */
791 	for (idx = 0; idx < ARRAY_SIZE(rev_data); idx++) {
792 		/* min_profiles != 0 requires num_profiles header */
793 		u32 hdr_size = 1 + !!rev_data[idx].min_profiles;
794 		u32 profile_size = ACPI_GEO_PER_CHAIN_SIZE *
795 				   rev_data[idx].bands;
796 		u32 max_size = hdr_size + profile_size * rev_data[idx].profiles;
797 		u32 min_size;
798 
799 		if (!rev_data[idx].min_profiles)
800 			min_size = max_size;
801 		else
802 			min_size = hdr_size +
803 				   profile_size * rev_data[idx].min_profiles;
804 
805 		wifi_pkg = iwl_acpi_get_wifi_pkg_range(fwrt->dev, data,
806 						       min_size, max_size,
807 						       &tbl_rev);
808 		if (!IS_ERR(wifi_pkg)) {
809 			if (!(BIT(tbl_rev) & rev_data[idx].revisions))
810 				continue;
811 
812 			num_bands = rev_data[idx].bands;
813 			num_profiles = rev_data[idx].profiles;
814 
815 			if (rev_data[idx].min_profiles) {
816 				/* read header that says # of profiles */
817 				union acpi_object *entry;
818 
819 				entry = &wifi_pkg->package.elements[entry_idx];
820 				entry_idx++;
821 				if (entry->type != ACPI_TYPE_INTEGER ||
822 				    entry->integer.value > num_profiles ||
823 				    entry->integer.value <
824 					rev_data[idx].min_profiles) {
825 					ret = -EINVAL;
826 					goto out_free;
827 				}
828 
829 				/*
830 				 * Check to see if we received package count
831 				 * same as max # of profiles
832 				 */
833 				if (wifi_pkg->package.count !=
834 				    hdr_size + profile_size * num_profiles) {
835 					ret = -EINVAL;
836 					goto out_free;
837 				}
838 
839 				/* Number of valid profiles */
840 				num_profiles = entry->integer.value;
841 			}
842 			goto read_table;
843 		}
844 	}
845 
846 	if (idx < ARRAY_SIZE(rev_data))
847 		ret = PTR_ERR(wifi_pkg);
848 	else
849 		ret = -ENOENT;
850 	goto out_free;
851 
852 read_table:
853 	fwrt->geo_rev = tbl_rev;
854 	for (i = 0; i < num_profiles; i++) {
855 		for (j = 0; j < BIOS_GEO_MAX_NUM_BANDS; j++) {
856 			union acpi_object *entry;
857 
858 			/*
859 			 * num_bands is either 2 or 3, if it's only 2 then
860 			 * fill the third band (6 GHz) with the values from
861 			 * 5 GHz (second band)
862 			 */
863 			if (j >= num_bands) {
864 				fwrt->geo_profiles[i].bands[j].max =
865 					fwrt->geo_profiles[i].bands[1].max;
866 			} else {
867 				entry = &wifi_pkg->package.elements[entry_idx];
868 				entry_idx++;
869 				if (entry->type != ACPI_TYPE_INTEGER ||
870 				    entry->integer.value > U8_MAX) {
871 					ret = -EINVAL;
872 					goto out_free;
873 				}
874 
875 				fwrt->geo_profiles[i].bands[j].max =
876 					entry->integer.value;
877 			}
878 
879 			for (k = 0; k < BIOS_GEO_NUM_CHAINS; k++) {
880 				/* same here as above */
881 				if (j >= num_bands) {
882 					fwrt->geo_profiles[i].bands[j].chains[k] =
883 						fwrt->geo_profiles[i].bands[1].chains[k];
884 				} else {
885 					entry = &wifi_pkg->package.elements[entry_idx];
886 					entry_idx++;
887 					if (entry->type != ACPI_TYPE_INTEGER ||
888 					    entry->integer.value > U8_MAX) {
889 						ret = -EINVAL;
890 						goto out_free;
891 					}
892 
893 					fwrt->geo_profiles[i].bands[j].chains[k] =
894 						entry->integer.value;
895 				}
896 			}
897 		}
898 	}
899 
900 	fwrt->geo_num_profiles = num_profiles;
901 	fwrt->geo_enabled = true;
902 	ret = 0;
903 out_free:
904 	kfree(data);
905 	return ret;
906 }
907 
iwl_acpi_get_ppag_table(struct iwl_fw_runtime * fwrt)908 int iwl_acpi_get_ppag_table(struct iwl_fw_runtime *fwrt)
909 {
910 	union acpi_object *wifi_pkg, *data, *flags;
911 	int i, j, ret, tbl_rev, num_sub_bands = 0;
912 	int idx = 2;
913 
914 	data = iwl_acpi_get_object(fwrt->dev, ACPI_PPAG_METHOD);
915 	if (IS_ERR(data))
916 		return PTR_ERR(data);
917 
918 	/* try to read ppag table rev 1 to 4 (all have the same data size) */
919 	wifi_pkg = iwl_acpi_get_wifi_pkg(fwrt->dev, data,
920 				ACPI_PPAG_WIFI_DATA_SIZE_V2, &tbl_rev);
921 
922 	if (!IS_ERR(wifi_pkg)) {
923 		if (tbl_rev >= 1 && tbl_rev <= 4) {
924 			num_sub_bands = IWL_NUM_SUB_BANDS_V2;
925 			IWL_DEBUG_RADIO(fwrt,
926 					"Reading PPAG table (tbl_rev=%d)\n",
927 					tbl_rev);
928 			goto read_table;
929 		} else {
930 			ret = -EINVAL;
931 			goto out_free;
932 		}
933 	}
934 
935 	/* try to read ppag table revision 0 */
936 	wifi_pkg = iwl_acpi_get_wifi_pkg(fwrt->dev, data,
937 			ACPI_PPAG_WIFI_DATA_SIZE_V1, &tbl_rev);
938 
939 	if (!IS_ERR(wifi_pkg)) {
940 		if (tbl_rev != 0) {
941 			ret = -EINVAL;
942 			goto out_free;
943 		}
944 		num_sub_bands = IWL_NUM_SUB_BANDS_V1;
945 		IWL_DEBUG_RADIO(fwrt, "Reading PPAG table v1 (tbl_rev=0)\n");
946 		goto read_table;
947 	}
948 
949 	ret = PTR_ERR(wifi_pkg);
950 	goto out_free;
951 
952 read_table:
953 	fwrt->ppag_bios_rev = tbl_rev;
954 	flags = &wifi_pkg->package.elements[1];
955 
956 	if (flags->type != ACPI_TYPE_INTEGER) {
957 		ret = -EINVAL;
958 		goto out_free;
959 	}
960 
961 	fwrt->ppag_flags = iwl_bios_get_ppag_flags(flags->integer.value,
962 						   fwrt->ppag_bios_rev);
963 
964 	/*
965 	 * read, verify gain values and save them into the PPAG table.
966 	 * first sub-band (j=0) corresponds to Low-Band (2.4GHz), and the
967 	 * following sub-bands to High-Band (5GHz).
968 	 */
969 	for (i = 0; i < IWL_NUM_CHAIN_LIMITS; i++) {
970 		for (j = 0; j < num_sub_bands; j++) {
971 			union acpi_object *ent;
972 
973 			ent = &wifi_pkg->package.elements[idx++];
974 			if (ent->type != ACPI_TYPE_INTEGER) {
975 				ret = -EINVAL;
976 				goto out_free;
977 			}
978 
979 			fwrt->ppag_chains[i].subbands[j] = ent->integer.value;
980 		}
981 	}
982 
983 	fwrt->ppag_bios_source = BIOS_SOURCE_ACPI;
984 	ret = 0;
985 
986 out_free:
987 	kfree(data);
988 	return ret;
989 }
990 
iwl_acpi_get_phy_filters(struct iwl_fw_runtime * fwrt)991 int iwl_acpi_get_phy_filters(struct iwl_fw_runtime *fwrt)
992 {
993 	struct iwl_phy_specific_cfg *filters = &fwrt->phy_filters;
994 	struct iwl_phy_specific_cfg tmp = {};
995 	union acpi_object *wifi_pkg, *data __free(kfree);
996 	int tbl_rev, i;
997 
998 	data = iwl_acpi_get_object(fwrt->dev, ACPI_WPFC_METHOD);
999 	if (IS_ERR(data))
1000 		return PTR_ERR(data);
1001 
1002 	wifi_pkg = iwl_acpi_get_wifi_pkg(fwrt->dev, data,
1003 					 ACPI_WPFC_WIFI_DATA_SIZE,
1004 					 &tbl_rev);
1005 	if (IS_ERR(wifi_pkg))
1006 		return PTR_ERR(wifi_pkg);
1007 
1008 	if (tbl_rev != 0)
1009 		return -EINVAL;
1010 
1011 	BUILD_BUG_ON(ARRAY_SIZE(filters->filter_cfg_chains) !=
1012 		     ACPI_WPFC_WIFI_DATA_SIZE - 1);
1013 
1014 	for (i = 0; i < ARRAY_SIZE(filters->filter_cfg_chains); i++) {
1015 		if (wifi_pkg->package.elements[i + 1].type != ACPI_TYPE_INTEGER)
1016 			return -EINVAL;
1017 		tmp.filter_cfg_chains[i] =
1018 			cpu_to_le32(wifi_pkg->package.elements[i + 1].integer.value);
1019 	}
1020 
1021 	IWL_DEBUG_RADIO(fwrt, "Loaded WPFC filter config from ACPI\n");
1022 	*filters = tmp;
1023 	return 0;
1024 }
1025 IWL_EXPORT_SYMBOL(iwl_acpi_get_phy_filters);
1026 
iwl_acpi_get_guid_lock_status(struct iwl_fw_runtime * fwrt)1027 void iwl_acpi_get_guid_lock_status(struct iwl_fw_runtime *fwrt)
1028 {
1029 	union acpi_object *wifi_pkg, *data;
1030 	int tbl_rev;
1031 
1032 	data = iwl_acpi_get_object(fwrt->dev, ACPI_GLAI_METHOD);
1033 	if (IS_ERR(data))
1034 		return;
1035 
1036 	wifi_pkg = iwl_acpi_get_wifi_pkg(fwrt->dev, data,
1037 					 ACPI_GLAI_WIFI_DATA_SIZE,
1038 					 &tbl_rev);
1039 	if (IS_ERR(wifi_pkg))
1040 		goto out_free;
1041 
1042 	if (tbl_rev != 0) {
1043 		IWL_DEBUG_RADIO(fwrt, "Invalid GLAI revision: %d\n", tbl_rev);
1044 		goto out_free;
1045 	}
1046 
1047 	if (wifi_pkg->package.elements[1].type != ACPI_TYPE_INTEGER ||
1048 	    wifi_pkg->package.elements[1].integer.value > ACPI_GLAI_MAX_STATUS)
1049 		goto out_free;
1050 
1051 	fwrt->uefi_tables_lock_status =
1052 		wifi_pkg->package.elements[1].integer.value;
1053 
1054 	IWL_DEBUG_RADIO(fwrt,
1055 			"Loaded UEFI WIFI GUID lock status: %d from ACPI\n",
1056 			fwrt->uefi_tables_lock_status);
1057 out_free:
1058 	kfree(data);
1059 }
1060 IWL_EXPORT_SYMBOL(iwl_acpi_get_guid_lock_status);
1061 
iwl_acpi_get_wbem(struct iwl_fw_runtime * fwrt,u32 * value)1062 int iwl_acpi_get_wbem(struct iwl_fw_runtime *fwrt, u32 *value)
1063 {
1064 	union acpi_object *wifi_pkg, *data;
1065 	int ret = -ENOENT;
1066 	int tbl_rev;
1067 
1068 	data = iwl_acpi_get_object(fwrt->dev, ACPI_WBEM_METHOD);
1069 	if (IS_ERR(data))
1070 		return ret;
1071 
1072 	wifi_pkg = iwl_acpi_get_wifi_pkg(fwrt->dev, data,
1073 					 ACPI_WBEM_WIFI_DATA_SIZE,
1074 					 &tbl_rev);
1075 	if (IS_ERR(wifi_pkg))
1076 		goto out_free;
1077 
1078 	if (tbl_rev != IWL_ACPI_WBEM_REVISION) {
1079 		IWL_DEBUG_RADIO(fwrt, "Unsupported ACPI WBEM revision:%d\n",
1080 				tbl_rev);
1081 		goto out_free;
1082 	}
1083 
1084 	if (wifi_pkg->package.elements[1].type != ACPI_TYPE_INTEGER)
1085 		goto out_free;
1086 
1087 	*value = wifi_pkg->package.elements[1].integer.value &
1088 		 IWL_ACPI_WBEM_REV0_MASK;
1089 	IWL_DEBUG_RADIO(fwrt, "Loaded WBEM config from ACPI\n");
1090 	ret = 0;
1091 out_free:
1092 	kfree(data);
1093 	return ret;
1094 }
1095 
iwl_acpi_get_dsbr(struct iwl_fw_runtime * fwrt,u32 * value)1096 int iwl_acpi_get_dsbr(struct iwl_fw_runtime *fwrt, u32 *value)
1097 {
1098 	union acpi_object *wifi_pkg, *data;
1099 	int ret = -ENOENT;
1100 	int tbl_rev;
1101 
1102 	data = iwl_acpi_get_object(fwrt->dev, ACPI_DSBR_METHOD);
1103 	if (IS_ERR(data))
1104 		return ret;
1105 
1106 	wifi_pkg = iwl_acpi_get_wifi_pkg(fwrt->dev, data,
1107 					 ACPI_DSBR_WIFI_DATA_SIZE,
1108 					 &tbl_rev);
1109 	if (IS_ERR(wifi_pkg))
1110 		goto out_free;
1111 
1112 	if (tbl_rev != ACPI_DSBR_WIFI_DATA_REV) {
1113 		IWL_DEBUG_RADIO(fwrt, "Unsupported ACPI DSBR revision:%d\n",
1114 				tbl_rev);
1115 		goto out_free;
1116 	}
1117 
1118 	if (wifi_pkg->package.elements[1].type != ACPI_TYPE_INTEGER)
1119 		goto out_free;
1120 
1121 	*value = wifi_pkg->package.elements[1].integer.value;
1122 	IWL_DEBUG_RADIO(fwrt, "Loaded DSBR config from ACPI value: 0x%x\n",
1123 			*value);
1124 	ret = 0;
1125 out_free:
1126 	kfree(data);
1127 	return ret;
1128 }
1129