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

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

 



On 3/25/20 9:45 AM, Jiri Slaby wrote:
> On 24. 03. 20, 18:04, Arnaud Pouliquen wrote:
>> --- /dev/null
>> +++ b/drivers/tty/rpmsg_tty.c
>> @@ -0,0 +1,417 @@
>> +// SPDX-License-Identifier: GPL-2.0
>> +/*
>> + * Copyright (C) STMicroelectronics 2020 - All Rights Reserved
>> + * Authors: Arnaud Pouliquen <arnaud.pouliquen@xxxxxx> for STMicroelectronics.
>> + */
> ...
>> +typedef void (*rpmsg_tty_rx_cb_t)(struct rpmsg_device *, void *, int, void *,
>> +				  u32);
> 
> Unused, it seems?
> 
>> +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 (src == cport->data_dst) {
>> +		/* data message */
>> +		if (!len)
>> +			return -EINVAL;
>> +		copied = tty_insert_flip_string_fixed_flag(&cport->port, data,
>> +							   TTY_NORMAL, len);
> 
> Provided you always pass TTY_NORMAL, why not simply call
> tty_insert_flip_string instead?
> 
>> +		if (copied != len)
>> +			dev_dbg(&rpdev->dev, "trunc buffer: available space is %d\n",
>> +				copied);
>> +		tty_flip_buffer_push(&cport->port);
>> +	} else {
>> +		/* control message */
>> +		struct rpmsg_tty_ctrl *msg = data;
>> +
>> +		if (len != sizeof(*msg))
>> +			return -EINVAL;
>> +
>> +		cport->data_dst = msg->d_ept_addr;
>> +
>> +		/* Update remote cts state */
>> +		cport->cts = msg->cts ? 1 : 0;
> 
> Number to bool implicit conversion needs no magic, just do:
> cport->cts = msg->cts;

In this case i would prefer  cport->cts = (msg->cts != 1);
for the conversion

> 
>> +		if (cport->cts)
>> +			tty_port_tty_wakeup(&cport->port);
>> +	}
>> +
>> +	return 0;
>> +}
>> +
>> +static void rpmsg_tty_send_term_ready(struct tty_struct *tty, u8 state)
> 
> Should the state be bool? Should it be named "ready" instead?
> 
>> +{
>> +	struct rpmsg_tty_port *cport = tty->driver_data;
>> +	struct rpmsg_tty_ctrl m_ctrl;
>> +	int ret;
>> +
>> +	m_ctrl.cts = state;
>> +	m_ctrl.d_ept_addr = cport->d_ept->addr;
>> +
>> +	ret = rpmsg_trysend(cport->cs_ept, &m_ctrl, sizeof(m_ctrl));
>> +	if (ret < 0)
>> +		dev_dbg(tty->dev, "cannot send control (%d)\n", ret);
>> +};
>> +
>> +static void rpmsg_tty_throttle(struct tty_struct *tty)
>> +{
>> +	struct rpmsg_tty_port *cport = tty->driver_data;
>> +
>> +	/* Disable remote transmission */
>> +	if (cport->cs_ept)
>> +		rpmsg_tty_send_term_ready(tty, 0);
> 
> then s/0/false/;
> 
>> +};
>> +
>> +static void rpmsg_tty_unthrottle(struct tty_struct *tty)
>> +{
>> +	struct rpmsg_tty_port *cport = tty->driver_data;
>> +
>> +	/* Enable remote transmission */
>> +	if (cport->cs_ept)
>> +		rpmsg_tty_send_term_ready(tty, 1);
> 
> and s/1/true/> 
>> +};
> ...
>> +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;
>> +	u8 *tmpbuf;
>> +
>> +	/* If cts not set, the message is not sent*/
>> +	if (!cport->cts)
>> +		return 0;
>> +
>> +	rpdev = cport->rpdev;
>> +
>> +	dev_dbg(&rpdev->dev, "%s: send msg from tty->index = %d, len = %d\n",
>> +		__func__, tty->index, len);
>> +
>> +	msg_max_size = rpmsg_get_mtu(rpdev->ept);
>> +
>> +	msg_size = min(len, msg_max_size);
>> +	tmpbuf = kzalloc(msg_size, GFP_KERNEL);
>> +	if (!tmpbuf)
>> +		return -ENOMEM;
>> +
>> +	memcpy(tmpbuf, buf, msg_size);
> 
> This is kmemdup, but why do you do that in the first place?
> 
>> +	/*
>> +	 * Try to send the message to remote processor, if failed return 0 as
>> +	 * no data sent
>> +	 */
>> +	ret = rpmsg_trysendto(cport->d_ept, tmpbuf, msg_size, cport->data_dst);
> 
> data of rpmsg_trysendto is not const. OK, you seem you need to change
> that first, I see no blocker for that.

I created a temporary buffer to ensure that buffer to sent does not exceed the 
MTU size.
But perhaps this is an useless protection as the rpmsg_tty_write_room already
return the MTU value, and so the 'len' variable can not be higher that value
returned by the write_room?

