|
|
EDA365欢迎您登录!
您需要 登录 才可以下载或查看,没有帐号?注册
x
Linux动态频率调节系统CPUFreq之怎样注册一个cpufreq_driver驱动
- h/ ~3 {4 w# S/ ]. h& M! S. V/ d2 ~2 r( G% `
与governor不同,系统中只会存在一个cpufreq_driver驱动,根据上一篇Linux动态频率调节系统CPUFreq之概述的介绍,cpufreq_driver是平台相关的,负责最终实施频率的调整动作,而选择工作频率的策略是由governor完成的。所以,系统中只需要注册一个cpufreq_driver即可,它只负责知道如何控制该平台的时钟系统,从而设定由governor确定的工作频率。注册cpufreq_driver驱动会触发cpufreq核心的一系列额外的初始化动作,第一节所说的核心初始化工作非常简单,实际上,更多的初始化动作在注册cpufreq_driver阶段完成。核心提供了一个API:cpufreq_register_driver来完成注册工作。下面我们分析一下这个函数的工作过程:" T. a/ J$ f6 V* q( K5 c- O: a
R' x- ?! _; e# n- int cpufreq_register_driver(struct cpufreq_driver *driver_data)
- {
- ......
- 9 D7 L0 H. C* P9 d- }
- if (cpufreq_disabled())
- return -ENODEV;
/ T, W* S/ C' V0 @3 _7 l7 d, W- if (!driver_data || !driver_data->verify || !driver_data->init ||
- ((!driver_data->setpolicy) && (!driver_data->target)))
- return -EINVAL;0 s) r" S0 g1 ?
' Q0 K) w {7 h) h
. T: Q& o; i1 d( _1 I7 l9 g该API只有一个参数:一个cpufreq_driver指针,driver_data,该结构事先在驱动的代码中定义,调用该API时作为参数传入。函数先判断系统目前是否禁止了调频功能,然后检查cpufreq_driver的几个回调函数是否被实现,由代码可以看出,verify和init回调函数必须要实现,而setpolicy和target回调则至少要被实现其中的一个。这几个回调的作用请参考本系列的第一篇文章。接下来:# ~# T2 l c0 d9 B
- write_lock_irqsave(&cpufreq_driver_lock, flags);
- if (cpufreq_driver) {
- write_unlock_irqrestore(&cpufreq_driver_lock, flags);
- return -EBUSY;
- }
- cpufreq_driver = driver_data;
- write_unlock_irqrestore(&cpufreq_driver_lock, flags);) u$ g8 p, @0 t/ R& a; a
6 q- J6 K. P T! A0 U
! h( |' b- p) S( r; V检查全局变量cpufreq_driver是否已经被赋值,如果没有,则传入的参数被赋值给全局变量cpufreq_driver,从而保证了系统中只会注册一个cpufreq_driver驱动。然后:. W9 a# l" U* ~5 x0 S+ s& {) o
* x! }! ^0 |: D7 \. ^- ret = subsys_inteRFace_register(&cpufreq_interface);
-
- ......
- ......
) y1 _5 m. L. ]4 E0 l4 q3 `- register_hotcpu_notifier(&cpufreq_cpu_notifier);+ k7 \- `, e# ]4 \& |
; ?4 {5 a9 U; p9 {" r/ Y2 Z( E& `: y/ K% h7 c/ n$ i8 i1 m* ^
通过subsys_interface_register给每一个cpu建立一个cpufreq_policy,最后注册cpu hot plug通知,以便在cpu hot plug的时候,能够动态地处理各个cpu policy之间的关系(比如迁移负责管理的cpu等等)。这里要重点讨论一下subsys_interface_register的过程,回到第一节的内容,我们知道初始化阶段,cpu_subsys被建立,从而每个cpu都会在cpu总线设备下建立一个属于自己的设备:sys/devices/system/cpu/cpux。subsys_interface_register负责在cpu_subsys子系统的子设备下面注册公共的接口。我们看看参数cpufreq_interface的定义:
" e& i- t& h, Z
2 H% R/ `; k6 c2 Y- static struct subsys_interface cpufreq_interface = {
- .name = "cpufreq",
- .subsys = &cpu_subsys,
- .add_dev = cpufreq_add_dev,
- .remove_dev = cpufreq_remove_dev,
- };
% r: u% G0 U) G0 ^ 3 V! @; g: P4 @6 M! b
& E2 H3 y2 W/ vsubsys_interface_register函数的代码我就不再展开了,它的大致作用就是:遍历子系统下面的每一个子设备,然后用这个子设备作为参数,调用cpufrq_interface结构的add_dev回调函数,这里的回调函数被指向了cpufreq_add_dev,它的具体工作方式我们在下一节中讨论。
# R" Q8 M9 {6 {
# H& d% ]1 ?, s' gdriver注册完成后,驱动被保存在全局变量cpufreq_driver中,供核心层使用,同时,每个cpu也会建立自己的policy策略,governor也开始工作,实时地监控着cpu的负载并计算合适的工作频率,然后通过driver调整真正的工作频率。下图是cpufreq_driver注册过程的序列图:3 y5 V) d" l* L$ l: k
/ j& `9 t( y: o% R
+ F) w( b j! E! K0 r3 w( T& Q3 B% m* A! W# h5 A- E
图 3.1 cpufreq_driver的注册过程
: R& s1 t* d2 m8 r
( o' `/ H) c9 A- r/ G6 h
{' k E, A- q, b/ }, X
; ~, i1 |6 }5 P4 X% v$ C5 k7 E/ ^ a$ M# L
8 ]% Y" \3 H- G+ ]1 g) x# a2 a
1 R) o7 o# P/ r5 ]% F3 l" ~: Y6 J0 \% P% _. ~; T
1 d" h2 D3 N, u# v
3 h, w9 X/ x) o; I% {1 S; M
2 b$ ^& N8 b7 z# p, S1 |" }# @! ^6 ?+ F3 B4 [
|
|