From acd9bf8f9047b03f023514bceab6a00e037977ca Mon Sep 17 00:00:00 2001 From: Ovidiu Panait Date: Wed, 16 Sep 2026 12:00:01 +0000 Subject: [PATCH] thermal/drivers/renesas/rzg3e: Fix race between set_trips() and get_temp() Datasheet section 7.11.9.2 "Conversion Start Trigger" states that a conversion must only be started while no other conversion is in progress: "Before making the setting to start conversion by software or an ELC trigger, check that the CONV bit of the sensor status register is 0b." set_trips() starts a conversion at the end of the function and returns without waiting for it to finish. A get_temp() call arriving right after that starts a conversion while the CONV bit may still be set, violating the requirement above. Fix this by: - polling for CONV == 0 in get_temp() before starting a conversion - not starting a conversion at the end of set_trips() anymore The conversion started at the end of set_trips() was supposed to check whether the thresholds have been passed, since the hw cannot raise interrupts on its own, but only when the temperature is read. However, the thermal core reads the temperature and computes the trip window from it just before calling into set_trips(), so reading the temperature again straight away is useless. Fixes: dc67521c20b7 ("thermal/drivers/renesas/rzg3e: Fix add thermal driver for the Renesas RZ/G3E SoC") Signed-off-by: Ovidiu Panait Signed-off-by: Daniel Lezcano Link: https://patch.msgid.link/20260916120003.87018-4-ovidiu.panait.rb@renesas.com --- drivers/thermal/renesas/rzg3e_thermal.c | 13 +++++++++++-- 1 file changed, 11 insertions(+), 2 deletions(-) diff --git a/drivers/thermal/renesas/rzg3e_thermal.c b/drivers/thermal/renesas/rzg3e_thermal.c index 45f67b2e1131..58fdcc66456a 100644 --- a/drivers/thermal/renesas/rzg3e_thermal.c +++ b/drivers/thermal/renesas/rzg3e_thermal.c @@ -225,6 +225,16 @@ static int rzg3e_thermal_get_temp(struct thermal_zone_device *tz, int *temp) guard(mutex)(&priv->lock); + /* Make sure a previous conversion is not in progress */ + ret = readl_poll_timeout(priv->base + TSU_SSR, status, + !(status & TSU_SSR_CONV), + TSU_POLL_DELAY_US, + USEC_PER_MSEC); + if (ret) { + dev_err(priv->dev, "Timeout waiting for conversion\n"); + goto out; + } + /* Clear any previous conversion status */ writel(TSU_SICR_ADCLR, priv->base + TSU_SICR); @@ -304,9 +314,8 @@ static int rzg3e_thermal_set_trips(struct thermal_zone_device *tz, /* Enable comparison with "out of range" mode (CMPCOND=0) */ writel(TSU_CMSR_CMPEN, priv->base + TSU_CMSR); - /* Unmask compare IRQ and start a conversion to evaluate window */ + /* Unmask compare IRQ */ writel(TSU_SIER_CMPIE, priv->base + TSU_SIER); - writel(TSU_STRGR_ADST, priv->base + TSU_STRGR); pm_runtime_mark_last_busy(priv->dev); pm_runtime_put_autosuspend(priv->dev);