1 // SPDX-License-Identifier: GPL-2.0
3 * Driver for FPGA Management Engine (FME)
5 * Copyright (C) 2017-2018 Intel Corporation, Inc.
17 #include <linux/kernel.h>
18 #include <linux/module.h>
19 #include <linux/uaccess.h>
20 #include <linux/fpga-dfl.h>
25 static ssize_t ports_num_show(struct device *dev,
26 struct device_attribute *attr, char *buf)
31 base = dfl_get_feature_ioaddr_by_id(dev, FME_FEATURE_ID_HEADER);
33 v = readq(base + FME_HDR_CAP);
35 return scnprintf(buf, PAGE_SIZE, "%u\n",
36 (unsigned int)FIELD_GET(FME_CAP_NUM_PORTS, v));
38 static DEVICE_ATTR_RO(ports_num);
41 * Bitstream (static FPGA region) identifier number. It contains the
42 * detailed version and other information of this static FPGA region.
44 static ssize_t bitstream_id_show(struct device *dev,
45 struct device_attribute *attr, char *buf)
50 base = dfl_get_feature_ioaddr_by_id(dev, FME_FEATURE_ID_HEADER);
52 v = readq(base + FME_HDR_BITSTREAM_ID);
54 return scnprintf(buf, PAGE_SIZE, "0x%llx\n", (unsigned long long)v);
56 static DEVICE_ATTR_RO(bitstream_id);
59 * Bitstream (static FPGA region) meta data. It contains the synthesis
60 * date, seed and other information of this static FPGA region.
62 static ssize_t bitstream_metadata_show(struct device *dev,
63 struct device_attribute *attr, char *buf)
68 base = dfl_get_feature_ioaddr_by_id(dev, FME_FEATURE_ID_HEADER);
70 v = readq(base + FME_HDR_BITSTREAM_MD);
72 return scnprintf(buf, PAGE_SIZE, "0x%llx\n", (unsigned long long)v);
74 static DEVICE_ATTR_RO(bitstream_metadata);
76 static ssize_t cache_size_show(struct device *dev,
77 struct device_attribute *attr, char *buf)
82 base = dfl_get_feature_ioaddr_by_id(dev, FME_FEATURE_ID_HEADER);
84 v = readq(base + FME_HDR_CAP);
86 return sprintf(buf, "%u\n",
87 (unsigned int)FIELD_GET(FME_CAP_CACHE_SIZE, v));
89 static DEVICE_ATTR_RO(cache_size);
91 static ssize_t fabric_version_show(struct device *dev,
92 struct device_attribute *attr, char *buf)
97 base = dfl_get_feature_ioaddr_by_id(dev, FME_FEATURE_ID_HEADER);
99 v = readq(base + FME_HDR_CAP);
101 return sprintf(buf, "%u\n",
102 (unsigned int)FIELD_GET(FME_CAP_FABRIC_VERID, v));
104 static DEVICE_ATTR_RO(fabric_version);
106 static ssize_t socket_id_show(struct device *dev,
107 struct device_attribute *attr, char *buf)
112 base = dfl_get_feature_ioaddr_by_id(dev, FME_FEATURE_ID_HEADER);
114 v = readq(base + FME_HDR_CAP);
116 return sprintf(buf, "%u\n",
117 (unsigned int)FIELD_GET(FME_CAP_SOCKET_ID, v));
119 static DEVICE_ATTR_RO(socket_id);
121 static struct attribute *fme_hdr_attrs[] = {
122 &dev_attr_ports_num.attr,
123 &dev_attr_bitstream_id.attr,
124 &dev_attr_bitstream_metadata.attr,
125 &dev_attr_cache_size.attr,
126 &dev_attr_fabric_version.attr,
127 &dev_attr_socket_id.attr,
131 static const struct attribute_group fme_hdr_group = {
132 .attrs = fme_hdr_attrs,
135 static long fme_hdr_ioctl_release_port(struct dfl_feature_platform_data *pdata,
138 struct dfl_fpga_cdev *cdev = pdata->dfl_cdev;
141 if (get_user(port_id, (int __user *)arg))
144 return dfl_fpga_cdev_release_port(cdev, port_id);
147 static long fme_hdr_ioctl_assign_port(struct dfl_feature_platform_data *pdata,
150 struct dfl_fpga_cdev *cdev = pdata->dfl_cdev;
153 if (get_user(port_id, (int __user *)arg))
156 return dfl_fpga_cdev_assign_port(cdev, port_id);
159 static long fme_hdr_ioctl(struct platform_device *pdev,
160 struct dfl_feature *feature,
161 unsigned int cmd, unsigned long arg)
163 struct dfl_feature_platform_data *pdata = dev_get_platdata(&pdev->dev);
166 case DFL_FPGA_FME_PORT_RELEASE:
167 return fme_hdr_ioctl_release_port(pdata, arg);
168 case DFL_FPGA_FME_PORT_ASSIGN:
169 return fme_hdr_ioctl_assign_port(pdata, arg);
175 static const struct dfl_feature_id fme_hdr_id_table[] = {
176 {.id = FME_FEATURE_ID_HEADER,},
180 static const struct dfl_feature_ops fme_hdr_ops = {
181 .ioctl = fme_hdr_ioctl,
184 static struct dfl_feature_driver fme_feature_drvs[] = {
186 .id_table = fme_hdr_id_table,
190 .id_table = fme_pr_mgmt_id_table,
191 .ops = &fme_pr_mgmt_ops,
194 .id_table = fme_global_err_id_table,
195 .ops = &fme_global_err_ops,
202 static long fme_ioctl_check_extension(struct dfl_feature_platform_data *pdata,
205 /* No extension support for now */
209 static int fme_open(struct inode *inode, struct file *filp)
211 struct platform_device *fdev = dfl_fpga_inode_to_feature_dev(inode);
212 struct dfl_feature_platform_data *pdata = dev_get_platdata(&fdev->dev);
218 ret = dfl_feature_dev_use_begin(pdata);
222 dev_dbg(&fdev->dev, "Device File Open\n");
223 filp->private_data = pdata;
228 static int fme_release(struct inode *inode, struct file *filp)
230 struct dfl_feature_platform_data *pdata = filp->private_data;
231 struct platform_device *pdev = pdata->dev;
233 dev_dbg(&pdev->dev, "Device File Release\n");
234 dfl_feature_dev_use_end(pdata);
239 static long fme_ioctl(struct file *filp, unsigned int cmd, unsigned long arg)
241 struct dfl_feature_platform_data *pdata = filp->private_data;
242 struct platform_device *pdev = pdata->dev;
243 struct dfl_feature *f;
246 dev_dbg(&pdev->dev, "%s cmd 0x%x\n", __func__, cmd);
249 case DFL_FPGA_GET_API_VERSION:
250 return DFL_FPGA_API_VERSION;
251 case DFL_FPGA_CHECK_EXTENSION:
252 return fme_ioctl_check_extension(pdata, arg);
255 * Let sub-feature's ioctl function to handle the cmd.
256 * Sub-feature's ioctl returns -ENODEV when cmd is not
257 * handled in this sub feature, and returns 0 or other
258 * error code if cmd is handled.
260 dfl_fpga_dev_for_each_feature(pdata, f) {
261 if (f->ops && f->ops->ioctl) {
262 ret = f->ops->ioctl(pdev, f, cmd, arg);
272 static int fme_dev_init(struct platform_device *pdev)
274 struct dfl_feature_platform_data *pdata = dev_get_platdata(&pdev->dev);
277 fme = devm_kzalloc(&pdev->dev, sizeof(*fme), GFP_KERNEL);
283 mutex_lock(&pdata->lock);
284 dfl_fpga_pdata_set_private(pdata, fme);
285 mutex_unlock(&pdata->lock);
290 static void fme_dev_destroy(struct platform_device *pdev)
292 struct dfl_feature_platform_data *pdata = dev_get_platdata(&pdev->dev);
295 mutex_lock(&pdata->lock);
296 fme = dfl_fpga_pdata_get_private(pdata);
297 dfl_fpga_pdata_set_private(pdata, NULL);
298 mutex_unlock(&pdata->lock);
301 static const struct file_operations fme_fops = {
302 .owner = THIS_MODULE,
304 .release = fme_release,
305 .unlocked_ioctl = fme_ioctl,
308 static int fme_probe(struct platform_device *pdev)
312 ret = fme_dev_init(pdev);
316 ret = dfl_fpga_dev_feature_init(pdev, fme_feature_drvs);
320 ret = dfl_fpga_dev_ops_register(pdev, &fme_fops, THIS_MODULE);
327 dfl_fpga_dev_feature_uinit(pdev);
329 fme_dev_destroy(pdev);
334 static int fme_remove(struct platform_device *pdev)
336 dfl_fpga_dev_ops_unregister(pdev);
337 dfl_fpga_dev_feature_uinit(pdev);
338 fme_dev_destroy(pdev);
343 static const struct attribute_group *fme_dev_groups[] = {
345 &fme_global_err_group,
349 static struct platform_driver fme_driver = {
351 .name = DFL_FPGA_FEATURE_DEV_FME,
352 .dev_groups = fme_dev_groups,
355 .remove = fme_remove,
358 module_platform_driver(fme_driver);
360 MODULE_DESCRIPTION("FPGA Management Engine driver");
361 MODULE_AUTHOR("Intel Corporation");
362 MODULE_LICENSE("GPL v2");
363 MODULE_ALIAS("platform:dfl-fme");