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

Last change on this file since 209 was 207, checked in by alain, 12 years ago

Several bugs have been fixed to support TSAR multi-cluster architecture
such as the "tsarv4-generic_mmu" platform.

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