Re: [PATCH 1/1] serial: imx - Add dma buffer confugration via sysfs

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

 



Hello,

On Wed, Jun 27, 2018 at 10:01:06AM +0200, Fabien Lahoudere wrote:
> In order to optimize serial communication on imx53 and imx6, we may
> need to tweak DMA period and buffer length per period.
> This patch add sysfs attributes to configure thoses values before
> initialising DMA.
> 
> For example, you can access values by reading/writing:
> 
> /sys/devices/soc0/soc/2100000.aips-bus/21ec000.serial/period_number
> /sys/devices/soc0/soc/2100000.aips-bus/21ec000.serial/period_length

I don't think "period_number" and "period_length" are good choices. I'd
suggest "dma_buffer_count" and "dma_buffer_size".

> Signed-off-by: Fabien Lahoudere <fabien.lahoudere@xxxxxxxxxxxxx>
> ---
>  drivers/tty/serial/imx.c | 100 ++++++++++++++++++++++++++++++++++++++++++++---
>  1 file changed, 95 insertions(+), 5 deletions(-)
> 
> diff --git a/drivers/tty/serial/imx.c b/drivers/tty/serial/imx.c
> index 4e85357..b35381c 100644
> --- a/drivers/tty/serial/imx.c
> +++ b/drivers/tty/serial/imx.c
> @@ -218,8 +218,11 @@ struct imx_port {
>  	struct dma_chan		*dma_chan_rx, *dma_chan_tx;
>  	struct scatterlist	rx_sgl, tx_sgl[2];
>  	void			*rx_buf;
> +	unsigned int		rx_buf_size;
>  	struct circ_buf		rx_ring;
> +	unsigned int		rx_period_length;
>  	unsigned int		rx_periods;
> +	struct mutex		rx_period_lock;

Please document, what this lock protects.

>  	dma_cookie_t		rx_cookie;
>  	unsigned int		tx_bytes;
>  	unsigned int		dma_tx_nents;
> @@ -1028,8 +1031,6 @@ static void imx_uart_timeout(struct timer_list *t)
>  	}
>  }
>  
> -#define RX_BUF_SIZE	(PAGE_SIZE)
> -
>  /*
>   * There are two kinds of RX DMA interrupts(such as in the MX6Q):
>   *   [1] the RX DMA buffer is full.
> @@ -1124,9 +1125,8 @@ static int imx_uart_start_rx_dma(struct imx_port *sport)
>  
>  	sport->rx_ring.head = 0;
>  	sport->rx_ring.tail = 0;
> -	sport->rx_periods = RX_DMA_PERIODS;
>  
> -	sg_init_one(sgl, sport->rx_buf, RX_BUF_SIZE);
> +	sg_init_one(sgl, sport->rx_buf, sport->rx_buf_size);
>  	ret = dma_map_sg(dev, sgl, 1, DMA_FROM_DEVICE);
>  	if (ret == 0) {
>  		dev_err(dev, "DMA mapping error for RX.\n");
> @@ -1244,7 +1244,10 @@ static int imx_uart_dma_init(struct imx_port *sport)
>  		goto err;
>  	}
>  
> -	sport->rx_buf = kzalloc(RX_BUF_SIZE, GFP_KERNEL);
> +	mutex_lock(&sport->rx_period_lock);
> +	sport->rx_buf_size = sport->rx_period_length * sport->rx_periods;
> +	mutex_unlock(&sport->rx_period_lock);
> +	sport->rx_buf = kzalloc(sport->rx_buf_size, GFP_KERNEL);
>  	if (!sport->rx_buf) {
>  		ret = -ENOMEM;
>  		goto err;
> @@ -2133,6 +2137,84 @@ static void imx_uart_console_early_write(struct console *con, const char *s,
>  	.cons           = IMX_CONSOLE,
>  };
>  
> +static ssize_t imx_uart_set_period_length(struct device *dev,
> +					  struct device_attribute *attr,
> +					  const char *buf, size_t count)
> +{
> +	unsigned int plen;
> +	int ret;
> +	struct imx_port *sport = dev_get_drvdata(dev);
> +
> +	if (count == 0)
> +		return -EINVAL;

Can this happen?

> +	if (sport->dma_chan_rx) {
> +		dev_warn(dev, "You cannot set period length if DMA is inited");

missing \n

> +		return -EBUSY;
> +	}
> +
> +	ret = sscanf(buf, "%u", &plen);
> +	if (ret <= 0)
> +		return ret;

Is it right to return 0 here? I think there are helpers more suitable
than sscanf.

> +	mutex_lock(&sport->rx_period_lock);
> +	sport->rx_period_length = plen;
> +	mutex_unlock(&sport->rx_period_lock);
> +
> +	return strnlen(buf, count);

Is it right to return 5 if I write "5 a b" to the sysfs file?

> +}
> +
> +static ssize_t imx_uart_get_period_length(struct device *dev,
> +					  struct device_attribute *attr,
> +					  char *buf)
> +{
> +	struct imx_port *sport = dev_get_drvdata(dev);
> +
> +	return snprintf(buf, PAGE_SIZE, "%u\n", sport->rx_period_length);
> +}
> +
> +static ssize_t imx_uart_set_period_number(struct device *dev,
> +					  struct device_attribute *attr,
> +					  const char *buf, size_t count)
> +{
> +	unsigned int periods;
> +	int ret;
> +	struct imx_port *sport = dev_get_drvdata(dev);
> +
> +	if (count == 0)
> +		return -EINVAL;
> +
> +	if (sport->dma_chan_rx) {
> +		dev_warn(dev,
> +			 "You cannot set number of period if DMA is inited");

missing \n

> +		return -EBUSY;
> +	}
> +
> +	ret = sscanf(buf, "%u", &periods);
> +	if (ret <= 0)
> +		return ret;
> +
> +	mutex_lock(&sport->rx_period_lock);
> +	sport->rx_periods = periods;
> +	mutex_unlock(&sport->rx_period_lock);
> +	return strnlen(buf, count);
> +}
> +
> +static ssize_t imx_uart_get_period_number(struct device *dev,
> +					  struct device_attribute *attr,
> +					  char *buf)
> +{
> +	struct imx_port *sport = dev_get_drvdata(dev);
> +
> +	return snprintf(buf, PAGE_SIZE, "%u\n", sport->rx_periods);
> +}
> +
> +static DEVICE_ATTR(period_length, 0660,
> +		   imx_uart_get_period_length, imx_uart_set_period_length);
> +static DEVICE_ATTR(period_number, 0660,
> +		   imx_uart_get_period_number, imx_uart_set_period_number);

I would have used 0644, consider using DEVICE_ATTR_RW.

> +
>  #ifdef CONFIG_OF
>  /*
>   * This function returns 1 iff pdev isn't a device instatiated by dt, 0 iff it
> @@ -2216,6 +2297,13 @@ static int imx_uart_probe(struct platform_device *pdev)
>  		return -EINVAL;
>  	}
>  
> +	if (device_create_file(&pdev->dev,
> +	     (const struct device_attribute *)&dev_attr_period_length.attr) != 0)
> +		dev_err(&pdev->dev, "Cannot create period length attribute");
> +	if (device_create_file(&pdev->dev,
> +	     (const struct device_attribute *)&dev_attr_period_number.attr) != 0)
> +		dev_err(&pdev->dev, "Cannot create period number attribute");
> +

This is bad and wrong. You must not add attributes to already registered
devices. This also needs API documentation.

Also should this only be added if the device will use DMA on the next
startup?

>  	res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
>  	base = devm_ioremap_resource(&pdev->dev, res);
>  	if (IS_ERR(base))
> @@ -2257,6 +2345,10 @@ static int imx_uart_probe(struct platform_device *pdev)
>  
>  	sport->port.uartclk = clk_get_rate(sport->clk_per);
>  
> +	sport->rx_period_length = PAGE_SIZE / RX_DMA_PERIODS;
> +	sport->rx_periods = RX_DMA_PERIODS;
> +	mutex_init(&sport->rx_period_lock);
> +
>  	/* For register access, we only need to enable the ipg clock. */
>  	ret = clk_prepare_enable(sport->clk_ipg);
>  	if (ret) {

Best regards
Uwe

-- 
Pengutronix e.K.                           | Uwe Kleine-König            |
Industrial Linux Solutions                 | http://www.pengutronix.de/  |
--
To unsubscribe from this list: send the line "unsubscribe linux-serial" in
the body of a message to majordomo@xxxxxxxxxxxxxxx
More majordomo info at  http://vger.kernel.org/majordomo-info.html



[Index of Archives]     [Kernel Newbies]     [Security]     [Netfilter]     [Bugtraq]     [Linux PPP]     [Linux FS]     [Yosemite News]     [MIPS Linux]     [ARM Linux]     [Linux Security]     [Linux RAID]     [Samba]     [Video 4 Linux]     [Linmodem]     [Device Mapper]     [Linux Kernel for ARM]

  Powered by Linux