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

Last change on this file since 231 was 231, checked in by joannou, 11 years ago
  • Bugfix in Interruption mechanism :
    • _it_mask() and _it_restore() functions now share a global array indexed by the proc_id (used a simple global variable before => problem with multiproc)
    • added 2 new fuctions _it_enable() and _it_disable() that only affect the IE bit of the status register in COP0
    • replaced interrupt masking/restoring arround _ctx_switch() in sys_handler by a simple interrupt disabling before the call to _ctx_switch (restoring after a _ctx_switch wouldn't restore the correct task's status register)
    • replaced the use of _ctx_switch in _exit() by a call to _context_switch() (this function actually does the interrupt disabling)
  • Added some comments in the ctx_handler.h
  • Added the delay reset in the idle task (ctx_handler.c)
  • Added a new irq type (PTI)
    • Modifications in xml_parser.c to accept PTI irq type (now used in xml mappings)
    • Added the test on the irq type in the _irq_demux() function. This leads to a different argument passed to the ISR (i.e. either channel_id or irq_id (aka icuid) )
File size: 9.7 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
[228]22extern volatile unsigned char _user_timer_event[NB_CLUSTERS * NB_TIMERS_MAX] ;
[215]23#endif
24
[158]25///////////////////////////////////////////////////////////////////////////////////
[228]26//     _irq_demux()
[189]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///////////////////////////////////////////////////////////////////////////////////
[228]42void _irq_demux() {
43    unsigned int pid = _procid();
44    unsigned int irq_id;
[158]45
[216]46
[189]47    // get the highest priority active IRQ index
[228]48    if (_icu_get_index( pid / NB_PROCS_MAX, pid % NB_PROCS_MAX, &irq_id)) {
[203]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);
[189]52    }
[158]53
[216]54
[228]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;
[231]59        unsigned int type_id = (entry >> 8) & 0x000000FF;
[228]60        unsigned int channel_id = (entry >> 16) & 0x0000FFFF;
[231]61        if(type_id == 0) // HARD irq type
62        {
63            if      ( isr_id == ISR_SWITCH) _isr_switch(channel_id);
64            else if ( isr_id == ISR_IOC   ) _isr_ioc();
65            else if ( isr_id == ISR_DMA   ) _isr_dma(channel_id);
66            else if ( isr_id == ISR_TTY   ) _isr_tty(channel_id);
67            else if ( isr_id == ISR_TIMER ) _isr_timer(channel_id);
68            else                            _isr_default();
69        }
70        else // PTI irq type
71        {
72            if      ( isr_id == ISR_SWITCH) _isr_switch(irq_id);
73            else if ( isr_id == ISR_TIMER ) _isr_timer(irq_id);
74        }
[165]75    }
[158]76}
[228]77
78
[158]79///////////////////////////////////////////////////////////////////////////////////
[228]80//     _isr_default()
[158]81// The default ISR is called when no specific ISR has been installed in the
[203]82// interrupt vector. It simply displays an error message on kernel TTY[0].
[158]83///////////////////////////////////////////////////////////////////////////////////
[228]84void _isr_default() {
[203]85    _get_lock(&_tty_put_lock);
86    _puts("\n[GIET ERROR] Strange... Default ISR activated for processor ");
87    _putd( _procid() );
88    _puts("\n");
89    _release_lock(&_tty_put_lock);
[158]90}
[165]91
[228]92
[158]93///////////////////////////////////////////////////////////////////////////////////
[228]94//     _isr_dma()
[189]95// This ISR handles all IRQs generated by the multi-channels DMA controlers.
96// The multi_dma components can be distributed in the clusters.
[207]97// The channel_id argument is the local DMA channel index.
98//     dma_global_id = cluster_id*NB_DMAS_MAX + channel_id
99// - The ISR saves the transfert status in _dma_status[dma_global_id].
[189]100// - It acknowledges the interrupt to reinitialize the DMA controler.
[207]101// - it resets the synchronisation variable _dma_busy[dma_global_id].
[158]102///////////////////////////////////////////////////////////////////////////////////
[228]103void _isr_dma(unsigned int channel_id) {
[213]104#if NB_DMAS_MAX > 0
[207]105    // compute cluster_id
[228]106    unsigned int cluster_id = _procid() / NB_PROCS_MAX;
[158]107
[207]108    // compute dma_global_id
[228]109    unsigned int dma_global_id = cluster_id * NB_DMAS_MAX + channel_id;
[207]110
[169]111    // save DMA channel status 
[228]112    if (_dma_get_status(cluster_id, channel_id, 
113            (unsigned int *) &_dma_status[dma_global_id])) {
[204]114        _get_lock(&_tty_put_lock);
115        _puts("[GIET ERROR] illegal DMA channel detected by _isr_dma\n");
116        _release_lock(&_tty_put_lock);
117        return;
118    }
[169]119
[204]120    // reset DMA channel irq
[228]121    if (_dma_reset_irq(cluster_id, channel_id)) {
[204]122        _get_lock(&_tty_put_lock);
123        _puts("[GIET ERROR] illegal DMA channel detected by _isr_dma\n");
124        _release_lock(&_tty_put_lock);
125        return;
126    }
[165]127
[169]128    // release DMA channel
[207]129    _dma_done[dma_global_id] = 1; 
[213]130#else
131    _puts("[GIET ERROR] NB_DMAS_MAX is set to zero\n");
132
133#endif
[158]134}
[165]135
[158]136///////////////////////////////////////////////////////////////////////////////////
[228]137//     _isr_ioc()
[189]138// There is only one IOC controler shared by all tasks.
139// - The ISR save the status and acknowledge the IRQ.
140// - It sets the _ioc_done variable to signal completion.
[158]141///////////////////////////////////////////////////////////////////////////////////
[228]142void _isr_ioc() {
143    // save status & reset IRQ
144    if (_ioc_get_status((unsigned int *) &_ioc_status )) {
[204]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
[228]152    _ioc_done = 1; 
[158]153}
[165]154
[228]155
[158]156///////////////////////////////////////////////////////////////////////////////////
[228]157//        _isr_timer()
[203]158// This ISR handles the IRQs generated by the "user" timers (the IRQs generated
159// by the "system" timers should be handled by the _isr_switch().
[189]160// These timers are distributed in all clusters, and can be implemented
161// in a vci_multi_timer component, or in a vci_xicu component.
[207]162// The timer_id argument is the user timer local index.
163//     timer_globa_id = cluster_id*(NB_TIMERS_MAX) + timer_id
[189]164// The ISR acknowledges the IRQ and registers the event in the proper entry
[203]165// of the _timer_event[] array, and a log message is displayed on kernel terminal.
[158]166///////////////////////////////////////////////////////////////////////////////////
[228]167void _isr_timer(unsigned int timer_id) {
[207]168    // compute cluster_id
[228]169    unsigned int cluster_id = _procid() / NB_PROCS_MAX;
[158]170
[203]171    // aknowledge IRQ
[228]172    if (_timer_reset_irq( cluster_id, timer_id)) {
[204]173        _get_lock(&_tty_put_lock);
174        _puts("[GIET ERROR] illegal timer index detected by _isr_timer\n");
175        _release_lock(&_tty_put_lock);
176        return;
177    }
[189]178
179#if NB_TIMERS_MAX
180    // register the event
[228]181    unsigned int timer_global_id = cluster_id * NB_TIMERS_MAX + timer_id;
[207]182    _user_timer_event[timer_global_id] = 1;
[189]183#endif
184
185    // display a message on TTY 0
[203]186    _get_lock(&_tty_put_lock);
[207]187    _puts("\n[GIET] User Timer IRQ at cycle ");
[228]188    _putd(_proctime());
[207]189    _puts("\n - cluster_id = ");
[228]190    _putd(cluster_id);
[207]191    _puts("\n - timer_id   = ");
[228]192    _putd(timer_id);
[189]193    _puts("\n");
[203]194    _release_lock(&_tty_put_lock);
[158]195}
196
[228]197
[158]198///////////////////////////////////////////////////////////////////////////////////
[189]199//  _isr_tty()
200// This ISR handles the IRQs generated by the multi_tty controler,
201// signaling that a character is available.
[204]202// There is one single multi_tty component controling all TTYs,
[207]203// and the tty_id argument is the global TTY index.
[189]204// There is one communication buffer _tty_buf[tty_id] per terminal.
205// The sychronisation variable _tty_full[tty_id], is set by the ISR,
[158]206// and reset by the OS.
207// A character is lost if the buffer is full when the ISR is executed.
208///////////////////////////////////////////////////////////////////////////////////
[228]209void _isr_tty(unsigned int tty_id) {
[189]210    // save character and reset IRQ
[228]211    if (_tty_get_char( tty_id, (unsigned char *) &_tty_get_buf[tty_id])) {
[204]212        _get_lock(&_tty_put_lock);
213        _puts("[GIET ERROR] illegal tty index detected by _isr_tty\n");
214        _release_lock(&_tty_put_lock);
215        return;
216    }
[158]217
[189]218    // signals character available
[158]219    _tty_get_full[tty_id] = 1;
220}
221
[228]222
[158]223/////////////////////////////////////////////////////////////////////////////////////
224// _isr_switch
[189]225// This ISR is in charge of context switch, and handle the IRQs generated by
226// the "system" timers.
227// The IRQs can be generated by the MULTI_TIMER component or by the XICU component,
228// that are distributed in all clusters.
229// The ISR acknowledges the IRQ and calls the _ctx_switch() function.
[158]230/////////////////////////////////////////////////////////////////////////////////////
[228]231void _isr_switch( unsigned int timer_id) {
[189]232    // get cluster index and proc local index
[216]233    unsigned int cluster_id = _procid() / NB_PROCS_MAX;
[158]234
[203]235    // acknowledge IRQ
[228]236    if (_timer_reset_irq(cluster_id, timer_id)) {
[204]237        _get_lock(&_tty_put_lock);
238        _puts("[GIET ERROR] illegal proc index detected by _isr_switch\n");
239        _release_lock(&_tty_put_lock);
240        return;
241    }
[158]242
[189]243    // performs the context switch
[158]244    _ctx_switch();
245}
246
[228]247
248// Local Variables:
249// tab-width: 4
250// c-basic-offset: 4
251// c-file-offsets:((innamespace . 0)(inline-open . 0))
252// indent-tabs-mode: nil
253// End:
254// vim: filetype=c:expandtab:shiftwidth=4:tabstop=4:softtabstop=4
255
Note: See TracBrowser for help on using the repository browser.