tegra3 CPU auto hotplug和Big/little switch工作的基本原理

by 宋宝华

《Tegra3 vSMP架构Android运行时CPU热插拔及高低功耗CPU切换》一文中我们通过运行华硕平板电脑看出来tegra3的dvfs结合了CPU热插拔和G/LP core cluster之间的切换,本文从代码角度分析其运行机理。

tegra3是典型的BIG/LITTLE模式,4个G core(高性能,高功耗)加上1个LP core(低性能,低功耗)。运行过程中,我们会发现4个G core会动态热插拔,而4个G core和1个LP core之间,会根据运行负载进行cluster切换。这一部分都是在内核里面实现,和tegra的cpufreq驱动(DVFS驱动)紧密关联。相关代码可见于

http://nv-tegra.nvidia.com/gitweb/?p=linux-2.6.git;a=tree;f=arch/arm/mach-tegra;h=e5d1ff22f5c5629f3c8078e1db308a4b45fa382e;hb=rel-14r7

相关代码未见于LKML和kernel org。

 

如何判断自己是什么core

 

每个core都可以通过调用is_lp_cluster()来判断当前执行CPU是LP还是G处理器:

static inline unsigned int is_lp_cluster(void)

{

        unsignedint reg;

        reg =readl(FLOW_CTRL_CLUSTER_CONTROL);

        return (reg& 1); /* 0 == G, 1 == LP*/

}

即读FLOW_CTRL_CLUSTER_CONTROL寄存器判断出来自己是G core还是LP core。

 

G core和LP core cluster的切换时机

 

[场景1]何时从LP切换给G:当前执行于LPcluster,cpufreq驱动判断出LP需要升频率超过高值门限,即TEGRA_HP_UP:


        caseTEGRA_HP_UP:

                if(is_lp_cluster() && !no_lp) {

                       if(!clk_set_parent(cpu_clk, cpu_g_clk)) {

                               hp_stats_update(CONFIG_NR_CPUS, false);

                               hp_stats_update(0, true);

                                /* catch-upwith governor target speed */

                               tegra_cpu_set_speed_cap(NULL);

                       }  


[场景2]何时从G切换给LP:当前执行于Gcluster,cpufreq驱动判断出某G core需要降频率到小于低值门限,即TEGRA_HP_DOWN,且最慢的CPUID不小于nr_cpu_ids(实际上代码逻辑跟踪等价于只有CPU0还活着):

        caseTEGRA_HP_DOWN:

                cpu= tegra_get_slowest_cpu_n();

                if(cpu < nr_cpu_ids) {

                       ...

                }else if (!is_lp_cluster() && !no_lp) {

                       if(!clk_set_parent(cpu_clk, cpu_lp_clk)) {

                               hp_stats_update(CONFIG_NR_CPUS, true);

                               hp_stats_update(0, false);

                                /* catch-upwith governor target speed */

                               tegra_cpu_set_speed_cap(NULL);

                       } else

                               queue_delayed_work(

                                       hotplug_wq, &hotplug_work, down_delay);

               }  

               break;


 切换实际上就发生在clk_set_parent()更改CPU的父时钟里面,这部分代码写地比较丑,1个函数完成n个功能,实际不仅切换了时钟,还切换了G和LP cluster:

clk_set_parent(cpu_clk, cpu_lp_clk) ->

         tegra3_cpu_cmplx_clk_set_parent(structclk *c, struct clk *p) ->

                   tegra_cluster_control(unsignedint us, unsigned int flags) ->

                            tegra_cluster_switch_prolog()-> tegra_cluster_switch_epilog()

 

G core动态热插拔

何时进行G core的动态plug和unplug:

[场景3]

1.      当前执行于G cluster,cpufreq驱动判断出某Gcore需要降频率到小于低值门限,即TEGRA_HP_DOWN,且最慢的CPUID小于nr_cpu_ids(实际上等价于还有2个或2个以上的G core活着),关闭最慢的CPU,留意tegra_get_slowest_cpu_n()不会返回0,意味着CPU0要么活着,要么切换给LP(对应场景2):

        caseTEGRA_HP_DOWN:

                cpu= tegra_get_slowest_cpu_n();

                if(cpu < nr_cpu_ids) {

                       up = false;

                       queue_delayed_work(

                                hotplug_wq,&hotplug_work, down_delay);

                       hp_stats_update(cpu, false);

                }


[场景4]

2.      当前执行于G cluster,cpufreq驱动判断出某Gcore需要设置频率大于高值门限,即TEGRA_HP_UP,如果负载平衡状态为TEGRA_CPU_SPEED_BALANCED,再开一个core;如果状态为TEGRA_CPU_SPEED_SKEWED,则关一个core。TEGRA_CPU_SPEED_BALANCED的含义是当前所有Gcore要求的频率都高于最高频率的50%,TEGRA_CPU_SPEED_SKEWED的含义是当前至少有2个Gcore要求的频率低于门限的25%,即CPU 频率的要求在各个core间有倾斜。

        caseTEGRA_HP_UP:

                if(is_lp_cluster() && !no_lp) {

                        ...

                }else {

                       switch (tegra_cpu_speed_balance()) {

                       /* cpu speed is up and balanced - one more on-line */

                       case TEGRA_CPU_SPEED_BALANCED:

                               cpu =cpumask_next_zero(0, cpu_online_mask);

                                if (cpu <nr_cpu_ids) {

                                        up =true;

                                       hp_stats_update(cpu, true);

                               }

                                break;

                       /* cpu speed is up, but skewed - remove one core */

                       case TEGRA_CPU_SPEED_SKEWED:

                                cpu =tegra_get_slowest_cpu_n();

                                if (cpu < nr_cpu_ids) {

                                        up =false;

                                       hp_stats_update(cpu, false);

                                }

                                break;

                       /* cpu speed is up, butunder-utilized - do nothing */

                       case TEGRA_CPU_SPEED_BIASED:

                       default:

                                break;

                       }

                }

上述代码中TEGRA_CPU_SPEED_BIASED路径的含义是有1个以上Gcore的频率低于最高频率的50%但是未形成SKEWED条件,即只是“BIASED”,还没有达到“SKEWED”的程度,所以暂时什么都不做。

 


  • 1
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 2
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

宋宝华

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值