2015年4月29日 星期三

Terasic DE5-NET Altera Stratix V FPGA PCIe 使用(三)

再承接上一篇
這邊會把最後的 driver, user space API 的部份寫完


5. Kernel Driver

driver 設定檔案裡面提供了很好的註解

# Example for the configuration file

# Vendor ID and Device ID
vendor_id  =  0x1172
device_id  =  0x5566

# related to the pcie and the fixed translation table
pci_dma_bit_range  = 31
tx_base_addr       = 0x80000000
pcie_cra_bar_no    = 2
pcie_cra_base_addr = 0x00000000

# maximum number of DMA controllers is 4
# followings are arrays to define the parameters for the DMA controllers

# type == 0 means no DMA, 1 means DMA Controller, 2 means SG-DMA Controller
dma_type           =          1,          0,          0,          0
dma_irq_no         =          1,          0,          0,          0
dma_ctrl_bar_no    =          0,          0,          0,          0
dma_ctrl_base_addr = 0x00004000, 0x00000000, 0x00000000, 0x00000000

# for the DMA Controller only, you can ignore this if you are using SG-DMA
sdma_data_width    =         16,          0,          0,          0

device ID/vender ID 應該不須要解釋了
在創造 PCIe 的時候就有設定這兩個值了
在 driver initialization 的以下幾行就是指定之後要 match 這個裝置的

alt_up_pci_id_table[0].vendor = vendor_id;
alt_up_pci_id_table[0].device = device_id;
alt_up_pci_id_table[0].subvendor = PCI_ANY_ID;
alt_up_pci_id_table[0].subdevice = PCI_ANY_ID;

可以看到在 PCIe 裡面設定的除了 vendor ID, device ID 之外都沒用到

接著先解釋下面幾行的設定,對照下圖
根據註解可以看到我們的設定檔描述的系統有一個 DMA
至於什麼是 SGDMA,啊哈哈我也不清楚,就算了吧
而且這個 DMA 從透過 BAR0 在 0x4000 的位置可以 access 到
IRQ 的 ID 是 1(這也是現代電腦系統的功能,就是 interrupt)
寬度是 16,跟我們剛剛 DMA 設置的 quadword 符合

CRA 控制器的設定也是類似 DMA
這個設定中,CRA 接在 BAR0 的 0x0000 位置上面
不過我不太清楚是要幹嘛的

最後剩下兩個參數
其中 DMA bit range 似乎只能設定 31
tx base address 是指 DMA 看到 Txs 的位置是 0x80000000 開始
而 Txs 又能透過 PCIe 看到 CPU DRAM
DMA 對 Txs 的讀寫就是對 CPU DRAM 的讀寫,前面有說這邊的大小是 4096B
透過這個方式我們就能用 DMA 傳輸資料了

driver 裡面有這兩行顯示了這個功能如何被實現
virtual address 就是 CPU 要讀寫的位置
bus address 就是 Txs 只要看到他
就能去 CPU DRAM 找到 virtual address 對應的 physical address 搬資料
我們只要把 bus address 給 DMA,剩下就能自動完成了這中間的協定我們不用處理

virt_addr = pci_alloc_consistent(pci_dev, SDMA_BUF_SIZE, &bus_addr);
copy_from_user(virt_addr, user_buffer, SDMA_BUF_SIZE);

6. Use user space API

Altera 提供了 user space 的 API 可以使用
讓我們可以對 PCIe BAR 進行類似 file operation 的動作

alt_up_pci_open/close

這個就是開啟 Altera PCIe 裝置

alt_up_pci_read/write

就是讀寫這個裝置,額外可以多指定要用哪個 BAR

alt_up_pci_dma_add/go

就是操作 DMA
可以指定要叫哪個 DMA 做事
因為我們現在只有一個,所以都用第 0 個就好了
add 是說要把工作塞進去
go 是叫他把事情都處理掉,可以指定要 polling 或是 interrupt
在我的測試中 polling 明顯比較快

在 user space API 看起來雖然是用 ioctl 操作
但是本質上最後還是對應到 iowrite 操作
我們在 user space/driver 裡面可以找到這幾行說明呼叫的層級

   retval = ioctl(fd, ALT_UP_IOCTL_DMA_ADD, &handler);
-> .unlocked_ioctl = alt_up_pci_ioctl_unlocked,
-> temp=alt_up_pci_sdma_go ( myctrller, handler...
-> alt_up_pci_sdma_set(myctrller, local_addr, (u32)...
-> iowrite32( rStartAddr, myctrller->...

7. Slide / Source Code

最後放上幾個可能有用的檔案

沒有留言:

張貼留言