alt_irq_handler.c001: #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