source: soft/giet_vm/sys/irq_handler.c @ 206

Last change on this file since 206 was 204, checked in by alain, 12 years ago

mproving support for multi-clusters architectures (CLUSTER_SIZE & CLUSTER_IO_ID parameters)

File size: 9.3 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 <drivers.h>
17#include <common.h>
18#include <ctx_handler.h>
19#include <hwr_mapping.h>
20
21///////////////////////////////////////////////////////////////////////////////////
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.
29//
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.
34//
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///////////////////////////////////////////////////////////////////////////////////
38void _irq_demux()
39{
40    unsigned int    pid = _procid();
41    unsigned int        irq_id;
42
43    // get the highest priority active IRQ index
44    if ( _icu_get_index( pid / NB_PROCS_MAX,
45                         pid % NB_PROCS_MAX,
46                         &irq_id ) )
47    {
48        _get_lock(&_tty_put_lock);
49        _puts("\n[GIET ERROR] Strange... Wrong _icu_read in _irq_demux()\n");
50        _release_lock(&_tty_put_lock);
51    }
52
53    if ( irq_id < 32 )  // do nothing if no interrupt active
54    {
55        unsigned int entry      = _get_interrupt_vector_entry(irq_id);
56        unsigned int isr_id     = entry & 0x000000FF;
57        unsigned int channel_id = (entry>>16) & 0x0000FFFF;
58        if      ( isr_id == ISR_SWITCH  ) _isr_switch();
59        else if ( isr_id == ISR_IOC     ) _isr_ioc();
60        else if ( isr_id == ISR_DMA     ) _isr_dma( channel_id );
61        else if ( isr_id == ISR_TTY     ) _isr_tty( channel_id );
62        else if ( isr_id == ISR_TIMER   ) _isr_timer( channel_id );
63        else                              _isr_default();
64    }
65}
66///////////////////////////////////////////////////////////////////////////////////
67//      _isr_default()
68// The default ISR is called when no specific ISR has been installed in the
69// interrupt vector. It simply displays an error message on kernel TTY[0].
70///////////////////////////////////////////////////////////////////////////////////
71void _isr_default()
72{
73    _get_lock(&_tty_put_lock);
74    _puts("\n[GIET ERROR] Strange... Default ISR activated for processor ");
75    _putd( _procid() );
76    _puts("\n");
77    _release_lock(&_tty_put_lock);
78}
79
80///////////////////////////////////////////////////////////////////////////////////
81//      _isr_dma()
82// This ISR handles all IRQs generated by the multi-channels DMA controlers.
83// The multi_dma components can be distributed in the clusters.
84// The channel_id argument is the global DMA channel index.
85//     channel_id = cluster_id*NB_DMAS_MAX + loc_id
86// - The ISR saves the transfert status in _dma_status[channel_id].
87// - It acknowledges the interrupt to reinitialize the DMA controler.
88// - it resets the synchronisation variable _dma_busy[channel_id].
89///////////////////////////////////////////////////////////////////////////////////
90void _isr_dma( unsigned int channel_id )
91{
92    // compute cluster_id and loc_id
93    unsigned int cluster_id = channel_id / NB_DMAS_MAX;
94    unsigned int local_id   = channel_id % NB_DMAS_MAX;
95
96    // save DMA channel status 
97    if ( _dma_get_status(cluster_id, local_id, &_dma_status[channel_id]) )
98    {
99        _get_lock(&_tty_put_lock);
100        _puts("[GIET ERROR] illegal DMA channel detected by _isr_dma\n");
101        _release_lock(&_tty_put_lock);
102        return;
103    }
104
105    // reset DMA channel irq
106    if ( _dma_reset_irq(cluster_id, local_id) )
107    {
108        _get_lock(&_tty_put_lock);
109        _puts("[GIET ERROR] illegal DMA channel detected by _isr_dma\n");
110        _release_lock(&_tty_put_lock);
111        return;
112    }
113
114    // release DMA channel
115    _dma_done[channel_id] = 1; 
116}
117
118///////////////////////////////////////////////////////////////////////////////////
119//      _isr_ioc()
120// There is only one IOC controler shared by all tasks.
121// - The ISR save the status and acknowledge the IRQ.
122// - It sets the _ioc_done variable to signal completion.
123///////////////////////////////////////////////////////////////////////////////////
124void _isr_ioc()
125{
126     // save status & reset IRQ
127    if ( _ioc_get_status( &_ioc_status ) )
128    {
129        _get_lock(&_tty_put_lock);
130        _puts("[GIET ERROR] bad access to IOC status detected by _isr_ioc\n");
131        _release_lock(&_tty_put_lock);
132        return;
133    }
134
135    // signals completion
136    _ioc_done   = 1; 
137}
138
139///////////////////////////////////////////////////////////////////////////////////
140//         _isr_timer()
141// This ISR handles the IRQs generated by the "user" timers (the IRQs generated
142// by the "system" timers should be handled by the _isr_switch().
143// These timers are distributed in all clusters, and can be implemented
144// in a vci_multi_timer component, or in a vci_xicu component.
145// The timer_id argument is a global index:
146//     timer_id = cluster_id*(NB_TIMERS_MAX+NB_PROCS_MAX) + local_id
147// The user timer local index is (loc_id - NB_PROCS_MAX).
148//
149// The ISR acknowledges the IRQ and registers the event in the proper entry
150// of the _timer_event[] array, and a log message is displayed on kernel terminal.
151///////////////////////////////////////////////////////////////////////////////////
152void _isr_timer(unsigned int timer_id)
153{
154
155    unsigned int cluster_id = timer_id / (NB_TIMERS_MAX + NB_PROCS_MAX);
156    unsigned int local_id   = timer_id % (NB_TIMERS_MAX + NB_PROCS_MAX); 
157
158    // checking timer type
159    if (local_id < NB_PROCS_MAX )
160    {
161        _get_lock(&_tty_put_lock);
162        _puts("[GIET ERROR] Strange... User timer ISR for a system timer\n");
163        _release_lock(&_tty_put_lock);
164        return;
165    }
166
167    // aknowledge IRQ
168    if ( _timer_reset_irq( cluster_id, local_id ) )
169    {
170        _get_lock(&_tty_put_lock);
171        _puts("[GIET ERROR] illegal timer index detected by _isr_timer\n");
172        _release_lock(&_tty_put_lock);
173        return;
174    }
175
176#if NB_TIMERS_MAX
177    // register the event
178    _timer_event[(cluster_id*NB_TIMERS_MAX) + (loc_id - NB_PROCS_MAX)] = 1;
179#endif
180
181    // display a message on TTY 0
182    _get_lock(&_tty_put_lock);
183    _puts("[GIET] User Timer IRQ at cycle ");
184    _putd( _proctime() );
185    _puts(" / index = ");
186    _putd(timer_id);
187    _puts("\n");
188    _release_lock(&_tty_put_lock);
189}
190
191///////////////////////////////////////////////////////////////////////////////////
192//  _isr_tty()
193// This ISR handles the IRQs generated by the multi_tty controler,
194// signaling that a character is available.
195// There is one single multi_tty component controling all TTYs,
196// and the tty_id // argument is the global TTY index.
197// There is one communication buffer _tty_buf[tty_id] per terminal.
198// The sychronisation variable _tty_full[tty_id], is set by the ISR,
199// and reset by the OS.
200// A character is lost if the buffer is full when the ISR is executed.
201///////////////////////////////////////////////////////////////////////////////////
202void _isr_tty(unsigned int tty_id)
203{
204    // save character and reset IRQ
205    if ( _tty_get_char( tty_id, &_tty_get_buf[tty_id] ) )
206    {
207        _get_lock(&_tty_put_lock);
208        _puts("[GIET ERROR] illegal tty index detected by _isr_tty\n");
209        _release_lock(&_tty_put_lock);
210        return;
211    }
212
213    // signals character available
214    _tty_get_full[tty_id] = 1;
215}
216
217/////////////////////////////////////////////////////////////////////////////////////
218// _isr_switch
219// This ISR is in charge of context switch, and handle the IRQs generated by
220// the "system" timers.
221// The IRQs can be generated by the MULTI_TIMER component or by the XICU component,
222// that are distributed in all clusters.
223// The ISR acknowledges the IRQ and calls the _ctx_switch() function.
224/////////////////////////////////////////////////////////////////////////////////////
225void _isr_switch()
226{
227    // get cluster index and proc local index
228    unsigned int pid        = _procid();
229    unsigned int local_id   = pid % NB_PROCS_MAX;
230    unsigned int cluster_id = pid / NB_PROCS_MAX;
231
232    // acknowledge IRQ
233    if ( _timer_reset_irq( cluster_id, local_id ) ) 
234    {
235        _get_lock(&_tty_put_lock);
236        _puts("[GIET ERROR] illegal proc index detected by _isr_switch\n");
237        _release_lock(&_tty_put_lock);
238        return;
239    }
240
241    // performs the context switch
242    _ctx_switch();
243}
244
Note: See TracBrowser for help on using the repository browser.