我正在開發Xilinx Virtex 6 PCIe定製板卡的設備驅動程序。 在做DMA寫(從主機到設備)會出現以下情況:Linux設備驅動程序DMA內存緩衝區未按PCIe硬件順序排列
用戶空間應用:
a. fill buffer with the following byte pattern (tested up to 16kB)
00 00 .. 00 (64bytes)
01 01 .. 00 (64bytes)
...
ff ff .. ff (64bytes)
00 00 .. 00 (64bytes)
01 01 .. 00 (64bytes)
etc
b. call custom ioctl to pass pointer to buffer and size
內核空間:
a. retrieve buffer (bufp) with
copy_from_user(ptdev->kbuf, bufp, cnt)
b. setup and start DMA
b1. //setup physical address
iowrite32(cpu_to_be32((u32) ptdev->kbuf_dma_addr),
ptdev->region0 + TDO_DMA_HOST_ADDR);
b2. //setup transfer size
iowrite32(cpu_to_be32(((cnt+3)/4)*4),
ptdev->region0 + TDO_DMA_BYTELEN);
b3. //memory barrier to make sure kbuf is in memorry
mb();
//start dma
b4. iowrite32(cpu_to_be32(TDO_DMA_H2A | TDO_DMA_BURST_FIXED | TDO_DMA_START),
ptdev->region0 + TDO_DMA_CTL_STAT);
c. put process to sleep
wait_res = wait_event_interruptible_timeout(ptdev->dma_queue,
!(tdo_dma_busy(ptdev, &dma_stat)),
timeout);
d. check wait_res result and dma status register and return
Note that the kernel buffer is allocated once at device probe with:
ptdev->kbuf = pci_alloc_consistent(dev, ptdev->kbuf_size, --512kB
&ptdev->kbuf_dma_addr);
設備PCIE TLP轉儲(通過邏輯分析儀獲得在Xilinx核心之後):
a. TLP received (by the device)
a1. 40000001 0000000F F7C04808 37900000 (MWr corresponds to b1 above)
a1. 40000001 0000000F F7C0480C 00000FF8 (MWr corresponds to b2 above)
a1. 40000001 0000000F F7C04800 00010011 (MWr corresponds to b4 above)
b. TLP sent (by the device)
b1. 00000080 010000FF 37900000 (MRd 80h DW @ addr 37900000h)
b2. 00000080 010000FF 37900200 (MRd 80h DW @ addr 37900200h)
b3. 00000080 010000FF 37900400 (MRd 80h DW @ addr 37900400h)
b4. 00000080 010000FF 37900600 (MRd 80h DW @ addr 37900600h)
...
c. TLP received (by the device)
c1. 4A000020 00000080 01000000 00 00 .. 00 01 01 .. 01 CplD 128B
c2. 4A000020 00000080 01000000 02 02 .. 02 03 03 .. 03 CplD 128B
c3. 4A000020 00000080 01000000 04 04 .. 04 05 05 .. 05 CplD 128B
c4. 4A000020 00000080 01000000 06 06 .. 0A 0A 0A .. 0A CplD 128B <=
c5. 4A000010 00000040 01000040 07 07 .. 07 CplD 64B <=
c6. 4A000010 00000040 01000040 0B 0B .. 0B CplD 64B <=
c7. 4A000020 00000080 01000000 08 08 .. 08 09 09 .. 09 CplD 128B <=
c8. 4A000020 00000080 01000000 0C 0C .. 0C 0D 0D .. 0D CplD 128B
.. the remaining bytes are transfered correctly and
the total number of bytes (FF8h) matches the requested size
signal interrupt
現在這個表面存儲器命令er ror發生的概率很高(0.8 < p < 1),並且排序不匹配發生在傳輸中不同的隨機點。
編輯:請注意,上述點c4將表明內存驅動程序沒有按正確順序填充內存(我假設內存控制器使用連續內存填充TLP)。 64B是緩存行的大小,這可能與緩存操作有關。
當我禁用與內核緩衝區高速緩存,
echo "base=0xaf180000 size=0x00008000 type=uncachable" > /proc/mtrr
錯誤仍然發生,但更多的很少(P < 0.1和依賴於傳輸大小)
這只是發生在一個i7-基於4770(Haswell)的機器(在3臺相同的機器上進行測試,配有3塊板)。 我嘗試了內核2.6.32(RH6.5),庫存3.10.28和庫存3.13.1,結果相同。
我在基於i7-610 QM57的機器和Xeon 5400機器上嘗試了代碼和設備,沒有出現任何問題。
歡迎任何想法/建議。
此致
克勞迪奧
感謝您的回答。 'lspci'爲我提供以下內容:
'LnkSta:速度2.5GT/s,寬度x8,TrErr-列車 - SlotClk- DLActive- BWMgmt- ABWMgmt-。 '
它看起來與PCIe 2.0(2.5GT/s)鏈接相關聯。 – Claudio
我記得PCIe支持TLP的重新排序,如果擴展位打開的話。它是'pci_regs.h'中的'PCI_EXP_DEVCTL_RELAX_EN'。你能檢查這是否與你的問題有關嗎? *比較* https://github.com/torvalds/linux/blob/master/drivers/net/ethernet/broadcom/tg3.c#L9132 – nodakai
@nodaki。事實上,TLP具有與排序和緩存一致性相關的屬性(2位)。這些是TLP頭的字節2中的比特5:4。 位5:鬆散排序位(如果1允許鬆散排序,如果0使用嚴格的排序) 位4:無偵測位(如果如果0窺探啓用在此訪問1個禁用探聽) 在B [1 ,2,3,...]我的設計發送 00000080:MRd TC = 0 EP = 0 TD = 0 Attr = 0 Len = 0x80 DW(256Bytes注意= MaxReadRequest) 不過,我按照您的建議清除了PCI_EXP_DEVCTL_RELAX_EN沒有明顯的變化。 – Claudio