All of lore.kernel.org
 help / color / mirror / Atom feed
From: Aravind Thokala <aravind.thokala@amd.com>
To: <mdf@kernel.org>, <yilun.xu@intel.com>, <trix@redhat.com>,
	<sumit.semwal@linaro.org>, <christian.koenig@amd.com>
Cc: <corbet@lwn.net>, <skhan@linuxfoundation.org>,
	<linux-kernel@vger.kernel.org>, <linux-fpga@vger.kernel.org>,
	<linux-media@vger.kernel.org>, <dri-devel@lists.freedesktop.org>,
	<linaro-mm-sig@lists.linaro.org>, <linux-doc@vger.kernel.org>,
	<git@amd.com>, <aravind.thokala@amd.com>,
	<nava.kishore.manne@amd.com>
Subject: [PATCH 1/2] fpga: Add dma-buf interface for FPGA programming
Date: Sun, 16 Aug 2026 20:37:33 +0530	[thread overview]
Message-ID: <20260816150734.2092802-2-aravind.thokala@amd.com> (raw)
In-Reply-To: <20260816150734.2092802-1-aravind.thokala@amd.com>

Loading FPGA images through the firmware interface requires the image
to be loaded into kernel memory first and then copied into DMA memory.
This extra copy creates needless memory pressure and delays.

Add a module that allows userspace to pass a pre-allocated DMA buffer
directly to the FPGA manager via ioctl, eliminating the extra copy.
A miscdevice (/dev/fpgaX) is created for each FPGA manager that
registers dma-buf support. The module imports the dma-buf fd, maps it
for DMA, and calls the FPGA manager load API with the scatter-gather
table.

Co-developed-by: Nava kishore Manne <nava.kishore.manne@amd.com>
Signed-off-by: Nava kishore Manne <nava.kishore.manne@amd.com>
Signed-off-by: Aravind Thokala <aravind.thokala@amd.com>
---
 .../userspace-api/ioctl/ioctl-number.rst      |   1 +
 MAINTAINERS                                   |   1 +
 drivers/fpga/Kconfig                          |   9 +
 drivers/fpga/Makefile                         |   2 +
 drivers/fpga/fpga-dmabuf.c                    | 198 ++++++++++++++++++
 include/linux/fpga/fpga-dmabuf.h              |  22 ++
 include/linux/fpga/fpga-mgr.h                 |   1 +
 include/uapi/linux/fpga.h                     |  15 ++
 8 files changed, 249 insertions(+)
 create mode 100644 drivers/fpga/fpga-dmabuf.c
 create mode 100644 include/linux/fpga/fpga-dmabuf.h
 create mode 100644 include/uapi/linux/fpga.h

diff --git a/Documentation/userspace-api/ioctl/ioctl-number.rst b/Documentation/userspace-api/ioctl/ioctl-number.rst
index 3f0ef1e27eb0..f8537dd23463 100644
--- a/Documentation/userspace-api/ioctl/ioctl-number.rst
+++ b/Documentation/userspace-api/ioctl/ioctl-number.rst
@@ -170,6 +170,7 @@ Code  Seq#    Include File                                             Comments
 'I'   all    linux/isdn.h                                              conflict!
 'I'   00-0F  drivers/isdn/divert/isdn_divert.h                         conflict!
 'I'   40-4F  linux/mISDNif.h                                           conflict!
+'J'   01     uapi/linux/fpga.h                                         FPGA DMA buffer interface
 'K'   all    linux/kd.h
 'L'   00-1F  linux/loop.h                                              conflict!
 'L'   10-1F  drivers/scsi/mpt3sas/mpt3sas_ctl.h                        conflict!
diff --git a/MAINTAINERS b/MAINTAINERS
index 5114e6db7307..7551dfa35d1c 100644
--- a/MAINTAINERS
+++ b/MAINTAINERS
@@ -10217,6 +10217,7 @@ F:	Documentation/driver-api/fpga/
 F:	Documentation/fpga/
 F:	drivers/fpga/
 F:	include/linux/fpga/
+F:	include/uapi/linux/fpga.h
 
 FRAMEBUFFER CONSOLE
 M:	Helge Deller <deller@gmx.de>
diff --git a/drivers/fpga/Kconfig b/drivers/fpga/Kconfig
index 748fc210c135..e3ad791c9808 100644
--- a/drivers/fpga/Kconfig
+++ b/drivers/fpga/Kconfig
@@ -157,6 +157,15 @@ config OF_FPGA_REGION
 	  Support for loading FPGA images by applying a Device Tree
 	  overlay.
 
