123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256 |
- /*
- * CXL ACPI Implementation
- *
- * Copyright(C) 2020 Intel Corporation.
- *
- * This library is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation; either
- * version 2 of the License, or (at your option) any later version.
- *
- * This library is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * Lesser General Public License for more details.
- *
- * You should have received a copy of the GNU Lesser General Public
- * License along with this library; if not, see <http://www.gnu.org/licenses/>
- */
- #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 "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 - currently equal to bus number */
- build_append_int_noprefix(table_data, cxl->bus_nr, 4);
- /* Version */
- build_append_int_noprefix(table_data, 1, 4);
- /* Reserved */
- build_append_int_noprefix(table_data, 0, 4);
- /* Base - subregion within a container that is in PA space */
- build_append_int_noprefix(table_data, mr->container->addr + mr->addr, 8);
- /* Length */
- build_append_int_noprefix(table_data, memory_region_size(mr), 8);
- }
- /*
- * CFMWS entries in CXL 2.0 ECN: CEDT CFMWS & QTG _DSM.
- * Interleave ways encoding in CXL 2.0 ECN: 3, 6, 12 and 16-way memory
- * interleaving.
- */
- static void cedt_build_cfmws(GArray *table_data, CXLState *cxls)
- {
- GList *it;
- for (it = cxls->fixed_windows; it; it = it->next) {
- CXLFixedWindow *fw = it->data;
- int i;
- /* Type */
- build_append_int_noprefix(table_data, 1, 1);
- /* Reserved */
- build_append_int_noprefix(table_data, 0, 1);
- /* Record Length */
- build_append_int_noprefix(table_data, 36 + 4 * fw->num_targets, 2);
- /* Reserved */
- build_append_int_noprefix(table_data, 0, 4);
- /* Base HPA */
- build_append_int_noprefix(table_data, fw->mr.addr, 8);
- /* Window Size */
- build_append_int_noprefix(table_data, fw->size, 8);
- /* Host Bridge Interleave Ways */
- build_append_int_noprefix(table_data, fw->enc_int_ways, 1);
- /* Host Bridge Interleave Arithmetic */
- build_append_int_noprefix(table_data, 0, 1);
- /* Reserved */
- build_append_int_noprefix(table_data, 0, 2);
- /* Host Bridge Interleave Granularity */
- build_append_int_noprefix(table_data, fw->enc_int_gran, 4);
- /* Window Restrictions */
- build_append_int_noprefix(table_data, 0x0f, 2); /* No restrictions */
- /* QTG ID */
- build_append_int_noprefix(table_data, 0, 2);
- /* Host Bridge List (list of UIDs - currently bus_nr) */
- for (i = 0; i < fw->num_targets; i++) {
- g_assert(fw->target_hbs[i]);
- build_append_int_noprefix(table_data, fw->target_hbs[i]->bus_nr, 4);
- }
- }
- }
- static int cxl_foreach_pxb_hb(Object *obj, void *opaque)
- {
- Aml *cedt = opaque;
- if (object_dynamic_cast(obj, TYPE_PXB_CXL_DEVICE)) {
- cedt_build_chbs(cedt->buf, PXB_CXL_DEV(obj));
- }
- return 0;
- }
- void cxl_build_cedt(GArray *table_offsets, GArray *table_data,
- BIOSLinker *linker, const char *oem_id,
- const char *oem_table_id, CXLState *cxl_state)
- {
- Aml *cedt;
- AcpiTable table = { .sig = "CEDT", .rev = 1, .oem_id = oem_id,
- .oem_table_id = oem_table_id };
- acpi_add_table(table_offsets, table_data);
- acpi_table_begin(&table, table_data);
- cedt = init_aml_allocator();
- /* reserve space for CEDT header */
- object_child_foreach_recursive(object_get_root(), cxl_foreach_pxb_hb, cedt);
- cedt_build_cfmws(cedt->buf, cxl_state);
- /* copy AML table into ACPI tables blob and patch header there */
- g_array_append_vals(table_data, cedt->buf->data, cedt->buf->len);
- free_aml_allocator();
- acpi_table_end(linker, &table);
- }
- static Aml *__build_cxl_osc_method(void)
- {
- Aml *method, *if_uuid, *else_uuid, *if_arg1_not_1, *if_cxl, *if_caps_masked;
- Aml *a_ctrl = aml_local(0);
- Aml *a_cdw1 = aml_name("CDW1");
- method = aml_method("_OSC", 4, AML_NOTSERIALIZED);
- /* CDW1 is used for the return value so is present whether or not a match occurs */
- aml_append(method, aml_create_dword_field(aml_arg(3), aml_int(0), "CDW1"));
- /*
- * Generate shared section between:
- * CXL 2.0 - 9.14.2.1.4 and
- * PCI Firmware Specification 3.0
- * 4.5.1. _OSC Interface for PCI Host Bridge Devices
- * The _OSC interface for a PCI/PCI-X/PCI Express hierarchy is
- * identified by the Universal Unique IDentifier (UUID)
- * 33DB4D5B-1FF7-401C-9657-7441C03DD766
- * The _OSC interface for a CXL Host bridge is
- * identified by the UUID 68F2D50B-C469-4D8A-BD3D-941A103FD3FC
- * A CXL Host bridge is compatible with a PCI host bridge so
- * for the shared section match both.
- */
- if_uuid = aml_if(
- aml_lor(aml_equal(aml_arg(0),
- aml_touuid("33DB4D5B-1FF7-401C-9657-7441C03DD766")),
- aml_equal(aml_arg(0),
- aml_touuid("68F2D50B-C469-4D8A-BD3D-941A103FD3FC"))));
- aml_append(if_uuid, aml_create_dword_field(aml_arg(3), aml_int(4), "CDW2"));
- aml_append(if_uuid, aml_create_dword_field(aml_arg(3), aml_int(8), "CDW3"));
- aml_append(if_uuid, aml_store(aml_name("CDW3"), a_ctrl));
- /*
- *
- * Allows OS control for all 5 features:
- * PCIeHotplug SHPCHotplug PME AER PCIeCapability
- */
- aml_append(if_uuid, aml_and(a_ctrl, aml_int(0x1F), a_ctrl));
- /*
- * Check _OSC revision.
- * PCI Firmware specification 3.3 and CXL 2.0 both use revision 1
- * Unknown Revision is CDW1 - BIT (3)
- */
- if_arg1_not_1 = aml_if(aml_lnot(aml_equal(aml_arg(1), aml_int(0x1))));
- aml_append(if_arg1_not_1, aml_or(a_cdw1, aml_int(0x08), a_cdw1));
- aml_append(if_uuid, if_arg1_not_1);
- if_caps_masked = aml_if(aml_lnot(aml_equal(aml_name("CDW3"), a_ctrl)));
- /* Capability bits were masked */
- aml_append(if_caps_masked, aml_or(a_cdw1, aml_int(0x10), a_cdw1));
- aml_append(if_uuid, if_caps_masked);
- aml_append(if_uuid, aml_store(aml_name("CDW2"), aml_name("SUPP")));
- aml_append(if_uuid, aml_store(aml_name("CDW3"), aml_name("CTRL")));
- /* Update DWORD3 (the return value) */
- aml_append(if_uuid, aml_store(a_ctrl, aml_name("CDW3")));
- /* CXL only section as per CXL 2.0 - 9.14.2.1.4 */
- if_cxl = aml_if(aml_equal(
- aml_arg(0), aml_touuid("68F2D50B-C469-4D8A-BD3D-941A103FD3FC")));
- /* CXL support field */
- aml_append(if_cxl, aml_create_dword_field(aml_arg(3), aml_int(12), "CDW4"));
- /* CXL capabilities */
- aml_append(if_cxl, aml_create_dword_field(aml_arg(3), aml_int(16), "CDW5"));
- aml_append(if_cxl, aml_store(aml_name("CDW4"), aml_name("SUPC")));
- aml_append(if_cxl, aml_store(aml_name("CDW5"), aml_name("CTRC")));
- /* CXL 2.0 Port/Device Register access */
- aml_append(if_cxl,
- aml_or(aml_name("CDW5"), aml_int(0x1), aml_name("CDW5")));
- aml_append(if_uuid, if_cxl);
- aml_append(if_uuid, aml_return(aml_arg(3)));
- aml_append(method, if_uuid);
- /*
- * If no UUID matched, return Unrecognized UUID via Arg3 DWord 1
- * ACPI 6.4 - 6.2.11
- * Unrecognised UUID - BIT(2)
- */
- else_uuid = aml_else();
- aml_append(else_uuid,
- aml_or(aml_name("CDW1"), aml_int(0x4), aml_name("CDW1")));
- aml_append(else_uuid, aml_return(aml_arg(3)));
- aml_append(method, else_uuid);
- return method;
- }
- void build_cxl_osc_method(Aml *dev)
- {
- aml_append(dev, aml_name_decl("SUPP", aml_int(0)));
- aml_append(dev, aml_name_decl("CTRL", aml_int(0)));
- aml_append(dev, aml_name_decl("SUPC", aml_int(0)));
- aml_append(dev, aml_name_decl("CTRC", aml_int(0)));
- aml_append(dev, __build_cxl_osc_method());
- }
|