NDIS 散佈圖/收集 DMA
警告
針對 Arm 和 Arm64 處理器,我們強烈建議 NDIS 驅動程式寫入器使用 WDF DMA 或 WDM DMA,而不是 NDIS 散佈圖/收集 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 也可以將資料雙緩衝處理至 NIC 支援的實體位址,例如,資料的實體位址高於 32 位上限,而 NIC 不支援 64 位 DMA。
為了避免死結的情況,NDIS 會取得封包的 SG 清單,並一次傳送一個封包。 如果 NDIS 嘗試先對應所有封包,再將其傳送至迷你埠驅動程式,系統可能會用盡資源。 在此情況下,NDIS 會等候地圖暫存器可供使用,而某些地圖暫存器會鎖定尚未傳送的封包。 無法重複使用鎖定的封包。
這個對 SGDMA 支援的方法有下列限制:
因為封包會先對應到迷你埠驅動程式,所以驅動程式無法針對太分散的小型封包或封包進行優化。 迷你埠驅動程式無法將封包雙重緩衝至已知的實體位址。
不保證傳遞至迷你埠驅動程式的 NDIS 實體位址陣列會對應至原始資料的虛擬位址。 因此,如果驅動程式在傳送之前變更 MDL 鏈結中虛擬位址的資料,對資料的修改不會反映在實體位址中的資料中。 在此情況下,NIC 會傳送未修改的資料。
NDIS 一次只能傳送一個封包,以避免因資源問題而造成死結。 這不像傳送多個封包一樣有效率。
因為 NDIS 無法判斷迷你埠驅動程式的傳輸功能,所以無法預先配置 SG 清單緩衝區的儲存體。 因此,NDIS 必須在執行時間配置必要的儲存體。 這不像預先配置儲存體一樣有效率。
配置 SG 清單的 HAL 函式應該在 IRQL = DISPATCH_LEVEL呼叫。 NDIS 沒有目前的 IRQL 資訊,因此即使 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 的內容中發生,所以迷你埠驅動程式可以釋出 SG 清單,而不需要引發 IRQL。
註冊和取消註冊 DMA 通道
NDIS 迷你埠驅動程式會從其MiniportInitializeEx函式呼叫NdisMRegisterScatterGatherDma函式,以向 NDIS 註冊 DMA 通道。
迷你埠驅動程式會將 DMA 描述傳遞給DmaDescription參數中的NdisMRegisterScatterGatherDma。 NdisMRegisterScatterGatherDma 會傳回緩衝區的大小,其大小應足以保存散佈/收集清單。 迷你埠驅動程式應該使用此大小預先配置散佈/收集清單的儲存體。
迷你埠驅動程式也會傳遞 NdisMRegisterScatterGatherDma NDIS 呼叫以處理散佈/收集清單的 MiniportXxx 函式進入點。 NDIS 會在 HAL 建置緩衝區的散佈/收集清單之後,呼叫迷你埠驅動程式的 MiniportProcessSGList 函式。 NdisMRegisterScatterGatherDma 提供 pNdisMiniportDmaHandle 參數中的控制碼,迷你埠驅動程式必須在後續呼叫 NDIS 散佈/收集 DMA 函式時使用。
NDIS 迷你埠驅動程式會從其MiniportHaltEx函式呼叫NdisMDeregisterScatterGatherDma函式,以釋放散佈/收集 DMA 資源。
配置和釋放散佈圖/收集清單
NDIS 迷你埠驅動程式在其MiniportSendNetBufferLists函式中呼叫NdisMAllocateNetBufferSGList函式。 迷你埠驅動程式會針對必須對應的每個NET_BUFFER結構呼叫NdisMAllocateNetBufferSGList一次。 資源可用且 HAL 備妥 SG 清單之後,NDIS 會呼叫驅動程式的 MiniportProcessSGList 函式。 NDIS 可以在迷你埠驅動程式呼叫NdisMAllocateNetBufferSGList傳回之前或之後呼叫MiniportProcessSGList。
為了改善系統效能,從在相關聯NET_BUFFER_DATA結構之 CurrentMdl成員指定的 MDL 開頭開始,從網路資料產生散佈/收集清單。 SG 清單中的網路資料的開頭會依相關聯NET_BUFFER_DATA結構之 CurrentMdlOffset成員中指定的值,從 SG 清單的開頭位移。
處理傳送完成中斷的 DPC,而且在迷你埠驅動程式不再需要 SG 清單之後,迷你埠驅動程式應該呼叫 NdisMFreeNetBufferSGList 函式以釋放 SG 清單。
注意當驅動程式或硬體仍在存取與散佈/收集清單相關聯的NET_BUFFER結構所描述的記憶體時,請勿呼叫NdisMFreeNetBufferSGList。
存取收到的資料之前,迷你埠驅動程式必須呼叫 NdisMFreeNetBufferSGList 來清除記憶體快取。