lists.openwall.net   lists  /  announce  owl-users  owl-dev  john-users  john-dev  passwdqc-users  yescrypt  popa3d-users  /  oss-security  kernel-hardening  musl  sabotage  tlsify  passwords  /  crypt-dev  xvendor  /  Bugtraq  Full-Disclosure  linux-kernel  linux-netdev  linux-ext4  linux-hardening  linux-cve-announce  PHC 
Open Source and information security mailing list archives
 
Hash Suite: Windows password security audit tool. GUI, reports in PDF.
[<prev] [next>] [<thread-prev] [day] [month] [year] [list]
Message-ID: <20251217055632.1776206-3-adrianhoyin.ng@altera.com>
Date: Wed, 17 Dec 2025 13:56:32 +0800
From: adrianhoyin.ng@...era.com
To: dinguyen@...nel.org,
	mdf@...nel.org,
	yilun.xu@...el.com,
	trix@...hat.com,
	linux-fpga@...r.kernel.org,
	linux-kernel@...r.kernel.org
Cc: adrianhoyin.ng@...era.com
Subject: [PATCH 2/2] fpga: stratix10-soc: Add persistent SMMU-aware DMA handling for Agilex5

From: Adrian Ng Ho Yin <adrianhoyin.ng@...era.com>

Agilex5 platforms require SMMU translation for FPGA configuration
buffers, but the Stratix10 FPGA manager previously assumed direct
physical addressing, causing reconfiguration failures when SMMU was
enabled.

This patch adds SMMU-aware DMA mapping and unmapping of service-layer
buffers and introduces a dma_addr field to track mapped addresses.
Buffers are also allocated once at probe() instead of per transfer,
reducing IOMMU overhead and avoiding timeout issues on Agilex5.

These updates enable reliable configuration on Agilex5 while preserving
behaviour on Stratix10 and Agilex7.

Signed-off-by: Adrian Ng Ho Yin <adrianhoyin.ng@...era.com>
---
 drivers/fpga/stratix10-soc.c | 67 +++++++++++++++++++++++++-----------
 1 file changed, 46 insertions(+), 21 deletions(-)

diff --git a/drivers/fpga/stratix10-soc.c b/drivers/fpga/stratix10-soc.c
index 0a295ccf1644..e5128ede8fa6 100644
--- a/drivers/fpga/stratix10-soc.c
+++ b/drivers/fpga/stratix10-soc.c
@@ -5,6 +5,7 @@
  *  Copyright (C) 2018 Intel Corporation
  */
 #include <linux/completion.h>
+#include <linux/dma-mapping.h>
 #include <linux/fpga/fpga-mgr.h>
 #include <linux/firmware/intel/stratix10-svc-client.h>
 #include <linux/module.h>
@@ -32,6 +33,7 @@
  */
 struct s10_svc_buf {
 	char *buf;
+	dma_addr_t dma_addr;
 	unsigned long lock;
 };
 
@@ -41,6 +43,7 @@ struct s10_priv {
 	struct completion status_return_completion;
 	struct s10_svc_buf svc_bufs[NUM_SVC_BUFS];
 	unsigned long status;
+	bool is_smmu_enabled;
 };
 
 static int s10_svc_send_msg(struct s10_priv *priv,
@@ -94,16 +97,16 @@ static bool s10_free_buffers(struct fpga_manager *mgr)
 }
 
 /*
- * Returns count of how many buffers are not in use.
+ * Returns count of how many buffers are not in locked state.
  */
