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