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

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

commit 7c2930c3df497917d954c6e8a3c30c967ac11de4
Author: Ville Juven <ville.ju...@unikie.com>
AuthorDate: Thu May 25 14:22:02 2023 +0300

    mpfs/mpfs_corespi: Optimize TX / RX FIFO handling
    
    Remove unnecessary reading of the status register when loading / unloading
    the FIFOs. Reading from the IP block is slow due to BUS synchronization and
    this basically makes the SPI busy loop for no reason at all, destroying the
    CPU usage.
    
    The overall benefit of these changes is approx. 25%-points, which is a
    MASSIVE improvement.
---
 arch/risc-v/src/mpfs/mpfs_corespi.c | 80 ++++++++++++++++++++++++++-----------
 1 file changed, 57 insertions(+), 23 deletions(-)

diff --git a/arch/risc-v/src/mpfs/mpfs_corespi.c 
b/arch/risc-v/src/mpfs/mpfs_corespi.c
index b5f850dd13..1bf5cb0396 100644
--- a/arch/risc-v/src/mpfs/mpfs_corespi.c
+++ b/arch/risc-v/src/mpfs/mpfs_corespi.c
@@ -388,6 +388,54 @@ static void mpfs_spi_rxoverflow_recover(struct 
mpfs_spi_priv_s *priv)
   mpfs_spi_enable(priv, 1);
 }
 
+/****************************************************************************
+ * Name: mpfs_rx_wait_last_frame
+ *
+ * Description:
+ *   Wait for the last frame in TXDONE interrupt. We must potentially do this
+ *   wait because the TXDONE interrupt is asserted when the last frame is
+ *   moved from the TXLAST register to the FIFO, thus there can be 1-2 frame
+ *   delay before the last RX frame is available in the FIFO.
+ *
+ * Input Parameters:
+ *   priv   - Private SPI device structure
+ *
+ * Returned Value:
+ *   None
+ *
+ ****************************************************************************/
+
+static int mpfs_rx_wait_last_frame(struct mpfs_spi_priv_s *priv)
+{
+  uint32_t rxempty;
+  uint32_t rxretry;
+  uint32_t timeout;
+
+  rxretry = 0;
+
+  while ((rxempty = getreg32(MPFS_SPI_STATUS) & MPFS_SPI_RXEMPTY))
+    {
+      /* Last RX character not ready yet, try again (once) */
+
+      if (rxretry == 0)
+        {
+          /* Use safe type for timeout calculations */
+
+          timeout = priv->nbits;
+          timeout = SPI_TTOA_US(timeout << 1, priv->actual);
+          rxretry = 1;
+          up_udelay(timeout);
+          continue;
+        }
+
+      /* Nothing is coming, get out */
+
+      return -1;
+    }
+
+  return 0;
+}
+
 /****************************************************************************
  * Name: mpfs_spi_lock
  *
@@ -688,14 +736,12 @@ static void mpfs_spi_load_tx_fifo(struct mpfs_spi_priv_s 
*priv,
                                   const void *txbuffer,
                                   uint32_t nwords)
 {
-  uint32_t tx_fifo_full;
   uint16_t *data16;
   uint8_t *data8;
   int last;
   int i;
 
   DEBUGASSERT(nwords > 0);
-
   data16 = (uint16_t *)txbuffer;
   data8 = (uint8_t *)txbuffer;
   last = nwords - 1;
@@ -740,9 +786,6 @@ static void mpfs_spi_load_tx_fifo(struct mpfs_spi_priv_s 
*priv,
         }
 
       priv->tx_pos++;
-      tx_fifo_full = getreg32(MPFS_SPI_STATUS) & MPFS_SPI_TXFULL;
-
-      DEBUGASSERT(tx_fifo_full == 0);
     }
 }
 
@@ -767,38 +810,29 @@ static void mpfs_spi_unload_rx_fifo(struct 
mpfs_spi_priv_s *priv,
                                     void *rxbuffer,
                                     uint32_t nwords)
 {
-  uint32_t rx_fifo_empty;
-  uint32_t rxretry;
   uint16_t *data16;
   uint8_t *data8;
+  int last;
   int i;
 
   DEBUGASSERT(nwords > 0);
 
   data16 = (uint16_t *)rxbuffer;
   data8 = (uint8_t *)rxbuffer;
-  rxretry = 0;
+  last = nwords - 1;
 
   for (i = 0; i < nwords; i++)
     {
-      while ((rx_fifo_empty = getreg32(MPFS_SPI_STATUS) & MPFS_SPI_RXEMPTY))
-        {
-          /* Last RX character not ready yet, try again (once) */
+      /* The last character might not be available yet due to bus delays */
 
-          if (rxretry == 0)
+      if (i == last)
+        {
+          if (mpfs_rx_wait_last_frame(priv) < 0)
             {
-              /* Use safe type for timeout calculations */
+              /* Nothing came, get out */
 
-              uint32_t timeout = priv->nbits;
-              timeout = SPI_TTOA_US(timeout << 1, priv->actual);
-              rxretry = 1;
-              up_udelay(timeout);
-              continue;
+              return;
             }
-
-          /* Nothing is coming, get out */
-
-          return;
         }
 
       if (rxbuffer)
@@ -867,7 +901,7 @@ static void mpfs_spi_irq_exchange(struct mpfs_spi_priv_s 
*priv,
   DEBUGASSERT(priv->nbits == 8 || priv->nbits == 16);
 
   priv->fifosize = (MPFS_FIFO_SIZE_BITS / priv->nbits);
-  priv->fifolevel = priv->fifosize / 2;
+  priv->fifolevel = priv->fifosize - 2;
 
   priv->txwords = nwords;
   priv->txbuf   = txbuffer;

Reply via email to