ナビゲーションリンクをスキップ | |
印刷ビューの終了 | |
デバイスドライバの記述 Oracle Solaris 11.1 Information Library (日本語) |
パート I Oracle Solaris プラットフォーム用デバイスドライバの設計
2. Oracle Solaris カーネルとデバイスツリー
DMA ソフトウェアコンポーネント: ハンドル、ウィンドウ、cookie
22. ドライバのコンパイル、ロード、パッケージ化、およびテスト
23. デバイスドライバのデバッグ、テスト、およびチューニング
このセクションでは、DMA 資源を管理する方法について説明します。
DMA 資源をメモリーオブジェクトに割り当てる前に、そのオブジェクトを移動できないようにする必要があります。そうしないと、デバイスがオブジェクトへの書き込みを試している間に、システムがそのオブジェクトをメモリーから削除する可能性があります。オブジェクトが見つからないと、データ転送に失敗し、システムが破壊される恐れがあります。DMA 転送中にメモリーオブジェクトが移動できないようにするプロセスは、オブジェクトのロックダウンと呼ばれます。
次のオブジェクトタイプは、明示的なロックが必要ありません。
strategy(9E) によってファイルシステムから生成されるバッファー。これらのバッファーはファイルシステムによってすでにロックされています。
デバイスドライバ内で割り当てられたカーネルメモリー (ddi_dma_mem_alloc(9F) で割り当てられたものなど)。
ユーザー空間から生成されるバッファーなど、その他のオブジェクトについては、physio(9F) または ddi_umem_lock(9F) を使用してロックダウンする必要があります。これらの関数を使ったオブジェクトのロックダウンは通常、文字デバイスドライバの read(9E) または write(9E) ルーチン内で実行されます。「データ転送方法」を参照してください。
DMA ハンドルは、そのあとに割り当てられる DMA 資源への参照として使用される不透明なオブジェクトです。DMA ハンドルは通常、ddi_dma_alloc_handle(9F) を使用する、ドライバの attach() エントリポイントで割り当てられます。ddi_dma_alloc_handle() 関数は、dip によって参照されるデバイス情報と、ddi_dma_attr(9S) 構造体によってパラメータとして記述されたデバイスの DMA 属性を取得します。ddi_dma_alloc_handle() 関数の構文は次のとおりです。
int ddi_dma_alloc_handle(dev_info_t *dip, ddi_dma_attr_t *attr, int (*callback)(caddr_t), caddr_t arg, ddi_dma_handle_t *handlep);
各表記の意味は次のとおりです。
デバイスの dev_info 構造体へのポインタ。
ddi_dma_attr(9S) 構造体へのポインタです (「DMA 属性」 を参照)。
資源割り当てエラーに対処するためのコールバック関数のアドレスです。
コールバック関数に渡される引数です。
返されたハンドルを格納するための DMA ハンドルへのポインタです。
DMA 資源は次の 2 つのインタフェースで割り当てられます。
ddi_dma_buf_bind_handle(9F) – buf(9S) 構造体とともに使用されます
ddi_dma_addr_bind_handle(9F) – 仮想アドレスとともに使用されます
DMA 資源は通常、ドライバの xxstart() ルーチンで割り当てられます (xxstart() ルーチンが存在する場合)。xxstart() については、「非同期データ転送 (ブロックドライバ)」を参照してください。これらの 2 つのインタフェースの構文は次のとおりです。
int ddi_dma_addr_bind_handle(ddi_dma_handle_t handle, struct as *as, caddr_t addr, size_t len, uint_t flags, int (*callback)(caddr_t), caddr_t arg, ddi_dma_cookie_t *cookiep, uint_t *ccountp); int ddi_dma_buf_bind_handle(ddi_dma_handle_t handle, struct buf *bp, uint_t flags, int (*callback)(caddr_t), caddr_t arg, ddi_dma_cookie_t *cookiep, uint_t *ccountp);
次の引数は、ddi_dma_addr_bind_handle(9F) と ddi_dma_buf_bind_handle(9F) の両方に共通です。
DMA ハンドルと、資源を割り当てるためのオブジェクトです。
転送方向などの属性を指定するフラグセットです。DDI_DMA_READ はデバイスからメモリーへのデータ転送を指定します。DDI_DMA_WRITE はメモリーからデバイスへのデータ転送を指定します。利用できるフラグの詳細は、ddi_dma_addr_bind_handle(9F) または ddi_dma_buf_bind_handle(9F) のマニュアルページを参照してください。
資源割り当てエラーに対処するためのコールバック関数のアドレスです。ddi_dma_alloc_handle(9F) のマニュアルページを参照してください。
コールバック関数に渡される引数です。
このオブジェクトの最初の DMA cookie へのポインタです。
このオブジェクトの DMA cookie の数へのポインタです。
ddi_dma_addr_bind_handle(9F) の場合、オブジェクトは、次のパラメータでアドレス範囲を指定することによって記述します。
アドレス空間構造体へのポインタです。as の値は NULL になります。
オブジェクトのベースカーネルアドレスです。
オブジェクトの長さをバイト単位で指定します。
ddi_dma_buf_bind_handle(9F) の場合、オブジェクトは、bp が示す buf(9S) 構造体で記述します。
DMA 対応デバイスには、前述の例で使用したものよりも多くのレジスタが必要になります。
scatter/gather 機能を使わずに DMA 対応デバイスをサポートするには、デバイスレジスタ構造体で次のフィールドを使用します。
uint32_t dma_addr; /* starting address for DMA */ uint32_t dma_size; /* amount of data to transfer */
scatter/gather 機能を使って DMA 対応デバイスをサポートするには、デバイスレジスタ構造体で次のフィールドを使用します。
struct sglentry { uint32_t dma_addr; uint32_t dma_size; } sglist[SGLLEN]; caddr_t iopb_addr; /* When written, informs the device of the next */ /* command's parameter block address. */ /* When read after an interrupt, contains */ /* the address of the completed command. */
例 9-1 では、コールバック関数として xxstart() を使用します。また、xxstart() の引数としてデバイスごとの状態構造体を使用します。xxstart() 関数は、コマンドを開始しようとします。資源が利用できないためにコマンドを開始できない場合、xxstart() はあとで資源が利用可能になったときに呼び出されるようにスケジュールされます。
xxstart() は DMA コールバックとして使用されるため、xxstart() は DMA コールバックに課せられている次の規則に従う必要があります。
資源は利用可能であると想定できない。コールバックで資源の割り当てを再度試みる必要がある。
コールバックで、割り当てが成功したかどうかをシステムに知らせる必要がある。コールバックが資源の割り当てに失敗すると、DDI_DMA_CALLBACK_RUNOUT が返されます。その場合は、あとで xxstart() を再度呼び出す必要があります。DDI_DMA_CALLBACK_DONE は成功を示しているため、これ以上コールバックは必要ありません。
例 9-1 DMA コールバックの例
static int xxstart(caddr_t arg) { struct xxstate *xsp = (struct xxstate *)arg; struct device_reg *regp; int flags; mutex_enter(&xsp->mu); if (xsp->busy) { /* transfer in progress */ mutex_exit(&xsp->mu); return (DDI_DMA_CALLBACK_RUNOUT); } xsp->busy = 1; regp = xsp->regp; if ( /* transfer is a read */ ) { flags = DDI_DMA_READ; } else { flags = DDI_DMA_WRITE; } mutex_exit(&xsp->mu); if (ddi_dma_buf_bind_handle(xsp->handle,xsp->bp,flags, xxstart, (caddr_t)xsp, &cookie, &ccount) != DDI_DMA_MAPPED) { /* really should check all return values in a switch */ mutex_enter(&xsp->mu); xsp->busy=0; mutex_exit(&xsp->mu); return (DDI_DMA_CALLBACK_RUNOUT); } /* Program the DMA engine. */ return (DDI_DMA_CALLBACK_DONE); }
ドライバは、そのデバイスがサポートする DMA バーストサイズを、ddi_dma_attr(9S) 構造体の dma_attr_burstsizes フィールドで指定します。このフィールドは、サポートされるバーストサイズのビットマップです。ただし、システムでは、DMA 資源が割り当てられたときに、デバイスが実際に使用する可能性のあるバーストサイズに対してさらなる制限を加えることがあります。ddi_dma_burstsizes(9F) ルーチンを使用すると、許容されるバーストサイズを取得できます。このルーチンは、デバイスの適切なバーストサイズビットマップを返します。ドライバは、DMA 資源が割り当てられるときに、DMA エンジンに使用する適切なバーストサイズをシステムに問い合わせることができます。
例 9-2 バーストサイズの決定
#define BEST_BURST_SIZE 0x20 /* 32 bytes */ if (ddi_dma_buf_bind_handle(xsp->handle,xsp->bp, flags, xxstart, (caddr_t)xsp, &cookie, &ccount) != DDI_DMA_MAPPED) { /* error handling */ } burst = ddi_dma_burstsizes(xsp->handle); /* check which bit is set and choose one burstsize to */ /* program the DMA engine */ if (burst & BEST_BURST_SIZE) { /* program DMA engine to use this burst size */ } else { /* other cases */ }
一部のデバイスドライバでは、ユーザースレッドやカーネルから要求された転送を実行するのに加え、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) 関数を使用します。
注 - ドライバは、バッファーが適切に配置されるようにする必要があります。下方バインドされた DMA バッファーの配置要件が設定されているデバイスのドライバは、それらの要件を満たすドライバの中間バッファーにデータをコピーしてから、その中間バッファーを DMA 用の DMA ハンドルにバインドすることが必要な場合があります。ドライバの中間バッファーを割り当てるには、ddi_dma_mem_alloc(9F) を使用します。アクセスするデバイスにメモリーを割り当てるには、kmem_alloc(9F) ではなく、必ず ddi_dma_mem_alloc(9F) を使用します。
資源割り当てルーチンは、割り当てエラーの処理時にいくつかのオプションをドライバに提供します。waitfp 引数は、次の表に示すように、割り当てルーチンがブロックする、すぐに復帰する、コールバックをスケジュールするのいずれになるかを示します。
表 9-1 資源割り当て処理
|
資源の割り当てが正常に完了したら、デバイスをプログラミングする必要があります。DMA エンジンのプログラミングはデバイスごとに異なりますが、開始アドレスと転送カウントはすべての DMA エンジンに必要です。デバイスドライバはこれらの 2 つの値を、ddi_dma_addr_bind_handle(9F)、ddi_dma_buf_bind_handle(9F)、または ddi_dma_getwin(9F) の呼び出しが正常に行われた場合に返されるDMA cookie から取得します。これらの関数はすべて、最初の DMA cookie と、DMA オブジェクトが複数の cookie で構成されているかどうかを示す cookie カウントを返します。cookie カウント N が 1 よりも大きければ、ddi_dma_nextcookie(9F) を N-1 回だけ呼び出して残りの cookie をすべて取得します。
DMA cookie の型は ddi_dma_cookie(9S) です。この型の cookie には次のフィールドがあります。
uint64_t _dmac_ll; /* 64-bit DMA address */ uint32_t _dmac_la[2]; /* 2 x 32-bit address */ size_t dmac_size; /* DMA cookie size */ uint_t dmac_type; /* bus specific type bits */
dmac_laddress フィールドには、デバイスの DMA エンジンのプログラミングに適した 64 ビットの入出力アドレスを指定します。デバイスに 64 ビットの DMA アドレスレジスタがある場合、ドライバはこのフィールドを使用して DMA エンジンをプログラミングします。dmac_address フィールドには、32 ビットの DMA アドレスレジスタを持つデバイスに使用される 32 ビットの入出力アドレスを指定します。dmac_size フィールドには、転送カウントが入ります。cookie の dmac_type フィールドがドライバで必要になるかどうかは、バスアーキテクチャーによって決まります。ドライバは、cookie に対して論理操作や算術操作などの操作は一切行いません。
例 9-4 ddi_dma_cookie(9S) の例
ddi_dma_cookie_t cookie; if (ddi_dma_buf_bind_handle(xsp->handle,xsp->bp, flags, xxstart, (caddr_t)xsp, &cookie, &xsp->ccount) != DDI_DMA_MAPPED) { /* error handling */ } sglp = regp->sglist; for (cnt = 1; cnt <= SGLLEN; cnt++, sglp++) { /* store the cookie parms into the S/G list */ ddi_put32(xsp->access_hdl, &sglp->dma_size, (uint32_t)cookie.dmac_size); ddi_put32(xsp->access_hdl, &sglp->dma_addr, cookie.dmac_address); /* Check for end of cookie list */ if (cnt == xsp->ccount) break; /* Get next DMA cookie */ (void) ddi_dma_nextcookie(xsp->handle, &cookie); } /* start DMA transfer */ ddi_put8(xsp->access_hdl, ®p->csr, ENABLE_INTERRUPTS | START_TRANSFER);
DMA 転送の完了後、通常は割り込みルーチンで、ドライバは ddi_dma_unbind_handle(9F) を呼び出して、DMA 資源を解放できます。
「メモリーオブジェクトの同期」で説明しているように、ddi_dma_unbind_handle(9F) が ddi_dma_sync(9F) を呼び出すことで、明示的に同期を行う必要がなくなります。ddi_dma_unbind_handle(9F) の呼び出し後、DMA 資源は無効になり、それ以上その資源を参照しても結果は保証されません。次の例は、ddi_dma_unbind_handle(9F) の使用方法を示しています。
例 9-5 DMA 資源の解放
static uint_t xxintr(caddr_t arg) { struct xxstate *xsp = (struct xxstate *)arg; uint8_t status; volatile uint8_t temp; mutex_enter(&xsp->mu); /* read status */ status = ddi_get8(xsp->access_hdl, &xsp->regp->csr); if (!(status & INTERRUPTING)) { mutex_exit(&xsp->mu); return (DDI_INTR_UNCLAIMED); } ddi_put8(xsp->access_hdl, &xsp->regp->csr, CLEAR_INTERRUPT); /* for store buffers */ temp = ddi_get8(xsp->access_hdl, &xsp->regp->csr); ddi_dma_unbind_handle(xsp->handle); /* Check for errors. */ xsp->busy = 0; mutex_exit(&xsp->mu); if ( /* pending transfers */ ) { (void) xxstart((caddr_t)xsp); } return (DDI_INTR_CLAIMED); }
DMA 資源が解放されます。次の転送で別のオブジェクトが使用される場合、DMA 資源を再割り当てする必要があります。ただし、同じオブジェクトが常に使用される場合、資源の割り当ては一度で構いません。途中の ddi_dma_sync(9F) の呼び出しが残っているかぎり、資源の再利用が可能です。
ドライバが切り離される場合は、DMA ハンドルを解放する必要があります。ddi_dma_free_handle(9F) 関数は、DMA ハンドルと、システムがそのハンドル上でキャッシュしている残りの資源をすべて破棄します。DMA ハンドルをそれ以上参照しても結果は保証されません。
DMA コールバックを取り消すことはできません。DMA コールバックを取り消すには、ドライバの detach(9E) エントリポイントにコードを追加する必要があります。未処理のコールバックが存在する場合は、detach() ルーチンが DDI_SUCCESS を返すことはありません。例 9-6 を参照してください。DMA コールバックが発生すると、detach() ルーチンはコールバックが実行されるのを待つ必要があります。コールバックが完了したら、detach() はコールバックが再スケジュールを行わないようにする必要があります。次の例に示すように、状態構造体で追加のフィールドを指定することによって、コールバックが再スケジュールを行わないようにすることができます。
例 9-6 DMA コールバックの取り消し
static int xxdetach(dev_info_t *dip, ddi_detach_cmd_t cmd) { /* ... */ mutex_enter(&xsp->callback_mutex); xsp->cancel_callbacks = 1; while (xsp->callback_count > 0) { cv_wait(&xsp->callback_cv, &xsp->callback_mutex); } mutex_exit(&xsp->callback_mutex); /* ... */ } static int xxstrategy(struct buf *bp) { /* ... */ mutex_enter(&xsp->callback_mutex); xsp->bp = bp; error = ddi_dma_buf_bind_handle(xsp->handle, xsp->bp, flags, xxdmacallback, (caddr_t)xsp, &cookie, &ccount); if (error == DDI_DMA_NORESOURCES) xsp->callback_count++; mutex_exit(&xsp->callback_mutex); /* ... */ } static int xxdmacallback(caddr_t callbackarg) { struct xxstate *xsp = (struct xxstate *)callbackarg; /* ... */ mutex_enter(&xsp->callback_mutex); if (xsp->cancel_callbacks) { /* do not reschedule, in process of detaching */ xsp->callback_count--; if (xsp->callback_count == 0) cv_signal(&xsp->callback_cv); mutex_exit(&xsp->callback_mutex); return (DDI_DMA_CALLBACK_DONE); /* don't reschedule it */ } /* * Presumably at this point the device is still active * and will not be detached until the DMA has completed. * A return of 0 means try again later */ error = ddi_dma_buf_bind_handle(xsp->handle, xsp->bp, flags, DDI_DMA_DONTWAIT, NULL, &cookie, &ccount); if (error == DDI_DMA_MAPPED) { /* Program the DMA engine. */ xsp->callback_count--; mutex_exit(&xsp->callback_mutex); return (DDI_DMA_CALLBACK_DONE); } if (error != DDI_DMA_NORESOURCES) { xsp->callback_count--; mutex_exit(&xsp->callback_mutex); return (DDI_DMA_CALLBACK_DONE); } mutex_exit(&xsp->callback_mutex); return (DDI_DMA_CALLBACK_RUNOUT); }
メモリーオブジェクトにアクセスする過程で、ドライバはさまざまなキャッシュに対してメモリーオブジェクトを同期させることが必要な場合があります。このセクションでは、メモリーオブジェクトの同期を行うタイミングとその方法に関するガイドラインを示します。
CPU キャッシュは、CPU とシステムのメインメモリーの間に位置する非常に高速なメモリーです。入出力キャッシュは、デバイスとシステムのメインメモリーの間に位置します (次の図を参照)。
メインメモリーからデータを読み取ろうとすると、関連付けられたキャッシュは要求されたデータがあるかどうかを確認します。データが利用可能である場合、キャッシュはすぐにデータを提供します。データがキャッシュに含まれていない場合、キャッシュはメインメモリーからそのデータを取り出します。次に、そのデータを要求元に渡し、次の要求に備えてデータを保存します。
同様に、書き込みサイクルでは、データはすぐにキャッシュに格納されます。CPU やデバイスは、実行 (つまりデータの転送) を続けることができます。データをキャッシュに格納するのにかかる時間は、データがメモリーに書き込まれるのを待つ時間よりもはるかに短くてすみます。
このモデルでは、デバイス転送が完了したあとも、引き続きデータを入出力キャッシュに格納でき、メインメモリーにはデータが入っていません。CPU がメモリーにアクセスした場合、CPU は CPU キャッシュから間違ったデータを読み取る可能性があります。ドライバは、同期ルーチンを呼び出して、入出力キャッシュからデータをフラッシュし、新しいデータで CPU キャッシュを更新する必要があります。この処理により、CPU のメモリーのビューの一貫性が確保されます。同様に、CPU によって変更されたデータにデバイスからアクセスする場合も、同期段階が必要です。
デバイスとメモリーの間に、バスエクステンダやブリッジなどの追加のキャッシュやバッファーを作成できます。ddi_dma_sync(9F) を使用して、該当するすべてのキャッシュを同期させます。
メモリーオブジェクトには、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 エンジンによって読み取られようとしている場合は、type を DDI_DMA_SYNC_FORDEV に設定して、デバイスのオブジェクトビューを同期させる必要があります。デバイスの DMA エンジンがメモリーオブジェクトに書き込みを行なったあとで、そのオブジェクトが CPU によって読み取られようとしている場合は、type を DDI_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 フラグが設定されているかのように動作します。