Re: [PATCH 2/2] staging: pi433: add debugfs interface
From: Paulo Miguel Almeida
Date: Sun Jan 23 2022 - 23:16:18 EST
On Sun, Jan 23, 2022 at 12:20:57PM +0100, Greg KH wrote:
> On Sun, Jan 23, 2022 at 08:40:29PM +1300, Paulo Miguel Almeida wrote:
> > This adds debugfs interface that can be used for debugging possible
> > hardware/software issues.
> >
> > It currently exposes the following debugfs entries for each SPI device
> > probed:
> >
> > /sys/kernel/debug/pi433/<DEVICE>/regs
> > ...
> >
> > The 'regs' file contains all rf69 uC registers values that are useful
> > for troubleshooting misconfigurations between 2 devices. It contains one
> > register per line so it should be easy to use normal filtering tools to
> > find the registers of interest if needed.
> >
> > Signed-off-by: Paulo Miguel Almeida <paulo.miguel.almeida.rodenas@xxxxxxxxx>
> > ---
> > Meta-comments:
> >
> > - I'm not entirely sure if I'm allowed to add additional dependencies to Kconfig
> > the way I did or if I should surround debugfs routines with
> > #ifdef CONFIG_DEBUG_FS. I saw both approaches couldn't put my finger on which
> > one is the 'right' way here. I'm taking suggestions :)
>
> Neither is really needed at all. The debugfs api will work properly if
> the main config option is not enabled, and the code will be compiled
> away properly.
>
> So no need to add any dependancy to your driver at all.
>
> debugfs was designed to be simple to use, and adding dependancies is not
> simple. Same goes for my comments below, the goal is to keep it simple
> and not worry about any error handling.
>
> > - I saw that in some other drivers there is a tendency to have debugfs routines
> > in a separate file such as debugfs.c and in that way this allows for smaller
> > files (which I do like) and Makefile that build files based on selected
> > configs such as:
> >
> > pi433-$(CONFIG_DEBUG_FS) += debugfs.o
>
> Again, not needed.
>
> > The only way I could achieve such thing would be if I moved pi433_device struct
> > to pi433_if.h but I wanted to double check if reviewers would agree with this
> > approach first.
> >
> > ---
> > drivers/staging/pi433/Kconfig | 2 +-
> > drivers/staging/pi433/pi433_if.c | 82 ++++++++++++++++++++++++++++++++
> > drivers/staging/pi433/rf69.c | 2 +-
> > drivers/staging/pi433/rf69.h | 1 +
> > 4 files changed, 85 insertions(+), 2 deletions(-)
> >
> > diff --git a/drivers/staging/pi433/Kconfig b/drivers/staging/pi433/Kconfig
> > index dd9e4709d1a8..9a8b7ef3e670 100644
> > --- a/drivers/staging/pi433/Kconfig
> > +++ b/drivers/staging/pi433/Kconfig
> > @@ -1,7 +1,7 @@
> > # SPDX-License-Identifier: GPL-2.0
> > config PI433
> > tristate "Pi433 - a 433MHz radio module for Raspberry Pi"
> > - depends on SPI
> > + depends on SPI && DEBUG_FS
>
> You can drop this.
>
> > help
> > This option allows you to enable support for the radio module Pi433.
> >
> > diff --git a/drivers/staging/pi433/pi433_if.c b/drivers/staging/pi433/pi433_if.c
> > index 17ff51f6a9da..e3a0d78385c0 100644
> > --- a/drivers/staging/pi433/pi433_if.c
> > +++ b/drivers/staging/pi433/pi433_if.c
> > @@ -41,6 +41,9 @@
> > #ifdef CONFIG_COMPAT
> > #include <linux/compat.h>
> > #endif
> > +#include <linux/debugfs.h>
> > +#include <linux/seq_file.h>
> > +
> >
> > #include "pi433_if.h"
> > #include "rf69.h"
> > @@ -56,6 +59,8 @@ static DEFINE_MUTEX(minor_lock); /* Protect idr accesses */
> >
> > static struct class *pi433_class; /* mainly for udev to create /dev/pi433 */
> >
> > +static struct dentry *dbgfs_root_entry;
>
> There is no need for this dentry. Just look it up if you care about it.
>
> > +
> > /*
> > * tx config is instance specific
> > * so with each open a new tx config struct is needed
> > @@ -103,6 +108,9 @@ struct pi433_device {
> > bool rx_active;
> > bool tx_active;
> > bool interrupt_rx_allowed;
> > +
> > + /* debug fs */
> > + struct dentry *entry;
>
> Again, no need for this, look it up if you need it.
>
> > };
> >
> > struct pi433_instance {
> > @@ -1102,6 +1110,72 @@ static const struct file_operations pi433_fops = {
> > .llseek = no_llseek,
> > };
> >
> > +static int pi433_debugfs_regs_show(struct seq_file *m, void *p)
> > +{
> > + struct pi433_device *dev;
> > + u8 reg_data[114];
> > + size_t i;
> > + char *fmt = "0x%02x, 0x%02x\n";
> > +
> > + // obtain pi433_device reference
> > + dev = m->private;
>
> That is not a "reference", that is just a normal empty pointer. No need
> to call it something else, that's just confusing.
>
> > +
> > + // acquire locks to avoid race conditions
> > + mutex_lock(&dev->tx_fifo_lock);
> > + mutex_lock(&dev->rx_lock);
> > +
> > + // wait for on-going operations to finish
> > + if (dev->tx_active)
> > + wait_event_interruptible(dev->rx_wait_queue, !dev->tx_active);
> > +
> > + if (dev->rx_active)
> > + wait_event_interruptible(dev->tx_wait_queue, !dev->rx_active);
> > +
> > + // read contiguous regs
> > + // skip FIFO register (0x0) otherwise this can affect some of uC ops
> > + for (i = 1; i < 0x50; i++)
> > + reg_data[i] = rf69_read_reg(dev->spi, i);
> > +
> > + // read non-contiguous regs
> > + reg_data[REG_TESTLNA] = rf69_read_reg(dev->spi, REG_TESTLNA);
> > + reg_data[REG_TESTPA1] = rf69_read_reg(dev->spi, REG_TESTPA1);
> > + reg_data[REG_TESTPA2] = rf69_read_reg(dev->spi, REG_TESTPA2);
> > + reg_data[REG_TESTDAGC] = rf69_read_reg(dev->spi, REG_TESTDAGC);
> > + reg_data[REG_TESTAFC] = rf69_read_reg(dev->spi, REG_TESTAFC);
> > +
> > + seq_puts(m, "# reg, val\n");
> > +
> > + // print contiguous regs
> > + for (i = 1; i < 0x50; i++)
> > + seq_printf(m, fmt, i, reg_data[i]);
> > +
> > + // print non-contiguous regs
> > + seq_printf(m, fmt, REG_TESTLNA, reg_data[REG_TESTLNA]);
> > + seq_printf(m, fmt, REG_TESTPA1, reg_data[REG_TESTPA1]);
> > + seq_printf(m, fmt, REG_TESTPA2, reg_data[REG_TESTPA2]);
> > + seq_printf(m, fmt, REG_TESTDAGC, reg_data[REG_TESTDAGC]);
> > + seq_printf(m, fmt, REG_TESTAFC, reg_data[REG_TESTAFC]);
> > +
> > + // release locks
> > + mutex_unlock(&dev->tx_fifo_lock);
> > + mutex_unlock(&dev->rx_lock);
> > +
> > + return 0;
> > +}
> > +
> > +static ssize_t pi433_debugfs_regs_open(struct inode *inode, struct file *filp)
> > +{
> > + return single_open(filp, pi433_debugfs_regs_show, inode->i_private);
> > +}
> > +
> > +static const struct file_operations debugfs_fops = {
> > + .llseek = seq_lseek,
> > + .open = pi433_debugfs_regs_open,
> > + .owner = THIS_MODULE,
> > + .read = seq_read,
> > + .release = single_release
> > +};
> > +
> > /*-------------------------------------------------------------------------*/
> >
> > static int pi433_probe(struct spi_device *spi)
> > @@ -1256,6 +1330,10 @@ static int pi433_probe(struct spi_device *spi)
> > /* spi setup */
> > spi_set_drvdata(spi, device);
> >
> > + /* debugfs setup */
> > + device->entry = debugfs_create_dir(dev_name(device->dev), dbgfs_root_entry);
>
> Make "entry" a local variable, and then pass it to the next call.
>
> And look up dbgfs_root_entry as well. This can be rewritten as:
> entry = debugfs_create_dir(dev_name(device->dev,
> debugfs_lookup("pi433", NULL);
>
> > + debugfs_create_file("regs", 0400, device->entry, device, &debugfs_fops);
>
> When do you ever remove the debugfs entry for the device? I do not see
> that in any release function here. Did you forget about that?
>
> > +
> > return 0;
> >
> > del_cdev:
> > @@ -1353,6 +1431,8 @@ static int __init pi433_init(void)
> > return PTR_ERR(pi433_class);
> > }
> >
> > + dbgfs_root_entry = debugfs_create_dir("pi433", NULL);
>
> Again, no need to keep this around, see above.
>
> > +
> > status = spi_register_driver(&pi433_spi_driver);
> > if (status < 0) {
> > class_destroy(pi433_class);
> > @@ -1370,6 +1450,8 @@ static void __exit pi433_exit(void)
> > spi_unregister_driver(&pi433_spi_driver);
> > class_destroy(pi433_class);
> > unregister_chrdev(MAJOR(pi433_dev), pi433_spi_driver.driver.name);
> > + debugfs_remove_recursive(dbgfs_root_entry);
>
> Can be rewritten as:
> debugfs_remove_recursive(debugfs_lookup("pi433", NULL));
>
> Or better yet:
> debugfs_remove_recursive(debugfs_lookup(KBUILD_MODULE_NAME, NULL));
>
> thanks,
>
> greg k-h
thanks for taking the time to review this patchset.
you are right, I will make the changes you pointed out and submit a new
version of the patchset shortly.
thanks,
Paulo Almeida