目的
Riffa是一個基於FPGA的PCIe介面通訊框架,用於解析PCIe傳送的TLP包,並轉換成資料流形式的讀寫請求,主要用於高速資料通訊。相比於網上已有的如何在FPGA上使用Riffa的資料,筆者決定採用自頂向下的分析方法,先從Riffa的Linux Driver入手,分析上位機軟體是如何完成資料通訊的,然後再結合Verilog原始碼分析其行為,從另一個層面學習Riffa,在此過程也作為學習記錄,也進行分享。
驅動原始碼
根據Riffa2.2公開的原始碼,下載後可以在driver/linux/riffa_driver.c檔案內檢視到大部分的Linux驅動。那麼接下來將從Driver初始化開始,一步一步進行分析。
初始化
1 /** 2 * Called to initialize the PCI device. 3 */ 4 static int __init fpga_init(void) 5 { 6 int i; 7 int error; 8 9 for (i = 0; i < NUM_FPGAS; i++) 10 atomic_set(&used_fpgas[i], 0); 11 12 error = pci_register_driver(&fpga_driver); 13 if (error != 0) { 14 printk(KERN_ERR "riffa: pci_module_register returned %d\n", error); 15 return (error); 16 } 17 18 error = register_chrdev(MAJOR_NUM, DEVICE_NAME, &fpga_fops); 19 if (error < 0) { 20 printk(KERN_ERR "riffa: register_chrdev returned %d\n", error); 21 return (error); 22 } 23 24 #if LINUX_VERSION_CODE < KERNEL_VERSION(6, 4, 0) 25 mymodule_class = class_create(THIS_MODULE, DEVICE_NAME); 26 #else 27 mymodule_class = class_create(DEVICE_NAME); 28 #endif 29 30 if (IS_ERR(mymodule_class)) { 31 error = PTR_ERR(mymodule_class); 32 printk(KERN_ERR "riffa: class_create() returned %d\n", error); 33 return (error); 34 } 35 36 devt = MKDEV(MAJOR_NUM, 0); 37 device_create(mymodule_class, NULL, devt, "%s", DEVICE_NAME); 38 39 return 0; 40 } 41 42 /** 43 * Called to destroy the PCI device. 44 */ 45 static void __exit fpga_exit(void) 46 { 47 device_destroy(mymodule_class, devt); 48 class_destroy(mymodule_class); 49 pci_unregister_driver(&fpga_driver); 50 unregister_chrdev(MAJOR_NUM, DEVICE_NAME); 51 }