From 543be3d8c999b30e1e1c05d30c1ea3f2d922340b Mon Sep 17 00:00:00 2001 From: Wu Hao Date: Sat, 30 Jun 2018 08:53:13 +0800 Subject: fpga: add device feature list support Device Feature List (DFL) defines a feature list structure that creates a linked list of feature headers within the MMIO space to provide an extensible way of adding features. This patch introduces a kernel module to provide basic infrastructure to support FPGA devices which implement the Device Feature List. Usually there will be different features and their sub features linked into the DFL. This code provides common APIs for feature enumeration, it creates a container device (FPGA base region), walks through the DFLs and creates platform devices for feature devices (Currently it only supports two different feature devices, FPGA Management Engine (FME) and Port which the Accelerator Function Unit (AFU) connected to). In order to enumerate the DFLs, the common APIs required low level driver to provide necessary enumeration information (e.g. address for each device feature list for given device) and fill it to the dfl_fpga_enum_info data structure. Please refer to below description for APIs added for enumeration. Functions for enumeration information preparation: *dfl_fpga_enum_info_alloc allocate enumeration information data structure. *dfl_fpga_enum_info_add_dfl add a device feature list to dfl_fpga_enum_info data structure. *dfl_fpga_enum_info_free free dfl_fpga_enum_info data structure and related resources. Functions for feature device enumeration: *dfl_fpga_feature_devs_enumerate enumerate feature devices and return container device. *dfl_fpga_feature_devs_remove remove feature devices under given container device. Signed-off-by: Tim Whisonant Signed-off-by: Enno Luebbers Signed-off-by: Shiva Rao Signed-off-by: Christopher Rauer Signed-off-by: Zhang Yi Signed-off-by: Xiao Guangrong Signed-off-by: Wu Hao Acked-by: Alan Tull Signed-off-by: Greg Kroah-Hartman --- drivers/fpga/Kconfig | 16 ++++++++++++++++ 1 file changed, 16 insertions(+) (limited to 'drivers/fpga/Kconfig') diff --git a/drivers/fpga/Kconfig b/drivers/fpga/Kconfig index ee9c5420c47f..4880fd676a19 100644 --- a/drivers/fpga/Kconfig +++ b/drivers/fpga/Kconfig @@ -130,4 +130,20 @@ config OF_FPGA_REGION Support for loading FPGA images by applying a Device Tree overlay. +config FPGA_DFL + tristate "FPGA Device Feature List (DFL) support" + select FPGA_BRIDGE + select FPGA_REGION + help + Device Feature List (DFL) defines a feature list structure that + creates a linked list of feature headers within the MMIO space + to provide an extensible way of adding features for FPGA. + Driver can walk through the feature headers to enumerate feature + devices (e.g. FPGA Management Engine, Port and Accelerator + Function Unit) and their private features for target FPGA devices. + + Select this option to enable common support for Field-Programmable + Gate Array (FPGA) solutions which implement Device Feature List. + It provides enumeration APIs and feature device infrastructure. + endif # FPGA -- cgit v1.2.3 From 72ddd9f34040a49a221c0d5d1754061e007a10e6 Mon Sep 17 00:00:00 2001 From: Zhang Yi Date: Sat, 30 Jun 2018 08:53:19 +0800 Subject: fpga: add FPGA DFL PCIe device driver This patch implements the basic framework of the driver for FPGA PCIe device which implements the Device Feature List (DFL) in its MMIO space. This driver is verified on Intel(R) PCIe-based FPGA DFL devices, including both integrated (e.g. Intel Server Platform with In-package FPGA) and discrete (e.g. Intel FPGA PCIe Acceleration Cards) solutions. Signed-off-by: Tim Whisonant Signed-off-by: Enno Luebbers Signed-off-by: Shiva Rao Signed-off-by: Christopher Rauer Signed-off-by: Zhang Yi Signed-off-by: Xiao Guangrong Signed-off-by: Wu Hao Acked-by: Alan Tull Acked-by: Moritz Fischer Signed-off-by: Greg Kroah-Hartman --- drivers/fpga/Kconfig | 15 +++++++ drivers/fpga/Makefile | 3 ++ drivers/fpga/dfl-pci.c | 103 +++++++++++++++++++++++++++++++++++++++++++++++++ 3 files changed, 121 insertions(+) create mode 100644 drivers/fpga/dfl-pci.c (limited to 'drivers/fpga/Kconfig') diff --git a/drivers/fpga/Kconfig b/drivers/fpga/Kconfig index 4880fd676a19..f2659f10e92e 100644 --- a/drivers/fpga/Kconfig +++ b/drivers/fpga/Kconfig @@ -146,4 +146,19 @@ config FPGA_DFL Gate Array (FPGA) solutions which implement Device Feature List. It provides enumeration APIs and feature device infrastructure. +config FPGA_DFL_PCI + tristate "FPGA DFL PCIe Device Driver" + depends on PCI && FPGA_DFL + help + Select this option to enable PCIe driver for PCIe-based + Field-Programmable Gate Array (FPGA) solutions which implement + the Device Feature List (DFL). This driver provides interfaces + for userspace applications to configure, enumerate, open and access + FPGA accelerators on the FPGA DFL devices, enables system level + management functions such as FPGA partial reconfiguration, power + management and virtualization with DFL framework and DFL feature + device drivers. + + To compile this as a module, choose M here. + endif # FPGA diff --git a/drivers/fpga/Makefile b/drivers/fpga/Makefile index 7a7a11739e00..02e025398cd5 100644 --- a/drivers/fpga/Makefile +++ b/drivers/fpga/Makefile @@ -31,3 +31,6 @@ obj-$(CONFIG_OF_FPGA_REGION) += of-fpga-region.o # FPGA Device Feature List Support obj-$(CONFIG_FPGA_DFL) += dfl.o + +# Drivers for FPGAs which implement DFL +obj-$(CONFIG_FPGA_DFL_PCI) += dfl-pci.o diff --git a/drivers/fpga/dfl-pci.c b/drivers/fpga/dfl-pci.c new file mode 100644 index 000000000000..e1e1f0fbe98c --- /dev/null +++ b/drivers/fpga/dfl-pci.c @@ -0,0 +1,103 @@ +// SPDX-License-Identifier: GPL-2.0 +/* + * Driver for FPGA Device Feature List (DFL) PCIe device + * + * Copyright (C) 2017-2018 Intel Corporation, Inc. + * + * Authors: + * Zhang Yi + * Xiao Guangrong + * Joseph Grecco + * Enno Luebbers + * Tim Whisonant + * Ananda Ravuri + * Henry Mitchel + */ + +#include +#include +#include +#include +#include +#include +#include + +#define DRV_VERSION "0.8" +#define DRV_NAME "dfl-pci" + +/* PCI Device ID */ +#define PCIE_DEVICE_ID_PF_INT_5_X 0xBCBD +#define PCIE_DEVICE_ID_PF_INT_6_X 0xBCC0 +#define PCIE_DEVICE_ID_PF_DSC_1_X 0x09C4 +/* VF Device */ +#define PCIE_DEVICE_ID_VF_INT_5_X 0xBCBF +#define PCIE_DEVICE_ID_VF_INT_6_X 0xBCC1 +#define PCIE_DEVICE_ID_VF_DSC_1_X 0x09C5 + +static struct pci_device_id cci_pcie_id_tbl[] = { + {PCI_DEVICE(PCI_VENDOR_ID_INTEL, PCIE_DEVICE_ID_PF_INT_5_X),}, + {PCI_DEVICE(PCI_VENDOR_ID_INTEL, PCIE_DEVICE_ID_VF_INT_5_X),}, + {PCI_DEVICE(PCI_VENDOR_ID_INTEL, PCIE_DEVICE_ID_PF_INT_6_X),}, + {PCI_DEVICE(PCI_VENDOR_ID_INTEL, PCIE_DEVICE_ID_VF_INT_6_X),}, + {PCI_DEVICE(PCI_VENDOR_ID_INTEL, PCIE_DEVICE_ID_PF_DSC_1_X),}, + {PCI_DEVICE(PCI_VENDOR_ID_INTEL, PCIE_DEVICE_ID_VF_DSC_1_X),}, + {0,} +}; +MODULE_DEVICE_TABLE(pci, cci_pcie_id_tbl); + +static +int cci_pci_probe(struct pci_dev *pcidev, const struct pci_device_id *pcidevid) +{ + int ret; + + ret = pcim_enable_device(pcidev); + if (ret < 0) { + dev_err(&pcidev->dev, "Failed to enable device %d.\n", ret); + return ret; + } + + ret = pci_enable_pcie_error_reporting(pcidev); + if (ret && ret != -EINVAL) + dev_info(&pcidev->dev, "PCIE AER unavailable %d.\n", ret); + + pci_set_master(pcidev); + + if (!pci_set_dma_mask(pcidev, DMA_BIT_MASK(64))) { + ret = pci_set_consistent_dma_mask(pcidev, DMA_BIT_MASK(64)); + if (ret) + goto disable_error_report_exit; + } else if (!pci_set_dma_mask(pcidev, DMA_BIT_MASK(32))) { + ret = pci_set_consistent_dma_mask(pcidev, DMA_BIT_MASK(32)); + if (ret) + goto disable_error_report_exit; + } else { + ret = -EIO; + dev_err(&pcidev->dev, "No suitable DMA support available.\n"); + goto disable_error_report_exit; + } + + /* TODO: create and add the platform device per feature list */ + return 0; + +disable_error_report_exit: + pci_disable_pcie_error_reporting(pcidev); + return ret; +} + +static void cci_pci_remove(struct pci_dev *pcidev) +{ + pci_disable_pcie_error_reporting(pcidev); +} + +static struct pci_driver cci_pci_driver = { + .name = DRV_NAME, + .id_table = cci_pcie_id_tbl, + .probe = cci_pci_probe, + .remove = cci_pci_remove, +}; + +module_pci_driver(cci_pci_driver); + +MODULE_DESCRIPTION("FPGA DFL PCIe Device Driver"); +MODULE_AUTHOR("Intel Corporation"); +MODULE_LICENSE("GPL v2"); -- cgit v1.2.3 From 322ddebe54ae2b18c86a3bffb2b76bc5e67762ac Mon Sep 17 00:00:00 2001 From: Kang Luwei Date: Sat, 30 Jun 2018 08:53:21 +0800 Subject: fpga: dfl: add FPGA Management Engine driver basic framework The FPGA Management Engine (FME) provides power, thermal management, performance counters, partial reconfiguration and other functions. For each function, it is packaged into a private feature linked to the FME feature device in the 'Device Feature List'. It's a platform device created by DFL framework. This patch adds the basic framework of FME platform driver. It defines sub feature drivers to handle the different sub features, including init, uinit and ioctl. It also registers the file operations for the device file. Signed-off-by: Tim Whisonant Signed-off-by: Enno Luebbers Signed-off-by: Shiva Rao Signed-off-by: Christopher Rauer Signed-off-by: Kang Luwei Signed-off-by: Xiao Guangrong Signed-off-by: Wu Hao Acked-by: Alan Tull Acked-by: Moritz Fischer Signed-off-by: Greg Kroah-Hartman --- drivers/fpga/Kconfig | 10 +++ drivers/fpga/Makefile | 3 + drivers/fpga/dfl-fme-main.c | 158 ++++++++++++++++++++++++++++++++++++++++++++ 3 files changed, 171 insertions(+) create mode 100644 drivers/fpga/dfl-fme-main.c (limited to 'drivers/fpga/Kconfig') diff --git a/drivers/fpga/Kconfig b/drivers/fpga/Kconfig index f2659f10e92e..43803a10cdae 100644 --- a/drivers/fpga/Kconfig +++ b/drivers/fpga/Kconfig @@ -146,6 +146,16 @@ config FPGA_DFL Gate Array (FPGA) solutions which implement Device Feature List. It provides enumeration APIs and feature device infrastructure. +config FPGA_DFL_FME + tristate "FPGA DFL FME Driver" + depends on FPGA_DFL + help + The FPGA Management Engine (FME) is a feature device implemented + under Device Feature List (DFL) framework. Select this option to + enable the platform device driver for FME which implements all + FPGA platform level management features. There shall be one FME + per DFL based FPGA device. + config FPGA_DFL_PCI tristate "FPGA DFL PCIe Device Driver" depends on PCI && FPGA_DFL diff --git a/drivers/fpga/Makefile b/drivers/fpga/Makefile index 02e025398cd5..db11f340ba0f 100644 --- a/drivers/fpga/Makefile +++ b/drivers/fpga/Makefile @@ -31,6 +31,9 @@ obj-$(CONFIG_OF_FPGA_REGION) += of-fpga-region.o # FPGA Device Feature List Support obj-$(CONFIG_FPGA_DFL) += dfl.o +obj-$(CONFIG_FPGA_DFL_FME) += dfl-fme.o + +dfl-fme-objs := dfl-fme-main.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 new file mode 100644 index 000000000000..bdcfe951d939 --- /dev/null +++ b/drivers/fpga/dfl-fme-main.c @@ -0,0 +1,158 @@ +// SPDX-License-Identifier: GPL-2.0 +/* + * Driver for FPGA Management Engine (FME) + * + * Copyright (C) 2017-2018 Intel Corporation, Inc. + * + * Authors: + * Kang Luwei + * Xiao Guangrong + * Joseph Grecco + * Enno Luebbers + * Tim Whisonant + * Ananda Ravuri + * Henry Mitchel + */ + +#include +#include + +#include "dfl.h" + +static int fme_hdr_init(struct platform_device *pdev, + struct dfl_feature *feature) +{ + dev_dbg(&pdev->dev, "FME HDR Init.\n"); + + return 0; +} + +static void fme_hdr_uinit(struct platform_device *pdev, + struct dfl_feature *feature) +{ + dev_dbg(&pdev->dev, "FME HDR UInit.\n"); +} + +static const struct dfl_feature_ops fme_hdr_ops = { + .init = fme_hdr_init, + .uinit = fme_hdr_uinit, +}; + +static struct dfl_feature_driver fme_feature_drvs[] = { + { + .id = FME_FEATURE_ID_HEADER, + .ops = &fme_hdr_ops, + }, + { + .ops = NULL, + }, +}; + +static int fme_open(struct inode *inode, struct file *filp) +{ + struct platform_device *fdev = dfl_fpga_inode_to_feature_dev(inode); + struct dfl_feature_platform_data *pdata = dev_get_platdata(&fdev->dev); + int ret; + + if (WARN_ON(!pdata)) + return -ENODEV; + + ret = dfl_feature_dev_use_begin(pdata); + if (ret) + return ret; + + dev_dbg(&fdev->dev, "Device File Open\n"); + filp->private_data = pdata; + + return 0; +} + +static int fme_release(struct inode *inode, struct file *filp) +{ + struct dfl_feature_platform_data *pdata = filp->private_data; + struct platform_device *pdev = pdata->dev; + + dev_dbg(&pdev->dev, "Device File Release\n"); + dfl_feature_dev_use_end(pdata); + + return 0; +} + +static long fme_ioctl(struct file *filp, unsigned int cmd, unsigned long arg) +{ + struct dfl_feature_platform_data *pdata = filp->private_data; + struct platform_device *pdev = pdata->dev; + struct dfl_feature *f; + long ret; + + dev_dbg(&pdev->dev, "%s cmd 0x%x\n", __func__, cmd); + + switch (cmd) { + default: + /* + * Let sub-feature's ioctl function to handle the cmd. + * Sub-feature's ioctl returns -ENODEV when cmd is not + * handled in this sub feature, and returns 0 or other + * error code if cmd is handled. + */ + dfl_fpga_dev_for_each_feature(pdata, f) { + if (f->ops && f->ops->ioctl) { + ret = f->ops->ioctl(pdev, f, cmd, arg); + if (ret != -ENODEV) + return ret; + } + } + } + + return -EINVAL; +} + +static const struct file_operations fme_fops = { + .owner = THIS_MODULE, + .open = fme_open, + .release = fme_release, + .unlocked_ioctl = fme_ioctl, +}; + +static int fme_probe(struct platform_device *pdev) +{ + int ret; + + ret = dfl_fpga_dev_feature_init(pdev, fme_feature_drvs); + if (ret) + goto exit; + + ret = dfl_fpga_dev_ops_register(pdev, &fme_fops, THIS_MODULE); + if (ret) + goto feature_uinit; + + return 0; + +feature_uinit: + dfl_fpga_dev_feature_uinit(pdev); +exit: + return ret; +} + +static int fme_remove(struct platform_device *pdev) +{ + dfl_fpga_dev_ops_unregister(pdev); + dfl_fpga_dev_feature_uinit(pdev); + + return 0; +} + +static struct platform_driver fme_driver = { + .driver = { + .name = DFL_FPGA_FEATURE_DEV_FME, + }, + .probe = fme_probe, + .remove = fme_remove, +}; + +module_platform_driver(fme_driver); + +MODULE_DESCRIPTION("FPGA Management Engine driver"); +MODULE_AUTHOR("Intel Corporation"); +MODULE_LICENSE("GPL v2"); +MODULE_ALIAS("platform:dfl-fme"); -- cgit v1.2.3 From af275ec6160ba68714371cfe0575f9aa478ce02f Mon Sep 17 00:00:00 2001 From: Wu Hao Date: Sat, 30 Jun 2018 08:53:25 +0800 Subject: fpga: dfl: add fpga manager platform driver for FME This patch adds fpga manager driver for FPGA Management Engine (FME). It implements fpga_manager_ops for FPGA Partial Reconfiguration function. Signed-off-by: Tim Whisonant Signed-off-by: Enno Luebbers Signed-off-by: Shiva Rao Signed-off-by: Christopher Rauer Signed-off-by: Kang Luwei Signed-off-by: Xiao Guangrong Signed-off-by: Wu Hao Acked-by: Alan Tull Signed-off-by: Greg Kroah-Hartman --- drivers/fpga/Kconfig | 6 + drivers/fpga/Makefile | 1 + drivers/fpga/dfl-fme-mgr.c | 334 +++++++++++++++++++++++++++++++++++++++++++++ 3 files changed, 341 insertions(+) create mode 100644 drivers/fpga/dfl-fme-mgr.c (limited to 'drivers/fpga/Kconfig') diff --git a/drivers/fpga/Kconfig b/drivers/fpga/Kconfig index 43803a10cdae..46b48e5164db 100644 --- a/drivers/fpga/Kconfig +++ b/drivers/fpga/Kconfig @@ -156,6 +156,12 @@ config FPGA_DFL_FME FPGA platform level management features. There shall be one FME per DFL based FPGA device. +config FPGA_DFL_FME_MGR + tristate "FPGA DFL FME Manager Driver" + depends on FPGA_DFL_FME && HAS_IOMEM + help + Say Y to enable FPGA Manager driver for FPGA Management Engine. + config FPGA_DFL_PCI tristate "FPGA DFL PCIe Device Driver" depends on PCI && FPGA_DFL diff --git a/drivers/fpga/Makefile b/drivers/fpga/Makefile index fd334d40aa1c..23f41b02f894 100644 --- a/drivers/fpga/Makefile +++ b/drivers/fpga/Makefile @@ -32,6 +32,7 @@ obj-$(CONFIG_OF_FPGA_REGION) += of-fpga-region.o # FPGA Device Feature List Support obj-$(CONFIG_FPGA_DFL) += dfl.o obj-$(CONFIG_FPGA_DFL_FME) += dfl-fme.o +obj-$(CONFIG_FPGA_DFL_FME_MGR) += dfl-fme-mgr.o dfl-fme-objs := dfl-fme-main.o dfl-fme-pr.o diff --git a/drivers/fpga/dfl-fme-mgr.c b/drivers/fpga/dfl-fme-mgr.c new file mode 100644 index 000000000000..df843b51c663 --- /dev/null +++ b/drivers/fpga/dfl-fme-mgr.c @@ -0,0 +1,334 @@ +// SPDX-License-Identifier: GPL-2.0 +/* + * FPGA Manager Driver for FPGA Management Engine (FME) + * + * Copyright (C) 2017-2018 Intel Corporation, Inc. + * + * Authors: + * Kang Luwei + * Xiao Guangrong + * Wu Hao + * Joseph Grecco + * Enno Luebbers + * Tim Whisonant + * Ananda Ravuri + * Christopher Rauer + * Henry Mitchel + */ + +#include +#include +#include +#include +#include + +#include "dfl-fme-pr.h" + +/* FME Partial Reconfiguration Sub Feature Register Set */ +#define FME_PR_DFH 0x0 +#define FME_PR_CTRL 0x8 +#define FME_PR_STS 0x10 +#define FME_PR_DATA 0x18 +#define FME_PR_ERR 0x20 +#define FME_PR_INTFC_ID_H 0xA8 +#define FME_PR_INTFC_ID_L 0xB0 + +/* FME PR Control Register Bitfield */ +#define FME_PR_CTRL_PR_RST BIT_ULL(0) /* Reset PR engine */ +#define FME_PR_CTRL_PR_RSTACK BIT_ULL(4) /* Ack for PR engine reset */ +#define FME_PR_CTRL_PR_RGN_ID GENMASK_ULL(9, 7) /* PR Region ID */ +#define FME_PR_CTRL_PR_START BIT_ULL(12) /* Start to request PR service */ +#define FME_PR_CTRL_PR_COMPLETE BIT_ULL(13) /* PR data push completion */ + +/* FME PR Status Register Bitfield */ +/* Number of available entries in HW queue inside the PR engine. */ +#define FME_PR_STS_PR_CREDIT GENMASK_ULL(8, 0) +#define FME_PR_STS_PR_STS BIT_ULL(16) /* PR operation status */ +#define FME_PR_STS_PR_STS_IDLE 0 +#define FME_PR_STS_PR_CTRLR_STS GENMASK_ULL(22, 20) /* Controller status */ +#define FME_PR_STS_PR_HOST_STS GENMASK_ULL(27, 24) /* PR host status */ + +/* FME PR Data Register Bitfield */ +/* PR data from the raw-binary file. */ +#define FME_PR_DATA_PR_DATA_RAW GENMASK_ULL(32, 0) + +/* FME PR Error Register */ +/* PR Operation errors detected. */ +#define FME_PR_ERR_OPERATION_ERR BIT_ULL(0) +/* CRC error detected. */ +#define FME_PR_ERR_CRC_ERR BIT_ULL(1) +/* Incompatible PR bitstream detected. */ +#define FME_PR_ERR_INCOMPATIBLE_BS BIT_ULL(2) +/* PR data push protocol violated. */ +#define FME_PR_ERR_PROTOCOL_ERR BIT_ULL(3) +/* PR data fifo overflow error detected */ +#define FME_PR_ERR_FIFO_OVERFLOW BIT_ULL(4) + +#define PR_WAIT_TIMEOUT 8000000 +#define PR_HOST_STATUS_IDLE 0 + +struct fme_mgr_priv { + void __iomem *ioaddr; + u64 pr_error; +}; + +static u64 pr_error_to_mgr_status(u64 err) +{ + u64 status = 0; + + if (err & FME_PR_ERR_OPERATION_ERR) + status |= FPGA_MGR_STATUS_OPERATION_ERR; + if (err & FME_PR_ERR_CRC_ERR) + status |= FPGA_MGR_STATUS_CRC_ERR; + if (err & FME_PR_ERR_INCOMPATIBLE_BS) + status |= FPGA_MGR_STATUS_INCOMPATIBLE_IMAGE_ERR; + if (err & FME_PR_ERR_PROTOCOL_ERR) + status |= FPGA_MGR_STATUS_IP_PROTOCOL_ERR; + if (err & FME_PR_ERR_FIFO_OVERFLOW) + status |= FPGA_MGR_STATUS_FIFO_OVERFLOW_ERR; + + return status; +} + +static u64 fme_mgr_pr_error_handle(void __iomem *fme_pr) +{ + u64 pr_status, pr_error; + + pr_status = readq(fme_pr + FME_PR_STS); + if (!(pr_status & FME_PR_STS_PR_STS)) + return 0; + + pr_error = readq(fme_pr + FME_PR_ERR); + writeq(pr_error, fme_pr + FME_PR_ERR); + + return pr_error; +} + +static int fme_mgr_write_init(struct fpga_manager *mgr, + struct fpga_image_info *info, + const char *buf, size_t count) +{ + struct device *dev = &mgr->dev; + struct fme_mgr_priv *priv = mgr->priv; + void __iomem *fme_pr = priv->ioaddr; + u64 pr_ctrl, pr_status; + + if (!(info->flags & FPGA_MGR_PARTIAL_RECONFIG)) { + dev_err(dev, "only supports partial reconfiguration.\n"); + return -EINVAL; + } + + dev_dbg(dev, "resetting PR before initiated PR\n"); + + pr_ctrl = readq(fme_pr + FME_PR_CTRL); + pr_ctrl |= FME_PR_CTRL_PR_RST; + writeq(pr_ctrl, fme_pr + FME_PR_CTRL); + + if (readq_poll_timeout(fme_pr + FME_PR_CTRL, pr_ctrl, + pr_ctrl & FME_PR_CTRL_PR_RSTACK, 1, + PR_WAIT_TIMEOUT)) { + dev_err(dev, "PR Reset ACK timeout\n"); + return -ETIMEDOUT; + } + + pr_ctrl = readq(fme_pr + FME_PR_CTRL); + pr_ctrl &= ~FME_PR_CTRL_PR_RST; + writeq(pr_ctrl, fme_pr + FME_PR_CTRL); + + dev_dbg(dev, + "waiting for PR resource in HW to be initialized and ready\n"); + + if (readq_poll_timeout(fme_pr + FME_PR_STS, pr_status, + (pr_status & FME_PR_STS_PR_STS) == + FME_PR_STS_PR_STS_IDLE, 1, PR_WAIT_TIMEOUT)) { + dev_err(dev, "PR Status timeout\n"); + priv->pr_error = fme_mgr_pr_error_handle(fme_pr); + return -ETIMEDOUT; + } + + dev_dbg(dev, "check and clear previous PR error\n"); + priv->pr_error = fme_mgr_pr_error_handle(fme_pr); + if (priv->pr_error) + dev_dbg(dev, "previous PR error detected %llx\n", + (unsigned long long)priv->pr_error); + + dev_dbg(dev, "set PR port ID\n"); + + pr_ctrl = readq(fme_pr + FME_PR_CTRL); + pr_ctrl &= ~FME_PR_CTRL_PR_RGN_ID; + pr_ctrl |= FIELD_PREP(FME_PR_CTRL_PR_RGN_ID, info->region_id); + writeq(pr_ctrl, fme_pr + FME_PR_CTRL); + + return 0; +} + +static int fme_mgr_write(struct fpga_manager *mgr, + const char *buf, size_t count) +{ + struct device *dev = &mgr->dev; + struct fme_mgr_priv *priv = mgr->priv; + void __iomem *fme_pr = priv->ioaddr; + u64 pr_ctrl, pr_status, pr_data; + int delay = 0, pr_credit, i = 0; + + dev_dbg(dev, "start request\n"); + + pr_ctrl = readq(fme_pr + FME_PR_CTRL); + pr_ctrl |= FME_PR_CTRL_PR_START; + writeq(pr_ctrl, fme_pr + FME_PR_CTRL); + + dev_dbg(dev, "pushing data from bitstream to HW\n"); + + /* + * driver can push data to PR hardware using PR_DATA register once HW + * has enough pr_credit (> 1), pr_credit reduces one for every 32bit + * pr data write to PR_DATA register. If pr_credit <= 1, driver needs + * to wait for enough pr_credit from hardware by polling. + */ + pr_status = readq(fme_pr + FME_PR_STS); + pr_credit = FIELD_GET(FME_PR_STS_PR_CREDIT, pr_status); + + while (count > 0) { + while (pr_credit <= 1) { + if (delay++ > PR_WAIT_TIMEOUT) { + dev_err(dev, "PR_CREDIT timeout\n"); + return -ETIMEDOUT; + } + udelay(1); + + pr_status = readq(fme_pr + FME_PR_STS); + pr_credit = FIELD_GET(FME_PR_STS_PR_CREDIT, pr_status); + } + + if (count < 4) { + dev_err(dev, "Invaild PR bitstream size\n"); + return -EINVAL; + } + + pr_data = 0; + pr_data |= FIELD_PREP(FME_PR_DATA_PR_DATA_RAW, + *(((u32 *)buf) + i)); + writeq(pr_data, fme_pr + FME_PR_DATA); + count -= 4; + pr_credit--; + i++; + } + + return 0; +} + +static int fme_mgr_write_complete(struct fpga_manager *mgr, + struct fpga_image_info *info) +{ + struct device *dev = &mgr->dev; + struct fme_mgr_priv *priv = mgr->priv; + void __iomem *fme_pr = priv->ioaddr; + u64 pr_ctrl; + + pr_ctrl = readq(fme_pr + FME_PR_CTRL); + pr_ctrl |= FME_PR_CTRL_PR_COMPLETE; + writeq(pr_ctrl, fme_pr + FME_PR_CTRL); + + dev_dbg(dev, "green bitstream push complete\n"); + dev_dbg(dev, "waiting for HW to release PR resource\n"); + + if (readq_poll_timeout(fme_pr + FME_PR_CTRL, pr_ctrl, + !(pr_ctrl & FME_PR_CTRL_PR_START), 1, + PR_WAIT_TIMEOUT)) { + dev_err(dev, "PR Completion ACK timeout.\n"); + return -ETIMEDOUT; + } + + dev_dbg(dev, "PR operation complete, checking status\n"); + priv->pr_error = fme_mgr_pr_error_handle(fme_pr); + if (priv->pr_error) { + dev_dbg(dev, "PR error detected %llx\n", + (unsigned long long)priv->pr_error); + return -EIO; + } + + dev_dbg(dev, "PR done successfully\n"); + + return 0; +} + +static enum fpga_mgr_states fme_mgr_state(struct fpga_manager *mgr) +{ + return FPGA_MGR_STATE_UNKNOWN; +} + +static u64 fme_mgr_status(struct fpga_manager *mgr) +{ + struct fme_mgr_priv *priv = mgr->priv; + + return pr_error_to_mgr_status(priv->pr_error); +} + +static const struct fpga_manager_ops fme_mgr_ops = { + .write_init = fme_mgr_write_init, + .write = fme_mgr_write, + .write_complete = fme_mgr_write_complete, + .state = fme_mgr_state, + .status = fme_mgr_status, +}; + +static int fme_mgr_probe(struct platform_device *pdev) +{ + struct dfl_fme_mgr_pdata *pdata = dev_get_platdata(&pdev->dev); + struct device *dev = &pdev->dev; + struct fme_mgr_priv *priv; + struct fpga_manager *mgr; + struct resource *res; + int ret; + + priv = devm_kzalloc(dev, sizeof(*priv), GFP_KERNEL); + if (!priv) + return -ENOMEM; + + if (pdata->ioaddr) + priv->ioaddr = pdata->ioaddr; + + if (!priv->ioaddr) { + res = platform_get_resource(pdev, IORESOURCE_MEM, 0); + priv->ioaddr = devm_ioremap_resource(dev, res); + if (IS_ERR(priv->ioaddr)) + return PTR_ERR(priv->ioaddr); + } + + mgr = fpga_mgr_create(dev, "DFL FME FPGA Manager", + &fme_mgr_ops, priv); + if (!mgr) + return -ENOMEM; + + platform_set_drvdata(pdev, mgr); + + ret = fpga_mgr_register(mgr); + if (ret) + fpga_mgr_free(mgr); + + return ret; +} + +static int fme_mgr_remove(struct platform_device *pdev) +{ + struct fpga_manager *mgr = platform_get_drvdata(pdev); + + fpga_mgr_unregister(mgr); + + return 0; +} + +static struct platform_driver fme_mgr_driver = { + .driver = { + .name = DFL_FPGA_FME_MGR, + }, + .probe = fme_mgr_probe, + .remove = fme_mgr_remove, +}; + +module_platform_driver(fme_mgr_driver); + +MODULE_DESCRIPTION("FPGA Manager for DFL FPGA Management Engine"); +MODULE_AUTHOR("Intel Corporation"); +MODULE_LICENSE("GPL v2"); +MODULE_ALIAS("platform:dfl-fme-mgr"); -- cgit v1.2.3 From de892dff17b36d138ff41aeb46366d7c1ed4cd77 Mon Sep 17 00:00:00 2001 From: Wu Hao Date: Sat, 30 Jun 2018 08:53:27 +0800 Subject: fpga: dfl: add fpga bridge platform driver for FME This patch adds fpga bridge platform driver for FPGA Management Engine. It implements the enable_set callback for fpga bridge. Signed-off-by: Tim Whisonant Signed-off-by: Enno Luebbers Signed-off-by: Shiva Rao Signed-off-by: Christopher Rauer Signed-off-by: Wu Hao Acked-by: Alan Tull Acked-by: Moritz Fischer Signed-off-by: Greg Kroah-Hartman --- drivers/fpga/Kconfig | 6 +++ drivers/fpga/Makefile | 1 + drivers/fpga/dfl-fme-br.c | 114 ++++++++++++++++++++++++++++++++++++++++++++++ 3 files changed, 121 insertions(+) create mode 100644 drivers/fpga/dfl-fme-br.c (limited to 'drivers/fpga/Kconfig') diff --git a/drivers/fpga/Kconfig b/drivers/fpga/Kconfig index 46b48e5164db..11d1943b91d4 100644 --- a/drivers/fpga/Kconfig +++ b/drivers/fpga/Kconfig @@ -162,6 +162,12 @@ config FPGA_DFL_FME_MGR help Say Y to enable FPGA Manager driver for FPGA Management Engine. +config FPGA_DFL_FME_BRIDGE + tristate "FPGA DFL FME Bridge Driver" + depends on FPGA_DFL_FME && HAS_IOMEM + help + Say Y to enable FPGA Bridge driver for FPGA Management Engine. + config FPGA_DFL_PCI tristate "FPGA DFL PCIe Device Driver" depends on PCI && FPGA_DFL diff --git a/drivers/fpga/Makefile b/drivers/fpga/Makefile index 23f41b02f894..cda05515ebfd 100644 --- a/drivers/fpga/Makefile +++ b/drivers/fpga/Makefile @@ -33,6 +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 obj-$(CONFIG_FPGA_DFL_FME_MGR) += dfl-fme-mgr.o +obj-$(CONFIG_FPGA_DFL_FME_BRIDGE) += dfl-fme-br.o dfl-fme-objs := dfl-fme-main.o dfl-fme-pr.o diff --git a/drivers/fpga/dfl-fme-br.c b/drivers/fpga/dfl-fme-br.c new file mode 100644 index 000000000000..7cc041def8b3 --- /dev/null +++ b/drivers/fpga/dfl-fme-br.c @@ -0,0 +1,114 @@ +// SPDX-License-Identifier: GPL-2.0 +/* + * FPGA Bridge Driver for FPGA Management Engine (FME) + * + * Copyright (C) 2017-2018 Intel Corporation, Inc. + * + * Authors: + * Wu Hao + * Joseph Grecco + * Enno Luebbers + * Tim Whisonant + * Ananda Ravuri + * Henry Mitchel + */ + +#include +#include + +#include "dfl.h" +#include "dfl-fme-pr.h" + +struct fme_br_priv { + struct dfl_fme_br_pdata *pdata; + struct dfl_fpga_port_ops *port_ops; + struct platform_device *port_pdev; +}; + +static int fme_bridge_enable_set(struct fpga_bridge *bridge, bool enable) +{ + struct fme_br_priv *priv = bridge->priv; + struct platform_device *port_pdev; + struct dfl_fpga_port_ops *ops; + + if (!priv->port_pdev) { + port_pdev = dfl_fpga_cdev_find_port(priv->pdata->cdev, + &priv->pdata->port_id, + dfl_fpga_check_port_id); + if (!port_pdev) + return -ENODEV; + + priv->port_pdev = port_pdev; + } + + if (priv->port_pdev && !priv->port_ops) { + ops = dfl_fpga_port_ops_get(priv->port_pdev); + if (!ops || !ops->enable_set) + return -ENOENT; + + priv->port_ops = ops; + } + + return priv->port_ops->enable_set(priv->port_pdev, enable); +} + +static const struct fpga_bridge_ops fme_bridge_ops = { + .enable_set = fme_bridge_enable_set, +}; + +static int fme_br_probe(struct platform_device *pdev) +{ + struct device *dev = &pdev->dev; + struct fme_br_priv *priv; + struct fpga_bridge *br; + int ret; + + priv = devm_kzalloc(dev, sizeof(*priv), GFP_KERNEL); + if (!priv) + return -ENOMEM; + + priv->pdata = dev_get_platdata(dev); + + br = fpga_bridge_create(dev, "DFL FPGA FME Bridge", + &fme_bridge_ops, priv); + if (!br) + return -ENOMEM; + + platform_set_drvdata(pdev, br); + + ret = fpga_bridge_register(br); + if (ret) + fpga_bridge_free(br); + + return ret; +} + +static int fme_br_remove(struct platform_device *pdev) +{ + struct fpga_bridge *br = platform_get_drvdata(pdev); + struct fme_br_priv *priv = br->priv; + + fpga_bridge_unregister(br); + + if (priv->port_pdev) + put_device(&priv->port_pdev->dev); + if (priv->port_ops) + dfl_fpga_port_ops_put(priv->port_ops); + + return 0; +} + +static struct platform_driver fme_br_driver = { + .driver = { + .name = DFL_FPGA_FME_BRIDGE, + }, + .probe = fme_br_probe, + .remove = fme_br_remove, +}; + +module_platform_driver(fme_br_driver); + +MODULE_DESCRIPTION("FPGA Bridge for DFL FPGA Management Engine"); +MODULE_AUTHOR("Intel Corporation"); +MODULE_LICENSE("GPL v2"); +MODULE_ALIAS("platform:dfl-fme-bridge"); -- cgit v1.2.3 From bb61b9be3e6b001f1571b230316bf3867dc41df3 Mon Sep 17 00:00:00 2001 From: Wu Hao Date: Sat, 30 Jun 2018 08:53:28 +0800 Subject: fpga: dfl: add fpga region platform driver for FME This patch adds fpga region platform driver for FPGA Management Engine. It register an fpga region with given fpga manager / bridge device. Signed-off-by: Tim Whisonant Signed-off-by: Enno Luebbers Signed-off-by: Shiva Rao Signed-off-by: Christopher Rauer Signed-off-by: Wu Hao Acked-by: Alan Tull Acked-by: Moritz Fischer Signed-off-by: Greg Kroah-Hartman --- drivers/fpga/Kconfig | 6 +++ drivers/fpga/Makefile | 1 + drivers/fpga/dfl-fme-region.c | 88 +++++++++++++++++++++++++++++++++++++++++++ 3 files changed, 95 insertions(+) create mode 100644 drivers/fpga/dfl-fme-region.c (limited to 'drivers/fpga/Kconfig') diff --git a/drivers/fpga/Kconfig b/drivers/fpga/Kconfig index 11d1943b91d4..f99f422feec9 100644 --- a/drivers/fpga/Kconfig +++ b/drivers/fpga/Kconfig @@ -168,6 +168,12 @@ config FPGA_DFL_FME_BRIDGE help Say Y to enable FPGA Bridge driver for FPGA Management Engine. +config FPGA_DFL_FME_REGION + tristate "FPGA DFL FME Region Driver" + depends on FPGA_DFL_FME && HAS_IOMEM + help + Say Y to enable FPGA Region driver for FPGA Management Engine. + config FPGA_DFL_PCI tristate "FPGA DFL PCIe Device Driver" depends on PCI && FPGA_DFL diff --git a/drivers/fpga/Makefile b/drivers/fpga/Makefile index cda05515ebfd..637c27512c28 100644 --- a/drivers/fpga/Makefile +++ b/drivers/fpga/Makefile @@ -34,6 +34,7 @@ obj-$(CONFIG_FPGA_DFL) += dfl.o obj-$(CONFIG_FPGA_DFL_FME) += dfl-fme.o obj-$(CONFIG_FPGA_DFL_FME_MGR) += dfl-fme-mgr.o obj-$(CONFIG_FPGA_DFL_FME_BRIDGE) += dfl-fme-br.o +obj-$(CONFIG_FPGA_DFL_FME_REGION) += dfl-fme-region.o dfl-fme-objs := dfl-fme-main.o dfl-fme-pr.o diff --git a/drivers/fpga/dfl-fme-region.c b/drivers/fpga/dfl-fme-region.c new file mode 100644 index 000000000000..a6e0bde7cc31 --- /dev/null +++ b/drivers/fpga/dfl-fme-region.c @@ -0,0 +1,88 @@ +// SPDX-License-Identifier: GPL-2.0 +/* + * FPGA Region Driver for FPGA Management Engine (FME) + * + * Copyright (C) 2017-2018 Intel Corporation, Inc. + * + * Authors: + * Wu Hao + * Joseph Grecco + * Enno Luebbers + * Tim Whisonant + * Ananda Ravuri + * Henry Mitchel + */ + +#include +#include + +#include "dfl-fme-pr.h" + +static int fme_region_get_bridges(struct fpga_region *region) +{ + struct dfl_fme_region_pdata *pdata = region->priv; + struct device *dev = &pdata->br->dev; + + return fpga_bridge_get_to_list(dev, region->info, ®ion->bridge_list); +} + +static int fme_region_probe(struct platform_device *pdev) +{ + struct dfl_fme_region_pdata *pdata = dev_get_platdata(&pdev->dev); + struct device *dev = &pdev->dev; + struct fpga_region *region; + struct fpga_manager *mgr; + int ret; + + mgr = fpga_mgr_get(&pdata->mgr->dev); + if (IS_ERR(mgr)) + return -EPROBE_DEFER; + + region = fpga_region_create(dev, mgr, fme_region_get_bridges); + if (!region) { + ret = -ENOMEM; + goto eprobe_mgr_put; + } + + region->priv = pdata; + platform_set_drvdata(pdev, region); + + ret = fpga_region_register(region); + if (ret) + goto region_free; + + dev_dbg(dev, "DFL FME FPGA Region probed\n"); + + return 0; + +region_free: + fpga_region_free(region); +eprobe_mgr_put: + fpga_mgr_put(mgr); + return ret; +} + +static int fme_region_remove(struct platform_device *pdev) +{ + struct fpga_region *region = dev_get_drvdata(&pdev->dev); + + fpga_region_unregister(region); + fpga_mgr_put(region->mgr); + + return 0; +} + +static struct platform_driver fme_region_driver = { + .driver = { + .name = DFL_FPGA_FME_REGION, + }, + .probe = fme_region_probe, + .remove = fme_region_remove, +}; + +module_platform_driver(fme_region_driver); + +MODULE_DESCRIPTION("FPGA Region for DFL FPGA Management Engine"); +MODULE_AUTHOR("Intel Corporation"); +MODULE_LICENSE("GPL v2"); +MODULE_ALIAS("platform:dfl-fme-region"); -- cgit v1.2.3 From 1a1527cf5ddacc6716a3cacfa232111d92ffd93b Mon Sep 17 00:00:00 2001 From: Wu Hao Date: Sat, 30 Jun 2018 08:53:30 +0800 Subject: fpga: dfl: add FPGA Accelerated Function Unit driver basic framework On DFL FPGA devices, the Accelerated Function Unit (AFU), can be reprogrammed for different functions. It connects to the FPGA infrastructure (static FPGA region) via a Port. Port CSRs are implemented separately from the AFU CSRs to provide control and status of the Port. Once valid PR bitstream is programmed into the AFU, it allows access to the AFU CSRs in the AFU MMIO space. This patch only implements basic driver framework for AFU, including device file operation framework. Signed-off-by: Tim Whisonant Signed-off-by: Enno Luebbers Signed-off-by: Shiva Rao Signed-off-by: Christopher Rauer Signed-off-by: Xiao Guangrong Signed-off-by: Wu Hao Acked-by: Alan Tull Signed-off-by: Greg Kroah-Hartman --- drivers/fpga/Kconfig | 9 +++ drivers/fpga/Makefile | 2 + drivers/fpga/dfl-afu-main.c | 162 ++++++++++++++++++++++++++++++++++++++++++++ 3 files changed, 173 insertions(+) create mode 100644 drivers/fpga/dfl-afu-main.c (limited to 'drivers/fpga/Kconfig') diff --git a/drivers/fpga/Kconfig b/drivers/fpga/Kconfig index f99f422feec9..1ebcef4bab5b 100644 --- a/drivers/fpga/Kconfig +++ b/drivers/fpga/Kconfig @@ -174,6 +174,15 @@ config FPGA_DFL_FME_REGION help Say Y to enable FPGA Region driver for FPGA Management Engine. +config FPGA_DFL_AFU + tristate "FPGA DFL AFU Driver" + depends on FPGA_DFL + help + This is the driver for FPGA Accelerated Function Unit (AFU) which + implements AFU and Port management features. A User AFU connects + to the FPGA infrastructure via a Port. There may be more than one + Port/AFU per DFL based FPGA device. + config FPGA_DFL_PCI tristate "FPGA DFL PCIe Device Driver" depends on PCI && FPGA_DFL diff --git a/drivers/fpga/Makefile b/drivers/fpga/Makefile index 637c27512c28..1ac7749b2542 100644 --- a/drivers/fpga/Makefile +++ b/drivers/fpga/Makefile @@ -35,8 +35,10 @@ obj-$(CONFIG_FPGA_DFL_FME) += dfl-fme.o obj-$(CONFIG_FPGA_DFL_FME_MGR) += dfl-fme-mgr.o obj-$(CONFIG_FPGA_DFL_FME_BRIDGE) += dfl-fme-br.o obj-$(CONFIG_FPGA_DFL_FME_REGION) += dfl-fme-region.o +obj-$(CONFIG_FPGA_DFL_AFU) += dfl-afu.o dfl-fme-objs := dfl-fme-main.o dfl-fme-pr.o +dfl-afu-objs := dfl-afu-main.o # Drivers for FPGAs which implement DFL obj-$(CONFIG_FPGA_DFL_PCI) += dfl-pci.o diff --git a/drivers/fpga/dfl-afu-main.c b/drivers/fpga/dfl-afu-main.c new file mode 100644 index 000000000000..08f88cdb3bfc --- /dev/null +++ b/drivers/fpga/dfl-afu-main.c @@ -0,0 +1,162 @@ +// SPDX-License-Identifier: GPL-2.0 +/* + * Driver for FPGA Accelerated Function Unit (AFU) + * + * Copyright (C) 2017-2018 Intel Corporation, Inc. + * + * Authors: + * Wu Hao + * Xiao Guangrong + * Joseph Grecco + * Enno Luebbers + * Tim Whisonant + * Ananda Ravuri + * Henry Mitchel + */ + +#include +#include + +#include "dfl.h" + +static int port_hdr_init(struct platform_device *pdev, + struct dfl_feature *feature) +{ + dev_dbg(&pdev->dev, "PORT HDR Init.\n"); + + return 0; +} + +static void port_hdr_uinit(struct platform_device *pdev, + struct dfl_feature *feature) +{ + dev_dbg(&pdev->dev, "PORT HDR UInit.\n"); +} + +static const struct dfl_feature_ops port_hdr_ops = { + .init = port_hdr_init, + .uinit = port_hdr_uinit, +}; + +static struct dfl_feature_driver port_feature_drvs[] = { + { + .id = PORT_FEATURE_ID_HEADER, + .ops = &port_hdr_ops, + }, + { + .ops = NULL, + } +}; + +static int afu_open(struct inode *inode, struct file *filp) +{ + struct platform_device *fdev = dfl_fpga_inode_to_feature_dev(inode); + struct dfl_feature_platform_data *pdata; + int ret; + + pdata = dev_get_platdata(&fdev->dev); + if (WARN_ON(!pdata)) + return -ENODEV; + + ret = dfl_feature_dev_use_begin(pdata); + if (ret) + return ret; + + dev_dbg(&fdev->dev, "Device File Open\n"); + filp->private_data = fdev; + + return 0; +} + +static int afu_release(struct inode *inode, struct file *filp) +{ + struct platform_device *pdev = filp->private_data; + struct dfl_feature_platform_data *pdata; + + dev_dbg(&pdev->dev, "Device File Release\n"); + + pdata = dev_get_platdata(&pdev->dev); + + dfl_feature_dev_use_end(pdata); + + return 0; +} + +static long afu_ioctl(struct file *filp, unsigned int cmd, unsigned long arg) +{ + struct platform_device *pdev = filp->private_data; + struct dfl_feature_platform_data *pdata; + struct dfl_feature *f; + long ret; + + dev_dbg(&pdev->dev, "%s cmd 0x%x\n", __func__, cmd); + + pdata = dev_get_platdata(&pdev->dev); + + switch (cmd) { + default: + /* + * Let sub-feature's ioctl function to handle the cmd + * Sub-feature's ioctl returns -ENODEV when cmd is not + * handled in this sub feature, and returns 0 and other + * error code if cmd is handled. + */ + dfl_fpga_dev_for_each_feature(pdata, f) + if (f->ops && f->ops->ioctl) { + ret = f->ops->ioctl(pdev, f, cmd, arg); + if (ret != -ENODEV) + return ret; + } + } + + return -EINVAL; +} + +static const struct file_operations afu_fops = { + .owner = THIS_MODULE, + .open = afu_open, + .release = afu_release, + .unlocked_ioctl = afu_ioctl, +}; + +static int afu_probe(struct platform_device *pdev) +{ + int ret; + + dev_dbg(&pdev->dev, "%s\n", __func__); + + ret = dfl_fpga_dev_feature_init(pdev, port_feature_drvs); + if (ret) + return ret; + + ret = dfl_fpga_dev_ops_register(pdev, &afu_fops, THIS_MODULE); + if (ret) + dfl_fpga_dev_feature_uinit(pdev); + + return ret; +} + +static int afu_remove(struct platform_device *pdev) +{ + dev_dbg(&pdev->dev, "%s\n", __func__); + + dfl_fpga_dev_ops_unregister(pdev); + dfl_fpga_dev_feature_uinit(pdev); + + return 0; +} + +static struct platform_driver afu_driver = { + .driver = { + .name = DFL_FPGA_FEATURE_DEV_PORT, + }, + .probe = afu_probe, + .remove = afu_remove, +}; + +module_platform_driver(afu_driver); + +MODULE_DESCRIPTION("FPGA Accelerated Function Unit driver"); +MODULE_AUTHOR("Intel Corporation"); +MODULE_LICENSE("GPL v2"); +MODULE_ALIAS("platform:dfl-port"); -- cgit v1.2.3