+config FPGA_DMA_BUF
+	tristate "FPGA DMA Buffer Support"
+	depends on DMA_SHARED_BUFFER
+	help
+	  Support for programming FPGAs from a pre-allocated DMA buffer
+	  shared via dma-buf. A miscdevice (/dev/fpgaX) accepts a dma-buf
+	  file descriptor via ioctl to load the FPGA image without
+	  redundant memory copies.
+
 config FPGA_DFL
 	tristate "FPGA Device Feature List (DFL) support"
 	select FPGA_BRIDGE
diff --git a/drivers/fpga/Makefile b/drivers/fpga/Makefile
index 6f5798b27e0d..e52154296d2d 100644
--- a/drivers/fpga/Makefile
+++ b/drivers/fpga/Makefile
@@ -40,6 +40,8 @@ obj-$(CONFIG_XILINX_PR_DECOUPLER)	+= xilinx-pr-decoupler.o
 # High Level Interfaces
 obj-$(CONFIG_FPGA_REGION)		+= fpga-region.o
 obj-$(CONFIG_OF_FPGA_REGION)		+= of-fpga-region.o
+# FPGA DMA Buffer Interface
+obj-$(CONFIG_FPGA_DMA_BUF)		+= fpga-dmabuf.o
 
 # FPGA Device Feature List Support
 obj-$(CONFIG_FPGA_DFL)			+= dfl.o
