* 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.
This commit is contained in:
Joel Sherrill
2002-02-01 15:15:02 +00:00
parent e6dec71c27
commit 2835b3a568
5 changed files with 323 additions and 117 deletions

View File

@@ -1,3 +1,19 @@
2001-02-01 Greg Menke <gregory.menke@gsfc.nasa.gov>
* 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 <corsepiu@faw.uni-ulm.de>
* mongoosev/vectorisrs/vectorisrs.c: Include rtems/bspIo.h instead of bspIo.h.

View File

@@ -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.

View File

@@ -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
*/

View File

@@ -19,122 +19,36 @@
#include "idtcpu.h"
#define CALL_ISR(_vector,_frame) \
do { \
if ( _ISR_Vector_table[_vector] ) \
(_ISR_Vector_table[_vector])(_vector,_frame); \
else \
mips_default_isr(_vector); \
} while (0)
#include <bspIo.h> /* for printk */
#include <rtems/bspIo.h> /* for printk */
void mips_vector_isr_handlers( CPU_Interrupt_frame *frame )
int mips_default_isr( int vector )
{
unsigned32 sr, srmaskoff;
unsigned32 cause, cshifted;
unsigned32 bit;
unsigned32 pf_icr;
/* mips_get_sr( sr ); */
sr = frame->regs[ R_SR ];
mips_get_cause( cause );
/* mask off everything other than the interrupt bits */
cause &= SR_IMASK;
/* mask off the pending interrupts in the status register */
srmaskoff = sr & ~cause;
mips_set_sr( srmaskoff );
/* allow nesting for all non-pending interrupts */
asm volatile( "rfe" );
cshifted = (cause & (sr & SR_IMASK)) >> CAUSE_IPSHIFT;
if ( cshifted & 0x04 ) /* IP[0] ==> INT0 == TIMER1 */
CALL_ISR( MONGOOSEV_IRQ_TIMER1, frame );
if ( cshifted & 0x08 ) /* IP[1] ==> INT1 == TIMER2*/
CALL_ISR( MONGOOSEV_IRQ_TIMER2, frame );
if ( cshifted & 0x10 ) /* IP[2] ==> INT2 */
CALL_ISR( MONGOOSEV_IRQ_INT2, frame );
if ( cshifted & 0x20 ) /* IP[3] ==> INT3 == FPU interrupt */
CALL_ISR( MONGOOSEV_IRQ_INT3, frame );
if ( cshifted & 0x40 ) /* IP[4] ==> INT4, external interrupt */
CALL_ISR( MONGOOSEV_IRQ_INT4, frame );
if ( cshifted & 0x80 ) /* IP[5] ==> INT5, peripheral interrupt */
{
pf_icr = MONGOOSEV_READ( MONGOOSEV_PERIPHERAL_FUNCTION_INTERRUPT_CAUSE_REGISTER );
/* if !pf_icr */
for ( bit=0 ; bit <= 31 ; bit++, pf_icr >>= 1 )
{
if ( pf_icr & 1 )
{
CALL_ISR( MONGOOSEV_IRQ_PERIPHERAL_BASE + bit, frame );
}
}
}
/* all the pending interrupts were serviced, now re-enable them */
mips_get_sr( sr );
/* 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 );
}
void mips_default_isr( int vector )
{
unsigned int sr;
unsigned int sr, sr2;
unsigned int cause;
mips_get_sr( sr );
mips_get_cause( cause );
printk( "Unhandled isr exception: vector 0x%02x, cause 0x%08X, sr 0x%08X\n",
vector, cause, sr );
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 >= 0 && n<2 )
if( n<2 )
{
unsigned32 c;
mips_get_cause(c);
c = ((n+1) << 8);
c = ((n+1) << CAUSE_IPSHIFT);
mips_set_cause(c);
return n;
@@ -142,3 +56,211 @@ int assertSoftwareInterrupt( unsigned32 n )
else return -1;
}
#define CALL_ISR(_vector,_frame) \
do { \
if( _ISR_Vector_table[_vector] ) \
(_ISR_Vector_table[_vector])(_vector,_frame); \
else \
mips_default_isr(_vector); \
} while (0)
//
// 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 cshifted;
/* mips_get_sr( sr ); */
_ivsr = frame->regs[ R_SR ];
cshifted = READ_CAUSE();
intvect:
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) );
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();
}
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*/
{
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 */
{
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 */
{
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 */
{
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 */
{
unsigned32 bit;
unsigned32 pf_icr, pf_mask, pf_reset = 0;
unsigned32 i, m;
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;
}
}
*/
//
// 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
m = (1 << bit);
// 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) );
// or each serviced interrupt into our interrupt clear
// mask
pf_reset |= m;
// xor off each int we service so we can immediately
// exit once we get the last one
pf_icr %= m;
// 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 );
}
//
// 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;
}
// eof

View File

@@ -11,7 +11,7 @@
#include <stdlib.h>
#include "iregdef.h"
#include "idtcpu.h"
#include <rtems/bspIo.h>
#include <bspIo.h>
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.