You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@nuttx.apache.org by xi...@apache.org on 2024/02/06 16:52:38 UTC

(nuttx) 02/07: risc-v/mpfs: i2c: perform sanity checks

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

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

commit bcf7aa4b631ef21d6d2b668ec87e1458bfac45bf
Author: Eero Nurkkala <ee...@offcode.fi>
AuthorDate: Tue Dec 5 12:53:39 2023 +0200

    risc-v/mpfs: i2c: perform sanity checks
    
    Replace risky DEBUGASSERT()s with real sanity checks. Also,
    do a few more checks as the system might occasionally fire an
    interrupt if the system has been restarted while in middle of
    an i2c transaction.
    
    Yet, modify i2c_transfer() function so that up_disable_irq()
    is always called at the end to better prevent ill-timed irqs.
    
    Signed-off-by: Eero Nurkkala <ee...@offcode.fi>
---
 arch/risc-v/src/mpfs/mpfs_i2c.c | 68 +++++++++++++++++++++++++++++++++++------
 1 file changed, 59 insertions(+), 9 deletions(-)

diff --git a/arch/risc-v/src/mpfs/mpfs_i2c.c b/arch/risc-v/src/mpfs/mpfs_i2c.c
index 7748db1f0f..3a131f68e9 100644
--- a/arch/risc-v/src/mpfs/mpfs_i2c.c
+++ b/arch/risc-v/src/mpfs/mpfs_i2c.c
@@ -437,8 +437,6 @@ static int mpfs_i2c_irq(int cpuint, void *context, void *arg)
   volatile uint32_t status;
   uint8_t clear_irq = 1u;
 
-  DEBUGASSERT(msg != NULL);
-
   status = getreg32(MPFS_I2C_STATUS);
 
   switch (status)
@@ -479,7 +477,16 @@ static int mpfs_i2c_irq(int cpuint, void *context, void *arg)
       case MPFS_I2C_ST_TX_DATA_ACK:
         if (priv->tx_idx < priv->tx_size)
           {
-            DEBUGASSERT(priv->tx_buffer != NULL);
+            if (priv->tx_buffer == NULL)
+              {
+                i2cerr("ERROR: tx_buffer is NULL!\n");
+
+                /* Clear the serial interrupt flag and exit */
+
+                modifyreg32(MPFS_I2C_CTRL, MPFS_I2C_CTRL_SI_MASK, 0);
+                return 0;
+              }
+
             putreg32(priv->tx_buffer[priv->tx_idx], MPFS_I2C_DATA);
             priv->tx_idx++;
           }
@@ -557,10 +564,18 @@ static int mpfs_i2c_irq(int cpuint, void *context, void *arg)
         break;
 
       case MPFS_I2C_ST_RX_DATA_ACK:
+        if (priv->rx_buffer == NULL)
+          {
+            i2cerr("ERROR: rx_buffer is NULL!\n");
+
+            /* Clear the serial interrupt flag and exit */
+
+            modifyreg32(MPFS_I2C_CTRL, MPFS_I2C_CTRL_SI_MASK, 0);
+            return 0;
+          }
 
         /* Data byte received, ACK returned */
 
-        DEBUGASSERT(priv->rx_buffer != NULL);
         priv->rx_buffer[priv->rx_idx] = (uint8_t)getreg32(MPFS_I2C_DATA);
         priv->rx_idx++;
 
@@ -572,10 +587,29 @@ static int mpfs_i2c_irq(int cpuint, void *context, void *arg)
 
       case MPFS_I2C_ST_RX_DATA_NACK:
 
+        /* Some sanity checks */
+
+        if (priv->rx_buffer == NULL)
+          {
+            i2cerr("ERROR: rx_buffer is NULL!\n");
+
+            /* Clear the serial interrupt flag and exit */
+
+            modifyreg32(MPFS_I2C_CTRL, MPFS_I2C_CTRL_SI_MASK, 0);
+            return 0;
+          }
+        else if (priv->rx_idx >= priv->rx_size)
+          {
+            i2cerr("ERROR: rx_idx is out of bounds!\n");
+
+            /* Clear the serial interrupt flag and exit */
+
+            modifyreg32(MPFS_I2C_CTRL, MPFS_I2C_CTRL_SI_MASK, 0);
+            return 0;
+          }
+
         /* Data byte received, NACK returned */
 
-        DEBUGASSERT(priv->rx_buffer != NULL);
-        DEBUGASSERT(priv->rx_idx < priv->rx_size);
         priv->rx_buffer[priv->rx_idx] = (uint8_t)getreg32(MPFS_I2C_DATA);
         priv->rx_idx++;
 
@@ -673,7 +707,11 @@ static int mpfs_i2c_transfer(struct i2c_master_s *dev,
   int ret = OK;
 
   i2cinfo("Starting transfer request of %d message(s):\n", count);
-  DEBUGASSERT(count > 0);
+
+  if (count <= 0)
+    {
+      return -EINVAL;
+    }
 
   ret = nxmutex_lock(&priv->lock);
   if (ret < 0)
@@ -715,9 +753,17 @@ static int mpfs_i2c_transfer(struct i2c_master_s *dev,
 
           if (msgs[i].flags & I2C_M_NOSTOP)
             {
-              /* Support only write + read combinations */
+              /* Support only write + read combinations.  No write + write,
+               * nor read + write without stop condition between supported
+               * yet.
+               */
 
-              DEBUGASSERT(!(msgs[i].flags & I2C_M_READ));
+              if (msgs[i].flags & I2C_M_READ)
+                {
+                  i2cerr("No read before write supported!\n");
+                  nxmutex_unlock(&priv->lock);
+                  return -EINVAL;
+                }
 
               /* Combine write + read transaction into one */
 
@@ -765,6 +811,10 @@ static int mpfs_i2c_transfer(struct i2c_master_s *dev,
         i2cinfo("Message %" PRIu8 " transfer complete.\n", priv->msgid);
     }
 
+  /* Irq was enabled at mpfs_i2c_sendstart()  */
+
+  up_disable_irq(priv->plic_irq);
+
   nxmutex_unlock(&priv->lock);
   return ret;
 }