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”的程度,所以暂时什么都不做。


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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值