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

Last change on this file since 287 was 281, checked in by cfuguet, 11 years ago

Modifications in GIET_VM:

  • Supporting platforms with more than one IRQ per processor from the XICU.

When this is the case, the IRQ per processor can be signalled
by the XCU peripheric number of channels on the XML file.

The xml_parser will generate a constant on the hard_config.h
file, called IRQ_PER_PROCESSOR and this constant will be use
by the GIET_VM to create accordingly the irq masks on the
ICU

  • Property svn:executable set to *
File size: 10.1 KB
Line 
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
31extern volatile unsigned char _user_timer_event[X_SIZE*Y_SIZE*NB_TIM_CHANNELS] ;
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    unsigned int icu_out_index = local_id * IRQ_PER_PROCESSOR;
62
63#if USE_XICU
64    ko = _xcu_get_index( cluster_id, icu_out_index, &irq_id );
65#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
77    if (irq_id < 32) 
78    {
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
86        {
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 );
93        }
94        else if(type_id == IRQ_TYPE_PTI) // PTI
95        {
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 );
104        }
105    }
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///////////////////////////////////////////////////////////////////////////////////
112void _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///////////////////////////////////////////////////////////////////////////////////
135void _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///////////////////////////////////////////////////////////////////////////////////
152void _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///////////////////////////////////////////////////////////////////////////////////
177void _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)) 
184    {
185        _tty_get_lock( 0 );
186        _puts("[GIET ERROR] illegal timer index detected by _isr_timer\n");
187        _tty_release_lock( 0 );
188        return;
189    }
190
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///////////////////////////////////////////////////////////////////////////////////
220void _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
229
230/////////////////////////////////////////////////////////////////////////////////////
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.
236/////////////////////////////////////////////////////////////////////////////////////
237void _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
263    _ctx_switch();
264}
265
266
267// Local Variables:
268// tab-width: 4
269// c-basic-offset: 4
270// c-file-offsets:((innamespace . 0)(inline-open . 0))
271// indent-tabs-mode: nil
272// End:
273// vim: filetype=c:expandtab:shiftwidth=4:tabstop=4:softtabstop=4
274
Note: See TracBrowser for help on using the repository browser.