mirror of
https://github.com/izzy2lost/xemu.git
synced 2026-07-06 00:20:22 -07:00
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:
@@ -88,3 +88,4 @@ Emulated Devices
|
||||
devices/usb.rst
|
||||
devices/vhost-user.rst
|
||||
devices/virtio-pmem.rst
|
||||
devices/vhost-user-rng.rst
|
||||
|
||||
@@ -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 \
|
||||
...
|
||||
@@ -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
@@ -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
File diff suppressed because it is too large
Load Diff
+5
-5
@@ -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,
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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'))
|
||||
|
||||
@@ -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"
|
||||
|
||||
@@ -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);
|
||||
@@ -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)
|
||||
@@ -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
@@ -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);
|
||||
}
|
||||
|
||||
@@ -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,
|
||||
|
||||
@@ -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 */
|
||||
@@ -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;
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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"
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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
Reference in New Issue
Block a user