Re: [PATCH v8 2/2] tty: add rpmsg driver

From: Arnaud POULIQUEN
Date: Tue Oct 05 2021 - 12:03:39 EST


Hello Greg,

On 10/5/21 2:59 PM, Greg Kroah-Hartman wrote:
> On Thu, Sep 30, 2021 at 06:05:20PM +0200, Arnaud Pouliquen wrote:
>> This driver exposes a standard TTY interface on top of the rpmsg
>> framework through a rpmsg service.
>>
>> This driver supports multi-instances, offering a /dev/ttyRPMSGx entry
>> per rpmsg endpoint.
>>
>> Signed-off-by: Arnaud Pouliquen <arnaud.pouliquen@xxxxxxxxxxx>
>> ---
>> Documentation/serial/tty_rpmsg.rst | 15 ++
>> drivers/tty/Kconfig | 9 +
>> drivers/tty/Makefile | 1 +
>> drivers/tty/rpmsg_tty.c | 275 +++++++++++++++++++++++++++++
>> 4 files changed, 300 insertions(+)
>> create mode 100644 Documentation/serial/tty_rpmsg.rst
>> create mode 100644 drivers/tty/rpmsg_tty.c
>>
>> diff --git a/Documentation/serial/tty_rpmsg.rst b/Documentation/serial/tty_rpmsg.rst
>> new file mode 100644
>> index 000000000000..b055107866c9
>> --- /dev/null
>> +++ b/Documentation/serial/tty_rpmsg.rst
>> @@ -0,0 +1,15 @@
>> +.. SPDX-License-Identifier: GPL-2.0
>> +
>> +=========
>> +RPMsg TTY
>> +=========
>> +
>> +The rpmsg tty driver implements serial communication on the RPMsg bus to makes possible for
>> +user-space programs to send and receive rpmsg messages as a standard tty protocol.
>> +
>> +The remote processor can instantiate a new tty by requesting a "rpmsg-tty" RPMsg service.
>> +
>> +The "rpmsg-tty" service is directly used for data exchange. No flow control is implemented.
>> +
>> +Information related to the RPMsg and associated tty device is available in
>> +/sys/bus/rpmsg/devices/.
>
>
> Why is this file needed? Nothing references it, and this would be the
> only file in this directory.

This file is created by the RPMsg framework, it allows to have information about
RPMsg endpoint addresses associated to the rpmsg tty service instance.
I can add this additional information to clarify the sentence.

>
>> diff --git a/drivers/tty/Kconfig b/drivers/tty/Kconfig
>> index 23cc988c68a4..5095513029d7 100644
>> --- a/drivers/tty/Kconfig
>> +++ b/drivers/tty/Kconfig
>> @@ -368,6 +368,15 @@ config VCC
>>
>> source "drivers/tty/hvc/Kconfig"
>>
>> +config RPMSG_TTY
>> + tristate "RPMSG tty driver"
>> + depends on RPMSG
>> + help
>> + Say y here to export rpmsg endpoints as tty devices, usually found
>> + in /dev/ttyRPMSGx.
>> + This makes it possible for user-space programs to send and receive
>> + rpmsg messages as a standard tty protocol.
>
> What is the module name going to be?

I will add information

>
>
>> +
>> endif # TTY
>>
>> source "drivers/tty/serdev/Kconfig"
>> diff --git a/drivers/tty/Makefile b/drivers/tty/Makefile
>> index a2bd75fbaaa4..07aca5184a55 100644
>> --- a/drivers/tty/Makefile
>> +++ b/drivers/tty/Makefile
>> @@ -26,5 +26,6 @@ obj-$(CONFIG_PPC_EPAPR_HV_BYTECHAN) += ehv_bytechan.o
>> obj-$(CONFIG_GOLDFISH_TTY) += goldfish.o
>> obj-$(CONFIG_MIPS_EJTAG_FDC_TTY) += mips_ejtag_fdc.o
>> obj-$(CONFIG_VCC) += vcc.o
>> +obj-$(CONFIG_RPMSG_TTY) += rpmsg_tty.o
>>
>> obj-y += ipwireless/
>> diff --git a/drivers/tty/rpmsg_tty.c b/drivers/tty/rpmsg_tty.c
>> new file mode 100644
>> index 000000000000..0c99f54c2911
>> --- /dev/null
>> +++ b/drivers/tty/rpmsg_tty.c
>> @@ -0,0 +1,275 @@
>> +// SPDX-License-Identifier: GPL-2.0
>> +/*
>> + * Copyright (C) STMicroelectronics 2021 - All Rights Reserved
>
> Copyright needs a year, right?

The year is present, but indicated after the company, to inverse

>
>> + */
>> +
>> +#include <linux/module.h>
>> +#include <linux/rpmsg.h>
>> +#include <linux/slab.h>
>> +#include <linux/tty.h>
>> +#include <linux/tty_flip.h>
>> +
>> +#define MAX_TTY_RPMSG 32
>
> Why have a max at all?

