Implementing Hardware Interrupt Affinity via the Irq_chip Interface

The Linux kernel employs the struct irq_chip abstraction to represent interrupt controller hardware. Since different processor architectures manage interrupts uniquely, this structure encapsulates callback functon pointers directed at the underlying hardware control logic. Key operations such as enabling, masking, and configuring affinity are routed through these functions.

Structure Definition

The core interface resides in struct irq_chip, containing handlers for lifecycle events and configuration updates:

struct irq_chip {
    const char              *name;
    unsigned int            (*irq_startup)(struct irq_data *data);
    void                    (*irq_shutdown)(struct irq_data *data);
    void                    (*irq_enable)(struct irq_data *data);
    void                    (*irq_disable)(struct irq_data *data);
    void                    (*irq_ack)(struct irq_data *data);
    void                    (*irq_mask)(struct irq_data *data);
    void                    (*irq_unmask)(struct irq_data *data);
    void                    (*irq_eoi)(struct irq_data *data);
    int                     (*irq_set_affinity)(struct irq_data *data, const struct cpumask *dest, bool force);
    int                     (*irq_retrigger)(struct irq_data *data);
    int                     (*irq_set_type)(struct irq_data *data, unsigned int flow_type);
    /* Other members omitted for brevity */
    unsigned long           flags;
};

Device Tree Configuration

To bind interrupts within the device tree, the corresponding controller node must expose interrupt properties. Below is an example configuraton for a GPIO controller utilizing a GIC SPI line:

        my_gpio_controller: gpio@e6050000 {
            compatible = "renesas,gpio-r8a7796",
                         "renesas,rcar-gen3-gpio";
            reg = <0 0xe6050000 0 0x50>;
            interrupts = <GIC_SPI 4 IRQ_TYPE_LEVEL_HIGH>;
            #gpio-cells = <2>;
            gpio-controller;
            gpio-ranges = <&pfc 0 0 16>;
            #interrupt-cells = <2>;
            interrupt-controller;
            clocks = <&cpg CPG_MOD 912>;
            power-domains = <&sysc R8A7796_PD_ALWAYS_ON>;
            resets = <&cpg 912>;
        };

Driver Implementation

In a kernel driver, populate the irq_chip structure with specific handler implementations. Ensure all mandatory callbacks for the hardware state are defined.

static struct irq_chip platform_gpio_irqchip = {
    .name                   = "platform_gpio",
    .irq_ack                = gpio_irq_ack_handler,
    .irq_set_type           = gpio_irq_set_trigger,
    .irq_enable             = gpio_irq_enable_handler,
    .irq_disable            = gpio_irq_disable_handler,
    .irq_set_affinity       = gpio_set_irq_affinity,
};

Handling CPU Affintiy Requests

When the kernel requests to bind an interrupt to specific CPU cores, the .irq_set_affinity callback executes. You must retrieve the parent IRQ chip and delegate the request to manage multi-level interrupt hierarchies effectively.

static int gpio_set_irq_affinity(struct irq_data *data,
                                 const struct cpumask *cpumask,
                                 bool force)
{
    struct gpio_chip *gc = irq_data_get_irq_chip_data(data);
    struct irq_chip *parent_chip = irq_get_chip(gc->irq.irq);

    if (parent_chip && parent_chip->irq_set_affinity) {
        return parent_chip->irq_set_affinity(data, cpumask, force);
    }
    return -EINVAL;
}

This ensures that affinity settings propagate correctly up the interrupt hierarchy to the root controller capable of executing the hardware routing change.

Tags: linux-kernel driver-development irq-affinity embedded-systems

Posted on Mon, 01 Jun 2026 17:27:36 +0000 by msound