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