> 
>> +	kfree(tmpbuf);
>> +	if (ret) {
>> +		dev_dbg(&rpdev->dev, "rpmsg_send failed: %d\n", ret);
>> +		return 0;
>> +	}
>> +
>> +	return msg_size;
>> +}
>> +
>> +static int rpmsg_tty_write_room(struct tty_struct *tty)
>> +{
>> +	struct rpmsg_tty_port *cport = tty->driver_data;
>> +
>> +	return cport->cts ? rpmsg_get_mtu(cport->rpdev->ept) : 0;
> 
> With if, this would be more readable, IMO.
> 
>> +}
> ...> +static struct rpmsg_tty_port *rpmsg_tty_alloc_cport(void)
>> +{
>> +	struct rpmsg_tty_port *cport;
>> +
>> +	cport = kzalloc(sizeof(*cport), GFP_KERNEL);
>> +	if (!cport)
>> +		return ERR_PTR(-ENOMEM);
>> +
>> +	mutex_lock(&idr_lock);
>> +	cport->id = idr_alloc(&tty_idr, cport, 0, MAX_TTY_RPMSG, GFP_KERNEL);
>> +	mutex_unlock(&idr_lock);
>> +
>> +	if (cport->id < 0) {
>> +		kfree(cport);
>> +		return ERR_PTR(-ENOSPC);
> 
> You should return ERR_PTR(cport->id) instead. It might be ENOMEM too.
> 
>> +	}
>> +
>> +	return cport;
>> +}
> ...
>> +static int rpmsg_tty_port_activate(struct tty_port *p, struct tty_struct *tty)
>> +{
>> +	p->low_latency = (p->flags & ASYNC_LOW_LATENCY) ? 1 : 0;
>> +
>> +	/* Allocate the buffer we use for writing data */
> 
> Where exactly -- am I missing something?

in tty_port_alloc_xmit_buf. it's a copy past from mips_ejtag_fdc.c,
I will clean this line if it's confusing.
 
> 
>> +	return tty_port_alloc_xmit_buf(p);
>> +}
>> +
>> +static void rpmsg_tty_port_shutdown(struct tty_port *p)
>> +{
>> +	/* Free the write buffer */
>> +	tty_port_free_xmit_buf(p);
>> +}
> ...
>> +static int rpmsg_tty_probe(struct rpmsg_device *rpdev)
>> +{
>> +	struct rpmsg_tty_port *cport;
>> +	struct device *dev = &rpdev->dev;
>> +	struct rpmsg_channel_info chinfo;
>> +	struct device *tty_dev;
>> +	int ret;
>> +
>> +	cport = rpmsg_tty_alloc_cport();
>> +	if (IS_ERR(cport)) {
>> +		dev_err(dev, "failed to alloc tty port\n");
>> +		return PTR_ERR(cport);
>> +	}
>> +
>> +	if (!strncmp(rpdev->id.name, TTY_CH_NAME_WITH_CTS,
>> +		     sizeof(TTY_CH_NAME_WITH_CTS))) {
> 
> sizeof of a string feels unnatural, but will work in this case. Can a
> compiler optimize strlen of a static string?

I don't know if a compiler can do this...
what about replacing sizeof by strlen function? 
i saw some code example that use strlen with static string...
(e.g  https://elixir.bootlin.com/linux/latest/source/drivers/edac/edac_mc.c#L1193)


I will take into account all your other comments in may next version.

Thanks for the review,
Arnaud

> 
>> +		/*
>> +		 * the default endpoint is used for control. Create a second
>> +		 * endpoint for the data that would be exchanges trough control
>> +		 * endpoint. address of the data endpoint will be provided with
>> +		 * the cts state
>> +		 */
>> +		cport->cs_ept = rpdev->ept;
>> +		cport->data_dst = RPMSG_ADDR_ANY;
>> +
>> +		strscpy(chinfo.name, TTY_CH_NAME_WITH_CTS, sizeof(chinfo.name));
>> +		chinfo.src = RPMSG_ADDR_ANY;
>> +		chinfo.dst = RPMSG_ADDR_ANY;
>> +
>> +		cport->d_ept = rpmsg_create_ept(rpdev, rpmsg_tty_cb, cport,
>> +						chinfo);
>> +		if (!cport->d_ept) {
>> +			dev_err(dev, "failed to create tty control channel\n");
>> +			ret = -ENOMEM;
>> +			goto err_r_cport;
>> +		}
>> +		dev_dbg(dev, "%s: creating data endpoint with address %#x\n",
>> +			__func__, cport->d_ept->addr);
>> +	} else {
>> +		/*
>> +		 * TTY over rpmsg without CTS management the default endpoint
>> +		 * is use for raw data transmission.
>> +		 */
>> +		cport->cs_ept = NULL;
>> +		cport->cts = 1;
>> +		cport->d_ept = rpdev->ept;
>> +		cport->data_dst = rpdev->dst;
>> +	}
>> +
>> +	tty_port_init(&cport->port);
>> +	cport->port.ops = &rpmsg_tty_port_ops;
> 
> I expected these two in rpmsg_tty_alloc_cport
> 
>> +
>> +	tty_dev = tty_port_register_device(&cport->port, rpmsg_tty_driver,
>> +					   cport->id, dev);
>> +	if (IS_ERR(tty_dev)) {
>> +		dev_err(dev, "failed to register tty port\n");
>> +		ret = PTR_ERR(tty_dev);
>> +		goto  err_destroy;
>> +	}
>> +
>> +	cport->rpdev = rpdev;
>> +
>> +	dev_set_drvdata(dev, cport);
>> +
>> +	dev_dbg(dev, "new channel: 0x%x -> 0x%x : ttyRPMSG%d\n",
>> +		rpdev->src, rpdev->dst, cport->id);
>> +
>> +	return 0;
>> +
>> +err_destroy:
>> +	tty_port_destroy(&cport->port);
>> +	if (cport->cs_ept)
>> +		rpmsg_destroy_ept(cport->d_ept);
>> +err_r_cport:
>> +	rpmsg_tty_release_cport(cport);
>> +
>> +	return ret;
>> +}
> 
> thanks,
> 



[Index of Archives]     [Linux Sound]     [ALSA Users]     [ALSA Devel]     [Linux Audio Users]     [Linux Media]     [Kernel]     [Photo Sharing]     [Gimp]     [Yosemite News]     [Linux Media]

  Powered by Linux