smp模型指的是对称多处理模型(Symmetric Multi-Processor),与它对应的是NUMA非一致性存储访问结果(Non-Uniform Memory Access)和MPP海量并行处理结构(Massive Parallel Processing)。它们的区别分别在于,SMP指的是多个CPU之间是平等关系,共享全部总线,内存和IO等。但是这个结构扩展性不好,往往CPU数量多了之后,很容易遇到抢占资源的问题。NUMA结构则是把CPU分模块,每个模块具有独立的内存,IO插槽等。各个模块之间通过互联模块进行数据交互。但是这样,就表示了有的内存数据在这个CPU模块中,那么处理这个数据当然最好是选择当前的CPU模块,这样每个CPU实际上地位就不一致了。所以叫做非一致性的存储访问结构。而MPP呢,则是由多个SMP服务器通过互联网连接起来,支持SMP模型的CPU有AMD/AMD64,而支持NUMA的的X86,而smp_setup_process_id在普通情况下是空实现,在不同的体系,比如arc/arm/kernel/setup.c就有对应的逻辑。
//.../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");
}