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