Example #1
0
static int acpi_processor_stop(struct device *dev)
{
	struct acpi_device *device;
	struct acpi_processor *pr;

	if (acpi_bus_get_device(ACPI_HANDLE(dev), &device))
		return 0;

	acpi_remove_notify_handler(device->handle, ACPI_DEVICE_NOTIFY,
				   acpi_processor_notify);

	pr = acpi_driver_data(device);
	if (!pr)
		return 0;

	acpi_processor_power_exit(pr);

	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;
	}
	return 0;
}
Example #2
0
static int __acpi_processor_start(struct acpi_device *device)
{
    struct acpi_processor *pr = acpi_driver_data(device);
    acpi_status status;
    int result = 0;

    if (!pr)
        return -ENODEV;

    if (pr->flags.need_hotplug_init)
        return 0;

    result = acpi_cppc_processor_probe(pr);
    if (result)
        return -ENODEV;

    if (!cpuidle_get_driver() || cpuidle_get_driver() == &acpi_idle_driver)
        acpi_processor_power_init(pr);

    result = acpi_pss_perf_init(pr, device);
    if (result)
        goto err_power_exit;

    status = acpi_install_notify_handler(device->handle, ACPI_DEVICE_NOTIFY,
                                         acpi_processor_notify, device);
    if (ACPI_SUCCESS(status))
        return 0;

err_power_exit:
    acpi_processor_power_exit(pr);
    return result;
}
Example #3
0
static int acpi_processor_remove(struct acpi_device *device, int type)
{
	acpi_status status = AE_OK;
	struct acpi_processor *pr = NULL;


	if (!device || !acpi_driver_data(device))
		return -EINVAL;

	pr = acpi_driver_data(device);

	if (pr->id >= NR_CPUS) {
		kfree(pr);
		return 0;
	}

	if (type == ACPI_BUS_REMOVAL_EJECT) {
		if (acpi_processor_handle_eject(pr))
			return -EINVAL;
	}

	acpi_processor_power_exit(pr, device);

	status = acpi_remove_notify_handler(pr->handle, ACPI_DEVICE_NOTIFY,
					    acpi_processor_notify);

	acpi_processor_remove_fs(device);

	processors[pr->id] = NULL;

	kfree(pr);

	return 0;
}
Example #4
0
/*
 * acpi_processor_start() is called by the cpu_hotplug_notifier func:
 * acpi_cpu_soft_notify(). Getting it __cpuinit{data} is difficult, the
 * root cause seem to be that acpi_processor_uninstall_hotplug_notify()
 * is in the module_exit (__exit) func. Allowing acpi_processor_start()
 * to not be in __cpuinit section, but being called from __cpuinit funcs
 * via __ref looks like the right thing to do here.
 */
static __ref int acpi_processor_start(struct acpi_processor *pr)
{
	struct acpi_device *device = per_cpu(processor_device_array, pr->id);
	int result = 0;

#ifdef CONFIG_CPU_FREQ
	acpi_processor_ppc_has_changed(pr, 0);
	acpi_processor_load_module(pr);
#endif
	acpi_processor_get_throttling_info(pr);
	acpi_processor_get_limit_info(pr);

	if (!cpuidle_get_driver() || cpuidle_get_driver() == &acpi_idle_driver)
		acpi_processor_power_init(pr);

	pr->cdev = thermal_cooling_device_register("Processor", device,
						   &processor_cooling_ops);
	if (IS_ERR(pr->cdev)) {
		result = PTR_ERR(pr->cdev);
		goto err_power_exit;
	}

	dev_dbg(&device->dev, "registered as cooling_device%d\n",
		pr->cdev->id);

	result = sysfs_create_link(&device->dev.kobj,
				   &pr->cdev->device.kobj,
				   "thermal_cooling");
	if (result) {
		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) {
		dev_err(&pr->cdev->device,
			"Failed to create sysfs link 'device'\n");
		goto err_remove_sysfs_thermal;
	}

	return 0;

err_remove_sysfs_thermal:
	sysfs_remove_link(&device->dev.kobj, "thermal_cooling");
err_thermal_unregister:
	thermal_cooling_device_unregister(pr->cdev);
err_power_exit:
	acpi_processor_power_exit(pr);

	return result;
}
Example #5
0
static int acpi_processor_remove(struct acpi_device *device, int type)
{
	acpi_status status = AE_OK;
	struct acpi_processor *pr = NULL;


	if (!device || !acpi_driver_data(device))
		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;
	}

	acpi_processor_power_exit(pr, device);

	status = acpi_remove_notify_handler(pr->handle, ACPI_DEVICE_NOTIFY,
					    acpi_processor_notify);

	sysfs_remove_link(&device->dev.kobj, "sysdev");

	acpi_processor_remove_fs(device);

	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;
	}

	per_cpu(processors, pr->id) = NULL;
	per_cpu(processor_device_array, pr->id) = NULL;

