Merge tag 'for_upstream' of https://git.kernel.org/pub/scm/virt/kvm/mst/qemu into staging

pc,virtio: features, tests, fixes, cleanups

virtio introspection
new serial number opton for cxl
vhost user blk dynamic config size
virtio-gpio vhost user backend

Tests fixes cleanups all over the place

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

# -----BEGIN PGP SIGNATURE-----
#
# iQFDBAABCAAtFiEEXQn9CHHI+FuUyooNKB8NuNKNVGkFAmNEVeoPHG1zdEByZWRo
# YXQuY29tAAoJECgfDbjSjVRph8YH+gMWpb5IglE0Q+H2JiQPBwB/Ghy1ohRKnOvZ
# lChB7+oy18o2xXRFTOXwG9Ijqsbdn0QMbU/r3NWxBuMzxDow012xiMDniJlJmcXw
# /4POOCSTKrIfzVBhsEErVSA9NwSE5cQKr1oiRBGIa9UdZfZ//v7s6SoP4vtyj8RZ
# UJVYVnMDtq/0PaN92IMs06lhqo/LkegE7gTGHMBf8Nvw4SgQoZgfPyp1eR+dKOhz
# lXNqqvTds9yt8yS65UWbuSrZ9d7GpCQf8nuyLaLaENHd6FQUVfmTTT37l2EKziwp
# PK0EwWMHeGkj7LHrylztradhE9xBlIW23ROP8wPdGZHmgLNHbC0=
# =20Zb
# -----END PGP SIGNATURE-----
# gpg: Signature made Mon 10 Oct 2022 13:27:06 EDT
# 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: (55 commits)
  x86: pci: acpi: consolidate PCI slots creation
  tests: acpi: update expected blobs
  x86: pci: acpi: reorder Device's _DSM method
  tests: acpi: whitelist pc/q35 DSDT before moving _ADR field
  tests: acpi: update expected blobs
  x86: pci: acpi: reorder Device's _ADR and _SUN fields
  tests: acpi: whitelist pc/q35 DSDT before moving _ADR field
  tests: acpi: update expected blobs
  x86: acpi: cleanup PCI device _DSM duplication
  tests: acpi: whitelist pc/q35 DSDT before switching _DSM to use ASUN
  tests: acpi: update expected blobs
  x86: acpi: _DSM: use Package to pass parameters
  acpi: x86: refactor PDSM method to reduce nesting
  tests: acpi: whitelist pc/q35 DSDT due to HPET AML move
  tests: acpi: update expected blobs after HPET move
  acpi: x86: deduplicate HPET AML building
  tests: acpi: whitelist pc/q35 DSDT due to HPET AML move
  hw/smbios: support for type 8 (port connector)
  pci: Sanity check mask argument to pci_set_*_by_mask()
  pci: Remove unused pci_get_*_by_mask() functions
  ...

