Following up on #6074, where @harkgill-amd narrowed this down to a PCIe atomics
dependency introduced in RCCL with ROCm 7.2.1, and said the open question is whether
to keep atomics as an explicit dependency or remove it.
This report is about where the dependency actually lives, because it turns out not
to be in the code. On RCCL 2.30.4 the failure survives a build with zero
hostcall-calling instructions, which means removing the device-side assert() would
not be sufficient. That seemed worth its own issue rather than a comment.
The part that bears on the keep-or-remove decision
We built RCCL 2.30.4 (ROCm/rocm-systems, projects/rccl) with
add_compile_definitions(NDEBUG), for seven architectures. It still fails, at
hipify/src/enqueue.cc:2118. Static inspection of the linked device image:
| check |
result |
__assert_fail |
0 — NDEBUG did its job |
__ockl_fprintf |
0 — COLLTRACE is gone from 2.30.4 entirely |
__ockl_* of any kind |
0 — no hostcall-calling code remains at all |
hidden_hostcall_buffer in kernel metadata |
3 — one per ncclDevKernel_Generic_{1,2,4} |
So the metadata declaration alone is enough for ROCr to refuse dispatch. Removing
every instruction that could use hostcall does not help while the kernel still
declares the implicit argument.
Bisected to the link step:
device_build/common.o (before device link) hostcall = 0
device_build/gfx1100/device.elf (after device link) hostcall = 3
2.30.4 replaced the ordinary HIP fat-binary path with its own device linker
(tools/rccl-device-compile --link, which also hand-patches SGPR/VGPR fields in the
kernel descriptor). That tool contains no hostcall or hidden_ strings, so the
declaration appears to be emitted during the dispatcher link, conservatively, for
kernels that demonstrably never call hostcall. Ruled out with trivial-kernel probes
(all give hostcall = 0): plain whole-program compile, -fgpu-rdc,
-mcode-object-version=4, and -fgpu-rdc + COv4. So it is neither RDC as such nor
the code-object version.
If the decision is to drop the dependency, the device-link step looks like the place
it has to be dropped. One workaround we have not tried: strip the implicit-argument
entry from the kernel metadata after linking, since RCCL's own tool already rewrites
that region.
What works today, for anyone arriving here from a search engine
If the cards are passed through to a QEMU/KVM guest, check the passthrough form
before rebuilding anything. Passing the GPU as a single function rather than
alongside its audio function gives the guest AtomicOp completer support, and with
atomics present stock RCCL needs no patch at all, 2.30.4 included. Measured here on
2026-08-23, one line of VM configuration and nothing else changed:
https://github.com/cadamcat/dual-radeon-vllm/blob/main/docs/vfio-atomics.md
Where atomics cannot be had, RCCL 2.27.7 rebuilt with NDEBUG does remove the
declaration, and multi-GPU works: gemma-4-31B at 43.2 tok/s under vLLM TP=2 on
2× RX 7900 XT, both GPUs at 265 W synchronised. 2.30.4 is not fixable this way, so
2.27.7 is the only rebuild route we have verified. Build script, deployment steps and
prebuilt libraries: https://github.com/cadamcat/dual-radeon-vllm
A reproducer that needs no RCCL
Useful for triage, and for telling this failure apart from the several other things
that produce the same message. 30 lines of HIP, one GPU is enough. Two kernels with
identical launch shape; the only difference is that the second needs a hostcall
because it calls printf:
devices=2
--- dev0 ---
[plain ] launch:no error sync:no error
[hostcall ] launch:the operation cannot be performed in the present state sync:the operation cannot be performed in the present state
--- dev1 ---
[plain ] launch:no error sync:no error
[hostcall ] launch:the operation cannot be performed in the present state sync:the operation cannot be performed in the present state
Source: diagnose/hipgate3.cpp in the repository above. Driver-level confirmation
with AMD_LOG_LEVEL=4, at the moment RCCL fails:
ncclDevKernel_Generic
rocvirtual.cpp:4208 Pcie atomics not enabled, hostcall not supported
rocvirtual.cpp:4636 AQL dispatch failed!
-> hipErrorIllegalState
Telling affected machines apart from unaffected ones
This may be why the failure has been awkward to reproduce on request: whether a
machine shows it is decided entirely by the root port, not by the GPU, the slot width
or the RCCL build. One command, no ROCm needed:
dmesg | grep "PCIE atomic"
# affected: amdgpu 0000:01:00.0: PCIE atomic ops is not supported
# not affected: no output
Grep the exact phrase; a bare grep -i atomic also matches unrelated
DMA: preallocated ... pool for atomic allocations lines from early boot.
On the machine in this report:
[ 9.044936] amdgpu 0000:01:00.0: PCIE atomic ops is not supported
[ 9.568264] amdgpu 0000:02:00.0: PCIE atomic ops is not supported
0000:00:1c.0: AtomicOpsCap: Routing- 32bit- 64bit- 128bitCAS-
The 32bit- 64bit- on that root port is the upstream cause of the amdgpu line. pci_enable_atomic_ops_to_root() requires 32- and 64-bit AtomicOp completer support on the root port above the device, and AtomicOp routing only on the switch ports in between; a root port's own Routing bit describes peer-to-peer between root ports and is not part of the test. Whether QEMU's emulated root port advertises completer support depends on how the device below it is passed, not on the host CPU. vfio_pci_enable_rp_atomics() in hw/vfio/pci.c sets it up automatically and has since v8.1.0, and gives up on pdev->devfn or QEMU_PCI_CAP_MULTIFUNCTION among other conditions. Proxmox's default hostpciX: 0000:0b:00 form hands the GPU over together with its audio function and takes that branch, which is what produced the 32bit- 64bit- above; passing the same card as 0000:0b:00.0 gives the guest 32bit+ 64bit+ and the GPU AtomicOpsCtl: ReqEn+, measured here on 2026-08-23 with nothing else changed. So a passthrough Instinct is affected when it is passed multifunction and not when it is passed as a single function -- a configuration rather than a property of virtualisation. The bare-metal reports in #6074 and vllm-project/vllm#38587 are single-NUMA desktops (7800X3D and 13900K) with 2× 7900 XTX.
Edited twice. This paragraph first said Routing- on the root port was the cause, which is the wrong capability bit (correction and evidence). It then said every QEMU root port declines completer support regardless of what sits behind it, and drew from that the claim that this reaches any VFIO passthrough guest including virtualised Instinct. That is wrong for a single-function passthrough, and the A/B is one line of VM configuration: vfio-atomics.md. The severity claim is narrowed accordingly rather than withdrawn, since the multifunction form is the Proxmox default.
Two conclusions of ours that were wrong
Recorded because they cost us several days and may be costing others the same.
- "It is an RCCL regression between 2.27.7-b38 and -b43." Plausible, since a
downgrade does fix it, but building b38 from source on the newer runtime fails the
same way. The version correlation is real, the causation is not.
- "ROCm ≥ 7.13's HIP runtime gates kernel submission in VFIO guests." Disproved by
a minimal probe: hipExtLaunchKernel with a completion event, 4 KB kernargs and
cross-stream waits all pass on the same runtime. Submission is fine; only
hostcall-carrying kernels are refused.
13 hypotheses were tested and 12 eliminated (kernel version, iommu=pt, event flags,
memory, NUMA, SDMA, P2P, cuMem, shared-memory size, transport layer, and others).
The matrix is in docs/root-cause.md in the repository.
Two smaller asks
- On 2.27.7, we did not test
COLLTRACE=OFF on its own, which is the supported knob
rather than a patch; NDEBUG happens to remove both sources at once. If disabling
COLLTRACE alone is sufficient there, that is the cleaner answer and we would be glad
to hear it.
hipErrorIllegalState at enqueue.cc sends people hunting through RCCL versions and
environment variables for days. A message along the lines of "hostcall unavailable:
PCIe atomics disabled" would end that search immediately, whatever is decided about
the dependency itself.
Environment
- 2× Radeon RX 7900 XT (gfx1100), cross-die, PCIe 3.0, no P2P
- Host: Threadripper 1950X / X399; Proxmox VE + QEMU 11.0.2, VFIO passthrough
- ROCm 7.14, PyTorch 2.11, vLLM 0.23. Also reproduced on ROCm 7.13 and 7.0.0
- Last working combination before the rebuild: the ROCm 7.0.0 image, whose RCCL 2.26.6
device kernels predate the hostcall dependency
Following up on #6074, where @harkgill-amd narrowed this down to a PCIe atomics
dependency introduced in RCCL with ROCm 7.2.1, and said the open question is whether
to keep atomics as an explicit dependency or remove it.
This report is about where the dependency actually lives, because it turns out not
to be in the code. On RCCL 2.30.4 the failure survives a build with zero
hostcall-calling instructions, which means removing the device-side
assert()wouldnot be sufficient. That seemed worth its own issue rather than a comment.
The part that bears on the keep-or-remove decision
We built RCCL 2.30.4 (
ROCm/rocm-systems,projects/rccl) withadd_compile_definitions(NDEBUG), for seven architectures. It still fails, athipify/src/enqueue.cc:2118. Static inspection of the linked device image:__assert_fail__ockl_fprintf__ockl_*of any kindhidden_hostcall_bufferin kernel metadatancclDevKernel_Generic_{1,2,4}So the metadata declaration alone is enough for ROCr to refuse dispatch. Removing
every instruction that could use hostcall does not help while the kernel still
declares the implicit argument.
Bisected to the link step:
2.30.4 replaced the ordinary HIP fat-binary path with its own device linker
(
tools/rccl-device-compile --link, which also hand-patches SGPR/VGPR fields in thekernel descriptor). That tool contains no
hostcallorhidden_strings, so thedeclaration appears to be emitted during the dispatcher link, conservatively, for
kernels that demonstrably never call hostcall. Ruled out with trivial-kernel probes
(all give hostcall = 0): plain whole-program compile,
-fgpu-rdc,-mcode-object-version=4, and-fgpu-rdc+ COv4. So it is neither RDC as such northe code-object version.
If the decision is to drop the dependency, the device-link step looks like the place
it has to be dropped. One workaround we have not tried: strip the implicit-argument
entry from the kernel metadata after linking, since RCCL's own tool already rewrites
that region.
What works today, for anyone arriving here from a search engine
If the cards are passed through to a QEMU/KVM guest, check the passthrough form
before rebuilding anything. Passing the GPU as a single function rather than
alongside its audio function gives the guest AtomicOp completer support, and with
atomics present stock RCCL needs no patch at all, 2.30.4 included. Measured here on
2026-08-23, one line of VM configuration and nothing else changed:
https://github.com/cadamcat/dual-radeon-vllm/blob/main/docs/vfio-atomics.md
Where atomics cannot be had, RCCL 2.27.7 rebuilt with
NDEBUGdoes remove thedeclaration, and multi-GPU works: gemma-4-31B at 43.2 tok/s under vLLM TP=2 on
2× RX 7900 XT, both GPUs at 265 W synchronised. 2.30.4 is not fixable this way, so
2.27.7 is the only rebuild route we have verified. Build script, deployment steps and
prebuilt libraries: https://github.com/cadamcat/dual-radeon-vllm
A reproducer that needs no RCCL
Useful for triage, and for telling this failure apart from the several other things
that produce the same message. 30 lines of HIP, one GPU is enough. Two kernels with
identical launch shape; the only difference is that the second needs a hostcall
because it calls
printf:Source:
diagnose/hipgate3.cppin the repository above. Driver-level confirmationwith
AMD_LOG_LEVEL=4, at the moment RCCL fails:Telling affected machines apart from unaffected ones
This may be why the failure has been awkward to reproduce on request: whether a
machine shows it is decided entirely by the root port, not by the GPU, the slot width
or the RCCL build. One command, no ROCm needed:
Grep the exact phrase; a bare
grep -i atomicalso matches unrelatedDMA: preallocated ... pool for atomic allocationslines from early boot.On the machine in this report:
The
32bit- 64bit-on that root port is the upstream cause of the amdgpu line.pci_enable_atomic_ops_to_root()requires 32- and 64-bit AtomicOp completer support on the root port above the device, and AtomicOp routing only on the switch ports in between; a root port's ownRoutingbit describes peer-to-peer between root ports and is not part of the test. Whether QEMU's emulated root port advertises completer support depends on how the device below it is passed, not on the host CPU.vfio_pci_enable_rp_atomics()inhw/vfio/pci.csets it up automatically and has since v8.1.0, and gives up onpdev->devfnorQEMU_PCI_CAP_MULTIFUNCTIONamong other conditions. Proxmox's defaulthostpciX: 0000:0b:00form hands the GPU over together with its audio function and takes that branch, which is what produced the32bit- 64bit-above; passing the same card as0000:0b:00.0gives the guest32bit+ 64bit+and the GPUAtomicOpsCtl: ReqEn+, measured here on 2026-08-23 with nothing else changed. So a passthrough Instinct is affected when it is passed multifunction and not when it is passed as a single function -- a configuration rather than a property of virtualisation. The bare-metal reports in #6074 and vllm-project/vllm#38587 are single-NUMA desktops (7800X3D and 13900K) with 2× 7900 XTX.Edited twice. This paragraph first said
Routing-on the root port was the cause, which is the wrong capability bit (correction and evidence). It then said every QEMU root port declines completer support regardless of what sits behind it, and drew from that the claim that this reaches any VFIO passthrough guest including virtualised Instinct. That is wrong for a single-function passthrough, and the A/B is one line of VM configuration: vfio-atomics.md. The severity claim is narrowed accordingly rather than withdrawn, since the multifunction form is the Proxmox default.Two conclusions of ours that were wrong
Recorded because they cost us several days and may be costing others the same.
downgrade does fix it, but building b38 from source on the newer runtime fails the
same way. The version correlation is real, the causation is not.
a minimal probe:
hipExtLaunchKernelwith a completion event, 4 KB kernargs andcross-stream waits all pass on the same runtime. Submission is fine; only
hostcall-carrying kernels are refused.
13 hypotheses were tested and 12 eliminated (kernel version,
iommu=pt, event flags,memory, NUMA, SDMA, P2P,
cuMem, shared-memory size, transport layer, and others).The matrix is in
docs/root-cause.mdin the repository.Two smaller asks
COLLTRACE=OFFon its own, which is the supported knobrather than a patch;
NDEBUGhappens to remove both sources at once. If disablingCOLLTRACE alone is sufficient there, that is the cleaner answer and we would be glad
to hear it.
hipErrorIllegalStateatenqueue.ccsends people hunting through RCCL versions andenvironment variables for days. A message along the lines of "hostcall unavailable:
PCIe atomics disabled" would end that search immediately, whatever is decided about
the dependency itself.
Environment
device kernels predate the hostcall dependency