aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/cpufreq/cppc_cpufreq.c
diff options
context:
space:
mode:
authorXiongfeng Wang <wangxiongfeng2@huawei.com>2019-02-16 22:54:15 -0500
committerRafael J. Wysocki <rafael.j.wysocki@intel.com>2019-02-18 05:27:42 -0500
commit6c8d750f9784cef32a8cffdad74c8a351b4ca3a6 (patch)
tree06da47433058ef334c86a52421fbb5e076042e71 /drivers/cpufreq/cppc_cpufreq.c
parent1757d05f3112acc5c0cdbcccad3afdee99655bf9 (diff)
cpufreq / cppc: Work around for Hisilicon CPPC cpufreq
Hisilicon chips do not support delivered performance counter register and reference performance counter register. But the platform can calculate the real performance using its own method. We reuse the desired performance register to store the real performance calculated by the platform. After the platform finished the frequency adjust, it gets the real performance and writes it into desired performance register. Os can use it to calculate the real frequency. Signed-off-by: Xiongfeng Wang <wangxiongfeng2@huawei.com> [ rjw: Drop unnecessary braces ] Signed-off-by: Rafael J. Wysocki <rafael.j.wysocki@intel.com>
Diffstat (limited to 'drivers/cpufreq/cppc_cpufreq.c')
-rw-r--r--drivers/cpufreq/cppc_cpufreq.c65
1 files changed, 65 insertions, 0 deletions
diff --git a/drivers/cpufreq/cppc_cpufreq.c b/drivers/cpufreq/cppc_cpufreq.c
index fd25c21cee72..2ae978d27e61 100644
--- a/drivers/cpufreq/cppc_cpufreq.c
+++ b/drivers/cpufreq/cppc_cpufreq.c
@@ -42,6 +42,66 @@
42 */ 42 */
43static struct cppc_cpudata **all_cpu_data; 43static struct cppc_cpudata **all_cpu_data;
44 44
45struct cppc_workaround_oem_info {
46 char oem_id[ACPI_OEM_ID_SIZE +1];
47 char oem_table_id[ACPI_OEM_TABLE_ID_SIZE + 1];
48 u32 oem_revision;
49};
50
51static bool apply_hisi_workaround;
52
53static struct cppc_workaround_oem_info wa_info[] = {
54 {
55 .oem_id = "HISI ",
56 .oem_table_id = "HIP07 ",
57 .oem_revision = 0,
58 }, {
59 .oem_id = "HISI ",
60 .oem_table_id = "HIP08 ",
61 .oem_revision = 0,
62 }
63};
64
65static unsigned int cppc_cpufreq_perf_to_khz(struct cppc_cpudata *cpu,
66 unsigned int perf);
67
68/*
69 * HISI platform does not support delivered performance counter and
70 * reference performance counter. It can calculate the performance using the
71 * platform specific mechanism. We reuse the desired performance register to
72 * store the real performance calculated by the platform.
73 */
74static unsigned int hisi_cppc_cpufreq_get_rate(unsigned int cpunum)
75{
76 struct cppc_cpudata *cpudata = all_cpu_data[cpunum];
77 u64 desired_perf;
78 int ret;
79
80 ret = cppc_get_desired_perf(cpunum, &desired_perf);
81 if (ret < 0)
82 return -EIO;
83
84 return cppc_cpufreq_perf_to_khz(cpudata, desired_perf);
85}
86
87static void cppc_check_hisi_workaround(void)
88{
89 struct acpi_table_header *tbl;
90 acpi_status status = AE_OK;
91 int i;
92
93 status = acpi_get_table(ACPI_SIG_PCCT, 0, &tbl);
94 if (ACPI_FAILURE(status) || !tbl)
95 return;
96
97 for (i = 0; i < ARRAY_SIZE(wa_info); i++) {
98 if (!memcmp(wa_info[i].oem_id, tbl->oem_id, ACPI_OEM_ID_SIZE) &&
99 !memcmp(wa_info[i].oem_table_id, tbl->oem_table_id, ACPI_OEM_TABLE_ID_SIZE) &&
100 wa_info[i].oem_revision == tbl->oem_revision)
101 apply_hisi_workaround = true;
102 }
103}
104
45/* Callback function used to retrieve the max frequency from DMI */ 105/* Callback function used to retrieve the max frequency from DMI */
46static void cppc_find_dmi_mhz(const struct dmi_header *dm, void *private) 106static void cppc_find_dmi_mhz(const struct dmi_header *dm, void *private)
47{ 107{
@@ -334,6 +394,9 @@ static unsigned int cppc_cpufreq_get_rate(unsigned int cpunum)
334 struct cppc_cpudata *cpu = all_cpu_data[cpunum]; 394 struct cppc_cpudata *cpu = all_cpu_data[cpunum];
335 int ret; 395 int ret;
336 396
397 if (apply_hisi_workaround)
398 return hisi_cppc_cpufreq_get_rate(cpunum);
399
337 ret = cppc_get_perf_ctrs(cpunum, &fb_ctrs_t0); 400 ret = cppc_get_perf_ctrs(cpunum, &fb_ctrs_t0);
338 if (ret) 401 if (ret)
339 return ret; 402 return ret;
@@ -386,6 +449,8 @@ static int __init cppc_cpufreq_init(void)
386 goto out; 449 goto out;
387 } 450 }
388 451
452 cppc_check_hisi_workaround();
453
389 ret = cpufreq_register_driver(&cppc_cpufreq_driver); 454 ret = cpufreq_register_driver(&cppc_cpufreq_driver);
390 if (ret) 455 if (ret)
391 goto out; 456 goto out;