Freigeben über


NDIS Scatter/Gather DMA

Vorsicht

Für Arm- und Arm64-Prozessoren empfehlen wir dringend, dass NDIS-Treiberautoren WDF DMA oder WDM DMA anstelle von NDIS Scatter/Gather DMA verwenden.

Weitere Informationen zu WDF DMA finden Sie unter Behandeln von DMA-Vorgängen in KMDF Drivers.

Weitere Informationen zu WDM DMA finden Sie in den DMA-bezogenen untergeordneten Themen Managing Input/Output for Drivers.

NDIS-Miniport-Treiber können die Scatter/Gather-DMA (SGDMA)-Methode verwenden, um Daten zwischen einer Netzwerkkarte (NIC) und dem Systemspeicher zu übertragen. Eine erfolgreiche DMA-Übertragung erfordert die physische Adresse der Daten in einem Adressbereich, den die NIC unterstützt. HAL stellt einen Mechanismus bereit, mit dem Treiber die physische Adressliste für eine MDL-Kette abrufen können. Bei Bedarf werden die Daten in einem physischen Adressbereich doppelt gepuffert.

In NDIS-Versionen vor NDIS 6.0 ist die SGDMA-Unterstützung in Miniporttreibern und NDIS in manchen Fällen eingeschränkt, und insbesondere funktioniert dies in einem Multipacket-Sendeszenario nicht gut. Die NDIS 6.0 SGDMA-Unterstützung überwindet diese Einschränkungen und bietet gleichzeitig eine einfache Schnittstelle für Miniporttreiber.

Geschichte von NDIS SGDMA

In NDIS-Versionen vor NDIS 6.0 erhält NDIS für jedes Paket eine Scatter-Gather-Liste (SG), bevor das Paket an den Miniporttreiber gesendet wird. NDIS behandelt auch den Fall, in dem der ursprüngliche Versuch, die SG-Liste abzurufen, aufgrund einer übermäßigen Fragmentierung fehlschlägt. In diesem Fall puffert NDIS das Paket in einen zusammenhängenden Puffer und versucht es erneut. HAL kann die Daten auch auf eine physische Adresse zwischenspeichern, die von der NIC unterstützt wird, wenn beispielsweise die physische Adresse der Daten über dem 32-Bit-Maximum liegt und die NIC 64-Bit-DMA nicht unterstützt.

Um eine Deadlock-Situation zu vermeiden, ruft NDIS eine SG-Liste für ein Paket ab und sendet jeweils ein Paket. Wenn NDIS versucht, alle Pakete zuzuordnen, bevor sie an den Miniporttreiber gesendet werden, kann das System Ressourcen auslaufen. In diesem Fall wartet NDIS auf die Verfügbarkeit von Kartenregistern, während einige Kartenregister für die Pakete gesperrt sind, die nicht gesendet wurden. Gesperrte Pakete können nicht wiederverwendet werden.

Dieser Ansatz für die SGDMA-Unterstützung hat die folgenden Einschränkungen:

  • Da das Paket zugeordnet wird, bevor es zum Miniporttreiber gelangt, kann der Treiber nicht für kleine Pakete oder Pakete optimiert werden, die zu fragmentiert sind. Der Miniporttreiber kann das Paket nicht zu einer bekannten physischen Adresse doppelpuffern.

  • Es gibt keine Garantie dafür, dass das physische Adressarray, das NDIS an den Miniporttreiber übergeben hat, der virtuellen Adresse der ursprünglichen Daten zugeordnet ist. Wenn der Treiber die Daten an der virtuellen Adresse in der MDL-Kette vor dem Senden ändert, werden die an den Daten vorgenommenen Änderungen nicht in den Daten in den physischen Adressen widergespiegelt. In diesem Fall sendet die NIC die nicht geänderten Daten.

  • NDIS ist auf das Gleichzeitige Senden eines Pakets beschränkt, um einen Deadlock aufgrund von Ressourcenproblemen zu vermeiden. Dies ist nicht so effizient wie das Senden mehrerer Pakete.

  • Da NDIS die Übertragungsfunktionen von Miniporttreibern nicht ermitteln kann, kann der Speicher für einen SG-Listenpuffer nicht vorab zugewiesen werden. Daher muss NDIS zur Laufzeit den erforderlichen Speicher zuordnen. Dies ist nicht so effizient wie das Vorzuweisen des Speichers.

  • HAL-Funktionen, die eine SG-Liste zuordnen, sollten bei IRQL = DISPATCH_LEVEL aufgerufen werden. NDIS verfügt nicht über die aktuellen IRQL-Informationen, daher muss der IRQL auf DISPATCH_LEVEL festgelegt werden, auch wenn er bereits bei DISPATCH_LEVEL ist. Dies ist nicht effizient, wenn die IRQL bereits auf DISPATCH_LEVEL ist.

Vorteile der NDIS-SGDMA-Unterstützung

In der NDIS 6.0- und höher-SGDMA-Schnittstelle ordnet NDIS den Datenpuffer nicht zu, bevor er an den Miniporttreiber gesendet wird. Stattdessen stellt NDIS eine Schnittstelle für den Treiber bereit, um die Netzwerkdaten abzubilden.

