diff options
Diffstat (limited to 'drivers/acpi/cppc_acpi.c')
-rw-r--r-- | drivers/acpi/cppc_acpi.c | 81 |
1 files changed, 65 insertions, 16 deletions
diff --git a/drivers/acpi/cppc_acpi.c b/drivers/acpi/cppc_acpi.c index 735c74a4cbdb..8fa3d3a6e5b6 100644 --- a/drivers/acpi/cppc_acpi.c +++ b/drivers/acpi/cppc_acpi.c | |||
@@ -156,6 +156,9 @@ show_cppc_data(cppc_get_perf_caps, cppc_perf_caps, highest_perf); | |||
156 | show_cppc_data(cppc_get_perf_caps, cppc_perf_caps, lowest_perf); | 156 | show_cppc_data(cppc_get_perf_caps, cppc_perf_caps, lowest_perf); |
157 | show_cppc_data(cppc_get_perf_caps, cppc_perf_caps, nominal_perf); | 157 | show_cppc_data(cppc_get_perf_caps, cppc_perf_caps, nominal_perf); |
158 | show_cppc_data(cppc_get_perf_caps, cppc_perf_caps, lowest_nonlinear_perf); | 158 | show_cppc_data(cppc_get_perf_caps, cppc_perf_caps, lowest_nonlinear_perf); |
159 | show_cppc_data(cppc_get_perf_caps, cppc_perf_caps, lowest_freq); | ||
160 | show_cppc_data(cppc_get_perf_caps, cppc_perf_caps, nominal_freq); | ||
161 | |||
159 | show_cppc_data(cppc_get_perf_ctrs, cppc_perf_fb_ctrs, reference_perf); | 162 | show_cppc_data(cppc_get_perf_ctrs, cppc_perf_fb_ctrs, reference_perf); |
160 | show_cppc_data(cppc_get_perf_ctrs, cppc_perf_fb_ctrs, wraparound_time); | 163 | show_cppc_data(cppc_get_perf_ctrs, cppc_perf_fb_ctrs, wraparound_time); |
161 | 164 | ||
@@ -183,6 +186,8 @@ static struct attribute *cppc_attrs[] = { | |||
183 | &lowest_perf.attr, | 186 | &lowest_perf.attr, |
184 | &lowest_nonlinear_perf.attr, | 187 | &lowest_nonlinear_perf.attr, |
185 | &nominal_perf.attr, | 188 | &nominal_perf.attr, |
189 | &nominal_freq.attr, | ||
190 | &lowest_freq.attr, | ||
186 | NULL | 191 | NULL |
187 | }; | 192 | }; |
188 | 193 | ||
@@ -613,7 +618,6 @@ bool __weak cpc_ffh_supported(void) | |||
613 | return false; | 618 | return false; |
614 | } | 619 | } |
615 | 620 | ||
616 | |||
617 | /** | 621 | /** |
618 | * pcc_data_alloc() - Allocate the pcc_data memory for pcc subspace | 622 | * pcc_data_alloc() - Allocate the pcc_data memory for pcc subspace |
619 | * | 623 | * |
@@ -641,6 +645,34 @@ int pcc_data_alloc(int pcc_ss_id) | |||
641 | 645 | ||
642 | return 0; | 646 | return 0; |
643 | } | 647 | } |
648 | |||
649 | /* Check if CPPC revision + num_ent combination is supported */ | ||
650 | static bool is_cppc_supported(int revision, int num_ent) | ||
651 | { | ||
652 | int expected_num_ent; | ||
653 | |||
654 | switch (revision) { | ||
655 | case CPPC_V2_REV: | ||
656 | expected_num_ent = CPPC_V2_NUM_ENT; | ||
657 | break; | ||
658 | case CPPC_V3_REV: | ||
659 | expected_num_ent = CPPC_V3_NUM_ENT; | ||
660 | break; | ||
661 | default: | ||
662 | pr_debug("Firmware exports unsupported CPPC revision: %d\n", | ||
663 | revision); | ||
664 | return false; | ||
665 | } | ||
666 | |||
667 | if (expected_num_ent != num_ent) { | ||
668 | pr_debug("Firmware exports %d entries. Expected: %d for CPPC rev:%d\n", | ||
669 | num_ent, expected_num_ent, revision); | ||
670 | return false; | ||
671 | } | ||
672 | |||
673 | return true; | ||
674 | } | ||
675 | |||
644 | /* | 676 | /* |
645 | * An example CPC table looks like the following. | 677 | * An example CPC table looks like the following. |
646 | * | 678 | * |
@@ -731,14 +763,6 @@ int acpi_cppc_processor_probe(struct acpi_processor *pr) | |||
731 | cpc_obj->type); | 763 | cpc_obj->type); |
732 | goto out_free; | 764 | goto out_free; |
733 | } | 765 | } |
734 | |||
735 | /* Only support CPPCv2. Bail otherwise. */ | ||
736 | if (num_ent != CPPC_NUM_ENT) { | ||
737 | pr_debug("Firmware exports %d entries. Expected: %d\n", | ||
738 | num_ent, CPPC_NUM_ENT); | ||
739 | goto out_free; | ||
740 | } | ||
741 | |||
742 | cpc_ptr->num_entries = num_ent; | 766 | cpc_ptr->num_entries = num_ent; |
743 | 767 | ||
744 | /* Second entry should be revision. */ | 768 | /* Second entry should be revision. */ |
@@ -750,12 +774,10 @@ int acpi_cppc_processor_probe(struct acpi_processor *pr) | |||
750 | cpc_obj->type); | 774 | cpc_obj->type); |
751 | goto out_free; | 775 | goto out_free; |
752 | } | 776 | } |
777 | cpc_ptr->version = cpc_rev; | ||
753 | 778 | ||
754 | if (cpc_rev != CPPC_REV) { | 779 | if (!is_cppc_supported(cpc_rev, num_ent)) |
755 | pr_debug("Firmware exports revision:%d. Expected:%d\n", | ||
756 | cpc_rev, CPPC_REV); | ||
757 | goto out_free; | 780 | goto out_free; |
758 | } | ||
759 | 781 | ||
760 | /* Iterate through remaining entries in _CPC */ | 782 | /* Iterate through remaining entries in _CPC */ |
761 | for (i = 2; i < num_ent; i++) { | 783 | for (i = 2; i < num_ent; i++) { |
@@ -808,6 +830,18 @@ int acpi_cppc_processor_probe(struct acpi_processor *pr) | |||
808 | } | 830 | } |
809 | } | 831 | } |
810 | per_cpu(cpu_pcc_subspace_idx, pr->id) = pcc_subspace_id; | 832 | per_cpu(cpu_pcc_subspace_idx, pr->id) = pcc_subspace_id; |
833 | |||
834 | /* | ||
835 | * Initialize the remaining cpc_regs as unsupported. | ||
836 | * Example: In case FW exposes CPPC v2, the below loop will initialize | ||
837 | * LOWEST_FREQ and NOMINAL_FREQ regs as unsupported | ||
838 | */ | ||
839 | for (i = num_ent - 2; i < MAX_CPC_REG_ENT; i++) { | ||
840 | cpc_ptr->cpc_regs[i].type = ACPI_TYPE_INTEGER; | ||
841 | cpc_ptr->cpc_regs[i].cpc_entry.int_value = 0; | ||
842 | } | ||
843 | |||
844 | |||
811 | /* Store CPU Logical ID */ | 845 | /* Store CPU Logical ID */ |
812 | cpc_ptr->cpu_id = pr->id; | 846 | cpc_ptr->cpu_id = pr->id; |
813 | 847 | ||
@@ -1037,8 +1071,9 @@ int cppc_get_perf_caps(int cpunum, struct cppc_perf_caps *perf_caps) | |||
1037 | { | 1071 | { |
1038 | struct cpc_desc *cpc_desc = per_cpu(cpc_desc_ptr, cpunum); | 1072 | struct cpc_desc *cpc_desc = per_cpu(cpc_desc_ptr, cpunum); |
1039 | struct cpc_register_resource *highest_reg, *lowest_reg, | 1073 | struct cpc_register_resource *highest_reg, *lowest_reg, |
1040 | *lowest_non_linear_reg, *nominal_reg; | 1074 | *lowest_non_linear_reg, *nominal_reg, |
1041 | u64 high, low, nom, min_nonlinear; | 1075 | *low_freq_reg = NULL, *nom_freq_reg = NULL; |
1076 | u64 high, low, nom, min_nonlinear, low_f = 0, nom_f = 0; | ||
1042 | int pcc_ss_id = per_cpu(cpu_pcc_subspace_idx, cpunum); | 1077 | int pcc_ss_id = per_cpu(cpu_pcc_subspace_idx, cpunum); |
1043 | struct cppc_pcc_data *pcc_ss_data; | 1078 | struct cppc_pcc_data *pcc_ss_data; |
1044 | int ret = 0, regs_in_pcc = 0; | 1079 | int ret = 0, regs_in_pcc = 0; |
@@ -1053,10 +1088,13 @@ int cppc_get_perf_caps(int cpunum, struct cppc_perf_caps *perf_caps) | |||
1053 | lowest_reg = &cpc_desc->cpc_regs[LOWEST_PERF]; | 1088 | lowest_reg = &cpc_desc->cpc_regs[LOWEST_PERF]; |
1054 | lowest_non_linear_reg = &cpc_desc->cpc_regs[LOW_NON_LINEAR_PERF]; | 1089 | lowest_non_linear_reg = &cpc_desc->cpc_regs[LOW_NON_LINEAR_PERF]; |
1055 | nominal_reg = &cpc_desc->cpc_regs[NOMINAL_PERF]; | 1090 | nominal_reg = &cpc_desc->cpc_regs[NOMINAL_PERF]; |
1091 | low_freq_reg = &cpc_desc->cpc_regs[LOWEST_FREQ]; | ||
1092 | nom_freq_reg = &cpc_desc->cpc_regs[NOMINAL_FREQ]; | ||
1056 | 1093 | ||
1057 | /* Are any of the regs PCC ?*/ | 1094 | /* Are any of the regs PCC ?*/ |
1058 | if (CPC_IN_PCC(highest_reg) || CPC_IN_PCC(lowest_reg) || | 1095 | if (CPC_IN_PCC(highest_reg) || CPC_IN_PCC(lowest_reg) || |
1059 | CPC_IN_PCC(lowest_non_linear_reg) || CPC_IN_PCC(nominal_reg)) { | 1096 | CPC_IN_PCC(lowest_non_linear_reg) || CPC_IN_PCC(nominal_reg) || |
1097 | CPC_IN_PCC(low_freq_reg) || CPC_IN_PCC(nom_freq_reg)) { | ||
1060 | regs_in_pcc = 1; | 1098 | regs_in_pcc = 1; |
1061 | down_write(&pcc_ss_data->pcc_lock); | 1099 | down_write(&pcc_ss_data->pcc_lock); |
1062 | /* Ring doorbell once to update PCC subspace */ | 1100 | /* Ring doorbell once to update PCC subspace */ |
@@ -1081,6 +1119,17 @@ int cppc_get_perf_caps(int cpunum, struct cppc_perf_caps *perf_caps) | |||
1081 | if (!high || !low || !nom || !min_nonlinear) | 1119 | if (!high || !low || !nom || !min_nonlinear) |
1082 | ret = -EFAULT; | 1120 | ret = -EFAULT; |
1083 | 1121 | ||
1122 | /* Read optional lowest and nominal frequencies if present */ | ||
1123 | if (CPC_SUPPORTED(low_freq_reg)) | ||
1124 | cpc_read(cpunum, low_freq_reg, &low_f); | ||
1125 | |||
1126 | if (CPC_SUPPORTED(nom_freq_reg)) | ||
1127 | cpc_read(cpunum, nom_freq_reg, &nom_f); | ||
1128 | |||
1129 | perf_caps->lowest_freq = low_f; | ||
1130 | perf_caps->nominal_freq = nom_f; | ||
1131 | |||
1132 | |||
1084 | out_err: | 1133 | out_err: |
1085 | if (regs_in_pcc) | 1134 | if (regs_in_pcc) |
1086 | up_write(&pcc_ss_data->pcc_lock); | 1135 | up_write(&pcc_ss_data->pcc_lock); |