VOID NICFreeBusySendPackets( IN PFDO_DATA FdoData ) /*++ Routine Description: Free and complete the stopped active sends Assumption: This function is called with the Send SPINLOCK held. Arguments: FdoData Pointer to our FdoData Return Value: None --*/ { PMP_TCB pMpTcb; TraceEvents(TRACE_LEVEL_VERBOSE, 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_SUCCESS); } else { break; } } TraceEvents(TRACE_LEVEL_VERBOSE, DBG_WRITE, "<-- NICFreeBusySendPackets\n"); }
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"); }
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: This function is called with the Send SPINLOCK held. Arguments: FdoData Pointer to our FdoData Return Value: NTSTATUS code --*/ { NTSTATUS status = STATUS_SUCCESS; PMP_TCB pMpTcb; BOOLEAN transactionComplete; #if DBG ULONG i; #endif TraceEvents(TRACE_LEVEL_VERBOSE, DBG_WRITE, "--> NICHandleSendInterrupt\n"); // // Any packets being sent? Any packet waiting in the send queue? // if (FdoData->nBusySend == 0) { ASSERT(FdoData->CurrSendHead == FdoData->CurrSendTail); 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) { TraceEvents(TRACE_LEVEL_ERROR, DBG_WRITE, "nBusySend= %d\n", FdoData->nBusySend); TraceEvents(TRACE_LEVEL_ERROR, DBG_WRITE, "CurrSendhead= %p\n", FdoData->CurrSendHead); TraceEvents(TRACE_LEVEL_ERROR, DBG_WRITE, "CurrSendTail= %p\n", FdoData->CurrSendTail); ASSERT(FALSE); } #endif pMpTcb = FdoData->CurrSendHead; ASSERT(pMpTcb->DmaTransaction); // // Indicate this DMA operation has completed: // This may drive the transfer on the next packet if // there is still data to be transfered in the DmaTransaction. // transactionComplete = WdfDmaTransactionDmaCompleted( pMpTcb->DmaTransaction, &status ); if(transactionComplete == TRUE) { ASSERT(status == STATUS_SUCCESS); MP_FREE_SEND_PACKET(FdoData, pMpTcb, status); } else { // // NOTE: For this ethernet driver this should never // be returned as the packets are <= 1514 bytes. // It is included to show the complete DmaTransaction // coding pattern. // ASSERT(!"STATUS_MORE_PROCESSING_REQUIRED"); } } TraceEvents(TRACE_LEVEL_VERBOSE, DBG_WRITE, "<-- NICHandleSendInterrupt\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 NICWritePacket( __in PFDO_DATA FdoData, __in PIRP Irp, __in BOOLEAN bFromQueue ) /*++ Routine Description: Do the work to send a packet Assumption: Send spinlock has been acquired Arguments: FdoData Pointer to our FdoData Packet The packet bFromQueue TRUE if it's taken from the send wait queue Return Value: --*/ { PMP_TCB pMpTcb = NULL; ULONG packetLength; PVOID virtualAddress; DebugPrint(TRACE, DBG_WRITE, "--> NICWritePacket, Irp= %p\n", Irp); // // Get the next free TCB and initialize it to represent the // request buffer. // pMpTcb = FdoData->CurrSendTail; ASSERT(!MP_TEST_FLAG(pMpTcb, fMP_TCB_IN_USE)); // // If the adapter is not ready, fail the request. // if(MP_IS_NOT_READY(FdoData)) { MP_FREE_SEND_PACKET(FdoData, pMpTcb, STATUS_DEVICE_NOT_READY); return; } pMpTcb->FirstBuffer = Irp->MdlAddress; virtualAddress = MmGetMdlVirtualAddress(Irp->MdlAddress); pMpTcb->BufferCount = 1; pMpTcb->PacketLength = packetLength = MmGetMdlByteCount(Irp->MdlAddress); pMpTcb->PhysBufCount = ADDRESS_AND_SIZE_TO_SPAN_PAGES(virtualAddress, packetLength); pMpTcb->Irp = Irp; MP_SET_FLAG(pMpTcb, fMP_TCB_IN_USE); // // Call the send handler, it only needs to deal with the frag list // NICSendPacket(FdoData, pMpTcb, Irp->Tail.Overlay.DriverContext[3]); FdoData->nBusySend++; ASSERT(FdoData->nBusySend <= FdoData->NumTcb); FdoData->CurrSendTail = FdoData->CurrSendTail->Next; DebugPrint(TRACE, DBG_WRITE, "<-- NICWritePacket\n"); return; }