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_range(struct device *dev, 188 union acpi_object *data, 189 int min_data_size, 190 int max_data_size, 191 int *tbl_rev) 192 { 193 int i; 194 union acpi_object *wifi_pkg; 195 196 /* 197 * We need at least one entry in the wifi package that 198 * describes the domain, and one more entry, otherwise there's 199 * no point in reading it. 200 */ 201 if (WARN_ON_ONCE(min_data_size < 2 || min_data_size > max_data_size)) 202 return ERR_PTR(-EINVAL); 203 204 /* 205 * We need at least two packages, one for the revision and one 206 * for the data itself. Also check that the revision is valid 207 * (i.e. it is an integer (each caller has to check by itself 208 * if the returned revision is supported)). 209 */ 210 if (data->type != ACPI_TYPE_PACKAGE || 211 data->package.count < 2 || 212 data->package.elements[0].type != ACPI_TYPE_INTEGER) { 213 IWL_DEBUG_DEV_RADIO(dev, "Invalid packages structure\n"); 214 return ERR_PTR(-EINVAL); 215 } 216 217 *tbl_rev = data->package.elements[0].integer.value; 218 219 /* loop through all the packages to find the one for WiFi */ 220 for (i = 1; i < data->package.count; i++) { 221 union acpi_object *domain; 222 223 wifi_pkg = &data->package.elements[i]; 224 225 /* skip entries that are not a package with the right size */ 226 if (wifi_pkg->type != ACPI_TYPE_PACKAGE || 227 wifi_pkg->package.count < min_data_size || 228 wifi_pkg->package.count > max_data_size) 229 continue; 230 231 domain = &wifi_pkg->package.elements[0]; 232 if (domain->type == ACPI_TYPE_INTEGER && 233 domain->integer.value == ACPI_WIFI_DOMAIN) 234 goto found; 235 } 236 237 return ERR_PTR(-ENOENT); 238 239 found: 240 return wifi_pkg; 241 } 242 IWL_EXPORT_SYMBOL(iwl_acpi_get_wifi_pkg_range); 243 244 int iwl_acpi_get_tas(struct iwl_fw_runtime *fwrt, 245 __le32 *block_list_array, 246 int *block_list_size) 247 { 248 union acpi_object *wifi_pkg, *data; 249 int ret, tbl_rev, i; 250 bool enabled; 251 252 data = iwl_acpi_get_object(fwrt->dev, ACPI_WTAS_METHOD); 253 if (IS_ERR(data)) 254 return PTR_ERR(data); 255 256 wifi_pkg = iwl_acpi_get_wifi_pkg(fwrt->dev, data, 257 ACPI_WTAS_WIFI_DATA_SIZE, 258 &tbl_rev); 259 if (IS_ERR(wifi_pkg)) { 260 ret = PTR_ERR(wifi_pkg); 261 goto out_free; 262 } 263 264 if (wifi_pkg->package.elements[0].type != ACPI_TYPE_INTEGER || 265 tbl_rev != 0) { 266 ret = -EINVAL; 267 goto out_free; 268 } 269 270 enabled = !!wifi_pkg->package.elements[1].integer.value; 271 272 if (!enabled) { 273 *block_list_size = -1; 274 IWL_DEBUG_RADIO(fwrt, "TAS not enabled\n"); 275 ret = 0; 276 goto out_free; 277 } 278 279 if (wifi_pkg->package.elements[2].type != ACPI_TYPE_INTEGER || 280 wifi_pkg->package.elements[2].integer.value > 281 APCI_WTAS_BLACK_LIST_MAX) { 282 IWL_DEBUG_RADIO(fwrt, "TAS invalid array size %llu\n", 283 wifi_pkg->package.elements[1].integer.value); 284 ret = -EINVAL; 285 goto out_free; 286 } 287 *block_list_size = wifi_pkg->package.elements[2].integer.value; 288 289 IWL_DEBUG_RADIO(fwrt, "TAS array size %d\n", *block_list_size); 290 if (*block_list_size > APCI_WTAS_BLACK_LIST_MAX) { 291 IWL_DEBUG_RADIO(fwrt, "TAS invalid array size value %u\n", 292 *block_list_size); 293 ret = -EINVAL; 294 goto out_free; 295 } 296 297 for (i = 0; i < *block_list_size; i++) { 298 u32 country; 299 300 if (wifi_pkg->package.elements[3 + i].type != 301 ACPI_TYPE_INTEGER) { 302 IWL_DEBUG_RADIO(fwrt, 303 "TAS invalid array elem %d\n", 3 + i); 304 ret = -EINVAL; 305 goto out_free; 306 } 307 308 country = wifi_pkg->package.elements[3 + i].integer.value; 309 block_list_array[i] = cpu_to_le32(country); 310 IWL_DEBUG_RADIO(fwrt, "TAS block list country %d\n", country); 311 } 312 313 ret = 0; 314 out_free: 315 kfree(data); 316 return ret; 317 } 318 IWL_EXPORT_SYMBOL(iwl_acpi_get_tas); 319 320 int iwl_acpi_get_mcc(struct device *dev, char *mcc) 321 { 322 union acpi_object *wifi_pkg, *data; 323 u32 mcc_val; 324 int ret, tbl_rev; 325 326 data = iwl_acpi_get_object(dev, ACPI_WRDD_METHOD); 327 if (IS_ERR(data)) 328 return PTR_ERR(data); 329 330 wifi_pkg = iwl_acpi_get_wifi_pkg(dev, data, ACPI_WRDD_WIFI_DATA_SIZE, 331 &tbl_rev); 332 if (IS_ERR(wifi_pkg)) { 333 ret = PTR_ERR(wifi_pkg); 334 goto out_free; 335 } 336 337 if (wifi_pkg->package.elements[1].type != ACPI_TYPE_INTEGER || 338 tbl_rev != 0) { 339 ret = -EINVAL; 340 goto out_free; 341 } 342 343 mcc_val = wifi_pkg->package.elements[1].integer.value; 344 345 mcc[0] = (mcc_val >> 8) & 0xff; 346 mcc[1] = mcc_val & 0xff; 347 mcc[2] = '\0'; 348 349 ret = 0; 350 out_free: 351 kfree(data); 352 return ret; 353 } 354 IWL_EXPORT_SYMBOL(iwl_acpi_get_mcc); 355 356 u64 iwl_acpi_get_pwr_limit(struct device *dev) 357 { 358 union acpi_object *data, *wifi_pkg; 359 u64 dflt_pwr_limit; 360 int tbl_rev; 361 362 data = iwl_acpi_get_object(dev, ACPI_SPLC_METHOD); 363 if (IS_ERR(data)) { 364 dflt_pwr_limit = 0; 365 goto out; 366 } 367 368 wifi_pkg = iwl_acpi_get_wifi_pkg(dev, data, 369 ACPI_SPLC_WIFI_DATA_SIZE, &tbl_rev); 370 if (IS_ERR(wifi_pkg) || tbl_rev != 0 || 371 wifi_pkg->package.elements[1].integer.value != ACPI_TYPE_INTEGER) { 372 dflt_pwr_limit = 0; 373 goto out_free; 374 } 375 376 dflt_pwr_limit = wifi_pkg->package.elements[1].integer.value; 377 out_free: 378 kfree(data); 379 out: 380 return dflt_pwr_limit; 381 } 382 IWL_EXPORT_SYMBOL(iwl_acpi_get_pwr_limit); 383 384 int iwl_acpi_get_eckv(struct device *dev, u32 *extl_clk) 385 { 386 union acpi_object *wifi_pkg, *data; 387 int ret, tbl_rev; 388 389 data = iwl_acpi_get_object(dev, ACPI_ECKV_METHOD); 390 if (IS_ERR(data)) 391 return PTR_ERR(data); 392 393 wifi_pkg = iwl_acpi_get_wifi_pkg(dev, data, ACPI_ECKV_WIFI_DATA_SIZE, 394 &tbl_rev); 395 if (IS_ERR(wifi_pkg)) { 396 ret = PTR_ERR(wifi_pkg); 397 goto out_free; 398 } 399 400 if (wifi_pkg->package.elements[1].type != ACPI_TYPE_INTEGER || 401 tbl_rev != 0) { 402 ret = -EINVAL; 403 goto out_free; 404 } 405 406 *extl_clk = wifi_pkg->package.elements[1].integer.value; 407 408 ret = 0; 409 410 out_free: 411 kfree(data); 412 return ret; 413 } 414 IWL_EXPORT_SYMBOL(iwl_acpi_get_eckv); 415 416 static int iwl_sar_set_profile(union acpi_object *table, 417 struct iwl_sar_profile *profile, 418 bool enabled, u8 num_chains, u8 num_sub_bands) 419 { 420 int i, j, idx = 0; 421 422 /* 423 * The table from ACPI is flat, but we store it in a 424 * structured array. 425 */ 426 for (i = 0; i < ACPI_SAR_NUM_CHAINS_REV2; i++) { 427 for (j = 0; j < ACPI_SAR_NUM_SUB_BANDS_REV2; j++) { 428 /* if we don't have the values, use the default */ 429 if (i >= num_chains || j >= num_sub_bands) { 430 profile->chains[i].subbands[j] = 0; 431 } else { 432 if (table[idx].type != ACPI_TYPE_INTEGER || 433 table[idx].integer.value > U8_MAX) 434 return -EINVAL; 435 436 profile->chains[i].subbands[j] = 437 table[idx].integer.value; 438 439 idx++; 440 } 441 } 442 } 443 444 /* Only if all values were valid can the profile be enabled */ 445 profile->enabled = enabled; 446 447 return 0; 448 } 449 450 static int iwl_sar_fill_table(struct iwl_fw_runtime *fwrt, 451 __le16 *per_chain, u32 n_subbands, 452 int prof_a, int prof_b) 453 { 454 int profs[ACPI_SAR_NUM_CHAINS_REV0] = { prof_a, prof_b }; 455 int i, j; 456 457 for (i = 0; i < ACPI_SAR_NUM_CHAINS_REV0; i++) { 458 struct iwl_sar_profile *prof; 459 460 /* don't allow SAR to be disabled (profile 0 means disable) */ 461 if (profs[i] == 0) 462 return -EPERM; 463 464 /* we are off by one, so allow up to ACPI_SAR_PROFILE_NUM */ 465 if (profs[i] > ACPI_SAR_PROFILE_NUM) 466 return -EINVAL; 467 468 /* profiles go from 1 to 4, so decrement to access the array */ 469 prof = &fwrt->sar_profiles[profs[i] - 1]; 470 471 /* if the profile is disabled, do nothing */ 472 if (!prof->enabled) { 473 IWL_DEBUG_RADIO(fwrt, "SAR profile %d is disabled.\n", 474 profs[i]); 475 /* 476 * if one of the profiles is disabled, we 477 * ignore all of them and return 1 to 478 * differentiate disabled from other failures. 479 */ 480 return 1; 481 } 482 483 IWL_DEBUG_INFO(fwrt, 484 "SAR EWRD: chain %d profile index %d\n", 485 i, profs[i]); 486 IWL_DEBUG_RADIO(fwrt, " Chain[%d]:\n", i); 487 for (j = 0; j < n_subbands; j++) { 488 per_chain[i * n_subbands + j] = 489 cpu_to_le16(prof->chains[i].subbands[j]); 490 IWL_DEBUG_RADIO(fwrt, " Band[%d] = %d * .125dBm\n", 491 j, prof->chains[i].subbands[j]); 492 } 493 } 494 495 return 0; 496 } 497 498 int iwl_sar_select_profile(struct iwl_fw_runtime *fwrt, 499 __le16 *per_chain, u32 n_tables, u32 n_subbands, 500 int prof_a, int prof_b) 501 { 502 int i, ret = 0; 503 504 for (i = 0; i < n_tables; i++) { 505 ret = iwl_sar_fill_table(fwrt, 506 &per_chain[i * n_subbands * ACPI_SAR_NUM_CHAINS_REV0], 507 n_subbands, prof_a, prof_b); 508 if (ret) 509 break; 510 } 511 512 return ret; 513 } 514 IWL_EXPORT_SYMBOL(iwl_sar_select_profile); 515 516 int iwl_sar_get_wrds_table(struct iwl_fw_runtime *fwrt) 517 { 518 union acpi_object *wifi_pkg, *table, *data; 519 bool enabled; 520 int ret, tbl_rev; 521 u8 num_chains, num_sub_bands; 522 523 data = iwl_acpi_get_object(fwrt->dev, ACPI_WRDS_METHOD); 524 if (IS_ERR(data)) 525 return PTR_ERR(data); 526 527 /* start by trying to read revision 2 */ 528 wifi_pkg = iwl_acpi_get_wifi_pkg(fwrt->dev, data, 529 ACPI_WRDS_WIFI_DATA_SIZE_REV2, 530 &tbl_rev); 531 if (!IS_ERR(wifi_pkg)) { 532 if (tbl_rev != 2) { 533 ret = PTR_ERR(wifi_pkg); 534 goto out_free; 535 } 536 537 num_chains = ACPI_SAR_NUM_CHAINS_REV2; 538 num_sub_bands = ACPI_SAR_NUM_SUB_BANDS_REV2; 539 540 goto read_table; 541 } 542 543 /* then try revision 1 */ 544 wifi_pkg = iwl_acpi_get_wifi_pkg(fwrt->dev, data, 545 ACPI_WRDS_WIFI_DATA_SIZE_REV1, 546 &tbl_rev); 547 if (!IS_ERR(wifi_pkg)) { 548 if (tbl_rev != 1) { 549 ret = PTR_ERR(wifi_pkg); 550 goto out_free; 551 } 552 553 num_chains = ACPI_SAR_NUM_CHAINS_REV1; 554 num_sub_bands = ACPI_SAR_NUM_SUB_BANDS_REV1; 555 556 goto read_table; 557 } 558 559 /* then finally revision 0 */ 560 wifi_pkg = iwl_acpi_get_wifi_pkg(fwrt->dev, data, 561 ACPI_WRDS_WIFI_DATA_SIZE_REV0, 562 &tbl_rev); 563 if (!IS_ERR(wifi_pkg)) { 564 if (tbl_rev != 0) { 565 ret = PTR_ERR(wifi_pkg); 566 goto out_free; 567 } 568 569 num_chains = ACPI_SAR_NUM_CHAINS_REV0; 570 num_sub_bands = ACPI_SAR_NUM_SUB_BANDS_REV0; 571 572 goto read_table; 573 } 574 575 ret = PTR_ERR(wifi_pkg); 576 goto out_free; 577 578 read_table: 579 if (wifi_pkg->package.elements[1].type != ACPI_TYPE_INTEGER) { 580 ret = -EINVAL; 581 goto out_free; 582 } 583 584 IWL_DEBUG_RADIO(fwrt, "Reading WRDS tbl_rev=%d\n", tbl_rev); 585 586 enabled = !!(wifi_pkg->package.elements[1].integer.value); 587 588 /* position of the actual table */ 589 table = &wifi_pkg->package.elements[2]; 590 591 /* The profile from WRDS is officially profile 1, but goes 592 * into sar_profiles[0] (because we don't have a profile 0). 593 */ 594 ret = iwl_sar_set_profile(table, &fwrt->sar_profiles[0], enabled, 595 num_chains, num_sub_bands); 596 out_free: 597 kfree(data); 598 return ret; 599 } 600 IWL_EXPORT_SYMBOL(iwl_sar_get_wrds_table); 601 602 int iwl_sar_get_ewrd_table(struct iwl_fw_runtime *fwrt) 603 { 604 union acpi_object *wifi_pkg, *data; 605 bool enabled; 606 int i, n_profiles, tbl_rev, pos; 607 int ret = 0; 608 u8 num_chains, num_sub_bands; 609 610 data = iwl_acpi_get_object(fwrt->dev, ACPI_EWRD_METHOD); 611 if (IS_ERR(data)) 612 return PTR_ERR(data); 613 614 /* start by trying to read revision 2 */ 615 wifi_pkg = iwl_acpi_get_wifi_pkg(fwrt->dev, data, 616 ACPI_EWRD_WIFI_DATA_SIZE_REV2, 617 &tbl_rev); 618 if (!IS_ERR(wifi_pkg)) { 619 if (tbl_rev != 2) { 620 ret = PTR_ERR(wifi_pkg); 621 goto out_free; 622 } 623 624 num_chains = ACPI_SAR_NUM_CHAINS_REV2; 625 num_sub_bands = ACPI_SAR_NUM_SUB_BANDS_REV2; 626 627 goto read_table; 628 } 629 630 /* then try revision 1 */ 631 wifi_pkg = iwl_acpi_get_wifi_pkg(fwrt->dev, data, 632 ACPI_EWRD_WIFI_DATA_SIZE_REV1, 633 &tbl_rev); 634 if (!IS_ERR(wifi_pkg)) { 635 if (tbl_rev != 1) { 636 ret = PTR_ERR(wifi_pkg); 637 goto out_free; 638 } 639 640 num_chains = ACPI_SAR_NUM_CHAINS_REV1; 641 num_sub_bands = ACPI_SAR_NUM_SUB_BANDS_REV1; 642 643 goto read_table; 644 } 645 646 /* then finally revision 0 */ 647 wifi_pkg = iwl_acpi_get_wifi_pkg(fwrt->dev, data, 648 ACPI_EWRD_WIFI_DATA_SIZE_REV0, 649 &tbl_rev); 650 if (!IS_ERR(wifi_pkg)) { 651 if (tbl_rev != 0) { 652 ret = PTR_ERR(wifi_pkg); 653 goto out_free; 654 } 655 656 num_chains = ACPI_SAR_NUM_CHAINS_REV0; 657 num_sub_bands = ACPI_SAR_NUM_SUB_BANDS_REV0; 658 659 goto read_table; 660 } 661 662 ret = PTR_ERR(wifi_pkg); 663 goto out_free; 664 665 read_table: 666 if (wifi_pkg->package.elements[1].type != ACPI_TYPE_INTEGER || 667 wifi_pkg->package.elements[2].type != ACPI_TYPE_INTEGER) { 668 ret = -EINVAL; 669 goto out_free; 670 } 671 672 enabled = !!(wifi_pkg->package.elements[1].integer.value); 673 n_profiles = wifi_pkg->package.elements[2].integer.value; 674 675 /* 676 * Check the validity of n_profiles. The EWRD profiles start 677 * from index 1, so the maximum value allowed here is 678 * ACPI_SAR_PROFILES_NUM - 1. 679 */ 680 if (n_profiles <= 0 || n_profiles >= ACPI_SAR_PROFILE_NUM) { 681 ret = -EINVAL; 682 goto out_free; 683 } 684 685 /* the tables start at element 3 */ 686 pos = 3; 687 688 for (i = 0; i < n_profiles; i++) { 689 /* The EWRD profiles officially go from 2 to 4, but we 690 * save them in sar_profiles[1-3] (because we don't 691 * have profile 0). So in the array we start from 1. 692 */ 693 ret = iwl_sar_set_profile(&wifi_pkg->package.elements[pos], 694 &fwrt->sar_profiles[i + 1], enabled, 695 num_chains, num_sub_bands); 696 if (ret < 0) 697 break; 698 699 /* go to the next table */ 700 pos += num_chains * num_sub_bands; 701 } 702 703 out_free: 704 kfree(data); 705 return ret; 706 } 707 IWL_EXPORT_SYMBOL(iwl_sar_get_ewrd_table); 708 709 int iwl_sar_get_wgds_table(struct iwl_fw_runtime *fwrt) 710 { 711 union acpi_object *wifi_pkg, *data; 712 int i, j, k, ret, tbl_rev; 713 u8 num_bands, num_profiles; 714 static const struct { 715 u8 revisions; 716 u8 bands; 717 u8 profiles; 718 u8 min_profiles; 719 } rev_data[] = { 720 { 721 .revisions = BIT(3), 722 .bands = ACPI_GEO_NUM_BANDS_REV2, 723 .profiles = ACPI_NUM_GEO_PROFILES_REV3, 724 .min_profiles = 3, 725 }, 726 { 727 .revisions = BIT(2), 728 .bands = ACPI_GEO_NUM_BANDS_REV2, 729 .profiles = ACPI_NUM_GEO_PROFILES, 730 }, 731 { 732 .revisions = BIT(0) | BIT(1), 733 .bands = ACPI_GEO_NUM_BANDS_REV0, 734 .profiles = ACPI_NUM_GEO_PROFILES, 735 }, 736 }; 737 int idx; 738 /* start from one to skip the domain */ 739 int entry_idx = 1; 740 741 BUILD_BUG_ON(ACPI_NUM_GEO_PROFILES_REV3 != IWL_NUM_GEO_PROFILES_V3); 742 BUILD_BUG_ON(ACPI_NUM_GEO_PROFILES != IWL_NUM_GEO_PROFILES); 743 744 data = iwl_acpi_get_object(fwrt->dev, ACPI_WGDS_METHOD); 745 if (IS_ERR(data)) 746 return PTR_ERR(data); 747 748 /* read the highest revision we understand first */ 749 for (idx = 0; idx < ARRAY_SIZE(rev_data); idx++) { 750 /* min_profiles != 0 requires num_profiles header */ 751 u32 hdr_size = 1 + !!rev_data[idx].min_profiles; 752 u32 profile_size = ACPI_GEO_PER_CHAIN_SIZE * 753 rev_data[idx].bands; 754 u32 max_size = hdr_size + profile_size * rev_data[idx].profiles; 755 u32 min_size; 756 757 if (!rev_data[idx].min_profiles) 758 min_size = max_size; 759 else 760 min_size = hdr_size + 761 profile_size * rev_data[idx].min_profiles; 762 763 wifi_pkg = iwl_acpi_get_wifi_pkg_range(fwrt->dev, data, 764 min_size, max_size, 765 &tbl_rev); 766 if (!IS_ERR(wifi_pkg)) { 767 if (!(BIT(tbl_rev) & rev_data[idx].revisions)) 768 continue; 769 770 num_bands = rev_data[idx].bands; 771 num_profiles = rev_data[idx].profiles; 772 773 if (rev_data[idx].min_profiles) { 774 /* read header that says # of profiles */ 775 union acpi_object *entry; 776 777 entry = &wifi_pkg->package.elements[entry_idx]; 778 entry_idx++; 779 if (entry->type != ACPI_TYPE_INTEGER || 780 entry->integer.value > num_profiles) { 781 ret = -EINVAL; 782 goto out_free; 783 } 784 num_profiles = entry->integer.value; 785 786 /* 787 * this also validates >= min_profiles since we 788 * otherwise wouldn't have gotten the data when 789 * looking up in ACPI 790 */ 791 if (wifi_pkg->package.count != 792 min_size + profile_size * num_profiles) { 793 ret = -EINVAL; 794 goto out_free; 795 } 796 } 797 goto read_table; 798 } 799 } 800 801 if (idx < ARRAY_SIZE(rev_data)) 802 ret = PTR_ERR(wifi_pkg); 803 else 804 ret = -ENOENT; 805 goto out_free; 806 807 read_table: 808 fwrt->geo_rev = tbl_rev; 809 for (i = 0; i < num_profiles; i++) { 810 for (j = 0; j < ACPI_GEO_NUM_BANDS_REV2; j++) { 811 union acpi_object *entry; 812 813 /* 814 * num_bands is either 2 or 3, if it's only 2 then 815 * fill the third band (6 GHz) with the values from 816 * 5 GHz (second band) 817 */ 818 if (j >= num_bands) { 819 fwrt->geo_profiles[i].bands[j].max = 820 fwrt->geo_profiles[i].bands[1].max; 821 } else { 822 entry = &wifi_pkg->package.elements[entry_idx]; 823 entry_idx++; 824 if (entry->type != ACPI_TYPE_INTEGER || 825 entry->integer.value > U8_MAX) { 826 ret = -EINVAL; 827 goto out_free; 828 } 829 830 fwrt->geo_profiles[i].bands[j].max = 831 entry->integer.value; 832 } 833 834 for (k = 0; k < ACPI_GEO_NUM_CHAINS; k++) { 835 /* same here as above */ 836 if (j >= num_bands) { 837 fwrt->geo_profiles[i].bands[j].chains[k] = 838 fwrt->geo_profiles[i].bands[1].chains[k]; 839 } else { 840 entry = &wifi_pkg->package.elements[entry_idx]; 841 entry_idx++; 842 if (entry->type != ACPI_TYPE_INTEGER || 843 entry->integer.value > U8_MAX) { 844 ret = -EINVAL; 845 goto out_free; 846 } 847 848 fwrt->geo_profiles[i].bands[j].chains[k] = 849 entry->integer.value; 850 } 851 } 852 } 853 } 854 855 ret = 0; 856 out_free: 857 kfree(data); 858 return ret; 859 } 860 IWL_EXPORT_SYMBOL(iwl_sar_get_wgds_table); 861 862 bool iwl_sar_geo_support(struct iwl_fw_runtime *fwrt) 863 { 864 /* 865 * The PER_CHAIN_LIMIT_OFFSET_CMD command is not supported on 866 * earlier firmware versions. Unfortunately, we don't have a 867 * TLV API flag to rely on, so rely on the major version which 868 * is in the first byte of ucode_ver. This was implemented 869 * initially on version 38 and then backported to 17. It was 870 * also backported to 29, but only for 7265D devices. The 871 * intention was to have it in 36 as well, but not all 8000 872 * family got this feature enabled. The 8000 family is the 873 * only one using version 36, so skip this version entirely. 874 */ 875 return IWL_UCODE_SERIAL(fwrt->fw->ucode_ver) >= 38 || 876 IWL_UCODE_SERIAL(fwrt->fw->ucode_ver) == 17 || 877 (IWL_UCODE_SERIAL(fwrt->fw->ucode_ver) == 29 && 878 ((fwrt->trans->hw_rev & CSR_HW_REV_TYPE_MSK) == 879 CSR_HW_REV_TYPE_7265D)); 880 } 881 IWL_EXPORT_SYMBOL(iwl_sar_geo_support); 882 883 int iwl_sar_geo_init(struct iwl_fw_runtime *fwrt, 884 struct iwl_per_chain_offset *table, 885 u32 n_bands, u32 n_profiles) 886 { 887 int i, j; 888 889 if (!iwl_sar_geo_support(fwrt)) 890 return -EOPNOTSUPP; 891 892 for (i = 0; i < n_profiles; i++) { 893 for (j = 0; j < n_bands; j++) { 894 struct iwl_per_chain_offset *chain = 895 &table[i * n_bands + j]; 896 897 chain->max_tx_power = 898 cpu_to_le16(fwrt->geo_profiles[i].bands[j].max); 899 chain->chain_a = fwrt->geo_profiles[i].bands[j].chains[0]; 900 chain->chain_b = fwrt->geo_profiles[i].bands[j].chains[1]; 901 IWL_DEBUG_RADIO(fwrt, 902 "SAR geographic profile[%d] Band[%d]: chain A = %d chain B = %d max_tx_power = %d\n", 903 i, j, 904 fwrt->geo_profiles[i].bands[j].chains[0], 905 fwrt->geo_profiles[i].bands[j].chains[1], 906 fwrt->geo_profiles[i].bands[j].max); 907 } 908 } 909 910 return 0; 911 } 912 IWL_EXPORT_SYMBOL(iwl_sar_geo_init); 913 914 __le32 iwl_acpi_get_lari_config_bitmap(struct iwl_fw_runtime *fwrt) 915 { 916 int ret; 917 u8 value; 918 __le32 config_bitmap = 0; 919 920 /* 921 ** Evaluate func 'DSM_FUNC_ENABLE_INDONESIA_5G2' 922 */ 923 ret = iwl_acpi_get_dsm_u8(fwrt->dev, 0, 924 DSM_FUNC_ENABLE_INDONESIA_5G2, 925 &iwl_guid, &value); 926 927 if (!ret && value == DSM_VALUE_INDONESIA_ENABLE) 928 config_bitmap |= 929 cpu_to_le32(LARI_CONFIG_ENABLE_5G2_IN_INDONESIA_MSK); 930 931 /* 932 ** Evaluate func 'DSM_FUNC_DISABLE_SRD' 933 */ 934 ret = iwl_acpi_get_dsm_u8(fwrt->dev, 0, 935 DSM_FUNC_DISABLE_SRD, 936 &iwl_guid, &value); 937 if (!ret) { 938 if (value == DSM_VALUE_SRD_PASSIVE) 939 config_bitmap |= 940 cpu_to_le32(LARI_CONFIG_CHANGE_ETSI_TO_PASSIVE_MSK); 941 else if (value == DSM_VALUE_SRD_DISABLE) 942 config_bitmap |= 943 cpu_to_le32(LARI_CONFIG_CHANGE_ETSI_TO_DISABLED_MSK); 944 } 945 946 return config_bitmap; 947 } 948 IWL_EXPORT_SYMBOL(iwl_acpi_get_lari_config_bitmap); 949