#ident "@(#) NEC xxinitnt.c 1.18 95/03/17 11:59:37" /*++ Copyright (c) 1991-1994 Microsoft Corporation Module Name: xxinitnt.c Abstract: This module implements the interrupt initialization for a MIPS R3000 or R4000 system. --*/ /* * Original source: Build Number 1.612 * * Modify for R98(MIPS/R4400) * *********************************************************************** * * L001 94.03/22-5/13 T.Samezima * * add control of Eif interrupt. * make table of change from iRRE bit number to NABus code. * make table of arbitration table and arbitration pointer. * make variable for access of registers. * connect the timer interrupt service routine. * clear unknown interrupt counter * * del only '#if defined(_DUO_)' * '#if defined(_JAZZ_)' with content * HalpCountInterrupt() * * change interrupt control * various vector of interrupt service routine * *********************************************************************** * * S002 94.5/17 T.Samezima * * del Arbitration table * *********************************************************************** * * S003 94.6/10-14 T.Samezima * * del Compile err * *********************************************************************** * * S004 94.7/7 T.Samezima * * Chg Use UNKNOWN_COUNT_BUF_LEN to max * for HalpUnknownInterruptCount * *********************************************************************** * * S005 94.7/7 T.Samezima * * Del move interrupt arbitration pointer to r98dspt.c * *********************************************************************** * * S006 94.7/23 T.Samezima * * Add Enable EIF interrupt on SIC. * *********************************************************************** * * S007 94.8/22 T.Samezima on SNES * * Chg Register buffer size from USHORT to ULONG * Value of set to MKSR register * Condition change * * Add Clear interrupt pending bit on edge level interrupt * * Del Move EISA NMI enable logic to HalpCreateEisaStructure() * *********************************************************************** * * S008 94.9/5 T.Samezima * * Add Institute number of repeat for interrupt clear loop * *********************************************************************** * * S009 94.9/16 T.Samezima * * Chg Only CPU#0 on I/O Initerrupt clear * *********************************************************************** * * S00a 94.10/14 T.Samezima * * Fix Version Up at build807 * -Move Int1 interrupt enable to allstart.c * * S00b 94.10/18 T.Samezima * Chg Enable interrupt on MKR register only exist device, * * S00c 94.12/06 T.Samezima * Bug Disable ECC 1bit error interrupt. * * S00d 94.12/06 T.Samezima * Add Disable NMI * * S00e 95.01/10 T.Samezima * Add Enable ECC 1bit error interrupt * Rewrite cycle start on ecc 1bit error * * S00f 95.01/24 T.Samezima * Add Disable rewrite cycle on ecc 1bit error * * S010 95.03/13 T.Samezima * Add Enable HW cache flush. * */ #include "halp.h" #include "eisa.h" // S003 // // Put all code for HAL initialization in the INIT section. It will be // deallocated by memory management when phase 1 initialization is // completed. // #if defined(ALLOC_PRAGMA) #pragma alloc_text(INIT, HalpInitializeInterrupts) #endif // // Define global data for builtin device interrupt enables. // ULONG HalpBuiltinInterruptEnable; // S007 // // Define the IRQL mask and level mapping table. // // These tables are transfered to the PCR and determine the priority of // interrupts. // // N.B. The two software interrupt levels MUST be the lowest levels. // UCHAR HalpIrqlMask[] = {4, 5, 6, 6, 7, 7, 7, 7, // 0000 - 0111 high 4-bits 8, 8, 8, 8, 8, 8, 8, 8, // 1000 - 1111 high 4-bits 0, 1, 2, 2, 3, 3, 3, 3, // 0000 - 0111 low 4-bits 4, 4, 4, 4, 4, 4, 4, 4}; // 1000 - 1111 low 4-bits UCHAR HalpIrqlTable[] = {0xff, // IRQL 0 0xfe, // IRQL 1 0xfc, // IRQL 2 0xf8, // IRQL 3 0xf0, // IRQL 4 0xe0, // IRQL 5 0xc0, // IRQL 6 0x80, // IRQL 7 0x00}; // IRQL 8 /* Start L001 */ // // Define table of change from iRRE bit number to NABus code // ULONG HalpNaBusCodeTable[] = {0x8000, 0x0010, // iRRE bit0,1 0x0006, 0x0000, // iRRE bit2,3 0x0002, 0x0002, // iRRE bit4,5 0x000a, 0x000a, // iRRE bit6,7 0x0008, 0x000c, // iRRE bit8,9 0x8000, 0x8000, // iRRE bit10,11 0x8000, 0x8000, // iRRE bit12,13 0x8000, 0x8000, // iRRE bit14,15 0x8000, 0x0004, // iRRE bit16,17 0x8000, 0x8000, // iRRE bit18,19 0x8000, 0x8000, // iRRE bit20,21 0x000c, 0x8000, // iRRE bit22,23 0x8000, 0x8000, // iRRE bit24,25 0x8000, 0x8000, // iRRE bit26,27 0x8000, 0x8000, // iRRE bit28,29 0x8000, 0x8000 }; // iRRE bit30,31 // // Define table of order of interrupt arbitration // ULONG HalpUnknownInterruptCount[UNKNOWN_COUNT_BUF_LEN]; // S004 /* End L001*/ BOOLEAN HalpInitializeInterrupts ( VOID ) /*++ Routine Description: This function initializes interrupts for a Jazz or Duo MIPS system. N.B. This function is only called during phase 0 initialization. Arguments: None. Return Value: A value of TRUE is returned if the initialization is successfully completed. Otherwise a value of FALSE is returned. --*/ { USHORT DataShort; ULONG DataLong; ULONG Index; PKPRCB Prcb; /* Start L001 */ ULONG pmcRegisterAddr; ULONG pmcRegisterUpperPart; ULONG pmcRegisterLowerPart; ULONG bitCount; ULONG buffer; ULONG buffer2; // S006 UCHAR charBuffer; LONG repeatCounter; // S008 /* End L001 */ // // Get the address of the processor control block for the current // processor. // Prcb = PCR->Prcb; // // Initialize the IRQL translation tables in the PCR. These tables are // used by the interrupt dispatcher to determine the new IRQL and the // mask value that is to be loaded into the PSR. They are also used by // the routines that raise and lower IRQL to load a new mask value into // the PSR. // for (Index = 0; Index < sizeof(HalpIrqlMask); Index += 1) { PCR->IrqlMask[Index] = HalpIrqlMask[Index]; } for (Index = 0; Index < sizeof(HalpIrqlTable); Index += 1) { PCR->IrqlTable[Index] = HalpIrqlTable[Index]; } /* Start L001 */ // // All interrupt disables. // pmcRegisterAddr = (ULONG)( &(PMC_CONTROL1)->MKR ); // S003 pmcRegisterUpperPart = MKR_DISABLE_ALL_INTERRUPT_HIGH; pmcRegisterLowerPart = MKR_DISABLE_ALL_INTERRUPT_LOW; HalpWriteLargeRegister( pmcRegisterAddr, &pmcRegisterUpperPart, &pmcRegisterLowerPart ); // // If processor 0 is being initialized, then set all device // interrupt disables. // if (Prcb->Number == 0) { HalpBuiltinInterruptEnable = iREN_DISABLE_ALL_INTERRUPT; for (Index = 0; Index < UNKNOWN_COUNT_BUF_LEN; Index += 1) { // S004 HalpUnknownInterruptCount[Index] = 0; } // } // S009 /* End L001 */ // // Disable individual device interrupts and make sure no device interrupts // are pending. // /* Start L001 */ WRITE_REGISTER_ULONG( &( LR_CONTROL2 )->iREN, HalpBuiltinInterruptEnable ); WRITE_REGISTER_ULONG( &( IOB_CONTROL )->EIMR.Long, EIMR_DISABLE_ALL_EIF ); repeatCounter = 0; // S008 while( ((DataLong = READ_REGISTER_ULONG( &( LR_CONTROL2 )->iRRE) & iRRE_MASK) != 0) && (++repeatCounter < 16) ) { // S008 for( bitCount = 0 ; bitCount <= 31 ; bitCount++ ) { if( (DataLong & ( 1 << bitCount )) != 0) { // Start S007 if( bitCount < 15 ){ WRITE_REGISTER_ULONG( &( LR_CONTROL2 )->iRSF, ( 1 << bitCount ) ); } // End S007 WRITE_REGISTER_ULONG( &( IOB_CONTROL )->AIMR.Long, HalpNaBusCodeTable[bitCount] ); } } WRITE_REGISTER_ULONG( &( LR_CONTROL2 )->iRSF, iRSF_CLEAR_INTERRUPT ); pmcRegisterAddr = (ULONG)( &(PMC_CONTROL1)->IPRR ); // S003 pmcRegisterUpperPart = 0x0; pmcRegisterLowerPart = 0xffffffff; HalpWriteLargeRegister( pmcRegisterAddr, &pmcRegisterUpperPart, &pmcRegisterLowerPart ); } /* End L001 */ HalpBuiltinInterruptEnable |= 0x10; // S010 // // If processor 0 is being initialized, then enable device interrupts. // // if (Prcb->Number == 0) { // S009 /* Start L001 */ // // Enable INT0-1 interrupt on PMC // /* Start S003 */ WRITE_REGISTER_ULONG( &( IOB_CONTROL )->AII0.Long, AII_INIT_DATA ); WRITE_REGISTER_ULONG( &( IOB_CONTROL )->AII1.Long, AII_INIT_DATA ); WRITE_REGISTER_ULONG( &( IOB_CONTROL )->AII2.Long, AII_INIT_DATA ); WRITE_REGISTER_ULONG( &( IOB_CONTROL )->AII3.Long, AII_INIT_DATA ); /* End S003 */ pmcRegisterAddr = (ULONG)( &(PMC_CONTROL1)->MKR ); // S003 HalpReadLargeRegister( pmcRegisterAddr, &pmcRegisterUpperPart, &pmcRegisterLowerPart ); pmcRegisterLowerPart = ( pmcRegisterLowerPart | MKR_INT0_DEVICE_ENABLE_LOW // S00b // | MKR_INT1_DEVICE_ENABLE_LOW // S00a, S00b | MKR_INT2_DEVICE_ENABLE_LOW // S00b ); // S003 HalpWriteLargeRegister( pmcRegisterAddr, &pmcRegisterUpperPart, &pmcRegisterLowerPart ); // DataLong = READ_REGISTER_ULONG(&((PDMA_REGISTERS)DMA_VIRTUAL_BASE)->InterruptEnable.Long); // DataLong |= ENABLE_DEVICE_INTERRUPTS; // WRITE_REGISTER_ULONG(&((PDMA_REGISTERS)DMA_VIRTUAL_BASE)->InterruptEnable.Long, // DataLong); /* End L001 */ } /* Start L001 */ // // Connect the eif interrupt to the eif interrupt routine // PCR->InterruptRoutine[EIF_LEVEL] = HalpEifDispatch; // // Enable the eif interrupt // pmcRegisterAddr = (ULONG)( &(PMC_CONTROL1)->MKR ); // S003 HalpReadLargeRegister( pmcRegisterAddr, &pmcRegisterUpperPart, &pmcRegisterLowerPart ); pmcRegisterUpperPart = ( pmcRegisterUpperPart | MKR_INT5_ENABLE_HIGH ); pmcRegisterLowerPart = ( pmcRegisterLowerPart | MKR_INT5_ENABLE_LOW ); HalpWriteLargeRegister( pmcRegisterAddr, &pmcRegisterUpperPart, &pmcRegisterLowerPart ); buffer = READ_REGISTER_ULONG( &( PMC_CONTROL1 )->STSR.Long); buffer = (buffer | STSR_EIF_ENABLE); #if defined(DISABLE_NMI) // S00d buffer = (buffer | STSR_NMI_DISABLE); #endif WRITE_REGISTER_ULONG( &( PMC_CONTROL1 )->STSR.Long, buffer); WRITE_REGISTER_ULONG( &( PMC_CONTROL1 )->ERRMK.Long, ERRMK_EIF_ENABLE); WRITE_REGISTER_ULONG( &( IOB_CONTROL )->IEMR.Long, IEMR_ENABLE_ALL_EIF); WRITE_REGISTER_ULONG( &( IOB_CONTROL )->EIMR.Long, EIMR_ENABLE_ALL_EIF); /* Start S006 */ buffer = READ_REGISTER_ULONG( &( IOB_CONTROL )->SCFR.Long ); IOB_DUMMY_READ; if( (buffer & SCFR_SIC_SET0_CONNECT) == 0 ) { // S007 buffer2 = READ_REGISTER_ULONG( &(SIC_ERR_CONTROL_OR(SIC_NO0_OFFSET))->CKE0.Long ); buffer2 &= CKE0_DISABLE_SBE; // S00c buffer2 |= CKE0_ENABLE_ALL_EIF; WRITE_REGISTER_ULONG( &( SIC_ERR_CONTROL_OR(SIC_SET0_OFFSET) )->CKE0.Long, buffer2 ); // S00e vvv buffer2 = READ_REGISTER_ULONG( &(SIC_DATA_CONTROL_OR(SIC_NO0_OFFSET))->DPCM.Long ); buffer2 &= DPCM_ENABLE_MASK; // S00c WRITE_REGISTER_ULONG( &( SIC_DATA_CONTROL_OR(SIC_SET0_OFFSET) )->DPCM.Long, buffer2 ); #if 0 // S00f WRITE_REGISTER_ULONG( &( SIC_ERR_CONTROL_OR(SIC_SET0_OFFSET) )->SECT.Long, SECT_REWRITE_ENABLE ); #endif // S00e ^^^ WRITE_REGISTER_ULONG( &( SIC_ERR_CONTROL_OR(SIC_SET0_OFFSET) )->CKE1.Long, CKE1_ENABLE_ALL_EIF ); } if( (buffer & SCFR_SIC_SET1_CONNECT) == 0 ) { // S007 buffer2 = READ_REGISTER_ULONG( &(SIC_ERR_CONTROL_OR(SIC_NO2_OFFSET))->CKE0.Long ); buffer2 &= CKE0_DISABLE_SBE; // S00c buffer2 |= CKE0_ENABLE_ALL_EIF; WRITE_REGISTER_ULONG( &( SIC_ERR_CONTROL_OR(SIC_SET1_OFFSET) )->CKE0.Long, buffer2 ); // S00e vvv buffer2 = READ_REGISTER_ULONG( &(SIC_DATA_CONTROL_OR(SIC_NO2_OFFSET))->DPCM.Long ); buffer2 &= DPCM_ENABLE_MASK; // S00c WRITE_REGISTER_ULONG( &( SIC_DATA_CONTROL_OR(SIC_SET1_OFFSET) )->DPCM.Long, buffer2 ); #if 0 // S00f WRITE_REGISTER_ULONG( &( SIC_ERR_CONTROL_OR(SIC_SET1_OFFSET) )->SECT.Long, SECT_REWRITE_ENABLE ); #endif // S00e ^^^ WRITE_REGISTER_ULONG( &( SIC_ERR_CONTROL_OR(SIC_SET1_OFFSET) )->CKE1.Long, CKE1_ENABLE_ALL_EIF ); } /* End S006 */ // S007 // // If processor 0 is being initialized, then connect the interval timer // interrupt to the stall interrupt routine so the stall execution count // can be computed during phase 1 initialization. Otherwise, connect the // interval timer interrupt to the appropriate interrupt service routine // and set stall execution count from the computation made on processor // 0. // PCR->InterruptRoutine[TIMER_LEVEL] = HalpTimerDispatch; // S003 if (Prcb->Number == 0) { /* Start L001 */ PCR->InterruptRoutine[CLOCK_VECTOR] = HalpStallInterrupt; /* End L001 */ } else { /* Start L001 */ PCR->InterruptRoutine[CLOCK_VECTOR] = HalpClockInterrupt1; /* End L001 */ PCR->StallScaleFactor = HalpStallScaleFactor; } // // Initialize the interval timer to interrupt at the specified interval. // /* Start L001 */ WRITE_REGISTER_ULONG( &( PMC_CONTROL1 )->TMSR1.Long, CLOCK_INTERVAL); // // Initialize the profile timer to interrupt at the default interval. // WRITE_REGISTER_ULONG( &( PMC_CONTROL1 )->TMSR2.Long, DEFAULT_PROFILETIMER_COUNT); /* End L001 */ // // Enable the interval timer interrupt on the current processor. // /* Start L001 */ WRITE_REGISTER_ULONG( &( PMC_CONTROL1 )->MKSR.Long, 0x3f-IPR_CLOCK_BIT_NO); // S007 WRITE_REGISTER_ULONG( &( PMC_CONTROL1 )->TMCR1.Long, 0x3); /* End L001 */ // // If processor 0 is being initialized, then connect the count/compare // interrupt to the count interrupt routine to handle early count/compare // interrupts during phase 1 initialization. Otherwise, connect the // count\comapre interrupt to the appropriate interrupt service routine. // /* Start L001 */ if (Prcb->Number != 0) { PCR->InterruptRoutine[PROFILE_VECTOR] = HalpProfileInterrupt; WRITE_REGISTER_ULONG( &( PMC_CONTROL1 )->MKSR.Long, 0x3f-IPR_PROFILE_BIT_NO); // S007 WRITE_REGISTER_ULONG( &( PMC_CONTROL1 )->TMCR2.Long, 0x3); } /* End L001 */ // // Connect the interprocessor interrupt service routine and enable // interprocessor interrupts. // PCR->InterruptRoutine[IPI_LEVEL] = HalpIpiInterrupt; /*Start L001 */ pmcRegisterAddr = (ULONG)( &(PMC_CONTROL1)->MKR ); // S003 HalpReadLargeRegister( pmcRegisterAddr, &pmcRegisterUpperPart, &pmcRegisterLowerPart ); pmcRegisterUpperPart = ( pmcRegisterUpperPart | MKR_INT4_ENABLE_HIGH ); pmcRegisterLowerPart = ( pmcRegisterLowerPart | MKR_INT4_ENABLE_LOW ); HalpWriteLargeRegister( pmcRegisterAddr, &pmcRegisterUpperPart, &pmcRegisterLowerPart ); /*End L001 */ // // Reserve the local device interrupt vector for exclusive use by the HAL. // /* Start L001 */ // PCR->ReservedVectors |= (1 << DEVICE_LEVEL); // PCR->ReservedVectors |= (1 << INT1_LEVEL); // S00a PCR->ReservedVectors |= (1 << INT2_LEVEL); /* End L001 */ return TRUE; }