|
|
EDA365欢迎您登录!
您需要 登录 才可以下载或查看,没有帐号?注册
x
Linux动态频率调节系统CPUFreq之怎样为每个CPU建立频率调整策略(policy)2 B" F g! b( a3 m& }: p: \
. l& y1 P* ^/ e5 H5 o
& b% B. R" m+ T为每个cpu建立频率调整策略实在注册cpufreq_driver阶段的subsys_inteRFace_registe函数中完成的,上一节已经提到,该函数最终会调用cpufreq_add_dev回调函数,现在展开这个函数分析一下:0 l7 H; I' o) N' f3 J/ b7 w
, v6 ?1 M4 n$ A! f因为subsys_interface_registe会枚举各个cpu设备,不管该cpu处于offline还是online状态,cpufreq_add_dev都会被调用,所以函数的一开始,判断如果cpu处于offline状态,直接返回。
: I L6 D& { z' f, G9 D/ J t) W3 V9 z6 i9 g7 o+ V" ~
- static int cpufreq_add_dev(struct device *dev, struct subsys_interface *sif)
- {
- ......
- * m& [) o, _; ] F$ f; A2 ^8 F
- if (cpu_is_offline(cpu))
- return 0;+ F( ?" x6 f' o ~* g
- r4 c* O& U6 L9 G0 G
如果是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期间一并建立的)。
: {9 O* P# f" s* y) ]1 e
$ z, r2 B; Y; ?/ w% `. ~- policy = cpufreq_cpu_get(cpu);
- if (unlikely(policy)) {
- cpufreq_cpu_put(policy);
- return 0;
- }( w6 l8 b3 ?: ~. J1 u
: y: {( ~1 R; `. W0 G% l
" b6 T' B9 K3 Y" _$ c, O2 d/ p因为cpu hot plug期间,cpufreq_add_dev也会被调用,下面的代码片段检测该cpu之前是否被hot-unpluged过,如果是,找到其中一个相关的cpu(这些相关的cpu都委托给同一个托管它cpu进行管理,调用cpufreq_add_policy_cpu函数,该函数只是简单地建立一个cpufreq链接,链接到管理cpu的cpufreq节点。3 x! h/ \( f8 R* ]6 Q
" o0 e3 s% m% V" u$ ^- 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);
- }
- }
8 V/ [! [. k+ q7 D; w
3 [) R$ o8 i- ^# g9 [0 w- d3 m, S8 z& `1 _1 c" H# `
当这是系统初始化阶段第一次调用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字段中:1 s. p. E1 b( G: k* i7 X, ?; a
: @: \5 f# B5 t7 m% L) S; K5 f- policy = kzalloc(sizeof(struct cpufreq_policy), GFP_KERNEL);
- if (!policy)
- goto nomem_out;
- 1 l. F! t1 V+ R) l/ Z7 f
- if (!alloc_cpumask_var(&policy->cpus, GFP_KERNEL))
- goto err_free_policy;
! e* N* s% u3 _0 W( I2 N, D- if (!zalloc_cpumask_var(&policy->related_cpus, GFP_KERNEL))
- goto err_free_cpumask;
% v$ T: r, V0 k# J1 n n! d+ X% B) g- policy->cpu = cpu;
- policy->governor = CPUFREQ_DEFAULT_GOVERNOR;
- cpumask_copy(policy->cpus, cpumask_of(cpu));
- V$ L9 g. \# C4 _" b( {+ L
- /* Initially set CPU itself as the policy_cpu */
- per_cpu(cpufreq_policy_cpu, cpu) = cpu;' C+ ]' A' y9 ~% |. I* d1 _
% S3 {# {. m; M
S |" l3 P* O) p9 }2 j
7 b) L! r. }& J3 A1 L0 x# ~
3 A1 h6 e/ p% d |
|