source: soft/giet_vm/giet_kernel/irq_handler.c @ 276

Last change on this file since 276 was 263, checked in by alain, 11 years ago

Introducing support for TSAR fixed format cluster index (cluster_xy)
We have now 4 parameters defined in map.xml:

  • X_WIDTH, Y_WIDTH define the fixed format (typically X_WIDTH = 4 / Y_WIDTH = 4)
  • X_SIZE, Y_SIZE define the actual TSAR 2D mesh variable size (from 1 to 16)
  • Property svn:executable set to *
File size: 10.0 KB
RevLine 
[258]1///////////////////////////////////////////////////////////////////////////////////
2// File     : irq_handler.c
3// Date     : 01/04/2012
4// Author   : alain greiner
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 or
9// ICU component (Interupt Controler Unit), and the various ISRs (Interrupt
10// Service Routine) associated to the peripherals.
11///////////////////////////////////////////////////////////////////////////////////
12
13#include <giet_config.h>
14#include <irq_handler.h>
15#include <sys_handler.h>
16#include <ctx_handler.h>
17#include <tim_driver.h>
18#include <icu_driver.h>
19#include <xcu_driver.h>
20#include <tty_driver.h>
21#include <ioc_driver.h>
22#include <dma_driver.h>
23#include<mapping_info.h>
24#include <utils.h>
25
26#if !defined( USE_XICU )
27# error: You must define USE_XICU in the hard_config.h file
28#endif
29
30#if NB_TIM_CHANNELS
[263]31extern volatile unsigned char _user_timer_event[X_SIZE*Y_SIZE*NB_TIM_CHANNELS] ;
[258]32#endif
33
34///////////////////////////////////////////////////////////////////////////////////
35// This function uses the ICU or XICU component (Interrupt Controler Unit)
36// to get the interrupt vector entry. There is one ICU or XICU component per
37// cluster, and this component can support up to NB_PROCS_MAX output IRQs.
38// It returns the highest priority active interrupt index (smaller
39// indexes have the highest priority).
40// Any value larger than 31 means "no active interrupt", and no ISR is executed.
41//
42// There is one interrupt vector per processor (stored in the scheduler associated
43// 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_PTI
46// - channel_id bits[30:16] : defines the channel for multi-channels peripherals.
47// - valid      bit 31      : valid interrupt vector entry
48// If the peripheral is replicated in clusters (TIMER or DMA), the channel_id is
49// a global index : channel_id = cluster_id * NB_CHANNELS_MAX + loc_id   
50///////////////////////////////////////////////////////////////////////////////////
51void _irq_demux() 
52{
53    unsigned int gpid       = _get_procid();
54    unsigned int cluster_id = gpid / NB_PROCS_MAX;
55    unsigned int local_id   = gpid % NB_PROCS_MAX;
56    unsigned int irq_id;
57    unsigned int ko;
58
59    // get the highest priority active IRQ index
60
61#if USE_XICU
62    ko = _xcu_get_index( cluster_id, local_id, &irq_id );
63#else
64    ko = _icu_get_index( cluster_id, local_id, &irq_id );
65#endif
66
67    if ( ko )
68    {
69        _tty_get_lock( 0 );
70        _puts("\n[GIET ERROR] Wrong _icu_read in _irq_demux()\n");
71        _tty_release_lock( 0 );
72    }
73
74    // do nothing if no interrupt active, or
75    if (irq_id < 32) 
76    {
77        static_scheduler_t* psched     = (static_scheduler_t*)_get_sched();
78        unsigned int        entry      = psched->interrupt_vector[irq_id];
79        unsigned int        isr_id     = (entry    ) & 0x000000FF;
80        unsigned int        type_id    = (entry>> 8) & 0x000000FF;
81        unsigned int        channel_id = (entry>>16) & 0x00007FFF;
82
83        if(type_id == IRQ_TYPE_HWI)      // HWI
84        {
85            if      ( isr_id == ISR_SWITCH) _isr_switch(channel_id);
86            else if ( isr_id == ISR_IOC   ) _isr_ioc();
87            else if ( isr_id == ISR_TTY   ) _isr_tty(channel_id);
88            else if ( isr_id == ISR_TIMER ) _isr_timer(channel_id);
89            else if ( isr_id == ISR_WAKUP ) _isr_timer(channel_id);
90            else                            _isr_default( irq_id, isr_id, type_id );
91        }
92        else if(type_id == IRQ_TYPE_PTI) // PTI
93        {
94            if      ( isr_id == ISR_SWITCH) _isr_switch(irq_id);
95            else if ( isr_id == ISR_TIMER ) _isr_timer(irq_id);
96            else                            _isr_default( irq_id, isr_id, type_id );
97        }
98        else if(type_id == IRQ_TYPE_SWI) // SWI
99        {
100            if      ( isr_id == ISR_WAKUP ) return;
101            else                            _isr_default( irq_id, isr_id, type_id );
102        }
103    }
104}
105
106///////////////////////////////////////////////////////////////////////////////////
107// The default ISR is called when no specific ISR has been installed in the
108// interrupt vector. It simply displays an error message on kernel TTY[0].
109///////////////////////////////////////////////////////////////////////////////////
110void _isr_default( unsigned int irq_id,
111                   unsigned int isr_id,
112                   unsigned int type_id ) 
113{
114    _tty_get_lock( 0 );
115    _puts("\n[GIET ERROR] Undefined ISR index = ");
116    _putd( isr_id );
117    if(type_id == IRQ_TYPE_HWI) _puts(" / type = HWI ");
118    if(type_id == IRQ_TYPE_SWI) _puts(" / type = SWI ");
119    if(type_id == IRQ_TYPE_PTI) _puts(" / type = PTI ");
120    _puts(" / IRQ index = ");
121    _putd( irq_id );
122    _puts(" / processor = ");
123    _putd( _get_procid() );
124    _puts("\n");
125    _tty_release_lock( 0 );
126    _exit();
127}
128
129
130///////////////////////////////////////////////////////////////////////////////////
131// This ISR is executed when a processor wakes up after a SWI interrup.
132///////////////////////////////////////////////////////////////////////////////////
133void _isr_wakup() 
134{
135    _tty_get_lock( 0 );
136    _puts("\n  Processor ");
137    _putd( _get_procid() );
138    _puts(" wake up\n");
139    _tty_release_lock( 0 );
140}
141
142///////////////////////////////////////////////////////////////////////////////////
143// There is only one IOC controler shared by all tasks.
144// This ISR save the status, acknowledge the IRQ.
145// and activates the task waiting on IO transfer.
146//
147// TODO the _set_task_slot access should be replaced by an atomic LL/SC
148//      when the CTX_RUN bool will be replaced by a bit_vector.
149///////////////////////////////////////////////////////////////////////////////////
150void _isr_ioc() 
151{
152    // save status in _ioc_status variable and reset IRQ
153    _ioc_status = _ioc_get_status(); 
154
155    // reactivate task waiting on IOC
156    unsigned int gpid = _ioc_gtid>>16;
157    unsigned int ltid = _ioc_gtid & 0xFFFF;
158
159    _set_task_slot( gpid,        // global processor index
160                    ltid,        // local task index (on processor)
161                    CTX_RUN_ID,  // CTX_RUN slot
162                    1 );         // running
163}
164
165///////////////////////////////////////////////////////////////////////////////////
166// This ISR handles the IRQs generated by the "user" timers (the IRQs generated
167// by the "system" timers should be handled by the _isr_switch().
168// These timers are distributed in all clusters, and can be implemented
169// in a vci_multi_timer component, or in a vci_xicu component.
170// The timer_id argument is the user timer local index.
171//     timer_globa_id = cluster_id*(NB_TIM_CHANNELS) + timer_id
172// The ISR acknowledges the IRQ and registers the event in the proper entry
173// of the _timer_event[] array, and a log message is displayed on kernel terminal.
174///////////////////////////////////////////////////////////////////////////////////
175void _isr_timer(unsigned int timer_id) 
176{
177    // compute cluster_id
178    unsigned int cluster_id = _get_procid() / NB_PROCS_MAX;
179
180    // aknowledge IRQ
181    if (_timer_reset_irq( cluster_id, timer_id)) 
182    {
183        _tty_get_lock( 0 );
184        _puts("[GIET ERROR] illegal timer index detected by _isr_timer\n");
185        _tty_release_lock( 0 );
186        return;
187    }
188
189#if NB_TIM_CHANNELS
190    // register the event
191    unsigned int timer_global_id = cluster_id * NB_TIM_CHANNELS + timer_id;
192    _user_timer_event[timer_global_id] = 1;
193#endif
194
195    // display a message on TTY 0
196    _tty_get_lock( 0 );
197    _puts("\n[GIET] User Timer IRQ at cycle ");
198    _putd(_get_proctime());
199    _puts("\n - cluster_id = ");
200    _putd(cluster_id);
201    _puts("\n - timer_id   = ");
202    _putd(timer_id);
203    _puts("\n");
204    _tty_release_lock( 0 );
205}
206
207
208///////////////////////////////////////////////////////////////////////////////////
209// This ISR handles the IRQs generated by the multi_tty controler,
210// signaling that a character is available.
211// There is one single multi_tty component controling all TTYs,
212// and the tty_id argument is the global TTY index.
213// There is one communication buffer _tty_buf[tty_id] per terminal.
214// The sychronisation variable _tty_full[tty_id], is set by the ISR,
215// and reset by the OS.
216// A character is lost if the buffer is full when the ISR is executed.
217///////////////////////////////////////////////////////////////////////////////////
218void _isr_tty(unsigned int tty_id) 
219{
220    // read character and reset IRQ in one read access
221    _tty_get_buf[tty_id] = _tty_read_data( tty_id ); 
222
223    // signals character available
224    _tty_get_full[tty_id] = 1;
225}
226
227
228/////////////////////////////////////////////////////////////////////////////////////
229// This ISR is in charge of context switch, and handle the IRQs generated by
230// the "system" timers.
231// The IRQs can be generated by the MULTI_TIMER component or by the XICU component,
232// that are distributed in all clusters.
233// The ISR acknowledges the IRQ and calls the _ctx_switch() function.
234/////////////////////////////////////////////////////////////////////////////////////
235void _isr_switch( unsigned int timer_id) 
236{
237    // get cluster index
238    unsigned int cluster_id = _get_procid() / NB_PROCS_MAX;
239
240    // acknowledge IRQ
241
242#if USE_XICU
243    if ( _xcu_timer_reset_irq( cluster_id, timer_id) ) 
244    {
245        _tty_get_lock( 0 );
246        _puts("[GIET ERROR] illegal proc index detected by _isr_switch\n");
247        _tty_release_lock( 0 );
248        return;
249    }
250#else
251    if (_timer_reset_irq(cluster_id, timer_id)) 
252    {
253        _tty_get_lock( 0 );
254        _puts("[GIET ERROR] illegal proc index detected by _isr_switch\n");
255        _tty_release_lock( 0 );
256        return;
257    }
258#endif
259
260    // performs the context switch
261    _ctx_switch();
262}
263
264
265// Local Variables:
266// tab-width: 4
267// c-basic-offset: 4
268// c-file-offsets:((innamespace . 0)(inline-open . 0))
269// indent-tabs-mode: nil
270// End:
271// vim: filetype=c:expandtab:shiftwidth=4:tabstop=4:softtabstop=4
272
Note: See TracBrowser for help on using the repository browser.