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

Last change on this file since 255 was 246, checked in by meunier, 11 years ago

Cosmétique + gestion du reset de l'irq du timer ou de l'xicu lors d'un task_switch

File size: 9.9 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
[238]21#if NB_TIM_CHANNELS
22extern volatile unsigned char _user_timer_event[NB_CLUSTERS * NB_TIM_CHANNELS] ;
[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
[238]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
[189]38// - channel_id : defines the specific channel for multi-channels peripherals.
[158]39//
[189]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   
[158]42///////////////////////////////////////////////////////////////////////////////////
[238]43void _irq_demux() 
44{
[228]45    unsigned int pid = _procid();
46    unsigned int irq_id;
[158]47
[189]48    // get the highest priority active IRQ index
[238]49    if (_icu_get_index( pid / NB_PROCS_MAX, pid % NB_PROCS_MAX, &irq_id)) 
50    {
[203]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);
[189]54    }
[158]55
[238]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;
[216]64
[231]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        }
[165]79    }
[158]80}
[228]81
[158]82///////////////////////////////////////////////////////////////////////////////////
[228]83//     _isr_default()
[158]84// The default ISR is called when no specific ISR has been installed in the
[203]85// interrupt vector. It simply displays an error message on kernel TTY[0].
[158]86///////////////////////////////////////////////////////////////////////////////////
[238]87void _isr_default() 
88{
[203]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);
[158]94}
[165]95
[228]96
[158]97///////////////////////////////////////////////////////////////////////////////////
[228]98//     _isr_dma()
[189]99// This ISR handles all IRQs generated by the multi-channels DMA controlers.
100// The multi_dma components can be distributed in the clusters.
[207]101// The channel_id argument is the local DMA channel index.
[238]102//     dma_global_id = cluster_id*NB_DMA_CHANNELS + channel_id
[207]103// - The ISR saves the transfert status in _dma_status[dma_global_id].
[189]104// - It acknowledges the interrupt to reinitialize the DMA controler.
[207]105// - it resets the synchronisation variable _dma_busy[dma_global_id].
[158]106///////////////////////////////////////////////////////////////////////////////////
[238]107void _isr_dma(unsigned int channel_id) 
108{
109#if NB_DMA_CHANNELS > 0
[207]110    // compute cluster_id
[228]111    unsigned int cluster_id = _procid() / NB_PROCS_MAX;
[158]112
[207]113    // compute dma_global_id
[238]114    unsigned int dma_global_id = cluster_id * NB_DMA_CHANNELS + channel_id;
[207]115
[169]116    // save DMA channel status 
[228]117    if (_dma_get_status(cluster_id, channel_id, 
[238]118            (unsigned int *) &_dma_status[dma_global_id])) 
119    {
[204]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    }
[169]125
[204]126    // reset DMA channel irq
[238]127    if (_dma_reset_irq(cluster_id, channel_id)) 
128    {
[204]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    }
[165]134
[169]135    // release DMA channel
[237]136    _dma_done[dma_global_id] = 1;
[238]137
[213]138#else
[238]139    _get_lock(&_tty_put_lock);
140    _puts("[GIET ERROR] NB_DMA_CHANNELS is set to zero\n");
141    _release_lock(&_tty_put_lock);
[213]142#endif
[158]143}
[165]144
[158]145///////////////////////////////////////////////////////////////////////////////////
[228]146//     _isr_ioc()
[189]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.
[158]150///////////////////////////////////////////////////////////////////////////////////
[238]151void _isr_ioc() 
152{
[228]153    // save status & reset IRQ
[246]154    if (_ioc_get_status((unsigned int *) &_ioc_status)) 
[238]155    {
[204]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    }
[158]161
[204]162    // signals completion
[228]163    _ioc_done = 1; 
[158]164}
[165]165
[228]166
[158]167///////////////////////////////////////////////////////////////////////////////////
[228]168//        _isr_timer()
[203]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().
[189]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.
[207]173// The timer_id argument is the user timer local index.
[238]174//     timer_globa_id = cluster_id*(NB_TIM_CHANNELS) + timer_id
[189]175// The ISR acknowledges the IRQ and registers the event in the proper entry
[203]176// of the _timer_event[] array, and a log message is displayed on kernel terminal.
[158]177///////////////////////////////////////////////////////////////////////////////////
[238]178void _isr_timer(unsigned int timer_id) 
179{
[207]180    // compute cluster_id
[228]181    unsigned int cluster_id = _procid() / NB_PROCS_MAX;
[158]182
[203]183    // aknowledge IRQ
[238]184    if (_timer_reset_irq( cluster_id, timer_id)) 
185    {
[204]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    }
[189]191
[238]192#if NB_TIM_CHANNELS
[189]193    // register the event
[238]194    unsigned int timer_global_id = cluster_id * NB_TIM_CHANNELS + timer_id;
[207]195    _user_timer_event[timer_global_id] = 1;
[189]196#endif
197
198    // display a message on TTY 0
[203]199    _get_lock(&_tty_put_lock);
[207]200    _puts("\n[GIET] User Timer IRQ at cycle ");
[228]201    _putd(_proctime());
[207]202    _puts("\n - cluster_id = ");
[228]203    _putd(cluster_id);
[207]204    _puts("\n - timer_id   = ");
[228]205    _putd(timer_id);
[189]206    _puts("\n");
[203]207    _release_lock(&_tty_put_lock);
[158]208}
209
[228]210
[158]211///////////////////////////////////////////////////////////////////////////////////
[189]212//  _isr_tty()
213// This ISR handles the IRQs generated by the multi_tty controler,
214// signaling that a character is available.
[204]215// There is one single multi_tty component controling all TTYs,
[207]216// and the tty_id argument is the global TTY index.
[189]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,
[158]219// and reset by the OS.
220// A character is lost if the buffer is full when the ISR is executed.
221///////////////////////////////////////////////////////////////////////////////////
[238]222void _isr_tty(unsigned int tty_id) 
223{
[189]224    // save character and reset IRQ
[238]225    if (_tty_get_char( tty_id, (unsigned char *) &_tty_get_buf[tty_id])) 
226    {
[204]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    }
[158]232
[189]233    // signals character available
[158]234    _tty_get_full[tty_id] = 1;
235}
236
[228]237
[158]238/////////////////////////////////////////////////////////////////////////////////////
239// _isr_switch
[189]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.
[158]245/////////////////////////////////////////////////////////////////////////////////////
[238]246void _isr_switch( unsigned int timer_id) 
247{
[189]248    // get cluster index and proc local index
[216]249    unsigned int cluster_id = _procid() / NB_PROCS_MAX;
[158]250
[203]251    // acknowledge IRQ
[238]252    if (_timer_reset_irq(cluster_id, timer_id)) 
253    {
[204]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    }
[158]259
[189]260    // performs the context switch
[158]261    _ctx_switch();
262}
263
[228]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.