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