dri-devel.lists.freedesktop.org archive mirror
 help / color / mirror / Atom feed
From: "Martin Hundebøll" <mhu@silicom.dk>
To: Nava kishore Manne <nava.manne@xilinx.com>,
	mdf@kernel.org, trix@redhat.com, robh+dt@kernel.org,
	michal.simek@xilinx.com, sumit.semwal@linaro.org,
	christian.koenig@amd.com, linux-fpga@vger.kernel.org,
	devicetree@vger.kernel.org, linux-kernel@vger.kernel.org,
	linux-arm-kernel@lists.infradead.org,
	linux-media@vger.kernel.org, dri-devel@lists.freedesktop.org,
	linaro-mm-sig@lists.linaro.org, git@xilinx.com
Subject: Re: [PATCH RFC 2/3] fpga: support loading from a pre-allocated buffer
Date: Tue, 6 Apr 2021 08:42:51 +0200	[thread overview]
Message-ID: <531e5970-acc5-fc89-497c-cbff4259a416@silicom.dk> (raw)
In-Reply-To: <20210402090933.32276-3-nava.manne@xilinx.com>

Hi Nava,

On minor comment below.

On 02/04/2021 11.09, Nava kishore Manne wrote:
> 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 <nava.manne@xilinx.com>
> ---
>   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 <linux/dma-buf.h>
> +#include <linux/dma-map-ops.h>
>   #include <linux/firmware.h>
>   #include <linux/fpga/fpga-mgr.h>
>   #include <linux/idr.h>
> @@ -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

s/fpga_mgr_buf_load/fpga_dmabuf_load

// Martin

