wiki:icu_device_api

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

--

ICU generic device API

A) General principles

The ICU (Interrupt Controller Unit) device is an internal peripheral, distributed in all clusters containing cores. He is in charge of concentrating all IRQs (interrupt request) generated by the - internal or external - peripherals to signal the completion of a given I/O operation, and routing each IRQ to the core that started the I/O operation. He is also in charge of helping the kernel to select the ISR (Interrupt Service Routine) to be executed by the target core.

This component can be implemented as a dedicated hardware, distributed in all clusters, or emulated in software, as long as it implements the API defined below.

ALMOS-MK defines three types of IRQs, that are concentrated by the 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 can be 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, the ICU device uses three interrupts vectors, implemented as three arrays (HWI/WTI/PTI) stored in the core descriptor. Each entry in one interrupt vector array (defining one IRQ type and index) 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 generic ICU device working for a single client that is the local kernel instance, it does not use the device descriptor queue. All commands are immediately executed, and use the device lock to get exclusive access to the ICU device state.

B) Access Functions

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.

*

  • @ dev : pointer on ICU device descriptor. /

void dev_icu_init( device_t * icu );

/*

  • This blocking function enable one IRQ defined by its type (HWI/WTI/PTI) and index
  • in the local ICU device descriptor, and register it in the proper interrupt vector
  • of the calling core. *
  • @ irq_type : HWI/WTI/PTI.
  • @ irq_id : IRQ index.
  • @ device : pointer on device descriptor source of IRQ.
  • @ returns 0 if success / returns EINVAL if illegal arguments. /

error_t dev_icu_enable_irq( uint32_t irq_type,

uint32_t irq_id, device_t * src_dev );

/*

  • This blocking function disable one IRQ defined by its type (HWI/WTI/PTI) and index
  • in the local ICU device descriptor, and remove it from the proper interrupt vector
  • of the calling core. *
  • @ irq_type : HWI/WTI/PTI.
  • @ irq_id : IRQ index.
  • @ returns 0 if success / returns EINVAL if illegal arguments. /

error_t dev_icu_disable_irq( uint32_t irq_type,

uint32_t irq_id );

/*

  • This blocking function set the period value for a timer identified by the PTI index
  • in the local ICU device descriptor. *
  • @ pti_id : PTI index.
  • @ period : number of cycles.
  • @ return 0 if success / returns EINVAL if illegal arguments. /

error_t dev_icu_set_period( core_t * core,

uint32_t pti_id, uint32_t period );

/*

  • 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). *
  • @ cxy : destination cluster identifier.
  • @ lid : destination core local index.
  • @ return 0 if success (IPI registered) / returns EINVAL if illegal cxy or lid. /

error_t dev_icu_send_ipi( cxy_t cxy,

lid_t lid );

/*

  • 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 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. /

void dev_icu_irq_handler();