高度な検索
Developer Connection
Member Login ログイン | ご入会 ADC連絡先

Technote 1018

Understanding the SerialDMA Driver


内容

SerialDMAドライバについて

SerialDMAドライバを使用する

SerialDMAドライバリファレンス

その他の詳細な情報について
のTechnoteは、Macintosh DMA Serial Driver(SerialDMA 2.0の名でも知られています)について述べるものです。SerialDMAドライバは、Macintoshのシリアル・デバイス・ドライバの標準セット(これらは、しばしば.AIn、.AOut、.BInならびに.BOutというドライバ名で参照されます)を代替するものです。SerialDMAは、標準のZ8530シリアル通信コントローラの機能を持つDMAチャネルを搭載したMacintoshでのみ利用可能です。
すべての試行は、DMA操作をサポートしていない従来形式のMacintoshシリアルドライバとの互換性を確保するように行われました。少々動作が異なる部分が何点かありますが、主な相違点は以下の通りです。
  • シリアルのスループットの大幅な改善
  • 長い間存在したバグのフィックス
  • いくつかの機能追加
SerialDMAドライバがその「生涯」において施されたアーキテクチャ上の変更は非常に大きいので、それがどのように進化してきたかを理解することは重要です。このTechnoteは、主に第二世代のSerialDMAドライバについて述べ、第一世代のドライバに関してはその文脈の中で触れます。
本Technoteの読者は、Macintoshのデバイスドライバの概要を、また、従来形式のMacintoshシリアルドライバの詳細を理解している必要があります。それらに関しては、Inside Macintosh : Devices第1章第7章をご覧ください。


SerialDMAドライバについて

Macintosh Centris 660AVからPower Macintosh 8100/110に至るまで(1993年から1994年まで)の、DMA機能を有するMacintoshに搭載されていたシステムソフトウェアに含まれていたSerialDMAは、Appleの第一世代のDMA(対応)シリアルドライバでした。このドライバは、アーキテクチャ上の欠陥に起因する問題を何点か抱えていました。その欠陥は、主に待ち時間の増加(latency problem)として表面化しました。この問題は、ソフトウェア・ハンドシェイキングと特定の種類のリード・ライト操作に影響をおよぼしました。
SerialDMAのオリジナル版は、Serial Driverバージョン8として識別可能です。Appleといくつかのサードパーティが気づいたように、バージョン8はある種のアプリケーションには適さないことがありました。
その問題に答え、Appleは第二世代のSerialDMAドライバ(バージョン9)を提供しました。これは、最初のバージョンの設計上の欠陥を修正し、従来形式のシリアルドライバとのより高い互換性を可能な限りの範囲で確保し、また、DMAハードウェアの潜在力をフルに発揮するようにパフォーマンスを最適化したものです。このアーキテクチャの変更は、
  • 68K版におけるメモリ使用量の大幅な減少(30%以上減少)
  • Power Macintoshにおけるネイティブコードの実行
  • 信頼性の大幅な向上
  • Read要求とXOn/XOffハンドシェイク・キャラクタに対するレスポンスの向上(minimal latency in response)
といった点に影響を及ぼしています。
SerialDMAドライバの第二世代の開発にあたっては、最優先すべき3つのゴールが設定されました。それらのゴールには、SerialDMAのオリジナル版開発時から引き継がれているものもありますが、カスタマーからのフィードバックをもとに、その後のリリースにおいてそれぞれのゴールの比重とそれらの優先順位を全面的に再評価を行いました。

ゴール#1:互換性
いくつかのバグがフィックスされていることとスループットがはるかに向上している点を除くと、SerialDMA 2.0と従来のシリアルドライバを見分けることはほとんど不可能といってよいでしょう。DMAコントローラによりデータが転送される際のSCCのプログラミングが少々異なり、その結果、標準の送信/受信割り込みハンドラはほとんどの場合起動されません。しかしながら、従来のSCC割り込みハンドラAPIは完全にサポートされています。ドライバをオープンするときにシリアルドライバのSCC割り込みハンドラが置き換えられることに依存しているソフトウェアは、期待通りの動作をしなくなるでしょう。DMA割り込みハンドラのインタフェースは、Apple Computerにプライベートです。
一方、完了ルーチンは、遅延タスク時ではなくマスクされた割り込みでコールされています。これにより、クライアントソフトウェアがおかしな動作をするという互換性の問題の原因が排除されます。
非同期的なI/O要求を行っている間、ドライバのクライアントはパラメータブロックioActCountフィールドがインクリメントされることを仮定することはできません。というのも、プロセッサはデータ転送になんら関与しないからです。

