From: Bjorn Helgaas <helgaas@kernel.org>
To: Leon Romanovsky <leon@kernel.org>
Cc: "Bjorn Helgaas" <bhelgaas@google.com>,
"Logan Gunthorpe" <logang@deltatee.com>,
"Jason Gunthorpe" <jgg@ziepe.ca>,
"Joerg Roedel (AMD)" <joro@8bytes.org>,
"Will Deacon" <will@kernel.org>,
"Robin Murphy" <robin.murphy@arm.com>,
"Christian König" <christian.koenig@amd.com>,
"Thomas Hellström" <thomas.hellstrom@linux.intel.com>,
linux-pci@vger.kernel.org, linux-kernel@vger.kernel.org,
linux-doc@vger.kernel.org, iommu@lists.linux.dev,
"Tushar Dave" <tdave@nvidia.com>,
linux-media@vger.kernel.org, dri-devel@lists.freedesktop.org,
linaro-mm-sig@lists.linaro.org, linux-rdma@vger.kernel.org,
kvm@vger.kernel.org, "Chaitanya Kulkarni" <kch@nvidia.com>,
"Greg Kroah-Hartman" <gregkh@linuxfoundation.org>,
"Jens Axboe" <axboe@kernel.dk>,
"Alex Williamson" <alex@shazbot.org>,
"Ankit Agrawal" <ankita@nvidia.com>,
"Jonathan Corbet" <corbet@lwn.net>,
"Shuah Khan" <skhan@linuxfoundation.org>,
"Randy Dunlap" <rdunlap@infradead.org>,
"Sumit Semwal" <sumit.semwal@linaro.org>
Subject: Re: [PATCH v9 06/18] PCI/P2PDMA: Collect the path's ACS controls before deciding
Date: Tue, 6 Oct 2026 16:48:58 -0500 [thread overview]
Message-ID: <20261006214858.GA717151@bhelgaas> (raw)
In-Reply-To: <20261001-fix-p2p-acs-v4-0-v9-6-1a8e0f50ddd9@nvidia.com>
On Thu, Oct 01, 2026 at 02:55:14PM +0300, Leon Romanovsky wrote:
> From: Leon Romanovsky <leonro@nvidia.com>
>
> calc_map_type_and_dist() reads each divergence port's ACS Control register
> and folds the result into running counters as it goes. Any routing property
> that depends on the kind of TLP being routed would have to be threaded
> through that code, so there is nowhere to put one without reading the
> registers again for each kind.
What is the "one" that there's nowhere to put? I guess the routing
property? So this is an optimization to avoid some config reads?
> Collect the two ports' ACS Control values into struct pci_p2pdma_acs_path
> first, then decide from it. pci_p2pdma_route() applies the same rule as
> before: a path routes directly only when both directions do.
>
> Reviewed-by: Logan Gunthorpe <logang@deltatee.com>
> Tested-by: Tushar Dave <tdave@nvidia.com>
> Signed-off-by: Leon Romanovsky <leonro@nvidia.com>
> ---
> drivers/pci/p2pdma.c | 148 +++++++++++++++++++++++++++++++++------------------
> 1 file changed, 96 insertions(+), 52 deletions(-)
>
> diff --git a/drivers/pci/p2pdma.c b/drivers/pci/p2pdma.c
> index 550e6c7346ef..841c86be31bb 100644
> --- a/drivers/pci/p2pdma.c
> +++ b/drivers/pci/p2pdma.c
> @@ -553,6 +553,80 @@ static void seq_buf_print_bus_devfn(struct seq_buf *buf, struct pci_dev *pdev)
> seq_buf_printf(buf, "%s;", pci_name(pdev));
> }
>
> +/*
> + * What the topology walk found out about one provider/client path. Producing
> + * this costs a walk and one config read per divergence port, none of which
> + * depends on the TLP being routed.
> + *
> + * @req_ctrl: ACS Control of the client-side divergence port. That is the
> + * first port at which a Request can route toward the peer rather
> + * than upstream, so it is where the Request controls apply.
> + * @cpl_ctrl: ACS Control of the provider-side divergence port, likewise for
> + * the Completions travelling back.
> + * @unreadable: First port whose ACS Control could not be read, if any.
> + */
> +struct pci_p2pdma_acs_path {
> + u16 req_ctrl;
> + u16 cpl_ctrl;
> + struct pci_dev *unreadable;
> +};
> +
> +/*
> + * Combine both directions into a mapping type. Only a path that routes the
> + * Request and the Completions it generates directly can be programmed with
> + * the peer's bus addresses.
> + */
> +static enum pci_p2pdma_map_type
> +pci_p2pdma_route(const struct pci_p2pdma_acs_path *path)
> +{
> + if (path->unreadable)
> + return PCI_P2PDMA_MAP_NOT_SUPPORTED;
> +
> + if (pci_acs_p2pdma_request(path->req_ctrl) == PCI_ACS_P2PDMA_DIRECT &&
> + pci_acs_p2pdma_completion(path->cpl_ctrl) == PCI_ACS_P2PDMA_DIRECT)
> + return PCI_P2PDMA_MAP_BUS_ADDR;
> +
> + return PCI_P2PDMA_MAP_THRU_HOST_BRIDGE;
> +}
> +
> +/*
> + * Name the ports that keep this path off a direct route, so that the admin
> + * can hand them to pci=disable_acs_redir=.
> + */
> +static void pci_p2pdma_warn_path(struct pci_dev *client,
> + struct pci_dev *provider,
> + const struct pci_p2pdma_acs_path *path,
> + struct pci_dev *a_child,
> + struct pci_dev *b_child)
> +{
> + struct seq_buf acs_list;
> + char buf[128];
> +
> + if (path->unreadable) {
> + pci_warn(client,
> + "ACS Control is unreadable for provider %s at %s\n",
> + pci_name(provider), pci_name(path->unreadable));
> + return;
> + }
> +
> + seq_buf_init(&acs_list, buf, sizeof(buf));
> + if (pci_acs_p2pdma_completion(path->cpl_ctrl) != PCI_ACS_P2PDMA_DIRECT)
> + seq_buf_print_bus_devfn(&acs_list, a_child);
> + if (pci_acs_p2pdma_request(path->req_ctrl) != PCI_ACS_P2PDMA_DIRECT)
> + seq_buf_print_bus_devfn(&acs_list, b_child);
> +
> + /* Drop the final semicolon; the list is not empty here. */
> + if (!seq_buf_has_overflowed(&acs_list))
> + acs_list.buffer[acs_list.len - 1] = '\0';
> +
> + pci_warn(client,
> + "ACS redirect is set between the client and provider (%s)\n",
> + pci_name(provider));
> + pci_warn(client,
> + "to disable ACS controls for this path, add the kernel parameter: pci=disable_acs_redir=%s\n",
> + seq_buf_str(&acs_list));
> +}
> +
> static bool cpu_supports_p2pdma(void)
> {
> #ifdef CONFIG_X86
> @@ -751,19 +825,13 @@ calc_map_type_and_dist(struct pci_dev *provider, struct pci_dev *client,
> int *dist, bool verbose)
> {
> enum pci_p2pdma_map_type map_type = PCI_P2PDMA_MAP_THRU_HOST_BRIDGE;
> - enum pci_acs_p2pdma_state state = PCI_ACS_P2PDMA_NOT_SUPPORTED;
> struct pci_dev *a = provider, *b = client, *bb;
> struct pci_dev *a_child = NULL, *b_child = NULL;
> - struct pci_dev *acs_unreadable = NULL;
> + struct pci_p2pdma_acs_path path = {};
> struct pci_p2pdma *p2pdma;
> - struct seq_buf acs_list;
> - int acs_redirect_cnt = 0;
> + bool cpu_p2pdma, host_whitelisted = false;
> int dist_a = 0;
> int dist_b = 0;
> - char buf[128];
> - u16 ctrl;
> -
> - seq_buf_init(&acs_list, buf, sizeof(buf));
>
> /*
> * Note, we don't need to take references to devices returned by
> @@ -806,61 +874,35 @@ calc_map_type_and_dist(struct pci_dev *provider, struct pci_dev *client,
> * branch is upstream, so redirect controls do not affect the path.
> */
> if (a_child && b_child) {
> - if (pci_acs_p2pdma_ctrl(a_child, &ctrl))
> - state = pci_acs_p2pdma_completion(ctrl);
> - if (state != PCI_ACS_P2PDMA_DIRECT) {
> - seq_buf_print_bus_devfn(&acs_list, a_child);
> - if (state == PCI_ACS_P2PDMA_REDIRECT)
> - acs_redirect_cnt++;
> - else if (!acs_unreadable)
> - acs_unreadable = a_child;
> - }
> -
> - state = PCI_ACS_P2PDMA_NOT_SUPPORTED;
> - if (pci_acs_p2pdma_ctrl(b_child, &ctrl))
> - state = pci_acs_p2pdma_request(ctrl);
> - if (state != PCI_ACS_P2PDMA_DIRECT) {
> - seq_buf_print_bus_devfn(&acs_list, b_child);
> - if (state == PCI_ACS_P2PDMA_REDIRECT)
> - acs_redirect_cnt++;
> - else if (!acs_unreadable)
> - acs_unreadable = b_child;
> - }
> + if (!pci_acs_p2pdma_ctrl(a_child, &path.cpl_ctrl))
> + path.unreadable = a_child;
> + if (!pci_acs_p2pdma_ctrl(b_child, &path.req_ctrl) &&
> + !path.unreadable)
> + path.unreadable = b_child;
> }
>
> /*
> * Below a shared upstream bridge, a path whose divergence ports do not
> * redirect routes the request directly.
> */
> - if (!acs_unreadable && !acs_redirect_cnt) {
> - map_type = PCI_P2PDMA_MAP_BUS_ADDR;
> + map_type = pci_p2pdma_route(&path);
> + if (map_type == PCI_P2PDMA_MAP_BUS_ADDR)
> goto done;
> - }
>
> - if (verbose) {
> - /* Drop the final semicolon; the list is not empty here. */
> - if (!seq_buf_has_overflowed(&acs_list))
> - acs_list.buffer[acs_list.len - 1] = '\0';
> - if (acs_unreadable)
> - pci_warn(client, "ACS Control is unreadable for provider %s at %s\n",
> - pci_name(provider), pci_name(acs_unreadable));
> - else {
> - pci_warn(client, "ACS redirect is set between the client and provider (%s)\n",
> - pci_name(provider));
> - pci_warn(client, "to disable ACS controls for this path, add the kernel parameter: pci=disable_acs_redir=%s\n",
> - seq_buf_str(&acs_list));
> - }
> - }
> + if (verbose)
> + pci_p2pdma_warn_path(client, provider, &path, a_child, b_child);
>
> /* An unreadable control does not establish an upstream redirect. */
> - if (acs_unreadable) {
> - map_type = PCI_P2PDMA_MAP_NOT_SUPPORTED;
> + if (path.unreadable)
> goto done;
> - }
>
> map_through_host_bridge:
> - if (!cpu_supports_p2pdma() &&
> - !host_bridge_whitelist(provider, client, verbose)) {
> + cpu_p2pdma = cpu_supports_p2pdma();
> + if (!cpu_p2pdma)
> + host_whitelisted = host_bridge_whitelist(provider, client,
> + verbose);
> +
> + if (!cpu_p2pdma && !host_whitelisted) {
> if (verbose)
> pci_warn(client, "cannot be used for peer-to-peer DMA as the client and provider (%s) do not share an upstream bridge or whitelisted host bridge\n",
> pci_name(provider));
> @@ -1193,8 +1235,9 @@ enum pci_p2pdma_map_type pci_p2pdma_map_type(struct p2pdma_provider *provider,
> {
> enum pci_p2pdma_map_type type = PCI_P2PDMA_MAP_NOT_SUPPORTED;
> struct pci_dev *pdev = to_pci_dev(provider->owner);
> - struct pci_dev *client;
> struct pci_p2pdma *p2pdma;
> + unsigned long cache_index;
> + struct pci_dev *client;
> int dist;
>
> if (!pdev->p2pdma)
> @@ -1204,13 +1247,14 @@ enum pci_p2pdma_map_type pci_p2pdma_map_type(struct p2pdma_provider *provider,
> return PCI_P2PDMA_MAP_NOT_SUPPORTED;
>
> client = to_pci_dev(dev);
> + cache_index = map_types_idx(client);
>
> rcu_read_lock();
> p2pdma = rcu_dereference(pdev->p2pdma);
>
> if (p2pdma)
> type = xa_to_value(xa_load(&p2pdma->map_types,
> - map_types_idx(client)));
> + cache_index));
> rcu_read_unlock();
>
> if (type == PCI_P2PDMA_MAP_UNKNOWN)
>
> --
> 2.55.0
>
next prev parent reply other threads:[~2026-10-06 21:49 UTC|newest]
Thread overview: 37+ messages / expand[flat|nested] mbox.gz Atom feed top
2026-10-01 11:55 [PATCH v9 00/18] PCI/P2PDMA: Route peer-to-peer DMA by TLP class Leon Romanovsky
2026-10-01 11:55 ` [PATCH v9 01/18] PCI/P2PDMA: Document the TLP attribute assumptions Leon Romanovsky
2026-10-07 20:12 ` Bjorn Helgaas
2026-10-01 11:55 ` [PATCH v9 02/18] PCI/P2PDMA: Derive routing from directional ACS controls Leon Romanovsky
2026-10-06 20:49 ` Bjorn Helgaas
2026-10-07 6:32 ` Leon Romanovsky
2026-10-01 11:55 ` [PATCH v9 03/18] PCI: Reject unreadable ACS controls in isolation checks Leon Romanovsky
2026-10-01 11:55 ` [PATCH v9 04/18] PCI/P2PDMA: Evaluate ACS controls at the path divergence Leon Romanovsky
2026-10-06 21:08 ` Bjorn Helgaas
2026-10-07 10:51 ` Leon Romanovsky
2026-10-01 11:55 ` [PATCH v9 05/18] PCI/P2PDMA: Document directional ACS routing Leon Romanovsky
2026-10-06 21:32 ` Bjorn Helgaas
2026-10-07 13:46 ` Leon Romanovsky
2026-10-07 20:10 ` Bjorn Helgaas
2026-10-01 11:55 ` [PATCH v9 06/18] PCI/P2PDMA: Collect the path's ACS controls before deciding Leon Romanovsky
2026-10-06 21:48 ` Bjorn Helgaas [this message]
2026-10-07 13:50 ` Leon Romanovsky
2026-10-01 11:55 ` [PATCH v9 07/18] PCI/P2PDMA: Answer routing per TLP class Leon Romanovsky
2026-10-01 11:55 ` [PATCH v9 08/18] PCI/P2PDMA: Route Relaxed Ordering Completions directly Leon Romanovsky
2026-10-06 22:21 ` Bjorn Helgaas
2026-10-01 11:55 ` [PATCH v9 09/18] PCI/P2PDMA: Reject Translated Requests blocked by Translation Blocking Leon Romanovsky
2026-10-01 11:55 ` [PATCH v9 10/18] PCI/P2PDMA: Route Translated Requests under Direct Translated P2P Leon Romanovsky
2026-10-06 22:28 ` Bjorn Helgaas
2026-10-01 11:55 ` [PATCH v9 11/18] PCI/P2PDMA: Log detailed ACS routing diagnostics Leon Romanovsky
2026-10-01 11:55 ` [PATCH v9 12/18] PCI/P2PDMA: Add KUnit tests for the ACS routing decisions Leon Romanovsky
2026-10-01 11:55 ` [PATCH v9 13/18] PCI/P2PDMA: Test the ACS P2P routing walk Leon Romanovsky
2026-10-01 11:55 ` [PATCH v9 14/18] PCI: Add KUnit coverage for ACS isolation checks Leon Romanovsky
2026-10-01 11:55 ` [PATCH v9 15/18] PCI/P2PDMA: Document TLP-class routing Leon Romanovsky
2026-10-01 11:55 ` [PATCH v9 16/18] PCI/P2PDMA: Let a client declare that it selects ATS per mapping Leon Romanovsky
2026-10-01 11:55 ` [PATCH v9 17/18] PCI/P2PDMA: Evaluate the ATS path for clients with ATS enabled Leon Romanovsky
2026-10-01 11:55 ` [PATCH v9 18/18] PCI/P2PDMA: Test the routing of " Leon Romanovsky
2026-10-06 19:29 ` [PATCH v9 00/18] PCI/P2PDMA: Route peer-to-peer DMA by TLP class Bjorn Helgaas
2026-10-06 21:22 ` Leon Romanovsky
2026-10-06 21:36 ` Bjorn Helgaas
2026-10-07 6:56 ` Bjorn Helgaas
2026-10-07 10:54 ` Leon Romanovsky
2026-10-07 11:31 ` Bjorn Helgaas
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=20261006214858.GA717151@bhelgaas \
--to=helgaas@kernel.org \
--cc=alex@shazbot.org \
--cc=ankita@nvidia.com \
--cc=axboe@kernel.dk \
--cc=bhelgaas@google.com \
--cc=christian.koenig@amd.com \
--cc=corbet@lwn.net \
--cc=dri-devel@lists.freedesktop.org \
--cc=gregkh@linuxfoundation.org \
--cc=iommu@lists.linux.dev \
--cc=jgg@ziepe.ca \
--cc=joro@8bytes.org \
--cc=kch@nvidia.com \
--cc=kvm@vger.kernel.org \
--cc=leon@kernel.org \
--cc=linaro-mm-sig@lists.linaro.org \
--cc=linux-doc@vger.kernel.org \
--cc=linux-kernel@vger.kernel.org \
--cc=linux-media@vger.kernel.org \
--cc=linux-pci@vger.kernel.org \
--cc=linux-rdma@vger.kernel.org \
--cc=logang@deltatee.com \
--cc=rdunlap@infradead.org \
--cc=robin.murphy@arm.com \
--cc=skhan@linuxfoundation.org \
--cc=sumit.semwal@linaro.org \
--cc=tdave@nvidia.com \
--cc=thomas.hellstrom@linux.intel.com \
--cc=will@kernel.org \
/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 a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox
all inboxes | Powered by JetHome®