Esempio n. 1
0
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;

	ACPI_FUNCTION_TRACE("acpi_processor_notify");

	if (!pr)
		return_VOID;

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

	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;
	default:
		ACPI_DEBUG_PRINT((ACPI_DB_INFO,
				  "Unsupported event [0x%x]\n", event));
		break;
	}

	return_VOID;
}
Esempio n. 2
0
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 = per_cpu(processors, cpu);

	if (action == CPU_ONLINE && pr) {
		/* CPU got physically hotplugged and onlined the first time:
		 * Initialize missing things
		 */
		if (pr->flags.need_hotplug_init) {
			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;
		/* Normal CPU soft online event */
		} else {
			acpi_processor_ppc_has_changed(pr, 0);
			acpi_processor_hotplug(pr);
			acpi_processor_reevaluate_tstate(pr, action);
			acpi_processor_tstate_has_changed(pr);
		}
	}
	if (action == CPU_DEAD && pr) {
		/* invalidate the flag.throttling after one CPU is offline */
		acpi_processor_reevaluate_tstate(pr, action);
	}
	return NOTIFY_OK;
}
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 = per_cpu(processors, cpu);

	if (action == CPU_ONLINE && pr) {
		if (pr->flags.need_hotplug_init) {
			struct cpuidle_driver *idle_driver =
				cpuidle_get_driver();

			printk(KERN_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;
			if (idle_driver && !strcmp(idle_driver->name,
						   "intel_idle")) {
				intel_idle_cpu_init(pr->id);
			}
		
		} else {
			acpi_processor_ppc_has_changed(pr, 0);
			acpi_processor_cst_has_changed(pr);
			acpi_processor_reevaluate_tstate(pr, action);
			acpi_processor_tstate_has_changed(pr);
		}
	}
	if (action == CPU_DEAD && pr) {
		
		acpi_processor_reevaluate_tstate(pr, action);
	}
	return NOTIFY_OK;
}
Esempio n. 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;
}
Esempio n. 5
0
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 = per_cpu(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;
}
Esempio n. 6
0
static int acpi_pss_perf_init(struct acpi_processor *pr,
                              struct acpi_device *device)
{
    int result = 0;

    acpi_processor_ppc_has_changed(pr, 0);

    acpi_processor_get_throttling_info(pr);

    if (pr->flags.throttling)
        pr->flags.limit = 1;

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

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

