BUS_DMA(9)

名称
bus_dma, bus_dmamap_create, bus_dmamap_destroy, bus_dmamap_load, bus_dmamap_load_mbuf, bus_dmamap_load_uio, bus_dmamap_load_raw, bus_dmamap_unload, bus_dmamap_sync, bus_dmamem_alloc, bus_dmamem_free, bus_dmamem_map, bus_dmamem_unmap, bus_dmamem_mmap - バスとマシンアーキテクチャに依存しない DMA マッピングインタフェース

書式
#include <machine/bus.h> int bus_dmamap_create(bus_dma_tag_t tag, bus_size_t size, int nsegments, bus_size_t maxsegsz, bus_size_t boundary, int flags, bus_dmamap_t *dmamp) void bus_dmamap_destroy(bus_dma_tag_t tag, bus_dmamap_t dmam) int bus_dmamap_load(bus_dma_tag_t tag, bus_dmamap_t dmam, void *buf, bus_size_t buflen, struct proc *p, int flags) int bus_dmamap_load_mbuf(bus_dma_tag_t tag, bus_dmamap_t dmam, struct mbuf *chain, int flags) int bus_dmamap_load_uio(bus_dma_tag_t tag, bus_dmamap_t dmam, struct uio *uio, int flags) int bus_dmamap_load_raw(bus_dma_tag_t tag, bus_dmamap_t dmam, bus_dma_segment_t *segs, int nsegs, bus_size_t size, int flags) void bus_dmamap_unload(bus_dma_tag_t tag, bus_dmamap_t dmam) void bus_dmamap_sync(bus_dma_tag_t tag, bus_dmamap_t dmam, bus_addr_t offset, bus_size_t len, int ops) int bus_dmamem_alloc(bus_dma_tag_t tag, bus_size_t size, bus_size_t alignment, bus_size_t boundary, bus_dma_segment_t *segs, int nsegs, int *rsegs, int flags) void bus_dmamem_free(bus_dma_tag_t tag, bus_dma_segment_t *segs, int nsegs) int bus_dmamem_map(bus_dma_tag_t tag, bus_dma_segment_t *segs, int nsegs, size_t size, caddr_t *kvap, int flags) void bus_dmamem_unmap(bus_dma_tag_t tag, caddr_t kva, size_t size) int bus_dmamem_mmap(bus_dma_tag_t tag, bus_dma_segment_t *segs, int nsegs, int off, int prot, int flags)

解説
バス/マシンアーキテクチャ 非依存の "DMA マッピングインタフェース" を提供する

注意

全てのデータ構造、関数プロトタイプ、マクロは、各アーキテクチャ毎の ヘッダ ~ <machine/bus.h> に定義されます。 この文書はそれぞれの型が現状の "bus.h" インタフェースに定義済みである ことを前提としていることに注意して下さい。

他に記してなければ、このインタフェースでの全ての関数呼び出しは cpp(1) マクロとして定義されているはずです。

データ型

実装内部ではこれらデータ構造に好きずきの名前をつけますが、外部向けには 下記の形式を提供します:

bus_dma_tag_t
    アーキテクチャ依存の不定の型で、バスの DMA 実装を表します。

bus_dma_segment_t
    最低限次のメンバを持った構造体です:

        	bus_addr_t	ds_addr;
        	bus_size_t	ds_len;

    この構造体はアーキテクチャ依存のメンバを、自由な配置で持つことができます。 ds_addr と ds_len の値は、DMA コントローラのアドレスと長さレジスタをプログラムで使用する ためのものです。

bus_dmamap_t
    最低限次のメンバを持った構造体へのポインタです:

        	bus_size_t	dm_mapsize;
        	int		dm_nsegs;
        	bus_dma_segment_t *dm_segs;

    この構造体はアーキテクチャ依存のメンバを、自由な配置で持つことができます。 dm_mapsize メンバは、マッピングのサイズを表します。 値が 0 の場合は、そのマッピングが無効であることを表します。 dm_segs メンバはセグメントの配列か、またはセグメントの配列へのポインタです。 dm_nsegs メンバは dm_segs のセグメントの数を示します。

関数

