Skip to content

Commit

Permalink
mpfs_i2c: fix semaphore race condition
Browse files Browse the repository at this point in the history
MPFS_I2C_ST_STOP_SENT interrupt might be received right after semaphore timeout,
which would cause the semaphore to be in the incorrect signaled state when the
next transfer starts.

Signed-off-by: Tero Salminen <[email protected]>
  • Loading branch information
t-salminen committed Mar 25, 2024
1 parent 8b2053d commit d1140a5
Showing 1 changed file with 23 additions and 3 deletions.
26 changes: 23 additions & 3 deletions arch/risc-v/src/mpfs/mpfs_i2c.c
Original file line number Diff line number Diff line change
Expand Up @@ -425,6 +425,10 @@ static int mpfs_i2c_init(struct mpfs_i2c_priv_s *priv)

putreg32(MPFS_I2C_CTRL_ENS1_MASK, MPFS_I2C_CTRL);

#ifdef CONFIG_MPFS_COREI2C
nxsem_init(&priv->sem_isr, 0, 0);
#endif

priv->initialized = true;
}

Expand Down Expand Up @@ -469,8 +473,24 @@ static void mpfs_i2c_deinit(struct mpfs_i2c_priv_s *priv)

static int mpfs_i2c_sem_waitdone(struct mpfs_i2c_priv_s *priv)
{
int res = 0;
uint32_t timeout = mpfs_i2c_timeout(priv->msgc, priv->msgv);
return nxsem_tickwait_uninterruptible(&priv->sem_isr, USEC2TICK(timeout));

res = nxsem_tickwait_uninterruptible(&priv->sem_isr, USEC2TICK(timeout));

/* -> race condition <- */

priv->inflight = false;

/* Handle a race condition above in which interrupt MPFS_I2C_ST_STOP_SENT was

Check failure on line 485 in arch/risc-v/src/mpfs/mpfs_i2c.c

View workflow job for this annotation

GitHub Actions / check

Long line found
* received right after semaphore timeout. In that case semaphore is signalled

Check failure on line 486 in arch/risc-v/src/mpfs/mpfs_i2c.c

View workflow job for this annotation

GitHub Actions / check

Long line found
* and has the incorrect state when the next transfer starts.
*/

Check failure on line 488 in arch/risc-v/src/mpfs/mpfs_i2c.c

View workflow job for this annotation

GitHub Actions / check

Missing blank line after comment
if (res < 0) {

Check failure on line 489 in arch/risc-v/src/mpfs/mpfs_i2c.c

View workflow job for this annotation

GitHub Actions / check

Left bracket not on separate line
res = nxsem_tickwait_uninterruptible(&priv->sem_isr, USEC2TICK(timeout));
}

Check failure on line 491 in arch/risc-v/src/mpfs/mpfs_i2c.c

View workflow job for this annotation

GitHub Actions / check

Bad right brace alignment

return res;
}

/****************************************************************************
Expand Down Expand Up @@ -872,7 +892,6 @@ static int mpfs_i2c_transfer(struct i2c_master_s *dev,
if (mpfs_i2c_sem_waitdone(priv) < 0)
{
i2cinfo("Message %" PRIu8 " timed out.\n", priv->msgid);
priv->inflight = false;
ret = -ETIMEDOUT;
break;
}
Expand Down Expand Up @@ -933,6 +952,8 @@ static int mpfs_i2c_reset(struct i2c_master_s *dev)

nxmutex_lock(&priv->lock);

i2cerr("i2c bus %d reset\n", priv->id);

mpfs_i2c_deinit(priv);

ret = mpfs_i2c_init(priv);
Expand Down Expand Up @@ -1138,7 +1159,6 @@ struct i2c_master_s *mpfs_i2cbus_initialize(int port)
priv->hw_base = CONFIG_MPFS_COREI2C_BASE +
port * CONFIG_MPFS_COREI2C_INST_OFFSET;
priv->plic_irq = MPFS_IRQ_FABRIC_F2H_0 + CONFIG_MPFS_COREI2C_IRQNUM + port;
nxsem_init(&priv->sem_isr, 0, 0);
priv->status = MPFS_I2C_SUCCESS;
priv->fpga = true;
#endif
Expand Down

0 comments on commit d1140a5

Please sign in to comment.