    return result;
}
Esempio n. 7
0
static void acpi_processor_notify(acpi_handle handle, u32 event, void *data)
{
	struct acpi_device *device = data;
	struct acpi_processor *pr;
	int saved;

	if (device->handle != handle)
		return;

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

	switch (event) {
	case ACPI_PROCESSOR_NOTIFY_PERFORMANCE:
		saved = pr->performance_platform_limit;
		acpi_processor_ppc_has_changed(pr, 1);
		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,
						  dev_name(&device->dev), event,
						  pr->performance_platform_limit);
		break;
	case ACPI_PROCESSOR_NOTIFY_POWER:
		acpi_processor_cst_has_changed(pr);
		acpi_bus_generate_proc_event(device, event, 0);
		acpi_bus_generate_netlink_event(device->pnp.device_class,
						  dev_name(&device->dev), 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,
						  dev_name(&device->dev), event, 0);
		break;
	default:
		ACPI_DEBUG_PRINT((ACPI_DB_INFO,
				  "Unsupported event [0x%x]\n", event));
		break;
	}

	return;
}
Esempio n. 8
0
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 = per_cpu(processors, cpu);
    struct acpi_device *device;
    action &= ~CPU_TASKS_FROZEN;

    switch (action) {
    case CPU_ONLINE:
    case CPU_DEAD:
        break;
    default:
        return NOTIFY_DONE;
    }

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

    if (action == CPU_ONLINE) {
        /*
         * CPU got physically hotplugged and onlined for the first time:
         * Initialize missing things.
         */
        if (pr->flags.need_hotplug_init) {
            int ret;

            pr_info("Will online and init hotplugged CPU: %d\n",
                    pr->id);
            pr->flags.need_hotplug_init = 0;
            ret = __acpi_processor_start(device);
            WARN(ret, "Failed to start CPU: %d\n", pr->id);
        } else {
            /* Normal CPU soft online event. */
            acpi_processor_ppc_has_changed(pr, 0);
            acpi_processor_hotplug(pr);
            acpi_processor_reevaluate_tstate(pr, action);
            acpi_processor_tstate_has_changed(pr);
        }
    } else if (action == CPU_DEAD) {
        /* Invalidate flag.throttling after the CPU is offline. */
        acpi_processor_reevaluate_tstate(pr, action);
    }
    return NOTIFY_OK;
}
Esempio n. 9
0
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 = per_cpu(processors, cpu);

	if (action == CPU_ONLINE && pr) {
		acpi_processor_ppc_has_changed(pr, 0);
		acpi_processor_cst_has_changed(pr);
		acpi_processor_reevaluate_tstate(pr, action);
		acpi_processor_tstate_has_changed(pr);
	}
	if (action == CPU_DEAD && pr) {
		/* invalidate the flag.throttling after one CPU is offline */
		acpi_processor_reevaluate_tstate(pr, action);
	}
	return NOTIFY_OK;
}
Esempio n. 10
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;
}
Esempio n. 11
0
static int acpi_processor_get_info(struct acpi_processor *pr)
{
	acpi_status status = 0;
	union acpi_object object = { 0 };
	struct acpi_buffer buffer = { sizeof(union acpi_object), &object };
	u8 cpu_index;
	static int cpu0_initialized;

	ACPI_FUNCTION_TRACE("acpi_processor_get_info");

	if (!pr)
		return_VALUE(-EINVAL);

	if (num_online_cpus() > 1)
		errata.smp = TRUE;

	acpi_processor_errata(pr);

	/*
	 * 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) {
		pr->flags.bm_control = 1;
		ACPI_DEBUG_PRINT((ACPI_DB_INFO,
				  "Bus mastering arbitration control present\n"));
	} else
		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;

	cpu_index = convert_acpiid_to_cpu(pr->acpi_id);

	/* Handle UP system running SMP kernel, with no LAPIC in MADT */
	if (!cpu0_initialized && (cpu_index == 0xff) &&
	    (num_online_cpus() == 1)) {
		cpu_index = 0;
	}

	cpu0_initialized = 1;

	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 (cpu_index >= NR_CPUS) {
		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);
		}
	}

	ACPI_DEBUG_PRINT((ACPI_DB_INFO, "Processor [%d:%d]\n", pr->id,
			  pr->acpi_id));

	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));
	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->pblk = object.processor.pblk_address;

		/*
		 * We don't care about error returns - we just try to mark
		 * these reserved so that nobody else is confused into thinking
		 * that this region might be unused..
		 *
		 * (In particular, allocating the IO range for Cardbus)
		 */
		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);

	return_VALUE(0);
}
Esempio n. 12
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;
}
static int __cpuinit acpi_processor_start(struct acpi_device *device)
{
	int result = 0;
	struct acpi_processor *pr;
	struct sys_device *sysdev;

	pr = acpi_driver_data(device);

	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");
		return -ENODEV;
	}
	per_cpu(processor_device_array, pr->id) = device;

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

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

	sysdev = get_cpu_sysdev(pr->id);
	if (sysfs_create_link(&device->dev.kobj, &sysdev->kobj, "sysdev"))
		return -EFAULT;

	/* _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;
	}

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

	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;
}
Esempio n. 14
0
static int __cpuinit acpi_processor_start(struct acpi_device *device)
{
	int result = 0;
	acpi_status status = AE_OK;
	struct acpi_processor *pr;


	pr = acpi_driver_data(device);

	result = acpi_processor_get_info(pr, device->flags.unique_id);
	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 (processor_device_array[pr->id] != NULL &&
	    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] = device;

	processors[pr->id] = pr;

	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);
#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);

	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;
}
Esempio n. 15
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;
}
Esempio n. 16
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;
}