Re: [PATCH 2/2] fpga: add FPGA manager debugfs

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

 



On Thu, Aug 16, 2018 at 1:59 PM, Moritz Fischer <mdf@xxxxxxxxxx> wrote:
> Hi Alan,

Hi Moritz,

> comments inline. While I see how this is useful, I have the
> suspicion that from the moment this gets merged vendor kernels
> will just default to use this ...

Yeah, I have that suspicion as well.  That's probably why I sat on
this and didn't upstream it for 2 years.  But on the other hand, I
keep hearing of lots of cases of people implementing this
independently anyway.  At least if it is debugfs, it makes it clear
that it's not intended for production use.

>
> On Wed, Aug 15, 2018 at 05:09:58PM -0500, Alan Tull wrote:
>> From: Alan Tull <atull@xxxxxxxxxxxxxxxxxxxxx>
>>
>> Implement DebugFS for the FPGA Manager Framework for
>> debugging and developmental use.
>>
>> Enabled by CONFIG_FPGA_MGR_DEBUG_FS
>>
>> Each FPGA gets its own directory such as
>>  <debugfs>/fpga_manager/fpga0 and three files:
>>
>>  * [RW] flags          = flags as defined in fpga-mgr.h
>>  * [RW] firmware_name  = write/read back name of FPGA image
>>                          firmware file to program
>>  * [WO] image          = write-only file for directly writing
>>                          fpga image w/o firmware layer
>>  * [RW] config_complete_timeout_us = maximum for the FPGA to
>>                          go to the operating state after
>>                        programming
>>
>> The debugfs is implemented in a separate fpga_mgr_debugfs.c
>> file, but the FPGA manager core is still built as one
>> module.  Note the name change from fpga-mgr.ko to fpga_mgr.ko.
>>
>> Signed-off-by: Alan Tull <atull@xxxxxxxxxx>
>> Signed-off-by: Matthew Gerlach <matthew.gerlach@xxxxxxxxxxxxxxx>
>> ---
>>  drivers/fpga/Kconfig            |   7 ++
>>  drivers/fpga/Makefile           |   4 +-
>>  drivers/fpga/fpga-mgr-debugfs.c | 221 ++++++++++++++++++++++++++++++++++++++++
>>  drivers/fpga/fpga-mgr-debugfs.h |  22 ++++
>>  drivers/fpga/fpga-mgr.c         |   8 ++
>>  include/linux/fpga/fpga-mgr.h   |   3 +
>>  6 files changed, 264 insertions(+), 1 deletion(-)
>>  create mode 100644 drivers/fpga/fpga-mgr-debugfs.c
>>  create mode 100644 drivers/fpga/fpga-mgr-debugfs.h
>>
>> diff --git a/drivers/fpga/Kconfig b/drivers/fpga/Kconfig
>> index 1ebcef4..600924d 100644
>> --- a/drivers/fpga/Kconfig
>> +++ b/drivers/fpga/Kconfig
>> @@ -9,6 +9,13 @@ menuconfig FPGA
>>         kernel.  The FPGA framework adds a 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
>> diff --git a/drivers/fpga/Makefile b/drivers/fpga/Makefile
>> index 7a2d73b..62910cc 100644
>> --- a/drivers/fpga/Makefile
>> +++ b/drivers/fpga/Makefile
>> @@ -4,7 +4,9 @@
>>  #
>>
>>  # Core FPGA Manager Framework
>> -obj-$(CONFIG_FPGA)                   += fpga-mgr.o
>> +obj-$(CONFIG_FPGA)                   += fpga_mgr.o
>> +fpga_mgr-y                           := fpga-mgr.o
>> +fpga_mgr-$(CONFIG_FPGA_MGR_DEBUG_FS) += fpga-mgr-debugfs.o
>>
>>  # FPGA Manager Drivers
>>  obj-$(CONFIG_FPGA_MGR_ALTERA_CVP)    += altera-cvp.o
>> diff --git a/drivers/fpga/fpga-mgr-debugfs.c b/drivers/fpga/fpga-mgr-debugfs.c
>> new file mode 100644
>> index 0000000..f2fdf58
>> --- /dev/null
>> +++ b/drivers/fpga/fpga-mgr-debugfs.c
>> @@ -0,0 +1,221 @@
>> +// SPDX-License-Identifier: GPL-2.0
>> +/*
>> + * FPGA Manager DebugFS
>> + *
>> + *  Copyright (C) 2016-2018 Intel Corporation.  All rights reserved.
>> + */
>> +#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;
>> +     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;
>> +     struct device *dev = &mgr->dev;
>> +     char *buf;
>> +     int ret;
>> +
>> +     ret = fpga_mgr_lock(mgr);
>> +     if (ret) {
>> +             dev_err(dev, "FPGA manager is busy\n");
>> +             return -EBUSY;
>> +     }
>> +
>> +     buf = devm_kzalloc(dev, count, GFP_KERNEL);
>> +     if (!buf) {
>> +             fpga_mgr_unlock(mgr);
>> +             return -ENOMEM;
>> +     }
>> +
>> +     if (copy_from_user(buf, user_buf, count)) {
>> +             fpga_mgr_unlock(mgr);
>> +             devm_kfree(dev, buf);
>> +             return -EFAULT;
>> +     }
>> +
>> +     buf[count] = 0;
>> +     if (buf[count - 1] == '\n')
>> +             buf[count - 1] = 0;
>> +
>> +     /* Release previous firmware name (if any). Save current one. */
>> +     if (debugfs->info->firmware_name)
>> +             devm_kfree(dev, debugfs->info->firmware_name);
>> +     debugfs->info->firmware_name = buf;
>> +
>> +     ret = fpga_mgr_load(mgr, debugfs->info);
>> +     if (ret)
>> +             dev_err(dev, "fpga_mgr_load returned with value %d\n", ret);
>> +
>> +     fpga_mgr_unlock(mgr);
>> +
>> +     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->info->firmware_name)
>> +             return 0;
>> +
>> +     buf = kzalloc(PAGE_SIZE, GFP_KERNEL);
>> +     if (!buf)
>> +             return -ENOMEM;
>> +
>> +     ret = snprintf(buf, PAGE_SIZE, "%s\n", debugfs->info->firmware_name);
> snip:
> ---->8->8->8-----
>> +     if (ret < 0) {
>> +             kfree(buf);
>> +             return ret;
>> +     }
> ---->8->8->8-----
> just replace with:
>         if (ret < 0)
>                 goto out;
>> +
>> +     ret = simple_read_from_buffer(user_buf, count, ppos, buf, ret);
>
> out:
>> +     kfree(buf);
>> +     return ret;
>> +}

