1 // SPDX-License-Identifier: GPL-2.0 OR BSD-3-Clause 2 /* 3 * Copyright (C) 2017 Intel Deutschland GmbH 4 * Copyright (C) 2019-2022 Intel Corporation 5 */ 6 #include <linux/uuid.h> 7 #include <linux/dmi.h> 8 #include "iwl-drv.h" 9 #include "iwl-debug.h" 10 #include "acpi.h" 11 #include "fw/runtime.h" 12 13 const guid_t iwl_guid = GUID_INIT(0xF21202BF, 0x8F78, 0x4DC6, 14 0xA5, 0xB3, 0x1F, 0x73, 15 0x8E, 0x28, 0x5A, 0xDE); 16 IWL_EXPORT_SYMBOL(iwl_guid); 17 18 const guid_t iwl_rfi_guid = GUID_INIT(0x7266172C, 0x220B, 0x4B29, 19 0x81, 0x4F, 0x75, 0xE4, 20 0xDD, 0x26, 0xB5, 0xFD); 21 IWL_EXPORT_SYMBOL(iwl_rfi_guid); 22 23 static const struct dmi_system_id dmi_ppag_approved_list[] = { 24 { .ident = "HP", 25 .matches = { 26 DMI_MATCH(DMI_SYS_VENDOR, "HP"), 27 }, 28 }, 29 { .ident = "SAMSUNG", 30 .matches = { 31 DMI_MATCH(DMI_SYS_VENDOR, "SAMSUNG ELECTRONICS CO., LTD"), 32 }, 33 }, 34 { .ident = "MSFT", 35 .matches = { 36 DMI_MATCH(DMI_SYS_VENDOR, "Microsoft Corporation"), 37 }, 38 }, 39 { .ident = "ASUS", 40 .matches = { 41 DMI_MATCH(DMI_SYS_VENDOR, "ASUSTeK COMPUTER INC."), 42 }, 43 }, 44 {} 45 }; 46 47 static int iwl_acpi_get_handle(struct device *dev, acpi_string method, 48 acpi_handle *ret_handle) 49 { 50 acpi_handle root_handle; 51 acpi_status status; 52 53 root_handle = ACPI_HANDLE(dev); 54 if (!root_handle) { 55 IWL_DEBUG_DEV_RADIO(dev, 56 "ACPI: Could not retrieve root port handle\n"); 57 return -ENOENT; 58 } 59 60 status = acpi_get_handle(root_handle, method, ret_handle); 61 if (ACPI_FAILURE(status)) { 62 IWL_DEBUG_DEV_RADIO(dev, 63 "ACPI: %s method not found\n", method); 64 return -ENOENT; 65 } 66 return 0; 67 } 68 69 void *iwl_acpi_get_object(struct device *dev, acpi_string method) 70 { 71 struct acpi_buffer buf = {ACPI_ALLOCATE_BUFFER, NULL}; 72 acpi_handle handle; 73 acpi_status status; 74 int ret; 75 76 ret = iwl_acpi_get_handle(dev, method, &handle); 77 if (ret) 78 return ERR_PTR(-ENOENT); 79 80 /* Call the method with no arguments */ 81 status = acpi_evaluate_object(handle, NULL, NULL, &buf); 82 if (ACPI_FAILURE(status)) { 83 IWL_DEBUG_DEV_RADIO(dev, 84 "ACPI: %s method invocation failed (status: 0x%x)\n", 85 method, status); 86 return ERR_PTR(-ENOENT); 87 } 88 return buf.pointer; 89 } 90 IWL_EXPORT_SYMBOL(iwl_acpi_get_object); 91 92 /* 93 * Generic function for evaluating a method defined in the device specific 94 * method (DSM) interface. The returned acpi object must be freed by calling 95 * function. 96 */ 97 static void *iwl_acpi_get_dsm_object(struct device *dev, int rev, int func, 98 union acpi_object *args, 99 const guid_t *guid) 100 { 101 union acpi_object *obj; 102 103 obj = acpi_evaluate_dsm(ACPI_HANDLE(dev), guid, rev, func, 104 args); 105 if (!obj) { 106 IWL_DEBUG_DEV_RADIO(dev, 107 "ACPI: DSM method invocation failed (rev: %d, func:%d)\n", 108 rev, func); 109 return ERR_PTR(-ENOENT); 110 } 111 return obj; 112 } 113 114 /* 115 * Generic function to evaluate a DSM with no arguments 116 * and an integer return value, 117 * (as an integer object or inside a buffer object), 118 * verify and assign the value in the "value" parameter. 119 * return 0 in success and the appropriate errno otherwise. 120 */ 121 static int iwl_acpi_get_dsm_integer(struct device *dev, int rev, int func, 122 const guid_t *guid, u64 *value, 123 size_t expected_size) 124 { 125 union acpi_object *obj; 126 int ret = 0; 127 128 obj = iwl_acpi_get_dsm_object(dev, rev, func, NULL, guid); 129 if (IS_ERR(obj)) { 130 IWL_DEBUG_DEV_RADIO(dev, 131 "Failed to get DSM object. func= %d\n", 132 func); 133 return -ENOENT; 134 } 135 136 if (obj->type == ACPI_TYPE_INTEGER) { 137 *value = obj->integer.value; 138 } else if (obj->type == ACPI_TYPE_BUFFER) { 139 __le64 le_value = 0; 140 141 if (WARN_ON_ONCE(expected_size > sizeof(le_value))) 142 return -EINVAL; 143 144 /* if the buffer size doesn't match the expected size */ 145 if (obj->buffer.length != expected_size) 146 IWL_DEBUG_DEV_RADIO(dev, 147 "ACPI: DSM invalid buffer size, padding or truncating (%d)\n", 148 obj->buffer.length); 149 150 /* assuming LE from Intel BIOS spec */ 151 memcpy(&le_value, obj->buffer.pointer, 152 min_t(size_t, expected_size, (size_t)obj->buffer.length)); 153 *value = le64_to_cpu(le_value); 154 } else { 155 IWL_DEBUG_DEV_RADIO(dev, 156 "ACPI: DSM method did not return a valid object, type=%d\n", 157 obj->type); 158 ret = -EINVAL; 159 goto out; 160 } 161 162 IWL_DEBUG_DEV_RADIO(dev, 163 "ACPI: DSM method evaluated: func=%d, ret=%d\n", 164 func, ret); 165 out: 166 ACPI_FREE(obj); 167 return ret; 168 } 169 170 /* 171 * Evaluate a DSM with no arguments and a u8 return value, 172 */ 173 int iwl_acpi_get_dsm_u8(struct device *dev, int rev, int func, 174 const guid_t *guid, u8 *value) 175 { 176 int ret; 177 u64 val; 178 179 ret = iwl_acpi_get_dsm_integer(dev, rev, func, 180 guid, &val, sizeof(u8)); 181 182 if (ret < 0) 183 return ret; 184 185 /* cast val (u64) to be u8 */ 186 *value = (u8)val; 187 return 0; 188 } 189 IWL_EXPORT_SYMBOL(iwl_acpi_get_dsm_u8); 190 191 /* 192 * Evaluate a DSM with no arguments and a u32 return value, 193 */ 194 int iwl_acpi_get_dsm_u32(struct device *dev, int rev, int func, 195 const guid_t *guid, u32 *value) 196 { 197 int ret; 198 u64 val; 199 200 ret = iwl_acpi_get_dsm_integer(dev, rev, func, 201 guid, &val, sizeof(u32)); 202 203 if (ret < 0) 204 return ret; 205 206 /* cast val (u64) to be u32 */ 207 *value = (u32)val; 208 return 0; 209 } 210 IWL_EXPORT_SYMBOL(iwl_acpi_get_dsm_u32); 211 212 union acpi_object *iwl_acpi_get_wifi_pkg_range(struct device *dev, 213 union acpi_object *data, 214 int min_data_size, 215 int max_data_size, 216 int *tbl_rev) 217 { 218 int i; 219 union acpi_object *wifi_pkg; 220 221 /* 222 * We need at least one entry in the wifi package that 223 * describes the domain, and one more entry, otherwise there's 224 * no point in reading it. 225 */ 226 if (WARN_ON_ONCE(min_data_size < 2 || min_data_size > max_data_size)) 227 return ERR_PTR(-EINVAL); 228 229 /* 230 * We need at least two packages, one for the revision and one 231 * for the data itself. Also check that the revision is valid 232 * (i.e. it is an integer (each caller has to check by itself 233 * if the returned revision is supported)). 234 */ 235 if (data->type != ACPI_TYPE_PACKAGE || 236 data->package.count < 2 || 237 data->package.elements[0].type != ACPI_TYPE_INTEGER) { 238 IWL_DEBUG_DEV_RADIO(dev, "Invalid packages structure\n"); 239 return ERR_PTR(-EINVAL); 240 } 241 242 *tbl_rev = data->package.elements[0].integer.value; 243 244 /* loop through all the packages to find the one for WiFi */ 245 for (i = 1; i < data->package.count; i++) { 246 union acpi_object *domain; 247 248 wifi_pkg = &data->package.elements[i]; 249 250 /* skip entries that are not a package with the right size */ 251 if (wifi_pkg->type != ACPI_TYPE_PACKAGE || 252 wifi_pkg->package.count < min_data_size || 253 wifi_pkg->package.count > max_data_size) 254 continue; 255 256 domain = &wifi_pkg->package.elements[0]; 257 if (domain->type == ACPI_TYPE_INTEGER && 258 domain->integer.value == ACPI_WIFI_DOMAIN) 259 goto found; 260 } 261 262 return ERR_PTR(-ENOENT); 263 264 found: 265 return wifi_pkg; 266 } 267 IWL_EXPORT_SYMBOL(iwl_acpi_get_wifi_pkg_range); 268 269 int iwl_acpi_get_tas(struct iwl_fw_runtime *fwrt, 270 union iwl_tas_config_cmd *cmd, int fw_ver) 271 { 272 union acpi_object *wifi_pkg, *data; 273 int ret, tbl_rev, i, block_list_size, enabled; 274 275 data = iwl_acpi_get_object(fwrt->dev, ACPI_WTAS_METHOD); 276 if (IS_ERR(data)) 277 return PTR_ERR(data); 278 279 /* try to read wtas table revision 1 or revision 0*/ 280 wifi_pkg = iwl_acpi_get_wifi_pkg(fwrt->dev, data, 281 ACPI_WTAS_WIFI_DATA_SIZE, 282 &tbl_rev); 283 if (IS_ERR(wifi_pkg)) { 284 ret = PTR_ERR(wifi_pkg); 285 goto out_free; 286 } 287 288 if (tbl_rev == 1 && wifi_pkg->package.elements[1].type == 289 ACPI_TYPE_INTEGER) { 290 u32 tas_selection = 291 (u32)wifi_pkg->package.elements[1].integer.value; 292 u16 override_iec = 293 (tas_selection & ACPI_WTAS_OVERRIDE_IEC_MSK) >> ACPI_WTAS_OVERRIDE_IEC_POS; 294 u16 enabled_iec = (tas_selection & ACPI_WTAS_ENABLE_IEC_MSK) >> 295 ACPI_WTAS_ENABLE_IEC_POS; 296 u8 usa_tas_uhb = (tas_selection & ACPI_WTAS_USA_UHB_MSK) >> ACPI_WTAS_USA_UHB_POS; 297 298 299 enabled = tas_selection & ACPI_WTAS_ENABLED_MSK; 300 if (fw_ver <= 3) { 301 cmd->v3.override_tas_iec = cpu_to_le16(override_iec); 302 cmd->v3.enable_tas_iec = cpu_to_le16(enabled_iec); 303 } else { 304 cmd->v4.usa_tas_uhb_allowed = usa_tas_uhb; 305 cmd->v4.override_tas_iec = (u8)override_iec; 306 cmd->v4.enable_tas_iec = (u8)enabled_iec; 307 } 308 309 } else if (tbl_rev == 0 && 310 wifi_pkg->package.elements[1].type == ACPI_TYPE_INTEGER) { 311 enabled = !!wifi_pkg->package.elements[1].integer.value; 312 } else { 313 ret = -EINVAL; 314 goto out_free; 315 } 316 317 if (!enabled) { 318 IWL_DEBUG_RADIO(fwrt, "TAS not enabled\n"); 319 ret = 0; 320 goto out_free; 321 } 322 323 IWL_DEBUG_RADIO(fwrt, "Reading TAS table revision %d\n", tbl_rev); 324 if (wifi_pkg->package.elements[2].type != ACPI_TYPE_INTEGER || 325 wifi_pkg->package.elements[2].integer.value > 326 APCI_WTAS_BLACK_LIST_MAX) { 327 IWL_DEBUG_RADIO(fwrt, "TAS invalid array size %llu\n", 328 wifi_pkg->package.elements[2].integer.value); 329 ret = -EINVAL; 330 goto out_free; 331 } 332 block_list_size = wifi_pkg->package.elements[2].integer.value; 333 cmd->v4.block_list_size = cpu_to_le32(block_list_size); 334 335 IWL_DEBUG_RADIO(fwrt, "TAS array size %u\n", block_list_size); 336 if (block_list_size > APCI_WTAS_BLACK_LIST_MAX) { 337 IWL_DEBUG_RADIO(fwrt, "TAS invalid array size value %u\n", 338 block_list_size); 339 ret = -EINVAL; 340 goto out_free; 341 } 342 343 for (i = 0; i < block_list_size; i++) { 344 u32 country; 345 346 if (wifi_pkg->package.elements[3 + i].type != 347 ACPI_TYPE_INTEGER) { 348 IWL_DEBUG_RADIO(fwrt, 349 "TAS invalid array elem %d\n", 3 + i); 350 ret = -EINVAL; 351 goto out_free; 352 } 353 354 country = wifi_pkg->package.elements[3 + i].integer.value; 355 cmd->v4.block_list_array[i] = cpu_to_le32(country); 356 IWL_DEBUG_RADIO(fwrt, "TAS block list country %d\n", country); 357 } 358 359 ret = 1; 360 out_free: 361 kfree(data); 362 return ret; 363 } 364 IWL_EXPORT_SYMBOL(iwl_acpi_get_tas); 365 366 int iwl_acpi_get_mcc(struct device *dev, char *mcc) 367 { 368 union acpi_object *wifi_pkg, *data; 369 u32 mcc_val; 370 int ret, tbl_rev; 371 372 data = iwl_acpi_get_object(dev, ACPI_WRDD_METHOD); 373 if (IS_ERR(data)) 374 return PTR_ERR(data); 375 376 wifi_pkg = iwl_acpi_get_wifi_pkg(dev, data, ACPI_WRDD_WIFI_DATA_SIZE, 377 &tbl_rev); 378 if (IS_ERR(wifi_pkg)) { 379 ret = PTR_ERR(wifi_pkg); 380 goto out_free; 381 } 382 383 if (wifi_pkg->package.elements[1].type != ACPI_TYPE_INTEGER || 384 tbl_rev != 0) { 385 ret = -EINVAL; 386 goto out_free; 387 } 388 389 mcc_val = wifi_pkg->package.elements[1].integer.value; 390 391 mcc[0] = (mcc_val >> 8) & 0xff; 392 mcc[1] = mcc_val & 0xff; 393 mcc[2] = '\0'; 394 395 ret = 0; 396 out_free: 397 kfree(data); 398 return ret; 399 } 400 IWL_EXPORT_SYMBOL(iwl_acpi_get_mcc); 401 402 u64 iwl_acpi_get_pwr_limit(struct device *dev) 403 { 404 union acpi_object *data, *wifi_pkg; 405 u64 dflt_pwr_limit; 406 int tbl_rev; 407 408 data = iwl_acpi_get_object(dev, ACPI_SPLC_METHOD); 409 if (IS_ERR(data)) { 410 dflt_pwr_limit = 0; 411 goto out; 412 } 413 414 wifi_pkg = iwl_acpi_get_wifi_pkg(dev, data, 415 ACPI_SPLC_WIFI_DATA_SIZE, &tbl_rev); 416 if (IS_ERR(wifi_pkg) || tbl_rev != 0 || 417 wifi_pkg->package.elements[1].integer.value != ACPI_TYPE_INTEGER) { 418 dflt_pwr_limit = 0; 419 goto out_free; 420 } 421 422 dflt_pwr_limit = wifi_pkg->package.elements[1].integer.value; 423 out_free: 424 kfree(data); 425 out: 426 return dflt_pwr_limit; 427 } 428 IWL_EXPORT_SYMBOL(iwl_acpi_get_pwr_limit); 429 430 int iwl_acpi_get_eckv(struct device *dev, u32 *extl_clk) 431 { 432 union acpi_object *wifi_pkg, *data; 433 int ret, tbl_rev; 434 435 data = iwl_acpi_get_object(dev, ACPI_ECKV_METHOD); 436 if (IS_ERR(data)) 437 return PTR_ERR(data); 438 439 wifi_pkg = iwl_acpi_get_wifi_pkg(dev, data, ACPI_ECKV_WIFI_DATA_SIZE, 440 &tbl_rev); 441 if (IS_ERR(wifi_pkg)) { 442 ret = PTR_ERR(wifi_pkg); 443 goto out_free; 444 } 445 446 if (wifi_pkg->package.elements[1].type != ACPI_TYPE_INTEGER || 447 tbl_rev != 0) { 448 ret = -EINVAL; 449 goto out_free; 450 } 451 452 *extl_clk = wifi_pkg->package.elements[1].integer.value; 453 454 ret = 0; 455 456 out_free: 457 kfree(data); 458 return ret; 459 } 460 IWL_EXPORT_SYMBOL(iwl_acpi_get_eckv); 461 462 static int iwl_sar_set_profile(union acpi_object *table, 463 struct iwl_sar_profile *profile, 464 bool enabled, u8 num_chains, u8 num_sub_bands) 465 { 466 int i, j, idx = 0; 467 468 /* 469 * The table from ACPI is flat, but we store it in a 470 * structured array. 471 */ 472 for (i = 0; i < ACPI_SAR_NUM_CHAINS_REV2; i++) { 473 for (j = 0; j < ACPI_SAR_NUM_SUB_BANDS_REV2; j++) { 474 /* if we don't have the values, use the default */ 475 if (i >= num_chains || j >= num_sub_bands) { 476 profile->chains[i].subbands[j] = 0; 477 } else { 478 if (table[idx].type != ACPI_TYPE_INTEGER || 479 table[idx].integer.value > U8_MAX) 480 return -EINVAL; 481 482 profile->chains[i].subbands[j] = 483 table[idx].integer.value; 484 485 idx++; 486 } 487 } 488 } 489 490 /* Only if all values were valid can the profile be enabled */ 491 profile->enabled = enabled; 492 493 return 0; 494 } 495 496 static int iwl_sar_fill_table(struct iwl_fw_runtime *fwrt, 497 __le16 *per_chain, u32 n_subbands, 498 int prof_a, int prof_b) 499 { 500 int profs[ACPI_SAR_NUM_CHAINS_REV0] = { prof_a, prof_b }; 501 int i, j; 502 503 for (i = 0; i < ACPI_SAR_NUM_CHAINS_REV0; i++) { 504 struct iwl_sar_profile *prof; 505 506 /* don't allow SAR to be disabled (profile 0 means disable) */ 507 if (profs[i] == 0) 508 return -EPERM; 509 510 /* we are off by one, so allow up to ACPI_SAR_PROFILE_NUM */ 511 if (profs[i] > ACPI_SAR_PROFILE_NUM) 512 return -EINVAL; 513 514 /* profiles go from 1 to 4, so decrement to access the array */ 515 prof = &fwrt->sar_profiles[profs[i] - 1]; 516 517 /* if the profile is disabled, do nothing */ 518 if (!prof->enabled) { 519 IWL_DEBUG_RADIO(fwrt, "SAR profile %d is disabled.\n", 520 profs[i]); 521 /* 522 * if one of the profiles is disabled, we 523 * ignore all of them and return 1 to 524 * differentiate disabled from other failures. 525 */ 526 return 1; 527 } 528 529 IWL_DEBUG_INFO(fwrt, 530 "SAR EWRD: chain %d profile index %d\n", 531 i, profs[i]); 532 IWL_DEBUG_RADIO(fwrt, " Chain[%d]:\n", i); 533 for (j = 0; j < n_subbands; j++) { 534 per_chain[i * n_subbands + j] = 535 cpu_to_le16(prof->chains[i].subbands[j]); 536 IWL_DEBUG_RADIO(fwrt, " Band[%d] = %d * .125dBm\n", 537 j, prof->chains[i].subbands[j]); 538 } 539 } 540 541 return 0; 542 } 543 544 int iwl_sar_select_profile(struct iwl_fw_runtime *fwrt, 545 __le16 *per_chain, u32 n_tables, u32 n_subbands, 546 int prof_a, int prof_b) 547 { 548 int i, ret = 0; 549 550 for (i = 0; i < n_tables; i++) { 551 ret = iwl_sar_fill_table(fwrt, 552 &per_chain[i * n_subbands * ACPI_SAR_NUM_CHAINS_REV0], 553 n_subbands, prof_a, prof_b); 554 if (ret) 555 break; 556 } 557 558 return ret; 559 } 560 IWL_EXPORT_SYMBOL(iwl_sar_select_profile); 561 562 int iwl_sar_get_wrds_table(struct iwl_fw_runtime *fwrt) 563 { 564 union acpi_object *wifi_pkg, *table, *data; 565 int ret, tbl_rev; 566 u32 flags; 567 u8 num_chains, num_sub_bands; 568 569 data = iwl_acpi_get_object(fwrt->dev, ACPI_WRDS_METHOD); 570 if (IS_ERR(data)) 571 return PTR_ERR(data); 572 573 /* start by trying to read revision 2 */ 574 wifi_pkg = iwl_acpi_get_wifi_pkg(fwrt->dev, data, 575 ACPI_WRDS_WIFI_DATA_SIZE_REV2, 576 &tbl_rev); 577 if (!IS_ERR(wifi_pkg)) { 578 if (tbl_rev != 2) { 579 ret = PTR_ERR(wifi_pkg); 580 goto out_free; 581 } 582 583 num_chains = ACPI_SAR_NUM_CHAINS_REV2; 584 num_sub_bands = ACPI_SAR_NUM_SUB_BANDS_REV2; 585 586 goto read_table; 587 } 588 589 /* then try revision 1 */ 590 wifi_pkg = iwl_acpi_get_wifi_pkg(fwrt->dev, data, 591 ACPI_WRDS_WIFI_DATA_SIZE_REV1, 592 &tbl_rev); 593 if (!IS_ERR(wifi_pkg)) { 594 if (tbl_rev != 1) { 595 ret = PTR_ERR(wifi_pkg); 596 goto out_free; 597 } 598 599 num_chains = ACPI_SAR_NUM_CHAINS_REV1; 600 num_sub_bands = ACPI_SAR_NUM_SUB_BANDS_REV1; 601 602 goto read_table; 603 } 604 605 /* then finally revision 0 */ 606 wifi_pkg = iwl_acpi_get_wifi_pkg(fwrt->dev, data, 607 ACPI_WRDS_WIFI_DATA_SIZE_REV0, 608 &tbl_rev); 609 if (!IS_ERR(wifi_pkg)) { 610 if (tbl_rev != 0) { 611 ret = PTR_ERR(wifi_pkg); 612 goto out_free; 613 } 614 615 num_chains = ACPI_SAR_NUM_CHAINS_REV0; 616 num_sub_bands = ACPI_SAR_NUM_SUB_BANDS_REV0; 617 618 goto read_table; 619 } 620 621 ret = PTR_ERR(wifi_pkg); 622 goto out_free; 623 624 read_table: 625 if (wifi_pkg->package.elements[1].type != ACPI_TYPE_INTEGER) { 626 ret = -EINVAL; 627 goto out_free; 628 } 629 630 IWL_DEBUG_RADIO(fwrt, "Reading WRDS tbl_rev=%d\n", tbl_rev); 631 632 flags = wifi_pkg->package.elements[1].integer.value; 633 fwrt->reduced_power_flags = flags >> IWL_REDUCE_POWER_FLAGS_POS; 634 635 /* position of the actual table */ 636 table = &wifi_pkg->package.elements[2]; 637 638 /* The profile from WRDS is officially profile 1, but goes 639 * into sar_profiles[0] (because we don't have a profile 0). 640 */ 641 ret = iwl_sar_set_profile(table, &fwrt->sar_profiles[0], 642 flags & IWL_SAR_ENABLE_MSK, 643 num_chains, num_sub_bands); 644 out_free: 645 kfree(data); 646 return ret; 647 } 648 IWL_EXPORT_SYMBOL(iwl_sar_get_wrds_table); 649 650 int iwl_sar_get_ewrd_table(struct iwl_fw_runtime *fwrt) 651 { 652 union acpi_object *wifi_pkg, *data; 653 bool enabled; 654 int i, n_profiles, tbl_rev, pos; 655 int ret = 0; 656 u8 num_chains, num_sub_bands; 657 658 data = iwl_acpi_get_object(fwrt->dev, ACPI_EWRD_METHOD); 659 if (IS_ERR(data)) 660 return PTR_ERR(data); 661 662 /* start by trying to read revision 2 */ 663 wifi_pkg = iwl_acpi_get_wifi_pkg(fwrt->dev, data, 664 ACPI_EWRD_WIFI_DATA_SIZE_REV2, 665 &tbl_rev); 666 if (!IS_ERR(wifi_pkg)) { 667 if (tbl_rev != 2) { 668 ret = PTR_ERR(wifi_pkg); 669 goto out_free; 670 } 671 672 num_chains = ACPI_SAR_NUM_CHAINS_REV2; 673 num_sub_bands = ACPI_SAR_NUM_SUB_BANDS_REV2; 674 675 goto read_table; 676 } 677 678 /* then try revision 1 */ 679 wifi_pkg = iwl_acpi_get_wifi_pkg(fwrt->dev, data, 680 ACPI_EWRD_WIFI_DATA_SIZE_REV1, 681 &tbl_rev); 682 if (!IS_ERR(wifi_pkg)) { 683 if (tbl_rev != 1) { 684 ret = PTR_ERR(wifi_pkg); 685 goto out_free; 686 } 687 688 num_chains = ACPI_SAR_NUM_CHAINS_REV1; 689 num_sub_bands = ACPI_SAR_NUM_SUB_BANDS_REV1; 690 691 goto read_table; 692 } 693 694 /* then finally revision 0 */ 695 wifi_pkg = iwl_acpi_get_wifi_pkg(fwrt->dev, data, 696 ACPI_EWRD_WIFI_DATA_SIZE_REV0, 697 &tbl_rev); 698 if (!IS_ERR(wifi_pkg)) { 699 if (tbl_rev != 0) { 700 ret = PTR_ERR(wifi_pkg); 701 goto out_free; 702 } 703 704 num_chains = ACPI_SAR_NUM_CHAINS_REV0; 705 num_sub_bands = ACPI_SAR_NUM_SUB_BANDS_REV0; 706 707 goto read_table; 708 } 709 710 ret = PTR_ERR(wifi_pkg); 711 goto out_free; 712 713 read_table: 714 if (wifi_pkg->package.elements[1].type != ACPI_TYPE_INTEGER || 715 wifi_pkg->package.elements[2].type != ACPI_TYPE_INTEGER) { 716 ret = -EINVAL; 717 goto out_free; 718 } 719 720 enabled = !!(wifi_pkg->package.elements[1].integer.value); 721 n_profiles = wifi_pkg->package.elements[2].integer.value; 722 723 /* 724 * Check the validity of n_profiles. The EWRD profiles start 725 * from index 1, so the maximum value allowed here is 726 * ACPI_SAR_PROFILES_NUM - 1. 727 */ 728 if (n_profiles <= 0 || n_profiles >= ACPI_SAR_PROFILE_NUM) { 729 ret = -EINVAL; 730 goto out_free; 731 } 732 733 /* the tables start at element 3 */ 734 pos = 3; 735 736 for (i = 0; i < n_profiles; i++) { 737 /* The EWRD profiles officially go from 2 to 4, but we 738 * save them in sar_profiles[1-3] (because we don't 739 * have profile 0). So in the array we start from 1. 740 */ 741 ret = iwl_sar_set_profile(&wifi_pkg->package.elements[pos], 742 &fwrt->sar_profiles[i + 1], enabled, 743 num_chains, num_sub_bands); 744 if (ret < 0) 745 break; 746 747 /* go to the next table */ 748 pos += num_chains * num_sub_bands; 749 } 750 751 out_free: 752 kfree(data); 753 return ret; 754 } 755 IWL_EXPORT_SYMBOL(iwl_sar_get_ewrd_table); 756 757 int iwl_sar_get_wgds_table(struct iwl_fw_runtime *fwrt) 758 { 759 union acpi_object *wifi_pkg, *data; 760 int i, j, k, ret, tbl_rev; 761 u8 num_bands, num_profiles; 762 static const struct { 763 u8 revisions; 764 u8 bands; 765 u8 profiles; 766 u8 min_profiles; 767 } rev_data[] = { 768 { 769 .revisions = BIT(3), 770 .bands = ACPI_GEO_NUM_BANDS_REV2, 771 .profiles = ACPI_NUM_GEO_PROFILES_REV3, 772 .min_profiles = 3, 773 }, 774 { 775 .revisions = BIT(2), 776 .bands = ACPI_GEO_NUM_BANDS_REV2, 777 .profiles = ACPI_NUM_GEO_PROFILES, 778 }, 779 { 780 .revisions = BIT(0) | BIT(1), 781 .bands = ACPI_GEO_NUM_BANDS_REV0, 782 .profiles = ACPI_NUM_GEO_PROFILES, 783 }, 784 }; 785 int idx; 786 /* start from one to skip the domain */ 787 int entry_idx = 1; 788 789 BUILD_BUG_ON(ACPI_NUM_GEO_PROFILES_REV3 != IWL_NUM_GEO_PROFILES_V3); 790 BUILD_BUG_ON(ACPI_NUM_GEO_PROFILES != IWL_NUM_GEO_PROFILES); 791 792 data = iwl_acpi_get_object(fwrt->dev, ACPI_WGDS_METHOD); 793 if (IS_ERR(data)) 794 return PTR_ERR(data); 795 796 /* read the highest revision we understand first */ 797 for (idx = 0; idx < ARRAY_SIZE(rev_data); idx++) { 798 /* min_profiles != 0 requires num_profiles header */ 799 u32 hdr_size = 1 + !!rev_data[idx].min_profiles; 800 u32 profile_size = ACPI_GEO_PER_CHAIN_SIZE * 801 rev_data[idx].bands; 802 u32 max_size = hdr_size + profile_size * rev_data[idx].profiles; 803 u32 min_size; 804 805 if (!rev_data[idx].min_profiles) 806 min_size = max_size; 807 else 808 min_size = hdr_size + 809 profile_size * rev_data[idx].min_profiles; 810 811 wifi_pkg = iwl_acpi_get_wifi_pkg_range(fwrt->dev, data, 812 min_size, max_size, 813 &tbl_rev); 814 if (!IS_ERR(wifi_pkg)) { 815 if (!(BIT(tbl_rev) & rev_data[idx].revisions)) 816 continue; 817 818 num_bands = rev_data[idx].bands; 819 num_profiles = rev_data[idx].profiles; 820 821 if (rev_data[idx].min_profiles) { 822 /* read header that says # of profiles */ 823 union acpi_object *entry; 824 825 entry = &wifi_pkg->package.elements[entry_idx]; 826 entry_idx++; 827 if (entry->type != ACPI_TYPE_INTEGER || 828 entry->integer.value > num_profiles) { 829 ret = -EINVAL; 830 goto out_free; 831 } 832 num_profiles = entry->integer.value; 833 834 /* 835 * this also validates >= min_profiles since we 836 * otherwise wouldn't have gotten the data when 837 * looking up in ACPI 838 */ 839 if (wifi_pkg->package.count != 840 hdr_size + profile_size * num_profiles) { 841 ret = -EINVAL; 842 goto out_free; 843 } 844 } 845 goto read_table; 846 } 847 } 848 849 if (idx < ARRAY_SIZE(rev_data)) 850 ret = PTR_ERR(wifi_pkg); 851 else 852 ret = -ENOENT; 853 goto out_free; 854 855 read_table: 856 fwrt->geo_rev = tbl_rev; 857 for (i = 0; i < num_profiles; i++) { 858 for (j = 0; j < ACPI_GEO_NUM_BANDS_REV2; j++) { 859 union acpi_object *entry; 860 861 /* 862 * num_bands is either 2 or 3, if it's only 2 then 863 * fill the third band (6 GHz) with the values from 864 * 5 GHz (second band) 865 */ 866 if (j >= num_bands) { 867 fwrt->geo_profiles[i].bands[j].max = 868 fwrt->geo_profiles[i].bands[1].max; 869 } else { 870 entry = &wifi_pkg->package.elements[entry_idx]; 871 entry_idx++; 872 if (entry->type != ACPI_TYPE_INTEGER || 873 entry->integer.value > U8_MAX) { 874 ret = -EINVAL; 875 goto out_free; 876 } 877 878 fwrt->geo_profiles[i].bands[j].max = 879 entry->integer.value; 880 } 881 882 for (k = 0; k < ACPI_GEO_NUM_CHAINS; k++) { 883 /* same here as above */ 884 if (j >= num_bands) { 885 fwrt->geo_profiles[i].bands[j].chains[k] = 886 fwrt->geo_profiles[i].bands[1].chains[k]; 887 } else { 888 entry = &wifi_pkg->package.elements[entry_idx]; 889 entry_idx++; 890 if (entry->type != ACPI_TYPE_INTEGER || 891 entry->integer.value > U8_MAX) { 892 ret = -EINVAL; 893 goto out_free; 894 } 895 896 fwrt->geo_profiles[i].bands[j].chains[k] = 897 entry->integer.value; 898 } 899 } 900 } 901 } 902 903 fwrt->geo_num_profiles = num_profiles; 904 fwrt->geo_enabled = true; 905 ret = 0; 906 out_free: 907 kfree(data); 908 return ret; 909 } 910 IWL_EXPORT_SYMBOL(iwl_sar_get_wgds_table); 911 912 bool iwl_sar_geo_support(struct iwl_fw_runtime *fwrt) 913 { 914 /* 915 * The PER_CHAIN_LIMIT_OFFSET_CMD command is not supported on 916 * earlier firmware versions. Unfortunately, we don't have a 917 * TLV API flag to rely on, so rely on the major version which 918 * is in the first byte of ucode_ver. This was implemented 919 * initially on version 38 and then backported to 17. It was 920 * also backported to 29, but only for 7265D devices. The 921 * intention was to have it in 36 as well, but not all 8000 922 * family got this feature enabled. The 8000 family is the 923 * only one using version 36, so skip this version entirely. 924 */ 925 return IWL_UCODE_SERIAL(fwrt->fw->ucode_ver) >= 38 || 926 (IWL_UCODE_SERIAL(fwrt->fw->ucode_ver) == 17 && 927 fwrt->trans->hw_rev != CSR_HW_REV_TYPE_3160) || 928 (IWL_UCODE_SERIAL(fwrt->fw->ucode_ver) == 29 && 929 ((fwrt->trans->hw_rev & CSR_HW_REV_TYPE_MSK) == 930 CSR_HW_REV_TYPE_7265D)); 931 } 932 IWL_EXPORT_SYMBOL(iwl_sar_geo_support); 933 934 int iwl_sar_geo_init(struct iwl_fw_runtime *fwrt, 935 struct iwl_per_chain_offset *table, 936 u32 n_bands, u32 n_profiles) 937 { 938 int i, j; 939 940 if (!fwrt->geo_enabled) 941 return -ENODATA; 942 943 if (!iwl_sar_geo_support(fwrt)) 944 return -EOPNOTSUPP; 945 946 for (i = 0; i < n_profiles; i++) { 947 for (j = 0; j < n_bands; j++) { 948 struct iwl_per_chain_offset *chain = 949 &table[i * n_bands + j]; 950 951 chain->max_tx_power = 952 cpu_to_le16(fwrt->geo_profiles[i].bands[j].max); 953 chain->chain_a = fwrt->geo_profiles[i].bands[j].chains[0]; 954 chain->chain_b = fwrt->geo_profiles[i].bands[j].chains[1]; 955 IWL_DEBUG_RADIO(fwrt, 956 "SAR geographic profile[%d] Band[%d]: chain A = %d chain B = %d max_tx_power = %d\n", 957 i, j, 958 fwrt->geo_profiles[i].bands[j].chains[0], 959 fwrt->geo_profiles[i].bands[j].chains[1], 960 fwrt->geo_profiles[i].bands[j].max); 961 } 962 } 963 964 return 0; 965 } 966 IWL_EXPORT_SYMBOL(iwl_sar_geo_init); 967 968 __le32 iwl_acpi_get_lari_config_bitmap(struct iwl_fw_runtime *fwrt) 969 { 970 int ret; 971 u8 value; 972 __le32 config_bitmap = 0; 973 974 /* 975 ** Evaluate func 'DSM_FUNC_ENABLE_INDONESIA_5G2' 976 */ 977 ret = iwl_acpi_get_dsm_u8(fwrt->dev, 0, 978 DSM_FUNC_ENABLE_INDONESIA_5G2, 979 &iwl_guid, &value); 980 981 if (!ret && value == DSM_VALUE_INDONESIA_ENABLE) 982 config_bitmap |= 983 cpu_to_le32(LARI_CONFIG_ENABLE_5G2_IN_INDONESIA_MSK); 984 985 /* 986 ** Evaluate func 'DSM_FUNC_DISABLE_SRD' 987 */ 988 ret = iwl_acpi_get_dsm_u8(fwrt->dev, 0, 989 DSM_FUNC_DISABLE_SRD, 990 &iwl_guid, &value); 991 if (!ret) { 992 if (value == DSM_VALUE_SRD_PASSIVE) 993 config_bitmap |= 994 cpu_to_le32(LARI_CONFIG_CHANGE_ETSI_TO_PASSIVE_MSK); 995 else if (value == DSM_VALUE_SRD_DISABLE) 996 config_bitmap |= 997 cpu_to_le32(LARI_CONFIG_CHANGE_ETSI_TO_DISABLED_MSK); 998 } 999 1000 return config_bitmap; 1001 } 1002 IWL_EXPORT_SYMBOL(iwl_acpi_get_lari_config_bitmap); 1003 1004 int iwl_acpi_get_ppag_table(struct iwl_fw_runtime *fwrt) 1005 { 1006 union acpi_object *wifi_pkg, *data, *flags; 1007 int i, j, ret, tbl_rev, num_sub_bands = 0; 1008 int idx = 2; 1009 u8 cmd_ver; 1010 1011 fwrt->ppag_flags = 0; 1012 fwrt->ppag_table_valid = false; 1013 1014 data = iwl_acpi_get_object(fwrt->dev, ACPI_PPAG_METHOD); 1015 if (IS_ERR(data)) 1016 return PTR_ERR(data); 1017 1018 /* try to read ppag table rev 2 or 1 (both have the same data size) */ 1019 wifi_pkg = iwl_acpi_get_wifi_pkg(fwrt->dev, data, 1020 ACPI_PPAG_WIFI_DATA_SIZE_V2, &tbl_rev); 1021 1022 if (!IS_ERR(wifi_pkg)) { 1023 if (tbl_rev == 1 || tbl_rev == 2) { 1024 num_sub_bands = IWL_NUM_SUB_BANDS_V2; 1025 IWL_DEBUG_RADIO(fwrt, 1026 "Reading PPAG table v2 (tbl_rev=%d)\n", 1027 tbl_rev); 1028 goto read_table; 1029 } else { 1030 ret = -EINVAL; 1031 goto out_free; 1032 } 1033 } 1034 1035 /* try to read ppag table revision 0 */ 1036 wifi_pkg = iwl_acpi_get_wifi_pkg(fwrt->dev, data, 1037 ACPI_PPAG_WIFI_DATA_SIZE_V1, &tbl_rev); 1038 1039 if (!IS_ERR(wifi_pkg)) { 1040 if (tbl_rev != 0) { 1041 ret = -EINVAL; 1042 goto out_free; 1043 } 1044 num_sub_bands = IWL_NUM_SUB_BANDS_V1; 1045 IWL_DEBUG_RADIO(fwrt, "Reading PPAG table v1 (tbl_rev=0)\n"); 1046 goto read_table; 1047 } 1048 1049 read_table: 1050 fwrt->ppag_ver = tbl_rev; 1051 flags = &wifi_pkg->package.elements[1]; 1052 1053 if (flags->type != ACPI_TYPE_INTEGER) { 1054 ret = -EINVAL; 1055 goto out_free; 1056 } 1057 1058 fwrt->ppag_flags = flags->integer.value & ACPI_PPAG_MASK; 1059 cmd_ver = iwl_fw_lookup_cmd_ver(fwrt->fw, 1060 WIDE_ID(PHY_OPS_GROUP, 1061 PER_PLATFORM_ANT_GAIN_CMD), 1062 IWL_FW_CMD_VER_UNKNOWN); 1063 if (cmd_ver == IWL_FW_CMD_VER_UNKNOWN) { 1064 ret = -EINVAL; 1065 goto out_free; 1066 } 1067 if (!fwrt->ppag_flags && cmd_ver <= 3) { 1068 ret = 0; 1069 goto out_free; 1070 } 1071 1072 /* 1073 * read, verify gain values and save them into the PPAG table. 1074 * first sub-band (j=0) corresponds to Low-Band (2.4GHz), and the 1075 * following sub-bands to High-Band (5GHz). 1076 */ 1077 for (i = 0; i < IWL_NUM_CHAIN_LIMITS; i++) { 1078 for (j = 0; j < num_sub_bands; j++) { 1079 union acpi_object *ent; 1080 1081 ent = &wifi_pkg->package.elements[idx++]; 1082 if (ent->type != ACPI_TYPE_INTEGER) { 1083 ret = -EINVAL; 1084 goto out_free; 1085 } 1086 1087 fwrt->ppag_chains[i].subbands[j] = ent->integer.value; 1088 /* from ver 4 the fw deals with out of range values */ 1089 if (cmd_ver >= 4) 1090 continue; 1091 if ((j == 0 && 1092 (fwrt->ppag_chains[i].subbands[j] > ACPI_PPAG_MAX_LB || 1093 fwrt->ppag_chains[i].subbands[j] < ACPI_PPAG_MIN_LB)) || 1094 (j != 0 && 1095 (fwrt->ppag_chains[i].subbands[j] > ACPI_PPAG_MAX_HB || 1096 fwrt->ppag_chains[i].subbands[j] < ACPI_PPAG_MIN_HB))) { 1097 ret = -EINVAL; 1098 goto out_free; 1099 } 1100 } 1101 } 1102 1103 fwrt->ppag_table_valid = true; 1104 ret = 0; 1105 1106 out_free: 1107 kfree(data); 1108 return ret; 1109 } 1110 IWL_EXPORT_SYMBOL(iwl_acpi_get_ppag_table); 1111 1112 int iwl_read_ppag_table(struct iwl_fw_runtime *fwrt, union iwl_ppag_table_cmd *cmd, 1113 int *cmd_size) 1114 { 1115 u8 cmd_ver; 1116 int i, j, num_sub_bands; 1117 s8 *gain; 1118 1119 /* many firmware images for JF lie about this */ 1120 if (CSR_HW_RFID_TYPE(fwrt->trans->hw_rf_id) == 1121 CSR_HW_RFID_TYPE(CSR_HW_RF_ID_TYPE_JF)) 1122 return -EOPNOTSUPP; 1123 1124 if (!fw_has_capa(&fwrt->fw->ucode_capa, IWL_UCODE_TLV_CAPA_SET_PPAG)) { 1125 IWL_DEBUG_RADIO(fwrt, 1126 "PPAG capability not supported by FW, command not sent.\n"); 1127 return -EINVAL; 1128 } 1129 1130 cmd_ver = iwl_fw_lookup_cmd_ver(fwrt->fw, 1131 WIDE_ID(PHY_OPS_GROUP, 1132 PER_PLATFORM_ANT_GAIN_CMD), 1133 IWL_FW_CMD_VER_UNKNOWN); 1134 if (!fwrt->ppag_table_valid || (cmd_ver <= 3 && !fwrt->ppag_flags)) { 1135 IWL_DEBUG_RADIO(fwrt, "PPAG not enabled, command not sent.\n"); 1136 return -EINVAL; 1137 } 1138 1139 /* The 'flags' field is the same in v1 and in v2 so we can just 1140 * use v1 to access it. 1141 */ 1142 cmd->v1.flags = cpu_to_le32(fwrt->ppag_flags); 1143 1144 if (cmd_ver == 1) { 1145 num_sub_bands = IWL_NUM_SUB_BANDS_V1; 1146 gain = cmd->v1.gain[0]; 1147 *cmd_size = sizeof(cmd->v1); 1148 if (fwrt->ppag_ver == 1 || fwrt->ppag_ver == 2) { 1149 IWL_DEBUG_RADIO(fwrt, 1150 "PPAG table rev is %d but FW supports v1, sending truncated table\n", 1151 fwrt->ppag_ver); 1152 cmd->v1.flags &= cpu_to_le32(IWL_PPAG_ETSI_MASK); 1153 } 1154 } else if (cmd_ver >= 2 && cmd_ver <= 4) { 1155 num_sub_bands = IWL_NUM_SUB_BANDS_V2; 1156 gain = cmd->v2.gain[0]; 1157 *cmd_size = sizeof(cmd->v2); 1158 if (fwrt->ppag_ver == 0) { 1159 IWL_DEBUG_RADIO(fwrt, 1160 "PPAG table is v1 but FW supports v2, sending padded table\n"); 1161 } else if (cmd_ver == 2 && fwrt->ppag_ver == 2) { 1162 IWL_DEBUG_RADIO(fwrt, 1163 "PPAG table is v3 but FW supports v2, sending partial bitmap.\n"); 1164 cmd->v1.flags &= cpu_to_le32(IWL_PPAG_ETSI_MASK); 1165 } 1166 } else { 1167 IWL_DEBUG_RADIO(fwrt, "Unsupported PPAG command version\n"); 1168 return -EINVAL; 1169 } 1170 1171 for (i = 0; i < IWL_NUM_CHAIN_LIMITS; i++) { 1172 for (j = 0; j < num_sub_bands; j++) { 1173 gain[i * num_sub_bands + j] = 1174 fwrt->ppag_chains[i].subbands[j]; 1175 IWL_DEBUG_RADIO(fwrt, 1176 "PPAG table: chain[%d] band[%d]: gain = %d\n", 1177 i, j, gain[i * num_sub_bands + j]); 1178 } 1179 } 1180 1181 return 0; 1182 } 1183 IWL_EXPORT_SYMBOL(iwl_read_ppag_table); 1184 1185 bool iwl_acpi_is_ppag_approved(struct iwl_fw_runtime *fwrt) 1186 { 1187 1188 if (!dmi_check_system(dmi_ppag_approved_list)) { 1189 IWL_DEBUG_RADIO(fwrt, 1190 "System vendor '%s' is not in the approved list, disabling PPAG.\n", 1191 dmi_get_system_info(DMI_SYS_VENDOR)); 1192 fwrt->ppag_flags = 0; 1193 return false; 1194 } 1195 1196 return true; 1197 } 1198 IWL_EXPORT_SYMBOL(iwl_acpi_is_ppag_approved); 1199