Merge remote-tracking branch 'remotes/mst/tags/for_upstream' into staging

pc,pci,virtio: features, fixes, tests

vhost user rng
vdpa multiqueue
Fixes, cleanups, new tests all over the place.

Signed-off-by: Michael S. Tsirkin <mst@redhat.com>

# gpg: Signature made Wed 20 Oct 2021 03:18:24 AM PDT
# 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]

* remotes/mst/tags/for_upstream: (44 commits)
  tests/acpi/bios-tables-test: update DSDT blob for multifunction bridge test
  tests/acpi/pcihp: add unit tests for hotplug on multifunction bridges for q35
  tests/acpi/bios-tables-test: add and allow changes to a new q35 DSDT table blob
  pci: fix PCI resource reserve capability on BE
  vhost-vdpa: multiqueue support
  virtio-net: vhost control virtqueue support
  vhost: record the last virtqueue index for the virtio device
  virtio-net: use "queue_pairs" instead of "queues" when possible
  vhost-net: control virtqueue support
  net: introduce control client
  vhost-vdpa: let net_vhost_vdpa_init() returns NetClientState *
  vhost-vdpa: prepare for the multiqueue support
  vhost-vdpa: classify one time request
  vhost-vdpa: open device fd in net_init_vhost_vdpa()
  bios-tables-test: don't disassemble empty files
  rebuild-expected-aml.sh: allow partial target list
  qdev/qbus: remove failover specific code
  vhost-user-blk-test: pass vhost-user socket fds to QSD
  failover: fix a regression introduced by JSON'ification of -device
  vhost-user: fix duplicated notifier MR init
  ...

