AUTHOR: Joseph Yang (杨红刚) <[email protected]>
CONTENT: cpufreq.c 源码分析
NOTE: linux-3.0
LAST MODIFIED:09-19-2011
-----------------------------------------------------------------------------------------------------------
Distributed and Embedded System Lab (分布式嵌入式系统实验室,兰州大学)
=========================================================================================================================
----------------------- function list
|- function
|| unlock_policy_rwsem_read +
|| unlock_policy_rwsem_write +
|| init_cpufreq_transition_notifier_list +
|| cpufreq_cpu_get +
|| cpufreq_cpu_put +
|| adjust_jiffies +
|| cpufreq_notify_transition +
|| __find_governor +
|| cpufreq_parse_governor +
|| show_cpuinfo_cur_freq +
|| show_scaling_governor +
|| store_scaling_governor +
|| show_scaling_driver +
|| show_scaling_available_governors +
|| show_cpus +
|| show_related_cpus +
|| show_affected_cpus +
|| store_scaling_setspeed +
|| show_scaling_setspeed +
|| show_bios_limit +
|| show +
|| store +
|| cpufreq_sysfs_release +
|| cpufreq_add_dev_policy +
|| cpufreq_add_dev_symlink +
|| cpufreq_add_dev_interface +
|| cpufreq_add_dev +
|| __cpufreq_remove_dev
|| cpufreq_remove_dev
|| handle_update +
|| cpufreq_out_of_sync +
|| cpufreq_quick_get +
|| __cpufreq_get +
|| cpufreq_get +
|| cpufreq_bp_suspend +
|| cpufreq_bp_resume +
|| cpufreq_register_notifier +
|| cpufreq_unregister_notifier +
|| __cpufreq_driver_target +
|| cpufreq_driver_target +
|| __cpufreq_driver_getavg +
|| __cpufreq_governor +
|| cpufreq_register_governor +
|| cpufreq_unregister_governor +
|| cpufreq_get_policy +
|| __cpufreq_set_policy +
|| cpufreq_update_policy +
|| cpufreq_cpu_callback +
|| cpufreq_register_driver +
|| cpufreq_unregister_driver +
|| cpufreq_core_init +
==========================================================
1.
函数: static int __init cpufreq_core_init(void)
参数:
返回值:
功能: 初始化用到的一些全局变量,创建cpufreq文件夹,注册系统核心操作
调用模块:
执行流程:
初始化per cpu变量 cpufreq_policy_cpu
初始化per cpu 类型的semaphore 变量cpu_policy_rwsem
创建一个名为cpufreq的kobject对象//其结果是,在/sys/devices/system/cpu/cpuX下创建了cpufreq文件夹
//kobject_create_and_add
在对象创建失败时引发oops
注册系统核心操作cpufreq_syscore_ops //register_syscore_ops ?????不知道被谁,什么时候调用
2.
函数:
/**
* cpufreq_bp_suspend - Prepare the boot CPU for system suspend.
*
* This function is only executed for the boot processor. The other CPUs
* have been put offline by means of CPU hotplug.
*/
static int cpufreq_bp_suspend(void)
参数:
返回值:
功能: 在当前CPU上调用cpufreq_driver->suspend // Prepare the boot CPU for system suspend.
调用模块:
执行流程:
获得代码运行在的cpu 号 //smp_processor_id
取得cpufreq_policy 类型的值的指针data,并增一data所指向结构的引用计数 //cpufreq_cpu_get
如果cpufreq_driver->suspend不空,则调用之
对cpufreq_policy* 类型data所指向的结构的引用计数减一//cpufreq_cpu_put
3.
函数: struct cpufreq_policy *cpufreq_cpu_get(unsigned int cpu)
参数:
返回值:
功能: 取得cpufreq_policy 类型的cpufreq_cpu_data的副本,对cpufreq_cpu_data引用计数增一
调用模块:
执行流程:
得到cpufreq_driver_lock锁 // spin_lock_irqsave
如果cpufreq_driver->owner模块已经插入内核,则递增该模块引用计数;
如果该模块还没有插入内核,则返回0表示出错。//try_module_get,
获得cpufreq_policy类型变量cpufreq_cpu_data的指针,保存在data中//per_cpu <-----------------<<<<在哪里进行的设置?
对cpufreq_cpu_data引用计数增一//kobject_get
释放cpufreq_driver_lock锁//spin_unlock_irqrestore
返回cpufreq_policy 类型的cpufreq_cpu_data的副本
4.
函数: void cpufreq_cpu_put(struct cpufreq_policy *data)
参数:
返回值:
功能: 对data的引用计数减一
调用模块:
执行流程:
对data的引用计数减一 // kobject_put
** //module_put
5.
函数:
/**
* cpufreq_bp_resume - Restore proper frequency handling of the boot CPU.
*
* 1.) resume CPUfreq hardware support (cpufreq_driver->resume())
* 2.) schedule call cpufreq_update_policy() ASAP as interrupts are
* restored. It will verify that the current freq is in sync with
* what we believe it to be. This is a bit later than when it
* should be, but nonethteless it's better than calling
* cpufreq_driver->get() here which might re-enable interrupts...
*
* This function is only executed for the boot CPU. The other CPUs have not
* been turned on yet.
*/
static void cpufreq_bp_resume(void);
参数:
返回值:
功能: Restore proper frequency handling of the boot CPU. //执行policy的resume调用,并调用update_policy()
调用模块:
执行流程:
得到当前CPU的id号 //smp_processor_id
取得cpufreq_policy 类型的值data //cpufreq_cpu_get
如果当前CPU的policy为空,则函数返回
否则,执行resume调用
将policy的update函数成员添加到全局工作队列(workqueue)// schedule_work
//为了在中断环境下,调用update_policy() 函数
6.
函数: int cpufreq_register_governor(struct cpufreq_governor *governor)
参数:
返回值:
功能: 将cpufreq_governor添加到全局governor表(cpufreq_governor_list)中
调用模块:
执行流程:
获得保护cpufreq_governor_list的锁cpufreq_governor_mutex//mutex_lock
如果要添加的cpufreq_governor不在cpufreq_governor_list中,则添加//__find_governor, list_add
释放锁//mutex_unlock
7.
函数: static struct cpufreq_governor *__find_governor(const char *str_governor)
参数:str_governor:要查找的cpufreq_governor的名字
返回值:
功能: 获得cpufreq_governor_list中名为str_governor 的cpufreq_governor的指针,
不存在时返回NULL
调用模块:
执行流程:
按名字在cpufreq_governor_list中顺序查找相关cpufreq_governor
如果有,则返回指向它的指针
否则,返回空 //list_for_each_entry,strnicmp
8.
函数: void cpufreq_unregister_governor(struct cpufreq_governor *governor)
参数:
返回值:
功能: 将cpufreq_cpu_governor置为“空串“, 从governor->governor_list 中删除governor
调用模块:
执行流程:
检查cpu号CPU是否可以调度(检查cpu是否在cpu_online_mask中)// cpu_online
如果可以调度,则跳过该CPU
如果governor跟当前设置的 cpufreq_governor相同,则将cpufreq_cpu_governor置为“空串“//strcpy
获取cpufreq_governor_mutex锁 //mutex_lock
从governor->governor_list 中删除governor //list_del
释放cpufreq_governor_mutex锁 //mutex_unlock
/* This one keeps track of the previously set governor of a removed CPU */
static DEFINE_PER_CPU(char[CPUFREQ_NAME_LEN], cpufreq_cpu_governor);
9.
函数:
/*
* when "event" is CPUFREQ_GOV_LIMITS
*/
static int __cpufreq_governor(struct cpufreq_policy *policy,
unsigned int event);
参数:
返回值:
功能: 使用policy处理event事件
调用模块:
执行流程:
如果policy的transition_latency大于它的max_transition_latency,
则,把policy的governor设置为cpufreq_gov_performance
如果policy->governor->owner模块已经插入内核,则递增该模块引用计数;
如果该模块还没有插入内核,则返回0//try_module_get
调用policy->governor->governor
当 event 是CPUFREQ_GOV_STOP 或CPUFREQ_GOV_LIMITS时
或者 policy->governor->governor执行失败
或者 event 是 CPUFREQ_GOV_STOP 并且policy->governor->governor执行成功时
则,卸载模块 //module_put
struct cpufreq_governor cpufreq_gov_performance = {
.name = "performance",
.governor = cpufreq_governor_performance,//一个governor,它静态地把cpu frequency 设置为最大可用值
.owner = THIS_MODULE,
};
10.
函数:
/**
* 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);
参数:
返回值:
功能: 注册cpufreq_driver驱动, 并注册cpu notifier 回调函数
调用模块:
执行流程:
参数检查
为driver_data->flags设置CPUFREQ_CONST_LOOPS标志
获得cpufreq_driver_lock // spin_lock_irqsave
如果cpufreq_driver已经有值了,
则,释放cpufreq_driver_lock锁 // spin_unlock_irqrestore
使用传入的值,更新cpufreq_driver的值
释放cpufreq_driver_lock锁//spin_unlock_irqrestore
注册辅助驱动 //sysdev_driver_register,cpufreq_sysdev_driver is inserted into cpu_sysdev_class->drivers to be
// called on each operation on devices of that class. The refcount of cpu_sysdev_class is incremented.
driver_data->flag没有设置CPUFREQ_STICKY标志,
则,找到一个working CPU //cpu_possible, per_cpu
// 对这个CPU的要求:1. CPU may be pluged in at any time.
// 2. cpufreq_cpu_data非空//已经设置了cpufreq policy
如果没有找到一个working CPU,
那么,卸载辅助驱动 //sysdev_driver_unregister
如果找到了一个working CPU,那么
Add notifier to "cpu_chain" raw notifier chain //register_hotcpu_notifier
------------------------------
#define register_hotcpu_notifier(nb) register_cpu_notifier(nb)
/* Need to know about CPUs going up/down? */
int __ref register_cpu_notifier(struct notifier_block *nb)
{
int ret;
cpu_maps_update_begin();
ret = raw_notifier_chain_register(&cpu_chain, nb); //Add notifier to "cpu_chain" raw notifier chain
cpu_maps_update_done();
return ret;
}
static RAW_NOTIFIER_HEAD(cpu_chain);
---------------------
#define cpu_possible(cpu) cpumask_test_cpu((cpu), cpu_possible_mask)
/* flags */
#define CPUFREQ_STICKY 0x01 /* the driver isn't removed even if
* all ->init() calls failed */
#define CPUFREQ_CONST_LOOPS 0x02 /* loops_per_jiffy or other kernel
* "constants" aren't affected by
* frequency transitions */ ????????<-----------------------<<<<<<<<
#define CPUFREQ_PM_NO_WARN 0x04 /* don't warn on suspend/resume speed
* mismatches */
/**
* The "cpufreq driver" - the arch- or hardware-dependent low
* level driver of CPUFreq support, and its spinlock. This lock
* also protects the cpufreq_cpu_data array.
*/
static struct cpufreq_driver *cpufreq_driver; //"cpufreq driver"
static DEFINE_SPINLOCK(cpufreq_driver_lock);
static struct sysdev_driver cpufreq_sysdev_driver = {
.add = cpufreq_add_dev,
.remove = cpufreq_remove_dev,
};
static DEFINE_PER_CPU(struct cpufreq_policy *, cpufreq_cpu_data); //在cpufreq_add_dev_policy中被设置用来保存cpufreq_policy
11.
函数:
static int __cpuinit cpufreq_cpu_callback(struct notifier_block *nfb,
unsigned long action, void *hcpu)
参数:
返回值:
功能: 根据不同的action,决定“添加”cpufreq interface, 或者 “删除”cpufreq interface
调用模块:
执行流程:
得到//get_cpu_sysdev
如果action是:CPU_ONLINE// CPU (unsigned)v is up
或者CPU_ONLINE_FROZEN// + tasks are frozen due to a suspend
则,Adds the cpufreq interface for a CPU device //cpufreq_add_dev
如果action是:CPU_DOWN_PREPARE //CPU (unsigned)v going down
或者 CPU_DOWN_PREPARE_FROZEN // + tasks are frozen due to a suspend
则,Removes the cpufreq interface for a CPU device. //__cpufreq_remove_dev
如果action是:CPU_DOWN_FAILED //CPU (unsigned)v NOT going down
或者 CPU_DOWN_FAILED_FROZEN // + tasks are frozen due to a suspend
则,Adds the cpufreq interface for a CPU device //cpufreq_add_dev
12.
函数:
/**
* cpufreq_unregister_driver - unregister the current CPUFreq driver
*
* Unregister the current CPUFreq driver. Only call this if you have
* the right to do so, i.e. if you have succeeded in initialising before!
* Returns zero if successful, and -EINVAL if the cpufreq_driver is
* currently not initialised.
*/
int cpufreq_unregister_driver(struct cpufreq_driver *driver)
参数:
返回值:
功能: 卸载辅助驱动, Remove notifier to "cpu_chain" raw notifier chain, cpufreq_driver置为空
调用模块:
执行流程:
卸载辅助驱动 //sysdev_driver_unregister
Remove notifier to "cpu_chain" raw notifier chain//unregister_hotcpu_notifier
cpufreq_driver置为空
13.
函数:
/**
* cpufreq_get_policy - get the current cpufreq_policy
* @policy: struct cpufreq_policy into which the current cpufreq_policy
* is written
* Reads the current cpufreq policy.
*/
int cpufreq_get_policy(struct cpufreq_policy *policy, unsigned int cpu);
参数:
返回值:
功能: Reads the current cpufreq policy.
调用模块:
执行流程:
取得cpufreq_policy 类型的cpufreq_cpu_data的副本,对cpufreq_cpu_data引用计数增一 //cpufreq_cpu_get
复制cpufreq_cpu_data的副本到返回值//memcpy
对cpu_policy的引用计数减一 //cpufreq_cpu_put
14. ************ 时钟相关
函数:
/*
* data : current policy.
* policy : policy to be set.
*/
static int __cpufreq_set_policy(struct cpufreq_policy *data,
struct cpufreq_policy *policy)
参数:
返回值:
功能: 设置新的policy
调用模块:
执行流程:
复制旧policy 的cpuinfo域到新的policy的cpuinfo域//memcpy
检查频率范围是否合理
verify the cpu speed can be set within this limit//cpufreq_driver->verify(policy)
通知链上的各个事件监听者,调整(CPUFREQ_ADJUST) cpufreq_policy// blocking_notifier_call_chain
通知链上的各个事件监听者, (CPUFREQ_INCOMPATIBLE) // blocking_notifier_call_chain
verify the cpu speed can be set within this limit//cpufreq_driver->verify(policy)
notification of the new policy(CPUFREQ_NOTIFY) // blocking_notifier_call_chain
记录频率协商结果到旧的policy中
如果cpufreq_driver->setpolicy非空,则 调用cpufreq_driver中setpolicy函数 //cpufreq_driver->setpolicy(policy)
如果cpufreq_driver->setpolicy 空,
则, save old, working values(data->governor)
end old governor (CPUFREQ_GOV_STOP)//__cpufreq_governor
---------------------------
struct cpufreq_cpuinfo { //该结构内成员值,由driver负责填写
unsigned int max_freq; //the minimum and maximum frequency (in kHz) which is supported by this CPU
unsigned int min_freq;
/* in 10^(-9) s = nanoseconds */
unsigned int transition_latency; //the time it takes on this CPU to switch between two frequencies innanoseconds
// (if appropriate, else specify CPUFREQ_ETERNAL)
};
/**
* Two notifier lists: the "policy" list is involved in the
* validation process for a new CPU frequency policy; the
* "transition" list for kernel code that needs to handle
* changes to devices when the CPU clock speed changes.
* The mutex locks both lists.
*/
static BLOCKING_NOTIFIER_HEAD(cpufreq_policy_notifier_list);//新 CPU frequency policy 更新通知链
static struct srcu_notifier_head cpufreq_transition_notifier_list; //CPU clock speed chagne 更新通知链
15.
函数:
/**
* cpufreq_update_policy - re-evaluate an existing cpufreq policy
* @cpu: CPU which shall be re-evaluated
* Useful for policy notifiers which have different necessities
* at different times.
*/
int cpufreq_update_policy(unsigned int cpu);
参数:
返回值:
功能: re-evaluate an existing cpufreq policy //cpufreq_driver->suspend
调用模块:
执行流程:
取得cpufreq_policy 类型的值的指针data,并增一data所指向结构的引用计数 //cpufreq_cpu_get
获取写锁cpu_policy_rwsem //lock_policy_rwsem_write
把当前cpufreq_policy的值复制到辅助变量中,
使用user_policy成员的中数据更新辅助变量的相关域
检查是否频率是否又被改变
如果是,则call notifier chain and adjust_jiffies on frequency transition // cpufreq_out_of_sync
如果没有改变,则
以辅助变量为参数调用 设置新的policy//__cpufreq_set_policy
释放写锁cpu_policy_rwsem//unlock_policy_rwsem_write
对cpufreq_policy* 类型data所指向的结构的引用计数减一//cpufreq_cpu_put
16.
#define lock_policy_rwsem(mode, cpu) \
static int lock_policy_rwsem_##mode \
(int cpu) \
{ \
int policy_cpu = per_cpu(cpufreq_policy_cpu, cpu); \ //获得对应于cpu的cpufreq_policy_cpu
BUG_ON(policy_cpu == -1); \
down_##mode(&per_cpu(cpu_policy_rwsem, policy_cpu)); \ //获取cpu_policy_rwsem锁
if (unlikely(!cpu_online(cpu))) { \ //检查CPU是否处于online状态
up_##mode(&per_cpu(cpu_policy_rwsem, policy_cpu)); \ //如果不是,则释放cpu_policy_rwsem锁
return -1; \
} \
\
return 0; \
}
lock_policy_rwsem(read, cpu); //获取读锁
lock_policy_rwsem(write, cpu); //获取写锁
17.
函数:static void unlock_policy_rwsem_read(int cpu)
参数:
返回值:
功能: 释放读锁cpu_policy_rwsem
调用模块:
执行流程:
获得与cpu号CPU对应的cpufreq_policy_cpu //per_cpu
释放读锁cpu_policy_rwsem//up_read
18.
函数:static void unlock_policy_rwsem_write(int cpu)
参数:
返回值:
功能: 释放写锁cpu_policy_rwsem
调用模块:
执行流程:
获得与cpu号CPU对应的cpufreq_policy_cpu //per_cpu
释放写锁cpu_policy_rwsem//up_read
/*
* cpu_policy_rwsem is a per CPU reader-writer semaphore designed to cure
* all cpufreq/hotplug/workqueue/etc related lock issues.
*
* The rules for this semaphore:
* - Any routine that wants to read from the policy structure will
* do a down_read on this semaphore.
* - Any routine that will write to the policy structure and/or may take away
* the policy altogether (eg. CPU hotplug), will hold this lock in write
* mode before doing so.
*
* Additional rules:
* - All holders of the lock should check to make sure that the CPU they
* are concerned with are online after they get the lock.
* - Governor routines that can be called in cpufreq hotplug path should not
* take this sem as top level hotplug notifier handler takes this.
* - Lock should not be held across
* __cpufreq_governor(data, CPUFREQ_GOV_STOP);
*/
static DEFINE_PER_CPU(int, cpufreq_policy_cpu);
static DEFINE_PER_CPU(struct rw_semaphore, cpu_policy_rwsem);
19. **************时钟相关的
static bool init_cpufreq_transition_notifier_list_called;
函数:static int __init init_cpufreq_transition_notifier_list(void)
参数:
返回值:
功能: 初始化cpufreq_transition_notifier_list
调用模块:
执行流程:
Initialize an SRCU notifier head //srcu_init_notifier_head
init_cpufreq_transition_notifier_list_called置位
/**
* Two notifier lists: the "policy" list is involved in the
* validation process for a new CPU frequency policy; the
* "transition" list for kernel code that needs to handle
* changes to devices when the CPU clock speed changes.
* The mutex locks both lists.
*/
static BLOCKING_NOTIFIER_HEAD(cpufreq_policy_notifier_list);
static struct srcu_notifier_head cpufreq_transition_notifier_list;
20. **************时钟相关的
函数:
/**
* cpufreq_register_notifier - register a driver with cpufreq
* @nb: notifier function to register
* @list: CPUFREQ_TRANSITION_NOTIFIER or CPUFREQ_POLICY_NOTIFIER
*
* Add a driver to one of two lists: either a list of drivers that
* are notified about clock rate changes (once before and once after
* the transition), or a list of drivers that are notified about
* changes in cpufreq policy. //只能选择一个list
*
* This function may sleep, and has the same return conditions as
* blocking_notifier_chain_register.
*/
int cpufreq_register_notifier(struct notifier_block *nb, unsigned int list);
参数:
返回值:
功能: 注册一个notifier到 cpufreq_transition_notifier_list或者blocking_notifier_chain_register
调用模块:
执行流程:
list:CPUFREQ_TRANSITION_NOTIFIER 时
注册到cpufreq_transition_notifier_list//srcu_notifier_chain_register
list:CPUFREQ_POLICY_NOTIFIER 时
注册到blocking_notifier_chain_register//cpufreq_policy_notifier_list
21.**************时钟相关的
函数:
/**
* cpufreq_unregister_notifier - unregister a driver with cpufreq
* @nb: notifier block to be unregistered
* @list: CPUFREQ_TRANSITION_NOTIFIER or CPUFREQ_POLICY_NOTIFIER
*
* Remove a driver from the CPU frequency notifier list.
*
* This function may sleep, and has the same return conditions as
* blocking_notifier_chain_unregister.
*/
int cpufreq_unregister_notifier(struct notifier_block *nb, unsigned int list);
参数:
返回值:
功能: Remove a driver from the CPU frequency notifier list.
调用模块:
执行流程:
ist:CPUFREQ_TRANSITION_NOTIFIER 时
从cpufreq_transition_notifier_list上删除//srcu_notifier_chain_unregister
list:CPUFREQ_POLICY_NOTIFIER 时
注册到blocking_notifier_chain_register// blocking_notifier_chain_unregister
22. **************时钟相关的
函数:
/**
* cpufreq_notify_transition - call notifier chain and adjust_jiffies
* on frequency transition.
*
* This function calls the transition notifiers and the "adjust_jiffies"
* function. It is called twice on all CPU frequency changes that have
* external effects.
*/
void cpufreq_notify_transition(struct cpufreq_freqs *freqs, unsigned int state);
参数:
返回值:
功能: call notifier chain and adjust_jiffies on frequency transition
调用模块:
执行流程:
若果中断被关闭,则打印BUG信息,然后调用PANIC函数,让系统panic //irqs_disabled,BUG_ON
把cpufreq_driver->flags复制到freqs->flags
得到全局cpufreq_policy结构的指针cpufreq_cpu_data //per_cpu
如果处于 CPUFREQ_PRECHANGE阶段:
如果cpufreq_driver->flags没有设置CPUFREQ_CONST_LOOPS标志,
则, 如果 policy中cur(当前的CPU频率)跟freqs->old不同时,使用cur更新freqs->old值
通知注册在cpufreq_transition_notifier_list上的监听者,CPU freq 发生改变//srcu_notifier_call_chain
adjust the system "loops_per_jiffy" //adjust_jiffies
如果处于CPUFREQ_POSTCHANGE阶段:
adjust the system "loops_per_jiffy" // adjust_jiffies
//没有找到//trace_cpu_frequency //???????????????
通知注册在cpufreq_transition_notifier_list上的监听者,CPU freq 发生改变 //srcu_notifier_call_chain
policy->cur = freqs->new;
=--------------------------=-
#define CPUFREQ_PRECHANGE (0) // <----------------------------------<<<<??????
#define CPUFREQ_POSTCHANGE (1)
#define CPUFREQ_RESUMECHANGE (8)
#define CPUFREQ_SUSPENDCHANGE (9)
struct cpufreq_freqs {
unsigned int cpu; /* cpu nr */
unsigned int old; //
unsigned int new; //新设置的CPU 频率
u8 flags; /* flags of cpufreq_driver, see below. *///CPUFREQ_CONST_LOOPS, CPUFREQ_STICKY, CPUFREQ_PM_NO_WARN
};
23.
函数:
/**
* adjust_jiffies - adjust the system "loops_per_jiffy"
*
* This function alters the system "loops_per_jiffy" for the clock
* speed change. Note that loops_per_jiffy cannot be updated on SMP
* systems as each CPU might be scaled differently. So, use the arch
* per-CPU loops_per_jiffy value wherever possible.
*/
static unsigned long l_p_j_ref;
static unsigned int l_p_j_ref_freq;
static void adjust_jiffies(unsigned long val, struct cpufreq_freqs *ci);
参数:
ci->new: 要设置的频率
ci->old:原来的频率
返回值:
功能: adjust the system "loops_per_jiffy"
调用模块:
执行流程:
如果 cpufreq_freqs类型变量ci的flags设置了CPUFREQ_CONST_LOOPS标志,
则,直接返回
/// ?????????????????????????????? <--------------------------<<<<<<<这里的if语句中的条件没有看懂
计算新值更新loops_per_jiffy值 //cpufreq_scale
24.
函数:
/**
* cpufreq_scale - "old * mult / div" calculation for large values (32-bit-arch safe)
* @old: old value
* @div: divisor
* @mult: multiplier
* new = old * mult / div
*/
static inline unsigned long cpufreq_scale(unsigned long old, u_int div, u_int mult);
参数:
返回值:
功能: "old * mult / div" calculation for large values (32-bit-arch safe)
调用模块:
执行流程:
loops_per_jiffy计算原理:
假设频率设置为ci->new后对应的loops_per_jiffy为X,则有
X loops_per_jiffy
------------ = --------------------
ci->new ci->old
25.
函数:
int __cpufreq_driver_target(struct cpufreq_policy *policy,
unsigned int target_freq,
unsigned int relation);
参数:target_freq must be within policy->min and policy->max,
返回值:
功能: 执行 cpufreq_driver->target
调用模块:
执行流程:
cpufreq_driver->target
26.
函数:
int cpufreq_driver_target(struct cpufreq_policy *policy,
unsigned int target_freq,
unsigned int relation)
参数: target_freq must be within policy->min and policy->max,
返回值:
功能: 执行 cpufreq_driver->target
调用模块:
执行流程:
取得cpufreq_policy 类型的cpufreq_cpu_data的副本,对cpufreq_cpu_data引用计数增一 //cpufreq_cpu_get
获得写锁//lock_policy_rwsem_write
执行 cpufreq_driver->target//__cpufreq_driver_target
释放写锁 //unlock_policy_rwsem_write
对cpufreq_policy* 类型data所指向的结构的引用计数减一 //cpufreq_cpu_put
27.
函数:int __cpufreq_driver_getavg(struct cpufreq_policy *policy, unsigned int cpu)
参数:
返回值:
功能:
调用模块:
执行流程:
取得cpufreq_policy 类型的cpufreq_cpu_data的副本,对cpufreq_cpu_data引用计数增一 //cpufreq_cpu_get
执行cpufreq_driver->getavg
对cpufreq_policy* 类型data所指向的结构的引用计数减一 //cpufreq_cpu_put
28.
函数:static struct cpufreq_governor *__find_governor(const char *str_governor)
参数:
返回值:
功能: 在cpufreq_governor_list上寻找名字为str_governor的governor
NOTE: 在使用本函数前要先获得锁!!
调用模块:
执行流程:
在cpufreq_governor_list上寻找名字为str_governor的governor //strnicmp,
static LIST_HEAD(cpufreq_governor_list);
static DEFINE_MUTEX(cpufreq_governor_mutex);
29.
函数:
/**
* cpufreq_parse_governor - parse a governor string
*/
static int cpufreq_parse_governor(char *str_governor, unsigned int *policy,
struct cpufreq_governor **governor)
参数:
返回值:governor:str_governor对应的 cpufreq_governor结构
policy:如果governor是 performance,或者 powersave,则指示,在policy中返回
功能: parse a governor string
调用模块:
执行流程:
如果str_governor是“performance”,那么policy是CPUFREQ_POLICY_PERFORMANCE
如果str_governor是 "powersave", 那么policy是CPUFREQ_POLICY_POWERSAVE
否则,
获得cpufreq_governor_list保护的锁cpufreq_governor_mutex //mutex_lock
在cpufreq_governor_list上寻找名字为str_governor的governor //__find_governor
如果没有找到,则
放弃cpufreq_governor_mutex锁//mutex_unlock
try to load a kernel module //cpufreq_##str_governor
获得cpufreq_governor_list保护的锁cpufreq_governor_mutex //mutex_lock
在cpufreq_governor_list上寻找名字为str_governor的governor //__find_governor
如果找到了,则保存在governor中
放弃cpufreq_governor_mutex锁//mutex_unlock
返回
30.
函数:
/**
* show_cpuinfo_cur_freq - current CPU frequency as detected by hardware
*/
static ssize_t show_cpuinfo_cur_freq(struct cpufreq_policy *policy,
char *buf)
参数:
返回值:
功能:
调用模块:
执行流程:
获得cpu对应的CPU的实际运行频率 保存到 ret_freq,若实际运行频率和policy->cur
不一致则,依据实际频率调整 policy 的参数。 //__cpufreq_get
显示CPU的实际运行频率
31.
函数:static unsigned int __cpufreq_get(unsigned int cpu)
参数:
返回值:
功能: 获得cpu对应的CPU的实际运行频率 保存到 ret_freq,若实际运行频率和policy->cur
不一致则,依据实际频率调整 policy 的参数。
调用模块:
执行流程:
获得cpufreq_policy类型cpufreq_cpu_data变量 //
获得cpu对应的CPU的实际运行频率 保存到 ret_freq //cpufreq_driver->get
如果CPU的实际运行频率 ret_freq 和系统"认为的“运行频率policy->cur不一致
则, call notifier chain and adjust_jiffies on frequency transition //cpufreq_out_of_sync
put work task ‘handle_update’ in global workqueue //schedule_work(&policy->update);
//handle_update 将会re-evaluate an existing cpufreq policy
32. ******** 时钟相关
函数:
/**
* cpufreq_out_of_sync - If actual and saved CPU frequency differs, we're in deep trouble.
* @cpu: cpu number
* @old_freq: CPU frequency the kernel thinks the CPU runs at
* @new_freq: CPU frequency the CPU actually runs at
*
* We adjust to current frequency first, and need to clean up later.
* So either call to cpufreq_update_policy() or schedule handle_update()).
*/
static void cpufreq_out_of_sync(unsigned int cpu, unsigned int old_freq,
unsigned int new_freq);
参数:
返回值:
功能: call notifier chain and adjust_jiffies on frequency transition
调用模块:
执行流程:
call notifier chain and adjust_jiffies on frequency transition //cpufreq_notify_transition
33.
函数:static void handle_update(struct work_struct *work) //
参数:
返回值:
功能: re-evaluate an existing cpufreq policy
调用模块:
执行流程:
re-evaluate an existing cpufreq policy // cpufreq_update_policy
----------
INIT_WORK(&policy->update, handle_update); //初始化
put work task ‘handle_update’ in global workqueue//schedule_work(&policy->update);
//handle_update 将会re-evaluate an existing cpufreq policy
34.
函数:
/**
* cpufreq_get - get the current CPU frequency (in kHz)
* @cpu: CPU number
*
* Get the CPU current (static) CPU frequency
*/
unsigned int cpufreq_get(unsigned int cpu);
参数:
返回值:
功能: get the current CPU frequency (in kHz)
调用模块:
执行流程:
取得cpufreq_policy 类型的cpufreq_cpu_data的副本,对cpufreq_cpu_data引用计数增一 //cpufreq_cpu_get
获取读锁cpu_policy_rwsem//lock_policy_rwsem_read
获得cpu对应的CPU的实际运行频率 保存到 ret_freq,若实际运行频率和policy->cur
不一致则,依据实际频率调整 policy 的参数。 // __cpufreq_get
释放读锁cpu_policy_rwsem//unlock_policy_rwsem_read
对cpufreq_policy* 类型data所指向的结构的引用计数减一//cpufreq_cpu_put
35.
函数:
/**
* cpufreq_quick_get - get the CPU frequency (in kHz) from policy->cur
* @cpu: CPU number
*
* This is the last known freq, without actually getting it from the driver.
* Return value will be same as what is shown in scaling_cur_freq in sysfs.
*/
unsigned int cpufreq_quick_get(unsigned int cpu);
参数:
返回值:
功能: get the CPU frequency (in kHz) from policy->cur
//This is the last known freq getted from the driver.
调用模块:
执行流程:
取得cpufreq_policy 类型的cpufreq_cpu_data的副本,
对cpufreq_cpu_data引用计数增一//cpufreq_cpu_get
ret_freq = policy->cur
对cpufreq_policy* 类型data所指向的结构的引用计数减一//cpufreq_cpu_put
36.
函数:
/**
* show_scaling_governor - show the current policy for the specified CPU
*/
static ssize_t show_scaling_governor(struct cpufreq_policy *policy, char *buf);
参数:
返回值:
功能: show the current policy for the specified CPU
调用模块:
执行流程:
37.
函数:
/**
* store_scaling_governor - store policy for the specified CPU
*/
static ssize_t store_scaling_governor(struct cpufreq_policy *policy,
const char *buf, size_t count);
参数:
返回值:
功能: store policy for the specified CPU
调用模块:
执行流程:
取得cpufreq_policy 类型的cpufreq_cpu_data的副本,
对cpufreq_cpu_data引用计数增一//cpufreq_get_policy
得到要设置的governor的名字 //sscanf
parse a governor string //cpufreq_parse_governor
设置新的policy //__cpufreq_set_policy
更新policy//policy->user_policy.policy = policy->policy;
更新governor //policy->user_policy.governor = policy->governor;
38.
函数:
/**
* show_scaling_driver - show the cpufreq driver currently loaded
*/
static ssize_t show_scaling_driver(struct cpufreq_policy *policy, char *buf);
39.
函数:
/**
* show_scaling_available_governors - show the available CPUfreq governors
*/
static ssize_t show_scaling_available_governors(struct cpufreq_policy *policy,
char *buf);
40.
函数:static ssize_t show_cpus(const struct cpumask *mask, char *buf)
功能:
显示在mask中的CPU //for_each_cpu(cpu, mask)
41.
函数:
/**
* show_related_cpus - show the CPUs affected by each transition even if
* hw coordination is in use
*/
static ssize_t show_related_cpus(struct cpufreq_policy *policy, char *buf);
42:
函数:
/**
* show_affected_cpus - show the CPUs affected by each transition
*/
static ssize_t show_affected_cpus(struct cpufreq_policy *policy, char *buf);
43.
函数:
static ssize_t store_scaling_setspeed(struct cpufreq_policy *policy,
const char *buf, size_t count)
功能: 设置新的CPU运行频率//policy->governor->store_setspeed(policy, freq)
44.
函数:
static ssize_t show_scaling_setspeed(struct cpufreq_policy *policy, char *buf)
功能 : 显示CPU运行频率//policy->governor->show_setspeed(policy, buf);
45.
函数:
/**
* show_scaling_driver - show the current cpufreq HW/BIOS limitation
*/
static ssize_t show_bios_limit(struct cpufreq_policy *policy, char *buf);
46.
函数:
/**
* cpufreq_add_dev - add a CPU device
*
* Adds the cpufreq interface for a CPU device.
*
* The Oracle says: try running cpufreq registration/unregistration concurrently
* with with cpu hotplugging and all hell will break loose. Tried to clean this
* mess up, but more thorough testing is needed. - Mathieu
*/
static int cpufreq_add_dev(struct sys_device *sys_dev);
参数:
返回值:
功能: Adds the cpufreq interface for a CPU device.
调用模块:
执行流程:
检查cpu号CPU是否可以调度(检查cpu是否在cpu_online_mask中)//cpu_is_offline
如果不能调度,则返回
取得cpufreq_policy 类型的cpufreq_cpu_data的副本,
对cpufreq_cpu_data引用计数增一//cpufreq_cpu_get
如果已经有其他CPU注册了该CPU设备,
则 对cpufreq_policy* 类型data所指向的结构的引用计数减一//cpufreq_cpu_put
返回
如果cpufreq_driver->owner模块已经插入内核,则递增该模块引用计数;
如果该模块还没有插入内核,则对try_module_get调用返回0//try_module_get
allocate a struct cpumask ,并把policy->cpus指向该变量 //alloc_cpumask_var
allocate a struct cpumask,结构清零,并把policy->related_cpus//zalloc_cpumask_var
policy->cpu 初始化为sys_dev->id // sys_dev->id
初始化policy->cpus,仅仅设置和cpu相关的bit位 //cpumask_copy,cpumask_of
暂时把当前cpu设置为policy cpu // per_cpu(cpufreq_policy_cpu, cpu) = cpu;
获取写锁cpu_policy_rwsem //lock_policy_rwsem_write, 该函数的参数为 policy cpu的号
初始化 ** *//init_completion,INIT_WORK
查找是否有其他CPU x 注册了cpu freq policy,而且当前cpu也在它的related_cpus中
如果找到了,则 使用已经CPU x注册在policy中的 governor初始化本policy的governor域
如果没有找到,则使用默认的governor
调用driver的 init方法
policy->user_policy.min = policy->min;
policy->user_policy.max = policy->max;
通告注册在cpufreq_policy_notifier_list上的所有监听者
CPUFREQ_START //blocking_notifier_call_chain ????表达的什么信息呢??policy改变吗??
//这要看接收到消息的监听者注册的函数了:
用policy的cpus域更新每个每个处在policy->cpus中的cpu对应的policy的cpus域,
并在sys_dev对应的文件夹(cpux????)下创建符号链接“cpufreq”
// cpufreq_add_dev_policy ????????????
在cpuX下,创建‘cpufreq’文件夹,在文件夹下创建跟driver相关的控制文件,
统一policy->cpus中的cpu的当前policy为 poliy,policy cpu 为policy->cpu
在cpu对应的文件‘cpuX' 下,创建 policy对应的文件'cpufreq'的符号链接 //cpufreq_add_dev_interface
释放写锁cpu_policy_rwsem //unlock_policy_rwsem_write
向用户空间通知 cpufreq文件可用(policy->kobj)//kobject_uevent
cpufreq_driver->owner模块引用计数减一 //module_put
47.
函数:
/*
* Returns:
* Negative: Failure
* 0: Success
* Positive: When we have a managed CPU and the sysfs got symlinked
*/
static int cpufreq_add_dev_policy(unsigned int cpu,
struct cpufreq_policy *policy,
struct sys_device *sys_dev);
参数:
返回值:
功能: 用policy的cpus域更新每个每个处在policy->cpus中的cpu对应的policy的cpus域,
并在sys_dev对应的文件夹(cpux????)下创建符号链接“cpufreq” //???????????????
调用模块:
执行流程:
找到cpufreq_governor_list上名为cpufreq_cpu_governor的governor
//cpufreq_cpu_governor ,__find_governor
用找到的governor初始化policy->governor//这样会把cpufreq_add_dev中对该域的初始化值覆盖
对于 policy->cpus中的除了自身外的每个cpu执行如下操作:
取得对应于cpu的cpufreq_policy 类型的cpufreq_cpu_data的副本,
即,该cpu的当前 cpufreq_policy , 并对cpufreq_cpu_data引用计数增一 //cpufreq_cpu_get
释放写锁cpu_policy_rwsem//unlock_policy_rwsem_write; lock_policy_rwsem_write在那里调用了????
对cpufreq_policy_cpu 赋值为 cpufreq_add_dev调用时,写入policy->cpu的值//
获得cpu_policy_rwsem写锁 //lock_policy_rwsem_write ********** 没有释放锁
如果调用失败,则
调用cpufreq_driver->exit(policy)//??????什么作用
对cpufreq_policy* 类型 managed_policy所指向的结构的引用计数减一 //cpufreq_cpu_put
获得cpufreq_driver_lock锁//spin_lock_irqsave
把 policy->cpus复制到managed_policy->cpus // ******************
把cpufreq_cpu_data赋值为 managed_policy//
释放cpufreq_driver_lock锁,并恢复中断标志 //spin_unlock_irqrestore
在sys_dev->kobj("cpuX????")下创建指向managed_policy->kobj(cpufreq)的
符号链接文件cpufreq //sysfs_create_link *****************
对cpufreq_policy* 类型 managed_policy所指向的结构的引用计数减一 //cpufreq_cpu_put
cpufreq_driver->exit(policy)//??????? *************
48.
函数:
static int cpufreq_add_dev_interface(unsigned int cpu,
struct cpufreq_policy *policy,
struct sys_device *sys_dev);
参数:
返回值:
功能: 在cpuX下,创建‘cpufreq’文件夹,在文件夹下创建跟driver相关的控制文件,
统一policy->cpus中的cpu的当前policy为 poliy,policy cpu 为policy->cpu
在cpu对应的文件‘cpuX' 下,创建 policy对应的文件'cpufreq'的符号链接
调用模块:
执行流程:
在sys_dev下创建 cpufreq文件夹 //kobject_init_and_add
在cpufreq下创建跟driver属性相关的控制文件//sysfs_create_file
在cpufreq下创建跟driver成员函数相关的控制文件//sysfs_create_file
得到锁cpufreq_driver_lock//spin_lock_irqsave
对于每个处于policy->cpus中的cpu,执行如下操作:
如果cpu在线,则
更新它的cpufreq_cpu_data(每个cpu的当前policy结构的指针)
更新它的cpufreq_policy_cpu
释放锁cpufreq_driver_lock//spin_unlock_irqrestore
在cpu对应的文件‘cpuX' 下,创建 policy对应的文件'cpufreq'的
符号链接//cpufreq_add_dev_symlink
将new_policy备份到policy中//memcpy
设置新的policy //__cpufreq_set_policy
policy->user_policy.policy = policy->policy;
policy->user_policy.governor = policy->governor;
49.
函数:
/* symlink affected CPUs */
static int cpufreq_add_dev_symlink(unsigned int cpu,
struct cpufreq_policy *policy);
参数:
返回值:
功能: 在cpu对应的文件‘cpuX' 下,创建 policy对应的文件'cpufreq'的符号链接
调用模块:
执行流程:
对于 policy->cpus中的每个cpu执行如下操作: //for_each_cpu
取得cpufreq_policy 类型的cpufreq_cpu_data的副本,
对cpufreq_cpu_data引用计数增一//cpufreq_cpu_get
获得cpu对应的sys_device //get_cpu_sysdev
在‘cpuX‘下创建'cpufreq'文件的符号链接//sysfs_create_link
50
函数:static int cpufreq_remove_dev(struct sys_device *sys_dev)
参数:
返回值:
功能:
调用模块:
执行流程:
得到写锁cpu_policy_rwsem//lock_policy_rwsem_write
//__cpufreq_remove_dev
51.
函数:
/**
* __cpufreq_remove_dev - remove a CPU device
*
* Removes the cpufreq interface for a CPU device.
* Caller should already have policy_rwsem in write mode for this CPU.
* This routine frees the rwsem before returning.
*/
static int __cpufreq_remove_dev(struct sys_device *sys_dev);
参数:
返回值:
功能: remove CPU device //可能被递归调用
调用模块:
执行流程:
获得cpufreq_driver_lock锁 //spin_lock_irqsave
获得cpufreq_cpu_data保存在data中,即当前policy结构的指针
cpufreq_cpu_data置为空
如果,当前cpu不是 data->cpu 那么,
将cpu 从data->cpus 中清除 //cpumask_clear_cpu
释放锁,并恢复中断标志 //spin_unlock_irqrestore
对cpufreq_policy* 类型data所指向的结构的引用计数减一//cpufreq_cpu_put
释放写锁cpu_policy_rwsem//unlock_policy_rwsem_write
把cpuX下的cpufreq文件删除 //sysfs_remove_link
把删除的cpu的governor保存到cpufreq_cpu_governor
若还有其他cpu共用该policy //cpumask_weight
那么,把每个相关的cpu的cpufreq_cpu_data置为空
//cpufreq_cpu_data每个cpu的当前policy结构的指针
释放cpufreq_driver_lock锁 //spin_unlock_irqrestore
对于还有其他cpu共用该policy的情况,
把data->governor->name保存到每个cpu的cpufreq_cpu_governor
获得与cpu相关的cpu 设备的sys_device变量//get_cpu_sysdev
释放与cpu相关的写锁cpu_policy_rwsem//unlock_policy_rwsem_write
把cpuX下的cpufreq文件删除 //sysfs_remove_link
取得与cpu相关的写锁cpu_policy_rwsem//lock_policy_rwsem_write
对cpufreq_policy* 类型data所指向的结构的引用计数减一 //cpufreq_cpu_put
使用policy处理event事件(CPUFREQ_GOV_STOP),卸载模块 //__cpufreq_governor
//cmp = &data->kobj_unregister ???? what's this used for
释放与cpu相关的写锁cpu_policy_rwsem//unlock_policy_rwsem_write
释放policy对象//kobject_put
调用data->kobj_unregister,并等待 //wait_for_completion
调用cpufreq_driver->exit //?????????????,可以通过读实际的driver代码,看到底完成什么工作
对于还有其他cpu共用该policy的情况,
when the CPU which is the parent of the kobj is hotplugged
offline, check for siblings, and create cpufreq sysfs interface
and symlinks //cpumask_clear_cpu, cpufreq_add_dev, get_cpu_sysdev, cpumask_first
取得与cpu相关的写锁cpu_policy_rwsem// lock_policy_rwsem_write
递归调用// __cpufreq_remove_dev
释放policy相关的动态分配的内存//free_cpumask_var, free_cpumask_var, kfree
---------相关的宏和用到的数据结构
static struct notifier_block __refdata cpufreq_cpu_notifier = {
.notifier_call = cpufreq_cpu_callback,
};
struct notifier_block {
int (*notifier_call)(struct notifier_block *, unsigned long, void *);
struct notifier_block __rcu *next;
int priority;
};
-----=-
#define CPUFREQ_GOV_START 1 //This governor shall start its duty for the CPU policy->cpu
#define CPUFREQ_GOV_STOP 2 //This governor shall end its duty for the CPU
#define CPUFREQ_GOV_LIMITS 3 //The limits for CPU policy->cpu have changed to policy->min and policy->max
struct cpufreq_governor {
char name[CPUFREQ_NAME_LEN]; //
int (*governor) (struct cpufreq_policy *policy, //在__cpufreq_governor中被调用。
ssize_t (*show_setspeed) (struct cpufreq_policy *policy,
char *buf); //用户空间显示CPU运行频率时调用
int (*store_setspeed) (struct cpufreq_policy *policy,
unsigned int freq); //用户空间设置频率时调用
unsigned int max_transition_latency; /* HW must be able to switch to
next freq faster than this value in nano secs or we
will fallback to performance governor */
struct list_head governor_list;
struct module *owner;
};
129 static LIST_HEAD(cpufreq_governor_list);
130 static DEFINE_MUTEX(cpufreq_governor_mutex);
#define CPUFREQ_RELATION_L 0 /* lowest frequency at or above target */
#define CPUFREQ_RELATION_H 1 /* highest frequency below or at target */
struct cpufreq_cpuinfo { //该结构内成员值,由driver负责填写
unsigned int max_freq; //the minimum and maximum frequency (in kHz) which is supported by this CPU
unsigned int min_freq;
/* in 10^(-9) s = nanoseconds */
unsigned int transition_latency; //the time it takes on this CPU to switch between two frequencies innanoseconds
// (if appropriate, else specify CPUFREQ_ETERNAL)
};
struct cpufreq_policy {
cpumask_var_t cpus; /* CPUs requiring sw coordination */ // CPUs affected by each transition
//在添加CPU设备时,在cpufreq_add_dev分配空间,并初始化
//List of CPUs that require software coordination of frequency.
cpumask_var_t related_cpus; /* CPUs with any coordination */ // the CPUs affected by each transition
// List of CPUs that need some sort of frequency
// coordination, whether software or hardware.
unsigned int shared_type; /* ANY or ALL affected CPUs
should set cpufreq */
unsigned int cpu; /* cpu nr of registered CPU */ //在cpufreq_add_dev中被赋值为sys_dev->id
struct cpufreq_cpuinfo cpuinfo;/* see above */ 14
unsigned int min; /* in kHz */ //由 driver负责填写
unsigned int max; /* in kHz */ //由 driver负责填写
unsigned int cur; /* in kHz, only needed if cpufreq //系统认为的,cpu的运行频率(但是有
可能不是CPU真正的运行频率,CPU真正的运行频率,可调用cpufreq_driver结构的
get成员函数获得 ) //由 driver负责填写
* governors are used */
unsigned int policy; /* see above */ // must contain the "default policy" for this CPU.
// CPUFREQ_POLICY_POWERSAVE, powersave policy
//CPUFREQ_POLICY_PERFORMANCE, performance
//other policy
//由 driver负责填写
struct cpufreq_governor *governor; /* see below */ //A few moments later, cpufreq_driver.verify and either
//cpufreq_driver.setpolicy or cpufreq_driver.target is called with
//these values.
//可以是CPUFREQ_DEFAULT_GOVERNOR
//由 driver负责填写
struct work_struct update; /* if update_policy() needs to be
* called, but you're in IRQ context */ //__cpufreq_get 调用了, 在 cpufreq_add_dev中初始化
struct cpufreq_real_policy user_policy; // 在cpufreq_update_policy用到,在store_scaling_governor中被设置
//保存了用户设置的policy的相关参数??
struct kobject kobj;
struct completion kobj_unregister;//在 cpufreq_add_dev中初始化,
//__cpufreq_remove_dev调用,确保在调用cpufreq_driver->exit前,
//没有对kobj的其他引用???
};
struct cpufreq_real_policy { //
unsigned int min; /* in kHz */
unsigned int max; /* in kHz */
unsigned int policy; /* see above */
struct cpufreq_governor *governor; /* see below */
};
struct cpufreq_driver {
struct module *owner; //
char name[CPUFREQ_NAME_LEN];
u8 flags; //CPUFREQ_CONST_LOOPS, CPUFREQ_STICKY, CPUFREQ_PM_NO_WARN
/* needed by all drivers */
int (*init) (struct cpufreq_policy *policy);//A pointer to the per-CPU initialization function.
int (*verify) (struct cpufreq_policy *policy); //A pointer to a "verification" function.
/* define one out of two */
int (*setpolicy) (struct cpufreq_policy *policy);
int (*target) (struct cpufreq_policy *policy,
unsigned int target_freq,
unsigned int relation); // 如果target没有定义的话,那么只有performance powersave可用????
/* should be defined, if possible */
unsigned int (*get) (unsigned int cpu); //返回的值是当前号为cpu的CPU的真正频率
//__cpufreq_get 中有调用
/* optional */
unsigned int (*getavg) (struct cpufreq_policy *policy,
unsigned int cpu); ///?????????????
int (*bios_limit) (int cpu, unsigned int *limit); // show the current cpufreq HW/BIOS limitation
int (*exit) (struct cpufreq_policy *policy); //A pointer to a per-CPU cleanup function
int (*suspend) (struct cpufreq_policy *policy);// re-evaluate an existing cpufreq policy //cpufreq_update_policy中用到了
int (*resume) (struct cpufreq_policy *policy);//A pointer to a per-CPU resume function which is called with interrupts disabled
//and _before_ the pre-suspend frequency and/or policy is restored by a call to ->target or ->setpolicy
struct freq_attr **attr; //A pointer to a NULL-terminated list of "struct freq_attr" which allow to export values to sysfs.
};
static struct cpufreq_driver *cpufreq_driver; //<-------------------------------------------<<<<<<<<<<<<<driver 的统一调用接口???
static DEFINE_PER_CPU(struct cpufreq_policy *, cpufreq_cpu_data); //存放了每个cpu的当前policy结构的指针
static DEFINE_SPINLOCK(cpufreq_driver_lock); //用来保护cpufreq_driver结构
/*
* cpu_policy_rwsem is a per CPU reader-writer semaphore designed to cure
* all cpufreq/hotplug/workqueue/etc related lock issues.
*
* The rules for this semaphore:
* - Any routine that wants to read from the policy structure will
* do a down_read on this semaphore.
* - Any routine that will write to the policy structure and/or may take away
* the policy altogether (eg. CPU hotplug), will hold this lock in write
* mode before doing so.
*
* Additional rules:
* - All holders of the lock should check to make sure that the CPU they
* are concerned with are online after they get the lock.
* - Governor routines that can be called in cpufreq hotplug path should not
* take this sem as top level hotplug notifier handler takes this.
* - Lock should not be held across
* __cpufreq_governor(data, CPUFREQ_GOV_STOP);
*/
static DEFINE_PER_CPU(int, cpufreq_policy_cpu); // policy cpu, 设置policy时所在的cpu
static DEFINE_PER_CPU(struct rw_semaphore, cpu_policy_rwsem);
--------------------------------------------------------------------------------------------------------
------------------------------------------ 关于for_each_possible_cpu
for_each_possible_cpu(cpu) {
per_cpu(cpufreq_policy_cpu, cpu) = -1;//对cpufreq_policy_cpu赋值为-1
init_rwsem(&per_cpu(cpu_policy_rwsem, cpu));//初始化semaphore
}
//添加一个 for头和一个struct cpumask类型的变量cpu_possible_mask,该变量用于?????
//
#define for_each_possible_cpu(cpu) for_each_cpu((cpu), cpu_possible_mask)
/**
* for_each_cpu - iterate over every cpu in a mask
* @cpu: the (optionally unsigned) integer iterator
* @mask: the cpumask pointer
*
* After the loop, cpu is >= nr_cpu_ids.
*/
#define for_each_cpu(cpu, mask) \
for ((cpu) = -1; \
(cpu) = cpumask_next((cpu), (mask)), \
(cpu) < nr_cpu_ids;)
/**
* cpumask_next - get the next cpu in a cpumask
* @n: the cpu prior to the place to search (ie. return will be > @n)
* @srcp: the cpumask pointer
*
* Returns >= nr_cpu_ids if no further cpus set.
*/
static inline unsigned int cpumask_next(int n, const struct cpumask *srcp)
{
/* -1 is a legal arg here. */
if (n != -1)
cpumask_check(n);
return find_next_bit(cpumask_bits(srcp), nr_cpumask_bits, n+1);
}
/* verify cpu argument to cpumask_* operators */
static inline unsigned int cpumask_check(unsigned int cpu)
{
#ifdef CONFIG_DEBUG_PER_CPU_MAPS
WARN_ON_ONCE(cpu >= nr_cpumask_bits);
#endif /* CONFIG_DEBUG_PER_CPU_MAPS */
return cpu;
}
/*
* Find the next set bit in a memory region.
*/
unsigned long find_next_bit(const unsigned long *addr, unsigned long size,
unsigned long offset)
{
const unsigned long *p = addr + BITOP_WORD(offset);
unsigned long result = offset & ~(BITS_PER_LONG-1);
unsigned long tmp;
if (offset >= size)
return size;
size -= result;
offset %= BITS_PER_LONG;
if (offset) {
tmp = *(p++);
tmp &= (~0UL << offset);
if (size < BITS_PER_LONG)
goto found_first;
if (tmp)
goto found_middle;
size -= BITS_PER_LONG;
result += BITS_PER_LONG;
}
while (size & ~(BITS_PER_LONG-1)) {
if ((tmp = *(p++)))
goto found_middle;
result += BITS_PER_LONG;
size -= BITS_PER_LONG;
}
if (!size)
return result;
tmp = *p;
found_first:
tmp &= (~0UL >> (BITS_PER_LONG - size));
if (tmp == 0UL) /* Are any bits set? */
return result + size; /* Nope. */
found_middle:
return result + __ffs(tmp);
}
//创建一个能容纳CONFIG_NR_CPUS个bit位的long类型的数组,并转为为struct cpumask
//类型返回给cpu_possible_mask
//总之,就是得到cpu_possible_mask,它是一个struct cpumask类型
const struct cpumask *const cpu_possible_mask = to_cpumask(cpu_possible_bits);
//to_cpumask 把数组bitmap转化为struct cpumask类型
#define to_cpumask(bitmap) \
((struct cpumask *)(1 ? (bitmap) \
: (void *)sizeof(__check_is_bitmap(bitmap))))
static inline int __check_is_bitmap(const unsigned long *bitmap)
{
return 1;
}
typedef struct cpumask { DECLARE_BITMAP(bits, NR_CPUS); } cpumask_t;//结构体cpumask含有一个成员,
//该成员是一个能够容纳bits个bit位的名为name的long类型的数组
#define DECLARE_BITMAP(name,bits) \ //创建一个能够容纳bits个bit位的名为name的long类型的数组
unsigned long name[BITS_TO_LONGS(bits)]
--------------------------------------
#define BITS_TO_LONGS(nr) DIV_ROUND_UP(nr, BITS_PER_BYTE * sizeof(long)) //取得bit数除以long所占的bit数的向上取整
#define DIV_ROUND_UP(n,d) (((n) + (d) - 1) / (d))
#define BITS_PER_BYTE 8
----
// cpu_possible_bits是一个long类型数组
#ifdef CONFIG_INIT_ALL_POSSIBLE
static DECLARE_BITMAP(cpu_possible_bits, CONFIG_NR_CPUS) __read_mostly
= CPU_BITS_ALL;
#else
static DECLARE_BITMAP(cpu_possible_bits, CONFIG_NR_CPUS) __read_mostly;
#endif
----------per_cpu //取得per cpu变量 var在CPU号cpu上的副本
/*
* A percpu variable may point to a discarded regions. The following are
* established ways to produce a usable pointer from the percpu variable
* offset.
*/
#define per_cpu(var, cpu) \
(*SHIFT_PERCPU_PTR(&(var), per_cpu_offset(cpu)))
/*
* Add a offset to a pointer but keep the pointer as is.
*
* Only S390 provides its own means of moving the pointer.
*/
/* Weird cast keeps both GCC and sparse happy. */
#define SHIFT_PERCPU_PTR(__p, __offset) ({ \
__verify_pcpu_ptr((__p)); \
RELOC_HIDE((typeof(*(__p)) __kernel __force *)(__p), (__offset)); \
})
/*
* This macro obfuscates arithmetic on a variable address so that gcc
* shouldn't recognize the original var, and make assumptions about it.
*
* This is needed because the C standard makes it undefined to do
* pointer arithmetic on "objects" outside their boundaries and the
* gcc optimizers assume this is the case. In particular they
* assume such arithmetic does not wrap.
*
* A miscompilation has been observed because of this on PPC.
* To work around it we hide the relationship of the pointer and the object
* using this macro.
*
* Versions of the ppc64 compiler before 4.1 had a bug where use of
* RELOC_HIDE could trash r30. The bug can be worked around by changing
* the inline assembly constraint from =g to =r, in this particular
* case either is valid.
*/
#define RELOC_HIDE(ptr, off) \ //
({ unsigned long __ptr; \
__asm__ ("" : "=r"(__ptr) : "0"(ptr)); \
(typeof(ptr)) (__ptr + (off)); })
/*
* per_cpu_offset() is the offset that has to be added to a <------------------<<<<< per_cpu_offset
* percpu variable to get to the instance for a certain processor.
*
* Most arches use the __per_cpu_offset array for those offsets but
* some arches have their own ways of determining the offset (x86_64, s390).
*/
extern unsigned long __per_cpu_offset[NR_CPUS];
#define per_cpu_offset(x) (__per_cpu_offset[x])
/// x86_64
#include <asm/trap_block.h>
#define __per_cpu_offset(__cpu) \
(trap_block[(__cpu)].__per_cpu_base)
#define per_cpu_offset(x) (__per_cpu_offset(x))
#define __my_cpu_offset __local_per_cpu_offset
struct trap_per_cpu trap_block[NR_CPUS];
///end of x86_64
--------------------------------- for_each_present_cpu //添加一个 for头和一个struct cpumask类型的变量 cpu_present_mask,该变量用于?????
#define for_each_present_cpu(cpu) for_each_cpu((cpu), cpu_present_mask)
//总之,就是得到cpu_present_mask,它是一个struct cpumask类型
static DECLARE_BITMAP(cpu_present_bits, CONFIG_NR_CPUS) __read_mostly;
const struct cpumask *const cpu_present_mask = to_cpumask(cpu_present_bits);
---------------- cpu_online(cpu) //检查cpu号CPU是否可以调度(检查cpu是否在cpu_online_mask中)
/*
* The following particular system cpumasks and operations manage
* possible, present, active and online cpus.
*
* cpu_possible_mask- has bit 'cpu' set iff cpu is populatable
* cpu_present_mask - has bit 'cpu' set iff cpu is populated
* cpu_online_mask - has bit 'cpu' set iff cpu available to scheduler
* cpu_active_mask - has bit 'cpu' set iff cpu available to migration
*
* If !CONFIG_HOTPLUG_CPU, present == possible, and active == online.
*
* The cpu_possible_mask is fixed at boot time, as the set of CPU id's
* that it is possible might ever be plugged in at anytime during the
* life of that system boot. The cpu_present_mask is dynamic(*),
* representing which CPUs are currently plugged in. And
* cpu_online_mask is the dynamic subset of cpu_present_mask,
* indicating those CPUs available for scheduling.
*
* If HOTPLUG is enabled, then cpu_possible_mask is forced to have
* all NR_CPUS bits set, otherwise it is just the set of CPUs that
* ACPI reports present at boot.
*
* If HOTPLUG is enabled, then cpu_present_mask varies dynamically,
* depending on what ACPI reports as currently plugged in, otherwise
* cpu_present_mask is just a copy of cpu_possible_mask.
*
* (*) Well, cpu_present_mask is dynamic in the hotplug case. If not
* hotplug, it's a copy of cpu_possible_mask, hence fixed at boot.
*
* Subtleties:
* 1) UP arch's (NR_CPUS == 1, CONFIG_SMP not defined) hardcode
* assumption that their single CPU is online. The UP
* cpu_{online,possible,present}_masks are placebos. Changing them
* will have no useful affect on the following num_*_cpus()
* and cpu_*() macros in the UP case. This ugliness is a UP
* optimization - don't waste any instructions or memory references
* asking if you're online or how many CPUs there are if there is
* only one CPU.
*/
#define cpu_online(cpu) cpumask_test_cpu((cpu), cpu_online_mask)//检查cpu是否在cpu_online_mask中
typedef struct cpumask { DECLARE_BITMAP(bits, NR_CPUS); } cpumask_t;//结构体cpumask含有一个成员,
//该成员是一个能够容纳bits个bit位的名为bits的long类型的数组
static DECLARE_BITMAP(cpu_online_bits, CONFIG_NR_CPUS) __read_mostly;
const struct cpumask *const cpu_online_mask = to_cpumask(cpu_online_bits);
/**
* cpumask_test_cpu - test for a cpu in a cpumask //得到struct cpumask的bits域
* @cpu: cpu number (< nr_cpu_ids)
* @cpumask: the cpumask pointer
*
* No static inline type checking - see Subtlety (1) above.
*/
#define cpumask_test_cpu(cpu, cpumask) \
test_bit(cpumask_check(cpu), cpumask_bits((cpumask)))//如果小于cpu值小于CPU个数,得到struct cpumask 的bits域
//确保cpu值是有效的,即小于CPU个数,返回值为cpu
/* verify cpu argument to cpumask_* operators */
static inline unsigned int cpumask_check(unsigned int cpu)
{
#ifdef CONFIG_DEBUG_PER_CPU_MAPS
WARN_ON_ONCE(cpu >= nr_cpumask_bits); //确保cpu小于的CPU个数
#endif /* CONFIG_DEBUG_PER_CPU_MAPS */
return cpu;
}
/**
* cpumask_bits - get the bits in a cpumask
* @maskp: the struct cpumask *
*
* You should only assume nr_cpu_ids bits of this mask are valid. This is
* a macro so it's const-correct.
*/
#define cpumask_bits(maskp) ((maskp)->bits)
// 总之,nr_cpumask_bits 数值跟 NR_CPUS相同
#ifdef CONFIG_CPUMASK_OFFSTACK//Use dynamic allocation for cpumask_var_t, instead of putting them on the stack.
/* Assuming NR_CPUS is huge, a runtime limit is more efficient. Also,
* not all bits may be allocated. */
#define nr_cpumask_bits nr_cpu_ids //如果动态分配cpumask_var_t
#else
#define nr_cpumask_bits NR_CPUS //如果在栈上分配cpumask_var_t
#endif
------------------------test_bit
//如果addr的nr位为1,则返回1,否则,返回0
#define test_bit(nr,addr) \
(__builtin_constant_p(nr) ? \ //如果是内建常量?????
constant_test_bit((nr),(addr)) : \ //如果addr的nr位为1,则返回1,否则,返回0
variable_test_bit((nr),(addr)))
//如果addr的nr位为1,则返回1,否则,返回0
static __always_inline int constant_test_bit(unsigned int nr, const volatile unsigned long *addr)
{
return ((1UL << (nr % BITS_PER_LONG)) &
(addr[nr / BITS_PER_LONG])) != 0;
}
static inline int variable_test_bit(int nr, volatile const unsigned long *addr)
{
int oldbit;
asm volatile("bt %2,%1\n\t" //把 addr中指定的nr位的内容送到CF
"sbb %0,%0" //带借位减法,CF - 0 => oldbit
: "=r" (oldbit)
: "m" (*(unsigned long *)addr), "Ir" (nr));
return oldbit;
}