diff --git a/drivers/fpga/fpga-dmabuf.c b/drivers/fpga/fpga-dmabuf.c
new file mode 100644
index 000000000000..0e92eb134698
--- /dev/null
+++ b/drivers/fpga/fpga-dmabuf.c
@@ -0,0 +1,198 @@
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * FPGA Manager DMA Buffer Support
+ *
+ * Copyright (C) 2026 Advanced Micro Devices, Inc.
+ */
+#include <linux/capability.h>
+#include <linux/dma-buf.h>
+#include <linux/fpga/fpga-dmabuf.h>
+#include <linux/fpga/fpga-mgr.h>
+#include <linux/kref.h>
+#include <linux/miscdevice.h>
+#include <linux/module.h>
+#include <linux/mutex.h>
+#include <linux/slab.h>
+#include <uapi/linux/fpga.h>
+
+struct fpga_dmabuf_priv {
+	struct kref ref;
+	struct mutex lock; /* serializes ioctl against teardown */
+	bool dead;
+	struct fpga_manager *mgr;
+	struct miscdevice miscdev;
+};
+
+static void fpga_dmabuf_free(struct kref *ref)
+{
+	struct fpga_dmabuf_priv *priv = container_of(ref,
+					struct fpga_dmabuf_priv, ref);
+
+	put_device(&priv->mgr->dev);
+	kfree(priv->miscdev.name);
+	kfree(priv);
+}
+
+static int fpga_dmabuf_load(struct fpga_manager *mgr, int buffd)
+{
+	struct fpga_image_info *info;
+	struct dma_buf_attachment *attach;
+	struct dma_buf *dmabuf;
+	struct sg_table *sgt;
+	int ret;
+
+	dmabuf = dma_buf_get(buffd);
+	if (IS_ERR(dmabuf))
+		return PTR_ERR(dmabuf);
+
+	info = fpga_image_info_alloc(mgr->dev.parent);
+	if (!info) {
+		ret = -ENOMEM;
+		goto err_put;
+	}
+
+	attach = dma_buf_attach(dmabuf, mgr->dev.parent);
+	if (IS_ERR(attach)) {
+		ret = PTR_ERR(attach);
+		goto err_free_info;
+	}
+
+	sgt = dma_buf_map_attachment_unlocked(attach, DMA_TO_DEVICE);
+	if (IS_ERR(sgt)) {
+		ret = PTR_ERR(sgt);
+		goto err_detach;
+	}
+
+	info->sgt = sgt;
+
+	ret = fpga_mgr_lock(mgr);
+	if (ret)
+		goto err_unmap;
+
+	ret = fpga_mgr_load(mgr, info);
+	fpga_mgr_unlock(mgr);
+
+err_unmap:
+	dma_buf_unmap_attachment_unlocked(attach, sgt, DMA_TO_DEVICE);
+err_detach:
+	dma_buf_detach(dmabuf, attach);
+err_free_info:
+	fpga_image_info_free(info);
+err_put:
+	dma_buf_put(dmabuf);
+
+	return ret;
+}
+
+static int fpga_dmabuf_open(struct inode *inode, struct file *file)
+{
+	struct miscdevice *miscdev = file->private_data;
+	struct fpga_dmabuf_priv *priv;
+
+	priv = container_of(miscdev, struct fpga_dmabuf_priv, miscdev);
+	kref_get(&priv->ref);
+	file->private_data = priv;
+
+	return 0;
+}
+
+static int fpga_dmabuf_release(struct inode *inode, struct file *file)
+{
+	struct fpga_dmabuf_priv *priv = file->private_data;
+
+	kref_put(&priv->ref, fpga_dmabuf_free);
+	return 0;
+}
+
+static long fpga_dmabuf_ioctl(struct file *file, unsigned int cmd,
+			      unsigned long arg)
+{
+	struct fpga_dmabuf_priv *priv = file->private_data;
+	int buffd;
+	int ret;
+
+	switch (cmd) {
+	case FPGA_IOCTL_LOAD_DMA_BUF:
+		if (!capable(CAP_SYS_RAWIO))
+			return -EPERM;
+		if (copy_from_user(&buffd, (void __user *)arg, sizeof(buffd)))
+			return -EFAULT;
+
+		mutex_lock(&priv->lock);
+		if (priv->dead) {
+			mutex_unlock(&priv->lock);
+			return -ENODEV;
+		}
+		ret = fpga_dmabuf_load(priv->mgr, buffd);
+		mutex_unlock(&priv->lock);
+		return ret;
+	default:
+		return -ENOTTY;
+	}
+}
+
+static const struct file_operations fpga_dmabuf_fops = {
+	.owner		= THIS_MODULE,
+	.open		= fpga_dmabuf_open,
+	.release	= fpga_dmabuf_release,
+	.unlocked_ioctl	= fpga_dmabuf_ioctl,
+	.compat_ioctl	= compat_ptr_ioctl,
+};
+
+int fpga_dmabuf_register(struct fpga_manager *mgr)
+{
+	struct fpga_dmabuf_priv *priv;
+	int ret;
+
+	priv = kzalloc_obj(*priv);
+	if (!priv)
+		return -ENOMEM;
+
+	kref_init(&priv->ref);
+	mutex_init(&priv->lock);
+	get_device(&mgr->dev);
+	priv->mgr = mgr;
+	priv->miscdev.minor = MISC_DYNAMIC_MINOR;
+	priv->miscdev.name = kstrdup(dev_name(&mgr->dev), GFP_KERNEL);
+	if (!priv->miscdev.name) {
+		put_device(&mgr->dev);
+		kfree(priv);
+		return -ENOMEM;
+	}
+	priv->miscdev.fops = &fpga_dmabuf_fops;
+	priv->miscdev.parent = &mgr->dev;
+
+	ret = misc_register(&priv->miscdev);
+	if (ret) {
+		kfree(priv->miscdev.name);
+		put_device(&mgr->dev);
+		kfree(priv);
+		return ret;
+	}
+
+	mgr->dmabuf_priv = priv;
+
+	return 0;
+}
+EXPORT_SYMBOL_GPL(fpga_dmabuf_register);
+
+void fpga_dmabuf_unregister(struct fpga_manager *mgr)
+{
+	struct fpga_dmabuf_priv *priv = mgr->dmabuf_priv;
+
+	if (!priv)
+		return;
+
+	mutex_lock(&priv->lock);
+	priv->dead = true;
+	mutex_unlock(&priv->lock);
+
+	misc_deregister(&priv->miscdev);
+	mgr->dmabuf_priv = NULL;
+	kref_put(&priv->ref, fpga_dmabuf_free);
+}
+EXPORT_SYMBOL_GPL(fpga_dmabuf_unregister);
+
+MODULE_IMPORT_NS("DMA_BUF");
+MODULE_DESCRIPTION("FPGA DMA Buffer Interface");
+MODULE_LICENSE("GPL");
diff --git a/include/linux/fpga/fpga-dmabuf.h b/include/linux/fpga/fpga-dmabuf.h
new file mode 100644
index 000000000000..bf54bdfdf968
--- /dev/null
+++ b/include/linux/fpga/fpga-dmabuf.h
@@ -0,0 +1,22 @@
+/* SPDX-License-Identifier: GPL-2.0 */
+/*
+ * Copyright (C) 2026 Advanced Micro Devices, Inc.
+ */
+#ifndef _LINUX_FPGA_DMABUF_H
+#define _LINUX_FPGA_DMABUF_H
+
+struct fpga_manager;
+
+#if IS_REACHABLE(CONFIG_FPGA_DMA_BUF)
+int fpga_dmabuf_register(struct fpga_manager *mgr);
+void fpga_dmabuf_unregister(struct fpga_manager *mgr);
+#else
+static inline int fpga_dmabuf_register(struct fpga_manager *mgr)
+{
+	return 0;
+}
+
+static inline void fpga_dmabuf_unregister(struct fpga_manager *mgr) {}
+#endif
+
+#endif /* _LINUX_FPGA_DMABUF_H */
diff --git a/include/linux/fpga/fpga-mgr.h b/include/linux/fpga/fpga-mgr.h
index 0d4fe068f3d8..38af47f60503 100644
--- a/include/linux/fpga/fpga-mgr.h
+++ b/include/linux/fpga/fpga-mgr.h
@@ -213,6 +213,7 @@ struct fpga_manager {
 	const struct fpga_manager_ops *mops;
 	struct module *mops_owner;
 	void *priv;
+	void *dmabuf_priv;
 };
 
 #define to_fpga_manager(d) container_of(d, struct fpga_manager, dev)
