linux hotplugarm 无法开启内核 没有cpu1/online这个文件! 有的只是hotplug文件夹!

三星如此丧病?Exynos 7420没有Hotplug?_高通吧_百度贴吧
&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&签到排名:今日本吧第个签到,本吧因你更精彩,明天继续来努力!
本吧签到人数:0成为超级会员,使用一键签到本月漏签0次!成为超级会员,赠送8张补签卡连续签到:天&&累计签到:天超级会员单次开通12个月以上,赠送连续签到卡3张
三星如此丧病?Exynos 7420没有Hotplug?收藏
见上图(换成interactive governor也是如此),本以为是使用了CF-AutoRoot的原因,因为Root以后CPU无法进入Deep Sleep,所以怀疑是CF-AutoRoot造成了Hotplug失效,于是用Odin刷回原版系统,开机以后立刻ADB,结果如下(最后一行su是为了验证Root已经失效,CPU8怪我的算术老师) 三星这次是对自己的14nm有多自信
不明白什么意思?
真心看不懂...
你这3c toolbox pro是不是老版本的?你试下把mp打开看看。
都是大神,完全看不懂
所有cpu永远在线
完全理解不了!求大神解释一下!
s6续航可看出一切
之前的hmp就不关核心了吧?
root以后就找不到了,三桑的意思就让你不要root
对自己的功耗很有信心呀
我记得以前s3也是4核同频,永不休眠的
牺牲续航换所谓流畅?
Big Little HMP的核心调度早就不需要Hotplug来管理核心在线了,即使看上去八核在线,没有用到的核心会自动关闭处于低功耗状态
三星一直都没有吧
HMP是没有的
叫你不买810机子,看肥威微博,用kernel adiutor可控制810核心数量。
LZ意思是指热度管控?
5410开始就没有hotplug了,4核心全部在线
刷第三方内核就有hotplug,话说三棒为何要八核全开……
楼主火星啦
hotplug是什么东西!
ARM64 generic CPU idle driver新驱动,8核一直在线,实际上有休眠的,必要时通过CCI总线唤醒核心。
1.楼主直接看cpu/online 就可以看几个核跑了,没必要这费事 2.cpuidle进入c3态,是关电和时钟的,不费电 3.hotplug打开,理论上是可以省电,虽然很有限。可以避免timer中断经常把cpu从c态拉出来,注意,no hz 打开,也会有时钟中断 4.有些任务会bound到某一个cpu.使cpu进c态时间缩短,这点hmp调度解决不了,还得hotplug靠谱
热拔插……
17楼正解 -- 高端大气上档次,低调奢华有内涵。奔放洋气有深度,狂拽炫酷屌炸天。
登录百度帐号推荐应用
为兴趣而生,贴吧更懂你。或Linux内核(63)
由“”的描述可知,kernel cpu control位于“.\kernel\cpu.c”中,是一个承上启下的模块,负责屏蔽arch-dependent的实现细节,向上层软件提供控制CPU
core的统一API(主要包括cpu_up/cpu_down等接口的实现)。本文将基于这些API,从上到下,分析CPU core从启动到关闭的整个过程(主要是CPU hotplug),进一步理解系统运行过程中CPU core电源管理相关的行为。
注1:其实这一部分已经不属于电源管理的范畴了,而是系统级的软件行为(boot、调度、电源管理等等),之所以放到这里讲述,主要原因是,这些复杂行为的背后,目的只有一个----节电。因此,本文只会focus在CPU core power状态切换的过程上,涉及到得其它知识,如进程调度,只会一笔带过。
2. possible/present/active/online cpus
前面文章提到过,kernel使用4个bitmap,来保存分别处于4种状态的CPU core:possible、present、active和online。这四个状态的意义到底是什么?下面我们根据相关的代码逻辑,来解答这个问题。
开始之前,先看一下kernel中对他们的注释:
1: /* include/linux/cpumask.h */
* The following particular system cpumasks and operations manage
* possible, present, active and online cpus.
cpu_possible_mask- has bit 'cpu' set iff cpu is populatable
cpu_present_mask - has bit 'cpu' set iff cpu is populated
cpu_online_mask
- has bit 'cpu' set iff cpu available to scheduler
cpu_active_mask
- has bit 'cpu' set iff cpu available to migration
If !CONFIG_HOTPLUG_CPU, present == possible, and active == online.
The cpu_possible_mask is fixed at boot time, as the set of CPU id's
that it is possible might ever be plugged in at anytime during the
life of that system boot.
The cpu_present_mask is dynamic(*),
representing which CPUs are currently plugged in.
cpu_online_mask is the dynamic subset of cpu_present_mask,
indicating those CPUs available for scheduling.
If HOTPLUG is enabled, then cpu_possible_mask is forced to have
all NR_CPUS bits set, otherwise it is just the set of CPUs that
ACPI reports present at boot.
If HOTPLUG is enabled, then cpu_present_mask varies dynamically,
depending on what ACPI reports as currently plugged in, otherwise
cpu_present_mask is just a copy of cpu_possible_mask.
大意是这样的:
possible状态的CPU意味着是“populatable(觉得这个单词还没有possible易懂)”的,可理解为存在这个CPU资源,但还没有纳入Kernel的管理范围;
present状态的CPU,是已经“populated”的CPU,可理解为已经被kernel接管;
online状态的CPU,表示可以被调度器使用;
active状态的CPU,表示可以被migrate(什么意思?);
如果系统没有使能CPU Hotplug功能,则present等于possible,active等于online。
还真不是很容易理解,不急,我们一个一个分析。
2.1 possible CPU
possible的CPUs,代表了系统中可被使用的所有的CPU,在boot阶段确定之后,就不会再修改。以ARM64为例,其初始化的过程如下。
1)系统上电后,boot CPU启动,执行start_kernel(init/main.c),并分别调用boot_cpu_init和setup_arch两个接口,进行possible CPU相关的初始化。
2)boot_cpu_init负责将当前的boot CPU放到possible CPU的bitmap中,同理,boot CPU也是present、oneline、active CPU(因此,后续的描述,都是针对非boot CPU的)。如下:
1: /* init/main.c */
3: static void __init boot_cpu_init(void)
int cpu = smp_processor_id();
/* Mark the boot cpu &present&, &online& etc for SMP and UP case */
set_cpu_online(cpu, true);
set_cpu_active(cpu, true);
set_cpu_present(cpu, true);
set_cpu_possible(cpu, true);
smp_processor_id用于获取当前的CPU id;
set_cpu_xxx接口,可以将指定的CPU设置为(或者清除)指定的状态。
3)setup_arch负责根据MPIDR寄存器,以及DTS配置,解析并设置其它的possible CPU,如下:
1: /* arch/arm64/kernel/setup.c */
3: void __init setup_arch(char **cmdline_p)
cpu_logical_map(0) = read_cpuid_mpidr() & MPIDR_HWID_BITMASK;
cpu_read_bootcpu_ops();
8: #ifdef CONFIG_SMP
smp_init_cpus();
smp_build_mpidr_hash();
11: #endif
3a)cpu_logical_map数组
kernel使用一个整形数组(cpu_logical_map,定义如下),保存物理CPU(由ID标示)和逻辑CPU(数组的index)之间的映射,该数组的长度由NR_CPUS决定。
1: /* arch/arm64/include/asm/smp_plat.h */
* Logical CPU mapping.
6: extern u64 __cpu_logical_map[NR_CPUS];
7: #define cpu_logical_map(cpu)
__cpu_logical_map[cpu]
上面setup_arch代码的第六行,通过read_cpuid_mpidr接口,读取当前CPU(boot CPU)的ID(物理ID),并保存在map表的第一个位置。
3b)smp_init_cpus
如果使能了SMP,则调用smp_init_cpus接口,完成如下事情:
从DTS中解析其它CPU的HW ID(通过‘reg’关键字,如下),并保存在cpu_logical_map数组中;
对所有cpu_logical_map数组中的CPU,执行set_cpu_possible操作,将它们设置为possible状态。
#address-cells = &2&;
#size-cells = &0&;
device_type = &cpu&;
compatible = &arm,cortex-a53&, &arm,armv8&;
reg = &0x0 0x0&;
enable-method = &psci&;
cpu-idle-states = &&CPU_SLEEP_0 &CPU_SLEEP_1&;
device_type = &cpu&;
compatible = &arm,cortex-a53&, &arm,armv8&;
reg = &0x0 0x1&;
enable-method = &psci&;
cpu-idle-states = &&CPU_SLEEP_0 &CPU_SLEEP_1&;
CPU DTS文件示例。&
对ARM64来说,possible的CPU,就是在DTS中指定了的,物理存在的CPU core。
2.2 present CPU
还是以ARM64为例,“start_kernel—&setup_arch”成功执行之后,继续执行“start_kernel—&rest_init—&kernel_init(pid 1,init task)—&kernel_init_freeable”,在kernel_init_freeable中会调用arch-dependent的接口:smp_prepare_cpus,该接口主要的主要功能有两个:
1)构建系统中CPU的拓扑结构,具体可参考“”。
2)拓扑结构构建完成后,根据CPU的拓扑,初始化系统的present CPU mask,代码如下:
1: void __init smp_prepare_cpus(unsigned int max_cpus)
/* Don't bother if we're effectively UP */
if (max_cpus &= 1)
* Initialise the present map (which describes the set of CPUs
* actually populated at the present time) and release the
* secondaries from the bootloader.
* Make sure we online at most (max_cpus - 1) additional CPUs.
max_cpus--;
for_each_possible_cpu(cpu) {
if (max_cpus == 0)
if (cpu == smp_processor_id())
if (!cpu_ops[cpu])
err = cpu_ops[cpu]-&cpu_prepare(cpu);
set_cpu_present(cpu, true);
max_cpus--;
4~6行:当然,如果CPU个数不大于1,则不是SMP系统,就没有后续的概念,直接返回。
16~32行,轮询所有的possible CPU,如果某个CPU core满足一些条件,则调用set_cpu_present,将其设置为present CPU,满足的条件包括:具备相应的cpu_ops指针(有关cpu ops请参考“”);cpu ops的.cpu_prepare回调成功执行。
由“”中有关CPU ops的解释可知,.cpu_prepare回调主要用于检查某个CPU是否具备执行的条件。如果.cpu_prepare执行成功,则说明该CPU是可以启动的。因此,present
CPU的意义是:
该CPU已经被kernel识别到,并且具备执行代码的条件,后续可以在需要的时候(如hotpulg的时候),启动该CPU。
2.3 online CPU
由前面present CPU可知,如果某个CPU是present的,则说明该CPU具备boot的条件,但是否已经boot还是未知数。
由“”的介绍可知,所谓的CPU boot,就是让CPU执行(取指译码/执行)代码(这里为linux kernel)。而CPU是否boot,则反映到online mask上,已经boot的CPU,会在secondary_start_kernel中,调用set_cpu_online接口,将其设置为online状态。反之,会在__cpu_disable中将其从online
mask中清除。
有关CPU boot的流程,请参考下面的介绍。
2.4 active CPU
在单核时代,调度器(scheduler)的职责很单纯:主要负责管理、调教一帮调皮捣蛋的task,尽量以“公平公正”的原则,为它们分配有限的CPU资源。
但在SMP系统中,特别是支持CPU hotplug的系统中,调度器需要多操一份心,即:
CPU资源可以在任何时候增加或者删除。增加的时候,需要将新增的资源分配给等待的task。删除的时候,需要将那些运行在这些CPU上的task,转移到其它尚存的CPU上(这个过程称作migration)。
要达到上面的目的,调度器需要监视CPU hotplug有关的每一个风吹草动。由于调度器和两个独立的模块,kernel通过notifier机制(“”中有提及,但没有过多介绍)实现这一功能。
简言之,每当系统的CPU资源有任何变动,模块就会通知调度器,调度器根据相应的event(CPU_DOWN_FAILED、CPU_DOWN_PREPARE等),调用set_cpu_active接口,将某个CPU添加到active
mask或者移出active mask。这就是active CPU的意义:
从调度器的角度,CPU的状态,即是否对调度器可见,或者说,调度器是否可以把task分配到这个CPU上运行。
注2:由此可知,active状态,只是为了方便调度器操作,抽象出的状态,和CPU电源管理之间没有耦合,后面就不在涉及这部分内容。
3. CPU的控制流程
CPU的控制流程,可以总结为up和down两种行为(和“.\kernel\cpu.c”中的cpu_up、cpu_down两个接口对应),up指CPU的启动过程,down指相反地过程。
根据CPU的发展过程,up和down的行为又可以分为三类:单核CPU的up/down;多核CPU的up/down;hotplugable CPU的up/down。下面让我们对这几种情况做一下简单的介绍。
3.1 单核CPU的控制流程
单核时代,只有一个CPU core,因此CPU的up/down,就是软件的整个生命周期(也就无所谓up/down了),如下:
1)系统上电,CPU从ROM代码执行,经bootloader(非必须),将控制权交给linux kernel。这就是cpu up的过程。
2)系统运行(一大堆省略号)。
3)由linux kernel及其进程调度算法所决定,不允许系统在没有CPU资源的情况下运行(这也是boot CPU的由来),所以系统的整个运行过程中,CPU都是up状态。
4)系统关闭,cpu down。
3.2 多核CPU的控制流程
linux kernel对待SMP系统的基本策略是:指定一个boot CPU,完成系统的初始化,然后再启动其它CPU。过程如下:
1)boot CPU启动,其up/down的控制流程和生命周期,和单核CPU一样。
2)boot CPU启动的过程中,调用cpu_up接口,启动其它CPU(称作secondary CPUs),使它们变成online状态(具体可参考“”)。这就是secondary
CPUs的up过程。
3)由于CPU不支持hotplug功能,因此所有CPU只能up,不能down。直到系统关闭,才是cpu down。
3.3 CPU hotplug的控制流程
对于支持CPU hotplug功能的平台来说,可以在系统启动后的任意时刻,关闭任意一个secondary CPU(对ARM平台来说,CPU0或者说boot CPU,是不可以被关闭的),并在需要的时候,再次打开它。因此,相应的CPU控制流程如下:
1)boot CPU启动,其up/down的控制流程和生命周期,和单核CPU一样。
2)boot CPU启动的过程中,调用cpu_up接口,启动secondary CPU,使它们变成online状态,这是secondary CPUs的up过程的一种。
<span style="color:#)在系统负荷较低、或者不需要使用的时候,调用cpu_down接口,关闭不需要使用的secondary CPU,这是secondary CPUs的down过程。
<span style="color:#)在需要的时候,再次调用cpu_up接口,启动处于down状态的CPU,这是secondary CPUs的up过程的另一种。
有关CPU hotplug的具体说明,可参考后面描述。
4. CPU hotplug
4.1 CPU hotplug的时机
在kernel/cpu.c中,cpu_up接口,只会在使能了CONFIG_SMP配置项(意味着是SMP系统)后才会提供。而cpu_down接口,则只会在使能了CONFIG_HOTPLUG_CPU配置项(意味着支持CPU hotplug)后才会提供。
在当前kernel实现中,只支持通过sysfs的形式,关闭或打开CPU(当然,如果需要可以自定义一些方法,实现动态开关核的功能,本文就不在描述了),例如:
echo 0 & /sys/devices/system/cpu/cpuX/online&&&&& # 关闭CPU
echo 1 & /sys/devices/system/cpu/cpuX/online&&&&& # 打开CPU
另外,CPU hotplug还受“maxcpus”命令行参数影响:
系统启动的时候,可以通过命令行参数“maxcpus”,告知kernel本次启动所使用的CPU个数,该个数可以小于等于possible CPU的个数。系统初始化时,只会把“maxcpus”所指定个数的CPU置为present状态,具体可参考上面2.2小节所描述的smp_prepare_cpus的代码实现。
因此,CPU hotplug只能管理“maxcpus”所指定个数的CPU,具体可参考后面_cpu_up的流程分析。
注3:蜗蜗对这部分的理解,和“Documentation\cpu-hotplug.txt”中的描述有出入,文档是这样描述的:
maxcpus=n&&& Restrict boot time cpus to n. Say if you have 4 cpus, using&
&&&&&&&&&&&& maxcpus=2 will only boot 2. You can choose to bring the&
&&&&&&&&&&&& other cpus later online, read FAQ's for more info.
它说其它CPU可以在后边被online,但从代码逻辑来说,没有机会online啊!先存疑吧!!
4.2 CPU hotplug的过程分析
CPU online的软件流程如下:
echo 0 & /sys/devices/system/cpu/cpuX/online&
&&&&&&& online_store(drivers/base/core.c)&
&&&&&&&&&&&&&&& device_online(drivers/base/core.c)&
&&&&&&&&&&&&&&&&&&&&&&& cpu_subsys_online(drivers/base/cpu.c)&
&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&& cpu_up(kernel/cpu.c)&
&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&& _cpu_up(kernel/cpu.c)&
CPU offline的流程和online类&#20284;,不再详细介绍。这两个操作,最终是由cpu_up/cpu_down(也即_cpu_up/_cpu_down)两个接口实现的,下面我们重点分析这两个接口。
注4:内核中经常有这样的函数,xxx、_xxx或者__xxx,区别是一个或者两个下划线,其中的含义是:
xxx接口,通常需要由某个锁保护,一般提供给其它模块调用。它会直接调用_xxx接口;
_xxx接口,则不需要保护,一般由模块内部在确保安全的情况下调用。有时,外部模块确信可行(不需要保护),也可能会直接调用;
__xxx接口,一般提供给arch-dependent的软件层实现,比如这里的arch/arm64/kernel/xxx.c。
理解这些含义后,会加快我们阅读代码的速度,另外,如果直接写代码,也尽量遵守这样的原则,以便使自己的代码更规范、更通用。
4.3 cpu_up流程分析
cpu_up的基本流程如下所示:
其要点包括:
1)up前后,发送PREPARE、ONLINE、STARTING等notify,以便让关心者作出相应的动作,例如调度器、RCU、workqueue等模块,都需要关注CPU的hotplug动作,以便进行任务的重新分配等操作。
2)执行Arch-specific相关的boot操作,将CPU boot起来,最终通过secondary_start_kernel接口,停留在per-CPU的idle线程上。
下面我们结合代码,对上述过程做一个简单的分析。
4.3.1 per-CPU的idle线程
我们在“”的系列文章中,已经分析过linux cpuidle有关的工作原理,但却没有提及cpuidle的源头,这里我们补充回来。
首先,boot CPU在执行初始化动作的时候,会通过“smp_init—&idle_threads_init—&idle_init”的调用,为每个CPU创建一个idle线程,如下:
1: /* kernel/smpboot.c */
2: static inline void idle_init(unsigned int cpu)
struct task_struct *tsk = per_cpu(idle_threads, cpu);
if (!tsk) {
tsk = fork_idle(cpu);
if (IS_ERR(tsk))
pr_err(&SMP: fork_idle() failed for CPU %u\n&, cpu);
per_cpu(idle_threads, cpu) =
该接口的本质是,为每个CPU fork一个idle thread(由struct task_struct结构表示),并保存在一个per-CPU的全局变量(idle_threads)中。
此时,idle thread只是一个task结构,并没有执行。那它最终怎么执行的呢?我们继续往后面看。
4.3.2 arch-specific CPU boot
_cpu_up接口会在完成一些准备动作之后,调用平台相关的__cpu_up接口,由平台代码完成具体的up操作,如下:
1: static int _cpu_up(unsigned int cpu, int tasks_frozen)
int ret, nr_calls = 0;
void *hcpu = (void *)(long)
unsigned long mod = tasks_frozen ? CPU_TASKS_FROZEN : 0;
struct task_struct *
cpu_hotplug_begin();
if (cpu_online(cpu) || !cpu_present(cpu)) {
ret = -EINVAL;
idle = idle_thread_get(cpu);
if (IS_ERR(idle)) {
ret = PTR_ERR(idle);
ret = smpboot_create_threads(cpu);
ret = __cpu_notify(CPU_UP_PREPARE | mod, hcpu, -1, &nr_calls);
if (ret) {
nr_calls--;
pr_warn(&%s: attempt to bring up CPU %u failed\n&,
__func__, cpu);
/* Arch-specific enabling code. */
ret = __cpu_up(cpu, idle);
if (ret != 0)
BUG_ON(!cpu_online(cpu));
/* Wake the per cpu threads */
smpboot_unpark_threads(cpu);
/* Now call notifier in preparation. */
cpu_notify(CPU_ONLINE | mod, hcpu);
45: out_notify:
if (ret != 0)
__cpu_notify(CPU_UP_CANCELED | mod, hcpu, nr_calls, NULL);
cpu_hotplug_done();
准备动作包括:
1)获取idle thread的task指针,该指针最终会以参数的形式传递给arch-specific代码。
2)创建一个用于管理CPU hotplug动作的线程(smpboot_create_threads),该线程的具体意义,后面会再说明。
3)发送CPU_UP_PREPARE notify。
以ARM64为例,__cpu_up的内部实现如下:
1: /* arch/arm64/kernel/smp.c */
2: int __cpu_up(unsigned int cpu, struct task_struct *idle)
* We need to tell the secondary core where to find its stack and the
* page tables.
secondary_data.stack = task_stack_page(idle) &#43; THREAD_START_SP;
__flush_dcache_area(&secondary_data, sizeof(secondary_data));
* Now bring the CPU into our world.
ret = boot_secondary(cpu, idle);
if (ret == 0) {
* CPU was successfully started, wait for it to come online or
* time out.
wait_for_completion_timeout(&cpu_running,
msecs_to_jiffies(1000));
if (!cpu_online(cpu)) {
pr_crit(&CPU%u: failed to come online\n&, cpu);
ret = -EIO;
pr_err(&CPU%u: failed to boot: %d\n&, cpu, ret);
secondary_data.stack = NULL;
该接口以idle thread的task指针为参数,完成如下动作:
1)将idle线程的堆栈,保存在一个名称为secondary_data的全局变量中(这地方很重要,后面再介绍其中的奥妙)。
2)执行boot_secondary接口,boot CPU,具体的流程,可参考“”中的描述。
3)boot_secondary返回后,等待对应的CPU切换为online状态。
4.3.3 secondary_startup
“” 4.1小节,分析了使用SPIN TABLE cpu ops的情况下,boot_secondary到secondary_startup的流程(其它cpu ops类&#20284;),本文继续secondary_startup的分析。
该接口位于arch/arm64/kernel/head.S中,负责secondary CPU启动后的后期操作,如下:
1: ENTRY(secondary_startup)
* Common entry point for secondary CPUs.
x22, midr_el1
// x22=cpuid
lookup_processor_type
// x23=current cpu_table
x23, __error_p
// invalid processor (x23=0)?
x25, x26, x28
// x25=TTBR0, x26=TTBR1
x12, [x23, #CPU_INFO_SETUP]
x12, x12, x28
// __virt_to_phys
// initialise processor
x21, =secondary_data
x27, =__secondary_switched
// address to jump to after enabling the MMU
__enable_mmu
19: ENDPROC(secondary_startup)
21: ENTRY(__secondary_switched)
// get secondary_data.stack
secondary_start_kernel
26: ENDPROC(__secondary_switched)
我们重点关注上面16~17行,以及21~26行的__secondary_switched,__secondary_switched会将保存在secondary_data全局变量中的堆栈取出,保存在该CPU的SP中,并跳转到secondary_start_kernel继续执行。思考一下其中的意义:
我们都知道,CPU启动后,需要先配置好堆栈,才能进行后续的函数调用,这里使用的是该CPU idle thread的堆栈。就这么简单吗?当然不是,看一下kernel中“current”指针(获取当前task结构的宏定义)的实现方法:
1: #define current get_current()
2: #define get_current() (current_thread_info()-&task)
4: static inline struct thread_info *current_thread_info(void)
register unsigned long sp asm (&sp&);
return (struct thread_info *)(sp & ~(THREAD_SIZE - 1));
有没有豁然开朗的感觉?通过CPU的SP指针,是可以获得CPU的当前task的(这和linux kernel进程管理的实现有关,我们不深究)。也就是说,当CPU SP被赋&#20540;为idle thread的堆栈的那一瞬间,当前的上下文已经是idle thread了!!
至于后面的secondary_start_kernel,就比较简单了,使能GIC、Timers,设置CPU为online状态,使能本地IRQ中断。等等。最后,调用cpu_startup_entry,进入cpuidle的loop中,已经和“”中描述接上了,自此,CPU UP完成。
4.4 cpu_down流程
cpu_down是cpu_up的反过程,用于将某个CPU从系统中移出。从表面上看,它和cpu_up的过程应该类&#20284;,但实际上它的处理过程却异常繁琐、复杂,同时牵涉到非常多的进程调度的知识,鉴于篇幅,本文就不再继续分析了。如果有机会,后面再专门用一篇文章分析这个过程。
另外,前面提到的smpboot有关的内容,也和cpu_down的过程有关,也就不再介绍了。
由本文的分析可知,cpu control有关的过程,其本身的逻辑比较简单,复杂之处在于:与此相关的系统服务(任务、中断、timer等等)的迁移。如果要理解这个过程,就必须有深厚的进程调度、中断管理等背景知识作支撑。不着急,来日方长,有机会我们继续分析。
原创文章,转发请注明出处。蜗窝科技,。
参考知识库
* 以上用户言论只代表其个人观点,不代表CSDN网站的观点或立场
访问:18622次
排名:千里之外
原创:15篇
转载:128篇
(1)(5)(9)(34)(95)博客访问: 1350984
博文数量: 378
博客积分: 10161
博客等级: 上将
技术积分: 5147
注册时间:
IT168企业级官微
微信号:IT168qiye
系统架构师大会
微信号:SACC2013
分类: LINUX
Q: What architectures support CPU hotplug?
A: As of 2.6.14, the following architectures support CPU hotplug.
i386 (Intel), ppc, ppc64, parisc, s390, ia64 and x86_64
Q: How to test if hotplug is supported on the newly built kernel?怎么测试最新编译的内核是否支持CPU热插拔操作。
A: You should now notice an entry in sysfs.
Now you should see entries for all present cpu, the following is an example
in a 8-way system.
#/sys/devices/system/cpu
drwxr-xr-x&& 10 root root 0 Sep 19 07:44 .
drwxr-xr-x&& 13 root root 0 Sep 19 07:45 ..
drwxr-xr-x&&
3 root root 0 Sep 19 07:44 cpu0
drwxr-xr-x&&
3 root root 0 Sep 19 07:44 cpu1
drwxr-xr-x&&
3 root root 0 Sep 19 07:44 cpu2
drwxr-xr-x&&
3 root root 0 Sep 19 07:44 cpu3
drwxr-xr-x&&
3 root root 0 Sep 19 07:44 cpu4
drwxr-xr-x&&
3 root root 0 Sep 19 07:44 cpu5
drwxr-xr-x&&
3 root root 0 Sep 19 07:44 cpu6
drwxr-xr-x&&
3 root root 0 Sep 19 07:48 cpu7
Under each directory you would find an "online" file which is the control
file to logically online/offline a processor.
在每个目录下可以看见一个“online”文件,该文件描述的所属CPU是否online
Q: Does hot-add/hot-remove refer to physical add/remove of cpus?是否CPU热插拔支持物理CPU添加和移出?
A: The usage of hot-add/remove may not be very consistently used in the code.
CONFIG_HOTPLUG_CPU enables logical online/offline capability in the kernel.
To support physical addition/removal, one would need some BIOS hooks and
the platform should have something like an attention button in PCI hotplug.
CONFIG_ACPI_HOTPLUG_CPU enables ACPI support for physical add/remove of CPUs.
CPU逻辑上的热插拔处理是在linux内核的代码完成。支持物理上CPU热插拔,需要BIOS支持以及硬件平台的支持比如像PCI设备热插拔以类似的硬件支持
Q: How do i logically offline a CPU?我该怎么将一个CPU逻辑上热移出。
A: Do the following.
&&&&&&&&#echo 0 > /sys/devices/system/cpu/cpuX/online(在终端里,输本行命令即可)
Once the logical offline is successful, check(检查是否成功将CPU热移出)
#cat /proc/interrupts(在终端里,输本行命令即可)
You should now not see the CPU that you removed. Also online file will report
the state as 0 when a cpu if offline and 1 when its online.
在“online”文件里描述CPU的状态,0代表已经移出,1代表已经添加成功
#To display the current cpu state.
#cat /sys/devices/system/cpu/cpuX/online
Q: Why cant i remove CPU0 on some systems?
A: Some architectures may have some special dependency on a certain CPU.
For e.g in IA64 platforms we have ability to sent platform interrupts to the
OS. a.k.a Corrected Platform Error Interrupts (CPEI). In current ACPI
specifications, we didn't have a way to change the target CPU. Hence if the
current ACPI version doesn't support such re-direction, we disable that CPU
by making it not-removable.
In such cases you will also notice that the online file is missing under cpu0.
Q: How do i find out if a particular CPU is not removable?
A: Depending on the implementation, some architectures may show this by the
absence of the "online" file. This is done if it can be determined ahead of
time that this CPU cannot be removed.
In some situations, this can be a run time check, i.e if you try to remove the
last CPU, this will not be permitted. You can find such failures by
investigating the return value of the "echo" command.
Q: What happens when a CPU is being logically offlined?当一个CPU逻辑热移出时,内核放生了什么?
A: The following happen, listed in no particular order :-)
- A notification is sent to in-kernel registered modules by sending an event
&& CPU_DOWN_PREPARE or CPU_DOWN_PREPARE_FROZEN, depending on whether or not the
&& CPU is being offlined while tasks are frozen due to a suspend operation in
&& progress
将事件CPU_DOWN_PREPARE 或者 CPU_DOWN_PREPARE_FROZEN发送到内核中
- All processes are migrated away from this outgoing CPU to new CPUs.
&& The new CPU is chosen from each process' current cpuset, which may be
&& a subset of all online CPUs.
将所有进程从目标CPU迁移到系统其他CPU上运行。
- All interrupts targeted to this CPU is migrated to a new CPU
将所有中断从目标CPU迁移到其他CPU
- timers/bottom half/task lets are also migrated to a new CPU
计时器和下半部迁移到其他CPU
- Once all services are migrated, kernel calls an arch specific routine
&& __cpu_disable() to perform arch specific cleanup.
当所有服务迁移后,内核调用例程__cpu_disable()执行体系结构特定的清除操作
- Once this is successful, an event for successful cleanup is sent by an event
&& CPU_DEAD (or CPU_DEAD_FROZEN if tasks are frozen due to a suspend while the
&& CPU is being offlined).
一旦成功地将CPU热移出,就会发送CPU_DEAD。
&& "It is expected that each service cleans up when the CPU_DOWN_PREPARE
&& notifier is called, when CPU_DEAD is called its expected there is nothing
&& running on behalf of this CPU that was offlined"
希望在执行通知链上CPU_DOWN_PREPARE操作时完成所有服务的清除操作。当执行通知链上CPU_DEAD的操作时,希望没有任何服务在CPU上执行,因为CPU已经成功地被移出。
Q: If i have some kernel code that needs to be aware of CPU arrival and
departure, how to i arrange for proper notification?
A: This is what you would need in your kernel code to receive notifications.
static int __cpuinit foobar_cpu_callback(struct notifier_block *nfb,
&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&
unsigned long action, void *hcpu)
&&&&&&&&&&&&&&&&&&
unsigned int cpu = (unsigned long)
&&&&&&&&&&&&&&&&&&
switch (action) {
&&&&&&&&&&&&&&&&&&
case CPU_ONLINE:
&&&&&&&&&&&&&&&&&&
case CPU_ONLINE_FROZEN:
&&&&&&&&&&&&&&&&&&&&&&&&&&&& foobar_online_action(cpu);
&&&&&&&&&&&&&&&&&&&&&&&&&&&&
&&&&&&&&&&&&&&&&&&
case CPU_DEAD:
&&&&&&&&&&&&&&&&&&
case CPU_DEAD_FROZEN:
&&&&&&&&&&&&&&&&&&&&&&&&&&&& foobar_dead_action(cpu);
&&&&&&&&&&&&&&&&&&&&&&&&&&&&
&&&&&&&&&&&&&&&&&&
&&&&&&&&&&&&&&&&&&
return NOTIFY_OK;
static struct notifier_block __cpuinitdata foobar_cpu_notifer =
&&&&&&&&&&&& .notifier_call = foobar_cpu_callback,
You need to call register_cpu_notifier() from your init function.
Init functions could be of two types:
1. early init (init function called when only the boot processor is online).
2. late init (init function called _after_ all the CPUs are online).
For the first case, you should add the following to your init function
register_cpu_notifier(&foobar_cpu_notifier);
For the second case, you should add the following to your init function
register_hotcpu_notifier(&foobar_cpu_notifier);
You can fail PREPARE notifiers if something doesn't work to prepare resources.
This will stop the activity and send a following CANCELED event back.
CPU_DEAD should not be failed, its just a goodness indication, but bad
things will happen if a notifier in path sent a BAD notify code.
Q: I don't see my action being called for all CPUs already up and running?
A: Yes, CPU notifiers are called only when new CPUs are on-lined or offlined.
If you need to perform some action for each cpu already in the system, then
for_each_online_cpu(i) {
&&&&&&&&&&&&&&&&&&
foobar_cpu_callback(&foobar_cpu_notifier, CPU_UP_PREPARE, i);
&&&&&&&&&&&&&&&&&&
foobar_cpu_callback(&foobar_cpu_notifier, CPU_ONLINE, i);
Q: If i would like to develop cpu hotplug support for a new architecture,
what do i need at a minimum?
A: The following are what is required for CPU hotplug infrastructure to work
correctly.
&&&& - Make sure you have an entry in Kconfig to enable CONFIG_HOTPLUG_CPU
&&&& - __cpu_up()&&&&&&&& - Arch interface to bring up a CPU
&&&& - __cpu_disable()&&
- Arch interface to shutdown a CPU, no more interrupts
&&&&&&&&&&&&&&&&&&&&&&&&&& can be handled by the kernel after the routine
&&&&&&&&&&&&&&&&&&&&&&&&&& returns. Including local APIC timers etc are
&&&&&&&&&&&&&&&&&&&&&&&&&& shutdown.
- __cpu_die()&&&&&& - This actually supposed to ensure death of the CPU.
&&&&&&&&&&&&&&&&&&&&&&&&&& Actually look at some example code in other arch
&&&&&&&&&&&&&&&&&&&&&&&&&& that implement CPU hotplug. The processor is taken
&&&&&&&&&&&&&&&&&&&&&&&&&& down from the idle() loop for that specific
&&&&&&&&&&&&&&&&&&&&&&&&&& architecture. __cpu_die() typically waits for some
&&&&&&&&&&&&&&&&&&&&&&&&&& per_cpu state to be set, to ensure the processor
&&&&&&&&&&&&&&&&&&&&&&&&&& dead routine is called to be sure positively.
Q: I need to ensure that a particular cpu is not removed when there is some
work specific to this cpu is in progress.
A: First switch the current thread context to preferred cpu
int my_func_on_cpu(int cpu)
&&&&&&&&&&&&&&&&&&
cpumask_t saved_mask, new_mask = CPU_MASK_NONE;
&&&&&&&&&&&&&&&&&&
int curr_cpu, err = 0;
&&&&&&&&&&&&&&&&&&
saved_mask = current->cpus_
&&&&&&&&&&&&&&&&&&
cpu_set(cpu, new_mask);
&&&&&&&&&&&&&&&&&&
err = set_cpus_allowed(current, new_mask);
&&&&&&&&&&&&&&&&&&
&&&&&&&&&&&&&&&&&&&&&&&&&&&&
&&&&&&&&&&&&&&&&&&
&&&&&&&&&&&&&&&&&&&& * If we got scheduled out just after the return from
&&&&&&&&&&&&&&&&&&&& * set_cpus_allowed() before running the work, this ensures
&&&&&&&&&&&&&&&&&&&& * we stay locked.
&&&&&&&&&&&&&&&&&&&& */
&&&&&&&&&&&&&&&&&&
curr_cpu = get_cpu();
&&&&&&&&&&&&&&&&&&
if (curr_cpu != cpu) {
&&&&&&&&&&&&&&&&&&&&&&&&&&&& err = -EAGAIN;
&&&&&&&&&&&&&&&&&&&&&&&&&&&&
&&&&&&&&&&&&&&&&&&
&&&&&&&&&&&&&&&&&&&&&&&&&&&& /*
&&&&&&&&&&&&&&&&&&&&&&&&&&&&
* Do work : But cant sleep, since get_cpu() disables preempt
&&&&&&&&&&&&&&&&&&&&&&&&&&&&
&&&&&&&&&&&&&&&&&&
&&&&&&&&&&&&&&&&&&
&&&&&&&&&&&&&&&&&&&&&&&&&&&& put_cpu();
&&&&&&&&&&&&&&&&&&&&&&&&&&&& set_cpus_allowed(current, saved_mask);
&&&&&&&&&&&&&&&&&&&&&&&&&&&&
&&&&&&&&&&&&&&&&&&
Q: How do we determine how many CPUs are available for hotplug.
A: There is no clear spec defined way from ACPI that can give us that
information today. Based on some input from Natalie of Unisys,
that the ACPI MADT (Multiple APIC Description Tables) marks those possible
CPUs in a system with disabled status.
Andi implemented some simple heuristics that count the number of disabled
CPUs in MADT as hotpluggable CPUS.&& In the case there are no disabled CPUS
we assume 1/2 the number of CPUs currently present can be hotplugged.
Caveat: Today's ACPI MADT can only provide 256 entries since the apicid field
in MADT is only 8 bits.
User Space Notification
Hotplug support for devices is common in Linux today. Its being used today to
support automatic configuration of network, usb and pci devices. A hotplug
event can be used to invoke an agent script to perform the configuration task.
You can add /etc/hotplug/cpu.agent to handle hotplug notification user space
#!/bin/bash
# $Id: cpu.agent
# Kernel hotplug params include:
#ACTION=%s [online or offline]
#DEVPATH=%s
cd /etc/hotplug
. ./hotplug.functions
case $ACTION in
&&&&&&&&&&&&&&&&&&
&&&&&&&&&&&&&&&&&&&&&&&&&&&& echo `date` ":cpu.agent" add cpu >> /tmp/hotplug.txt
&&&&&&&&&&&&&&&&&&&&&&&&&&&& ;;
&&&&&&&&&&&&&&&&&&
&&&&&&&&&&&&&&&&&&&&&&&&&&&& echo `date` ":cpu.agent" remove cpu >>/tmp/hotplug.txt
&&&&&&&&&&&&&&&&&&&&&&&&&&&& ;;
&&&&&&&&&&&&&&&&&&
&&&&&&&&&&&&&&&&&&&&&&&&&&&& debug_mesg CPU $ACTION event not supported
&&&&&&&& exit 1
&&&&&&&& ;;
阅读(4862) | 评论(0) | 转发(1) |
相关热门文章
给主人留下些什么吧!~~
请登录后评论。

我要回帖

更多关于 linux hotplug 的文章

 

随机推荐