hw/i386/pc.c | 17 ++++++++++------- 1 file changed, 10 insertions(+), 7 deletions(-)
This is a backport of the fix from commit 8b1c560937467d0d9 to the QEMU
10.0.x LTS series.
When using a CXL Type 3 device together with a virtio 9p device in QEMU on a
physical server, the 9p device fails to initialize properly. The kernel reports
the following error:
virtio: device uses modern interface but does not have VIRTIO_F_VERSION_1
9pnet_virtio virtio0: probe with driver 9pnet_virtio failed with error -22
Further investigation revealed that the 64-bit BAR space assigned to the 9pnet
device was overlapped by the memory window allocated for the CXL devices. As a
result, the kernel could not correctly access the BAR region, causing the
virtio device to malfunction.
An excerpt from /proc/iomem shows:
480010000-cffffffff : CXL Window 0
480010000-4bfffffff : PCI Bus 0000:00
4c0000000-4c01fffff : PCI Bus 0000:0c
4c0000000-4c01fffff : PCI Bus 0000:0d
4c0200000-cffffffff : PCI Bus 0000:00
4c0200000-4c0203fff : 0000:00:03.0
4c0200000-4c0203fff : virtio-pci-modern
To address this issue, this patch adds the reserved memory end calculation
for cxl devices to reserve sufficient address space and ensure that CXL memory
windows are allocated beyond all PCI 64-bit BARs. This prevents overlap with
64-bit BARs regions such as those used by virtio or other pcie devices,
resolving the conflict.
Tested on intel Granite Rapids(GNR) servers using QEMU 10.0 LTS,
resolving the issue without causing regressions.
QEMU Build Configuration:
./configure --prefix=/home/work/qemu_master/build/ \
--target-list=x86_64-softmmu \
--enable-kvm \
--enable-virtfs
QEMU Boot Command:
sudo /home/work/qemu_master/qemu/build/qemu-system-x86_64 \
-nographic -machine q35,cxl=on -enable-kvm -m 16G -smp 8 \
-hda /home/work/gp_qemu/rootfs.img \
-virtfs local,path=/home/work/gp_qemu/share,mount_tag=host0,security_model=passthrough,id=host0 \
-kernel /home/work/linux_output/arch/x86/boot/bzImage \
--append "console=ttyS0 crashkernel=256M root=/dev/sda rootfstype=ext4 rw loglevel=8" \
-device pci-testdev,membar=2G \
-object memory-backend-ram,id=vmem0,share=on,size=4096M \
-device pxb-cxl,bus_nr=12,bus=pcie.0,id=cxl.1 \
-device cxl-rp,port=0,bus=cxl.1,id=root_port13,chassis=0,slot=2 \
-device cxl-type3,bus=root_port13,volatile-memdev=vmem0,id=cxl-vmem0,sn=0x123456789 \
-M cxl-fmw.0.targets.0=cxl.1,cxl-fmw.0.size=4G
Fixes: 03b39fcf64bc ("hw/cxl: Make the CXL fixed memory window setup a machine parameter")
Signed-off-by: peng guo <engguopeng@buaa.edu.cn>
Tested-by: peng guo <engguopeng@buaa.edu.cn>
Reviewed-by: Michael S. Tsirkin <mst@redhat.com>
Message-ID: <20250805142300.15226-1-engguopeng@buaa.edu.cn>
Signed-off-by: Michael S. Tsirkin <mst@redhat.com>
(cherry picked from commit d1193481dee63442fc41e47ca6ebc4cd34f1f69c)
---
hw/i386/pc.c | 17 ++++++++++-------
1 file changed, 10 insertions(+), 7 deletions(-)
diff --git a/hw/i386/pc.c b/hw/i386/pc.c
index 01d0581f62a3..502cf8a47dfb 100644
--- a/hw/i386/pc.c
+++ b/hw/i386/pc.c
@@ -840,6 +840,7 @@ void pc_memory_init(PCMachineState *pcms,
hwaddr maxphysaddr, maxusedaddr;
hwaddr cxl_base, cxl_resv_end = 0;
X86CPU *cpu = X86_CPU(first_cpu);
+ uint64_t res_mem_end;
assert(machine->ram_size == x86ms->below_4g_mem_size +
x86ms->above_4g_mem_size);
@@ -993,17 +994,19 @@ void pc_memory_init(PCMachineState *pcms,
rom_set_fw(fw_cfg);
- if (machine->device_memory) {
- uint64_t *val = g_malloc(sizeof(*val));
- uint64_t res_mem_end = machine->device_memory->base;
-
+ if (pcms->cxl_devices_state.is_enabled) {
+ res_mem_end = cxl_resv_end;
+ } else if (machine->device_memory) {
+ res_mem_end = machine->device_memory->base;
if (!pcmc->broken_reserved_end) {
res_mem_end += memory_region_size(&machine->device_memory->mr);
}
+ } else {
+ res_mem_end = 0;
+ }
- if (pcms->cxl_devices_state.is_enabled) {
- res_mem_end = cxl_resv_end;
- }
+ if (res_mem_end) {
+ uint64_t *val = g_malloc(sizeof(*val));
*val = cpu_to_le64(ROUND_UP(res_mem_end, 1 * GiB));
fw_cfg_add_file(fw_cfg, "etc/reserved-memory-end", val, sizeof(*val));
}
--
2.43.0
On 11/4/25 16:02, peng guo via wrote:
> This is a backport of the fix from commit 8b1c560937467d0d9 to the QEMU
> 10.0.x LTS series.
>
> When using a CXL Type 3 device together with a virtio 9p device in QEMU on a
> physical server, the 9p device fails to initialize properly. The kernel reports
> the following error:
>
> virtio: device uses modern interface but does not have VIRTIO_F_VERSION_1
> 9pnet_virtio virtio0: probe with driver 9pnet_virtio failed with error -22
>
> Further investigation revealed that the 64-bit BAR space assigned to the 9pnet
> device was overlapped by the memory window allocated for the CXL devices. As a
> result, the kernel could not correctly access the BAR region, causing the
> virtio device to malfunction.
>
> An excerpt from /proc/iomem shows:
>
> 480010000-cffffffff : CXL Window 0
> 480010000-4bfffffff : PCI Bus 0000:00
> 4c0000000-4c01fffff : PCI Bus 0000:0c
> 4c0000000-4c01fffff : PCI Bus 0000:0d
> 4c0200000-cffffffff : PCI Bus 0000:00
> 4c0200000-4c0203fff : 0000:00:03.0
> 4c0200000-4c0203fff : virtio-pci-modern
>
> To address this issue, this patch adds the reserved memory end calculation
> for cxl devices to reserve sufficient address space and ensure that CXL memory
> windows are allocated beyond all PCI 64-bit BARs. This prevents overlap with
> 64-bit BARs regions such as those used by virtio or other pcie devices,
> resolving the conflict.
>
> Tested on intel Granite Rapids(GNR) servers using QEMU 10.0 LTS,
> resolving the issue without causing regressions.
>
> QEMU Build Configuration:
>
> ./configure --prefix=/home/work/qemu_master/build/ \
> --target-list=x86_64-softmmu \
> --enable-kvm \
> --enable-virtfs
>
> QEMU Boot Command:
>
> sudo /home/work/qemu_master/qemu/build/qemu-system-x86_64 \
> -nographic -machine q35,cxl=on -enable-kvm -m 16G -smp 8 \
> -hda /home/work/gp_qemu/rootfs.img \
> -virtfs local,path=/home/work/gp_qemu/share,mount_tag=host0,security_model=passthrough,id=host0 \
> -kernel /home/work/linux_output/arch/x86/boot/bzImage \
> --append "console=ttyS0 crashkernel=256M root=/dev/sda rootfstype=ext4 rw loglevel=8" \
> -device pci-testdev,membar=2G \
> -object memory-backend-ram,id=vmem0,share=on,size=4096M \
> -device pxb-cxl,bus_nr=12,bus=pcie.0,id=cxl.1 \
> -device cxl-rp,port=0,bus=cxl.1,id=root_port13,chassis=0,slot=2 \
> -device cxl-type3,bus=root_port13,volatile-memdev=vmem0,id=cxl-vmem0,sn=0x123456789 \
> -M cxl-fmw.0.targets.0=cxl.1,cxl-fmw.0.size=4G
>
> Fixes: 03b39fcf64bc ("hw/cxl: Make the CXL fixed memory window setup a machine parameter")
> Signed-off-by: peng guo <engguopeng@buaa.edu.cn>
> Tested-by: peng guo <engguopeng@buaa.edu.cn>
> Reviewed-by: Michael S. Tsirkin <mst@redhat.com>
> Message-ID: <20250805142300.15226-1-engguopeng@buaa.edu.cn>
> Signed-off-by: Michael S. Tsirkin <mst@redhat.com>
> (cherry picked from commit d1193481dee63442fc41e47ca6ebc4cd34f1f69c)
Yes. This looks very much sane.
Thank you very much for providing this backport for 10.0.x
I've added this text to the commit message:
(backport for missing-in-10.0.x v10.0.0-1264-g8b1c56093746
"hw/i386/pc: Remove PCMachineClass::broken_reserved_end field"
by peng quo)
for reference.
And.. there was no rush :)
/mjt
> ---
> hw/i386/pc.c | 17 ++++++++++-------
> 1 file changed, 10 insertions(+), 7 deletions(-)
>
> diff --git a/hw/i386/pc.c b/hw/i386/pc.c
> index 01d0581f62a3..502cf8a47dfb 100644
> --- a/hw/i386/pc.c
> +++ b/hw/i386/pc.c
> @@ -840,6 +840,7 @@ void pc_memory_init(PCMachineState *pcms,
> hwaddr maxphysaddr, maxusedaddr;
> hwaddr cxl_base, cxl_resv_end = 0;
> X86CPU *cpu = X86_CPU(first_cpu);
> + uint64_t res_mem_end;
>
> assert(machine->ram_size == x86ms->below_4g_mem_size +
> x86ms->above_4g_mem_size);
> @@ -993,17 +994,19 @@ void pc_memory_init(PCMachineState *pcms,
>
> rom_set_fw(fw_cfg);
>
> - if (machine->device_memory) {
> - uint64_t *val = g_malloc(sizeof(*val));
> - uint64_t res_mem_end = machine->device_memory->base;
> -
> + if (pcms->cxl_devices_state.is_enabled) {
> + res_mem_end = cxl_resv_end;
> + } else if (machine->device_memory) {
> + res_mem_end = machine->device_memory->base;
> if (!pcmc->broken_reserved_end) {
> res_mem_end += memory_region_size(&machine->device_memory->mr);
> }
> + } else {
> + res_mem_end = 0;
> + }
>
> - if (pcms->cxl_devices_state.is_enabled) {
> - res_mem_end = cxl_resv_end;
> - }
> + if (res_mem_end) {
> + uint64_t *val = g_malloc(sizeof(*val));
> *val = cpu_to_le64(ROUND_UP(res_mem_end, 1 * GiB));
> fw_cfg_add_file(fw_cfg, "etc/reserved-memory-end", val, sizeof(*val));
> }
© 2016 - 2025 Red Hat, Inc.