Commit 4b31e77455b868b43e665edceb111c9a330c8e0f
Committed by
Len Brown
1 parent
45bea1555f
Exists in
master
and in
7 other branches
[ACPI] Always set P-state on initialization
Otherwise a platform that supports ACPI based cpufreq and boots up at lowest possible speed could stay there forever. This because the governor may request max speed, but the code doesn't update if there is no change in speed, and it assumed the initial state of max speed. http://bugzilla.kernel.org/show_bug.cgi?id=4634 Signed-off-by: Dominik Brodowski <linux@dominikbrodowski.net> Signed-off-by: Venkatesh Pallipadi <venkatesh.pallipadi@intel.com> Signed-off-by: Len Brown <len.brown@intel.com>
Showing 1 changed file with 7 additions and 0 deletions Inline Diff
arch/i386/kernel/cpu/cpufreq/acpi-cpufreq.c
1 | /* | 1 | /* |
2 | * acpi-cpufreq.c - ACPI Processor P-States Driver ($Revision: 1.3 $) | 2 | * acpi-cpufreq.c - ACPI Processor P-States Driver ($Revision: 1.3 $) |
3 | * | 3 | * |
4 | * Copyright (C) 2001, 2002 Andy Grover <andrew.grover@intel.com> | 4 | * Copyright (C) 2001, 2002 Andy Grover <andrew.grover@intel.com> |
5 | * Copyright (C) 2001, 2002 Paul Diefenbaugh <paul.s.diefenbaugh@intel.com> | 5 | * Copyright (C) 2001, 2002 Paul Diefenbaugh <paul.s.diefenbaugh@intel.com> |
6 | * Copyright (C) 2002 - 2004 Dominik Brodowski <linux@brodo.de> | 6 | * Copyright (C) 2002 - 2004 Dominik Brodowski <linux@brodo.de> |
7 | * | 7 | * |
8 | * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ | 8 | * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ |
9 | * | 9 | * |
10 | * This program is free software; you can redistribute it and/or modify | 10 | * This program is free software; you can redistribute it and/or modify |
11 | * it under the terms of the GNU General Public License as published by | 11 | * it under the terms of the GNU General Public License as published by |
12 | * the Free Software Foundation; either version 2 of the License, or (at | 12 | * the Free Software Foundation; either version 2 of the License, or (at |
13 | * your option) any later version. | 13 | * your option) any later version. |
14 | * | 14 | * |
15 | * This program is distributed in the hope that it will be useful, but | 15 | * This program is distributed in the hope that it will be useful, but |
16 | * WITHOUT ANY WARRANTY; without even the implied warranty of | 16 | * WITHOUT ANY WARRANTY; without even the implied warranty of |
17 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU | 17 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU |
18 | * General Public License for more details. | 18 | * General Public License for more details. |
19 | * | 19 | * |
20 | * You should have received a copy of the GNU General Public License along | 20 | * You should have received a copy of the GNU General Public License along |
21 | * with this program; if not, write to the Free Software Foundation, Inc., | 21 | * with this program; if not, write to the Free Software Foundation, Inc., |
22 | * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA. | 22 | * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA. |
23 | * | 23 | * |
24 | * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ | 24 | * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ |
25 | */ | 25 | */ |
26 | 26 | ||
27 | #include <linux/config.h> | 27 | #include <linux/config.h> |
28 | #include <linux/kernel.h> | 28 | #include <linux/kernel.h> |
29 | #include <linux/module.h> | 29 | #include <linux/module.h> |
30 | #include <linux/init.h> | 30 | #include <linux/init.h> |
31 | #include <linux/cpufreq.h> | 31 | #include <linux/cpufreq.h> |
32 | #include <linux/proc_fs.h> | 32 | #include <linux/proc_fs.h> |
33 | #include <linux/seq_file.h> | 33 | #include <linux/seq_file.h> |
34 | #include <asm/io.h> | 34 | #include <asm/io.h> |
35 | #include <asm/delay.h> | 35 | #include <asm/delay.h> |
36 | #include <asm/uaccess.h> | 36 | #include <asm/uaccess.h> |
37 | 37 | ||
38 | #include <linux/acpi.h> | 38 | #include <linux/acpi.h> |
39 | #include <acpi/processor.h> | 39 | #include <acpi/processor.h> |
40 | 40 | ||
41 | #include "speedstep-est-common.h" | 41 | #include "speedstep-est-common.h" |
42 | 42 | ||
43 | #define dprintk(msg...) cpufreq_debug_printk(CPUFREQ_DEBUG_DRIVER, "acpi-cpufreq", msg) | 43 | #define dprintk(msg...) cpufreq_debug_printk(CPUFREQ_DEBUG_DRIVER, "acpi-cpufreq", msg) |
44 | 44 | ||
45 | MODULE_AUTHOR("Paul Diefenbaugh, Dominik Brodowski"); | 45 | MODULE_AUTHOR("Paul Diefenbaugh, Dominik Brodowski"); |
46 | MODULE_DESCRIPTION("ACPI Processor P-States Driver"); | 46 | MODULE_DESCRIPTION("ACPI Processor P-States Driver"); |
47 | MODULE_LICENSE("GPL"); | 47 | MODULE_LICENSE("GPL"); |
48 | 48 | ||
49 | 49 | ||
50 | struct cpufreq_acpi_io { | 50 | struct cpufreq_acpi_io { |
51 | struct acpi_processor_performance acpi_data; | 51 | struct acpi_processor_performance acpi_data; |
52 | struct cpufreq_frequency_table *freq_table; | 52 | struct cpufreq_frequency_table *freq_table; |
53 | unsigned int resume; | 53 | unsigned int resume; |
54 | }; | 54 | }; |
55 | 55 | ||
56 | static struct cpufreq_acpi_io *acpi_io_data[NR_CPUS]; | 56 | static struct cpufreq_acpi_io *acpi_io_data[NR_CPUS]; |
57 | 57 | ||
58 | static struct cpufreq_driver acpi_cpufreq_driver; | 58 | static struct cpufreq_driver acpi_cpufreq_driver; |
59 | 59 | ||
60 | static int | 60 | static int |
61 | acpi_processor_write_port( | 61 | acpi_processor_write_port( |
62 | u16 port, | 62 | u16 port, |
63 | u8 bit_width, | 63 | u8 bit_width, |
64 | u32 value) | 64 | u32 value) |
65 | { | 65 | { |
66 | if (bit_width <= 8) { | 66 | if (bit_width <= 8) { |
67 | outb(value, port); | 67 | outb(value, port); |
68 | } else if (bit_width <= 16) { | 68 | } else if (bit_width <= 16) { |
69 | outw(value, port); | 69 | outw(value, port); |
70 | } else if (bit_width <= 32) { | 70 | } else if (bit_width <= 32) { |
71 | outl(value, port); | 71 | outl(value, port); |
72 | } else { | 72 | } else { |
73 | return -ENODEV; | 73 | return -ENODEV; |
74 | } | 74 | } |
75 | return 0; | 75 | return 0; |
76 | } | 76 | } |
77 | 77 | ||
78 | static int | 78 | static int |
79 | acpi_processor_read_port( | 79 | acpi_processor_read_port( |
80 | u16 port, | 80 | u16 port, |
81 | u8 bit_width, | 81 | u8 bit_width, |
82 | u32 *ret) | 82 | u32 *ret) |
83 | { | 83 | { |
84 | *ret = 0; | 84 | *ret = 0; |
85 | if (bit_width <= 8) { | 85 | if (bit_width <= 8) { |
86 | *ret = inb(port); | 86 | *ret = inb(port); |
87 | } else if (bit_width <= 16) { | 87 | } else if (bit_width <= 16) { |
88 | *ret = inw(port); | 88 | *ret = inw(port); |
89 | } else if (bit_width <= 32) { | 89 | } else if (bit_width <= 32) { |
90 | *ret = inl(port); | 90 | *ret = inl(port); |
91 | } else { | 91 | } else { |
92 | return -ENODEV; | 92 | return -ENODEV; |
93 | } | 93 | } |
94 | return 0; | 94 | return 0; |
95 | } | 95 | } |
96 | 96 | ||
97 | static int | 97 | static int |
98 | acpi_processor_set_performance ( | 98 | acpi_processor_set_performance ( |
99 | struct cpufreq_acpi_io *data, | 99 | struct cpufreq_acpi_io *data, |
100 | unsigned int cpu, | 100 | unsigned int cpu, |
101 | int state) | 101 | int state) |
102 | { | 102 | { |
103 | u16 port = 0; | 103 | u16 port = 0; |
104 | u8 bit_width = 0; | 104 | u8 bit_width = 0; |
105 | int ret = 0; | 105 | int ret = 0; |
106 | u32 value = 0; | 106 | u32 value = 0; |
107 | int i = 0; | 107 | int i = 0; |
108 | struct cpufreq_freqs cpufreq_freqs; | 108 | struct cpufreq_freqs cpufreq_freqs; |
109 | cpumask_t saved_mask; | 109 | cpumask_t saved_mask; |
110 | int retval; | 110 | int retval; |
111 | 111 | ||
112 | dprintk("acpi_processor_set_performance\n"); | 112 | dprintk("acpi_processor_set_performance\n"); |
113 | 113 | ||
114 | /* | 114 | /* |
115 | * TBD: Use something other than set_cpus_allowed. | 115 | * TBD: Use something other than set_cpus_allowed. |
116 | * As set_cpus_allowed is a bit racy, | 116 | * As set_cpus_allowed is a bit racy, |
117 | * with any other set_cpus_allowed for this process. | 117 | * with any other set_cpus_allowed for this process. |
118 | */ | 118 | */ |
119 | saved_mask = current->cpus_allowed; | 119 | saved_mask = current->cpus_allowed; |
120 | set_cpus_allowed(current, cpumask_of_cpu(cpu)); | 120 | set_cpus_allowed(current, cpumask_of_cpu(cpu)); |
121 | if (smp_processor_id() != cpu) { | 121 | if (smp_processor_id() != cpu) { |
122 | return (-EAGAIN); | 122 | return (-EAGAIN); |
123 | } | 123 | } |
124 | 124 | ||
125 | if (state == data->acpi_data.state) { | 125 | if (state == data->acpi_data.state) { |
126 | if (unlikely(data->resume)) { | 126 | if (unlikely(data->resume)) { |
127 | dprintk("Called after resume, resetting to P%d\n", state); | 127 | dprintk("Called after resume, resetting to P%d\n", state); |
128 | data->resume = 0; | 128 | data->resume = 0; |
129 | } else { | 129 | } else { |
130 | dprintk("Already at target state (P%d)\n", state); | 130 | dprintk("Already at target state (P%d)\n", state); |
131 | retval = 0; | 131 | retval = 0; |
132 | goto migrate_end; | 132 | goto migrate_end; |
133 | } | 133 | } |
134 | } | 134 | } |
135 | 135 | ||
136 | dprintk("Transitioning from P%d to P%d\n", | 136 | dprintk("Transitioning from P%d to P%d\n", |
137 | data->acpi_data.state, state); | 137 | data->acpi_data.state, state); |
138 | 138 | ||
139 | /* cpufreq frequency struct */ | 139 | /* cpufreq frequency struct */ |
140 | cpufreq_freqs.cpu = cpu; | 140 | cpufreq_freqs.cpu = cpu; |
141 | cpufreq_freqs.old = data->freq_table[data->acpi_data.state].frequency; | 141 | cpufreq_freqs.old = data->freq_table[data->acpi_data.state].frequency; |
142 | cpufreq_freqs.new = data->freq_table[state].frequency; | 142 | cpufreq_freqs.new = data->freq_table[state].frequency; |
143 | 143 | ||
144 | /* notify cpufreq */ | 144 | /* notify cpufreq */ |
145 | cpufreq_notify_transition(&cpufreq_freqs, CPUFREQ_PRECHANGE); | 145 | cpufreq_notify_transition(&cpufreq_freqs, CPUFREQ_PRECHANGE); |
146 | 146 | ||
147 | /* | 147 | /* |
148 | * First we write the target state's 'control' value to the | 148 | * First we write the target state's 'control' value to the |
149 | * control_register. | 149 | * control_register. |
150 | */ | 150 | */ |
151 | 151 | ||
152 | port = data->acpi_data.control_register.address; | 152 | port = data->acpi_data.control_register.address; |
153 | bit_width = data->acpi_data.control_register.bit_width; | 153 | bit_width = data->acpi_data.control_register.bit_width; |
154 | value = (u32) data->acpi_data.states[state].control; | 154 | value = (u32) data->acpi_data.states[state].control; |
155 | 155 | ||
156 | dprintk("Writing 0x%08x to port 0x%04x\n", value, port); | 156 | dprintk("Writing 0x%08x to port 0x%04x\n", value, port); |
157 | 157 | ||
158 | ret = acpi_processor_write_port(port, bit_width, value); | 158 | ret = acpi_processor_write_port(port, bit_width, value); |
159 | if (ret) { | 159 | if (ret) { |
160 | dprintk("Invalid port width 0x%04x\n", bit_width); | 160 | dprintk("Invalid port width 0x%04x\n", bit_width); |
161 | retval = ret; | 161 | retval = ret; |
162 | goto migrate_end; | 162 | goto migrate_end; |
163 | } | 163 | } |
164 | 164 | ||
165 | /* | 165 | /* |
166 | * Then we read the 'status_register' and compare the value with the | 166 | * Then we read the 'status_register' and compare the value with the |
167 | * target state's 'status' to make sure the transition was successful. | 167 | * target state's 'status' to make sure the transition was successful. |
168 | * Note that we'll poll for up to 1ms (100 cycles of 10us) before | 168 | * Note that we'll poll for up to 1ms (100 cycles of 10us) before |
169 | * giving up. | 169 | * giving up. |
170 | */ | 170 | */ |
171 | 171 | ||
172 | port = data->acpi_data.status_register.address; | 172 | port = data->acpi_data.status_register.address; |
173 | bit_width = data->acpi_data.status_register.bit_width; | 173 | bit_width = data->acpi_data.status_register.bit_width; |
174 | 174 | ||
175 | dprintk("Looking for 0x%08x from port 0x%04x\n", | 175 | dprintk("Looking for 0x%08x from port 0x%04x\n", |
176 | (u32) data->acpi_data.states[state].status, port); | 176 | (u32) data->acpi_data.states[state].status, port); |
177 | 177 | ||
178 | for (i=0; i<100; i++) { | 178 | for (i=0; i<100; i++) { |
179 | ret = acpi_processor_read_port(port, bit_width, &value); | 179 | ret = acpi_processor_read_port(port, bit_width, &value); |
180 | if (ret) { | 180 | if (ret) { |
181 | dprintk("Invalid port width 0x%04x\n", bit_width); | 181 | dprintk("Invalid port width 0x%04x\n", bit_width); |
182 | retval = ret; | 182 | retval = ret; |
183 | goto migrate_end; | 183 | goto migrate_end; |
184 | } | 184 | } |
185 | if (value == (u32) data->acpi_data.states[state].status) | 185 | if (value == (u32) data->acpi_data.states[state].status) |
186 | break; | 186 | break; |
187 | udelay(10); | 187 | udelay(10); |
188 | } | 188 | } |
189 | 189 | ||
190 | /* notify cpufreq */ | 190 | /* notify cpufreq */ |
191 | cpufreq_notify_transition(&cpufreq_freqs, CPUFREQ_POSTCHANGE); | 191 | cpufreq_notify_transition(&cpufreq_freqs, CPUFREQ_POSTCHANGE); |
192 | 192 | ||
193 | if (value != (u32) data->acpi_data.states[state].status) { | 193 | if (value != (u32) data->acpi_data.states[state].status) { |
194 | unsigned int tmp = cpufreq_freqs.new; | 194 | unsigned int tmp = cpufreq_freqs.new; |
195 | cpufreq_freqs.new = cpufreq_freqs.old; | 195 | cpufreq_freqs.new = cpufreq_freqs.old; |
196 | cpufreq_freqs.old = tmp; | 196 | cpufreq_freqs.old = tmp; |
197 | cpufreq_notify_transition(&cpufreq_freqs, CPUFREQ_PRECHANGE); | 197 | cpufreq_notify_transition(&cpufreq_freqs, CPUFREQ_PRECHANGE); |
198 | cpufreq_notify_transition(&cpufreq_freqs, CPUFREQ_POSTCHANGE); | 198 | cpufreq_notify_transition(&cpufreq_freqs, CPUFREQ_POSTCHANGE); |
199 | printk(KERN_WARNING "acpi-cpufreq: Transition failed\n"); | 199 | printk(KERN_WARNING "acpi-cpufreq: Transition failed\n"); |
200 | retval = -ENODEV; | 200 | retval = -ENODEV; |
201 | goto migrate_end; | 201 | goto migrate_end; |
202 | } | 202 | } |
203 | 203 | ||
204 | dprintk("Transition successful after %d microseconds\n", i * 10); | 204 | dprintk("Transition successful after %d microseconds\n", i * 10); |
205 | 205 | ||
206 | data->acpi_data.state = state; | 206 | data->acpi_data.state = state; |
207 | 207 | ||
208 | retval = 0; | 208 | retval = 0; |
209 | migrate_end: | 209 | migrate_end: |
210 | set_cpus_allowed(current, saved_mask); | 210 | set_cpus_allowed(current, saved_mask); |
211 | return (retval); | 211 | return (retval); |
212 | } | 212 | } |
213 | 213 | ||
214 | 214 | ||
215 | static int | 215 | static int |
216 | acpi_cpufreq_target ( | 216 | acpi_cpufreq_target ( |
217 | struct cpufreq_policy *policy, | 217 | struct cpufreq_policy *policy, |
218 | unsigned int target_freq, | 218 | unsigned int target_freq, |
219 | unsigned int relation) | 219 | unsigned int relation) |
220 | { | 220 | { |
221 | struct cpufreq_acpi_io *data = acpi_io_data[policy->cpu]; | 221 | struct cpufreq_acpi_io *data = acpi_io_data[policy->cpu]; |
222 | unsigned int next_state = 0; | 222 | unsigned int next_state = 0; |
223 | unsigned int result = 0; | 223 | unsigned int result = 0; |
224 | 224 | ||
225 | dprintk("acpi_cpufreq_setpolicy\n"); | 225 | dprintk("acpi_cpufreq_setpolicy\n"); |
226 | 226 | ||
227 | result = cpufreq_frequency_table_target(policy, | 227 | result = cpufreq_frequency_table_target(policy, |
228 | data->freq_table, | 228 | data->freq_table, |
229 | target_freq, | 229 | target_freq, |
230 | relation, | 230 | relation, |
231 | &next_state); | 231 | &next_state); |
232 | if (result) | 232 | if (result) |
233 | return (result); | 233 | return (result); |
234 | 234 | ||
235 | result = acpi_processor_set_performance (data, policy->cpu, next_state); | 235 | result = acpi_processor_set_performance (data, policy->cpu, next_state); |
236 | 236 | ||
237 | return (result); | 237 | return (result); |
238 | } | 238 | } |
239 | 239 | ||
240 | 240 | ||
241 | static int | 241 | static int |
242 | acpi_cpufreq_verify ( | 242 | acpi_cpufreq_verify ( |
243 | struct cpufreq_policy *policy) | 243 | struct cpufreq_policy *policy) |
244 | { | 244 | { |
245 | unsigned int result = 0; | 245 | unsigned int result = 0; |
246 | struct cpufreq_acpi_io *data = acpi_io_data[policy->cpu]; | 246 | struct cpufreq_acpi_io *data = acpi_io_data[policy->cpu]; |
247 | 247 | ||
248 | dprintk("acpi_cpufreq_verify\n"); | 248 | dprintk("acpi_cpufreq_verify\n"); |
249 | 249 | ||
250 | result = cpufreq_frequency_table_verify(policy, | 250 | result = cpufreq_frequency_table_verify(policy, |
251 | data->freq_table); | 251 | data->freq_table); |
252 | 252 | ||
253 | return (result); | 253 | return (result); |
254 | } | 254 | } |
255 | 255 | ||
256 | 256 | ||
257 | static unsigned long | 257 | static unsigned long |
258 | acpi_cpufreq_guess_freq ( | 258 | acpi_cpufreq_guess_freq ( |
259 | struct cpufreq_acpi_io *data, | 259 | struct cpufreq_acpi_io *data, |
260 | unsigned int cpu) | 260 | unsigned int cpu) |
261 | { | 261 | { |
262 | if (cpu_khz) { | 262 | if (cpu_khz) { |
263 | /* search the closest match to cpu_khz */ | 263 | /* search the closest match to cpu_khz */ |
264 | unsigned int i; | 264 | unsigned int i; |
265 | unsigned long freq; | 265 | unsigned long freq; |
266 | unsigned long freqn = data->acpi_data.states[0].core_frequency * 1000; | 266 | unsigned long freqn = data->acpi_data.states[0].core_frequency * 1000; |
267 | 267 | ||
268 | for (i=0; i < (data->acpi_data.state_count - 1); i++) { | 268 | for (i=0; i < (data->acpi_data.state_count - 1); i++) { |
269 | freq = freqn; | 269 | freq = freqn; |
270 | freqn = data->acpi_data.states[i+1].core_frequency * 1000; | 270 | freqn = data->acpi_data.states[i+1].core_frequency * 1000; |
271 | if ((2 * cpu_khz) > (freqn + freq)) { | 271 | if ((2 * cpu_khz) > (freqn + freq)) { |
272 | data->acpi_data.state = i; | 272 | data->acpi_data.state = i; |
273 | return (freq); | 273 | return (freq); |
274 | } | 274 | } |
275 | } | 275 | } |
276 | data->acpi_data.state = data->acpi_data.state_count - 1; | 276 | data->acpi_data.state = data->acpi_data.state_count - 1; |
277 | return (freqn); | 277 | return (freqn); |
278 | } else | 278 | } else |
279 | /* assume CPU is at P0... */ | 279 | /* assume CPU is at P0... */ |
280 | data->acpi_data.state = 0; | 280 | data->acpi_data.state = 0; |
281 | return data->acpi_data.states[0].core_frequency * 1000; | 281 | return data->acpi_data.states[0].core_frequency * 1000; |
282 | 282 | ||
283 | } | 283 | } |
284 | 284 | ||
285 | 285 | ||
286 | /* | 286 | /* |
287 | * acpi_processor_cpu_init_pdc_est - let BIOS know about the SMP capabilities | 287 | * acpi_processor_cpu_init_pdc_est - let BIOS know about the SMP capabilities |
288 | * of this driver | 288 | * of this driver |
289 | * @perf: processor-specific acpi_io_data struct | 289 | * @perf: processor-specific acpi_io_data struct |
290 | * @cpu: CPU being initialized | 290 | * @cpu: CPU being initialized |
291 | * | 291 | * |
292 | * To avoid issues with legacy OSes, some BIOSes require to be informed of | 292 | * To avoid issues with legacy OSes, some BIOSes require to be informed of |
293 | * the SMP capabilities of OS P-state driver. Here we set the bits in _PDC | 293 | * the SMP capabilities of OS P-state driver. Here we set the bits in _PDC |
294 | * accordingly, for Enhanced Speedstep. Actual call to _PDC is done in | 294 | * accordingly, for Enhanced Speedstep. Actual call to _PDC is done in |
295 | * driver/acpi/processor.c | 295 | * driver/acpi/processor.c |
296 | */ | 296 | */ |
297 | static void | 297 | static void |
298 | acpi_processor_cpu_init_pdc_est( | 298 | acpi_processor_cpu_init_pdc_est( |
299 | struct acpi_processor_performance *perf, | 299 | struct acpi_processor_performance *perf, |
300 | unsigned int cpu, | 300 | unsigned int cpu, |
301 | struct acpi_object_list *obj_list | 301 | struct acpi_object_list *obj_list |
302 | ) | 302 | ) |
303 | { | 303 | { |
304 | union acpi_object *obj; | 304 | union acpi_object *obj; |
305 | u32 *buf; | 305 | u32 *buf; |
306 | struct cpuinfo_x86 *c = cpu_data + cpu; | 306 | struct cpuinfo_x86 *c = cpu_data + cpu; |
307 | dprintk("acpi_processor_cpu_init_pdc_est\n"); | 307 | dprintk("acpi_processor_cpu_init_pdc_est\n"); |
308 | 308 | ||
309 | if (!cpu_has(c, X86_FEATURE_EST)) | 309 | if (!cpu_has(c, X86_FEATURE_EST)) |
310 | return; | 310 | return; |
311 | 311 | ||
312 | /* Initialize pdc. It will be used later. */ | 312 | /* Initialize pdc. It will be used later. */ |
313 | if (!obj_list) | 313 | if (!obj_list) |
314 | return; | 314 | return; |
315 | 315 | ||
316 | if (!(obj_list->count && obj_list->pointer)) | 316 | if (!(obj_list->count && obj_list->pointer)) |
317 | return; | 317 | return; |
318 | 318 | ||
319 | obj = obj_list->pointer; | 319 | obj = obj_list->pointer; |
320 | if ((obj->buffer.length == 12) && obj->buffer.pointer) { | 320 | if ((obj->buffer.length == 12) && obj->buffer.pointer) { |
321 | buf = (u32 *)obj->buffer.pointer; | 321 | buf = (u32 *)obj->buffer.pointer; |
322 | buf[0] = ACPI_PDC_REVISION_ID; | 322 | buf[0] = ACPI_PDC_REVISION_ID; |
323 | buf[1] = 1; | 323 | buf[1] = 1; |
324 | buf[2] = ACPI_PDC_EST_CAPABILITY_SMP; | 324 | buf[2] = ACPI_PDC_EST_CAPABILITY_SMP; |
325 | perf->pdc = obj_list; | 325 | perf->pdc = obj_list; |
326 | } | 326 | } |
327 | return; | 327 | return; |
328 | } | 328 | } |
329 | 329 | ||
330 | 330 | ||
331 | /* CPU specific PDC initialization */ | 331 | /* CPU specific PDC initialization */ |
332 | static void | 332 | static void |
333 | acpi_processor_cpu_init_pdc( | 333 | acpi_processor_cpu_init_pdc( |
334 | struct acpi_processor_performance *perf, | 334 | struct acpi_processor_performance *perf, |
335 | unsigned int cpu, | 335 | unsigned int cpu, |
336 | struct acpi_object_list *obj_list | 336 | struct acpi_object_list *obj_list |
337 | ) | 337 | ) |
338 | { | 338 | { |
339 | struct cpuinfo_x86 *c = cpu_data + cpu; | 339 | struct cpuinfo_x86 *c = cpu_data + cpu; |
340 | dprintk("acpi_processor_cpu_init_pdc\n"); | 340 | dprintk("acpi_processor_cpu_init_pdc\n"); |
341 | perf->pdc = NULL; | 341 | perf->pdc = NULL; |
342 | if (cpu_has(c, X86_FEATURE_EST)) | 342 | if (cpu_has(c, X86_FEATURE_EST)) |
343 | acpi_processor_cpu_init_pdc_est(perf, cpu, obj_list); | 343 | acpi_processor_cpu_init_pdc_est(perf, cpu, obj_list); |
344 | return; | 344 | return; |
345 | } | 345 | } |
346 | 346 | ||
347 | 347 | ||
348 | static int | 348 | static int |
349 | acpi_cpufreq_cpu_init ( | 349 | acpi_cpufreq_cpu_init ( |
350 | struct cpufreq_policy *policy) | 350 | struct cpufreq_policy *policy) |
351 | { | 351 | { |
352 | unsigned int i; | 352 | unsigned int i; |
353 | unsigned int cpu = policy->cpu; | 353 | unsigned int cpu = policy->cpu; |
354 | struct cpufreq_acpi_io *data; | 354 | struct cpufreq_acpi_io *data; |
355 | unsigned int result = 0; | 355 | unsigned int result = 0; |
356 | 356 | ||
357 | union acpi_object arg0 = {ACPI_TYPE_BUFFER}; | 357 | union acpi_object arg0 = {ACPI_TYPE_BUFFER}; |
358 | u32 arg0_buf[3]; | 358 | u32 arg0_buf[3]; |
359 | struct acpi_object_list arg_list = {1, &arg0}; | 359 | struct acpi_object_list arg_list = {1, &arg0}; |
360 | 360 | ||
361 | dprintk("acpi_cpufreq_cpu_init\n"); | 361 | dprintk("acpi_cpufreq_cpu_init\n"); |
362 | /* setup arg_list for _PDC settings */ | 362 | /* setup arg_list for _PDC settings */ |
363 | arg0.buffer.length = 12; | 363 | arg0.buffer.length = 12; |
364 | arg0.buffer.pointer = (u8 *) arg0_buf; | 364 | arg0.buffer.pointer = (u8 *) arg0_buf; |
365 | 365 | ||
366 | data = kmalloc(sizeof(struct cpufreq_acpi_io), GFP_KERNEL); | 366 | data = kmalloc(sizeof(struct cpufreq_acpi_io), GFP_KERNEL); |
367 | if (!data) | 367 | if (!data) |
368 | return (-ENOMEM); | 368 | return (-ENOMEM); |
369 | memset(data, 0, sizeof(struct cpufreq_acpi_io)); | 369 | memset(data, 0, sizeof(struct cpufreq_acpi_io)); |
370 | 370 | ||
371 | acpi_io_data[cpu] = data; | 371 | acpi_io_data[cpu] = data; |
372 | 372 | ||
373 | acpi_processor_cpu_init_pdc(&data->acpi_data, cpu, &arg_list); | 373 | acpi_processor_cpu_init_pdc(&data->acpi_data, cpu, &arg_list); |
374 | result = acpi_processor_register_performance(&data->acpi_data, cpu); | 374 | result = acpi_processor_register_performance(&data->acpi_data, cpu); |
375 | data->acpi_data.pdc = NULL; | 375 | data->acpi_data.pdc = NULL; |
376 | 376 | ||
377 | if (result) | 377 | if (result) |
378 | goto err_free; | 378 | goto err_free; |
379 | 379 | ||
380 | if (is_const_loops_cpu(cpu)) { | 380 | if (is_const_loops_cpu(cpu)) { |
381 | acpi_cpufreq_driver.flags |= CPUFREQ_CONST_LOOPS; | 381 | acpi_cpufreq_driver.flags |= CPUFREQ_CONST_LOOPS; |
382 | } | 382 | } |
383 | 383 | ||
384 | /* capability check */ | 384 | /* capability check */ |
385 | if (data->acpi_data.state_count <= 1) { | 385 | if (data->acpi_data.state_count <= 1) { |
386 | dprintk("No P-States\n"); | 386 | dprintk("No P-States\n"); |
387 | result = -ENODEV; | 387 | result = -ENODEV; |
388 | goto err_unreg; | 388 | goto err_unreg; |
389 | } | 389 | } |
390 | if ((data->acpi_data.control_register.space_id != ACPI_ADR_SPACE_SYSTEM_IO) || | 390 | if ((data->acpi_data.control_register.space_id != ACPI_ADR_SPACE_SYSTEM_IO) || |
391 | (data->acpi_data.status_register.space_id != ACPI_ADR_SPACE_SYSTEM_IO)) { | 391 | (data->acpi_data.status_register.space_id != ACPI_ADR_SPACE_SYSTEM_IO)) { |
392 | dprintk("Unsupported address space [%d, %d]\n", | 392 | dprintk("Unsupported address space [%d, %d]\n", |
393 | (u32) (data->acpi_data.control_register.space_id), | 393 | (u32) (data->acpi_data.control_register.space_id), |
394 | (u32) (data->acpi_data.status_register.space_id)); | 394 | (u32) (data->acpi_data.status_register.space_id)); |
395 | result = -ENODEV; | 395 | result = -ENODEV; |
396 | goto err_unreg; | 396 | goto err_unreg; |
397 | } | 397 | } |
398 | 398 | ||
399 | /* alloc freq_table */ | 399 | /* alloc freq_table */ |
400 | data->freq_table = kmalloc(sizeof(struct cpufreq_frequency_table) * (data->acpi_data.state_count + 1), GFP_KERNEL); | 400 | data->freq_table = kmalloc(sizeof(struct cpufreq_frequency_table) * (data->acpi_data.state_count + 1), GFP_KERNEL); |
401 | if (!data->freq_table) { | 401 | if (!data->freq_table) { |
402 | result = -ENOMEM; | 402 | result = -ENOMEM; |
403 | goto err_unreg; | 403 | goto err_unreg; |
404 | } | 404 | } |
405 | 405 | ||
406 | /* detect transition latency */ | 406 | /* detect transition latency */ |
407 | policy->cpuinfo.transition_latency = 0; | 407 | policy->cpuinfo.transition_latency = 0; |
408 | for (i=0; i<data->acpi_data.state_count; i++) { | 408 | for (i=0; i<data->acpi_data.state_count; i++) { |
409 | if ((data->acpi_data.states[i].transition_latency * 1000) > policy->cpuinfo.transition_latency) | 409 | if ((data->acpi_data.states[i].transition_latency * 1000) > policy->cpuinfo.transition_latency) |
410 | policy->cpuinfo.transition_latency = data->acpi_data.states[i].transition_latency * 1000; | 410 | policy->cpuinfo.transition_latency = data->acpi_data.states[i].transition_latency * 1000; |
411 | } | 411 | } |
412 | policy->governor = CPUFREQ_DEFAULT_GOVERNOR; | 412 | policy->governor = CPUFREQ_DEFAULT_GOVERNOR; |
413 | 413 | ||
414 | /* The current speed is unknown and not detectable by ACPI... */ | 414 | /* The current speed is unknown and not detectable by ACPI... */ |
415 | policy->cur = acpi_cpufreq_guess_freq(data, policy->cpu); | 415 | policy->cur = acpi_cpufreq_guess_freq(data, policy->cpu); |
416 | 416 | ||
417 | /* table init */ | 417 | /* table init */ |
418 | for (i=0; i<=data->acpi_data.state_count; i++) | 418 | for (i=0; i<=data->acpi_data.state_count; i++) |
419 | { | 419 | { |
420 | data->freq_table[i].index = i; | 420 | data->freq_table[i].index = i; |
421 | if (i<data->acpi_data.state_count) | 421 | if (i<data->acpi_data.state_count) |
422 | data->freq_table[i].frequency = data->acpi_data.states[i].core_frequency * 1000; | 422 | data->freq_table[i].frequency = data->acpi_data.states[i].core_frequency * 1000; |
423 | else | 423 | else |
424 | data->freq_table[i].frequency = CPUFREQ_TABLE_END; | 424 | data->freq_table[i].frequency = CPUFREQ_TABLE_END; |
425 | } | 425 | } |
426 | 426 | ||
427 | result = cpufreq_frequency_table_cpuinfo(policy, data->freq_table); | 427 | result = cpufreq_frequency_table_cpuinfo(policy, data->freq_table); |
428 | if (result) { | 428 | if (result) { |
429 | goto err_freqfree; | 429 | goto err_freqfree; |
430 | } | 430 | } |
431 | 431 | ||
432 | /* notify BIOS that we exist */ | 432 | /* notify BIOS that we exist */ |
433 | acpi_processor_notify_smm(THIS_MODULE); | 433 | acpi_processor_notify_smm(THIS_MODULE); |
434 | 434 | ||
435 | printk(KERN_INFO "acpi-cpufreq: CPU%u - ACPI performance management activated.\n", | 435 | printk(KERN_INFO "acpi-cpufreq: CPU%u - ACPI performance management activated.\n", |
436 | cpu); | 436 | cpu); |
437 | for (i = 0; i < data->acpi_data.state_count; i++) | 437 | for (i = 0; i < data->acpi_data.state_count; i++) |
438 | dprintk(" %cP%d: %d MHz, %d mW, %d uS\n", | 438 | dprintk(" %cP%d: %d MHz, %d mW, %d uS\n", |
439 | (i == data->acpi_data.state?'*':' '), i, | 439 | (i == data->acpi_data.state?'*':' '), i, |
440 | (u32) data->acpi_data.states[i].core_frequency, | 440 | (u32) data->acpi_data.states[i].core_frequency, |
441 | (u32) data->acpi_data.states[i].power, | 441 | (u32) data->acpi_data.states[i].power, |
442 | (u32) data->acpi_data.states[i].transition_latency); | 442 | (u32) data->acpi_data.states[i].transition_latency); |
443 | 443 | ||
444 | cpufreq_frequency_table_get_attr(data->freq_table, policy->cpu); | 444 | cpufreq_frequency_table_get_attr(data->freq_table, policy->cpu); |
445 | |||
446 | /* | ||
447 | * the first call to ->target() should result in us actually | ||
448 | * writing something to the appropriate registers. | ||
449 | */ | ||
450 | data->resume = 1; | ||
451 | |||
445 | return (result); | 452 | return (result); |
446 | 453 | ||
447 | err_freqfree: | 454 | err_freqfree: |
448 | kfree(data->freq_table); | 455 | kfree(data->freq_table); |
449 | err_unreg: | 456 | err_unreg: |
450 | acpi_processor_unregister_performance(&data->acpi_data, cpu); | 457 | acpi_processor_unregister_performance(&data->acpi_data, cpu); |
451 | err_free: | 458 | err_free: |
452 | kfree(data); | 459 | kfree(data); |
453 | acpi_io_data[cpu] = NULL; | 460 | acpi_io_data[cpu] = NULL; |
454 | 461 | ||
455 | return (result); | 462 | return (result); |
456 | } | 463 | } |
457 | 464 | ||
458 | 465 | ||
459 | static int | 466 | static int |
460 | acpi_cpufreq_cpu_exit ( | 467 | acpi_cpufreq_cpu_exit ( |
461 | struct cpufreq_policy *policy) | 468 | struct cpufreq_policy *policy) |
462 | { | 469 | { |
463 | struct cpufreq_acpi_io *data = acpi_io_data[policy->cpu]; | 470 | struct cpufreq_acpi_io *data = acpi_io_data[policy->cpu]; |
464 | 471 | ||
465 | 472 | ||
466 | dprintk("acpi_cpufreq_cpu_exit\n"); | 473 | dprintk("acpi_cpufreq_cpu_exit\n"); |
467 | 474 | ||
468 | if (data) { | 475 | if (data) { |
469 | cpufreq_frequency_table_put_attr(policy->cpu); | 476 | cpufreq_frequency_table_put_attr(policy->cpu); |
470 | acpi_io_data[policy->cpu] = NULL; | 477 | acpi_io_data[policy->cpu] = NULL; |
471 | acpi_processor_unregister_performance(&data->acpi_data, policy->cpu); | 478 | acpi_processor_unregister_performance(&data->acpi_data, policy->cpu); |
472 | kfree(data); | 479 | kfree(data); |
473 | } | 480 | } |
474 | 481 | ||
475 | return (0); | 482 | return (0); |
476 | } | 483 | } |
477 | 484 | ||
478 | static int | 485 | static int |
479 | acpi_cpufreq_resume ( | 486 | acpi_cpufreq_resume ( |
480 | struct cpufreq_policy *policy) | 487 | struct cpufreq_policy *policy) |
481 | { | 488 | { |
482 | struct cpufreq_acpi_io *data = acpi_io_data[policy->cpu]; | 489 | struct cpufreq_acpi_io *data = acpi_io_data[policy->cpu]; |
483 | 490 | ||
484 | 491 | ||
485 | dprintk("acpi_cpufreq_resume\n"); | 492 | dprintk("acpi_cpufreq_resume\n"); |
486 | 493 | ||
487 | data->resume = 1; | 494 | data->resume = 1; |
488 | 495 | ||
489 | return (0); | 496 | return (0); |
490 | } | 497 | } |
491 | 498 | ||
492 | 499 | ||
493 | static struct freq_attr* acpi_cpufreq_attr[] = { | 500 | static struct freq_attr* acpi_cpufreq_attr[] = { |
494 | &cpufreq_freq_attr_scaling_available_freqs, | 501 | &cpufreq_freq_attr_scaling_available_freqs, |
495 | NULL, | 502 | NULL, |
496 | }; | 503 | }; |
497 | 504 | ||
498 | static struct cpufreq_driver acpi_cpufreq_driver = { | 505 | static struct cpufreq_driver acpi_cpufreq_driver = { |
499 | .verify = acpi_cpufreq_verify, | 506 | .verify = acpi_cpufreq_verify, |
500 | .target = acpi_cpufreq_target, | 507 | .target = acpi_cpufreq_target, |
501 | .init = acpi_cpufreq_cpu_init, | 508 | .init = acpi_cpufreq_cpu_init, |
502 | .exit = acpi_cpufreq_cpu_exit, | 509 | .exit = acpi_cpufreq_cpu_exit, |
503 | .resume = acpi_cpufreq_resume, | 510 | .resume = acpi_cpufreq_resume, |
504 | .name = "acpi-cpufreq", | 511 | .name = "acpi-cpufreq", |
505 | .owner = THIS_MODULE, | 512 | .owner = THIS_MODULE, |
506 | .attr = acpi_cpufreq_attr, | 513 | .attr = acpi_cpufreq_attr, |
507 | }; | 514 | }; |
508 | 515 | ||
509 | 516 | ||
510 | static int __init | 517 | static int __init |
511 | acpi_cpufreq_init (void) | 518 | acpi_cpufreq_init (void) |
512 | { | 519 | { |
513 | int result = 0; | 520 | int result = 0; |
514 | 521 | ||
515 | dprintk("acpi_cpufreq_init\n"); | 522 | dprintk("acpi_cpufreq_init\n"); |
516 | 523 | ||
517 | result = cpufreq_register_driver(&acpi_cpufreq_driver); | 524 | result = cpufreq_register_driver(&acpi_cpufreq_driver); |
518 | 525 | ||
519 | return (result); | 526 | return (result); |
520 | } | 527 | } |
521 | 528 | ||
522 | 529 | ||
523 | static void __exit | 530 | static void __exit |
524 | acpi_cpufreq_exit (void) | 531 | acpi_cpufreq_exit (void) |
525 | { | 532 | { |
526 | dprintk("acpi_cpufreq_exit\n"); | 533 | dprintk("acpi_cpufreq_exit\n"); |
527 | 534 | ||
528 | cpufreq_unregister_driver(&acpi_cpufreq_driver); | 535 | cpufreq_unregister_driver(&acpi_cpufreq_driver); |
529 | 536 | ||
530 | return; | 537 | return; |
531 | } | 538 | } |
532 | 539 | ||
533 | 540 | ||
534 | late_initcall(acpi_cpufreq_init); | 541 | late_initcall(acpi_cpufreq_init); |
535 | module_exit(acpi_cpufreq_exit); | 542 | module_exit(acpi_cpufreq_exit); |
536 | 543 | ||
537 | MODULE_ALIAS("acpi"); | 544 | MODULE_ALIAS("acpi"); |
538 | 545 |