我正在尝试在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"
所以基本上没有数据完成,状态为Unsupported Request。 我不认为TLP的构造有什么问题,但我也看不到驾驶员方面的任何问题。 我正在使用的内核启用了PCIe错误报告,但我在dmesg输出中看不到任何内容。 怎么了?或者,有没有办法找到我得到不支持的请求的原因 完成?
马
答案 0 :(得分: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个dwords执行MemWr
而不是读dword的明显区别。另一个差异,在我第一次这样做时给我带来了麻烦,就是如果地址低于4GB 你必须使用3DW标题。
这意味着您必须检查从主机获得的地址,并确定是否需要使用3DW标头(仅使用LSB的地址)或完整的4DW标头模式。
除非您需要传输大量数据,否则您可以将dma地址掩码设置为32位以保持3DW情况,Linux默认情况下应保留大量低于4GB的内存位置。