free:
	free_cpumask_var(pr->throttling.shared_cpu_map);
	kfree(pr);

	return 0;
}
Example #6
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);

	pr = (struct acpi_processor *)acpi_driver_data(device);

	if (pr->id >= NR_CPUS) {
		kfree(pr);
		return_VALUE(0);
	}

	if (type == ACPI_BUS_REMOVAL_EJECT) {
		if (acpi_processor_handle_eject(pr))
			return_VALUE(-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;

	kfree(pr);

	return_VALUE(0);
}
Example #7
0
static int acpi_processor_stop(struct device *dev)
{
    struct acpi_device *device = ACPI_COMPANION(dev);
    struct acpi_processor *pr;

    if (!device)
        return 0;

    acpi_remove_notify_handler(device->handle, ACPI_DEVICE_NOTIFY,
                               acpi_processor_notify);

    pr = acpi_driver_data(device);
    if (!pr)
        return 0;
    acpi_processor_power_exit(pr);

    acpi_pss_perf_exit(pr, device);

    acpi_cppc_processor_exit(pr);

    return 0;
}
Example #8
0
static int acpi_processor_remove(struct acpi_device *device)
{
	struct acpi_processor *pr = NULL;


	if (!device || !acpi_driver_data(device))
		return -EINVAL;

	pr = acpi_driver_data(device);

	if (pr->id >= nr_cpu_ids)
		goto free;

	if (device->removal_type == ACPI_BUS_REMOVAL_EJECT) {
		if (acpi_processor_handle_eject(pr))
			return -EINVAL;
	}

	acpi_processor_power_exit(pr);

	sysfs_remove_link(&device->dev.kobj, "sysdev");

	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;
	}

	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);
	kfree(pr);

	return 0;
}
Example #9
0
static int __cpuinit acpi_processor_add(struct acpi_device *device)
{
	struct acpi_processor *pr = NULL;
	int result = 0;
	struct sys_device *sysdev;

	pr = kzalloc(sizeof(struct acpi_processor), GFP_KERNEL);
	if (!pr)
		return -ENOMEM;

	if (!zalloc_cpumask_var(&pr->throttling.shared_cpu_map, GFP_KERNEL)) {
		kfree(pr);
		return -ENOMEM;
	}

	pr->handle = device->handle;
	strcpy(acpi_device_name(device), ACPI_PROCESSOR_DEVICE_NAME);
	strcpy(acpi_device_class(device), ACPI_PROCESSOR_CLASS);
	device->driver_data = pr;

	result = acpi_processor_get_info(device);
	if (result) {
		/* Processor is physically not present */
		return 0;
	}

	BUG_ON((pr->id >= nr_cpu_ids) || (pr->id < 0));

	/*
	 * Buggy BIOS check
	 * ACPI id of processors can be reported wrongly by the BIOS.
	 * Don't trust it blindly
	 */
	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");
		result = -ENODEV;
		goto err_free_cpumask;
	}
	per_cpu(processor_device_array, pr->id) = device;

	per_cpu(processors, pr->id) = pr;

	result = acpi_processor_add_fs(device);
	if (result)
		goto err_free_cpumask;

	sysdev = get_cpu_sysdev(pr->id);
	if (sysfs_create_link(&device->dev.kobj, &sysdev->kobj, "sysdev")) {
		result = -EFAULT;
		goto err_remove_fs;
	}

	/* _PDC call should be done before doing anything else (if reqd.). */
	arch_acpi_processor_init_pdc(pr);
	acpi_processor_set_pdc(pr);
	arch_acpi_processor_cleanup_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 err_power_exit;
	}

	dev_info(&device->dev, "registered as cooling_device%d\n",
		 pr->cdev->id);

	result = sysfs_create_link(&device->dev.kobj,
				   &pr->cdev->device.kobj,
				   "thermal_cooling");
	if (result) {
		printk(KERN_ERR PREFIX "Create sysfs link\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");
		goto err_remove_sysfs;
	}

	return 0;

err_remove_sysfs:
	sysfs_remove_link(&device->dev.kobj, "thermal_cooling");
