[PATCH] iommu/exynos: quiesce SysMMU before requesting IRQ
From: Runyu Xiao
Date: Mon Sep 21 2026 - 08:15:47 EST
exynos_sysmmu_probe() registers the IRQ before obtaining clocks and
detecting the SysMMU variant. A pending IRQ during this window can enter
exynos_sysmmu_irq(), which takes data->lock and then dereferences
clk_master and variant before they are initialized.
Obtain the clock resources and initialize the software state before
requesting the IRQ. Detect the variant and quiesce the hardware by
disabling the SysMMU and clearing its configuration while the clocks are
enabled. This leaves the block inactive when the handler is published.
Also ignore interrupts observed while the SysMMU is inactive, so a
spurious interrupt cannot access inactive fault state.
The race is theoretical; no runtime occurrence has been observed.
Fixes: 2a96536e77b4 ("iommu/exynos: Add iommu driver for EXYNOS Platforms")
Cc: stable@xxxxxxxxxxxxxxx
Link: https://lore.kernel.org/all/20260901130527.3289245-1-runyu.xiao@xxxxxxxxxx/
Assisted-by: LLM Codex
Signed-off-by: Runyu Xiao <runyu.xiao@xxxxxxxxxx>
---
drivers/iommu/exynos-iommu.c | 27 ++++++++++++++++++---------
1 file changed, 18 insertions(+), 9 deletions(-)
diff --git a/drivers/iommu/exynos-iommu.c b/drivers/iommu/exynos-iommu.c
index 874d05f4b3969..8081bd93c67cb 100644
--- a/drivers/iommu/exynos-iommu.c
+++ b/drivers/iommu/exynos-iommu.c
@@ -571,9 +571,12 @@ static irqreturn_t exynos_sysmmu_irq(int irq, void *dev_id)
struct sysmmu_fault fault;
int ret = -ENOSYS;
- WARN_ON(!data->active);
-
spin_lock(&data->lock);
+ if (!data->active) {
+ spin_unlock(&data->lock);
+ return IRQ_NONE;
+ }
+
clk_enable(data->clk_master);
itype = __ffs(readl(SYSMMU_REG(data, int_status)));
@@ -744,13 +747,6 @@ static int exynos_sysmmu_probe(struct platform_device *pdev)
if (irq <= 0)
return irq;
- ret = devm_request_irq(dev, irq, exynos_sysmmu_irq, 0,
- dev_name(dev), data);
- if (ret) {
- dev_err(dev, "Unable to register handler of irq %d\n", irq);
- return ret;
- }
-
data->clk = devm_clk_get_optional(dev, "sysmmu");
if (IS_ERR(data->clk))
return PTR_ERR(data->clk);
@@ -777,6 +773,19 @@ static int exynos_sysmmu_probe(struct platform_device *pdev)
__sysmmu_get_version(data);
+ /* Keep the hardware quiesced before publishing the IRQ handler. */
+ __sysmmu_enable_clocks(data);
+ writel(CTRL_DISABLE, data->sfrbase + REG_MMU_CTRL);
+ writel(0, data->sfrbase + REG_MMU_CFG);
+ __sysmmu_disable_clocks(data);
+
+ ret = devm_request_irq(dev, irq, exynos_sysmmu_irq, 0,
+ dev_name(dev), data);
+ if (ret) {
+ dev_err(dev, "Unable to register handler of irq %d\n", irq);
+ return ret;
+ }
+
ret = iommu_device_sysfs_add(&data->iommu, &pdev->dev, NULL,
dev_name(data->sysmmu));
if (ret)
--
2.34.1