12a3282c6SBen Widawsky /*
22a3282c6SBen Widawsky * CXL ACPI Implementation
32a3282c6SBen Widawsky *
42a3282c6SBen Widawsky * Copyright(C) 2020 Intel Corporation.
52a3282c6SBen Widawsky *
62a3282c6SBen Widawsky * This library is free software; you can redistribute it and/or
72a3282c6SBen Widawsky * modify it under the terms of the GNU Lesser General Public
82a3282c6SBen Widawsky * License as published by the Free Software Foundation; either
92a3282c6SBen Widawsky * version 2 of the License, or (at your option) any later version.
102a3282c6SBen Widawsky *
112a3282c6SBen Widawsky * This library is distributed in the hope that it will be useful,
122a3282c6SBen Widawsky * but WITHOUT ANY WARRANTY; without even the implied warranty of
132a3282c6SBen Widawsky * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
142a3282c6SBen Widawsky * Lesser General Public License for more details.
152a3282c6SBen Widawsky *
162a3282c6SBen Widawsky * You should have received a copy of the GNU Lesser General Public
172a3282c6SBen Widawsky * License along with this library; if not, see <http://www.gnu.org/licenses/>
182a3282c6SBen Widawsky */
192a3282c6SBen Widawsky
202a3282c6SBen Widawsky #include "qemu/osdep.h"
213d6a69b6SBen Widawsky #include "hw/sysbus.h"
223d6a69b6SBen Widawsky #include "hw/pci/pci_bridge.h"
233d6a69b6SBen Widawsky #include "hw/pci/pci_host.h"
242a3282c6SBen Widawsky #include "hw/cxl/cxl.h"
253d6a69b6SBen Widawsky #include "hw/mem/memory-device.h"
262a3282c6SBen Widawsky #include "hw/acpi/acpi.h"
272a3282c6SBen Widawsky #include "hw/acpi/aml-build.h"
282a3282c6SBen Widawsky #include "hw/acpi/bios-linker-loader.h"
292a3282c6SBen Widawsky #include "hw/acpi/cxl.h"
302a3282c6SBen Widawsky #include "qapi/error.h"
312a3282c6SBen Widawsky #include "qemu/uuid.h"
322a3282c6SBen Widawsky
build_cxl_dsm_method(Aml * dev)33*6cdd46f6SDave Jiang void build_cxl_dsm_method(Aml *dev)
34*6cdd46f6SDave Jiang {
35*6cdd46f6SDave Jiang Aml *method, *ifctx, *ifctx2;
36*6cdd46f6SDave Jiang
37*6cdd46f6SDave Jiang method = aml_method("_DSM", 4, AML_SERIALIZED);
38*6cdd46f6SDave Jiang {
39*6cdd46f6SDave Jiang Aml *function, *uuid;
40*6cdd46f6SDave Jiang
41*6cdd46f6SDave Jiang uuid = aml_arg(0);
42*6cdd46f6SDave Jiang function = aml_arg(2);
43*6cdd46f6SDave Jiang /* CXL spec v3.0 9.17.3.1 _DSM Function for Retrieving QTG ID */
44*6cdd46f6SDave Jiang ifctx = aml_if(aml_equal(
45*6cdd46f6SDave Jiang uuid, aml_touuid("F365F9A6-A7DE-4071-A66A-B40C0B4F8E52")));
46*6cdd46f6SDave Jiang
47*6cdd46f6SDave Jiang /* Function 0, standard DSM query function */
48*6cdd46f6SDave Jiang ifctx2 = aml_if(aml_equal(function, aml_int(0)));
49*6cdd46f6SDave Jiang {
50*6cdd46f6SDave Jiang uint8_t byte_list[1] = { 0x01 }; /* function 1 only */
51*6cdd46f6SDave Jiang
52*6cdd46f6SDave Jiang aml_append(ifctx2,
53*6cdd46f6SDave Jiang aml_return(aml_buffer(sizeof(byte_list), byte_list)));
54*6cdd46f6SDave Jiang }
55*6cdd46f6SDave Jiang aml_append(ifctx, ifctx2);
56*6cdd46f6SDave Jiang
57*6cdd46f6SDave Jiang /*
58*6cdd46f6SDave Jiang * Function 1
59*6cdd46f6SDave Jiang * Creating a package with static values. The max supported QTG ID will
60*6cdd46f6SDave Jiang * be 1 and recommended QTG IDs are 0 and then 1.
61*6cdd46f6SDave Jiang * The values here are statically created to simplify emulation. Values
62*6cdd46f6SDave Jiang * from a real BIOS would be determined by the performance of all the
63*6cdd46f6SDave Jiang * present CXL memory and then assigned.
64*6cdd46f6SDave Jiang */
65*6cdd46f6SDave Jiang ifctx2 = aml_if(aml_equal(function, aml_int(1)));
66*6cdd46f6SDave Jiang {
67*6cdd46f6SDave Jiang Aml *pak, *pak1;
68*6cdd46f6SDave Jiang
69*6cdd46f6SDave Jiang /*
70*6cdd46f6SDave Jiang * Return: A package containing two elements - a WORD that returns
71*6cdd46f6SDave Jiang * the maximum throttling group that the platform supports, and a
72*6cdd46f6SDave Jiang * package containing the QTG ID(s) that the platform recommends.
73*6cdd46f6SDave Jiang * Package {
74*6cdd46f6SDave Jiang * Max Supported QTG ID
75*6cdd46f6SDave Jiang * Package {QTG Recommendations}
76*6cdd46f6SDave Jiang * }
77*6cdd46f6SDave Jiang *
78*6cdd46f6SDave Jiang * While the SPEC specified WORD that hints at the value being
79*6cdd46f6SDave Jiang * 16bit, the ACPI dump of BIOS DSDT table showed that the values
80*6cdd46f6SDave Jiang * are integers with no specific size specification. aml_int() will
81*6cdd46f6SDave Jiang * be used for the values.
82*6cdd46f6SDave Jiang */
83*6cdd46f6SDave Jiang pak1 = aml_package(2);
84*6cdd46f6SDave Jiang /* Set QTG ID of 0 */
85*6cdd46f6SDave Jiang aml_append(pak1, aml_int(0));
86*6cdd46f6SDave Jiang /* Set QTG ID of 1 */
87*6cdd46f6SDave Jiang aml_append(pak1, aml_int(1));
88*6cdd46f6SDave Jiang
89*6cdd46f6SDave Jiang pak = aml_package(2);
90*6cdd46f6SDave Jiang /* Set Max QTG 1 */
91*6cdd46f6SDave Jiang aml_append(pak, aml_int(1));
92*6cdd46f6SDave Jiang aml_append(pak, pak1);
93*6cdd46f6SDave Jiang
94*6cdd46f6SDave Jiang aml_append(ifctx2, aml_return(pak));
95*6cdd46f6SDave Jiang }
96*6cdd46f6SDave Jiang aml_append(ifctx, ifctx2);
97*6cdd46f6SDave Jiang }
98*6cdd46f6SDave Jiang aml_append(method, ifctx);
99*6cdd46f6SDave Jiang aml_append(dev, method);
100*6cdd46f6SDave Jiang }
101*6cdd46f6SDave Jiang
cedt_build_chbs(GArray * table_data,PXBCXLDev * cxl)102c28db9e0SJonathan Cameron static void cedt_build_chbs(GArray *table_data, PXBCXLDev *cxl)
1033d6a69b6SBen Widawsky {
104c28db9e0SJonathan Cameron PXBDev *pxb = PXB_DEV(cxl);
105c28db9e0SJonathan Cameron SysBusDevice *sbd = SYS_BUS_DEVICE(cxl->cxl_host_bridge);
1063d6a69b6SBen Widawsky struct MemoryRegion *mr = sbd->mmio[0].memory;
1073d6a69b6SBen Widawsky
1083d6a69b6SBen Widawsky /* Type */
1093d6a69b6SBen Widawsky build_append_int_noprefix(table_data, 0, 1);
1103d6a69b6SBen Widawsky
1113d6a69b6SBen Widawsky /* Reserved */
1123d6a69b6SBen Widawsky build_append_int_noprefix(table_data, 0, 1);
1133d6a69b6SBen Widawsky
1143d6a69b6SBen Widawsky /* Record Length */
1153d6a69b6SBen Widawsky build_append_int_noprefix(table_data, 32, 2);
1163d6a69b6SBen Widawsky
1173d6a69b6SBen Widawsky /* UID - currently equal to bus number */
118c28db9e0SJonathan Cameron build_append_int_noprefix(table_data, pxb->bus_nr, 4);
1193d6a69b6SBen Widawsky
1203d6a69b6SBen Widawsky /* Version */
1213d6a69b6SBen Widawsky build_append_int_noprefix(table_data, 1, 4);
1223d6a69b6SBen Widawsky
1233d6a69b6SBen Widawsky /* Reserved */
1243d6a69b6SBen Widawsky build_append_int_noprefix(table_data, 0, 4);
1253d6a69b6SBen Widawsky
1263d6a69b6SBen Widawsky /* Base - subregion within a container that is in PA space */
1273d6a69b6SBen Widawsky build_append_int_noprefix(table_data, mr->container->addr + mr->addr, 8);
1283d6a69b6SBen Widawsky
1293d6a69b6SBen Widawsky /* Length */
1303d6a69b6SBen Widawsky build_append_int_noprefix(table_data, memory_region_size(mr), 8);
1313d6a69b6SBen Widawsky }
1323d6a69b6SBen Widawsky
13321df6ab9SBen Widawsky /*
13421df6ab9SBen Widawsky * CFMWS entries in CXL 2.0 ECN: CEDT CFMWS & QTG _DSM.
13521df6ab9SBen Widawsky * Interleave ways encoding in CXL 2.0 ECN: 3, 6, 12 and 16-way memory
13621df6ab9SBen Widawsky * interleaving.
13721df6ab9SBen Widawsky */
cedt_build_cfmws(GArray * table_data,CXLState * cxls)13851359805SJonathan Cameron static void cedt_build_cfmws(GArray *table_data, CXLState *cxls)
13921df6ab9SBen Widawsky {
14021df6ab9SBen Widawsky GList *it;
14121df6ab9SBen Widawsky
14221df6ab9SBen Widawsky for (it = cxls->fixed_windows; it; it = it->next) {
14321df6ab9SBen Widawsky CXLFixedWindow *fw = it->data;
14421df6ab9SBen Widawsky int i;
14521df6ab9SBen Widawsky
14621df6ab9SBen Widawsky /* Type */
14721df6ab9SBen Widawsky build_append_int_noprefix(table_data, 1, 1);
14821df6ab9SBen Widawsky
14921df6ab9SBen Widawsky /* Reserved */
15021df6ab9SBen Widawsky build_append_int_noprefix(table_data, 0, 1);
15121df6ab9SBen Widawsky
15221df6ab9SBen Widawsky /* Record Length */
15321df6ab9SBen Widawsky build_append_int_noprefix(table_data, 36 + 4 * fw->num_targets, 2);
15421df6ab9SBen Widawsky
15521df6ab9SBen Widawsky /* Reserved */
15621df6ab9SBen Widawsky build_append_int_noprefix(table_data, 0, 4);
15721df6ab9SBen Widawsky
15821df6ab9SBen Widawsky /* Base HPA */
15921df6ab9SBen Widawsky build_append_int_noprefix(table_data, fw->mr.addr, 8);
16021df6ab9SBen Widawsky
16121df6ab9SBen Widawsky /* Window Size */
16221df6ab9SBen Widawsky build_append_int_noprefix(table_data, fw->size, 8);
16321df6ab9SBen Widawsky
16421df6ab9SBen Widawsky /* Host Bridge Interleave Ways */
16521df6ab9SBen Widawsky build_append_int_noprefix(table_data, fw->enc_int_ways, 1);
16621df6ab9SBen Widawsky
16721df6ab9SBen Widawsky /* Host Bridge Interleave Arithmetic */
16821df6ab9SBen Widawsky build_append_int_noprefix(table_data, 0, 1);
16921df6ab9SBen Widawsky
17021df6ab9SBen Widawsky /* Reserved */
17121df6ab9SBen Widawsky build_append_int_noprefix(table_data, 0, 2);
17221df6ab9SBen Widawsky
17321df6ab9SBen Widawsky /* Host Bridge Interleave Granularity */
17421df6ab9SBen Widawsky build_append_int_noprefix(table_data, fw->enc_int_gran, 4);
17521df6ab9SBen Widawsky
17621df6ab9SBen Widawsky /* Window Restrictions */
17721df6ab9SBen Widawsky build_append_int_noprefix(table_data, 0x0f, 2); /* No restrictions */
17821df6ab9SBen Widawsky
17921df6ab9SBen Widawsky /* QTG ID */
18021df6ab9SBen Widawsky build_append_int_noprefix(table_data, 0, 2);
18121df6ab9SBen Widawsky
18221df6ab9SBen Widawsky /* Host Bridge List (list of UIDs - currently bus_nr) */
18321df6ab9SBen Widawsky for (i = 0; i < fw->num_targets; i++) {
18421df6ab9SBen Widawsky g_assert(fw->target_hbs[i]);
185c28db9e0SJonathan Cameron build_append_int_noprefix(table_data, PXB_DEV(fw->target_hbs[i])->bus_nr, 4);
18621df6ab9SBen Widawsky }
18721df6ab9SBen Widawsky }
18821df6ab9SBen Widawsky }
18921df6ab9SBen Widawsky
cxl_foreach_pxb_hb(Object * obj,void * opaque)1903d6a69b6SBen Widawsky static int cxl_foreach_pxb_hb(Object *obj, void *opaque)
1913d6a69b6SBen Widawsky {
1923d6a69b6SBen Widawsky Aml *cedt = opaque;
1933d6a69b6SBen Widawsky
194c28db9e0SJonathan Cameron if (object_dynamic_cast(obj, TYPE_PXB_CXL_DEV)) {
1953d6a69b6SBen Widawsky cedt_build_chbs(cedt->buf, PXB_CXL_DEV(obj));
1963d6a69b6SBen Widawsky }
1973d6a69b6SBen Widawsky
1983d6a69b6SBen Widawsky return 0;
1993d6a69b6SBen Widawsky }
2003d6a69b6SBen Widawsky
cxl_build_cedt(GArray * table_offsets,GArray * table_data,BIOSLinker * linker,const char * oem_id,const char * oem_table_id,CXLState * cxl_state)20151359805SJonathan Cameron void cxl_build_cedt(GArray *table_offsets, GArray *table_data,
2023d6a69b6SBen Widawsky BIOSLinker *linker, const char *oem_id,
20351359805SJonathan Cameron const char *oem_table_id, CXLState *cxl_state)
2043d6a69b6SBen Widawsky {
2053d6a69b6SBen Widawsky Aml *cedt;
2063d6a69b6SBen Widawsky AcpiTable table = { .sig = "CEDT", .rev = 1, .oem_id = oem_id,
2073d6a69b6SBen Widawsky .oem_table_id = oem_table_id };
2083d6a69b6SBen Widawsky
2093d6a69b6SBen Widawsky acpi_add_table(table_offsets, table_data);
2103d6a69b6SBen Widawsky acpi_table_begin(&table, table_data);
2113d6a69b6SBen Widawsky cedt = init_aml_allocator();
2123d6a69b6SBen Widawsky
2133d6a69b6SBen Widawsky /* reserve space for CEDT header */
2143d6a69b6SBen Widawsky
2153d6a69b6SBen Widawsky object_child_foreach_recursive(object_get_root(), cxl_foreach_pxb_hb, cedt);
21651359805SJonathan Cameron cedt_build_cfmws(cedt->buf, cxl_state);
2173d6a69b6SBen Widawsky
2183d6a69b6SBen Widawsky /* copy AML table into ACPI tables blob and patch header there */
2193d6a69b6SBen Widawsky g_array_append_vals(table_data, cedt->buf->data, cedt->buf->len);
2203d6a69b6SBen Widawsky free_aml_allocator();
2213d6a69b6SBen Widawsky
2223d6a69b6SBen Widawsky acpi_table_end(linker, &table);
2233d6a69b6SBen Widawsky }
2243d6a69b6SBen Widawsky
__build_cxl_osc_method(void)2252a3282c6SBen Widawsky static Aml *__build_cxl_osc_method(void)
2262a3282c6SBen Widawsky {
2272a3282c6SBen Widawsky Aml *method, *if_uuid, *else_uuid, *if_arg1_not_1, *if_cxl, *if_caps_masked;
2282a3282c6SBen Widawsky Aml *a_ctrl = aml_local(0);
2292a3282c6SBen Widawsky Aml *a_cdw1 = aml_name("CDW1");
2302a3282c6SBen Widawsky
2312a3282c6SBen Widawsky method = aml_method("_OSC", 4, AML_NOTSERIALIZED);
2322a3282c6SBen Widawsky /* CDW1 is used for the return value so is present whether or not a match occurs */
2332a3282c6SBen Widawsky aml_append(method, aml_create_dword_field(aml_arg(3), aml_int(0), "CDW1"));
2342a3282c6SBen Widawsky
2352a3282c6SBen Widawsky /*
2362a3282c6SBen Widawsky * Generate shared section between:
2372a3282c6SBen Widawsky * CXL 2.0 - 9.14.2.1.4 and
2382a3282c6SBen Widawsky * PCI Firmware Specification 3.0
2392a3282c6SBen Widawsky * 4.5.1. _OSC Interface for PCI Host Bridge Devices
2402a3282c6SBen Widawsky * The _OSC interface for a PCI/PCI-X/PCI Express hierarchy is
2412a3282c6SBen Widawsky * identified by the Universal Unique IDentifier (UUID)
2422a3282c6SBen Widawsky * 33DB4D5B-1FF7-401C-9657-7441C03DD766
2432a3282c6SBen Widawsky * The _OSC interface for a CXL Host bridge is
2442a3282c6SBen Widawsky * identified by the UUID 68F2D50B-C469-4D8A-BD3D-941A103FD3FC
2452a3282c6SBen Widawsky * A CXL Host bridge is compatible with a PCI host bridge so
2462a3282c6SBen Widawsky * for the shared section match both.
2472a3282c6SBen Widawsky */
2482a3282c6SBen Widawsky if_uuid = aml_if(
2492a3282c6SBen Widawsky aml_lor(aml_equal(aml_arg(0),
2502a3282c6SBen Widawsky aml_touuid("33DB4D5B-1FF7-401C-9657-7441C03DD766")),
2512a3282c6SBen Widawsky aml_equal(aml_arg(0),
2522a3282c6SBen Widawsky aml_touuid("68F2D50B-C469-4D8A-BD3D-941A103FD3FC"))));
2532a3282c6SBen Widawsky aml_append(if_uuid, aml_create_dword_field(aml_arg(3), aml_int(4), "CDW2"));
2542a3282c6SBen Widawsky aml_append(if_uuid, aml_create_dword_field(aml_arg(3), aml_int(8), "CDW3"));
2552a3282c6SBen Widawsky
2562a3282c6SBen Widawsky aml_append(if_uuid, aml_store(aml_name("CDW3"), a_ctrl));
2572a3282c6SBen Widawsky
2582a3282c6SBen Widawsky /*
2592a3282c6SBen Widawsky *
2602a3282c6SBen Widawsky * Allows OS control for all 5 features:
2612a3282c6SBen Widawsky * PCIeHotplug SHPCHotplug PME AER PCIeCapability
2622a3282c6SBen Widawsky */
2632a3282c6SBen Widawsky aml_append(if_uuid, aml_and(a_ctrl, aml_int(0x1F), a_ctrl));
2642a3282c6SBen Widawsky
2652a3282c6SBen Widawsky /*
2662a3282c6SBen Widawsky * Check _OSC revision.
2672a3282c6SBen Widawsky * PCI Firmware specification 3.3 and CXL 2.0 both use revision 1
2682a3282c6SBen Widawsky * Unknown Revision is CDW1 - BIT (3)
2692a3282c6SBen Widawsky */
2702a3282c6SBen Widawsky if_arg1_not_1 = aml_if(aml_lnot(aml_equal(aml_arg(1), aml_int(0x1))));
2712a3282c6SBen Widawsky aml_append(if_arg1_not_1, aml_or(a_cdw1, aml_int(0x08), a_cdw1));
2722a3282c6SBen Widawsky aml_append(if_uuid, if_arg1_not_1);
2732a3282c6SBen Widawsky
2742a3282c6SBen Widawsky if_caps_masked = aml_if(aml_lnot(aml_equal(aml_name("CDW3"), a_ctrl)));
2752a3282c6SBen Widawsky
2762a3282c6SBen Widawsky /* Capability bits were masked */
2772a3282c6SBen Widawsky aml_append(if_caps_masked, aml_or(a_cdw1, aml_int(0x10), a_cdw1));
2782a3282c6SBen Widawsky aml_append(if_uuid, if_caps_masked);
2792a3282c6SBen Widawsky
2802a3282c6SBen Widawsky aml_append(if_uuid, aml_store(aml_name("CDW2"), aml_name("SUPP")));
2812a3282c6SBen Widawsky aml_append(if_uuid, aml_store(aml_name("CDW3"), aml_name("CTRL")));
2822a3282c6SBen Widawsky
2832a3282c6SBen Widawsky /* Update DWORD3 (the return value) */
2842a3282c6SBen Widawsky aml_append(if_uuid, aml_store(a_ctrl, aml_name("CDW3")));
2852a3282c6SBen Widawsky
2862a3282c6SBen Widawsky /* CXL only section as per CXL 2.0 - 9.14.2.1.4 */
2872a3282c6SBen Widawsky if_cxl = aml_if(aml_equal(
2882a3282c6SBen Widawsky aml_arg(0), aml_touuid("68F2D50B-C469-4D8A-BD3D-941A103FD3FC")));
2892a3282c6SBen Widawsky /* CXL support field */
2902a3282c6SBen Widawsky aml_append(if_cxl, aml_create_dword_field(aml_arg(3), aml_int(12), "CDW4"));
2912a3282c6SBen Widawsky /* CXL capabilities */
2922a3282c6SBen Widawsky aml_append(if_cxl, aml_create_dword_field(aml_arg(3), aml_int(16), "CDW5"));
2932a3282c6SBen Widawsky aml_append(if_cxl, aml_store(aml_name("CDW4"), aml_name("SUPC")));
2942a3282c6SBen Widawsky aml_append(if_cxl, aml_store(aml_name("CDW5"), aml_name("CTRC")));
2952a3282c6SBen Widawsky
2962a3282c6SBen Widawsky /* CXL 2.0 Port/Device Register access */
2972a3282c6SBen Widawsky aml_append(if_cxl,
2982a3282c6SBen Widawsky aml_or(aml_name("CDW5"), aml_int(0x1), aml_name("CDW5")));
2992a3282c6SBen Widawsky aml_append(if_uuid, if_cxl);
3002a3282c6SBen Widawsky
3012a3282c6SBen Widawsky aml_append(if_uuid, aml_return(aml_arg(3)));
3022a3282c6SBen Widawsky aml_append(method, if_uuid);
3032a3282c6SBen Widawsky
3042a3282c6SBen Widawsky /*
3052a3282c6SBen Widawsky * If no UUID matched, return Unrecognized UUID via Arg3 DWord 1
3062a3282c6SBen Widawsky * ACPI 6.4 - 6.2.11
3072a3282c6SBen Widawsky * Unrecognised UUID - BIT(2)
3082a3282c6SBen Widawsky */
3092a3282c6SBen Widawsky else_uuid = aml_else();
3102a3282c6SBen Widawsky
3112a3282c6SBen Widawsky aml_append(else_uuid,
3122a3282c6SBen Widawsky aml_or(aml_name("CDW1"), aml_int(0x4), aml_name("CDW1")));
3132a3282c6SBen Widawsky aml_append(else_uuid, aml_return(aml_arg(3)));
3142a3282c6SBen Widawsky aml_append(method, else_uuid);
3152a3282c6SBen Widawsky
3162a3282c6SBen Widawsky return method;
3172a3282c6SBen Widawsky }
3182a3282c6SBen Widawsky
build_cxl_osc_method(Aml * dev)3192a3282c6SBen Widawsky void build_cxl_osc_method(Aml *dev)
3202a3282c6SBen Widawsky {
3212a3282c6SBen Widawsky aml_append(dev, aml_name_decl("SUPP", aml_int(0)));
3222a3282c6SBen Widawsky aml_append(dev, aml_name_decl("CTRL", aml_int(0)));
3232a3282c6SBen Widawsky aml_append(dev, aml_name_decl("SUPC", aml_int(0)));
3242a3282c6SBen Widawsky aml_append(dev, aml_name_decl("CTRC", aml_int(0)));
3252a3282c6SBen Widawsky aml_append(dev, __build_cxl_osc_method());
3262a3282c6SBen Widawsky }
327