2 * CPPC (Collaborative Processor Performance Control) driver for
3 * interfacing with the CPUfreq layer and governors. See
4 * cppc_acpi.c for CPPC specific methods.
6 * (C) Copyright 2014, 2015 Linaro Ltd.
7 * Author: Ashwin Chaugule <ashwin.chaugule@linaro.org>
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
15 #define pr_fmt(fmt) "CPPC Cpufreq:" fmt
17 #include <linux/kernel.h>
18 #include <linux/module.h>
19 #include <linux/delay.h>
20 #include <linux/cpu.h>
21 #include <linux/cpufreq.h>
22 #include <linux/dmi.h>
23 #include <linux/vmalloc.h>
25 #include <asm/unaligned.h>
27 #include <acpi/cppc_acpi.h>
29 /* Minimum struct length needed for the DMI processor entry we want */
30 #define DMI_ENTRY_PROCESSOR_MIN_LENGTH 48
32 /* Offest in the DMI processor structure for the max frequency */
33 #define DMI_PROCESSOR_MAX_SPEED 0x14
36 * These structs contain information parsed from per CPU
37 * ACPI _CPC structures.
38 * e.g. For each CPU the highest, lowest supported
39 * performance capabilities, desired performance level
42 static struct cppc_cpudata
**all_cpu_data
;
44 /* Capture the max KHz from DMI */
45 static u64 cppc_dmi_max_khz
;
47 /* Callback function used to retrieve the max frequency from DMI */
48 static void cppc_find_dmi_mhz(const struct dmi_header
*dm
, void *private)
50 const u8
*dmi_data
= (const u8
*)dm
;
51 u16
*mhz
= (u16
*)private;
53 if (dm
->type
== DMI_ENTRY_PROCESSOR
&&
54 dm
->length
>= DMI_ENTRY_PROCESSOR_MIN_LENGTH
) {
55 u16 val
= (u16
)get_unaligned((const u16
*)
56 (dmi_data
+ DMI_PROCESSOR_MAX_SPEED
));
57 *mhz
= val
> *mhz
? val
: *mhz
;
61 /* Look up the max frequency in DMI */
62 static u64
cppc_get_dmi_max_khz(void)
66 dmi_walk(cppc_find_dmi_mhz
, &mhz
);
69 * Real stupid fallback value, just in case there is no
77 static int cppc_cpufreq_set_target(struct cpufreq_policy
*policy
,
78 unsigned int target_freq
,
79 unsigned int relation
)
81 struct cppc_cpudata
*cpu
;
82 struct cpufreq_freqs freqs
;
86 cpu
= all_cpu_data
[policy
->cpu
];
88 desired_perf
= (u64
)target_freq
* cpu
->perf_caps
.highest_perf
/ cppc_dmi_max_khz
;
89 /* Return if it is exactly the same perf */
90 if (desired_perf
== cpu
->perf_ctrls
.desired_perf
)
93 cpu
->perf_ctrls
.desired_perf
= desired_perf
;
94 freqs
.old
= policy
->cur
;
95 freqs
.new = target_freq
;
97 cpufreq_freq_transition_begin(policy
, &freqs
);
98 ret
= cppc_set_perf(cpu
->cpu
, &cpu
->perf_ctrls
);
99 cpufreq_freq_transition_end(policy
, &freqs
, ret
!= 0);
102 pr_debug("Failed to set target on CPU:%d. ret:%d\n",
108 static int cppc_verify_policy(struct cpufreq_policy
*policy
)
110 cpufreq_verify_within_cpu_limits(policy
);
114 static void cppc_cpufreq_stop_cpu(struct cpufreq_policy
*policy
)
116 int cpu_num
= policy
->cpu
;
117 struct cppc_cpudata
*cpu
= all_cpu_data
[cpu_num
];
120 cpu
->perf_ctrls
.desired_perf
= cpu
->perf_caps
.lowest_perf
;
122 ret
= cppc_set_perf(cpu_num
, &cpu
->perf_ctrls
);
124 pr_debug("Err setting perf value:%d on CPU:%d. ret:%d\n",
125 cpu
->perf_caps
.lowest_perf
, cpu_num
, ret
);
128 static int cppc_cpufreq_cpu_init(struct cpufreq_policy
*policy
)
130 struct cppc_cpudata
*cpu
;
131 unsigned int cpu_num
= policy
->cpu
;
134 cpu
= all_cpu_data
[policy
->cpu
];
137 ret
= cppc_get_perf_caps(policy
->cpu
, &cpu
->perf_caps
);
140 pr_debug("Err reading CPU%d perf capabilities. ret:%d\n",
145 cppc_dmi_max_khz
= cppc_get_dmi_max_khz();
148 * Set min to lowest nonlinear perf to avoid any efficiency penalty (see
149 * Section 8.4.7.1.1.5 of ACPI 6.1 spec)
151 policy
->min
= cpu
->perf_caps
.lowest_nonlinear_perf
* cppc_dmi_max_khz
/
152 cpu
->perf_caps
.highest_perf
;
153 policy
->max
= cppc_dmi_max_khz
;
156 * Set cpuinfo.min_freq to Lowest to make the full range of performance
157 * available if userspace wants to use any perf between lowest & lowest
160 policy
->cpuinfo
.min_freq
= cpu
->perf_caps
.lowest_perf
* cppc_dmi_max_khz
/
161 cpu
->perf_caps
.highest_perf
;
162 policy
->cpuinfo
.max_freq
= cppc_dmi_max_khz
;
164 policy
->cpuinfo
.transition_latency
= cppc_get_transition_latency(cpu_num
);
165 policy
->shared_type
= cpu
->shared_type
;
167 if (policy
->shared_type
== CPUFREQ_SHARED_TYPE_ANY
)
168 cpumask_copy(policy
->cpus
, cpu
->shared_cpu_map
);
169 else if (policy
->shared_type
== CPUFREQ_SHARED_TYPE_ALL
) {
170 /* Support only SW_ANY for now. */
171 pr_debug("Unsupported CPU co-ord type\n");
175 cpumask_set_cpu(policy
->cpu
, policy
->cpus
);
176 cpu
->cur_policy
= policy
;
178 /* Set policy->cur to max now. The governors will adjust later. */
179 policy
->cur
= cppc_dmi_max_khz
;
180 cpu
->perf_ctrls
.desired_perf
= cpu
->perf_caps
.highest_perf
;
182 ret
= cppc_set_perf(cpu_num
, &cpu
->perf_ctrls
);
184 pr_debug("Err setting perf value:%d on CPU:%d. ret:%d\n",
185 cpu
->perf_caps
.highest_perf
, cpu_num
, ret
);
190 static struct cpufreq_driver cppc_cpufreq_driver
= {
191 .flags
= CPUFREQ_CONST_LOOPS
,
192 .verify
= cppc_verify_policy
,
193 .target
= cppc_cpufreq_set_target
,
194 .init
= cppc_cpufreq_cpu_init
,
195 .stop_cpu
= cppc_cpufreq_stop_cpu
,
196 .name
= "cppc_cpufreq",
199 static int __init
cppc_cpufreq_init(void)
202 struct cppc_cpudata
*cpu
;
207 all_cpu_data
= kzalloc(sizeof(void *) * num_possible_cpus(), GFP_KERNEL
);
211 for_each_possible_cpu(i
) {
212 all_cpu_data
[i
] = kzalloc(sizeof(struct cppc_cpudata
), GFP_KERNEL
);
213 if (!all_cpu_data
[i
])
216 cpu
= all_cpu_data
[i
];
217 if (!zalloc_cpumask_var(&cpu
->shared_cpu_map
, GFP_KERNEL
))
221 ret
= acpi_get_psd_map(all_cpu_data
);
223 pr_debug("Error parsing PSD data. Aborting cpufreq registration.\n");
227 ret
= cpufreq_register_driver(&cppc_cpufreq_driver
);
234 for_each_possible_cpu(i
)
235 kfree(all_cpu_data
[i
]);
241 static void __exit
cppc_cpufreq_exit(void)
243 struct cppc_cpudata
*cpu
;
246 cpufreq_unregister_driver(&cppc_cpufreq_driver
);
248 for_each_possible_cpu(i
) {
249 cpu
= all_cpu_data
[i
];
250 free_cpumask_var(cpu
->shared_cpu_map
);
257 module_exit(cppc_cpufreq_exit
);
258 MODULE_AUTHOR("Ashwin Chaugule");
259 MODULE_DESCRIPTION("CPUFreq driver based on the ACPI CPPC v5.0+ spec");
260 MODULE_LICENSE("GPL");
262 late_initcall(cppc_cpufreq_init
);
264 static const struct acpi_device_id cppc_acpi_ids
[] = {
265 {ACPI_PROCESSOR_DEVICE_HID
, },
269 MODULE_DEVICE_TABLE(acpi
, cppc_acpi_ids
);