pkarashchenko commented on code in PR #9057:
URL: https://github.com/apache/nuttx/pull/9057#discussion_r1173605069


##########
drivers/serial/uart_16550.c:
##########
@@ -56,9 +62,24 @@
 struct u16550_s
 {
   uart_addrwidth_t uartbase;  /* Base address of UART registers */
-#ifndef CONFIG_16550_SUPRESS_CONFIG
+#ifdef HAVE_16550_UART_DMA
+  int32_t                dmatx;
+  FAR struct dma_chan_s *chantx;
+  int32_t                dmarx;
+  FAR struct dma_chan_s *chanrx;
+  FAR void              *dmarxbuf;
+  size_t                 dmarxsize;
+  volatile size_t        dmarxhead;
+  volatile size_t        dmarxtail;
+  int32_t                dmarxtimeout;
+#endif
+#if !defined(CONFIG_16550_SUPRESS_CONFIG) || defined(HAVE_16550_UART_DMA)
   uint32_t         baud;      /* Configured baud */

Review Comment:
   I think we need to add some spaces to align with above.



##########
drivers/serial/uart_16550.c:
##########
@@ -1157,25 +1317,198 @@ static bool u16550_rxflowcontrol(struct uart_dev_s 
*dev,
  *
  ****************************************************************************/
 
-#ifdef CONFIG_SERIAL_TXDMA
+#ifdef HAVE_16550_UART_DMA
+static void u16550_dmasend_done(FAR struct dma_chan_s *chan,
+                                FAR void *arg, ssize_t len)
+{
+  FAR struct uart_dev_s *dev = arg;
+
+  if (len > 0)
+    {
+      dev->dmatx.nbytes = len;
+      uart_xmitchars_done(dev);
+      uart_xmitchars_dma(dev);
+    }
+  else /* Fail, resend */
+    {
+      u16550_dmasend(dev);
+    }
+}
+
 static void u16550_dmasend(FAR struct uart_dev_s *dev)
 {
+  FAR struct u16550_s *priv = dev->priv;
+  FAR void *buffer = dev->dmatx.buffer;
+  size_t length = dev->dmatx.length;
+
+  up_clean_dcache((uintptr_t)buffer, (uintptr_t)buffer + length);
+  DMA_START(priv->chantx, u16550_dmasend_done, dev,
+            up_addrenv_va_to_pa((void *)priv->uartbase),

Review Comment:
   ```suggestion
               up_addrenv_va_to_pa((FAR void *)priv->uartbase),
   ```



##########
include/nuttx/dma/dma.h:
##########
@@ -0,0 +1,365 @@
+/****************************************************************************
+ * include/nuttx/dma/dma.h
+ *
+ *   Copyright (C) 2018 Pinecone Inc. All rights reserved.
+ *   Author: Zhong An <[email protected]>
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in
+ *    the documentation and/or other materials provided with the
+ *    distribution.
+ * 3. Neither the name NuttX nor the names of its contributors may be
+ *    used to endorse or promote products derived from this software
+ *    without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
+ * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
+ * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
+ * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS
+ * OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
+ * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
+ * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+ * POSSIBILITY OF SUCH DAMAGE.
+ *
+ ****************************************************************************/
+
+#ifndef __INCLUDE_NUTTX_DMA_DMA_H
+#define __INCLUDE_NUTTX_DMA_DMA_H
+
+/****************************************************************************
+ * Included Files
+ ****************************************************************************/
+
+#include <nuttx/config.h>
+#include <stdint.h>
+#include <sys/types.h>
+
+/****************************************************************************
+ * Pre-processor Definitions
+ ****************************************************************************/
+
+/* DMA transfer direction indicator */
+
+#define DMA_MEM_TO_MEM          1
+#define DMA_MEM_TO_DEV          2
+#define DMA_DEV_TO_MEM          3
+#define DMA_DEV_TO_DEV          4
+
+#ifdef CONFIG_DMA_LINK
+# define DMA_BLOCK_MODE         0
+# define DMA_SRC_LINK_MODE      1
+# define DMA_DST_LINK_MODE      2
+# define DMA_DUAL_LINK_MODE     3

Review Comment:
   ```suggestion
   #  define DMA_BLOCK_MODE         0
   #  define DMA_SRC_LINK_MODE      1
   #  define DMA_DST_LINK_MODE      2
   #  define DMA_DUAL_LINK_MODE     3
   ```



##########
drivers/serial/uart_16550.c:
##########
@@ -1157,25 +1317,198 @@ static bool u16550_rxflowcontrol(struct uart_dev_s 
*dev,
  *
  ****************************************************************************/
 
-#ifdef CONFIG_SERIAL_TXDMA
+#ifdef HAVE_16550_UART_DMA
+static void u16550_dmasend_done(FAR struct dma_chan_s *chan,
+                                FAR void *arg, ssize_t len)
+{
+  FAR struct uart_dev_s *dev = arg;
+
+  if (len > 0)
+    {
+      dev->dmatx.nbytes = len;
+      uart_xmitchars_done(dev);
+      uart_xmitchars_dma(dev);
+    }
+  else /* Fail, resend */
+    {
+      u16550_dmasend(dev);
+    }
+}
+
 static void u16550_dmasend(FAR struct uart_dev_s *dev)
 {
+  FAR struct u16550_s *priv = dev->priv;
+  FAR void *buffer = dev->dmatx.buffer;
+  size_t length = dev->dmatx.length;
+
+  up_clean_dcache((uintptr_t)buffer, (uintptr_t)buffer + length);
+  DMA_START(priv->chantx, u16550_dmasend_done, dev,
+            up_addrenv_va_to_pa((void *)priv->uartbase),
+            up_addrenv_va_to_pa(buffer), length);
+}
+
+static void u16550_dmareceive_done(FAR struct dma_chan_s *chan,
+                                   FAR void *arg, ssize_t len)
+{
+  FAR struct uart_dev_s *dev = arg;
+  FAR struct u16550_s *priv = dev->priv;
+
+  if (len >= 0)
+    {
+      size_t slot   = priv->dmarxhead / priv->dmarxsize;
+      size_t offset = priv->dmarxhead - slot * priv->dmarxsize;
+
+      if (len >= priv->dmarxsize)
+        {
+          len = 0;
+        }
+      if (len < offset)
+        {
+          slot++; /* Wrap, move to the next slot */
+        }
+
+      priv->dmarxhead = slot * priv->dmarxsize + len;
+      if (priv->dmarxhead - priv->dmarxtail >= priv->dmarxsize)
+        {
+          serr("The receive dma buffer is overrun\n");
+          priv->dmarxtail = priv->dmarxhead - priv->dmarxsize / 2;
+        }
+
+      /* The receive isn't in the process? */
+      if (dev->dmarx.length == 0)
+        {
+          /* Trigger the receive process */
+          uart_recvchars_dma(dev);
+        }
+      else
+        {
+          /* Copy the received data */
+          u16550_dmareceive(dev);
+        }
+    }
 }
-#endif
 
-#ifdef CONFIG_SERIAL_RXDMA
 static void u16550_dmareceive(FAR struct uart_dev_s *dev)
 {
+  FAR struct u16550_s *priv = dev->priv;
+
+  if (priv->dmarxhead != priv->dmarxtail)
+    {
+      size_t length = priv->dmarxhead - priv->dmarxtail;
+      size_t offset = priv->dmarxtail % priv->dmarxsize;
+      FAR void *buffer = priv->dmarxbuf + offset;

Review Comment:
   void pointer arithmetics is not defined by a C standard



##########
drivers/serial/uart_16550.c:
##########
@@ -1157,25 +1317,198 @@ static bool u16550_rxflowcontrol(struct uart_dev_s 
*dev,
  *
  ****************************************************************************/
 
-#ifdef CONFIG_SERIAL_TXDMA
+#ifdef HAVE_16550_UART_DMA
+static void u16550_dmasend_done(FAR struct dma_chan_s *chan,
+                                FAR void *arg, ssize_t len)
+{
+  FAR struct uart_dev_s *dev = arg;
+
+  if (len > 0)
+    {
+      dev->dmatx.nbytes = len;
+      uart_xmitchars_done(dev);
+      uart_xmitchars_dma(dev);
+    }
+  else /* Fail, resend */
+    {
+      u16550_dmasend(dev);
+    }
+}
+
 static void u16550_dmasend(FAR struct uart_dev_s *dev)
 {
+  FAR struct u16550_s *priv = dev->priv;
+  FAR void *buffer = dev->dmatx.buffer;
+  size_t length = dev->dmatx.length;
+
+  up_clean_dcache((uintptr_t)buffer, (uintptr_t)buffer + length);
+  DMA_START(priv->chantx, u16550_dmasend_done, dev,
+            up_addrenv_va_to_pa((void *)priv->uartbase),
+            up_addrenv_va_to_pa(buffer), length);
+}
+
+static void u16550_dmareceive_done(FAR struct dma_chan_s *chan,
+                                   FAR void *arg, ssize_t len)
+{
+  FAR struct uart_dev_s *dev = arg;
+  FAR struct u16550_s *priv = dev->priv;
+
+  if (len >= 0)
+    {
+      size_t slot   = priv->dmarxhead / priv->dmarxsize;
+      size_t offset = priv->dmarxhead - slot * priv->dmarxsize;
+
+      if (len >= priv->dmarxsize)
+        {
+          len = 0;
+        }
+      if (len < offset)
+        {
+          slot++; /* Wrap, move to the next slot */
+        }
+
+      priv->dmarxhead = slot * priv->dmarxsize + len;
+      if (priv->dmarxhead - priv->dmarxtail >= priv->dmarxsize)
+        {
+          serr("The receive dma buffer is overrun\n");
+          priv->dmarxtail = priv->dmarxhead - priv->dmarxsize / 2;
+        }
+
+      /* The receive isn't in the process? */
+      if (dev->dmarx.length == 0)
+        {
+          /* Trigger the receive process */
+          uart_recvchars_dma(dev);
+        }
+      else
+        {
+          /* Copy the received data */
+          u16550_dmareceive(dev);
+        }
+    }
 }
-#endif
 
-#ifdef CONFIG_SERIAL_RXDMA
 static void u16550_dmareceive(FAR struct uart_dev_s *dev)
 {
+  FAR struct u16550_s *priv = dev->priv;
+
+  if (priv->dmarxhead != priv->dmarxtail)
+    {
+      size_t length = priv->dmarxhead - priv->dmarxtail;
+      size_t offset = priv->dmarxtail % priv->dmarxsize;
+      FAR void *buffer = priv->dmarxbuf + offset;
+
+      if (offset + length > priv->dmarxsize)
+        {
+          length = priv->dmarxsize - offset;
+        }
+      if (length > dev->dmarx.length)
+        {
+          length = dev->dmarx.length;
+        }
+
+      up_invalidate_dcache((uintptr_t)buffer, (uintptr_t)buffer + length);
+      memcpy(dev->dmarx.buffer, buffer, length);
+      dev->dmarx.nbytes = length;
+      priv->dmarxtail += length;
+
+      uart_recvchars_done(dev);
+      if (priv->dmarxhead != priv->dmarxtail)
+        {
+          /* Trigger the receive process again */
+          uart_recvchars_dma(dev);
+        }
+    }
+}
+
+static void u16550_dmarxconfig(FAR struct uart_dev_s *dev)
+{
+  FAR struct u16550_s *priv = dev->priv;
+  struct dma_config_s config;
+
+  if (priv->chanrx != NULL)
+    {
+      memset(&config, 0, sizeof(config));
+      config.direction = DMA_DEV_TO_MEM;
+      /* 12bit = 1bit start + 8bit data + 1bit parity + 2bit stop */
+      config.timeout   = 12 * 1000000ull * priv->dmarxtimeout / priv->baud;
+      config.src_width = 1;
+      DMA_CONFIG(priv->chanrx, &config);
+    }
 }
 
 static void u16550_dmarxfree(FAR struct uart_dev_s *dev)
 {
+  FAR struct u16550_s *priv = dev->priv;
+
+  if (priv->dmarx == -1)
+    {
+      return; /* Can't receive by DMA */
+    }
+
+  if (priv->chanrx == NULL)
+    {
+      priv->chanrx = uart_dmachan(priv->uartbase, priv->dmarx);
+      if (priv->chanrx == NULL)
+        {
+          return; /* Fail to get DMA channel */
+        }
+      u16550_dmarxconfig(dev);
+
+      /* Start a never stop DMA cyclic transfer in the background */
+      DMA_START_CYCLIC(priv->chanrx, u16550_dmareceive_done, dev,
+                       up_addrenv_va_to_pa(priv->dmarxbuf),
+                       up_addrenv_va_to_pa((void *)priv->uartbase),

Review Comment:
   ```suggestion
                          up_addrenv_va_to_pa((FAR void *)priv->uartbase),
   ```



-- 
This is an automated message from the Apache Git Service.
To respond to the message, please log on to GitHub and use the
URL above to go to the specific comment.

To unsubscribe, e-mail: [email protected]

For queries about this service, please contact Infrastructure at:
[email protected]

Reply via email to