hc
2024-10-22 8ac6c7a54ed1b98d142dce24b11c6de6a1e239a5
kernel/drivers/cpufreq/cppc_cpufreq.c
....@@ -1,3 +1,4 @@
1
+// SPDX-License-Identifier: GPL-2.0-only
12 /*
23 * CPPC (Collaborative Processor Performance Control) driver for
34 * interfacing with the CPUfreq layer and governors. See
....@@ -5,11 +6,6 @@
56 *
67 * (C) Copyright 2014, 2015 Linaro Ltd.
78 * Author: Ashwin Chaugule <ashwin.chaugule@linaro.org>
8
- *
9
- * This program is free software; you can redistribute it and/or
10
- * modify it under the terms of the GNU General Public License
11
- * as published by the Free Software Foundation; version 2
12
- * of the License.
139 */
1410
1511 #define pr_fmt(fmt) "CPPC Cpufreq:" fmt
....@@ -41,6 +37,25 @@
4137 * requested etc.
4238 */
4339 static struct cppc_cpudata **all_cpu_data;
40
+static bool boost_supported;
41
+
42
+struct cppc_workaround_oem_info {
43
+ char oem_id[ACPI_OEM_ID_SIZE + 1];
44
+ char oem_table_id[ACPI_OEM_TABLE_ID_SIZE + 1];
45
+ u32 oem_revision;
46
+};
47
+
48
+static struct cppc_workaround_oem_info wa_info[] = {
49
+ {
50
+ .oem_id = "HISI ",
51
+ .oem_table_id = "HIP07 ",
52
+ .oem_revision = 0,
53
+ }, {
54
+ .oem_id = "HISI ",
55
+ .oem_table_id = "HIP08 ",
56
+ .oem_revision = 0,
57
+ }
58
+};
4459
4560 /* Callback function used to retrieve the max frequency from DMI */
4661 static void cppc_find_dmi_mhz(const struct dmi_header *dm, void *private)
....@@ -100,7 +115,7 @@
100115 if (!max_khz)
101116 max_khz = cppc_get_dmi_max_khz();
102117 mul = max_khz;
103
- div = cpu->perf_caps.highest_perf;
118
+ div = caps->highest_perf;
104119 }
105120 return (u64)perf * mul / div;
106121 }
....@@ -123,7 +138,7 @@
123138 } else {
124139 if (!max_khz)
125140 max_khz = cppc_get_dmi_max_khz();
126
- mul = cpu->perf_caps.highest_perf;
141
+ mul = caps->highest_perf;
127142 div = max_khz;
128143 }
129144
....@@ -161,7 +176,7 @@
161176 return ret;
162177 }
163178
164
-static int cppc_verify_policy(struct cpufreq_policy *policy)
179
+static int cppc_verify_policy(struct cpufreq_policy_data *policy)
165180 {
166181 cpufreq_verify_within_cpu_limits(policy);
167182 return 0;
....@@ -250,7 +265,7 @@
250265 * Section 8.4.7.1.1.5 of ACPI 6.1 spec)
251266 */
252267 policy->min = cppc_cpufreq_perf_to_khz(cpu, cpu->perf_caps.lowest_nonlinear_perf);
253
- policy->max = cppc_cpufreq_perf_to_khz(cpu, cpu->perf_caps.highest_perf);
268
+ policy->max = cppc_cpufreq_perf_to_khz(cpu, cpu->perf_caps.nominal_perf);
254269
255270 /*
256271 * Set cpuinfo.min_freq to Lowest to make the full range of performance
....@@ -258,7 +273,7 @@
258273 * nonlinear perf
259274 */
260275 policy->cpuinfo.min_freq = cppc_cpufreq_perf_to_khz(cpu, cpu->perf_caps.lowest_perf);
261
- policy->cpuinfo.max_freq = cppc_cpufreq_perf_to_khz(cpu, cpu->perf_caps.highest_perf);
276
+ policy->cpuinfo.max_freq = cppc_cpufreq_perf_to_khz(cpu, cpu->perf_caps.nominal_perf);
262277
263278 policy->transition_delay_us = cppc_cpufreq_get_transition_delay_us(cpu_num);
264279 policy->shared_type = cpu->shared_type;
....@@ -282,6 +297,13 @@
282297 }
283298
284299 cpu->cur_policy = policy;
300
+
301
+ /*
302
+ * If 'highest_perf' is greater than 'nominal_perf', we assume CPU Boost
303
+ * is supported.
304
+ */
305
+ if (cpu->perf_caps.highest_perf > cpu->perf_caps.nominal_perf)
306
+ boost_supported = true;
285307
286308 /* Set policy->cur to max now. The governors will adjust later. */
287309 policy->cur = cppc_cpufreq_perf_to_khz(cpu,
....@@ -347,6 +369,32 @@
347369 return cppc_get_rate_from_fbctrs(cpu, fb_ctrs_t0, fb_ctrs_t1);
348370 }
349371
372
+static int cppc_cpufreq_set_boost(struct cpufreq_policy *policy, int state)
373
+{
374
+ struct cppc_cpudata *cpudata;
375
+ int ret;
376
+
377
+ if (!boost_supported) {
378
+ pr_err("BOOST not supported by CPU or firmware\n");
379
+ return -EINVAL;
380
+ }
381
+
382
+ cpudata = all_cpu_data[policy->cpu];
383
+ if (state)
384
+ policy->max = cppc_cpufreq_perf_to_khz(cpudata,
385
+ cpudata->perf_caps.highest_perf);
386
+ else
387
+ policy->max = cppc_cpufreq_perf_to_khz(cpudata,
388
+ cpudata->perf_caps.nominal_perf);
389
+ policy->cpuinfo.max_freq = policy->max;
390
+
391
+ ret = freq_qos_update_request(policy->max_freq_req, policy->max);
392
+ if (ret < 0)
393
+ return ret;
394
+
395
+ return 0;
396
+}
397
+
350398 static struct cpufreq_driver cppc_cpufreq_driver = {
351399 .flags = CPUFREQ_CONST_LOOPS,
352400 .verify = cppc_verify_policy,
....@@ -354,8 +402,51 @@
354402 .get = cppc_cpufreq_get_rate,
355403 .init = cppc_cpufreq_cpu_init,
356404 .stop_cpu = cppc_cpufreq_stop_cpu,
405
+ .set_boost = cppc_cpufreq_set_boost,
357406 .name = "cppc_cpufreq",
358407 };
408
+
409
+/*
410
+ * HISI platform does not support delivered performance counter and
411
+ * reference performance counter. It can calculate the performance using the
412
+ * platform specific mechanism. We reuse the desired performance register to
413
+ * store the real performance calculated by the platform.
414
+ */
415
+static unsigned int hisi_cppc_cpufreq_get_rate(unsigned int cpunum)
416
+{
417
+ struct cppc_cpudata *cpudata = all_cpu_data[cpunum];
418
+ u64 desired_perf;
419
+ int ret;
420
+
421
+ ret = cppc_get_desired_perf(cpunum, &desired_perf);
422
+ if (ret < 0)
423
+ return -EIO;
424
+
425
+ return cppc_cpufreq_perf_to_khz(cpudata, desired_perf);
426
+}
427
+
428
+static void cppc_check_hisi_workaround(void)
429
+{
430
+ struct acpi_table_header *tbl;
431
+ acpi_status status = AE_OK;
432
+ int i;
433
+
434
+ status = acpi_get_table(ACPI_SIG_PCCT, 0, &tbl);
435
+ if (ACPI_FAILURE(status) || !tbl)
436
+ return;
437
+
438
+ for (i = 0; i < ARRAY_SIZE(wa_info); i++) {
439
+ if (!memcmp(wa_info[i].oem_id, tbl->oem_id, ACPI_OEM_ID_SIZE) &&
440
+ !memcmp(wa_info[i].oem_table_id, tbl->oem_table_id, ACPI_OEM_TABLE_ID_SIZE) &&
441
+ wa_info[i].oem_revision == tbl->oem_revision) {
442
+ /* Overwrite the get() callback */
443
+ cppc_cpufreq_driver.get = hisi_cppc_cpufreq_get_rate;
444
+ break;
445
+ }
446
+ }
447
+
448
+ acpi_put_table(tbl);
449
+}
359450
360451 static int __init cppc_cpufreq_init(void)
361452 {
....@@ -385,6 +476,8 @@
385476 pr_debug("Error parsing PSD data. Aborting cpufreq registration.\n");
386477 goto out;
387478 }
479
+
480
+ cppc_check_hisi_workaround();
388481
389482 ret = cpufreq_register_driver(&cppc_cpufreq_driver);
390483 if (ret)
....@@ -428,7 +521,7 @@
428521
429522 late_initcall(cppc_cpufreq_init);
430523
431
-static const struct acpi_device_id cppc_acpi_ids[] = {
524
+static const struct acpi_device_id cppc_acpi_ids[] __used = {
432525 {ACPI_PROCESSOR_DEVICE_HID, },
433526 {}
434527 };