DMA PCIe read transfer from PC to FPGA -
i'm trying dma transfer working between fpga , x86_64 linux machine.
on pc side i'm doing initialization:
//driver probe ... pci_set_master(dev); //set endpoint master result = pci_set_dma_mask(dev, 0xffffffffffffffff); //set 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 fpga wmb(); writeq(cpu_to_be64(1),bar1addr); //start trasnfer wmb();
the bus address 64bits address. on fpga side tlp i'm sending out read of 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 dma map page)
the completion 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"
so completion without data , status unsupported request. don't think there wrong on construction of tlp cannot see problem on driver side either. kernel i'm using has pcie error reporting enabled see nothing in dmesg output. what's wrong? or, there way find why unsupported request completion?
marco
this extract 1 of designs (that works!). it's vhdl , different you:
-- 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 requester id, set hardware pcie core tlp_header_1(15 downto 8) <= x"00"; -- tag, may have increment tlp_header_1( 7 downto 4) <= "1111"; -- last dword byte enable tlp_header_1( 3 downto 0) <= "1111"; -- first dword byte enable -- third , fourth dwords of tlp header, fourth *not* sent when pcie_addr 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));
let's ignore obvious difference performing memwr
of 32 dwords instead of reading dword. other difference, caused me trouble first time did this, have use 3dw header if address below 4gb.
that means have check address host , determine if need use 3dw header (with lsbs of address) or full 4dw header mode.
unless need transfer ungodly amount of data, can set dma address mask 32 bits in 3dw case, linux should reserve plenty of memory location below 4gb default.
Comments
Post a Comment