Re: [PATCH AUTOSEL 6.19-5.10] PCI: Enable ACS after configuring IOMMU for OF platforms

Thorsten Leemhuis
2026-03-18T08:30:04Z

On 2/14/26 22:23, Sasha Levin wrote:
> From: Manivannan Sadhasivam <manivannan.sadhasivam@oss.qualcomm.com>
>
> [ Upstream commit c41e2fb67e26b04d919257875fa954aa5f6e392e ]
>
> Platform, ACPI, or IOMMU drivers call pci_request_acs(), which sets
> 'pci_acs_enable' to request that ACS be enabled for any devices enumerated
> in the future.
>
> OF platforms called pci_enable_acs() for the first device before
> of_iommu_configure() called pci_request_acs(), so ACS was never enabled for
> that device (typically a Root Port).
>
> Call pci_enable_acs() later, from pci_dma_configure(), after
> of_dma_configure() has had a chance to call pci_request_acs().

Alan (CCed) reported a regression (see below for details) since 6.12.75
bisected to this change that a revert can fix. The change made it to
v6.18.16, v6.6.128, v6.1.165, v5.15.202, v5.10.252, too. But 6.18.17
works fine for Alan.

Is there maybe something missing in older series that causes this
problem? And if not: should this be reverted

Anyway, here is the report:
https://bugzilla.kernel.org/show_bug.cgi?id=221234

"""
Alan Norbauer 2026-03-15 05:56:05 UTC

Created attachment 309662 [details]
iommu group captures across multiple kernels

OVERVIEW:

I isolated a regression in IOMMU groups to Linux Kernel 6.12.75. I use
GPU passthrough and need my two GPUs to be in IOMMU groups that can be
passed-through. If the GPUs are collapsed into group 0 they can no
longer be passed-through to a VM.

STEPS TO REPRODUCE:

I captured my iommu groups on various kernels using this script:
```
kernel=$(uname -r)
echo "Kernel: $kernel"
echo ""
for g in /sys/kernel/iommu_groups/*/devices/*; do
group=$(echo "$g" | grep -oP 'iommu_groups/\K[0-9]+')
device=$(basename "$g")
desc=$(${pkgs.pciutils}/bin/lspci -nns "$device" 2>/dev/null || echo
"unknown")
echo "Group $group: $device $desc"
done | sort -t' ' -k2 -n
```

If the GPUs are in Group 0 then my VMs break.

RESULTS on Kernel 6.12.74 ✅:

Group 14: 0000:01:00.0 01:00.0 VGA compatible controller [0300]: NVIDIA
Corporation AD107GL [RTX 2000 / 2000E Ada Generation] [10de:28b0] (rev a1)
...
Group 18: 0000:05:00.0 05:00.0 VGA compatible controller [0300]: Intel
Corporation DG2 [Arc A310] [8086:56a6] (rev 05)

RESULTS on Kernel 6.12.75 ❌:

Group 0: 0000:01:00.0 01:00.0 VGA compatible controller [0300]: NVIDIA
Corporation AD107GL [RTX 2000 / 2000E Ada Generation] [10de:28b0] (rev a1)
...
Group 0: 0000:05:00.0 05:00.0 VGA compatible controller [0300]: Intel
Corporation DG2 [Arc A310] [8086:56a6] (rev 05)

I also tested:
Kernel 6.12.75 with the following patch reverted and the issue was fixed
and my groups were correct again:

"PCI: Enable ACS after configuring IOMMU for OF platforms"
https://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git/commit/?id=7a126c1b6cfa2c4b5a7013164451ecddd210110d

I also tested:
kernel 6.12.76 => broken ❌
kernel 6.18.17 => good ✅
kernel 6.19.7 => good ✅

You can find the full script output for all the above kernels in the
attached captures.zip

TEST HARDWARE:

- Motherboard = Supermicro H13SAE-MF
- CPU = AMD EPYC 4545P CPU
- GPU1 = Intel Arc A310
- GPU2 = NVIDIA RTX 2000 Ada
"""

Ciao, Thorsten

