Oracle® Solaris 11.2 デバイスドライバの記述

印刷ビューの終了

更新: 2014 年 9 月
 
 

メモリーオブジェクトの同期

メモリーオブジェクトにアクセスする過程で、ドライバはさまざまなキャッシュに対してメモリーオブジェクトを同期させることが必要な場合があります。このセクションでは、メモリーオブジェクトの同期を行うタイミングとその方法に関するガイドラインを示します。

キャッシュ

CPU キャッシュは、CPU とシステムのメインメモリーの間に位置する非常に高速なメモリーです。入出力キャッシュは、デバイスとシステムのメインメモリーの間に位置します (次の図を参照)。

図 9-1  CPU キャッシュとシステムの入出力キャッシュ

image:図は、キャッシュを使用して、デバイスのデータ転送の速度を上げる方法を示しています。

メインメモリーからデータを読み取ろうとすると、関連付けられたキャッシュは要求されたデータがあるかどうかを確認します。データが利用可能である場合、キャッシュはすぐにデータを提供します。データがキャッシュに含まれていない場合、キャッシュはメインメモリーからそのデータを取り出します。次に、そのデータを要求元に渡し、次の要求に備えてデータを保存します。

同様に、書き込みサイクルでは、データはすぐにキャッシュに格納されます。CPU やデバイスは、実行 (つまりデータの転送) を続けることができます。データをキャッシュに格納するのにかかる時間は、データがメモリーに書き込まれるのを待つ時間よりもはるかに短くてすみます。

このモデルでは、デバイス転送が完了したあとも、引き続きデータを入出力キャッシュに格納でき、メインメモリーにはデータが入っていません。CPU がメモリーにアクセスした場合、CPU は CPU キャッシュから間違ったデータを読み取る可能性があります。ドライバは、同期ルーチンを呼び出して、入出力キャッシュからデータをフラッシュし、新しいデータで CPU キャッシュを更新する必要があります。この処理により、CPU のメモリーのビューの一貫性が確保されます。同様に、CPU によって変更されたデータにデバイスからアクセスする場合も、同期段階が必要です。

デバイスとメモリーの間に、バスエクステンダやブリッジなどの追加のキャッシュやバッファーを作成できます。ddi_dma_sync(9F) を使用して、該当するすべてのキャッシュを同期させます。

ddi_dma_sync() 関数

メモリーオブジェクトには、DMA ハンドルによって、CPU やデバイス用などの複数のマッピングが定義されている場合があります。複数のマッピングを持つドライバは、メモリーオブジェクトの変更にいずれかのマッピングが使用される場合、 ddi_dma_sync(9F) を呼び出す必要があります。ddi_dma_sync() を呼び出すと、メモリーオブジェクトが別のマッピングを通じてアクセスされる前に、そのオブジェクトの変更が必ず完了しているようになります。ddi_dma_sync() 関数は、オブジェクトへのキャッシュされた参照が古くなっている場合に、オブジェクトのほかのマッピングに知らせることもできます。また、ddi_dma_sync() は必要に応じて古いキャッシュ参照をフラッシュしたり、無効にしたりします。

通常、ドライバは DMA 転送が完了したときに ddi_dma_sync() を呼び出す必要があります。ただし、ddi_dma_unbind_handle(9F) を使用した DMA リソースの解放により、ドライバに代わって ddi_dma_sync() が暗黙的に実行される場合は、この規則に当てはまりません。ddi_dma_sync() の構文は次のとおりです。

int ddi_dma_sync(ddi_dma_handle_t handle, off_t off,
size_t length, uint_t type);

オブジェクトがデバイスの DMA エンジンによって読み取られようとしている場合は、typeDDI_DMA_SYNC_FORDEV に設定して、デバイスのオブジェクトビューを同期させる必要があります。デバイスの DMA エンジンがメモリーオブジェクトに書き込みを行なったあとで、そのオブジェクトが CPU によって読み取られようとしている場合は、typeDDI_DMA_SYNC_FORCPU に設定して、CPU のオブジェクトビューを同期させる必要があります。

次の例は、CPU のための DMA オブジェクトの同期を示しています。

if (ddi_dma_sync(xsp->handle, 0, length, DDI_DMA_SYNC_FORCPU)
    == DDI_SUCCESS) {
    /* the CPU can now access the transferred data */
    /* ... */
} else {
    /* error handling */
}

メモリーが ddi_dma_mem_alloc(9F) によって割り当てられる場合のように、カーネルのためのマッピングしかない場合は、DDI_DMA_SYNC_FORKERNEL フラグを使用します。システムは、CPU のビューよりもかなり迅速にカーネルのビューを同期させようとします。システムがカーネルビューを高速で同期できない場合、システムは DDI_DMA_SYNC_FORCPU フラグが設定されているかのように動作します。