aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--hw/i386/pc_piix.c24
-rw-r--r--hw/s390x/css.c2
-rw-r--r--hw/s390x/css.h1
-rw-r--r--hw/s390x/virtio-ccw.c207
-rw-r--r--hw/s390x/virtio-ccw.h8
-rw-r--r--include/hw/i386/pc.h3
-rw-r--r--target-s390x/cpu.h16
-rw-r--r--target-s390x/kvm.c19
-rw-r--r--xen-all.c12
-rw-r--r--xen-stub.c5
10 files changed, 278 insertions, 19 deletions
diff --git a/hw/i386/pc_piix.c b/hw/i386/pc_piix.c
index 7972443374..fa59a0cb26 100644
--- a/hw/i386/pc_piix.c
+++ b/hw/i386/pc_piix.c
@@ -91,6 +91,11 @@ static void pc_init1(MemoryRegion *system_memory,
DeviceState *icc_bridge;
FWCfgState *fw_cfg = NULL;
+ if (xen_enabled() && xen_hvm_init() != 0) {
+ fprintf(stderr, "xen hardware virtual machine initialisation failed\n");
+ exit(1);
+ }
+
icc_bridge = qdev_create(NULL, TYPE_ICC_BRIDGE);
object_property_add_child(qdev_get_machine(), "icc-bridge",
OBJECT(icc_bridge), NULL);
@@ -102,9 +107,9 @@ static void pc_init1(MemoryRegion *system_memory,
kvmclock_create();
}
- if (ram_size >= QEMU_BELOW_4G_RAM_END ) {
- above_4g_mem_size = ram_size - QEMU_BELOW_4G_RAM_END;
- below_4g_mem_size = QEMU_BELOW_4G_RAM_END;
+ if (ram_size >= 0xe0000000 ) {
+ above_4g_mem_size = ram_size - 0xe0000000;
+ below_4g_mem_size = 0xe0000000;
} else {
above_4g_mem_size = 0;
below_4g_mem_size = ram_size;
@@ -174,9 +179,6 @@ static void pc_init1(MemoryRegion *system_memory,
pc_register_ferr_irq(gsi[13]);
pc_vga_init(isa_bus, pci_enabled ? pci_bus : NULL);
- if (xen_enabled()) {
- pci_create_simple(pci_bus, -1, "xen-platform");
- }
/* init basic PC hardware */
pc_basic_device_init(isa_bus, gsi, &rtc_state, &floppy, xen_enabled());
@@ -320,10 +322,14 @@ static void pc_init_isa(QEMUMachineInitArgs *args)
#ifdef CONFIG_XEN
static void pc_xen_hvm_init(QEMUMachineInitArgs *args)
{
- if (xen_hvm_init() != 0) {
- hw_error("xen hardware virtual machine initialisation failed");
- }
+ PCIBus *bus;
+
pc_init_pci(args);
+
+ bus = pci_find_root_bus(0);
+ if (bus != NULL) {
+ pci_create_simple(bus, -1, "xen-platform");
+ }
}
#endif
diff --git a/hw/s390x/css.c b/hw/s390x/css.c
index f82abfe029..93b0b9733b 100644
--- a/hw/s390x/css.c
+++ b/hw/s390x/css.c
@@ -68,7 +68,7 @@ int css_create_css_image(uint8_t cssid, bool default_image)
return 0;
}
-static uint16_t css_build_subchannel_id(SubchDev *sch)
+uint16_t css_build_subchannel_id(SubchDev *sch)
{
if (channel_subsys->max_cssid > 0) {
return (sch->cssid << 8) | (1 << 3) | (sch->ssid << 1) | 1;
diff --git a/hw/s390x/css.h b/hw/s390x/css.h
index 85ed05d0f5..b536ab5957 100644
--- a/hw/s390x/css.h
+++ b/hw/s390x/css.h
@@ -90,6 +90,7 @@ 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,
uint16_t devno, SubchDev *sch);
void css_sch_build_virtual_schib(SubchDev *sch, uint8_t chpid, uint8_t type);
+uint16_t css_build_subchannel_id(SubchDev *sch);
void css_reset(void);
void css_reset_sch(SubchDev *sch);
void css_queue_crw(uint8_t rsc, uint8_t erc, int chain, uint16_t rsid);
diff --git a/hw/s390x/virtio-ccw.c b/hw/s390x/virtio-ccw.c
index 201a635607..faef5ddf57 100644
--- a/hw/s390x/virtio-ccw.c
+++ b/hw/s390x/virtio-ccw.c
@@ -63,6 +63,91 @@ VirtIODevice *virtio_ccw_get_vdev(SubchDev *sch)
return vdev;
}
+static int virtio_ccw_set_guest2host_notifier(VirtioCcwDevice *dev, int n,
+ bool assign, bool set_handler)
+{
+ VirtQueue *vq = virtio_get_queue(dev->vdev, n);
+ EventNotifier *notifier = virtio_queue_get_host_notifier(vq);
+ int r = 0;
+ SubchDev *sch = dev->sch;
+ uint32_t sch_id = (css_build_subchannel_id(sch) << 16) | sch->schid;
+
+ if (assign) {
+ r = event_notifier_init(notifier, 1);
+ if (r < 0) {
+ error_report("%s: unable to init event notifier: %d", __func__, r);
+ return r;
+ }
+ virtio_queue_set_host_notifier_fd_handler(vq, true, set_handler);
+ r = s390_assign_subch_ioeventfd(event_notifier_get_fd(notifier), sch_id,
+ n, assign);
+ if (r < 0) {
+ error_report("%s: unable to assign ioeventfd: %d", __func__, r);
+ virtio_queue_set_host_notifier_fd_handler(vq, false, false);
+ event_notifier_cleanup(notifier);
+ return r;
+ }
+ } else {
+ virtio_queue_set_host_notifier_fd_handler(vq, false, false);
+ s390_assign_subch_ioeventfd(event_notifier_get_fd(notifier), sch_id,
+ n, assign);
+ event_notifier_cleanup(notifier);
+ }
+ return r;
+}
+
+static void virtio_ccw_start_ioeventfd(VirtioCcwDevice *dev)
+{
+ int n, r;
+
+ if (!(dev->flags & VIRTIO_CCW_FLAG_USE_IOEVENTFD) ||
+ dev->ioeventfd_disabled ||
+ dev->ioeventfd_started) {
+ return;
+ }
+ for (n = 0; n < VIRTIO_PCI_QUEUE_MAX; n++) {
+ if (!virtio_queue_get_num(dev->vdev, n)) {
+ continue;
+ }
+ r = virtio_ccw_set_guest2host_notifier(dev, n, true, true);
+ if (r < 0) {
+ goto assign_error;
+ }
+ }
+ dev->ioeventfd_started = true;
+ return;
+
+ assign_error:
+ while (--n >= 0) {
+ if (!virtio_queue_get_num(dev->vdev, n)) {
+ continue;
+ }
+ r = virtio_ccw_set_guest2host_notifier(dev, n, false, false);
+ assert(r >= 0);
+ }
+ dev->ioeventfd_started = false;
+ /* Disable ioeventfd for this device. */
+ dev->flags &= ~VIRTIO_CCW_FLAG_USE_IOEVENTFD;
+ error_report("%s: failed. Fallback to userspace (slower).", __func__);
+}
+
+static void virtio_ccw_stop_ioeventfd(VirtioCcwDevice *dev)
+{
+ int n, r;
+
+ if (!dev->ioeventfd_started) {
+ return;
+ }
+ for (n = 0; n < VIRTIO_PCI_QUEUE_MAX; n++) {
+ if (!virtio_queue_get_num(dev->vdev, n)) {
+ continue;
+ }
+ r = virtio_ccw_set_guest2host_notifier(dev, n, false, false);
+ assert(r >= 0);
+ }
+ dev->ioeventfd_started = false;
+}
+
VirtualCssBus *virtual_css_bus_init(void)
{
VirtualCssBus *cbus;
@@ -187,6 +272,7 @@ static int virtio_ccw_cb(SubchDev *sch, CCW1 ccw)
}
break;
case CCW_CMD_VDEV_RESET:
+ virtio_ccw_stop_ioeventfd(dev);
virtio_reset(dev->vdev);
ret = 0;
break;
@@ -309,10 +395,16 @@ static int virtio_ccw_cb(SubchDev *sch, CCW1 ccw)
ret = -EFAULT;
} else {
status = ldub_phys(ccw.cda);
+ if (!(status & VIRTIO_CONFIG_S_DRIVER_OK)) {
+ virtio_ccw_stop_ioeventfd(dev);
+ }
virtio_set_status(dev->vdev, status);
if (dev->vdev->status == 0) {
virtio_reset(dev->vdev);
}
+ if (status & VIRTIO_CONFIG_S_DRIVER_OK) {
+ virtio_ccw_start_ioeventfd(dev);
+ }
sch->curr_status.scsw.count = ccw.count - sizeof(status);
ret = 0;
}
@@ -540,6 +632,7 @@ static int virtio_ccw_exit(VirtioCcwDevice *dev)
{
SubchDev *sch = dev->sch;
+ virtio_ccw_stop_ioeventfd(dev);
if (sch) {
css_subch_assign(sch->cssid, sch->ssid, sch->schid, sch->devno, NULL);
g_free(sch);
@@ -801,8 +894,106 @@ static void virtio_ccw_reset(DeviceState *d)
{
VirtioCcwDevice *dev = VIRTIO_CCW_DEVICE(d);
+ virtio_ccw_stop_ioeventfd(dev);
virtio_reset(dev->vdev);
css_reset_sch(dev->sch);
+ dev->indicators = 0;
+ dev->indicators2 = 0;
+}
+
+static void virtio_ccw_vmstate_change(DeviceState *d, bool running)
+{
+ VirtioCcwDevice *dev = VIRTIO_CCW_DEVICE(d);
+
+ if (running) {
+ virtio_ccw_start_ioeventfd(dev);
+ } else {
+ virtio_ccw_stop_ioeventfd(dev);
+ }
+}
+
+static bool virtio_ccw_query_guest_notifiers(DeviceState *d)
+{
+ VirtioCcwDevice *dev = VIRTIO_CCW_DEVICE(d);
+
+ return !!(dev->sch->curr_status.pmcw.flags & PMCW_FLAGS_MASK_ENA);
+}
+
+static int virtio_ccw_set_host_notifier(DeviceState *d, int n, bool assign)
+{
+ VirtioCcwDevice *dev = VIRTIO_CCW_DEVICE(d);
+
+ /* Stop using the generic ioeventfd, we are doing eventfd handling
+ * ourselves below */
+ dev->ioeventfd_disabled = assign;
+ if (assign) {
+ virtio_ccw_stop_ioeventfd(dev);
+ }
+ return virtio_ccw_set_guest2host_notifier(dev, n, assign, false);
+}
+
+static int virtio_ccw_set_guest_notifier(VirtioCcwDevice *dev, int n,
+ bool assign, bool with_irqfd)
+{
+ VirtQueue *vq = virtio_get_queue(dev->vdev, n);
+ EventNotifier *notifier = virtio_queue_get_guest_notifier(vq);
+ VirtioDeviceClass *k = VIRTIO_DEVICE_GET_CLASS(dev->vdev);
+
+ if (assign) {
+ int r = event_notifier_init(notifier, 0);
+
+ if (r < 0) {
+ return r;
+ }
+ virtio_queue_set_guest_notifier_fd_handler(vq, true, with_irqfd);
+ /* We do not support irqfd for classic I/O interrupts, because the
+ * classic interrupts are intermixed with the subchannel status, that
+ * is queried with test subchannel. We want to use vhost, though.
+ * Lets make sure to have vhost running and wire up the irq fd to
+ * land in qemu (and only the irq fd) in this code.
+ */
+ if (k->guest_notifier_mask) {
+ k->guest_notifier_mask(dev->vdev, n, false);
+ }
+ /* get lost events and re-inject */
+ if (k->guest_notifier_pending &&
+ k->guest_notifier_pending(dev->vdev, n)) {
+ event_notifier_set(notifier);
+ }
+ } else {
+ if (k->guest_notifier_mask) {
+ k->guest_notifier_mask(dev->vdev, n, true);
+ }
+ virtio_queue_set_guest_notifier_fd_handler(vq, false, with_irqfd);
+ event_notifier_cleanup(notifier);
+ }
+ return 0;
+}
+
+static int virtio_ccw_set_guest_notifiers(DeviceState *d, int nvqs,
+ bool assigned)
+{
+ VirtioCcwDevice *dev = VIRTIO_CCW_DEVICE(d);
+ VirtIODevice *vdev = dev->vdev;
+ int r, n;
+
+ for (n = 0; n < nvqs; n++) {
+ if (!virtio_queue_get_num(vdev, n)) {
+ break;
+ }
+ /* false -> true, as soon as irqfd works */
+ r = virtio_ccw_set_guest_notifier(dev, n, assigned, false);
+ if (r < 0) {
+ goto assign_error;
+ }
+ }
+ return 0;
+
+assign_error:
+ while (--n >= 0) {
+ virtio_ccw_set_guest_notifier(dev, n, !assigned, false);
+ }
+ return r;
}
/**************** Virtio-ccw Bus Device Descriptions *******************/
@@ -812,6 +1003,8 @@ static Property virtio_ccw_net_properties[] = {
DEFINE_VIRTIO_NET_FEATURES(VirtioCcwDevice, host_features[0]),
DEFINE_VIRTIO_NET_PROPERTIES(VirtIONetCcw, vdev.net_conf),
DEFINE_NIC_PROPERTIES(VirtIONetCcw, vdev.nic_conf),
+ DEFINE_PROP_BIT("ioeventfd", VirtioCcwDevice, flags,
+ VIRTIO_CCW_FLAG_USE_IOEVENTFD_BIT, true),
DEFINE_PROP_END_OF_LIST(),
};
@@ -838,6 +1031,8 @@ static Property virtio_ccw_blk_properties[] = {
DEFINE_PROP_STRING("devno", VirtioCcwDevice, bus_id),
DEFINE_VIRTIO_BLK_FEATURES(VirtioCcwDevice, host_features[0]),
DEFINE_VIRTIO_BLK_PROPERTIES(VirtIOBlkCcw, blk),
+ DEFINE_PROP_BIT("ioeventfd", VirtioCcwDevice, flags,
+ VIRTIO_CCW_FLAG_USE_IOEVENTFD_BIT, true),
DEFINE_PROP_END_OF_LIST(),
};
@@ -864,6 +1059,8 @@ static Property virtio_ccw_serial_properties[] = {
DEFINE_PROP_STRING("devno", VirtioCcwDevice, bus_id),
DEFINE_VIRTIO_SERIAL_PROPERTIES(VirtioSerialCcw, vdev.serial),
DEFINE_VIRTIO_COMMON_FEATURES(VirtioCcwDevice, host_features[0]),
+ DEFINE_PROP_BIT("ioeventfd", VirtioCcwDevice, flags,
+ VIRTIO_CCW_FLAG_USE_IOEVENTFD_BIT, true),
DEFINE_PROP_END_OF_LIST(),
};
@@ -889,6 +1086,8 @@ static const TypeInfo virtio_ccw_serial = {
static Property virtio_ccw_balloon_properties[] = {
DEFINE_PROP_STRING("devno", VirtioCcwDevice, bus_id),
DEFINE_VIRTIO_COMMON_FEATURES(VirtioCcwDevice, host_features[0]),
+ DEFINE_PROP_BIT("ioeventfd", VirtioCcwDevice, flags,
+ VIRTIO_CCW_FLAG_USE_IOEVENTFD_BIT, true),
DEFINE_PROP_END_OF_LIST(),
};
@@ -915,6 +1114,8 @@ static Property virtio_ccw_scsi_properties[] = {
DEFINE_PROP_STRING("devno", VirtioCcwDevice, bus_id),
DEFINE_VIRTIO_SCSI_PROPERTIES(VirtIOSCSICcw, vdev.parent_obj.conf),
DEFINE_VIRTIO_SCSI_FEATURES(VirtioCcwDevice, host_features[0]),
+ DEFINE_PROP_BIT("ioeventfd", VirtioCcwDevice, flags,
+ VIRTIO_CCW_FLAG_USE_IOEVENTFD_BIT, true),
DEFINE_PROP_END_OF_LIST(),
};
@@ -978,6 +1179,8 @@ static Property virtio_ccw_rng_properties[] = {
DEFINE_PROP_STRING("devno", VirtioCcwDevice, bus_id),
DEFINE_VIRTIO_COMMON_FEATURES(VirtioCcwDevice, host_features[0]),
DEFINE_VIRTIO_RNG_PROPERTIES(VirtIORNGCcw, vdev.conf),
+ DEFINE_PROP_BIT("ioeventfd", VirtioCcwDevice, flags,
+ VIRTIO_CCW_FLAG_USE_IOEVENTFD_BIT, true),
DEFINE_PROP_END_OF_LIST(),
};
@@ -1105,6 +1308,10 @@ static void virtio_ccw_bus_class_init(ObjectClass *klass, void *data)
bus_class->max_dev = 1;
k->notify = virtio_ccw_notify;
k->get_features = virtio_ccw_get_features;
+ k->vmstate_change = virtio_ccw_vmstate_change;
+ 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;
}
static const TypeInfo virtio_ccw_bus_info = {
diff --git a/hw/s390x/virtio-ccw.h b/hw/s390x/virtio-ccw.h
index 121a5f8c4a..96d6f5d5b7 100644
--- a/hw/s390x/virtio-ccw.h
+++ b/hw/s390x/virtio-ccw.h
@@ -69,6 +69,11 @@ typedef struct VirtIOCCWDeviceClass {
/* Change here if we want to support more feature bits. */
#define VIRTIO_CCW_FEATURE_SIZE 1
+/* Performance improves when virtqueue kick processing is decoupled from the
+ * vcpu thread using ioeventfd for some devices. */
+#define VIRTIO_CCW_FLAG_USE_IOEVENTFD_BIT 1
+#define VIRTIO_CCW_FLAG_USE_IOEVENTFD (1 << VIRTIO_CCW_FLAG_USE_IOEVENTFD_BIT)
+
struct VirtioCcwDevice {
DeviceState parent_obj;
SubchDev *sch;
@@ -76,6 +81,9 @@ struct VirtioCcwDevice {
char *bus_id;
uint32_t host_features[VIRTIO_CCW_FEATURE_SIZE];
VirtioBusState bus;
+ bool ioeventfd_started;
+ bool ioeventfd_disabled;
+ uint32_t flags;
/* Guest provided values: */
hwaddr indicators;
hwaddr indicators2;
diff --git a/include/hw/i386/pc.h b/include/hw/i386/pc.h
index 7f0496764c..a417402bbb 100644
--- a/include/hw/i386/pc.h
+++ b/include/hw/i386/pc.h
@@ -79,9 +79,6 @@ extern int fd_bootchk;
void pc_register_ferr_irq(qemu_irq irq);
void pc_acpi_smi_interrupt(void *opaque, int irq, int level);
-#define QEMU_BELOW_4G_RAM_END 0xe0000000
-#define QEMU_BELOW_4G_MMIO_LENGTH ((1ULL << 32) - QEMU_BELOW_4G_RAM_END)
-
void pc_cpus_init(const char *cpu_model, DeviceState *icc_bridge);
void pc_hot_add_cpu(const int64_t id, Error **errp);
void pc_acpi_init(const char *default_dsdt);
diff --git a/target-s390x/cpu.h b/target-s390x/cpu.h
index 0ce82cf830..918c819c64 100644
--- a/target-s390x/cpu.h
+++ b/target-s390x/cpu.h
@@ -1081,6 +1081,7 @@ void kvm_s390_io_interrupt(S390CPU *cpu, uint16_t subchannel_id,
void kvm_s390_crw_mchk(S390CPU *cpu);
void kvm_s390_enable_css_support(S390CPU *cpu);
int kvm_s390_get_registers_partial(CPUState *cpu);
+int kvm_s390_assign_subch_ioeventfd(int fd, uint32_t sch, int vq, bool assign);
#else
static inline void kvm_s390_io_interrupt(S390CPU *cpu,
uint16_t subchannel_id,
@@ -1099,6 +1100,11 @@ static inline int kvm_s390_get_registers_partial(CPUState *cpu)
{
return -ENOSYS;
}
+static inline int kvm_s390_assign_subch_ioeventfd(int fd, uint32_t sch, int vq,
+ bool assign)
+{
+ return -ENOSYS;
+}
#endif
static inline void s390_io_interrupt(S390CPU *cpu,
@@ -1125,4 +1131,14 @@ static inline void s390_crw_mchk(S390CPU *cpu)
}
}
+static inline int s390_assign_subch_ioeventfd(int fd, uint32_t sch_id, int vq,
+ bool assign)
+{
+ if (kvm_enabled()) {
+ return kvm_s390_assign_subch_ioeventfd(fd, sch_id, vq, assign);
+ } else {
+ return -ENOSYS;
+ }
+}
+
#endif
diff --git a/target-s390x/kvm.c b/target-s390x/kvm.c
index 4d9ac4ad0c..650d3a5da9 100644
--- a/target-s390x/kvm.c
+++ b/target-s390x/kvm.c
@@ -932,3 +932,22 @@ void kvm_s390_enable_css_support(S390CPU *cpu)
void kvm_arch_init_irq_routing(KVMState *s)
{
}
+
+int kvm_s390_assign_subch_ioeventfd(int fd, uint32_t sch, int vq, bool assign)
+{
+ struct kvm_ioeventfd kick = {
+ .flags = KVM_IOEVENTFD_FLAG_VIRTIO_CCW_NOTIFY |
+ KVM_IOEVENTFD_FLAG_DATAMATCH,
+ .fd = fd,
+ .datamatch = vq,
+ .addr = sch,
+ .len = 8,
+ };
+ if (!kvm_check_extension(kvm_state, KVM_CAP_IOEVENTFD)) {
+ return -ENOSYS;
+ }
+ if (!assign) {
+ kick.flags |= KVM_IOEVENTFD_FLAG_DEASSIGN;
+ }
+ return kvm_vm_ioctl(kvm_state, KVM_IOEVENTFD, &kick);
+}
diff --git a/xen-all.c b/xen-all.c
index 9b5735048d..dcb57a0a56 100644
--- a/xen-all.c
+++ b/xen-all.c
@@ -161,18 +161,18 @@ static void xen_ram_init(ram_addr_t ram_size)
ram_addr_t block_len;
block_len = ram_size;
- if (ram_size >= QEMU_BELOW_4G_RAM_END) {
+ if (ram_size >= HVM_BELOW_4G_RAM_END) {
/* Xen does not allocate the memory continuously, and keep a hole at
- * QEMU_BELOW_4G_RAM_END of QEMU_BELOW_4G_MMIO_LENGTH
+ * HVM_BELOW_4G_MMIO_START of HVM_BELOW_4G_MMIO_LENGTH
*/
- block_len += QEMU_BELOW_4G_MMIO_LENGTH;
+ block_len += HVM_BELOW_4G_MMIO_LENGTH;
}
memory_region_init_ram(&ram_memory, "xen.ram", block_len);
vmstate_register_ram_global(&ram_memory);
- if (ram_size >= QEMU_BELOW_4G_RAM_END) {
- above_4g_mem_size = ram_size - QEMU_BELOW_4G_RAM_END;
- below_4g_mem_size = QEMU_BELOW_4G_RAM_END;
+ if (ram_size >= HVM_BELOW_4G_RAM_END) {
+ above_4g_mem_size = ram_size - HVM_BELOW_4G_RAM_END;
+ below_4g_mem_size = HVM_BELOW_4G_RAM_END;
} else {
below_4g_mem_size = ram_size;
}
diff --git a/xen-stub.c b/xen-stub.c
index 6f0516aa3e..47c8e73e0f 100644
--- a/xen-stub.c
+++ b/xen-stub.c
@@ -63,3 +63,8 @@ void qmp_xen_set_global_dirty_log(bool enable, Error **errp)
void xen_modified_memory(ram_addr_t start, ram_addr_t length)
{
}
+
+int xen_hvm_init(void)
+{
+ return 0;
+}