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 shortly after a warm reboot.

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 5, 2023
1 parent b1d7e41 commit 4048a84
Showing 1 changed file with 58 additions and 9 deletions.
67 changes: 58 additions & 9 deletions arch/risc-v/src/mpfs/mpfs_i2c.c
Original file line number Diff line number Diff line change
Expand Up @@ -432,11 +432,24 @@ static int mpfs_i2c_sem_waitdone(struct mpfs_i2c_priv_s *priv)
static int mpfs_i2c_irq(int cpuint, void *context, void *arg)
{
struct mpfs_i2c_priv_s *priv = (struct mpfs_i2c_priv_s *)arg;
struct i2c_msg_s *msg = &priv->msgv[priv->msgid];
struct i2c_msg_s *msg;
volatile uint32_t status;
uint8_t clear_irq = 1u;

DEBUGASSERT(msg != NULL);
/* On a very special case, i2c irq might arrive shortly after a warm
* reboot. Try to detect that with some sanity checks.
*/

if (priv == NULL)
{
return 0;
}

msg = &priv->msgv[priv->msgid];
if (msg == NULL)
{
return 0;
}

status = getreg32(MPFS_I2C_STATUS);

Expand Down Expand Up @@ -478,7 +491,12 @@ 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");
return 0;
}

putreg32(priv->tx_buffer[priv->tx_idx], MPFS_I2C_DATA);
priv->tx_idx++;
}
Expand Down Expand Up @@ -556,10 +574,14 @@ 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");
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 +593,21 @@ 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");
return 0;
}
else if (priv->rx_idx >= priv->rx_size)
{
i2cerr("ERROR: rx_idx is out of bounds!\n");
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 +705,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 +751,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 +809,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 4048a84

Please sign in to comment.