/*+
* file: alloc.c
*
* Copyright (C) 1994 by
* Digital Equipment Corporation, Maynard, Massachusetts.
* All rights reserved.
*
* This software is furnished under a license and may be used and copied
* only in accordance of the terms of such license and with the
* inclusion of the above copyright notice. This software or any other
* copies thereof may not be provided or otherwise made available to any
* other person. No title to and ownership of the software is hereby
* transferred.
*
* The information in this software is subject to change without notice
* and should not be construed as a commitment by digital equipment
* corporation.
*
* Digital assumes no responsibility for the use or reliability of its
* software on equipment which is not supplied by digital.
*
*
* Abstract: This file is part of the NDIS 4.0 miniport driver for
* DEC's DC21X4 Ethernet controller family.
*
*
* Author: Philippe Klein
*
* Revision History:
*
* phk 31-Jul-1994 Initial entry
* phk 11-Dec-1994 Allocate the shared data buffers in
* cached memory.
*
-*/
#include <precomp.h>
#pragma NDIS_PAGABLE_FUNCTION(AllocateAdapterMemory)
#pragma NDIS_PAGABLE_FUNCTION(FreeAdapterMemory)
#pragma NDIS_PAGABLE_FUNCTION(AlignStructure)
/*+
*
* AllocateAdapterMemory
*
* Routine Description:
*
* This routine allocates memory for:
*
* - Transmit descriptor ring
* - Receive descriptor ring
* - Receive buffers
* - Transmit buffer
* - Setup buffer
*
* Arguments:
*
* Adapter - The adapter to allocate memory for.
*
* Functional description
*
* For each allocated zone, we maintain a set of pointers:
* - virtual & physical addresses of the allocated block
* - virtual & physical addresses of the aligned structure (descriptor ring, buffer,...)
* whithin the block
*
* Return Value:
*
* Returns FALSE if an allocation fails.
*
-*/
extern
BOOLEAN
AllocateAdapterMemory(
IN PDC21X4_ADAPTER Adapter
)
{
PDC21X4_TRANSMIT_DESCRIPTOR TransmitDescriptor;
PDC21X4_RECEIVE_DESCRIPTOR ReceiveDescriptor;
NDIS_STATUS Status;
PRCV_HEADER RcvHeader;
PNDIS_PACKET Packet;
ULONG AllocSize;
PULONG AllocVa;
NDIS_PHYSICAL_ADDRESS AllocPa;
ULONG Va;
ULONG Pa;
UINT i;
ULONG Offset;
INT TransmitDescriptorRingSize;
INT ReceiveDescriptorRingSize;
Adapter->RcvHeaderSize =
((RCV_HEADER_SIZE + Adapter->CacheLineSize - 1) / Adapter->CacheLineSize)
* Adapter->CacheLineSize;
#if _DBG
DbgPrint("Alloc Rcv_ring[%d desc.], Txm_ring[%d desc.], setup_buf[%d]...\n",
Adapter->ReceiveRingSize,
TRANSMIT_RING_SIZE,
DC21X4_SETUP_BUFFER_SIZE
);
#endif
// Allocate space for transmit descriptor ring,
// the receive descriptor ring and the setup buffer
TransmitDescriptorRingSize =
Adapter->DescriptorSize * TRANSMIT_RING_SIZE;
ReceiveDescriptorRingSize =
Adapter->DescriptorSize * Adapter->ReceiveRingSize;
Adapter->DescriptorRing.AllocSize =
TransmitDescriptorRingSize
+ ReceiveDescriptorRingSize
+ DC21X4_SETUP_BUFFER_SIZE
+ Adapter->CacheLineSize;
NdisMAllocateSharedMemory(
Adapter->MiniportAdapterHandle,
Adapter->DescriptorRing.AllocSize,
FALSE, // NON-CACHED
(PVOID *)&Adapter->DescriptorRing.AllocVa, // virtual ...
&Adapter->DescriptorRing.AllocPa // and physical address of the allocation
);
// Check the allocation success
if ((PVOID)Adapter->DescriptorRing.AllocVa == (PVOID)NULL) {
return FALSE;
}
if (NdisGetPhysicalAddressHigh(Adapter->DescriptorRing.AllocPa) != 0) {
return FALSE;
}
NdisZeroMemory (
(PVOID)(Adapter->DescriptorRing.AllocVa),
(ULONG)(Adapter->DescriptorRing.AllocSize)
);
// Align to the next cache line boundary
AlignStructure (
&Adapter->DescriptorRing,
Adapter->CacheLineSize
);
Adapter->TransmitDescriptorRingVa = Adapter->DescriptorRing.Va;
Adapter->TransmitDescriptorRingPa = Adapter->DescriptorRing.Pa;
Offset = TransmitDescriptorRingSize;
Adapter->ReceiveDescriptorRingVa = Adapter->DescriptorRing.Va + Offset;
Adapter->ReceiveDescriptorRingPa = Adapter->DescriptorRing.Pa + Offset;
Offset += ReceiveDescriptorRingSize;
Adapter->SetupBufferVa = Adapter->DescriptorRing.Va + Offset;
Adapter->SetupBufferPa = Adapter->DescriptorRing.Pa + Offset;
//Initialize the setup buffer
NdisZeroMemory (
(PVOID)(Adapter->SetupBufferVa),
DC21X4_SETUP_BUFFER_SIZE
);
// Allocate a pool of NDIS buffers
NdisAllocateBufferPool(
&Status,
&Adapter->FlushBufferPoolHandle,
( Adapter->ReceiveRingSize
+ Adapter->ExtraReceiveBuffers
+ DC21X4_NUMBER_OF_MAX_TRANSMIT_BUFFERS
+ DC21X4_NUMBER_OF_MIN_TRANSMIT_BUFFERS )
);
if (Status != NDIS_STATUS_SUCCESS) {
return FALSE;
}
// Allocate a pool of packets.
#if _DBG
DbgPrint("Allocate PacketPool [%d packets]\n",
Adapter->ExtraReceivePackets);
#endif
NdisAllocatePacketPool(
&Status,
&Adapter->ReceivePacketPool,
Adapter->ExtraReceivePackets,
0
);
if (Status != NDIS_STATUS_SUCCESS) {
return FALSE;
}
// Allocate all of the packets out of the packet pool
// and place them on a queue.
for (i = 0; i < Adapter->ExtraReceivePackets; i++) {
// Allocate a packet from the pool.
NdisAllocatePacket(
&Status,
&Packet,
Adapter->ReceivePacketPool
);
if (Status != NDIS_STATUS_SUCCESS) {
return(FALSE);
}
// Set the header size in the packet's Out-Of-Band information.
// All other fields in the Out-Of-Band information have been
// initialized to 0 by NdisAllocatePacket().
NDIS_SET_PACKET_HEADER_SIZE(Packet, ETH_HEADER_SIZE);
// Place it on the receive packet free list.
RCV_RESERVED(Packet)->Next = Adapter->FreePacketList;
Adapter->FreePacketList = Packet;
}
// Clear out the free receive list of buffers.
Adapter->FreeRcvList = NULL;
// We allocate the receive buffers. We allocate both
// the buffers for the descriptor ring and the extra
// buffers and place them all on the free queue.
#if _DBG
DbgPrint("Allocate Receive Buffers [%d]\n",
Adapter->ExtraReceiveBuffers+Adapter->ReceiveRingSize);
#endif
// Attempt to allocate all the receive buffer space
// in one block
// If it fails,allocate each buffer individually
// Allocation size
Adapter->RcvBufferSpace.AllocSize =
((Adapter->ExtraReceiveBuffers + Adapter->ReceiveRingSize)
* (DC21X4_RECEIVE_BUFFER_SIZE + Adapter->RcvHeaderSize))
+ Adapter->CacheLineSize;
NdisMAllocateSharedMemory(
Adapter->MiniportAdapterHandle,
Adapter->RcvBufferSpace.AllocSize,
TRUE,
(PVOID *)&Adapter->RcvBufferSpace.AllocVa,
&Adapter->RcvBufferSpace.AllocPa
);
// Check the allocation success
if (((PVOID)Adapter->RcvBufferSpace.AllocVa != (PVOID)NULL)
&& (NdisGetPhysicalAddressHigh(Adapter->RcvBufferSpace.AllocPa) == 0)) {
NdisZeroMemory (
(PVOID)(Adapter->RcvBufferSpace.AllocVa),
(ULONG)(Adapter->RcvBufferSpace.AllocSize)
);
// Align to the next cache line boundary
AlignStructure (
&Adapter->RcvBufferSpace,
Adapter->CacheLineSize
);
// Allocation size needed for the receive buffer
AllocSize = DC21X4_RECEIVE_BUFFER_SIZE
+ Adapter->RcvHeaderSize;
Offset=0;
}
else
{
// Allocation size needed for the receive buffer
AllocSize = DC21X4_RECEIVE_BUFFER_SIZE
+ Adapter->RcvHeaderSize
+ Adapter->CacheLineSize;
Adapter->RcvBufferSpace.Va=0;
}
for (i = 0;
i < (Adapter->ExtraReceiveBuffers + Adapter->ReceiveRingSize);
i++
) {
if (Adapter->RcvBufferSpace.Va != 0) {
Va = Adapter->RcvBufferSpace.Va + Offset;
Pa = Adapter->RcvBufferSpace.Pa + Offset;
Offset += AllocSize;
}
else
{
// Allocate a receive buffer.
NdisMAllocateSharedMemory(
Adapter->MiniportAdapterHandle,
AllocSize,
TRUE,
(PVOID *)&AllocVa,
&AllocPa
);
if (((PVOID)AllocVa == (PVOID)NULL)
|| (NdisGetPhysicalAddressHigh(AllocPa) != 0)) {
return FALSE;
}
NdisZeroMemory(AllocVa, AllocSize);
// Align on the cache line boundary
Offset = Adapter->CacheLineSize - ((ULONG)AllocVa % Adapter->CacheLineSize);
Va = (ULONG)(AllocVa) + Offset;
Pa = NdisGetPhysicalAddressLow(AllocPa) + Offset;
}
//The receive header points to the aligned va.
RcvHeader = (PRCV_HEADER)Va;
RcvHeader->AllocVa = (ULONG)AllocVa;
RcvHeader->AllocPa = AllocPa;
RcvHeader->AllocSize = (USHORT)AllocSize;
// These addresses point to the data buffer
RcvHeader->Va = (ULONG)(Va + Adapter->RcvHeaderSize);
RcvHeader->Pa = Pa + Adapter->RcvHeaderSize;
RcvHeader->Size = DC21X4_RECEIVE_BUFFER_SIZE;
#if DBG
RcvHeader->Signature = 'dHxR';
#if _DBG
DbgPrint(
"%-3d RcvHeader: %lx, RcvBuffer: %lx/%lx, HeaderSize: %lx\n",
i,RcvHeader,
RcvHeader->Va,
RcvHeader->Pa,
Adapter->RcvHeaderSize
);
#endif
#endif
// Allocate an NDIS flush buffer for each receive buffer.
NdisAllocateBuffer(
&Status,
&RcvHeader->FlushBuffer,
Adapter->FlushBufferPoolHandle,
(PVOID)RcvHeader->Va,
DC21X4_RECEIVE_BUFFER_SIZE
);
if (Status != NDIS_STATUS_SUCCESS) {
return FALSE;
}
// Grab a packet off of the free packet list and
// associate it with the buffer.
Packet = Adapter->FreePacketList;
Adapter->FreePacketList = RCV_RESERVED(Packet)->Next;
// Chain the buffer on the packet.
NdisChainBufferAtFront(Packet, RcvHeader->FlushBuffer);
// Save a pointer to the receive header with the packet.
RCV_RESERVED(Packet)->RcvHeader = RcvHeader;
// Save the packet with the receive header.
RcvHeader->Packet = Packet;
// Place the descriptor on the free queue.
RcvHeader->Next = Adapter->FreeRcvList;
Adapter->FreeRcvList = RcvHeader;
Adapter->CurrentReceiveBufferCount++;
}
#if _DBG
DbgPrint("Init Rcv ring..\n");
#endif
// Assign the receive buffers to the descriptors.
for (i = 0,
ReceiveDescriptor = (PDC21X4_RECEIVE_DESCRIPTOR)Adapter->ReceiveDescriptorRingVa,
Pa = Adapter->ReceiveDescriptorRingPa;
i < Adapter->ReceiveRingSize;
i++,
(PCHAR)ReceiveDescriptor += Adapter->DescriptorSize,
Pa += Adapter->DescriptorSize
) {
// Grab a receive buffer from the free list.
ASSERT(Adapter->FreeRcvList != NULL);
RcvHeader = Adapter->FreeRcvList;
Adapter->FreeRcvList = RcvHeader->Next;
Adapter->CurrentReceiveBufferCount--;
// Associate the buffer with the descriptor.
ReceiveDescriptor->RcvHeader = RcvHeader;
ReceiveDescriptor->FirstBufferAddress = RcvHeader->Pa;
ReceiveDescriptor->Status = DESC_OWNED_BY_DC21X4;
ReceiveDescriptor->Control = DC21X4_RECEIVE_BUFFER_SIZE;
ReceiveDescriptor->Next =
(PDC21X4_RECEIVE_DESCRIPTOR)((PCHAR)ReceiveDescriptor + Adapter->DescriptorSize);
}
//last descriptor of the ring
(PCHAR)ReceiveDescriptor -= Adapter->DescriptorSize;
ReceiveDescriptor->Control |= DC21X4_RDES_SECOND_ADDR_CHAINED;
ReceiveDescriptor->SecondBufferAddress = Adapter->ReceiveDescriptorRingPa;
ReceiveDescriptor->Next =
(PDC21X4_RECEIVE_DESCRIPTOR)Adapter->ReceiveDescriptorRingVa;
#if _DBG
DbgPrint("Init Txm ring..\n");
#endif
// Initialize the Transmit Descriptor ring
for (i=0,
TransmitDescriptor = (PDC21X4_TRANSMIT_DESCRIPTOR)Adapter->TransmitDescriptorRingVa,
Pa = Adapter->TransmitDescriptorRingPa;
i < TRANSMIT_RING_SIZE;
i++,
(PCHAR)TransmitDescriptor += Adapter->DescriptorSize,
Pa += Adapter->DescriptorSize
) {
TransmitDescriptor->MapTableIndex = i * NUMBER_OF_SEGMENT_PER_DESC;
TransmitDescriptor->DescriptorPa = Pa;
TransmitDescriptor->Next =
(PDC21X4_TRANSMIT_DESCRIPTOR)((PCHAR)TransmitDescriptor + Adapter->DescriptorSize);
}
//last descriptor of the ring
(PCHAR)TransmitDescriptor -= Adapter->DescriptorSize;
TransmitDescriptor->Control = DC21X4_TDES_SECOND_ADDR_CHAINED;
TransmitDescriptor->SecondBufferAddress = Adapter->TransmitDescriptorRingPa;
TransmitDescriptor->Next =
(PDC21X4_TRANSMIT_DESCRIPTOR)Adapter->TransmitDescriptorRingVa;
// Txm buffers
for (i = 0;i < DC21X4_NUMBER_OF_MAX_TRANSMIT_BUFFERS;i ++) {
Adapter->MaxTransmitBuffer[i].AllocSize =
DC21X4_MAX_TRANSMIT_BUFFER_SIZE + Adapter->CacheLineSize;
NdisMAllocateSharedMemory(
Adapter->MiniportAdapterHandle,
Adapter->MaxTransmitBuffer[i].AllocSize,
TRUE, // CACHED
(PVOID *)&Adapter->MaxTransmitBuffer[i].AllocVa, // virtual ...
&Adapter->MaxTransmitBuffer[i].AllocPa // and physical address of the buffer allocation
);
// Check the allocation success
if (((PVOID)Adapter->MaxTransmitBuffer[i].AllocVa == (PVOID)NULL)
|| (NdisGetPhysicalAddressHigh(Adapter->MaxTransmitBuffer[i].AllocPa) != 0)) {
return FALSE;
}
// Align the buffer on the cache line boundary
AlignStructure (
&Adapter->MaxTransmitBuffer[i],
Adapter->CacheLineSize
);
// Allocate an NDIS flush buffer for each transmit buffer
NdisAllocateBuffer(
&Status,
&Adapter->MaxTransmitBuffer[i].FlushBuffer,
Adapter->FlushBufferPoolHandle,
(PVOID)Adapter->MaxTransmitBuffer[i].Va,
DC21X4_MAX_TRANSMIT_BUFFER_SIZE
);
if (Status != NDIS_STATUS_SUCCESS) {
return FALSE;
}
}
// Allocate the minimal packet buffers
Adapter->MinTransmitBuffer[0].AllocSize =
(DC21X4_NUMBER_OF_MIN_TRANSMIT_BUFFERS * DC21X4_MIN_TRANSMIT_BUFFER_SIZE)
+ Adapter->CacheLineSize;
NdisMAllocateSharedMemory(
Adapter->MiniportAdapterHandle,
Adapter->MinTransmitBuffer[0].AllocSize,
TRUE, // CACHED
(PVOID *)&Adapter->MinTransmitBuffer[0].AllocVa, // virtual ...
&Adapter->MinTransmitBuffer[0].AllocPa // and physical address of the buffer allocation
);
// Check the allocation success
if (((PVOID)Adapter->MinTransmitBuffer[0].AllocVa == (PVOID)NULL)
|| (NdisGetPhysicalAddressHigh(Adapter->MinTransmitBuffer[0].AllocPa) != 0)) {
Adapter->DontUseMinTransmitBuffer = TRUE;
return TRUE;
}
// Align the buffer on the cache line boundary
AlignStructure (
&Adapter->MinTransmitBuffer[0],
Adapter->CacheLineSize
);
for (i = 0;i < DC21X4_NUMBER_OF_MIN_TRANSMIT_BUFFERS;i ++) {
Offset = i * DC21X4_MIN_TRANSMIT_BUFFER_SIZE;
Adapter->MinTransmitBuffer[i].Va =
Adapter->MinTransmitBuffer[0].Va + Offset;
Adapter->MinTransmitBuffer[i].Pa =
Adapter->MinTransmitBuffer[0].Pa + Offset;
// Allocate an NDIS flush buffer for each transmit buffer
NdisAllocateBuffer(
&Status,
&Adapter->MinTransmitBuffer[i].FlushBuffer,
Adapter->FlushBufferPoolHandle,
(PVOID)Adapter->MinTransmitBuffer[i].Va,
DC21X4_MIN_TRANSMIT_BUFFER_SIZE
);
if (Status != NDIS_STATUS_SUCCESS) {
return FALSE;
}
}
// Allocation has completed successfully
return TRUE;
}
/*+
*
* FreeAdapterMemory
*
* Routine Description:
*
* Frees the memory previously allocated by
* AllocateAdapterMemory
*
* Arguments:
*
* Adapter - The adapter to deallocate memory for.
*
* Return Value:
*
* None.
*
-*/
extern
VOID
FreeAdapterMemory(
IN PDC21X4_ADAPTER Adapter
)
{
PDC21X4_RECEIVE_DESCRIPTOR ReceiveDescriptor;
PRCV_HEADER RcvHeader;
PNDIS_PACKET Packet;
UINT i;
if ((PVOID)Adapter->DescriptorRing.AllocVa == (PVOID)NULL) {
// AllocateAdapterMemory failed on the first allocation:
// no ressources were allocated
return;
}
for (i = 0,
ReceiveDescriptor = (PDC21X4_RECEIVE_DESCRIPTOR)Adapter->ReceiveDescriptorRingVa;
i < Adapter->ReceiveRingSize;
i++,
(PCHAR)ReceiveDescriptor += Adapter->DescriptorSize
) {
if (ReceiveDescriptor->RcvHeader) {
RcvHeader = ReceiveDescriptor->RcvHeader;
if (RcvHeader->FlushBuffer) {
NdisFreeBuffer(RcvHeader->FlushBuffer);
}
if (RcvHeader->Packet) {
NdisFreePacket(RcvHeader->Packet);
}
if (!Adapter->RcvBufferSpace.Va)
{
NdisMFreeSharedMemory(
Adapter->MiniportAdapterHandle,
RcvHeader->AllocSize,
TRUE,
(PVOID)RcvHeader->AllocVa,
RcvHeader->AllocPa
);
}
}
}
while (Adapter->FreeRcvList != NULL) {
RcvHeader = Adapter->FreeRcvList;
Adapter->FreeRcvList = RcvHeader->Next;
if (RcvHeader->FlushBuffer) {
NdisFreeBuffer(RcvHeader->FlushBuffer);
}
if ( !Adapter->RcvBufferSpace.Va
&& RcvHeader->AllocVa)
{
NdisMFreeSharedMemory(
Adapter->MiniportAdapterHandle,
RcvHeader->AllocSize,
TRUE,
(PVOID)RcvHeader->AllocVa,
RcvHeader->AllocPa
);
}
}
while (Adapter->FreePacketList != NULL)
{
Packet = Adapter->FreePacketList;
Adapter->FreePacketList = RCV_RESERVED(Packet)->Next;
if (NULL != Packet)
{
NdisFreePacket(Packet);
}
}
if (Adapter->RcvBufferSpace.Va) {
NdisMFreeSharedMemory(
Adapter->MiniportAdapterHandle,
Adapter->RcvBufferSpace.AllocSize,
TRUE,
(PVOID)Adapter->RcvBufferSpace.AllocVa,
Adapter->RcvBufferSpace.AllocPa
);
}
if (Adapter->ReceivePacketPool) {
NdisFreePacketPool((PVOID)Adapter->ReceivePacketPool);
}
for (i = 0; i < DC21X4_NUMBER_OF_MAX_TRANSMIT_BUFFERS;i ++ ) {
if (Adapter->MaxTransmitBuffer[i].AllocVa) {
NdisMFreeSharedMemory(
Adapter->MiniportAdapterHandle,
Adapter->MaxTransmitBuffer[i].AllocSize,
TRUE,
(PVOID)Adapter->MaxTransmitBuffer[i].AllocVa,
Adapter->MaxTransmitBuffer[i].AllocPa
);
}
if (Adapter->MaxTransmitBuffer[i].FlushBuffer) {
NdisFreeBuffer(Adapter->MaxTransmitBuffer[i].FlushBuffer);
}
}
if (Adapter->MinTransmitBuffer[0].AllocVa &&
!Adapter->DontUseMinTransmitBuffer) {
NdisMFreeSharedMemory(
Adapter->MiniportAdapterHandle,
Adapter->MinTransmitBuffer[0].AllocSize,
TRUE,
(PVOID)Adapter->MinTransmitBuffer[0].AllocVa,
Adapter->MinTransmitBuffer[0].AllocPa
);
}
for (i = 0; i < DC21X4_NUMBER_OF_MIN_TRANSMIT_BUFFERS;i ++ ) {
if (Adapter->MinTransmitBuffer[i].FlushBuffer) {
NdisFreeBuffer(Adapter->MinTransmitBuffer[i].FlushBuffer);
}
}
if (Adapter->FlushBufferPoolHandle) {
NdisFreeBufferPool(Adapter->FlushBufferPoolHandle);
}
if (Adapter->DescriptorRing.AllocVa) {
NdisMFreeSharedMemory(
Adapter->MiniportAdapterHandle,
Adapter->DescriptorRing.AllocSize,
FALSE,
(PVOID)Adapter->DescriptorRing.AllocVa,
Adapter->DescriptorRing.AllocPa
);
}
}
/*
* AlignStructure
*
* Align a structure within a bloc of allocated memory
* on a specified boundary
*
*/
VOID
AlignStructure (
IN PALLOCATION_MAP Map,
IN UINT Boundary
)
{
ULONG AlignmentOffset;
AlignmentOffset = Boundary - ((ULONG)(Map->AllocVa) % Boundary);
Map->Va = (ULONG)(Map->AllocVa) + AlignmentOffset;
Map->Pa = NdisGetPhysicalAddressLow(Map->AllocPa)+ AlignmentOffset;
}
/*
* DC21X4AllocateComplete
*
*
*
*/
VOID
DC21X4AllocateComplete(
IN NDIS_HANDLE MiniportAdapterContext,
IN PVOID VirtualAddress,
IN PNDIS_PHYSICAL_ADDRESS PhysicalAddress,
IN ULONG Length,
IN PVOID Context
)
{
}