Signed-off-by: Stefan Hajnoczi <stefanha@redhat.com>
This commit is contained in:
Stefan Hajnoczi
2022-10-12 16:00:15 -04:00
87 changed files with 3796 additions and 289 deletions
+12
View File
@@ -2030,8 +2030,10 @@ virtio-blk
M: Stefan Hajnoczi <stefanha@redhat.com>
L: qemu-block@nongnu.org
S: Supported
F: hw/block/virtio-blk-common.c
F: hw/block/virtio-blk.c
F: hw/block/dataplane/*
F: include/hw/virtio/virtio-blk-common.h
F: tests/qtest/virtio-blk-test.c
T: git https://github.com/stefanha/qemu.git block
@@ -2098,6 +2100,14 @@ F: hw/virtio/vhost-user-rng-pci.c
F: include/hw/virtio/vhost-user-rng.h
F: tools/vhost-user-rng/*
vhost-user-gpio
M: Alex Bennée <alex.bennee@linaro.org>
R: Viresh Kumar <viresh.kumar@linaro.org>
S: Maintained
F: hw/virtio/vhost-user-gpio*
F: include/hw/virtio/vhost-user-gpio.h
F: tests/qtest/libqos/virtio-gpio.*
virtio-crypto
M: Gonglei <arei.gonglei@huawei.com>
S: Supported
@@ -2271,11 +2281,13 @@ S: Maintained
F: contrib/vhost-user-blk/
F: contrib/vhost-user-scsi/
F: hw/block/vhost-user-blk.c
F: hw/block/virtio-blk-common.c
F: hw/scsi/vhost-user-scsi.c
F: hw/virtio/vhost-user-blk-pci.c
F: hw/virtio/vhost-user-scsi-pci.c
F: include/hw/virtio/vhost-user-blk.h
F: include/hw/virtio/vhost-user-scsi.h
F: include/hw/virtio/virtio-blk-common.h
vhost-user-gpu
M: Marc-André Lureau <marcandre.lureau@redhat.com>
+70
View File
@@ -923,3 +923,73 @@ SRST
``stats``
Show runtime-collected statistics
ERST
{
.name = "virtio",
.args_type = "",
.params = "",
.help = "List all available virtio devices",
.cmd = hmp_virtio_query,
.flags = "p",
},
SRST
``info virtio``
List all available virtio devices
ERST
{
.name = "virtio-status",
.args_type = "path:s",
.params = "path",
.help = "Display status of a given virtio device",
.cmd = hmp_virtio_status,
.flags = "p",
},
SRST
``info virtio-status`` *path*
Display status of a given virtio device
ERST
{
.name = "virtio-queue-status",
.args_type = "path:s,queue:i",
.params = "path queue",
.help = "Display status of a given virtio queue",
.cmd = hmp_virtio_queue_status,
.flags = "p",
},
SRST
``info virtio-queue-status`` *path* *queue*
Display status of a given virtio queue
ERST
{
.name = "virtio-vhost-queue-status",
.args_type = "path:s,queue:i",
.params = "path queue",
.help = "Display status of a given vhost queue",
.cmd = hmp_vhost_queue_status,
.flags = "p",
},
SRST
``info virtio-vhost-queue-status`` *path* *queue*
Display status of a given vhost queue
ERST
{
.name = "virtio-queue-element",
.args_type = "path:s,queue:i,index:i?",
.params = "path queue [index]",
.help = "Display element of a given virtio queue",
.cmd = hmp_virtio_queue_element,
.flags = "p",
},
SRST
``info virtio-queue-element`` *path* *queue* [*index*]
Display element of a given virtio queue
ERST
+2 -3
View File
@@ -592,8 +592,7 @@ build_gtdt(GArray *table_data, BIOSLinker *linker, VirtMachineState *vms)
acpi_table_begin(&table, table_data);
/* CntControlBase Physical Address */
/* FIXME: invalid value, should be 0xFFFFFFFFFFFFFFFF if not impl. ? */
build_append_int_noprefix(table_data, 0, 8);
build_append_int_noprefix(table_data, 0xFFFFFFFFFFFFFFFF, 8);
build_append_int_noprefix(table_data, 0, 4); /* Reserved */
/*
* FIXME: clarify comment:
@@ -618,7 +617,7 @@ build_gtdt(GArray *table_data, BIOSLinker *linker, VirtMachineState *vms)
/* Non-Secure EL2 timer Flags */
build_append_int_noprefix(table_data, irqflags, 4);
/* CntReadBase Physical address */
build_append_int_noprefix(table_data, 0, 8);
build_append_int_noprefix(table_data, 0xFFFFFFFFFFFFFFFF, 8);
/* Platform Timer Count */
build_append_int_noprefix(table_data, 0, 4);
/* Platform Timer Offset */
+2 -2
View File
@@ -16,7 +16,7 @@ softmmu_ss.add(when: 'CONFIG_SWIM', if_true: files('swim.c'))
softmmu_ss.add(when: 'CONFIG_XEN', if_true: files('xen-block.c'))
softmmu_ss.add(when: 'CONFIG_TC58128', if_true: files('tc58128.c'))
specific_ss.add(when: 'CONFIG_VIRTIO_BLK', if_true: files('virtio-blk.c'))
specific_ss.add(when: 'CONFIG_VHOST_USER_BLK', if_true: files('vhost-user-blk.c'))
specific_ss.add(when: 'CONFIG_VIRTIO_BLK', if_true: files('virtio-blk.c', 'virtio-blk-common.c'))
specific_ss.add(when: 'CONFIG_VHOST_USER_BLK', if_true: files('vhost-user-blk.c', 'virtio-blk-common.c'))
subdir('dataplane')
+24 -15
View File
@@ -23,6 +23,7 @@
#include "hw/qdev-core.h"
#include "hw/qdev-properties.h"
#include "hw/qdev-properties-system.h"
#include "hw/virtio/virtio-blk-common.h"
#include "hw/virtio/vhost.h"
#include "hw/virtio/vhost-user-blk.h"
#include "hw/virtio/virtio.h"
@@ -63,7 +64,7 @@ static void vhost_user_blk_update_config(VirtIODevice *vdev, uint8_t *config)
/* Our num_queues overrides the device backend */
virtio_stw_p(vdev, &s->blkcfg.num_queues, s->num_queues);
memcpy(config, &s->blkcfg, sizeof(struct virtio_blk_config));
memcpy(config, &s->blkcfg, vdev->config_len);
}
static void vhost_user_blk_set_config(VirtIODevice *vdev, const uint8_t *config)
@@ -92,12 +93,12 @@ static int vhost_user_blk_handle_config_change(struct vhost_dev *dev)
{
int ret;
struct virtio_blk_config blkcfg;
VirtIODevice *vdev = dev->vdev;
VHostUserBlk *s = VHOST_USER_BLK(dev->vdev);
Error *local_err = NULL;
ret = vhost_dev_get_config(dev, (uint8_t *)&blkcfg,
sizeof(struct virtio_blk_config),
&local_err);
vdev->config_len, &local_err);
if (ret < 0) {
error_report_err(local_err);
return ret;
@@ -106,7 +107,7 @@ static int vhost_user_blk_handle_config_change(struct vhost_dev *dev)
/* valid for resize only */
if (blkcfg.capacity != s->blkcfg.capacity) {
s->blkcfg.capacity = blkcfg.capacity;
memcpy(dev->vdev->config, &s->blkcfg, sizeof(struct virtio_blk_config));
memcpy(dev->vdev->config, &s->blkcfg, vdev->config_len);
virtio_notify_config(dev->vdev);
}
@@ -229,7 +230,7 @@ static void vhost_user_blk_set_status(VirtIODevice *vdev, uint8_t status)
return;
}
if (s->dev.started == should_start) {
if (vhost_dev_is_started(&s->dev) == should_start) {
return;
}
@@ -259,12 +260,7 @@ static uint64_t vhost_user_blk_get_features(VirtIODevice *vdev,
virtio_add_feature(&features, VIRTIO_BLK_F_BLK_SIZE);
virtio_add_feature(&features, VIRTIO_BLK_F_FLUSH);
virtio_add_feature(&features, VIRTIO_BLK_F_RO);
virtio_add_feature(&features, VIRTIO_BLK_F_DISCARD);
virtio_add_feature(&features, VIRTIO_BLK_F_WRITE_ZEROES);
if (s->config_wce) {
virtio_add_feature(&features, VIRTIO_BLK_F_CONFIG_WCE);
}
if (s->num_queues > 1) {
virtio_add_feature(&features, VIRTIO_BLK_F_MQ);
}
@@ -286,7 +282,7 @@ static void vhost_user_blk_handle_output(VirtIODevice *vdev, VirtQueue *vq)
return;
}
if (s->dev.started) {
if (vhost_dev_is_started(&s->dev)) {
return;
}
@@ -415,6 +411,12 @@ static void vhost_user_blk_event(void *opaque, QEMUChrEvent event)
* the vhost migration code. If disconnect was caught there is an
* option for the general vhost code to get the dev state without
* knowing its type (in this case vhost-user).
*
* FIXME: this is sketchy to be reaching into vhost_dev
* now because we are forcing something that implies we
* have executed vhost_dev_stop() but that won't happen
* until vhost_user_blk_stop() gets called from the bh.
* Really this state check should be tracked locally.
*/
s->dev.started = false;
}
@@ -447,7 +449,7 @@ static int vhost_user_blk_realize_connect(VHostUserBlk *s, Error **errp)
assert(s->connected);
ret = vhost_dev_get_config(&s->dev, (uint8_t *)&s->blkcfg,
sizeof(struct virtio_blk_config), errp);
s->parent_obj.config_len, errp);
if (ret < 0) {
qemu_chr_fe_disconnect(&s->chardev);
vhost_dev_cleanup(&s->dev);
@@ -462,6 +464,7 @@ static void vhost_user_blk_device_realize(DeviceState *dev, Error **errp)
ERRP_GUARD();
VirtIODevice *vdev = VIRTIO_DEVICE(dev);
VHostUserBlk *s = VHOST_USER_BLK(vdev);
size_t config_size;
int retries;
int i, ret;
@@ -492,8 +495,9 @@ static void vhost_user_blk_device_realize(DeviceState *dev, Error **errp)
return;
}
virtio_init(vdev, VIRTIO_ID_BLOCK,
sizeof(struct virtio_blk_config));
config_size = virtio_get_config_size(&virtio_blk_cfg_size_params,
vdev->host_features);
virtio_init(vdev, VIRTIO_ID_BLOCK, config_size);
s->virtqs = g_new(VirtQueue *, s->num_queues);
for (i = 0; i < s->num_queues; i++) {
@@ -591,7 +595,12 @@ static Property vhost_user_blk_properties[] = {
DEFINE_PROP_UINT16("num-queues", VHostUserBlk, num_queues,
VHOST_USER_BLK_AUTO_NUM_QUEUES),
DEFINE_PROP_UINT32("queue-size", VHostUserBlk, queue_size, 128),
DEFINE_PROP_BIT("config-wce", VHostUserBlk, config_wce, 0, true),
DEFINE_PROP_BIT64("config-wce", VHostUserBlk, parent_obj.host_features,
VIRTIO_BLK_F_CONFIG_WCE, true),
DEFINE_PROP_BIT64("discard", VHostUserBlk, parent_obj.host_features,
VIRTIO_BLK_F_DISCARD, true),
DEFINE_PROP_BIT64("write-zeroes", VHostUserBlk, parent_obj.host_features,
VIRTIO_BLK_F_WRITE_ZEROES, true),
DEFINE_PROP_END_OF_LIST(),
};
+39
View File
@@ -0,0 +1,39 @@
/*
* Virtio Block Device common helpers
*
* Copyright IBM, Corp. 2007
*
* Authors:
* Anthony Liguori <aliguori@us.ibm.com>
*
* This work is licensed under the terms of the GNU GPL, version 2. See
* the COPYING file in the top-level directory.
*/
#include "qemu/osdep.h"
#include "standard-headers/linux/virtio_blk.h"
#include "hw/virtio/virtio.h"
#include "hw/virtio/virtio-blk-common.h"
/* Config size before the discard support (hide associated config fields) */
#define VIRTIO_BLK_CFG_SIZE offsetof(struct virtio_blk_config, \
max_discard_sectors)
/*
* Starting from the discard feature, we can use this array to properly
* set the config size depending on the features enabled.
*/
static const VirtIOFeature feature_sizes[] = {
{.flags = 1ULL << VIRTIO_BLK_F_DISCARD,
.end = endof(struct virtio_blk_config, discard_sector_alignment)},
{.flags = 1ULL << VIRTIO_BLK_F_WRITE_ZEROES,
.end = endof(struct virtio_blk_config, write_zeroes_may_unmap)},
{}
};
const VirtIOConfigSizeParams virtio_blk_cfg_size_params = {
.min_size = VIRTIO_BLK_CFG_SIZE,
.max_size = sizeof(struct virtio_blk_config),
.feature_sizes = feature_sizes
};
+3 -25
View File
@@ -32,31 +32,9 @@
#include "hw/virtio/virtio-bus.h"
#include "migration/qemu-file-types.h"
#include "hw/virtio/virtio-access.h"
#include "hw/virtio/virtio-blk-common.h"
#include "qemu/coroutine.h"
/* Config size before the discard support (hide associated config fields) */
#define VIRTIO_BLK_CFG_SIZE offsetof(struct virtio_blk_config, \
max_discard_sectors)
/*
* Starting from the discard feature, we can use this array to properly
* set the config size depending on the features enabled.
*/
static const VirtIOFeature feature_sizes[] = {
{.flags = 1ULL << VIRTIO_BLK_F_DISCARD,
.end = endof(struct virtio_blk_config, discard_sector_alignment)},
{.flags = 1ULL << VIRTIO_BLK_F_WRITE_ZEROES,
.end = endof(struct virtio_blk_config, write_zeroes_may_unmap)},
{}
};
static void virtio_blk_set_config_size(VirtIOBlock *s, uint64_t host_features)
{
s->config_size = MAX(VIRTIO_BLK_CFG_SIZE,
virtio_feature_get_config_size(feature_sizes, host_features));
assert(s->config_size <= sizeof(struct virtio_blk_config));
}
static void virtio_blk_init_request(VirtIOBlock *s, VirtQueue *vq,
VirtIOBlockReq *req)
{
@@ -1204,8 +1182,8 @@ static void virtio_blk_device_realize(DeviceState *dev, Error **errp)
return;
}
virtio_blk_set_config_size(s, s->host_features);
s->config_size = virtio_get_config_size(&virtio_blk_cfg_size_params,
s->host_features);
virtio_init(vdev, VIRTIO_ID_BLOCK, s->config_size);
s->blk = conf->conf.blk;
+160 -140
View File
@@ -374,6 +374,25 @@ build_facs(GArray *table_data)
g_array_append_vals(table_data, reserved, 40); /* Reserved */
}
Aml *aml_pci_device_dsm(void)
{
Aml *method;
method = aml_method("_DSM", 4, AML_SERIALIZED);
{
Aml *params = aml_local(0);
Aml *pkg = aml_package(2);
aml_append(pkg, aml_name("BSEL"));
aml_append(pkg, aml_name("ASUN"));
aml_append(method, aml_store(pkg, params));
aml_append(method,
aml_return(aml_call5("PDSM", aml_arg(0), aml_arg(1),
aml_arg(2), aml_arg(3), params))
);
}
return method;
}
static void build_append_pcihp_notify_entry(Aml *method, int slot)
{
Aml *if_ctx;
@@ -408,13 +427,41 @@ static void build_append_pci_bus_devices(Aml *parent_scope, PCIBus *bus,
int func = PCI_FUNC(devfn);
/* ACPI spec: 1.0b: Table 6-2 _ADR Object Bus Types, PCI type */
int adr = slot << 16 | func;
bool hotplug_enabled_dev;
bool bridge_in_acpi;
bool cold_plugged_bridge;
bool hotpluggbale_slot = false;
bool bridge_in_acpi = false;
bool cold_plugged_bridge = false;
bool is_vga = false;
if (pdev) {
pc = PCI_DEVICE_GET_CLASS(pdev);
dc = DEVICE_GET_CLASS(pdev);
if (pc->class_id == PCI_CLASS_BRIDGE_ISA) {
continue;
}
is_vga = pc->class_id == PCI_CLASS_DISPLAY_VGA;
if (!pdev) {
/*
* add hotplug slots for non present devices.
* Cold plugged bridges aren't themselves hot-pluggable.
* Hotplugged bridges *are* hot-pluggable.
*/
cold_plugged_bridge = pc->is_bridge && !DEVICE(pdev)->hotplugged;
bridge_in_acpi = cold_plugged_bridge && pcihp_bridge_en;
hotpluggbale_slot = bsel && dc->hotpluggable &&
!cold_plugged_bridge;
/*
* allow describing coldplugged bridges in ACPI even if they are not
* on function 0, as they are not unpluggable, for all other devices
* generate description only for function 0 per slot
*/
if (func && !bridge_in_acpi) {
continue;
}
} else {
/*
* hotplug is supported only for non-multifunction device
* so generate device description only for function 0
*/
@@ -422,51 +469,11 @@ static void build_append_pci_bus_devices(Aml *parent_scope, PCIBus *bus,
if (pci_bus_is_express(bus) && slot > 0) {
break;
}
dev = aml_device("S%.02X", devfn);
aml_append(dev, aml_name_decl("_SUN", aml_int(slot)));
aml_append(dev, aml_name_decl("_ADR", aml_int(adr)));
method = aml_method("_EJ0", 1, AML_NOTSERIALIZED);
aml_append(method,
aml_call2("PCEJ", aml_name("BSEL"), aml_name("_SUN"))
);
aml_append(dev, method);
method = aml_method("_DSM", 4, AML_SERIALIZED);
aml_append(method,
aml_return(aml_call6("PDSM", aml_arg(0), aml_arg(1),
aml_arg(2), aml_arg(3),
aml_name("BSEL"), aml_name("_SUN")))
);
aml_append(dev, method);
aml_append(parent_scope, dev);
build_append_pcihp_notify_entry(notify_method, slot);
/* mark it as empty hotpluggable slot */
hotpluggbale_slot = true;
} else {
continue;
}
continue;
}
pc = PCI_DEVICE_GET_CLASS(pdev);
dc = DEVICE_GET_CLASS(pdev);
/*
* Cold plugged bridges aren't themselves hot-pluggable.
* Hotplugged bridges *are* hot-pluggable.
*/
cold_plugged_bridge = pc->is_bridge && !DEVICE(pdev)->hotplugged;
bridge_in_acpi = cold_plugged_bridge && pcihp_bridge_en;
hotplug_enabled_dev = bsel && dc->hotpluggable && !cold_plugged_bridge;
if (pc->class_id == PCI_CLASS_BRIDGE_ISA) {
continue;
}
/*
* allow describing coldplugged bridges in ACPI even if they are not
* on function 0, as they are not unpluggable, for all other devices
* generate description only for function 0 per slot
*/
if (func && !bridge_in_acpi) {
continue;
}
/* start to compose PCI device descriptor */
@@ -479,15 +486,10 @@ static void build_append_pci_bus_devices(Aml *parent_scope, PCIBus *bus,
* enumeration order in linux kernel, so use another variable for it
*/
aml_append(dev, aml_name_decl("ASUN", aml_int(slot)));
method = aml_method("_DSM", 4, AML_SERIALIZED);
aml_append(method, aml_return(
aml_call6("PDSM", aml_arg(0), aml_arg(1), aml_arg(2),
aml_arg(3), aml_name("BSEL"), aml_name("ASUN"))
));
aml_append(dev, method);
aml_append(dev, aml_pci_device_dsm());
}
if (pc->class_id == PCI_CLASS_DISPLAY_VGA) {
if (is_vga) {
/* add VGA specific AML methods */
int s3d;
@@ -508,19 +510,10 @@ static void build_append_pci_bus_devices(Aml *parent_scope, PCIBus *bus,
method = aml_method("_S3D", 0, AML_NOTSERIALIZED);
aml_append(method, aml_return(aml_int(s3d)));
aml_append(dev, method);
} else if (hotplug_enabled_dev) {
aml_append(dev, aml_name_decl("_SUN", aml_int(slot)));
/* add _EJ0 to make slot hotpluggable */
method = aml_method("_EJ0", 1, AML_NOTSERIALIZED);
aml_append(method,
aml_call2("PCEJ", aml_name("BSEL"), aml_name("_SUN"))
);
aml_append(dev, method);
}
if (bsel) {
build_append_pcihp_notify_entry(notify_method, slot);
}
} else if (bridge_in_acpi) {
bridge_in_acpi = cold_plugged_bridge && pcihp_bridge_en;
if (bridge_in_acpi) {
/*
* device is coldplugged bridge,
* add child device descriptions into its scope
@@ -529,6 +522,19 @@ static void build_append_pci_bus_devices(Aml *parent_scope, PCIBus *bus,
build_append_pci_bus_devices(dev, sec_bus, pcihp_bridge_en);
}
if (hotpluggbale_slot) {
aml_append(dev, aml_name_decl("_SUN", aml_int(slot)));
/* add _EJ0 to make slot hotpluggable */
method = aml_method("_EJ0", 1, AML_NOTSERIALIZED);
aml_append(method,
aml_call2("PCEJ", aml_name("BSEL"), aml_name("_SUN"))
);
aml_append(dev, method);
build_append_pcihp_notify_entry(notify_method, slot);
}
/* device descriptor has been composed, add it into parent context */
aml_append(parent_scope, dev);
}
@@ -572,84 +578,100 @@ static void build_append_pci_bus_devices(Aml *parent_scope, PCIBus *bus,
qobject_unref(bsel);
}
Aml *aml_pci_device_dsm(void)
static Aml *aml_pci_pdsm(void)
{
Aml *method, *UUID, *ifctx, *ifctx1, *ifctx2, *ifctx3, *elsectx;
Aml *acpi_index = aml_local(0);
Aml *method, *UUID, *ifctx, *ifctx1;
Aml *ret = aml_local(0);
Aml *caps = aml_local(1);
Aml *acpi_index = aml_local(2);
Aml *zero = aml_int(0);
Aml *bnum = aml_arg(4);
Aml *one = aml_int(1);
Aml *func = aml_arg(2);
Aml *rev = aml_arg(1);
Aml *sunum = aml_arg(5);
Aml *params = aml_arg(4);
Aml *bnum = aml_derefof(aml_index(params, aml_int(0)));
Aml *sunum = aml_derefof(aml_index(params, aml_int(1)));
method = aml_method("PDSM", 6, AML_SERIALIZED);
method = aml_method("PDSM", 5, AML_SERIALIZED);
/* get supported functions */
ifctx = aml_if(aml_equal(func, zero));
{
uint8_t byte_list[1] = { 0 }; /* nothing supported yet */
aml_append(ifctx, aml_store(aml_buffer(1, byte_list), ret));
aml_append(ifctx, aml_store(zero, caps));
/*
* PCI Firmware Specification 3.1
* 4.6. _DSM Definitions for PCI
*/
UUID = aml_touuid("E5C937D0-3553-4D7A-9117-EA4D19C3434D");
ifctx1 = aml_if(aml_lnot(aml_equal(aml_arg(0), UUID)));
{
/* call is for unsupported UUID, bail out */
aml_append(ifctx1, aml_return(ret));
}
aml_append(ifctx, ifctx1);
ifctx1 = aml_if(aml_lless(rev, aml_int(2)));
{
/* call is for unsupported REV, bail out */
aml_append(ifctx1, aml_return(ret));
}
aml_append(ifctx, ifctx1);
aml_append(ifctx,
aml_store(aml_call2("AIDX", bnum, sunum), acpi_index));
/*
* advertise function 7 if device has acpi-index
* acpi_index values:
* 0: not present (default value)
* FFFFFFFF: not supported (old QEMU without PIDX reg)
* other: device's acpi-index
*/
ifctx1 = aml_if(aml_lnot(
aml_or(aml_equal(acpi_index, zero),
aml_equal(acpi_index, aml_int(0xFFFFFFFF)), NULL)
));
{
/* have supported functions */
aml_append(ifctx1, aml_or(caps, one, caps));
/* support for function 7 */
aml_append(ifctx1,
aml_or(caps, aml_shiftleft(one, aml_int(7)), caps));
}
aml_append(ifctx, ifctx1);
aml_append(ifctx, aml_store(caps, aml_index(ret, zero)));
aml_append(ifctx, aml_return(ret));
}
aml_append(method, ifctx);
/* handle specific functions requests */
/*
* PCI Firmware Specification 3.1
* 4.6. _DSM Definitions for PCI
* 4.6.7. _DSM for Naming a PCI or PCI Express Device Under
* Operating Systems
*/
UUID = aml_touuid("E5C937D0-3553-4D7A-9117-EA4D19C3434D");
ifctx = aml_if(aml_equal(aml_arg(0), UUID));
ifctx = aml_if(aml_equal(func, aml_int(7)));
{
aml_append(ifctx, aml_store(aml_call2("AIDX", bnum, sunum), acpi_index));
ifctx1 = aml_if(aml_equal(func, zero));
{
uint8_t byte_list[1];
Aml *pkg = aml_package(2);
ifctx2 = aml_if(aml_equal(rev, aml_int(2)));
{
/*
* advertise function 7 if device has acpi-index
* acpi_index values:
* 0: not present (default value)
* FFFFFFFF: not supported (old QEMU without PIDX reg)
* other: device's acpi-index
*/
ifctx3 = aml_if(aml_lnot(
aml_or(aml_equal(acpi_index, zero),
aml_equal(acpi_index, aml_int(0xFFFFFFFF)), NULL)
));
{
byte_list[0] =
1 /* have supported functions */ |
1 << 7 /* support for function 7 */
;
aml_append(ifctx3, aml_return(aml_buffer(1, byte_list)));
}
aml_append(ifctx2, ifctx3);
}
aml_append(ifctx1, ifctx2);
aml_append(pkg, zero);
/*
* optional, if not impl. should return null string
*/
aml_append(pkg, aml_string("%s", ""));
aml_append(ifctx, aml_store(pkg, ret));
byte_list[0] = 0; /* nothing supported */
aml_append(ifctx1, aml_return(aml_buffer(1, byte_list)));
}
aml_append(ifctx, ifctx1);
elsectx = aml_else();
/*
* PCI Firmware Specification 3.1
* 4.6.7. _DSM for Naming a PCI or PCI Express Device Under
* Operating Systems
*/
ifctx1 = aml_if(aml_equal(func, aml_int(7)));
{
Aml *pkg = aml_package(2);
Aml *ret = aml_local(1);
aml_append(pkg, zero);
/*
* optional, if not impl. should return null string
*/
aml_append(pkg, aml_string("%s", ""));
aml_append(ifctx1, aml_store(pkg, ret));
/*
* update acpi-index to actual value
*/
aml_append(ifctx1, aml_store(acpi_index, aml_index(ret, zero)));
aml_append(ifctx1, aml_return(ret));
}
aml_append(elsectx, ifctx1);
aml_append(ifctx, elsectx);
aml_append(ifctx, aml_store(aml_call2("AIDX", bnum, sunum), acpi_index));
/*
* update acpi-index to actual value
*/
aml_append(ifctx, aml_store(acpi_index, aml_index(ret, zero)));
aml_append(ifctx, aml_return(ret));
}
aml_append(method, ifctx);
return method;
}
@@ -1339,7 +1361,7 @@ static void build_x86_acpi_pci_hotplug(Aml *table, uint64_t pcihp_addr)
aml_append(method, aml_return(aml_local(0)));
aml_append(scope, method);
aml_append(scope, aml_pci_device_dsm());
aml_append(scope, aml_pci_pdsm());
aml_append(table, scope);
}
@@ -1467,9 +1489,6 @@ build_dsdt(GArray *table_data, BIOSLinker *linker,
aml_append(sb_scope, dev);
aml_append(dsdt, sb_scope);
if (misc->has_hpet) {
build_hpet_aml(dsdt);
}
build_piix4_isa_bridge(dsdt);
if (pm->pcihp_bridge_en || pm->pcihp_root_en) {
build_x86_acpi_pci_hotplug(dsdt, pm->pcihp_io_base);
@@ -1515,9 +1534,6 @@ build_dsdt(GArray *table_data, BIOSLinker *linker,
aml_append(dsdt, sb_scope);
if (misc->has_hpet) {
build_hpet_aml(dsdt);
}
build_q35_isa_bridge(dsdt);
if (pm->pcihp_bridge_en) {
build_x86_acpi_pci_hotplug(dsdt, pm->pcihp_io_base);
@@ -1528,6 +1544,10 @@ build_dsdt(GArray *table_data, BIOSLinker *linker,
}
}
if (misc->has_hpet) {
build_hpet_aml(dsdt);
}
if (vmbus_bridge) {
sb_scope = aml_scope("_SB");
aml_append(sb_scope, build_vmbus_device_aml(vmbus_bridge));
+5
View File
@@ -3818,6 +3818,11 @@ static bool vtd_decide_config(IntelIOMMUState *s, Error **errp)
error_setg(errp, "eim=on requires accel=kvm,kernel-irqchip=split");
return false;
}
if (!kvm_enable_x2apic()) {
error_setg(errp, "eim=on requires support on the KVM side"
"(X2APIC_API, first shipped in v4.7)");
return false;
}
}
/* Currently only address widths supported are 39 and 48 bits */
+13 -1
View File
@@ -14,6 +14,12 @@
#include "sysemu/hostmem.h"
#include "hw/cxl/cxl.h"
/*
* Null value of all Fs suggested by IEEE RA guidelines for use of
* EU, OUI and CID
*/
#define UI64_NULL ~(0ULL)
static void build_dvsecs(CXLType3Dev *ct3d)
{
CXLComponentState *cxl_cstate = &ct3d->cxl_cstate;
@@ -149,7 +155,12 @@ static void ct3_realize(PCIDevice *pci_dev, Error **errp)
pci_config_set_class(pci_conf, PCI_CLASS_MEMORY_CXL);
pcie_endpoint_cap_init(pci_dev, 0x80);
cxl_cstate->dvsec_offset = 0x100;
if (ct3d->sn != UI64_NULL) {
pcie_dev_ser_num_init(pci_dev, 0x100, ct3d->sn);
cxl_cstate->dvsec_offset = 0x100 + 0x0c;
} else {
cxl_cstate->dvsec_offset = 0x100;
}
ct3d->cxl_cstate.pdev = pci_dev;
build_dvsecs(ct3d);
@@ -275,6 +286,7 @@ static Property ct3_props[] = {
HostMemoryBackend *),
DEFINE_PROP_LINK("lsa", CXLType3Dev, lsa, TYPE_MEMORY_BACKEND,
HostMemoryBackend *),
DEFINE_PROP_UINT64("sn", CXLType3Dev, sn, UI64_NULL),
DEFINE_PROP_END_OF_LIST(),
};
+7 -2
View File
@@ -106,6 +106,12 @@ static const VirtIOFeature feature_sizes[] = {
{}
};
static const VirtIOConfigSizeParams cfg_size_params = {
.min_size = endof(struct virtio_net_config, mac),
.max_size = sizeof(struct virtio_net_config),
.feature_sizes = feature_sizes
};
static VirtIONetQueue *virtio_net_get_subqueue(NetClientState *nc)
{
VirtIONet *n = qemu_get_nic_opaque(nc);
@@ -3241,8 +3247,7 @@ static void virtio_net_set_config_size(VirtIONet *n, uint64_t host_features)
{
virtio_add_feature(&host_features, VIRTIO_NET_F_MAC);
n->config_size = virtio_feature_get_config_size(feature_sizes,
host_features);
n->config_size = virtio_get_config_size(&cfg_size_params, host_features);
}
void virtio_net_set_netclient_name(VirtIONet *n, const char *name,
+2 -2
View File
@@ -120,7 +120,7 @@ static void vhost_scsi_set_status(VirtIODevice *vdev, uint8_t val)
start = false;
}
if (vsc->dev.started == start) {
if (vhost_dev_is_started(&vsc->dev) == start) {
return;
}
@@ -147,7 +147,7 @@ static int vhost_scsi_pre_save(void *opaque)
/* At this point, backend must be stopped, otherwise
* it might keep writing to memory. */
assert(!vsc->dev.started);
assert(!vhost_dev_is_started(&vsc->dev));
return 0;
}
+1 -1
View File
@@ -49,7 +49,7 @@ static void vhost_user_scsi_set_status(VirtIODevice *vdev, uint8_t status)
VHostSCSICommon *vsc = VHOST_SCSI_COMMON(s);
bool start = (status & VIRTIO_CONFIG_S_DRIVER_OK) && vdev->vm_running;
if (vsc->dev.started == start) {
if (vhost_dev_is_started(&vsc->dev) == start) {
return;
}
+63
View File
@@ -111,6 +111,13 @@ static struct {
.processor_id = 0,
};
struct type8_instance {
const char *internal_reference, *external_reference;
uint8_t connector_type, port_type;
QTAILQ_ENTRY(type8_instance) next;
};
static QTAILQ_HEAD(, type8_instance) type8 = QTAILQ_HEAD_INITIALIZER(type8);
static struct {
size_t nvalues;
char **values;
@@ -337,6 +344,29 @@ static const QemuOptDesc qemu_smbios_type4_opts[] = {
{ /* end of list */ }
};
static const QemuOptDesc qemu_smbios_type8_opts[] = {
{
.name = "internal_reference",
.type = QEMU_OPT_STRING,
.help = "internal reference designator",
},
{
.name = "external_reference",
.type = QEMU_OPT_STRING,
.help = "external reference designator",
},
{
.name = "connector_type",
.type = QEMU_OPT_NUMBER,
.help = "connector type",
},
{
.name = "port_type",
.type = QEMU_OPT_NUMBER,
.help = "port type",
},
};
static const QemuOptDesc qemu_smbios_type11_opts[] = {
{
.name = "value",
@@ -718,6 +748,26 @@ static void smbios_build_type_4_table(MachineState *ms, unsigned instance)
smbios_type4_count++;
}
static void smbios_build_type_8_table(void)
{
unsigned instance = 0;
struct type8_instance *t8;
QTAILQ_FOREACH(t8, &type8, next) {
SMBIOS_BUILD_TABLE_PRE(8, T0_BASE + instance, true);
SMBIOS_TABLE_SET_STR(8, internal_reference_str, t8->internal_reference);
SMBIOS_TABLE_SET_STR(8, external_reference_str, t8->external_reference);
/* most vendors seem to set this to None */
t->internal_connector_type = 0x0;
t->external_connector_type = t8->connector_type;
t->port_type = t8->port_type;
SMBIOS_BUILD_TABLE_POST;
instance++;
}
}
static void smbios_build_type_11_table(void)
{
char count_str[128];
@@ -1030,6 +1080,7 @@ void smbios_get_tables(MachineState *ms,
smbios_build_type_4_table(ms, i);
}
smbios_build_type_8_table();
smbios_build_type_11_table();
#define MAX_DIMM_SZ (16 * GiB)
@@ -1348,6 +1399,18 @@ void smbios_entry_add(QemuOpts *opts, Error **errp)
UINT16_MAX);
}
return;
case 8:
if (!qemu_opts_validate(opts, qemu_smbios_type8_opts, errp)) {
return;
}
struct type8_instance *t;
t = g_new0(struct type8_instance, 1);
save_opt(&t->internal_reference, opts, "internal_reference");
save_opt(&t->external_reference, opts, "external_reference");
t->connector_type = qemu_opt_get_number(opts, "connector_type", 0);
t->port_type = qemu_opt_get_number(opts, "port_type", 0);
QTAILQ_INSERT_TAIL(&type8, t, next);
return;
case 11:
if (!qemu_opts_validate(opts, qemu_smbios_type11_opts, errp)) {
return;
+5
View File
@@ -80,3 +80,8 @@ config VHOST_USER_FS
bool
default y
depends on VIRTIO && VHOST_USER
config VHOST_USER_GPIO
bool
default y
depends on VIRTIO && VHOST_USER
+4
View File
@@ -29,6 +29,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_VHOST_USER_RNG', if_true: files('vhost-user-rng.c'))
virtio_ss.add(when: 'CONFIG_VHOST_USER_GPIO', if_true: files('vhost-user-gpio.c'))
virtio_ss.add(when: ['CONFIG_VIRTIO_PCI', 'CONFIG_VHOST_USER_GPIO'], if_true: files('vhost-user-gpio-pci.c'))
virtio_pci_ss = ss.source_set()
virtio_pci_ss.add(when: 'CONFIG_VHOST_VSOCK', if_true: files('vhost-vsock-pci.c'))
@@ -60,4 +62,6 @@ virtio_ss.add_all(when: 'CONFIG_VIRTIO_PCI', if_true: virtio_pci_ss)
specific_ss.add_all(when: 'CONFIG_VIRTIO', if_true: virtio_ss)
softmmu_ss.add_all(when: 'CONFIG_VIRTIO', if_true: softmmu_virtio_ss)
softmmu_ss.add(when: 'CONFIG_VIRTIO', if_false: files('vhost-stub.c'))
softmmu_ss.add(when: 'CONFIG_VIRTIO', if_false: files('virtio-stub.c'))
softmmu_ss.add(when: 'CONFIG_ALL', if_true: files('vhost-stub.c'))
softmmu_ss.add(when: 'CONFIG_ALL', if_true: files('virtio-stub.c'))
+9
View File
@@ -8,6 +8,10 @@ vhost_region_add_section_aligned(const char *name, uint64_t gpa, uint64_t size,
vhost_section(const char *name) "%s"
vhost_reject_section(const char *name, int d) "%s:%d"
vhost_iotlb_miss(void *dev, int step) "%p step %d"
vhost_dev_cleanup(void *dev) "%p"
vhost_dev_start(void *dev, const char *name) "%p:%s"
vhost_dev_stop(void *dev, const char *name) "%p:%s"
# vhost-user.c
vhost_user_postcopy_end_entry(void) ""
@@ -140,3 +144,8 @@ virtio_mem_state_response(uint16_t state) "state=%" PRIu16
virtio_pmem_flush_request(void) "flush request"
virtio_pmem_response(void) "flush response"
virtio_pmem_flush_done(int type) "fsync return=%d"
# virtio-gpio.c
virtio_gpio_start(void) "start"
virtio_gpio_stop(void) "stop"
virtio_gpio_set_status(uint8_t status) "0x%x"
+3 -6
View File
@@ -20,6 +20,7 @@
#include "hw/virtio/virtio-bus.h"
#include "hw/virtio/virtio-access.h"
#include "qemu/error-report.h"
#include "hw/virtio/vhost.h"
#include "hw/virtio/vhost-user-fs.h"
#include "monitor/monitor.h"
#include "sysemu/sysemu.h"
@@ -122,13 +123,9 @@ static void vuf_stop(VirtIODevice *vdev)
static void vuf_set_status(VirtIODevice *vdev, uint8_t status)
{
VHostUserFS *fs = VHOST_USER_FS(vdev);
bool should_start = status & VIRTIO_CONFIG_S_DRIVER_OK;
bool should_start = virtio_device_started(vdev, status);
if (!vdev->vm_running) {
should_start = false;
}
if (fs->vhost_dev.started == should_start) {
if (vhost_dev_is_started(&fs->vhost_dev) == should_start) {
return;
}
+69
View File
@@ -0,0 +1,69 @@
/*
* Vhost-user gpio virtio device PCI glue
*
* Copyright (c) 2022 Viresh Kumar <viresh.kumar@linaro.org>
*
* SPDX-License-Identifier: GPL-2.0-or-later
*/
#include "qemu/osdep.h"
#include "hw/qdev-properties.h"
#include "hw/virtio/vhost-user-gpio.h"
#include "hw/virtio/virtio-pci.h"
struct VHostUserGPIOPCI {
VirtIOPCIProxy parent_obj;
VHostUserGPIO vdev;
};
typedef struct VHostUserGPIOPCI VHostUserGPIOPCI;
#define TYPE_VHOST_USER_GPIO_PCI "vhost-user-gpio-pci-base"
DECLARE_INSTANCE_CHECKER(VHostUserGPIOPCI, VHOST_USER_GPIO_PCI,
TYPE_VHOST_USER_GPIO_PCI)
static void vhost_user_gpio_pci_realize(VirtIOPCIProxy *vpci_dev, Error **errp)
{
VHostUserGPIOPCI *dev = VHOST_USER_GPIO_PCI(vpci_dev);
DeviceState *vdev = DEVICE(&dev->vdev);
vpci_dev->nvectors = 1;
qdev_realize(vdev, BUS(&vpci_dev->bus), errp);
}
static void vhost_user_gpio_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_gpio_pci_realize;
set_bit(DEVICE_CATEGORY_INPUT, dc->categories);
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_COMMUNICATION_OTHER;
}
static void vhost_user_gpio_pci_instance_init(Object *obj)
{
VHostUserGPIOPCI *dev = VHOST_USER_GPIO_PCI(obj);
virtio_instance_init_common(obj, &dev->vdev, sizeof(dev->vdev),
TYPE_VHOST_USER_GPIO);
}
static const VirtioPCIDeviceTypeInfo vhost_user_gpio_pci_info = {
.base_name = TYPE_VHOST_USER_GPIO_PCI,
.non_transitional_name = "vhost-user-gpio-pci",
.instance_size = sizeof(VHostUserGPIOPCI),
.instance_init = vhost_user_gpio_pci_instance_init,
.class_init = vhost_user_gpio_pci_class_init,
};
static void vhost_user_gpio_pci_register(void)
{
virtio_pci_types_register(&vhost_user_gpio_pci_info);
}
type_init(vhost_user_gpio_pci_register);
+411
View File
@@ -0,0 +1,411 @@
/*
* Vhost-user GPIO virtio device
*
* Copyright (c) 2022 Viresh Kumar <viresh.kumar@linaro.org>
*
* 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-gpio.h"
#include "qemu/error-report.h"
#include "standard-headers/linux/virtio_ids.h"
#include "trace.h"
#define REALIZE_CONNECTION_RETRIES 3
/* Features required from VirtIO */
static const int feature_bits[] = {
VIRTIO_F_VERSION_1,
VIRTIO_F_NOTIFY_ON_EMPTY,
VIRTIO_RING_F_INDIRECT_DESC,
VIRTIO_RING_F_EVENT_IDX,
VIRTIO_GPIO_F_IRQ,
VHOST_INVALID_FEATURE_BIT
};
static void vu_gpio_get_config(VirtIODevice *vdev, uint8_t *config)
{
VHostUserGPIO *gpio = VHOST_USER_GPIO(vdev);
memcpy(config, &gpio->config, sizeof(gpio->config));
}
static int vu_gpio_config_notifier(struct vhost_dev *dev)
{
VHostUserGPIO *gpio = VHOST_USER_GPIO(dev->vdev);
memcpy(dev->vdev->config, &gpio->config, sizeof(gpio->config));
virtio_notify_config(dev->vdev);
return 0;
}
const VhostDevConfigOps gpio_ops = {
.vhost_dev_config_notifier = vu_gpio_config_notifier,
};
static int vu_gpio_start(VirtIODevice *vdev)
{
BusState *qbus = BUS(qdev_get_parent_bus(DEVICE(vdev)));
VirtioBusClass *k = VIRTIO_BUS_GET_CLASS(qbus);
VHostUserGPIO *gpio = VHOST_USER_GPIO(vdev);
struct vhost_dev *vhost_dev = &gpio->vhost_dev;
int ret, i;
if (!k->set_guest_notifiers) {
error_report("binding does not support guest notifiers");
return -ENOSYS;
}
ret = vhost_dev_enable_notifiers(vhost_dev, vdev);
if (ret < 0) {
error_report("Error enabling host notifiers: %d", ret);
return ret;
}
ret = k->set_guest_notifiers(qbus->parent, vhost_dev->nvqs, true);
if (ret < 0) {
error_report("Error binding guest notifier: %d", ret);
goto err_host_notifiers;
}
/*
* Before we start up we need to ensure we have the final feature
* set needed for the vhost configuration. The backend may also
* apply backend_features when the feature set is sent.
*/
vhost_ack_features(&gpio->vhost_dev, feature_bits, vdev->guest_features);
ret = vhost_dev_start(&gpio->vhost_dev, vdev);
if (ret < 0) {
error_report("Error starting vhost-user-gpio: %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 < gpio->vhost_dev.nvqs; i++) {
vhost_virtqueue_mask(&gpio->vhost_dev, vdev, i, false);
}
/*
* As we must have VHOST_USER_F_PROTOCOL_FEATURES (because
* VHOST_USER_GET_CONFIG requires it) we need to explicitly enable
* the vrings.
*/
g_assert(vhost_dev->vhost_ops &&
vhost_dev->vhost_ops->vhost_set_vring_enable);
ret = vhost_dev->vhost_ops->vhost_set_vring_enable(vhost_dev, true);
if (ret == 0) {
return 0;
}
error_report("Failed to start vrings for vhost-user-gpio: %d", ret);
err_guest_notifiers:
k->set_guest_notifiers(qbus->parent, gpio->vhost_dev.nvqs, false);
err_host_notifiers:
vhost_dev_disable_notifiers(&gpio->vhost_dev, vdev);
return ret;
}
static void vu_gpio_stop(VirtIODevice *vdev)
{
VHostUserGPIO *gpio = VHOST_USER_GPIO(vdev);
BusState *qbus = BUS(qdev_get_parent_bus(DEVICE(vdev)));
VirtioBusClass *k = VIRTIO_BUS_GET_CLASS(qbus);
struct vhost_dev *vhost_dev = &gpio->vhost_dev;
int ret;
if (!k->set_guest_notifiers) {
return;
}
/*
* We can call vu_gpio_stop multiple times, for example from
* vm_state_notify and the final object finalisation. Check we
* aren't already stopped before doing so.
*/
if (!vhost_dev_is_started(vhost_dev)) {
return;
}
vhost_dev_stop(vhost_dev, vdev);
ret = k->set_guest_notifiers(qbus->parent, vhost_dev->nvqs, false);
if (ret < 0) {
error_report("vhost guest notifier cleanup failed: %d", ret);
return;
}
vhost_dev_disable_notifiers(vhost_dev, vdev);
}
static void vu_gpio_set_status(VirtIODevice *vdev, uint8_t status)
{
VHostUserGPIO *gpio = VHOST_USER_GPIO(vdev);
bool should_start = virtio_device_started(vdev, status);
trace_virtio_gpio_set_status(status);
if (!gpio->connected) {
return;
}
if (vhost_dev_is_started(&gpio->vhost_dev) == should_start) {
return;
}
if (should_start) {
if (vu_gpio_start(vdev)) {
qemu_chr_fe_disconnect(&gpio->chardev);
}
} else {
vu_gpio_stop(vdev);
}
}
static uint64_t vu_gpio_get_features(VirtIODevice *vdev, uint64_t features,
Error **errp)
{
VHostUserGPIO *gpio = VHOST_USER_GPIO(vdev);
return vhost_get_features(&gpio->vhost_dev, feature_bits, features);
}
static void vu_gpio_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_gpio_guest_notifier_mask(VirtIODevice *vdev, int idx, bool mask)
{
VHostUserGPIO *gpio = VHOST_USER_GPIO(vdev);
vhost_virtqueue_mask(&gpio->vhost_dev, vdev, idx, mask);
}
static void do_vhost_user_cleanup(VirtIODevice *vdev, VHostUserGPIO *gpio)
{
virtio_delete_queue(gpio->command_vq);
virtio_delete_queue(gpio->interrupt_vq);
g_free(gpio->vhost_dev.vqs);
gpio->vhost_dev.vqs = NULL;
virtio_cleanup(vdev);
vhost_user_cleanup(&gpio->vhost_user);
}
static int vu_gpio_connect(DeviceState *dev, Error **errp)
{
VirtIODevice *vdev = VIRTIO_DEVICE(dev);
VHostUserGPIO *gpio = VHOST_USER_GPIO(vdev);
struct vhost_dev *vhost_dev = &gpio->vhost_dev;
int ret;
if (gpio->connected) {
return 0;
}
gpio->connected = true;
vhost_dev_set_config_notifier(vhost_dev, &gpio_ops);
gpio->vhost_user.supports_config = true;
ret = vhost_dev_init(vhost_dev, &gpio->vhost_user,
VHOST_BACKEND_TYPE_USER, 0, errp);
if (ret < 0) {
return ret;
}
/* restore vhost state */
if (virtio_device_started(vdev, vdev->status)) {
vu_gpio_start(vdev);
}
return 0;
}
static void vu_gpio_disconnect(DeviceState *dev)
{
VirtIODevice *vdev = VIRTIO_DEVICE(dev);
VHostUserGPIO *gpio = VHOST_USER_GPIO(vdev);
if (!gpio->connected) {
return;
}
gpio->connected = false;
vu_gpio_stop(vdev);
vhost_dev_cleanup(&gpio->vhost_dev);
}
static void vu_gpio_event(void *opaque, QEMUChrEvent event)
{
DeviceState *dev = opaque;
VirtIODevice *vdev = VIRTIO_DEVICE(dev);
VHostUserGPIO *gpio = VHOST_USER_GPIO(vdev);
Error *local_err = NULL;
switch (event) {
case CHR_EVENT_OPENED:
if (vu_gpio_connect(dev, &local_err) < 0) {
qemu_chr_fe_disconnect(&gpio->chardev);
return;
}
break;
case CHR_EVENT_CLOSED:
vu_gpio_disconnect(dev);
break;
case CHR_EVENT_BREAK:
case CHR_EVENT_MUX_IN:
case CHR_EVENT_MUX_OUT:
/* Ignore */
break;
}
}
static int vu_gpio_realize_connect(VHostUserGPIO *gpio, Error **errp)
{
VirtIODevice *vdev = &gpio->parent_obj;
DeviceState *dev = &vdev->parent_obj;
struct vhost_dev *vhost_dev = &gpio->vhost_dev;
int ret;
ret = qemu_chr_fe_wait_connected(&gpio->chardev, errp);
if (ret < 0) {
return ret;
}
/*
* vu_gpio_connect() may have already connected (via the event
* callback) in which case it will just report success.
*/
ret = vu_gpio_connect(dev, errp);
if (ret < 0) {
qemu_chr_fe_disconnect(&gpio->chardev);
return ret;
}
g_assert(gpio->connected);
ret = vhost_dev_get_config(vhost_dev, (uint8_t *)&gpio->config,
sizeof(gpio->config), errp);
if (ret < 0) {
error_report("vhost-user-gpio: get config failed");
qemu_chr_fe_disconnect(&gpio->chardev);
vhost_dev_cleanup(vhost_dev);
return ret;
}
return 0;
}
static void vu_gpio_device_realize(DeviceState *dev, Error **errp)
{
ERRP_GUARD();
VirtIODevice *vdev = VIRTIO_DEVICE(dev);
VHostUserGPIO *gpio = VHOST_USER_GPIO(dev);
int retries, ret;
if (!gpio->chardev.chr) {
error_setg(errp, "vhost-user-gpio: chardev is mandatory");
return;
}
if (!vhost_user_init(&gpio->vhost_user, &gpio->chardev, errp)) {
return;
}
virtio_init(vdev, VIRTIO_ID_GPIO, sizeof(gpio->config));
gpio->vhost_dev.nvqs = 2;
gpio->command_vq = virtio_add_queue(vdev, 256, vu_gpio_handle_output);
gpio->interrupt_vq = virtio_add_queue(vdev, 256, vu_gpio_handle_output);
gpio->vhost_dev.vqs = g_new0(struct vhost_virtqueue, gpio->vhost_dev.nvqs);
gpio->connected = false;
qemu_chr_fe_set_handlers(&gpio->chardev, NULL, NULL, vu_gpio_event, NULL,
dev, NULL, true);
retries = REALIZE_CONNECTION_RETRIES;
g_assert(!*errp);
do {
if (*errp) {
error_prepend(errp, "Reconnecting after error: ");
error_report_err(*errp);
*errp = NULL;
}
ret = vu_gpio_realize_connect(gpio, errp);
} while (ret < 0 && retries--);
if (ret < 0) {
do_vhost_user_cleanup(vdev, gpio);
}
return;
}
static void vu_gpio_device_unrealize(DeviceState *dev)
{
VirtIODevice *vdev = VIRTIO_DEVICE(dev);
VHostUserGPIO *gpio = VHOST_USER_GPIO(dev);
vu_gpio_set_status(vdev, 0);
qemu_chr_fe_set_handlers(&gpio->chardev, NULL, NULL, NULL, NULL, NULL, NULL,
false);
vhost_dev_cleanup(&gpio->vhost_dev);
do_vhost_user_cleanup(vdev, gpio);
}
static const VMStateDescription vu_gpio_vmstate = {
.name = "vhost-user-gpio",
.unmigratable = 1,
};
static Property vu_gpio_properties[] = {
DEFINE_PROP_CHR("chardev", VHostUserGPIO, chardev),
DEFINE_PROP_END_OF_LIST(),
};
static void vu_gpio_class_init(ObjectClass *klass, void *data)
{
DeviceClass *dc = DEVICE_CLASS(klass);
VirtioDeviceClass *vdc = VIRTIO_DEVICE_CLASS(klass);
device_class_set_props(dc, vu_gpio_properties);
dc->vmsd = &vu_gpio_vmstate;
set_bit(DEVICE_CATEGORY_INPUT, dc->categories);
vdc->realize = vu_gpio_device_realize;
vdc->unrealize = vu_gpio_device_unrealize;
vdc->get_features = vu_gpio_get_features;
vdc->get_config = vu_gpio_get_config;
vdc->set_status = vu_gpio_set_status;
vdc->guest_notifier_mask = vu_gpio_guest_notifier_mask;
}
static const TypeInfo vu_gpio_info = {
.name = TYPE_VHOST_USER_GPIO,
.parent = TYPE_VIRTIO_DEVICE,
.instance_size = sizeof(VHostUserGPIO),
.class_init = vu_gpio_class_init,
};
static void vu_gpio_register_types(void)
{
type_register_static(&vu_gpio_info);
}
type_init(vu_gpio_register_types)

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