Commit 29de7624 authored by Kang Luwei's avatar Kang Luwei Committed by Greg Kroah-Hartman

fpga: dfl: fme: add partial reconfiguration sub feature support

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: default avatarTim Whisonant <tim.whisonant@intel.com>
Signed-off-by: default avatarEnno Luebbers <enno.luebbers@intel.com>
Signed-off-by: default avatarShiva Rao <shiva.rao@intel.com>
Signed-off-by: default avatarChristopher Rauer <christopher.rauer@intel.com>
Signed-off-by: default avatarKang Luwei <luwei.kang@intel.com>
Signed-off-by: default avatarXiao Guangrong <guangrong.xiao@linux.intel.com>
Signed-off-by: default avatarWu Hao <hao.wu@intel.com>
Acked-by: default avatarAlan Tull <atull@kernel.org>
Signed-off-by: default avatarGreg Kroah-Hartman <gregkh@linuxfoundation.org>
parent 620e1902
...@@ -33,7 +33,7 @@ obj-$(CONFIG_OF_FPGA_REGION) += of-fpga-region.o ...@@ -33,7 +33,7 @@ obj-$(CONFIG_OF_FPGA_REGION) += of-fpga-region.o
obj-$(CONFIG_FPGA_DFL) += dfl.o obj-$(CONFIG_FPGA_DFL) += dfl.o
obj-$(CONFIG_FPGA_DFL_FME) += dfl-fme.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 # Drivers for FPGAs which implement DFL
obj-$(CONFIG_FPGA_DFL_PCI) += dfl-pci.o obj-$(CONFIG_FPGA_DFL_PCI) += dfl-pci.o
...@@ -19,6 +19,7 @@ ...@@ -19,6 +19,7 @@
#include <linux/fpga-dfl.h> #include <linux/fpga-dfl.h>
#include "dfl.h" #include "dfl.h"
#include "dfl-fme.h"
static ssize_t ports_num_show(struct device *dev, static ssize_t ports_num_show(struct device *dev,
struct device_attribute *attr, char *buf) struct device_attribute *attr, char *buf)
...@@ -112,6 +113,10 @@ static struct dfl_feature_driver fme_feature_drvs[] = { ...@@ -112,6 +113,10 @@ static struct dfl_feature_driver fme_feature_drvs[] = {
.id = FME_FEATURE_ID_HEADER, .id = FME_FEATURE_ID_HEADER,
.ops = &fme_hdr_ops, .ops = &fme_hdr_ops,
}, },
{
.id = FME_FEATURE_ID_PR_MGMT,
.ops = &pr_mgmt_ops,
},
{ {
.ops = NULL, .ops = NULL,
}, },
...@@ -187,6 +192,35 @@ static long fme_ioctl(struct file *filp, unsigned int cmd, unsigned long arg) ...@@ -187,6 +192,35 @@ static long fme_ioctl(struct file *filp, unsigned int cmd, unsigned long arg)
return -EINVAL; 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 = { static const struct file_operations fme_fops = {
.owner = THIS_MODULE, .owner = THIS_MODULE,
.open = fme_open, .open = fme_open,
...@@ -198,10 +232,14 @@ static int fme_probe(struct platform_device *pdev) ...@@ -198,10 +232,14 @@ static int fme_probe(struct platform_device *pdev)
{ {
int ret; int ret;
ret = dfl_fpga_dev_feature_init(pdev, fme_feature_drvs); ret = fme_dev_init(pdev);
if (ret) if (ret)
goto exit; 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); ret = dfl_fpga_dev_ops_register(pdev, &fme_fops, THIS_MODULE);
if (ret) if (ret)
goto feature_uinit; goto feature_uinit;
...@@ -210,6 +248,8 @@ static int fme_probe(struct platform_device *pdev) ...@@ -210,6 +248,8 @@ static int fme_probe(struct platform_device *pdev)
feature_uinit: feature_uinit:
dfl_fpga_dev_feature_uinit(pdev); dfl_fpga_dev_feature_uinit(pdev);
dev_destroy:
fme_dev_destroy(pdev);
exit: exit:
return ret; return ret;
} }
...@@ -218,6 +258,7 @@ static int fme_remove(struct platform_device *pdev) ...@@ -218,6 +258,7 @@ static int fme_remove(struct platform_device *pdev)
{ {
dfl_fpga_dev_ops_unregister(pdev); dfl_fpga_dev_ops_unregister(pdev);
dfl_fpga_dev_feature_uinit(pdev); dfl_fpga_dev_feature_uinit(pdev);
fme_dev_destroy(pdev);
return 0; return 0;
} }
......
This diff is collapsed.
/* 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@intel.com>
* Xiao Guangrong <guangrong.xiao@linux.intel.com>
* Wu Hao <hao.wu@intel.com>
* Joseph Grecco <joe.grecco@intel.com>
* Enno Luebbers <enno.luebbers@intel.com>
* Tim Whisonant <tim.whisonant@intel.com>
* Ananda Ravuri <ananda.ravuri@intel.com>
* Henry Mitchel <henry.mitchel@intel.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 */
/* 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@intel.com>
* Xiao Guangrong <guangrong.xiao@linux.intel.com>
* Wu Hao <hao.wu@intel.com>
* Joseph Grecco <joe.grecco@intel.com>
* Enno Luebbers <enno.luebbers@intel.com>
* Tim Whisonant <tim.whisonant@intel.com>
* Ananda Ravuri <ananda.ravuri@intel.com>
* Henry Mitchel <henry.mitchel@intel.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: linked list of FME's FPGA regions.
* @bridge_list: linked 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 */
...@@ -14,6 +14,7 @@ ...@@ -14,6 +14,7 @@
#ifndef _UAPI_LINUX_FPGA_DFL_H #ifndef _UAPI_LINUX_FPGA_DFL_H
#define _UAPI_LINUX_FPGA_DFL_H #define _UAPI_LINUX_FPGA_DFL_H
#include <linux/types.h>
#include <linux/ioctl.h> #include <linux/ioctl.h>
#define DFL_FPGA_API_VERSION 0 #define DFL_FPGA_API_VERSION 0
...@@ -28,6 +29,7 @@ ...@@ -28,6 +29,7 @@
#define DFL_FPGA_MAGIC 0xB6 #define DFL_FPGA_MAGIC 0xB6
#define DFL_FPGA_BASE 0 #define DFL_FPGA_BASE 0
#define DFL_FME_BASE 0x80
/** /**
* DFL_FPGA_GET_API_VERSION - _IO(DFL_FPGA_MAGIC, DFL_FPGA_BASE + 0) * DFL_FPGA_GET_API_VERSION - _IO(DFL_FPGA_MAGIC, DFL_FPGA_BASE + 0)
...@@ -47,4 +49,29 @@ ...@@ -47,4 +49,29 @@
#define DFL_FPGA_CHECK_EXTENSION _IO(DFL_FPGA_MAGIC, DFL_FPGA_BASE + 1) #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 */ #endif /* _UAPI_LINUX_FPGA_DFL_H */
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment