lists.openwall.net   lists  /  announce  owl-users  owl-dev  john-users  john-dev  passwdqc-users  yescrypt  popa3d-users  /  oss-security  kernel-hardening  musl  sabotage  tlsify  passwords  /  crypt-dev  xvendor  /  Bugtraq  Full-Disclosure  linux-kernel  linux-netdev  linux-ext4  linux-hardening  linux-cve-announce  PHC 
Open Source and information security mailing list archives
 
Hash Suite for Android: free password hash cracker in your pocket
[<prev] [next>] [thread-next>] [day] [month] [year] [list]
Date:   Mon,  7 Feb 2022 17:18:30 +0100
From:   Nicolas Cavallari <nicolas.cavallari@...en-communications.fr>
To:     "Rafael J. Wysocki" <rafael@...nel.org>,
        Daniel Lezcano <daniel.lezcano@...aro.org>,
        Shawn Guo <shawnguo@...nel.org>,
        Sascha Hauer <s.hauer@...gutronix.de>
Cc:     Amit Kucheria <amitk@...nel.org>, Zhang Rui <rui.zhang@...el.com>,
        Pengutronix Kernel Team <kernel@...gutronix.de>,
        Fabio Estevam <festevam@...il.com>,
        NXP Linux Team <linux-imx@....com>,
        Andrzej Pietrasiewicz <andrzej.p@...labora.com>,
        linux-pm@...r.kernel.org, linux-kernel@...r.kernel.org
Subject: [PATCH] imx_thermal: Fix temperature retrieval after overheat

When the CPU temperature is above the passive trip point, reading the
temperature would fail forever with EAGAIN.  Fortunately, the thermal
core would continue to assume that the system is overheating, so would
put all passive cooling devices to the max.  Unfortunately, it does
this forever, even if the temperature returns to normal.

This can be easily tested by setting a very low trip point and crossing
it with while(1) loops.

The cause is commit d92ed2c9d3ff ("thermal: imx: Use driver's local data
to decide whether to run a measurement"), which replaced a check for
thermal_zone_device_is_enabled() by a check for irq_enabled, which
tests if the passive trip interrupt is enabled.

Normally, when the thermal zone is enabled, the temperature sensors
are always enabled and the interrupt is used to detect overheating.
When the interrupt fires, it must be disabled.
In that case, the commit causes the measurements to be done
manually (enable sensor, do measurement, disable sensor).
If the thermal core successfully cools down the system below the trip
point (which it typically does quickly), the irq is enabled again but
the sensor is not enabled.

To fix this without using thermal_zone_device_is_enabled(), use a
separate variable to record if the thermal zone is enabled.

Fixes: d92ed2c9d3ff ("thermal: imx: Use driver's local data to decide
whether to run a measurement")

Signed-off-by: Nicolas Cavallari <nicolas.cavallari@...en-communications.fr>
---
 drivers/thermal/imx_thermal.c | 10 ++++++----
 1 file changed, 6 insertions(+), 4 deletions(-)

diff --git a/drivers/thermal/imx_thermal.c b/drivers/thermal/imx_thermal.c
index 2c7473d86a59..5a6ad5bae238 100644
--- a/drivers/thermal/imx_thermal.c
+++ b/drivers/thermal/imx_thermal.c
@@ -205,6 +205,7 @@ struct imx_thermal_data {
 	int alarm_temp;
 	int last_temp;
 	bool irq_enabled;
+	bool tz_enabled;
 	int irq;
 	struct clk *thermal_clk;
 	const struct thermal_soc_data *socdata;
@@ -252,11 +253,10 @@ static int imx_get_temp(struct thermal_zone_device *tz, int *temp)
 	const struct thermal_soc_data *soc_data = data->socdata;
 	struct regmap *map = data->tempmon;
 	unsigned int n_meas;
-	bool wait, run_measurement;
+	bool wait;
 	u32 val;
 
-	run_measurement = !data->irq_enabled;
-	if (!run_measurement) {
+	if (data->tz_enabled) {
 		/* Check if a measurement is currently in progress */
 		regmap_read(map, soc_data->temp_data, &val);
 		wait = !(val & soc_data->temp_valid_mask);
@@ -283,7 +283,7 @@ static int imx_get_temp(struct thermal_zone_device *tz, int *temp)
 
 	regmap_read(map, soc_data->temp_data, &val);
 
-	if (run_measurement) {
+	if (!data->tz_enabled) {
 		regmap_write(map, soc_data->sensor_ctrl + REG_CLR,
 			     soc_data->measure_temp_mask);
 		regmap_write(map, soc_data->sensor_ctrl + REG_SET,
@@ -339,6 +339,7 @@ static int imx_change_mode(struct thermal_zone_device *tz,
 	const struct thermal_soc_data *soc_data = data->socdata;
 
 	if (mode == THERMAL_DEVICE_ENABLED) {
+		data->tz_enabled = true;
 		regmap_write(map, soc_data->sensor_ctrl + REG_CLR,
 			     soc_data->power_down_mask);
 		regmap_write(map, soc_data->sensor_ctrl + REG_SET,
@@ -349,6 +350,7 @@ static int imx_change_mode(struct thermal_zone_device *tz,
 			enable_irq(data->irq);
 		}
 	} else {
+		data->tz_enabled = false;
 		regmap_write(map, soc_data->sensor_ctrl + REG_CLR,
 			     soc_data->measure_temp_mask);
 		regmap_write(map, soc_data->sensor_ctrl + REG_SET,
-- 
2.34.1

Powered by blists - more mailing lists

Powered by Openwall GNU/*/Linux Powered by OpenVZ