diff options
Diffstat (limited to 'c/src/lib/libcpu/mips/mongoosev/vectorisrs/vectorisrs.c')
-rw-r--r-- | c/src/lib/libcpu/mips/mongoosev/vectorisrs/vectorisrs.c | 300 |
1 files changed, 211 insertions, 89 deletions
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 <bspIo.h> /* 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 <rtems/bspIo.h> /* 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 |