mirror of
https://github.com/izzy2lost/xemu.git
synced 2026-07-06 00:20:22 -07:00
Merge tag 'for_upstream' of https://git.kernel.org/pub/scm/virt/kvm/mst/qemu into staging
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>
This commit is contained in:
@@ -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>
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
@@ -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;
|
||||
|
||||
@@ -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;
|
||||
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
}
|
||||
|
||||
+406
-27
File diff suppressed because it is too large
Load Diff
@@ -1,5 +1,6 @@
|
||||
softmmu_ss.add([files(
|
||||
'cryptodev-builtin.c',
|
||||
'cryptodev-hmp-cmds.c',
|
||||
'cryptodev.c',
|
||||
'hostmem-ram.c',
|
||||
'hostmem.c',
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
+13
-8
@@ -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);
|
||||
|
||||
+12
-2
@@ -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);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
+25
-87
@@ -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);
|
||||
|
||||
+22
-11
@@ -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;
|
||||
|
||||
@@ -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,
|
||||
|
||||
+19
-12
@@ -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];
|
||||
|
||||
+129
-50
@@ -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));
|
||||
build_append_pci_dsm_func0_common(ifctx, ret);
|
||||
|
||||
aml_append(ifctx, aml_store(zero, caps));
|
||||
|
||||
/*
|
||||
* PCI Firmware Specification 3.1
|
||||
* 4.6. _DSM Definitions for PCI
|
||||
*/
|
||||
UUID = aml_touuid("E5C937D0-3553-4D7A-9117-EA4D19C3434D");
|
||||
ifctx1 = aml_if(aml_lnot(aml_equal(aml_arg(0), UUID)));
|
||||
{
|
||||
/* call is for unsupported UUID, bail out */
|
||||
aml_append(ifctx1, aml_return(ret));
|
||||
}
|
||||
aml_append(ifctx, ifctx1);
|
||||
|
||||
ifctx1 = aml_if(aml_lless(rev, aml_int(2)));
|
||||
{
|
||||
/* call is for unsupported REV, bail out */
|
||||
aml_append(ifctx1, aml_return(ret));
|
||||
}
|
||||
aml_append(ifctx, ifctx1);
|
||||
|
||||
aml_append(ifctx,
|
||||
aml_store(aml_call2("AIDX", bnum, sunum), acpi_index));
|
||||
/*
|
||||
@@ -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);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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);
|
||||
|
||||
@@ -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");
|
||||
}
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user