PowerSaver驱动源码分析技术文档

目  录

一、简述 1

二、操作环境 2

三、主要原理及关键结构体、函数分析 2

cpufreq_policy结构体 2

cpufreq_frequency_table结构体 4

eps_cpu_data结构体 4

四、具体函数分析 6

eps_cpu_init分析 6

eps_cpu_exit分析 7

eps_verify分析 7

eps_target分析 7

eps_set_state分析 8

eps_get分析 8

参考文献 8

一、简述

目前在做编写适配兆芯Nano CPU节能驱动模块,分析Linux内核源码中关于PowerSaver驱动程序源码,本文主要讲述PowerSaver驱动程序的关键结构体、函数的作用及关系,通过本文可以了解Linux内核关于能耗模块的概述。

二、操作环境


操作系统


mint17


内核


3.8.0


编译器


gcc4.7.3


CPU


VIA Nano X2 L4530 @ 1.6+ GHz


内存


4G


多核


2个

三、主要原理及关键结构体、函数分析

PowerSaver驱动的功能是兆芯VIA CPU能耗驱动,它是VIA的一大特色【1】,它主要是通过调节CPU电压、频率达到降低能耗的作用。有关VIA CPU能耗驱动主要有两个:Longhaul和PowerSaver,PowerSaver是Longhaul的升级版。Longhaul支持VIA的老版本(C3,C7)PowerSaver支持较为新的CPU(C7+),但是它不支持Nano,分析PowerSaver驱动的目的在于参考其驱动程序,来编写兆芯Nano CPU的能耗驱动程序。

PowerSaver驱动程序在driver/cpufreq/e_powersaver.c中。

该驱动的主要作用原理是通过读写msr寄存器(rdmsr/wrmsr)来调节CPU的电压和频率。

首先介绍关键结构体和函数:

cpufreq_policy结构体

cpufreq_policy结构体是能耗驱动的核心,它贯穿于能耗驱动主要函数。

struct cpufreq_policy {
	cpumask_var_t		cpus;	/* CPUs requiring sw coordination */
	cpumask_var_t		related_cpus; /* CPUs with any coordination */
	unsigned int		shared_type; /* ANY or ALL affected CPUs
						should set cpufreq */
	unsigned int		cpu;    /* cpu nr of registered CPU */
	struct cpufreq_cpuinfo	cpuinfo;/* see above */

	unsigned int		min;    /* in kHz */
	unsigned int		max;    /* in kHz */
	unsigned int		cur;    /* in kHz, only needed if cpufreq
					 * governors are used */
	unsigned int		policy; /* see above */
	struct cpufreq_governor	*governor; /* see below */

	struct work_struct	update; /* if update_policy() needs to be
					 * called, but you're in IRQ context */
	struct cpufreq_real_policy	user_policy;
	struct kobject		kobj;
	struct completion	kobj_unregister;
};

其中的各个字段的解释如下【2】:

l cpus和related_cpus 这两个都是cpumask_var_t变量,cpus表示的是这一policy控制之下的所有还出于online状态的cpu,而related_cpus则是online和offline两者的合集。主要是用于多个cpu使用同一种policy的情况,实际上,我们平常见到的大多数系统中都是这种情况:所有的cpu同时使用同一种policy。我们需要related_cpus变量指出这个policy所管理的所有cpu编号。

l cpu和last_cpu    虽然一种policy可以同时用于多个cpu,但是通常一种policy只会由其中的一个cpu进行管理,cpu变量用于记录用于管理该policy的cpu编号,而last_cpu则是上一次管理该policy的cpu编号(因为管理policy的cpu可能会被plug out,这时候就要把管理工作迁移到另一个cpu上)。

l cpuinfo    保存cpu硬件所能支持的最大和最小的频率以及切换延迟信息。

l min/max/cur  该policy下的可使用的最小频率,最大频率和当前频率。

l policy    该变量可以取以下两个值:CPUFREQ_POLICY_POWERSAVE和CPUFREQ_POLICY_PERFORMANCE,该变量只有当调频驱动支持setpolicy回调函数的时候有效,这时候由驱动根据policy变量的值来决定系统的工作频率或状态。如果调频驱动(cpufreq_driver)支持target回调,则频率由相应的governor来决定。

