RE: [RFC 4/6] omap: introduce common remoteproc module

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

 



> -----Original Message-----
> From: linux-omap-owner@xxxxxxxxxxxxxxx
> [mailto:linux-omap-owner@xxxxxxxxxxxxxxx] On Behalf Of Ohad Ben-Cohen
> Sent: Friday, July 02, 2010 3:53 AM
> To: linux-omap@xxxxxxxxxxxxxxx
> Cc: Kanigeri, Hari; Ben-cohen, Ohad
> Subject: [RFC 4/6] omap: introduce common remoteproc module
>
> From: Ohad Ben-Cohen <ohadb@xxxxxx>
>
> The OMAP remote processor module decouples
> machine-specific code from TI's IPC
> drivers (e.g. dspbridge and syslink).
>
> While dspbridge calls the remoteproc handlers
> from the kernel, syslink calls them from
> user space. Hence remoteproc supports both
> interfaces.
>
> Signed-off-by: Ohad Ben-Cohen <ohadb@xxxxxx>
> Signed-off-by: Hari Kanigeri <h-kanigeri2@xxxxxx>
> ---
>  arch/arm/plat-omap/include/plat/remoteproc.h |   75 ++++++
>  arch/arm/plat-omap/remoteproc.c              |  316
> ++++++++++++++++++++++++++
>  2 files changed, 391 insertions(+), 0 deletions(-)
>  create mode 100644 arch/arm/plat-omap/include/plat/remoteproc.h
>  create mode 100644 arch/arm/plat-omap/remoteproc.c
>
> diff --git a/arch/arm/plat-omap/include/plat/remoteproc.h
> b/arch/arm/plat-omap/include/plat/remoteproc.h
> new file mode 100644
> index 0000000..1cedd08
> --- /dev/null
> +++ b/arch/arm/plat-omap/include/plat/remoteproc.h
> @@ -0,0 +1,75 @@
> +/*
> + * OMAP Remote Processor driver
> + *
> + * Copyright (C) 2010 Texas Instruments Inc.
> + *
> + * Written by Ohad Ben-Cohen <ohad@xxxxxxxxxx>
> + *
> + * This program is free software; you can redistribute it and/or
> + * modify it under the terms of the GNU General Public License
> + * version 2 as published by the Free Software Foundation.
> + *
> + * This program is distributed in the hope that 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, write to the Free Software
> + * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
> + * 02110-1301 USA
> + *
> + */
> +
> +#ifndef REMOTEPROC_H
> +#define REMOTEPROC_H
> +
> +#include <linux/ioctl.h>
> +#include <linux/cdev.h>
> +
> +#define RPROC_IOC_MAGIC              'P'

[sp] I notice that there is already a conflict with this magic number in
     Documentation/ioctl/ioctl-number.txt.

     Suggest reserving a different code as per the steps mentioned in the
     same file.

> +
> +#define RPROC_IOCSTART               _IOW(RPROC_IOC_MAGIC, 1, int)
> +#define RPROC_IOCSTOP                _IO(RPROC_IOC_MAGIC, 2)
> +#define RPROC_IOCGETSTATE    _IOR(RPROC_IOC_MAGIC, 3, int)
> +
> +#define RPROC_IOC_MAXNR              (3)
> +
> +struct omap_rproc;
> +
> +struct omap_rproc_ops {
> +     int (*start)(struct device *dev, u32 start_addr);
> +     int (*stop)(struct device *dev);
> +     int (*get_state)(struct device *dev);
> +};
> +
> +struct omap_rproc_clk_t {
> +     void *clk_handle;
> +     const char *dev_id;
> +     const char *con_id;
> +};
> +

[sp] Small description of the fields in the structure will help understand the code better.
     I couldn't locate usage of con_id in this patch; not sure what it signifies.
     ...hope it becomes clear in one of the other patches in the series.
     (after one review) The structure is not used anywhere in this file.

> +struct omap_rproc_platform_data {
> +     struct omap_rproc_ops *ops;
> +     char *name;
> +     char *oh_name;
> +};

[sp] same comment here.

> +
> +struct omap_rproc {
> +     struct device *dev;
> +     struct cdev cdev;
> +     atomic_t count;

[sp] I believe this field is for "use-counts". If so, suggest renaming to
     "usecount".

> +     int minor;
> +};
> +
> +struct omap_rproc_start_args {
> +     u32 start_addr;
> +};
> +
> +struct omap_rproc_platform_data *omap3_get_rproc_data(void);
> +int omap3_get_rproc_data_size(void);
> +struct omap_rproc_platform_data *omap4_get_rproc_data(void);
> +int omap4_get_rproc_data_size(void);
[sp] The forward declaration seems to be used for plugging
     device specific data (haven't looked at complet code, so
     it is currently a speculation).

     The contents of this header have so far been device independent.
     Can we look to reorganiza this code such that this header remains
     generic?

