Xilinx Virtex 6 PCIe カスタム ボード用のデバイス ドライバーを開発しています。DMA 書き込み (ホストからデバイスへ) を実行すると、次のようになります。
ユーザー空間アプリ:
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 ダンプ (ザイリンクス コアの後にロジック アナライザーで取得):
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
現在、この明らかなメモリ順序付けエラーは高い確率 (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 マシンでコードとデバイスを試してみましたが、問題はありませんでした。
どんなアイデア/提案も大歓迎です。
よろしくお願いします
クラウディオ