l governor和governor_data 指向该policy当前使用的cpufreq_governor结构和它的上下文数据。governor是实现该policy的关键所在,调频策略的逻辑由governor实现。

l update 有时在中断上下文中需要更新policy,需要利用该工作队列把实际的工作移到稍后的进程上下文中执行。

l user_policy    有时候因为特殊的原因需要修改policy的参数,比如溫度过高时,最大可允许的运行频率可能会被降低,为了在适当的时候恢复原有的运行参数,需要使用user_policy保存原始的参数(min,max,policy,governor)。

l kobj    该policy在sysfs中对应的kobj的对象。

cpufreq_frequency_table结构体

cpufreq_frequency_table结构体是用于记录CPU支持的频率表,index标示检索值,frequency表示频率,单位kHz。

struct cpufreq_frequency_table {
	unsigned int	index;     /* any */
	unsigned int	frequency; /* kHz - doesn't need to be in ascending
				    * order */
};

eps_cpu_data结构体

eps_cpu_data是PowerSaver独有的结构体,专门用于在驱动程序各个函数之间传递信息,包含fsb 前端总线频率和cpufreq_frequency_table项。如果Linux内核配置了

CONFIG_ACPI_PROCESSOR或者CONFIG_ACPI_PROCESSOR_MODULE选项。定义bios_limit,bios限制频率。在eps_get(),eps_set_state(),eps_target(),eps_cpu_init()这几个函数中应用。

struct eps_cpu_data {
	u32 fsb;
#if defined CONFIG_ACPI_PROCESSOR || defined CONFIG_ACPI_PROCESSOR_MODULE
	u32 bios_limit;
#endif
	struct cpufreq_frequency_table freq_table[];
};

以上介绍了PowerSaver驱动的关键结构体,下面介绍关键函数。Linux内核能耗驱动框架是统一的,即cpufreq_driver。支持不同硬件、版本的驱动程序本质上就是填写这个cpufreq_driver驱动结构体(cpufreq.h中定义)。

struct cpufreq_driver {
	struct module           *owner;
	char			name[CPUFREQ_NAME_LEN];
	u8			flags;

	/* needed by all drivers */
	int	(*init)		(struct cpufreq_policy *policy);
	int	(*verify)	(struct cpufreq_policy *policy);

	/* define one out of two */
	int	(*setpolicy)	(struct cpufreq_policy *policy);
	int	(*target)	(struct cpufreq_policy *policy,
				 unsigned int target_freq,
				 unsigned int relation);

	/* should be defined, if possible */
	unsigned int	(*get)	(unsigned int cpu);

	/* optional */
	unsigned int (*getavg)	(struct cpufreq_policy *policy,
				 unsigned int cpu);
	int	(*bios_limit)	(int cpu, unsigned int *limit);

	int	(*exit)		(struct cpufreq_policy *policy);
	int	(*suspend)	(struct cpufreq_policy *policy);
	int	(*resume)	(struct cpufreq_policy *policy);
	struct freq_attr	**attr;
};

相关的字段的意义解释如下:

l name    该频率驱动的名字。

l init    回调函数,该回调函数必须实现,CPUFreq Core会通过该回调函数对该驱动进行必要的初始化工作。

l verify    回调函数,该回调函数必须实现,CPUFreq Core会通过该回调函数检查policy的参数是否被驱动支持。

l setpolicy/target    回调函数,驱动必须实现这两个函数中的其中一个,如果不支持通过governor选择合适的运行频率,则实现setpolicy回调函数,这样系统只能支持CPUFREQ_POLICY_POWERSAVE

和CPUFREQ_POLICY_PERFORMANCE这两种工作策略。反之,实现target回调函数,通过target回调设定governor所需要的频率。

l get    回调函数,用于获取cpu当前的工作频率。

l getavg    回调函数,用于获取cpu当前的平均工作频率。

下面是PowerSaver驱动的实例化:

