设备驱动-RESERVEDMEM_OF_DECLARE预留内存-dts匹配-init函数调用
RESERVEDMEM_OF_DECLARE
在 include/linux/of_reserved_mem.h
11struct reserved_mem { 12 const char *name; 13 unsigned long fdt_node; 14 unsigned long phandle; 15 const struct reserved_mem_ops *ops; 16 phys_addr_t base; 17 phys_addr_t size; 18 void *priv; 19}; 21struct reserved_mem_ops { 22 int (*device_init)(struct reserved_mem *rmem, 23 struct device *dev); 24 void (*device_release)(struct reserved_mem *rmem, 25 struct device *dev); 26}; 28typedef int (*reservedmem_of_init_fn)(struct reserved_mem *rmem); 30#define RESERVEDMEM_OF_DECLARE(name, compat, init) \ 31 _OF_DECLARE(reservedmem, name, compat, init, reservedmem_of_init_fn)
30 - 定义 - 需要 3 个参数, name ,compat, init ;
name 就是一个名称 , 用来构建变量名称 ;
compat 是字符串,和 dts 中的 compatible 字符串匹配 ;
init 是一个函数, 函数 , 这个函数 类型 需要 是 reservedmem_of_init_fnc 这样的类型,即 返回 int , 参数为 reserved_mem 指针;
_OF_DECLARE
_OF_DECLARE 在 include/linux/of.h
1300#define _OF_DECLARE(table, name, compat, fn, fn_type) \
1301 static const struct of_device_id __of_table_##name \
1302 __used __section("__" #table "_of_table") \
1303 = { .compatible = compat, \
1304 .data = (fn == (fn_type)NULL) ? fn : fn }
构建一个 static 的 struct of_device_id 对象 __of_device_name ,这个对象放在 __reservedmem_of_table 这个 section 里面 ;
对象的 compatible 赋值为 compat 字符串; .data 赋值为 fn ;
(fn==(fn_type)NULL)? 这个 检查, 主要作用就是 检查 fn 函数 类型 是 fn_type 。 如果不是,编译就会报错 ;
示例:
drivers/soc/fsl/qbman/qman_ccsr.c
482static int qman_pfdr(struct reserved_mem *rmem) 483{ 484 pfdr_a = rmem->base; 485 pfdr_sz = rmem->size; 486 487 WARN_ON(!(pfdr_a && pfdr_sz)); 488 489 return 0; 490} 491RESERVEDMEM_OF_DECLARE(qman_pfdr, "fsl,qman-pfdr", qman_pfdr);
这样就 定义了 一个 struct of_device_id __of_device_qman_pfdr = {.compatible = "fsl,qman-pfdr" , .data = qman_fpdr } ;
qman_pfdr 函数类型,确实是 int qman_pfdr(struct reserved_mem * rmem) ;
dts 中reserved memory 解析和调用匹配的 of_device_id 的 .data 函数
setup_arch
--->arm64_memblock_init
--->early_init_fdt_scan_reserved_mem
--->fdt_init_reserved_mem
--->__reserved_mem_init_node
fdt_init_reserved_mem
drivers/of/of_reserved_mem.c
246void __init fdt_init_reserved_mem(void) 247{ 248 int i; 253 for (i = 0; i < reserved_mem_count; i++) { 254 struct reserved_mem *rmem = &reserved_mem[i]; 255 unsigned long node = rmem->fdt_node; 256 int len; 257 const __be32 *prop; 258 int err = 0; 259 bool nomap; 260 261 nomap = of_get_flat_dt_prop(node, "no-map", NULL) != NULL; 262 prop = of_get_flat_dt_prop(node, "phandle", &len); 263 if (!prop) 264 prop = of_get_flat_dt_prop(node, "linux,phandle", &len); 265 if (prop) 266 rmem->phandle = of_read_number(prop, len/4); 267 268 if (rmem->size == 0) 269 err = __reserved_mem_alloc_size(node, rmem->name, 270 &rmem->base, &rmem->size); 271 if (err == 0) { 272 err = __reserved_mem_init_node(rmem); 273 if (err != 0 && err != -ENOENT) { 274 pr_info("node %s compatible matching fail\n", 275 rmem->name); 276 memblock_free(rmem->base, rmem->size); 277 if (nomap) 278 memblock_add(rmem->base, rmem->size); 279 } 280 } 281 } 282}
253 - for 循环处理每一块 reserved memory
268 ~ 269 如果还没有为 node 预留内存,则使用 __reserved_mem_alloc_size ,继续解析 node 的 dts 中的 参数,预留内存。
271 err == 0 ,说明预留内存成功, 对预留的这部分内存 调用 __reserved_mem_init_node 函数(下面详述) ;
如果 __reserved_mem init node 失败了, 则需要释放 预留的这部分内存 。 先 memblock free ; 如果 有 nomap 属性,则还需要进一步把这块内存 add 到 memblock 的memory type 的 链表中 ;
__reserved_mem_init_node
drivers/of/of_reserved_mem.c
170static int __init __reserved_mem_init_node(struct reserved_mem *rmem) 171{ 172 extern const struct of_device_id __reservedmem_of_table[]; 173 const struct of_device_id *i; 174 int ret = -ENOENT; 175 176 for (i = __reservedmem_of_table; i < &__rmem_of_table_sentinel; i++) { 177 reservedmem_of_init_fn initfn = i->data; 178 const char *compat = i->compatible; 179 180 if (!of_flat_dt_is_compatible(rmem->fdt_node, compat)) 181 continue; 182 183 ret = initfn(rmem); 184 if (ret == 0) { 185 pr_info("initialized node %s, compatible id %s\n", 186 rmem->name, compat); 187 break; 188 } 189 } 190 return ret; 191} 192
对 rmem ,遍历 __reservedmem_of_table 这个 section 里面 的所有 of_device_id 对象 ;
rmem 的 fdt_node 和 of_device_id 对象的 compat (char * 字符串) 进行匹配
匹配成功,调用 of_device_id 的 data 字段 里面存放的函数 。 initfn( rmem ) ;
下一篇:
memory-region和of_reserved_mem_device_init将设备与reserved mem关联
https://www.cnblogs.com/zhangzhiwei122/p/16125822.html