diff options
-rw-r--r-- | drivers/net/wireless/intel/iwlwifi/pcie/drv.c | 79 |
1 files changed, 48 insertions, 31 deletions
diff --git a/drivers/net/wireless/intel/iwlwifi/pcie/drv.c b/drivers/net/wireless/intel/iwlwifi/pcie/drv.c index 001be406a3d3..2f8134b2a504 100644 --- a/drivers/net/wireless/intel/iwlwifi/pcie/drv.c +++ b/drivers/net/wireless/intel/iwlwifi/pcie/drv.c | |||
@@ -541,48 +541,64 @@ static const struct pci_device_id iwl_hw_card_ids[] = { | |||
541 | MODULE_DEVICE_TABLE(pci, iwl_hw_card_ids); | 541 | MODULE_DEVICE_TABLE(pci, iwl_hw_card_ids); |
542 | 542 | ||
543 | #ifdef CONFIG_ACPI | 543 | #ifdef CONFIG_ACPI |
544 | #define SPL_METHOD "SPLC" | 544 | #define ACPI_SPLC_METHOD "SPLC" |
545 | #define SPL_DOMAINTYPE_MODULE BIT(0) | 545 | #define ACPI_SPLC_DOMAIN_WIFI (0x07) |
546 | #define SPL_DOMAINTYPE_WIFI BIT(1) | ||
547 | #define SPL_DOMAINTYPE_WIGIG BIT(2) | ||
548 | #define SPL_DOMAINTYPE_RFEM BIT(3) | ||
549 | 546 | ||
550 | static u64 splx_get_pwr_limit(struct iwl_trans *trans, union acpi_object *splx) | 547 | static u64 splc_get_pwr_limit(struct iwl_trans *trans, union acpi_object *splc) |
551 | { | 548 | { |
552 | union acpi_object *limits, *domain_type, *power_limit; | 549 | union acpi_object *data_pkg, *dflt_pwr_limit; |
553 | 550 | int i; | |
554 | if (splx->type != ACPI_TYPE_PACKAGE || | 551 | |
555 | splx->package.count != 2 || | 552 | /* We need at least two elements, one for the revision and one |
556 | splx->package.elements[0].type != ACPI_TYPE_INTEGER || | 553 | * for the data itself. Also check that the revision is |
557 | splx->package.elements[0].integer.value != 0) { | 554 | * supported (currently only revision 0). |
558 | IWL_ERR(trans, "Unsupported splx structure\n"); | 555 | */ |
556 | if (splc->type != ACPI_TYPE_PACKAGE || | ||
557 | splc->package.count < 2 || | ||
558 | splc->package.elements[0].type != ACPI_TYPE_INTEGER || | ||
559 | splc->package.elements[0].integer.value != 0) { | ||
560 | IWL_DEBUG_INFO(trans, | ||
561 | "Unsupported structure returned by the SPLC method. Ignoring.\n"); | ||
559 | return 0; | 562 | return 0; |
560 | } | 563 | } |
561 | 564 | ||
562 | limits = &splx->package.elements[1]; | 565 | /* loop through all the packages to find the one for WiFi */ |
563 | if (limits->type != ACPI_TYPE_PACKAGE || | 566 | for (i = 1; i < splc->package.count; i++) { |
564 | limits->package.count < 2 || | 567 | union acpi_object *domain; |
565 | limits->package.elements[0].type != ACPI_TYPE_INTEGER || | 568 | |
566 | limits->package.elements[1].type != ACPI_TYPE_INTEGER) { | 569 | data_pkg = &splc->package.elements[i]; |
567 | IWL_ERR(trans, "Invalid limits element\n"); | 570 | |
568 | return 0; | 571 | /* Skip anything that is not a package with the right |
572 | * amount of elements (i.e. at least 2 integers). | ||
573 | */ | ||
574 | if (data_pkg->type != ACPI_TYPE_PACKAGE || | ||
575 | data_pkg->package.count < 2 || | ||
576 | data_pkg->package.elements[0].type != ACPI_TYPE_INTEGER || | ||
577 | data_pkg->package.elements[1].type != ACPI_TYPE_INTEGER) | ||
578 | continue; | ||
579 | |||
580 | domain = &data_pkg->package.elements[0]; | ||
581 | if (domain->integer.value == ACPI_SPLC_DOMAIN_WIFI) | ||
582 | break; | ||
583 | |||
584 | data_pkg = NULL; | ||
569 | } | 585 | } |
570 | 586 | ||
571 | domain_type = &limits->package.elements[0]; | 587 | if (!data_pkg) { |
572 | power_limit = &limits->package.elements[1]; | 588 | IWL_DEBUG_INFO(trans, |
573 | if (!(domain_type->integer.value & SPL_DOMAINTYPE_WIFI)) { | 589 | "No element for the WiFi domain returned by the SPLC method.\n"); |
574 | IWL_DEBUG_INFO(trans, "WiFi power is not limited\n"); | ||
575 | return 0; | 590 | return 0; |
576 | } | 591 | } |
577 | 592 | ||
578 | return power_limit->integer.value; | 593 | dflt_pwr_limit = &data_pkg->package.elements[1]; |
594 | return dflt_pwr_limit->integer.value; | ||
579 | } | 595 | } |
580 | 596 | ||
581 | static void set_dflt_pwr_limit(struct iwl_trans *trans, struct pci_dev *pdev) | 597 | static void set_dflt_pwr_limit(struct iwl_trans *trans, struct pci_dev *pdev) |
582 | { | 598 | { |
583 | acpi_handle pxsx_handle; | 599 | acpi_handle pxsx_handle; |
584 | acpi_handle handle; | 600 | acpi_handle handle; |
585 | struct acpi_buffer splx = {ACPI_ALLOCATE_BUFFER, NULL}; | 601 | struct acpi_buffer splc = {ACPI_ALLOCATE_BUFFER, NULL}; |
586 | acpi_status status; | 602 | acpi_status status; |
587 | 603 | ||
588 | pxsx_handle = ACPI_HANDLE(&pdev->dev); | 604 | pxsx_handle = ACPI_HANDLE(&pdev->dev); |
@@ -593,23 +609,24 @@ static void set_dflt_pwr_limit(struct iwl_trans *trans, struct pci_dev *pdev) | |||
593 | } | 609 | } |
594 | 610 | ||
595 | /* Get the method's handle */ | 611 | /* Get the method's handle */ |
596 | status = acpi_get_handle(pxsx_handle, (acpi_string)SPL_METHOD, &handle); | 612 | status = acpi_get_handle(pxsx_handle, (acpi_string)ACPI_SPLC_METHOD, |
613 | &handle); | ||
597 | if (ACPI_FAILURE(status)) { | 614 | if (ACPI_FAILURE(status)) { |
598 | IWL_DEBUG_INFO(trans, "SPL method not found\n"); | 615 | IWL_DEBUG_INFO(trans, "SPLC method not found\n"); |
599 | return; | 616 | return; |
600 | } | 617 | } |
601 | 618 | ||
602 | /* Call SPLC with no arguments */ | 619 | /* Call SPLC with no arguments */ |
603 | status = acpi_evaluate_object(handle, NULL, NULL, &splx); | 620 | status = acpi_evaluate_object(handle, NULL, NULL, &splc); |
604 | if (ACPI_FAILURE(status)) { | 621 | if (ACPI_FAILURE(status)) { |
605 | IWL_ERR(trans, "SPLC invocation failed (0x%x)\n", status); | 622 | IWL_ERR(trans, "SPLC invocation failed (0x%x)\n", status); |
606 | return; | 623 | return; |
607 | } | 624 | } |
608 | 625 | ||
609 | trans->dflt_pwr_limit = splx_get_pwr_limit(trans, splx.pointer); | 626 | trans->dflt_pwr_limit = splc_get_pwr_limit(trans, splc.pointer); |
610 | IWL_DEBUG_INFO(trans, "Default power limit set to %lld\n", | 627 | IWL_DEBUG_INFO(trans, "Default power limit set to %lld\n", |
611 | trans->dflt_pwr_limit); | 628 | trans->dflt_pwr_limit); |
612 | kfree(splx.pointer); | 629 | kfree(splc.pointer); |
613 | } | 630 | } |
614 | 631 | ||
615 | #else /* CONFIG_ACPI */ | 632 | #else /* CONFIG_ACPI */ |