bus_dmamap_create(tag, size, nsegments, maxsegsz, boundary, flags, dmamp)
    引数にしたがい、DMA ハンドルを割り当てて初期化します。 引数については下記:
    tag <bus>_attach_args を経由して、親ドライバから渡される bus_dma_tag_t です。
    size
        そのハンドルでマップ可能な DMA 転送の最大値です。
    nsegments
        デバイスが一回の DMA トランザクションで扱うことのできるセグメント数です。 デバイスが扱えるスキャッタ-ギャザディスクリプタの数の場合もあります。
    maxsegsz
        指定された DMA セグメントが転送できる最大バイト数です。
    boundary
        DMA コントローラによっては、データを特定の境界をまたいで転送できない 場合があります。この境界をこの引数で指定します。境界は 0 から 始まり、 boundary バイトの倍数値の位置です。マッピングは境界位置から始まりますが、 終了は境界位置であったり、境界をまたいだりできません。境界条件が 必要ない場合は、 boundary 引数は 0 で使用します。
    flags
        Flags の定義は下記:
        BUS_DMA_WAITOK
            呼出の間、リソースのために待つ (sleep) ことができることを表しています。
        BUS_DMA_NOWAIT
            呼出の間、リソースのために待つ (sleep) ことができないことを表しています。
        BUS_DMA_ALLOCNOW
            このハンドルが必要なリソースの割当をすぐに行います。これが指定されて いない場合は、割当は bus_dmamap_load() まで遅延されます。 このフラグが指定されていれば、 bus_dmamap_load() のリソース割当はブロックしません。
        BUS_DMA_BUS[1-4]
            これらのフラグは予備のためのもので、バス依存の機能を提供するために 使用してもかまいません。
    dmamp
        bus_dmamap_t へのポインタです。このルーチンが正常に終了した場合、 DMA マップは dmamp の指す位置に割り当てられます。

    bus_dmamap_create() に不正な引数を渡した場合の動作は未定義です。

    正常終了で 0、そうでなければ失敗のモードを示すコードを返します。

bus_dmamap_destroy(tag, dmam)
    指定された DMA ハンドルにかかわる全てのリソースを解放します。引数は 下記:
    tag <bus>_attach_args を経由して、親ドライバから渡される bus_dma_tag_t です。
    dmam
        解放する DMA ハンドルです。

    DMA ハンドルが有効なマッピングを含んでいた場合、 bus_dmamap_unload() と同じ仕組みによってマッピングがアンロードされます。

    bus_dmamap_destroy() に不正な引数を渡した場合の動作は未定義です。

    有効な引数を渡した場合、 bus_dmamap_destroy() は必ず正常終了します。

bus_dmamap_load(tag, dmam, buf, buflen, p, flags)
    DMA ハンドラに DMA 転送のためのマッピングをロードします。DMA 転送に 使用する全ページは "wired" (訳注: 実メモリ固定?) であることが前提です。 引数は下記:
    tag <bus>_attach_args を経由して、親ドライバから渡される bus_dma_tag_t です。
    dmam
        転送対象のマップの DMA ハンドルです。
    buf DMA 転送で使用されるバッファです。
    buflen
        バッファのサイズです。
    p   バッファの位置するアドレス空間を指します。 NULL ならば、バッファはカーネル空間にあると解釈されます。そうでなければ、 バッファはプロセス p のアドレス空間にあると解釈されます。
    flags
        の定義は以下:
        BUS_DMA_WAITOK
            呼出の間、リソースのために待つ (sleep) ことができることを表しています。
        BUS_DMA_NOWAIT
            呼出の間、リソースのために待つ (sleep) ことができないことを表しています。
        BUS_DMA_BUS[1-4]
            これらのフラグは予備のためのもので、バス依存の機能を提供するために 使用してもかまいません。

    上述のように、 BUS_DMA_ALLOCNOW で作成した DMA ハンドルの場合、 bus_dmamap_load() はブロックしません。

    bus_dmamap_load() 呼出が失敗した場合、その DMA ハンドルのマッピングは無効となります。 uio 時に一連の動作が完了ず、デバイスの状態の矛盾が発生した場合、 これを解消するのは呼び出した側で行います。

    bus_dmamap_load() に不正な引数を渡した場合の動作は未定義です。

    正常終了で 0、そうでなければ失敗のモードを示すエラーコードを返します。

bus_dmamap_load_mbuf(tag, dmam, chain, flags)
    bus_dmamap_load() の変形で、DMA 転送に mbuf 連鎖をマップします。mbuf 連鎖は カーネル仮想アドレスにあると解釈されます。