Yes, that's better. I'll include that in v2.

>> +
>> +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;
>> +     struct device *dev = &mgr->dev;
>> +     char *buf;
>> +     int ret;
>> +
>> +     dev_info(dev, "writing %zu bytes to %s\n", count, mgr->name);
>> +
>> +     ret = fpga_mgr_lock(mgr);
>> +     if (ret) {
>> +             dev_err(dev, "FPGA manager is busy\n");
>> +             return -EBUSY;
>> +     }
>> +
>> +     buf = kzalloc(count, GFP_KERNEL);
>> +     if (!buf) {
>> +             fpga_mgr_unlock(mgr);
>> +             return -ENOMEM;
>> +     }
>> +
>> +     if (copy_from_user(buf, user_buf, count)) {
>> +             fpga_mgr_unlock(mgr);
>> +             kfree(buf);
>> +             return -EFAULT;
>> +     }
>> +
>> +     /* If firmware interface was previously used, forget it. */
>> +     if (debugfs->info->firmware_name)
>> +             devm_kfree(dev, debugfs->info->firmware_name);
>> +     debugfs->info->firmware_name = NULL;
>> +
>> +     debugfs->info->buf = buf;
>> +     debugfs->info->count = count;
>> +
>> +     ret = fpga_mgr_load(mgr, debugfs->info);
>> +     if (ret)
>> +             dev_err(dev, "fpga_mgr_load returned with value %d\n", ret);
>> +
>> +     fpga_mgr_unlock(mgr);
>> +
>> +     debugfs->info->buf = NULL;
>> +     debugfs->info->count = 0;
>
> Is that ordering between unlock() and setting those correct?

