|
EDA365欢迎您登录!
您需要 登录 才可以下载或查看,没有帐号?注册
x
Linux动态频率调节系统CPUFreq之怎样为每个CPU建立频率调整策略(policy)) k/ w' Q T' k. J- g7 A8 d/ {
5 J k& m$ P; p+ e7 {0 S9 s/ N+ C8 X. G' H4 w2 Q+ d3 `. f
为每个cpu建立频率调整策略实在注册cpufreq_driver阶段的subsys_inteRFace_registe函数中完成的,上一节已经提到,该函数最终会调用cpufreq_add_dev回调函数,现在展开这个函数分析一下:
; F2 q5 }- x) o5 A4 F
; s* y+ t7 |( j因为subsys_interface_registe会枚举各个cpu设备,不管该cpu处于offline还是online状态,cpufreq_add_dev都会被调用,所以函数的一开始,判断如果cpu处于offline状态,直接返回。1 B$ I( T5 W- |/ \
8 k8 D; g/ ?8 S2 V! b6 W- static int cpufreq_add_dev(struct device *dev, struct subsys_interface *sif)
- {
- ......
0 M9 i) r( S# X- if (cpu_is_offline(cpu))
- return 0;
0 X& o2 u. M u- f% X
/ E2 ^* \3 C T5 {. Q% S% n0 o如果是smp系统,本cpu的policy可能和其他cpu共同使用同一个policy,并委托另一个叫做管理cpu的cpu进行管理,下面的代码判断这种情况,如果已经委托别的cpu管理,则直接返回,核心层定义了另一个per_cpu变量:cpufreq_cpu_data,用来保存各个cpu所使用的cpufreq_policy结构的指针,cpufreq_cpu_get函数实际上就是通过这个per_cpu变量,获取该指针,如果该指针非0,代表该cpu已经建立好了它自身的policy(可能是在他之前的管理cpu建立policy期间一并建立的)。
7 a: B+ {5 ^$ s: X3 k
, z7 ^- X& s, X! a6 H& o- policy = cpufreq_cpu_get(cpu);
- if (unlikely(policy)) {
- cpufreq_cpu_put(policy);
- return 0;
- }" C: S' ]) e$ n6 W7 E5 C
- [% r5 q n5 u( o
* x. L6 `: P2 B* d* G因为cpu hot plug期间,cpufreq_add_dev也会被调用,下面的代码片段检测该cpu之前是否被hot-unpluged过,如果是,找到其中一个相关的cpu(这些相关的cpu都委托给同一个托管它cpu进行管理,调用cpufreq_add_policy_cpu函数,该函数只是简单地建立一个cpufreq链接,链接到管理cpu的cpufreq节点。: |% L+ S2 Q6 f
4 b5 H( k7 l, I3 D6 \) g9 @5 b
- for_each_online_cpu(sibling) {
- struct cpufreq_policy *cp = per_cpu(cpufreq_cpu_data, sibling);
- if (cp && cpumask_test_cpu(cpu, cp->related_cpus)) {
- read_unlock_irqrestore(&cpufreq_driver_lock, flags);
- return cpufreq_add_policy_cpu(cpu, sibling, dev);
- }
- }
7 J* D0 }/ C0 @2 j) G/ X% D
4 A% H" U, I+ F3 i
" C( J! W, r7 V* c当这是系统初始化阶段第一次调用cpufreq_add_dev时(subsys_interface_register枚举到的第一个cpu,通常就是cpu0),cpufreq_cpu_data应该为NULL,所以我们要为这样的cpu分配一个cpufreq_policy结构,并初始化该policy所管理的cpu,包括online的cpus字段和online+offline的cpu_related字段,并把自己设置为这个policy的管理cpu,使用默认governor初始化policy->governor字段,同时吧自己加入到online的cpus字段中:) S3 t9 Z0 Y" I- O6 B/ t
( l M' I, o( O+ D) Q& a- s- policy = kzalloc(sizeof(struct cpufreq_policy), GFP_KERNEL);
- if (!policy)
- goto nomem_out;
- " q3 A% k1 @8 N" Z! Q8 \" ~+ y# A" g
- if (!alloc_cpumask_var(&policy->cpus, GFP_KERNEL))
- goto err_free_policy;
& J# @1 B, Z. T. s! f, R! S- if (!zalloc_cpumask_var(&policy->related_cpus, GFP_KERNEL))
- goto err_free_cpumask;
- " d4 p8 o/ }& r$ u8 P8 P
- policy->cpu = cpu;
- policy->governor = CPUFREQ_DEFAULT_GOVERNOR;
- cpumask_copy(policy->cpus, cpumask_of(cpu));
/ O0 H! C' r, u" Q& t7 L8 T* T2 `- /* Initially set CPU itself as the policy_cpu */
- per_cpu(cpufreq_policy_cpu, cpu) = cpu;3 K' f, ?4 Q) e, B
8 ^. [5 U5 o* f$ B0 Y
4 e5 X5 ]! y) t2 F6 I
+ V7 [1 d1 D& Y
- H+ C( t* Q: Y' { i" q$ ^ |
|