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[1].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[2].type != ACPI_TYPE_INTEGER || 277 wifi_pkg->package.elements[2].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[2].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[3 + i].type != 298 ACPI_TYPE_INTEGER) { 299 IWL_DEBUG_RADIO(fwrt, 300 "TAS invalid array elem %d\n", 3 + i); 301 ret = -EINVAL; 302 goto out_free; 303 } 304 305 country = wifi_pkg->package.elements[3 + 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, u8 num_chains, u8 num_sub_bands) 416 { 417 int i, j, idx = 0; 418 419 /* 420 * The table from ACPI is flat, but we store it in a 421 * structured array. 422 */ 423 for (i = 0; i < ACPI_SAR_NUM_CHAINS_REV2; i++) { 424 for (j = 0; j < ACPI_SAR_NUM_SUB_BANDS_REV2; j++) { 425 /* if we don't have the values, use the default */ 426 if (i >= num_chains || j >= num_sub_bands) { 427 profile->chains[i].subbands[j] = 0; 428 } else { 429 if (table[idx].type != ACPI_TYPE_INTEGER || 430 table[idx].integer.value > U8_MAX) 431 return -EINVAL; 432 433 profile->chains[i].subbands[j] = 434 table[idx].integer.value; 435 436 idx++; 437 } 438 } 439 } 440 441 /* Only if all values were valid can the profile be enabled */ 442 profile->enabled = enabled; 443 444 return 0; 445 } 446 447 static int iwl_sar_fill_table(struct iwl_fw_runtime *fwrt, 448 __le16 *per_chain, u32 n_subbands, 449 int prof_a, int prof_b) 450 { 451 int profs[ACPI_SAR_NUM_CHAINS_REV0] = { prof_a, prof_b }; 452 int i, j; 453 454 for (i = 0; i < ACPI_SAR_NUM_CHAINS_REV0; i++) { 455 struct iwl_sar_profile *prof; 456 457 /* don't allow SAR to be disabled (profile 0 means disable) */ 458 if (profs[i] == 0) 459 return -EPERM; 460 461 /* we are off by one, so allow up to ACPI_SAR_PROFILE_NUM */ 462 if (profs[i] > ACPI_SAR_PROFILE_NUM) 463 return -EINVAL; 464 465 /* profiles go from 1 to 4, so decrement to access the array */ 466 prof = &fwrt->sar_profiles[profs[i] - 1]; 467 468 /* if the profile is disabled, do nothing */ 469 if (!prof->enabled) { 470 IWL_DEBUG_RADIO(fwrt, "SAR profile %d is disabled.\n", 471 profs[i]); 472 /* 473 * if one of the profiles is disabled, we 474 * ignore all of them and return 1 to 475 * differentiate disabled from other failures. 476 */ 477 return 1; 478 } 479 480 IWL_DEBUG_INFO(fwrt, 481 "SAR EWRD: chain %d profile index %d\n", 482 i, profs[i]); 483 IWL_DEBUG_RADIO(fwrt, " Chain[%d]:\n", i); 484 for (j = 0; j < n_subbands; j++) { 485 per_chain[i * n_subbands + j] = 486 cpu_to_le16(prof->chains[i].subbands[j]); 487 IWL_DEBUG_RADIO(fwrt, " Band[%d] = %d * .125dBm\n", 488 j, prof->chains[i].subbands[j]); 489 } 490 } 491 492 return 0; 493 } 494 495 int iwl_sar_select_profile(struct iwl_fw_runtime *fwrt, 496 __le16 *per_chain, u32 n_tables, u32 n_subbands, 497 int prof_a, int prof_b) 498 { 499 int i, ret = 0; 500 501 for (i = 0; i < n_tables; i++) { 502 ret = iwl_sar_fill_table(fwrt, 503 &per_chain[i * n_subbands * ACPI_SAR_NUM_CHAINS_REV0], 504 n_subbands, prof_a, prof_b); 505 if (ret) 506 break; 507 } 508 509 return ret; 510 } 511 IWL_EXPORT_SYMBOL(iwl_sar_select_profile); 512 513 int iwl_sar_get_wrds_table(struct iwl_fw_runtime *fwrt) 514 { 515 union acpi_object *wifi_pkg, *table, *data; 516 bool enabled; 517 int ret, tbl_rev; 518 u8 num_chains, num_sub_bands; 519 520 data = iwl_acpi_get_object(fwrt->dev, ACPI_WRDS_METHOD); 521 if (IS_ERR(data)) 522 return PTR_ERR(data); 523 524 /* start by trying to read revision 2 */ 525 wifi_pkg = iwl_acpi_get_wifi_pkg(fwrt->dev, data, 526 ACPI_WRDS_WIFI_DATA_SIZE_REV2, 527 &tbl_rev); 528 if (!IS_ERR(wifi_pkg)) { 529 if (tbl_rev != 2) { 530 ret = PTR_ERR(wifi_pkg); 531 goto out_free; 532 } 533 534 num_chains = ACPI_SAR_NUM_CHAINS_REV2; 535 num_sub_bands = ACPI_SAR_NUM_SUB_BANDS_REV2; 536 537 goto read_table; 538 } 539 540 /* then try revision 1 */ 541 wifi_pkg = iwl_acpi_get_wifi_pkg(fwrt->dev, data, 542 ACPI_WRDS_WIFI_DATA_SIZE_REV1, 543 &tbl_rev); 544 if (!IS_ERR(wifi_pkg)) { 545 if (tbl_rev != 1) { 546 ret = PTR_ERR(wifi_pkg); 547 goto out_free; 548 } 549 550 num_chains = ACPI_SAR_NUM_CHAINS_REV1; 551 num_sub_bands = ACPI_SAR_NUM_SUB_BANDS_REV1; 552 553 goto read_table; 554 } 555 556 /* then finally revision 0 */ 557 wifi_pkg = iwl_acpi_get_wifi_pkg(fwrt->dev, data, 558 ACPI_WRDS_WIFI_DATA_SIZE_REV0, 559 &tbl_rev); 560 if (!IS_ERR(wifi_pkg)) { 561 if (tbl_rev != 0) { 562 ret = PTR_ERR(wifi_pkg); 563 goto out_free; 564 } 565 566 num_chains = ACPI_SAR_NUM_CHAINS_REV0; 567 num_sub_bands = ACPI_SAR_NUM_SUB_BANDS_REV0; 568 569 goto read_table; 570 } 571 572 ret = PTR_ERR(wifi_pkg); 573 goto out_free; 574 575 read_table: 576 if (wifi_pkg->package.elements[1].type != ACPI_TYPE_INTEGER) { 577 ret = -EINVAL; 578 goto out_free; 579 } 580 581 IWL_DEBUG_RADIO(fwrt, "Reading WRDS tbl_rev=%d\n", tbl_rev); 582 583 enabled = !!(wifi_pkg->package.elements[1].integer.value); 584 585 /* position of the actual table */ 586 table = &wifi_pkg->package.elements[2]; 587 588 /* The profile from WRDS is officially profile 1, but goes 589 * into sar_profiles[0] (because we don't have a profile 0). 590 */ 591 ret = iwl_sar_set_profile(table, &fwrt->sar_profiles[0], enabled, 592 num_chains, num_sub_bands); 593 out_free: 594 kfree(data); 595 return ret; 596 } 597 IWL_EXPORT_SYMBOL(iwl_sar_get_wrds_table); 598 599 int iwl_sar_get_ewrd_table(struct iwl_fw_runtime *fwrt) 600 { 601 union acpi_object *wifi_pkg, *data; 602 bool enabled; 603 int i, n_profiles, tbl_rev, pos; 604 int ret = 0; 605 u8 num_chains, num_sub_bands; 606 607 data = iwl_acpi_get_object(fwrt->dev, ACPI_EWRD_METHOD); 608 if (IS_ERR(data)) 609 return PTR_ERR(data); 610 611 /* start by trying to read revision 2 */ 612 wifi_pkg = iwl_acpi_get_wifi_pkg(fwrt->dev, data, 613 ACPI_EWRD_WIFI_DATA_SIZE_REV2, 614 &tbl_rev); 615 if (!IS_ERR(wifi_pkg)) { 616 if (tbl_rev != 2) { 617 ret = PTR_ERR(wifi_pkg); 618 goto out_free; 619 } 620 621 num_chains = ACPI_SAR_NUM_CHAINS_REV2; 622 num_sub_bands = ACPI_SAR_NUM_SUB_BANDS_REV2; 623 624 goto read_table; 625 } 626 627 /* then try revision 1 */ 628 wifi_pkg = iwl_acpi_get_wifi_pkg(fwrt->dev, data, 629 ACPI_EWRD_WIFI_DATA_SIZE_REV1, 630 &tbl_rev); 631 if (!IS_ERR(wifi_pkg)) { 632 if (tbl_rev != 1) { 633 ret = PTR_ERR(wifi_pkg); 634 goto out_free; 635 } 636 637 num_chains = ACPI_SAR_NUM_CHAINS_REV1; 638 num_sub_bands = ACPI_SAR_NUM_SUB_BANDS_REV1; 639 640 goto read_table; 641 } 642 643 /* then finally revision 0 */ 644 wifi_pkg = iwl_acpi_get_wifi_pkg(fwrt->dev, data, 645 ACPI_EWRD_WIFI_DATA_SIZE_REV0, 646 &tbl_rev); 647 if (!IS_ERR(wifi_pkg)) { 648 if (tbl_rev != 0) { 649 ret = PTR_ERR(wifi_pkg); 650 goto out_free; 651 } 652 653 num_chains = ACPI_SAR_NUM_CHAINS_REV0; 654 num_sub_bands = ACPI_SAR_NUM_SUB_BANDS_REV0; 655 656 goto read_table; 657 } 658 659 ret = PTR_ERR(wifi_pkg); 660 goto out_free; 661 662 read_table: 663 if (wifi_pkg->package.elements[1].type != ACPI_TYPE_INTEGER || 664 wifi_pkg->package.elements[2].type != ACPI_TYPE_INTEGER) { 665 ret = -EINVAL; 666 goto out_free; 667 } 668 669 enabled = !!(wifi_pkg->package.elements[1].integer.value); 670 n_profiles = wifi_pkg->package.elements[2].integer.value; 671 672 /* 673 * Check the validity of n_profiles. The EWRD profiles start 674 * from index 1, so the maximum value allowed here is 675 * ACPI_SAR_PROFILES_NUM - 1. 676 */ 677 if (n_profiles <= 0 || n_profiles >= ACPI_SAR_PROFILE_NUM) { 678 ret = -EINVAL; 679 goto out_free; 680 } 681 682 /* the tables start at element 3 */ 683 pos = 3; 684 685 for (i = 0; i < n_profiles; i++) { 686 /* The EWRD profiles officially go from 2 to 4, but we 687 * save them in sar_profiles[1-3] (because we don't 688 * have profile 0). So in the array we start from 1. 689 */ 690 ret = iwl_sar_set_profile(&wifi_pkg->package.elements[pos], 691 &fwrt->sar_profiles[i + 1], enabled, 692 num_chains, num_sub_bands); 693 if (ret < 0) 694 break; 695 696 /* go to the next table */ 697 pos += num_chains * num_sub_bands; 698 } 699 700 out_free: 701 kfree(data); 702 return ret; 703 } 704 IWL_EXPORT_SYMBOL(iwl_sar_get_ewrd_table); 705 706 int iwl_sar_get_wgds_table(struct iwl_fw_runtime *fwrt) 707 { 708 union acpi_object *wifi_pkg, *data; 709 int i, j, k, ret, tbl_rev; 710 int idx = 1; /* start from one to skip the domain */ 711 u8 num_bands; 712 713 data = iwl_acpi_get_object(fwrt->dev, ACPI_WGDS_METHOD); 714 if (IS_ERR(data)) 715 return PTR_ERR(data); 716 717 /* start by trying to read revision 2 */ 718 wifi_pkg = iwl_acpi_get_wifi_pkg(fwrt->dev, data, 719 ACPI_WGDS_WIFI_DATA_SIZE_REV2, 720 &tbl_rev); 721 if (!IS_ERR(wifi_pkg)) { 722 if (tbl_rev != 2) { 723 ret = PTR_ERR(wifi_pkg); 724 goto out_free; 725 } 726 727 num_bands = ACPI_GEO_NUM_BANDS_REV2; 728 729 goto read_table; 730 } 731 732 /* then try revision 0 (which is the same as 1) */ 733 wifi_pkg = iwl_acpi_get_wifi_pkg(fwrt->dev, data, 734 ACPI_WGDS_WIFI_DATA_SIZE_REV0, 735 &tbl_rev); 736 if (!IS_ERR(wifi_pkg)) { 737 if (tbl_rev != 0 && tbl_rev != 1) { 738 ret = PTR_ERR(wifi_pkg); 739 goto out_free; 740 } 741 742 num_bands = ACPI_GEO_NUM_BANDS_REV0; 743 744 goto read_table; 745 } 746 747 ret = PTR_ERR(wifi_pkg); 748 goto out_free; 749 750 read_table: 751 fwrt->geo_rev = tbl_rev; 752 for (i = 0; i < ACPI_NUM_GEO_PROFILES; i++) { 753 for (j = 0; j < ACPI_GEO_NUM_BANDS_REV2; j++) { 754 union acpi_object *entry; 755 756 /* 757 * num_bands is either 2 or 3, if it's only 2 then 758 * fill the third band (6 GHz) with the values from 759 * 5 GHz (second band) 760 */ 761 if (j >= num_bands) { 762 fwrt->geo_profiles[i].bands[j].max = 763 fwrt->geo_profiles[i].bands[1].max; 764 } else { 765 entry = &wifi_pkg->package.elements[idx++]; 766 if (entry->type != ACPI_TYPE_INTEGER || 767 entry->integer.value > U8_MAX) { 768 ret = -EINVAL; 769 goto out_free; 770 } 771 772 fwrt->geo_profiles[i].bands[j].max = 773 entry->integer.value; 774 } 775 776 for (k = 0; k < ACPI_GEO_NUM_CHAINS; k++) { 777 /* same here as above */ 778 if (j >= num_bands) { 779 fwrt->geo_profiles[i].bands[j].chains[k] = 780 fwrt->geo_profiles[i].bands[1].chains[k]; 781 } else { 782 entry = &wifi_pkg->package.elements[idx++]; 783 if (entry->type != ACPI_TYPE_INTEGER || 784 entry->integer.value > U8_MAX) { 785 ret = -EINVAL; 786 goto out_free; 787 } 788 789 fwrt->geo_profiles[i].bands[j].chains[k] = 790 entry->integer.value; 791 } 792 } 793 } 794 } 795 796 ret = 0; 797 out_free: 798 kfree(data); 799 return ret; 800 } 801 IWL_EXPORT_SYMBOL(iwl_sar_get_wgds_table); 802 803 bool iwl_sar_geo_support(struct iwl_fw_runtime *fwrt) 804 { 805 /* 806 * The GEO_TX_POWER_LIMIT command is not supported on earlier 807 * firmware versions. Unfortunately, we don't have a TLV API 808 * flag to rely on, so rely on the major version which is in 809 * the first byte of ucode_ver. This was implemented 810 * initially on version 38 and then backported to 17. It was 811 * also backported to 29, but only for 7265D devices. The 812 * intention was to have it in 36 as well, but not all 8000 813 * family got this feature enabled. The 8000 family is the 814 * only one using version 36, so skip this version entirely. 815 */ 816 return IWL_UCODE_SERIAL(fwrt->fw->ucode_ver) >= 38 || 817 IWL_UCODE_SERIAL(fwrt->fw->ucode_ver) == 17 || 818 (IWL_UCODE_SERIAL(fwrt->fw->ucode_ver) == 29 && 819 ((fwrt->trans->hw_rev & CSR_HW_REV_TYPE_MSK) == 820 CSR_HW_REV_TYPE_7265D)); 821 } 822 IWL_EXPORT_SYMBOL(iwl_sar_geo_support); 823 824 int iwl_sar_geo_init(struct iwl_fw_runtime *fwrt, 825 struct iwl_per_chain_offset *table, u32 n_bands) 826 { 827 int i, j; 828 829 if (!iwl_sar_geo_support(fwrt)) 830 return -EOPNOTSUPP; 831 832 for (i = 0; i < ACPI_NUM_GEO_PROFILES; i++) { 833 for (j = 0; j < n_bands; j++) { 834 struct iwl_per_chain_offset *chain = 835 &table[i * n_bands + j]; 836 837 chain->max_tx_power = 838 cpu_to_le16(fwrt->geo_profiles[i].bands[j].max); 839 chain->chain_a = fwrt->geo_profiles[i].bands[j].chains[0]; 840 chain->chain_b = fwrt->geo_profiles[i].bands[j].chains[1]; 841 IWL_DEBUG_RADIO(fwrt, 842 "SAR geographic profile[%d] Band[%d]: chain A = %d chain B = %d max_tx_power = %d\n", 843 i, j, 844 fwrt->geo_profiles[i].bands[j].chains[0], 845 fwrt->geo_profiles[i].bands[j].chains[1], 846 fwrt->geo_profiles[i].bands[j].max); 847 } 848 } 849 850 return 0; 851 } 852 IWL_EXPORT_SYMBOL(iwl_sar_geo_init); 853 854 __le32 iwl_acpi_get_lari_config_bitmap(struct iwl_fw_runtime *fwrt) 855 { 856 int ret; 857 u8 value; 858 __le32 config_bitmap = 0; 859 860 /* 861 ** Evaluate func 'DSM_FUNC_ENABLE_INDONESIA_5G2' 862 */ 863 ret = iwl_acpi_get_dsm_u8(fwrt->dev, 0, 864 DSM_FUNC_ENABLE_INDONESIA_5G2, 865 &iwl_guid, &value); 866 867 if (!ret && value == DSM_VALUE_INDONESIA_ENABLE) 868 config_bitmap |= 869 cpu_to_le32(LARI_CONFIG_ENABLE_5G2_IN_INDONESIA_MSK); 870 871 /* 872 ** Evaluate func 'DSM_FUNC_DISABLE_SRD' 873 */ 874 ret = iwl_acpi_get_dsm_u8(fwrt->dev, 0, 875 DSM_FUNC_DISABLE_SRD, 876 &iwl_guid, &value); 877 if (!ret) { 878 if (value == DSM_VALUE_SRD_PASSIVE) 879 config_bitmap |= 880 cpu_to_le32(LARI_CONFIG_CHANGE_ETSI_TO_PASSIVE_MSK); 881 else if (value == DSM_VALUE_SRD_DISABLE) 882 config_bitmap |= 883 cpu_to_le32(LARI_CONFIG_CHANGE_ETSI_TO_DISABLED_MSK); 884 } 885 886 return config_bitmap; 887 } 888 IWL_EXPORT_SYMBOL(iwl_acpi_get_lari_config_bitmap); 889