> +int omap_get_num_of_remoteproc(void);

[sp] Don't see this being implemented in the "C" file below.
     If this function is expected to be implemented in the omap3/4
     specific file, then I suspect multi-omap will break for compilation.
     Same function will be defined multiple times.

> +
> +#endif /* REMOTEPROC_H */
> diff --git a/arch/arm/plat-omap/remoteproc.c
> b/arch/arm/plat-omap/remoteproc.c
> new file mode 100644
> index 0000000..7a9862e
> --- /dev/null
> +++ b/arch/arm/plat-omap/remoteproc.c
> @@ -0,0 +1,316 @@
> +/*
> + * OMAP Remote Processor driver
> + *
> + * Copyright (C) 2010 Texas Instruments Inc.
> + *
> + * Authors:
> + * Ohad Ben-Cohen <ohad@xxxxxxxxxx>
> + * Hari Kanigeri <h-kanigeri2@xxxxxx>
> + *
> + * This program is free software; you can redistribute it and/or
> + * modify it under the terms of the GNU General Public License
> + * version 2 as published by the Free Software Foundation.
> + *
> + * This program is distributed in the hope that 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, write to the Free Software
> + * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
> + * 02110-1301 USA
> + *
> + */
> +
> +#include <linux/kernel.h>
> +#include <linux/module.h>
> +#include <linux/interrupt.h>
> +#include <linux/device.h>
> +#include <linux/delay.h>
> +#include <linux/file.h>
> +#include <linux/poll.h>
> +#include <linux/mm.h>
> +#include <linux/platform_device.h>
> +
> +#include <plat/remoteproc.h>
> +
> +#define OMAP_RPROC_NAME "omap-rproc"

[sp] See my comment in 0/6 about "omap-" prefix in the name.

     BTW, I am reviewing this file from bottom; so comments may not be
     in sequence.

> +
> +static struct class *omap_rproc_class;
> +static dev_t omap_rproc_dev;
> +static atomic_t num_of_rprocs;
> +
> +static inline int rproc_start(struct omap_rproc *rproc,
> const void __user *arg)
> +{
> +     struct omap_rproc_platform_data *pdata;
> +     struct omap_rproc_start_args start_args;
> +
> +     if (!rproc->dev)
> +             return -EINVAL;
> +
> +     pdata = rproc->dev->platform_data;
> +     if (!pdata->ops)
> +             return -EINVAL;
> +
> +     if (copy_from_user(&start_args, arg, sizeof(start_args)))
> +             return -EFAULT;
> +
> +     return pdata->ops->start(rproc->dev, start_args.start_addr);
> +}
> +
> +static inline int rproc_stop(struct omap_rproc *rproc)
> +{
> +     struct omap_rproc_platform_data *pdata;
> +     if (!rproc->dev)
> +             return -EINVAL;
> +
> +     pdata = rproc->dev->platform_data;
> +     if (!pdata->ops)
> +             return -EINVAL;
> +
> +     return pdata->ops->stop(rproc->dev);
> +}
> +
> +static inline int rproc_get_state(struct omap_rproc *rproc)
> +{
> +     struct omap_rproc_platform_data *pdata;
> +     if (!rproc->dev)
> +             return -EINVAL;
> +
> +     pdata = rproc->dev->platform_data;
> +     if (!pdata->ops)
> +             return -EINVAL;
> +
> +     return pdata->ops->get_state(rproc->dev);
> +}
> +
> +static int omap_rproc_open(struct inode *inode, struct file *filp)

[sp] May be nitpicking, but "filp" could simply be "fp" ... more common
     in usage for file pointer.

