alt_irq_handler.c


001: #include <errno.h>
002: 
003: #include "system.h"
004: #include "sys/alt_irq.h"
005: #include "os/alt_hooks.h"
006: 
007: #include "alt_types.h"
008: 
009: /*
010:  * The header, alt_irq_table.h contains a table describing which function
011:  * handles each interrupt.
012:  */
013: 
014: #include "priv/alt_irq_table.h"
015: 
016: /*
017:  * alt_irq_handler() is called by the interrupt exception handler in order to 
018:  * process any outstanding interrupts. 
019:  *
020:  * It is defined here since (in the case of nios2) it is linked in using weak 
021:  * linkage. This means that if there is never a call to alt_irq_register() 
022:  * (above) then this function will not get linked in to the executable. This is
023:  * acceptable since if no handler is ever registered, then an interrupt can never
024:  * occur.
025:  *
026:  * If Nios II interrupt vector custom instruction exists, use it to accelerate
027:  * the dispatch of interrupt handlers.  The Nios II interrupt vector custom 
028:  * instruction is present if the macro ALT_CI_INTERRUPT_VECTOR defined.
029:  */
030: 
031: void alt_irq_handler (void) __attribute__ ((section (".exceptions")));
032: void alt_irq_handler (void)
033: {
034: #ifdef ALT_CI_INTERRUPT_VECTOR
035:   alt_32 offset;
036:   char*  alt_irq_base = (char*)alt_irq;
037: #else
038:   alt_u32 active;
039:   alt_u32 mask;
040:   alt_u32 i;
041: #endif /* ALT_CI_INTERRUPT_VECTOR */
042:   
043:   /*
044:    * Notify the operating system that we are at interrupt level.
045:    */ 
046:   
047:   ALT_OS_INT_ENTER();
048: 
049: #ifdef ALT_CI_INTERRUPT_VECTOR
050:   /*
051:    * Call the interrupt vector custom instruction using the 
052:    * ALT_CI_INTERRUPT_VECTOR macro.
053:    * It returns the offset into the vector table of the lowest-valued pending
054:    * interrupt (corresponds to highest priority) or a negative value if none.
055:    * The custom instruction assumes that each table entry is eight bytes.
056:    */
057:   while ((offset = ALT_CI_INTERRUPT_VECTOR) >= 0) {
058:     struct ALT_IRQ_HANDLER* handler_entry = 
059:       (struct ALT_IRQ_HANDLER*)(alt_irq_base + offset);
060: 
061:     handler_entry->handler(handler_entry->context, offset >> 3);
062:   }
063: #else
064:   /* 
065:    * Obtain from the interrupt controller a bit list of pending interrupts,
066:    * and then process the highest priority interrupt. This process loops, 
067:    * loading the active interrupt list on each pass until alt_irq_pending() 
068:    * return zero.
069:    * 
070:    * The maximum interrupt latency for the highest priority interrupt is
071:    * reduced by finding out which interrupts are pending as late as possible.
072:    * Consider the case where the high priority interupt is asserted during
073:    * the interrupt entry sequence for a lower priority interrupt to see why
074:    * this is the case.
075:    */
076: 
077:   active = alt_irq_pending ();
078: 
079:   do
080:   {
081:     i = 0;
082:     mask = 1;
083: 
084:     /*
085:      * Test each bit in turn looking for an active interrupt. Once one is 
086:      * found, the interrupt handler asigned by a call to alt_irq_register() is
087:      * called to clear the interrupt condition.
088:      */
089: 
090:     do
091:     {
092:       if (active & mask)
093:       { 
094:         alt_irq[i].handler(alt_irq[i].context, i); 
095:         break;
096:       }
097:       mask <<= 1;
098:       i++;
099: 
100:     } while (1);
101: 
102:     active = alt_irq_pending ();
103:     
104:   } while (active);
105: #endif /* ALT_CI_INTERRUPT_VECTOR */
106: 
107:   /*
108:    * Notify the operating system that interrupt processing is complete.
109:    */ 
110: 
111:   ALT_OS_INT_EXIT();
112: }


Maintained by John Loomis, updated Thu Nov 13 22:27:00 2008