diff options
author | David Hildenbrand <david@redhat.com> | 2017-09-28 22:36:39 +0200 |
---|---|---|
committer | Cornelia Huck <cohuck@redhat.com> | 2017-10-20 13:32:10 +0200 |
commit | 6482b0ffd12ce83810c10b1a3884a75eba2ade1a (patch) | |
tree | 211d5b6b5a5859c608aa00518b68ad8c56048cd5 /target/s390x/excp_helper.c | |
parent | 9ea63c05d90ba85d819f9b2472ce6dfba7a403b4 (diff) |
s390x/tcg: turn INTERRUPT_EXT into a mask
External interrupts are currently all handled like floating external
interrupts, they are queued. Let's prepare for a split of floating
and local interrupts by turning INTERRUPT_EXT into a mask.
While we can have various floating external interrupts of one kind, there
is usually only one (or a fixed number) of the local external interrupts.
So turn INTERRUPT_EXT into a mask and properly indicate the kind of
external interrupt. Floating interrupts will have to moved out of
one CPU instance later once we have SMP support.
The only floating external interrupts used right now are SERVICE
interrupts, so let's use that name. Following patches will clean up
SERVICE interrupt injection.
This get's rid of the ugly special handling for cpu timer and clock
comparator interrupts. And we really only store the parameters as
defined by the PoP.
Reviewed-by: Richard Henderson <richard.henderson@linaro.org>
Signed-off-by: David Hildenbrand <david@redhat.com>
Message-Id: <20170928203708.9376-2-david@redhat.com>
Signed-off-by: Cornelia Huck <cohuck@redhat.com>
Diffstat (limited to 'target/s390x/excp_helper.c')
-rw-r--r-- | target/s390x/excp_helper.c | 63 |
1 files changed, 32 insertions, 31 deletions
diff --git a/target/s390x/excp_helper.c b/target/s390x/excp_helper.c index 3e4349d00b..b58486b98b 100644 --- a/target/s390x/excp_helper.c +++ b/target/s390x/excp_helper.c @@ -247,29 +247,42 @@ static void do_ext_interrupt(CPUS390XState *env) cpu_abort(CPU(cpu), "Ext int w/o ext mask\n"); } - if (env->ext_index < 0 || env->ext_index >= MAX_EXT_QUEUE) { - cpu_abort(CPU(cpu), "Ext queue overrun: %d\n", env->ext_index); - } - - q = &env->ext_queue[env->ext_index]; lowcore = cpu_map_lowcore(env); - lowcore->ext_int_code = cpu_to_be16(q->code); - lowcore->ext_params = cpu_to_be32(q->param); - lowcore->ext_params2 = cpu_to_be64(q->param64); - lowcore->external_old_psw.mask = cpu_to_be64(get_psw_mask(env)); - lowcore->external_old_psw.addr = cpu_to_be64(env->psw.addr); - lowcore->cpu_addr = cpu_to_be16(env->core_id | VIRTIO_SUBCODE_64); + if (env->pending_int & INTERRUPT_EXT_CLOCK_COMPARATOR) { + lowcore->ext_int_code = cpu_to_be16(EXT_CLOCK_COMP); + lowcore->cpu_addr = 0; + env->pending_int &= ~INTERRUPT_EXT_CLOCK_COMPARATOR; + } else if (env->pending_int & INTERRUPT_EXT_CPU_TIMER) { + lowcore->ext_int_code = cpu_to_be16(EXT_CPU_TIMER); + lowcore->cpu_addr = 0; + env->pending_int &= ~INTERRUPT_EXT_CPU_TIMER; + } else if (env->pending_int & INTERRUPT_EXT_SERVICE) { + g_assert(env->ext_index >= 0); + /* + * FIXME: floating IRQs should be considered by all CPUs and + * shuld not get cleared by CPU reset. + */ + q = &env->ext_queue[env->ext_index]; + lowcore->ext_int_code = cpu_to_be16(q->code); + lowcore->ext_params = cpu_to_be32(q->param); + lowcore->ext_params2 = cpu_to_be64(q->param64); + lowcore->cpu_addr = cpu_to_be16(env->core_id | VIRTIO_SUBCODE_64); + env->ext_index--; + if (env->ext_index == -1) { + env->pending_int &= ~INTERRUPT_EXT_SERVICE; + } + } else { + g_assert_not_reached(); + } + mask = be64_to_cpu(lowcore->external_new_psw.mask); addr = be64_to_cpu(lowcore->external_new_psw.addr); + lowcore->external_old_psw.mask = cpu_to_be64(get_psw_mask(env)); + lowcore->external_old_psw.addr = cpu_to_be64(env->psw.addr); cpu_unmap_lowcore(lowcore); - env->ext_index--; - if (env->ext_index == -1) { - env->pending_int &= ~INTERRUPT_EXT; - } - DPRINTF("%s: %" PRIx64 " %" PRIx64 "\n", __func__, env->psw.mask, env->psw.addr); @@ -422,21 +435,9 @@ void s390_cpu_do_interrupt(CPUState *cs) } /* handle external interrupts */ if ((env->psw.mask & PSW_MASK_EXT) && - cs->exception_index == -1) { - if (env->pending_int & INTERRUPT_EXT) { - /* code is already in env */ - cs->exception_index = EXCP_EXT; - } else if (env->pending_int & INTERRUPT_TOD) { - cpu_inject_ext(cpu, 0x1004, 0, 0); - cs->exception_index = EXCP_EXT; - env->pending_int &= ~INTERRUPT_EXT; - env->pending_int &= ~INTERRUPT_TOD; - } else if (env->pending_int & INTERRUPT_CPUTIMER) { - cpu_inject_ext(cpu, 0x1005, 0, 0); - cs->exception_index = EXCP_EXT; - env->pending_int &= ~INTERRUPT_EXT; - env->pending_int &= ~INTERRUPT_TOD; - } + cs->exception_index == -1 && + (env->pending_int & INTERRUPT_EXT)) { + cs->exception_index = EXCP_EXT; } /* handle I/O interrupts */ if ((env->psw.mask & PSW_MASK_IO) && |