* [PATCH v3 01/11] target/arm: Call arm*_cpu_do_interrupt directly instead of via TCGCPUOps
2026-09-02 15:20 [PATCH v3 00/11] accel/tcg: Push BQL down into per-target do_interrupt handlers Philippe Mathieu-Daudé
@ 2026-09-02 15:20 ` Philippe Mathieu-Daudé
2026-09-02 19:52 ` Pierrick Bouvier
` (2 more replies)
2026-09-02 15:20 ` [PATCH v3 03/11] target/i386: Rename fake_do_interrupt to fake_user_exception Philippe Mathieu-Daudé
` (10 subsequent siblings)
11 siblings, 3 replies; 28+ messages in thread
From: Philippe Mathieu-Daudé @ 2026-09-02 15:20 UTC (permalink / raw)
To: qemu-devel
Cc: Mark Cave-Ayland, Peter Maydell, Paolo Bonzini, qemu-ppc,
qemu-s390x, Richard Henderson, Pierrick Bouvier, qemu-riscv,
qemu-arm, Philippe Mathieu-Daudé
The TCGCPUOps.do_interrupt handler is a target-specific
callback installed for use by target-agnostic TCG core methods.
Target-specific code should not dispatch through this indirection;
call the ARM implementation directly instead.
Reported-by: Richard Henderson <richard.henderson@linaro.org>
Signed-off-by: Philippe Mathieu-Daudé <philmd@oss.qualcomm.com>
---
target/arm/cpu-irq.c | 2 +-
target/arm/tcg/cpu-v7m.c | 2 +-
2 files changed, 2 insertions(+), 2 deletions(-)
diff --git a/target/arm/cpu-irq.c b/target/arm/cpu-irq.c
index 883e8a176c3..e8a6520e5ca 100644
--- a/target/arm/cpu-irq.c
+++ b/target/arm/cpu-irq.c
@@ -270,7 +270,7 @@ bool arm_cpu_exec_interrupt(CPUState *cs, int interrupt_request)
found:
cs->exception_index = excp_idx;
env->exception.target_el = target_el;
- cs->cc->tcg_ops->do_interrupt(cs);
+ arm_cpu_do_interrupt(cs);
return true;
}
#endif /* CONFIG_TCG */
diff --git a/target/arm/tcg/cpu-v7m.c b/target/arm/tcg/cpu-v7m.c
index 48b31d5eac8..502998dbd1c 100644
--- a/target/arm/tcg/cpu-v7m.c
+++ b/target/arm/tcg/cpu-v7m.c
@@ -34,7 +34,7 @@ static bool arm_v7m_cpu_exec_interrupt(CPUState *cs, int interrupt_request)
if (interrupt_request & CPU_INTERRUPT_HARD
&& (armv7m_nvic_can_take_pending_exception(env->nvic))) {
cs->exception_index = EXCP_IRQ;
- cs->cc->tcg_ops->do_interrupt(cs);
+ arm_v7m_cpu_do_interrupt(cs);
ret = true;
}
return ret;
--
2.53.0
^ permalink raw reply related [flat|nested] 28+ messages in thread* Re: [PATCH v3 01/11] target/arm: Call arm*_cpu_do_interrupt directly instead of via TCGCPUOps
2026-09-02 15:20 ` [PATCH v3 01/11] target/arm: Call arm*_cpu_do_interrupt directly instead of via TCGCPUOps Philippe Mathieu-Daudé
@ 2026-09-02 19:52 ` Pierrick Bouvier
2026-09-08 16:09 ` Peter Maydell
2026-09-13 2:42 ` Richard Henderson
2 siblings, 0 replies; 28+ messages in thread
From: Pierrick Bouvier @ 2026-09-02 19:52 UTC (permalink / raw)
To: Philippe Mathieu-Daudé, qemu-devel
Cc: Mark Cave-Ayland, Peter Maydell, Paolo Bonzini, qemu-ppc,
qemu-s390x, Richard Henderson, qemu-riscv, qemu-arm
On 9/2/2026 8:20 AM, Philippe Mathieu-Daudé wrote:
> The TCGCPUOps.do_interrupt handler is a target-specific
> callback installed for use by target-agnostic TCG core methods.
> Target-specific code should not dispatch through this indirection;
> call the ARM implementation directly instead.
>
> Reported-by: Richard Henderson <richard.henderson@linaro.org>
> Signed-off-by: Philippe Mathieu-Daudé <philmd@oss.qualcomm.com>
> ---
> target/arm/cpu-irq.c | 2 +-
> target/arm/tcg/cpu-v7m.c | 2 +-
> 2 files changed, 2 insertions(+), 2 deletions(-)
>
Reviewed-by: Pierrick Bouvier <pierrick.bouvier@oss.qualcomm.com>
^ permalink raw reply [flat|nested] 28+ messages in thread
* Re: [PATCH v3 01/11] target/arm: Call arm*_cpu_do_interrupt directly instead of via TCGCPUOps
2026-09-02 15:20 ` [PATCH v3 01/11] target/arm: Call arm*_cpu_do_interrupt directly instead of via TCGCPUOps Philippe Mathieu-Daudé
2026-09-02 19:52 ` Pierrick Bouvier
@ 2026-09-08 16:09 ` Peter Maydell
2026-09-13 2:42 ` Richard Henderson
2 siblings, 0 replies; 28+ messages in thread
From: Peter Maydell @ 2026-09-08 16:09 UTC (permalink / raw)
To: Philippe Mathieu-Daudé
Cc: qemu-devel, Mark Cave-Ayland, Paolo Bonzini, qemu-ppc, qemu-s390x,
Richard Henderson, Pierrick Bouvier, qemu-riscv, qemu-arm
On Wed, 2 Sept 2026 at 16:20, Philippe Mathieu-Daudé
<philmd@oss.qualcomm.com> wrote:
>
> The TCGCPUOps.do_interrupt handler is a target-specific
> callback installed for use by target-agnostic TCG core methods.
> Target-specific code should not dispatch through this indirection;
> call the ARM implementation directly instead.
>
> Reported-by: Richard Henderson <richard.henderson@linaro.org>
> Signed-off-by: Philippe Mathieu-Daudé <philmd@oss.qualcomm.com>
> ---
> target/arm/cpu-irq.c | 2 +-
> target/arm/tcg/cpu-v7m.c | 2 +-
> 2 files changed, 2 insertions(+), 2 deletions(-)
>
> diff --git a/target/arm/cpu-irq.c b/target/arm/cpu-irq.c
> index 883e8a176c3..e8a6520e5ca 100644
> --- a/target/arm/cpu-irq.c
> +++ b/target/arm/cpu-irq.c
> @@ -270,7 +270,7 @@ bool arm_cpu_exec_interrupt(CPUState *cs, int interrupt_request)
> found:
> cs->exception_index = excp_idx;
> env->exception.target_el = target_el;
> - cs->cc->tcg_ops->do_interrupt(cs);
> + arm_cpu_do_interrupt(cs);
> return true;
> }
> #endif /* CONFIG_TCG */
> diff --git a/target/arm/tcg/cpu-v7m.c b/target/arm/tcg/cpu-v7m.c
> index 48b31d5eac8..502998dbd1c 100644
> --- a/target/arm/tcg/cpu-v7m.c
> +++ b/target/arm/tcg/cpu-v7m.c
> @@ -34,7 +34,7 @@ static bool arm_v7m_cpu_exec_interrupt(CPUState *cs, int interrupt_request)
> if (interrupt_request & CPU_INTERRUPT_HARD
> && (armv7m_nvic_can_take_pending_exception(env->nvic))) {
> cs->exception_index = EXCP_IRQ;
> - cs->cc->tcg_ops->do_interrupt(cs);
> + arm_v7m_cpu_do_interrupt(cs);
> ret = true;
> }
This works because we have separate cpu_exec_interrupt
methods for M-profile and A/R-profile, so we can drop the
indirection. If we had anywhere where we were trying to
do "call the appropriate do_interrupt function" from
code that's agnostic to M vs A/R this wouldn't work, but
happily we don't.
Reviewed-by: Peter Maydell <peter.maydell@linaro.org>
thanks
-- PMM
^ permalink raw reply [flat|nested] 28+ messages in thread* Re: [PATCH v3 01/11] target/arm: Call arm*_cpu_do_interrupt directly instead of via TCGCPUOps
2026-09-02 15:20 ` [PATCH v3 01/11] target/arm: Call arm*_cpu_do_interrupt directly instead of via TCGCPUOps Philippe Mathieu-Daudé
2026-09-02 19:52 ` Pierrick Bouvier
2026-09-08 16:09 ` Peter Maydell
@ 2026-09-13 2:42 ` Richard Henderson
2 siblings, 0 replies; 28+ messages in thread
From: Richard Henderson @ 2026-09-13 2:42 UTC (permalink / raw)
To: Philippe Mathieu-Daudé, qemu-devel
Cc: Mark Cave-Ayland, Peter Maydell, Paolo Bonzini, qemu-ppc,
qemu-s390x, Pierrick Bouvier, qemu-riscv, qemu-arm
On 9/2/26 05:20, Philippe Mathieu-Daudé wrote:
> The TCGCPUOps.do_interrupt handler is a target-specific
> callback installed for use by target-agnostic TCG core methods.
> Target-specific code should not dispatch through this indirection;
> call the ARM implementation directly instead.
>
> Reported-by: Richard Henderson<richard.henderson@linaro.org>
> Signed-off-by: Philippe Mathieu-Daudé<philmd@oss.qualcomm.com>
> ---
> target/arm/cpu-irq.c | 2 +-
> target/arm/tcg/cpu-v7m.c | 2 +-
> 2 files changed, 2 insertions(+), 2 deletions(-)
Reviewed-by: Richard Henderson <richard.henderson@linaro.org>
r~
^ permalink raw reply [flat|nested] 28+ messages in thread
* [PATCH v3 03/11] target/i386: Rename fake_do_interrupt to fake_user_exception
2026-09-02 15:20 [PATCH v3 00/11] accel/tcg: Push BQL down into per-target do_interrupt handlers Philippe Mathieu-Daudé
2026-09-02 15:20 ` [PATCH v3 01/11] target/arm: Call arm*_cpu_do_interrupt directly instead of via TCGCPUOps Philippe Mathieu-Daudé
@ 2026-09-02 15:20 ` Philippe Mathieu-Daudé
2026-09-13 2:44 ` Richard Henderson
2026-09-02 15:20 ` [PATCH v3 04/11] accel/tcg: Document cpu_exec_interrupt() callback contract Philippe Mathieu-Daudé
` (9 subsequent siblings)
11 siblings, 1 reply; 28+ messages in thread
From: Philippe Mathieu-Daudé @ 2026-09-02 15:20 UTC (permalink / raw)
To: qemu-devel
Cc: Mark Cave-Ayland, Peter Maydell, Paolo Bonzini, qemu-ppc,
qemu-s390x, Richard Henderson, Pierrick Bouvier, qemu-riscv,
qemu-arm, Philippe Mathieu-Daudé
The fake_user_exception hook handles exceptions in the outer
exception loop (cpu_handle_exception), not inner loop interrupts
(cpu_handle_interrupt). Rename to clarify the scope and intent.
Signed-off-by: Philippe Mathieu-Daudé <philmd@oss.qualcomm.com>
---
include/accel/tcg/cpu-ops.h | 4 ++--
target/i386/tcg/helper-tcg.h | 4 +++-
accel/tcg/cpu-exec.c | 4 ++--
target/i386/tcg/tcg-cpu.c | 2 +-
target/i386/tcg/user/seg_helper.c | 6 +++---
5 files changed, 11 insertions(+), 9 deletions(-)
diff --git a/include/accel/tcg/cpu-ops.h b/include/accel/tcg/cpu-ops.h
index 3ff6e6810e0..ded7cc700df 100644
--- a/include/accel/tcg/cpu-ops.h
+++ b/include/accel/tcg/cpu-ops.h
@@ -106,12 +106,12 @@ struct TCGCPUOps {
#ifdef CONFIG_USER_ONLY
/**
- * @fake_user_interrupt: Callback for 'fake exception' handling.
+ * @fake_user_exception: Callback for 'fake exception' handling.
*
* Simulate 'fake exception' which will be handled outside the
* cpu execution loop (hack for x86 user mode).
*/
- void (*fake_user_interrupt)(CPUState *cpu);
+ void (*fake_user_exception)(CPUState *cpu);
/**
* record_sigsegv:
diff --git a/target/i386/tcg/helper-tcg.h b/target/i386/tcg/helper-tcg.h
index f4b2ff740d5..5349ab71be9 100644
--- a/target/i386/tcg/helper-tcg.h
+++ b/target/i386/tcg/helper-tcg.h
@@ -35,11 +35,13 @@
* x86_cpu_do_interrupt:
* @cpu: vCPU the interrupt is to be handled by.
*/
-void x86_cpu_do_interrupt(CPUState *cpu);
#ifndef CONFIG_USER_ONLY
+void x86_cpu_do_interrupt(CPUState *cpu);
bool x86_cpu_exec_halt(CPUState *cpu);
bool x86_need_replay_interrupt(int interrupt_request);
bool x86_cpu_exec_interrupt(CPUState *cpu, int int_req);
+#else
+void x86_cpu_fake_user_exception(CPUState *cs);
#endif
void breakpoint_handler(CPUState *cs);
diff --git a/accel/tcg/cpu-exec.c b/accel/tcg/cpu-exec.c
index 257211235db..609931a0d6e 100644
--- a/accel/tcg/cpu-exec.c
+++ b/accel/tcg/cpu-exec.c
@@ -717,8 +717,8 @@ static inline bool cpu_handle_exception(CPUState *cpu, int *ret)
* handled outside the cpu execution loop.
*/
const TCGCPUOps *tcg_ops = cpu->cc->tcg_ops;
- if (tcg_ops->fake_user_interrupt) {
- tcg_ops->fake_user_interrupt(cpu);
+ if (tcg_ops->fake_user_exception) {
+ tcg_ops->fake_user_exception(cpu);
}
*ret = cpu->exception_index;
cpu->exception_index = -1;
diff --git a/target/i386/tcg/tcg-cpu.c b/target/i386/tcg/tcg-cpu.c
index 6f5dc06b3b9..7a4d73e7fee 100644
--- a/target/i386/tcg/tcg-cpu.c
+++ b/target/i386/tcg/tcg-cpu.c
@@ -173,7 +173,7 @@ const TCGCPUOps x86_tcg_ops = {
.cpu_exec_enter = x86_cpu_exec_enter,
.cpu_exec_exit = x86_cpu_exec_exit,
#ifdef CONFIG_USER_ONLY
- .fake_user_interrupt = x86_cpu_do_interrupt,
+ .fake_user_exception = x86_cpu_fake_user_exception,
.record_sigsegv = x86_cpu_record_sigsegv,
.record_sigbus = x86_cpu_record_sigbus,
#else
diff --git a/target/i386/tcg/user/seg_helper.c b/target/i386/tcg/user/seg_helper.c
index 3a4a6d5a745..019a781458b 100644
--- a/target/i386/tcg/user/seg_helper.c
+++ b/target/i386/tcg/user/seg_helper.c
@@ -42,7 +42,7 @@ void helper_syscall(CPUX86State *env, int next_eip_addend)
* instruction. It is only relevant if is_int is TRUE or if intno
* is EXCP_SYSCALL.
*/
-static void do_interrupt_user(CPUX86State *env, int intno, int is_int,
+static void do_exception_user(CPUX86State *env, int intno, int is_int,
int error_code, target_ulong next_eip)
{
if (is_int) {
@@ -76,7 +76,7 @@ static void do_interrupt_user(CPUX86State *env, int intno, int is_int,
}
}
-void x86_cpu_do_interrupt(CPUState *cs)
+void x86_cpu_fake_user_exception(CPUState *cs)
{
X86CPU *cpu = X86_CPU(cs);
CPUX86State *env = &cpu->env;
@@ -84,7 +84,7 @@ void x86_cpu_do_interrupt(CPUState *cs)
/* if user mode only, we simulate a fake exception
which will be handled outside the cpu execution
loop */
- do_interrupt_user(env, cs->exception_index,
+ do_exception_user(env, cs->exception_index,
env->exception_is_int,
env->error_code,
env->exception_next_eip);
--
2.53.0
^ permalink raw reply related [flat|nested] 28+ messages in thread* Re: [PATCH v3 03/11] target/i386: Rename fake_do_interrupt to fake_user_exception
2026-09-02 15:20 ` [PATCH v3 03/11] target/i386: Rename fake_do_interrupt to fake_user_exception Philippe Mathieu-Daudé
@ 2026-09-13 2:44 ` Richard Henderson
0 siblings, 0 replies; 28+ messages in thread
From: Richard Henderson @ 2026-09-13 2:44 UTC (permalink / raw)
To: Philippe Mathieu-Daudé, qemu-devel
Cc: Mark Cave-Ayland, Peter Maydell, Paolo Bonzini, qemu-ppc,
qemu-s390x, Pierrick Bouvier, qemu-riscv, qemu-arm
On 9/2/26 05:20, Philippe Mathieu-Daudé wrote:
> The fake_user_exception hook handles exceptions in the outer
> exception loop (cpu_handle_exception), not inner loop interrupts
> (cpu_handle_interrupt). Rename to clarify the scope and intent.
>
> Signed-off-by: Philippe Mathieu-Daudé<philmd@oss.qualcomm.com>
> ---
> include/accel/tcg/cpu-ops.h | 4 ++--
> target/i386/tcg/helper-tcg.h | 4 +++-
> accel/tcg/cpu-exec.c | 4 ++--
> target/i386/tcg/tcg-cpu.c | 2 +-
> target/i386/tcg/user/seg_helper.c | 6 +++---
> 5 files changed, 11 insertions(+), 9 deletions(-)
Reviewed-by: Richard Henderson <richard.henderson@linaro.org>
r~
^ permalink raw reply [flat|nested] 28+ messages in thread
* [PATCH v3 04/11] accel/tcg: Document cpu_exec_interrupt() callback contract
2026-09-02 15:20 [PATCH v3 00/11] accel/tcg: Push BQL down into per-target do_interrupt handlers Philippe Mathieu-Daudé
2026-09-02 15:20 ` [PATCH v3 01/11] target/arm: Call arm*_cpu_do_interrupt directly instead of via TCGCPUOps Philippe Mathieu-Daudé
2026-09-02 15:20 ` [PATCH v3 03/11] target/i386: Rename fake_do_interrupt to fake_user_exception Philippe Mathieu-Daudé
@ 2026-09-02 15:20 ` Philippe Mathieu-Daudé
2026-09-08 16:25 ` Peter Maydell
2026-09-02 15:20 ` [PATCH v3 05/11] accel/tcg: Document do_interrupt() " Philippe Mathieu-Daudé
` (8 subsequent siblings)
11 siblings, 1 reply; 28+ messages in thread
From: Philippe Mathieu-Daudé @ 2026-09-02 15:20 UTC (permalink / raw)
To: qemu-devel
Cc: Mark Cave-Ayland, Peter Maydell, Paolo Bonzini, qemu-ppc,
qemu-s390x, Richard Henderson, Pierrick Bouvier, qemu-riscv,
qemu-arm, Philippe Mathieu-Daudé
Expand docstring to clarify that @interrupt_request is a bitmask,
the handler is called with BQL held, and document the return value
semantics. Fix typo in arm_cpu_exec_interrupt() documentation
(s/inrerrupt/interrupt).
Signed-off-by: Philippe Mathieu-Daudé <philmd@oss.qualcomm.com>
---
include/accel/tcg/cpu-ops.h | 15 ++++++++++++++-
target/arm/internals.h | 2 +-
2 files changed, 15 insertions(+), 2 deletions(-)
diff --git a/include/accel/tcg/cpu-ops.h b/include/accel/tcg/cpu-ops.h
index ded7cc700df..87850402203 100644
--- a/include/accel/tcg/cpu-ops.h
+++ b/include/accel/tcg/cpu-ops.h
@@ -171,8 +171,21 @@ struct TCGCPUOps {
#else
/** @do_interrupt: Callback for interrupt handling. */
void (*do_interrupt)(CPUState *cpu);
- /** @cpu_exec_interrupt: Callback for processing interrupts in cpu_exec */
+
+ /**
+ * @cpu_exec_interrupt: Callback for processing target-specific interrupts
+ * @cpu: cpu context
+ * @interrupt_request: Bitmask of pending interrupts
+ *
+ * Called from cpu_handle_interrupt() with the BQL held. Process the
+ * pending interrupt according to the target specific @interrupt_request
+ * masking rules.
+ *
+ * Returns: %true if an interrupt was processed and the next TB should
+ * be restarted, %false to continue normal execution.
+ */
bool (*cpu_exec_interrupt)(CPUState *cpu, int interrupt_request);
+
/** @cpu_exec_reset: Callback for reset in cpu_exec. */
void (*cpu_exec_reset)(CPUState *cpu);
/**
diff --git a/target/arm/internals.h b/target/arm/internals.h
index 1775835ad50..551a6b4a872 100644
--- a/target/arm/internals.h
+++ b/target/arm/internals.h
@@ -1248,7 +1248,7 @@ static inline const char *aarch32_mode_name(uint32_t psr)
}
/**
- * arm_cpu_exec_interrupt(): Implementation of the cpu_exec_inrerrupt hook.
+ * arm_cpu_exec_interrupt(): Implementation of the cpu_exec_interrupt hook.
*/
bool arm_cpu_exec_interrupt(CPUState *cs, int interrupt_request);
--
2.53.0
^ permalink raw reply related [flat|nested] 28+ messages in thread* Re: [PATCH v3 04/11] accel/tcg: Document cpu_exec_interrupt() callback contract
2026-09-02 15:20 ` [PATCH v3 04/11] accel/tcg: Document cpu_exec_interrupt() callback contract Philippe Mathieu-Daudé
@ 2026-09-08 16:25 ` Peter Maydell
0 siblings, 0 replies; 28+ messages in thread
From: Peter Maydell @ 2026-09-08 16:25 UTC (permalink / raw)
To: Philippe Mathieu-Daudé
Cc: qemu-devel, Mark Cave-Ayland, Paolo Bonzini, qemu-ppc, qemu-s390x,
Richard Henderson, Pierrick Bouvier, qemu-riscv, qemu-arm
On Wed, 2 Sept 2026 at 16:21, Philippe Mathieu-Daudé
<philmd@oss.qualcomm.com> wrote:
>
> Expand docstring to clarify that @interrupt_request is a bitmask,
> the handler is called with BQL held, and document the return value
> semantics. Fix typo in arm_cpu_exec_interrupt() documentation
> (s/inrerrupt/interrupt).
>
> Signed-off-by: Philippe Mathieu-Daudé <philmd@oss.qualcomm.com>
> ---
> include/accel/tcg/cpu-ops.h | 15 ++++++++++++++-
> target/arm/internals.h | 2 +-
> 2 files changed, 15 insertions(+), 2 deletions(-)
>
> diff --git a/include/accel/tcg/cpu-ops.h b/include/accel/tcg/cpu-ops.h
> index ded7cc700df..87850402203 100644
> --- a/include/accel/tcg/cpu-ops.h
> +++ b/include/accel/tcg/cpu-ops.h
> @@ -171,8 +171,21 @@ struct TCGCPUOps {
> #else
> /** @do_interrupt: Callback for interrupt handling. */
> void (*do_interrupt)(CPUState *cpu);
> - /** @cpu_exec_interrupt: Callback for processing interrupts in cpu_exec */
> +
> + /**
> + * @cpu_exec_interrupt: Callback for processing target-specific interrupts
> + * @cpu: cpu context
> + * @interrupt_request: Bitmask of pending interrupts
> + *
> + * Called from cpu_handle_interrupt() with the BQL held. Process the
> + * pending interrupt according to the target specific @interrupt_request
> + * masking rules.
I think we could clarify this a little to explain what to do with
multiple pending interrupts. How about:
Identify which, if any, of the possibly multiple pending interrupts
specified by @interrupt_request should be taken, using the target
architecture's rules for interrupt prioritization and masking.
If an interrupt can validly be taken, take it (by updating the
emulated CPU state for an interrupt entry).
?
(I'm trying to get across that the function sets things up
for execution of the interrupt handler as the next thing, it
doesn't cause the whole interrupt handler to run. But maybe
that's obvious enough we don't need to say so.)
> + *
> + * Returns: %true if an interrupt was processed and the next TB should
> + * be restarted, %false to continue normal execution.
> + */
> bool (*cpu_exec_interrupt)(CPUState *cpu, int interrupt_request);
> +
> /** @cpu_exec_reset: Callback for reset in cpu_exec. */
> void (*cpu_exec_reset)(CPUState *cpu);
> /**
> diff --git a/target/arm/internals.h b/target/arm/internals.h
> index 1775835ad50..551a6b4a872 100644
> --- a/target/arm/internals.h
> +++ b/target/arm/internals.h
> @@ -1248,7 +1248,7 @@ static inline const char *aarch32_mode_name(uint32_t psr)
> }
>
> /**
> - * arm_cpu_exec_interrupt(): Implementation of the cpu_exec_inrerrupt hook.
> + * arm_cpu_exec_interrupt(): Implementation of the cpu_exec_interrupt hook.
> */
> bool arm_cpu_exec_interrupt(CPUState *cs, int interrupt_request);
>
-- PMM
^ permalink raw reply [flat|nested] 28+ messages in thread
* [PATCH v3 05/11] accel/tcg: Document do_interrupt() callback contract
2026-09-02 15:20 [PATCH v3 00/11] accel/tcg: Push BQL down into per-target do_interrupt handlers Philippe Mathieu-Daudé
` (2 preceding siblings ...)
2026-09-02 15:20 ` [PATCH v3 04/11] accel/tcg: Document cpu_exec_interrupt() callback contract Philippe Mathieu-Daudé
@ 2026-09-02 15:20 ` Philippe Mathieu-Daudé
2026-09-02 19:54 ` Pierrick Bouvier
2026-09-13 3:30 ` Richard Henderson
2026-09-02 15:20 ` [PATCH v3 06/11] accel/tcg: Rename do_interrupt() to do_interrupt_locked() Philippe Mathieu-Daudé
` (7 subsequent siblings)
11 siblings, 2 replies; 28+ messages in thread
From: Philippe Mathieu-Daudé @ 2026-09-02 15:20 UTC (permalink / raw)
To: qemu-devel
Cc: Mark Cave-Ayland, Peter Maydell, Paolo Bonzini, qemu-ppc,
qemu-s390x, Richard Henderson, Pierrick Bouvier, qemu-riscv,
qemu-arm, Philippe Mathieu-Daudé
Expand docstring to clarify the handler is called with BQL held.
Add assertion that this callback is mandatory and never NULL, since
all targets must implement interrupt handling.
Signed-off-by: Philippe Mathieu-Daudé <philmd@oss.qualcomm.com>
---
include/accel/tcg/cpu-ops.h | 11 ++++++++++-
accel/tcg/cpu-exec.c | 1 +
2 files changed, 11 insertions(+), 1 deletion(-)
diff --git a/include/accel/tcg/cpu-ops.h b/include/accel/tcg/cpu-ops.h
index 87850402203..13df70eaa9f 100644
--- a/include/accel/tcg/cpu-ops.h
+++ b/include/accel/tcg/cpu-ops.h
@@ -169,7 +169,16 @@ struct TCGCPUOps {
*/
vaddr (*untagged_addr)(CPUState *cs, vaddr addr);
#else
- /** @do_interrupt: Callback for interrupt handling. */
+ /**
+ * @do_interrupt: Deliver a pending exception/interrupt to the CPU
+ * @cpu: cpu context
+ *
+ * Called when cs->exception_index contains an exception code to deliver.
+ * Updates CPU architectural state (usually before executing a guest
+ * exception handler).
+ *
+ * Called from cpu_handle_exception() with BQL held.
+ */
void (*do_interrupt)(CPUState *cpu);
/**
diff --git a/accel/tcg/cpu-exec.c b/accel/tcg/cpu-exec.c
index 609931a0d6e..2fae2c024b8 100644
--- a/accel/tcg/cpu-exec.c
+++ b/accel/tcg/cpu-exec.c
@@ -1059,6 +1059,7 @@ bool tcg_exec_realizefn(CPUState *cpu, Error **errp)
assert(tcg_ops->cpu_exec_halt);
assert(tcg_ops->cpu_exec_interrupt);
assert(tcg_ops->cpu_exec_reset);
+ assert(tcg_ops->do_interrupt);
assert(tcg_ops->pointer_wrap);
#endif /* !CONFIG_USER_ONLY */
assert(tcg_ops->translate_code);
--
2.53.0
^ permalink raw reply related [flat|nested] 28+ messages in thread* Re: [PATCH v3 05/11] accel/tcg: Document do_interrupt() callback contract
2026-09-02 15:20 ` [PATCH v3 05/11] accel/tcg: Document do_interrupt() " Philippe Mathieu-Daudé
@ 2026-09-02 19:54 ` Pierrick Bouvier
2026-09-02 20:48 ` Philippe Mathieu-Daudé
2026-09-13 3:30 ` Richard Henderson
1 sibling, 1 reply; 28+ messages in thread
From: Pierrick Bouvier @ 2026-09-02 19:54 UTC (permalink / raw)
To: Philippe Mathieu-Daudé, qemu-devel
Cc: Mark Cave-Ayland, Peter Maydell, Paolo Bonzini, qemu-ppc,
qemu-s390x, Richard Henderson, qemu-riscv, qemu-arm
On 9/2/2026 8:20 AM, Philippe Mathieu-Daudé wrote:
> Expand docstring to clarify the handler is called with BQL held.
> Add assertion that this callback is mandatory and never NULL, since
> all targets must implement interrupt handling.
>
> Signed-off-by: Philippe Mathieu-Daudé <philmd@oss.qualcomm.com>
> ---
> include/accel/tcg/cpu-ops.h | 11 ++++++++++-
> accel/tcg/cpu-exec.c | 1 +
> 2 files changed, 11 insertions(+), 1 deletion(-)
>
> diff --git a/include/accel/tcg/cpu-ops.h b/include/accel/tcg/cpu-ops.h
> index 87850402203..13df70eaa9f 100644
> --- a/include/accel/tcg/cpu-ops.h
> +++ b/include/accel/tcg/cpu-ops.h
> @@ -169,7 +169,16 @@ struct TCGCPUOps {
> */
> vaddr (*untagged_addr)(CPUState *cs, vaddr addr);
> #else
> - /** @do_interrupt: Callback for interrupt handling. */
> + /**
> + * @do_interrupt: Deliver a pending exception/interrupt to the CPU
> + * @cpu: cpu context
> + *
> + * Called when cs->exception_index contains an exception code to deliver.
> + * Updates CPU architectural state (usually before executing a guest
> + * exception handler).
> + *
> + * Called from cpu_handle_exception() with BQL held.
Would that be clearer to ensure this with an assert instead or relying
on comment?
> + */
> void (*do_interrupt)(CPUState *cpu);
>
> /**
> diff --git a/accel/tcg/cpu-exec.c b/accel/tcg/cpu-exec.c
> index 609931a0d6e..2fae2c024b8 100644
> --- a/accel/tcg/cpu-exec.c
> +++ b/accel/tcg/cpu-exec.c
> @@ -1059,6 +1059,7 @@ bool tcg_exec_realizefn(CPUState *cpu, Error **errp)
> assert(tcg_ops->cpu_exec_halt);
> assert(tcg_ops->cpu_exec_interrupt);
> assert(tcg_ops->cpu_exec_reset);
> + assert(tcg_ops->do_interrupt);
> assert(tcg_ops->pointer_wrap);
> #endif /* !CONFIG_USER_ONLY */
> assert(tcg_ops->translate_code);
^ permalink raw reply [flat|nested] 28+ messages in thread* Re: [PATCH v3 05/11] accel/tcg: Document do_interrupt() callback contract
2026-09-02 19:54 ` Pierrick Bouvier
@ 2026-09-02 20:48 ` Philippe Mathieu-Daudé
0 siblings, 0 replies; 28+ messages in thread
From: Philippe Mathieu-Daudé @ 2026-09-02 20:48 UTC (permalink / raw)
To: Pierrick Bouvier, qemu-devel
Cc: Mark Cave-Ayland, Peter Maydell, Paolo Bonzini, qemu-ppc,
qemu-s390x, Richard Henderson, qemu-riscv, qemu-arm
On 2/9/26 21:54, Pierrick Bouvier wrote:
> On 9/2/2026 8:20 AM, Philippe Mathieu-Daudé wrote:
>> Expand docstring to clarify the handler is called with BQL held.
>> Add assertion that this callback is mandatory and never NULL, since
>> all targets must implement interrupt handling.
>>
>> Signed-off-by: Philippe Mathieu-Daudé <philmd@oss.qualcomm.com>
>> ---
>> include/accel/tcg/cpu-ops.h | 11 ++++++++++-
>> accel/tcg/cpu-exec.c | 1 +
>> 2 files changed, 11 insertions(+), 1 deletion(-)
>>
>> diff --git a/include/accel/tcg/cpu-ops.h b/include/accel/tcg/cpu-ops.h
>> index 87850402203..13df70eaa9f 100644
>> --- a/include/accel/tcg/cpu-ops.h
>> +++ b/include/accel/tcg/cpu-ops.h
>> @@ -169,7 +169,16 @@ struct TCGCPUOps {
>> */
>> vaddr (*untagged_addr)(CPUState *cs, vaddr addr);
>> #else
>> - /** @do_interrupt: Callback for interrupt handling. */
>> + /**
>> + * @do_interrupt: Deliver a pending exception/interrupt to the CPU
>> + * @cpu: cpu context
>> + *
>> + * Called when cs->exception_index contains an exception code to deliver.
>> + * Updates CPU architectural state (usually before executing a guest
>> + * exception handler).
>> + *
>> + * Called from cpu_handle_exception() with BQL held.
>
> Would that be clearer to ensure this with an assert instead or relying
> on comment?
This docstring contract is a help to implement callees.
>
>> + */
>> void (*do_interrupt)(CPUState *cpu);
>>
>> /**
>> diff --git a/accel/tcg/cpu-exec.c b/accel/tcg/cpu-exec.c
>> index 609931a0d6e..2fae2c024b8 100644
>> --- a/accel/tcg/cpu-exec.c
>> +++ b/accel/tcg/cpu-exec.c
>> @@ -1059,6 +1059,7 @@ bool tcg_exec_realizefn(CPUState *cpu, Error **errp)
>> assert(tcg_ops->cpu_exec_halt);
>> assert(tcg_ops->cpu_exec_interrupt);
>> assert(tcg_ops->cpu_exec_reset);
>> + assert(tcg_ops->do_interrupt);
>> assert(tcg_ops->pointer_wrap);
>> #endif /* !CONFIG_USER_ONLY */
>> assert(tcg_ops->translate_code);
>
>
^ permalink raw reply [flat|nested] 28+ messages in thread
* Re: [PATCH v3 05/11] accel/tcg: Document do_interrupt() callback contract
2026-09-02 15:20 ` [PATCH v3 05/11] accel/tcg: Document do_interrupt() " Philippe Mathieu-Daudé
2026-09-02 19:54 ` Pierrick Bouvier
@ 2026-09-13 3:30 ` Richard Henderson
1 sibling, 0 replies; 28+ messages in thread
From: Richard Henderson @ 2026-09-13 3:30 UTC (permalink / raw)
To: Philippe Mathieu-Daudé, qemu-devel
Cc: Mark Cave-Ayland, Peter Maydell, Paolo Bonzini, qemu-ppc,
qemu-s390x, Pierrick Bouvier, qemu-riscv, qemu-arm
On 9/2/26 05:20, Philippe Mathieu-Daudé wrote:
> Expand docstring to clarify the handler is called with BQL held.
> Add assertion that this callback is mandatory and never NULL, since
> all targets must implement interrupt handling.
>
> Signed-off-by: Philippe Mathieu-Daudé<philmd@oss.qualcomm.com>
> ---
> include/accel/tcg/cpu-ops.h | 11 ++++++++++-
> accel/tcg/cpu-exec.c | 1 +
> 2 files changed, 11 insertions(+), 1 deletion(-)
Reviewed-by: Richard Henderson <richard.henderson@linaro.org>
r~
^ permalink raw reply [flat|nested] 28+ messages in thread
* [PATCH v3 06/11] accel/tcg: Rename do_interrupt() to do_interrupt_locked()
2026-09-02 15:20 [PATCH v3 00/11] accel/tcg: Push BQL down into per-target do_interrupt handlers Philippe Mathieu-Daudé
` (3 preceding siblings ...)
2026-09-02 15:20 ` [PATCH v3 05/11] accel/tcg: Document do_interrupt() " Philippe Mathieu-Daudé
@ 2026-09-02 15:20 ` Philippe Mathieu-Daudé
2026-09-13 3:31 ` Richard Henderson
2026-09-02 15:20 ` [PATCH v3 07/11] accel/tcg: Add do_interrupt() wrapper for targets to manage BQL Philippe Mathieu-Daudé
` (6 subsequent siblings)
11 siblings, 1 reply; 28+ messages in thread
From: Philippe Mathieu-Daudé @ 2026-09-02 15:20 UTC (permalink / raw)
To: qemu-devel
Cc: Mark Cave-Ayland, Peter Maydell, Paolo Bonzini, qemu-ppc,
qemu-s390x, Richard Henderson, Pierrick Bouvier, qemu-riscv,
qemu-arm, Robert Foley, Philippe Mathieu-Daudé,
Michael Rolnik, Brian Cain, Helge Deller, Song Gao, Bibo Mao,
Xianglai Li, Laurent Vivier, Edgar E. Iglesias,
Philippe Mathieu-Daudé, Aurelien Jarno, Jiaxun Yang,
Aleksandar Rikalo, Stafford Horne, Chinmay Rath, Nicholas Piggin,
Glenn Miles, Harsh Prateek Bora, Palmer Dabbelt, Alistair Francis,
Weiwei Li, Daniel Henrique Barboza, Liu Zhiwei, Chao Liu,
Yoshinori Sato, Cornelia Huck, Eric Farman, Matthew Rosato,
Ilya Leoshkevich, David Hildenbrand, Artyom Tarasenko,
Max Filippov
From: Robert Foley <robert.foley@linaro.org>
Prepare for pushing BQL locking down to per-target implementations.
The old do_interrupt() name will later be reused for a wrapper that
acquires BQL and calls do_interrupt_locked(), enabling targets to
eventually remove BQL from the cpu_handle_interrupt/exception paths.
Suggested-by: Paolo Bonzini <pbonzini@redhat.com>
Signed-off-by: Robert Foley <robert.foley@linaro.org>
[PMD: Rebased and reworded description]
Signed-off-by: Philippe Mathieu-Daudé <philmd@oss.qualcomm.com>
---
include/accel/tcg/cpu-ops.h | 4 ++--
accel/tcg/cpu-exec.c | 4 ++--
target/alpha/cpu.c | 2 +-
target/arm/cpu.c | 2 +-
target/arm/tcg/cpu-v7m.c | 2 +-
target/avr/cpu.c | 2 +-
target/hexagon/cpu.c | 2 +-
target/hppa/cpu.c | 2 +-
target/i386/tcg/tcg-cpu.c | 2 +-
target/loongarch/tcg/tcg_cpu.c | 2 +-
target/m68k/cpu.c | 2 +-
target/microblaze/cpu.c | 2 +-
target/mips/cpu.c | 2 +-
target/or1k/cpu.c | 2 +-
target/ppc/cpu_init.c | 2 +-
target/riscv/tcg/tcg-cpu.c | 2 +-
target/rx/cpu.c | 2 +-
target/s390x/cpu.c | 2 +-
target/sh4/cpu.c | 2 +-
target/sparc/cpu.c | 2 +-
target/xtensa/cpu.c | 2 +-
21 files changed, 23 insertions(+), 23 deletions(-)
diff --git a/include/accel/tcg/cpu-ops.h b/include/accel/tcg/cpu-ops.h
index 13df70eaa9f..2e97f79a373 100644
--- a/include/accel/tcg/cpu-ops.h
+++ b/include/accel/tcg/cpu-ops.h
@@ -170,7 +170,7 @@ struct TCGCPUOps {
vaddr (*untagged_addr)(CPUState *cs, vaddr addr);
#else
/**
- * @do_interrupt: Deliver a pending exception/interrupt to the CPU
+ * @do_interrupt_locked: Deliver a pending exception/interrupt to the CPU
* @cpu: cpu context
*
* Called when cs->exception_index contains an exception code to deliver.
@@ -179,7 +179,7 @@ struct TCGCPUOps {
*
* Called from cpu_handle_exception() with BQL held.
*/
- void (*do_interrupt)(CPUState *cpu);
+ void (*do_interrupt_locked)(CPUState *cpu);
/**
* @cpu_exec_interrupt: Callback for processing target-specific interrupts
diff --git a/accel/tcg/cpu-exec.c b/accel/tcg/cpu-exec.c
index 2fae2c024b8..8d9c203f222 100644
--- a/accel/tcg/cpu-exec.c
+++ b/accel/tcg/cpu-exec.c
@@ -728,7 +728,7 @@ static inline bool cpu_handle_exception(CPUState *cpu, int *ret)
const TCGCPUOps *tcg_ops = cpu->cc->tcg_ops;
bql_lock();
- tcg_ops->do_interrupt(cpu);
+ tcg_ops->do_interrupt_locked(cpu);
bql_unlock();
cpu->exception_index = -1;
@@ -1059,7 +1059,7 @@ bool tcg_exec_realizefn(CPUState *cpu, Error **errp)
assert(tcg_ops->cpu_exec_halt);
assert(tcg_ops->cpu_exec_interrupt);
assert(tcg_ops->cpu_exec_reset);
- assert(tcg_ops->do_interrupt);
+ assert(tcg_ops->do_interrupt_locked);
assert(tcg_ops->pointer_wrap);
#endif /* !CONFIG_USER_ONLY */
assert(tcg_ops->translate_code);
diff --git a/target/alpha/cpu.c b/target/alpha/cpu.c
index 12e86021663..aca9e82bfb2 100644
--- a/target/alpha/cpu.c
+++ b/target/alpha/cpu.c
@@ -267,7 +267,7 @@ static const TCGCPUOps alpha_tcg_ops = {
.cpu_exec_interrupt = alpha_cpu_exec_interrupt,
.cpu_exec_halt = alpha_cpu_has_work,
.cpu_exec_reset = cpu_reset,
- .do_interrupt = alpha_cpu_do_interrupt,
+ .do_interrupt_locked = alpha_cpu_do_interrupt,
.do_transaction_failed = alpha_cpu_do_transaction_failed,
.do_unaligned_access = alpha_cpu_do_unaligned_access,
#endif /* !CONFIG_USER_ONLY */
diff --git a/target/arm/cpu.c b/target/arm/cpu.c
index 77aa78f00e2..0d0555b7ad4 100644
--- a/target/arm/cpu.c
+++ b/target/arm/cpu.c
@@ -2606,7 +2606,7 @@ static const TCGCPUOps arm_tcg_ops = {
.cpu_exec_interrupt = arm_cpu_exec_interrupt,
.cpu_exec_halt = arm_cpu_exec_halt,
.cpu_exec_reset = cpu_reset,
- .do_interrupt = arm_cpu_do_interrupt,
+ .do_interrupt_locked = arm_cpu_do_interrupt,
.do_transaction_failed = arm_cpu_do_transaction_failed,
.do_unaligned_access = arm_cpu_do_unaligned_access,
.adjust_watchpoint_address = arm_adjust_watchpoint_address,
diff --git a/target/arm/tcg/cpu-v7m.c b/target/arm/tcg/cpu-v7m.c
index 502998dbd1c..1f698b70283 100644
--- a/target/arm/tcg/cpu-v7m.c
+++ b/target/arm/tcg/cpu-v7m.c
@@ -304,7 +304,7 @@ static const TCGCPUOps arm_v7m_tcg_ops = {
.cpu_exec_interrupt = arm_v7m_cpu_exec_interrupt,
.cpu_exec_halt = arm_cpu_exec_halt,
.cpu_exec_reset = cpu_reset,
- .do_interrupt = arm_v7m_cpu_do_interrupt,
+ .do_interrupt_locked = arm_v7m_cpu_do_interrupt,
.do_transaction_failed = arm_cpu_do_transaction_failed,
.do_unaligned_access = arm_cpu_do_unaligned_access,
.adjust_watchpoint_address = arm_adjust_watchpoint_address,
diff --git a/target/avr/cpu.c b/target/avr/cpu.c
index f8409f32ab9..bc7639031b8 100644
--- a/target/avr/cpu.c
+++ b/target/avr/cpu.c
@@ -249,7 +249,7 @@ static const TCGCPUOps avr_tcg_ops = {
.cpu_exec_halt = avr_cpu_has_work,
.cpu_exec_reset = cpu_reset,
.tlb_fill = avr_cpu_tlb_fill,
- .do_interrupt = avr_cpu_do_interrupt,
+ .do_interrupt_locked = avr_cpu_do_interrupt,
/*
* TODO: code and data wrapping are different, but for the most part
* AVR only references bytes or aligned code fetches. But we use
diff --git a/target/hexagon/cpu.c b/target/hexagon/cpu.c
index 7067e5b70f7..b5dcbfc99db 100644
--- a/target/hexagon/cpu.c
+++ b/target/hexagon/cpu.c
@@ -769,7 +769,7 @@ static const TCGCPUOps hexagon_tcg_ops = {
.tlb_fill = hexagon_tlb_fill,
.do_unaligned_access = hexagon_cpu_do_unaligned_access,
.cpu_exec_halt = hexagon_cpu_has_work,
- .do_interrupt = hexagon_cpu_do_interrupt,
+ .do_interrupt_locked = hexagon_cpu_do_interrupt,
#endif /* !CONFIG_USER_ONLY */
};
diff --git a/target/hppa/cpu.c b/target/hppa/cpu.c
index 07b49e51326..c6d915d314f 100644
--- a/target/hppa/cpu.c
+++ b/target/hppa/cpu.c
@@ -272,7 +272,7 @@ static const TCGCPUOps hppa_tcg_ops = {
.cpu_exec_interrupt = hppa_cpu_exec_interrupt,
.cpu_exec_halt = hppa_cpu_has_work,
.cpu_exec_reset = cpu_reset,
- .do_interrupt = hppa_cpu_do_interrupt,
+ .do_interrupt_locked = hppa_cpu_do_interrupt,
.do_unaligned_access = hppa_cpu_do_unaligned_access,
.do_transaction_failed = hppa_cpu_do_transaction_failed,
#endif /* !CONFIG_USER_ONLY */
diff --git a/target/i386/tcg/tcg-cpu.c b/target/i386/tcg/tcg-cpu.c
index 7a4d73e7fee..ff65641654d 100644
--- a/target/i386/tcg/tcg-cpu.c
+++ b/target/i386/tcg/tcg-cpu.c
@@ -179,7 +179,7 @@ const TCGCPUOps x86_tcg_ops = {
#else
.tlb_fill = x86_cpu_tlb_fill,
.pointer_wrap = x86_pointer_wrap,
- .do_interrupt = x86_cpu_do_interrupt,
+ .do_interrupt_locked = x86_cpu_do_interrupt,
.cpu_exec_halt = x86_cpu_exec_halt,
.cpu_exec_interrupt = x86_cpu_exec_interrupt,
.cpu_exec_reset = x86_cpu_exec_reset,
diff --git a/target/loongarch/tcg/tcg_cpu.c b/target/loongarch/tcg/tcg_cpu.c
index 4b1d44a1644..6455ae0c99a 100644
--- a/target/loongarch/tcg/tcg_cpu.c
+++ b/target/loongarch/tcg/tcg_cpu.c
@@ -329,7 +329,7 @@ const TCGCPUOps loongarch_tcg_ops = {
.cpu_exec_interrupt = loongarch_cpu_exec_interrupt,
.cpu_exec_halt = loongarch_cpu_has_work,
.cpu_exec_reset = cpu_reset,
- .do_interrupt = loongarch_cpu_do_interrupt,
+ .do_interrupt_locked = loongarch_cpu_do_interrupt,
.do_transaction_failed = loongarch_cpu_do_transaction_failed,
#endif
};
diff --git a/target/m68k/cpu.c b/target/m68k/cpu.c
index 9b52ad5fc23..85496deff67 100644
--- a/target/m68k/cpu.c
+++ b/target/m68k/cpu.c
@@ -712,7 +712,7 @@ static const TCGCPUOps m68k_tcg_ops = {
.cpu_exec_interrupt = m68k_cpu_exec_interrupt,
.cpu_exec_halt = m68k_cpu_has_work,
.cpu_exec_reset = cpu_reset,
- .do_interrupt = m68k_cpu_do_interrupt,
+ .do_interrupt_locked = m68k_cpu_do_interrupt,
.do_transaction_failed = m68k_cpu_transaction_failed,
#endif /* !CONFIG_USER_ONLY */
};
diff --git a/target/microblaze/cpu.c b/target/microblaze/cpu.c
index 389a5124b12..649bcebf703 100644
--- a/target/microblaze/cpu.c
+++ b/target/microblaze/cpu.c
@@ -450,7 +450,7 @@ static const TCGCPUOps mb_tcg_ops = {
.cpu_exec_interrupt = mb_cpu_exec_interrupt,
.cpu_exec_halt = mb_cpu_has_work,
.cpu_exec_reset = cpu_reset,
- .do_interrupt = mb_cpu_do_interrupt,
+ .do_interrupt_locked = mb_cpu_do_interrupt,
.do_transaction_failed = mb_cpu_transaction_failed,
.do_unaligned_access = mb_cpu_do_unaligned_access,
#endif /* !CONFIG_USER_ONLY */
diff --git a/target/mips/cpu.c b/target/mips/cpu.c
index 0fead20d651..073e466b713 100644
--- a/target/mips/cpu.c
+++ b/target/mips/cpu.c
@@ -718,7 +718,7 @@ static const TCGCPUOps mips_tcg_ops = {
.cpu_exec_interrupt = mips_cpu_exec_interrupt,
.cpu_exec_halt = mips_cpu_has_work,
.cpu_exec_reset = cpu_reset,
- .do_interrupt = mips_cpu_do_interrupt,
+ .do_interrupt_locked = mips_cpu_do_interrupt,
.do_transaction_failed = mips_cpu_do_transaction_failed,
.do_unaligned_access = mips_cpu_do_unaligned_access,
.io_recompile_replay_branch = mips_io_recompile_replay_branch,
diff --git a/target/or1k/cpu.c b/target/or1k/cpu.c
index 66c00c0930c..83dc071c180 100644
--- a/target/or1k/cpu.c
+++ b/target/or1k/cpu.c
@@ -268,7 +268,7 @@ static const TCGCPUOps openrisc_tcg_ops = {
.cpu_exec_interrupt = openrisc_cpu_exec_interrupt,
.cpu_exec_halt = openrisc_cpu_has_work,
.cpu_exec_reset = cpu_reset,
- .do_interrupt = openrisc_cpu_do_interrupt,
+ .do_interrupt_locked = openrisc_cpu_do_interrupt,
#endif /* !CONFIG_USER_ONLY */
};
diff --git a/target/ppc/cpu_init.c b/target/ppc/cpu_init.c
index 6c626843c93..2676562b2f1 100644
--- a/target/ppc/cpu_init.c
+++ b/target/ppc/cpu_init.c
@@ -7498,7 +7498,7 @@ static const TCGCPUOps ppc_tcg_ops = {
.cpu_exec_interrupt = ppc_cpu_exec_interrupt,
.cpu_exec_halt = ppc_cpu_has_work,
.cpu_exec_reset = cpu_reset,
- .do_interrupt = ppc_cpu_do_interrupt,
+ .do_interrupt_locked = ppc_cpu_do_interrupt,
.cpu_exec_enter = ppc_cpu_exec_enter,
.cpu_exec_exit = ppc_cpu_exec_exit,
.do_unaligned_access = ppc_cpu_do_unaligned_access,
diff --git a/target/riscv/tcg/tcg-cpu.c b/target/riscv/tcg/tcg-cpu.c
index 9e3cc87f8a3..ea3189ab3d2 100644
--- a/target/riscv/tcg/tcg-cpu.c
+++ b/target/riscv/tcg/tcg-cpu.c
@@ -289,7 +289,7 @@ const TCGCPUOps riscv_tcg_ops = {
.cpu_exec_interrupt = riscv_cpu_exec_interrupt,
.cpu_exec_halt = riscv_cpu_has_work,
.cpu_exec_reset = cpu_reset,
- .do_interrupt = riscv_cpu_do_interrupt,
+ .do_interrupt_locked = riscv_cpu_do_interrupt,
.do_transaction_failed = riscv_cpu_do_transaction_failed,
.do_unaligned_access = riscv_cpu_do_unaligned_access,
.debug_excp_handler = riscv_cpu_debug_excp_handler,
diff --git a/target/rx/cpu.c b/target/rx/cpu.c
index 9b8473d71cf..ea58a804154 100644
--- a/target/rx/cpu.c
+++ b/target/rx/cpu.c
@@ -229,7 +229,7 @@ static const TCGCPUOps rx_tcg_ops = {
.cpu_exec_interrupt = rx_cpu_exec_interrupt,
.cpu_exec_halt = rx_cpu_has_work,
.cpu_exec_reset = cpu_reset,
- .do_interrupt = rx_cpu_do_interrupt,
+ .do_interrupt_locked = rx_cpu_do_interrupt,
};
static void rx_cpu_class_init(ObjectClass *klass, const void *data)
diff --git a/target/s390x/cpu.c b/target/s390x/cpu.c
index 7c725b8a4a4..053eafaa842 100644
--- a/target/s390x/cpu.c
+++ b/target/s390x/cpu.c
@@ -386,7 +386,7 @@ static const TCGCPUOps s390_tcg_ops = {
.cpu_exec_interrupt = s390_cpu_exec_interrupt,
.cpu_exec_halt = s390_cpu_has_work,
.cpu_exec_reset = cpu_reset,
- .do_interrupt = s390_cpu_do_interrupt,
+ .do_interrupt_locked = s390_cpu_do_interrupt,
.debug_excp_handler = s390x_cpu_debug_excp_handler,
.do_unaligned_access = s390x_cpu_do_unaligned_access,
#endif /* !CONFIG_USER_ONLY */
diff --git a/target/sh4/cpu.c b/target/sh4/cpu.c
index 3bbdee301d5..fdab5106b27 100644
--- a/target/sh4/cpu.c
+++ b/target/sh4/cpu.c
@@ -314,7 +314,7 @@ static const TCGCPUOps superh_tcg_ops = {
.cpu_exec_interrupt = superh_cpu_exec_interrupt,
.cpu_exec_halt = superh_cpu_has_work,
.cpu_exec_reset = cpu_reset,
- .do_interrupt = superh_cpu_do_interrupt,
+ .do_interrupt_locked = superh_cpu_do_interrupt,
.do_unaligned_access = superh_cpu_do_unaligned_access,
.io_recompile_replay_branch = superh_io_recompile_replay_branch,
#endif /* !CONFIG_USER_ONLY */
diff --git a/target/sparc/cpu.c b/target/sparc/cpu.c
index ae9bdca9df8..23fd0a5e3fe 100644
--- a/target/sparc/cpu.c
+++ b/target/sparc/cpu.c
@@ -1076,7 +1076,7 @@ static const TCGCPUOps sparc_tcg_ops = {
.cpu_exec_interrupt = sparc_cpu_exec_interrupt,
.cpu_exec_halt = sparc_cpu_has_work,
.cpu_exec_reset = cpu_reset,
- .do_interrupt = sparc_cpu_do_interrupt,
+ .do_interrupt_locked = sparc_cpu_do_interrupt,
.do_transaction_failed = sparc_cpu_do_transaction_failed,
.do_unaligned_access = sparc_cpu_do_unaligned_access,
#endif /* !CONFIG_USER_ONLY */
diff --git a/target/xtensa/cpu.c b/target/xtensa/cpu.c
index 7c25b9ab707..e980a13eadd 100644
--- a/target/xtensa/cpu.c
+++ b/target/xtensa/cpu.c
@@ -327,7 +327,7 @@ static const TCGCPUOps xtensa_tcg_ops = {
.cpu_exec_interrupt = xtensa_cpu_exec_interrupt,
.cpu_exec_halt = xtensa_cpu_has_work,
.cpu_exec_reset = cpu_reset,
- .do_interrupt = xtensa_cpu_do_interrupt,
+ .do_interrupt_locked = xtensa_cpu_do_interrupt,
.do_transaction_failed = xtensa_cpu_do_transaction_failed,
.do_unaligned_access = xtensa_cpu_do_unaligned_access,
.debug_check_breakpoint = xtensa_debug_check_breakpoint,
--
2.53.0
^ permalink raw reply related [flat|nested] 28+ messages in thread* Re: [PATCH v3 06/11] accel/tcg: Rename do_interrupt() to do_interrupt_locked()
2026-09-02 15:20 ` [PATCH v3 06/11] accel/tcg: Rename do_interrupt() to do_interrupt_locked() Philippe Mathieu-Daudé
@ 2026-09-13 3:31 ` Richard Henderson
0 siblings, 0 replies; 28+ messages in thread
From: Richard Henderson @ 2026-09-13 3:31 UTC (permalink / raw)
To: Philippe Mathieu-Daudé, qemu-devel
On 9/2/26 05:20, Philippe Mathieu-Daudé wrote:
> From: Robert Foley<robert.foley@linaro.org>
>
> Prepare for pushing BQL locking down to per-target implementations.
> The old do_interrupt() name will later be reused for a wrapper that
> acquires BQL and calls do_interrupt_locked(), enabling targets to
> eventually remove BQL from the cpu_handle_interrupt/exception paths.
>
> Suggested-by: Paolo Bonzini<pbonzini@redhat.com>
> Signed-off-by: Robert Foley<robert.foley@linaro.org>
> [PMD: Rebased and reworded description]
> Signed-off-by: Philippe Mathieu-Daudé<philmd@oss.qualcomm.com>
> ---
Reviewed-by: Richard Henderson <richard.henderson@linaro.org>
r~
^ permalink raw reply [flat|nested] 28+ messages in thread
* [PATCH v3 07/11] accel/tcg: Add do_interrupt() wrapper for targets to manage BQL
2026-09-02 15:20 [PATCH v3 00/11] accel/tcg: Push BQL down into per-target do_interrupt handlers Philippe Mathieu-Daudé
` (4 preceding siblings ...)
2026-09-02 15:20 ` [PATCH v3 06/11] accel/tcg: Rename do_interrupt() to do_interrupt_locked() Philippe Mathieu-Daudé
@ 2026-09-02 15:20 ` Philippe Mathieu-Daudé
2026-09-13 3:50 ` Richard Henderson
2026-09-02 15:20 ` [PATCH v3 08/11] target/hexagon: Move to do_interrupt() (BQL acquired internally) Philippe Mathieu-Daudé
` (5 subsequent siblings)
11 siblings, 1 reply; 28+ messages in thread
From: Philippe Mathieu-Daudé @ 2026-09-02 15:20 UTC (permalink / raw)
To: qemu-devel
Cc: Mark Cave-Ayland, Peter Maydell, Paolo Bonzini, qemu-ppc,
qemu-s390x, Richard Henderson, Pierrick Bouvier, qemu-riscv,
qemu-arm, Philippe Mathieu-Daudé
Add TCGCPUOps::do_interrupt() as a wrapper that targets can
implement to control BQL locking independently. The existing
do_interrupt_locked() callback remains for BQL-held contexts.
This allows each target to decide when to acquire the BQL.
Signed-off-by: Philippe Mathieu-Daudé <philmd@oss.qualcomm.com>
---
include/accel/tcg/cpu-ops.h | 14 ++++++++++++++
accel/tcg/cpu-exec.c | 12 ++++++++----
2 files changed, 22 insertions(+), 4 deletions(-)
diff --git a/include/accel/tcg/cpu-ops.h b/include/accel/tcg/cpu-ops.h
index 2e97f79a373..e2e67f796f6 100644
--- a/include/accel/tcg/cpu-ops.h
+++ b/include/accel/tcg/cpu-ops.h
@@ -169,6 +169,20 @@ struct TCGCPUOps {
*/
vaddr (*untagged_addr)(CPUState *cs, vaddr addr);
#else
+ /**
+ * @do_interrupt: Deliver a pending exception/interrupt to the CPU
+ *
+ * Called when cs->exception_index contains the exception code to deliver.
+ * Updates CPU architectural state (usually before executing a guest
+ * exception handler).
+ *
+ * Called from cpu_handle_exception(). Implementations must acquire the
+ * BQL before modifying CPU state and hold it for the duration of the
+ * handler (this ensures safe access to shared CPU and device state during
+ * exception delivery, which may be cross-vCPU).
+ */
+ void (*do_interrupt)(CPUState *cpu);
+
/**
* @do_interrupt_locked: Deliver a pending exception/interrupt to the CPU
* @cpu: cpu context
diff --git a/accel/tcg/cpu-exec.c b/accel/tcg/cpu-exec.c
index 8d9c203f222..4deb7e00571 100644
--- a/accel/tcg/cpu-exec.c
+++ b/accel/tcg/cpu-exec.c
@@ -727,9 +727,13 @@ static inline bool cpu_handle_exception(CPUState *cpu, int *ret)
if (replay_exception()) {
const TCGCPUOps *tcg_ops = cpu->cc->tcg_ops;
- bql_lock();
- tcg_ops->do_interrupt_locked(cpu);
- bql_unlock();
+ if (tcg_ops->do_interrupt) {
+ tcg_ops->do_interrupt(cpu);
+ } else {
+ bql_lock();
+ tcg_ops->do_interrupt_locked(cpu);
+ bql_unlock();
+ }
cpu->exception_index = -1;
if (unlikely(cpu_single_stepping(cpu))) {
@@ -1059,7 +1063,7 @@ bool tcg_exec_realizefn(CPUState *cpu, Error **errp)
assert(tcg_ops->cpu_exec_halt);
assert(tcg_ops->cpu_exec_interrupt);
assert(tcg_ops->cpu_exec_reset);
- assert(tcg_ops->do_interrupt_locked);
+ assert(tcg_ops->do_interrupt || tcg_ops->do_interrupt_locked);
assert(tcg_ops->pointer_wrap);
#endif /* !CONFIG_USER_ONLY */
assert(tcg_ops->translate_code);
--
2.53.0
^ permalink raw reply related [flat|nested] 28+ messages in thread* Re: [PATCH v3 07/11] accel/tcg: Add do_interrupt() wrapper for targets to manage BQL
2026-09-02 15:20 ` [PATCH v3 07/11] accel/tcg: Add do_interrupt() wrapper for targets to manage BQL Philippe Mathieu-Daudé
@ 2026-09-13 3:50 ` Richard Henderson
0 siblings, 0 replies; 28+ messages in thread
From: Richard Henderson @ 2026-09-13 3:50 UTC (permalink / raw)
To: Philippe Mathieu-Daudé, qemu-devel
Cc: Mark Cave-Ayland, Peter Maydell, Paolo Bonzini, qemu-ppc,
qemu-s390x, Pierrick Bouvier, qemu-riscv, qemu-arm
On 9/2/26 05:20, Philippe Mathieu-Daudé wrote:
> Add TCGCPUOps::do_interrupt() as a wrapper that targets can
> implement to control BQL locking independently. The existing
> do_interrupt_locked() callback remains for BQL-held contexts.
> This allows each target to decide when to acquire the BQL.
>
> Signed-off-by: Philippe Mathieu-Daudé<philmd@oss.qualcomm.com>
> ---
> include/accel/tcg/cpu-ops.h | 14 ++++++++++++++
> accel/tcg/cpu-exec.c | 12 ++++++++----
> 2 files changed, 22 insertions(+), 4 deletions(-)
Reviewed-by: Richard Henderson <richard.henderson@linaro.org>
r~
^ permalink raw reply [flat|nested] 28+ messages in thread
* [PATCH v3 08/11] target/hexagon: Move to do_interrupt() (BQL acquired internally)
2026-09-02 15:20 [PATCH v3 00/11] accel/tcg: Push BQL down into per-target do_interrupt handlers Philippe Mathieu-Daudé
` (5 preceding siblings ...)
2026-09-02 15:20 ` [PATCH v3 07/11] accel/tcg: Add do_interrupt() wrapper for targets to manage BQL Philippe Mathieu-Daudé
@ 2026-09-02 15:20 ` Philippe Mathieu-Daudé
2026-09-03 0:15 ` Brian Cain
2026-09-13 3:55 ` Richard Henderson
2026-09-02 15:20 ` [RFC PATCH v3 09/11] targets: Move interrupt handlers to do_interrupt() Philippe Mathieu-Daudé
` (4 subsequent siblings)
11 siblings, 2 replies; 28+ messages in thread
From: Philippe Mathieu-Daudé @ 2026-09-02 15:20 UTC (permalink / raw)
To: qemu-devel
Cc: Mark Cave-Ayland, Peter Maydell, Paolo Bonzini, qemu-ppc,
qemu-s390x, Richard Henderson, Pierrick Bouvier, qemu-riscv,
qemu-arm, Philippe Mathieu-Daudé, Brian Cain
hexagon_cpu_do_interrupt() already acquires the BQL internally,
so register it as do_interrupt() instead of do_interrupt_locked().
This reflects the actual locking model used by the target.
Signed-off-by: Philippe Mathieu-Daudé <philmd@oss.qualcomm.com>
---
target/hexagon/cpu.c | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/target/hexagon/cpu.c b/target/hexagon/cpu.c
index b5dcbfc99db..7067e5b70f7 100644
--- a/target/hexagon/cpu.c
+++ b/target/hexagon/cpu.c
@@ -769,7 +769,7 @@ static const TCGCPUOps hexagon_tcg_ops = {
.tlb_fill = hexagon_tlb_fill,
.do_unaligned_access = hexagon_cpu_do_unaligned_access,
.cpu_exec_halt = hexagon_cpu_has_work,
- .do_interrupt_locked = hexagon_cpu_do_interrupt,
+ .do_interrupt = hexagon_cpu_do_interrupt,
#endif /* !CONFIG_USER_ONLY */
};
--
2.53.0
^ permalink raw reply related [flat|nested] 28+ messages in thread* Re: [PATCH v3 08/11] target/hexagon: Move to do_interrupt() (BQL acquired internally)
2026-09-02 15:20 ` [PATCH v3 08/11] target/hexagon: Move to do_interrupt() (BQL acquired internally) Philippe Mathieu-Daudé
@ 2026-09-03 0:15 ` Brian Cain
2026-09-13 3:55 ` Richard Henderson
1 sibling, 0 replies; 28+ messages in thread
From: Brian Cain @ 2026-09-03 0:15 UTC (permalink / raw)
To: Philippe Mathieu-Daudé, qemu-devel
Cc: Mark Cave-Ayland, Peter Maydell, Paolo Bonzini, qemu-ppc,
qemu-s390x, Richard Henderson, Pierrick Bouvier, qemu-riscv,
qemu-arm
On 9/2/2026 10:20 AM, Philippe Mathieu-Daudé wrote:
> hexagon_cpu_do_interrupt() already acquires the BQL internally,
> so register it as do_interrupt() instead of do_interrupt_locked().
> This reflects the actual locking model used by the target.
>
> Signed-off-by: Philippe Mathieu-Daudé <philmd@oss.qualcomm.com>
Reviewed-by: Brian Cain <brian.cain@oss.qualcomm.com>
> ---
> target/hexagon/cpu.c | 2 +-
> 1 file changed, 1 insertion(+), 1 deletion(-)
>
> diff --git a/target/hexagon/cpu.c b/target/hexagon/cpu.c
> index b5dcbfc99db..7067e5b70f7 100644
> --- a/target/hexagon/cpu.c
> +++ b/target/hexagon/cpu.c
> @@ -769,7 +769,7 @@ static const TCGCPUOps hexagon_tcg_ops = {
> .tlb_fill = hexagon_tlb_fill,
> .do_unaligned_access = hexagon_cpu_do_unaligned_access,
> .cpu_exec_halt = hexagon_cpu_has_work,
> - .do_interrupt_locked = hexagon_cpu_do_interrupt,
> + .do_interrupt = hexagon_cpu_do_interrupt,
> #endif /* !CONFIG_USER_ONLY */
> };
>
^ permalink raw reply [flat|nested] 28+ messages in thread* Re: [PATCH v3 08/11] target/hexagon: Move to do_interrupt() (BQL acquired internally)
2026-09-02 15:20 ` [PATCH v3 08/11] target/hexagon: Move to do_interrupt() (BQL acquired internally) Philippe Mathieu-Daudé
2026-09-03 0:15 ` Brian Cain
@ 2026-09-13 3:55 ` Richard Henderson
1 sibling, 0 replies; 28+ messages in thread
From: Richard Henderson @ 2026-09-13 3:55 UTC (permalink / raw)
To: Philippe Mathieu-Daudé, qemu-devel
Cc: Mark Cave-Ayland, Peter Maydell, Paolo Bonzini, qemu-ppc,
qemu-s390x, Pierrick Bouvier, qemu-riscv, qemu-arm, Brian Cain
On 9/2/26 05:20, Philippe Mathieu-Daudé wrote:
> hexagon_cpu_do_interrupt() already acquires the BQL internally,
> so register it as do_interrupt() instead of do_interrupt_locked().
> This reflects the actual locking model used by the target.
>
> Signed-off-by: Philippe Mathieu-Daudé <philmd@oss.qualcomm.com>
> ---
> target/hexagon/cpu.c | 2 +-
> 1 file changed, 1 insertion(+), 1 deletion(-)
>
> diff --git a/target/hexagon/cpu.c b/target/hexagon/cpu.c
> index b5dcbfc99db..7067e5b70f7 100644
> --- a/target/hexagon/cpu.c
> +++ b/target/hexagon/cpu.c
> @@ -769,7 +769,7 @@ static const TCGCPUOps hexagon_tcg_ops = {
> .tlb_fill = hexagon_tlb_fill,
> .do_unaligned_access = hexagon_cpu_do_unaligned_access,
> .cpu_exec_halt = hexagon_cpu_has_work,
> - .do_interrupt_locked = hexagon_cpu_do_interrupt,
> + .do_interrupt = hexagon_cpu_do_interrupt,
> #endif /* !CONFIG_USER_ONLY */
> };
>
Eh. Except all that hexagon does is acquire the lock at the beginning
of the function and keep it for the entire duration. I think hexagon
should stay using _locked and *not* do internal locking.
r~
^ permalink raw reply [flat|nested] 28+ messages in thread
* [RFC PATCH v3 09/11] targets: Move interrupt handlers to do_interrupt()
2026-09-02 15:20 [PATCH v3 00/11] accel/tcg: Push BQL down into per-target do_interrupt handlers Philippe Mathieu-Daudé
` (6 preceding siblings ...)
2026-09-02 15:20 ` [PATCH v3 08/11] target/hexagon: Move to do_interrupt() (BQL acquired internally) Philippe Mathieu-Daudé
@ 2026-09-02 15:20 ` Philippe Mathieu-Daudé
2026-09-13 4:00 ` Richard Henderson
2026-09-02 15:20 ` [RFC PATCH v3 10/11] targets: Move BQL locking into do_interrupt() handlers Philippe Mathieu-Daudé
` (3 subsequent siblings)
11 siblings, 1 reply; 28+ messages in thread
From: Philippe Mathieu-Daudé @ 2026-09-02 15:20 UTC (permalink / raw)
To: qemu-devel
Cc: Mark Cave-Ayland, Peter Maydell, Paolo Bonzini, qemu-ppc,
qemu-s390x, Richard Henderson, Pierrick Bouvier, qemu-riscv,
qemu-arm, Philippe Mathieu-Daudé, Song Gao, Bibo Mao,
Xianglai Li, Laurent Vivier, Edgar E. Iglesias, Stafford Horne
LoongArch, M68K, MicroBlaze, and OpenRISC interrupt handlers
don't require external BQL protection, so move them from
do_interrupt_locked() to do_interrupt().
Signed-off-by: Philippe Mathieu-Daudé <philmd@oss.qualcomm.com>
---
target/loongarch/tcg/tcg_cpu.c | 2 +-
target/m68k/cpu.c | 2 +-
target/microblaze/cpu.c | 2 +-
target/or1k/cpu.c | 2 +-
4 files changed, 4 insertions(+), 4 deletions(-)
diff --git a/target/loongarch/tcg/tcg_cpu.c b/target/loongarch/tcg/tcg_cpu.c
index 6455ae0c99a..4b1d44a1644 100644
--- a/target/loongarch/tcg/tcg_cpu.c
+++ b/target/loongarch/tcg/tcg_cpu.c
@@ -329,7 +329,7 @@ const TCGCPUOps loongarch_tcg_ops = {
.cpu_exec_interrupt = loongarch_cpu_exec_interrupt,
.cpu_exec_halt = loongarch_cpu_has_work,
.cpu_exec_reset = cpu_reset,
- .do_interrupt_locked = loongarch_cpu_do_interrupt,
+ .do_interrupt = loongarch_cpu_do_interrupt,
.do_transaction_failed = loongarch_cpu_do_transaction_failed,
#endif
};
diff --git a/target/m68k/cpu.c b/target/m68k/cpu.c
index 85496deff67..9b52ad5fc23 100644
--- a/target/m68k/cpu.c
+++ b/target/m68k/cpu.c
@@ -712,7 +712,7 @@ static const TCGCPUOps m68k_tcg_ops = {
.cpu_exec_interrupt = m68k_cpu_exec_interrupt,
.cpu_exec_halt = m68k_cpu_has_work,
.cpu_exec_reset = cpu_reset,
- .do_interrupt_locked = m68k_cpu_do_interrupt,
+ .do_interrupt = m68k_cpu_do_interrupt,
.do_transaction_failed = m68k_cpu_transaction_failed,
#endif /* !CONFIG_USER_ONLY */
};
diff --git a/target/microblaze/cpu.c b/target/microblaze/cpu.c
index 649bcebf703..389a5124b12 100644
--- a/target/microblaze/cpu.c
+++ b/target/microblaze/cpu.c
@@ -450,7 +450,7 @@ static const TCGCPUOps mb_tcg_ops = {
.cpu_exec_interrupt = mb_cpu_exec_interrupt,
.cpu_exec_halt = mb_cpu_has_work,
.cpu_exec_reset = cpu_reset,
- .do_interrupt_locked = mb_cpu_do_interrupt,
+ .do_interrupt = mb_cpu_do_interrupt,
.do_transaction_failed = mb_cpu_transaction_failed,
.do_unaligned_access = mb_cpu_do_unaligned_access,
#endif /* !CONFIG_USER_ONLY */
diff --git a/target/or1k/cpu.c b/target/or1k/cpu.c
index 83dc071c180..66c00c0930c 100644
--- a/target/or1k/cpu.c
+++ b/target/or1k/cpu.c
@@ -268,7 +268,7 @@ static const TCGCPUOps openrisc_tcg_ops = {
.cpu_exec_interrupt = openrisc_cpu_exec_interrupt,
.cpu_exec_halt = openrisc_cpu_has_work,
.cpu_exec_reset = cpu_reset,
- .do_interrupt_locked = openrisc_cpu_do_interrupt,
+ .do_interrupt = openrisc_cpu_do_interrupt,
#endif /* !CONFIG_USER_ONLY */
};
--
2.53.0
^ permalink raw reply related [flat|nested] 28+ messages in thread* Re: [RFC PATCH v3 09/11] targets: Move interrupt handlers to do_interrupt()
2026-09-02 15:20 ` [RFC PATCH v3 09/11] targets: Move interrupt handlers to do_interrupt() Philippe Mathieu-Daudé
@ 2026-09-13 4:00 ` Richard Henderson
0 siblings, 0 replies; 28+ messages in thread
From: Richard Henderson @ 2026-09-13 4:00 UTC (permalink / raw)
To: Philippe Mathieu-Daudé, qemu-devel
On 9/2/26 05:20, Philippe Mathieu-Daudé wrote:
> LoongArch, M68K, MicroBlaze, and OpenRISC interrupt handlers
> don't require external BQL protection, so move them from
> do_interrupt_locked() to do_interrupt().
>
> Signed-off-by: Philippe Mathieu-Daudé <philmd@oss.qualcomm.com>
> ---
> target/loongarch/tcg/tcg_cpu.c | 2 +-
> target/m68k/cpu.c | 2 +-
> target/microblaze/cpu.c | 2 +-
> target/or1k/cpu.c | 2 +-
> 4 files changed, 4 insertions(+), 4 deletions(-)
How did you determine that these do not require locking?
E.g. why does alpha require locking when loongarch does not?
r~
^ permalink raw reply [flat|nested] 28+ messages in thread
* [RFC PATCH v3 10/11] targets: Move BQL locking into do_interrupt() handlers
2026-09-02 15:20 [PATCH v3 00/11] accel/tcg: Push BQL down into per-target do_interrupt handlers Philippe Mathieu-Daudé
` (7 preceding siblings ...)
2026-09-02 15:20 ` [RFC PATCH v3 09/11] targets: Move interrupt handlers to do_interrupt() Philippe Mathieu-Daudé
@ 2026-09-02 15:20 ` Philippe Mathieu-Daudé
2026-09-02 15:20 ` [PATCH v3 11/11] accel/tcg: Remove do_interrupt_locked() callback Philippe Mathieu-Daudé
` (2 subsequent siblings)
11 siblings, 0 replies; 28+ messages in thread
From: Philippe Mathieu-Daudé @ 2026-09-02 15:20 UTC (permalink / raw)
To: qemu-devel
Cc: Mark Cave-Ayland, Peter Maydell, Paolo Bonzini, qemu-ppc,
qemu-s390x, Richard Henderson, Pierrick Bouvier, qemu-riscv,
qemu-arm, Philippe Mathieu-Daudé, Michael Rolnik,
Helge Deller, Philippe Mathieu-Daudé, Aurelien Jarno,
Jiaxun Yang, Aleksandar Rikalo, Chinmay Rath, Nicholas Piggin,
Glenn Miles, Harsh Prateek Bora, Palmer Dabbelt, Alistair Francis,
Weiwei Li, Daniel Henrique Barboza, Liu Zhiwei, Chao Liu,
Yoshinori Sato, Ilya Leoshkevich, David Hildenbrand,
Cornelia Huck, Eric Farman, Matthew Rosato, Artyom Tarasenko,
Max Filippov
Migrate 13 targets to acquire the BQL explicitly within their
do_interrupt() implementations instead of relying on the TCG core
to hold it. This allows per-target control over locking granularity
and paves the way for fine-grained BQL optimization.
Signed-off-by: Philippe Mathieu-Daudé <philmd@oss.qualcomm.com>
---
target/alpha/cpu.c | 2 +-
target/alpha/helper.c | 3 +++
target/arm/cpu.c | 2 +-
target/arm/helper.c | 1 +
target/arm/tcg/cpu-v7m.c | 2 +-
target/arm/tcg/m_helper.c | 2 ++
target/avr/cpu.c | 2 +-
target/avr/helper.c | 3 +++
target/hppa/cpu.c | 2 +-
target/hppa/int_helper.c | 2 ++
target/i386/tcg/system/seg_helper.c | 2 ++
target/i386/tcg/tcg-cpu.c | 2 +-
target/mips/cpu.c | 2 +-
target/mips/tcg/system/tlb_helper.c | 3 +++
target/ppc/cpu_init.c | 2 +-
target/ppc/excp_helper.c | 2 ++
target/riscv/tcg/tcg-cpu.c | 2 +-
target/rx/cpu.c | 2 +-
target/rx/helper.c | 3 +++
target/s390x/cpu.c | 2 +-
target/s390x/tcg/excp_helper.c | 3 +++
target/sh4/cpu.c | 2 +-
target/sh4/helper.c | 3 +++
target/sparc/cpu.c | 2 +-
target/sparc/int32_helper.c | 2 ++
target/sparc/int64_helper.c | 2 ++
target/xtensa/cpu.c | 2 +-
target/xtensa/exc_helper.c | 2 ++
28 files changed, 47 insertions(+), 14 deletions(-)
diff --git a/target/alpha/cpu.c b/target/alpha/cpu.c
index aca9e82bfb2..12e86021663 100644
--- a/target/alpha/cpu.c
+++ b/target/alpha/cpu.c
@@ -267,7 +267,7 @@ static const TCGCPUOps alpha_tcg_ops = {
.cpu_exec_interrupt = alpha_cpu_exec_interrupt,
.cpu_exec_halt = alpha_cpu_has_work,
.cpu_exec_reset = cpu_reset,
- .do_interrupt_locked = alpha_cpu_do_interrupt,
+ .do_interrupt = alpha_cpu_do_interrupt,
.do_transaction_failed = alpha_cpu_do_transaction_failed,
.do_unaligned_access = alpha_cpu_do_unaligned_access,
#endif /* !CONFIG_USER_ONLY */
diff --git a/target/alpha/helper.c b/target/alpha/helper.c
index c3614ecafda..e21cd8e2b44 100644
--- a/target/alpha/helper.c
+++ b/target/alpha/helper.c
@@ -26,6 +26,7 @@
#include "fpu/softfloat-types.h"
#include "fpu/softfloat-helpers.h"
#include "exec/helper-proto.h"
+#include "qemu/main-loop.h"
#include "qemu/qemu-print.h"
#include "system/memory.h"
#include "accel/tcg/cpu-loop.h"
@@ -341,6 +342,8 @@ void alpha_cpu_do_interrupt(CPUState *cs)
int i = cs->exception_index;
uint64_t last_pc = env->pc;
+ BQL_LOCK_GUARD();
+
if (qemu_loglevel_mask(CPU_LOG_INT)) {
static int count;
const char *name = "<unknown>";
diff --git a/target/arm/cpu.c b/target/arm/cpu.c
index 0d0555b7ad4..77aa78f00e2 100644
--- a/target/arm/cpu.c
+++ b/target/arm/cpu.c
@@ -2606,7 +2606,7 @@ static const TCGCPUOps arm_tcg_ops = {
.cpu_exec_interrupt = arm_cpu_exec_interrupt,
.cpu_exec_halt = arm_cpu_exec_halt,
.cpu_exec_reset = cpu_reset,
- .do_interrupt_locked = arm_cpu_do_interrupt,
+ .do_interrupt = arm_cpu_do_interrupt,
.do_transaction_failed = arm_cpu_do_transaction_failed,
.do_unaligned_access = arm_cpu_do_unaligned_access,
.adjust_watchpoint_address = arm_adjust_watchpoint_address,
diff --git a/target/arm/helper.c b/target/arm/helper.c
index c3f607e6d6b..fbedb3fa39c 100644
--- a/target/arm/helper.c
+++ b/target/arm/helper.c
@@ -9714,6 +9714,7 @@ void arm_cpu_do_interrupt(CPUState *cs)
uint64_t last_pc = cs->cc->get_pc(cs);
assert(!arm_feature(env, ARM_FEATURE_M));
+ BQL_LOCK_GUARD();
arm_log_exception(cs);
qemu_log_mask(CPU_LOG_INT, "...from EL%d to EL%d\n", arm_current_el(env),
diff --git a/target/arm/tcg/cpu-v7m.c b/target/arm/tcg/cpu-v7m.c
index 1f698b70283..502998dbd1c 100644
--- a/target/arm/tcg/cpu-v7m.c
+++ b/target/arm/tcg/cpu-v7m.c
@@ -304,7 +304,7 @@ static const TCGCPUOps arm_v7m_tcg_ops = {
.cpu_exec_interrupt = arm_v7m_cpu_exec_interrupt,
.cpu_exec_halt = arm_cpu_exec_halt,
.cpu_exec_reset = cpu_reset,
- .do_interrupt_locked = arm_v7m_cpu_do_interrupt,
+ .do_interrupt = arm_v7m_cpu_do_interrupt,
.do_transaction_failed = arm_cpu_do_transaction_failed,
.do_unaligned_access = arm_cpu_do_unaligned_access,
.adjust_watchpoint_address = arm_adjust_watchpoint_address,
diff --git a/target/arm/tcg/m_helper.c b/target/arm/tcg/m_helper.c
index 33c9e7c55bc..9e15781f08d 100644
--- a/target/arm/tcg/m_helper.c
+++ b/target/arm/tcg/m_helper.c
@@ -2214,6 +2214,8 @@ void arm_v7m_cpu_do_interrupt(CPUState *cs)
bool ignore_stackfaults;
uint64_t last_pc = env->regs[15];
+ BQL_LOCK_GUARD();
+
arm_log_exception(cs);
/*
diff --git a/target/avr/cpu.c b/target/avr/cpu.c
index bc7639031b8..f8409f32ab9 100644
--- a/target/avr/cpu.c
+++ b/target/avr/cpu.c
@@ -249,7 +249,7 @@ static const TCGCPUOps avr_tcg_ops = {
.cpu_exec_halt = avr_cpu_has_work,
.cpu_exec_reset = cpu_reset,
.tlb_fill = avr_cpu_tlb_fill,
- .do_interrupt_locked = avr_cpu_do_interrupt,
+ .do_interrupt = avr_cpu_do_interrupt,
/*
* TODO: code and data wrapping are different, but for the most part
* AVR only references bytes or aligned code fetches. But we use
diff --git a/target/avr/helper.c b/target/avr/helper.c
index f452c9d9040..ed839b6db31 100644
--- a/target/avr/helper.c
+++ b/target/avr/helper.c
@@ -21,6 +21,7 @@
#include "qemu/osdep.h"
#include "qemu/log.h"
#include "qemu/error-report.h"
+#include "qemu/main-loop.h"
#include "cpu.h"
#include "accel/tcg/cpu-ops.h"
#include "accel/tcg/cpu-loop.h"
@@ -89,6 +90,8 @@ void avr_cpu_do_interrupt(CPUState *cs)
vector = ctz64(env->intsrc) + 1;
}
+ BQL_LOCK_GUARD();
+
if (avr_feature(env, AVR_FEATURE_3_BYTE_PC)) {
do_stb(env, env->sp--, ret, 0);
do_stb(env, env->sp--, ret >> 8, 0);
diff --git a/target/hppa/cpu.c b/target/hppa/cpu.c
index c6d915d314f..07b49e51326 100644
--- a/target/hppa/cpu.c
+++ b/target/hppa/cpu.c
@@ -272,7 +272,7 @@ static const TCGCPUOps hppa_tcg_ops = {
.cpu_exec_interrupt = hppa_cpu_exec_interrupt,
.cpu_exec_halt = hppa_cpu_has_work,
.cpu_exec_reset = cpu_reset,
- .do_interrupt_locked = hppa_cpu_do_interrupt,
+ .do_interrupt = hppa_cpu_do_interrupt,
.do_unaligned_access = hppa_cpu_do_unaligned_access,
.do_transaction_failed = hppa_cpu_do_transaction_failed,
#endif /* !CONFIG_USER_ONLY */
diff --git a/target/hppa/int_helper.c b/target/hppa/int_helper.c
index 3e87b9a0011..852d0649d84 100644
--- a/target/hppa/int_helper.c
+++ b/target/hppa/int_helper.c
@@ -98,6 +98,8 @@ void hppa_cpu_do_interrupt(CPUState *cs)
uint64_t old_psw, old_gva_offset_mask;
uint64_t last_pc = cs->cc->get_pc(cs);
+ BQL_LOCK_GUARD();
+
/* As documented in pa2.0 -- interruption handling. */
/* step 1 */
env->cr[CR_IPSW] = old_psw = cpu_hppa_get_psw(env);
diff --git a/target/i386/tcg/system/seg_helper.c b/target/i386/tcg/system/seg_helper.c
index 8c7856be81e..8eaeb746128 100644
--- a/target/i386/tcg/system/seg_helper.c
+++ b/target/i386/tcg/system/seg_helper.c
@@ -115,6 +115,8 @@ void x86_cpu_do_interrupt(CPUState *cs)
X86CPU *cpu = X86_CPU(cs);
CPUX86State *env = &cpu->env;
+ BQL_LOCK_GUARD();
+
if (cs->exception_index == EXCP_VMEXIT) {
assert(env->old_exception == -1);
do_vmexit(env);
diff --git a/target/i386/tcg/tcg-cpu.c b/target/i386/tcg/tcg-cpu.c
index ff65641654d..7a4d73e7fee 100644
--- a/target/i386/tcg/tcg-cpu.c
+++ b/target/i386/tcg/tcg-cpu.c
@@ -179,7 +179,7 @@ const TCGCPUOps x86_tcg_ops = {
#else
.tlb_fill = x86_cpu_tlb_fill,
.pointer_wrap = x86_pointer_wrap,
- .do_interrupt_locked = x86_cpu_do_interrupt,
+ .do_interrupt = x86_cpu_do_interrupt,
.cpu_exec_halt = x86_cpu_exec_halt,
.cpu_exec_interrupt = x86_cpu_exec_interrupt,
.cpu_exec_reset = x86_cpu_exec_reset,
diff --git a/target/mips/cpu.c b/target/mips/cpu.c
index 073e466b713..0fead20d651 100644
--- a/target/mips/cpu.c
+++ b/target/mips/cpu.c
@@ -718,7 +718,7 @@ static const TCGCPUOps mips_tcg_ops = {
.cpu_exec_interrupt = mips_cpu_exec_interrupt,
.cpu_exec_halt = mips_cpu_has_work,
.cpu_exec_reset = cpu_reset,
- .do_interrupt_locked = mips_cpu_do_interrupt,
+ .do_interrupt = mips_cpu_do_interrupt,
.do_transaction_failed = mips_cpu_do_transaction_failed,
.do_unaligned_access = mips_cpu_do_unaligned_access,
.io_recompile_replay_branch = mips_io_recompile_replay_branch,
diff --git a/target/mips/tcg/system/tlb_helper.c b/target/mips/tcg/system/tlb_helper.c
index 4398c6f80b4..2b8478f9a9d 100644
--- a/target/mips/tcg/system/tlb_helper.c
+++ b/target/mips/tcg/system/tlb_helper.c
@@ -18,6 +18,7 @@
*/
#include "qemu/osdep.h"
#include "qemu/bitops.h"
+#include "qemu/main-loop.h"
#include "qemu/plugin.h"
#include "cpu.h"
@@ -1045,6 +1046,8 @@ void mips_cpu_do_interrupt(CPUState *cs)
int cause = -1;
uint64_t last_pc = env->active_tc.PC;
+ BQL_LOCK_GUARD();
+
if (qemu_loglevel_mask(CPU_LOG_INT)
&& cs->exception_index != EXCP_EXT_INTERRUPT) {
qemu_log("%s enter: PC " TARGET_FMT_lx " EPC " TARGET_FMT_lx
diff --git a/target/ppc/cpu_init.c b/target/ppc/cpu_init.c
index 2676562b2f1..6c626843c93 100644
--- a/target/ppc/cpu_init.c
+++ b/target/ppc/cpu_init.c
@@ -7498,7 +7498,7 @@ static const TCGCPUOps ppc_tcg_ops = {
.cpu_exec_interrupt = ppc_cpu_exec_interrupt,
.cpu_exec_halt = ppc_cpu_has_work,
.cpu_exec_reset = cpu_reset,
- .do_interrupt_locked = ppc_cpu_do_interrupt,
+ .do_interrupt = ppc_cpu_do_interrupt,
.cpu_exec_enter = ppc_cpu_exec_enter,
.cpu_exec_exit = ppc_cpu_exec_exit,
.do_unaligned_access = ppc_cpu_do_unaligned_access,
diff --git a/target/ppc/excp_helper.c b/target/ppc/excp_helper.c
index 6d05b865058..6352a4fcaf3 100644
--- a/target/ppc/excp_helper.c
+++ b/target/ppc/excp_helper.c
@@ -1761,6 +1761,8 @@ void ppc_cpu_do_interrupt(CPUState *cs)
{
PowerPCCPU *cpu = POWERPC_CPU(cs);
+ BQL_LOCK_GUARD();
+
powerpc_excp(cpu, cs->exception_index);
}
diff --git a/target/riscv/tcg/tcg-cpu.c b/target/riscv/tcg/tcg-cpu.c
index ea3189ab3d2..9e3cc87f8a3 100644
--- a/target/riscv/tcg/tcg-cpu.c
+++ b/target/riscv/tcg/tcg-cpu.c
@@ -289,7 +289,7 @@ const TCGCPUOps riscv_tcg_ops = {
.cpu_exec_interrupt = riscv_cpu_exec_interrupt,
.cpu_exec_halt = riscv_cpu_has_work,
.cpu_exec_reset = cpu_reset,
- .do_interrupt_locked = riscv_cpu_do_interrupt,
+ .do_interrupt = riscv_cpu_do_interrupt,
.do_transaction_failed = riscv_cpu_do_transaction_failed,
.do_unaligned_access = riscv_cpu_do_unaligned_access,
.debug_excp_handler = riscv_cpu_debug_excp_handler,
diff --git a/target/rx/cpu.c b/target/rx/cpu.c
index ea58a804154..9b8473d71cf 100644
--- a/target/rx/cpu.c
+++ b/target/rx/cpu.c
@@ -229,7 +229,7 @@ static const TCGCPUOps rx_tcg_ops = {
.cpu_exec_interrupt = rx_cpu_exec_interrupt,
.cpu_exec_halt = rx_cpu_has_work,
.cpu_exec_reset = cpu_reset,
- .do_interrupt_locked = rx_cpu_do_interrupt,
+ .do_interrupt = rx_cpu_do_interrupt,
};
static void rx_cpu_class_init(ObjectClass *klass, const void *data)
diff --git a/target/rx/helper.c b/target/rx/helper.c
index 0f99279bbaa..784193ebd40 100644
--- a/target/rx/helper.c
+++ b/target/rx/helper.c
@@ -18,6 +18,7 @@
#include "qemu/osdep.h"
#include "qemu/bitops.h"
+#include "qemu/main-loop.h"
#include "cpu.h"
#include "exec/log.h"
#include "accel/tcg/cpu-ldst.h"
@@ -47,6 +48,8 @@ void rx_cpu_do_interrupt(CPUState *cs)
uint32_t save_psw;
uint64_t last_pc = env->pc;
+ BQL_LOCK_GUARD();
+
env->in_sleep = 0;
if (env->psw_u) {
diff --git a/target/s390x/cpu.c b/target/s390x/cpu.c
index 053eafaa842..7c725b8a4a4 100644
--- a/target/s390x/cpu.c
+++ b/target/s390x/cpu.c
@@ -386,7 +386,7 @@ static const TCGCPUOps s390_tcg_ops = {
.cpu_exec_interrupt = s390_cpu_exec_interrupt,
.cpu_exec_halt = s390_cpu_has_work,
.cpu_exec_reset = cpu_reset,
- .do_interrupt_locked = s390_cpu_do_interrupt,
+ .do_interrupt = s390_cpu_do_interrupt,
.debug_excp_handler = s390x_cpu_debug_excp_handler,
.do_unaligned_access = s390x_cpu_do_unaligned_access,
#endif /* !CONFIG_USER_ONLY */
diff --git a/target/s390x/tcg/excp_helper.c b/target/s390x/tcg/excp_helper.c
index 01c0d77b13b..d39d41bfcf3 100644
--- a/target/s390x/tcg/excp_helper.c
+++ b/target/s390x/tcg/excp_helper.c
@@ -28,6 +28,7 @@
#include "s390x-internal.h"
#include "tcg_s390x.h"
#ifndef CONFIG_USER_ONLY
+#include "qemu/main-loop.h"
#include "qemu/timer.h"
#include "system/address-spaces.h"
#include "system/memory.h"
@@ -503,6 +504,8 @@ void s390_cpu_do_interrupt(CPUState *cs)
bool stopped = false;
uint64_t last_pc = cpu->env.psw.addr;
+ BQL_LOCK_GUARD();
+
qemu_log_mask(CPU_LOG_INT, "%s: %d at psw=%" PRIx64 ":%" PRIx64 "\n",
__func__, cs->exception_index, env->psw.mask, env->psw.addr);
diff --git a/target/sh4/cpu.c b/target/sh4/cpu.c
index fdab5106b27..3bbdee301d5 100644
--- a/target/sh4/cpu.c
+++ b/target/sh4/cpu.c
@@ -314,7 +314,7 @@ static const TCGCPUOps superh_tcg_ops = {
.cpu_exec_interrupt = superh_cpu_exec_interrupt,
.cpu_exec_halt = superh_cpu_has_work,
.cpu_exec_reset = cpu_reset,
- .do_interrupt_locked = superh_cpu_do_interrupt,
+ .do_interrupt = superh_cpu_do_interrupt,
.do_unaligned_access = superh_cpu_do_unaligned_access,
.io_recompile_replay_branch = superh_io_recompile_replay_branch,
#endif /* !CONFIG_USER_ONLY */
diff --git a/target/sh4/helper.c b/target/sh4/helper.c
index b6b057f104b..1d854262d13 100644
--- a/target/sh4/helper.c
+++ b/target/sh4/helper.c
@@ -28,6 +28,7 @@
#include "qemu/plugin.h"
#if !defined(CONFIG_USER_ONLY)
+#include "qemu/main-loop.h"
#include "hw/sh4/sh_intc.h"
#include "system/runstate.h"
#endif
@@ -64,6 +65,8 @@ void superh_cpu_do_interrupt(CPUState *cs)
int do_exp, irq_vector = cs->exception_index;
uint64_t last_pc = env->pc;
+ BQL_LOCK_GUARD();
+
/* prioritize exceptions over interrupts */
do_exp = cs->exception_index != -1;
diff --git a/target/sparc/cpu.c b/target/sparc/cpu.c
index 23fd0a5e3fe..ae9bdca9df8 100644
--- a/target/sparc/cpu.c
+++ b/target/sparc/cpu.c
@@ -1076,7 +1076,7 @@ static const TCGCPUOps sparc_tcg_ops = {
.cpu_exec_interrupt = sparc_cpu_exec_interrupt,
.cpu_exec_halt = sparc_cpu_has_work,
.cpu_exec_reset = cpu_reset,
- .do_interrupt_locked = sparc_cpu_do_interrupt,
+ .do_interrupt = sparc_cpu_do_interrupt,
.do_transaction_failed = sparc_cpu_do_transaction_failed,
.do_unaligned_access = sparc_cpu_do_unaligned_access,
#endif /* !CONFIG_USER_ONLY */
diff --git a/target/sparc/int32_helper.c b/target/sparc/int32_helper.c
index d6bb3fa1e54..3eea824c9a3 100644
--- a/target/sparc/int32_helper.c
+++ b/target/sparc/int32_helper.c
@@ -105,6 +105,8 @@ void sparc_cpu_do_interrupt(CPUState *cs)
CPUSPARCState *env = cpu_env(cs);
int cwp, intno = cs->exception_index;
+ BQL_LOCK_GUARD();
+
if (qemu_loglevel_mask(CPU_LOG_INT)) {
static int count;
const char *name;
diff --git a/target/sparc/int64_helper.c b/target/sparc/int64_helper.c
index 60ab0478fc6..e26d3ac5142 100644
--- a/target/sparc/int64_helper.c
+++ b/target/sparc/int64_helper.c
@@ -138,6 +138,8 @@ void sparc_cpu_do_interrupt(CPUState *cs)
int intno = cs->exception_index;
trap_state *tsptr;
+ BQL_LOCK_GUARD();
+
#ifdef DEBUG_PCALL
if (qemu_loglevel_mask(CPU_LOG_INT)) {
static int count;
diff --git a/target/xtensa/cpu.c b/target/xtensa/cpu.c
index e980a13eadd..7c25b9ab707 100644
--- a/target/xtensa/cpu.c
+++ b/target/xtensa/cpu.c
@@ -327,7 +327,7 @@ static const TCGCPUOps xtensa_tcg_ops = {
.cpu_exec_interrupt = xtensa_cpu_exec_interrupt,
.cpu_exec_halt = xtensa_cpu_has_work,
.cpu_exec_reset = cpu_reset,
- .do_interrupt_locked = xtensa_cpu_do_interrupt,
+ .do_interrupt = xtensa_cpu_do_interrupt,
.do_transaction_failed = xtensa_cpu_do_transaction_failed,
.do_unaligned_access = xtensa_cpu_do_unaligned_access,
.debug_check_breakpoint = xtensa_debug_check_breakpoint,
diff --git a/target/xtensa/exc_helper.c b/target/xtensa/exc_helper.c
index 7cb67d179a8..81b303a35f3 100644
--- a/target/xtensa/exc_helper.c
+++ b/target/xtensa/exc_helper.c
@@ -208,6 +208,8 @@ void xtensa_cpu_do_interrupt(CPUState *cs)
{
CPUXtensaState *env = cpu_env(cs);
+ BQL_LOCK_GUARD();
+
if (cs->exception_index == EXC_IRQ) {
uint64_t last_pc = env->pc;
--
2.53.0
^ permalink raw reply related [flat|nested] 28+ messages in thread* [PATCH v3 11/11] accel/tcg: Remove do_interrupt_locked() callback
2026-09-02 15:20 [PATCH v3 00/11] accel/tcg: Push BQL down into per-target do_interrupt handlers Philippe Mathieu-Daudé
` (8 preceding siblings ...)
2026-09-02 15:20 ` [RFC PATCH v3 10/11] targets: Move BQL locking into do_interrupt() handlers Philippe Mathieu-Daudé
@ 2026-09-02 15:20 ` Philippe Mathieu-Daudé
2026-09-13 4:00 ` Richard Henderson
2026-09-02 15:33 ` [PATCH v3 00/11] accel/tcg: Push BQL down into per-target do_interrupt handlers Philippe Mathieu-Daudé
[not found] ` <20260902152044.31291-3-philmd@oss.qualcomm.com>
11 siblings, 1 reply; 28+ messages in thread
From: Philippe Mathieu-Daudé @ 2026-09-02 15:20 UTC (permalink / raw)
To: qemu-devel
Cc: Mark Cave-Ayland, Peter Maydell, Paolo Bonzini, qemu-ppc,
qemu-s390x, Richard Henderson, Pierrick Bouvier, qemu-riscv,
qemu-arm, Philippe Mathieu-Daudé
All targets now manage their own BQL locking via do_interrupt(),
making the do_interrupt_locked() hook unnecessary. Remove it to
simplify the TCGCPUOps interface.
Signed-off-by: Philippe Mathieu-Daudé <philmd@oss.qualcomm.com>
---
include/accel/tcg/cpu-ops.h | 12 ------------
accel/tcg/cpu-exec.c | 10 ++--------
2 files changed, 2 insertions(+), 20 deletions(-)
diff --git a/include/accel/tcg/cpu-ops.h b/include/accel/tcg/cpu-ops.h
index e2e67f796f6..89b3a11fd6a 100644
--- a/include/accel/tcg/cpu-ops.h
+++ b/include/accel/tcg/cpu-ops.h
@@ -183,18 +183,6 @@ struct TCGCPUOps {
*/
void (*do_interrupt)(CPUState *cpu);
- /**
- * @do_interrupt_locked: Deliver a pending exception/interrupt to the CPU
- * @cpu: cpu context
- *
- * Called when cs->exception_index contains an exception code to deliver.
- * Updates CPU architectural state (usually before executing a guest
- * exception handler).
- *
- * Called from cpu_handle_exception() with BQL held.
- */
- void (*do_interrupt_locked)(CPUState *cpu);
-
/**
* @cpu_exec_interrupt: Callback for processing target-specific interrupts
* @cpu: cpu context
diff --git a/accel/tcg/cpu-exec.c b/accel/tcg/cpu-exec.c
index 4deb7e00571..5d4b26357ff 100644
--- a/accel/tcg/cpu-exec.c
+++ b/accel/tcg/cpu-exec.c
@@ -727,13 +727,7 @@ static inline bool cpu_handle_exception(CPUState *cpu, int *ret)
if (replay_exception()) {
const TCGCPUOps *tcg_ops = cpu->cc->tcg_ops;
- if (tcg_ops->do_interrupt) {
- tcg_ops->do_interrupt(cpu);
- } else {
- bql_lock();
- tcg_ops->do_interrupt_locked(cpu);
- bql_unlock();
- }
+ tcg_ops->do_interrupt(cpu);
cpu->exception_index = -1;
if (unlikely(cpu_single_stepping(cpu))) {
@@ -1063,7 +1057,7 @@ bool tcg_exec_realizefn(CPUState *cpu, Error **errp)
assert(tcg_ops->cpu_exec_halt);
assert(tcg_ops->cpu_exec_interrupt);
assert(tcg_ops->cpu_exec_reset);
- assert(tcg_ops->do_interrupt || tcg_ops->do_interrupt_locked);
+ assert(tcg_ops->do_interrupt);
assert(tcg_ops->pointer_wrap);
#endif /* !CONFIG_USER_ONLY */
assert(tcg_ops->translate_code);
--
2.53.0
^ permalink raw reply related [flat|nested] 28+ messages in thread* Re: [PATCH v3 11/11] accel/tcg: Remove do_interrupt_locked() callback
2026-09-02 15:20 ` [PATCH v3 11/11] accel/tcg: Remove do_interrupt_locked() callback Philippe Mathieu-Daudé
@ 2026-09-13 4:00 ` Richard Henderson
0 siblings, 0 replies; 28+ messages in thread
From: Richard Henderson @ 2026-09-13 4:00 UTC (permalink / raw)
To: Philippe Mathieu-Daudé, qemu-devel
Cc: Mark Cave-Ayland, Peter Maydell, Paolo Bonzini, qemu-ppc,
qemu-s390x, Pierrick Bouvier, qemu-riscv, qemu-arm
On 9/2/26 05:20, Philippe Mathieu-Daudé wrote:
> All targets now manage their own BQL locking via do_interrupt(),
> making the do_interrupt_locked() hook unnecessary. Remove it to
> simplify the TCGCPUOps interface.
>
> Signed-off-by: Philippe Mathieu-Daudé<philmd@oss.qualcomm.com>
> ---
> include/accel/tcg/cpu-ops.h | 12 ------------
> accel/tcg/cpu-exec.c | 10 ++--------
> 2 files changed, 2 insertions(+), 20 deletions(-)
Oh I see. Objection to hexagon change retracted.
Reviewed-by: Richard Henderson <richard.henderson@linaro.org>
r~
^ permalink raw reply [flat|nested] 28+ messages in thread
* Re: [PATCH v3 00/11] accel/tcg: Push BQL down into per-target do_interrupt handlers
2026-09-02 15:20 [PATCH v3 00/11] accel/tcg: Push BQL down into per-target do_interrupt handlers Philippe Mathieu-Daudé
` (9 preceding siblings ...)
2026-09-02 15:20 ` [PATCH v3 11/11] accel/tcg: Remove do_interrupt_locked() callback Philippe Mathieu-Daudé
@ 2026-09-02 15:33 ` Philippe Mathieu-Daudé
[not found] ` <20260902152044.31291-3-philmd@oss.qualcomm.com>
11 siblings, 0 replies; 28+ messages in thread
From: Philippe Mathieu-Daudé @ 2026-09-02 15:33 UTC (permalink / raw)
To: qemu-devel, Robert Foley
Cc: Mark Cave-Ayland, Peter Maydell, Paolo Bonzini, qemu-ppc,
qemu-s390x, Richard Henderson, Pierrick Bouvier, qemu-riscv,
qemu-arm
On 2/9/26 17:20, Philippe Mathieu-Daudé wrote:
> This is a respin of Robert Foley's v2 series from August 2020 [1]
> triggered by a broader review of BQL contract in my halt-to-exec
> transitions series by Peter [2] and Mark [3].
> v2 Summary
> ----------
>
> This series pushes the Big QEMU Lock (BQL) down from the core TCG
> cpu_handle_interrupt/cpu_handle_exception paths into per-target
> implementations. This allows each architecture to manage BQL locking
> granularity independently, reducing contention on a known bottleneck
> as measured by QEMU sync profiling (qsp).
(I couldn't find what/where 'QEMU sync profiling' is).
>
> The BQL has long been a scaling bottleneck in QEMU, and the
> interrupt/exception handling path is one of its heaviest users. By
> allowing targets to acquire the BQL only when needed, we enable
> future per-target optimizations.
^ permalink raw reply [flat|nested] 28+ messages in thread[parent not found: <20260902152044.31291-3-philmd@oss.qualcomm.com>]
* Re: [PATCH v3 02/11] target/s390x: Restrict interrupt handlers to system mode
[not found] ` <20260902152044.31291-3-philmd@oss.qualcomm.com>
@ 2026-09-02 19:52 ` Pierrick Bouvier
2026-09-13 2:43 ` Richard Henderson
1 sibling, 0 replies; 28+ messages in thread
From: Pierrick Bouvier @ 2026-09-02 19:52 UTC (permalink / raw)
To: Philippe Mathieu-Daudé, qemu-devel
Cc: Mark Cave-Ayland, Peter Maydell, Paolo Bonzini, qemu-ppc,
qemu-s390x, Richard Henderson, qemu-riscv, qemu-arm,
Cornelia Huck, Eric Farman, Matthew Rosato, Ilya Leoshkevich,
David Hildenbrand
On 9/2/2026 8:20 AM, Philippe Mathieu-Daudé wrote:
> Move s390_cpu_do_interrupt() and s390_cpu_exec_interrupt()
> declarations from system/user shared header to system-mode-only
> section, removing the unused user-mode stub.
>
> Signed-off-by: Philippe Mathieu-Daudé <philmd@oss.qualcomm.com>
> ---
> target/s390x/s390x-internal.h | 5 ++---
> target/s390x/tcg/excp_helper.c | 5 -----
> 2 files changed, 2 insertions(+), 8 deletions(-)
>
Reviewed-by: Pierrick Bouvier <pierrick.bouvier@oss.qualcomm.com>
^ permalink raw reply [flat|nested] 28+ messages in thread* Re: [PATCH v3 02/11] target/s390x: Restrict interrupt handlers to system mode
[not found] ` <20260902152044.31291-3-philmd@oss.qualcomm.com>
2026-09-02 19:52 ` [PATCH v3 02/11] target/s390x: Restrict interrupt handlers to system mode Pierrick Bouvier
@ 2026-09-13 2:43 ` Richard Henderson
1 sibling, 0 replies; 28+ messages in thread
From: Richard Henderson @ 2026-09-13 2:43 UTC (permalink / raw)
To: Philippe Mathieu-Daudé, qemu-devel
Cc: Mark Cave-Ayland, Peter Maydell, Paolo Bonzini, qemu-ppc,
qemu-s390x, Pierrick Bouvier, qemu-riscv, qemu-arm, Cornelia Huck,
Eric Farman, Matthew Rosato, Ilya Leoshkevich, David Hildenbrand
On 9/2/26 05:20, Philippe Mathieu-Daudé wrote:
> Move s390_cpu_do_interrupt() and s390_cpu_exec_interrupt()
> declarations from system/user shared header to system-mode-only
> section, removing the unused user-mode stub.
>
> Signed-off-by: Philippe Mathieu-Daudé<philmd@oss.qualcomm.com>
> ---
> target/s390x/s390x-internal.h | 5 ++---
> target/s390x/tcg/excp_helper.c | 5 -----
> 2 files changed, 2 insertions(+), 8 deletions(-)
Reviewed-by: Richard Henderson <richard.henderson@linaro.org>
r~
^ permalink raw reply [flat|nested] 28+ messages in thread