一部のデバイスドライバでは、ユーザースレッドやカーネルから要求された転送を実行するのに加え、DMA 転送用のメモリーを割り当てることが必要になる場合があります。プライベート DMA バッファーを割り当てる例として、デバイスとの通信用の共有メモリーを設定したり、中間転送バッファーを割り当てたりすることが挙げられます。DMA 転送用のメモリーを割り当てるには、 ddi_dma_mem_alloc(9F) を使用します。
int ddi_dma_mem_alloc(ddi_dma_handle_t handle, size_t length, ddi_device_acc_attr_t *accattrp, uint_t flags, int (*waitfp)(caddr_t), caddr_t arg, caddr_t *kaddrp, size_t *real_length, ddi_acc_handle_t *handlep);
ここでは:
DMA ハンドルです
目的とする割り当ての長さ (バイト単位) です
デバイスアクセス属性構造体へのポインタです
データ転送モードフラグです。使用できる値は、DDI_DMA_CONSISTENT と DDI_DMA_STREAMING です。
リソース割り当てエラーに対処するためのコールバック関数のアドレスです。 ddi_dma_alloc_handle(9F) のマニュアルページを参照してください。
コールバック関数に渡される引数です
割り当てられたストレージのアドレスを含む正常な復帰へのポインタです
割り当てられた長さ (バイト単位) です
データアクセスハンドルへのポインタです
デバイスが非順次方式でアクセスする場合、flags パラメータは DDI_DMA_CONSISTENT に設定されます。 ddi_dma_sync(9F) を使用する同期段階は、小さなオブジェクトに頻繁に適用されるため、できるだけ軽量にします。このようなアクセスは一般に、一貫性アクセスと呼ばれています。一貫性アクセスは、デバイスとドライバ間の通信に使用される入出力パラメータブロックに特に役立ちます。
x86 プラットフォームでは、物理的に連続したメモリーである DMA メモリーを割り当てる際に次の要件があります。
ddi_dma_attr(9S) 構造体に含まれる scatter/gather リスト dma_attr_sgllen の長さを 1 に設定する必要がある。
DDI_DMA_PARTIAL を指定しない。DDI_DMA_PARTIAL を指定すると、部分的なリソース割り当てが可能になります。
次の例は、IOPB メモリーと、そのメモリーへのアクセスに必要な DMA リソースの割り当て方法を示しています。DMA リソースを引き続き割り当て、DDI_DMA_CONSISTENT フラグを割り当て関数に渡す必要があります。
使用例 9-3 ddi_dma_mem_alloc(9F) の使用if (ddi_dma_mem_alloc(xsp->iopb_handle, size, &accattr, DDI_DMA_CONSISTENT, DDI_DMA_SLEEP, NULL, &xsp->iopb_array, &real_length, &xsp->acchandle) != DDI_SUCCESS) { /* error handling */ goto failure; } if (ddi_dma_addr_bind_handle(xsp->iopb_handle, NULL, xsp->iopb_array, real_length, DDI_DMA_READ | DDI_DMA_CONSISTENT, DDI_DMA_SLEEP, NULL, &cookie, &count) != DDI_DMA_MAPPED) { /* error handling */ ddi_dma_mem_free(&xsp->acchandle); goto failure; }
メモリー転送が順次、単方向、ブロックサイズ、およびブロック整列の方式で行われる場合、flags パラメータは DDI_DMA_STREAMING に設定されます。このようなアクセスは一般に、ストリーミングアクセスと呼ばれています。
場合によっては、入出力キャッシュを使用すると入出力転送の速度を上げることができます。入出力キャッシュは、最低でも 1 つのキャッシュラインを転送します。ddi_dma_mem_alloc(9F) ルーチンでは、データの破壊を避けるために size を四捨五入してキャッシュラインの倍数にします。
ddi_dma_mem_alloc(9F) 関数は、割り当てられたメモリーオブジェクトの実際のサイズを返します。パディングと配置の要件のために、実際のサイズは要求されたサイズよりも大きくなることがあります。ddi_dma_addr_bind_handle(9F) 関数には実際の長さを指定する必要があります。
ddi_dma_mem_alloc(9F) で割り当てられたメモリーを解放するには、ddi_dma_mem_free(9F) 関数を使用します。