Changeset 294 for soft/giet_vm/giet_kernel/irq_handler.c
- Timestamp:
- Mar 26, 2014, 6:10:01 PM (11 years ago)
- File:
-
- 1 edited
Legend:
- Unmodified
- Added
- Removed
-
soft/giet_vm/giet_kernel/irq_handler.c
r281 r294 4 4 // Author : alain greiner 5 5 // Copyright (c) UPMC-LIP6 6 ///////////////////////////////////////////////////////////////////////////////////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 or9 // ICU component (Interupt Controler Unit), and the various ISRs (Interrupt10 // Service Routine) associated to the peripherals.11 6 /////////////////////////////////////////////////////////////////////////////////// 12 7 … … 19 14 #include <xcu_driver.h> 20 15 #include <tty_driver.h> 21 #include <ioc_driver.h> 16 #include <nic_driver.h> 17 #include <cma_driver.h> 18 #include <bdv_driver.h> 22 19 #include <dma_driver.h> 23 20 #include <mapping_info.h> … … 40 37 // Any value larger than 31 means "no active interrupt", and no ISR is executed. 41 38 // 42 // There is one interrupt vector per processor (stored in the scheduler associated43 // to the processor. Each interrupt vector entry contains four bits fields:44 // - isr_id bits[7:0] : defines the type of ISR to be executed.45 // - type_id bits[15:8] : IRQ_TYPE_HWI / IRQ_TYPE_SWI / IRQ_TYPE_PTI39 // There is three interrupt vectors per processor (stored in the processor's 40 // scheduler) for the three HWI, PTI, and WTI interrupts types. 41 // Each interrupt vector entry contains three bits fields: 42 // - isr_id bits[15:0] : defines the type of ISR to be executed. 46 43 // - channel_id bits[30:16] : defines the channel for multi-channels peripherals. 47 44 // - valid bit 31 : valid interrupt vector entry 48 // If the peripheral is replicated in clusters (TIMER or DMA), the channel_id is45 // If the peripheral is replicated in clusters, the channel_id is 49 46 // a global index : channel_id = cluster_id * NB_CHANNELS_MAX + loc_id 50 47 /////////////////////////////////////////////////////////////////////////////////// 51 48 void _irq_demux() 52 49 { 53 unsigned int gpid = _get_procid(); 54 unsigned int cluster_id = gpid / NB_PROCS_MAX; 55 unsigned int local_id = gpid % NB_PROCS_MAX; 50 unsigned int gpid = _get_procid(); 51 unsigned int cluster_xy = gpid / NB_PROCS_MAX; 52 unsigned int x = cluster_xy >> Y_WIDTH; 53 unsigned int y = cluster_xy & ((1<<Y_WIDTH)-1); 54 unsigned int lpid = gpid % NB_PROCS_MAX; 56 55 unsigned int irq_id; 57 unsigned int ko; 56 unsigned int irq_type; 57 char* irq_type_str[] = { "HWI", "WTI", "PTI" }; 58 58 59 59 // get the highest priority active IRQ index 60 61 unsigned int icu_out_index = local_id * IRQ_PER_PROCESSOR; 60 unsigned int icu_out_index = lpid * IRQ_PER_PROCESSOR; 62 61 63 62 #if USE_XICU 64 ko = _xcu_get_index( cluster_id, icu_out_index, &irq_id);63 _xcu_get_index( cluster_xy, icu_out_index, &irq_id, &irq_type ); 65 64 #else 66 ko = _icu_get_index( cluster_id, icu_out_index, &irq_id ); 67 #endif 68 69 if ( ko ) 70 { 71 _tty_get_lock( 0 ); 72 _puts("\n[GIET ERROR] Wrong _icu_read in _irq_demux()\n"); 73 _tty_release_lock( 0 ); 74 } 75 76 // do nothing if no interrupt active, or 65 irq_type = IRQ_TYPE_HWI; 66 _icu_get_index( cluster_xy, icu_out_index, &irq_id ); 67 #endif 68 77 69 if (irq_id < 32) 78 70 { 79 static_scheduler_t* psched = (static_scheduler_t*)_get_sched(); 80 unsigned int entry = psched->interrupt_vector[irq_id]; 81 unsigned int isr_id = (entry ) & 0x000000FF; 82 unsigned int type_id = (entry>> 8) & 0x000000FF; 83 unsigned int channel_id = (entry>>16) & 0x00007FFF; 84 85 if(type_id == IRQ_TYPE_HWI) // HWI 71 static_scheduler_t* psched = (static_scheduler_t*)_get_sched(); 72 unsigned int entry; 73 unsigned int isr_type; 74 unsigned int channel; 75 76 if (irq_type == IRQ_TYPE_HWI) entry = psched->hwi_vector[irq_id]; 77 else if (irq_type == IRQ_TYPE_PTI) entry = psched->pti_vector[irq_id]; 78 else if (irq_type == IRQ_TYPE_WTI) entry = psched->wti_vector[irq_id]; 79 else 86 80 { 87 if ( isr_id == ISR_SWITCH) _isr_switch(channel_id); 88 else if ( isr_id == ISR_IOC ) _isr_ioc(); 89 else if ( isr_id == ISR_TTY ) _isr_tty(channel_id); 90 else if ( isr_id == ISR_TIMER ) _isr_timer(channel_id); 91 else if ( isr_id == ISR_WAKUP ) _isr_timer(channel_id); 92 else _isr_default( irq_id, isr_id, type_id ); 81 _printf("\n[GIET ERROR] illegal irq_type in irq_demux()\n"); 82 _exit(); 93 83 } 94 else if(type_id == IRQ_TYPE_PTI) // PTI 84 85 isr_type = (entry ) & 0x0000FFFF; 86 channel = (entry>>16) & 0x00007FFF; 87 88 #if GIET_DEBUG_IRQS // we don't take the TTY lock to avoid deadlocks 89 _puts("\n[IRQS DEBUG] Processor["); 90 _putd(x); 91 _puts(","); 92 _putd(y); 93 _puts(","); 94 _putd(lpid); 95 _puts("] enters _irq_demux() at cycle "); 96 _putd(_get_proctime() ); 97 _puts("\n "); 98 _puts(irq_type_str[irq_type] ); 99 _puts(" : irq_id = "); 100 _putd(irq_id); 101 _puts(" / isr_type = "); 102 _putd(isr_type); 103 _puts(" / channel = "); 104 _putd(channel); 105 _puts("\n"); 106 #endif 107 108 // ISR call 109 if ( isr_type == ISR_TICK ) _isr_tick ( irq_type, irq_id, channel ); 110 else if ( isr_type == ISR_WAKUP ) _isr_wakup ( irq_type, irq_id, channel ); 111 else if ( isr_type == ISR_BDV ) _bdv_isr ( irq_type, irq_id, channel ); 112 else if ( isr_type == ISR_CMA ) _cma_isr ( irq_type, irq_id, channel ); 113 else if ( isr_type == ISR_TTY_RX ) _tty_rx_isr ( irq_type, irq_id, channel ); 114 else if ( isr_type == ISR_TTY_TX ) _tty_tx_isr ( irq_type, irq_id, channel ); 115 else if ( isr_type == ISR_NIC_RX ) _nic_rx_isr ( irq_type, irq_id, channel ); 116 else if ( isr_type == ISR_NIC_TX ) _nic_tx_isr ( irq_type, irq_id, channel ); 117 else if ( isr_type == ISR_TIMER ) _timer_isr ( irq_type, irq_id, channel ); 118 else 95 119 { 96 if ( isr_id == ISR_SWITCH) _isr_switch(irq_id); 97 else if ( isr_id == ISR_TIMER ) _isr_timer(irq_id); 98 else _isr_default( irq_id, isr_id, type_id ); 99 } 100 else if(type_id == IRQ_TYPE_SWI) // SWI 101 { 102 if ( isr_id == ISR_WAKUP ) return; 103 else _isr_default( irq_id, isr_id, type_id ); 120 // we don't take the TTY lock to avoid deadlock 121 _puts("\n[GIET ERROR] in _irq_demux() illegal ISR type on processor["); 122 _putd(x); 123 _puts(","); 124 _putd(y); 125 _puts(","); 126 _putd(lpid); 127 _puts("] at cycle "); 128 _putd(_get_proctime() ); 129 _puts("\n "); 130 _puts(irq_type_str[irq_type] ); 131 _puts(" : irq_id = "); 132 _putd(irq_id); 133 _puts(" / isr_type = "); 134 _putd(isr_type); 135 _puts(" / channel = "); 136 _putd(channel); 137 _puts("\n"); 138 _exit(); 104 139 } 105 140 } 106 } 107 108 /////////////////////////////////////////////////////////////////////////////////// 109 // The default ISR is called when no specific ISR has been installed in the 110 // interrupt vector. It simply displays an error message on kernel TTY[0]. 111 /////////////////////////////////////////////////////////////////////////////////// 112 void _isr_default( unsigned int irq_id, 113 unsigned int isr_id, 114 unsigned int type_id ) 115 { 116 _tty_get_lock( 0 ); 117 _puts("\n[GIET ERROR] Undefined ISR index = "); 118 _putd( isr_id ); 119 if(type_id == IRQ_TYPE_HWI) _puts(" / type = HWI "); 120 if(type_id == IRQ_TYPE_SWI) _puts(" / type = SWI "); 121 if(type_id == IRQ_TYPE_PTI) _puts(" / type = PTI "); 122 _puts(" / IRQ index = "); 123 _putd( irq_id ); 124 _puts(" / processor = "); 125 _putd( _get_procid() ); 126 _puts("\n"); 127 _tty_release_lock( 0 ); 128 _exit(); 129 } 130 131 132 /////////////////////////////////////////////////////////////////////////////////// 133 // This ISR is executed when a processor wakes up after a SWI interrup. 134 /////////////////////////////////////////////////////////////////////////////////// 135 void _isr_wakup() 136 { 137 _tty_get_lock( 0 ); 138 _puts("\n Processor "); 139 _putd( _get_procid() ); 140 _puts(" wake up\n"); 141 _tty_release_lock( 0 ); 142 } 143 144 /////////////////////////////////////////////////////////////////////////////////// 145 // There is only one IOC controler shared by all tasks. 146 // This ISR save the status, acknowledge the IRQ. 147 // and activates the task waiting on IO transfer. 148 // 149 // TODO the _set_task_slot access should be replaced by an atomic LL/SC 150 // when the CTX_RUN bool will be replaced by a bit_vector. 151 /////////////////////////////////////////////////////////////////////////////////// 152 void _isr_ioc() 153 { 154 // save status in _ioc_status variable and reset IRQ 155 if ( _ioc_get_status(0, &_ioc_status) ) return; 156 157 // reactivate task waiting on IOC 158 unsigned int gpid = _ioc_gtid>>16; 159 unsigned int ltid = _ioc_gtid & 0xFFFF; 160 161 _set_task_slot( gpid, // global processor index 162 ltid, // local task index (on processor) 163 CTX_RUN_ID, // CTX_RUN slot 164 1 ); // running 165 } 166 167 /////////////////////////////////////////////////////////////////////////////////// 168 // This ISR handles the IRQs generated by the "user" timers (the IRQs generated 169 // by the "system" timers should be handled by the _isr_switch(). 170 // These timers are distributed in all clusters, and can be implemented 171 // in a vci_multi_timer component, or in a vci_xicu component. 172 // The timer_id argument is the user timer local index. 173 // timer_globa_id = cluster_id*(NB_TIM_CHANNELS) + timer_id 174 // The ISR acknowledges the IRQ and registers the event in the proper entry 175 // of the _timer_event[] array, and a log message is displayed on kernel terminal. 176 /////////////////////////////////////////////////////////////////////////////////// 177 void _isr_timer(unsigned int timer_id) 178 { 179 // compute cluster_id 180 unsigned int cluster_id = _get_procid() / NB_PROCS_MAX; 181 182 // aknowledge IRQ 183 if (_timer_reset_irq( cluster_id, timer_id)) 141 else // no interrupt active 184 142 { 185 _tty_get_lock( 0 ); 186 _puts("[GIET ERROR] illegal timer index detected by _isr_timer\n"); 187 _tty_release_lock( 0 ); 188 return; 143 _isr_default(); 144 } 145 } 146 147 /////////////////////////////////////////////////////////////////////////////////// 148 // The default ISR is called when there is no active IRQ when the interrupt 149 // handler is called. It simply displays a warning message on TTY[0]. 150 /////////////////////////////////////////////////////////////////////////////////// 151 void _isr_default() 152 { 153 unsigned int gpid = _get_procid(); 154 unsigned int cluster_xy = gpid / NB_PROCS_MAX; 155 unsigned int x = cluster_xy >> Y_WIDTH; 156 unsigned int y = cluster_xy & ((1<<Y_WIDTH)-1); 157 unsigned int lpid = gpid % NB_PROCS_MAX; 158 159 // We don't take TTY lock to avoid deadlock 160 _puts("\n[GIET WARNING] IRQ handler called but no active IRQ on processor["); 161 _putd( x ); 162 _puts(","); 163 _putd( y ); 164 _puts(","); 165 _putd( lpid ); 166 _puts("] at cycle "); 167 _putd( _get_proctime() ); 168 _puts("\n "); 169 } 170 171 172 /////////////////////////////////////////////////////////////////////////////////// 173 // This ISR can only be executed after a WTI (IPI) to force a context switch 174 // on a remote processor. The context switch is only executed if the current task 175 // is the IDLE_TASK, or if the value written in the mailbox is non zero. 176 /////////////////////////////////////////////////////////////////////////////////// 177 void _isr_wakup( unsigned int irq_type, // HWI / WTI / PTI 178 unsigned int irq_id, // index returned by ICU 179 unsigned int channel ) // unused 180 { 181 unsigned int procid = _get_procid(); 182 unsigned int cluster_xy = procid / NB_PROCS_MAX; 183 unsigned int x = cluster_xy >> Y_WIDTH; 184 unsigned int y = cluster_xy & ((1<<Y_WIDTH)-1); 185 unsigned int lpid = procid % NB_PROCS_MAX; 186 unsigned int task = _get_current_task_id(); 187 unsigned int value; 188 189 if ( irq_type != IRQ_TYPE_WTI ) 190 { 191 // we don't take the TTY lock to avoid deadlocks 192 _puts("[GIET ERROR] _isr_wakup() not called by a WTI on processor["); 193 _putd( x ); 194 _puts(","); 195 _putd( y ); 196 _puts(","); 197 _putd( lpid ); 198 _puts("] at cycle "); 199 _putd( _get_proctime() ); 200 _puts("\n"); 201 _exit(); 189 202 } 190 203 191 #if NB_TIM_CHANNELS 192 // register the event 193 unsigned int timer_global_id = cluster_id * NB_TIM_CHANNELS + timer_id; 194 _user_timer_event[timer_global_id] = 1; 195 #endif 196 197 // display a message on TTY 0 198 _tty_get_lock( 0 ); 199 _puts("\n[GIET] User Timer IRQ at cycle "); 200 _putd(_get_proctime()); 201 _puts("\n - cluster_id = "); 202 _putd(cluster_id); 203 _puts("\n - timer_id = "); 204 _putd(timer_id); 205 _puts("\n"); 206 _tty_release_lock( 0 ); 207 } 208 209 210 /////////////////////////////////////////////////////////////////////////////////// 211 // This ISR handles the IRQs generated by the multi_tty controler, 212 // signaling that a character is available. 213 // There is one single multi_tty component controling all TTYs, 214 // and the tty_id argument is the global TTY index. 215 // There is one communication buffer _tty_buf[tty_id] per terminal. 216 // The sychronisation variable _tty_full[tty_id], is set by the ISR, 217 // and reset by the OS. 218 // A character is lost if the buffer is full when the ISR is executed. 219 /////////////////////////////////////////////////////////////////////////////////// 220 void _isr_tty(unsigned int tty_id) 221 { 222 // read character and reset IRQ in one read access 223 _tty_get_buf[tty_id] = _tty_read_data( tty_id ); 224 225 // signals character available 226 _tty_get_full[tty_id] = 1; 227 } 228 204 // get mailbox value and acknowledge WTI 205 _xcu_get_wti_value( cluster_xy, irq_id, &value ); 206 207 #if GIET_DEBUG_IRQS // we don't take the TTY lock to avoid deadlocks 208 _puts("\n[IRQS DEBUG] Processor["); 209 _putd( x ); 210 _puts(","); 211 _putd( y ); 212 _puts(","); 213 _putd( lpid ); 214 _puts("] enters _isr_wakup() at cycle "); 215 _putd( _get_proctime() ); 216 _puts("\n WTI / mailbox data = "); 217 _putx( value ); 218 _puts(" / current task index = "); 219 _putd( task ); 220 _puts("\n "); 221 #endif 222 223 // context swich if required 224 if ( (task == IDLE_TASK_INDEX) || (value != 0) ) _ctx_switch(); 225 } 229 226 230 227 ///////////////////////////////////////////////////////////////////////////////////// 231 // This ISR is in charge of context switch, and handle the IRQs generated by 232 // the "system" timers. 233 // The IRQs can be generated by the MULTI_TIMER component or by the XICU component, 234 // that are distributed in all clusters. 235 // The ISR acknowledges the IRQ and calls the _ctx_switch() function. 228 // This ISR is in charge of context switch, and handles the IRQs generated by 229 // the "system" timers contained in the MULTI_TIMER or in the XICU component. 230 // The ISR acknowledges the IRQ, and calls the _ctx_switch() function. 236 231 ///////////////////////////////////////////////////////////////////////////////////// 237 void _isr_switch( unsigned int timer_id) 238 { 239 // get cluster index 240 unsigned int cluster_id = _get_procid() / NB_PROCS_MAX; 241 242 // acknowledge IRQ 243 244 #if USE_XICU 245 if ( _xcu_timer_reset_irq( cluster_id, timer_id) ) 246 { 247 _tty_get_lock( 0 ); 248 _puts("[GIET ERROR] illegal proc index detected by _isr_switch\n"); 249 _tty_release_lock( 0 ); 250 return; 251 } 252 #else 253 if (_timer_reset_irq(cluster_id, timer_id)) 254 { 255 _tty_get_lock( 0 ); 256 _puts("[GIET ERROR] illegal proc index detected by _isr_switch\n"); 257 _tty_release_lock( 0 ); 258 return; 259 } 260 #endif 261 262 // performs the context switch 232 void _isr_tick( unsigned int irq_type, // HWI / WTI / PTI 233 unsigned int irq_id, // index returned by ICU 234 unsigned int channel ) // channel index if HWI 235 { 236 unsigned int procid = _get_procid(); 237 unsigned int cluster_xy = procid / NB_PROCS_MAX; 238 239 // acknowledge HWI or PTI 240 if ( irq_type == IRQ_TYPE_HWI ) _timer_reset_irq( cluster_xy, channel ); 241 else _xcu_timer_reset_irq( cluster_xy, irq_id ); 242 243 #if GIET_DEBUG_IRQS // we don't take the lock to avoid deadlock 244 unsigned int x = cluster_xy >> Y_WIDTH; 245 unsigned int y = cluster_xy & ((1<<Y_WIDTH)-1); 246 unsigned int lpid = procid % NB_PROCS_MAX; 247 _puts("\n[IRQS DEBUG] Processor["); 248 _putd( x ); 249 _puts(","); 250 _putd( y ); 251 _puts(","); 252 _putd( lpid ); 253 _puts("] enters _isr_tick() at cycle "); 254 _putd( _get_proctime() ); 255 _puts("\n "); 256 #endif 257 258 // context switch 263 259 _ctx_switch(); 264 260 }
Note: See TracChangeset
for help on using the changeset viewer.