mirror of
https://gitlab.com/qemu-project/qemu.git
synced 2026-10-28 14:04:39 +08:00
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:
1 parent
f3aefe24fb
commit
e600f0f9e9
3 files changed
+26
-12
No files matched your search
+7
-3
@@ -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);
|
||||
}
|
||||
|
||||
@@ -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 */
|
||||
@@ -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);
|
||||
}
|
||||
|
||||
|
||||
Reference in new issue
Block a user