ARM Linux 大小核切换——cortex-A7 big.LITTLE 大小切换代码分析

8核CPU或者是更多核的处理器,这些CPU有可能不完全对称。有的是4个A15和4个A7,或者是4个A57和4个A53,甚至像海思麒麟935处理器(4核A53 2.2 GHz + 4核A53 1.5 GHz),这8个核的频率可能不一样,则使用过程中需要大小核切换(频率高的是大核,频率低的是小核)。本文以ARM cortex-A7为例,分析大小核切换的代码,着重于分析实现切换的代码,对于为什么要这样切换、以及什么时候切换,不做过多探讨。

主要代码分布:

arch/arm/common/bL_switcher.c

arch/arm/include/asm/bL_switcher.h

drivers/cpufreq/Arm_big_little.c

编译后形成的两个驱动模块:

__initcall_bL_switcher_init6

__initcall_bL_cpufreq_register7

执行流程图如下所示。

上图的左边是bL_switcher_init执行流程。

右边是切换线程bL_switcher_thread执行流程,这个线程是核心代码。代码的上半部分是一个CPU在运行,然后这个CPU完成下电后。下半部分蓝色所示,是起来的那个CPU在运行,这样就完成了大小核的切换操作。

1 bL_switcher_init

bL_switcher_init执行流程如下:

如果最大CPU组数(簇)不为2,则报错,然后返回

bL_running_cluster赋值1,默认设为是第一簇在运行

no_bL_switcher初值为FALSE

bL_switcher_enable

bL_switcher_halve_cpus 关闭不必要的CPU

为每个online的CPU创建切换线程bL_switcher_thread

bL_switcher_active赋值1

bL_switcher_sysfs_init 创建sys/kernel/bL_switcher

bL_switcher_restore_unpaired_cpus 恢复不成对的CPU,给它们上电

创建完sys/kernel/bL_switcher,则可以通过下面的命令,手动查看/设置能否切换、查看/设置切换那个簇的CPU。

         cat  /sys/kernel/bL_switcher/active

echo  0/1  >  /sys/kernel/ bL_switcher/active

cat  /sys/kernel/bL_switcher/do_switch

echo  0/1  >  /sys/kernel/ bL_switcher/ do_switch

2 切换请求bL_switch_request

这是个内联函数,需要两个参数,第一个是CPU的ID,第二个是簇号,内核调到的有三处。

一是在Arm_big_little.c:bL_cpufreq_set_rate:需要不同的簇切换时;

二、三是在执行echo  0/1 > /sys/kernel/ bL_switcher/ do_switch ,调用到bL_do_switch_store函数,这里面判断是否需要切换

这个内联函数,直接执行bL_switch_request_cb,参数是前面的2个,再加上两个NULL。

bL_switch_request_cb:

判断第一个参数CPU的ID是否超出范围;

获取当前CPU的线程函数指针

赋值wanted_cluster

唤醒当前线程函数的工作队列

3 切换线程bL_switcher_thread

bL_switcher_thread执行流程:

等待事件。满足事件的两个可能条件:

一是上面的bL_switch_request_cb函数,唤醒线程,且切换到的CPU簇数不为-1;

二是bL_switcher_disable函数调用kthread_stop,唤醒线程

bL_switch_to

找到成对的CPU ID ,簇号

mcpm_cpu_power_up 给CPU上电,跳转到 mcpm_entry_point

gic_send_sgi 给其发送0号软中断

