hw/intc: ciad should forward its mask to l2vic

ciad cleared the last interrupt the L2VIC delivered regardless of its
mask.  So a ciad for any other interrupt would get applied incorrectly.

Only clear the active interrupt when the ciad acknowledges the CPU
interrupt that its VID group is delivered on, and only if that interrupt
was taken or set with siad.

Reviewed-by: Pierrick Bouvier <pierrick.bouvier@oss.qualcomm.com>
Signed-off-by: Brian Cain <brian.cain@oss.qualcomm.com>
This commit is contained in:
Brian Cain committed 2026-10-27 07:23:27 -07:00
1 parent f3aefe24fb
commit e600f0f9e9
3 files changed
+26 -12

No files matched your search

+7 -3
View File
@@ -448,12 +448,16 @@ static void l2vic_interface_update_vid_impl(HexL2VicInterface *iface,
l2vic_update_all(s);
}
static void l2vic_interface_clear_interrupt_impl(HexL2VicInterface *iface)
static void l2vic_interface_clear_interrupt_impl(HexL2VicInterface *iface,
uint32_t mask)
{
HexL2VICState *s = HEX_L2VIC(iface);
const uint32_t size = L2VIC_INTERRUPT_MAX;
const uint32_t active_irq = find_first_bit32(s->int_status, size);
if (s->vid < L2VIC_INTERRUPT_MAX) {
clear_bit32(s->vid, s->int_status);
/* VID group n is delivered on CPU interrupt n + 2 */
if (active_irq != size && (mask & BIT(get_vid(s, active_irq) + 2))) {
clear_bit32(active_irq, s->int_status);
}
l2vic_update_all(s);
}
+10 -4
View File
@@ -31,8 +31,13 @@ typedef struct HexL2VicInterfaceClass {
void (*update_vid)(HexL2VicInterface *l2vic, uint32_t group,
uint32_t value);
/* Clear interrupt using CIAD instruction */
void (*clear_interrupt)(HexL2VicInterface *l2vic);
/*
* Clear interrupts using the CIAD instruction.
* @mask the CPU interrupts that the CIAD acknowledged. The interrupt is
* only cleared if @mask has the CPU interrupt that its VID group is
* delivered on.
*/
void (*clear_interrupt)(HexL2VicInterface *l2vic, uint32_t mask);
} HexL2VicInterfaceClass;
DECLARE_OBJ_CHECKERS(HexL2VicInterface, HexL2VicInterfaceClass,
@@ -52,10 +57,11 @@ static inline void l2vic_update_vid(HexL2VicInterface *l2vic, uint32_t group,
k->update_vid(l2vic, group, value);
}
static inline void l2vic_clear_interrupt(HexL2VicInterface *l2vic)
static inline void l2vic_clear_interrupt(HexL2VicInterface *l2vic,
uint32_t mask)
{
HexL2VicInterfaceClass *k = HEX_L2VIC_INTERFACE_GET_CLASS(l2vic);
k->clear_interrupt(l2vic);
k->clear_interrupt(l2vic, mask);
}
#endif /* HW_INTC_HEX_L2VIC_H */
+9 -5
View File
@@ -1686,26 +1686,30 @@ void HELPER(raise_stack_overflow)(CPUHexagonState *env, uint32_t slot,
void HELPER(ciad)(CPUHexagonState *env, uint32_t mask)
{
uint32_t iad;
uint32_t was_set;
HexagonCPU *cpu;
BQL_LOCK_GUARD();
cpu = env_archcpu(env);
if (cpu->cfg.hex_def->hex_version >= HEX_VER_V81) {
iad = hexagon_globalreg_read(cpu->globalregs, HEX_SREG_IAD,
env->threadId) & ~mask;
hexagon_globalreg_write(cpu->globalregs, HEX_SREG_IAD, iad,
env->threadId);
was_set = iad & mask;
hexagon_globalreg_write(cpu->globalregs, HEX_SREG_IAD, iad & ~mask,
env->threadId);
} else {
uint32_t ipendad =
hexagon_globalreg_read(cpu->globalregs, HEX_SREG_IPENDAD,
env->threadId);
fSET_FIELD(ipendad, IPENDAD_IAD,
fGET_FIELD(ipendad, IPENDAD_IAD) & ~mask);
iad = fGET_FIELD(ipendad, IPENDAD_IAD);
was_set = iad & mask;
fSET_FIELD(ipendad, IPENDAD_IAD, iad & ~mask);
hexagon_globalreg_write(cpu->globalregs, HEX_SREG_IPENDAD,
ipendad, env->threadId);
}
l2vic_clear_interrupt(cpu->l2vic);
/* Only an interrupt that was taken, or set with siad, can be cleared */
l2vic_clear_interrupt(cpu->l2vic, was_set);
hex_interrupt_update(env);
}