From 2c4fe28d4ee9af35a660fca8a8d1b6ced59c7ced Mon Sep 17 00:00:00 2001 From: wangzhi16 Date: Thu, 23 Jan 2025 15:14:28 +0800 Subject: [PATCH] Use small lock to protect resources related to i2c master and slave. Signed-off-by: wangzhi16 --- arch/arm/src/lpc54xx/lpc54_i2c_master.c | 29 +++++++++++----- arch/arm/src/rp2040/rp2040_i2c_slave.c | 38 ++++++++++++-------- arch/arm/src/rp23xx/rp23xx_i2c_slave.c | 38 ++++++++++++-------- arch/arm/src/samd2l2/sam_i2c_master.c | 42 ++++++++++++++-------- arch/arm/src/samd5e5/sam_i2c_master.c | 46 +++++++++++++++++-------- arch/arm/src/stm32/stm32_i2c_alt.c | 14 ++++++-- arch/arm/src/stm32/stm32_i2c_v2.c | 19 +++++++--- 7 files changed, 150 insertions(+), 76 deletions(-) diff --git a/arch/arm/src/lpc54xx/lpc54_i2c_master.c b/arch/arm/src/lpc54xx/lpc54_i2c_master.c index 0e61e4af8fd37..ead84fadfc109 100644 --- a/arch/arm/src/lpc54xx/lpc54_i2c_master.c +++ b/arch/arm/src/lpc54xx/lpc54_i2c_master.c @@ -60,7 +60,7 @@ #include #include -#include +#include #include #include "chip.h" @@ -136,6 +136,7 @@ struct lpc54_i2cdev_s int16_t result; /* The result of the transfer */ mutex_t lock; /* Only one thread can access at a time */ + spinlock_t spinlock; /* Spinlock */ #ifndef CONFIG_I2C_POLLED sem_t waitsem; /* Supports wait for state machine completion */ uint16_t irq; /* Flexcomm IRQ number */ @@ -186,6 +187,7 @@ struct i2c_ops_s lpc54_i2c_ops = static struct lpc54_i2cdev_s g_i2c0_dev = { .lock = NXMUTEX_INITIALIZER, + .spinlock = SP_UNLOCKED, # ifndef CONFIG_I2C_POLLED .waitsem = SEM_INITIALIZER(0), # endif @@ -196,6 +198,7 @@ static struct lpc54_i2cdev_s g_i2c0_dev = static struct lpc54_i2cdev_s g_i2c1_dev = { .lock = NXMUTEX_INITIALIZER, + .spinlock = SP_UNLOCKED, # ifndef CONFIG_I2C_POLLED .waitsem = SEM_INITIALIZER(0), # endif @@ -206,6 +209,7 @@ static struct lpc54_i2cdev_s g_i2c1_dev = static struct lpc54_i2cdev_s g_i2c2_dev = { .lock = NXMUTEX_INITIALIZER, + .spinlock = SP_UNLOCKED, # ifndef CONFIG_I2C_POLLED .waitsem = SEM_INITIALIZER(0), # endif @@ -216,6 +220,7 @@ static struct lpc54_i2cdev_s g_i2c2_dev = static struct lpc54_i2cdev_s g_i2c3_dev = { .lock = NXMUTEX_INITIALIZER, + .spinlock = SP_UNLOCKED, # ifndef CONFIG_I2C_POLLED .waitsem = SEM_INITIALIZER(0), # endif @@ -226,6 +231,7 @@ static struct lpc54_i2cdev_s g_i2c3_dev = static struct lpc54_i2cdev_s g_i2c4_dev = { .lock = NXMUTEX_INITIALIZER, + .spinlock = SP_UNLOCKED, # ifndef CONFIG_I2C_POLLED .waitsem = SEM_INITIALIZER(0), # endif @@ -236,6 +242,7 @@ static struct lpc54_i2cdev_s g_i2c4_dev = static struct lpc54_i2cdev_s g_i2c5_dev = { .lock = NXMUTEX_INITIALIZER, + .spinlock = SP_UNLOCKED, # ifndef CONFIG_I2C_POLLED .waitsem = SEM_INITIALIZER(0), # endif @@ -246,6 +253,7 @@ static struct lpc54_i2cdev_s g_i2c5_dev = static struct lpc54_i2cdev_s g_i2c6_dev = { .lock = NXMUTEX_INITIALIZER, + .spinlock = SP_UNLOCKED, # ifndef CONFIG_I2C_POLLED .waitsem = SEM_INITIALIZER(0), # endif @@ -256,6 +264,7 @@ static struct lpc54_i2cdev_s g_i2c6_dev = static struct lpc54_i2cdev_s g_i2c7_dev = { .lock = NXMUTEX_INITIALIZER, + .spinlock = SP_UNLOCKED, # ifndef CONFIG_I2C_POLLED .waitsem = SEM_INITIALIZER(0), # endif @@ -266,6 +275,7 @@ static struct lpc54_i2cdev_s g_i2c7_dev = static struct lpc54_i2cdev_s g_i2c8_dev = { .lock = NXMUTEX_INITIALIZER, + .spinlock = SP_UNLOCKED, # ifndef CONFIG_I2C_POLLED .waitsem = SEM_INITIALIZER(0), # endif @@ -276,6 +286,7 @@ static struct lpc54_i2cdev_s g_i2c8_dev = static struct lpc54_i2cdev_s g_i2c9_dev = { .lock = NXMUTEX_INITIALIZER, + .spinlock = SP_UNLOCKED, # ifndef CONFIG_I2C_POLLED .waitsem = SEM_INITIALIZER(0), # endif @@ -409,7 +420,7 @@ static void lpc54_i2c_timeout(wdparm_t arg) struct lpc54_i2cdev_s *priv = (struct lpc54_i2cdev_s *)arg; #ifndef CONFIG_I2C_POLLED - irqstate_t flags = enter_critical_section(); + irqstate_t flags = spin_lock_irqsave(&priv->spinlock); #endif i2cerr("ERROR: Timeout! state=%u\n", priv->state); @@ -430,7 +441,7 @@ static void lpc54_i2c_timeout(wdparm_t arg) /* Wake up any waiters */ nxsem_post(&priv->waitsem); - leave_critical_section(flags); + spin_unlock_irqrestore(&priv->spinlock, flags); #endif } @@ -521,7 +532,7 @@ static bool lpc54_i2c_nextmsg(struct lpc54_i2cdev_s *priv) * here. */ - flags = enter_critical_section(); + flags = spin_lock_irqsave(&priv->spinlock); i2cinfo("nmsgs=%u\n", priv->nmsgs - 1); @@ -535,7 +546,7 @@ static bool lpc54_i2c_nextmsg(struct lpc54_i2cdev_s *priv) lpc54_i2c_xfrsetup(priv); i2cinfo("state=%u\n", priv->state); - leave_critical_section(flags); + spin_unlock_irqrestore(&priv->spinlock, flags); return false; } else @@ -552,7 +563,7 @@ static bool lpc54_i2c_nextmsg(struct lpc54_i2cdev_s *priv) priv->state = I2CSTATE_IDLE; i2cinfo("state=%u\n", priv->state); - leave_critical_section(flags); + spin_unlock_irqrestore(&priv->spinlock, flags); return true; } } @@ -903,7 +914,7 @@ struct i2c_master_s *lpc54_i2cbus_initialize(int port) i2cinfo("port=%d\n", port); - flags = enter_critical_section(); + flags = spin_lock_irqsave(&priv->spinlock); /* Configure the requestin I2C peripheral */ @@ -1252,12 +1263,12 @@ struct i2c_master_s *lpc54_i2cbus_initialize(int port) else #endif { + spin_unlock_irqrestore(&priv->spinlock, flags); i2cerr("ERROR: Unsupported port=%d\n", port); - leave_critical_section(flags); return NULL; } - leave_critical_section(flags); + spin_unlock_irqrestore(&priv->spinlock, flags); /* Install our operations */ diff --git a/arch/arm/src/rp2040/rp2040_i2c_slave.c b/arch/arm/src/rp2040/rp2040_i2c_slave.c index c9aabe2d8b070..e8d17cfd5504d 100644 --- a/arch/arm/src/rp2040/rp2040_i2c_slave.c +++ b/arch/arm/src/rp2040/rp2040_i2c_slave.c @@ -37,7 +37,7 @@ #include #include -#include +#include #include #include @@ -77,6 +77,8 @@ typedef struct rp2040_i2c_slave_s i2c_slave_callback_t *callback; /* Callback function */ void *callback_arg; /* Argument for callback */ + + spinlock_t spinlock; /* Spinlock */ } rp2040_i2c_slave_t; /**************************************************************************** @@ -123,6 +125,7 @@ rp2040_i2c_slave_t i2c0_slave_dev = { .dev.ops = &i2c_slaveops, /* Slave operations */ .controller = 0, /* I2C controller number */ + .spinlock = SP_UNLOCKED, /* Spinlock */ }; #endif @@ -133,6 +136,7 @@ rp2040_i2c_slave_t i2c1_slave_dev = { .dev.ops = &i2c_slaveops, /* Slave operations */ .controller = 1, /* I2C controller number */ + .spinlock = SP_UNLOCKED, /* Spinlock */ }; #endif @@ -312,12 +316,9 @@ static int i2c_interrupt(int irq, void *context, void *arg) * ****************************************************************************/ -static void enable_i2c_slave(struct i2c_slave_s *dev) +static void enable_i2c_slave_nolock(struct i2c_slave_s *dev) { rp2040_i2c_slave_t *priv = (rp2040_i2c_slave_t *) dev; - irqstate_t flags; - - flags = enter_critical_section(); uint32_t intr_mask = RP2040_I2C_IC_INTR_STAT_R_RD_REQ | RP2040_I2C_IC_INTR_STAT_R_RX_FULL @@ -344,8 +345,15 @@ static void enable_i2c_slave(struct i2c_slave_s *dev) putreg32(RP2040_I2C_IC_ENABLE_ENABLE, RP2040_I2C_IC_ENABLE(priv->controller)); +} + +static void enable_i2c_slave(struct i2c_slave_s *dev) +{ + irqstate_t flags; - leave_critical_section(flags); + flags = spin_lock_irqsave(&priv->spinlock); + enable_i2c_slave_nolock(dev); + spin_unlock_irqrestore(&priv->spinlock, flags); } /**************************************************************************** @@ -366,7 +374,7 @@ static int my_set_own_address(struct i2c_slave_s *dev, | RP2040_I2C_IC_CON_SPEED_FAST; irqstate_t flags; - flags = enter_critical_section(); + flags = spin_lock_irqsave(&priv->spinlock); putreg32(address, RP2040_I2C_IC_SAR(priv->controller)); @@ -377,9 +385,9 @@ static int my_set_own_address(struct i2c_slave_s *dev, putreg32(con, RP2040_I2C_IC_CON(priv->controller)); - enable_i2c_slave(dev); + enable_i2c_slave_nolock(dev); - leave_critical_section(flags); + spin_unlock_irqrestore(&priv->spinlock, flags); return OK; } @@ -399,13 +407,13 @@ static int my_write(struct i2c_slave_s *dev, rp2040_i2c_slave_t *priv = (rp2040_i2c_slave_t *) dev; irqstate_t flags; - flags = enter_critical_section(); + flags = spin_lock_irqsave(&priv->spinlock); priv->tx_buffer = buffer; priv->tx_buf_ptr = buffer; priv->tx_buf_end = priv->tx_buffer + length; - leave_critical_section(flags); + spin_unlock_irqrestore(&priv->spinlock, flags); return OK; } @@ -426,13 +434,13 @@ static int my_read(struct i2c_slave_s *dev, rp2040_i2c_slave_t *priv = (rp2040_i2c_slave_t *) dev; irqstate_t flags; - flags = enter_critical_section(); + flags = spin_lock_irqsave(&priv->spinlock); priv->rx_buffer = buffer; priv->rx_buf_ptr = buffer; priv->rx_buf_end = priv->rx_buffer + length; - leave_critical_section(flags); + spin_unlock_irqrestore(&priv->spinlock, flags); return OK; } @@ -453,12 +461,12 @@ static int my_register_callback(struct i2c_slave_s *dev, rp2040_i2c_slave_t *priv = (rp2040_i2c_slave_t *) dev; irqstate_t flags; - flags = enter_critical_section(); + flags = spin_lock_irqsave(&priv->spinlock); priv->callback = callback; priv->callback_arg = arg; - leave_critical_section(flags); + spin_unlock_irqrestore(&priv->spinlock, flags); return OK; } diff --git a/arch/arm/src/rp23xx/rp23xx_i2c_slave.c b/arch/arm/src/rp23xx/rp23xx_i2c_slave.c index 7502a6c34397e..2d6ca7bdc3502 100644 --- a/arch/arm/src/rp23xx/rp23xx_i2c_slave.c +++ b/arch/arm/src/rp23xx/rp23xx_i2c_slave.c @@ -37,7 +37,7 @@ #include #include -#include +#include #include #include @@ -77,6 +77,8 @@ typedef struct rp23xx_i2c_slave_s i2c_slave_callback_t *callback; /* Callback function */ void *callback_arg; /* Argument for callback */ + + spinlock_t spinlock; /* Spinlock */ } rp23xx_i2c_slave_t; /**************************************************************************** @@ -123,6 +125,7 @@ rp23xx_i2c_slave_t i2c0_slave_dev = { .dev.ops = &i2c_slaveops, /* Slave operations */ .controller = 0, /* I2C controller number */ + .spinlock = SP_UNLOCKED, /* Spinlock */ }; #endif @@ -133,6 +136,7 @@ rp23xx_i2c_slave_t i2c1_slave_dev = { .dev.ops = &i2c_slaveops, /* Slave operations */ .controller = 1, /* I2C controller number */ + .spinlock = SP_UNLOCKED, /* Spinlock */ }; #endif @@ -312,12 +316,9 @@ static int i2c_interrupt(int irq, void *context, void *arg) * ****************************************************************************/ -static void enable_i2c_slave(struct i2c_slave_s *dev) +static void enable_i2c_slave_nolock(struct i2c_slave_s *dev) { rp23xx_i2c_slave_t *priv = (rp23xx_i2c_slave_t *) dev; - irqstate_t flags; - - flags = enter_critical_section(); uint32_t intr_mask = RP23XX_I2C_IC_INTR_STAT_R_RD_REQ | RP23XX_I2C_IC_INTR_STAT_R_RX_FULL @@ -344,8 +345,15 @@ static void enable_i2c_slave(struct i2c_slave_s *dev) putreg32(RP23XX_I2C_IC_ENABLE_ENABLE, RP23XX_I2C_IC_ENABLE(priv->controller)); +} + +static void enable_i2c_slave(struct i2c_slave_s *dev) +{ + irqstate_t flags; - leave_critical_section(flags); + flags = spin_lock_irqsave(&priv->spinlock); + enable_i2c_slave_nolock(dev); + spin_unlock_irqrestore(&priv->spinlock, flags); } /**************************************************************************** @@ -366,7 +374,7 @@ static int my_set_own_address(struct i2c_slave_s *dev, | RP23XX_I2C_IC_CON_SPEED_FAST; irqstate_t flags; - flags = enter_critical_section(); + flags = spin_lock_irqsave(&priv->spinlock); putreg32(address, RP23XX_I2C_IC_SAR(priv->controller)); @@ -377,9 +385,9 @@ static int my_set_own_address(struct i2c_slave_s *dev, putreg32(con, RP23XX_I2C_IC_CON(priv->controller)); - enable_i2c_slave(dev); + enable_i2c_slave_nolock(dev); - leave_critical_section(flags); + spin_unlock_irqrestore(&priv->spinlock, flags); return OK; } @@ -399,13 +407,13 @@ static int my_write(struct i2c_slave_s *dev, rp23xx_i2c_slave_t *priv = (rp23xx_i2c_slave_t *) dev; irqstate_t flags; - flags = enter_critical_section(); + flags = spin_lock_irqsave(&priv->spinlock); priv->tx_buffer = buffer; priv->tx_buf_ptr = buffer; priv->tx_buf_end = priv->tx_buffer + length; - leave_critical_section(flags); + spin_unlock_irqrestore(&priv->spinlock, flags); return OK; } @@ -426,13 +434,13 @@ static int my_read(struct i2c_slave_s *dev, rp23xx_i2c_slave_t *priv = (rp23xx_i2c_slave_t *) dev; irqstate_t flags; - flags = enter_critical_section(); + flags = spin_lock_irqsave(&priv->spinlock); priv->rx_buffer = buffer; priv->rx_buf_ptr = buffer; priv->rx_buf_end = priv->rx_buffer + length; - leave_critical_section(flags); + spin_unlock_irqrestore(&priv->spinlock, flags); return OK; } @@ -453,12 +461,12 @@ static int my_register_callback(struct i2c_slave_s *dev, rp23xx_i2c_slave_t *priv = (rp23xx_i2c_slave_t *) dev; irqstate_t flags; - flags = enter_critical_section(); + flags = spin_lock_irqsave(&priv->spinlock); priv->callback = callback; priv->callback_arg = arg; - leave_critical_section(flags); + spin_unlock_irqrestore(&priv->spinlock, flags); return OK; } diff --git a/arch/arm/src/samd2l2/sam_i2c_master.c b/arch/arm/src/samd2l2/sam_i2c_master.c index a7e83d3b1d875..cde0029fdcdaf 100644 --- a/arch/arm/src/samd2l2/sam_i2c_master.c +++ b/arch/arm/src/samd2l2/sam_i2c_master.c @@ -58,7 +58,7 @@ #include #include -#include +#include #include #include #include @@ -171,6 +171,7 @@ struct sam_i2c_dev_s uint16_t nextflags; /* Next message flags */ mutex_t lock; /* Only one thread can access at a time */ + spinlock_t spinlock; /* Spinlock */ sem_t waitsem; /* Wait for I2C transfer completion */ volatile int result; /* The result of the transfer */ volatile int xfrd; /* Number of bytes transfers */ @@ -284,6 +285,7 @@ static struct sam_i2c_dev_s g_i2c0 = }, .attr = &g_i2c0attr, .lock = NXMUTEX_INITIALIZER, + .spinlock = SP_UNLOCKED, .waitsem = SEM_INITIALIZER(0), }; #endif @@ -310,6 +312,7 @@ static struct sam_i2c_dev_s g_i2c1 = }, .attr = &g_i2c1attr, .lock = NXMUTEX_INITIALIZER, + .spinlock = SP_UNLOCKED, .waitsem = SEM_INITIALIZER(0), }; #endif @@ -337,6 +340,7 @@ static struct sam_i2c_dev_s g_i2c2 = }, .attr = &g_i2c2attr, .lock = NXMUTEX_INITIALIZER, + .spinlock = SP_UNLOCKED, .waitsem = SEM_INITIALIZER(0), }; #endif @@ -364,6 +368,7 @@ static struct sam_i2c_dev_s g_i2c3 = }, .attr = &g_i2c3attr, .lock = NXMUTEX_INITIALIZER, + .spinlock = SP_UNLOCKED, .waitsem = SEM_INITIALIZER(0), }; #endif @@ -391,6 +396,7 @@ static struct sam_i2c_dev_s g_i2c4 = }, .attr = &g_i2c4attr, .lock = NXMUTEX_INITIALIZER, + .spinlock = SP_UNLOCKED, .waitsem = SEM_INITIALIZER(0), }; #endif @@ -418,6 +424,7 @@ static struct sam_i2c_dev_s g_i2c5 = }, .attr = &g_i2c5attr, .lock = NXMUTEX_INITIALIZER, + .spinlock = SP_UNLOCKED, .waitsem = SEM_INITIALIZER(0), }; #endif @@ -1018,14 +1025,16 @@ static int sam_i2c_transfer(struct i2c_master_s *dev, { priv->msg = msgs; priv->nextflags = count == 0 ? 0 : msgs[1].flags; - flags = enter_critical_section(); + flags = spin_lock_irqsave(&priv->spinlock); i2c_startmessage(priv, msgs); /* And wait for the transfers to complete. * Interrupts will be re-enabled while we are waiting. */ + spin_unlock_irqrestore(&priv->spinlock, flags); ret = i2c_wait_for_bus(priv, msgs->length); + flags = spin_lock_irqsave(&priv->spinlock); if (ret < 0) { #if 0 @@ -1040,12 +1049,12 @@ static int sam_i2c_transfer(struct i2c_master_s *dev, i2c_putreg8(priv, I2C_INT_MB | I2C_INT_SB, SAM_I2C_INTENCLR_OFFSET); - leave_critical_section(flags); + spin_unlock_irqrestore(&priv->spinlock, flags); nxmutex_unlock(&priv->lock); return ret; } - leave_critical_section(flags); + spin_unlock_irqrestore(&priv->spinlock, flags); /* Move to the next message */ @@ -1169,9 +1178,9 @@ static uint32_t sam_i2c_setfrequency(struct sam_i2c_dev_s *priv, * ****************************************************************************/ -static void i2c_hw_initialize(struct sam_i2c_dev_s *priv, uint32_t frequency) +static void i2c_hw_initialize_nolock(struct sam_i2c_dev_s *priv, + uint32_t frequency) { - irqstate_t flags; uint32_t regval; uint32_t ctrla = 0; @@ -1179,7 +1188,6 @@ static void i2c_hw_initialize(struct sam_i2c_dev_s *priv, uint32_t frequency) /* Enable clocking to the SERCOM module in PM */ - flags = enter_critical_section(); sercom_enable(priv->attr->sercom); /* Configure the GCLKs for the SERCOM module */ @@ -1194,7 +1202,6 @@ static void i2c_hw_initialize(struct sam_i2c_dev_s *priv, uint32_t frequency) { i2cerr ("ERROR: Cannot initialize I2C because it is already initialized!\n"); - leave_critical_section(flags); return; } @@ -1204,7 +1211,6 @@ static void i2c_hw_initialize(struct sam_i2c_dev_s *priv, uint32_t frequency) if (regval & I2C_CTRLA_SWRST) { i2cerr("ERROR: Module is in RESET process!\n"); - leave_critical_section(flags); return; } @@ -1244,7 +1250,15 @@ static void i2c_hw_initialize(struct sam_i2c_dev_s *priv, uint32_t frequency) /* Enable SERCOM interrupts at the NVIC */ up_enable_irq(priv->attr->irq); - leave_critical_section(flags); +} + +static void i2c_hw_initialize(struct sam_i2c_dev_s *priv, uint32_t frequency) +{ + irqstate_t flags; + + flags = spin_lock_irqsave(&priv->spinlock); + i2c_hw_initialize_nolock(priv, frequency); + spin_unlock_irqrestore(&priv->spinlock, flags); } /**************************************************************************** @@ -1369,7 +1383,7 @@ struct i2c_master_s *sam_i2c_master_initialize(int bus) /* Perform one-time I2C initialization */ - flags = enter_critical_section(); + flags = spin_lock_irqsave(&priv->spinlock); /* Attach Interrupt Handler */ @@ -1377,14 +1391,14 @@ struct i2c_master_s *sam_i2c_master_initialize(int bus) if (ret < 0) { i2cerr("ERROR: Failed to attach irq %d\n", priv->attr->irq); - leave_critical_section(flags); + spin_unlock_irqrestore(&priv->spinlock, flags); return NULL; } /* Perform repeatable I2C hardware initialization */ - i2c_hw_initialize(priv, frequency); - leave_critical_section(flags); + i2c_hw_initialize_nolock(priv, frequency); + spin_unlock_irqrestore(&priv->spinlock, flags); return &priv->dev; } diff --git a/arch/arm/src/samd5e5/sam_i2c_master.c b/arch/arm/src/samd5e5/sam_i2c_master.c index 69ee4258bfe56..4f8bbb80c457b 100644 --- a/arch/arm/src/samd5e5/sam_i2c_master.c +++ b/arch/arm/src/samd5e5/sam_i2c_master.c @@ -55,7 +55,7 @@ #include #include -#include +#include #include #include #include @@ -165,6 +165,7 @@ struct sam_i2c_dev_s uint16_t nextflags; /* Next message flags */ mutex_t lock; /* Only one thread can access at a time */ + spinlock_t spinlock; /* Spinlock */ sem_t waitsem; /* Wait for I2C transfer completion */ volatile int result; /* The result of the transfer */ volatile int xfrd; /* Number of bytes transfers */ @@ -276,6 +277,7 @@ static struct sam_i2c_dev_s g_i2c0 = }, .attr = &g_i2c0attr, .lock = NXMUTEX_INITIALIZER, + .spinlock = SP_UNLOCKED, .waitsem = SEM_INITIALIZER(0), }; #endif @@ -303,6 +305,7 @@ static struct sam_i2c_dev_s g_i2c1 = }, .attr = &g_i2c1attr, .lock = NXMUTEX_INITIALIZER, + .spinlock = SP_UNLOCKED, .waitsem = SEM_INITIALIZER(0), }; #endif @@ -330,6 +333,7 @@ static struct sam_i2c_dev_s g_i2c2 = }, .attr = &g_i2c2attr, .lock = NXMUTEX_INITIALIZER, + .spinlock = SP_UNLOCKED, .waitsem = SEM_INITIALIZER(0), }; #endif @@ -357,6 +361,7 @@ static struct sam_i2c_dev_s g_i2c3 = }, .attr = &g_i2c3attr, .lock = NXMUTEX_INITIALIZER, + .spinlock = SP_UNLOCKED, .waitsem = SEM_INITIALIZER(0), }; #endif @@ -384,6 +389,7 @@ static struct sam_i2c_dev_s g_i2c4 = }, .attr = &g_i2c4attr, .lock = NXMUTEX_INITIALIZER, + .spinlock = SP_UNLOCKED, .waitsem = SEM_INITIALIZER(0), }; #endif @@ -411,6 +417,7 @@ static struct sam_i2c_dev_s g_i2c5 = }, .attr = &g_i2c5attr, .lock = NXMUTEX_INITIALIZER, + .spinlock = SP_UNLOCKED, .waitsem = SEM_INITIALIZER(0), }; #endif @@ -438,6 +445,7 @@ static struct sam_i2c_dev_s g_i2c6 = }, .attr = &g_i2c6attr, .lock = NXMUTEX_INITIALIZER, + .spinlock = SP_UNLOCKED, .waitsem = SEM_INITIALIZER(0), }; #endif @@ -465,6 +473,7 @@ static struct sam_i2c_dev_s g_i2c7 = }, .attr = &g_i2c7attr, .lock = NXMUTEX_INITIALIZER, + .spinlock = SP_UNLOCKED, .waitsem = SEM_INITIALIZER(0), }; #endif @@ -1068,22 +1077,24 @@ static int sam_i2c_transfer(struct i2c_master_s *dev, { priv->msg = msgs; priv->nextflags = count == 0 ? 0 : msgs[1].flags; - flags = enter_critical_section(); + flags = spin_lock_irqsave(&priv->spinlock); i2c_startmessage(priv, msgs); /* And wait for the transfers to complete. * Interrupts will be re-enabled while we are waiting. */ + spin_unlock_irqrestore(&priv->spinlock, flags); ret = i2c_wait_for_bus(priv, msgs->length); + flags = spin_lock_irqsave(&priv->spinlock); if (ret < 0) { - leave_critical_section(flags); + spin_unlock_irqrestore(&priv->spinlock, flags); nxmutex_unlock(&priv->lock); return ret; } - leave_critical_section(flags); + spin_unlock_irqrestore(&priv->spinlock, flags); /* Move to the next message */ @@ -1209,9 +1220,9 @@ static uint32_t sam_i2c_setfrequency(struct sam_i2c_dev_s *priv, * ****************************************************************************/ -static void i2c_hw_initialize(struct sam_i2c_dev_s *priv, uint32_t frequency) +static void i2c_hw_initialize_nolock(struct sam_i2c_dev_s *priv, + uint32_t frequency) { - irqstate_t flags; uint32_t regval; uint32_t ctrla = 0; @@ -1219,7 +1230,6 @@ static void i2c_hw_initialize(struct sam_i2c_dev_s *priv, uint32_t frequency) /* Enable clocking to the SERCOM module in PM */ - flags = enter_critical_section(); sercom_enable(priv->attr->sercom); /* Configure the GCLKs for the SERCOM module */ @@ -1234,7 +1244,6 @@ static void i2c_hw_initialize(struct sam_i2c_dev_s *priv, uint32_t frequency) { i2cerr("ERROR: Cannot initialize I2C " "because it is already initialized!\n"); - leave_critical_section(flags); return; } @@ -1244,7 +1253,6 @@ static void i2c_hw_initialize(struct sam_i2c_dev_s *priv, uint32_t frequency) if (regval & I2C_CTRLA_SWRST) { i2cerr("ERROR: Module is in RESET process!\n"); - leave_critical_section(flags); return; } @@ -1288,7 +1296,15 @@ static void i2c_hw_initialize(struct sam_i2c_dev_s *priv, uint32_t frequency) up_enable_irq(priv->attr->irq); up_enable_irq(priv->attr->irq + 1); - leave_critical_section(flags); +} + +static void i2c_hw_initialize(struct sam_i2c_dev_s *priv, uint32_t frequency) +{ + irqstate_t flags; + + flags = spin_lock_irqsave(&priv->spinlock); + i2c_hw_initialize_nolock(priv, frequency); + spin_unlock_irqrestore(&priv->spinlock, flags); } /**************************************************************************** @@ -1433,7 +1449,7 @@ struct i2c_master_s *sam_i2c_master_initialize(int bus) /* Perform one-time I2C initialization */ - flags = enter_critical_section(); + flags = spin_lock_irqsave(&priv->spinlock); /* Attach Interrupt Handler */ @@ -1441,7 +1457,7 @@ struct i2c_master_s *sam_i2c_master_initialize(int bus) if (ret < 0) { i2cerr("ERROR: Failed to attach irq %d\n", priv->attr->irq); - leave_critical_section(flags); + spin_unlock_irqrestore(&priv->spinlock, flags); return NULL; } @@ -1449,14 +1465,14 @@ struct i2c_master_s *sam_i2c_master_initialize(int bus) if (ret < 0) { i2cerr("ERROR: Failed to attach irq %d\n", priv->attr->irq); - leave_critical_section(flags); + spin_unlock_irqrestore(&priv->spinlock, flags); return NULL; } /* Perform repeatable I2C hardware initialization */ - i2c_hw_initialize(priv, frequency); - leave_critical_section(flags); + i2c_hw_initialize_nolock(priv, frequency); + spin_unlock_irqrestore(&priv->spinlock, flags); return &priv->dev; } diff --git a/arch/arm/src/stm32/stm32_i2c_alt.c b/arch/arm/src/stm32/stm32_i2c_alt.c index a23a66ec62679..5eed869c0dbd8 100644 --- a/arch/arm/src/stm32/stm32_i2c_alt.c +++ b/arch/arm/src/stm32/stm32_i2c_alt.c @@ -89,7 +89,7 @@ #include #include -#include +#include #include #include #include @@ -288,6 +288,7 @@ struct stm32_i2c_priv_s int refs; /* Reference count */ mutex_t lock; /* Mutual exclusion mutex */ + spinlock_t spinlock; /* Spinlock */ #ifndef CONFIG_I2C_POLLED sem_t sem_isr; /* Interrupt wait semaphore */ #endif @@ -406,6 +407,7 @@ static struct stm32_i2c_priv_s stm32_i2c1_priv = .config = &stm32_i2c1_config, .refs = 0, .lock = NXMUTEX_INITIALIZER, + .spinlock = SP_UNLOCKED, #ifndef CONFIG_I2C_POLLED .sem_isr = SEM_INITIALIZER(0), #endif @@ -439,6 +441,7 @@ static struct stm32_i2c_priv_s stm32_i2c2_priv = .config = &stm32_i2c2_config, .refs = 0, .lock = NXMUTEX_INITIALIZER, + .spinlock = SP_UNLOCKED, #ifndef CONFIG_I2C_POLLED .sem_isr = SEM_INITIALIZER(0), #endif @@ -472,6 +475,7 @@ static struct stm32_i2c_priv_s stm32_i2c3_priv = .config = &stm32_i2c3_config, .refs = 0, .lock = NXMUTEX_INITIALIZER, + .spinlock = SP_UNLOCKED, #ifndef CONFIG_I2C_POLLED .sem_isr = SEM_INITIALIZER(0), #endif @@ -577,7 +581,7 @@ static int stm32_i2c_sem_waitdone(struct stm32_i2c_priv_s *priv) uint32_t regval; int ret; - flags = enter_critical_section(); + flags = spin_lock_irqsave(&priv->spinlock); /* Enable I2C interrupts */ @@ -593,6 +597,8 @@ static int stm32_i2c_sem_waitdone(struct stm32_i2c_priv_s *priv) priv->intstate = INTSTATE_WAITING; do { + spin_unlock_irqrestore(&priv->spinlock, flags); + /* Wait until either the transfer is complete or the timeout expires */ #ifdef CONFIG_STM32_I2C_DYNTIMEO @@ -611,6 +617,8 @@ static int stm32_i2c_sem_waitdone(struct stm32_i2c_priv_s *priv) break; } + + flags = spin_lock_irqsave(&priv->spinlock); } /* Loop until the interrupt level transfer is complete. */ @@ -627,7 +635,7 @@ static int stm32_i2c_sem_waitdone(struct stm32_i2c_priv_s *priv) regval &= ~I2C_CR2_ALLINTS; stm32_i2c_putreg(priv, STM32_I2C_CR2_OFFSET, regval); - leave_critical_section(flags); + spin_unlock_irqrestore(&priv->spinlock, flags); return ret; } #else diff --git a/arch/arm/src/stm32/stm32_i2c_v2.c b/arch/arm/src/stm32/stm32_i2c_v2.c index 3ddf200be78e9..a8476888fcb92 100644 --- a/arch/arm/src/stm32/stm32_i2c_v2.c +++ b/arch/arm/src/stm32/stm32_i2c_v2.c @@ -225,7 +225,7 @@ #include #include -#include +#include #include #include #include @@ -407,6 +407,7 @@ struct stm32_i2c_priv_s int refs; /* Reference count */ mutex_t lock; /* Mutual exclusion mutex */ + spinlock_t spinlock; /* Spinlock */ #ifndef CONFIG_I2C_POLLED sem_t sem_isr; /* Interrupt wait semaphore */ #endif @@ -520,6 +521,7 @@ static struct stm32_i2c_priv_s stm32_i2c1_priv = .config = &stm32_i2c1_config, .refs = 0, .lock = NXMUTEX_INITIALIZER, + .spinlock = SP_UNLOCKED, #ifndef CONFIG_I2C_POLLED .sem_isr = SEM_INITIALIZER(0), #endif @@ -556,6 +558,7 @@ static struct stm32_i2c_priv_s stm32_i2c2_priv = .config = &stm32_i2c2_config, .refs = 0, .lock = NXMUTEX_INITIALIZER, + .spinlock = SP_UNLOCKED, #ifndef CONFIG_I2C_POLLED .sem_isr = SEM_INITIALIZER(0), #endif @@ -592,6 +595,7 @@ static struct stm32_i2c_priv_s stm32_i2c3_priv = .config = &stm32_i2c3_config, .refs = 0, .lock = NXMUTEX_INITIALIZER, + .spinlock = SP_UNLOCKED, #ifndef CONFIG_I2C_POLLED .sem_isr = SEM_INITIALIZER(0), #endif @@ -628,6 +632,7 @@ static struct stm32_i2c_priv_s stm32_i2c4_priv = .config = &stm32_i2c4_config, .refs = 0, .lock = NXMUTEX_INITIALIZER, + .spinlock = SP_UNLOCKED, #ifndef CONFIG_I2C_POLLED .sem_isr = SEM_INITIALIZER(0), #endif @@ -793,7 +798,7 @@ static inline int stm32_i2c_sem_waitdone(struct stm32_i2c_priv_s *priv) irqstate_t flags; int ret; - flags = enter_critical_section(); + flags = spin_lock_irqsave(&priv->spinlock); /* Enable I2C interrupts */ @@ -810,6 +815,8 @@ static inline int stm32_i2c_sem_waitdone(struct stm32_i2c_priv_s *priv) priv->intstate = INTSTATE_WAITING; do { + spin_unlock_irqrestore(&priv->spinlock, flags); + /* Wait until either the transfer is complete or the timeout expires */ #ifdef CONFIG_STM32_I2C_DYNTIMEO @@ -828,6 +835,8 @@ static inline int stm32_i2c_sem_waitdone(struct stm32_i2c_priv_s *priv) break; } + + flags = spin_lock_irqsave(&priv->spinlock); } /* Loop until the interrupt level transfer is complete. */ @@ -842,7 +851,7 @@ static inline int stm32_i2c_sem_waitdone(struct stm32_i2c_priv_s *priv) stm32_i2c_modifyreg32(priv, STM32_I2C_CR1_OFFSET, I2C_CR1_ALLINTS, 0); - leave_critical_section(flags); + spin_unlock_irqrestore(&priv->spinlock, flags); return ret; } #else @@ -1742,7 +1751,7 @@ static int stm32_i2c_isr_process(struct stm32_i2c_priv_s *priv) */ #ifdef CONFIG_I2C_POLLED - irqstate_t state = enter_critical_section(); + irqstate_t state = spin_lock_irqsave(&priv->spinlock); #endif /* Receive a byte */ @@ -1759,7 +1768,7 @@ static int stm32_i2c_isr_process(struct stm32_i2c_priv_s *priv) priv->dcnt--; #ifdef CONFIG_I2C_POLLED - leave_critical_section(state); + spin_unlock_irqrestore(&priv->spinlock, state); #endif } else