Linux內核中ACPI電源管理部分解析

ACPI包括很多功能,電源管理是其功能之一,具體的ACPI的介紹可以參考ACPI的技術文檔。

Linux中利用模塊機制,實現ACPI對電源的管理:

static struct cpufreq_driver acpi_cpufreq_driver = {
	.verify		= acpi_cpufreq_verify,
	.target		= acpi_cpufreq_target,
	.bios_limit	= acpi_processor_get_bios_limit,
	.init		= acpi_cpufreq_cpu_init,
	.exit		= acpi_cpufreq_cpu_exit,
	.resume		= acpi_cpufreq_resume,
	.name		= "acpi-cpufreq",
	.owner		= THIS_MODULE,
	.attr		= acpi_cpufreq_attr,
};

模塊的初始化工作由以下代碼完成:

static int __init acpi_cpufreq_init(void)
{
	int ret;

	if (acpi_disabled)
		return 0;

	pr_debug("acpi_cpufreq_init\n");

	ret = acpi_cpufreq_early_init();
	if (ret)
		return ret;

	ret = cpufreq_register_driver(&acpi_cpufreq_driver);//核心
	if (ret)
		free_acpi_perf_data();

	return ret;
}



主要是cpufreq_register_driver:

/*********************************************************************
 *               REGISTER / UNREGISTER CPUFREQ DRIVER                *
 *********************************************************************/

/**
 * cpufreq_register_driver - register a CPU Frequency driver
 * @driver_data: A struct cpufreq_driver containing the values#
 * submitted by the CPU Frequency driver.
 *
 *   Registers a CPU Frequency driver to this core code. This code
 * returns zero on success, -EBUSY when another driver got here first
 * (and isn't unregistered in the meantime).
 *
 */
int cpufreq_register_driver(struct cpufreq_driver *driver_data)
{
	unsigned long flags;
	int ret;

	if (!driver_data || !driver_data->verify || !driver_data->init ||
	    ((!driver_data->setpolicy) && (!driver_data->target)))
		return -EINVAL;

	pr_debug("trying to register driver %s\n", driver_data->name);

	if (driver_data->setpolicy)
		driver_data->flags |= CPUFREQ_CONST_LOOPS;

	spin_lock_irqsave(&cpufreq_driver_lock, flags);
	if (cpufreq_driver) {
		spin_unlock_irqrestore(&cpufreq_driver_lock, flags);
		return -EBUSY;
	}
	cpufreq_driver = driver_data; 
	spin_unlock_irqrestore(&cpufreq_driver_lock, flags);

	ret = sysdev_driver_register(&cpu_sysdev_class,
					&cpufreq_sysdev_driver);
	if (ret)
		goto err_null_driver;

	if (!(cpufreq_driver->flags & CPUFREQ_STICKY)) {
		int i;
		ret = -ENODEV;

		/* check for at least one working CPU */
		for (i = 0; i < nr_cpu_ids; i++)
			if (cpu_possible(i) && per_cpu(cpufreq_cpu_data, i)) {
				ret = 0;
				break;
			}

		/* if all ->init() calls failed, unregister */
		if (ret) {
			pr_debug("no CPU initialized for driver %s\n",
							driver_data->name);
			goto err_sysdev_unreg;
		}
	}

	register_hotcpu_notifier(&cpufreq_cpu_notifier);
	pr_debug("driver %s up and running\n", driver_data->name);

	return 0;
err_sysdev_unreg:
	sysdev_driver_unregister(&cpu_sysdev_class,
			&cpufreq_sysdev_driver);
err_null_driver:
	spin_lock_irqsave(&cpufreq_driver_lock, flags);
	cpufreq_driver = NULL;
	spin_unlock_irqrestore(&cpufreq_driver_lock, flags);
	return ret;
}



爲什麼不直接引用acpi_cpufreq_driver呢?


由於傳遞過來的參數是acpi_cpufreq_driver,因此以後引用cpufreq_driver就相當於引用acpi_cpufreq_driver了。爲什麼這麼做呢?因爲,還有一種叫做pcc_cpufreq_driver的東西,和acpi_cpufreq_driver一樣,是電源管理的一種方式,它的初始化也是用這個函數,因爲這兩種方式你只能選擇一種,因此,cpufreq_driver要麼是acpi_cpufreq_driver,要麼是pcc_cpufreq_driver。這樣的實現方式,避免了代碼的重複!
有這樣一行代碼
	cpufreq_driver = driver_data; 




發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章