/******************************************************************************* * * Function : DpcForIsr * * Description: This routine will be triggered by the ISR to service an interrupt * ******************************************************************************/ VOID DpcForIsr( PLX_DPC_PARAM *pArg1 ) { U32 RegValue; unsigned long flags; DEVICE_EXTENSION *pdx; PLX_INTERRUPT_DATA IntData; // Get the device extension pdx = container_of( pArg1, DEVICE_EXTENSION, Task_DpcForIsr ); // Abort DPC if device is being stopped and resources released if ((pdx->State != PLX_STATE_STARTED) || (pdx->PciBar[0].pVa == NULL)) { DebugPrintf(("DPC aborted, device is stopping\n")); // Flag DPC is no longer pending pdx->bDpcPending = FALSE; return; } // Get interrupt source IntData.Source_Ints = pdx->Source_Ints; IntData.Source_Doorbell = 0; // Local Interrupt 1 if (IntData.Source_Ints & INTR_TYPE_LOCAL_1) { // Synchronize access to Interrupt Control/Status Register spin_lock_irqsave( &(pdx->Lock_Isr), flags ); // Mask local interrupt 1 since true source is unknown RegValue = PLX_9000_REG_READ( pdx, PCI9056_INT_CTRL_STAT ); RegValue &= ~(1 << 11); PLX_9000_REG_WRITE( pdx, PCI9056_INT_CTRL_STAT, RegValue ); spin_unlock_irqrestore( &(pdx->Lock_Isr), flags ); } // Doorbell Interrupt if (IntData.Source_Ints & INTR_TYPE_DOORBELL) { // Get Doorbell register RegValue = PLX_9000_REG_READ( pdx, PCI9056_PCI_DOORBELL ); // Clear Doorbell interrupt PLX_9000_REG_WRITE( pdx, PCI9056_PCI_DOORBELL, RegValue ); // Save the doorbell value IntData.Source_Doorbell = RegValue; } // PCI Abort interrupt if (IntData.Source_Ints & INTR_TYPE_PCI_ABORT) { // Get the PCI Command register PLX_PCI_REG_READ( pdx, 0x04, &RegValue ); // Write to back to clear PCI Abort PLX_PCI_REG_WRITE( pdx, 0x04, RegValue ); } // DMA Channel 0 interrupt if (IntData.Source_Ints & INTR_TYPE_DMA_0) { // Get DMA Control/Status RegValue = PLX_9000_REG_READ( pdx, PCI9056_DMA_COMMAND_STAT ); // Clear DMA interrupt PLX_9000_REG_WRITE( pdx, PCI9056_DMA_COMMAND_STAT, RegValue | (1 << 3) ); RegValue = PLX_9000_REG_READ( pdx, PCI9056_DMA0_MODE ); // Check if SGL is enabled & cleanup if (RegValue & (1 << 9)) { PlxSglDmaTransferComplete( pdx, 0 ); } } // DMA Channel 1 interrupt if (IntData.Source_Ints & INTR_TYPE_DMA_1) { // Get DMA Control/Status RegValue = PLX_9000_REG_READ( pdx, PCI9056_DMA_COMMAND_STAT ); // Clear DMA interrupt PLX_9000_REG_WRITE( pdx, PCI9056_DMA_COMMAND_STAT, RegValue | (1 << 11) ); RegValue = PLX_9000_REG_READ( pdx, PCI9056_DMA1_MODE ); // Check if SGL is enabled & cleanup if (RegValue & (1 << 9)) { PlxSglDmaTransferComplete( pdx, 1 ); } } // Outbound post FIFO interrupt if (IntData.Source_Ints & INTR_TYPE_OUTBOUND_POST) { // Mask Outbound Post interrupt PLX_9000_REG_WRITE( pdx, PCI9056_OUTPOST_INT_MASK, (1 << 3) ); } // Signal any objects waiting for notification PlxSignalNotifications( pdx, &IntData ); // Re-enable interrupts PlxChipInterruptsEnable( pdx ); // Flag a DPC is no longer pending pdx->bDpcPending = FALSE; }
/****************************************************************************** * * Function : PlxChip_DmaChannelClose * * Description: Close a previously opened channel * ******************************************************************************/ PLX_STATUS PlxChip_DmaChannelClose( DEVICE_EXTENSION *pdx, U8 channel, BOOLEAN bCheckInProgress, VOID *pOwner ) { PLX_STATUS status; DebugPrintf(("Closing DMA channel %d...\n", channel)); // Verify valid DMA channel switch (channel) { case 0: case 1: break; default: DebugPrintf(("ERROR - Invalid DMA channel\n")); return ApiDmaChannelInvalid; } // Verify DMA channel was opened if (pdx->DmaInfo[channel].bOpen == FALSE) { DebugPrintf(("ERROR - DMA channel has not been opened\n")); return ApiDmaChannelUnavailable; } // Verify owner if (pdx->DmaInfo[channel].pOwner != pOwner) { DebugPrintf(("ERROR - DMA owned by different process\n")); return ApiDeviceInUse; } // Check DMA status status = PlxChip_DmaStatus( pdx, channel, pOwner ); // Verify DMA is not in progress if (status != ApiDmaDone) { // DMA is still in progress if (bCheckInProgress) return status; DebugPrintf(("DMA in progress, aborting...\n")); // Force DMA abort, which may generate a DMA done interrupt PlxChip_DmaControl( pdx, channel, DmaAbort, pOwner ); // Small delay to let driver cleanup if DMA interrupts Plx_sleep( 100 ); } spin_lock( &(pdx->Lock_Dma[channel]) ); // Close the channel pdx->DmaInfo[channel].bOpen = FALSE; // Clear owner information pdx->DmaInfo[channel].pOwner = NULL; spin_unlock( &(pdx->Lock_Dma[channel]) ); // If DMA is hung, an SGL transfer could be pending, so release user buffer if (pdx->DmaInfo[channel].bSglPending) { PlxSglDmaTransferComplete( pdx, channel ); } // Release memory previously used for SGL descriptors if (pdx->DmaInfo[channel].SglBuffer.pKernelVa != NULL) { DebugPrintf(("Releasing memory used for SGL descriptors...\n")); Plx_dma_buffer_free( pdx, &pdx->DmaInfo[channel].SglBuffer ); } return ApiSuccess; }