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:
Peter Maydell
2023-03-10 14:31:37 +00:00
97 changed files with 2039 additions and 472 deletions
+2
View File
@@ -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>
+25 -17
View File
@@ -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;
}
+54
View File
@@ -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);
}
+8 -11
View File
@@ -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;
+6 -7
View File
@@ -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;
+2 -2
View File
@@ -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
View File
File diff suppressed because it is too large Load Diff
+1
View File
@@ -1,5 +1,6 @@
softmmu_ss.add([files(
'cryptodev-builtin.c',
'cryptodev-hmp-cmds.c',
'cryptodev.c',
'hostmem-ram.c',
'hostmem.c',
+14
View File
@@ -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
+6 -3
View File
@@ -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
View File
@@ -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
View File
@@ -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
View File
@@ -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
View File
@@ -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;
+11 -9
View File
@@ -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
View File
@@ -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
View File
@@ -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);
}
}
+1
View File
@@ -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;
+294
View File
@@ -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);
+17
View File
@@ -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