mirror of
https://github.com/izzy2lost/xemu.git
synced 2026-07-06 00:20:22 -07:00
Merge tag 'for_upstream' of https://git.kernel.org/pub/scm/virt/kvm/mst/qemu into staging
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:
+12
@@ -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>
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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 */
|
||||
|
||||
@@ -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
@@ -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(),
|
||||
};
|
||||
|
||||
|
||||
@@ -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
@@ -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
@@ -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));
|
||||
|
||||
@@ -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
@@ -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
@@ -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,
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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'))
|
||||
|
||||
@@ -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"
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
|
||||
@@ -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);
|
||||
@@ -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
Reference in New Issue
Block a user