-static uint s10_free_buffer_count(struct fpga_manager *mgr)
+static uint s10_get_unlocked_buffer_count(struct fpga_manager *mgr)
 {
 	struct s10_priv *priv = mgr->priv;
 	uint num_free = 0;
 	uint i;
 
 	for (i = 0; i < NUM_SVC_BUFS; i++)
-		if (!priv->svc_bufs[i].buf)
+		if (!priv->svc_bufs[i].lock)
 			num_free++;
 
 	return num_free;
@@ -126,6 +129,10 @@ static void s10_unlock_bufs(struct s10_priv *priv, void *kaddr)
 
 	for (i = 0; i < NUM_SVC_BUFS; i++)
 		if (priv->svc_bufs[i].buf == kaddr) {
+			if (priv->is_smmu_enabled)
+				dma_unmap_single(priv->client.dev,
+						 priv->svc_bufs[i].dma_addr,
+						 SVC_BUF_SIZE, DMA_TO_DEVICE);
 			clear_bit_unlock(SVC_BUF_LOCK,
 					 &priv->svc_bufs[i].lock);
 			return;
@@ -179,7 +186,6 @@ static int s10_ops_write_init(struct fpga_manager *mgr,
 	struct s10_priv *priv = mgr->priv;
 	struct device *dev = priv->client.dev;
 	struct stratix10_svc_command_config_type ctype;
-	char *kbuf;
 	uint i;
 	int ret;
 
@@ -211,18 +217,9 @@ static int s10_ops_write_init(struct fpga_manager *mgr,
 		goto init_done;
 	}
 
-	/* Allocate buffers from the service layer's pool. */
-	for (i = 0; i < NUM_SVC_BUFS; i++) {
-		kbuf = stratix10_svc_allocate_memory(priv->chan, SVC_BUF_SIZE);
-		if (IS_ERR(kbuf)) {
-			s10_free_buffers(mgr);
-			ret = PTR_ERR(kbuf);
-			goto init_done;
-		}
-
-		priv->svc_bufs[i].buf = kbuf;
+	/* Init buffer lock */
+	for (i = 0; i < NUM_SVC_BUFS; i++)
 		priv->svc_bufs[i].lock = 0;
-	}
 
 init_done:
 	stratix10_svc_done(priv->chan);
@@ -259,6 +256,10 @@ static int s10_send_buf(struct fpga_manager *mgr, const char *buf, size_t count)
 
 	svc_buf = priv->svc_bufs[i].buf;
 	memcpy(svc_buf, buf, xfer_sz);
+	if (priv->is_smmu_enabled)
+		priv->svc_bufs[i].dma_addr = dma_map_single(dev, svc_buf,
+							    SVC_BUF_SIZE,
+							    DMA_TO_DEVICE);
 	ret = s10_svc_send_msg(priv, COMMAND_RECONFIG_DATA_SUBMIT,
 			       svc_buf, xfer_sz);
 	if (ret < 0) {
@@ -288,7 +289,7 @@ static int s10_ops_write(struct fpga_manager *mgr, const char *buf,
 	 * Loop waiting for buffers to be returned.  When a buffer is returned,
 	 * reuse it to send more data or free if if all data has been sent.
 	 */
-	while (count > 0 || s10_free_buffer_count(mgr) != NUM_SVC_BUFS) {
+	while (true) {
 		reinit_completion(&priv->status_return_completion);
 
 		if (count > 0) {
@@ -299,7 +300,7 @@ static int s10_ops_write(struct fpga_manager *mgr, const char *buf,
 			count -= sent;
 			buf += sent;
 		} else {
-			if (s10_free_buffers(mgr))
+			if (s10_get_unlocked_buffer_count(mgr) == NUM_SVC_BUFS)
 				return 0;
 
 			ret = s10_svc_send_msg(
@@ -339,9 +340,6 @@ static int s10_ops_write(struct fpga_manager *mgr, const char *buf,
 		}
 	}
 
-	if (!s10_free_buffers(mgr))
-		dev_err(dev, "%s not all buffers were freed\n", __func__);
-
 	return ret;
 }
 
@@ -400,7 +398,9 @@ static int s10_probe(struct platform_device *pdev)
 	struct device *dev = &pdev->dev;
 	struct s10_priv *priv;
 	struct fpga_manager *mgr;
-	int ret;
+	int ret, i;
+	struct device_node *node = pdev->dev.of_node;
+	char *kbuf;
 
 	priv = devm_kzalloc(dev, sizeof(*priv), GFP_KERNEL);
 	if (!priv)
@@ -409,6 +409,10 @@ static int s10_probe(struct platform_device *pdev)
 	priv->client.dev = dev;
 	priv->client.receive_cb = s10_receive_callback;
 	priv->client.priv = priv;
+	priv->is_smmu_enabled = false;
+
+	if (of_device_is_compatible(node, "intel,agilex5-soc-fpga-mgr"))
+		priv->is_smmu_enabled = true;
 
 	priv->chan = stratix10_svc_request_channel_byname(&priv->client,
 							  SVC_CLIENT_FPGA);
@@ -428,6 +432,19 @@ static int s10_probe(struct platform_device *pdev)
 		goto probe_err;
 	}
 
+	/* Allocate buffers from the service layer's pool. */
+	for (i = 0; i < NUM_SVC_BUFS; i++) {
+		kbuf = stratix10_svc_allocate_memory(priv->chan, SVC_BUF_SIZE);
+		if (IS_ERR(kbuf)) {
+			s10_free_buffers(mgr);
+			ret = PTR_ERR(kbuf);
+			goto probe_err;
+		}
+
+		priv->svc_bufs[i].buf = kbuf;
+		priv->svc_bufs[i].lock = 0;
+	}
+
 	platform_set_drvdata(pdev, mgr);
 	return 0;
 
@@ -440,6 +457,13 @@ static void s10_remove(struct platform_device *pdev)
 {
 	struct fpga_manager *mgr = platform_get_drvdata(pdev);
 	struct s10_priv *priv = mgr->priv;
+	int i;
+
+	for (i = 0; i < NUM_SVC_BUFS; i++) {
+		if (priv->svc_bufs[i].buf)
+			stratix10_svc_free_memory(priv->chan,
+						  priv->svc_bufs[i].buf);
+	}
 
 	fpga_mgr_unregister(mgr);
 	stratix10_svc_free_channel(priv->chan);
@@ -448,6 +472,7 @@ static void s10_remove(struct platform_device *pdev)
 static const struct of_device_id s10_of_match[] = {
 	{.compatible = "intel,stratix10-soc-fpga-mgr"},
 	{.compatible = "intel,agilex-soc-fpga-mgr"},
+	{.compatible = "intel,agilex5-soc-fpga-mgr"},
 	{},
 };
 
-- 
2.49.GIT


Powered by blists - more mailing lists

Powered by Openwall GNU/*/Linux Powered by OpenVZ