#include <linux/seq_file.h>
#include <linux/dmi.h>
#include <linux/moduleparam.h>
+#include <linux/cpuidle.h>
#include <asm/io.h>
#include <asm/system.h>
#define ACPI_PROCESSOR_COMPONENT 0x01000000
#define ACPI_PROCESSOR_CLASS "processor"
-#define ACPI_PROCESSOR_DRIVER_NAME "ACPI Processor Driver"
#define ACPI_PROCESSOR_DEVICE_NAME "Processor"
#define ACPI_PROCESSOR_FILE_INFO "info"
#define ACPI_PROCESSOR_FILE_THROTTLING "throttling"
#define ACPI_PROCESSOR_FILE_LIMIT "limit"
#define ACPI_PROCESSOR_NOTIFY_PERFORMANCE 0x80
#define ACPI_PROCESSOR_NOTIFY_POWER 0x81
+#define ACPI_PROCESSOR_NOTIFY_THROTTLING 0x82
#define ACPI_PROCESSOR_LIMIT_USER 0
#define ACPI_PROCESSOR_LIMIT_THERMAL 1
-#define ACPI_STA_PRESENT 0x00000001
-
#define _COMPONENT ACPI_PROCESSOR_COMPONENT
-ACPI_MODULE_NAME("acpi_processor")
+ACPI_MODULE_NAME("processor_core");
- MODULE_AUTHOR("Paul Diefenbaugh");
-MODULE_DESCRIPTION(ACPI_PROCESSOR_DRIVER_NAME);
+MODULE_AUTHOR("Paul Diefenbaugh");
+MODULE_DESCRIPTION("ACPI Processor Driver");
MODULE_LICENSE("GPL");
static int acpi_processor_add(struct acpi_device *device);
static void acpi_processor_notify(acpi_handle handle, u32 event, void *data);
static acpi_status acpi_processor_hotadd_init(acpi_handle handle, int *p_cpu);
static int acpi_processor_handle_eject(struct acpi_processor *pr);
+extern int acpi_processor_tstate_has_changed(struct acpi_processor *pr);
+
+
+static const struct acpi_device_id processor_device_ids[] = {
+ {ACPI_PROCESSOR_HID, 0},
+ {"", 0},
+};
+MODULE_DEVICE_TABLE(acpi, processor_device_ids);
static struct acpi_driver acpi_processor_driver = {
- .name = ACPI_PROCESSOR_DRIVER_NAME,
+ .name = "processor",
.class = ACPI_PROCESSOR_CLASS,
- .ids = ACPI_PROCESSOR_HID,
+ .ids = processor_device_ids,
.ops = {
.add = acpi_processor_add,
.remove = acpi_processor_remove,
.start = acpi_processor_start,
+ .suspend = acpi_processor_suspend,
+ .resume = acpi_processor_resume,
},
};
#define INSTALL_NOTIFY_HANDLER 1
#define UNINSTALL_NOTIFY_HANDLER 2
-static struct file_operations acpi_processor_info_fops = {
+static const struct file_operations acpi_processor_info_fops = {
+ .owner = THIS_MODULE,
.open = acpi_processor_info_open_fs,
.read = seq_read,
.llseek = seq_lseek,
static int acpi_processor_errata_piix4(struct pci_dev *dev)
{
- u8 rev = 0;
u8 value1 = 0;
u8 value2 = 0;
- ACPI_FUNCTION_TRACE("acpi_processor_errata_piix4");
if (!dev)
- return_VALUE(-EINVAL);
+ return -EINVAL;
/*
* Note that 'dev' references the PIIX4 ACPI Controller.
*/
- pci_read_config_byte(dev, PCI_REVISION_ID, &rev);
-
- switch (rev) {
+ switch (dev->revision) {
case 0:
ACPI_DEBUG_PRINT((ACPI_DB_INFO, "Found PIIX4 A-step\n"));
break;
break;
}
- switch (rev) {
+ switch (dev->revision) {
case 0: /* PIIX4 A-step */
case 1: /* PIIX4 B-step */
ACPI_DEBUG_PRINT((ACPI_DB_INFO,
"Type-F DMA livelock erratum (C3 disabled)\n"));
- return_VALUE(0);
+ return 0;
}
static int acpi_processor_errata(struct acpi_processor *pr)
int result = 0;
struct pci_dev *dev = NULL;
- ACPI_FUNCTION_TRACE("acpi_processor_errata");
if (!pr)
- return_VALUE(-EINVAL);
+ return -EINVAL;
/*
* PIIX4
pci_dev_put(dev);
}
- return_VALUE(result);
+ return result;
}
/* --------------------------------------------------------------------------
struct acpi_object_list *pdc_in = pr->pdc;
acpi_status status = AE_OK;
- ACPI_FUNCTION_TRACE("acpi_processor_set_pdc");
if (!pdc_in)
- return_VALUE(status);
+ return status;
status = acpi_evaluate_object(pr->handle, "_PDC", pdc_in, NULL);
ACPI_DEBUG_PRINT((ACPI_DB_INFO,
"Could not evaluate _PDC, using legacy perf. control...\n"));
- return_VALUE(status);
+ return status;
}
/* --------------------------------------------------------------------------
static int acpi_processor_info_seq_show(struct seq_file *seq, void *offset)
{
- struct acpi_processor *pr = (struct acpi_processor *)seq->private;
+ struct acpi_processor *pr = seq->private;
- ACPI_FUNCTION_TRACE("acpi_processor_info_seq_show");
if (!pr)
goto end;
pr->flags.limit ? "yes" : "no");
end:
- return_VALUE(0);
+ return 0;
}
static int acpi_processor_info_open_fs(struct inode *inode, struct file *file)
{
struct proc_dir_entry *entry = NULL;
- ACPI_FUNCTION_TRACE("acpi_processor_add_fs");
if (!acpi_device_dir(device)) {
acpi_device_dir(device) = proc_mkdir(acpi_device_bid(device),
acpi_processor_dir);
if (!acpi_device_dir(device))
- return_VALUE(-ENODEV);
+ return -ENODEV;
}
acpi_device_dir(device)->owner = THIS_MODULE;
/* 'info' [R] */
- entry = create_proc_entry(ACPI_PROCESSOR_FILE_INFO,
- S_IRUGO, acpi_device_dir(device));
+ entry = proc_create_data(ACPI_PROCESSOR_FILE_INFO,
+ S_IRUGO, acpi_device_dir(device),
+ &acpi_processor_info_fops,
+ acpi_driver_data(device));
if (!entry)
- ACPI_DEBUG_PRINT((ACPI_DB_ERROR,
- "Unable to create '%s' fs entry\n",
- ACPI_PROCESSOR_FILE_INFO));
- else {
- entry->proc_fops = &acpi_processor_info_fops;
- entry->data = acpi_driver_data(device);
- entry->owner = THIS_MODULE;
- }
+ return -EIO;
/* 'throttling' [R/W] */
- entry = create_proc_entry(ACPI_PROCESSOR_FILE_THROTTLING,
- S_IFREG | S_IRUGO | S_IWUSR,
- acpi_device_dir(device));
+ entry = proc_create_data(ACPI_PROCESSOR_FILE_THROTTLING,
+ S_IFREG | S_IRUGO | S_IWUSR,
+ acpi_device_dir(device),
+ &acpi_processor_throttling_fops,
+ acpi_driver_data(device));
if (!entry)
- ACPI_DEBUG_PRINT((ACPI_DB_ERROR,
- "Unable to create '%s' fs entry\n",
- ACPI_PROCESSOR_FILE_THROTTLING));
- else {
- entry->proc_fops = &acpi_processor_throttling_fops;
- entry->data = acpi_driver_data(device);
- entry->owner = THIS_MODULE;
- }
+ return -EIO;
/* 'limit' [R/W] */
- entry = create_proc_entry(ACPI_PROCESSOR_FILE_LIMIT,
- S_IFREG | S_IRUGO | S_IWUSR,
- acpi_device_dir(device));
+ entry = proc_create_data(ACPI_PROCESSOR_FILE_LIMIT,
+ S_IFREG | S_IRUGO | S_IWUSR,
+ acpi_device_dir(device),
+ &acpi_processor_limit_fops,
+ acpi_driver_data(device));
if (!entry)
- ACPI_DEBUG_PRINT((ACPI_DB_ERROR,
- "Unable to create '%s' fs entry\n",
- ACPI_PROCESSOR_FILE_LIMIT));
- else {
- entry->proc_fops = &acpi_processor_limit_fops;
- entry->data = acpi_driver_data(device);
- entry->owner = THIS_MODULE;
- }
-
- return_VALUE(0);
+ return -EIO;
+ return 0;
}
static int acpi_processor_remove_fs(struct acpi_device *device)
{
- ACPI_FUNCTION_TRACE("acpi_processor_remove_fs");
if (acpi_device_dir(device)) {
remove_proc_entry(ACPI_PROCESSOR_FILE_INFO,
acpi_device_dir(device) = NULL;
}
- return_VALUE(0);
+ return 0;
}
/* Use the acpiid in MADT to map cpus in case of SMP */
+
#ifndef CONFIG_SMP
-#define convert_acpiid_to_cpu(acpi_id) (0xff)
+static int get_cpu_id(acpi_handle handle, u32 acpi_id) {return -1;}
#else
-#ifdef CONFIG_IA64
-#define arch_acpiid_to_apicid ia64_acpiid_to_sapicid
-#define arch_cpu_to_apicid ia64_cpu_to_sapicid
-#define ARCH_BAD_APICID (0xffff)
-#else
-#define arch_acpiid_to_apicid x86_acpiid_to_apicid
-#define arch_cpu_to_apicid x86_cpu_to_apicid
-#define ARCH_BAD_APICID (0xff)
-#endif
+static struct acpi_table_madt *madt;
+
+static int map_lapic_id(struct acpi_subtable_header *entry,
+ u32 acpi_id, int *apic_id)
+{
+ struct acpi_madt_local_apic *lapic =
+ (struct acpi_madt_local_apic *)entry;
+ if ((lapic->lapic_flags & ACPI_MADT_ENABLED) &&
+ lapic->processor_id == acpi_id) {
+ *apic_id = lapic->id;
+ return 1;
+ }
+ return 0;
+}
-static u8 convert_acpiid_to_cpu(u8 acpi_id)
+static int map_lsapic_id(struct acpi_subtable_header *entry,
+ u32 acpi_id, int *apic_id)
+{
+ struct acpi_madt_local_sapic *lsapic =
+ (struct acpi_madt_local_sapic *)entry;
+ /* Only check enabled APICs*/
+ if (lsapic->lapic_flags & ACPI_MADT_ENABLED) {
+ /* First check against id */
+ if (lsapic->processor_id == acpi_id) {
+ *apic_id = (lsapic->id << 8) | lsapic->eid;
+ return 1;
+ /* Check against optional uid */
+ } else if (entry->length >= 16 &&
+ lsapic->uid == acpi_id) {
+ *apic_id = lsapic->uid;
+ return 1;
+ }
+ }
+ return 0;
+}
+
+static int map_madt_entry(u32 acpi_id)
+{
+ unsigned long madt_end, entry;
+ int apic_id = -1;
+
+ if (!madt)
+ return apic_id;
+
+ entry = (unsigned long)madt;
+ madt_end = entry + madt->header.length;
+
+ /* Parse all entries looking for a match. */
+
+ entry += sizeof(struct acpi_table_madt);
+ while (entry + sizeof(struct acpi_subtable_header) < madt_end) {
+ struct acpi_subtable_header *header =
+ (struct acpi_subtable_header *)entry;
+ if (header->type == ACPI_MADT_TYPE_LOCAL_APIC) {
+ if (map_lapic_id(header, acpi_id, &apic_id))
+ break;
+ } else if (header->type == ACPI_MADT_TYPE_LOCAL_SAPIC) {
+ if (map_lsapic_id(header, acpi_id, &apic_id))
+ break;
+ }
+ entry += header->length;
+ }
+ return apic_id;
+}
+
+static int map_mat_entry(acpi_handle handle, u32 acpi_id)
+{
+ struct acpi_buffer buffer = { ACPI_ALLOCATE_BUFFER, NULL };
+ union acpi_object *obj;
+ struct acpi_subtable_header *header;
+ int apic_id = -1;
+
+ if (ACPI_FAILURE(acpi_evaluate_object(handle, "_MAT", NULL, &buffer)))
+ goto exit;
+
+ if (!buffer.length || !buffer.pointer)
+ goto exit;
+
+ obj = buffer.pointer;
+ if (obj->type != ACPI_TYPE_BUFFER ||
+ obj->buffer.length < sizeof(struct acpi_subtable_header)) {
+ goto exit;
+ }
+
+ header = (struct acpi_subtable_header *)obj->buffer.pointer;
+ if (header->type == ACPI_MADT_TYPE_LOCAL_APIC) {
+ map_lapic_id(header, acpi_id, &apic_id);
+ } else if (header->type == ACPI_MADT_TYPE_LOCAL_SAPIC) {
+ map_lsapic_id(header, acpi_id, &apic_id);
+ }
+
+exit:
+ if (buffer.pointer)
+ kfree(buffer.pointer);
+ return apic_id;
+}
+
+static int get_cpu_id(acpi_handle handle, u32 acpi_id)
{
- u16 apic_id;
int i;
+ int apic_id = -1;
- apic_id = arch_acpiid_to_apicid[acpi_id];
- if (apic_id == ARCH_BAD_APICID)
- return -1;
+ apic_id = map_mat_entry(handle, acpi_id);
+ if (apic_id == -1)
+ apic_id = map_madt_entry(acpi_id);
+ if (apic_id == -1)
+ return apic_id;
- for (i = 0; i < NR_CPUS; i++) {
- if (arch_cpu_to_apicid[i] == apic_id)
+ for_each_possible_cpu(i) {
+ if (cpu_physical_id(i) == apic_id)
return i;
}
return -1;
Driver Interface
-------------------------------------------------------------------------- */
-static int acpi_processor_get_info(struct acpi_processor *pr)
+static int acpi_processor_get_info(struct acpi_processor *pr, unsigned has_uid)
{
acpi_status status = 0;
union acpi_object object = { 0 };
struct acpi_buffer buffer = { sizeof(union acpi_object), &object };
- u8 cpu_index;
+ int cpu_index;
static int cpu0_initialized;
- ACPI_FUNCTION_TRACE("acpi_processor_get_info");
if (!pr)
- return_VALUE(-EINVAL);
+ return -EINVAL;
if (num_online_cpus() > 1)
errata.smp = TRUE;
* Check to see if we have bus mastering arbitration control. This
* is required for proper C3 usage (to maintain cache coherency).
*/
- if (acpi_fadt.V1_pm2_cnt_blk && acpi_fadt.pm2_cnt_len) {
+ if (acpi_gbl_FADT.pm2_control_block && acpi_gbl_FADT.pm2_control_length) {
pr->flags.bm_control = 1;
ACPI_DEBUG_PRINT((ACPI_DB_INFO,
"Bus mastering arbitration control present\n"));
ACPI_DEBUG_PRINT((ACPI_DB_INFO,
"No bus mastering arbitration control\n"));
- /*
- * Evalute the processor object. Note that it is common on SMP to
- * have the first (boot) processor with a valid PBLK address while
- * all others have a NULL address.
- */
- status = acpi_evaluate_object(pr->handle, NULL, NULL, &buffer);
- if (ACPI_FAILURE(status)) {
- ACPI_DEBUG_PRINT((ACPI_DB_ERROR,
- "Error evaluating processor object\n"));
- return_VALUE(-ENODEV);
- }
-
- /*
- * TBD: Synch processor ID (via LAPIC/LSAPIC structures) on SMP.
- * >>> 'acpi_get_processor_id(acpi_id, &id)' in arch/xxx/acpi.c
- */
- pr->acpi_id = object.processor.proc_id;
+ /* Check if it is a Device with HID and UID */
+ if (has_uid) {
+ unsigned long value;
+ status = acpi_evaluate_integer(pr->handle, METHOD_NAME__UID,
+ NULL, &value);
+ if (ACPI_FAILURE(status)) {
+ printk(KERN_ERR PREFIX "Evaluating processor _UID\n");
+ return -ENODEV;
+ }
+ pr->acpi_id = value;
+ } else {
+ /*
+ * Evalute the processor object. Note that it is common on SMP to
+ * have the first (boot) processor with a valid PBLK address while
+ * all others have a NULL address.
+ */
+ status = acpi_evaluate_object(pr->handle, NULL, NULL, &buffer);
+ if (ACPI_FAILURE(status)) {
+ printk(KERN_ERR PREFIX "Evaluating processor object\n");
+ return -ENODEV;
+ }
- cpu_index = convert_acpiid_to_cpu(pr->acpi_id);
+ /*
+ * TBD: Synch processor ID (via LAPIC/LSAPIC structures) on SMP.
+ * >>> 'acpi_get_processor_id(acpi_id, &id)' in arch/xxx/acpi.c
+ */
+ pr->acpi_id = object.processor.proc_id;
+ }
+ cpu_index = get_cpu_id(pr->handle, pr->acpi_id);
/* Handle UP system running SMP kernel, with no LAPIC in MADT */
- if (!cpu0_initialized && (cpu_index == 0xff) &&
+ if (!cpu0_initialized && (cpu_index == -1) &&
(num_online_cpus() == 1)) {
cpu_index = 0;
}
* less than the max # of CPUs. They should be ignored _iff
* they are physically not present.
*/
- if (cpu_index >= NR_CPUS) {
+ if (pr->id == -1) {
if (ACPI_FAILURE
(acpi_processor_hotadd_init(pr->handle, &pr->id))) {
- ACPI_DEBUG_PRINT((ACPI_DB_ERROR,
- "Error getting cpuindex for acpiid 0x%x\n",
- pr->acpi_id));
- return_VALUE(-ENODEV);
+ return -ENODEV;
}
}
if (!object.processor.pblk_address)
ACPI_DEBUG_PRINT((ACPI_DB_INFO, "No PBLK (NULL address)\n"));
else if (object.processor.pblk_length != 6)
- ACPI_DEBUG_PRINT((ACPI_DB_ERROR, "Invalid PBLK length [%d]\n",
- object.processor.pblk_length));
+ printk(KERN_ERR PREFIX "Invalid PBLK length [%d]\n",
+ object.processor.pblk_length);
else {
pr->throttling.address = object.processor.pblk_address;
- pr->throttling.duty_offset = acpi_fadt.duty_offset;
- pr->throttling.duty_width = acpi_fadt.duty_width;
+ pr->throttling.duty_offset = acpi_gbl_FADT.duty_offset;
+ pr->throttling.duty_width = acpi_gbl_FADT.duty_width;
pr->pblk = object.processor.pblk_address;
request_region(pr->throttling.address, 6, "ACPI CPU throttle");
}
-#ifdef CONFIG_CPU_FREQ
- acpi_processor_ppc_has_changed(pr);
-#endif
- acpi_processor_get_throttling_info(pr);
- acpi_processor_get_limit_info(pr);
+ /*
+ * If ACPI describes a slot number for this CPU, we can use it
+ * ensure we get the right value in the "physical id" field
+ * of /proc/cpuinfo
+ */
+ status = acpi_evaluate_object(pr->handle, "_SUN", NULL, &buffer);
+ if (ACPI_SUCCESS(status))
+ arch_fix_phys_package_id(pr->id, object.integer.value);
- return_VALUE(0);
+ return 0;
}
static void *processor_device_array[NR_CPUS];
-static int acpi_processor_start(struct acpi_device *device)
+static int __cpuinit acpi_processor_start(struct acpi_device *device)
{
int result = 0;
acpi_status status = AE_OK;
struct acpi_processor *pr;
- ACPI_FUNCTION_TRACE("acpi_processor_start");
pr = acpi_driver_data(device);
- result = acpi_processor_get_info(pr);
+ result = acpi_processor_get_info(pr, device->flags.unique_id);
if (result) {
/* Processor is physically not present */
- return_VALUE(0);
+ return 0;
}
- BUG_ON((pr->id >= NR_CPUS) || (pr->id < 0));
+ BUG_ON((pr->id >= nr_cpu_ids) || (pr->id < 0));
/*
* Buggy BIOS check
* Don't trust it blindly
*/
if (processor_device_array[pr->id] != NULL &&
- processor_device_array[pr->id] != (void *)device) {
- ACPI_DEBUG_PRINT((ACPI_DB_ERROR, "BIOS reporting wrong ACPI id"
- "for the processor\n"));
- return_VALUE(-ENODEV);
+ processor_device_array[pr->id] != device) {
+ printk(KERN_WARNING "BIOS reported wrong ACPI id "
+ "for the processor\n");
+ return -ENODEV;
}
- processor_device_array[pr->id] = (void *)device;
+ processor_device_array[pr->id] = device;
processors[pr->id] = pr;
status = acpi_install_notify_handler(pr->handle, ACPI_DEVICE_NOTIFY,
acpi_processor_notify, pr);
- if (ACPI_FAILURE(status)) {
- ACPI_DEBUG_PRINT((ACPI_DB_ERROR,
- "Error installing device notify handler\n"));
- }
/* _PDC call should be done before doing anything else (if reqd.). */
arch_acpi_processor_init_pdc(pr);
acpi_processor_set_pdc(pr);
+#ifdef CONFIG_CPU_FREQ
+ acpi_processor_ppc_has_changed(pr);
+#endif
+ acpi_processor_get_throttling_info(pr);
+ acpi_processor_get_limit_info(pr);
+
acpi_processor_power_init(pr, device);
+ pr->cdev = thermal_cooling_device_register("Processor", device,
+ &processor_cooling_ops);
+ if (IS_ERR(pr->cdev)) {
+ result = PTR_ERR(pr->cdev);
+ goto end;
+ }
+ if (pr->cdev) {
+ printk(KERN_INFO PREFIX
+ "%s is registered as cooling_device%d\n",
+ device->dev.bus_id, pr->cdev->id);
+
+ result = sysfs_create_link(&device->dev.kobj,
+ &pr->cdev->device.kobj,
+ "thermal_cooling");
+ if (result)
+ return result;
+ result = sysfs_create_link(&pr->cdev->device.kobj,
+ &device->dev.kobj,
+ "device");
+ if (result)
+ return result;
+ }
+
if (pr->flags.throttling) {
printk(KERN_INFO PREFIX "%s [%s] (supports",
acpi_device_name(device), acpi_device_bid(device));
end:
- return_VALUE(result);
+ return result;
}
static void acpi_processor_notify(acpi_handle handle, u32 event, void *data)
{
- struct acpi_processor *pr = (struct acpi_processor *)data;
+ struct acpi_processor *pr = data;
struct acpi_device *device = NULL;
-
- ACPI_FUNCTION_TRACE("acpi_processor_notify");
+ int saved;
if (!pr)
- return_VOID;
+ return;
if (acpi_bus_get_device(pr->handle, &device))
- return_VOID;
+ return;
switch (event) {
case ACPI_PROCESSOR_NOTIFY_PERFORMANCE:
+ saved = pr->performance_platform_limit;
acpi_processor_ppc_has_changed(pr);
- acpi_bus_generate_event(device, event,
+ if (saved == pr->performance_platform_limit)
+ break;
+ acpi_bus_generate_proc_event(device, event,
pr->performance_platform_limit);
+ acpi_bus_generate_netlink_event(device->pnp.device_class,
+ device->dev.bus_id, event,
+ pr->performance_platform_limit);
break;
case ACPI_PROCESSOR_NOTIFY_POWER:
acpi_processor_cst_has_changed(pr);
- acpi_bus_generate_event(device, event, 0);
+ acpi_bus_generate_proc_event(device, event, 0);
+ acpi_bus_generate_netlink_event(device->pnp.device_class,
+ device->dev.bus_id, event, 0);
break;
+ case ACPI_PROCESSOR_NOTIFY_THROTTLING:
+ acpi_processor_tstate_has_changed(pr);
+ acpi_bus_generate_proc_event(device, event, 0);
+ acpi_bus_generate_netlink_event(device->pnp.device_class,
+ device->dev.bus_id, event, 0);
default:
ACPI_DEBUG_PRINT((ACPI_DB_INFO,
"Unsupported event [0x%x]\n", event));
break;
}
- return_VOID;
+ return;
}
+static int acpi_cpu_soft_notify(struct notifier_block *nfb,
+ unsigned long action, void *hcpu)
+{
+ unsigned int cpu = (unsigned long)hcpu;
+ struct acpi_processor *pr = processors[cpu];
+
+ if (action == CPU_ONLINE && pr) {
+ acpi_processor_ppc_has_changed(pr);
+ acpi_processor_cst_has_changed(pr);
+ acpi_processor_tstate_has_changed(pr);
+ }
+ return NOTIFY_OK;
+}
+
+static struct notifier_block acpi_cpu_notifier =
+{
+ .notifier_call = acpi_cpu_soft_notify,
+};
+
static int acpi_processor_add(struct acpi_device *device)
{
struct acpi_processor *pr = NULL;
- ACPI_FUNCTION_TRACE("acpi_processor_add");
if (!device)
- return_VALUE(-EINVAL);
+ return -EINVAL;
- pr = kmalloc(sizeof(struct acpi_processor), GFP_KERNEL);
+ pr = kzalloc(sizeof(struct acpi_processor), GFP_KERNEL);
if (!pr)
- return_VALUE(-ENOMEM);
- memset(pr, 0, sizeof(struct acpi_processor));
+ return -ENOMEM;
pr->handle = device->handle;
strcpy(acpi_device_name(device), ACPI_PROCESSOR_DEVICE_NAME);
strcpy(acpi_device_class(device), ACPI_PROCESSOR_CLASS);
acpi_driver_data(device) = pr;
- return_VALUE(0);
+ return 0;
}
static int acpi_processor_remove(struct acpi_device *device, int type)
acpi_status status = AE_OK;
struct acpi_processor *pr = NULL;
- ACPI_FUNCTION_TRACE("acpi_processor_remove");
if (!device || !acpi_driver_data(device))
- return_VALUE(-EINVAL);
+ return -EINVAL;
- pr = (struct acpi_processor *)acpi_driver_data(device);
+ pr = acpi_driver_data(device);
- if (pr->id >= NR_CPUS) {
+ if (pr->id >= nr_cpu_ids) {
kfree(pr);
- return_VALUE(0);
+ return 0;
}
if (type == ACPI_BUS_REMOVAL_EJECT) {
if (acpi_processor_handle_eject(pr))
- return_VALUE(-EINVAL);
+ return -EINVAL;
}
acpi_processor_power_exit(pr, device);
status = acpi_remove_notify_handler(pr->handle, ACPI_DEVICE_NOTIFY,
acpi_processor_notify);
- if (ACPI_FAILURE(status)) {
- ACPI_DEBUG_PRINT((ACPI_DB_ERROR,
- "Error removing notify handler\n"));
- }
acpi_processor_remove_fs(device);
- processors[pr->id] = NULL;
+ if (pr->cdev) {
+ sysfs_remove_link(&device->dev.kobj, "thermal_cooling");
+ sysfs_remove_link(&pr->cdev->device.kobj, "device");
+ thermal_cooling_device_unregister(pr->cdev);
+ pr->cdev = NULL;
+ }
+ processors[pr->id] = NULL;
+ processor_device_array[pr->id] = NULL;
kfree(pr);
- return_VALUE(0);
+ return 0;
}
#ifdef CONFIG_ACPI_HOTPLUG_CPU
* Acpi processor hotplug support *
****************************************************************************/
-static int is_processor_present(acpi_handle handle);
-
static int is_processor_present(acpi_handle handle)
{
acpi_status status;
unsigned long sta = 0;
- ACPI_FUNCTION_TRACE("is_processor_present");
status = acpi_evaluate_integer(handle, "_STA", NULL, &sta);
- if (ACPI_FAILURE(status) || !(sta & ACPI_STA_PRESENT)) {
- ACPI_DEBUG_PRINT((ACPI_DB_ERROR,
- "Processor Device is not present\n"));
- return_VALUE(0);
- }
- return_VALUE(1);
+
+ if (ACPI_SUCCESS(status) && (sta & ACPI_STA_DEVICE_PRESENT))
+ return 1;
+
+ /*
+ * _STA is mandatory for a processor that supports hot plug
+ */
+ if (status == AE_NOT_FOUND)
+ ACPI_DEBUG_PRINT((ACPI_DB_INFO,
+ "Processor does not support hot plug\n"));
+ else
+ ACPI_EXCEPTION((AE_INFO, status,
+ "Processor Device is not present"));
+ return 0;
}
static
struct acpi_device *pdev;
struct acpi_processor *pr;
- ACPI_FUNCTION_TRACE("acpi_processor_device_add");
if (acpi_get_parent(handle, &phandle)) {
- return_VALUE(-ENODEV);
+ return -ENODEV;
}
if (acpi_bus_get_device(phandle, &pdev)) {
- return_VALUE(-ENODEV);
+ return -ENODEV;
}
if (acpi_bus_add(device, pdev, handle, ACPI_BUS_TYPE_PROCESSOR)) {
- return_VALUE(-ENODEV);
+ return -ENODEV;
}
acpi_bus_start(*device);
pr = acpi_driver_data(*device);
if (!pr)
- return_VALUE(-ENODEV);
+ return -ENODEV;
- if ((pr->id >= 0) && (pr->id < NR_CPUS)) {
- kobject_uevent(&(*device)->kobj, KOBJ_ONLINE);
+ if ((pr->id >= 0) && (pr->id < nr_cpu_ids)) {
+ kobject_uevent(&(*device)->dev.kobj, KOBJ_ONLINE);
}
- return_VALUE(0);
+ return 0;
}
-static void
-acpi_processor_hotplug_notify(acpi_handle handle, u32 event, void *data)
+static void __ref acpi_processor_hotplug_notify(acpi_handle handle,
+ u32 event, void *data)
{
struct acpi_processor *pr;
struct acpi_device *device = NULL;
int result;
- ACPI_FUNCTION_TRACE("acpi_processor_hotplug_notify");
switch (event) {
case ACPI_NOTIFY_BUS_CHECK:
case ACPI_NOTIFY_DEVICE_CHECK:
- printk("Processor driver received %s event\n",
+ ACPI_DEBUG_PRINT((ACPI_DB_INFO,
+ "Processor driver received %s event\n",
(event == ACPI_NOTIFY_BUS_CHECK) ?
- "ACPI_NOTIFY_BUS_CHECK" : "ACPI_NOTIFY_DEVICE_CHECK");
+ "ACPI_NOTIFY_BUS_CHECK" : "ACPI_NOTIFY_DEVICE_CHECK"));
if (!is_processor_present(handle))
break;
if (acpi_bus_get_device(handle, &device)) {
result = acpi_processor_device_add(handle, &device);
if (result)
- ACPI_DEBUG_PRINT((ACPI_DB_ERROR,
- "Unable to add the device\n"));
+ printk(KERN_ERR PREFIX
+ "Unable to add the device\n");
break;
}
pr = acpi_driver_data(device);
if (!pr) {
- ACPI_DEBUG_PRINT((ACPI_DB_ERROR,
- "Driver data is NULL\n"));
+ printk(KERN_ERR PREFIX "Driver data is NULL\n");
break;
}
- if (pr->id >= 0 && (pr->id < NR_CPUS)) {
- kobject_uevent(&device->kobj, KOBJ_OFFLINE);
+ if (pr->id >= 0 && (pr->id < nr_cpu_ids)) {
+ kobject_uevent(&device->dev.kobj, KOBJ_OFFLINE);
break;
}
result = acpi_processor_start(device);
- if ((!result) && ((pr->id >= 0) && (pr->id < NR_CPUS))) {
- kobject_uevent(&device->kobj, KOBJ_ONLINE);
+ if ((!result) && ((pr->id >= 0) && (pr->id < nr_cpu_ids))) {
+ kobject_uevent(&device->dev.kobj, KOBJ_ONLINE);
} else {
- ACPI_DEBUG_PRINT((ACPI_DB_ERROR,
- "Device [%s] failed to start\n",
- acpi_device_bid(device)));
+ printk(KERN_ERR PREFIX "Device [%s] failed to start\n",
+ acpi_device_bid(device));
}
break;
case ACPI_NOTIFY_EJECT_REQUEST:
"received ACPI_NOTIFY_EJECT_REQUEST\n"));
if (acpi_bus_get_device(handle, &device)) {
- ACPI_DEBUG_PRINT((ACPI_DB_ERROR,
- "Device don't exist, dropping EJECT\n"));
+ printk(KERN_ERR PREFIX
+ "Device don't exist, dropping EJECT\n");
break;
}
pr = acpi_driver_data(device);
if (!pr) {
- ACPI_DEBUG_PRINT((ACPI_DB_ERROR,
- "Driver data is NULL, dropping EJECT\n"));
- return_VOID;
+ printk(KERN_ERR PREFIX
+ "Driver data is NULL, dropping EJECT\n");
+ return;
}
- if ((pr->id < NR_CPUS) && (cpu_present(pr->id)))
- kobject_uevent(&device->kobj, KOBJ_OFFLINE);
+ if ((pr->id < nr_cpu_ids) && (cpu_present(pr->id)))
+ kobject_uevent(&device->dev.kobj, KOBJ_OFFLINE);
break;
default:
ACPI_DEBUG_PRINT((ACPI_DB_INFO,
break;
}
- return_VOID;
+ return;
}
static acpi_status
static acpi_status acpi_processor_hotadd_init(acpi_handle handle, int *p_cpu)
{
- ACPI_FUNCTION_TRACE("acpi_processor_hotadd_init");
if (!is_processor_present(handle)) {
- return_VALUE(AE_ERROR);
+ return AE_ERROR;
}
if (acpi_map_lsapic(handle, p_cpu))
- return_VALUE(AE_ERROR);
+ return AE_ERROR;
if (arch_register_cpu(*p_cpu)) {
acpi_unmap_lsapic(*p_cpu);
- return_VALUE(AE_ERROR);
+ return AE_ERROR;
}
- return_VALUE(AE_OK);
+ return AE_OK;
}
static int acpi_processor_handle_eject(struct acpi_processor *pr)
ACPI_UINT32_MAX,
processor_walk_namespace_cb, &action, NULL);
#endif
+ register_hotcpu_notifier(&acpi_cpu_notifier);
}
static
ACPI_UINT32_MAX,
processor_walk_namespace_cb, &action, NULL);
#endif
+ unregister_hotcpu_notifier(&acpi_cpu_notifier);
}
/*
{
int result = 0;
- ACPI_FUNCTION_TRACE("acpi_processor_init");
memset(&processors, 0, sizeof(processors));
memset(&errata, 0, sizeof(errata));
+#ifdef CONFIG_SMP
+ if (ACPI_FAILURE(acpi_get_table(ACPI_SIG_MADT, 0,
+ (struct acpi_table_header **)&madt)))
+ madt = NULL;
+#endif
+
acpi_processor_dir = proc_mkdir(ACPI_PROCESSOR_CLASS, acpi_root_dir);
if (!acpi_processor_dir)
- return_VALUE(0);
+ return -ENOMEM;
acpi_processor_dir->owner = THIS_MODULE;
+ result = cpuidle_register_driver(&acpi_idle_driver);
+ if (result < 0)
+ goto out_proc;
+
result = acpi_bus_register_driver(&acpi_processor_driver);
- if (result < 0) {
- remove_proc_entry(ACPI_PROCESSOR_CLASS, acpi_root_dir);
- return_VALUE(0);
- }
+ if (result < 0)
+ goto out_cpuidle;
acpi_processor_install_hotplug_notify();
acpi_processor_ppc_init();
- return_VALUE(0);
+ acpi_processor_throttling_init();
+
+ return 0;
+
+out_cpuidle:
+ cpuidle_unregister_driver(&acpi_idle_driver);
+
+out_proc:
+ remove_proc_entry(ACPI_PROCESSOR_CLASS, acpi_root_dir);
+
+ return result;
}
static void __exit acpi_processor_exit(void)
{
- ACPI_FUNCTION_TRACE("acpi_processor_exit");
-
acpi_processor_ppc_exit();
acpi_thermal_cpufreq_exit();
acpi_bus_unregister_driver(&acpi_processor_driver);
+ cpuidle_unregister_driver(&acpi_idle_driver);
+
remove_proc_entry(ACPI_PROCESSOR_CLASS, acpi_root_dir);
- return_VOID;
+ return;
}
module_init(acpi_processor_init);