@@ -206,12 +206,6 @@ config ACPI_IPMI
To compile this driver as a module, choose M here:
the module will be called as acpi_ipmi.
-config ACPI_HOTPLUG_CPU
- bool
- depends on EXPERIMENTAL && ACPI_PROCESSOR && HOTPLUG_CPU
- select ACPI_CONTAINER
- default y
-
config ACPI_PROCESSOR_AGGREGATOR
tristate "Processor Aggregator"
depends on ACPI_PROCESSOR
@@ -372,6 +366,11 @@ config ACPI_HOTPLUG_DRIVER
To compile this driver as a module, choose M here:
the module will be called acpihp_drv.
+config ACPI_HOTPLUG_CPU
+ bool
+ depends on ACPI_HOTPLUG && ACPI_PROCESSOR && HOTPLUG_CPU
+ default y
+
config ACPI_CONTAINER
tristate "Container and Module Devices (EXPERIMENTAL)"
depends on ACPI_HOTPLUG
@@ -56,6 +56,7 @@
#include <acpi/acpi_bus.h>
#include <acpi/acpi_drivers.h>
#include <acpi/processor.h>
+#include <acpi/acpi_hotplug.h>
#define PREFIX "ACPI: "
@@ -76,9 +77,10 @@ MODULE_LICENSE("GPL");
static int acpi_processor_add(struct acpi_device *device);
static int acpi_processor_remove(struct acpi_device *device, int type);
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);
static int acpi_processor_start(struct acpi_processor *pr);
+#ifdef CONFIG_ACPI_HOTPLUG_CPU
+static struct acpihp_dev_ops acpi_processor_hp_ops;
+#endif
static const struct acpi_device_id processor_device_ids[] = {
{ACPI_PROCESSOR_OBJECT_HID, 0},
@@ -98,13 +100,13 @@ static struct acpi_driver acpi_processor_driver = {
.add = acpi_processor_add,
.remove = acpi_processor_remove,
.notify = acpi_processor_notify,
- },
+#ifdef CONFIG_ACPI_HOTPLUG_CPU
+ .hp_ops = &acpi_processor_hp_ops,
+#endif
+ },
.drv.pm = &acpi_processor_pm,
};
-#define INSTALL_NOTIFY_HANDLER 1
-#define UNINSTALL_NOTIFY_HANDLER 2
-
static DEFINE_PER_CPU(void *, processor_device_array);
DEFINE_PER_CPU(struct acpi_processor *, processors);
@@ -314,15 +316,6 @@ static int acpi_processor_get_info(struct acpi_device *device)
pr->id = cpu_index;
/*
- * Extra Processor objects may be enumerated on MP systems with
- * less than the max # of CPUs. They should be ignored _iff
- * they are physically not present.
- */
- if (pr->id == -1) {
- if (ACPI_FAILURE(acpi_processor_hotadd_init(pr)))
- return -ENODEV;
- }
- /*
* On some boxes several processors use the same processor bus id.
* But they are located in different scope. For example:
* \_SB.SCK0.CPU0
@@ -649,20 +642,12 @@ static int acpi_processor_remove(struct acpi_device *device, int type)
return -EINVAL;
pr = acpi_driver_data(device);
- if (pr->id >= nr_cpu_ids)
- goto free;
-
- if (type == ACPI_BUS_REMOVAL_EJECT) {
- if (acpi_processor_handle_eject(pr))
- return -EINVAL;
- }
get_online_cpus();
- acpi_processor_stop(pr);
+ acpi_processor_stop(device, pr);
acpi_processor_unlink(device, pr);
put_online_cpus();
-free:
device->driver_data = NULL;
free_cpumask_var(pr->throttling.shared_cpu_map);
kfree(pr);
@@ -675,258 +660,160 @@ free:
* Acpi processor hotplug support *
****************************************************************************/
-static int is_processor_present(acpi_handle handle)
+static void acpi_processor_reset(struct acpi_device *device, struct acpi_processor *pr)
{
- acpi_status status;
- unsigned long long sta = 0;
-
-
- status = acpi_evaluate_integer(handle, "_STA", NULL, &sta);
-
- 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;
+ get_online_cpus();
+ acpi_processor_unlink(device, pr);
+ put_online_cpus();
+ arch_unregister_cpu(pr->id);
+ acpi_unmap_lsapic(pr->id);
+ pr->id = -1;
}
-static
-int acpi_processor_device_add(acpi_handle handle, struct acpi_device **device)
+static int acpi_processor_get_dev_info(struct acpi_device *device,
+ struct acpihp_dev_info *info)
{
- acpi_handle phandle;
- struct acpi_device *pdev;
-
-
- if (acpi_get_parent(handle, &phandle)) {
- return -ENODEV;
- }
+ struct acpi_processor *pr;
- if (acpi_bus_get_device(phandle, &pdev)) {
- return -ENODEV;
- }
+ if (!device || !acpi_driver_data(device))
+ return -EINVAL;
+ pr = acpi_driver_data(device);
- if (acpi_bus_add(device, pdev, handle, ACPI_BUS_TYPE_PROCESSOR)) {
- return -ENODEV;
- }
+ info->type = ACPIHP_DEV_TYPE_CPU;
+ if (pr->id >= 0)
+ info->status |= ACPIHP_DEV_STATUS_STARTED;
return 0;
}
-static void acpi_processor_hotplug_notify(acpi_handle handle,
- u32 event, void *data)
+static int acpi_processor_pre_configure(struct acpi_device *device,
+ struct acpihp_cancel_context *ctx)
{
- struct acpi_processor *pr;
- struct acpi_device *device = NULL;
- u32 ost_code = ACPI_OST_SC_NON_SPECIFIC_FAILURE; /* default */
int result;
+ struct acpi_processor *pr;
- switch (event) {
- case ACPI_NOTIFY_BUS_CHECK:
- case ACPI_NOTIFY_DEVICE_CHECK:
- 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"));
-
- if (!is_processor_present(handle))
- break;
-
- if (!acpi_bus_get_device(handle, &device))
- break;
-
- result = acpi_processor_device_add(handle, &device);
- if (result) {
- printk(KERN_ERR PREFIX "Unable to add the device\n");
- break;
- }
-
- ost_code = ACPI_OST_SC_SUCCESS;
- break;
-
- case ACPI_NOTIFY_EJECT_REQUEST:
- ACPI_DEBUG_PRINT((ACPI_DB_INFO,
- "received ACPI_NOTIFY_EJECT_REQUEST\n"));
+ if (!device || !acpi_driver_data(device))
+ return -EINVAL;
+ pr = acpi_driver_data(device);
- if (acpi_bus_get_device(handle, &device)) {
- printk(KERN_ERR PREFIX
- "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");
- break;
- }
+ /* Generate CPUID for hot-added CPUs */
+ if (pr->id == -1) {
+ result = acpi_map_lsapic(device->handle, &pr->id);
+ if (result)
+ goto out_unlock;
+ BUG_ON((pr->id >= nr_cpu_ids) || (pr->id < 0));
+ result = arch_register_cpu(pr->id);
+ if (result)
+ goto out_unmap;
- /* REVISIT: update when eject is supported */
- ost_code = ACPI_OST_SC_EJECT_NOT_SUPPORTED;
- break;
+ /*
+ * CPU got hot-plugged, but cpu_data is not initialized yet.
+ * Set flag to let acpi_cpu_soft_notify() initialize cpu_data
+ * by calling acpi_processor_start
+ */
+ pr->flags.need_hotplug_init = 1;
+ dev_info(&device->dev, "CPU %d got hotplugged\n", pr->id);
+ }
- default:
- ACPI_DEBUG_PRINT((ACPI_DB_INFO,
- "Unsupported event [0x%x]\n", event));
+ return 0;
- /* non-hotplug event; possibly handled by other handler */
- return;
- }
+out_unmap:
+ acpi_unmap_lsapic(pr->id);
+ pr->id = -1;
+out_unlock:
+ put_online_cpus();
- /* Inform firmware that the hotplug operation has completed */
- (void) acpi_evaluate_hotplug_ost(handle, event, ost_code, NULL);
- return;
+ return result;
}
-static acpi_status is_processor_device(acpi_handle handle)
+static int acpi_processor_configure(struct acpi_device *device,
+ struct acpihp_cancel_context *ctx)
{
- struct acpi_device_info *info;
- char *hid;
- acpi_status status;
-
- status = acpi_get_object_info(handle, &info);
- if (ACPI_FAILURE(status))
- return status;
-
- if (info->type == ACPI_TYPE_PROCESSOR) {
- kfree(info);
- return AE_OK; /* found a processor object */
- }
+ int result;
+ struct acpi_processor *pr;
- if (!(info->valid & ACPI_VALID_HID)) {
- kfree(info);
- return AE_ERROR;
- }
+ if (!device || !acpi_driver_data(device))
+ return -EINVAL;
+ pr = acpi_driver_data(device);
- hid = info->hardware_id.string;
- if ((hid == NULL) || strcmp(hid, ACPI_PROCESSOR_DEVICE_HID)) {
- kfree(info);
- return AE_ERROR;
- }
+ get_online_cpus();
+ result = acpi_processor_link(device, pr);
+ put_online_cpus();
- kfree(info);
- return AE_OK; /* found a processor device object */
+ return result;
}
-static acpi_status
-processor_walk_namespace_cb(acpi_handle handle,
- u32 lvl, void *context, void **rv)
+static void acpi_processor_post_configure(struct acpi_device *device,
+ enum acpihp_dev_post_cmd cmd)
{
- acpi_status status;
- int *action = context;
-
- status = is_processor_device(handle);
- if (ACPI_FAILURE(status))
- return AE_OK; /* not a processor; continue to walk */
-
- switch (*action) {
- case INSTALL_NOTIFY_HANDLER:
- acpi_install_notify_handler(handle,
- ACPI_SYSTEM_NOTIFY,
- acpi_processor_hotplug_notify,
- NULL);
- break;
- case UNINSTALL_NOTIFY_HANDLER:
- acpi_remove_notify_handler(handle,
- ACPI_SYSTEM_NOTIFY,
- acpi_processor_hotplug_notify);
- break;
- default:
- break;
- }
+ struct acpi_processor *pr;
+
+ BUG_ON(!device || !acpi_driver_data(device));
+ pr = acpi_driver_data(device);
- /* found a processor; skip walking underneath */
- return AE_CTRL_DEPTH;
+ if (cmd == ACPIHP_DEV_POST_CMD_COMMIT) {
+ if (!cpu_online(pr->id) && cpu_up(pr->id))
+ dev_warn(&device->dev,
+ "fails to online CPU%d.\n", pr->id);
+ } else if (cmd == ACPIHP_DEV_POST_CMD_ROLLBACK)
+ acpi_processor_reset(device, pr);
}
-static acpi_status acpi_processor_hotadd_init(struct acpi_processor *pr)
+static int acpi_processor_release(struct acpi_device *device,
+ struct acpihp_cancel_context *ctx)
{
- acpi_handle handle = pr->handle;
-
- if (!is_processor_present(handle)) {
- return AE_ERROR;
- }
-
- if (acpi_map_lsapic(handle, &pr->id))
- return AE_ERROR;
+ int result = 0;
+ struct acpi_processor *pr;
- if (arch_register_cpu(pr->id)) {
- acpi_unmap_lsapic(pr->id);
- return AE_ERROR;
- }
+ if (!device || !acpi_driver_data(device))
+ return -EINVAL;
+ pr = acpi_driver_data(device);
- /* CPU got hot-plugged, but cpu_data is not initialized yet
- * Set flag to delay cpu_idle/throttling initialization
- * in:
- * acpi_processor_add()
- * acpi_processor_get_info()
- * 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->flags.need_hotplug_init = 1;
+ if (cpu_online(pr->id))
+ result = cpu_down(pr->id);
- return AE_OK;
+ return result;
}
-static int acpi_processor_handle_eject(struct acpi_processor *pr)
+static void acpi_processor_post_release(struct acpi_device *device,
+ enum acpihp_dev_post_cmd cmd)
{
- if (cpu_online(pr->id))
- cpu_down(pr->id);
+ struct acpi_processor *pr;
- arch_unregister_cpu(pr->id);
- acpi_unmap_lsapic(pr->id);
- return (0);
-}
-#else
-static acpi_status acpi_processor_hotadd_init(struct acpi_processor *pr)
-{
- return AE_ERROR;
-}
-static int acpi_processor_handle_eject(struct acpi_processor *pr)
-{
- return (-EINVAL);
-}
-#endif
+ BUG_ON(!device || !acpi_driver_data(device));
+ pr = acpi_driver_data(device);
-static
-void acpi_processor_install_hotplug_notify(void)
-{
-#ifdef CONFIG_ACPI_HOTPLUG_CPU
- int action = INSTALL_NOTIFY_HANDLER;
- acpi_walk_namespace(ACPI_TYPE_ANY,
- ACPI_ROOT_OBJECT,
- ACPI_UINT32_MAX,
- processor_walk_namespace_cb, NULL, &action, NULL);
-#endif
- register_hotcpu_notifier(&acpi_cpu_notifier);
+ if (cmd == ACPIHP_DEV_POST_CMD_ROLLBACK)
+ if (!cpu_online(pr->id))
+ cpu_up(pr->id);
}
-static
-void acpi_processor_uninstall_hotplug_notify(void)
+static void acpi_processor_unconfigure(struct acpi_device *device)
{
-#ifdef CONFIG_ACPI_HOTPLUG_CPU
- int action = UNINSTALL_NOTIFY_HANDLER;
- acpi_walk_namespace(ACPI_TYPE_ANY,
- ACPI_ROOT_OBJECT,
- ACPI_UINT32_MAX,
- processor_walk_namespace_cb, NULL, &action, NULL);
-#endif
- unregister_hotcpu_notifier(&acpi_cpu_notifier);
+ struct acpi_processor *pr;
+
+ BUG_ON(!device || !acpi_driver_data(device));
+ pr = acpi_driver_data(device);
+ acpi_processor_stop(device, pr);
+ acpi_processor_reset(device, pr);
}
+static struct acpihp_dev_ops acpi_processor_hp_ops = {
+ .get_info = &acpi_processor_get_dev_info,
+ .pre_configure = &acpi_processor_pre_configure,
+ .configure = &acpi_processor_configure,
+ .post_configure = &acpi_processor_post_configure,
+ .release = &acpi_processor_release,
+ .post_release = &acpi_processor_post_release,
+ .unconfigure = &acpi_processor_unconfigure,
+};
+#endif /* CONFIG_ACPI_HOTPLUG_CPU */
+
/*
* We keep the driver loaded even when ACPI is not running.
* This is needed for the powernow-k8 driver, that works even without
* ACPI, but needs symbols from this driver
*/
-
static int __init acpi_processor_init(void)
{
int result = 0;
@@ -940,7 +827,7 @@ static int __init acpi_processor_init(void)
if (result < 0)
return result;
- acpi_processor_install_hotplug_notify();
+ register_hotcpu_notifier(&acpi_cpu_notifier);
acpi_thermal_cpufreq_init();
@@ -960,7 +847,7 @@ static void __exit acpi_processor_exit(void)
acpi_thermal_cpufreq_exit();
- acpi_processor_uninstall_hotplug_notify();
+ unregister_hotcpu_notifier(&acpi_cpu_notifier);
acpi_bus_unregister_driver(&acpi_processor_driver);