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

Last change on this file since 215 was 215, checked in by karaoui, 12 years ago

New components are now mandotory in the XML description:

The files giet_vsegs.ld and hard_config.h are now autogenerated by the xml2bin tool.

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