Marcel Apfelbaum | 40d14be | 2015-06-02 14:23:06 +0300 | [diff] [blame] | 1 | /* |
| 2 | * PCI Expander Bridge Device Emulation |
| 3 | * |
| 4 | * Copyright (C) 2015 Red Hat Inc |
| 5 | * |
| 6 | * Authors: |
| 7 | * Marcel Apfelbaum <marcel@redhat.com> |
| 8 | * |
| 9 | * This work is licensed under the terms of the GNU GPL, version 2 or later. |
| 10 | * See the COPYING file in the top-level directory. |
| 11 | */ |
| 12 | |
Peter Maydell | 97d5408 | 2016-01-26 18:17:15 +0000 | [diff] [blame] | 13 | #include "qemu/osdep.h" |
Wei Jiangang | 86395eb | 2016-05-17 18:18:46 +0800 | [diff] [blame] | 14 | #include "qapi/error.h" |
Marcel Apfelbaum | 40d14be | 2015-06-02 14:23:06 +0300 | [diff] [blame] | 15 | #include "hw/pci/pci.h" |
| 16 | #include "hw/pci/pci_bus.h" |
| 17 | #include "hw/pci/pci_host.h" |
Jonathan Cameron | 154070e | 2023-02-27 15:31:28 +0000 | [diff] [blame] | 18 | #include "hw/pci/pcie_port.h" |
Markus Armbruster | a27bd6c | 2019-08-12 07:23:51 +0200 | [diff] [blame] | 19 | #include "hw/qdev-properties.h" |
Laszlo Ersek | 3cf0ecb | 2015-06-19 04:40:10 +0200 | [diff] [blame] | 20 | #include "hw/pci/pci_bridge.h" |
Jonathan Cameron | 7bd1900 | 2022-06-08 15:54:37 +0100 | [diff] [blame] | 21 | #include "hw/pci-bridge/pci_expander_bridge.h" |
Ben Widawsky | 4f8db87 | 2022-04-29 15:40:39 +0100 | [diff] [blame] | 22 | #include "hw/cxl/cxl.h" |
Marcel Apfelbaum | 40d14be | 2015-06-02 14:23:06 +0300 | [diff] [blame] | 23 | #include "qemu/range.h" |
| 24 | #include "qemu/error-report.h" |
Markus Armbruster | 0b8fa32 | 2019-05-23 16:35:07 +0200 | [diff] [blame] | 25 | #include "qemu/module.h" |
Marcel Apfelbaum | 0e79e51 | 2015-06-02 14:23:10 +0300 | [diff] [blame] | 26 | #include "sysemu/numa.h" |
Tao Xu | aa57020 | 2019-08-09 14:57:22 +0800 | [diff] [blame] | 27 | #include "hw/boards.h" |
Eduardo Habkost | db1015e | 2020-09-03 16:43:22 -0400 | [diff] [blame] | 28 | #include "qom/object.h" |
Marcel Apfelbaum | 40d14be | 2015-06-02 14:23:06 +0300 | [diff] [blame] | 29 | |
Ben Widawsky | 9dccb12 | 2022-04-29 15:40:37 +0100 | [diff] [blame] | 30 | enum BusType { PCI, PCIE, CXL }; |
Ben Widawsky | 25a2e52 | 2022-04-29 15:40:36 +0100 | [diff] [blame] | 31 | |
Marcel Apfelbaum | 40d14be | 2015-06-02 14:23:06 +0300 | [diff] [blame] | 32 | #define TYPE_PXB_BUS "pxb-bus" |
Eduardo Habkost | db1015e | 2020-09-03 16:43:22 -0400 | [diff] [blame] | 33 | typedef struct PXBBus PXBBus; |
Eduardo Habkost | 8110fa1 | 2020-08-31 17:07:33 -0400 | [diff] [blame] | 34 | DECLARE_INSTANCE_CHECKER(PXBBus, PXB_BUS, |
| 35 | TYPE_PXB_BUS) |
Marcel Apfelbaum | 40d14be | 2015-06-02 14:23:06 +0300 | [diff] [blame] | 36 | |
Marcel Apfelbaum | 02b0743 | 2015-11-26 18:00:27 +0200 | [diff] [blame] | 37 | #define TYPE_PXB_PCIE_BUS "pxb-pcie-bus" |
Eduardo Habkost | 8110fa1 | 2020-08-31 17:07:33 -0400 | [diff] [blame] | 38 | DECLARE_INSTANCE_CHECKER(PXBBus, PXB_PCIE_BUS, |
| 39 | TYPE_PXB_PCIE_BUS) |
Marcel Apfelbaum | 02b0743 | 2015-11-26 18:00:27 +0200 | [diff] [blame] | 40 | |
Ben Widawsky | 9dccb12 | 2022-04-29 15:40:37 +0100 | [diff] [blame] | 41 | #define TYPE_PXB_CXL_BUS "pxb-cxl-bus" |
| 42 | DECLARE_INSTANCE_CHECKER(PXBBus, PXB_CXL_BUS, |
| 43 | TYPE_PXB_CXL_BUS) |
| 44 | |
Eduardo Habkost | db1015e | 2020-09-03 16:43:22 -0400 | [diff] [blame] | 45 | struct PXBBus { |
Marcel Apfelbaum | 40d14be | 2015-06-02 14:23:06 +0300 | [diff] [blame] | 46 | /*< private >*/ |
| 47 | PCIBus parent_obj; |
| 48 | /*< public >*/ |
| 49 | |
| 50 | char bus_path[8]; |
Eduardo Habkost | db1015e | 2020-09-03 16:43:22 -0400 | [diff] [blame] | 51 | }; |
Marcel Apfelbaum | 40d14be | 2015-06-02 14:23:06 +0300 | [diff] [blame] | 52 | |
Jonathan Cameron | c28db9e | 2023-04-20 15:27:50 +0100 | [diff] [blame] | 53 | #define TYPE_PXB_PCIE_DEV "pxb-pcie" |
| 54 | OBJECT_DECLARE_SIMPLE_TYPE(PXBPCIEDev, PXB_PCIE_DEV) |
Marcel Apfelbaum | 02b0743 | 2015-11-26 18:00:27 +0200 | [diff] [blame] | 55 | |
Laszlo Ersek | 48ea3de | 2015-06-19 04:40:17 +0200 | [diff] [blame] | 56 | static GList *pxb_dev_list; |
| 57 | |
Marcel Apfelbaum | 40d14be | 2015-06-02 14:23:06 +0300 | [diff] [blame] | 58 | #define TYPE_PXB_HOST "pxb-host" |
| 59 | |
Jonathan Cameron | 0b4aec2 | 2022-04-29 15:40:56 +0100 | [diff] [blame] | 60 | CXLComponentState *cxl_get_hb_cstate(PCIHostState *hb) |
| 61 | { |
| 62 | CXLHost *host = PXB_CXL_HOST(hb); |
| 63 | |
| 64 | return &host->cxl_cstate; |
| 65 | } |
| 66 | |
Jonathan Cameron | 154070e | 2023-02-27 15:31:28 +0000 | [diff] [blame] | 67 | bool cxl_get_hb_passthrough(PCIHostState *hb) |
| 68 | { |
| 69 | CXLHost *host = PXB_CXL_HOST(hb); |
| 70 | |
| 71 | return host->passthrough; |
| 72 | } |
| 73 | |
Marcel Apfelbaum | 40d14be | 2015-06-02 14:23:06 +0300 | [diff] [blame] | 74 | static int pxb_bus_num(PCIBus *bus) |
| 75 | { |
Jonathan Cameron | c28db9e | 2023-04-20 15:27:50 +0100 | [diff] [blame] | 76 | PXBDev *pxb = PXB_DEV(bus->parent_dev); |
Marcel Apfelbaum | 40d14be | 2015-06-02 14:23:06 +0300 | [diff] [blame] | 77 | |
| 78 | return pxb->bus_nr; |
| 79 | } |
| 80 | |
Marcel Apfelbaum | 0e79e51 | 2015-06-02 14:23:10 +0300 | [diff] [blame] | 81 | static uint16_t pxb_bus_numa_node(PCIBus *bus) |
| 82 | { |
Jonathan Cameron | c28db9e | 2023-04-20 15:27:50 +0100 | [diff] [blame] | 83 | PXBDev *pxb = PXB_DEV(bus->parent_dev); |
Marcel Apfelbaum | 0e79e51 | 2015-06-02 14:23:10 +0300 | [diff] [blame] | 84 | |
| 85 | return pxb->numa_node; |
| 86 | } |
| 87 | |
Marcel Apfelbaum | 40d14be | 2015-06-02 14:23:06 +0300 | [diff] [blame] | 88 | static void pxb_bus_class_init(ObjectClass *class, void *data) |
| 89 | { |
| 90 | PCIBusClass *pbc = PCI_BUS_CLASS(class); |
| 91 | |
| 92 | pbc->bus_num = pxb_bus_num; |
Marcel Apfelbaum | 0e79e51 | 2015-06-02 14:23:10 +0300 | [diff] [blame] | 93 | pbc->numa_node = pxb_bus_numa_node; |
Marcel Apfelbaum | 40d14be | 2015-06-02 14:23:06 +0300 | [diff] [blame] | 94 | } |
| 95 | |
| 96 | static const TypeInfo pxb_bus_info = { |
| 97 | .name = TYPE_PXB_BUS, |
| 98 | .parent = TYPE_PCI_BUS, |
| 99 | .instance_size = sizeof(PXBBus), |
| 100 | .class_init = pxb_bus_class_init, |
| 101 | }; |
| 102 | |
Marcel Apfelbaum | 02b0743 | 2015-11-26 18:00:27 +0200 | [diff] [blame] | 103 | static const TypeInfo pxb_pcie_bus_info = { |
| 104 | .name = TYPE_PXB_PCIE_BUS, |
| 105 | .parent = TYPE_PCIE_BUS, |
| 106 | .instance_size = sizeof(PXBBus), |
| 107 | .class_init = pxb_bus_class_init, |
| 108 | }; |
| 109 | |
Ben Widawsky | 4f8db87 | 2022-04-29 15:40:39 +0100 | [diff] [blame] | 110 | static const TypeInfo pxb_cxl_bus_info = { |
| 111 | .name = TYPE_PXB_CXL_BUS, |
| 112 | .parent = TYPE_CXL_BUS, |
| 113 | .instance_size = sizeof(PXBBus), |
| 114 | .class_init = pxb_bus_class_init, |
| 115 | }; |
| 116 | |
Marcel Apfelbaum | 40d14be | 2015-06-02 14:23:06 +0300 | [diff] [blame] | 117 | static const char *pxb_host_root_bus_path(PCIHostState *host_bridge, |
| 118 | PCIBus *rootbus) |
| 119 | { |
Ben Widawsky | 4f8db87 | 2022-04-29 15:40:39 +0100 | [diff] [blame] | 120 | PXBBus *bus = pci_bus_is_cxl(rootbus) ? |
| 121 | PXB_CXL_BUS(rootbus) : |
| 122 | pci_bus_is_express(rootbus) ? PXB_PCIE_BUS(rootbus) : |
| 123 | PXB_BUS(rootbus); |
Marcel Apfelbaum | 40d14be | 2015-06-02 14:23:06 +0300 | [diff] [blame] | 124 | |
| 125 | snprintf(bus->bus_path, 8, "0000:%02x", pxb_bus_num(rootbus)); |
| 126 | return bus->bus_path; |
| 127 | } |
| 128 | |
Laszlo Ersek | 48ea3de | 2015-06-19 04:40:17 +0200 | [diff] [blame] | 129 | static char *pxb_host_ofw_unit_address(const SysBusDevice *dev) |
| 130 | { |
| 131 | const PCIHostState *pxb_host; |
| 132 | const PCIBus *pxb_bus; |
| 133 | const PXBDev *pxb_dev; |
| 134 | int position; |
| 135 | const DeviceState *pxb_dev_base; |
| 136 | const PCIHostState *main_host; |
| 137 | const SysBusDevice *main_host_sbd; |
| 138 | |
| 139 | pxb_host = PCI_HOST_BRIDGE(dev); |
| 140 | pxb_bus = pxb_host->bus; |
Jonathan Cameron | c28db9e | 2023-04-20 15:27:50 +0100 | [diff] [blame] | 141 | pxb_dev = PXB_DEV(pxb_bus->parent_dev); |
Laszlo Ersek | 48ea3de | 2015-06-19 04:40:17 +0200 | [diff] [blame] | 142 | position = g_list_index(pxb_dev_list, pxb_dev); |
| 143 | assert(position >= 0); |
| 144 | |
| 145 | pxb_dev_base = DEVICE(pxb_dev); |
| 146 | main_host = PCI_HOST_BRIDGE(pxb_dev_base->parent_bus->parent); |
| 147 | main_host_sbd = SYS_BUS_DEVICE(main_host); |
| 148 | |
| 149 | if (main_host_sbd->num_mmio > 0) { |
Philippe Mathieu-Daudé | 883f2c5 | 2023-01-10 22:29:47 +0100 | [diff] [blame] | 150 | return g_strdup_printf(HWADDR_FMT_plx ",%x", |
Laszlo Ersek | 48ea3de | 2015-06-19 04:40:17 +0200 | [diff] [blame] | 151 | main_host_sbd->mmio[0].addr, position + 1); |
| 152 | } |
| 153 | if (main_host_sbd->num_pio > 0) { |
| 154 | return g_strdup_printf("i%04x,%x", |
| 155 | main_host_sbd->pio[0], position + 1); |
| 156 | } |
| 157 | return NULL; |
| 158 | } |
| 159 | |
Marcel Apfelbaum | 40d14be | 2015-06-02 14:23:06 +0300 | [diff] [blame] | 160 | static void pxb_host_class_init(ObjectClass *class, void *data) |
| 161 | { |
| 162 | DeviceClass *dc = DEVICE_CLASS(class); |
Laszlo Ersek | 48ea3de | 2015-06-19 04:40:17 +0200 | [diff] [blame] | 163 | SysBusDeviceClass *sbc = SYS_BUS_DEVICE_CLASS(class); |
Marcel Apfelbaum | 40d14be | 2015-06-02 14:23:06 +0300 | [diff] [blame] | 164 | PCIHostBridgeClass *hc = PCI_HOST_BRIDGE_CLASS(class); |
| 165 | |
| 166 | dc->fw_name = "pci"; |
Marcel Apfelbaum | bf8d492 | 2016-06-27 18:38:33 +0300 | [diff] [blame] | 167 | /* Reason: Internal part of the pxb/pxb-pcie device, not usable by itself */ |
Eduardo Habkost | e90f2a8 | 2017-05-03 17:35:44 -0300 | [diff] [blame] | 168 | dc->user_creatable = false; |
Laszlo Ersek | 48ea3de | 2015-06-19 04:40:17 +0200 | [diff] [blame] | 169 | sbc->explicit_ofw_unit_address = pxb_host_ofw_unit_address; |
Marcel Apfelbaum | 40d14be | 2015-06-02 14:23:06 +0300 | [diff] [blame] | 170 | hc->root_bus_path = pxb_host_root_bus_path; |
| 171 | } |
| 172 | |
| 173 | static const TypeInfo pxb_host_info = { |
| 174 | .name = TYPE_PXB_HOST, |
| 175 | .parent = TYPE_PCI_HOST_BRIDGE, |
| 176 | .class_init = pxb_host_class_init, |
| 177 | }; |
| 178 | |
Ben Widawsky | 6e4e3ae | 2022-04-29 15:40:48 +0100 | [diff] [blame] | 179 | static void pxb_cxl_realize(DeviceState *dev, Error **errp) |
| 180 | { |
Ben Widawsky | 6e4e3ae | 2022-04-29 15:40:48 +0100 | [diff] [blame] | 181 | SysBusDevice *sbd = SYS_BUS_DEVICE(dev); |
| 182 | CXLHost *cxl = PXB_CXL_HOST(dev); |
| 183 | CXLComponentState *cxl_cstate = &cxl->cxl_cstate; |
| 184 | struct MemoryRegion *mr = &cxl_cstate->crb.component_registers; |
Ben Widawsky | 6e4e3ae | 2022-04-29 15:40:48 +0100 | [diff] [blame] | 185 | |
| 186 | cxl_component_register_block_init(OBJECT(dev), cxl_cstate, |
| 187 | TYPE_PXB_CXL_HOST); |
| 188 | sysbus_init_mmio(sbd, mr); |
Jonathan Cameron | 7bd1900 | 2022-06-08 15:54:37 +0100 | [diff] [blame] | 189 | } |
Ben Widawsky | 6e4e3ae | 2022-04-29 15:40:48 +0100 | [diff] [blame] | 190 | |
Jonathan Cameron | 7bd1900 | 2022-06-08 15:54:37 +0100 | [diff] [blame] | 191 | /* |
| 192 | * Host bridge realization has no means of knowning state associated |
| 193 | * with a particular machine. As such, it is nececssary to delay |
| 194 | * final setup of the host bridge register space until later in the |
| 195 | * machine bring up. |
| 196 | */ |
| 197 | void pxb_cxl_hook_up_registers(CXLState *cxl_state, PCIBus *bus, Error **errp) |
| 198 | { |
Jonathan Cameron | c28db9e | 2023-04-20 15:27:50 +0100 | [diff] [blame] | 199 | PXBCXLDev *pxb = PXB_CXL_DEV(pci_bridge_get_device(bus)); |
| 200 | CXLHost *cxl = pxb->cxl_host_bridge; |
Jonathan Cameron | 7bd1900 | 2022-06-08 15:54:37 +0100 | [diff] [blame] | 201 | CXLComponentState *cxl_cstate = &cxl->cxl_cstate; |
| 202 | struct MemoryRegion *mr = &cxl_cstate->crb.component_registers; |
| 203 | hwaddr offset; |
| 204 | |
| 205 | offset = memory_region_size(mr) * cxl_state->next_mr_idx; |
| 206 | if (offset > memory_region_size(&cxl_state->host_mr)) { |
Ben Widawsky | 6e4e3ae | 2022-04-29 15:40:48 +0100 | [diff] [blame] | 207 | error_setg(errp, "Insufficient space for pxb cxl host register space"); |
| 208 | return; |
| 209 | } |
| 210 | |
Jonathan Cameron | 7bd1900 | 2022-06-08 15:54:37 +0100 | [diff] [blame] | 211 | memory_region_add_subregion(&cxl_state->host_mr, offset, mr); |
| 212 | cxl_state->next_mr_idx++; |
Ben Widawsky | 6e4e3ae | 2022-04-29 15:40:48 +0100 | [diff] [blame] | 213 | } |
| 214 | |
| 215 | static void pxb_cxl_host_class_init(ObjectClass *class, void *data) |
| 216 | { |
| 217 | DeviceClass *dc = DEVICE_CLASS(class); |
| 218 | PCIHostBridgeClass *hc = PCI_HOST_BRIDGE_CLASS(class); |
| 219 | |
| 220 | hc->root_bus_path = pxb_host_root_bus_path; |
| 221 | dc->fw_name = "cxl"; |
| 222 | dc->realize = pxb_cxl_realize; |
| 223 | /* Reason: Internal part of the pxb/pxb-pcie device, not usable by itself */ |
| 224 | dc->user_creatable = false; |
| 225 | } |
| 226 | |
| 227 | /* |
| 228 | * This is a device to handle the MMIO for a CXL host bridge. It does nothing |
| 229 | * else. |
| 230 | */ |
| 231 | static const TypeInfo cxl_host_info = { |
| 232 | .name = TYPE_PXB_CXL_HOST, |
| 233 | .parent = TYPE_PCI_HOST_BRIDGE, |
| 234 | .instance_size = sizeof(CXLHost), |
| 235 | .class_init = pxb_cxl_host_class_init, |
| 236 | }; |
| 237 | |
Marcel Apfelbaum | 40d14be | 2015-06-02 14:23:06 +0300 | [diff] [blame] | 238 | /* |
Wei Jiangang | 86395eb | 2016-05-17 18:18:46 +0800 | [diff] [blame] | 239 | * Registers the PXB bus as a child of pci host root bus. |
Marcel Apfelbaum | 40d14be | 2015-06-02 14:23:06 +0300 | [diff] [blame] | 240 | */ |
Wei Jiangang | 86395eb | 2016-05-17 18:18:46 +0800 | [diff] [blame] | 241 | static void pxb_register_bus(PCIDevice *dev, PCIBus *pxb_bus, Error **errp) |
Marcel Apfelbaum | 40d14be | 2015-06-02 14:23:06 +0300 | [diff] [blame] | 242 | { |
David Gibson | fd56e06 | 2017-11-29 19:46:27 +1100 | [diff] [blame] | 243 | PCIBus *bus = pci_get_bus(dev); |
Marcel Apfelbaum | 40d14be | 2015-06-02 14:23:06 +0300 | [diff] [blame] | 244 | int pxb_bus_num = pci_bus_num(pxb_bus); |
| 245 | |
| 246 | if (bus->parent_dev) { |
Wei Jiangang | 86395eb | 2016-05-17 18:18:46 +0800 | [diff] [blame] | 247 | error_setg(errp, "PXB devices can be attached only to root bus"); |
| 248 | return; |
Marcel Apfelbaum | 40d14be | 2015-06-02 14:23:06 +0300 | [diff] [blame] | 249 | } |
| 250 | |
| 251 | QLIST_FOREACH(bus, &bus->child, sibling) { |
| 252 | if (pci_bus_num(bus) == pxb_bus_num) { |
Wei Jiangang | 86395eb | 2016-05-17 18:18:46 +0800 | [diff] [blame] | 253 | error_setg(errp, "Bus %d is already in use", pxb_bus_num); |
| 254 | return; |
Marcel Apfelbaum | 40d14be | 2015-06-02 14:23:06 +0300 | [diff] [blame] | 255 | } |
| 256 | } |
David Gibson | fd56e06 | 2017-11-29 19:46:27 +1100 | [diff] [blame] | 257 | QLIST_INSERT_HEAD(&pci_get_bus(dev)->child, pxb_bus, sibling); |
Marcel Apfelbaum | 40d14be | 2015-06-02 14:23:06 +0300 | [diff] [blame] | 258 | } |
| 259 | |
Marcel Apfelbaum | 0639b00 | 2015-06-02 14:23:08 +0300 | [diff] [blame] | 260 | static int pxb_map_irq_fn(PCIDevice *pci_dev, int pin) |
| 261 | { |
David Gibson | fd56e06 | 2017-11-29 19:46:27 +1100 | [diff] [blame] | 262 | PCIDevice *pxb = pci_get_bus(pci_dev)->parent_dev; |
Marcel Apfelbaum | 0639b00 | 2015-06-02 14:23:08 +0300 | [diff] [blame] | 263 | |
| 264 | /* |
Jonathan Cameron | e609301 | 2022-01-18 17:48:55 +0000 | [diff] [blame] | 265 | * First carry out normal swizzle to handle |
| 266 | * multple root ports on a pxb instance. |
| 267 | */ |
| 268 | pin = pci_swizzle_map_irq_fn(pci_dev, pin); |
| 269 | |
| 270 | /* |
Marcel Apfelbaum | 0639b00 | 2015-06-02 14:23:08 +0300 | [diff] [blame] | 271 | * The bios does not index the pxb slot number when |
| 272 | * it computes the IRQ because it resides on bus 0 |
| 273 | * and not on the current bus. |
| 274 | * However QEMU routes the irq through bus 0 and adds |
| 275 | * the pxb slot to the IRQ computation of the PXB |
| 276 | * device. |
| 277 | * |
| 278 | * Synchronize between bios and QEMU by canceling |
| 279 | * pxb's effect. |
| 280 | */ |
| 281 | return pin - PCI_SLOT(pxb->devfn); |
| 282 | } |
| 283 | |
Jonathan Cameron | 154070e | 2023-02-27 15:31:28 +0000 | [diff] [blame] | 284 | static void pxb_cxl_dev_reset(DeviceState *dev) |
Ben Widawsky | 4f8db87 | 2022-04-29 15:40:39 +0100 | [diff] [blame] | 285 | { |
Jonathan Cameron | c28db9e | 2023-04-20 15:27:50 +0100 | [diff] [blame] | 286 | CXLHost *cxl = PXB_CXL_DEV(dev)->cxl_host_bridge; |
Ben Widawsky | 6e4e3ae | 2022-04-29 15:40:48 +0100 | [diff] [blame] | 287 | CXLComponentState *cxl_cstate = &cxl->cxl_cstate; |
Jonathan Cameron | 154070e | 2023-02-27 15:31:28 +0000 | [diff] [blame] | 288 | PCIHostState *hb = PCI_HOST_BRIDGE(cxl); |
Ben Widawsky | 6e4e3ae | 2022-04-29 15:40:48 +0100 | [diff] [blame] | 289 | uint32_t *reg_state = cxl_cstate->crb.cache_mem_registers; |
| 290 | uint32_t *write_msk = cxl_cstate->crb.cache_mem_regs_write_mask; |
Jonathan Cameron | 154070e | 2023-02-27 15:31:28 +0000 | [diff] [blame] | 291 | int dsp_count = 0; |
Ben Widawsky | 6e4e3ae | 2022-04-29 15:40:48 +0100 | [diff] [blame] | 292 | |
| 293 | cxl_component_register_init_common(reg_state, write_msk, CXL2_ROOT_PORT); |
Jonathan Cameron | 154070e | 2023-02-27 15:31:28 +0000 | [diff] [blame] | 294 | /* |
| 295 | * The CXL specification allows for host bridges with no HDM decoders |
| 296 | * if they only have a single root port. |
| 297 | */ |
Jonathan Cameron | 9136f66 | 2023-04-20 15:27:49 +0100 | [diff] [blame] | 298 | if (!PXB_CXL_DEV(dev)->hdm_for_passthrough) { |
Jonathan Cameron | 154070e | 2023-02-27 15:31:28 +0000 | [diff] [blame] | 299 | dsp_count = pcie_count_ds_ports(hb->bus); |
| 300 | } |
| 301 | /* Initial reset will have 0 dsp so wait until > 0 */ |
| 302 | if (dsp_count == 1) { |
| 303 | cxl->passthrough = true; |
| 304 | /* Set Capability ID in header to NONE */ |
| 305 | ARRAY_FIELD_DP32(reg_state, CXL_HDM_CAPABILITY_HEADER, ID, 0); |
| 306 | } else { |
| 307 | ARRAY_FIELD_DP32(reg_state, CXL_HDM_DECODER_CAPABILITY, TARGET_COUNT, |
| 308 | 8); |
| 309 | } |
Ben Widawsky | 4f8db87 | 2022-04-29 15:40:39 +0100 | [diff] [blame] | 310 | } |
| 311 | |
Laszlo Ersek | 48ea3de | 2015-06-19 04:40:17 +0200 | [diff] [blame] | 312 | static gint pxb_compare(gconstpointer a, gconstpointer b) |
| 313 | { |
| 314 | const PXBDev *pxb_a = a, *pxb_b = b; |
| 315 | |
| 316 | return pxb_a->bus_nr < pxb_b->bus_nr ? -1 : |
| 317 | pxb_a->bus_nr > pxb_b->bus_nr ? 1 : |
| 318 | 0; |
| 319 | } |
| 320 | |
Ben Widawsky | 25a2e52 | 2022-04-29 15:40:36 +0100 | [diff] [blame] | 321 | static void pxb_dev_realize_common(PCIDevice *dev, enum BusType type, |
| 322 | Error **errp) |
Marcel Apfelbaum | 40d14be | 2015-06-02 14:23:06 +0300 | [diff] [blame] | 323 | { |
Jonathan Cameron | c28db9e | 2023-04-20 15:27:50 +0100 | [diff] [blame] | 324 | PXBDev *pxb = PXB_DEV(dev); |
Marcel Apfelbaum | 02b0743 | 2015-11-26 18:00:27 +0200 | [diff] [blame] | 325 | DeviceState *ds, *bds = NULL; |
Marcel Apfelbaum | 40d14be | 2015-06-02 14:23:06 +0300 | [diff] [blame] | 326 | PCIBus *bus; |
| 327 | const char *dev_name = NULL; |
Wei Jiangang | 86395eb | 2016-05-17 18:18:46 +0800 | [diff] [blame] | 328 | Error *local_err = NULL; |
Tao Xu | aa57020 | 2019-08-09 14:57:22 +0800 | [diff] [blame] | 329 | MachineState *ms = MACHINE(qdev_get_machine()); |
| 330 | |
| 331 | if (ms->numa_state == NULL) { |
| 332 | error_setg(errp, "NUMA is not supported by this machine-type"); |
| 333 | return; |
| 334 | } |
Marcel Apfelbaum | 40d14be | 2015-06-02 14:23:06 +0300 | [diff] [blame] | 335 | |
Marcel Apfelbaum | 0e79e51 | 2015-06-02 14:23:10 +0300 | [diff] [blame] | 336 | if (pxb->numa_node != NUMA_NODE_UNASSIGNED && |
Tao Xu | aa57020 | 2019-08-09 14:57:22 +0800 | [diff] [blame] | 337 | pxb->numa_node >= ms->numa_state->num_nodes) { |
Wei Jiangang | 86395eb | 2016-05-17 18:18:46 +0800 | [diff] [blame] | 338 | error_setg(errp, "Illegal numa node %d", pxb->numa_node); |
| 339 | return; |
Marcel Apfelbaum | 0e79e51 | 2015-06-02 14:23:10 +0300 | [diff] [blame] | 340 | } |
| 341 | |
Marcel Apfelbaum | 40d14be | 2015-06-02 14:23:06 +0300 | [diff] [blame] | 342 | if (dev->qdev.id && *dev->qdev.id) { |
| 343 | dev_name = dev->qdev.id; |
| 344 | } |
| 345 | |
Ben Widawsky | 6e4e3ae | 2022-04-29 15:40:48 +0100 | [diff] [blame] | 346 | ds = qdev_new(type == CXL ? TYPE_PXB_CXL_HOST : TYPE_PXB_HOST); |
Ben Widawsky | 25a2e52 | 2022-04-29 15:40:36 +0100 | [diff] [blame] | 347 | if (type == PCIE) { |
David Gibson | 1115ff6 | 2017-11-29 19:46:22 +1100 | [diff] [blame] | 348 | bus = pci_root_bus_new(ds, dev_name, NULL, NULL, 0, TYPE_PXB_PCIE_BUS); |
Ben Widawsky | 9dccb12 | 2022-04-29 15:40:37 +0100 | [diff] [blame] | 349 | } else if (type == CXL) { |
| 350 | bus = pci_root_bus_new(ds, dev_name, NULL, NULL, 0, TYPE_PXB_CXL_BUS); |
| 351 | bus->flags |= PCI_BUS_CXL; |
Jonathan Cameron | c28db9e | 2023-04-20 15:27:50 +0100 | [diff] [blame] | 352 | PXB_CXL_DEV(dev)->cxl_host_bridge = PXB_CXL_HOST(ds); |
Marcel Apfelbaum | 02b0743 | 2015-11-26 18:00:27 +0200 | [diff] [blame] | 353 | } else { |
David Gibson | 1115ff6 | 2017-11-29 19:46:22 +1100 | [diff] [blame] | 354 | bus = pci_root_bus_new(ds, "pxb-internal", NULL, NULL, 0, TYPE_PXB_BUS); |
Markus Armbruster | df70796 | 2020-06-10 07:31:59 +0200 | [diff] [blame] | 355 | bds = qdev_new("pci-bridge"); |
Kevin Wolf | 163f384 | 2021-10-08 15:34:35 +0200 | [diff] [blame] | 356 | bds->id = g_strdup(dev_name); |
Marcel Apfelbaum | 02b0743 | 2015-11-26 18:00:27 +0200 | [diff] [blame] | 357 | qdev_prop_set_uint8(bds, PCI_BRIDGE_DEV_PROP_CHASSIS_NR, pxb->bus_nr); |
| 358 | qdev_prop_set_bit(bds, PCI_BRIDGE_DEV_PROP_SHPC, false); |
| 359 | } |
Marcel Apfelbaum | 40d14be | 2015-06-02 14:23:06 +0300 | [diff] [blame] | 360 | |
| 361 | bus->parent_dev = dev; |
David Gibson | fd56e06 | 2017-11-29 19:46:27 +1100 | [diff] [blame] | 362 | bus->address_space_mem = pci_get_bus(dev)->address_space_mem; |
| 363 | bus->address_space_io = pci_get_bus(dev)->address_space_io; |
Marcel Apfelbaum | 0639b00 | 2015-06-02 14:23:08 +0300 | [diff] [blame] | 364 | bus->map_irq = pxb_map_irq_fn; |
Marcel Apfelbaum | 40d14be | 2015-06-02 14:23:06 +0300 | [diff] [blame] | 365 | |
Marcel Apfelbaum | 40d14be | 2015-06-02 14:23:06 +0300 | [diff] [blame] | 366 | PCI_HOST_BRIDGE(ds)->bus = bus; |
Xingang Wang | 91528f4 | 2021-07-08 12:55:12 +0000 | [diff] [blame] | 367 | PCI_HOST_BRIDGE(ds)->bypass_iommu = pxb->bypass_iommu; |
Marcel Apfelbaum | 40d14be | 2015-06-02 14:23:06 +0300 | [diff] [blame] | 368 | |
Wei Jiangang | 86395eb | 2016-05-17 18:18:46 +0800 | [diff] [blame] | 369 | pxb_register_bus(dev, bus, &local_err); |
| 370 | if (local_err) { |
| 371 | error_propagate(errp, local_err); |
Wei Jiangang | 2e4278b | 2016-03-23 15:26:19 +0800 | [diff] [blame] | 372 | goto err_register_bus; |
Marcel Apfelbaum | 40d14be | 2015-06-02 14:23:06 +0300 | [diff] [blame] | 373 | } |
| 374 | |
Markus Armbruster | 3c6ef47 | 2020-06-10 07:32:34 +0200 | [diff] [blame] | 375 | sysbus_realize_and_unref(SYS_BUS_DEVICE(ds), &error_fatal); |
Marcel Apfelbaum | 02b0743 | 2015-11-26 18:00:27 +0200 | [diff] [blame] | 376 | if (bds) { |
Markus Armbruster | df70796 | 2020-06-10 07:31:59 +0200 | [diff] [blame] | 377 | qdev_realize_and_unref(bds, &bus->qbus, &error_fatal); |
Marcel Apfelbaum | 02b0743 | 2015-11-26 18:00:27 +0200 | [diff] [blame] | 378 | } |
Marcel Apfelbaum | 40d14be | 2015-06-02 14:23:06 +0300 | [diff] [blame] | 379 | |
| 380 | pci_word_test_and_set_mask(dev->config + PCI_STATUS, |
| 381 | PCI_STATUS_66MHZ | PCI_STATUS_FAST_BACK); |
| 382 | pci_config_set_class(dev->config, PCI_CLASS_BRIDGE_HOST); |
| 383 | |
Laszlo Ersek | 48ea3de | 2015-06-19 04:40:17 +0200 | [diff] [blame] | 384 | pxb_dev_list = g_list_insert_sorted(pxb_dev_list, pxb, pxb_compare); |
Wei Jiangang | 86395eb | 2016-05-17 18:18:46 +0800 | [diff] [blame] | 385 | return; |
Wei Jiangang | 2e4278b | 2016-03-23 15:26:19 +0800 | [diff] [blame] | 386 | |
| 387 | err_register_bus: |
| 388 | object_unref(OBJECT(bds)); |
| 389 | object_unparent(OBJECT(bus)); |
| 390 | object_unref(OBJECT(ds)); |
Marcel Apfelbaum | 40d14be | 2015-06-02 14:23:06 +0300 | [diff] [blame] | 391 | } |
| 392 | |
Wei Jiangang | 86395eb | 2016-05-17 18:18:46 +0800 | [diff] [blame] | 393 | static void pxb_dev_realize(PCIDevice *dev, Error **errp) |
Marcel Apfelbaum | 02b0743 | 2015-11-26 18:00:27 +0200 | [diff] [blame] | 394 | { |
David Gibson | fd56e06 | 2017-11-29 19:46:27 +1100 | [diff] [blame] | 395 | if (pci_bus_is_express(pci_get_bus(dev))) { |
Wei Jiangang | 86395eb | 2016-05-17 18:18:46 +0800 | [diff] [blame] | 396 | error_setg(errp, "pxb devices cannot reside on a PCIe bus"); |
| 397 | return; |
Marcel Apfelbaum | 02b0743 | 2015-11-26 18:00:27 +0200 | [diff] [blame] | 398 | } |
| 399 | |
Ben Widawsky | 25a2e52 | 2022-04-29 15:40:36 +0100 | [diff] [blame] | 400 | pxb_dev_realize_common(dev, PCI, errp); |
Marcel Apfelbaum | 02b0743 | 2015-11-26 18:00:27 +0200 | [diff] [blame] | 401 | } |
| 402 | |
Laszlo Ersek | 48ea3de | 2015-06-19 04:40:17 +0200 | [diff] [blame] | 403 | static void pxb_dev_exitfn(PCIDevice *pci_dev) |
| 404 | { |
Jonathan Cameron | c28db9e | 2023-04-20 15:27:50 +0100 | [diff] [blame] | 405 | PXBDev *pxb = PXB_DEV(pci_dev); |
Laszlo Ersek | 48ea3de | 2015-06-19 04:40:17 +0200 | [diff] [blame] | 406 | |
| 407 | pxb_dev_list = g_list_remove(pxb_dev_list, pxb); |
| 408 | } |
| 409 | |
Marcel Apfelbaum | 40d14be | 2015-06-02 14:23:06 +0300 | [diff] [blame] | 410 | static Property pxb_dev_properties[] = { |
Cao jin | f9735fd | 2016-03-01 17:45:24 +0800 | [diff] [blame] | 411 | /* Note: 0 is not a legal PXB bus number. */ |
Marcel Apfelbaum | 40d14be | 2015-06-02 14:23:06 +0300 | [diff] [blame] | 412 | DEFINE_PROP_UINT8("bus_nr", PXBDev, bus_nr, 0), |
Marcel Apfelbaum | 0e79e51 | 2015-06-02 14:23:10 +0300 | [diff] [blame] | 413 | DEFINE_PROP_UINT16("numa_node", PXBDev, numa_node, NUMA_NODE_UNASSIGNED), |
Xingang Wang | 91528f4 | 2021-07-08 12:55:12 +0000 | [diff] [blame] | 414 | DEFINE_PROP_BOOL("bypass_iommu", PXBDev, bypass_iommu, false), |
Marcel Apfelbaum | 40d14be | 2015-06-02 14:23:06 +0300 | [diff] [blame] | 415 | DEFINE_PROP_END_OF_LIST(), |
| 416 | }; |
| 417 | |
| 418 | static void pxb_dev_class_init(ObjectClass *klass, void *data) |
| 419 | { |
| 420 | DeviceClass *dc = DEVICE_CLASS(klass); |
| 421 | PCIDeviceClass *k = PCI_DEVICE_CLASS(klass); |
| 422 | |
Wei Jiangang | 86395eb | 2016-05-17 18:18:46 +0800 | [diff] [blame] | 423 | k->realize = pxb_dev_realize; |
Laszlo Ersek | 48ea3de | 2015-06-19 04:40:17 +0200 | [diff] [blame] | 424 | k->exit = pxb_dev_exitfn; |
Marcel Apfelbaum | 40d14be | 2015-06-02 14:23:06 +0300 | [diff] [blame] | 425 | k->vendor_id = PCI_VENDOR_ID_REDHAT; |
| 426 | k->device_id = PCI_DEVICE_ID_REDHAT_PXB; |
| 427 | k->class_id = PCI_CLASS_BRIDGE_HOST; |
| 428 | |
| 429 | dc->desc = "PCI Expander Bridge"; |
Marc-André Lureau | 4f67d30 | 2020-01-10 19:30:32 +0400 | [diff] [blame] | 430 | device_class_set_props(dc, pxb_dev_properties); |
Marcel Apfelbaum | 7b346c7 | 2016-07-17 19:53:10 +0300 | [diff] [blame] | 431 | dc->hotpluggable = false; |
Marcel Apfelbaum | 13d11b0 | 2016-02-03 13:56:10 +0200 | [diff] [blame] | 432 | set_bit(DEVICE_CATEGORY_BRIDGE, dc->categories); |
Marcel Apfelbaum | 40d14be | 2015-06-02 14:23:06 +0300 | [diff] [blame] | 433 | } |
| 434 | |
| 435 | static const TypeInfo pxb_dev_info = { |
Jonathan Cameron | c28db9e | 2023-04-20 15:27:50 +0100 | [diff] [blame] | 436 | .name = TYPE_PXB_DEV, |
Marcel Apfelbaum | 40d14be | 2015-06-02 14:23:06 +0300 | [diff] [blame] | 437 | .parent = TYPE_PCI_DEVICE, |
| 438 | .instance_size = sizeof(PXBDev), |
| 439 | .class_init = pxb_dev_class_init, |
Eduardo Habkost | fd3b02c | 2017-09-27 16:56:34 -0300 | [diff] [blame] | 440 | .interfaces = (InterfaceInfo[]) { |
| 441 | { INTERFACE_CONVENTIONAL_PCI_DEVICE }, |
| 442 | { }, |
| 443 | }, |
Marcel Apfelbaum | 40d14be | 2015-06-02 14:23:06 +0300 | [diff] [blame] | 444 | }; |
| 445 | |
Wei Jiangang | 86395eb | 2016-05-17 18:18:46 +0800 | [diff] [blame] | 446 | static void pxb_pcie_dev_realize(PCIDevice *dev, Error **errp) |
Marcel Apfelbaum | 02b0743 | 2015-11-26 18:00:27 +0200 | [diff] [blame] | 447 | { |
David Gibson | fd56e06 | 2017-11-29 19:46:27 +1100 | [diff] [blame] | 448 | if (!pci_bus_is_express(pci_get_bus(dev))) { |
Wei Jiangang | 86395eb | 2016-05-17 18:18:46 +0800 | [diff] [blame] | 449 | error_setg(errp, "pxb-pcie devices cannot reside on a PCI bus"); |
| 450 | return; |
Marcel Apfelbaum | 02b0743 | 2015-11-26 18:00:27 +0200 | [diff] [blame] | 451 | } |
| 452 | |
Ben Widawsky | 25a2e52 | 2022-04-29 15:40:36 +0100 | [diff] [blame] | 453 | pxb_dev_realize_common(dev, PCIE, errp); |
Marcel Apfelbaum | 02b0743 | 2015-11-26 18:00:27 +0200 | [diff] [blame] | 454 | } |
| 455 | |
| 456 | static void pxb_pcie_dev_class_init(ObjectClass *klass, void *data) |
| 457 | { |
| 458 | DeviceClass *dc = DEVICE_CLASS(klass); |
| 459 | PCIDeviceClass *k = PCI_DEVICE_CLASS(klass); |
| 460 | |
Wei Jiangang | 86395eb | 2016-05-17 18:18:46 +0800 | [diff] [blame] | 461 | k->realize = pxb_pcie_dev_realize; |
Marcel Apfelbaum | 02b0743 | 2015-11-26 18:00:27 +0200 | [diff] [blame] | 462 | k->exit = pxb_dev_exitfn; |
| 463 | k->vendor_id = PCI_VENDOR_ID_REDHAT; |
| 464 | k->device_id = PCI_DEVICE_ID_REDHAT_PXB_PCIE; |
| 465 | k->class_id = PCI_CLASS_BRIDGE_HOST; |
| 466 | |
| 467 | dc->desc = "PCI Express Expander Bridge"; |
Marcel Apfelbaum | 7b346c7 | 2016-07-17 19:53:10 +0300 | [diff] [blame] | 468 | dc->hotpluggable = false; |
Marcel Apfelbaum | 13d11b0 | 2016-02-03 13:56:10 +0200 | [diff] [blame] | 469 | set_bit(DEVICE_CATEGORY_BRIDGE, dc->categories); |
Marcel Apfelbaum | 02b0743 | 2015-11-26 18:00:27 +0200 | [diff] [blame] | 470 | } |
| 471 | |
| 472 | static const TypeInfo pxb_pcie_dev_info = { |
Jonathan Cameron | c28db9e | 2023-04-20 15:27:50 +0100 | [diff] [blame] | 473 | .name = TYPE_PXB_PCIE_DEV, |
| 474 | .parent = TYPE_PXB_DEV, |
| 475 | .instance_size = sizeof(PXBPCIEDev), |
Marcel Apfelbaum | 02b0743 | 2015-11-26 18:00:27 +0200 | [diff] [blame] | 476 | .class_init = pxb_pcie_dev_class_init, |
Eduardo Habkost | fd3b02c | 2017-09-27 16:56:34 -0300 | [diff] [blame] | 477 | .interfaces = (InterfaceInfo[]) { |
| 478 | { INTERFACE_CONVENTIONAL_PCI_DEVICE }, |
| 479 | { }, |
| 480 | }, |
Marcel Apfelbaum | 02b0743 | 2015-11-26 18:00:27 +0200 | [diff] [blame] | 481 | }; |
| 482 | |
Ben Widawsky | 4f8db87 | 2022-04-29 15:40:39 +0100 | [diff] [blame] | 483 | static void pxb_cxl_dev_realize(PCIDevice *dev, Error **errp) |
| 484 | { |
Ben Widawsky | 4f8db87 | 2022-04-29 15:40:39 +0100 | [diff] [blame] | 485 | /* A CXL PXB's parent bus is still PCIe */ |
| 486 | if (!pci_bus_is_express(pci_get_bus(dev))) { |
| 487 | error_setg(errp, "pxb-cxl devices cannot reside on a PCI bus"); |
| 488 | return; |
| 489 | } |
Ben Widawsky | 4f8db87 | 2022-04-29 15:40:39 +0100 | [diff] [blame] | 490 | |
| 491 | pxb_dev_realize_common(dev, CXL, errp); |
Jonathan Cameron | 154070e | 2023-02-27 15:31:28 +0000 | [diff] [blame] | 492 | pxb_cxl_dev_reset(DEVICE(dev)); |
Ben Widawsky | 4f8db87 | 2022-04-29 15:40:39 +0100 | [diff] [blame] | 493 | } |
| 494 | |
Jonathan Cameron | 154070e | 2023-02-27 15:31:28 +0000 | [diff] [blame] | 495 | static Property pxb_cxl_dev_properties[] = { |
Jonathan Cameron | c28db9e | 2023-04-20 15:27:50 +0100 | [diff] [blame] | 496 | DEFINE_PROP_BOOL("hdm_for_passthrough", PXBCXLDev, hdm_for_passthrough, false), |
Jonathan Cameron | 154070e | 2023-02-27 15:31:28 +0000 | [diff] [blame] | 497 | DEFINE_PROP_END_OF_LIST(), |
| 498 | }; |
| 499 | |
Ben Widawsky | 4f8db87 | 2022-04-29 15:40:39 +0100 | [diff] [blame] | 500 | static void pxb_cxl_dev_class_init(ObjectClass *klass, void *data) |
| 501 | { |
| 502 | DeviceClass *dc = DEVICE_CLASS(klass); |
| 503 | PCIDeviceClass *k = PCI_DEVICE_CLASS(klass); |
| 504 | |
| 505 | k->realize = pxb_cxl_dev_realize; |
| 506 | k->exit = pxb_dev_exitfn; |
| 507 | /* |
| 508 | * XXX: These types of bridges don't actually show up in the hierarchy so |
| 509 | * vendor, device, class, etc. ids are intentionally left out. |
| 510 | */ |
| 511 | |
| 512 | dc->desc = "CXL Host Bridge"; |
Jonathan Cameron | 154070e | 2023-02-27 15:31:28 +0000 | [diff] [blame] | 513 | device_class_set_props(dc, pxb_cxl_dev_properties); |
Ben Widawsky | 4f8db87 | 2022-04-29 15:40:39 +0100 | [diff] [blame] | 514 | set_bit(DEVICE_CATEGORY_BRIDGE, dc->categories); |
| 515 | |
| 516 | /* Host bridges aren't hotpluggable. FIXME: spec reference */ |
| 517 | dc->hotpluggable = false; |
Jonathan Cameron | 154070e | 2023-02-27 15:31:28 +0000 | [diff] [blame] | 518 | dc->reset = pxb_cxl_dev_reset; |
Ben Widawsky | 4f8db87 | 2022-04-29 15:40:39 +0100 | [diff] [blame] | 519 | } |
| 520 | |
| 521 | static const TypeInfo pxb_cxl_dev_info = { |
Jonathan Cameron | c28db9e | 2023-04-20 15:27:50 +0100 | [diff] [blame] | 522 | .name = TYPE_PXB_CXL_DEV, |
| 523 | .parent = TYPE_PXB_PCIE_DEV, |
| 524 | .instance_size = sizeof(PXBCXLDev), |
Ben Widawsky | 4f8db87 | 2022-04-29 15:40:39 +0100 | [diff] [blame] | 525 | .class_init = pxb_cxl_dev_class_init, |
| 526 | .interfaces = |
| 527 | (InterfaceInfo[]){ |
| 528 | { INTERFACE_CONVENTIONAL_PCI_DEVICE }, |
| 529 | {}, |
| 530 | }, |
| 531 | }; |
| 532 | |
Marcel Apfelbaum | 40d14be | 2015-06-02 14:23:06 +0300 | [diff] [blame] | 533 | static void pxb_register_types(void) |
| 534 | { |
| 535 | type_register_static(&pxb_bus_info); |
Marcel Apfelbaum | 02b0743 | 2015-11-26 18:00:27 +0200 | [diff] [blame] | 536 | type_register_static(&pxb_pcie_bus_info); |
Ben Widawsky | 4f8db87 | 2022-04-29 15:40:39 +0100 | [diff] [blame] | 537 | type_register_static(&pxb_cxl_bus_info); |
Marcel Apfelbaum | 40d14be | 2015-06-02 14:23:06 +0300 | [diff] [blame] | 538 | type_register_static(&pxb_host_info); |
Ben Widawsky | 6e4e3ae | 2022-04-29 15:40:48 +0100 | [diff] [blame] | 539 | type_register_static(&cxl_host_info); |
Marcel Apfelbaum | 40d14be | 2015-06-02 14:23:06 +0300 | [diff] [blame] | 540 | type_register_static(&pxb_dev_info); |
Marcel Apfelbaum | 02b0743 | 2015-11-26 18:00:27 +0200 | [diff] [blame] | 541 | type_register_static(&pxb_pcie_dev_info); |
Ben Widawsky | 4f8db87 | 2022-04-29 15:40:39 +0100 | [diff] [blame] | 542 | type_register_static(&pxb_cxl_dev_info); |
Marcel Apfelbaum | 40d14be | 2015-06-02 14:23:06 +0300 | [diff] [blame] | 543 | } |
| 544 | |
| 545 | type_init(pxb_register_types) |