From a1191a77351e25ddf091bb1a231cae12ee598b5d Mon Sep 17 00:00:00 2001 From: Julien Panis Date: Thu, 2 May 2024 15:46:03 +0200 Subject: [PATCH 1/4] thermal/drivers/mediatek/lvts_thermal: Check NULL ptr on lvts_data Verify that lvts_data is not NULL before using it. Signed-off-by: Julien Panis Signed-off-by: Daniel Lezcano Link: https://lore.kernel.org/r/20240502-mtk-thermal-lvts-data-v1-1-65f1b0bfad37@baylibre.com --- drivers/thermal/mediatek/lvts_thermal.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/drivers/thermal/mediatek/lvts_thermal.c b/drivers/thermal/mediatek/lvts_thermal.c index 86b2f44355ac..20a64b68f9c0 100644 --- a/drivers/thermal/mediatek/lvts_thermal.c +++ b/drivers/thermal/mediatek/lvts_thermal.c @@ -1271,6 +1271,8 @@ static int lvts_probe(struct platform_device *pdev) return -ENOMEM; lvts_data = of_device_get_match_data(dev); + if (!lvts_data) + return -ENODEV; lvts_td->clk = devm_clk_get_enabled(dev, NULL); if (IS_ERR(lvts_td->clk)) From e2d2266a2ac1da67a74c855c24ed3acb54a1e410 Mon Sep 17 00:00:00 2001 From: Julien Panis Date: Fri, 3 May 2024 17:35:13 +0200 Subject: [PATCH 2/4] thermal/drivers/mediatek/lvts_thermal: Remove unused members from struct lvts_ctrl_data In struct lvts_ctrl_data, num_lvts_sensor and cal_offset[] are not used. Signed-off-by: Julien Panis Reviewed-by: AngeloGioacchino Del Regno Reviewed-by: Nicolas Pitre Signed-off-by: Daniel Lezcano Link: https://lore.kernel.org/r/20240503-mtk-thermal-lvts-ctrl-idx-fix-v1-1-f605c50ca117@baylibre.com --- drivers/thermal/mediatek/lvts_thermal.c | 2 -- 1 file changed, 2 deletions(-) diff --git a/drivers/thermal/mediatek/lvts_thermal.c b/drivers/thermal/mediatek/lvts_thermal.c index 20a64b68f9c0..4fa5e74cbcc8 100644 --- a/drivers/thermal/mediatek/lvts_thermal.c +++ b/drivers/thermal/mediatek/lvts_thermal.c @@ -105,8 +105,6 @@ struct lvts_sensor_data { struct lvts_ctrl_data { struct lvts_sensor_data lvts_sensor[LVTS_SENSOR_MAX]; - int cal_offset[LVTS_SENSOR_MAX]; - int num_lvts_sensor; u8 valid_sensor_mask; int offset; int mode; From b66c079aabdff3954e93fdd7f52bd8f9ad6482c7 Mon Sep 17 00:00:00 2001 From: Julien Panis Date: Fri, 3 May 2024 17:35:14 +0200 Subject: [PATCH 3/4] thermal/drivers/mediatek/lvts_thermal: Fix wrong lvts_ctrl index In 'lvts_should_update_thresh()' and 'lvts_ctrl_start()' functions, the parameter passed to 'lvts_for_each_valid_sensor()' macro is always 'lvts_ctrl->lvts_data->lvts_ctrl'. In other words, the array index 0 is systematically passed as 'struct lvts_ctrl_data' type item, even when another item should be consumed instead. Hence, the 'valid_sensor_mask' value which is selected can be wrong because unrelated to the 'struct lvts_ctrl_data' type item that should be used. Hence, some thermal zone can be registered for a sensor 'i' that does not actually exist. Because of the invalid address used as 'lvts_sensor[i].msr', this situation ends up with a crash in 'lvts_get_temp()' function, where this 'msr' pointer is passed to 'readl_poll_timeout()' function. The following message is output: "Unable to handle kernel NULL pointer dereference at virtual address ", with = 0. This patch fixes the issue. Fixes: 11e6f4c31447 ("thermal/drivers/mediatek/lvts_thermal: Allow early empty sensor slots") Signed-off-by: Julien Panis Reviewed-by: Nicolas Pitre Reviewed-by: AngeloGioacchino Del Regno Signed-off-by: Daniel Lezcano Link: https://lore.kernel.org/r/20240503-mtk-thermal-lvts-ctrl-idx-fix-v1-2-f605c50ca117@baylibre.com --- drivers/thermal/mediatek/lvts_thermal.c | 11 +++++++---- 1 file changed, 7 insertions(+), 4 deletions(-) diff --git a/drivers/thermal/mediatek/lvts_thermal.c b/drivers/thermal/mediatek/lvts_thermal.c index 4fa5e74cbcc8..0bb3a495b56e 100644 --- a/drivers/thermal/mediatek/lvts_thermal.c +++ b/drivers/thermal/mediatek/lvts_thermal.c @@ -116,9 +116,9 @@ struct lvts_ctrl_data { ((s2) ? BIT(2) : 0) | \ ((s3) ? BIT(3) : 0)) -#define lvts_for_each_valid_sensor(i, lvts_ctrl_data) \ +#define lvts_for_each_valid_sensor(i, lvts_ctrl) \ for ((i) = 0; (i) < LVTS_SENSOR_MAX; (i)++) \ - if (!((lvts_ctrl_data)->valid_sensor_mask & BIT(i))) \ + if (!((lvts_ctrl)->valid_sensor_mask & BIT(i))) \ continue; \ else @@ -145,6 +145,7 @@ struct lvts_ctrl { const struct lvts_data *lvts_data; u32 calibration[LVTS_SENSOR_MAX]; u32 hw_tshut_raw_temp; + u8 valid_sensor_mask; int mode; void __iomem *base; int low_thresh; @@ -356,7 +357,7 @@ static bool lvts_should_update_thresh(struct lvts_ctrl *lvts_ctrl, int high) if (high > lvts_ctrl->high_thresh) return true; - lvts_for_each_valid_sensor(i, lvts_ctrl->lvts_data->lvts_ctrl) + lvts_for_each_valid_sensor(i, lvts_ctrl) if (lvts_ctrl->sensors[i].high_thresh == lvts_ctrl->high_thresh && lvts_ctrl->sensors[i].low_thresh == lvts_ctrl->low_thresh) return false; @@ -617,6 +618,8 @@ static int lvts_sensor_init(struct device *dev, struct lvts_ctrl *lvts_ctrl, lvts_sensor[i].high_thresh = INT_MIN; }; + lvts_ctrl->valid_sensor_mask = lvts_ctrl_data->valid_sensor_mask; + return 0; } @@ -1112,7 +1115,7 @@ static int lvts_ctrl_start(struct device *dev, struct lvts_ctrl *lvts_ctrl) u32 *sensor_bitmap = lvts_ctrl->mode == LVTS_MSR_IMMEDIATE_MODE ? sensor_imm_bitmap : sensor_filt_bitmap; - lvts_for_each_valid_sensor(i, lvts_ctrl->lvts_data->lvts_ctrl) { + lvts_for_each_valid_sensor(i, lvts_ctrl) { int dt_id = lvts_sensors[i].dt_id; From 8c69a777e480174b1fdd75dab5ad584454dd6555 Mon Sep 17 00:00:00 2001 From: "Rafael J. Wysocki" Date: Fri, 17 May 2024 11:24:03 +0200 Subject: [PATCH 4/4] thermal: core: Fix the handling of invalid trip points Commit 9ad18043fb35 ("thermal: core: Send trip crossing notifications at init time if needed") overlooked the case when a trip point that has started as invalid is set to a valid temperature later. Namely, the initial threshold value for all trips is zero, so if a previously invalid trip becomes valid and its (new) low temperature is above the zone temperature, a spurious trip crossing notification will occur and it may trigger the WARN_ON() in handle_thermal_trip(). To address this, set the initial threshold for all trips to INT_MAX. There is also the case when a valid writable trip becomes invalid that requires special handling. First, in accordance with the change mentioned above, the trip's threshold needs to be set to INT_MAX to avoid the same issue. Second, if the trip in question is passive and it has been crossed by the thermal zone temperature on the way up, the zone's passive count has been incremented and it is in the passive polling mode, so its passive count needs to be adjusted to allow the passive polling to be turned off eventually. Fixes: 9ad18043fb35 ("thermal: core: Send trip crossing notifications at init time if needed") Fixes: 042a3d80f118 ("thermal: core: Move passive polling management to the core") Reported-by: Zhang Rui Signed-off-by: Rafael J. Wysocki Tested-by: Wendy Wang --- drivers/thermal/thermal_core.c | 9 ++++++++- drivers/thermal/thermal_trip.c | 18 ++++++++++++++++++ 2 files changed, 26 insertions(+), 1 deletion(-) diff --git a/drivers/thermal/thermal_core.c b/drivers/thermal/thermal_core.c index 11750a145d74..54cce4e523bc 100644 --- a/drivers/thermal/thermal_core.c +++ b/drivers/thermal/thermal_core.c @@ -1398,8 +1398,15 @@ thermal_zone_device_register_with_trips(const char *type, tz->device.class = thermal_class; tz->devdata = devdata; tz->num_trips = num_trips; - for_each_trip_desc(tz, td) + for_each_trip_desc(tz, td) { td->trip = *trip++; + /* + * Mark all thresholds as invalid to start with even though + * this only matters for the trips that start as invalid and + * become valid later. + */ + td->threshold = INT_MAX; + } thermal_set_delay_jiffies(&tz->passive_delay_jiffies, passive_delay); thermal_set_delay_jiffies(&tz->polling_delay_jiffies, polling_delay); diff --git a/drivers/thermal/thermal_trip.c b/drivers/thermal/thermal_trip.c index 21ece8399997..d6a6acc78ddb 100644 --- a/drivers/thermal/thermal_trip.c +++ b/drivers/thermal/thermal_trip.c @@ -152,6 +152,24 @@ void thermal_zone_set_trip_temp(struct thermal_zone_device *tz, if (trip->temperature == temp) return; + if (temp == THERMAL_TEMP_INVALID) { + struct thermal_trip_desc *td = trip_to_trip_desc(trip); + + if (trip->type == THERMAL_TRIP_PASSIVE && + tz->temperature >= td->threshold) { + /* + * The trip has been crossed, so the thermal zone's + * passive count needs to be adjusted. + */ + tz->passive--; + WARN_ON_ONCE(tz->passive < 0); + } + /* + * Invalidate the threshold to avoid triggering a spurious + * trip crossing notification when the trip becomes valid. + */ + td->threshold = INT_MAX; + } trip->temperature = temp; thermal_notify_tz_trip_change(tz, trip); }