[RFC PATCH 1/2] lib: sbi: introduce INTC abstraction for wired interrupts

Anup Patel anup at brainfault.org
Thu Jan 29 23:48:22 PST 2026


On Tue, Jan 27, 2026 at 8:54 PM Raymond Mao <raymondmaoca at gmail.com> wrote:
>
> From: Raymond Mao <raymond.mao at riscstar.com>
>
> Add a wired interrupt-controller (INTC) abstraction to OpenSBI.
> This introduces a small provider interface based on
> claim/complete/mask/unmak semantics, allowing to register a wired
> interrupt controller as a provider.
> Plus, add virtual IRQ number mapping to avoid exposure of hwirq.
>
> Signed-off-by: Raymond Mao <raymond.mao at riscstar.com>
> ---
>  sbi_intc.h | 99 ++++++++++++++++++++++++++++++++++++++++++++++++++++++
>  1 file changed, 99 insertions(+)
>  create mode 100644 sbi_intc.h
>
> diff --git a/sbi_intc.h b/sbi_intc.h
> new file mode 100644
> index 00000000..f51974c9
> --- /dev/null
> +++ b/sbi_intc.h
> @@ -0,0 +1,99 @@
> +/*
> + * SPDX-License-Identifier: BSD-2-Clause
> + *
> + * Copyright (c) 2026 RISCstar Solutions Corporation.
> + *
> + * Author: Raymond Mao <raymond.mao at riscstar.com>
> + */
> +
> +#ifndef __SBI_INTC_H__
> +#define __SBI_INTC_H__
> +
> +#include <sbi/sbi_types.h>
> +
> +/* Handler for a specified IRQ number */
> +typedef int (*sbi_intc_irq_handler_t)(u32 irq, void *priv);
> +
> +/*
> + * Provider capabilities, at the moment it contains the maximum valid source ID
> + * but extensible in the future
> + */
> +struct sbi_intc_provider_caps {
> +       /*
> +        * Maximum supported wired source ID for this provider.
> +        *
> +        * For APLIC this corresponds to the highest valid source ID (1..N).
> +        * The INTC core treats this as an abstract provider source ID space.
> +        */
> +       u32 max_src;
> +};
> +
> +/* Provider operations */
> +struct sbi_intc_provider_ops {
> +       /*
> +        * Query provider capabilities.
> +        *
> +        * This avoids exposing provider-specific limits (such as APLIC
> +        * num_source) through the registration API.
> +        */
> +       int (*get_caps)(void *ctx, struct sbi_intc_provider_caps *caps);

This callback is not needed instead you driver can pass max_src
as parameter to sbi_intc_register_provider()

> +
> +       /*
> +        * Claim a pending wired interrupt on current hart.
> +        * Returns:
> +        *   SBI_OK      : *hwirq is valid
> +        *   SBI_ENOENT  : no pending wired interrupt
> +        *   <0          : error
> +        */
> +       int (*claim)(void *ctx, u32 *irq);
> +
> +       /*
> +        * Complete/acknowledge a previously claimed wired interrupt
> +        * (if required by HW).
> +        * Some HW may not require an explicit completion.
> +        */
> +       void (*complete)(void *ctx, u32 irq);

All provider callbacks should take hwirq as a parameter.

> +
> +       /*
> +        * mask/unmask a wired interrupt line.
> +        *
> +        * These are required for reliable couriering of level-triggered device
> +        * interrupts to S-mode: mask in M-mode before enqueueing, and unmask
> +        * after S-mode has cleared the device interrupt source.
> +        */
> +       void (*mask)(void *ctx, u32 irq);
> +       void (*unmask)(void *ctx, u32 irq);

Same as above.

> +};
> +
> +/* Register the active wired interrupt provider, e.g. APLIC, via ops and ctx */
> +int sbi_intc_register_provider(const struct sbi_intc_provider_ops *ops,
> +                              void *ctx);
> +
> +/*
> + * Optional: map a IRQ number (irq) to a hardware wired IRQ (hwirq).
> + *
> + * If no explicit mapping exists, 'irq==hwirq' is assumed.
> + *
> + * This allows upper layers (e.g. VIRQ courier/emulation) to use stable irq
> + * identifiers without exposing the wired controller's hwirq numbering.
> + */
> +int sbi_intc_map_irq(u32 irq, u32 hwirq);
> +int sbi_intc_unmap_irq(u32 irq);

The virq courier/emulation will be an independent module
so drop these functions.

Also, the driver should have no control on how irq is mapped
to hwirq. The INTC framework will internally manage irq to
hwirq mapping for a particular provider.

> +u32 sbi_intc_irq_to_hwirq(u32 irq);
> +u32 sbi_intc_hwirq_to_irq(u32 hwirq);
> +
> +/* Set/clear handler for a specified IRQ number */
> +int sbi_intc_set_handler(u32 irq, sbi_intc_irq_handler_t handler, void *priv);
> +int sbi_intc_clear_handler(u32 irq);
> +
> +/*
> + * Platform independent mask/unmak wrappers on top of platform registered
> + * mask/unmask ops functions.
> + */
> +void sbi_intc_mask_irq(u32 irq);
> +void sbi_intc_unmask_irq(u32 irq);
> +
> +/* External interrupt handler (for irqchip device hook 'irqchip.irq_handle') */
> +int sbi_intc_handle_external_irq(void);
> +
> +#endif

Also, introducing a new set of sbi_intc.c and sbi_intc.h is
not going to fly.

We had already created sbi_irqchip.c and sbi_irqchip.h to
manage external interrupts so the goal should be to enhance
these frameworks.

Regards,
Anup



More information about the opensbi mailing list