NdisMAllocateSharedMemory

VOID
NdisMAllocateSharedMemory(

IN NDIS_HANDLE MiniportAdapterHandle,
IN ULONG Length,
IN BOOLEAN Cached,
OUT PVOID *VirtualAddress,
OUT PNDIS_PHYSICAL_ADDRESS PhysicalAddress
);

NdisMAllocateSharedMemory allocates and maps a host memory range so it is simultaneously accessible from both the system and a busmaster DMA NIC.

Parameters

MiniportAdapterHandle

Specifies the handle input to MiniportInitialize.

Length

Specifies the number of bytes to allocate.

Cached

Specifies TRUE if the range can be allocated from cached memory.

VirtualAddress

Points to a caller-supplied variable in which this function returns the base virtual address of the allocation for use by the miniport. If NdisMAllocateSharedMemory cannot satisfy its caller, it returns NULL to indicate that no memory was allocated.

PhysicalAddress

Points to a caller-supplied variable in which this function returns a physical address, suitable for use by the NIC, that corresponds to that returned at VirtualAddress, or it returns NULL.

Comments

NdisMAllocateSharedMemory provides both the mapped virtual address range that the driver uses to access the shared memory block and the NDIS_PHYSICAL_ADDRESS-type range that the NIC uses. A value returned at PhysicalAddress can be doubly mapped by the system. That is, a "physical" address range described by the value at PhysicalAddress and Length can be a range of mapped logical addresses that do not match the host physical addresses for the allocation in every possible platform.

NdisMAllocateSharedMemory can be called only from MiniportInitialize. How large an allocation to request depends on how the driver writer, knowing the capabilities and features of the NIC, decides to make the tradeoff between the following performance versus size dilemma:

·In periods of high network traffic, a miniport cannot maintain high I/O throughput if it runs low on shared memory space for device-accessible data buffers.

For example, the miniport could be indicating receive buffers in shared memory faster than such buffers are being returned from bound protocols when a flood of receives come in to its NIC. If all its shared memory space is consumed by outstanding receive buffers, the miniport might have to disable receive interrupts on its NIC until it has some shared memory space available for receive buffers.

·On the other hand, calling NdisMAllocateSharedMemory with a Length chosen to anticipate some maximum transfer demand makes the driver's image larger and its resource usage quite uneconomical, except for rare periods of very high I/O demand. Moreover, NdisMAllocateSharedMemory might not give the driver such a large block if insufficient system memory is available, forcing the driver to fail initialization.

A NIC driver that supplies a MiniportAllocateComplete function has considerably more flexibility in resolving the preceding performance versus size dilemma. MiniportInitialize should allocate only enough shared memory with NdisMAllocateSharedMemory for a moderate demand for network transfer operations through the NIC if the driver has a MiniportAllocateComplete function. Such a miniport can call NdisMAllocateSharedMemoryAsync dynamically to allocate more shared memory in periods of heavier transfer demand on its NIC. When the high demand for transfers subsides, such a driver calls NdisMFreeSharedMemory to release the additional memory it allocated.

NdisMAllocateSharedMemory and NdisMAllocateSharedMemoryAsync are the only NdisXxx functions that can be called to allocate host memory that is shared between the driver, which uses virtual addresses, and a busmaster NIC, which uses the corresponding logical addresses.

Whenever possible, a NIC driver calls NdisMAllocateSharedMemory with Cached set to TRUE because its request is more likely to succeed. In any platform, noncached memory is always a scarce system resource. Usually, drivers can get larger allocations from cached memory as well. A NIC driver must allocate its shared memory space from noncached memory if either of the following is true:

·The NIC or miniport writes directly into receive buffers before the miniport indicates the newly received data.

For example, a NIC that sets flags in each received frame after it has been transferred must have access to receive buffers in noncached memory. Otherwise, the miniport could not determine when it should issue a flush to maintain cache coherency: either the miniport would take a performance hit by waiting for a fail-safe interval to flush the cached receive buffer, or the miniport would make indications in which the frame flags were randomly set.

·The NIC transfers some number of received frames sequentially into contiguous physical memory within the shared memory space.

If such a NIC transferred incoming frames into contiguous cached memory, its driver cannot maintain data integrity for all such frames when any frame might straddle a cache-line boundary. When the miniport flushed the range for such a frame, it also might flush the cache space containing some of the next frame if it was already transferred, thereby making that next frame incoherent.

A miniport should align the buffers it allocates from shared cached memory on an integral of the host data-cache-line boundary to prevent cache-line tearing during DMA. Cache-line tearing can cause data-integrity problems in the driver or degrade the driver's (and the system's) I/O performance by requiring excessive data-cache flushing to maintain data integrity. MiniportInitialize can call NdisGetCacheFillSize to determine the alignment boundary in the current platform for device-accessible buffers that the driver will set up within an allocated range of shared memory.

MiniportInitialize also might call NdisSystemProcessorCount before it calls NdisMAllocateSharedMemory if the driver writer decides to allocate a larger shared memory block in multiprocessor machines on the assumption that any SMP machine is likely to be a network server with higher network-transfer demands on the NIC than a workstation.

MiniportInitialize must call NdisMAllocateMapRegisters before it calls NdisMAllocateSharedMemory; otherwise, no memory can be allocated. NDIS allocates an additional map register internally for the shared memory range when it is allocated.

If MiniportInitialize did not specify that the NIC is a busmaster when it called NdisMSetAttributes or NdisMSetAttributesEx, NdisMAllocateSharedMemory simply returns control without attempting to make an allocation.

If its call to NdisMAllocateSharedMemory fails, MiniportInitialize can call again requesting a smaller allocation. However, if MiniportInitialize cannot allocate sufficient shared memory for the NIC, it must release all resources it has already allocated and fail initialization.

If the NIC driver subsequently indicates receives with NdisMIndicateReceivePacket, it must allocate some number of buffer descriptors from buffer pool that map the NIC's receive buffers in the shared memory block.

If the allocated memory is cached and, therefore, needs to be flushed on transfers, the miniport must call NdisAllocateBuffer to allocate an NDIS_BUFFER-type descriptor for the shared memory range. The NIC driver must call NdisFlushBuffer with this buffer descriptor to perform such a flush. In addition, such a miniport should call NdisMUpdateSharedMemory to ensure data integrity on all possible platforms.

Any miniport that calls NdisMAllocateSharedMemoryAsync or NdisMAllocateSharedMemory must release all outstanding allocations with one or more calls to NdisMFreeSharedMemory when its NIC is removed, that is, when its MiniportHalt function is called.

Callers of NdisMAllocateSharedMemory run at IRQL PASSIVE_LEVEL.

See Also

MiniportAllocateComplete, MiniportHalt, MiniportInitialize, NdisAllocateBuffer, NdisAllocateBufferPool, NdisCreateLookaheadBufferFromSharedMemory, NdisDestroyLookaheadBufferFromSharedMemory, NdisFlushBuffer, NdisGetCacheFillSize, NdisMAllocateMapRegisters, NdisMAllocateSharedMemoryAsync, NdisMFreeSharedMemory, NdisMIndicateReceivePacket, NdisMSetAttributes, NdisMSetAttributesEx, NdisMStartBufferPhysicalMapping, NdisMUpdateSharedMemory, NdisSystemProcessorCount