wait_for_completion_timeout(&inbound_alive  等待它给我发送软中断 IPI_COMPLETION

关闭IRQ、FIQ

迁移中断到对应的CPU上

关闭时钟Tick

cpu_pm_enter        gic_cpu_save 保存中断设置

cpu_suspend   这个跟睡眠的流程很相似

bL_switchpoint

call_with_stack       arch/arm/lib/call_with_stack.S      若失败了,是可以返回的

bL_do_switch

让刚起来的CPU跳转到cpu_resume,给其发送sev

若handshake变量为0,则进入wfe

等待不为0后,mcpm_cpu_power_down对自身断电

call_with_stack携带的三个参数,第一个是函数,第二个是函数调用时用到的参数,第三个是栈地址

将SP、LR依次放入栈的顶部

SP赋值让开两个寄存器后的地址

R0赋给R2

R1赋给R0

LR赋值下面的标号1处

R2赋给PC,即跳转到R2

若失败了,则跳转到LR处,就是标号1处

弹出LR

弹出SP

LR赋给PC,跳转到了bL_switchpoint,调用call_with_stack函数的地方。

此处设置真是巧妙,不同簇对应的CPU ID都是0,则刚起来的CPU正好能通过下面的步骤

mcpm_entry_point  -> cpu_resume -> cpu_do_resume=cpu_v7_do_resume -> cpu_resume_mmu -> 再次跳转到上面调用__cpu_suspend处继续运行了。

即要下电的CPU刚保存后堆栈,又被刚上电的CPU恢复了。

接下来就是上电的CPU再运行了。

cpu_pm_exit gic_cpu_restore 恢复中断设置

时钟接着运行 Tick,两个CPU用到的节拍Timer是同一个。

开启IRQ、FIQ

*handshake_ptr = 1;

dsb_sev 给那个CPU发送事件

这样就完成了CPU的切换,这个函数的前一半是一个CPU在执行,后一半变成了另一个CPU在执行。

4 bL_cpufreq_register

获取bL_switcher_active的值,将这个值(真或者假)设置给bL_switching_enabled变量;

初始化互斥锁cluster_lock;

注册cpufreq_driver驱动bL_cpufreq_driver。

如果上面的驱动注册成功,则将bL_switcher_notifier 挂在bL_activation_notifier链表上;

若挂载失败,则卸载驱动bL_cpufreq_driver

 

bL_cpufreq_driver定义如下:

static struct cpufreq_driver bL_cpufreq_driver = {

.name                         = "arm-big-little",

.flags                           = CPUFREQ_STICKY,

.verify                          = bL_cpufreq_verify_policy,

.target                        = bL_cpufreq_set_target,

.get                    = bL_cpufreq_get_rate,

.init                     = bL_cpufreq_init,

.have_governor_per_policy = true,

.attr                   = bL_cpufreq_attr,

};

若bL_cpufreq_driver注册成功,执行下面的命令,就可以看到有个驱动是arm-big-little

cat /sys/devices/system/cpu/cpu0/cpufreq/scaling_available_governors

conservative ondemand userspace powersave interactive performance

cat /sys/devices/system/cpu/cpu0/cpufreq/scaling_governors

interactive

cat /sys/devices/system/cpu/cpu0/cpufreq/scaling_driver

arm-big-little

用bL_cpufreq_driver这种调频策略时,就会执行到bL_cpufreq_set_target,然后执行bL_cpufreq_set_rate,则有可能调用到bL_switch_request。

ARM Linux 大小核切换 ——cortex-A7 big.LITTLE 大小核 切换代码分析的更多相关文章

  1. Linux kernel的中断子系统之(七):GIC代码分析

    返回目录:<ARM-Linux中断系统>. 总结: 原文地址:<linux kernel的中断子系统之(七):GIC代码分析> 参考代码:http://elixir.free- ...

  2. ARM Linux中断发生时内核堆栈切换

    转载注明出处:http://www.wowotech.net/forum/viewtopic.php?id=54 对ARM Linux中断非常简洁.精确的描述. 发生了中断,最重要的是保存现场,在中断 ...

  3. ARM linux电源管理——Cortex A系列CPU(32位)睡眠和唤醒的底层汇编实现

    ARM linux电源管理——Cortex A系列CPU(32位)睡眠和唤醒的底层汇编实现 承接 http://www.wowotech.net/pm_subsystem/suspend_and_re ...

  4. ARM Linux 内核 panic 之cache 一致性 ——cci-400 cache一致互联

    ARM Linux 内核 panic 之cache 一致性 ——cci-400 cache一致互联 CCI-400 集合了互联和一致性功能,有 2 个 ACE slave 接口和 3 个 ACE-Li ...

  5. arm linux kernel 从入口到start_kernel 的代码分析

    参考资料: <ARM体系结构与编程> <嵌入式Linux应用开发完全手册> Linux_Memory_Address_Mapping http://www.chinaunix. ...

  6. Arm Linux系统调用流程详细解析

    Linux系统通过向内核发出系统调用(system call)实现了用户态进程和硬件设备之间的大部分接口. 系统调用是操作系统提供的服务,用户程序通过各种系统调用,来引用内核提供的各种服务,系统调用的 ...

  7. Linux时间子系统之(十七):ARM generic timer驱动代码分析

    专题文档汇总目录 Notes:ARM平台Clock/Timer架构:System counter.Timer以及两者之间关系:Per cpu timer通过CP15访问,System counter通 ...

  8. Linux时间子系统(十七) ARM generic timer驱动代码分析

    一.前言 关注ARM平台上timer driver(clocksource chip driver和clockevent chip driver)的驱动工程师应该会注意到timer硬件的演化过程.在单 ...

  9. ARM linux的启动部分源代码简略分析【转】

    转自:http://www.cnblogs.com/armlinux/archive/2011/11/07/2396784.html ARM linux的启动部分源代码简略分析 以友善之臂的mini2 ...

随机推荐

  1. Android源码下编译APK步骤

    1.进入android源码目录下的build下执行:source envsetup.sh 后继续在该路径下执行lunch. 2.编写完成工程 3.编写Android.mk文件,放入工程目录下     ...

  2. httpclient x-www-form-urlencoded

    1. 使用Apache httpclient提交post请求 http工具方法(需指定编码, 否则出错,这里用的UTF-8) public static String postWithParamsFo ...

  3. 警告: The web application [ROOT] appears to have started a thread named [Thread-48] but has failed to stop it. This is very likely to create a memory leak. Stack trace of thread:

    1. 问题描述 tomcat跑web项目(其中依赖java项目) 出现大量上述警告 项目起不来 关键字 memory leak 内存泄漏 2. 解决方案 难道是程序写的有问题? 最终 将tomcat ...

  4. js对象之间的继承

    js的对象之间的继承抛弃了原型与构造器的概念,而转为字面量对象之间进行属性拷贝的方式进行继承. 首先我们来写一个封装好的继承函数: function extend(parent){ var child ...

  5. [小北De编程手记] : Lesson 05 - Selenium For C# 之 API 下

    上一篇,我们介绍了一些Selenium WebDriver相关的API,下面我们就接着上一篇继续介绍Selenium常用的API,这一篇的内容主要涉及到以下话题: Selenium API:复杂事件处 ...

  6. Ubuntu上如何搭建Android开发环境

    1.以下是开始Android应用程序编程之前需要的软件列表: a.Java JDK5 及以后版本 b.Java运行环境 c.Android Studio 2.安装Android Studio: x64 ...

  7. idea 使用 git打成jar包到 nexus

    1.使用idea生成jar包参考:http://blog.csdn.net/eastgrand/article/details/11945309 2.进入到 自己的工程目录(含有pom.xml的目录) ...

  8. Netty入门3之----Decoder和Encoder

    ​ Netty强大的地方,是他能方便的实现自定义协议的网络传输.在上一篇文章中,通过使用Netty封装好的工具类,实现了简单的http服务器.在接下来的文章中,我们看看怎么使用他来搭建自定义协议的服务 ...

  9. Oracle数据库从入门到精通 多表查询知识以及范例

    视频课程:李兴华 Oracle从入门到精通视频课程 学习者:阳光罗诺 视频来源:51CTO学院 总体内容: 多表查询的意义以及基本问题. 表的连接查询 SQL:1999语法标准对多表查询的支持. 数据 ...

  10. 用java读取多种文件格式的文件(pdf,pptx,ppt,doc,docx..)

    本文通过开源pdfbox和poi进行处理多种文件格式的文本读入 1.需要的jar的maven坐标: <dependency> <groupId>org.apache.pdfbo ...