Share via


NDIS Scatter/Gather DMA

Achtung

Für Arm- und Arm64-Prozessoren wird dringend empfohlen, 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-Treibern.

Weitere Informationen zu WDM DMA finden Sie in den DMA-bezogenen untergeordneten Themen unter Verwalten von Eingabe/Ausgabe für Treiber.

NDIS-Miniporttreiber können die Scatter/Gather DMA-Methode (SGDMA) verwenden, um Daten zwischen einer Netzwerkkarte und dem Systemspeicher zu übertragen. Eine erfolgreiche DMA-Übertragung erfordert, dass die physische Adresse der Daten in einem Adressbereich liegt, den die NIC unterstützt. HAL bietet einen Mechanismus für Treiber zum Abrufen der physischen Adressliste für eine MDL-Kette und puffert die Daten bei Bedarf in einen physischen Adressbereich.

In NDIS-Versionen vor NDIS 6.0 ist die SGDMA-Unterstützung in Miniporttreibern und NDIS in einigen Punkten eingeschränkt und funktioniert insbesondere 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 ruft NDIS eine Punktsammlungsliste (SG) für jedes Paket ab, 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 keine 64-Bit-DMA unterstützt.

Um eine Deadlocksituation 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, können ressourcenauslaufen. In diesem Fall wartet NDIS darauf, dass Kartenregister verfügbar werden, 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 weist die folgenden Einschränkungen auf:

  • Da das Paket zugeordnet wird, bevor es an den Miniporttreiber gelangt, kann der Treiber nicht für kleine Pakete oder Pakete optimieren, die zu fragmentiert sind. Der Miniporttreiber kann das Paket nicht auf eine bekannte physische Adresse zwischenpuffern.

  • Es gibt keine Garantie dafür, dass das physische Adressarray, das NDIS an den Miniporttreiber übergeben hat, der virtuellen Adresse der ursprünglichen Daten entspricht. Wenn der Treiber daher 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 wider. In diesem Fall sendet die Netzwerkkarte die unveränderten Daten.

  • NDIS ist auf das 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 zugeordnet werden. Daher muss NDIS den erforderlichen Speicher zur Laufzeit zuordnen. Dies ist nicht so effizient wie das Vorabzuweisen des Speichers.

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

Vorteile der NDIS SGDMA-Unterstützung

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

Dieser Ansatz bietet die folgenden Vorteile:

  • Da NDIS die Schnittstelle zu HAL zum Zuordnen der Netzwerkdaten bereitstellt, schützt NDIS Miniporttreiber vor der Komplexität und den Details des Zuordnungsprozesses.

  • Miniport-Treiber 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 von der SG-Liste dargestellt werden, auch wenn NDIS oder HAL die Daten doppelt puffert.

  • Miniporttreiber können die Übertragung kleiner oder stark fragmentierter Pakete optimieren, indem sie sie in einen vorab zugewiesenen Puffer mit einer bekannten physischen Adresse kopieren. Dieser Ansatz vermeidet keine Zuordnung, die nicht erforderlich ist, und verbessert daher die Systemleistung.

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

  • Miniporttreiber können den Arbeitsspeicher für eine SG-Liste als Teil der Übertragungsdeskriptorblöcke vorab allocatieren. Daher müssen NDIS- oder Miniporttreiber zur Laufzeit keinen Arbeitsspeicher für SG-Listen zuweisen.

  • Da Miniporttreiber unter IRQL = DISPATCH_LEVEL ausgeführt werden können, können Miniporttreiber unnötige Aufrufe vermeiden, um die IRQL auf DISPATCH_LEVEL zu erhöhen. Da das Abschließen eines Sendevorgangs beispielsweise im Kontext eines Interrupt-DPC erfolgt, können Miniporttreiber die SG-Liste freigeben, ohne die IRQL zu auslösen.

Registrieren und Aufheben der Registrierung von DMA-Kanälen

Ein NDIS-Miniporttreiber ruft die NdisMRegisterScatterGatherDma-Funktion aus seiner 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 Punkt-/Sammlungsliste zu enthalten. Miniport-Treiber sollten diese Größe verwenden, um den Speicher für Punkt-/Sammlungslisten vorab zuzuweisen.

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

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

Zuordnen und Freigeben von Punkt-/Sammlungslisten

Ein NDIS-Miniporttreiber ruft die NdisMAllocateNetBufferSGList-Funktion in seiner MiniportSendNetBufferLists-Funktion auf . Der Miniporttreiber ruft NdisMAllocateNetBufferSGList einmal für jede NET_BUFFER Struktur auf, die er 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 Aufruf des Miniporttreibers an NdisMAllocateNetBufferSGList zurückgegeben wird.

Um die Systemleistung zu verbessern, wird die Scatter/Gather-Liste aus den Netzwerkdaten generiert, beginnend am Anfang der MDL, die am CurrentMdl-Member der zugeordneten NET_BUFFER_DATA-Struktur angegeben wird. 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 Sendevorgangs-Interrupt und nachdem der Miniporttreiber die SG-Liste nicht mehr benötigt, sollte der Miniporttreiber die NdisMFreeNetBufferSGList-Funktion aufrufen, um die SG-Liste freizusetzen.

Hinweis Rufen Sie NdisMFreeNetBufferSGList nicht auf, während der Treiber oder die Hardware weiterhin auf den Arbeitsspeicher 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.