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

Junjie Cao <[email protected]>
Newsgroups org.nongnu.qemu-riscv,org.kernel.vger.linux-cxl,org.nongnu.qemu-devel
Message-ID <[email protected]>
Hi Chen Pei,

On Fri, 21 Aug 2026 16:19:53 +0800, Chen Pei wrote:
> - The CXL host bridge _CRS is produced by the generic build_crs()
>   path.  EDK2's PciBusDxe only recurses into PCI-to-PCI bridges, while
>   the pxb-cxl expander bridge presents as a class 0x0600 host bridge
>   with a type-0 header, so firmware never enumerates behind it and
>   leaves the CXL root port's window and bus-number registers unset;
>   build_crs() would therefore return an empty _CRS.  Simulate the

I see the same empty _CRS you traced for Igor on v2, but the cause
sits one level up: riscv virt never tells the firmware that the
expander bus is there.

etc/extra-pci-roots is how the other machines advertise expander root
buses. hw/arm/virt.c, hw/i386/pc.c and hw/hppa/machine.c all call
pci_bus_add_fw_cfg_extra_pci_roots(); arm got it in 09fad16744 as
part of the pxb enablement there. hw/riscv/virt.c has no such call,
and since PXB is default y only for Q35 and ARM_VIRT, this series is
what first brings pxb to riscv at all -- so nothing has needed that
fw_cfg entry until now.

Same binary, in-tree edk2-riscv, only difference on the command line
being -fw_cfg name=etc/extra-pci-roots,file=<le64 1>:

  PciHostBridgeUtilityGetRootBridgesBusScan: 1 extra root buses ...
  PciHostBridgeUtilityInitRootBridge: populated root bus 12, ...
  PciBus: Resource Map for Bridge [0C|00|00]
  Type =  Mem32; Base = 0x40400000; Length = 0x200000; ...
     Base = 0x40400000; Length = 0x10000; ... Owner = PCI [0D|00|00:10]

so PciBusDxe does go behind the pxb-cxl once it knows the root bus
exists, and it assigns the root port window and the Type3 BARs itself.

With this patch dropped and pci_bus_add_fw_cfg_extra_pci_roots()
called from virt_machine_done() instead, next to
cxl_fmws_link_targets(), the regenerated DSDT has PC0C as

    DWordMemory (ResourceProducer, ...)
        0x40400000,         // Range Minimum
        0x405FFFFF,         // Range Maximum
    QWordMemory (ResourceProducer, ...)
        0x0000000400100000, // Range Minimum
        0x000000040010FFFF, // Range Maximum
    WordBusNumber (...)
        0x000C,             // Range Minimum
        0x000D,             // Range Maximum

with PCI0 keeping the rest of the 32-bit aperture
(0x40000000-0x403FFFFF and 0x40600000-0x7FFFFFFF). Firmware
partitions the aperture itself, sizes the window to what is actually
behind the bridge, and the 64-bit window comes along too. With a
second pxb-cxl added (bus_nr 12 and 200), the two bridges get
0x40400000-0x405FFFFF and 0x40600000-0x407FFFFF, so the
single-bridge limitation in the TODO would not arise either.

I have only looked at firmware enumeration and the generated tables
here, not at a booting CXL guest, so your RVA22 run may well turn up
something this misses. But if it holds, it drops the 256 MiB carve-out,
virt_cxl_init_bridge_windows() and the reset handler, and it is the
"fix UEFI to perform required initialization" option Igor raised on
v2, with the UEFI side already in place.

Many thanks,
Junjie
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.