概要
* struct machine_desc - Board specific callbacks, called from ARC common code
* Provided by each ARC board using MACHINE_START()/MACHINE_END(), so
* a multi-platform kernel builds with array of such descriptors.
* We extend the early DT scan to also match the DT's "compatible" string
* against the @dt_compat of all such descriptors, and one with highest
* "DT score" is selected as global @machine_desc.
在这段关于machine_desc的描述中可以得出以下信息:
- 在一个平台内核中存在一个machine_desc 数组
- 对象用MACHINE_START和MACHINE_END构造
- 用设备树中“compatible”字符串匹配machine_desc中的dt_compat属性
- 在匹配过程中需要进行评分
数据结构
* @name: Board/SoC name
* @dt_compat: Array of device tree 'compatible' strings
* (XXX: although only 1st entry is looked at)
* @init_early: Very early callback [called from setup_arch()]
* @init_per_cpu: for each CPU as it is coming up (SMP as well as UP)
* [(M):init_IRQ(), (o):start_kernel_secondary()]
* @init_machine: arch initcall level callback (e.g. populate static
* platform devices or parse Devicetree)
* @init_late: Late initcall level callback
struct machine_desc {
const char *name;
const char **dt_compat;
void (*init_early)(void);
void (*init_per_cpu)(unsigned int);
void (*init_machine)(void);
void (*init_late)(void);
};
对象构造
构造通过宏实现
/*
* Set of macros to define architecture features.
* This is built into a table by the linker.
*/
#define MACHINE_START(_type, _name) \
static const struct machine_desc __mach_desc_##_type \
__used __section(".arch.info.init") = { \
.name = _name,
#define MACHINE_END \
};
构造例子如下:
static const char *hsdk_compat[] __initconst = {
"snps,hsdk",
NULL, //以空指针结束
};
MACHINE_START(SIMULATION, "hsdk")
.dt_compat = hsdk_compat,
.init_early = hsdk_init_early,
MACHINE_END
从宏的定义可知所有声明的对象存储在 .arch.info.init,该段信息如下:
.init.arch.info : {
__arch_info_begin = .; //开始
*(.arch.info.init)
__arch_info_end = .; //结束
}
遍历与评估
static const void * __init arch_get_next_mach(const char *const **match)
{
static const struct machine_desc *mdesc = __arch_info_begin; //开始位置
const struct machine_desc *m = mdesc;
if (m >= __arch_info_end) //结束位置
return NULL;
mdesc++;
*match = m->dt_compat; /返回当前的兼容性字符串数组
return m;
}
/**
* setup_machine_fdt - Machine setup when an dtb was passed to the kernel
* @dt: virtual address pointer to dt blob
*
* If a dtb was passed to the kernel, then use it to choose the correct
* machine_desc and to setup the system.
*/
const struct machine_desc * __init setup_machine_fdt(void *dt)
{
const struct machine_desc *mdesc;
unsigned long dt_root;
.....................
mdesc = of_flat_dt_match_machine(NULL, arch_get_next_mach);
.....................
return mdesc;
}
/**
* of_flat_dt_match_machine - Iterate match tables to find matching machine.
*
* @default_match: A machine specific ptr to return in case of no match.
* @get_next_compat: callback function to return next compatible match table.
*
* Iterate through machine match tables to find the best match for the machine
* compatible string in the FDT.
*/
const void * __init of_flat_dt_match_machine(const void *default_match,
const void * (*get_next_compat)(const char * const**))
{
const void *data = NULL;
const void *best_data = default_match;
const char *const *compat;
unsigned long dt_root;
unsigned int best_score = ~1, score = 0; //初始值
dt_root = of_get_flat_dt_root();
while ((data = get_next_compat(&compat))) { //循环获取下一个对象的兼容性字符串数组
score = of_flat_dt_match(dt_root, compat);
if (score > 0 && score < best_score) { //评估最佳匹配值,越小匹配度越好
best_data = data;
best_score = score;
}
}
...........................
return best_data;
}
/**
* of_fdt_is_compatible - Return true if given node from the given blob has
* compat in its compatible list
* @blob: A device tree blob
* @node: node to test
* @compat: compatible string to compare with compatible list.
*
* Return: a non-zero value on match with smaller values returned for more
* specific compatible values.
*/
static int of_fdt_is_compatible(const void *blob,
unsigned long node, const char *compat)
{
const char *cp;
int cplen;
unsigned long l, score = 0;
cp = fdt_getprop(blob, node, "compatible", &cplen); //获取设备树中的compatible属性
if (cp == NULL)
return 0;
while (cplen > 0) {
score++; //最佳匹配值为1,越大匹配度越低
if (of_compat_cmp(cp, compat, strlen(compat)) == 0)
return score;
l = strlen(cp) + 1; // compatible数组中下一个对象
cp += l;
cplen -= l;
}
return 0;
}
/*
* of_flat_dt_match - Return true if node matches a list of compatible values
*/
static int __init of_flat_dt_match(unsigned long node, const char *const *compat)
{
unsigned int tmp, score = 0;
if (!compat)
return 0;
while (*compat) { //遍历machine_desc对象中的dt_compat字符串数组,直至空
tmp = of_fdt_is_compatible(initial_boot_params, node, *compat);
if (tmp && (score == 0 || (tmp < score)))
score = tmp;
compat++;
}
return score;
}