aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorPeter Maydell <peter.maydell@linaro.org>2023-03-10 14:31:37 +0000
committerPeter Maydell <peter.maydell@linaro.org>2023-03-10 14:31:37 +0000
commit674acdd17808052519aafcbee1583ad89b66181a (patch)
treecbe42ce9a0e5e0f2ba240c0307bf2a42666bcc5b
parent7dfce9bd0fb226debf03a9bc73eaa0b85e836bab (diff)
parentbbc1c327d7974261c61566cdb950cc5fa0196b41 (diff)
downloadqemu-674acdd17808052519aafcbee1583ad89b66181a.zip
qemu-674acdd17808052519aafcbee1583ad89b66181a.tar.gz
qemu-674acdd17808052519aafcbee1583ad89b66181a.tar.bz2
Merge tag 'for_upstream' of https://git.kernel.org/pub/scm/virt/kvm/mst/qemu into staging
virtio,pc,pci: features, fixes Several features that landed at the last possible moment: Passthrough HDM decoder emulation Refactor cryptodev RAS error emulation and injection acpi-index support on non-hotpluggable slots Dynamically switch to vhost shadow virtqueues at vdpa net migration Plus a couple of bugfixes that look important to have in the release. Signed-off-by: Michael S. Tsirkin <mst@redhat.com> # -----BEGIN PGP SIGNATURE----- # # iQFDBAABCAAtFiEEXQn9CHHI+FuUyooNKB8NuNKNVGkFAmQJ8TYPHG1zdEByZWRo # YXQuY29tAAoJECgfDbjSjVRp37YIAMpQA5/ddmKKz/ABtBMHB5JX/SVYcG+1xkBR # j9IFYusOfmmDfmgAhv0Qxi9+Wik95lszVZUnphvocSGd0PXH47pK7yv9RZ1ttaYX # oAbXrGqXo8rUhl1ksQsJ8Iasj2di1BLP0byPuozbRkg1Kkz5TqRd9+hBqSBGEx21 # tsP5708UVCDAriwYYO78Cx0ZasmB9bqqeom5FdEsg9sYJ5aElOOvitp9YO1p2xhU # gRvhD+k/aqNi+mfOUF7qGDBanxKgx75VV/KU1cjjS9R1vNtwRhfc/26PBrROY00a # wkZWnAxmzDFKRS6cEfeb+eDGEVjC3IqLAjcFeuAIT/78CwdvIiY= # =e1yv # -----END PGP SIGNATURE----- # gpg: Signature made Thu 09 Mar 2023 14:46:14 GMT # 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: (72 commits) virtio: fix reachable assertion due to stale value of cached region size hw/virtio/vhost-user: avoid using unitialized errp hw/pxb-cxl: Support passthrough HDM Decoders unless overridden hw/pci: Add pcie_count_ds_port() and pcie_find_port_first() helpers hw/mem/cxl_type3: Add CXL RAS Error Injection Support. hw/pci/aer: Make PCIE AER error injection facility available for other emulation to use. hw/cxl: Fix endian issues in CXL RAS capability defaults / masks hw/mem/cxl-type3: Add AER extended capability hw/pci-bridge/cxl_root_port: Wire up MSI hw/pci-bridge/cxl_root_port: Wire up AER hw/pci/aer: Add missing routing for AER errors hw/pci/aer: Implement PCI_ERR_UNCOR_MASK register pcihp: add ACPI PCI hotplug specific is_hotpluggable_bus() callback pcihp: move fields enabling hotplug into AcpiPciHpState acpi: pci: move out ACPI PCI hotplug generator from generic slot generator build_append_pci_bus_devices() acpi: pci: move BSEL into build_append_pcihp_slots() acpi: pci: drop BSEL usage when deciding that device isn't hotpluggable pci: move acpi-index uniqueness check to generic PCI device code tests: acpi: update expected blobs tests: acpi: add non zero function device with acpi-index on non-hotpluggble bus ... Signed-off-by: Peter Maydell <peter.maydell@linaro.org>
-rw-r--r--MAINTAINERS2
-rw-r--r--backends/cryptodev-builtin.c42
-rw-r--r--backends/cryptodev-hmp-cmds.c54
-rw-r--r--backends/cryptodev-lkcf.c19
-rw-r--r--backends/cryptodev-vhost-user.c13
-rw-r--r--backends/cryptodev-vhost.c4
-rw-r--r--backends/cryptodev.c433
-rw-r--r--backends/meson.build1
-rw-r--r--hmp-commands-info.hx14
-rw-r--r--hw/acpi/acpi-pci-hotplug-stub.c9
-rw-r--r--hw/acpi/ich9.c21
-rw-r--r--hw/acpi/pci-bridge.c14
-rw-r--r--hw/acpi/pcihp.c112
-rw-r--r--hw/acpi/piix4.c33
-rw-r--r--hw/cxl/cxl-component-utils.c20
-rw-r--r--hw/cxl/cxl-host.c31
-rw-r--r--hw/i386/acpi-build.c179
-rw-r--r--hw/isa/lpc_ich9.c1
-rw-r--r--hw/mem/cxl_type3.c294
-rw-r--r--hw/mem/cxl_type3_stubs.c17
-rw-r--r--hw/mem/meson.build2
-rw-r--r--hw/pci-bridge/cxl_root_port.c64
-rw-r--r--hw/pci-bridge/pci_expander_bridge.c44
-rw-r--r--hw/pci/pci-internal.h1
-rw-r--r--hw/pci/pci.c57
-rw-r--r--hw/pci/pcie_aer.c14
-rw-r--r--hw/pci/pcie_port.c46
-rw-r--r--hw/virtio/trace-events1
-rw-r--r--hw/virtio/vhost-shadow-virtqueue.c8
-rw-r--r--hw/virtio/vhost-user.c4
-rw-r--r--hw/virtio/vhost-vdpa.c126
-rw-r--r--hw/virtio/vhost.c3
-rw-r--r--hw/virtio/virtio-crypto.c48
-rw-r--r--hw/virtio/virtio.c11
-rw-r--r--include/hw/acpi/ich9.h1
-rw-r--r--include/hw/acpi/pcihp.h11
-rw-r--r--include/hw/acpi/piix4.h2
-rw-r--r--include/hw/cxl/cxl.h1
-rw-r--r--include/hw/cxl/cxl_component.h27
-rw-r--r--include/hw/cxl/cxl_device.h11
-rw-r--r--include/hw/hotplug.h2
-rw-r--r--include/hw/pci/pci_bridge.h1
-rw-r--r--include/hw/pci/pcie_aer.h1
-rw-r--r--include/hw/pci/pcie_port.h2
-rw-r--r--include/hw/pci/pcie_regs.h3
-rw-r--r--include/hw/qdev-core.h13
-rw-r--r--include/hw/virtio/vhost-backend.h4
-rw-r--r--include/hw/virtio/vhost-vdpa.h3
-rw-r--r--include/monitor/hmp.h1
-rw-r--r--include/sysemu/cryptodev.h113
-rw-r--r--net/vhost-vdpa.c198
-rw-r--r--qapi/cryptodev.json89
-rw-r--r--qapi/cxl.json128
-rw-r--r--qapi/meson.build2
-rw-r--r--qapi/qapi-schema.json2
-rw-r--r--qapi/qom.json8
-rw-r--r--qapi/stats.json10
-rw-r--r--stats/stats-hmp-cmds.c5
-rw-r--r--stats/stats-qmp-cmds.c2
-rw-r--r--tests/data/acpi/pc/DSDTbin6360 -> 6488 bytes
-rw-r--r--tests/data/acpi/pc/DSDT.acpierstbin6283 -> 6411 bytes
-rw-r--r--tests/data/acpi/pc/DSDT.acpihmatbin7685 -> 7813 bytes
-rw-r--r--tests/data/acpi/pc/DSDT.bridgebin12487 -> 12615 bytes
-rw-r--r--tests/data/acpi/pc/DSDT.cphpbin6824 -> 6952 bytes
-rw-r--r--tests/data/acpi/pc/DSDT.dimmpxmbin8014 -> 8142 bytes
-rw-r--r--tests/data/acpi/pc/DSDT.hpbridgebin6289 -> 6451 bytes
-rw-r--r--tests/data/acpi/pc/DSDT.hpbrrootbin3081 -> 3343 bytes
-rw-r--r--tests/data/acpi/pc/DSDT.ipmikcsbin6432 -> 6560 bytes
-rw-r--r--tests/data/acpi/pc/DSDT.memhpbin7719 -> 7847 bytes
-rw-r--r--tests/data/acpi/pc/DSDT.nohpetbin6218 -> 6346 bytes
-rw-r--r--tests/data/acpi/pc/DSDT.numamembin6366 -> 6494 bytes
-rw-r--r--tests/data/acpi/pc/DSDT.roothpbin9745 -> 9873 bytes
-rw-r--r--tests/data/acpi/q35/DSDTbin8252 -> 8361 bytes
-rw-r--r--tests/data/acpi/q35/DSDT.acpierstbin8269 -> 8378 bytes
-rw-r--r--tests/data/acpi/q35/DSDT.acpihmatbin9577 -> 9686 bytes
-rw-r--r--tests/data/acpi/q35/DSDT.acpihmat-noinitiatorbin8531 -> 8640 bytes
-rw-r--r--tests/data/acpi/q35/DSDT.applesmcbin8298 -> 8407 bytes
-rw-r--r--tests/data/acpi/q35/DSDT.bridgebin11481 -> 11590 bytes
-rw-r--r--tests/data/acpi/q35/DSDT.core-count2bin32392 -> 32501 bytes
-rw-r--r--tests/data/acpi/q35/DSDT.cphpbin8716 -> 8825 bytes
-rw-r--r--tests/data/acpi/q35/DSDT.cxlbin9564 -> 9673 bytes
-rw-r--r--tests/data/acpi/q35/DSDT.dimmpxmbin9906 -> 10015 bytes
-rw-r--r--tests/data/acpi/q35/DSDT.ipmibtbin8327 -> 8436 bytes
-rw-r--r--tests/data/acpi/q35/DSDT.ipmismbusbin8340 -> 8449 bytes
-rw-r--r--tests/data/acpi/q35/DSDT.ivrsbin8269 -> 8378 bytes
-rw-r--r--tests/data/acpi/q35/DSDT.memhpbin9611 -> 9720 bytes
-rw-r--r--tests/data/acpi/q35/DSDT.mmio64bin9382 -> 9491 bytes
-rw-r--r--tests/data/acpi/q35/DSDT.multi-bridgebin12337 -> 12770 bytes
-rw-r--r--tests/data/acpi/q35/DSDT.noacpihpbin0 -> 8248 bytes
-rw-r--r--tests/data/acpi/q35/DSDT.nohpetbin8110 -> 8219 bytes
-rw-r--r--tests/data/acpi/q35/DSDT.numamembin8258 -> 8367 bytes
-rw-r--r--tests/data/acpi/q35/DSDT.pvpanic-isabin8353 -> 8462 bytes
-rw-r--r--tests/data/acpi/q35/DSDT.tis.tpm12bin8858 -> 8967 bytes
-rw-r--r--tests/data/acpi/q35/DSDT.tis.tpm2bin8884 -> 8993 bytes
-rw-r--r--tests/data/acpi/q35/DSDT.viotbin9361 -> 9470 bytes
-rw-r--r--tests/data/acpi/q35/DSDT.xapicbin35615 -> 35724 bytes
-rw-r--r--tests/qtest/bios-tables-test.c125
97 files changed, 2037 insertions, 470 deletions
diff --git a/MAINTAINERS b/MAINTAINERS
index 3f24bc2..2f2f4de 100644
--- a/MAINTAINERS
+++ b/MAINTAINERS
@@ -2889,9 +2889,11 @@ T: git https://gitlab.com/ehabkost/qemu.git machine-next
Cryptodev Backends
M: Gonglei <arei.gonglei@huawei.com>
+M: zhenwei pi <pizhenwei@bytedance.com>
S: Maintained
F: include/sysemu/cryptodev*.h
F: backends/cryptodev*.c
+F: qapi/cryptodev.json
Python library
M: John Snow <jsnow@redhat.com>
diff --git a/backends/cryptodev-builtin.c b/backends/cryptodev-builtin.c
index cda6ca3..39d0455 100644
--- a/backends/cryptodev-builtin.c
+++ b/backends/cryptodev-builtin.c
@@ -59,6 +59,19 @@ struct CryptoDevBackendBuiltin {
CryptoDevBackendBuiltinSession *sessions[MAX_NUM_SESSIONS];
};
+static void cryptodev_builtin_init_akcipher(CryptoDevBackend *backend)
+{
+ QCryptoAkCipherOptions opts;
+
+ opts.alg = QCRYPTO_AKCIPHER_ALG_RSA;
+ opts.u.rsa.padding_alg = QCRYPTO_RSA_PADDING_ALG_RAW;
+ if (qcrypto_akcipher_supports(&opts)) {
+ backend->conf.crypto_services |=
+ (1u << QCRYPTODEV_BACKEND_SERVICE_AKCIPHER);
+ backend->conf.akcipher_algo = 1u << VIRTIO_CRYPTO_AKCIPHER_RSA;
+ }
+}
+
static void cryptodev_builtin_init(
CryptoDevBackend *backend, Error **errp)
{
@@ -72,21 +85,18 @@ static void cryptodev_builtin_init(
return;
}
- cc = cryptodev_backend_new_client(
- "cryptodev-builtin", NULL);
+ cc = cryptodev_backend_new_client();
cc->info_str = g_strdup_printf("cryptodev-builtin0");
cc->queue_index = 0;
- cc->type = CRYPTODEV_BACKEND_TYPE_BUILTIN;
+ cc->type = QCRYPTODEV_BACKEND_TYPE_BUILTIN;
backend->conf.peers.ccs[0] = cc;
backend->conf.crypto_services =
- 1u << VIRTIO_CRYPTO_SERVICE_CIPHER |
- 1u << VIRTIO_CRYPTO_SERVICE_HASH |
- 1u << VIRTIO_CRYPTO_SERVICE_MAC |
- 1u << VIRTIO_CRYPTO_SERVICE_AKCIPHER;
+ 1u << QCRYPTODEV_BACKEND_SERVICE_CIPHER |
+ 1u << QCRYPTODEV_BACKEND_SERVICE_HASH |
+ 1u << QCRYPTODEV_BACKEND_SERVICE_MAC;
backend->conf.cipher_algo_l = 1u << VIRTIO_CRYPTO_CIPHER_AES_CBC;
backend->conf.hash_algo = 1u << VIRTIO_CRYPTO_HASH_SHA1;
- backend->conf.akcipher_algo = 1u << VIRTIO_CRYPTO_AKCIPHER_RSA;
/*
* Set the Maximum length of crypto request.
* Why this value? Just avoid to overflow when
@@ -95,6 +105,7 @@ static void cryptodev_builtin_init(
backend->conf.max_size = LONG_MAX - sizeof(CryptoDevBackendOpInfo);
backend->conf.max_cipher_key_len = CRYPTODEV_BUITLIN_MAX_CIPHER_KEY_LEN;
backend->conf.max_auth_key_len = CRYPTODEV_BUITLIN_MAX_AUTH_KEY_LEN;
+ cryptodev_builtin_init_akcipher(backend);
cryptodev_backend_set_ready(backend, true);
}
@@ -528,17 +539,14 @@ static int cryptodev_builtin_asym_operation(
static int cryptodev_builtin_operation(
CryptoDevBackend *backend,
- CryptoDevBackendOpInfo *op_info,
- uint32_t queue_index,
- CryptoDevCompletionFunc cb,
- void *opaque)
+ CryptoDevBackendOpInfo *op_info)
{
CryptoDevBackendBuiltin *builtin =
CRYPTODEV_BACKEND_BUILTIN(backend);
CryptoDevBackendBuiltinSession *sess;
CryptoDevBackendSymOpInfo *sym_op_info;
CryptoDevBackendAsymOpInfo *asym_op_info;
- enum CryptoDevBackendAlgType algtype = op_info->algtype;
+ QCryptodevBackendAlgType algtype = op_info->algtype;
int status = -VIRTIO_CRYPTO_ERR;
Error *local_error = NULL;
@@ -550,11 +558,11 @@ static int cryptodev_builtin_operation(
}
sess = builtin->sessions[op_info->session_id];
- if (algtype == CRYPTODEV_BACKEND_ALG_SYM) {
+ if (algtype == QCRYPTODEV_BACKEND_ALG_SYM) {
sym_op_info = op_info->u.sym_op_info;
status = cryptodev_builtin_sym_operation(sess, sym_op_info,
&local_error);
- } else if (algtype == CRYPTODEV_BACKEND_ALG_ASYM) {
+ } else if (algtype == QCRYPTODEV_BACKEND_ALG_ASYM) {
asym_op_info = op_info->u.asym_op_info;
status = cryptodev_builtin_asym_operation(sess, op_info->op_code,
asym_op_info, &local_error);
@@ -563,8 +571,8 @@ static int cryptodev_builtin_operation(
if (local_error) {
error_report_err(local_error);
}
- if (cb) {
- cb(opaque, status);
+ if (op_info->cb) {
+ op_info->cb(op_info->opaque, status);
}
return 0;
}
diff --git a/backends/cryptodev-hmp-cmds.c b/backends/cryptodev-hmp-cmds.c
new file mode 100644
index 0000000..4f7220b
--- /dev/null
+++ b/backends/cryptodev-hmp-cmds.c
@@ -0,0 +1,54 @@
+/*
+ * HMP commands related to cryptodev
+ *
+ * Copyright (c) 2023 Bytedance.Inc
+ *
+ * Authors:
+ * zhenwei pi<pizhenwei@bytedance.com>
+ *
+ * This work is licensed under the terms of the GNU GPL, version 2 or
+ * (at your option) any later version.
+ */
+
+#include "qemu/osdep.h"
+#include "monitor/hmp.h"
+#include "monitor/monitor.h"
+#include "qapi/qapi-commands-cryptodev.h"
+#include "qapi/qmp/qdict.h"
+
+
+void hmp_info_cryptodev(Monitor *mon, const QDict *qdict)
+{
+ QCryptodevInfoList *il;
+ QCryptodevBackendServiceTypeList *sl;
+ QCryptodevBackendClientList *cl;
+
+ for (il = qmp_query_cryptodev(NULL); il; il = il->next) {
+ g_autofree char *services = NULL;
+ QCryptodevInfo *info = il->value;
+ char *tmp_services;
+
+ /* build a string like 'service=[akcipher|mac|hash|cipher]' */
+ for (sl = info->service; sl; sl = sl->next) {
+ const char *service = QCryptodevBackendServiceType_str(sl->value);
+
+ if (!services) {
+ services = g_strdup(service);
+ } else {
+ tmp_services = g_strjoin("|", services, service, NULL);
+ g_free(services);
+ services = tmp_services;
+ }
+ }
+ monitor_printf(mon, "%s: service=[%s]\n", info->id, services);
+
+ for (cl = info->client; cl; cl = cl->next) {
+ QCryptodevBackendClient *client = cl->value;
+ monitor_printf(mon, " queue %" PRIu32 ": type=%s\n",
+ client->queue,
+ QCryptodevBackendType_str(client->type));
+ }
+ }
+
+ qapi_free_QCryptodevInfoList(il);
+}
diff --git a/backends/cryptodev-lkcf.c b/backends/cryptodev-lkcf.c
index 133bd70..45aba1f 100644
--- a/backends/cryptodev-lkcf.c
+++ b/backends/cryptodev-lkcf.c
@@ -223,14 +223,14 @@ static void cryptodev_lkcf_init(CryptoDevBackend *backend, Error **errp)
return;
}
- cc = cryptodev_backend_new_client("cryptodev-lkcf", NULL);
+ cc = cryptodev_backend_new_client();
cc->info_str = g_strdup_printf("cryptodev-lkcf0");
cc->queue_index = 0;
- cc->type = CRYPTODEV_BACKEND_TYPE_LKCF;
+ cc->type = QCRYPTODEV_BACKEND_TYPE_LKCF;
backend->conf.peers.ccs[0] = cc;
backend->conf.crypto_services =
- 1u << VIRTIO_CRYPTO_SERVICE_AKCIPHER;
+ 1u << QCRYPTODEV_BACKEND_SERVICE_AKCIPHER;
backend->conf.akcipher_algo = 1u << VIRTIO_CRYPTO_AKCIPHER_RSA;
lkcf->running = true;
@@ -469,15 +469,12 @@ static void *cryptodev_lkcf_worker(void *arg)
static int cryptodev_lkcf_operation(
CryptoDevBackend *backend,
- CryptoDevBackendOpInfo *op_info,
- uint32_t queue_index,
- CryptoDevCompletionFunc cb,
- void *opaque)
+ CryptoDevBackendOpInfo *op_info)
{
CryptoDevBackendLKCF *lkcf =
CRYPTODEV_BACKEND_LKCF(backend);
CryptoDevBackendLKCFSession *sess;
- enum CryptoDevBackendAlgType algtype = op_info->algtype;
+ QCryptodevBackendAlgType algtype = op_info->algtype;
CryptoDevLKCFTask *task;
if (op_info->session_id >= MAX_SESSIONS ||
@@ -488,15 +485,15 @@ static int cryptodev_lkcf_operation(
}
sess = lkcf->sess[op_info->session_id];
- if (algtype != CRYPTODEV_BACKEND_ALG_ASYM) {
+ if (algtype != QCRYPTODEV_BACKEND_ALG_ASYM) {
error_report("algtype not supported: %u", algtype);
return -VIRTIO_CRYPTO_NOTSUPP;
}
task = g_new0(CryptoDevLKCFTask, 1);
task->op_info = op_info;
- task->cb = cb;
- task->opaque = opaque;
+ task->cb = op_info->cb;
+ task->opaque = op_info->opaque;
task->sess = sess;
task->lkcf = lkcf;
task->status = -VIRTIO_CRYPTO_ERR;
diff --git a/backends/cryptodev-vhost-user.c b/backends/cryptodev-vhost-user.c
index ab3028e..b1d9eb7 100644
--- a/backends/cryptodev-vhost-user.c
+++ b/backends/cryptodev-vhost-user.c
@@ -67,7 +67,7 @@ cryptodev_vhost_user_get_vhost(
{
CryptoDevBackendVhostUser *s =
CRYPTODEV_BACKEND_VHOST_USER(b);
- assert(cc->type == CRYPTODEV_BACKEND_TYPE_VHOST_USER);
+ assert(cc->type == QCRYPTODEV_BACKEND_TYPE_VHOST_USER);
assert(queue < MAX_CRYPTO_QUEUE_NUM);
return s->vhost_crypto[queue];
@@ -198,12 +198,11 @@ static void cryptodev_vhost_user_init(
s->opened = true;
for (i = 0; i < queues; i++) {
- cc = cryptodev_backend_new_client(
- "cryptodev-vhost-user", NULL);
+ cc = cryptodev_backend_new_client();
cc->info_str = g_strdup_printf("cryptodev-vhost-user%zu to %s ",
i, chr->label);
cc->queue_index = i;
- cc->type = CRYPTODEV_BACKEND_TYPE_VHOST_USER;
+ cc->type = QCRYPTODEV_BACKEND_TYPE_VHOST_USER;
backend->conf.peers.ccs[i] = cc;
@@ -222,9 +221,9 @@ static void cryptodev_vhost_user_init(
cryptodev_vhost_user_event, NULL, s, NULL, true);
backend->conf.crypto_services =
- 1u << VIRTIO_CRYPTO_SERVICE_CIPHER |
- 1u << VIRTIO_CRYPTO_SERVICE_HASH |
- 1u << VIRTIO_CRYPTO_SERVICE_MAC;
+ 1u << QCRYPTODEV_BACKEND_SERVICE_CIPHER |
+ 1u << QCRYPTODEV_BACKEND_SERVICE_HASH |
+ 1u << QCRYPTODEV_BACKEND_SERVICE_MAC;
backend->conf.cipher_algo_l = 1u << VIRTIO_CRYPTO_CIPHER_AES_CBC;
backend->conf.hash_algo = 1u << VIRTIO_CRYPTO_HASH_SHA1;
diff --git a/backends/cryptodev-vhost.c b/backends/cryptodev-vhost.c
index 74ea0ad..9352373 100644
--- a/backends/cryptodev-vhost.c
+++ b/backends/cryptodev-vhost.c
@@ -127,7 +127,7 @@ cryptodev_get_vhost(CryptoDevBackendClient *cc,
switch (cc->type) {
#if defined(CONFIG_VHOST_USER) && defined(CONFIG_LINUX)
- case CRYPTODEV_BACKEND_TYPE_VHOST_USER:
+ case QCRYPTODEV_BACKEND_TYPE_VHOST_USER:
vhost_crypto = cryptodev_vhost_user_get_vhost(cc, b, queue);
break;
#endif
@@ -195,7 +195,7 @@ int cryptodev_vhost_start(VirtIODevice *dev, int total_queues)
* because vhost user doesn't interrupt masking/unmasking
* properly.
*/
- if (cc->type == CRYPTODEV_BACKEND_TYPE_VHOST_USER) {
+ if (cc->type == QCRYPTODEV_BACKEND_TYPE_VHOST_USER) {
dev->use_guest_notifier_mask = false;
}
}
diff --git a/backends/cryptodev.c b/backends/cryptodev.c
index 54ee8c8..94ca393 100644
--- a/backends/cryptodev.c
+++ b/backends/cryptodev.c
@@ -23,29 +23,92 @@
#include "qemu/osdep.h"
#include "sysemu/cryptodev.h"
+#include "sysemu/stats.h"
#include "qapi/error.h"
+#include "qapi/qapi-commands-cryptodev.h"
+#include "qapi/qapi-types-stats.h"
#include "qapi/visitor.h"
#include "qemu/config-file.h"
#include "qemu/error-report.h"
+#include "qemu/main-loop.h"
#include "qom/object_interfaces.h"
#include "hw/virtio/virtio-crypto.h"
+#define SYM_ENCRYPT_OPS_STR "sym-encrypt-ops"
+#define SYM_DECRYPT_OPS_STR "sym-decrypt-ops"
+#define SYM_ENCRYPT_BYTES_STR "sym-encrypt-bytes"
+#define SYM_DECRYPT_BYTES_STR "sym-decrypt-bytes"
+
+#define ASYM_ENCRYPT_OPS_STR "asym-encrypt-ops"
+#define ASYM_DECRYPT_OPS_STR "asym-decrypt-ops"
+#define ASYM_SIGN_OPS_STR "asym-sign-ops"
+#define ASYM_VERIFY_OPS_STR "asym-verify-ops"
+#define ASYM_ENCRYPT_BYTES_STR "asym-encrypt-bytes"
+#define ASYM_DECRYPT_BYTES_STR "asym-decrypt-bytes"
+#define ASYM_SIGN_BYTES_STR "asym-sign-bytes"
+#define ASYM_VERIFY_BYTES_STR "asym-verify-bytes"
+
+typedef struct StatsArgs {
+ union StatsResultsType {
+ StatsResultList **stats;
+ StatsSchemaList **schema;
+ } result;
+ strList *names;
+ Error **errp;
+} StatsArgs;
static QTAILQ_HEAD(, CryptoDevBackendClient) crypto_clients;
+static int qmp_query_cryptodev_foreach(Object *obj, void *data)
+{
+ CryptoDevBackend *backend;
+ QCryptodevInfoList **infolist = data;
+ uint32_t services, i;
+
+ if (!object_dynamic_cast(obj, TYPE_CRYPTODEV_BACKEND)) {
+ return 0;
+ }
+
+ QCryptodevInfo *info = g_new0(QCryptodevInfo, 1);
+ info->id = g_strdup(object_get_canonical_path_component(obj));
+
+ backend = CRYPTODEV_BACKEND(obj);
+ services = backend->conf.crypto_services;
+ for (i = 0; i < QCRYPTODEV_BACKEND_SERVICE__MAX; i++) {
+ if (services & (1 << i)) {
+ QAPI_LIST_PREPEND(info->service, i);
+ }
+ }
+
+ for (i = 0; i < backend->conf.peers.queues; i++) {
+ CryptoDevBackendClient *cc = backend->conf.peers.ccs[i];
+ QCryptodevBackendClient *client = g_new0(QCryptodevBackendClient, 1);
+
+ client->queue = cc->queue_index;
+ client->type = cc->type;
+ QAPI_LIST_PREPEND(info->client, client);
+ }
+
+ QAPI_LIST_PREPEND(*infolist, info);
+
+ return 0;
+}
-CryptoDevBackendClient *
-cryptodev_backend_new_client(const char *model,
- const char *name)
+QCryptodevInfoList *qmp_query_cryptodev(Error **errp)
+{
+ QCryptodevInfoList *list = NULL;
+ Object *objs = container_get(object_get_root(), "/objects");
+
+ object_child_foreach(objs, qmp_query_cryptodev_foreach, &list);
+
+ return list;
+}
+
+CryptoDevBackendClient *cryptodev_backend_new_client(void)
{
CryptoDevBackendClient *cc;
cc = g_new0(CryptoDevBackendClient, 1);
- cc->model = g_strdup(model);
- if (name) {
- cc->name = g_strdup(name);
- }
-
QTAILQ_INSERT_TAIL(&crypto_clients, cc, next);
return cc;
@@ -55,8 +118,6 @@ void cryptodev_backend_free_client(
CryptoDevBackendClient *cc)
{
QTAILQ_REMOVE(&crypto_clients, cc, next);
- g_free(cc->name);
- g_free(cc->model);
g_free(cc->info_str);
g_free(cc);
}
@@ -71,6 +132,9 @@ void cryptodev_backend_cleanup(
if (bc->cleanup) {
bc->cleanup(backend, errp);
}
+
+ g_free(backend->sym_stat);
+ g_free(backend->asym_stat);
}
int cryptodev_backend_create_session(
@@ -107,38 +171,111 @@ int cryptodev_backend_close_session(
static int cryptodev_backend_operation(
CryptoDevBackend *backend,
- CryptoDevBackendOpInfo *op_info,
- uint32_t queue_index,
- CryptoDevCompletionFunc cb,
- void *opaque)
+ CryptoDevBackendOpInfo *op_info)
{
CryptoDevBackendClass *bc =
CRYPTODEV_BACKEND_GET_CLASS(backend);
if (bc->do_op) {
- return bc->do_op(backend, op_info, queue_index, cb, opaque);
+ return bc->do_op(backend, op_info);
}
return -VIRTIO_CRYPTO_NOTSUPP;
}
+static int cryptodev_backend_account(CryptoDevBackend *backend,
+ CryptoDevBackendOpInfo *op_info)
+{
+ enum QCryptodevBackendAlgType algtype = op_info->algtype;
+ int len;
+
+ if (algtype == QCRYPTODEV_BACKEND_ALG_ASYM) {
+ CryptoDevBackendAsymOpInfo *asym_op_info = op_info->u.asym_op_info;
+ len = asym_op_info->src_len;
+ switch (op_info->op_code) {
+ case VIRTIO_CRYPTO_AKCIPHER_ENCRYPT:
+ CryptodevAsymStatIncEncrypt(backend, len);
+ break;
+ case VIRTIO_CRYPTO_AKCIPHER_DECRYPT:
+ CryptodevAsymStatIncDecrypt(backend, len);
+ break;
+ case VIRTIO_CRYPTO_AKCIPHER_SIGN:
+ CryptodevAsymStatIncSign(backend, len);
+ break;
+ case VIRTIO_CRYPTO_AKCIPHER_VERIFY:
+ CryptodevAsymStatIncVerify(backend, len);
+ break;
+ default:
+ return -VIRTIO_CRYPTO_NOTSUPP;
+ }
+ } else if (algtype == QCRYPTODEV_BACKEND_ALG_SYM) {
+ CryptoDevBackendSymOpInfo *sym_op_info = op_info->u.sym_op_info;
+ len = sym_op_info->src_len;
+ switch (op_info->op_code) {
+ case VIRTIO_CRYPTO_CIPHER_ENCRYPT:
+ CryptodevSymStatIncEncrypt(backend, len);
+ break;
+ case VIRTIO_CRYPTO_CIPHER_DECRYPT:
+ CryptodevSymStatIncDecrypt(backend, len);
+ break;
+ default:
+ return -VIRTIO_CRYPTO_NOTSUPP;
+ }
+ } else {
+ error_report("Unsupported cryptodev alg type: %" PRIu32 "", algtype);
+ return -VIRTIO_CRYPTO_NOTSUPP;
+ }
+
+ return len;
+}
+
+static void cryptodev_backend_throttle_timer_cb(void *opaque)
+{
+ CryptoDevBackend *backend = (CryptoDevBackend *)opaque;
+ CryptoDevBackendOpInfo *op_info, *tmpop;
+ int ret;
+
+ QTAILQ_FOREACH_SAFE(op_info, &backend->opinfos, next, tmpop) {
+ QTAILQ_REMOVE(&backend->opinfos, op_info, next);
+ ret = cryptodev_backend_account(backend, op_info);
+ if (ret < 0) {
+ op_info->cb(op_info->opaque, ret);
+ continue;
+ }
+
+ throttle_account(&backend->ts, true, ret);
+ cryptodev_backend_operation(backend, op_info);
+ if (throttle_enabled(&backend->tc) &&
+ throttle_schedule_timer(&backend->ts, &backend->tt, true)) {
+ break;
+ }
+ }
+}
+
int cryptodev_backend_crypto_operation(
CryptoDevBackend *backend,
- void *opaque1,
- uint32_t queue_index,
- CryptoDevCompletionFunc cb, void *opaque2)
+ CryptoDevBackendOpInfo *op_info)
{
- VirtIOCryptoReq *req = opaque1;
- CryptoDevBackendOpInfo *op_info = &req->op_info;
- enum CryptoDevBackendAlgType algtype = req->flags;
+ int ret;
- if ((algtype != CRYPTODEV_BACKEND_ALG_SYM)
- && (algtype != CRYPTODEV_BACKEND_ALG_ASYM)) {
- error_report("Unsupported cryptodev alg type: %" PRIu32 "", algtype);
- return -VIRTIO_CRYPTO_NOTSUPP;
+ if (!throttle_enabled(&backend->tc)) {
+ goto do_account;
+ }
+
+ if (throttle_schedule_timer(&backend->ts, &backend->tt, true) ||
+ !QTAILQ_EMPTY(&backend->opinfos)) {
+ QTAILQ_INSERT_TAIL(&backend->opinfos, op_info, next);
+ return 0;
}
- return cryptodev_backend_operation(backend, op_info, queue_index,
- cb, opaque2);
+do_account:
+ ret = cryptodev_backend_account(backend, op_info);
+ if (ret < 0) {
+ return ret;
+ }
+
+ throttle_account(&backend->ts, true, ret);
+
+ return cryptodev_backend_operation(backend, op_info);
}
static void
@@ -169,15 +306,111 @@ cryptodev_backend_set_queues(Object *obj, Visitor *v, const char *name,
backend->conf.peers.queues = value;
}
+static void cryptodev_backend_set_throttle(CryptoDevBackend *backend, int field,
+ uint64_t value, Error **errp)
+{
+ uint64_t orig = backend->tc.buckets[field].avg;
+ bool enabled = throttle_enabled(&backend->tc);
+
+ if (orig == value) {
+ return;
+ }
+
+ backend->tc.buckets[field].avg = value;
+ if (!throttle_enabled(&backend->tc)) {
+ throttle_timers_destroy(&backend->tt);
+ cryptodev_backend_throttle_timer_cb(backend); /* drain opinfos */
+ return;
+ }
+
+ if (!throttle_is_valid(&backend->tc, errp)) {
+ backend->tc.buckets[field].avg = orig; /* revert change */
+ return;
+ }
+
+ if (!enabled) {
+ throttle_init(&backend->ts);
+ throttle_timers_init(&backend->tt, qemu_get_aio_context(),
+ QEMU_CLOCK_REALTIME,
+ cryptodev_backend_throttle_timer_cb, /* FIXME */
+ cryptodev_backend_throttle_timer_cb, backend);
+ }
+
+ throttle_config(&backend->ts, QEMU_CLOCK_REALTIME, &backend->tc);
+}
+
+static void cryptodev_backend_get_bps(Object *obj, Visitor *v,
+ const char *name, void *opaque,
+ Error **errp)
+{
+ CryptoDevBackend *backend = CRYPTODEV_BACKEND(obj);
+ uint64_t value = backend->tc.buckets[THROTTLE_BPS_TOTAL].avg;
+
+ visit_type_uint64(v, name, &value, errp);
+}
+
+static void cryptodev_backend_set_bps(Object *obj, Visitor *v, const char *name,
+ void *opaque, Error **errp)
+{
+ CryptoDevBackend *backend = CRYPTODEV_BACKEND(obj);
+ uint64_t value;
+
+ if (!visit_type_uint64(v, name, &value, errp)) {
+ return;
+ }
+
+ cryptodev_backend_set_throttle(backend, THROTTLE_BPS_TOTAL, value, errp);
+}
+
+static void cryptodev_backend_get_ops(Object *obj, Visitor *v, const char *name,
+ void *opaque, Error **errp)
+{
+ CryptoDevBackend *backend = CRYPTODEV_BACKEND(obj);
+ uint64_t value = backend->tc.buckets[THROTTLE_OPS_TOTAL].avg;
+
+ visit_type_uint64(v, name, &value, errp);
+}
+
+static void cryptodev_backend_set_ops(Object *obj, Visitor *v,
+ const char *name, void *opaque,
+ Error **errp)
+{
+ CryptoDevBackend *backend = CRYPTODEV_BACKEND(obj);
+ uint64_t value;
+
+ if (!visit_type_uint64(v, name, &value, errp)) {
+ return;
+ }
+
+ cryptodev_backend_set_throttle(backend, THROTTLE_OPS_TOTAL, value, errp);
+}
+
static void
cryptodev_backend_complete(UserCreatable *uc, Error **errp)
{
CryptoDevBackend *backend = CRYPTODEV_BACKEND(uc);
CryptoDevBackendClass *bc = CRYPTODEV_BACKEND_GET_CLASS(uc);
+ uint32_t services;
+ uint64_t value;
+
+ QTAILQ_INIT(&backend->opinfos);
+ value = backend->tc.buckets[THROTTLE_OPS_TOTAL].avg;
+ cryptodev_backend_set_throttle(backend, THROTTLE_OPS_TOTAL, value, errp);
+ value = backend->tc.buckets[THROTTLE_BPS_TOTAL].avg;
+ cryptodev_backend_set_throttle(backend, THROTTLE_BPS_TOTAL, value, errp);
if (bc->init) {
bc->init(backend, errp);
}
+
+ services = backend->conf.crypto_services;
+ if (services & (1 << QCRYPTODEV_BACKEND_SERVICE_CIPHER)) {
+ backend->sym_stat = g_new0(CryptodevBackendSymStat, 1);
+ }
+
+ if (services & (1 << QCRYPTODEV_BACKEND_SERVICE_AKCIPHER)) {
+ backend->asym_stat = g_new0(CryptodevBackendAsymStat, 1);
+ }
}
void cryptodev_backend_set_used(CryptoDevBackend *backend, bool used)
@@ -208,8 +441,12 @@ cryptodev_backend_can_be_deleted(UserCreatable *uc)
static void cryptodev_backend_instance_init(Object *obj)
{
+ CryptoDevBackend *backend = CRYPTODEV_BACKEND(obj);
+
/* Initialize devices' queues property to 1 */
object_property_set_int(obj, "queues", 1, NULL);
+
+ throttle_config_init(&backend->tc);
}
static void cryptodev_backend_finalize(Object *obj)
@@ -217,6 +454,137 @@ static void cryptodev_backend_finalize(Object *obj)
CryptoDevBackend *backend = CRYPTODEV_BACKEND(obj);
cryptodev_backend_cleanup(backend, NULL);
+ if (throttle_enabled(&backend->tc)) {
+ throttle_timers_destroy(&backend->tt);
+ }
+}
+
+static StatsList *cryptodev_backend_stats_add(const char *name, int64_t *val,
+ StatsList *stats_list)
+{
+ Stats *stats = g_new0(Stats, 1);
+
+ stats->name = g_strdup(name);
+ stats->value = g_new0(StatsValue, 1);
+ stats->value->type = QTYPE_QNUM;
+ stats->value->u.scalar = *val;
+
+ QAPI_LIST_PREPEND(stats_list, stats);
+ return stats_list;
+}
+
+static int cryptodev_backend_stats_query(Object *obj, void *data)
+{
+ StatsArgs *stats_args = data;
+ StatsResultList **stats_results = stats_args->result.stats;
+ StatsList *stats_list = NULL;
+ StatsResult *entry;
+ CryptoDevBackend *backend;
+ CryptodevBackendSymStat *sym_stat;
+ CryptodevBackendAsymStat *asym_stat;
+
+ if (!object_dynamic_cast(obj, TYPE_CRYPTODEV_BACKEND)) {
+ return 0;
+ }
+
+ backend = CRYPTODEV_BACKEND(obj);
+ sym_stat = backend->sym_stat;
+ if (sym_stat) {
+ stats_list = cryptodev_backend_stats_add(SYM_ENCRYPT_OPS_STR,
+ &sym_stat->encrypt_ops, stats_list);
+ stats_list = cryptodev_backend_stats_add(SYM_DECRYPT_OPS_STR,
+ &sym_stat->decrypt_ops, stats_list);
+ stats_list = cryptodev_backend_stats_add(SYM_ENCRYPT_BYTES_STR,
+ &sym_stat->encrypt_bytes, stats_list);
+ stats_list = cryptodev_backend_stats_add(SYM_DECRYPT_BYTES_STR,
+ &sym_stat->decrypt_bytes, stats_list);
+ }
+
+ asym_stat = backend->asym_stat;
+ if (asym_stat) {
+ stats_list = cryptodev_backend_stats_add(ASYM_ENCRYPT_OPS_STR,
+ &asym_stat->encrypt_ops, stats_list);
+ stats_list = cryptodev_backend_stats_add(ASYM_DECRYPT_OPS_STR,
+ &asym_stat->decrypt_ops, stats_list);
+ stats_list = cryptodev_backend_stats_add(ASYM_SIGN_OPS_STR,
+ &asym_stat->sign_ops, stats_list);
+ stats_list = cryptodev_backend_stats_add(ASYM_VERIFY_OPS_STR,
+ &asym_stat->verify_ops, stats_list);
+ stats_list = cryptodev_backend_stats_add(ASYM_ENCRYPT_BYTES_STR,
+ &asym_stat->encrypt_bytes, stats_list);
+ stats_list = cryptodev_backend_stats_add(ASYM_DECRYPT_BYTES_STR,
+ &asym_stat->decrypt_bytes, stats_list);
+ stats_list = cryptodev_backend_stats_add(ASYM_SIGN_BYTES_STR,
+ &asym_stat->sign_bytes, stats_list);
+ stats_list = cryptodev_backend_stats_add(ASYM_VERIFY_BYTES_STR,
+ &asym_stat->verify_bytes, stats_list);
+ }
+
+ entry = g_new0(StatsResult, 1);
+ entry->provider = STATS_PROVIDER_CRYPTODEV;
+ entry->qom_path = g_strdup(object_get_canonical_path(obj));
+ entry->stats = stats_list;
+ QAPI_LIST_PREPEND(*stats_results, entry);
+
+ return 0;
+}
+
+static void cryptodev_backend_stats_cb(StatsResultList **result,
+ StatsTarget target,
+ strList *names, strList *targets,
+ Error **errp)
+{
+ switch (target) {
+ case STATS_TARGET_CRYPTODEV:
+ {
+ Object *objs = container_get(object_get_root(), "/objects");
+ StatsArgs stats_args;
+ stats_args.result.stats = result;
+ stats_args.names = names;
+ stats_args.errp = errp;
+
+ object_child_foreach(objs, cryptodev_backend_stats_query, &stats_args);
+ break;
+ }
+ default:
+ break;
+ }
+}
+
+static StatsSchemaValueList *cryptodev_backend_schemas_add(const char *name,
+ StatsSchemaValueList *list)
+{
+ StatsSchemaValueList *schema_entry = g_new0(StatsSchemaValueList, 1);
+
+ schema_entry->value = g_new0(StatsSchemaValue, 1);
+ schema_entry->value->type = STATS_TYPE_CUMULATIVE;
+ schema_entry->value->name = g_strdup(name);
+ schema_entry->next = list;
+
+ return schema_entry;
+}
+
+static void cryptodev_backend_schemas_cb(StatsSchemaList **result,
+ Error **errp)
+{
+ StatsSchemaValueList *stats_list = NULL;
+ const char *sym_stats[] = { SYM_ENCRYPT_OPS_STR, SYM_DECRYPT_OPS_STR,
+ SYM_ENCRYPT_BYTES_STR, SYM_DECRYPT_BYTES_STR };
+ const char *asym_stats[] = { ASYM_ENCRYPT_OPS_STR, ASYM_DECRYPT_OPS_STR,
+ ASYM_SIGN_OPS_STR, ASYM_VERIFY_OPS_STR,
+ ASYM_ENCRYPT_BYTES_STR, ASYM_DECRYPT_BYTES_STR,
+ ASYM_SIGN_BYTES_STR, ASYM_VERIFY_BYTES_STR };
+
+ for (int i = 0; i < ARRAY_SIZE(sym_stats); i++) {
+ stats_list = cryptodev_backend_schemas_add(sym_stats[i], stats_list);
+ }
+
+ for (int i = 0; i < ARRAY_SIZE(asym_stats); i++) {
+ stats_list = cryptodev_backend_schemas_add(asym_stats[i], stats_list);
+ }
+
+ add_stats_schema(result, STATS_PROVIDER_CRYPTODEV, STATS_TARGET_CRYPTODEV,
+ stats_list);
}
static void
@@ -232,6 +600,17 @@ cryptodev_backend_class_init(ObjectClass *oc, void *data)
cryptodev_backend_get_queues,
cryptodev_backend_set_queues,
NULL, NULL);
+ object_class_property_add(oc, "throttle-bps", "uint64",
+ cryptodev_backend_get_bps,
+ cryptodev_backend_set_bps,
+ NULL, NULL);
+ object_class_property_add(oc, "throttle-ops", "uint64",
+ cryptodev_backend_get_ops,
+ cryptodev_backend_set_ops,
+ NULL, NULL);
+
+ add_stats_callbacks(STATS_PROVIDER_CRYPTODEV, cryptodev_backend_stats_cb,
+ cryptodev_backend_schemas_cb);
}
static const TypeInfo cryptodev_backend_info = {
diff --git a/backends/meson.build b/backends/meson.build
index 954e658..b369e0a 100644
--- a/backends/meson.build
+++ b/backends/meson.build
@@ -1,5 +1,6 @@
softmmu_ss.add([files(
'cryptodev-builtin.c',
+ 'cryptodev-hmp-cmds.c',
'cryptodev.c',
'hostmem-ram.c',
'hostmem.c',
diff --git a/hmp-commands-info.hx b/hmp-commands-info.hx
index 754b1e8..47d63d2 100644
--- a/hmp-commands-info.hx
+++ b/hmp-commands-info.hx
@@ -993,3 +993,17 @@ SRST
``info virtio-queue-element`` *path* *queue* [*index*]
Display element of a given virtio queue
ERST
+
+ {
+ .name = "cryptodev",
+ .args_type = "",
+ .params = "",
+ .help = "show the crypto devices",
+ .cmd = hmp_info_cryptodev,
+ .flags = "p",
+ },
+
+SRST
+ ``info cryptodev``
+ Show the crypto devices.
+ERST
diff --git a/hw/acpi/acpi-pci-hotplug-stub.c b/hw/acpi/acpi-pci-hotplug-stub.c
index a43f6da..dcee3ad 100644
--- a/hw/acpi/acpi-pci-hotplug-stub.c
+++ b/hw/acpi/acpi-pci-hotplug-stub.c
@@ -5,8 +5,7 @@
const VMStateDescription vmstate_acpi_pcihp_pci_status;
void acpi_pcihp_init(Object *owner, AcpiPciHpState *s, PCIBus *root_bus,
- MemoryRegion *address_space_io, bool bridges_enabled,
- uint16_t io_base)
+ MemoryRegion *address_space_io, uint16_t io_base)
{
return;
}
@@ -36,8 +35,12 @@ void acpi_pcihp_device_unplug_request_cb(HotplugHandler *hotplug_dev,
return;
}
-void acpi_pcihp_reset(AcpiPciHpState *s, bool acpihp_root_off)
+void acpi_pcihp_reset(AcpiPciHpState *s)
{
return;
}
+bool acpi_pcihp_is_hotpluggbale_bus(AcpiPciHpState *s, BusState *bus)
+{
+ return true;
+}
diff --git a/hw/acpi/ich9.c b/hw/acpi/ich9.c
index d23bfca..25e2c72 100644
--- a/hw/acpi/ich9.c
+++ b/hw/acpi/ich9.c
@@ -218,7 +218,7 @@ static bool vmstate_test_use_pcihp(void *opaque)
{
ICH9LPCPMRegs *s = opaque;
- return s->use_acpi_hotplug_bridge;
+ return s->acpi_pci_hotplug.use_acpi_hotplug_bridge;
}
static const VMStateDescription vmstate_pcihp_state = {
@@ -277,8 +277,8 @@ static void pm_reset(void *opaque)
}
pm->smi_en_wmask = ~0;
- if (pm->use_acpi_hotplug_bridge) {
- acpi_pcihp_reset(&pm->acpi_pci_hotplug, true);
+ if (pm->acpi_pci_hotplug.use_acpi_hotplug_bridge) {
+ acpi_pcihp_reset(&pm->acpi_pci_hotplug);
}
acpi_update_sci(&pm->acpi_regs, pm->irq);
@@ -316,12 +316,11 @@ void ich9_pm_init(PCIDevice *lpc_pci, ICH9LPCPMRegs *pm, qemu_irq sci_irq)
acpi_pm_tco_init(&pm->tco_regs, &pm->io);
}
- if (pm->use_acpi_hotplug_bridge) {
+ if (pm->acpi_pci_hotplug.use_acpi_hotplug_bridge) {
acpi_pcihp_init(OBJECT(lpc_pci),
&pm->acpi_pci_hotplug,
pci_get_bus(lpc_pci),
pci_address_space_io(lpc_pci),
- true,
ACPI_PCIHP_ADDR_ICH9);
qbus_set_hotplug_handler(BUS(pci_get_bus(lpc_pci)),
@@ -403,14 +402,14 @@ static bool ich9_pm_get_acpi_pci_hotplug(Object *obj, Error **errp)
{
ICH9LPCState *s = ICH9_LPC_DEVICE(obj);
- return s->pm.use_acpi_hotplug_bridge;
+ return s->pm.acpi_pci_hotplug.use_acpi_hotplug_bridge;
}
static void ich9_pm_set_acpi_pci_hotplug(Object *obj, bool value, Error **errp)
{
ICH9LPCState *s = ICH9_LPC_DEVICE(obj);
- s->pm.use_acpi_hotplug_bridge = value;
+ s->pm.acpi_pci_hotplug.use_acpi_hotplug_bridge = value;
}
static bool ich9_pm_get_keep_pci_slot_hpc(Object *obj, Error **errp)
@@ -435,7 +434,7 @@ void ich9_pm_add_properties(Object *obj, ICH9LPCPMRegs *pm)
pm->disable_s3 = 0;
pm->disable_s4 = 0;
pm->s4_val = 2;
- pm->use_acpi_hotplug_bridge = true;
+ pm->acpi_pci_hotplug.use_acpi_hotplug_bridge = true;
pm->keep_pci_slot_hpc = true;
pm->enable_tco = true;
@@ -579,6 +578,12 @@ void ich9_pm_device_unplug_cb(HotplugHandler *hotplug_dev, DeviceState *dev,
}
}
+bool ich9_pm_is_hotpluggable_bus(HotplugHandler *hotplug_dev, BusState *bus)
+{
+ ICH9LPCState *lpc = ICH9_LPC_DEVICE(hotplug_dev);
+ return acpi_pcihp_is_hotpluggbale_bus(&lpc->pm.acpi_pci_hotplug, bus);
+}
+
void ich9_pm_ospm_status(AcpiDeviceIf *adev, ACPIOSTInfoList ***list)
{
ICH9LPCState *s = ICH9_LPC_DEVICE(adev);
diff --git a/hw/acpi/pci-bridge.c b/hw/acpi/pci-bridge.c
index 5f3ee51..7baa703 100644
--- a/hw/acpi/pci-bridge.c
+++ b/hw/acpi/pci-bridge.c
@@ -21,7 +21,17 @@ void build_pci_bridge_aml(AcpiDevAmlIf *adev, Aml *scope)
{
PCIBridge *br = PCI_BRIDGE(adev);
- if (object_property_find(OBJECT(&br->sec_bus), ACPI_PCIHP_PROP_BSEL)) {
- build_append_pci_bus_devices(scope, pci_bridge_get_sec_bus(br));
+ if (!DEVICE(br)->hotplugged) {
+ PCIBus *sec_bus = pci_bridge_get_sec_bus(br);
+
+ build_append_pci_bus_devices(scope, sec_bus);
+
+ /*
+ * generate hotplug slots descriptors if
+ * bridge has ACPI PCI hotplug attached,
+ */
+ if (object_property_find(OBJECT(sec_bus), ACPI_PCIHP_PROP_BSEL)) {
+ build_append_pcihp_slots(scope, sec_bus);
+ }
}
}
diff --git a/hw/acpi/pcihp.c b/hw/acpi/pcihp.c
index 5dc7377..dcfb779 100644
--- a/hw/acpi/pcihp.c
+++ b/hw/acpi/pcihp.c
@@ -54,21 +54,6 @@ typedef struct AcpiPciHpFind {
PCIBus *bus;
} AcpiPciHpFind;
-static gint g_cmp_uint32(gconstpointer a, gconstpointer b, gpointer user_data)
-{
- return a - b;
-}
-
-static GSequence *pci_acpi_index_list(void)
-{
- static GSequence *used_acpi_index_list;
-
- if (!used_acpi_index_list) {
- used_acpi_index_list = g_sequence_new(NULL);
- }
- return used_acpi_index_list;
-}
-
static int acpi_pcihp_get_bsel(PCIBus *bus)
{
Error *local_err = NULL;
@@ -136,20 +121,6 @@ static void acpi_set_pci_info(bool has_bridge_hotplug)
}
}
-static void acpi_pcihp_disable_root_bus(void)
-{
- Object *host = acpi_get_i386_pci_host();
- PCIBus *bus;
-
- bus = PCI_HOST_BRIDGE(host)->bus;
- if (bus && qbus_is_hotpluggable(BUS(bus))) {
- /* setting the hotplug handler to NULL makes the bus non-hotpluggable */
- qbus_set_hotplug_handler(BUS(bus), NULL);
- }
-
- return;
-}
-
static void acpi_pcihp_test_hotplug_bus(PCIBus *bus, void *opaque)
{
AcpiPciHpFind *find = opaque;
@@ -291,17 +262,12 @@ static void acpi_pcihp_update(AcpiPciHpState *s)
}
}
-void acpi_pcihp_reset(AcpiPciHpState *s, bool acpihp_root_off)
+void acpi_pcihp_reset(AcpiPciHpState *s)
{
- if (acpihp_root_off) {
- acpi_pcihp_disable_root_bus();
- }
- acpi_set_pci_info(!s->legacy_piix);
+ acpi_set_pci_info(s->use_acpi_hotplug_bridge);
acpi_pcihp_update(s);
}
-#define ONBOARD_INDEX_MAX (16 * 1024 - 1)
-
void acpi_pcihp_device_pre_plug_cb(HotplugHandler *hotplug_dev,
DeviceState *dev, Error **errp)
{
@@ -314,34 +280,6 @@ void acpi_pcihp_device_pre_plug_cb(HotplugHandler *hotplug_dev,
ACPI_PCIHP_PROP_BSEL "' set");
return;
}
-
- /*
- * capped by systemd (see: udev-builtin-net_id.c)
- * as it's the only known user honor it to avoid users
- * misconfigure QEMU and then wonder why acpi-index doesn't work
- */
- if (pdev->acpi_index > ONBOARD_INDEX_MAX) {
- error_setg(errp, "acpi-index should be less or equal to %u",
- ONBOARD_INDEX_MAX);
- return;
- }
-
- /*
- * make sure that acpi-index is unique across all present PCI devices
- */
- if (pdev->acpi_index) {
- GSequence *used_indexes = pci_acpi_index_list();
-
- if (g_sequence_lookup(used_indexes, GINT_TO_POINTER(pdev->acpi_index),
- g_cmp_uint32, NULL)) {
- error_setg(errp, "a PCI device with acpi-index = %" PRIu32
- " already exist", pdev->acpi_index);
- return;
- }
- g_sequence_insert_sorted(used_indexes,
- GINT_TO_POINTER(pdev->acpi_index),
- g_cmp_uint32, NULL);
- }
}
void acpi_pcihp_device_plug_cb(HotplugHandler *hotplug_dev, AcpiPciHpState *s,
@@ -361,17 +299,10 @@ void acpi_pcihp_device_plug_cb(HotplugHandler *hotplug_dev, AcpiPciHpState *s,
* Overwrite the default hotplug handler with the ACPI PCI one
* for cold plugged bridges only.
*/
- if (!s->legacy_piix &&
+ if (s->use_acpi_hotplug_bridge &&
object_dynamic_cast(OBJECT(dev), TYPE_PCI_BRIDGE)) {
PCIBus *sec = pci_bridge_get_sec_bus(PCI_BRIDGE(pdev));
- /* Remove all hot-plug handlers if hot-plug is disabled on slot */
- if (object_dynamic_cast(OBJECT(dev), TYPE_PCIE_SLOT) &&
- !PCIE_SLOT(pdev)->hotplug) {
- qbus_set_hotplug_handler(BUS(sec), NULL);
- return;
- }
-
qbus_set_hotplug_handler(BUS(sec), OBJECT(hotplug_dev));
/* We don't have to overwrite any other hotplug handler yet */
assert(QLIST_EMPTY(&sec->child));
@@ -401,17 +332,6 @@ void acpi_pcihp_device_unplug_cb(HotplugHandler *hotplug_dev, AcpiPciHpState *s,
trace_acpi_pci_unplug(PCI_SLOT(pdev->devfn),
acpi_pcihp_get_bsel(pci_get_bus(pdev)));
- /*
- * clean up acpi-index so it could reused by another device
- */
- if (pdev->acpi_index) {
- GSequence *used_indexes = pci_acpi_index_list();
-
- g_sequence_remove(g_sequence_lookup(used_indexes,
- GINT_TO_POINTER(pdev->acpi_index),
- g_cmp_uint32, NULL));
- }
-
qdev_unrealize(dev);
}
@@ -441,6 +361,24 @@ void acpi_pcihp_device_unplug_request_cb(HotplugHandler *hotplug_dev,
acpi_send_event(DEVICE(hotplug_dev), ACPI_PCI_HOTPLUG_STATUS);
}
+bool acpi_pcihp_is_hotpluggbale_bus(AcpiPciHpState *s, BusState *bus)
+{
+ Object *o = OBJECT(bus->parent);
+
+ if (s->use_acpi_hotplug_bridge &&
+ object_dynamic_cast(o, TYPE_PCI_BRIDGE)) {
+ if (object_dynamic_cast(o, TYPE_PCIE_SLOT) && !PCIE_SLOT(o)->hotplug) {
+ return false;
+ }
+ return true;
+ }
+
+ if (s->use_acpi_root_pci_hotplug) {
+ return true;
+ }
+ return false;
+}
+
static uint64_t pci_read(void *opaque, hwaddr addr, unsigned int size)
{
AcpiPciHpState *s = opaque;
@@ -454,7 +392,7 @@ static uint64_t pci_read(void *opaque, hwaddr addr, unsigned int size)
switch (addr) {
case PCI_UP_BASE:
val = s->acpi_pcihp_pci_status[bsel].up;
- if (!s->legacy_piix) {
+ if (s->use_acpi_hotplug_bridge) {
s->acpi_pcihp_pci_status[bsel].up = 0;
}
trace_acpi_pci_up_read(val);
@@ -529,7 +467,8 @@ static void pci_write(void *opaque, hwaddr addr, uint64_t data,
trace_acpi_pci_ej_write(addr, data);
break;
case PCI_SEL_BASE:
- s->hotplug_select = s->legacy_piix ? ACPI_PCIHP_BSEL_DEFAULT : data;
+ s->hotplug_select = s->use_acpi_hotplug_bridge ? data :
+ ACPI_PCIHP_BSEL_DEFAULT;
trace_acpi_pci_sel_write(addr, data);
default:
break;
@@ -547,14 +486,13 @@ static const MemoryRegionOps acpi_pcihp_io_ops = {
};
void acpi_pcihp_init(Object *owner, AcpiPciHpState *s, PCIBus *root_bus,
- MemoryRegion *address_space_io, bool bridges_enabled,
+ MemoryRegion *address_space_io,
uint16_t io_base)
{
s->io_len = ACPI_PCIHP_SIZE;
s->io_base = io_base;
s->root = root_bus;
- s->legacy_piix = !bridges_enabled;
memory_region_init_io(&s->io, owner, &acpi_pcihp_io_ops, s,
"acpi-pci-hotplug", s->io_len);
diff --git a/hw/acpi/piix4.c b/hw/acpi/piix4.c
index eac2125..63d2113 100644
--- a/hw/acpi/piix4.c
+++ b/hw/acpi/piix4.c
@@ -170,14 +170,14 @@ static const VMStateDescription vmstate_pci_status = {
static bool vmstate_test_use_acpi_hotplug_bridge(void *opaque, int version_id)
{
PIIX4PMState *s = opaque;
- return s->use_acpi_hotplug_bridge;
+ return s->acpi_pci_hotplug.use_acpi_hotplug_bridge;
}
static bool vmstate_test_no_use_acpi_hotplug_bridge(void *opaque,
int version_id)
{
PIIX4PMState *s = opaque;
- return !s->use_acpi_hotplug_bridge;
+ return !s->acpi_pci_hotplug.use_acpi_hotplug_bridge;
}
static bool vmstate_test_use_memhp(void *opaque)
@@ -234,7 +234,8 @@ static bool piix4_vmstate_need_smbus(void *opaque, int version_id)
static bool vmstate_test_migrate_acpi_index(void *opaque, int version_id)
{
PIIX4PMState *s = PIIX4_PM(opaque);
- return s->use_acpi_hotplug_bridge && !s->not_migrate_acpi_index;
+ return s->acpi_pci_hotplug.use_acpi_hotplug_bridge &&
+ !s->not_migrate_acpi_index;
}
/* qemu-kvm 1.2 uses version 3 but advertised as 2
@@ -303,8 +304,9 @@ static void piix4_pm_reset(DeviceState *dev)
acpi_update_sci(&s->ar, s->irq);
pm_io_space_update(s);
- if (s->use_acpi_hotplug_bridge || s->use_acpi_root_pci_hotplug) {
- acpi_pcihp_reset(&s->acpi_pci_hotplug, !s->use_acpi_root_pci_hotplug);
+ if (s->acpi_pci_hotplug.use_acpi_hotplug_bridge ||
+ s->acpi_pci_hotplug.use_acpi_root_pci_hotplug) {
+ acpi_pcihp_reset(&s->acpi_pci_hotplug);
}
}
@@ -402,6 +404,13 @@ static void piix4_device_unplug_cb(HotplugHandler *hotplug_dev,
}
}
+static bool piix4_is_hotpluggable_bus(HotplugHandler *hotplug_dev,
+ BusState *bus)
+{
+ PIIX4PMState *s = PIIX4_PM(hotplug_dev);
+ return acpi_pcihp_is_hotpluggbale_bus(&s->acpi_pci_hotplug, bus);
+}
+
static void piix4_pm_machine_ready(Notifier *n, void *opaque)
{
PIIX4PMState *s = container_of(n, PIIX4PMState, machine_ready);
@@ -487,12 +496,11 @@ static void piix4_pm_realize(PCIDevice *dev, Error **errp)
qemu_add_machine_init_done_notifier(&s->machine_ready);
if (xen_enabled()) {
- s->use_acpi_hotplug_bridge = false;
+ s->acpi_pci_hotplug.use_acpi_hotplug_bridge = false;
}
piix4_acpi_system_hot_add_init(pci_address_space_io(dev),
pci_get_bus(dev), s);
- qbus_set_hotplug_handler(BUS(pci_get_bus(dev)), OBJECT(s));
piix4_pm_add_properties(s);
}
@@ -561,9 +569,11 @@ static void piix4_acpi_system_hot_add_init(MemoryRegion *parent,
"acpi-gpe0", GPE_LEN);
memory_region_add_subregion(parent, GPE_BASE, &s->io_gpe);
- if (s->use_acpi_hotplug_bridge || s->use_acpi_root_pci_hotplug) {
+ if (s->acpi_pci_hotplug.use_acpi_hotplug_bridge ||
+ s->acpi_pci_hotplug.use_acpi_root_pci_hotplug) {
acpi_pcihp_init(OBJECT(s), &s->acpi_pci_hotplug, bus, parent,
- s->use_acpi_hotplug_bridge, ACPI_PCIHP_ADDR_PIIX4);
+ ACPI_PCIHP_ADDR_PIIX4);
+ qbus_set_hotplug_handler(BUS(pci_get_bus(PCI_DEVICE(s))), OBJECT(s));
}
s->cpu_hotplug_legacy = true;
@@ -602,9 +612,9 @@ static Property piix4_pm_properties[] = {
DEFINE_PROP_UINT8(ACPI_PM_PROP_S4_DISABLED, PIIX4PMState, disable_s4, 0),
DEFINE_PROP_UINT8(ACPI_PM_PROP_S4_VAL, PIIX4PMState, s4_val, 2),
DEFINE_PROP_BOOL(ACPI_PM_PROP_ACPI_PCIHP_BRIDGE, PIIX4PMState,
- use_acpi_hotplug_bridge, true),
+ acpi_pci_hotplug.use_acpi_hotplug_bridge, true),
DEFINE_PROP_BOOL(ACPI_PM_PROP_ACPI_PCI_ROOTHP, PIIX4PMState,
- use_acpi_root_pci_hotplug, true),
+ acpi_pci_hotplug.use_acpi_root_pci_hotplug, true),
DEFINE_PROP_BOOL("memory-hotplug-support", PIIX4PMState,
acpi_memory_hotplug.is_enabled, true),
DEFINE_PROP_BOOL("smm-compat", PIIX4PMState, smm_compat, false),
@@ -641,6 +651,7 @@ static void piix4_pm_class_init(ObjectClass *klass, void *data)
hc->plug = piix4_device_plug_cb;
hc->unplug_request = piix4_device_unplug_request_cb;
hc->unplug = piix4_device_unplug_cb;
+ hc->is_hotpluggable_bus = piix4_is_hotpluggable_bus;
adevc->ospm_status = piix4_ospm_status;
adevc->send_event = piix4_send_gpe;
adevc->madt_cpu = pc_madt_cpu_entry;
diff --git a/hw/cxl/cxl-component-utils.c b/hw/cxl/cxl-component-utils.c
index 3edd303..b665d4f 100644
--- a/hw/cxl/cxl-component-utils.c
+++ b/hw/cxl/cxl-component-utils.c
@@ -141,17 +141,19 @@ static void ras_init_common(uint32_t *reg_state, uint32_t *write_msk)
* Error status is RW1C but given bits are not yet set, it can
* be handled as RO.
*/
- reg_state[R_CXL_RAS_UNC_ERR_STATUS] = 0;
+ stl_le_p(reg_state + R_CXL_RAS_UNC_ERR_STATUS, 0);
+ stl_le_p(write_msk + R_CXL_RAS_UNC_ERR_STATUS, 0x1cfff);
/* Bits 12-13 and 17-31 reserved in CXL 2.0 */
- reg_state[R_CXL_RAS_UNC_ERR_MASK] = 0x1cfff;
- write_msk[R_CXL_RAS_UNC_ERR_MASK] = 0x1cfff;
- reg_state[R_CXL_RAS_UNC_ERR_SEVERITY] = 0x1cfff;
- write_msk[R_CXL_RAS_UNC_ERR_SEVERITY] = 0x1cfff;
- reg_state[R_CXL_RAS_COR_ERR_STATUS] = 0;
- reg_state[R_CXL_RAS_COR_ERR_MASK] = 0x7f;
- write_msk[R_CXL_RAS_COR_ERR_MASK] = 0x7f;
+ stl_le_p(reg_state + R_CXL_RAS_UNC_ERR_MASK, 0x1cfff);
+ stl_le_p(write_msk + R_CXL_RAS_UNC_ERR_MASK, 0x1cfff);
+ stl_le_p(reg_state + R_CXL_RAS_UNC_ERR_SEVERITY, 0x1cfff);
+ stl_le_p(write_msk + R_CXL_RAS_UNC_ERR_SEVERITY, 0x1cfff);
+ stl_le_p(reg_state + R_CXL_RAS_COR_ERR_STATUS, 0);
+ stl_le_p(write_msk + R_CXL_RAS_COR_ERR_STATUS, 0x7f);
+ stl_le_p(reg_state + R_CXL_RAS_COR_ERR_MASK, 0x7f);
+ stl_le_p(write_msk + R_CXL_RAS_COR_ERR_MASK, 0x7f);
/* CXL switches and devices must set */
- reg_state[R_CXL_RAS_ERR_CAP_CTRL] = 0x00;
+ stl_le_p(reg_state + R_CXL_RAS_ERR_CAP_CTRL, 0x200);
}
static void hdm_init_common(uint32_t *reg_state, uint32_t *write_msk,
diff --git a/hw/cxl/cxl-host.c b/hw/cxl/cxl-host.c
index 3c1ec87..6e923ce 100644
--- a/hw/cxl/cxl-host.c
+++ b/hw/cxl/cxl-host.c
@@ -146,21 +146,28 @@ static PCIDevice *cxl_cfmws_find_device(CXLFixedWindow *fw, hwaddr addr)
return NULL;
}
- hb_cstate = cxl_get_hb_cstate(hb);
- if (!hb_cstate) {
- return NULL;
- }
+ if (cxl_get_hb_passthrough(hb)) {
+ rp = pcie_find_port_first(hb->bus);
+ if (!rp) {
+ return NULL;
+ }
+ } else {
+ hb_cstate = cxl_get_hb_cstate(hb);
+ if (!hb_cstate) {
+ return NULL;
+ }
- cache_mem = hb_cstate->crb.cache_mem_registers;
+ cache_mem = hb_cstate->crb.cache_mem_registers;
- target_found = cxl_hdm_find_target(cache_mem, addr, &target);
- if (!target_found) {
- return NULL;
- }
+ target_found = cxl_hdm_find_target(cache_mem, addr, &target);
+ if (!target_found) {
+ return NULL;
+ }
- rp = pcie_find_port_by_pn(hb->bus, target);
- if (!rp) {
- return NULL;
+ rp = pcie_find_port_by_pn(hb->bus, target);
+ if (!rp) {
+ return NULL;
+ }
}
d = pci_bridge_get_sec_bus(PCI_BRIDGE(rp))->devices[0];
diff --git a/hw/i386/acpi-build.c b/hw/i386/acpi-build.c
index b19fb42..ec857a1 100644
--- a/hw/i386/acpi-build.c
+++ b/hw/i386/acpi-build.c
@@ -373,6 +373,104 @@ Aml *aml_pci_device_dsm(void)
return method;
}
+static void build_append_pci_dsm_func0_common(Aml *ctx, Aml *retvar)
+{
+ Aml *UUID, *ifctx1;
+ uint8_t byte_list[1] = { 0 }; /* nothing supported yet */
+
+ aml_append(ctx, aml_store(aml_buffer(1, byte_list), retvar));
+ /*
+ * 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(retvar));
+ }
+ aml_append(ctx, ifctx1);
+
+ ifctx1 = aml_if(aml_lless(aml_arg(1), aml_int(2)));
+ {
+ /* call is for unsupported REV, bail out */
+ aml_append(ifctx1, aml_return(retvar));
+ }
+ aml_append(ctx, ifctx1);
+}
+
+static Aml *aml_pci_edsm(void)
+{
+ Aml *method, *ifctx;
+ Aml *zero = aml_int(0);
+ Aml *func = aml_arg(2);
+ Aml *ret = aml_local(0);
+ Aml *aidx = aml_local(1);
+ Aml *params = aml_arg(4);
+
+ method = aml_method("EDSM", 5, AML_SERIALIZED);
+
+ /* get supported functions */
+ ifctx = aml_if(aml_equal(func, zero));
+ {
+ /* 1: have supported functions */
+ /* 7: support for function 7 */
+ const uint8_t caps = 1 | BIT(7);
+ build_append_pci_dsm_func0_common(ifctx, ret);
+ aml_append(ifctx, aml_store(aml_int(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.7. _DSM for Naming a PCI or PCI Express Device Under
+ * Operating Systems
+ */
+ ifctx = aml_if(aml_equal(func, aml_int(7)));
+ {
+ Aml *pkg = aml_package(2);
+ 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));
+
+ /*
+ * IASL is fine when initializing Package with computational data,
+ * however it makes guest unhappy /it fails to process such AML/.
+ * So use runtime assignment to set acpi-index after initializer
+ * to make OSPM happy.
+ */
+ aml_append(ifctx,
+ aml_store(aml_derefof(aml_index(params, aml_int(0))), aidx));
+ aml_append(ifctx, aml_store(aidx, aml_index(ret, zero)));
+ aml_append(ifctx, aml_return(ret));
+ }
+ aml_append(method, ifctx);
+
+ return method;
+}
+
+static Aml *aml_pci_static_endpoint_dsm(PCIDevice *pdev)
+{
+ Aml *method;
+
+ g_assert(pdev->acpi_index != 0);
+ method = aml_method("_DSM", 4, AML_SERIALIZED);
+ {
+ Aml *params = aml_local(0);
+ Aml *pkg = aml_package(1);
+ aml_append(pkg, aml_int(pdev->acpi_index));
+ aml_append(method, aml_store(pkg, params));
+ aml_append(method,
+ aml_return(aml_call5("EDSM", 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;
@@ -396,12 +494,6 @@ static bool is_devfn_ignored_generic(const int devfn, const PCIBus *bus)
if (DEVICE(pdev)->hotplugged) {
return true;
}
- } else if (!get_dev_aml_func(DEVICE(pdev))) {
- /*
- * Ignore all other devices on !0 functions unless they
- * have AML description (i.e have get_dev_aml_func() != 0)
- */
- return true;
}
}
return false;
@@ -428,12 +520,14 @@ static bool is_devfn_ignored_hotplug(const int devfn, const PCIBus *bus)
return false;
}
-static void build_append_pcihp_slots(Aml *parent_scope, PCIBus *bus,
- QObject *bsel)
+void build_append_pcihp_slots(Aml *parent_scope, PCIBus *bus)
{
int devfn;
Aml *dev, *notify_method = NULL, *method;
+ QObject *bsel = object_property_get_qobject(OBJECT(bus),
+ ACPI_PCIHP_PROP_BSEL, NULL);
uint64_t bsel_val = qnum_get_uint(qobject_to(QNum, bsel));
+ qobject_unref(bsel);
aml_append(parent_scope, aml_name_decl("BSEL", aml_int(bsel_val)));
notify_method = aml_method("DVNT", 2, AML_NOTSERIALIZED);
@@ -478,12 +572,9 @@ static void build_append_pcihp_slots(Aml *parent_scope, PCIBus *bus,
void build_append_pci_bus_devices(Aml *parent_scope, PCIBus *bus)
{
- QObject *bsel;
int devfn;
Aml *dev;
- bsel = object_property_get_qobject(OBJECT(bus), ACPI_PCIHP_PROP_BSEL, NULL);
-
for (devfn = 0; devfn < ARRAY_SIZE(bus->devices); devfn++) {
/* ACPI spec: 1.0b: Table 6-2 _ADR Object Bus Types, PCI type */
int adr = PCI_SLOT(devfn) << 16 | PCI_FUNC(devfn);
@@ -498,16 +589,16 @@ void build_append_pci_bus_devices(Aml *parent_scope, PCIBus *bus)
aml_append(dev, aml_name_decl("_ADR", aml_int(adr)));
call_dev_aml_func(DEVICE(bus->devices[devfn]), dev);
+ /* add _DSM if device has acpi-index set */
+ if (pdev->acpi_index &&
+ !object_property_get_bool(OBJECT(pdev), "hotpluggable",
+ &error_abort)) {
+ aml_append(dev, aml_pci_static_endpoint_dsm(pdev));
+ }
/* device descriptor has been composed, add it into parent context */
aml_append(parent_scope, dev);
}
-
- if (bsel) {
- build_append_pcihp_slots(parent_scope, bus, bsel);
- }
-
- qobject_unref(bsel);
}
static bool build_append_notfication_callback(Aml *parent_scope,
@@ -517,16 +608,24 @@ static bool build_append_notfication_callback(Aml *parent_scope,
PCIBus *sec;
QObject *bsel;
int nr_notifiers = 0;
+ GQueue *pcnt_bus_list = g_queue_new();
QLIST_FOREACH(sec, &bus->child, sibling) {
Aml *br_scope = aml_scope("S%.02X", sec->parent_dev->devfn);
- if (pci_bus_is_root(sec) ||
- !object_property_find(OBJECT(sec), ACPI_PCIHP_PROP_BSEL)) {
+ if (pci_bus_is_root(sec)) {
continue;
}
nr_notifiers = nr_notifiers +
build_append_notfication_callback(br_scope, sec);
- aml_append(parent_scope, br_scope);
+ /*
+ * add new child scope to parent
+ * and keep track of bus that have PCNT,
+ * bus list is used later to call children PCNTs from this level PCNT
+ */
+ if (nr_notifiers) {
+ g_queue_push_tail(pcnt_bus_list, sec);
+ aml_append(parent_scope, br_scope);
+ }
}
/*
@@ -550,30 +649,25 @@ static bool build_append_notfication_callback(Aml *parent_scope,
}
/* Notify about child bus events in any case */
- QLIST_FOREACH(sec, &bus->child, sibling) {
- if (pci_bus_is_root(sec) ||
- !object_property_find(OBJECT(sec), ACPI_PCIHP_PROP_BSEL)) {
- continue;
- }
-
+ while ((sec = g_queue_pop_head(pcnt_bus_list))) {
aml_append(method, aml_name("^S%.02X.PCNT", sec->parent_dev->devfn));
}
aml_append(parent_scope, method);
qobject_unref(bsel);
+ g_queue_free(pcnt_bus_list);
return !!nr_notifiers;
}
static Aml *aml_pci_pdsm(void)
{
- Aml *method, *UUID, *ifctx, *ifctx1;
+ Aml *method, *ifctx, *ifctx1;
Aml *ret = aml_local(0);
Aml *caps = aml_local(1);
Aml *acpi_index = aml_local(2);
Aml *zero = aml_int(0);
Aml *one = aml_int(1);
Aml *func = aml_arg(2);
- Aml *rev = aml_arg(1);
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)));
@@ -583,29 +677,9 @@ static Aml *aml_pci_pdsm(void)
/* 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);
+ build_append_pci_dsm_func0_common(ifctx, ret);
+ aml_append(ifctx, aml_store(zero, caps));
aml_append(ifctx,
aml_store(aml_call2("AIDX", bnum, sunum), acpi_index));
/*
@@ -1388,6 +1462,7 @@ build_dsdt(GArray *table_data, BIOSLinker *linker,
aml_append(dev, aml_name_decl("_HID", aml_eisaid("PNP0A03")));
aml_append(dev, aml_name_decl("_ADR", aml_int(0)));
aml_append(dev, aml_name_decl("_UID", aml_int(pcmc->pci_root_uid)));
+ aml_append(dev, aml_pci_edsm());
aml_append(sb_scope, dev);
aml_append(dsdt, sb_scope);
@@ -1403,6 +1478,7 @@ build_dsdt(GArray *table_data, BIOSLinker *linker,
aml_append(dev, aml_name_decl("_ADR", aml_int(0)));
aml_append(dev, aml_name_decl("_UID", aml_int(pcmc->pci_root_uid)));
aml_append(dev, build_q35_osc_method(!pm->pcihp_bridge_en));
+ aml_append(dev, aml_pci_edsm());
aml_append(sb_scope, dev);
if (mcfg_valid) {
aml_append(sb_scope, build_q35_dram_controller(&mcfg));
@@ -1710,6 +1786,9 @@ build_dsdt(GArray *table_data, BIOSLinker *linker,
Aml *scope = aml_scope("PCI0");
/* Scan all PCI buses. Generate tables to support hotplug. */
build_append_pci_bus_devices(scope, bus);
+ if (object_property_find(OBJECT(bus), ACPI_PCIHP_PROP_BSEL)) {
+ build_append_pcihp_slots(scope, bus);
+ }
aml_append(sb_scope, scope);
}
}
diff --git a/hw/isa/lpc_ich9.c b/hw/isa/lpc_ich9.c
index d8303d0..9714b00 100644
--- a/hw/isa/lpc_ich9.c
+++ b/hw/isa/lpc_ich9.c
@@ -865,6 +865,7 @@ static void ich9_lpc_class_init(ObjectClass *klass, void *data)
hc->plug = ich9_pm_device_plug_cb;
hc->unplug_request = ich9_pm_device_unplug_request_cb;
hc->unplug = ich9_pm_device_unplug_cb;
+ hc->is_hotpluggable_bus = ich9_pm_is_hotpluggable_bus;
adevc->ospm_status = ich9_pm_ospm_status;
adevc->send_event = ich9_send_gpe;
adevc->madt_cpu = pc_madt_cpu_entry;
diff --git a/hw/mem/cxl_type3.c b/hw/mem/cxl_type3.c
index 217a5e6..abe60b3 100644
--- a/hw/mem/cxl_type3.c
+++ b/hw/mem/cxl_type3.c
@@ -1,6 +1,7 @@
#include "qemu/osdep.h"
#include "qemu/units.h"
#include "qemu/error-report.h"
+#include "qapi/qapi-commands-cxl.h"
#include "hw/mem/memory-device.h"
#include "hw/mem/pc-dimm.h"
#include "hw/pci/pci.h"
@@ -250,6 +251,7 @@ static void ct3d_config_write(PCIDevice *pci_dev, uint32_t addr, uint32_t val,
pcie_doe_write_config(&ct3d->doe_cdat, addr, val, size);
pci_default_write_config(pci_dev, addr, val, size);
+ pcie_aer_write_config(pci_dev, addr, val, size);
}
/*
@@ -322,6 +324,66 @@ static void hdm_decoder_commit(CXLType3Dev *ct3d, int which)
ARRAY_FIELD_DP32(cache_mem, CXL_HDM_DECODER0_CTRL, COMMITTED, 1);
}
+static int ct3d_qmp_uncor_err_to_cxl(CxlUncorErrorType qmp_err)
+{
+ switch (qmp_err) {
+ case CXL_UNCOR_ERROR_TYPE_CACHE_DATA_PARITY:
+ return CXL_RAS_UNC_ERR_CACHE_DATA_PARITY;
+ case CXL_UNCOR_ERROR_TYPE_CACHE_ADDRESS_PARITY:
+ return CXL_RAS_UNC_ERR_CACHE_ADDRESS_PARITY;
+ case CXL_UNCOR_ERROR_TYPE_CACHE_BE_PARITY:
+ return CXL_RAS_UNC_ERR_CACHE_BE_PARITY;
+ case CXL_UNCOR_ERROR_TYPE_CACHE_DATA_ECC:
+ return CXL_RAS_UNC_ERR_CACHE_DATA_ECC;
+ case CXL_UNCOR_ERROR_TYPE_MEM_DATA_PARITY:
+ return CXL_RAS_UNC_ERR_MEM_DATA_PARITY;
+ case CXL_UNCOR_ERROR_TYPE_MEM_ADDRESS_PARITY:
+ return CXL_RAS_UNC_ERR_MEM_ADDRESS_PARITY;
+ case CXL_UNCOR_ERROR_TYPE_MEM_BE_PARITY:
+ return CXL_RAS_UNC_ERR_MEM_BE_PARITY;
+ case CXL_UNCOR_ERROR_TYPE_MEM_DATA_ECC:
+ return CXL_RAS_UNC_ERR_MEM_DATA_ECC;
+ case CXL_UNCOR_ERROR_TYPE_REINIT_THRESHOLD:
+ return CXL_RAS_UNC_ERR_REINIT_THRESHOLD;
+ case CXL_UNCOR_ERROR_TYPE_RSVD_ENCODING:
+ return CXL_RAS_UNC_ERR_RSVD_ENCODING;
+ case CXL_UNCOR_ERROR_TYPE_POISON_RECEIVED:
+ return CXL_RAS_UNC_ERR_POISON_RECEIVED;
+ case CXL_UNCOR_ERROR_TYPE_RECEIVER_OVERFLOW:
+ return CXL_RAS_UNC_ERR_RECEIVER_OVERFLOW;
+ case CXL_UNCOR_ERROR_TYPE_INTERNAL:
+ return CXL_RAS_UNC_ERR_INTERNAL;
+ case CXL_UNCOR_ERROR_TYPE_CXL_IDE_TX:
+ return CXL_RAS_UNC_ERR_CXL_IDE_TX;
+ case CXL_UNCOR_ERROR_TYPE_CXL_IDE_RX:
+ return CXL_RAS_UNC_ERR_CXL_IDE_RX;
+ default:
+ return -EINVAL;
+ }
+}
+
+static int ct3d_qmp_cor_err_to_cxl(CxlCorErrorType qmp_err)
+{
+ switch (qmp_err) {
+ case CXL_COR_ERROR_TYPE_CACHE_DATA_ECC:
+ return CXL_RAS_COR_ERR_CACHE_DATA_ECC;
+ case CXL_COR_ERROR_TYPE_MEM_DATA_ECC:
+ return CXL_RAS_COR_ERR_MEM_DATA_ECC;
+ case CXL_COR_ERROR_TYPE_CRC_THRESHOLD:
+ return CXL_RAS_COR_ERR_CRC_THRESHOLD;
+ case CXL_COR_ERROR_TYPE_RETRY_THRESHOLD:
+ return CXL_RAS_COR_ERR_RETRY_THRESHOLD;
+ case CXL_COR_ERROR_TYPE_CACHE_POISON_RECEIVED:
+ return CXL_RAS_COR_ERR_CACHE_POISON_RECEIVED;
+ case CXL_COR_ERROR_TYPE_MEM_POISON_RECEIVED:
+ return CXL_RAS_COR_ERR_MEM_POISON_RECEIVED;
+ case CXL_COR_ERROR_TYPE_PHYSICAL:
+ return CXL_RAS_COR_ERR_PHYSICAL;
+ default:
+ return -EINVAL;
+ }
+}
+
static void ct3d_reg_write(void *opaque, hwaddr offset, uint64_t value,
unsigned size)
{
@@ -340,6 +402,83 @@ static void ct3d_reg_write(void *opaque, hwaddr offset, uint64_t value,
should_commit = FIELD_EX32(value, CXL_HDM_DECODER0_CTRL, COMMIT);
which_hdm = 0;
break;
+ case A_CXL_RAS_UNC_ERR_STATUS:
+ {
+ uint32_t capctrl = ldl_le_p(cache_mem + R_CXL_RAS_ERR_CAP_CTRL);
+ uint32_t fe = FIELD_EX32(capctrl, CXL_RAS_ERR_CAP_CTRL, FIRST_ERROR_POINTER);
+ CXLError *cxl_err;
+ uint32_t unc_err;
+
+ /*
+ * If single bit written that corresponds to the first error
+ * pointer being cleared, update the status and header log.
+ */
+ if (!QTAILQ_EMPTY(&ct3d->error_list)) {
+ if ((1 << fe) ^ value) {
+ CXLError *cxl_next;
+ /*
+ * Software is using wrong flow for multiple header recording
+ * Following behavior in PCIe r6.0 and assuming multiple
+ * header support. Implementation defined choice to clear all
+ * matching records if more than one bit set - which corresponds
+ * closest to behavior of hardware not capable of multiple
+ * header recording.
+ */
+ QTAILQ_FOREACH_SAFE(cxl_err, &ct3d->error_list, node, cxl_next) {
+ if ((1 << cxl_err->type) & value) {
+ QTAILQ_REMOVE(&ct3d->error_list, cxl_err, node);
+ g_free(cxl_err);
+ }
+ }
+ } else {
+ /* Done with previous FE, so drop from list */
+ cxl_err = QTAILQ_FIRST(&ct3d->error_list);
+ QTAILQ_REMOVE(&ct3d->error_list, cxl_err, node);
+ g_free(cxl_err);
+ }
+
+ /*
+ * If there is another FE, then put that in place and update
+ * the header log
+ */
+ if (!QTAILQ_EMPTY(&ct3d->error_list)) {
+ uint32_t *header_log = &cache_mem[R_CXL_RAS_ERR_HEADER0];
+ int i;
+
+ cxl_err = QTAILQ_FIRST(&ct3d->error_list);
+ for (i = 0; i < CXL_RAS_ERR_HEADER_NUM; i++) {
+ stl_le_p(header_log + i, cxl_err->header[i]);
+ }
+ capctrl = FIELD_DP32(capctrl, CXL_RAS_ERR_CAP_CTRL,
+ FIRST_ERROR_POINTER, cxl_err->type);
+ } else {
+ /*
+ * If no more errors, then follow recomendation of PCI spec
+ * r6.0 6.2.4.2 to set the first error pointer to a status
+ * bit that will never be used.
+ */
+ capctrl = FIELD_DP32(capctrl, CXL_RAS_ERR_CAP_CTRL,
+ FIRST_ERROR_POINTER,
+ CXL_RAS_UNC_ERR_CXL_UNUSED);
+ }
+ stl_le_p((uint8_t *)cache_mem + A_CXL_RAS_ERR_CAP_CTRL, capctrl);
+ }
+ unc_err = 0;
+ QTAILQ_FOREACH(cxl_err, &ct3d->error_list, node) {
+ unc_err |= 1 << cxl_err->type;
+ }
+ stl_le_p((uint8_t *)cache_mem + offset, unc_err);
+
+ return;
+ }
+ case A_CXL_RAS_COR_ERR_STATUS:
+ {
+ uint32_t rw1c = value;
+ uint32_t temp = ldl_le_p((uint8_t *)cache_mem + offset);
+ temp &= ~rw1c;
+ stl_le_p((uint8_t *)cache_mem + offset, temp);
+ return;
+ }
default:
break;
}
@@ -403,6 +542,8 @@ static void ct3_realize(PCIDevice *pci_dev, Error **errp)
unsigned short msix_num = 1;
int i, rc;
+ QTAILQ_INIT(&ct3d->error_list);
+
if (!cxl_setup_memory(ct3d, errp)) {
return;
}
@@ -452,8 +593,19 @@ static void ct3_realize(PCIDevice *pci_dev, Error **errp)
cxl_cstate->cdat.free_cdat_table = ct3_free_cdat_table;
cxl_cstate->cdat.private = ct3d;
cxl_doe_cdat_init(cxl_cstate, errp);
+
+ pcie_cap_deverr_init(pci_dev);
+ /* Leave a bit of room for expansion */
+ rc = pcie_aer_init(pci_dev, PCI_ERR_VER, 0x200, PCI_ERR_SIZEOF, NULL);
+ if (rc) {
+ goto err_release_cdat;
+ }
+
return;
+err_release_cdat:
+ cxl_doe_cdat_release(cxl_cstate);
+ g_free(regs->special_ops);
err_address_space_free:
address_space_destroy(&ct3d->hostmem_as);
return;
@@ -465,6 +617,7 @@ static void ct3_exit(PCIDevice *pci_dev)
CXLComponentState *cxl_cstate = &ct3d->cxl_cstate;
ComponentRegisters *regs = &cxl_cstate->crb;
+ pcie_aer_exit(pci_dev);
cxl_doe_cdat_release(cxl_cstate);
g_free(regs->special_ops);
address_space_destroy(&ct3d->hostmem_as);
@@ -618,6 +771,147 @@ static void set_lsa(CXLType3Dev *ct3d, const void *buf, uint64_t size,
*/
}
+/* For uncorrectable errors include support for multiple header recording */
+void qmp_cxl_inject_uncorrectable_errors(const char *path,
+ CXLUncorErrorRecordList *errors,
+ Error **errp)
+{
+ Object *obj = object_resolve_path(path, NULL);
+ static PCIEAERErr err = {};
+ CXLType3Dev *ct3d;
+ CXLError *cxl_err;
+ uint32_t *reg_state;
+ uint32_t unc_err;
+ bool first;
+
+ if (!obj) {
+ error_setg(errp, "Unable to resolve path");
+ return;
+ }
+
+ if (!object_dynamic_cast(obj, TYPE_CXL_TYPE3)) {
+ error_setg(errp, "Path does not point to a CXL type 3 device");
+ return;
+ }
+
+ err.status = PCI_ERR_UNC_INTN;
+ err.source_id = pci_requester_id(PCI_DEVICE(obj));
+ err.flags = 0;
+
+ ct3d = CXL_TYPE3(obj);
+
+ first = QTAILQ_EMPTY(&ct3d->error_list);
+ reg_state = ct3d->cxl_cstate.crb.cache_mem_registers;
+ while (errors) {
+ uint32List *header = errors->value->header;
+ uint8_t header_count = 0;
+ int cxl_err_code;
+
+ cxl_err_code = ct3d_qmp_uncor_err_to_cxl(errors->value->type);
+ if (cxl_err_code < 0) {
+ error_setg(errp, "Unknown error code");
+ return;
+ }
+
+ /* If the error is masked, nothing to do here */
+ if (!((1 << cxl_err_code) &
+ ~ldl_le_p(reg_state + R_CXL_RAS_UNC_ERR_MASK))) {
+ errors = errors->next;
+ continue;
+ }
+
+ cxl_err = g_malloc0(sizeof(*cxl_err));
+ if (!cxl_err) {
+ return;
+ }
+
+ cxl_err->type = cxl_err_code;
+ while (header && header_count < 32) {
+ cxl_err->header[header_count++] = header->value;
+ header = header->next;
+ }
+ if (header_count > 32) {
+ error_setg(errp, "Header must be 32 DWORD or less");
+ return;
+ }
+ QTAILQ_INSERT_TAIL(&ct3d->error_list, cxl_err, node);
+
+ errors = errors->next;
+ }
+
+ if (first && !QTAILQ_EMPTY(&ct3d->error_list)) {
+ uint32_t *cache_mem = ct3d->cxl_cstate.crb.cache_mem_registers;
+ uint32_t capctrl = ldl_le_p(cache_mem + R_CXL_RAS_ERR_CAP_CTRL);
+ uint32_t *header_log = &cache_mem[R_CXL_RAS_ERR_HEADER0];
+ int i;
+
+ cxl_err = QTAILQ_FIRST(&ct3d->error_list);
+ for (i = 0; i < CXL_RAS_ERR_HEADER_NUM; i++) {
+ stl_le_p(header_log + i, cxl_err->header[i]);
+ }
+
+ capctrl = FIELD_DP32(capctrl, CXL_RAS_ERR_CAP_CTRL,
+ FIRST_ERROR_POINTER, cxl_err->type);
+ stl_le_p(cache_mem + R_CXL_RAS_ERR_CAP_CTRL, capctrl);
+ }
+
+ unc_err = 0;
+ QTAILQ_FOREACH(cxl_err, &ct3d->error_list, node) {
+ unc_err |= (1 << cxl_err->type);
+ }
+ if (!unc_err) {
+ return;
+ }
+
+ stl_le_p(reg_state + R_CXL_RAS_UNC_ERR_STATUS, unc_err);
+ pcie_aer_inject_error(PCI_DEVICE(obj), &err);
+
+ return;
+}
+
+void qmp_cxl_inject_correctable_error(const char *path, CxlCorErrorType type,
+ Error **errp)
+{
+ static PCIEAERErr err = {};
+ Object *obj = object_resolve_path(path, NULL);
+ CXLType3Dev *ct3d;
+ uint32_t *reg_state;
+ uint32_t cor_err;
+ int cxl_err_type;
+
+ if (!obj) {
+ error_setg(errp, "Unable to resolve path");
+ return;
+ }
+ if (!object_dynamic_cast(obj, TYPE_CXL_TYPE3)) {
+ error_setg(errp, "Path does not point to a CXL type 3 device");
+ return;
+ }
+
+ err.status = PCI_ERR_COR_INTERNAL;
+ err.source_id = pci_requester_id(PCI_DEVICE(obj));
+ err.flags = PCIE_AER_ERR_IS_CORRECTABLE;
+
+ ct3d = CXL_TYPE3(obj);
+ reg_state = ct3d->cxl_cstate.crb.cache_mem_registers;
+ cor_err = ldl_le_p(reg_state + R_CXL_RAS_COR_ERR_STATUS);
+
+ cxl_err_type = ct3d_qmp_cor_err_to_cxl(type);
+ if (cxl_err_type < 0) {
+ error_setg(errp, "Invalid COR error");
+ return;
+ }
+ /* If the error is masked, nothting to do here */
+ if (!((1 << cxl_err_type) & ~ldl_le_p(reg_state + R_CXL_RAS_COR_ERR_MASK))) {
+ return;
+ }
+
+ cor_err |= (1 << cxl_err_type);
+ stl_le_p(reg_state + R_CXL_RAS_COR_ERR_STATUS, cor_err);
+
+ pcie_aer_inject_error(PCI_DEVICE(obj), &err);
+}
+
static void ct3_class_init(ObjectClass *oc, void *data)
{
DeviceClass *dc = DEVICE_CLASS(oc);
diff --git a/hw/mem/cxl_type3_stubs.c b/hw/mem/cxl_type3_stubs.c
new file mode 100644
index 0000000..d574c58
--- /dev/null
+++ b/hw/mem/cxl_type3_stubs.c
@@ -0,0 +1,17 @@
+
+#include "qemu/osdep.h"
+#include "qapi/error.h"
+#include "qapi/qapi-commands-cxl.h"
+
+void qmp_cxl_inject_uncorrectable_errors(const char *path,
+ CXLUncorErrorRecordList *errors,
+ Error **errp)
+{
+ error_setg(errp, "CXL Type 3 support is not compiled in");
+}
+
+void qmp_cxl_inject_correctable_error(const char *path, CxlCorErrorType type,
+ Error **errp)
+{
+ error_setg(errp, "CXL Type 3 support is not compiled in");
+}
diff --git a/hw/mem/meson.build b/hw/mem/meson.build
index 609b2b3..56c2618 100644
--- a/hw/mem/meson.build
+++ b/hw/mem/meson.build
@@ -4,6 +4,8 @@ mem_ss.add(when: 'CONFIG_DIMM', if_true: files('pc-dimm.c'))
mem_ss.add(when: 'CONFIG_NPCM7XX', if_true: files('npcm7xx_mc.c'))
mem_ss.add(when: 'CONFIG_NVDIMM', if_true: files('nvdimm.c'))
mem_ss.add(when: 'CONFIG_CXL_MEM_DEVICE', if_true: files('cxl_type3.c'))
+softmmu_ss.add(when: 'CONFIG_CXL_MEM_DEVICE', if_false: files('cxl_type3_stubs.c'))
+softmmu_ss.add(when: 'CONFIG_ALL', if_true: files('cxl_type3_stubs.c'))
softmmu_ss.add_all(when: 'CONFIG_MEM_DEVICE', if_true: mem_ss)
diff --git a/hw/pci-bridge/cxl_root_port.c b/hw/pci-bridge/cxl_root_port.c
index 6664783..7dfd20a 100644
--- a/hw/pci-bridge/cxl_root_port.c
+++ b/hw/pci-bridge/cxl_root_port.c
@@ -22,6 +22,7 @@
#include "qemu/range.h"
#include "hw/pci/pci_bridge.h"
#include "hw/pci/pcie_port.h"
+#include "hw/pci/msi.h"
#include "hw/qdev-properties.h"
#include "hw/sysbus.h"
#include "qapi/error.h"
@@ -29,6 +30,10 @@
#define CXL_ROOT_PORT_DID 0x7075
+#define CXL_RP_MSI_OFFSET 0x60
+#define CXL_RP_MSI_SUPPORTED_FLAGS PCI_MSI_FLAGS_MASKBIT
+#define CXL_RP_MSI_NR_VECTOR 2
+
/* Copied from the gen root port which we derive */
#define GEN_PCIE_ROOT_PORT_AER_OFFSET 0x100
#define GEN_PCIE_ROOT_PORT_ACS_OFFSET \
@@ -47,6 +52,49 @@ typedef struct CXLRootPort {
#define TYPE_CXL_ROOT_PORT "cxl-rp"
DECLARE_INSTANCE_CHECKER(CXLRootPort, CXL_ROOT_PORT, TYPE_CXL_ROOT_PORT)
+/*
+ * If two MSI vector are allocated, Advanced Error Interrupt Message Number
+ * is 1. otherwise 0.
+ * 17.12.5.10 RPERRSTS, 32:27 bit Advanced Error Interrupt Message Number.
+ */
+static uint8_t cxl_rp_aer_vector(const PCIDevice *d)
+{
+ switch (msi_nr_vectors_allocated(d)) {
+ case 1:
+ return 0;
+ case 2:
+ return 1;
+ case 4:
+ case 8:
+ case 16:
+ case 32:
+ default:
+ break;
+ }
+ abort();
+ return 0;
+}
+
+static int cxl_rp_interrupts_init(PCIDevice *d, Error **errp)
+{
+ int rc;
+
+ rc = msi_init(d, CXL_RP_MSI_OFFSET, CXL_RP_MSI_NR_VECTOR,
+ CXL_RP_MSI_SUPPORTED_FLAGS & PCI_MSI_FLAGS_64BIT,
+ CXL_RP_MSI_SUPPORTED_FLAGS & PCI_MSI_FLAGS_MASKBIT,
+ errp);
+ if (rc < 0) {
+ assert(rc == -ENOTSUP);
+ }
+
+ return rc;
+}
+
+static void cxl_rp_interrupts_uninit(PCIDevice *d)
+{
+ msi_uninit(d);
+}
+
static void latch_registers(CXLRootPort *crp)
{
uint32_t *reg_state = crp->cxl_cstate.crb.cache_mem_registers;
@@ -183,16 +231,29 @@ static void cxl_rp_dvsec_write_config(PCIDevice *dev, uint32_t addr,
}
}
+static void cxl_rp_aer_vector_update(PCIDevice *d)
+{
+ PCIERootPortClass *rpc = PCIE_ROOT_PORT_GET_CLASS(d);
+
+ if (rpc->aer_vector) {
+ pcie_aer_root_set_vector(d, rpc->aer_vector(d));
+ }
+}
+
static void cxl_rp_write_config(PCIDevice *d, uint32_t address, uint32_t val,
int len)
{
uint16_t slt_ctl, slt_sta;
+ uint32_t root_cmd =
+ pci_get_long(d->config + d->exp.aer_cap + PCI_ERR_ROOT_COMMAND);
pcie_cap_slot_get(d, &slt_ctl, &slt_sta);
pci_bridge_write_config(d, address, val, len);
+ cxl_rp_aer_vector_update(d);
pcie_cap_flr_write_config(d, address, val, len);
pcie_cap_slot_write_config(d, slt_ctl, slt_sta, address, val, len);
pcie_aer_write_config(d, address, val, len);
+ pcie_aer_root_write_config(d, address, val, len, root_cmd);
cxl_rp_dvsec_write_config(d, address, val, len);
}
@@ -217,6 +278,9 @@ static void cxl_root_port_class_init(ObjectClass *oc, void *data)
rpc->aer_offset = GEN_PCIE_ROOT_PORT_AER_OFFSET;
rpc->acs_offset = GEN_PCIE_ROOT_PORT_ACS_OFFSET;
+ rpc->aer_vector = cxl_rp_aer_vector;
+ rpc->interrupts_init = cxl_rp_interrupts_init;
+ rpc->interrupts_uninit = cxl_rp_interrupts_uninit;
dc->hotpluggable = false;
}
diff --git a/hw/pci-bridge/pci_expander_bridge.c b/hw/pci-bridge/pci_expander_bridge.c
index e752a21..ead33f0 100644
--- a/hw/pci-bridge/pci_expander_bridge.c
+++ b/hw/pci-bridge/pci_expander_bridge.c
@@ -15,6 +15,7 @@
#include "hw/pci/pci.h"
#include "hw/pci/pci_bus.h"
#include "hw/pci/pci_host.h"
+#include "hw/pci/pcie_port.h"
#include "hw/qdev-properties.h"
#include "hw/pci/pci_bridge.h"
#include "hw/pci-bridge/pci_expander_bridge.h"
@@ -79,6 +80,13 @@ CXLComponentState *cxl_get_hb_cstate(PCIHostState *hb)
return &host->cxl_cstate;
}
+bool cxl_get_hb_passthrough(PCIHostState *hb)
+{
+ CXLHost *host = PXB_CXL_HOST(hb);
+
+ return host->passthrough;
+}
+
static int pxb_bus_num(PCIBus *bus)
{
PXBDev *pxb = convert_to_pxb(bus->parent_dev);
@@ -289,15 +297,32 @@ static int pxb_map_irq_fn(PCIDevice *pci_dev, int pin)
return pin - PCI_SLOT(pxb->devfn);
}
-static void pxb_dev_reset(DeviceState *dev)
+static void pxb_cxl_dev_reset(DeviceState *dev)
{
CXLHost *cxl = PXB_CXL_DEV(dev)->cxl.cxl_host_bridge;
CXLComponentState *cxl_cstate = &cxl->cxl_cstate;
+ PCIHostState *hb = PCI_HOST_BRIDGE(cxl);
uint32_t *reg_state = cxl_cstate->crb.cache_mem_registers;
uint32_t *write_msk = cxl_cstate->crb.cache_mem_regs_write_mask;
+ int dsp_count = 0;
cxl_component_register_init_common(reg_state, write_msk, CXL2_ROOT_PORT);
- ARRAY_FIELD_DP32(reg_state, CXL_HDM_DECODER_CAPABILITY, TARGET_COUNT, 8);
+ /*
+ * The CXL specification allows for host bridges with no HDM decoders
+ * if they only have a single root port.
+ */
+ if (!PXB_DEV(dev)->hdm_for_passthrough) {
+ dsp_count = pcie_count_ds_ports(hb->bus);
+ }
+ /* Initial reset will have 0 dsp so wait until > 0 */
+ if (dsp_count == 1) {
+ cxl->passthrough = true;
+ /* Set Capability ID in header to NONE */
+ ARRAY_FIELD_DP32(reg_state, CXL_HDM_CAPABILITY_HEADER, ID, 0);
+ } else {
+ ARRAY_FIELD_DP32(reg_state, CXL_HDM_DECODER_CAPABILITY, TARGET_COUNT,
+ 8);
+ }
}
static gint pxb_compare(gconstpointer a, gconstpointer b)
@@ -481,9 +506,18 @@ static void pxb_cxl_dev_realize(PCIDevice *dev, Error **errp)
}
pxb_dev_realize_common(dev, CXL, errp);
- pxb_dev_reset(DEVICE(dev));
+ pxb_cxl_dev_reset(DEVICE(dev));
}
+static Property pxb_cxl_dev_properties[] = {
+ /* Note: 0 is not a legal PXB bus number. */
+ DEFINE_PROP_UINT8("bus_nr", PXBDev, bus_nr, 0),
+ DEFINE_PROP_UINT16("numa_node", PXBDev, numa_node, NUMA_NODE_UNASSIGNED),
+ DEFINE_PROP_BOOL("bypass_iommu", PXBDev, bypass_iommu, false),
+ DEFINE_PROP_BOOL("hdm_for_passthrough", PXBDev, hdm_for_passthrough, false),
+ DEFINE_PROP_END_OF_LIST(),
+};
+
static void pxb_cxl_dev_class_init(ObjectClass *klass, void *data)
{
DeviceClass *dc = DEVICE_CLASS(klass);
@@ -497,12 +531,12 @@ static void pxb_cxl_dev_class_init(ObjectClass *klass, void *data)
*/
dc->desc = "CXL Host Bridge";
- device_class_set_props(dc, pxb_dev_properties);
+ device_class_set_props(dc, pxb_cxl_dev_properties);
set_bit(DEVICE_CATEGORY_BRIDGE, dc->categories);
/* Host bridges aren't hotpluggable. FIXME: spec reference */
dc->hotpluggable = false;
- dc->reset = pxb_dev_reset;
+ dc->reset = pxb_cxl_dev_reset;
}
static const TypeInfo pxb_cxl_dev_info = {
diff --git a/hw/pci/pci-internal.h b/hw/pci/pci-internal.h
index 2ea356b..a7d6d8a 100644
--- a/hw/pci/pci-internal.h
+++ b/hw/pci/pci-internal.h
@@ -20,6 +20,5 @@ void pcibus_dev_print(Monitor *mon, DeviceState *dev, int indent);
int pcie_aer_parse_error_string(const char *error_name,
uint32_t *status, bool *correctable);
-int pcie_aer_inject_error(PCIDevice *dev, const PCIEAERErr *err);
#endif
diff --git a/hw/pci/pci.c b/hw/pci/pci.c
index 034fe49..def5000 100644
--- a/hw/pci/pci.c
+++ b/hw/pci/pci.c
@@ -95,6 +95,21 @@ static const VMStateDescription vmstate_pcibus = {
}
};
+static gint g_cmp_uint32(gconstpointer a, gconstpointer b, gpointer user_data)
+{
+ return a - b;
+}
+
+static GSequence *pci_acpi_index_list(void)
+{
+ static GSequence *used_acpi_index_list;
+
+ if (!used_acpi_index_list) {
+ used_acpi_index_list = g_sequence_new(NULL);
+ }
+ return used_acpi_index_list;
+}
+
static void pci_init_bus_master(PCIDevice *pci_dev)
{
AddressSpace *dma_as = pci_device_iommu_address_space(pci_dev);
@@ -1246,6 +1261,17 @@ static void pci_qdev_unrealize(DeviceState *dev)
do_pci_unregister_device(pci_dev);
pci_dev->msi_trigger = NULL;
+
+ /*
+ * clean up acpi-index so it could reused by another device
+ */
+ if (pci_dev->acpi_index) {
+ GSequence *used_indexes = pci_acpi_index_list();
+
+ g_sequence_remove(g_sequence_lookup(used_indexes,
+ GINT_TO_POINTER(pci_dev->acpi_index),
+ g_cmp_uint32, NULL));
+ }
}
void pci_register_bar(PCIDevice *pci_dev, int region_num,
@@ -2005,6 +2031,8 @@ PCIDevice *pci_find_device(PCIBus *bus, int bus_num, uint8_t devfn)
return bus->devices[devfn];
}
+#define ONBOARD_INDEX_MAX (16 * 1024 - 1)
+
static void pci_qdev_realize(DeviceState *qdev, Error **errp)
{
PCIDevice *pci_dev = (PCIDevice *)qdev;
@@ -2014,6 +2042,35 @@ static void pci_qdev_realize(DeviceState *qdev, Error **errp)
bool is_default_rom;
uint16_t class_id;
+ /*
+ * capped by systemd (see: udev-builtin-net_id.c)
+ * as it's the only known user honor it to avoid users
+ * misconfigure QEMU and then wonder why acpi-index doesn't work
+ */
+ if (pci_dev->acpi_index > ONBOARD_INDEX_MAX) {
+ error_setg(errp, "acpi-index should be less or equal to %u",
+ ONBOARD_INDEX_MAX);
+ return;
+ }
+
+ /*
+ * make sure that acpi-index is unique across all present PCI devices
+ */
+ if (pci_dev->acpi_index) {
+ GSequence *used_indexes = pci_acpi_index_list();
+
+ if (g_sequence_lookup(used_indexes,
+ GINT_TO_POINTER(pci_dev->acpi_index),
+ g_cmp_uint32, NULL)) {
+ error_setg(errp, "a PCI device with acpi-index = %" PRIu32
+ " already exist", pci_dev->acpi_index);
+ return;
+ }
+ g_sequence_insert_sorted(used_indexes,
+ GINT_TO_POINTER(pci_dev->acpi_index),
+ g_cmp_uint32, NULL);
+ }
+
if (pci_dev->romsize != -1 && !is_power_of_2(pci_dev->romsize)) {
error_setg(errp, "ROM size %u is not a power of two", pci_dev->romsize);
return;
diff --git a/hw/pci/pcie_aer.c b/hw/pci/pcie_aer.c
index 9a19be4..103667c 100644
--- a/hw/pci/pcie_aer.c
+++ b/hw/pci/pcie_aer.c
@@ -112,6 +112,10 @@ int pcie_aer_init(PCIDevice *dev, uint8_t cap_ver, uint16_t offset,
pci_set_long(dev->w1cmask + offset + PCI_ERR_UNCOR_STATUS,
PCI_ERR_UNC_SUPPORTED);
+ pci_set_long(dev->config + offset + PCI_ERR_UNCOR_MASK,
+ PCI_ERR_UNC_MASK_DEFAULT);
+ pci_set_long(dev->wmask + offset + PCI_ERR_UNCOR_MASK,
+ PCI_ERR_UNC_SUPPORTED);
pci_set_long(dev->config + offset + PCI_ERR_UNCOR_SEVER,
PCI_ERR_UNC_SEVERITY_DEFAULT);
@@ -188,8 +192,16 @@ static void pcie_aer_update_uncor_status(PCIDevice *dev)
static bool
pcie_aer_msg_alldev(PCIDevice *dev, const PCIEAERMsg *msg)
{
+ uint16_t devctl = pci_get_word(dev->config + dev->exp.exp_cap +
+ PCI_EXP_DEVCTL);
if (!(pcie_aer_msg_is_uncor(msg) &&
- (pci_get_word(dev->config + PCI_COMMAND) & PCI_COMMAND_SERR))) {
+ (pci_get_word(dev->config + PCI_COMMAND) & PCI_COMMAND_SERR)) &&
+ !((msg->severity == PCI_ERR_ROOT_CMD_NONFATAL_EN) &&
+ (devctl & PCI_EXP_DEVCTL_NFERE)) &&
+ !((msg->severity == PCI_ERR_ROOT_CMD_COR_EN) &&
+ (devctl & PCI_EXP_DEVCTL_CERE)) &&
+ !((msg->severity == PCI_ERR_ROOT_CMD_FATAL_EN) &&
+ (devctl & PCI_EXP_DEVCTL_FERE))) {
return false;
}
diff --git a/hw/pci/pcie_port.c b/hw/pci/pcie_port.c
index 65a397a..20ff2b3 100644
--- a/hw/pci/pcie_port.c
+++ b/hw/pci/pcie_port.c
@@ -161,6 +161,51 @@ PCIDevice *pcie_find_port_by_pn(PCIBus *bus, uint8_t pn)
return NULL;
}
+/* Find first port in devfn number order */
+PCIDevice *pcie_find_port_first(PCIBus *bus)
+{
+ int devfn;
+
+ for (devfn = 0; devfn < ARRAY_SIZE(bus->devices); devfn++) {
+ PCIDevice *d = bus->devices[devfn];
+
+ if (!d || !pci_is_express(d) || !d->exp.exp_cap) {
+ continue;
+ }
+
+ if (object_dynamic_cast(OBJECT(d), TYPE_PCIE_PORT)) {
+ return d;
+ }
+ }
+
+ return NULL;
+}
+
+int pcie_count_ds_ports(PCIBus *bus)
+{
+ int dsp_count = 0;
+ int devfn;
+
+ for (devfn = 0; devfn < ARRAY_SIZE(bus->devices); devfn++) {
+ PCIDevice *d = bus->devices[devfn];
+
+ if (!d || !pci_is_express(d) || !d->exp.exp_cap) {
+ continue;
+ }
+ if (object_dynamic_cast(OBJECT(d), TYPE_PCIE_PORT)) {
+ dsp_count++;
+ }
+ }
+ return dsp_count;
+}
+
+static bool pcie_slot_is_hotpluggbale_bus(HotplugHandler *plug_handler,
+ BusState *bus)
+{
+ PCIESlot *s = PCIE_SLOT(bus->parent);
+ return s->hotplug;
+}
+
static const TypeInfo pcie_port_type_info = {
.name = TYPE_PCIE_PORT,
.parent = TYPE_PCI_BRIDGE,
@@ -188,6 +233,7 @@ static void pcie_slot_class_init(ObjectClass *oc, void *data)
hc->plug = pcie_cap_slot_plug_cb;
hc->unplug = pcie_cap_slot_unplug_cb;
hc->unplug_request = pcie_cap_slot_unplug_request_cb;
+ hc->is_hotpluggable_bus = pcie_slot_is_hotpluggbale_bus;
}
static const TypeInfo pcie_slot_type_info = {
diff --git a/hw/virtio/trace-events b/hw/virtio/trace-events
index a87c5f3..8f8d05c 100644
--- a/hw/virtio/trace-events
+++ b/hw/virtio/trace-events
@@ -50,6 +50,7 @@ vhost_vdpa_set_vring_ready(void *dev) "dev: %p"
vhost_vdpa_dump_config(void *dev, const char *line) "dev: %p %s"
vhost_vdpa_set_config(void *dev, uint32_t offset, uint32_t size, uint32_t flags) "dev: %p offset: %"PRIu32" size: %"PRIu32" flags: 0x%"PRIx32
vhost_vdpa_get_config(void *dev, void *config, uint32_t config_len) "dev: %p config: %p config_len: %"PRIu32
+vhost_vdpa_suspend(void *dev) "dev: %p"
vhost_vdpa_dev_start(void *dev, bool started) "dev: %p started: %d"
vhost_vdpa_set_log_base(void *dev, uint64_t base, unsigned long long size, int refcnt, int fd, void *log) "dev: %p base: 0x%"PRIx64" size: %llu refcnt: %d fd: %d log: %p"
vhost_vdpa_set_vring_addr(void *dev, unsigned int index, unsigned int flags, uint64_t desc_user_addr, uint64_t used_user_addr, uint64_t avail_user_addr, uint64_t log_guest_addr) "dev: %p index: %u flags: 0x%x desc_user_addr: 0x%"PRIx64" used_user_addr: 0x%"PRIx64" avail_user_addr: 0x%"PRIx64" log_guest_addr: 0x%"PRIx64
diff --git a/hw/virtio/vhost-shadow-virtqueue.c b/hw/virtio/vhost-shadow-virtqueue.c
index 515ccf8..8361e70 100644
--- a/hw/virtio/vhost-shadow-virtqueue.c
+++ b/hw/virtio/vhost-shadow-virtqueue.c
@@ -694,13 +694,17 @@ void vhost_svq_stop(VhostShadowVirtqueue *svq)
g_autofree VirtQueueElement *elem = NULL;
elem = g_steal_pointer(&svq->desc_state[i].elem);
if (elem) {
- virtqueue_detach_element(svq->vq, elem, 0);
+ /*
+ * TODO: This is ok for networking, but other kinds of devices
+ * might have problems with just unpop these.
+ */
+ virtqueue_unpop(svq->vq, elem, 0);
}
}
next_avail_elem = g_steal_pointer(&svq->next_guest_avail_elem);
if (next_avail_elem) {
- virtqueue_detach_element(svq->vq, next_avail_elem, 0);
+ virtqueue_unpop(svq->vq, next_avail_elem, 0);
}
svq->vq = NULL;
g_free(svq->desc_next);
diff --git a/hw/virtio/vhost-user.c b/hw/virtio/vhost-user.c
index 8968541..e5285df 100644
--- a/hw/virtio/vhost-user.c
+++ b/hw/virtio/vhost-user.c
@@ -2031,8 +2031,8 @@ static int vhost_user_backend_init(struct vhost_dev *dev, void *opaque,
} else {
if (virtio_has_feature(protocol_features,
VHOST_USER_PROTOCOL_F_CONFIG)) {
- warn_reportf_err(*errp, "vhost-user backend supports "
- "VHOST_USER_PROTOCOL_F_CONFIG but QEMU does not.");
+ warn_report("vhost-user backend supports "
+ "VHOST_USER_PROTOCOL_F_CONFIG but QEMU does not.");
protocol_features &= ~(1ULL << VHOST_USER_PROTOCOL_F_CONFIG);
}
}
diff --git a/hw/virtio/vhost-vdpa.c b/hw/virtio/vhost-vdpa.c
index df3a1e9..bc6bad2 100644
--- a/hw/virtio/vhost-vdpa.c
+++ b/hw/virtio/vhost-vdpa.c
@@ -431,16 +431,6 @@ static int vhost_vdpa_init(struct vhost_dev *dev, void *opaque, Error **errp)
trace_vhost_vdpa_init(dev, opaque);
int ret;
- /*
- * Similar to VFIO, we end up pinning all guest memory and have to
- * disable discarding of RAM.
- */
- ret = ram_block_discard_disable(true);
- if (ret) {
- error_report("Cannot set discarding of RAM broken");
- return ret;
- }
-
v = opaque;
v->dev = dev;
dev->opaque = opaque ;
@@ -448,10 +438,36 @@ static int vhost_vdpa_init(struct vhost_dev *dev, void *opaque, Error **errp)
v->msg_type = VHOST_IOTLB_MSG_V2;
vhost_vdpa_init_svq(dev, v);
+ error_propagate(&dev->migration_blocker, v->migration_blocker);
if (!vhost_vdpa_first_dev(dev)) {
return 0;
}
+ /*
+ * If dev->shadow_vqs_enabled at initialization that means the device has
+ * been started with x-svq=on, so don't block migration
+ */
+ if (dev->migration_blocker == NULL && !v->shadow_vqs_enabled) {
+ /* We don't have dev->features yet */
+ uint64_t features;
+ ret = vhost_vdpa_get_dev_features(dev, &features);
+ if (unlikely(ret)) {
+ error_setg_errno(errp, -ret, "Could not get device features");
+ return ret;
+ }
+ vhost_svq_valid_features(features, &dev->migration_blocker);
+ }
+
+ /*
+ * Similar to VFIO, we end up pinning all guest memory and have to
+ * disable discarding of RAM.
+ */
+ ret = ram_block_discard_disable(true);
+ if (ret) {
+ error_report("Cannot set discarding of RAM broken");
+ return ret;
+ }
+
vhost_vdpa_add_status(dev, VIRTIO_CONFIG_S_ACKNOWLEDGE |
VIRTIO_CONFIG_S_DRIVER);
@@ -577,12 +593,15 @@ static int vhost_vdpa_cleanup(struct vhost_dev *dev)
assert(dev->vhost_ops->backend_type == VHOST_BACKEND_TYPE_VDPA);
v = dev->opaque;
trace_vhost_vdpa_cleanup(dev, v);
+ if (vhost_vdpa_first_dev(dev)) {
+ ram_block_discard_disable(false);
+ }
+
vhost_vdpa_host_notifiers_uninit(dev, dev->nvqs);
memory_listener_unregister(&v->listener);
vhost_vdpa_svq_cleanup(dev);
dev->opaque = NULL;
- ram_block_discard_disable(false);
return 0;
}
@@ -659,7 +678,8 @@ static int vhost_vdpa_set_backend_cap(struct vhost_dev *dev)
uint64_t features;
uint64_t f = 0x1ULL << VHOST_BACKEND_F_IOTLB_MSG_V2 |
0x1ULL << VHOST_BACKEND_F_IOTLB_BATCH |
- 0x1ULL << VHOST_BACKEND_F_IOTLB_ASID;
+ 0x1ULL << VHOST_BACKEND_F_IOTLB_ASID |
+ 0x1ULL << VHOST_BACKEND_F_SUSPEND;
int r;
if (vhost_vdpa_call(dev, VHOST_GET_BACKEND_FEATURES, &features)) {
@@ -691,11 +711,13 @@ static int vhost_vdpa_get_device_id(struct vhost_dev *dev,
static int vhost_vdpa_reset_device(struct vhost_dev *dev)
{
+ struct vhost_vdpa *v = dev->opaque;
int ret;
uint8_t status = 0;
ret = vhost_vdpa_call(dev, VHOST_VDPA_SET_STATUS, &status);
trace_vhost_vdpa_reset_device(dev, status);
+ v->suspended = false;
return ret;
}
@@ -1094,6 +1116,29 @@ static void vhost_vdpa_svqs_stop(struct vhost_dev *dev)
}
}
+static void vhost_vdpa_suspend(struct vhost_dev *dev)
+{
+ struct vhost_vdpa *v = dev->opaque;
+ int r;
+
+ if (!vhost_vdpa_first_dev(dev)) {
+ return;
+ }
+
+ if (dev->backend_cap & BIT_ULL(VHOST_BACKEND_F_SUSPEND)) {
+ trace_vhost_vdpa_suspend(dev);
+ r = ioctl(v->device_fd, VHOST_VDPA_SUSPEND);
+ if (unlikely(r)) {
+ error_report("Cannot suspend: %s(%d)", g_strerror(errno), errno);
+ } else {
+ v->suspended = true;
+ return;
+ }
+ }
+
+ vhost_vdpa_reset_device(dev);
+}
+
static int vhost_vdpa_dev_start(struct vhost_dev *dev, bool started)
{
struct vhost_vdpa *v = dev->opaque;
@@ -1108,6 +1153,7 @@ static int vhost_vdpa_dev_start(struct vhost_dev *dev, bool started)
}
vhost_vdpa_set_vring_ready(dev);
} else {
+ vhost_vdpa_suspend(dev);
vhost_vdpa_svqs_stop(dev);
vhost_vdpa_host_notifiers_uninit(dev, dev->nvqs);
}
@@ -1119,14 +1165,23 @@ static int vhost_vdpa_dev_start(struct vhost_dev *dev, bool started)
if (started) {
memory_listener_register(&v->listener, &address_space_memory);
return vhost_vdpa_add_status(dev, VIRTIO_CONFIG_S_DRIVER_OK);
- } else {
- vhost_vdpa_reset_device(dev);
- vhost_vdpa_add_status(dev, VIRTIO_CONFIG_S_ACKNOWLEDGE |
- VIRTIO_CONFIG_S_DRIVER);
- memory_listener_unregister(&v->listener);
+ }
- return 0;
+ return 0;
+}
+
+static void vhost_vdpa_reset_status(struct vhost_dev *dev)
+{
+ struct vhost_vdpa *v = dev->opaque;
+
+ if (dev->vq_index + dev->nvqs != dev->vq_index_end) {
+ return;
}
+
+ vhost_vdpa_reset_device(dev);
+ vhost_vdpa_add_status(dev, VIRTIO_CONFIG_S_ACKNOWLEDGE |
+ VIRTIO_CONFIG_S_DRIVER);
+ memory_listener_unregister(&v->listener);
}
static int vhost_vdpa_set_log_base(struct vhost_dev *dev, uint64_t base,
@@ -1169,18 +1224,7 @@ static int vhost_vdpa_set_vring_base(struct vhost_dev *dev,
struct vhost_vring_state *ring)
{
struct vhost_vdpa *v = dev->opaque;
- VirtQueue *vq = virtio_get_queue(dev->vdev, ring->index);
- /*
- * vhost-vdpa devices does not support in-flight requests. Set all of them
- * as available.
- *
- * TODO: This is ok for networking, but other kinds of devices might
- * have problems with these retransmissions.
- */
- while (virtqueue_rewind(vq, 1)) {
- continue;
- }
if (v->shadow_vqs_enabled) {
/*
* Device vring base was set at device start. SVQ base is handled by
@@ -1203,6 +1247,14 @@ static int vhost_vdpa_get_vring_base(struct vhost_dev *dev,
return 0;
}
+ if (!v->suspended) {
+ /*
+ * Cannot trust in value returned by device, let vhost recover used
+ * idx from guest.
+ */
+ return -1;
+ }
+
ret = vhost_vdpa_call(dev, VHOST_GET_VRING_BASE, ring);
trace_vhost_vdpa_get_vring_base(dev, ring->index, ring->num);
return ret;
@@ -1227,25 +1279,24 @@ static int vhost_vdpa_set_vring_call(struct vhost_dev *dev,
struct vhost_vring_file *file)
{
struct vhost_vdpa *v = dev->opaque;
+ int vdpa_idx = file->index - dev->vq_index;
+ VhostShadowVirtqueue *svq = g_ptr_array_index(v->shadow_vqs, vdpa_idx);
+ /* Remember last call fd because we can switch to SVQ anytime. */
+ vhost_svq_set_svq_call_fd(svq, file->fd);
if (v->shadow_vqs_enabled) {
- int vdpa_idx = file->index - dev->vq_index;
- VhostShadowVirtqueue *svq = g_ptr_array_index(v->shadow_vqs, vdpa_idx);
-
- vhost_svq_set_svq_call_fd(svq, file->fd);
return 0;
- } else {
- return vhost_vdpa_set_vring_dev_call(dev, file);
}
+
+ return vhost_vdpa_set_vring_dev_call(dev, file);
}
static int vhost_vdpa_get_features(struct vhost_dev *dev,
uint64_t *features)
{
- struct vhost_vdpa *v = dev->opaque;
int ret = vhost_vdpa_get_dev_features(dev, features);
- if (ret == 0 && v->shadow_vqs_enabled) {
+ if (ret == 0) {
/* Add SVQ logging capabilities */
*features |= BIT_ULL(VHOST_F_LOG_ALL);
}
@@ -1313,4 +1364,5 @@ const VhostOps vdpa_ops = {
.vhost_vq_get_addr = vhost_vdpa_vq_get_addr,
.vhost_force_iommu = vhost_vdpa_force_iommu,
.vhost_set_config_call = vhost_vdpa_set_config_call,
+ .vhost_reset_status = vhost_vdpa_reset_status,
};
diff --git a/hw/virtio/vhost.c b/hw/virtio/vhost.c
index eb8c4c3..a266396 100644
--- a/hw/virtio/vhost.c
+++ b/hw/virtio/vhost.c
@@ -2049,6 +2049,9 @@ void vhost_dev_stop(struct vhost_dev *hdev, VirtIODevice *vdev, bool vrings)
hdev->vqs + i,
hdev->vq_index + i);
}
+ if (hdev->vhost_ops->vhost_reset_status) {
+ hdev->vhost_ops->vhost_reset_status(hdev);
+ }
if (vhost_dev_has_iommu(hdev)) {
if (hdev->vhost_ops->vhost_set_iotlb_callback) {
diff --git a/hw/virtio/virtio-crypto.c b/hw/virtio/virtio-crypto.c
index 516425e..802e1b9 100644
--- a/hw/virtio/virtio-crypto.c
+++ b/hw/virtio/virtio-crypto.c
@@ -462,7 +462,7 @@ static void virtio_crypto_init_request(VirtIOCrypto *vcrypto, VirtQueue *vq,
req->in_iov = NULL;
req->in_num = 0;
req->in_len = 0;
- req->flags = CRYPTODEV_BACKEND_ALG__MAX;
+ req->flags = QCRYPTODEV_BACKEND_ALG__MAX;
memset(&req->op_info, 0x00, sizeof(req->op_info));
}
@@ -472,7 +472,7 @@ static void virtio_crypto_free_request(VirtIOCryptoReq *req)
return;
}
- if (req->flags == CRYPTODEV_BACKEND_ALG_SYM) {
+ if (req->flags == QCRYPTODEV_BACKEND_ALG_SYM) {
size_t max_len;
CryptoDevBackendSymOpInfo *op_info = req->op_info.u.sym_op_info;
@@ -485,7 +485,7 @@ static void virtio_crypto_free_request(VirtIOCryptoReq *req)
/* Zeroize and free request data structure */
memset(op_info, 0, sizeof(*op_info) + max_len);
g_free(op_info);
- } else if (req->flags == CRYPTODEV_BACKEND_ALG_ASYM) {
+ } else if (req->flags == QCRYPTODEV_BACKEND_ALG_ASYM) {
CryptoDevBackendAsymOpInfo *op_info = req->op_info.u.asym_op_info;
if (op_info) {
g_free(op_info->src);
@@ -570,10 +570,10 @@ static void virtio_crypto_req_complete(void *opaque, int ret)
VirtIODevice *vdev = VIRTIO_DEVICE(vcrypto);
uint8_t status = -ret;
- if (req->flags == CRYPTODEV_BACKEND_ALG_SYM) {
+ if (req->flags == QCRYPTODEV_BACKEND_ALG_SYM) {
virtio_crypto_sym_input_data_helper(vdev, req, status,
req->op_info.u.sym_op_info);
- } else if (req->flags == CRYPTODEV_BACKEND_ALG_ASYM) {
+ } else if (req->flags == QCRYPTODEV_BACKEND_ALG_ASYM) {
virtio_crypto_akcipher_input_data_helper(vdev, req, status,
req->op_info.u.asym_op_info);
}
@@ -871,11 +871,14 @@ virtio_crypto_handle_request(VirtIOCryptoReq *request)
opcode = ldl_le_p(&req.header.opcode);
op_info->session_id = ldq_le_p(&req.header.session_id);
op_info->op_code = opcode;
+ op_info->queue_index = queue_index;
+ op_info->cb = virtio_crypto_req_complete;
+ op_info->opaque = request;
switch (opcode) {
case VIRTIO_CRYPTO_CIPHER_ENCRYPT:
case VIRTIO_CRYPTO_CIPHER_DECRYPT:
- op_info->algtype = request->flags = CRYPTODEV_BACKEND_ALG_SYM;
+ op_info->algtype = request->flags = QCRYPTODEV_BACKEND_ALG_SYM;
ret = virtio_crypto_handle_sym_req(vcrypto,
&req.u.sym_req, op_info,
out_iov, out_num);
@@ -885,7 +888,7 @@ virtio_crypto_handle_request(VirtIOCryptoReq *request)
case VIRTIO_CRYPTO_AKCIPHER_DECRYPT:
case VIRTIO_CRYPTO_AKCIPHER_SIGN:
case VIRTIO_CRYPTO_AKCIPHER_VERIFY:
- op_info->algtype = request->flags = CRYPTODEV_BACKEND_ALG_ASYM;
+ op_info->algtype = request->flags = QCRYPTODEV_BACKEND_ALG_ASYM;
ret = virtio_crypto_handle_asym_req(vcrypto,
&req.u.akcipher_req, op_info,
out_iov, out_num);
@@ -898,9 +901,7 @@ check_result:
virtio_crypto_req_complete(request, -VIRTIO_CRYPTO_NOTSUPP);
} else {
ret = cryptodev_backend_crypto_operation(vcrypto->cryptodev,
- request, queue_index,
- virtio_crypto_req_complete,
- request);
+ op_info);
if (ret < 0) {
virtio_crypto_req_complete(request, ret);
}
@@ -997,12 +998,35 @@ static void virtio_crypto_reset(VirtIODevice *vdev)
}
}
+static uint32_t virtio_crypto_init_services(uint32_t qservices)
+{
+ uint32_t vservices = 0;
+
+ if (qservices & (1 << QCRYPTODEV_BACKEND_SERVICE_CIPHER)) {
+ vservices |= (1 << VIRTIO_CRYPTO_SERVICE_CIPHER);
+ }
+ if (qservices & (1 << QCRYPTODEV_BACKEND_SERVICE_HASH)) {
+ vservices |= (1 << VIRTIO_CRYPTO_SERVICE_HASH);
+ }
+ if (qservices & (1 << QCRYPTODEV_BACKEND_SERVICE_MAC)) {
+ vservices |= (1 << VIRTIO_CRYPTO_SERVICE_MAC);
+ }
+ if (qservices & (1 << QCRYPTODEV_BACKEND_SERVICE_AEAD)) {
+ vservices |= (1 << VIRTIO_CRYPTO_SERVICE_AEAD);
+ }
+ if (qservices & (1 << QCRYPTODEV_BACKEND_SERVICE_AKCIPHER)) {
+ vservices |= (1 << VIRTIO_CRYPTO_SERVICE_AKCIPHER);
+ }
+
+ return vservices;
+}
+
static void virtio_crypto_init_config(VirtIODevice *vdev)
{
VirtIOCrypto *vcrypto = VIRTIO_CRYPTO(vdev);
- vcrypto->conf.crypto_services =
- vcrypto->conf.cryptodev->conf.crypto_services;
+ vcrypto->conf.crypto_services = virtio_crypto_init_services(
+ vcrypto->conf.cryptodev->conf.crypto_services);
vcrypto->conf.cipher_algo_l =
vcrypto->conf.cryptodev->conf.cipher_algo_l;
vcrypto->conf.cipher_algo_h =
diff --git a/hw/virtio/virtio.c b/hw/virtio/virtio.c
index f35178f..98c4819 100644
--- a/hw/virtio/virtio.c
+++ b/hw/virtio/virtio.c
@@ -1069,7 +1069,7 @@ static void virtqueue_split_get_avail_bytes(VirtQueue *vq,
VRingMemoryRegionCaches *caches)
{
VirtIODevice *vdev = vq->vdev;
- unsigned int max, idx;
+ unsigned int idx;
unsigned int total_bufs, in_total, out_total;
MemoryRegionCache indirect_desc_cache = MEMORY_REGION_CACHE_INVALID;
int64_t len = 0;
@@ -1078,13 +1078,12 @@ static void virtqueue_split_get_avail_bytes(VirtQueue *vq,
idx = vq->last_avail_idx;
total_bufs = in_total = out_total = 0;
- max = vq->vring.num;
-
while ((rc = virtqueue_num_heads(vq, idx)) > 0) {
MemoryRegionCache *desc_cache = &caches->desc;
unsigned int num_bufs;
VRingDesc desc;
unsigned int i;
+ unsigned int max = vq->vring.num;
num_bufs = total_bufs;
@@ -1206,7 +1205,7 @@ static void virtqueue_packed_get_avail_bytes(VirtQueue *vq,
VRingMemoryRegionCaches *caches)
{
VirtIODevice *vdev = vq->vdev;
- unsigned int max, idx;
+ unsigned int idx;
unsigned int total_bufs, in_total, out_total;
MemoryRegionCache *desc_cache;
MemoryRegionCache indirect_desc_cache = MEMORY_REGION_CACHE_INVALID;
@@ -1218,14 +1217,14 @@ static void virtqueue_packed_get_avail_bytes(VirtQueue *vq,
wrap_counter = vq->last_avail_wrap_counter;
total_bufs = in_total = out_total = 0;
- max = vq->vring.num;
-
for (;;) {
unsigned int num_bufs = total_bufs;
unsigned int i = idx;
int rc;
+ unsigned int max = vq->vring.num;
desc_cache = &caches->desc;
+
vring_packed_desc_read(vdev, &desc, desc_cache, idx, true);
if (!is_desc_avail(desc.flags, wrap_counter)) {
break;
diff --git a/include/hw/acpi/ich9.h b/include/hw/acpi/ich9.h
index 57a542c..2faf7f0 100644
--- a/include/hw/acpi/ich9.h
+++ b/include/hw/acpi/ich9.h
@@ -87,6 +87,7 @@ void ich9_pm_device_unplug_request_cb(HotplugHandler *hotplug_dev,
DeviceState *dev, Error **errp);
void ich9_pm_device_unplug_cb(HotplugHandler *hotplug_dev, DeviceState *dev,
Error **errp);
+bool ich9_pm_is_hotpluggable_bus(HotplugHandler *hotplug_dev, BusState *bus);
void ich9_pm_ospm_status(AcpiDeviceIf *adev, ACPIOSTInfoList ***list);
#endif /* HW_ACPI_ICH9_H */
diff --git a/include/hw/acpi/pcihp.h b/include/hw/acpi/pcihp.h
index 7e268c2..ef59810 100644
--- a/include/hw/acpi/pcihp.h
+++ b/include/hw/acpi/pcihp.h
@@ -49,15 +49,16 @@ typedef struct AcpiPciHpState {
uint32_t acpi_index;
PCIBus *root;
MemoryRegion io;
- bool legacy_piix;
uint16_t io_base;
uint16_t io_len;
+ bool use_acpi_hotplug_bridge;
+ bool use_acpi_root_pci_hotplug;
} AcpiPciHpState;
void acpi_pcihp_init(Object *owner, AcpiPciHpState *, PCIBus *root,
- MemoryRegion *address_space_io, bool bridges_enabled,
- uint16_t io_base);
+ MemoryRegion *address_space_io, uint16_t io_base);
+bool acpi_pcihp_is_hotpluggbale_bus(AcpiPciHpState *s, BusState *bus);
void acpi_pcihp_device_pre_plug_cb(HotplugHandler *hotplug_dev,
DeviceState *dev, Error **errp);
void acpi_pcihp_device_plug_cb(HotplugHandler *hotplug_dev, AcpiPciHpState *s,
@@ -69,7 +70,9 @@ void acpi_pcihp_device_unplug_request_cb(HotplugHandler *hotplug_dev,
Error **errp);
/* Called on reset */
-void acpi_pcihp_reset(AcpiPciHpState *s, bool acpihp_root_off);
+void acpi_pcihp_reset(AcpiPciHpState *s);
+
+void build_append_pcihp_slots(Aml *parent_scope, PCIBus *bus);
extern const VMStateDescription vmstate_acpi_pcihp_pci_status;
diff --git a/include/hw/acpi/piix4.h b/include/hw/acpi/piix4.h
index be1f8ea..eb1c122 100644
--- a/include/hw/acpi/piix4.h
+++ b/include/hw/acpi/piix4.h
@@ -57,8 +57,6 @@ struct PIIX4PMState {
Notifier powerdown_notifier;
AcpiPciHpState acpi_pci_hotplug;
- bool use_acpi_hotplug_bridge;
- bool use_acpi_root_pci_hotplug;
bool not_migrate_acpi_index;
uint8_t disable_s3;
diff --git a/include/hw/cxl/cxl.h b/include/hw/cxl/cxl.h
index b161be5..b2cffbb 100644
--- a/include/hw/cxl/cxl.h
+++ b/include/hw/cxl/cxl.h
@@ -49,6 +49,7 @@ struct CXLHost {
PCIHostState parent_obj;
CXLComponentState cxl_cstate;
+ bool passthrough;
};
#define TYPE_PXB_CXL_HOST "pxb-cxl-host"
diff --git a/include/hw/cxl/cxl_component.h b/include/hw/cxl/cxl_component.h
index 692d7a5..42c7e58 100644
--- a/include/hw/cxl/cxl_component.h
+++ b/include/hw/cxl/cxl_component.h
@@ -65,11 +65,37 @@ CXLx_CAPABILITY_HEADER(SNOOP, 0x14)
#define CXL_RAS_REGISTERS_OFFSET 0x80
#define CXL_RAS_REGISTERS_SIZE 0x58
REG32(CXL_RAS_UNC_ERR_STATUS, CXL_RAS_REGISTERS_OFFSET)
+#define CXL_RAS_UNC_ERR_CACHE_DATA_PARITY 0
+#define CXL_RAS_UNC_ERR_CACHE_ADDRESS_PARITY 1
+#define CXL_RAS_UNC_ERR_CACHE_BE_PARITY 2
+#define CXL_RAS_UNC_ERR_CACHE_DATA_ECC 3
+#define CXL_RAS_UNC_ERR_MEM_DATA_PARITY 4
+#define CXL_RAS_UNC_ERR_MEM_ADDRESS_PARITY 5
+#define CXL_RAS_UNC_ERR_MEM_BE_PARITY 6
+#define CXL_RAS_UNC_ERR_MEM_DATA_ECC 7
+#define CXL_RAS_UNC_ERR_REINIT_THRESHOLD 8
+#define CXL_RAS_UNC_ERR_RSVD_ENCODING 9
+#define CXL_RAS_UNC_ERR_POISON_RECEIVED 10
+#define CXL_RAS_UNC_ERR_RECEIVER_OVERFLOW 11
+#define CXL_RAS_UNC_ERR_INTERNAL 14
+#define CXL_RAS_UNC_ERR_CXL_IDE_TX 15
+#define CXL_RAS_UNC_ERR_CXL_IDE_RX 16
+#define CXL_RAS_UNC_ERR_CXL_UNUSED 63 /* Magic value */
REG32(CXL_RAS_UNC_ERR_MASK, CXL_RAS_REGISTERS_OFFSET + 0x4)
REG32(CXL_RAS_UNC_ERR_SEVERITY, CXL_RAS_REGISTERS_OFFSET + 0x8)
REG32(CXL_RAS_COR_ERR_STATUS, CXL_RAS_REGISTERS_OFFSET + 0xc)
+#define CXL_RAS_COR_ERR_CACHE_DATA_ECC 0
+#define CXL_RAS_COR_ERR_MEM_DATA_ECC 1
+#define CXL_RAS_COR_ERR_CRC_THRESHOLD 2
+#define CXL_RAS_COR_ERR_RETRY_THRESHOLD 3
+#define CXL_RAS_COR_ERR_CACHE_POISON_RECEIVED 4
+#define CXL_RAS_COR_ERR_MEM_POISON_RECEIVED 5
+#define CXL_RAS_COR_ERR_PHYSICAL 6
REG32(CXL_RAS_COR_ERR_MASK, CXL_RAS_REGISTERS_OFFSET + 0x10)
REG32(CXL_RAS_ERR_CAP_CTRL, CXL_RAS_REGISTERS_OFFSET + 0x14)
+ FIELD(CXL_RAS_ERR_CAP_CTRL, FIRST_ERROR_POINTER, 0, 6)
+REG32(CXL_RAS_ERR_HEADER0, CXL_RAS_REGISTERS_OFFSET + 0x18)
+#define CXL_RAS_ERR_HEADER_NUM 32
/* Offset 0x18 - 0x58 reserved for RAS logs */
/* 8.2.5.10 - CXL Security Capability Structure */
@@ -221,6 +247,7 @@ static inline hwaddr cxl_decode_ig(int ig)
}
CXLComponentState *cxl_get_hb_cstate(PCIHostState *hb);
+bool cxl_get_hb_passthrough(PCIHostState *hb);
void cxl_doe_cdat_init(CXLComponentState *cxl_cstate, Error **errp);
void cxl_doe_cdat_release(CXLComponentState *cxl_cstate);
diff --git a/include/hw/cxl/cxl_device.h b/include/hw/cxl/cxl_device.h
index 7e5ad65..d589f78 100644
--- a/include/hw/cxl/cxl_device.h
+++ b/include/hw/cxl/cxl_device.h
@@ -232,6 +232,14 @@ REG64(CXL_MEM_DEV_STS, 0)
FIELD(CXL_MEM_DEV_STS, MBOX_READY, 4, 1)
FIELD(CXL_MEM_DEV_STS, RESET_NEEDED, 5, 3)
+typedef struct CXLError {
+ QTAILQ_ENTRY(CXLError) node;
+ int type; /* Error code as per FE definition */
+ uint32_t header[32];
+} CXLError;
+
+typedef QTAILQ_HEAD(, CXLError) CXLErrorList;
+
struct CXLType3Dev {
/* Private */
PCIDevice parent_obj;
@@ -248,6 +256,9 @@ struct CXLType3Dev {
/* DOE */
DOECap doe_cdat;
+
+ /* Error injection */
+ CXLErrorList error_list;
};
#define TYPE_CXL_TYPE3 "cxl-type3"
diff --git a/include/hw/hotplug.h b/include/hw/hotplug.h
index e15f59c..a9840ed 100644
--- a/include/hw/hotplug.h
+++ b/include/hw/hotplug.h
@@ -48,6 +48,7 @@ typedef void (*hotplug_fn)(HotplugHandler *plug_handler,
* @unplug: unplug callback.
* Used for device removal with devices that implement
* asynchronous and synchronous (surprise) removal.
+ * @is_hotpluggable_bus: called to check if bus/its parent allow hotplug on bus
*/
struct HotplugHandlerClass {
/* <private> */
@@ -58,6 +59,7 @@ struct HotplugHandlerClass {
hotplug_fn plug;
hotplug_fn unplug_request;
hotplug_fn unplug;
+ bool (*is_hotpluggable_bus)(HotplugHandler *plug_handler, BusState *bus);
};
/**
diff --git a/include/hw/pci/pci_bridge.h b/include/hw/pci/pci_bridge.h
index 63a7521..81a058b 100644
--- a/include/hw/pci/pci_bridge.h
+++ b/include/hw/pci/pci_bridge.h
@@ -92,6 +92,7 @@ struct PXBDev {
uint8_t bus_nr;
uint16_t numa_node;
bool bypass_iommu;
+ bool hdm_for_passthrough;
struct cxl_dev {
CXLHost *cxl_host_bridge; /* Pointer to a CXLHost */
} cxl;
diff --git a/include/hw/pci/pcie_aer.h b/include/hw/pci/pcie_aer.h
index 65e71d9..1234fdc 100644
--- a/include/hw/pci/pcie_aer.h
+++ b/include/hw/pci/pcie_aer.h
@@ -100,4 +100,5 @@ void pcie_aer_root_write_config(PCIDevice *dev,
uint32_t addr, uint32_t val, int len,
uint32_t root_cmd_prev);
+int pcie_aer_inject_error(PCIDevice *dev, const PCIEAERErr *err);
#endif /* QEMU_PCIE_AER_H */
diff --git a/include/hw/pci/pcie_port.h b/include/hw/pci/pcie_port.h
index 6c40e37..90e6cf4 100644
--- a/include/hw/pci/pcie_port.h
+++ b/include/hw/pci/pcie_port.h
@@ -41,6 +41,8 @@ struct PCIEPort {
void pcie_port_init_reg(PCIDevice *d);
PCIDevice *pcie_find_port_by_pn(PCIBus *bus, uint8_t pn);
+PCIDevice *pcie_find_port_first(PCIBus *bus);
+int pcie_count_ds_ports(PCIBus *bus);
#define TYPE_PCIE_SLOT "pcie-slot"
OBJECT_DECLARE_SIMPLE_TYPE(PCIESlot, PCIE_SLOT)
diff --git a/include/hw/pci/pcie_regs.h b/include/hw/pci/pcie_regs.h
index 1fe0bdd..4972106 100644
--- a/include/hw/pci/pcie_regs.h
+++ b/include/hw/pci/pcie_regs.h
@@ -141,6 +141,9 @@ typedef enum PCIExpLinkWidth {
PCI_ERR_UNC_ATOP_EBLOCKED | \
PCI_ERR_UNC_TLP_PRF_BLOCKED)
+#define PCI_ERR_UNC_MASK_DEFAULT (PCI_ERR_UNC_INTN | \
+ PCI_ERR_UNC_TLP_PRF_BLOCKED)
+
#define PCI_ERR_UNC_SEVERITY_DEFAULT (PCI_ERR_UNC_DLP | \
PCI_ERR_UNC_SDN | \
PCI_ERR_UNC_FCP | \
diff --git a/include/hw/qdev-core.h b/include/hw/qdev-core.h
index f5b3b2f..bd50ad5 100644
--- a/include/hw/qdev-core.h
+++ b/include/hw/qdev-core.h
@@ -812,7 +812,18 @@ void qbus_set_bus_hotplug_handler(BusState *bus);
static inline bool qbus_is_hotpluggable(BusState *bus)
{
- return bus->hotplug_handler;
+ HotplugHandler *plug_handler = bus->hotplug_handler;
+ bool ret = !!plug_handler;
+
+ if (plug_handler) {
+ HotplugHandlerClass *hdc;
+
+ hdc = HOTPLUG_HANDLER_GET_CLASS(plug_handler);
+ if (hdc->is_hotpluggable_bus) {
+ ret = hdc->is_hotpluggable_bus(plug_handler, bus);
+ }
+ }
+ return ret;
}
/**
diff --git a/include/hw/virtio/vhost-backend.h b/include/hw/virtio/vhost-backend.h
index c5ab490..ec3fbae 100644
--- a/include/hw/virtio/vhost-backend.h
+++ b/include/hw/virtio/vhost-backend.h
@@ -130,6 +130,9 @@ typedef bool (*vhost_force_iommu_op)(struct vhost_dev *dev);
typedef int (*vhost_set_config_call_op)(struct vhost_dev *dev,
int fd);
+
+typedef void (*vhost_reset_status_op)(struct vhost_dev *dev);
+
typedef struct VhostOps {
VhostBackendType backend_type;
vhost_backend_init vhost_backend_init;
@@ -177,6 +180,7 @@ typedef struct VhostOps {
vhost_get_device_id_op vhost_get_device_id;
vhost_force_iommu_op vhost_force_iommu;
vhost_set_config_call_op vhost_set_config_call;
+ vhost_reset_status_op vhost_reset_status;
} VhostOps;
int vhost_backend_update_device_iotlb(struct vhost_dev *dev,
diff --git a/include/hw/virtio/vhost-vdpa.h b/include/hw/virtio/vhost-vdpa.h
index 7997f09..c278a2a 100644
--- a/include/hw/virtio/vhost-vdpa.h
+++ b/include/hw/virtio/vhost-vdpa.h
@@ -42,12 +42,15 @@ typedef struct vhost_vdpa {
bool shadow_vqs_enabled;
/* Vdpa must send shadow addresses as IOTLB key for data queues, not GPA */
bool shadow_data;
+ /* Device suspended successfully */
+ bool suspended;
/* IOVA mapping used by the Shadow Virtqueue */
VhostIOVATree *iova_tree;
GPtrArray *shadow_vqs;
const VhostShadowVirtqueueOps *shadow_vq_ops;
void *shadow_vq_ops_opaque;
struct vhost_dev *dev;
+ Error *migration_blocker;
VhostVDPAHostNotifier notifier[VIRTIO_QUEUE_MAX];
} VhostVDPA;
diff --git a/include/monitor/hmp.h b/include/monitor/hmp.h
index efae6b0..fdb69b7 100644
--- a/include/monitor/hmp.h
+++ b/include/monitor/hmp.h
@@ -180,5 +180,6 @@ void hmp_ioport_read(Monitor *mon, const QDict *qdict);
void hmp_ioport_write(Monitor *mon, const QDict *qdict);
void hmp_boot_set(Monitor *mon, const QDict *qdict);
void hmp_info_mtree(Monitor *mon, const QDict *qdict);
+void hmp_info_cryptodev(Monitor *mon, const QDict *qdict);
#endif
diff --git a/include/sysemu/cryptodev.h b/include/sysemu/cryptodev.h
index cf9b3f0..bc021ce 100644
--- a/include/sysemu/cryptodev.h
+++ b/include/sysemu/cryptodev.h
@@ -24,7 +24,9 @@
#define CRYPTODEV_H
#include "qemu/queue.h"
+#include "qemu/throttle.h"
#include "qom/object.h"
+#include "qapi/qapi-types-cryptodev.h"
/**
* CryptoDevBackend:
@@ -48,12 +50,6 @@ typedef struct CryptoDevBackendPeers CryptoDevBackendPeers;
typedef struct CryptoDevBackendClient
CryptoDevBackendClient;
-enum CryptoDevBackendAlgType {
- CRYPTODEV_BACKEND_ALG_SYM,
- CRYPTODEV_BACKEND_ALG_ASYM,
- CRYPTODEV_BACKEND_ALG__MAX,
-};
-
/**
* CryptoDevBackendSymSessionInfo:
*
@@ -179,17 +175,22 @@ typedef struct CryptoDevBackendAsymOpInfo {
uint8_t *dst;
} CryptoDevBackendAsymOpInfo;
+typedef void (*CryptoDevCompletionFunc) (void *opaque, int ret);
+
typedef struct CryptoDevBackendOpInfo {
- enum CryptoDevBackendAlgType algtype;
+ QCryptodevBackendAlgType algtype;
uint32_t op_code;
+ uint32_t queue_index;
+ CryptoDevCompletionFunc cb;
+ void *opaque; /* argument for cb */
uint64_t session_id;
union {
CryptoDevBackendSymOpInfo *sym_op_info;
CryptoDevBackendAsymOpInfo *asym_op_info;
} u;
+ QTAILQ_ENTRY(CryptoDevBackendOpInfo) next;
} CryptoDevBackendOpInfo;
-typedef void (*CryptoDevCompletionFunc) (void *opaque, int ret);
struct CryptoDevBackendClass {
ObjectClass parent_class;
@@ -209,24 +210,11 @@ struct CryptoDevBackendClass {
void *opaque);
int (*do_op)(CryptoDevBackend *backend,
- CryptoDevBackendOpInfo *op_info,
- uint32_t queue_index,
- CryptoDevCompletionFunc cb,
- void *opaque);
+ CryptoDevBackendOpInfo *op_info);
};
-typedef enum CryptoDevBackendOptionsType {
- CRYPTODEV_BACKEND_TYPE_NONE = 0,
- CRYPTODEV_BACKEND_TYPE_BUILTIN = 1,
- CRYPTODEV_BACKEND_TYPE_VHOST_USER = 2,
- CRYPTODEV_BACKEND_TYPE_LKCF = 3,
- CRYPTODEV_BACKEND_TYPE__MAX,
-} CryptoDevBackendOptionsType;
-
struct CryptoDevBackendClient {
- CryptoDevBackendOptionsType type;
- char *model;
- char *name;
+ QCryptodevBackendType type;
char *info_str;
unsigned int queue_index;
int vring_enable;
@@ -260,6 +248,24 @@ struct CryptoDevBackendConf {
uint64_t max_size;
};
+typedef struct CryptodevBackendSymStat {
+ int64_t encrypt_ops;
+ int64_t decrypt_ops;
+ int64_t encrypt_bytes;
+ int64_t decrypt_bytes;
+} CryptodevBackendSymStat;
+
+typedef struct CryptodevBackendAsymStat {
+ int64_t encrypt_ops;
+ int64_t decrypt_ops;
+ int64_t sign_ops;
+ int64_t verify_ops;
+ int64_t encrypt_bytes;
+ int64_t decrypt_bytes;
+ int64_t sign_bytes;
+ int64_t verify_bytes;
+} CryptodevBackendAsymStat;
+
struct CryptoDevBackend {
Object parent_obj;
@@ -267,15 +273,48 @@ struct CryptoDevBackend {
/* Tag the cryptodev backend is used by virtio-crypto or not */
bool is_used;
CryptoDevBackendConf conf;
+ CryptodevBackendSymStat *sym_stat;
+ CryptodevBackendAsymStat *asym_stat;
+
+ ThrottleState ts;
+ ThrottleTimers tt;
+ ThrottleConfig tc;
+ QTAILQ_HEAD(, CryptoDevBackendOpInfo) opinfos;
};
+#define CryptodevSymStatInc(be, op, bytes) do { \
+ be->sym_stat->op##_bytes += (bytes); \
+ be->sym_stat->op##_ops += 1; \
+} while (/*CONSTCOND*/0)
+
+#define CryptodevSymStatIncEncrypt(be, bytes) \
+ CryptodevSymStatInc(be, encrypt, bytes)
+
+#define CryptodevSymStatIncDecrypt(be, bytes) \
+ CryptodevSymStatInc(be, decrypt, bytes)
+
+#define CryptodevAsymStatInc(be, op, bytes) do { \
+ be->asym_stat->op##_bytes += (bytes); \
+ be->asym_stat->op##_ops += 1; \
+} while (/*CONSTCOND*/0)
+
+#define CryptodevAsymStatIncEncrypt(be, bytes) \
+ CryptodevAsymStatInc(be, encrypt, bytes)
+
+#define CryptodevAsymStatIncDecrypt(be, bytes) \
+ CryptodevAsymStatInc(be, decrypt, bytes)
+
+#define CryptodevAsymStatIncSign(be, bytes) \
+ CryptodevAsymStatInc(be, sign, bytes)
+
+#define CryptodevAsymStatIncVerify(be, bytes) \
+ CryptodevAsymStatInc(be, verify, bytes)
+
+
/**
* cryptodev_backend_new_client:
- * @model: the cryptodev backend model
- * @name: the cryptodev backend name, can be NULL
*
- * Creates a new cryptodev backend client object
- * with the @name in the model @model.
+ * Creates a new cryptodev backend client object.
*
* The returned object must be released with
* cryptodev_backend_free_client() when no
@@ -283,9 +322,8 @@ struct CryptoDevBackend {
*
* Returns: a new cryptodev backend client object
*/
-CryptoDevBackendClient *
-cryptodev_backend_new_client(const char *model,
- const char *name);
+CryptoDevBackendClient *cryptodev_backend_new_client(void);
+
/**
* cryptodev_backend_free_client:
* @cc: the cryptodev backend client object
@@ -354,24 +392,17 @@ int cryptodev_backend_close_session(
/**
* cryptodev_backend_crypto_operation:
* @backend: the cryptodev backend object
- * @opaque1: pointer to a VirtIOCryptoReq object
- * @queue_index: queue index of cryptodev backend client
- * @errp: pointer to a NULL-initialized error object
- * @cb: callbacks when operation is completed
- * @opaque2: parameter passed to cb
+ * @op_info: pointer to a CryptoDevBackendOpInfo object
*
- * Do crypto operation, such as encryption and
- * decryption
+ * Do crypto operation, such as encryption, decryption, signature and
+ * verification
*
* Returns: 0 for success and cb will be called when creation is completed,
* negative value for error, and cb will not be called.
*/
int cryptodev_backend_crypto_operation(
CryptoDevBackend *backend,
- void *opaque1,
- uint32_t queue_index,
- CryptoDevCompletionFunc cb,
- void *opaque2);
+ CryptoDevBackendOpInfo *op_info);
/**
* cryptodev_backend_set_used:
diff --git a/net/vhost-vdpa.c b/net/vhost-vdpa.c
index de5ed8f..99904a0 100644
--- a/net/vhost-vdpa.c
+++ b/net/vhost-vdpa.c
@@ -26,12 +26,15 @@
#include <err.h>
#include "standard-headers/linux/virtio_net.h"
#include "monitor/monitor.h"
+#include "migration/migration.h"
+#include "migration/misc.h"
#include "hw/virtio/vhost.h"
/* Todo:need to add the multiqueue support here */
typedef struct VhostVDPAState {
NetClientState nc;
struct vhost_vdpa vhost_vdpa;
+ Notifier migration_state;
VHostNetState *vhost_net;
/* Control commands shadow buffers */
@@ -98,6 +101,8 @@ static const uint64_t vdpa_svq_device_features =
BIT_ULL(VIRTIO_NET_F_MQ) |
BIT_ULL(VIRTIO_F_ANY_LAYOUT) |
BIT_ULL(VIRTIO_NET_F_CTRL_MAC_ADDR) |
+ /* VHOST_F_LOG_ALL is exposed by SVQ */
+ BIT_ULL(VHOST_F_LOG_ALL) |
BIT_ULL(VIRTIO_NET_F_RSC_EXT) |
BIT_ULL(VIRTIO_NET_F_STANDBY);
@@ -178,13 +183,9 @@ err_init:
static void vhost_vdpa_cleanup(NetClientState *nc)
{
VhostVDPAState *s = DO_UPCAST(VhostVDPAState, nc, nc);
- struct vhost_dev *dev = &s->vhost_net->dev;
qemu_vfree(s->cvq_cmd_out_buffer);
qemu_vfree(s->status);
- if (dev->vq_index + dev->nvqs == dev->vq_index_end) {
- g_clear_pointer(&s->vhost_vdpa.iova_tree, vhost_iova_tree_delete);
- }
if (s->vhost_net) {
vhost_net_cleanup(s->vhost_net);
g_free(s->vhost_net);
@@ -234,10 +235,126 @@ static ssize_t vhost_vdpa_receive(NetClientState *nc, const uint8_t *buf,
return size;
}
+/** From any vdpa net client, get the netclient of the first queue pair */
+static VhostVDPAState *vhost_vdpa_net_first_nc_vdpa(VhostVDPAState *s)
+{
+ NICState *nic = qemu_get_nic(s->nc.peer);
+ NetClientState *nc0 = qemu_get_peer(nic->ncs, 0);
+
+ return DO_UPCAST(VhostVDPAState, nc, nc0);
+}
+
+static void vhost_vdpa_net_log_global_enable(VhostVDPAState *s, bool enable)
+{
+ struct vhost_vdpa *v = &s->vhost_vdpa;
+ VirtIONet *n;
+ VirtIODevice *vdev;
+ int data_queue_pairs, cvq, r;
+
+ /* We are only called on the first data vqs and only if x-svq is not set */
+ if (s->vhost_vdpa.shadow_vqs_enabled == enable) {
+ return;
+ }
+
+ vdev = v->dev->vdev;
+ n = VIRTIO_NET(vdev);
+ if (!n->vhost_started) {
+ return;
+ }
+
+ data_queue_pairs = n->multiqueue ? n->max_queue_pairs : 1;
+ cvq = virtio_vdev_has_feature(vdev, VIRTIO_NET_F_CTRL_VQ) ?
+ n->max_ncs - n->max_queue_pairs : 0;
+ /*
+ * TODO: vhost_net_stop does suspend, get_base and reset. We can be smarter
+ * in the future and resume the device if read-only operations between
+ * suspend and reset goes wrong.
+ */
+ vhost_net_stop(vdev, n->nic->ncs, data_queue_pairs, cvq);
+
+ /* Start will check migration setup_or_active to configure or not SVQ */
+ r = vhost_net_start(vdev, n->nic->ncs, data_queue_pairs, cvq);
+ if (unlikely(r < 0)) {
+ error_report("unable to start vhost net: %s(%d)", g_strerror(-r), -r);
+ }
+}
+
+static void vdpa_net_migration_state_notifier(Notifier *notifier, void *data)
+{
+ MigrationState *migration = data;
+ VhostVDPAState *s = container_of(notifier, VhostVDPAState,
+ migration_state);
+
+ if (migration_in_setup(migration)) {
+ vhost_vdpa_net_log_global_enable(s, true);
+ } else if (migration_has_failed(migration)) {
+ vhost_vdpa_net_log_global_enable(s, false);
+ }
+}
+
+static void vhost_vdpa_net_data_start_first(VhostVDPAState *s)
+{
+ struct vhost_vdpa *v = &s->vhost_vdpa;
+
+ add_migration_state_change_notifier(&s->migration_state);
+ if (v->shadow_vqs_enabled) {
+ v->iova_tree = vhost_iova_tree_new(v->iova_range.first,
+ v->iova_range.last);
+ }
+}
+
+static int vhost_vdpa_net_data_start(NetClientState *nc)
+{
+ VhostVDPAState *s = DO_UPCAST(VhostVDPAState, nc, nc);
+ struct vhost_vdpa *v = &s->vhost_vdpa;
+
+ assert(nc->info->type == NET_CLIENT_DRIVER_VHOST_VDPA);
+
+ if (s->always_svq ||
+ migration_is_setup_or_active(migrate_get_current()->state)) {
+ v->shadow_vqs_enabled = true;
+ v->shadow_data = true;
+ } else {
+ v->shadow_vqs_enabled = false;
+ v->shadow_data = false;
+ }
+
+ if (v->index == 0) {
+ vhost_vdpa_net_data_start_first(s);
+ return 0;
+ }
+
+ if (v->shadow_vqs_enabled) {
+ VhostVDPAState *s0 = vhost_vdpa_net_first_nc_vdpa(s);
+ v->iova_tree = s0->vhost_vdpa.iova_tree;
+ }
+
+ return 0;
+}
+
+static void vhost_vdpa_net_client_stop(NetClientState *nc)
+{
+ VhostVDPAState *s = DO_UPCAST(VhostVDPAState, nc, nc);
+ struct vhost_dev *dev;
+
+ assert(nc->info->type == NET_CLIENT_DRIVER_VHOST_VDPA);
+
+ if (s->vhost_vdpa.index == 0) {
+ remove_migration_state_change_notifier(&s->migration_state);
+ }
+
+ dev = s->vhost_vdpa.dev;
+ if (dev->vq_index + dev->nvqs == dev->vq_index_end) {
+ g_clear_pointer(&s->vhost_vdpa.iova_tree, vhost_iova_tree_delete);
+ }
+}
+
static NetClientInfo net_vhost_vdpa_info = {
.type = NET_CLIENT_DRIVER_VHOST_VDPA,
.size = sizeof(VhostVDPAState),
.receive = vhost_vdpa_receive,
+ .start = vhost_vdpa_net_data_start,
+ .stop = vhost_vdpa_net_client_stop,
.cleanup = vhost_vdpa_cleanup,
.has_vnet_hdr = vhost_vdpa_has_vnet_hdr,
.has_ufo = vhost_vdpa_has_ufo,
@@ -351,7 +468,7 @@ dma_map_err:
static int vhost_vdpa_net_cvq_start(NetClientState *nc)
{
- VhostVDPAState *s;
+ VhostVDPAState *s, *s0;
struct vhost_vdpa *v;
uint64_t backend_features;
int64_t cvq_group;
@@ -362,11 +479,12 @@ static int vhost_vdpa_net_cvq_start(NetClientState *nc)
s = DO_UPCAST(VhostVDPAState, nc, nc);
v = &s->vhost_vdpa;
- v->shadow_data = s->always_svq;
+ s0 = vhost_vdpa_net_first_nc_vdpa(s);
+ v->shadow_data = s0->vhost_vdpa.shadow_vqs_enabled;
v->shadow_vqs_enabled = s->always_svq;
s->vhost_vdpa.address_space_id = VHOST_VDPA_GUEST_PA_ASID;
- if (s->always_svq) {
+ if (s->vhost_vdpa.shadow_data) {
/* SVQ is already configured for all virtqueues */
goto out;
}
@@ -415,8 +533,6 @@ static int vhost_vdpa_net_cvq_start(NetClientState *nc)
return r;
}
- v->iova_tree = vhost_iova_tree_new(v->iova_range.first,
- v->iova_range.last);
v->shadow_vqs_enabled = true;
s->vhost_vdpa.address_space_id = VHOST_VDPA_NET_CVQ_ASID;
@@ -425,6 +541,26 @@ out:
return 0;
}
+ if (s0->vhost_vdpa.iova_tree) {
+ /*
+ * SVQ is already configured for all virtqueues. Reuse IOVA tree for
+ * simplicity, whether CVQ shares ASID with guest or not, because:
+ * - Memory listener need access to guest's memory addresses allocated
+ * in the IOVA tree.
+ * - There should be plenty of IOVA address space for both ASID not to
+ * worry about collisions between them. Guest's translations are
+ * still validated with virtio virtqueue_pop so there is no risk for
+ * the guest to access memory that it shouldn't.
+ *
+ * To allocate a iova tree per ASID is doable but it complicates the
+ * code and it is not worth it for the moment.
+ */
+ v->iova_tree = s0->vhost_vdpa.iova_tree;
+ } else {
+ v->iova_tree = vhost_iova_tree_new(v->iova_range.first,
+ v->iova_range.last);
+ }
+
r = vhost_vdpa_cvq_map_buf(&s->vhost_vdpa, s->cvq_cmd_out_buffer,
vhost_vdpa_net_cvq_cmd_page_len(), false);
if (unlikely(r < 0)) {
@@ -449,15 +585,9 @@ static void vhost_vdpa_net_cvq_stop(NetClientState *nc)
if (s->vhost_vdpa.shadow_vqs_enabled) {
vhost_vdpa_cvq_unmap_buf(&s->vhost_vdpa, s->cvq_cmd_out_buffer);
vhost_vdpa_cvq_unmap_buf(&s->vhost_vdpa, s->status);
- if (!s->always_svq) {
- /*
- * If only the CVQ is shadowed we can delete this safely.
- * If all the VQs are shadows this will be needed by the time the
- * device is started again to register SVQ vrings and similar.
- */
- g_clear_pointer(&s->vhost_vdpa.iova_tree, vhost_iova_tree_delete);
- }
}
+
+ vhost_vdpa_net_client_stop(nc);
}
static ssize_t vhost_vdpa_net_cvq_add(VhostVDPAState *s, size_t out_len,
@@ -668,7 +798,7 @@ static NetClientState *net_vhost_vdpa_init(NetClientState *peer,
bool is_datapath,
bool svq,
struct vhost_vdpa_iova_range iova_range,
- VhostIOVATree *iova_tree)
+ uint64_t features)
{
NetClientState *nc = NULL;
VhostVDPAState *s;
@@ -687,11 +817,14 @@ static NetClientState *net_vhost_vdpa_init(NetClientState *peer,
s->vhost_vdpa.device_fd = vdpa_device_fd;
s->vhost_vdpa.index = queue_pair_index;
s->always_svq = svq;
+ s->migration_state.notify = vdpa_net_migration_state_notifier;
s->vhost_vdpa.shadow_vqs_enabled = svq;
s->vhost_vdpa.iova_range = iova_range;
s->vhost_vdpa.shadow_data = svq;
- s->vhost_vdpa.iova_tree = iova_tree;
- if (!is_datapath) {
+ if (queue_pair_index == 0) {
+ vhost_vdpa_net_valid_svq_features(features,
+ &s->vhost_vdpa.migration_blocker);
+ } else if (!is_datapath) {
s->cvq_cmd_out_buffer = qemu_memalign(qemu_real_host_page_size(),
vhost_vdpa_net_cvq_cmd_page_len());
memset(s->cvq_cmd_out_buffer, 0, vhost_vdpa_net_cvq_cmd_page_len());
@@ -701,6 +834,15 @@ static NetClientState *net_vhost_vdpa_init(NetClientState *peer,
s->vhost_vdpa.shadow_vq_ops = &vhost_vdpa_net_svq_ops;
s->vhost_vdpa.shadow_vq_ops_opaque = s;
+
+ /*
+ * TODO: We cannot migrate devices with CVQ as there is no way to set
+ * the device state (MAC, MQ, etc) before starting the datapath.
+ *
+ * Migration blocker ownership now belongs to s->vhost_vdpa.
+ */
+ error_setg(&s->vhost_vdpa.migration_blocker,
+ "net vdpa cannot migrate with CVQ feature");
}
ret = vhost_vdpa_add(nc, (void *)&s->vhost_vdpa, queue_pair_index, nvqs);
if (ret) {
@@ -760,7 +902,6 @@ int net_init_vhost_vdpa(const Netdev *netdev, const char *name,
uint64_t features;
int vdpa_device_fd;
g_autofree NetClientState **ncs = NULL;
- g_autoptr(VhostIOVATree) iova_tree = NULL;
struct vhost_vdpa_iova_range iova_range;
NetClientState *nc;
int queue_pairs, r, i = 0, has_cvq = 0;
@@ -812,12 +953,8 @@ int net_init_vhost_vdpa(const Netdev *netdev, const char *name,
goto err;
}
- if (opts->x_svq) {
- if (!vhost_vdpa_net_valid_svq_features(features, errp)) {
- goto err_svq;
- }
-
- iova_tree = vhost_iova_tree_new(iova_range.first, iova_range.last);
+ if (opts->x_svq && !vhost_vdpa_net_valid_svq_features(features, errp)) {
+ goto err;
}
ncs = g_malloc0(sizeof(*ncs) * queue_pairs);
@@ -825,7 +962,7 @@ int net_init_vhost_vdpa(const Netdev *netdev, const char *name,
for (i = 0; i < queue_pairs; i++) {
ncs[i] = net_vhost_vdpa_init(peer, TYPE_VHOST_VDPA, name,
vdpa_device_fd, i, 2, true, opts->x_svq,
- iova_range, iova_tree);
+ iova_range, features);
if (!ncs[i])
goto err;
}
@@ -833,13 +970,11 @@ int net_init_vhost_vdpa(const Netdev *netdev, const char *name,
if (has_cvq) {
nc = net_vhost_vdpa_init(peer, TYPE_VHOST_VDPA, name,
vdpa_device_fd, i, 1, false,
- opts->x_svq, iova_range, iova_tree);
+ opts->x_svq, iova_range, features);
if (!nc)
goto err;
}
- /* iova_tree ownership belongs to last NetClientState */
- g_steal_pointer(&iova_tree);
return 0;
err:
@@ -849,7 +984,6 @@ err:
}
}
-err_svq:
qemu_close(vdpa_device_fd);
return -1;
diff --git a/qapi/cryptodev.json b/qapi/cryptodev.json
new file mode 100644
index 0000000..f33f96a
--- /dev/null
+++ b/qapi/cryptodev.json
@@ -0,0 +1,89 @@
+# -*- Mode: Python -*-
+# vim: filetype=python
+#
+# This work is licensed under the terms of the GNU GPL, version 2 or later.
+# See the COPYING file in the top-level directory.
+
+##
+# @QCryptodevBackendAlgType:
+#
+# The supported algorithm types of a crypto device.
+#
+# @sym: symmetric encryption
+# @asym: asymmetric Encryption
+#
+# Since: 8.0
+##
+{ 'enum': 'QCryptodevBackendAlgType',
+ 'prefix': 'QCRYPTODEV_BACKEND_ALG',
+ 'data': ['sym', 'asym']}
+
+##
+# @QCryptodevBackendServiceType:
+#
+# The supported service types of a crypto device.
+#
+# Since: 8.0
+##
+{ 'enum': 'QCryptodevBackendServiceType',
+ 'prefix': 'QCRYPTODEV_BACKEND_SERVICE',
+ 'data': ['cipher', 'hash', 'mac', 'aead', 'akcipher']}
+
+##
+# @QCryptodevBackendType:
+#
+# The crypto device backend type
+#
+# @builtin: the QEMU builtin support
+# @vhost-user: vhost-user
+# @lkcf: Linux kernel cryptographic framework
+#
+# Since: 8.0
+##
+{ 'enum': 'QCryptodevBackendType',
+ 'prefix': 'QCRYPTODEV_BACKEND_TYPE',
+ 'data': ['builtin', 'vhost-user', 'lkcf']}
+
+##
+# @QCryptodevBackendClient:
+#
+# Information about a queue of crypto device.
+#
+# @queue: the queue index of the crypto device
+#
+# @type: the type of the crypto device
+#
+# Since: 8.0
+##
+{ 'struct': 'QCryptodevBackendClient',
+ 'data': { 'queue': 'uint32',
+ 'type': 'QCryptodevBackendType' } }
+
+##
+# @QCryptodevInfo:
+#
+# Information about a crypto device.
+#
+# @id: the id of the crypto device
+#
+# @service: supported service types of a crypto device
+#
+# @client: the additional infomation of the crypto device
+#
+# Since: 8.0
+##
+{ 'struct': 'QCryptodevInfo',
+ 'data': { 'id': 'str',
+ 'service': ['QCryptodevBackendServiceType'],
+ 'client': ['QCryptodevBackendClient'] } }
+
+##
+# @query-cryptodev:
+#
+# Returns information about current crypto devices.
+#
+# Returns: a list of @QCryptodevInfo
+#
+# Since: 8.0
+##
+{ 'command': 'query-cryptodev', 'returns': ['QCryptodevInfo']}
diff --git a/qapi/cxl.json b/qapi/cxl.json
new file mode 100644
index 0000000..4be7d46
--- /dev/null
+++ b/qapi/cxl.json
@@ -0,0 +1,128 @@
+# -*- Mode: Python -*-
+# vim: filetype=python
+
+##
+# = CXL devices
+##
+
+##
+# @CxlUncorErrorType:
+#
+# Type of uncorrectable CXL error to inject. These errors are reported via
+# an AER uncorrectable internal error with additional information logged at
+# the CXL device.
+#
+# @cache-data-parity: Data error such as data parity or data ECC error CXL.cache
+# @cache-address-parity: Address parity or other errors associated with the
+# address field on CXL.cache
+# @cache-be-parity: Byte enable parity or other byte enable errors on CXL.cache
+# @cache-data-ecc: ECC error on CXL.cache
+# @mem-data-parity: Data error such as data parity or data ECC error on CXL.mem
+# @mem-address-parity: Address parity or other errors associated with the
+# address field on CXL.mem
+# @mem-be-parity: Byte enable parity or other byte enable errors on CXL.mem.
+# @mem-data-ecc: Data ECC error on CXL.mem.
+# @reinit-threshold: REINIT threshold hit.
+# @rsvd-encoding: Received unrecognized encoding.
+# @poison-received: Received poison from the peer.
+# @receiver-overflow: Buffer overflows (first 3 bits of header log indicate which)
+# @internal: Component specific error
+# @cxl-ide-tx: Integrity and data encryption tx error.
+# @cxl-ide-rx: Integrity and data encryption rx error.
+#
+# Since: 8.0
+##
+
+{ 'enum': 'CxlUncorErrorType',
+ 'data': ['cache-data-parity',
+ 'cache-address-parity',
+ 'cache-be-parity',
+ 'cache-data-ecc',
+ 'mem-data-parity',
+ 'mem-address-parity',
+ 'mem-be-parity',
+ 'mem-data-ecc',
+ 'reinit-threshold',
+ 'rsvd-encoding',
+ 'poison-received',
+ 'receiver-overflow',
+ 'internal',
+ 'cxl-ide-tx',
+ 'cxl-ide-rx'
+ ]
+ }
+
+##
+# @CXLUncorErrorRecord:
+#
+# Record of a single error including header log.
+#
+# @type: Type of error
+# @header: 16 DWORD of header.
+#
+# Since: 8.0
+##
+{ 'struct': 'CXLUncorErrorRecord',
+ 'data': {
+ 'type': 'CxlUncorErrorType',
+ 'header': [ 'uint32' ]
+ }
+}
+
+##
+# @cxl-inject-uncorrectable-errors:
+#
+# Command to allow injection of multiple errors in one go. This allows testing
+# of multiple header log handling in the OS.
+#
+# @path: CXL Type 3 device canonical QOM path
+# @errors: Errors to inject
+#
+# Since: 8.0
+##
+{ 'command': 'cxl-inject-uncorrectable-errors',
+ 'data': { 'path': 'str',
+ 'errors': [ 'CXLUncorErrorRecord' ] }}
+
+##
+# @CxlCorErrorType:
+#
+# Type of CXL correctable error to inject
+#
+# @cache-data-ecc: Data ECC error on CXL.cache
+# @mem-data-ecc: Data ECC error on CXL.mem
+# @crc-threshold: Component specific and applicable to 68 byte Flit mode only.
+# @cache-poison-received: Received poison from a peer on CXL.cache.
+# @mem-poison-received: Received poison from a peer on CXL.mem
+# @physical: Received error indication from the physical layer.
+#
+# Since: 8.0
+##
+{ 'enum': 'CxlCorErrorType',
+ 'data': ['cache-data-ecc',
+ 'mem-data-ecc',
+ 'crc-threshold',
+ 'retry-threshold',
+ 'cache-poison-received',
+ 'mem-poison-received',
+ 'physical']
+}
+
+##
+# @cxl-inject-correctable-error:
+#
+# Command to inject a single correctable error. Multiple error injection
+# of this error type is not interesting as there is no associated header log.
+# These errors are reported via AER as a correctable internal error, with
+# additional detail available from the CXL device.
+#
+# @path: CXL Type 3 device canonical QOM path
+# @type: Type of error.
+#
+# Since: 8.0
+##
+{ 'command': 'cxl-inject-correctable-error',
+ 'data': { 'path': 'str',
+ 'type': 'CxlCorErrorType'
+ }
+}
diff --git a/qapi/meson.build b/qapi/meson.build
index fbdb442..9fd480c 100644
--- a/qapi/meson.build
+++ b/qapi/meson.build
@@ -31,6 +31,7 @@ qapi_all_modules = [
'compat',
'control',
'crypto',
+ 'cxl',
'dump',
'error',
'introspect',
@@ -56,6 +57,7 @@ if have_system
qapi_all_modules += [
'acpi',
'audio',
+ 'cryptodev',
'qdev',
'pci',
'rdma',
diff --git a/qapi/qapi-schema.json b/qapi/qapi-schema.json
index f000b90..7c09af5 100644
--- a/qapi/qapi-schema.json
+++ b/qapi/qapi-schema.json
@@ -95,3 +95,5 @@
{ 'include': 'pci.json' }
{ 'include': 'stats.json' }
{ 'include': 'virtio.json' }
+{ 'include': 'cryptodev.json' }
+{ 'include': 'cxl.json' }
diff --git a/qapi/qom.json b/qapi/qom.json
index 30e7665..a877b87 100644
--- a/qapi/qom.json
+++ b/qapi/qom.json
@@ -278,10 +278,16 @@
# cryptodev-backend and must be 1 for cryptodev-backend-builtin.
# (default: 1)
#
+# @throttle-bps: limit total bytes per second (Since 8.0)
+#
+# @throttle-ops: limit total operations per second (Since 8.0)
+#
# Since: 2.8
##
{ 'struct': 'CryptodevBackendProperties',
- 'data': { '*queues': 'uint32' } }
+ 'data': { '*queues': 'uint32',
+ '*throttle-bps': 'uint64',
+ '*throttle-ops': 'uint64' } }
##
# @CryptodevVhostUserProperties:
diff --git a/qapi/stats.json b/qapi/stats.json
index 57db5b1..1f5d3c5 100644
--- a/qapi/stats.json
+++ b/qapi/stats.json
@@ -50,10 +50,14 @@
#
# Enumeration of statistics providers.
#
+# @kvm: since 7.1
+#
+# @cryptodev: since 8.0
+#
# Since: 7.1
##
{ 'enum': 'StatsProvider',
- 'data': [ 'kvm' ] }
+ 'data': [ 'kvm', 'cryptodev' ] }
##
# @StatsTarget:
@@ -65,10 +69,12 @@
#
# @vcpu: statistics that apply to a single virtual CPU.
#
+# @cryptodev: statistics that apply to a crypto device. since 8.0
+#
# Since: 7.1
##
{ 'enum': 'StatsTarget',
- 'data': [ 'vm', 'vcpu' ] }
+ 'data': [ 'vm', 'vcpu', 'cryptodev' ] }
##
# @StatsRequest:
diff --git a/stats/stats-hmp-cmds.c b/stats/stats-hmp-cmds.c
index 531e35d..1f91bf8 100644
--- a/stats/stats-hmp-cmds.c
+++ b/stats/stats-hmp-cmds.c
@@ -155,6 +155,8 @@ static StatsFilter *stats_filter(StatsTarget target, const char *names,
filter->u.vcpu.vcpus = vcpu_list;
break;
}
+ case STATS_TARGET_CRYPTODEV:
+ break;
default:
break;
}
@@ -226,6 +228,9 @@ void hmp_info_stats(Monitor *mon, const QDict *qdict)
int cpu_index = monitor_get_cpu_index(mon);
filter = stats_filter(target, names, cpu_index, provider);
break;
+ case STATS_TARGET_CRYPTODEV:
+ filter = stats_filter(target, names, -1, provider);
+ break;
default:
abort();
}
diff --git a/stats/stats-qmp-cmds.c b/stats/stats-qmp-cmds.c
index bc97374..e214b96 100644
--- a/stats/stats-qmp-cmds.c
+++ b/stats/stats-qmp-cmds.c
@@ -64,6 +64,8 @@ static bool invoke_stats_cb(StatsCallbacks *entry,
targets = filter->u.vcpu.vcpus;
}
break;
+ case STATS_TARGET_CRYPTODEV:
+ break;
default:
abort();
}
diff --git a/tests/data/acpi/pc/DSDT b/tests/data/acpi/pc/DSDT
index 0b475fb..32d255c 100644
--- a/tests/data/acpi/pc/DSDT
+++ b/tests/data/acpi/pc/DSDT
Binary files differ
diff --git a/tests/data/acpi/pc/DSDT.acpierst b/tests/data/acpi/pc/DSDT.acpierst
index 17ef7ca..33e872b 100644
--- a/tests/data/acpi/pc/DSDT.acpierst
+++ b/tests/data/acpi/pc/DSDT.acpierst
Binary files differ
diff --git a/tests/data/acpi/pc/DSDT.acpihmat b/tests/data/acpi/pc/DSDT.acpihmat
index 675b674..cd84abc 100644
--- a/tests/data/acpi/pc/DSDT.acpihmat
+++ b/tests/data/acpi/pc/DSDT.acpihmat
Binary files differ
diff --git a/tests/data/acpi/pc/DSDT.bridge b/tests/data/acpi/pc/DSDT.bridge
index c1ce061..69a73ea 100644
--- a/tests/data/acpi/pc/DSDT.bridge
+++ b/tests/data/acpi/pc/DSDT.bridge
Binary files differ
diff --git a/tests/data/acpi/pc/DSDT.cphp b/tests/data/acpi/pc/DSDT.cphp
index 754ab85..2037905 100644
--- a/tests/data/acpi/pc/DSDT.cphp
+++ b/tests/data/acpi/pc/DSDT.cphp
Binary files differ
diff --git a/tests/data/acpi/pc/DSDT.dimmpxm b/tests/data/acpi/pc/DSDT.dimmpxm
index 1705033..435496e 100644
--- a/tests/data/acpi/pc/DSDT.dimmpxm
+++ b/tests/data/acpi/pc/DSDT.dimmpxm
Binary files differ
diff --git a/tests/data/acpi/pc/DSDT.hpbridge b/tests/data/acpi/pc/DSDT.hpbridge
index 834c270..b6eafab 100644
--- a/tests/data/acpi/pc/DSDT.hpbridge
+++ b/tests/data/acpi/pc/DSDT.hpbridge
Binary files differ
diff --git a/tests/data/acpi/pc/DSDT.hpbrroot b/tests/data/acpi/pc/DSDT.hpbrroot
index a71ed4f..a4073f3 100644
--- a/tests/data/acpi/pc/DSDT.hpbrroot
+++ b/tests/data/acpi/pc/DSDT.hpbrroot
Binary files differ
diff --git a/tests/data/acpi/pc/DSDT.ipmikcs b/tests/data/acpi/pc/DSDT.ipmikcs
index dd71356..06aa7bfd 100644
--- a/tests/data/acpi/pc/DSDT.ipmikcs
+++ b/tests/data/acpi/pc/DSDT.ipmikcs
Binary files differ
diff --git a/tests/data/acpi/pc/DSDT.memhp b/tests/data/acpi/pc/DSDT.memhp
index 2f895e9..10a0e44 100644
--- a/tests/data/acpi/pc/DSDT.memhp
+++ b/tests/data/acpi/pc/DSDT.memhp
Binary files differ
diff --git a/tests/data/acpi/pc/DSDT.nohpet b/tests/data/acpi/pc/DSDT.nohpet
index c012b63..6905312 100644
--- a/tests/data/acpi/pc/DSDT.nohpet
+++ b/tests/data/acpi/pc/DSDT.nohpet
Binary files differ
diff --git a/tests/data/acpi/pc/DSDT.numamem b/tests/data/acpi/pc/DSDT.numamem
index f2ef4b9..59e3133 100644
--- a/tests/data/acpi/pc/DSDT.numamem
+++ b/tests/data/acpi/pc/DSDT.numamem
Binary files differ
diff --git a/tests/data/acpi/pc/DSDT.roothp b/tests/data/acpi/pc/DSDT.roothp
index 657c826..448d596 100644
--- a/tests/data/acpi/pc/DSDT.roothp
+++ b/tests/data/acpi/pc/DSDT.roothp
Binary files differ
diff --git a/tests/data/acpi/q35/DSDT b/tests/data/acpi/q35/DSDT
index d68c472..720e8cb 100644
--- a/tests/data/acpi/q35/DSDT
+++ b/tests/data/acpi/q35/DSDT
Binary files differ
diff --git a/tests/data/acpi/q35/DSDT.acpierst b/tests/data/acpi/q35/DSDT.acpierst
index de7ae27..f26b1f2 100644
--- a/tests/data/acpi/q35/DSDT.acpierst
+++ b/tests/data/acpi/q35/DSDT.acpierst
Binary files differ
diff --git a/tests/data/acpi/q35/DSDT.acpihmat b/tests/data/acpi/q35/DSDT.acpihmat
index 48e2862..86771f1 100644
--- a/tests/data/acpi/q35/DSDT.acpihmat
+++ b/tests/data/acpi/q35/DSDT.acpihmat
Binary files differ
diff --git a/tests/data/acpi/q35/DSDT.acpihmat-noinitiator b/tests/data/acpi/q35/DSDT.acpihmat-noinitiator
index 30a4aa2..a894a2d 100644
--- a/tests/data/acpi/q35/DSDT.acpihmat-noinitiator
+++ b/tests/data/acpi/q35/DSDT.acpihmat-noinitiator
Binary files differ
diff --git a/tests/data/acpi/q35/DSDT.applesmc b/tests/data/acpi/q35/DSDT.applesmc
index 84e2b5c..276ae1d 100644
--- a/tests/data/acpi/q35/DSDT.applesmc
+++ b/tests/data/acpi/q35/DSDT.applesmc
Binary files differ
diff --git a/tests/data/acpi/q35/DSDT.bridge b/tests/data/acpi/q35/DSDT.bridge
index e411d40..9f8a208 100644
--- a/tests/data/acpi/q35/DSDT.bridge
+++ b/tests/data/acpi/q35/DSDT.bridge
Binary files differ
diff --git a/tests/data/acpi/q35/DSDT.core-count2 b/tests/data/acpi/q35/DSDT.core-count2
index 0603db8..2ec11fe 100644
--- a/tests/data/acpi/q35/DSDT.core-count2
+++ b/tests/data/acpi/q35/DSDT.core-count2
Binary files differ
diff --git a/tests/data/acpi/q35/DSDT.cphp b/tests/data/acpi/q35/DSDT.cphp
index beeb83c..612c85b 100644
--- a/tests/data/acpi/q35/DSDT.cphp
+++ b/tests/data/acpi/q35/DSDT.cphp
Binary files differ
diff --git a/tests/data/acpi/q35/DSDT.cxl b/tests/data/acpi/q35/DSDT.cxl
index 4586b9a..f049f41 100644
--- a/tests/data/acpi/q35/DSDT.cxl
+++ b/tests/data/acpi/q35/DSDT.cxl
Binary files differ
diff --git a/tests/data/acpi/q35/DSDT.dimmpxm b/tests/data/acpi/q35/DSDT.dimmpxm
index 99a93e1..23dabea 100644
--- a/tests/data/acpi/q35/DSDT.dimmpxm
+++ b/tests/data/acpi/q35/DSDT.dimmpxm
Binary files differ
diff --git a/tests/data/acpi/q35/DSDT.ipmibt b/tests/data/acpi/q35/DSDT.ipmibt
index 7f7601d..541bb70 100644
--- a/tests/data/acpi/q35/DSDT.ipmibt
+++ b/tests/data/acpi/q35/DSDT.ipmibt
Binary files differ
diff --git a/tests/data/acpi/q35/DSDT.ipmismbus b/tests/data/acpi/q35/DSDT.ipmismbus
index 6c5d1af..e2d57a3 100644
--- a/tests/data/acpi/q35/DSDT.ipmismbus
+++ b/tests/data/acpi/q35/DSDT.ipmismbus
Binary files differ
diff --git a/tests/data/acpi/q35/DSDT.ivrs b/tests/data/acpi/q35/DSDT.ivrs
index de7ae27..f26b1f2 100644
--- a/tests/data/acpi/q35/DSDT.ivrs
+++ b/tests/data/acpi/q35/DSDT.ivrs
Binary files differ
diff --git a/tests/data/acpi/q35/DSDT.memhp b/tests/data/acpi/q35/DSDT.memhp
index 79bce5c..809d7e2 100644
--- a/tests/data/acpi/q35/DSDT.memhp
+++ b/tests/data/acpi/q35/DSDT.memhp
Binary files differ
diff --git a/tests/data/acpi/q35/DSDT.mmio64 b/tests/data/acpi/q35/DSDT.mmio64
index c249929..ab3fe3c 100644
--- a/tests/data/acpi/q35/DSDT.mmio64
+++ b/tests/data/acpi/q35/DSDT.mmio64
Binary files differ
diff --git a/tests/data/acpi/q35/DSDT.multi-bridge b/tests/data/acpi/q35/DSDT.multi-bridge
index 66b39be..9ae8ee0 100644
--- a/tests/data/acpi/q35/DSDT.multi-bridge
+++ b/tests/data/acpi/q35/DSDT.multi-bridge
Binary files differ
diff --git a/tests/data/acpi/q35/DSDT.noacpihp b/tests/data/acpi/q35/DSDT.noacpihp
new file mode 100644
index 0000000..6ab1f0e
--- /dev/null
+++ b/tests/data/acpi/q35/DSDT.noacpihp
Binary files differ
diff --git a/tests/data/acpi/q35/DSDT.nohpet b/tests/data/acpi/q35/DSDT.nohpet
index 9ff9983..becb5f7 100644
--- a/tests/data/acpi/q35/DSDT.nohpet
+++ b/tests/data/acpi/q35/DSDT.nohpet
Binary files differ
diff --git a/tests/data/acpi/q35/DSDT.numamem b/tests/data/acpi/q35/DSDT.numamem
index 1e7c45e..0cdec0b 100644
--- a/tests/data/acpi/q35/DSDT.numamem
+++ b/tests/data/acpi/q35/DSDT.numamem
Binary files differ
diff --git a/tests/data/acpi/q35/DSDT.pvpanic-isa b/tests/data/acpi/q35/DSDT.pvpanic-isa
index ed47451..6a9904e 100644
--- a/tests/data/acpi/q35/DSDT.pvpanic-isa
+++ b/tests/data/acpi/q35/DSDT.pvpanic-isa
Binary files differ
diff --git a/tests/data/acpi/q35/DSDT.tis.tpm12 b/tests/data/acpi/q35/DSDT.tis.tpm12
index efc2efc..628bf62 100644
--- a/tests/data/acpi/q35/DSDT.tis.tpm12
+++ b/tests/data/acpi/q35/DSDT.tis.tpm12
Binary files differ
diff --git a/tests/data/acpi/q35/DSDT.tis.tpm2 b/tests/data/acpi/q35/DSDT.tis.tpm2
index 6753397..35c6b08 100644
--- a/tests/data/acpi/q35/DSDT.tis.tpm2
+++ b/tests/data/acpi/q35/DSDT.tis.tpm2
Binary files differ
diff --git a/tests/data/acpi/q35/DSDT.viot b/tests/data/acpi/q35/DSDT.viot
index eeb40b3..3ad4d26 100644
--- a/tests/data/acpi/q35/DSDT.viot
+++ b/tests/data/acpi/q35/DSDT.viot
Binary files differ
diff --git a/tests/data/acpi/q35/DSDT.xapic b/tests/data/acpi/q35/DSDT.xapic
index 3aa86f0..d4a34e2 100644
--- a/tests/data/acpi/q35/DSDT.xapic
+++ b/tests/data/acpi/q35/DSDT.xapic
Binary files differ
diff --git a/tests/qtest/bios-tables-test.c b/tests/qtest/bios-tables-test.c
index d29a4e4..76d5100 100644
--- a/tests/qtest/bios-tables-test.c
+++ b/tests/qtest/bios-tables-test.c
@@ -949,9 +949,14 @@ static void test_acpi_piix4_no_acpi_pci_hotplug(void)
data.required_struct_types_len = ARRAY_SIZE(base_required_struct_types);
test_acpi_one("-global PIIX4_PM.acpi-root-pci-hotplug=off "
"-global PIIX4_PM.acpi-pci-hotplug-with-bridge-support=off "
- "-device pci-bridge,chassis_nr=1 "
- "-device pci-testdev,bus=pci.0 "
- "-device pci-testdev,bus=pci.1", &data);
+ "-device pci-bridge,chassis_nr=1,addr=4.0 "
+ "-device pci-testdev,bus=pci.0,addr=5.0 "
+ "-device pci-testdev,bus=pci.0,addr=6.0,acpi-index=101 "
+ "-device pci-testdev,bus=pci.1,addr=1.0 "
+ "-device pci-testdev,bus=pci.1,addr=2.0,acpi-index=201 "
+ "-device pci-bridge,id=nhpbr,chassis_nr=2,shpc=off,addr=7.0 "
+ "-device pci-testdev,bus=nhpbr,addr=1.0,acpi-index=301 "
+ , &data);
free_test_data(&data);
}
@@ -1002,18 +1007,42 @@ static void test_acpi_q35_tcg_bridge(void)
free_test_data(&data);
}
+static void test_acpi_q35_tcg_no_acpi_hotplug(void)
+{
+ test_data data;
+
+ memset(&data, 0, sizeof(data));
+ data.machine = MACHINE_Q35;
+ data.variant = ".noacpihp";
+ data.required_struct_types = base_required_struct_types;
+ data.required_struct_types_len = ARRAY_SIZE(base_required_struct_types);
+ test_acpi_one("-global ICH9-LPC.acpi-pci-hotplug-with-bridge-support=off"
+ " -device pci-testdev,bus=pcie.0,acpi-index=101,addr=3.0"
+ " -device pci-bridge,chassis_nr=1,id=shpcbr,addr=4.0"
+ " -device pci-testdev,bus=shpcbr,addr=1.0,acpi-index=201"
+ " -device pci-bridge,chassis_nr=2,shpc=off,id=noshpcbr,addr=5.0"
+ " -device pci-testdev,bus=noshpcbr,addr=1.0,acpi-index=301"
+ " -device pcie-root-port,id=hprp,port=0x0,chassis=1,addr=6.0"
+ " -device pci-testdev,bus=hprp,acpi-index=401"
+ " -device pcie-root-port,id=nohprp,port=0x0,chassis=2,hotplug=off,"
+ "addr=7.0"
+ " -device pci-testdev,bus=nohprp,acpi-index=501"
+ " -device pcie-root-port,id=nohprpint,port=0x0,chassis=3,hotplug=off,"
+ "multifunction=on,addr=8.0"
+ " -device pci-testdev,bus=nohprpint,acpi-index=601,addr=8.1"
+ " -device pcie-root-port,id=hprp2,port=0x0,chassis=4,bus=nohprpint,"
+ "addr=9.0"
+ " -device pci-testdev,bus=hprp2,acpi-index=602"
+ , &data);
+ free_test_data(&data);
+}
+
static void test_acpi_q35_multif_bridge(void)
{
test_data data = {
.machine = MACHINE_Q35,
.variant = ".multi-bridge",
};
-
- if (!qtest_has_device("pcie-root-port")) {
- g_test_skip("Device pcie-root-port is not available");
- goto out;
- }
-
test_vm_prepare("-S"
" -device virtio-balloon,id=balloon0,addr=0x4.0x2"
" -device pcie-root-port,id=rp0,multifunction=on,"
@@ -1025,9 +1054,14 @@ static void test_acpi_q35_multif_bridge(void)
" -device pcie-root-port,id=rphptgt2,port=0x0,chassis=6,addr=2.2"
" -device pcie-root-port,id=rphptgt3,port=0x0,chassis=7,addr=2.3"
" -device pci-testdev,bus=pcie.0,addr=2.4"
+ " -device pci-testdev,bus=pcie.0,addr=2.5,acpi-index=102"
" -device pci-testdev,bus=pcie.0,addr=5.0"
+ " -device pci-testdev,bus=pcie.0,addr=0xf.0,acpi-index=101"
" -device pci-testdev,bus=rp0,addr=0.0"
- " -device pci-testdev,bus=br1", &data);
+ " -device pci-testdev,bus=br1"
+ " -device pcie-root-port,id=rpnohp,chassis=8,addr=0xA.0,hotplug=off"
+ " -device pcie-root-port,id=rp3,chassis=9,bus=rpnohp"
+ , &data);
/* hotplugged bridges section */
qtest_qmp_device_add(data.qts, "pci-bridge", "hpbr1",
@@ -1049,7 +1083,6 @@ static void test_acpi_q35_multif_bridge(void)
/* check that reboot/reset doesn't change any ACPI tables */
qtest_qmp_send(data.qts, "{'execute':'system_reset' }");
process_acpi_tables(&data);
-out:
free_test_data(&data);
}
@@ -1403,11 +1436,6 @@ static void test_acpi_tcg_dimm_pxm(const char *machine)
{
test_data data;
- if (!qtest_has_device("nvdimm")) {
- g_test_skip("Device nvdimm is not available");
- return;
- }
-
memset(&data, 0, sizeof(data));
data.machine = machine;
data.variant = ".dimmpxm";
@@ -1456,11 +1484,6 @@ static void test_acpi_virt_tcg_memhp(void)
.scan_len = 256ULL * 1024 * 1024,
};
- if (!qtest_has_device("nvdimm")) {
- g_test_skip("Device nvdimm is not available");
- goto out;
- }
-
data.variant = ".memhp";
test_acpi_one(" -machine nvdimm=on"
" -cpu cortex-a57"
@@ -1474,7 +1497,7 @@ static void test_acpi_virt_tcg_memhp(void)
" -device pc-dimm,id=dimm0,memdev=ram2,node=0"
" -device nvdimm,id=dimm1,memdev=nvm0,node=1",
&data);
-out:
+
free_test_data(&data);
}
@@ -1492,11 +1515,6 @@ static void test_acpi_microvm_tcg(void)
{
test_data data;
- if (!qtest_has_device("virtio-blk-device")) {
- g_test_skip("Device virtio-blk-device is not available");
- return;
- }
-
test_acpi_microvm_prepare(&data);
test_acpi_one(" -machine microvm,acpi=on,ioapic2=off,rtc=off",
&data);
@@ -1507,11 +1525,6 @@ static void test_acpi_microvm_usb_tcg(void)
{
test_data data;
- if (!qtest_has_device("virtio-blk-device")) {
- g_test_skip("Device virtio-blk-device is not available");
- return;
- }
-
test_acpi_microvm_prepare(&data);
data.variant = ".usb";
test_acpi_one(" -machine microvm,acpi=on,ioapic2=off,usb=on,rtc=off",
@@ -1523,11 +1536,6 @@ static void test_acpi_microvm_rtc_tcg(void)
{
test_data data;
- if (!qtest_has_device("virtio-blk-device")) {
- g_test_skip("Device virtio-blk-device is not available");
- return;
- }
-
test_acpi_microvm_prepare(&data);
data.variant = ".rtc";
test_acpi_one(" -machine microvm,acpi=on,ioapic2=off,rtc=on",
@@ -1539,11 +1547,6 @@ static void test_acpi_microvm_pcie_tcg(void)
{
test_data data;
- if (!qtest_has_device("virtio-blk-device")) {
- g_test_skip("Device virtio-blk-device is not available");
- return;
- }
-
test_acpi_microvm_prepare(&data);
data.variant = ".pcie";
data.tcg_only = true; /* need constant host-phys-bits */
@@ -1556,11 +1559,6 @@ static void test_acpi_microvm_ioapic2_tcg(void)
{
test_data data;
- if (!qtest_has_device("virtio-blk-device")) {
- g_test_skip("Device virtio-blk-device is not available");
- return;
- }
-
test_acpi_microvm_prepare(&data);
data.variant = ".ioapic2";
test_acpi_one(" -machine microvm,acpi=on,ioapic2=on,rtc=off",
@@ -1600,12 +1598,6 @@ static void test_acpi_virt_tcg_pxb(void)
.ram_start = 0x40000000ULL,
.scan_len = 128ULL * 1024 * 1024,
};
-
- if (!qtest_has_device("pcie-root-port")) {
- g_test_skip("Device pcie-root-port is not available");
- goto out;
- }
-
/*
* While using -cdrom, the cdrom would auto plugged into pxb-pcie,
* the reason is the bus of pxb-pcie is also root bus, it would lead
@@ -1624,7 +1616,7 @@ static void test_acpi_virt_tcg_pxb(void)
" -cpu cortex-a57"
" -device pxb-pcie,bus_nr=128",
&data);
-out:
+
free_test_data(&data);
}
@@ -1812,12 +1804,6 @@ static void test_acpi_microvm_acpi_erst(void)
gchar *params;
test_data data;
- if (!qtest_has_device("virtio-blk-device")) {
- g_test_skip("Device virtio-blk-device is not available");
- g_free(tmp_path);
- return;
- }
-
test_acpi_microvm_prepare(&data);
data.variant = ".pcie";
data.tcg_only = true; /* need constant host-phys-bits */
@@ -1878,11 +1864,6 @@ static void test_acpi_q35_viot(void)
.variant = ".viot",
};
- if (!qtest_has_device("virtio-iommu")) {
- g_test_skip("Device virtio-iommu is not available");
- goto out;
- }
-
/*
* To keep things interesting, two buses bypass the IOMMU.
* VIOT should only describes the other two buses.
@@ -1893,7 +1874,6 @@ static void test_acpi_q35_viot(void)
"-device pxb-pcie,bus_nr=0x20,id=pcie.200,bus=pcie.0,bypass_iommu=on "
"-device pxb-pcie,bus_nr=0x30,id=pcie.300,bus=pcie.0",
&data);
-out:
free_test_data(&data);
}
@@ -1954,10 +1934,8 @@ static void test_acpi_virt_viot(void)
.scan_len = 128ULL * 1024 * 1024,
};
- if (qtest_has_device("virtio-iommu")) {
- test_acpi_one("-cpu cortex-a57 "
- "-device virtio-iommu-pci", &data);
- }
+ test_acpi_one("-cpu cortex-a57 "
+ "-device virtio-iommu-pci", &data);
free_test_data(&data);
}
@@ -2066,11 +2044,6 @@ static void test_acpi_microvm_oem_fields(void)
test_data data;
char *args;
- if (!qtest_has_device("virtio-blk-device")) {
- g_test_skip("Device virtio-blk-device is not available");
- return;
- }
-
test_acpi_microvm_prepare(&data);
args = test_acpi_create_args(&data,
@@ -2161,6 +2134,8 @@ int main(int argc, char *argv[])
test_acpi_q35_tcg_tpm12_tis);
}
qtest_add_func("acpi/q35/bridge", test_acpi_q35_tcg_bridge);
+ qtest_add_func("acpi/q35/no-acpi-hotplug",
+ test_acpi_q35_tcg_no_acpi_hotplug);
qtest_add_func("acpi/q35/multif-bridge",
test_acpi_q35_multif_bridge);
qtest_add_func("acpi/q35/mmio64", test_acpi_q35_tcg_mmio64);