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; }
_Use_decl_annotations_ VOID PLxEvtInterruptDpc( WDFINTERRUPT Interrupt, WDFOBJECT Device ) /*++ Routine Description: DPC callback for ISR. Please note that on a multiprocessor system, you could have more than one DPCs running simulataneously on multiple processors. So if you are accesing any global resources make sure to synchrnonize the accesses with a spinlock. Arguments: Interupt - Handle to WDFINTERRUPT Object for this device. Device - WDFDEVICE object passed to InterruptCreate Return Value: --*/ { NTSTATUS status; WDFDMATRANSACTION dmaTransaction; PDEVICE_EXTENSION devExt; BOOLEAN writeInterrupt = FALSE; BOOLEAN readInterrupt = FALSE; UNREFERENCED_PARAMETER(Device); TraceEvents(TRACE_LEVEL_INFORMATION, DBG_DPC, "--> EvtInterruptDpc"); devExt = PLxGetDeviceContext(WdfInterruptGetDevice(Interrupt)); // // Acquire this device's InterruptSpinLock. // WdfInterruptAcquireLock( Interrupt ); if ((devExt->IntCsr.bits.DmaChan0IntActive) && (devExt->Dma0Csr.bits.Done)) { // // If Dma0 channel 0 (write) is interrupting and the // Done bit is set in the Dma0 CSR, // we're interrupting because a WRITE is complete. // Clear the done bit and channel interrupting bit from // our copies... // devExt->IntCsr.bits.DmaChan0IntActive = FALSE; devExt->Dma0Csr.uchar = 0; writeInterrupt = TRUE; } if ((devExt->IntCsr.bits.DmaChan1IntActive) && (devExt->Dma1Csr.bits.Done)) { // // If DMA channel 1 is interrupting and the // DONE bit is set in the DMA1 control/status // register, we're interrupting because a READ // is complete. // Clear the done bit and channel interrupting bit from // our copies... // devExt->IntCsr.bits.DmaChan1IntActive = FALSE; devExt->Dma0Csr.uchar = 0; readInterrupt = TRUE; } // // Release our interrupt spinlock // WdfInterruptReleaseLock( Interrupt ); // // Did a Write DMA complete? // if (writeInterrupt) { BOOLEAN transactionComplete; // // Get the current Write DmaTransaction. // dmaTransaction = devExt->WriteDmaTransaction; // // 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 request. // transactionComplete = WdfDmaTransactionDmaCompleted( dmaTransaction, &status ); if (transactionComplete) { // // Complete this DmaTransaction. // TraceEvents(TRACE_LEVEL_INFORMATION, DBG_DPC, "Completing Write request in the DpcForIsr"); PLxWriteRequestComplete( dmaTransaction, status ); } } // // Did a Read DMA complete? // if (readInterrupt) { BOOLEAN transactionComplete; PDMA_TRANSFER_ELEMENT dteVA; size_t length; // // Get the current Read DmaTransaction. // dmaTransaction = devExt->ReadDmaTransaction; // // Only on Read-side -- // Use "DMA Clear-Count Mode" to get complemetary // transferred byte count. // length = WdfDmaTransactionGetCurrentDmaTransferLength( dmaTransaction ); dteVA = (PDMA_TRANSFER_ELEMENT) devExt->ReadCommonBufferBase; while(dteVA->DescPtr.LastElement == FALSE) { length -= dteVA->TransferSize; dteVA++; } length -= dteVA->TransferSize; // // 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 request. // transactionComplete = WdfDmaTransactionDmaCompletedWithLength( dmaTransaction, length, &status ); if (transactionComplete) { // // Complete this DmaTransaction. // TraceEvents(TRACE_LEVEL_INFORMATION, DBG_DPC, "Completing Read request in the DpcForIsr"); PLxReadRequestComplete( dmaTransaction, status ); } } TraceEvents(TRACE_LEVEL_INFORMATION, DBG_DPC, "<-- EvtInterruptDpc"); return; }
VOID AmccPciEvtInterruptDpc( __in WDFINTERRUPT WdfInterrupt, __in WDFOBJECT WdfDevice ) /*++ Routine Description: DPC callback for ISR. Arguments: WdfInterrupt - Handle to the framework interrupt object WdfDevice - Associated device object. Return Value: --*/ { PAMCC_DEVICE_EXTENSION devExt; WDFREQUEST request; REQUEST_CONTEXT * transfer; NTSTATUS status; size_t transferred; BOOLEAN transactionComplete; UNREFERENCED_PARAMETER( WdfInterrupt ); devExt = AmccPciGetDevExt(WdfDevice); // // Retreive request and transfer. // request = devExt->CurrentRequest; transfer = GetRequestContext(request); // // Check to see if the request is cancelled by the system. While // we are DMAing a large buffer into multiple transaction, // there is good possibilty for the request to get cancelled because // the originator of the request exited or cancelled the I/O explicitly. // if(WdfRequestIsCanceled(request)) { TraceEvents(TRACE_LEVEL_ERROR, AMCC_TRACE_IO, "Aborted DMA transaction 0x%p", request); WdfObjectDelete( transfer->DmaTransaction ); devExt->CurrentRequest = NULL; WdfRequestComplete(request, STATUS_CANCELLED); return; } // // The boolean transactionComplete indicates whether the transaction has // exited the transfer state, e.g. no further transfers are scheduled. // // If transactionComplete == FALSE, then the next DMA transfer has been // scheduled, e.g. the next interrrupt will drive the ISR again. // // If transactionComplete == TRUE, then status indicates the reason; // SUCCESS is the nomative case, while non-SUCCESS indicates the // DMA transaction failed for "status" reason. // transactionComplete = WdfDmaTransactionDmaCompleted( transfer->DmaTransaction, &status ); if (transactionComplete) { ASSERT(status != STATUS_MORE_PROCESSING_REQUIRED); // // No more data: request is complete // TraceEvents(TRACE_LEVEL_INFORMATION, AMCC_TRACE_IO, "Request %p completed: status %X", request, status); // // Get the final bytes transferred count. // transferred = WdfDmaTransactionGetBytesTransferred( transfer->DmaTransaction ); TraceEvents(TRACE_LEVEL_INFORMATION, AMCC_TRACE_IO, "Bytes transfered %d", (int) transferred ); // // Delete this DmaTransaction transaction. // WdfObjectDelete( transfer->DmaTransaction ); // // Clean-up for this request. // devExt->CurrentRequest = NULL; // // Complete this IO request. // WdfRequestCompleteWithInformation( request, status, (NT_SUCCESS(status)) ? transferred : 0 ); } }