Re: [PATCH v2 1/2] remoteproc: Add character device interface

From: Mathieu Poirier
Date: Fri Apr 03 2020 - 16:30:47 EST


On Thu, 2 Apr 2020 at 11:28, Arnaud POULIQUEN <arnaud.pouliquen@xxxxxx> wrote:
>
> Hi
>
> On 4/1/20 2:03 AM, Rishabh Bhatnagar wrote:
> > Add the character device interface for userspace applications.
> > This interface can be used in order to boot up and shutdown
> > remote subsystems. Currently there is only a sysfs interface
> > which the userspace clients can use. If a usersapce application
> > crashes after booting the remote processor does not get any
> > indication about the crash. It might still assume that the
> > application is running. For example modem uses remotefs service
> > to fetch data from disk/flash memory. If the remotefs service
> > crashes, modem keeps on requesting data which might lead to a
> > crash. Adding a character device interface makes the remote
> > processor tightly coupled with the user space application.
> > A crash of the application leads to a close on the file descriptors
> > therefore shutting down the remoteproc.
>
> Sorry I'm late in the discussion, I hope I've gone through the whole
> discussion so I don't reopen a closed point...
>
> Something here is not crystal clear to me so I'd rather share it...
>
> I suppose that you the automatic restart of the application is not possible to
> stop and restart the remote processor...
>
> Why this use case can not be solved by a process monitor or a service
> in userland that detects the application crash and stop the remote firmware using
> the sysfs interface?

I also looked for a better way to do things... The conclusion I came
to is that it may take too long between the application crash and the
monitoring service to stop the firmware via sysfs.

>
> I just want to be sure that there is no alternative to this, because having two ways
> for application to shutdown the firmware seems to me confusing...
>
> What about the opposite service, mean inform the application that the remote
> processor is crashed?

Also a valid point - the problem with asynchronous notification
schemes is the possibility to get out of sync. I would also like to
find a better way...

