Re: [PATCH v2 3/4] hw/riscv/virt, gpex: Provide 32-bit MMIO window for CXL host bridges

Chen Pei <[email protected]>
Newsgroups gmane.comp.emulators.qemu
Message-ID <[email protected]>
Hi Igor,

Thanks for the review.

On Mon, 27 Jul 2026 11:06:15 +0200
Igor Mammedov <[email protected]> wrote:

> I kind of dislike (basically riscv specific hack) in generic code.
> well, correct way to tackle this is
>  1: fix UEFI to perform required initialization.

I agree this is not a clean solution, and I acknowledge the concern
about putting riscv-specific behavior into the shared gpex code.

I did try the "fix UEFI" direction first. With the current EDK2
(edk2-stable202602, the same FdtPciHostBridgeLib/PciBusDxe used by
both aarch64 and riscv virt), I booted a riscv virt machine with
pxb-cxl and dumped the ECAM config space after the firmware finished
enumeration:

  - pxb-cxl (1b36:000b) on bus 0: class 0x0600 (host bridge),
    header type 0, memory/prefetchable window registers all zero;
  - cxl-rp on bus 12: memory window base > limit (empty, reset value);
  - cxl-type3 on bus 13: entire config space reads 0xffffffff,
    i.e. the firmware never enumerated behind the CXL host bridge.

The root cause is that PciBusDxe only recurses into devices for which
IS_PCI_BRIDGE() is true (header layout 1), while pxb-cxl presents
header type 0 and class 0x0600, so the firmware neither assigns it a
secondary bus number nor any MMIO window. FdtPciHostBridgeLib likewise
only consumes the single "pci-host-ecam-generic" node describing PCI0
and has no knowledge of the expander bridge. As a result build_crs()
genuinely returns an empty set on riscv today - this is not a timing
artifact.

> if you have to put a hack into QEMU, make it work with current build_crs()
> and localize 'proper simulated initialization' in riscv codebase
> (i.e. do not spread it to common codebase). But before doing it see (#1 not=
e).

Understood. Since #1 (a UEFI that performs the initialization) is not
available on riscv at the moment, the static window is currently the
only path that makes CXL host bridge _CRS usable here.

For what it is worth, this is consistent with how CXL is being handled
on the ARM side. The sbsa-ref enablement (Yuquan Wang, RFC up to v7,
"hw/arm/sbsa-ref: Support CXL Host Bridge & CFMW" [1], plus the
matching edk2-platforms RFC [2]) deliberately carves out exclusive
static MMIO32/MMIO64 and bus-number ranges for the CXL host bridge and
builds static ACPI tables, explicitly noting that it "doesn't need to
communicate CXL contents via DT to edk2". Jonathan Cameron's arm/virt
approach instead relies on EDK2 performing the enumeration and QEMU
reading the result back via build_crs(), but that depends on a recent
EDK2 with expander-bridge support that we do not have on riscv yet;
his earlier DT-binding RFC for expander bridges [3] also notes that on
the DT path QEMU has to allocate the windows itself.

[1] https://lore.kernel.org/all/[email protected]/
[2] https://op-lists.linaro.org/archives/list/[email protected]/thread/EPPN4R6KLGKYLWPOZUBWJG5HCXAAO3SQ/
[3] https://lore.kernel.org/all/[email protected]/

Given that, my tentative plan for v3 is to keep the static-window
approach for now but address your objection by localizing it: drop the
cxl_mmio32 field and the is_cxl branch from the common gpex code, and
instead simulate the initialization in riscv virt code so that the
existing build_crs() path produces the correct _CRS (i.e. have riscv
pre-populate the bridge window registers / range set the way a
firmware would), keeping the common codebase untouched.

Before I rework it that way, I would appreciate any suggestions you
may have on this approach.

Thanks,
Pei
lmpx.com only provides a reader for public news (NNTP) servers. It is not affiliated with the servers or forums shown here and is not responsible for the content of articles, which is written by their respective authors.