aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/cpufreq/cppc_cpufreq.c
diff options
context:
space:
mode:
Diffstat (limited to 'drivers/cpufreq/cppc_cpufreq.c')
-rw-r--r--drivers/cpufreq/cppc_cpufreq.c74
1 files changed, 63 insertions, 11 deletions
diff --git a/drivers/cpufreq/cppc_cpufreq.c b/drivers/cpufreq/cppc_cpufreq.c
index 8882b8e2ecd0..4852d9efe74e 100644
--- a/drivers/cpufreq/cppc_cpufreq.c
+++ b/drivers/cpufreq/cppc_cpufreq.c
@@ -19,10 +19,19 @@
19#include <linux/delay.h> 19#include <linux/delay.h>
20#include <linux/cpu.h> 20#include <linux/cpu.h>
21#include <linux/cpufreq.h> 21#include <linux/cpufreq.h>
22#include <linux/dmi.h>
22#include <linux/vmalloc.h> 23#include <linux/vmalloc.h>
23 24
25#include <asm/unaligned.h>
26
24#include <acpi/cppc_acpi.h> 27#include <acpi/cppc_acpi.h>
25 28
29/* Minimum struct length needed for the DMI processor entry we want */
30#define DMI_ENTRY_PROCESSOR_MIN_LENGTH 48
31
32/* Offest in the DMI processor structure for the max frequency */
33#define DMI_PROCESSOR_MAX_SPEED 0x14
34
26/* 35/*
27 * These structs contain information parsed from per CPU 36 * These structs contain information parsed from per CPU
28 * ACPI _CPC structures. 37 * ACPI _CPC structures.
@@ -30,19 +39,58 @@
30 * performance capabilities, desired performance level 39 * performance capabilities, desired performance level
31 * requested etc. 40 * requested etc.
32 */ 41 */
33static struct cpudata **all_cpu_data; 42static struct cppc_cpudata **all_cpu_data;
43
44/* Capture the max KHz from DMI */
45static u64 cppc_dmi_max_khz;
46
47/* Callback function used to retrieve the max frequency from DMI */
48static void cppc_find_dmi_mhz(const struct dmi_header *dm, void *private)
49{
50 const u8 *dmi_data = (const u8 *)dm;
51 u16 *mhz = (u16 *)private;
52
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;
58 }
59}
60
61/* Look up the max frequency in DMI */
62static u64 cppc_get_dmi_max_khz(void)
63{
64 u16 mhz = 0;
65
66 dmi_walk(cppc_find_dmi_mhz, &mhz);
67
68 /*
69 * Real stupid fallback value, just in case there is no
70 * actual value set.
71 */
72 mhz = mhz ? mhz : 1;
73
74 return (1000 * mhz);
75}
34 76
35static int cppc_cpufreq_set_target(struct cpufreq_policy *policy, 77static int cppc_cpufreq_set_target(struct cpufreq_policy *policy,
36 unsigned int target_freq, 78 unsigned int target_freq,
37 unsigned int relation) 79 unsigned int relation)
38{ 80{
39 struct cpudata *cpu; 81 struct cppc_cpudata *cpu;
40 struct cpufreq_freqs freqs; 82 struct cpufreq_freqs freqs;
83 u32 desired_perf;
41 int ret = 0; 84 int ret = 0;
42 85
43 cpu = all_cpu_data[policy->cpu]; 86 cpu = all_cpu_data[policy->cpu];
44 87
45 cpu->perf_ctrls.desired_perf = target_freq; 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)
91 return ret;
92
93 cpu->perf_ctrls.desired_perf = desired_perf;
46 freqs.old = policy->cur; 94 freqs.old = policy->cur;
47 freqs.new = target_freq; 95 freqs.new = target_freq;
48 96
@@ -66,7 +114,7 @@ static int cppc_verify_policy(struct cpufreq_policy *policy)
66static void cppc_cpufreq_stop_cpu(struct cpufreq_policy *policy) 114static void cppc_cpufreq_stop_cpu(struct cpufreq_policy *policy)
67{ 115{
68 int cpu_num = policy->cpu; 116 int cpu_num = policy->cpu;
69 struct cpudata *cpu = all_cpu_data[cpu_num]; 117 struct cppc_cpudata *cpu = all_cpu_data[cpu_num];
70 int ret; 118 int ret;
71 119
72 cpu->perf_ctrls.desired_perf = cpu->perf_caps.lowest_perf; 120 cpu->perf_ctrls.desired_perf = cpu->perf_caps.lowest_perf;
@@ -79,7 +127,7 @@ static void cppc_cpufreq_stop_cpu(struct cpufreq_policy *policy)
79 127
80static int cppc_cpufreq_cpu_init(struct cpufreq_policy *policy) 128static int cppc_cpufreq_cpu_init(struct cpufreq_policy *policy)
81{ 129{
82 struct cpudata *cpu; 130 struct cppc_cpudata *cpu;
83 unsigned int cpu_num = policy->cpu; 131 unsigned int cpu_num = policy->cpu;
84 int ret = 0; 132 int ret = 0;
85 133
@@ -94,10 +142,13 @@ static int cppc_cpufreq_cpu_init(struct cpufreq_policy *policy)
94 return ret; 142 return ret;
95 } 143 }
96 144
97 policy->min = cpu->perf_caps.lowest_perf; 145 cppc_dmi_max_khz = cppc_get_dmi_max_khz();
98 policy->max = cpu->perf_caps.highest_perf; 146
147 policy->min = cpu->perf_caps.lowest_perf * cppc_dmi_max_khz / cpu->perf_caps.highest_perf;
148 policy->max = cppc_dmi_max_khz;
99 policy->cpuinfo.min_freq = policy->min; 149 policy->cpuinfo.min_freq = policy->min;
100 policy->cpuinfo.max_freq = policy->max; 150 policy->cpuinfo.max_freq = policy->max;
151 policy->cpuinfo.transition_latency = cppc_get_transition_latency(cpu_num);
101 policy->shared_type = cpu->shared_type; 152 policy->shared_type = cpu->shared_type;
102 153
103 if (policy->shared_type == CPUFREQ_SHARED_TYPE_ANY) 154 if (policy->shared_type == CPUFREQ_SHARED_TYPE_ANY)
@@ -112,7 +163,8 @@ static int cppc_cpufreq_cpu_init(struct cpufreq_policy *policy)
112 cpu->cur_policy = policy; 163 cpu->cur_policy = policy;
113 164
114 /* Set policy->cur to max now. The governors will adjust later. */ 165 /* Set policy->cur to max now. The governors will adjust later. */
115 policy->cur = cpu->perf_ctrls.desired_perf = cpu->perf_caps.highest_perf; 166 policy->cur = cppc_dmi_max_khz;
167 cpu->perf_ctrls.desired_perf = cpu->perf_caps.highest_perf;
116 168
117 ret = cppc_set_perf(cpu_num, &cpu->perf_ctrls); 169 ret = cppc_set_perf(cpu_num, &cpu->perf_ctrls);
118 if (ret) 170 if (ret)
@@ -134,7 +186,7 @@ static struct cpufreq_driver cppc_cpufreq_driver = {
134static int __init cppc_cpufreq_init(void) 186static int __init cppc_cpufreq_init(void)
135{ 187{
136 int i, ret = 0; 188 int i, ret = 0;
137 struct cpudata *cpu; 189 struct cppc_cpudata *cpu;
138 190
139 if (acpi_disabled) 191 if (acpi_disabled)
140 return -ENODEV; 192 return -ENODEV;
@@ -144,7 +196,7 @@ static int __init cppc_cpufreq_init(void)
144 return -ENOMEM; 196 return -ENOMEM;
145 197
146 for_each_possible_cpu(i) { 198 for_each_possible_cpu(i) {
147 all_cpu_data[i] = kzalloc(sizeof(struct cpudata), GFP_KERNEL); 199 all_cpu_data[i] = kzalloc(sizeof(struct cppc_cpudata), GFP_KERNEL);
148 if (!all_cpu_data[i]) 200 if (!all_cpu_data[i])
149 goto out; 201 goto out;
150 202
@@ -175,7 +227,7 @@ out:
175 227
176static void __exit cppc_cpufreq_exit(void) 228static void __exit cppc_cpufreq_exit(void)
177{ 229{
178 struct cpudata *cpu; 230 struct cppc_cpudata *cpu;
179 int i; 231 int i;
180 232
181 cpufreq_unregister_driver(&cppc_cpufreq_driver); 233 cpufreq_unregister_driver(&cppc_cpufreq_driver);