📄 nic_recv.c
字号:
/*++
Copyright (c) Microsoft Corporation. All rights reserved.
THIS CODE AND INFORMATION IS PROVIDED "AS IS" WITHOUT WARRANTY OF ANY
KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE
IMPLIED WARRANTIES OF MERCHANTABILITY AND/OR FITNESS FOR A PARTICULAR
PURPOSE.
Module Name:
NIC_RECV.C
Abstract:
This module contains miniport receive routines
Environment:
Kernel mode
Revision History:
DChen 11-01-99 created
EliyasY Feb 13, 2003 converted to WDM
--*/
#include "precomp.h"
#if defined(EVENT_TRACING)
#include "nic_recv.tmh"
#endif
VOID
NICHandleRecvInterrupt(
IN PFDO_DATA FdoData
)
/*++
Routine Description:
Interrupt handler for receive processing. Put the received packets
into an array and call NICServiceReadIrps. If we run low on
RFDs, allocate another one.
Assumption: Rcv spinlock has been acquired
Arguments:
FdoData Pointer to our FdoData
Return Value:
None
--*/
{
PMP_RFD pMpRfd = NULL;
PHW_RFD pHwRfd = NULL;
PMP_RFD PacketArray[NIC_DEF_RFDS];
PMP_RFD PacketFreeArray[NIC_DEF_RFDS];
UINT PacketArrayCount;
UINT PacketFreeCount;
UINT Index;
UINT LoopIndex = 0;
UINT LoopCount = NIC_MAX_RFDS / NIC_DEF_RFDS + 1; // avoid staying here too long
BOOLEAN bContinue = TRUE;
BOOLEAN bAllocNewRfd = FALSE;
USHORT PacketStatus;
DebugPrint(TRACE, DBG_READ, "---> NICHandleRecvInterrupt\n");
ASSERT(FdoData->nReadyRecv >= NIC_MIN_RFDS);
while (LoopIndex++ < LoopCount && bContinue)
{
PacketArrayCount = 0;
PacketFreeCount = 0;
//
// Process up to the array size RFD's
//
while (PacketArrayCount < NIC_DEF_RFDS)
{
if (IsListEmpty(&FdoData->RecvList))
{
ASSERT(FdoData->nReadyRecv == 0);
bContinue = FALSE;
break;
}
//
// Get the next MP_RFD to process
//
pMpRfd = (PMP_RFD)GetListHeadEntry(&FdoData->RecvList);
//
// Get the associated HW_RFD
//
pHwRfd = pMpRfd->HwRfd;
//
// Is this packet completed?
//
PacketStatus = NIC_RFD_GET_STATUS(pHwRfd);
if (!NIC_RFD_STATUS_COMPLETED(PacketStatus))
{
bContinue = FALSE;
break;
}
//
// HW specific - check if actual count field has been updated
//
if (!NIC_RFD_VALID_ACTUALCOUNT(pHwRfd))
{
bContinue = FALSE;
break;
}
//
// Remove the RFD from the head of the List
//
RemoveEntryList((PLIST_ENTRY)pMpRfd);
FdoData->nReadyRecv--;
ASSERT(FdoData->nReadyRecv >= 0);
ASSERT(MP_TEST_FLAG(pMpRfd, fMP_RFD_RECV_READY));
MP_CLEAR_FLAG(pMpRfd, fMP_RFD_RECV_READY);
//
// A good packet? drop it if not.
//
if (!NIC_RFD_STATUS_SUCCESS(PacketStatus))
{
DebugPrint(WARNING, DBG_READ, "Receive failure = %x\n", PacketStatus);
NICReturnRFD(FdoData, pMpRfd);
continue;
}
//
// Do not receive any packets until a filter has been set
//
if (!FdoData->PacketFilter)
{
NICReturnRFD(FdoData, pMpRfd);
continue;
}
//
// Do not receive any packets until we are at D0
//
if (FdoData->DevicePowerState != PowerDeviceD0)
{
NICReturnRFD(FdoData, pMpRfd);
continue;
}
pMpRfd->PacketSize = NIC_RFD_GET_PACKET_SIZE(pHwRfd);
KeFlushIoBuffers(pMpRfd->Mdl, TRUE, TRUE);
//
// set the status on the packet, either resources or success
//
if (FdoData->nReadyRecv >= MIN_NUM_RFD)
{
MP_SET_FLAG(pMpRfd, fMP_RFD_RECV_PEND);
//InsertTailList(&FdoData->RecvPendList, (PLIST_ENTRY)pMpRfd); TODO:
//MP_INC_RCV_REF(FdoData);
}
else
{
MP_SET_FLAG(pMpRfd, fMP_RFD_RESOURCES);
PacketFreeArray[PacketFreeCount] = pMpRfd;
PacketFreeCount++;
//
// Reset the RFD shrink count - don't attempt to shrink RFD
//
FdoData->RfdShrinkCount = 0;
//
// Remember to allocate a new RFD later
//
bAllocNewRfd = TRUE;
}
PacketArray[PacketArrayCount] = pMpRfd;
PacketArrayCount++;
//
// Update the number of outstanding Recvs
//
PciDrvIoIncrement(FdoData);
}
//
// if we didn't process any receives, just return from here
//
if (PacketArrayCount == 0)
{
break;
}
KeReleaseSpinLockFromDpcLevel(&FdoData->RcvLock);
KeAcquireSpinLockAtDpcLevel(&FdoData->Lock);
//
// If we have a Recv interrupt and have reported a media disconnect status
// time to indicate the new status
//
if (Disconnected == FdoData->MediaState)
{
DebugPrint(WARNING, DBG_READ, "Media state changed to Connected\n");
MP_CLEAR_FLAG(FdoData, fMP_ADAPTER_NO_CABLE);
FdoData->MediaState = Connected;
KeReleaseSpinLockFromDpcLevel(&FdoData->Lock);
//
// Indicate the media event
//
NICServiceIndicateStatusIrp(FdoData);
}
else
{
KeReleaseSpinLockFromDpcLevel(&FdoData->Lock);
}
NICServiceReadIrps(
FdoData,
PacketArray,
PacketArrayCount);
//
// Return all the RFDs to the pool.
//
KeAcquireSpinLockAtDpcLevel(&FdoData->RcvLock);
for (Index = 0; Index < PacketFreeCount; Index++)
{
//
// Get the MP_RFD saved in this packet, in NICAllocRfd
//
pMpRfd = PacketFreeArray[Index];
ASSERT(MP_TEST_FLAG(pMpRfd, fMP_RFD_RESOURCES));
MP_CLEAR_FLAG(pMpRfd, fMP_RFD_RESOURCES);
NICReturnRFD(FdoData, pMpRfd);
}
}
//
// If we ran low on RFD's, we need to allocate a new RFD
//
if (bAllocNewRfd)
{
//
// Allocate one more RFD only if it doesn't exceed the max RFD limit
//
if (FdoData->CurrNumRfd < FdoData->MaxNumRfd
&& !FdoData->AllocNewRfd)
{
NTSTATUS status;
//
// Increment the IO count to accout for the pending workitem. This
// will prevent us from freeing resources during stop/remove until
// the workitem callback is executed.
//
PciDrvIoIncrement(FdoData);
FdoData->AllocNewRfd = TRUE;
//
// Since we are running at DISPATCH_LEVEL, we will queue a workitem
// to allocate RFD memory at PASSIVE_LEVEL. Note that
// AllocateCommonBuffer and FreeCommonBuffer can be called only at
// PASSIVE_LEVEL.
//
status = PciDrvQueuePassiveLevelCallback(FdoData,
NICAllocRfdWorkItem,
NULL, NULL);
if(!NT_SUCCESS(status)){
PciDrvIoDecrement(FdoData);
FdoData->AllocNewRfd = FALSE;
}
}
}
ASSERT(FdoData->nReadyRecv >= NIC_MIN_RFDS);
DebugPrint(TRACE, DBG_READ, "<--- NICHandleRecvInterrupt\n");
}
VOID
NICReturnRFD(
IN PFDO_DATA FdoData,
IN PMP_RFD pMpRfd
)
/*++
Routine Description:
Recycle a RFD and put it back onto the receive list
Assumption: Rcv spinlock has been acquired
Arguments:
FdoData Pointer to our FdoData
pMpRfd Pointer to the RFD
Return Value:
None
--*/
{
PMP_RFD pLastMpRfd;
PHW_RFD pHwRfd = pMpRfd->HwRfd;
ASSERT(pMpRfd->Flags == 0);
MP_SET_FLAG(pMpRfd, fMP_RFD_RECV_READY);
//
// HW_SPECIFIC_START
//
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -