From nobody Thu Sep 24 21:19:39 2026 Received: from smtp.kernel.org (aws-us-west-2-korg-mail-alma10-1.taild15c8.ts.net [100.103.45.18]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by smtp.subspace.kernel.org (Postfix) with ESMTPS id BE93C41A78A; Sun, 20 Sep 2026 11:41:48 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=100.103.45.18 ARC-Seal: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1789904512; cv=none; b=n8XGQfDVUljF06vTPJ9KoZzOeSH0l+A28VYtCskHqLzObdC1tHw5x7IhJ5zrH3fqiqyXTylRV/GolRd2spoADsKJWQUIypFwizwBVHnfRTxLAgoH8wFr8jQCN/WBSdwL4Vb5oBp/Nvm+BBzds73qyVXC97/DBl54hhCQ+77wEzA= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1789904512; c=relaxed/simple; bh=QUzVSRZvTKg2E13vIgCE8+l+zgBTXZofkjJhl+ER15s=; h=From:To:Cc:Subject:Date:Message-ID:In-Reply-To:References: MIME-Version:Content-Type; b=s4H2FymZKdHHZ+s7N8JVG4uLP4f0WO9Eul0KC6koQyFxf+giKszbkqHWuOrkF2WJBvbmCTBJXbmQ2ZHEpK6prnHbW1++eihHJZCpao8pTbVtsbetK/BaKGkvLpF4/cejpSAyBFMJW6o/qQRRLNig8QPqpOpZFqFdeN4/986ZhhU= ARC-Authentication-Results: i=1; smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=kernel.org header.i=@kernel.org header.b=DskItDFS; arc=none smtp.client-ip=100.103.45.18 Authentication-Results: smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=kernel.org header.i=@kernel.org header.b="DskItDFS" Received: by smtp.kernel.org (Postfix) with ESMTPSA id 6404F1F00893; Sun, 20 Sep 2026 11:41:47 +0000 (UTC) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=kernel.org; s=k20260515; t=1789904508; bh=6I7K2CcZKiNEkj3tMDTHshN0X+VnIpc+D+swyH4+62w=; h=From:To:Cc:Subject:Date:In-Reply-To:References; b=DskItDFSncfH8LsSl3L4tDvd1Nh6r6SWlq0gJ262aq6EGYpdlhSs8odG3/BTkwCwk YWNF0/bwmVtImLIVUVDcCWUHRvZ0mfQQUSYrhxxEQY5GR9FxXAZg8f//RLhNyk077f 9vE7STkQGnwx2kek1aTcC4XIpmTe/dOsz4Dtml8n+E8UZVEnAi587MUmAUuJbtEzQn xqj8g5nKEqpED7aew7tyUjaAiT23QsiRa6gpwOQCzJbQUYTxDxfTQmkMuoF0g0G1fq VmTvP+6M/MIk6Z3BkQONAy6lVWaM21P+9wMFtJXkJMsh+xDLfJtrOF2NQO47SNoL8x iu5iwAMLyX/UQ== From: Leon Romanovsky To: Bjorn Helgaas , Logan Gunthorpe , Chaitanya Kulkarni , Greg Kroah-Hartman , Jens Axboe , Alex Williamson , Leon Romanovsky , Ankit Agrawal , Jason Gunthorpe , Jonathan Corbet , Shuah Khan , "Joerg Roedel (AMD)" , Will Deacon , Robin Murphy , Randy Dunlap , Sumit Semwal , =?utf-8?q?Christian_K=C3=B6nig?= Cc: linux-pci@vger.kernel.org, linux-kernel@vger.kernel.org, linux-doc@vger.kernel.org, iommu@lists.linux.dev, Tushar Dave , 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 Subject: [PATCH v7 01/19] PCI/P2PDMA: Document the TLP attribute assumptions Date: Sun, 20 Sep 2026 14:41:13 +0300 Message-ID: <20260920-fix-p2p-acs-v4-0-v7-1-ca0828ab697c@nvidia.com> X-Mailer: git-send-email 2.55.0 In-Reply-To: <20260920-fix-p2p-acs-v4-0-v7-0-ca0828ab697c@nvidia.com> References: <20260920-fix-p2p-acs-v4-0-v7-0-ca0828ab697c@nvidia.com> Precedence: bulk X-Mailing-List: linux-kernel@vger.kernel.org List-Id: List-Subscribe: List-Unsubscribe: MIME-Version: 1.0 Content-Type: text/plain; charset="utf-8" X-Mailer: b4 0.15-dev-18f8f Content-Transfer-Encoding: quoted-printable From: Leon Romanovsky P2PDMA selects a mapping without receiving the Request's ordering or Address Type attributes. Its ACS handles only strictly ordered Requests carrying an Untranslated address. Document that the result is not defined for Relaxed Ordering or ATS-translated Requests because those TLP attributes can select different routes through the fabric. Reviewed-by: Logan Gunthorpe Tested-by: Tushar Dave Signed-off-by: Leon Romanovsky --- Documentation/driver-api/pci/p2pdma.rst | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/Documentation/driver-api/pci/p2pdma.rst b/Documentation/driver= -api/pci/p2pdma.rst index 63cff9e4d2c9..80f8fec9b0e9 100644 --- a/Documentation/driver-api/pci/p2pdma.rst +++ b/Documentation/driver-api/pci/p2pdma.rst @@ -15,6 +15,13 @@ then based on the ACS settings the transaction can route= entirely within the PCIe hierarchy and never reach the root port. The kernel will evaluate the PCIe topology and always permit P2P in these well-defined cases. =20 +This evaluation assumes clients issue strictly ordered Requests carrying an +Untranslated address. Its result is not defined when clients use Relaxed +Ordering or issue ATS-translated Requests because those TLP attributes can +select different routes through the fabric. Unless ACS Translation Blocking +is enabled, a Port with ACS Direct Translated P2P enabled routes a +Translated Request directly to the peer regardless of the redirect control= s. + However, if the P2P transaction reaches the host bridge then it might have= to hairpin back out the same root port, be routed inside the CPU SOC to anoth= er PCIe root port, or routed internally to the SOC. --=20 2.55.0 From nobody Thu Sep 24 21:19:39 2026 Received: from smtp.kernel.org (aws-us-west-2-korg-mail-alma10-1.taild15c8.ts.net [100.103.45.18]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by smtp.subspace.kernel.org (Postfix) with ESMTPS id C206241A4E4; Sun, 20 Sep 2026 11:42:00 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=100.103.45.18 ARC-Seal: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1789904522; cv=none; b=FRr4PvGmtpPSRgAjbvIMZ+DnTcMc2ASZeCQwDc0BG0Csz1yWRlbLLp0I2T9kjLgUMbu/n8A6yp4ptVZUgeF1zQdywv+4Ah9HV9/JrI+f5ZK3c9A17WaXPY28G93fqAJTvIKac34YtPVoSo7bf3nk5V25Kya7+SxCor7NGLkLs5w= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1789904522; c=relaxed/simple; bh=aaFum9yU69sOwp2RMcjWN0+TXt3+BrCc/FlmyPGpws0=; h=From:To:Cc:Subject:Date:Message-ID:In-Reply-To:References: MIME-Version:Content-Type; b=N+ccWzJMhvC/+2HAzb9zYq6EChM2MsQhUUYmsfmqJh84bcG9sz9nJde4gMo4773LXDuDOk0d+mreBaLJK2TGrMwNLzKllLlr7M0eNAabribGXG1IZpBquwdZIkiWOtZM1IabShuSfSRIshJwq4IcdEfr/aPelhjXztfHDJ1mkS8= ARC-Authentication-Results: i=1; smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=kernel.org header.i=@kernel.org header.b=k6zzJJbo; arc=none smtp.client-ip=100.103.45.18 Authentication-Results: smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=kernel.org header.i=@kernel.org header.b="k6zzJJbo" Received: by smtp.kernel.org (Postfix) with ESMTPSA id 6D7BD1F00893; Sun, 20 Sep 2026 11:41:58 +0000 (UTC) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=kernel.org; s=k20260515; t=1789904520; bh=nKDJoxw+Ot4U8L3uXhOzCP4LuztjFHxRxiiCcc2FhCI=; h=From:To:Cc:Subject:Date:In-Reply-To:References; b=k6zzJJbouCl8T0pAzVS+d4rGTWZ4/SiauCxQsVVVkoFlQhqwIEOI5w2vx5q69YR89 9h9ZjIdFREF2ezo0ZxI2tAt73o+wTplFcgqeDwtwBKFshBmXXrjvrZjv6iPiKLJjzq EgOtwJyjxQceW9DGNyQjj1P7nDsMRQt/MT7wo+adLWtQUXMmxrVCsDTQPJBmQIsbG/ zwSDNQZ5iO8AcHKyEch3wFIfq7kvq387DMxhQjLxqY7LxoF8vsrg7gGMRJ9z2z7XA8 gSmChgb8ZmJ59KUpF8IaaJl5aN9qnmSs2xz4wP62ISVvGdHUXcI0qSmOf7T0oDgg2J I0lwsDh89n7ww== From: Leon Romanovsky To: Bjorn Helgaas , Logan Gunthorpe , Chaitanya Kulkarni , Greg Kroah-Hartman , Jens Axboe , Alex Williamson , Leon Romanovsky , Ankit Agrawal , Jason Gunthorpe , Jonathan Corbet , Shuah Khan , "Joerg Roedel (AMD)" , Will Deacon , Robin Murphy , Randy Dunlap , Sumit Semwal , =?utf-8?q?Christian_K=C3=B6nig?= Cc: linux-pci@vger.kernel.org, linux-kernel@vger.kernel.org, linux-doc@vger.kernel.org, iommu@lists.linux.dev, Tushar Dave , 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 Subject: [PATCH v7 02/19] PCI/P2PDMA: Derive routing from directional ACS controls Date: Sun, 20 Sep 2026 14:41:14 +0300 Message-ID: <20260920-fix-p2p-acs-v4-0-v7-2-ca0828ab697c@nvidia.com> X-Mailer: git-send-email 2.55.0 In-Reply-To: <20260920-fix-p2p-acs-v4-0-v7-0-ca0828ab697c@nvidia.com> References: <20260920-fix-p2p-acs-v4-0-v7-0-ca0828ab697c@nvidia.com> Precedence: bulk X-Mailing-List: linux-kernel@vger.kernel.org List-Id: List-Subscribe: List-Unsubscribe: MIME-Version: 1.0 Content-Type: text/plain; charset="utf-8" X-Mailer: b4 0.15-dev-18f8f Content-Transfer-Encoding: quoted-printable From: Leon Romanovsky pci_bridge_has_acs_redir() treats Request and Completion Redirect as interchangeable. On asymmetric fabrics, a control for only the reverse TLP direction can unnecessarily force P2PDMA through the host bridge. Evaluate Request Redirect for client Requests and Completion Redirect for provider read Completions. Continue treating enabled Egress Control conservatively as a Request redirect. Fixes: 52916982af48 ("PCI/P2PDMA: Support peer-to-peer memory") Tested-by: Tushar Dave Signed-off-by: Leon Romanovsky Reviewed-by: Logan Gunthorpe --- drivers/pci/p2pdma.c | 75 ++++++++++++++++++++++++++++++++++++++++--------= ---- 1 file changed, 58 insertions(+), 17 deletions(-) diff --git a/drivers/pci/p2pdma.c b/drivers/pci/p2pdma.c index 4e4d2df17a45..12612b82d80d 100644 --- a/drivers/pci/p2pdma.c +++ b/drivers/pci/p2pdma.c @@ -21,6 +21,8 @@ #include #include =20 +#include "pci.h" + struct pci_p2pdma { struct gen_pool *pool; bool p2pmem_published; @@ -490,26 +492,56 @@ static struct pci_dev *find_parent_pci_dev(struct dev= ice *dev) return NULL; } =20 +enum pci_acs_p2pdma_state { + PCI_ACS_P2PDMA_DIRECT, + PCI_ACS_P2PDMA_REDIRECT, +}; + /* - * Check if a PCI bridge has its ACS redirection bits set to redirect P2P - * TLPs upstream via ACS. Returns 1 if the packets will be redirected - * upstream, 0 otherwise. + * Decide how a peer-to-peer Request at an ACS-capable ingress port routes, + * from that port's ACS Control register. + * + * Linux does not read the Egress Control Vector, so Egress Control is tre= ated + * conservatively as a redirect. Per PCIe r7.0 Table 6-11 the outcomes it + * selects are a direct route and an ACS Violation, and neither one lets p= eer + * bus addressing be assumed. */ -static int pci_bridge_has_acs_redir(struct pci_dev *pdev) +static enum pci_acs_p2pdma_state +pci_acs_p2pdma_request(u16 ctrl) { - int pos; - u16 ctrl; + return ctrl & (PCI_ACS_RR | PCI_ACS_EC) ? + PCI_ACS_P2PDMA_REDIRECT : PCI_ACS_P2PDMA_DIRECT; +} =20 - pos =3D pdev->acs_cap; - if (!pos) - return 0; +/* + * Decide how a peer-to-peer Completion at an ACS-capable ingress port rou= tes. + * PCIe r7.0 sec 6.12.1.1: no ACS control other than P2P Completion Redire= ct + * affects a Completion. + */ +static enum pci_acs_p2pdma_state +pci_acs_p2pdma_completion(u16 ctrl) +{ + return ctrl & PCI_ACS_CR ? PCI_ACS_P2PDMA_REDIRECT : + PCI_ACS_P2PDMA_DIRECT; +} =20 - pci_read_config_word(pdev, pos + PCI_ACS_CTRL, &ctrl); +/* + * Read @pdev's ACS Control register. A device without an ACS capability h= as + * no peer-to-peer controls at all, which routes the same as having them a= ll + * clear. Returns false when the register is present but cannot be read; @= ctrl + * is then meaningless. + */ +static bool pci_acs_p2pdma_ctrl(struct pci_dev *pdev, u16 *ctrl) +{ + int pos; =20 - if (ctrl & (PCI_ACS_RR | PCI_ACS_CR | PCI_ACS_EC)) - return 1; + pos =3D pdev->acs_cap; + if (!pos) { + *ctrl =3D 0; + return true; + } =20 - return 0; + return !pci_read_config_word(pdev, pos + PCI_ACS_CTRL, ctrl); } =20 static void seq_buf_print_bus_devfn(struct seq_buf *buf, struct pci_dev *p= dev) @@ -698,6 +730,10 @@ static unsigned long map_types_idx(struct pci_dev *cli= ent) * then to Device B. The mapping type returned depends on the ACS * redirection setting of the ports along the path. * + * The client initiates Requests to provider memory. Check Request Redirect + * on the client path and Completion Redirect for read Completions on the + * provider path. + * * If ACS redirect is set on any port in the path, traffic between the * devices will go through the host bridge, so return * PCI_P2PDMA_MAP_THRU_HOST_BRIDGE; otherwise return @@ -721,6 +757,7 @@ calc_map_type_and_dist(struct pci_dev *provider, struct= pci_dev *client, int dist_a =3D 0; int dist_b =3D 0; char buf[128]; + u16 ctrl; =20 seq_buf_init(&acs_list, buf, sizeof(buf)); =20 @@ -732,7 +769,9 @@ calc_map_type_and_dist(struct pci_dev *provider, struct= pci_dev *client, while (a) { dist_b =3D 0; =20 - if (pci_bridge_has_acs_redir(a)) { + if (!pci_acs_p2pdma_ctrl(a, &ctrl) || + pci_acs_p2pdma_completion(ctrl) =3D=3D + PCI_ACS_P2PDMA_REDIRECT) { seq_buf_print_bus_devfn(&acs_list, a); acs_cnt++; } @@ -761,7 +800,9 @@ calc_map_type_and_dist(struct pci_dev *provider, struct= pci_dev *client, if (a =3D=3D bb) break; =20 - if (pci_bridge_has_acs_redir(bb)) { + if (!pci_acs_p2pdma_ctrl(bb, &ctrl) || + pci_acs_p2pdma_request(ctrl) =3D=3D + PCI_ACS_P2PDMA_REDIRECT) { seq_buf_print_bus_devfn(&acs_list, bb); acs_cnt++; } @@ -1109,10 +1150,10 @@ EXPORT_SYMBOL_GPL(pci_p2pmem_publish); /** * pci_p2pdma_map_type - Determine the mapping type for P2PDMA transfers * @provider: P2PDMA provider structure - * @dev: Target device for the transfer + * @dev: Client device that initiates the transfer * * Determines how peer-to-peer DMA transfers should be mapped between - * the provider and the target device. The mapping type indicates whether + * the provider and the client device. The mapping type indicates whether * the transfer can be done directly through PCI switches or must go * through the host bridge. */ --=20 2.55.0 From nobody Thu Sep 24 21:19:39 2026 Received: from smtp.kernel.org (aws-us-west-2-korg-mail-alma10-1.taild15c8.ts.net [100.103.45.18]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by smtp.subspace.kernel.org (Postfix) with ESMTPS id 34D0A3515F8; Sun, 20 Sep 2026 11:41:51 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=100.103.45.18 ARC-Seal: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1789904513; cv=none; b=Hbg6xPOIRkVoax6/BgYdcBBzu1eKPVkcgVvlgM7lGwGaKI9xyH3/ishkmVCBPxjddA1cIa+FwPS7K7+VWZC3l6xrD0rjGtNsZ4Mqq2QV12aFOSWGwmyV98hPk/5h5h62ZOkrDFIQNQLio+/kjwey0ToUiH3+3CuE2DpvYGYdBrs= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1789904513; c=relaxed/simple; bh=r82jL5WVcsE7kmahJOP1AjghFLzIXt1P4Mp9z2NJ+Vw=; h=From:To:Cc:Subject:Date:Message-ID:In-Reply-To:References: MIME-Version:Content-Type; b=A+qgeZeJKy7Yfago80e14rA7nWo954mzeELethrIOWfwTpsVAAcQ/87Q2sp1iMeR0ypbjvtrkl9UW9Y4F4NQ8Ba9osAXUNq7+Z0wsve/Se/jgau2wxSkr/pZ1PXLxAdR77NmvZ7z/NUzxQXgeJj+B82y5qdZ4yGiVhxQ/zDpROo= ARC-Authentication-Results: i=1; smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=kernel.org header.i=@kernel.org header.b=EQqBUWJF; arc=none smtp.client-ip=100.103.45.18 Authentication-Results: smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=kernel.org header.i=@kernel.org header.b="EQqBUWJF" Received: by smtp.kernel.org (Postfix) with ESMTPSA id 3E26E1F000FF; Sun, 20 Sep 2026 11:41:51 +0000 (UTC) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=kernel.org; s=k20260515; t=1789904511; bh=mB9EKqkzLzypkhdTWBPdUAfJNQuk4resftiaCbJ0Vhw=; h=From:To:Cc:Subject:Date:In-Reply-To:References; b=EQqBUWJF5+nKXmOJtT2JE4EiQKGekYJkgGty3zB523vGr8s8VfiEDwatYoLvMBKZf ZSnheTyWquCZ2QjOQ+f8svrrUYdcgMgM6F5+NKzJxrfFLGKcuvkWwISS9bDgk7PPNC NRHwchF1HjcPHs34r1OxuC1Jq9FQKjJqMFvVCv0cvzpeHgQAVvf2ckMFR90O/3uPEm xk0DHSGLTFjjuUk2oO62We9xkLNoj/BsE0eeqXxdbfGvkKJ01dtPOF9YzzaaDsDJsw ATFGcvPCDSVhnDzW3mFd4Ior9lZXbKvnGDt/KOaSy3xpOfdcN5sjOWvIjza2H3j2YM 8GYhwArtYJK7A== From: Leon Romanovsky To: Bjorn Helgaas , Logan Gunthorpe , Chaitanya Kulkarni , Greg Kroah-Hartman , Jens Axboe , Alex Williamson , Leon Romanovsky , Ankit Agrawal , Jason Gunthorpe , Jonathan Corbet , Shuah Khan , "Joerg Roedel (AMD)" , Will Deacon , Robin Murphy , Randy Dunlap , Sumit Semwal , =?utf-8?q?Christian_K=C3=B6nig?= Cc: linux-pci@vger.kernel.org, linux-kernel@vger.kernel.org, linux-doc@vger.kernel.org, iommu@lists.linux.dev, Tushar Dave , 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 Subject: [PATCH v7 03/19] PCI: Reject unreadable ACS controls in isolation checks Date: Sun, 20 Sep 2026 14:41:15 +0300 Message-ID: <20260920-fix-p2p-acs-v4-0-v7-3-ca0828ab697c@nvidia.com> X-Mailer: git-send-email 2.55.0 In-Reply-To: <20260920-fix-p2p-acs-v4-0-v7-0-ca0828ab697c@nvidia.com> References: <20260920-fix-p2p-acs-v4-0-v7-0-ca0828ab697c@nvidia.com> Precedence: bulk X-Mailing-List: linux-kernel@vger.kernel.org List-Id: List-Subscribe: List-Unsubscribe: MIME-Version: 1.0 Content-Type: text/plain; charset="utf-8" X-Mailer: b4 0.15-dev-18f8f Content-Transfer-Encoding: quoted-printable From: Leon Romanovsky pci_acs_flags_enabled() and the Intel SPT PCH quirk use ACS registers without checking config-space read errors. A failed read may leave control state indeterminate yet allow the device to satisfy requested isolation controls. Return false when either ACS capability or control state cannot be read. An unknown state cannot prove isolation. Reviewed-by: Logan Gunthorpe Tested-by: Tushar Dave Signed-off-by: Leon Romanovsky --- drivers/pci/pci.c | 3 ++- drivers/pci/quirks.c | 6 ++++-- 2 files changed, 6 insertions(+), 3 deletions(-) diff --git a/drivers/pci/pci.c b/drivers/pci/pci.c index b2879a6be5f8..f7d94ecf9157 100644 --- a/drivers/pci/pci.c +++ b/drivers/pci/pci.c @@ -3594,7 +3594,8 @@ static bool pci_acs_flags_enabled(struct pci_dev *pde= v, u16 acs_flags) */ acs_flags &=3D (pdev->acs_capabilities | PCI_ACS_EC); =20 - pci_read_config_word(pdev, pos + PCI_ACS_CTRL, &ctrl); + if (pci_read_config_word(pdev, pos + PCI_ACS_CTRL, &ctrl)) + return false; return (ctrl & acs_flags) =3D=3D acs_flags; } =20 diff --git a/drivers/pci/quirks.c b/drivers/pci/quirks.c index de9bbccda21f..d5c3e6802840 100644 --- a/drivers/pci/quirks.c +++ b/drivers/pci/quirks.c @@ -4992,10 +4992,12 @@ static int pci_quirk_intel_spt_pch_acs(struct pci_d= ev *dev, u16 acs_flags) return -ENOTTY; =20 /* see pci_acs_flags_enabled() */ - pci_read_config_dword(dev, pos + PCI_ACS_CAP, &cap); + if (pci_read_config_dword(dev, pos + PCI_ACS_CAP, &cap)) + return 0; acs_flags &=3D (cap | PCI_ACS_EC); =20 - pci_read_config_dword(dev, pos + INTEL_SPT_ACS_CTRL, &ctrl); + if (pci_read_config_dword(dev, pos + INTEL_SPT_ACS_CTRL, &ctrl)) + return 0; =20 return pci_acs_ctrl_enabled(acs_flags, ctrl); } --=20 2.55.0 From nobody Thu Sep 24 21:19:39 2026 Received: from smtp.kernel.org (aws-us-west-2-korg-mail-alma10-1.taild15c8.ts.net [100.103.45.18]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by smtp.subspace.kernel.org (Postfix) with ESMTPS id D691141D620; Sun, 20 Sep 2026 11:41:55 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=100.103.45.18 ARC-Seal: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1789904522; cv=none; b=G+DNQ68hEaGAeYQeut++73UXweDFqPuFs4aTJkt0GcnNFSSTCrpSI174w7IzIoauSfeii9F8eInbR+M8WAPVocAMqdGiDoA/FdFr94QRgqo1UJo4g92i3Q8Uzq0Wl7ANmGmoPQVqpO7ExrVb43IhvXgxAcO5wbQ3amk0TlE0Ku4= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1789904522; c=relaxed/simple; bh=0OXlrC2SeAnL13qvS43FM1ee/5BZiEd8vimpS0xOrMc=; h=From:To:Cc:Subject:Date:Message-ID:In-Reply-To:References: MIME-Version:Content-Type; b=N6egdSm0b/nD+npAxpBKmmtHRDf7NB5INRbbwzX6KSRRrQ8/tibOGyOGFAlqP52pR21BhFYDfjLL9R4Fa6JOSe27Eo98+BQRJFlOTUZAllif1wn93y+Jqop/GpnB7LijwMHkF6G5z1lRVgr3GqCtM2AyArRpRAihA6LCvoMFzgg= ARC-Authentication-Results: i=1; smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=kernel.org header.i=@kernel.org header.b=e1C8PvFb; arc=none smtp.client-ip=100.103.45.18 Authentication-Results: smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=kernel.org header.i=@kernel.org header.b="e1C8PvFb" Received: by smtp.kernel.org (Postfix) with ESMTPSA id EB99F1F000FF; Sun, 20 Sep 2026 11:41:54 +0000 (UTC) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=kernel.org; s=k20260515; t=1789904515; bh=NWdkiRcet/sX3Mzh02gDok5dMURhUNjj/n84+zYY09Q=; h=From:To:Cc:Subject:Date:In-Reply-To:References; b=e1C8PvFbUJFT8e393Pm6m63+iqauRcF8fNQbhVE6hyXsptNw4nnmzJn1MXcEUFtaj s6QqL8iq6munYtrHGwcLTJNdBquRynhVD96hIJItlRmwN1GF8+HDKJcCFSEAWRh+Pe +AgUbWv+BBzEDLZ0EJ/jjaTGG020LiqnYKvWBsUWc5+Ym3/bcNbRL1wD15Y+CG6Usx 9o1JNGwAGXltRsgA1aeS53aizdpQBxakWDqxHMlZkPMDWq9w1MAVe6PFH7rnvLAJE3 q3YcM2o4v1XDuvGu6C4ZQVnRvz4z6c/+cY3kZXmLxppkmjXGpZnTS9M+D7gXlm/t91 mlrPBXLrTpcNQ== From: Leon Romanovsky To: Bjorn Helgaas , Logan Gunthorpe , Chaitanya Kulkarni , Greg Kroah-Hartman , Jens Axboe , Alex Williamson , Leon Romanovsky , Ankit Agrawal , Jason Gunthorpe , Jonathan Corbet , Shuah Khan , "Joerg Roedel (AMD)" , Will Deacon , Robin Murphy , Randy Dunlap , Sumit Semwal , =?utf-8?q?Christian_K=C3=B6nig?= Cc: linux-pci@vger.kernel.org, linux-kernel@vger.kernel.org, linux-doc@vger.kernel.org, iommu@lists.linux.dev, Tushar Dave , 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 Subject: [PATCH v7 04/19] PCI/P2PDMA: Evaluate ACS controls at the path divergence Date: Sun, 20 Sep 2026 14:41:16 +0300 Message-ID: <20260920-fix-p2p-acs-v4-0-v7-4-ca0828ab697c@nvidia.com> X-Mailer: git-send-email 2.55.0 In-Reply-To: <20260920-fix-p2p-acs-v4-0-v7-0-ca0828ab697c@nvidia.com> References: <20260920-fix-p2p-acs-v4-0-v7-0-ca0828ab697c@nvidia.com> Precedence: bulk X-Mailing-List: linux-kernel@vger.kernel.org List-Id: List-Subscribe: List-Unsubscribe: MIME-Version: 1.0 Content-Type: text/plain; charset="utf-8" X-Mailer: b4 0.15-dev-18f8f Content-Transfer-Encoding: quoted-printable From: Leon Romanovsky ACS redirect controls choose between peer and upstream routes only at the path divergence. Applying them below that point rejects valid nested topologies because traffic already has only an upstream route. Evaluate Request controls on the client-side divergence port and Completion Redirect on the provider-side port and reject an unreadable ACS Control register. Fixes: 52916982af48 ("PCI/P2PDMA: Support peer-to-peer memory") Reviewed-by: Logan Gunthorpe Tested-by: Tushar Dave Signed-off-by: Leon Romanovsky --- drivers/pci/p2pdma.c | 101 +++++++++++++++++++++++++++++------------= ---- include/linux/pci-p2pdma.h | 8 ++-- 2 files changed, 70 insertions(+), 39 deletions(-) diff --git a/drivers/pci/p2pdma.c b/drivers/pci/p2pdma.c index 12612b82d80d..550e6c7346ef 100644 --- a/drivers/pci/p2pdma.c +++ b/drivers/pci/p2pdma.c @@ -493,6 +493,7 @@ static struct pci_dev *find_parent_pci_dev(struct devic= e *dev) } =20 enum pci_acs_p2pdma_state { + PCI_ACS_P2PDMA_NOT_SUPPORTED, PCI_ACS_P2PDMA_DIRECT, PCI_ACS_P2PDMA_REDIRECT, }; @@ -730,13 +731,13 @@ static unsigned long map_types_idx(struct pci_dev *cl= ient) * then to Device B. The mapping type returned depends on the ACS * redirection setting of the ports along the path. * - * The client initiates Requests to provider memory. Check Request Redirect - * on the client path and Completion Redirect for read Completions on the - * provider path. + * The client initiates Requests to provider memory. At the path divergenc= e, + * check Request Redirect and Egress Control on the client-side port, and + * Completion Redirect for read Completions on the provider-side port. * - * If ACS redirect is set on any port in the path, traffic between the - * devices will go through the host bridge, so return - * PCI_P2PDMA_MAP_THRU_HOST_BRIDGE; otherwise return + * If ACS redirects traffic at either divergence port, return + * PCI_P2PDMA_MAP_THRU_HOST_BRIDGE. If the ACS Control register cannot be + * read, return PCI_P2PDMA_MAP_NOT_SUPPORTED. Otherwise, return * PCI_P2PDMA_MAP_BUS_ADDR. * * Any two devices that have a data path that goes through the host bridge @@ -750,10 +751,13 @@ calc_map_type_and_dist(struct pci_dev *provider, stru= ct pci_dev *client, int *dist, bool verbose) { enum pci_p2pdma_map_type map_type =3D PCI_P2PDMA_MAP_THRU_HOST_BRIDGE; + enum pci_acs_p2pdma_state state =3D PCI_ACS_P2PDMA_NOT_SUPPORTED; struct pci_dev *a =3D provider, *b =3D client, *bb; + struct pci_dev *a_child =3D NULL, *b_child =3D NULL; + struct pci_dev *acs_unreadable =3D NULL; struct pci_p2pdma *p2pdma; struct seq_buf acs_list; - int acs_cnt =3D 0; + int acs_redirect_cnt =3D 0; int dist_a =3D 0; int dist_b =3D 0; char buf[128]; @@ -768,51 +772,67 @@ calc_map_type_and_dist(struct pci_dev *provider, stru= ct pci_dev *client, */ while (a) { dist_b =3D 0; - - if (!pci_acs_p2pdma_ctrl(a, &ctrl) || - pci_acs_p2pdma_completion(ctrl) =3D=3D - PCI_ACS_P2PDMA_REDIRECT) { - seq_buf_print_bus_devfn(&acs_list, a); - acs_cnt++; - } - + b_child =3D NULL; bb =3D b; =20 while (bb) { if (a =3D=3D bb) - goto check_b_path_acs; + goto check_paths_acs; =20 + b_child =3D bb; bb =3D pci_upstream_bridge(bb); dist_b++; } =20 + a_child =3D a; a =3D pci_upstream_bridge(a); dist_a++; } =20 + /* + * The paths share no upstream bridge, so there is no direct path for + * ACS to gate: PCI_P2PDMA_MAP_BUS_ADDR is not reachable here and the + * request can only get to the peer through the host bridge. + */ *dist =3D dist_a + dist_b; goto map_through_host_bridge; =20 -check_b_path_acs: - bb =3D b; - - while (bb) { - if (a =3D=3D bb) - break; +check_paths_acs: + *dist =3D dist_a + dist_b; =20 - if (!pci_acs_p2pdma_ctrl(bb, &ctrl) || - pci_acs_p2pdma_request(ctrl) =3D=3D - PCI_ACS_P2PDMA_REDIRECT) { - seq_buf_print_bus_devfn(&acs_list, bb); - acs_cnt++; + /* + * ACS P2P routing controls apply where a TLP can route toward the peer + * or upstream. Below that divergence, its only route toward the other + * 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 =3D pci_acs_p2pdma_completion(ctrl); + if (state !=3D PCI_ACS_P2PDMA_DIRECT) { + seq_buf_print_bus_devfn(&acs_list, a_child); + if (state =3D=3D PCI_ACS_P2PDMA_REDIRECT) + acs_redirect_cnt++; + else if (!acs_unreadable) + acs_unreadable =3D a_child; } =20 - bb =3D pci_upstream_bridge(bb); + state =3D PCI_ACS_P2PDMA_NOT_SUPPORTED; + if (pci_acs_p2pdma_ctrl(b_child, &ctrl)) + state =3D pci_acs_p2pdma_request(ctrl); + if (state !=3D PCI_ACS_P2PDMA_DIRECT) { + seq_buf_print_bus_devfn(&acs_list, b_child); + if (state =3D=3D PCI_ACS_P2PDMA_REDIRECT) + acs_redirect_cnt++; + else if (!acs_unreadable) + acs_unreadable =3D b_child; + } } =20 - *dist =3D dist_a + dist_b; - - if (!acs_cnt) { + /* + * 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 =3D PCI_P2PDMA_MAP_BUS_ADDR; goto done; } @@ -821,10 +841,21 @@ calc_map_type_and_dist(struct pci_dev *provider, stru= ct pci_dev *client, /* Drop the final semicolon; the list is not empty here. */ if (!seq_buf_has_overflowed(&acs_list)) acs_list.buffer[acs_list.len - 1] =3D '\0'; - pci_warn(client, "ACS redirect is set between the client and provider (%= s)\n", - pci_name(provider)); - pci_warn(client, "to disable ACS redirect for this path, add the kernel = parameter: pci=3Ddisable_acs_redir=3D%s\n", - seq_buf_str(&acs_list)); + 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=3Ddisable_acs_redir=3D%s\n", + seq_buf_str(&acs_list)); + } + } + + /* An unreadable control does not establish an upstream redirect. */ + if (acs_unreadable) { + map_type =3D PCI_P2PDMA_MAP_NOT_SUPPORTED; + goto done; } =20 map_through_host_bridge: diff --git a/include/linux/pci-p2pdma.h b/include/linux/pci-p2pdma.h index 873de20a2247..dd17501ba1b6 100644 --- a/include/linux/pci-p2pdma.h +++ b/include/linux/pci-p2pdma.h @@ -42,10 +42,10 @@ enum pci_p2pdma_map_type { PCI_P2PDMA_MAP_NONE, =20 /* - * PCI_P2PDMA_MAP_NOT_SUPPORTED: Indicates the transaction will - * traverse the host bridge and the host bridge is not in the - * allowlist. DMA Mapping routines should return an error when - * this is returned. + * PCI_P2PDMA_MAP_NOT_SUPPORTED: Indicates no safe mapping is available, + * for example because ACS blocks the direct path or the required host + * bridge is not in the allowlist. DMA Mapping routines should return an + * error when this is returned. */ PCI_P2PDMA_MAP_NOT_SUPPORTED, =20 --=20 2.55.0 From nobody Thu Sep 24 21:19:39 2026 Received: from smtp.kernel.org (aws-us-west-2-korg-mail-alma10-1.taild15c8.ts.net [100.103.45.18]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by smtp.subspace.kernel.org (Postfix) with ESMTPS id 7CF8B4266B9; Sun, 20 Sep 2026 11:42:15 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=100.103.45.18 ARC-Seal: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1789904537; cv=none; b=DuBGEvH64Ff8WfEXHF3ZszKrICPrFrZ3roMm+G9t3jDJO8m723z03AiQLQpAiN//MgeeQbifor+lylTRQWsSmYnRwM+O+ET+LN8NFy90pasKqs08BC+WN79ZEQ7jRggue2CZgo5MgOh0e3Fv4xnrIUTmkSwY/qKYJSMPacJRkMM= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1789904537; c=relaxed/simple; bh=71jVaBjyZuoLNNx+bNul7zhaxrvycDU4I/l4vBaY4CA=; h=From:To:Cc:Subject:Date:Message-ID:In-Reply-To:References: MIME-Version:Content-Type; b=NGeK/EAnmIEOraLvGi9DekwIArg9KEx5lXojv03Ode+MtmS5vizIjkimzTau/l8oj0y+5taRNBB6VgHZZxL8lcA5m/tSN5tL9QQe0+V/iKP1RjT/TnkAigeK87IeECySjVjAwNw05N1t/NSgwpfHMB9TQaTZTf087UBU5QFLy4M= ARC-Authentication-Results: i=1; smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=kernel.org header.i=@kernel.org header.b=O8gddd5m; arc=none smtp.client-ip=100.103.45.18 Authentication-Results: smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=kernel.org header.i=@kernel.org header.b="O8gddd5m" Received: by smtp.kernel.org (Postfix) with ESMTPSA id 742D01F000FF; Sun, 20 Sep 2026 11:42:14 +0000 (UTC) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=kernel.org; s=k20260515; t=1789904535; bh=NXMIcf51pqX530la2Oa4PtVUCCs8cvksEPgvaOoHW6w=; h=From:To:Cc:Subject:Date:In-Reply-To:References; b=O8gddd5mp15jUZ7kAPto2BM0TiYEG9lPjMo3u6tZV2oTCYB/z2oVvT7t55gHU2zHI qcIkOcLR2zMrIWygs1uIZXQcLoGEFnTc2f03QsJQCGlIIjv1JMHKqsOB2lbKioEr9O FN5BjV3Y1/HCnYpWUm6uNYl9uP2d1aGHOCvdmUjMHjPG8uYUHW5wQmZ5Dco0hvBU/q 5ewprFrKDxXjh8/K/DwCa8NAGqHHEA7YEb/nfJLHA9Ph5GWiSZqMTpug3uYgPcSxjn rZvDYzyMoM/SfOGbXd8mevmrcPx5veD+CJxu+iPq8E2tG+rxeXZgiCzQY0EKzndK4N PKUSne8y4blgw== From: Leon Romanovsky To: Bjorn Helgaas , Logan Gunthorpe , Chaitanya Kulkarni , Greg Kroah-Hartman , Jens Axboe , Alex Williamson , Leon Romanovsky , Ankit Agrawal , Jason Gunthorpe , Jonathan Corbet , Shuah Khan , "Joerg Roedel (AMD)" , Will Deacon , Robin Murphy , Randy Dunlap , Sumit Semwal , =?utf-8?q?Christian_K=C3=B6nig?= Cc: linux-pci@vger.kernel.org, linux-kernel@vger.kernel.org, linux-doc@vger.kernel.org, iommu@lists.linux.dev, Tushar Dave , 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 Subject: [PATCH v7 05/19] PCI/P2PDMA: Document directional ACS routing Date: Sun, 20 Sep 2026 14:41:17 +0300 Message-ID: <20260920-fix-p2p-acs-v4-0-v7-5-ca0828ab697c@nvidia.com> X-Mailer: git-send-email 2.55.0 In-Reply-To: <20260920-fix-p2p-acs-v4-0-v7-0-ca0828ab697c@nvidia.com> References: <20260920-fix-p2p-acs-v4-0-v7-0-ca0828ab697c@nvidia.com> Precedence: bulk X-Mailing-List: linux-kernel@vger.kernel.org List-Id: List-Subscribe: List-Unsubscribe: MIME-Version: 1.0 Content-Type: text/plain; charset="utf-8" X-Mailer: b4 0.15-dev-18f8f Content-Transfer-Encoding: quoted-printable From: Leon Romanovsky P2PDMA documentation describes ACS controls as path-wide, although Request and Completion controls apply to different transaction directions and only affect peer-versus-upstream decisions at the path divergence. Document the fixed client and provider roles, the divergence port checked for each TLP direction, and the conservative handling of unreadable ACS state. Clarify which controls disable_acs_redir changes. Reviewed-by: Logan Gunthorpe Tested-by: Tushar Dave Signed-off-by: Leon Romanovsky --- Documentation/admin-guide/kernel-parameters.txt | 15 +++++++++------ Documentation/driver-api/pci/p2pdma.rst | 13 +++++++++++++ 2 files changed, 22 insertions(+), 6 deletions(-) diff --git a/Documentation/admin-guide/kernel-parameters.txt b/Documentatio= n/admin-guide/kernel-parameters.txt index 68647ff4bdd2..bc83e07dd5fc 100644 --- a/Documentation/admin-guide/kernel-parameters.txt +++ b/Documentation/admin-guide/kernel-parameters.txt @@ -5291,12 +5291,15 @@ Kernel parameters disable_acs_redir=3D[; ...] Specify one or more PCI devices (in the format specified above) separated by semicolons. - Each device specified will have the PCI ACS - redirect capabilities forced off which will - allow P2P traffic between devices through - bridges without forcing it upstream. Note: - this removes isolation between devices and - may put more devices in an IOMMU group. + Each device specified will have the PCI ACS P2P + Request Redirect, Completion Redirect, and Egress + Control features forced off. This may allow P2P + traffic through bridges that would otherwise be + redirected upstream. This may allow P2P traffic + through bridges that would otherwise be redirected + upstream and thus this removes isolation between + devices and may cause affected devices to share + an IOMMU group. config_acs=3D Format: @[; ...] diff --git a/Documentation/driver-api/pci/p2pdma.rst b/Documentation/driver= -api/pci/p2pdma.rst index 80f8fec9b0e9..42b18610bf7d 100644 --- a/Documentation/driver-api/pci/p2pdma.rst +++ b/Documentation/driver-api/pci/p2pdma.rst @@ -15,6 +15,19 @@ then based on the ACS settings the transaction can route= entirely within the PCIe hierarchy and never reach the root port. The kernel will evaluate the PCIe topology and always permit P2P in these well-defined cases. =20 +The client remains the PCIe requester when it reads or writes provider mem= ory. +Where the paths diverge, the kernel therefore evaluates P2P Request Redire= ct +and Egress Control on the client-side port, and P2P Completion Redirect on= the +provider-side port for completions from a read. An enabled Egress Control = is +conservatively treated as a Request redirect. + +Below the divergence, the route toward the other branch is already upstrea= m, +so those P2P redirect controls do not affect it. Redirect controls for the +reverse transaction directions do not affect the mapping. P2P DMA is routed +through the host bridge when either applicable port redirects. If an ACS +Control register cannot be read, P2P DMA is rejected because the kernel ca= nnot +establish a usable route. + This evaluation assumes clients issue strictly ordered Requests carrying an Untranslated address. Its result is not defined when clients use Relaxed Ordering or issue ATS-translated Requests because those TLP attributes can --=20 2.55.0 From nobody Thu Sep 24 21:19:39 2026 Received: from smtp.kernel.org (aws-us-west-2-korg-mail-alma10-1.taild15c8.ts.net [100.103.45.18]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by smtp.subspace.kernel.org (Postfix) with ESMTPS id 9618341D23B; Sun, 20 Sep 2026 11:42:04 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=100.103.45.18 ARC-Seal: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1789904529; cv=none; b=fwu+n8Ec3MUTfPBMTdZr19lIfzW0kuu0xyIgEp12SbCLUv2ed+AL2Vw1WtCu3Yl+7Q0+9nxIGWYJ7JsnCEZjarlVwmzgLP4M7R6cU6tY5GrcCgF5Lh7dIv4VYPLVlyCTu0rKgC7L/LcgEOXm+xWGERUuFCDFK7UNQItofXlxMk0= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1789904529; c=relaxed/simple; bh=m/9dXXzylK1SrjgTUrcVbikEY6Zbzst47ERZoPzgAQg=; h=From:To:Cc:Subject:Date:Message-ID:In-Reply-To:References: MIME-Version:Content-Type; b=GptEXX/UBQWOn/h47RryF3GhiAmqpR86Q0iGOf7fDxHis27s9Wp397qu0Ekom8vRnUnV/qJs/xoGXxdceXBd8cLcNGDN/gXDPQfhAUmQrlW1u2aCvbRsuHj+20DVzFaEJkbWBZQjkLLCNJNxt5WHI0HwRLsxlOKlKLREHfR0/mE= ARC-Authentication-Results: i=1; smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=kernel.org header.i=@kernel.org header.b=n+ps1Ngb; arc=none smtp.client-ip=100.103.45.18 Authentication-Results: smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=kernel.org header.i=@kernel.org header.b="n+ps1Ngb" Received: by smtp.kernel.org (Postfix) with ESMTPSA id 466911F000FF; Sun, 20 Sep 2026 11:42:03 +0000 (UTC) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=kernel.org; s=k20260515; t=1789904524; bh=Z95hbdfgOpnr57c2fIo3qviMBbxUl2sFsECI1kVRitw=; h=From:To:Cc:Subject:Date:In-Reply-To:References; b=n+ps1Ngbv+noXq51uHbeyD6nyeAKcl5uxrYLJ8ncnRya2pq2lwsWpCSrkNnpRULRq F7g60j2HdXwnXQ7XnPcxosx0tq9X44gdHunSb9D6dylA2HToSRNH2lbxVfS08lP0UX ZzCbS5pT96rXJzhkDeLR4vkQiodugeJSTvII9aJiV/1GcXhfXhGYWqxI4aVZ01ss43 B+8vDoX0Q8v2lJxgSdutjjn0uSfr6lylPcnIracXjgfpeTtQNmprvA0zNHkk85yggN BPWfJUWnJIFqtXltILnvgAYdirSLPjUHj28I1MhfOILRNE0y7Q4M2F4qAa/1abGtUZ nC+LJn28sJklg== From: Leon Romanovsky To: Bjorn Helgaas , Logan Gunthorpe , Chaitanya Kulkarni , Greg Kroah-Hartman , Jens Axboe , Alex Williamson , Leon Romanovsky , Ankit Agrawal , Jason Gunthorpe , Jonathan Corbet , Shuah Khan , "Joerg Roedel (AMD)" , Will Deacon , Robin Murphy , Randy Dunlap , Sumit Semwal , =?utf-8?q?Christian_K=C3=B6nig?= Cc: linux-pci@vger.kernel.org, linux-kernel@vger.kernel.org, linux-doc@vger.kernel.org, iommu@lists.linux.dev, Tushar Dave , 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 Subject: [PATCH v7 06/19] PCI/P2PDMA: Collect the path's ACS controls before deciding Date: Sun, 20 Sep 2026 14:41:18 +0300 Message-ID: <20260920-fix-p2p-acs-v4-0-v7-6-ca0828ab697c@nvidia.com> X-Mailer: git-send-email 2.55.0 In-Reply-To: <20260920-fix-p2p-acs-v4-0-v7-0-ca0828ab697c@nvidia.com> References: <20260920-fix-p2p-acs-v4-0-v7-0-ca0828ab697c@nvidia.com> Precedence: bulk X-Mailing-List: linux-kernel@vger.kernel.org List-Id: List-Subscribe: List-Unsubscribe: MIME-Version: 1.0 Content-Type: text/plain; charset="utf-8" X-Mailer: b4 0.15-dev-18f8f Content-Transfer-Encoding: quoted-printable From: Leon Romanovsky 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. 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 Tested-by: Tushar Dave Signed-off-by: Leon Romanovsky --- 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 *bu= f, struct pci_dev *pdev) seq_buf_printf(buf, "%s;", pci_name(pdev)); } =20 +/* + * What the topology walk found out about one provider/client path. Produc= ing + * 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 f= or + * 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) =3D=3D PCI_ACS_P2PDMA_DIRECT && + pci_acs_p2pdma_completion(path->cpl_ctrl) =3D=3D PCI_ACS_P2PDMA_DIREC= T) + 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=3Ddisable_acs_redir=3D. + */ +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) !=3D PCI_ACS_P2PDMA_DIRECT) + seq_buf_print_bus_devfn(&acs_list, a_child); + if (pci_acs_p2pdma_request(path->req_ctrl) !=3D 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] =3D '\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= =3Ddisable_acs_redir=3D%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, stru= ct pci_dev *client, int *dist, bool verbose) { enum pci_p2pdma_map_type map_type =3D PCI_P2PDMA_MAP_THRU_HOST_BRIDGE; - enum pci_acs_p2pdma_state state =3D PCI_ACS_P2PDMA_NOT_SUPPORTED; struct pci_dev *a =3D provider, *b =3D client, *bb; struct pci_dev *a_child =3D NULL, *b_child =3D NULL; - struct pci_dev *acs_unreadable =3D NULL; + struct pci_p2pdma_acs_path path =3D {}; struct pci_p2pdma *p2pdma; - struct seq_buf acs_list; - int acs_redirect_cnt =3D 0; + bool cpu_p2pdma, host_whitelisted =3D false; int dist_a =3D 0; int dist_b =3D 0; - char buf[128]; - u16 ctrl; - - seq_buf_init(&acs_list, buf, sizeof(buf)); =20 /* * 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, stru= ct 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 =3D pci_acs_p2pdma_completion(ctrl); - if (state !=3D PCI_ACS_P2PDMA_DIRECT) { - seq_buf_print_bus_devfn(&acs_list, a_child); - if (state =3D=3D PCI_ACS_P2PDMA_REDIRECT) - acs_redirect_cnt++; - else if (!acs_unreadable) - acs_unreadable =3D a_child; - } - - state =3D PCI_ACS_P2PDMA_NOT_SUPPORTED; - if (pci_acs_p2pdma_ctrl(b_child, &ctrl)) - state =3D pci_acs_p2pdma_request(ctrl); - if (state !=3D PCI_ACS_P2PDMA_DIRECT) { - seq_buf_print_bus_devfn(&acs_list, b_child); - if (state =3D=3D PCI_ACS_P2PDMA_REDIRECT) - acs_redirect_cnt++; - else if (!acs_unreadable) - acs_unreadable =3D b_child; - } + if (!pci_acs_p2pdma_ctrl(a_child, &path.cpl_ctrl)) + path.unreadable =3D a_child; + if (!pci_acs_p2pdma_ctrl(b_child, &path.req_ctrl) && + !path.unreadable) + path.unreadable =3D b_child; } =20 /* * 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 =3D PCI_P2PDMA_MAP_BUS_ADDR; + map_type =3D pci_p2pdma_route(&path); + if (map_type =3D=3D PCI_P2PDMA_MAP_BUS_ADDR) goto done; - } =20 - 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] =3D '\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=3Ddisable_acs_redir=3D%s\n", - seq_buf_str(&acs_list)); - } - } + if (verbose) + pci_p2pdma_warn_path(client, provider, &path, a_child, b_child); =20 /* An unreadable control does not establish an upstream redirect. */ - if (acs_unreadable) { - map_type =3D PCI_P2PDMA_MAP_NOT_SUPPORTED; + if (path.unreadable) goto done; - } =20 map_through_host_bridge: - if (!cpu_supports_p2pdma() && - !host_bridge_whitelist(provider, client, verbose)) { + cpu_p2pdma =3D cpu_supports_p2pdma(); + if (!cpu_p2pdma) + host_whitelisted =3D 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 p= 2pdma_provider *provider, { enum pci_p2pdma_map_type type =3D PCI_P2PDMA_MAP_NOT_SUPPORTED; struct pci_dev *pdev =3D to_pci_dev(provider->owner); - struct pci_dev *client; struct pci_p2pdma *p2pdma; + unsigned long cache_index; + struct pci_dev *client; int dist; =20 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; =20 client =3D to_pci_dev(dev); + cache_index =3D map_types_idx(client); =20 rcu_read_lock(); p2pdma =3D rcu_dereference(pdev->p2pdma); =20 if (p2pdma) type =3D xa_to_value(xa_load(&p2pdma->map_types, - map_types_idx(client))); + cache_index)); rcu_read_unlock(); =20 if (type =3D=3D PCI_P2PDMA_MAP_UNKNOWN) --=20 2.55.0 From nobody Thu Sep 24 21:19:39 2026 Received: from smtp.kernel.org (aws-us-west-2-korg-mail-alma10-1.taild15c8.ts.net [100.103.45.18]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by smtp.subspace.kernel.org (Postfix) with ESMTPS id 1585641D201; Sun, 20 Sep 2026 11:42:07 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=100.103.45.18 ARC-Seal: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1789904531; cv=none; b=tVWAwPEiTiYNK8T2FQGjwpoLanEgcrgOhxEbOKo3jzvXqChxGdrGS8AyjPO1q9l0/rlqtdY/EseFA9oMK2U+rmcqgzw2ywCXigjPffF+4KsRlv4IMz9lLKej7y2NgFmbAN/p8xzIR4WUh+VId7VQ/C/tL4lcQ6ehdvIpZ68YLqw= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1789904531; c=relaxed/simple; bh=1k6IkPMjhdvK5IMoO7MrzmOmDE2/6gdVPiXj4Vf7CDI=; h=From:To:Cc:Subject:Date:Message-ID:In-Reply-To:References: MIME-Version:Content-Type; b=l9oZAH9bLUEBb6YICKIZysLXH9DWW3U+yUodN6C+dKlaKYQWKmTzsTzYA48wS0VUvvBuImAh/JnEKb3BocBY3f1mYJPGd4RdME7tYpv2uld2m1HYI60NlxLDXFrpGtWifgVX5vgCKCCTXL799Lp0xcvdFFGso6vRDIQ/SNy68MA= ARC-Authentication-Results: i=1; smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=kernel.org header.i=@kernel.org header.b=mFgwY0Px; arc=none smtp.client-ip=100.103.45.18 Authentication-Results: smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=kernel.org header.i=@kernel.org header.b="mFgwY0Px" Received: by smtp.kernel.org (Postfix) with ESMTPSA id 191C31F00899; Sun, 20 Sep 2026 11:42:07 +0000 (UTC) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=kernel.org; s=k20260515; t=1789904527; bh=mIu1BRrQ1dNy6GB1MbpLNkuO3YFqDUwCDbKBABgUfQM=; h=From:To:Cc:Subject:Date:In-Reply-To:References; b=mFgwY0Pxpz0yVIx8tET3FV58HhXfC53jSsKugFPvedLJl/UNRmK2cufBVL6/o3t/F Q2S/x9exOChlc9oT71Y2Ma8/3r2ZTbc84V1JRd9IgSuchbnjRzITm0CCIMjdu0bmeP b3MrwsopZ6C9WycVxWNM7XWX5M9z6ausbl7r5/ksrECtxjdFJDQj2XWZKYFuwpIecj N1G41h795vC+FGuUEFL6NMQMyVac7ZqG3Bo++M4Qu7cB9B55Zwj4B7ZOfkw4SgRhKP 51eYdqDNDOXzejzZOw2+OYZyxe55qZY34NbZtG493K+WA7IzxgUz+tqKimU8O4F4O4 hkZRw5OrFFCyA== From: Leon Romanovsky To: Bjorn Helgaas , Logan Gunthorpe , Chaitanya Kulkarni , Greg Kroah-Hartman , Jens Axboe , Alex Williamson , Leon Romanovsky , Ankit Agrawal , Jason Gunthorpe , Jonathan Corbet , Shuah Khan , "Joerg Roedel (AMD)" , Will Deacon , Robin Murphy , Randy Dunlap , Sumit Semwal , =?utf-8?q?Christian_K=C3=B6nig?= Cc: linux-pci@vger.kernel.org, linux-kernel@vger.kernel.org, linux-doc@vger.kernel.org, iommu@lists.linux.dev, Tushar Dave , 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 Subject: [PATCH v7 07/19] PCI/P2PDMA: Answer routing per TLP class Date: Sun, 20 Sep 2026 14:41:19 +0300 Message-ID: <20260920-fix-p2p-acs-v4-0-v7-7-ca0828ab697c@nvidia.com> X-Mailer: git-send-email 2.55.0 In-Reply-To: <20260920-fix-p2p-acs-v4-0-v7-0-ca0828ab697c@nvidia.com> References: <20260920-fix-p2p-acs-v4-0-v7-0-ca0828ab697c@nvidia.com> Precedence: bulk X-Mailing-List: linux-kernel@vger.kernel.org List-Id: List-Subscribe: List-Unsubscribe: MIME-Version: 1.0 Content-Type: text/plain; charset="utf-8" X-Mailer: b4 0.15-dev-18f8f Content-Transfer-Encoding: quoted-printable From: Leon Romanovsky calc_map_type_and_dist() returns one mapping type per provider and client, valid only for strictly ordered Requests carrying an Untranslated address. Clients that use Relaxed Ordering or ATS cannot ask what the fabric would do with their traffic. Add enum pci_p2pdma_tlp_flags to name a class and pci_p2pdma_map_type_tlp() to ask about one. The topology walk and the ACS Control reads do not depend on the class, so decide all of them from the one walk and cache them together, four bits each. Every class still answers alike; the controls that tell them apart come next. Tested-by: Tushar Dave Signed-off-by: Leon Romanovsky Reviewed-by: Logan Gunthorpe --- drivers/pci/p2pdma.c | 121 +++++++++++++++++++++++++++++++++--------= ---- include/linux/pci-p2pdma.h | 49 ++++++++++++++++-- 2 files changed, 136 insertions(+), 34 deletions(-) diff --git a/drivers/pci/p2pdma.c b/drivers/pci/p2pdma.c index 841c86be31bb..7e067e1331fa 100644 --- a/drivers/pci/p2pdma.c +++ b/drivers/pci/p2pdma.c @@ -508,7 +508,7 @@ enum pci_acs_p2pdma_state { * bus addressing be assumed. */ static enum pci_acs_p2pdma_state -pci_acs_p2pdma_request(u16 ctrl) +pci_acs_p2pdma_request(u16 ctrl, unsigned int tlp_flags) { return ctrl & (PCI_ACS_RR | PCI_ACS_EC) ? PCI_ACS_P2PDMA_REDIRECT : PCI_ACS_P2PDMA_DIRECT; @@ -520,7 +520,7 @@ pci_acs_p2pdma_request(u16 ctrl) * affects a Completion. */ static enum pci_acs_p2pdma_state -pci_acs_p2pdma_completion(u16 ctrl) +pci_acs_p2pdma_completion(u16 ctrl, unsigned int tlp_flags) { return ctrl & PCI_ACS_CR ? PCI_ACS_P2PDMA_REDIRECT : PCI_ACS_P2PDMA_DIRECT; @@ -577,13 +577,16 @@ struct pci_p2pdma_acs_path { * the peer's bus addresses. */ static enum pci_p2pdma_map_type -pci_p2pdma_route(const struct pci_p2pdma_acs_path *path) +pci_p2pdma_route(const struct pci_p2pdma_acs_path *path, + unsigned int tlp_flags) { if (path->unreadable) return PCI_P2PDMA_MAP_NOT_SUPPORTED; =20 - if (pci_acs_p2pdma_request(path->req_ctrl) =3D=3D PCI_ACS_P2PDMA_DIRECT && - pci_acs_p2pdma_completion(path->cpl_ctrl) =3D=3D PCI_ACS_P2PDMA_DIREC= T) + if (pci_acs_p2pdma_request(path->req_ctrl, tlp_flags) =3D=3D + PCI_ACS_P2PDMA_DIRECT && + pci_acs_p2pdma_completion(path->cpl_ctrl, tlp_flags) =3D=3D + PCI_ACS_P2PDMA_DIRECT) return PCI_P2PDMA_MAP_BUS_ADDR; =20 return PCI_P2PDMA_MAP_THRU_HOST_BRIDGE; @@ -591,7 +594,9 @@ pci_p2pdma_route(const struct pci_p2pdma_acs_path *path) =20 /* * Name the ports that keep this path off a direct route, so that the admin - * can hand them to pci=3Ddisable_acs_redir=3D. + * can hand them to pci=3Ddisable_acs_redir=3D. That parameter clears the + * redirect controls, which decide the default class, so that is the class + * this reports on. */ static void pci_p2pdma_warn_path(struct pci_dev *client, struct pci_dev *provider, @@ -610,9 +615,10 @@ static void pci_p2pdma_warn_path(struct pci_dev *clien= t, } =20 seq_buf_init(&acs_list, buf, sizeof(buf)); - if (pci_acs_p2pdma_completion(path->cpl_ctrl) !=3D PCI_ACS_P2PDMA_DIRECT) + if (pci_acs_p2pdma_completion(path->cpl_ctrl, 0) !=3D + PCI_ACS_P2PDMA_DIRECT) seq_buf_print_bus_devfn(&acs_list, a_child); - if (pci_acs_p2pdma_request(path->req_ctrl) !=3D PCI_ACS_P2PDMA_DIRECT) + if (pci_acs_p2pdma_request(path->req_ctrl, 0) !=3D PCI_ACS_P2PDMA_DIRECT) seq_buf_print_bus_devfn(&acs_list, b_child); =20 /* Drop the final semicolon; the list is not empty here. */ @@ -780,6 +786,31 @@ static unsigned long map_types_idx(struct pci_dev *cli= ent) return (pci_domain_nr(client->bus) << 16) | pci_dev_id(client); } =20 +/* + * One cache entry holds the routing of every TLP class, four bits each, + * indexed by the &enum pci_p2pdma_tlp_flags combination that selects it. = An + * absent entry reads back as PCI_P2PDMA_MAP_UNKNOWN in every class. + */ +static_assert(PCI_P2PDMA_MAP_THRU_HOST_BRIDGE < 16); + +static unsigned long +pci_p2pdma_map_types_pack(const enum pci_p2pdma_map_type *type) +{ + unsigned long val =3D 0; + unsigned int flags; + + for (flags =3D 0; flags < PCI_P2PDMA_TLP_CLASSES; flags++) + val |=3D (unsigned long)type[flags] << (flags * 4); + + return val; +} + +static enum pci_p2pdma_map_type +pci_p2pdma_map_types_unpack(unsigned long val, unsigned int tlp_flags) +{ + return (val >> (tlp_flags * 4)) & 0xf; +} + /* * Calculate the P2PDMA mapping type and distance between two PCI devices. * @@ -809,6 +840,10 @@ static unsigned long map_types_idx(struct pci_dev *cli= ent) * check Request Redirect and Egress Control on the client-side port, and * Completion Redirect for read Completions on the provider-side port. * + * Those controls apply to different TLPs, so every class named by &enum + * pci_p2pdma_tlp_flags is decided from the one walk and cached together; + * @tlp_flags selects which one is returned. + * * If ACS redirects traffic at either divergence port, return * PCI_P2PDMA_MAP_THRU_HOST_BRIDGE. If the ACS Control register cannot be * read, return PCI_P2PDMA_MAP_NOT_SUPPORTED. Otherwise, return @@ -822,14 +857,16 @@ static unsigned long map_types_idx(struct pci_dev *cl= ient) */ static enum pci_p2pdma_map_type calc_map_type_and_dist(struct pci_dev *provider, struct pci_dev *client, - int *dist, bool verbose) + int *dist, unsigned int tlp_flags, bool verbose) { - enum pci_p2pdma_map_type map_type =3D PCI_P2PDMA_MAP_THRU_HOST_BRIDGE; + enum pci_p2pdma_map_type map_type[PCI_P2PDMA_TLP_CLASSES]; struct pci_dev *a =3D provider, *b =3D client, *bb; struct pci_dev *a_child =3D NULL, *b_child =3D NULL; struct pci_p2pdma_acs_path path =3D {}; struct pci_p2pdma *p2pdma; bool cpu_p2pdma, host_whitelisted =3D false; + bool host_fallback =3D false; + unsigned int flags; int dist_a =3D 0; int dist_b =3D 0; =20 @@ -863,6 +900,8 @@ calc_map_type_and_dist(struct pci_dev *provider, struct= pci_dev *client, * request can only get to the peer through the host bridge. */ *dist =3D dist_a + dist_b; + for (flags =3D 0; flags < PCI_P2PDMA_TLP_CLASSES; flags++) + map_type[flags] =3D PCI_P2PDMA_MAP_THRU_HOST_BRIDGE; goto map_through_host_bridge; =20 check_paths_acs: @@ -882,18 +921,24 @@ calc_map_type_and_dist(struct pci_dev *provider, stru= ct pci_dev *client, } =20 /* - * Below a shared upstream bridge, a path whose divergence ports do not - * redirect routes the request directly. + * The walk and the config reads above serve every class; only the + * decision below depends on the kind of TLP being routed. */ - map_type =3D pci_p2pdma_route(&path); - if (map_type =3D=3D PCI_P2PDMA_MAP_BUS_ADDR) - goto done; + for (flags =3D 0; flags < PCI_P2PDMA_TLP_CLASSES; flags++) { + map_type[flags] =3D pci_p2pdma_route(&path, flags); + if (map_type[flags] =3D=3D PCI_P2PDMA_MAP_THRU_HOST_BRIDGE) + host_fallback =3D true; + } =20 - if (verbose) - pci_p2pdma_warn_path(client, provider, &path, a_child, b_child); + if (verbose && map_type[0] !=3D PCI_P2PDMA_MAP_BUS_ADDR) + pci_p2pdma_warn_path(client, provider, &path, a_child, + b_child); =20 - /* An unreadable control does not establish an upstream redirect. */ - if (path.unreadable) + /* + * Nothing needs the host bridge: the classes that did not get a direct + * route have no fallback that would use it. + */ + if (!host_fallback) goto done; =20 map_through_host_bridge: @@ -906,16 +951,19 @@ calc_map_type_and_dist(struct pci_dev *provider, stru= ct pci_dev *client, 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)); - map_type =3D PCI_P2PDMA_MAP_NOT_SUPPORTED; + for (flags =3D 0; flags < PCI_P2PDMA_TLP_CLASSES; flags++) + if (map_type[flags] =3D=3D PCI_P2PDMA_MAP_THRU_HOST_BRIDGE) + map_type[flags] =3D PCI_P2PDMA_MAP_NOT_SUPPORTED; } done: rcu_read_lock(); p2pdma =3D rcu_dereference(provider->p2pdma); if (p2pdma) xa_store(&p2pdma->map_types, map_types_idx(client), - xa_mk_value(map_type), GFP_ATOMIC); + xa_mk_value(pci_p2pdma_map_types_pack(map_type)), + GFP_ATOMIC); rcu_read_unlock(); - return map_type; + return map_type[tlp_flags]; } =20 /** @@ -956,7 +1004,7 @@ int pci_p2pdma_distance_many(struct pci_dev *provider,= struct device **clients, return -1; } =20 - map =3D calc_map_type_and_dist(provider, pci_client, &distance, + map =3D calc_map_type_and_dist(provider, pci_client, &distance, 0, verbose); =20 pci_dev_put(pci_client); @@ -1221,25 +1269,34 @@ void pci_p2pmem_publish(struct pci_dev *pdev, bool = publish) EXPORT_SYMBOL_GPL(pci_p2pmem_publish); =20 /** - * pci_p2pdma_map_type - Determine the mapping type for P2PDMA transfers + * pci_p2pdma_map_type_tlp - Determine the mapping type for P2PDMA transfe= rs * @provider: P2PDMA provider structure * @dev: Client device that initiates the transfer + * @tlp_flags: &enum pci_p2pdma_tlp_flags describing the TLPs @dev will is= sue * * Determines how peer-to-peer DMA transfers should be mapped between * the provider and the client device. The mapping type indicates whether * the transfer can be done directly through PCI switches or must go * through the host bridge. + * + * ACS routes a peer-to-peer transaction by the attributes its TLPs carry,= so + * the answer depends on @tlp_flags. A caller that passes flags its traffic + * does not match gets a mapping the fabric will not deliver. */ -enum pci_p2pdma_map_type pci_p2pdma_map_type(struct p2pdma_provider *provi= der, - struct device *dev) +enum pci_p2pdma_map_type +pci_p2pdma_map_type_tlp(struct p2pdma_provider *provider, struct device *d= ev, + unsigned int tlp_flags) { - enum pci_p2pdma_map_type type =3D PCI_P2PDMA_MAP_NOT_SUPPORTED; struct pci_dev *pdev =3D to_pci_dev(provider->owner); + unsigned long cache_index, cached =3D 0; + enum pci_p2pdma_map_type type; struct pci_p2pdma *p2pdma; - unsigned long cache_index; struct pci_dev *client; int dist; =20 + if (WARN_ON_ONCE(tlp_flags >=3D PCI_P2PDMA_TLP_CLASSES)) + return PCI_P2PDMA_MAP_NOT_SUPPORTED; + if (!pdev->p2pdma) return PCI_P2PDMA_MAP_NOT_SUPPORTED; =20 @@ -1253,12 +1310,14 @@ enum pci_p2pdma_map_type pci_p2pdma_map_type(struct= p2pdma_provider *provider, p2pdma =3D rcu_dereference(pdev->p2pdma); =20 if (p2pdma) - type =3D xa_to_value(xa_load(&p2pdma->map_types, - cache_index)); + cached =3D xa_to_value(xa_load(&p2pdma->map_types, + cache_index)); rcu_read_unlock(); + type =3D pci_p2pdma_map_types_unpack(cached, tlp_flags); =20 if (type =3D=3D PCI_P2PDMA_MAP_UNKNOWN) - return calc_map_type_and_dist(pdev, client, &dist, true); + return calc_map_type_and_dist(pdev, client, &dist, tlp_flags, + true); =20 return type; } diff --git a/include/linux/pci-p2pdma.h b/include/linux/pci-p2pdma.h index dd17501ba1b6..36045b1b730c 100644 --- a/include/linux/pci-p2pdma.h +++ b/include/linux/pci-p2pdma.h @@ -28,6 +28,33 @@ struct p2pdma_provider { u64 bus_offset; }; =20 +/** + * enum pci_p2pdma_tlp_flags - Properties of the TLPs a client will issue + * + * These describe the traffic rather than the topology, and select which A= CS + * controls apply along the peer-to-peer path. A value of 0 means strictly + * ordered Requests carrying an Untranslated address. + * + * @PCI_P2PDMA_TLP_TRANSLATED: Requests carry an ATS Translated address. P= CIe + * r7.0 sec 6.12.3 routes those to the peer regardless of ACS P2P Request + * Redirect and ACS P2P Egress Control wherever ACS Direct Translated P2P + * is enabled. + * @PCI_P2PDMA_TLP_RELAXED_CPL: The provider returns Completions with the + * Relaxed Ordering attribute set. PCIe r7.0 sec 6.12.1.1 never redirects + * those, so ACS P2P Completion Redirect does not gate the path. The + * Completer chooses this attribute and the specification does not require + * it to copy Relaxed Ordering from the Request into the Completion, so a + * caller passing this flag asserts that its provider does. + */ +enum pci_p2pdma_tlp_flags { + PCI_P2PDMA_TLP_TRANSLATED =3D 1 << 0, + PCI_P2PDMA_TLP_RELAXED_CPL =3D 1 << 1, +}; + +/* Every combination of the flags above selects one routing class. */ +#define PCI_P2PDMA_TLP_CLASSES \ + ((PCI_P2PDMA_TLP_TRANSLATED | PCI_P2PDMA_TLP_RELAXED_CPL) + 1) + enum pci_p2pdma_map_type { /* * PCI_P2PDMA_MAP_UNKNOWN: Used internally as an initial state before @@ -86,8 +113,9 @@ int pci_p2pdma_enable_store(const char *page, struct pci= _dev **p2p_dev, bool *use_p2pdma); ssize_t pci_p2pdma_enable_show(char *page, struct pci_dev *p2p_dev, bool use_p2pdma); -enum pci_p2pdma_map_type pci_p2pdma_map_type(struct p2pdma_provider *provi= der, - struct device *dev); +enum pci_p2pdma_map_type +pci_p2pdma_map_type_tlp(struct p2pdma_provider *provider, struct device *d= ev, + unsigned int tlp_flags); #else /* CONFIG_PCI_P2PDMA */ static inline int pcim_p2pdma_init(struct pci_dev *pdev) { @@ -150,7 +178,8 @@ static inline ssize_t pci_p2pdma_enable_show(char *page, return sprintf(page, "none\n"); } static inline enum pci_p2pdma_map_type -pci_p2pdma_map_type(struct p2pdma_provider *provider, struct device *dev) +pci_p2pdma_map_type_tlp(struct p2pdma_provider *provider, struct device *d= ev, + unsigned int tlp_flags) { return PCI_P2PDMA_MAP_NOT_SUPPORTED; } @@ -168,6 +197,20 @@ static inline struct pci_dev *pci_p2pmem_find(struct d= evice *client) return pci_p2pmem_find_many(&client, 1); } =20 +/** + * pci_p2pdma_map_type - Determine the mapping type for P2PDMA transfers + * @provider: P2PDMA provider structure + * @dev: Client device that initiates the transfer + * + * Same as pci_p2pdma_map_type_tlp() for a client issuing strictly ordered + * Requests that carry an Untranslated address. + */ +static inline enum pci_p2pdma_map_type +pci_p2pdma_map_type(struct p2pdma_provider *provider, struct device *dev) +{ + return pci_p2pdma_map_type_tlp(provider, dev, 0); +} + struct pci_p2pdma_map_state { struct p2pdma_provider *mem; enum pci_p2pdma_map_type map; --=20 2.55.0 From nobody Thu Sep 24 21:19:39 2026 Received: from smtp.kernel.org (aws-us-west-2-korg-mail-alma10-1.taild15c8.ts.net [100.103.45.18]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by smtp.subspace.kernel.org (Postfix) with ESMTPS id 585D7422E34; Sun, 20 Sep 2026 11:42:11 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=100.103.45.18 ARC-Seal: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1789904533; cv=none; b=PN+4UtA02P41G1eAh0WnQv4MLnfGlXzw1pPNM+rbdvJAq5zLd7RZafuTtP5nG22L6xLZYpcxLTt78FIY5jA9x0bZKdRKJ9rSowdYx27vLewW2+RPWLsTCeydEkpKbf89vqGC5yfUrh48mI2anMarWz3FdiX8bl6oWv2lLKf90ko= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1789904533; c=relaxed/simple; bh=3CbO+X138z9WBErboej9RFc9J/ikiZ8eNlVagy2nQbI=; h=From:To:Cc:Subject:Date:Message-ID:In-Reply-To:References: MIME-Version:Content-Type; b=vFHVPE92qSubywmULTv4X+gW6+PlmnVuHdyhvV1FqrHjQbodZkpPPyvckUcara0FPkjbHOj8u4kTq4KsxdBKWnxnbAN0WCJT11AsyFkOSm1VEbMwO8CcIv9MaFpHYJ1JtQl1fw03CMWG2WBK7TjgK3y2ECVrix/gftDapY+YrDc= ARC-Authentication-Results: i=1; smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=kernel.org header.i=@kernel.org header.b=AIckF1HI; arc=none smtp.client-ip=100.103.45.18 Authentication-Results: smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=kernel.org header.i=@kernel.org header.b="AIckF1HI" Received: by smtp.kernel.org (Postfix) with ESMTPSA id B37371F000FF; Sun, 20 Sep 2026 11:42:10 +0000 (UTC) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=kernel.org; s=k20260515; t=1789904531; bh=SuncNYeOTYCFrmur6x8EWT3Z+JU509LogGMtfMK+Q7Y=; h=From:To:Cc:Subject:Date:In-Reply-To:References; b=AIckF1HIQkb6qFGr7RTuYXXmhMjF9JAufH0GFDLcnYLngeqx9h+a3F2NIAkVi/wAq f14siGd3D40SaMdtNW75kStQnzDQIvUIgPWBTz+1RTOzyXmaxZuTSY1Vz0/gAnSCeR xD51JrVmCr64UySw47WcK4yY9BtfxHzmqcPcaO5ETi9oa3tuJopz5A6EI1ySrBcKml ABcGbSqNNiU5HfT3/HS3+KlVu88PQgAEs9AwGSOE7ogIdx3QMUjTD4MxxClw2N9tYB 1cZUEoD7Ur8ai0hrXCwhTVTO0/wmHrh77Ksjcm2T+vWN+EETB6DIcIaCM8a+ngkdl9 fHTHSF2JrpKbg== From: Leon Romanovsky To: Bjorn Helgaas , Logan Gunthorpe , Chaitanya Kulkarni , Greg Kroah-Hartman , Jens Axboe , Alex Williamson , Leon Romanovsky , Ankit Agrawal , Jason Gunthorpe , Jonathan Corbet , Shuah Khan , "Joerg Roedel (AMD)" , Will Deacon , Robin Murphy , Randy Dunlap , Sumit Semwal , =?utf-8?q?Christian_K=C3=B6nig?= Cc: linux-pci@vger.kernel.org, linux-kernel@vger.kernel.org, linux-doc@vger.kernel.org, iommu@lists.linux.dev, Tushar Dave , 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 Subject: [PATCH v7 08/19] PCI/P2PDMA: Route Relaxed Ordering Completions directly Date: Sun, 20 Sep 2026 14:41:20 +0300 Message-ID: <20260920-fix-p2p-acs-v4-0-v7-8-ca0828ab697c@nvidia.com> X-Mailer: git-send-email 2.55.0 In-Reply-To: <20260920-fix-p2p-acs-v4-0-v7-0-ca0828ab697c@nvidia.com> References: <20260920-fix-p2p-acs-v4-0-v7-0-ca0828ab697c@nvidia.com> Precedence: bulk X-Mailing-List: linux-kernel@vger.kernel.org List-Id: List-Subscribe: List-Unsubscribe: MIME-Version: 1.0 Content-Type: text/plain; charset="utf-8" X-Mailer: b4 0.15-dev-18f8f Content-Transfer-Encoding: quoted-printable From: Leon Romanovsky ACS P2P Completion Redirect leaves Completions carrying the Relaxed Ordering attribute alone. PCIe r7.0 sec 6.12.1.1 redirects only those "that do not have the Relaxed Ordering Attribute bit set", and sec 7.7.12.5 describes the enable bit as "applicable only to Completions whose Relaxed Ordering Attribute is clear". P2PDMA reports one answer for every kind of TLP, so a client whose provider returns such Completions is sent through the host bridge for a redirect that never happens to it. Add enum pci_p2pdma_tlp_flags and let a caller state that property. Reviewed-by: Logan Gunthorpe Tested-by: Tushar Dave Signed-off-by: Leon Romanovsky --- drivers/pci/p2pdma.c | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/drivers/pci/p2pdma.c b/drivers/pci/p2pdma.c index 7e067e1331fa..3e5262a5265a 100644 --- a/drivers/pci/p2pdma.c +++ b/drivers/pci/p2pdma.c @@ -517,11 +517,15 @@ pci_acs_p2pdma_request(u16 ctrl, unsigned int tlp_fla= gs) /* * Decide how a peer-to-peer Completion at an ACS-capable ingress port rou= tes. * PCIe r7.0 sec 6.12.1.1: no ACS control other than P2P Completion Redire= ct - * affects a Completion. + * affects a Completion, and that one leaves Completions carrying the Rela= xed + * Ordering attribute alone. */ static enum pci_acs_p2pdma_state pci_acs_p2pdma_completion(u16 ctrl, unsigned int tlp_flags) { + if (tlp_flags & PCI_P2PDMA_TLP_RELAXED_CPL) + return PCI_ACS_P2PDMA_DIRECT; + return ctrl & PCI_ACS_CR ? PCI_ACS_P2PDMA_REDIRECT : PCI_ACS_P2PDMA_DIRECT; } --=20 2.55.0 From nobody Thu Sep 24 21:19:39 2026 Received: from smtp.kernel.org (aws-us-west-2-korg-mail-alma10-1.taild15c8.ts.net [100.103.45.18]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by smtp.subspace.kernel.org (Postfix) with ESMTPS id 0F46F425872; Sun, 20 Sep 2026 11:42:33 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=100.103.45.18 ARC-Seal: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1789904555; cv=none; b=pwnCGgfXJPS957QdNKcCHIEcNA8/vTpyl8s5oOPnMaPN202pZj/av6dUlYUSWcbEa6MqlVgVpwhphDbJq7bxNZ5TuqyqhuWynpU9TFxwqOU5hQJGv5wLk3pPKHhQ2+jgwTPe9UsqTrEWzwEX3jNjiIguqlpy/hz5cjrCOfbkpGM= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1789904555; c=relaxed/simple; bh=mP9GY8zvg3XC9BdD97szM1l9xD9j4HHCg9TdANMh88c=; h=From:To:Cc:Subject:Date:Message-ID:In-Reply-To:References: MIME-Version:Content-Type; b=aytVq4FPMnz1DqvtRNJXV6kEvCkaDdyx1kKqm3NOZfNtq0Sj7NPZP9DB59rLLB1glxOH9sbZreQnN+pTm+QFOnign1OdlXKJqEODN580D2Z3KBYJvDjIIn/TZlCxpVBczltA2OW6p8Jhwzym/Oad5u6piQJOXF1F6cX5kr2gRcs= ARC-Authentication-Results: i=1; smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=kernel.org header.i=@kernel.org header.b=kOdos1s6; arc=none smtp.client-ip=100.103.45.18 Authentication-Results: smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=kernel.org header.i=@kernel.org header.b="kOdos1s6" Received: by smtp.kernel.org (Postfix) with ESMTPSA id B25401F00898; Sun, 20 Sep 2026 11:42:31 +0000 (UTC) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=kernel.org; s=k20260515; t=1789904552; bh=87lhp9r4MoscZ3UnJr1MzYAOKK3ZWyNcgC1BxUkuEiQ=; h=From:To:Cc:Subject:Date:In-Reply-To:References; b=kOdos1s6LyBPEdVA2Z+gKZbhkw7PruJwGnjWLn6w6YF+OpIgJk1S3GhLiYQ5MjDNg fIBsLlwSKPxvbZbl/ZDlFWfaenzEFpmD7gb5MJdGvoTtB+dJz2pDpoaaEJMpMSjt22 czytU/1Ypc5s2nYMTVL2r6RdWIq9jFsxZW4EW0qH7RNzTBPkF1v5hvrz2GvWKXtn0I I7EvIEPdO9d+ZfHE1RkcVtDy0e7FM0xtg+GKkBGAGMsJ9X/4d5tci65Bg31EaBtkSh gAQityVVNC1URilwHh2/nZdnqMQNMWU2PWk4G90MubhUUyTfk78enNPoLRfHDF88Qf 83ixL5RoyCCaA== From: Leon Romanovsky To: Bjorn Helgaas , Logan Gunthorpe , Chaitanya Kulkarni , Greg Kroah-Hartman , Jens Axboe , Alex Williamson , Leon Romanovsky , Ankit Agrawal , Jason Gunthorpe , Jonathan Corbet , Shuah Khan , "Joerg Roedel (AMD)" , Will Deacon , Robin Murphy , Randy Dunlap , Sumit Semwal , =?utf-8?q?Christian_K=C3=B6nig?= Cc: linux-pci@vger.kernel.org, linux-kernel@vger.kernel.org, linux-doc@vger.kernel.org, iommu@lists.linux.dev, Tushar Dave , 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 Subject: [PATCH v7 09/19] PCI/P2PDMA: Reject Translated Requests blocked by Translation Blocking Date: Sun, 20 Sep 2026 14:41:21 +0300 Message-ID: <20260920-fix-p2p-acs-v4-0-v7-9-ca0828ab697c@nvidia.com> X-Mailer: git-send-email 2.55.0 In-Reply-To: <20260920-fix-p2p-acs-v4-0-v7-0-ca0828ab697c@nvidia.com> References: <20260920-fix-p2p-acs-v4-0-v7-0-ca0828ab697c@nvidia.com> Precedence: bulk X-Mailing-List: linux-kernel@vger.kernel.org List-Id: List-Subscribe: List-Unsubscribe: MIME-Version: 1.0 Content-Type: text/plain; charset="utf-8" X-Mailer: b4 0.15-dev-18f8f Content-Transfer-Encoding: quoted-printable From: Leon Romanovsky A Downstream Port with ACS Translation Blocking enabled treats every Upstream Memory Request whose Address Type is not Untranslated as an ACS Violation, ahead of "any applicable ACS P2P control mechanisms" per PCIe r7.0 sec 6.12.1.1. P2PDMA never looks at that bit, so it reports a bus-addressable path where an ATS client's Requests would be rejected. Add PCI_ACS_P2PDMA_BLOCKED, and because blocking is not a routing control, scan the path for it rather than the divergence port alone. A blocked Request has no host bridge fallback, since the Address Type is rejected wherever the Request is addressed. The two routes do not pass the same ports, so scan them separately. A direct route turns around at the divergence and only passes the ports below it, while the host bridge route keeps climbing and passes that port and everything above it as well. Tested-by: Tushar Dave Signed-off-by: Leon Romanovsky Reviewed-by: Logan Gunthorpe --- drivers/pci/p2pdma.c | 120 +++++++++++++++++++++++++++++++++++++++++++++++= ---- 1 file changed, 112 insertions(+), 8 deletions(-) diff --git a/drivers/pci/p2pdma.c b/drivers/pci/p2pdma.c index 3e5262a5265a..839285b77b62 100644 --- a/drivers/pci/p2pdma.c +++ b/drivers/pci/p2pdma.c @@ -496,11 +496,12 @@ enum pci_acs_p2pdma_state { PCI_ACS_P2PDMA_NOT_SUPPORTED, PCI_ACS_P2PDMA_DIRECT, PCI_ACS_P2PDMA_REDIRECT, + PCI_ACS_P2PDMA_BLOCKED, }; =20 /* * Decide how a peer-to-peer Request at an ACS-capable ingress port routes, - * from that port's ACS Control register. + * from that port's ACS Control register and the Request's Address Type. * * Linux does not read the Egress Control Vector, so Egress Control is tre= ated * conservatively as a redirect. Per PCIe r7.0 Table 6-11 the outcomes it @@ -510,6 +511,18 @@ enum pci_acs_p2pdma_state { static enum pci_acs_p2pdma_state pci_acs_p2pdma_request(u16 ctrl, unsigned int tlp_flags) { + if (tlp_flags & PCI_P2PDMA_TLP_TRANSLATED) { + /* + * PCIe r7.0 sec 6.12.1.1: Translation Blocking makes every + * Upstream Memory Request whose Address Type is not + * Untranslated an ACS Violation, taking precedence over the + * P2P controls. Sec 7.7.12.5: Direct Translated P2P "is + * ignored if ACS Translation Blocking Enable is 1b". + */ + if (ctrl & PCI_ACS_TB) + return PCI_ACS_P2PDMA_BLOCKED; + } + return ctrl & (PCI_ACS_RR | PCI_ACS_EC) ? PCI_ACS_P2PDMA_REDIRECT : PCI_ACS_P2PDMA_DIRECT; } @@ -549,6 +562,39 @@ static bool pci_acs_p2pdma_ctrl(struct pci_dev *pdev, = u16 *ctrl) return !pci_read_config_word(pdev, pos + PCI_ACS_CTRL, ctrl); } =20 +/* + * Report whether any port between @client and @common rejects Translated + * addresses. @common is NULL to walk every port up to the host bridge. A = port + * whose ACS Control cannot be read counts as blocking, which withdraws on= ly + * the Translated classes because an Untranslated Request is routed by the + * redirect controls instead. + */ +static bool pci_p2pdma_path_blocks_translation(struct pci_dev *client, + struct pci_dev *common) +{ + struct pci_dev *pdev; + u16 ctrl; + + /* + * @common is @client itself when the provider is the client or sits + * below it. The Request never travels upstream then, so no port sees + * it and none can reject its Address Type. + */ + if (client =3D=3D common) + return false; + + for (pdev =3D pci_upstream_bridge(client); pdev && pdev !=3D common; + pdev =3D pci_upstream_bridge(pdev)) { + if (!pci_acs_p2pdma_ctrl(pdev, &ctrl)) + return true; + + if (ctrl & PCI_ACS_TB) + return true; + } + + return false; +} + static void seq_buf_print_bus_devfn(struct seq_buf *buf, struct pci_dev *p= dev) { if (!buf) @@ -567,14 +613,42 @@ static void seq_buf_print_bus_devfn(struct seq_buf *b= uf, struct pci_dev *pdev) * than upstream, so it is where the Request controls apply. * @cpl_ctrl: ACS Control of the provider-side divergence port, likewise f= or * the Completions travelling back. + * @tb_on_path: A port below the divergence blocks Translated addresses. + * Every route out of @client passes those, so none carries them. + * @tb_above_divergence: A port at or above the divergence blocks Translat= ed + * addresses. Only a Request continuing to the host bridge passes + * those, so a direct route is still open to them. + * @no_common_bridge: The two paths share no upstream bridge, so no direct + * route exists for ACS to gate. * @unreadable: First port whose ACS Control could not be read, if any. */ struct pci_p2pdma_acs_path { u16 req_ctrl; u16 cpl_ctrl; + bool tb_on_path; + bool tb_above_divergence; + bool no_common_bridge; struct pci_dev *unreadable; }; =20 +/* + * ACS Translation Blocking is not a routing control, so unlike the redire= ct + * controls it is not decided at the divergence alone. PCIe r7.0 sec 6.12.= 1.1 + * has every Downstream Port check the Address Type of each Upstream Memory + * Request it receives, ahead of "any applicable ACS P2P control mechanism= s". + * A port below the divergence cannot redirect the Request anywhere it was= not + * already going, but it can still reject a Translated address. + */ +static enum pci_acs_p2pdma_state +pci_p2pdma_request_state(const struct pci_p2pdma_acs_path *path, + unsigned int tlp_flags) +{ + if (tlp_flags & PCI_P2PDMA_TLP_TRANSLATED && path->tb_on_path) + return PCI_ACS_P2PDMA_BLOCKED; + + return pci_acs_p2pdma_request(path->req_ctrl, tlp_flags); +} + /* * Combine both directions into a mapping type. Only a path that routes the * Request and the Completions it generates directly can be programmed with @@ -584,15 +658,35 @@ static enum pci_p2pdma_map_type pci_p2pdma_route(const struct pci_p2pdma_acs_path *path, unsigned int tlp_flags) { + enum pci_acs_p2pdma_state req; + if (path->unreadable) return PCI_P2PDMA_MAP_NOT_SUPPORTED; =20 - if (pci_acs_p2pdma_request(path->req_ctrl, tlp_flags) =3D=3D - PCI_ACS_P2PDMA_DIRECT && + req =3D pci_p2pdma_request_state(path, tlp_flags); + + /* + * Translation Blocking rejects the Address Type rather than the + * target, so a blocked Request stays blocked however it is addressed. + * No host bridge fallback keeps a Translated address working; the + * caller has to issue a different kind of Request instead. + */ + if (req =3D=3D PCI_ACS_P2PDMA_BLOCKED) + return PCI_P2PDMA_MAP_NOT_SUPPORTED; + + if (!path->no_common_bridge && req =3D=3D PCI_ACS_P2PDMA_DIRECT && pci_acs_p2pdma_completion(path->cpl_ctrl, tlp_flags) =3D=3D PCI_ACS_P2PDMA_DIRECT) return PCI_P2PDMA_MAP_BUS_ADDR; =20 + /* + * A Request that turns around at the divergence never reaches the + * ports above it, but one that keeps climbing to the host bridge + * does, so that route has to clear their Translation Blocking too. + */ + if (tlp_flags & PCI_P2PDMA_TLP_TRANSLATED && path->tb_above_divergence) + return PCI_P2PDMA_MAP_NOT_SUPPORTED; + return PCI_P2PDMA_MAP_THRU_HOST_BRIDGE; } =20 @@ -841,8 +935,11 @@ pci_p2pdma_map_types_unpack(unsigned long val, unsigne= d int tlp_flags) * redirection setting of the ports along the path. * * The client initiates Requests to provider memory. At the path divergenc= e, - * check Request Redirect and Egress Control on the client-side port, and - * Completion Redirect for read Completions on the provider-side port. + * check Request Redirect, Egress Control, Translation Blocking and Direct + * Translated P2P on the client-side port, and Completion Redirect for read + * Completions on the provider-side port. Translation Blocking is checked = on + * every client-side port instead, because it rejects a Request rather than + * routing it. * * Those controls apply to different TLPs, so every class named by &enum * pci_p2pdma_tlp_flags is decided from the one walk and cached together; @@ -850,8 +947,8 @@ pci_p2pdma_map_types_unpack(unsigned long val, unsigned= int tlp_flags) * * If ACS redirects traffic at either divergence port, return * PCI_P2PDMA_MAP_THRU_HOST_BRIDGE. If the ACS Control register cannot be - * read, return PCI_P2PDMA_MAP_NOT_SUPPORTED. Otherwise, return - * PCI_P2PDMA_MAP_BUS_ADDR. + * read, or Translation Blocking rejects the class being asked about, retu= rn + * PCI_P2PDMA_MAP_NOT_SUPPORTED. Otherwise, return PCI_P2PDMA_MAP_BUS_ADDR. * * Any two devices that have a data path that goes through the host bridge * will consult a whitelist. If the host bridge is in the whitelist, return @@ -904,8 +1001,10 @@ calc_map_type_and_dist(struct pci_dev *provider, stru= ct pci_dev *client, * request can only get to the peer through the host bridge. */ *dist =3D dist_a + dist_b; + path.no_common_bridge =3D true; + path.tb_on_path =3D pci_p2pdma_path_blocks_translation(client, NULL); for (flags =3D 0; flags < PCI_P2PDMA_TLP_CLASSES; flags++) - map_type[flags] =3D PCI_P2PDMA_MAP_THRU_HOST_BRIDGE; + map_type[flags] =3D pci_p2pdma_route(&path, flags); goto map_through_host_bridge; =20 check_paths_acs: @@ -924,6 +1023,11 @@ calc_map_type_and_dist(struct pci_dev *provider, stru= ct pci_dev *client, path.unreadable =3D b_child; } =20 + path.tb_on_path =3D pci_p2pdma_path_blocks_translation(client, a); + if (b_child) + path.tb_above_divergence =3D + pci_p2pdma_path_blocks_translation(b_child, NULL); + /* * The walk and the config reads above serve every class; only the * decision below depends on the kind of TLP being routed. --=20 2.55.0 From nobody Thu Sep 24 21:19:39 2026 Received: from smtp.kernel.org (aws-us-west-2-korg-mail-alma10-1.taild15c8.ts.net [100.103.45.18]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by smtp.subspace.kernel.org (Postfix) with ESMTPS id 93C6241F5C4; Sun, 20 Sep 2026 11:42:19 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=100.103.45.18 ARC-Seal: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1789904540; cv=none; b=uhWZLzdOamW5HbHUtrLaUmJoM4xen9w0xL++nfns59M3ejrxIS9aELFuG+wy0ToIShVtZS+i0KgPsgMRR18ekKlz+TRY8yCgRdeSfGMHuwIKChCTsjJX2q0UEkSVk5ZHzJfK0q8cvZtCSALgjU6mhIceGV+fz0PPA2C9OBh/zHs= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1789904540; c=relaxed/simple; bh=2Jhej95EvZHHpMD58ypT4GYun4rflR2PnJqMWtNqsE4=; h=From:To:Cc:Subject:Date:Message-ID:In-Reply-To:References: MIME-Version:Content-Type; b=dgoN+FMBhiYG6CqFosdR/8cZvV3MJVnDs0mAjIWkZLpjj/j/D3wgvugW7cp7QzwW2DazFQ3i/iYsVo5LOF2lzGDZJVwH3xLhWW2b/PSEpEEQe5STv4G3sqjKIY1GOD09slkaYsqKAMzUl6H+F/UbF9T1mJMBTpQlkvDDk2EhaGk= ARC-Authentication-Results: i=1; smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=kernel.org header.i=@kernel.org header.b=kgNLFcpX; arc=none smtp.client-ip=100.103.45.18 Authentication-Results: smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=kernel.org header.i=@kernel.org header.b="kgNLFcpX" Received: by smtp.kernel.org (Postfix) with ESMTPSA id 72B5A1F000FF; Sun, 20 Sep 2026 11:42:18 +0000 (UTC) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=kernel.org; s=k20260515; t=1789904539; bh=VFMFmLWutyr/vRpCG+vwDoBVNtSGdEDDoC9Rg8S2X/0=; h=From:To:Cc:Subject:Date:In-Reply-To:References; b=kgNLFcpXFj84PHhVf+qQxtx7eyHLOL4cTQnIkN8E9oA4wRSWuF/ST3nmYGLRVXSWO ofsnZ+U3KAEK7X62jEV6m66vXZZ0muIPNh0LHXGXQqfaxCNUTPnYrcfgi0PGZnb/wI UEivb2fnZvI/QcdcxNWc05KjDtvFw9fCcWbMusfOfNZoN8Xequdm8SybFWNTFKrAax 3zMYuFcodtlcUt6kCVvTFsUiZzpR67frim4mfPnKkie7QYt9rjHjaL4cVINCCwAqlP gIUE9c0HG1tNblj9snPl3BvqxU825AlmPWQcn0ONPkBN1xOfvbsGdsz12AflbBMdAq ie8b4S5u21aJA== From: Leon Romanovsky To: Bjorn Helgaas , Logan Gunthorpe , Chaitanya Kulkarni , Greg Kroah-Hartman , Jens Axboe , Alex Williamson , Leon Romanovsky , Ankit Agrawal , Jason Gunthorpe , Jonathan Corbet , Shuah Khan , "Joerg Roedel (AMD)" , Will Deacon , Robin Murphy , Randy Dunlap , Sumit Semwal , =?utf-8?q?Christian_K=C3=B6nig?= Cc: linux-pci@vger.kernel.org, linux-kernel@vger.kernel.org, linux-doc@vger.kernel.org, iommu@lists.linux.dev, Tushar Dave , 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 Subject: [PATCH v7 10/19] PCI/P2PDMA: Route Translated Requests under Direct Translated P2P Date: Sun, 20 Sep 2026 14:41:22 +0300 Message-ID: <20260920-fix-p2p-acs-v4-0-v7-10-ca0828ab697c@nvidia.com> X-Mailer: git-send-email 2.55.0 In-Reply-To: <20260920-fix-p2p-acs-v4-0-v7-0-ca0828ab697c@nvidia.com> References: <20260920-fix-p2p-acs-v4-0-v7-0-ca0828ab697c@nvidia.com> Precedence: bulk X-Mailing-List: linux-kernel@vger.kernel.org List-Id: List-Subscribe: List-Unsubscribe: MIME-Version: 1.0 Content-Type: text/plain; charset="utf-8" X-Mailer: b4 0.15-dev-18f8f Content-Transfer-Encoding: quoted-printable From: Leon Romanovsky A Downstream Port with ACS Direct Translated P2P enabled routes a Request whose Address Type is Translated "to the peer Egress Port without redirection, regardless of ACS P2P Request Redirect and ACS P2P Egress Control", per PCIe r7.0 sec 6.12.3. P2PDMA assumes every Request carries an Untranslated address, so it sends an ATS client through the host bridge even where the fabric would route it straight to the peer. Add PCI_P2PDMA_TLP_TRANSLATED and consult Direct Translated P2P for the Requests it describes. Tested-by: Tushar Dave Signed-off-by: Leon Romanovsky Reviewed-by: Logan Gunthorpe --- drivers/pci/p2pdma.c | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/drivers/pci/p2pdma.c b/drivers/pci/p2pdma.c index 839285b77b62..13fe83142c71 100644 --- a/drivers/pci/p2pdma.c +++ b/drivers/pci/p2pdma.c @@ -521,6 +521,15 @@ pci_acs_p2pdma_request(u16 ctrl, unsigned int tlp_flag= s) */ if (ctrl & PCI_ACS_TB) return PCI_ACS_P2PDMA_BLOCKED; + + /* + * PCIe r7.0 sec 6.12.3: ACS Direct Translated P2P routes a + * Request carrying a Translated address to the peer "without + * redirection, regardless of ACS P2P Request Redirect and ACS + * P2P Egress Control settings". + */ + if (ctrl & PCI_ACS_DT) + return PCI_ACS_P2PDMA_DIRECT; } =20 return ctrl & (PCI_ACS_RR | PCI_ACS_EC) ? --=20 2.55.0 From nobody Thu Sep 24 21:19:39 2026 Received: from smtp.kernel.org (aws-us-west-2-korg-mail-alma10-1.taild15c8.ts.net [100.103.45.18]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by smtp.subspace.kernel.org (Postfix) with ESMTPS id 2069A421257; Sun, 20 Sep 2026 11:42:22 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=100.103.45.18 ARC-Seal: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1789904544; cv=none; b=NIp/efZgGAa3wYsDcLcudHZZT8Yx+R4QaO9ElqEZye6NP+O/o1f4f5rlXnSaiPJ0kwGgCbSMOvRsbpZchZ7AoYSmkMdnL8aZ2Oo+HEvaJol33xWeO3bufp9rfyvD4HNA8xemmNyScpT6wQmAGye91Q9iWUhv5pGvYHgX3xQKrks= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1789904544; c=relaxed/simple; bh=CAbLu2WY10gS+HzkjNk0U61eFzMDdgqOluZ165b5Puw=; h=From:To:Cc:Subject:Date:Message-ID:In-Reply-To:References: MIME-Version:Content-Type; b=cGDSjM3TnAnba2j4l6UJ5w8yoW2WjyyDjGPrtWTWhKgzpfr4DbgC3uz5CNJ1LjeyHKSFHNultGfF3LeQIk2Iy0AsAGkFX4smIfE4plgttoM53gHnVkwbA72Qny7EUANo7XacvyGROfBDJppA8KeL8tbeLy1Mu6BstTQapG9blkM= ARC-Authentication-Results: i=1; smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=kernel.org header.i=@kernel.org header.b=hYeCDqsV; arc=none smtp.client-ip=100.103.45.18 Authentication-Results: smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=kernel.org header.i=@kernel.org header.b="hYeCDqsV" Received: by smtp.kernel.org (Postfix) with ESMTPSA id 3292A1F00893; Sun, 20 Sep 2026 11:42:22 +0000 (UTC) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=kernel.org; s=k20260515; t=1789904542; bh=NZXJnxtCa94///6qEohwzHTXL0/Wx4EyUxNwxoRKBZE=; h=From:To:Cc:Subject:Date:In-Reply-To:References; b=hYeCDqsVwEO3LR1WxTTpX4JVpfgVmWl78ncOccZeBYGDwSWcnQypkgQn6oF4Es4uu VKj3FhG7F/rf2ZG0VU8H5Csq538xXihIC31lKTc1BaPu8EBdM8saaEylX4BsJfDYcG qQRd0YjMWoAbMpL6lcev3enUThQsqBF8szouo6vq5XEHJSFVJ4iCownW5U8lSrI6Ci 2J0n69w8BWNrB9otpzkuH/GphuOkComGw7NmRV5zeDoiHt0XwkbJoc5OjkSYQQkod5 v9BJzGRjA5j2Ja95OlMs74NKZIx1gEU3Uvobu0FE/ZyH4PyFSscQKI03KjEv+n/n84 BlBhcLry6VxZw== From: Leon Romanovsky To: Bjorn Helgaas , Logan Gunthorpe , Chaitanya Kulkarni , Greg Kroah-Hartman , Jens Axboe , Alex Williamson , Leon Romanovsky , Ankit Agrawal , Jason Gunthorpe , Jonathan Corbet , Shuah Khan , "Joerg Roedel (AMD)" , Will Deacon , Robin Murphy , Randy Dunlap , Sumit Semwal , =?utf-8?q?Christian_K=C3=B6nig?= Cc: linux-pci@vger.kernel.org, linux-kernel@vger.kernel.org, linux-doc@vger.kernel.org, iommu@lists.linux.dev, Tushar Dave , 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 Subject: [PATCH v7 11/19] PCI/P2PDMA: Log detailed ACS routing diagnostics Date: Sun, 20 Sep 2026 14:41:23 +0300 Message-ID: <20260920-fix-p2p-acs-v4-0-v7-11-ca0828ab697c@nvidia.com> X-Mailer: git-send-email 2.55.0 In-Reply-To: <20260920-fix-p2p-acs-v4-0-v7-0-ca0828ab697c@nvidia.com> References: <20260920-fix-p2p-acs-v4-0-v7-0-ca0828ab697c@nvidia.com> Precedence: bulk X-Mailing-List: linux-kernel@vger.kernel.org List-Id: List-Subscribe: List-Unsubscribe: MIME-Version: 1.0 Content-Type: text/plain; charset="utf-8" X-Mailer: b4 0.15-dev-18f8f Content-Transfer-Encoding: quoted-printable From: Leon Romanovsky When P2PDMA rejects a mapping, existing warnings identify only the final ACS or host-bridge result. They omit topology, live controls, divergence ports, cache state, and intermediate routing decisions. Emit debug-level messages for verbose calculations and cache lookups. Report both paths, decoded ACS controls, directional decisions, host fallback, and the final mapping. This keeps incidental unsupported probes quiet while allowing the diagnostics to be enabled when needed. Tested-by: Tushar Dave Signed-off-by: Leon Romanovsky Reviewed-by: Logan Gunthorpe --- drivers/pci/p2pdma.c | 232 +++++++++++++++++++++++++++++++++++++++++++++++= ---- 1 file changed, 215 insertions(+), 17 deletions(-) diff --git a/drivers/pci/p2pdma.c b/drivers/pci/p2pdma.c index 13fe83142c71..800fe0f67d9b 100644 --- a/drivers/pci/p2pdma.c +++ b/drivers/pci/p2pdma.c @@ -552,23 +552,128 @@ pci_acs_p2pdma_completion(u16 ctrl, unsigned int tlp= _flags) PCI_ACS_P2PDMA_DIRECT; } =20 +static const char *pci_acs_p2pdma_state_name(enum pci_acs_p2pdma_state sta= te) +{ + switch (state) { + case PCI_ACS_P2PDMA_DIRECT: + return "direct"; + case PCI_ACS_P2PDMA_REDIRECT: + return "redirect"; + case PCI_ACS_P2PDMA_BLOCKED: + return "blocked"; + case PCI_ACS_P2PDMA_NOT_SUPPORTED: + return "not-supported"; + } + + return "invalid"; +} + +static const char *pci_p2pdma_map_type_name(enum pci_p2pdma_map_type type) +{ + switch (type) { + case PCI_P2PDMA_MAP_UNKNOWN: + return "unknown"; + case PCI_P2PDMA_MAP_NONE: + return "none"; + case PCI_P2PDMA_MAP_NOT_SUPPORTED: + return "not-supported"; + case PCI_P2PDMA_MAP_BUS_ADDR: + return "bus-address"; + case PCI_P2PDMA_MAP_THRU_HOST_BRIDGE: + return "through-host-bridge"; + } + + return "invalid"; +} + /* * Read @pdev's ACS Control register. A device without an ACS capability h= as * no peer-to-peer controls at all, which routes the same as having them a= ll * clear. Returns false when the register is present but cannot be read; @= ctrl * is then meaningless. */ -static bool pci_acs_p2pdma_ctrl(struct pci_dev *pdev, u16 *ctrl) +static bool pci_acs_p2pdma_ctrl(struct pci_dev *pdev, const char *what, + u16 *ctrl, bool verbose) { - int pos; + int pos, ret; =20 pos =3D pdev->acs_cap; if (!pos) { + if (verbose) + pci_dbg(pdev, + "P2PDMA ACS: %s has no ACS capability\n", what); *ctrl =3D 0; return true; } =20 - return !pci_read_config_word(pdev, pos + PCI_ACS_CTRL, ctrl); + ret =3D pci_read_config_word(pdev, pos + PCI_ACS_CTRL, ctrl); + if (ret) { + if (verbose) + pci_dbg(pdev, + "P2PDMA ACS: %s ACS Control read failed at %#x: %#x\n", + what, pos + PCI_ACS_CTRL, ret); + return false; + } + + if (verbose) { + pci_dbg(pdev, + "P2PDMA ACS: %s cap=3D%#x caps=3D%#06x ctrl=3D%#06x\n", + what, pos, pdev->acs_capabilities, *ctrl); + pci_dbg(pdev, + "P2PDMA ACS: control bits SV=3D%u TB=3D%u RR=3D%u CR=3D%u UF=3D%u EC= =3D%u DT=3D%u\n", + !!(*ctrl & PCI_ACS_SV), !!(*ctrl & PCI_ACS_TB), + !!(*ctrl & PCI_ACS_RR), !!(*ctrl & PCI_ACS_CR), + !!(*ctrl & PCI_ACS_UF), !!(*ctrl & PCI_ACS_EC), + !!(*ctrl & PCI_ACS_DT)); + } + + return true; +} + +static void pci_p2pdma_log_path(const char *name, struct pci_dev *start, + struct pci_dev *common) +{ + struct pci_dev *pdev, *upstream; + int hop =3D 0, ret, type; + u16 ctrl; + + for (pdev =3D start; pdev; pdev =3D upstream, hop++) { + upstream =3D pci_upstream_bridge(pdev); + type =3D pci_is_pcie(pdev) ? pci_pcie_type(pdev) : -1; + pci_dbg(pdev, + "P2PDMA ACS: %s path hop=3D%d common=3D%u pcie=3D%u type=3D%d class=3D= %#08x vendor=3D%04x device=3D%04x upstream=3D%s\n", + name, hop, pdev =3D=3D common, pci_is_pcie(pdev), type, + pdev->class, pdev->vendor, pdev->device, + upstream ? pci_name(upstream) : ""); + + if (pdev->subordinate) + pci_dbg(pdev, + "P2PDMA ACS: bridge bus range=3D%02llx-%02llx\n", + (unsigned long long)pdev->subordinate->busn_res.start, + (unsigned long long)pdev->subordinate->busn_res.end); + + if (!pdev->acs_cap) { + pci_dbg(pdev, "P2PDMA ACS: ACS capability absent\n"); + continue; + } + + ret =3D pci_read_config_word(pdev, pdev->acs_cap + PCI_ACS_CTRL, + &ctrl); + if (ret) { + pci_dbg(pdev, + "P2PDMA ACS: ACS cap=3D%#x caps=3D%#06x Control read failed: %#x\n", + pdev->acs_cap, pdev->acs_capabilities, ret); + continue; + } + + pci_dbg(pdev, + "P2PDMA ACS: ACS cap=3D%#x caps=3D%#06x ctrl=3D%#06x SV=3D%u TB=3D%u RR= =3D%u CR=3D%u UF=3D%u EC=3D%u DT=3D%u\n", + pdev->acs_cap, pdev->acs_capabilities, ctrl, + !!(ctrl & PCI_ACS_SV), !!(ctrl & PCI_ACS_TB), + !!(ctrl & PCI_ACS_RR), !!(ctrl & PCI_ACS_CR), + !!(ctrl & PCI_ACS_UF), !!(ctrl & PCI_ACS_EC), + !!(ctrl & PCI_ACS_DT)); + } } =20 /* @@ -579,7 +684,8 @@ static bool pci_acs_p2pdma_ctrl(struct pci_dev *pdev, u= 16 *ctrl) * redirect controls instead. */ static bool pci_p2pdma_path_blocks_translation(struct pci_dev *client, - struct pci_dev *common) + struct pci_dev *common, + bool verbose) { struct pci_dev *pdev; u16 ctrl; @@ -594,11 +700,15 @@ static bool pci_p2pdma_path_blocks_translation(struct= pci_dev *client, =20 for (pdev =3D pci_upstream_bridge(client); pdev && pdev !=3D common; pdev =3D pci_upstream_bridge(pdev)) { - if (!pci_acs_p2pdma_ctrl(pdev, &ctrl)) + if (!pci_acs_p2pdma_ctrl(pdev, "path hop", &ctrl, verbose)) return true; =20 - if (ctrl & PCI_ACS_TB) + if (ctrl & PCI_ACS_TB) { + if (verbose) + pci_dbg(pdev, + "P2PDMA ACS: Translation Blocking rejects Translated Requests on this= path\n"); return true; + } } =20 return false; @@ -972,14 +1082,22 @@ calc_map_type_and_dist(struct pci_dev *provider, str= uct pci_dev *client, enum pci_p2pdma_map_type map_type[PCI_P2PDMA_TLP_CLASSES]; struct pci_dev *a =3D provider, *b =3D client, *bb; struct pci_dev *a_child =3D NULL, *b_child =3D NULL; + struct pci_host_bridge *provider_host, *client_host; struct pci_p2pdma_acs_path path =3D {}; struct pci_p2pdma *p2pdma; bool cpu_p2pdma, host_whitelisted =3D false; + bool cache_store =3D false; bool host_fallback =3D false; unsigned int flags; int dist_a =3D 0; int dist_b =3D 0; =20 + if (verbose) + pci_dbg(client, + "P2PDMA ACS: begin provider=3D%s client=3D%s cache-index=3D%#lx\n", + pci_name(provider), pci_name(client), + map_types_idx(client)); + /* * Note, we don't need to take references to devices returned by * pci_upstream_bridge() seeing we hold a reference to a child @@ -1010,14 +1128,32 @@ calc_map_type_and_dist(struct pci_dev *provider, st= ruct pci_dev *client, * request can only get to the peer through the host bridge. */ *dist =3D dist_a + dist_b; + if (verbose) { + pci_dbg(client, + "P2PDMA ACS: no common upstream bridge provider-distance=3D%d client-di= stance=3D%d total=3D%d\n", + dist_a, dist_b, *dist); + pci_p2pdma_log_path("provider", provider, NULL); + pci_p2pdma_log_path("client", client, NULL); + } path.no_common_bridge =3D true; - path.tb_on_path =3D pci_p2pdma_path_blocks_translation(client, NULL); + path.tb_on_path =3D pci_p2pdma_path_blocks_translation(client, NULL, + verbose); for (flags =3D 0; flags < PCI_P2PDMA_TLP_CLASSES; flags++) map_type[flags] =3D pci_p2pdma_route(&path, flags); goto map_through_host_bridge; =20 check_paths_acs: *dist =3D dist_a + dist_b; + if (verbose) { + pci_dbg(client, + "P2PDMA ACS: common=3D%s provider-divergence=3D%s client-divergence=3D%= s provider-distance=3D%d client-distance=3D%d total=3D%d\n", + pci_name(a), + a_child ? pci_name(a_child) : "", + b_child ? pci_name(b_child) : "", + dist_a, dist_b, *dist); + pci_p2pdma_log_path("provider", provider, a); + pci_p2pdma_log_path("client", client, a); + } =20 /* * ACS P2P routing controls apply where a TLP can route toward the peer @@ -1025,17 +1161,33 @@ calc_map_type_and_dist(struct pci_dev *provider, st= ruct 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, &path.cpl_ctrl)) + if (!pci_acs_p2pdma_ctrl(a_child, "completion", &path.cpl_ctrl, + verbose)) path.unreadable =3D a_child; - if (!pci_acs_p2pdma_ctrl(b_child, &path.req_ctrl) && - !path.unreadable) + if (!pci_acs_p2pdma_ctrl(b_child, "request", &path.req_ctrl, + verbose) && !path.unreadable) path.unreadable =3D b_child; + if (verbose && !path.unreadable) + pci_dbg(client, + "P2PDMA ACS: request=3D%s at %s completion=3D%s at %s\n", + pci_acs_p2pdma_state_name( + pci_p2pdma_request_state(&path, 0)), + pci_name(b_child), + pci_acs_p2pdma_state_name( + pci_acs_p2pdma_completion(path.cpl_ctrl, + 0)), + pci_name(a_child)); + } else if (verbose) { + pci_dbg(client, + "P2PDMA ACS: peer divergence is incomplete; no ACS peer-routing control= s evaluated\n"); } =20 - path.tb_on_path =3D pci_p2pdma_path_blocks_translation(client, a); + path.tb_on_path =3D pci_p2pdma_path_blocks_translation(client, a, + verbose); if (b_child) path.tb_above_divergence =3D - pci_p2pdma_path_blocks_translation(b_child, NULL); + pci_p2pdma_path_blocks_translation(b_child, NULL, + verbose); =20 /* * The walk and the config reads above serve every class; only the @@ -1064,6 +1216,19 @@ calc_map_type_and_dist(struct pci_dev *provider, str= uct pci_dev *client, host_whitelisted =3D host_bridge_whitelist(provider, client, verbose); =20 + if (verbose) { + provider_host =3D pci_find_host_bridge(provider->bus); + client_host =3D pci_find_host_bridge(client->bus); + pci_dbg(client, + "P2PDMA ACS: host fallback cpu-support=3D%u whitelist=3D%s provider-hos= t=3D%s client-host=3D%s same-host=3D%u\n", + cpu_p2pdma, + cpu_p2pdma ? "not-consulted" : + (host_whitelisted ? "yes" : "no"), + provider_host ? dev_name(&provider_host->dev) : "", + client_host ? dev_name(&client_host->dev) : "", + provider_host && provider_host =3D=3D client_host); + } + 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= ", @@ -1075,11 +1240,31 @@ calc_map_type_and_dist(struct pci_dev *provider, st= ruct pci_dev *client, done: rcu_read_lock(); p2pdma =3D rcu_dereference(provider->p2pdma); - if (p2pdma) + if (p2pdma) { xa_store(&p2pdma->map_types, map_types_idx(client), - xa_mk_value(pci_p2pdma_map_types_pack(map_type)), - GFP_ATOMIC); + xa_mk_value(pci_p2pdma_map_types_pack(map_type)), GFP_ATOMIC); + cache_store =3D true; + } rcu_read_unlock(); + if (verbose) { + pci_dbg(client, + "P2PDMA ACS: final provider=3D%s result=3D%s(%d) tlp-flags=3D%#x distan= ce=3D%d unreadable=3D%s cache-store=3D%u index=3D%#lx\n", + pci_name(provider), + pci_p2pdma_map_type_name(map_type[tlp_flags]), + map_type[tlp_flags], tlp_flags, *dist, + path.unreadable ? pci_name(path.unreadable) : "", + cache_store, map_types_idx(client)); + pci_dbg(client, + "P2PDMA ACS: classes strict=3D%s relaxed=3D%s translated=3D%s translate= d+relaxed=3D%s\n", + pci_p2pdma_map_type_name(map_type[0]), + pci_p2pdma_map_type_name( + map_type[PCI_P2PDMA_TLP_RELAXED_CPL]), + pci_p2pdma_map_type_name( + map_type[PCI_P2PDMA_TLP_TRANSLATED]), + pci_p2pdma_map_type_name( + map_type[PCI_P2PDMA_TLP_TRANSLATED | + PCI_P2PDMA_TLP_RELAXED_CPL])); + } return map_type[tlp_flags]; } =20 @@ -1409,16 +1594,24 @@ pci_p2pdma_map_type_tlp(struct p2pdma_provider *pro= vider, struct device *dev, enum pci_p2pdma_map_type type; struct pci_p2pdma *p2pdma; struct pci_dev *client; + bool provider_state; int dist; =20 if (WARN_ON_ONCE(tlp_flags >=3D PCI_P2PDMA_TLP_CLASSES)) return PCI_P2PDMA_MAP_NOT_SUPPORTED; =20 - if (!pdev->p2pdma) + if (!pdev->p2pdma) { + pci_dbg(pdev, + "P2PDMA ACS: map lookup rejected; provider state is absent\n"); return PCI_P2PDMA_MAP_NOT_SUPPORTED; + } =20 - if (!dev_is_pci(dev)) + if (!dev_is_pci(dev)) { + dev_dbg(dev, + "P2PDMA ACS: provider=3D%s map lookup rejected; client is not PCI\n", + pci_name(pdev)); return PCI_P2PDMA_MAP_NOT_SUPPORTED; + } =20 client =3D to_pci_dev(dev); cache_index =3D map_types_idx(client); @@ -1429,8 +1622,13 @@ pci_p2pdma_map_type_tlp(struct p2pdma_provider *prov= ider, struct device *dev, if (p2pdma) cached =3D xa_to_value(xa_load(&p2pdma->map_types, cache_index)); + provider_state =3D !!p2pdma; rcu_read_unlock(); type =3D pci_p2pdma_map_types_unpack(cached, tlp_flags); + pci_dbg(client, + "P2PDMA ACS: map lookup provider=3D%s index=3D%#lx tlp-flags=3D%#x cach= ed=3D%s(%d) provider-state=3D%u\n", + pci_name(pdev), cache_index, tlp_flags, + pci_p2pdma_map_type_name(type), type, provider_state); =20 if (type =3D=3D PCI_P2PDMA_MAP_UNKNOWN) return calc_map_type_and_dist(pdev, client, &dist, tlp_flags, --=20 2.55.0 From nobody Thu Sep 24 21:19:39 2026 Received: from smtp.kernel.org (aws-us-west-2-korg-mail-alma10-1.taild15c8.ts.net [100.103.45.18]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by smtp.subspace.kernel.org (Postfix) with ESMTPS id 2B61C4302FA; Sun, 20 Sep 2026 11:42:25 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=100.103.45.18 ARC-Seal: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1789904547; cv=none; b=SMbLcSXDNt0VkhyOr+voXhO8IrJPQfqokQM8tBoyJ/7AvMPQ5h4WV968lqyG8mTW3YeyfWoJQI5Qo05J8Gn6e2BXRsUUNZBpDVWWuO8JldqdeM8Z+1GxVl4pwnSSABKNIgdAbgHN/fOe2gGSAqMjRcwme2hc+95TNmsXTL8Cf8E= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1789904547; c=relaxed/simple; bh=5BEeOATn1Pl+p7DWZw4CQp1UUPPn6E68gKnatzMP074=; h=From:To:Cc:Subject:Date:Message-ID:In-Reply-To:References: MIME-Version:Content-Type; b=EbK6k/DoTssjoGMlCzW8njKq5WLQSQCGKf3ohOInUpaWXae7vx7AkxY15cRMNteTdDqPq5RBAN4Ao0C+43vB027Lf9hT+CZOmNP0quYJ6exFdlpo+KJ6GqdcmkIGuvR1rZ+XT7rh3C0DS+8xUCLc0DXmW9I18XNSTcZn7sUJzaM= ARC-Authentication-Results: i=1; smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=kernel.org header.i=@kernel.org header.b=mKnjJxyV; arc=none smtp.client-ip=100.103.45.18 Authentication-Results: smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=kernel.org header.i=@kernel.org header.b="mKnjJxyV" Received: by smtp.kernel.org (Postfix) with ESMTPSA id 438861F000FF; Sun, 20 Sep 2026 11:42:25 +0000 (UTC) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=kernel.org; s=k20260515; t=1789904545; bh=jXxj7n8PWib7y8EA/g0mK2LNDzC+Svk64eLnhj+P6rA=; h=From:To:Cc:Subject:Date:In-Reply-To:References; b=mKnjJxyVEmOqF7l2EtBXl9ZOL58lS1q1jyI1ARrsKrJNQiLmIXeq2Q5WLxChQI0lg CNsmUphXsffV0e/4ScoZ1XZEscy/bS/YuxZ1GtyVVTvKvfFTl6GH1cGNXWs07AXqTi nkdXl47GgyKjNlfwN1OLNIH0tqi9B6sMFoX5WRoFyFp8Vma6bra4L3w/T8D9kaI+QD 0wyeTR2OFcgguxl2VF6p6fpJUli4f4fyaqQcDnrhKJXnhon7XT4wW7viXfbtTwUPEn 9m/geurifQRshIKdOhmwP1KH2RENXdQH2w1bcFXApJroDLkBf6BtvXC8ObMAzH0BUD g5YwRJC85CMdg== From: Leon Romanovsky To: Bjorn Helgaas , Logan Gunthorpe , Chaitanya Kulkarni , Greg Kroah-Hartman , Jens Axboe , Alex Williamson , Leon Romanovsky , Ankit Agrawal , Jason Gunthorpe , Jonathan Corbet , Shuah Khan , "Joerg Roedel (AMD)" , Will Deacon , Robin Murphy , Randy Dunlap , Sumit Semwal , =?utf-8?q?Christian_K=C3=B6nig?= Cc: linux-pci@vger.kernel.org, linux-kernel@vger.kernel.org, linux-doc@vger.kernel.org, iommu@lists.linux.dev, Tushar Dave , 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 Subject: [PATCH v7 12/19] PCI/P2PDMA: Add KUnit tests for the ACS routing decisions Date: Sun, 20 Sep 2026 14:41:24 +0300 Message-ID: <20260920-fix-p2p-acs-v4-0-v7-12-ca0828ab697c@nvidia.com> X-Mailer: git-send-email 2.55.0 In-Reply-To: <20260920-fix-p2p-acs-v4-0-v7-0-ca0828ab697c@nvidia.com> References: <20260920-fix-p2p-acs-v4-0-v7-0-ca0828ab697c@nvidia.com> Precedence: bulk X-Mailing-List: linux-kernel@vger.kernel.org List-Id: List-Subscribe: List-Unsubscribe: MIME-Version: 1.0 Content-Type: text/plain; charset="utf-8" X-Mailer: b4 0.15-dev-18f8f Content-Transfer-Encoding: quoted-printable From: Leon Romanovsky pci_acs_p2pdma_request() and pci_acs_p2pdma_completion() turn an ACS Control register and a TLP class into a routing decision. Which bits apply to which direction and which class is easy to get wrong, and hardware that exposes a given combination may not be at hand. Drive both from a table of register values and classes, covering the redirect controls per direction and Translation Blocking, Direct Translated P2P and Relaxed Ordering. Direct Translated P2P gets a case with and without a redirect to override, since it changes nothing without one. Exposing the two helpers moves their state enum into pci.h. Tested-by: Tushar Dave Signed-off-by: Leon Romanovsky --- drivers/pci/Kconfig | 15 ++++++ drivers/pci/Makefile | 1 + drivers/pci/p2pdma.c | 13 ++--- drivers/pci/pci.h | 16 ++++++ drivers/pci/pci_acs_test.c | 121 +++++++++++++++++++++++++++++++++++++++++= ++++ 5 files changed, 157 insertions(+), 9 deletions(-) diff --git a/drivers/pci/Kconfig b/drivers/pci/Kconfig index 0c7408509ba2..7a3eb5beb328 100644 --- a/drivers/pci/Kconfig +++ b/drivers/pci/Kconfig @@ -226,6 +226,21 @@ config PCI_P2PDMA =20 If unsure, say N. =20 +config PCI_ACS_KUNIT_TEST + tristate "KUnit tests for PCI ACS P2P routing" if !KUNIT_ALL_TESTS + depends on PCI_P2PDMA && KUNIT + default KUNIT_ALL_TESTS + help + Enable KUnit tests for the PCI ACS peer-to-peer routing decision + logic, including direction-specific Request and Completion + controls that cannot all be exercised on typical peer-to-peer + hardware. + + For more information on KUnit and unit tests in general, refer to + the KUnit documentation in Documentation/dev-tools/kunit/. + + If unsure, say N. + config PCI_LABEL def_bool y if (DMI || ACPI) select NLS diff --git a/drivers/pci/Makefile b/drivers/pci/Makefile index 41ebc3b9a518..6305d128d3df 100644 --- a/drivers/pci/Makefile +++ b/drivers/pci/Makefile @@ -31,6 +31,7 @@ obj-$(CONFIG_PCI_STUB) +=3D pci-stub.o obj-$(CONFIG_PCI_PF_STUB) +=3D pci-pf-stub.o obj-$(CONFIG_PCI_ECAM) +=3D ecam.o obj-$(CONFIG_PCI_P2PDMA) +=3D p2pdma.o +obj-$(CONFIG_PCI_ACS_KUNIT_TEST) +=3D pci_acs_test.o obj-$(CONFIG_XEN_PCIDEV_FRONTEND) +=3D xen-pcifront.o obj-$(CONFIG_VGA_ARB) +=3D vgaarb.o obj-$(CONFIG_PCI_DOE) +=3D doe.o diff --git a/drivers/pci/p2pdma.c b/drivers/pci/p2pdma.c index 800fe0f67d9b..fcc67d9f74a6 100644 --- a/drivers/pci/p2pdma.c +++ b/drivers/pci/p2pdma.c @@ -492,13 +492,6 @@ static struct pci_dev *find_parent_pci_dev(struct devi= ce *dev) return NULL; } =20 -enum pci_acs_p2pdma_state { - PCI_ACS_P2PDMA_NOT_SUPPORTED, - PCI_ACS_P2PDMA_DIRECT, - PCI_ACS_P2PDMA_REDIRECT, - PCI_ACS_P2PDMA_BLOCKED, -}; - /* * Decide how a peer-to-peer Request at an ACS-capable ingress port routes, * from that port's ACS Control register and the Request's Address Type. @@ -508,7 +501,7 @@ enum pci_acs_p2pdma_state { * selects are a direct route and an ACS Violation, and neither one lets p= eer * bus addressing be assumed. */ -static enum pci_acs_p2pdma_state +VISIBLE_IF_KUNIT enum pci_acs_p2pdma_state pci_acs_p2pdma_request(u16 ctrl, unsigned int tlp_flags) { if (tlp_flags & PCI_P2PDMA_TLP_TRANSLATED) { @@ -535,6 +528,7 @@ pci_acs_p2pdma_request(u16 ctrl, unsigned int tlp_flags) return ctrl & (PCI_ACS_RR | PCI_ACS_EC) ? PCI_ACS_P2PDMA_REDIRECT : PCI_ACS_P2PDMA_DIRECT; } +EXPORT_SYMBOL_IF_KUNIT(pci_acs_p2pdma_request); =20 /* * Decide how a peer-to-peer Completion at an ACS-capable ingress port rou= tes. @@ -542,7 +536,7 @@ pci_acs_p2pdma_request(u16 ctrl, unsigned int tlp_flags) * affects a Completion, and that one leaves Completions carrying the Rela= xed * Ordering attribute alone. */ -static enum pci_acs_p2pdma_state +VISIBLE_IF_KUNIT enum pci_acs_p2pdma_state pci_acs_p2pdma_completion(u16 ctrl, unsigned int tlp_flags) { if (tlp_flags & PCI_P2PDMA_TLP_RELAXED_CPL) @@ -551,6 +545,7 @@ pci_acs_p2pdma_completion(u16 ctrl, unsigned int tlp_fl= ags) return ctrl & PCI_ACS_CR ? PCI_ACS_P2PDMA_REDIRECT : PCI_ACS_P2PDMA_DIRECT; } +EXPORT_SYMBOL_IF_KUNIT(pci_acs_p2pdma_completion); =20 static const char *pci_acs_p2pdma_state_name(enum pci_acs_p2pdma_state sta= te) { diff --git a/drivers/pci/pci.h b/drivers/pci/pci.h index ba3c3fddddc2..c0d2711d73f9 100644 --- a/drivers/pci/pci.h +++ b/drivers/pci/pci.h @@ -2,6 +2,7 @@ #ifndef DRIVERS_PCI_H #define DRIVERS_PCI_H =20 +#include #include #include #include @@ -1093,6 +1094,21 @@ resource_size_t pci_min_window_alignment(struct pci_= bus *bus, =20 void pci_acs_init(struct pci_dev *dev); void pci_enable_acs(struct pci_dev *dev); + +enum pci_acs_p2pdma_state { + PCI_ACS_P2PDMA_NOT_SUPPORTED, + PCI_ACS_P2PDMA_DIRECT, + PCI_ACS_P2PDMA_REDIRECT, + PCI_ACS_P2PDMA_BLOCKED, +}; + +#if IS_ENABLED(CONFIG_KUNIT) +enum pci_acs_p2pdma_state pci_acs_p2pdma_request(u16 ctrl, + unsigned int tlp_flags); +enum pci_acs_p2pdma_state pci_acs_p2pdma_completion(u16 ctrl, + unsigned int tlp_flags); +#endif + #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); diff --git a/drivers/pci/pci_acs_test.c b/drivers/pci/pci_acs_test.c new file mode 100644 index 000000000000..ce6b9375da36 --- /dev/null +++ b/drivers/pci/pci_acs_test.c @@ -0,0 +1,121 @@ +// SPDX-License-Identifier: GPL-2.0 +/* + * KUnit tests for PCI ACS peer-to-peer routing decisions. + * + * These exercise Request and Completion routing independently of the ACS + * settings exposed by available PCIe hardware. + */ +#include + +#include +#include +#include + +#include "pci.h" + +struct acs_decision_case { + const char *desc; + u16 ctrl; + unsigned int tlp_flags; + enum pci_acs_p2pdma_state expect; +}; + +/* Shorthands to keep the tables below readable. */ +#define ACS_DIRECT PCI_ACS_P2PDMA_DIRECT +#define ACS_REDIR PCI_ACS_P2PDMA_REDIRECT +#define ACS_RO PCI_P2PDMA_TLP_RELAXED_CPL +#define ACS_AT PCI_P2PDMA_TLP_TRANSLATED +#define ACS_BLOCK PCI_ACS_P2PDMA_BLOCKED + +/* Request routing ignores Completion Redirect. */ +static const struct acs_decision_case acs_request_cases[] =3D { + { "req/none", 0, 0, ACS_DIRECT }, + { "req/rr", PCI_ACS_RR, 0, ACS_REDIR }, + { "req/cr", PCI_ACS_CR, 0, ACS_DIRECT }, + { "req/rr_cr", PCI_ACS_RR | PCI_ACS_CR, 0, ACS_REDIR }, + { "req/ec", PCI_ACS_EC, 0, ACS_REDIR }, + { "req/ec_cr", PCI_ACS_EC | PCI_ACS_CR, 0, ACS_REDIR }, + + /* + * Direct Translated P2P overrides the redirect controls, but only for + * a Request that actually carries a Translated address. + */ + { "req/dt", PCI_ACS_DT, 0, ACS_DIRECT }, + { "req/dt_rr", PCI_ACS_DT | PCI_ACS_RR, 0, ACS_REDIR }, + { "req/at", 0, ACS_AT, ACS_DIRECT }, + { "req/at_rr", PCI_ACS_RR, ACS_AT, ACS_REDIR }, + { "req/at_dt_rr", PCI_ACS_DT | PCI_ACS_RR, ACS_AT, ACS_DIRECT }, + { "req/at_dt_ec", PCI_ACS_DT | PCI_ACS_EC, ACS_AT, ACS_DIRECT }, + + /* + * Translation Blocking rejects a Translated address outright, and + * makes the port ignore Direct Translated P2P. + */ + { "req/tb", PCI_ACS_TB, 0, ACS_DIRECT }, + { "req/tb_rr", PCI_ACS_TB | PCI_ACS_RR, 0, ACS_REDIR }, + { "req/at_tb", PCI_ACS_TB, ACS_AT, ACS_BLOCK }, + { "req/at_tb_dt", PCI_ACS_TB | PCI_ACS_DT, ACS_AT, ACS_BLOCK }, +}; + +/* Completion routing depends only on Completion Redirect. */ +static const struct acs_decision_case acs_completion_cases[] =3D { + { "cpl/none", 0, 0, ACS_DIRECT }, + { "cpl/rr", PCI_ACS_RR, 0, ACS_DIRECT }, + { "cpl/cr", PCI_ACS_CR, 0, ACS_REDIR }, + { "cpl/rr_cr", PCI_ACS_RR | PCI_ACS_CR, 0, ACS_REDIR }, + { "cpl/ec", PCI_ACS_EC, 0, ACS_DIRECT }, + { "cpl/ec_cr", PCI_ACS_EC | PCI_ACS_CR, 0, ACS_REDIR }, + + /* Relaxed Ordering Completions are never redirected. */ + { "cpl/ro", 0, ACS_RO, ACS_DIRECT }, + { "cpl/ro_cr", PCI_ACS_CR, ACS_RO, ACS_DIRECT }, + { "cpl/ro_rr_cr", PCI_ACS_RR | PCI_ACS_CR, ACS_RO, ACS_DIRECT }, +}; + +#undef ACS_DIRECT +#undef ACS_REDIR +#undef ACS_RO +#undef ACS_AT +#undef ACS_BLOCK + +static void acs_decision_desc(const struct acs_decision_case *c, char *des= c) +{ + strscpy(desc, c->desc, KUNIT_PARAM_DESC_SIZE); +} + +KUNIT_ARRAY_PARAM(acs_request, acs_request_cases, acs_decision_desc); +KUNIT_ARRAY_PARAM(acs_completion, acs_completion_cases, acs_decision_desc); + +static void pci_acs_p2pdma_request_test(struct kunit *test) +{ + const struct acs_decision_case *c =3D test->param_value; + + KUNIT_EXPECT_EQ(test, pci_acs_p2pdma_request(c->ctrl, c->tlp_flags), + c->expect); +} + +static void pci_acs_p2pdma_completion_test(struct kunit *test) +{ + const struct acs_decision_case *c =3D test->param_value; + + KUNIT_EXPECT_EQ(test, pci_acs_p2pdma_completion(c->ctrl, c->tlp_flags), + c->expect); +} + +static struct kunit_case pci_acs_test_cases[] =3D { + KUNIT_CASE_PARAM(pci_acs_p2pdma_request_test, + acs_request_gen_params), + KUNIT_CASE_PARAM(pci_acs_p2pdma_completion_test, + acs_completion_gen_params), + {} +}; + +static struct kunit_suite pci_acs_test_suite =3D { + .name =3D "pci_acs", + .test_cases =3D pci_acs_test_cases, +}; +kunit_test_suite(pci_acs_test_suite); + +MODULE_IMPORT_NS("EXPORTED_FOR_KUNIT_TESTING"); +MODULE_LICENSE("GPL"); +MODULE_DESCRIPTION("KUnit tests for PCI ACS peer-to-peer routing decisions= "); --=20 2.55.0 From nobody Thu Sep 24 21:19:39 2026 Received: from smtp.kernel.org (aws-us-west-2-korg-mail-alma10-1.taild15c8.ts.net [100.103.45.18]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by smtp.subspace.kernel.org (Postfix) with ESMTPS id 1D7C343231F; Sun, 20 Sep 2026 11:42:29 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=100.103.45.18 ARC-Seal: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1789904551; cv=none; b=BU+AtTUK8RIkQdqGT78gengdUHVOz8FzhGXzrJYOTKjlZMYb8nTQ3/zGTqqsyVYHHlJLXJCBqAcERfvEZb0oE18JIfzORGmAuA2gK+RABtbgPWcBM1TX9/1v8/ld4dFErt/8mogIkWR0qIy34Enwf1qiv01cmNrNZJkW4c6mkFI= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1789904551; c=relaxed/simple; bh=jZZRcwYKEHMd+lN4aQFfqLSMXYAIse/mTZS8MweNpn8=; h=From:To:Cc:Subject:Date:Message-ID:In-Reply-To:References: MIME-Version:Content-Type; b=Yd4HAzIuAlpb6U07kzuvRlcwVrudi3/rdm/Y8Q7tu+G/OOlky8iSkPJD3/xGQCU6ohenOuwFxeMFNDp2B08BnlDFbrRLpUtaG/ByVHx5e5q/hFblTnqa96mdYAvlSu5KJYSCgl2Yd0UwR/800XpWpqjeFeF0hqELFz0C+qKwdRM= ARC-Authentication-Results: i=1; smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=kernel.org header.i=@kernel.org header.b=fPzFkFoo; arc=none smtp.client-ip=100.103.45.18 Authentication-Results: smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=kernel.org header.i=@kernel.org header.b="fPzFkFoo" Received: by smtp.kernel.org (Postfix) with ESMTPSA id 6BDCF1F000FF; Sun, 20 Sep 2026 11:42:28 +0000 (UTC) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=kernel.org; s=k20260515; t=1789904549; bh=VV4iWBVaK9pjYnq3ZVo6I0FMaKR9oQfRpMd0SnYBrg8=; h=From:To:Cc:Subject:Date:In-Reply-To:References; b=fPzFkFoovWbEFXOcLsoD/mpvrNkcFpKYyoFkw6GTJNCKc+eUyxYLcynSe3ewjjyr9 C98rTfUcqCuwRc7RvSKNxpfT0c7p7gpg3lGOCEjJm3txul6X/eRirsysci0LGeBLEI K78Y/vw8R1StpG6A50+Pqe6lpP+uXUCBM0gBSdmcaIN22ybaNgekLXxTZA1dNnxD3a ORuzNWT7FsBi0n7Te49a15XfbssQ/m8yOAe9NOI0HIg8rBIwDrUBxPv28rdlapdtuB v+Wu+WOUwLmXa9ZQAJ0vC9DL1s3V6UJ+52aNObka9mq2geu22pZ3PEJTV4GdNTKgeO GGjw3q/cra9kw== From: Leon Romanovsky To: Bjorn Helgaas , Logan Gunthorpe , Chaitanya Kulkarni , Greg Kroah-Hartman , Jens Axboe , Alex Williamson , Leon Romanovsky , Ankit Agrawal , Jason Gunthorpe , Jonathan Corbet , Shuah Khan , "Joerg Roedel (AMD)" , Will Deacon , Robin Murphy , Randy Dunlap , Sumit Semwal , =?utf-8?q?Christian_K=C3=B6nig?= Cc: linux-pci@vger.kernel.org, linux-kernel@vger.kernel.org, linux-doc@vger.kernel.org, iommu@lists.linux.dev, Tushar Dave , 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 Subject: [PATCH v7 13/19] PCI/P2PDMA: Test the ACS P2P routing walk Date: Sun, 20 Sep 2026 14:41:25 +0300 Message-ID: <20260920-fix-p2p-acs-v4-0-v7-13-ca0828ab697c@nvidia.com> X-Mailer: git-send-email 2.55.0 In-Reply-To: <20260920-fix-p2p-acs-v4-0-v7-0-ca0828ab697c@nvidia.com> References: <20260920-fix-p2p-acs-v4-0-v7-0-ca0828ab697c@nvidia.com> Precedence: bulk X-Mailing-List: linux-kernel@vger.kernel.org List-Id: List-Subscribe: List-Unsubscribe: MIME-Version: 1.0 Content-Type: text/plain; charset="utf-8" X-Mailer: b4 0.15-dev-18f8f Content-Transfer-Encoding: quoted-printable From: Leon Romanovsky calc_map_type_and_dist() decides which ports along a path carry the routing controls, and holds every class's answer in one cache entry. Neither depends on a single register, so a table of them cannot reach the walk itself. Drive the walk over a fabricated fabric of two devices below a switch, with fake config space supplying the ACS Control registers. Cover the ports below the divergence, the three cases where two classes of one path disagree, and the packed cache, which the fabric has no provider state to exercise indirectly. Tested-by: Tushar Dave Signed-off-by: Leon Romanovsky --- drivers/pci/p2pdma.c | 9 +- drivers/pci/pci.h | 9 + drivers/pci/pci_acs_test.c | 478 +++++++++++++++++++++++++++++++++++++++++= ++++ 3 files changed, 493 insertions(+), 3 deletions(-) diff --git a/drivers/pci/p2pdma.c b/drivers/pci/p2pdma.c index fcc67d9f74a6..6da427319f29 100644 --- a/drivers/pci/p2pdma.c +++ b/drivers/pci/p2pdma.c @@ -1005,7 +1005,7 @@ static unsigned long map_types_idx(struct pci_dev *cl= ient) */ static_assert(PCI_P2PDMA_MAP_THRU_HOST_BRIDGE < 16); =20 -static unsigned long +VISIBLE_IF_KUNIT unsigned long pci_p2pdma_map_types_pack(const enum pci_p2pdma_map_type *type) { unsigned long val =3D 0; @@ -1016,12 +1016,14 @@ pci_p2pdma_map_types_pack(const enum pci_p2pdma_map= _type *type) =20 return val; } +EXPORT_SYMBOL_IF_KUNIT(pci_p2pdma_map_types_pack); =20 -static enum pci_p2pdma_map_type +VISIBLE_IF_KUNIT enum pci_p2pdma_map_type pci_p2pdma_map_types_unpack(unsigned long val, unsigned int tlp_flags) { return (val >> (tlp_flags * 4)) & 0xf; } +EXPORT_SYMBOL_IF_KUNIT(pci_p2pdma_map_types_unpack); =20 /* * Calculate the P2PDMA mapping type and distance between two PCI devices. @@ -1070,7 +1072,7 @@ pci_p2pdma_map_types_unpack(unsigned long val, unsign= ed int tlp_flags) * ports per above. If the device is not in the whitelist, return * PCI_P2PDMA_MAP_NOT_SUPPORTED. */ -static enum pci_p2pdma_map_type +VISIBLE_IF_KUNIT enum pci_p2pdma_map_type calc_map_type_and_dist(struct pci_dev *provider, struct pci_dev *client, int *dist, unsigned int tlp_flags, bool verbose) { @@ -1262,6 +1264,7 @@ calc_map_type_and_dist(struct pci_dev *provider, stru= ct pci_dev *client, } return map_type[tlp_flags]; } +EXPORT_SYMBOL_IF_KUNIT(calc_map_type_and_dist); =20 /** * pci_p2pdma_distance_many - Determine the cumulative distance between diff --git a/drivers/pci/pci.h b/drivers/pci/pci.h index c0d2711d73f9..56f821e40637 100644 --- a/drivers/pci/pci.h +++ b/drivers/pci/pci.h @@ -7,6 +7,7 @@ #include #include #include +#include #include =20 struct pcie_tlp_log; @@ -1107,6 +1108,14 @@ enum pci_acs_p2pdma_state pci_acs_p2pdma_request(u16= ctrl, unsigned int tlp_flags); enum pci_acs_p2pdma_state pci_acs_p2pdma_completion(u16 ctrl, unsigned int tlp_flags); +unsigned long pci_p2pdma_map_types_pack(const enum pci_p2pdma_map_type *ty= pe); +enum pci_p2pdma_map_type pci_p2pdma_map_types_unpack(unsigned long val, + unsigned int tlp_flags); +enum pci_p2pdma_map_type calc_map_type_and_dist(struct pci_dev *provider, + struct pci_dev *client, + int *dist, + unsigned int tlp_flags, + bool verbose); #endif =20 #ifdef CONFIG_PCI_QUIRKS diff --git a/drivers/pci/pci_acs_test.c b/drivers/pci/pci_acs_test.c index ce6b9375da36..7f4f9cc04bfb 100644 --- a/drivers/pci/pci_acs_test.c +++ b/drivers/pci/pci_acs_test.c @@ -102,11 +102,489 @@ static void pci_acs_p2pdma_completion_test(struct ku= nit *test) c->expect); } =20 +/* + * Drive calc_map_type_and_dist() over a fabricated PCIe fabric matching t= he + * canonical topology of two devices below one switch: + * + * host bridge / root bus + * Root Port + * Switch Upstream Port + * Switch Downstream Port 0 + * Nested Switch -- provider + * Switch Downstream Port 1 + * Nested Switch -- client + * + * Fake config-space operations supply the ACS Control registers. This lets + * the cases vary both divergence ports and controls below the divergence + * without depending on real hardware. + */ +struct acs_port_cfg { + u16 ctrl; + bool fail_read; +}; + +struct acs_fabric { + struct pci_dev *rootport; + struct pci_dev *provider; + struct pci_dev *client; + struct pci_dev *dn0; /* Downstream Port 0 (provider side) */ + struct pci_dev *dn1; /* Downstream Port 1 (client side) */ + struct pci_dev *provider_leaf; + struct pci_dev *client_leaf; + struct acs_port_cfg dn0_cfg; + struct acs_port_cfg dn1_cfg; + struct acs_port_cfg provider_leaf_cfg; + struct acs_port_cfg client_leaf_cfg; + struct acs_port_cfg rootport_cfg; +}; + +static int acs_port_read(struct pci_dev *port, struct acs_port_cfg *cfg, + int where, int size, u32 *val) +{ + if (port->acs_cap && size =3D=3D 2 && + where =3D=3D port->acs_cap + PCI_ACS_CTRL) { + if (cfg->fail_read) + return PCIBIOS_DEVICE_NOT_FOUND; + *val =3D cfg->ctrl; + } + + return PCIBIOS_SUCCESSFUL; +} + +static int acs_fabric_read(struct pci_bus *bus, unsigned int devfn, + int where, int size, u32 *val) +{ + struct acs_fabric *f =3D bus->sysdata; + + *val =3D 0; + if (bus =3D=3D f->rootport->bus && devfn =3D=3D f->rootport->devfn) + return acs_port_read(f->rootport, &f->rootport_cfg, + where, size, val); + if (bus =3D=3D f->dn0->bus && devfn =3D=3D f->dn0->devfn) + return acs_port_read(f->dn0, &f->dn0_cfg, where, size, val); + if (bus =3D=3D f->dn1->bus && devfn =3D=3D f->dn1->devfn) + return acs_port_read(f->dn1, &f->dn1_cfg, where, size, val); + if (bus =3D=3D f->provider_leaf->bus && + devfn =3D=3D f->provider_leaf->devfn) + return acs_port_read(f->provider_leaf, &f->provider_leaf_cfg, + where, size, val); + if (bus =3D=3D f->client_leaf->bus && devfn =3D=3D f->client_leaf->devfn) + return acs_port_read(f->client_leaf, &f->client_leaf_cfg, + where, size, val); + + return PCIBIOS_SUCCESSFUL; +} + +static int acs_fabric_write(struct pci_bus *bus, unsigned int devfn, + int where, int size, u32 val) +{ + return PCIBIOS_SUCCESSFUL; +} + +static struct pci_ops acs_fabric_ops =3D { + .read =3D acs_fabric_read, + .write =3D acs_fabric_write, +}; + +static struct pci_bus *acs_add_bus(struct kunit *test, struct pci_bus *par= ent, + struct pci_dev *self, u8 nr, void *sysdata) +{ + struct pci_bus *bus =3D kunit_kzalloc(test, sizeof(*bus), GFP_KERNEL); + + KUNIT_ASSERT_NOT_NULL(test, bus); + bus->parent =3D parent; + bus->self =3D self; + bus->number =3D nr; + bus->ops =3D &acs_fabric_ops; + bus->sysdata =3D sysdata; + INIT_LIST_HEAD(&bus->devices); + return bus; +} + +static struct pci_dev *acs_add_dev(struct kunit *test, struct pci_bus *bus, + unsigned int devfn, int pcie_type) +{ + struct pci_dev *dev =3D kunit_kzalloc(test, sizeof(*dev), GFP_KERNEL); + + KUNIT_ASSERT_NOT_NULL(test, dev); + dev->bus =3D bus; + dev->devfn =3D devfn; + dev->pcie_cap =3D 0x40; + dev->pcie_flags_reg =3D (pcie_type << 4) | 0x2; + list_add_tail(&dev->bus_list, &bus->devices); + return dev; +} + +static void acs_build_fabric(struct kunit *test, struct acs_fabric *f) +{ + struct pci_bus *bus0, *bus1, *bus2, *bus3, *bus4, *bus5, *bus6; + struct pci_bus *bus7, *bus8; + struct pci_dev *swup, *provider_swup, *client_swup; + struct pci_dev *rootport; + struct pci_host_bridge *host; + + host =3D kunit_kzalloc(test, sizeof(*host), GFP_KERNEL); + KUNIT_ASSERT_NOT_NULL(test, host); + + bus0 =3D acs_add_bus(test, NULL, NULL, 0, f); + /* The Root Port doubles as the whitelisted host-bridge device. */ + rootport =3D acs_add_dev(test, bus0, PCI_DEVFN(0, 0), + PCI_EXP_TYPE_ROOT_PORT); + f->rootport =3D rootport; + rootport->vendor =3D PCI_VENDOR_ID_GOOGLE; + rootport->device =3D 0x1234; + host->bus =3D bus0; + bus0->bridge =3D &host->dev; + + bus1 =3D acs_add_bus(test, bus0, rootport, 1, f); + swup =3D acs_add_dev(test, bus1, PCI_DEVFN(0, 0), + PCI_EXP_TYPE_UPSTREAM); + + bus2 =3D acs_add_bus(test, bus1, swup, 2, f); + f->dn0 =3D acs_add_dev(test, bus2, PCI_DEVFN(0, 0), + PCI_EXP_TYPE_DOWNSTREAM); + f->dn1 =3D acs_add_dev(test, bus2, PCI_DEVFN(1, 0), + PCI_EXP_TYPE_DOWNSTREAM); + + bus3 =3D acs_add_bus(test, bus2, f->dn0, 3, f); + provider_swup =3D acs_add_dev(test, bus3, PCI_DEVFN(0, 0), + PCI_EXP_TYPE_UPSTREAM); + bus5 =3D acs_add_bus(test, bus3, provider_swup, 5, f); + f->provider_leaf =3D acs_add_dev(test, bus5, PCI_DEVFN(0, 0), + PCI_EXP_TYPE_DOWNSTREAM); + bus7 =3D acs_add_bus(test, bus5, f->provider_leaf, 7, f); + f->provider =3D acs_add_dev(test, bus7, PCI_DEVFN(0, 0), + PCI_EXP_TYPE_ENDPOINT); + + bus4 =3D acs_add_bus(test, bus2, f->dn1, 4, f); + client_swup =3D acs_add_dev(test, bus4, PCI_DEVFN(0, 0), + PCI_EXP_TYPE_UPSTREAM); + bus6 =3D acs_add_bus(test, bus4, client_swup, 6, f); + f->client_leaf =3D acs_add_dev(test, bus6, PCI_DEVFN(0, 0), + PCI_EXP_TYPE_DOWNSTREAM); + bus8 =3D acs_add_bus(test, bus6, f->client_leaf, 8, f); + f->client =3D acs_add_dev(test, bus8, PCI_DEVFN(0, 0), + PCI_EXP_TYPE_ENDPOINT); +} + +static enum pci_p2pdma_map_type acs_walk_map(struct acs_fabric *f, + unsigned int tlp_flags) +{ + int dist; + + return calc_map_type_and_dist(f->provider, f->client, &dist, tlp_flags, + false); +} + +static void acs_walk_bus_addr_test(struct kunit *test) +{ + struct acs_fabric f =3D {}; + + acs_build_fabric(test, &f); + KUNIT_EXPECT_EQ(test, acs_walk_map(&f, 0), PCI_P2PDMA_MAP_BUS_ADDR); +} + +static void acs_walk_request_redirect_test(struct kunit *test) +{ + struct acs_fabric f =3D {}; + + acs_build_fabric(test, &f); + f.dn1->acs_cap =3D 0x100; + f.dn1->acs_capabilities =3D PCI_ACS_RR; + f.dn1_cfg.ctrl =3D PCI_ACS_RR; + + KUNIT_EXPECT_EQ(test, acs_walk_map(&f, 0), + PCI_P2PDMA_MAP_THRU_HOST_BRIDGE); +} + +static void acs_walk_completion_redirect_test(struct kunit *test) +{ + struct acs_fabric f =3D {}; + + acs_build_fabric(test, &f); + f.dn0->acs_cap =3D 0x100; + f.dn0->acs_capabilities =3D PCI_ACS_CR; + f.dn0_cfg.ctrl =3D PCI_ACS_CR; + + KUNIT_EXPECT_EQ(test, acs_walk_map(&f, 0), + PCI_P2PDMA_MAP_THRU_HOST_BRIDGE); +} + +static void acs_walk_egress_control_test(struct kunit *test) +{ + struct acs_fabric f =3D {}; + + acs_build_fabric(test, &f); + f.dn1->acs_cap =3D 0x100; + f.dn1->acs_capabilities =3D PCI_ACS_EC; + f.dn1_cfg.ctrl =3D PCI_ACS_EC; + + KUNIT_EXPECT_EQ(test, acs_walk_map(&f, 0), + PCI_P2PDMA_MAP_THRU_HOST_BRIDGE); +} + +static void acs_walk_asymmetric_direct_test(struct kunit *test) +{ + struct acs_fabric f =3D {}; + + acs_build_fabric(test, &f); + /* These controls affect only the reverse transaction directions. */ + f.dn0->acs_cap =3D 0x100; + f.dn0->acs_capabilities =3D PCI_ACS_RR | PCI_ACS_EC; + f.dn0_cfg.ctrl =3D PCI_ACS_RR | PCI_ACS_EC; + f.dn1->acs_cap =3D 0x100; + f.dn1->acs_capabilities =3D PCI_ACS_CR; + f.dn1_cfg.ctrl =3D PCI_ACS_CR; + + KUNIT_EXPECT_EQ(test, acs_walk_map(&f, 0), PCI_P2PDMA_MAP_BUS_ADDR); +} + +static void acs_walk_nested_completion_redirect_test(struct kunit *test) +{ + struct acs_fabric f =3D {}; + + acs_build_fabric(test, &f); + f.provider_leaf->acs_cap =3D 0x100; + f.provider_leaf->acs_capabilities =3D PCI_ACS_CR; + f.provider_leaf_cfg.ctrl =3D PCI_ACS_CR; + + KUNIT_EXPECT_EQ(test, acs_walk_map(&f, 0), PCI_P2PDMA_MAP_BUS_ADDR); +} + +static void acs_walk_nested_request_redirect_test(struct kunit *test) +{ + struct acs_fabric f =3D {}; + + acs_build_fabric(test, &f); + f.client_leaf->acs_cap =3D 0x100; + f.client_leaf->acs_capabilities =3D PCI_ACS_RR; + f.client_leaf_cfg.ctrl =3D PCI_ACS_RR; + + KUNIT_EXPECT_EQ(test, acs_walk_map(&f, 0), PCI_P2PDMA_MAP_BUS_ADDR); +} + +static void acs_walk_translation_blocking_test(struct kunit *test) +{ + struct acs_fabric f =3D {}; + + acs_build_fabric(test, &f); + f.client_leaf->acs_cap =3D 0x100; + f.client_leaf->acs_capabilities =3D PCI_ACS_TB; + f.client_leaf_cfg.ctrl =3D PCI_ACS_TB; + + /* Untranslated Requests are unaffected by Translation Blocking. */ + KUNIT_EXPECT_EQ(test, acs_walk_map(&f, 0), PCI_P2PDMA_MAP_BUS_ADDR); + KUNIT_EXPECT_EQ(test, acs_walk_map(&f, PCI_P2PDMA_TLP_TRANSLATED), + PCI_P2PDMA_MAP_NOT_SUPPORTED); +} + +static void acs_walk_relaxed_completion_test(struct kunit *test) +{ + struct acs_fabric f =3D {}; + + acs_build_fabric(test, &f); + f.dn0->acs_cap =3D 0x100; + f.dn0->acs_capabilities =3D PCI_ACS_CR; + f.dn0_cfg.ctrl =3D PCI_ACS_CR; + + KUNIT_EXPECT_EQ(test, acs_walk_map(&f, 0), + PCI_P2PDMA_MAP_THRU_HOST_BRIDGE); + KUNIT_EXPECT_EQ(test, acs_walk_map(&f, PCI_P2PDMA_TLP_RELAXED_CPL), + PCI_P2PDMA_MAP_BUS_ADDR); +} + +static void acs_walk_direct_translated_test(struct kunit *test) +{ + struct acs_fabric f =3D {}; + + acs_build_fabric(test, &f); + f.dn1->acs_cap =3D 0x100; + f.dn1->acs_capabilities =3D PCI_ACS_RR | PCI_ACS_DT; + f.dn1_cfg.ctrl =3D PCI_ACS_RR | PCI_ACS_DT; + + KUNIT_EXPECT_EQ(test, acs_walk_map(&f, 0), + PCI_P2PDMA_MAP_THRU_HOST_BRIDGE); + KUNIT_EXPECT_EQ(test, acs_walk_map(&f, PCI_P2PDMA_TLP_TRANSLATED), + PCI_P2PDMA_MAP_BUS_ADDR); +} + +/* + * The cache stores one packed value per client, so every class has to come + * back out under the flags that selected it. + */ +static void acs_map_types_pack_test(struct kunit *test) +{ + static const enum pci_p2pdma_map_type type[PCI_P2PDMA_TLP_CLASSES] =3D { + [0] =3D PCI_P2PDMA_MAP_THRU_HOST_BRIDGE, + [PCI_P2PDMA_TLP_TRANSLATED] =3D PCI_P2PDMA_MAP_NOT_SUPPORTED, + [PCI_P2PDMA_TLP_RELAXED_CPL] =3D PCI_P2PDMA_MAP_BUS_ADDR, + [PCI_P2PDMA_TLP_TRANSLATED | PCI_P2PDMA_TLP_RELAXED_CPL] =3D + PCI_P2PDMA_MAP_UNKNOWN, + }; + unsigned long packed =3D pci_p2pdma_map_types_pack(type); + unsigned int flags; + + for (flags =3D 0; flags < PCI_P2PDMA_TLP_CLASSES; flags++) + KUNIT_EXPECT_EQ(test, + pci_p2pdma_map_types_unpack(packed, flags), + type[flags]); + + /* An absent cache entry reads back as unknown in every class. */ + for (flags =3D 0; flags < PCI_P2PDMA_TLP_CLASSES; flags++) + KUNIT_EXPECT_EQ(test, pci_p2pdma_map_types_unpack(0, flags), + PCI_P2PDMA_MAP_UNKNOWN); +} + +/* + * The provider can be an ancestor of the client, which leaves no divergen= ce + * to evaluate. Translation Blocking still applies to every port the Reque= st + * passes on its way up. + */ +static void acs_walk_ancestor_provider_tb_test(struct kunit *test) +{ + struct acs_fabric f =3D {}; + int dist; + + acs_build_fabric(test, &f); + f.client_leaf->acs_cap =3D 0x100; + f.client_leaf->acs_capabilities =3D PCI_ACS_TB; + f.client_leaf_cfg.ctrl =3D PCI_ACS_TB; + + KUNIT_EXPECT_EQ(test, + calc_map_type_and_dist(f.dn1, f.client, &dist, 0, + false), + PCI_P2PDMA_MAP_BUS_ADDR); + KUNIT_EXPECT_EQ(test, + calc_map_type_and_dist(f.dn1, f.client, &dist, + PCI_P2PDMA_TLP_TRANSLATED, + false), + PCI_P2PDMA_MAP_NOT_SUPPORTED); +} + +/* + * Without a common upstream bridge the Request still climbs towards the h= ost + * bridge, so Translation Blocking on the way withdraws the Translated cla= sses + * there too. + */ +static void acs_walk_no_common_bridge_tb_test(struct kunit *test) +{ + struct acs_fabric f =3D {}, g =3D {}; + int dist; + + acs_build_fabric(test, &f); + acs_build_fabric(test, &g); + f.client_leaf->acs_cap =3D 0x100; + f.client_leaf->acs_capabilities =3D PCI_ACS_TB; + f.client_leaf_cfg.ctrl =3D PCI_ACS_TB; + + KUNIT_EXPECT_EQ(test, + calc_map_type_and_dist(g.provider, f.client, &dist, 0, + false), + PCI_P2PDMA_MAP_THRU_HOST_BRIDGE); + KUNIT_EXPECT_EQ(test, + calc_map_type_and_dist(g.provider, f.client, &dist, + PCI_P2PDMA_TLP_TRANSLATED, + false), + PCI_P2PDMA_MAP_NOT_SUPPORTED); +} + +/* + * A Request between the client and itself never leaves the device, so no = port + * is in a position to inspect its Address Type. Translation Blocking dire= ctly + * above the client must not withdraw the Translated classes. + */ +static void acs_walk_self_dma_tb_test(struct kunit *test) +{ + struct acs_fabric f =3D {}; + int dist; + + acs_build_fabric(test, &f); + f.client_leaf->acs_cap =3D 0x100; + f.client_leaf->acs_capabilities =3D PCI_ACS_TB; + f.client_leaf_cfg.ctrl =3D PCI_ACS_TB; + + KUNIT_EXPECT_EQ(test, + calc_map_type_and_dist(f.client, f.client, &dist, 0, + false), + PCI_P2PDMA_MAP_BUS_ADDR); + KUNIT_EXPECT_EQ(test, + calc_map_type_and_dist(f.client, f.client, &dist, + PCI_P2PDMA_TLP_TRANSLATED, + false), + PCI_P2PDMA_MAP_BUS_ADDR); +} + +/* + * A direct route turns around at the divergence, so Translation Blocking = above + * it does not touch one. The host bridge route keeps climbing past that p= ort, + * and the Translated classes have to go without it. + */ +static void acs_walk_tb_above_divergence_test(struct kunit *test) +{ + struct acs_fabric f =3D {}; + int dist; + + acs_build_fabric(test, &f); + f.rootport->acs_cap =3D 0x100; + f.rootport->acs_capabilities =3D PCI_ACS_TB; + f.rootport_cfg.ctrl =3D PCI_ACS_TB; + + /* Nothing redirects yet, so the Request never reaches the Root Port. */ + KUNIT_EXPECT_EQ(test, + calc_map_type_and_dist(f.provider, f.client, &dist, + PCI_P2PDMA_TLP_TRANSLATED, + false), + PCI_P2PDMA_MAP_BUS_ADDR); + + /* Request Redirect sends it up past the Root Port instead. */ + f.dn1->acs_cap =3D 0x100; + f.dn1->acs_capabilities =3D PCI_ACS_RR; + f.dn1_cfg.ctrl =3D PCI_ACS_RR; + + KUNIT_EXPECT_EQ(test, + calc_map_type_and_dist(f.provider, f.client, &dist, 0, + false), + PCI_P2PDMA_MAP_THRU_HOST_BRIDGE); + KUNIT_EXPECT_EQ(test, + calc_map_type_and_dist(f.provider, f.client, &dist, + PCI_P2PDMA_TLP_TRANSLATED, + false), + PCI_P2PDMA_MAP_NOT_SUPPORTED); +} + +static void acs_walk_unreadable_control_test(struct kunit *test) +{ + struct acs_fabric f =3D {}; + + acs_build_fabric(test, &f); + f.dn1->acs_cap =3D 0x100; + f.dn1_cfg.fail_read =3D true; + + KUNIT_EXPECT_EQ(test, acs_walk_map(&f, 0), + PCI_P2PDMA_MAP_NOT_SUPPORTED); +} + static struct kunit_case pci_acs_test_cases[] =3D { KUNIT_CASE_PARAM(pci_acs_p2pdma_request_test, acs_request_gen_params), KUNIT_CASE_PARAM(pci_acs_p2pdma_completion_test, acs_completion_gen_params), + KUNIT_CASE(acs_walk_bus_addr_test), + KUNIT_CASE(acs_walk_request_redirect_test), + KUNIT_CASE(acs_walk_completion_redirect_test), + KUNIT_CASE(acs_walk_egress_control_test), + KUNIT_CASE(acs_walk_asymmetric_direct_test), + KUNIT_CASE(acs_walk_nested_completion_redirect_test), + KUNIT_CASE(acs_walk_nested_request_redirect_test), + KUNIT_CASE(acs_walk_translation_blocking_test), + KUNIT_CASE(acs_walk_ancestor_provider_tb_test), + KUNIT_CASE(acs_walk_no_common_bridge_tb_test), + KUNIT_CASE(acs_walk_self_dma_tb_test), + KUNIT_CASE(acs_walk_relaxed_completion_test), + KUNIT_CASE(acs_walk_direct_translated_test), + KUNIT_CASE(acs_walk_tb_above_divergence_test), + KUNIT_CASE(acs_walk_unreadable_control_test), + KUNIT_CASE(acs_map_types_pack_test), {} }; =20 --=20 2.55.0 From nobody Thu Sep 24 21:19:39 2026 Received: from smtp.kernel.org (aws-us-west-2-korg-mail-alma10-1.taild15c8.ts.net [100.103.45.18]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by smtp.subspace.kernel.org (Postfix) with ESMTPS id CC36742AF9B; Sun, 20 Sep 2026 11:42:47 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=100.103.45.18 ARC-Seal: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1789904569; cv=none; b=fPpFxOfuQ4xOSy7qoPbzCvUO/lxPV+W2V0ekpU4PJfLWVKf/SwGaShoE9hYBzuAHr8t/nrmoq+/XqysAdO0309+aMNFvAhtbNkS8R+DJSR/w7Psa8i0MSdjnPOatQon3aw5jSbALTIxne+7pC1hyeXayzM8e+W11gk9uZuYo4hQ= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1789904569; c=relaxed/simple; bh=5goHf8qnFEWVnRpyRSm4Q14v9IdJboPHAPbwFcwF3w4=; h=From:To:Cc:Subject:Date:Message-ID:In-Reply-To:References: MIME-Version:Content-Type; b=KUDYgQYsfa/3wH+mcSLsGn2fl2CQlfAhKtJ8av4dKFIezyJvMR1r0/ue0hhkNUK8TDw5nL4O7N5/yt3DC9+vXjhTLbrjSkYye/xKQiKo/6C5J0kKM4LGkcVz3pKHlSB7em4q1v7UXqilw11pp6ojBoMAAo5LQyfxH5gZc+wUd2M= ARC-Authentication-Results: i=1; smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=kernel.org header.i=@kernel.org header.b=JmvOFBry; arc=none smtp.client-ip=100.103.45.18 Authentication-Results: smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=kernel.org header.i=@kernel.org header.b="JmvOFBry" Received: by smtp.kernel.org (Postfix) with ESMTPSA id 746051F00893; Sun, 20 Sep 2026 11:42:46 +0000 (UTC) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=kernel.org; s=k20260515; t=1789904567; bh=M35ojtxEBbcQmcfS6jrUvGInMzs+pT9f0QfDo4m1kaI=; h=From:To:Cc:Subject:Date:In-Reply-To:References; b=JmvOFBryur+EUqk42exQkZe9urYWQfoVNSV0StWO0HcS/24RExdFR+waSj8jkAJnm gum5UuvQcf00sKWnjCdTDECy0zT9YPG0i8EIG10lgSPd5LNVmrKhqtZuvyh24RKBvi bDlLgfRbSSXpJzvCVdWCZSJPUjkiQFD4+K5kqQP0wJfgcU/IXMKgf0/dhNrmu9UurV 09Mk+r8iwx5t7Ec+TRXpUcF48DQDBVmDYUSa/vnXJmtbfZHH3eUruGmZHsYnz3r/sh vT/fImRQEjqx42o11QSLeBIy48O6ipYn6hza9GL5GwJoIwEdgUd0j0wvQhIVPDkGyA zrH0xaaiJmjAA== From: Leon Romanovsky To: Bjorn Helgaas , Logan Gunthorpe , Chaitanya Kulkarni , Greg Kroah-Hartman , Jens Axboe , Alex Williamson , Leon Romanovsky , Ankit Agrawal , Jason Gunthorpe , Jonathan Corbet , Shuah Khan , "Joerg Roedel (AMD)" , Will Deacon , Robin Murphy , Randy Dunlap , Sumit Semwal , =?utf-8?q?Christian_K=C3=B6nig?= Cc: linux-pci@vger.kernel.org, linux-kernel@vger.kernel.org, linux-doc@vger.kernel.org, iommu@lists.linux.dev, Tushar Dave , 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 Subject: [PATCH v7 14/19] PCI: Add KUnit coverage for ACS isolation checks Date: Sun, 20 Sep 2026 14:41:26 +0300 Message-ID: <20260920-fix-p2p-acs-v4-0-v7-14-ca0828ab697c@nvidia.com> X-Mailer: git-send-email 2.55.0 In-Reply-To: <20260920-fix-p2p-acs-v4-0-v7-0-ca0828ab697c@nvidia.com> References: <20260920-fix-p2p-acs-v4-0-v7-0-ca0828ab697c@nvidia.com> Precedence: bulk X-Mailing-List: linux-kernel@vger.kernel.org List-Id: List-Subscribe: List-Unsubscribe: MIME-Version: 1.0 Content-Type: text/plain; charset="utf-8" X-Mailer: b4 0.15-dev-18f8f Content-Transfer-Encoding: quoted-printable From: Leon Romanovsky Direct Translated P2P does not weaken IOMMU isolation because a Translated Request carries an address supplied by the IOMMU. Config-space read failures, however, leave ACS state unknown and must not report isolation. Exercise both cases with fake config-space operations. Also cover missing and unrequested controls and a missing ACS capability. Tested-by: Tushar Dave Signed-off-by: Leon Romanovsky --- drivers/pci/pci.c | 4 +- drivers/pci/pci.h | 1 + drivers/pci/pci_acs_test.c | 138 +++++++++++++++++++++++++++++++++++++++++= ++++ 3 files changed, 142 insertions(+), 1 deletion(-) diff --git a/drivers/pci/pci.c b/drivers/pci/pci.c index f7d94ecf9157..4a9ab3882aac 100644 --- a/drivers/pci/pci.c +++ b/drivers/pci/pci.c @@ -3578,7 +3578,8 @@ void pci_configure_ari(struct pci_dev *dev) } } =20 -static bool pci_acs_flags_enabled(struct pci_dev *pdev, u16 acs_flags) +VISIBLE_IF_KUNIT +bool pci_acs_flags_enabled(struct pci_dev *pdev, u16 acs_flags) { int pos; u16 ctrl; @@ -3598,6 +3599,7 @@ static bool pci_acs_flags_enabled(struct pci_dev *pde= v, u16 acs_flags) return false; return (ctrl & acs_flags) =3D=3D acs_flags; } +EXPORT_SYMBOL_IF_KUNIT(pci_acs_flags_enabled); =20 /** * pci_acs_enabled - test ACS against required flags for a given device diff --git a/drivers/pci/pci.h b/drivers/pci/pci.h index 56f821e40637..5bc703ff0c86 100644 --- a/drivers/pci/pci.h +++ b/drivers/pci/pci.h @@ -1104,6 +1104,7 @@ enum pci_acs_p2pdma_state { }; =20 #if IS_ENABLED(CONFIG_KUNIT) +bool pci_acs_flags_enabled(struct pci_dev *pdev, u16 acs_flags); enum pci_acs_p2pdma_state pci_acs_p2pdma_request(u16 ctrl, unsigned int tlp_flags); enum pci_acs_p2pdma_state pci_acs_p2pdma_completion(u16 ctrl, diff --git a/drivers/pci/pci_acs_test.c b/drivers/pci/pci_acs_test.c index 7f4f9cc04bfb..6a2cd38d968f 100644 --- a/drivers/pci/pci_acs_test.c +++ b/drivers/pci/pci_acs_test.c @@ -102,6 +102,140 @@ static void pci_acs_p2pdma_completion_test(struct kun= it *test) c->expect); } =20 +/* Flags an IOMMU asks for; see REQ_ACS_FLAGS in drivers/iommu/iommu.c. */ +#define ACS_REQ_FLAGS (PCI_ACS_SV | PCI_ACS_RR | PCI_ACS_CR | PCI_ACS_UF) +#define ACS_ALL_CAPS (PCI_ACS_SV | PCI_ACS_TB | PCI_ACS_RR | PCI_ACS_CR | \ + PCI_ACS_UF | PCI_ACS_DT) +#define ACS_TEST_CAP 0x100 + +struct acs_ctrl_cfg { + unsigned int devfn; + u16 cap; /* Offset where the ACS capability responds */ + u16 ctrl; + bool fail_read; +}; + +static int acs_ctrl_read(struct pci_bus *bus, unsigned int devfn, + int where, int size, u32 *val) +{ + struct acs_ctrl_cfg *cfg =3D bus->sysdata; + + *val =3D 0; + if (cfg->fail_read) + return PCIBIOS_DEVICE_NOT_FOUND; + + if (devfn =3D=3D cfg->devfn && size =3D=3D 2 && + where =3D=3D cfg->cap + PCI_ACS_CTRL) + *val =3D cfg->ctrl; + return PCIBIOS_SUCCESSFUL; +} + +static int acs_ctrl_write(struct pci_bus *bus, unsigned int devfn, + int where, int size, u32 val) +{ + return PCIBIOS_SUCCESSFUL; +} + +static struct pci_ops acs_ctrl_ops =3D { + .read =3D acs_ctrl_read, + .write =3D acs_ctrl_write, +}; + +struct acs_isolation_case { + const char *desc; + u16 ctrl; + u16 req; + bool expect; +}; + +static const struct acs_isolation_case acs_isolation_cases[] =3D { + { "all_enabled", ACS_REQ_FLAGS, ACS_REQ_FLAGS, true }, + /* Translated Requests remain isolated by their IOMMU translation. */ + { "dt", ACS_REQ_FLAGS | PCI_ACS_DT, ACS_REQ_FLAGS, true }, + { "rr_not_enabled", PCI_ACS_SV | PCI_ACS_CR | PCI_ACS_UF, + ACS_REQ_FLAGS, false }, + { "rr_not_required", PCI_ACS_SV | PCI_ACS_CR | PCI_ACS_UF, + PCI_ACS_SV | PCI_ACS_CR | PCI_ACS_UF, true }, +}; + +static void acs_isolation_desc(const struct acs_isolation_case *c, char *d= esc) +{ + strscpy(desc, c->desc, KUNIT_PARAM_DESC_SIZE); +} + +KUNIT_ARRAY_PARAM(acs_isolation, acs_isolation_cases, acs_isolation_desc); + +static void pci_acs_flags_enabled_test(struct kunit *test) +{ + const struct acs_isolation_case *c =3D test->param_value; + struct acs_ctrl_cfg cfg =3D { + .devfn =3D PCI_DEVFN(0, 0), + .cap =3D ACS_TEST_CAP, + .ctrl =3D c->ctrl, + }; + struct pci_bus *bus =3D kunit_kzalloc(test, sizeof(*bus), GFP_KERNEL); + struct pci_dev *pdev =3D kunit_kzalloc(test, sizeof(*pdev), GFP_KERNEL); + + KUNIT_ASSERT_NOT_NULL(test, bus); + KUNIT_ASSERT_NOT_NULL(test, pdev); + + bus->ops =3D &acs_ctrl_ops; + bus->sysdata =3D &cfg; + + pdev->bus =3D bus; + pdev->devfn =3D cfg.devfn; + pdev->acs_cap =3D ACS_TEST_CAP; + pdev->acs_capabilities =3D ACS_ALL_CAPS; + + KUNIT_EXPECT_EQ(test, pci_acs_flags_enabled(pdev, c->req), c->expect); +} + +static bool acs_isolated(struct kunit *test, struct acs_ctrl_cfg *cfg, + u16 acs_cap, u16 acs_flags) +{ + struct pci_bus *bus =3D kunit_kzalloc(test, sizeof(*bus), GFP_KERNEL); + struct pci_dev *pdev =3D kunit_kzalloc(test, sizeof(*pdev), GFP_KERNEL); + + KUNIT_ASSERT_NOT_NULL(test, bus); + KUNIT_ASSERT_NOT_NULL(test, pdev); + + bus->ops =3D &acs_ctrl_ops; + bus->sysdata =3D cfg; + + pdev->bus =3D bus; + pdev->devfn =3D cfg->devfn; + pdev->acs_cap =3D acs_cap; + pdev->acs_capabilities =3D ACS_ALL_CAPS; + + return pci_acs_flags_enabled(pdev, acs_flags); +} + +static void pci_acs_flags_no_cap_test(struct kunit *test) +{ + struct acs_ctrl_cfg cfg =3D { + .devfn =3D PCI_DEVFN(0, 0), + .cap =3D 0, + .ctrl =3D ACS_REQ_FLAGS, + }; + + KUNIT_EXPECT_FALSE(test, acs_isolated(test, &cfg, 0, ACS_REQ_FLAGS)); +} + +static void pci_acs_flags_read_fails_test(struct kunit *test) +{ + u16 no_rr =3D ACS_REQ_FLAGS & ~PCI_ACS_RR; + struct acs_ctrl_cfg cfg =3D { + .devfn =3D PCI_DEVFN(0, 0), + .cap =3D ACS_TEST_CAP, + .ctrl =3D ACS_REQ_FLAGS, + }; + + KUNIT_EXPECT_TRUE(test, acs_isolated(test, &cfg, ACS_TEST_CAP, no_rr)); + + cfg.fail_read =3D true; + KUNIT_EXPECT_FALSE(test, acs_isolated(test, &cfg, ACS_TEST_CAP, no_rr)); +} + /* * Drive calc_map_type_and_dist() over a fabricated PCIe fabric matching t= he * canonical topology of two devices below one switch: @@ -569,6 +703,10 @@ static struct kunit_case pci_acs_test_cases[] =3D { acs_request_gen_params), KUNIT_CASE_PARAM(pci_acs_p2pdma_completion_test, acs_completion_gen_params), + KUNIT_CASE_PARAM(pci_acs_flags_enabled_test, + acs_isolation_gen_params), + KUNIT_CASE(pci_acs_flags_no_cap_test), + KUNIT_CASE(pci_acs_flags_read_fails_test), KUNIT_CASE(acs_walk_bus_addr_test), KUNIT_CASE(acs_walk_request_redirect_test), KUNIT_CASE(acs_walk_completion_redirect_test), --=20 2.55.0 From nobody Thu Sep 24 21:19:39 2026 Received: from smtp.kernel.org (aws-us-west-2-korg-mail-alma10-1.taild15c8.ts.net [100.103.45.18]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by smtp.subspace.kernel.org (Postfix) with ESMTPS id 60A91434980; Sun, 20 Sep 2026 11:42:36 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=100.103.45.18 ARC-Seal: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1789904557; cv=none; b=XkZ9NLWKkwOw/2CkeGXvn/4Xf6ynex6tmpKWrqFGJPQLmPSV5Tdqg/Q5SMuDwgADkBtf539JtF0PsFamZnqx9oicjhhV5G8EwLzX7zWiaLMIhwPsSlxX714ciWPMsPPiSwRaJ9mDK+/FwN+kLSADS/EmufevGpwOgo7+CRT7SSc= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1789904557; c=relaxed/simple; bh=WJ8vDmq5Rqo9zAbKzJaD08931Vbczj72A909B5+v1IY=; h=From:To:Cc:Subject:Date:Message-ID:In-Reply-To:References: MIME-Version:Content-Type; b=Oy09zfysPsb3/ntAkvombtgilxtZMk64+ZI7uNLV8pstjxTayRZ2ARo2y1cMYSZhvcybk4h51CPZuqOd7NDNYFdKpXR3Mvs1RCXLPvd2LnDh3ZykQkkg8FUFjRSDRb1DPN1LUi4rqU1s/dbIcrAAbrgqf1F7TEo6iBV0KLZH+gM= ARC-Authentication-Results: i=1; smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=kernel.org header.i=@kernel.org header.b=TMwH4kQt; arc=none smtp.client-ip=100.103.45.18 Authentication-Results: smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=kernel.org header.i=@kernel.org header.b="TMwH4kQt" Received: by smtp.kernel.org (Postfix) with ESMTPSA id 4CAC21F000FF; Sun, 20 Sep 2026 11:42:35 +0000 (UTC) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=kernel.org; s=k20260515; t=1789904556; bh=68FZjmCCs1UD6FDyhk+W02Nb/KkrZwWXOELgmkfWKag=; h=From:To:Cc:Subject:Date:In-Reply-To:References; b=TMwH4kQt7AERs1SAKegLtBr5ODxXNlErREEp3vPn02AZxzlY/b6odiS66tZHTf7D+ vUaan1LgCy+T+9jIYm7RQ0yZwNm2nKFTWFGkP8VjYxKi5/aB5zHDAVl9g8HOk3hSBL GQCsmT2bDBz+6KJuGOChe9T0Av/pzhspUBZNUWJVema4LZoV3+LOZ92PQAg8QNYX6/ 6Uey4KMJGJlvBMo+WDgGyheiZMM7Q47L2NIcRUApxcnwWl+0iEKHs8TYhF8Sl6M/oz GAvNMZJQmijSSwA4Rwai9kpKIlQzzYW/Gk1Bz00aDd/fEeTCkgJ9Qgg6AGwCN0HA72 cBVzwBM39s66w== From: Leon Romanovsky To: Bjorn Helgaas , Logan Gunthorpe , Chaitanya Kulkarni , Greg Kroah-Hartman , Jens Axboe , Alex Williamson , Leon Romanovsky , Ankit Agrawal , Jason Gunthorpe , Jonathan Corbet , Shuah Khan , "Joerg Roedel (AMD)" , Will Deacon , Robin Murphy , Randy Dunlap , Sumit Semwal , =?utf-8?q?Christian_K=C3=B6nig?= Cc: linux-pci@vger.kernel.org, linux-kernel@vger.kernel.org, linux-doc@vger.kernel.org, iommu@lists.linux.dev, Tushar Dave , 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 Subject: [PATCH v7 15/19] PCI/P2PDMA: Document TLP-class routing Date: Sun, 20 Sep 2026 14:41:27 +0300 Message-ID: <20260920-fix-p2p-acs-v4-0-v7-15-ca0828ab697c@nvidia.com> X-Mailer: git-send-email 2.55.0 In-Reply-To: <20260920-fix-p2p-acs-v4-0-v7-0-ca0828ab697c@nvidia.com> References: <20260920-fix-p2p-acs-v4-0-v7-0-ca0828ab697c@nvidia.com> Precedence: bulk X-Mailing-List: linux-kernel@vger.kernel.org List-Id: List-Subscribe: List-Unsubscribe: MIME-Version: 1.0 Content-Type: text/plain; charset="utf-8" X-Mailer: b4 0.15-dev-18f8f Content-Transfer-Encoding: quoted-printable From: Leon Romanovsky The P2PDMA documentation stated that the mapping result is not defined for Relaxed Ordering or ATS-translated Requests. It now is. Replace that paragraph with what the three TLP-sensitive ACS controls do, the table of outcomes per class, and the interface a client uses to name its traffic. Record that a caller claiming Relaxed Ordering Completions is asserting provider behaviour the PCIe specification leaves optional. Tested-by: Tushar Dave Signed-off-by: Leon Romanovsky --- Documentation/driver-api/pci/p2pdma.rst | 63 +++++++++++++++++++++++++++++= ---- 1 file changed, 57 insertions(+), 6 deletions(-) diff --git a/Documentation/driver-api/pci/p2pdma.rst b/Documentation/driver= -api/pci/p2pdma.rst index 42b18610bf7d..b4ec53d74089 100644 --- a/Documentation/driver-api/pci/p2pdma.rst +++ b/Documentation/driver-api/pci/p2pdma.rst @@ -28,12 +28,63 @@ through the host bridge when either applicable port red= irects. If an ACS Control register cannot be read, P2P DMA is rejected because the kernel ca= nnot establish a usable route. =20 -This evaluation assumes clients issue strictly ordered Requests carrying an -Untranslated address. Its result is not defined when clients use Relaxed -Ordering or issue ATS-translated Requests because those TLP attributes can -select different routes through the fabric. Unless ACS Translation Blocking -is enabled, a Port with ACS Direct Translated P2P enabled routes a -Translated Request directly to the peer regardless of the redirect control= s. +Three of those controls act on TLP attributes that the client chooses rath= er +than on the topology, so the same path routes differently for different +traffic. ACS Translation Blocking rejects any Request whose Address Type is +not Untranslated, and takes precedence over every other P2P control. ACS +Direct Translated P2P routes a Translated Request to the peer regardless of +Request Redirect and Egress Control. ACS Completion Redirect leaves alone +Completions that carry the Relaxed Ordering attribute. + +A client therefore describes its traffic with ``enum pci_p2pdma_tlp_flags`` +and asks ``pci_p2pdma_map_type_tlp()``. ``pci_p2pdma_map_type()`` answers = for +the default: strictly ordered Requests carrying an Untranslated address. + +The two directions are decided independently. Translation Blocking (TB), +Direct Translated P2P (DT), Request Redirect (RR) and Egress Control (EC) = on +the client-side port decide the Request: + +=3D=3D=3D=3D=3D =3D=3D=3D=3D=3D =3D=3D=3D=3D=3D=3D=3D =3D=3D=3D=3D=3D= =3D=3D=3D=3D=3D=3D=3D =3D=3D=3D=3D=3D=3D=3D=3D=3D=3D +TB DT RR/EC TLP class Request +=3D=3D=3D=3D=3D =3D=3D=3D=3D=3D =3D=3D=3D=3D=3D=3D=3D =3D=3D=3D=3D=3D= =3D=3D=3D=3D=3D=3D=3D =3D=3D=3D=3D=3D=3D=3D=3D=3D=3D +set x x translated blocked +clear set x translated direct +clear clear clear translated direct +clear clear set translated redirected +x x clear untranslated direct +x x set untranslated redirected +=3D=3D=3D=3D=3D =3D=3D=3D=3D=3D =3D=3D=3D=3D=3D=3D=3D =3D=3D=3D=3D=3D= =3D=3D=3D=3D=3D=3D=3D =3D=3D=3D=3D=3D=3D=3D=3D=3D=3D + +Completion Redirect (CR) on the provider-side port decides the Completions: + +=3D=3D=3D=3D=3D =3D=3D=3D=3D=3D=3D=3D=3D=3D =3D=3D=3D=3D=3D=3D=3D=3D=3D= =3D +CR TLP class Completion +=3D=3D=3D=3D=3D =3D=3D=3D=3D=3D=3D=3D=3D=3D =3D=3D=3D=3D=3D=3D=3D=3D=3D= =3D +x relaxed direct +clear strict direct +set strict redirected +=3D=3D=3D=3D=3D =3D=3D=3D=3D=3D=3D=3D=3D=3D =3D=3D=3D=3D=3D=3D=3D=3D=3D= =3D + +A path is bus addressable only where both directions route directly, so wi= th +nothing enabled every class is. A blocked Request is not supported, because +Translation Blocking rejects the Address Type wherever the Request is +addressed. Anything else goes through the host bridge. + +Note that DT only matters where RR or EC would otherwise redirect: it +overrides them for a Translated address rather than granting a direct route +that was not already there. + +Translation Blocking is not a routing control, so it is evaluated on every +port the Request passes rather than at the divergence alone. A direct route +turns around at the divergence and only passes the ports below it, while t= he +host bridge route keeps climbing and passes that port and everything above= it +as well. Neither route falls back to the other, because the Address Type is +rejected wherever the Request is addressed. + +The Completer chooses whether a Completion carries Relaxed Ordering, and t= he +PCIe specification does not require it to copy that attribute from the +Request. A caller passing ``PCI_P2PDMA_TLP_RELAXED_CPL`` is asserting that +its provider does. =20 However, if the P2P transaction reaches the host bridge then it might have= to hairpin back out the same root port, be routed inside the CPU SOC to anoth= er --=20 2.55.0 From nobody Thu Sep 24 21:19:39 2026 Received: from smtp.kernel.org (aws-us-west-2-korg-mail-alma10-1.taild15c8.ts.net [100.103.45.18]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by smtp.subspace.kernel.org (Postfix) with ESMTPS id 215AB41DDFF; Sun, 20 Sep 2026 11:42:39 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=100.103.45.18 ARC-Seal: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1789904561; cv=none; b=Hy4uZkUxaZV9ifwspNWlDyiXJxRlIGc0YUnWQSwEIicIGnxsmJC0K0nqYH16S9kd23ACbyPtARwI69bN75EKprdBGG1l7vW4y2jrfCKYZ9Zx0LsvQPztRkSX70VDksyd6Jx1P2CwZiziv9hy2H5HOZZJLfqBfzXCfCvtWUi6uAU= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1789904561; c=relaxed/simple; bh=Soqbec9vVVKuXYZxvaud05V1gsviiQEyuDFMVwYcy0M=; h=From:To:Cc:Subject:Date:Message-ID:In-Reply-To:References: MIME-Version:Content-Type; b=SjRKr5Skp397kyyXtnFdr7JFYd+EAadkOB3axNzL2132yeLcNkzPzQRSTZ7qsTBx0mhGDIwJaOmuw2zZ4mlRC9riBpLu4l0OC68vY74f0N6zlKCP1np8xGQmN1/VkD48N5jVr2sNefkGfSaA5qWZaSzGutp2bh0a1/R5ECEDSds= ARC-Authentication-Results: i=1; smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=kernel.org header.i=@kernel.org header.b=e62EDnrb; arc=none smtp.client-ip=100.103.45.18 Authentication-Results: smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=kernel.org header.i=@kernel.org header.b="e62EDnrb" Received: by smtp.kernel.org (Postfix) with ESMTPSA id BBD851F000FF; Sun, 20 Sep 2026 11:42:38 +0000 (UTC) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=kernel.org; s=k20260515; t=1789904559; bh=/mrSoLPBT5WDIMN7g2Yzlv7di4OqO/Z3hH8lrqqJWsY=; h=From:To:Cc:Subject:Date:In-Reply-To:References; b=e62EDnrbydiZttmQe/8HcgDk1JM8eLmneCt3lGsITqpPb8jj9x+hiZhfnh5HM2fsz 3FiQx/pxf35ygHXRwt1HUOp83kwboKzESeHvdFMcSEObramm8pj9lpKM7SQSJHeuBh U1j5DhrQak4DHoKzFSuGJCh7P88Z9ZZfKq59C24WMIJLZY8UPC4qUG9DAN174njq+b BDAJy6fALd3AFl946DZXWAbvxcLN0t8r5xNkqCeXO3EGwZ2xudk6nuT7CIku7OnuoZ knWxAdDDuDDnneNLGIeeC55nVZBTpIKQsGpA4Z68lJDAuFHamiJNxy+7o9t2/LzcFA GTcIOV1qKqRlA== From: Leon Romanovsky To: Bjorn Helgaas , Logan Gunthorpe , Chaitanya Kulkarni , Greg Kroah-Hartman , Jens Axboe , Alex Williamson , Leon Romanovsky , Ankit Agrawal , Jason Gunthorpe , Jonathan Corbet , Shuah Khan , "Joerg Roedel (AMD)" , Will Deacon , Robin Murphy , Randy Dunlap , Sumit Semwal , =?utf-8?q?Christian_K=C3=B6nig?= Cc: linux-pci@vger.kernel.org, linux-kernel@vger.kernel.org, linux-doc@vger.kernel.org, iommu@lists.linux.dev, Tushar Dave , 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 Subject: [PATCH v7 16/19] dma-buf: Let importers ask how peer-to-peer traffic is routed Date: Sun, 20 Sep 2026 14:41:28 +0300 Message-ID: <20260920-fix-p2p-acs-v4-0-v7-16-ca0828ab697c@nvidia.com> X-Mailer: git-send-email 2.55.0 In-Reply-To: <20260920-fix-p2p-acs-v4-0-v7-0-ca0828ab697c@nvidia.com> References: <20260920-fix-p2p-acs-v4-0-v7-0-ca0828ab697c@nvidia.com> Precedence: bulk X-Mailing-List: linux-kernel@vger.kernel.org List-Id: List-Subscribe: List-Unsubscribe: MIME-Version: 1.0 Content-Type: text/plain; charset="utf-8" X-Mailer: b4 0.15-dev-18f8f Content-Transfer-Encoding: quoted-printable From: Leon Romanovsky Exporters keep the &struct p2pdma_provider backing a buffer in their own private data. An importer cannot reach it, so it has no way to learn how its own peer-to-peer traffic would be routed before it programs its hardware. Add an optional @p2pdma_provider callback for an exporter to hand that provider out, and dma_buf_p2pdma_map_type() for an importer to ask by TLP class. Exporters keep the provider where it already lives, so this adds an operation rather than changing any existing signature or structure. Tested-by: Tushar Dave Signed-off-by: Leon Romanovsky --- drivers/dma-buf/dma-buf-mapping.c | 39 +++++++++++++++++++++++++++++++++++= ++++ include/linux/dma-buf-mapping.h | 3 +++ include/linux/dma-buf.h | 19 +++++++++++++++++++ 3 files changed, 61 insertions(+) diff --git a/drivers/dma-buf/dma-buf-mapping.c b/drivers/dma-buf/dma-buf-ma= pping.c index 794acff2546a..41702045f803 100644 --- a/drivers/dma-buf/dma-buf-mapping.c +++ b/drivers/dma-buf/dma-buf-mapping.c @@ -6,6 +6,45 @@ #include #include =20 +/** + * dma_buf_p2pdma_map_type - How peer-to-peer traffic to a buffer is routed + * @attach: attachment of the importer that will issue the traffic + * @tlp_flags: &enum pci_p2pdma_tlp_flags describing the TLPs it will issue + * + * Reports how the PCIe fabric routes @tlp_flags traffic between the buffer + * behind @attach and the importer attached to it, so that an importer can + * choose the TLP attributes that earn it a direct route before it programs + * its hardware. + * + * The caller must hold the reservation lock. The provider is owned by the + * exporter's driver binding, and exporters revoke under that lock before + * letting an unbind proceed, so dropping it any earlier would leave this + * racing a teardown that frees the provider. + * + * Return: the mapping type for @tlp_flags traffic, or PCI_P2PDMA_MAP_NONE + * when the exporter names no &struct p2pdma_provider and nothing is known + * about the route. + */ +enum pci_p2pdma_map_type +dma_buf_p2pdma_map_type(struct dma_buf_attachment *attach, + unsigned int tlp_flags) +{ + struct dma_buf *dmabuf =3D attach->dmabuf; + struct p2pdma_provider *provider; + + dma_resv_assert_held(dmabuf->resv); + + if (!dmabuf->ops->p2pdma_provider) + return PCI_P2PDMA_MAP_NONE; + + provider =3D dmabuf->ops->p2pdma_provider(dmabuf); + if (!provider) + return PCI_P2PDMA_MAP_NONE; + + return pci_p2pdma_map_type_tlp(provider, attach->dev, tlp_flags); +} +EXPORT_SYMBOL_NS_GPL(dma_buf_p2pdma_map_type, "DMA_BUF"); + static struct scatterlist *fill_sg_entry(struct scatterlist *sgl, size_t l= ength, dma_addr_t addr) { diff --git a/include/linux/dma-buf-mapping.h b/include/linux/dma-buf-mappin= g.h index 09bde3f748e4..37b3da10b17a 100644 --- a/include/linux/dma-buf-mapping.h +++ b/include/linux/dma-buf-mapping.h @@ -7,6 +7,9 @@ #define __DMA_BUF_MAPPING_H__ #include =20 +enum pci_p2pdma_map_type +dma_buf_p2pdma_map_type(struct dma_buf_attachment *attach, + unsigned int tlp_flags); struct sg_table *dma_buf_phys_vec_to_sgt(struct dma_buf_attachment *attach, struct p2pdma_provider *provider, struct phys_vec *phys_vec, diff --git a/include/linux/dma-buf.h b/include/linux/dma-buf.h index d1203da56fc5..d56a48d41215 100644 --- a/include/linux/dma-buf.h +++ b/include/linux/dma-buf.h @@ -186,6 +186,25 @@ struct dma_buf_ops { * if the call would block. */ =20 + /** + * @p2pdma_provider: + * + * Returns the &struct p2pdma_provider backing this buffer, so that an + * importer can ask how its peer-to-peer traffic would be routed before + * it programs its hardware. Importers reach this through + * dma_buf_p2pdma_map_type() rather than calling it directly. + * + * Exporters of MMIO memory that is reachable peer-to-peer should + * implement this. Called with the &dma_buf.resv reservation lock held, + * which is what lets an exporter refuse once it has revoked the buffer + * and started tearing the provider down. This callback is optional. + * + * Returns: + * + * The provider backing the buffer. + */ + struct p2pdma_provider *(*p2pdma_provider)(struct dma_buf *dmabuf); + /** * @release: * --=20 2.55.0 From nobody Thu Sep 24 21:19:39 2026 Received: from smtp.kernel.org (aws-us-west-2-korg-mail-alma10-1.taild15c8.ts.net [100.103.45.18]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by smtp.subspace.kernel.org (Postfix) with ESMTPS id C65D2429CE8; Sun, 20 Sep 2026 11:42:43 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=100.103.45.18 ARC-Seal: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1789904564; cv=none; b=kSSTXJVa5fOmP2SxEvbra/6V8ahgBHlw0CNnxSf6TyT4I3MkJyv3S72zUdqU649qF8+Zs22xClzcoq+/JUF/aesApC1cKYE9UIl1ueyRFpvJSNkBdxYe8O7GH9gCa6efsgpz6D5DTYkIDBTT6W+bdmYhvOIEq7HNst7Oe8f/dgo= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1789904564; c=relaxed/simple; bh=9nyRnvU6J7pEfh0z00W+k9FTcBVUtgjZMQHncga3XKw=; h=From:To:Cc:Subject:Date:Message-ID:In-Reply-To:References: MIME-Version:Content-Type; b=bf0Jrw4reMCEhfob/dQh9U0uV+rr4BJGxSCOpGkUS3Ps9VBKvsbcV973Nzc6js5haZQQn90xoPc8FpHiDIs/F+CjUbw7xv37GZupqA2wnGv1KRV/zEIZhvk5pluK+OweH9XAkr2ZOC2ZAUFuzlQYtfLJFmrpwTbwNdACxC/BJUw= ARC-Authentication-Results: i=1; smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=kernel.org header.i=@kernel.org header.b=dmECX4xV; arc=none smtp.client-ip=100.103.45.18 Authentication-Results: smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=kernel.org header.i=@kernel.org header.b="dmECX4xV" Received: by smtp.kernel.org (Postfix) with ESMTPSA id A76BF1F00893; Sun, 20 Sep 2026 11:42:42 +0000 (UTC) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=kernel.org; s=k20260515; t=1789904563; bh=t1H31gQ69jwsTpe9r7dwRHyKnqahuj4ZFf+u0ryjpAc=; h=From:To:Cc:Subject:Date:In-Reply-To:References; b=dmECX4xVTgfhT7yMC/bO+XsW9AG8LPp/Zij4xq0iFO1Gb0jJCf/csNxVd/rOY1l5Z LJVQUqS9Naolc/dmgm/F5IMMMWB8S8IaOz0REEocxdvsAVD4LGWtgg+z6+lQMPrDD7 WJFMQKJWLDBnRAJ11bmJ7h/nU5RaO08KV9QawRAdLGJO3t723JFNotl+RHYZrcUeEx QZWUE2EjANGQorkQxUgi5bx8GzIRyJ5QlsnI/SZRcKjATpZ3psNxpHrAkN1AqETKC5 2++pVebYJuSklL0u6YuTlmvYfZ0/BEpoqMmmS1qVmpdI0FnJ5wxRAuKWB+ttIC94Ym PEduFrM2Ja1EQ== From: Leon Romanovsky To: Bjorn Helgaas , Logan Gunthorpe , Chaitanya Kulkarni , Greg Kroah-Hartman , Jens Axboe , Alex Williamson , Leon Romanovsky , Ankit Agrawal , Jason Gunthorpe , Jonathan Corbet , Shuah Khan , "Joerg Roedel (AMD)" , Will Deacon , Robin Murphy , Randy Dunlap , Sumit Semwal , =?utf-8?q?Christian_K=C3=B6nig?= Cc: linux-pci@vger.kernel.org, linux-kernel@vger.kernel.org, linux-doc@vger.kernel.org, iommu@lists.linux.dev, Tushar Dave , 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 Subject: [PATCH v7 17/19] vfio/pci: Hand out the P2PDMA provider behind a dma-buf Date: Sun, 20 Sep 2026 14:41:29 +0300 Message-ID: <20260920-fix-p2p-acs-v4-0-v7-17-ca0828ab697c@nvidia.com> X-Mailer: git-send-email 2.55.0 In-Reply-To: <20260920-fix-p2p-acs-v4-0-v7-0-ca0828ab697c@nvidia.com> References: <20260920-fix-p2p-acs-v4-0-v7-0-ca0828ab697c@nvidia.com> Precedence: bulk X-Mailing-List: linux-kernel@vger.kernel.org List-Id: List-Subscribe: List-Unsubscribe: MIME-Version: 1.0 Content-Type: text/plain; charset="utf-8" X-Mailer: b4 0.15-dev-18f8f Content-Transfer-Encoding: quoted-printable From: Leon Romanovsky An importer attached to a VFIO dma-buf cannot tell whether its peer-to-peer traffic would reach the exported BAR directly, because the &struct p2pdma_provider describing it stays in vfio_pci_dma_buf. Implement @p2pdma_provider so dma_buf_p2pdma_map_type() can reach it. Refuse once the buffer is revoked: vfio_pci_dma_buf_cleanup() revokes before it drops the device registration that keeps the provider allocated, so a revoked buffer has nothing left to describe. Tested-by: Tushar Dave Signed-off-by: Leon Romanovsky --- drivers/vfio/pci/vfio_pci_dmabuf.c | 12 ++++++++++++ 1 file changed, 12 insertions(+) diff --git a/drivers/vfio/pci/vfio_pci_dmabuf.c b/drivers/vfio/pci/vfio_pci= _dmabuf.c index c16f460c01d6..fcf392cfc3c5 100644 --- a/drivers/vfio/pci/vfio_pci_dmabuf.c +++ b/drivers/vfio/pci/vfio_pci_dmabuf.c @@ -99,11 +99,23 @@ static void vfio_pci_dma_buf_release(struct dma_buf *dm= abuf) kfree(priv); } =20 +static struct p2pdma_provider * +vfio_pci_dma_buf_provider(struct dma_buf *dmabuf) +{ + struct vfio_pci_dma_buf *priv =3D dmabuf->priv; + + if (priv->revoked) + return NULL; + + return priv->provider; +} + static const struct dma_buf_ops vfio_pci_dmabuf_ops =3D { .attach =3D vfio_pci_dma_buf_attach, .map_dma_buf =3D vfio_pci_dma_buf_map, .unmap_dma_buf =3D vfio_pci_dma_buf_unmap, .release =3D vfio_pci_dma_buf_release, + .p2pdma_provider =3D vfio_pci_dma_buf_provider, }; =20 /* --=20 2.55.0 From nobody Thu Sep 24 21:19:39 2026 Received: from smtp.kernel.org (aws-us-west-2-korg-mail-alma10-1.taild15c8.ts.net [100.103.45.18]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by smtp.subspace.kernel.org (Postfix) with ESMTPS id BF61C42E401; Sun, 20 Sep 2026 11:42:55 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=100.103.45.18 ARC-Seal: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1789904577; cv=none; b=D25FMImkP2QeSMAMFIC2/RlO3LSXIKUrdydFQ/ULGc7hmy9gElzZ3TE5Pr56k8kVvcHipWBc2Hti70rhdHDbUbm+Z7xLjMowbhMKXAzYBU7VyLYr9qsnJ1cNVsGZ2fy4WUqaeMt1CmPn/UB0x7oZCWSzrtLa1MMDaf3Isbz1/Ac= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1789904577; c=relaxed/simple; bh=riGlHG++DL8f0DnvaJ2KRuj/96+VOlrVeHQ7nm4g8CI=; h=From:To:Cc:Subject:Date:Message-ID:In-Reply-To:References: MIME-Version:Content-Type; b=Lin2sbAfTYSzb8Y6/dtiEHE0RXTnvKNs7TtI2t4RpcWXaGADw9vQC/g2fCZF4K+OdwDlGjrMG21aAgyZPOSYN9g6g0qkEwJlsJlI7YyAgZv7yIdlmO3E++5MZ12CfmATEjYhNBj9Ac9tp4WQyiJ+nIslX9KZcxKmRNIrtJIyqEE= ARC-Authentication-Results: i=1; smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=kernel.org header.i=@kernel.org header.b=PoGh9Arc; arc=none smtp.client-ip=100.103.45.18 Authentication-Results: smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=kernel.org header.i=@kernel.org header.b="PoGh9Arc" Received: by smtp.kernel.org (Postfix) with ESMTPSA id 57CB01F00893; Sun, 20 Sep 2026 11:42:54 +0000 (UTC) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=kernel.org; s=k20260515; t=1789904575; bh=s9hM+k8hMa1R4u6jdfPzKiE4L3rfw69xZAFpd6/U+Zg=; h=From:To:Cc:Subject:Date:In-Reply-To:References; b=PoGh9ArcYHh6zXNr/LygdppEE41Db17kxr5t8DdpKSiAmGcvrNfiIokCmXawiSfgM Hku+cxQAisaRVymDGpXIo3meEk+bOR2g+Y8aLtNmYxus8IwnLKNDcdCfeOGfpUAhKb qg3DXxavmZka1Wpk5hk3AzrKJd30UoX4QkJZaYjeiG7YyoC73R736Zf+VPco5sxyqZ 7yyzoTpNQaSFpcz9B8xtmt4zInIak96Jr+dPLsMf3PpVjYkdKBLbKPlS/ZSi2KdJmB QwQiMhcXSYtwK3//ZBexba+fRUsUAsieD8tve6cl17Yql9bVvOorZZC4N0wazzUl1c b1Nj4vFiXfdmQ== From: Leon Romanovsky To: Bjorn Helgaas , Logan Gunthorpe , Chaitanya Kulkarni , Greg Kroah-Hartman , Jens Axboe , Alex Williamson , Leon Romanovsky , Ankit Agrawal , Jason Gunthorpe , Jonathan Corbet , Shuah Khan , "Joerg Roedel (AMD)" , Will Deacon , Robin Murphy , Randy Dunlap , Sumit Semwal , =?utf-8?q?Christian_K=C3=B6nig?= Cc: linux-pci@vger.kernel.org, linux-kernel@vger.kernel.org, linux-doc@vger.kernel.org, iommu@lists.linux.dev, Tushar Dave , 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 Subject: [PATCH v7 18/19] RDMA/uverbs: Hand out the P2PDMA provider behind a dma-buf Date: Sun, 20 Sep 2026 14:41:30 +0300 Message-ID: <20260920-fix-p2p-acs-v4-0-v7-18-ca0828ab697c@nvidia.com> X-Mailer: git-send-email 2.55.0 In-Reply-To: <20260920-fix-p2p-acs-v4-0-v7-0-ca0828ab697c@nvidia.com> References: <20260920-fix-p2p-acs-v4-0-v7-0-ca0828ab697c@nvidia.com> Precedence: bulk X-Mailing-List: linux-kernel@vger.kernel.org List-Id: List-Subscribe: List-Unsubscribe: MIME-Version: 1.0 Content-Type: text/plain; charset="utf-8" X-Mailer: b4 0.15-dev-18f8f Content-Transfer-Encoding: quoted-printable From: Leon Romanovsky An importer attached to a uverbs dma-buf cannot tell whether its peer-to-peer traffic would reach the exported memory directly, because the &struct p2pdma_provider describing it stays in ib_uverbs_dmabuf_file. Implement @p2pdma_provider so dma_buf_p2pdma_map_type() can reach it, and refuse once the buffer is revoked and the memory it described is gone. Tested-by: Tushar Dave Signed-off-by: Leon Romanovsky --- drivers/infiniband/core/uverbs_std_types_dmabuf.c | 12 ++++++++++++ 1 file changed, 12 insertions(+) diff --git a/drivers/infiniband/core/uverbs_std_types_dmabuf.c b/drivers/in= finiband/core/uverbs_std_types_dmabuf.c index 2411ebee69e2..5a6a1ee430a7 100644 --- a/drivers/infiniband/core/uverbs_std_types_dmabuf.c +++ b/drivers/infiniband/core/uverbs_std_types_dmabuf.c @@ -76,6 +76,17 @@ static void uverbs_dmabuf_release(struct dma_buf *dmabuf) uverbs_uobject_release(&priv->uobj); } =20 +static struct p2pdma_provider * +uverbs_dmabuf_provider(struct dma_buf *dmabuf) +{ + struct ib_uverbs_dmabuf_file *priv =3D dmabuf->priv; + + if (priv->revoked) + return NULL; + + return priv->provider; +} + static const struct dma_buf_ops uverbs_dmabuf_ops =3D { .attach =3D uverbs_dmabuf_attach, .map_dma_buf =3D uverbs_dmabuf_map, @@ -83,6 +94,7 @@ static const struct dma_buf_ops uverbs_dmabuf_ops =3D { .pin =3D uverbs_dmabuf_pin, .unpin =3D uverbs_dmabuf_unpin, .release =3D uverbs_dmabuf_release, + .p2pdma_provider =3D uverbs_dmabuf_provider, }; =20 static int UVERBS_HANDLER(UVERBS_METHOD_DMABUF_ALLOC)( --=20 2.55.0 From nobody Thu Sep 24 21:19:39 2026 Received: from smtp.kernel.org (aws-us-west-2-korg-mail-alma10-1.taild15c8.ts.net [100.103.45.18]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by smtp.subspace.kernel.org (Postfix) with ESMTPS id 0181543CEDF; Sun, 20 Sep 2026 11:42:51 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=100.103.45.18 ARC-Seal: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1789904573; cv=none; b=s/PruUyevTzXQhwXYqJ7iU8IVHmWg0RUHEbCdxo/qYzbinX5zRer0mUqW33oB812eGfcukm7Hr8B6G3AX6aW+bSv9K4zgtJWOuSMPWAvYHYzceKYnZVy05YzfVS0ClvSAHECzR5IVVMXL5omv9BE3W8xTwOj/r/IDwQ1TH77cTg= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1789904573; c=relaxed/simple; bh=hSst6qWliwQhuFmjuRAmeH6CDSXIKUX4iZOlyu/PnoY=; h=From:To:Cc:Subject:Date:Message-ID:In-Reply-To:References: MIME-Version:Content-Type; b=WV1zDhiGlb5AJ7ZzNQrpuyfoZS9lfBPtpkZzuHQjloFhNSIsEk1gHCHHGXHpdyii7T1EBQQ5Qi9JHOnkbdAc4f7jDhbZqys8KP78nInbGFYKze+bzzzWu+VeLGlr0jyXyiuDXHfHMINM5kQ+ZpKe4QZvvYfwIjhtuTaRvDIpMoE= ARC-Authentication-Results: i=1; smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=kernel.org header.i=@kernel.org header.b=UzHVFcSF; arc=none smtp.client-ip=100.103.45.18 Authentication-Results: smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=kernel.org header.i=@kernel.org header.b="UzHVFcSF" Received: by smtp.kernel.org (Postfix) with ESMTPSA id 733151F000FF; Sun, 20 Sep 2026 11:42:50 +0000 (UTC) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=kernel.org; s=k20260515; t=1789904571; bh=TgQxhDeMgGS4hAKE9KuPylRAS2weZCdiODgFDrMrTuE=; h=From:To:Cc:Subject:Date:In-Reply-To:References; b=UzHVFcSFSo5/yOvzED44g3FnEcTaTQ5Pqk9Ki7e+pxcn+Ir9ATS2EN0ofYwPaTzLT 2wQCUk6jfgluHKCdVz8hWeLGAJNELzHxs7cFqiJ0q3woPfm91NT+5HNoD3MFDqG/b9 unU2xFFrJ8fXUSc4SDxjj0LkSnCm1usqRraJfe9LVeQsQkp6q3QLB6qrx9MC6t86Dp ObEdXYHmEq8Z7nWe/hlQ3QNkVzgHFoZ6cNq8ONm/4ptuHDXNjlnNiqZfzRUHCLgNoI fQZgsJwj4DYXcWMimjkhTSCEMjsB6MQkZZ9/LwDMrEecMQj1KhryG9QZ3NDW5qrQOL MwA416Cx77iPA== From: Leon Romanovsky To: Bjorn Helgaas , Logan Gunthorpe , Chaitanya Kulkarni , Greg Kroah-Hartman , Jens Axboe , Alex Williamson , Leon Romanovsky , Ankit Agrawal , Jason Gunthorpe , Jonathan Corbet , Shuah Khan , "Joerg Roedel (AMD)" , Will Deacon , Robin Murphy , Randy Dunlap , Sumit Semwal , =?utf-8?q?Christian_K=C3=B6nig?= Cc: linux-pci@vger.kernel.org, linux-kernel@vger.kernel.org, linux-doc@vger.kernel.org, iommu@lists.linux.dev, Tushar Dave , 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 Subject: [PATCH v7 19/19] RDMA/mlx5: Ask P2PDMA whether ATS takes a direct peer-to-peer route Date: Sun, 20 Sep 2026 14:41:31 +0300 Message-ID: <20260920-fix-p2p-acs-v4-0-v7-19-ca0828ab697c@nvidia.com> X-Mailer: git-send-email 2.55.0 In-Reply-To: <20260920-fix-p2p-acs-v4-0-v7-0-ca0828ab697c@nvidia.com> References: <20260920-fix-p2p-acs-v4-0-v7-0-ca0828ab697c@nvidia.com> Precedence: bulk X-Mailing-List: linux-kernel@vger.kernel.org List-Id: List-Subscribe: List-Unsubscribe: MIME-Version: 1.0 Content-Type: text/plain; charset="utf-8" X-Mailer: b4 0.15-dev-18f8f Content-Transfer-Encoding: quoted-printable From: Leon Romanovsky mlx5_umem_needs_ats() enables ATS for any dma-buf whose caller asked for Relaxed Ordering, on the assumption that a switch in the path has CR, RR and DT all set. It also enables it for a buffer already mapped with the peer's bus addresses, which are not translatable at all. P2PDMA has read the ACS controls, so ask it through dma_buf_p2pdma_map_type(): enable ATS only where the path is not routed directly as it stands, but would be for a Translated Request whose Completions carry Relaxed Ordering. Exporters that name no provider keep the old assumption, since their ACS settings remain hidden. Tested-by: Tushar Dave Signed-off-by: Leon Romanovsky --- drivers/infiniband/hw/mlx5/mlx5_ib.h | 36 ++------------------------- drivers/infiniband/hw/mlx5/mr.c | 47 ++++++++++++++++++++++++++++++++= ++++ 2 files changed, 49 insertions(+), 34 deletions(-) diff --git a/drivers/infiniband/hw/mlx5/mlx5_ib.h b/drivers/infiniband/hw/m= lx5/mlx5_ib.h index e9ddf2e97a76..ab32742b2180 100644 --- a/drivers/infiniband/hw/mlx5/mlx5_ib.h +++ b/drivers/infiniband/hw/mlx5/mlx5_ib.h @@ -1646,40 +1646,8 @@ static inline bool rt_supported(int ts_cap) ts_cap =3D=3D MLX5_TIMESTAMP_FORMAT_CAP_FREE_RUNNING_AND_REAL_TIME; } =20 -/* - * PCI Peer to Peer is a trainwreck. If no switch is present then things - * sometimes work, depending on the pci_distance_p2p logic for excluding b= roken - * root complexes. However if a switch is present in the path, then things= get - * really ugly depending on how the switch is setup. This table assumes th= at the - * root complex is strict and is validating that all req/reps are matches - * perfectly - so any scenario where it sees only half the transaction is a - * failure. - * - * CR/RR/DT ATS RO P2P - * 00X X X OK - * 010 X X fails (request is routed to root but root never sees c= omp) - * 011 0 X fails (request is routed to root but root never sees c= omp) - * 011 1 X OK - * 10X X 1 OK - * 101 X 0 fails (completion is routed to root but root didn't se= e req) - * 110 X 0 SLOW - * 111 0 0 SLOW - * 111 1 0 fails (completion is routed to root but root didn't se= e req) - * 111 1 1 OK - * - * Unfortunately we cannot reliably know if a switch is present or what the - * CR/RR/DT ACS settings are, as in a VM that is all hidden. Assume that - * CR/RR/DT is 111 if the ATS cap is enabled and follow the last three row= s. - * - * For now assume if the umem is a dma_buf then it is P2P. - */ -static inline bool mlx5_umem_needs_ats(struct mlx5_ib_dev *dev, - struct ib_umem *umem, int access_flags) -{ - if (!MLX5_CAP_GEN(dev->mdev, ats) || !umem->is_dmabuf) - return false; - return access_flags & IB_ACCESS_RELAXED_ORDERING; -} +bool mlx5_umem_needs_ats(struct mlx5_ib_dev *dev, struct ib_umem *umem, + int access_flags); =20 int set_roce_addr(struct mlx5_ib_dev *dev, u32 port_num, unsigned int index, const union ib_gid *gid, diff --git a/drivers/infiniband/hw/mlx5/mr.c b/drivers/infiniband/hw/mlx5/m= r.c index 00e13028762a..ee8982125c8c 100644 --- a/drivers/infiniband/hw/mlx5/mr.c +++ b/drivers/infiniband/hw/mlx5/mr.c @@ -38,6 +38,7 @@ #include #include #include +#include #include #include #include @@ -47,6 +48,52 @@ #include "data_direct.h" #include "dmah.h" =20 +MODULE_IMPORT_NS("DMA_BUF"); + +bool mlx5_umem_needs_ats(struct mlx5_ib_dev *dev, struct ib_umem *umem, + int access_flags) +{ + struct dma_buf_attachment *attach; + bool ats; + + if (!MLX5_CAP_GEN(dev->mdev, ats) || !umem->is_dmabuf) + return false; + + /* + * The Completer decides whether its Completions carry Relaxed + * Ordering, and only a Request that asked for it can expect them to. + */ + if (!(access_flags & IB_ACCESS_RELAXED_ORDERING)) + return false; + + attach =3D to_ib_umem_dmabuf(umem)->attach; + + dma_resv_lock(attach->dmabuf->resv, NULL); + switch (dma_buf_p2pdma_map_type(attach, 0)) { + case PCI_P2PDMA_MAP_NONE: + /* Nothing is known about the route, so fall back to the bet. */ + ats =3D true; + break; + case PCI_P2PDMA_MAP_BUS_ADDR: + /* + * The path is routed directly already and is programmed with + * the peer's bus addresses. Those are not translatable, so + * ATS would be wrong as well as pointless. + */ + ats =3D false; + break; + default: + ats =3D dma_buf_p2pdma_map_type(attach, + PCI_P2PDMA_TLP_TRANSLATED | + PCI_P2PDMA_TLP_RELAXED_CPL) =3D=3D + PCI_P2PDMA_MAP_BUS_ADDR; + break; + } + dma_resv_unlock(attach->dmabuf->resv); + + return ats; +} + static int mkey_max_umr_order(struct mlx5_ib_dev *dev) { if (MLX5_CAP_GEN(dev->mdev, umr_extended_translation_offset)) --=20 2.55.0