| From 8de4c0a64c59bf7465f451e96fc28e9df24ff797 Mon Sep 17 00:00:00 2001 |
| From: Wu Hao <hao.wu@intel.com> |
| Date: Sat, 30 Jun 2018 08:53:32 +0800 |
| Subject: [PATCH 1726/1795] fpga: dfl: afu: add header sub feature support |
| |
| The port header register set is always present for port, it is mainly |
| for capability, control and status of the ports that AFU connected to. |
| |
| This patch implements header sub feature support. Below user interfaces |
| are created by this patch. |
| |
| Sysfs interface: |
| * /sys/class/fpga_region/<regionX>/<dfl-port.x>/id |
| Read-only. Port ID. |
| |
| Ioctl interface: |
| * DFL_FPGA_PORT_RESET |
| Reset the FPGA Port and its AFU. |
| |
| Signed-off-by: Tim Whisonant <tim.whisonant@intel.com> |
| Signed-off-by: Enno Luebbers <enno.luebbers@intel.com> |
| Signed-off-by: Shiva Rao <shiva.rao@intel.com> |
| Signed-off-by: Christopher Rauer <christopher.rauer@intel.com> |
| Signed-off-by: Xiao Guangrong <guangrong.xiao@linux.intel.com> |
| Signed-off-by: Wu Hao <hao.wu@intel.com> |
| Acked-by: Alan Tull <atull@kernel.org> |
| Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org> |
| (cherry picked from commit e4664c0ee4ac44993c62d10b048ab0a960691da5) |
| Signed-off-by: Geert Uytterhoeven <geert+renesas@glider.be> |
| --- |
| .../ABI/testing/sysfs-platform-dfl-port | 7 ++ |
| drivers/fpga/dfl-afu-main.c | 79 ++++++++++++++++++- |
| include/uapi/linux/fpga-dfl.h | 17 ++++ |
| 3 files changed, 102 insertions(+), 1 deletion(-) |
| create mode 100644 Documentation/ABI/testing/sysfs-platform-dfl-port |
| |
| diff --git a/Documentation/ABI/testing/sysfs-platform-dfl-port b/Documentation/ABI/testing/sysfs-platform-dfl-port |
| new file mode 100644 |
| index 000000000000..cb91165f5397 |
| --- /dev/null |
| +++ b/Documentation/ABI/testing/sysfs-platform-dfl-port |
| @@ -0,0 +1,7 @@ |
| +What: /sys/bus/platform/devices/dfl-port.0/id |
| +Date: June 2018 |
| +KernelVersion: 4.19 |
| +Contact: Wu Hao <hao.wu@intel.com> |
| +Description: Read-only. It returns id of this port. One DFL FPGA device |
| + may have more than one port. Userspace could use this id to |
| + distinguish different ports under same FPGA device. |
| diff --git a/drivers/fpga/dfl-afu-main.c b/drivers/fpga/dfl-afu-main.c |
| index a38d6a825e7e..d36b3e9f3984 100644 |
| --- a/drivers/fpga/dfl-afu-main.c |
| +++ b/drivers/fpga/dfl-afu-main.c |
| @@ -16,6 +16,7 @@ |
| |
| #include <linux/kernel.h> |
| #include <linux/module.h> |
| +#include <linux/fpga-dfl.h> |
| |
| #include "dfl.h" |
| |
| @@ -87,6 +88,41 @@ static int port_disable(struct platform_device *pdev) |
| return 0; |
| } |
| |
| +/* |
| + * This function resets the FPGA Port and its accelerator (AFU) by function |
| + * __port_disable and __port_enable (set port soft reset bit and then clear |
| + * it). Userspace can do Port reset at any time, e.g. during DMA or Partial |
| + * Reconfiguration. But it should never cause any system level issue, only |
| + * functional failure (e.g. DMA or PR operation failure) and be recoverable |
| + * from the failure. |
| + * |
| + * Note: the accelerator (AFU) is not accessible when its port is in reset |
| + * (disabled). Any attempts on MMIO access to AFU while in reset, will |
| + * result errors reported via port error reporting sub feature (if present). |
| + */ |
| +static int __port_reset(struct platform_device *pdev) |
| +{ |
| + int ret; |
| + |
| + ret = port_disable(pdev); |
| + if (!ret) |
| + port_enable(pdev); |
| + |
| + return ret; |
| +} |
| + |
| +static int port_reset(struct platform_device *pdev) |
| +{ |
| + struct dfl_feature_platform_data *pdata = dev_get_platdata(&pdev->dev); |
| + int ret; |
| + |
| + mutex_lock(&pdata->lock); |
| + ret = __port_reset(pdev); |
| + mutex_unlock(&pdata->lock); |
| + |
| + return ret; |
| +} |
| + |
| static int port_get_id(struct platform_device *pdev) |
| { |
| void __iomem *base; |
| @@ -96,23 +132,63 @@ static int port_get_id(struct platform_device *pdev) |
| return FIELD_GET(PORT_CAP_PORT_NUM, readq(base + PORT_HDR_CAP)); |
| } |
| |
| +static ssize_t |
| +id_show(struct device *dev, struct device_attribute *attr, char *buf) |
| +{ |
| + int id = port_get_id(to_platform_device(dev)); |
| + |
| + return scnprintf(buf, PAGE_SIZE, "%d\n", id); |
| +} |
| +static DEVICE_ATTR_RO(id); |
| + |
| +static const struct attribute *port_hdr_attrs[] = { |
| + &dev_attr_id.attr, |
| + NULL, |
| +}; |
| + |
| static int port_hdr_init(struct platform_device *pdev, |
| struct dfl_feature *feature) |
| { |
| dev_dbg(&pdev->dev, "PORT HDR Init.\n"); |
| |
| - return 0; |
| + port_reset(pdev); |
| + |
| + return sysfs_create_files(&pdev->dev.kobj, port_hdr_attrs); |
| } |
| |
| static void port_hdr_uinit(struct platform_device *pdev, |
| struct dfl_feature *feature) |
| { |
| dev_dbg(&pdev->dev, "PORT HDR UInit.\n"); |
| + |
| + sysfs_remove_files(&pdev->dev.kobj, port_hdr_attrs); |
| +} |
| + |
| +static long |
| +port_hdr_ioctl(struct platform_device *pdev, struct dfl_feature *feature, |
| + unsigned int cmd, unsigned long arg) |
| +{ |
| + long ret; |
| + |
| + switch (cmd) { |
| + case DFL_FPGA_PORT_RESET: |
| + if (!arg) |
| + ret = port_reset(pdev); |
| + else |
| + ret = -EINVAL; |
| + break; |
| + default: |
| + dev_dbg(&pdev->dev, "%x cmd not handled", cmd); |
| + ret = -ENODEV; |
| + } |
| + |
| + return ret; |
| } |
| |
| static const struct dfl_feature_ops port_hdr_ops = { |
| .init = port_hdr_init, |
| .uinit = port_hdr_uinit, |
| + .ioctl = port_hdr_ioctl, |
| }; |
| |
| static struct dfl_feature_driver port_feature_drvs[] = { |
| @@ -154,6 +230,7 @@ static int afu_release(struct inode *inode, struct file *filp) |
| |
| pdata = dev_get_platdata(&pdev->dev); |
| |
| + port_reset(pdev); |
| dfl_feature_dev_use_end(pdata); |
| |
| return 0; |
| diff --git a/include/uapi/linux/fpga-dfl.h b/include/uapi/linux/fpga-dfl.h |
| index 9666af85a8f5..e6b4dd26cc68 100644 |
| --- a/include/uapi/linux/fpga-dfl.h |
| +++ b/include/uapi/linux/fpga-dfl.h |
| @@ -29,8 +29,11 @@ |
| #define DFL_FPGA_MAGIC 0xB6 |
| |
| #define DFL_FPGA_BASE 0 |
| +#define DFL_PORT_BASE 0x40 |
| #define DFL_FME_BASE 0x80 |
| |
| +/* Common IOCTLs for both FME and AFU file descriptor */ |
| + |
| /** |
| * DFL_FPGA_GET_API_VERSION - _IO(DFL_FPGA_MAGIC, DFL_FPGA_BASE + 0) |
| * |
| @@ -49,6 +52,20 @@ |
| |
| #define DFL_FPGA_CHECK_EXTENSION _IO(DFL_FPGA_MAGIC, DFL_FPGA_BASE + 1) |
| |
| +/* IOCTLs for AFU file descriptor */ |
| + |
| +/** |
| + * DFL_FPGA_PORT_RESET - _IO(DFL_FPGA_MAGIC, DFL_PORT_BASE + 0) |
| + * |
| + * Reset the FPGA Port and its AFU. No parameters are supported. |
| + * Userspace can do Port reset at any time, e.g. during DMA or PR. But |
| + * it should never cause any system level issue, only functional failure |
| + * (e.g. DMA or PR operation failure) and be recoverable from the failure. |
| + * Return: 0 on success, -errno of failure |
| + */ |
| + |
| +#define DFL_FPGA_PORT_RESET _IO(DFL_FPGA_MAGIC, DFL_PORT_BASE + 0) |
| + |
| /* IOCTLs for FME file descriptor */ |
| |
| /** |
| -- |
| 2.19.0 |
| |