aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/acpi/cppc_acpi.c
diff options
context:
space:
mode:
Diffstat (limited to 'drivers/acpi/cppc_acpi.c')
-rw-r--r--drivers/acpi/cppc_acpi.c81
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);
156show_cppc_data(cppc_get_perf_caps, cppc_perf_caps, lowest_perf); 156show_cppc_data(cppc_get_perf_caps, cppc_perf_caps, lowest_perf);
157show_cppc_data(cppc_get_perf_caps, cppc_perf_caps, nominal_perf); 157show_cppc_data(cppc_get_perf_caps, cppc_perf_caps, nominal_perf);
158show_cppc_data(cppc_get_perf_caps, cppc_perf_caps, lowest_nonlinear_perf); 158show_cppc_data(cppc_get_perf_caps, cppc_perf_caps, lowest_nonlinear_perf);
159show_cppc_data(cppc_get_perf_caps, cppc_perf_caps, lowest_freq);
160show_cppc_data(cppc_get_perf_caps, cppc_perf_caps, nominal_freq);
161
159show_cppc_data(cppc_get_perf_ctrs, cppc_perf_fb_ctrs, reference_perf); 162show_cppc_data(cppc_get_perf_ctrs, cppc_perf_fb_ctrs, reference_perf);
160show_cppc_data(cppc_get_perf_ctrs, cppc_perf_fb_ctrs, wraparound_time); 163show_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 */
650static 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
1084out_err: 1133out_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);