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

📄 nic_send.c

📁 ddk开发pci范例,使用9054芯片
💻 C
📖 第 1 页 / 共 2 页
字号:
/*++
Routine Description:

    NIC specific send handler
    Assumption: Send spinlock has been acquired 

Arguments:

    FdoData     Pointer to our FdoData
    pMpTcb      Pointer to MP_TCB
    pFragList   The pointer to the frag list to be filled

Return Value:

    NTSTATUS code

--*/
{
    NTSTATUS    status;
    ULONG       index;
    UCHAR       TbdCount = 0;

    PHW_TCB      pHwTcb = pMpTcb->HwTcb;
    PTBD_STRUC   pHwTbd = pMpTcb->HwTbd;

    DebugPrint(TRACE, DBG_WRITE, "--> NICSendPacket\n");

    for (index = 0; index < pFragList->NumberOfElements; index++)
    {
        if (pFragList->Elements[index].Length)
        {
            pHwTbd->TbdBufferAddress = pFragList->Elements[index].Address.LowPart;
            pHwTbd->TbdCount = pFragList->Elements[index].Length;

            pHwTbd++;                    
            TbdCount++;   
        }
    }

    pHwTcb->TxCbHeader.CbStatus = 0;
    pHwTcb->TxCbHeader.CbCommand = CB_S_BIT | CB_TRANSMIT | CB_TX_SF_BIT;

    pHwTcb->TxCbTbdPointer = pMpTcb->HwTbdPhys;
    pHwTcb->TxCbTbdNumber = TbdCount;
    pHwTcb->TxCbCount = 0;
    pHwTcb->TxCbThreshold = (UCHAR) FdoData->AiThreshold;

   
    status = NICStartSend(FdoData, pMpTcb);
    if(!NT_SUCCESS(status)){
        DebugPrint(ERROR, DBG_WRITE, "NICStartSend returned error %x\n", status);
    }
    
    DebugPrint(TRACE, DBG_WRITE, "<-- NICSendPacket\n");

    return status;
}

NTSTATUS 
NICStartSend(
    IN  PFDO_DATA  FdoData,
    IN  PMP_TCB    pMpTcb
    )
/*++
Routine Description:

    Issue a send command to the NIC
    Assumption: Send spinlock has been acquired 

Arguments:

    FdoData     Pointer to our FdoData
    pMpTcb      Pointer to MP_TCB

Return Value:

    NTSTATUS code

--*/
{
    NTSTATUS     status;

    DebugPrint(TRACE, DBG_WRITE, "--> NICStartSend\n");

    //
    // If the transmit unit is idle (very first transmit) then we must
    // setup the general pointer and issue a full CU-start
    //
    if (FdoData->TransmitIdle)
    {
        
        DebugPrint(TRACE, DBG_WRITE, "CU is idle -- First TCB added to Active List\n");

        //
        // Wait for the SCB to clear before we set the general pointer
        //
        if (!WaitScb(FdoData))
        {
            DebugPrint(ERROR, DBG_WRITE, "NICStartSend -- WaitScb returned error\n");
            status = STATUS_DEVICE_DATA_ERROR;
            goto exit;
        }

        //
        // Don't try to start the transmitter if the command unit is not
        // idle ((not idle) == (Cu-Suspended or Cu-Active)).
        //
        if ((FdoData->CSRAddress->ScbStatus & SCB_CUS_MASK) != SCB_CUS_IDLE)
        {
            DebugPrint(ERROR, DBG_WRITE, "FdoData = %p, CU Not IDLE\n", FdoData);
            MP_SET_HARDWARE_ERROR(FdoData);
            KeStallExecutionProcessor(25);
        }

        FdoData->CSRAddress->ScbGeneralPointer = pMpTcb->HwTcbPhys;

        status = D100IssueScbCommand(FdoData, SCB_CUC_START, FALSE);

        FdoData->TransmitIdle = FALSE;
        FdoData->ResumeWait = TRUE;
    }
    else
    {
        //
        // If the command unit has already been started, then append this
        // TCB onto the end of the transmit chain, and issue a CU-Resume.
        //
        DebugPrint(LOUD, DBG_WRITE, "adding TCB to Active chain\n");

        //
        // Clear the suspend bit on the previous packet.
        //
        pMpTcb->PrevHwTcb->TxCbHeader.CbCommand &= ~CB_S_BIT;

        //
        // Issue a CU-Resume command to the device.  We only need to do a
        // WaitScb if the last command was NOT a RESUME.
        //
        status = D100IssueScbCommand(FdoData, SCB_CUC_RESUME, FdoData->ResumeWait);
    }

    exit:
                      
    DebugPrint(TRACE, DBG_WRITE, "<-- NICStartSend\n");

    return status;
}

