我已经编写了一个Linux内核模块来充当基于飞思卡尔P2020RDB的定制电路板的FPGA驱动程序。 该驱动程序包含多个#defines
来指定各种地址,大小,总线宽度等。我想从驱动程序内部访问该板的拼合设备树(FDT)来configuration这些地址,因此该驱动程序可用于其他板,FPGA具有不同的大小或驻留在不同的地址。
我已经将以下简单的代码添加到模块的初始化函数中,这是我在巡航Linux内核源代码树时发现的代码:
... #include <linux/of_device.h> #include <linux/of_platform.h> static int __init fpga_init(void) { struct device_node *dt_node; const u8 *property; int len; printk(KERN_INFO "(I) FPGA module loaded at 0x%p\n", fpga_init); dt_node = of_find_node_by_path("/fpga_dt@c0000000"); if (!dt_node) { printk(KERN_ERR "(E) Failed to find device-tree node: /fpga_dt@c0000000\n"); return -ENODEV; } printk(KERN_INFO "(I) Found device-tree node. Now retrieving property.\n"); property = of_get_property(dt_node, "reg", &len); printk(KERN_INFO "(I) reg=0x%08lX\n", (unsigned long) property[0]); ... return 0; }
不幸的是,在试图find设备节点时插入模块会产生分段错误。
# insmod fpga_drv.ko (I) FPGA module loaded at 0xe112d000 Unable to handle kernel paging request for data at address 0x00000000 Faulting instruction address: 0xe112d07c Oops: Kernel access of bad area, sig: 11 [#1] SMP NR_CPUS=2 P2020 RDB Modules linked in: fpga_drv(P+) NIP: e112d07c LR: e112d078 CTR: c03ed6a4 REGS: df043e10 TRAP: 0300 Tainted: P (2.6.32.13) MSR: 00029000 <EE,ME,CE> CR: 24000222 XER: 20000000 DEAR: 00000000, ESR: 00000000 TASK = dfb85300[1167] 'insmod' THREAD: df042000 CPU: 1 GPR00: e112d078 df043ec0 dfb85300 00000000 e11761f4 c05838c4 00000000 dfffc650 GPR08: 00000020 00000000 00000012 c03ed6a4 24000282 10098374 1ff92100 10081fc8 GPR16: 1007a3e0 1007a434 00000000 00000002 00000000 00000000 bfbe6364 4801f468 GPR24: 10094009 1007ca88 c064d07c 00000000 e112d000 c0690000 e1170000 e1170000 NIP [e112d07c] fpga_init+0x7c/0x460 [fpga_drv] LR [e112d078] fpga_init+0x78/0x460 [fpga_drv] Call Trace: [df043ec0] [e112d078] fpga_init+0x78/0x460 [fpga_drv] (unreliable) [df043ef0] [c0001d94] do_one_initcall+0x3c/0x1e8 [df043f20] [c0077720] sys_init_module+0xf8/0x220 [df043f40] [c0010644] ret_from_syscall+0x0/0x3c Instruction dump: 3860ffed 80010034 bb410018 38210030 7c0803a6 4e800020 3c80e117 38a10008 388461f4 3fe0e117 4800038d 3fc0e117 <80830000> 3c60e117 386361f8 4cc63182 ---[ end trace 40317dd8a9588d98 ]--- Segmentation fault
这是什么意思? 有什么方法来validation设备树blob是否被正确加载和使用? 我是否需要更多的“设置”代码来准备这样的查询? 或者,我是否想用螺丝刀当锤子?
谢谢!
顺便说一句,这是我的FDT(DTS)来源:
/dts-v1/; / { model = "fsl,P2020"; compatible = "fsl,P2020RDB"; #address-cells = <2>; #size-cells = <2>; ... fpga_dt@c0000000 { #address-cells = <1>; #size-cells = <1>; compatible = "xilinx,xc6vlx240t", "virtex6"; model = "xilinx,XC6VLX240T"; reg = <0xc0000000 1 0xc8000000 0x08000000>; label = "Xilinx FPGA XC6VLX240T for My Custom Board"; }; };
我将专门回答这个问题:
有什么方法来验证设备树blob是否被正确加载和使用?
验证FDT是否正确的两种方法。
首先在u-boot。 您可以转储FDT。
例如,如果您的FDT驻留在NV存储器中,请先将其复制到RAM中。
cp.b 0xFFF70000 0x800000 0x200
设置fdt,然后转储fdt树(如u-boot所示)
fdt addr 800000 fdt print
这应该工作,因为你的节点是静态的。 在这一点上,您将很容易地看到设备树是否不正确。
其次是在内核,但你必须重新编译调试! 您必须启用CONFIG_DEBUG_FS并定义DEBUG arch / powerpc / kernel / prom.c。 这将导出设备树在/ proc 🙂
还有第三种方法。 您可以转储设备树,因为内核在启动期间很早解析它。 确切的方法现在逃脱了我。 我很确定你需要重新编译内核并添加一个bootarg。
祝你好运。
sessyargc.jp的回答是足够的; 然而,为了完整起见,我想提供一些C代码,用于从驱动程序内部打印出一些基本的树状信息:
#include <linux/of_device.h> #include <linux/of_platform.h> ... print_device_tree_node(of_find_node_by_path("/"), 0); ... static void print_device_tree_node(struct device_node *node, int depth) { int i = 0; struct device_node *child; struct property *properties; char indent[255] = ""; for(i = 0; i < depth * 3; i++) { indent[i] = ' '; } indent[i] = '\0'; ++depth; for_each_child_of_node(node, child) { printk(KERN_INFO "%s{ name = %s\n", indent, child->name); printk(KERN_INFO "%s type = %s\n", indent, child->type); for (properties = child->properties; properties != NULL; properties = properties->next) { printk(KERN_INFO "%s %s (%d)\n", indent, properties->name, properties->length); } print_device_tree_node(child, depth); printk(KERN_INFO "%s}\n", indent); } }
我希望我知道如何确定每个属性类型,所以我可以格式化值并正确输出。 有什么建议么?
最后,这里是原始片段,稍微修改一下哦:
char *path = "/fpga_dt@c0000000"; struct device_node *dt_node; const u32 *property; int len; dt_node = of_find_node_by_path(path); if (!dt_node) { printk(KERN_ERR "(E) Failed to find device-tree node: %s\n", path); return -ENODEV; } printk(KERN_INFO "(I) Found device-tree node. Now retrieving property.\n"); property = of_get_property(dt_node, "reg", &len); printk(KERN_INFO "(I) len=%d\n", len); printk(KERN_INFO "(I) reg[0]=0x%08lX\n", (unsigned long) property[0]); printk(KERN_INFO "(I) reg[1]=0x%08lX\n", (unsigned long) property[1]); printk(KERN_INFO "(I) reg[2]=0x%08lX\n", (unsigned long) property[2]); printk(KERN_INFO "(I) reg[3]=0x%08lX\n", (unsigned long) property[3]);
seg-fault发生在一些糟糕的设备树路径上。 显然,有一些typeo错误。 我最终通过探测根路径,然后一些其他基本节点(如/ cpu0,/内存等)来解决问题,最后我能够探测到我的fpga。 我不确定真正改变了什么,但是当使用上面的代码时,我能够正确引用我的FPGA的设备树节点。
感谢所有的帮助! 🙂