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

Last change on this file since 228 was 228, checked in by meunier, 11 years ago

Added support for memspaces and const.
Added an interrupt masking to the "giet_context_switch" syscall
Corrected two bugs in boot/boot_init.c (one minor and one regarding barriers initialization)
Reformatted the code in all files.

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    unsigned int pid = _procid();
44    unsigned int irq_id;
45
46
47    // get the highest priority active IRQ index
48    if (_icu_get_index( pid / NB_PROCS_MAX, pid % NB_PROCS_MAX, &irq_id)) {
49        _get_lock(&_tty_put_lock);
50        _puts("\n[GIET ERROR] Strange... Wrong _icu_read in _irq_demux()\n");
51        _release_lock(&_tty_put_lock);
52    }
53
54
55    if (irq_id < 32) {
56        // do nothing if no interrupt active
57        unsigned int entry = _get_interrupt_vector_entry(irq_id);
58        unsigned int isr_id = entry & 0x000000FF;
59        unsigned int channel_id = (entry >> 16) & 0x0000FFFF;
60        if      ( isr_id == ISR_SWITCH) _isr_switch( channel_id);
61        else if ( isr_id == ISR_IOC   ) _isr_ioc();
62        else if ( isr_id == ISR_DMA   ) _isr_dma(channel_id);
63        else if ( isr_id == ISR_TTY   ) _isr_tty(channel_id);
64        else if ( isr_id == ISR_TIMER ) _isr_timer(channel_id);
65        else                            _isr_default();
66    }
67}
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    _get_lock(&_tty_put_lock);
77    _puts("\n[GIET ERROR] Strange... Default ISR activated for processor ");
78    _putd( _procid() );
79    _puts("\n");
80    _release_lock(&_tty_put_lock);
81}
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#if NB_DMAS_MAX > 0
96    // compute cluster_id
97    unsigned int cluster_id = _procid() / NB_PROCS_MAX;
98
99    // compute dma_global_id
100    unsigned int dma_global_id = cluster_id * NB_DMAS_MAX + channel_id;
101
102    // save DMA channel status 
103    if (_dma_get_status(cluster_id, channel_id, 
104            (unsigned int *) &_dma_status[dma_global_id])) {
105        _get_lock(&_tty_put_lock);
106        _puts("[GIET ERROR] illegal DMA channel detected by _isr_dma\n");
107        _release_lock(&_tty_put_lock);
108        return;
109    }
110
111    // reset DMA channel irq
112    if (_dma_reset_irq(cluster_id, channel_id)) {
113        _get_lock(&_tty_put_lock);
114        _puts("[GIET ERROR] illegal DMA channel detected by _isr_dma\n");
115        _release_lock(&_tty_put_lock);
116        return;
117    }
118
119    // release DMA channel
120    _dma_done[dma_global_id] = 1; 
121#else
122    _puts("[GIET ERROR] NB_DMAS_MAX is set to zero\n");
123
124#endif
125}
126
127///////////////////////////////////////////////////////////////////////////////////
128//     _isr_ioc()
129// There is only one IOC controler shared by all tasks.
130// - The ISR save the status and acknowledge the IRQ.
131// - It sets the _ioc_done variable to signal completion.
132///////////////////////////////////////////////////////////////////////////////////
133void _isr_ioc() {
134    // save status & reset IRQ
135    if (_ioc_get_status((unsigned int *) &_ioc_status )) {
136        _get_lock(&_tty_put_lock);
137        _puts("[GIET ERROR] bad access to IOC status detected by _isr_ioc\n");
138        _release_lock(&_tty_put_lock);
139        return;
140    }
141
142    // signals completion
143    _ioc_done = 1; 
144}
145
146
147///////////////////////////////////////////////////////////////////////////////////
148//        _isr_timer()
149// This ISR handles the IRQs generated by the "user" timers (the IRQs generated
150// by the "system" timers should be handled by the _isr_switch().
151// These timers are distributed in all clusters, and can be implemented
152// in a vci_multi_timer component, or in a vci_xicu component.
153// The timer_id argument is the user timer local index.
154//     timer_globa_id = cluster_id*(NB_TIMERS_MAX) + timer_id
155// The ISR acknowledges the IRQ and registers the event in the proper entry
156// of the _timer_event[] array, and a log message is displayed on kernel terminal.
157///////////////////////////////////////////////////////////////////////////////////
158void _isr_timer(unsigned int timer_id) {
159    // compute cluster_id
160    unsigned int cluster_id = _procid() / NB_PROCS_MAX;
161
162    // aknowledge IRQ
163    if (_timer_reset_irq( cluster_id, timer_id)) {
164        _get_lock(&_tty_put_lock);
165        _puts("[GIET ERROR] illegal timer index detected by _isr_timer\n");
166        _release_lock(&_tty_put_lock);
167        return;
168    }
169
170#if NB_TIMERS_MAX
171    // register the event
172    unsigned int timer_global_id = cluster_id * NB_TIMERS_MAX + timer_id;
173    _user_timer_event[timer_global_id] = 1;
174#endif
175
176    // display a message on TTY 0
177    _get_lock(&_tty_put_lock);
178    _puts("\n[GIET] User Timer IRQ at cycle ");
179    _putd(_proctime());
180    _puts("\n - cluster_id = ");
181    _putd(cluster_id);
182    _puts("\n - timer_id   = ");
183    _putd(timer_id);
184    _puts("\n");
185    _release_lock(&_tty_put_lock);
186}
187
188
189///////////////////////////////////////////////////////////////////////////////////
190//  _isr_tty()
191// This ISR handles the IRQs generated by the multi_tty controler,
192// signaling that a character is available.
193// There is one single multi_tty component controling all TTYs,
194// and the tty_id argument is the global TTY index.
195// There is one communication buffer _tty_buf[tty_id] per terminal.
196// The sychronisation variable _tty_full[tty_id], is set by the ISR,
197// and reset by the OS.
198// A character is lost if the buffer is full when the ISR is executed.
199///////////////////////////////////////////////////////////////////////////////////
200void _isr_tty(unsigned int tty_id) {
201    // save character and reset IRQ
202    if (_tty_get_char( tty_id, (unsigned char *) &_tty_get_buf[tty_id])) {
203        _get_lock(&_tty_put_lock);
204        _puts("[GIET ERROR] illegal tty index detected by _isr_tty\n");
205        _release_lock(&_tty_put_lock);
206        return;
207    }
208
209    // signals character available
210    _tty_get_full[tty_id] = 1;
211}
212
213
214/////////////////////////////////////////////////////////////////////////////////////
215// _isr_switch
216// This ISR is in charge of context switch, and handle the IRQs generated by
217// the "system" timers.
218// The IRQs can be generated by the MULTI_TIMER component or by the XICU component,
219// that are distributed in all clusters.
220// The ISR acknowledges the IRQ and calls the _ctx_switch() function.
221/////////////////////////////////////////////////////////////////////////////////////
222void _isr_switch( unsigned int timer_id) {
223    // get cluster index and proc local index
224    unsigned int cluster_id = _procid() / NB_PROCS_MAX;
225
226    // acknowledge IRQ
227    if (_timer_reset_irq(cluster_id, timer_id)) {
228        _get_lock(&_tty_put_lock);
229        _puts("[GIET ERROR] illegal proc index detected by _isr_switch\n");
230        _release_lock(&_tty_put_lock);
231        return;
232    }
233
234    // performs the context switch
235    _ctx_switch();
236}
237
238
239// Local Variables:
240// tab-width: 4
241// c-basic-offset: 4
242// c-file-offsets:((innamespace . 0)(inline-open . 0))
243// indent-tabs-mode: nil
244// End:
245// vim: filetype=c:expandtab:shiftwidth=4:tabstop=4:softtabstop=4
246
Note: See TracBrowser for help on using the repository browser.