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