3.5.1.245. raw_local_irq_disable
#define raw_local_irq_disable() arch_local_irq_disable()
raw_local_irq_disable
用于禁止本地中断,其作为一个过度接口,用于指向与体系相关的函数.
3.5.1.246. raw_smp_processor_id
#define raw_smp_processor_id (current_thread_info()->cpu)
static inline struct thread_info *current_thread_info(void)
{
return (struct thread_info *)(current_stack_pointer & ~(THREAD_SIZE - 1));
}
raw_smp_processor_id
用于获得当前SMP系统使用的CPU号
3.5.1.247. rmem_cma_device_init
static int rmem_cma_device_init(struct reserved_mem *rmem, struct device *dev)
{
dev_set_cma_area(dev, rmem->priv);
return 0;
}
static inline void dev_set_cma_area(struct device *dev, struct cma *cma)
{
if(dev)
dev->cma_area = cma;
}
rmem_cma_device_init
用于在CMA region初始化过程中,设置CMA region对应的device
3.5.1.248. rmem_cma_device_release
static void rmem_cma_device_release(struct reserved_mem *rmem, struct device *dev)
{
dev_set_cma_area(dev, NULL);
}
3.5.1.249. rmem_cma_setup
static int __init rmem_cma_setup(struct reserved_mem *rmem)
{
phys_addr_t align = PAGE_SIZE << max(MAX_ORDER - 1, pageblock_order);
phys_addr_t mask = align - 1;
unsigned long node = rmem->fdt_node;
struct cma *cma;
int err;
if(!of_get_flat_dt_prop(node, "reusable", NULL) || of_get_flat_dt_prop(node, "no-map", NULL))
return -EINVAL;
if((rmem->base & mask) || (rmem->size & mask)) {
pr_err("Reserved memory: incorrect alignment of CMA region\n");
return -EINVAL;
}
err = cma_init_reserved_mem(rmem->base, rmem->size, 0, rmem->name, &cma);
if(err) {
pr_err("Reserved memory: unable to setup CMA region\n");
return err;
}
dma_contiguous_early_fixup(rmem->base, rmem->size);
if(of_get_flat_dt_prop(node, "linux, cma-default", NULL))
dma_contiguous_set_default(cma);
rmem->ops = &rmem_cma_ops;
rmem->priv = cma;
return 0;
}
RESERVEDMEM_OF_DECLARE(cma, "shared-dma-pool", rmem_cma_setup);
rmem_cma_setup
将dts中reserved-memory节点的子节点,compatible属性值为”shared-dma-pool”的节点为CMA region
3.5.1.250. rmem_dma_setup
static int __init rmem_dma_setup(struct reserved_mem *rmem)
{
unsigned long node = rmem->fdt_node;
//判断rmem对应的节点是否包含reusable属性
if(of_get_flat_dt_prop(node, "reusable", NULL))
return -EINVAL;
#ifdef CONFIG_ARM
if(!of_get_flat_dt_prop(node, "no-map", NULL)) {
pr_err("Reserved memory: regions without no-map are not yet supported\n");
return -EINVAL;
}
if(of_get_flat_dt_prop(node, "linux,dma-default", NULL)) {
dma_reserved_default_memory = rmem;
}
#endif
rmem->ops = &rmem_dma_ops;
return 0;
}
rmem_dma_setup
用于初始化DMA的预留区
注解
DMA的物理内存区域是不能给其他程序使用,所以要将DMA设置为独占,但”reusable”属性的存在代表不独占重复使用
3.5.1.251. RESERVEDMEM_OF_DECLARE
#define RESERVEDMEM_OF_DECLARE(name, compat, init) \
_OF_DECLARE(reservedmem, name, compat, init, reservedmem_of_init_fn)
RESERVEDMEM_OF_DECLARE
宏用在__reservedmem_of_table section内建立一个struct of_device_id其compat成员就是compat参数,并且该数据结构
的data成员就是init参数
3.5.1.252. __reserved_mem_alloc_size
static int __init __reserved_mem_alloc_size(unsigned long node, const char *uname, phys_addr_t *res_base,
phys_addr_t *res_size)
{
int t_len = (dt_root_addr_cells + dt_root_size_cells) * sizeof(__be32);
phys_addr_t start = 0, end = 0;
phys_addr_t base = 0, align = 0, size;
int len;
const __be32 *prop;
int nomap;
int ret;
//
prop = of_get_flat_dt_prop(node, "size", &len);
if(!prop)
return -EINVAL;
if(len != dt_root_size_cells * sizeof(__be32))
return -EINVAL;
size = dt_mem_next_cell(dt_root_size_cells, &prop);
nomap = of_get_flat_dt_prop(node, "no-map", &len);
prop = of_get_flat_dt_prop(node, "alignment", &len);
if(prop) {
if(len != dt_root_addr_cells * sizeof(__be32)) {
return -EINVAL;
}
align = dt_mem_next_cell(dt_root_addr_cells, &prop);
}
if(IS_ENABLED(CONFIG_CMA) && of_flat_dt_is_compatible(node, "shared-dma-pool")
&& of_get_flat_dt_prop(node, "reusable", NULL) &&
!of_get_flat_dt_prop(node, "no-map", NULL)) {
unsigned long order = max_t(unsigned long, MAX_ORDER - 1, pageblock_order);
align = max(align, (phys_addr_t)PAGE_SIZE << order);
}
prop = of_get_flat_dt_prop(node, "alloc-ranges", &len);
if(prop) {
if(len % t_len != 0)
return -EINVAL;
base = 0;
while(len > 0) {
start = dt_mem_next_cell(dt_root_addr_cells, &prop);
end = start + dt_mem_next_cell(dt_root_addr_cells, &prop);
ret = early_init_dt_alloc_reserved_memory_arch(size, align, start, end, nomap, &base);
if(ret == 0)
break;
len -= t_len;
}
} else {
ret = early_init_dt_alloc_reserved_memory_arch(size, align, 0, 0, nomap, &base);
}
if(base == 0)
return -ENOMEM;
*res_base = base;
*res_size = size;
}
__reserved_mem_alloc_size
用于为dts reserved-memory节点中特定子节点分配内存,该类节点包含size属性,但不包含reg属性,
因此要对这类子节点分配物理内存.这类节点例如
reserved-memory {
#address-cells = <1>;
#size-cells = <1>;
ranges;
default-pool {
compatible = "shared-dma-pool";
size = <0x2000000>;
alloc-ranges = <0x61000000 0x4000000>;
alignment = <0x1000000>;
reusable;
linux,cma-default;
};
};
3.5.1.253. __reserved_mem_check_root
static int __init __reserved_mem_check_root(unsigned long node)
{
const __be32 *prop;
prop = of_get_flat_dt_prop(node, "#size-cells", NULL);
if(!prop || be32_to_cpup(prop) != dt_root_size_cells)
return -EINVAL;
prop = of_get_flat_dt_prop(node, "#address-cells", NULL);
if(!prop || be32_to_cpup(prop) != dt_root_size_cells)
return -EINVAL;
prop = of_get_flat_dt_prop(node, "ranges", NULL);
if(!prop)
return -EINVAL;
return 0;
}
__reserved_mem_check_root
用于检查指定node的”#size-cells”属性值和”#address-cells”属性值是否一致,
并确保节点包含”ranges”属性
3.5.1.254. __reserved_mem_init_node
//rmem为reserved_mem[]数组中的成员
static int __init __reserved_mem_init_node(struct reserved_mem *rmem)
{
extern const struct of_device_id __reservedmem_of_table[];
const struct of_device_id *i;
//获得__reservedmem_of_table表基地址,表里都是__reservedmem_of_table section成员
//每个成员都包含特定的初始化程序
for(i = __reservedmem_of_table; i < &__rmem_of_table_sentinel; i++)
{
reservedmem_of_init_fn initfn = i->data;
const char *compat = i->compatible;
//遍历所有成员,如果rmem对应节点的compatible和遍历到成员的compatible相同
//则使用成员的初始化函数初始化该节点
if(!of_flat_dt_is_compatible(rmem->fdt_node, compat))
continue;
if(initfn(rmem) == 0) {
return 0;
}
}
return -ENOENT;
}
__reserved_mem_init_node
用于初始化rmem对应的节点
3.5.1.255. __rmem_check_for_overlap
static void __init __rmem_check_for_overlap(void)
{
int i;
//如果预留区的数量小于2,则没必要检测
if(reserved_mem_count < 2)
return;
//对reserved_mem数组中预留区按基地址进行排序
sort(reserved_mem, reserved_mem_count, sizeof(reserved_mem[0]), __rmem_cmp, NULL);
for(i = 0; i < reserved_mem_count - 1; i++)
{
struct reserved_mem *this, *next;
this = &reserved_mem[i];
next = &reserved_mem[i + 1];
if(!(this->base && next->base))
continue;
if(this->base + this->size > next->base)
{
phys_addr_t this_end, next_end;
this_end = this->base + this->size;
next_end = next->base + next->size;
}
}
}
__rmem_check_for_overlap
检查reserved_mem维护的预留区是否存在重叠部分.
3.5.1.256. __round_mask
#define __round_mask(x, y) ((__typeof__(x))((y)-1))