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

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