Changeset 189 for soft/giet_vm/sys/irq_handler.c
- Timestamp:
- Aug 7, 2012, 6:37:49 PM (12 years ago)
- File:
-
- 1 edited
Legend:
- Unmodified
- Added
- Removed
-
soft/giet_vm/sys/irq_handler.c
r169 r189 2 2 // File : irq_handler.c 3 3 // Date : 01/04/2012 4 // Author : alain greiner and joel porquet4 // Author : alain greiner 5 5 // Copyright (c) UPMC-LIP6 6 6 /////////////////////////////////////////////////////////////////////////////////// 7 // The irq_handler.c and irq_handler.h files are part of the GIET nano-kernel.8 // They contain the code of the _i nt_demux function that handle9 // the ICU (Interupt Controler Unit), and the various ISRs associated10 // to the CoCLibperipherals.7 // The irq_handler.c and irq_handler.h files are part of the GIET-VM nano-kernel. 8 // They contain the code of the _irq_demux() function that access the XICU or 9 // ICU component (Interupt Controler Unit), and the various ISRs (Interrupt 10 // Service Routine) associated to the peripherals. 11 11 /////////////////////////////////////////////////////////////////////////////////// 12 12 … … 20 20 21 21 /////////////////////////////////////////////////////////////////////////////////// 22 // Initialize the whole interrupt vector with the default ISR 23 /////////////////////////////////////////////////////////////////////////////////// 24 25 __attribute__((section (".kdata"))) _isr_func_t _interrupt_vector[32] = 26 { [0 ... 31] = &_isr_default }; 27 28 /////////////////////////////////////////////////////////////////////////////////// 29 // _int_demux() 30 // This functions uses an external ICU component (Interrupt Controler Unit) 31 // that concentrates up to 32 input interrupts lines. This component 32 // can support up to NB_PROCS output IRQ. 22 // _irq_demux() 23 // This function uses the ICU or XICU component (Interrupt Controler Unit) 24 // to get the interrupt vector entry. There is one ICU or XICU component per 25 // cluster, and this component can support up to NB_PROCS_MAX output IRQs. 26 // It returns the highest priority active interrupt index (smaller 27 // indexes have the highest priority). 28 // Any value larger than 31 means "no active interrupt", and no ISR is executed. 33 29 // 34 // Th is component returns the highest priority active interrupt index (smaller35 // indexes have the highest priority) by reading the ICU_IT_VECTOR register.36 // Any value larger than 31 means "no active interrupt", and the default ISR37 // (that does nothing) is executed.30 // There is one interrupt vector per processor (stored in the scheduler associated 31 // to the processor. Each interrupt vector entry contains two 16 bits fields: 32 // - isr_id : defines the type of ISR to be executed. 33 // - channel_id : defines the specific channel for multi-channels peripherals. 38 34 // 39 // The interrupt vector (32 ISR addresses array stored at _interrupt_vector 40 // address) is initialised with the default ISR address. The actual ISR 41 // addresses are supposed to be written in the interrupt vector array 42 // during system initialisation. 43 /////////////////////////////////////////////////////////////////////////////////// 44 void _int_demux(void) 45 { 46 int interrupt_index; 47 _isr_func_t isr; 48 unsigned int pid = _procid(); 49 50 // retrieves the highest priority active interrupt index 51 if (!_icu_read( pid / NB_PROCS, 52 pid % NB_PROCS, 35 // If the peripheral is replicated in clusters (TIMER or DMA), the channel_id is 36 // a global index : channel_id = cluster_id * NB_CHANNELS_MAX + loc_id 37 /////////////////////////////////////////////////////////////////////////////////// 38 void _irq_demux() 39 { 40 unsigned int pid = _procid(); 41 unsigned int irq_id; 42 43 // get the highest priority active IRQ index 44 45 #if GIET_USE_XICU 46 47 #else 48 49 if ( _icu_read( pid / NB_PROCS_MAX, 50 pid % NB_PROCS_MAX, 53 51 ICU_IT_VECTOR, 54 (unsigned int*)&interrupt_index) )52 &irq_id ) ) 55 53 { 56 if (interrupt_index == -1) // no interrupt is active 57 return; 58 59 isr = _interrupt_vector[interrupt_index]; 60 isr(); 61 } 62 else 63 { 64 _puts("\n[GIET ERROR] In _demux function : wrong arguments in _icu_read()\n"); 54 _puts("\n[GIET ERROR] wrong _icu_read in _irq_demux() function\n"); 65 55 _exit(); 66 56 } 57 58 #endif 59 60 if ( irq_id < 32 ) // do nothing if no interrupt active 61 { 62 unsigned int entry = _get_interrupt_vector_entry(irq_id); 63 unsigned int isr_id = entry & 0x000000FF; 64 unsigned int channel_id = (entry>>16) & 0x0000FFFF; 65 if ( isr_id == ISR_SWITCH ) _isr_switch(); 66 else if ( isr_id == ISR_IOC ) _isr_ioc(); 67 else if ( isr_id == ISR_DMA ) _isr_dma( channel_id ); 68 else if ( isr_id == ISR_TTY ) _isr_tty( channel_id ); 69 else if ( isr_id == ISR_TIMER ) _isr_timer( channel_id ); 70 else _isr_default(); 71 } 67 72 } 68 73 /////////////////////////////////////////////////////////////////////////////////// 69 74 // _isr_default() 70 75 // The default ISR is called when no specific ISR has been installed in the 71 // interrupt vector. It simply displays a message on TTY0.76 // interrupt vector. It simply displays a message on kernel TTY[0]. 72 77 /////////////////////////////////////////////////////////////////////////////////// 73 78 void _isr_default() 74 79 { 75 _puts("\n\n!!! Default ISR!!!\n");80 _puts("\n\n!!! Strange... Default ISR activated !!!\n"); 76 81 } 77 82 78 83 /////////////////////////////////////////////////////////////////////////////////// 79 84 // _isr_dma() 80 // This ISR handles up to 8 IRQs generated by 8 independant channels of the 81 // multi_dma component. It acknowledges the interrupt and reset the synchronisation 82 // variable _dma_busy[i], after copying the status into the _dma_status[i] variable. 83 /////////////////////////////////////////////////////////////////////////////////// 84 void _isr_dma_indexed( unsigned int dma_id ) 85 { 86 volatile unsigned int* dma_address; 85 // This ISR handles all IRQs generated by the multi-channels DMA controlers. 86 // The multi_dma components can be distributed in the clusters. 87 // The channel_id argument is the global DMA channel index. 88 // channel_id = cluster_id*NB_DMAS_MAX + loc_id 89 // - The ISR saves the transfert status in _dma_status[channel_id]. 90 // - It acknowledges the interrupt to reinitialize the DMA controler. 91 // - it resets the synchronisation variable _dma_busy[channel_id]. 92 /////////////////////////////////////////////////////////////////////////////////// 93 void _isr_dma( unsigned int channel_id ) 94 { 95 // compute cluster_id and loc_id 96 unsigned int cluster_id = channel_id / NB_DMAS_MAX; 97 unsigned int loc_id = channel_id % NB_DMAS_MAX; 87 98 88 99 // compute DMA channel address 89 dma_address = (unsigned int*)&seg_dma_base + (dma_id * DMA_SPAN); 100 unsigned int* dma_address = (unsigned int*)&seg_dma_base + 101 (loc_id * DMA_SPAN) + 102 (cluster_id * CLUSTER_SPAN); 90 103 91 104 // save DMA channel status 92 _dma_status[ dma_id] = dma_address[DMA_LEN]; /* save status */105 _dma_status[channel_id] = dma_address[DMA_LEN]; 93 106 94 107 // reset DMA channel 95 dma_address[DMA_RESET] = 0; /* reset IRQ */108 dma_address[DMA_RESET] = 0; 96 109 97 110 // release DMA channel 98 _dma_busy[dma_id] = 0; /* release DMA */ 99 } 100 101 void _isr_dma_0() { _isr_dma_indexed(0); } 102 void _isr_dma_1() { _isr_dma_indexed(1); } 103 void _isr_dma_2() { _isr_dma_indexed(2); } 104 void _isr_dma_3() { _isr_dma_indexed(3); } 105 void _isr_dma_4() { _isr_dma_indexed(4); } 106 void _isr_dma_5() { _isr_dma_indexed(5); } 107 void _isr_dma_6() { _isr_dma_indexed(6); } 108 void _isr_dma_7() { _isr_dma_indexed(7); } 111 _dma_done[channel_id] = 1; 112 } 109 113 110 114 /////////////////////////////////////////////////////////////////////////////////// 111 115 // _isr_ioc() 112 // There is only one IOC controler shared by all tasks. It acknowledge the IRQ113 // using the ioc base address, save the status, and set the _ioc_done variable114 // to signal completion.116 // There is only one IOC controler shared by all tasks. 117 // - The ISR save the status and acknowledge the IRQ. 118 // - It sets the _ioc_done variable to signal completion. 115 119 /////////////////////////////////////////////////////////////////////////////////// 116 120 void _isr_ioc() 117 121 { 118 volatile unsigned int* ioc_address; 119 120 ioc_address = (unsigned int*)&seg_ioc_base; 122 unsigned int* ioc_address = (unsigned int*)&seg_ioc_base; 121 123 122 124 _ioc_status = ioc_address[BLOCK_DEVICE_STATUS]; /* save status & reset IRQ */ … … 125 127 126 128 /////////////////////////////////////////////////////////////////////////////////// 127 // _isr_timer_* (* = 0,1,2,3,4,5,6,7) 128 // This ISR handles up to 8 IRQs generated by 8 independant timers. 129 // It acknowledges the IRQ on TIMER[*] and displays a message on TTY0 130 /////////////////////////////////////////////////////////////////////////////////// 131 void _isr_timer_indexed(unsigned int timer_id) 132 { 133 volatile unsigned int *timer_address; 134 135 timer_address = (unsigned int*)&seg_timer_base + (timer_id * TIMER_SPAN); 136 137 timer_address[TIMER_RESETIRQ] = 0; /* reset IRQ */ 138 139 _puts("\n\n!!! Interrupt timer received from timer "); 140 _putw( timer_id ); 141 _puts(" at cycle "); 142 _putw( _proctime() ); 143 _puts("\n\n"); 144 } 145 146 void _isr_timer_0() { _isr_timer_indexed(0); } 147 void _isr_timer_1() { _isr_timer_indexed(1); } 148 void _isr_timer_2() { _isr_timer_indexed(2); } 149 void _isr_timer_3() { _isr_timer_indexed(3); } 150 void _isr_timer_4() { _isr_timer_indexed(4); } 151 void _isr_timer_5() { _isr_timer_indexed(5); } 152 void _isr_timer_6() { _isr_timer_indexed(6); } 153 void _isr_timer_7() { _isr_timer_indexed(7); } 154 155 /////////////////////////////////////////////////////////////////////////////////// 156 // _isr_tty_get_* (* = 0,1,2,3,4,5,6,7,9,10,11,12,13,14,15) 157 // The Giet supports up to 16 TTY terminals. 158 // These 16 ISRs handle the up to 16 IRQs associated to 16 independant 159 // terminals, signaling that a character is available. 160 // There is one communication buffer _tty_get_buf[tty_id] per terminal. 161 // The sychronisation variable _tty_get_full[tty_id], is set by the ISR, 129 // _isr_timer() 130 // This ISR handles the IRQs generated by the "user" timers (the IRQs 131 // generated by the "system" timers should be handled by the _isr_switch(). 132 // These timers are distributed in all clusters, and can be implemented 133 // in a vci_multi_timer component, or in a vci_xicu component. 134 // The channel_id argument is the global channel index: 135 // channel_id = cluster_id*(NB_TIMERS_MAX+NB_PROCS_MAX) + loc_id 136 // The user timer local index is (loc_id - NB_PROCS_MAX). 137 // 138 // The ISR acknowledges the IRQ and registers the event in the proper entry 139 // of the _timer_event[] array. 140 // A log message is displayed on the kernel terminal. 141 /////////////////////////////////////////////////////////////////////////////////// 142 void _isr_timer(unsigned int channel_id) 143 { 144 145 unsigned int cluster_id = channel_id / (NB_TIMERS_MAX + NB_PROCS_MAX); 146 unsigned int loc_id = channel_id % (NB_TIMERS_MAX + NB_PROCS_MAX); 147 148 if (loc_id < NB_PROCS_MAX ) 149 { 150 _puts("[GIET ERROR] Receiving a user timer IRQ for a system timer\n"); 151 _puts(" cluster = "); 152 _putw(cluster_id); 153 _puts(" / local_id = "); 154 _putw(loc_id); 155 } 156 157 #if GIET_USE_XICU 158 159 // TODO 160 161 #else 162 163 // compute Timer address 164 unsigned int* timer_address = (unsigned int*)&seg_timer_base + 165 (loc_id * TIMER_SPAN) + 166 (cluster_id * CLUSTER_SPAN); 167 168 // reset IRQ 169 timer_address[TIMER_RESETIRQ] = 0; 170 171 #endif 172 173 #if NB_TIMERS_MAX 174 // register the event 175 _timer_event[(cluster_id*NB_TIMERS_MAX) + (loc_id - NB_PROCS_MAX)] = 1; 176 #endif 177 178 // display a message on TTY 0 179 _puts("[GIET] User Timer IRQ / cluster = "); 180 _putw(cluster_id); 181 _puts(" / timer = "); 182 _putw(loc_id - NB_PROCS_MAX); 183 _puts("\n"); 184 } 185 186 /////////////////////////////////////////////////////////////////////////////////// 187 // _isr_tty() 188 // This ISR handles the IRQs generated by the multi_tty controler, 189 // signaling that a character is available. 190 // There is one single multi_tty component controling all TTYs, and the tty_id 191 // argument is the global TTY index. 192 // There is one communication buffer _tty_buf[tty_id] per terminal. 193 // The sychronisation variable _tty_full[tty_id], is set by the ISR, 162 194 // and reset by the OS. 163 195 // A character is lost if the buffer is full when the ISR is executed. 164 196 /////////////////////////////////////////////////////////////////////////////////// 165 void _isr_tty_get_indexed(unsigned int tty_id) 166 { 167 volatile unsigned int *tty_address; 168 169 /* compute terminal base address */ 170 tty_address = (unsigned int*)&seg_tty_base + (tty_id * TTY_SPAN); 171 172 /* save character and reset IRQ */ 197 void _isr_tty(unsigned int tty_id) 198 { 199 // compute terminal base address 200 unsigned int *tty_address = (unsigned int*)&seg_tty_base + (tty_id * TTY_SPAN); 201 202 // save character and reset IRQ 173 203 _tty_get_buf[tty_id] = (unsigned char)tty_address[TTY_READ]; 174 204 175 / * signals character available */205 // signals character available 176 206 _tty_get_full[tty_id] = 1; 177 207 } 178 179 void _isr_tty_get_0() { _isr_tty_get_indexed(0); }180 void _isr_tty_get_1() { _isr_tty_get_indexed(1); }181 void _isr_tty_get_2() { _isr_tty_get_indexed(2); }182 void _isr_tty_get_3() { _isr_tty_get_indexed(3); }183 void _isr_tty_get_4() { _isr_tty_get_indexed(4); }184 void _isr_tty_get_5() { _isr_tty_get_indexed(5); }185 void _isr_tty_get_6() { _isr_tty_get_indexed(6); }186 void _isr_tty_get_7() { _isr_tty_get_indexed(7); }187 void _isr_tty_get_8() { _isr_tty_get_indexed(8); }188 void _isr_tty_get_9() { _isr_tty_get_indexed(9); }189 void _isr_tty_get_10() { _isr_tty_get_indexed(10); }190 void _isr_tty_get_11() { _isr_tty_get_indexed(11); }191 void _isr_tty_get_12() { _isr_tty_get_indexed(12); }192 void _isr_tty_get_13() { _isr_tty_get_indexed(13); }193 void _isr_tty_get_14() { _isr_tty_get_indexed(14); }194 void _isr_tty_get_15() { _isr_tty_get_indexed(15); }195 208 196 209 ///////////////////////////////////////////////////////////////////////////////////// 197 210 // _isr_switch 198 // This ISR is in charge of context switch. 199 // It acknowledges the IRQ on TIMER[proc_id] and calls the _ctx_switch() function. 211 // This ISR is in charge of context switch, and handle the IRQs generated by 212 // the "system" timers. 213 // The IRQs can be generated by the MULTI_TIMER component or by the XICU component, 214 // that are distributed in all clusters. 215 // The ISR acknowledges the IRQ and calls the _ctx_switch() function. 200 216 ///////////////////////////////////////////////////////////////////////////////////// 201 217 void _isr_switch() 202 218 { 203 volatile unsigned int *timer_address; 204 unsigned int proc_id; 205 206 proc_id = _procid(); 207 timer_address = (unsigned int*)&seg_timer_base + (proc_id * TIMER_SPAN); 208 209 timer_address[TIMER_RESETIRQ] = 0; /* reset IRQ */ 219 // get cluster index and proc local index 220 unsigned int pid = _procid(); 221 unsigned int loc_id = pid % NB_PROCS_MAX; 222 unsigned int cluster_id = pid / NB_PROCS_MAX; 223 224 #if GIET_USE_XICU 225 226 unsigned int* timer_address = // TODO 227 228 #else 229 230 // compute Timer address 231 unsigned int* timer_address = (unsigned int*)&seg_timer_base + 232 (loc_id * TIMER_SPAN) + 233 (cluster_id * CLUSTER_SPAN); 234 235 // reset IRQ 236 timer_address[TIMER_RESETIRQ] = 0; 237 238 #endif 239 240 // performs the context switch 210 241 _ctx_switch(); 211 } 212 242 243 } 244
Note: See TracChangeset
for help on using the changeset viewer.