ゴール#2:応答性
第一世代のドライバの最も重大な欠陥は、XOn/XOffキャラクタを受信したまさにその時点や、Read要求が完了したその時点で割り込みを発生するようにDMAコントローラがプログラムされていなかったことでした。そのかわりに、そのような事象に応答するまでのタイムアウト時間(timeout latency)が半ばカスタマイズ可能でした。その結果、割り込み待ち時間に対する高い許容性を得られはしたものの、スループットよりも応答時間がより重要なクライアントのパフォーマンスの著しい低下という代償を払うことになりました。
第二世代のドライバは、応答性に関する要求と待ち時間に対する許容性をより高いレベルで妥協させるために、洗練されたDMAチャネル管理を実装しています。その応答性を従来のシリアルドライバと判別することは、もはや不可能でしょう。レイテンシーに対する許容性もおそらく充分なはずです。

ゴール#3:パフォーマンス
データ送信のスループットは従来もほぼ最適化されていましたが、第二世代のドライバでは、より洗練されたDMAチャネル管理の結果、いくつかの部分の実装にともない多少改善されています。
データ受信のバンド幅には、特別な配慮がされました。DMAの受信チャネルの可用性(receive DMA channel availalability)は、ドライバ・クライアントに対する迅速な対応性との両立を考慮し、可能な限り高いレベルで保たれています。チャネルの正確な可用性特性(exact channel availability characteristics)はDMAコントローラに依存しますが、その可能性(possibility)は非常に小さいためDMAコントローラはデータ転送量を消費し尽くしてしまいSCCのオーバーランを引き起こしてしまうでしょう。
第二世代のドライバでは、そのメモリのバンド幅とシステムの典型的な割り込み待ち時間により、例外的な事象が利用可能なDMA資源を消費せず、また、クライアントがドライバを効果的は方法で操作している限り、最大230.4K bpsのデータストリームをサポートすることが可能になりました。新たに追加されたControlコードを使用することにより、クライアントは困難でリスクの高いハッキングや回避策を講じることなく簡単に通信速度を115.2Kあるいは230.4K bpsに設定することが可能です。

SerialDMAドライバを使用する

ある機能がシリアルドライバに存在するかどうかを調べる際に、その機能に対応するControlコールやStatusコールを発行してその結果をチェックするというのは、通常は正しい方法です。もしその機能がサポートされていなければ、そのコールはcontrolErrあるいはstatusErrを返します。ドライバーのバージョンをもとに判断を下すという方法は、特定のバージョンのドライバの一般的な特性があらかじめ判明している場合にのみ適しています。バージョン番号を変更せずにシリアルドライバを改訂することは可能であり、また、そうされるであろうことから、シリアルドライバの機能をそのバージョン番号から判断することは難しいのです。しかしながら、第一世代のSerialDMAドライバはすでに旧式(obsolete)であり、今後メンテナンスされないことをAppleは保証します。
開発を目的とした場合、システムにインストールされているドライバのバージョンをチェックするのに最も簡単で迅速な方法は、MacsBugのdrvr dcmdを使用することです。このdcmdはシステムにインストールされているすべてのドライバを、バージョン番号が付加されている場合にはそれも含めて表示します。

新たに追加された機能
SerialDMAをサポートしているマシンに搭載されているハイパフォーマンスなDMAコントローラにより、従来よりも高いシリアルデータ転送速度が実現可能になりました。拡張されたシリアルドライバのAPIを注意深く使用し、ドライバのパフォーマンスを阻害する要因を理解することにより、従来の限界である57,600 bpsを超えた速度での接続が実現可能です。28,800 bps V.34モデムに対して230.4K bpsのDTE速度での接続を維持することさえも可能でしょう。
クライアントがSerialDMAドライバのパフォーマンスとその潜在的なスループットにどのように影響を与えるかに関しては、「その他の詳細な情報について」のセクションをご覧ください。

