summaryrefslogtreecommitdiffstats
path: root/c/src/lib/libcpu/mips/mongoosev/vectorisrs/vectorisrs.c
diff options
context:
space:
mode:
Diffstat (limited to 'c/src/lib/libcpu/mips/mongoosev/vectorisrs/vectorisrs.c')
-rw-r--r--c/src/lib/libcpu/mips/mongoosev/vectorisrs/vectorisrs.c300
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