This is an automated email from the ASF dual-hosted git repository.

xiaoxiang781216 pushed a commit to branch master
in repository https://gitbox.apache.org/repos/asf/nuttx.git


The following commit(s) were added to refs/heads/master by this push:
     new 753d2a34667 drivers/serial: fetch uart_writev data from the iovec 
segment
753d2a34667 is described below

commit 753d2a34667b41df648d9bc50b4d2db68523cdb5
Author: raiden00pl <[email protected]>
AuthorDate: Tue Jul 21 15:07:56 2026 +0200

    drivers/serial: fetch uart_writev data from the iovec segment
    
    Since 00010089b8 uart_writev() takes the data one byte at a time with
    uio_copyto() plus uio_advance().  Both of them walk the iovec list and
    redo the byte counters for every single byte, so most of the work is
    bookkeeping rather than copying.  On slow cores this is what limits how
    fast the TX buffer can be filled.
    
    Take a pointer to the current iovec segment and read the bytes straight
    from it, and move the uio forward once per segment instead of once per
    byte.  nseg counts only the bytes that really went into the buffer: it
    is increased at the end of a loop pass, and that step is skipped when
    uart_putxmitchar() fails.
    
    Measured on nRF52840 (Cortex-M4, 64 MHz), 8 MiB write() to a CDC/ACM
    port: 223 KB/s to 481 KB/s.
    
    Signed-off-by: raiden00pl <[email protected]>
    Assisted-by: Claude Code
---
 drivers/serial/serial.c | 24 ++++++++++++++++++++++--
 1 file changed, 22 insertions(+), 2 deletions(-)

diff --git a/drivers/serial/serial.c b/drivers/serial/serial.c
index c2c76b5249d..8c4704cd3c7 100644
--- a/drivers/serial/serial.c
+++ b/drivers/serial/serial.c
@@ -1480,6 +1480,9 @@ static ssize_t uart_writev(FAR struct file *filep, FAR 
struct uio *uio)
 {
   FAR struct inode *inode    = filep->f_inode;
   FAR uart_dev_t   *dev      = inode->i_private;
+  FAR const char   *segbuf   = NULL;
+  size_t            seglen   = 0;
+  size_t            nseg     = 0;
   ssize_t           nwritten;
   ssize_t           buflen;
   bool              oktoblock;
@@ -1554,9 +1557,22 @@ static ssize_t uart_writev(FAR struct file *filep, FAR 
struct uio *uio)
    */
 
   uart_disabletxint(dev);
-  for (; buflen; uio_advance(uio, 1), buflen--)
+  for (; buflen; buflen--, nseg++)
     {
-      uio_copyto(uio, 0, &ch, 1);
+      if (nseg >= seglen)
+        {
+          /* Consume the current segment and take a pointer to the next.
+           * uio_advance() steps over any zero-length iovec.
+           */
+
+          uio_advance(uio, nseg);
+          segbuf = (FAR const char *)uio->uio_iov->iov_base +
+                   uio->uio_offset_in_iov;
+          seglen = uio->uio_iov->iov_len - uio->uio_offset_in_iov;
+          nseg   = 0;
+        }
+
+      ch  = segbuf[nseg];
       ret = OK;
 
       /* Do output post-processing */
@@ -1631,6 +1647,10 @@ static ssize_t uart_writev(FAR struct file *filep, FAR 
struct uio *uio)
         }
     }
 
+  /* Consume the bytes that were successfully queued */
+
+  uio_advance(uio, nseg);
+
   if (dev->xmit.head != dev->xmit.tail)
     {
 #ifdef CONFIG_SERIAL_TXDMA

Reply via email to