|
EDA365欢迎您登录!
您需要 登录 才可以下载或查看,没有帐号?注册
x
Linux动态频率调节系统CPUFreq之怎样注册一个cpufreq_driver驱动& P$ s$ n) d3 j7 \8 E8 P9 r
! }" w; H( _7 I7 C! D与governor不同,系统中只会存在一个cpufreq_driver驱动,根据上一篇Linux动态频率调节系统CPUFreq之概述的介绍,cpufreq_driver是平台相关的,负责最终实施频率的调整动作,而选择工作频率的策略是由governor完成的。所以,系统中只需要注册一个cpufreq_driver即可,它只负责知道如何控制该平台的时钟系统,从而设定由governor确定的工作频率。注册cpufreq_driver驱动会触发cpufreq核心的一系列额外的初始化动作,第一节所说的核心初始化工作非常简单,实际上,更多的初始化动作在注册cpufreq_driver阶段完成。核心提供了一个API:cpufreq_register_driver来完成注册工作。下面我们分析一下这个函数的工作过程:
/ {7 `8 M6 f# G9 q/ E; N. n# T% ^2 i+ i l' w- U9 n4 k
- int cpufreq_register_driver(struct cpufreq_driver *driver_data)
- {
- ......
! m g6 [1 z! l) r- {2 ~, P- if (cpufreq_disabled())
- return -ENODEV;
- . t7 J; X, \6 y" r$ H
- if (!driver_data || !driver_data->verify || !driver_data->init ||
- ((!driver_data->setpolicy) && (!driver_data->target)))
- return -EINVAL;# P y8 @+ d# N* o" K
* f6 W" H: ^% k( c& u" Q
# M2 P* I7 r1 n+ i- R0 [' {5 Q; [& ^
该API只有一个参数:一个cpufreq_driver指针,driver_data,该结构事先在驱动的代码中定义,调用该API时作为参数传入。函数先判断系统目前是否禁止了调频功能,然后检查cpufreq_driver的几个回调函数是否被实现,由代码可以看出,verify和init回调函数必须要实现,而setpolicy和target回调则至少要被实现其中的一个。这几个回调的作用请参考本系列的第一篇文章。接下来:% P2 |* r( }" z+ g: N( u
- 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);
# }5 G. m( |( K; {9 A4 J) \ 1 S. L; z' W ~& n( C7 T" L9 \, X# ?5 e
/ A) K3 f( [6 O$ Z J( T
检查全局变量cpufreq_driver是否已经被赋值,如果没有,则传入的参数被赋值给全局变量cpufreq_driver,从而保证了系统中只会注册一个cpufreq_driver驱动。然后:
# a6 `( i, W& U! U' Z* m3 B. q. M; h/ N
- ret = subsys_inteRFace_register(&cpufreq_interface);
-
- ......
- ......
- 5 U4 ~3 ?+ x9 o" ]
- register_hotcpu_notifier(&cpufreq_cpu_notifier);
& l- A: w( U* l d! V) w 9 `* o5 c, _$ b% W' C/ S, D
/ X& `3 I1 t, Q' O: `0 m: B
通过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的定义:
8 L% |# Q* d* `- c7 Y8 D* P- W6 d. G. `7 n4 U; r# w* a
- static struct subsys_interface cpufreq_interface = {
- .name = "cpufreq",
- .subsys = &cpu_subsys,
- .add_dev = cpufreq_add_dev,
- .remove_dev = cpufreq_remove_dev,
- };
* P% C- y2 _1 | 9 p5 `, q4 q3 u# |/ r
7 \+ ^. P7 l+ l2 y7 e( `
subsys_interface_register函数的代码我就不再展开了,它的大致作用就是:遍历子系统下面的每一个子设备,然后用这个子设备作为参数,调用cpufrq_interface结构的add_dev回调函数,这里的回调函数被指向了cpufreq_add_dev,它的具体工作方式我们在下一节中讨论。: W7 ^! m6 o7 Y8 q9 r% ^/ Z4 i% y
1 O! w& q. K1 U8 o" ]7 {driver注册完成后,驱动被保存在全局变量cpufreq_driver中,供核心层使用,同时,每个cpu也会建立自己的policy策略,governor也开始工作,实时地监控着cpu的负载并计算合适的工作频率,然后通过driver调整真正的工作频率。下图是cpufreq_driver注册过程的序列图:
% r/ z% g# t5 J- `- I* r* t- ^2 J2 C* Q2 q& ], S: H
+ m i7 b- o5 {% `1 S
9 b1 Q4 R# ~6 o& y
图 3.1 cpufreq_driver的注册过程
( O, ]5 \# c$ w! z
6 c4 B3 w u/ T! V, d$ O
8 y5 O! ~+ a3 K7 a9 E4 c' N4 i( O# }2 n
6 j0 A5 b+ u" H" Z- y: e2 l) g# Q( p& _0 G+ V
, u" i. _" S/ S* p& }$ K2 `4 ~
' y0 `2 \ q! n9 J
( C8 O) l/ B9 i8 U
5 V C: N T: @% I+ X
4 y3 p- @$ t& d m; Z/ G& I8 r+ l! o
|
|