Ben Widawsky | 2a3282c | 2022-04-29 15:40:49 +0100 | [diff] [blame] | 1 | /* |
| 2 | * CXL ACPI Implementation |
| 3 | * |
| 4 | * Copyright(C) 2020 Intel Corporation. |
| 5 | * |
| 6 | * This library is free software; you can redistribute it and/or |
| 7 | * modify it under the terms of the GNU Lesser General Public |
| 8 | * License as published by the Free Software Foundation; either |
| 9 | * version 2 of the License, or (at your option) any later version. |
| 10 | * |
| 11 | * This library is distributed in the hope that it will be useful, |
| 12 | * but WITHOUT ANY WARRANTY; without even the implied warranty of |
| 13 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU |
| 14 | * Lesser General Public License for more details. |
| 15 | * |
| 16 | * You should have received a copy of the GNU Lesser General Public |
| 17 | * License along with this library; if not, see <http://www.gnu.org/licenses/> |
| 18 | */ |
| 19 | |
| 20 | #include "qemu/osdep.h" |
Ben Widawsky | 3d6a69b | 2022-04-29 15:40:50 +0100 | [diff] [blame] | 21 | #include "hw/sysbus.h" |
| 22 | #include "hw/pci/pci_bridge.h" |
| 23 | #include "hw/pci/pci_host.h" |
Ben Widawsky | 2a3282c | 2022-04-29 15:40:49 +0100 | [diff] [blame] | 24 | #include "hw/cxl/cxl.h" |
Ben Widawsky | 3d6a69b | 2022-04-29 15:40:50 +0100 | [diff] [blame] | 25 | #include "hw/mem/memory-device.h" |
Ben Widawsky | 2a3282c | 2022-04-29 15:40:49 +0100 | [diff] [blame] | 26 | #include "hw/acpi/acpi.h" |
| 27 | #include "hw/acpi/aml-build.h" |
| 28 | #include "hw/acpi/bios-linker-loader.h" |
| 29 | #include "hw/acpi/cxl.h" |
| 30 | #include "qapi/error.h" |
| 31 | #include "qemu/uuid.h" |
| 32 | |
Ben Widawsky | 3d6a69b | 2022-04-29 15:40:50 +0100 | [diff] [blame] | 33 | static void cedt_build_chbs(GArray *table_data, PXBDev *cxl) |
| 34 | { |
| 35 | SysBusDevice *sbd = SYS_BUS_DEVICE(cxl->cxl.cxl_host_bridge); |
| 36 | struct MemoryRegion *mr = sbd->mmio[0].memory; |
| 37 | |
| 38 | /* Type */ |
| 39 | build_append_int_noprefix(table_data, 0, 1); |
| 40 | |
| 41 | /* Reserved */ |
| 42 | build_append_int_noprefix(table_data, 0, 1); |
| 43 | |
| 44 | /* Record Length */ |
| 45 | build_append_int_noprefix(table_data, 32, 2); |
| 46 | |
| 47 | /* UID - currently equal to bus number */ |
| 48 | build_append_int_noprefix(table_data, cxl->bus_nr, 4); |
| 49 | |
| 50 | /* Version */ |
| 51 | build_append_int_noprefix(table_data, 1, 4); |
| 52 | |
| 53 | /* Reserved */ |
| 54 | build_append_int_noprefix(table_data, 0, 4); |
| 55 | |
| 56 | /* Base - subregion within a container that is in PA space */ |
| 57 | build_append_int_noprefix(table_data, mr->container->addr + mr->addr, 8); |
| 58 | |
| 59 | /* Length */ |
| 60 | build_append_int_noprefix(table_data, memory_region_size(mr), 8); |
| 61 | } |
| 62 | |
Ben Widawsky | 21df6ab | 2022-04-29 15:40:53 +0100 | [diff] [blame] | 63 | /* |
| 64 | * CFMWS entries in CXL 2.0 ECN: CEDT CFMWS & QTG _DSM. |
| 65 | * Interleave ways encoding in CXL 2.0 ECN: 3, 6, 12 and 16-way memory |
| 66 | * interleaving. |
| 67 | */ |
Jonathan Cameron | 5135980 | 2022-06-08 15:54:34 +0100 | [diff] [blame] | 68 | static void cedt_build_cfmws(GArray *table_data, CXLState *cxls) |
Ben Widawsky | 21df6ab | 2022-04-29 15:40:53 +0100 | [diff] [blame] | 69 | { |
Ben Widawsky | 21df6ab | 2022-04-29 15:40:53 +0100 | [diff] [blame] | 70 | GList *it; |
| 71 | |
| 72 | for (it = cxls->fixed_windows; it; it = it->next) { |
| 73 | CXLFixedWindow *fw = it->data; |
| 74 | int i; |
| 75 | |
| 76 | /* Type */ |
| 77 | build_append_int_noprefix(table_data, 1, 1); |
| 78 | |
| 79 | /* Reserved */ |
| 80 | build_append_int_noprefix(table_data, 0, 1); |
| 81 | |
| 82 | /* Record Length */ |
| 83 | build_append_int_noprefix(table_data, 36 + 4 * fw->num_targets, 2); |
| 84 | |
| 85 | /* Reserved */ |
| 86 | build_append_int_noprefix(table_data, 0, 4); |
| 87 | |
| 88 | /* Base HPA */ |
| 89 | build_append_int_noprefix(table_data, fw->mr.addr, 8); |
| 90 | |
| 91 | /* Window Size */ |
| 92 | build_append_int_noprefix(table_data, fw->size, 8); |
| 93 | |
| 94 | /* Host Bridge Interleave Ways */ |
| 95 | build_append_int_noprefix(table_data, fw->enc_int_ways, 1); |
| 96 | |
| 97 | /* Host Bridge Interleave Arithmetic */ |
| 98 | build_append_int_noprefix(table_data, 0, 1); |
| 99 | |
| 100 | /* Reserved */ |
| 101 | build_append_int_noprefix(table_data, 0, 2); |
| 102 | |
| 103 | /* Host Bridge Interleave Granularity */ |
| 104 | build_append_int_noprefix(table_data, fw->enc_int_gran, 4); |
| 105 | |
| 106 | /* Window Restrictions */ |
| 107 | build_append_int_noprefix(table_data, 0x0f, 2); /* No restrictions */ |
| 108 | |
| 109 | /* QTG ID */ |
| 110 | build_append_int_noprefix(table_data, 0, 2); |
| 111 | |
| 112 | /* Host Bridge List (list of UIDs - currently bus_nr) */ |
| 113 | for (i = 0; i < fw->num_targets; i++) { |
| 114 | g_assert(fw->target_hbs[i]); |
| 115 | build_append_int_noprefix(table_data, fw->target_hbs[i]->bus_nr, 4); |
| 116 | } |
| 117 | } |
| 118 | } |
| 119 | |
Ben Widawsky | 3d6a69b | 2022-04-29 15:40:50 +0100 | [diff] [blame] | 120 | static int cxl_foreach_pxb_hb(Object *obj, void *opaque) |
| 121 | { |
| 122 | Aml *cedt = opaque; |
| 123 | |
| 124 | if (object_dynamic_cast(obj, TYPE_PXB_CXL_DEVICE)) { |
| 125 | cedt_build_chbs(cedt->buf, PXB_CXL_DEV(obj)); |
| 126 | } |
| 127 | |
| 128 | return 0; |
| 129 | } |
| 130 | |
Jonathan Cameron | 5135980 | 2022-06-08 15:54:34 +0100 | [diff] [blame] | 131 | void cxl_build_cedt(GArray *table_offsets, GArray *table_data, |
Ben Widawsky | 3d6a69b | 2022-04-29 15:40:50 +0100 | [diff] [blame] | 132 | BIOSLinker *linker, const char *oem_id, |
Jonathan Cameron | 5135980 | 2022-06-08 15:54:34 +0100 | [diff] [blame] | 133 | const char *oem_table_id, CXLState *cxl_state) |
Ben Widawsky | 3d6a69b | 2022-04-29 15:40:50 +0100 | [diff] [blame] | 134 | { |
| 135 | Aml *cedt; |
| 136 | AcpiTable table = { .sig = "CEDT", .rev = 1, .oem_id = oem_id, |
| 137 | .oem_table_id = oem_table_id }; |
| 138 | |
| 139 | acpi_add_table(table_offsets, table_data); |
| 140 | acpi_table_begin(&table, table_data); |
| 141 | cedt = init_aml_allocator(); |
| 142 | |
| 143 | /* reserve space for CEDT header */ |
| 144 | |
| 145 | object_child_foreach_recursive(object_get_root(), cxl_foreach_pxb_hb, cedt); |
Jonathan Cameron | 5135980 | 2022-06-08 15:54:34 +0100 | [diff] [blame] | 146 | cedt_build_cfmws(cedt->buf, cxl_state); |
Ben Widawsky | 3d6a69b | 2022-04-29 15:40:50 +0100 | [diff] [blame] | 147 | |
| 148 | /* copy AML table into ACPI tables blob and patch header there */ |
| 149 | g_array_append_vals(table_data, cedt->buf->data, cedt->buf->len); |
| 150 | free_aml_allocator(); |
| 151 | |
| 152 | acpi_table_end(linker, &table); |
| 153 | } |
| 154 | |
Ben Widawsky | 2a3282c | 2022-04-29 15:40:49 +0100 | [diff] [blame] | 155 | static Aml *__build_cxl_osc_method(void) |
| 156 | { |
| 157 | Aml *method, *if_uuid, *else_uuid, *if_arg1_not_1, *if_cxl, *if_caps_masked; |
| 158 | Aml *a_ctrl = aml_local(0); |
| 159 | Aml *a_cdw1 = aml_name("CDW1"); |
| 160 | |
| 161 | method = aml_method("_OSC", 4, AML_NOTSERIALIZED); |
| 162 | /* CDW1 is used for the return value so is present whether or not a match occurs */ |
| 163 | aml_append(method, aml_create_dword_field(aml_arg(3), aml_int(0), "CDW1")); |
| 164 | |
| 165 | /* |
| 166 | * Generate shared section between: |
| 167 | * CXL 2.0 - 9.14.2.1.4 and |
| 168 | * PCI Firmware Specification 3.0 |
| 169 | * 4.5.1. _OSC Interface for PCI Host Bridge Devices |
| 170 | * The _OSC interface for a PCI/PCI-X/PCI Express hierarchy is |
| 171 | * identified by the Universal Unique IDentifier (UUID) |
| 172 | * 33DB4D5B-1FF7-401C-9657-7441C03DD766 |
| 173 | * The _OSC interface for a CXL Host bridge is |
| 174 | * identified by the UUID 68F2D50B-C469-4D8A-BD3D-941A103FD3FC |
| 175 | * A CXL Host bridge is compatible with a PCI host bridge so |
| 176 | * for the shared section match both. |
| 177 | */ |
| 178 | if_uuid = aml_if( |
| 179 | aml_lor(aml_equal(aml_arg(0), |
| 180 | aml_touuid("33DB4D5B-1FF7-401C-9657-7441C03DD766")), |
| 181 | aml_equal(aml_arg(0), |
| 182 | aml_touuid("68F2D50B-C469-4D8A-BD3D-941A103FD3FC")))); |
| 183 | aml_append(if_uuid, aml_create_dword_field(aml_arg(3), aml_int(4), "CDW2")); |
| 184 | aml_append(if_uuid, aml_create_dword_field(aml_arg(3), aml_int(8), "CDW3")); |
| 185 | |
| 186 | aml_append(if_uuid, aml_store(aml_name("CDW3"), a_ctrl)); |
| 187 | |
| 188 | /* |
| 189 | * |
| 190 | * Allows OS control for all 5 features: |
| 191 | * PCIeHotplug SHPCHotplug PME AER PCIeCapability |
| 192 | */ |
| 193 | aml_append(if_uuid, aml_and(a_ctrl, aml_int(0x1F), a_ctrl)); |
| 194 | |
| 195 | /* |
| 196 | * Check _OSC revision. |
| 197 | * PCI Firmware specification 3.3 and CXL 2.0 both use revision 1 |
| 198 | * Unknown Revision is CDW1 - BIT (3) |
| 199 | */ |
| 200 | if_arg1_not_1 = aml_if(aml_lnot(aml_equal(aml_arg(1), aml_int(0x1)))); |
| 201 | aml_append(if_arg1_not_1, aml_or(a_cdw1, aml_int(0x08), a_cdw1)); |
| 202 | aml_append(if_uuid, if_arg1_not_1); |
| 203 | |
| 204 | if_caps_masked = aml_if(aml_lnot(aml_equal(aml_name("CDW3"), a_ctrl))); |
| 205 | |
| 206 | /* Capability bits were masked */ |
| 207 | aml_append(if_caps_masked, aml_or(a_cdw1, aml_int(0x10), a_cdw1)); |
| 208 | aml_append(if_uuid, if_caps_masked); |
| 209 | |
| 210 | aml_append(if_uuid, aml_store(aml_name("CDW2"), aml_name("SUPP"))); |
| 211 | aml_append(if_uuid, aml_store(aml_name("CDW3"), aml_name("CTRL"))); |
| 212 | |
| 213 | /* Update DWORD3 (the return value) */ |
| 214 | aml_append(if_uuid, aml_store(a_ctrl, aml_name("CDW3"))); |
| 215 | |
| 216 | /* CXL only section as per CXL 2.0 - 9.14.2.1.4 */ |
| 217 | if_cxl = aml_if(aml_equal( |
| 218 | aml_arg(0), aml_touuid("68F2D50B-C469-4D8A-BD3D-941A103FD3FC"))); |
| 219 | /* CXL support field */ |
| 220 | aml_append(if_cxl, aml_create_dword_field(aml_arg(3), aml_int(12), "CDW4")); |
| 221 | /* CXL capabilities */ |
| 222 | aml_append(if_cxl, aml_create_dword_field(aml_arg(3), aml_int(16), "CDW5")); |
| 223 | aml_append(if_cxl, aml_store(aml_name("CDW4"), aml_name("SUPC"))); |
| 224 | aml_append(if_cxl, aml_store(aml_name("CDW5"), aml_name("CTRC"))); |
| 225 | |
| 226 | /* CXL 2.0 Port/Device Register access */ |
| 227 | aml_append(if_cxl, |
| 228 | aml_or(aml_name("CDW5"), aml_int(0x1), aml_name("CDW5"))); |
| 229 | aml_append(if_uuid, if_cxl); |
| 230 | |
| 231 | aml_append(if_uuid, aml_return(aml_arg(3))); |
| 232 | aml_append(method, if_uuid); |
| 233 | |
| 234 | /* |
| 235 | * If no UUID matched, return Unrecognized UUID via Arg3 DWord 1 |
| 236 | * ACPI 6.4 - 6.2.11 |
| 237 | * Unrecognised UUID - BIT(2) |
| 238 | */ |
| 239 | else_uuid = aml_else(); |
| 240 | |
| 241 | aml_append(else_uuid, |
| 242 | aml_or(aml_name("CDW1"), aml_int(0x4), aml_name("CDW1"))); |
| 243 | aml_append(else_uuid, aml_return(aml_arg(3))); |
| 244 | aml_append(method, else_uuid); |
| 245 | |
| 246 | return method; |
| 247 | } |
| 248 | |
| 249 | void build_cxl_osc_method(Aml *dev) |
| 250 | { |
| 251 | aml_append(dev, aml_name_decl("SUPP", aml_int(0))); |
| 252 | aml_append(dev, aml_name_decl("CTRL", aml_int(0))); |
| 253 | aml_append(dev, aml_name_decl("SUPC", aml_int(0))); |
| 254 | aml_append(dev, aml_name_decl("CTRC", aml_int(0))); |
| 255 | aml_append(dev, __build_cxl_osc_method()); |
| 256 | } |