* [PATCH] i2c: stm32f7: close SMBus alert work before removing ARA
@ 2026-10-12 5:16 Myeonghun Pak
0 siblings, 0 replies; only message in thread
From: Myeonghun Pak @ 2026-10-12 5:16 UTC (permalink / raw)
To: Pierre-Yves MORDRET, Alain Volmat, Andi Shyti
Cc: Maxime Coquelin, Alexandre Torgue, Wolfram Sang, linux-i2c,
linux-stm32, linux-arm-kernel, linux-kernel, Ijae Kim
Clearing ALERTEN does not join a handler that already observed ALERT.
It can enqueue work after the ARA client has cancelled work and freed
its backing state.
Exclude transfers and join both controller IRQs before detaching the
alert pointer. Check that pointer before queuing ARA work, and handle
single-line controllers without disabling the same IRQ twice.
Resume the controller before masking and clearing ALERT. On resume
failure, skip MMIO while pointer detachment still closes the producer.
Restore IRQs and release the bus lock before unregistering ARA so its
worker can finish an I2C transfer.
This issue was found by static analysis.
Fixes: c8062d11e20c ("i2c: stm32f7: add SMBus-Alert support")
Assisted-by: LLM
Co-developed-by: Ijae Kim <ae878000@gmail.com>
Signed-off-by: Ijae Kim <ae878000@gmail.com>
Signed-off-by: Myeonghun Pak <mhun512@gmail.com>
---
drivers/i2c/busses/i2c-stm32f7.c | 44 +++++++++++++++++++++++++++++---
1 file changed, 40 insertions(+), 4 deletions(-)
diff --git a/drivers/i2c/busses/i2c-stm32f7.c b/drivers/i2c/busses/i2c-stm32f7.c
index 6bd281a9ef72..9b8f378afe3b 100644
--- a/drivers/i2c/busses/i2c-stm32f7.c
+++ b/drivers/i2c/busses/i2c-stm32f7.c
@@ -331,6 +331,8 @@ struct stm32f7_i2c_alert {
* @dnf_dt: value of digital filter requested via dt
* @dnf: value of digital filter to apply
* @alert: SMBus alert specific data
+ * @irq_event: interrupt for events
+ * @irq_error: interrupt for errors, or irq_event for single-line controllers
* @atomic: boolean indicating that current transfer is atomic
*/
struct stm32f7_i2c_dev {
@@ -364,6 +366,8 @@ struct stm32f7_i2c_dev {
u32 dnf_dt;
u32 dnf;
struct stm32f7_i2c_alert *alert;
+ int irq_event;
+ int irq_error;
bool atomic;
};
@@ -1534,9 +1538,12 @@ static irqreturn_t stm32f7_i2c_handle_isr_errs(struct stm32f7_i2c_dev *i2c_dev,
}
if (status & STM32F7_I2C_ISR_ALERT) {
+ struct stm32f7_i2c_alert *alert = READ_ONCE(i2c_dev->alert);
+
dev_dbg(dev, "SMBus alert received\n");
writel_relaxed(STM32F7_I2C_ICR_ALERTCF, base + STM32F7_I2C_ICR);
- i2c_handle_smbus_alert(i2c_dev->alert->ara);
+ if (alert)
+ i2c_handle_smbus_alert(alert->ara);
return IRQ_HANDLED;
}
@@ -2116,13 +2123,39 @@ static void stm32f7_i2c_disable_smbus_alert(struct stm32f7_i2c_dev *i2c_dev)
{
struct stm32f7_i2c_alert *alert = i2c_dev->alert;
void __iomem *base = i2c_dev->base;
+ int ret;
+
+ if (!alert)
+ return;
+
+ ret = pm_runtime_resume_and_get(i2c_dev->dev);
+ if (ret < 0)
+ dev_warn(i2c_dev->dev, "Failed to resume for SMBus alert shutdown: %d\n", ret);
+
+ /* Exclude transfers and both interrupt handlers while detaching ARA. */
+ i2c_lock_bus(&i2c_dev->adap, I2C_LOCK_ROOT_ADAPTER);
+ disable_irq(i2c_dev->irq_event);
+ if (i2c_dev->irq_error != i2c_dev->irq_event)
+ disable_irq(i2c_dev->irq_error);
- if (alert) {
- /* Disable SMBus Alert */
+ /* Keep late or pending ALERT flags from queuing work on the old ARA. */
+ WRITE_ONCE(i2c_dev->alert, NULL);
+ if (ret >= 0) {
stm32f7_i2c_clr_bits(base + STM32F7_I2C_CR1,
STM32F7_I2C_CR1_ALERTEN);
- i2c_unregister_device(alert->ara);
+ writel_relaxed(STM32F7_I2C_ICR_ALERTCF, base + STM32F7_I2C_ICR);
+ readl(base + STM32F7_I2C_ISR);
}
+
+ if (i2c_dev->irq_error != i2c_dev->irq_event)
+ enable_irq(i2c_dev->irq_error);
+ enable_irq(i2c_dev->irq_event);
+ i2c_unlock_bus(&i2c_dev->adap, I2C_LOCK_ROOT_ADAPTER);
+
+ /* The alert worker may need a transfer before its removal completes. */
+ i2c_unregister_device(alert->ara);
+ if (ret >= 0)
+ pm_runtime_put_autosuspend(i2c_dev->dev);
}
static u32 stm32f7_i2c_func(struct i2c_adapter *adap)
@@ -2178,6 +2211,8 @@ static int stm32f7_i2c_probe(struct platform_device *pdev)
irq_event = platform_get_irq(pdev, 0);
if (irq_event < 0)
return irq_event;
+ i2c_dev->irq_event = irq_event;
+ i2c_dev->irq_error = irq_event;
i2c_dev->wakeup_src = of_property_read_bool(pdev->dev.of_node,
"wakeup-source");
@@ -2210,6 +2245,7 @@ static int stm32f7_i2c_probe(struct platform_device *pdev)
irq_error = platform_get_irq(pdev, 1);
if (irq_error < 0)
return irq_error;
+ i2c_dev->irq_error = irq_error;
ret = devm_request_threaded_irq(&pdev->dev, irq_error,
NULL,
^ permalink raw reply [flat|nested] only message in thread
only message in thread, other threads:[~2026-10-12 5:16 UTC | newest]
Thread overview: (only message) (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2026-10-12 5:16 [PATCH] i2c: stm32f7: close SMBus alert work before removing ARA Myeonghun Pak
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox
all inboxes | Powered by JetHome®