.. | .. |
---|
| 1 | +// SPDX-License-Identifier: GPL-2.0-only |
---|
1 | 2 | /* |
---|
2 | 3 | * acpi_processor.c - ACPI processor enumeration support |
---|
3 | 4 | * |
---|
.. | .. |
---|
7 | 8 | * Copyright (C) 2004 Anil S Keshavamurthy <anil.s.keshavamurthy@intel.com> |
---|
8 | 9 | * Copyright (C) 2013, Intel Corporation |
---|
9 | 10 | * Rafael J. Wysocki <rafael.j.wysocki@intel.com> |
---|
10 | | - * |
---|
11 | | - * This program is free software; you can redistribute it and/or modify it |
---|
12 | | - * under the terms of the GNU General Public License version 2 as published |
---|
13 | | - * by the Free Software Foundation. |
---|
14 | 11 | */ |
---|
15 | 12 | |
---|
16 | 13 | #include <linux/acpi.h> |
---|
.. | .. |
---|
82 | 79 | * PIIX4 models. |
---|
83 | 80 | */ |
---|
84 | 81 | errata.piix4.throttle = 1; |
---|
85 | | - /* fall through*/ |
---|
| 82 | + fallthrough; |
---|
86 | 83 | |
---|
87 | 84 | case 2: /* PIIX4E */ |
---|
88 | 85 | case 3: /* PIIX4M */ |
---|
.. | .. |
---|
267 | 264 | } else { |
---|
268 | 265 | /* |
---|
269 | 266 | * Declared with "Device" statement; match _UID. |
---|
270 | | - * Note that we don't handle string _UIDs yet. |
---|
271 | 267 | */ |
---|
272 | 268 | status = acpi_evaluate_integer(pr->handle, METHOD_NAME__UID, |
---|
273 | 269 | NULL, &value); |
---|
.. | .. |
---|
708 | 704 | acpi_scan_add_handler_with_hotplug(&processor_handler, "processor"); |
---|
709 | 705 | acpi_scan_add_handler(&processor_container_handler); |
---|
710 | 706 | } |
---|
| 707 | + |
---|
| 708 | +#ifdef CONFIG_ACPI_PROCESSOR_CSTATE |
---|
| 709 | +/** |
---|
| 710 | + * acpi_processor_claim_cst_control - Request _CST control from the platform. |
---|
| 711 | + */ |
---|
| 712 | +bool acpi_processor_claim_cst_control(void) |
---|
| 713 | +{ |
---|
| 714 | + static bool cst_control_claimed; |
---|
| 715 | + acpi_status status; |
---|
| 716 | + |
---|
| 717 | + if (!acpi_gbl_FADT.cst_control || cst_control_claimed) |
---|
| 718 | + return true; |
---|
| 719 | + |
---|
| 720 | + status = acpi_os_write_port(acpi_gbl_FADT.smi_command, |
---|
| 721 | + acpi_gbl_FADT.cst_control, 8); |
---|
| 722 | + if (ACPI_FAILURE(status)) { |
---|
| 723 | + pr_warn("ACPI: Failed to claim processor _CST control\n"); |
---|
| 724 | + return false; |
---|
| 725 | + } |
---|
| 726 | + |
---|
| 727 | + cst_control_claimed = true; |
---|
| 728 | + return true; |
---|
| 729 | +} |
---|
| 730 | +EXPORT_SYMBOL_GPL(acpi_processor_claim_cst_control); |
---|
| 731 | + |
---|
| 732 | +/** |
---|
| 733 | + * acpi_processor_evaluate_cst - Evaluate the processor _CST control method. |
---|
| 734 | + * @handle: ACPI handle of the processor object containing the _CST. |
---|
| 735 | + * @cpu: The numeric ID of the target CPU. |
---|
| 736 | + * @info: Object write the C-states information into. |
---|
| 737 | + * |
---|
| 738 | + * Extract the C-state information for the given CPU from the output of the _CST |
---|
| 739 | + * control method under the corresponding ACPI processor object (or processor |
---|
| 740 | + * device object) and populate @info with it. |
---|
| 741 | + * |
---|
| 742 | + * If any ACPI_ADR_SPACE_FIXED_HARDWARE C-states are found, invoke |
---|
| 743 | + * acpi_processor_ffh_cstate_probe() to verify them and update the |
---|
| 744 | + * cpu_cstate_entry data for @cpu. |
---|
| 745 | + */ |
---|
| 746 | +int acpi_processor_evaluate_cst(acpi_handle handle, u32 cpu, |
---|
| 747 | + struct acpi_processor_power *info) |
---|
| 748 | +{ |
---|
| 749 | + struct acpi_buffer buffer = { ACPI_ALLOCATE_BUFFER, NULL }; |
---|
| 750 | + union acpi_object *cst; |
---|
| 751 | + acpi_status status; |
---|
| 752 | + u64 count; |
---|
| 753 | + int last_index = 0; |
---|
| 754 | + int i, ret = 0; |
---|
| 755 | + |
---|
| 756 | + status = acpi_evaluate_object(handle, "_CST", NULL, &buffer); |
---|
| 757 | + if (ACPI_FAILURE(status)) { |
---|
| 758 | + acpi_handle_debug(handle, "No _CST\n"); |
---|
| 759 | + return -ENODEV; |
---|
| 760 | + } |
---|
| 761 | + |
---|
| 762 | + cst = buffer.pointer; |
---|
| 763 | + |
---|
| 764 | + /* There must be at least 2 elements. */ |
---|
| 765 | + if (!cst || cst->type != ACPI_TYPE_PACKAGE || cst->package.count < 2) { |
---|
| 766 | + acpi_handle_warn(handle, "Invalid _CST output\n"); |
---|
| 767 | + ret = -EFAULT; |
---|
| 768 | + goto end; |
---|
| 769 | + } |
---|
| 770 | + |
---|
| 771 | + count = cst->package.elements[0].integer.value; |
---|
| 772 | + |
---|
| 773 | + /* Validate the number of C-states. */ |
---|
| 774 | + if (count < 1 || count != cst->package.count - 1) { |
---|
| 775 | + acpi_handle_warn(handle, "Inconsistent _CST data\n"); |
---|
| 776 | + ret = -EFAULT; |
---|
| 777 | + goto end; |
---|
| 778 | + } |
---|
| 779 | + |
---|
| 780 | + for (i = 1; i <= count; i++) { |
---|
| 781 | + union acpi_object *element; |
---|
| 782 | + union acpi_object *obj; |
---|
| 783 | + struct acpi_power_register *reg; |
---|
| 784 | + struct acpi_processor_cx cx; |
---|
| 785 | + |
---|
| 786 | + /* |
---|
| 787 | + * If there is not enough space for all C-states, skip the |
---|
| 788 | + * excess ones and log a warning. |
---|
| 789 | + */ |
---|
| 790 | + if (last_index >= ACPI_PROCESSOR_MAX_POWER - 1) { |
---|
| 791 | + acpi_handle_warn(handle, |
---|
| 792 | + "No room for more idle states (limit: %d)\n", |
---|
| 793 | + ACPI_PROCESSOR_MAX_POWER - 1); |
---|
| 794 | + break; |
---|
| 795 | + } |
---|
| 796 | + |
---|
| 797 | + memset(&cx, 0, sizeof(cx)); |
---|
| 798 | + |
---|
| 799 | + element = &cst->package.elements[i]; |
---|
| 800 | + if (element->type != ACPI_TYPE_PACKAGE) { |
---|
| 801 | + acpi_handle_info(handle, "_CST C%d type(%x) is not package, skip...\n", |
---|
| 802 | + i, element->type); |
---|
| 803 | + continue; |
---|
| 804 | + } |
---|
| 805 | + |
---|
| 806 | + if (element->package.count != 4) { |
---|
| 807 | + acpi_handle_info(handle, "_CST C%d package count(%d) is not 4, skip...\n", |
---|
| 808 | + i, element->package.count); |
---|
| 809 | + continue; |
---|
| 810 | + } |
---|
| 811 | + |
---|
| 812 | + obj = &element->package.elements[0]; |
---|
| 813 | + |
---|
| 814 | + if (obj->type != ACPI_TYPE_BUFFER) { |
---|
| 815 | + acpi_handle_info(handle, "_CST C%d package element[0] type(%x) is not buffer, skip...\n", |
---|
| 816 | + i, obj->type); |
---|
| 817 | + continue; |
---|
| 818 | + } |
---|
| 819 | + |
---|
| 820 | + reg = (struct acpi_power_register *)obj->buffer.pointer; |
---|
| 821 | + |
---|
| 822 | + obj = &element->package.elements[1]; |
---|
| 823 | + if (obj->type != ACPI_TYPE_INTEGER) { |
---|
| 824 | + acpi_handle_info(handle, "_CST C[%d] package element[1] type(%x) is not integer, skip...\n", |
---|
| 825 | + i, obj->type); |
---|
| 826 | + continue; |
---|
| 827 | + } |
---|
| 828 | + |
---|
| 829 | + cx.type = obj->integer.value; |
---|
| 830 | + /* |
---|
| 831 | + * There are known cases in which the _CST output does not |
---|
| 832 | + * contain C1, so if the type of the first state found is not |
---|
| 833 | + * C1, leave an empty slot for C1 to be filled in later. |
---|
| 834 | + */ |
---|
| 835 | + if (i == 1 && cx.type != ACPI_STATE_C1) |
---|
| 836 | + last_index = 1; |
---|
| 837 | + |
---|
| 838 | + cx.address = reg->address; |
---|
| 839 | + cx.index = last_index + 1; |
---|
| 840 | + |
---|
| 841 | + if (reg->space_id == ACPI_ADR_SPACE_FIXED_HARDWARE) { |
---|
| 842 | + if (!acpi_processor_ffh_cstate_probe(cpu, &cx, reg)) { |
---|
| 843 | + /* |
---|
| 844 | + * In the majority of cases _CST describes C1 as |
---|
| 845 | + * a FIXED_HARDWARE C-state, but if the command |
---|
| 846 | + * line forbids using MWAIT, use CSTATE_HALT for |
---|
| 847 | + * C1 regardless. |
---|
| 848 | + */ |
---|
| 849 | + if (cx.type == ACPI_STATE_C1 && |
---|
| 850 | + boot_option_idle_override == IDLE_NOMWAIT) { |
---|
| 851 | + cx.entry_method = ACPI_CSTATE_HALT; |
---|
| 852 | + snprintf(cx.desc, ACPI_CX_DESC_LEN, "ACPI HLT"); |
---|
| 853 | + } else { |
---|
| 854 | + cx.entry_method = ACPI_CSTATE_FFH; |
---|
| 855 | + } |
---|
| 856 | + } else if (cx.type == ACPI_STATE_C1) { |
---|
| 857 | + /* |
---|
| 858 | + * In the special case of C1, FIXED_HARDWARE can |
---|
| 859 | + * be handled by executing the HLT instruction. |
---|
| 860 | + */ |
---|
| 861 | + cx.entry_method = ACPI_CSTATE_HALT; |
---|
| 862 | + snprintf(cx.desc, ACPI_CX_DESC_LEN, "ACPI HLT"); |
---|
| 863 | + } else { |
---|
| 864 | + acpi_handle_info(handle, "_CST C%d declares FIXED_HARDWARE C-state but not supported in hardware, skip...\n", |
---|
| 865 | + i); |
---|
| 866 | + continue; |
---|
| 867 | + } |
---|
| 868 | + } else if (reg->space_id == ACPI_ADR_SPACE_SYSTEM_IO) { |
---|
| 869 | + cx.entry_method = ACPI_CSTATE_SYSTEMIO; |
---|
| 870 | + snprintf(cx.desc, ACPI_CX_DESC_LEN, "ACPI IOPORT 0x%x", |
---|
| 871 | + cx.address); |
---|
| 872 | + } else { |
---|
| 873 | + acpi_handle_info(handle, "_CST C%d space_id(%x) neither FIXED_HARDWARE nor SYSTEM_IO, skip...\n", |
---|
| 874 | + i, reg->space_id); |
---|
| 875 | + continue; |
---|
| 876 | + } |
---|
| 877 | + |
---|
| 878 | + if (cx.type == ACPI_STATE_C1) |
---|
| 879 | + cx.valid = 1; |
---|
| 880 | + |
---|
| 881 | + obj = &element->package.elements[2]; |
---|
| 882 | + if (obj->type != ACPI_TYPE_INTEGER) { |
---|
| 883 | + acpi_handle_info(handle, "_CST C%d package element[2] type(%x) not integer, skip...\n", |
---|
| 884 | + i, obj->type); |
---|
| 885 | + continue; |
---|
| 886 | + } |
---|
| 887 | + |
---|
| 888 | + cx.latency = obj->integer.value; |
---|
| 889 | + |
---|
| 890 | + obj = &element->package.elements[3]; |
---|
| 891 | + if (obj->type != ACPI_TYPE_INTEGER) { |
---|
| 892 | + acpi_handle_info(handle, "_CST C%d package element[3] type(%x) not integer, skip...\n", |
---|
| 893 | + i, obj->type); |
---|
| 894 | + continue; |
---|
| 895 | + } |
---|
| 896 | + |
---|
| 897 | + memcpy(&info->states[++last_index], &cx, sizeof(cx)); |
---|
| 898 | + } |
---|
| 899 | + |
---|
| 900 | + acpi_handle_info(handle, "Found %d idle states\n", last_index); |
---|
| 901 | + |
---|
| 902 | + info->count = last_index; |
---|
| 903 | + |
---|
| 904 | + end: |
---|
| 905 | + kfree(buffer.pointer); |
---|
| 906 | + |
---|
| 907 | + return ret; |
---|
| 908 | +} |
---|
| 909 | +EXPORT_SYMBOL_GPL(acpi_processor_evaluate_cst); |
---|
| 910 | +#endif /* CONFIG_ACPI_PROCESSOR_CSTATE */ |
---|