第一世代のドライバを識別するには
第一世代のSerialDMAドライバの有するバグやその応答時間が問題となるようなアプリケーションの場合、ドライバが第一世代のものかどうかをプログラム的に識別することは有用でしょう。この場合、使用するドライバがDMA対応かどうかではなく、ドライバの実装そのものが問題となることに注意してください。論理的な帰結として、チェックの方法は当該ドライバがDMAを利用しているかどうかではなく、ドライバが第一世代のDMAドライバかどうかということになるのです。
第一世代のドライバは、2つの方法のうちのどちらかで識別することができるでしょう。クライアントがドライバのバージョンを取得するには、シリアルドライバに対してcsCode = 9のStatusコールを発行します。第一世代のドライバはcsParamの最初のバイトに8を返します。あるいは、csCodeに17987をセットしてStatusコールを発行し、その結果を調べるという方法もあります。シリアルドライバの他のバージョンは当該csCodeを実装していないので、このバージョンのドライバだけがnoErrを返します(その他のバージョンは、デフォルトでcontrolErrを返します)。第一世代のSerialDMAドライバに特有のこの特殊なControlコールは、DMAのタイムアウト時間(timeout latency)を1〜65,535 Tickの間でカスタマイズするためのものでした。タイムアウト時間はControlコールの際にcsParamワードの最初の16ビットに指定しなければなりません。その値として1を渡すことにより、やや効率は落ちますが、安全でありかつ最高のパフォーマンスを発揮します。
註:第一世代のドライバを使用する場合でもこの特殊なcsCodeを使用することにより、シリアルドライバの応答時間に敏感なアプリケーションが動作する可能性があります。しかしながら、現在では第二世代のドライバが利用可能なので、このハックはお薦めできるものではありません。

第二世代のドライバを識別するには
もちろん理想を言えば、すべてのバージョンのシリアルドライバは相互に互換であるべきです。これはまた、バージョン間の判別が実質的に不可能であることを意味します。SerialDMA 2.0における互換性のゴールは、「従来のDMA対応ではないシリアルドライバや、あるいはDMA対応シリアルドライバの第一世代との差にだれもが気づかないこと」というように明確に定められていました。しかし何らかの理由により第二世代のSerialDMAドライバを識別したい場合、それを調べるための直接的な方法は、ドライバのバージョン番号を確認することです。先にも述べたように、StatusコールにcsCode = 9を渡しその結果を得ることで可能です。第二世代のドライバは、バージョン番号として9を返します。
第二世代のSerialDMAは、115.2K bpsモードあるいは230.4K bpsモードを起動するためのcsCodeをサポートした最初のドライバです。したがって、その方法でドライバのバージョンを調べることも可能であると、ある意味では言えるかもしれません。しかし、将来的にその他のバージョンのドライバがそれらのコールをサポートする可能性もあります。したがって、それらの機能を使用したい場合には、ドライバのバージョンに関係なくそのControlコールを発行してください。

重要:シリアルドライバのバージョン番号そのものにより機能を仮定しないでください。それぞれのバージョン番号は本質的にはドライバのアーキテクチャを識別するためのものであり、バージョン番号を時系列的に付加する方法とは方針が異なります。例えば、バージョン10のドライバはSerialDMAとまったく異なる設計となるかもしれませんし、また、DMAをサポートするか等についても同様です。

SerialDMAドライバリファレンス

このセクションでは、従来の非DMAドライバの機能に加えてSerialDMAに新たに追加されたコントロールコードについて述べます。

ローレベル・ルーチン
SerialDMAドライバは、csCode 15をサポートしています。これは、MIDIの外部クロック機能をサポートするために設計されました。このcsCodeは以前もMacintosh IIfx、Quadra 900そしてQuadra 950のIOPシリアルドライバでサポートされていましたが、すでに出荷された大多数のマシンでは実装されていなかった機能なので、公式には記述されていませんでした。
SerialDMAドライバは、新たに2つのcsCode、115と230をサポートしています。これらのcsCodeをControlルーチンに渡すことにより、ドライバを高速モードにセットすることができます。これらのcsCodeは115.2Kボーおよび230.4Kボーの転送速度をサポートします。これらのコールを実行する正しいタイミングは、その他の(より低速な)ボーレートを指定してSerResetをコールした後です。というのも、SerResetは数々の設定作業を行いますが、その際にボーレートはSCCのボーレート・ジェネレータが提供する機能であると仮定しているからです。上で述べたような高速通信を実現するには、ボーレート・ジェネレータをバイパスし、標準的な3.672 MHzのSCCクロックと非常に限られた分周値(rate divisor)を使用しなければなりません。これらのcsCodeは、ボーレート・ジェネレータをバイパスし、高速通信を実現するためにクロックの分周値を設定する作業を行うのです。
註:もしSCCがRTxCの内部クロックを使用せずにGPiラインから外部クロックを受けている場合、これら2つのcsCodeは、ボーレートをGPiクロック値を分周値で除算した値に設定する働きをします(selecting a baud rate as a fraction of the GPi clock rate)。この場合、csCode 115のときは分周値は32に、また、csCode 230のときは分周値は16になります。

