Linux Audio

Check our new training course

Loading...
Note: File does not exist in v3.5.6.
  1// SPDX-License-Identifier: GPL-2.0
  2/*
  3 * Driver for FPGA Management Engine (FME)
  4 *
  5 * Copyright (C) 2017-2018 Intel Corporation, Inc.
  6 *
  7 * Authors:
  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>
 15 */
 16
 17#include <linux/kernel.h>
 18#include <linux/module.h>
 19#include <linux/uaccess.h>
 20#include <linux/fpga-dfl.h>
 21
 22#include "dfl.h"
 23#include "dfl-fme.h"
 24
 25static ssize_t ports_num_show(struct device *dev,
 26			      struct device_attribute *attr, char *buf)
 27{
 28	void __iomem *base;
 29	u64 v;
 30
 31	base = dfl_get_feature_ioaddr_by_id(dev, FME_FEATURE_ID_HEADER);
 32
 33	v = readq(base + FME_HDR_CAP);
 34
 35	return scnprintf(buf, PAGE_SIZE, "%u\n",
 36			 (unsigned int)FIELD_GET(FME_CAP_NUM_PORTS, v));
 37}
 38static DEVICE_ATTR_RO(ports_num);
 39
 40/*
 41 * Bitstream (static FPGA region) identifier number. It contains the
 42 * detailed version and other information of this static FPGA region.
 43 */
 44static ssize_t bitstream_id_show(struct device *dev,
 45				 struct device_attribute *attr, char *buf)
 46{
 47	void __iomem *base;
 48	u64 v;
 49
 50	base = dfl_get_feature_ioaddr_by_id(dev, FME_FEATURE_ID_HEADER);
 51
 52	v = readq(base + FME_HDR_BITSTREAM_ID);
 53
 54	return scnprintf(buf, PAGE_SIZE, "0x%llx\n", (unsigned long long)v);
 55}
 56static DEVICE_ATTR_RO(bitstream_id);
 57
 58/*
 59 * Bitstream (static FPGA region) meta data. It contains the synthesis
 60 * date, seed and other information of this static FPGA region.
 61 */
 62static ssize_t bitstream_metadata_show(struct device *dev,
 63				       struct device_attribute *attr, char *buf)
 64{
 65	void __iomem *base;
 66	u64 v;
 67
 68	base = dfl_get_feature_ioaddr_by_id(dev, FME_FEATURE_ID_HEADER);
 69
 70	v = readq(base + FME_HDR_BITSTREAM_MD);
 71
 72	return scnprintf(buf, PAGE_SIZE, "0x%llx\n", (unsigned long long)v);
 73}
 74static DEVICE_ATTR_RO(bitstream_metadata);
 75
 76static ssize_t cache_size_show(struct device *dev,
 77			       struct device_attribute *attr, char *buf)
 78{
 79	void __iomem *base;
 80	u64 v;
 81
 82	base = dfl_get_feature_ioaddr_by_id(dev, FME_FEATURE_ID_HEADER);
 83
 84	v = readq(base + FME_HDR_CAP);
 85
 86	return sprintf(buf, "%u\n",
 87		       (unsigned int)FIELD_GET(FME_CAP_CACHE_SIZE, v));
 88}
 89static DEVICE_ATTR_RO(cache_size);
 90
 91static ssize_t fabric_version_show(struct device *dev,
 92				   struct device_attribute *attr, char *buf)
 93{
 94	void __iomem *base;
 95	u64 v;
 96
 97	base = dfl_get_feature_ioaddr_by_id(dev, FME_FEATURE_ID_HEADER);
 98
 99	v = readq(base + FME_HDR_CAP);
100
101	return sprintf(buf, "%u\n",
102		       (unsigned int)FIELD_GET(FME_CAP_FABRIC_VERID, v));
103}
104static DEVICE_ATTR_RO(fabric_version);
105
106static ssize_t socket_id_show(struct device *dev,
107			      struct device_attribute *attr, char *buf)
108{
109	void __iomem *base;
110	u64 v;
111
112	base = dfl_get_feature_ioaddr_by_id(dev, FME_FEATURE_ID_HEADER);
113
114	v = readq(base + FME_HDR_CAP);
115
116	return sprintf(buf, "%u\n",
117		       (unsigned int)FIELD_GET(FME_CAP_SOCKET_ID, v));
118}
119static DEVICE_ATTR_RO(socket_id);
120
121static 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,
128	NULL,
129};
130
131static const struct attribute_group fme_hdr_group = {
132	.attrs = fme_hdr_attrs,
133};
134
135static long fme_hdr_ioctl_release_port(struct dfl_feature_platform_data *pdata,
136				       unsigned long arg)
137{
138	struct dfl_fpga_cdev *cdev = pdata->dfl_cdev;
139	int port_id;
140
141	if (get_user(port_id, (int __user *)arg))
142		return -EFAULT;
143
144	return dfl_fpga_cdev_release_port(cdev, port_id);
145}
146
147static long fme_hdr_ioctl_assign_port(struct dfl_feature_platform_data *pdata,
148				      unsigned long arg)
149{
150	struct dfl_fpga_cdev *cdev = pdata->dfl_cdev;
151	int port_id;
152
153	if (get_user(port_id, (int __user *)arg))
154		return -EFAULT;
155
156	return dfl_fpga_cdev_assign_port(cdev, port_id);
157}
158
159static long fme_hdr_ioctl(struct platform_device *pdev,
160			  struct dfl_feature *feature,
161			  unsigned int cmd, unsigned long arg)
162{
163	struct dfl_feature_platform_data *pdata = dev_get_platdata(&pdev->dev);
164
165	switch (cmd) {
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);
170	}
171
172	return -ENODEV;
173}
174
175static const struct dfl_feature_id fme_hdr_id_table[] = {
176	{.id = FME_FEATURE_ID_HEADER,},
177	{0,}
178};
179
180static const struct dfl_feature_ops fme_hdr_ops = {
181	.ioctl = fme_hdr_ioctl,
182};
183
184static struct dfl_feature_driver fme_feature_drvs[] = {
185	{
186		.id_table = fme_hdr_id_table,
187		.ops = &fme_hdr_ops,
188	},
189	{
190		.id_table = fme_pr_mgmt_id_table,
191		.ops = &fme_pr_mgmt_ops,
192	},
193	{
194		.id_table = fme_global_err_id_table,
195		.ops = &fme_global_err_ops,
196	},
197	{
198		.ops = NULL,
199	},
200};
201
202static long fme_ioctl_check_extension(struct dfl_feature_platform_data *pdata,
203				      unsigned long arg)
204{
205	/* No extension support for now */
206	return 0;
207}
208
209static int fme_open(struct inode *inode, struct file *filp)
210{
211	struct platform_device *fdev = dfl_fpga_inode_to_feature_dev(inode);
212	struct dfl_feature_platform_data *pdata = dev_get_platdata(&fdev->dev);
213	int ret;
214
215	if (WARN_ON(!pdata))
216		return -ENODEV;
217
218	ret = dfl_feature_dev_use_begin(pdata);
219	if (ret)
220		return ret;
221
222	dev_dbg(&fdev->dev, "Device File Open\n");
223	filp->private_data = pdata;
224
225	return 0;
226}
227
228static int fme_release(struct inode *inode, struct file *filp)
229{
230	struct dfl_feature_platform_data *pdata = filp->private_data;
231	struct platform_device *pdev = pdata->dev;
232
233	dev_dbg(&pdev->dev, "Device File Release\n");
234	dfl_feature_dev_use_end(pdata);
235
236	return 0;
237}
238
239static long fme_ioctl(struct file *filp, unsigned int cmd, unsigned long arg)
240{
241	struct dfl_feature_platform_data *pdata = filp->private_data;
242	struct platform_device *pdev = pdata->dev;
243	struct dfl_feature *f;
244	long ret;
245
246	dev_dbg(&pdev->dev, "%s cmd 0x%x\n", __func__, cmd);
247
248	switch (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);
253	default:
254		/*
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.
259		 */
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);
263				if (ret != -ENODEV)
264					return ret;
265			}
266		}
267	}
268
269	return -EINVAL;
270}
271
272static int fme_dev_init(struct platform_device *pdev)
273{
274	struct dfl_feature_platform_data *pdata = dev_get_platdata(&pdev->dev);
275	struct dfl_fme *fme;
276
277	fme = devm_kzalloc(&pdev->dev, sizeof(*fme), GFP_KERNEL);
278	if (!fme)
279		return -ENOMEM;
280
281	fme->pdata = pdata;
282
283	mutex_lock(&pdata->lock);
284	dfl_fpga_pdata_set_private(pdata, fme);
285	mutex_unlock(&pdata->lock);
286
287	return 0;
288}
289
290static void fme_dev_destroy(struct platform_device *pdev)
291{
292	struct dfl_feature_platform_data *pdata = dev_get_platdata(&pdev->dev);
293	struct dfl_fme *fme;
294
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);
299}
300
301static const struct file_operations fme_fops = {
302	.owner		= THIS_MODULE,
303	.open		= fme_open,
304	.release	= fme_release,
305	.unlocked_ioctl = fme_ioctl,
306};
307
308static int fme_probe(struct platform_device *pdev)
309{
310	int ret;
311
312	ret = fme_dev_init(pdev);
313	if (ret)
314		goto exit;
315
316	ret = dfl_fpga_dev_feature_init(pdev, fme_feature_drvs);
317	if (ret)
318		goto dev_destroy;
319
320	ret = dfl_fpga_dev_ops_register(pdev, &fme_fops, THIS_MODULE);
321	if (ret)
322		goto feature_uinit;
323
324	return 0;
325
326feature_uinit:
327	dfl_fpga_dev_feature_uinit(pdev);
328dev_destroy:
329	fme_dev_destroy(pdev);
330exit:
331	return ret;
332}
333
334static int fme_remove(struct platform_device *pdev)
335{
336	dfl_fpga_dev_ops_unregister(pdev);
337	dfl_fpga_dev_feature_uinit(pdev);
338	fme_dev_destroy(pdev);
339
340	return 0;
341}
342
343static const struct attribute_group *fme_dev_groups[] = {
344	&fme_hdr_group,
345	&fme_global_err_group,
346	NULL
347};
348
349static struct platform_driver fme_driver = {
350	.driver	= {
351		.name       = DFL_FPGA_FEATURE_DEV_FME,
352		.dev_groups = fme_dev_groups,
353	},
354	.probe   = fme_probe,
355	.remove  = fme_remove,
356};
357
358module_platform_driver(fme_driver);
359
360MODULE_DESCRIPTION("FPGA Management Engine driver");
361MODULE_AUTHOR("Intel Corporation");
362MODULE_LICENSE("GPL v2");
363MODULE_ALIAS("platform:dfl-fme");