> Do you identify such need? or the "auto" crash recovery is sufficient?
>
> Thanks,
> Arnaud
> >
> > Signed-off-by: Rishabh Bhatnagar <rishabhb@xxxxxxxxxxxxxx>
> > ---
> > drivers/remoteproc/Kconfig | 9 +++
> > drivers/remoteproc/Makefile | 1 +
> > drivers/remoteproc/remoteproc_cdev.c | 100 +++++++++++++++++++++++++++++++
> > drivers/remoteproc/remoteproc_internal.h | 22 +++++++
> > include/linux/remoteproc.h | 2 +
> > 5 files changed, 134 insertions(+)
> > create mode 100644 drivers/remoteproc/remoteproc_cdev.c
> >
> > diff --git a/drivers/remoteproc/Kconfig b/drivers/remoteproc/Kconfig
> > index de3862c..6374b79 100644
> > --- a/drivers/remoteproc/Kconfig
> > +++ b/drivers/remoteproc/Kconfig
> > @@ -14,6 +14,15 @@ config REMOTEPROC
> >
> > if REMOTEPROC
> >
> > +config REMOTEPROC_CDEV
> > + bool "Remoteproc character device interface"
> > + help
> > + Say y here to have a character device interface for Remoteproc
> > + framework. Userspace can boot/shutdown remote processors through
> > + this interface.
> > +
> > + It's safe to say N if you don't want to use this interface.
> > +
> > config IMX_REMOTEPROC
> > tristate "IMX6/7 remoteproc support"
> > depends on ARCH_MXC
> > diff --git a/drivers/remoteproc/Makefile b/drivers/remoteproc/Makefile
> > index e30a1b1..b7d4f77 100644
> > --- a/drivers/remoteproc/Makefile
> > +++ b/drivers/remoteproc/Makefile
> > @@ -9,6 +9,7 @@ remoteproc-y += remoteproc_debugfs.o
> > remoteproc-y += remoteproc_sysfs.o
> > remoteproc-y += remoteproc_virtio.o
> > remoteproc-y += remoteproc_elf_loader.o
> > +obj-$(CONFIG_REMOTEPROC_CDEV) += remoteproc_cdev.o
> > obj-$(CONFIG_IMX_REMOTEPROC) += imx_rproc.o
> > obj-$(CONFIG_MTK_SCP) += mtk_scp.o mtk_scp_ipi.o
> > obj-$(CONFIG_OMAP_REMOTEPROC) += omap_remoteproc.o
> > diff --git a/drivers/remoteproc/remoteproc_cdev.c b/drivers/remoteproc/remoteproc_cdev.c
> > new file mode 100644
> > index 0000000..8182bd1
> > --- /dev/null
> > +++ b/drivers/remoteproc/remoteproc_cdev.c
> > @@ -0,0 +1,100 @@
> > +// SPDX-License-Identifier: GPL-2.0-only
> > +/*
> > + * Character device interface driver for Remoteproc framework.
> > + *
> > + * Copyright (c) 2020, The Linux Foundation. All rights reserved.
> > + */
> > +
> > +#include <linux/cdev.h>
> > +#include <linux/fs.h>
> > +#include <linux/module.h>
> > +#include <linux/mutex.h>
> > +#include <linux/remoteproc.h>
> > +
> > +#include "remoteproc_internal.h"
> > +
> > +#define NUM_RPROC_DEVICES 64
> > +static dev_t rproc_cdev;
> > +static DEFINE_IDA(cdev_minor_ida);
> > +
> > +static int rproc_cdev_open(struct inode *inode, struct file *file)
> > +{
> > + struct rproc *rproc;
> > +
> > + rproc = container_of(inode->i_cdev, struct rproc, char_dev);
> > +
> > + if (!rproc)
> > + return -EINVAL;
> > +
> > + if (rproc->state == RPROC_RUNNING)
> > + return -EBUSY;
> > +
> > + return rproc_boot(rproc);
> > +}
> > +
> > +static int rproc_cdev_release(struct inode *inode, struct file *file)
> > +{
> > + struct rproc *rproc;
> > +
> > + rproc = container_of(inode->i_cdev, struct rproc, char_dev);
> > +
> > + if (!rproc || rproc->state != RPROC_RUNNING)
> > + return -EINVAL;
> > +
> > + rproc_shutdown(rproc);
> > +
> > + return 0;
> > +}
> > +
> > +static const struct file_operations rproc_fops = {
> > + .open = rproc_cdev_open,
> > + .release = rproc_cdev_release,
> > +};
> > +
> > +int rproc_char_device_add(struct rproc *rproc)
> > +{
> > + int ret, minor;
> > + dev_t cdevt;
> > +
> > + minor = ida_simple_get(&cdev_minor_ida, 0, NUM_RPROC_DEVICES,
> > + GFP_KERNEL);
> > + if (minor < 0) {
> > + dev_err(&rproc->dev, "%s: No more minor numbers left! rc:%d\n",
> > + __func__, minor);
> > + return -ENODEV;
> > + }
> > +
> > + cdev_init(&rproc->char_dev, &rproc_fops);
> > + rproc->char_dev.owner = THIS_MODULE;
> > +
> > + cdevt = MKDEV(MAJOR(rproc_cdev), minor);
> > + ret = cdev_add(&rproc->char_dev, cdevt, 1);
> > + if (ret < 0)
> > + ida_simple_remove(&cdev_minor_ida, minor);
> > +
> > + rproc->dev.devt = cdevt;
> > + return ret;
> > +}
> > +
> > +void rproc_char_device_remove(struct rproc *rproc)
> > +{
> > + __unregister_chrdev(MAJOR(rproc->dev.devt), MINOR(rproc->dev.devt), 1,
> > + "rproc");
> > + ida_simple_remove(&cdev_minor_ida, MINOR(rproc->dev.devt));
> > +}
> > +
> > +void __init rproc_init_cdev(void)
> > +{
> > + int ret;
> > +
> > + ret = alloc_chrdev_region(&rproc_cdev, 0, NUM_RPROC_DEVICES, "rproc");
> > + if (ret < 0) {
> > + pr_err("Failed to alloc rproc_cdev region, err %d\n", ret);
> > + return;
> > + }
> > +}
> > +
> > +void __exit rproc_exit_cdev(void)
> > +{
> > + __unregister_chrdev(MAJOR(rproc_cdev), 0, NUM_RPROC_DEVICES, "rproc");
> > +}
> > diff --git a/drivers/remoteproc/remoteproc_internal.h b/drivers/remoteproc/remoteproc_internal.h
> > index 493ef92..28d61a1 100644
> > --- a/drivers/remoteproc/remoteproc_internal.h
> > +++ b/drivers/remoteproc/remoteproc_internal.h
> > @@ -47,6 +47,27 @@ struct dentry *rproc_create_trace_file(const char *name, struct rproc *rproc,
> > int rproc_init_sysfs(void);
> > void rproc_exit_sysfs(void);
> >
> > +#ifdef CONFIG_REMOTEPROC_CDEV
> > +void rproc_init_cdev(void);
> > +void rproc_exit_cdev(void);
> > +int rproc_char_device_add(struct rproc *rproc);
> > +void rproc_char_device_remove(struct rproc *rproc);
> > +#else
> > +static inline void rproc_init_cdev(void)
> > +{
> > +}
> > +static inline void rproc_exit_cdev(void)
> > +{
> > +}
> > +static inline int rproc_char_device_add(struct rproc *rproc)
> > +{
> > + return 0;
> > +}
> > +static inline void rproc_char_device_remove(struct rproc *rproc)
> > +{
> > +}
> > +#endif
> > +
> > void rproc_free_vring(struct rproc_vring *rvring);
> > int rproc_alloc_vring(struct rproc_vdev *rvdev, int i);
> >
> > @@ -63,6 +84,7 @@ struct resource_table *rproc_elf_find_loaded_rsc_table(struct rproc *rproc,
> > struct rproc_mem_entry *
> > rproc_find_carveout_by_name(struct rproc *rproc, const char *name, ...);
> >
> > +
> > static inline
> > int rproc_fw_sanity_check(struct rproc *rproc, const struct firmware *fw)
> > {
> > diff --git a/include/linux/remoteproc.h b/include/linux/remoteproc.h
> > index 16ad666..c4ca796 100644
> > --- a/include/linux/remoteproc.h
> > +++ b/include/linux/remoteproc.h
> > @@ -37,6 +37,7 @@
> >
> > #include <linux/types.h>
> > #include <linux/mutex.h>
> > +#include <linux/cdev.h>
> > #include <linux/virtio.h>
> > #include <linux/completion.h>
> > #include <linux/idr.h>
> > @@ -514,6 +515,7 @@ struct rproc {
> > bool auto_boot;
> > struct list_head dump_segments;
> > int nb_vdev;
> > + struct cdev char_dev;
> > };
> >
> > /**
> >