2015-06-02 39 views
5

我試圖讓DMA傳輸的FPGA和x86_64的Linux機器之間的工作。DMA的PCIe讀從PC轉移到FPGA

在PC端我這樣做初始化:

//driver probe 
... 
pci_set_master(dev); //set endpoint as master 
result = pci_set_dma_mask(dev, 0xffffffffffffffff); //set as 64bit capable 
... 

//read 
pagePointer = __get_free_page(__GFP_HIGHMEM); //get 1 page 
temp_addr = dma_map_page(&myPCIDev->dev,pagePointer,0,PAGE_SIZE,DMA_TO_DEVICE); 
printk(KERN_WARNING "[%s]Page address: 0x%lx Bus address: 0x%lx\n",DEVICE_NAME,pagePointer,temp_addr); 
writeq(cpu_to_be64(temp_addr),bar0Addr); //send address to FPGA 
wmb(); 
writeq(cpu_to_be64(1),bar1Addr); //start trasnfer 
wmb(); 

總線地址是64位地址。 在FPGA側TLP我送出去的1 DW讀:

Fmt: "001" 
Type: "00000" 
R|TC|R|Attr|R|TH : "00000000" 
TD|EP|Attr|AT : "000000" 
Length : "0000000001" 
Requester ID 
Tag : "00000000" 
Byte Enable : "00001111"; 
Address : (address from dma map page) 

,我回來從PC完成是:

Fmt: "000" 
Type: "01010" 
R|TC|R|Attr|R|TH : "00000000" 
TD|EP|Attr|AT : "000000" 
Length : "0000000000" 
Completer ID 
Compl Status|BCM : "0010" 
Length : "0000000000"; 
Requester ID 
Tag : "00000000" 
R|Lower address : "00000000" 

所以基本上沒有一個完成數據和狀態不支持的請求。 我不認爲有什麼不對的TLP的建設,但我看不出在駕駛員側的任何問題,無論是。 我正在使用的內核啓用了PCIe錯誤報告,但是我在dmesg輸出中看不到任何內容。 有什麼問題?或者,有沒有辦法找到爲什麼我得到不受支持的請求 完成?

Marco

+0

你可以你的代碼比較如何使用內核功能DMA等開放的PCIe驅動器,如裏法2.x或XilliBus。 – Paebbels

回答

2

這是我的一個設計(工程!)的摘錄。這是VHDL和略有不同,但希望它會幫助你:

-- First dword of TLP Header 
tlp_header_0(31 downto 30) <= "01";   -- Format = MemWr 
tlp_header_0(29)      <= '0' when pcie_addr(63 downto 32) = 0 else '1'; -- 3DW header or 4DW header 
tlp_header_0(28 downto 24) <= "00000";   -- Type 
tlp_header_0(23)      <= '0'; -- Reserved 
tlp_header_0(22 downto 20) <= "000";   -- Default traffic class 
tlp_header_0(19)      <= '0'; -- Reserved 
tlp_header_0(18)      <= '0'; -- No ID-based ordering 
tlp_header_0(17)      <= '0'; -- Reserved 
tlp_header_0(16)      <= '0'; -- No TLP processing hint 
tlp_header_0(15)      <= '0'; -- No TLP Digest 
tlp_header_0(14)      <= '0'; -- Not poisoned 
tlp_header_0(13 downto 12) <= "00";   -- No PCI-X relaxed ordering, no snooping 
tlp_header_0(11 downto 10) <= "00";   -- No address translation 
tlp_header_0(9 downto 0) <= "00" & X"20"; -- Length = 32 dwords 

-- Second dword of TLP Header 
-- Bits 31 downto 16 are Requester ID, set by hardware PCIe core 
tlp_header_1(15 downto 8)  <= X"00"; -- Tag, it may have to increment 
tlp_header_1(7 downto 4)  <= "1111"; -- Last dword byte enable 
tlp_header_1(3 downto 0)  <= "1111"; -- First dword byte enable 

-- Third and fourth dwords of TLP Header, fourth is *not* sent when pcie_addr is 32 bits 
tlp_header_2 <= std_logic_vector(pcie_addr(31 downto 0)) when pcie_addr(63 downto 32) = 0 else std_logic_vector(pcie_addr(31 downto 0)); 
tlp_header_3 <= std_logic_vector(pcie_addr(31 downto 0)); 

讓我們忽略了,我是執行32 MemWr雙字,而不是讀一個DWORD明顯的區別。另外一個區別,這引起了我的麻煩,我第一次這樣做,是你必須使用DW標頭如果地址低於4GB

這意味着你必須檢查從主機獲得的地址,並確定是否需要使用DW標頭(與地址的只有最低有效位)或全4DW頭模式。

除非您需要傳輸不合需要數量的數據,您可以將dma地址掩碼設置爲32位以始終處於3DW情況下,Linux應默認保留大量內存位置低於4GB的位置。

+0

從dma_map_page我總是收到一個64位地址,這就是爲什麼我使用4DW標題。如果我將dma掩碼設置爲32位,調用dma_map_page時內核崩潰。順便說一句,我使用VHDL。 – Cpu86

+1

如果你在一個物理內存小於4GB的系統上運行你的代碼,你不能確定這一點嗎?你可以使用'dma_map_single'或'dma_map_coherent'而不是'dma_map_page',至少可以測試嗎?它可能崩潰,因爲'get_page'是無關的DMA,所以如果它給你一個頁面> 4GB,並要求在地圖上<4GB ...內核也有一個GFP_DMA存儲區,但我不知道這是有關moder系統,其中所有的區域應該可用於DMA。 –

+0

你說得對,我無法確定每一次。就我而言,我打印總線地址並始終爲64位。我看到GPF_DMA32的某處,但沒有很好的記錄。問題是,將來我可能需要映射大量的內存,甚至大於4GB。您是否嘗試過在高內存(> 4GB)區域傳輸頁面並使用4DW TLP?它有用嗎? – Cpu86