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 union acpi_object *iwl_acpi_get_wifi_pkg(struct device *dev, 167 union acpi_object *data, 168 int data_size, int *tbl_rev) 169 { 170 int i; 171 union acpi_object *wifi_pkg; 172 173 /* 174 * We need at least one entry in the wifi package that 175 * describes the domain, and one more entry, otherwise there's 176 * no point in reading it. 177 */ 178 if (WARN_ON_ONCE(data_size < 2)) 179 return ERR_PTR(-EINVAL); 180 181 /* 182 * We need at least two packages, one for the revision and one 183 * for the data itself. Also check that the revision is valid 184 * (i.e. it is an integer (each caller has to check by itself 185 * if the returned revision is supported)). 186 */ 187 if (data->type != ACPI_TYPE_PACKAGE || 188 data->package.count < 2 || 189 data->package.elements[0].type != ACPI_TYPE_INTEGER) { 190 IWL_DEBUG_DEV_RADIO(dev, "Invalid packages structure\n"); 191 return ERR_PTR(-EINVAL); 192 } 193 194 *tbl_rev = data->package.elements[0].integer.value; 195 196 /* loop through all the packages to find the one for WiFi */ 197 for (i = 1; i < data->package.count; i++) { 198 union acpi_object *domain; 199 200 wifi_pkg = &data->package.elements[i]; 201 202 /* skip entries that are not a package with the right size */ 203 if (wifi_pkg->type != ACPI_TYPE_PACKAGE || 204 wifi_pkg->package.count != data_size) 205 continue; 206 207 domain = &wifi_pkg->package.elements[0]; 208 if (domain->type == ACPI_TYPE_INTEGER && 209 domain->integer.value == ACPI_WIFI_DOMAIN) 210 goto found; 211 } 212 213 return ERR_PTR(-ENOENT); 214 215 found: 216 return wifi_pkg; 217 } 218 IWL_EXPORT_SYMBOL(iwl_acpi_get_wifi_pkg); 219 220 int iwl_acpi_get_tas(struct iwl_fw_runtime *fwrt, 221 __le32 *block_list_array, 222 int *block_list_size) 223 { 224 union acpi_object *wifi_pkg, *data; 225 int ret, tbl_rev, i; 226 bool enabled; 227 228 data = iwl_acpi_get_object(fwrt->dev, ACPI_WTAS_METHOD); 229 if (IS_ERR(data)) 230 return PTR_ERR(data); 231 232 wifi_pkg = iwl_acpi_get_wifi_pkg(fwrt->dev, data, 233 ACPI_WTAS_WIFI_DATA_SIZE, 234 &tbl_rev); 235 if (IS_ERR(wifi_pkg)) { 236 ret = PTR_ERR(wifi_pkg); 237 goto out_free; 238 } 239 240 if (wifi_pkg->package.elements[0].type != ACPI_TYPE_INTEGER || 241 tbl_rev != 0) { 242 ret = -EINVAL; 243 goto out_free; 244 } 245 246 enabled = !!wifi_pkg->package.elements[0].integer.value; 247 248 if (!enabled) { 249 *block_list_size = -1; 250 IWL_DEBUG_RADIO(fwrt, "TAS not enabled\n"); 251 ret = 0; 252 goto out_free; 253 } 254 255 if (wifi_pkg->package.elements[1].type != ACPI_TYPE_INTEGER || 256 wifi_pkg->package.elements[1].integer.value > 257 APCI_WTAS_BLACK_LIST_MAX) { 258 IWL_DEBUG_RADIO(fwrt, "TAS invalid array size %llu\n", 259 wifi_pkg->package.elements[1].integer.value); 260 ret = -EINVAL; 261 goto out_free; 262 } 263 *block_list_size = wifi_pkg->package.elements[1].integer.value; 264 265 IWL_DEBUG_RADIO(fwrt, "TAS array size %d\n", *block_list_size); 266 if (*block_list_size > APCI_WTAS_BLACK_LIST_MAX) { 267 IWL_DEBUG_RADIO(fwrt, "TAS invalid array size value %u\n", 268 *block_list_size); 269 ret = -EINVAL; 270 goto out_free; 271 } 272 273 for (i = 0; i < *block_list_size; i++) { 274 u32 country; 275 276 if (wifi_pkg->package.elements[2 + i].type != 277 ACPI_TYPE_INTEGER) { 278 IWL_DEBUG_RADIO(fwrt, 279 "TAS invalid array elem %d\n", 2 + i); 280 ret = -EINVAL; 281 goto out_free; 282 } 283 284 country = wifi_pkg->package.elements[2 + i].integer.value; 285 block_list_array[i] = cpu_to_le32(country); 286 IWL_DEBUG_RADIO(fwrt, "TAS block list country %d\n", country); 287 } 288 289 ret = 0; 290 out_free: 291 kfree(data); 292 return ret; 293 } 294 IWL_EXPORT_SYMBOL(iwl_acpi_get_tas); 295 296 int iwl_acpi_get_mcc(struct device *dev, char *mcc) 297 { 298 union acpi_object *wifi_pkg, *data; 299 u32 mcc_val; 300 int ret, tbl_rev; 301 302 data = iwl_acpi_get_object(dev, ACPI_WRDD_METHOD); 303 if (IS_ERR(data)) 304 return PTR_ERR(data); 305 306 wifi_pkg = iwl_acpi_get_wifi_pkg(dev, data, ACPI_WRDD_WIFI_DATA_SIZE, 307 &tbl_rev); 308 if (IS_ERR(wifi_pkg)) { 309 ret = PTR_ERR(wifi_pkg); 310 goto out_free; 311 } 312 313 if (wifi_pkg->package.elements[1].type != ACPI_TYPE_INTEGER || 314 tbl_rev != 0) { 315 ret = -EINVAL; 316 goto out_free; 317 } 318 319 mcc_val = wifi_pkg->package.elements[1].integer.value; 320 321 mcc[0] = (mcc_val >> 8) & 0xff; 322 mcc[1] = mcc_val & 0xff; 323 mcc[2] = '\0'; 324 325 ret = 0; 326 out_free: 327 kfree(data); 328 return ret; 329 } 330 IWL_EXPORT_SYMBOL(iwl_acpi_get_mcc); 331 332 u64 iwl_acpi_get_pwr_limit(struct device *dev) 333 { 334 union acpi_object *data, *wifi_pkg; 335 u64 dflt_pwr_limit; 336 int tbl_rev; 337 338 data = iwl_acpi_get_object(dev, ACPI_SPLC_METHOD); 339 if (IS_ERR(data)) { 340 dflt_pwr_limit = 0; 341 goto out; 342 } 343 344 wifi_pkg = iwl_acpi_get_wifi_pkg(dev, data, 345 ACPI_SPLC_WIFI_DATA_SIZE, &tbl_rev); 346 if (IS_ERR(wifi_pkg) || tbl_rev != 0 || 347 wifi_pkg->package.elements[1].integer.value != ACPI_TYPE_INTEGER) { 348 dflt_pwr_limit = 0; 349 goto out_free; 350 } 351 352 dflt_pwr_limit = wifi_pkg->package.elements[1].integer.value; 353 out_free: 354 kfree(data); 355 out: 356 return dflt_pwr_limit; 357 } 358 IWL_EXPORT_SYMBOL(iwl_acpi_get_pwr_limit); 359 360 int iwl_acpi_get_eckv(struct device *dev, u32 *extl_clk) 361 { 362 union acpi_object *wifi_pkg, *data; 363 int ret, tbl_rev; 364 365 data = iwl_acpi_get_object(dev, ACPI_ECKV_METHOD); 366 if (IS_ERR(data)) 367 return PTR_ERR(data); 368 369 wifi_pkg = iwl_acpi_get_wifi_pkg(dev, data, ACPI_ECKV_WIFI_DATA_SIZE, 370 &tbl_rev); 371 if (IS_ERR(wifi_pkg)) { 372 ret = PTR_ERR(wifi_pkg); 373 goto out_free; 374 } 375 376 if (wifi_pkg->package.elements[1].type != ACPI_TYPE_INTEGER || 377 tbl_rev != 0) { 378 ret = -EINVAL; 379 goto out_free; 380 } 381 382 *extl_clk = wifi_pkg->package.elements[1].integer.value; 383 384 ret = 0; 385 386 out_free: 387 kfree(data); 388 return ret; 389 } 390 IWL_EXPORT_SYMBOL(iwl_acpi_get_eckv); 391 392 static int iwl_sar_set_profile(union acpi_object *table, 393 struct iwl_sar_profile *profile, 394 bool enabled) 395 { 396 int i; 397 398 profile->enabled = enabled; 399 400 for (i = 0; i < ACPI_SAR_TABLE_SIZE; i++) { 401 if (table[i].type != ACPI_TYPE_INTEGER || 402 table[i].integer.value > U8_MAX) 403 return -EINVAL; 404 405 profile->table[i] = table[i].integer.value; 406 } 407 408 return 0; 409 } 410 411 static int iwl_sar_fill_table(struct iwl_fw_runtime *fwrt, 412 __le16 *per_chain, u32 n_subbands, 413 int prof_a, int prof_b) 414 { 415 int profs[ACPI_SAR_NUM_CHAIN_LIMITS] = { prof_a, prof_b }; 416 int i, j, idx; 417 418 for (i = 0; i < ACPI_SAR_NUM_CHAIN_LIMITS; i++) { 419 struct iwl_sar_profile *prof; 420 421 /* don't allow SAR to be disabled (profile 0 means disable) */ 422 if (profs[i] == 0) 423 return -EPERM; 424 425 /* we are off by one, so allow up to ACPI_SAR_PROFILE_NUM */ 426 if (profs[i] > ACPI_SAR_PROFILE_NUM) 427 return -EINVAL; 428 429 /* profiles go from 1 to 4, so decrement to access the array */ 430 prof = &fwrt->sar_profiles[profs[i] - 1]; 431 432 /* if the profile is disabled, do nothing */ 433 if (!prof->enabled) { 434 IWL_DEBUG_RADIO(fwrt, "SAR profile %d is disabled.\n", 435 profs[i]); 436 /* 437 * if one of the profiles is disabled, we 438 * ignore all of them and return 1 to 439 * differentiate disabled from other failures. 440 */ 441 return 1; 442 } 443 444 IWL_DEBUG_INFO(fwrt, 445 "SAR EWRD: chain %d profile index %d\n", 446 i, profs[i]); 447 IWL_DEBUG_RADIO(fwrt, " Chain[%d]:\n", i); 448 for (j = 0; j < n_subbands; j++) { 449 idx = i * ACPI_SAR_NUM_SUB_BANDS + j; 450 per_chain[i * n_subbands + j] = 451 cpu_to_le16(prof->table[idx]); 452 IWL_DEBUG_RADIO(fwrt, " Band[%d] = %d * .125dBm\n", 453 j, prof->table[idx]); 454 } 455 } 456 457 return 0; 458 } 459 460 int iwl_sar_select_profile(struct iwl_fw_runtime *fwrt, 461 __le16 *per_chain, u32 n_tables, u32 n_subbands, 462 int prof_a, int prof_b) 463 { 464 int i, ret = 0; 465 466 for (i = 0; i < n_tables; i++) { 467 ret = iwl_sar_fill_table(fwrt, 468 &per_chain[i * n_subbands * ACPI_SAR_NUM_CHAIN_LIMITS], 469 n_subbands, prof_a, prof_b); 470 if (ret) 471 break; 472 } 473 474 return ret; 475 } 476 IWL_EXPORT_SYMBOL(iwl_sar_select_profile); 477 478 int iwl_sar_get_wrds_table(struct iwl_fw_runtime *fwrt) 479 { 480 union acpi_object *wifi_pkg, *table, *data; 481 bool enabled; 482 int ret, tbl_rev; 483 484 data = iwl_acpi_get_object(fwrt->dev, ACPI_WRDS_METHOD); 485 if (IS_ERR(data)) 486 return PTR_ERR(data); 487 488 wifi_pkg = iwl_acpi_get_wifi_pkg(fwrt->dev, data, 489 ACPI_WRDS_WIFI_DATA_SIZE, &tbl_rev); 490 if (IS_ERR(wifi_pkg)) { 491 ret = PTR_ERR(wifi_pkg); 492 goto out_free; 493 } 494 495 if (tbl_rev != 0) { 496 ret = -EINVAL; 497 goto out_free; 498 } 499 500 if (wifi_pkg->package.elements[1].type != ACPI_TYPE_INTEGER) { 501 ret = -EINVAL; 502 goto out_free; 503 } 504 505 enabled = !!(wifi_pkg->package.elements[1].integer.value); 506 507 /* position of the actual table */ 508 table = &wifi_pkg->package.elements[2]; 509 510 /* The profile from WRDS is officially profile 1, but goes 511 * into sar_profiles[0] (because we don't have a profile 0). 512 */ 513 ret = iwl_sar_set_profile(table, &fwrt->sar_profiles[0], enabled); 514 out_free: 515 kfree(data); 516 return ret; 517 } 518 IWL_EXPORT_SYMBOL(iwl_sar_get_wrds_table); 519 520 int iwl_sar_get_ewrd_table(struct iwl_fw_runtime *fwrt) 521 { 522 union acpi_object *wifi_pkg, *data; 523 bool enabled; 524 int i, n_profiles, tbl_rev, pos; 525 int ret = 0; 526 527 data = iwl_acpi_get_object(fwrt->dev, ACPI_EWRD_METHOD); 528 if (IS_ERR(data)) 529 return PTR_ERR(data); 530 531 wifi_pkg = iwl_acpi_get_wifi_pkg(fwrt->dev, data, 532 ACPI_EWRD_WIFI_DATA_SIZE, &tbl_rev); 533 if (IS_ERR(wifi_pkg)) { 534 ret = PTR_ERR(wifi_pkg); 535 goto out_free; 536 } 537 538 if (tbl_rev != 0) { 539 ret = -EINVAL; 540 goto out_free; 541 } 542 543 if (wifi_pkg->package.elements[1].type != ACPI_TYPE_INTEGER || 544 wifi_pkg->package.elements[2].type != ACPI_TYPE_INTEGER) { 545 ret = -EINVAL; 546 goto out_free; 547 } 548 549 enabled = !!(wifi_pkg->package.elements[1].integer.value); 550 n_profiles = wifi_pkg->package.elements[2].integer.value; 551 552 /* 553 * Check the validity of n_profiles. The EWRD profiles start 554 * from index 1, so the maximum value allowed here is 555 * ACPI_SAR_PROFILES_NUM - 1. 556 */ 557 if (n_profiles <= 0 || n_profiles >= ACPI_SAR_PROFILE_NUM) { 558 ret = -EINVAL; 559 goto out_free; 560 } 561 562 /* the tables start at element 3 */ 563 pos = 3; 564 565 for (i = 0; i < n_profiles; i++) { 566 /* The EWRD profiles officially go from 2 to 4, but we 567 * save them in sar_profiles[1-3] (because we don't 568 * have profile 0). So in the array we start from 1. 569 */ 570 ret = iwl_sar_set_profile(&wifi_pkg->package.elements[pos], 571 &fwrt->sar_profiles[i + 1], 572 enabled); 573 if (ret < 0) 574 break; 575 576 /* go to the next table */ 577 pos += ACPI_SAR_TABLE_SIZE; 578 } 579 580 out_free: 581 kfree(data); 582 return ret; 583 } 584 IWL_EXPORT_SYMBOL(iwl_sar_get_ewrd_table); 585 586 int iwl_sar_get_wgds_table(struct iwl_fw_runtime *fwrt) 587 { 588 union acpi_object *wifi_pkg, *data; 589 int i, j, ret, tbl_rev; 590 int idx = 1; 591 592 data = iwl_acpi_get_object(fwrt->dev, ACPI_WGDS_METHOD); 593 if (IS_ERR(data)) 594 return PTR_ERR(data); 595 596 wifi_pkg = iwl_acpi_get_wifi_pkg(fwrt->dev, data, 597 ACPI_WGDS_WIFI_DATA_SIZE, &tbl_rev); 598 599 if (IS_ERR(wifi_pkg)) { 600 ret = PTR_ERR(wifi_pkg); 601 goto out_free; 602 } 603 604 if (tbl_rev > 1) { 605 ret = -EINVAL; 606 goto out_free; 607 } 608 609 fwrt->geo_rev = tbl_rev; 610 for (i = 0; i < ACPI_NUM_GEO_PROFILES; i++) { 611 for (j = 0; j < ACPI_GEO_TABLE_SIZE; j++) { 612 union acpi_object *entry; 613 614 entry = &wifi_pkg->package.elements[idx++]; 615 if (entry->type != ACPI_TYPE_INTEGER || 616 entry->integer.value > U8_MAX) { 617 ret = -EINVAL; 618 goto out_free; 619 } 620 621 fwrt->geo_profiles[i].values[j] = entry->integer.value; 622 } 623 } 624 ret = 0; 625 out_free: 626 kfree(data); 627 return ret; 628 } 629 IWL_EXPORT_SYMBOL(iwl_sar_get_wgds_table); 630 631 bool iwl_sar_geo_support(struct iwl_fw_runtime *fwrt) 632 { 633 /* 634 * The GEO_TX_POWER_LIMIT command is not supported on earlier 635 * firmware versions. Unfortunately, we don't have a TLV API 636 * flag to rely on, so rely on the major version which is in 637 * the first byte of ucode_ver. This was implemented 638 * initially on version 38 and then backported to 17. It was 639 * also backported to 29, but only for 7265D devices. The 640 * intention was to have it in 36 as well, but not all 8000 641 * family got this feature enabled. The 8000 family is the 642 * only one using version 36, so skip this version entirely. 643 */ 644 return IWL_UCODE_SERIAL(fwrt->fw->ucode_ver) >= 38 || 645 IWL_UCODE_SERIAL(fwrt->fw->ucode_ver) == 17 || 646 (IWL_UCODE_SERIAL(fwrt->fw->ucode_ver) == 29 && 647 ((fwrt->trans->hw_rev & CSR_HW_REV_TYPE_MSK) == 648 CSR_HW_REV_TYPE_7265D)); 649 } 650 IWL_EXPORT_SYMBOL(iwl_sar_geo_support); 651 652 int iwl_sar_geo_init(struct iwl_fw_runtime *fwrt, 653 struct iwl_per_chain_offset *table, u32 n_bands) 654 { 655 int ret, i, j; 656 657 if (!iwl_sar_geo_support(fwrt)) 658 return -EOPNOTSUPP; 659 660 ret = iwl_sar_get_wgds_table(fwrt); 661 if (ret < 0) { 662 IWL_DEBUG_RADIO(fwrt, 663 "Geo SAR BIOS table invalid or unavailable. (%d)\n", 664 ret); 665 /* we don't fail if the table is not available */ 666 return -ENOENT; 667 } 668 669 for (i = 0; i < ACPI_NUM_GEO_PROFILES; i++) { 670 for (j = 0; j < n_bands; j++) { 671 struct iwl_per_chain_offset *chain = 672 &table[i * n_bands + j]; 673 u8 *value; 674 675 if (j * ACPI_GEO_PER_CHAIN_SIZE >= 676 ARRAY_SIZE(fwrt->geo_profiles[0].values)) 677 /* 678 * Currently we only store lb an hb values, and 679 * don't have any special ones for uhb. So leave 680 * those empty for the time being 681 */ 682 break; 683 684 value = &fwrt->geo_profiles[i].values[j * 685 ACPI_GEO_PER_CHAIN_SIZE]; 686 chain->max_tx_power = cpu_to_le16(value[0]); 687 chain->chain_a = value[1]; 688 chain->chain_b = value[2]; 689 IWL_DEBUG_RADIO(fwrt, 690 "SAR geographic profile[%d] Band[%d]: chain A = %d chain B = %d max_tx_power = %d\n", 691 i, j, value[1], value[2], value[0]); 692 } 693 } 694 695 return 0; 696 } 697 IWL_EXPORT_SYMBOL(iwl_sar_geo_init); 698 699 static u32 iwl_acpi_eval_dsm_func(struct device *dev, enum iwl_dsm_funcs_rev_0 eval_func) 700 { 701 union acpi_object *obj; 702 u32 ret; 703 704 obj = iwl_acpi_get_dsm_object(dev, 0, 705 eval_func, NULL, 706 &iwl_guid); 707 708 if (IS_ERR(obj)) { 709 IWL_DEBUG_DEV_RADIO(dev, 710 "ACPI: DSM func '%d': Got Error in obj = %ld\n", 711 eval_func, 712 PTR_ERR(obj)); 713 return 0; 714 } 715 716 if (obj->type != ACPI_TYPE_INTEGER) { 717 IWL_DEBUG_DEV_RADIO(dev, 718 "ACPI: DSM func '%d' did not return a valid object, type=%d\n", 719 eval_func, 720 obj->type); 721 ret = 0; 722 goto out; 723 } 724 725 ret = obj->integer.value; 726 IWL_DEBUG_DEV_RADIO(dev, 727 "ACPI: DSM method evaluated: func='%d', ret=%d\n", 728 eval_func, 729 ret); 730 out: 731 ACPI_FREE(obj); 732 return ret; 733 } 734 735 __le32 iwl_acpi_get_lari_config_bitmap(struct iwl_fw_runtime *fwrt) 736 { 737 u32 ret; 738 __le32 config_bitmap = 0; 739 740 /* 741 ** Evaluate func 'DSM_FUNC_ENABLE_INDONESIA_5G2' 742 */ 743 ret = iwl_acpi_eval_dsm_func(fwrt->dev, DSM_FUNC_ENABLE_INDONESIA_5G2); 744 745 if (ret == DSM_VALUE_INDONESIA_ENABLE) 746 config_bitmap |= 747 cpu_to_le32(LARI_CONFIG_ENABLE_5G2_IN_INDONESIA_MSK); 748 749 /* 750 ** Evaluate func 'DSM_FUNC_DISABLE_SRD' 751 */ 752 ret = iwl_acpi_eval_dsm_func(fwrt->dev, DSM_FUNC_DISABLE_SRD); 753 754 if (ret == DSM_VALUE_SRD_PASSIVE) 755 config_bitmap |= 756 cpu_to_le32(LARI_CONFIG_CHANGE_ETSI_TO_PASSIVE_MSK); 757 758 else if (ret == DSM_VALUE_SRD_DISABLE) 759 config_bitmap |= 760 cpu_to_le32(LARI_CONFIG_CHANGE_ETSI_TO_DISABLED_MSK); 761 762 return config_bitmap; 763 } 764 IWL_EXPORT_SYMBOL(iwl_acpi_get_lari_config_bitmap); 765