diff options
Diffstat (limited to 'drivers/acpi/processor_driver.c')
| -rw-r--r-- | drivers/acpi/processor_driver.c | 128 |
1 files changed, 76 insertions, 52 deletions
diff --git a/drivers/acpi/processor_driver.c b/drivers/acpi/processor_driver.c index bd4e5dca3ff7..bec717ffd25f 100644 --- a/drivers/acpi/processor_driver.c +++ b/drivers/acpi/processor_driver.c @@ -44,6 +44,8 @@ #include <linux/moduleparam.h> #include <linux/cpuidle.h> #include <linux/slab.h> +#include <linux/acpi.h> +#include <linux/memory_hotplug.h> #include <asm/io.h> #include <asm/cpu.h> @@ -80,7 +82,7 @@ MODULE_DESCRIPTION("ACPI Processor Driver"); MODULE_LICENSE("GPL"); static int acpi_processor_add(struct acpi_device *device); -static int acpi_processor_remove(struct acpi_device *device, int type); +static int acpi_processor_remove(struct acpi_device *device); static void acpi_processor_notify(struct acpi_device *device, u32 event); static acpi_status acpi_processor_hotadd_init(struct acpi_processor *pr); static int acpi_processor_handle_eject(struct acpi_processor *pr); @@ -282,7 +284,9 @@ static int acpi_processor_get_info(struct acpi_device *device) /* Declared with "Processor" statement; match ProcessorID */ status = acpi_evaluate_object(pr->handle, NULL, NULL, &buffer); if (ACPI_FAILURE(status)) { - printk(KERN_ERR PREFIX "Evaluating processor object\n"); + dev_err(&device->dev, + "Failed to evaluate processor object (0x%x)\n", + status); return -ENODEV; } @@ -301,8 +305,9 @@ static int acpi_processor_get_info(struct acpi_device *device) status = acpi_evaluate_integer(pr->handle, METHOD_NAME__UID, NULL, &value); if (ACPI_FAILURE(status)) { - printk(KERN_ERR PREFIX - "Evaluating processor _UID [%#x]\n", status); + dev_err(&device->dev, + "Failed to evaluate processor _UID (0x%x)\n", + status); return -ENODEV; } device_declaration = 1; @@ -345,7 +350,7 @@ static int acpi_processor_get_info(struct acpi_device *device) if (!object.processor.pblk_address) ACPI_DEBUG_PRINT((ACPI_DB_INFO, "No PBLK (NULL address)\n")); else if (object.processor.pblk_length != 6) - printk(KERN_ERR PREFIX "Invalid PBLK length [%d]\n", + dev_err(&device->dev, "Invalid PBLK length [%d]\n", object.processor.pblk_length); else { pr->throttling.address = object.processor.pblk_address; @@ -430,8 +435,8 @@ static int acpi_cpu_soft_notify(struct notifier_block *nfb, * Initialize missing things */ if (pr->flags.need_hotplug_init) { - printk(KERN_INFO "Will online and init hotplugged " - "CPU: %d\n", pr->id); + pr_info("Will online and init hotplugged CPU: %d\n", + pr->id); WARN(acpi_processor_start(pr), "Failed to start CPU:" " %d\n", pr->id); pr->flags.need_hotplug_init = 0; @@ -492,14 +497,16 @@ static __ref int acpi_processor_start(struct acpi_processor *pr) &pr->cdev->device.kobj, "thermal_cooling"); if (result) { - printk(KERN_ERR PREFIX "Create sysfs link\n"); + dev_err(&device->dev, + "Failed to create sysfs link 'thermal_cooling'\n"); goto err_thermal_unregister; } result = sysfs_create_link(&pr->cdev->device.kobj, &device->dev.kobj, "device"); if (result) { - printk(KERN_ERR PREFIX "Create sysfs link\n"); + dev_err(&pr->cdev->device, + "Failed to create sysfs link 'device'\n"); goto err_remove_sysfs_thermal; } @@ -552,7 +559,7 @@ static int __cpuinit acpi_processor_add(struct acpi_device *device) return 0; #endif - BUG_ON((pr->id >= nr_cpu_ids) || (pr->id < 0)); + BUG_ON(pr->id >= nr_cpu_ids); /* * Buggy BIOS check @@ -561,8 +568,9 @@ static int __cpuinit acpi_processor_add(struct acpi_device *device) */ if (per_cpu(processor_device_array, pr->id) != NULL && per_cpu(processor_device_array, pr->id) != device) { - printk(KERN_WARNING "BIOS reported wrong ACPI id " - "for the processor\n"); + dev_warn(&device->dev, + "BIOS reported wrong ACPI id %d for the processor\n", + pr->id); result = -ENODEV; goto err_free_cpumask; } @@ -603,7 +611,7 @@ err_free_pr: return result; } -static int acpi_processor_remove(struct acpi_device *device, int type) +static int acpi_processor_remove(struct acpi_device *device) { struct acpi_processor *pr = NULL; @@ -616,7 +624,7 @@ static int acpi_processor_remove(struct acpi_device *device, int type) if (pr->id >= nr_cpu_ids) goto free; - if (type == ACPI_BUS_REMOVAL_EJECT) { + if (device->removal_type == ACPI_BUS_REMOVAL_EJECT) { if (acpi_processor_handle_eject(pr)) return -EINVAL; } @@ -634,6 +642,7 @@ static int acpi_processor_remove(struct acpi_device *device, int type) per_cpu(processors, pr->id) = NULL; per_cpu(processor_device_array, pr->id) = NULL; + try_offline_node(cpu_to_node(pr->id)); free: free_cpumask_var(pr->throttling.shared_cpu_map); @@ -670,36 +679,17 @@ static int is_processor_present(acpi_handle handle) return 0; } -static -int acpi_processor_device_add(acpi_handle handle, struct acpi_device **device) -{ - acpi_handle phandle; - struct acpi_device *pdev; - - - if (acpi_get_parent(handle, &phandle)) { - return -ENODEV; - } - - if (acpi_bus_get_device(phandle, &pdev)) { - return -ENODEV; - } - - if (acpi_bus_add(device, pdev, handle, ACPI_BUS_TYPE_PROCESSOR)) { - return -ENODEV; - } - - return 0; -} - static void acpi_processor_hotplug_notify(acpi_handle handle, u32 event, void *data) { - struct acpi_processor *pr; struct acpi_device *device = NULL; + struct acpi_eject_event *ej_event = NULL; u32 ost_code = ACPI_OST_SC_NON_SPECIFIC_FAILURE; /* default */ + acpi_status status; int result; + acpi_scan_lock_acquire(); + switch (event) { case ACPI_NOTIFY_BUS_CHECK: case ACPI_NOTIFY_DEVICE_CHECK: @@ -714,12 +704,16 @@ static void acpi_processor_hotplug_notify(acpi_handle handle, if (!acpi_bus_get_device(handle, &device)) break; - result = acpi_processor_device_add(handle, &device); + result = acpi_bus_scan(handle); if (result) { - printk(KERN_ERR PREFIX "Unable to add the device\n"); + acpi_handle_err(handle, "Unable to add the device\n"); + break; + } + result = acpi_bus_get_device(handle, &device); + if (result) { + acpi_handle_err(handle, "Missing device object\n"); break; } - ost_code = ACPI_OST_SC_SUCCESS; break; @@ -728,32 +722,48 @@ static void acpi_processor_hotplug_notify(acpi_handle handle, "received ACPI_NOTIFY_EJECT_REQUEST\n")); if (acpi_bus_get_device(handle, &device)) { - printk(KERN_ERR PREFIX - "Device don't exist, dropping EJECT\n"); + acpi_handle_err(handle, + "Device don't exist, dropping EJECT\n"); break; } - pr = acpi_driver_data(device); - if (!pr) { - printk(KERN_ERR PREFIX - "Driver data is NULL, dropping EJECT\n"); + if (!acpi_driver_data(device)) { + acpi_handle_err(handle, + "Driver data is NULL, dropping EJECT\n"); break; } - /* REVISIT: update when eject is supported */ - ost_code = ACPI_OST_SC_EJECT_NOT_SUPPORTED; - break; + ej_event = kmalloc(sizeof(*ej_event), GFP_KERNEL); + if (!ej_event) { + acpi_handle_err(handle, "No memory, dropping EJECT\n"); + break; + } + + get_device(&device->dev); + ej_event->device = device; + ej_event->event = ACPI_NOTIFY_EJECT_REQUEST; + /* The eject is carried out asynchronously. */ + status = acpi_os_hotplug_execute(acpi_bus_hot_remove_device, + ej_event); + if (ACPI_FAILURE(status)) { + put_device(&device->dev); + kfree(ej_event); + break; + } + goto out; default: ACPI_DEBUG_PRINT((ACPI_DB_INFO, "Unsupported event [0x%x]\n", event)); /* non-hotplug event; possibly handled by other handler */ - return; + goto out; } /* Inform firmware that the hotplug operation has completed */ (void) acpi_evaluate_hotplug_ost(handle, event, ost_code, NULL); - return; + + out: + acpi_scan_lock_release(); } static acpi_status is_processor_device(acpi_handle handle) @@ -841,7 +851,7 @@ static acpi_status acpi_processor_hotadd_init(struct acpi_processor *pr) * and do it when the CPU gets online the first time * TBD: Cleanup above functions and try to do this more elegant. */ - printk(KERN_INFO "CPU %d got hotplugged\n", pr->id); + pr_info("CPU %d got hotplugged\n", pr->id); pr->flags.need_hotplug_init = 1; return AE_OK; @@ -852,8 +862,22 @@ static int acpi_processor_handle_eject(struct acpi_processor *pr) if (cpu_online(pr->id)) cpu_down(pr->id); + get_online_cpus(); + /* + * The cpu might become online again at this point. So we check whether + * the cpu has been onlined or not. If the cpu became online, it means + * that someone wants to use the cpu. So acpi_processor_handle_eject() + * returns -EAGAIN. + */ + if (unlikely(cpu_online(pr->id))) { + put_online_cpus(); + pr_warn("Failed to remove CPU %d, because other task " + "brought the CPU back online\n", pr->id); + return -EAGAIN; + } arch_unregister_cpu(pr->id); acpi_unmap_lsapic(pr->id); + put_online_cpus(); return (0); } #else |
