diff --git a/hw/intc/s390_flic.c b/hw/intc/s390_flic.c index ce7f355248288d836816d9a23ec4b6f42c11f151..efcb1dd0f122c841f7899845a83c212899c05598 100644 --- a/hw/intc/s390_flic.c +++ b/hw/intc/s390_flic.c @@ -13,8 +13,11 @@ #include "qemu/osdep.h" #include "qemu/error-report.h" #include "hw/sysbus.h" +#include "hw/s390x/ioinst.h" #include "hw/s390x/s390_flic.h" +#include "hw/s390x/css.h" #include "trace.h" +#include "cpu.h" #include "hw/qdev.h" #include "qapi/error.h" #include "hw/s390x/s390-virtio-ccw.h" @@ -100,6 +103,29 @@ static int qemu_s390_modify_ais_mode(S390FLICState *fs, uint8_t isc, return 0; } +static int qemu_s390_inject_airq(S390FLICState *fs, uint8_t type, + uint8_t isc, uint8_t flags) +{ + QEMUS390FLICState *flic = QEMU_S390_FLIC(fs); + bool flag = flags & S390_ADAPTER_SUPPRESSIBLE; + uint32_t io_int_word = (isc << 27) | IO_INT_WORD_AI; + + if (flag && (flic->nimm & AIS_MODE_MASK(isc))) { + trace_qemu_s390_airq_suppressed(type, isc); + return 0; + } + + s390_io_interrupt(0, 0, 0, io_int_word); + + if (flag && (flic->simm & AIS_MODE_MASK(isc))) { + flic->nimm |= AIS_MODE_MASK(isc); + trace_qemu_s390_suppress_airq(isc, "Single-Interruption Mode", + "NO-Interruptions Mode"); + } + + return 0; +} + static void qemu_s390_flic_reset(DeviceState *dev) { QEMUS390FLICState *flic = QEMU_S390_FLIC(dev); @@ -120,6 +146,7 @@ static void qemu_s390_flic_class_init(ObjectClass *oc, void *data) fsc->release_adapter_routes = qemu_s390_release_adapter_routes; fsc->clear_io_irq = qemu_s390_clear_io_flic; fsc->modify_ais_mode = qemu_s390_modify_ais_mode; + fsc->inject_airq = qemu_s390_inject_airq; } static Property s390_flic_common_properties[] = { diff --git a/hw/intc/s390_flic_kvm.c b/hw/intc/s390_flic_kvm.c index 55aa35fc6ae73ce074610f3acdf4b70bbf40d57c..a587ace3df9417c9975d20c852f51e8342d7947c 100644 --- a/hw/intc/s390_flic_kvm.c +++ b/hw/intc/s390_flic_kvm.c @@ -170,6 +170,23 @@ static int kvm_s390_modify_ais_mode(S390FLICState *fs, uint8_t isc, return ioctl(flic->fd, KVM_SET_DEVICE_ATTR, &attr) ? -errno : 0; } +static int kvm_s390_inject_airq(S390FLICState *fs, uint8_t type, + uint8_t isc, uint8_t flags) +{ + KVMS390FLICState *flic = KVM_S390_FLIC(fs); + uint32_t id = css_get_adapter_id(type, isc); + struct kvm_device_attr attr = { + .group = KVM_DEV_FLIC_AIRQ_INJECT, + .attr = id, + }; + + if (!fs->ais_supported) { + return -ENOSYS; + } + + return ioctl(flic->fd, KVM_SET_DEVICE_ATTR, &attr) ? -errno : 0; +} + /** * __get_all_irqs - store all pending irqs in buffer * @flic: pointer to flic device state @@ -515,6 +532,7 @@ static void kvm_s390_flic_class_init(ObjectClass *oc, void *data) fsc->release_adapter_routes = kvm_s390_release_adapter_routes; fsc->clear_io_irq = kvm_s390_clear_io_flic; fsc->modify_ais_mode = kvm_s390_modify_ais_mode; + fsc->inject_airq = kvm_s390_inject_airq; } static const TypeInfo kvm_s390_flic_info = { diff --git a/hw/intc/trace-events b/hw/intc/trace-events index 729c1288f1c9571400beac7813d635bed8baf0c8..c586714d893566e8767dee66845057c0b97f6913 100644 --- a/hw/intc/trace-events +++ b/hw/intc/trace-events @@ -73,6 +73,10 @@ flic_create_device(int err) "flic: create device failed %d" flic_no_device_api(int err) "flic: no Device Contral API support %d" flic_reset_failed(int err) "flic: reset failed %d" +# hw/intc/s390_flic.c +qemu_s390_airq_suppressed(uint8_t type, uint8_t isc) "flic: adapter I/O interrupt suppressed (type %x isc %x)" +qemu_s390_suppress_airq(uint8_t isc, const char *from, const char *to) "flic: for isc %x, suppress airq by modifying ais mode from %s to %s" + # hw/intc/aspeed_vic.c aspeed_vic_set_irq(int irq, int level) "Enabling IRQ %d: %d" aspeed_vic_update_fiq(int flags) "Raising FIQ: %d" diff --git a/include/hw/s390x/s390_flic.h b/include/hw/s390x/s390_flic.h index f500184794f10b5ad8f39922d2e7b82ea3b3157c..2f173d905cece71054b87fcfb2d79b32f03ea049 100644 --- a/include/hw/s390x/s390_flic.h +++ b/include/hw/s390x/s390_flic.h @@ -64,6 +64,8 @@ typedef struct S390FLICStateClass { int (*clear_io_irq)(S390FLICState *fs, uint16_t subchannel_id, uint16_t subchannel_nr); int (*modify_ais_mode)(S390FLICState *fs, uint8_t isc, uint16_t mode); + int (*inject_airq)(S390FLICState *fs, uint8_t type, uint8_t isc, + uint8_t flags); } S390FLICStateClass; #define TYPE_KVM_S390_FLIC "s390-flic-kvm"