mirror of https://github.com/lianthony/NT4.0
You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
833 lines
19 KiB
833 lines
19 KiB
/*******************************************************************/
|
|
/* Copyright(c) 1993 Microsoft Corporation */
|
|
/*******************************************************************/
|
|
|
|
//***
|
|
//
|
|
// Filename: rcvpkt.c
|
|
//
|
|
// Description: rcv pkt pool manager
|
|
//
|
|
// Author: Stefan Solomon (stefans) October 5, 1993.
|
|
//
|
|
// Revision History:
|
|
//
|
|
//***
|
|
|
|
#include "rtdefs.h"
|
|
|
|
PRCVPKT_SEGMENT
|
|
CreateRcvPktSegment(VOID);
|
|
|
|
VOID
|
|
DestroyRcvPktSegment(PRCVPKT_SEGMENT segp);
|
|
|
|
PPACKET_TAG
|
|
CreateRcvPkt(PULONG buffp,
|
|
PRCVPKT_SEGMENT segp);
|
|
|
|
VOID
|
|
DestroyRcvPkt(PPACKET_TAG pktp);
|
|
|
|
// the pool size parameter
|
|
UINT RcvPktPoolSize = RCVPKT_MEDIUM_POOL_SIZE;
|
|
|
|
// the number of receive packets per pool segment (config parameter)
|
|
UINT RcvPktsPerSegment = DEF_RCV_PKTS_PER_SEGMENT;
|
|
UINT LowRcvPktsCount = 0;
|
|
|
|
|
|
// Max frame size as a multiple of ULONGs
|
|
UINT UlongMaxFrameSize;
|
|
|
|
//
|
|
//*** Control Structures For the Rcv Pkt Segment List ***
|
|
//
|
|
|
|
NDIS_SPIN_LOCK RcvPktSegListLock;
|
|
|
|
UINT RcvPktSegCount = 0; // total segments allocated
|
|
// for this pool
|
|
UINT MaxRcvPktCount = 0; // max nr of pkts the pool can have
|
|
UINT RcvPktCount = 0; // total pkts allocated for the
|
|
// pool: free + owned by nics
|
|
PUINT RcvPktPerNicCount; // table of pkts allocated for
|
|
// each nic, indexed by NicId
|
|
LIST_ENTRY RcvPktSegList; // list of pool segments
|
|
|
|
//*** Statistics: Peak rcv pkts allocation ***
|
|
|
|
ULONG StatMemAllocCount = 0;
|
|
ULONG StatMemPeakCount = 0;
|
|
|
|
//*** Control Structure for the Allocate Ahead Function ***
|
|
|
|
typedef enum _ALLOC_AHEAD_STATE {
|
|
|
|
ALLOC_AHEAD_IDLE,
|
|
ALLOC_AHEAD_ACTIVE
|
|
} ALLOC_AHEAD_STATE;
|
|
|
|
ALLOC_AHEAD_STATE AllocAheadState;
|
|
|
|
WORK_QUEUE_ITEM AllocAheadWorkItem;
|
|
|
|
VOID
|
|
AllocAhead(PVOID parameter);
|
|
|
|
VOID
|
|
CheckAllocationAhead(VOID);
|
|
|
|
//***
|
|
//
|
|
// Function: CreateRcvPktPool
|
|
//
|
|
// Descr: Allocates the rcv pkt descr and buff descr pools.
|
|
// Creates the rcv pkt segment list and allocates one segment
|
|
//
|
|
// Params: none
|
|
//
|
|
// Returns: 0 - success, 1 - failure
|
|
//
|
|
//***
|
|
|
|
UINT
|
|
CreateRcvPktPool(VOID)
|
|
{
|
|
UINT MaxRcvPktsPerNic;
|
|
PRCVPKT_SEGMENT segp;
|
|
|
|
RtPrint(DBG_INIT, ("IpxRouter: CreateRcvPktPool: Entered\n"));
|
|
|
|
// calculate the maxrcvpktspernic function of the pool size
|
|
switch(RcvPktPoolSize) {
|
|
|
|
case RCVPKT_SMALL_POOL_SIZE:
|
|
|
|
MaxRcvPktsPerNic = 100;
|
|
break;
|
|
|
|
case RCVPKT_MEDIUM_POOL_SIZE:
|
|
|
|
MaxRcvPktsPerNic = 250;
|
|
break;
|
|
|
|
case RCVPKT_LARGE_POOL_SIZE:
|
|
default:
|
|
|
|
MaxRcvPktsPerNic = 0; // unlimited
|
|
break;
|
|
}
|
|
|
|
INITIALIZE_SPIN_LOCK(&RcvPktSegListLock);
|
|
|
|
InitializeListHead(&RcvPktSegList);
|
|
|
|
// initialize the pool max limit.
|
|
if(MaxRcvPktsPerNic) {
|
|
|
|
MaxRcvPktCount = MaximumNicCount * MaxRcvPktsPerNic;
|
|
}
|
|
else
|
|
{
|
|
MaxRcvPktCount = 0xFFFFFFFF;
|
|
}
|
|
|
|
UlongMaxFrameSize = MaxFrameSize / sizeof(ULONG) + 1;
|
|
|
|
// allocate the array of rcv pkts allocated /nic
|
|
if((RcvPktPerNicCount = (PUINT)CTEAllocMem(
|
|
MaximumNicCount * sizeof(UINT))) == NULL) {
|
|
|
|
goto cleanup;
|
|
}
|
|
RtlZeroMemory(RcvPktPerNicCount, MaximumNicCount * sizeof(UINT));
|
|
|
|
//
|
|
//*** Create the first segment and insert it in the pool
|
|
//
|
|
|
|
if((segp = CreateRcvPktSegment()) == NULL) {
|
|
|
|
goto cleanup;
|
|
}
|
|
|
|
// chain the segment in the rcv pkt seg list
|
|
ACQUIRE_SPIN_LOCK(&RcvPktSegListLock);
|
|
|
|
RcvPktSegCount++;
|
|
RcvPktCount += segp->MaxPktCount;
|
|
|
|
InsertTailList(&RcvPktSegList, &segp->SegmentLinkage);
|
|
|
|
// initialize the allocate ahead structures
|
|
AllocAheadState = ALLOC_AHEAD_IDLE;
|
|
LowRcvPktsCount = RcvPktsPerSegment / 2;
|
|
ExInitializeWorkItem(&AllocAheadWorkItem, AllocAhead, NULL);
|
|
|
|
RELEASE_SPIN_LOCK(&RcvPktSegListLock);
|
|
|
|
// All Done
|
|
|
|
return 0;
|
|
|
|
cleanup:
|
|
|
|
DestroyRcvPktPool();
|
|
|
|
return 1;
|
|
}
|
|
|
|
//***
|
|
//
|
|
// Function: DestroyRcvPktPool
|
|
//
|
|
// Descr: Destroys all the pool segments.
|
|
// Frees the rcv pkt segment memory array.
|
|
//
|
|
// Params: none
|
|
//
|
|
// Returns: none
|
|
//
|
|
//***
|
|
|
|
VOID
|
|
DestroyRcvPktPool(VOID)
|
|
{
|
|
PLIST_ENTRY slp;
|
|
PRCVPKT_SEGMENT sp;
|
|
|
|
RtPrint(DBG_INIT, ("IpxRouter: DestroyRcvPktPool: Entered\n"));
|
|
|
|
// ckeck if segment list has been created and destroy it if it exists
|
|
ACQUIRE_SPIN_LOCK(&RcvPktSegListLock);
|
|
|
|
while(!IsListEmpty(&RcvPktSegList)) {
|
|
|
|
slp = RemoveTailList(&RcvPktSegList);
|
|
sp = CONTAINING_RECORD(slp, RCVPKT_SEGMENT, SegmentLinkage);
|
|
|
|
DestroyRcvPktSegment(sp);
|
|
}
|
|
|
|
RELEASE_SPIN_LOCK(&RcvPktSegListLock);
|
|
|
|
if(RcvPktPerNicCount) {
|
|
|
|
CTEFreeMem(RcvPktPerNicCount);
|
|
}
|
|
|
|
DEINITIALIZE_SPIN_LOCK(&RcvPktSegListLock);
|
|
}
|
|
|
|
//***
|
|
//
|
|
// Function: CreateRcvPktSegment
|
|
//
|
|
// Descr: Allocates a memory buffer of size:
|
|
// rcv pkt segment + n * maxframesize.
|
|
// Allocates n rcv pkt descr and 2n buff descr and creates the
|
|
// rcv packets.
|
|
// Chains all rcv pkts in the rcv pkt segment.
|
|
// Note:
|
|
// Only one buff descr is chained in each packet descr.
|
|
// A ptr is kept in the packet tag to the second buff descr which
|
|
// is associated with the MAC header in the packet tag.
|
|
//
|
|
// Params: none
|
|
//
|
|
// Returns: Segment ptr or NULL if failure.
|
|
//
|
|
//***
|
|
|
|
PRCVPKT_SEGMENT
|
|
CreateRcvPktSegment(VOID)
|
|
{
|
|
PRCVPKT_SEGMENT segp;
|
|
ULONG seglen;
|
|
UINT i;
|
|
PPACKET_TAG pktp;
|
|
PULONG buffp;
|
|
NDIS_STATUS NdisStatus;
|
|
UINT PktReservedLen;
|
|
|
|
RtPrint(DBG_RCVPKT, ("IpxRouter: CreateRcvPktSegment: Entered\n"));
|
|
|
|
seglen = sizeof(RCVPKT_SEGMENT) +
|
|
RcvPktsPerSegment * UlongMaxFrameSize * sizeof(ULONG);
|
|
|
|
if((segp = CTEAllocMem(seglen)) == NULL) {
|
|
|
|
return NULL;
|
|
}
|
|
|
|
RtlZeroMemory(segp, sizeof(RCVPKT_SEGMENT));
|
|
InitializeListHead(&segp->PacketList);
|
|
|
|
// Allocate receive packet descriptors and buffer descriptors pools
|
|
// for this segment
|
|
|
|
PktReservedLen = sizeof(PACKET_TAG);
|
|
segp->RcvPktDescrPoolSize = RcvPktsPerSegment;
|
|
|
|
NdisAllocatePacketPool(
|
|
&NdisStatus,
|
|
&segp->RcvPktDescrPoolHandle,
|
|
segp->RcvPktDescrPoolSize,
|
|
PktReservedLen);
|
|
|
|
if(NdisStatus != NDIS_STATUS_SUCCESS) {
|
|
|
|
CTEFreeMem(segp);
|
|
return NULL;
|
|
}
|
|
|
|
// each packet has 2 buffer descriptors
|
|
segp->RcvPktBuffDescrPoolSize = 2 * RcvPktsPerSegment;
|
|
|
|
NdisAllocateBufferPool (
|
|
&NdisStatus,
|
|
&segp->RcvPktBuffDescrPoolHandle,
|
|
segp->RcvPktBuffDescrPoolSize);
|
|
|
|
if(NdisStatus != NDIS_STATUS_SUCCESS) {
|
|
|
|
NdisFreePacketPool(segp->RcvPktDescrPoolHandle);
|
|
CTEFreeMem(segp);
|
|
return NULL;
|
|
}
|
|
|
|
// Make the list of packets
|
|
for(i=0, buffp=segp->DataBuffer; i<RcvPktsPerSegment; i++) {
|
|
|
|
if(pktp = CreateRcvPkt(buffp, segp)) {
|
|
|
|
// enqueue this packet in the segment control block
|
|
InsertTailList(&segp->PacketList, &pktp->PacketLinkage);
|
|
segp->AvailablePktCount++;
|
|
|
|
buffp += UlongMaxFrameSize;
|
|
}
|
|
else
|
|
{
|
|
DbgBreakPoint();
|
|
DestroyRcvPktSegment(segp);
|
|
return NULL;
|
|
}
|
|
}
|
|
|
|
// set up the total packet allocation count for this segment
|
|
segp->MaxPktCount = segp->AvailablePktCount;
|
|
|
|
RtPrint(DBG_RCVPKT, ("IpxRouter: CreateRcvPktSegment: success\n"));
|
|
|
|
return segp;
|
|
}
|
|
|
|
|
|
//***
|
|
//
|
|
// Function: DestroyRcvPktSegment
|
|
//
|
|
// Descr: Dequeues the pkt descr and
|
|
// buff descriptors to their respective pools.
|
|
// Frees the memory buffer.
|
|
//
|
|
// Params: Segment ptr
|
|
//
|
|
// Returns: none
|
|
//
|
|
//***
|
|
|
|
VOID
|
|
DestroyRcvPktSegment(PRCVPKT_SEGMENT segp)
|
|
{
|
|
PLIST_ENTRY lep;
|
|
PPACKET_TAG pktp;
|
|
|
|
RtPrint(DBG_RCVPKT, ("IpxRouter: DestroyRcvPktSegment: Entered\n"));
|
|
|
|
while(!IsListEmpty(&segp->PacketList)) {
|
|
|
|
lep = RemoveHeadList(&segp->PacketList);
|
|
pktp = CONTAINING_RECORD(lep, PACKET_TAG, PacketLinkage);
|
|
DestroyRcvPkt(pktp);
|
|
}
|
|
|
|
// deallocate the buff descr pool and packet descr pool
|
|
NdisFreeBufferPool(segp->RcvPktBuffDescrPoolHandle);
|
|
NdisFreePacketPool(segp->RcvPktDescrPoolHandle);
|
|
|
|
CTEFreeMem(segp);
|
|
}
|
|
|
|
//***
|
|
//
|
|
// Function: CreateRcvPkt
|
|
//
|
|
// Descr: allocates a pkt descr and 2 buff descr
|
|
// makes the necessary chains
|
|
//
|
|
// Params: data buffer ptr
|
|
//
|
|
// Returns: prt to packet or null is failure
|
|
//
|
|
//***
|
|
|
|
PPACKET_TAG
|
|
CreateRcvPkt(PULONG buffp,
|
|
PRCVPKT_SEGMENT segp)
|
|
{
|
|
NDIS_STATUS NdisStatus;
|
|
PNDIS_PACKET NdisPacket;
|
|
PNDIS_BUFFER NdisDataBuffer;
|
|
PNDIS_BUFFER NdisMacBuffer;
|
|
UINT bufflen;
|
|
PPACKET_TAG pktp;
|
|
|
|
RtPrint(DBG_RCVPKT, ("IpxRouter: CreateRcvPkt: Entered\n"));
|
|
|
|
bufflen = UlongMaxFrameSize * sizeof(ULONG);
|
|
|
|
NdisAllocatePacket(&NdisStatus,
|
|
&NdisPacket,
|
|
segp->RcvPktDescrPoolHandle);
|
|
|
|
if(NdisStatus != NDIS_STATUS_SUCCESS) {
|
|
|
|
return NULL;
|
|
}
|
|
|
|
pktp = (PPACKET_TAG)&NdisPacket->ProtocolReserved;
|
|
RtlZeroMemory(pktp, sizeof(PACKET_TAG));
|
|
|
|
NdisAllocateBuffer(&NdisStatus,
|
|
&NdisDataBuffer,
|
|
segp->RcvPktBuffDescrPoolHandle,
|
|
buffp,
|
|
bufflen);
|
|
|
|
if(NdisStatus != NDIS_STATUS_SUCCESS) {
|
|
|
|
NdisFreePacket(NdisPacket);
|
|
|
|
return NULL;
|
|
}
|
|
|
|
NdisAllocateBuffer(&NdisStatus,
|
|
&NdisMacBuffer,
|
|
segp->RcvPktBuffDescrPoolHandle,
|
|
pktp->MacHeader,
|
|
MacHeaderNeeded);
|
|
|
|
if(NdisStatus != NDIS_STATUS_SUCCESS) {
|
|
|
|
NdisFreePacket(NdisPacket);
|
|
NdisFreeBuffer(NdisDataBuffer);
|
|
|
|
return NULL;
|
|
}
|
|
|
|
NdisChainBufferAtFront(NdisPacket, NdisDataBuffer);
|
|
pktp->Identifier = IDENTIFIER_RIP;
|
|
pktp->ReservedPvoid[0] = NULL;
|
|
pktp->ReservedPvoid[1] = NULL;
|
|
pktp->PacketType = RCV_PACKET;
|
|
pktp->RcvPktSegmentp = segp;
|
|
pktp->DataBufferp = (PUCHAR)buffp;
|
|
pktp->DataBufferLength = bufflen;
|
|
pktp->HeaderBuffDescrp = NdisMacBuffer;
|
|
|
|
return pktp;
|
|
}
|
|
|
|
//***
|
|
//
|
|
// Function: DestroyRcvPkt
|
|
//
|
|
// Descr: deallocates a pkt descr and 2 buff descr
|
|
// unmakes the necessary chains
|
|
//
|
|
// Params: Packet
|
|
//
|
|
// Returns: none
|
|
//
|
|
//***
|
|
|
|
VOID
|
|
DestroyRcvPkt(PPACKET_TAG pktp)
|
|
{
|
|
PNDIS_PACKET NdisPacket;
|
|
PNDIS_BUFFER NdisBuffer;
|
|
|
|
RtPrint(DBG_RCVPKT, ("IpxRouter: DestroyRcvPkt: Entered\n"));
|
|
|
|
NdisPacket = CONTAINING_RECORD(pktp, NDIS_PACKET, ProtocolReserved);
|
|
|
|
// free the data buffer descr
|
|
NdisUnchainBufferAtBack (NdisPacket, &NdisBuffer);
|
|
if (NdisBuffer != NULL) {
|
|
NdisFreeBuffer (NdisBuffer);
|
|
}
|
|
else
|
|
{
|
|
// !!! break
|
|
DbgBreakPoint();
|
|
}
|
|
|
|
// free the mac hdr buff descr
|
|
NdisFreeBuffer(pktp->HeaderBuffDescrp);
|
|
|
|
NdisFreePacket(NdisPacket);
|
|
}
|
|
|
|
//***
|
|
//
|
|
// Function: AllocateRcvPkt
|
|
//
|
|
// Descr: Tries to do the allocation starting with the FIRST available
|
|
// segment.
|
|
// If no available segments, tries to allocate one.
|
|
// Decrements available pkts counter and resets scavenger's tick
|
|
// count. Sets the packet tag rcv pool array ptr to this segment.
|
|
// HOLDS THE LOCK until done.
|
|
//
|
|
// Params: NicCbp to charge
|
|
//
|
|
// Returns: Packet or NULL if the rcv pkt pool array is empty.
|
|
//
|
|
//***
|
|
|
|
PPACKET_TAG
|
|
AllocateRcvPkt(PNICCB niccbp)
|
|
{
|
|
PLIST_ENTRY nextp;
|
|
PRCVPKT_SEGMENT segp;
|
|
PPACKET_TAG pktp;
|
|
USHORT NicId;
|
|
PLIST_ENTRY lep;
|
|
UINT FreeRcvPktCount = 0; // how many pkts are available in the
|
|
// pool
|
|
|
|
NicId = niccbp->NicId;
|
|
|
|
ACQUIRE_SPIN_LOCK(&RcvPktSegListLock);
|
|
|
|
// walk the segments list until we find a segment with available pkts
|
|
nextp = RcvPktSegList.Flink;
|
|
|
|
while(nextp != &RcvPktSegList) {
|
|
|
|
segp = CONTAINING_RECORD(nextp, RCVPKT_SEGMENT, SegmentLinkage);
|
|
if(segp->AvailablePktCount) {
|
|
|
|
goto allocation_ok;
|
|
}
|
|
nextp = segp->SegmentLinkage.Flink;
|
|
}
|
|
|
|
// pool is empty, check if we can create a new segment
|
|
if(RcvPktCount >= MaxRcvPktCount) {
|
|
|
|
// we can't allocate anything
|
|
goto allocation_failure;
|
|
}
|
|
|
|
// we can allocate a new segment
|
|
if((segp = CreateRcvPktSegment()) == NULL) {
|
|
|
|
// we are beyond salvation !!! break
|
|
goto allocation_failure;
|
|
}
|
|
|
|
// increment the segment count
|
|
RcvPktSegCount++;
|
|
|
|
// add the new segment to the pool
|
|
InsertTailList(&RcvPktSegList, &segp->SegmentLinkage);
|
|
|
|
// and increment the global allocation counter
|
|
RcvPktCount += segp->AvailablePktCount;
|
|
|
|
allocation_ok:
|
|
|
|
RtPrint(DBG_RCVPKT, ("IpxRouter: AllocateRcvPkt: OK\n"));
|
|
|
|
lep = RemoveHeadList(&segp->PacketList);
|
|
pktp = CONTAINING_RECORD(lep, PACKET_TAG, PacketLinkage);
|
|
|
|
ASSERT(pktp != NULL);
|
|
|
|
segp->AvailablePktCount--;
|
|
|
|
// reset the segment aging timer
|
|
segp->AgingTimer = 0;
|
|
|
|
// charge the nic for this allocation
|
|
RcvPktPerNicCount[NicId]++;
|
|
|
|
// set the nic owner in the packet
|
|
pktp->PacketOwnerNicCbp = niccbp;
|
|
|
|
// set the packet type
|
|
pktp->PacketType = RCV_PACKET;
|
|
|
|
// before we return the packet, we check if we have hit the low packet
|
|
// count and, if true, queue a work item to allocate a new segment
|
|
CheckAllocationAhead();
|
|
|
|
// return the packet
|
|
|
|
// update statistics
|
|
StatMemAllocCount++;
|
|
|
|
if(StatMemPeakCount < StatMemAllocCount) {
|
|
|
|
StatMemPeakCount = StatMemAllocCount;
|
|
}
|
|
|
|
RELEASE_SPIN_LOCK(&RcvPktSegListLock);
|
|
|
|
return pktp;
|
|
|
|
allocation_failure:
|
|
|
|
RtPrint(DBG_RCVPKT, ("IpxRouter: AllocateRcvPkt: Failure\n"));
|
|
|
|
RELEASE_SPIN_LOCK(&RcvPktSegListLock);
|
|
|
|
return NULL;
|
|
}
|
|
|
|
//***
|
|
//
|
|
// Function: FreeRcvPkt
|
|
//
|
|
// Descr: Inserts the rcv pkt in the respective list and increments the
|
|
// available pkts counter for this pool segment.
|
|
// HOLDS the lock until done.
|
|
//
|
|
// Params: Packet
|
|
//
|
|
// Returns: none
|
|
//
|
|
//***
|
|
|
|
VOID
|
|
FreeRcvPkt(PPACKET_TAG pktp)
|
|
{
|
|
PRCVPKT_SEGMENT segp;
|
|
|
|
#if DBG
|
|
PRCVPKT_SEGMENT walksegp;
|
|
PLIST_ENTRY nextp;
|
|
#endif // DBG
|
|
|
|
USHORT NicId;
|
|
|
|
RtPrint(DBG_RCVPKT, ("IpxRouter: FreeRcvPkt: Entered\n"));
|
|
|
|
ACQUIRE_SPIN_LOCK(&RcvPktSegListLock);
|
|
|
|
// update statistics
|
|
StatMemAllocCount--;
|
|
|
|
// discharge the Nic
|
|
NicId = pktp->PacketOwnerNicCbp->NicId;
|
|
RcvPktPerNicCount[NicId]--;
|
|
|
|
// get the packet segment
|
|
segp = pktp->RcvPktSegmentp;
|
|
|
|
#if DBG
|
|
|
|
{
|
|
// check that this segment is indeed in our list by walking the list
|
|
BOOLEAN ValidSegment = FALSE;
|
|
|
|
nextp = RcvPktSegList.Flink;
|
|
|
|
while(nextp != &RcvPktSegList) {
|
|
|
|
walksegp = CONTAINING_RECORD(nextp, RCVPKT_SEGMENT, SegmentLinkage);
|
|
if(nextp == &segp->SegmentLinkage) {
|
|
|
|
ValidSegment = TRUE;
|
|
break;
|
|
}
|
|
nextp = walksegp->SegmentLinkage.Flink;
|
|
}
|
|
|
|
ASSERT(ValidSegment == TRUE);
|
|
}
|
|
#endif
|
|
|
|
// put packet back into the segment list
|
|
InsertTailList(&segp->PacketList, &pktp->PacketLinkage);
|
|
|
|
// increment the available pkts count for this segment
|
|
segp->AvailablePktCount++;
|
|
|
|
ASSERT(segp->AvailablePktCount <= segp->MaxPktCount);
|
|
|
|
RELEASE_SPIN_LOCK(&RcvPktSegListLock);
|
|
|
|
return;
|
|
}
|
|
|
|
//***
|
|
//
|
|
// Function: RcvPktPoolScavenger
|
|
//
|
|
// Descr: Entered every 2 sec as a timer DPC.
|
|
// Increments the scavenger tick count for the segment at the
|
|
// tail. If the tick count reaches 3 (6 secs not used) destroys
|
|
// the segment.
|
|
// The scavenger does not act on the FIRST segment.
|
|
// HOLDS THE LOCK until done
|
|
//
|
|
//
|
|
// Params: none
|
|
//
|
|
// Returns: none
|
|
//
|
|
//***
|
|
|
|
VOID
|
|
RcvPktPoolScavenger(VOID)
|
|
{
|
|
PRCVPKT_SEGMENT segp;
|
|
PLIST_ENTRY lastep;
|
|
|
|
// RtPrint(DBG_RCVPKT, ("IpxRouter: Pool scavenger: pool has %d segmentst\n", RcvPktSegCount));
|
|
|
|
ACQUIRE_SPIN_LOCK(&RcvPktSegListLock);
|
|
|
|
ASSERT(RcvPktSegCount);
|
|
|
|
if(RcvPktSegCount == 1) {
|
|
|
|
RELEASE_SPIN_LOCK(&RcvPktSegListLock);
|
|
|
|
return;
|
|
}
|
|
|
|
// get to the last segment in the list
|
|
lastep = RcvPktSegList.Blink;
|
|
segp = CONTAINING_RECORD(lastep, RCVPKT_SEGMENT, SegmentLinkage);
|
|
|
|
// check if all packets are returned to the segment
|
|
if(segp->AvailablePktCount == segp->MaxPktCount) {
|
|
|
|
// we can age this segment
|
|
if(segp->AgingTimer++ >= 3) {
|
|
|
|
// this segment too old and may be deleted
|
|
RtPrint(DBG_RCVPKT, ("IpxRouter: Pool scavenger: pool has %d segments, will destroy the last\n",
|
|
RcvPktSegCount));
|
|
|
|
RemoveEntryList(&segp->SegmentLinkage);
|
|
RcvPktSegCount--;
|
|
RcvPktCount -= segp->MaxPktCount;
|
|
|
|
DestroyRcvPktSegment(segp);
|
|
}
|
|
}
|
|
|
|
RELEASE_SPIN_LOCK(&RcvPktSegListLock);
|
|
|
|
return;
|
|
}
|
|
|
|
//***
|
|
//
|
|
// Function: AllocAhead
|
|
//
|
|
// Descr:
|
|
//
|
|
//***
|
|
|
|
VOID
|
|
AllocAhead(PVOID Parameter)
|
|
{
|
|
PRCVPKT_SEGMENT segp;
|
|
|
|
RtPrint(DBG_RCVPKT, ("IpxRouter: AllocAhead: Entered\n"));
|
|
|
|
ACQUIRE_SPIN_LOCK(&RcvPktSegListLock);
|
|
|
|
// check if we can create a new segment
|
|
if(RcvPktCount >= MaxRcvPktCount) {
|
|
|
|
// we can't allocate anything
|
|
goto aa_exit;
|
|
}
|
|
|
|
// we can allocate a new segment
|
|
if((segp = CreateRcvPktSegment()) == NULL) {
|
|
|
|
// we are beyond salvation !!! break
|
|
goto aa_exit;
|
|
}
|
|
|
|
// increment the segment count
|
|
RcvPktSegCount++;
|
|
|
|
// add the new segment to the pool
|
|
InsertTailList(&RcvPktSegList, &segp->SegmentLinkage);
|
|
|
|
// and increment the global allocation counter
|
|
RcvPktCount += segp->AvailablePktCount;
|
|
|
|
aa_exit:
|
|
|
|
AllocAheadState = ALLOC_AHEAD_IDLE;
|
|
|
|
RELEASE_SPIN_LOCK(&RcvPktSegListLock);
|
|
}
|
|
|
|
VOID
|
|
CheckAllocationAhead(VOID)
|
|
{
|
|
UINT FreeRcvPktsCount = 0;
|
|
PLIST_ENTRY nextp;
|
|
PRCVPKT_SEGMENT segp;
|
|
|
|
// get the total number of free packets in the pool and check if we
|
|
// are at our low count
|
|
nextp = RcvPktSegList.Flink;
|
|
|
|
while(nextp != &RcvPktSegList) {
|
|
|
|
segp = CONTAINING_RECORD(nextp, RCVPKT_SEGMENT, SegmentLinkage);
|
|
FreeRcvPktsCount += segp->AvailablePktCount;
|
|
nextp = segp->SegmentLinkage.Flink;
|
|
}
|
|
|
|
if((FreeRcvPktsCount <= LowRcvPktsCount) &&
|
|
(AllocAheadState == ALLOC_AHEAD_IDLE)) {
|
|
|
|
ExQueueWorkItem(&AllocAheadWorkItem, CriticalWorkQueue);
|
|
AllocAheadState = ALLOC_AHEAD_ACTIVE;
|
|
}
|
|
}
|
|
|
|
BOOLEAN
|
|
IsRcvPktResourceFree(PNICCB niccbp)
|
|
{
|
|
USHORT NicId;
|
|
BOOLEAN res_free = FALSE;
|
|
|
|
NicId = niccbp->NicId;
|
|
|
|
ACQUIRE_SPIN_LOCK(&RcvPktSegListLock);
|
|
|
|
if(!RcvPktPerNicCount[NicId]) {
|
|
|
|
res_free = TRUE;
|
|
}
|
|
|
|
RELEASE_SPIN_LOCK(&RcvPktSegListLock);
|
|
|
|
return res_free;
|
|
}
|