From f068d320def7fd83bf0fcdca37b305f1c2ac5413 Mon Sep 17 00:00:00 2001 From: Cornelia Huck Date: Tue, 27 May 2014 12:40:44 +0200 Subject: s390x/css: handle emw correctly for tsch We should not try to store the emw portion of the irb if extended measurements are not applicable. In particular, we should not surprise the guest by storing a larger irb if it did not enable extended measurements. Cc: qemu-stable@nongnu.org Reviewed-by: David Hildenbrand Tested-by: Christian Borntraeger Signed-off-by: Cornelia Huck --- hw/s390x/css.c | 24 ++++++++++++++++++++---- 1 file changed, 20 insertions(+), 4 deletions(-) diff --git a/hw/s390x/css.c b/hw/s390x/css.c index 2678e44..a813b23 100644 --- a/hw/s390x/css.c +++ b/hw/s390x/css.c @@ -779,9 +779,11 @@ out: return ret; } -static void copy_irb_to_guest(IRB *dest, const IRB *src) +static void copy_irb_to_guest(IRB *dest, const IRB *src, PMCW *pmcw) { int i; + uint16_t stctl = src->scsw.ctrl & SCSW_CTRL_MASK_STCTL; + uint16_t actl = src->scsw.ctrl & SCSW_CTRL_MASK_ACTL; copy_scsw_to_guest(&dest->scsw, &src->scsw); @@ -791,8 +793,22 @@ static void copy_irb_to_guest(IRB *dest, const IRB *src) for (i = 0; i < ARRAY_SIZE(dest->ecw); i++) { dest->ecw[i] = cpu_to_be32(src->ecw[i]); } - for (i = 0; i < ARRAY_SIZE(dest->emw); i++) { - dest->emw[i] = cpu_to_be32(src->emw[i]); + /* extended measurements enabled? */ + if ((src->scsw.flags & SCSW_FLAGS_MASK_ESWF) || + !(pmcw->flags & PMCW_FLAGS_MASK_TF) || + !(pmcw->chars & PMCW_CHARS_MASK_XMWME)) { + return; + } + /* extended measurements pending? */ + if (!(stctl & SCSW_STCTL_STATUS_PEND)) { + return; + } + if ((stctl & SCSW_STCTL_PRIMARY) || + (stctl == SCSW_STCTL_SECONDARY) || + ((stctl & SCSW_STCTL_INTERMEDIATE) && (actl & SCSW_ACTL_SUSP))) { + for (i = 0; i < ARRAY_SIZE(dest->emw); i++) { + dest->emw[i] = cpu_to_be32(src->emw[i]); + } } } @@ -838,7 +854,7 @@ int css_do_tsch(SubchDev *sch, IRB *target_irb) } } /* Store the irb to the guest. */ - copy_irb_to_guest(target_irb, &irb); + copy_irb_to_guest(target_irb, &irb, p); /* Clear conditions on subchannel, if applicable. */ if (stctl & SCSW_STCTL_STATUS_PEND) { -- cgit v1.1 From 08da527fd07cf01dc29ca60a144fbdd60b0fb7c0 Mon Sep 17 00:00:00 2001 From: Cornelia Huck Date: Wed, 28 May 2014 14:15:57 +0200 Subject: s390x/kvm: make flic play well with old kernels If we run with an old kernel that does not support KVM_CAP_IRQ_ROUTING, we don't have to do anything in the ->register_io_adapter and ->io_adapter_map callbacks and therefore should return 0 instead of -ENOSYS (just as the non-kvm flic does). This fixes using adapter interrupts when running under an older kernel, which broke with "s390x: add I/O adapter registration". Reported-by: Christian Borntraeger Signed-off-by: Cornelia Huck --- hw/intc/s390_flic_kvm.c | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/hw/intc/s390_flic_kvm.c b/hw/intc/s390_flic_kvm.c index 46c9e61..a734094 100644 --- a/hw/intc/s390_flic_kvm.c +++ b/hw/intc/s390_flic_kvm.c @@ -170,7 +170,8 @@ static int kvm_s390_register_io_adapter(S390FLICState *fs, uint32_t id, }; if (!kvm_check_extension(kvm_state, KVM_CAP_IRQ_ROUTING)) { - return -ENOSYS; + /* nothing to do */ + return 0; } r = ioctl(flic->fd, KVM_SET_DEVICE_ATTR, &attr); @@ -195,7 +196,8 @@ static int kvm_s390_io_adapter_map(S390FLICState *fs, uint32_t id, int r; if (!kvm_check_extension(kvm_state, KVM_CAP_IRQ_ROUTING)) { - return -ENOSYS; + /* nothing to do */ + return 0; } r = ioctl(flic->fd, KVM_SET_DEVICE_ATTR, &attr); -- cgit v1.1 From 4cb88c3c378ae8c86c0ba53619caf6924f72239c Mon Sep 17 00:00:00 2001 From: Dominik Dingel Date: Fri, 11 Apr 2014 13:47:40 +0200 Subject: s390x/kvm: enable/reset cmma via vm attributes Exploit the new api for userspace-controlled cmma. If supported, enable cmma during kvm initialization and register a reset handler for cmma, which is also called directly from the load IPL code. The reset functionality is needed to reset the cmma state of the guest pages, e.g. if a system reset is triggered via qemu monitor; otherwise this could result in data corruption. A guest triggered reboot may now lead to multiple cmma resets; this is OK, however, as this is slowpath anyway and the simplest way to achieve the intended effects. Signed-off-by: Dominik Dingel Acked-by: Christian Borntraeger Acked-by: Cornelia Huck Signed-off-by: Cornelia Huck --- target-s390x/cpu.h | 12 ++++++++++ target-s390x/kvm.c | 58 ++++++++++++++++++++++++++++++++++++++++++++++ target-s390x/misc_helper.c | 2 ++ trace-events | 4 ++++ 4 files changed, 76 insertions(+) diff --git a/target-s390x/cpu.h b/target-s390x/cpu.h index 06454d6..808b906 100644 --- a/target-s390x/cpu.h +++ b/target-s390x/cpu.h @@ -1074,6 +1074,7 @@ void kvm_s390_enable_css_support(S390CPU *cpu); int kvm_s390_assign_subch_ioeventfd(EventNotifier *notifier, uint32_t sch, int vq, bool assign); int kvm_s390_cpu_restart(S390CPU *cpu); +void kvm_s390_clear_cmma_callback(void *opaque); #else static inline void kvm_s390_io_interrupt(S390CPU *cpu, uint16_t subchannel_id, @@ -1098,8 +1099,19 @@ static inline int kvm_s390_cpu_restart(S390CPU *cpu) { return -ENOSYS; } +static inline void kvm_s390_clear_cmma_callback(void *opaque) +{ +} #endif +static inline void cmma_reset(S390CPU *cpu) +{ + if (kvm_enabled()) { + CPUState *cs = CPU(cpu); + kvm_s390_clear_cmma_callback(cs->kvm_state); + } +} + static inline int s390_cpu_restart(S390CPU *cpu) { if (kvm_enabled()) { diff --git a/target-s390x/kvm.c b/target-s390x/kvm.c index 7a07f9d..0a2a205 100644 --- a/target-s390x/kvm.c +++ b/target-s390x/kvm.c @@ -32,6 +32,7 @@ #include "qemu/timer.h" #include "sysemu/sysemu.h" #include "sysemu/kvm.h" +#include "hw/hw.h" #include "cpu.h" #include "sysemu/device_tree.h" #include "qapi/qmp/qjson.h" @@ -104,10 +105,67 @@ static int cap_async_pf; static void *legacy_s390_alloc(size_t size); +static int kvm_s390_check_clear_cmma(KVMState *s) +{ + struct kvm_device_attr attr = { + .group = KVM_S390_VM_MEM_CTRL, + .attr = KVM_S390_VM_MEM_CLR_CMMA, + }; + + return kvm_vm_ioctl(s, KVM_HAS_DEVICE_ATTR, &attr); +} + +static int kvm_s390_check_enable_cmma(KVMState *s) +{ + struct kvm_device_attr attr = { + .group = KVM_S390_VM_MEM_CTRL, + .attr = KVM_S390_VM_MEM_ENABLE_CMMA, + }; + + return kvm_vm_ioctl(s, KVM_HAS_DEVICE_ATTR, &attr); +} + +void kvm_s390_clear_cmma_callback(void *opaque) +{ + int rc; + KVMState *s = opaque; + struct kvm_device_attr attr = { + .group = KVM_S390_VM_MEM_CTRL, + .attr = KVM_S390_VM_MEM_CLR_CMMA, + }; + + rc = kvm_vm_ioctl(s, KVM_SET_DEVICE_ATTR, &attr); + trace_kvm_clear_cmma(rc); +} + +static void kvm_s390_enable_cmma(KVMState *s) +{ + int rc; + struct kvm_device_attr attr = { + .group = KVM_S390_VM_MEM_CTRL, + .attr = KVM_S390_VM_MEM_ENABLE_CMMA, + }; + + if (kvm_s390_check_enable_cmma(s) || kvm_s390_check_clear_cmma(s)) { + return; + } + + rc = kvm_vm_ioctl(s, KVM_SET_DEVICE_ATTR, &attr); + if (!rc) { + qemu_register_reset(kvm_s390_clear_cmma_callback, s); + } + trace_kvm_enable_cmma(rc); +} + int kvm_arch_init(KVMState *s) { cap_sync_regs = kvm_check_extension(s, KVM_CAP_SYNC_REGS); cap_async_pf = kvm_check_extension(s, KVM_CAP_ASYNC_PF); + + if (kvm_check_extension(s, KVM_CAP_VM_ATTRIBUTES)) { + kvm_s390_enable_cmma(s); + } + if (!kvm_check_extension(s, KVM_CAP_S390_GMAP) || !kvm_check_extension(s, KVM_CAP_S390_COW)) { phys_mem_set_alloc(legacy_s390_alloc); diff --git a/target-s390x/misc_helper.c b/target-s390x/misc_helper.c index 9dae025..519edb8 100644 --- a/target-s390x/misc_helper.c +++ b/target-s390x/misc_helper.c @@ -136,6 +136,7 @@ static int modified_clear_reset(S390CPU *cpu) pause_all_vcpus(); cpu_synchronize_all_states(); cpu_full_reset_all(); + cmma_reset(cpu); io_subsystem_reset(); scc->load_normal(CPU(cpu)); cpu_synchronize_all_post_reset(); @@ -150,6 +151,7 @@ static int load_normal_reset(S390CPU *cpu) pause_all_vcpus(); cpu_synchronize_all_states(); cpu_reset_all(); + cmma_reset(cpu); io_subsystem_reset(); scc->initial_cpu_reset(CPU(cpu)); scc->load_normal(CPU(cpu)); diff --git a/trace-events b/trace-events index ffe6e62..e984e76 100644 --- a/trace-events +++ b/trace-events @@ -1258,3 +1258,7 @@ xen_pv_mmio_write(uint64_t addr) "WARNING: write to Xen PV Device MMIO space (ad # hw/pci/pci_host.c pci_cfg_read(const char *dev, unsigned devid, unsigned fnid, unsigned offs, unsigned val) "%s %02u:%u @0x%x -> 0x%x" pci_cfg_write(const char *dev, unsigned devid, unsigned fnid, unsigned offs, unsigned val) "%s %02u:%u @0x%x <- 0x%x" + +# target-s390x/kvm.c +kvm_enable_cmma(int rc) "CMMA: enabling with result code %d" +kvm_clear_cmma(int rc) "CMMA: clearing with result code %d" -- cgit v1.1 From a2689242b10a7bbc9a952659a2a5cc04a86d10e1 Mon Sep 17 00:00:00 2001 From: Thomas Huth Date: Thu, 20 Mar 2014 21:49:18 +0100 Subject: s390x/kvm: Log unmanageable external interruptions Interception code 0x14 only drops to userspace when an unmanageable external interruption interception occured (e.g. if the External New PSW does not disable external interruptions). Instead of bailing out via the default handler, it is better to inform the user with a proper error message that also includes the bad PSW, and to stop the affected CPU with a panic event instead. Signed-off-by: Thomas Huth Signed-off-by: Jens Freimann Reviewed-by: David Hildenbrand Acked-by: Christian Borntraeger Signed-off-by: Cornelia Huck --- target-s390x/kvm.c | 35 +++++++++++++++++++++++++++++------ 1 file changed, 29 insertions(+), 6 deletions(-) diff --git a/target-s390x/kvm.c b/target-s390x/kvm.c index 0a2a205..be703bd 100644 --- a/target-s390x/kvm.c +++ b/target-s390x/kvm.c @@ -83,6 +83,7 @@ #define DIAG_KVM_BREAKPOINT 0x501 #define ICPT_INSTRUCTION 0x04 +#define ICPT_EXT_INT 0x14 #define ICPT_WAITPSW 0x1c #define ICPT_SOFT_INTERCEPT 0x24 #define ICPT_CPU_STOP 0x28 @@ -930,6 +931,28 @@ static bool is_special_wait_psw(CPUState *cs) return cs->kvm_run->psw_addr == 0xfffUL; } +static void guest_panicked(void) +{ + QObject *data; + + data = qobject_from_jsonf("{ 'action': %s }", "pause"); + monitor_protocol_event(QEVENT_GUEST_PANICKED, data); + qobject_decref(data); + + vm_stop(RUN_STATE_GUEST_PANICKED); +} + +static void unmanageable_intercept(S390CPU *cpu, const char *str, int pswoffset) +{ + CPUState *cs = CPU(cpu); + + error_report("Unmanageable %s! CPU%i new PSW: 0x%016lx:%016lx", + str, cs->cpu_index, ldq_phys(cs->as, cpu->env.psa + pswoffset), + ldq_phys(cs->as, cpu->env.psa + pswoffset + 8)); + s390_del_running_cpu(cpu); + guest_panicked(); +} + static int handle_intercept(S390CPU *cpu) { CPUState *cs = CPU(cpu); @@ -943,18 +966,18 @@ static int handle_intercept(S390CPU *cpu) case ICPT_INSTRUCTION: r = handle_instruction(cpu, run); break; + case ICPT_EXT_INT: + unmanageable_intercept(cpu, "external interrupt", + offsetof(LowCore, external_new_psw)); + r = EXCP_HALTED; + break; case ICPT_WAITPSW: /* disabled wait, since enabled wait is handled in kernel */ if (s390_del_running_cpu(cpu) == 0) { if (is_special_wait_psw(cs)) { qemu_system_shutdown_request(); } else { - QObject *data; - - data = qobject_from_jsonf("{ 'action': %s }", "pause"); - monitor_protocol_event(QEVENT_GUEST_PANICKED, data); - qobject_decref(data); - vm_stop(RUN_STATE_GUEST_PANICKED); + guest_panicked(); } } r = EXCP_HALTED; -- cgit v1.1 From 6449a41a4d4082ddb0a6e156c7e8932fe7d60fbf Mon Sep 17 00:00:00 2001 From: Thomas Huth Date: Wed, 7 May 2014 09:45:21 +0200 Subject: s390x/kvm: Log unmanageable program interruptions The kernel only drops to userspace if an endless program interrupt loop has been detected. Let's print an error message in this case to inform the user about the crash and stop the affected CPU with a panic event, just like it is already done for the external interruption loop detection. Signed-off-by: Thomas Huth Signed-off-by: Jens Freimann Reviewed-by: Cornelia Huck Signed-off-by: Cornelia Huck --- target-s390x/kvm.c | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/target-s390x/kvm.c b/target-s390x/kvm.c index be703bd..9adda1b 100644 --- a/target-s390x/kvm.c +++ b/target-s390x/kvm.c @@ -83,6 +83,7 @@ #define DIAG_KVM_BREAKPOINT 0x501 #define ICPT_INSTRUCTION 0x04 +#define ICPT_PROGRAM 0x08 #define ICPT_EXT_INT 0x14 #define ICPT_WAITPSW 0x1c #define ICPT_SOFT_INTERCEPT 0x24 @@ -966,6 +967,11 @@ static int handle_intercept(S390CPU *cpu) case ICPT_INSTRUCTION: r = handle_instruction(cpu, run); break; + case ICPT_PROGRAM: + unmanageable_intercept(cpu, "program interrupt", + offsetof(LowCore, program_new_psw)); + r = EXCP_HALTED; + break; case ICPT_EXT_INT: unmanageable_intercept(cpu, "external interrupt", offsetof(LowCore, external_new_psw)); -- cgit v1.1 From bcb2b582f35a34b5aee6bdafd93f3eabd9fca6ff Mon Sep 17 00:00:00 2001 From: Jens Freimann Date: Tue, 11 Feb 2014 13:29:44 +0100 Subject: s390/virtio-ccw: migration support This patch adds live migration support for virtio-ccw devices. It's not done with vmstate because virtio itself is not yet ported to vmstate either. Signed-off-by: Jens Freimann Signed-off-by: Cornelia Huck --- hw/s390x/css.c | 111 ++++++++++++++++++++++++++++++++++++++++++++++++++ hw/s390x/css.h | 2 + hw/s390x/virtio-ccw.c | 95 ++++++++++++++++++++++++++++++++++++++++++ 3 files changed, 208 insertions(+) diff --git a/hw/s390x/css.c b/hw/s390x/css.c index a813b23..67b22ae 100644 --- a/hw/s390x/css.c +++ b/hw/s390x/css.c @@ -1293,6 +1293,117 @@ int css_enable_mss(void) return 0; } +void subch_device_save(SubchDev *s, QEMUFile *f) +{ + int i; + + qemu_put_byte(f, s->cssid); + qemu_put_byte(f, s->ssid); + qemu_put_be16(f, s->schid); + qemu_put_be16(f, s->devno); + qemu_put_byte(f, s->thinint_active); + /* SCHIB */ + /* PMCW */ + qemu_put_be32(f, s->curr_status.pmcw.intparm); + qemu_put_be16(f, s->curr_status.pmcw.flags); + qemu_put_be16(f, s->curr_status.pmcw.devno); + qemu_put_byte(f, s->curr_status.pmcw.lpm); + qemu_put_byte(f, s->curr_status.pmcw.pnom); + qemu_put_byte(f, s->curr_status.pmcw.lpum); + qemu_put_byte(f, s->curr_status.pmcw.pim); + qemu_put_be16(f, s->curr_status.pmcw.mbi); + qemu_put_byte(f, s->curr_status.pmcw.pom); + qemu_put_byte(f, s->curr_status.pmcw.pam); + qemu_put_buffer(f, s->curr_status.pmcw.chpid, 8); + qemu_put_be32(f, s->curr_status.pmcw.chars); + /* SCSW */ + qemu_put_be16(f, s->curr_status.scsw.flags); + qemu_put_be16(f, s->curr_status.scsw.ctrl); + qemu_put_be32(f, s->curr_status.scsw.cpa); + qemu_put_byte(f, s->curr_status.scsw.dstat); + qemu_put_byte(f, s->curr_status.scsw.cstat); + qemu_put_be16(f, s->curr_status.scsw.count); + qemu_put_be64(f, s->curr_status.mba); + qemu_put_buffer(f, s->curr_status.mda, 4); + /* end SCHIB */ + qemu_put_buffer(f, s->sense_data, 32); + qemu_put_be64(f, s->channel_prog); + /* last cmd */ + qemu_put_byte(f, s->last_cmd.cmd_code); + qemu_put_byte(f, s->last_cmd.flags); + qemu_put_be16(f, s->last_cmd.count); + qemu_put_be32(f, s->last_cmd.cda); + qemu_put_byte(f, s->last_cmd_valid); + qemu_put_byte(f, s->id.reserved); + qemu_put_be16(f, s->id.cu_type); + qemu_put_byte(f, s->id.cu_model); + qemu_put_be16(f, s->id.dev_type); + qemu_put_byte(f, s->id.dev_model); + qemu_put_byte(f, s->id.unused); + for (i = 0; i < ARRAY_SIZE(s->id.ciw); i++) { + qemu_put_byte(f, s->id.ciw[i].type); + qemu_put_byte(f, s->id.ciw[i].command); + qemu_put_be16(f, s->id.ciw[i].count); + } + return; +} + +int subch_device_load(SubchDev *s, QEMUFile *f) +{ + int i; + + s->cssid = qemu_get_byte(f); + s->ssid = qemu_get_byte(f); + s->schid = qemu_get_be16(f); + s->devno = qemu_get_be16(f); + s->thinint_active = qemu_get_byte(f); + /* SCHIB */ + /* PMCW */ + s->curr_status.pmcw.intparm = qemu_get_be32(f); + s->curr_status.pmcw.flags = qemu_get_be16(f); + s->curr_status.pmcw.devno = qemu_get_be16(f); + s->curr_status.pmcw.lpm = qemu_get_byte(f); + s->curr_status.pmcw.pnom = qemu_get_byte(f); + s->curr_status.pmcw.lpum = qemu_get_byte(f); + s->curr_status.pmcw.pim = qemu_get_byte(f); + s->curr_status.pmcw.mbi = qemu_get_be16(f); + s->curr_status.pmcw.pom = qemu_get_byte(f); + s->curr_status.pmcw.pam = qemu_get_byte(f); + qemu_get_buffer(f, s->curr_status.pmcw.chpid, 8); + s->curr_status.pmcw.chars = qemu_get_be32(f); + /* SCSW */ + s->curr_status.scsw.flags = qemu_get_be16(f); + s->curr_status.scsw.ctrl = qemu_get_be16(f); + s->curr_status.scsw.cpa = qemu_get_be32(f); + s->curr_status.scsw.dstat = qemu_get_byte(f); + s->curr_status.scsw.cstat = qemu_get_byte(f); + s->curr_status.scsw.count = qemu_get_be16(f); + s->curr_status.mba = qemu_get_be64(f); + qemu_get_buffer(f, s->curr_status.mda, 4); + /* end SCHIB */ + qemu_get_buffer(f, s->sense_data, 32); + s->channel_prog = qemu_get_be64(f); + /* last cmd */ + s->last_cmd.cmd_code = qemu_get_byte(f); + s->last_cmd.flags = qemu_get_byte(f); + s->last_cmd.count = qemu_get_be16(f); + s->last_cmd.cda = qemu_get_be32(f); + s->last_cmd_valid = qemu_get_byte(f); + s->id.reserved = qemu_get_byte(f); + s->id.cu_type = qemu_get_be16(f); + s->id.cu_model = qemu_get_byte(f); + s->id.dev_type = qemu_get_be16(f); + s->id.dev_model = qemu_get_byte(f); + s->id.unused = qemu_get_byte(f); + for (i = 0; i < ARRAY_SIZE(s->id.ciw); i++) { + s->id.ciw[i].type = qemu_get_byte(f); + s->id.ciw[i].command = qemu_get_byte(f); + s->id.ciw[i].count = qemu_get_be16(f); + } + return 0; +} + + static void css_init(void) { channel_subsys = g_malloc0(sizeof(*channel_subsys)); diff --git a/hw/s390x/css.h b/hw/s390x/css.h index 6586106..c864ea7 100644 --- a/hw/s390x/css.h +++ b/hw/s390x/css.h @@ -85,6 +85,8 @@ struct SubchDev { typedef SubchDev *(*css_subch_cb_func)(uint8_t m, uint8_t cssid, uint8_t ssid, uint16_t schid); +void subch_device_save(SubchDev *s, QEMUFile *f); +int subch_device_load(SubchDev *s, QEMUFile *f); int css_create_css_image(uint8_t cssid, bool default_image); bool css_devno_used(uint8_t cssid, uint8_t ssid, uint16_t devno); void css_subch_assign(uint8_t cssid, uint8_t ssid, uint16_t schid, diff --git a/hw/s390x/virtio-ccw.c b/hw/s390x/virtio-ccw.c index c4f21d3..05656a2 100644 --- a/hw/s390x/virtio-ccw.c +++ b/hw/s390x/virtio-ccw.c @@ -1275,6 +1275,97 @@ irqroute_error: return r; } +static void virtio_ccw_save_queue(DeviceState *d, int n, QEMUFile *f) +{ + VirtioCcwDevice *dev = VIRTIO_CCW_DEVICE(d); + VirtIODevice *vdev = virtio_bus_get_device(&dev->bus); + + qemu_put_be16(f, virtio_queue_vector(vdev, n)); +} + +static int virtio_ccw_load_queue(DeviceState *d, int n, QEMUFile *f) +{ + VirtioCcwDevice *dev = VIRTIO_CCW_DEVICE(d); + VirtIODevice *vdev = virtio_bus_get_device(&dev->bus); + uint16_t vector; + + qemu_get_be16s(f, &vector); + virtio_queue_set_vector(vdev, n , vector); + + return 0; +} + +static void virtio_ccw_save_config(DeviceState *d, QEMUFile *f) +{ + VirtioCcwDevice *dev = VIRTIO_CCW_DEVICE(d); + SubchDev *s = dev->sch; + + subch_device_save(s, f); + if (dev->indicators != NULL) { + qemu_put_be32(f, dev->indicators->len); + qemu_put_be64(f, dev->indicators->addr); + } else { + qemu_put_be32(f, 0); + qemu_put_be64(f, 0UL); + } + if (dev->indicators2 != NULL) { + qemu_put_be32(f, dev->indicators2->len); + qemu_put_be64(f, dev->indicators2->addr); + } else { + qemu_put_be32(f, 0); + qemu_put_be64(f, 0UL); + } + if (dev->summary_indicator != NULL) { + qemu_put_be32(f, dev->summary_indicator->len); + qemu_put_be64(f, dev->summary_indicator->addr); + } else { + qemu_put_be32(f, 0); + qemu_put_be64(f, 0UL); + } + qemu_put_be64(f, dev->routes.adapter.ind_offset); + qemu_put_byte(f, dev->thinint_isc); +} + +static int virtio_ccw_load_config(DeviceState *d, QEMUFile *f) +{ + VirtioCcwDevice *dev = VIRTIO_CCW_DEVICE(d); + SubchDev *s = dev->sch; + int len; + + s->driver_data = dev; + subch_device_load(s, f); + len = qemu_get_be32(f); + if (len != 0) { + dev->indicators = get_indicator(qemu_get_be64(f), len); + } else { + qemu_get_be64(f); + dev->indicators = NULL; + } + len = qemu_get_be32(f); + if (len != 0) { + dev->indicators2 = get_indicator(qemu_get_be64(f), len); + } else { + qemu_get_be64(f); + dev->indicators2 = NULL; + } + len = qemu_get_be32(f); + if (len != 0) { + dev->summary_indicator = get_indicator(qemu_get_be64(f), len); + } else { + qemu_get_be64(f); + dev->summary_indicator = NULL; + } + dev->routes.adapter.ind_offset = qemu_get_be64(f); + dev->thinint_isc = qemu_get_byte(f); + if (s->thinint_active) { + return css_register_io_adapter(CSS_IO_ADAPTER_VIRTIO, + dev->thinint_isc, true, false, + &dev->routes.adapter.adapter_id); + } + + return 0; +} + /**************** Virtio-ccw Bus Device Descriptions *******************/ static Property virtio_ccw_net_properties[] = { @@ -1597,6 +1688,10 @@ static void virtio_ccw_bus_class_init(ObjectClass *klass, void *data) k->query_guest_notifiers = virtio_ccw_query_guest_notifiers; k->set_host_notifier = virtio_ccw_set_host_notifier; k->set_guest_notifiers = virtio_ccw_set_guest_notifiers; + k->save_queue = virtio_ccw_save_queue; + k->load_queue = virtio_ccw_load_queue; + k->save_config = virtio_ccw_save_config; + k->load_config = virtio_ccw_load_config; } static const TypeInfo virtio_ccw_bus_info = { -- cgit v1.1 From 79afc36d91be7550affbe7db227b4552451da41d Mon Sep 17 00:00:00 2001 From: Cornelia Huck Date: Tue, 11 Mar 2014 13:52:06 +0100 Subject: s390x: consolidate floating interrupts Move the injection code for all floating interrupts to interrupt.c and add a comment. Also get rid of the #ifdef CONFIG_KVM for the service interrupt. Reviewed-by: Thomas Huth Signed-off-by: Cornelia Huck --- hw/s390x/s390-virtio-bus.c | 11 ----------- target-s390x/cpu.h | 32 +++++++++----------------------- target-s390x/interrupt.c | 44 ++++++++++++++++++++++++++++++++++++++------ target-s390x/kvm.c | 5 +++++ 4 files changed, 52 insertions(+), 40 deletions(-) diff --git a/hw/s390x/s390-virtio-bus.c b/hw/s390x/s390-virtio-bus.c index 9c71afa..45c6b1f 100644 --- a/hw/s390x/s390-virtio-bus.c +++ b/hw/s390x/s390-virtio-bus.c @@ -45,8 +45,6 @@ do { } while (0) #endif -#define VIRTIO_EXT_CODE 0x2603 - static void virtio_s390_bus_new(VirtioBusState *bus, size_t bus_size, VirtIOS390Device *dev); @@ -113,15 +111,6 @@ VirtIOS390Bus *s390_virtio_bus_init(ram_addr_t *ram_size) return bus; } -static void s390_virtio_irq(S390CPU *cpu, int config_change, uint64_t token) -{ - if (kvm_enabled()) { - kvm_s390_virtio_irq(cpu, config_change, token); - } else { - cpu_inject_ext(cpu, VIRTIO_EXT_CODE, config_change, token); - } -} - static int s390_virtio_device_init(VirtIOS390Device *dev, VirtIODevice *vdev) { VirtIOS390Bus *bus; diff --git a/target-s390x/cpu.h b/target-s390x/cpu.h index 808b906..5940f22 100644 --- a/target-s390x/cpu.h +++ b/target-s390x/cpu.h @@ -357,6 +357,7 @@ void s390x_tod_timer(void *opaque); void s390x_cpu_timer(void *opaque); int s390_virtio_hypercall(CPUS390XState *env); +void s390_virtio_irq(S390CPU *cpu, int config_change, uint64_t token); #ifdef CONFIG_KVM void kvm_s390_reset_vcpu(S390CPU *cpu); @@ -364,6 +365,7 @@ void kvm_s390_interrupt(S390CPU *cpu, int type, uint32_t code); void kvm_s390_virtio_irq(S390CPU *cpu, int config_change, uint64_t token); void kvm_s390_interrupt_internal(S390CPU *cpu, int type, uint32_t parm, uint64_t parm64, int vm); +void kvm_s390_service_interrupt(S390CPU *cpu, uint32_t parm); #else static inline void kvm_s390_reset_vcpu(S390CPU *cpu) { @@ -383,6 +385,9 @@ static inline void kvm_s390_interrupt_internal(S390CPU *cpu, int type, int vm) { } +static inline void kvm_s390_service_interrupt(S390CPU *cpu, uint32_t parm) +{ +} #endif S390CPU *s390_cpu_addr2state(uint16_t cpu_addr); void s390_add_running_cpu(S390CPU *cpu); @@ -1120,29 +1125,10 @@ static inline int s390_cpu_restart(S390CPU *cpu) return -ENOSYS; } -static inline void s390_io_interrupt(S390CPU *cpu, - uint16_t subchannel_id, - uint16_t subchannel_nr, - uint32_t io_int_parm, - uint32_t io_int_word) -{ - if (kvm_enabled()) { - kvm_s390_io_interrupt(cpu, subchannel_id, subchannel_nr, io_int_parm, - io_int_word); - } else { - cpu_inject_io(cpu, subchannel_id, subchannel_nr, io_int_parm, - io_int_word); - } -} - -static inline void s390_crw_mchk(S390CPU *cpu) -{ - if (kvm_enabled()) { - kvm_s390_crw_mchk(cpu); - } else { - cpu_inject_crw_mchk(cpu); - } -} +void s390_io_interrupt(S390CPU *cpu, uint16_t subchannel_id, + uint16_t subchannel_nr, uint32_t io_int_parm, + uint32_t io_int_word); +void s390_crw_mchk(S390CPU *cpu); static inline int s390_assign_subch_ioeventfd(EventNotifier *notifier, uint32_t sch_id, int vq, diff --git a/target-s390x/interrupt.c b/target-s390x/interrupt.c index 6d6580d..c32bdcb 100644 --- a/target-s390x/interrupt.c +++ b/target-s390x/interrupt.c @@ -1,7 +1,7 @@ /* * QEMU S/390 Interrupt support * - * Copyright IBM, Corp. 2012 + * Copyright IBM Corp. 2012, 2014 * * This work is licensed under the terms of the GNU GPL, version 2 or (at your * option) any later version. See the COPYING file in the top-level directory. @@ -10,21 +10,53 @@ #include "cpu.h" #include "sysemu/kvm.h" +/* + * All of the following interrupts are floating, i.e. not per-vcpu. + * We just need a dummy cpustate in order to be able to inject. + */ #if !defined(CONFIG_USER_ONLY) -/* service interrupts are floating therefore we must not pass an cpustate */ void s390_sclp_extint(uint32_t parm) { S390CPU *dummy_cpu = s390_cpu_addr2state(0); CPUS390XState *env = &dummy_cpu->env; if (kvm_enabled()) { -#ifdef CONFIG_KVM - kvm_s390_interrupt_internal(dummy_cpu, KVM_S390_INT_SERVICE, parm, - 0, 1); -#endif + kvm_s390_service_interrupt(dummy_cpu, parm); } else { env->psw.addr += 4; cpu_inject_ext(dummy_cpu, EXT_SERVICE, parm, 0); } } + +void s390_virtio_irq(S390CPU *cpu, int config_change, uint64_t token) +{ + if (kvm_enabled()) { + kvm_s390_virtio_irq(cpu, config_change, token); + } else { + cpu_inject_ext(cpu, EXT_VIRTIO, config_change, token); + } +} + +void s390_io_interrupt(S390CPU *cpu, uint16_t subchannel_id, + uint16_t subchannel_nr, uint32_t io_int_parm, + uint32_t io_int_word) +{ + if (kvm_enabled()) { + kvm_s390_io_interrupt(cpu, subchannel_id, subchannel_nr, io_int_parm, + io_int_word); + } else { + cpu_inject_io(cpu, subchannel_id, subchannel_nr, io_int_parm, + io_int_word); + } +} + +void s390_crw_mchk(S390CPU *cpu) +{ + if (kvm_enabled()) { + kvm_s390_crw_mchk(cpu); + } else { + cpu_inject_crw_mchk(cpu); + } +} + #endif diff --git a/target-s390x/kvm.c b/target-s390x/kvm.c index 9adda1b..9474f81 100644 --- a/target-s390x/kvm.c +++ b/target-s390x/kvm.c @@ -593,6 +593,11 @@ void kvm_s390_interrupt(S390CPU *cpu, int type, uint32_t code) kvm_s390_interrupt_internal(cpu, type, code, 0, 0); } +void kvm_s390_service_interrupt(S390CPU *cpu, uint32_t parm) +{ + kvm_s390_interrupt_internal(cpu, KVM_S390_INT_SERVICE, parm, 0 , 1); +} + static void enter_pgmcheck(S390CPU *cpu, uint16_t code) { kvm_s390_interrupt(cpu, KVM_S390_PROGRAM_INT, code); -- cgit v1.1 From 66ad0893f07f194b5c8607cb81061b8d7202511c Mon Sep 17 00:00:00 2001 From: Cornelia Huck Date: Tue, 11 Mar 2014 17:10:07 +0100 Subject: s390x/kvm: add alternative injection interface Add kvm_s390_{vcpu,floating}_interrupt, which offer the possibility to inject interrupts with larger payloads (when a kvm backend becomes available). Moreover, kvm_s390_floating_interrupt() does no longer have the bogus requirement for a vcpu. Signed-off-by: Cornelia Huck --- target-s390x/cpu.h | 2 ++ target-s390x/kvm.c | 86 ++++++++++++++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 88 insertions(+) diff --git a/target-s390x/cpu.h b/target-s390x/cpu.h index 5940f22..644d126 100644 --- a/target-s390x/cpu.h +++ b/target-s390x/cpu.h @@ -366,6 +366,8 @@ void kvm_s390_virtio_irq(S390CPU *cpu, int config_change, uint64_t token); void kvm_s390_interrupt_internal(S390CPU *cpu, int type, uint32_t parm, uint64_t parm64, int vm); void kvm_s390_service_interrupt(S390CPU *cpu, uint32_t parm); +void kvm_s390_vcpu_interrupt(S390CPU *cpu, struct kvm_s390_irq *irq); +void kvm_s390_floating_interrupt(struct kvm_s390_irq *irq); #else static inline void kvm_s390_reset_vcpu(S390CPU *cpu) { diff --git a/target-s390x/kvm.c b/target-s390x/kvm.c index 9474f81..0d36ab4 100644 --- a/target-s390x/kvm.c +++ b/target-s390x/kvm.c @@ -555,6 +555,92 @@ int kvm_arch_process_async_events(CPUState *cs) return cs->halted; } +static int s390_kvm_irq_to_interrupt(struct kvm_s390_irq *irq, + struct kvm_s390_interrupt *interrupt) +{ + int r = 0; + + interrupt->type = irq->type; + switch (irq->type) { + case KVM_S390_INT_VIRTIO: + interrupt->parm = irq->u.ext.ext_params; + /* fall through */ + case KVM_S390_INT_PFAULT_INIT: + case KVM_S390_INT_PFAULT_DONE: + interrupt->parm64 = irq->u.ext.ext_params2; + break; + case KVM_S390_PROGRAM_INT: + interrupt->parm = irq->u.pgm.code; + break; + case KVM_S390_SIGP_SET_PREFIX: + interrupt->parm = irq->u.prefix.address; + break; + case KVM_S390_INT_SERVICE: + interrupt->parm = irq->u.ext.ext_params; + break; + case KVM_S390_MCHK: + interrupt->parm = irq->u.mchk.cr14; + interrupt->parm64 = irq->u.mchk.mcic; + break; + case KVM_S390_INT_EXTERNAL_CALL: + interrupt->parm = irq->u.extcall.code; + break; + case KVM_S390_INT_EMERGENCY: + interrupt->parm = irq->u.emerg.code; + break; + case KVM_S390_SIGP_STOP: + case KVM_S390_RESTART: + break; /* These types have no parameters */ + case KVM_S390_INT_IO_MIN...KVM_S390_INT_IO_MAX: + interrupt->parm = irq->u.io.subchannel_id << 16; + interrupt->parm |= irq->u.io.subchannel_nr; + interrupt->parm64 = (uint64_t)irq->u.io.io_int_parm << 32; + interrupt->parm64 |= irq->u.io.io_int_word; + break; + default: + r = -EINVAL; + break; + } + return r; +} + +void kvm_s390_vcpu_interrupt(S390CPU *cpu, struct kvm_s390_irq *irq) +{ + struct kvm_s390_interrupt kvmint = {}; + CPUState *cs = CPU(cpu); + int r; + + r = s390_kvm_irq_to_interrupt(irq, &kvmint); + if (r < 0) { + fprintf(stderr, "%s called with bogus interrupt\n", __func__); + exit(1); + } + + r = kvm_vcpu_ioctl(cs, KVM_S390_INTERRUPT, &kvmint); + if (r < 0) { + fprintf(stderr, "KVM failed to inject interrupt\n"); + exit(1); + } +} + +void kvm_s390_floating_interrupt(struct kvm_s390_irq *irq) +{ + struct kvm_s390_interrupt kvmint = {}; + int r; + + r = s390_kvm_irq_to_interrupt(irq, &kvmint); + if (r < 0) { + fprintf(stderr, "%s called with bogus interrupt\n", __func__); + exit(1); + } + + r = kvm_vm_ioctl(kvm_state, KVM_S390_INTERRUPT, &kvmint); + if (r < 0) { + fprintf(stderr, "KVM failed to inject interrupt\n"); + exit(1); + } +} + void kvm_s390_interrupt_internal(S390CPU *cpu, int type, uint32_t parm, uint64_t parm64, int vm) { -- cgit v1.1 From de13d2161473d02ae97ec0f8e4503147554892dd Mon Sep 17 00:00:00 2001 From: Cornelia Huck Date: Tue, 11 Mar 2014 13:19:43 +0100 Subject: s390x: cleanup interrupt injection Remove the need for a cpu to inject a floating interrupt on kvm. Acked-by: Thomas Huth Signed-off-by: Cornelia Huck --- hw/s390x/css.c | 15 ++----- hw/s390x/s390-virtio-bus.c | 6 +-- target-s390x/cpu.h | 41 ++++++------------ target-s390x/interrupt.c | 38 ++++++++++------- target-s390x/kvm.c | 104 ++++++++++++++++++++------------------------- target-s390x/misc_helper.c | 7 ++- 6 files changed, 91 insertions(+), 120 deletions(-) diff --git a/hw/s390x/css.c b/hw/s390x/css.c index 67b22ae..e758890 100644 --- a/hw/s390x/css.c +++ b/hw/s390x/css.c @@ -128,13 +128,11 @@ uint16_t css_build_subchannel_id(SubchDev *sch) static void css_inject_io_interrupt(SubchDev *sch) { - S390CPU *cpu = s390_cpu_addr2state(0); uint8_t isc = (sch->curr_status.pmcw.flags & PMCW_FLAGS_MASK_ISC) >> 11; trace_css_io_interrupt(sch->cssid, sch->ssid, sch->schid, sch->curr_status.pmcw.intparm, isc, ""); - s390_io_interrupt(cpu, - css_build_subchannel_id(sch), + s390_io_interrupt(css_build_subchannel_id(sch), sch->schid, sch->curr_status.pmcw.intparm, isc << 27); @@ -147,7 +145,6 @@ void css_conditional_io_interrupt(SubchDev *sch) * with alert status. */ if (!(sch->curr_status.scsw.ctrl & SCSW_STCTL_STATUS_PEND)) { - S390CPU *cpu = s390_cpu_addr2state(0); uint8_t isc = (sch->curr_status.pmcw.flags & PMCW_FLAGS_MASK_ISC) >> 11; trace_css_io_interrupt(sch->cssid, sch->ssid, sch->schid, @@ -157,8 +154,7 @@ void css_conditional_io_interrupt(SubchDev *sch) sch->curr_status.scsw.ctrl |= SCSW_STCTL_ALERT | SCSW_STCTL_STATUS_PEND; /* Inject an I/O interrupt. */ - s390_io_interrupt(cpu, - css_build_subchannel_id(sch), + s390_io_interrupt(css_build_subchannel_id(sch), sch->schid, sch->curr_status.pmcw.intparm, isc << 27); @@ -167,11 +163,10 @@ void css_conditional_io_interrupt(SubchDev *sch) void css_adapter_interrupt(uint8_t isc) { - S390CPU *cpu = s390_cpu_addr2state(0); uint32_t io_int_word = (isc << 27) | IO_INT_WORD_AI; trace_css_adapter_interrupt(isc); - s390_io_interrupt(cpu, 0, 0, 0, io_int_word); + s390_io_interrupt(0, 0, 0, io_int_word); } static void sch_handle_clear_func(SubchDev *sch) @@ -1231,11 +1226,9 @@ void css_queue_crw(uint8_t rsc, uint8_t erc, int chain, uint16_t rsid) QTAILQ_INSERT_TAIL(&channel_subsys->pending_crws, crw_cont, sibling); if (channel_subsys->do_crw_mchk) { - S390CPU *cpu = s390_cpu_addr2state(0); - channel_subsys->do_crw_mchk = false; /* Inject crw pending machine check. */ - s390_crw_mchk(cpu); + s390_crw_mchk(); } } diff --git a/hw/s390x/s390-virtio-bus.c b/hw/s390x/s390-virtio-bus.c index 45c6b1f..7c8c81b 100644 --- a/hw/s390x/s390-virtio-bus.c +++ b/hw/s390x/s390-virtio-bus.c @@ -133,8 +133,7 @@ static int s390_virtio_device_init(VirtIOS390Device *dev, VirtIODevice *vdev) s390_virtio_device_sync(dev); s390_virtio_reset_idx(dev); if (dev->qdev.hotplugged) { - S390CPU *cpu = s390_cpu_addr2state(0); - s390_virtio_irq(cpu, VIRTIO_PARAM_DEV_ADD, dev->dev_offs); + s390_virtio_irq(VIRTIO_PARAM_DEV_ADD, dev->dev_offs); } return 0; @@ -478,9 +477,8 @@ static void virtio_s390_notify(DeviceState *d, uint16_t vector) { VirtIOS390Device *dev = to_virtio_s390_device_fast(d); uint64_t token = s390_virtio_device_vq_token(dev, vector); - S390CPU *cpu = s390_cpu_addr2state(0); - s390_virtio_irq(cpu, 0, token); + s390_virtio_irq(0, token); } static unsigned virtio_s390_get_features(DeviceState *d) diff --git a/target-s390x/cpu.h b/target-s390x/cpu.h index 644d126..9982c35 100644 --- a/target-s390x/cpu.h +++ b/target-s390x/cpu.h @@ -357,37 +357,22 @@ void s390x_tod_timer(void *opaque); void s390x_cpu_timer(void *opaque); int s390_virtio_hypercall(CPUS390XState *env); -void s390_virtio_irq(S390CPU *cpu, int config_change, uint64_t token); +void s390_virtio_irq(int config_change, uint64_t token); #ifdef CONFIG_KVM void kvm_s390_reset_vcpu(S390CPU *cpu); -void kvm_s390_interrupt(S390CPU *cpu, int type, uint32_t code); -void kvm_s390_virtio_irq(S390CPU *cpu, int config_change, uint64_t token); -void kvm_s390_interrupt_internal(S390CPU *cpu, int type, uint32_t parm, - uint64_t parm64, int vm); -void kvm_s390_service_interrupt(S390CPU *cpu, uint32_t parm); +void kvm_s390_virtio_irq(int config_change, uint64_t token); +void kvm_s390_service_interrupt(uint32_t parm); void kvm_s390_vcpu_interrupt(S390CPU *cpu, struct kvm_s390_irq *irq); void kvm_s390_floating_interrupt(struct kvm_s390_irq *irq); #else static inline void kvm_s390_reset_vcpu(S390CPU *cpu) { } - -static inline void kvm_s390_interrupt(S390CPU *cpu, int type, uint32_t code) -{ -} - -static inline void kvm_s390_virtio_irq(S390CPU *cpu, int config_change, - uint64_t token) -{ -} - -static inline void kvm_s390_interrupt_internal(S390CPU *cpu, int type, - uint32_t parm, uint64_t parm64, - int vm) +static inline void kvm_s390_virtio_irq(int config_change, uint64_t token) { } -static inline void kvm_s390_service_interrupt(S390CPU *cpu, uint32_t parm) +static inline void kvm_s390_service_interrupt(uint32_t parm) { } #endif @@ -1073,24 +1058,23 @@ void QEMU_NORETURN runtime_exception(CPUS390XState *env, int excp, uintptr_t retaddr); #ifdef CONFIG_KVM -void kvm_s390_io_interrupt(S390CPU *cpu, uint16_t subchannel_id, +void kvm_s390_io_interrupt(uint16_t subchannel_id, uint16_t subchannel_nr, uint32_t io_int_parm, uint32_t io_int_word); -void kvm_s390_crw_mchk(S390CPU *cpu); +void kvm_s390_crw_mchk(void); void kvm_s390_enable_css_support(S390CPU *cpu); int kvm_s390_assign_subch_ioeventfd(EventNotifier *notifier, uint32_t sch, int vq, bool assign); int kvm_s390_cpu_restart(S390CPU *cpu); void kvm_s390_clear_cmma_callback(void *opaque); #else -static inline void kvm_s390_io_interrupt(S390CPU *cpu, - uint16_t subchannel_id, +static inline void kvm_s390_io_interrupt(uint16_t subchannel_id, uint16_t subchannel_nr, uint32_t io_int_parm, uint32_t io_int_word) { } -static inline void kvm_s390_crw_mchk(S390CPU *cpu) +static inline void kvm_s390_crw_mchk(void) { } static inline void kvm_s390_enable_css_support(S390CPU *cpu) @@ -1127,10 +1111,9 @@ static inline int s390_cpu_restart(S390CPU *cpu) return -ENOSYS; } -void s390_io_interrupt(S390CPU *cpu, uint16_t subchannel_id, - uint16_t subchannel_nr, uint32_t io_int_parm, - uint32_t io_int_word); -void s390_crw_mchk(S390CPU *cpu); +void s390_io_interrupt(uint16_t subchannel_id, uint16_t subchannel_nr, + uint32_t io_int_parm, uint32_t io_int_word); +void s390_crw_mchk(void); static inline int s390_assign_subch_ioeventfd(EventNotifier *notifier, uint32_t sch_id, int vq, diff --git a/target-s390x/interrupt.c b/target-s390x/interrupt.c index c32bdcb..23a9114 100644 --- a/target-s390x/interrupt.c +++ b/target-s390x/interrupt.c @@ -12,50 +12,56 @@ /* * All of the following interrupts are floating, i.e. not per-vcpu. - * We just need a dummy cpustate in order to be able to inject. + * We just need a dummy cpustate in order to be able to inject in the + * non-kvm case. */ #if !defined(CONFIG_USER_ONLY) void s390_sclp_extint(uint32_t parm) { - S390CPU *dummy_cpu = s390_cpu_addr2state(0); - CPUS390XState *env = &dummy_cpu->env; - if (kvm_enabled()) { - kvm_s390_service_interrupt(dummy_cpu, parm); + kvm_s390_service_interrupt(parm); } else { + S390CPU *dummy_cpu = s390_cpu_addr2state(0); + CPUS390XState *env = &dummy_cpu->env; + env->psw.addr += 4; cpu_inject_ext(dummy_cpu, EXT_SERVICE, parm, 0); } } -void s390_virtio_irq(S390CPU *cpu, int config_change, uint64_t token) +void s390_virtio_irq(int config_change, uint64_t token) { if (kvm_enabled()) { - kvm_s390_virtio_irq(cpu, config_change, token); + kvm_s390_virtio_irq(config_change, token); } else { - cpu_inject_ext(cpu, EXT_VIRTIO, config_change, token); + S390CPU *dummy_cpu = s390_cpu_addr2state(0); + + cpu_inject_ext(dummy_cpu, EXT_VIRTIO, config_change, token); } } -void s390_io_interrupt(S390CPU *cpu, uint16_t subchannel_id, - uint16_t subchannel_nr, uint32_t io_int_parm, - uint32_t io_int_word) +void s390_io_interrupt(uint16_t subchannel_id, uint16_t subchannel_nr, + uint32_t io_int_parm, uint32_t io_int_word) { if (kvm_enabled()) { - kvm_s390_io_interrupt(cpu, subchannel_id, subchannel_nr, io_int_parm, + kvm_s390_io_interrupt(subchannel_id, subchannel_nr, io_int_parm, io_int_word); } else { - cpu_inject_io(cpu, subchannel_id, subchannel_nr, io_int_parm, + S390CPU *dummy_cpu = s390_cpu_addr2state(0); + + cpu_inject_io(dummy_cpu, subchannel_id, subchannel_nr, io_int_parm, io_int_word); } } -void s390_crw_mchk(S390CPU *cpu) +void s390_crw_mchk(void) { if (kvm_enabled()) { - kvm_s390_crw_mchk(cpu); + kvm_s390_crw_mchk(); } else { - cpu_inject_crw_mchk(cpu); + S390CPU *dummy_cpu = s390_cpu_addr2state(0); + + cpu_inject_crw_mchk(dummy_cpu); } } diff --git a/target-s390x/kvm.c b/target-s390x/kvm.c index 0d36ab4..a2133ff 100644 --- a/target-s390x/kvm.c +++ b/target-s390x/kvm.c @@ -641,52 +641,35 @@ void kvm_s390_floating_interrupt(struct kvm_s390_irq *irq) } } -void kvm_s390_interrupt_internal(S390CPU *cpu, int type, uint32_t parm, - uint64_t parm64, int vm) +void kvm_s390_virtio_irq(int config_change, uint64_t token) { - CPUState *cs = CPU(cpu); - struct kvm_s390_interrupt kvmint; - int r; - - if (!cs->kvm_state) { - return; - } - - kvmint.type = type; - kvmint.parm = parm; - kvmint.parm64 = parm64; - - if (vm) { - r = kvm_vm_ioctl(cs->kvm_state, KVM_S390_INTERRUPT, &kvmint); - } else { - r = kvm_vcpu_ioctl(cs, KVM_S390_INTERRUPT, &kvmint); - } - - if (r < 0) { - fprintf(stderr, "KVM failed to inject interrupt\n"); - exit(1); - } -} + struct kvm_s390_irq irq = { + .type = KVM_S390_INT_VIRTIO, + .u.ext.ext_params = config_change, + .u.ext.ext_params2 = token, + }; -void kvm_s390_virtio_irq(S390CPU *cpu, int config_change, uint64_t token) -{ - kvm_s390_interrupt_internal(cpu, KVM_S390_INT_VIRTIO, config_change, - token, 1); + kvm_s390_floating_interrupt(&irq); } -void kvm_s390_interrupt(S390CPU *cpu, int type, uint32_t code) +void kvm_s390_service_interrupt(uint32_t parm) { - kvm_s390_interrupt_internal(cpu, type, code, 0, 0); -} + struct kvm_s390_irq irq = { + .type = KVM_S390_INT_SERVICE, + .u.ext.ext_params = parm, + }; -void kvm_s390_service_interrupt(S390CPU *cpu, uint32_t parm) -{ - kvm_s390_interrupt_internal(cpu, KVM_S390_INT_SERVICE, parm, 0 , 1); + kvm_s390_floating_interrupt(&irq); } static void enter_pgmcheck(S390CPU *cpu, uint16_t code) { - kvm_s390_interrupt(cpu, KVM_S390_PROGRAM_INT, code); + struct kvm_s390_irq irq = { + .type = KVM_S390_PROGRAM_INT, + .u.pgm.code = code, + }; + + kvm_s390_vcpu_interrupt(cpu, &irq); } static int kvm_sclp_service_call(S390CPU *cpu, struct kvm_run *run, @@ -902,7 +885,11 @@ static int kvm_s390_cpu_start(S390CPU *cpu) int kvm_s390_cpu_restart(S390CPU *cpu) { - kvm_s390_interrupt(cpu, KVM_S390_RESTART, 0); + struct kvm_s390_irq irq = { + .type = KVM_S390_RESTART, + }; + + kvm_s390_vcpu_interrupt(cpu, &irq); s390_add_running_cpu(cpu); qemu_cpu_kick(CPU(cpu)); DPRINTF("DONE: KVM cpu restart: %p\n", &cpu->env); @@ -1122,18 +1109,10 @@ static int handle_tsch(S390CPU *cpu) * If an I/O interrupt had been dequeued, we have to reinject it. */ if (run->s390_tsch.dequeued) { - uint16_t subchannel_id = run->s390_tsch.subchannel_id; - uint16_t subchannel_nr = run->s390_tsch.subchannel_nr; - uint32_t io_int_parm = run->s390_tsch.io_int_parm; - uint32_t io_int_word = run->s390_tsch.io_int_word; - uint32_t type = ((subchannel_id & 0xff00) << 24) | - ((subchannel_id & 0x00060) << 22) | (subchannel_nr << 16); - - kvm_s390_interrupt_internal(cpu, type, - ((uint32_t)subchannel_id << 16) - | subchannel_nr, - ((uint64_t)io_int_parm << 32) - | io_int_word, 1); + kvm_s390_io_interrupt(run->s390_tsch.subchannel_id, + run->s390_tsch.subchannel_nr, + run->s390_tsch.io_int_parm, + run->s390_tsch.io_int_word); } ret = 0; } @@ -1218,27 +1197,34 @@ int kvm_arch_on_sigbus(int code, void *addr) return 1; } -void kvm_s390_io_interrupt(S390CPU *cpu, uint16_t subchannel_id, +void kvm_s390_io_interrupt(uint16_t subchannel_id, uint16_t subchannel_nr, uint32_t io_int_parm, uint32_t io_int_word) { - uint32_t type; + struct kvm_s390_irq irq = { + .u.io.subchannel_id = subchannel_id, + .u.io.subchannel_nr = subchannel_nr, + .u.io.io_int_parm = io_int_parm, + .u.io.io_int_word = io_int_word, + }; if (io_int_word & IO_INT_WORD_AI) { - type = KVM_S390_INT_IO(1, 0, 0, 0); + irq.type = KVM_S390_INT_IO(1, 0, 0, 0); } else { - type = ((subchannel_id & 0xff00) << 24) | + irq.type = ((subchannel_id & 0xff00) << 24) | ((subchannel_id & 0x00060) << 22) | (subchannel_nr << 16); } - kvm_s390_interrupt_internal(cpu, type, - ((uint32_t)subchannel_id << 16) | subchannel_nr, - ((uint64_t)io_int_parm << 32) | io_int_word, 1); + kvm_s390_floating_interrupt(&irq); } -void kvm_s390_crw_mchk(S390CPU *cpu) +void kvm_s390_crw_mchk(void) { - kvm_s390_interrupt_internal(cpu, KVM_S390_MCHK, 1 << 28, - 0x00400f1d40330000, 1); + struct kvm_s390_irq irq = { + .type = KVM_S390_MCHK, + .u.mchk.cr14 = 1 << 28, + .u.mchk.mcic = 0x00400f1d40330000, + }; + kvm_s390_floating_interrupt(&irq); } void kvm_s390_enable_css_support(S390CPU *cpu) diff --git a/target-s390x/misc_helper.c b/target-s390x/misc_helper.c index 519edb8..0b62582 100644 --- a/target-s390x/misc_helper.c +++ b/target-s390x/misc_helper.c @@ -85,7 +85,12 @@ void program_interrupt(CPUS390XState *env, uint32_t code, int ilen) if (kvm_enabled()) { #ifdef CONFIG_KVM - kvm_s390_interrupt(cpu, KVM_S390_PROGRAM_INT, code); + struct kvm_s390_irq irq = { + .type = KVM_S390_PROGRAM_INT, + .u.pgm.code = code, + }; + + kvm_s390_vcpu_interrupt(cpu, &irq); #endif } else { CPUState *cs = CPU(cpu); -- cgit v1.1 From bbd8bb8e3245cf6fc6d12b10b3320ab183adb866 Mon Sep 17 00:00:00 2001 From: Cornelia Huck Date: Wed, 12 Mar 2014 12:40:31 +0100 Subject: s390x/kvm: inject via flic Try to inject floating interrupts via the flic if it is available. This allows us to inject the full range of floating interrupts. Reviewed-by: Jens Freimann Signed-off-by: Cornelia Huck --- hw/intc/s390_flic_kvm.c | 10 ++++++++++ target-s390x/cpu.h | 1 + target-s390x/kvm.c | 19 ++++++++++++++++++- 3 files changed, 29 insertions(+), 1 deletion(-) diff --git a/hw/intc/s390_flic_kvm.c b/hw/intc/s390_flic_kvm.c index a734094..b471e7a 100644 --- a/hw/intc/s390_flic_kvm.c +++ b/hw/intc/s390_flic_kvm.c @@ -117,6 +117,16 @@ static int flic_enqueue_irqs(void *buf, uint64_t len, return rc ? -errno : 0; } +int kvm_s390_inject_flic(struct kvm_s390_irq *irq) +{ + static KVMS390FLICState *flic; + + if (unlikely(!flic)) { + flic = KVM_S390_FLIC(s390_get_flic()); + } + return flic_enqueue_irqs(irq, sizeof(*irq), flic); +} + /** * __get_all_irqs - store all pending irqs in buffer * @flic: pointer to flic device state diff --git a/target-s390x/cpu.h b/target-s390x/cpu.h index 9982c35..b13761d 100644 --- a/target-s390x/cpu.h +++ b/target-s390x/cpu.h @@ -365,6 +365,7 @@ void kvm_s390_virtio_irq(int config_change, uint64_t token); void kvm_s390_service_interrupt(uint32_t parm); void kvm_s390_vcpu_interrupt(S390CPU *cpu, struct kvm_s390_irq *irq); void kvm_s390_floating_interrupt(struct kvm_s390_irq *irq); +int kvm_s390_inject_flic(struct kvm_s390_irq *irq); #else static inline void kvm_s390_reset_vcpu(S390CPU *cpu) { diff --git a/target-s390x/kvm.c b/target-s390x/kvm.c index a2133ff..a1a4cc2 100644 --- a/target-s390x/kvm.c +++ b/target-s390x/kvm.c @@ -623,7 +623,7 @@ void kvm_s390_vcpu_interrupt(S390CPU *cpu, struct kvm_s390_irq *irq) } } -void kvm_s390_floating_interrupt(struct kvm_s390_irq *irq) +static void __kvm_s390_floating_interrupt(struct kvm_s390_irq *irq) { struct kvm_s390_interrupt kvmint = {}; int r; @@ -641,6 +641,23 @@ void kvm_s390_floating_interrupt(struct kvm_s390_irq *irq) } } +void kvm_s390_floating_interrupt(struct kvm_s390_irq *irq) +{ + static bool use_flic = true; + int r; + + if (use_flic) { + r = kvm_s390_inject_flic(irq); + if (r == -ENOSYS) { + use_flic = false; + } + if (!r) { + return; + } + } + __kvm_s390_floating_interrupt(irq); +} + void kvm_s390_virtio_irq(int config_change, uint64_t token) { struct kvm_s390_irq irq = { -- cgit v1.1