From rkrcmar at qti.qualcomm.com Mon Feb 2 06:49:23 2026 From: rkrcmar at qti.qualcomm.com (Radim Krcmar) Date: Mon, 2 Feb 2026 14:49:23 +0000 Subject: [PATCH 3/3] firmware: fw_base.S: Add common NMI trap handler In-Reply-To: <20260129-smrnmi-v3-v1-3-5d297d3e2027@sifive.com> References: <20260129-smrnmi-v3-v1-0-5d297d3e2027@sifive.com> <20260129-smrnmi-v3-v1-3-5d297d3e2027@sifive.com> Message-ID: 2026-01-29T00:13:43-08:00, Nylon Chen : > Add rnmi_handler assembly wrapper and sbi_rnmi_trap_handler default > C handler. The default handler prints diagnostics and hangs the hart. > > Co-developed-by: Zong Li > Signed-off-by: Zong Li > Suggested-by: Nick Hu > Suggested-by: Samuel Holland > Signed-off-by: Nylon Chen > Signed-off-by: Yong-Xuan Wang > --- > diff --git a/firmware/fw_base.S b/firmware/fw_base.S > @@ -643,6 +643,70 @@ memcmp: > + .section .entry, "ax", %progbits > + .align 4 > + .globl sbi_rnmi_vector > +sbi_rnmi_vector: > + /* Swap SP with MNSCRATCH */ > + csrrw sp, CSR_MNSCRATCH, sp > + > + /* Allocate space for full trap registers structure */ > + addi sp, sp, -(SBI_TRAP_REGS_SIZE) [2/3] did: rnmi_context_offset = sbi_scratch_alloc_offset(SBI_TRAP_REGS_SIZE); rnmi_ctx = sbi_scratch_offset_ptr(scratch, rnmi_context_offset); rnmi_sp = (unsigned long)rnmi_ctx + SBI_TRAP_REGS_SIZE; csr_write(CSR_MNSCRATCH, rnmi_sp); We can avoid the add/subtract dance, since it produces rnmi_ctx. A bigger issue is that it leaves 0 bytes for the stack of the callback. Is there a reason not to reuse the existing M-mode stack? Thanks. From raymondmaoca at gmail.com Mon Feb 2 07:02:05 2026 From: raymondmaoca at gmail.com (Raymond Mao) Date: Mon, 2 Feb 2026 10:02:05 -0500 Subject: [RFC v2 PATCH 0/2] Introduce irqchip and VIRQ layer prototypes Message-ID: <20260202150207.1331811-1-raymondmaoca@gmail.com> From: Raymond Mao This RFC introduces irqchip abstraction and VIRQ layers for APLIC wired interrupt support in OpenSBI. In the current OpenSBI implementation, APLIC support primarily focuses on initialization and delegation, while external interrupt handling for wired interrupts remains largely stubbed. As a result: - There is no generic mechanism for OpenSBI drivers or platforms to register handlers for wired interrupt lines. - Interrupt dispatch remains tightly coupled to specific irqchip implementations. The goal is to introduce a small, extensible abstraction for irqchip to hide the HW details and provide abstract operations like interrupt provider registration, claim/complete/mask/unmask operations. VIRQ (Virtual IRQ) layer is on top of INTC, providing IRQ state management via per-(domain,hart) IRQ pending queue, with courier dispatching and interface to enqueue/pop/complete an IRQ and map hwirq to virtual IRQ number to avoid exposure of hwirq. Raymond Mao (2): lib: sbi: introduce abstraction for wired interrupt handling lib: sbi: Add VIRQ interrupt abstraction Changes in v2: - Move INTC to irqchip - Move hwirq mapping to VIRQ - Remove get_caps and pass in max_src during provider registration - All irqchip interface use hwirq as parameter include/sbi/sbi_irqchip.h | 52 ++++++++++++++++++++++ include/sbi/sbi_virq.h | 90 +++++++++++++++++++++++++++++++++++++++ 2 files changed, 142 insertions(+) create mode 100644 include/sbi/sbi_virq.h -- 2.25.1 From raymondmaoca at gmail.com Mon Feb 2 07:02:06 2026 From: raymondmaoca at gmail.com (Raymond Mao) Date: Mon, 2 Feb 2026 10:02:06 -0500 Subject: [PATCH v2 1/2] lib: sbi: introduce abstraction for wired interrupt handling In-Reply-To: <20260202150207.1331811-1-raymondmaoca@gmail.com> References: <20260202150207.1331811-1-raymondmaoca@gmail.com> Message-ID: <20260202150207.1331811-2-raymondmaoca@gmail.com> From: Raymond Mao Add wired interrupt handling abstraction into irqchip. This introduces a small provider interface based on claim/complete/mask/unmak semantics, allowing to register a wired interrupt controller as a provider. Signed-off-by: Raymond Mao --- include/sbi/sbi_irqchip.h | 52 +++++++++++++++++++++++++++++++++++++++ 1 file changed, 52 insertions(+) diff --git a/include/sbi/sbi_irqchip.h b/include/sbi/sbi_irqchip.h index e0ae12f5..27b88765 100644 --- a/include/sbi/sbi_irqchip.h +++ b/include/sbi/sbi_irqchip.h @@ -27,6 +27,38 @@ struct sbi_irqchip_device { int (*irq_handle)(void); }; +/* Handler for a specified hwirq */ +typedef int (*sbi_irqchip_irq_handler_t)(void *priv); + +/* Provider operations */ +struct sbi_irqchip_provider_ops { + /* + * 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 *hwirq); + + /* + * Complete/acknowledge a previously claimed wired interrupt + * (if required by HW). + * Some HW may not require an explicit completion. + */ + void (*complete)(void *ctx, u32 hwirq); + + /* + * 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 hwirq); + void (*unmask)(void *ctx, u32 hwirq); +}; + /** * Process external interrupts * @@ -46,4 +78,24 @@ int sbi_irqchip_init(struct sbi_scratch *scratch, bool cold_boot); /** Exit interrupt controllers */ void sbi_irqchip_exit(struct sbi_scratch *scratch); +/* + * Register the active wired interrupt provider. + * - max_hwirq specifies the highest valid hwirq ID. + */ +int sbi_irqchip_register_provider(const struct sbi_irqchip_provider_ops *ops, + void *ctx, u32 max_hwirq); + +u32 sbi_irqchip_get_max_src(void); + +/* Set/clear handler for a specified hwirq */ +int sbi_irqchip_set_handler(u32 hwirq, sbi_irqchip_irq_handler_t handler, + void *priv); +int sbi_irqchip_clear_handler(u32 hwirq); + +void sbi_irqchip_mask_irq(u32 hwirq); +void sbi_irqchip_unmask_irq(u32 hwirq); + +/* external interrupt handler (irqchip device hook) */ +int sbi_irqchip_handle_external_irq(void); + #endif -- 2.25.1 From raymondmaoca at gmail.com Mon Feb 2 07:02:07 2026 From: raymondmaoca at gmail.com (Raymond Mao) Date: Mon, 2 Feb 2026 10:02:07 -0500 Subject: [PATCH v2 2/2] lib: sbi: Add VIRQ interrupt abstraction In-Reply-To: <20260202150207.1331811-1-raymondmaoca@gmail.com> References: <20260202150207.1331811-1-raymondmaoca@gmail.com> Message-ID: <20260202150207.1331811-3-raymondmaoca@gmail.com> From: Raymond Mao VIRQ (Virtual IRQ) layer is on top of irqchip, providing IRQ state management via per-(domain,hart) IRQ pending queue, with courier dispatching and interface to enqueue/pop/complete an IRQ. It dispatches claimed wired interrupts to S-Mode domains via SSE injection on current hart. Signed-off-by: Raymond Mao --- include/sbi/sbi_virq.h | 90 ++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 90 insertions(+) create mode 100644 include/sbi/sbi_virq.h diff --git a/include/sbi/sbi_virq.h b/include/sbi/sbi_virq.h new file mode 100644 index 00000000..1760d9b5 --- /dev/null +++ b/include/sbi/sbi_virq.h @@ -0,0 +1,90 @@ +/* + * SPDX-License-Identifier: BSD-2-Clause + * + * Copyright (c) 2026 RISCstar Solutions Corporation. + * + * Author: Raymond Mao + */ + +#ifndef __SBI_VIRQ_H__ +#define __SBI_VIRQ_H__ + +#include +#include + +/* + * Keep the queue small for bring-up. If it overflows, we drop and warn. + */ +#define SBI_VIRQ_QSIZE 32 + +/* per-(domain,hart) IRQ state */ +struct sbi_domain_virq_state { + spinlock_t lock; + u32 head; + u32 tail; + /* pending IRQ queue */ + u32 q[SBI_VIRQ_QSIZE]; +}; + +/* Per-domain VIRQ context */ +struct sbi_domain_virq_priv { + /* harts number of the domain */ + u32 nharts; + /* IRQ states of all harts of the domain */ + struct sbi_domain_virq_state st[]; +}; + +struct sbi_virq_courier_priv { + struct sbi_domain *dom; + u32 virq; +}; + +/* Enqueue an interrupt (as seen by the generic irqchip layer) for a domain. */ +int sbi_virq_enqueue(struct sbi_domain *dom, u32 irq); + +/* + * Complete a previously couriered irq for the current domain. + * + * This will unmask the interrupt line at the active irqchip provider, allowing + * further interrupts once S-mode has cleared the device interrupt source. + */ +void sbi_virq_complete_thishart(u32 irq); + +/* Pop next pending irq for current domain on this hart. Returns 0 if none. */ +u32 sbi_virq_pop_thishart(void); + +/* + * Courier handler for wired irqchip dispatch. + * + * Intended usage: + * sbi_irqchip_set_handler(hwirq, sbi_virq_courier_handler, dom); + * + * It will enqueue (irq) for the provided domain and inject SSE on the + * current hart to notify S-mode. + */ +int sbi_virq_courier_handler(void *priv); + +/* + * Bind helper function: bind a given irq and register the courier handler + * for a domain. + */ +int sbi_virq_bind_irq_to_domain(u32 irq, struct sbi_domain *dom); + +/* Initialize per-domain virq state (alloc + lock init). */ +int sbi_virq_domain_init(struct sbi_domain *dom); + + +/* + * Optional: map a virtual IRQ number (virq) to a hardware wired IRQ (hwirq). + * + * If no explicit mapping exists, 'virq==hwirq' is assumed. + * + * This allows upper layers (e.g. VIRQ courier/emulation) to use stable virq + * identifiers without exposing the wired controller's hwirq numbering. + */ +int sbi_virq_map_irq(u32 virq, u32 hwirq); +int sbi_virq_unmap_irq(u32 virq); +u32 sbi_virq_irq_to_hwirq(u32 virq); +u32 sbi_virq_hwirq_to_irq(u32 hwirq); + +#endif -- 2.25.1 From rkrcmar at qti.qualcomm.com Mon Feb 2 07:26:33 2026 From: rkrcmar at qti.qualcomm.com (Radim Krcmar) Date: Mon, 2 Feb 2026 15:26:33 +0000 Subject: [PATCH 2/3] lib: sbi: Enable Smrnmi extension handler In-Reply-To: <20260129-smrnmi-v3-v1-2-5d297d3e2027@sifive.com> References: <20260129-smrnmi-v3-v1-0-5d297d3e2027@sifive.com> <20260129-smrnmi-v3-v1-2-5d297d3e2027@sifive.com> Message-ID: 2026-01-29T00:13:42-08:00, Nylon Chen : > Enable the Smrnmi extension by: > 1. Adding sbi_rnmi_vector_init() to allocate per-HART RNMI context and enable RNMI via MNSTATUS.NMIE > 2. Saving and restoring CSR_MNSCRATCH and CSR_MNSTATUS across non-retentive suspend/resume > 3. Calling sbi_rnmi_vector_init() from the cold and warm init paths > > Co-developed-by: Zong Li > Signed-off-by: Zong Li > Suggested-by: Nick Hu > Suggested-by: Samuel Holland > Signed-off-by: Nylon Chen > Signed-off-by: Yong-Xuan Wang > --- > diff --git a/include/sbi/sbi_platform.h b/include/sbi/sbi_platform.h > @@ -149,6 +149,15 @@ struct sbi_platform_operations { > unsigned long log2len); > /** platform specific pmp disable on current HART */ > void (*pmp_disable)(unsigned int n); > + /** > + * Platform-specific helper to program the RNMI trap vector. > + * > + * The core will call this from sbi_rnmi_vector_init() with the > + * firmware RNMI handler entry address (rnmi_handler) and the > + * cold_boot flag. Platforms that support Smrnmi should implement > + * this; others can leave it NULL. > + */ If the hart supports Smrnmi, then it begins with nmstatus.NMIE=0, which means that any exception is going to enter a critical state. The platform must somehow support Smrnmi to be useful, and I think it would be better not to do it behind opensbi's back. If the platform wants to handle Smrnmi itself, it can hide Smrnmi from opensbi, so I think the requirement here would be better as MUST. > + int (*set_rnmi_trap_vector)(uintptr_t handler_addr, bool cold_boot); > diff --git a/lib/sbi/sbi_init.c b/lib/sbi/sbi_init.c > @@ -273,6 +273,10 @@ static void __noreturn init_coldboot(struct sbi_scratch *scratch, u32 hartid) > if (rc) > sbi_hart_hang(); > > + rc = sbi_rnmi_vector_init(scratch, true); Are we sure that earlier opensbi code won't try to trigger a trap before this point? OpenSBI would fail to boot if it did... Thanks. From atish.patra at linux.dev Mon Feb 2 11:28:08 2026 From: atish.patra at linux.dev (Atish Patra) Date: Mon, 2 Feb 2026 11:28:08 -0800 Subject: [PATCH] lib: sbi_pmu: Track SBI_PMU_FW_PLATFORM started counter In-Reply-To: <20260127-pmu_platform_stop-v1-1-b07d1abd1ef2@gmail.com> References: <20260127-pmu_platform_stop-v1-1-b07d1abd1ef2@gmail.com> Message-ID: <2eed3524-7faa-4311-9f2c-8d790f792f6e@linux.dev> On 1/27/26 3:58 PM, Charlie Jenkins via B4 Relay wrote: > From: Charlie Jenkins > > When a SBI_PMU_FW_PLATFORM starts, add the counter to the counter array > instead of returning early. This will cause fw_counter_stop() to be > called when a SBI_PMU_FW_PLATFORM counter should be stopped. > > Signed-off-by: Charlie Jenkins > --- > lib/sbi/sbi_pmu.c | 10 ++++++---- > 1 file changed, 6 insertions(+), 4 deletions(-) > > diff --git a/lib/sbi/sbi_pmu.c b/lib/sbi/sbi_pmu.c > index e084005d..3c61079b 100644 > --- a/lib/sbi/sbi_pmu.c > +++ b/lib/sbi/sbi_pmu.c > @@ -448,6 +448,8 @@ static int pmu_ctr_start_fw(struct sbi_pmu_hart_state *phs, > uint64_t event_data, uint64_t ival, > bool ival_update) > { > + int rc = 0; > + > if ((event_code >= SBI_PMU_FW_MAX && > event_code <= SBI_PMU_FW_RESERVED_MAX) || > event_code > SBI_PMU_FW_PLATFORM) > @@ -468,9 +470,9 @@ static int pmu_ctr_start_fw(struct sbi_pmu_hart_state *phs, > cidx - num_hw_ctrs, > ival); > > - return pmu_dev->fw_counter_start(phs->hartid, > - cidx - num_hw_ctrs, > - event_data); > + rc = pmu_dev->fw_counter_start(phs->hartid, > + cidx - num_hw_ctrs, > + event_data); > } else { > if (ival_update) > phs->fw_counters_data[cidx - num_hw_ctrs] = ival; > @@ -478,7 +480,7 @@ static int pmu_ctr_start_fw(struct sbi_pmu_hart_state *phs, > > phs->fw_counters_started |= BIT(cidx - num_hw_ctrs); > > - return 0; > + return rc; > } > > static void pmu_update_inhibit_flags(unsigned long flags, uint64_t *mhpmevent_val) > Reviewed-by: Atish Patra > --- > base-commit: 74434f255873d74e56cc50aa762d1caf24c099f8 > change-id: 20260127-pmu_platform_stop-febef65abf54 > > - Charlie > > >