> + * @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, &mgr->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(&buffd, 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 = {
> +	.owner		= THIS_MODULE,
> +	.open		= fpga_device_open,
> +	.release	= fpga_device_release,
> +	.unlocked_ioctl	= fpga_device_ioctl,
> +	.compat_ioctl	= fpga_device_ioctl,
> +};
> +
>   /**
>    * fpga_mgr_create - create and initialize a FPGA manager struct
>    * @dev:	fpga manager device from pdev
> @@ -569,8 +674,7 @@ struct fpga_manager *fpga_mgr_create(struct device *dev, const char *name,
>   	int id, ret;
>   
>   	if (!mops || !mops->write_complete || !mops->state ||
> -	    !mops->write_init || (!mops->write && !mops->write_sg) ||
> -	    (mops->write && mops->write_sg)) {
> +	    !mops->write_init || (!mops->write && !mops->write_sg)) {
>   		dev_err(dev, "Attempt to register without fpga_manager_ops\n");
>   		return NULL;
>   	}
> @@ -601,10 +705,28 @@ struct fpga_manager *fpga_mgr_create(struct device *dev, const char *name,
>   	mgr->dev.of_node = dev->of_node;
>   	mgr->dev.id = id;
>   
> +	/* Make device dma capable by inheriting from parent's */
> +	set_dma_ops(&mgr->dev, get_dma_ops(dev));
> +	ret = dma_coerce_mask_and_coherent(&mgr->dev, dma_get_mask(dev));
> +	if (ret) {
> +		dev_warn(dev,
> +			 "Failed to set DMA mask %llx.Trying to continue.%x\n",
> +			 dma_get_mask(dev), ret);
> +	}
> +
>   	ret = dev_set_name(&mgr->dev, "fpga%d", id);
>   	if (ret)
>   		goto error_device;
>   
> +	mgr->miscdev.minor = MISC_DYNAMIC_MINOR;
> +	mgr->miscdev.name = kobject_name(&mgr->dev.kobj);
> +	mgr->miscdev.fops = &fpga_fops;
> +	ret = misc_register(&mgr->miscdev);
> +	if (ret) {
> +		pr_err("fpga: failed to register misc device.\n");
> +		goto error_device;
> +	}
> +
>   	return mgr;
>   
>   error_device:
> diff --git a/drivers/fpga/of-fpga-region.c b/drivers/fpga/of-fpga-region.c
> index 35fc2f3d4bd8..698e3e42ccba 100644
> --- a/drivers/fpga/of-fpga-region.c
> +++ b/drivers/fpga/of-fpga-region.c
> @@ -229,6 +229,9 @@ static struct fpga_image_info *of_fpga_region_parse_ov(
>   	if (of_property_read_bool(overlay, "encrypted-fpga-config"))
>   		info->flags |= FPGA_MGR_ENCRYPTED_BITSTREAM;
>   
> +	if (of_property_read_bool(overlay, "fpga-config-from-dmabuf"))
> +		info->flags |= FPGA_MGR_CONFIG_DMA_BUF;
> +
>   	if (!of_property_read_string(overlay, "firmware-name",
>   				     &firmware_name)) {
>   		info->firmware_name = devm_kstrdup(dev, firmware_name,
> diff --git a/include/linux/fpga/fpga-mgr.h b/include/linux/fpga/fpga-mgr.h
> index 2bc3030a69e5..6208c22f7bed 100644
> --- a/include/linux/fpga/fpga-mgr.h
> +++ b/include/linux/fpga/fpga-mgr.h
> @@ -9,6 +9,7 @@
>   #define _LINUX_FPGA_MGR_H
>   
>   #include <linux/mutex.h>
> +#include <linux/miscdevice.h>
>   #include <linux/platform_device.h>
>   
>   struct fpga_manager;
> @@ -73,7 +74,7 @@ enum fpga_mgr_states {
>   #define FPGA_MGR_ENCRYPTED_BITSTREAM	BIT(2)
>   #define FPGA_MGR_BITSTREAM_LSB_FIRST	BIT(3)
>   #define FPGA_MGR_COMPRESSED_BITSTREAM	BIT(4)
> -
> +#define FPGA_MGR_CONFIG_DMA_BUF		BIT(5)
>   /**
>    * struct fpga_image_info - information specific to a FPGA image
>    * @flags: boolean flags as defined above
> @@ -167,6 +168,8 @@ struct fpga_compat_id {
>   struct fpga_manager {
>   	const char *name;
>   	struct device dev;
> +	struct miscdevice miscdev;
> +	struct dma_buf *dmabuf;
>   	struct mutex ref_mutex;
>   	enum fpga_mgr_states state;
>   	struct fpga_compat_id *compat_id;
> @@ -204,4 +207,5 @@ struct fpga_manager *devm_fpga_mgr_create(struct device *dev, const char *name,
>   					  const struct fpga_manager_ops *mops,
>   					  void *priv);
>   
> +#define FPGA_IOCTL_LOAD_DMA_BUFF	_IOWR('R', 1, __u32)
>   #endif /*_LINUX_FPGA_MGR_H */
> 
_______________________________________________
dri-devel mailing list
dri-devel@lists.freedesktop.org
https://lists.freedesktop.org/mailman/listinfo/dri-devel

  reply	other threads:[~2021-04-06 11:53 UTC|newest]

Thread overview: 7+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2021-04-02  9:09 [PATCH RFC 0/3] Adds support to allow the bitstream configuration from pre-allocated dma-buffer Nava kishore Manne
2021-04-02  9:09 ` [PATCH RFC 1/3] fpga: region: Add fpga-region property 'fpga-config-from-dmabuf' Nava kishore Manne
2021-04-09 14:47   ` Rob Herring
2021-04-02  9:09 ` [PATCH RFC 2/3] fpga: support loading from a pre-allocated buffer Nava kishore Manne
2021-04-06  6:42   ` Martin Hundebøll [this message]
2021-04-02  9:09 ` [PATCH RFC 3/3] fpga: zynqmp: Use the scatterlist interface Nava kishore Manne
2021-04-02 14:35 ` [PATCH RFC 0/3] Adds support to allow the bitstream configuration from pre-allocated dma-buffer Tom Rix

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=531e5970-acc5-fc89-497c-cbff4259a416@silicom.dk \
    --to=mhu@silicom.dk \
    --cc=christian.koenig@amd.com \
    --cc=devicetree@vger.kernel.org \
    --cc=dri-devel@lists.freedesktop.org \
    --cc=git@xilinx.com \
    --cc=linaro-mm-sig@lists.linaro.org \
    --cc=linux-arm-kernel@lists.infradead.org \
    --cc=linux-fpga@vger.kernel.org \
    --cc=linux-kernel@vger.kernel.org \
    --cc=linux-media@vger.kernel.org \
    --cc=mdf@kernel.org \
    --cc=michal.simek@xilinx.com \
    --cc=nava.manne@xilinx.com \
    --cc=robh+dt@kernel.org \
    --cc=sumit.semwal@linaro.org \
    --cc=trix@redhat.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 a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for NNTP newsgroup(s).