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, cleanups CXL now can use Generic Port Affinity Structures. CXL now allows control of link speed and width vhost-user-blk now supports live resize, by means of a new device-sync-config command amd iommu now supports interrupt remapping pcie devices now report extended tag field support intel_iommu dropped support for Transient Mapping, to match VTD spec arch agnostic ACPI infrastructure for vCPU Hotplug Fixes, cleanups all over the place. Signed-off-by: Michael S. Tsirkin <mst@redhat.com> # -----BEGIN PGP SIGNATURE----- # # iQFDBAABCAAtFiEEXQn9CHHI+FuUyooNKB8NuNKNVGkFAmcpNqUPHG1zdEByZWRo # YXQuY29tAAoJECgfDbjSjVRp/2oH/0qO33prhDa48J5mqT9NuJzzYwp5QHKF9Zjv # fDAplMUEmfxZIEgJchcyDWPYTGX2geT4pCFhRWioZMIR/0JyzrFgSwsk1kL88cMh # 46gzhNVD6ybyPJ7O0Zq3GLy5jo7rlw/n+fFxKAuRCzcbK/fmH8gNC+RwW1IP64Na # HDczYilHUhnO7yKZFQzQNQVbK4BckrG1bu0Fcx0EMUQBf4V6x7GLOrT+3hkKYcr6 # +DG5DmUmv20or/FXnu2Ye+MzR8Ebx6JVK3A3sXEE4Ns2CCzK9QLzeeyc2aU13jWN # OpZ6WcKF8HqYprIwnSsMTxhPcq0/c7TvrGrazVwna5RUBMyjjvc= # =zSX4 # -----END PGP SIGNATURE----- # gpg: Signature made Mon 04 Nov 2024 21:03:33 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: (65 commits) intel_iommu: Add missed reserved bit check for IEC descriptor intel_iommu: Add missed sanity check for 256-bit invalidation queue intel_iommu: Send IQE event when setting reserved bit in IQT_TAIL hw/acpi: Update GED with vCPU Hotplug VMSD for migration tests/qtest/bios-tables-test: Update DSDT golden masters for x86/{pc,q35} hw/acpi: Update ACPI `_STA` method with QOM vCPU ACPI Hotplug states qtest: allow ACPI DSDT Table changes hw/acpi: Make CPUs ACPI `presence` conditional during vCPU hot-unplug hw/pci: Add parenthesis to PCI_BUILD_BDF macro hw/cxl: Ensure there is enough data to read the input header in cmd_get_physical_port_state() hw/cxl: Ensure there is enough data for the header in cmd_ccls_set_lsa() hw/cxl: Check that writes do not go beyond end of target attributes hw/cxl: Ensuring enough data to read parameters in cmd_tunnel_management_cmd() hw/cxl: Avoid accesses beyond the end of cel_log. hw/cxl: Check the length of data requested fits in get_log() hw/cxl: Check enough data in cmd_firmware_update_transfer() hw/cxl: Check input length is large enough in cmd_events_clear_records() hw/cxl: Check input includes at least the header in cmd_features_set_feature() hw/cxl: Check size of input data to dynamic capacity mailbox commands hw/cxl/cxl-mailbox-util: Fix output buffer index update when retrieving DC extents ... Signed-off-by: Peter Maydell <peter.maydell@linaro.org>
This commit is contained in:
+13
-11
@@ -167,6 +167,8 @@ A vring address description
|
||||
Note that a ring address is an IOVA if ``VIRTIO_F_IOMMU_PLATFORM`` has
|
||||
been negotiated. Otherwise it is a user address.
|
||||
|
||||
.. _memory_region_description:
|
||||
|
||||
Memory region description
|
||||
^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||
|
||||
@@ -180,7 +182,7 @@ Memory region description
|
||||
|
||||
:user address: a 64-bit user address
|
||||
|
||||
:mmap offset: 64-bit offset where region starts in the mapped memory
|
||||
:mmap offset: a 64-bit offset where region starts in the mapped memory
|
||||
|
||||
When the ``VHOST_USER_PROTOCOL_F_XEN_MMAP`` protocol feature has been
|
||||
successfully negotiated, the memory region description contains two extra
|
||||
@@ -190,7 +192,7 @@ fields at the end.
|
||||
| guest address | size | user address | mmap offset | xen mmap flags | domid |
|
||||
+---------------+------+--------------+-------------+----------------+-------+
|
||||
|
||||
:xen mmap flags: 32-bit bit field
|
||||
:xen mmap flags: a 32-bit bit field
|
||||
|
||||
- Bit 0 is set for Xen foreign memory mapping.
|
||||
- Bit 1 is set for Xen grant memory mapping.
|
||||
@@ -211,7 +213,7 @@ Single memory region description
|
||||
|
||||
:padding: 64-bit
|
||||
|
||||
A region is represented by Memory region description.
|
||||
:region: region is represented by :ref:`Memory region description <memory_region_description>`.
|
||||
|
||||
Multiple Memory regions description
|
||||
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||
@@ -224,7 +226,7 @@ Multiple Memory regions description
|
||||
|
||||
:padding: 32-bit
|
||||
|
||||
A region is represented by Memory region description.
|
||||
:regions: regions field contains 8 regions of type :ref:`Memory region description <memory_region_description>`.
|
||||
|
||||
Log description
|
||||
^^^^^^^^^^^^^^^
|
||||
@@ -233,9 +235,9 @@ Log description
|
||||
| log size | log offset |
|
||||
+----------+------------+
|
||||
|
||||
:log size: size of area used for logging
|
||||
:log size: a 64-bit size of area used for logging
|
||||
|
||||
:log offset: offset from start of supplied file descriptor where
|
||||
:log offset: a 64-bit offset from start of supplied file descriptor where
|
||||
logging starts (i.e. where guest address 0 would be
|
||||
logged)
|
||||
|
||||
@@ -382,7 +384,7 @@ the kernel implementation.
|
||||
|
||||
The communication consists of the *front-end* sending message requests and
|
||||
the *back-end* sending message replies. Most of the requests don't require
|
||||
replies. Here is a list of the ones that do:
|
||||
replies, except for the following requests:
|
||||
|
||||
* ``VHOST_USER_GET_FEATURES``
|
||||
* ``VHOST_USER_GET_PROTOCOL_FEATURES``
|
||||
@@ -1239,11 +1241,11 @@ Front-end message types
|
||||
(*a vring descriptor index for split virtqueues* vs. *vring descriptor
|
||||
indices for packed virtqueues*).
|
||||
|
||||
When and as long as all of a device’s vrings are stopped, it is
|
||||
When and as long as all of a device's vrings are stopped, it is
|
||||
*suspended*, see :ref:`Suspended device state
|
||||
<suspended_device_state>`.
|
||||
|
||||
The request payload’s *num* field is currently reserved and must be
|
||||
The request payload's *num* field is currently reserved and must be
|
||||
set to 0.
|
||||
|
||||
``VHOST_USER_SET_VRING_KICK``
|
||||
@@ -1662,7 +1664,7 @@ Front-end message types
|
||||
:reply payload: ``u64``
|
||||
|
||||
Front-end and back-end negotiate a channel over which to transfer the
|
||||
back-end’s internal state during migration. Either side (front-end or
|
||||
back-end's internal state during migration. Either side (front-end or
|
||||
back-end) may create the channel. The nature of this channel is not
|
||||
restricted or defined in this document, but whichever side creates it
|
||||
must create a file descriptor that is provided to the respectively
|
||||
@@ -1714,7 +1716,7 @@ Front-end message types
|
||||
:request payload: N/A
|
||||
:reply payload: ``u64``
|
||||
|
||||
After transferring the back-end’s internal state during migration (see
|
||||
After transferring the back-end's internal state during migration (see
|
||||
the :ref:`Migrating back-end state <migrating_backend_state>`
|
||||
section), check whether the back-end was able to successfully fully
|
||||
process the state.
|
||||
|
||||
@@ -1,148 +0,0 @@
|
||||
// SPDX-License-Identifier: GPL-2.0-only
|
||||
/*
|
||||
* Copyright (c) 2024, NVIDIA CORPORATION & AFFILIATES. All rights reserved
|
||||
*/
|
||||
|
||||
#include "qemu/osdep.h"
|
||||
#include "hw/acpi/acpi_generic_initiator.h"
|
||||
#include "hw/acpi/aml-build.h"
|
||||
#include "hw/boards.h"
|
||||
#include "hw/pci/pci_device.h"
|
||||
#include "qemu/error-report.h"
|
||||
|
||||
typedef struct AcpiGenericInitiatorClass {
|
||||
ObjectClass parent_class;
|
||||
} AcpiGenericInitiatorClass;
|
||||
|
||||
OBJECT_DEFINE_TYPE_WITH_INTERFACES(AcpiGenericInitiator, acpi_generic_initiator,
|
||||
ACPI_GENERIC_INITIATOR, OBJECT,
|
||||
{ TYPE_USER_CREATABLE },
|
||||
{ NULL })
|
||||
|
||||
OBJECT_DECLARE_SIMPLE_TYPE(AcpiGenericInitiator, ACPI_GENERIC_INITIATOR)
|
||||
|
||||
static void acpi_generic_initiator_init(Object *obj)
|
||||
{
|
||||
AcpiGenericInitiator *gi = ACPI_GENERIC_INITIATOR(obj);
|
||||
|
||||
gi->node = MAX_NODES;
|
||||
gi->pci_dev = NULL;
|
||||
}
|
||||
|
||||
static void acpi_generic_initiator_finalize(Object *obj)
|
||||
{
|
||||
AcpiGenericInitiator *gi = ACPI_GENERIC_INITIATOR(obj);
|
||||
|
||||
g_free(gi->pci_dev);
|
||||
}
|
||||
|
||||
static void acpi_generic_initiator_set_pci_device(Object *obj, const char *val,
|
||||
Error **errp)
|
||||
{
|
||||
AcpiGenericInitiator *gi = ACPI_GENERIC_INITIATOR(obj);
|
||||
|
||||
gi->pci_dev = g_strdup(val);
|
||||
}
|
||||
|
||||
static void acpi_generic_initiator_set_node(Object *obj, Visitor *v,
|
||||
const char *name, void *opaque,
|
||||
Error **errp)
|
||||
{
|
||||
AcpiGenericInitiator *gi = ACPI_GENERIC_INITIATOR(obj);
|
||||
MachineState *ms = MACHINE(qdev_get_machine());
|
||||
uint32_t value;
|
||||
|
||||
if (!visit_type_uint32(v, name, &value, errp)) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (value >= MAX_NODES) {
|
||||
error_printf("%s: Invalid NUMA node specified\n",
|
||||
TYPE_ACPI_GENERIC_INITIATOR);
|
||||
exit(1);
|
||||
}
|
||||
|
||||
gi->node = value;
|
||||
ms->numa_state->nodes[gi->node].has_gi = true;
|
||||
}
|
||||
|
||||
static void acpi_generic_initiator_class_init(ObjectClass *oc, void *data)
|
||||
{
|
||||
object_class_property_add_str(oc, "pci-dev", NULL,
|
||||
acpi_generic_initiator_set_pci_device);
|
||||
object_class_property_add(oc, "node", "int", NULL,
|
||||
acpi_generic_initiator_set_node, NULL, NULL);
|
||||
}
|
||||
|
||||
/*
|
||||
* ACPI 6.3:
|
||||
* Table 5-78 Generic Initiator Affinity Structure
|
||||
*/
|
||||
static void
|
||||
build_srat_generic_pci_initiator_affinity(GArray *table_data, int node,
|
||||
PCIDeviceHandle *handle)
|
||||
{
|
||||
uint8_t index;
|
||||
|
||||
build_append_int_noprefix(table_data, 5, 1); /* Type */
|
||||
build_append_int_noprefix(table_data, 32, 1); /* Length */
|
||||
build_append_int_noprefix(table_data, 0, 1); /* Reserved */
|
||||
build_append_int_noprefix(table_data, 1, 1); /* Device Handle Type: PCI */
|
||||
build_append_int_noprefix(table_data, node, 4); /* Proximity Domain */
|
||||
|
||||
/* Device Handle - PCI */
|
||||
build_append_int_noprefix(table_data, handle->segment, 2);
|
||||
build_append_int_noprefix(table_data, handle->bdf, 2);
|
||||
for (index = 0; index < 12; index++) {
|
||||
build_append_int_noprefix(table_data, 0, 1);
|
||||
}
|
||||
|
||||
build_append_int_noprefix(table_data, GEN_AFFINITY_ENABLED, 4); /* Flags */
|
||||
build_append_int_noprefix(table_data, 0, 4); /* Reserved */
|
||||
}
|
||||
|
||||
static int build_all_acpi_generic_initiators(Object *obj, void *opaque)
|
||||
{
|
||||
MachineState *ms = MACHINE(qdev_get_machine());
|
||||
AcpiGenericInitiator *gi;
|
||||
GArray *table_data = opaque;
|
||||
PCIDeviceHandle dev_handle;
|
||||
PCIDevice *pci_dev;
|
||||
Object *o;
|
||||
|
||||
if (!object_dynamic_cast(obj, TYPE_ACPI_GENERIC_INITIATOR)) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
gi = ACPI_GENERIC_INITIATOR(obj);
|
||||
if (gi->node >= ms->numa_state->num_nodes) {
|
||||
error_printf("%s: Specified node %d is invalid.\n",
|
||||
TYPE_ACPI_GENERIC_INITIATOR, gi->node);
|
||||
exit(1);
|
||||
}
|
||||
|
||||
o = object_resolve_path_type(gi->pci_dev, TYPE_PCI_DEVICE, NULL);
|
||||
if (!o) {
|
||||
error_printf("%s: Specified device must be a PCI device.\n",
|
||||
TYPE_ACPI_GENERIC_INITIATOR);
|
||||
exit(1);
|
||||
}
|
||||
|
||||
pci_dev = PCI_DEVICE(o);
|
||||
|
||||
dev_handle.segment = 0;
|
||||
dev_handle.bdf = PCI_BUILD_BDF(pci_bus_num(pci_get_bus(pci_dev)),
|
||||
pci_dev->devfn);
|
||||
|
||||
build_srat_generic_pci_initiator_affinity(table_data,
|
||||
gi->node, &dev_handle);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
void build_srat_generic_pci_initiator(GArray *table_data)
|
||||
{
|
||||
object_child_foreach_recursive(object_get_root(),
|
||||
build_all_acpi_generic_initiators,
|
||||
table_data);
|
||||
}
|
||||
@@ -1937,6 +1937,89 @@ void build_srat_memory(GArray *table_data, uint64_t base,
|
||||
build_append_int_noprefix(table_data, 0, 8); /* Reserved */
|
||||
}
|
||||
|
||||
/*
|
||||
* ACPI Spec Revision 6.3
|
||||
* Table 5-80 Device Handle - PCI
|
||||
*/
|
||||
static void build_append_srat_pci_device_handle(GArray *table_data,
|
||||
uint16_t segment,
|
||||
uint8_t bus, uint8_t devfn)
|
||||
{
|
||||
/* PCI segment number */
|
||||
build_append_int_noprefix(table_data, segment, 2);
|
||||
/* PCI Bus Device Function */
|
||||
build_append_int_noprefix(table_data, bus, 1);
|
||||
build_append_int_noprefix(table_data, devfn, 1);
|
||||
/* Reserved */
|
||||
build_append_int_noprefix(table_data, 0, 12);
|
||||
}
|
||||
|
||||
static void build_append_srat_acpi_device_handle(GArray *table_data,
|
||||
const char *hid,
|
||||
uint32_t uid)
|
||||
{
|
||||
assert(strlen(hid) == 8);
|
||||
/* Device Handle - ACPI */
|
||||
for (int i = 0; i < sizeof(hid); i++) {
|
||||
build_append_int_noprefix(table_data, hid[i], 1);
|
||||
}
|
||||
build_append_int_noprefix(table_data, uid, 4);
|
||||
build_append_int_noprefix(table_data, 0, 4);
|
||||
}
|
||||
|
||||
/*
|
||||
* ACPI spec, Revision 6.3
|
||||
* 5.2.16.6 Generic Initiator Affinity Structure
|
||||
* With PCI Device Handle.
|
||||
*/
|
||||
void build_srat_pci_generic_initiator(GArray *table_data, uint32_t node,
|
||||
uint16_t segment, uint8_t bus,
|
||||
uint8_t devfn)
|
||||
{
|
||||
/* Type */
|
||||
build_append_int_noprefix(table_data, 5, 1);
|
||||
/* Length */
|
||||
build_append_int_noprefix(table_data, 32, 1);
|
||||
/* Reserved */
|
||||
build_append_int_noprefix(table_data, 0, 1);
|
||||
/* Device Handle Type: PCI */
|
||||
build_append_int_noprefix(table_data, 1, 1);
|
||||
/* Proximity Domain */
|
||||
build_append_int_noprefix(table_data, node, 4);
|
||||
/* Device Handle */
|
||||
build_append_srat_pci_device_handle(table_data, segment, bus, devfn);
|
||||
/* Flags - GI Enabled */
|
||||
build_append_int_noprefix(table_data, 1, 4);
|
||||
/* Reserved */
|
||||
build_append_int_noprefix(table_data, 0, 4);
|
||||
}
|
||||
|
||||
/*
|
||||
* ACPI spec, Revision 6.5
|
||||
* 5.2.16.7 Generic Port Affinity Structure
|
||||
* With ACPI Device Handle.
|
||||
*/
|
||||
void build_srat_acpi_generic_port(GArray *table_data, uint32_t node,
|
||||
const char *hid, uint32_t uid)
|
||||
{
|
||||
/* Type */
|
||||
build_append_int_noprefix(table_data, 6, 1);
|
||||
/* Length */
|
||||
build_append_int_noprefix(table_data, 32, 1);
|
||||
/* Reserved */
|
||||
build_append_int_noprefix(table_data, 0, 1);
|
||||
/* Device Handle Type: ACPI */
|
||||
build_append_int_noprefix(table_data, 0, 1);
|
||||
/* Proximity Domain */
|
||||
build_append_int_noprefix(table_data, node, 4);
|
||||
/* Device Handle */
|
||||
build_append_srat_acpi_device_handle(table_data, hid, uid);
|
||||
/* Flags - GP Enabled */
|
||||
build_append_int_noprefix(table_data, 1, 4);
|
||||
/* Reserved */
|
||||
build_append_int_noprefix(table_data, 0, 4);
|
||||
}
|
||||
|
||||
/*
|
||||
* ACPI spec 5.2.17 System Locality Distance Information Table
|
||||
* (Revision 2.0 or later)
|
||||
|
||||
+48
-5
@@ -50,6 +50,18 @@ void acpi_cpu_ospm_status(CPUHotplugState *cpu_st, ACPIOSTInfoList ***list)
|
||||
}
|
||||
}
|
||||
|
||||
static bool check_cpu_enabled_status(DeviceState *dev)
|
||||
{
|
||||
CPUClass *k = dev ? CPU_GET_CLASS(dev) : NULL;
|
||||
CPUState *cpu = CPU(dev);
|
||||
|
||||
if (cpu && (!k->cpu_enabled_status || k->cpu_enabled_status(cpu))) {
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
static uint64_t cpu_hotplug_rd(void *opaque, hwaddr addr, unsigned size)
|
||||
{
|
||||
uint64_t val = 0;
|
||||
@@ -63,10 +75,11 @@ static uint64_t cpu_hotplug_rd(void *opaque, hwaddr addr, unsigned size)
|
||||
cdev = &cpu_st->devs[cpu_st->selector];
|
||||
switch (addr) {
|
||||
case ACPI_CPU_FLAGS_OFFSET_RW: /* pack and return is_* fields */
|
||||
val |= cdev->cpu ? 1 : 0;
|
||||
val |= check_cpu_enabled_status(DEVICE(cdev->cpu)) ? 1 : 0;
|
||||
val |= cdev->is_inserting ? 2 : 0;
|
||||
val |= cdev->is_removing ? 4 : 0;
|
||||
val |= cdev->fw_remove ? 16 : 0;
|
||||
val |= cdev->cpu ? 32 : 0;
|
||||
trace_cpuhp_acpi_read_flags(cpu_st->selector, val);
|
||||
break;
|
||||
case ACPI_CPU_CMD_DATA_OFFSET_RW:
|
||||
@@ -233,6 +246,17 @@ void cpu_hotplug_hw_init(MemoryRegion *as, Object *owner,
|
||||
memory_region_add_subregion(as, base_addr, &state->ctrl_reg);
|
||||
}
|
||||
|
||||
static bool should_remain_acpi_present(DeviceState *dev)
|
||||
{
|
||||
CPUClass *k = CPU_GET_CLASS(dev);
|
||||
/*
|
||||
* A system may contain CPUs that are always present on one die, NUMA node,
|
||||
* or socket, yet may be non-present on another simultaneously. Check from
|
||||
* architecture specific code.
|
||||
*/
|
||||
return k->cpu_persistent_status && k->cpu_persistent_status(CPU(dev));
|
||||
}
|
||||
|
||||
static AcpiCpuStatus *get_cpu_status(CPUHotplugState *cpu_st, DeviceState *dev)
|
||||
{
|
||||
CPUClass *k = CPU_GET_CLASS(dev);
|
||||
@@ -289,7 +313,9 @@ void acpi_cpu_unplug_cb(CPUHotplugState *cpu_st,
|
||||
return;
|
||||
}
|
||||
|
||||
cdev->cpu = NULL;
|
||||
if (!should_remain_acpi_present(dev)) {
|
||||
cdev->cpu = NULL;
|
||||
}
|
||||
}
|
||||
|
||||
static const VMStateDescription vmstate_cpuhp_sts = {
|
||||
@@ -336,6 +362,7 @@ const VMStateDescription vmstate_cpu_hotplug = {
|
||||
#define CPU_REMOVE_EVENT "CRMV"
|
||||
#define CPU_EJECT_EVENT "CEJ0"
|
||||
#define CPU_FW_EJECT_EVENT "CEJF"
|
||||
#define CPU_PRESENT "CPRS"
|
||||
|
||||
void build_cpus_aml(Aml *table, MachineState *machine, CPUHotplugFeatures opts,
|
||||
build_madt_cpu_fn build_madt_cpu, hwaddr base_addr,
|
||||
@@ -396,7 +423,9 @@ void build_cpus_aml(Aml *table, MachineState *machine, CPUHotplugFeatures opts,
|
||||
aml_append(field, aml_named_field(CPU_EJECT_EVENT, 1));
|
||||
/* tell firmware to do device eject, write only */
|
||||
aml_append(field, aml_named_field(CPU_FW_EJECT_EVENT, 1));
|
||||
aml_append(field, aml_reserved_field(3));
|
||||
/* 1 if present, read only */
|
||||
aml_append(field, aml_named_field(CPU_PRESENT, 1));
|
||||
aml_append(field, aml_reserved_field(2));
|
||||
aml_append(field, aml_named_field(CPU_COMMAND, 8));
|
||||
aml_append(cpu_ctrl_dev, field);
|
||||
|
||||
@@ -426,6 +455,7 @@ void build_cpus_aml(Aml *table, MachineState *machine, CPUHotplugFeatures opts,
|
||||
Aml *ctrl_lock = aml_name("%s.%s", cphp_res_path, CPU_LOCK);
|
||||
Aml *cpu_selector = aml_name("%s.%s", cphp_res_path, CPU_SELECTOR);
|
||||
Aml *is_enabled = aml_name("%s.%s", cphp_res_path, CPU_ENABLED);
|
||||
Aml *is_present = aml_name("%s.%s", cphp_res_path, CPU_PRESENT);
|
||||
Aml *cpu_cmd = aml_name("%s.%s", cphp_res_path, CPU_COMMAND);
|
||||
Aml *cpu_data = aml_name("%s.%s", cphp_res_path, CPU_DATA);
|
||||
Aml *ins_evt = aml_name("%s.%s", cphp_res_path, CPU_INSERT_EVENT);
|
||||
@@ -454,13 +484,26 @@ void build_cpus_aml(Aml *table, MachineState *machine, CPUHotplugFeatures opts,
|
||||
{
|
||||
Aml *idx = aml_arg(0);
|
||||
Aml *sta = aml_local(0);
|
||||
Aml *ifctx2;
|
||||
Aml *else_ctx;
|
||||
|
||||
aml_append(method, aml_acquire(ctrl_lock, 0xFFFF));
|
||||
aml_append(method, aml_store(idx, cpu_selector));
|
||||
aml_append(method, aml_store(zero, sta));
|
||||
ifctx = aml_if(aml_equal(is_enabled, one));
|
||||
ifctx = aml_if(aml_equal(is_present, one));
|
||||
{
|
||||
aml_append(ifctx, aml_store(aml_int(0xF), sta));
|
||||
ifctx2 = aml_if(aml_equal(is_enabled, one));
|
||||
{
|
||||
/* cpu is present and enabled */
|
||||
aml_append(ifctx2, aml_store(aml_int(0xF), sta));
|
||||
}
|
||||
aml_append(ifctx, ifctx2);
|
||||
else_ctx = aml_else();
|
||||
{
|
||||
/* cpu is present but disabled */
|
||||
aml_append(else_ctx, aml_store(aml_int(0xD), sta));
|
||||
}
|
||||
aml_append(ifctx, else_ctx);
|
||||
}
|
||||
aml_append(method, ifctx);
|
||||
aml_append(method, aml_release(ctrl_lock));
|
||||
|
||||
@@ -331,6 +331,24 @@ static const VMStateDescription vmstate_memhp_state = {
|
||||
}
|
||||
};
|
||||
|
||||
static bool cpuhp_needed(void *opaque)
|
||||
{
|
||||
MachineClass *mc = MACHINE_GET_CLASS(qdev_get_machine());
|
||||
|
||||
return mc->has_hotpluggable_cpus;
|
||||
}
|
||||
|
||||
static const VMStateDescription vmstate_cpuhp_state = {
|
||||
.name = "acpi-ged/cpuhp",
|
||||
.version_id = 1,
|
||||
.minimum_version_id = 1,
|
||||
.needed = cpuhp_needed,
|
||||
.fields = (VMStateField[]) {
|
||||
VMSTATE_CPU_HOTPLUG(cpuhp_state, AcpiGedState),
|
||||
VMSTATE_END_OF_LIST()
|
||||
}
|
||||
};
|
||||
|
||||
static const VMStateDescription vmstate_ged_state = {
|
||||
.name = "acpi-ged-state",
|
||||
.version_id = 1,
|
||||
@@ -379,6 +397,7 @@ static const VMStateDescription vmstate_acpi_ged = {
|
||||
},
|
||||
.subsections = (const VMStateDescription * const []) {
|
||||
&vmstate_memhp_state,
|
||||
&vmstate_cpuhp_state,
|
||||
&vmstate_ghes_state,
|
||||
NULL
|
||||
}
|
||||
|
||||
@@ -1,6 +1,5 @@
|
||||
acpi_ss = ss.source_set()
|
||||
acpi_ss.add(files(
|
||||
'acpi_generic_initiator.c',
|
||||
'acpi_interface.c',
|
||||
'aml-build.c',
|
||||
'bios-linker-loader.c',
|
||||
|
||||
+242
@@ -24,8 +24,14 @@
|
||||
*/
|
||||
|
||||
#include "qemu/osdep.h"
|
||||
#include "qemu/error-report.h"
|
||||
#include "qom/object_interfaces.h"
|
||||
#include "qapi/error.h"
|
||||
#include "hw/boards.h"
|
||||
#include "hw/acpi/aml-build.h"
|
||||
#include "hw/acpi/pci.h"
|
||||
#include "hw/pci/pci_bridge.h"
|
||||
#include "hw/pci/pci_device.h"
|
||||
#include "hw/pci/pcie_host.h"
|
||||
|
||||
/*
|
||||
@@ -59,3 +65,239 @@ void build_mcfg(GArray *table_data, BIOSLinker *linker, AcpiMcfgInfo *info,
|
||||
|
||||
acpi_table_end(linker, &table);
|
||||
}
|
||||
|
||||
typedef struct AcpiGenericInitiator {
|
||||
/* private */
|
||||
Object parent;
|
||||
|
||||
/* public */
|
||||
char *pci_dev;
|
||||
uint32_t node;
|
||||
} AcpiGenericInitiator;
|
||||
|
||||
typedef struct AcpiGenericInitiatorClass {
|
||||
ObjectClass parent_class;
|
||||
} AcpiGenericInitiatorClass;
|
||||
|
||||
#define TYPE_ACPI_GENERIC_INITIATOR "acpi-generic-initiator"
|
||||
|
||||
OBJECT_DEFINE_TYPE_WITH_INTERFACES(AcpiGenericInitiator, acpi_generic_initiator,
|
||||
ACPI_GENERIC_INITIATOR, OBJECT,
|
||||
{ TYPE_USER_CREATABLE },
|
||||
{ NULL })
|
||||
|
||||
OBJECT_DECLARE_SIMPLE_TYPE(AcpiGenericInitiator, ACPI_GENERIC_INITIATOR)
|
||||
|
||||
static void acpi_generic_initiator_init(Object *obj)
|
||||
{
|
||||
AcpiGenericInitiator *gi = ACPI_GENERIC_INITIATOR(obj);
|
||||
|
||||
gi->node = MAX_NODES;
|
||||
gi->pci_dev = NULL;
|
||||
}
|
||||
|
||||
static void acpi_generic_initiator_finalize(Object *obj)
|
||||
{
|
||||
AcpiGenericInitiator *gi = ACPI_GENERIC_INITIATOR(obj);
|
||||
|
||||
g_free(gi->pci_dev);
|
||||
}
|
||||
|
||||
static void acpi_generic_initiator_set_pci_device(Object *obj, const char *val,
|
||||
Error **errp)
|
||||
{
|
||||
AcpiGenericInitiator *gi = ACPI_GENERIC_INITIATOR(obj);
|
||||
|
||||
gi->pci_dev = g_strdup(val);
|
||||
}
|
||||
|
||||
static void acpi_generic_initiator_set_node(Object *obj, Visitor *v,
|
||||
const char *name, void *opaque,
|
||||
Error **errp)
|
||||
{
|
||||
AcpiGenericInitiator *gi = ACPI_GENERIC_INITIATOR(obj);
|
||||
MachineState *ms = MACHINE(qdev_get_machine());
|
||||
uint32_t value;
|
||||
|
||||
if (!visit_type_uint32(v, name, &value, errp)) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (value >= MAX_NODES) {
|
||||
error_printf("%s: Invalid NUMA node specified\n",
|
||||
TYPE_ACPI_GENERIC_INITIATOR);
|
||||
exit(1);
|
||||
}
|
||||
|
||||
gi->node = value;
|
||||
ms->numa_state->nodes[gi->node].has_gi = true;
|
||||
}
|
||||
|
||||
static void acpi_generic_initiator_class_init(ObjectClass *oc, void *data)
|
||||
{
|
||||
object_class_property_add_str(oc, "pci-dev", NULL,
|
||||
acpi_generic_initiator_set_pci_device);
|
||||
object_class_property_set_description(oc, "pci-dev",
|
||||
"PCI device to associate with the node");
|
||||
object_class_property_add(oc, "node", "int", NULL,
|
||||
acpi_generic_initiator_set_node, NULL, NULL);
|
||||
object_class_property_set_description(oc, "node",
|
||||
"NUMA node associated with the PCI device");
|
||||
}
|
||||
|
||||
static int build_acpi_generic_initiator(Object *obj, void *opaque)
|
||||
{
|
||||
MachineState *ms = MACHINE(qdev_get_machine());
|
||||
AcpiGenericInitiator *gi;
|
||||
GArray *table_data = opaque;
|
||||
int32_t devfn;
|
||||
uint8_t bus;
|
||||
Object *o;
|
||||
|
||||
if (!object_dynamic_cast(obj, TYPE_ACPI_GENERIC_INITIATOR)) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
gi = ACPI_GENERIC_INITIATOR(obj);
|
||||
if (gi->node >= ms->numa_state->num_nodes) {
|
||||
error_printf("%s: Specified node %d is invalid.\n",
|
||||
TYPE_ACPI_GENERIC_INITIATOR, gi->node);
|
||||
exit(1);
|
||||
}
|
||||
|
||||
o = object_resolve_path_type(gi->pci_dev, TYPE_PCI_DEVICE, NULL);
|
||||
if (!o) {
|
||||
error_printf("%s: Specified device must be a PCI device.\n",
|
||||
TYPE_ACPI_GENERIC_INITIATOR);
|
||||
exit(1);
|
||||
}
|
||||
|
||||
bus = object_property_get_uint(o, "busnr", &error_fatal);
|
||||
devfn = object_property_get_uint(o, "addr", &error_fatal);
|
||||
/* devfn is constrained in PCI to be 8 bit but storage is an int32_t */
|
||||
assert(devfn >= 0 && devfn < PCI_DEVFN_MAX);
|
||||
|
||||
build_srat_pci_generic_initiator(table_data, gi->node, 0, bus, devfn);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
typedef struct AcpiGenericPort {
|
||||
/* private */
|
||||
Object parent;
|
||||
|
||||
/* public */
|
||||
char *pci_bus;
|
||||
uint32_t node;
|
||||
} AcpiGenericPort;
|
||||
|
||||
typedef struct AcpiGenericPortClass {
|
||||
ObjectClass parent_class;
|
||||
} AcpiGenericPortClass;
|
||||
|
||||
#define TYPE_ACPI_GENERIC_PORT "acpi-generic-port"
|
||||
|
||||
OBJECT_DEFINE_TYPE_WITH_INTERFACES(AcpiGenericPort, acpi_generic_port,
|
||||
ACPI_GENERIC_PORT, OBJECT,
|
||||
{ TYPE_USER_CREATABLE },
|
||||
{ NULL })
|
||||
|
||||
OBJECT_DECLARE_SIMPLE_TYPE(AcpiGenericPort, ACPI_GENERIC_PORT)
|
||||
|
||||
static void acpi_generic_port_init(Object *obj)
|
||||
{
|
||||
AcpiGenericPort *gp = ACPI_GENERIC_PORT(obj);
|
||||
|
||||
gp->node = MAX_NODES;
|
||||
gp->pci_bus = NULL;
|
||||
}
|
||||
|
||||
static void acpi_generic_port_finalize(Object *obj)
|
||||
{
|
||||
AcpiGenericPort *gp = ACPI_GENERIC_PORT(obj);
|
||||
|
||||
g_free(gp->pci_bus);
|
||||
}
|
||||
|
||||
static void acpi_generic_port_set_pci_bus(Object *obj, const char *val,
|
||||
Error **errp)
|
||||
{
|
||||
AcpiGenericPort *gp = ACPI_GENERIC_PORT(obj);
|
||||
|
||||
gp->pci_bus = g_strdup(val);
|
||||
}
|
||||
|
||||
static void acpi_generic_port_set_node(Object *obj, Visitor *v,
|
||||
const char *name, void *opaque,
|
||||
Error **errp)
|
||||
{
|
||||
AcpiGenericPort *gp = ACPI_GENERIC_PORT(obj);
|
||||
uint32_t value;
|
||||
|
||||
if (!visit_type_uint32(v, name, &value, errp)) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (value >= MAX_NODES) {
|
||||
error_printf("%s: Invalid NUMA node specified\n",
|
||||
TYPE_ACPI_GENERIC_INITIATOR);
|
||||
exit(1);
|
||||
}
|
||||
|
||||
gp->node = value;
|
||||
}
|
||||
|
||||
static void acpi_generic_port_class_init(ObjectClass *oc, void *data)
|
||||
{
|
||||
object_class_property_add_str(oc, "pci-bus", NULL,
|
||||
acpi_generic_port_set_pci_bus);
|
||||
object_class_property_set_description(oc, "pci-bus",
|
||||
"PCI Bus of the host bridge associated with this GP affinity structure");
|
||||
object_class_property_add(oc, "node", "int", NULL,
|
||||
acpi_generic_port_set_node, NULL, NULL);
|
||||
object_class_property_set_description(oc, "node",
|
||||
"The NUMA node like ID to index HMAT/SLIT NUMA properties involving GP");
|
||||
}
|
||||
|
||||
static int build_acpi_generic_port(Object *obj, void *opaque)
|
||||
{
|
||||
MachineState *ms = MACHINE(qdev_get_machine());
|
||||
const char *hid = "ACPI0016";
|
||||
GArray *table_data = opaque;
|
||||
AcpiGenericPort *gp;
|
||||
uint32_t uid;
|
||||
Object *o;
|
||||
|
||||
if (!object_dynamic_cast(obj, TYPE_ACPI_GENERIC_PORT)) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
gp = ACPI_GENERIC_PORT(obj);
|
||||
|
||||
if (gp->node >= ms->numa_state->num_nodes) {
|
||||
error_printf("%s: node %d is invalid.\n",
|
||||
TYPE_ACPI_GENERIC_PORT, gp->node);
|
||||
exit(1);
|
||||
}
|
||||
|
||||
o = object_resolve_path_type(gp->pci_bus, TYPE_PXB_CXL_BUS, NULL);
|
||||
if (!o) {
|
||||
error_printf("%s: device must be a CXL host bridge.\n",
|
||||
TYPE_ACPI_GENERIC_PORT);
|
||||
exit(1);
|
||||
}
|
||||
|
||||
uid = object_property_get_uint(o, "acpi_uid", &error_fatal);
|
||||
build_srat_acpi_generic_port(table_data, gp->node, hid, uid);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
void build_srat_generic_affinity_structures(GArray *table_data)
|
||||
{
|
||||
object_child_foreach_recursive(object_get_root(),
|
||||
build_acpi_generic_initiator,
|
||||
table_data);
|
||||
object_child_foreach_recursive(object_get_root(), build_acpi_generic_port,
|
||||
table_data);
|
||||
}
|
||||
|
||||
@@ -57,7 +57,6 @@
|
||||
#include "migration/vmstate.h"
|
||||
#include "hw/acpi/ghes.h"
|
||||
#include "hw/acpi/viot.h"
|
||||
#include "hw/acpi/acpi_generic_initiator.h"
|
||||
#include "hw/virtio/virtio-acpi.h"
|
||||
#include "target/arm/multiprocessing.h"
|
||||
|
||||
@@ -511,7 +510,7 @@ build_srat(GArray *table_data, BIOSLinker *linker, VirtMachineState *vms)
|
||||
}
|
||||
}
|
||||
|
||||
build_srat_generic_pci_initiator(table_data);
|
||||
build_srat_generic_affinity_structures(table_data);
|
||||
|
||||
if (ms->nvdimms_state->is_enabled) {
|
||||
nvdimm_build_srat(table_data);
|
||||
|
||||
@@ -90,27 +90,39 @@ static void vhost_user_blk_set_config(VirtIODevice *vdev, const uint8_t *config)
|
||||
s->blkcfg.wce = blkcfg->wce;
|
||||
}
|
||||
|
||||
static int vhost_user_blk_sync_config(DeviceState *dev, Error **errp)
|
||||
{
|
||||
int ret;
|
||||
VirtIODevice *vdev = VIRTIO_DEVICE(dev);
|
||||
VHostUserBlk *s = VHOST_USER_BLK(vdev);
|
||||
|
||||
ret = vhost_dev_get_config(&s->dev, (uint8_t *)&s->blkcfg,
|
||||
vdev->config_len, errp);
|
||||
if (ret < 0) {
|
||||
return ret;
|
||||
}
|
||||
|
||||
memcpy(vdev->config, &s->blkcfg, vdev->config_len);
|
||||
virtio_notify_config(vdev);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int vhost_user_blk_handle_config_change(struct vhost_dev *dev)
|
||||
{
|
||||
int ret;
|
||||
VirtIODevice *vdev = dev->vdev;
|
||||
VHostUserBlk *s = VHOST_USER_BLK(dev->vdev);
|
||||
Error *local_err = NULL;
|
||||
|
||||
if (!dev->started) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
ret = vhost_dev_get_config(dev, (uint8_t *)&s->blkcfg,
|
||||
vdev->config_len, &local_err);
|
||||
ret = vhost_user_blk_sync_config(DEVICE(dev->vdev), &local_err);
|
||||
if (ret < 0) {
|
||||
error_report_err(local_err);
|
||||
return ret;
|
||||
}
|
||||
|
||||
memcpy(dev->vdev->config, &s->blkcfg, vdev->config_len);
|
||||
virtio_notify_config(dev->vdev);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
@@ -579,6 +591,7 @@ static void vhost_user_blk_class_init(ObjectClass *klass, void *data)
|
||||
|
||||
device_class_set_props(dc, vhost_user_blk_properties);
|
||||
dc->vmsd = &vmstate_vhost_user_blk;
|
||||
dc->sync_config = vhost_user_blk_sync_config;
|
||||
set_bit(DEVICE_CATEGORY_STORAGE, dc->categories);
|
||||
vdc->realize = vhost_user_blk_device_realize;
|
||||
vdc->unrealize = vhost_user_blk_device_unrealize;
|
||||
|
||||
+3
-1
@@ -34,7 +34,9 @@
|
||||
#include "hw/virtio/virtio-iommu.h"
|
||||
#include "audio/audio.h"
|
||||
|
||||
GlobalProperty hw_compat_9_1[] = {};
|
||||
GlobalProperty hw_compat_9_1[] = {
|
||||
{ TYPE_PCI_DEVICE, "x-pcie-ext-tag", "false" },
|
||||
};
|
||||
const size_t hw_compat_9_1_len = G_N_ELEMENTS(hw_compat_9_1);
|
||||
|
||||
GlobalProperty hw_compat_9_0[] = {
|
||||
|
||||
+81
-34
@@ -151,6 +151,9 @@ static CXLRetCode cmd_tunnel_management_cmd(const struct cxl_cmd *cmd,
|
||||
in = (void *)payload_in;
|
||||
out = (void *)payload_out;
|
||||
|
||||
if (len_in < sizeof(*in)) {
|
||||
return CXL_MBOX_INVALID_PAYLOAD_LENGTH;
|
||||
}
|
||||
/* Enough room for minimum sized message - no payload */
|
||||
if (in->size < sizeof(in->ccimessage)) {
|
||||
return CXL_MBOX_INVALID_PAYLOAD_LENGTH;
|
||||
@@ -266,6 +269,12 @@ static CXLRetCode cmd_events_clear_records(const struct cxl_cmd *cmd,
|
||||
CXLClearEventPayload *pl;
|
||||
|
||||
pl = (CXLClearEventPayload *)payload_in;
|
||||
|
||||
if (len_in < sizeof(*pl) ||
|
||||
len_in < sizeof(*pl) + sizeof(*pl->handle) * pl->nr_recs) {
|
||||
return CXL_MBOX_INVALID_PAYLOAD_LENGTH;
|
||||
}
|
||||
|
||||
*len_out = 0;
|
||||
return cxl_event_clear_records(cxlds, pl);
|
||||
}
|
||||
@@ -374,7 +383,7 @@ static CXLRetCode cmd_infostat_identify(const struct cxl_cmd *cmd,
|
||||
uint16_t pcie_subsys_vid;
|
||||
uint16_t pcie_subsys_id;
|
||||
uint64_t sn;
|
||||
uint8_t max_message_size;
|
||||
uint8_t max_message_size;
|
||||
uint8_t component_type;
|
||||
} QEMU_PACKED *is_identify;
|
||||
QEMU_BUILD_BUG_ON(sizeof(*is_identify) != 18);
|
||||
@@ -521,6 +530,9 @@ static CXLRetCode cmd_get_physical_port_state(const struct cxl_cmd *cmd,
|
||||
in = (struct cxl_fmapi_get_phys_port_state_req_pl *)payload_in;
|
||||
out = (struct cxl_fmapi_get_phys_port_state_resp_pl *)payload_out;
|
||||
|
||||
if (len_in < sizeof(*in)) {
|
||||
return CXL_MBOX_INVALID_PAYLOAD_LENGTH;
|
||||
}
|
||||
/* Check if what was requested can fit */
|
||||
if (sizeof(*out) + sizeof(*out->ports) * in->num_ports > cci->payload_max) {
|
||||
return CXL_MBOX_INVALID_INPUT;
|
||||
@@ -649,9 +661,9 @@ static CXLRetCode cmd_firmware_update_get_info(const struct cxl_cmd *cmd,
|
||||
} QEMU_PACKED *fw_info;
|
||||
QEMU_BUILD_BUG_ON(sizeof(*fw_info) != 0x50);
|
||||
|
||||
if ((cxl_dstate->vmem_size < CXL_CAPACITY_MULTIPLIER) ||
|
||||
(cxl_dstate->pmem_size < CXL_CAPACITY_MULTIPLIER) ||
|
||||
(ct3d->dc.total_capacity < CXL_CAPACITY_MULTIPLIER)) {
|
||||
if (!QEMU_IS_ALIGNED(cxl_dstate->vmem_size, CXL_CAPACITY_MULTIPLIER) ||
|
||||
!QEMU_IS_ALIGNED(cxl_dstate->pmem_size, CXL_CAPACITY_MULTIPLIER) ||
|
||||
!QEMU_IS_ALIGNED(ct3d->dc.total_capacity, CXL_CAPACITY_MULTIPLIER)) {
|
||||
return CXL_MBOX_INTERNAL_ERROR;
|
||||
}
|
||||
|
||||
@@ -699,6 +711,10 @@ static CXLRetCode cmd_firmware_update_transfer(const struct cxl_cmd *cmd,
|
||||
} QEMU_PACKED *fw_transfer = (void *)payload_in;
|
||||
size_t offset, length;
|
||||
|
||||
if (len < sizeof(*fw_transfer)) {
|
||||
return CXL_MBOX_INVALID_PAYLOAD_LENGTH;
|
||||
}
|
||||
|
||||
if (fw_transfer->action == CXL_FW_XFER_ACTION_ABORT) {
|
||||
/*
|
||||
* At this point there aren't any on-going transfers
|
||||
@@ -927,17 +943,7 @@ static CXLRetCode cmd_logs_get_log(const struct cxl_cmd *cmd,
|
||||
|
||||
get_log = (void *)payload_in;
|
||||
|
||||
/*
|
||||
* CXL r3.1 Section 8.2.9.5.2: Get Log (Opcode 0401h)
|
||||
* The device shall return Invalid Input if the Offset or Length
|
||||
* fields attempt to access beyond the size of the log as reported by Get
|
||||
* Supported Logs.
|
||||
*
|
||||
* The CEL buffer is large enough to fit all commands in the emulation, so
|
||||
* the only possible failure would be if the mailbox itself isn't big
|
||||
* enough.
|
||||
*/
|
||||
if (get_log->offset + get_log->length > cci->payload_max) {
|
||||
if (get_log->length > cci->payload_max) {
|
||||
return CXL_MBOX_INVALID_INPUT;
|
||||
}
|
||||
|
||||
@@ -945,6 +951,20 @@ static CXLRetCode cmd_logs_get_log(const struct cxl_cmd *cmd,
|
||||
return CXL_MBOX_INVALID_LOG;
|
||||
}
|
||||
|
||||
/*
|
||||
* CXL r3.1 Section 8.2.9.5.2: Get Log (Opcode 0401h)
|
||||
* The device shall return Invalid Input if the Offset or Length
|
||||
* fields attempt to access beyond the size of the log as reported by Get
|
||||
* Supported Log.
|
||||
*
|
||||
* Only valid for there to be one entry per opcode, but the length + offset
|
||||
* may still be greater than that if the inputs are not valid and so access
|
||||
* beyond the end of cci->cel_log.
|
||||
*/
|
||||
if ((uint64_t)get_log->offset + get_log->length >= sizeof(cci->cel_log)) {
|
||||
return CXL_MBOX_INVALID_INPUT;
|
||||
}
|
||||
|
||||
/* Store off everything to local variables so we can wipe out the payload */
|
||||
*len_out = get_log->length;
|
||||
|
||||
@@ -1133,10 +1153,8 @@ static CXLRetCode cmd_features_get_supported(const struct cxl_cmd *cmd,
|
||||
(struct CXLSupportedFeatureEntry) {
|
||||
.uuid = ecs_uuid,
|
||||
.feat_index = index,
|
||||
.get_feat_size = CXL_ECS_NUM_MEDIA_FRUS *
|
||||
sizeof(CXLMemECSReadAttrs),
|
||||
.set_feat_size = CXL_ECS_NUM_MEDIA_FRUS *
|
||||
sizeof(CXLMemECSWriteAttrs),
|
||||
.get_feat_size = sizeof(CXLMemECSReadAttrs),
|
||||
.set_feat_size = sizeof(CXLMemECSWriteAttrs),
|
||||
.attr_flags = CXL_FEAT_ENTRY_ATTR_FLAG_CHANGABLE,
|
||||
.get_feat_version = CXL_ECS_GET_FEATURE_VERSION,
|
||||
.set_feat_version = CXL_ECS_SET_FEATURE_VERSION,
|
||||
@@ -1204,13 +1222,10 @@ static CXLRetCode cmd_features_get_feature(const struct cxl_cmd *cmd,
|
||||
(uint8_t *)&ct3d->patrol_scrub_attrs + get_feature->offset,
|
||||
bytes_to_copy);
|
||||
} else if (qemu_uuid_is_equal(&get_feature->uuid, &ecs_uuid)) {
|
||||
if (get_feature->offset >= CXL_ECS_NUM_MEDIA_FRUS *
|
||||
sizeof(CXLMemECSReadAttrs)) {
|
||||
if (get_feature->offset >= sizeof(CXLMemECSReadAttrs)) {
|
||||
return CXL_MBOX_INVALID_INPUT;
|
||||
}
|
||||
bytes_to_copy = CXL_ECS_NUM_MEDIA_FRUS *
|
||||
sizeof(CXLMemECSReadAttrs) -
|
||||
get_feature->offset;
|
||||
bytes_to_copy = sizeof(CXLMemECSReadAttrs) - get_feature->offset;
|
||||
bytes_to_copy = MIN(bytes_to_copy, get_feature->count);
|
||||
memcpy(payload_out,
|
||||
(uint8_t *)&ct3d->ecs_attrs + get_feature->offset,
|
||||
@@ -1243,6 +1258,9 @@ static CXLRetCode cmd_features_set_feature(const struct cxl_cmd *cmd,
|
||||
CXLType3Dev *ct3d;
|
||||
uint16_t count;
|
||||
|
||||
if (len_in < sizeof(*hdr)) {
|
||||
return CXL_MBOX_INVALID_PAYLOAD_LENGTH;
|
||||
}
|
||||
|
||||
if (!object_dynamic_cast(OBJECT(cci->d), TYPE_CXL_TYPE3)) {
|
||||
return CXL_MBOX_UNSUPPORTED;
|
||||
@@ -1277,6 +1295,11 @@ static CXLRetCode cmd_features_set_feature(const struct cxl_cmd *cmd,
|
||||
|
||||
ps_set_feature = (void *)payload_in;
|
||||
ps_write_attrs = &ps_set_feature->feat_data;
|
||||
|
||||
if ((uint32_t)hdr->offset + bytes_to_copy >
|
||||
sizeof(ct3d->patrol_scrub_wr_attrs)) {
|
||||
return CXL_MBOX_INVALID_PAYLOAD_LENGTH;
|
||||
}
|
||||
memcpy((uint8_t *)&ct3d->patrol_scrub_wr_attrs + hdr->offset,
|
||||
ps_write_attrs,
|
||||
bytes_to_copy);
|
||||
@@ -1299,18 +1322,22 @@ static CXLRetCode cmd_features_set_feature(const struct cxl_cmd *cmd,
|
||||
|
||||
ecs_set_feature = (void *)payload_in;
|
||||
ecs_write_attrs = ecs_set_feature->feat_data;
|
||||
memcpy((uint8_t *)ct3d->ecs_wr_attrs + hdr->offset,
|
||||
|
||||
if ((uint32_t)hdr->offset + bytes_to_copy >
|
||||
sizeof(ct3d->ecs_wr_attrs)) {
|
||||
return CXL_MBOX_INVALID_PAYLOAD_LENGTH;
|
||||
}
|
||||
memcpy((uint8_t *)&ct3d->ecs_wr_attrs + hdr->offset,
|
||||
ecs_write_attrs,
|
||||
bytes_to_copy);
|
||||
set_feat_info->data_size += bytes_to_copy;
|
||||
|
||||
if (data_transfer_flag == CXL_SET_FEATURE_FLAG_FULL_DATA_TRANSFER ||
|
||||
data_transfer_flag == CXL_SET_FEATURE_FLAG_FINISH_DATA_TRANSFER) {
|
||||
ct3d->ecs_attrs.ecs_log_cap = ct3d->ecs_wr_attrs.ecs_log_cap;
|
||||
for (count = 0; count < CXL_ECS_NUM_MEDIA_FRUS; count++) {
|
||||
ct3d->ecs_attrs[count].ecs_log_cap =
|
||||
ct3d->ecs_wr_attrs[count].ecs_log_cap;
|
||||
ct3d->ecs_attrs[count].ecs_config =
|
||||
ct3d->ecs_wr_attrs[count].ecs_config & 0x1F;
|
||||
ct3d->ecs_attrs.fru_attrs[count].ecs_config =
|
||||
ct3d->ecs_wr_attrs.fru_attrs[count].ecs_config & 0x1F;
|
||||
}
|
||||
}
|
||||
} else {
|
||||
@@ -1324,7 +1351,7 @@ static CXLRetCode cmd_features_set_feature(const struct cxl_cmd *cmd,
|
||||
if (qemu_uuid_is_equal(&hdr->uuid, &patrol_scrub_uuid)) {
|
||||
memset(&ct3d->patrol_scrub_wr_attrs, 0, set_feat_info->data_size);
|
||||
} else if (qemu_uuid_is_equal(&hdr->uuid, &ecs_uuid)) {
|
||||
memset(ct3d->ecs_wr_attrs, 0, set_feat_info->data_size);
|
||||
memset(&ct3d->ecs_wr_attrs, 0, set_feat_info->data_size);
|
||||
}
|
||||
set_feat_info->data_transfer_flag = 0;
|
||||
set_feat_info->data_saved_across_reset = false;
|
||||
@@ -1445,7 +1472,7 @@ static CXLRetCode cmd_ccls_get_lsa(const struct cxl_cmd *cmd,
|
||||
} QEMU_PACKED *get_lsa;
|
||||
CXLType3Dev *ct3d = CXL_TYPE3(cci->d);
|
||||
CXLType3Class *cvc = CXL_TYPE3_GET_CLASS(ct3d);
|
||||
uint32_t offset, length;
|
||||
uint64_t offset, length;
|
||||
|
||||
get_lsa = (void *)payload_in;
|
||||
offset = get_lsa->offset;
|
||||
@@ -1479,8 +1506,8 @@ static CXLRetCode cmd_ccls_set_lsa(const struct cxl_cmd *cmd,
|
||||
const size_t hdr_len = offsetof(struct set_lsa_pl, data);
|
||||
|
||||
*len_out = 0;
|
||||
if (!len_in) {
|
||||
return CXL_MBOX_SUCCESS;
|
||||
if (len_in < hdr_len) {
|
||||
return CXL_MBOX_INVALID_PAYLOAD_LENGTH;
|
||||
}
|
||||
|
||||
if (set_lsa_payload->offset + len_in > cvc->get_lsa_size(ct3d) + hdr_len) {
|
||||
@@ -2233,6 +2260,7 @@ static CXLRetCode cmd_dcd_get_dyn_cap_ext_list(const struct cxl_cmd *cmd,
|
||||
stw_le_p(&out_rec->shared_seq, ent->shared_seq);
|
||||
|
||||
record_done++;
|
||||
out_rec++;
|
||||
if (record_done == record_count) {
|
||||
break;
|
||||
}
|
||||
@@ -2470,11 +2498,20 @@ static CXLRetCode cmd_dcd_add_dyn_cap_rsp(const struct cxl_cmd *cmd,
|
||||
uint64_t dpa, len;
|
||||
CXLRetCode ret;
|
||||
|
||||
if (len_in < sizeof(*in)) {
|
||||
return CXL_MBOX_INVALID_PAYLOAD_LENGTH;
|
||||
}
|
||||
|
||||
if (in->num_entries_updated == 0) {
|
||||
cxl_extent_group_list_delete_front(&ct3d->dc.extents_pending);
|
||||
return CXL_MBOX_SUCCESS;
|
||||
}
|
||||
|
||||
if (len_in <
|
||||
sizeof(*in) + sizeof(*in->updated_entries) * in->num_entries_updated) {
|
||||
return CXL_MBOX_INVALID_PAYLOAD_LENGTH;
|
||||
}
|
||||
|
||||
/* Adding extents causes exceeding device's extent tracking ability. */
|
||||
if (in->num_entries_updated + ct3d->dc.total_extent_count >
|
||||
CXL_NUM_EXTENTS_SUPPORTED) {
|
||||
@@ -2629,10 +2666,19 @@ static CXLRetCode cmd_dcd_release_dyn_cap(const struct cxl_cmd *cmd,
|
||||
uint32_t updated_list_size;
|
||||
CXLRetCode ret;
|
||||
|
||||
if (len_in < sizeof(*in)) {
|
||||
return CXL_MBOX_INVALID_PAYLOAD_LENGTH;
|
||||
}
|
||||
|
||||
if (in->num_entries_updated == 0) {
|
||||
return CXL_MBOX_INVALID_INPUT;
|
||||
}
|
||||
|
||||
if (len_in <
|
||||
sizeof(*in) + sizeof(*in->updated_entries) * in->num_entries_updated) {
|
||||
return CXL_MBOX_INVALID_PAYLOAD_LENGTH;
|
||||
}
|
||||
|
||||
ret = cxl_detect_malformed_extent_list(ct3d, in);
|
||||
if (ret != CXL_MBOX_SUCCESS) {
|
||||
return ret;
|
||||
@@ -2879,7 +2925,8 @@ static void bg_timercb(void *opaque)
|
||||
}
|
||||
} else {
|
||||
/* estimate only */
|
||||
cci->bg.complete_pct = 100 * now / total_time;
|
||||
cci->bg.complete_pct =
|
||||
100 * (now - cci->bg.starttime) / cci->bg.runtime;
|
||||
timer_mod(cci->bg.timer, now + CXL_MBOX_BG_UPDATE_FREQ);
|
||||
}
|
||||
|
||||
|
||||
@@ -68,7 +68,6 @@
|
||||
#include "hw/acpi/utils.h"
|
||||
#include "hw/acpi/pci.h"
|
||||
#include "hw/acpi/cxl.h"
|
||||
#include "hw/acpi/acpi_generic_initiator.h"
|
||||
|
||||
#include "qom/qom-qobject.h"
|
||||
#include "hw/i386/amd_iommu.h"
|
||||
@@ -741,7 +740,8 @@ static Aml *build_prt(bool is_pci0_prt)
|
||||
int pin;
|
||||
|
||||
method = aml_method("_PRT", 0, AML_NOTSERIALIZED);
|
||||
rt_pkg = aml_varpackage(nroutes);
|
||||
assert(nroutes < 256);
|
||||
rt_pkg = aml_package(nroutes);
|
||||
|
||||
for (pin = 0; pin < nroutes; pin++) {
|
||||
Aml *pkg = aml_package(4);
|
||||
@@ -1476,6 +1476,7 @@ build_dsdt(GArray *table_data, BIOSLinker *linker,
|
||||
QLIST_FOREACH(bus, &bus->child, sibling) {
|
||||
uint8_t bus_num = pci_bus_num(bus);
|
||||
uint8_t numa_node = pci_bus_numa_node(bus);
|
||||
uint32_t uid;
|
||||
|
||||
/* look only for expander root buses */
|
||||
if (!pci_bus_is_root(bus)) {
|
||||
@@ -1486,6 +1487,8 @@ build_dsdt(GArray *table_data, BIOSLinker *linker,
|
||||
root_bus_limit = bus_num - 1;
|
||||
}
|
||||
|
||||
uid = object_property_get_uint(OBJECT(bus), "acpi_uid",
|
||||
&error_fatal);
|
||||
scope = aml_scope("\\_SB");
|
||||
|
||||
if (pci_bus_is_cxl(bus)) {
|
||||
@@ -1493,7 +1496,7 @@ build_dsdt(GArray *table_data, BIOSLinker *linker,
|
||||
} else {
|
||||
dev = aml_device("PC%.02X", bus_num);
|
||||
}
|
||||
aml_append(dev, aml_name_decl("_UID", aml_int(bus_num)));
|
||||
aml_append(dev, aml_name_decl("_UID", aml_int(uid)));
|
||||
aml_append(dev, aml_name_decl("_BBN", aml_int(bus_num)));
|
||||
if (pci_bus_is_cxl(bus)) {
|
||||
struct Aml *aml_pkg = aml_package(2);
|
||||
@@ -1971,7 +1974,7 @@ build_srat(GArray *table_data, BIOSLinker *linker, MachineState *machine)
|
||||
build_srat_memory(table_data, 0, 0, 0, MEM_AFFINITY_NOFLAGS);
|
||||
}
|
||||
|
||||
build_srat_generic_pci_initiator(table_data);
|
||||
build_srat_generic_affinity_structures(table_data);
|
||||
|
||||
/*
|
||||
* Entry is required for Windows to enable memory hotplug in OS
|
||||
@@ -2321,7 +2324,7 @@ build_amd_iommu(GArray *table_data, BIOSLinker *linker, const char *oem_id,
|
||||
/* Capability offset */
|
||||
build_append_int_noprefix(table_data, s->pci.capab_offset, 2);
|
||||
/* IOMMU base address */
|
||||
build_append_int_noprefix(table_data, s->mmio.addr, 8);
|
||||
build_append_int_noprefix(table_data, s->mr_mmio.addr, 8);
|
||||
/* PCI Segment Group */
|
||||
build_append_int_noprefix(table_data, 0, 2);
|
||||
/* IOMMU info */
|
||||
@@ -2356,7 +2359,7 @@ build_amd_iommu(GArray *table_data, BIOSLinker *linker, const char *oem_id,
|
||||
/* Capability offset */
|
||||
build_append_int_noprefix(table_data, s->pci.capab_offset, 2);
|
||||
/* IOMMU base address */
|
||||
build_append_int_noprefix(table_data, s->mmio.addr, 8);
|
||||
build_append_int_noprefix(table_data, s->mr_mmio.addr, 8);
|
||||
/* PCI Segment Group */
|
||||
build_append_int_noprefix(table_data, 0, 2);
|
||||
/* IOMMU info */
|
||||
|
||||
+79
-19
@@ -32,6 +32,7 @@
|
||||
#include "trace.h"
|
||||
#include "hw/i386/apic-msidef.h"
|
||||
#include "hw/qdev-properties.h"
|
||||
#include "kvm/kvm_i386.h"
|
||||
|
||||
/* used AMD-Vi MMIO registers */
|
||||
const char *amdvi_mmio_low[] = {
|
||||
@@ -60,8 +61,9 @@ struct AMDVIAddressSpace {
|
||||
uint8_t bus_num; /* bus number */
|
||||
uint8_t devfn; /* device function */
|
||||
AMDVIState *iommu_state; /* AMDVI - one per machine */
|
||||
MemoryRegion root; /* AMDVI Root memory map region */
|
||||
MemoryRegion root; /* AMDVI Root memory map region */
|
||||
IOMMUMemoryRegion iommu; /* Device's address translation region */
|
||||
MemoryRegion iommu_nodma; /* Alias of shared nodma memory region */
|
||||
MemoryRegion iommu_ir; /* Device's interrupt remapping region */
|
||||
AddressSpace as; /* device's corresponding address space */
|
||||
};
|
||||
@@ -430,6 +432,12 @@ static void amdvi_complete_ppr(AMDVIState *s, uint64_t *cmd)
|
||||
trace_amdvi_ppr_exec();
|
||||
}
|
||||
|
||||
static void amdvi_intremap_inval_notify_all(AMDVIState *s, bool global,
|
||||
uint32_t index, uint32_t mask)
|
||||
{
|
||||
x86_iommu_iec_notify_all(X86_IOMMU_DEVICE(s), global, index, mask);
|
||||
}
|
||||
|
||||
static void amdvi_inval_all(AMDVIState *s, uint64_t *cmd)
|
||||
{
|
||||
if (extract64(cmd[0], 0, 60) || cmd[1]) {
|
||||
@@ -437,6 +445,9 @@ static void amdvi_inval_all(AMDVIState *s, uint64_t *cmd)
|
||||
s->cmdbuf + s->cmdbuf_head);
|
||||
}
|
||||
|
||||
/* Notify global invalidation */
|
||||
amdvi_intremap_inval_notify_all(s, true, 0, 0);
|
||||
|
||||
amdvi_iotlb_reset(s);
|
||||
trace_amdvi_all_inval();
|
||||
}
|
||||
@@ -485,6 +496,9 @@ static void amdvi_inval_inttable(AMDVIState *s, uint64_t *cmd)
|
||||
return;
|
||||
}
|
||||
|
||||
/* Notify global invalidation */
|
||||
amdvi_intremap_inval_notify_all(s, true, 0, 0);
|
||||
|
||||
trace_amdvi_intr_inval();
|
||||
}
|
||||
|
||||
@@ -1412,6 +1426,7 @@ static AddressSpace *amdvi_host_dma_iommu(PCIBus *bus, void *opaque, int devfn)
|
||||
AMDVIState *s = opaque;
|
||||
AMDVIAddressSpace **iommu_as, *amdvi_dev_as;
|
||||
int bus_num = pci_bus_num(bus);
|
||||
X86IOMMUState *x86_iommu = X86_IOMMU_DEVICE(s);
|
||||
|
||||
iommu_as = s->address_spaces[bus_num];
|
||||
|
||||
@@ -1436,13 +1451,13 @@ static AddressSpace *amdvi_host_dma_iommu(PCIBus *bus, void *opaque, int devfn)
|
||||
* Memory region relationships looks like (Address range shows
|
||||
* only lower 32 bits to make it short in length...):
|
||||
*
|
||||
* |-----------------+-------------------+----------|
|
||||
* | Name | Address range | Priority |
|
||||
* |-----------------+-------------------+----------+
|
||||
* | amdvi_root | 00000000-ffffffff | 0 |
|
||||
* | amdvi_iommu | 00000000-ffffffff | 1 |
|
||||
* | amdvi_iommu_ir | fee00000-feefffff | 64 |
|
||||
* |-----------------+-------------------+----------|
|
||||
* |--------------------+-------------------+----------|
|
||||
* | Name | Address range | Priority |
|
||||
* |--------------------+-------------------+----------+
|
||||
* | amdvi-root | 00000000-ffffffff | 0 |
|
||||
* | amdvi-iommu_nodma | 00000000-ffffffff | 0 |
|
||||
* | amdvi-iommu_ir | fee00000-feefffff | 1 |
|
||||
* |--------------------+-------------------+----------|
|
||||
*/
|
||||
memory_region_init_iommu(&amdvi_dev_as->iommu,
|
||||
sizeof(amdvi_dev_as->iommu),
|
||||
@@ -1452,16 +1467,34 @@ static AddressSpace *amdvi_host_dma_iommu(PCIBus *bus, void *opaque, int devfn)
|
||||
memory_region_init(&amdvi_dev_as->root, OBJECT(s),
|
||||
"amdvi_root", UINT64_MAX);
|
||||
address_space_init(&amdvi_dev_as->as, &amdvi_dev_as->root, name);
|
||||
memory_region_init_io(&amdvi_dev_as->iommu_ir, OBJECT(s),
|
||||
&amdvi_ir_ops, s, "amd_iommu_ir",
|
||||
AMDVI_INT_ADDR_SIZE);
|
||||
memory_region_add_subregion_overlap(&amdvi_dev_as->root,
|
||||
AMDVI_INT_ADDR_FIRST,
|
||||
&amdvi_dev_as->iommu_ir,
|
||||
64);
|
||||
memory_region_add_subregion_overlap(&amdvi_dev_as->root, 0,
|
||||
MEMORY_REGION(&amdvi_dev_as->iommu),
|
||||
1);
|
||||
0);
|
||||
|
||||
/* Build the DMA Disabled alias to shared memory */
|
||||
memory_region_init_alias(&amdvi_dev_as->iommu_nodma, OBJECT(s),
|
||||
"amdvi-sys", &s->mr_sys, 0,
|
||||
memory_region_size(&s->mr_sys));
|
||||
memory_region_add_subregion_overlap(&amdvi_dev_as->root, 0,
|
||||
&amdvi_dev_as->iommu_nodma,
|
||||
0);
|
||||
/* Build the Interrupt Remapping alias to shared memory */
|
||||
memory_region_init_alias(&amdvi_dev_as->iommu_ir, OBJECT(s),
|
||||
"amdvi-ir", &s->mr_ir, 0,
|
||||
memory_region_size(&s->mr_ir));
|
||||
memory_region_add_subregion_overlap(MEMORY_REGION(&amdvi_dev_as->iommu),
|
||||
AMDVI_INT_ADDR_FIRST,
|
||||
&amdvi_dev_as->iommu_ir, 1);
|
||||
|
||||
if (!x86_iommu->pt_supported) {
|
||||
memory_region_set_enabled(&amdvi_dev_as->iommu_nodma, false);
|
||||
memory_region_set_enabled(MEMORY_REGION(&amdvi_dev_as->iommu),
|
||||
true);
|
||||
} else {
|
||||
memory_region_set_enabled(MEMORY_REGION(&amdvi_dev_as->iommu),
|
||||
false);
|
||||
memory_region_set_enabled(&amdvi_dev_as->iommu_nodma, true);
|
||||
}
|
||||
}
|
||||
return &iommu_as[devfn]->as;
|
||||
}
|
||||
@@ -1598,10 +1631,37 @@ static void amdvi_sysbus_realize(DeviceState *dev, Error **errp)
|
||||
x86ms->ioapic_as = amdvi_host_dma_iommu(bus, s, AMDVI_IOAPIC_SB_DEVID);
|
||||
|
||||
/* set up MMIO */
|
||||
memory_region_init_io(&s->mmio, OBJECT(s), &mmio_mem_ops, s, "amdvi-mmio",
|
||||
AMDVI_MMIO_SIZE);
|
||||
memory_region_init_io(&s->mr_mmio, OBJECT(s), &mmio_mem_ops, s,
|
||||
"amdvi-mmio", AMDVI_MMIO_SIZE);
|
||||
memory_region_add_subregion(get_system_memory(), AMDVI_BASE_ADDR,
|
||||
&s->mmio);
|
||||
&s->mr_mmio);
|
||||
|
||||
/* Create the share memory regions by all devices */
|
||||
memory_region_init(&s->mr_sys, OBJECT(s), "amdvi-sys", UINT64_MAX);
|
||||
|
||||
/* set up the DMA disabled memory region */
|
||||
memory_region_init_alias(&s->mr_nodma, OBJECT(s),
|
||||
"amdvi-nodma", get_system_memory(), 0,
|
||||
memory_region_size(get_system_memory()));
|
||||
memory_region_add_subregion_overlap(&s->mr_sys, 0,
|
||||
&s->mr_nodma, 0);
|
||||
|
||||
/* set up the Interrupt Remapping memory region */
|
||||
memory_region_init_io(&s->mr_ir, OBJECT(s), &amdvi_ir_ops,
|
||||
s, "amdvi-ir", AMDVI_INT_ADDR_SIZE);
|
||||
memory_region_add_subregion_overlap(&s->mr_sys, AMDVI_INT_ADDR_FIRST,
|
||||
&s->mr_ir, 1);
|
||||
|
||||
/* AMD IOMMU with x2APIC mode requires xtsup=on */
|
||||
if (x86ms->apic_id_limit > 255 && !s->xtsup) {
|
||||
error_report("AMD IOMMU with x2APIC confguration requires xtsup=on");
|
||||
exit(EXIT_FAILURE);
|
||||
}
|
||||
if (s->xtsup && kvm_irqchip_is_split() && !kvm_enable_x2apic()) {
|
||||
error_report("AMD IOMMU xtsup=on requires support on the KVM side");
|
||||
exit(EXIT_FAILURE);
|
||||
}
|
||||
|
||||
pci_setup_iommu(bus, &amdvi_iommu_ops, s);
|
||||
amdvi_init(s);
|
||||
}
|
||||
|
||||
+4
-1
@@ -353,7 +353,10 @@ struct AMDVIState {
|
||||
uint32_t pprlog_head; /* ppr log head */
|
||||
uint32_t pprlog_tail; /* ppr log tail */
|
||||
|
||||
MemoryRegion mmio; /* MMIO region */
|
||||
MemoryRegion mr_mmio; /* MMIO region */
|
||||
MemoryRegion mr_sys;
|
||||
MemoryRegion mr_nodma;
|
||||
MemoryRegion mr_ir;
|
||||
uint8_t mmior[AMDVI_MMIO_SIZE]; /* read/write MMIO */
|
||||
uint8_t w1cmask[AMDVI_MMIO_SIZE]; /* read/write 1 clear mask */
|
||||
uint8_t romask[AMDVI_MMIO_SIZE]; /* MMIO read/only mask */
|
||||
|
||||
+71
-25
@@ -2532,15 +2532,51 @@ static bool vtd_get_inv_desc(IntelIOMMUState *s,
|
||||
return true;
|
||||
}
|
||||
|
||||
static bool vtd_inv_desc_reserved_check(IntelIOMMUState *s,
|
||||
VTDInvDesc *inv_desc,
|
||||
uint64_t mask[4], bool dw,
|
||||
const char *func_name,
|
||||
const char *desc_type)
|
||||
{
|
||||
if (s->iq_dw) {
|
||||
if (inv_desc->val[0] & mask[0] || inv_desc->val[1] & mask[1] ||
|
||||
inv_desc->val[2] & mask[2] || inv_desc->val[3] & mask[3]) {
|
||||
error_report("%s: invalid %s desc val[3]: 0x%"PRIx64
|
||||
" val[2]: 0x%"PRIx64" val[1]=0x%"PRIx64
|
||||
" val[0]=0x%"PRIx64" (reserved nonzero)",
|
||||
func_name, desc_type, inv_desc->val[3],
|
||||
inv_desc->val[2], inv_desc->val[1],
|
||||
inv_desc->val[0]);
|
||||
return false;
|
||||
}
|
||||
} else {
|
||||
if (dw) {
|
||||
error_report("%s: 256-bit %s desc in 128-bit invalidation queue",
|
||||
func_name, desc_type);
|
||||
return false;
|
||||
}
|
||||
|
||||
if (inv_desc->lo & mask[0] || inv_desc->hi & mask[1]) {
|
||||
error_report("%s: invalid %s desc: hi=%"PRIx64", lo=%"PRIx64
|
||||
" (reserved nonzero)", func_name, desc_type,
|
||||
inv_desc->hi, inv_desc->lo);
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
static bool vtd_process_wait_desc(IntelIOMMUState *s, VTDInvDesc *inv_desc)
|
||||
{
|
||||
if ((inv_desc->hi & VTD_INV_DESC_WAIT_RSVD_HI) ||
|
||||
(inv_desc->lo & VTD_INV_DESC_WAIT_RSVD_LO)) {
|
||||
error_report_once("%s: invalid wait desc: hi=%"PRIx64", lo=%"PRIx64
|
||||
" (reserved nonzero)", __func__, inv_desc->hi,
|
||||
inv_desc->lo);
|
||||
uint64_t mask[4] = {VTD_INV_DESC_WAIT_RSVD_LO, VTD_INV_DESC_WAIT_RSVD_HI,
|
||||
VTD_INV_DESC_ALL_ONE, VTD_INV_DESC_ALL_ONE};
|
||||
|
||||
if (!vtd_inv_desc_reserved_check(s, inv_desc, mask, false,
|
||||
__func__, "wait")) {
|
||||
return false;
|
||||
}
|
||||
|
||||
if (inv_desc->lo & VTD_INV_DESC_WAIT_SW) {
|
||||
/* Status Write */
|
||||
uint32_t status_data = (uint32_t)(inv_desc->lo >>
|
||||
@@ -2574,13 +2610,14 @@ static bool vtd_process_context_cache_desc(IntelIOMMUState *s,
|
||||
VTDInvDesc *inv_desc)
|
||||
{
|
||||
uint16_t sid, fmask;
|
||||
uint64_t mask[4] = {VTD_INV_DESC_CC_RSVD, VTD_INV_DESC_ALL_ONE,
|
||||
VTD_INV_DESC_ALL_ONE, VTD_INV_DESC_ALL_ONE};
|
||||
|
||||
if ((inv_desc->lo & VTD_INV_DESC_CC_RSVD) || inv_desc->hi) {
|
||||
error_report_once("%s: invalid cc inv desc: hi=%"PRIx64", lo=%"PRIx64
|
||||
" (reserved nonzero)", __func__, inv_desc->hi,
|
||||
inv_desc->lo);
|
||||
if (!vtd_inv_desc_reserved_check(s, inv_desc, mask, false,
|
||||
__func__, "cc inv")) {
|
||||
return false;
|
||||
}
|
||||
|
||||
switch (inv_desc->lo & VTD_INV_DESC_CC_G) {
|
||||
case VTD_INV_DESC_CC_DOMAIN:
|
||||
trace_vtd_inv_desc_cc_domain(
|
||||
@@ -2610,12 +2647,11 @@ static bool vtd_process_iotlb_desc(IntelIOMMUState *s, VTDInvDesc *inv_desc)
|
||||
uint16_t domain_id;
|
||||
uint8_t am;
|
||||
hwaddr addr;
|
||||
uint64_t mask[4] = {VTD_INV_DESC_IOTLB_RSVD_LO, VTD_INV_DESC_IOTLB_RSVD_HI,
|
||||
VTD_INV_DESC_ALL_ONE, VTD_INV_DESC_ALL_ONE};
|
||||
|
||||
if ((inv_desc->lo & VTD_INV_DESC_IOTLB_RSVD_LO) ||
|
||||
(inv_desc->hi & VTD_INV_DESC_IOTLB_RSVD_HI)) {
|
||||
error_report_once("%s: invalid iotlb inv desc: hi=0x%"PRIx64
|
||||
", lo=0x%"PRIx64" (reserved bits unzero)",
|
||||
__func__, inv_desc->hi, inv_desc->lo);
|
||||
if (!vtd_inv_desc_reserved_check(s, inv_desc, mask, false,
|
||||
__func__, "iotlb inv")) {
|
||||
return false;
|
||||
}
|
||||
|
||||
@@ -2656,6 +2692,14 @@ static bool vtd_process_iotlb_desc(IntelIOMMUState *s, VTDInvDesc *inv_desc)
|
||||
static bool vtd_process_inv_iec_desc(IntelIOMMUState *s,
|
||||
VTDInvDesc *inv_desc)
|
||||
{
|
||||
uint64_t mask[4] = {VTD_INV_DESC_IEC_RSVD, VTD_INV_DESC_ALL_ONE,
|
||||
VTD_INV_DESC_ALL_ONE, VTD_INV_DESC_ALL_ONE};
|
||||
|
||||
if (!vtd_inv_desc_reserved_check(s, inv_desc, mask, false,
|
||||
__func__, "iec inv")) {
|
||||
return false;
|
||||
}
|
||||
|
||||
trace_vtd_inv_desc_iec(inv_desc->iec.granularity,
|
||||
inv_desc->iec.index,
|
||||
inv_desc->iec.index_mask);
|
||||
@@ -2705,19 +2749,19 @@ static bool vtd_process_device_iotlb_desc(IntelIOMMUState *s,
|
||||
hwaddr addr;
|
||||
uint16_t sid;
|
||||
bool size;
|
||||
uint64_t mask[4] = {VTD_INV_DESC_DEVICE_IOTLB_RSVD_LO,
|
||||
VTD_INV_DESC_DEVICE_IOTLB_RSVD_HI,
|
||||
VTD_INV_DESC_ALL_ONE, VTD_INV_DESC_ALL_ONE};
|
||||
|
||||
if (!vtd_inv_desc_reserved_check(s, inv_desc, mask, false,
|
||||
__func__, "dev-iotlb inv")) {
|
||||
return false;
|
||||
}
|
||||
|
||||
addr = VTD_INV_DESC_DEVICE_IOTLB_ADDR(inv_desc->hi);
|
||||
sid = VTD_INV_DESC_DEVICE_IOTLB_SID(inv_desc->lo);
|
||||
size = VTD_INV_DESC_DEVICE_IOTLB_SIZE(inv_desc->hi);
|
||||
|
||||
if ((inv_desc->lo & VTD_INV_DESC_DEVICE_IOTLB_RSVD_LO) ||
|
||||
(inv_desc->hi & VTD_INV_DESC_DEVICE_IOTLB_RSVD_HI)) {
|
||||
error_report_once("%s: invalid dev-iotlb inv desc: hi=%"PRIx64
|
||||
", lo=%"PRIx64" (reserved nonzero)", __func__,
|
||||
inv_desc->hi, inv_desc->lo);
|
||||
return false;
|
||||
}
|
||||
|
||||
/*
|
||||
* Using sid is OK since the guest should have finished the
|
||||
* initialization of both the bus and device.
|
||||
@@ -2847,6 +2891,7 @@ static void vtd_handle_iqt_write(IntelIOMMUState *s)
|
||||
if (s->iq_dw && (val & VTD_IQT_QT_256_RSV_BIT)) {
|
||||
error_report_once("%s: RSV bit is set: val=0x%"PRIx64,
|
||||
__func__, val);
|
||||
vtd_handle_inv_queue_error(s);
|
||||
return;
|
||||
}
|
||||
s->iq_tail = VTD_IQT_QT(s->iq_dw, val);
|
||||
@@ -3372,6 +3417,7 @@ static Property vtd_properties[] = {
|
||||
DEFINE_PROP_BOOL("x-pasid-mode", IntelIOMMUState, pasid, false),
|
||||
DEFINE_PROP_BOOL("dma-drain", IntelIOMMUState, dma_drain, true),
|
||||
DEFINE_PROP_BOOL("dma-translation", IntelIOMMUState, dma_translation, true),
|
||||
DEFINE_PROP_BOOL("stale-tm", IntelIOMMUState, stale_tm, false),
|
||||
DEFINE_PROP_END_OF_LIST(),
|
||||
};
|
||||
|
||||
@@ -4138,15 +4184,15 @@ static void vtd_init(IntelIOMMUState *s)
|
||||
*/
|
||||
vtd_spte_rsvd[0] = ~0ULL;
|
||||
vtd_spte_rsvd[1] = VTD_SPTE_PAGE_L1_RSVD_MASK(s->aw_bits,
|
||||
x86_iommu->dt_supported);
|
||||
x86_iommu->dt_supported && s->stale_tm);
|
||||
vtd_spte_rsvd[2] = VTD_SPTE_PAGE_L2_RSVD_MASK(s->aw_bits);
|
||||
vtd_spte_rsvd[3] = VTD_SPTE_PAGE_L3_RSVD_MASK(s->aw_bits);
|
||||
vtd_spte_rsvd[4] = VTD_SPTE_PAGE_L4_RSVD_MASK(s->aw_bits);
|
||||
|
||||
vtd_spte_rsvd_large[2] = VTD_SPTE_LPAGE_L2_RSVD_MASK(s->aw_bits,
|
||||
x86_iommu->dt_supported);
|
||||
x86_iommu->dt_supported && s->stale_tm);
|
||||
vtd_spte_rsvd_large[3] = VTD_SPTE_LPAGE_L3_RSVD_MASK(s->aw_bits,
|
||||
x86_iommu->dt_supported);
|
||||
x86_iommu->dt_supported && s->stale_tm);
|
||||
|
||||
if (s->scalable_mode || s->snoop_control) {
|
||||
vtd_spte_rsvd[1] &= ~VTD_SPTE_SNP;
|
||||
|
||||
@@ -356,6 +356,7 @@ union VTDInvDesc {
|
||||
typedef union VTDInvDesc VTDInvDesc;
|
||||
|
||||
/* Masks for struct VTDInvDesc */
|
||||
#define VTD_INV_DESC_ALL_ONE -1ULL
|
||||
#define VTD_INV_DESC_TYPE(val) ((((val) >> 5) & 0x70ULL) | \
|
||||
((val) & 0xfULL))
|
||||
#define VTD_INV_DESC_CC 0x1 /* Context-cache Invalidate Desc */
|
||||
@@ -409,11 +410,14 @@ typedef union VTDInvDesc VTDInvDesc;
|
||||
#define VTD_INV_DESC_DEVICE_IOTLB_RSVD_HI 0xffeULL
|
||||
#define VTD_INV_DESC_DEVICE_IOTLB_RSVD_LO 0xffff0000ffe0f1f0
|
||||
|
||||
/* Masks for Interrupt Entry Invalidate Descriptor */
|
||||
#define VTD_INV_DESC_IEC_RSVD 0xffff000007fff1e0ULL
|
||||
|
||||
/* Rsvd field masks for spte */
|
||||
#define VTD_SPTE_SNP 0x800ULL
|
||||
|
||||
#define VTD_SPTE_PAGE_L1_RSVD_MASK(aw, dt_supported) \
|
||||
dt_supported ? \
|
||||
#define VTD_SPTE_PAGE_L1_RSVD_MASK(aw, stale_tm) \
|
||||
stale_tm ? \
|
||||
(0x800ULL | ~(VTD_HAW_MASK(aw) | VTD_SL_IGN_COM | VTD_SL_TM)) : \
|
||||
(0x800ULL | ~(VTD_HAW_MASK(aw) | VTD_SL_IGN_COM))
|
||||
#define VTD_SPTE_PAGE_L2_RSVD_MASK(aw) \
|
||||
@@ -423,12 +427,12 @@ typedef union VTDInvDesc VTDInvDesc;
|
||||
#define VTD_SPTE_PAGE_L4_RSVD_MASK(aw) \
|
||||
(0x880ULL | ~(VTD_HAW_MASK(aw) | VTD_SL_IGN_COM))
|
||||
|
||||
#define VTD_SPTE_LPAGE_L2_RSVD_MASK(aw, dt_supported) \
|
||||
dt_supported ? \
|
||||
#define VTD_SPTE_LPAGE_L2_RSVD_MASK(aw, stale_tm) \
|
||||
stale_tm ? \
|
||||
(0x1ff800ULL | ~(VTD_HAW_MASK(aw) | VTD_SL_IGN_COM | VTD_SL_TM)) : \
|
||||
(0x1ff800ULL | ~(VTD_HAW_MASK(aw) | VTD_SL_IGN_COM))
|
||||
#define VTD_SPTE_LPAGE_L3_RSVD_MASK(aw, dt_supported) \
|
||||
dt_supported ? \
|
||||
#define VTD_SPTE_LPAGE_L3_RSVD_MASK(aw, stale_tm) \
|
||||
stale_tm ? \
|
||||
(0x3ffff800ULL | ~(VTD_HAW_MASK(aw) | VTD_SL_IGN_COM | VTD_SL_TM)) : \
|
||||
(0x3ffff800ULL | ~(VTD_HAW_MASK(aw) | VTD_SL_IGN_COM))
|
||||
|
||||
|
||||
@@ -82,6 +82,7 @@
|
||||
GlobalProperty pc_compat_9_1[] = {
|
||||
{ "ICH9-LPC", "x-smi-swsmi-timer", "off" },
|
||||
{ "ICH9-LPC", "x-smi-periodic-timer", "off" },
|
||||
{ TYPE_INTEL_IOMMU_DEVICE, "stale-tm", "on" },
|
||||
};
|
||||
const size_t pc_compat_9_1_len = G_N_ELEMENTS(pc_compat_9_1);
|
||||
|
||||
|
||||
+12
-9
@@ -17,6 +17,7 @@
|
||||
#include "hw/mem/pc-dimm.h"
|
||||
#include "hw/pci/pci.h"
|
||||
#include "hw/qdev-properties.h"
|
||||
#include "hw/qdev-properties-system.h"
|
||||
#include "qapi/error.h"
|
||||
#include "qemu/log.h"
|
||||
#include "qemu/module.h"
|
||||
@@ -919,16 +920,15 @@ static void ct3_realize(PCIDevice *pci_dev, Error **errp)
|
||||
ct3d->patrol_scrub_attrs.scrub_flags = CXL_MEMDEV_PS_ENABLE_DEFAULT;
|
||||
|
||||
/* Set default value for DDR5 ECS read attributes */
|
||||
ct3d->ecs_attrs.ecs_log_cap = CXL_ECS_LOG_ENTRY_TYPE_DEFAULT;
|
||||
for (count = 0; count < CXL_ECS_NUM_MEDIA_FRUS; count++) {
|
||||
ct3d->ecs_attrs[count].ecs_log_cap =
|
||||
CXL_ECS_LOG_ENTRY_TYPE_DEFAULT;
|
||||
ct3d->ecs_attrs[count].ecs_cap =
|
||||
ct3d->ecs_attrs.fru_attrs[count].ecs_cap =
|
||||
CXL_ECS_REALTIME_REPORT_CAP_DEFAULT;
|
||||
ct3d->ecs_attrs[count].ecs_config =
|
||||
ct3d->ecs_attrs.fru_attrs[count].ecs_config =
|
||||
CXL_ECS_THRESHOLD_COUNT_DEFAULT |
|
||||
(CXL_ECS_MODE_DEFAULT << 3);
|
||||
/* Reserved */
|
||||
ct3d->ecs_attrs[count].ecs_flags = 0;
|
||||
ct3d->ecs_attrs.fru_attrs[count].ecs_flags = 0;
|
||||
}
|
||||
|
||||
return;
|
||||
@@ -1200,6 +1200,7 @@ static void ct3d_reset(DeviceState *dev)
|
||||
uint32_t *reg_state = ct3d->cxl_cstate.crb.cache_mem_registers;
|
||||
uint32_t *write_msk = ct3d->cxl_cstate.crb.cache_mem_regs_write_mask;
|
||||
|
||||
pcie_cap_fill_link_ep_usp(PCI_DEVICE(dev), ct3d->width, ct3d->speed);
|
||||
cxl_component_register_init_common(reg_state, write_msk, CXL2_TYPE3_DEVICE);
|
||||
cxl_device_register_init_t3(ct3d);
|
||||
|
||||
@@ -1229,6 +1230,10 @@ static Property ct3_props[] = {
|
||||
DEFINE_PROP_UINT8("num-dc-regions", CXLType3Dev, dc.num_regions, 0),
|
||||
DEFINE_PROP_LINK("volatile-dc-memdev", CXLType3Dev, dc.host_dc,
|
||||
TYPE_MEMORY_BACKEND, HostMemoryBackend *),
|
||||
DEFINE_PROP_PCIE_LINK_SPEED("x-speed", CXLType3Dev,
|
||||
speed, PCIE_LINK_SPEED_32),
|
||||
DEFINE_PROP_PCIE_LINK_WIDTH("x-width", CXLType3Dev,
|
||||
width, PCIE_LINK_WIDTH_16),
|
||||
DEFINE_PROP_END_OF_LIST(),
|
||||
};
|
||||
|
||||
@@ -1375,9 +1380,7 @@ void qmp_cxl_inject_poison(const char *path, uint64_t start, uint64_t length,
|
||||
ct3d = CXL_TYPE3(obj);
|
||||
|
||||
QLIST_FOREACH(p, &ct3d->poison_list, node) {
|
||||
if (((start >= p->start) && (start < p->start + p->length)) ||
|
||||
((start + length > p->start) &&
|
||||
(start + length <= p->start + p->length))) {
|
||||
if ((start < p->start + p->length) && (start + length > p->start)) {
|
||||
error_setg(errp,
|
||||
"Overlap with existing poisoned region not supported");
|
||||
return;
|
||||
@@ -2060,11 +2063,11 @@ static void qmp_cxl_process_dynamic_capacity_prescriptive(const char *path,
|
||||
stw_le_p(&dCap.host_id, hid);
|
||||
/* only valid for DC_REGION_CONFIG_UPDATED event */
|
||||
dCap.updated_region_id = 0;
|
||||
dCap.flags = 0;
|
||||
for (i = 0; i < num_extents; i++) {
|
||||
memcpy(&dCap.dynamic_capacity_extent, &extents[i],
|
||||
sizeof(CXLDCExtentRaw));
|
||||
|
||||
dCap.flags = 0;
|
||||
if (i < num_extents - 1) {
|
||||
/* Set "More" flag */
|
||||
dCap.flags |= BIT(0);
|
||||
|
||||
@@ -13,6 +13,8 @@
|
||||
#include "hw/pci/msi.h"
|
||||
#include "hw/pci/pcie.h"
|
||||
#include "hw/pci/pcie_port.h"
|
||||
#include "hw/qdev-properties.h"
|
||||
#include "hw/qdev-properties-system.h"
|
||||
#include "hw/cxl/cxl.h"
|
||||
#include "qapi/error.h"
|
||||
|
||||
@@ -210,24 +212,20 @@ static void cxl_dsp_exitfn(PCIDevice *d)
|
||||
pci_bridge_exitfn(d);
|
||||
}
|
||||
|
||||
static void cxl_dsp_instance_post_init(Object *obj)
|
||||
{
|
||||
PCIESlot *s = PCIE_SLOT(obj);
|
||||
|
||||
if (!s->speed) {
|
||||
s->speed = QEMU_PCI_EXP_LNK_2_5GT;
|
||||
}
|
||||
|
||||
if (!s->width) {
|
||||
s->width = QEMU_PCI_EXP_LNK_X1;
|
||||
}
|
||||
}
|
||||
static Property cxl_dsp_props[] = {
|
||||
DEFINE_PROP_PCIE_LINK_SPEED("x-speed", PCIESlot,
|
||||
speed, PCIE_LINK_SPEED_64),
|
||||
DEFINE_PROP_PCIE_LINK_WIDTH("x-width", PCIESlot,
|
||||
width, PCIE_LINK_WIDTH_16),
|
||||
DEFINE_PROP_END_OF_LIST()
|
||||
};
|
||||
|
||||
static void cxl_dsp_class_init(ObjectClass *oc, void *data)
|
||||
{
|
||||
DeviceClass *dc = DEVICE_CLASS(oc);
|
||||
PCIDeviceClass *k = PCI_DEVICE_CLASS(oc);
|
||||
|
||||
device_class_set_props(dc, cxl_dsp_props);
|
||||
k->config_write = cxl_dsp_config_write;
|
||||
k->realize = cxl_dsp_realize;
|
||||
k->exit = cxl_dsp_exitfn;
|
||||
@@ -243,7 +241,6 @@ static const TypeInfo cxl_dsp_info = {
|
||||
.name = TYPE_CXL_DSP,
|
||||
.instance_size = sizeof(CXLDownstreamPort),
|
||||
.parent = TYPE_PCIE_SLOT,
|
||||
.instance_post_init = cxl_dsp_instance_post_init,
|
||||
.class_init = cxl_dsp_class_init,
|
||||
.interfaces = (InterfaceInfo[]) {
|
||||
{ INTERFACE_PCIE_DEVICE },
|
||||
|
||||
@@ -24,6 +24,7 @@
|
||||
#include "hw/pci/pcie_port.h"
|
||||
#include "hw/pci/msi.h"
|
||||
#include "hw/qdev-properties.h"
|
||||
#include "hw/qdev-properties-system.h"
|
||||
#include "hw/sysbus.h"
|
||||
#include "qapi/error.h"
|
||||
#include "hw/cxl/cxl.h"
|
||||
@@ -206,6 +207,10 @@ static Property gen_rp_props[] = {
|
||||
-1),
|
||||
DEFINE_PROP_SIZE("pref64-reserve", CXLRootPort, res_reserve.mem_pref_64,
|
||||
-1),
|
||||
DEFINE_PROP_PCIE_LINK_SPEED("x-speed", PCIESlot,
|
||||
speed, PCIE_LINK_SPEED_64),
|
||||
DEFINE_PROP_PCIE_LINK_WIDTH("x-width", PCIESlot,
|
||||
width, PCIE_LINK_WIDTH_32),
|
||||
DEFINE_PROP_END_OF_LIST()
|
||||
};
|
||||
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user