This is linked to tty_alloc_driver in the module init
It is multi instance but need pre-allocation.
I did not find a proper way to do this. Any suggestion is welcome.

>
>
>> +
>> +static DEFINE_IDR(tty_idr); /* tty instance id */
>> +static DEFINE_MUTEX(idr_lock); /* protects tty_idr */
>
> I didn't think an idr needed a lock anymore, are you sure this is
> needed?

recognized in ird_alloc header for multi instance:
https://elixir.bootlin.com/linux/v5.15-rc1/source/lib/idr.c#L60

>
>
>> +
>> +static struct tty_driver *rpmsg_tty_driver;
>> +
>> +struct rpmsg_tty_port {
>> + struct tty_port port; /* TTY port data */
>> + int id; /* TTY rpmsg index */
>> + struct rpmsg_device *rpdev; /* rpmsg device */
>> +};
>> +
>> +static int rpmsg_tty_cb(struct rpmsg_device *rpdev, void *data, int len, void *priv, u32 src)
>> +{
>> + struct rpmsg_tty_port *cport = dev_get_drvdata(&rpdev->dev);
>> + int copied;
>> +
>> + if (!len)
>> + return -EINVAL;
>
> How can len be 0?

In the RPMsg framework, nothing prevents a RPMsg with len = 0 (means header with
no payload).
It should be possible that the remote processor firmware bug generates such message.

>
>
>> + copied = tty_insert_flip_string(&cport->port, data, len);
>> + if (copied != len)
>> + dev_dbg(&rpdev->dev, "Trunc buffer: available space is %d\n",
>> + copied);
>
> Is this the proper error handling?

Right, as a part of the message is lost, should be an error.

>
>
>> + tty_flip_buffer_push(&cport->port);
>
> Shouldn't you return the number of bytes sent?

For the RPMsg framework you mean? No, because for another RPMsg services, it
might not make sense. Return 0 seems to me more generic.
In any case today the RPMsg framework doesn't test the callback return,
associated action would depend on the service.

>
>> +
>> + return 0;
>> +}
>> +
>> +static int rpmsg_tty_install(struct tty_driver *driver, struct tty_struct *tty)
>> +{
>> + struct rpmsg_tty_port *cport = idr_find(&tty_idr, tty->index);
>> +
>> + if (!cport) {
>> + dev_err(tty->dev, "Cannot get cport\n");
>
> How can this happen?

Right over protection!

>
>
>> + return -ENODEV;
>> + }
>> +
>> + tty->driver_data = cport;
>> +
>> + return tty_port_install(&cport->port, driver, tty);
>> +}
>> +
>> +static int rpmsg_tty_open(struct tty_struct *tty, struct file *filp)
>> +{
>> + return tty_port_open(tty->port, tty, filp);
>> +}
>> +
>> +static void rpmsg_tty_close(struct tty_struct *tty, struct file *filp)
>> +{
>> + return tty_port_close(tty->port, tty, filp);
>> +}
>> +
>> +static int rpmsg_tty_write(struct tty_struct *tty, const u8 *buf, int len)
>> +{
>> + struct rpmsg_tty_port *cport = tty->driver_data;
>> + struct rpmsg_device *rpdev;
>> + int msg_max_size, msg_size;
>> + int ret;
>> +
>> + rpdev = cport->rpdev;
>> +
>> + dev_dbg(&rpdev->dev, "Send msg from tty->index = %d, len = %d\n", tty->index, len);
>
> ftrace is your friend, is this really still needed?
>

Yes, but unfortunately not the friend of all our customers :)
I will clean this log. The RPMsg dynamic traces already allows to trace the
messages, which should be enough for a first level of debug.

I will send a new revision integrating your comments.

Thanks & Regards,
Arnaud

> thanks,
>
> greg k-h
>