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

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

Major evolution to support physical addresses larger than 32 bits.
The map.xml format has been modified: the vsegs associated to schedulers
are now explicitely defined and mapped in the page tables.

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