MIDI対応クロックの設定 [control code 15]

csCode = 15 csParam = byte

このコールは、シリアルドライバを準MIDIモード(quasi-MIDI mode)に設定するために設計されました。動作はSerResetに似ていますが、シリアルドライバの設定を8データビット、1ストップビットのままにします。また、ハードウェア・ハンドシェイキングはオフになり、CTSピンから外部クロックが供給される必要があります。パラメータとして渡されるバイトは、以下のテーブルのように、外部クロック周波数がデータ速度を上回っている度合いを示すファクタです。その際に乗数(rate multiplier)として渡されるバイトの上位2ビットを使ってエンコードされています。その他のビットはリザーブされており、ゼロでなければなりません。

Table 1 csCode 15における乗数のエンコーディング
エンコーディング 乗数
0x00 x 1
0x40 x 16 250K baud 8x MIDI rate @ 4 MHz
0x80 x 32 125K baud 4x MIDI rate @ 4 MHz
0xC0 x 64 31.25K baud standard MIDI rate @ 2 MHz


115.2Kボーの設定 [control code 115]

csCode = 115

このコールは高速モデム用に設計されました。正常に通信を行うには、受信チャネルにDMAハードウェアが必要です。このコールはcsCode = 16を指定して行うクロック周波数選択機能に似ていますが、乗数に32を指定して3.672 MHzの内部RTxCクロックソースからボーレート用クロックを直接取得するように、シリアルドライバに強制します。その結果、送信及び受信のボーレートは定格で(nominally)115.2Kボーになります。その他の設定パラメータは影響を受けません。

230.4Kボーの設定 [control code 230]

csCode = 230

このコールは高速モデム用に設計されました。正常に通信を行うには、受信チャネルにDMAハードウェアが必要です。このコールはcsCode = 16を指定して行うクロック周波数選択機能に似ていますが、乗数に16を指定して3.672 MHzの内部RTxCクロックソースからボーレート用クロックを直接取得するように、シリアルドライバに強制します。その結果、送信及び受信のボーレートは定格で(nominally)230.4Kボーになります。その他の設定パラメータは影響を受けません。このドライバが出しうる最高速を実際に発揮するには、クライアントソフトウェアには様々な努力が必要になります。シリアルDMAのデータ受信の利点を活かすためには、クライアント・レイヤーの効率が非常にクリティカルです。シリアルドライバAPIを不用意に、あるいは非効率的に使用すると、システムのパフォーマンスが低下し、希望の転送速度の維持ができなくなる原因になります。後述の「パフォーマンスに関する考察」をご一読ください。

その他の詳細な情報について

