Linux内核中ACPI电源管理部分解析

2019-07-14 03:27发布

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 "); 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 ", 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 ", driver_data->name); goto err_sysdev_unreg; } } register_hotcpu_notifier(&cpufreq_cpu_notifier); pr_debug("driver %s up and running ", 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;