Signed-off-by: Richard Henderson <richard.henderson@linaro.org>
This commit is contained in:
Richard Henderson
2021-10-20 06:10:51 -07:00
42 changed files with 1075 additions and 233 deletions
+1
View File
@@ -88,3 +88,4 @@ Emulated Devices
devices/usb.rst
devices/vhost-user.rst
devices/virtio-pmem.rst
devices/vhost-user-rng.rst
+39
View File
@@ -0,0 +1,39 @@
QEMU vhost-user-rng - RNG emulation
===================================
Background
----------
What follows builds on the material presented in vhost-user.rst - it should
be reviewed before moving forward with the content in this file.
Description
-----------
The vhost-user-rng device implementation was designed to work with a random
number generator daemon such as the one found in the vhost-device crate of
the rust-vmm project available on github [1].
[1]. https://github.com/rust-vmm/vhost-device
Examples
--------
The daemon should be started first:
::
host# vhost-device-rng --socket-path=rng.sock -c 1 -m 512 -p 1000
The QEMU invocation needs to create a chardev socket the device can
use to communicate as well as share the guests memory over a memfd.
::
host# qemu-system \
-chardev socket,path=$(PATH)/rng.sock,id=rng0 \
-device vhost-user-rng-pci,chardev=rng0 \
-m 4096 \
-object memory-backend-file,id=mem,size=4G,mem-path=/dev/shm,share=on \
-numa node,memdev=mem \
...
+2 -2
View File
@@ -33,13 +33,13 @@ struct vhost_net *vhost_net_init(VhostNetOptions *options)
int vhost_net_start(VirtIODevice *dev,
NetClientState *ncs,
int total_queues)
int data_queue_pairs, int cvq)
{
return -ENOSYS;
}
void vhost_net_stop(VirtIODevice *dev,
NetClientState *ncs,
int total_queues)
int data_queue_pairs, int cvq)
{
}
+41 -14
View File
@@ -231,9 +231,11 @@ fail:
return NULL;
}
static void vhost_net_set_vq_index(struct vhost_net *net, int vq_index)
static void vhost_net_set_vq_index(struct vhost_net *net, int vq_index,
int last_index)
{
net->dev.vq_index = vq_index;
net->dev.last_index = last_index;
}
static int vhost_net_start_one(struct vhost_net *net,
@@ -315,25 +317,37 @@ static void vhost_net_stop_one(struct vhost_net *net,
}
int vhost_net_start(VirtIODevice *dev, NetClientState *ncs,
int total_queues)
int data_queue_pairs, int cvq)
{
BusState *qbus = BUS(qdev_get_parent_bus(DEVICE(dev)));
VirtioBusState *vbus = VIRTIO_BUS(qbus);
VirtioBusClass *k = VIRTIO_BUS_GET_CLASS(vbus);
int total_notifiers = data_queue_pairs * 2 + cvq;
VirtIONet *n = VIRTIO_NET(dev);
int nvhosts = data_queue_pairs + cvq;
struct vhost_net *net;
int r, e, i;
int r, e, i, last_index = data_queue_pairs * 2;
NetClientState *peer;
if (!cvq) {
last_index -= 1;
}
if (!k->set_guest_notifiers) {
error_report("binding does not support guest notifiers");
return -ENOSYS;
}
for (i = 0; i < total_queues; i++) {
for (i = 0; i < nvhosts; i++) {
if (i < data_queue_pairs) {
peer = qemu_get_peer(ncs, i);
} else { /* Control Virtqueue */
peer = qemu_get_peer(ncs, n->max_queue_pairs);
}
peer = qemu_get_peer(ncs, i);
net = get_vhost_net(peer);
vhost_net_set_vq_index(net, i * 2);
vhost_net_set_vq_index(net, i * 2, last_index);
/* Suppress the masking guest notifiers on vhost user
* because vhost user doesn't interrupt masking/unmasking
@@ -344,14 +358,18 @@ int vhost_net_start(VirtIODevice *dev, NetClientState *ncs,
}
}
r = k->set_guest_notifiers(qbus->parent, total_queues * 2, true);
r = k->set_guest_notifiers(qbus->parent, total_notifiers, true);
if (r < 0) {
error_report("Error binding guest notifier: %d", -r);
goto err;
}
for (i = 0; i < total_queues; i++) {
peer = qemu_get_peer(ncs, i);
for (i = 0; i < nvhosts; i++) {
if (i < data_queue_pairs) {
peer = qemu_get_peer(ncs, i);
} else {
peer = qemu_get_peer(ncs, n->max_queue_pairs);
}
r = vhost_net_start_one(get_vhost_net(peer), dev);
if (r < 0) {
@@ -375,7 +393,7 @@ err_start:
peer = qemu_get_peer(ncs , i);
vhost_net_stop_one(get_vhost_net(peer), dev);
}
e = k->set_guest_notifiers(qbus->parent, total_queues * 2, false);
e = k->set_guest_notifiers(qbus->parent, total_notifiers, false);
if (e < 0) {
fprintf(stderr, "vhost guest notifier cleanup failed: %d\n", e);
fflush(stderr);
@@ -385,18 +403,27 @@ err:
}
void vhost_net_stop(VirtIODevice *dev, NetClientState *ncs,
int total_queues)
int data_queue_pairs, int cvq)
{
BusState *qbus = BUS(qdev_get_parent_bus(DEVICE(dev)));
VirtioBusState *vbus = VIRTIO_BUS(qbus);
VirtioBusClass *k = VIRTIO_BUS_GET_CLASS(vbus);
VirtIONet *n = VIRTIO_NET(dev);
NetClientState *peer;
int total_notifiers = data_queue_pairs * 2 + cvq;
int nvhosts = data_queue_pairs + cvq;
int i, r;
for (i = 0; i < total_queues; i++) {
vhost_net_stop_one(get_vhost_net(ncs[i].peer), dev);
for (i = 0; i < nvhosts; i++) {
if (i < data_queue_pairs) {
peer = qemu_get_peer(ncs, i);
} else {
peer = qemu_get_peer(ncs, n->max_queue_pairs);
}
vhost_net_stop_one(get_vhost_net(peer), dev);
}
r = k->set_guest_notifiers(qbus->parent, total_queues * 2, false);
r = k->set_guest_notifiers(qbus->parent, total_notifiers, false);
if (r < 0) {
fprintf(stderr, "vhost guest notifier cleanup failed: %d\n", r);
fflush(stderr);
+119 -82
View File
File diff suppressed because it is too large Load Diff
+5 -5
View File
@@ -448,11 +448,11 @@ int pci_bridge_qemu_reserve_cap_init(PCIDevice *dev, int cap_offset,
PCIBridgeQemuCap cap = {
.len = cap_len,
.type = REDHAT_PCI_CAP_RESOURCE_RESERVE,
.bus_res = res_reserve.bus,
.io = res_reserve.io,
.mem = res_reserve.mem_non_pref,
.mem_pref_32 = res_reserve.mem_pref_32,
.mem_pref_64 = res_reserve.mem_pref_64
.bus_res = cpu_to_le32(res_reserve.bus),
.io = cpu_to_le64(res_reserve.io),
.mem = cpu_to_le32(res_reserve.mem_non_pref),
.mem_pref_32 = cpu_to_le32(res_reserve.mem_pref_32),
.mem_pref_64 = cpu_to_le64(res_reserve.mem_pref_64)
};
int offset = pci_add_capability(dev, PCI_CAP_ID_VNDR,
+5
View File
@@ -63,3 +63,8 @@ config VHOST_USER_I2C
bool
default y
depends on VIRTIO && VHOST_USER
config VHOST_USER_RNG
bool
default y
depends on VIRTIO && VHOST_USER
+2
View File
@@ -27,6 +27,8 @@ virtio_ss.add(when: 'CONFIG_VIRTIO_IOMMU', if_true: files('virtio-iommu.c'))
virtio_ss.add(when: 'CONFIG_VIRTIO_MEM', if_true: files('virtio-mem.c'))
virtio_ss.add(when: 'CONFIG_VHOST_USER_I2C', if_true: files('vhost-user-i2c.c'))
virtio_ss.add(when: ['CONFIG_VIRTIO_PCI', 'CONFIG_VHOST_USER_I2C'], if_true: files('vhost-user-i2c-pci.c'))
virtio_ss.add(when: 'CONFIG_VHOST_USER_RNG', if_true: files('vhost-user-rng.c'))
virtio_ss.add(when: ['CONFIG_VHOST_USER_RNG', 'CONFIG_VIRTIO_PCI'], if_true: files('vhost-user-rng-pci.c'))
virtio_pci_ss = ss.source_set()
virtio_pci_ss.add(when: 'CONFIG_VHOST_VSOCK', if_true: files('vhost-vsock-pci.c'))
+1
View File
@@ -52,6 +52,7 @@ vhost_vdpa_set_vring_call(void *dev, unsigned int index, int fd) "dev: %p index:
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
vhost_vdpa_get_iova_range(void *dev, uint64_t first, uint64_t last) "dev: %p first: 0x%"PRIx64" last: 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"
+79
View File
@@ -0,0 +1,79 @@
/*
* Vhost-user RNG virtio device PCI glue
*
* Copyright (c) 2021 Mathieu Poirier <mathieu.poirier@linaro.org>
*
* SPDX-License-Identifier: GPL-2.0-or-later
*/
#include "qemu/osdep.h"
#include "hw/qdev-properties.h"
#include "hw/virtio/vhost-user-rng.h"
#include "virtio-pci.h"
struct VHostUserRNGPCI {
VirtIOPCIProxy parent_obj;
VHostUserRNG vdev;
};
typedef struct VHostUserRNGPCI VHostUserRNGPCI;
#define TYPE_VHOST_USER_RNG_PCI "vhost-user-rng-pci-base"
DECLARE_INSTANCE_CHECKER(VHostUserRNGPCI, VHOST_USER_RNG_PCI,
TYPE_VHOST_USER_RNG_PCI)
static Property vhost_user_rng_pci_properties[] = {
DEFINE_PROP_UINT32("vectors", VirtIOPCIProxy, nvectors,
DEV_NVECTORS_UNSPECIFIED),
DEFINE_PROP_END_OF_LIST(),
};
static void vhost_user_rng_pci_realize(VirtIOPCIProxy *vpci_dev, Error **errp)
{
VHostUserRNGPCI *dev = VHOST_USER_RNG_PCI(vpci_dev);
DeviceState *vdev = DEVICE(&dev->vdev);
if (vpci_dev->nvectors == DEV_NVECTORS_UNSPECIFIED) {
vpci_dev->nvectors = 1;
}
qdev_realize(vdev, BUS(&vpci_dev->bus), errp);
}
static void vhost_user_rng_pci_class_init(ObjectClass *klass, void *data)
{
DeviceClass *dc = DEVICE_CLASS(klass);
VirtioPCIClass *k = VIRTIO_PCI_CLASS(klass);
PCIDeviceClass *pcidev_k = PCI_DEVICE_CLASS(klass);
k->realize = vhost_user_rng_pci_realize;
set_bit(DEVICE_CATEGORY_INPUT, dc->categories);
device_class_set_props(dc, vhost_user_rng_pci_properties);
pcidev_k->vendor_id = PCI_VENDOR_ID_REDHAT_QUMRANET;
pcidev_k->device_id = 0; /* Set by virtio-pci based on virtio id */
pcidev_k->revision = 0x00;
pcidev_k->class_id = PCI_CLASS_OTHERS;
}
static void vhost_user_rng_pci_instance_init(Object *obj)
{
VHostUserRNGPCI *dev = VHOST_USER_RNG_PCI(obj);
virtio_instance_init_common(obj, &dev->vdev, sizeof(dev->vdev),
TYPE_VHOST_USER_RNG);
}
static const VirtioPCIDeviceTypeInfo vhost_user_rng_pci_info = {
.base_name = TYPE_VHOST_USER_RNG_PCI,
.non_transitional_name = "vhost-user-rng-pci",
.instance_size = sizeof(VHostUserRNGPCI),
.instance_init = vhost_user_rng_pci_instance_init,
.class_init = vhost_user_rng_pci_class_init,
};
static void vhost_user_rng_pci_register(void)
{
virtio_pci_types_register(&vhost_user_rng_pci_info);
}
type_init(vhost_user_rng_pci_register);
+289
View File
@@ -0,0 +1,289 @@
/*
* Vhost-user RNG virtio device
*
* Copyright (c) 2021 Mathieu Poirier <mathieu.poirier@linaro.org>
*
* Implementation seriously tailored on vhost-user-i2c.c
*
* SPDX-License-Identifier: GPL-2.0-or-later
*/
#include "qemu/osdep.h"
#include "qapi/error.h"
#include "hw/qdev-properties.h"
#include "hw/virtio/virtio-bus.h"
#include "hw/virtio/vhost-user-rng.h"
#include "qemu/error-report.h"
#include "standard-headers/linux/virtio_ids.h"
static void vu_rng_start(VirtIODevice *vdev)
{
VHostUserRNG *rng = VHOST_USER_RNG(vdev);
BusState *qbus = BUS(qdev_get_parent_bus(DEVICE(vdev)));
VirtioBusClass *k = VIRTIO_BUS_GET_CLASS(qbus);
int ret;
int i;
if (!k->set_guest_notifiers) {
error_report("binding does not support guest notifiers");
return;
}
ret = vhost_dev_enable_notifiers(&rng->vhost_dev, vdev);
if (ret < 0) {
error_report("Error enabling host notifiers: %d", -ret);
return;
}
ret = k->set_guest_notifiers(qbus->parent, rng->vhost_dev.nvqs, true);
if (ret < 0) {
error_report("Error binding guest notifier: %d", -ret);
goto err_host_notifiers;
}
rng->vhost_dev.acked_features = vdev->guest_features;
ret = vhost_dev_start(&rng->vhost_dev, vdev);
if (ret < 0) {
error_report("Error starting vhost-user-rng: %d", -ret);
goto err_guest_notifiers;
}
/*
* guest_notifier_mask/pending not used yet, so just unmask
* everything here. virtio-pci will do the right thing by
* enabling/disabling irqfd.
*/
for (i = 0; i < rng->vhost_dev.nvqs; i++) {
vhost_virtqueue_mask(&rng->vhost_dev, vdev, i, false);
}
return;
err_guest_notifiers:
k->set_guest_notifiers(qbus->parent, rng->vhost_dev.nvqs, false);
err_host_notifiers:
vhost_dev_disable_notifiers(&rng->vhost_dev, vdev);
}
static void vu_rng_stop(VirtIODevice *vdev)
{
VHostUserRNG *rng = VHOST_USER_RNG(vdev);
BusState *qbus = BUS(qdev_get_parent_bus(DEVICE(vdev)));
VirtioBusClass *k = VIRTIO_BUS_GET_CLASS(qbus);
int ret;
if (!k->set_guest_notifiers) {
return;
}
vhost_dev_stop(&rng->vhost_dev, vdev);
ret = k->set_guest_notifiers(qbus->parent, rng->vhost_dev.nvqs, false);
if (ret < 0) {
error_report("vhost guest notifier cleanup failed: %d", ret);
return;
}
vhost_dev_disable_notifiers(&rng->vhost_dev, vdev);
}
static void vu_rng_set_status(VirtIODevice *vdev, uint8_t status)
{
VHostUserRNG *rng = VHOST_USER_RNG(vdev);
bool should_start = status & VIRTIO_CONFIG_S_DRIVER_OK;
if (!vdev->vm_running) {
should_start = false;
}
if (rng->vhost_dev.started == should_start) {
return;
}
if (should_start) {
vu_rng_start(vdev);
} else {
vu_rng_stop(vdev);
}
}
static uint64_t vu_rng_get_features(VirtIODevice *vdev,
uint64_t requested_features, Error **errp)
{
/* No feature bits used yet */
return requested_features;
}
static void vu_rng_handle_output(VirtIODevice *vdev, VirtQueue *vq)
{
/*
* Not normally called; it's the daemon that handles the queue;
* however virtio's cleanup path can call this.
*/
}
static void vu_rng_guest_notifier_mask(VirtIODevice *vdev, int idx, bool mask)
{
VHostUserRNG *rng = VHOST_USER_RNG(vdev);
vhost_virtqueue_mask(&rng->vhost_dev, vdev, idx, mask);
}
static bool vu_rng_guest_notifier_pending(VirtIODevice *vdev, int idx)
{
VHostUserRNG *rng = VHOST_USER_RNG(vdev);
return vhost_virtqueue_pending(&rng->vhost_dev, idx);
}
static void vu_rng_connect(DeviceState *dev)
{
VirtIODevice *vdev = VIRTIO_DEVICE(dev);
VHostUserRNG *rng = VHOST_USER_RNG(vdev);
if (rng->connected) {
return;
}
rng->connected = true;
/* restore vhost state */
if (virtio_device_started(vdev, vdev->status)) {
vu_rng_start(vdev);
}
}
static void vu_rng_disconnect(DeviceState *dev)
{
VirtIODevice *vdev = VIRTIO_DEVICE(dev);
VHostUserRNG *rng = VHOST_USER_RNG(vdev);
if (!rng->connected) {
return;
}
rng->connected = false;
if (rng->vhost_dev.started) {
vu_rng_stop(vdev);
}
}
static void vu_rng_event(void *opaque, QEMUChrEvent event)
{
DeviceState *dev = opaque;
switch (event) {
case CHR_EVENT_OPENED:
vu_rng_connect(dev);
break;
case CHR_EVENT_CLOSED:
vu_rng_disconnect(dev);
break;
case CHR_EVENT_BREAK:
case CHR_EVENT_MUX_IN:
case CHR_EVENT_MUX_OUT:
/* Ignore */
break;
}
}
static void vu_rng_device_realize(DeviceState *dev, Error **errp)
{
VirtIODevice *vdev = VIRTIO_DEVICE(dev);
VHostUserRNG *rng = VHOST_USER_RNG(dev);
int ret;
if (!rng->chardev.chr) {
error_setg(errp, "missing chardev");
return;
}
if (!vhost_user_init(&rng->vhost_user, &rng->chardev, errp)) {
return;
}
virtio_init(vdev, "vhost-user-rng", VIRTIO_ID_RNG, 0);
rng->req_vq = virtio_add_queue(vdev, 4, vu_rng_handle_output);
if (!rng->req_vq) {
error_setg_errno(errp, -1, "virtio_add_queue() failed");
goto virtio_add_queue_failed;
}
rng->vhost_dev.nvqs = 1;
rng->vhost_dev.vqs = g_new0(struct vhost_virtqueue, rng->vhost_dev.nvqs);
ret = vhost_dev_init(&rng->vhost_dev, &rng->vhost_user,
VHOST_BACKEND_TYPE_USER, 0, errp);
if (ret < 0) {
error_setg_errno(errp, -ret, "vhost_dev_init() failed");
goto vhost_dev_init_failed;
}
qemu_chr_fe_set_handlers(&rng->chardev, NULL, NULL, vu_rng_event, NULL,
dev, NULL, true);
return;
vhost_dev_init_failed:
virtio_delete_queue(rng->req_vq);
virtio_add_queue_failed:
virtio_cleanup(vdev);
vhost_user_cleanup(&rng->vhost_user);
}
static void vu_rng_device_unrealize(DeviceState *dev)
{
VirtIODevice *vdev = VIRTIO_DEVICE(dev);
VHostUserRNG *rng = VHOST_USER_RNG(dev);
vu_rng_set_status(vdev, 0);
vhost_dev_cleanup(&rng->vhost_dev);
g_free(rng->vhost_dev.vqs);
rng->vhost_dev.vqs = NULL;
virtio_delete_queue(rng->req_vq);
virtio_cleanup(vdev);
vhost_user_cleanup(&rng->vhost_user);
}
static const VMStateDescription vu_rng_vmstate = {
.name = "vhost-user-rng",
.unmigratable = 1,
};
static Property vu_rng_properties[] = {
DEFINE_PROP_CHR("chardev", VHostUserRNG, chardev),
DEFINE_PROP_END_OF_LIST(),
};
static void vu_rng_class_init(ObjectClass *klass, void *data)
{
DeviceClass *dc = DEVICE_CLASS(klass);
VirtioDeviceClass *vdc = VIRTIO_DEVICE_CLASS(klass);
device_class_set_props(dc, vu_rng_properties);
dc->vmsd = &vu_rng_vmstate;
set_bit(DEVICE_CATEGORY_INPUT, dc->categories);
vdc->realize = vu_rng_device_realize;
vdc->unrealize = vu_rng_device_unrealize;
vdc->get_features = vu_rng_get_features;
vdc->set_status = vu_rng_set_status;
vdc->guest_notifier_mask = vu_rng_guest_notifier_mask;
vdc->guest_notifier_pending = vu_rng_guest_notifier_pending;
}
static const TypeInfo vu_rng_info = {
.name = TYPE_VHOST_USER_RNG,
.parent = TYPE_VIRTIO_DEVICE,
.instance_size = sizeof(VHostUserRNG),
.class_init = vu_rng_class_init,
};
static void vu_rng_register_types(void)
{
type_register_static(&vu_rng_info);
}
type_init(vu_rng_register_types)
+3 -2
View File
@@ -1526,8 +1526,9 @@ static int vhost_user_slave_handle_vring_host_notifier(struct vhost_dev *dev,
name = g_strdup_printf("vhost-user/host-notifier@%p mmaps[%d]",
user, queue_idx);
memory_region_init_ram_device_ptr(&n->mr, OBJECT(vdev), name,
page_size, addr);
if (!n->mr.ram) /* Don't init again after suspend. */
memory_region_init_ram_device_ptr(&n->mr, OBJECT(vdev), name,
page_size, addr);
g_free(name);
if (virtio_queue_set_host_notifier_mr(vdev, queue_idx, &n->mr, true)) {
+111 -29
View File
@@ -24,19 +24,49 @@
#include "trace.h"
#include "qemu-common.h"
static bool vhost_vdpa_listener_skipped_section(MemoryRegionSection *section)
/*
* Return one past the end of the end of section. Be careful with uint64_t
* conversions!
*/
static Int128 vhost_vdpa_section_end(const MemoryRegionSection *section)
{
return (!memory_region_is_ram(section->mr) &&
!memory_region_is_iommu(section->mr)) ||
/* vhost-vDPA doesn't allow MMIO to be mapped */
memory_region_is_ram_device(section->mr) ||
/*
* Sizing an enabled 64-bit BAR can cause spurious mappings to
* addresses in the upper part of the 64-bit address space. These
* are never accessed by the CPU and beyond the address width of
* some IOMMU hardware. TODO: VDPA should tell us the IOMMU width.
*/
section->offset_within_address_space & (1ULL << 63);
Int128 llend = int128_make64(section->offset_within_address_space);
llend = int128_add(llend, section->size);
llend = int128_and(llend, int128_exts64(TARGET_PAGE_MASK));
return llend;
}
static bool vhost_vdpa_listener_skipped_section(MemoryRegionSection *section,
uint64_t iova_min,
uint64_t iova_max)
{
Int128 llend;
if ((!memory_region_is_ram(section->mr) &&
!memory_region_is_iommu(section->mr)) ||
memory_region_is_protected(section->mr) ||
/* vhost-vDPA doesn't allow MMIO to be mapped */
memory_region_is_ram_device(section->mr)) {
return true;
}
if (section->offset_within_address_space < iova_min) {
error_report("RAM section out of device range (min=0x%" PRIx64
", addr=0x%" HWADDR_PRIx ")",
iova_min, section->offset_within_address_space);
return true;
}
llend = vhost_vdpa_section_end(section);
if (int128_gt(llend, int128_make64(iova_max))) {
error_report("RAM section out of device range (max=0x%" PRIx64
", end addr=0x%" PRIx64 ")",
iova_max, int128_get64(llend));
return true;
}
return false;
}
static int vhost_vdpa_dma_map(struct vhost_vdpa *v, hwaddr iova, hwaddr size,
@@ -148,7 +178,8 @@ static void vhost_vdpa_listener_region_add(MemoryListener *listener,
void *vaddr;
int ret;
if (vhost_vdpa_listener_skipped_section(section)) {
if (vhost_vdpa_listener_skipped_section(section, v->iova_range.first,
v->iova_range.last)) {
return;
}
@@ -159,10 +190,7 @@ static void vhost_vdpa_listener_region_add(MemoryListener *listener,
}
iova = TARGET_PAGE_ALIGN(section->offset_within_address_space);
llend = int128_make64(section->offset_within_address_space);
llend = int128_add(llend, section->size);
llend = int128_and(llend, int128_exts64(TARGET_PAGE_MASK));
llend = vhost_vdpa_section_end(section);
if (int128_ge(int128_make64(iova), llend)) {
return;
}
@@ -209,7 +237,8 @@ static void vhost_vdpa_listener_region_del(MemoryListener *listener,
Int128 llend, llsize;
int ret;
if (vhost_vdpa_listener_skipped_section(section)) {
if (vhost_vdpa_listener_skipped_section(section, v->iova_range.first,
v->iova_range.last)) {
return;
}
@@ -220,9 +249,7 @@ static void vhost_vdpa_listener_region_del(MemoryListener *listener,
}
iova = TARGET_PAGE_ALIGN(section->offset_within_address_space);
llend = int128_make64(section->offset_within_address_space);
llend = int128_add(llend, section->size);
llend = int128_and(llend, int128_exts64(TARGET_PAGE_MASK));
llend = vhost_vdpa_section_end(section);
trace_vhost_vdpa_listener_region_del(v, iova, int128_get64(llend));
@@ -279,6 +306,26 @@ static void vhost_vdpa_add_status(struct vhost_dev *dev, uint8_t status)
vhost_vdpa_call(dev, VHOST_VDPA_SET_STATUS, &s);
}
static void vhost_vdpa_get_iova_range(struct vhost_vdpa *v)
{
int ret = vhost_vdpa_call(v->dev, VHOST_VDPA_GET_IOVA_RANGE,
&v->iova_range);
if (ret != 0) {
v->iova_range.first = 0;
v->iova_range.last = UINT64_MAX;
}
trace_vhost_vdpa_get_iova_range(v->dev, v->iova_range.first,
v->iova_range.last);
}
static bool vhost_vdpa_one_time_request(struct vhost_dev *dev)
{
struct vhost_vdpa *v = dev->opaque;
return v->index != 0;
}
static int vhost_vdpa_init(struct vhost_dev *dev, void *opaque, Error **errp)
{
struct vhost_vdpa *v;
@@ -291,6 +338,12 @@ static int vhost_vdpa_init(struct vhost_dev *dev, void *opaque, Error **errp)
v->listener = vhost_vdpa_memory_listener;
v->msg_type = VHOST_IOTLB_MSG_V2;
vhost_vdpa_get_iova_range(v);
if (vhost_vdpa_one_time_request(dev)) {
return 0;
}
vhost_vdpa_add_status(dev, VIRTIO_CONFIG_S_ACKNOWLEDGE |
VIRTIO_CONFIG_S_DRIVER);
@@ -401,6 +454,10 @@ static int vhost_vdpa_memslots_limit(struct vhost_dev *dev)
static int vhost_vdpa_set_mem_table(struct vhost_dev *dev,
struct vhost_memory *mem)
{
if (vhost_vdpa_one_time_request(dev)) {
return 0;
}
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)) {
@@ -424,6 +481,11 @@ static int vhost_vdpa_set_features(struct vhost_dev *dev,
uint64_t features)
{
int ret;
if (vhost_vdpa_one_time_request(dev)) {
return 0;
}
trace_vhost_vdpa_set_features(dev, features);
ret = vhost_vdpa_call(dev, VHOST_SET_FEATURES, &features);
uint8_t status = 0;
@@ -448,9 +510,12 @@ static int vhost_vdpa_set_backend_cap(struct vhost_dev *dev)
}
features &= f;
r = vhost_vdpa_call(dev, VHOST_SET_BACKEND_FEATURES, &features);
if (r) {
return -EFAULT;
if (vhost_vdpa_one_time_request(dev)) {
r = vhost_vdpa_call(dev, VHOST_SET_BACKEND_FEATURES, &features);
if (r) {
return -EFAULT;
}
}
dev->backend_cap = features;
@@ -481,8 +546,8 @@ 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;
trace_vhost_vdpa_get_vq_index(dev, idx, idx);
return idx;
}
static int vhost_vdpa_set_vring_ready(struct vhost_dev *dev)
@@ -559,11 +624,21 @@ 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) {
vhost_vdpa_host_notifiers_init(dev);
vhost_vdpa_set_vring_ready(dev);
} else {
vhost_vdpa_host_notifiers_uninit(dev, dev->nvqs);
}
if (dev->vq_index + dev->nvqs != dev->last_index) {
return 0;
}
if (started) {
uint8_t status = 0;
memory_listener_register(&v->listener, &address_space_memory);
vhost_vdpa_host_notifiers_init(dev);
vhost_vdpa_set_vring_ready(dev);
vhost_vdpa_add_status(dev, VIRTIO_CONFIG_S_DRIVER_OK);
vhost_vdpa_call(dev, VHOST_VDPA_GET_STATUS, &status);
@@ -572,7 +647,6 @@ static int vhost_vdpa_dev_start(struct vhost_dev *dev, bool started)
vhost_vdpa_reset_device(dev);
vhost_vdpa_add_status(dev, VIRTIO_CONFIG_S_ACKNOWLEDGE |
VIRTIO_CONFIG_S_DRIVER);
vhost_vdpa_host_notifiers_uninit(dev, dev->nvqs);
memory_listener_unregister(&v->listener);
return 0;
@@ -582,6 +656,10 @@ 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)
{
if (vhost_vdpa_one_time_request(dev)) {
return 0;
}
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);
@@ -647,6 +725,10 @@ static int vhost_vdpa_get_features(struct vhost_dev *dev,
static int vhost_vdpa_set_owner(struct vhost_dev *dev)
{
if (vhost_vdpa_one_time_request(dev)) {
return 0;
}
trace_vhost_vdpa_set_owner(dev);
return vhost_vdpa_call(dev, VHOST_SET_OWNER, NULL);
}
+1 -3
View File
@@ -98,9 +98,7 @@ 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",
.non_transitional_name = "virtio-iommu-pci-non-transitional",
.generic_name = TYPE_VIRTIO_IOMMU_PCI,
.instance_size = sizeof(VirtIOIOMMUPCI),
.instance_init = virtio_iommu_pci_instance_init,
.class_init = virtio_iommu_pci_class_init,
+33
View File
@@ -0,0 +1,33 @@
/*
* Vhost-user RNG virtio device
*
* Copyright (c) 2021 Mathieu Poirier <mathieu.poirier@linaro.org>
*
* SPDX-License-Identifier: GPL-2.0-or-later
*/
#ifndef _QEMU_VHOST_USER_RNG_H
#define _QEMU_VHOST_USER_RNG_H
#include "hw/virtio/virtio.h"
#include "hw/virtio/vhost.h"
#include "hw/virtio/vhost-user.h"
#include "chardev/char-fe.h"
#define TYPE_VHOST_USER_RNG "vhost-user-rng"
OBJECT_DECLARE_SIMPLE_TYPE(VHostUserRNG, VHOST_USER_RNG)
struct VHostUserRNG {
/*< private >*/
VirtIODevice parent;
CharBackend chardev;
struct vhost_virtqueue *vhost_vq;
struct vhost_dev vhost_dev;
VhostUserState vhost_user;
VirtQueue *req_vq;
bool connected;
/*< public >*/
};
#endif /* _QEMU_VHOST_USER_RNG_H */
+3
View File
@@ -13,6 +13,7 @@
#define HW_VIRTIO_VHOST_VDPA_H
#include "hw/virtio/virtio.h"
#include "standard-headers/linux/vhost_types.h"
typedef struct VhostVDPAHostNotifier {
MemoryRegion mr;
@@ -21,9 +22,11 @@ typedef struct VhostVDPAHostNotifier {
typedef struct vhost_vdpa {
int device_fd;
int index;
uint32_t msg_type;
bool iotlb_batch_begin_sent;
MemoryListener listener;
struct vhost_vdpa_iova_range iova_range;
struct vhost_dev *dev;
VhostVDPAHostNotifier notifier[VIRTIO_QUEUE_MAX];
} VhostVDPA;
+2
View File
@@ -74,6 +74,8 @@ struct vhost_dev {
unsigned int nvqs;
/* the first virtqueue which would be used by this vhost dev */
int vq_index;
/* the last vq index for the virtio device (not vhost) */
int last_index;
/* if non-zero, minimum required value for max_queues */
int num_queues;
uint64_t features;
+1 -1
View File
@@ -26,7 +26,7 @@
#include "qom/object.h"
#define TYPE_VIRTIO_IOMMU "virtio-iommu-device"
#define TYPE_VIRTIO_IOMMU_PCI "virtio-iommu-device-base"
#define TYPE_VIRTIO_IOMMU_PCI "virtio-iommu-pci"
OBJECT_DECLARE_SIMPLE_TYPE(VirtIOIOMMU, VIRTIO_IOMMU)
#define TYPE_VIRTIO_IOMMU_MEMORY_REGION "virtio-iommu-memory-region"
+3 -2
View File
@@ -194,8 +194,9 @@ struct VirtIONet {
NICConf nic_conf;
DeviceState *qdev;
int multiqueue;
uint16_t max_queues;
uint16_t curr_queues;
uint16_t max_queue_pairs;
uint16_t curr_queue_pairs;
uint16_t max_ncs;
size_t config_size;
char *netclient_name;
char *netclient_type;
+5
View File
@@ -105,6 +105,7 @@ struct NetClientState {
int vnet_hdr_len;
bool is_netdev;
bool do_not_pad; /* do not pad to the minimum ethernet frame length */
bool is_datapath;
QTAILQ_HEAD(, NetFilterState) filters;
};
@@ -136,6 +137,10 @@ NetClientState *qemu_new_net_client(NetClientInfo *info,
NetClientState *peer,
const char *model,
const char *name);
NetClientState *qemu_new_net_control_client(NetClientInfo *info,
NetClientState *peer,
const char *model,
const char *name);
NICState *qemu_new_nic(NetClientInfo *info,
NICConf *conf,
const char *model,

Some files were not shown because too many files have changed in this diff Show More