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