> +{
> +     unsigned int count, dev_num = iminor(inode);
> +     struct omap_rproc *rproc;
> +     struct omap_rproc_platform_data *pdata;
> +
> +     rproc = container_of(inode->i_cdev, struct omap_rproc, cdev);
> +     if (!rproc->dev)
> +             return -EINVAL;
> +
> +     pdata = rproc->dev->platform_data;
> +
> +     count = atomic_inc_return(&rproc->count);

[sp] Wouldn't atomic_read() be better used here?
     Avoids the need to call atomic_dec() below.

> +     dev_info(rproc->dev, "%s: dev num %d, name %s, count
> %d\n", __func__,
> +                                                     dev_num,
> +                                                     pdata->name,
> +                                                     count);
> +     if (count > 1) {
> +             dev_err(rproc->dev, "%s failed: remoteproc
> already in use\n",
> +
> __func__);
> +             atomic_dec(&rproc->count);
> +             return -EBUSY;
> +     }
> +
> +     filp->private_data = rproc;
> +
> +     return 0;
> +}
> +
> +static int omap_rproc_release(struct inode *inode, struct file *filp)
> +{
> +     struct omap_rproc_platform_data *pdata;
> +     struct omap_rproc *rproc = filp->private_data;
> +     if (!rproc || !rproc->dev)
> +             return -EINVAL;
> +
> +     pdata = rproc->dev->platform_data;
> +
> +     atomic_dec(&rproc->count);
> +
> +     return 0;
> +}
> +
> +static int omap_rproc_ioctl(struct inode *inode, struct file *filp,
> +                                     unsigned int cmd,
> unsigned long arg)
> +{
> +     int rc = 0;
> +     struct omap_rproc *rproc = filp->private_data;
> +
> +     dev_info(rproc->dev, "%s\n", __func__);
> +
> +     if (!rproc)
> +             return -EINVAL;
> +
> +     if (_IOC_TYPE(cmd) != RPROC_IOC_MAGIC)
> +             return -ENOTTY;
> +     if (_IOC_NR(cmd) > RPROC_IOC_MAXNR)
> +             return -ENOTTY;
> +
> +     switch (cmd) {
> +     case RPROC_IOCSTART:
> +             if (!capable(CAP_SYS_ADMIN))
> +                     return -EPERM;
> +             rc = rproc_start(rproc, (const void __user *) arg);
> +             break;
> +     case RPROC_IOCSTOP:
> +             if (!capable(CAP_SYS_ADMIN))
> +                     return -EPERM;
> +             rc = rproc_stop(rproc);
> +             break;
> +     case RPROC_IOCGETSTATE:
> +             rc = rproc_get_state(rproc);
> +             break;
> +
> +     default:
> +             return -ENOTTY;
> +     }
> +
> +     return rc;

[sp] Most of the functions in this file use "ret" as variable for
     return value. Here "rc" seems to out of place... significance
     didn't click to me immediately.

> +}
> +
> +static const struct file_operations omap_rproc_fops = {
> +     .open           =       omap_rproc_open,
> +     .release        =       omap_rproc_release,
> +     .ioctl          =       omap_rproc_ioctl,
> +     .owner          =       THIS_MODULE,
> +};
> +
> +static int omap_rproc_probe(struct platform_device *pdev)

[sp] Shouldn't this be __devinit ?

