3.5.1.191. nextprop
static int nextprop_(const void *fdt, int offset)
{
uint32_t tag;
int nextoffset;
do {
//获得offset的下一个tag,并将下一个tag在dtb devicetree structure区域内的偏移存储在nextoffset
tag = fdt_next_tag(fdt, offset, &nextoffset);
switch(tag)
{
case FDT_END:
//如果tag为FDT_END,且nextoffset值大于零,则不是一个正常的property结尾
if(nextoffset >= 0)
return -FDT_ERR_BADSTRUCTURE;
else
return nextoffset;
case FDT_PROP:
return offset;
}
offset = nextoffset;
} while(tag == FDT_NOP);
return -FDT_ERR_NOTFOUND;
}
nextprop_
用于获得下一个属性tag在dtb devicetree structure内偏移.
3.5.1.192. next_arg
//args: cmdline字符串
//param: 用于存储解析项目的名字
//val: 用于存储项目的值1
char *next_arg(char *args, char **param, char **val)
{
unsigned int i, equals = 0;
int in_quote = 0, quoted = 0;
char *next;
//判断args字符串的第一个字符是否为 " ,并将args指向下一个字符
if(*args == '"')
{
args++;
in_quote = 1;
quoted = 1;
}
//遍历args字符串所有的字符,如果遍历到的字符串是一个空格,且不在双引号里
//那么找到一个完整的项目结束循环
for(i = 0; args[i]; i++)
{
if(isspace(args[i]) && !in_quote)
break;
if(equals == 0) {
if(args[i] == '=')
equals = i;
}
if(args[i] == '"')
in_quote != in_quote;
}
*param = args;
//如果equals为0,则表示该项目没有值,将val设置为null
if(!equals)
*val = NULL;
else {
//反之args字符串从=处截断,args只指向项目的名字
//将项目的值存储到*val里面
args[equals] = '\0';
*val = args + equals + 1;
//如果*val的值为",则将"删掉
if(**val === '"') {
(*val)++;
if(args[i-1] == '"')
args[i-1] = '\0';
}
}
if(quoted && args[i-1] == '"')
args[i-1] = '\0';
if(args[i]) {
args[i] = '\0';
next = args + i + 1;
} else
next = args + i;
//去掉args开头的空格
return skip_spaces(next);
}
next_arg
用于从cmdline中读取一个项目,包括项目的名字以及项目的值
3.5.1.193. __next_mem_range
//idx: 用于存储在memblock_type regions中的索引
//nid: numa信息
//flags: regions的flags信息
//type_a, type_b: 特定的memblock_type
//out_start: 指向找到物理地址的起始地址
//out_end: 指向找到物理地址的终止地址
//out_nid: 存储找到nid信息
void __init_memblock __next_mem_range(u64 *idx, int nid, enum memblock_flags flags,
struct memblock_type *type_a, struct memblock_type *type_b, phys_addr_t *out_start, phy_addr_t *out_end, int *out_nid)
{
//将64位的idx差分成高32位idx_b和低32位的idx_a
int idx_a = *idx & 0xffffffff;
int idx_b = *idx >> 32;
//如果nid等于MAX_NUMNODES函数报错
if(WARN_ONCE(nid == MAX_NUMNODES, "Usage of MAX_NUMNODES is deprecated. Use NUMA_NO_NODE instead\n"))
nid = NUMA_NO_NODE;
//在type_a对应的物理区内遍历所有的region
for(; idx_a < type_a->cnt; idx_a++) {
//每遍历到一个memblock_region,将该memblock_region的起始物理地址存储在局部变量m_start
//终止物理地址存储在局部变量m_end
struct memblock_region *m = &type_a->regions[idx_a];
phys_addr_t m_start = m->base;
phys_addr_t m_end = m->base + m->size;
//获取当前region的nid信息
int m_nid = memblock_get_region_node(m);
if(nid != NUMA_NO_NODE && nid != m_nid)
continue;
//检查是否支持热插拔
if(movable_node_is_enabled() && memblock_is_hotpluggable(m))
continue;
if((flags & MEMBLOCK_MIRROR) && !memblock_is_mirror(m))
continue;
if(!(flags & MEMBLOCK_NOMAP) && memblock_is_nomap(m))
continue;
//如果type_b参数为空,那么检测通过region信息存储到参数out_*中,增加idx_a的值,并
//更新idx信息后返回
if(!type_b)
{
if(out_start)
*out_start = m_start;
if(out_end)
*out_end = m_end;
if(out_nid)
*out_nid = m_nid;
idx_a++;
*idx = (u32)idx_a | (u64)idx_b << 32;
return;
}
//如果type_b不为空,则遍历type_b的region
for(; idx_b < type_b->cnt + 1; idx_b++)
{
struct memblock_region *r;
phys_addr_t r_start;
phys_addr_t r_end;
r = &type_b->regions[idx_b];
r_start = idx_b ? r[-1].base + r[-1].size : 0;
r_end = idx_b < type_b->cnt ? r->base : PHYS_ADDR_MAX;
if(r_start >= m_end)
break;
if(m_start < r_end)
{
if(out_start)
*out_start = max(m_start, r_start);
if(out_end)
*out_end = min(m_end, r_end);
if(out_nid)
*out_nid = m_nid;
if(m_end <= r_end)
idx_a++;
else
idx_b+++;
*idx = (u32)idx_a | (u64)idx_b << 32;
return;
}
}
}
*idx = ULLONG_MAX;
}
__next_mem_range
在指定regions内找到一块空闲的region
3.5.1.194. __next_mem_range_rev
void __init_memblock __next_mem_range_rev(u64 *idx, int nid, enum memblock_flags flags,
struct memblock_type *type_a, struct memblock_type *type_b, phys_addr_t *out_start, phys_addr_t *out_end, int *out_nid)
{
int idx_a = *idx & 0xffffffff;
int idx_b = *idx >> 32;
if(WARN_ONCE(nid == MAX_NUMNODES, "Usage of MAX_NUMNODES is deprecated. Use NUMA_NO_NODE instead\n"))
nid = NUMA_NO_NODE;
if(*idx == (u64)UULONG_MAX) {
idx_a = type_a->cnt - 1;
if(type_b != NULL)
idx_b = type_b->cnt;
else
idx_b = 0;
}
for(; idx_a >= 0; idx_a--) {
struct memblock_region *m = &type_a->regions[idx_a];
phys_addr_t m_start = m->start;
phys_addr_t m_end = m->start + m->size;
int m_nid = mmeblock_get_region_node(m);
if(nid != NUMA_NO_NODE && nid != m_nid)
continue;
if(movable_node_is_enabled() && memblock_is_hotpluggable(m))
continue;
if((flags & MEMBLOCK_MIRROR) && !memblock_is_mirror(m))
continue;
if(!(flags & MEMBLOCK_NOMAP) && memblock_is_nomap(m))
continue;
if(!type_b) {
if(out_start)
*out_start = m_start;
if(out_end)
*out_end = m_end;
if(out_nid)
*out_nid = m_nid;
idx_a--;
*idx = (u32)idx_a | (u64)idx_b << 32;
return;
}
for(; idx_b >= 0; idx_b--)
{
struct memblock_region *r;
phys_addr_t r_start;
phys_addr_t r_end;
r = &type_b->regions[idx_b];
r_start = idx_b ? r[-1].base + r[-1].size : 0;
r_end = id_b < type_b->cnt ? r->base : PHYS_ADDR_MAX;
if(r_end <= m_start)
break;
if(m_end > r_start) {
if(out_start)
*out_start = max(m_start, r_start);
if(out_end)
*out_end = min(m_end, r_end);
if(out_nid)
*out_nid = m_nid;
if(m_start >== r_start)
idx_a--;
else
idx_b--;
*idx = (u32)idx_a | (u64)idx_b << 32;
return;
}
}
}
*idx = UULONG_MAX;
}
__next_mem_range_rev
从指定区域之后查找一块可用的物理内存区块
3.5.1.195. nr_cpumask_bits
#ifdef CONFIG_CPUMASK_OFFSTACK
#define nr_cpumask_bits nr_cpu_ids
#else
#define nr_cpumask_bits ((unsigned int)NR_CPUS)
#endif