⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 nic_recv.c

📁 plx9054的WDM驱动程序
💻 C
📖 第 1 页 / 共 2 页
字号:
/*++

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 + -