@@ -10,6 +10,13 @@ menuconfig FPGA
kernel. The FPGA framework adds an FPGA manager class and FPGA
manager drivers.
+config FPGA_MGR_DEBUG_FS
+ bool "FPGA Manager DebugFS"
+ depends on FPGA && DEBUG_FS
+ help
+ Say Y here if you want to expose a DebugFS interface for the
+ FPGA Manager Framework.
+
if FPGA
config FPGA_MGR_SOCFPGA
@@ -5,6 +5,7 @@
# Core FPGA Manager Framework
obj-$(CONFIG_FPGA) += fpga-mgr.o
+obj-$(CONFIG_FPGA_MGR_DEBUG_FS) += fpga-mgr-debugfs.o
# FPGA Manager Drivers
obj-$(CONFIG_FPGA_MGR_ALTERA_CVP) += altera-cvp.o
new file mode 100644
@@ -0,0 +1,183 @@
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * FPGA Manager DebugFS
+ *
+ * Copyright (C) 2016 Intel Corporation. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms and conditions of the GNU General Public License,
+ * version 2, as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
+ * more details.
+ *
+ * You should have received a copy of the GNU General Public License along with
+ * this program. If not, see <http://www.gnu.org/licenses/>.
+ */
+#include <linux/debugfs.h>
+#include <linux/fpga/fpga-mgr.h>
+#include <linux/slab.h>
+#include <linux/uaccess.h>
+
+static struct dentry *fpga_mgr_debugfs_root;
+
+struct fpga_mgr_debugfs {
+ struct dentry *debugfs_dir;
+ char *firmware_name;
+ struct fpga_image_info info;
+};
+
+static ssize_t fpga_mgr_firmware_write_file(struct file *file,
+ const char __user *user_buf,
+ size_t count, loff_t *ppos)
+{
+ struct fpga_manager *mgr = file->private_data;
+ struct fpga_mgr_debugfs *debugfs = mgr->debugfs;
+ char *buf;
+ int ret;
+
+ buf = kzalloc(count, GFP_KERNEL);
+ if (!buf)
+ return -ENOMEM;
+
+ if (copy_from_user(buf, user_buf, count))
+ return -EFAULT;
+
+ buf[count] = 0;
+ if (buf[count - 1] == '\n')
+ buf[count - 1] = 0;
+
+ kfree(debugfs->firmware_name);
+ debugfs->firmware_name = buf;
+
+ ret = fpga_mgr_firmware_load(mgr, &debugfs->info, buf);
+ if (ret)
+ dev_err(&mgr->dev,
+ "fpga_mgr_firmware_load returned with value %d\n", ret);
+
+ return count;
+}
+
+static ssize_t fpga_mgr_firmware_read_file(struct file *file,
+ char __user *user_buf,
+ size_t count, loff_t *ppos)
+{
+ struct fpga_manager *mgr = file->private_data;
+ struct fpga_mgr_debugfs *debugfs = mgr->debugfs;
+ char *buf;
+ int ret;
+
+ if (debugfs->firmware_name == NULL)
+ return 0;
+
+ buf = kzalloc(PAGE_SIZE, GFP_KERNEL);
+ if (!buf)
+ return -ENOMEM;
+
+ ret = snprintf(buf, PAGE_SIZE, "%s\n", debugfs->firmware_name);
+ if (ret < 0) {
+ kfree(buf);
+ return ret;
+ }
+
+ ret = simple_read_from_buffer(user_buf, count, ppos, buf, ret);
+ kfree(buf);
+
+ return ret;
+}
+
+static const struct file_operations fpga_mgr_firmware_fops = {
+ .open = simple_open,
+ .read = fpga_mgr_firmware_read_file,
+ .write = fpga_mgr_firmware_write_file,
+ .llseek = default_llseek,
+};
+
+static ssize_t fpga_mgr_image_write_file(struct file *file,
+ const char __user *user_buf,
+ size_t count, loff_t *ppos)
+{
+ struct fpga_manager *mgr = file->private_data;
+ struct fpga_mgr_debugfs *debugfs = mgr->debugfs;
+ char *buf;
+ int ret;
+
+ dev_info(&mgr->dev, "writing %d bytes to %s\n", count, mgr->name);
+
+ buf = kzalloc(count, GFP_KERNEL);
+ if (!buf)
+ return -ENOMEM;
+
+ if (copy_from_user(buf, user_buf, count))
+ return -EFAULT;
+
+ /* If firmware interface was previously used, forget it. */
+ kfree(debugfs->firmware_name);
+ debugfs->firmware_name = NULL;
+
+ ret = fpga_mgr_buf_load(mgr, &debugfs->info, buf, count);
+ if (ret)
+ dev_err(&mgr->dev,
+ "fpga_mgr_buf_load returned with value %d\n", ret);
+
+ return count;
+}
+
+static const struct file_operations fpga_mgr_image_fops = {
+ .open = simple_open,
+ .write = fpga_mgr_image_write_file,
+ .llseek = default_llseek,
+};
+
+void fpga_mgr_debugfs_add(struct fpga_manager *mgr)
+{
+ struct fpga_mgr_debugfs *debugfs;
+ struct fpga_image_info *info;
+
+ if (!fpga_mgr_debugfs_root)
+ return;
+
+ debugfs = kzalloc(sizeof(*debugfs), GFP_KERNEL);
+ if (!debugfs)
+ return;
+
+ debugfs->debugfs_dir = debugfs_create_dir(dev_name(&mgr->dev),
+ fpga_mgr_debugfs_root);
+
+ debugfs_create_file("firmware_name", 0600, debugfs->debugfs_dir, mgr,
+ &fpga_mgr_firmware_fops);
+
+ debugfs_create_file("image", 0200, debugfs->debugfs_dir, mgr,
+ &fpga_mgr_image_fops);
+
+ info = &debugfs->info;
+ debugfs_create_u32("flags", 0600, debugfs->debugfs_dir, &info->flags);
+
+ mgr->debugfs = debugfs;
+}
+
+void fpga_mgr_debugfs_remove(struct fpga_manager *mgr)
+{
+ struct fpga_mgr_debugfs *debugfs = mgr->debugfs;
+
+ if (!fpga_mgr_debugfs_root)
+ return;
+
+ debugfs_remove_recursive(debugfs->debugfs_dir);
+ kfree(debugfs->firmware_name);
+ kfree(debugfs);
+}
+
+void fpga_mgr_debugfs_init(void)
+{
+ fpga_mgr_debugfs_root = debugfs_create_dir("fpga_manager", NULL);
+ if (!fpga_mgr_debugfs_root)
+ pr_warn("fpga_mgr: Failed to create debugfs root\n");
+}
+
+void fpga_mgr_debugfs_uninit(void)
+{
+ debugfs_remove_recursive(fpga_mgr_debugfs_root);
+}
new file mode 100644
@@ -0,0 +1,32 @@
+/* SPDX-License-Identifier: GPL-2.0
+ * FPGA Manager DebugFS
+ *
+ * Copyright (C) 2016 Intel Corporation. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms and conditions of the GNU General Public License,
+ * version 2, as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
+ * more details.
+ *
+ * You should have received a copy of the GNU General Public License along with
+ * this program. If not, see <http://www.gnu.org/licenses/>.
+ */
+#ifdef CONFIG_FPGA_MGR_DEBUG_FS
+
+void fpga_mgr_debugfs_add(struct fpga_manager *mgr);
+void fpga_mgr_debugfs_remove(struct fpga_manager *mgr);
+void fpga_mgr_debugfs_init(void);
+void fpga_mgr_debugfs_uninit(void);
+
+#else
+
+void fpga_mgr_debugfs_add(struct fpga_manager *mgr) {}
+void fpga_mgr_debugfs_remove(struct fpga_manager *mgr) {}
+void fpga_mgr_debugfs_init(void) {}
+void fpga_mgr_debugfs_uninit(void) {}
+
+#endif /* CONFIG_FPGA_MGR_DEBUG_FS */
@@ -17,6 +17,7 @@
#include <linux/slab.h>
#include <linux/scatterlist.h>
#include <linux/highmem.h>
+#include "fpga-mgr-debugfs.h"
static DEFINE_IDA(fpga_mgr_ida);
static struct class *fpga_mgr_class;
@@ -658,6 +659,8 @@ fpga_mgr_register_full(struct device *parent, const struct fpga_manager_info *in
return ERR_PTR(ret);
}
+ fpga_mgr_debugfs_add(mgr);
+
return mgr;
error_device:
@@ -708,6 +711,8 @@ void fpga_mgr_unregister(struct fpga_manager *mgr)
{
dev_info(&mgr->dev, "%s %s\n", __func__, mgr->name);
+ fpga_mgr_debugfs_remove(mgr);
+
/*
* If the low level driver provides a method for putting fpga into
* a desired state upon unregister, do it.
@@ -800,11 +805,14 @@ static int __init fpga_mgr_class_init(void)
fpga_mgr_class->dev_groups = fpga_mgr_groups;
fpga_mgr_class->dev_release = fpga_mgr_dev_release;
+ fpga_mgr_debugfs_init();
+
return 0;
}
static void __exit fpga_mgr_class_exit(void)
{
+ fpga_mgr_debugfs_uninit();
class_destroy(fpga_mgr_class);
ida_destroy(&fpga_mgr_ida);
}
@@ -191,6 +191,9 @@ struct fpga_manager {
struct fpga_compat_id *compat_id;
const struct fpga_manager_ops *mops;
void *priv;
+#ifdef CONFIG_FPGA_MGR_DEBUG_FS
+ void *debugfs;
+#endif
};
#define to_fpga_manager(d) container_of(d, struct fpga_manager, dev)