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
13const guid_t iwl_guid = GUID_INIT(0xF21202BF, 0x8F78, 0x4DC6,
14				  0xA5, 0xB3, 0x1F, 0x73,
15				  0x8E, 0x28, 0x5A, 0xDE);
16IWL_EXPORT_SYMBOL(iwl_guid);
17
18const guid_t iwl_rfi_guid = GUID_INIT(0x7266172C, 0x220B, 0x4B29,
19				      0x81, 0x4F, 0x75, 0xE4,
20				      0xDD, 0x26, 0xB5, 0xFD);
21IWL_EXPORT_SYMBOL(iwl_rfi_guid);
22
23static 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
80static 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
102static 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 */
129static 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 */
153static 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);
197out:
198	ACPI_FREE(obj);
199	return ret;
200}
201
202/*
203 * Evaluate a DSM with no arguments and a u8 return value,
204 */
205int 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}
221IWL_EXPORT_SYMBOL(iwl_acpi_get_dsm_u8);
222
223/*
224 * Evaluate a DSM with no arguments and a u32 return value,
225 */
226int 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}
242IWL_EXPORT_SYMBOL(iwl_acpi_get_dsm_u32);
243
244static union acpi_object *
245iwl_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
297found:
298	return wifi_pkg;
299}
300
301static union acpi_object *
302iwl_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
311int 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;
402out_free:
403	kfree(data);
404	return ret;
405}
406IWL_EXPORT_SYMBOL(iwl_acpi_get_tas);
407
408int 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;
438out_free:
439	kfree(data);
440	return ret;
441}
442IWL_EXPORT_SYMBOL(iwl_acpi_get_mcc);
443
444u64 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;
465out_free:
466	kfree(data);
467out:
468	return dflt_pwr_limit;
469}
470IWL_EXPORT_SYMBOL(iwl_acpi_get_pwr_limit);
471
472int 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
498out_free:
499	kfree(data);
500	return ret;
501}
502IWL_EXPORT_SYMBOL(iwl_acpi_get_eckv);
503
504static 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
538static 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
586int 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}
602IWL_EXPORT_SYMBOL(iwl_sar_select_profile);
603
604int 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
666read_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);
686out_free:
687	kfree(data);
688	return ret;
689}
690IWL_EXPORT_SYMBOL(iwl_sar_get_wrds_table);
691
692int 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
755read_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 >= 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
793out_free:
794	kfree(data);
795	return ret;
796}
797IWL_EXPORT_SYMBOL(iwl_sar_get_ewrd_table);
798
799int 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
897read_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;
948out_free:
949	kfree(data);
950	return ret;
951}
952IWL_EXPORT_SYMBOL(iwl_sar_get_wgds_table);
953
954bool 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}
974IWL_EXPORT_SYMBOL(iwl_sar_geo_support);
975
976int 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}
1008IWL_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	__le32 config_bitmap = 0;
1015
1016	/*
1017	 ** Evaluate func 'DSM_FUNC_ENABLE_INDONESIA_5G2'
1018	 */
1019	ret = iwl_acpi_get_dsm_u8(fwrt->dev, 0,
1020				  DSM_FUNC_ENABLE_INDONESIA_5G2,
1021				  &iwl_guid, &value);
1022
1023	if (!ret && value == DSM_VALUE_INDONESIA_ENABLE)
1024		config_bitmap |=
1025			cpu_to_le32(LARI_CONFIG_ENABLE_5G2_IN_INDONESIA_MSK);
1026
1027	/*
1028	 ** Evaluate func 'DSM_FUNC_DISABLE_SRD'
1029	 */
1030	ret = iwl_acpi_get_dsm_u8(fwrt->dev, 0,
1031				  DSM_FUNC_DISABLE_SRD,
1032				  &iwl_guid, &value);
1033	if (!ret) {
1034		if (value == DSM_VALUE_SRD_PASSIVE)
1035			config_bitmap |=
1036				cpu_to_le32(LARI_CONFIG_CHANGE_ETSI_TO_PASSIVE_MSK);
1037		else if (value == DSM_VALUE_SRD_DISABLE)
1038			config_bitmap |=
1039				cpu_to_le32(LARI_CONFIG_CHANGE_ETSI_TO_DISABLED_MSK);
1040	}
1041
1042	return config_bitmap;
1043}
1044IWL_EXPORT_SYMBOL(iwl_acpi_get_lari_config_bitmap);
1045
1046int iwl_acpi_get_ppag_table(struct iwl_fw_runtime *fwrt)
1047{
1048	union acpi_object *wifi_pkg, *data, *flags;
1049	int i, j, ret, tbl_rev, num_sub_bands = 0;
1050	int idx = 2;
1051	u8 cmd_ver;
1052
1053	fwrt->ppag_flags = 0;
1054	fwrt->ppag_table_valid = false;
1055
1056	data = iwl_acpi_get_object(fwrt->dev, ACPI_PPAG_METHOD);
1057	if (IS_ERR(data))
1058		return PTR_ERR(data);
1059
1060	/* try to read ppag table rev 2 or 1 (both have the same data size) */
1061	wifi_pkg = iwl_acpi_get_wifi_pkg(fwrt->dev, data,
1062				ACPI_PPAG_WIFI_DATA_SIZE_V2, &tbl_rev);
1063
1064	if (!IS_ERR(wifi_pkg)) {
1065		if (tbl_rev == 1 || tbl_rev == 2) {
1066			num_sub_bands = IWL_NUM_SUB_BANDS_V2;
1067			IWL_DEBUG_RADIO(fwrt,
1068					"Reading PPAG table v2 (tbl_rev=%d)\n",
1069					tbl_rev);
1070			goto read_table;
1071		} else {
1072			ret = -EINVAL;
1073			goto out_free;
1074		}
1075	}
1076
1077	/* try to read ppag table revision 0 */
1078	wifi_pkg = iwl_acpi_get_wifi_pkg(fwrt->dev, data,
1079			ACPI_PPAG_WIFI_DATA_SIZE_V1, &tbl_rev);
1080
1081	if (!IS_ERR(wifi_pkg)) {
1082		if (tbl_rev != 0) {
1083			ret = -EINVAL;
1084			goto out_free;
1085		}
1086		num_sub_bands = IWL_NUM_SUB_BANDS_V1;
1087		IWL_DEBUG_RADIO(fwrt, "Reading PPAG table v1 (tbl_rev=0)\n");
1088		goto read_table;
1089	}
1090
1091	ret = PTR_ERR(wifi_pkg);
1092	goto out_free;
1093
1094read_table:
1095	fwrt->ppag_ver = tbl_rev;
1096	flags = &wifi_pkg->package.elements[1];
1097
1098	if (flags->type != ACPI_TYPE_INTEGER) {
1099		ret = -EINVAL;
1100		goto out_free;
1101	}
1102
1103	fwrt->ppag_flags = flags->integer.value & ACPI_PPAG_MASK;
1104	cmd_ver = iwl_fw_lookup_cmd_ver(fwrt->fw,
1105					WIDE_ID(PHY_OPS_GROUP,
1106						PER_PLATFORM_ANT_GAIN_CMD),
1107					IWL_FW_CMD_VER_UNKNOWN);
1108	if (cmd_ver == IWL_FW_CMD_VER_UNKNOWN) {
1109		ret = -EINVAL;
1110		goto out_free;
1111	}
1112	if (!fwrt->ppag_flags && cmd_ver <= 3) {
1113		ret = 0;
1114		goto out_free;
1115	}
1116
1117	/*
1118	 * read, verify gain values and save them into the PPAG table.
1119	 * first sub-band (j=0) corresponds to Low-Band (2.4GHz), and the
1120	 * following sub-bands to High-Band (5GHz).
1121	 */
1122	for (i = 0; i < IWL_NUM_CHAIN_LIMITS; i++) {
1123		for (j = 0; j < num_sub_bands; j++) {
1124			union acpi_object *ent;
1125
1126			ent = &wifi_pkg->package.elements[idx++];
1127			if (ent->type != ACPI_TYPE_INTEGER) {
1128				ret = -EINVAL;
1129				goto out_free;
1130			}
1131
1132			fwrt->ppag_chains[i].subbands[j] = ent->integer.value;
1133			/* from ver 4 the fw deals with out of range values */
1134			if (cmd_ver >= 4)
1135				continue;
1136			if ((j == 0 &&
1137				(fwrt->ppag_chains[i].subbands[j] > ACPI_PPAG_MAX_LB ||
1138				 fwrt->ppag_chains[i].subbands[j] < ACPI_PPAG_MIN_LB)) ||
1139				(j != 0 &&
1140				(fwrt->ppag_chains[i].subbands[j] > ACPI_PPAG_MAX_HB ||
1141				fwrt->ppag_chains[i].subbands[j] < ACPI_PPAG_MIN_HB))) {
1142					ret = -EINVAL;
1143					goto out_free;
1144				}
1145		}
1146	}
1147
1148	fwrt->ppag_table_valid = true;
1149	ret = 0;
1150
1151out_free:
1152	kfree(data);
1153	return ret;
1154}
1155IWL_EXPORT_SYMBOL(iwl_acpi_get_ppag_table);
1156
1157int iwl_read_ppag_table(struct iwl_fw_runtime *fwrt, union iwl_ppag_table_cmd *cmd,
1158			int *cmd_size)
1159{
1160        u8 cmd_ver;
1161        int i, j, num_sub_bands;
1162        s8 *gain;
1163
1164	/* many firmware images for JF lie about this */
1165	if (CSR_HW_RFID_TYPE(fwrt->trans->hw_rf_id) ==
1166	    CSR_HW_RFID_TYPE(CSR_HW_RF_ID_TYPE_JF))
1167		return -EOPNOTSUPP;
1168
1169        if (!fw_has_capa(&fwrt->fw->ucode_capa, IWL_UCODE_TLV_CAPA_SET_PPAG)) {
1170                IWL_DEBUG_RADIO(fwrt,
1171                                "PPAG capability not supported by FW, command not sent.\n");
1172                return -EINVAL;
1173	}
1174
1175	cmd_ver = iwl_fw_lookup_cmd_ver(fwrt->fw,
1176					WIDE_ID(PHY_OPS_GROUP,
1177						PER_PLATFORM_ANT_GAIN_CMD),
1178					IWL_FW_CMD_VER_UNKNOWN);
1179	if (!fwrt->ppag_table_valid || (cmd_ver <= 3 && !fwrt->ppag_flags)) {
1180		IWL_DEBUG_RADIO(fwrt, "PPAG not enabled, command not sent.\n");
1181		return -EINVAL;
1182	}
1183
1184        /* The 'flags' field is the same in v1 and in v2 so we can just
1185         * use v1 to access it.
1186         */
1187        cmd->v1.flags = cpu_to_le32(fwrt->ppag_flags);
1188
1189	IWL_DEBUG_RADIO(fwrt, "PPAG cmd ver is %d\n", cmd_ver);
1190	if (cmd_ver == 1) {
1191                num_sub_bands = IWL_NUM_SUB_BANDS_V1;
1192                gain = cmd->v1.gain[0];
1193                *cmd_size = sizeof(cmd->v1);
1194                if (fwrt->ppag_ver == 1 || fwrt->ppag_ver == 2) {
1195			/* in this case FW supports revision 0 */
1196                        IWL_DEBUG_RADIO(fwrt,
1197					"PPAG table rev is %d, send truncated table\n",
1198                                        fwrt->ppag_ver);
1199		}
1200	} else if (cmd_ver >= 2 && cmd_ver <= 4) {
1201                num_sub_bands = IWL_NUM_SUB_BANDS_V2;
1202                gain = cmd->v2.gain[0];
1203                *cmd_size = sizeof(cmd->v2);
1204                if (fwrt->ppag_ver == 0) {
1205			/* in this case FW supports revisions 1 or 2 */
1206                        IWL_DEBUG_RADIO(fwrt,
1207					"PPAG table rev is 0, send padded table\n");
1208                }
1209        } else {
1210                IWL_DEBUG_RADIO(fwrt, "Unsupported PPAG command version\n");
1211                return -EINVAL;
1212        }
1213
1214	/* ppag mode */
1215	IWL_DEBUG_RADIO(fwrt,
1216			"PPAG MODE bits were read from bios: %d\n",
1217			cmd->v1.flags & cpu_to_le32(ACPI_PPAG_MASK));
1218	if ((cmd_ver == 1 && !fw_has_capa(&fwrt->fw->ucode_capa,
1219					  IWL_UCODE_TLV_CAPA_PPAG_CHINA_BIOS_SUPPORT)) ||
1220	    (cmd_ver == 2 && fwrt->ppag_ver == 2)) {
1221		cmd->v1.flags &= cpu_to_le32(IWL_PPAG_ETSI_MASK);
1222		IWL_DEBUG_RADIO(fwrt, "masking ppag China bit\n");
1223	} else {
1224		IWL_DEBUG_RADIO(fwrt, "isn't masking ppag China bit\n");
1225	}
1226
1227	IWL_DEBUG_RADIO(fwrt,
1228			"PPAG MODE bits going to be sent: %d\n",
1229			cmd->v1.flags & cpu_to_le32(ACPI_PPAG_MASK));
1230
1231	for (i = 0; i < IWL_NUM_CHAIN_LIMITS; i++) {
1232                for (j = 0; j < num_sub_bands; j++) {
1233                        gain[i * num_sub_bands + j] =
1234                                fwrt->ppag_chains[i].subbands[j];
1235                        IWL_DEBUG_RADIO(fwrt,
1236                                        "PPAG table: chain[%d] band[%d]: gain = %d\n",
1237                                        i, j, gain[i * num_sub_bands + j]);
1238                }
1239        }
1240
1241	return 0;
1242}
1243IWL_EXPORT_SYMBOL(iwl_read_ppag_table);
1244
1245bool iwl_acpi_is_ppag_approved(struct iwl_fw_runtime *fwrt)
1246{
1247
1248	if (!dmi_check_system(dmi_ppag_approved_list)) {
1249		IWL_DEBUG_RADIO(fwrt,
1250			"System vendor '%s' is not in the approved list, disabling PPAG.\n",
1251			dmi_get_system_info(DMI_SYS_VENDOR));
1252			fwrt->ppag_flags = 0;
1253			return false;
1254	}
1255
1256	return true;
1257}
1258IWL_EXPORT_SYMBOL(iwl_acpi_is_ppag_approved);
1259
1260void iwl_acpi_get_phy_filters(struct iwl_fw_runtime *fwrt,
1261			      struct iwl_phy_specific_cfg *filters)
1262{
1263	struct iwl_phy_specific_cfg tmp = {};
1264	union acpi_object *wifi_pkg, *data;
1265	int tbl_rev, i;
1266
1267	data = iwl_acpi_get_object(fwrt->dev, ACPI_WPFC_METHOD);
1268	if (IS_ERR(data))
1269		return;
1270
1271	wifi_pkg = iwl_acpi_get_wifi_pkg(fwrt->dev, data,
1272					 ACPI_WPFC_WIFI_DATA_SIZE,
1273					 &tbl_rev);
1274	if (IS_ERR(wifi_pkg))
1275		goto out_free;
1276
1277	if (tbl_rev != 0)
1278		goto out_free;
1279
1280	BUILD_BUG_ON(ARRAY_SIZE(filters->filter_cfg_chains) !=
1281		     ACPI_WPFC_WIFI_DATA_SIZE - 1);
1282
1283	for (i = 0; i < ARRAY_SIZE(filters->filter_cfg_chains); i++) {
1284		if (wifi_pkg->package.elements[i + 1].type != ACPI_TYPE_INTEGER)
1285			goto out_free;
1286		tmp.filter_cfg_chains[i] =
1287			cpu_to_le32(wifi_pkg->package.elements[i + 1].integer.value);
1288	}
1289
1290	IWL_DEBUG_RADIO(fwrt, "Loaded WPFC filter config from ACPI\n");
1291	*filters = tmp;
1292out_free:
1293	kfree(data);
1294}
1295IWL_EXPORT_SYMBOL(iwl_acpi_get_phy_filters);
1296