wiki:icu_device_api

Version 15 (modified by alain, 7 years ago) (diff)

--

ICU device API

A) General principles

The ICU (Interrupt Controller Unit) device describes an internal peripheral, acting in all clusters containing cores. He is in charge of concentrating all IRQs (interrupt requests) generated by a peripheral to signal the completion of an I/O operation. Each IRQ should be routed to the core that started the I/O operation. The ICU device must also help the kernel to select the ISR (Interrupt Service Routine) that must be executed by the target core.

This component can be implemented as a dedicated hardware, centralized or distributed in all clusters, or emulated in software, as long as it implements the API defined below. For the TSAR architecture, the generic ICU device is implemented by the two hardware components soclib_xicu and and soclib_iopic, and their associated drivers.

ALMOS-MK defines three types of IRQs, that are handled by this generic ICU device:

  • HWI : The HardWare Interrupts are generated by a local internal peripheral. They are connected to the local ICU, to be routed to a given local core.
  • WTI : The Write Triggered Interrupts are actually mailboxes implemented in the local ICU. They are used to implement software IPIs (Inter-Processor-Interrupts), or to route an IRQ generated by an external peripheral to a given local core.
  • PTI : The Programmable Timer Interrupts are actually timers generating periodic interrupts controled by softare, contained in the local ICU, and routed to a given local core.

The max numbers of interrupts of each type in a given cluster are defined by the CONFIG_IRQ_HWI_MAX, CONFIG_IRQ_WTI_MAX, and CONFIG_IRQ_PTI_MAX parameters. The actual numbers for a given manycore architecture are defined in the boot_info file.

The generic ICU device provides three main services:

  1. It allows the kernel to selectively enable/disable any IRQ (identified by its type and index) for a given core. It is the kernel responsibility to enable a given IRQ to the core that started the I/O operation core, as a given IRQ event should be handled by only one core.
  2. It makes a global OR between all enabled IRQs for a given core, to interrupt the core when at least one enabled IRQ is active. Of course, the core is interrupted only if the interrupts are not globally masked for the target core.
  3. It is capable to return the highest priority active IRQ of each type. The priority scheme depends on the ICU device implementation.

To select the ISR to be executed for a given IRQ routed to a given core, ALMOS-MK uses three interrupts vectors, implemented as three arrays (HWI/WTI/PTI) stored in the core descriptor. Each entry in one interrupt vector array contains an extended pointer on the device descriptor that is the "source" of the interrupt. This device descriptor contains a link to the ISR to be executed to handle the interrupt event.

The ICU peripheral does not execute I/O operations, but is just acting as a dynamically configurable interrupt router for another I/O operation. Therefore, ALMOS-MK does not use the iCU device waiting queue, but calls directly the ICU driver blocking functions.

B) Access Functions

1) void dev_icu_init( device_t * icu )

This function makes two initialisations: It initialises the ICU specific fields of the device descriptor. it initialises the implementation specific ICU hardware device and associated data structures if required. It must be executed once by a thread running in the cluster containing the ICU device descriptor. The <icu> argument is a local pointer on the ICU device descriptor.

2) void dev_icu_enable_irq( uint32_t irq_type , uint32_t irq_id , xptr_t src_dev )

This function enables the routing of a given IRQ, defined by its type and index, to the calling core. It registers it in the calling core interrupt vector the extended pointer on the "source" device descriptor. The <irq_type> and <irq_id> arguments define the IRQ type and index. The <src_dev> argument is the remote pointer on the source device.

3) void dev_icu_disable_irq( uint32_t irq_type , uint32_t irq_id )

This function must be executed by a thread running in the cluster containing the ICU device descriptor. It disables one IRQ defined by its type and index, for the calling core, and remove it from the interrupt vector. The <irq_type> and <irq_id> arguments define the IRQ type and index.

4) void dev_icu_set_period( uint32_t pti_id , uint32_t period )

This function set the period value for a PTI timer identified by its index in the local ICU device descriptor. The <period> argument is the period value (number of cycles).

5) void dev_icu_ack_timer( uint32_t pti_id )

This function acknowledge a PTI IRQ for a timer identified by the PTI index in the local ICU device descriptor. The <pti_id> argument is the timer index.

6) void dev_icu_send_ipi( cxy_t cxy , lid_t lid )

This function send an IPI (Inter Processor Interrupt) to a core identified by its cluster identifier and local index. This IPI force a context switch, and the handling of pending RPC(s). The <cxy> argument is the destination cluster identifier. The <lid> argument is the destination core local index.

7) void dev_icu_irq_handler()

This function is called by a core when it receives an IRQ from the ICU device. It access the local ICU device descriptor to get the highest priority active IRQ of each type (HWI / WTI / PTI). If it is a WTI or an HWI, the function uses the calling core interrupt-vectors to call the relevant ISR, registered in the source device descriptor. If it is a PTI, the source device descriptor is the ICU device itself, and it call the core_clock() function to execute all operations related to the TICK event.

8) uint32_t dev_icu_wti_alloc()

This function implements the WTI mailbox allocator. This mailbox is used by all I/O operations for completion signaling. If there is no mailbox available, the client thread must deschedule and retry later. It returns the allocated WTI mailbox index. If N is the total number of WTI mailboxes in a cluster, and NC the number of cores, the number of dynamically allocatable WTI mailboxes is (N-NC) because the first N WTI mailboxes are used by the IPIs (one IPI per core).

9) void dev_icu_wti_release( uint32_t wti_id )

This function releases a dynamically allocated WTI mailbox. The <wti_id> argument is the WTI index.

10) xptr_t dev_icu_wti_xptr( cxy_t cxy , uint32_t wti_id )

This function returns an extended pointer on a WTI mailbox identified by its cluster identifier and local index in ICU. WARNING: it assumes that all ICU hardware devices have the same local base address. The <cxy> argument is the mailbox cluster identifier. The <wti_id> argument is the mailbox WTI index. It returns extended pointer on the mailbox register.