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