xref: /freebsd/sys/contrib/dev/iwlwifi/fw/acpi.c (revision bdd1243df58e60e85101c09001d9812a789b6bc4)
1 // SPDX-License-Identifier: GPL-2.0 OR BSD-3-Clause
2 /*
3  * Copyright (C) 2017 Intel Deutschland GmbH
4  * Copyright (C) 2019-2022 Intel Corporation
5  */
6 #include <linux/uuid.h>
7 #include <linux/dmi.h>
8 #include "iwl-drv.h"
9 #include "iwl-debug.h"
10 #include "acpi.h"
11 #include "fw/runtime.h"
12 
13 const guid_t iwl_guid = GUID_INIT(0xF21202BF, 0x8F78, 0x4DC6,
14 				  0xA5, 0xB3, 0x1F, 0x73,
15 				  0x8E, 0x28, 0x5A, 0xDE);
16 IWL_EXPORT_SYMBOL(iwl_guid);
17 
18 const guid_t iwl_rfi_guid = GUID_INIT(0x7266172C, 0x220B, 0x4B29,
19 				      0x81, 0x4F, 0x75, 0xE4,
20 				      0xDD, 0x26, 0xB5, 0xFD);
21 IWL_EXPORT_SYMBOL(iwl_rfi_guid);
22 
23 static const struct dmi_system_id dmi_ppag_approved_list[] = {
24 	{ .ident = "HP",
25 	  .matches = {
26 			DMI_MATCH(DMI_SYS_VENDOR, "HP"),
27 		},
28 	},
29 	{ .ident = "SAMSUNG",
30 	  .matches = {
31 			DMI_MATCH(DMI_SYS_VENDOR, "SAMSUNG ELECTRONICS CO., LTD"),
32 		},
33 	},
34 	{ .ident = "MSFT",
35 	  .matches = {
36 			DMI_MATCH(DMI_SYS_VENDOR, "Microsoft Corporation"),
37 		},
38 	},
39 	{ .ident = "ASUS",
40 	  .matches = {
41 			DMI_MATCH(DMI_SYS_VENDOR, "ASUSTek COMPUTER INC."),
42 		},
43 	},
44 	{}
45 };
46 
47 static int iwl_acpi_get_handle(struct device *dev, acpi_string method,
48 			       acpi_handle *ret_handle)
49 {
50 	acpi_handle root_handle;
51 	acpi_status status;
52 
53 	root_handle = ACPI_HANDLE(dev);
54 	if (!root_handle) {
55 		IWL_DEBUG_DEV_RADIO(dev,
56 				    "ACPI: Could not retrieve root port handle\n");
57 		return -ENOENT;
58 	}
59 
60 	status = acpi_get_handle(root_handle, method, ret_handle);
61 	if (ACPI_FAILURE(status)) {
62 		IWL_DEBUG_DEV_RADIO(dev,
63 				    "ACPI: %s method not found\n", method);
64 		return -ENOENT;
65 	}
66 	return 0;
67 }
68 
69 void *iwl_acpi_get_object(struct device *dev, acpi_string method)
70 {
71 	struct acpi_buffer buf = {ACPI_ALLOCATE_BUFFER, NULL};
72 	acpi_handle handle;
73 	acpi_status status;
74 	int ret;
75 
76 	ret = iwl_acpi_get_handle(dev, method, &handle);
77 	if (ret)
78 		return ERR_PTR(-ENOENT);
79 
80 	/* Call the method with no arguments */
81 	status = acpi_evaluate_object(handle, NULL, NULL, &buf);
82 	if (ACPI_FAILURE(status)) {
83 		IWL_DEBUG_DEV_RADIO(dev,
84 				    "ACPI: %s method invocation failed (status: 0x%x)\n",
85 				    method, status);
86 		return ERR_PTR(-ENOENT);
87 	}
88 	return buf.pointer;
89 }
90 IWL_EXPORT_SYMBOL(iwl_acpi_get_object);
91 
92 /*
93  * Generic function for evaluating a method defined in the device specific
94  * method (DSM) interface. The returned acpi object must be freed by calling
95  * function.
96  */
97 static void *iwl_acpi_get_dsm_object(struct device *dev, int rev, int func,
98 				     union acpi_object *args,
99 				     const guid_t *guid)
100 {
101 	union acpi_object *obj;
102 
103 	obj = acpi_evaluate_dsm(ACPI_HANDLE(dev), guid, rev, func,
104 				args);
105 	if (!obj) {
106 		IWL_DEBUG_DEV_RADIO(dev,
107 				    "ACPI: DSM method invocation failed (rev: %d, func:%d)\n",
108 				    rev, func);
109 		return ERR_PTR(-ENOENT);
110 	}
111 	return obj;
112 }
113 
114 /*
115  * Generic function to evaluate a DSM with no arguments
116  * and an integer return value,
117  * (as an integer object or inside a buffer object),
118  * verify and assign the value in the "value" parameter.
119  * return 0 in success and the appropriate errno otherwise.
120  */
121 static int iwl_acpi_get_dsm_integer(struct device *dev, int rev, int func,
122 				    const guid_t *guid, u64 *value,
123 				    size_t expected_size)
124 {
125 	union acpi_object *obj;
126 	int ret = 0;
127 
128 	obj = iwl_acpi_get_dsm_object(dev, rev, func, NULL, guid);
129 	if (IS_ERR(obj)) {
130 		IWL_DEBUG_DEV_RADIO(dev,
131 				    "Failed to get  DSM object. func= %d\n",
132 				    func);
133 		return -ENOENT;
134 	}
135 
136 	if (obj->type == ACPI_TYPE_INTEGER) {
137 		*value = obj->integer.value;
138 	} else if (obj->type == ACPI_TYPE_BUFFER) {
139 		__le64 le_value = 0;
140 
141 		if (WARN_ON_ONCE(expected_size > sizeof(le_value)))
142 			return -EINVAL;
143 
144 		/* if the buffer size doesn't match the expected size */
145 		if (obj->buffer.length != expected_size)
146 			IWL_DEBUG_DEV_RADIO(dev,
147 					    "ACPI: DSM invalid buffer size, padding or truncating (%d)\n",
148 					    obj->buffer.length);
149 
150 		 /* assuming LE from Intel BIOS spec */
151 		memcpy(&le_value, obj->buffer.pointer,
152 		       min_t(size_t, expected_size, (size_t)obj->buffer.length));
153 		*value = le64_to_cpu(le_value);
154 	} else {
155 		IWL_DEBUG_DEV_RADIO(dev,
156 				    "ACPI: DSM method did not return a valid object, type=%d\n",
157 				    obj->type);
158 		ret = -EINVAL;
159 		goto out;
160 	}
161 
162 	IWL_DEBUG_DEV_RADIO(dev,
163 			    "ACPI: DSM method evaluated: func=%d, ret=%d\n",
164 			    func, ret);
165 out:
166 	ACPI_FREE(obj);
167 	return ret;
168 }
169 
170 /*
171  * Evaluate a DSM with no arguments and a u8 return value,
172  */
173 int iwl_acpi_get_dsm_u8(struct device *dev, int rev, int func,
174 			const guid_t *guid, u8 *value)
175 {
176 	int ret;
177 	u64 val;
178 
179 	ret = iwl_acpi_get_dsm_integer(dev, rev, func,
180 				       guid, &val, sizeof(u8));
181 
182 	if (ret < 0)
183 		return ret;
184 
185 	/* cast val (u64) to be u8 */
186 	*value = (u8)val;
187 	return 0;
188 }
189 IWL_EXPORT_SYMBOL(iwl_acpi_get_dsm_u8);
190 
191 /*
192  * Evaluate a DSM with no arguments and a u32 return value,
193  */
194 int iwl_acpi_get_dsm_u32(struct device *dev, int rev, int func,
195 			 const guid_t *guid, u32 *value)
196 {
197 	int ret;
198 	u64 val;
199 
200 	ret = iwl_acpi_get_dsm_integer(dev, rev, func,
201 				       guid, &val, sizeof(u32));
202 
203 	if (ret < 0)
204 		return ret;
205 
206 	/* cast val (u64) to be u32 */
207 	*value = (u32)val;
208 	return 0;
209 }
210 IWL_EXPORT_SYMBOL(iwl_acpi_get_dsm_u32);
211 
212 union acpi_object *iwl_acpi_get_wifi_pkg_range(struct device *dev,
213 					       union acpi_object *data,
214 					       int min_data_size,
215 					       int max_data_size,
216 					       int *tbl_rev)
217 {
218 	int i;
219 	union acpi_object *wifi_pkg;
220 
221 	/*
222 	 * We need at least one entry in the wifi package that
223 	 * describes the domain, and one more entry, otherwise there's
224 	 * no point in reading it.
225 	 */
226 	if (WARN_ON_ONCE(min_data_size < 2 || min_data_size > max_data_size))
227 		return ERR_PTR(-EINVAL);
228 
229 	/*
230 	 * We need at least two packages, one for the revision and one
231 	 * for the data itself.  Also check that the revision is valid
232 	 * (i.e. it is an integer (each caller has to check by itself
233 	 * if the returned revision is supported)).
234 	 */
235 	if (data->type != ACPI_TYPE_PACKAGE ||
236 	    data->package.count < 2 ||
237 	    data->package.elements[0].type != ACPI_TYPE_INTEGER) {
238 		IWL_DEBUG_DEV_RADIO(dev, "Invalid packages structure\n");
239 		return ERR_PTR(-EINVAL);
240 	}
241 
242 	*tbl_rev = data->package.elements[0].integer.value;
243 
244 	/* loop through all the packages to find the one for WiFi */
245 	for (i = 1; i < data->package.count; i++) {
246 		union acpi_object *domain;
247 
248 		wifi_pkg = &data->package.elements[i];
249 
250 		/* skip entries that are not a package with the right size */
251 		if (wifi_pkg->type != ACPI_TYPE_PACKAGE ||
252 		    wifi_pkg->package.count < min_data_size ||
253 		    wifi_pkg->package.count > max_data_size)
254 			continue;
255 
256 		domain = &wifi_pkg->package.elements[0];
257 		if (domain->type == ACPI_TYPE_INTEGER &&
258 		    domain->integer.value == ACPI_WIFI_DOMAIN)
259 			goto found;
260 	}
261 
262 	return ERR_PTR(-ENOENT);
263 
264 found:
265 	return wifi_pkg;
266 }
267 IWL_EXPORT_SYMBOL(iwl_acpi_get_wifi_pkg_range);
268 
269 int iwl_acpi_get_tas(struct iwl_fw_runtime *fwrt,
270 		     union iwl_tas_config_cmd *cmd, int fw_ver)
271 {
272 	union acpi_object *wifi_pkg, *data;
273 	int ret, tbl_rev, i, block_list_size, enabled;
274 
275 	data = iwl_acpi_get_object(fwrt->dev, ACPI_WTAS_METHOD);
276 	if (IS_ERR(data))
277 		return PTR_ERR(data);
278 
279 	/* try to read wtas table revision 1 or revision 0*/
280 	wifi_pkg = iwl_acpi_get_wifi_pkg(fwrt->dev, data,
281 					 ACPI_WTAS_WIFI_DATA_SIZE,
282 					 &tbl_rev);
283 	if (IS_ERR(wifi_pkg)) {
284 		ret = PTR_ERR(wifi_pkg);
285 		goto out_free;
286 	}
287 
288 	if (tbl_rev == 1 && wifi_pkg->package.elements[1].type ==
289 		ACPI_TYPE_INTEGER) {
290 		u32 tas_selection =
291 			(u32)wifi_pkg->package.elements[1].integer.value;
292 		u16 override_iec =
293 			(tas_selection & ACPI_WTAS_OVERRIDE_IEC_MSK) >> ACPI_WTAS_OVERRIDE_IEC_POS;
294 		u16 enabled_iec = (tas_selection & ACPI_WTAS_ENABLE_IEC_MSK) >>
295 			ACPI_WTAS_ENABLE_IEC_POS;
296 		u8 usa_tas_uhb = (tas_selection & ACPI_WTAS_USA_UHB_MSK) >> ACPI_WTAS_USA_UHB_POS;
297 
298 
299 		enabled = tas_selection & ACPI_WTAS_ENABLED_MSK;
300 		if (fw_ver <= 3) {
301 			cmd->v3.override_tas_iec = cpu_to_le16(override_iec);
302 			cmd->v3.enable_tas_iec = cpu_to_le16(enabled_iec);
303 		} else {
304 			cmd->v4.usa_tas_uhb_allowed = usa_tas_uhb;
305 			cmd->v4.override_tas_iec = (u8)override_iec;
306 			cmd->v4.enable_tas_iec = (u8)enabled_iec;
307 		}
308 
309 	} else if (tbl_rev == 0 &&
310 		wifi_pkg->package.elements[1].type == ACPI_TYPE_INTEGER) {
311 		enabled = !!wifi_pkg->package.elements[1].integer.value;
312 	} else {
313 		ret = -EINVAL;
314 		goto out_free;
315 	}
316 
317 	if (!enabled) {
318 		IWL_DEBUG_RADIO(fwrt, "TAS not enabled\n");
319 		ret = 0;
320 		goto out_free;
321 	}
322 
323 	IWL_DEBUG_RADIO(fwrt, "Reading TAS table revision %d\n", tbl_rev);
324 	if (wifi_pkg->package.elements[2].type != ACPI_TYPE_INTEGER ||
325 	    wifi_pkg->package.elements[2].integer.value >
326 	    APCI_WTAS_BLACK_LIST_MAX) {
327 		IWL_DEBUG_RADIO(fwrt, "TAS invalid array size %llu\n",
328 				wifi_pkg->package.elements[2].integer.value);
329 		ret = -EINVAL;
330 		goto out_free;
331 	}
332 	block_list_size = wifi_pkg->package.elements[2].integer.value;
333 	cmd->v4.block_list_size = cpu_to_le32(block_list_size);
334 
335 	IWL_DEBUG_RADIO(fwrt, "TAS array size %u\n", block_list_size);
336 	if (block_list_size > APCI_WTAS_BLACK_LIST_MAX) {
337 		IWL_DEBUG_RADIO(fwrt, "TAS invalid array size value %u\n",
338 				block_list_size);
339 		ret = -EINVAL;
340 		goto out_free;
341 	}
342 
343 	for (i = 0; i < block_list_size; i++) {
344 		u32 country;
345 
346 		if (wifi_pkg->package.elements[3 + i].type !=
347 		    ACPI_TYPE_INTEGER) {
348 			IWL_DEBUG_RADIO(fwrt,
349 					"TAS invalid array elem %d\n", 3 + i);
350 			ret = -EINVAL;
351 			goto out_free;
352 		}
353 
354 		country = wifi_pkg->package.elements[3 + i].integer.value;
355 		cmd->v4.block_list_array[i] = cpu_to_le32(country);
356 		IWL_DEBUG_RADIO(fwrt, "TAS block list country %d\n", country);
357 	}
358 
359 	ret = 1;
360 out_free:
361 	kfree(data);
362 	return ret;
363 }
364 IWL_EXPORT_SYMBOL(iwl_acpi_get_tas);
365 
366 int iwl_acpi_get_mcc(struct device *dev, char *mcc)
367 {
368 	union acpi_object *wifi_pkg, *data;
369 	u32 mcc_val;
370 	int ret, tbl_rev;
371 
372 	data = iwl_acpi_get_object(dev, ACPI_WRDD_METHOD);
373 	if (IS_ERR(data))
374 		return PTR_ERR(data);
375 
376 	wifi_pkg = iwl_acpi_get_wifi_pkg(dev, data, ACPI_WRDD_WIFI_DATA_SIZE,
377 					 &tbl_rev);
378 	if (IS_ERR(wifi_pkg)) {
379 		ret = PTR_ERR(wifi_pkg);
380 		goto out_free;
381 	}
382 
383 	if (wifi_pkg->package.elements[1].type != ACPI_TYPE_INTEGER ||
384 	    tbl_rev != 0) {
385 		ret = -EINVAL;
386 		goto out_free;
387 	}
388 
389 	mcc_val = wifi_pkg->package.elements[1].integer.value;
390 
391 	mcc[0] = (mcc_val >> 8) & 0xff;
392 	mcc[1] = mcc_val & 0xff;
393 	mcc[2] = '\0';
394 
395 	ret = 0;
396 out_free:
397 	kfree(data);
398 	return ret;
399 }
400 IWL_EXPORT_SYMBOL(iwl_acpi_get_mcc);
401 
402 u64 iwl_acpi_get_pwr_limit(struct device *dev)
403 {
404 	union acpi_object *data, *wifi_pkg;
405 	u64 dflt_pwr_limit;
406 	int tbl_rev;
407 
408 	data = iwl_acpi_get_object(dev, ACPI_SPLC_METHOD);
409 	if (IS_ERR(data)) {
410 		dflt_pwr_limit = 0;
411 		goto out;
412 	}
413 
414 	wifi_pkg = iwl_acpi_get_wifi_pkg(dev, data,
415 					 ACPI_SPLC_WIFI_DATA_SIZE, &tbl_rev);
416 	if (IS_ERR(wifi_pkg) || tbl_rev != 0 ||
417 	    wifi_pkg->package.elements[1].integer.value != ACPI_TYPE_INTEGER) {
418 		dflt_pwr_limit = 0;
419 		goto out_free;
420 	}
421 
422 	dflt_pwr_limit = wifi_pkg->package.elements[1].integer.value;
423 out_free:
424 	kfree(data);
425 out:
426 	return dflt_pwr_limit;
427 }
428 IWL_EXPORT_SYMBOL(iwl_acpi_get_pwr_limit);
429 
430 int iwl_acpi_get_eckv(struct device *dev, u32 *extl_clk)
431 {
432 	union acpi_object *wifi_pkg, *data;
433 	int ret, tbl_rev;
434 
435 	data = iwl_acpi_get_object(dev, ACPI_ECKV_METHOD);
436 	if (IS_ERR(data))
437 		return PTR_ERR(data);
438 
439 	wifi_pkg = iwl_acpi_get_wifi_pkg(dev, data, ACPI_ECKV_WIFI_DATA_SIZE,
440 					 &tbl_rev);
441 	if (IS_ERR(wifi_pkg)) {
442 		ret = PTR_ERR(wifi_pkg);
443 		goto out_free;
444 	}
445 
446 	if (wifi_pkg->package.elements[1].type != ACPI_TYPE_INTEGER ||
447 	    tbl_rev != 0) {
448 		ret = -EINVAL;
449 		goto out_free;
450 	}
451 
452 	*extl_clk = wifi_pkg->package.elements[1].integer.value;
453 
454 	ret = 0;
455 
456 out_free:
457 	kfree(data);
458 	return ret;
459 }
460 IWL_EXPORT_SYMBOL(iwl_acpi_get_eckv);
461 
462 static int iwl_sar_set_profile(union acpi_object *table,
463 			       struct iwl_sar_profile *profile,
464 			       bool enabled, u8 num_chains, u8 num_sub_bands)
465 {
466 	int i, j, idx = 0;
467 
468 	/*
469 	 * The table from ACPI is flat, but we store it in a
470 	 * structured array.
471 	 */
472 	for (i = 0; i < ACPI_SAR_NUM_CHAINS_REV2; i++) {
473 		for (j = 0; j < ACPI_SAR_NUM_SUB_BANDS_REV2; j++) {
474 			/* if we don't have the values, use the default */
475 			if (i >= num_chains || j >= num_sub_bands) {
476 				profile->chains[i].subbands[j] = 0;
477 			} else {
478 				if (table[idx].type != ACPI_TYPE_INTEGER ||
479 				    table[idx].integer.value > U8_MAX)
480 					return -EINVAL;
481 
482 				profile->chains[i].subbands[j] =
483 					table[idx].integer.value;
484 
485 				idx++;
486 			}
487 		}
488 	}
489 
490 	/* Only if all values were valid can the profile be enabled */
491 	profile->enabled = enabled;
492 
493 	return 0;
494 }
495 
496 static int iwl_sar_fill_table(struct iwl_fw_runtime *fwrt,
497 			      __le16 *per_chain, u32 n_subbands,
498 			      int prof_a, int prof_b)
499 {
500 	int profs[ACPI_SAR_NUM_CHAINS_REV0] = { prof_a, prof_b };
501 	int i, j;
502 
503 	for (i = 0; i < ACPI_SAR_NUM_CHAINS_REV0; i++) {
504 		struct iwl_sar_profile *prof;
505 
506 		/* don't allow SAR to be disabled (profile 0 means disable) */
507 		if (profs[i] == 0)
508 			return -EPERM;
509 
510 		/* we are off by one, so allow up to ACPI_SAR_PROFILE_NUM */
511 		if (profs[i] > ACPI_SAR_PROFILE_NUM)
512 			return -EINVAL;
513 
514 		/* profiles go from 1 to 4, so decrement to access the array */
515 		prof = &fwrt->sar_profiles[profs[i] - 1];
516 
517 		/* if the profile is disabled, do nothing */
518 		if (!prof->enabled) {
519 			IWL_DEBUG_RADIO(fwrt, "SAR profile %d is disabled.\n",
520 					profs[i]);
521 			/*
522 			 * if one of the profiles is disabled, we
523 			 * ignore all of them and return 1 to
524 			 * differentiate disabled from other failures.
525 			 */
526 			return 1;
527 		}
528 
529 		IWL_DEBUG_INFO(fwrt,
530 			       "SAR EWRD: chain %d profile index %d\n",
531 			       i, profs[i]);
532 		IWL_DEBUG_RADIO(fwrt, "  Chain[%d]:\n", i);
533 		for (j = 0; j < n_subbands; j++) {
534 			per_chain[i * n_subbands + j] =
535 				cpu_to_le16(prof->chains[i].subbands[j]);
536 			IWL_DEBUG_RADIO(fwrt, "    Band[%d] = %d * .125dBm\n",
537 					j, prof->chains[i].subbands[j]);
538 		}
539 	}
540 
541 	return 0;
542 }
543 
544 int iwl_sar_select_profile(struct iwl_fw_runtime *fwrt,
545 			   __le16 *per_chain, u32 n_tables, u32 n_subbands,
546 			   int prof_a, int prof_b)
547 {
548 	int i, ret = 0;
549 
550 	for (i = 0; i < n_tables; i++) {
551 		ret = iwl_sar_fill_table(fwrt,
552 			 &per_chain[i * n_subbands * ACPI_SAR_NUM_CHAINS_REV0],
553 			 n_subbands, prof_a, prof_b);
554 		if (ret)
555 			break;
556 	}
557 
558 	return ret;
559 }
560 IWL_EXPORT_SYMBOL(iwl_sar_select_profile);
561 
562 int iwl_sar_get_wrds_table(struct iwl_fw_runtime *fwrt)
563 {
564 	union acpi_object *wifi_pkg, *table, *data;
565 	int ret, tbl_rev;
566 	u32 flags;
567 	u8 num_chains, num_sub_bands;
568 
569 	data = iwl_acpi_get_object(fwrt->dev, ACPI_WRDS_METHOD);
570 	if (IS_ERR(data))
571 		return PTR_ERR(data);
572 
573 	/* start by trying to read revision 2 */
574 	wifi_pkg = iwl_acpi_get_wifi_pkg(fwrt->dev, data,
575 					 ACPI_WRDS_WIFI_DATA_SIZE_REV2,
576 					 &tbl_rev);
577 	if (!IS_ERR(wifi_pkg)) {
578 		if (tbl_rev != 2) {
579 			ret = PTR_ERR(wifi_pkg);
580 			goto out_free;
581 		}
582 
583 		num_chains = ACPI_SAR_NUM_CHAINS_REV2;
584 		num_sub_bands = ACPI_SAR_NUM_SUB_BANDS_REV2;
585 
586 		goto read_table;
587 	}
588 
589 	/* then try revision 1 */
590 	wifi_pkg = iwl_acpi_get_wifi_pkg(fwrt->dev, data,
591 					 ACPI_WRDS_WIFI_DATA_SIZE_REV1,
592 					 &tbl_rev);
593 	if (!IS_ERR(wifi_pkg)) {
594 		if (tbl_rev != 1) {
595 			ret = PTR_ERR(wifi_pkg);
596 			goto out_free;
597 		}
598 
599 		num_chains = ACPI_SAR_NUM_CHAINS_REV1;
600 		num_sub_bands = ACPI_SAR_NUM_SUB_BANDS_REV1;
601 
602 		goto read_table;
603 	}
604 
605 	/* then finally revision 0 */
606 	wifi_pkg = iwl_acpi_get_wifi_pkg(fwrt->dev, data,
607 					 ACPI_WRDS_WIFI_DATA_SIZE_REV0,
608 					 &tbl_rev);
609 	if (!IS_ERR(wifi_pkg)) {
610 		if (tbl_rev != 0) {
611 			ret = PTR_ERR(wifi_pkg);
612 			goto out_free;
613 		}
614 
615 		num_chains = ACPI_SAR_NUM_CHAINS_REV0;
616 		num_sub_bands = ACPI_SAR_NUM_SUB_BANDS_REV0;
617 
618 		goto read_table;
619 	}
620 
621 	ret = PTR_ERR(wifi_pkg);
622 	goto out_free;
623 
624 read_table:
625 	if (wifi_pkg->package.elements[1].type != ACPI_TYPE_INTEGER) {
626 		ret = -EINVAL;
627 		goto out_free;
628 	}
629 
630 	IWL_DEBUG_RADIO(fwrt, "Reading WRDS tbl_rev=%d\n", tbl_rev);
631 
632 	flags = wifi_pkg->package.elements[1].integer.value;
633 	fwrt->reduced_power_flags = flags >> IWL_REDUCE_POWER_FLAGS_POS;
634 
635 	/* position of the actual table */
636 	table = &wifi_pkg->package.elements[2];
637 
638 	/* The profile from WRDS is officially profile 1, but goes
639 	 * into sar_profiles[0] (because we don't have a profile 0).
640 	 */
641 	ret = iwl_sar_set_profile(table, &fwrt->sar_profiles[0],
642 				  flags & IWL_SAR_ENABLE_MSK,
643 				  num_chains, num_sub_bands);
644 out_free:
645 	kfree(data);
646 	return ret;
647 }
648 IWL_EXPORT_SYMBOL(iwl_sar_get_wrds_table);
649 
650 int iwl_sar_get_ewrd_table(struct iwl_fw_runtime *fwrt)
651 {
652 	union acpi_object *wifi_pkg, *data;
653 	bool enabled;
654 	int i, n_profiles, tbl_rev, pos;
655 	int ret = 0;
656 	u8 num_chains, num_sub_bands;
657 
658 	data = iwl_acpi_get_object(fwrt->dev, ACPI_EWRD_METHOD);
659 	if (IS_ERR(data))
660 		return PTR_ERR(data);
661 
662 	/* start by trying to read revision 2 */
663 	wifi_pkg = iwl_acpi_get_wifi_pkg(fwrt->dev, data,
664 					 ACPI_EWRD_WIFI_DATA_SIZE_REV2,
665 					 &tbl_rev);
666 	if (!IS_ERR(wifi_pkg)) {
667 		if (tbl_rev != 2) {
668 			ret = PTR_ERR(wifi_pkg);
669 			goto out_free;
670 		}
671 
672 		num_chains = ACPI_SAR_NUM_CHAINS_REV2;
673 		num_sub_bands = ACPI_SAR_NUM_SUB_BANDS_REV2;
674 
675 		goto read_table;
676 	}
677 
678 	/* then try revision 1 */
679 	wifi_pkg = iwl_acpi_get_wifi_pkg(fwrt->dev, data,
680 					 ACPI_EWRD_WIFI_DATA_SIZE_REV1,
681 					 &tbl_rev);
682 	if (!IS_ERR(wifi_pkg)) {
683 		if (tbl_rev != 1) {
684 			ret = PTR_ERR(wifi_pkg);
685 			goto out_free;
686 		}
687 
688 		num_chains = ACPI_SAR_NUM_CHAINS_REV1;
689 		num_sub_bands = ACPI_SAR_NUM_SUB_BANDS_REV1;
690 
691 		goto read_table;
692 	}
693 
694 	/* then finally revision 0 */
695 	wifi_pkg = iwl_acpi_get_wifi_pkg(fwrt->dev, data,
696 					 ACPI_EWRD_WIFI_DATA_SIZE_REV0,
697 					 &tbl_rev);
698 	if (!IS_ERR(wifi_pkg)) {
699 		if (tbl_rev != 0) {
700 			ret = PTR_ERR(wifi_pkg);
701 			goto out_free;
702 		}
703 
704 		num_chains = ACPI_SAR_NUM_CHAINS_REV0;
705 		num_sub_bands = ACPI_SAR_NUM_SUB_BANDS_REV0;
706 
707 		goto read_table;
708 	}
709 
710 	ret = PTR_ERR(wifi_pkg);
711 	goto out_free;
712 
713 read_table:
714 	if (wifi_pkg->package.elements[1].type != ACPI_TYPE_INTEGER ||
715 	    wifi_pkg->package.elements[2].type != ACPI_TYPE_INTEGER) {
716 		ret = -EINVAL;
717 		goto out_free;
718 	}
719 
720 	enabled = !!(wifi_pkg->package.elements[1].integer.value);
721 	n_profiles = wifi_pkg->package.elements[2].integer.value;
722 
723 	/*
724 	 * Check the validity of n_profiles.  The EWRD profiles start
725 	 * from index 1, so the maximum value allowed here is
726 	 * ACPI_SAR_PROFILES_NUM - 1.
727 	 */
728 	if (n_profiles <= 0 || n_profiles >= ACPI_SAR_PROFILE_NUM) {
729 		ret = -EINVAL;
730 		goto out_free;
731 	}
732 
733 	/* the tables start at element 3 */
734 	pos = 3;
735 
736 	for (i = 0; i < n_profiles; i++) {
737 		/* The EWRD profiles officially go from 2 to 4, but we
738 		 * save them in sar_profiles[1-3] (because we don't
739 		 * have profile 0).  So in the array we start from 1.
740 		 */
741 		ret = iwl_sar_set_profile(&wifi_pkg->package.elements[pos],
742 					  &fwrt->sar_profiles[i + 1], enabled,
743 					  num_chains, num_sub_bands);
744 		if (ret < 0)
745 			break;
746 
747 		/* go to the next table */
748 		pos += num_chains * num_sub_bands;
749 	}
750 
751 out_free:
752 	kfree(data);
753 	return ret;
754 }
755 IWL_EXPORT_SYMBOL(iwl_sar_get_ewrd_table);
756 
757 int iwl_sar_get_wgds_table(struct iwl_fw_runtime *fwrt)
758 {
759 	union acpi_object *wifi_pkg, *data;
760 	int i, j, k, ret, tbl_rev;
761 	u8 num_bands, num_profiles;
762 	static const struct {
763 		u8 revisions;
764 		u8 bands;
765 		u8 profiles;
766 		u8 min_profiles;
767 	} rev_data[] = {
768 		{
769 			.revisions = BIT(3),
770 			.bands = ACPI_GEO_NUM_BANDS_REV2,
771 			.profiles = ACPI_NUM_GEO_PROFILES_REV3,
772 			.min_profiles = 3,
773 		},
774 		{
775 			.revisions = BIT(2),
776 			.bands = ACPI_GEO_NUM_BANDS_REV2,
777 			.profiles = ACPI_NUM_GEO_PROFILES,
778 		},
779 		{
780 			.revisions = BIT(0) | BIT(1),
781 			.bands = ACPI_GEO_NUM_BANDS_REV0,
782 			.profiles = ACPI_NUM_GEO_PROFILES,
783 		},
784 	};
785 	int idx;
786 	/* start from one to skip the domain */
787 	int entry_idx = 1;
788 
789 	BUILD_BUG_ON(ACPI_NUM_GEO_PROFILES_REV3 != IWL_NUM_GEO_PROFILES_V3);
790 	BUILD_BUG_ON(ACPI_NUM_GEO_PROFILES != IWL_NUM_GEO_PROFILES);
791 
792 	data = iwl_acpi_get_object(fwrt->dev, ACPI_WGDS_METHOD);
793 	if (IS_ERR(data))
794 		return PTR_ERR(data);
795 
796 	/* read the highest revision we understand first */
797 	for (idx = 0; idx < ARRAY_SIZE(rev_data); idx++) {
798 		/* min_profiles != 0 requires num_profiles header */
799 		u32 hdr_size = 1 + !!rev_data[idx].min_profiles;
800 		u32 profile_size = ACPI_GEO_PER_CHAIN_SIZE *
801 				   rev_data[idx].bands;
802 		u32 max_size = hdr_size + profile_size * rev_data[idx].profiles;
803 		u32 min_size;
804 
805 		if (!rev_data[idx].min_profiles)
806 			min_size = max_size;
807 		else
808 			min_size = hdr_size +
809 				   profile_size * rev_data[idx].min_profiles;
810 
811 		wifi_pkg = iwl_acpi_get_wifi_pkg_range(fwrt->dev, data,
812 						       min_size, max_size,
813 						       &tbl_rev);
814 		if (!IS_ERR(wifi_pkg)) {
815 			if (!(BIT(tbl_rev) & rev_data[idx].revisions))
816 				continue;
817 
818 			num_bands = rev_data[idx].bands;
819 			num_profiles = rev_data[idx].profiles;
820 
821 			if (rev_data[idx].min_profiles) {
822 				/* read header that says # of profiles */
823 				union acpi_object *entry;
824 
825 				entry = &wifi_pkg->package.elements[entry_idx];
826 				entry_idx++;
827 				if (entry->type != ACPI_TYPE_INTEGER ||
828 				    entry->integer.value > num_profiles) {
829 					ret = -EINVAL;
830 					goto out_free;
831 				}
832 				num_profiles = entry->integer.value;
833 
834 				/*
835 				 * this also validates >= min_profiles since we
836 				 * otherwise wouldn't have gotten the data when
837 				 * looking up in ACPI
838 				 */
839 				if (wifi_pkg->package.count !=
840 				    hdr_size + profile_size * num_profiles) {
841 					ret = -EINVAL;
842 					goto out_free;
843 				}
844 			}
845 			goto read_table;
846 		}
847 	}
848 
849 	if (idx < ARRAY_SIZE(rev_data))
850 		ret = PTR_ERR(wifi_pkg);
851 	else
852 		ret = -ENOENT;
853 	goto out_free;
854 
855 read_table:
856 	fwrt->geo_rev = tbl_rev;
857 	for (i = 0; i < num_profiles; i++) {
858 		for (j = 0; j < ACPI_GEO_NUM_BANDS_REV2; j++) {
859 			union acpi_object *entry;
860 
861 			/*
862 			 * num_bands is either 2 or 3, if it's only 2 then
863 			 * fill the third band (6 GHz) with the values from
864 			 * 5 GHz (second band)
865 			 */
866 			if (j >= num_bands) {
867 				fwrt->geo_profiles[i].bands[j].max =
868 					fwrt->geo_profiles[i].bands[1].max;
869 			} else {
870 				entry = &wifi_pkg->package.elements[entry_idx];
871 				entry_idx++;
872 				if (entry->type != ACPI_TYPE_INTEGER ||
873 				    entry->integer.value > U8_MAX) {
874 					ret = -EINVAL;
875 					goto out_free;
876 				}
877 
878 				fwrt->geo_profiles[i].bands[j].max =
879 					entry->integer.value;
880 			}
881 
882 			for (k = 0; k < ACPI_GEO_NUM_CHAINS; k++) {
883 				/* same here as above */
884 				if (j >= num_bands) {
885 					fwrt->geo_profiles[i].bands[j].chains[k] =
886 						fwrt->geo_profiles[i].bands[1].chains[k];
887 				} else {
888 					entry = &wifi_pkg->package.elements[entry_idx];
889 					entry_idx++;
890 					if (entry->type != ACPI_TYPE_INTEGER ||
891 					    entry->integer.value > U8_MAX) {
892 						ret = -EINVAL;
893 						goto out_free;
894 					}
895 
896 					fwrt->geo_profiles[i].bands[j].chains[k] =
897 						entry->integer.value;
898 				}
899 			}
900 		}
901 	}
902 
903 	fwrt->geo_num_profiles = num_profiles;
904 	fwrt->geo_enabled = true;
905 	ret = 0;
906 out_free:
907 	kfree(data);
908 	return ret;
909 }
910 IWL_EXPORT_SYMBOL(iwl_sar_get_wgds_table);
911 
912 bool iwl_sar_geo_support(struct iwl_fw_runtime *fwrt)
913 {
914 	/*
915 	 * The PER_CHAIN_LIMIT_OFFSET_CMD command is not supported on
916 	 * earlier firmware versions.  Unfortunately, we don't have a
917 	 * TLV API flag to rely on, so rely on the major version which
918 	 * is in the first byte of ucode_ver.  This was implemented
919 	 * initially on version 38 and then backported to 17.  It was
920 	 * also backported to 29, but only for 7265D devices.  The
921 	 * intention was to have it in 36 as well, but not all 8000
922 	 * family got this feature enabled.  The 8000 family is the
923 	 * only one using version 36, so skip this version entirely.
924 	 */
925 	return IWL_UCODE_SERIAL(fwrt->fw->ucode_ver) >= 38 ||
926 		(IWL_UCODE_SERIAL(fwrt->fw->ucode_ver) == 17 &&
927 		 fwrt->trans->hw_rev != CSR_HW_REV_TYPE_3160) ||
928 		(IWL_UCODE_SERIAL(fwrt->fw->ucode_ver) == 29 &&
929 		 ((fwrt->trans->hw_rev & CSR_HW_REV_TYPE_MSK) ==
930 		  CSR_HW_REV_TYPE_7265D));
931 }
932 IWL_EXPORT_SYMBOL(iwl_sar_geo_support);
933 
934 int iwl_sar_geo_init(struct iwl_fw_runtime *fwrt,
935 		     struct iwl_per_chain_offset *table,
936 		     u32 n_bands, u32 n_profiles)
937 {
938 	int i, j;
939 
940 	if (!iwl_sar_geo_support(fwrt))
941 		return -EOPNOTSUPP;
942 
943 	for (i = 0; i < n_profiles; i++) {
944 		for (j = 0; j < n_bands; j++) {
945 			struct iwl_per_chain_offset *chain =
946 				&table[i * n_bands + j];
947 
948 			chain->max_tx_power =
949 				cpu_to_le16(fwrt->geo_profiles[i].bands[j].max);
950 			chain->chain_a = fwrt->geo_profiles[i].bands[j].chains[0];
951 			chain->chain_b = fwrt->geo_profiles[i].bands[j].chains[1];
952 			IWL_DEBUG_RADIO(fwrt,
953 					"SAR geographic profile[%d] Band[%d]: chain A = %d chain B = %d max_tx_power = %d\n",
954 					i, j,
955 					fwrt->geo_profiles[i].bands[j].chains[0],
956 					fwrt->geo_profiles[i].bands[j].chains[1],
957 					fwrt->geo_profiles[i].bands[j].max);
958 		}
959 	}
960 
961 	return 0;
962 }
963 IWL_EXPORT_SYMBOL(iwl_sar_geo_init);
964 
965 __le32 iwl_acpi_get_lari_config_bitmap(struct iwl_fw_runtime *fwrt)
966 {
967 	int ret;
968 	u8 value;
969 	__le32 config_bitmap = 0;
970 
971 	/*
972 	 ** Evaluate func 'DSM_FUNC_ENABLE_INDONESIA_5G2'
973 	 */
974 	ret = iwl_acpi_get_dsm_u8(fwrt->dev, 0,
975 				  DSM_FUNC_ENABLE_INDONESIA_5G2,
976 				  &iwl_guid, &value);
977 
978 	if (!ret && value == DSM_VALUE_INDONESIA_ENABLE)
979 		config_bitmap |=
980 			cpu_to_le32(LARI_CONFIG_ENABLE_5G2_IN_INDONESIA_MSK);
981 
982 	/*
983 	 ** Evaluate func 'DSM_FUNC_DISABLE_SRD'
984 	 */
985 	ret = iwl_acpi_get_dsm_u8(fwrt->dev, 0,
986 				  DSM_FUNC_DISABLE_SRD,
987 				  &iwl_guid, &value);
988 	if (!ret) {
989 		if (value == DSM_VALUE_SRD_PASSIVE)
990 			config_bitmap |=
991 				cpu_to_le32(LARI_CONFIG_CHANGE_ETSI_TO_PASSIVE_MSK);
992 		else if (value == DSM_VALUE_SRD_DISABLE)
993 			config_bitmap |=
994 				cpu_to_le32(LARI_CONFIG_CHANGE_ETSI_TO_DISABLED_MSK);
995 	}
996 
997 	return config_bitmap;
998 }
999 IWL_EXPORT_SYMBOL(iwl_acpi_get_lari_config_bitmap);
1000 
1001 int iwl_acpi_get_ppag_table(struct iwl_fw_runtime *fwrt)
1002 {
1003 	union acpi_object *wifi_pkg, *data, *flags;
1004 	int i, j, ret, tbl_rev, num_sub_bands = 0;
1005 	int idx = 2;
1006 
1007 	fwrt->ppag_flags = 0;
1008 
1009 	data = iwl_acpi_get_object(fwrt->dev, ACPI_PPAG_METHOD);
1010 	if (IS_ERR(data))
1011 		return PTR_ERR(data);
1012 
1013 	/* try to read ppag table rev 2 or 1 (both have the same data size) */
1014 	wifi_pkg = iwl_acpi_get_wifi_pkg(fwrt->dev, data,
1015 				ACPI_PPAG_WIFI_DATA_SIZE_V2, &tbl_rev);
1016 
1017 	if (!IS_ERR(wifi_pkg)) {
1018 		if (tbl_rev == 1 || tbl_rev == 2) {
1019 			num_sub_bands = IWL_NUM_SUB_BANDS_V2;
1020 			IWL_DEBUG_RADIO(fwrt,
1021 					"Reading PPAG table v2 (tbl_rev=%d)\n",
1022 					tbl_rev);
1023 			goto read_table;
1024 		} else {
1025 			ret = -EINVAL;
1026 			goto out_free;
1027 		}
1028 	}
1029 
1030 	/* try to read ppag table revision 0 */
1031 	wifi_pkg = iwl_acpi_get_wifi_pkg(fwrt->dev, data,
1032 			ACPI_PPAG_WIFI_DATA_SIZE_V1, &tbl_rev);
1033 
1034 	if (!IS_ERR(wifi_pkg)) {
1035 		if (tbl_rev != 0) {
1036 			ret = -EINVAL;
1037 			goto out_free;
1038 		}
1039 		num_sub_bands = IWL_NUM_SUB_BANDS_V1;
1040 		IWL_DEBUG_RADIO(fwrt, "Reading PPAG table v1 (tbl_rev=0)\n");
1041 		goto read_table;
1042 	}
1043 
1044 read_table:
1045 	fwrt->ppag_ver = tbl_rev;
1046 	flags = &wifi_pkg->package.elements[1];
1047 
1048 	if (flags->type != ACPI_TYPE_INTEGER) {
1049 		ret = -EINVAL;
1050 		goto out_free;
1051 	}
1052 
1053 	fwrt->ppag_flags = flags->integer.value & ACPI_PPAG_MASK;
1054 
1055 	if (!fwrt->ppag_flags) {
1056 		ret = 0;
1057 		goto out_free;
1058 	}
1059 
1060 	/*
1061 	 * read, verify gain values and save them into the PPAG table.
1062 	 * first sub-band (j=0) corresponds to Low-Band (2.4GHz), and the
1063 	 * following sub-bands to High-Band (5GHz).
1064 	 */
1065 	for (i = 0; i < IWL_NUM_CHAIN_LIMITS; i++) {
1066 		for (j = 0; j < num_sub_bands; j++) {
1067 			union acpi_object *ent;
1068 
1069 			ent = &wifi_pkg->package.elements[idx++];
1070 			if (ent->type != ACPI_TYPE_INTEGER) {
1071 				ret = -EINVAL;
1072 				goto out_free;
1073 			}
1074 
1075 			fwrt->ppag_chains[i].subbands[j] = ent->integer.value;
1076 
1077 			if ((j == 0 &&
1078 				(fwrt->ppag_chains[i].subbands[j] > ACPI_PPAG_MAX_LB ||
1079 				 fwrt->ppag_chains[i].subbands[j] < ACPI_PPAG_MIN_LB)) ||
1080 				(j != 0 &&
1081 				(fwrt->ppag_chains[i].subbands[j] > ACPI_PPAG_MAX_HB ||
1082 				fwrt->ppag_chains[i].subbands[j] < ACPI_PPAG_MIN_HB))) {
1083 					fwrt->ppag_flags = 0;
1084 					ret = -EINVAL;
1085 					goto out_free;
1086 				}
1087 		}
1088 	}
1089 
1090 
1091 	ret = 0;
1092 
1093 out_free:
1094 	kfree(data);
1095 	return ret;
1096 }
1097 IWL_EXPORT_SYMBOL(iwl_acpi_get_ppag_table);
1098 
1099 int iwl_read_ppag_table(struct iwl_fw_runtime *fwrt, union iwl_ppag_table_cmd *cmd,
1100 			int *cmd_size)
1101 {
1102         u8 cmd_ver;
1103         int i, j, num_sub_bands;
1104         s8 *gain;
1105 
1106         if (!fw_has_capa(&fwrt->fw->ucode_capa, IWL_UCODE_TLV_CAPA_SET_PPAG)) {
1107                 IWL_DEBUG_RADIO(fwrt,
1108                                 "PPAG capability not supported by FW, command not sent.\n");
1109                 return -EINVAL;
1110         }
1111         if (!fwrt->ppag_flags) {
1112                 IWL_DEBUG_RADIO(fwrt, "PPAG not enabled, command not sent.\n");
1113                 return -EINVAL;
1114         }
1115 
1116         /* The 'flags' field is the same in v1 and in v2 so we can just
1117          * use v1 to access it.
1118          */
1119         cmd->v1.flags = cpu_to_le32(fwrt->ppag_flags);
1120         cmd_ver = iwl_fw_lookup_cmd_ver(fwrt->fw,
1121                                         WIDE_ID(PHY_OPS_GROUP, PER_PLATFORM_ANT_GAIN_CMD),
1122                                         IWL_FW_CMD_VER_UNKNOWN);
1123 	if (cmd_ver == 1) {
1124                 num_sub_bands = IWL_NUM_SUB_BANDS_V1;
1125                 gain = cmd->v1.gain[0];
1126                 *cmd_size = sizeof(cmd->v1);
1127                 if (fwrt->ppag_ver == 1 || fwrt->ppag_ver == 2) {
1128                         IWL_DEBUG_RADIO(fwrt,
1129                                         "PPAG table rev is %d but FW supports v1, sending truncated table\n",
1130                                         fwrt->ppag_ver);
1131                         cmd->v1.flags &= cpu_to_le32(IWL_PPAG_ETSI_MASK);
1132 		}
1133 	} else if (cmd_ver == 2 || cmd_ver == 3) {
1134                 num_sub_bands = IWL_NUM_SUB_BANDS_V2;
1135                 gain = cmd->v2.gain[0];
1136                 *cmd_size = sizeof(cmd->v2);
1137                 if (fwrt->ppag_ver == 0) {
1138                         IWL_DEBUG_RADIO(fwrt,
1139                                         "PPAG table is v1 but FW supports v2, sending padded table\n");
1140                 } else if (cmd_ver == 2 && fwrt->ppag_ver == 2) {
1141                         IWL_DEBUG_RADIO(fwrt,
1142                                         "PPAG table is v3 but FW supports v2, sending partial bitmap.\n");
1143                         cmd->v1.flags &= cpu_to_le32(IWL_PPAG_ETSI_MASK);
1144                 }
1145         } else {
1146                 IWL_DEBUG_RADIO(fwrt, "Unsupported PPAG command version\n");
1147                 return -EINVAL;
1148         }
1149 
1150 	for (i = 0; i < IWL_NUM_CHAIN_LIMITS; i++) {
1151                 for (j = 0; j < num_sub_bands; j++) {
1152                         gain[i * num_sub_bands + j] =
1153                                 fwrt->ppag_chains[i].subbands[j];
1154                         IWL_DEBUG_RADIO(fwrt,
1155                                         "PPAG table: chain[%d] band[%d]: gain = %d\n",
1156                                         i, j, gain[i * num_sub_bands + j]);
1157                 }
1158         }
1159 
1160 	return 0;
1161 }
1162 IWL_EXPORT_SYMBOL(iwl_read_ppag_table);
1163 
1164 bool iwl_acpi_is_ppag_approved(struct iwl_fw_runtime *fwrt)
1165 {
1166 
1167 	if (!dmi_check_system(dmi_ppag_approved_list)) {
1168 		IWL_DEBUG_RADIO(fwrt,
1169 			"System vendor '%s' is not in the approved list, disabling PPAG.\n",
1170 			dmi_get_system_info(DMI_SYS_VENDOR));
1171 			fwrt->ppag_flags = 0;
1172 			return false;
1173 	}
1174 
1175 	return true;
1176 }
1177 IWL_EXPORT_SYMBOL(iwl_acpi_is_ppag_approved);
1178