第二世代のSerialDMAドライバは、基本的には従来のシリアルドライバ(これは68Kのアセンブリ言語で書かれていました)をC言語で書き直したものですが、68Kコードから成るDevice Managerとのバインドのために、68Kアセンブリ言語によるグルーコード(Power Macintoshネイティブコードのドライバの場合はMixed Modeグルーコード)も一部存在します。SCCは、ドライバに対して外部状況あるいはステータスの変化(external/status changes)、あるいは特殊な受信状況の発生(special receive conditions)を知らせはしますが、送信時および受信時の割り込みの発生は行いません。通常のデータ転送はすべてDMAにより行われ、システムと転送経過の同期はDMA割り込みにより行われます。
Z8530シリアル通信コントローラの抽象化は行われていません。シリアルドライバはこのいささか古びた(legacy)ハードウェアに密接に依存しています。しかしながら、ドライバの大部分は特定のDMAコントローラの細部からは比較的独立しています。ドライバがオープンされるときにインストールされるプリミティブ・ベクタはわずかであり、すべてのDMA操作はSerialDMAドライバのメイン部でデバイスに依存しない方法により処理されます。
以下は、このドライバのDMAモデルに対する柔軟さを知るための例になるのですが、Quadra 840AVのDMAコントローラは任意の大きさのユーザ定義の線形バッファを2つ必要とし、それぞれのバッファのトランスファ・カウントが0になると自動的に他方に切り替わります(automatically ping-pongs between them)。Power Macintosh 8100はシステムがDMA用循環バッファ(circular DMA buffer)をひとつ有しており、そのトランスファ・カウントが0になると割り込みを発生させます。また、その割り込みが処理を待っている間にデータの転送を続けることもオプションで可能です。Power Macintosh 9500は、任意の個数のバッファをサポートする半インテリジェントなDMAコマンドプロセッサを使用しています。
SerialDMAは、簡潔で抽象化されたプリミティブを8つ、また、それぞれのDMAコントローラに特有の割り込みハンドラを3つあるいは4つ使用することにより、それらのDMAモデルを容易にサポートしています。

PowerPCネイティブコードによる実装
Power Macintosh用に、SerialDMAドライバはPowerPCネイティブコードにコンパイルされています。これは、MarconiあるいはCopland用のCFM形式のドライバではなく、PowerPCインストラクションから成る従来形式のMacintoshドライバ('DRVR'形式)です。このドライバを68KアーキテクチャのDevice Managerとバインドするために、ドライバヘッダ中のオフセットはMixed Modeのルーチン・デスクリプタを指しています。すべてのSCCおよびDMA割り込みハンドラもPowerPCネイティブであり、割り込みディスパッチテーブルには対応するルーチン・デスクリプタへのポインタがインストールされます。IODoneやLAP ManagerのポートB調停ルーチン等の68Kルーチンのコールは、それらに対応するProcInfoCallUniversalProcを通じて行われます。
PowerPCネイティブのSerialDMAはMixed Modeスイッチによるオーバーヘッドという高価な代償をともないますが、DMAがサスペンドされているときや割り込みを禁止して大きなデータパケットを転送しているときなど、特定のクリティカルなコードシーケンスをPowerPCネイティブコードで実行することにより、高パフォーマンスの実現が困難な状況の大半においても、全体としては好結果をもたらすのです。
PowerPCネイティブのドライバは、'nsrd'というタイプのコードリソースとして格納されており、Mixed Modeにより'SERD'リソースと同じ呼び出し規約を実装しています。'SERD'リソースは68Kマシン用であり、また、'nsrd'リソースはPowerPCマシン専用です。

割り込み
Macintoshの従来形式のシリアルドライバは、キャラクタがSCCのレシーバに到着、あるいは、SCCトランスミッタから送信されるたびに、また、CTS入力の状態が変化したりブレーク状態が検出されたときにシステムが発行する割り込みに対応することにより機能していました。この設計では、ドライバはSCCで発生するすべての事象に対してシステムの割り込み待ち時間分の遅れだけで対応することができるため、非常に高い応答性を実現することができます。一方、システムの割り込み待ち時間がドライバのデータ・スループットの上限を制限してしまうため、従来形式のシリアルドライバにとってこれは非常に大きな制約ともなります。例えば、230.4K bpsの転送速度では、キャラクタは43.4μ秒、あるいは1085マシンサイクル(25 MHzで動作するCPUの場合)ごとにSCCに到着します。システムの割り込みハンドラとドライバのドライバ・サービス・ルーチンの往復には数百マシンサイクルを要するため、このように高速なデータ転送ではCPUのバンド幅の大半を消費してしまい、その結果、システムのパフォーマンスを著しく低下させるかあるいはシステムの能力を超えてしまい、それによりデータの損失を招くことは明らかです。

DMAエンジンは、データをSCCからメモリに移動する際のCPUの負担を軽減します。最良の場合、データのスループットはシステムの割り込み待ち時間ではなくメモリシステムのバンド幅により制約を受けます。通常、メモリシステムのバンド幅は、一般的なシリアルI/Oハードウェアが達成しうる速度よりもはるかに高速です。DMAハードウェアは、前もって指定された量のキャラクタが転送された時点で割り込みを発生します。非DMAモデルと比較した場合、DMA転送による恩恵はDMA転送量の平均サイズに比例して増大するということが直感的に理解できます。CPUに干渉することなく個々のキャラクタを転送することにより貴重なプロセッサ時間が節約され、その他の割り込み駆動による処理(interrupt-driven process)のレスポンスが向上します。