err_thermal_unregister:
	thermal_cooling_device_unregister(pr->cdev);
err_power_exit:
	acpi_processor_power_exit(pr, device);
err_remove_fs:
	acpi_processor_remove_fs(device);
err_free_cpumask:
	free_cpumask_var(pr->throttling.shared_cpu_map);

	return result;
}
Example #10
0
static int __acpi_processor_start(struct acpi_device *device)
{
	struct acpi_processor *pr = acpi_driver_data(device);
	acpi_status status;
	int result = 0;

	if (!pr)
		return -ENODEV;

	if (pr->flags.need_hotplug_init)
		return 0;

#ifdef CONFIG_CPU_FREQ
	acpi_processor_ppc_has_changed(pr, 0);
	acpi_processor_load_module(pr);
#endif
	acpi_processor_get_throttling_info(pr);
	acpi_processor_get_limit_info(pr);

	if (!cpuidle_get_driver() || cpuidle_get_driver() == &acpi_idle_driver)
		acpi_processor_power_init(pr);

	pr->cdev = thermal_cooling_device_register("Processor", device,
						   &processor_cooling_ops);
	if (IS_ERR(pr->cdev)) {
		result = PTR_ERR(pr->cdev);
		goto err_power_exit;
	}

	dev_dbg(&device->dev, "registered as cooling_device%d\n",
		pr->cdev->id);

	result = sysfs_create_link(&device->dev.kobj,
				   &pr->cdev->device.kobj,
				   "thermal_cooling");
	if (result) {
		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) {
		dev_err(&pr->cdev->device,
			"Failed to create sysfs link 'device'\n");
		goto err_remove_sysfs_thermal;
	}

	status = acpi_install_notify_handler(device->handle, ACPI_DEVICE_NOTIFY,
					     acpi_processor_notify, device);
	if (ACPI_SUCCESS(status))
		return 0;

	sysfs_remove_link(&pr->cdev->device.kobj, "device");
 err_remove_sysfs_thermal:
	sysfs_remove_link(&device->dev.kobj, "thermal_cooling");
 err_thermal_unregister:
	thermal_cooling_device_unregister(pr->cdev);
 err_power_exit:
	acpi_processor_power_exit(pr);
	return result;
}
Example #11
0
static int __cpuinit acpi_processor_add(struct acpi_device *device)
{
	struct acpi_processor *pr = NULL;
	int result = 0;
	struct sys_device *sysdev;

	pr = kzalloc(sizeof(struct acpi_processor), GFP_KERNEL);
	if (!pr)
		return -ENOMEM;

	if (!zalloc_cpumask_var(&pr->throttling.shared_cpu_map, GFP_KERNEL)) {
		kfree(pr);
		return -ENOMEM;
	}

	pr->handle = device->handle;
	strcpy(acpi_device_name(device), ACPI_PROCESSOR_DEVICE_NAME);
	strcpy(acpi_device_class(device), ACPI_PROCESSOR_CLASS);
	device->driver_data = pr;

 	processor_extcntl_init();

	result = acpi_processor_get_info(device);
	if (result ||
	    ((pr->id == -1) && !processor_cntl_external())) {
		/* Processor is physically not present */
		return 0;
	}

	BUG_ON(!processor_cntl_external() &&
	       ((pr->id >= nr_cpu_ids) || (pr->id < 0)));

	/*
	 * Buggy BIOS check
	 * ACPI id of processors can be reported wrongly by the BIOS.
	 * Don't trust it blindly
	 */
#ifndef CONFIG_XEN
	if (per_cpu(processor_device_array, pr->id) != NULL &&
	    per_cpu(processor_device_array, pr->id) != device) {
#else
	BUG_ON(pr->acpi_id >= NR_ACPI_CPUS);
	if (processor_device_array[pr->acpi_id] != NULL &&
	    processor_device_array[pr->acpi_id] != device) {
#endif
		printk(KERN_WARNING "BIOS reported wrong ACPI id "
			"for the processor\n");
		result = -ENODEV;
		goto err_free_cpumask;
	}
#ifndef CONFIG_XEN
	per_cpu(processor_device_array, pr->id) = device;

	per_cpu(processors, pr->id) = pr;
#else
	processor_device_array[pr->acpi_id] = device;
	if (pr->id != -1)
		per_cpu(processors, pr->id) = pr;
#endif

	result = acpi_processor_add_fs(device);
	if (result)
		goto err_free_cpumask;

	if (pr->id != -1) {
		sysdev = get_cpu_sysdev(pr->id);
		if (sysfs_create_link(&device->dev.kobj, &sysdev->kobj, "sysdev")) {
			result = -EFAULT;
			goto err_remove_fs;
		}
	}

	/* _PDC call should be done before doing anything else (if reqd.). */
	arch_acpi_processor_init_pdc(pr);
	acpi_processor_set_pdc(pr);
	arch_acpi_processor_cleanup_pdc(pr);

#if defined(CONFIG_CPU_FREQ) || defined(CONFIG_PROCESSOR_EXTERNAL_CONTROL)
	acpi_processor_ppc_has_changed(pr);
#endif

	/*
	 * pr->id may equal to -1 while processor_cntl_external enabled.
	 * throttle and thermal module don't support this case.
	 * Tx only works when dom0 vcpu == pcpu num by far, as we give
	 * control to dom0.
	 */
	if (pr->id != -1) {
		acpi_processor_get_throttling_info(pr);
		acpi_processor_get_limit_info(pr);
	}

	acpi_processor_power_init(pr, device);

	result = processor_extcntl_prepare(pr);
	if (result)
		goto err_power_exit;

	pr->cdev = thermal_cooling_device_register("Processor", device,
						&processor_cooling_ops);
	if (IS_ERR(pr->cdev)) {
		result = PTR_ERR(pr->cdev);
		goto err_power_exit;
	}

	dev_info(&device->dev, "registered as cooling_device%d\n",
		 pr->cdev->id);

	result = sysfs_create_link(&device->dev.kobj,
				   &pr->cdev->device.kobj,
				   "thermal_cooling");
	if (result) {
		printk(KERN_ERR PREFIX "Create sysfs link\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");
		goto err_remove_sysfs;
	}

	return 0;

err_remove_sysfs:
	sysfs_remove_link(&device->dev.kobj, "thermal_cooling");
err_thermal_unregister:
	thermal_cooling_device_unregister(pr->cdev);
err_power_exit:
	acpi_processor_power_exit(pr, device);
err_remove_fs:
	acpi_processor_remove_fs(device);
err_free_cpumask:
	free_cpumask_var(pr->throttling.shared_cpu_map);

	return result;
}

static int acpi_processor_remove(struct acpi_device *device, int type)
{
	struct acpi_processor *pr = NULL;


	if (!device || !acpi_driver_data(device))
		return -EINVAL;

	pr = acpi_driver_data(device);

	if (!processor_cntl_external() && pr->id >= nr_cpu_ids)
		goto free;

	if (type == ACPI_BUS_REMOVAL_EJECT) {
		if (acpi_processor_handle_eject(pr))
			return -EINVAL;
	}

	acpi_processor_power_exit(pr, device);

	if (pr->id != -1)
		sysfs_remove_link(&device->dev.kobj, "sysdev");

	acpi_processor_remove_fs(device);

	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;
	}

#ifndef CONFIG_XEN
	per_cpu(processors, pr->id) = NULL;
	per_cpu(processor_device_array, pr->id) = NULL;
#else
	if (pr->id != -1)
		per_cpu(processors, pr->id) = NULL;
	processor_device_array[pr->acpi_id] = NULL;
#endif

free:
	free_cpumask_var(pr->throttling.shared_cpu_map);
	kfree(pr);

	return 0;
}

