Example of modifying the interrupt controller in a BSP when using InterruptAttach()
By default, when you use InterruptAttach() calls to attach an ISR to a specific interrupt, the ISR is executed on the core that receives the interrupt. Routing an interrupt to a specific core isn’t done in the kernel, but can be done in the startup code of a board support package where you would program the interrupt controller (PIC/GIC) initialization code.
You can call a new function to modify the interrupt controller to deliver an interrupt to a specific CPU (CPU0 – CPUn where n represents the CPU number), presuming the interrupt controller provides this support. By default, interrupts are delivered to CPU0 with the exception of IPIs which are delivered to specific CPUs.
- create a function to configure interrupt routing
- call the function that you created in the previous step in the
init_intrinfo(void)function
In the init_intrinfo(void) function in the imx_init_intrinfo.c), you can call a custom function to route interrupts to a specific CPU that you create.
...
...
/**
* Example function to Route SPI Interrupts to a Specific CPU
*
* @param gicd GIC distributor base address.
* @param aff3 (ARM_GICD_IROUTERn[39:32]) — affinity level 3, the least
* significant affinity level field
* @param aff2 (ARM_GICD_IROUTERn[23:16]) — affinity level 2, an intermediate
* affinity level field
* @param aff1 (ARM_GICD_IROUTERn[15:8]) — affinity level 1, an intermediate
* affinity level field
* @param aff0 (ARM_GICD_IROUTERn[7:0]) — affinity level 0, the most significant
* affinity level field
*/
void gic_v3_intr_route(paddr_t gicd, uint8_t aff3, uint8_t aff2,
uint8_t aff1, uint8_t aff0)
{
unsigned itn, spi_vectors, i;
/* Calculate the number of interrupt lines */
uint32_t const gicd_typer = in32(gicd + ARM_GICD_TYPER);
itn = ((gicd_typer & ARM_GICD_TYPER_ITLN) + 1) * 32;
if (debug_flag > 1) {
kprintf("GICv3: %d interrupts\n", itn);
}
spi_vectors = min(1020, itn) - 32;
/* Route all SPI interrupts to the specific CPU */
for (i = 0; i < spi_vectors; i++) {
((uint64_t *)(gicd + ARM_GICD_IROUTERn))[i+32] = ((uint64_t)aff3 << 32) |
((uint64_t)aff2 << 16) |
((uint64_t)aff1 << 8) |
((uint64_t)aff0 << 0);
}
kprintf("Route %d SPI interrupt to CPU affinity %d.%d.%d.%d\n",
spi_vectors, aff3, aff2, aff1, aff0);
}
/**
* Initialize Generic Interrupt Controller (GIC).
*/
void init_intrinfo(void)
{
/* Initialize GIC */
gic_v3_init(IMX_GIC_GICD_BASE, IMX_GIC_GICR_BASE, IMX_GIC_GICC_BASE, 0, 0);
/* Example to route all SPI interrupts to CPU1 (affinity 0.0.0.1) */
gic_v3_intr_route(IMX_GIC_GICD_BASE, 0, 0, 0, 1);
/* Add the interrupt callouts */
add_interrupt_array(pci_steer_intr, sizeof(pci_steer_intr));
}
...
/** @} */ /* End of startup */
