summaryrefslogtreecommitdiffstats
path: root/c/src/lib/libcpu/mips/au1x00/vectorisrs/vectorisrs.c
diff options
context:
space:
mode:
Diffstat (limited to 'c/src/lib/libcpu/mips/au1x00/vectorisrs/vectorisrs.c')
-rw-r--r--c/src/lib/libcpu/mips/au1x00/vectorisrs/vectorisrs.c174
1 files changed, 174 insertions, 0 deletions
diff --git a/c/src/lib/libcpu/mips/au1x00/vectorisrs/vectorisrs.c b/c/src/lib/libcpu/mips/au1x00/vectorisrs/vectorisrs.c
new file mode 100644
index 0000000000..01256e38ad
--- /dev/null
+++ b/c/src/lib/libcpu/mips/au1x00/vectorisrs/vectorisrs.c
@@ -0,0 +1,174 @@
+/*
+ * Au1x00 Interrupt Vectoring
+ *
+ * Copyright (c) 2005 by Cogent Computer Systems
+ * Written by Jay Monkman <jtm@lopingdog.com>
+ *
+ * The license and distribution terms for this file may be
+ * found in the file LICENSE in this distribution or at
+ *
+ * http://www.OARcorp.com/rtems/license.html.
+ *
+ * $Id$
+ */
+
+#include <rtems.h>
+#include <stdlib.h>
+#include <libcpu/au1x00.h>
+
+void mips_default_isr( int vector );
+static void call_vectored_isr(CPU_Interrupt_frame *, unsigned32 , void *);
+
+#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 <rtems/bspIo.h> /* for printk */
+
+void mips_vector_isr_handlers( CPU_Interrupt_frame *frame )
+{
+ unsigned int sr;
+ unsigned int cause;
+
+ mips_get_sr( sr );
+ mips_get_cause( cause );
+
+ cause &= (sr & SR_IMASK);
+ cause >>= CAUSE_IPSHIFT;
+
+ /* count/compare interrupt */
+ if ( cause & 0x80 ) {
+ unsigned long zero = 0;
+ /*
+ * I don't see a good way to disable the compare
+ * interrupt, so let's just ignore it.
+ */
+ asm volatile ("mtc0 %0, $11\n" :: "r" (zero));
+
+/* CALL_ISR( AU1X00_IRQ_CNT, frame ); */
+ }
+
+ /* Performance counter */
+ if ( cause & 0x40 ) {
+ CALL_ISR( AU1X00_IRQ_PERF, frame );
+ }
+
+ /* Interrupt controller 0 */
+ if ( cause & 0x0c ) {
+ call_vectored_isr(frame, cause, (void *)AU1X00_IC0_ADDR);
+ }
+
+ /* Interrupt controller 1 */
+ if ( cause & 0x30 ) {
+ call_vectored_isr(frame, cause, (void *)AU1X00_IC1_ADDR);
+ }
+
+ /* SW[0] */
+ if ( cause & 0x01 )
+ CALL_ISR( AU1X00_IRQ_SW0, frame );
+
+ /* SW[1] */
+ if ( cause & 0x02 )
+ CALL_ISR( AU1X00_IRQ_SW1, frame );
+}
+
+void mips_default_isr( int vector )
+{
+ unsigned int sr;
+ 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 );
+ rtems_fatal_error_occurred(1);
+}
+
+static void call_vectored_isr(
+ CPU_Interrupt_frame *frame,
+ unsigned32 cause,
+ void *ctrlr
+ )
+{
+ unsigned32 src;
+ unsigned32 mask;
+ int index;
+
+ /* get mask register */
+ mask = AU1X00_IC_MASKRD(ctrlr);
+
+ /* check request 0 */
+ src = AU1X00_IC_REQ0INT(ctrlr);
+ src = src & mask;
+ index = 0;
+ while (src) {
+ /* check LSB */
+ if (src & 1) {
+ /* clear rising/falling edge detects */
+ AU1X00_IC_RISINGCLR(ctrlr) = (1 << index);
+ AU1X00_IC_FALLINGCLR(ctrlr) = (1 << index);
+ au_sync();
+ CALL_ISR(AU1X00_IRQ_IC0_BASE + index, frame);
+ }
+ index ++;
+
+ /* shift, and make sure MSB is clear */
+ src = (src >> 1) & 0x7fffffff;
+ }
+
+ /* check request 1 */
+ src = AU1X00_IC_REQ1INT(ctrlr);
+ src = src & mask;
+ index = 0;
+ while (src) {
+ /* check LSB */
+ if (src & 1) {
+ /* clear rising/falling edge detects */
+ AU1X00_IC_RISINGCLR(ctrlr) = (1 << index);
+ AU1X00_IC_FALLINGCLR(ctrlr) = (1 << index);
+ au_sync();
+ CALL_ISR(AU1X00_IRQ_IC0_BASE + index, frame);
+ }
+ index ++;
+
+ /* shift, and make sure MSB is clear */
+ src = (src >> 1) & 0x7fffffff;
+ }
+}
+
+/* Generate a software interrupt */
+int assert_sw_irq(unsigned32 irqnum)
+{
+ unsigned32 cause;
+
+ if (irqnum <= 1) {
+ mips_get_cause(cause);
+ cause = cause | ((irqnum + 1) << CAUSE_IPSHIFT);
+ mips_set_cause(cause);
+
+ return irqnum;
+ } else {
+ return -1;
+ }
+}
+
+/* Clear a software interrupt */
+int negate_sw_irq(unsigned32 irqnum)
+{
+ unsigned32 cause;
+
+ if (irqnum <= 1) {
+ mips_get_cause(cause);
+ cause = cause & ~((irqnum + 1) << CAUSE_IPSHIFT);
+ mips_set_cause(cause);
+
+ return irqnum;
+ } else {
+ return -1;
+ }
+}