I/Oアダプタが存在可能である。PCIバスをサポートして、ダイレクトマップDMAまたはスキャッタギャザマップDMAのために使用される3つのDMAウィンドウを持つ。接続されるすべてのPCIバスにおいて共有される。スキャッタギャザページテーブルのためにホストRAMを使わない。PCIバスで共有する必要がある。DMAページテーブルのアクセスにおけるレーテンシが非常に大きくなるためである。PCI実装の上では明示的なスキャッタ・ギャザTLBの無効化は必要でない。PCIスロットだけを持っていてイーサネットI/Oだけのために単独で使用される。直接にアクセスすることができない。本質的には、これはDMAバウンスのハードウェアによる実装である。これは、A12システムの対象アプリケーション(クロスバー上でMPI[注12]を介して通信する並列計算方式アプリケーション)を考慮すれば、アーキテクチャ上の制約であるとは言えない。アーキテクチャーは、「ウマ(horse)」(中心バックプレーン)と2つの「鞍(saddles)」(バックプレーンの両側の主PCIバスアダプタ)で構成される。バスアダプタを持つことも可能である。DMAウィンドウを持つ。PCIホストバスアダプタはソフトウェア的に互換性がある。持つのでウィンドウ変換は必要でない。24ビットアドレス制約があることとスキャッタギャザマップDMAを持たないことにより、ISAバスにおいてはDMAバウンスについて適切な処理を行う必要がある。カーネル上ではこれらのチップセットは共通のデバイスドライバを使用している。システムにおけるシステムバスの名前である。I/Oバスはクロスバーであり、並列プロセッサにおいて他のノードと通信するために使われる。並列プログラムにおいてデータおよび制御を交換するための標準化されたAPIである。DMAタグはよく似ている。13の関数ポインタを持つ。DMAタグと、DMA関数の低レベル実装によって解釈される不透明型(opaque)クッキーを取得するための関数のポインタを持つ。不透明(opaque)型クッキーは、チップセットの静的に割り当てられた状態情報へのポインタである。スキャッタギャザマップDMAを実現するための一つのDMAウィンドウの状態情報すべてを保持する。DMAウィンドウのベースアドレスである。インターフェースのすべての実装においてほぼ標準となっている慣行である)。特有なクセ(quirk)に固有の付加的な状態変数を含む。DMAマップは、スキャッタギャザマップDMAに関連したいくつかの状態変数を含む。DMAマップは、マップ固有のクッキーにポインタを含む。DMAバウンスのための状態情報を保持する。この状態情報は独立したクッキーにおいて記憶される。Alpha上におけるスキャッタギャザマップDMAと比較してi386上におけるDMAバウンスはあまり共通のものとは言えないからである。スキャッタギャザマップDMAを実行しなければならないからである。DMAセグメント構造体は、インターフェースによって定義されるパブリックメンバだけを含む。[注13]エクステントマップは任意の数の範囲を管理するデータ構造であり、いくつかのリソース割り当てのためのプリミティブを提供する。各種のカーネルサブシステムによって使われる汎用エクステントマップマネージャを持つ。実装は、ともにコード再利用のために単純な継承方式を使う。DMAタグを生成することで実現されている。タグが生成されるとき、その階層における固有な操作が要求される関数ポインタのメンバに、親階層は自身のための手順(関数など)を挿入する。固有操作を要求しない手順に対してはその関数ポインタは共通コードへのポインタで初期化される。コードは、チップセット固有コード、共通ダイレクトマップ操作を記述するコード、共通スキャッタギャザ操作を記述するコード、そしてダイレクトマップおよびスキャッタギャザマップDMAに共通な操作を記述するコード、の4つの基本的なカテゴリーに分類される。共通関数の一部は、タグの関数スイッチを通して直接呼び出されることはない。それらの関数は補助的な関数であり、チップセットフロントエンドによって使用されるためだけに存在する。DMAロード関数がある。これらの関数は、インターフェース定義の呼び出し手順と同じ引数全部に加えて、DMAウィンドウのベースDMAアドレスという特別な引数を取る。3つの基本的なカテゴリーに分類される。DMAタグの関数スイッチから直接呼び出すことができる。DMA操作は用意されない。DMAバウンスのためのサポートを提供する。関数呼び出しを共通の操作にリダイレクトするだけである。対する特別な要求事項を伴ってサポートされる唯一のバスである。これは、システムの将来バージョンでは変わるかもしれない。カーネルのオートコンフィギュレーションシステムでは、デバイスツリーにおけるノード(デバイス)階層順探索が使われる。この手順は、機種依存部のコードが機種非依存のオートコンフィギュレーションフレームワークに対して大元となるバスを検出したことを通知することにより起動される。呼ばれる大元のバスは仮想的なデバイスであり、システムのいずれの物理的なバスとも直接一致はしない。ためのデバイスドライバは、機種依存部のコードで実装される。このドライバの役割は、1つもしくは2つ以上の主I/Oバス構成することである。階層においても主I/Oバスであると見なされる。ドライバはそのチップセットの名前を検出することでそのチップセットを設定(configration)する。チップセットのデバイスドライバがアタッチされるときに、そのDMAウィンドウやデータ構造は初期化される。バスドライバは、PCIバス上のそれぞれのデバイスその他を順に検出し設定していく。デバイスドライバに渡される。DMAタグを渡していく。PCIバスドライバが異なるバスタイプ(例えばEISAやISA)のブリッジに遭遇した場合は、機械依存コードによる介入が必要である。DMAタグを要求する場合がある。ドライバーは、機種依存部のコードにおいて実装される。ドライバを機種非依存部のコードとして実装することも可能ではあるが、セカンダリバスは特殊な機種依存となる割り込み設定および割り当てを要求する可能性があるため、そのような実装は行われていない。仮に機種依存のバス遷移詳細を扱うコールバックのすべてを実装したとしても、それにより共有できるコードの量はほとんどその労力に見合わない。バスドライバによって検出された特定のハードウェアデバイスとデバイスドライバが関連づけられる際に、デバイスの初期化およびアクセスに必要ないくつかの情報が与えられる。DMA動作を要求するのであれば、ドライバはこのタグを保持しておく必要がある。インターフェースの呼び出しにおいて使用される。主I/Oバスの構成方法が大きく異なっている。ISAバスを中心にして設計されてきた。非常に類似したものになっている。I/Oマップ[注15]およびメモリマップされた空間を持つ。PC上のハードウェアとファームウェアは標準でこれらのバスをマップするため、オペレーティングシステムのソフトウェアによるバスアダプタの初期化は不要である。いずれのバスも主I/Oバスと見なすことが可能である。ドライバは、降順で主I/Oバスを設定する。タグを直接I/Oバスに渡す。バスのコンフィグ中に見つけられない場合に限りこれらのバスをコンフィグしようとする。ブリッジを識別して、それらのブリッジに対してもデバイスツリーにおけるオートコンフィギュレーションノードを割り当てる。バスはこれらのノードに論理的に接続される。DMAタグへ直接アクセスすることができ、それぞれに応じてタグをI/Oバスに渡す。プロセッサ上では特別な命令によってアクセスされる。インターフェースを実装する機種依存部コードの動作を解説する。本来のアプリケーションでないが、非常に理解しやすい例として挙げる。インターフェースの開発において目的としていたアプリケーションは高性能な階層大容量記憶システムであるが、その詳細は非常に複雑なものになる。デバイスドライバの詳細のすべてについてはここでは解説しない。DMAの観点から重要なもののみを解説する。モデルのものがあるとする。4つの組み合わせが存在することになる。それらについて次のような記号を用いて表すことにする。持っていると仮定する。DMAバウンスが必要となるかもしれない。ついてアドレス指定可能であると仮定する。マップの同期の解説においては、特有の個別操作を必要とする場合にのみ解説を行うので注意してもらいたい。CPUのライトバッファの掃き出しを実行する。場合はすべての同期操作では何の操作も行われない。DMA-safeメモリに対する同期操作も同様である。ハードウェア概要カードはバスマスタであり、DMAを通して固定長のコマンドブロックを読み取ることによって動作する。レジスタにコマンドブロックのDMAアドレスを書き込むことで動作を開始する。要素は、カードのDMAエンジンによって使われるソフトウェアスキャッタギャザリストのDMAアドレスである。要素は、それぞれのリストにおけるスキャッタギャザエントリの数である。それぞれのスキャッタギャザエントリは、DMAアドレス、長さ(いずれも32ビットワード)を含む。カードがリクエストを処理する際には、DMAを通してコマンドブロックを読み取り、そしてコマンドブロックを調べ、いずれの動作を行うかを決定する。バイト分だけ読み込む。それからカードは該当する処理エンジンに入力を切り換える。DMA転送するのに用いられる。DESエンジンに向けられ、暗号化または復号化のいずれかのモードに切り替えられる。DMAアドレスが与えられると、すべてのデータが処理されるまで入力-処理-出力のサイクルが開始される。ステータスワードが書き込まれ、ホストに対して割り込みを発生させる。ドライバソフトウェアは、コマンドが正常に完了したどうか確認するためにこのステータスワードを読み取る必要がある。エントリーポイントを提供する。通して出すと、ドライバはそれを作業待ち行列に置く。よって動作をブロックする。カードが現在アイドル状態であれば、ドライバはカードに対して直ちにコマンドを発行する。シグナルを通してユーザーに対しリクエストが完了したことを通知する。作業待ち行列上にさらにジョブが存在する場合は、すべてのジョブがなくなるまで待ち行列から次のジョブが取り出されて開始される。ドライバー初期化ドライバインスタンスが作られる(アタッチされる)とき、ドライバは動作上必要となるデータ構造を作成して初期化する必要がある。データマップはドライバ待ち行列エントリの中に保持されるが、その待ち行列エントリはジョブが渡されるときに作成される。DMA-safeなメモリを割り当てなければならない。3ページのメモリを割り当てる。単純化のためドライバは単一メモリセグメントを要求する。この例におけるすべてのプラットホームおよびバスにおいては、この操作は必要な制約条件に基づいてメモリを割り当てるための仮想記憶システム中の関数を呼ぶだけである。ISA階層自身を呼び出し条件に追加する。それ以外の場合は、単に存在する実メモリ範囲全体を指定する。このメモリの一部分はコマンドブロックのために使われる。2つのスキャッタギャザリスト用に二等分される。呼ぶことでカーネル仮想記憶空間にマップされ、3つの構造体へのカーネルポインタが初期化される。フラグによってキャッシュ禁止ビットがPTEにおいてセットされるようになる。ダイレクトマップされたカーネルセグメントを通してマップされ、カーネル仮想記憶空間を使用する必要はない。DMAマップをロードする。DMAアドレスを(それらのオフセットをメモリのDMAアドレスに加えることで)キャッシュする。pmapモジュールから取り出していき、可能であれば複数のセグメントを一つにまとめていく。ここではメモリはもともと単一のセグメントに割り当てられているので、ロード関数は単一のDMAセグメントにマップする。処理の例ユーザーがすでに暗号用キーをセットし、それを使ってデータバッファを暗号化しようとしていると想定しよう。DMA実行中にデータがページアウトされてしまうのを防ぐためにユーザーのバッファをロックする。1つのジョブ待ち行列エントリが割り当てられ、2つのDMAマップがそのジョブ待ち行列エントリのために作成される。1つは入力バッファ用、もう1つは出力バッファ用である。DMAマップ構造体が割り当てられる。クッキーが割り当てられる。待ち行列エントリが割り当てられたら、それを初期化する必要がある。このプロセスでの最初の処理は、入出力バッファ用DMAマップのロードである。このプロセスは入力バッファと出力バッファとで本質的に同一であるので、ここでは入力バッファのマップに対する動作のみを説明する。下位のコードはユーザーのバッファを走査してそれぞれのページの物理アドレスを取り出す。DMAウィンドウのベースがこのアドレスに加算される。DMAセグメントリストに入れられる。各セグメントが連続である場合はそれらのセグメントは連結される。おいてはほぼ同様のプロセスが行われる。物理アドレスをマップのセグメントリストに入れるのではなく、スキャッタギャザマップDMAアドレス空間が割り当てられ、対応するページテーブルエントリにアドレスが設定される。このプロセスが完了すると、スキャッタギャザマップされた領域の先頭を指す一つのDMAセグメントがマップのセグメントリストに置かれる。16Mバイトの閾値より上位にあるページがないことを確認するために行われる。場合とまったく同じである。DMAバウンスが必要であるとする。バウンスバッファはこの時点で割り当てられる。ここでカーネルは依然としてプロセスコンテキスト上にあるため、この割り当てはブロックされても構わない。クッキーに格納され、バウンスバッファの物理アドレスがマップのセグメントリストに置かれる。次の作業は、転送を待ち行列にに入れる、もしくは転送を開始することである。ここでは簡単な例にとどめるため、他に実行中の転送は存在しないと仮定する。DMAアドレスを用いて制御ブロックを初期化することである。DMAマップのセグメントリストの内容によって初期化される。データ転送の開始をカードに指示する前には、DMAマップを同期する必要がある。マップは、入力バッファマップである。[i386/ISA]の場合は、ここでユーザーのバッファがバウンスバッファにユーザーのアドレス空間からコピーされる[注16]。同期すべき次のマップは、出力バッファマップである。最後に制御マップの同期を行う。この時点でDMA転送処理が開始可能となる。DMAアドレスを書き込むことでカードは動作を開始する。ドライバはユーザー空間にリターンし、プロセスは処理が完了したことを伝えるシグナルを待つ。転送処理が完了すると、カードはホストに対して割り込みを発生させる。ここで割り込みハンドラは、DMAシーケンスを完了させ動作の完了を要求元のプロセスに通知する動作を行う。ここで実行する第一の作業は入力バッファマップの同期である。次に出力バッファマップの同期を行う。場合は、ここで出力バウンスバッファの内容がユーザーのバッファへコピーされる[注17]。最後に、制御マップの同期を行う。DMAマップが同期されたあと、それらのマップをアンロードする必要がある。場合、解放すべきリソースはなく単にマップが無効とマークされるだけである。リソースが解放される。[i386/ISA]の場合、バウンスバッファが解放される。ユーザーのバッファはこれ以降使用されることはないので、バッファはデバイスドライバによりアンロックされる。この時点でプロセスに対しI/Oが完了したことを示すシグナルを出すことができる、最後の作業は、入出力バッファのDMAマップとジョブ待ち行列のエントリの破棄である。[注16]仮想記憶システムに相当な変更を必要としたので、これは現在実装されていない。関数は現在のプロセスのコンテキスト上のみで機能し、バウンスの時点ではそのコンテキスト存在しない可能性があるからである。今後のリリースで登場するだろう。DMAバウンスは現状でもサポートされている。操作の注記と同じ内容が適用される。カーネルに対して導入された。インターフェースを使うように変更されていた)。デバイスのサポートも提供した。コントローラ)をインストールして行われた。実装における些細なバグを一つ修正しただけでデバイスは完全に動作した。新しいインターフェースの適用のためのデバイスドライバの書き換え作業において、書き換え後の各ドライバからは相当量の類似コードが削除可能であるということが明らかになった。削除されたのはソフトウェアスキャッタギャザリストを作成するためのループ処理であった。この処理ループの実装がより効率的で、かつ、複数セグメントの統合をサポートしていることから、ドライバの性能は際だって向上した。DMAを使う大部分の機種非依存のドライバは新しいインターフェースに変換され、さらに他のプラットホームにおいても必要なバックエンドが実装された。結果は非常にすばらしいものであった。テストを実施したほぼすべてのデバイスとプラットホームの組み合わせにおいて、デバイスドライバは追加の修正をすることなく動作した。DMAとは直接関係しない事項である。VMEバスのような、新たな機種非依存のバスオートコンフィギュレーションフレームワークのための道も開いた。VMEデバイスドライバを共有できるようになるだろう。カーネルにおける大きな構造上の利点となることを確認した。要約すると、抽象化は設計時に意図していたとおり「最大限のコード再利用による広範囲のプラットホームサポート手段」を提供した。21072コアロジックチップセットデータシート、1994年11月、DECオーダーナンバーEC-QAEMA-TE。21066アルファAXPマイクロプロセッサデータシート、1994年5月、DECオーダーナンバーEC-N0617-72。21171コアロジックチップセットテクニカルリファレンスマニュアル、1995年9月、DECオーダーナンバーEC-QE18B-TE。A12並列スーパーコンピュータ動作原理、1997年10月、Avalonコンピューターシステム社。本論文に対する更新は定期的に現れるかもしれない。見つけられるであろう[訳注6]。Postscript形式のファイルが得られる。内容は執筆時点から更新されていないようである。Waddellに、本論文を洗練させるためのレビューと私に対する援助に彼らが費やした時間に対して特別な感謝を表したい。Thorpeは、NASAのエイムスリサーチセンターの数値航空宇宙シミュレーション施設のネットワークシステムエンジニアである。彼の専門の関心は、移植性の高いオペレーティングシステム、高速コンピュータネットワーク、そしてネットワークプロトコルの設計と実装を含む。アクティブな参加者である。彼は1993年半ばからNetBSDプロジェクトの貢献者であり、かつてはほとんどすべてのポートを動かしていた。Groupのメンバでもある。Thorpe氏はNASAから離れている。NetBSDのページに戻るtsutsui@ceres.dti.ne.jp。