[RFC 2/2] fpga: versal: Use the scatterlist interface

2023-11-21 Thread Nava kishore Manne
Allows drivers to request the Configuration image
be loaded from dma-able continuous buffer to avoid
needless memory pressure and delays due to multiple
copies.

Signed-off-by: Nava kishore Manne 
---
 drivers/fpga/versal-fpga.c | 13 +
 1 file changed, 13 insertions(+)

diff --git a/drivers/fpga/versal-fpga.c b/drivers/fpga/versal-fpga.c
index 3710e8f01be2..bf4fb4426417 100644
--- a/drivers/fpga/versal-fpga.c
+++ b/drivers/fpga/versal-fpga.c
@@ -19,6 +19,18 @@ static int versal_fpga_ops_write_init(struct fpga_manager 
*mgr,
return 0;
 }
 
+static int versal_fpga_ops_write_sg(struct fpga_manager *mgr,
+   struct sg_table *sgt)
+{
+   dma_addr_t dma_addr;
+   int ret;
+
+   dma_addr = sg_dma_address(sgt->sgl);
+   ret = zynqmp_pm_load_pdi(PDI_SRC_DDR, dma_addr);
+
+   return ret;
+}
+
 static int versal_fpga_ops_write(struct fpga_manager *mgr,
 const char *buf, size_t size)
 {
@@ -40,6 +52,7 @@ static int versal_fpga_ops_write(struct fpga_manager *mgr,
 static const struct fpga_manager_ops versal_fpga_ops = {
.write_init = versal_fpga_ops_write_init,
.write = versal_fpga_ops_write,
+   .write_sg = versal_fpga_ops_write_sg,
 };
 
 static int versal_fpga_probe(struct platform_device *pdev)
-- 
2.25.1



[RFC 1/2] fpga: support loading from a pre-allocated buffer

2023-11-21 Thread Nava kishore Manne
Some systems are memory constrained but they need to load very
large Configuration files. The FPGA subsystem allows drivers to
request this Configuration image be loaded from the filesystem,
but this requires that the entire configuration data be loaded
into kernel memory first before it's provided to the driver.
This can lead to a situation where we map the configuration
data twice, once to load the configuration data into kernel
memory and once to copy the configuration data into the final
resting place which is nothing but a dma-able continuous buffer.

This creates needless memory pressure and delays due to multiple
copies. Let's add a dmabuf handling support to the fpga manager
framework that allows drivers to load the Configuration data
directly from a pre-allocated buffer. This skips the intermediate
step of allocating a buffer in kernel memory to hold the
Configuration data.

Signed-off-by: Nava kishore Manne 
---
 drivers/fpga/fpga-mgr.c   | 113 ++
 include/linux/fpga/fpga-mgr.h |  10 +++
 2 files changed, 123 insertions(+)

diff --git a/drivers/fpga/fpga-mgr.c b/drivers/fpga/fpga-mgr.c
index 06651389c592..23d2b4d45827 100644
--- a/drivers/fpga/fpga-mgr.c
+++ b/drivers/fpga/fpga-mgr.c
@@ -8,6 +8,8 @@
  * With code from the mailing list:
  * Copyright (C) 2013 Xilinx, Inc.
  */
+#include 
+#include 
 #include 
 #include 
 #include 
@@ -519,6 +521,39 @@ static int fpga_mgr_buf_load(struct fpga_manager *mgr,
return rc;
 }
 
+static int fpga_dmabuf_load(struct fpga_manager *mgr,
+   struct fpga_image_info *info)
+{
+   struct dma_buf_attachment *attach;
+   struct sg_table *sgt;
+   int ret;
+
+   /* create attachment for dmabuf with the user device */
+   attach = dma_buf_attach(mgr->dmabuf, >dev);
+   if (IS_ERR(attach)) {
+   pr_err("failed to attach dmabuf\n");
+   ret = PTR_ERR(attach);
+   goto fail_put;
+   }
+
+   sgt = dma_buf_map_attachment(attach, DMA_BIDIRECTIONAL);
+   if (IS_ERR(sgt)) {
+   ret = PTR_ERR(sgt);
+   goto fail_detach;
+   }
+
+   info->sgt = sgt;
+   ret = fpga_mgr_buf_load_sg(mgr, info, info->sgt);
+   dma_buf_unmap_attachment(attach, sgt, DMA_BIDIRECTIONAL);
+
+fail_detach:
+   dma_buf_detach(mgr->dmabuf, attach);
+fail_put:
+   dma_buf_put(mgr->dmabuf);
+
+   return ret;
+}
+
 /**
  * fpga_mgr_firmware_load - request firmware and load to fpga
  * @mgr:   fpga manager
@@ -573,6 +608,8 @@ int fpga_mgr_load(struct fpga_manager *mgr, struct 
fpga_image_info *info)
 {
info->header_size = mgr->mops->initial_header_size;
 
+   if (mgr->flags & FPGA_MGR_CONFIG_DMA_BUF)
+   return fpga_dmabuf_load(mgr, info);
if (info->sgt)
return fpga_mgr_buf_load_sg(mgr, info, info->sgt);
if (info->buf && info->count)
@@ -732,6 +769,64 @@ void fpga_mgr_put(struct fpga_manager *mgr)
 }
 EXPORT_SYMBOL_GPL(fpga_mgr_put);
 
+static int fpga_dmabuf_fd_get(struct file *file, char __user *argp)
+{
+   struct fpga_manager *mgr =  (struct fpga_manager *)(file->private_data);
+   int buffd;
+
+   if (copy_from_user(, argp, sizeof(buffd)))
+   return -EFAULT;
+
+   mgr->dmabuf = dma_buf_get(buffd);
+   if (IS_ERR_OR_NULL(mgr->dmabuf))
+   return -EINVAL;
+
+   mgr->flags = FPGA_MGR_CONFIG_DMA_BUF;
+
+   return 0;
+}
+
+static int fpga_device_open(struct inode *inode, struct file *file)
+{
+   struct miscdevice *miscdev = file->private_data;
+   struct fpga_manager *mgr = container_of(miscdev,
+   struct fpga_manager, miscdev);
+
+   file->private_data = mgr;
+
+   return 0;
+}
+
+static int fpga_device_release(struct inode *inode, struct file *file)
+{
+   return 0;
+}
+
+static long fpga_device_ioctl(struct file *file, unsigned int cmd,
+ unsigned long arg)
+{
+   char __user *argp = (char __user *)arg;
+   int err;
+
+   switch (cmd) {
+   case FPGA_IOCTL_LOAD_DMA_BUFF:
+   err = fpga_dmabuf_fd_get(file, argp);
+   break;
+   default:
+   err = -ENOTTY;
+   }
+
+   return err;
+}
+
+static const struct file_operations fpga_fops = {
+   .owner  = THIS_MODULE,
+   .open   = fpga_device_open,
+   .release= fpga_device_release,
+   .unlocked_ioctl = fpga_device_ioctl,
+   .compat_ioctl   = fpga_device_ioctl,
+};
+
 /**
  * fpga_mgr_lock - Lock FPGA manager for exclusive use
  * @mgr:   fpga manager
@@ -815,10 +910,28 @@ fpga_mgr_register_full(struct device *parent, const 
struct fpga_manager_info *in
mgr->dev.of_node = parent->of_node;
mgr->dev.id = id;
 
+   /* Make device dma capable

[RFC 0/2]fpga: Add fpga configuration support from a pre-allocated dma-able buffer

2023-11-21 Thread Nava kishore Manne
Lots of embedded systems have memory constraints but they need to load
very large configuration files.The FPGA subsystem allows drivers to
request this configuration image be loaded from the filesystem,but this
requires that the entire configuration data be loaded into kernel memory
first before it's provided to the driver.This can lead to a situation where
we map the configuration data twice, once to load the configuration data
into kernel memory and once to copy the configuration data into the final
resting place which is nothing but a dma-able continuous buffer.

This creates needless memory pressure and delays due to multiple copies.
Let's add a dmabuf handling support to the fpga manager framework that
allows drivers to load the Configuration data directly from a pre-allocated
buffer. This skips the intermediate step of allocating a buffer in kernel
memory to hold the Configuration data.

This implementation allows the lower-level drivers to request the FPGA
Configuration image be loaded from pre-allocated dma-able continuous
buffer and also it avoid needless memory pressure and delays due to
multiple copies.

Please take a look at the changes and let us know if any improvements
are required.

Nava kishore Manne (2):
  fpga: support loading from a pre-allocated buffer
  fpga: versal: Use the scatterlist interface

 drivers/fpga/fpga-mgr.c   | 113 ++
 drivers/fpga/versal-fpga.c|  13 
 include/linux/fpga/fpga-mgr.h |  10 +++
 3 files changed, 136 insertions(+)

-- 
2.25.1



[PATCH RFC 1/3] fpga: region: Add fpga-region property 'fpga-config-from-dmabuf'

2021-04-02 Thread Nava kishore Manne
Add "fpga-config-from-dmabuf" property to allow the bitstream
configuration from pre-allocated dma-buffer.

Signed-off-by: Nava kishore Manne 
---
 Documentation/devicetree/bindings/fpga/fpga-region.txt | 2 ++
 1 file changed, 2 insertions(+)

diff --git a/Documentation/devicetree/bindings/fpga/fpga-region.txt 
b/Documentation/devicetree/bindings/fpga/fpga-region.txt
index 969ca53bb65e..c573cf258d60 100644
--- a/Documentation/devicetree/bindings/fpga/fpga-region.txt
+++ b/Documentation/devicetree/bindings/fpga/fpga-region.txt
@@ -177,6 +177,8 @@ Optional properties:
it indicates that the FPGA has already been programmed with this image.
If this property is in an overlay targeting a FPGA region, it is a
request to program the FPGA with that image.
+- fpga-config-from-dmabuf : boolean, set if the FPGA configured done from the
+   pre-allocated dma-buffer.
 - fpga-bridges : should contain a list of phandles to FPGA Bridges that must be
controlled during FPGA programming along with the parent FPGA bridge.
This property is optional if the FPGA Manager handles the bridges.
-- 
2.18.0

___
dri-devel mailing list
dri-devel@lists.freedesktop.org
https://lists.freedesktop.org/mailman/listinfo/dri-devel


[PATCH RFC 0/3] Adds support to allow the bitstream configuration from pre-allocated dma-buffer

2021-04-02 Thread Nava kishore Manne
Nava kishore Manne (3):
  fpga: region: Add fpga-region property 'fpga-config-from-dmabuf'
  fpga: support loading from a pre-allocated buffer
  fpga: zynqmp: Use the scatterlist interface

 .../devicetree/bindings/fpga/fpga-region.txt  |   2 +
 drivers/fpga/fpga-mgr.c   | 126 +-
 drivers/fpga/of-fpga-region.c |   3 +
 drivers/fpga/zynqmp-fpga.c|  35 +
 include/linux/fpga/fpga-mgr.h |   6 +-
 5 files changed, 169 insertions(+), 3 deletions(-)

-- 
2.18.0

___
dri-devel mailing list
dri-devel@lists.freedesktop.org
https://lists.freedesktop.org/mailman/listinfo/dri-devel


[PATCH RFC 3/3] fpga: zynqmp: Use the scatterlist interface

2021-04-02 Thread Nava kishore Manne
Allows drivers to request the Configuration image
be loaded from dma-able continuous buffer to avoid
needless memory pressure and delays due to multiple
copies.

Signed-off-by: Nava kishore Manne 
---
 drivers/fpga/zynqmp-fpga.c | 35 +++
 1 file changed, 35 insertions(+)

diff --git a/drivers/fpga/zynqmp-fpga.c b/drivers/fpga/zynqmp-fpga.c
index 125743c9797f..3bb6bd520d71 100644
--- a/drivers/fpga/zynqmp-fpga.c
+++ b/drivers/fpga/zynqmp-fpga.c
@@ -66,6 +66,40 @@ static int zynqmp_fpga_ops_write(struct fpga_manager *mgr,
return ret;
 }
 
+static unsigned long zynqmp_fpga_get_contiguous_size(struct sg_table *sgt)
+{
+   dma_addr_t expected = sg_dma_address(sgt->sgl);
+   unsigned long size = 0;
+   struct scatterlist *s;
+   unsigned int i;
+
+   for_each_sg(sgt->sgl, s, sgt->nents, i) {
+   if (sg_dma_address(s) != expected)
+   break;
+   expected = sg_dma_address(s) + sg_dma_len(s);
+   size += sg_dma_len(s);
+   }
+
+   return size;
+}
+
+static int zynqmp_fpga_ops_write_sg(struct fpga_manager *mgr,
+   struct sg_table *sgt)
+{
+   struct zynqmp_fpga_priv *priv;
+   unsigned long contig_size;
+   dma_addr_t dma_addr;
+   u32 eemi_flags = 0;
+
+   priv = mgr->priv;
+   dma_addr = sg_dma_address(sgt->sgl);
+   contig_size = zynqmp_fpga_get_contiguous_size(sgt);
+   if (priv->flags & FPGA_MGR_PARTIAL_RECONFIG)
+   eemi_flags |= XILINX_ZYNQMP_PM_FPGA_PARTIAL;
+
+   return zynqmp_pm_fpga_load(dma_addr, contig_size, eemi_flags);
+}
+
 static int zynqmp_fpga_ops_write_complete(struct fpga_manager *mgr,
  struct fpga_image_info *info)
 {
@@ -87,6 +121,7 @@ static const struct fpga_manager_ops zynqmp_fpga_ops = {
.state = zynqmp_fpga_ops_state,
.write_init = zynqmp_fpga_ops_write_init,
.write = zynqmp_fpga_ops_write,
+   .write_sg = zynqmp_fpga_ops_write_sg,
.write_complete = zynqmp_fpga_ops_write_complete,
 };
 
-- 
2.18.0

___
dri-devel mailing list
dri-devel@lists.freedesktop.org
https://lists.freedesktop.org/mailman/listinfo/dri-devel


[PATCH RFC 2/3] fpga: support loading from a pre-allocated buffer

2021-04-02 Thread Nava kishore Manne
Some systems are memory constrained but they need to load very
large Configuration files. The FPGA subsystem allows drivers to
request this Configuration image be loaded from the filesystem,
but this requires that the entire configuration data be loaded
into kernel memory first before it's provided to the driver.
This can lead to a situation where we map the configuration
data twice, once to load the configuration data into kernel
memory and once to copy the configuration data into the final
resting place which is nothing but a dma-able continuous buffer.

This creates needless memory pressure and delays due to multiple
copies. Let's add a dmabuf handling support to the fpga manager
framework that allows drivers to load the Configuration data
directly from a pre-allocated buffer. This skips the intermediate
step of allocating a buffer in kernel memory to hold the
Configuration data.

Signed-off-by: Nava kishore Manne 
---
 drivers/fpga/fpga-mgr.c   | 126 +-
 drivers/fpga/of-fpga-region.c |   3 +
 include/linux/fpga/fpga-mgr.h |   6 +-
 3 files changed, 132 insertions(+), 3 deletions(-)

diff --git a/drivers/fpga/fpga-mgr.c b/drivers/fpga/fpga-mgr.c
index b85bc47c91a9..13faed61af62 100644
--- a/drivers/fpga/fpga-mgr.c
+++ b/drivers/fpga/fpga-mgr.c
@@ -8,6 +8,8 @@
  * With code from the mailing list:
  * Copyright (C) 2013 Xilinx, Inc.
  */
+#include 
+#include 
 #include 
 #include 
 #include 
@@ -306,6 +308,51 @@ static int fpga_mgr_buf_load(struct fpga_manager *mgr,
return rc;
 }
 
+/**
+ * fpga_mgr_buf_load - load fpga from image in dma buffer
+ * @mgr:fpga manager
+ * @info:   fpga image info
+ *
+ * Step the low level fpga manager through the device-specific steps of getting
+ * an FPGA ready to be configured, writing the image to it, then doing whatever
+ * post-configuration steps necessary.  This code assumes the caller got the
+ * mgr pointer from of_fpga_mgr_get() and checked that it is not an error code.
+ *
+ * Return: 0 on success, negative error code otherwise.
+ */
+static int fpga_dmabuf_load(struct fpga_manager *mgr,
+   struct fpga_image_info *info)
+{
+   struct dma_buf_attachment *attach;
+   struct sg_table *sgt;
+   int ret;
+
+   /* create attachment for dmabuf with the user device */
+   attach = dma_buf_attach(mgr->dmabuf, >dev);
+   if (IS_ERR(attach)) {
+   pr_err("failed to attach dmabuf\n");
+   ret = PTR_ERR(attach);
+   goto fail_put;
+   }
+
+   sgt = dma_buf_map_attachment(attach, DMA_BIDIRECTIONAL);
+   if (IS_ERR(sgt)) {
+   ret = PTR_ERR(sgt);
+   goto fail_detach;
+   }
+
+   info->sgt = sgt;
+   ret = fpga_mgr_buf_load_sg(mgr, info, info->sgt);
+   dma_buf_unmap_attachment(attach, sgt, DMA_BIDIRECTIONAL);
+
+fail_detach:
+   dma_buf_detach(mgr->dmabuf, attach);
+fail_put:
+   dma_buf_put(mgr->dmabuf);
+
+   return ret;
+}
+
 /**
  * fpga_mgr_firmware_load - request firmware and load to fpga
  * @mgr:   fpga manager
@@ -358,6 +405,8 @@ static int fpga_mgr_firmware_load(struct fpga_manager *mgr,
  */
 int fpga_mgr_load(struct fpga_manager *mgr, struct fpga_image_info *info)
 {
+   if (info->flags & FPGA_MGR_CONFIG_DMA_BUF)
+   return fpga_dmabuf_load(mgr, info);
if (info->sgt)
return fpga_mgr_buf_load_sg(mgr, info, info->sgt);
if (info->buf && info->count)
@@ -549,6 +598,62 @@ void fpga_mgr_unlock(struct fpga_manager *mgr)
 }
 EXPORT_SYMBOL_GPL(fpga_mgr_unlock);
 
+static int fpga_dmabuf_fd_get(struct file *file, char __user *argp)
+{
+   struct fpga_manager *mgr =  (struct fpga_manager *)(file->private_data);
+   int buffd;
+
+   if (copy_from_user(, argp, sizeof(buffd)))
+   return -EFAULT;
+
+   mgr->dmabuf = dma_buf_get(buffd);
+   if (IS_ERR_OR_NULL(mgr->dmabuf))
+   return -EINVAL;
+
+   return 0;
+}
+
+static int fpga_device_open(struct inode *inode, struct file *file)
+{
+   struct miscdevice *miscdev = file->private_data;
+   struct fpga_manager *mgr = container_of(miscdev,
+   struct fpga_manager, miscdev);
+
+   file->private_data = mgr;
+
+   return 0;
+}
+
+static int fpga_device_release(struct inode *inode, struct file *file)
+{
+   return 0;
+}
+
+static long fpga_device_ioctl(struct file *file, unsigned int cmd,
+ unsigned long arg)
+{
+   char __user *argp = (char __user *)arg;
+   int err;
+
+   switch (cmd) {
+   case FPGA_IOCTL_LOAD_DMA_BUFF:
+   err = fpga_dmabuf_fd_get(file, argp);
+   break;
+   default:
+   err = -ENOTTY;
+   }
+
+   return err;
+}
+
+static const struct file_operations fpga_fops = {
+   .ow