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