bus_dmamap_load_uio(tag, dmam, uio, flags)
    bus_dmamap_load() の変形で、DMA 転送に uio の示すバッファをマップします。 uio->uio_segflg の値はそのバッファがユーザかあるいはカーネル仮想アドレスにあるかに依って 決まります。 バッファがユーザアドレス空間にある場合、 uio->uio_procp のアドレス空間にあると解釈されます。

bus_dmamap_load_raw(tag, dmam, segs, nsegs, size, flags)
    bus_dmamap_load() の変形で、DMA 転送に bus_dmamem_alloc() (後述) の割り当てるバッファを使用します。 segs 引数は bus_dmamem_alloc() が割り当てる bus_dma_segment_t の配列です。 nsegs 引数は配列のセグメント数です。 size 引数は DMA 転送のサイズです。

bus_dmamap_unload(tag, dmam)
    指定された DMA ハンドルのマッピングを削除します。引数は以下:
    tag <bus>_attach_args を経由して、親ドライバから渡される bus_dma_tag_t です。
    dmam
        DMA ハンドルです。これが持つマッピングは削除されます。

    DMA ハンドルが BUS_DMA_ALLOCNOW で作成されていた場合、 bus_dmamap_create() でそれに割り当てられたリソースは bus_dmamap_unload() では解放されません。 これはハンドルが BUS_DMA_ALLOCNOW で作成された場合には、 bus_dmamap_load() が決してブロックしない、ということを確実にするためです。

    bus_dmamap_unload() に不正な引数を渡した場合の動作は未定義です。

    正しい引数を渡した場合は、 bus_dmamap_unload() は必ず正常終了します。

bus_dmamap_sync(tag, dmam, offset, len, ops)
    DMA 動作前,後のキャッシュあるいはバッファの同期を実行します。 引数は下記:
    tag <bus>_attach_args を経由して、親ドライバから渡される bus_dma_tag_t です。
    dmam
        同期される DMA マッピングです。
    offset
        同期する DMA マッピング内のオフセットです。
    len 同期させるマッピングの offset からの長さです。
    op  実行する同期操作です。DMA 同期操作で定義されているのは下記です:
        BUS_DMASYNC_PREREAD
            なんらかの読み込み前 DMA キャッシュ/バウンス操作を実行します。
        BUS_DMASYNC_POSTREAD
            なんらかの読み込み後 DMA キャッシュ/バウンス操作を実行します。
        BUS_DMASYNC_PREWRITE
            なんらかの書き出し前 DMA キャッシュ/バウンス操作を実行します。
        BUS_DMASYNC_POSTWRITE
            なんらかの書き出し後 DMA キャッシュ/バウンス操作を実行します。

        1 回の同期コールで複数の同期操作を行って構いません。 PRE と POST 操作を混ぜることは許されず、これを行った時の動作は未定義です。

    同期操作はホスト RAM を見る方向で表現されます。たとえば、 device -> memory 操作は READ で、 memory -> device は WRITE です。

    bus_dmamp_sync() は、 そのメモリが DMA の一貫性制御の方法 may consult state kept within the DMA map to determine if the memory is mapped in a DMA coherent fashion. もしそうであれば、 bus_dmamap_sync() はデータキャッシュのフラッシュなどのある種の高価な命令をスキップすると決める かもしれません。 この件に関する詳細は bus_dmamem_map() を参照してください。

    reordered store を実装しているプラットフォームでは bus_dmamap_sync() は常に store buffer をフラッシュします。

    この関数の目的は同一のバッファに複数の読み込み/書き出し転送を実行することが できるようにすることで、これによってドライバは、DMA 転送用のデータの準備が できたことを bus_dma コードに明示的に知らせることができます。

    以下は 1 つのマッピングへ複数の読み込み-書き出しを行う例です:

        bus_dmamap_load(...);
        while (not done) {
        	/* 必要なくなったキャッシュブロックを無効化します */
        	bus_dmamap_sync(..., BUS_DMASYNC_PREREAD);
        	[ DMA 読み込み実行 ]
        	/* バウンスバッファからコピーします */
        	bus_dmamap_sync(..., BUS_DMASYNC_POSTREAD);
        	/* ドライバが用意したバッファへ読み込みます */
        	[ 処理 ]
        	/* 書き出すデータはドライバが用意したバッファに */
        	/* 入っています */
        	/* 書き出しバッファとライトバックキャッシュを*/
        	/* フラッシュし、バウンスバッファへコピー */
        	bus_dmamap_sync(..., BUS_DMASYNC_PREWRITE);
        	[ DMA 書き出し実行 ]
        	/* 通常無処理ですが、一貫性のため書いておきます */
        	bus_dmamap_sync(..., BUS_DMASYNC_POSTWRITE);
        }
        bus_dmamap_unload(...);

    DMA 読み込み/書き出し操作が、前あるいは後に適切な同期処理をしなかった 場合の動作は未定義です。

    bus_dmamap_sync() に不正な引数を渡した場合の動作は未定義です。

    有効な引数を渡した場合、 bus_dmamap_sync() は必ず正常終了します。

