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