= GIET-VM / Interrupt Handler = The [source:soft/giet_vm/giet_kernel/irq_handler.c irq_handler.c] and [source:soft/giet_vm/giet_kernel/irq_handler.h 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. [[PageOutline]] The GIET_VM interrupt handler supports only the SOCLIB XCU internal interrupt controler, and the SOCLIB IOPIC external interrup controler. In a multi-cluster architectures, it must exist one XCU controller in each 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). The '''WTI''' are actually hardware mailboxes, that are used by the GIET-VM to implement two mechanisms: * they are used to implement software IPIs (Inter Processor Interrupt). * they are used to dynamically route the external IRQs (generated by the external peripherals) to a given processor. 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 || The max number of processors in a given cluster, and the max number of WTI mailboxes in XCU, are defined by the NB_PROCS_MAX and XCU_NB_WTI hardware parameters. == __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): 1. The GIET-VM uses only one XCU output IRQ per processor (with index = lpid * IRQ_PER_PROCESSOR), even if the hardware platform connect more than one IRQ line to each processor. 2. 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). 3. In each cluster, one private '''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. 4. In each cluster, one private '''WTI''' mailbox (called WAKE_UP), is statically allocated to each processor. It is used in two situations: When the interrupted processor is in "wait state" (low-power mode), the processor exit the "wait state", but the ISR is not executed. When the processor is not in "wait state" the ISR is executed. If the interrupted processor is runing the idle_task, or if the value written in the WTI mailbox is non zero, the ISR force a context switch on the target processor. 5. In each cluster, the other '''WTI''' mailboxes (XCU_NB_WTI - NB_PROCS_MAX) are dynamically allocated to external IRQs. This allocation can be for a long time (Network Controller RX or TX IRQs), or just for a single I/O operation (Disk Controller IRQ, or TTY channel IRQ). In each cluster, a specific lock protect exclusive access to the local WTI allocator. The dynamic routing of external IRQs relies on the MASK registers in the XCUs and IOPIC components. == __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 array describes the hardware wiring, as defined in the mapping. * unsigned char '''_wti_alloc'''[X_SIZE][Y_SIZE][XCU_NB_WTI]; This array describes the WTI mailboxes allocation status in each cluster. Boolean true if WTI mailbox allocated. * spin_lock_t '''_wti_lock'''[X_SIZE][Y_SIZE]; This array contains the locks protecting the WTI mailbox allocators in each cluster. * unsigned int '''_ext_irq_wti'''[GIET_ISR_TYPE_MAX][GIET_ISR_CHANNEL_MAX]; This array contains for each external IRQ, identified by the (is_type,channel) couple, the allocated WTI mailbox identifier. This identifier has the following format (x / y / lpid / wti), with one byte per field. == __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, that defines the IRQ index (i.e. the IOPIC input IRQ index) associated to an (isr_type / isr_channel) couple, as specified in the mapping. It defines the hardware connexions between external peripherals and the IOPIC external IRQ controller, and 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 only used when the architecture contains an external IOPIC component. It 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, using the XCU masks. 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 only 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 [source:soft/giet_vm/giet_drivers/xcu_driver.c _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 [wiki:periphal_drivers drivers]. Some ISRs are defined in the [source:soft/giet_vm/giet_kernel/irq_handler.c 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].