DMA PCIe从PC到FPGA的读传输

Cpu*_*u86 6 fpga dma pci-e

我正在尝试在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();
Run Code Online (Sandbox Code Playgroud)

总线地址是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)
Run Code Online (Sandbox Code Playgroud)

我从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"
Run Code Online (Sandbox Code Playgroud)

所以基本上没有数据完成,状态为Unsupported Request.我不认为TLP的构造有什么问题,但我也看不到驾驶员方面的任何问题.我正在使用的内核启用了PCIe错误报告,但我在dmesg输出中看不到任何内容.怎么了?或者,有没有办法找到为什么我得到不支持的请求完成?

马尔科

Jon*_*let 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));
Run Code Online (Sandbox Code Playgroud)

MemWr让我们忽略我执行32 个双字而不是读取一个双字的明显差异。另一个区别是,如果地址低于 4GB,则必须使用 3DW 标头,这在我第一次这样做时给我带来了麻烦。

这意味着您必须检查从主机获得的地址,并确定是否需要使用 3DW 标头(仅具有地址的 LSB)或完整的 4DW 标头模式。

除非您需要传输大量数据,否则您可以将 dma 地址掩码设置为 32 位,以便始终在 3DW 情况下,Linux 默认情况下应保留大量低于 4GB 的内存位置。