@@ -18,14 +18,83 @@
*/
#include "qemu/osdep.h"
+#include "hw/sysbus.h"
+#include "hw/pci/pci_bridge.h"
+#include "hw/pci/pci_host.h"
#include "hw/cxl/cxl.h"
+#include "hw/mem/memory-device.h"
#include "hw/acpi/acpi.h"
#include "hw/acpi/aml-build.h"
#include "hw/acpi/bios-linker-loader.h"
#include "hw/acpi/cxl.h"
+#include "hw/acpi/cxl.h"
#include "qapi/error.h"
#include "qemu/uuid.h"
+static void cedt_build_chbs(GArray *table_data, PXBDev *cxl)
+{
+ SysBusDevice *sbd = SYS_BUS_DEVICE(cxl->cxl.cxl_host_bridge);
+ struct MemoryRegion *mr = sbd->mmio[0].memory;
+
+ /* Type */
+ build_append_int_noprefix(table_data, 0, 1);
+
+ /* Reserved */
+ build_append_int_noprefix(table_data, 0, 1);
+
+ /* Record Length */
+ build_append_int_noprefix(table_data, 32, 2);
+
+ /* UID */
+ build_append_int_noprefix(table_data, cxl->uid, 4);
+
+ /* Version */
+ build_append_int_noprefix(table_data, 1, 4);
+
+ /* Reserved */
+ build_append_int_noprefix(table_data, 0, 4);
+
+ /* Base */
+ build_append_int_noprefix(table_data, mr->addr, 8);
+
+ /* Length */
+ build_append_int_noprefix(table_data, memory_region_size(mr), 8);
+}
+
+static int cxl_foreach_pxb_hb(Object *obj, void *opaque)
+{
+ Aml *cedt = opaque;
+
+ if (object_dynamic_cast(obj, TYPE_PXB_CXL_DEVICE)) {
+ PXBDev *pxb = PXB_CXL_DEV(obj);
+
+ cedt_build_chbs(cedt->buf, pxb);
+ }
+
+ return 0;
+}
+
+void cxl_build_cedt(GArray *table_offsets, GArray *table_data,
+ BIOSLinker *linker)
+{
+ const int cedt_start = table_data->len;
+ Aml *cedt;
+
+ cedt = init_aml_allocator();
+
+ /* reserve space for CEDT header */
+ acpi_add_table(table_offsets, table_data);
+ acpi_data_push(cedt->buf, sizeof(AcpiTableHeader));
+
+ object_child_foreach_recursive(object_get_root(), cxl_foreach_pxb_hb, cedt);
+
+ /* copy AML table into ACPI tables blob and patch header there */
+ g_array_append_vals(table_data, cedt->buf->data, cedt->buf->len);
+ build_header(linker, table_data, (void *)(table_data->data + cedt_start),
+ "CEDT", table_data->len - cedt_start, 1, NULL, NULL);
+ free_aml_allocator();
+}
+
static Aml *__build_cxl_osc_method(void)
{
Aml *method, *if_uuid, *else_uuid, *if_arg1_not_1, *if_cxl, *if_caps_masked;
@@ -75,6 +75,8 @@
#include "hw/acpi/ipmi.h"
#include "hw/acpi/hmat.h"
+#include "hw/acpi/cxl.h"
+
/* These are used to size the ACPI tables for -M pc-i440fx-1.7 and
* -M pc-i440fx-2.0. Even if the actual amount of AML generated grows
* a little bit, there should be plenty of free space since the DSDT
@@ -1371,7 +1373,7 @@ build_dsdt(GArray *table_data, BIOSLinker *linker,
scope = aml_scope("\\_SB");
if (type == CXL) {
- dev = aml_device("CXL%.01X", pci_bus_uid(bus));
+ dev = aml_device("CXL%.01X", uid);
} else {
dev = aml_device("PC%.02X", bus_num);
}
@@ -2277,6 +2279,8 @@ void acpi_build(AcpiBuildTables *tables, MachineState *machine)
machine->nvdimms_state, machine->ram_slots);
}
+ cxl_build_cedt(table_offsets, tables_blob, tables->linker);
+
acpi_add_table(table_offsets, tables_blob);
build_waet(tables_blob, tables->linker);
@@ -57,26 +57,6 @@ DECLARE_INSTANCE_CHECKER(PXBDev, PXB_DEV,
DECLARE_INSTANCE_CHECKER(PXBDev, PXB_PCIE_DEV,
TYPE_PXB_PCIE_DEVICE)
-#define TYPE_PXB_CXL_DEVICE "pxb-cxl"
-DECLARE_INSTANCE_CHECKER(PXBDev, PXB_CXL_DEV,
- TYPE_PXB_CXL_DEVICE)
-
-struct PXBDev {
- /*< private >*/
- PCIDevice parent_obj;
- /*< public >*/
-
- uint8_t bus_nr;
- uint16_t numa_node;
- int32_t uid;
- struct cxl_dev {
- HostMemoryBackend *memory_window[CXL_WINDOW_MAX];
-
- uint32_t num_windows;
- hwaddr *window_base[CXL_WINDOW_MAX];
- } cxl;
-};
-
typedef struct CXLHost {
PCIHostState parent_obj;
@@ -351,6 +331,7 @@ static void pxb_dev_realize_common(PCIDevice *dev, enum BusType type,
bus = pci_root_bus_new(ds, dev_name, NULL, NULL, 0, TYPE_PXB_CXL_BUS);
bus->flags |= PCI_BUS_CXL;
PXB_CXL_HOST(ds)->dev = PXB_CXL_DEV(dev);
+ PXB_CXL_DEV(dev)->cxl.cxl_host_bridge = ds;
} else {
bus = pci_root_bus_new(ds, "pxb-internal", NULL, NULL, 0, TYPE_PXB_BUS);
bds = qdev_new("pci-bridge");
@@ -18,6 +18,10 @@
#ifndef HW_ACPI_CXL_H
#define HW_ACPI_CXL_H
+#include "hw/acpi/bios-linker-loader.h"
+
+void cxl_build_cedt(GArray *table_offsets, GArray *table_data,
+ BIOSLinker *linker);
void build_cxl_osc_method(Aml *dev);
#endif
@@ -28,6 +28,7 @@
#include "hw/pci/pci.h"
#include "hw/pci/pci_bus.h"
+#include "hw/cxl/cxl.h"
#include "qom/object.h"
typedef struct PCIBridgeWindows PCIBridgeWindows;
@@ -81,6 +82,30 @@ struct PCIBridge {
#define PCI_BRIDGE_DEV_PROP_MSI "msi"
#define PCI_BRIDGE_DEV_PROP_SHPC "shpc"
+struct PXBDev {
+ /*< private >*/
+ PCIDevice parent_obj;
+ /*< public >*/
+
+ uint8_t bus_nr;
+ uint16_t numa_node;
+ int32_t uid;
+
+ struct cxl_dev {
+ HostMemoryBackend *memory_window[CXL_WINDOW_MAX];
+
+ uint32_t num_windows;
+ hwaddr *window_base[CXL_WINDOW_MAX];
+
+ void *cxl_host_bridge; /* Pointer to a CXLHost */
+ } cxl;
+};
+
+typedef struct PXBDev PXBDev;
+#define TYPE_PXB_CXL_DEVICE "pxb-cxl"
+DECLARE_INSTANCE_CHECKER(PXBDev, PXB_CXL_DEV,
+ TYPE_PXB_CXL_DEVICE)
+
int pci_bridge_ssvid_init(PCIDevice *dev, uint8_t offset,
uint16_t svid, uint16_t ssid,
Error **errp);
The CXL Early Discovery Table is defined in the CXL 2.0 specification as a way for the OS to get CXL specific information from the system firmware. As of CXL 2.0 spec, only 1 sub structure is defined, the CXL Host Bridge Structure (CHBS) which is primarily useful for telling the OS exactly where the MMIO for the host bridge is. v2: Update CHBS to spec released definition Signed-off-by: Ben Widawsky <ben.widawsky@intel.com> --- hw/acpi/cxl.c | 69 +++++++++++++++++++++++++++++ hw/i386/acpi-build.c | 6 ++- hw/pci-bridge/pci_expander_bridge.c | 21 +-------- include/hw/acpi/cxl.h | 4 ++ include/hw/pci/pci_bridge.h | 25 +++++++++++ 5 files changed, 104 insertions(+), 21 deletions(-)