aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/acpi/cppc_acpi.c
diff options
context:
space:
mode:
authorPrashanth Prakash <pprakash@codeaurora.org>2018-04-04 14:14:50 -0400
committerRafael J. Wysocki <rafael.j.wysocki@intel.com>2018-04-24 06:33:28 -0400
commit4773e77cdc9b3af93ee1ae7bcf2acf94fde17166 (patch)
tree14c9cb5e312d110870591131b6f400bc8fecca32 /drivers/acpi/cppc_acpi.c
parent6d08b06e67cd117f6992c46611dfb4ce267cd71e (diff)
ACPI / CPPC: Add support for CPPC v3
CPPC V3 introduces two new entries to make it easier to convert between abstract processor performance and frequency. The two new entries are lowest frequency and nominal frequency. These are the frequencies corresponding to lowest and nominal abstract performance. Add support to read the new entries and populate them as part of the CPPC performance capabilities which can be used by cpufreq drivers Signed-off-by: Prashanth Prakash <pprakash@codeaurora.org> Signed-off-by: Rafael J. Wysocki <rafael.j.wysocki@intel.com>
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);