1 // SPDX-License-Identifier: GPL-2.0 OR BSD-3-Clause 2 /* 3 * Copyright (C) 2017 Intel Deutschland GmbH 4 * Copyright (C) 2019-2021 Intel Corporation 5 */ 6 #include <linux/uuid.h> 7 #include "iwl-drv.h" 8 #include "iwl-debug.h" 9 #include "acpi.h" 10 #include "fw/runtime.h" 11 12 const guid_t iwl_guid = GUID_INIT(0xF21202BF, 0x8F78, 0x4DC6, 13 0xA5, 0xB3, 0x1F, 0x73, 14 0x8E, 0x28, 0x5A, 0xDE); 15 IWL_EXPORT_SYMBOL(iwl_guid); 16 17 const guid_t iwl_rfi_guid = GUID_INIT(0x7266172C, 0x220B, 0x4B29, 18 0x81, 0x4F, 0x75, 0xE4, 19 0xDD, 0x26, 0xB5, 0xFD); 20 IWL_EXPORT_SYMBOL(iwl_rfi_guid); 21 22 static int iwl_acpi_get_handle(struct device *dev, acpi_string method, 23 acpi_handle *ret_handle) 24 { 25 acpi_handle root_handle; 26 acpi_status status; 27 28 root_handle = ACPI_HANDLE(dev); 29 if (!root_handle) { 30 IWL_DEBUG_DEV_RADIO(dev, 31 "ACPI: Could not retrieve root port handle\n"); 32 return -ENOENT; 33 } 34 35 status = acpi_get_handle(root_handle, method, ret_handle); 36 if (ACPI_FAILURE(status)) { 37 IWL_DEBUG_DEV_RADIO(dev, 38 "ACPI: %s method not found\n", method); 39 return -ENOENT; 40 } 41 return 0; 42 } 43 44 void *iwl_acpi_get_object(struct device *dev, acpi_string method) 45 { 46 struct acpi_buffer buf = {ACPI_ALLOCATE_BUFFER, NULL}; 47 acpi_handle handle; 48 acpi_status status; 49 int ret; 50 51 ret = iwl_acpi_get_handle(dev, method, &handle); 52 if (ret) 53 return ERR_PTR(-ENOENT); 54 55 /* Call the method with no arguments */ 56 status = acpi_evaluate_object(handle, NULL, NULL, &buf); 57 if (ACPI_FAILURE(status)) { 58 IWL_DEBUG_DEV_RADIO(dev, 59 "ACPI: %s method invocation failed (status: 0x%x)\n", 60 method, status); 61 return ERR_PTR(-ENOENT); 62 } 63 return buf.pointer; 64 } 65 IWL_EXPORT_SYMBOL(iwl_acpi_get_object); 66 67 /* 68 * Generic function for evaluating a method defined in the device specific 69 * method (DSM) interface. The returned acpi object must be freed by calling 70 * function. 71 */ 72 static void *iwl_acpi_get_dsm_object(struct device *dev, int rev, int func, 73 union acpi_object *args, 74 const guid_t *guid) 75 { 76 union acpi_object *obj; 77 78 obj = acpi_evaluate_dsm(ACPI_HANDLE(dev), guid, rev, func, 79 args); 80 if (!obj) { 81 IWL_DEBUG_DEV_RADIO(dev, 82 "ACPI: DSM method invocation failed (rev: %d, func:%d)\n", 83 rev, func); 84 return ERR_PTR(-ENOENT); 85 } 86 return obj; 87 } 88 89 /* 90 * Generic function to evaluate a DSM with no arguments 91 * and an integer return value, 92 * (as an integer object or inside a buffer object), 93 * verify and assign the value in the "value" parameter. 94 * return 0 in success and the appropriate errno otherwise. 95 */ 96 static int iwl_acpi_get_dsm_integer(struct device *dev, int rev, int func, 97 const guid_t *guid, u64 *value, 98 size_t expected_size) 99 { 100 union acpi_object *obj; 101 int ret = 0; 102 103 obj = iwl_acpi_get_dsm_object(dev, rev, func, NULL, guid); 104 if (IS_ERR(obj)) { 105 IWL_DEBUG_DEV_RADIO(dev, 106 "Failed to get DSM object. func= %d\n", 107 func); 108 return -ENOENT; 109 } 110 111 if (obj->type == ACPI_TYPE_INTEGER) { 112 *value = obj->integer.value; 113 } else if (obj->type == ACPI_TYPE_BUFFER) { 114 __le64 le_value = 0; 115 116 if (WARN_ON_ONCE(expected_size > sizeof(le_value))) 117 return -EINVAL; 118 119 /* if the buffer size doesn't match the expected size */ 120 if (obj->buffer.length != expected_size) 121 IWL_DEBUG_DEV_RADIO(dev, 122 "ACPI: DSM invalid buffer size, padding or truncating (%d)\n", 123 obj->buffer.length); 124 125 /* assuming LE from Intel BIOS spec */ 126 memcpy(&le_value, obj->buffer.pointer, 127 min_t(size_t, expected_size, (size_t)obj->buffer.length)); 128 *value = le64_to_cpu(le_value); 129 } else { 130 IWL_DEBUG_DEV_RADIO(dev, 131 "ACPI: DSM method did not return a valid object, type=%d\n", 132 obj->type); 133 ret = -EINVAL; 134 goto out; 135 } 136 137 IWL_DEBUG_DEV_RADIO(dev, 138 "ACPI: DSM method evaluated: func=%d, ret=%d\n", 139 func, ret); 140 out: 141 ACPI_FREE(obj); 142 return ret; 143 } 144 145 /* 146 * Evaluate a DSM with no arguments and a u8 return value, 147 */ 148 int iwl_acpi_get_dsm_u8(struct device *dev, int rev, int func, 149 const guid_t *guid, u8 *value) 150 { 151 int ret; 152 u64 val; 153 154 ret = iwl_acpi_get_dsm_integer(dev, rev, func, 155 guid, &val, sizeof(u8)); 156 157 if (ret < 0) 158 return ret; 159 160 /* cast val (u64) to be u8 */ 161 *value = (u8)val; 162 return 0; 163 } 164 IWL_EXPORT_SYMBOL(iwl_acpi_get_dsm_u8); 165 166 /* 167 * Evaluate a DSM with no arguments and a u32 return value, 168 */ 169 int iwl_acpi_get_dsm_u32(struct device *dev, int rev, int func, 170 const guid_t *guid, u32 *value) 171 { 172 int ret; 173 u64 val; 174 175 ret = iwl_acpi_get_dsm_integer(dev, rev, func, 176 guid, &val, sizeof(u32)); 177 178 if (ret < 0) 179 return ret; 180 181 /* cast val (u64) to be u32 */ 182 *value = (u32)val; 183 return 0; 184 } 185 IWL_EXPORT_SYMBOL(iwl_acpi_get_dsm_u32); 186 187 union acpi_object *iwl_acpi_get_wifi_pkg(struct device *dev, 188 union acpi_object *data, 189 int data_size, int *tbl_rev) 190 { 191 int i; 192 union acpi_object *wifi_pkg; 193 194 /* 195 * We need at least one entry in the wifi package that 196 * describes the domain, and one more entry, otherwise there's 197 * no point in reading it. 198 */ 199 if (WARN_ON_ONCE(data_size < 2)) 200 return ERR_PTR(-EINVAL); 201 202 /* 203 * We need at least two packages, one for the revision and one 204 * for the data itself. Also check that the revision is valid 205 * (i.e. it is an integer (each caller has to check by itself 206 * if the returned revision is supported)). 207 */ 208 if (data->type != ACPI_TYPE_PACKAGE || 209 data->package.count < 2 || 210 data->package.elements[0].type != ACPI_TYPE_INTEGER) { 211 IWL_DEBUG_DEV_RADIO(dev, "Invalid packages structure\n"); 212 return ERR_PTR(-EINVAL); 213 } 214 215 *tbl_rev = data->package.elements[0].integer.value; 216 217 /* loop through all the packages to find the one for WiFi */ 218 for (i = 1; i < data->package.count; i++) { 219 union acpi_object *domain; 220 221 wifi_pkg = &data->package.elements[i]; 222 223 /* skip entries that are not a package with the right size */ 224 if (wifi_pkg->type != ACPI_TYPE_PACKAGE || 225 wifi_pkg->package.count != data_size) 226 continue; 227 228 domain = &wifi_pkg->package.elements[0]; 229 if (domain->type == ACPI_TYPE_INTEGER && 230 domain->integer.value == ACPI_WIFI_DOMAIN) 231 goto found; 232 } 233 234 return ERR_PTR(-ENOENT); 235 236 found: 237 return wifi_pkg; 238 } 239 IWL_EXPORT_SYMBOL(iwl_acpi_get_wifi_pkg); 240 241 int iwl_acpi_get_tas(struct iwl_fw_runtime *fwrt, 242 __le32 *block_list_array, 243 int *block_list_size) 244 { 245 union acpi_object *wifi_pkg, *data; 246 int ret, tbl_rev, i; 247 bool enabled; 248 249 data = iwl_acpi_get_object(fwrt->dev, ACPI_WTAS_METHOD); 250 if (IS_ERR(data)) 251 return PTR_ERR(data); 252 253 wifi_pkg = iwl_acpi_get_wifi_pkg(fwrt->dev, data, 254 ACPI_WTAS_WIFI_DATA_SIZE, 255 &tbl_rev); 256 if (IS_ERR(wifi_pkg)) { 257 ret = PTR_ERR(wifi_pkg); 258 goto out_free; 259 } 260 261 if (wifi_pkg->package.elements[0].type != ACPI_TYPE_INTEGER || 262 tbl_rev != 0) { 263 ret = -EINVAL; 264 goto out_free; 265 } 266 267 enabled = !!wifi_pkg->package.elements[0].integer.value; 268 269 if (!enabled) { 270 *block_list_size = -1; 271 IWL_DEBUG_RADIO(fwrt, "TAS not enabled\n"); 272 ret = 0; 273 goto out_free; 274 } 275 276 if (wifi_pkg->package.elements[1].type != ACPI_TYPE_INTEGER || 277 wifi_pkg->package.elements[1].integer.value > 278 APCI_WTAS_BLACK_LIST_MAX) { 279 IWL_DEBUG_RADIO(fwrt, "TAS invalid array size %llu\n", 280 wifi_pkg->package.elements[1].integer.value); 281 ret = -EINVAL; 282 goto out_free; 283 } 284 *block_list_size = wifi_pkg->package.elements[1].integer.value; 285 286 IWL_DEBUG_RADIO(fwrt, "TAS array size %d\n", *block_list_size); 287 if (*block_list_size > APCI_WTAS_BLACK_LIST_MAX) { 288 IWL_DEBUG_RADIO(fwrt, "TAS invalid array size value %u\n", 289 *block_list_size); 290 ret = -EINVAL; 291 goto out_free; 292 } 293 294 for (i = 0; i < *block_list_size; i++) { 295 u32 country; 296 297 if (wifi_pkg->package.elements[2 + i].type != 298 ACPI_TYPE_INTEGER) { 299 IWL_DEBUG_RADIO(fwrt, 300 "TAS invalid array elem %d\n", 2 + i); 301 ret = -EINVAL; 302 goto out_free; 303 } 304 305 country = wifi_pkg->package.elements[2 + i].integer.value; 306 block_list_array[i] = cpu_to_le32(country); 307 IWL_DEBUG_RADIO(fwrt, "TAS block list country %d\n", country); 308 } 309 310 ret = 0; 311 out_free: 312 kfree(data); 313 return ret; 314 } 315 IWL_EXPORT_SYMBOL(iwl_acpi_get_tas); 316 317 int iwl_acpi_get_mcc(struct device *dev, char *mcc) 318 { 319 union acpi_object *wifi_pkg, *data; 320 u32 mcc_val; 321 int ret, tbl_rev; 322 323 data = iwl_acpi_get_object(dev, ACPI_WRDD_METHOD); 324 if (IS_ERR(data)) 325 return PTR_ERR(data); 326 327 wifi_pkg = iwl_acpi_get_wifi_pkg(dev, data, ACPI_WRDD_WIFI_DATA_SIZE, 328 &tbl_rev); 329 if (IS_ERR(wifi_pkg)) { 330 ret = PTR_ERR(wifi_pkg); 331 goto out_free; 332 } 333 334 if (wifi_pkg->package.elements[1].type != ACPI_TYPE_INTEGER || 335 tbl_rev != 0) { 336 ret = -EINVAL; 337 goto out_free; 338 } 339 340 mcc_val = wifi_pkg->package.elements[1].integer.value; 341 342 mcc[0] = (mcc_val >> 8) & 0xff; 343 mcc[1] = mcc_val & 0xff; 344 mcc[2] = '\0'; 345 346 ret = 0; 347 out_free: 348 kfree(data); 349 return ret; 350 } 351 IWL_EXPORT_SYMBOL(iwl_acpi_get_mcc); 352 353 u64 iwl_acpi_get_pwr_limit(struct device *dev) 354 { 355 union acpi_object *data, *wifi_pkg; 356 u64 dflt_pwr_limit; 357 int tbl_rev; 358 359 data = iwl_acpi_get_object(dev, ACPI_SPLC_METHOD); 360 if (IS_ERR(data)) { 361 dflt_pwr_limit = 0; 362 goto out; 363 } 364 365 wifi_pkg = iwl_acpi_get_wifi_pkg(dev, data, 366 ACPI_SPLC_WIFI_DATA_SIZE, &tbl_rev); 367 if (IS_ERR(wifi_pkg) || tbl_rev != 0 || 368 wifi_pkg->package.elements[1].integer.value != ACPI_TYPE_INTEGER) { 369 dflt_pwr_limit = 0; 370 goto out_free; 371 } 372 373 dflt_pwr_limit = wifi_pkg->package.elements[1].integer.value; 374 out_free: 375 kfree(data); 376 out: 377 return dflt_pwr_limit; 378 } 379 IWL_EXPORT_SYMBOL(iwl_acpi_get_pwr_limit); 380 381 int iwl_acpi_get_eckv(struct device *dev, u32 *extl_clk) 382 { 383 union acpi_object *wifi_pkg, *data; 384 int ret, tbl_rev; 385 386 data = iwl_acpi_get_object(dev, ACPI_ECKV_METHOD); 387 if (IS_ERR(data)) 388 return PTR_ERR(data); 389 390 wifi_pkg = iwl_acpi_get_wifi_pkg(dev, data, ACPI_ECKV_WIFI_DATA_SIZE, 391 &tbl_rev); 392 if (IS_ERR(wifi_pkg)) { 393 ret = PTR_ERR(wifi_pkg); 394 goto out_free; 395 } 396 397 if (wifi_pkg->package.elements[1].type != ACPI_TYPE_INTEGER || 398 tbl_rev != 0) { 399 ret = -EINVAL; 400 goto out_free; 401 } 402 403 *extl_clk = wifi_pkg->package.elements[1].integer.value; 404 405 ret = 0; 406 407 out_free: 408 kfree(data); 409 return ret; 410 } 411 IWL_EXPORT_SYMBOL(iwl_acpi_get_eckv); 412 413 static int iwl_sar_set_profile(union acpi_object *table, 414 struct iwl_sar_profile *profile, 415 bool enabled) 416 { 417 int i; 418 419 profile->enabled = enabled; 420 421 for (i = 0; i < ACPI_SAR_TABLE_SIZE; i++) { 422 if (table[i].type != ACPI_TYPE_INTEGER || 423 table[i].integer.value > U8_MAX) 424 return -EINVAL; 425 426 profile->table[i] = table[i].integer.value; 427 } 428 429 return 0; 430 } 431 432 static int iwl_sar_fill_table(struct iwl_fw_runtime *fwrt, 433 __le16 *per_chain, u32 n_subbands, 434 int prof_a, int prof_b) 435 { 436 int profs[ACPI_SAR_NUM_CHAIN_LIMITS] = { prof_a, prof_b }; 437 int i, j, idx; 438 439 for (i = 0; i < ACPI_SAR_NUM_CHAIN_LIMITS; i++) { 440 struct iwl_sar_profile *prof; 441 442 /* don't allow SAR to be disabled (profile 0 means disable) */ 443 if (profs[i] == 0) 444 return -EPERM; 445 446 /* we are off by one, so allow up to ACPI_SAR_PROFILE_NUM */ 447 if (profs[i] > ACPI_SAR_PROFILE_NUM) 448 return -EINVAL; 449 450 /* profiles go from 1 to 4, so decrement to access the array */ 451 prof = &fwrt->sar_profiles[profs[i] - 1]; 452 453 /* if the profile is disabled, do nothing */ 454 if (!prof->enabled) { 455 IWL_DEBUG_RADIO(fwrt, "SAR profile %d is disabled.\n", 456 profs[i]); 457 /* 458 * if one of the profiles is disabled, we 459 * ignore all of them and return 1 to 460 * differentiate disabled from other failures. 461 */ 462 return 1; 463 } 464 465 IWL_DEBUG_INFO(fwrt, 466 "SAR EWRD: chain %d profile index %d\n", 467 i, profs[i]); 468 IWL_DEBUG_RADIO(fwrt, " Chain[%d]:\n", i); 469 for (j = 0; j < n_subbands; j++) { 470 idx = i * ACPI_SAR_NUM_SUB_BANDS + j; 471 per_chain[i * n_subbands + j] = 472 cpu_to_le16(prof->table[idx]); 473 IWL_DEBUG_RADIO(fwrt, " Band[%d] = %d * .125dBm\n", 474 j, prof->table[idx]); 475 } 476 } 477 478 return 0; 479 } 480 481 int iwl_sar_select_profile(struct iwl_fw_runtime *fwrt, 482 __le16 *per_chain, u32 n_tables, u32 n_subbands, 483 int prof_a, int prof_b) 484 { 485 int i, ret = 0; 486 487 for (i = 0; i < n_tables; i++) { 488 ret = iwl_sar_fill_table(fwrt, 489 &per_chain[i * n_subbands * ACPI_SAR_NUM_CHAIN_LIMITS], 490 n_subbands, prof_a, prof_b); 491 if (ret) 492 break; 493 } 494 495 return ret; 496 } 497 IWL_EXPORT_SYMBOL(iwl_sar_select_profile); 498 499 int iwl_sar_get_wrds_table(struct iwl_fw_runtime *fwrt) 500 { 501 union acpi_object *wifi_pkg, *table, *data; 502 bool enabled; 503 int ret, tbl_rev; 504 505 data = iwl_acpi_get_object(fwrt->dev, ACPI_WRDS_METHOD); 506 if (IS_ERR(data)) 507 return PTR_ERR(data); 508 509 wifi_pkg = iwl_acpi_get_wifi_pkg(fwrt->dev, data, 510 ACPI_WRDS_WIFI_DATA_SIZE, &tbl_rev); 511 if (IS_ERR(wifi_pkg)) { 512 ret = PTR_ERR(wifi_pkg); 513 goto out_free; 514 } 515 516 if (tbl_rev != 0) { 517 ret = -EINVAL; 518 goto out_free; 519 } 520 521 if (wifi_pkg->package.elements[1].type != ACPI_TYPE_INTEGER) { 522 ret = -EINVAL; 523 goto out_free; 524 } 525 526 enabled = !!(wifi_pkg->package.elements[1].integer.value); 527 528 /* position of the actual table */ 529 table = &wifi_pkg->package.elements[2]; 530 531 /* The profile from WRDS is officially profile 1, but goes 532 * into sar_profiles[0] (because we don't have a profile 0). 533 */ 534 ret = iwl_sar_set_profile(table, &fwrt->sar_profiles[0], enabled); 535 out_free: 536 kfree(data); 537 return ret; 538 } 539 IWL_EXPORT_SYMBOL(iwl_sar_get_wrds_table); 540 541 int iwl_sar_get_ewrd_table(struct iwl_fw_runtime *fwrt) 542 { 543 union acpi_object *wifi_pkg, *data; 544 bool enabled; 545 int i, n_profiles, tbl_rev, pos; 546 int ret = 0; 547 548 data = iwl_acpi_get_object(fwrt->dev, ACPI_EWRD_METHOD); 549 if (IS_ERR(data)) 550 return PTR_ERR(data); 551 552 wifi_pkg = iwl_acpi_get_wifi_pkg(fwrt->dev, data, 553 ACPI_EWRD_WIFI_DATA_SIZE, &tbl_rev); 554 if (IS_ERR(wifi_pkg)) { 555 ret = PTR_ERR(wifi_pkg); 556 goto out_free; 557 } 558 559 if (tbl_rev != 0) { 560 ret = -EINVAL; 561 goto out_free; 562 } 563 564 if (wifi_pkg->package.elements[1].type != ACPI_TYPE_INTEGER || 565 wifi_pkg->package.elements[2].type != ACPI_TYPE_INTEGER) { 566 ret = -EINVAL; 567 goto out_free; 568 } 569 570 enabled = !!(wifi_pkg->package.elements[1].integer.value); 571 n_profiles = wifi_pkg->package.elements[2].integer.value; 572 573 /* 574 * Check the validity of n_profiles. The EWRD profiles start 575 * from index 1, so the maximum value allowed here is 576 * ACPI_SAR_PROFILES_NUM - 1. 577 */ 578 if (n_profiles <= 0 || n_profiles >= ACPI_SAR_PROFILE_NUM) { 579 ret = -EINVAL; 580 goto out_free; 581 } 582 583 /* the tables start at element 3 */ 584 pos = 3; 585 586 for (i = 0; i < n_profiles; i++) { 587 /* The EWRD profiles officially go from 2 to 4, but we 588 * save them in sar_profiles[1-3] (because we don't 589 * have profile 0). So in the array we start from 1. 590 */ 591 ret = iwl_sar_set_profile(&wifi_pkg->package.elements[pos], 592 &fwrt->sar_profiles[i + 1], 593 enabled); 594 if (ret < 0) 595 break; 596 597 /* go to the next table */ 598 pos += ACPI_SAR_TABLE_SIZE; 599 } 600 601 out_free: 602 kfree(data); 603 return ret; 604 } 605 IWL_EXPORT_SYMBOL(iwl_sar_get_ewrd_table); 606 607 int iwl_sar_get_wgds_table(struct iwl_fw_runtime *fwrt) 608 { 609 union acpi_object *wifi_pkg, *data; 610 int i, j, ret, tbl_rev; 611 int idx = 1; 612 613 data = iwl_acpi_get_object(fwrt->dev, ACPI_WGDS_METHOD); 614 if (IS_ERR(data)) 615 return PTR_ERR(data); 616 617 wifi_pkg = iwl_acpi_get_wifi_pkg(fwrt->dev, data, 618 ACPI_WGDS_WIFI_DATA_SIZE, &tbl_rev); 619 620 if (IS_ERR(wifi_pkg)) { 621 ret = PTR_ERR(wifi_pkg); 622 goto out_free; 623 } 624 625 if (tbl_rev > 1) { 626 ret = -EINVAL; 627 goto out_free; 628 } 629 630 fwrt->geo_rev = tbl_rev; 631 for (i = 0; i < ACPI_NUM_GEO_PROFILES; i++) { 632 for (j = 0; j < ACPI_GEO_TABLE_SIZE; j++) { 633 union acpi_object *entry; 634 635 entry = &wifi_pkg->package.elements[idx++]; 636 if (entry->type != ACPI_TYPE_INTEGER || 637 entry->integer.value > U8_MAX) { 638 ret = -EINVAL; 639 goto out_free; 640 } 641 642 fwrt->geo_profiles[i].values[j] = entry->integer.value; 643 } 644 } 645 ret = 0; 646 out_free: 647 kfree(data); 648 return ret; 649 } 650 IWL_EXPORT_SYMBOL(iwl_sar_get_wgds_table); 651 652 bool iwl_sar_geo_support(struct iwl_fw_runtime *fwrt) 653 { 654 /* 655 * The GEO_TX_POWER_LIMIT command is not supported on earlier 656 * firmware versions. Unfortunately, we don't have a TLV API 657 * flag to rely on, so rely on the major version which is in 658 * the first byte of ucode_ver. This was implemented 659 * initially on version 38 and then backported to 17. It was 660 * also backported to 29, but only for 7265D devices. The 661 * intention was to have it in 36 as well, but not all 8000 662 * family got this feature enabled. The 8000 family is the 663 * only one using version 36, so skip this version entirely. 664 */ 665 return IWL_UCODE_SERIAL(fwrt->fw->ucode_ver) >= 38 || 666 IWL_UCODE_SERIAL(fwrt->fw->ucode_ver) == 17 || 667 (IWL_UCODE_SERIAL(fwrt->fw->ucode_ver) == 29 && 668 ((fwrt->trans->hw_rev & CSR_HW_REV_TYPE_MSK) == 669 CSR_HW_REV_TYPE_7265D)); 670 } 671 IWL_EXPORT_SYMBOL(iwl_sar_geo_support); 672 673 int iwl_sar_geo_init(struct iwl_fw_runtime *fwrt, 674 struct iwl_per_chain_offset *table, u32 n_bands) 675 { 676 int ret, i, j; 677 678 if (!iwl_sar_geo_support(fwrt)) 679 return -EOPNOTSUPP; 680 681 ret = iwl_sar_get_wgds_table(fwrt); 682 if (ret < 0) { 683 IWL_DEBUG_RADIO(fwrt, 684 "Geo SAR BIOS table invalid or unavailable. (%d)\n", 685 ret); 686 /* we don't fail if the table is not available */ 687 return -ENOENT; 688 } 689 690 for (i = 0; i < ACPI_NUM_GEO_PROFILES; i++) { 691 for (j = 0; j < n_bands; j++) { 692 struct iwl_per_chain_offset *chain = 693 &table[i * n_bands + j]; 694 u8 *value; 695 696 if (j * ACPI_GEO_PER_CHAIN_SIZE >= 697 ARRAY_SIZE(fwrt->geo_profiles[0].values)) 698 /* 699 * Currently we only store lb an hb values, and 700 * don't have any special ones for uhb. So leave 701 * those empty for the time being 702 */ 703 break; 704 705 value = &fwrt->geo_profiles[i].values[j * 706 ACPI_GEO_PER_CHAIN_SIZE]; 707 chain->max_tx_power = cpu_to_le16(value[0]); 708 chain->chain_a = value[1]; 709 chain->chain_b = value[2]; 710 IWL_DEBUG_RADIO(fwrt, 711 "SAR geographic profile[%d] Band[%d]: chain A = %d chain B = %d max_tx_power = %d\n", 712 i, j, value[1], value[2], value[0]); 713 } 714 } 715 716 return 0; 717 } 718 IWL_EXPORT_SYMBOL(iwl_sar_geo_init); 719 720 __le32 iwl_acpi_get_lari_config_bitmap(struct iwl_fw_runtime *fwrt) 721 { 722 int ret; 723 u8 value; 724 __le32 config_bitmap = 0; 725 726 /* 727 ** Evaluate func 'DSM_FUNC_ENABLE_INDONESIA_5G2' 728 */ 729 ret = iwl_acpi_get_dsm_u8(fwrt->dev, 0, 730 DSM_FUNC_ENABLE_INDONESIA_5G2, 731 &iwl_guid, &value); 732 733 if (!ret && value == DSM_VALUE_INDONESIA_ENABLE) 734 config_bitmap |= 735 cpu_to_le32(LARI_CONFIG_ENABLE_5G2_IN_INDONESIA_MSK); 736 737 /* 738 ** Evaluate func 'DSM_FUNC_DISABLE_SRD' 739 */ 740 ret = iwl_acpi_get_dsm_u8(fwrt->dev, 0, 741 DSM_FUNC_DISABLE_SRD, 742 &iwl_guid, &value); 743 if (!ret) { 744 if (value == DSM_VALUE_SRD_PASSIVE) 745 config_bitmap |= 746 cpu_to_le32(LARI_CONFIG_CHANGE_ETSI_TO_PASSIVE_MSK); 747 else if (value == DSM_VALUE_SRD_DISABLE) 748 config_bitmap |= 749 cpu_to_le32(LARI_CONFIG_CHANGE_ETSI_TO_DISABLED_MSK); 750 } 751 752 return config_bitmap; 753 } 754 IWL_EXPORT_SYMBOL(iwl_acpi_get_lari_config_bitmap); 755