Dieser Ansatz bietet die folgenden Vorteile:

  • Da NDIS die Schnittstelle zu HAL zum Zuordnen der Netzwerkdaten bereitstellt, schirmt NDIS Miniporttreiber von der Komplexität und Details des Zuordnungsprozesses ab.

  • Miniporttreiber haben Zugriff auf die Daten, bevor sie zugeordnet werden. Daher werden alle Änderungen, die an den ursprünglichen Daten vorgenommen wurden, in den Daten widergespiegelt, die durch die SG-Liste dargestellt werden, auch wenn NDIS oder HAL die Daten doppelt puffert.

  • Miniport-Treiber können die Übertragung kleiner oder hoch fragmentierter Pakete optimieren, indem sie sie in einen vordefinierten Puffer mit einer bekannten physischen Adresse kopieren. Dieser Ansatz vermeidet unnötige Zuordnungen und verbessert dadurch die Systemleistung.

  • NDIS kann mehrere Puffer sicher an den Miniporttreiber senden. Dies führt zu weniger Aufrufen von Miniporttreibern und verbessert daher die Systemleistung.

  • Miniport-Treiber können den Speicher für eine SG-Liste als Teil der Übertragungsdeskriptorblöcke vorschreiben. Daher müssen NDIS- oder Miniport-Treiber zur Laufzeit keinen Speicher für SG-Listen zuweisen.

  • Da Miniporttreiber bei IRQL = DISPATCH_LEVEL ausgeführt werden können, können Miniporttreiber unnötige Aufrufe vermeiden, um die IRQL auf DISPATCH_LEVEL auszuheben. Da der Abschluss eines Sendens beispielsweise im Kontext eines Interrupt-DPC erfolgt, können Miniporttreiber die SG-Liste freigeben, ohne das IRQL zu erhöhen.

Registrieren und Aufheben der Registrierung von DMA-Kanälen

Ein NDIS-Miniporttreiber ruft die NdisMRegisterScatterGatherDma-Funktion aus der MiniportInitializeEx-Funktion auf, um einen DMA-Kanal bei NDIS zu registrieren.

Der Miniporttreiber übergibt eine DMA-Beschreibung an NdisMRegisterScatterGatherDma im DmaDescription-Parameter . NdisMRegisterScatterGatherDma gibt eine Größe für den Puffer zurück, die groß genug sein sollte, um die Scatter/Gather-Liste zu enthalten. Miniport-Treiber sollten diese Größe verwenden, um den Speicher für Scatter/Gather-Listen vorab zuzuweisen.

Der Miniporttreiber übergibt auch NdisMRegisterScatterGatherDma die Einstiegspunkte für die MiniportXxx-Funktionen, die NDIS aufruft, um die Scatter/Gather-Liste zu verarbeiten. NDIS ruft die Funktion MiniportProcessSGList des Miniporttreibers auf, nachdem HAL die Scatter/Gather-Liste für einen Puffer erstellt hat. NdisMRegisterScatterGatherDma stellt im pNdisMiniportDmaHandle-Parameter einen Handle bereit, den der Miniporttreiber in nachfolgenden Aufrufen von NDIS Scatter/Gather-DMA-Funktionen verwenden muss.

Ein NDIS-Miniporttreiber ruft die NdisMDeregisterScatterGatherDma-Funktion aus seiner MiniportHaltEx-Funktion auf, um Scatter/Gather-DMA-Ressourcen freizugeben.

Zuweisen und Freigeben von Scatter/Gather-Listen

Ein NDIS-Miniporttreiber ruft die NdisMAllocateNetBufferSGList-Funktion in der MiniportSendNetBufferLists-Funktion auf. Der Miniporttreiber ruft NdisMAllocateNetBufferSGList einmal für jede NET_BUFFER Struktur auf, die sie zuordnen muss. Nachdem die Ressourcen verfügbar sind und HAL die SG-Liste bereit ist, ruft NDIS die MiniportProcessSGList-Funktion des Treibers auf. NDIS kann MiniportProcessSGList aufrufen, bevor oder nachdem der Miniporttreiber NdisMAllocateNetBufferSGList aufgerufen hat.

Um die Systemleistung zu verbessern, wird die Scatter/Gather-Liste aus den Netzwerkdaten generiert, beginnend am Anfang der MDL, die im CurrentMdl-Element der zugeordneten NET_BUFFER_DATA-Struktur angegeben ist. Der Anfang der Netzwerkdaten in der SG-Liste wird vom Anfang der SG-Liste durch den Wert versetzt, der im CurrentMdlOffset-Element der zugeordneten NET_BUFFER_DATA-Struktur angegeben ist.

Während der Behandlung eines DPC für einen Send-Complete-Interrupt, und nachdem der Miniporttreiber die SG-Liste nicht mehr benötigt, sollte der Miniporttreiber die NdisMFreeNetBufferSGList-Funktion aufrufen, um die SG-Liste freizuschalten.

Anmerkung Rufen Sie NdisMFreeNetBufferSGList nicht auf, während der Treiber oder die Hardware weiterhin auf den Speicher zugreift, der durch die NET_BUFFER Struktur beschrieben wird, die der Scatter/Gather-Liste zugeordnet ist. 

Vor dem Zugriff auf empfangene Daten müssen Miniporttreiber NdisMFreeNetBufferSGList aufrufen, um den Speichercache zu leeren.