1. 程式人生 > >linux啟動初始化步驟(九)----電源管理相關函式

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(&notifier_policy_block,
				CPUFREQ_POLICY_NOTIFIER);
	if (ret)
		return ret;

	ret = cpufreq_register_notifier(&notifier_trans_block,
				CPUFREQ_TRANSITION_NOTIFIER);
	if (ret) {
		cpufreq_unregister_notifier(&notifier_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);
}