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

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

 



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



[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