diff --git a/include/uapi/linux/fpga.h b/include/uapi/linux/fpga.h
new file mode 100644
index 000000000000..868650c66526
--- /dev/null
+++ b/include/uapi/linux/fpga.h
@@ -0,0 +1,15 @@
+/* SPDX-License-Identifier: GPL-2.0 WITH Linux-syscall-note */
+/*
+ * FPGA userspace API
+ *
+ * Copyright (C) 2026 Advanced Micro Devices, Inc.
+ */
+#ifndef _UAPI_LINUX_FPGA_H
+#define _UAPI_LINUX_FPGA_H
+
+#include <linux/ioctl.h>
+#include <linux/types.h>
+
+#define FPGA_IOCTL_LOAD_DMA_BUF	_IOW('J', 1, __s32)
+
+#endif /* _UAPI_LINUX_FPGA_H */
-- 
2.34.1


  reply	other threads:[~2026-08-16 15:07 UTC|newest]

Thread overview: 7+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2026-08-16 15:07 [PATCH 0/2] fpga: add dma-buf based FPGA programming interface Aravind Thokala
2026-08-16 15:07 ` Aravind Thokala [this message]
2026-08-16 15:19   ` [PATCH 1/2] fpga: Add dma-buf interface for FPGA programming sashiko-bot
2026-08-16 15:07 ` [PATCH 2/2] fpga: versal: add dma-buf programming support Aravind Thokala
2026-08-16 15:18   ` sashiko-bot
2026-08-20  6:57     ` Aravind Thokala
2026-08-24  8:50 ` [PATCH 0/2] fpga: add dma-buf based FPGA programming interface Christian König

Reply instructions:

You may reply publicly to this message via plain-text email
using any one of the following methods:

* Save the following mbox file, import it into your mail client,
  and reply-to-all from there: mbox

  Avoid top-posting and favor interleaved quoting:
  https://en.wikipedia.org/wiki/Posting_style#Interleaved_style

* Reply using the --to, --cc, and --in-reply-to
  switches of git-send-email(1):

  git send-email \
    --in-reply-to=20260816150734.2092802-2-aravind.thokala@amd.com \
    --to=aravind.thokala@amd.com \
    --cc=christian.koenig@amd.com \
    --cc=corbet@lwn.net \
    --cc=dri-devel@lists.freedesktop.org \
    --cc=git@amd.com \
    --cc=linaro-mm-sig@lists.linaro.org \
    --cc=linux-doc@vger.kernel.org \
    --cc=linux-fpga@vger.kernel.org \
    --cc=linux-kernel@vger.kernel.org \
    --cc=linux-media@vger.kernel.org \
    --cc=mdf@kernel.org \
    --cc=nava.kishore.manne@amd.com \
    --cc=skhan@linuxfoundation.org \
    --cc=sumit.semwal@linaro.org \
    --cc=trix@redhat.com \
    --cc=yilun.xu@intel.com \
    /path/to/YOUR_REPLY

  https://kernel.org/pub/software/scm/git/docs/git-send-email.html

* If your mail client supports setting the In-Reply-To header
  via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line before the message body.
This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.