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