-
一、概述
-
如果仔细地阅读完初始化函数start_kernel,就会发现里面还有调用smp_processor_id()函数,这两个函数都是获取多处理器的ID,为什么会需要两个函数呢?其实这里有一个差别的,smp_setup_processor_id()函数可以不调用setup_arch()初始化函数就可以使用,而smp_processor_id()函数是一定要调用setup_arch()初始化函数后,才能使用。smp_setup_processor_id()函数是直接从cpu寄存器获取对称多处理器的ID,而smp_processor_id()函数是获取内核变量保存的处理器ID,因此一定要调用初始化函数。由于smp_setup_processor_id()函数不用调用初始化函数,可以放在内核初始化start_kernel函数的最前面使用,而函数smp_processor_id()只能放到setup_arch()函数调用的后面使用了。
-
-
二、代码
-
//.../arch/arm/kernel/setup.c
-
void __init smp_setup_processor_id(void)
-
{
-
int i;
-
//判断是否是smp系统,如果是则从arm协处理器读取当前cpuid,否则为0
-
u32 mpidr = is_smp() ? read_cpuid_mpidr() & MPIDR_HWID_BITMASK : 0;
-
//根据level确定cpu号,即cpu=(mpidr>>0)&0xff
-
u32 cpu = MPIDR_AFFINITY_LEVEL(mpidr, 0);
-
-
//设置cpu的map数组
-
//#define cpu_logical_map(cpu) __cpu_logical_map[cpu]
-
cpu_logical_map(0) = cpu;
-
//nr_cpu_ids表示系统中cpu总数
-
for (i = 1; i < nr_cpu_ids; ++i)
-
cpu_logical_map(i) = i == cpu ? 0 : i;
-
-
set_my_cpu_offset(0);
-
-
pr_info("Booting Linux on physical CPU 0x%x\n", mpidr);
-
}
-
-
//检测是否为SMP架构
-
static inline bool is_smp(void)
-
{
-
#ifndef CONFIG_SMP
-
return false;
-
//CONFIG_SMP_ON_UP表示可以支援SMP Kernel运行在UniProcessor(單核心)的处理器上
-
#elif defined(CONFIG_SMP_ON_UP)
-
extern unsigned int smp_on_up;
-
return !!smp_on_up;
-
#else
-
return true;
-
#endif
-
}
-
-
//arch/arm/include/asm/cputype.h
-
static inline unsigned int __attribute_const__ read_cpuid_mpidr(void)
-
{
-
//从arm协处理器CP15的c0中读取当前cpu id
-
return read_cpuid(CPUID_MPIDR);
-
}
-
-
#define CPUID_MPIDR 5
-
#define read_cpuid(reg) \
-
({ \
-
unsigned int __val; \
-
asm("mrc p15, 0, %0, c0, c0, " __stringify(reg) \
-
: "=r" (__val) \
-
: \
-
: "cc"); \
-
__val; \
-
})
-
-
#define MPIDR_AFFINITY_LEVEL(mpidr, level) \
-
((mpidr >> (MPIDR_LEVEL_BITS * level)) & MPIDR_LEVEL_MASK)
-
-
static inline void set_my_cpu_offset(unsigned long off)
-
{
-
//Set TPIDRPRW
-
asm volatile("mcr p15, 0, %0, c13, c0, 4" : : "r" (off) : "memory");
- }