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

Last change on this file since 200 was 189, checked in by alain, 12 years ago

Introducing a new release where all initialisation
is done in the boot code.

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