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