static struct cpufreq_driver eps_driver = {
	.verify		= eps_verify,
	.target		= eps_target,
	.init		= eps_cpu_init,
	.exit		= eps_cpu_exit,
	.get		= eps_get,
	.name		= "e_powersaver",
	.owner		= THIS_MODULE,
	.attr		= eps_attr,
};

四、具体函数分析

eps_cpu_init分析

eps_cpu_init函数,主要用于初始化。读写msr寄存器使能PowerSaver。显示当前电压频率,对当前电压、步进、频率依据cpufreq_policy进行判断验证正确性。计算前端总线频率。设置频率表,设置cpufreq_policy的最大、小频率。测试CPU是否在降频状态。计算fsb速度。计算当前电压、转换延时到policy结构体中,这个函数主要是设置policy结构体,为  后续函数处理做准备。该初始化函数只是针对C3、C7的初始化,没有针对Nano的。有关如何读写msr寄存器需要结合硬件手册来看。

函数原型:

static int eps_cpu_init(struct cpufreq_policy *policy)

其中cpufreq_policy是之前讲的CPU频率规定结构体。

eps_cpu_exit分析

eps_cpu_exit函数的作用是:注销并释放空间

函数原型为:static int eps_cpu_exit(struct cpufreq_policy *policy)

eps_verify分析

eps_verify主要是验证处理器频率设定,检查频率表中的频率是否越界,是否不正确。

原型:static int eps_verify(struct cpufreq_policy *policy)

内部核心处理函数是:

int cpufreq_frequency_table_verify(struct cpufreq_policy *policy,

struct cpufreq_frequency_table *table)

eps_target分析

eps_target是具体实现函数,policy是频率规定结构体,target_freq是需要设定的频率。relation表示取值策略,取下限值还是上限值【3】。

relation可以取下列值:

#define CPUFREQ_RELATION_L 0  /* lowest frequency at or above target 取上限值*/

#define CPUFREQ_RELATION_H 1  /* highest frequency below or at target 下限值*/

函数原型:

static int eps_target(struct cpufreq_policy *policy,

unsigned int target_freq,

unsigned int relation)

该函数内部有两个关键函数:

1)cpufreq_frequency_table_target(),该函数的作用根据policy和relation(取值策略)和target_freq(目标频率)遍历policy的频率表,找到和target_freq最相近的频率值,把该检索点传递给newstate。

2) dest_state = centaur->freq_table[newstate].index & 0xffff;

ret = eps_set_state(centaur, cpu, dest_state);//通过wrmsr来设置频率。

eps_set_state分析

下面具体介绍eps_set_state函数,这个函数是具体设置CPU频率的核心函数!!

eps_set_state函数原型:

static int eps_set_state(struct eps_cpu_data *centaur,

unsigned int cpu,

u32 dest_state)

centaur是频率设定结构体,之前讲过的,cpu表示设定特定的CPU,dest_state是设置目的频率值。

该函数就是通过读写msr寄存器来设置CPU频率,这个需要结合硬件手册来分析。对于后续做耗电驱动程序来说需要参考这个还需要结合硬件厂商提供的硬件手册。

eps_get分析

eps_get函数的作用返回特定CPU的频率。

函数原型如下:

static unsigned int eps_get(unsigned int cpu)

时间: 2024-10-10 12:57:44

PowerSaver驱动源码分析技术文档的相关文章

手机游戏闯三国(乱世之刃)客户端+ 服务端源码 + 完整策划文档

闯三国(乱世之刃)客户端源码 + 服务端源码 + 完整策划文档) 乱世之刃源代码下载 <乱世之刃2>即将在近期上线了,为了让玩家感触最顺利的游戏体会,游戏商已做好了全部的准备,11月20日进行封测.[2] 游戏称号 浊世之刃 游戏种类 横版格斗游戏 游戏平台 iOS.Android 开发商 Xiamen Yidou 发行时刻 2012-11-15 适宜年纪 12岁以上 语    言 中文 安卓iOS游戏源码下载 目录 1 游戏介绍 2 游戏简介 ? 游戏布景 ? IOS有关信息 ? 游戏特征

