Skip to content

Commit

Permalink
risc-v/mpfs: i2c: perform sanity checks
Browse files Browse the repository at this point in the history
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 <[email protected]>
  • Loading branch information
eenurkka committed Dec 19, 2023
1 parent 0c5fb78 commit 870bf22
Showing 1 changed file with 59 additions and 9 deletions.
68 changes: 59 additions & 9 deletions arch/risc-v/src/mpfs/mpfs_i2c.c
Original file line number Diff line number Diff line change
Expand Up @@ -436,8 +436,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)
Expand Down Expand Up @@ -478,7 +476,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++;
}
Expand Down Expand Up @@ -556,10 +563,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++;

Expand All @@ -571,10 +586,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++;

Expand Down Expand Up @@ -672,7 +706,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)
Expand Down Expand Up @@ -714,9 +752,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 */

Expand Down Expand Up @@ -764,6 +810,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;
}
Expand Down

0 comments on commit 870bf22

Please sign in to comment.