This order should be alright, but I'll switch it anyway to be more
obviously correct.

>> +
>> +     kfree(buf);
>> +
>> +     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 device *dev = &mgr->dev;
>> +     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;
>> +
>> +     info = fpga_image_info_alloc(dev);
>> +     if (!info) {
>> +             kfree(debugfs);
>> +             return;
>> +     }
>> +     debugfs->info = info;
>> +
>> +     debugfs->debugfs_dir = debugfs_create_dir(dev_name(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);
>> +
>> +     debugfs_create_u32("flags", 0600, debugfs->debugfs_dir, &info->flags);
>> +
>> +     debugfs_create_u32("config_complete_timeout_us", 0600,
>> +                        debugfs->debugfs_dir,
>> +                        &info->config_complete_timeout_us);
>> +
>> +     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);
>> +
>> +     /* this function also frees debugfs->info->firmware_name */
>> +     fpga_image_info_free(debugfs->info);
>> +
>> +     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);
>> +}
>> diff --git a/drivers/fpga/fpga-mgr-debugfs.h b/drivers/fpga/fpga-mgr-debugfs.h
>> new file mode 100644
>> index 0000000..17cd3eb
>> --- /dev/null
>> +++ b/drivers/fpga/fpga-mgr-debugfs.h
>> @@ -0,0 +1,22 @@
>> +// SPDX-License-Identifier: GPL-2.0
>> +
>> +#ifndef _LINUX_FPGA_MGR_DEBUGFS_H
>> +#define _LINUX_FPGA_MGR_DEBUGFS_H
>> +
>> +#if IS_ENABLED(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 */
>> +
>> +#endif /*_LINUX_FPGA_MGR_DEBUGFS_H */
>> diff --git a/drivers/fpga/fpga-mgr.c b/drivers/fpga/fpga-mgr.c
>> index c8684bc..66eb6f6 100644
>> --- a/drivers/fpga/fpga-mgr.c
>> +++ b/drivers/fpga/fpga-mgr.c
>> @@ -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;
>> @@ -698,6 +699,8 @@ int fpga_mgr_register(struct fpga_manager *mgr)
>>       if (ret)
>>               goto error_device;
>>
>> +     fpga_mgr_debugfs_add(mgr);
>> +
>>       dev_info(&mgr->dev, "%s registered\n", mgr->name);
>>
>>       return 0;
>> @@ -722,6 +725,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.
>> @@ -748,11 +753,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);
>>  }
>> diff --git a/include/linux/fpga/fpga-mgr.h b/include/linux/fpga/fpga-mgr.h
>> index 777c502..e8f2159 100644
>> --- a/include/linux/fpga/fpga-mgr.h
>> +++ b/include/linux/fpga/fpga-mgr.h
>> @@ -170,6 +170,9 @@ struct fpga_manager {
>>       struct fpga_compat_id *compat_id;
>>       const struct fpga_manager_ops *mops;
>>       void *priv;
>> +#if IS_ENABLED(CONFIG_FPGA_MGR_DEBUG_FS)
>> +     void *debugfs;
>> +#endif
>>  };
>>
>>  #define to_fpga_manager(d) container_of(d, struct fpga_manager, dev)
>> --
>> 2.7.4
>>
>
> Thanks,
>
> Moritz

Thanks for the review!

Alan



[Index of Archives]     [Kernel Newbies]     [Security]     [Netfilter]     [Bugtraq]     [Linux FS]     [Yosemite Forum]     [MIPS Linux]     [ARM Linux]     [Linux Security]     [Linux RAID]     [Samba]     [Video 4 Linux]     [Device Mapper]     [Linux Resources]

  Powered by Linux