Go to main content
Oracle® Solaris 11.3 デバイスドライバの記述

印刷ビューの終了

更新: 2016 年 11 月
 
 

DMA 操作

DMA 転送の段階は、どの種類の DMA でも似ています。以降のセクションでは、DMA 転送を実行する方法について説明します。


注 - ファイルシステムから生成されるバッファー用のブロックドライバのメモリー内に DMA オブジェクトをロックしておく必要はありません。メモリー内のデータは、ファイルシステムによってすでにロックされています。

バスマスター DMA 転送の実行

ドライバは、バスマスター DMA に関する次の手順を実行します。

  1. DMA 属性を記述します。この手順により、DMA ルーチンで、デバイスがバッファーにアクセスできることを保証できるようになります。

  2. DMA ハンドルを割り当てます。

  3. DMA オブジェクトがメモリー内でロックされていることを確認します。physio(9F) またはddi_umem_lock(9F) のマニュアルページを参照してください。

  4. DMA リソースをオブジェクトに割り当てます。

  5. デバイス上で DMA エンジンをプログラミングします。

  6. エンジンを起動します。

  7. 転送が完了したら、バスマスター操作を続行します。

  8. 必要なオブジェクト同期があれば、それを行います。

  9. DMA リソースを解放します。

  10. DMA ハンドルを解放します。

ファーストパーティー DMA 転送の実行

ドライバは、ファーストパーティー DMA に関する次の手順を実行します。

  1. DMA チャネルを割り当てます。

  2. ddi_dmae_1stparty(9F) を使用してチャネルを構成します。

  3. DMA オブジェクトがメモリー内でロックされていることを確認します。physio(9F) またはddi_umem_lock(9F) のマニュアルページを参照してください。

  4. DMA リソースをオブジェクトに割り当てます。

  5. デバイス上で DMA エンジンをプログラミングします。

  6. エンジンを起動します。

  7. 転送が完了したら、バスマスター操作を続行します。

  8. 必要なオブジェクト同期があれば、それを行います。

  9. DMA リソースを解放します。

  10. DMA チャネルを解放します。

サードパーティー DMA 転送の実行

ドライバは、サードパーティー DMA に関する次の手順を実行します。

  1. DMA チャネルを割り当てます。

  2. ddi_dmae_getattr(9F) を使用してシステムの DMA エンジンの属性を取得します。

  3. DMA オブジェクトをメモリー内にロックします。physio(9F) またはddi_umem_lock(9F) のマニュアルページを参照してください。

  4. DMA リソースをオブジェクトに割り当てます。

  5. ddi_dmae_prog(9F) を使用して、転送を行うようにシステムの DMA エンジンをプログラミングします。

  6. 必要なオブジェクト同期があれば、それを行います。

  7. ddi_dmae_stop(9F) を使用して DMA エンジンを停止します。

  8. DMA リソースを解放します。

  9. DMA チャネルを解放します。

ハードウェアプラットフォームの中には、バス固有の方法で DMA 機能を制限しているものもあります。ドライバは ddi_slaveonly(9F) を使用して、DMA を使用できるスロット内にデバイスがあるかどうかを確認します。

DMA 属性

DMA 属性には、次のような DMA エンジンの属性と制限が記述されています。

  • デバイスがアクセスできるアドレスの制限

  • 最大転送数

  • アドレスの配置の制限

デバイスドライバは、ddi_dma_attr(9S) 構造体を通じて DMA エンジンのすべての制限をシステムに通知する必要があります。この処理により、システムが割り当てた DMA リソースにデバイスの DMA エンジンからアクセスできるようになります。システムでは、デバイス属性にさらなる制限を加えることはありますが、ドライバが設定した制限を削除することはありません。

ddi_dma_attr 構造体

DMA 属性構造体は、次のメンバーで構成されます。

typedef struct ddi_dma_attr {
    uint_t      dma_attr_version;       /* version number */
    uint64_t    dma_attr_addr_lo;       /* low DMA address range */
    uint64_t    dma_attr_addr_hi;       /* high DMA address range */
    uint64_t    dma_attr_count_max;     /* DMA counter register */
    uint64_t    dma_attr_align;         /* DMA address alignment */
    uint_t      dma_attr_burstsizes;    /* DMA burstsizes */
    uint32_t    dma_attr_minxfer;       /* min effective DMA size */
    uint64_t    dma_attr_maxxfer;       /* max DMA xfer size */
    uint64_t    dma_attr_seg;           /* segment boundary */
    int         dma_attr_sgllen;        /* s/g length */
    uint32_t    dma_attr_granular;      /* granularity of device */
    uint_t      dma_attr_flags;         /* Bus specific DMA flags */
} ddi_dma_attr_t;

ここでは:

dma_attr_version

属性構造体のバージョン番号です。dma_attr_version は DMA_ATTR_V0 に設定されます。

dma_attr_addr_lo

DMA エンジンがアクセスできる最下位のバスアドレスです。

dma_attr_addr_hi

DMA エンジンがアクセスできる最上位のバスアドレスです。

dma_attr_count_max

DMA エンジンが 1 つの cookie で処理できる最大転送数を指定します。上限は、最大数から 1 を引いた数で表されます。この数はビットマスクとして使用されるため、2 のべき乗よりも小さくする必要もあります。

dma_attr_align

ddi_dma_mem_alloc(9F) からメモリーを割り当てるときの配置要件を指定します。配置要件の例として、ページ境界での配置があります。dma_attr_align フィールドはメモリーの割り当て時にしか使用されません。バインド操作時には、このフィールドは無視されます。バインド操作では、ドライバはバッファーが適切に配置されるようにする必要があります。