#ifdef CONFIG_ACPI_HOTPLUG_CPU
/****************************************************************************
 * 	Acpi processor hotplug support 				       	    *
 ****************************************************************************/

static int is_processor_present(acpi_handle handle)
{
	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;
}
Example #12
0
static int acpi_processor_start(struct acpi_device *device)
{
	int result = 0;
	acpi_status status = AE_OK;
	struct acpi_processor *pr;

	processor_extcntl_init();

	pr = acpi_driver_data(device);

	result = acpi_processor_get_info(pr);
	if (result || 
	    ((pr->id == -1) && !processor_cntl_external())) {
		/* Processor is physically not present */
		return 0;
	}

	BUG_ON(!processor_cntl_external() &&
	       ((pr->id >= NR_CPUS) || (pr->id < 0)));

	/*
	 * Buggy BIOS check
	 * ACPI id of processors can be reported wrongly by the BIOS.
	 * Don't trust it blindly
	 */
#ifdef CONFIG_XEN
	BUG_ON(pr->acpi_id >= NR_ACPI_CPUS);
	if (processor_device_array[pr->acpi_id] != NULL &&
	    processor_device_array[pr->acpi_id] != (void *)device) {
#else
	if (processor_device_array[pr->id] != NULL &&
	    processor_device_array[pr->id] != (void *)device) {
#endif /* CONFIG_XEN */
		printk(KERN_WARNING "BIOS reported wrong ACPI id"
			"for the processor\n");
		return -ENODEV;
	}
#ifdef CONFIG_XEN
	processor_device_array[pr->acpi_id] = (void *)device;
	if (pr->id != -1)
		processors[pr->id] = pr;
#else
	processor_device_array[pr->id] = (void *)device;

	processors[pr->id] = pr;
#endif /* CONFIG_XEN */

	result = acpi_processor_add_fs(device);
	if (result)
		goto end;

	status = acpi_install_notify_handler(pr->handle, ACPI_DEVICE_NOTIFY,
					     acpi_processor_notify, pr);

	/* _PDC call should be done before doing anything else (if reqd.). */
	arch_acpi_processor_init_pdc(pr);
	acpi_processor_set_pdc(pr);

#if defined(CONFIG_CPU_FREQ) || defined(CONFIG_PROCESSOR_EXTERNAL_CONTROL)
	acpi_processor_ppc_has_changed(pr);
#endif

	/* 
	 * pr->id may equal to -1 while processor_cntl_external enabled.
	 * throttle and thermal module don't support this case.
	 * Tx only works when dom0 vcpu == pcpu num by far, as we give 
	 * control to dom0.
	 */
	if (pr->id != -1) {
		acpi_processor_get_throttling_info(pr);
		acpi_processor_get_limit_info(pr);
	}

	acpi_processor_power_init(pr, device);

	result = processor_extcntl_prepare(pr);
	if (result)
		goto end;

	if (pr->flags.throttling) {
		printk(KERN_INFO PREFIX "%s [%s] (supports",
		       acpi_device_name(device), acpi_device_bid(device));
		printk(" %d throttling states", pr->throttling.state_count);
		printk(")\n");
	}

      end:

	return result;
}

static void acpi_processor_notify(acpi_handle handle, u32 event, void *data)
{
	struct acpi_processor *pr = (struct acpi_processor *)data;
	struct acpi_device *device = NULL;


	if (!pr)
		return;

	if (acpi_bus_get_device(pr->handle, &device))
		return;

	switch (event) {
	case ACPI_PROCESSOR_NOTIFY_PERFORMANCE:
		acpi_processor_ppc_has_changed(pr);
		acpi_bus_generate_event(device, event,
					pr->performance_platform_limit);
		break;
	case ACPI_PROCESSOR_NOTIFY_POWER:
		acpi_processor_cst_has_changed(pr);
		acpi_bus_generate_event(device, event, 0);
		break;
	case ACPI_PROCESSOR_NOTIFY_THROTTLING:
		acpi_processor_tstate_has_changed(pr);
		acpi_bus_generate_event(device, event, 0);
		break;
	default:
		ACPI_DEBUG_PRINT((ACPI_DB_INFO,
				  "Unsupported event [0x%x]\n", event));
		break;
	}

	return;
}

static int acpi_processor_add(struct acpi_device *device)
{
	struct acpi_processor *pr = NULL;


	if (!device)
		return -EINVAL;

	pr = kmalloc(sizeof(struct acpi_processor), GFP_KERNEL);
	if (!pr)
		return -ENOMEM;
	memset(pr, 0, sizeof(struct acpi_processor));

	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 0;
}

static int acpi_processor_remove(struct acpi_device *device, int type)
{
	acpi_status status = AE_OK;
	struct acpi_processor *pr = NULL;


	if (!device || !acpi_driver_data(device))
		return -EINVAL;

	pr = (struct acpi_processor *)acpi_driver_data(device);

	if (!processor_cntl_external() && pr->id >= NR_CPUS) {
		kfree(pr);
		return 0;
	}

	if (type == ACPI_BUS_REMOVAL_EJECT) {
		if (acpi_processor_handle_eject(pr))
			return -EINVAL;
	}

	acpi_processor_power_exit(pr, device);

	status = acpi_remove_notify_handler(pr->handle, ACPI_DEVICE_NOTIFY,
					    acpi_processor_notify);

	acpi_processor_remove_fs(device);

#ifdef CONFIG_XEN
	if (pr->id != -1)
		processors[pr->id] = NULL;
#else
	processors[pr->id] = NULL;
#endif /* CONFIG_XEN */


	kfree(pr);

	return 0;
}