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