linux啟動初始化步驟(九)----電源管理相關函式
參考http://www.wowotech.net/sort/linux_kenrel博文的內容
Linux電源管理是一個比較龐大的子系統,涉及到供電(power supply)、充電(Charger)、時鐘(Clock)、頻率(Frequency)、電壓(Voltage)、睡眠/喚醒(Suspend/Resume)等方方面面。
Power Supply,是一個供使用者空間程式監控系統的供電狀態(電池供電,USB供電,AC供電等等)的class.通俗的講,它是一個Battery&Charger驅動的Framework
Clock Framework,Clock驅動的Framework,用於統一管理系統的時鐘資源
Regulator Framework,Volatage/Current Regulator驅動的Framework。該驅動用於調節CPU等模組的電壓和電流值
Dynamic Tick/Clock Event,在傳統的Linux Kernel中,系統Tick是固定週期(如10ms)的,因此每個一個Tick,就會產生一個Timer中斷。這會喚醒處於Idle或者Sleep狀態的CPU,而很多時候這種喚醒是沒有意義的。因此新的Kernel就提出了Dynamic Tick的概念,Tick不再是週期性的,而是根據系統中定時器的情況,不規律的產生,這樣可以減少很多無用的Timer中斷
CPU Idle,用於控制CPU Idle狀態的Framework
Generic PM,傳統意義上的Power Management,如Power Off、Suspend to RAM、Suspend to DISK、Hibernate等
Runtime PM and Wakelock,執行時的Power Management,不再需要使用者程式的干涉,由kernel統一排程,實時的關閉或開啟裝置,以便在使用效能和省電效能之間找到最佳的平衡。
CPU Freq/Device Freq,用於實現CPU以及Device頻率調整的Framework
OPP(Operating Performance Point),是指可以使SOCs或者Devices正常工作的電壓和頻率組合。核心提供這一個Layer,是為了在眾多的電壓和頻率組合中,篩選出一些相對固定的組合,從而使事情變得更為簡答一些二。
PM QOS,所謂的PM QOS,是指系統在指定的執行狀態下(不同電壓、頻率、不同模式之間切換,等等)的工作質量,包括latency、timeout、throughout三個引數,單位分別為us,us和kb.s。通過QOS,可以分析,改善系統的效能。
電源模組的相關初始化:
static int __init pm_init(void) { int error = pm_start_workqueue(); if (error) return error; hibernate_image_size_init(); hibernate_reserved_size_init(); power_kobj = kobject_create_and_add("power", NULL); if (!power_kobj) return -ENOMEM; return sysfs_create_group(power_kobj, &attr_group); }
電源管理有關的程式碼,kernel目錄下:
Cpu_pm.c (kernel):core_initcall(cpu_pm_init);//優先順序為1
電源管理有關的程式碼,kernel\power目錄下:
Main.c (kernel\power):core_initcall(pm_init);//優先順序為1
Main.c (kernel\power):late_initcall(pm_debugfs_init);//優先順序為7
Qos.c (kernel\power):late_initcall(pm_qos_power_init);//優先順序為7
電源管理有關的程式碼,drivers\base\power目錄下
Wakeup.c (drivers\base\power):postcore_initcall(wakeup_sources_debugfs_init);//優先順序為2
電源管理有關的程式碼,drivers\cpuidle目錄下(按呼叫順序):
Cpuidle.c (drivers\cpuidle):core_initcall(cpuidle_init);//優先順序為1
Ladder.c (drivers\cpuidle\governors):module_init(init_ladder);//優先順序為6
Menu.c (drivers\cpuidle\governors):module_init(init_menu);//優先順序為6
電源管理有關的程式碼,drivers\cpufreq目錄下(按呼叫順序):
Cpufreq.c (drivers\cpufreq):pure_initcall(init_cpufreq_transition_notifier_list);//優先順序為0
Cpufreq.c (drivers\cpufreq):core_initcall(cpufreq_core_init);//優先順序為1
Cpufreq_performance.c (drivers\cpufreq):fs_initcall(cpufreq_gov_performance_init);//優先順序為5
Cpufreq_userspace.c (drivers\cpufreq):fs_initcall(cpufreq_gov_userspace_init);//優先順序為5
Cpufreq_stats.c (drivers\cpufreq):module_init(cpufreq_stats_init);//優先順序為6
Cpufreq_powersave.c (drivers\cpufreq):module_init(cpufreq_gov_powersave_init);//優先順序為6
Cpufreq_conservative.c (drivers\cpufreq):module_init(cpufreq_gov_dbs_init);//優先順序為6
Cpufreq_ondemand.c (drivers\cpufreq):module_init(cpufreq_gov_dbs_init);//優先順序為6
優先順序為0的的函式:
static int __init init_cpufreq_transition_notifier_list(void)
{
srcu_init_notifier_head(&cpufreq_transition_notifier_list);
init_cpufreq_transition_notifier_list_called = true;
return 0;
}
優先順序為1的的函式:
Cpu_pm.c (kernel):core_initcall(cpu_pm_init)
static int cpu_pm_init(void)
{
register_syscore_ops(&cpu_pm_syscore_ops);
return 0;
}
Cpuidle.c (drivers\cpuidle):core_initcall(cpuidle_init);
/**
* cpuidle_init - core initializer
*/
static int __init cpuidle_init(void)
{
int ret;
if (cpuidle_disabled())
return -ENODEV;
ret = cpuidle_add_interface(cpu_subsys.dev_root);
if (ret)
return ret;
latency_notifier_init(&cpuidle_latency_notifier);
return 0;
}
Cpufreq.c (drivers\cpufreq):core_initcall(cpufreq_core_init);
static int __init cpufreq_core_init(void)
{
int cpu;
for_each_possible_cpu(cpu) {
per_cpu(cpufreq_policy_cpu, cpu) = -1;
init_rwsem(&per_cpu(cpu_policy_rwsem, cpu));
}
cpufreq_global_kobject = kobject_create_and_add("cpufreq", &cpu_subsys.dev_root->kobj);
BUG_ON(!cpufreq_global_kobject);
register_syscore_ops(&cpufreq_syscore_ops);
return 0;
}
優先順序為2的函式:
Wakeup.c (drivers\base\power):postcore_initcall(wakeup_sources_debugfs_init);
static int __init wakeup_sources_debugfs_init(void)
{
wakeup_sources_stats_dentry = debugfs_create_file("wakeup_sources",
S_IRUGO, NULL, NULL, &wakeup_sources_stats_fops);
return 0;
}
優先順序為5的函式:
Cpufreq_performance.c (drivers\cpufreq):fs_initcall(cpufreq_gov_performance_init);
static int __init cpufreq_gov_performance_init(void)
{
return cpufreq_register_governor(&cpufreq_gov_performance);
}
Cpufreq_userspace.c (drivers\cpufreq):fs_initcall(cpufreq_gov_userspace_init);
優先順序為6的函式:
Ladder.c (drivers\cpuidle\governors):module_init(init_ladder);
/**
* init_ladder - initializes the governor
*/
static int __init init_ladder(void)
{
return cpuidle_register_governor(&ladder_governor);
}
Menu.c (drivers\cpuidle\governors):module_init(init_menu);
/**
* init_menu - initializes the governor
*/
static int __init init_menu(void)
{
return cpuidle_register_governor(&menu_governor);
}
Cpufreq_stats.c (drivers\cpufreq):module_init(cpufreq_stats_init);
static int __init cpufreq_stats_init(void)
{
int ret;
unsigned int cpu;
spin_lock_init(&cpufreq_stats_lock);
ret = cpufreq_register_notifier(¬ifier_policy_block,
CPUFREQ_POLICY_NOTIFIER);
if (ret)
return ret;
ret = cpufreq_register_notifier(¬ifier_trans_block,
CPUFREQ_TRANSITION_NOTIFIER);
if (ret) {
cpufreq_unregister_notifier(¬ifier_policy_block,
CPUFREQ_POLICY_NOTIFIER);
return ret;
}
register_hotcpu_notifier(&cpufreq_stat_cpu_notifier);
for_each_online_cpu(cpu) {
cpufreq_update_policy(cpu);
}
return 0;
}
Cpufreq_powersave.c (drivers\cpufreq):module_init(cpufreq_gov_powersave_init);
static int __init cpufreq_gov_powersave_init(void)
{
return cpufreq_register_governor(&cpufreq_gov_powersave);
}
Cpufreq_conservative.c (drivers\cpufreq):module_init(cpufreq_gov_dbs_init);
static int __init cpufreq_gov_dbs_init(void)
{
return cpufreq_register_governor(&cpufreq_gov_conservative);
}
Cpufreq_ondemand.c (drivers\cpufreq):module_init(cpufreq_gov_dbs_init);
static int __init cpufreq_gov_dbs_init(void)
{
u64 idle_time;
int cpu = get_cpu();
idle_time = get_cpu_idle_time_us(cpu, NULL);
put_cpu();
if (idle_time != -1ULL) {
/* Idle micro accounting is supported. Use finer thresholds */
dbs_tuners_ins.up_threshold = MICRO_FREQUENCY_UP_THRESHOLD;
dbs_tuners_ins.down_differential =
MICRO_FREQUENCY_DOWN_DIFFERENTIAL;
/*
* In nohz/micro accounting case we set the minimum frequency
* not depending on HZ, but fixed (very low). The deferred
* timer might skip some samples if idle/sleeping as needed.
*/
min_sampling_rate = MICRO_FREQUENCY_MIN_SAMPLE_RATE;
} else {
/* For correct statistics, we need 10 ticks for each measure */
min_sampling_rate =
MIN_SAMPLING_RATE_RATIO * jiffies_to_usecs(10);
}
return cpufreq_register_governor(&cpufreq_gov_ondemand);
}
/* 這個檔案包含了和中斷有關的電源管理*/
Pm.c (kernel\irq):device_initcall(irq_pm_init_ops);
static int __init irq_pm_init_ops(void)
{
register_syscore_ops(&irq_pm_syscore_ops);
return 0;
}
優先順序為7的函式
Main.c (kernel\power):late_initcall(pm_debugfs_init);
static int __init pm_debugfs_init(void)
{
debugfs_create_file("suspend_stats", S_IFREG | S_IRUGO,
NULL, NULL, &suspend_stats_operations);
return 0;
}
Qos.c (kernel\power):late_initcall(pm_qos_power_init);
static int __init pm_qos_power_init(void)
{
int ret = 0;
ret = register_pm_qos_misc(&cpu_dma_pm_qos);
if (ret < 0) {
printk(KERN_ERR "pm_qos_param: cpu_dma_latency setup failed\n");
return ret;
}
ret = register_pm_qos_misc(&network_lat_pm_qos);
if (ret < 0) {
printk(KERN_ERR "pm_qos_param: network_latency setup failed\n");
return ret;
}
ret = register_pm_qos_misc(&network_throughput_pm_qos);
if (ret < 0)
printk(KERN_ERR
"pm_qos_param: network_throughput setup failed\n");
return ret;
}
Pm.c (arch\arm\mach-davinci):late_initcall(davinci_pm_init);
static int __init davinci_pm_init(void)
{
return platform_driver_probe(&davinci_pm_driver, davinci_pm_probe);
}