> +{
> +     int ret = 0, major, minor;
> +     struct device *tmpdev;
> +     struct device *dev = &pdev->dev;
> +     struct omap_rproc_platform_data *pdata = dev->platform_data;
> +     struct omap_rproc *rproc;
> +
> +     if (!pdata || !pdata->name || !pdata->oh_name || !pdata->ops)
> +             return -EINVAL;
> +
> +     dev_info(dev, "%s: adding rproc %s\n", __func__, pdata->name);
> +
> +     rproc = kzalloc(sizeof(struct omap_rproc), GFP_KERNEL);
[sp] any specific reason to not use kmalloc instead?

> +     if (!rproc) {
> +             dev_err(dev, "%s: kzalloc failed\n", __func__);
> +             ret = -ENOMEM;
> +             goto out;
> +     }
> +
> +     platform_set_drvdata(pdev, rproc);
> +     major = MAJOR(omap_rproc_dev);
> +     minor = atomic_read(&num_of_rprocs);
> +     atomic_inc(&num_of_rprocs);
> +
> +     rproc->dev = dev;
> +     rproc->minor = minor;
> +     atomic_set(&rproc->count, 0);
> +     cdev_init(&rproc->cdev, &omap_rproc_fops);

[sp] Character driver under directory "arch/arm/plat-omap" ?
     Shouldn't this driver be elsewhere? In fact, it will
     help make it usable for non-OMAP devices as well.

> +     rproc->cdev.owner = THIS_MODULE;
> +     ret = cdev_add(&rproc->cdev, MKDEV(major, minor), 1);
> +     if (ret) {
> +             dev_err(dev, "%s: cdev_add failed: %d\n",
> __func__, ret);
> +             goto free_rproc;
> +     }
> +
> +     tmpdev = device_create(omap_rproc_class, NULL,
> +                             MKDEV(major, minor),
> +                             NULL,
> +                             OMAP_RPROC_NAME "%d", minor);
> +     if (IS_ERR(tmpdev)) {
> +             ret = PTR_ERR(tmpdev);
> +             dev_err(dev, "%s: device_create failed: %d\n",
> __func__, ret);
> +             goto clean_cdev;
> +     }
> +
> +     dev_info(dev, "%s initialized %s, major: %d, base-minor: %d\n",
> +                     OMAP_RPROC_NAME,
> +                     pdata->name,
> +                     MAJOR(omap_rproc_dev),
> +                     minor);
> +     return 0;
> +
> +clean_cdev:
> +     cdev_del(&rproc->cdev);
> +free_rproc:
> +     kfree(rproc);
> +out:
> +     return ret;
> +}
> +
> +static int __devexit omap_rproc_remove(struct platform_device *pdev)
> +{
> +     int major = MAJOR(omap_rproc_dev);
> +     struct device *dev = &pdev->dev;
> +     struct omap_rproc_platform_data *pdata = dev->platform_data;
> +     struct omap_rproc *rproc = platform_get_drvdata(pdev);
> +
> +     if (!pdata || !rproc)
> +             return -EINVAL;
> +
> +     dev_info(dev, "%s removing %s, major: %d, base-minor: %d\n",
> +                     OMAP_RPROC_NAME,
> +                     pdata->name,
> +                     major,
> +                     rproc->minor);
> +
> +     device_destroy(omap_rproc_class, MKDEV(major, rproc->minor));
> +     cdev_del(&rproc->cdev);
> +
> +     return 0;
> +}
> +
> +static struct platform_driver omap_rproc_driver = {
> +     .probe = omap_rproc_probe,
> +     .remove = __devexit_p(omap_rproc_remove),
> +     .driver = {
> +             .name = OMAP_RPROC_NAME,
> +             .owner = THIS_MODULE,
> +     },
> +};
> +
> +static int __init omap_rproc_init(void)
> +{
> +     int num = omap_get_num_of_remoteproc();
> +     int ret;
> +
> +     ret = alloc_chrdev_region(&omap_rproc_dev, 0, num,
> OMAP_RPROC_NAME);
> +     if (ret) {
> +             pr_err("%s: alloc_chrdev_region failed: %d\n",
> __func__, ret);
> +             goto out;
> +     }
> +
> +     omap_rproc_class = class_create(THIS_MODULE, OMAP_RPROC_NAME);
> +     if (IS_ERR(omap_rproc_class)) {
> +             ret = PTR_ERR(omap_rproc_class);
> +             pr_err("%s: class_create failed: %d\n", __func__, ret);
> +             goto unreg_region;
> +     }
> +
> +     atomic_set(&num_of_rprocs, 0);

[sp] In the beginning of function "num" is expected to contain
     number of remote processors - going by the function name.

     Any specific reason for setting this variable to "0" which
     again seem to signify the same.

     There may be a reason; but it isn't clear here.

> +
> +     ret = platform_driver_register(&omap_rproc_driver);
> +     if (ret) {
> +             pr_err("%s: platform_driver_register failed:
> %d\n", __func__,
> +
>       ret);
> +             goto out;
> +     }
> +
> +     return 0;
> +
> +unreg_region:
> +     unregister_chrdev_region(omap_rproc_dev, num);
> +out:
> +     return ret;
> +}
> +module_init(omap_rproc_init);
> +
> +static void __exit omap_rproc_exit(void)
> +{
> +     int num = omap_get_num_of_remoteproc();

[sp] Why not use variable "num_of_rprocs" instead
     of fetching the value again?

     (after one review cycle) I see that you are using
     this variable to track the num of "open" active
     remote processors - not the total num. Renaming
     the variable appropriately will help.

> +
> +     class_destroy(omap_rproc_class);
> +     unregister_chrdev_region(omap_rproc_dev, num);
> +}
> +module_exit(omap_rproc_exit);
> +
> +MODULE_LICENSE("GPL v2");
> +MODULE_DESCRIPTION("OMAP Remote Processor driver");
> +MODULE_AUTHOR("Ohad Ben-Cohen <ohad@xxxxxxxxxx>");
> +MODULE_AUTHOR("Hari Kanigeri <h-kanigeri2@xxxxxx>");
> --
> 1.7.0.4
>
> --
> To unsubscribe from this list: send the line "unsubscribe
> linux-omap" in
> the body of a message to majordomo@xxxxxxxxxxxxxxx
> More majordomo info at  http://vger.kernel.org/majordomo-info.html
>
--
To unsubscribe from this list: send the line "unsubscribe linux-omap" in
the body of a message to majordomo@xxxxxxxxxxxxxxx
More majordomo info at  http://vger.kernel.org/majordomo-info.html


[Index of Archives]     [Linux Arm (vger)]     [ARM Kernel]     [ARM MSM]     [Linux Tegra]     [Linux WPAN Networking]     [Linux Wireless Networking]     [Maemo Users]     [Linux USB Devel]     [Video for Linux]     [Linux Audio Users]     [Yosemite Trails]     [Linux Kernel]     [Linux SCSI]

  Powered by Linux