DMAによる恩恵を低下させるひとつの要因は、1キャラクタ毎に実行されるSCC I/O割り込みハンドラに比べてDMA割り込みハンドラが複雑の度を増していることです。先に述べたDMAの利点を活かすことによりパフォーマンス上の障害を克服することは重要です。それには、一般的に言えば、汎用的に設計されたDMAブロックハンドラのオーバーヘッドは1キャラクタ毎に実行されるハンドラに比べて大きいため、そのオーバーヘッドが問題にならないようにするためには一回のDMA転送で何キャラクタを転送すればよいのかという平均値を算出することのみが必要になります。しかしながら、DMAの利点を活かさない方法でDMAシリアルドライバを操作すると、割り込み駆動のシリアルドライバよりもオーバーヘッドが大きくなるということは、理解しておく必要があります。パフォーマンスがクリティカルな場合やデータ・スループットが従来のMacintoshシリアルI/Oの水準よりも高速な場合には、そのような非効率的な使用法は避けねばなりません。

先にも述べたように、DMAシリアルドライバではDMAブロック転送が終了した時点でハードウェアが割り込みを発生します。また、ステータス割り込みに対しては従来のMacintoshシリアルドライバとまったく同じ方法で応答するので、CTS入力の状態が変わる都度、およびブレーク状況が検出されたときに割り込みはサービスされねばなりません。さらに、さまざまなシリアルドライバAPIコールは、ペンディングされているI/Oリクエストやハンドシェイキングのスレッショルド等とDMAエンジンを同期させるために、ドライバの割り込みハンドラを起動します。それらのAPIコールにより暗黙のうちに発生する割り込みは、MacintoshシリアルドライバAPIでサポートされている特定の事象に対する応答性にほぼ近いことが要求されます。

パフォーマンスに関する考察
カスタマーからのフィードバックでは、ブロック転送終了時に割り込みが発生するDMAシリアルドライバを使うとき、キャラクタ毎に割り込みが発生する(an interrupt-per-character)シリアルドライバで得られたのと同じ応答性をどのように実現するかということに、最も高い関心が寄せられています。そのためには、比較的洗練されたDMA受信チャネルの管理と数々のドライバAPIコールに対応し暗黙のうちに発生する割り込みが必要となります。DMAの割り込みが発生する度に、あるいはその他のさまざまな状況で、次の割り込みを最適なタイミングで発生させるために、選択されているハンドシェイキング・モードやRead要求、さらにはバッファサイズをもとに新たなDMA転送量が計算されます。このドキュメントではその計算法の詳細については述べませんが、その計算を行っている最中にDMA受信チャネルは休止(inactive)したままになるため、計算時間を最短にするために細心の注意が払われています。また、クライアントのシリアルドライバの使用法がドライバのDMAチャネル管理におよぼす影響が問題になってきます。

XOn/XOffによるアウトプット・ハンドシェイキングをDMAシリアルドライバでサポートすることは、特に大きな代償をともないます。というのも、XOnおよびXOffキャラクタの受信に対し容認できる程度の応答時間を保証するために、ドライバはDMAの利点の大半を使用せずに、非DMAシリアルドライバのように1キャラクタ受信する毎に割り込みを発生するからなのです。この場合、DMA割り込みハンドラは標準のキャラクタ受信割り込みハンドラよりも複雑で実行時間が長いということがパフォーマンスに影響を与えます。それにもかかわらず、DMAドライバはやや古い方式である(old-fashioned)ポーリング・プロシージャをサポートしていないので、結局のところ1キャラクタ毎にDMA割り込みハンドラを使用することのみが唯一採りうる方策です。結果として、高速通信時にはXOn/XOffハンドシェイキングは推奨できません(大まかな目安として、57,600 bpsはおそらくソフトウェア・ハンドシェイキングを有効に行うには速すぎるでしょう)。
そんなに手ひどくというわけではないですが、いかなるタイプのインプット・ハンドシェイキングも、バッファのスレッショルドに達したときに割り込みを発生させフロー制御をアサートするので、DMA転送量に(および使用可能なDMA資源にも)制限を与えます。

