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

Last change on this file since 238 was 238, checked in by alain, 11 years ago

Major evolution to support physical addresses larger than 32 bits.
The map.xml format has been modified: the vsegs associated to schedulers
are now explicitely defined and mapped in the page tables.

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
[238]154    if (_ioc_get_status((unsigned int *) &_ioc_status )) 
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.