summaryrefslogblamecommitdiffstats
path: root/c/src/lib/libcpu/mips/au1x00/vectorisrs/vectorisrs.c
blob: 7eb1ae12404ad8cf7964a4dd3d0e992e782ab14b (plain) (tree)
1
2
3
4
5
6
7
8
9
  
                              


                                                
  

                                                           
                                         







                          
                                                                        

























                                                           
                                                      

                                            
                                                        







                                              
 



                                                               
 



                                                               
 


                                        
 
             
                     
















                                                                              

                               


               

                  












































                                                         
                                  
 
                   












                                                        
                                  
 
                   










                                                         
/*
 *  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.rtems.com/license/LICENSE.
 *
 *  $Id$
 */

#include <rtems.h>
#include <stdlib.h>
#include <libcpu/au1x00.h>

static void call_vectored_isr(CPU_Interrupt_frame *, uint32_t , 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,
    uint32_t cause,
    void *ctrlr
    )
{
    uint32_t src;
    uint32_t 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(uint32_t irqnum)
{
    uint32_t 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(uint32_t irqnum)
{
    uint32_t cause;

    if (irqnum <= 1) {
        mips_get_cause(cause);
        cause = cause & ~((irqnum + 1) << CAUSE_IPSHIFT);
        mips_set_cause(cause);

        return irqnum;
    } else {
        return -1;
    }
}