* [PATCH v2 0/2] hw/pci-bridge: fix build with CONFIG_CXL disabled
@ 2026-09-28 9:56 Daniel P. Berrangé
2026-09-28 9:56 ` [PATCH v2 1/2] hw/arm: remove pci-bridge/pci_expander_bridge.h from virt.c Daniel P. Berrangé
2026-09-28 9:56 ` [PATCH v2 2/2] hw/pci-bridge: split CXL PXB into separate file Daniel P. Berrangé
0 siblings, 2 replies; 5+ messages in thread
From: Daniel P. Berrangé @ 2026-09-28 9:56 UTC (permalink / raw)
To: qemu-devel
Cc: linux-cxl, Michael S. Tsirkin, qemu-arm, Junjie Cao,
Peter Maydell, Anisa Su, Jonathan Cameron,
Philippe Mathieu-Daudé, Daniel P. Berrangé
See patch 2 for the details
Changed in v2:
* Instead of using CONFIG_CXL in pci_expander_bridge.c
split the file in two and conditionalize in meson.build
Daniel P. Berrangé (2):
hw/arm: remove pci-bridge/pci_expander_bridge.h from virt.c
hw/pci-bridge: split CXL PXB into separate file
hw/arm/virt.c | 1 -
hw/cxl/cxl-host.c | 2 +-
hw/pci-bridge/meson.build | 4 +-
hw/pci-bridge/pci_expander_bridge.c | 194 +----------------
hw/pci-bridge/pci_expander_bridge_common.h | 29 +++
hw/pci-bridge/pci_expander_bridge_cxl.c | 201 ++++++++++++++++++
hw/pci-bridge/pci_expander_bridge_stubs.c | 14 --
...der_bridge.h => pci_expander_bridge_cxl.h} | 0
8 files changed, 242 insertions(+), 203 deletions(-)
create mode 100644 hw/pci-bridge/pci_expander_bridge_common.h
create mode 100644 hw/pci-bridge/pci_expander_bridge_cxl.c
delete mode 100644 hw/pci-bridge/pci_expander_bridge_stubs.c
rename include/hw/pci-bridge/{pci_expander_bridge.h => pci_expander_bridge_cxl.h} (100%)
--
2.55.0
^ permalink raw reply [flat|nested] 5+ messages in thread
* [PATCH v2 1/2] hw/arm: remove pci-bridge/pci_expander_bridge.h from virt.c
2026-09-28 9:56 [PATCH v2 0/2] hw/pci-bridge: fix build with CONFIG_CXL disabled Daniel P. Berrangé
@ 2026-09-28 9:56 ` Daniel P. Berrangé
2026-09-28 10:01 ` Philippe Mathieu-Daudé
2026-09-28 9:56 ` [PATCH v2 2/2] hw/pci-bridge: split CXL PXB into separate file Daniel P. Berrangé
1 sibling, 1 reply; 5+ messages in thread
From: Daniel P. Berrangé @ 2026-09-28 9:56 UTC (permalink / raw)
To: qemu-devel
Cc: linux-cxl, Michael S. Tsirkin, qemu-arm, Junjie Cao,
Peter Maydell, Anisa Su, Jonathan Cameron,
Philippe Mathieu-Daudé, Daniel P. Berrangé
This include is redundant as the function is declares is not
referenced.
Signed-off-by: Daniel P. Berrangé <berrange@redhat.com>
---
hw/arm/virt.c | 1 -
1 file changed, 1 deletion(-)
diff --git a/hw/arm/virt.c b/hw/arm/virt.c
index 3eecf094bcc..a570832fc0e 100644
--- a/hw/arm/virt.c
+++ b/hw/arm/virt.c
@@ -58,7 +58,6 @@
#include "qemu/module.h"
#include "hw/pci/pci_bus.h"
#include "hw/pci-host/gpex.h"
-#include "hw/pci-bridge/pci_expander_bridge.h"
#include "hw/virtio/virtio-pci.h"
#include "hw/core/sysbus-fdt.h"
#include "hw/core/platform-bus.h"
--
2.55.0
^ permalink raw reply related [flat|nested] 5+ messages in thread
* [PATCH v2 2/2] hw/pci-bridge: split CXL PXB into separate file
2026-09-28 9:56 [PATCH v2 0/2] hw/pci-bridge: fix build with CONFIG_CXL disabled Daniel P. Berrangé
2026-09-28 9:56 ` [PATCH v2 1/2] hw/arm: remove pci-bridge/pci_expander_bridge.h from virt.c Daniel P. Berrangé
@ 2026-09-28 9:56 ` Daniel P. Berrangé
2026-09-28 10:03 ` Philippe Mathieu-Daudé
1 sibling, 1 reply; 5+ messages in thread
From: Daniel P. Berrangé @ 2026-09-28 9:56 UTC (permalink / raw)
To: qemu-devel
Cc: linux-cxl, Michael S. Tsirkin, qemu-arm, Junjie Cao,
Peter Maydell, Anisa Su, Jonathan Cameron,
Philippe Mathieu-Daudé, Daniel P. Berrangé
If CONFIG_CXL=n is added to the Kconfig, the build fails to link
the PXB device:
/usr/bin/ld.bfd: libsystem.a.p/hw_pci-bridge_pci_expander_bridge.c.o: in function `pxb_cxl_realize':
/home/berrange/src/virt/qemu/build/../hw/pci-bridge/pci_expander_bridge.c:202:(.text+0x330): undefined reference to `cxl_component_register_block_init'
/usr/bin/ld.bfd: libsystem.a.p/hw_pci-bridge_pci_expander_bridge.c.o: in function `pxb_cxl_dev_reset':
/home/berrange/src/virt/qemu/build/../hw/pci-bridge/pci_expander_bridge.c:309:(.text+0x768): undefined reference to `cxl_component_register_init_common'
We cannot use CONFIG_CXL in pci_expander_bridge.c because the
identifier is poisoned. Instead the CXL pieces must be split
off into a separate source file which can be conditionally
built.
With this change, the stubs file is no longer required, since
the code referencing the stub was already protected by CONFIG_CXL.
Fixes: 6e4e3ae936 (hw/cxl/component: Implement host bridge MMIO (8.2.5, table 142))
Signed-off-by: Daniel P. Berrangé <berrange@redhat.com>
---
hw/cxl/cxl-host.c | 2 +-
hw/pci-bridge/meson.build | 4 +-
hw/pci-bridge/pci_expander_bridge.c | 194 +----------------
hw/pci-bridge/pci_expander_bridge_common.h | 29 +++
hw/pci-bridge/pci_expander_bridge_cxl.c | 201 ++++++++++++++++++
hw/pci-bridge/pci_expander_bridge_stubs.c | 14 --
...der_bridge.h => pci_expander_bridge_cxl.h} | 0
7 files changed, 242 insertions(+), 202 deletions(-)
create mode 100644 hw/pci-bridge/pci_expander_bridge_common.h
create mode 100644 hw/pci-bridge/pci_expander_bridge_cxl.c
delete mode 100644 hw/pci-bridge/pci_expander_bridge_stubs.c
rename include/hw/pci-bridge/{pci_expander_bridge.h => pci_expander_bridge_cxl.h} (100%)
diff --git a/hw/cxl/cxl-host.c b/hw/cxl/cxl-host.c
index e279ce5fe3a..cda4dfed50d 100644
--- a/hw/cxl/cxl-host.c
+++ b/hw/cxl/cxl-host.c
@@ -20,7 +20,7 @@
#include "hw/pci/pci_bridge.h"
#include "hw/pci/pci_host.h"
#include "hw/pci/pcie_port.h"
-#include "hw/pci-bridge/pci_expander_bridge.h"
+#include "hw/pci-bridge/pci_expander_bridge_cxl.h"
static void cxl_fixed_memory_window_config(CXLFixedMemoryWindowOptions *object,
int index, Error **errp)
diff --git a/hw/pci-bridge/meson.build b/hw/pci-bridge/meson.build
index 2e0eb0d2332..aaeef64caaa 100644
--- a/hw/pci-bridge/meson.build
+++ b/hw/pci-bridge/meson.build
@@ -4,8 +4,8 @@ pci_ss.add(when: 'CONFIG_I82801B11', if_true: files('i82801b11.c'))
pci_ss.add(when: 'CONFIG_IOH3420', if_true: files('ioh3420.c'))
pci_ss.add(when: 'CONFIG_PCIE_PORT', if_true: files('pcie_root_port.c', 'gen_pcie_root_port.c'))
pci_ss.add(when: 'CONFIG_PCIE_PCI_BRIDGE', if_true: files('pcie_pci_bridge.c'))
-pci_ss.add(when: 'CONFIG_PXB', if_true: files('pci_expander_bridge.c'),
- if_false: files('pci_expander_bridge_stubs.c'))
+pci_ss.add(when: 'CONFIG_PXB', if_true: files('pci_expander_bridge.c'))
+pci_ss.add(when: 'CONFIG_CXL', if_true: files('pci_expander_bridge_cxl.c'))
pci_ss.add(when: 'CONFIG_XIO3130', if_true: files('xio3130_upstream.c', 'xio3130_downstream.c'))
pci_ss.add(when: 'CONFIG_CXL', if_true: files('cxl_root_port.c', 'cxl_upstream.c', 'cxl_downstream.c'))
diff --git a/hw/pci-bridge/pci_expander_bridge.c b/hw/pci-bridge/pci_expander_bridge.c
index 40ffbc4e082..2498df480bd 100644
--- a/hw/pci-bridge/pci_expander_bridge.c
+++ b/hw/pci-bridge/pci_expander_bridge.c
@@ -18,57 +18,29 @@
#include "hw/pci/pcie_port.h"
#include "hw/core/qdev-properties.h"
#include "hw/pci/pci_bridge.h"
-#include "hw/pci-bridge/pci_expander_bridge.h"
-#include "hw/cxl/cxl.h"
#include "qemu/range.h"
#include "qemu/error-report.h"
#include "qemu/module.h"
#include "system/numa.h"
#include "hw/core/boards.h"
#include "qom/object.h"
-
-enum BusType { PCI, PCIE, CXL };
+#include "pci_expander_bridge_common.h"
#define TYPE_PXB_BUS "pxb-bus"
-typedef struct PXBBus PXBBus;
+
DECLARE_INSTANCE_CHECKER(PXBBus, PXB_BUS,
TYPE_PXB_BUS)
DECLARE_INSTANCE_CHECKER(PXBBus, PXB_PCIE_BUS,
TYPE_PXB_PCIE_BUS)
-DECLARE_INSTANCE_CHECKER(PXBBus, PXB_CXL_BUS,
- TYPE_PXB_CXL_BUS)
-
-struct PXBBus {
- /*< private >*/
- PCIBus parent_obj;
- /*< public >*/
-
- char bus_path[8];
-};
-
OBJECT_DECLARE_SIMPLE_TYPE(PXBPCIEDev, PXB_PCIE_DEV)
static GList *pxb_dev_list;
#define TYPE_PXB_HOST "pxb-host"
-CXLComponentState *cxl_get_hb_cstate(PCIHostState *hb)
-{
- CXLHost *host = PXB_CXL_HOST(hb);
-
- return &host->cxl_cstate;
-}
-
-bool cxl_get_hb_passthrough(PCIHostState *hb)
-{
- CXLHost *host = PXB_CXL_HOST(hb);
-
- return host->passthrough;
-}
-
-static int pxb_bus_num(PCIBus *bus)
+int pxb_bus_num(PCIBus *bus)
{
PXBDev *pxb = PXB_DEV(bus->parent_dev);
@@ -96,7 +68,7 @@ static void prop_pxb_uid_get(Object *obj, Visitor *v, const char *name,
visit_type_uint32(v, name, &uid, errp);
}
-static void pxb_bus_class_init(ObjectClass *class, const void *data)
+void pxb_bus_class_init(ObjectClass *class, const void *data)
{
PCIBusClass *pbc = PCI_BUS_CLASS(class);
@@ -123,20 +95,11 @@ static const TypeInfo pxb_pcie_bus_info = {
.class_init = pxb_bus_class_init,
};
-static const TypeInfo pxb_cxl_bus_info = {
- .name = TYPE_PXB_CXL_BUS,
- .parent = TYPE_CXL_BUS,
- .instance_size = sizeof(PXBBus),
- .class_init = pxb_bus_class_init,
-};
-
static const char *pxb_host_root_bus_path(PCIHostState *host_bridge,
PCIBus *rootbus)
{
- PXBBus *bus = pci_bus_is_cxl(rootbus) ?
- PXB_CXL_BUS(rootbus) :
- pci_bus_is_express(rootbus) ? PXB_PCIE_BUS(rootbus) :
- PXB_BUS(rootbus);
+ PXBBus *bus = pci_bus_is_express(rootbus) ?
+ PXB_PCIE_BUS(rootbus) : PXB_BUS(rootbus);
snprintf(bus->bus_path, 8, "0000:%02x", pxb_bus_num(rootbus));
return bus->bus_path;
@@ -192,64 +155,6 @@ static const TypeInfo pxb_host_info = {
.class_init = pxb_host_class_init,
};
-static void pxb_cxl_realize(DeviceState *dev, Error **errp)
-{
- SysBusDevice *sbd = SYS_BUS_DEVICE(dev);
- CXLHost *cxl = PXB_CXL_HOST(dev);
- CXLComponentState *cxl_cstate = &cxl->cxl_cstate;
- struct MemoryRegion *mr = &cxl_cstate->crb.component_registers;
-
- cxl_component_register_block_init(OBJECT(dev), cxl_cstate,
- TYPE_PXB_CXL_HOST);
- sysbus_init_mmio(sbd, mr);
-}
-
-/*
- * Host bridge realization has no means of knowning state associated
- * with a particular machine. As such, it is nececssary to delay
- * final setup of the host bridge register space until later in the
- * machine bring up.
- */
-void pxb_cxl_hook_up_registers(CXLState *cxl_state, PCIBus *bus, Error **errp)
-{
- PXBCXLDev *pxb = PXB_CXL_DEV(pci_bridge_get_device(bus));
- CXLHost *cxl = pxb->cxl_host_bridge;
- CXLComponentState *cxl_cstate = &cxl->cxl_cstate;
- struct MemoryRegion *mr = &cxl_cstate->crb.component_registers;
- hwaddr offset;
-
- offset = memory_region_size(mr) * cxl_state->next_mr_idx;
- if (offset > memory_region_size(&cxl_state->host_mr)) {
- error_setg(errp, "Insufficient space for pxb cxl host register space");
- return;
- }
-
- memory_region_add_subregion(&cxl_state->host_mr, offset, mr);
- cxl_state->next_mr_idx++;
-}
-
-static void pxb_cxl_host_class_init(ObjectClass *class, const void *data)
-{
- DeviceClass *dc = DEVICE_CLASS(class);
- PCIHostBridgeClass *hc = PCI_HOST_BRIDGE_CLASS(class);
-
- hc->root_bus_path = pxb_host_root_bus_path;
- dc->fw_name = "cxl";
- dc->realize = pxb_cxl_realize;
- /* Reason: Internal part of the pxb/pxb-pcie device, not usable by itself */
- dc->user_creatable = false;
-}
-
-/*
- * This is a device to handle the MMIO for a CXL host bridge. It does nothing
- * else.
- */
-static const TypeInfo cxl_host_info = {
- .name = TYPE_PXB_CXL_HOST,
- .parent = TYPE_PCI_HOST_BRIDGE,
- .instance_size = sizeof(CXLHost),
- .class_init = pxb_cxl_host_class_init,
-};
/*
* Registers the PXB bus as a child of pci host root bus.
@@ -297,34 +202,6 @@ static int pxb_map_irq_fn(PCIDevice *pci_dev, int pin)
return pin - PCI_SLOT(pxb->devfn);
}
-static void pxb_cxl_dev_reset(DeviceState *dev)
-{
- CXLHost *cxl = PXB_CXL_DEV(dev)->cxl_host_bridge;
- CXLComponentState *cxl_cstate = &cxl->cxl_cstate;
- PCIHostState *hb = PCI_HOST_BRIDGE(cxl);
- uint32_t *reg_state = cxl_cstate->crb.cache_mem_registers;
- uint32_t *write_msk = cxl_cstate->crb.cache_mem_regs_write_mask;
- int dsp_count = 0;
-
- cxl_component_register_init_common(reg_state, write_msk, CXL2_RC, false);
- /*
- * The CXL specification allows for host bridges with no HDM decoders
- * if they only have a single root port.
- */
- if (!PXB_CXL_DEV(dev)->hdm_for_passthrough) {
- dsp_count = pcie_count_ds_ports(hb->bus);
- }
- /* Initial reset will have 0 dsp so wait until > 0 */
- if (dsp_count == 1) {
- cxl->passthrough = true;
- /* Set Capability ID in header to NONE */
- ARRAY_FIELD_DP32(reg_state, CXL_HDM_CAPABILITY_HEADER, ID, 0);
- } else {
- ARRAY_FIELD_DP32(reg_state, CXL_HDM_DECODER_CAPABILITY, TARGET_COUNT,
- 8);
- }
-}
-
static gint pxb_compare(gconstpointer a, gconstpointer b)
{
const PXBDev *pxb_a = a, *pxb_b = b;
@@ -334,8 +211,8 @@ static gint pxb_compare(gconstpointer a, gconstpointer b)
0;
}
-static bool pxb_dev_realize_common(PCIDevice *dev, enum BusType type,
- Error **errp)
+bool pxb_dev_realize_common(PCIDevice *dev, enum BusType type,
+ Error **errp)
{
PXBDev *pxb = PXB_DEV(dev);
DeviceState *ds, *bds = NULL;
@@ -417,7 +294,7 @@ static void pxb_dev_realize(PCIDevice *dev, Error **errp)
pxb_dev_realize_common(dev, PCI, errp);
}
-static void pxb_dev_exitfn(PCIDevice *pci_dev)
+void pxb_dev_exitfn(PCIDevice *pci_dev)
{
PXBDev *pxb = PXB_DEV(pci_dev);
@@ -496,67 +373,14 @@ static const TypeInfo pxb_pcie_dev_info = {
},
};
-static void pxb_cxl_dev_realize(PCIDevice *dev, Error **errp)
-{
- /* A CXL PXB's parent bus is still PCIe */
- if (!pci_bus_is_express(pci_get_bus(dev))) {
- error_setg(errp, "pxb-cxl devices cannot reside on a PCI bus");
- return;
- }
-
- if (!pxb_dev_realize_common(dev, CXL, errp)) {
- return;
- }
- pxb_cxl_dev_reset(DEVICE(dev));
-}
-
-static const Property pxb_cxl_dev_properties[] = {
- DEFINE_PROP_BOOL("hdm_for_passthrough", PXBCXLDev, hdm_for_passthrough, false),
-};
-
-static void pxb_cxl_dev_class_init(ObjectClass *klass, const void *data)
-{
- DeviceClass *dc = DEVICE_CLASS(klass);
- PCIDeviceClass *k = PCI_DEVICE_CLASS(klass);
-
- k->realize = pxb_cxl_dev_realize;
- k->exit = pxb_dev_exitfn;
- /*
- * XXX: These types of bridges don't actually show up in the hierarchy so
- * vendor, device, class, etc. ids are intentionally left out.
- */
-
- dc->desc = "CXL Host Bridge";
- device_class_set_props(dc, pxb_cxl_dev_properties);
- set_bit(DEVICE_CATEGORY_BRIDGE, dc->categories);
-
- /* Host bridges aren't hotpluggable. FIXME: spec reference */
- dc->hotpluggable = false;
- device_class_set_legacy_reset(dc, pxb_cxl_dev_reset);
-}
-
-static const TypeInfo pxb_cxl_dev_info = {
- .name = TYPE_PXB_CXL_DEV,
- .parent = TYPE_PXB_PCIE_DEV,
- .instance_size = sizeof(PXBCXLDev),
- .class_init = pxb_cxl_dev_class_init,
- .interfaces =
- (const InterfaceInfo[]){
- { INTERFACE_CONVENTIONAL_PCI_DEVICE },
- {},
- },
-};
static void pxb_register_types(void)
{
type_register_static(&pxb_bus_info);
type_register_static(&pxb_pcie_bus_info);
- type_register_static(&pxb_cxl_bus_info);
type_register_static(&pxb_host_info);
- type_register_static(&cxl_host_info);
type_register_static(&pxb_dev_info);
type_register_static(&pxb_pcie_dev_info);
- type_register_static(&pxb_cxl_dev_info);
}
type_init(pxb_register_types)
diff --git a/hw/pci-bridge/pci_expander_bridge_common.h b/hw/pci-bridge/pci_expander_bridge_common.h
new file mode 100644
index 00000000000..fc5d1ac8691
--- /dev/null
+++ b/hw/pci-bridge/pci_expander_bridge_common.h
@@ -0,0 +1,29 @@
+/*
+ * PCI Expander Bridge Device Emulation Common Code
+ *
+ * Copyright (C) 2015 Red Hat Inc
+ *
+ * Authors:
+ * Marcel Apfelbaum <marcel@redhat.com>
+ *
+ * This work is licensed under the terms of the GNU GPL, version 2 or later.
+ * See the COPYING file in the top-level directory.
+ */
+
+enum BusType { PCI, PCIE, CXL };
+
+typedef struct PXBBus PXBBus;
+
+struct PXBBus {
+ /*< private >*/
+ PCIBus parent_obj;
+ /*< public >*/
+
+ char bus_path[8];
+};
+
+int pxb_bus_num(PCIBus *bus);
+void pxb_bus_class_init(ObjectClass *class, const void *data);
+bool pxb_dev_realize_common(PCIDevice *dev, enum BusType type,
+ Error **errp);
+void pxb_dev_exitfn(PCIDevice *pci_dev);
diff --git a/hw/pci-bridge/pci_expander_bridge_cxl.c b/hw/pci-bridge/pci_expander_bridge_cxl.c
new file mode 100644
index 00000000000..3294baeaf99
--- /dev/null
+++ b/hw/pci-bridge/pci_expander_bridge_cxl.c
@@ -0,0 +1,201 @@
+/*
+ * CXL PCI Expander Bridge Device Emulation
+ *
+ * Copyright (C) 2015 Red Hat Inc
+ *
+ * Authors:
+ * Marcel Apfelbaum <marcel@redhat.com>
+ *
+ * This work is licensed under the terms of the GNU GPL, version 2 or later.
+ * See the COPYING file in the top-level directory.
+ */
+
+#include "qemu/osdep.h"
+#include "hw/pci/pci.h"
+#include "hw/pci/pci_bus.h"
+#include "hw/pci/pci_bridge.h"
+#include "hw/pci/pcie_port.h"
+#include "hw/core/qdev-properties.h"
+#include "hw/pci-bridge/pci_expander_bridge_cxl.h"
+#include "qom/object.h"
+#include "pci_expander_bridge_common.h"
+
+DECLARE_INSTANCE_CHECKER(PXBBus, PXB_CXL_BUS,
+ TYPE_PXB_CXL_BUS)
+
+CXLComponentState *cxl_get_hb_cstate(PCIHostState *hb)
+{
+ CXLHost *host = PXB_CXL_HOST(hb);
+
+ return &host->cxl_cstate;
+}
+
+bool cxl_get_hb_passthrough(PCIHostState *hb)
+{
+ CXLHost *host = PXB_CXL_HOST(hb);
+
+ return host->passthrough;
+}
+
+static const char *pxb_cxl_host_root_bus_path(PCIHostState *host_bridge,
+ PCIBus *rootbus)
+{
+ PXBBus *bus = PXB_CXL_BUS(rootbus);
+ snprintf(bus->bus_path, 8, "0000:%02x", pxb_bus_num(rootbus));
+ return bus->bus_path;
+}
+
+
+static const TypeInfo pxb_cxl_bus_info = {
+ .name = TYPE_PXB_CXL_BUS,
+ .parent = TYPE_CXL_BUS,
+ .instance_size = sizeof(PXBBus),
+ .class_init = pxb_bus_class_init,
+};
+
+static void pxb_cxl_realize(DeviceState *dev, Error **errp)
+{
+ SysBusDevice *sbd = SYS_BUS_DEVICE(dev);
+ CXLHost *cxl = PXB_CXL_HOST(dev);
+ CXLComponentState *cxl_cstate = &cxl->cxl_cstate;
+ struct MemoryRegion *mr = &cxl_cstate->crb.component_registers;
+
+ cxl_component_register_block_init(OBJECT(dev), cxl_cstate,
+ TYPE_PXB_CXL_HOST);
+ sysbus_init_mmio(sbd, mr);
+}
+
+/*
+ * Host bridge realization has no means of knowning state associated
+ * with a particular machine. As such, it is nececssary to delay
+ * final setup of the host bridge register space until later in the
+ * machine bring up.
+ */
+void pxb_cxl_hook_up_registers(CXLState *cxl_state, PCIBus *bus, Error **errp)
+{
+ PXBCXLDev *pxb = PXB_CXL_DEV(pci_bridge_get_device(bus));
+ CXLHost *cxl = pxb->cxl_host_bridge;
+ CXLComponentState *cxl_cstate = &cxl->cxl_cstate;
+ struct MemoryRegion *mr = &cxl_cstate->crb.component_registers;
+ hwaddr offset;
+
+ offset = memory_region_size(mr) * cxl_state->next_mr_idx;
+ if (offset > memory_region_size(&cxl_state->host_mr)) {
+ error_setg(errp, "Insufficient space for pxb cxl host register space");
+ return;
+ }
+
+ memory_region_add_subregion(&cxl_state->host_mr, offset, mr);
+ cxl_state->next_mr_idx++;
+}
+
+static void pxb_cxl_host_class_init(ObjectClass *class, const void *data)
+{
+ DeviceClass *dc = DEVICE_CLASS(class);
+ PCIHostBridgeClass *hc = PCI_HOST_BRIDGE_CLASS(class);
+
+ hc->root_bus_path = pxb_cxl_host_root_bus_path;
+ dc->fw_name = "cxl";
+ dc->realize = pxb_cxl_realize;
+ /* Reason: Internal part of the pxb/pxb-pcie device, not usable by itself */
+ dc->user_creatable = false;
+}
+
+/*
+ * This is a device to handle the MMIO for a CXL host bridge. It does nothing
+ * else.
+ */
+static const TypeInfo cxl_host_info = {
+ .name = TYPE_PXB_CXL_HOST,
+ .parent = TYPE_PCI_HOST_BRIDGE,
+ .instance_size = sizeof(CXLHost),
+ .class_init = pxb_cxl_host_class_init,
+};
+
+static void pxb_cxl_dev_reset(DeviceState *dev)
+{
+ CXLHost *cxl = PXB_CXL_DEV(dev)->cxl_host_bridge;
+ CXLComponentState *cxl_cstate = &cxl->cxl_cstate;
+ PCIHostState *hb = PCI_HOST_BRIDGE(cxl);
+ uint32_t *reg_state = cxl_cstate->crb.cache_mem_registers;
+ uint32_t *write_msk = cxl_cstate->crb.cache_mem_regs_write_mask;
+ int dsp_count = 0;
+
+ cxl_component_register_init_common(reg_state, write_msk, CXL2_RC, false);
+ /*
+ * The CXL specification allows for host bridges with no HDM decoders
+ * if they only have a single root port.
+ */
+ if (!PXB_CXL_DEV(dev)->hdm_for_passthrough) {
+ dsp_count = pcie_count_ds_ports(hb->bus);
+ }
+ /* Initial reset will have 0 dsp so wait until > 0 */
+ if (dsp_count == 1) {
+ cxl->passthrough = true;
+ /* Set Capability ID in header to NONE */
+ ARRAY_FIELD_DP32(reg_state, CXL_HDM_CAPABILITY_HEADER, ID, 0);
+ } else {
+ ARRAY_FIELD_DP32(reg_state, CXL_HDM_DECODER_CAPABILITY, TARGET_COUNT,
+ 8);
+ }
+}
+
+static void pxb_cxl_dev_realize(PCIDevice *dev, Error **errp)
+{
+ /* A CXL PXB's parent bus is still PCIe */
+ if (!pci_bus_is_express(pci_get_bus(dev))) {
+ error_setg(errp, "pxb-cxl devices cannot reside on a PCI bus");
+ return;
+ }
+
+ if (!pxb_dev_realize_common(dev, CXL, errp)) {
+ return;
+ }
+ pxb_cxl_dev_reset(DEVICE(dev));
+}
+
+static const Property pxb_cxl_dev_properties[] = {
+ DEFINE_PROP_BOOL("hdm_for_passthrough", PXBCXLDev, hdm_for_passthrough, false),
+};
+
+static void pxb_cxl_dev_class_init(ObjectClass *klass, const void *data)
+{
+ DeviceClass *dc = DEVICE_CLASS(klass);
+ PCIDeviceClass *k = PCI_DEVICE_CLASS(klass);
+
+ k->realize = pxb_cxl_dev_realize;
+ k->exit = pxb_dev_exitfn;
+ /*
+ * XXX: These types of bridges don't actually show up in the hierarchy so
+ * vendor, device, class, etc. ids are intentionally left out.
+ */
+
+ dc->desc = "CXL Host Bridge";
+ device_class_set_props(dc, pxb_cxl_dev_properties);
+ set_bit(DEVICE_CATEGORY_BRIDGE, dc->categories);
+
+ /* Host bridges aren't hotpluggable. FIXME: spec reference */
+ dc->hotpluggable = false;
+ device_class_set_legacy_reset(dc, pxb_cxl_dev_reset);
+}
+
+static const TypeInfo pxb_cxl_dev_info = {
+ .name = TYPE_PXB_CXL_DEV,
+ .parent = TYPE_PXB_PCIE_DEV,
+ .instance_size = sizeof(PXBCXLDev),
+ .class_init = pxb_cxl_dev_class_init,
+ .interfaces =
+ (const InterfaceInfo[]){
+ { INTERFACE_CONVENTIONAL_PCI_DEVICE },
+ {},
+ },
+};
+
+static void pxb_cxl_register_types(void)
+{
+ type_register_static(&pxb_cxl_bus_info);
+ type_register_static(&cxl_host_info);
+ type_register_static(&pxb_cxl_dev_info);
+}
+
+type_init(pxb_cxl_register_types)
diff --git a/hw/pci-bridge/pci_expander_bridge_stubs.c b/hw/pci-bridge/pci_expander_bridge_stubs.c
deleted file mode 100644
index b35180311f6..00000000000
--- a/hw/pci-bridge/pci_expander_bridge_stubs.c
+++ /dev/null
@@ -1,14 +0,0 @@
-/*
- * SPDX-License-Identifier: GPL-2.0-or-later
- *
- * Stubs for calls made from machines to handle the case where CONFIG_PXB
- * is not enabled.
- */
-#include "qemu/osdep.h"
-#include "qapi/error.h"
-#include "hw/pci/pci.h"
-#include "hw/pci/pci_bus.h"
-#include "hw/pci-bridge/pci_expander_bridge.h"
-#include "hw/cxl/cxl.h"
-
-void pxb_cxl_hook_up_registers(CXLState *state, PCIBus *bus, Error **errp) {};
diff --git a/include/hw/pci-bridge/pci_expander_bridge.h b/include/hw/pci-bridge/pci_expander_bridge_cxl.h
similarity index 100%
rename from include/hw/pci-bridge/pci_expander_bridge.h
rename to include/hw/pci-bridge/pci_expander_bridge_cxl.h
--
2.55.0
^ permalink raw reply related [flat|nested] 5+ messages in thread
* Re: [PATCH v2 1/2] hw/arm: remove pci-bridge/pci_expander_bridge.h from virt.c
2026-09-28 9:56 ` [PATCH v2 1/2] hw/arm: remove pci-bridge/pci_expander_bridge.h from virt.c Daniel P. Berrangé
@ 2026-09-28 10:01 ` Philippe Mathieu-Daudé
0 siblings, 0 replies; 5+ messages in thread
From: Philippe Mathieu-Daudé @ 2026-09-28 10:01 UTC (permalink / raw)
To: Daniel P. Berrangé, qemu-devel
Cc: linux-cxl, Michael S. Tsirkin, qemu-arm, Junjie Cao,
Peter Maydell, Anisa Su, Jonathan Cameron
On 28/9/26 11:56, Daniel P. Berrangé wrote:
> This include is redundant as the function is declares is not
> referenced.
>
> Signed-off-by: Daniel P. Berrangé <berrange@redhat.com>
> ---
> hw/arm/virt.c | 1 -
> 1 file changed, 1 deletion(-)
Reviewed-by: Philippe Mathieu-Daudé <philmd@oss.qualcomm.com>
^ permalink raw reply [flat|nested] 5+ messages in thread
* Re: [PATCH v2 2/2] hw/pci-bridge: split CXL PXB into separate file
2026-09-28 9:56 ` [PATCH v2 2/2] hw/pci-bridge: split CXL PXB into separate file Daniel P. Berrangé
@ 2026-09-28 10:03 ` Philippe Mathieu-Daudé
0 siblings, 0 replies; 5+ messages in thread
From: Philippe Mathieu-Daudé @ 2026-09-28 10:03 UTC (permalink / raw)
To: Daniel P. Berrangé, qemu-devel
Cc: linux-cxl, Michael S. Tsirkin, qemu-arm, Junjie Cao,
Peter Maydell, Anisa Su, Jonathan Cameron
On 28/9/26 11:56, Daniel P. Berrangé wrote:
> If CONFIG_CXL=n is added to the Kconfig, the build fails to link
> the PXB device:
>
> /usr/bin/ld.bfd: libsystem.a.p/hw_pci-bridge_pci_expander_bridge.c.o: in function `pxb_cxl_realize':
> /home/berrange/src/virt/qemu/build/../hw/pci-bridge/pci_expander_bridge.c:202:(.text+0x330): undefined reference to `cxl_component_register_block_init'
> /usr/bin/ld.bfd: libsystem.a.p/hw_pci-bridge_pci_expander_bridge.c.o: in function `pxb_cxl_dev_reset':
> /home/berrange/src/virt/qemu/build/../hw/pci-bridge/pci_expander_bridge.c:309:(.text+0x768): undefined reference to `cxl_component_register_init_common'
>
> We cannot use CONFIG_CXL in pci_expander_bridge.c because the
> identifier is poisoned. Instead the CXL pieces must be split
> off into a separate source file which can be conditionally
> built.
>
> With this change, the stubs file is no longer required, since
> the code referencing the stub was already protected by CONFIG_CXL.
>
> Fixes: 6e4e3ae936 (hw/cxl/component: Implement host bridge MMIO (8.2.5, table 142))
> Signed-off-by: Daniel P. Berrangé <berrange@redhat.com>
> ---
> hw/cxl/cxl-host.c | 2 +-
> hw/pci-bridge/meson.build | 4 +-
> hw/pci-bridge/pci_expander_bridge.c | 194 +----------------
> hw/pci-bridge/pci_expander_bridge_common.h | 29 +++
> hw/pci-bridge/pci_expander_bridge_cxl.c | 201 ++++++++++++++++++
> hw/pci-bridge/pci_expander_bridge_stubs.c | 14 --
> ...der_bridge.h => pci_expander_bridge_cxl.h} | 0
> 7 files changed, 242 insertions(+), 202 deletions(-)
> create mode 100644 hw/pci-bridge/pci_expander_bridge_common.h
> create mode 100644 hw/pci-bridge/pci_expander_bridge_cxl.c
> delete mode 100644 hw/pci-bridge/pci_expander_bridge_stubs.c
> rename include/hw/pci-bridge/{pci_expander_bridge.h => pci_expander_bridge_cxl.h} (100%)
> diff --git a/hw/pci-bridge/pci_expander_bridge_common.h b/hw/pci-bridge/pci_expander_bridge_common.h
> new file mode 100644
> index 00000000000..fc5d1ac8691
> --- /dev/null
> +++ b/hw/pci-bridge/pci_expander_bridge_common.h
> @@ -0,0 +1,29 @@
> +/*
> + * PCI Expander Bridge Device Emulation Common Code
> + *
> + * Copyright (C) 2015 Red Hat Inc
> + *
> + * Authors:
> + * Marcel Apfelbaum <marcel@redhat.com>
> + *
> + * This work is licensed under the terms of the GNU GPL, version 2 or later.
> + * See the COPYING file in the top-level directory.
> + */
> +
> +enum BusType { PCI, PCIE, CXL };
> +
> +typedef struct PXBBus PXBBus;
> +
> +struct PXBBus {
> + /*< private >*/
> + PCIBus parent_obj;
> + /*< public >*/
We updated our coding style to not use these private/public comments
anymore. I can remove them if MST is OK to merge via hw-misc tree.
Reviewed-by: Philippe Mathieu-Daudé <philmd@oss.qualcomm.com>
> +
> + char bus_path[8];
> +};
^ permalink raw reply [flat|nested] 5+ messages in thread
end of thread, other threads:[~2026-09-28 10:03 UTC | newest]
Thread overview: 5+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2026-09-28 9:56 [PATCH v2 0/2] hw/pci-bridge: fix build with CONFIG_CXL disabled Daniel P. Berrangé
2026-09-28 9:56 ` [PATCH v2 1/2] hw/arm: remove pci-bridge/pci_expander_bridge.h from virt.c Daniel P. Berrangé
2026-09-28 10:01 ` Philippe Mathieu-Daudé
2026-09-28 9:56 ` [PATCH v2 2/2] hw/pci-bridge: split CXL PXB into separate file Daniel P. Berrangé
2026-09-28 10:03 ` Philippe Mathieu-Daudé
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox