wiki:kernel_interrupts

Version 23 (modified by alain, 9 years ago) (diff)

--

GIET-VM / Interrupt Handler

The irq_handler.c and irq_handler.h files define the kernel functions that are used to handle interrupts. They are prefixed by "_" to remind that they can only be executed by a processor in kernel mode.

The GIET_VM interrupt handler supports only the SOCLIB XCU interrupt controler. In a multi-cluster architectures, it must exist one XCU controller in ech cluster containing processors.

A multi-channel XCU component in a given cluster must contain (NB_PROCS_MAX * IRQ_PER_PROCESSOR) channels (one channel = one XCU output IRQ).

There is three interrupt vectors per processor (stored in each processor's scheduler) for the three interrupts types: HWI (Hardware Interrupt), PTI (Programmable Timer Interrupt), and WTI (Write Triggered Interrupt). Each interrupt vector entry contains two fields:

isr_id bits[15:0] defines the type of ISR to be executed
channel_id bits[31:16] defines the channel for multi-channels ISR

Interrupt routing

Regarding the allocation of interrupts to processors (IRQ routing using the XCU_MASK registers), the GIET-VM implement the following policy (lpid is the local processor index, between 0 and 7):

  1. The GIET-VM uses only one XCU output IRQ per processor (with index = lpid * IRQ_PER_PROCESSOR), even if the hardware platform contains more than one IRQ_PER_PROCESSOR.
  1. In each cluster the local HWI generated by the local peripherals are statically allocated and distributed to local processors, to share the load between all processors).
  1. In each cluster, one PTI is statically allocated to each processor for context switch (pti_id = lpid). The TICK period is defined by the GIET_TICK_VALUE parameter in the giet_config.h file. The associated _isr_tick() interrupt service routine forces a context switch on the target processor.
  1. In each cluster, 4 WTI mailbox (called WAKE_UP, EXT_IRQ_ONE, EXT_IRQ_TWO, EXT_IRQ_TER) are statically allocated to each processor. The first one is used by the GIET_VM boot-loader for processor wakup, and is used by the kernel for inter-processor interrupts.
  1. The isr_wakup() interrupt service routine is associated to the WAKE_UP interrupt. When the destination processor is not in wait state (low-power mode), the ISR is executed. If the processor executing the idle_task, or if the value written in the WTI mailbox is non zero, this ISR force a context switch on the target processor.
  1. The three EXT_IRQ_ONE, EXT_IRQ_TWO and EXT_IRQ_TER interrupts are dynamically allocated to external IRQS generated by the external peripherals (through the IOPIC component), in order to route the external IRQ to the processor that launched the I/O operation.

The array below define the static routing of WTIs to the local processors, implemented by the XCU masks:

WTI name WTI index
WAKE_UP lpid
EXT_IRQ_ONE NB_PROCS_MAX + lpid
EXT_IRQ_TWO 2*NB_PROCS_MAX + lpid
EXT_IRQ_TER 3*NB_PROCS_MAX + lpid

Global variables used for external IRQs routing

  • unsigned char _ext_irq_index[GIET_ISR_TYPE_MAX][GIET_ISR_CHANNEL_MAX];

This array contains the external IRQ indexes (IOPIC input index) for each (isr/channel) couple. This is an hardware feature defined in the mapping.

  • unsigned char _wti_alloc_one[X_SIZE][Y_SIZE][NB_PROCS_MAX];
  • unsigned char _wti_alloc_two[X_SIZE][Y_SIZE][NB_PROCS_MAX];
  • unsigned char _wti_alloc_ter[X_SIZE][Y_SIZE][NB_PROCS_MAX];

These three arrays define the WTI allocators for each processor: non zero value when the entry has been allocated to a given external IRQ. This allocation is dynamically done by the kernel.

Functions used for external IRQs dynamic routing

void _ext_irq_init()

This function is only used when the architecture contains an external IOPIC component. It initializes the _ext_irq_index[isr][channel] kernel array. This array defines the IRQ index (i.e. the IOPIC input index) associated to an (isr_type / isr_channel) couple, as specified in the mapping. It is used by the kernel for dynamic routing of external IRQs.

void _ext_irq_alloc( unsigned int isr_type , unsigned int isr_channel , unsigned int* wti_index )

This function is used when the architecture contains an external IOPIC component. It dynamically allocates an external IRQ signaling completion of an I/O operation to the processor P[x,y,p] running the calling task. The two (isr_type / isr_channel) arguments define actually the external IRQ to be routed.

  • isr_type : type of ISR
  • isr_channel : ISR channel (for multi-channels peripherals)
  • wti_index : return value defining the index of the WTI mailbox allocated to P[x,y,p]

This function does three things:

  1. it allocates a WTI mailbox in the XCU of cluster[x,y] to the requesting processor ( index is in [4*p+1, 4*p+2, 4*p+3] ) ;
  2. it initializes the IOPIC register associated to the (isr_type / isr_channel) external IRQ.
  3. it initializes the proper entry in the WTI interrupt vector associated to processor P[x,y,p].

void _ext_irq_release( unsigned int isr_type , unsigned int isr_channel , unsigned int wti_index )

This function is used when the architecture contains an external IOPIC component. It desallocates the ressources allocated by the previous _ext_irq_alloc() function to the calling processor. The two (isr_type, isr_channel) arguments define actually the external IRQ to be released.

  • isr_type : type of ISR
  • isr_channel : ISR channel (for multi-channels peripherals)
  • wti_index : index of the WTI mailbox allocated to P[x,y,p] to be released.

This function does only two things:

  1. it desactivates the PIC entry associated to the (isr_type/isr_channel) IRQ.
  2. it releases the WTI mailbox allocated to P[x,y,p].
  3. The WTI interrupt vector is NOT modified

Functions used for all HWI / PTI / WTI interrupts

void _irq_demux()

This function access the XCU component to get the interrupt vector entry: It uses the _xcu_get_index() functions to get the IRQ type ( HWI / PTI / WTI ), and the index in the corresponding interrupt vector. Any index value larger than 31 means "no active interrupt", and the default ISR is executed.

All ISRs (but the default ISR) must have the same three arguments :

  • unsigned int irq_type,
  • unsigned int irq_id,
  • unsigned int channel

As most ISRs (Interrupt Service Routine) are associated to a specific peripheral, these ISR are defined in the drivers?. But the following ISRs are defined in the irq_handler.c file:

void _isr_wakup( unsigned int irq_type, unsigned int irq_id, unsigned int channel )

This ISR is executed after a WTI WAKUP (Inter Processor Interrupt). It is used to awake a processor in wait mode (low-power mode), or to force a context switch on a remote processor. The context switch is only executed if the current task is the IDLE_TASK, or if the value written in the mailbox is non zero.

void _isr_tick( unsigned int irq_type, unsigned int irq_id, unsigned int channel )

This ISR is in charge of context switch, and handles the PTI IRQs generated by the XCU timers. The ISR acknowledges the IRQ, and calls the _ctx_switch() function.

void _isr_default()

This default ISR is called when the interrupt handler is called, and there is no active IRQ. It simply displays a warning message on the kernel TTY[0].