aboutsummaryrefslogtreecommitdiff
path: root/hw/virtio
diff options
context:
space:
mode:
Diffstat (limited to 'hw/virtio')
-rw-r--r--hw/virtio/trace-events31
-rw-r--r--hw/virtio/vhost-backend.c86
-rw-r--r--hw/virtio/vhost-user-vsock-pci.c4
-rw-r--r--hw/virtio/vhost-vdpa.c158
-rw-r--r--hw/virtio/vhost-vsock-pci.c10
-rw-r--r--hw/virtio/vhost.c49
-rw-r--r--hw/virtio/virtio-iommu-pci.c2
-rw-r--r--hw/virtio/virtio-iommu.c8
-rw-r--r--hw/virtio/virtio-mem.c3
-rw-r--r--hw/virtio/virtio-pci.c14
-rw-r--r--hw/virtio/virtio-pmem-pci.c1
-rw-r--r--hw/virtio/virtio-pmem.c1
-rw-r--r--hw/virtio/virtio.c24
13 files changed, 351 insertions, 40 deletions
diff --git a/hw/virtio/trace-events b/hw/virtio/trace-events
index 845200b..cf1e59d 100644
--- a/hw/virtio/trace-events
+++ b/hw/virtio/trace-events
@@ -22,6 +22,37 @@ vhost_user_postcopy_waker(const char *rb, uint64_t rb_offset) "%s + 0x%"PRIx64
vhost_user_postcopy_waker_found(uint64_t client_addr) "0x%"PRIx64
vhost_user_postcopy_waker_nomatch(const char *rb, uint64_t rb_offset) "%s + 0x%"PRIx64
+# vhost-vdpa.c
+vhost_vdpa_dma_map(void *vdpa, int fd, uint32_t msg_type, uint64_t iova, uint64_t size, uint64_t uaddr, uint8_t perm, uint8_t type) "vdpa:%p fd: %d msg_type: %"PRIu32" iova: 0x%"PRIx64" size: 0x%"PRIx64" uaddr: 0x%"PRIx64" perm: 0x%"PRIx8" type: %"PRIu8
+vhost_vdpa_dma_unmap(void *vdpa, int fd, uint32_t msg_type, uint64_t iova, uint64_t size, uint8_t type) "vdpa:%p fd: %d msg_type: %"PRIu32" iova: 0x%"PRIx64" size: 0x%"PRIx64" type: %"PRIu8
+vhost_vdpa_listener_region_add(void *vdpa, uint64_t iova, uint64_t llend, void *vaddr, bool readonly) "vdpa: %p iova 0x%"PRIx64" llend 0x%"PRIx64" vaddr: %p read-only: %d"
+vhost_vdpa_listener_region_del(void *vdpa, uint64_t iova, uint64_t llend) "vdpa: %p iova 0x%"PRIx64" llend 0x%"PRIx64
+vhost_vdpa_add_status(void *dev, uint8_t status) "dev: %p status: 0x%"PRIx8
+vhost_vdpa_init(void *dev, void *vdpa) "dev: %p vdpa: %p"
+vhost_vdpa_cleanup(void *dev, void *vdpa) "dev: %p vdpa: %p"
+vhost_vdpa_memslots_limit(void *dev, int ret) "dev: %p = 0x%x"
+vhost_vdpa_set_mem_table(void *dev, uint32_t nregions, uint32_t padding) "dev: %p nregions: %"PRIu32" padding: 0x%"PRIx32
+vhost_vdpa_dump_regions(void *dev, int i, uint64_t guest_phys_addr, uint64_t memory_size, uint64_t userspace_addr, uint64_t flags_padding) "dev: %p %d: guest_phys_addr: 0x%"PRIx64" memory_size: 0x%"PRIx64" userspace_addr: 0x%"PRIx64" flags_padding: 0x%"PRIx64
+vhost_vdpa_set_features(void *dev, uint64_t features) "dev: %p features: 0x%"PRIx64
+vhost_vdpa_get_device_id(void *dev, uint32_t device_id) "dev: %p device_id %"PRIu32
+vhost_vdpa_reset_device(void *dev, uint8_t status) "dev: %p status: 0x%"PRIx8
+vhost_vdpa_get_vq_index(void *dev, int idx, int vq_idx) "dev: %p idx: %d vq idx: %d"
+vhost_vdpa_set_vring_ready(void *dev) "dev: %p"
+vhost_vdpa_dump_config(void *dev, const char *line) "dev: %p %s"
+vhost_vdpa_set_config(void *dev, uint32_t offset, uint32_t size, uint32_t flags) "dev: %p offset: %"PRIu32" size: %"PRIu32" flags: 0x%"PRIx32
+vhost_vdpa_get_config(void *dev, void *config, uint32_t config_len) "dev: %p config: %p config_len: %"PRIu32
+vhost_vdpa_dev_start(void *dev, bool started) "dev: %p started: %d"
+vhost_vdpa_set_log_base(void *dev, uint64_t base, unsigned long long size, int refcnt, int fd, void *log) "dev: %p base: 0x%"PRIx64" size: %llu refcnt: %d fd: %d log: %p"
+vhost_vdpa_set_vring_addr(void *dev, unsigned int index, unsigned int flags, uint64_t desc_user_addr, uint64_t used_user_addr, uint64_t avail_user_addr, uint64_t log_guest_addr) "dev: %p index: %u flags: 0x%x desc_user_addr: 0x%"PRIx64" used_user_addr: 0x%"PRIx64" avail_user_addr: 0x%"PRIx64" log_guest_addr: 0x%"PRIx64
+vhost_vdpa_set_vring_num(void *dev, unsigned int index, unsigned int num) "dev: %p index: %u num: %u"
+vhost_vdpa_set_vring_base(void *dev, unsigned int index, unsigned int num) "dev: %p index: %u num: %u"
+vhost_vdpa_get_vring_base(void *dev, unsigned int index, unsigned int num) "dev: %p index: %u num: %u"
+vhost_vdpa_set_vring_kick(void *dev, unsigned int index, int fd) "dev: %p index: %u fd: %d"
+vhost_vdpa_set_vring_call(void *dev, unsigned int index, int fd) "dev: %p index: %u fd: %d"
+vhost_vdpa_get_features(void *dev, uint64_t features) "dev: %p features: 0x%"PRIx64
+vhost_vdpa_set_owner(void *dev) "dev: %p"
+vhost_vdpa_vq_get_addr(void *dev, void *vq, uint64_t desc_user_addr, uint64_t avail_user_addr, uint64_t used_user_addr) "dev: %p vq: %p desc_user_addr: 0x%"PRIx64" avail_user_addr: 0x%"PRIx64" used_user_addr: 0x%"PRIx64
+
# virtio.c
virtqueue_alloc_element(void *elem, size_t sz, unsigned in_num, unsigned out_num) "elem %p size %zd in_num %u out_num %u"
virtqueue_fill(void *vq, const void *elem, unsigned int len, unsigned int idx) "vq %p elem %p len %u idx %u"
diff --git a/hw/virtio/vhost-backend.c b/hw/virtio/vhost-backend.c
index 782b1d6..88c8ecc 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 (dev->backend_cap &
+ (0x1ULL << VHOST_BACKEND_F_IOTLB_MSG_V2)) {
+ struct vhost_msg_v2 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_V2) {
+ error_report("Unknown vhost iotlb message type");
+ break;
+ }
+
+ vhost_backend_handle_iotlb_msg(dev, &msg.iotlb);
}
- if (msg.type != VHOST_IOTLB_MSG) {
- error_report("Unknown vhost iotlb message type");
- break;
+ } 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);
}
-
- 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-user-vsock-pci.c b/hw/virtio/vhost-user-vsock-pci.c
index 763f899..72a9619 100644
--- a/hw/virtio/vhost-user-vsock-pci.c
+++ b/hw/virtio/vhost-user-vsock-pci.c
@@ -41,6 +41,9 @@ static void vhost_user_vsock_pci_realize(VirtIOPCIProxy *vpci_dev, Error **errp)
VHostUserVSockPCI *dev = VHOST_USER_VSOCK_PCI(vpci_dev);
DeviceState *vdev = DEVICE(&dev->vdev);
+ /* unlike vhost-vsock, we do not need to care about pre-5.1 compat */
+ virtio_pci_force_virtio_1(vpci_dev);
+
qdev_realize(vdev, BUS(&vpci_dev->bus), errp);
}
@@ -69,7 +72,6 @@ static void vhost_user_vsock_pci_instance_init(Object *obj)
static const VirtioPCIDeviceTypeInfo vhost_user_vsock_pci_info = {
.base_name = TYPE_VHOST_USER_VSOCK_PCI,
.generic_name = "vhost-user-vsock-pci",
- .transitional_name = "vhost-user-vsock-pci-transitional",
.non_transitional_name = "vhost-user-vsock-pci-non-transitional",
.instance_size = sizeof(VHostUserVSockPCI),
.instance_init = vhost_user_vsock_pci_instance_init,
diff --git a/hw/virtio/vhost-vdpa.c b/hw/virtio/vhost-vdpa.c
index aedc52c..4f10399 100644
--- a/hw/virtio/vhost-vdpa.c
+++ b/hw/virtio/vhost-vdpa.c
@@ -20,6 +20,8 @@
#include "hw/virtio/vhost-vdpa.h"
#include "qemu/main-loop.h"
#include "cpu.h"
+#include "trace.h"
+#include "qemu-common.h"
static bool vhost_vdpa_listener_skipped_section(MemoryRegionSection *section)
{
@@ -48,6 +50,9 @@ static int vhost_vdpa_dma_map(struct vhost_vdpa *v, hwaddr iova, hwaddr size,
msg.iotlb.perm = readonly ? VHOST_ACCESS_RO : VHOST_ACCESS_RW;
msg.iotlb.type = VHOST_IOTLB_UPDATE;
+ trace_vhost_vdpa_dma_map(v, fd, msg.type, msg.iotlb.iova, msg.iotlb.size,
+ msg.iotlb.uaddr, msg.iotlb.perm, msg.iotlb.type);
+
if (write(fd, &msg, sizeof(msg)) != sizeof(msg)) {
error_report("failed to write, fd=%d, errno=%d (%s)",
fd, errno, strerror(errno));
@@ -69,6 +74,9 @@ static int vhost_vdpa_dma_unmap(struct vhost_vdpa *v, hwaddr iova,
msg.iotlb.size = size;
msg.iotlb.type = VHOST_IOTLB_INVALIDATE;
+ trace_vhost_vdpa_dma_unmap(v, fd, msg.type, msg.iotlb.iova,
+ msg.iotlb.size, msg.iotlb.type);
+
if (write(fd, &msg, sizeof(msg)) != sizeof(msg)) {
error_report("failed to write, fd=%d, errno=%d (%s)",
fd, errno, strerror(errno));
@@ -78,6 +86,46 @@ static int vhost_vdpa_dma_unmap(struct vhost_vdpa *v, hwaddr iova,
return ret;
}
+static void vhost_vdpa_listener_begin(MemoryListener *listener)
+{
+ struct vhost_vdpa *v = container_of(listener, struct vhost_vdpa, listener);
+ struct vhost_dev *dev = v->dev;
+ struct vhost_msg_v2 msg;
+ int fd = v->device_fd;
+
+ if (!(dev->backend_cap & (0x1ULL << VHOST_BACKEND_F_IOTLB_BATCH))) {
+ return;
+ }
+
+ msg.type = v->msg_type;
+ msg.iotlb.type = VHOST_IOTLB_BATCH_BEGIN;
+
+ if (write(fd, &msg, sizeof(msg)) != sizeof(msg)) {
+ error_report("failed to write, fd=%d, errno=%d (%s)",
+ fd, errno, strerror(errno));
+ }
+}
+
+static void vhost_vdpa_listener_commit(MemoryListener *listener)
+{
+ struct vhost_vdpa *v = container_of(listener, struct vhost_vdpa, listener);
+ struct vhost_dev *dev = v->dev;
+ struct vhost_msg_v2 msg;
+ int fd = v->device_fd;
+
+ if (!(dev->backend_cap & (0x1ULL << VHOST_BACKEND_F_IOTLB_BATCH))) {
+ return;
+ }
+
+ msg.type = v->msg_type;
+ msg.iotlb.type = VHOST_IOTLB_BATCH_END;
+
+ if (write(fd, &msg, sizeof(msg)) != sizeof(msg)) {
+ error_report("failed to write, fd=%d, errno=%d (%s)",
+ fd, errno, strerror(errno));
+ }
+}
+
static void vhost_vdpa_listener_region_add(MemoryListener *listener,
MemoryRegionSection *section)
{
@@ -114,6 +162,9 @@ static void vhost_vdpa_listener_region_add(MemoryListener *listener,
section->offset_within_region +
(iova - section->offset_within_address_space);
+ trace_vhost_vdpa_listener_region_add(v, iova, int128_get64(llend),
+ vaddr, section->readonly);
+
llsize = int128_sub(llend, int128_make64(iova));
ret = vhost_vdpa_dma_map(v, iova, int128_get64(llsize),
@@ -169,6 +220,8 @@ static void vhost_vdpa_listener_region_del(MemoryListener *listener,
llend = int128_add(llend, section->size);
llend = int128_and(llend, int128_exts64(TARGET_PAGE_MASK));
+ trace_vhost_vdpa_listener_region_del(v, iova, int128_get64(llend));
+
if (int128_ge(int128_make64(iova), llend)) {
return;
}
@@ -188,6 +241,8 @@ static void vhost_vdpa_listener_region_del(MemoryListener *listener,
* depends on the addnop().
*/
static const MemoryListener vhost_vdpa_memory_listener = {
+ .begin = vhost_vdpa_listener_begin,
+ .commit = vhost_vdpa_listener_commit,
.region_add = vhost_vdpa_listener_region_add,
.region_del = vhost_vdpa_listener_region_del,
};
@@ -207,6 +262,7 @@ static void vhost_vdpa_add_status(struct vhost_dev *dev, uint8_t status)
{
uint8_t s;
+ trace_vhost_vdpa_add_status(dev, status);
if (vhost_vdpa_call(dev, VHOST_VDPA_GET_STATUS, &s)) {
return;
}
@@ -221,8 +277,10 @@ static int vhost_vdpa_init(struct vhost_dev *dev, void *opaque)
struct vhost_vdpa *v;
uint64_t features;
assert(dev->vhost_ops->backend_type == VHOST_BACKEND_TYPE_VDPA);
+ trace_vhost_vdpa_init(dev, opaque);
v = opaque;
+ v->dev = dev;
dev->opaque = opaque ;
vhost_vdpa_call(dev, VHOST_GET_FEATURES, &features);
dev->backend_features = features;
@@ -240,6 +298,7 @@ static int vhost_vdpa_cleanup(struct vhost_dev *dev)
struct vhost_vdpa *v;
assert(dev->vhost_ops->backend_type == VHOST_BACKEND_TYPE_VDPA);
v = dev->opaque;
+ trace_vhost_vdpa_cleanup(dev, v);
memory_listener_unregister(&v->listener);
dev->opaque = NULL;
@@ -248,13 +307,25 @@ static int vhost_vdpa_cleanup(struct vhost_dev *dev)
static int vhost_vdpa_memslots_limit(struct vhost_dev *dev)
{
+ trace_vhost_vdpa_memslots_limit(dev, INT_MAX);
return INT_MAX;
}
static int vhost_vdpa_set_mem_table(struct vhost_dev *dev,
struct vhost_memory *mem)
{
-
+ trace_vhost_vdpa_set_mem_table(dev, mem->nregions, mem->padding);
+ if (trace_event_get_state_backends(TRACE_VHOST_VDPA_SET_MEM_TABLE) &&
+ trace_event_get_state_backends(TRACE_VHOST_VDPA_DUMP_REGIONS)) {
+ int i;
+ for (i = 0; i < mem->nregions; i++) {
+ trace_vhost_vdpa_dump_regions(dev, i,
+ mem->regions[i].guest_phys_addr,
+ mem->regions[i].memory_size,
+ mem->regions[i].userspace_addr,
+ mem->regions[i].flags_padding);
+ }
+ }
if (mem->padding) {
return -1;
}
@@ -266,6 +337,7 @@ static int vhost_vdpa_set_features(struct vhost_dev *dev,
uint64_t features)
{
int ret;
+ trace_vhost_vdpa_set_features(dev, features);
ret = vhost_vdpa_call(dev, VHOST_SET_FEATURES, &features);
uint8_t status = 0;
if (ret) {
@@ -277,29 +349,59 @@ static int vhost_vdpa_set_features(struct vhost_dev *dev,
return !(status & VIRTIO_CONFIG_S_FEATURES_OK);
}
+static int vhost_vdpa_set_backend_cap(struct vhost_dev *dev)
+{
+ uint64_t features;
+ uint64_t f = 0x1ULL << VHOST_BACKEND_F_IOTLB_MSG_V2 |
+ 0x1ULL << VHOST_BACKEND_F_IOTLB_BATCH;
+ int r;
+
+ if (vhost_vdpa_call(dev, VHOST_GET_BACKEND_FEATURES, &features)) {
+ return 0;
+ }
+
+ features &= f;
+ r = vhost_vdpa_call(dev, VHOST_SET_BACKEND_FEATURES, &features);
+ if (r) {
+ return 0;
+ }
+
+ dev->backend_cap = features;
+
+ return 0;
+}
+
int vhost_vdpa_get_device_id(struct vhost_dev *dev,
uint32_t *device_id)
{
- return vhost_vdpa_call(dev, VHOST_VDPA_GET_DEVICE_ID, device_id);
+ int ret;
+ ret = vhost_vdpa_call(dev, VHOST_VDPA_GET_DEVICE_ID, device_id);
+ trace_vhost_vdpa_get_device_id(dev, *device_id);
+ return ret;
}
static int vhost_vdpa_reset_device(struct vhost_dev *dev)
{
+ int ret;
uint8_t status = 0;
- return vhost_vdpa_call(dev, VHOST_VDPA_SET_STATUS, &status);
+ ret = vhost_vdpa_call(dev, VHOST_VDPA_SET_STATUS, &status);
+ trace_vhost_vdpa_reset_device(dev, status);
+ return ret;
}
static int vhost_vdpa_get_vq_index(struct vhost_dev *dev, int idx)
{
assert(idx >= dev->vq_index && idx < dev->vq_index + dev->nvqs);
+ trace_vhost_vdpa_get_vq_index(dev, idx, idx - dev->vq_index);
return idx - dev->vq_index;
}
static int vhost_vdpa_set_vring_ready(struct vhost_dev *dev)
{
int i;
+ trace_vhost_vdpa_set_vring_ready(dev);
for (i = 0; i < dev->nvqs; ++i) {
struct vhost_vring_state state = {
.index = dev->vq_index + i,
@@ -310,6 +412,19 @@ static int vhost_vdpa_set_vring_ready(struct vhost_dev *dev)
return 0;
}
+static void vhost_vdpa_dump_config(struct vhost_dev *dev, const uint8_t *config,
+ uint32_t config_len)
+{
+ int b, len;
+ char line[QEMU_HEXDUMP_LINE_LEN];
+
+ for (b = 0; b < config_len; b += 16) {
+ len = config_len - b;
+ qemu_hexdump_line(line, b, config, len, false);
+ trace_vhost_vdpa_dump_config(dev, line);
+ }
+}
+
static int vhost_vdpa_set_config(struct vhost_dev *dev, const uint8_t *data,
uint32_t offset, uint32_t size,
uint32_t flags)
@@ -318,10 +433,15 @@ static int vhost_vdpa_set_config(struct vhost_dev *dev, const uint8_t *data,
int ret;
unsigned long config_size = offsetof(struct vhost_vdpa_config, buf);
+ trace_vhost_vdpa_set_config(dev, offset, size, flags);
config = g_malloc(size + config_size);
config->off = offset;
config->len = size;
memcpy(config->buf, data, size);
+ if (trace_event_get_state_backends(TRACE_VHOST_VDPA_SET_CONFIG) &&
+ trace_event_get_state_backends(TRACE_VHOST_VDPA_DUMP_CONFIG)) {
+ vhost_vdpa_dump_config(dev, data, size);
+ }
ret = vhost_vdpa_call(dev, VHOST_VDPA_SET_CONFIG, config);
g_free(config);
return ret;
@@ -334,18 +454,24 @@ static int vhost_vdpa_get_config(struct vhost_dev *dev, uint8_t *config,
unsigned long config_size = offsetof(struct vhost_vdpa_config, buf);
int ret;
+ trace_vhost_vdpa_get_config(dev, config, config_len);
v_config = g_malloc(config_len + config_size);
v_config->len = config_len;
v_config->off = 0;
ret = vhost_vdpa_call(dev, VHOST_VDPA_GET_CONFIG, v_config);
memcpy(config, v_config->buf, config_len);
g_free(v_config);
+ if (trace_event_get_state_backends(TRACE_VHOST_VDPA_GET_CONFIG) &&
+ trace_event_get_state_backends(TRACE_VHOST_VDPA_DUMP_CONFIG)) {
+ vhost_vdpa_dump_config(dev, config, config_len);
+ }
return ret;
}
static int vhost_vdpa_dev_start(struct vhost_dev *dev, bool started)
{
struct vhost_vdpa *v = dev->opaque;
+ trace_vhost_vdpa_dev_start(dev, started);
if (started) {
uint8_t status = 0;
memory_listener_register(&v->listener, &address_space_memory);
@@ -367,53 +493,72 @@ static int vhost_vdpa_dev_start(struct vhost_dev *dev, bool started)
static int vhost_vdpa_set_log_base(struct vhost_dev *dev, uint64_t base,
struct vhost_log *log)
{
+ trace_vhost_vdpa_set_log_base(dev, base, log->size, log->refcnt, log->fd,
+ log->log);
return vhost_vdpa_call(dev, VHOST_SET_LOG_BASE, &base);
}
static int vhost_vdpa_set_vring_addr(struct vhost_dev *dev,
struct vhost_vring_addr *addr)
{
+ trace_vhost_vdpa_set_vring_addr(dev, addr->index, addr->flags,
+ addr->desc_user_addr, addr->used_user_addr,
+ addr->avail_user_addr,
+ addr->log_guest_addr);
return vhost_vdpa_call(dev, VHOST_SET_VRING_ADDR, addr);
}
static int vhost_vdpa_set_vring_num(struct vhost_dev *dev,
struct vhost_vring_state *ring)
{
+ trace_vhost_vdpa_set_vring_num(dev, ring->index, ring->num);
return vhost_vdpa_call(dev, VHOST_SET_VRING_NUM, ring);
}
static int vhost_vdpa_set_vring_base(struct vhost_dev *dev,
struct vhost_vring_state *ring)
{
+ trace_vhost_vdpa_set_vring_base(dev, ring->index, ring->num);
return vhost_vdpa_call(dev, VHOST_SET_VRING_BASE, ring);
}
static int vhost_vdpa_get_vring_base(struct vhost_dev *dev,
struct vhost_vring_state *ring)
{
- return vhost_vdpa_call(dev, VHOST_GET_VRING_BASE, ring);
+ int ret;
+
+ ret = vhost_vdpa_call(dev, VHOST_GET_VRING_BASE, ring);
+ trace_vhost_vdpa_get_vring_base(dev, ring->index, ring->num);
+ return ret;
}
static int vhost_vdpa_set_vring_kick(struct vhost_dev *dev,
struct vhost_vring_file *file)
{
+ trace_vhost_vdpa_set_vring_kick(dev, file->index, file->fd);
return vhost_vdpa_call(dev, VHOST_SET_VRING_KICK, file);
}
static int vhost_vdpa_set_vring_call(struct vhost_dev *dev,
struct vhost_vring_file *file)
{
+ trace_vhost_vdpa_set_vring_call(dev, file->index, file->fd);
return vhost_vdpa_call(dev, VHOST_SET_VRING_CALL, file);
}
static int vhost_vdpa_get_features(struct vhost_dev *dev,
uint64_t *features)
{
- return vhost_vdpa_call(dev, VHOST_GET_FEATURES, features);
+ int ret;
+
+ ret = vhost_vdpa_call(dev, VHOST_GET_FEATURES, features);
+ trace_vhost_vdpa_get_features(dev, *features);
+ return ret;
}
static int vhost_vdpa_set_owner(struct vhost_dev *dev)
{
+ trace_vhost_vdpa_set_owner(dev);
return vhost_vdpa_call(dev, VHOST_SET_OWNER, NULL);
}
@@ -424,6 +569,8 @@ static int vhost_vdpa_vq_get_addr(struct vhost_dev *dev,
addr->desc_user_addr = (uint64_t)(unsigned long)vq->desc_phys;
addr->avail_user_addr = (uint64_t)(unsigned long)vq->avail_phys;
addr->used_user_addr = (uint64_t)(unsigned long)vq->used_phys;
+ trace_vhost_vdpa_vq_get_addr(dev, vq, addr->desc_user_addr,
+ addr->avail_user_addr, addr->used_user_addr);
return 0;
}
@@ -444,6 +591,7 @@ const VhostOps vdpa_ops = {
.vhost_set_vring_kick = vhost_vdpa_set_vring_kick,
.vhost_set_vring_call = vhost_vdpa_set_vring_call,
.vhost_get_features = vhost_vdpa_get_features,
+ .vhost_set_backend_cap = vhost_vdpa_set_backend_cap,
.vhost_set_owner = vhost_vdpa_set_owner,
.vhost_set_vring_endian = NULL,
.vhost_backend_memslots_limit = vhost_vdpa_memslots_limit,
diff --git a/hw/virtio/vhost-vsock-pci.c b/hw/virtio/vhost-vsock-pci.c
index e56067b..205da8d 100644
--- a/hw/virtio/vhost-vsock-pci.c
+++ b/hw/virtio/vhost-vsock-pci.c
@@ -44,6 +44,15 @@ static void vhost_vsock_pci_realize(VirtIOPCIProxy *vpci_dev, Error **errp)
{
VHostVSockPCI *dev = VHOST_VSOCK_PCI(vpci_dev);
DeviceState *vdev = DEVICE(&dev->vdev);
+ VirtIODevice *virtio_dev = VIRTIO_DEVICE(vdev);
+
+ /*
+ * To avoid migration issues, we force virtio version 1 only when
+ * legacy check is enabled in the new machine types (>= 5.1).
+ */
+ if (!virtio_legacy_check_disabled(virtio_dev)) {
+ virtio_pci_force_virtio_1(vpci_dev);
+ }
qdev_realize(vdev, BUS(&vpci_dev->bus), errp);
}
@@ -73,7 +82,6 @@ static void vhost_vsock_pci_instance_init(Object *obj)
static const VirtioPCIDeviceTypeInfo vhost_vsock_pci_info = {
.base_name = TYPE_VHOST_VSOCK_PCI,
.generic_name = "vhost-vsock-pci",
- .transitional_name = "vhost-vsock-pci-transitional",
.non_transitional_name = "vhost-vsock-pci-non-transitional",
.instance_size = sizeof(VHostVSockPCI),
.instance_init = vhost_vsock_pci_instance_init,
diff --git a/hw/virtio/vhost.c b/hw/virtio/vhost.c
index 0119516..68f0a75 100644
--- a/hw/virtio/vhost.c
+++ b/hw/virtio/vhost.c
@@ -818,19 +818,41 @@ 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;
}
static int vhost_dev_set_log(struct vhost_dev *dev, bool enable_log)
{
int r, i, idx;
+ hwaddr addr;
+
r = vhost_dev_set_features(dev, enable_log);
if (r < 0) {
goto err_features;
}
for (i = 0; i < dev->nvqs; ++i) {
idx = dev->vhost_ops->vhost_get_vq_index(dev, dev->vq_index + i);
+ addr = virtio_queue_get_desc_addr(dev->vdev, idx);
+ if (!addr) {
+ /*
+ * The queue might not be ready for start. If this
+ * is the case there is no reason to continue the process.
+ * The similar logic is used by the vhost_virtqueue_start()
+ * routine.
+ */
+ continue;
+ }
r = vhost_virtqueue_set_addr(dev, dev->vqs + i, idx,
enable_log);
if (r < 0) {
@@ -861,21 +883,42 @@ static int vhost_migration_log(MemoryListener *listener, bool enable)
dev->log_enabled = enable;
return 0;
}
+
+ r = 0;
if (!enable) {
r = vhost_dev_set_log(dev, false);
if (r < 0) {
- return r;
+ goto check_dev_state;
}
vhost_log_put(dev, false);
} else {
vhost_dev_log_resize(dev, vhost_get_log_size(dev));
r = vhost_dev_set_log(dev, true);
if (r < 0) {
- return r;
+ goto check_dev_state;
}
}
+
+check_dev_state:
dev->log_enabled = enable;
- return 0;
+ /*
+ * vhost-user-* devices could change their state during log
+ * initialization due to disconnect. So check dev state after
+ * vhost communication.
+ */
+ if (!dev->started) {
+ /*
+ * Since device is in the stopped state, it is okay for
+ * migration. Return success.
+ */
+ r = 0;
+ }
+ if (r) {
+ /* An error is occured. */
+ dev->log_enabled = false;
+ }
+
+ return r;
}
static void vhost_log_global_start(MemoryListener *listener)
diff --git a/hw/virtio/virtio-iommu-pci.c b/hw/virtio/virtio-iommu-pci.c
index 76540e5..378f63b 100644
--- a/hw/virtio/virtio-iommu-pci.c
+++ b/hw/virtio/virtio-iommu-pci.c
@@ -69,6 +69,7 @@ static void virtio_iommu_pci_realize(VirtIOPCIProxy *vpci_dev, Error **errp)
object_property_set_link(OBJECT(dev), "primary-bus",
OBJECT(pci_get_bus(&vpci_dev->pci_dev)),
&error_abort);
+ virtio_pci_force_virtio_1(vpci_dev);
qdev_realize(vdev, BUS(&vpci_dev->bus), errp);
}
@@ -98,7 +99,6 @@ static void virtio_iommu_pci_instance_init(Object *obj)
static const VirtioPCIDeviceTypeInfo virtio_iommu_pci_info = {
.base_name = TYPE_VIRTIO_IOMMU_PCI,
.generic_name = "virtio-iommu-pci",
- .transitional_name = "virtio-iommu-pci-transitional",
.non_transitional_name = "virtio-iommu-pci-non-transitional",
.instance_size = sizeof(VirtIOIOMMUPCI),
.instance_init = virtio_iommu_pci_instance_init,
diff --git a/hw/virtio/virtio-iommu.c b/hw/virtio/virtio-iommu.c
index 5d56865..21ec63b 100644
--- a/hw/virtio/virtio-iommu.c
+++ b/hw/virtio/virtio-iommu.c
@@ -801,8 +801,12 @@ static void virtio_iommu_device_unrealize(DeviceState *dev)
VirtIOIOMMU *s = VIRTIO_IOMMU(dev);
g_hash_table_destroy(s->as_by_busptr);
- g_tree_destroy(s->domains);
- g_tree_destroy(s->endpoints);
+ if (s->domains) {
+ g_tree_destroy(s->domains);
+ }
+ if (s->endpoints) {
+ g_tree_destroy(s->endpoints);
+ }
virtio_delete_queue(s->req_vq);
virtio_delete_queue(s->event_vq);
diff --git a/hw/virtio/virtio-mem.c b/hw/virtio/virtio-mem.c
index 8fbec77..7c8ca9f 100644
--- a/hw/virtio/virtio-mem.c
+++ b/hw/virtio/virtio-mem.c
@@ -318,6 +318,7 @@ static void virtio_mem_handle_request(VirtIODevice *vdev, VirtQueue *vq)
if (iov_to_buf(elem->out_sg, elem->out_num, 0, &req, len) < len) {
virtio_error(vdev, "virtio-mem protocol violation: invalid request"
" size: %d", len);
+ virtqueue_detach_element(vq, elem, 0);
g_free(elem);
return;
}
@@ -327,6 +328,7 @@ static void virtio_mem_handle_request(VirtIODevice *vdev, VirtQueue *vq)
virtio_error(vdev, "virtio-mem protocol violation: not enough space"
" for response: %zu",
iov_size(elem->in_sg, elem->in_num));
+ virtqueue_detach_element(vq, elem, 0);
g_free(elem);
return;
}
@@ -348,6 +350,7 @@ static void virtio_mem_handle_request(VirtIODevice *vdev, VirtQueue *vq)
default:
virtio_error(vdev, "virtio-mem protocol violation: unknown request"
" type: %d", type);
+ virtqueue_detach_element(vq, elem, 0);
g_free(elem);
return;
}
diff --git a/hw/virtio/virtio-pci.c b/hw/virtio/virtio-pci.c
index 02790e3..36524a5 100644
--- a/hw/virtio/virtio-pci.c
+++ b/hw/virtio/virtio-pci.c
@@ -1597,8 +1597,18 @@ static void virtio_pci_device_plugged(DeviceState *d, Error **errp)
if (legacy) {
if (!virtio_legacy_allowed(vdev)) {
- error_setg(errp, "device is modern-only, use disable-legacy=on");
- return;
+ /*
+ * To avoid migration issues, we allow legacy mode when legacy
+ * check is disabled in the old machine types (< 5.1).
+ */
+ if (virtio_legacy_check_disabled(vdev)) {
+ warn_report("device is modern-only, but for backward "
+ "compatibility legacy is allowed");
+ } else {
+ error_setg(errp,
+ "device is modern-only, use disable-legacy=on");
+ return;
+ }
}
if (virtio_host_has_feature(vdev, VIRTIO_F_IOMMU_PLATFORM)) {
error_setg(errp, "VIRTIO_F_IOMMU_PLATFORM was supported by"
diff --git a/hw/virtio/virtio-pmem-pci.c b/hw/virtio/virtio-pmem-pci.c
index 21a457d..2b2a0b1 100644
--- a/hw/virtio/virtio-pmem-pci.c
+++ b/hw/virtio/virtio-pmem-pci.c
@@ -22,6 +22,7 @@ static void virtio_pmem_pci_realize(VirtIOPCIProxy *vpci_dev, Error **errp)
VirtIOPMEMPCI *pmem_pci = VIRTIO_PMEM_PCI(vpci_dev);
DeviceState *vdev = DEVICE(&pmem_pci->vdev);
+ virtio_pci_force_virtio_1(vpci_dev);
qdev_realize(vdev, BUS(&vpci_dev->bus), errp);
}
diff --git a/hw/virtio/virtio-pmem.c b/hw/virtio/virtio-pmem.c
index 1e0c137..ddb0125 100644
--- a/hw/virtio/virtio-pmem.c
+++ b/hw/virtio/virtio-pmem.c
@@ -77,6 +77,7 @@ static void virtio_pmem_flush(VirtIODevice *vdev, VirtQueue *vq)
if (req_data->elem.out_num < 1 || req_data->elem.in_num < 1) {
virtio_error(vdev, "virtio-pmem request not proper");
+ virtqueue_detach_element(vq, (VirtQueueElement *)req_data, 0);
g_free(req_data);
return;
}
diff --git a/hw/virtio/virtio.c b/hw/virtio/virtio.c
index 3a3d012..6f8f865 100644
--- a/hw/virtio/virtio.c
+++ b/hw/virtio/virtio.c
@@ -2963,17 +2963,16 @@ int virtio_set_features(VirtIODevice *vdev, uint64_t val)
return -EINVAL;
}
ret = virtio_set_features_nocheck(vdev, val);
- if (!ret) {
- if (virtio_vdev_has_feature(vdev, VIRTIO_RING_F_EVENT_IDX)) {
- /* VIRTIO_RING_F_EVENT_IDX changes the size of the caches. */
- int i;
- for (i = 0; i < VIRTIO_QUEUE_MAX; i++) {
- if (vdev->vq[i].vring.num != 0) {
- virtio_init_region_cache(vdev, i);
- }
+ if (virtio_vdev_has_feature(vdev, VIRTIO_RING_F_EVENT_IDX)) {
+ /* VIRTIO_RING_F_EVENT_IDX changes the size of the caches. */
+ int i;
+ for (i = 0; i < VIRTIO_QUEUE_MAX; i++) {
+ if (vdev->vq[i].vring.num != 0) {
+ virtio_init_region_cache(vdev, i);
}
}
-
+ }
+ if (!ret) {
if (!virtio_device_started(vdev, vdev->status) &&
!virtio_vdev_has_feature(vdev, VIRTIO_F_VERSION_1)) {
vdev->start_on_kick = true;
@@ -3304,6 +3303,11 @@ bool virtio_legacy_allowed(VirtIODevice *vdev)
}
}
+bool virtio_legacy_check_disabled(VirtIODevice *vdev)
+{
+ return vdev->disable_legacy_check;
+}
+
hwaddr virtio_queue_get_desc_addr(VirtIODevice *vdev, int n)
{
return vdev->vq[n].vring.desc;
@@ -3713,6 +3717,8 @@ static Property virtio_properties[] = {
DEFINE_VIRTIO_COMMON_FEATURES(VirtIODevice, host_features),
DEFINE_PROP_BOOL("use-started", VirtIODevice, use_started, true),
DEFINE_PROP_BOOL("use-disabled-flag", VirtIODevice, use_disabled_flag, true),
+ DEFINE_PROP_BOOL("x-disable-legacy-check", VirtIODevice,
+ disable_legacy_check, false),
DEFINE_PROP_END_OF_LIST(),
};