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.c68
1 files changed, 57 insertions, 11 deletions
diff --git a/drivers/cpufreq/cppc_cpufreq.c b/drivers/cpufreq/cppc_cpufreq.c
index 8882b8e2ecd0..1b2f28f69a81 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,52 @@
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;
41 int ret = 0; 83 int ret = 0;
42 84
43 cpu = all_cpu_data[policy->cpu]; 85 cpu = all_cpu_data[policy->cpu];
44 86
45 cpu->perf_ctrls.desired_perf = target_freq; 87 cpu->perf_ctrls.desired_perf = (u64)target_freq * policy->max / cppc_dmi_max_khz;
46 freqs.old = policy->cur; 88 freqs.old = policy->cur;
47 freqs.new = target_freq; 89 freqs.new = target_freq;
48 90
@@ -66,7 +108,7 @@ static int cppc_verify_policy(struct cpufreq_policy *policy)
66static void cppc_cpufreq_stop_cpu(struct cpufreq_policy *policy) 108static void cppc_cpufreq_stop_cpu(struct cpufreq_policy *policy)
67{ 109{
68 int cpu_num = policy->cpu; 110 int cpu_num = policy->cpu;
69 struct cpudata *cpu = all_cpu_data[cpu_num]; 111 struct cppc_cpudata *cpu = all_cpu_data[cpu_num];
70 int ret; 112 int ret;
71 113
72 cpu->perf_ctrls.desired_perf = cpu->perf_caps.lowest_perf; 114 cpu->perf_ctrls.desired_perf = cpu->perf_caps.lowest_perf;
@@ -79,7 +121,7 @@ static void cppc_cpufreq_stop_cpu(struct cpufreq_policy *policy)
79 121
80static int cppc_cpufreq_cpu_init(struct cpufreq_policy *policy) 122static int cppc_cpufreq_cpu_init(struct cpufreq_policy *policy)
81{ 123{
82 struct cpudata *cpu; 124 struct cppc_cpudata *cpu;
83 unsigned int cpu_num = policy->cpu; 125 unsigned int cpu_num = policy->cpu;
84 int ret = 0; 126 int ret = 0;
85 127
@@ -94,10 +136,13 @@ static int cppc_cpufreq_cpu_init(struct cpufreq_policy *policy)
94 return ret; 136 return ret;
95 } 137 }
96 138
97 policy->min = cpu->perf_caps.lowest_perf; 139 cppc_dmi_max_khz = cppc_get_dmi_max_khz();
98 policy->max = cpu->perf_caps.highest_perf; 140
141 policy->min = cpu->perf_caps.lowest_perf * cppc_dmi_max_khz / cpu->perf_caps.highest_perf;
142 policy->max = cppc_dmi_max_khz;
99 policy->cpuinfo.min_freq = policy->min; 143 policy->cpuinfo.min_freq = policy->min;
100 policy->cpuinfo.max_freq = policy->max; 144 policy->cpuinfo.max_freq = policy->max;
145 policy->cpuinfo.transition_latency = cppc_get_transition_latency(cpu_num);
101 policy->shared_type = cpu->shared_type; 146 policy->shared_type = cpu->shared_type;
102 147
103 if (policy->shared_type == CPUFREQ_SHARED_TYPE_ANY) 148 if (policy->shared_type == CPUFREQ_SHARED_TYPE_ANY)
@@ -112,7 +157,8 @@ static int cppc_cpufreq_cpu_init(struct cpufreq_policy *policy)
112 cpu->cur_policy = policy; 157 cpu->cur_policy = policy;
113 158
114 /* Set policy->cur to max now. The governors will adjust later. */ 159 /* Set policy->cur to max now. The governors will adjust later. */
115 policy->cur = cpu->perf_ctrls.desired_perf = cpu->perf_caps.highest_perf; 160 policy->cur = cppc_dmi_max_khz;
161 cpu->perf_ctrls.desired_perf = cpu->perf_caps.highest_perf;
116 162
117 ret = cppc_set_perf(cpu_num, &cpu->perf_ctrls); 163 ret = cppc_set_perf(cpu_num, &cpu->perf_ctrls);
118 if (ret) 164 if (ret)
@@ -134,7 +180,7 @@ static struct cpufreq_driver cppc_cpufreq_driver = {
134static int __init cppc_cpufreq_init(void) 180static int __init cppc_cpufreq_init(void)
135{ 181{
136 int i, ret = 0; 182 int i, ret = 0;
137 struct cpudata *cpu; 183 struct cppc_cpudata *cpu;
138 184
139 if (acpi_disabled) 185 if (acpi_disabled)
140 return -ENODEV; 186 return -ENODEV;
@@ -144,7 +190,7 @@ static int __init cppc_cpufreq_init(void)
144 return -ENOMEM; 190 return -ENOMEM;
145 191
146 for_each_possible_cpu(i) { 192 for_each_possible_cpu(i) {
147 all_cpu_data[i] = kzalloc(sizeof(struct cpudata), GFP_KERNEL); 193 all_cpu_data[i] = kzalloc(sizeof(struct cppc_cpudata), GFP_KERNEL);
148 if (!all_cpu_data[i]) 194 if (!all_cpu_data[i])
149 goto out; 195 goto out;
150 196
@@ -175,7 +221,7 @@ out:
175 221
176static void __exit cppc_cpufreq_exit(void) 222static void __exit cppc_cpufreq_exit(void)
177{ 223{
178 struct cpudata *cpu; 224 struct cppc_cpudata *cpu;
179 int i; 225 int i;
180 226
181 cpufreq_unregister_driver(&cppc_cpufreq_driver); 227 cpufreq_unregister_driver(&cppc_cpufreq_driver);