Ignore:
Timestamp:
Mar 26, 2014, 6:10:01 PM (11 years ago)
Author:
alain
Message:

Introducing support for IOPIC component.

File:
1 edited

Legend:

Unmodified
Added
Removed
  • soft/giet_vm/giet_kernel/irq_handler.c

    r281 r294  
    44// Author   : alain greiner
    55// Copyright (c) UPMC-LIP6
    6 ///////////////////////////////////////////////////////////////////////////////////
    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.
    116///////////////////////////////////////////////////////////////////////////////////
    127
     
    1914#include <xcu_driver.h>
    2015#include <tty_driver.h>
    21 #include <ioc_driver.h>
     16#include <nic_driver.h>
     17#include <cma_driver.h>
     18#include <bdv_driver.h>
    2219#include <dma_driver.h>
    2320#include <mapping_info.h>
     
    4037// Any value larger than 31 means "no active interrupt", and no ISR is executed.
    4138//
    42 // There is one interrupt vector per processor (stored in the scheduler associated
    43 // to the processor. Each interrupt vector entry contains four bits fields:
    44 // - isr_id     bits[7:0]   : defines the type of ISR to be executed.
    45 // - type_id    bits[15:8]  : IRQ_TYPE_HWI / IRQ_TYPE_SWI / IRQ_TYPE_PTI
     39// There is three interrupt vectors per processor (stored in the processor's
     40// scheduler) for the three HWI, PTI, and WTI interrupts types.
     41// Each interrupt vector entry contains three bits fields:
     42// - isr_id     bits[15:0]  : defines the type of ISR to be executed.
    4643// - channel_id bits[30:16] : defines the channel for multi-channels peripherals.
    4744// - valid      bit 31      : valid interrupt vector entry
    48 // If the peripheral is replicated in clusters (TIMER or DMA), the channel_id is
     45// If the peripheral is replicated in clusters, the channel_id is
    4946// a global index : channel_id = cluster_id * NB_CHANNELS_MAX + loc_id   
    5047///////////////////////////////////////////////////////////////////////////////////
    5148void _irq_demux()
    5249{
    53     unsigned int gpid       = _get_procid();
    54     unsigned int cluster_id = gpid / NB_PROCS_MAX;
    55     unsigned int local_id   = gpid % NB_PROCS_MAX;
     50    unsigned int gpid           = _get_procid();
     51    unsigned int cluster_xy     = gpid / NB_PROCS_MAX;
     52    unsigned int x              = cluster_xy >> Y_WIDTH;
     53    unsigned int y              = cluster_xy & ((1<<Y_WIDTH)-1);
     54    unsigned int lpid           = gpid % NB_PROCS_MAX;
    5655    unsigned int irq_id;
    57     unsigned int ko;
     56    unsigned int irq_type;
     57    char*        irq_type_str[] = { "HWI", "WTI", "PTI" };
    5858
    5959    // get the highest priority active IRQ index
    60 
    61     unsigned int icu_out_index = local_id * IRQ_PER_PROCESSOR;
     60    unsigned int icu_out_index = lpid * IRQ_PER_PROCESSOR;
    6261
    6362#if USE_XICU
    64     ko = _xcu_get_index( cluster_id, icu_out_index, &irq_id );
     63    _xcu_get_index( cluster_xy, icu_out_index, &irq_id, &irq_type );
    6564#else
    66     ko = _icu_get_index( cluster_id, icu_out_index, &irq_id );
    67 #endif
    68 
    69     if ( ko )
    70     {
    71         _tty_get_lock( 0 );
    72         _puts("\n[GIET ERROR] Wrong _icu_read in _irq_demux()\n");
    73         _tty_release_lock( 0 );
    74     }
    75 
    76     // do nothing if no interrupt active, or
     65    irq_type = IRQ_TYPE_HWI;
     66    _icu_get_index( cluster_xy, icu_out_index, &irq_id );
     67#endif
     68
    7769    if (irq_id < 32)
    7870    {
    79         static_scheduler_t* psched     = (static_scheduler_t*)_get_sched();
    80         unsigned int        entry      = psched->interrupt_vector[irq_id];
    81         unsigned int        isr_id     = (entry    ) & 0x000000FF;
    82         unsigned int        type_id    = (entry>> 8) & 0x000000FF;
    83         unsigned int        channel_id = (entry>>16) & 0x00007FFF;
    84 
    85         if(type_id == IRQ_TYPE_HWI)      // HWI
     71        static_scheduler_t* psched = (static_scheduler_t*)_get_sched();
     72        unsigned int        entry;
     73        unsigned int        isr_type;
     74        unsigned int        channel;
     75
     76        if      (irq_type == IRQ_TYPE_HWI) entry = psched->hwi_vector[irq_id];
     77        else if (irq_type == IRQ_TYPE_PTI) entry = psched->pti_vector[irq_id];
     78        else if (irq_type == IRQ_TYPE_WTI) entry = psched->wti_vector[irq_id];
     79        else
    8680        {
    87             if      ( isr_id == ISR_SWITCH) _isr_switch(channel_id);
    88             else if ( isr_id == ISR_IOC   ) _isr_ioc();
    89             else if ( isr_id == ISR_TTY   ) _isr_tty(channel_id);
    90             else if ( isr_id == ISR_TIMER ) _isr_timer(channel_id);
    91             else if ( isr_id == ISR_WAKUP ) _isr_timer(channel_id);
    92             else                            _isr_default( irq_id, isr_id, type_id );
     81            _printf("\n[GIET ERROR] illegal irq_type in irq_demux()\n");
     82            _exit();
    9383        }
    94         else if(type_id == IRQ_TYPE_PTI) // PTI
     84
     85        isr_type   = (entry    ) & 0x0000FFFF;
     86        channel    = (entry>>16) & 0x00007FFF;
     87
     88#if GIET_DEBUG_IRQS // we don't take the TTY lock to avoid deadlocks
     89_puts("\n[IRQS DEBUG] Processor[");
     90_putd(x);
     91_puts(",");
     92_putd(y);
     93_puts(",");
     94_putd(lpid);
     95_puts("] enters _irq_demux() at cycle ");
     96_putd(_get_proctime() );
     97_puts("\n  ");
     98_puts(irq_type_str[irq_type] );
     99_puts(" : irq_id = ");
     100_putd(irq_id);
     101_puts(" / isr_type = ");
     102_putd(isr_type);
     103_puts(" / channel = ");
     104_putd(channel);
     105_puts("\n");
     106#endif
     107
     108        // ISR call
     109        if      ( isr_type == ISR_TICK   ) _isr_tick   ( irq_type, irq_id, channel );
     110        else if ( isr_type == ISR_WAKUP  ) _isr_wakup  ( irq_type, irq_id, channel );
     111        else if ( isr_type == ISR_BDV    ) _bdv_isr    ( irq_type, irq_id, channel );
     112        else if ( isr_type == ISR_CMA    ) _cma_isr    ( irq_type, irq_id, channel );
     113        else if ( isr_type == ISR_TTY_RX ) _tty_rx_isr ( irq_type, irq_id, channel );
     114        else if ( isr_type == ISR_TTY_TX ) _tty_tx_isr ( irq_type, irq_id, channel );
     115        else if ( isr_type == ISR_NIC_RX ) _nic_rx_isr ( irq_type, irq_id, channel );
     116        else if ( isr_type == ISR_NIC_TX ) _nic_tx_isr ( irq_type, irq_id, channel );
     117        else if ( isr_type == ISR_TIMER  ) _timer_isr  ( irq_type, irq_id, channel );
     118        else
    95119        {
    96             if      ( isr_id == ISR_SWITCH) _isr_switch(irq_id);
    97             else if ( isr_id == ISR_TIMER ) _isr_timer(irq_id);
    98             else                            _isr_default( irq_id, isr_id, type_id );
    99         }
    100         else if(type_id == IRQ_TYPE_SWI) // SWI
    101         {
    102             if      ( isr_id == ISR_WAKUP ) return;
    103             else                            _isr_default( irq_id, isr_id, type_id );
     120            // we don't take the TTY lock to avoid deadlock
     121            _puts("\n[GIET ERROR] in _irq_demux() illegal ISR type on processor[");
     122            _putd(x);
     123            _puts(",");
     124            _putd(y);
     125            _puts(",");
     126            _putd(lpid);
     127            _puts("] at cycle ");
     128            _putd(_get_proctime() );
     129            _puts("\n  ");
     130            _puts(irq_type_str[irq_type] );
     131            _puts(" : irq_id = ");
     132            _putd(irq_id);
     133            _puts(" / isr_type = ");
     134            _putd(isr_type);
     135            _puts(" / channel = ");
     136            _putd(channel);
     137            _puts("\n");
     138            _exit();
    104139        }
    105140    }
    106 }
    107 
    108 ///////////////////////////////////////////////////////////////////////////////////
    109 // The default ISR is called when no specific ISR has been installed in the
    110 // interrupt vector. It simply displays an error message on kernel TTY[0].
    111 ///////////////////////////////////////////////////////////////////////////////////
    112 void _isr_default( unsigned int irq_id,
    113                    unsigned int isr_id,
    114                    unsigned int type_id )
    115 {
    116     _tty_get_lock( 0 );
    117     _puts("\n[GIET ERROR] Undefined ISR index = ");
    118     _putd( isr_id );
    119     if(type_id == IRQ_TYPE_HWI) _puts(" / type = HWI ");
    120     if(type_id == IRQ_TYPE_SWI) _puts(" / type = SWI ");
    121     if(type_id == IRQ_TYPE_PTI) _puts(" / type = PTI ");
    122     _puts(" / IRQ index = ");
    123     _putd( irq_id );
    124     _puts(" / processor = ");
    125     _putd( _get_procid() );
    126     _puts("\n");
    127     _tty_release_lock( 0 );
    128     _exit();
    129 }
    130 
    131 
    132 ///////////////////////////////////////////////////////////////////////////////////
    133 // This ISR is executed when a processor wakes up after a SWI interrup.
    134 ///////////////////////////////////////////////////////////////////////////////////
    135 void _isr_wakup()
    136 {
    137     _tty_get_lock( 0 );
    138     _puts("\n  Processor ");
    139     _putd( _get_procid() );
    140     _puts(" wake up\n");
    141     _tty_release_lock( 0 );
    142 }
    143 
    144 ///////////////////////////////////////////////////////////////////////////////////
    145 // There is only one IOC controler shared by all tasks.
    146 // This ISR save the status, acknowledge the IRQ.
    147 // and activates the task waiting on IO transfer.
    148 //
    149 // TODO the _set_task_slot access should be replaced by an atomic LL/SC
    150 //      when the CTX_RUN bool will be replaced by a bit_vector.
    151 ///////////////////////////////////////////////////////////////////////////////////
    152 void _isr_ioc()
    153 {
    154     // save status in _ioc_status variable and reset IRQ
    155     if ( _ioc_get_status(0, &_ioc_status) ) return;
    156 
    157     // reactivate task waiting on IOC
    158     unsigned int gpid = _ioc_gtid>>16;
    159     unsigned int ltid = _ioc_gtid & 0xFFFF;
    160 
    161     _set_task_slot( gpid,        // global processor index
    162                     ltid,        // local task index (on processor)
    163                     CTX_RUN_ID,  // CTX_RUN slot
    164                     1 );         // running
    165 }
    166 
    167 ///////////////////////////////////////////////////////////////////////////////////
    168 // This ISR handles the IRQs generated by the "user" timers (the IRQs generated
    169 // by the "system" timers should be handled by the _isr_switch().
    170 // These timers are distributed in all clusters, and can be implemented
    171 // in a vci_multi_timer component, or in a vci_xicu component.
    172 // The timer_id argument is the user timer local index.
    173 //     timer_globa_id = cluster_id*(NB_TIM_CHANNELS) + timer_id
    174 // The ISR acknowledges the IRQ and registers the event in the proper entry
    175 // of the _timer_event[] array, and a log message is displayed on kernel terminal.
    176 ///////////////////////////////////////////////////////////////////////////////////
    177 void _isr_timer(unsigned int timer_id)
    178 {
    179     // compute cluster_id
    180     unsigned int cluster_id = _get_procid() / NB_PROCS_MAX;
    181 
    182     // aknowledge IRQ
    183     if (_timer_reset_irq( cluster_id, timer_id))
     141    else   // no interrupt active
    184142    {
    185         _tty_get_lock( 0 );
    186         _puts("[GIET ERROR] illegal timer index detected by _isr_timer\n");
    187         _tty_release_lock( 0 );
    188         return;
     143        _isr_default();
     144    }
     145}
     146
     147///////////////////////////////////////////////////////////////////////////////////
     148// The default ISR is called when there is no active IRQ when the interrupt
     149// handler is called. It simply displays a warning message on TTY[0].
     150///////////////////////////////////////////////////////////////////////////////////
     151void _isr_default()
     152{
     153    unsigned int gpid       = _get_procid();
     154    unsigned int cluster_xy = gpid / NB_PROCS_MAX;
     155    unsigned int x          = cluster_xy >> Y_WIDTH;
     156    unsigned int y          = cluster_xy & ((1<<Y_WIDTH)-1);
     157    unsigned int lpid       = gpid % NB_PROCS_MAX;
     158
     159    // We don't take TTY lock to avoid deadlock
     160    _puts("\n[GIET WARNING] IRQ handler called but no active IRQ on processor[");
     161    _putd( x );
     162    _puts(",");
     163    _putd( y );
     164    _puts(",");
     165    _putd( lpid );
     166    _puts("] at cycle ");
     167    _putd( _get_proctime() );
     168    _puts("\n  ");
     169}
     170
     171
     172///////////////////////////////////////////////////////////////////////////////////
     173// This ISR can only be executed after a WTI (IPI) to force a context switch
     174// on a remote processor. The context switch is only executed if the current task
     175// is the IDLE_TASK, or if the value written in the mailbox is non zero.
     176///////////////////////////////////////////////////////////////////////////////////
     177void _isr_wakup( unsigned int irq_type,   // HWI / WTI / PTI
     178                 unsigned int irq_id,     // index returned by ICU
     179                 unsigned int channel )   // unused
     180{
     181    unsigned int procid     = _get_procid();
     182    unsigned int cluster_xy = procid / NB_PROCS_MAX;
     183    unsigned int x          = cluster_xy >> Y_WIDTH;
     184    unsigned int y          = cluster_xy & ((1<<Y_WIDTH)-1);
     185    unsigned int lpid       = procid % NB_PROCS_MAX;
     186    unsigned int task       = _get_current_task_id();
     187    unsigned int value;
     188
     189    if ( irq_type != IRQ_TYPE_WTI )
     190    {
     191        // we don't take the TTY lock to avoid deadlocks
     192        _puts("[GIET ERROR] _isr_wakup() not called by a WTI on processor[");
     193        _putd( x );
     194        _puts(",");
     195        _putd( y );
     196        _puts(",");
     197        _putd( lpid );
     198        _puts("] at cycle ");
     199        _putd( _get_proctime() );
     200        _puts("\n");
     201        _exit();
    189202    }
    190203
    191 #if NB_TIM_CHANNELS
    192     // register the event
    193     unsigned int timer_global_id = cluster_id * NB_TIM_CHANNELS + timer_id;
    194     _user_timer_event[timer_global_id] = 1;
    195 #endif
    196 
    197     // display a message on TTY 0
    198     _tty_get_lock( 0 );
    199     _puts("\n[GIET] User Timer IRQ at cycle ");
    200     _putd(_get_proctime());
    201     _puts("\n - cluster_id = ");
    202     _putd(cluster_id);
    203     _puts("\n - timer_id   = ");
    204     _putd(timer_id);
    205     _puts("\n");
    206     _tty_release_lock( 0 );
    207 }
    208 
    209 
    210 ///////////////////////////////////////////////////////////////////////////////////
    211 // This ISR handles the IRQs generated by the multi_tty controler,
    212 // signaling that a character is available.
    213 // There is one single multi_tty component controling all TTYs,
    214 // and the tty_id argument is the global TTY index.
    215 // There is one communication buffer _tty_buf[tty_id] per terminal.
    216 // The sychronisation variable _tty_full[tty_id], is set by the ISR,
    217 // and reset by the OS.
    218 // A character is lost if the buffer is full when the ISR is executed.
    219 ///////////////////////////////////////////////////////////////////////////////////
    220 void _isr_tty(unsigned int tty_id)
    221 {
    222     // read character and reset IRQ in one read access
    223     _tty_get_buf[tty_id] = _tty_read_data( tty_id );
    224 
    225     // signals character available
    226     _tty_get_full[tty_id] = 1;
    227 }
    228 
     204    // get mailbox value and acknowledge WTI
     205    _xcu_get_wti_value( cluster_xy, irq_id, &value );
     206
     207#if GIET_DEBUG_IRQS // we don't take the TTY lock to avoid deadlocks
     208_puts("\n[IRQS DEBUG] Processor[");
     209_putd( x );
     210_puts(",");
     211_putd( y );
     212_puts(",");
     213_putd( lpid );
     214_puts("] enters _isr_wakup() at cycle ");
     215_putd( _get_proctime() );
     216_puts("\n  WTI / mailbox data = ");
     217_putx( value );
     218_puts(" / current task index = ");
     219_putd( task );
     220_puts("\n  ");
     221#endif
     222
     223    // context swich if required
     224    if ( (task == IDLE_TASK_INDEX) || (value != 0) ) _ctx_switch();
     225}
    229226
    230227/////////////////////////////////////////////////////////////////////////////////////
    231 // This ISR is in charge of context switch, and handle the IRQs generated by
    232 // the "system" timers.
    233 // The IRQs can be generated by the MULTI_TIMER component or by the XICU component,
    234 // that are distributed in all clusters.
    235 // The ISR acknowledges the IRQ and calls the _ctx_switch() function.
     228// This ISR is in charge of context switch, and handles the IRQs generated by
     229// the "system" timers contained in the MULTI_TIMER or in the XICU component.
     230// The ISR acknowledges the IRQ, and calls the _ctx_switch() function.
    236231/////////////////////////////////////////////////////////////////////////////////////
    237 void _isr_switch( unsigned int timer_id)
    238 {
    239     // get cluster index
    240     unsigned int cluster_id = _get_procid() / NB_PROCS_MAX;
    241 
    242     // acknowledge IRQ
    243 
    244 #if USE_XICU
    245     if ( _xcu_timer_reset_irq( cluster_id, timer_id) )
    246     {
    247         _tty_get_lock( 0 );
    248         _puts("[GIET ERROR] illegal proc index detected by _isr_switch\n");
    249         _tty_release_lock( 0 );
    250         return;
    251     }
    252 #else
    253     if (_timer_reset_irq(cluster_id, timer_id))
    254     {
    255         _tty_get_lock( 0 );
    256         _puts("[GIET ERROR] illegal proc index detected by _isr_switch\n");
    257         _tty_release_lock( 0 );
    258         return;
    259     }
    260 #endif
    261 
    262     // performs the context switch
     232void _isr_tick( unsigned int irq_type,   // HWI / WTI / PTI
     233                unsigned int irq_id,     // index returned by ICU
     234                unsigned int channel )   // channel index if HWI
     235{
     236    unsigned int procid     = _get_procid();
     237    unsigned int cluster_xy = procid / NB_PROCS_MAX;
     238
     239    // acknowledge HWI or PTI
     240    if ( irq_type == IRQ_TYPE_HWI ) _timer_reset_irq( cluster_xy, channel );
     241    else                            _xcu_timer_reset_irq( cluster_xy, irq_id );
     242
     243#if GIET_DEBUG_IRQS  // we don't take the lock to avoid deadlock
     244unsigned int x          = cluster_xy >> Y_WIDTH;
     245unsigned int y          = cluster_xy & ((1<<Y_WIDTH)-1);
     246unsigned int lpid       = procid % NB_PROCS_MAX;
     247_puts("\n[IRQS DEBUG] Processor[");
     248_putd( x );
     249_puts(",");
     250_putd( y );
     251_puts(",");
     252_putd( lpid );
     253_puts("] enters _isr_tick() at cycle ");
     254_putd( _get_proctime() );
     255_puts("\n  ");
     256#endif
     257
     258    // context switch
    263259    _ctx_switch();
    264260}
Note: See TracChangeset for help on using the changeset viewer.