次の方法で共有


NDIS 散布図/DMA の収集

注意事項

Arm および Arm64 プロセッサに対しては、NDIS ドライバー作成者が NDIS スキャッター/ギャザー DMA の代わりに WDF DMA または WDM DMA を使用することを強く推奨します。

WDF DMA の詳細については、「KMDF ドライバーでの DMA 操作の処理」を参照してください。

WDM DMA の詳細については、ドライバーの入力/出力の管理の の DMA 関連の子トピックを参照してください。

NDIS ミニポート ドライバーは、分散/収集 DMA (SGDMA) メソッドを使用して、NIC とシステム メモリの間でデータを転送できます。 DMA 転送が成功した場合、データの物理アドレスが NIC でサポートされているアドレス範囲にある必要があります。 HAL は、ドライバーが MDL チェーンの物理アドレス一覧を取得するためのメカニズムを提供し、必要に応じて、物理アドレス範囲にデータをダブル バッファーします。

NDIS 6.0 より前の NDIS バージョンでは、ミニポート ドライバーと NDIS での SGDMA のサポートは一部の点で制限されており、特にマルチパケット送信シナリオではうまく機能しません。 NDIS 6.0 SGDMA サポートは、ミニポート ドライバーのシンプルなインターフェイスを提供しながら、これらの制限を克服します。

NDIS SGDMA の歴史

NDIS 6.0 より前の NDIS バージョンでは、NDIS はミニポート ドライバーにパケットを送信する前に、各パケットの散布図収集 (SG) の一覧を取得します。 NDIS は、過剰な断片化が原因で SG リストを取得する元の試行が失敗した場合も処理します。 この場合、NDIS は、連続したバッファーにパケットをダブル バッファーし、再試行します。 HAL では、データの物理アドレスが 32 ビットの最大値を超え、NIC が 64 ビット DMA をサポートしていない場合など、NIC がサポートする物理アドレスにデータをダブルバッファーすることもできます。

デッドロックの状況を回避するために、NDIS はパケットの SG リストを取得し、一度に 1 つのパケットを送信します。 NDIS がミニポート ドライバーに送信する前にすべてのパケットをマップしようとすると、システムがリソースを使い果たすことができます。 この場合、NDIS は、いくつかのマップレジスタが未送信のパケットに対してロックされている間、マップレジスタが利用可能になるのを待っている。 ロックダウンされたパケットは再利用できません。

SGDMA サポートに対するこのアプローチには、次の制限があります。

  • パケットはミニポート ドライバーに到達する前にマップされるため、ドライバーは小さなパケットや、断片化しすぎるパケットを最適化できません。 ミニポート ドライバーは、既知の物理アドレスにパケットをダブル バッファーできません。

  • NDIS ミニポート ドライバーに渡された物理アドレス配列が元のデータの仮想アドレスにマップされる保証はありません。 したがって、ドライバーが MDL チェーンの仮想アドレスにあるデータを送信する前に変更した場合、データに加えられた変更は物理アドレスのデータには反映されません。 この場合、NIC は変更されていないデータを送信します。

  • NDIS は、リソースの問題によるデッドロックを回避するために、一度に 1 つのパケットを送信するように制限されています。 これは、複数のパケットを送信するほど効率的ではありません。

  • NDIS はミニポート ドライバーの送信機能を決定できないため、SG リスト バッファーの記憶域を事前に割り当てることはできません。 そのため、NDIS は、実行時に必要な記憶域を割り当てる必要があります。 これは、ストレージの事前割り当てほど効率的ではありません。

  • SG リストを割り当てる HAL 関数は IRQL = DISPATCH_LEVELで呼び出す必要があります。 NDIS には現在の IRQL 情報がないため、たとえ既に DISPATCH_LEVEL にあっても、IRQL を DISPATCH_LEVEL に設定する必要があります。 IRQL が既に DISPATCH_LEVEL の場合、これは効率的ではありません。

NDIS SGDMA サポートの利点

NDIS 6.0 以降の SGDMA インターフェイスでは、NDIS はミニポート ドライバーに送信する前にデータ バッファーをマップしません。 代わりに、NDIS は、ネットワーク データをマップするドライバーのインターフェイスを提供します。

