How to access and debug FDT / DTS device tree from Linux driver (seg-fault)

I wrote a Linux kernel module to act as an FPGA driver for a custom board based on the Freescale P2020RDB. The driver contains several #defines to indicate various addresses, sizes, bus widths, etc. I would like to access the Flattened Device Tree (FDT) panel from the driver in order to configure these addresses so that the driver can be used for other boards where the FPGA has different sizes or is located at different addresses.

I added the following simple code to my module initialization function, the code of which I found while cruising the Linux kernel source tree:

 ... #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; } 

Unfortunately, inserting a module causes a segmentation error when trying to find a node device.

 # 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 

What does it mean? Is there a way to verify that the device block tree is loaded and used correctly? Do I need any other "installation" code to prepare such a request? Or am I trying to use a screwdriver as a hammer?

Thanks!

By the way, here is my source for 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"; }; }; 
+7
source share
2 answers

I will specifically answer this question:

Is there a way to verify that the device block tree is loaded and used correctly?

2 ways to verify the correctness of the FDT.

First in u-boot. You can reset the FDT.
For example, if your FDT is in NV memory, first copy it to RAM.

 cp.b 0xFFF70000 0x800000 0x200 


Install fdt, then unload the fdt tree (as seen from u-boot)

 fdt addr 800000 fdt print 


This should work because your node is static. You will easily understand whether the device tree is incorrect or not at the moment.

The second is in the kernel, but you need to recompile using debugging! You must enable CONFIG_DEBUG_FS and define DEBUG arch / powerpc / kernel / prom.c. This will export the device tree to / proc :-)

There is a third way. You can reset the device tree as the kernel analyzes it very early at boot time. The exact method is eluding me now. I am pretty sure you need to recompile the kernel and add bootarg.

Good luck.

+12
source

sessyargc.jp the answer was sufficient; however, just for completeness, I wanted to offer some C code that I used to print out some basic tree information from inside the driver:

 #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); } } 

I would like to know how to define each type of property so that I can format the value and output it correctly. Any suggestions?

Finally, here is the original snippet, slightly modified by oh-so:

 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]); 

A seg error occurred on some bad device tracks. Apparently there was some type error. I eventually fixed the problem by examining the root path and then some other base nodes (e.g. / cpu0, / memory, etc.), and finally I was able to examine my fpga. I'm not sure what really changed, but now I can correctly edit my node FPGA tree of devices using the code above.

Thanks for the help!:)

+3
source

All Articles