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] [thread-next>] [day] [month] [year] [list]
Message-ID: <20180614010713.fivl64pirawrnrhc@derp-derp.local>
Date:   Wed, 13 Jun 2018 20:07:13 -0500
From:   Moritz Fischer <mdf@...nel.org>
To:     Wu Hao <hao.wu@...el.com>
Cc:     atull@...nel.org, mdf@...nel.org, linux-fpga@...r.kernel.org,
        linux-kernel@...r.kernel.org, linux-api@...r.kernel.org,
        luwei.kang@...el.com, yi.z.zhang@...el.com,
        Tim Whisonant <tim.whisonant@...el.com>,
        Enno Luebbers <enno.luebbers@...el.com>,
        Shiva Rao <shiva.rao@...el.com>,
        Christopher Rauer <christopher.rauer@...el.com>,
        Xiao Guangrong <guangrong.xiao@...ux.intel.com>
Subject: Re: [PATCH v6 17/29] fpga: dfl: fme: add partial reconfiguration sub
 feature support

Hi,

quick question for Alan inline below.

On Tue, Jun 12, 2018 at 06:10:31PM +0800, Wu Hao wrote:
> From: Kang Luwei <luwei.kang@...el.com>
> 
> Partial Reconfiguration (PR) is the most important function for FME. It
> allows reconfiguration for given Port/Accelerated Function Unit (AFU).
> 
> It creates platform devices for fpga-mgr, fpga-regions and fpga-bridges,
> and invokes fpga-region's interface (fpga_region_program_fpga) for PR
> operation once PR request received via ioctl. Below user space interface
> is exposed by this sub feature.
> 
> Ioctl interface:
> * DFL_FPGA_FME_PORT_PR
>   Do partial reconfiguration per information from userspace, including
>   target port(AFU), buffer size and address info. It returns error code
>   to userspace if failed. For detailed PR error information, user needs
>   to read fpga-mgr's status sysfs interface.
> 
> Signed-off-by: Tim Whisonant <tim.whisonant@...el.com>
> Signed-off-by: Enno Luebbers <enno.luebbers@...el.com>
> Signed-off-by: Shiva Rao <shiva.rao@...el.com>
> Signed-off-by: Christopher Rauer <christopher.rauer@...el.com>
> Signed-off-by: Kang Luwei <luwei.kang@...el.com>
> Signed-off-by: Xiao Guangrong <guangrong.xiao@...ux.intel.com>
> Signed-off-by: Wu Hao <hao.wu@...el.com>
> Acked-by: Alan Tull <atull@...nel.org>
> ---
> v2: moved the code to drivers/fpga folder as suggested by Alan Tull.
>     switched to GPLv2 license.
>     removed status from FPGA_FME_PORT_PR ioctl data structure.
>     added platform devices creation for fpga-mgr/fpga-region/fpga-bridge.
>     switched to fpga-region interface fpga_region_program_fpga for PR.
>     fixed comments from Alan Tull on FPGA_MGR_PARTIAL_RECONFIG flag usage.
>     fixed kbuild warnings.
> v3: rename driver files to dfl-fme-*.
>     rebase due to fpga APIs change.
>     replace bitfields.
>     switch to fpga_cdev_find_port to find port device.
> v4: rebase and correct comments for some function.
>     fix SPDX license issue.
>     remove unnecessary input parameter for destroy_bridge/region function.
>     add dfl-fme-pr.h for PR sub feature data structure and registers.
> v5: rebase due to DFL framework API naming changes.
>     improve naming for IOCTL API, functions and data structure.
>     defer finding port platform device to fme bridge.
>     pass mapped ioaddr to fme manager via pdata.
>     remove useless devm_kfree().
> v6: rebase, fix copyright time and improve function name.
>     add Acked-by from Alan.
> ---
>  drivers/fpga/Makefile         |   2 +-
>  drivers/fpga/dfl-fme-main.c   |  43 +++-
>  drivers/fpga/dfl-fme-pr.c     | 474 ++++++++++++++++++++++++++++++++++++++++++
>  drivers/fpga/dfl-fme-pr.h     |  84 ++++++++
>  drivers/fpga/dfl-fme.h        |  38 ++++
>  include/uapi/linux/fpga-dfl.h |  28 +++
>  6 files changed, 667 insertions(+), 2 deletions(-)
>  create mode 100644 drivers/fpga/dfl-fme-pr.c
>  create mode 100644 drivers/fpga/dfl-fme-pr.h
>  create mode 100644 drivers/fpga/dfl-fme.h
> 
> diff --git a/drivers/fpga/Makefile b/drivers/fpga/Makefile
> index db11f34..fd334d40 100644
> --- a/drivers/fpga/Makefile
> +++ b/drivers/fpga/Makefile
> @@ -33,7 +33,7 @@ obj-$(CONFIG_OF_FPGA_REGION)		+= of-fpga-region.o
>  obj-$(CONFIG_FPGA_DFL)			+= dfl.o
>  obj-$(CONFIG_FPGA_DFL_FME)		+= dfl-fme.o
>  
> -dfl-fme-objs := dfl-fme-main.o
> +dfl-fme-objs := dfl-fme-main.o dfl-fme-pr.o
>  
>  # Drivers for FPGAs which implement DFL
>  obj-$(CONFIG_FPGA_DFL_PCI)		+= dfl-pci.o
> diff --git a/drivers/fpga/dfl-fme-main.c b/drivers/fpga/dfl-fme-main.c
> index 889d669..7359804 100644
> --- a/drivers/fpga/dfl-fme-main.c
> +++ b/drivers/fpga/dfl-fme-main.c
> @@ -19,6 +19,7 @@
>  #include <linux/fpga-dfl.h>
>  
>  #include "dfl.h"
> +#include "dfl-fme.h"
>  
>  static ssize_t ports_num_show(struct device *dev,
>  			      struct device_attribute *attr, char *buf)
> @@ -113,6 +114,10 @@ static void fme_hdr_uinit(struct platform_device *pdev,
>  		.ops = &fme_hdr_ops,
>  	},
>  	{
> +		.id = FME_FEATURE_ID_PR_MGMT,
> +		.ops = &pr_mgmt_ops,
> +	},
> +	{
>  		.ops = NULL,
>  	},
>  };
> @@ -187,6 +192,35 @@ static long fme_ioctl(struct file *filp, unsigned int cmd, unsigned long arg)
>  	return -EINVAL;
>  }
>  
> +static int fme_dev_init(struct platform_device *pdev)
> +{
> +	struct dfl_feature_platform_data *pdata = dev_get_platdata(&pdev->dev);
> +	struct dfl_fme *fme;
> +
> +	fme = devm_kzalloc(&pdev->dev, sizeof(*fme), GFP_KERNEL);
> +	if (!fme)
> +		return -ENOMEM;
> +
> +	fme->pdata = pdata;
> +
> +	mutex_lock(&pdata->lock);
> +	dfl_fpga_pdata_set_private(pdata, fme);
> +	mutex_unlock(&pdata->lock);
> +
> +	return 0;
> +}
> +
> +static void fme_dev_destroy(struct platform_device *pdev)
> +{
> +	struct dfl_feature_platform_data *pdata = dev_get_platdata(&pdev->dev);
> +	struct dfl_fme *fme;
> +
> +	mutex_lock(&pdata->lock);
> +	fme = dfl_fpga_pdata_get_private(pdata);
> +	dfl_fpga_pdata_set_private(pdata, NULL);
> +	mutex_unlock(&pdata->lock);
> +}
> +
>  static const struct file_operations fme_fops = {
>  	.owner		= THIS_MODULE,
>  	.open		= fme_open,
> @@ -198,10 +232,14 @@ static int fme_probe(struct platform_device *pdev)
>  {
>  	int ret;
>  
> -	ret = dfl_fpga_dev_feature_init(pdev, fme_feature_drvs);
> +	ret = fme_dev_init(pdev);
>  	if (ret)
>  		goto exit;
>  
> +	ret = dfl_fpga_dev_feature_init(pdev, fme_feature_drvs);
> +	if (ret)
> +		goto dev_destroy;
> +
>  	ret = dfl_fpga_dev_ops_register(pdev, &fme_fops, THIS_MODULE);
>  	if (ret)
>  		goto feature_uinit;
> @@ -210,6 +248,8 @@ static int fme_probe(struct platform_device *pdev)
>  
>  feature_uinit:
>  	dfl_fpga_dev_feature_uinit(pdev);
> +dev_destroy:
> +	fme_dev_destroy(pdev);
>  exit:
>  	return ret;
>  }
> @@ -218,6 +258,7 @@ static int fme_remove(struct platform_device *pdev)
>  {
>  	dfl_fpga_dev_ops_unregister(pdev);
>  	dfl_fpga_dev_feature_uinit(pdev);
> +	fme_dev_destroy(pdev);
>  
>  	return 0;
>  }
> diff --git a/drivers/fpga/dfl-fme-pr.c b/drivers/fpga/dfl-fme-pr.c
> new file mode 100644
> index 0000000..5939a5c
> --- /dev/null
> +++ b/drivers/fpga/dfl-fme-pr.c
> @@ -0,0 +1,474 @@
> +// SPDX-License-Identifier: GPL-2.0
> +/*
> + * Driver for FPGA Management Engine (FME) Partial Reconfiguration
> + *
> + * Copyright (C) 2017-2018 Intel Corporation, Inc.
> + *
> + * Authors:
> + *   Kang Luwei <luwei.kang@...el.com>
> + *   Xiao Guangrong <guangrong.xiao@...ux.intel.com>
> + *   Wu Hao <hao.wu@...el.com>
> + *   Joseph Grecco <joe.grecco@...el.com>
> + *   Enno Luebbers <enno.luebbers@...el.com>
> + *   Tim Whisonant <tim.whisonant@...el.com>
> + *   Ananda Ravuri <ananda.ravuri@...el.com>
> + *   Christopher Rauer <christopher.rauer@...el.com>
> + *   Henry Mitchel <henry.mitchel@...el.com>
> + */
> +
> +#include <linux/types.h>
> +#include <linux/device.h>
> +#include <linux/vmalloc.h>
> +#include <linux/uaccess.h>
> +#include <linux/fpga/fpga-mgr.h>
> +#include <linux/fpga/fpga-bridge.h>
> +#include <linux/fpga/fpga-region.h>
> +#include <linux/fpga-dfl.h>
> +
> +#include "dfl.h"
> +#include "dfl-fme.h"
> +#include "dfl-fme-pr.h"
> +
> +static struct dfl_fme_region *
> +dfl_fme_region_find_by_port_id(struct dfl_fme *fme, int port_id)
> +{
> +	struct dfl_fme_region *fme_region;
> +
> +	list_for_each_entry(fme_region, &fme->region_list, node)
> +		if (fme_region->port_id == port_id)
> +			return fme_region;
> +
> +	return NULL;
> +}
> +
> +static int dfl_fme_region_match(struct device *dev, const void *data)
> +{
> +	return dev->parent == data;
> +}
> +
> +static struct fpga_region *dfl_fme_region_find(struct dfl_fme *fme, int port_id)
> +{
> +	struct dfl_fme_region *fme_region;
> +	struct fpga_region *region;
> +
> +	fme_region = dfl_fme_region_find_by_port_id(fme, port_id);
> +	if (!fme_region)
> +		return NULL;
> +
> +	region = fpga_region_class_find(NULL, &fme_region->region->dev,
> +					dfl_fme_region_match);
> +	if (!region)
> +		return NULL;
> +
> +	return region;
> +}
> +
> +static int fme_pr(struct platform_device *pdev, unsigned long arg)
> +{
> +	struct dfl_feature_platform_data *pdata = dev_get_platdata(&pdev->dev);
> +	void __user *argp = (void __user *)arg;
> +	struct dfl_fpga_fme_port_pr port_pr;
> +	struct fpga_image_info *info;
> +	struct fpga_region *region;
> +	void __iomem *fme_hdr;
> +	struct dfl_fme *fme;
> +	unsigned long minsz;
> +	void *buf = NULL;
> +	int ret = 0;
> +	u64 v;
> +
> +	minsz = offsetofend(struct dfl_fpga_fme_port_pr, buffer_address);
> +
> +	if (copy_from_user(&port_pr, argp, minsz))
> +		return -EFAULT;
> +
> +	if (port_pr.argsz < minsz || port_pr.flags)
> +		return -EINVAL;
> +
> +	if (!IS_ALIGNED(port_pr.buffer_size, 4))
> +		return -EINVAL;
> +
> +	/* get fme header region */
> +	fme_hdr = dfl_get_feature_ioaddr_by_id(&pdev->dev,
> +					       FME_FEATURE_ID_HEADER);
> +
> +	/* check port id */
> +	v = readq(fme_hdr + FME_HDR_CAP);
> +	if (port_pr.port_id >= FIELD_GET(FME_CAP_NUM_PORTS, v)) {
> +		dev_dbg(&pdev->dev, "port number more than maximum\n");
> +		return -EINVAL;
> +	}
> +
> +	if (!access_ok(VERIFY_READ,
> +		       (void __user *)(unsigned long)port_pr.buffer_address,
> +		       port_pr.buffer_size))
> +		return -EFAULT;
> +
> +	buf = vmalloc(port_pr.buffer_size);
> +	if (!buf)
> +		return -ENOMEM;
> +
> +	if (copy_from_user(buf,
> +			   (void __user *)(unsigned long)port_pr.buffer_address,
> +			   port_pr.buffer_size)) {
> +		ret = -EFAULT;
> +		goto free_exit;
> +	}
> +
> +	/* prepare fpga_image_info for PR */
> +	info = fpga_image_info_alloc(&pdev->dev);
> +	if (!info) {
> +		ret = -ENOMEM;
> +		goto free_exit;
> +	}
> +
> +	info->flags |= FPGA_MGR_PARTIAL_RECONFIG;
> +
> +	mutex_lock(&pdata->lock);
> +	fme = dfl_fpga_pdata_get_private(pdata);
> +	/* fme device has been unregistered. */
> +	if (!fme) {
> +		ret = -EINVAL;
> +		goto unlock_exit;
> +	}
> +
> +	region = dfl_fme_region_find(fme, port_pr.port_id);
> +	if (!region) {
> +		ret = -EINVAL;
> +		goto unlock_exit;
> +	}
> +
> +	fpga_image_info_free(region->info);
> +
> +	info->buf = buf;
> +	info->count = port_pr.buffer_size;
> +	info->region_id = port_pr.port_id;
> +	region->info = info;
> +
> +	ret = fpga_region_program_fpga(region);
> +
> +	if (region->get_bridges)
> +		fpga_bridges_put(&region->bridge_list);

I'm wondering if this should not be done as part of
fpga_region_program_fpga() (It's not at the moment).

Alan, am I missing something obvious? :)
> +
> +	put_device(&region->dev);
> +unlock_exit:
> +	mutex_unlock(&pdata->lock);
> +free_exit:
> +	vfree(buf);
> +	if (copy_to_user((void __user *)arg, &port_pr, minsz))
> +		return -EFAULT;
> +
> +	return ret;
> +}
> +
> +/**
> + * dfl_fme_create_mgr - create fpga mgr platform device as child device
> + *
> + * @pdata: fme platform_device's pdata
> + *
> + * Return: mgr platform device if successful, and error code otherwise.
> + */
> +static struct platform_device *
> +dfl_fme_create_mgr(struct dfl_feature_platform_data *pdata,
> +		   struct dfl_feature *feature)
> +{
> +	struct platform_device *mgr, *fme = pdata->dev;
> +	struct dfl_fme_mgr_pdata mgr_pdata;
> +	int ret = -ENOMEM;
> +
> +	if (!feature->ioaddr)
> +		return ERR_PTR(-ENODEV);
> +
> +	mgr_pdata.ioaddr = feature->ioaddr;
> +
> +	/*
> +	 * Each FME has only one fpga-mgr, so allocate platform device using
> +	 * the same FME platform device id.
> +	 */
> +	mgr = platform_device_alloc(DFL_FPGA_FME_MGR, fme->id);
> +	if (!mgr)
> +		return ERR_PTR(ret);
> +
> +	mgr->dev.parent = &fme->dev;
> +
> +	ret = platform_device_add_data(mgr, &mgr_pdata, sizeof(mgr_pdata));
> +	if (ret)
> +		goto create_mgr_err;
> +
> +	ret = platform_device_add(mgr);
> +	if (ret)
> +		goto create_mgr_err;
> +
> +	return mgr;
> +
> +create_mgr_err:
> +	platform_device_put(mgr);
> +	return ERR_PTR(ret);
> +}
> +
> +/**
> + * dfl_fme_destroy_mgr - destroy fpga mgr platform device
> + * @pdata: fme platform device's pdata
> + */
> +static void dfl_fme_destroy_mgr(struct dfl_feature_platform_data *pdata)
> +{
> +	struct dfl_fme *priv = dfl_fpga_pdata_get_private(pdata);
> +
> +	platform_device_unregister(priv->mgr);
> +}
> +
> +/**
> + * dfl_fme_create_bridge - create fme fpga bridge platform device as child
> + *
> + * @pdata: fme platform device's pdata
> + * @port_id: port id for the bridge to be created.
> + *
> + * Return: bridge platform device if successful, and error code otherwise.
> + */
> +static struct dfl_fme_bridge *
> +dfl_fme_create_bridge(struct dfl_feature_platform_data *pdata, int port_id)
> +{
> +	struct device *dev = &pdata->dev->dev;
> +	struct dfl_fme_br_pdata br_pdata;
> +	struct dfl_fme_bridge *fme_br;
> +	int ret = -ENOMEM;
> +
> +	fme_br = devm_kzalloc(dev, sizeof(*fme_br), GFP_KERNEL);
> +	if (!fme_br)
> +		return ERR_PTR(ret);
> +
> +	br_pdata.cdev = pdata->dfl_cdev;
> +	br_pdata.port_id = port_id;
> +
> +	fme_br->br = platform_device_alloc(DFL_FPGA_FME_BRIDGE,
> +					   PLATFORM_DEVID_AUTO);
> +	if (!fme_br->br)
> +		return ERR_PTR(ret);
> +
> +	fme_br->br->dev.parent = dev;
> +
> +	ret = platform_device_add_data(fme_br->br, &br_pdata, sizeof(br_pdata));
> +	if (ret)
> +		goto create_br_err;
> +
> +	ret = platform_device_add(fme_br->br);
> +	if (ret)
> +		goto create_br_err;
> +
> +	return fme_br;
> +
> +create_br_err:
> +	platform_device_put(fme_br->br);
> +	return ERR_PTR(ret);
> +}
> +
> +/**
> + * dfl_fme_destroy_bridge - destroy fpga bridge platform device
> + * @fme_br: fme bridge to destroy
> + */
> +static void dfl_fme_destroy_bridge(struct dfl_fme_bridge *fme_br)
> +{
> +	platform_device_unregister(fme_br->br);
> +}
> +
> +/**
> + * dfl_fme_destroy_bridge - destroy all fpga bridge platform device
> + * @pdata: fme platform device's pdata
> + */
> +static void dfl_fme_destroy_bridges(struct dfl_feature_platform_data *pdata)
> +{
> +	struct dfl_fme *priv = dfl_fpga_pdata_get_private(pdata);
> +	struct dfl_fme_bridge *fbridge, *tmp;
> +
> +	list_for_each_entry_safe(fbridge, tmp, &priv->bridge_list, node) {
> +		list_del(&fbridge->node);
> +		dfl_fme_destroy_bridge(fbridge);
> +	}
> +}
> +
> +/**
> + * dfl_fme_create_region - create fpga region platform device as child
> + *
> + * @pdata: fme platform device's pdata
> + * @mgr: mgr platform device needed for region
> + * @br: br platform device needed for region
> + * @port_id: port id
> + *
> + * Return: fme region if successful, and error code otherwise.
> + */
> +static struct dfl_fme_region *
> +dfl_fme_create_region(struct dfl_feature_platform_data *pdata,
> +		      struct platform_device *mgr,
> +		      struct platform_device *br, int port_id)
> +{
> +	struct dfl_fme_region_pdata region_pdata;
> +	struct device *dev = &pdata->dev->dev;
> +	struct dfl_fme_region *fme_region;
> +	int ret = -ENOMEM;
> +
> +	fme_region = devm_kzalloc(dev, sizeof(*fme_region), GFP_KERNEL);
> +	if (!fme_region)
> +		return ERR_PTR(ret);
> +
> +	region_pdata.mgr = mgr;
> +	region_pdata.br = br;
> +
> +	/*
> +	 * Each FPGA device may have more than one port, so allocate platform
> +	 * device using the same port platform device id.
> +	 */
> +	fme_region->region = platform_device_alloc(DFL_FPGA_FME_REGION, br->id);
> +	if (!fme_region->region)
> +		return ERR_PTR(ret);
> +
> +	fme_region->region->dev.parent = dev;
> +
> +	ret = platform_device_add_data(fme_region->region, &region_pdata,
> +				       sizeof(region_pdata));
> +	if (ret)
> +		goto create_region_err;
> +
> +	ret = platform_device_add(fme_region->region);
> +	if (ret)
> +		goto create_region_err;
> +
> +	fme_region->port_id = port_id;
> +
> +	return fme_region;
> +
> +create_region_err:
> +	platform_device_put(fme_region->region);
> +	return ERR_PTR(ret);
> +}
> +
> +/**
> + * dfl_fme_destroy_region - destroy fme region
> + * @fme_region: fme region to destroy
> + */
> +static void dfl_fme_destroy_region(struct dfl_fme_region *fme_region)
> +{
> +	platform_device_unregister(fme_region->region);
> +}
> +
> +/**
> + * dfl_fme_destroy_regions - destroy all fme regions
> + * @pdata: fme platform device's pdata
> + */
> +static void dfl_fme_destroy_regions(struct dfl_feature_platform_data *pdata)
> +{
> +	struct dfl_fme *priv = dfl_fpga_pdata_get_private(pdata);
> +	struct dfl_fme_region *fme_region, *tmp;
> +
> +	list_for_each_entry_safe(fme_region, tmp, &priv->region_list, node) {
> +		list_del(&fme_region->node);
> +		dfl_fme_destroy_region(fme_region);
> +	}
> +}
> +
> +static int pr_mgmt_init(struct platform_device *pdev,
> +			struct dfl_feature *feature)
> +{
> +	struct dfl_feature_platform_data *pdata = dev_get_platdata(&pdev->dev);
> +	struct dfl_fme_region *fme_region;
> +	struct dfl_fme_bridge *fme_br;
> +	struct platform_device *mgr;
> +	struct dfl_fme *priv;
> +	void __iomem *fme_hdr;
> +	int ret = -ENODEV, i = 0;
> +	u64 fme_cap, port_offset;
> +
> +	fme_hdr = dfl_get_feature_ioaddr_by_id(&pdev->dev,
> +					       FME_FEATURE_ID_HEADER);
> +
> +	mutex_lock(&pdata->lock);
> +	priv = dfl_fpga_pdata_get_private(pdata);
> +
> +	/* Initialize the region and bridge sub device list */
> +	INIT_LIST_HEAD(&priv->region_list);
> +	INIT_LIST_HEAD(&priv->bridge_list);
> +
> +	/* Create fpga mgr platform device */
> +	mgr = dfl_fme_create_mgr(pdata, feature);
> +	if (IS_ERR(mgr)) {
> +		dev_err(&pdev->dev, "fail to create fpga mgr pdev\n");
> +		goto unlock;
> +	}
> +
> +	priv->mgr = mgr;
> +
> +	/* Read capability register to check number of regions and bridges */
> +	fme_cap = readq(fme_hdr + FME_HDR_CAP);
> +	for (; i < FIELD_GET(FME_CAP_NUM_PORTS, fme_cap); i++) {
> +		port_offset = readq(fme_hdr + FME_HDR_PORT_OFST(i));
> +		if (!(port_offset & FME_PORT_OFST_IMP))
> +			continue;
> +
> +		/* Create bridge for each port */
> +		fme_br = dfl_fme_create_bridge(pdata, i);
> +		if (IS_ERR(fme_br)) {
> +			ret = PTR_ERR(fme_br);
> +			goto destroy_region;
> +		}
> +
> +		list_add(&fme_br->node, &priv->bridge_list);
> +
> +		/* Create region for each port */
> +		fme_region = dfl_fme_create_region(pdata, mgr,
> +						   fme_br->br, i);
> +		if (!fme_region) {
> +			ret = PTR_ERR(fme_region);
> +			goto destroy_region;
> +		}
> +
> +		list_add(&fme_region->node, &priv->region_list);
> +	}
> +	mutex_unlock(&pdata->lock);
> +
> +	return 0;
> +
> +destroy_region:
> +	dfl_fme_destroy_regions(pdata);
> +	dfl_fme_destroy_bridges(pdata);
> +	dfl_fme_destroy_mgr(pdata);
> +unlock:
> +	mutex_unlock(&pdata->lock);
> +	return ret;
> +}
> +
> +static void pr_mgmt_uinit(struct platform_device *pdev,
> +			  struct dfl_feature *feature)
> +{
> +	struct dfl_feature_platform_data *pdata = dev_get_platdata(&pdev->dev);
> +	struct dfl_fme *priv;
> +
> +	mutex_lock(&pdata->lock);
> +	priv = dfl_fpga_pdata_get_private(pdata);
> +
> +	dfl_fme_destroy_regions(pdata);
> +	dfl_fme_destroy_bridges(pdata);
> +	dfl_fme_destroy_mgr(pdata);
> +	mutex_unlock(&pdata->lock);
> +}
> +
> +static long fme_pr_ioctl(struct platform_device *pdev,
> +			 struct dfl_feature *feature,
> +			 unsigned int cmd, unsigned long arg)
> +{
> +	long ret;
> +
> +	switch (cmd) {
> +	case DFL_FPGA_FME_PORT_PR:
> +		ret = fme_pr(pdev, arg);
> +		break;
> +	default:
> +		ret = -ENODEV;
> +	}
> +
> +	return ret;
> +}
> +
> +const struct dfl_feature_ops pr_mgmt_ops = {
> +	.init = pr_mgmt_init,
> +	.uinit = pr_mgmt_uinit,
> +	.ioctl = fme_pr_ioctl,
> +};
> diff --git a/drivers/fpga/dfl-fme-pr.h b/drivers/fpga/dfl-fme-pr.h
> new file mode 100644
> index 0000000..096a699
> --- /dev/null
> +++ b/drivers/fpga/dfl-fme-pr.h
> @@ -0,0 +1,84 @@
> +/* SPDX-License-Identifier: GPL-2.0 */
> +/*
> + * Header file for FPGA Management Engine (FME) Partial Reconfiguration Driver
> + *
> + * Copyright (C) 2017-2018 Intel Corporation, Inc.
> + *
> + * Authors:
> + *   Kang Luwei <luwei.kang@...el.com>
> + *   Xiao Guangrong <guangrong.xiao@...ux.intel.com>
> + *   Wu Hao <hao.wu@...el.com>
> + *   Joseph Grecco <joe.grecco@...el.com>
> + *   Enno Luebbers <enno.luebbers@...el.com>
> + *   Tim Whisonant <tim.whisonant@...el.com>
> + *   Ananda Ravuri <ananda.ravuri@...el.com>
> + *   Henry Mitchel <henry.mitchel@...el.com>
> + */
> +
> +#ifndef __DFL_FME_PR_H
> +#define __DFL_FME_PR_H
> +
> +#include <linux/platform_device.h>
> +
> +/**
> + * struct dfl_fme_region - FME fpga region data structure
> + *
> + * @region: platform device of the FPGA region.
> + * @node: used to link fme_region to a list.
> + * @port_id: indicate which port this region connected to.
> + */
> +struct dfl_fme_region {
> +	struct platform_device *region;
> +	struct list_head node;
> +	int port_id;
> +};
> +
> +/**
> + * struct dfl_fme_region_pdata - platform data for FME region platform device.
> + *
> + * @mgr: platform device of the FPGA manager.
> + * @br: platform device of the FPGA bridge.
> + * @region_id: region id (same as port_id).
> + */
> +struct dfl_fme_region_pdata {
> +	struct platform_device *mgr;
> +	struct platform_device *br;
> +	int region_id;
> +};
> +
> +/**
> + * struct dfl_fme_bridge - FME fpga bridge data structure
> + *
> + * @br: platform device of the FPGA bridge.
> + * @node: used to link fme_bridge to a list.
> + */
> +struct dfl_fme_bridge {
> +	struct platform_device *br;
> +	struct list_head node;
> +};
> +
> +/**
> + * struct dfl_fme_bridge_pdata - platform data for FME bridge platform device.
> + *
> + * @cdev: container device.
> + * @port_id: port id.
> + */
> +struct dfl_fme_br_pdata {
> +	struct dfl_fpga_cdev *cdev;
> +	int port_id;
> +};
> +
> +/**
> + * struct dfl_fme_mgr_pdata - platform data for FME manager platform device.
> + *
> + * @ioaddr: mapped io address for FME manager platform device.
> + */
> +struct dfl_fme_mgr_pdata {
> +	void __iomem *ioaddr;
> +};
> +
> +#define DFL_FPGA_FME_MGR	"dfl-fme-mgr"
> +#define DFL_FPGA_FME_BRIDGE	"dfl-fme-bridge"
> +#define DFL_FPGA_FME_REGION	"dfl-fme-region"
> +
> +#endif /* __DFL_FME_PR_H */
> diff --git a/drivers/fpga/dfl-fme.h b/drivers/fpga/dfl-fme.h
> new file mode 100644
> index 0000000..ac6d61a
> --- /dev/null
> +++ b/drivers/fpga/dfl-fme.h
> @@ -0,0 +1,38 @@
> +/* SPDX-License-Identifier: GPL-2.0 */
> +/*
> + * Header file for FPGA Management Engine (FME) Driver
> + *
> + * Copyright (C) 2017-2018 Intel Corporation, Inc.
> + *
> + * Authors:
> + *   Kang Luwei <luwei.kang@...el.com>
> + *   Xiao Guangrong <guangrong.xiao@...ux.intel.com>
> + *   Wu Hao <hao.wu@...el.com>
> + *   Joseph Grecco <joe.grecco@...el.com>
> + *   Enno Luebbers <enno.luebbers@...el.com>
> + *   Tim Whisonant <tim.whisonant@...el.com>
> + *   Ananda Ravuri <ananda.ravuri@...el.com>
> + *   Henry Mitchel <henry.mitchel@...el.com>
> + */
> +
> +#ifndef __DFL_FME_H
> +#define __DFL_FME_H
> +
> +/**
> + * struct dfl_fme - dfl fme private data
> + *
> + * @mgr: FME's FPGA manager platform device.
> + * @region_list: link list of FME's FPGA regions.
> + * @bridge_list: link list of FME's FPGA bridges.
> + * @pdata: fme platform device's pdata.
> + */
> +struct dfl_fme {
> +	struct platform_device *mgr;
> +	struct list_head region_list;
> +	struct list_head bridge_list;
> +	struct dfl_feature_platform_data *pdata;
> +};
> +
> +extern const struct dfl_feature_ops pr_mgmt_ops;
> +
> +#endif /* __DFL_FME_H */
> diff --git a/include/uapi/linux/fpga-dfl.h b/include/uapi/linux/fpga-dfl.h
> index 9ff26cb..9abfc1d 100644
> --- a/include/uapi/linux/fpga-dfl.h
> +++ b/include/uapi/linux/fpga-dfl.h
> @@ -14,6 +14,8 @@
>  #ifndef _UAPI_LINUX_FPGA_DFL_H
>  #define _UAPI_LINUX_FPGA_DFL_H
>  
> +#include <linux/types.h>
> +
>  #define DFL_FPGA_API_VERSION 0
>  
>  /*
> @@ -26,6 +28,7 @@
>  #define DFL_FPGA_MAGIC 0xB6
>  
>  #define DFL_FPGA_BASE 0
> +#define DFL_FME_BASE 0x80
>  
>  /**
>   * DFL_FPGA_GET_API_VERSION - _IO(DFL_FPGA_MAGIC, DFL_FPGA_BASE + 0)
> @@ -45,4 +48,29 @@
>  
>  #define DFL_FPGA_CHECK_EXTENSION	_IO(DFL_FPGA_MAGIC, DFL_FPGA_BASE + 1)
>  
> +/* IOCTLs for FME file descriptor */
> +
> +/**
> + * DFL_FPGA_FME_PORT_PR - _IOW(DFL_FPGA_MAGIC, DFL_FME_BASE + 0,
> + *						struct dfl_fpga_fme_port_pr)
> + *
> + * Driver does Partial Reconfiguration based on Port ID and Buffer (Image)
> + * provided by caller.
> + * Return: 0 on success, -errno on failure.
> + * If DFL_FPGA_FME_PORT_PR returns -EIO, that indicates the HW has detected
> + * some errors during PR, under this case, the user can fetch HW error info
> + * from the status of FME's fpga manager.
> + */
> +
> +struct dfl_fpga_fme_port_pr {
> +	/* Input */
> +	__u32 argsz;		/* Structure length */
> +	__u32 flags;		/* Zero for now */
> +	__u32 port_id;
> +	__u32 buffer_size;
> +	__u64 buffer_address;	/* Userspace address to the buffer for PR */
> +};
> +
> +#define DFL_FPGA_FME_PORT_PR	_IO(DFL_FPGA_MAGIC, DFL_FME_BASE + 0)
> +
>  #endif /* _UAPI_LINUX_FPGA_DFL_H */
> -- 
> 1.8.3.1
> 

Thanks,

Moritz

Powered by blists - more mailing lists

Powered by Openwall GNU/*/Linux Powered by OpenVZ