最初に設定されたDMA転送量に関わらず、受信側に特殊な状況が発生した場合には、シリアルドライバの仕様に従いデータストリームからcorruptしたキャラクタを取り出すために、現在アクティブなDMA転送は中止されます(これによっても、利用可能なDMA資源が制限されます)。ブレークシーケンスの受信も、DMA資源を一時的に制限しますし、また、ブレークがアサートされている間受信チャネルのDMAがサスペンドされます。

DMA転送量はハンドシェイキング・モード、バッファサイズ、Read要求サイズやその他の要因に依存するので、数々のControlコールやStatusコールの実行によりDMAは一時的にストップし、新しいパラメータでリスタートします。この動作はある程度のオーバーヘッドをともなうのですが、シリアルドライバAPIをより洗練された方法で使用することにより回避可能なことがしばしばなのです。例えば、SerGetBufを頻繁にコールしてポーリングするよりも、入力が予想できる程度のデータ量を指定して非同期のRead要求を一回発行しておき、もしデータの入力が行われなかった場合にはしばらくたった後にKillIOをコールしてタイムアウトにするという方法を採る方がはるかに効率的です。SCCによりデータ転送が行われない間Read要求をペンディングしておくことによりオーバーヘッドが発生することはまったくありませんが、ループ中でSerGetBufを使用してポーリングを行うことによるオーバーヘッドは非常に大きいのです。これは、DMAおよび非DMAシリアルドライバの双方に当てはまります。

パフォーマンスを大きく低下させるもう一つの要因は、一般的に使われている、少量のRead要求を連続的に行うアルゴリズムです。DMAの目的は、比較的大きな量のデータを高速に転送することなので、1キャラクタ読み込むRead要求(one-character read request)を頻繁にposeすることは、非常に非生産的なのです。Read要求が完了するたびに割り込みが発生しますし、また、Read要求が発行されるたびに暗黙の割り込みが発生し、DMAエンジンとクライアントが発行したRead要求のデータカウントを一致させようとします。高い通信速度を維持するためのカギは、システムにより発生する割り込みの回数を制限し、ブロックデータを処理する際のスケールを節約することにあるのです。

パフォーマンスの最適化に関するヒント
パフォーマンスを最適化するためのヒントを、以下に示します。

・高速通信を行うときには、ドライバからのデータアウトプットの制御にXOn/XOffハンドシェイキングを使用することは避けてください。XOn/XOffハンドシェイキングを行うことにより、受信チャネルのDMAはまったく役に立たなくなり、最悪のパフォーマンスのシナリオをもたらします。

・ドライバのステータスやバッファの状態をチェックするためにシリアルドライバを繰り返しポーリングすることは避けてください。このアプローチはシンプルではありますが、まったく同期的な操作でありDMAシリアルドライバにとっては特に非効率的です。

・トランザクション中に転送が予想されるデータの全容量に対して、可能な限り非同期のリクエストを使用してください。また、そのトランザクションを一回で処理してください。データが予定通りに送られてこなかった場合にはKillIOを発行してトランザクションをタイムアウトさせることができますし、また、そのようにすべきです。一方で、ペンディングの非同期リクエストが残っていない限りは、KillIOコマンドを発行する必要はありません。

・データが入力される可能性がある場合、シリアルドライバに対してドライバ自身のバッファ(デフォルト、あるいはSerSetBufで指定可能)を使用するよう要求することは避け、非同期のRead要求をペンディングさせておくようにしてください。クライアントのバッファは、スレッショルドのチェックの必要がないため効率がよいのです。

・もし完了ルーチン中で複雑な処理(例えば、セマフォのセットやクリア以上のこと)や次のI/Oの発行(chained I/O)を行っているのであれば、できるだけ早く制御をドライバの割り込みハンドラに返しその他の割り込みを処理できるようシステムを解放するために、そのコードを遅延タスク中で実行することを検討してください。ドライバにとっては、シリアルI/Oの完了ルーチンは遅延タスクとして実行されるのが最も好ましいのですが、シリアルドライバをそのように実装することは、VBLタスクやTime Managerタスク等からドライバを同期的にコールしているサードパーティ製ソフトウェアの互換性の問題につながるのです。