From: Bjorn Helgaas <helgaas@kernel.org>
To: Danny Gonzalez <digonzal@google.com>
Cc: Bjorn Helgaas <bhelgaas@google.com>,
David Decotigny <decot@google.com>,
Sheena Mohan <sheenamo@google.com>,
linux-pci@vger.kernel.org, linux-kernel@vger.kernel.org,
Pranjal Shrivastava <praan@google.com>,
Joerg Roedel <joerg.roedel@amd.com>,
Nicolin Chen <nicolinc@nvidia.com>,
Jason Gunthorpe <jgg@nvidia.com>,
Lu Baolu <baolu.lu@linux.intel.com>,
Kevin Tian <kevin.tian@intel.com>
Subject: Re: [PATCH v2] PCI/ATS: Disable ATS when ACS TB is set upstream
Date: Tue, 3 Nov 2026 12:16:16 -0600 [thread overview]
Message-ID: <20261103181616.GA1080116@bhelgaas> (raw)
In-Reply-To: <20261028233651.960835-1-digonzal@google.com>
[+cc other folks interested in ATS]
On Wed, Oct 28, 2026 at 11:36:51PM +0000, Danny Gonzalez wrote:
> Enabling ATS allows an endpoint to cache translations and initiate DMA
> requests with Translated addresses, which an upstream bridge with ACS
> Translation Blocking (PCI_ACS_TB) set will block as ACS Violations.
> Because pci_enable_acs() preserves existing PCI_ACS_CTRL bits (e.g., from
> firmware, a kexec kernel, or "pci=config_acs=") without relaxing them,
> PCI_ACS_TB may remain set on upstream bridges.
>
> Add pci_ats_check_acs() and call it from pci_dma_configure() after
> pci_enable_acs() to walk upstream bridges and clear dev->ats_cap if any
> bridge has PCI_ACS_TB enabled, leaving the endpoint to use Untranslated
> addresses.
> Tested by booting a machine with an endpoint advertising the ATS Capability
> behind a Root Port with PCI_ACS_TB set; verified ATS is disabled and the
> system boots cleanly.
>
> Signed-off-by: Danny Gonzalez <digonzal@google.com>
> ---
>
> v2 (based on sashiko review):
> - Move the upstream ACS TB check from pci_ats_supported() into
> pci_ats_check_acs() called after pci_enable_acs()
> - Use pci_acs_enabled() instead of reading PCI_ACS_CTRL directly
>
> drivers/pci/ats.c | 20 ++++++++++++++++++++
> drivers/pci/pci-driver.c | 1 +
> drivers/pci/pci.h | 2 ++
> 3 files changed, 23 insertions(+)
>
> diff --git a/drivers/pci/ats.c b/drivers/pci/ats.c
> index 9cb23780093d..0395612f3987 100644
> --- a/drivers/pci/ats.c
> +++ b/drivers/pci/ats.c
> @@ -31,6 +31,26 @@ void pci_ats_init(struct pci_dev *dev)
> dev->ats_cap = pos;
> }
>
> +void pci_ats_check_acs(struct pci_dev *dev)
> +{
> + struct pci_dev *bridge;
> +
> + if (!dev->ats_cap || dev->is_virtfn || dev->ats_stu)
> + return;
> +
> + /* Do not allow ATS if any upstream bridge blocks translation */
> + for (bridge = pci_upstream_bridge(dev); bridge;
> + bridge = pci_upstream_bridge(bridge)) {
> + if ((bridge->acs_capabilities & PCI_ACS_TB) &&
> + pci_acs_enabled(bridge, PCI_ACS_TB)) {
> + pci_warn_once(dev, "ATS disabled: upstream bridge %s has ACS Translation Blocking enabled\n",
> + pci_name(bridge));
> + dev->ats_cap = 0;
> + return;
> + }
> + }
This works by making pci_ats_supported() return "false". Can we do
this checking inside pci_ats_supported() instead? Then we wouldn't
need a new function, and I think it would be easier to understand the
control flow that way.
> +}
> +
> /**
> * pci_ats_supported - check if the device can use ATS
> * @dev: the PCI device
> diff --git a/drivers/pci/pci-driver.c b/drivers/pci/pci-driver.c
> index e16aa59dd7ac..9a1856def5bd 100644
> --- a/drivers/pci/pci-driver.c
> +++ b/drivers/pci/pci-driver.c
> @@ -1713,6 +1713,7 @@ static int pci_dma_configure(struct device *dev)
> * quirks.
> */
> pci_enable_acs(to_pci_dev(dev));
> + pci_ats_check_acs(to_pci_dev(dev));
> pci_put_host_bridge_device(bridge);
>
> diff --git a/drivers/pci/pci.h b/drivers/pci/pci.h
> index ba3c3fddddc2..cf2c93761d81 100644
> --- a/drivers/pci/pci.h
> +++ b/drivers/pci/pci.h
> @@ -961,9 +961,11 @@ static inline void pcie_walk_rcec(struct pci_dev *rcec,
> #ifdef CONFIG_PCI_ATS
> /* Address Translation Service */
> void pci_ats_init(struct pci_dev *dev);
> +void pci_ats_check_acs(struct pci_dev *dev);
> void pci_restore_ats_state(struct pci_dev *dev);
> #else
> static inline void pci_ats_init(struct pci_dev *d) { }
> +static inline void pci_ats_check_acs(struct pci_dev *d) { }
> static inline void pci_restore_ats_state(struct pci_dev *dev) { }
> #endif /* CONFIG_PCI_ATS */
>
> --
> 2.56.0.313.g2479322e68-goog
>
next prev parent reply other threads:[~2026-11-03 18:16 UTC|newest]
Thread overview: 4+ messages / expand[flat|nested] mbox.gz Atom feed top
2026-10-28 23:36 [PATCH v2] PCI/ATS: Disable ATS when ACS TB is set upstream Danny Gonzalez
2026-10-28 23:51 ` sashiko-bot
2026-11-03 18:16 ` Bjorn Helgaas [this message]
2026-11-03 18:20 ` Jason Gunthorpe
Reply instructions:
You may reply publicly to this message via plain-text email
using any one of the following methods:
* Save the following mbox file, import it into your mail client,
and reply-to-all from there: mbox
Avoid top-posting and favor interleaved quoting:
https://en.wikipedia.org/wiki/Posting_style#Interleaved_style
* Reply using the --to, --cc, and --in-reply-to
switches of git-send-email(1):
git send-email \
--in-reply-to=20261103181616.GA1080116@bhelgaas \
--to=helgaas@kernel.org \
--cc=baolu.lu@linux.intel.com \
--cc=bhelgaas@google.com \
--cc=decot@google.com \
--cc=digonzal@google.com \
--cc=jgg@nvidia.com \
--cc=joerg.roedel@amd.com \
--cc=kevin.tian@intel.com \
--cc=linux-kernel@vger.kernel.org \
--cc=linux-pci@vger.kernel.org \
--cc=nicolinc@nvidia.com \
--cc=praan@google.com \
--cc=sheenamo@google.com \
/path/to/YOUR_REPLY
https://kernel.org/pub/software/scm/git/docs/git-send-email.html
* If your mail client supports setting the In-Reply-To header
via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line
before the message body.
This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.