12

ユーザー空間ドライバーを備えた PCIe デバイスがあります。BAR を介してデバイスにコマンドを書き込んでいます。コマンドは遅延の影響を受けやすく、データ量が少ない (~64 バイト) ため、DMA を使用したくありません。

を使用してカーネル内の BAR の物理アドレスを再マップし、カーネルioremap_wcの BAR に 64バイトを書き込むと、64 バイトが PCIe 経由で単一の TLP として書き込まれていることがわかります。ユーザー空間プログラムをフラグ付きの領域に許可してから64 バイトを書き込むと、単一のトランザクションではなく、PCIe バス上に複数の TPL が表示されます。mmapMAP_SHARED

カーネルPATのドキュメントによると、書き込み結合ページをユーザー空間にエクスポートできるはずです。

一部のページをユーザー空間にエクスポートしたいドライバーは、mmap インターフェイスとの組み合わせを使用してそれを行います

1)pgprot_noncached()

2)io_remap_pfn_range()またはremap_pfn_range()またはvm_insert_pfn()

PAT のサポートにより、新しい APIpgprot_writecombineが追加されています。そのため、ドライバーは、ステップ 1 のいずれ pgprot_noncached()pgprot_writecombine()で上記のシーケンスを使用し、その後にステップ 2 を続けることができます。

このドキュメントに基づいて、私の mmap ハンドラーからの関連するカーネル コードは次のようになります。

 vma->vm_page_prot = pgprot_writecombine(vma->vm_page_prot);

 return io_remap_pfn_range(vma,
                           vma->vm_start,
                           info->mem[vma->vm_pgoff].addr >> PAGE_SHIFT,
                           vma->vm_end - vma->vm_start,
                           vma->vm_page_prot);

PCIe デバイスが lspci に表示され、予想どおりプリフェッチ可能としてマークされた BAR が表示されます。

    Latency: 0, Cache Line Size: 64 bytes
    Interrupt: pin A routed to IRQ 11
    Region 0: Memory at d8000000 (64-bit, prefetchable) [size=32M]
    Region 2: Memory at d4000000 (64-bit, prefetchable) [size=64M]

ユーザー空間から呼び出すとmmap、ログ メッセージが表示されます (debugpat カーネル ブート パラメータが設定されています)。

reserve_memtype 追加 [mem 0xd4000000-0xd7ffffff], track write-combining, req write-combining, ret write-combining

/sys/kernel/debug/x86/pat_memtype_listまた、PAT エントリが正しいように見え、重複する領域がないことも確認できます。

write-combining @ 0xd4000000-0xd8000000
uncached-minus  @ 0xd8000000-0xda000000

また、PAT 構成と競合する MTRR エントリがないことも確認しました。私が見る限り、書き込み結合がユーザー空間で発生するようにすべてが正しく設定されていますが、PCIe アナライザーを使用して PCIe バス上のトランザクションを観察すると、ユーザー空間のアクセス パターンは、カーネルから実行される同じ書き込みとはまったく異なります。ioremap_wc電話の後。

書き込み結合がユーザー空間から期待どおりに機能しないのはなぜですか?

さらにデバッグするにはどうすればよいですか?

現在、シングル ソケット 6 コア i7-3930K で実行しています。

4

1 に答える 1

1

これが役立つかどうかはわかりませんが、これが PCIe で書き込み結合を行う方法です。確かに、それはカーネル空間にありましたが、これはインテルのドキュメントに準拠しています。行き詰まっている場合は試してみる価値があります。

グローバルに定義:

unsigned int __attribute__ ((aligned(0x20))) srcArr[ARR_SIZE];

あなたの機能で:

int *pDestAddr

for (i = 0; i < ARR_SIZE; i++) {
    _mm_stream_si32(pDestAddr + i, pSrcAddr[i]);
}
于 2014-04-23T22:52:25.723 に答える