我正在尝试在FPGA和x86_64 Linux机器之间进行DMA传输。
在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输出中什么都看不到。
怎么了?或者,有没有一种方法可以找到我为什么收到该不受支持的请求的原因
完成吗?
马可
最佳答案
这是我的一个设计的摘要(有效!)。它是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个dword的
MemWr
而不是读取dword。另一个不同之处是,第一次使我麻烦的是,如果地址低于4GB ,则必须使用3DW header 。这意味着您必须检查从主机获得的地址,并确定是否需要使用3DW header (仅具有地址的LSB)或完整的4DW header 模式。
除非需要传输大量数据,否则可以将dma地址掩码设置为32位,以始终在3DW情况下使用,Linux默认应在4GB以下保留大量内存位置。
关于fpga - 从PC到FPGA的DMA PCIe读取传输,我们在Stack Overflow上找到一个类似的问题:https://stackoverflow.com/questions/30607667/