dma_attr_burstsizes

デバイスがサポートするバーストサイズを指定します。バーストサイズとは、デバイスがバスを放棄する前に転送できるデータ量のことです。バーストこのメンバーはバイナリ符号化方式のバーストサイズです。このサイズは、2 のべき乗になるものとみなされます。たとえば、デバイスが 1 バイト、2 バイト、4 バイト、および 16 バイトのバーストを処理できる場合、このフィールドは 0x17 に設定されます。システムでは、このフィールドを使用して配置制限も決めます。

dma_attr_minxfer

デバイスが実行できる効果的な最低転送サイズです。このサイズは、配置やパディングの制限にも影響を及ぼします。

dma_attr_maxxfer

DMA エンジンが 1 回の入出力コマンドで格納できる最大バイト数を記述します。この制限が意味を持つのは、dma_attr_maxxfer が (dma_attr_count_max + 1) * dma_attr_sgllen よりも小さい場合のみです。

dma_attr_seg

DMA エンジンのアドレスレジスタの上限です。dma_attr_seg は、アドレスレジスタの上位 8 ビットがセグメント番号を含むラッチである場合に頻繁に使用されます。下位 24 ビットはセグメントのアドレス指定に使用されます。この場合、dma_attr_seg は 0xFFFFFF に設定されます。これにより、オブジェクトへのリソースの割り当て時にシステムは 24 ビットのセグメント境界を越えることはできません。セグメント境界の制限は DMA cookie に適用されるため、DMA cookie セグメント境界を越えることはできません。ただし、DMA ウィンドウでは、セグメント境界の両側に cookie を含めることができます。

dma_attr_sgllen

scatter/gather リストに含まれる最大エントリ数を指定します。dma_attr_sgllen は、DMA エンジンがデバイスへの 1 回の入出力要求で使用できる cookie の数です。DMA エンジンに scatter/gather リストがない場合、このフィールドは 1 に設定されます。

dma_attr_granular

このフィールドは、デバイスの DMA 転送機能の粒度をバイト単位で指定します。この値の使用方法の例として、外部ストレージデバイスのセクターサイズの指定が挙げられます。バインド操作で部分的なマッピングが必要な場合、このフィールドを使用して、各 DMA ウィンドウ (最後のウィンドウを除く) 内の cookie のサイズ合計が粒度の整数倍になるようにします。ただし、デバイスに scatter/gather 機能がない場合は、DDI で粒度を保証することはできません。この場合、 dma_attr_granular フィールドの値は 1 になります。

dma_attr_flags

このフィールドには DDI_DMA_FORCE_PHYSICAL を設定できます。これは、システムが物理入出力アドレスと仮想入出力アドレスの両方をサポートしている場合に、仮想ではなく物理アドレスが返されることを示します。システムが物理 DMA をサポートしていない場合、ddi_dma_alloc_handle(9F) の戻り値は DDI_DMA_BADATTR になります。この場合、ドライバは DDI_DMA_FORCE_PHYSICAL をクリアし、処理を再試行する必要があります。

SBus の例

SPARC システムの SBus 上の DMA エンジンには、次の属性があります。

  • 0xFF000000 から 0xFFFFFFFF までのアドレスにのみアクセス

  • 32 ビットの DMA カウンタレジスタ

  • バイト整列された転送を処理できる

  • 1 バイト、2 バイト、および 4 バイトのバーストサイズをサポート

  • 効果的な最低転送サイズが 1 バイト

  • 32 ビットのアドレスレジスタ

  • scatter/gather リストなし

  • セクターのみ (ディスクなど) での操作

SPARC システムの SBus 上の DMA エンジンには、次の属性構造体があります。

static ddi_dma_attr_t attributes = {
    DMA_ATTR_V0,   /* Version number */
    0xFF000000,    /* low address */
    0xFFFFFFFF,    /* high address */
    0xFFFFFFFF,    /* counter register max */
    1,             /* byte alignment */
    0x7,           /* burst sizes: 0x1 | 0x2 | 0x4 */
    0x1,           /* minimum transfer size */
    0xFFFFFFFF,    /* max transfer size */
    0xFFFFFFFF,    /* address register max */
    1,             /* no scatter-gather */
    512,           /* device operates on sectors */
    0,             /* attr flag: set to 0 */
};

ISA バスの例

x86 システムの ISA バス上の DMA エンジンには、次の属性があります。

  • 最初の 16M バイトのメモリーにのみアクセス

  • 1 回の DMA 転送で 1M バイト境界を越えることはできない

  • 16 ビットのカウンタレジスタ

  • バイト整列された転送を処理できる

  • 1 バイト、2 バイト、および 4 バイトのバーストサイズをサポート

  • 効果的な最低転送サイズが 1 バイト

  • 17 以下の scatter/gather 転送を保持できる

  • セクターのみ (ディスクなど) での操作

x86 システムの ISA バス上の DMA エンジンには、次の属性構造体があります。

static ddi_dma_attr_t attributes = {
    DMA_ATTR_V0,   /* Version number */
    0x00000000,    /* low address */
    0x00FFFFFF,    /* high address */
    0xFFFF,        /* counter register max */
    1,             /* byte alignment */
    0x7,           /* burst sizes */
    0x1,           /* minimum transfer size */
    0xFFFFFFFF,    /* max transfer size */
    0x000FFFFF,    /* address register max */
    17,            /* scatter-gather */
    512,           /* device operates on sectors */
    0,             /* attr flag: set to 0 */
};