On 9/16/26 20:44, [email protected] wrote:
From: Manish Honap <[email protected]>
Only the guest's endpoint HDM decoder is programmed by the guest; the
decoders above it are covered only while the pxb-cxl host bridge stays in
passthrough mode. Reject a switch in the path, or a host bridge taken out
of passthrough, at realize before any mapping exists.
AI-used-for: code (prototype)
Signed-off-by: Manish Honap <[email protected]>
---
hw/vfio/pci.c | 73 +++++++++++++++++++++++++++++++++++++++++++++++++++
1 file changed, 73 insertions(+)
diff --git a/hw/vfio/pci.c b/hw/vfio/pci.c
index 2f84af5cf8..10b13f200d 100644
--- a/hw/vfio/pci.c
+++ b/hw/vfio/pci.c
@@ -27,6 +27,7 @@
#include "hw/pci/msi.h"
#include "hw/pci/msix.h"
#include "hw/pci/pci_bridge.h"
+#include "hw/cxl/cxl.h"
#include "hw/core/qdev-properties.h"
#include "hw/core/qdev-properties-system.h"
#include "hw/vfio/vfio-cpr.h"
@@ -3570,6 +3571,73 @@ bool vfio_pci_interrupt_setup(VFIOPCIDevice *vdev, Error
**errp)
return true;
}
+/*
+ * Walk the endpoint's ancestor bridges up to its pxb-cxl host bridge. A CXL
+ * switch in the path is rejected: the guest would then have to program switch
+ * decoders, which the passthrough model does not yet cover. This is the single
+ * place the supported-topology assumption lives, so switch support later
+ * relaxes it here.
+ */
+static PXBCXLDev *vfio_cxl_find_pxb(VFIOPCIDevice *vdev, Error **errp)
+{
+ PCIBus *bus = pci_get_bus(&vdev->parent_obj);
Could this routine be moved to the CXL subsytem component ?
+
+ if (!object_dynamic_cast(OBJECT(bus), TYPE_CXL_BUS)) {
+ error_setg(errp,
+ "vfio-cxl: %s: endpoint is not on a CXL root port (cxl-rp)",
+ vdev->vbasedev.name);
+ return NULL;
+ }
+
+ for (; bus; ) {
Why walk, since this is looking for the case "no-switch in between the
bus and the ep" ? the no-switch case is just two hops in the topology.
+ PCIDevice *bridge = bus->parent_dev;
+
+ if (!bridge) {
+ break;
+ }
+ if (object_dynamic_cast(OBJECT(bridge), TYPE_CXL_USP) ||
+ object_dynamic_cast(OBJECT(bridge), TYPE_CXL_DSP)) {
+ error_setg(errp,
+ "vfio-cxl: %s: switch-attached topology not supported",
+ vdev->vbasedev.name);
+ return NULL;
+ }
+ if (object_dynamic_cast(OBJECT(bridge), TYPE_PXB_CXL_DEV)) {
+ return PXB_CXL_DEV(bridge);
+ }
+ if (pci_bus_is_root(bus)) {
+ break;
+ }
+ bus = pci_get_bus(bridge);
+ }
+
+ error_setg(errp, "vfio-cxl: %s: not attached below a pxb-cxl host bridge",
+ vdev->vbasedev.name);
+ return NULL;
+}
+
+/*
+ * Only guest's endpoint decoder is programmed, so the host bridge must stay in
+ * HDM passthrough mode. Reject anything else at realize, before a mapping is
+ * built. cxl_get_hb_passthrough() reflects reset state and is not
+ * settled yet here, so gate on the static hdm_for_passthrough property.
+ */
+static bool vfio_cxl_check_topology(VFIOPCIDevice *vdev, Error **errp)
+{
+ PXBCXLDev *pxb = vfio_cxl_find_pxb(vdev, errp);
+
+ if (!pxb) {
+ return false;
+ }
+ if (pxb->hdm_for_passthrough) {
This naming is a bit confusing:
hdm_for_passthrough=false means "use HDM passthrough mode" (no decoders),
while
hdm_for_passthrough=true means "keep HDM decoders even in passthrough
topology.
I will get used to it.
Thanks,
C.
+ error_setg(errp,
+ "vfio-cxl: %s: the pxb-cxl must be in HDM passthrough mode "
+ "(do not set hdm_for_passthrough)", vdev->vbasedev.name);
+ return false;
+ }
+ return true;
+}
+
/*
* Learn the CXL geometry the kernel reports: the HPA-backed HDM memory region
* and the trapped HDM decoder block (which BAR carries it and at what
offset).
@@ -3623,6 +3691,11 @@ static bool vfio_cxl_setup(VFIOPCIDevice *vdev, Error
**errp)
cxl->dpa_size = mem_info->size;
cxl->comp_bar = cap->bar;
cxl->hdm_offset = cap->offset;
+
+ if (!vfio_cxl_check_topology(vdev, errp)) {
+ return false;
+ }
+
cxl->enabled = true;
return true;