bus_dmamem_alloc(tag, size, alignment, boundary, segs, ...)
    指定の tag のバスに "DMA safe" なメモリを割り当てます。メモリのマッピングは アーキテクチャ依存 (あるいは非透過) で、アーキテクチャ非依存のコードでは 返されるアドレスが有効なカーネルのアドレス空間であるとか、 返されるアドレスがシステムの物理アドレスであるとかを前提としては いけません。

    割り当ては、常にハードウエアのページサイズの倍数になります。このやり方の ほうが利点があり、小さなデータ構造はかたまりで割り当てるようにします。 引数は下記:
    tag <bus>_attach_args を経由して、親ドライバから渡される bus_dma_tag_t です。
    size
        割り当てるメモリの総数です。
    alignment
        割り当てられたメモリのセグメントはこの値の単位となります。この値が ハードウエアページサイズよりも小さい場合、ハードウエアページサイズまで 切り上げられます。この値は 2 の冪乗でなければなりません。
    boundary
        割り当てられたメモリのセグメントは (0 から相対で) この境界値を またいではなりません。この値は 2 の冪乗でなければなりません。 割り当てサイズより小さい境界値は無効です。
    segs
        メモリ割り当て後に bus_dma_segment_t の配列がここへ割り当てられます。 非透過なメモリ塊へのアドレスです。
    nsegs
        segs のセグメント数を指定します。割り当てられるメモリ連鎖の最大値です。
    rsegs
        実際にメモリにいくつのセグメントがあるかを返すのに使用されます。
    flags
        フラグの定義は以下:
        BUS_DMA_WAITOK
            呼出の間、リソースのために待つ (sleep) ことができることを表しています。
        BUS_DMA_NOWAIT
            呼出の間、リソースのために待つ (sleep) ことができないことを表しています。
        BUS_DMA_BUS[1-4]
            これらのフラグは予備のためのもので、バス依存の機能を提供するために 使用してもかまいません。

    bus_dmamem_alloc() で割り当てたページは、 bus_dmamem_free() で解放するまで確保されたままです。

    bus_dmamem_alloc() に不正な引数を渡した場合の動作は未定義です。

    正常終了で 0、そうでなければ失敗のモードを示すエラーコードを返します。

bus_dmamem_free(tag, segs, nsegs)
    bus_dmamem_alloc() で割り当てたメモリを解放します。 マッピングは全て無効になります。引数は以下:
    tag <bus>_attach_args を経由して、親ドライバから渡される bus_dma_tag_t です。
    segs
        bus_dmamem_alloc() で割り当てられた bus_dma_segment_t の配列です。
    nsegs
        segs のセグメント数です。

    bus_dmamem_free() に不正な引数を渡した場合の動作は未定義です。

    有効な引数では、 bus_dmamem_free() は常に正常終了します。

