Blame view
drivers/acpi/processor_perflib.c
19.3 KB
1da177e4c Linux-2.6.12-rc2 |
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 |
/* * processor_perflib.c - ACPI Processor P-States Library ($Revision: 71 $) * * Copyright (C) 2001, 2002 Andy Grover <andrew.grover@intel.com> * Copyright (C) 2001, 2002 Paul Diefenbaugh <paul.s.diefenbaugh@intel.com> * Copyright (C) 2004 Dominik Brodowski <linux@brodo.de> * Copyright (C) 2004 Anil S Keshavamurthy <anil.s.keshavamurthy@intel.com> * - Added processor hotplug support * * * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or (at * your option) any later version. * * This program is distributed in the hope that it will be useful, but * WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * General Public License for more details. * * You should have received a copy of the GNU General Public License along * with this program; if not, write to the Free Software Foundation, Inc., * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA. * */ |
1da177e4c Linux-2.6.12-rc2 |
28 29 30 31 |
#include <linux/kernel.h> #include <linux/module.h> #include <linux/init.h> #include <linux/cpufreq.h> |
5a0e3ad6a include cleanup: ... |
32 |
#include <linux/slab.h> |
1da177e4c Linux-2.6.12-rc2 |
33 |
|
16be87ea1 ACPI: cpufreq, pr... |
34 |
#ifdef CONFIG_X86 |
910dfae29 ACPI: cpufreq, pr... |
35 |
#include <asm/cpufeature.h> |
16be87ea1 ACPI: cpufreq, pr... |
36 |
#endif |
1da177e4c Linux-2.6.12-rc2 |
37 38 |
#include <acpi/acpi_bus.h> |
89595b8f2 ACPI: consolidate... |
39 |
#include <acpi/acpi_drivers.h> |
1da177e4c Linux-2.6.12-rc2 |
40 |
#include <acpi/processor.h> |
a192a9580 ACPI: Move defini... |
41 |
#define PREFIX "ACPI: " |
1da177e4c Linux-2.6.12-rc2 |
42 |
#define ACPI_PROCESSOR_CLASS "processor" |
1da177e4c Linux-2.6.12-rc2 |
43 44 |
#define ACPI_PROCESSOR_FILE_PERFORMANCE "performance" #define _COMPONENT ACPI_PROCESSOR_COMPONENT |
f52fd66d2 ACPI: clean up AC... |
45 |
ACPI_MODULE_NAME("processor_perflib"); |
1da177e4c Linux-2.6.12-rc2 |
46 |
|
65c19bbd2 sem2mutex: driver... |
47 |
static DEFINE_MUTEX(performance_mutex); |
1da177e4c Linux-2.6.12-rc2 |
48 49 50 51 52 53 54 55 56 57 |
/* * _PPC support is implemented as a CPUfreq policy notifier: * This means each time a CPUfreq driver registered also with * the ACPI core is asked to change the speed policy, the maximum * value is adjusted so that it is within the platform limit. * * Also, when a new platform limit value is detected, the CPUfreq * policy is adjusted accordingly. */ |
a1531acd4 cpufreq acpi: onl... |
58 59 60 61 62 63 |
/* ignore_ppc: * -1 -> cpufreq low level drivers not initialized -> _PSS, etc. not called yet * ignore _PPC * 0 -> cpufreq low level drivers initialized -> consider _PPC values * 1 -> ignore _PPC totally -> forced by user through boot param */ |
9f497bcc6 ACPI: Fix thermal... |
64 |
static int ignore_ppc = -1; |
613e5f337 ACPI: Fix now sig... |
65 |
module_param(ignore_ppc, int, 0644); |
623b78c39 ACPI: add "proces... |
66 67 |
MODULE_PARM_DESC(ignore_ppc, "If the frequency of your machine gets wrongly" \ "limited by BIOS, this should help"); |
1da177e4c Linux-2.6.12-rc2 |
68 69 |
#define PPC_REGISTERED 1 #define PPC_IN_USE 2 |
a1531acd4 cpufreq acpi: onl... |
70 |
static int acpi_processor_ppc_status; |
1da177e4c Linux-2.6.12-rc2 |
71 72 |
static int acpi_processor_ppc_notifier(struct notifier_block *nb, |
4be44fcd3 [ACPI] Lindent al... |
73 |
unsigned long event, void *data) |
1da177e4c Linux-2.6.12-rc2 |
74 75 76 77 |
{ struct cpufreq_policy *policy = data; struct acpi_processor *pr; unsigned int ppc = 0; |
a1531acd4 cpufreq acpi: onl... |
78 79 80 81 |
if (event == CPUFREQ_START && ignore_ppc <= 0) { ignore_ppc = 0; return 0; } |
623b78c39 ACPI: add "proces... |
82 83 |
if (ignore_ppc) return 0; |
1da177e4c Linux-2.6.12-rc2 |
84 |
if (event != CPUFREQ_INCOMPATIBLE) |
9b67c5d48 acpi cpufreq clea... |
85 86 87 |
return 0; mutex_lock(&performance_mutex); |
1da177e4c Linux-2.6.12-rc2 |
88 |
|
706546d02 ACPI: change proc... |
89 |
pr = per_cpu(processors, policy->cpu); |
1da177e4c Linux-2.6.12-rc2 |
90 91 |
if (!pr || !pr->performance) goto out; |
4be44fcd3 [ACPI] Lindent al... |
92 |
ppc = (unsigned int)pr->performance_platform_limit; |
1da177e4c Linux-2.6.12-rc2 |
93 |
|
0916bd3eb [PATCH] Correct b... |
94 |
if (ppc >= pr->performance->state_count) |
1da177e4c Linux-2.6.12-rc2 |
95 96 97 |
goto out; cpufreq_verify_within_limits(policy, 0, |
4be44fcd3 [ACPI] Lindent al... |
98 99 |
pr->performance->states[ppc]. core_frequency * 1000); |
1da177e4c Linux-2.6.12-rc2 |
100 |
|
4be44fcd3 [ACPI] Lindent al... |
101 |
out: |
65c19bbd2 sem2mutex: driver... |
102 |
mutex_unlock(&performance_mutex); |
1da177e4c Linux-2.6.12-rc2 |
103 104 105 |
return 0; } |
1da177e4c Linux-2.6.12-rc2 |
106 107 108 |
static struct notifier_block acpi_ppc_notifier_block = { .notifier_call = acpi_processor_ppc_notifier, }; |
4be44fcd3 [ACPI] Lindent al... |
109 |
static int acpi_processor_get_platform_limit(struct acpi_processor *pr) |
1da177e4c Linux-2.6.12-rc2 |
110 |
{ |
4be44fcd3 [ACPI] Lindent al... |
111 |
acpi_status status = 0; |
27663c585 ACPI: Change acpi... |
112 |
unsigned long long ppc = 0; |
1da177e4c Linux-2.6.12-rc2 |
113 |
|
1da177e4c Linux-2.6.12-rc2 |
114 115 |
if (!pr) |
d550d98d3 ACPI: delete trac... |
116 |
return -EINVAL; |
1da177e4c Linux-2.6.12-rc2 |
117 118 119 120 121 122 123 124 125 |
/* * _PPC indicates the maximum state currently supported by the platform * (e.g. 0 = states 0..n; 1 = states 1..n; etc. */ status = acpi_evaluate_integer(pr->handle, "_PPC", NULL, &ppc); if (status != AE_NOT_FOUND) acpi_processor_ppc_status |= PPC_IN_USE; |
4be44fcd3 [ACPI] Lindent al... |
126 |
if (ACPI_FAILURE(status) && status != AE_NOT_FOUND) { |
a6fc67202 ACPI: Enable ACPI... |
127 |
ACPI_EXCEPTION((AE_INFO, status, "Evaluating _PPC")); |
d550d98d3 ACPI: delete trac... |
128 |
return -ENODEV; |
1da177e4c Linux-2.6.12-rc2 |
129 |
} |
2d06d8c49 [CPUFREQ] use dyn... |
130 131 |
pr_debug("CPU %d: _PPC is %d - frequency %s limited ", pr->id, |
919158d17 ACPI: cpufreq: Pr... |
132 |
(int)ppc, ppc ? "" : "not"); |
4be44fcd3 [ACPI] Lindent al... |
133 |
pr->performance_platform_limit = (int)ppc; |
1da177e4c Linux-2.6.12-rc2 |
134 |
|
d550d98d3 ACPI: delete trac... |
135 |
return 0; |
1da177e4c Linux-2.6.12-rc2 |
136 |
} |
d81c45e1c ACPI: Notify the ... |
137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 |
#define ACPI_PROCESSOR_NOTIFY_PERFORMANCE 0x80 /* * acpi_processor_ppc_ost: Notify firmware the _PPC evaluation status * @handle: ACPI processor handle * @status: the status code of _PPC evaluation * 0: success. OSPM is now using the performance state specificed. * 1: failure. OSPM has not changed the number of P-states in use */ static void acpi_processor_ppc_ost(acpi_handle handle, int status) { union acpi_object params[2] = { {.type = ACPI_TYPE_INTEGER,}, {.type = ACPI_TYPE_INTEGER,}, }; struct acpi_object_list arg_list = {2, params}; acpi_handle temp; params[0].integer.value = ACPI_PROCESSOR_NOTIFY_PERFORMANCE; params[1].integer.value = status; /* when there is no _OST , skip it */ if (ACPI_FAILURE(acpi_get_handle(handle, "_OST", &temp))) return; acpi_evaluate_object(handle, "_OST", &arg_list, NULL); return; } int acpi_processor_ppc_has_changed(struct acpi_processor *pr, int event_flag) |
1da177e4c Linux-2.6.12-rc2 |
166 |
{ |
623b78c39 ACPI: add "proces... |
167 |
int ret; |
d81c45e1c ACPI: Notify the ... |
168 169 170 171 172 173 174 |
if (ignore_ppc) { /* * Only when it is notification event, the _OST object * will be evaluated. Otherwise it is skipped. */ if (event_flag) acpi_processor_ppc_ost(pr->handle, 1); |
623b78c39 ACPI: add "proces... |
175 |
return 0; |
d81c45e1c ACPI: Notify the ... |
176 |
} |
623b78c39 ACPI: add "proces... |
177 178 |
ret = acpi_processor_get_platform_limit(pr); |
d81c45e1c ACPI: Notify the ... |
179 180 181 182 183 184 185 186 187 188 |
/* * Only when it is notification event, the _OST object * will be evaluated. Otherwise it is skipped. */ if (event_flag) { if (ret < 0) acpi_processor_ppc_ost(pr->handle, 1); else acpi_processor_ppc_ost(pr->handle, 0); } |
1da177e4c Linux-2.6.12-rc2 |
189 190 191 192 193 |
if (ret < 0) return (ret); else return cpufreq_update_policy(pr->id); } |
e2f74f355 [ACPI/CPUFREQ] In... |
194 195 196 197 198 199 200 201 202 203 204 205 |
int acpi_processor_get_bios_limit(int cpu, unsigned int *limit) { struct acpi_processor *pr; pr = per_cpu(processors, cpu); if (!pr || !pr->performance || !pr->performance->state_count) return -ENODEV; *limit = pr->performance->states[pr->performance_platform_limit]. core_frequency * 1000; return 0; } EXPORT_SYMBOL(acpi_processor_get_bios_limit); |
4be44fcd3 [ACPI] Lindent al... |
206 207 208 209 |
void acpi_processor_ppc_init(void) { if (!cpufreq_register_notifier (&acpi_ppc_notifier_block, CPUFREQ_POLICY_NOTIFIER)) |
1da177e4c Linux-2.6.12-rc2 |
210 211 |
acpi_processor_ppc_status |= PPC_REGISTERED; else |
4be44fcd3 [ACPI] Lindent al... |
212 213 214 |
printk(KERN_DEBUG "Warning: Processor Platform Limit not supported. "); |
1da177e4c Linux-2.6.12-rc2 |
215 |
} |
4be44fcd3 [ACPI] Lindent al... |
216 217 |
void acpi_processor_ppc_exit(void) { |
1da177e4c Linux-2.6.12-rc2 |
218 |
if (acpi_processor_ppc_status & PPC_REGISTERED) |
4be44fcd3 [ACPI] Lindent al... |
219 220 |
cpufreq_unregister_notifier(&acpi_ppc_notifier_block, CPUFREQ_POLICY_NOTIFIER); |
1da177e4c Linux-2.6.12-rc2 |
221 222 223 |
acpi_processor_ppc_status &= ~PPC_REGISTERED; } |
4be44fcd3 [ACPI] Lindent al... |
224 |
static int acpi_processor_get_performance_control(struct acpi_processor *pr) |
1da177e4c Linux-2.6.12-rc2 |
225 |
{ |
4be44fcd3 [ACPI] Lindent al... |
226 227 228 229 230 |
int result = 0; acpi_status status = 0; struct acpi_buffer buffer = { ACPI_ALLOCATE_BUFFER, NULL }; union acpi_object *pct = NULL; union acpi_object obj = { 0 }; |
1da177e4c Linux-2.6.12-rc2 |
231 |
|
1da177e4c Linux-2.6.12-rc2 |
232 233 |
status = acpi_evaluate_object(pr->handle, "_PCT", NULL, &buffer); |
4be44fcd3 [ACPI] Lindent al... |
234 |
if (ACPI_FAILURE(status)) { |
a6fc67202 ACPI: Enable ACPI... |
235 |
ACPI_EXCEPTION((AE_INFO, status, "Evaluating _PCT")); |
d550d98d3 ACPI: delete trac... |
236 |
return -ENODEV; |
1da177e4c Linux-2.6.12-rc2 |
237 |
} |
4be44fcd3 [ACPI] Lindent al... |
238 |
pct = (union acpi_object *)buffer.pointer; |
1da177e4c Linux-2.6.12-rc2 |
239 |
if (!pct || (pct->type != ACPI_TYPE_PACKAGE) |
4be44fcd3 [ACPI] Lindent al... |
240 |
|| (pct->package.count != 2)) { |
6468463ab ACPI: un-export A... |
241 242 |
printk(KERN_ERR PREFIX "Invalid _PCT data "); |
1da177e4c Linux-2.6.12-rc2 |
243 244 245 246 247 248 249 250 251 252 253 |
result = -EFAULT; goto end; } /* * control_register */ obj = pct->package.elements[0]; if ((obj.type != ACPI_TYPE_BUFFER) |
4be44fcd3 [ACPI] Lindent al... |
254 255 |
|| (obj.buffer.length < sizeof(struct acpi_pct_register)) || (obj.buffer.pointer == NULL)) { |
6468463ab ACPI: un-export A... |
256 257 |
printk(KERN_ERR PREFIX "Invalid _PCT data (control_register) "); |
1da177e4c Linux-2.6.12-rc2 |
258 259 260 |
result = -EFAULT; goto end; } |
4be44fcd3 [ACPI] Lindent al... |
261 262 |
memcpy(&pr->performance->control_register, obj.buffer.pointer, sizeof(struct acpi_pct_register)); |
1da177e4c Linux-2.6.12-rc2 |
263 264 265 266 267 268 269 270 |
/* * status_register */ obj = pct->package.elements[1]; if ((obj.type != ACPI_TYPE_BUFFER) |
4be44fcd3 [ACPI] Lindent al... |
271 272 |
|| (obj.buffer.length < sizeof(struct acpi_pct_register)) || (obj.buffer.pointer == NULL)) { |
6468463ab ACPI: un-export A... |
273 274 |
printk(KERN_ERR PREFIX "Invalid _PCT data (status_register) "); |
1da177e4c Linux-2.6.12-rc2 |
275 276 277 |
result = -EFAULT; goto end; } |
4be44fcd3 [ACPI] Lindent al... |
278 279 |
memcpy(&pr->performance->status_register, obj.buffer.pointer, sizeof(struct acpi_pct_register)); |
1da177e4c Linux-2.6.12-rc2 |
280 |
|
4be44fcd3 [ACPI] Lindent al... |
281 |
end: |
02438d877 ACPI: delete acpi... |
282 |
kfree(buffer.pointer); |
1da177e4c Linux-2.6.12-rc2 |
283 |
|
d550d98d3 ACPI: delete trac... |
284 |
return result; |
1da177e4c Linux-2.6.12-rc2 |
285 |
} |
4be44fcd3 [ACPI] Lindent al... |
286 |
static int acpi_processor_get_performance_states(struct acpi_processor *pr) |
1da177e4c Linux-2.6.12-rc2 |
287 |
{ |
4be44fcd3 [ACPI] Lindent al... |
288 289 290 291 292 293 294 |
int result = 0; acpi_status status = AE_OK; struct acpi_buffer buffer = { ACPI_ALLOCATE_BUFFER, NULL }; struct acpi_buffer format = { sizeof("NNNNNN"), "NNNNNN" }; struct acpi_buffer state = { 0, NULL }; union acpi_object *pss = NULL; int i; |
1da177e4c Linux-2.6.12-rc2 |
295 |
|
1da177e4c Linux-2.6.12-rc2 |
296 297 |
status = acpi_evaluate_object(pr->handle, "_PSS", NULL, &buffer); |
4be44fcd3 [ACPI] Lindent al... |
298 |
if (ACPI_FAILURE(status)) { |
a6fc67202 ACPI: Enable ACPI... |
299 |
ACPI_EXCEPTION((AE_INFO, status, "Evaluating _PSS")); |
d550d98d3 ACPI: delete trac... |
300 |
return -ENODEV; |
1da177e4c Linux-2.6.12-rc2 |
301 |
} |
50dd09697 ACPI: Remove unne... |
302 |
pss = buffer.pointer; |
1da177e4c Linux-2.6.12-rc2 |
303 |
if (!pss || (pss->type != ACPI_TYPE_PACKAGE)) { |
6468463ab ACPI: un-export A... |
304 305 |
printk(KERN_ERR PREFIX "Invalid _PSS data "); |
1da177e4c Linux-2.6.12-rc2 |
306 307 308 309 310 311 |
result = -EFAULT; goto end; } ACPI_DEBUG_PRINT((ACPI_DB_INFO, "Found %d performance states ", |
4be44fcd3 [ACPI] Lindent al... |
312 |
pss->package.count)); |
1da177e4c Linux-2.6.12-rc2 |
313 314 |
pr->performance->state_count = pss->package.count; |
4be44fcd3 [ACPI] Lindent al... |
315 316 317 |
pr->performance->states = kmalloc(sizeof(struct acpi_processor_px) * pss->package.count, GFP_KERNEL); |
1da177e4c Linux-2.6.12-rc2 |
318 319 320 321 322 323 324 325 326 327 328 329 330 331 332 333 |
if (!pr->performance->states) { result = -ENOMEM; goto end; } for (i = 0; i < pr->performance->state_count; i++) { struct acpi_processor_px *px = &(pr->performance->states[i]); state.length = sizeof(struct acpi_processor_px); state.pointer = px; ACPI_DEBUG_PRINT((ACPI_DB_INFO, "Extracting state %d ", i)); status = acpi_extract_package(&(pss->package.elements[i]), |
4be44fcd3 [ACPI] Lindent al... |
334 |
&format, &state); |
1da177e4c Linux-2.6.12-rc2 |
335 |
if (ACPI_FAILURE(status)) { |
a6fc67202 ACPI: Enable ACPI... |
336 |
ACPI_EXCEPTION((AE_INFO, status, "Invalid _PSS data")); |
1da177e4c Linux-2.6.12-rc2 |
337 338 339 340 341 342 |
result = -EFAULT; kfree(pr->performance->states); goto end; } ACPI_DEBUG_PRINT((ACPI_DB_INFO, |
4be44fcd3 [ACPI] Lindent al... |
343 344 345 346 347 348 349 350 |
"State [%d]: core_frequency[%d] power[%d] transition_latency[%d] bus_master_latency[%d] control[0x%x] status[0x%x] ", i, (u32) px->core_frequency, (u32) px->power, (u32) px->transition_latency, (u32) px->bus_master_latency, (u32) px->control, (u32) px->status)); |
1da177e4c Linux-2.6.12-rc2 |
351 |
|
34d531e64 ACPI: sanity chec... |
352 353 354 355 356 357 358 359 360 361 |
/* * Check that ACPI's u64 MHz will be valid as u32 KHz in cpufreq */ if (!px->core_frequency || ((u32)(px->core_frequency * 1000) != (px->core_frequency * 1000))) { printk(KERN_ERR FW_BUG PREFIX "Invalid BIOS _PSS frequency: 0x%llx MHz ", px->core_frequency); |
1da177e4c Linux-2.6.12-rc2 |
362 363 364 365 366 |
result = -EFAULT; kfree(pr->performance->states); goto end; } } |
4be44fcd3 [ACPI] Lindent al... |
367 |
end: |
02438d877 ACPI: delete acpi... |
368 |
kfree(buffer.pointer); |
1da177e4c Linux-2.6.12-rc2 |
369 |
|
d550d98d3 ACPI: delete trac... |
370 |
return result; |
1da177e4c Linux-2.6.12-rc2 |
371 |
} |
4be44fcd3 [ACPI] Lindent al... |
372 |
static int acpi_processor_get_performance_info(struct acpi_processor *pr) |
1da177e4c Linux-2.6.12-rc2 |
373 |
{ |
4be44fcd3 [ACPI] Lindent al... |
374 375 376 |
int result = 0; acpi_status status = AE_OK; acpi_handle handle = NULL; |
1da177e4c Linux-2.6.12-rc2 |
377 |
|
1da177e4c Linux-2.6.12-rc2 |
378 |
if (!pr || !pr->performance || !pr->handle) |
d550d98d3 ACPI: delete trac... |
379 |
return -EINVAL; |
1da177e4c Linux-2.6.12-rc2 |
380 |
|
1da177e4c Linux-2.6.12-rc2 |
381 382 383 |
status = acpi_get_handle(pr->handle, "_PCT", &handle); if (ACPI_FAILURE(status)) { ACPI_DEBUG_PRINT((ACPI_DB_INFO, |
4be44fcd3 [ACPI] Lindent al... |
384 385 |
"ACPI-based processor performance control unavailable ")); |
d550d98d3 ACPI: delete trac... |
386 |
return -ENODEV; |
1da177e4c Linux-2.6.12-rc2 |
387 388 389 390 |
} result = acpi_processor_get_performance_control(pr); if (result) |
910dfae29 ACPI: cpufreq, pr... |
391 |
goto update_bios; |
1da177e4c Linux-2.6.12-rc2 |
392 393 394 |
result = acpi_processor_get_performance_states(pr); if (result) |
910dfae29 ACPI: cpufreq, pr... |
395 |
goto update_bios; |
1da177e4c Linux-2.6.12-rc2 |
396 |
|
455c0d71d ACPI: Fix regress... |
397 398 399 400 401 |
/* We need to call _PPC once when cpufreq starts */ if (ignore_ppc != 1) result = acpi_processor_get_platform_limit(pr); return result; |
910dfae29 ACPI: cpufreq, pr... |
402 403 404 405 406 407 |
/* * Having _PPC but missing frequencies (_PSS, _PCT) is a very good hint that * the BIOS is older than the CPU and does not know its frequencies */ update_bios: |
16be87ea1 ACPI: cpufreq, pr... |
408 |
#ifdef CONFIG_X86 |
910dfae29 ACPI: cpufreq, pr... |
409 410 411 412 413 414 |
if (ACPI_SUCCESS(acpi_get_handle(pr->handle, "_PPC", &handle))){ if(boot_cpu_has(X86_FEATURE_EST)) printk(KERN_WARNING FW_BUG "BIOS needs update for CPU " "frequency support "); } |
16be87ea1 ACPI: cpufreq, pr... |
415 |
#endif |
910dfae29 ACPI: cpufreq, pr... |
416 |
return result; |
1da177e4c Linux-2.6.12-rc2 |
417 |
} |
4be44fcd3 [ACPI] Lindent al... |
418 419 420 421 |
int acpi_processor_notify_smm(struct module *calling_module) { acpi_status status; static int is_done = 0; |
1da177e4c Linux-2.6.12-rc2 |
422 |
|
1da177e4c Linux-2.6.12-rc2 |
423 424 |
if (!(acpi_processor_ppc_status & PPC_REGISTERED)) |
d550d98d3 ACPI: delete trac... |
425 |
return -EBUSY; |
1da177e4c Linux-2.6.12-rc2 |
426 427 |
if (!try_module_get(calling_module)) |
d550d98d3 ACPI: delete trac... |
428 |
return -EINVAL; |
1da177e4c Linux-2.6.12-rc2 |
429 |
|
58f87ed0d ACPI: Fix typos |
430 431 |
/* is_done is set to negative if an error occurred, * and to postitive if _no_ error occurred, but SMM |
1da177e4c Linux-2.6.12-rc2 |
432 433 434 435 436 |
* was already notified. This avoids double notification * which might lead to unexpected results... */ if (is_done > 0) { module_put(calling_module); |
d550d98d3 ACPI: delete trac... |
437 |
return 0; |
4be44fcd3 [ACPI] Lindent al... |
438 |
} else if (is_done < 0) { |
1da177e4c Linux-2.6.12-rc2 |
439 |
module_put(calling_module); |
d550d98d3 ACPI: delete trac... |
440 |
return is_done; |
1da177e4c Linux-2.6.12-rc2 |
441 442 443 |
} is_done = -EIO; |
ad71860a1 ACPICA: minimal p... |
444 |
/* Can't write pstate_control to smi_command if either value is zero */ |
cee324b14 ACPICA: use new A... |
445 |
if ((!acpi_gbl_FADT.smi_command) || (!acpi_gbl_FADT.pstate_control)) { |
ad71860a1 ACPICA: minimal p... |
446 447 |
ACPI_DEBUG_PRINT((ACPI_DB_INFO, "No SMI port or pstate_control ")); |
1da177e4c Linux-2.6.12-rc2 |
448 |
module_put(calling_module); |
d550d98d3 ACPI: delete trac... |
449 |
return 0; |
1da177e4c Linux-2.6.12-rc2 |
450 |
} |
4be44fcd3 [ACPI] Lindent al... |
451 |
ACPI_DEBUG_PRINT((ACPI_DB_INFO, |
ad71860a1 ACPICA: minimal p... |
452 453 |
"Writing pstate_control [0x%x] to smi_command [0x%x] ", |
cee324b14 ACPICA: use new A... |
454 |
acpi_gbl_FADT.pstate_control, acpi_gbl_FADT.smi_command)); |
1da177e4c Linux-2.6.12-rc2 |
455 |
|
cee324b14 ACPICA: use new A... |
456 457 |
status = acpi_os_write_port(acpi_gbl_FADT.smi_command, (u32) acpi_gbl_FADT.pstate_control, 8); |
4be44fcd3 [ACPI] Lindent al... |
458 |
if (ACPI_FAILURE(status)) { |
a6fc67202 ACPI: Enable ACPI... |
459 |
ACPI_EXCEPTION((AE_INFO, status, |
ad71860a1 ACPICA: minimal p... |
460 |
"Failed to write pstate_control [0x%x] to " |
cee324b14 ACPICA: use new A... |
461 462 |
"smi_command [0x%x]", acpi_gbl_FADT.pstate_control, acpi_gbl_FADT.smi_command)); |
1da177e4c Linux-2.6.12-rc2 |
463 |
module_put(calling_module); |
d550d98d3 ACPI: delete trac... |
464 |
return status; |
1da177e4c Linux-2.6.12-rc2 |
465 466 467 468 469 470 471 472 |
} /* Success. If there's no _PPC, we need to fear nothing, so * we can allow the cpufreq driver to be rmmod'ed. */ is_done = 1; if (!(acpi_processor_ppc_status & PPC_IN_USE)) module_put(calling_module); |
d550d98d3 ACPI: delete trac... |
473 |
return 0; |
1da177e4c Linux-2.6.12-rc2 |
474 |
} |
1da177e4c Linux-2.6.12-rc2 |
475 |
|
4be44fcd3 [ACPI] Lindent al... |
476 |
EXPORT_SYMBOL(acpi_processor_notify_smm); |
1da177e4c Linux-2.6.12-rc2 |
477 |
|
3b2d99429 P-state software ... |
478 479 480 481 482 483 484 485 486 |
static int acpi_processor_get_psd(struct acpi_processor *pr) { int result = 0; acpi_status status = AE_OK; struct acpi_buffer buffer = {ACPI_ALLOCATE_BUFFER, NULL}; struct acpi_buffer format = {sizeof("NNNNN"), "NNNNN"}; struct acpi_buffer state = {0, NULL}; union acpi_object *psd = NULL; struct acpi_psd_package *pdomain; |
3b2d99429 P-state software ... |
487 488 |
status = acpi_evaluate_object(pr->handle, "_PSD", NULL, &buffer); if (ACPI_FAILURE(status)) { |
9011bff4b ACPI: delete newl... |
489 |
return -ENODEV; |
3b2d99429 P-state software ... |
490 |
} |
50dd09697 ACPI: Remove unne... |
491 |
psd = buffer.pointer; |
3b2d99429 P-state software ... |
492 |
if (!psd || (psd->type != ACPI_TYPE_PACKAGE)) { |
55ac9a018 ACPI: replace ACP... |
493 494 |
printk(KERN_ERR PREFIX "Invalid _PSD data "); |
3b2d99429 P-state software ... |
495 496 497 498 499 |
result = -EFAULT; goto end; } if (psd->package.count != 1) { |
55ac9a018 ACPI: replace ACP... |
500 501 |
printk(KERN_ERR PREFIX "Invalid _PSD data "); |
3b2d99429 P-state software ... |
502 503 504 505 506 507 508 509 510 511 512 513 |
result = -EFAULT; goto end; } pdomain = &(pr->performance->domain_info); state.length = sizeof(struct acpi_psd_package); state.pointer = pdomain; status = acpi_extract_package(&(psd->package.elements[0]), &format, &state); if (ACPI_FAILURE(status)) { |
55ac9a018 ACPI: replace ACP... |
514 515 |
printk(KERN_ERR PREFIX "Invalid _PSD data "); |
3b2d99429 P-state software ... |
516 517 518 519 520 |
result = -EFAULT; goto end; } if (pdomain->num_entries != ACPI_PSD_REV0_ENTRIES) { |
55ac9a018 ACPI: replace ACP... |
521 522 |
printk(KERN_ERR PREFIX "Unknown _PSD:num_entries "); |
3b2d99429 P-state software ... |
523 524 525 526 527 |
result = -EFAULT; goto end; } if (pdomain->revision != ACPI_PSD_REV0_REVISION) { |
55ac9a018 ACPI: replace ACP... |
528 529 |
printk(KERN_ERR PREFIX "Unknown _PSD:revision "); |
3b2d99429 P-state software ... |
530 531 532 |
result = -EFAULT; goto end; } |
e1eb47797 ACPI: Avoid wipin... |
533 534 535 536 537 538 539 540 |
if (pdomain->coord_type != DOMAIN_COORD_TYPE_SW_ALL && pdomain->coord_type != DOMAIN_COORD_TYPE_SW_ANY && pdomain->coord_type != DOMAIN_COORD_TYPE_HW_ALL) { printk(KERN_ERR PREFIX "Invalid _PSD:coord_type "); result = -EFAULT; goto end; } |
3b2d99429 P-state software ... |
541 |
end: |
02438d877 ACPI: delete acpi... |
542 |
kfree(buffer.pointer); |
9011bff4b ACPI: delete newl... |
543 |
return result; |
3b2d99429 P-state software ... |
544 545 546 |
} int acpi_processor_preregister_performance( |
a29d8b8e2 percpu: add __per... |
547 |
struct acpi_processor_performance __percpu *performance) |
3b2d99429 P-state software ... |
548 549 550 551 |
{ int count, count_target; int retval = 0; unsigned int i, j; |
2fdf66b49 cpumask: convert ... |
552 |
cpumask_var_t covered_cpus; |
3b2d99429 P-state software ... |
553 554 555 556 |
struct acpi_processor *pr; struct acpi_psd_package *pdomain; struct acpi_processor *match_pr; struct acpi_psd_package *match_pdomain; |
79f559977 cpumask: use zall... |
557 |
if (!zalloc_cpumask_var(&covered_cpus, GFP_KERNEL)) |
2fdf66b49 cpumask: convert ... |
558 |
return -ENOMEM; |
785fcccd6 ACPI: resolve mer... |
559 |
mutex_lock(&performance_mutex); |
3b2d99429 P-state software ... |
560 |
|
e1eb47797 ACPI: Avoid wipin... |
561 562 563 564 |
/* * Check if another driver has already registered, and abort before * changing pr->performance if it has. Check input data as well. */ |
193de0c79 ACPI: use for_eac... |
565 |
for_each_possible_cpu(i) { |
706546d02 ACPI: change proc... |
566 |
pr = per_cpu(processors, i); |
3b2d99429 P-state software ... |
567 568 569 570 571 572 573 |
if (!pr) { /* Look only at processors in ACPI namespace */ continue; } if (pr->performance) { retval = -EBUSY; |
e1eb47797 ACPI: Avoid wipin... |
574 |
goto err_out; |
3b2d99429 P-state software ... |
575 |
} |
b36128c83 alloc_percpu: cha... |
576 |
if (!performance || !per_cpu_ptr(performance, i)) { |
3b2d99429 P-state software ... |
577 |
retval = -EINVAL; |
e1eb47797 ACPI: Avoid wipin... |
578 |
goto err_out; |
3b2d99429 P-state software ... |
579 |
} |
e1eb47797 ACPI: Avoid wipin... |
580 581 582 583 584 585 586 |
} /* Call _PSD for all CPUs */ for_each_possible_cpu(i) { pr = per_cpu(processors, i); if (!pr) continue; |
3b2d99429 P-state software ... |
587 |
|
b36128c83 alloc_percpu: cha... |
588 |
pr->performance = per_cpu_ptr(performance, i); |
2fdf66b49 cpumask: convert ... |
589 |
cpumask_set_cpu(i, pr->performance->shared_cpu_map); |
3b2d99429 P-state software ... |
590 591 592 593 594 595 596 597 598 599 600 601 |
if (acpi_processor_get_psd(pr)) { retval = -EINVAL; continue; } } if (retval) goto err_ret; /* * Now that we have _PSD data from all CPUs, lets setup P-state * domain info. */ |
193de0c79 ACPI: use for_eac... |
602 |
for_each_possible_cpu(i) { |
706546d02 ACPI: change proc... |
603 |
pr = per_cpu(processors, i); |
3b2d99429 P-state software ... |
604 605 |
if (!pr) continue; |
2fdf66b49 cpumask: convert ... |
606 |
if (cpumask_test_cpu(i, covered_cpus)) |
3b2d99429 P-state software ... |
607 608 609 |
continue; pdomain = &(pr->performance->domain_info); |
2fdf66b49 cpumask: convert ... |
610 611 |
cpumask_set_cpu(i, pr->performance->shared_cpu_map); cpumask_set_cpu(i, covered_cpus); |
3b2d99429 P-state software ... |
612 613 614 615 616 617 |
if (pdomain->num_processors <= 1) continue; /* Validate the Domain info */ count_target = pdomain->num_processors; count = 1; |
46f18e3a2 ACPI: HW P-state ... |
618 |
if (pdomain->coord_type == DOMAIN_COORD_TYPE_SW_ALL) |
3b2d99429 P-state software ... |
619 |
pr->performance->shared_type = CPUFREQ_SHARED_TYPE_ALL; |
46f18e3a2 ACPI: HW P-state ... |
620 621 622 |
else if (pdomain->coord_type == DOMAIN_COORD_TYPE_HW_ALL) pr->performance->shared_type = CPUFREQ_SHARED_TYPE_HW; else if (pdomain->coord_type == DOMAIN_COORD_TYPE_SW_ANY) |
3b2d99429 P-state software ... |
623 |
pr->performance->shared_type = CPUFREQ_SHARED_TYPE_ANY; |
3b2d99429 P-state software ... |
624 |
|
193de0c79 ACPI: use for_eac... |
625 |
for_each_possible_cpu(j) { |
3b2d99429 P-state software ... |
626 627 |
if (i == j) continue; |
706546d02 ACPI: change proc... |
628 |
match_pr = per_cpu(processors, j); |
3b2d99429 P-state software ... |
629 630 631 632 633 634 635 636 637 638 639 640 641 642 643 644 645 646 |
if (!match_pr) continue; match_pdomain = &(match_pr->performance->domain_info); if (match_pdomain->domain != pdomain->domain) continue; /* Here i and j are in the same domain */ if (match_pdomain->num_processors != count_target) { retval = -EINVAL; goto err_ret; } if (pdomain->coord_type != match_pdomain->coord_type) { retval = -EINVAL; goto err_ret; } |
2fdf66b49 cpumask: convert ... |
647 648 |
cpumask_set_cpu(j, covered_cpus); cpumask_set_cpu(j, pr->performance->shared_cpu_map); |
3b2d99429 P-state software ... |
649 650 |
count++; } |
193de0c79 ACPI: use for_eac... |
651 |
for_each_possible_cpu(j) { |
3b2d99429 P-state software ... |
652 653 |
if (i == j) continue; |
706546d02 ACPI: change proc... |
654 |
match_pr = per_cpu(processors, j); |
3b2d99429 P-state software ... |
655 656 657 658 659 660 661 662 663 |
if (!match_pr) continue; match_pdomain = &(match_pr->performance->domain_info); if (match_pdomain->domain != pdomain->domain) continue; match_pr->performance->shared_type = pr->performance->shared_type; |
2fdf66b49 cpumask: convert ... |
664 665 |
cpumask_copy(match_pr->performance->shared_cpu_map, pr->performance->shared_cpu_map); |
3b2d99429 P-state software ... |
666 667 668 669 |
} } err_ret: |
193de0c79 ACPI: use for_eac... |
670 |
for_each_possible_cpu(i) { |
706546d02 ACPI: change proc... |
671 |
pr = per_cpu(processors, i); |
3b2d99429 P-state software ... |
672 673 674 675 676 |
if (!pr || !pr->performance) continue; /* Assume no coordination on any error parsing domain info */ if (retval) { |
2fdf66b49 cpumask: convert ... |
677 678 |
cpumask_clear(pr->performance->shared_cpu_map); cpumask_set_cpu(i, pr->performance->shared_cpu_map); |
3b2d99429 P-state software ... |
679 680 681 682 |
pr->performance->shared_type = CPUFREQ_SHARED_TYPE_ALL; } pr->performance = NULL; /* Will be set for real in register */ } |
e1eb47797 ACPI: Avoid wipin... |
683 |
err_out: |
785fcccd6 ACPI: resolve mer... |
684 |
mutex_unlock(&performance_mutex); |
2fdf66b49 cpumask: convert ... |
685 |
free_cpumask_var(covered_cpus); |
9011bff4b ACPI: delete newl... |
686 |
return retval; |
3b2d99429 P-state software ... |
687 688 |
} EXPORT_SYMBOL(acpi_processor_preregister_performance); |
1da177e4c Linux-2.6.12-rc2 |
689 |
int |
4be44fcd3 [ACPI] Lindent al... |
690 691 |
acpi_processor_register_performance(struct acpi_processor_performance *performance, unsigned int cpu) |
1da177e4c Linux-2.6.12-rc2 |
692 693 |
{ struct acpi_processor *pr; |
1da177e4c Linux-2.6.12-rc2 |
694 |
if (!(acpi_processor_ppc_status & PPC_REGISTERED)) |
d550d98d3 ACPI: delete trac... |
695 |
return -EINVAL; |
1da177e4c Linux-2.6.12-rc2 |
696 |
|
65c19bbd2 sem2mutex: driver... |
697 |
mutex_lock(&performance_mutex); |
1da177e4c Linux-2.6.12-rc2 |
698 |
|
706546d02 ACPI: change proc... |
699 |
pr = per_cpu(processors, cpu); |
1da177e4c Linux-2.6.12-rc2 |
700 |
if (!pr) { |
65c19bbd2 sem2mutex: driver... |
701 |
mutex_unlock(&performance_mutex); |
d550d98d3 ACPI: delete trac... |
702 |
return -ENODEV; |
1da177e4c Linux-2.6.12-rc2 |
703 704 705 |
} if (pr->performance) { |
65c19bbd2 sem2mutex: driver... |
706 |
mutex_unlock(&performance_mutex); |
d550d98d3 ACPI: delete trac... |
707 |
return -EBUSY; |
1da177e4c Linux-2.6.12-rc2 |
708 |
} |
a913f5070 [PATCH] powernow-... |
709 |
WARN_ON(!performance); |
1da177e4c Linux-2.6.12-rc2 |
710 711 712 713 |
pr->performance = performance; if (acpi_processor_get_performance_info(pr)) { pr->performance = NULL; |
65c19bbd2 sem2mutex: driver... |
714 |
mutex_unlock(&performance_mutex); |
d550d98d3 ACPI: delete trac... |
715 |
return -EIO; |
1da177e4c Linux-2.6.12-rc2 |
716 |
} |
65c19bbd2 sem2mutex: driver... |
717 |
mutex_unlock(&performance_mutex); |
d550d98d3 ACPI: delete trac... |
718 |
return 0; |
1da177e4c Linux-2.6.12-rc2 |
719 |
} |
1da177e4c Linux-2.6.12-rc2 |
720 |
|
4be44fcd3 [ACPI] Lindent al... |
721 |
EXPORT_SYMBOL(acpi_processor_register_performance); |
1da177e4c Linux-2.6.12-rc2 |
722 723 |
void |
4be44fcd3 [ACPI] Lindent al... |
724 725 |
acpi_processor_unregister_performance(struct acpi_processor_performance *performance, unsigned int cpu) |
1da177e4c Linux-2.6.12-rc2 |
726 727 |
{ struct acpi_processor *pr; |
65c19bbd2 sem2mutex: driver... |
728 |
mutex_lock(&performance_mutex); |
1da177e4c Linux-2.6.12-rc2 |
729 |
|
706546d02 ACPI: change proc... |
730 |
pr = per_cpu(processors, cpu); |
1da177e4c Linux-2.6.12-rc2 |
731 |
if (!pr) { |
65c19bbd2 sem2mutex: driver... |
732 |
mutex_unlock(&performance_mutex); |
d550d98d3 ACPI: delete trac... |
733 |
return; |
1da177e4c Linux-2.6.12-rc2 |
734 |
} |
a913f5070 [PATCH] powernow-... |
735 736 |
if (pr->performance) kfree(pr->performance->states); |
1da177e4c Linux-2.6.12-rc2 |
737 |
pr->performance = NULL; |
65c19bbd2 sem2mutex: driver... |
738 |
mutex_unlock(&performance_mutex); |
1da177e4c Linux-2.6.12-rc2 |
739 |
|
d550d98d3 ACPI: delete trac... |
740 |
return; |
1da177e4c Linux-2.6.12-rc2 |
741 |
} |
4be44fcd3 [ACPI] Lindent al... |
742 |
|
1da177e4c Linux-2.6.12-rc2 |
743 |
EXPORT_SYMBOL(acpi_processor_unregister_performance); |