この方法では、次の利点があります。

  • NDIS は、ネットワーク データをマッピングするための HAL へのインターフェイスを提供するため、NDIS は、複雑さとマッピング プロセスの詳細からミニポート ドライバーをシールドします。

  • ミニポート ドライバーは、マップされる前にデータにアクセスできます。 したがって、元のデータに加えられた変更は、NDIS または HAL がデータをダブルバッファーする場合でも、SG リストで表されるデータに反映されます。

  • ミニポート ドライバーは、既知の物理アドレスを持つ事前に割り当てられたバッファーにコピーすることによって、小さいまたは非常に断片化されたパケットの送信を最適化できます。 この方法では、不要なマッピングが回避されるため、システムのパフォーマンスが向上します。

  • NDIS は、ミニポート ドライバーに安全に複数のバッファーを送信できます。 これにより、ミニポート ドライバーへの呼び出しが少なくなるため、システムのパフォーマンスが向上します。

  • ミニポート ドライバーは、送信記述子ブロックの一部として SG リストのメモリを事前割り当てできます。 したがって、NDIS またはミニポート ドライバーは、実行時に SG リストのメモリを割り当てる必要はありません。

  • ミニポート ドライバーは IRQL = DISPATCH_LEVELで実行できるため、ミニポート ドライバーは、IRQL をDISPATCH_LEVELに発生させる不要な呼び出しを回避できます。 たとえば、送信の完了は割り込み DPC のコンテキストで行われるため、ミニポート ドライバーは IRQL を発生させずに SG リストを解放できます。

DMA チャネルの登録と登録解除

NDIS ミニポート ドライバーは、NDIS を使用して DMA チャネルを登録するミニポートInitializeEx 関数から NdisMRegisterScatterGatherDma 関数を呼び出します。

ミニポート ドライバーは、DmaDescription パラメーターで NdisMRegisterScatterGatherDma に DMA の説明を渡します。 NdisMRegisterScatterGatherDma は、散布図/収集リストを保持するのに十分な大きさのバッファーのサイズを返します。 ミニポート ドライバーは、散布図/収集リストの記憶域を事前に割り当てるには、このサイズを使用する必要があります。

ミニポート ドライバーは、NDIS が散布/収集リストを処理するために呼び出すミニポートXxx関数のエントリ ポイントをNdisMRegisterScatterGatherDmaに渡します。 NDIS は、HAL がバッファーの散布図/収集リストを構築した後 、ミニポート ドライバーのミニポートProcessSGList 関数を呼び出します。 NdisMRegisterScatterGatherDmapNdisMiniportDmaHandle パラメーターにハンドルを提供します。このパラメーターは、ミニポート ドライバーが NDIS 散布図/DMA 関数を収集する後続の呼び出しで使用する必要があります。

NDIS ミニポート ドライバーは、そのミニポートHaltEx 関数から NdisMDeregisterScatterGatherDma 関数を呼び出して、スキャッター/ギャザーDMAリソースを解放します。

スキャッター/ギャザーリストの割り当てと解放

NDIS ミニポート ドライバーは、MiniportSendNetBufferLists 関数内で NdisMAllocateNetBufferSGList 関数を呼び出します。 ミニポート ドライバーは、マップする必要がある各NET_BUFFER構造体に対して NdisMAllocateNetBufferSGList を 1 回呼び出します。 リソースが使用可能になり、HAL が SG リストの準備ができたら、NDIS はドライバーの ミニポートProcessSGList 関数を呼び出します。 NDIS は、NdisMAllocateNetBufferSGList のミニポート ドライバーによる呼び出しが返される前または後に、MiniportProcessSGList を呼び出すことができます。

システム のパフォーマンスを向上させるために、関連付けられているNET_BUFFER_DATA構造体の CurrentMdl メンバーで指定された MDL の先頭から、散布図/収集リストがネットワーク データから生成されます。 SG リスト内のネットワーク データの開始は、関連付けられたNET_BUFFER_DATA構造体の CurrentMdlOffset メンバーで指定された値によって、SG リストの先頭からオフセットされます。

送信完了割り込みの DPC を処理している間、ミニポート ドライバーが SG リストをこれ以上必要としない後、ミニポート ドライバーは NDISMFreeNetBufferSGList 関数を呼び出して SG リストを解放する必要があります。

手記ドライバーまたはハードウェアが、散布図/収集リストに関連付けられているNET_BUFFER構造体によって記述されているメモリにまだアクセスしている間は、NdisMFreeNetBufferSGList を呼び出さないでください。 

受信したデータにアクセスする前に、ミニポート ドライバーは NdisMFreeNetBufferSGList を呼び出してメモリ キャッシュをフラッシュする必要があります。