bus_dmamem_map(tag, segs, nsegs, size, kvap, flags)
    bus_dmamem_alloc() で割り当てたメモリをカーネル仮想アドレス空間にマップします。引数は以下:
    tag <bus>_attach_args を経由して、親ドライバから渡される bus_dma_tag_t です。
    segs
        bus_dmamem_alloc() で割り当てられた bus_dma_segment_t の配列で、マップするメモリ領域です。
    nsegs
        segs のセグメント数です。
    size
        マップするサイズです。
    kvap
        メモリをマップするカーネル仮想アドレスを指定するために使用します。
    flags
        フラグの定義は以下:
        BUS_DMA_WAITOK
            呼出の間、リソースのために待つ (sleep) ことができます。
        BUS_DMA_NOWAIT
            呼出の間、リソースのために待つ (sleep) ことができません。
        BUS_DMA_BUS[1-4]
            これらのフラグは予備のためのもので、バス依存の機能を提供するために 使用してもかまいません。
        BUS_DMA_COHERENT
            このフラグは マシン依存のコードに対して ヒント を与えるためのものです。もし可能であれば、DMA で一貫性制御が行われるように そのメモリをマップします。これには、そのページをキャッシュなしの アドレス空間にマップするとか、ページテーブルエントリ内のキャッシュ抑制 ビットといったことが含まれます。 DMA での一貫性制御マッピングの実装が不可能な場合、これは無視されます。

            後でこのメモリが DMA マップにロードされた時に、 そのメモリが DMA 一貫性制御を行うようにマップされているかどうかを調べるために 必要なことは全て行います。 これには、そのカーネル仮想アドレスが含まれるアドレス空間が無変更かどうかや、 ページテーブルエントリ内のキャッシュ抑制ビットがセットされているかどうか が含まれます。 もしそのマッピングが DMA で一貫性を保てると判断されると、 その状態が DMA map になります。これは、 後で呼び出される bus_dmamap_sync() で使われます。
        BUS_DMAMEM_NOSYNC
            bus_dmamap_sync() による同期が必要ないようにメモリをマップします。 あまりデバイスからの読み書きがなく、ホストからのコマンド/状態取得の やりとりが主なディスクリプタブロックの場合、マップの同期は不必要に 高価なため、この方法が有効です。このフラグは注意して使用して下さい

    bus_dmamem_map() に不正な引数を渡した場合の動作は未定義です。

    正常終了で 0、そうでなければ失敗のモードを示すエラーコードを返します。

bus_dmamem_unmap(tag, kva, size)
    以前に bus_dmamem_map() でマップしたメモリをマップ解除し、そのマッピングで使用していたカーネル 仮想アドレス空間を解放します。引数は以下:
    tag <bus>_attach_args を経由して、親ドライバから渡される bus_dma_tag_t です。
    kva マップされているメモリのカーネル仮想アドレスです。
    size
        マッピングのサイズです。

    bus_dmamem_unmap() に不正な引数を渡した場合の動作は未定義です。

    正しい引数を渡した場合は、 bus_dmamem_unmap() は必ず正常終了します。

bus_dmamem_mmap(tag, segs, nsegs, off, prot, flags)
    ユーザに DMA-safe なメモリの mmap(2) サポートを提供します。 この関数は、デバイスのページャが各ページをマップする時に呼び出される、 デバイスドライバの (*d_mmap)() エントリポイントから呼び出されます。 引数は以下:
    tag <bus>_attach_args を経由して、親ドライバから渡される bus_dma_tag_t です。
    segs
        bus_dmamem_alloc() で割り当てられた bus_dma_segment_t の配列で、 mmap(2) されるメモリです。
    nsegs
        segs 配列の要素数です。
    off マップする DMA メモリページのオフセットです。
    prot
        マップの保護コードです。
    flags
        フラグの定義は以下:
        BUS_DMA_WAITOK
            呼出の間、リソースのために待つ (sleep) ことができます。
        BUS_DMA_NOWAIT
            呼出の間、リソースのために待つ (sleep) ことができません。
        BUS_DMA_BUS[1-4]
            これらのフラグは予備のためのもので、バス依存の機能を提供するために 使用してもかまいません。
        BUS_DMAMEM_COHERENT
            このフラグに関しては、前述の bus_dmamem_map() の記述を参照してください。

    bus_dmamem_mmap() に不正な引数を渡した場合の動作は未定義です。

    異常終了で -1 を返します。他に、デバイスページャが解釈する非透過な 値を返すことがあります。

関連項目
bus_space(9)

作者
bus_dma インタフェースの設計と実装は Numerical Aerospace Simulation Facility, NASA Ames Research Center の Jason R. Thorpe が行いました。 bus_dma の設計に対し、Chris Demetriou, Charles Hannum, Ross Harvey, Matthew Jacob, Jonathan Stone, Matt Thomas が追加を行いました。

歴史
bus_dma インタフェースは NetBSD 1.3 で登場しました。