From 2835b3a5683ef8dc6b6e7da02c7754ac5d700344 Mon Sep 17 00:00:00 2001 From: Joel Sherrill Date: Fri, 1 Feb 2002 15:15:02 +0000 Subject: 2001-02-01 Greg Menke * Lots of tinkering and tuning as part of improving interrupt latency and improving the per-task interrupt level control and FP mask handling. With these modifications interrupt latency was measured at a worst-case of 100us, average below 60 us on a 12 Mhz R3000 class CPU with 50 RTEMS tasks in the application. * mongoosev/README: Updated. * mongoosev/include/mongoose-v.h: Masks modified. * mongoosev/vectorisrs/vectorisrs.c: Significant overhaul to address software prioritization of interrupts. If a higher priority interrupt occurs while we are looking for new interrupts, we will reinitiate the scan of all interrupts. * shared/interrupts/vectorexceptions.c: Removed warning and deleted blank lines. --- c/src/lib/libcpu/mips/ChangeLog | 16 ++ c/src/lib/libcpu/mips/mongoosev/README | 54 ++++ .../lib/libcpu/mips/mongoosev/include/mongoose-v.h | 46 ++-- .../libcpu/mips/mongoosev/vectorisrs/vectorisrs.c | 300 +++++++++++++++------ .../mips/shared/interrupts/vectorexceptions.c | 8 +- 5 files changed, 315 insertions(+), 109 deletions(-) (limited to 'c') diff --git a/c/src/lib/libcpu/mips/ChangeLog b/c/src/lib/libcpu/mips/ChangeLog index 30122d2cf2..73b3d3b4f1 100644 --- a/c/src/lib/libcpu/mips/ChangeLog +++ b/c/src/lib/libcpu/mips/ChangeLog @@ -1,3 +1,19 @@ +2001-02-01 Greg Menke + + * Lots of tinkering and tuning as part of improving interrupt latency + and improving the per-task interrupt level control and FP mask handling. + With these modifications interrupt latency was measured at a worst-case + of 100us, average below 60 us on a 12 Mhz R3000 class CPU with 50 + RTEMS tasks in the application. + * mongoosev/README: Updated. + * mongoosev/include/mongoose-v.h: Masks modified. + * mongoosev/vectorisrs/vectorisrs.c: Significant overhaul to address + software prioritization of interrupts. If a higher priority interrupt + occurs while we are looking for new interrupts, we will reinitiate the + scan of all interrupts. + * shared/interrupts/vectorexceptions.c: Removed warning and deleted + blank lines. + 2002-01-03 Ralf Corsepius * mongoosev/vectorisrs/vectorisrs.c: Include rtems/bspIo.h instead of bspIo.h. diff --git a/c/src/lib/libcpu/mips/mongoosev/README b/c/src/lib/libcpu/mips/mongoosev/README index c7e4e9f8ef..76a8a7529e 100644 --- a/c/src/lib/libcpu/mips/mongoosev/README +++ b/c/src/lib/libcpu/mips/mongoosev/README @@ -4,3 +4,57 @@ The Synova Mongoose-V is a radiation hardened derivative of the LSI 33K with on-CPU peripherals. + +Status +====== + +Per-task floating point enable/disable is supported for both immediate +and deferred FPU context swaps. + +Interrupt Levels are adapted reasonably well to the MIPS interrupt +model. Bit 0 of the int level is a global enable/disable, corresponding +to bit 0 of the processor's SR register. Bits 1 thru 6 are configured +as masks for the Int0 thru Int5 interrupts. The 2 software interrupt +bits are always enabled by default. Each task maintains its own +Interrupt Level setting, reconfiguring the SR register's interrupt bits +whenever scheduled in. The software ints, though not addressable via +the various Interrupt Level functions, are maintained on a per-task +basis, so if software manipulates them directly, things should behave as +expected. At the time of these udpates, the Interrupt Level was only 8 +bits, and completely supporting the global enable, software ints and the +hardware ints would require 9 bits. When more than 8 bits are +available, there is no reason the software interrupts could not be added +to the Interrupt Level. + +While supporting the Int0 thru Int5 bits in this way doesn't seem +wonderfully useful, it does increase the level of compliance with the +RTEMS spec. + +Interrupt Level 0 corresponds to interrupts globally enabled, software +ints enabled and Int0 thru Int5 enabled. If values other than 0 are +supplied, they should be formulated to impose the desired bitmask. +Interrupt priority is not a strong concept on this bsp, it is provided +only by the order in which interrupts are checked. + +If during the vectoring of an interrupt, others arrive, they will all be +processed in accordance with their ordering in SR & the peripheral +register. For example, if while we're vectoring Int4, Int3 and Int5 are +asserted, Int3 will be serviced before Int5. The peripheral interrupts +are individually vectored as a consequence of Int5 being asserted, +however Int5 is not itself vectored. Within the set of peripheral +interrupts, bit 0 is vectored first, 31 is last. + +Interrupts are not nested for MIPS1 or MIPS3 processors, but are +processed serially as possible. On an unloaded 50 task RTEMS program, +runnning on a 12mhz MIPS1 processor, worst-case latencies of 100us were +observed, the average being down at 60us or below. + + +These features are principally a consequence of fixes and tweaks to the +MIPS1 and MIPS3 processor support, and should be equally effective on +both levels of MIPS processors for any of their bsp's. + + + + + diff --git a/c/src/lib/libcpu/mips/mongoosev/include/mongoose-v.h b/c/src/lib/libcpu/mips/mongoosev/include/mongoose-v.h index 97412ecd5e..82583a9580 100644 --- a/c/src/lib/libcpu/mips/mongoosev/include/mongoose-v.h +++ b/c/src/lib/libcpu/mips/mongoosev/include/mongoose-v.h @@ -98,19 +98,19 @@ (MONGOOSEV_UART_CMD_PARITY_ODD << MONGOOSEV_UART0_CMD_SHIFT) #define MONGOOSEV_UART_CMD_TX_ENABLE_1 \ - (MONGOOSEV_UART_CMD_TX_ENABLE << MONGOOSEV_UART0_CMD_SHIFT) + (MONGOOSEV_UART_CMD_TX_ENABLE << MONGOOSEV_UART1_CMD_SHIFT) #define MONGOOSEV_UART_CMD_RX_ENABLE_1 \ - (MONGOOSEV_UART_CMD_RX_ENABLE << MONGOOSEV_UART0_CMD_SHIFT) + (MONGOOSEV_UART_CMD_RX_ENABLE << MONGOOSEV_UART1_CMD_SHIFT) #define MONGOOSEV_UART_CMD_TX_READY_1 \ - (MONGOOSEV_UART_CMD_TX_READY << MONGOOSEV_UART0_CMD_SHIFT) + (MONGOOSEV_UART_CMD_TX_READY << MONGOOSEV_UART1_CMD_SHIFT) #define MONGOOSEV_UART_CMD_PARITY_ENABLE_1 \ - (MONGOOSEV_UART_CMD_PARITY_ENABLE << MONGOOSEV_UART0_CMD_SHIFT) + (MONGOOSEV_UART_CMD_PARITY_ENABLE << MONGOOSEV_UART1_CMD_SHIFT) #define MONGOOSEV_UART_CMD_PARITY_DISABLE_1 \ - (MONGOOSEV_UART_CMD_PARITY_DISABLE << MONGOOSEV_UART0_CMD_SHIFT) + (MONGOOSEV_UART_CMD_PARITY_DISABLE << MONGOOSEV_UART1_CMD_SHIFT) #define MONGOOSEV_UART_CMD_PARITY_EVEN_1 \ - (MONGOOSEV_UART_CMD_PARITY_EVEN << MONGOOSEV_UART0_CMD_SHIFT) + (MONGOOSEV_UART_CMD_PARITY_EVEN << MONGOOSEV_UART1_CMD_SHIFT) #define MONGOOSEV_UART_CMD_PARITY_ODD_1 \ - (MONGOOSEV_UART_CMD_PARITY_ODD << MONGOOSEV_UART0_CMD_SHIFT) + (MONGOOSEV_UART_CMD_PARITY_ODD << MONGOOSEV_UART1_CMD_SHIFT) /* UART Bits in Peripheral Status and Interrupt Cause Register */ #define MONGOOSEV_UART_RX_FRAME_ERROR 0x0001 @@ -131,6 +131,17 @@ #define MONGOOSEV_UART0_IRQ_SHIFT 11 #define MONGOOSEV_UART1_IRQ_SHIFT 17 +#define MONGOOSEV_UART_FRAME_ERROR_0 \ + (MONGOOSEV_UART_FRAME_ERROR << MONGOOSEV_UART0_IRQ_SHIFT) +#define MONGOOSEV_UART_RX_OVERRUN_ERROR_0 \ + (MONGOOSEV_UART_RX_OVERRUN_ERROR << MONGOOSEV_UART0_IRQ_SHIFT) +#define MONGOOSEV_UART_TX_EMPTY_0 \ + (MONGOOSEV_UART_TX_EMPTY << MONGOOSEV_UART0_IRQ_SHIFT) +#define MONGOOSEV_UART_TX_READY_0 \ + (MONGOOSEV_UART_TX_READY << MONGOOSEV_UART0_IRQ_SHIFT) +#define MONGOOSEV_UART_RX_READY_0 \ + (MONGOOSEV_UART_RX_READY << MONGOOSEV_UART0_IRQ_SHIFT) + #define MONGOOSEV_UART_FRAME_ERROR_1 \ (MONGOOSEV_UART_FRAME_ERROR << MONGOOSEV_UART1_IRQ_SHIFT) #define MONGOOSEV_UART_RX_OVERRUN_ERROR_1 \ @@ -142,17 +153,6 @@ #define MONGOOSEV_UART_RX_READY_1 \ (MONGOOSEV_UART_RX_READY << MONGOOSEV_UART1_IRQ_SHIFT) -#define MONGOOSEV_UART_FRAME_ERROR_0 \ - (MONGOOSEV_UART_FRAME_ERROR << MONGOOSEV_UART1_IRQ_SHIFT) -#define MONGOOSEV_UART_RX_OVERRUN_ERROR_0 \ - (MONGOOSEV_UART_RX_OVERRUN_ERROR << MONGOOSEV_UART1_IRQ_SHIFT) -#define MONGOOSEV_UART_TX_EMPTY_0 \ - (MONGOOSEV_UART_TX_EMPTY << MONGOOSEV_UART1_IRQ_SHIFT) -#define MONGOOSEV_UART_TX_READY_0 \ - (MONGOOSEV_UART_TX_READY << MONGOOSEV_UART1_IRQ_SHIFT) -#define MONGOOSEV_UART_RX_READY_0 \ - (MONGOOSEV_UART_RX_READY << MONGOOSEV_UART1_IRQ_SHIFT) - /* * Bits in the Peripheral Interrupt Mask Register */ @@ -162,9 +162,9 @@ */ #define MONGOOSEV_EDAC_SERR_BIT 0x80000000 #define MONGOOSEV_EDAC_MERR_BIT 0x40000000 +/* 29 - 24 reserved */ #define MONGOOSEV_MAVN_WRITE_ACCESS 0x00800000 #define MONGOOSEV_MAVN_READ_ACCESS 0x00400000 -/* 29 - 24 reserved */ #define MONGOOSEV_UART_1_RX_READY 0x00200000 #define MONGOOSEV_UART_1_TX_READY 0x00100000 #define MONGOOSEV_UART_1_TX_EMPTY 0x00080000 @@ -189,6 +189,14 @@ #define MONGOOSEV_EXTERN_INT_0 0x00000001 +/* +** Peripheral Command bits (non-uart, those are defined above) +*/ +#define MONGOOSEV_COMMAND_ENABLE_EDAC MONGOOSEV_EDAC_SERR_BIT +#define MONGOOSEV_COMMAND_OVERRIDE_EDAC MONGOOSEV_EDAC_MERR_BIT + + + /* * EDAC Registers */ diff --git a/c/src/lib/libcpu/mips/mongoosev/vectorisrs/vectorisrs.c b/c/src/lib/libcpu/mips/mongoosev/vectorisrs/vectorisrs.c index 09e1419147..28ddf7f8b0 100644 --- a/c/src/lib/libcpu/mips/mongoosev/vectorisrs/vectorisrs.c +++ b/c/src/lib/libcpu/mips/mongoosev/vectorisrs/vectorisrs.c @@ -19,126 +19,248 @@ #include "idtcpu.h" +#include /* for printk */ + + + +int mips_default_isr( int vector ) +{ + unsigned int sr, sr2; + unsigned int cause; + + mips_get_sr( sr ); + mips_get_cause( cause ); + + sr2 = sr & ~0xff; + mips_set_sr(sr2); + + printk( "Unhandled isr exception: vector 0x%02x, cause 0x%08X, sr 0x%08X\n", vector, cause, sr ); + rtems_fatal_error_occurred(1); + return 0; +} + +/* userspace routine to assert either software interrupt */ + +int assertSoftwareInterrupt( unsigned32 n ) +{ + if( n<2 ) + { + unsigned32 c; + + mips_get_cause(c); + c = ((n+1) << CAUSE_IPSHIFT); + mips_set_cause(c); + + return n; + } + else return -1; +} + + + + + + #define CALL_ISR(_vector,_frame) \ do { \ - if ( _ISR_Vector_table[_vector] ) \ + if( _ISR_Vector_table[_vector] ) \ (_ISR_Vector_table[_vector])(_vector,_frame); \ else \ mips_default_isr(_vector); \ } while (0) -#include /* for printk */ +// +// Instrumentation tweaks for isr timing measurement, turning them off +// via this #if will remove the code entirely from the RTEMS kernel. +// + +#if 1 +#define SET_ISR_FLAG( offset ) *((unsigned32 *)(0x8001e000+offset)) = 1; +#define CLR_ISR_FLAG( offset ) *((unsigned32 *)(0x8001e000+offset)) = 0; +#else +#define SET_ISR_FLAG( offset ) +#define CLR_ISR_FLAG( offset ) +#endif + + + + + + +static volatile unsigned32 _ivcause, _ivsr; + + +static unsigned32 READ_CAUSE(void) +{ + mips_get_cause( _ivcause ); + _ivcause &= SR_IMASK; // mask off everything other than the interrupt bits + + return ((_ivcause & (_ivsr & SR_IMASK)) >> CAUSE_IPSHIFT); +} + + + +// +// This rather strangely coded routine enforces an interrupt priority +// scheme. As it runs thru finding whichever interrupt caused it to get +// here, it test for other interrupts arriving in the meantime (maybe it +// occured while the vector code is executing for instance). Each new +// interrupt will be served in order of its priority. In an effort to +// minimize overhead, the cause register is only fetched after an +// interrupt is serviced. Because of the intvect goto's, this routine +// will only exit when all interrupts have been serviced and no more +// have arrived, this improves interrupt latency at the cost of +// increasing scheduling jitter; though scheduling jitter should only +// become apparent in high interrupt load conditions. +// void mips_vector_isr_handlers( CPU_Interrupt_frame *frame ) { - unsigned32 sr, srmaskoff; - unsigned32 cause, cshifted; - unsigned32 bit; - unsigned32 pf_icr; + unsigned32 cshifted; - /* mips_get_sr( sr ); */ - sr = frame->regs[ R_SR ]; + /* mips_get_sr( sr ); */ + _ivsr = frame->regs[ R_SR ]; - mips_get_cause( cause ); + cshifted = READ_CAUSE(); - /* mask off everything other than the interrupt bits */ - cause &= SR_IMASK; + intvect: - /* mask off the pending interrupts in the status register */ - srmaskoff = sr & ~cause; - mips_set_sr( srmaskoff ); + if( cshifted & 0x3 ) + { + // making the software interrupt the highest priority is kind of + // stupid, but it makes the bit testing lots easier. On the other + // hand, these ints are infrequently used and the testing overhead + // is minimal. Who knows, high-priority software ints might be + // handy in some situation. + + /* unset both software int cause bits */ + mips_set_cause( _ivcause & ~(3 << CAUSE_IPSHIFT) ); - /* allow nesting for all non-pending interrupts */ - asm volatile( "rfe" ); + if ( cshifted & 0x01 ) /* SW[0] */ + { + CALL_ISR( MONGOOSEV_IRQ_SOFTWARE_1, frame ); + } + if ( cshifted & 0x02 ) /* SW[1] */ + { + CALL_ISR( MONGOOSEV_IRQ_SOFTWARE_2, frame ); + } + cshifted = READ_CAUSE(); + } - cshifted = (cause & (sr & SR_IMASK)) >> CAUSE_IPSHIFT; - if ( cshifted & 0x04 ) /* IP[0] ==> INT0 == TIMER1 */ - CALL_ISR( MONGOOSEV_IRQ_TIMER1, frame ); + if ( cshifted & 0x04 ) /* IP[0] ==> INT0 == TIMER1 */ + { + SET_ISR_FLAG( 0x4 ); + CALL_ISR( MONGOOSEV_IRQ_TIMER1, frame ); + CLR_ISR_FLAG( 0x4 ); + if( (cshifted = READ_CAUSE()) & 0x3 ) goto intvect; + } - if ( cshifted & 0x08 ) /* IP[1] ==> INT1 == TIMER2*/ - CALL_ISR( MONGOOSEV_IRQ_TIMER2, frame ); + if ( cshifted & 0x08 ) /* IP[1] ==> INT1 == TIMER2*/ + { + SET_ISR_FLAG( 0x8 ); + CALL_ISR( MONGOOSEV_IRQ_TIMER2, frame ); + CLR_ISR_FLAG( 0x8 ); + if( (cshifted = READ_CAUSE()) & 0x7 ) goto intvect; + } - if ( cshifted & 0x10 ) /* IP[2] ==> INT2 */ - CALL_ISR( MONGOOSEV_IRQ_INT2, frame ); + if ( cshifted & 0x10 ) /* IP[2] ==> INT2 */ + { + SET_ISR_FLAG( 0x10 ); + CALL_ISR( MONGOOSEV_IRQ_INT2, frame ); + CLR_ISR_FLAG( 0x10 ); + if( (cshifted = READ_CAUSE()) & 0xf ) goto intvect; + } - if ( cshifted & 0x20 ) /* IP[3] ==> INT3 == FPU interrupt */ - CALL_ISR( MONGOOSEV_IRQ_INT3, frame ); + if ( cshifted & 0x20 ) /* IP[3] ==> INT3 == FPU interrupt */ + { + SET_ISR_FLAG( 0x20 ); + CALL_ISR( MONGOOSEV_IRQ_INT3, frame ); + CLR_ISR_FLAG( 0x20 ); + if( (cshifted = READ_CAUSE()) & 0x1f ) goto intvect; + } - if ( cshifted & 0x40 ) /* IP[4] ==> INT4, external interrupt */ - CALL_ISR( MONGOOSEV_IRQ_INT4, frame ); + if ( cshifted & 0x40 ) /* IP[4] ==> INT4, external interrupt */ + { + SET_ISR_FLAG( 0x40 ); + CALL_ISR( MONGOOSEV_IRQ_INT4, frame ); + CLR_ISR_FLAG( 0x40 ); + if( (cshifted = READ_CAUSE()) & 0x3f ) goto intvect; + } - if ( cshifted & 0x80 ) /* IP[5] ==> INT5, peripheral interrupt */ - { - pf_icr = MONGOOSEV_READ( MONGOOSEV_PERIPHERAL_FUNCTION_INTERRUPT_CAUSE_REGISTER ); + if ( cshifted & 0x80 ) /* IP[5] ==> INT5, peripheral interrupt */ + { + unsigned32 bit; + unsigned32 pf_icr, pf_mask, pf_reset = 0; + unsigned32 i, m; - /* if !pf_icr */ - for ( bit=0 ; bit <= 31 ; bit++, pf_icr >>= 1 ) - { - if ( pf_icr & 1 ) - { - CALL_ISR( MONGOOSEV_IRQ_PERIPHERAL_BASE + bit, frame ); - } - } - } + pf_icr = MONGOOSEV_READ( MONGOOSEV_PERIPHERAL_FUNCTION_INTERRUPT_CAUSE_REGISTER ); +/* + for (bit=0, pf_mask = 1; bit < 32; bit++, pf_mask <<= 1 ) + { + if ( pf_icr & pf_mask ) + { + SET_ISR_FLAG( 0x80 + (bit*4) ); + CALL_ISR( MONGOOSEV_IRQ_PERIPHERAL_BASE + bit, frame ); + CLR_ISR_FLAG( 0x80 + (bit*4) ); + pf_reset |= pf_mask; + if( (cshifted = READ_CAUSE()) & 0xff ) break; + } + } +*/ - /* all the pending interrupts were serviced, now re-enable them */ - mips_get_sr( sr ); + // + // iterate thru 32 bits in 4 chunks of 8 bits each. This lets us + // quickly get past unasserted interrupts instead of flogging our + // way thru a full 32 bits. pf_mask shifts left 8 bits at a time + // to serve as a interrupt cause test mask. + // + for( bit=0, pf_mask = 0xff; (bit < 32 && pf_icr); (bit+=8, pf_mask <<= 8) ) + { + if ( pf_icr & pf_mask ) + { + // one or more of the 8 bits we're testing is high - /* we allow the 2 software interrupts to nest freely, under the - * assumption that the program knows what its doing... - */ - - if( cshifted & 0x3 ) - { - sr |= (SR_IBIT1 | SR_IBIT1); - cause &= ~(SR_IBIT1 | SR_IBIT1); - - mips_set_cause(cause); - mips_set_sr(sr); - - if ( cshifted & 0x01 ) /* SW[0] */ - { - CALL_ISR( MONGOOSEV_IRQ_SOFTWARE_1, frame ); - } - if ( cshifted & 0x02 ) /* SW[1] */ - { - CALL_ISR( MONGOOSEV_IRQ_SOFTWARE_2, frame ); - } - } - - sr |= cause; - mips_set_sr( sr ); -} + m = (1 << bit); -void mips_default_isr( int vector ) -{ - unsigned int sr; - unsigned int cause; + // iterate thru the 8 bits, servicing any of the interrupts + for(i=0; (i<8 && pf_icr); (i++, m <<= 1)) + { + if( pf_icr & m ) + { + SET_ISR_FLAG( 0x80 + ((bit + i) * 4) ); + CALL_ISR( MONGOOSEV_IRQ_PERIPHERAL_BASE + bit + i, frame ); + CLR_ISR_FLAG( 0x80 + ((bit + i) * 4) ); - mips_get_sr( sr ); - mips_get_cause( cause ); + // or each serviced interrupt into our interrupt clear + // mask + pf_reset |= m; - printk( "Unhandled isr exception: vector 0x%02x, cause 0x%08X, sr 0x%08X\n", - vector, cause, sr ); - rtems_fatal_error_occurred(1); -} + // xor off each int we service so we can immediately + // exit once we get the last one + pf_icr %= m; -/* userspace routine to assert either software interrupt */ + // if another interrupt has arrived, jump out right + // away but be sure to reset all the interrupts we've + // already serviced + //if( READ_CAUSE() & 0xff ) goto pfexit; + } + } + } + } + pfexit: + MONGOOSEV_WRITE( MONGOOSEV_PERIPHERAL_STATUS_REGISTER, pf_reset ); + } -int assertSoftwareInterrupt( unsigned32 n ) -{ - if( n >= 0 && n<2 ) - { - unsigned32 c; + // + // this is a last ditch interrupt check, if an interrupt arrives + // after this step, servicing it will incur the entire interrupt + // overhead cost. + // + if( (cshifted = READ_CAUSE()) & 0xff ) goto intvect; +} - mips_get_cause(c); - c = ((n+1) << 8); - mips_set_cause(c); - return n; - } - else return -1; -} +// eof diff --git a/c/src/lib/libcpu/mips/shared/interrupts/vectorexceptions.c b/c/src/lib/libcpu/mips/shared/interrupts/vectorexceptions.c index 926f4bb9d4..e57375307b 100644 --- a/c/src/lib/libcpu/mips/shared/interrupts/vectorexceptions.c +++ b/c/src/lib/libcpu/mips/shared/interrupts/vectorexceptions.c @@ -11,7 +11,7 @@ #include #include "iregdef.h" #include "idtcpu.h" -#include +#include char *cause_strings[32] = { @@ -89,6 +89,9 @@ void mips_default_exception_code_handler( int exc, CPU_Interrupt_frame *frame ) rtems_fatal_error_occurred(1); } + + + #define CALL_EXC(_vector,_frame) \ do { \ if ( _ISR_Vector_table[_vector] ) \ @@ -97,6 +100,9 @@ void mips_default_exception_code_handler( int exc, CPU_Interrupt_frame *frame ) mips_default_exception_code_handler( _vector, _frame ); \ } while(0) + + + /* * There are constants defined for these but they should basically * all be close to the same set. -- cgit v1.2.3