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 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; 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; + + if (sport->dma_chan_rx) { + dev_warn(dev, "You cannot set period length if DMA is inited"); + return -EBUSY; + } + + ret = sscanf(buf, "%u", &plen); + if (ret <= 0) + return ret; + + mutex_lock(&sport->rx_period_lock); + sport->rx_period_length = plen; + mutex_unlock(&sport->rx_period_lock); + + return strnlen(buf, count); +} + +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"); + 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); + #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"); + 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) { -- 1.8.3.1 -- 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