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,
Jason Gunthorpe <jgg@nvidia.com>,
Pranjal Shrivastava <praan@google.com>,
Joerg Roedel <joerg.roedel@amd.com>,
Nicolin Chen <nicolinc@nvidia.com>,
Lu Baolu <baolu.lu@linux.intel.com>,
Kevin Tian <kevin.tian@intel.com>
Subject: Re: [PATCH] PCI/ATS: Disable ATS when ACS TB is set upstream
Date: Thu, 5 Nov 2026 17:04:12 -0600 [thread overview]
Message-ID: <20261105230412.GA1450377@bhelgaas> (raw)
In-Reply-To: <20261020181053.2646782-1-digonzal@google.com>
[+cc other folks interested in ATS]
On Tue, Oct 20, 2026 at 06:10:52PM +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.
>
> Update pci_ats_supported() to walk upstream bridges and return false if
> any bridge has PCI_ACS_TB set, 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.
There was a v2 at
https://lore.kernel.org/all/20261028233651.960835-1-digonzal@google.com,
which added pci_ats_check_acs() in pci_dma_configure(). I thought
that was a non-obvious way to make pci_ats_supported() return "false",
and I proposed doing the checking in pci_ats_supported() directly to
avoid adding the new pci_ats_check_acs() interface.
I'm responding to v1 because it *did* add the checking in
pci_ats_supported(). But sashiko found some issues with it:
https://lore.kernel.org/all/sashiko-outbox-179488@kernel.org.
> Signed-off-by: Danny Gonzalez <digonzal@google.com>
> ---
> drivers/pci/ats.c | 28 ++++++++++++++++++++++++++++
> 1 file changed, 28 insertions(+)
>
> diff --git a/drivers/pci/ats.c b/drivers/pci/ats.c
> index 9cb23780093d..094f4f825acf 100644
> --- a/drivers/pci/ats.c
> +++ b/drivers/pci/ats.c
> @@ -31,6 +31,24 @@ void pci_ats_init(struct pci_dev *dev)
> dev->ats_cap = pos;
> }
>
> +static struct pci_dev *pci_acs_tb_path_blocked(struct pci_dev *dev)
> +{
> + struct pci_dev *bridge;
> +
> + for (bridge = pci_upstream_bridge(dev); bridge;
> + bridge = pci_upstream_bridge(bridge)) {
> + u16 ctrl;
> +
> + if (!bridge->acs_cap)
> + continue;
> + pci_read_config_word(bridge, bridge->acs_cap + PCI_ACS_CTRL,
> + &ctrl);
Sashiko noted that if bridge is inaccessible, this read sets ctrl to
~0, so we think PCI_ACS_TB is set. Maybe worth checking for
PCI_POSSIBLE_ERROR() before using ctrl.
> + if (ctrl & PCI_ACS_TB)
> + return bridge;
> + }
> + return NULL;
> +}
> +
> /**
> * pci_ats_supported - check if the device can use ATS
> * @dev: the PCI device
> @@ -40,12 +58,22 @@ void pci_ats_init(struct pci_dev *dev)
> */
> bool pci_ats_supported(struct pci_dev *dev)
> {
> + struct pci_dev *bridge;
> +
> if (!dev->ats_cap || dev->untrusted)
> return false;
>
> if (dev->is_virtfn)
> return pci_ats_supported(pci_physfn(dev));
>
> + /* Do not allow ATS if any upstream bridge blocks translation */
> + bridge = pci_acs_tb_path_blocked(dev);
> + if (bridge) {
> + pci_warn_once(dev, "ATS disabled: upstream bridge %s has ACS Translation Blocking enabled\n",
> + pci_name(bridge));
I think I suggested it, but now I'm not sure the warning is
worthwhile. I think this might be too far down in the bowels for it
to be useful. And sashiko complained about the warn-once bit too,
which is fair.
> + return false;
> + }
> +
Sashiko also noted problems if pci_ats_supported() returns different
values in:
* intel_iommu_probe_device() vs intel_iommu_release_device()
Different values break rbtree 'info' management: _probe_device()
can put 'info' in the rbtree and _release_device() may fail to
remove it.
I think the fix is for intel_iommu_probe_device() to keep its own
bit in struct device_domain_info to say whether 'info' is in the
rbtree so _release_device() doesn't need pci_ats_supported().
* pci_dev_reset_iommu_prepare() vs pci_dev_reset_iommu_done()
Different values will make gdev->reset_depth, group->recovery_cnt,
group->domain, and gdev->blocked get out of sync.
I think it would be better if _iommu_prepare() and _iommu_done()
themselves tracked what _iommu_done() needs to do, for example
they could do something like this:
int pci_dev_reset_iommu_prepare(struct pci_dev *pdev, bool *restore)
{
if (!pci_ats_supported(pdev) || !dev_has_iommu(&pdev->dev)) {
*restore = false;
return 0;
}
*restore = true;
...
}
Then pci_dev_reset_iommu_done() wouldn't need to call
pci_ats_supported() or dev_has_iommu(), and users would look like
this:
int pcie_flr(...)
{
bool restore;
ret = pci_dev_reset_iommu_prepare(dev, &restore);
...
if (restore)
pci_dev_reset_iommu_done(dev);
}
Or I guess we could call pci_dev_reset_iommu_done()
unconditionally and pass it 'restore' and it could test it
internally.
> return true;
> }
> EXPORT_SYMBOL_GPL(pci_ats_supported);
> --
> 2.56.0.218.g1ec904b173-goog
>
next prev parent reply other threads:[~2026-11-05 23:04 UTC|newest]
Thread overview: 5+ messages / expand[flat|nested] mbox.gz Atom feed top
2026-10-20 18:10 [PATCH] PCI/ATS: Disable ATS when ACS TB is set upstream Danny Gonzalez
2026-10-20 18:36 ` sashiko-bot
2026-11-05 23:04 ` Bjorn Helgaas [this message]
2026-11-05 23:15 ` Nicolin Chen
2026-11-06 17:49 ` 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=20261105230412.GA1450377@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.