/****************************************************************************** * * Function : PlxChipInterruptsDisable * * Description: Globally disables PLX chip interrupts * *****************************************************************************/ BOOLEAN PlxChipInterruptsDisable( DEVICE_EXTENSION *pdx ) { U32 RegValue; // Disable doorbell interrupts PLX_PCI_REG_READ( pdx, 0xc4, &RegValue ); RegValue &= ~0xFFFF; PLX_PCI_REG_WRITE( pdx, 0xc4, RegValue ); // Disable Message, S_RSTIN, S_PME, & GPIO interrupts PLX_PCI_REG_WRITE( pdx, 0xc8, 0x00000000 ); return TRUE; }
/******************************************************************************* * * 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 : PlxInterruptDisable * * Description: Disables specific interrupts of the PLX Chip * ******************************************************************************/ PLX_STATUS PlxInterruptDisable( DEVICE_EXTENSION *pdx, PLX_INTERRUPT *pPlxIntr ) { U32 RegValue; PLX_REG_DATA RegData; // Only 16 doorbell interrupts are supported pPlxIntr->Doorbell &= 0xFFFF; // Disable doorbell interrupts if (pPlxIntr->Doorbell) { PLX_PCI_REG_READ( pdx, 0xc4, &RegValue ); // Clear doorbell interrupts that are set RegValue &= 0xFFFF0000 | (~pPlxIntr->Doorbell & 0xFFFF); PLX_PCI_REG_WRITE( pdx, 0xc4, RegValue ); } // Setup to synchronize access to interrupt register RegData.pdx = pdx; RegData.offset = 0xc8; RegData.BitsToSet = 0; RegData.BitsToClear = 0; if (pPlxIntr->Message & (1 << 0)) RegData.BitsToClear |= (1 << 24); if (pPlxIntr->Message & (1 << 1)) RegData.BitsToClear |= (1 << 25); if (pPlxIntr->Message & (1 << 2)) RegData.BitsToClear |= (1 << 26); if (pPlxIntr->Message & (1 << 3)) RegData.BitsToClear |= (1 << 27); if (pPlxIntr->ResetDeassert) RegData.BitsToClear |= (1 << 28); if (pPlxIntr->PmeDeassert) RegData.BitsToClear |= (1 << 29); if (pPlxIntr->GPIO_14_15) RegData.BitsToClear |= (1 << 30); if (pPlxIntr->GPIO_4_5) RegData.BitsToClear |= (1 << 31); // Write register values if they have changed if (RegData.BitsToClear != 0) { // Synchronize write to interrupt register PlxSynchronizedRegisterModify( &RegData ); } return ApiSuccess; }
/****************************************************************************** * * Function : PlxChip_BoardReset * * Description: Resets a device using software reset feature of PLX chip * ******************************************************************************/ PLX_STATUS PlxChip_BoardReset( DEVICE_EXTENSION *pdx ) { U8 MU_Enabled; U8 EepromPresent; U32 RegValue; U32 RegInterrupt; U32 RegHotSwap; U32 RegPowerMgmnt; // Clear any PCI errors (04[31:27]) PLX_PCI_REG_READ( pdx, 0x04, &RegValue ); if (RegValue & (0xf8 << 24)) { // Write value back to clear aborts PLX_PCI_REG_WRITE( pdx, 0x04, RegValue ); } // Save state of I2O Decode Enable RegValue = PLX_9000_REG_READ( pdx, PCI9056_FIFO_CTRL_STAT ); MU_Enabled = (U8)(RegValue & (1 << 0)); // Determine if an EEPROM is present RegValue = PLX_9000_REG_READ( pdx, PCI9056_EEPROM_CTRL_STAT ); // Make sure S/W Reset & EEPROM reload bits are clear RegValue &= ~((1 << 30) | (1 << 29)); // Remember if EEPROM is present EepromPresent = (U8)((RegValue >> 28) & (1 << 0)); // Save interrupt line PLX_PCI_REG_READ( pdx, 0x3C, &RegInterrupt ); // Save some registers if EEPROM present if (EepromPresent) { PLX_PCI_REG_READ( pdx, PCI9056_HS_CAP_ID, &RegHotSwap ); PLX_PCI_REG_READ( pdx, PCI9056_PM_CSR, &RegPowerMgmnt ); } // Issue Software Reset to hold PLX chip in reset PLX_9000_REG_WRITE( pdx, PCI9056_EEPROM_CTRL_STAT, RegValue | (1 << 30) ); // Delay for a bit Plx_sleep(100); // Bring chip out of reset PLX_9000_REG_WRITE( pdx, PCI9056_EEPROM_CTRL_STAT, RegValue ); // Issue EEPROM reload in case now programmed PLX_9000_REG_WRITE( pdx, PCI9056_EEPROM_CTRL_STAT, RegValue | (1 << 29) ); // Delay for a bit Plx_sleep(10); // Clear EEPROM reload PLX_9000_REG_WRITE( pdx, PCI9056_EEPROM_CTRL_STAT, RegValue ); // Restore I2O Decode Enable state if (MU_Enabled) { // Save state of I2O Decode Enable RegValue = PLX_9000_REG_READ( pdx, PCI9056_FIFO_CTRL_STAT ); PLX_9000_REG_WRITE( pdx, PCI9056_FIFO_CTRL_STAT, RegValue | (1 << 0) ); } // Restore interrupt line PLX_PCI_REG_WRITE( pdx, 0x3C, RegInterrupt ); // If EEPROM was present, restore registers if (EepromPresent) { // Mask out HS bits that can be cleared RegHotSwap &= ~((1 << 23) | (1 << 22) | (1 << 17)); PLX_PCI_REG_WRITE( pdx, PCI9056_HS_CAP_ID, RegHotSwap ); // Mask out PM bits that can be cleared RegPowerMgmnt &= ~(1 << 15); PLX_PCI_REG_READ( pdx, PCI9056_PM_CSR, &RegPowerMgmnt ); } return ApiSuccess; }
/****************************************************************************** * * Function : PlxPciBoardReset * * Description: Resets a device using software reset feature of PLX chip * ******************************************************************************/ VOID PlxPciBoardReset( DEVICE_EXTENSION *pdx ) { U8 MU_Enabled; U8 EepromPresent; U32 RegValue; U32 RegInterrupt; U32 RegMailbox0; U32 RegMailbox1; // Added to avoid compiler warnings RegMailbox0 = 0; RegMailbox1 = 0; // Clear any PCI errors PLX_PCI_REG_READ( pdx, CFG_COMMAND, &RegValue ); if (RegValue & (0xf8 << 24)) { // Write value back to clear aborts PLX_PCI_REG_WRITE( pdx, CFG_COMMAND, RegValue ); } // Save state of I2O Decode Enable RegValue = PLX_REG_READ( pdx, PCI9080_FIFO_CTRL_STAT ); MU_Enabled = (U8)(RegValue & (1 << 0)); // Determine if an EEPROM is present RegValue = PLX_REG_READ( pdx, PCI9080_EEPROM_CTRL_STAT ); // Make sure S/W Reset & EEPROM reload bits are clear RegValue &= ~((1 << 30) | (1 << 29)); // Remember if EEPROM is present EepromPresent = (U8)((RegValue >> 28) & (1 << 0)); // Save some registers if EEPROM present if (RegValue & (1 << 28)) { RegMailbox0 = PLX_REG_READ( pdx, PCI9080_MAILBOX0 ); RegMailbox1 = PLX_REG_READ( pdx, PCI9080_MAILBOX1 ); PLX_PCI_REG_READ( pdx, CFG_INT_LINE, &RegInterrupt ); } // Issue Software Reset to hold PLX chip in reset PLX_REG_WRITE( pdx, PCI9080_EEPROM_CTRL_STAT, RegValue | (1 << 30) ); // Delay for a bit Plx_sleep(100); // Bring chip out of reset PLX_REG_WRITE( pdx, PCI9080_EEPROM_CTRL_STAT, RegValue ); // Issue EEPROM reload in case now programmed PLX_REG_WRITE( pdx, PCI9080_EEPROM_CTRL_STAT, RegValue | (1 << 29) ); // Delay for a bit Plx_sleep(10); // Clear EEPROM reload PLX_REG_WRITE( pdx, PCI9080_EEPROM_CTRL_STAT, RegValue ); // Restore I2O Decode Enable state if (MU_Enabled) { // Save state of I2O Decode Enable RegValue = PLX_REG_READ( pdx, PCI9080_FIFO_CTRL_STAT ); PLX_REG_WRITE( pdx, PCI9080_FIFO_CTRL_STAT, RegValue | (1 << 0) ); } // If EEPROM was present, restore registers if (EepromPresent) { // Restore saved registers PLX_REG_WRITE( pdx, PCI9080_MAILBOX0, RegMailbox0 ); PLX_REG_WRITE( pdx, PCI9080_MAILBOX1, RegMailbox1 ); PLX_PCI_REG_WRITE( pdx, CFG_INT_LINE, RegInterrupt ); } }