NTSTATUS 
NICHandleSendInterrupt(
    IN  PFDO_DATA  FdoData
    )
/*++
Routine Description:

    Interrupt handler for sending processing. Re-claim the send resources, 
    complete sends and get more to send from the send wait queue.
    
    Assumption: Send spinlock has been acquired 

Arguments:

    FdoData     Pointer to our FdoData

Return Value:

    NTSTATUS code

--*/
{
    NTSTATUS        status = STATUS_SUCCESS;
    PMP_TCB         pMpTcb;

#if DBG
    LONG            i;
#endif

    DebugPrint(TRACE, DBG_WRITE, "---> NICHandleSendInterrupt\n");

    //
    // Any packets being sent? Any packet waiting in the send queue?
    //
    if (FdoData->nBusySend == 0 &&
        IsListEmpty(&FdoData->SendQueueHead))
    {
        ASSERT(FdoData->CurrSendHead == FdoData->CurrSendTail);
        DebugPrint(TRACE, DBG_WRITE, "<--- NICHandleSendInterrupt\n");
        return status;
    }

    //
    // Check the first TCB on the send list
    //
    while (FdoData->nBusySend > 0)
    {

#if DBG
        pMpTcb = FdoData->CurrSendHead;
        for (i = 0; i < FdoData->nBusySend; i++)
        {
            pMpTcb = pMpTcb->Next;   
        }

        if (pMpTcb != FdoData->CurrSendTail)
        {
            DebugPrint(ERROR, DBG_WRITE, "nBusySend= %d\n", FdoData->nBusySend);
            DebugPrint(ERROR, DBG_WRITE, "CurrSendhead= %p\n", FdoData->CurrSendHead);
            DebugPrint(ERROR, DBG_WRITE, "CurrSendTail= %p\n", FdoData->CurrSendTail);
            ASSERT(FALSE);
        }
#endif      

        pMpTcb = FdoData->CurrSendHead;

        //
        // Is this TCB completed?
        //
        if (pMpTcb->HwTcb->TxCbHeader.CbStatus & CB_STATUS_COMPLETE)
        {
            //
            // Check if this is a multicast hw workaround packet
            //
            if ((pMpTcb->HwTcb->TxCbHeader.CbCommand & CB_CMD_MASK) != CB_MULTICAST)
            {
                MP_FREE_SEND_PACKET(FdoData, pMpTcb, STATUS_SUCCESS);
                
            } else {
                ASSERTMSG("Not sure what to do", FALSE);
            }
        }
        else
        {
            break;
        }
    }

    //
    // If we queued any transmits because we didn't have any TCBs earlier,
    // dequeue and send those packets now, as long as we have free TCBs.
    //
    while (!IsListEmpty(&FdoData->SendQueueHead) &&
        MP_TCB_RESOURCES_AVAIABLE(FdoData))
    {
        PIRP irp;
        PLIST_ENTRY pEntry; 
                   
        pEntry = RemoveHeadList(&FdoData->SendQueueHead); 
        
        ASSERT(pEntry);
        
        FdoData->nWaitSend--;

        irp = CONTAINING_RECORD(pEntry, IRP, Tail.Overlay.ListEntry);
        DebugPrint(LOUD, DBG_WRITE, "NICHandleSendInterrupt - send a queued packet\n");
        
        NICWritePacket(FdoData, irp, TRUE);
    }

    DebugPrint(TRACE, DBG_WRITE, "<--- NICHandleSendInterrupt\n");
    return status;
}

VOID
NICCompleteSendRequest(
    IN PFDO_DATA   FdoData,
    IN PIRP        Irp,
    IN NTSTATUS    Status,
    IN ULONG       Information,
    IN BOOLEAN     AtDispatchLevel
    )
