1

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 マシンでコードとデバイスを試してみましたが、問題はありませんでした。

どんなアイデア/提案も大歓迎です。

よろしくお願いします

クラウディオ

4

3 に答える 3

2

これが古いスレッドであることは知っていますが、「エラー」の理由は完了の並べ替えです。複数の未処理の読み取り要求は、順番に応答する必要はありません。完了は、同じ要求に対してのみ順番に行われます。その上、リクエストには常に同じタグが割り当てられます。これは、リクエストが同時にアクティブな場合は違法です。

于 2016-03-16T12:32:20.550 に答える