linux/drivers/fpga/dfl-fme-main.c
Wu Hao 620e1902f6 fpga: dfl: fme: add DFL_FPGA_GET_API_VERSION/CHECK_EXTENSION ioctls support
DFL_FPGA_GET_API_VERSION and DFL_FPGA_CHECK_EXTENSION ioctls are common
ones which need to be supported by all feature devices drivers including
FME and AFU. Userspace application can use these ioctl interfaces to get
the API info and check if specific extension is supported or not in
current driver.

This patch implements above 2 ioctls in FPGA Management Engine (FME)
driver.

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>
Acked-by: Moritz Fischer <mdf@kernel.org>
Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
2018-07-15 13:55:46 +02:00

239 lines
5.4 KiB
C

// SPDX-License-Identifier: GPL-2.0
/*
* Driver for FPGA Management Engine (FME)
*
* Copyright (C) 2017-2018 Intel Corporation, Inc.
*
* Authors:
* Kang Luwei <luwei.kang@intel.com>
* Xiao Guangrong <guangrong.xiao@linux.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>
*/
#include <linux/kernel.h>
#include <linux/module.h>
#include <linux/fpga-dfl.h>
#include "dfl.h"
static ssize_t ports_num_show(struct device *dev,
struct device_attribute *attr, char *buf)
{
void __iomem *base;
u64 v;
base = dfl_get_feature_ioaddr_by_id(dev, FME_FEATURE_ID_HEADER);
v = readq(base + FME_HDR_CAP);
return scnprintf(buf, PAGE_SIZE, "%u\n",
(unsigned int)FIELD_GET(FME_CAP_NUM_PORTS, v));
}
static DEVICE_ATTR_RO(ports_num);
/*
* Bitstream (static FPGA region) identifier number. It contains the
* detailed version and other information of this static FPGA region.
*/
static ssize_t bitstream_id_show(struct device *dev,
struct device_attribute *attr, char *buf)
{
void __iomem *base;
u64 v;
base = dfl_get_feature_ioaddr_by_id(dev, FME_FEATURE_ID_HEADER);
v = readq(base + FME_HDR_BITSTREAM_ID);
return scnprintf(buf, PAGE_SIZE, "0x%llx\n", (unsigned long long)v);
}
static DEVICE_ATTR_RO(bitstream_id);
/*
* Bitstream (static FPGA region) meta data. It contains the synthesis
* date, seed and other information of this static FPGA region.
*/
static ssize_t bitstream_metadata_show(struct device *dev,
struct device_attribute *attr, char *buf)
{
void __iomem *base;
u64 v;
base = dfl_get_feature_ioaddr_by_id(dev, FME_FEATURE_ID_HEADER);
v = readq(base + FME_HDR_BITSTREAM_MD);
return scnprintf(buf, PAGE_SIZE, "0x%llx\n", (unsigned long long)v);
}
static DEVICE_ATTR_RO(bitstream_metadata);
static const struct attribute *fme_hdr_attrs[] = {
&dev_attr_ports_num.attr,
&dev_attr_bitstream_id.attr,
&dev_attr_bitstream_metadata.attr,
NULL,
};
static int fme_hdr_init(struct platform_device *pdev,
struct dfl_feature *feature)
{
void __iomem *base = feature->ioaddr;
int ret;
dev_dbg(&pdev->dev, "FME HDR Init.\n");
dev_dbg(&pdev->dev, "FME cap %llx.\n",
(unsigned long long)readq(base + FME_HDR_CAP));
ret = sysfs_create_files(&pdev->dev.kobj, fme_hdr_attrs);
if (ret)
return ret;
return 0;
}
static void fme_hdr_uinit(struct platform_device *pdev,
struct dfl_feature *feature)
{
dev_dbg(&pdev->dev, "FME HDR UInit.\n");
sysfs_remove_files(&pdev->dev.kobj, fme_hdr_attrs);
}
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 long fme_ioctl_check_extension(struct dfl_feature_platform_data *pdata,
unsigned long arg)
{
/* No extension support for now */
return 0;
}
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) {
case DFL_FPGA_GET_API_VERSION:
return DFL_FPGA_API_VERSION;
case DFL_FPGA_CHECK_EXTENSION:
return fme_ioctl_check_extension(pdata, arg);
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");