/*++
Routine Description:

    This routine complete the IRP and free all the resources associated
    with the IRP. This function can be called at passive or dispatch
    level. 
    
Arguments:

    FdoData - Pointer to the device context.
    Irp     - Pointer to the write request.
    Status  - Final completion status of the IRP
    Information - Value to be set in the information field of the IRP
    AtDispatchLevel - Raising IRQL is as expensive as checking the current
                IRQL level. So, this parameter enables us to know the caller's
                current IRQL level and avoid raising and lowering IRQL 
                unnecessarily.
    
Return Value:

    VOID
    
--*/
{
    PSCATTER_GATHER_LIST sgl = Irp->Tail.Overlay.DriverContext[3];
    PVOID    sglBuffer = Irp->Tail.Overlay.DriverContext[2];    
    KIRQL oldIrql;

    DebugPrint(TRACE, DBG_WRITE, "NICCompleteSendRequest, Pkt= %p Sgl %p\n", 
                            Irp,
                            sgl);        

    
    if(sgl){
        //
        // Since PutScatterGatherList must be called at DISPATCH_LEVEL,
        // raise the IRQL if we are not at that level. 
        //
        if(!AtDispatchLevel) {        
            KeRaiseIrql(DISPATCH_LEVEL, &oldIrql);
        }
        
        ASSERT(FdoData->DmaAdapterObject);
        FdoData->DmaAdapterObject->DmaOperations->PutScatterGatherList(
                                FdoData->DmaAdapterObject,
                                sgl,
                                TRUE);

        if(!AtDispatchLevel) {                
            KeLowerIrql(oldIrql);
        }
    }

    if(sglBuffer){
        ExFreeToNPagedLookasideList(&FdoData->SGListLookasideList, sglBuffer);
    }
    
    Irp->Tail.Overlay.DriverContext[3] = NULL;
    Irp->Tail.Overlay.DriverContext[2] = NULL;
    
    Irp->IoStatus.Information = Information;
    Irp->IoStatus.Status = Status;
    IoCompleteRequest(Irp, IO_NO_INCREMENT);
    PciDrvIoDecrement (FdoData);
    
}

VOID
NICFreeBusySendPackets(
    IN  PFDO_DATA  FdoData
    )
/*++
Routine Description:

    Free and complete the stopped active sends
    Assumption: Send spinlock has been acquired 
    
Arguments:

    FdoData     Pointer to our FdoData

Return Value:

     None

--*/
{
    PMP_TCB     pMpTcb;
    NTSTATUS    status = MP_GET_STATUS_FROM_FLAGS(FdoData);

    DebugPrint(TRACE, DBG_WRITE, "--> NICFreeBusySendPackets\n");

    //
    // Any packets being sent? Check the first TCB on the send list
    //
    while (FdoData->nBusySend > 0)
    {
        pMpTcb = FdoData->CurrSendHead;

        //
        // Is this TCB completed?
        //
        if ((pMpTcb->HwTcb->TxCbHeader.CbCommand & CB_CMD_MASK) != CB_MULTICAST)
        {
            MP_FREE_SEND_PACKET(FdoData, pMpTcb, status);
        }
        else
        {
            break;
        }
    }

    DebugPrint(TRACE, DBG_WRITE, "<-- NICFreeBusySendPackets\n");
}


VOID 
NICFreeQueuedSendPackets(
    IN  PFDO_DATA  FdoData
    )
/*++
Routine Description:

    Free and complete the pended sends on SendQueueHead
    Assumption: spinlock has been acquired 
    
Arguments:

    FdoData     Pointer to our FdoData

Return Value:

     None

--*/
{
    PLIST_ENTRY     pEntry;
    PIRP            irp;
    NTSTATUS        status = MP_GET_STATUS_FROM_FLAGS(FdoData);

    DebugPrint(TRACE, DBG_WRITE, "--> NICFreeQueuedSendPackets\n");

    while (!IsListEmpty(&FdoData->SendQueueHead))
    {
        pEntry = RemoveHeadList(&FdoData->SendQueueHead); 
        FdoData->nWaitSend--;
        KeReleaseSpinLockFromDpcLevel(&FdoData->SendLock);

        ASSERT(pEntry);
        irp = CONTAINING_RECORD(pEntry, IRP, Tail.Overlay.ListEntry);
        
        NICCompleteSendRequest(FdoData, irp, status, 0, TRUE); 
        

        KeAcquireSpinLockAtDpcLevel(&FdoData->SendLock);
    }

    DebugPrint(TRACE, DBG_WRITE, "<-- NICFreeQueuedSendPackets\n");

}

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -