7

Ho scritto un modulo kernel Linux per fungere da driver FPGA per una scheda personalizzata basata su Freescale P2020RDB. Il driver contiene diversi #defines per specificare vari indirizzi, dimensioni, ampiezze del bus, ecc. Vorrei accedere all'albero del dispositivo appiattito (FDT) della scheda all'interno del driver per configurare questi indirizzi, in modo che il driver possa essere utilizzato per altre schede, dove l'FPGA ha dimensioni diverse o risiede in indirizzi diversi.come accedere e eseguire il debug di una struttura di dispositivi FDT/DTS da un driver Linux (seg-fault)

ho aggiunto il seguente codice semplice funzione di inizializzazione del mio modulo, quale codice ho trovato, mentre le crociere il codice sorgente del kernel 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("/[email protected]"); 
    if (!dt_node) { 
    printk(KERN_ERR "(E) Failed to find device-tree node: /[email protected]\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; 
} 

Purtroppo, l'inserimento del modulo produce un errore di segmentazione, mentre solo cercando di trova il nodo del dispositivo.

# 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 

Che cosa indica? C'è un modo per verificare che il BLOB dell'albero del dispositivo sia stato correttamente caricato e utilizzabile? Ho bisogno di qualche altro codice di "setup" per prepararmi a una tale richiesta? Oppure sto cercando di usare un cacciavite come un martello?

Grazie!

BTW, ecco la mia FDT (DTS) fonte:

/dts-v1/; 
/{ 
    model = "fsl,P2020"; 
    compatible = "fsl,P2020RDB"; 
    #address-cells = <2>; 
    #size-cells = <2>; 
    ... 
    [email protected] { 
     #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"; 
    }; 
}; 
+0

Puoi mostrare un disassemblaggio di 'fpga_init'? – ninjalj

risposta

12

io specificamente rispondere a questa domanda:

C'è qualche modo per verificare che l'albero blob dispositivo è stato correttamente caricato e utilizzabile?

2 modi per verificare se il FDT è corretta.

Primo in u-boot. Puoi scaricare l'FDT.
Ad esempio se il proprio FDT si trova nella memoria NV, copiarlo prima nella RAM.

cp.b 0xFFF70000 0x800000 0x200 


Setup del FDT, quindi scaricare l'albero FDT (come visto da u-boot)

fdt addr 800000 
fdt print 


Questo dovrebbe funzionare, perché il nodo è statico. Si vedrà facilmente se l'albero del dispositivo è errato o non a questo punto.

Il secondo è nel kernel ma è necessario ricompilare con il debugging! Devi abilitare CONFIG_DEBUG_FS e definire DEBUG arch/powerpc/kernel/prom.c. Questo esporterà l'albero del dispositivo in/proc :-)

C'è una terza via. È possibile scaricare l'albero dei dispositivi mentre il kernel lo analizza molto presto durante l'avvio. Il metodo esatto mi sfugge ora. Sono abbastanza sicuro di aver bisogno di ricompilare il kernel e aggiungere un bootarg.

Goodluck.

+0

Grazie, sessyargc.jp! Sono stato in grado di verificare che l'FDT era buono in u-boot usando il tuo suggerimento. (Ho dovuto modificarlo leggermente, dal momento che sto tirando l'FDT da un server TFTP, ma questa è una differenza minore.) Ho trovato anche l'albero dei dispositivi in ​​/ proc/device-tree, secondo il tuo suggerimento, che ero in grado di usare per verificare che il kernel abbia caricato correttamente l'albero. – Trevor

+0

È bello sapere. Spero che tu possa farlo funzionare presto! –

+0

Grazie a @ sessyargc.jp, mi ha aiutato. –

3

La risposta di sessyargc.jp era sufficiente; tuttavia, solo per completezza, ho voluto offrire un po 'di codice C che ho usato per stampare alcune informazioni albero di base dall'interno del conducente:

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

Vorrei sapere come determinare digitato ogni proprietà, in modo da potrebbe formattare il valore ed emetterlo correttamente. Eventuali suggerimenti?

Infine, ecco il frammento originale, modificato oh-così un po ':

char *path = "/[email protected]"; 
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]); 

Il seg-colpa stava accadendo su alcuni percorsi dispositivo-albero cattivo. Apparentemente, c'era qualche errore di tipo. Alla fine ho risolto il problema sondando il percorso root e poi alcuni altri nodi di base (come/cpu0,/memory, ecc.), E alla fine sono riuscito a sondare la mia fpga. Non sono sicuro di cosa sia realmente cambiato, ma ora sono in grado di fare riferimento correttamente al nodo dell'albero dei dispositivi dell'FPGA, quando utilizzo il codice precedente.

Grazie per tutto l'aiuto! :)

+0

Puoi anche ricavare il percorso da/proc/albero-dispositivo/e passarlo a of_find_node_by_path() –

Problemi correlati