Commit b16c5147 authored by Wu Hao's avatar Wu Hao Committed by Greg Kroah-Hartman

fpga: dfl: add chardev support for feature devices

For feature devices drivers, both the FPGA Management Engine (FME) and
Accelerated Function Unit (AFU) driver need to expose user interfaces via
the device file, for example, mmap and ioctls.

This patch adds chardev support in the dfl driver for feature devices,
FME and AFU. It reserves the chardev regions for FME and AFU and provide
interfaces for FME and AFU driver to register their device file operations.
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 avatarZhang Yi <yi.z.zhang@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 543be3d8
...@@ -22,6 +22,11 @@ static DEFINE_MUTEX(dfl_id_mutex); ...@@ -22,6 +22,11 @@ static DEFINE_MUTEX(dfl_id_mutex);
* dfl_devs table which is indexed by dfl_id_type, e.g. name string used for * dfl_devs table which is indexed by dfl_id_type, e.g. name string used for
* platform device creation (define name strings in dfl.h, as they could be * platform device creation (define name strings in dfl.h, as they could be
* reused by platform device drivers). * reused by platform device drivers).
*
* if the new feature dev needs chardev support, then it's required to add
* a new item in dfl_chardevs table and configure dfl_devs[i].devt_type as
* index to dfl_chardevs table. If no chardev support just set devt_type
* as one invalid index (DFL_FPGA_DEVT_MAX).
*/ */
enum dfl_id_type { enum dfl_id_type {
FME_ID, /* fme id allocation and mapping */ FME_ID, /* fme id allocation and mapping */
...@@ -29,22 +34,48 @@ enum dfl_id_type { ...@@ -29,22 +34,48 @@ enum dfl_id_type {
DFL_ID_MAX, DFL_ID_MAX,
}; };
enum dfl_fpga_devt_type {
DFL_FPGA_DEVT_FME,
DFL_FPGA_DEVT_PORT,
DFL_FPGA_DEVT_MAX,
};
/** /**
* dfl_dev_info - dfl feature device information. * dfl_dev_info - dfl feature device information.
* @name: name string of the feature platform device. * @name: name string of the feature platform device.
* @dfh_id: id value in Device Feature Header (DFH) register by DFL spec. * @dfh_id: id value in Device Feature Header (DFH) register by DFL spec.
* @id: idr id of the feature dev. * @id: idr id of the feature dev.
* @devt_type: index to dfl_chrdevs[].
*/ */
struct dfl_dev_info { struct dfl_dev_info {
const char *name; const char *name;
u32 dfh_id; u32 dfh_id;
struct idr id; struct idr id;
enum dfl_fpga_devt_type devt_type;
}; };
/* it is indexed by dfl_id_type */ /* it is indexed by dfl_id_type */
static struct dfl_dev_info dfl_devs[] = { static struct dfl_dev_info dfl_devs[] = {
{.name = DFL_FPGA_FEATURE_DEV_FME, .dfh_id = DFH_ID_FIU_FME}, {.name = DFL_FPGA_FEATURE_DEV_FME, .dfh_id = DFH_ID_FIU_FME,
{.name = DFL_FPGA_FEATURE_DEV_PORT, .dfh_id = DFH_ID_FIU_PORT}, .devt_type = DFL_FPGA_DEVT_FME},
{.name = DFL_FPGA_FEATURE_DEV_PORT, .dfh_id = DFH_ID_FIU_PORT,
.devt_type = DFL_FPGA_DEVT_PORT},
};
/**
* dfl_chardev_info - chardev information of dfl feature device
* @name: nmae string of the char device.
* @devt: devt of the char device.
*/
struct dfl_chardev_info {
const char *name;
dev_t devt;
};
/* indexed by enum dfl_fpga_devt_type */
static struct dfl_chardev_info dfl_chrdevs[] = {
{.name = DFL_FPGA_FEATURE_DEV_FME},
{.name = DFL_FPGA_FEATURE_DEV_PORT},
}; };
static void dfl_ids_init(void) static void dfl_ids_init(void)
...@@ -105,6 +136,86 @@ static enum dfl_id_type dfh_id_to_type(u32 id) ...@@ -105,6 +136,86 @@ static enum dfl_id_type dfh_id_to_type(u32 id)
return DFL_ID_MAX; return DFL_ID_MAX;
} }
static void dfl_chardev_uinit(void)
{
int i;
for (i = 0; i < DFL_FPGA_DEVT_MAX; i++)
if (MAJOR(dfl_chrdevs[i].devt)) {
unregister_chrdev_region(dfl_chrdevs[i].devt,
MINORMASK);
dfl_chrdevs[i].devt = MKDEV(0, 0);
}
}
static int dfl_chardev_init(void)
{
int i, ret;
for (i = 0; i < DFL_FPGA_DEVT_MAX; i++) {
ret = alloc_chrdev_region(&dfl_chrdevs[i].devt, 0, MINORMASK,
dfl_chrdevs[i].name);
if (ret)
goto exit;
}
return 0;
exit:
dfl_chardev_uinit();
return ret;
}
static dev_t dfl_get_devt(enum dfl_fpga_devt_type type, int id)
{
if (type >= DFL_FPGA_DEVT_MAX)
return 0;
return MKDEV(MAJOR(dfl_chrdevs[type].devt), id);
}
/**
* dfl_fpga_dev_ops_register - register cdev ops for feature dev
*
* @pdev: feature dev.
* @fops: file operations for feature dev's cdev.
* @owner: owning module/driver.
*
* Return: 0 on success, negative error code otherwise.
*/
int dfl_fpga_dev_ops_register(struct platform_device *pdev,
const struct file_operations *fops,
struct module *owner)
{
struct dfl_feature_platform_data *pdata = dev_get_platdata(&pdev->dev);
cdev_init(&pdata->cdev, fops);
pdata->cdev.owner = owner;
/*
* set parent to the feature device so that its refcount is
* decreased after the last refcount of cdev is gone, that
* makes sure the feature device is valid during device
* file's life-cycle.
*/
pdata->cdev.kobj.parent = &pdev->dev.kobj;
return cdev_add(&pdata->cdev, pdev->dev.devt, 1);
}
EXPORT_SYMBOL_GPL(dfl_fpga_dev_ops_register);
/**
* dfl_fpga_dev_ops_unregister - unregister cdev ops for feature dev
* @pdev: feature dev.
*/
void dfl_fpga_dev_ops_unregister(struct platform_device *pdev)
{
struct dfl_feature_platform_data *pdata = dev_get_platdata(&pdev->dev);
cdev_del(&pdata->cdev);
}
EXPORT_SYMBOL_GPL(dfl_fpga_dev_ops_unregister);
/** /**
* struct build_feature_devs_info - info collected during feature dev build. * struct build_feature_devs_info - info collected during feature dev build.
* *
...@@ -266,6 +377,7 @@ build_info_create_dev(struct build_feature_devs_info *binfo, ...@@ -266,6 +377,7 @@ build_info_create_dev(struct build_feature_devs_info *binfo,
return fdev->id; return fdev->id;
fdev->dev.parent = &binfo->cdev->region->dev; fdev->dev.parent = &binfo->cdev->region->dev;
fdev->dev.devt = dfl_get_devt(dfl_devs[type].devt_type, fdev->id);
return 0; return 0;
} }
...@@ -703,13 +815,20 @@ EXPORT_SYMBOL_GPL(dfl_fpga_feature_devs_remove); ...@@ -703,13 +815,20 @@ EXPORT_SYMBOL_GPL(dfl_fpga_feature_devs_remove);
static int __init dfl_fpga_init(void) static int __init dfl_fpga_init(void)
{ {
int ret;
dfl_ids_init(); dfl_ids_init();
return 0; ret = dfl_chardev_init();
if (ret)
dfl_ids_destroy();
return ret;
} }
static void __exit dfl_fpga_exit(void) static void __exit dfl_fpga_exit(void)
{ {
dfl_chardev_uinit();
dfl_ids_destroy(); dfl_ids_destroy();
} }
......
...@@ -15,6 +15,7 @@ ...@@ -15,6 +15,7 @@
#define __FPGA_DFL_H #define __FPGA_DFL_H
#include <linux/bitfield.h> #include <linux/bitfield.h>
#include <linux/cdev.h>
#include <linux/delay.h> #include <linux/delay.h>
#include <linux/fs.h> #include <linux/fs.h>
#include <linux/iopoll.h> #include <linux/iopoll.h>
...@@ -150,6 +151,7 @@ struct dfl_feature { ...@@ -150,6 +151,7 @@ struct dfl_feature {
* *
* @node: node to link feature devs to container device's port_dev_list. * @node: node to link feature devs to container device's port_dev_list.
* @lock: mutex to protect platform data. * @lock: mutex to protect platform data.
* @cdev: cdev of feature dev.
* @dev: ptr to platform device linked with this platform data. * @dev: ptr to platform device linked with this platform data.
* @dfl_cdev: ptr to container device. * @dfl_cdev: ptr to container device.
* @disable_count: count for port disable. * @disable_count: count for port disable.
...@@ -159,6 +161,7 @@ struct dfl_feature { ...@@ -159,6 +161,7 @@ struct dfl_feature {
struct dfl_feature_platform_data { struct dfl_feature_platform_data {
struct list_head node; struct list_head node;
struct mutex lock; struct mutex lock;
struct cdev cdev;
struct platform_device *dev; struct platform_device *dev;
struct dfl_fpga_cdev *dfl_cdev; struct dfl_fpga_cdev *dfl_cdev;
unsigned int disable_count; unsigned int disable_count;
...@@ -176,6 +179,11 @@ static inline int dfl_feature_platform_data_size(const int num) ...@@ -176,6 +179,11 @@ static inline int dfl_feature_platform_data_size(const int num)
num * sizeof(struct dfl_feature); num * sizeof(struct dfl_feature);
} }
int dfl_fpga_dev_ops_register(struct platform_device *pdev,
const struct file_operations *fops,
struct module *owner);
void dfl_fpga_dev_ops_unregister(struct platform_device *pdev);
#define dfl_fpga_dev_for_each_feature(pdata, feature) \ #define dfl_fpga_dev_for_each_feature(pdata, feature) \
for ((feature) = (pdata)->features; \ for ((feature) = (pdata)->features; \
(feature) < (pdata)->features + (pdata)->num; (feature)++) (feature) < (pdata)->features + (pdata)->num; (feature)++)
......
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