2015-06-02 17 views
5

Tôi đang cố gắng chuyển DMA hoạt động giữa FPGA và máy Linux x86_64.DMA PCIe đọc chuyển từ PC sang FPGA

Về phía máy tính tôi đang làm khởi này:

//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(); 

Địa chỉ xe buýt là một địa chỉ 64bits. Về phía FPGA TLP tôi gửi ra cho đọc trong tổng số 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) 

Việc hoàn thành mà tôi nhận lại từ máy PC là:

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" 

rất cơ bản là một kết thúc không có dữ liệu và với trạng thái Yêu cầu không được hỗ trợ. Tôi không nghĩ rằng có điều gì đó sai trái trong quá trình xây dựng TLP nhưng tôi cũng không thấy có vấn đề gì về phía tài xế. Hạt nhân tôi đang sử dụng có báo cáo lỗi PCIe được bật nhưng tôi không thấy gì trong đầu ra dmesg. Có gì sai? Hoặc, có cách nào để tìm lý do tại sao tôi nhận được Yêu cầu không được hỗ trợ đó Hoàn thành không?

Marco

+0

Bạn có thể so sánh mã của mình với các trình điều khiển PCIe mở khác như Riffa 2.x hoặc XilliBus về cách sử dụng hàm hạt nhân cho DMA. – Paebbels

Trả lời

2

Đây là trích từ một trong các thiết kế của tôi (hoạt động!). Đó là VHDL và hơi khác nhau nhưng hy vọng nó sẽ giúp bạn:

-- 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)); 

Hãy bỏ qua những khác biệt rõ ràng rằng tôi đã thực hiện MemWr 32 dwords thay vì đọc một dword. Sự khác biệt khác, gây ra rắc rối cho tôi lần đầu tiên tôi làm điều này, là bạn phải sử dụng tiêu đề 3DW nếu địa chỉ dưới 4GB.

Điều đó có nghĩa là bạn phải kiểm tra địa chỉ bạn nhận được từ máy chủ và xác định xem bạn có cần sử dụng tiêu đề 3DW (chỉ với LSB địa chỉ) hoặc chế độ tiêu đề 4DW đầy đủ hay không. Trừ khi bạn cần chuyển số lượng dữ liệu không đúng, bạn có thể đặt mặt nạ địa chỉ dma thành 32 bit để luôn trong trường hợp 3DW, Linux sẽ đặt trước nhiều vị trí bộ nhớ dưới 4GB theo mặc định.

+0

Từ dma_map_page tôi luôn nhận được địa chỉ 64 bit, đó là lý do tại sao tôi sử dụng tiêu đề 4DW. Nếu tôi đặt mặt nạ dma thành 32 bit, hạt nhân sẽ gặp sự cố khi gọi dma_map_page. BTW Tôi sử dụng VHDL. – Cpu86

+1

Bạn không thể chắc chắn về điều đó, nếu bạn chạy mã trên một hệ thống có bộ nhớ vật lý ít hơn 4GB thì sao? Bạn có thể sử dụng 'dma_map_single' hoặc' dma_map_coherent' thay vì 'dma_map_page', ít nhất là để kiểm tra? Nó có thể bị treo vì 'get_page' không liên quan đến dma, vì vậy nếu nó cung cấp cho bạn một trang> 4GB và yêu cầu bản đồ trên <4GB ... Hạt nhân cũng có vùng bộ nhớ GFP_DMA, nhưng tôi không chắc rằng nó có liên quan đến moder system nơi tất cả các khu vực sẽ có sẵn cho DMA. –

+0

Bạn đúng là tôi không thể chắc chắn mỗi lần. Chỉ trong trường hợp của tôi, tôi in địa chỉ xe buýt và luôn là 64bits. Tôi thấy một nơi nào đó GPF_DMA32 nhưng không tài liệu tốt. Vấn đề là trong tương lai tôi có lẽ sẽ cần phải bản đồ một số lượng lớn bộ nhớ, thậm chí> 4GB. Bạn đã bao giờ thử chuyển một trang trong vùng bộ nhớ cao (> 4GB) và sử dụng TLP 4DW chưa? Nó có hoạt động không? – Cpu86

Các vấn đề liên quan