NDIS DMA introduction

I try to understand how I should implement an NDIS 6 miniport driver in respect to dma. It should be a simple driver, not high-performance. As far as i know, I should call NdisMRegisterScatterGatherDma during initialization. My hardware has bus-master dma. I set the ProcessSGListHandler. When a protocol driver sends frames, NDIS provides me the NET_BUFFER_LIST. When I call NdisMAllocateNetBufferSGList, NDIS converts a NET_BUFFER to a SGList. I configure the dma controller with the scatter gather elements for one frame and start the dma transfer to the device. The hardware notifies me via interrupt when the send has completed.

How should I implement the receive? I have a fixed number of rx descriptors in the dma controller, so I assume I should allocate a commonbuffer with size = MAX_SIZE_OF_ETHERNET_FRAME * NUMBER_OF_RX_DESCRIPTORS. How do I allocate this physical contiguous buffer? During initialization I would program the rx dma. The rx dma engine is a fifo. I configure each rx descriptor with the physical address in the common buffer.

The windows driver samples github repo did not contain an example that uses NdisMRegisterScatterGatherDma. In the repo https://github.com/microsoftarchive/msdn-code-gallery-microsoft I found the driver “Native Wi-Fi Miniport Sample Driver”, but until now I could not find the way it allocates the rx buffer.

Hi,
Older Wi-Fi drivers (before high-performance modes) did quite complex manipulation on the data in software, and implementing SG DMA in hardware was not justified. New fast PCIe devices probably offload these manipulations to hardware and have SG DMA ability.
The Atheros example was made in the old times. You’re not finding the DMA details in that example because this is hidden in an export library (athhal.sys) which is provided only as binary + lib. And the example itself now seems to be removed from the gallery.
I’m afraid there are no other public examples for Windows. Even Linux wi-fi divers are large and complicated (not even to mention the firmware).
But you wrote ’ It should be a simple driver’ - so it isn’t anything wireless?

– pa

Correct, I’m working on an ethernet driver. The “Native Wi-Fi Miniport Sample Driver” was the only NDIS 6 miniport driver with dma that I could find. It is still available in the repo. Here is the path:

msdn-code-gallery-microsoft/Official Windows Driver Kit Sample/Windows Driver Kit (WDK) 8.1 Samples/[C++]-windows-driver-kit-81-cpp/WDK 8.1 C++ Samples/Native Wi-Fi Miniport Sample Driver/C++/

git clone did not work for me, so I downloaded the driver via gitzip (http://kinolien.github.io/gitzip).

I understood the general dma tx workflow in the wifi driver. It calls NdisMRegisterScatterGatherDma. In MPSendNetBufferLists the function NdisMAllocateNetBufferSGList is called. In the handler HWProcessSGList NDIS provides the scatter gather list for a NET_BUFFER . The driver fills the hardware address and length for each sg element into a descriptor. The descriptor is forwarded to the hidden export library.

Rx is not clear to me yet.

For RX the driver usually keeps a pool of memory which it owns. If you want to do SG DMA on receive, allocate in advance some net buffers and SG lists for them. If you want to keep it simple (but lower performance), do RMA receive to a common buffer and fill NDIS net buffers later (in a DPC).
– pa

There is an example of the full-features NIC (for para-virtualized device) where you see how to allocate and use RX buffers:
https://github.com/virtio-win/kvm-guest-drivers-windows/tree/master/NetKVM

If you want to run the driver, start any VM (VirtualBox or QEMU) that supports the virtio-net device.

Thank you, Pavel_A and Yan_Vugenfirer-4.