VOID NICCheckForQueuedSends( IN PFDO_DATA FdoData ) /*++ Routine Description: Arguments: FdoData Pointer to our FdoData Return Value: --*/ { WDFREQUEST request; WDFDMATRANSACTION dmaTransaction; NTSTATUS status; UNREFERENCED_PARAMETER( dmaTransaction ); TraceEvents(TRACE_LEVEL_VERBOSE, DBG_WRITE, "--> NICCheckForQueuedSends\n"); // // 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 (MP_TCB_RESOURCES_AVAIABLE(FdoData)) { status = WdfIoQueueRetrieveNextRequest( FdoData->PendingWriteQueue, &request ); if(!NT_SUCCESS(status) ) { if(STATUS_NO_MORE_ENTRIES != status) { TraceEvents(TRACE_LEVEL_VERBOSE, DBG_WRITE, "WdfIoQueueRetrieveNextRequest failed %X\n", status); } break; } TraceEvents(TRACE_LEVEL_VERBOSE, DBG_WRITE, "\t processing Request %p \n", request); status = NICInitiateDmaTransfer(FdoData, request); if(!NT_SUCCESS(status)) { WdfRequestCompleteWithInformation(request, status, 0); } FdoData->nWaitSend--; } TraceEvents(TRACE_LEVEL_VERBOSE, DBG_WRITE, "<-- NICCheckForQueuedSends\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: 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; }
BOOLEAN NICEvtProgramDmaFunction( IN WDFDMATRANSACTION Transaction, IN WDFDEVICE Device, IN PVOID Context, IN WDF_DMA_DIRECTION Direction, IN PSCATTER_GATHER_LIST ScatterGather ) /*++ Routine Description: Arguments: Return Value: --*/ { PFDO_DATA fdoData; WDFREQUEST request; NTSTATUS status; UNREFERENCED_PARAMETER( Context ); UNREFERENCED_PARAMETER( Direction ); TraceEvents(TRACE_LEVEL_VERBOSE, DBG_WRITE, "--> NICEvtProgramDmaFunction\n"); fdoData = FdoGetData(Device); request = WdfDmaTransactionGetRequest(Transaction); WdfSpinLockAcquire(fdoData->SendLock); // // If tcb or link is not available, queue the request // if (!MP_TCB_RESOURCES_AVAIABLE(fdoData)) { TraceEvents(TRACE_LEVEL_VERBOSE, DBG_WRITE, "Resource is not available: queue Request %p\n", request); // // Must abort the transaction before deleting. // (VOID) WdfDmaTransactionDmaCompletedFinal(Transaction, 0, &status); ASSERT(NT_SUCCESS(status)); WdfObjectDelete( Transaction ); // // Queue the request for later processing. // status = WdfRequestForwardToIoQueue(request, fdoData->PendingWriteQueue); if(!NT_SUCCESS(status)) { ASSERTMSG(" WdfRequestForwardToIoQueue failed ", FALSE); WdfSpinLockRelease(fdoData->SendLock); WdfRequestCompleteWithInformation(request, STATUS_UNSUCCESSFUL, 0); return FALSE; } fdoData->nWaitSend++; } else { status = NICWritePacket(fdoData, Transaction, ScatterGather); if(!NT_SUCCESS(status)) { TraceEvents(TRACE_LEVEL_ERROR, DBG_WRITE, "<-- NICEvtProgramDmaFunction returning %!STATUS!\n", status); // // Must abort the transaction before deleting. // (VOID )WdfDmaTransactionDmaCompletedFinal(Transaction, 0, &status); ASSERT(NT_SUCCESS(status)); WdfObjectDelete( Transaction ); WdfSpinLockRelease(fdoData->SendLock); WdfRequestCompleteWithInformation(request, STATUS_UNSUCCESSFUL, 0); return FALSE; } } WdfSpinLockRelease(fdoData->SendLock); TraceEvents(TRACE_LEVEL_VERBOSE, DBG_WRITE, "<-- NICEvtProgramDmaFunction\n"); return TRUE; }
VOID NICProcessSGList( PDEVICE_OBJECT DeviceObject, PIRP Irp,//unused PSCATTER_GATHER_LIST ScatterGather, PVOID Context ) /*++ Routine Description: This routine is called at IRQL = DISPATCH_LEVEL when the bus-master adapter is available. Arguments: DeviceObject - This is the device object for the target device, previously created by the driver's AddDevice routine. Irp - Useful only if the driver has a StartIo routine. ScatterGather - Structure describing scatter/gather regions. Context - Pointer to the Request. Return Value: None. --*/ { PFDO_DATA fdoData; PIRP irp = (PIRP)Context; DebugPrint(TRACE, DBG_WRITE, "--> NICProcessSGList\n"); fdoData = DeviceObject->DeviceExtension; // // Save the ScatterGather pointer in the DriverContext so that we can free // the list when we complete the request. // irp->Tail.Overlay.DriverContext[3] = ScatterGather; KeAcquireSpinLockAtDpcLevel(&fdoData->SendLock); // // If tcb is not available or the device is doing link detection (during init), // queue the request // if (!MP_TCB_RESOURCES_AVAIABLE(fdoData) || MP_TEST_FLAG(fdoData, fMP_ADAPTER_LINK_DETECTION)) { // // Instead of locking up the map registers while the request is // waiting in the queue or, we could free it up and reallocate it whenever // we are ready to handle the request later. // // DebugPrint(TRACE, DBG_WRITE, "Resource or the link is not available, queue packet\n"); InsertTailList(&fdoData->SendQueueHead, &irp->Tail.Overlay.ListEntry); fdoData->nWaitSend++; } else { NICWritePacket(fdoData, irp, FALSE); } KeReleaseSpinLockFromDpcLevel(&fdoData->SendLock); DebugPrint(TRACE, DBG_WRITE, "<-- NICProcessSGList\n"); return; }