22

私の質問は次のとおり[pci_]dma_sync_single_for_{cpu,device}です。デバイス ドライバーで正しく使用しているときに、キャッシュ スヌーピングを無効にしても安全な時期をどのように判断できますか?

私は、PCI Express (DMA) 経由で RAM に直接書き込むデバイスのデバイス ドライバーに取り組んでおり、キャッシュ コヒーレンスの管理に関心があります。DMA を開始するときに、DMA 中のキャッシュ スヌーピングを有効または無効にするために設定できる制御ビットがあります。

pci_dma_sync_single_for_cpu()DMA バッファを切り替えるときに、必要に応じて割り込みルーチンを呼び出します..._for_device()が、32 ビット Linux 2.6.18 (RHEL 5) では、これらのコマンドは何も展開されないマクロであることがわかります...これは、デバイスがガベージを返す理由を説明していますこのカーネルでキャッシュスヌーピングが無効になっている場合!

カーネル ソースの歴史を調べてみたところ、2.6.25 までは 64 ビット x86 だけが DMA 同期用のフックを持っていたようです。2.6.26 か​​ら、 のフィールドをinclude/asm-generic/dma-mapping-common.h介した DMA 同期 (現在は )のための一般的な統合間接メカニズムがあるようですが、これまでのところ、これらの操作の定義を見つけることができませんでした。sync_single_for_{cpu,device}dma_map_ops

4

2 に答える 2

17

誰もこれに答えていないことに本当に驚いているので、ここでは非 Linux 固有の答えに進みます (より具体的にするには、Linux カーネル自体について十分な知識がありません) ...

キャッシュ スヌーピングは、DMA コントローラーに、DMA されるメモリのすべての CPU にキャッシュ無効化要求を送信するように指示するだけです。これは明らかにキャッシュ コヒーレンシ バスに負荷を追加し、すべての CPU がスヌープを発行する DMA コントローラーとのシングル ホップ接続を持つわけではないため、プロセッサを追加すると特にスケールが悪くなります。したがって、「キャッシュ スヌーピングを無効にしても安全な場合」に対する簡単な答えは、DMA されるメモリがどの CPU キャッシュにも存在しないか、そのキャッシュ ラインが無効としてマークされている場合です。つまり、DMA 領域からの読み取りを試みると、常にメイン メモリからの読み取りになります。

では、DMA 領域からの読み取りが常にメイン メモリに行われるようにするにはどうすればよいでしょうか?

DMA キャッシュ スヌーピングのような高度な機能が登場する前の時代、私たちが行っていたのは、次のように分割された一連のステージを介して DMA メモリを供給することで、DMA メモリをパイプライン化することでした。

ステージ 1: 「ダーティでクリーニングが必要な」DMA メモリ リストに「ダーティ」DMA メモリ領域を追加します。

ステージ 2: 次回、デバイスが新しい DMA 処理されたデータで割り込みを行うとき、それらのブロックにアクセスする可能性のあるすべての CPU (多くの場合、各 CPU はそのローカルメモリブロックで構成される独自のリスト)。上記のセグメントを「クリーン」リストに移動します。

ステージ 3: 次の DMA 割り込み (もちろん、前のキャッシュの無効化が完了する前に発生しないことは確かです)、「クリーン」リストから新しい領域を取得し、次の DMA がそれに入る必要があることをデバイスに伝えます。汚れたブロックをリサイクルします。

ステージ 4: 繰り返します。

これは手間がかかる分、いくつかの大きな利点があります。まず、DMA 処理を単一の CPU (通常はプライマリ CPU0) または単一の SMP ノードにピン留めできます。つまり、単一の CPU/ノードだけがキャッシュの無効化について心配する必要があります。次に、時間の経過とともに操作の間隔を空け、キャッシュ コヒーレンシ バスの負荷を分散することで、メモリ サブシステムがメモリのレイテンシを隠す機会を大幅に増やします。パフォーマンスの鍵は、一般に、関連する DMA コントローラにできるだけ近い CPU で DMA を発生させ、その CPU にできるだけ近いメモリに発生させることです。

新しく DMA されたメモリを常にユーザー空間や他の CPU に渡す場合は、非同期キャッシュ無効化パイプラインの前に新しく取得したメモリを挿入するだけです。一部のOS(Linuxについては不明)には、ゼロ化されたメモリを事前注文するための最適化されたルーチンがあるため、OSは基本的にバックグラウンドでメモリをゼロ化し、迅速な満足キャッシュを維持します。は非常に遅いです。ハードウェア オフロード メモリのゼロ化を使用する過去 10 年間に作成されたプラットフォームを認識していないため、すべての新しいメモリには、無効化が必要な有効なキャッシュ ラインが含まれている可能性があると想定する必要があります。

これがあなたの質問の半分にしか答えていないことを感謝しますが、何もないよりはましです. 幸運を!

ニール

于 2012-02-27T13:52:04.663 に答える
6

少し遅れているかもしれませんが、

キャッシュ スヌーピングを無効にすると、ハードウェアはキャッシュの一貫性を処理しなくなります。したがって、カーネルはこれを自分で行う必要があります。ここ数日、[pci_]dma_sync_single_for_{cpu,device} の X86 バリアントのレビューに時間を費やしてきました。彼らが一貫性を維持するための努力をしている兆候は見当たりませんでした。これは、キャッシュ スヌーピングが PCI(e) 仕様でデフォルトでオンになっているという事実と一致しているようです。

したがって、キャッシュ スヌーピングをオフにする場合は、ドライバーで一貫性を維持する必要があります。おそらく clflush_cache_range() (X86) などを呼び出すことによって?

参照:

于 2013-02-06T13:50:28.007 に答える