mirror of
https://github.com/izzy2lost/xemu.git
synced 2026-07-06 00:20:22 -07:00
Merge tag 'for_upstream' of https://git.kernel.org/pub/scm/virt/kvm/mst/qemu into staging
virtio,pc,pci: features, cleanups, fixes vhost-scsi support for worker ioctls fixes, cleanups all over the place. Signed-off-by: Michael S. Tsirkin <mst@redhat.com> # -----BEGIN PGP SIGNATURE----- # # iQFDBAABCAAtFiEEXQn9CHHI+FuUyooNKB8NuNKNVGkFAmWKohIPHG1zdEByZWRo # YXQuY29tAAoJECgfDbjSjVRpG2YH/1rJGV8TQm4V8kcGP9wOknPAMFADnEFdFmrB # V+JEDnyKrdcEZLPRh0b846peWRJhC13iL7Ks3VNjeVsfE9TyzNyNDpUzCJPfYFjR # 3m8ChLDvE9tKBA5/hXMIcgDXaYcPIrPvHyl4HG8EQn7oaeMpS2uecKqDpDDvNXGq # oNamNvqimFSqA+3ChzA+0Qt07Ts7xFEw4OEXSwfRXlsam/dhQG0SI+crRheHuvFb # HR8EwmNydA1D/M51AuBNuvX36u3SnPWm7Anp5711SZ1b59unshI0ztIqIJnGkvYe # qpUJSmxR6ulwWe4nQfb+GhBsuJ2j2ORC7YfXyAT7mw8rds8loaI= # =cNy2 # -----END PGP SIGNATURE----- # gpg: Signature made Tue 26 Dec 2023 04:51:14 EST # gpg: using RSA key 5D09FD0871C8F85B94CA8A0D281F0DB8D28D5469 # gpg: issuer "mst@redhat.com" # gpg: Good signature from "Michael S. Tsirkin <mst@kernel.org>" [full] # gpg: aka "Michael S. Tsirkin <mst@redhat.com>" [full] # Primary key fingerprint: 0270 606B 6F3C DF3D 0B17 0970 C350 3912 AFBE 8E67 # Subkey fingerprint: 5D09 FD08 71C8 F85B 94CA 8A0D 281F 0DB8 D28D 5469 * tag 'for_upstream' of https://git.kernel.org/pub/scm/virt/kvm/mst/qemu: (21 commits) vdpa: move memory listener to vhost_vdpa_shared vdpa: use dev_shared in vdpa_iommu vdpa: use VhostVDPAShared in vdpa_dma_map and unmap vdpa: move iommu_list to vhost_vdpa_shared vdpa: remove msg type of vhost_vdpa vdpa: move backend_cap to vhost_vdpa_shared vdpa: move iotlb_batch_begin_sent to vhost_vdpa_shared vdpa: move file descriptor to vhost_vdpa_shared vdpa: use vdpa shared for tracing vdpa: move shadow_data to vhost_vdpa_shared vdpa: move iova_range to vhost_vdpa_shared vdpa: move iova tree to the shared struct vdpa: add VhostVDPAShared vdpa: do not set virtio status bits if unneeded Fix bugs when VM shutdown with virtio-gpu unplugged vhost-scsi: fix usage of error_reportf_err() hw/acpi: propagate vcpu hotplug after switch to modern interface vhost-scsi: Add support for a worker thread per virtqueue vhost: Add worker backend callouts tests: bios-tables-test: Rename smbios type 4 related test functions ... Signed-off-by: Stefan Hajnoczi <stefanha@redhat.com>
This commit is contained in:
+16
-4
@@ -59,7 +59,8 @@ static const MemoryRegionOps AcpiCpuHotplug_ops = {
|
||||
},
|
||||
};
|
||||
|
||||
static void acpi_set_cpu_present_bit(AcpiCpuHotplug *g, CPUState *cpu)
|
||||
static void acpi_set_cpu_present_bit(AcpiCpuHotplug *g, CPUState *cpu,
|
||||
bool *swtchd_to_modern)
|
||||
{
|
||||
CPUClass *k = CPU_GET_CLASS(cpu);
|
||||
int64_t cpu_id;
|
||||
@@ -68,23 +69,34 @@ static void acpi_set_cpu_present_bit(AcpiCpuHotplug *g, CPUState *cpu)
|
||||
if ((cpu_id / 8) >= ACPI_GPE_PROC_LEN) {
|
||||
object_property_set_bool(g->device, "cpu-hotplug-legacy", false,
|
||||
&error_abort);
|
||||
*swtchd_to_modern = true;
|
||||
return;
|
||||
}
|
||||
|
||||
*swtchd_to_modern = false;
|
||||
g->sts[cpu_id / 8] |= (1 << (cpu_id % 8));
|
||||
}
|
||||
|
||||
void legacy_acpi_cpu_plug_cb(HotplugHandler *hotplug_dev,
|
||||
AcpiCpuHotplug *g, DeviceState *dev, Error **errp)
|
||||
{
|
||||
acpi_set_cpu_present_bit(g, CPU(dev));
|
||||
acpi_send_event(DEVICE(hotplug_dev), ACPI_CPU_HOTPLUG_STATUS);
|
||||
bool swtchd_to_modern;
|
||||
Error *local_err = NULL;
|
||||
|
||||
acpi_set_cpu_present_bit(g, CPU(dev), &swtchd_to_modern);
|
||||
if (swtchd_to_modern) {
|
||||
/* propagate the hotplug to the modern interface */
|
||||
hotplug_handler_plug(hotplug_dev, dev, &local_err);
|
||||
} else {
|
||||
acpi_send_event(DEVICE(hotplug_dev), ACPI_CPU_HOTPLUG_STATUS);
|
||||
}
|
||||
}
|
||||
|
||||
void legacy_acpi_cpu_hotplug_init(MemoryRegion *parent, Object *owner,
|
||||
AcpiCpuHotplug *gpe_cpu, uint16_t base)
|
||||
{
|
||||
CPUState *cpu;
|
||||
bool swtchd_to_modern;
|
||||
|
||||
memory_region_init_io(&gpe_cpu->io, owner, &AcpiCpuHotplug_ops,
|
||||
gpe_cpu, "acpi-cpu-hotplug", ACPI_GPE_PROC_LEN);
|
||||
@@ -92,7 +104,7 @@ void legacy_acpi_cpu_hotplug_init(MemoryRegion *parent, Object *owner,
|
||||
gpe_cpu->device = owner;
|
||||
|
||||
CPU_FOREACH(cpu) {
|
||||
acpi_set_cpu_present_bit(gpe_cpu, cpu);
|
||||
acpi_set_cpu_present_bit(gpe_cpu, cpu, &swtchd_to_modern);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -251,7 +251,11 @@ void
|
||||
virtio_gpu_base_device_unrealize(DeviceState *qdev)
|
||||
{
|
||||
VirtIOGPUBase *g = VIRTIO_GPU_BASE(qdev);
|
||||
VirtIODevice *vdev = VIRTIO_DEVICE(qdev);
|
||||
|
||||
virtio_del_queue(vdev, 0);
|
||||
virtio_del_queue(vdev, 1);
|
||||
virtio_cleanup(vdev);
|
||||
migrate_del_blocker(&g->migration_blocker);
|
||||
}
|
||||
|
||||
|
||||
+64
-2
@@ -91,13 +91,13 @@ static int vhost_scsi_start(VHostSCSI *s)
|
||||
|
||||
ret = vhost_scsi_common_start(vsc, &local_err);
|
||||
if (ret < 0) {
|
||||
error_reportf_err(local_err, "Error starting vhost-scsi");
|
||||
error_reportf_err(local_err, "Error starting vhost-scsi: ");
|
||||
return ret;
|
||||
}
|
||||
|
||||
ret = vhost_scsi_set_endpoint(s);
|
||||
if (ret < 0) {
|
||||
error_reportf_err(local_err, "Error setting vhost-scsi endpoint");
|
||||
error_report("Error setting vhost-scsi endpoint");
|
||||
vhost_scsi_common_stop(vsc);
|
||||
}
|
||||
|
||||
@@ -165,6 +165,59 @@ static const VMStateDescription vmstate_virtio_vhost_scsi = {
|
||||
.pre_save = vhost_scsi_pre_save,
|
||||
};
|
||||
|
||||
static int vhost_scsi_set_workers(VHostSCSICommon *vsc, bool per_virtqueue)
|
||||
{
|
||||
struct vhost_dev *dev = &vsc->dev;
|
||||
struct vhost_vring_worker vq_worker;
|
||||
struct vhost_worker_state worker;
|
||||
int i, ret;
|
||||
|
||||
/* Use default worker */
|
||||
if (!per_virtqueue || dev->nvqs == VHOST_SCSI_VQ_NUM_FIXED + 1) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*
|
||||
* ctl/evt share the first worker since it will be rare for them
|
||||
* to send cmds while IO is running.
|
||||
*/
|
||||
for (i = VHOST_SCSI_VQ_NUM_FIXED + 1; i < dev->nvqs; i++) {
|
||||
memset(&worker, 0, sizeof(worker));
|
||||
|
||||
ret = dev->vhost_ops->vhost_new_worker(dev, &worker);
|
||||
if (ret == -ENOTTY) {
|
||||
/*
|
||||
* worker ioctls are not implemented so just ignore and
|
||||
* and continue device setup.
|
||||
*/
|
||||
warn_report("vhost-scsi: Backend supports a single worker. "
|
||||
"Ignoring worker_per_virtqueue=true setting.");
|
||||
ret = 0;
|
||||
break;
|
||||
} else if (ret) {
|
||||
break;
|
||||
}
|
||||
|
||||
memset(&vq_worker, 0, sizeof(vq_worker));
|
||||
vq_worker.worker_id = worker.worker_id;
|
||||
vq_worker.index = i;
|
||||
|
||||
ret = dev->vhost_ops->vhost_attach_vring_worker(dev, &vq_worker);
|
||||
if (ret == -ENOTTY) {
|
||||
/*
|
||||
* It's a bug for the kernel to have supported the worker creation
|
||||
* ioctl but not attach.
|
||||
*/
|
||||
dev->vhost_ops->vhost_free_worker(dev, &worker);
|
||||
break;
|
||||
} else if (ret) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
static void vhost_scsi_realize(DeviceState *dev, Error **errp)
|
||||
{
|
||||
VirtIOSCSICommon *vs = VIRTIO_SCSI_COMMON(dev);
|
||||
@@ -232,6 +285,13 @@ static void vhost_scsi_realize(DeviceState *dev, Error **errp)
|
||||
goto free_vqs;
|
||||
}
|
||||
|
||||
ret = vhost_scsi_set_workers(vsc, vs->conf.worker_per_virtqueue);
|
||||
if (ret < 0) {
|
||||
error_setg(errp, "vhost-scsi: vhost worker setup failed: %s",
|
||||
strerror(-ret));
|
||||
goto free_vqs;
|
||||
}
|
||||
|
||||
/* At present, channel and lun both are 0 for bootable vhost-scsi disk */
|
||||
vsc->channel = 0;
|
||||
vsc->lun = 0;
|
||||
@@ -297,6 +357,8 @@ static Property vhost_scsi_properties[] = {
|
||||
VIRTIO_SCSI_F_T10_PI,
|
||||
false),
|
||||
DEFINE_PROP_BOOL("migratable", VHostSCSICommon, migratable, false),
|
||||
DEFINE_PROP_BOOL("worker_per_virtqueue", VirtIOSCSICommon,
|
||||
conf.worker_per_virtqueue, false),
|
||||
DEFINE_PROP_END_OF_LIST(),
|
||||
};
|
||||
|
||||
|
||||
@@ -83,7 +83,8 @@ static void vhost_user_scsi_set_status(VirtIODevice *vdev, uint8_t status)
|
||||
if (should_start) {
|
||||
ret = vhost_user_scsi_start(s, &local_err);
|
||||
if (ret < 0) {
|
||||
error_reportf_err(local_err, "unable to start vhost-user-scsi: %s",
|
||||
error_reportf_err(local_err,
|
||||
"unable to start vhost-user-scsi: %s: ",
|
||||
strerror(-ret));
|
||||
qemu_chr_fe_disconnect(&vs->conf.chardev);
|
||||
}
|
||||
|
||||
@@ -30,16 +30,16 @@ vhost_user_write(uint32_t req, uint32_t flags) "req:%d flags:0x%"PRIx32""
|
||||
vhost_user_create_notifier(int idx, void *n) "idx:%d n:%p"
|
||||
|
||||
# vhost-vdpa.c
|
||||
vhost_vdpa_dma_map(void *vdpa, int fd, uint32_t msg_type, uint32_t asid, uint64_t iova, uint64_t size, uint64_t uaddr, uint8_t perm, uint8_t type) "vdpa:%p fd: %d msg_type: %"PRIu32" asid: %"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, uint32_t asid, uint64_t iova, uint64_t size, uint8_t type) "vdpa:%p fd: %d msg_type: %"PRIu32" asid: %"PRIu32" iova: 0x%"PRIx64" size: 0x%"PRIx64" type: %"PRIu8
|
||||
vhost_vdpa_listener_begin_batch(void *v, int fd, uint32_t msg_type, uint8_t type) "vdpa:%p fd: %d msg_type: %"PRIu32" type: %"PRIu8
|
||||
vhost_vdpa_listener_commit(void *v, int fd, uint32_t msg_type, uint8_t type) "vdpa:%p fd: %d msg_type: %"PRIu32" type: %"PRIu8
|
||||
vhost_vdpa_listener_region_add_unaligned(void *v, const char *name, uint64_t offset_as, uint64_t offset_page) "vdpa: %p region %s offset_within_address_space %"PRIu64" offset_within_region %"PRIu64
|
||||
vhost_vdpa_dma_map(void *vdpa, int fd, uint32_t msg_type, uint32_t asid, uint64_t iova, uint64_t size, uint64_t uaddr, uint8_t perm, uint8_t type) "vdpa_shared:%p fd: %d msg_type: %"PRIu32" asid: %"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, uint32_t asid, uint64_t iova, uint64_t size, uint8_t type) "vdpa_shared:%p fd: %d msg_type: %"PRIu32" asid: %"PRIu32" iova: 0x%"PRIx64" size: 0x%"PRIx64" type: %"PRIu8
|
||||
vhost_vdpa_listener_begin_batch(void *v, int fd, uint32_t msg_type, uint8_t type) "vdpa_shared:%p fd: %d msg_type: %"PRIu32" type: %"PRIu8
|
||||
vhost_vdpa_listener_commit(void *v, int fd, uint32_t msg_type, uint8_t type) "vdpa_shared:%p fd: %d msg_type: %"PRIu32" type: %"PRIu8
|
||||
vhost_vdpa_listener_region_add_unaligned(void *v, const char *name, uint64_t offset_as, uint64_t offset_page) "vdpa_shared: %p region %s offset_within_address_space %"PRIu64" offset_within_region %"PRIu64
|
||||
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_unaligned(void *v, const char *name, uint64_t offset_as, uint64_t offset_page) "vdpa: %p region %s offset_within_address_space %"PRIu64" offset_within_region %"PRIu64
|
||||
vhost_vdpa_listener_region_del_unaligned(void *v, const char *name, uint64_t offset_as, uint64_t offset_page) "vdpa_shared: %p region %s offset_within_address_space %"PRIu64" offset_within_region %"PRIu64
|
||||
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_init(void *dev, void *s, void *vdpa) "dev: %p, common 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
|
||||
|
||||
@@ -66,7 +66,6 @@ static void vhost_vdpa_device_realize(DeviceState *dev, Error **errp)
|
||||
if (*errp) {
|
||||
return;
|
||||
}
|
||||
v->vdpa.device_fd = v->vhostfd;
|
||||
|
||||
v->vdev_id = vhost_vdpa_device_get_u32(v->vhostfd,
|
||||
VHOST_VDPA_GET_DEVICE_ID, errp);
|
||||
@@ -114,7 +113,9 @@ static void vhost_vdpa_device_realize(DeviceState *dev, Error **errp)
|
||||
strerror(-ret));
|
||||
goto free_vqs;
|
||||
}
|
||||
v->vdpa.iova_range = iova_range;
|
||||
v->vdpa.shared = g_new0(VhostVDPAShared, 1);
|
||||
v->vdpa.shared->device_fd = v->vhostfd;
|
||||
v->vdpa.shared->iova_range = iova_range;
|
||||
|
||||
ret = vhost_dev_init(&v->dev, &v->vdpa, VHOST_BACKEND_TYPE_VDPA, 0, NULL);
|
||||
if (ret < 0) {
|
||||
@@ -162,6 +163,7 @@ vhost_cleanup:
|
||||
vhost_dev_cleanup(&v->dev);
|
||||
free_vqs:
|
||||
g_free(vqs);
|
||||
g_free(v->vdpa.shared);
|
||||
out:
|
||||
qemu_close(v->vhostfd);
|
||||
v->vhostfd = -1;
|
||||
@@ -184,6 +186,7 @@ static void vhost_vdpa_device_unrealize(DeviceState *dev)
|
||||
g_free(s->config);
|
||||
g_free(s->dev.vqs);
|
||||
vhost_dev_cleanup(&s->dev);
|
||||
g_free(s->vdpa.shared);
|
||||
qemu_close(s->vhostfd);
|
||||
s->vhostfd = -1;
|
||||
}
|
||||
|
||||
@@ -158,6 +158,30 @@ static int vhost_kernel_set_vring_busyloop_timeout(struct vhost_dev *dev,
|
||||
return vhost_kernel_call(dev, VHOST_SET_VRING_BUSYLOOP_TIMEOUT, s);
|
||||
}
|
||||
|
||||
static int vhost_kernel_new_worker(struct vhost_dev *dev,
|
||||
struct vhost_worker_state *worker)
|
||||
{
|
||||
return vhost_kernel_call(dev, VHOST_NEW_WORKER, worker);
|
||||
}
|
||||
|
||||
static int vhost_kernel_free_worker(struct vhost_dev *dev,
|
||||
struct vhost_worker_state *worker)
|
||||
{
|
||||
return vhost_kernel_call(dev, VHOST_FREE_WORKER, worker);
|
||||
}
|
||||
|
||||
static int vhost_kernel_attach_vring_worker(struct vhost_dev *dev,
|
||||
struct vhost_vring_worker *worker)
|
||||
{
|
||||
return vhost_kernel_call(dev, VHOST_ATTACH_VRING_WORKER, worker);
|
||||
}
|
||||
|
||||
static int vhost_kernel_get_vring_worker(struct vhost_dev *dev,
|
||||
struct vhost_vring_worker *worker)
|
||||
{
|
||||
return vhost_kernel_call(dev, VHOST_GET_VRING_WORKER, worker);
|
||||
}
|
||||
|
||||
static int vhost_kernel_set_features(struct vhost_dev *dev,
|
||||
uint64_t features)
|
||||
{
|
||||
@@ -313,6 +337,10 @@ const VhostOps kernel_ops = {
|
||||
.vhost_set_vring_err = vhost_kernel_set_vring_err,
|
||||
.vhost_set_vring_busyloop_timeout =
|
||||
vhost_kernel_set_vring_busyloop_timeout,
|
||||
.vhost_get_vring_worker = vhost_kernel_get_vring_worker,
|
||||
.vhost_attach_vring_worker = vhost_kernel_attach_vring_worker,
|
||||
.vhost_new_worker = vhost_kernel_new_worker,
|
||||
.vhost_free_worker = vhost_kernel_free_worker,
|
||||
.vhost_set_features = vhost_kernel_set_features,
|
||||
.vhost_get_features = vhost_kernel_get_features,
|
||||
.vhost_set_backend_cap = vhost_kernel_set_backend_cap,
|
||||
|
||||
@@ -129,6 +129,14 @@ static void vu_rng_guest_notifier_mask(VirtIODevice *vdev, int idx, bool mask)
|
||||
{
|
||||
VHostUserRNG *rng = VHOST_USER_RNG(vdev);
|
||||
|
||||
/*
|
||||
* We don't support interrupts, return early if index is set to
|
||||
* VIRTIO_CONFIG_IRQ_IDX.
|
||||
*/
|
||||
if (idx == VIRTIO_CONFIG_IRQ_IDX) {
|
||||
return;
|
||||
}
|
||||
|
||||
vhost_virtqueue_mask(&rng->vhost_dev, vdev, idx, mask);
|
||||
}
|
||||
|
||||
@@ -136,6 +144,14 @@ static bool vu_rng_guest_notifier_pending(VirtIODevice *vdev, int idx)
|
||||
{
|
||||
VHostUserRNG *rng = VHOST_USER_RNG(vdev);
|
||||
|
||||
/*
|
||||
* We don't support interrupts, return early if index is set to
|
||||
* VIRTIO_CONFIG_IRQ_IDX.
|
||||
*/
|
||||
if (idx == VIRTIO_CONFIG_IRQ_IDX) {
|
||||
return false;
|
||||
}
|
||||
|
||||
return vhost_virtqueue_pending(&rng->vhost_dev, idx);
|
||||
}
|
||||
|
||||
|
||||
+85
-79
File diff suppressed because it is too large
Load Diff
@@ -45,6 +45,8 @@ struct vhost_memory;
|
||||
struct vhost_vring_file;
|
||||
struct vhost_vring_state;
|
||||
struct vhost_vring_addr;
|
||||
struct vhost_vring_worker;
|
||||
struct vhost_worker_state;
|
||||
struct vhost_scsi_target;
|
||||
struct vhost_iotlb_msg;
|
||||
struct vhost_virtqueue;
|
||||
@@ -85,6 +87,14 @@ typedef int (*vhost_set_vring_err_op)(struct vhost_dev *dev,
|
||||
struct vhost_vring_file *file);
|
||||
typedef int (*vhost_set_vring_busyloop_timeout_op)(struct vhost_dev *dev,
|
||||
struct vhost_vring_state *r);
|
||||
typedef int (*vhost_attach_vring_worker_op)(struct vhost_dev *dev,
|
||||
struct vhost_vring_worker *worker);
|
||||
typedef int (*vhost_get_vring_worker_op)(struct vhost_dev *dev,
|
||||
struct vhost_vring_worker *worker);
|
||||
typedef int (*vhost_new_worker_op)(struct vhost_dev *dev,
|
||||
struct vhost_worker_state *worker);
|
||||
typedef int (*vhost_free_worker_op)(struct vhost_dev *dev,
|
||||
struct vhost_worker_state *worker);
|
||||
typedef int (*vhost_set_features_op)(struct vhost_dev *dev,
|
||||
uint64_t features);
|
||||
typedef int (*vhost_get_features_op)(struct vhost_dev *dev,
|
||||
@@ -172,6 +182,10 @@ typedef struct VhostOps {
|
||||
vhost_set_vring_call_op vhost_set_vring_call;
|
||||
vhost_set_vring_err_op vhost_set_vring_err;
|
||||
vhost_set_vring_busyloop_timeout_op vhost_set_vring_busyloop_timeout;
|
||||
vhost_new_worker_op vhost_new_worker;
|
||||
vhost_free_worker_op vhost_free_worker;
|
||||
vhost_get_vring_worker_op vhost_get_vring_worker;
|
||||
vhost_attach_vring_worker_op vhost_attach_vring_worker;
|
||||
vhost_set_features_op vhost_set_features;
|
||||
vhost_get_features_op vhost_get_features;
|
||||
vhost_set_backend_cap_op vhost_set_backend_cap;
|
||||
|
||||
@@ -30,42 +30,52 @@ typedef struct VhostVDPAHostNotifier {
|
||||
void *addr;
|
||||
} VhostVDPAHostNotifier;
|
||||
|
||||
typedef struct vhost_vdpa {
|
||||
/* Info shared by all vhost_vdpa device models */
|
||||
typedef struct vhost_vdpa_shared {
|
||||
int device_fd;
|
||||
int index;
|
||||
uint32_t msg_type;
|
||||
bool iotlb_batch_begin_sent;
|
||||
uint32_t address_space_id;
|
||||
MemoryListener listener;
|
||||
struct vhost_vdpa_iova_range iova_range;
|
||||
uint64_t acked_features;
|
||||
bool shadow_vqs_enabled;
|
||||
/* Vdpa must send shadow addresses as IOTLB key for data queues, not GPA */
|
||||
bool shadow_data;
|
||||
/* Device suspended successfully */
|
||||
bool suspended;
|
||||
QLIST_HEAD(, vdpa_iommu) iommu_list;
|
||||
|
||||
/* IOVA mapping used by the Shadow Virtqueue */
|
||||
VhostIOVATree *iova_tree;
|
||||
|
||||
/* Copy of backend features */
|
||||
uint64_t backend_cap;
|
||||
|
||||
bool iotlb_batch_begin_sent;
|
||||
|
||||
/* Vdpa must send shadow addresses as IOTLB key for data queues, not GPA */
|
||||
bool shadow_data;
|
||||
} VhostVDPAShared;
|
||||
|
||||
typedef struct vhost_vdpa {
|
||||
int index;
|
||||
uint32_t address_space_id;
|
||||
uint64_t acked_features;
|
||||
bool shadow_vqs_enabled;
|
||||
/* Device suspended successfully */
|
||||
bool suspended;
|
||||
VhostVDPAShared *shared;
|
||||
GPtrArray *shadow_vqs;
|
||||
const VhostShadowVirtqueueOps *shadow_vq_ops;
|
||||
void *shadow_vq_ops_opaque;
|
||||
struct vhost_dev *dev;
|
||||
Error *migration_blocker;
|
||||
VhostVDPAHostNotifier notifier[VIRTIO_QUEUE_MAX];
|
||||
QLIST_HEAD(, vdpa_iommu) iommu_list;
|
||||
IOMMUNotifier n;
|
||||
} VhostVDPA;
|
||||
|
||||
int vhost_vdpa_get_iova_range(int fd, struct vhost_vdpa_iova_range *iova_range);
|
||||
int vhost_vdpa_set_vring_ready(struct vhost_vdpa *v, unsigned idx);
|
||||
|
||||
int vhost_vdpa_dma_map(struct vhost_vdpa *v, uint32_t asid, hwaddr iova,
|
||||
int vhost_vdpa_dma_map(VhostVDPAShared *s, uint32_t asid, hwaddr iova,
|
||||
hwaddr size, void *vaddr, bool readonly);
|
||||
int vhost_vdpa_dma_unmap(struct vhost_vdpa *v, uint32_t asid, hwaddr iova,
|
||||
int vhost_vdpa_dma_unmap(VhostVDPAShared *s, uint32_t asid, hwaddr iova,
|
||||
hwaddr size);
|
||||
|
||||
typedef struct vdpa_iommu {
|
||||
struct vhost_vdpa *dev;
|
||||
VhostVDPAShared *dev_shared;
|
||||
IOMMUMemoryRegion *iommu_mr;
|
||||
hwaddr iommu_offset;
|
||||
IOMMUNotifier n;
|
||||
|
||||
@@ -51,6 +51,7 @@ typedef struct virtio_scsi_config VirtIOSCSIConfig;
|
||||
struct VirtIOSCSIConf {
|
||||
uint32_t num_queues;
|
||||
uint32_t virtqueue_size;
|
||||
bool worker_per_virtqueue;
|
||||
bool seg_max_adjust;
|
||||
uint32_t max_sectors;
|
||||
uint32_t cmd_per_lun;
|
||||
|
||||
+57
-59
@@ -236,10 +236,11 @@ static void vhost_vdpa_cleanup(NetClientState *nc)
|
||||
g_free(s->vhost_net);
|
||||
s->vhost_net = NULL;
|
||||
}
|
||||
if (s->vhost_vdpa.device_fd >= 0) {
|
||||
qemu_close(s->vhost_vdpa.device_fd);
|
||||
s->vhost_vdpa.device_fd = -1;
|
||||
if (s->vhost_vdpa.index != 0) {
|
||||
return;
|
||||
}
|
||||
qemu_close(s->vhost_vdpa.shared->device_fd);
|
||||
g_free(s->vhost_vdpa.shared);
|
||||
}
|
||||
|
||||
/** Dummy SetSteeringEBPF to support RSS for vhost-vdpa backend */
|
||||
@@ -286,15 +287,6 @@ static ssize_t vhost_vdpa_receive(NetClientState *nc, const uint8_t *buf,
|
||||
return size;
|
||||
}
|
||||
|
||||
/** From any vdpa net client, get the netclient of the first queue pair */
|
||||
static VhostVDPAState *vhost_vdpa_net_first_nc_vdpa(VhostVDPAState *s)
|
||||
{
|
||||
NICState *nic = qemu_get_nic(s->nc.peer);
|
||||
NetClientState *nc0 = qemu_get_peer(nic->ncs, 0);
|
||||
|
||||
return DO_UPCAST(VhostVDPAState, nc, nc0);
|
||||
}
|
||||
|
||||
static void vhost_vdpa_net_log_global_enable(VhostVDPAState *s, bool enable)
|
||||
{
|
||||
struct vhost_vdpa *v = &s->vhost_vdpa;
|
||||
@@ -350,8 +342,8 @@ static void vhost_vdpa_net_data_start_first(VhostVDPAState *s)
|
||||
migration_add_notifier(&s->migration_state,
|
||||
vdpa_net_migration_state_notifier);
|
||||
if (v->shadow_vqs_enabled) {
|
||||
v->iova_tree = vhost_iova_tree_new(v->iova_range.first,
|
||||
v->iova_range.last);
|
||||
v->shared->iova_tree = vhost_iova_tree_new(v->shared->iova_range.first,
|
||||
v->shared->iova_range.last);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -365,22 +357,16 @@ static int vhost_vdpa_net_data_start(NetClientState *nc)
|
||||
if (s->always_svq ||
|
||||
migration_is_setup_or_active(migrate_get_current()->state)) {
|
||||
v->shadow_vqs_enabled = true;
|
||||
v->shadow_data = true;
|
||||
} else {
|
||||
v->shadow_vqs_enabled = false;
|
||||
v->shadow_data = false;
|
||||
}
|
||||
|
||||
if (v->index == 0) {
|
||||
v->shared->shadow_data = v->shadow_vqs_enabled;
|
||||
vhost_vdpa_net_data_start_first(s);
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (v->shadow_vqs_enabled) {
|
||||
VhostVDPAState *s0 = vhost_vdpa_net_first_nc_vdpa(s);
|
||||
v->iova_tree = s0->vhost_vdpa.iova_tree;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
@@ -413,9 +399,8 @@ static void vhost_vdpa_net_client_stop(NetClientState *nc)
|
||||
|
||||
dev = s->vhost_vdpa.dev;
|
||||
if (dev->vq_index + dev->nvqs == dev->vq_index_end) {
|
||||
g_clear_pointer(&s->vhost_vdpa.iova_tree, vhost_iova_tree_delete);
|
||||
} else {
|
||||
s->vhost_vdpa.iova_tree = NULL;
|
||||
g_clear_pointer(&s->vhost_vdpa.shared->iova_tree,
|
||||
vhost_iova_tree_delete);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -460,7 +445,7 @@ static int vhost_vdpa_set_address_space_id(struct vhost_vdpa *v,
|
||||
};
|
||||
int r;
|
||||
|
||||
r = ioctl(v->device_fd, VHOST_VDPA_SET_GROUP_ASID, &asid);
|
||||
r = ioctl(v->shared->device_fd, VHOST_VDPA_SET_GROUP_ASID, &asid);
|
||||
if (unlikely(r < 0)) {
|
||||
error_report("Can't set vq group %u asid %u, errno=%d (%s)",
|
||||
asid.index, asid.num, errno, g_strerror(errno));
|
||||
@@ -470,7 +455,7 @@ static int vhost_vdpa_set_address_space_id(struct vhost_vdpa *v,
|
||||
|
||||
static void vhost_vdpa_cvq_unmap_buf(struct vhost_vdpa *v, void *addr)
|
||||
{
|
||||
VhostIOVATree *tree = v->iova_tree;
|
||||
VhostIOVATree *tree = v->shared->iova_tree;
|
||||
DMAMap needle = {
|
||||
/*
|
||||
* No need to specify size or to look for more translations since
|
||||
@@ -486,7 +471,8 @@ static void vhost_vdpa_cvq_unmap_buf(struct vhost_vdpa *v, void *addr)
|
||||
return;
|
||||
}
|
||||
|
||||
r = vhost_vdpa_dma_unmap(v, v->address_space_id, map->iova, map->size + 1);
|
||||
r = vhost_vdpa_dma_unmap(v->shared, v->address_space_id, map->iova,
|
||||
map->size + 1);
|
||||
if (unlikely(r != 0)) {
|
||||
error_report("Device cannot unmap: %s(%d)", g_strerror(r), r);
|
||||
}
|
||||
@@ -504,13 +490,13 @@ static int vhost_vdpa_cvq_map_buf(struct vhost_vdpa *v, void *buf, size_t size,
|
||||
map.translated_addr = (hwaddr)(uintptr_t)buf;
|
||||
map.size = size - 1;
|
||||
map.perm = write ? IOMMU_RW : IOMMU_RO,
|
||||
r = vhost_iova_tree_map_alloc(v->iova_tree, &map);
|
||||
r = vhost_iova_tree_map_alloc(v->shared->iova_tree, &map);
|
||||
if (unlikely(r != IOVA_OK)) {
|
||||
error_report("Cannot map injected element");
|
||||
return r;
|
||||
}
|
||||
|
||||
r = vhost_vdpa_dma_map(v, v->address_space_id, map.iova,
|
||||
r = vhost_vdpa_dma_map(v->shared, v->address_space_id, map.iova,
|
||||
vhost_vdpa_net_cvq_cmd_page_len(), buf, !write);
|
||||
if (unlikely(r < 0)) {
|
||||
goto dma_map_err;
|
||||
@@ -519,13 +505,13 @@ static int vhost_vdpa_cvq_map_buf(struct vhost_vdpa *v, void *buf, size_t size,
|
||||
return 0;
|
||||
|
||||
dma_map_err:
|
||||
vhost_iova_tree_remove(v->iova_tree, map);
|
||||
vhost_iova_tree_remove(v->shared->iova_tree, map);
|
||||
return r;
|
||||
}
|
||||
|
||||
static int vhost_vdpa_net_cvq_start(NetClientState *nc)
|
||||
{
|
||||
VhostVDPAState *s, *s0;
|
||||
VhostVDPAState *s;
|
||||
struct vhost_vdpa *v;
|
||||
int64_t cvq_group;
|
||||
int r;
|
||||
@@ -536,12 +522,10 @@ static int vhost_vdpa_net_cvq_start(NetClientState *nc)
|
||||
s = DO_UPCAST(VhostVDPAState, nc, nc);
|
||||
v = &s->vhost_vdpa;
|
||||
|
||||
s0 = vhost_vdpa_net_first_nc_vdpa(s);
|
||||
v->shadow_data = s0->vhost_vdpa.shadow_vqs_enabled;
|
||||
v->shadow_vqs_enabled = s0->vhost_vdpa.shadow_vqs_enabled;
|
||||
v->shadow_vqs_enabled = v->shared->shadow_data;
|
||||
s->vhost_vdpa.address_space_id = VHOST_VDPA_GUEST_PA_ASID;
|
||||
|
||||
if (s->vhost_vdpa.shadow_data) {
|
||||
if (v->shared->shadow_data) {
|
||||
/* SVQ is already configured for all virtqueues */
|
||||
goto out;
|
||||
}
|
||||
@@ -558,7 +542,7 @@ static int vhost_vdpa_net_cvq_start(NetClientState *nc)
|
||||
return 0;
|
||||
}
|
||||
|
||||
cvq_group = vhost_vdpa_get_vring_group(v->device_fd,
|
||||
cvq_group = vhost_vdpa_get_vring_group(v->shared->device_fd,
|
||||
v->dev->vq_index_end - 1,
|
||||
&err);
|
||||
if (unlikely(cvq_group < 0)) {
|
||||
@@ -579,24 +563,22 @@ out:
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (s0->vhost_vdpa.iova_tree) {
|
||||
/*
|
||||
* SVQ is already configured for all virtqueues. Reuse IOVA tree for
|
||||
* simplicity, whether CVQ shares ASID with guest or not, because:
|
||||
* - Memory listener need access to guest's memory addresses allocated
|
||||
* in the IOVA tree.
|
||||
* - There should be plenty of IOVA address space for both ASID not to
|
||||
* worry about collisions between them. Guest's translations are
|
||||
* still validated with virtio virtqueue_pop so there is no risk for
|
||||
* the guest to access memory that it shouldn't.
|
||||
*
|
||||
* To allocate a iova tree per ASID is doable but it complicates the
|
||||
* code and it is not worth it for the moment.
|
||||
*/
|
||||
v->iova_tree = s0->vhost_vdpa.iova_tree;
|
||||
} else {
|
||||
v->iova_tree = vhost_iova_tree_new(v->iova_range.first,
|
||||
v->iova_range.last);
|
||||
/*
|
||||
* If other vhost_vdpa already have an iova_tree, reuse it for simplicity,
|
||||
* whether CVQ shares ASID with guest or not, because:
|
||||
* - Memory listener need access to guest's memory addresses allocated in
|
||||
* the IOVA tree.
|
||||
* - There should be plenty of IOVA address space for both ASID not to
|
||||
* worry about collisions between them. Guest's translations are still
|
||||
* validated with virtio virtqueue_pop so there is no risk for the guest
|
||||
* to access memory that it shouldn't.
|
||||
*
|
||||
* To allocate a iova tree per ASID is doable but it complicates the code
|
||||
* and it is not worth it for the moment.
|
||||
*/
|
||||
if (!v->shared->iova_tree) {
|
||||
v->shared->iova_tree = vhost_iova_tree_new(v->shared->iova_range.first,
|
||||
v->shared->iova_range.last);
|
||||
}
|
||||
|
||||
r = vhost_vdpa_cvq_map_buf(&s->vhost_vdpa, s->cvq_cmd_out_buffer,
|
||||
@@ -1661,6 +1643,7 @@ static NetClientState *net_vhost_vdpa_init(NetClientState *peer,
|
||||
bool svq,
|
||||
struct vhost_vdpa_iova_range iova_range,
|
||||
uint64_t features,
|
||||
VhostVDPAShared *shared,
|
||||
Error **errp)
|
||||
{
|
||||
NetClientState *nc = NULL;
|
||||
@@ -1686,16 +1669,17 @@ static NetClientState *net_vhost_vdpa_init(NetClientState *peer,
|
||||
qemu_set_info_str(nc, TYPE_VHOST_VDPA);
|
||||
s = DO_UPCAST(VhostVDPAState, nc, nc);
|
||||
|
||||
s->vhost_vdpa.device_fd = vdpa_device_fd;
|
||||
s->vhost_vdpa.index = queue_pair_index;
|
||||
s->always_svq = svq;
|
||||
s->migration_state.notify = NULL;
|
||||
s->vhost_vdpa.shadow_vqs_enabled = svq;
|
||||
s->vhost_vdpa.iova_range = iova_range;
|
||||
s->vhost_vdpa.shadow_data = svq;
|
||||
if (queue_pair_index == 0) {
|
||||
vhost_vdpa_net_valid_svq_features(features,
|
||||
&s->vhost_vdpa.migration_blocker);
|
||||
s->vhost_vdpa.shared = g_new0(VhostVDPAShared, 1);
|
||||
s->vhost_vdpa.shared->device_fd = vdpa_device_fd;
|
||||
s->vhost_vdpa.shared->iova_range = iova_range;
|
||||
s->vhost_vdpa.shared->shadow_data = svq;
|
||||
} else if (!is_datapath) {
|
||||
s->cvq_cmd_out_buffer = mmap(NULL, vhost_vdpa_net_cvq_cmd_page_len(),
|
||||
PROT_READ | PROT_WRITE,
|
||||
@@ -1708,11 +1692,16 @@ static NetClientState *net_vhost_vdpa_init(NetClientState *peer,
|
||||
s->vhost_vdpa.shadow_vq_ops_opaque = s;
|
||||
s->cvq_isolated = cvq_isolated;
|
||||
}
|
||||
if (queue_pair_index != 0) {
|
||||
s->vhost_vdpa.shared = shared;
|
||||
}
|
||||
|
||||
ret = vhost_vdpa_add(nc, (void *)&s->vhost_vdpa, queue_pair_index, nvqs);
|
||||
if (ret) {
|
||||
qemu_del_net_client(nc);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
return nc;
|
||||
}
|
||||
|
||||
@@ -1824,17 +1813,26 @@ int net_init_vhost_vdpa(const Netdev *netdev, const char *name,
|
||||
ncs = g_malloc0(sizeof(*ncs) * queue_pairs);
|
||||
|
||||
for (i = 0; i < queue_pairs; i++) {
|
||||
VhostVDPAShared *shared = NULL;
|
||||
|
||||
if (i) {
|
||||
shared = DO_UPCAST(VhostVDPAState, nc, ncs[0])->vhost_vdpa.shared;
|
||||
}
|
||||
ncs[i] = net_vhost_vdpa_init(peer, TYPE_VHOST_VDPA, name,
|
||||
vdpa_device_fd, i, 2, true, opts->x_svq,
|
||||
iova_range, features, errp);
|
||||
iova_range, features, shared, errp);
|
||||
if (!ncs[i])
|
||||
goto err;
|
||||
}
|
||||
|
||||
if (has_cvq) {
|
||||
VhostVDPAState *s0 = DO_UPCAST(VhostVDPAState, nc, ncs[0]);
|
||||
VhostVDPAShared *shared = s0->vhost_vdpa.shared;
|
||||
|
||||
nc = net_vhost_vdpa_init(peer, TYPE_VHOST_VDPA, name,
|
||||
vdpa_device_fd, i, 1, false,
|
||||
opts->x_svq, iova_range, features, errp);
|
||||
opts->x_svq, iova_range, features, shared,
|
||||
errp);
|
||||
if (!nc)
|
||||
goto err;
|
||||
}
|
||||
|
||||
@@ -1015,7 +1015,7 @@ static void test_acpi_q35_tcg(void)
|
||||
free_test_data(&data);
|
||||
}
|
||||
|
||||
static void test_acpi_q35_tcg_type4_count(void)
|
||||
static void test_acpi_q35_kvm_type4_count(void)
|
||||
{
|
||||
test_data data = {
|
||||
.machine = MACHINE_Q35,
|
||||
@@ -1031,7 +1031,7 @@ static void test_acpi_q35_tcg_type4_count(void)
|
||||
free_test_data(&data);
|
||||
}
|
||||
|
||||
static void test_acpi_q35_tcg_core_count(void)
|
||||
static void test_acpi_q35_kvm_core_count(void)
|
||||
{
|
||||
test_data data = {
|
||||
.machine = MACHINE_Q35,
|
||||
@@ -1048,7 +1048,7 @@ static void test_acpi_q35_tcg_core_count(void)
|
||||
free_test_data(&data);
|
||||
}
|
||||
|
||||
static void test_acpi_q35_tcg_core_count2(void)
|
||||
static void test_acpi_q35_kvm_core_count2(void)
|
||||
{
|
||||
test_data data = {
|
||||
.machine = MACHINE_Q35,
|
||||
@@ -1065,7 +1065,7 @@ static void test_acpi_q35_tcg_core_count2(void)
|
||||
free_test_data(&data);
|
||||
}
|
||||
|
||||
static void test_acpi_q35_tcg_thread_count(void)
|
||||
static void test_acpi_q35_kvm_thread_count(void)
|
||||
{
|
||||
test_data data = {
|
||||
.machine = MACHINE_Q35,
|
||||
@@ -1082,7 +1082,7 @@ static void test_acpi_q35_tcg_thread_count(void)
|
||||
free_test_data(&data);
|
||||
}
|
||||
|
||||
static void test_acpi_q35_tcg_thread_count2(void)
|
||||
static void test_acpi_q35_kvm_thread_count2(void)
|
||||
{
|
||||
test_data data = {
|
||||
.machine = MACHINE_Q35,
|
||||
@@ -2262,15 +2262,15 @@ int main(int argc, char *argv[])
|
||||
qtest_add_func("acpi/q35/kvm/xapic", test_acpi_q35_kvm_xapic);
|
||||
qtest_add_func("acpi/q35/kvm/dmar", test_acpi_q35_kvm_dmar);
|
||||
qtest_add_func("acpi/q35/type4-count",
|
||||
test_acpi_q35_tcg_type4_count);
|
||||
test_acpi_q35_kvm_type4_count);
|
||||
qtest_add_func("acpi/q35/core-count",
|
||||
test_acpi_q35_tcg_core_count);
|
||||
test_acpi_q35_kvm_core_count);
|
||||
qtest_add_func("acpi/q35/core-count2",
|
||||
test_acpi_q35_tcg_core_count2);
|
||||
test_acpi_q35_kvm_core_count2);
|
||||
qtest_add_func("acpi/q35/thread-count",
|
||||
test_acpi_q35_tcg_thread_count);
|
||||
test_acpi_q35_kvm_thread_count);
|
||||
qtest_add_func("acpi/q35/thread-count2",
|
||||
test_acpi_q35_tcg_thread_count2);
|
||||
test_acpi_q35_kvm_thread_count2);
|
||||
}
|
||||
if (qtest_has_device("virtio-iommu-pci")) {
|
||||
qtest_add_func("acpi/q35/viot", test_acpi_q35_viot);
|
||||
|
||||
Reference in New Issue
Block a user