Linux芯片级移植与底层驱动(基于3…
来源:互联网 发布:多多返利网站源码 编辑:程序博客网 时间:2024/04/30 23:10
宋宝华 Barry Song <<ahref="mailto:21cnbao@gmail.com">21cnbao@gmail.com>
新浪微博: @宋宝华Barry
在Linux系统中,对于多核的ARM芯片而言,Bootrom代码中,CPU0会率先起来,引导Bootloader和Linux内核执行,而其他的核则在上电时Bootrom一般将自身置于WFI或者WFE状态,并等待CPU0给其发CPU核间中断(IPI)或事件(一般透过SEV指令)唤醒之。一个典型的启动过程如下图:
被CPU0唤醒的CPUn可以在运行过程中进行热插拔。譬如运行如下命令即可卸载CPU1并且将CPU1上的任务全部迁移到其他CPU:
# echo 0 >/sys/devices/system/cpu/cpu1/online
同样地,运行如下命令可以再次启动CPU1:
# echo 1 >/sys/devices/system/cpu/cpu1/online
之后CPU1会主动参与系统中各个CPU之间要运行任务的负载均衡工作。
CPU0唤醒其他CPU的动作在内核中被封装为一个smp_operations的结构体,该结构体的成员如下:
666DT_MACHINE_START(VEXPRESS_DT,"ARM-Versatile Express")
透过arch/arm/mach-vexpress/platsmp.c的实现代码可以看出,smp_operations的成员函数smp_init_cpus() 即vexpress_smp_init_cpus()会探测SoC内CPU核的个数,并设置了核间通信的方式为gic_raise_softirq()。可见于vexpress_smp_init_cpus()中调用的vexpress_dt_smp_init_cpus():
103static void __initvexpress_dt_smp_init_cpus(void)
128
而smp_operations的成员函数smp_prepare_cpus()即vexpress_smp_prepare_cpus()则会透过v2m_flags_set(virt_to_phys(versatile_secondary_startup))设置其他CPU的启动地址为versatile_secondary_startup:
179static void __initvexpress_smp_prepare_cpus(unsigned int max_cpus)
注意这部分的具体实现方法是SoC相关的,由芯片的设计以及芯片内部的Bootrom决定。对于VEXPRESS来讲,设置方法如下:
139void __init v2m_flags_set(u32data)
即填充v2m_sysreg_base +V2M_SYS_FLAGSCLR地址为0xFFFFFFFF,将其他CPU初始启动执行的指令地址填入v2m_sysreg_base + V2M_SYS_FLAGSSET。这2个地址属于芯片实现时候设定的。填入的CPUn的起始地址都透过virt_to_phys()转化为物理地址,因为此时CPUn的MMU尚未开启。
比较关键的是smp_operations的成员函数smp_boot_secondary(),它完成最终的CPUn的唤醒工作:
上述代码中高亮的部分首先会将pen_release变量设置为要唤醒的CPU核的CPU号cpu_logical_map(cpu),而后透过gic_raise_softirq(cpumask_of(cpu),0)给CPUcpu发起0号IPI,这个时候,CPUcpu核会从前面smp_operations中的smp_prepare_cpus()成员函数即vexpress_smp_prepare_cpus()透过v2m_flags_set()设置的其他CPU核的起始地址versatile_secondary_startup开始执行,如果顺利的话,该CPU会将原先为正数的pen_release写为-1,以便CPU0从等待pen_release成为-1的循环中跳出。
versatile_secondary_startup实现于arch/arm/plat-versatile/headsmp.S,是一段汇编:
第1段高亮的部分实际上是等待pen_release成为CPU0设置的cpu_logical_map(cpu),一般直接就成立了。第2段高亮的部分则调用到内核通用的secondary_startup()函数,经过一系列的初始化如MMU等,最终新的被唤醒的CPU将调用到smp_operations的smp_secondary_init()成员函数,对于本例为versatile_secondary_init():
上述代码中高亮的那1行会将pen_release写为-1,于是CPU0还在执行的 versatile_boot_secondary()函数中的如下循环就退出了:
此后CPU0和新唤醒的其他CPU各自狂奔。整个系统在运行过程中会进行实时进程和正常进程的动态负载均衡。
CPU hotplug的实现也是芯片相关的,对于VEXPRESS而言,实现了smp_operations的cpu_die()成员函数即vexpress_cpu_die()。它会在进行CPUn的拔除操作时将CPUn投入低功耗的WFI状态,相关代码位于arch/arm/mach-vexpress/hotplug.c:
CPUn睡眠于wfi(),之后再次online的时候,又会因为CPU0给它发出的IPI而从wfi()函数返回继续执行,醒来时CPUn也判决了是否pen_release ==cpu_logical_map(cpu)成立,以确定该次醒来确确实实是由CPU0唤醒的一次正常醒来。
本文出自 “宋宝华的博客”博客,请务必保留此出处http://21cnbao.blog.51cto.com/109393/1143518
- Linux芯片级移植与底层驱动(基于3…
- Linux芯片级移植与底层驱动(基于3…
- Linux芯片级移植与底层驱动
- Linux芯片级移植与底层驱动(基于3.7.4内核)
- Linux芯片级移植与底层驱动(基于3.7.4内核) --内核节拍
- Linux芯片级移植与底层驱动(基于3.7.4内核)
- Linux芯片级移植与底层驱动(基于3.7.4内核)
- Linux芯片级移植与底层驱动(基于3.7.4内核) --中断控制器
- Linux芯片级移植与底层驱动(基于3.7.4内核) --内核节拍
- Linux芯片级移植与底层驱动(基于3.7.4内核)
- Linux芯片级移植与底层驱动(基于3.7.4内核)
- Linux芯片级移植与底层驱动(基于3.7.4内核) --中断控制器
- Linux芯片级移植与底层驱动(基于3.7.4内核)
- Linux芯片级移植与底层驱动(基于3.7.4内核)(GPIO&&pinctrl&&clk)
- Linux芯片级移植与底层驱动(基于3.7.4内核)
- Linux芯片级移植与底层驱动(基于3.7.4内核)
- Linux芯片级移植与底层驱动(基于3.7.4内核) --中断控制器
- Linux芯片级移植与底层驱动(基于3.7.4内核) --内核节拍
- 最简单的 Git 使用流程
- 最简单的 Git 使用流程
- 通用设备的动态DMA映射
- 通用设备的动态DMA映射
- Linux芯片级移植与底层驱动(基于3…
- Linux芯片级移植与底层驱动(基于3…
- 并发与竞态及解决途径
- 在开关电源中 反馈电压分压电阻接输出的一个电阻并联一个电容的作用是什么。如图中C1就是一个例子
- 并发与竞态及解决途径
- Device drivers on SMP systems
- Device drivers on SMP systems
- linux中断嵌套以及中断丢失
- linux中断嵌套以及中断丢失
- ldd3学习之七:中断处理