diff --git a/hw/virtio/vhost-backend.c b/hw/virtio/vhost-backend.c index 782b1d67d9..88c8ecc9e0 100644 --- a/hw/virtio/vhost-backend.c +++ b/hw/virtio/vhost-backend.c @@ -156,6 +156,28 @@ static int vhost_kernel_set_features(struct vhost_dev *dev, return vhost_kernel_call(dev, VHOST_SET_FEATURES, &features); } +static int vhost_kernel_set_backend_cap(struct vhost_dev *dev) +{ + uint64_t features; + uint64_t f = 0x1ULL << VHOST_BACKEND_F_IOTLB_MSG_V2; + int r; + + if (vhost_kernel_call(dev, VHOST_GET_BACKEND_FEATURES, &features)) { + return 0; + } + + features &= f; + r = vhost_kernel_call(dev, VHOST_SET_BACKEND_FEATURES, + &features); + if (r) { + return 0; + } + + dev->backend_cap = features; + + return 0; +} + static int vhost_kernel_get_features(struct vhost_dev *dev, uint64_t *features) { @@ -195,34 +217,65 @@ static int vhost_kernel_vsock_set_running(struct vhost_dev *dev, int start) static void vhost_kernel_iotlb_read(void *opaque) { struct vhost_dev *dev = opaque; - struct vhost_msg msg; ssize_t len; - while ((len = read((uintptr_t)dev->opaque, &msg, sizeof msg)) > 0) { - if (len < sizeof msg) { - error_report("Wrong vhost message len: %d", (int)len); - break; - } - if (msg.type != VHOST_IOTLB_MSG) { - error_report("Unknown vhost iotlb message type"); - break; - } + if (dev->backend_cap & + (0x1ULL << VHOST_BACKEND_F_IOTLB_MSG_V2)) { + struct vhost_msg_v2 msg; - vhost_backend_handle_iotlb_msg(dev, &msg.iotlb); + while ((len = read((uintptr_t)dev->opaque, &msg, sizeof msg)) > 0) { + if (len < sizeof msg) { + error_report("Wrong vhost message len: %d", (int)len); + break; + } + if (msg.type != VHOST_IOTLB_MSG_V2) { + error_report("Unknown vhost iotlb message type"); + break; + } + + vhost_backend_handle_iotlb_msg(dev, &msg.iotlb); + } + } else { + struct vhost_msg msg; + + while ((len = read((uintptr_t)dev->opaque, &msg, sizeof msg)) > 0) { + if (len < sizeof msg) { + error_report("Wrong vhost message len: %d", (int)len); + break; + } + if (msg.type != VHOST_IOTLB_MSG) { + error_report("Unknown vhost iotlb message type"); + break; + } + + vhost_backend_handle_iotlb_msg(dev, &msg.iotlb); + } } } static int vhost_kernel_send_device_iotlb_msg(struct vhost_dev *dev, struct vhost_iotlb_msg *imsg) { - struct vhost_msg msg; + if (dev->backend_cap & (1ULL << VHOST_BACKEND_F_IOTLB_MSG_V2)) { + struct vhost_msg_v2 msg; - msg.type = VHOST_IOTLB_MSG; - msg.iotlb = *imsg; + msg.type = VHOST_IOTLB_MSG_V2; + msg.iotlb = *imsg; - if (write((uintptr_t)dev->opaque, &msg, sizeof msg) != sizeof msg) { - error_report("Fail to update device iotlb"); - return -EFAULT; + if (write((uintptr_t)dev->opaque, &msg, sizeof msg) != sizeof msg) { + error_report("Fail to update device iotlb"); + return -EFAULT; + } + } else { + struct vhost_msg msg; + + msg.type = VHOST_IOTLB_MSG; + msg.iotlb = *imsg; + + if (write((uintptr_t)dev->opaque, &msg, sizeof msg) != sizeof msg) { + error_report("Fail to update device iotlb"); + return -EFAULT; + } } return 0; @@ -260,6 +313,7 @@ static const VhostOps kernel_ops = { vhost_kernel_set_vring_busyloop_timeout, .vhost_set_features = vhost_kernel_set_features, .vhost_get_features = vhost_kernel_get_features, + .vhost_set_backend_cap = vhost_kernel_set_backend_cap, .vhost_set_owner = vhost_kernel_set_owner, .vhost_reset_device = vhost_kernel_reset_device, .vhost_get_vq_index = vhost_kernel_get_vq_index, diff --git a/hw/virtio/vhost.c b/hw/virtio/vhost.c index 0119516254..8087f200e9 100644 --- a/hw/virtio/vhost.c +++ b/hw/virtio/vhost.c @@ -818,7 +818,17 @@ static int vhost_dev_set_features(struct vhost_dev *dev, r = dev->vhost_ops->vhost_set_features(dev, features); if (r < 0) { VHOST_OPS_DEBUG("vhost_set_features failed"); + goto out; } + if (dev->vhost_ops->vhost_set_backend_cap) { + r = dev->vhost_ops->vhost_set_backend_cap(dev); + if (r < 0) { + VHOST_OPS_DEBUG("vhost_set_backend_cap failed"); + goto out; + } + } + +out: return r < 0 ? -errno : 0; } diff --git a/include/hw/virtio/vhost-backend.h b/include/hw/virtio/vhost-backend.h index 8825bd278f..8a6f8e2a7a 100644 --- a/include/hw/virtio/vhost-backend.h +++ b/include/hw/virtio/vhost-backend.h @@ -74,6 +74,7 @@ typedef int (*vhost_set_features_op)(struct vhost_dev *dev, uint64_t features); typedef int (*vhost_get_features_op)(struct vhost_dev *dev, uint64_t *features); +typedef int (*vhost_set_backend_cap_op)(struct vhost_dev *dev); typedef int (*vhost_set_owner_op)(struct vhost_dev *dev); typedef int (*vhost_reset_device_op)(struct vhost_dev *dev); typedef int (*vhost_get_vq_index_op)(struct vhost_dev *dev, int idx); @@ -146,6 +147,7 @@ typedef struct VhostOps { vhost_set_vring_busyloop_timeout_op vhost_set_vring_busyloop_timeout; vhost_set_features_op vhost_set_features; vhost_get_features_op vhost_get_features; + vhost_set_backend_cap_op vhost_set_backend_cap; vhost_set_owner_op vhost_set_owner; vhost_reset_device_op vhost_reset_device; vhost_get_vq_index_op vhost_get_vq_index; diff --git a/include/hw/virtio/vhost.h b/include/hw/virtio/vhost.h index 767a95ec0b..94585067f7 100644 --- a/include/hw/virtio/vhost.h +++ b/include/hw/virtio/vhost.h @@ -79,6 +79,7 @@ struct vhost_dev { uint64_t backend_features; uint64_t protocol_features; uint64_t max_queues; + uint64_t backend_cap; bool started; bool log_enabled; uint64_t log_size;