1 // SPDX-License-Identifier: GPL-2.0
3 * Driver for FPGA Management Engine (FME)
5 * Copyright (C) 2017-2018 Intel Corporation, Inc.
8 * Kang Luwei <luwei.kang@intel.com>
9 * Xiao Guangrong <guangrong.xiao@linux.intel.com>
10 * Joseph Grecco <joe.grecco@intel.com>
11 * Enno Luebbers <enno.luebbers@intel.com>
12 * Tim Whisonant <tim.whisonant@intel.com>
13 * Ananda Ravuri <ananda.ravuri@intel.com>
14 * Henry Mitchel <henry.mitchel@intel.com>
17 #include <linux/kernel.h>
18 #include <linux/module.h>
19 #include <linux/fpga-dfl.h>
24 static ssize_t
ports_num_show(struct device
*dev
,
25 struct device_attribute
*attr
, char *buf
)
30 base
= dfl_get_feature_ioaddr_by_id(dev
, FME_FEATURE_ID_HEADER
);
32 v
= readq(base
+ FME_HDR_CAP
);
34 return scnprintf(buf
, PAGE_SIZE
, "%u\n",
35 (unsigned int)FIELD_GET(FME_CAP_NUM_PORTS
, v
));
37 static DEVICE_ATTR_RO(ports_num
);
40 * Bitstream (static FPGA region) identifier number. It contains the
41 * detailed version and other information of this static FPGA region.
43 static ssize_t
bitstream_id_show(struct device
*dev
,
44 struct device_attribute
*attr
, char *buf
)
49 base
= dfl_get_feature_ioaddr_by_id(dev
, FME_FEATURE_ID_HEADER
);
51 v
= readq(base
+ FME_HDR_BITSTREAM_ID
);
53 return scnprintf(buf
, PAGE_SIZE
, "0x%llx\n", (unsigned long long)v
);
55 static DEVICE_ATTR_RO(bitstream_id
);
58 * Bitstream (static FPGA region) meta data. It contains the synthesis
59 * date, seed and other information of this static FPGA region.
61 static ssize_t
bitstream_metadata_show(struct device
*dev
,
62 struct device_attribute
*attr
, char *buf
)
67 base
= dfl_get_feature_ioaddr_by_id(dev
, FME_FEATURE_ID_HEADER
);
69 v
= readq(base
+ FME_HDR_BITSTREAM_MD
);
71 return scnprintf(buf
, PAGE_SIZE
, "0x%llx\n", (unsigned long long)v
);
73 static DEVICE_ATTR_RO(bitstream_metadata
);
75 static const struct attribute
*fme_hdr_attrs
[] = {
76 &dev_attr_ports_num
.attr
,
77 &dev_attr_bitstream_id
.attr
,
78 &dev_attr_bitstream_metadata
.attr
,
82 static int fme_hdr_init(struct platform_device
*pdev
,
83 struct dfl_feature
*feature
)
85 void __iomem
*base
= feature
->ioaddr
;
88 dev_dbg(&pdev
->dev
, "FME HDR Init.\n");
89 dev_dbg(&pdev
->dev
, "FME cap %llx.\n",
90 (unsigned long long)readq(base
+ FME_HDR_CAP
));
92 ret
= sysfs_create_files(&pdev
->dev
.kobj
, fme_hdr_attrs
);
99 static void fme_hdr_uinit(struct platform_device
*pdev
,
100 struct dfl_feature
*feature
)
102 dev_dbg(&pdev
->dev
, "FME HDR UInit.\n");
103 sysfs_remove_files(&pdev
->dev
.kobj
, fme_hdr_attrs
);
106 static const struct dfl_feature_ops fme_hdr_ops
= {
107 .init
= fme_hdr_init
,
108 .uinit
= fme_hdr_uinit
,
111 static struct dfl_feature_driver fme_feature_drvs
[] = {
113 .id
= FME_FEATURE_ID_HEADER
,
117 .id
= FME_FEATURE_ID_PR_MGMT
,
125 static long fme_ioctl_check_extension(struct dfl_feature_platform_data
*pdata
,
128 /* No extension support for now */
132 static int fme_open(struct inode
*inode
, struct file
*filp
)
134 struct platform_device
*fdev
= dfl_fpga_inode_to_feature_dev(inode
);
135 struct dfl_feature_platform_data
*pdata
= dev_get_platdata(&fdev
->dev
);
141 ret
= dfl_feature_dev_use_begin(pdata
);
145 dev_dbg(&fdev
->dev
, "Device File Open\n");
146 filp
->private_data
= pdata
;
151 static int fme_release(struct inode
*inode
, struct file
*filp
)
153 struct dfl_feature_platform_data
*pdata
= filp
->private_data
;
154 struct platform_device
*pdev
= pdata
->dev
;
156 dev_dbg(&pdev
->dev
, "Device File Release\n");
157 dfl_feature_dev_use_end(pdata
);
162 static long fme_ioctl(struct file
*filp
, unsigned int cmd
, unsigned long arg
)
164 struct dfl_feature_platform_data
*pdata
= filp
->private_data
;
165 struct platform_device
*pdev
= pdata
->dev
;
166 struct dfl_feature
*f
;
169 dev_dbg(&pdev
->dev
, "%s cmd 0x%x\n", __func__
, cmd
);
172 case DFL_FPGA_GET_API_VERSION
:
173 return DFL_FPGA_API_VERSION
;
174 case DFL_FPGA_CHECK_EXTENSION
:
175 return fme_ioctl_check_extension(pdata
, arg
);
178 * Let sub-feature's ioctl function to handle the cmd.
179 * Sub-feature's ioctl returns -ENODEV when cmd is not
180 * handled in this sub feature, and returns 0 or other
181 * error code if cmd is handled.
183 dfl_fpga_dev_for_each_feature(pdata
, f
) {
184 if (f
->ops
&& f
->ops
->ioctl
) {
185 ret
= f
->ops
->ioctl(pdev
, f
, cmd
, arg
);
195 static int fme_dev_init(struct platform_device
*pdev
)
197 struct dfl_feature_platform_data
*pdata
= dev_get_platdata(&pdev
->dev
);
200 fme
= devm_kzalloc(&pdev
->dev
, sizeof(*fme
), GFP_KERNEL
);
206 mutex_lock(&pdata
->lock
);
207 dfl_fpga_pdata_set_private(pdata
, fme
);
208 mutex_unlock(&pdata
->lock
);
213 static void fme_dev_destroy(struct platform_device
*pdev
)
215 struct dfl_feature_platform_data
*pdata
= dev_get_platdata(&pdev
->dev
);
218 mutex_lock(&pdata
->lock
);
219 fme
= dfl_fpga_pdata_get_private(pdata
);
220 dfl_fpga_pdata_set_private(pdata
, NULL
);
221 mutex_unlock(&pdata
->lock
);
224 static const struct file_operations fme_fops
= {
225 .owner
= THIS_MODULE
,
227 .release
= fme_release
,
228 .unlocked_ioctl
= fme_ioctl
,
231 static int fme_probe(struct platform_device
*pdev
)
235 ret
= fme_dev_init(pdev
);
239 ret
= dfl_fpga_dev_feature_init(pdev
, fme_feature_drvs
);
243 ret
= dfl_fpga_dev_ops_register(pdev
, &fme_fops
, THIS_MODULE
);
250 dfl_fpga_dev_feature_uinit(pdev
);
252 fme_dev_destroy(pdev
);
257 static int fme_remove(struct platform_device
*pdev
)
259 dfl_fpga_dev_ops_unregister(pdev
);
260 dfl_fpga_dev_feature_uinit(pdev
);
261 fme_dev_destroy(pdev
);
266 static struct platform_driver fme_driver
= {
268 .name
= DFL_FPGA_FEATURE_DEV_FME
,
271 .remove
= fme_remove
,
274 module_platform_driver(fme_driver
);
276 MODULE_DESCRIPTION("FPGA Management Engine driver");
277 MODULE_AUTHOR("Intel Corporation");
278 MODULE_LICENSE("GPL v2");
279 MODULE_ALIAS("platform:dfl-fme");