> Here's the call path, showing the move of pci_enable_acs() from
> pci_acs_init() to pci_dma_configure(), where it always happens after
> pci_request_acs():
>
> pci_device_add
> pci_init_capabilities
> pci_acs_init
> - pci_enable_acs
> - if (pci_acs_enable) <-- previous test
> - ...
> device_add
> bus_notify(BUS_NOTIFY_ADD_DEVICE)
> iommu_bus_notifier
> iommu_probe_device
> iommu_init_device
> dev->bus->dma_configure
> pci_dma_configure # pci_bus_type.dma_configure
> of_dma_configure
> of_iommu_configure
> pci_request_acs
> pci_acs_enable = 1 <-- set
> + pci_enable_acs
> + if (pci_acs_enable) <-- new test
> + ...
> bus_probe_device
> device_initial_probe
> ...
> really_probe
> dev->bus->dma_configure
> pci_dma_configure # pci_bus_type.dma_configure
> ...
> pci_enable_acs
>
> Note that we will now call pci_enable_acs() twice for every device, first
> from the iommu_probe_device() path and again from the really_probe() path.
> Presumably that's not an issue since we also call dev->bus->dma_configure()
> twice.
>
> For the ACPI platforms, pci_request_acs() is called during ACPI
> initialization time itself, independent of the IOMMU framework.
>
> Signed-off-by: Manivannan Sadhasivam <manivannan.sadhasivam@oss.qualcomm.com>
> [bhelgaas: commit log]
> Signed-off-by: Bjorn Helgaas <bhelgaas@google.com>
> Tested-by: Marek Szyprowski <m.szyprowski@samsung.com>
> Tested-by: Naresh Kamboju <naresh.kamboju@linaro.org>
> Link: https://patch.msgid.link/20260102-pci_acs-v3-1-72280b94d288@oss.qualcomm.com
> Signed-off-by: Sasha Levin <sashal@kernel.org>
> ---
>
> LLM Generated explanations, may be completely bogus:
>
> The commit under review builds on the existing `pci_enable_acs()`
> infrastructure. The key dependency is on `f3c3ccc4fe49d` ("PCI: Fix
> pci_enable_acs() support for the ACS quirks") from v6.12 era, which
> restructured `pci_enable_acs()` and `pci_dev_specific_enable_acs()`. The
> code structure in the diff matches what's in current mainline,
> suggesting this applies to the current code layout which includes the
> ACS refactoring from 6.11/6.12.
>
> ### 6. STABLE KERNEL ASSESSMENT
>
> **Meets stable criteria:**
> - **Fixes a real bug**: ACS not being enabled on the first PCI device on
> OF platforms
> - **Obviously correct**: Simply moves a function call to after its
> dependency is satisfied
> - **Small and contained**: ~30 lines changed across 3 files, all in PCI
> subsystem
> - **No new features**: Just reorders existing functionality
> - **Tested**: Two Tested-by tags
> - **Written by subsystem experts**: PCI maintainer involvement
>
> **Concerns:**
> - The commit depends on the `pci_enable_acs()` refactoring from
> `47c8846a49ba` ("PCI: Extend ACS configurability") and its fix
> `f3c3ccc4fe49d`. These are from v6.11/v6.12 timeframe, so they should
> be in recent stable trees but may not be in older LTS trees (5.15,
> 5.10). The backport would need to be adapted for trees where
> `pci_enable_acs()` has a different structure.
> - For recent stable trees (6.6+, 6.12+) this should apply cleanly or
> with minor adjustments.
>
> ### 7. CONCLUSION
>
> This is a real bug fix for OF/DT platforms where ACS is never enabled on
> the first PCI device (Root Port). This impacts IOMMU isolation, device
> passthrough, and security. The fix is small, surgical, well-understood,
> and tested. It moves an existing function call to the correct point in
> the initialization sequence. The risk is low — the function is
> idempotent and the change doesn't alter any logic, only timing.
>
> The primary concern is dependency on ACS refactoring in newer kernels,
> but for stable trees that have that infrastructure, this is a clear
> backport candidate.
>
> **YES**
>
> drivers/pci/pci-driver.c | 8 ++++++++
> drivers/pci/pci.c | 10 +---------
> drivers/pci/pci.h | 1 +
> 3 files changed, 10 insertions(+), 9 deletions(-)
>
> diff --git a/drivers/pci/pci-driver.c b/drivers/pci/pci-driver.c
> index 7c2d9d5962586..301a9418e38e0 100644
> --- a/drivers/pci/pci-driver.c
> +++ b/drivers/pci/pci-driver.c
> @@ -1650,6 +1650,14 @@ static int pci_dma_configure(struct device *dev)
> ret = acpi_dma_configure(dev, acpi_get_dma_attr(adev));
> }
>
> + /*
> + * Attempt to enable ACS regardless of capability because some Root
> + * Ports (e.g. those quirked with *_intel_pch_acs_*) do not have
> + * the standard ACS capability but still support ACS via those
> + * quirks.
> + */
> + pci_enable_acs(to_pci_dev(dev));
> +
> pci_put_host_bridge_device(bridge);
>
> /* @drv may not be valid when we're called from the IOMMU layer */
> diff --git a/drivers/pci/pci.c b/drivers/pci/pci.c
> index b99ad5f50f30d..479887ece9e7a 100644
> --- a/drivers/pci/pci.c
> +++ b/drivers/pci/pci.c
> @@ -1015,7 +1015,7 @@ static void pci_std_enable_acs(struct pci_dev *dev, struct pci_acs *caps)
> * pci_enable_acs - enable ACS if hardware support it
> * @dev: the PCI device
> */
> -static void pci_enable_acs(struct pci_dev *dev)
> +void pci_enable_acs(struct pci_dev *dev)
> {
> struct pci_acs caps;
> bool enable_acs = false;
> @@ -3648,14 +3648,6 @@ bool pci_acs_path_enabled(struct pci_dev *start,
> void pci_acs_init(struct pci_dev *dev)
> {
> dev->acs_cap = pci_find_ext_capability(dev, PCI_EXT_CAP_ID_ACS);
> -
> - /*
> - * Attempt to enable ACS regardless of capability because some Root
> - * Ports (e.g. those quirked with *_intel_pch_acs_*) do not have
> - * the standard ACS capability but still support ACS via those
> - * quirks.
> - */
> - pci_enable_acs(dev);
> }
>
> /**
> diff --git a/drivers/pci/pci.h b/drivers/pci/pci.h
> index 0e67014aa0013..4592ede0ebcc6 100644
> --- a/drivers/pci/pci.h
> +++ b/drivers/pci/pci.h
> @@ -939,6 +939,7 @@ static inline resource_size_t pci_resource_alignment(struct pci_dev *dev,
> }
>
> void pci_acs_init(struct pci_dev *dev);
> +void pci_enable_acs(struct pci_dev *dev);
> #ifdef CONFIG_PCI_QUIRKS
> int pci_dev_specific_acs_enabled(struct pci_dev *dev, u16 acs_flags);
> int pci_dev_specific_enable_acs(struct pci_dev *dev);