Commit | Line | Data |
---|---|---|
1da177e4 LT |
1 | /* |
2 | * acpi_processor.c - ACPI Processor Driver ($Revision: 71 $) | |
3 | * | |
4 | * Copyright (C) 2001, 2002 Andy Grover <andrew.grover@intel.com> | |
5 | * Copyright (C) 2001, 2002 Paul Diefenbaugh <paul.s.diefenbaugh@intel.com> | |
6 | * Copyright (C) 2004 Dominik Brodowski <linux@brodo.de> | |
7 | * Copyright (C) 2004 Anil S Keshavamurthy <anil.s.keshavamurthy@intel.com> | |
8 | * - Added processor hotplug support | |
9 | * | |
10 | * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ | |
11 | * | |
12 | * This program is free software; you can redistribute it and/or modify | |
13 | * it under the terms of the GNU General Public License as published by | |
14 | * the Free Software Foundation; either version 2 of the License, or (at | |
15 | * your option) any later version. | |
16 | * | |
17 | * This program is distributed in the hope that it will be useful, but | |
18 | * WITHOUT ANY WARRANTY; without even the implied warranty of | |
19 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU | |
20 | * General Public License for more details. | |
21 | * | |
22 | * You should have received a copy of the GNU General Public License along | |
23 | * with this program; if not, write to the Free Software Foundation, Inc., | |
24 | * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA. | |
25 | * | |
26 | * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ | |
27 | * TBD: | |
28 | * 1. Make # power states dynamic. | |
29 | * 2. Support duty_cycle values that span bit 4. | |
30 | * 3. Optimize by having scheduler determine business instead of | |
31 | * having us try to calculate it here. | |
32 | * 4. Need C1 timing -- must modify kernel (IRQ handler) to get this. | |
33 | */ | |
34 | ||
35 | #include <linux/kernel.h> | |
36 | #include <linux/module.h> | |
37 | #include <linux/init.h> | |
38 | #include <linux/types.h> | |
39 | #include <linux/pci.h> | |
40 | #include <linux/pm.h> | |
41 | #include <linux/cpufreq.h> | |
42 | #include <linux/cpu.h> | |
43 | #include <linux/proc_fs.h> | |
44 | #include <linux/seq_file.h> | |
45 | #include <linux/dmi.h> | |
46 | #include <linux/moduleparam.h> | |
47 | ||
48 | #include <asm/io.h> | |
49 | #include <asm/system.h> | |
50 | #include <asm/cpu.h> | |
51 | #include <asm/delay.h> | |
52 | #include <asm/uaccess.h> | |
53 | #include <asm/processor.h> | |
54 | #include <asm/smp.h> | |
55 | #include <asm/acpi.h> | |
56 | ||
57 | #include <acpi/acpi_bus.h> | |
58 | #include <acpi/acpi_drivers.h> | |
59 | #include <acpi/processor.h> | |
60 | ||
61 | ||
62 | #define ACPI_PROCESSOR_COMPONENT 0x01000000 | |
63 | #define ACPI_PROCESSOR_CLASS "processor" | |
64 | #define ACPI_PROCESSOR_DRIVER_NAME "ACPI Processor Driver" | |
65 | #define ACPI_PROCESSOR_DEVICE_NAME "Processor" | |
66 | #define ACPI_PROCESSOR_FILE_INFO "info" | |
67 | #define ACPI_PROCESSOR_FILE_THROTTLING "throttling" | |
68 | #define ACPI_PROCESSOR_FILE_LIMIT "limit" | |
69 | #define ACPI_PROCESSOR_NOTIFY_PERFORMANCE 0x80 | |
70 | #define ACPI_PROCESSOR_NOTIFY_POWER 0x81 | |
71 | ||
72 | #define ACPI_PROCESSOR_LIMIT_USER 0 | |
73 | #define ACPI_PROCESSOR_LIMIT_THERMAL 1 | |
74 | ||
75 | #define ACPI_STA_PRESENT 0x00000001 | |
76 | ||
77 | #define _COMPONENT ACPI_PROCESSOR_COMPONENT | |
78 | ACPI_MODULE_NAME ("acpi_processor") | |
79 | ||
80 | MODULE_AUTHOR("Paul Diefenbaugh"); | |
81 | MODULE_DESCRIPTION(ACPI_PROCESSOR_DRIVER_NAME); | |
82 | MODULE_LICENSE("GPL"); | |
83 | ||
84 | ||
85 | static int acpi_processor_add (struct acpi_device *device); | |
86 | static int acpi_processor_start (struct acpi_device *device); | |
87 | static int acpi_processor_remove (struct acpi_device *device, int type); | |
88 | static int acpi_processor_info_open_fs(struct inode *inode, struct file *file); | |
89 | static void acpi_processor_notify ( acpi_handle handle, u32 event, void *data); | |
90 | static acpi_status acpi_processor_hotadd_init(acpi_handle handle, int *p_cpu); | |
91 | static int acpi_processor_handle_eject(struct acpi_processor *pr); | |
92 | ||
93 | static struct acpi_driver acpi_processor_driver = { | |
94 | .name = ACPI_PROCESSOR_DRIVER_NAME, | |
95 | .class = ACPI_PROCESSOR_CLASS, | |
96 | .ids = ACPI_PROCESSOR_HID, | |
97 | .ops = { | |
98 | .add = acpi_processor_add, | |
99 | .remove = acpi_processor_remove, | |
100 | .start = acpi_processor_start, | |
101 | }, | |
102 | }; | |
103 | ||
104 | #define INSTALL_NOTIFY_HANDLER 1 | |
105 | #define UNINSTALL_NOTIFY_HANDLER 2 | |
106 | ||
107 | ||
108 | static struct file_operations acpi_processor_info_fops = { | |
109 | .open = acpi_processor_info_open_fs, | |
110 | .read = seq_read, | |
111 | .llseek = seq_lseek, | |
112 | .release = single_release, | |
113 | }; | |
114 | ||
115 | ||
116 | struct acpi_processor *processors[NR_CPUS]; | |
117 | struct acpi_processor_errata errata; | |
118 | ||
119 | ||
120 | /* -------------------------------------------------------------------------- | |
121 | Errata Handling | |
122 | -------------------------------------------------------------------------- */ | |
123 | ||
124 | static int | |
125 | acpi_processor_errata_piix4 ( | |
126 | struct pci_dev *dev) | |
127 | { | |
128 | u8 rev = 0; | |
129 | u8 value1 = 0; | |
130 | u8 value2 = 0; | |
131 | ||
132 | ACPI_FUNCTION_TRACE("acpi_processor_errata_piix4"); | |
133 | ||
134 | if (!dev) | |
135 | return_VALUE(-EINVAL); | |
136 | ||
137 | /* | |
138 | * Note that 'dev' references the PIIX4 ACPI Controller. | |
139 | */ | |
140 | ||
141 | pci_read_config_byte(dev, PCI_REVISION_ID, &rev); | |
142 | ||
143 | switch (rev) { | |
144 | case 0: | |
145 | ACPI_DEBUG_PRINT((ACPI_DB_INFO, "Found PIIX4 A-step\n")); | |
146 | break; | |
147 | case 1: | |
148 | ACPI_DEBUG_PRINT((ACPI_DB_INFO, "Found PIIX4 B-step\n")); | |
149 | break; | |
150 | case 2: | |
151 | ACPI_DEBUG_PRINT((ACPI_DB_INFO, "Found PIIX4E\n")); | |
152 | break; | |
153 | case 3: | |
154 | ACPI_DEBUG_PRINT((ACPI_DB_INFO, "Found PIIX4M\n")); | |
155 | break; | |
156 | default: | |
157 | ACPI_DEBUG_PRINT((ACPI_DB_INFO, "Found unknown PIIX4\n")); | |
158 | break; | |
159 | } | |
160 | ||
161 | switch (rev) { | |
162 | ||
163 | case 0: /* PIIX4 A-step */ | |
164 | case 1: /* PIIX4 B-step */ | |
165 | /* | |
166 | * See specification changes #13 ("Manual Throttle Duty Cycle") | |
167 | * and #14 ("Enabling and Disabling Manual Throttle"), plus | |
168 | * erratum #5 ("STPCLK# Deassertion Time") from the January | |
169 | * 2002 PIIX4 specification update. Applies to only older | |
170 | * PIIX4 models. | |
171 | */ | |
172 | errata.piix4.throttle = 1; | |
173 | ||
174 | case 2: /* PIIX4E */ | |
175 | case 3: /* PIIX4M */ | |
176 | /* | |
177 | * See erratum #18 ("C3 Power State/BMIDE and Type-F DMA | |
178 | * Livelock") from the January 2002 PIIX4 specification update. | |
179 | * Applies to all PIIX4 models. | |
180 | */ | |
181 | ||
182 | /* | |
183 | * BM-IDE | |
184 | * ------ | |
185 | * Find the PIIX4 IDE Controller and get the Bus Master IDE | |
186 | * Status register address. We'll use this later to read | |
187 | * each IDE controller's DMA status to make sure we catch all | |
188 | * DMA activity. | |
189 | */ | |
190 | dev = pci_get_subsys(PCI_VENDOR_ID_INTEL, | |
191 | PCI_DEVICE_ID_INTEL_82371AB, | |
192 | PCI_ANY_ID, PCI_ANY_ID, NULL); | |
193 | if (dev) { | |
194 | errata.piix4.bmisx = pci_resource_start(dev, 4); | |
195 | pci_dev_put(dev); | |
196 | } | |
197 | ||
198 | /* | |
199 | * Type-F DMA | |
200 | * ---------- | |
201 | * Find the PIIX4 ISA Controller and read the Motherboard | |
202 | * DMA controller's status to see if Type-F (Fast) DMA mode | |
203 | * is enabled (bit 7) on either channel. Note that we'll | |
204 | * disable C3 support if this is enabled, as some legacy | |
205 | * devices won't operate well if fast DMA is disabled. | |
206 | */ | |
207 | dev = pci_get_subsys(PCI_VENDOR_ID_INTEL, | |
208 | PCI_DEVICE_ID_INTEL_82371AB_0, | |
209 | PCI_ANY_ID, PCI_ANY_ID, NULL); | |
210 | if (dev) { | |
211 | pci_read_config_byte(dev, 0x76, &value1); | |
212 | pci_read_config_byte(dev, 0x77, &value2); | |
213 | if ((value1 & 0x80) || (value2 & 0x80)) | |
214 | errata.piix4.fdma = 1; | |
215 | pci_dev_put(dev); | |
216 | } | |
217 | ||
218 | break; | |
219 | } | |
220 | ||
221 | if (errata.piix4.bmisx) | |
222 | ACPI_DEBUG_PRINT((ACPI_DB_INFO, | |
223 | "Bus master activity detection (BM-IDE) erratum enabled\n")); | |
224 | if (errata.piix4.fdma) | |
225 | ACPI_DEBUG_PRINT((ACPI_DB_INFO, | |
226 | "Type-F DMA livelock erratum (C3 disabled)\n")); | |
227 | ||
228 | return_VALUE(0); | |
229 | } | |
230 | ||
231 | ||
232 | int | |
233 | acpi_processor_errata ( | |
234 | struct acpi_processor *pr) | |
235 | { | |
236 | int result = 0; | |
237 | struct pci_dev *dev = NULL; | |
238 | ||
239 | ACPI_FUNCTION_TRACE("acpi_processor_errata"); | |
240 | ||
241 | if (!pr) | |
242 | return_VALUE(-EINVAL); | |
243 | ||
244 | /* | |
245 | * PIIX4 | |
246 | */ | |
247 | dev = pci_get_subsys(PCI_VENDOR_ID_INTEL, | |
248 | PCI_DEVICE_ID_INTEL_82371AB_3, PCI_ANY_ID, PCI_ANY_ID, NULL); | |
249 | if (dev) { | |
250 | result = acpi_processor_errata_piix4(dev); | |
251 | pci_dev_put(dev); | |
252 | } | |
253 | ||
254 | return_VALUE(result); | |
255 | } | |
256 | ||
257 | ||
258 | /* -------------------------------------------------------------------------- | |
259 | FS Interface (/proc) | |
260 | -------------------------------------------------------------------------- */ | |
261 | ||
262 | static struct proc_dir_entry *acpi_processor_dir = NULL; | |
263 | ||
264 | static int acpi_processor_info_seq_show(struct seq_file *seq, void *offset) | |
265 | { | |
266 | struct acpi_processor *pr = (struct acpi_processor *)seq->private; | |
267 | ||
268 | ACPI_FUNCTION_TRACE("acpi_processor_info_seq_show"); | |
269 | ||
270 | if (!pr) | |
271 | goto end; | |
272 | ||
273 | seq_printf(seq, "processor id: %d\n" | |
274 | "acpi id: %d\n" | |
275 | "bus mastering control: %s\n" | |
276 | "power management: %s\n" | |
277 | "throttling control: %s\n" | |
278 | "limit interface: %s\n", | |
279 | pr->id, | |
280 | pr->acpi_id, | |
281 | pr->flags.bm_control ? "yes" : "no", | |
282 | pr->flags.power ? "yes" : "no", | |
283 | pr->flags.throttling ? "yes" : "no", | |
284 | pr->flags.limit ? "yes" : "no"); | |
285 | ||
286 | end: | |
287 | return_VALUE(0); | |
288 | } | |
289 | ||
290 | static int acpi_processor_info_open_fs(struct inode *inode, struct file *file) | |
291 | { | |
292 | return single_open(file, acpi_processor_info_seq_show, | |
293 | PDE(inode)->data); | |
294 | } | |
295 | ||
296 | ||
297 | static int | |
298 | acpi_processor_add_fs ( | |
299 | struct acpi_device *device) | |
300 | { | |
301 | struct proc_dir_entry *entry = NULL; | |
302 | ||
303 | ACPI_FUNCTION_TRACE("acpi_processor_add_fs"); | |
304 | ||
305 | if (!acpi_device_dir(device)) { | |
306 | acpi_device_dir(device) = proc_mkdir(acpi_device_bid(device), | |
307 | acpi_processor_dir); | |
308 | if (!acpi_device_dir(device)) | |
309 | return_VALUE(-ENODEV); | |
310 | } | |
311 | acpi_device_dir(device)->owner = THIS_MODULE; | |
312 | ||
313 | /* 'info' [R] */ | |
314 | entry = create_proc_entry(ACPI_PROCESSOR_FILE_INFO, | |
315 | S_IRUGO, acpi_device_dir(device)); | |
316 | if (!entry) | |
317 | ACPI_DEBUG_PRINT((ACPI_DB_ERROR, | |
318 | "Unable to create '%s' fs entry\n", | |
319 | ACPI_PROCESSOR_FILE_INFO)); | |
320 | else { | |
321 | entry->proc_fops = &acpi_processor_info_fops; | |
322 | entry->data = acpi_driver_data(device); | |
323 | entry->owner = THIS_MODULE; | |
324 | } | |
325 | ||
326 | /* 'throttling' [R/W] */ | |
327 | entry = create_proc_entry(ACPI_PROCESSOR_FILE_THROTTLING, | |
328 | S_IFREG|S_IRUGO|S_IWUSR, acpi_device_dir(device)); | |
329 | if (!entry) | |
330 | ACPI_DEBUG_PRINT((ACPI_DB_ERROR, | |
331 | "Unable to create '%s' fs entry\n", | |
332 | ACPI_PROCESSOR_FILE_THROTTLING)); | |
333 | else { | |
334 | entry->proc_fops = &acpi_processor_throttling_fops; | |
335 | entry->proc_fops->write = acpi_processor_write_throttling; | |
336 | entry->data = acpi_driver_data(device); | |
337 | entry->owner = THIS_MODULE; | |
338 | } | |
339 | ||
340 | /* 'limit' [R/W] */ | |
341 | entry = create_proc_entry(ACPI_PROCESSOR_FILE_LIMIT, | |
342 | S_IFREG|S_IRUGO|S_IWUSR, acpi_device_dir(device)); | |
343 | if (!entry) | |
344 | ACPI_DEBUG_PRINT((ACPI_DB_ERROR, | |
345 | "Unable to create '%s' fs entry\n", | |
346 | ACPI_PROCESSOR_FILE_LIMIT)); | |
347 | else { | |
348 | entry->proc_fops = &acpi_processor_limit_fops; | |
349 | entry->proc_fops->write = acpi_processor_write_limit; | |
350 | entry->data = acpi_driver_data(device); | |
351 | entry->owner = THIS_MODULE; | |
352 | } | |
353 | ||
354 | return_VALUE(0); | |
355 | } | |
356 | ||
357 | ||
358 | static int | |
359 | acpi_processor_remove_fs ( | |
360 | struct acpi_device *device) | |
361 | { | |
362 | ACPI_FUNCTION_TRACE("acpi_processor_remove_fs"); | |
363 | ||
364 | if (acpi_device_dir(device)) { | |
365 | remove_proc_entry(ACPI_PROCESSOR_FILE_INFO,acpi_device_dir(device)); | |
366 | remove_proc_entry(ACPI_PROCESSOR_FILE_THROTTLING, | |
367 | acpi_device_dir(device)); | |
368 | remove_proc_entry(ACPI_PROCESSOR_FILE_LIMIT,acpi_device_dir(device)); | |
369 | remove_proc_entry(acpi_device_bid(device), acpi_processor_dir); | |
370 | acpi_device_dir(device) = NULL; | |
371 | } | |
372 | ||
373 | return_VALUE(0); | |
374 | } | |
375 | ||
376 | /* Use the acpiid in MADT to map cpus in case of SMP */ | |
377 | #ifndef CONFIG_SMP | |
378 | #define convert_acpiid_to_cpu(acpi_id) (0xff) | |
379 | #else | |
380 | ||
381 | #ifdef CONFIG_IA64 | |
382 | #define arch_acpiid_to_apicid ia64_acpiid_to_sapicid | |
383 | #define arch_cpu_to_apicid ia64_cpu_to_sapicid | |
384 | #define ARCH_BAD_APICID (0xffff) | |
385 | #else | |
386 | #define arch_acpiid_to_apicid x86_acpiid_to_apicid | |
387 | #define arch_cpu_to_apicid x86_cpu_to_apicid | |
388 | #define ARCH_BAD_APICID (0xff) | |
389 | #endif | |
390 | ||
391 | static u8 convert_acpiid_to_cpu(u8 acpi_id) | |
392 | { | |
393 | u16 apic_id; | |
394 | int i; | |
395 | ||
396 | apic_id = arch_acpiid_to_apicid[acpi_id]; | |
397 | if (apic_id == ARCH_BAD_APICID) | |
398 | return -1; | |
399 | ||
400 | for (i = 0; i < NR_CPUS; i++) { | |
401 | if (arch_cpu_to_apicid[i] == apic_id) | |
402 | return i; | |
403 | } | |
404 | return -1; | |
405 | } | |
406 | #endif | |
407 | ||
408 | /* -------------------------------------------------------------------------- | |
409 | Driver Interface | |
410 | -------------------------------------------------------------------------- */ | |
411 | ||
412 | static int | |
413 | acpi_processor_get_info ( | |
414 | struct acpi_processor *pr) | |
415 | { | |
416 | acpi_status status = 0; | |
417 | union acpi_object object = {0}; | |
418 | struct acpi_buffer buffer = {sizeof(union acpi_object), &object}; | |
419 | u8 cpu_index; | |
420 | static int cpu0_initialized; | |
421 | ||
422 | ACPI_FUNCTION_TRACE("acpi_processor_get_info"); | |
423 | ||
424 | if (!pr) | |
425 | return_VALUE(-EINVAL); | |
426 | ||
427 | if (num_online_cpus() > 1) | |
428 | errata.smp = TRUE; | |
429 | ||
430 | acpi_processor_errata(pr); | |
431 | ||
432 | /* | |
433 | * Check to see if we have bus mastering arbitration control. This | |
434 | * is required for proper C3 usage (to maintain cache coherency). | |
435 | */ | |
436 | if (acpi_fadt.V1_pm2_cnt_blk && acpi_fadt.pm2_cnt_len) { | |
437 | pr->flags.bm_control = 1; | |
438 | ACPI_DEBUG_PRINT((ACPI_DB_INFO, | |
439 | "Bus mastering arbitration control present\n")); | |
440 | } | |
441 | else | |
442 | ACPI_DEBUG_PRINT((ACPI_DB_INFO, | |
443 | "No bus mastering arbitration control\n")); | |
444 | ||
445 | /* | |
446 | * Evalute the processor object. Note that it is common on SMP to | |
447 | * have the first (boot) processor with a valid PBLK address while | |
448 | * all others have a NULL address. | |
449 | */ | |
450 | status = acpi_evaluate_object(pr->handle, NULL, NULL, &buffer); | |
451 | if (ACPI_FAILURE(status)) { | |
452 | ACPI_DEBUG_PRINT((ACPI_DB_ERROR, | |
453 | "Error evaluating processor object\n")); | |
454 | return_VALUE(-ENODEV); | |
455 | } | |
456 | ||
457 | /* | |
458 | * TBD: Synch processor ID (via LAPIC/LSAPIC structures) on SMP. | |
459 | * >>> 'acpi_get_processor_id(acpi_id, &id)' in arch/xxx/acpi.c | |
460 | */ | |
461 | pr->acpi_id = object.processor.proc_id; | |
462 | ||
463 | cpu_index = convert_acpiid_to_cpu(pr->acpi_id); | |
464 | ||
465 | /* Handle UP system running SMP kernel, with no LAPIC in MADT */ | |
466 | if ( !cpu0_initialized && (cpu_index == 0xff) && | |
467 | (num_online_cpus() == 1)) { | |
468 | cpu_index = 0; | |
469 | } | |
470 | ||
471 | cpu0_initialized = 1; | |
472 | ||
473 | pr->id = cpu_index; | |
474 | ||
475 | /* | |
476 | * Extra Processor objects may be enumerated on MP systems with | |
477 | * less than the max # of CPUs. They should be ignored _iff | |
478 | * they are physically not present. | |
479 | */ | |
480 | if (cpu_index >= NR_CPUS) { | |
481 | if (ACPI_FAILURE(acpi_processor_hotadd_init(pr->handle, &pr->id))) { | |
482 | ACPI_DEBUG_PRINT((ACPI_DB_ERROR, | |
483 | "Error getting cpuindex for acpiid 0x%x\n", | |
484 | pr->acpi_id)); | |
485 | return_VALUE(-ENODEV); | |
486 | } | |
487 | } | |
488 | ||
489 | ACPI_DEBUG_PRINT((ACPI_DB_INFO, "Processor [%d:%d]\n", pr->id, | |
490 | pr->acpi_id)); | |
491 | ||
492 | if (!object.processor.pblk_address) | |
493 | ACPI_DEBUG_PRINT((ACPI_DB_INFO, "No PBLK (NULL address)\n")); | |
494 | else if (object.processor.pblk_length != 6) | |
495 | ACPI_DEBUG_PRINT((ACPI_DB_ERROR, "Invalid PBLK length [%d]\n", | |
496 | object.processor.pblk_length)); | |
497 | else { | |
498 | pr->throttling.address = object.processor.pblk_address; | |
499 | pr->throttling.duty_offset = acpi_fadt.duty_offset; | |
500 | pr->throttling.duty_width = acpi_fadt.duty_width; | |
501 | ||
502 | pr->pblk = object.processor.pblk_address; | |
503 | ||
504 | /* | |
505 | * We don't care about error returns - we just try to mark | |
506 | * these reserved so that nobody else is confused into thinking | |
507 | * that this region might be unused.. | |
508 | * | |
509 | * (In particular, allocating the IO range for Cardbus) | |
510 | */ | |
511 | request_region(pr->throttling.address, 6, "ACPI CPU throttle"); | |
512 | } | |
513 | ||
514 | #ifdef CONFIG_CPU_FREQ | |
515 | acpi_processor_ppc_has_changed(pr); | |
516 | #endif | |
517 | acpi_processor_get_throttling_info(pr); | |
518 | acpi_processor_get_limit_info(pr); | |
519 | ||
520 | return_VALUE(0); | |
521 | } | |
522 | ||
523 | static int | |
524 | acpi_processor_start( | |
525 | struct acpi_device *device) | |
526 | { | |
527 | int result = 0; | |
528 | acpi_status status = AE_OK; | |
529 | struct acpi_processor *pr; | |
530 | ||
531 | ACPI_FUNCTION_TRACE("acpi_processor_start"); | |
532 | ||
533 | pr = acpi_driver_data(device); | |
534 | ||
535 | result = acpi_processor_get_info(pr); | |
536 | if (result) { | |
537 | /* Processor is physically not present */ | |
538 | return_VALUE(0); | |
539 | } | |
540 | ||
541 | BUG_ON((pr->id >= NR_CPUS) || (pr->id < 0)); | |
542 | ||
543 | processors[pr->id] = pr; | |
544 | ||
545 | result = acpi_processor_add_fs(device); | |
546 | if (result) | |
547 | goto end; | |
548 | ||
549 | status = acpi_install_notify_handler(pr->handle, ACPI_DEVICE_NOTIFY, | |
550 | acpi_processor_notify, pr); | |
551 | if (ACPI_FAILURE(status)) { | |
552 | ACPI_DEBUG_PRINT((ACPI_DB_ERROR, | |
553 | "Error installing device notify handler\n")); | |
554 | } | |
555 | ||
556 | acpi_processor_power_init(pr, device); | |
557 | ||
558 | if (pr->flags.throttling) { | |
559 | printk(KERN_INFO PREFIX "%s [%s] (supports", | |
560 | acpi_device_name(device), acpi_device_bid(device)); | |
561 | printk(" %d throttling states", pr->throttling.state_count); | |
562 | printk(")\n"); | |
563 | } | |
564 | ||
565 | end: | |
566 | ||
567 | return_VALUE(result); | |
568 | } | |
569 | ||
570 | ||
571 | ||
572 | static void | |
573 | acpi_processor_notify ( | |
574 | acpi_handle handle, | |
575 | u32 event, | |
576 | void *data) | |
577 | { | |
578 | struct acpi_processor *pr = (struct acpi_processor *) data; | |
579 | struct acpi_device *device = NULL; | |
580 | ||
581 | ACPI_FUNCTION_TRACE("acpi_processor_notify"); | |
582 | ||
583 | if (!pr) | |
584 | return_VOID; | |
585 | ||
586 | if (acpi_bus_get_device(pr->handle, &device)) | |
587 | return_VOID; | |
588 | ||
589 | switch (event) { | |
590 | case ACPI_PROCESSOR_NOTIFY_PERFORMANCE: | |
591 | acpi_processor_ppc_has_changed(pr); | |
592 | acpi_bus_generate_event(device, event, | |
593 | pr->performance_platform_limit); | |
594 | break; | |
595 | case ACPI_PROCESSOR_NOTIFY_POWER: | |
596 | acpi_processor_cst_has_changed(pr); | |
597 | acpi_bus_generate_event(device, event, 0); | |
598 | break; | |
599 | default: | |
600 | ACPI_DEBUG_PRINT((ACPI_DB_INFO, | |
601 | "Unsupported event [0x%x]\n", event)); | |
602 | break; | |
603 | } | |
604 | ||
605 | return_VOID; | |
606 | } | |
607 | ||
608 | ||
609 | static int | |
610 | acpi_processor_add ( | |
611 | struct acpi_device *device) | |
612 | { | |
613 | struct acpi_processor *pr = NULL; | |
614 | ||
615 | ACPI_FUNCTION_TRACE("acpi_processor_add"); | |
616 | ||
617 | if (!device) | |
618 | return_VALUE(-EINVAL); | |
619 | ||
620 | pr = kmalloc(sizeof(struct acpi_processor), GFP_KERNEL); | |
621 | if (!pr) | |
622 | return_VALUE(-ENOMEM); | |
623 | memset(pr, 0, sizeof(struct acpi_processor)); | |
624 | ||
625 | pr->handle = device->handle; | |
626 | strcpy(acpi_device_name(device), ACPI_PROCESSOR_DEVICE_NAME); | |
627 | strcpy(acpi_device_class(device), ACPI_PROCESSOR_CLASS); | |
628 | acpi_driver_data(device) = pr; | |
629 | ||
630 | return_VALUE(0); | |
631 | } | |
632 | ||
633 | ||
634 | static int | |
635 | acpi_processor_remove ( | |
636 | struct acpi_device *device, | |
637 | int type) | |
638 | { | |
639 | acpi_status status = AE_OK; | |
640 | struct acpi_processor *pr = NULL; | |
641 | ||
642 | ACPI_FUNCTION_TRACE("acpi_processor_remove"); | |
643 | ||
644 | if (!device || !acpi_driver_data(device)) | |
645 | return_VALUE(-EINVAL); | |
646 | ||
647 | pr = (struct acpi_processor *) acpi_driver_data(device); | |
648 | ||
649 | if (pr->id >= NR_CPUS) { | |
650 | kfree(pr); | |
651 | return_VALUE(0); | |
652 | } | |
653 | ||
654 | if (type == ACPI_BUS_REMOVAL_EJECT) { | |
655 | if (acpi_processor_handle_eject(pr)) | |
656 | return_VALUE(-EINVAL); | |
657 | } | |
658 | ||
659 | acpi_processor_power_exit(pr, device); | |
660 | ||
661 | status = acpi_remove_notify_handler(pr->handle, ACPI_DEVICE_NOTIFY, | |
662 | acpi_processor_notify); | |
663 | if (ACPI_FAILURE(status)) { | |
664 | ACPI_DEBUG_PRINT((ACPI_DB_ERROR, | |
665 | "Error removing notify handler\n")); | |
666 | } | |
667 | ||
668 | acpi_processor_remove_fs(device); | |
669 | ||
670 | processors[pr->id] = NULL; | |
671 | ||
672 | kfree(pr); | |
673 | ||
674 | return_VALUE(0); | |
675 | } | |
676 | ||
677 | #ifdef CONFIG_ACPI_HOTPLUG_CPU | |
678 | /**************************************************************************** | |
679 | * Acpi processor hotplug support * | |
680 | ****************************************************************************/ | |
681 | ||
682 | static int is_processor_present(acpi_handle handle); | |
683 | ||
684 | static int | |
685 | is_processor_present( | |
686 | acpi_handle handle) | |
687 | { | |
688 | acpi_status status; | |
689 | unsigned long sta = 0; | |
690 | ||
691 | ACPI_FUNCTION_TRACE("is_processor_present"); | |
692 | ||
693 | status = acpi_evaluate_integer(handle, "_STA", NULL, &sta); | |
694 | if (ACPI_FAILURE(status) || !(sta & ACPI_STA_PRESENT)) { | |
695 | ACPI_DEBUG_PRINT((ACPI_DB_ERROR, | |
696 | "Processor Device is not present\n")); | |
697 | return_VALUE(0); | |
698 | } | |
699 | return_VALUE(1); | |
700 | } | |
701 | ||
702 | ||
703 | static | |
704 | int acpi_processor_device_add( | |
705 | acpi_handle handle, | |
706 | struct acpi_device **device) | |
707 | { | |
708 | acpi_handle phandle; | |
709 | struct acpi_device *pdev; | |
710 | struct acpi_processor *pr; | |
711 | ||
712 | ACPI_FUNCTION_TRACE("acpi_processor_device_add"); | |
713 | ||
714 | if (acpi_get_parent(handle, &phandle)) { | |
715 | return_VALUE(-ENODEV); | |
716 | } | |
717 | ||
718 | if (acpi_bus_get_device(phandle, &pdev)) { | |
719 | return_VALUE(-ENODEV); | |
720 | } | |
721 | ||
722 | if (acpi_bus_add(device, pdev, handle, ACPI_BUS_TYPE_PROCESSOR)) { | |
723 | return_VALUE(-ENODEV); | |
724 | } | |
725 | ||
726 | acpi_bus_scan(*device); | |
727 | ||
728 | pr = acpi_driver_data(*device); | |
729 | if (!pr) | |
730 | return_VALUE(-ENODEV); | |
731 | ||
732 | if ((pr->id >=0) && (pr->id < NR_CPUS)) { | |
733 | kobject_hotplug(&(*device)->kobj, KOBJ_ONLINE); | |
734 | } | |
735 | return_VALUE(0); | |
736 | } | |
737 | ||
738 | ||
739 | static void | |
740 | acpi_processor_hotplug_notify ( | |
741 | acpi_handle handle, | |
742 | u32 event, | |
743 | void *data) | |
744 | { | |
745 | struct acpi_processor *pr; | |
746 | struct acpi_device *device = NULL; | |
747 | int result; | |
748 | ||
749 | ACPI_FUNCTION_TRACE("acpi_processor_hotplug_notify"); | |
750 | ||
751 | switch (event) { | |
752 | case ACPI_NOTIFY_BUS_CHECK: | |
753 | case ACPI_NOTIFY_DEVICE_CHECK: | |
754 | printk("Processor driver received %s event\n", | |
755 | (event==ACPI_NOTIFY_BUS_CHECK)? | |
756 | "ACPI_NOTIFY_BUS_CHECK":"ACPI_NOTIFY_DEVICE_CHECK"); | |
757 | ||
758 | if (!is_processor_present(handle)) | |
759 | break; | |
760 | ||
761 | if (acpi_bus_get_device(handle, &device)) { | |
762 | result = acpi_processor_device_add(handle, &device); | |
763 | if (result) | |
764 | ACPI_DEBUG_PRINT((ACPI_DB_ERROR, | |
765 | "Unable to add the device\n")); | |
766 | break; | |
767 | } | |
768 | ||
769 | pr = acpi_driver_data(device); | |
770 | if (!pr) { | |
771 | ACPI_DEBUG_PRINT((ACPI_DB_ERROR, | |
772 | "Driver data is NULL\n")); | |
773 | break; | |
774 | } | |
775 | ||
776 | if (pr->id >= 0 && (pr->id < NR_CPUS)) { | |
777 | kobject_hotplug(&device->kobj, KOBJ_OFFLINE); | |
778 | break; | |
779 | } | |
780 | ||
781 | result = acpi_processor_start(device); | |
782 | if ((!result) && ((pr->id >=0) && (pr->id < NR_CPUS))) { | |
783 | kobject_hotplug(&device->kobj, KOBJ_ONLINE); | |
784 | } else { | |
785 | ACPI_DEBUG_PRINT((ACPI_DB_ERROR, | |
786 | "Device [%s] failed to start\n", | |
787 | acpi_device_bid(device))); | |
788 | } | |
789 | break; | |
790 | case ACPI_NOTIFY_EJECT_REQUEST: | |
791 | ACPI_DEBUG_PRINT((ACPI_DB_INFO,"received ACPI_NOTIFY_EJECT_REQUEST\n")); | |
792 | ||
793 | if (acpi_bus_get_device(handle, &device)) { | |
794 | ACPI_DEBUG_PRINT((ACPI_DB_ERROR,"Device don't exist, dropping EJECT\n")); | |
795 | break; | |
796 | } | |
797 | pr = acpi_driver_data(device); | |
798 | if (!pr) { | |
799 | ACPI_DEBUG_PRINT((ACPI_DB_ERROR,"Driver data is NULL, dropping EJECT\n")); | |
800 | return_VOID; | |
801 | } | |
802 | ||
803 | if ((pr->id < NR_CPUS) && (cpu_present(pr->id))) | |
804 | kobject_hotplug(&device->kobj, KOBJ_OFFLINE); | |
805 | break; | |
806 | default: | |
807 | ACPI_DEBUG_PRINT((ACPI_DB_INFO, | |
808 | "Unsupported event [0x%x]\n", event)); | |
809 | break; | |
810 | } | |
811 | ||
812 | return_VOID; | |
813 | } | |
814 | ||
815 | static acpi_status | |
816 | processor_walk_namespace_cb(acpi_handle handle, | |
817 | u32 lvl, | |
818 | void *context, | |
819 | void **rv) | |
820 | { | |
821 | acpi_status status; | |
822 | int *action = context; | |
823 | acpi_object_type type = 0; | |
824 | ||
825 | status = acpi_get_type(handle, &type); | |
826 | if (ACPI_FAILURE(status)) | |
827 | return(AE_OK); | |
828 | ||
829 | if (type != ACPI_TYPE_PROCESSOR) | |
830 | return(AE_OK); | |
831 | ||
832 | switch(*action) { | |
833 | case INSTALL_NOTIFY_HANDLER: | |
834 | acpi_install_notify_handler(handle, | |
835 | ACPI_SYSTEM_NOTIFY, | |
836 | acpi_processor_hotplug_notify, | |
837 | NULL); | |
838 | break; | |
839 | case UNINSTALL_NOTIFY_HANDLER: | |
840 | acpi_remove_notify_handler(handle, | |
841 | ACPI_SYSTEM_NOTIFY, | |
842 | acpi_processor_hotplug_notify); | |
843 | break; | |
844 | default: | |
845 | break; | |
846 | } | |
847 | ||
848 | return(AE_OK); | |
849 | } | |
850 | ||
851 | ||
852 | static acpi_status | |
853 | acpi_processor_hotadd_init( | |
854 | acpi_handle handle, | |
855 | int *p_cpu) | |
856 | { | |
857 | ACPI_FUNCTION_TRACE("acpi_processor_hotadd_init"); | |
858 | ||
859 | if (!is_processor_present(handle)) { | |
860 | return_VALUE(AE_ERROR); | |
861 | } | |
862 | ||
863 | if (acpi_map_lsapic(handle, p_cpu)) | |
864 | return_VALUE(AE_ERROR); | |
865 | ||
866 | if (arch_register_cpu(*p_cpu)) { | |
867 | acpi_unmap_lsapic(*p_cpu); | |
868 | return_VALUE(AE_ERROR); | |
869 | } | |
870 | ||
871 | return_VALUE(AE_OK); | |
872 | } | |
873 | ||
874 | ||
875 | static int | |
876 | acpi_processor_handle_eject(struct acpi_processor *pr) | |
877 | { | |
878 | if (cpu_online(pr->id)) { | |
879 | return(-EINVAL); | |
880 | } | |
881 | arch_unregister_cpu(pr->id); | |
882 | acpi_unmap_lsapic(pr->id); | |
883 | return(0); | |
884 | } | |
885 | #else | |
886 | static acpi_status | |
887 | acpi_processor_hotadd_init( | |
888 | acpi_handle handle, | |
889 | int *p_cpu) | |
890 | { | |
891 | return AE_ERROR; | |
892 | } | |
893 | static int | |
894 | acpi_processor_handle_eject(struct acpi_processor *pr) | |
895 | { | |
896 | return(-EINVAL); | |
897 | } | |
898 | #endif | |
899 | ||
900 | ||
901 | static | |
902 | void acpi_processor_install_hotplug_notify(void) | |
903 | { | |
904 | #ifdef CONFIG_ACPI_HOTPLUG_CPU | |
905 | int action = INSTALL_NOTIFY_HANDLER; | |
906 | acpi_walk_namespace(ACPI_TYPE_PROCESSOR, | |
907 | ACPI_ROOT_OBJECT, | |
908 | ACPI_UINT32_MAX, | |
909 | processor_walk_namespace_cb, | |
910 | &action, NULL); | |
911 | #endif | |
912 | } | |
913 | ||
914 | ||
915 | static | |
916 | void acpi_processor_uninstall_hotplug_notify(void) | |
917 | { | |
918 | #ifdef CONFIG_ACPI_HOTPLUG_CPU | |
919 | int action = UNINSTALL_NOTIFY_HANDLER; | |
920 | acpi_walk_namespace(ACPI_TYPE_PROCESSOR, | |
921 | ACPI_ROOT_OBJECT, | |
922 | ACPI_UINT32_MAX, | |
923 | processor_walk_namespace_cb, | |
924 | &action, NULL); | |
925 | #endif | |
926 | } | |
927 | ||
928 | /* | |
929 | * We keep the driver loaded even when ACPI is not running. | |
930 | * This is needed for the powernow-k8 driver, that works even without | |
931 | * ACPI, but needs symbols from this driver | |
932 | */ | |
933 | ||
934 | static int __init | |
935 | acpi_processor_init (void) | |
936 | { | |
937 | int result = 0; | |
938 | ||
939 | ACPI_FUNCTION_TRACE("acpi_processor_init"); | |
940 | ||
941 | memset(&processors, 0, sizeof(processors)); | |
942 | memset(&errata, 0, sizeof(errata)); | |
943 | ||
944 | acpi_processor_dir = proc_mkdir(ACPI_PROCESSOR_CLASS, acpi_root_dir); | |
945 | if (!acpi_processor_dir) | |
946 | return_VALUE(0); | |
947 | acpi_processor_dir->owner = THIS_MODULE; | |
948 | ||
949 | result = acpi_bus_register_driver(&acpi_processor_driver); | |
950 | if (result < 0) { | |
951 | remove_proc_entry(ACPI_PROCESSOR_CLASS, acpi_root_dir); | |
952 | return_VALUE(0); | |
953 | } | |
954 | ||
955 | acpi_processor_install_hotplug_notify(); | |
956 | ||
957 | acpi_thermal_cpufreq_init(); | |
958 | ||
959 | acpi_processor_ppc_init(); | |
960 | ||
961 | return_VALUE(0); | |
962 | } | |
963 | ||
964 | ||
965 | static void __exit | |
966 | acpi_processor_exit (void) | |
967 | { | |
968 | ACPI_FUNCTION_TRACE("acpi_processor_exit"); | |
969 | ||
970 | acpi_processor_ppc_exit(); | |
971 | ||
972 | acpi_thermal_cpufreq_exit(); | |
973 | ||
974 | acpi_processor_uninstall_hotplug_notify(); | |
975 | ||
976 | acpi_bus_unregister_driver(&acpi_processor_driver); | |
977 | ||
978 | remove_proc_entry(ACPI_PROCESSOR_CLASS, acpi_root_dir); | |
979 | ||
980 | return_VOID; | |
981 | } | |
982 | ||
983 | ||
984 | module_init(acpi_processor_init); | |
985 | module_exit(acpi_processor_exit); | |
986 | ||
987 | EXPORT_SYMBOL(acpi_processor_set_thermal_limit); | |
988 | ||
989 | MODULE_ALIAS("processor"); |