目录
3.Cotex-A75 spec关于MPIDR_EL寄存器的说明
本文目的在于理解MPIDR_EL1寄存器,掌握处理器亲和寄存器作用。
1.MPIDR_EL1寄存器作用
多核处理器的亲和寄存器,每个处理器单元都具有独立该寄存器。该寄存器值为该处理单元的另一种标识、表示对应处理器单元的亲和力,该值用于系统调度。
2.关于MPIDR_EL1的个人理解
该寄存器更像是为了解决64bit、多核系统问题,而对MPIDR寄存器的扩展;该寄存器的低32bit与MPIDR一致。
3.Cotex-A75 spec关于MPIDR_EL寄存器的说明
a.该寄存器为只读寄存器
b.AFF3 & AFF2 都为ClusterID(从软件角度理解为不同CPU组的ID),AFF1 为CPUID, AFF0 为多线程核的线程ID
d.U 表示是多Cluster还是单Cluster
4.MPIDR_EL1在devicetree中的体现
配置DTS时,需要设置MPIDR_EL1的值到CPU node中的reg property,以ArmV8 64bit系统为例:当#address-cell property为2时,需要设置MPIDR_EL1[39:32]到reg[7:0]、MPIDR_EL1[23:0]到reg[23:0]; 当#address-cell property为1时,需要设置MPIDR_EL1[23:0]到reg[23:0];reg的其他位设置位0。
参考:Documentation/devicetree/bindings/arm/cpus.txt
5.Linux启动过程中MPIDR_EL1的相关逻辑
a.内核中定义了cpu的逻辑映射变量如下,该变量保存MPIDR_EL1寄存器中亲和值。
/* * Logical CPU mapping. */
extern u64 __cpu_logical_map[NR_CPUS];
#define cpu_logical_map(cpu) __cpu_logical_map[cpu]
b.cpu0(boot cpu/primary cpu)获取mpidr_el1亲和值的方式与其他cpu(secondary cpu)
获取方式有所不同。
void __init smp_setup_processor_id(void)
{
/*启动该过程时只有boot cpu即cpu0在执行,其他cpu还未启动
通过read_cpuid_mpidr获取的MPIDR_EL1值即为当前执行的CPU0
的亲和值*/
u64 mpidr = read_cpuid_mpidr() & MPIDR_HWID_BITMASK;
/*将获取到的cpu0的亲和值保存在cpu_logical_map(0)*/
cpu_logical_map(0) = mpidr;
/*
* clear __my_cpu_offset on boot CPU to avoid hang caused by
* using percpu variable early, for example, lockdep will
* access percpu variable inside lock_release
*/
set_my_cpu_offset(0);
pr_info("Booting Linux on physical CPU 0x%lx\n", (unsigned long)mpidr);
}
c.其他cpu(secondary cpu)亲和值获取方式
static void __init of_parse_and_init_cpus(void)
{
struct device_node *dn;
for_each_node_by_type(dn, "cpu") { //遍历dts中cpu node
u64 hwid = of_get_cpu_mpidr(dn); //获取该cpu node中reg property的值
if (hwid == INVALID_HWID)
goto next;
//判断hwid是否重复,若重复则直接忽略、进行后续Cpu node判断;
if (is_mpidr_duplicate(cpu_count, hwid)) {
pr_err("%pOF: duplicate cpu reg properties in the DT\n",
dn);
goto next;
}
/*
* The numbering scheme requires that the boot CPU
* must be assigned logical id 0. Record it so that
* the logical map built from DT is validated and can
* be used.
*/
//获取的hwid与CPU0 hwid相同时则认定该cpu node为cpu0对应的node
if (hwid == cpu_logical_map(0)) {
if (bootcpu_valid) {
pr_err("%pOF: duplicate boot cpu reg property in DT\n",
dn);
goto next;
}
bootcpu_valid = true;
early_map_cpu_to_node(0, of_node_to_nid(dn));
/*
* cpu_logical_map has already been
* initialized and the boot cpu doesn't need
* the enable-method so continue without
* incrementing cpu.
*/
continue;
}
if (cpu_count >= NR_CPUS)
goto next;
pr_debug("cpu logical map 0x%llx\n", hwid);
//记录该cpu的node 和 hwid
cpu_logical_map(cpu_count) = hwid;
early_map_cpu_to_node(cpu_count, of_node_to_nid(dn));
next:
cpu_count++;
}
}