summaryrefslogtreecommitdiffstats
path: root/qemu/hw/s390x/virtio-ccw.c
diff options
context:
space:
mode:
Diffstat (limited to 'qemu/hw/s390x/virtio-ccw.c')
-rw-r--r--qemu/hw/s390x/virtio-ccw.c144
1 files changed, 62 insertions, 82 deletions
diff --git a/qemu/hw/s390x/virtio-ccw.c b/qemu/hw/s390x/virtio-ccw.c
index d36373e88..d51642db0 100644
--- a/qemu/hw/s390x/virtio-ccw.c
+++ b/qemu/hw/s390x/virtio-ccw.c
@@ -10,6 +10,8 @@
* directory.
*/
+#include "qemu/osdep.h"
+#include "qapi/error.h"
#include "hw/hw.h"
#include "sysemu/block-backend.h"
#include "sysemu/blockdev.h"
@@ -31,69 +33,6 @@
#include "virtio-ccw.h"
#include "trace.h"
-static QTAILQ_HEAD(, IndAddr) indicator_addresses =
- QTAILQ_HEAD_INITIALIZER(indicator_addresses);
-
-static IndAddr *get_indicator(hwaddr ind_addr, int len)
-{
- IndAddr *indicator;
-
- QTAILQ_FOREACH(indicator, &indicator_addresses, sibling) {
- if (indicator->addr == ind_addr) {
- indicator->refcnt++;
- return indicator;
- }
- }
- indicator = g_new0(IndAddr, 1);
- indicator->addr = ind_addr;
- indicator->len = len;
- indicator->refcnt = 1;
- QTAILQ_INSERT_TAIL(&indicator_addresses, indicator, sibling);
- return indicator;
-}
-
-static int s390_io_adapter_map(AdapterInfo *adapter, uint64_t map_addr,
- bool do_map)
-{
- S390FLICState *fs = s390_get_flic();
- S390FLICStateClass *fsc = S390_FLIC_COMMON_GET_CLASS(fs);
-
- return fsc->io_adapter_map(fs, adapter->adapter_id, map_addr, do_map);
-}
-
-static void release_indicator(AdapterInfo *adapter, IndAddr *indicator)
-{
- assert(indicator->refcnt > 0);
- indicator->refcnt--;
- if (indicator->refcnt > 0) {
- return;
- }
- QTAILQ_REMOVE(&indicator_addresses, indicator, sibling);
- if (indicator->map) {
- s390_io_adapter_map(adapter, indicator->map, false);
- }
- g_free(indicator);
-}
-
-static int map_indicator(AdapterInfo *adapter, IndAddr *indicator)
-{
- int ret;
-
- if (indicator->map) {
- return 0; /* already mapped is not an error */
- }
- indicator->map = indicator->addr;
- ret = s390_io_adapter_map(adapter, indicator->map, true);
- if ((ret != 0) && (ret != -ENOSYS)) {
- goto out_err;
- }
- return 0;
-
-out_err:
- indicator->map = 0;
- return ret;
-}
-
static void virtio_ccw_bus_new(VirtioBusState *bus, size_t bus_size,
VirtioCcwDevice *dev);
@@ -307,11 +246,18 @@ static int virtio_ccw_set_vqs(SubchDev *sch, VqInfoBlock *info,
if (!desc) {
virtio_queue_set_vector(vdev, index, VIRTIO_NO_VECTOR);
} else {
- /* Fail if we don't have a big enough queue. */
- /* TODO: Add interface to handle vring.num changing */
- if (virtio_queue_get_num(vdev, index) > num) {
+ if (info) {
+ /* virtio-1 allows changing the ring size. */
+ if (virtio_queue_get_num(vdev, index) < num) {
+ /* Fail if we exceed the maximum number. */
+ return -EINVAL;
+ }
+ virtio_queue_set_num(vdev, index, num);
+ } else if (virtio_queue_get_num(vdev, index) > num) {
+ /* Fail if we don't have a big enough queue. */
return -EINVAL;
}
+ /* We ignore possible increased num for legacy for compatibility. */
virtio_queue_set_vector(vdev, index, index);
}
/* tell notify handler in case of config change */
@@ -460,16 +406,19 @@ static int virtio_ccw_cb(SubchDev *sch, CCW1 ccw)
MEMTXATTRS_UNSPECIFIED,
NULL);
if (features.index == 0) {
- features.features = (uint32_t)vdev->host_features;
- } else if (features.index == 1) {
- features.features = (uint32_t)(vdev->host_features >> 32);
+ if (dev->revision >= 1) {
+ /* Don't offer legacy features for modern devices. */
+ features.features = (uint32_t)
+ (vdev->host_features & ~VIRTIO_LEGACY_FEATURES);
+ } else {
+ features.features = (uint32_t)vdev->host_features;
+ }
+ } else if ((features.index == 1) && (dev->revision >= 1)) {
/*
- * Don't offer version 1 to the guest if it did not
- * negotiate at least revision 1.
+ * Only offer feature bits beyond 31 if the guest has
+ * negotiated at least revision 1.
*/
- if (dev->revision <= 0) {
- features.features &= ~(1 << (VIRTIO_F_VERSION_1 - 32));
- }
+ features.features = (uint32_t)(vdev->host_features >> 32);
} else {
/* Return zeroes if the guest supports more feature bits. */
features.features = 0;
@@ -508,14 +457,12 @@ static int virtio_ccw_cb(SubchDev *sch, CCW1 ccw)
virtio_set_features(vdev,
(vdev->guest_features & 0xffffffff00000000ULL) |
features.features);
- } else if (features.index == 1) {
+ } else if ((features.index == 1) && (dev->revision >= 1)) {
/*
- * The guest should not set version 1 if it didn't
- * negotiate a revision >= 1.
+ * If the guest did not negotiate at least revision 1,
+ * we did not offer it any feature bits beyond 31. Such a
+ * guest passing us any bit here is therefore buggy.
*/
- if (dev->revision <= 0) {
- features.features &= ~(1 << (VIRTIO_F_VERSION_1 - 32));
- }
virtio_set_features(vdev,
(vdev->guest_features & 0x00000000ffffffffULL) |
((uint64_t)features.features << 32));
@@ -766,7 +713,7 @@ static int virtio_ccw_cb(SubchDev *sch, CCW1 ccw)
* need to fetch it here. Nothing to do for now, though.
*/
if (dev->revision >= 0 ||
- revinfo.revision > virtio_ccw_rev_max(vdev)) {
+ revinfo.revision > virtio_ccw_rev_max(dev)) {
ret = -ENOSYS;
break;
}
@@ -1169,7 +1116,8 @@ static void virtio_ccw_notify(DeviceState *d, uint16_t vector)
SubchDev *sch = dev->sch;
uint64_t indicators;
- if (vector >= 128) {
+ /* queue indicators + secondary indicators */
+ if (vector >= VIRTIO_CCW_QUEUE_MAX + 64) {
return;
}
@@ -1539,10 +1487,25 @@ static void virtio_ccw_device_plugged(DeviceState *d, Error **errp)
sch->id.cu_model = virtio_bus_get_vdev_id(&dev->bus);
+ if (dev->max_rev >= 1) {
+ virtio_add_feature(&vdev->host_features, VIRTIO_F_VERSION_1);
+ }
+
css_generate_sch_crws(sch->cssid, sch->ssid, sch->schid,
d->hotplugged, 1);
}
+static void virtio_ccw_post_plugged(DeviceState *d, Error **errp)
+{
+ VirtioCcwDevice *dev = VIRTIO_CCW_DEVICE(d);
+ VirtIODevice *vdev = virtio_bus_get_device(&dev->bus);
+
+ if (!virtio_host_has_feature(vdev, VIRTIO_F_VERSION_1)) {
+ /* A backend didn't support modern virtio. */
+ dev->max_rev = 0;
+ }
+}
+
static void virtio_ccw_device_unplugged(DeviceState *d)
{
VirtioCcwDevice *dev = VIRTIO_CCW_DEVICE(d);
@@ -1555,6 +1518,8 @@ static Property virtio_ccw_net_properties[] = {
DEFINE_PROP_STRING("devno", VirtioCcwDevice, bus_id),
DEFINE_PROP_BIT("ioeventfd", VirtioCcwDevice, flags,
VIRTIO_CCW_FLAG_USE_IOEVENTFD_BIT, true),
+ DEFINE_PROP_UINT32("max_revision", VirtioCcwDevice, max_rev,
+ VIRTIO_CCW_MAX_REV),
DEFINE_PROP_END_OF_LIST(),
};
@@ -1582,6 +1547,8 @@ static Property virtio_ccw_blk_properties[] = {
DEFINE_PROP_STRING("devno", VirtioCcwDevice, bus_id),
DEFINE_PROP_BIT("ioeventfd", VirtioCcwDevice, flags,
VIRTIO_CCW_FLAG_USE_IOEVENTFD_BIT, true),
+ DEFINE_PROP_UINT32("max_revision", VirtioCcwDevice, max_rev,
+ VIRTIO_CCW_MAX_REV),
DEFINE_PROP_END_OF_LIST(),
};
@@ -1609,6 +1576,8 @@ static Property virtio_ccw_serial_properties[] = {
DEFINE_PROP_STRING("devno", VirtioCcwDevice, bus_id),
DEFINE_PROP_BIT("ioeventfd", VirtioCcwDevice, flags,
VIRTIO_CCW_FLAG_USE_IOEVENTFD_BIT, true),
+ DEFINE_PROP_UINT32("max_revision", VirtioCcwDevice, max_rev,
+ VIRTIO_CCW_MAX_REV),
DEFINE_PROP_END_OF_LIST(),
};
@@ -1636,6 +1605,8 @@ static Property virtio_ccw_balloon_properties[] = {
DEFINE_PROP_STRING("devno", VirtioCcwDevice, bus_id),
DEFINE_PROP_BIT("ioeventfd", VirtioCcwDevice, flags,
VIRTIO_CCW_FLAG_USE_IOEVENTFD_BIT, true),
+ DEFINE_PROP_UINT32("max_revision", VirtioCcwDevice, max_rev,
+ VIRTIO_CCW_MAX_REV),
DEFINE_PROP_END_OF_LIST(),
};
@@ -1663,6 +1634,8 @@ static Property virtio_ccw_scsi_properties[] = {
DEFINE_PROP_STRING("devno", VirtioCcwDevice, bus_id),
DEFINE_PROP_BIT("ioeventfd", VirtioCcwDevice, flags,
VIRTIO_CCW_FLAG_USE_IOEVENTFD_BIT, true),
+ DEFINE_PROP_UINT32("max_revision", VirtioCcwDevice, max_rev,
+ VIRTIO_CCW_MAX_REV),
DEFINE_PROP_END_OF_LIST(),
};
@@ -1689,6 +1662,8 @@ static const TypeInfo virtio_ccw_scsi = {
#ifdef CONFIG_VHOST_SCSI
static Property vhost_ccw_scsi_properties[] = {
DEFINE_PROP_STRING("devno", VirtioCcwDevice, bus_id),
+ DEFINE_PROP_UINT32("max_revision", VirtioCcwDevice, max_rev,
+ VIRTIO_CCW_MAX_REV),
DEFINE_PROP_END_OF_LIST(),
};
@@ -1727,6 +1702,8 @@ static Property virtio_ccw_rng_properties[] = {
DEFINE_PROP_STRING("devno", VirtioCcwDevice, bus_id),
DEFINE_PROP_BIT("ioeventfd", VirtioCcwDevice, flags,
VIRTIO_CCW_FLAG_USE_IOEVENTFD_BIT, true),
+ DEFINE_PROP_UINT32("max_revision", VirtioCcwDevice, max_rev,
+ VIRTIO_CCW_MAX_REV),
DEFINE_PROP_END_OF_LIST(),
};
@@ -1865,6 +1842,7 @@ static void virtio_ccw_bus_class_init(ObjectClass *klass, void *data)
k->save_config = virtio_ccw_save_config;
k->load_config = virtio_ccw_load_config;
k->device_plugged = virtio_ccw_device_plugged;
+ k->post_plugged = virtio_ccw_post_plugged;
k->device_unplugged = virtio_ccw_device_unplugged;
}
@@ -1880,6 +1858,8 @@ static Property virtio_ccw_9p_properties[] = {
DEFINE_PROP_STRING("devno", VirtioCcwDevice, bus_id),
DEFINE_PROP_BIT("ioeventfd", VirtioCcwDevice, flags,
VIRTIO_CCW_FLAG_USE_IOEVENTFD_BIT, true),
+ DEFINE_PROP_UINT32("max_revision", VirtioCcwDevice, max_rev,
+ VIRTIO_CCW_MAX_REV),
DEFINE_PROP_END_OF_LIST(),
};