在MyEclipse显示struts2源码和doc文档及自动完成功能

分类: struts2 2010-01-07 16:34 1498人阅读 评论(1) 收藏 举报 myeclipsestruts文档xmlfileurl 在MyEclipse显示struts2源码和doc文档及自动完成功能 在MyEclipse中显示struts的源码 -------右键点击/webAppName/WebRoot/WEB-INF/lib/struts2-core-2.1.8.1.jar -------propertes -------Java Source Attachment

eclipse导入java和android sdk源码,帮助文档

eclipse导入java和android sdk源码,帮助文档 http://blog.csdn.net/ashelyhss/article/details/37993261 JavaDoc集成到Eclipse的帮助中 http://blog.chinaunix.net/uid-90129-id-132837.html android帮助文档打开慢的三种解决方法 set path=C:\Program Files\Git\bin; find . -name "*.html"|xarg

Android记录17-sdk更新、Eclipse下查看源码、chm文档提供等干货

Android记录17-sdk更新.Eclipse下查看源码.chm文档提供等干货 本篇博客分享一些Android开发者提高开发效率的一些干货,之从Google被和谐了之后,Android开发者可谓痛不欲生,只能通过翻墙的方式去查看官网,sdk更新不了,无法下载源码等问题就出现了,作为一位有追求的Android开发者,不可能只满足于使用sdk这种初级技能了,提高开发效率和代码质量是每位开发者应该去追求的,下面小巫整理总结了一些解决方案供各位参考,让Android开发变得高大上一些. sdk更新

Python Django框架实现商城项目源码加设计文档和注释

Python Django框架实现商城项目源码加设计文档和注释 链接:https://pan.baidu.com/s/1yN2iBgx3zmpTkoY8u1LWRg 提取码:lfsx 非常完整的django项目源码,分享给撸友们,不管是学习还是深造,都是可以学习借鉴的!! 原文地址:https://www.cnblogs.com/zyxlovesjy/p/12115491.html

linux驱动开发之蜂鸣器驱动源码分析(一)

蜂鸣器的驱动源码在/driver/char/buzzer/x210-buzzer.c文件中,源码如下 #include <linux/module.h> #include <linux/kernel.h> #include <linux/fs.h> #include <linux/init.h> #include <linux/delay.h> #include <linux/poll.h> #include <asm/irq.

【C#附源码】数据库文档生成工具支持(Excel+Html)

[2015] 很多时候,我们在生成数据库文档时,使用某些工具,可效果总不理想,不是内容不详细,就是表现效果一般般.很多还是word.html的.看着真是别扭.本人习惯用Excel,所以闲暇时,就简单的编写了数据库文档生成工具,供大家交流学习之用,与程序员共勉.     该工具为C#控制台,以NPOI为基础,操作Excel.简单方便,简单配置.两次回车,OK!即可生成清晰的数据库文档.另外,支持生成HTML文档.源码大小7MB,OS上传不了,放到百度云盘里了:http://pan.baidu.co

MyEclipse查看Struts2源码及Javadoc文档

一.查看Struts2源码 1.Referenced Libraries >struts2-core-2.1.6.jar>右击>properties. 2.Java Source Attachment >External Folder>(选择架包存放目录)/struts-2.1.6/src/core/src/main/java>OK. 3.双击打开struts2-core-2.1.6.jar根目录下的class文件你就可以看到Struts2的源码了. 二.Javadoc

ASP.NET大型企业OA平台100%源码+所有文档说明

这个OA系统是我之前从朋友那里花了不少RMB买来的,之后我修改了一些Bug和界面等.系统采用的是ASP.NET框架,后台全部是用C#语音写的,数据库采用的是SQL Server.我主要是想学习学习它的整体架构和一些功能模块的实现方法.如果大家有需求的话,可以留言后直接支付宝或者微信转账给我,只需30元,我会把所以文档说明和100%源码给大家,文档包括:OA介绍.OA使用手册.目录文件说明.数据库存储过程.系统解决方案,系统数据库设计等等(文章底部扫一扫二维码就可以转账). 不会使用的朋友可以留言