Linux-PM Archive on lore.kernel.org
 help / color / Atom feed
* [RFC 0/8] Stop monitoring disabled devices
@ 2020-04-07 17:49 Andrzej Pietrasiewicz
  2020-04-07 17:49 ` [RFC 1/8] thermal: int3400_thermal: Statically initialize .get_mode()/.set_mode() ops Andrzej Pietrasiewicz
                   ` (8 more replies)
  0 siblings, 9 replies; 63+ messages in thread
From: Andrzej Pietrasiewicz @ 2020-04-07 17:49 UTC (permalink / raw)
  To: linux-pm
  Cc: Zhang Rui, Rafael J . Wysocki, Len Brown, Jiri Pirko,
	Ido Schimmel, David S . Miller, Peter Kaestle, Darren Hart,
	Andy Shevchenko, Support Opensource, Daniel Lezcano,
	Amit Kucheria, Shawn Guo, Sascha Hauer, Pengutronix Kernel Team,
	Fabio Estevam, NXP Linux Team, Allison Randal, Enrico Weigelt,
	Gayatri Kammela, Thomas Gleixner, linux-acpi, netdev,
	platform-driver-x86, linux-arm-kernel, kernel,
	Andrzej Pietrasiewicz

The current kernel behavior is to keep polling the thermal zone devices
regardless of their current mode. This is not desired, as all such "disabled"
devices are meant to be handled by userspace, so polling them makes no sense.

There was an attempt to solve this issue:

https://lkml.org/lkml/2018/2/26/498

and it ultimately has not succeeded:

https://lkml.org/lkml/2018/2/27/910

This is a new attempt addressing all the relevant drivers, and I have
identified them with:

$ git grep "thermal_zone_device_ops" | grep "= {" | cut -f1 -d: | sort | uniq

The idea is to modify thermal_zone_device_update() and monitor_thermal_zone()
in such a way that they stop polling a disabled device. To do decide what to
do they should call ->get_mode() operation of the specialized thermal zone
device in question (e.g. drivers/acpi/thermal.c's). But here comes problem:
sometimes a thermal zone device must be initially disabled and becomes enabled
only after its sensors appear on the system. If such thermal zone's
->get_mode() /* in the context of thermal_zone_device_update() or
monitor_thermal_zone() */ is called _before_ the sensors are available, it will
be reported as "disabled" and consequently polling it will be ceased. This is
a change in behavior from userspace's perspective.

To solve the above described problem I want to introduce the third mode of a
thermal_zone_device: initial. The idea is that when the device is in its
initial mode, then its polling will be handled as it is now. This is a good
thing: should the temperature be just about hitting the critical treshnold
early during the boot process, it might be too late if we wait for the
userspace to run to save the system from overheating. The initial mode should
be reported in sysfs as "enabled" to keep the userspace interface intact.
From the initial mode there will be two possible transitions: to enabled or
disabled mode, but there will be no transition back to initial. If the
transition is from initial to enabled, then keep polling. If the transition is
from initial to disabled, then stop polling. If the transition is from enabled
to disabled, then stop polling. The transition from disabled to enabled must
be handled in a special way: there must be a mandatory call to
monitor_thermal_zone(), otherwise the polling will not start. If this
transition is triggeted from sysfs, then it can be easily handled at the
thermal framework level. However, if drivers call their own ->set_mode()
operation then they must also call "monitor_thermal_zone()" afterwards.
The latter being a sensible thing anyway, so perhaps all/most of the drivers
in question do. The plan for implementation is this:

- ensure ALL users use symbolic enum names (THERMAL_DEVICE_DISABLED,
THERMAL_DEVICE_ENABLED) for thermal device mode rather than the numeric
values of enum thermal_device_mode elements
- add THERMAL_DEVICE_INITIAL to the said enum making its value 0 (so that
kzalloc() results in the initial state)
- modify thermal zone device's mode_show() (thermal framework level) so that
it reports "enabled" for THERMAL_DEVICE_INITIAL
- modify thermal zone device's mode_store() (thermal framework level) so that
it calls monitor_thermal_zone() upon mode change
- modify ALL thermal drivers so that their code is prepared to return
THERMAL_DEVICE_INITIAL before they call thermal_zone_device_register(); when
the invocation of the latter completes then polling is expected to be started
- verify ALL drivers which call their own ->set_mode() to ensure they do call
monitor_thermal_zone() afterwards
- modify thermal_zone_device_update() and monitor_thermal_zone() so that they
cancel polling for disabled thermal zone devices (but not for those in
THERMAL_DEVICE_INITIAL mode)

This RFC series does all the above steps in more or less that order.

I kindly ask for comments/suggestions/improvements.

Rebased onto v5.6.

Andrzej Pietrasiewicz (8):
  thermal: int3400_thermal: Statically initialize
    .get_mode()/.set_mode() ops
  thermal: Properly handle mode values in .set_mode()
  thermal: Store thermal mode in a dedicated enum
  thermal: core: Introduce THERMAL_DEVICE_INITIAL
  thermal: core: Monitor thermal zone after mode change
  thermal: Set initial state to THERMAL_DEVICE_INITIAL
  thermal: of: Monitor thermal zone after enabling it
  thermal: Stop polling DISABLED thermal devices

 drivers/acpi/thermal.c                        | 28 +++++-----
 .../ethernet/mellanox/mlxsw/core_thermal.c    | 11 +++-
 drivers/platform/x86/acerhdf.c                | 17 ++++--
 drivers/thermal/da9062-thermal.c              |  2 +-
 drivers/thermal/imx_thermal.c                 |  5 +-
 .../intel/int340x_thermal/int3400_thermal.c   | 24 ++++-----
 .../thermal/intel/intel_quark_dts_thermal.c   |  6 ++-
 drivers/thermal/of-thermal.c                  |  9 +++-
 drivers/thermal/thermal_core.c                | 52 ++++++++++++++++++-
 drivers/thermal/thermal_core.h                |  2 +
 drivers/thermal/thermal_sysfs.c               | 12 +++--
 include/linux/thermal.h                       |  3 +-
 12 files changed, 123 insertions(+), 48 deletions(-)

-- 
2.17.1


^ permalink raw reply	[flat|nested] 63+ messages in thread

* [RFC 1/8] thermal: int3400_thermal: Statically initialize .get_mode()/.set_mode() ops
  2020-04-07 17:49 [RFC 0/8] Stop monitoring disabled devices Andrzej Pietrasiewicz
@ 2020-04-07 17:49 ` Andrzej Pietrasiewicz
       [not found]   ` <CGME20200415091204eucas1p1983548c2db52d8d0c2a5367034ec80dd@eucas1p1.samsung.com>
  2020-04-07 17:49 ` [RFC 2/8] thermal: Properly handle mode values in .set_mode() Andrzej Pietrasiewicz
                   ` (7 subsequent siblings)
  8 siblings, 1 reply; 63+ messages in thread
From: Andrzej Pietrasiewicz @ 2020-04-07 17:49 UTC (permalink / raw)
  To: linux-pm
  Cc: Zhang Rui, Rafael J . Wysocki, Len Brown, Jiri Pirko,
	Ido Schimmel, David S . Miller, Peter Kaestle, Darren Hart,
	Andy Shevchenko, Support Opensource, Daniel Lezcano,
	Amit Kucheria, Shawn Guo, Sascha Hauer, Pengutronix Kernel Team,
	Fabio Estevam, NXP Linux Team, Allison Randal, Enrico Weigelt,
	Gayatri Kammela, Thomas Gleixner, linux-acpi, netdev,
	platform-driver-x86, linux-arm-kernel, kernel,
	Andrzej Pietrasiewicz

int3400_thermal_ops is used inside int3400_thermal_probe() only after
the assignments, which can just as well be made statically at struct's
initizer.

Signed-off-by: Andrzej Pietrasiewicz <andrzej.p@collabora.com>
---
 drivers/thermal/intel/int340x_thermal/int3400_thermal.c | 5 ++---
 1 file changed, 2 insertions(+), 3 deletions(-)

diff --git a/drivers/thermal/intel/int340x_thermal/int3400_thermal.c b/drivers/thermal/intel/int340x_thermal/int3400_thermal.c
index efae0c02d898..634b943e9e3d 100644
--- a/drivers/thermal/intel/int340x_thermal/int3400_thermal.c
+++ b/drivers/thermal/intel/int340x_thermal/int3400_thermal.c
@@ -271,6 +271,8 @@ static int int3400_thermal_set_mode(struct thermal_zone_device *thermal,
 
 static struct thermal_zone_device_ops int3400_thermal_ops = {
 	.get_temp = int3400_thermal_get_temp,
+	.get_mode = int3400_thermal_get_mode,
+	.set_mode = int3400_thermal_set_mode,
 };
 
 static struct thermal_zone_params int3400_thermal_params = {
@@ -309,9 +311,6 @@ static int int3400_thermal_probe(struct platform_device *pdev)
 
 	platform_set_drvdata(pdev, priv);
 
-	int3400_thermal_ops.get_mode = int3400_thermal_get_mode;
-	int3400_thermal_ops.set_mode = int3400_thermal_set_mode;
-
 	priv->thermal = thermal_zone_device_register("INT3400 Thermal", 0, 0,
 						priv, &int3400_thermal_ops,
 						&int3400_thermal_params, 0, 0);
-- 
2.17.1


^ permalink raw reply	[flat|nested] 63+ messages in thread

* [RFC 2/8] thermal: Properly handle mode values in .set_mode()
  2020-04-07 17:49 [RFC 0/8] Stop monitoring disabled devices Andrzej Pietrasiewicz
  2020-04-07 17:49 ` [RFC 1/8] thermal: int3400_thermal: Statically initialize .get_mode()/.set_mode() ops Andrzej Pietrasiewicz
@ 2020-04-07 17:49 ` Andrzej Pietrasiewicz
       [not found]   ` <CGME20200415100543eucas1p24e24293da39844ca8791db86af5365a7@eucas1p2.samsung.com>
  2020-04-07 17:49 ` [RFC 3/8] thermal: Store thermal mode in a dedicated enum Andrzej Pietrasiewicz
                   ` (6 subsequent siblings)
  8 siblings, 1 reply; 63+ messages in thread
From: Andrzej Pietrasiewicz @ 2020-04-07 17:49 UTC (permalink / raw)
  To: linux-pm
  Cc: Zhang Rui, Rafael J . Wysocki, Len Brown, Jiri Pirko,
	Ido Schimmel, David S . Miller, Peter Kaestle, Darren Hart,
	Andy Shevchenko, Support Opensource, Daniel Lezcano,
	Amit Kucheria, Shawn Guo, Sascha Hauer, Pengutronix Kernel Team,
	Fabio Estevam, NXP Linux Team, Allison Randal, Enrico Weigelt,
	Gayatri Kammela, Thomas Gleixner, linux-acpi, netdev,
	platform-driver-x86, linux-arm-kernel, kernel,
	Andrzej Pietrasiewicz

Allow only THERMAL_DEVICE_ENABLED and THERMAL_DEVICE_DISABLED as valid
states to transition to.

Signed-off-by: Andrzej Pietrasiewicz <andrzej.p@collabora.com>
---
 drivers/net/ethernet/mellanox/mlxsw/core_thermal.c | 8 ++++++--
 drivers/platform/x86/acerhdf.c                     | 4 ++++
 drivers/thermal/imx_thermal.c                      | 4 +++-
 drivers/thermal/intel/intel_quark_dts_thermal.c    | 5 ++++-
 drivers/thermal/of-thermal.c                       | 4 +++-
 5 files changed, 20 insertions(+), 5 deletions(-)

diff --git a/drivers/net/ethernet/mellanox/mlxsw/core_thermal.c b/drivers/net/ethernet/mellanox/mlxsw/core_thermal.c
index ce0a6837daa3..cd435ca7adbe 100644
--- a/drivers/net/ethernet/mellanox/mlxsw/core_thermal.c
+++ b/drivers/net/ethernet/mellanox/mlxsw/core_thermal.c
@@ -296,8 +296,10 @@ static int mlxsw_thermal_set_mode(struct thermal_zone_device *tzdev,
 
 	if (mode == THERMAL_DEVICE_ENABLED)
 		tzdev->polling_delay = thermal->polling_delay;
-	else
+	else if (mode == THERMAL_DEVICE_DISABLED)
 		tzdev->polling_delay = 0;
+	else
+		return -EINVAL;
 
 	mutex_unlock(&tzdev->lock);
 
@@ -486,8 +488,10 @@ static int mlxsw_thermal_module_mode_set(struct thermal_zone_device *tzdev,
 
 	if (mode == THERMAL_DEVICE_ENABLED)
 		tzdev->polling_delay = thermal->polling_delay;
-	else
+	else if (mode == THERMAL_DEVICE_DISABLED)
 		tzdev->polling_delay = 0;
+	else
+		return -EINVAL;
 
 	mutex_unlock(&tzdev->lock);
 
diff --git a/drivers/platform/x86/acerhdf.c b/drivers/platform/x86/acerhdf.c
index 8cc86f4e3ac1..d5188c1d688b 100644
--- a/drivers/platform/x86/acerhdf.c
+++ b/drivers/platform/x86/acerhdf.c
@@ -431,6 +431,10 @@ static int acerhdf_get_mode(struct thermal_zone_device *thermal,
 static int acerhdf_set_mode(struct thermal_zone_device *thermal,
 			    enum thermal_device_mode mode)
 {
+	if (mode != THERMAL_DEVICE_DISABLED &&
+	    mode != THERMAL_DEVICE_ENABLED)
+		return -EINVAL;
+
 	if (mode == THERMAL_DEVICE_DISABLED && kernelmode)
 		acerhdf_revert_to_bios_mode();
 	else if (mode == THERMAL_DEVICE_ENABLED && !kernelmode)
diff --git a/drivers/thermal/imx_thermal.c b/drivers/thermal/imx_thermal.c
index bb6754a5342c..014512581918 100644
--- a/drivers/thermal/imx_thermal.c
+++ b/drivers/thermal/imx_thermal.c
@@ -368,7 +368,7 @@ static int imx_set_mode(struct thermal_zone_device *tz,
 			data->irq_enabled = true;
 			enable_irq(data->irq);
 		}
-	} else {
+	} else if (mode == THERMAL_DEVICE_DISABLED) {
 		regmap_write(map, soc_data->sensor_ctrl + REG_CLR,
 			     soc_data->measure_temp_mask);
 		regmap_write(map, soc_data->sensor_ctrl + REG_SET,
@@ -381,6 +381,8 @@ static int imx_set_mode(struct thermal_zone_device *tz,
 			disable_irq(data->irq);
 			data->irq_enabled = false;
 		}
+	} else {
+		return -EINVAL;
 	}
 
 	data->mode = mode;
diff --git a/drivers/thermal/intel/intel_quark_dts_thermal.c b/drivers/thermal/intel/intel_quark_dts_thermal.c
index 5d33b350da1c..5f4bcc0e4fd3 100644
--- a/drivers/thermal/intel/intel_quark_dts_thermal.c
+++ b/drivers/thermal/intel/intel_quark_dts_thermal.c
@@ -328,8 +328,11 @@ static int sys_set_mode(struct thermal_zone_device *tzd,
 	mutex_lock(&dts_update_mutex);
 	if (mode == THERMAL_DEVICE_ENABLED)
 		ret = soc_dts_enable(tzd);
-	else
+	else if (mode == THERMAL_DEVICE_DISABLED)
 		ret = soc_dts_disable(tzd);
+	else
+		return -EINVAL;
+
 	mutex_unlock(&dts_update_mutex);
 
 	return ret;
diff --git a/drivers/thermal/of-thermal.c b/drivers/thermal/of-thermal.c
index ef0baa954ff0..b7621dfab17c 100644
--- a/drivers/thermal/of-thermal.c
+++ b/drivers/thermal/of-thermal.c
@@ -289,9 +289,11 @@ static int of_thermal_set_mode(struct thermal_zone_device *tz,
 	if (mode == THERMAL_DEVICE_ENABLED) {
 		tz->polling_delay = data->polling_delay;
 		tz->passive_delay = data->passive_delay;
-	} else {
+	} else if (mode == THERMAL_DEVICE_DISABLED) {
 		tz->polling_delay = 0;
 		tz->passive_delay = 0;
+	} else {
+		return -EINVAL;
 	}
 
 	mutex_unlock(&tz->lock);
-- 
2.17.1


^ permalink raw reply	[flat|nested] 63+ messages in thread

* [RFC 3/8] thermal: Store thermal mode in a dedicated enum
  2020-04-07 17:49 [RFC 0/8] Stop monitoring disabled devices Andrzej Pietrasiewicz
  2020-04-07 17:49 ` [RFC 1/8] thermal: int3400_thermal: Statically initialize .get_mode()/.set_mode() ops Andrzej Pietrasiewicz
  2020-04-07 17:49 ` [RFC 2/8] thermal: Properly handle mode values in .set_mode() Andrzej Pietrasiewicz
@ 2020-04-07 17:49 ` Andrzej Pietrasiewicz
       [not found]   ` <CGME20200415100944eucas1p1dcfeb784e790ca2fc3417fd2797e3f5d@eucas1p1.samsung.com>
  2020-04-07 17:49 ` [RFC 4/8] thermal: core: Introduce THERMAL_DEVICE_INITIAL Andrzej Pietrasiewicz
                   ` (5 subsequent siblings)
  8 siblings, 1 reply; 63+ messages in thread
From: Andrzej Pietrasiewicz @ 2020-04-07 17:49 UTC (permalink / raw)
  To: linux-pm
  Cc: Zhang Rui, Rafael J . Wysocki, Len Brown, Jiri Pirko,
	Ido Schimmel, David S . Miller, Peter Kaestle, Darren Hart,
	Andy Shevchenko, Support Opensource, Daniel Lezcano,
	Amit Kucheria, Shawn Guo, Sascha Hauer, Pengutronix Kernel Team,
	Fabio Estevam, NXP Linux Team, Allison Randal, Enrico Weigelt,
	Gayatri Kammela, Thomas Gleixner, linux-acpi, netdev,
	platform-driver-x86, linux-arm-kernel, kernel,
	Andrzej Pietrasiewicz

Prepare for adding THERMAL_DEVICE_INITIAL mode.

Signed-off-by: Andrzej Pietrasiewicz <andrzej.p@collabora.com>
---
 drivers/acpi/thermal.c                        | 27 +++++++++----------
 drivers/platform/x86/acerhdf.c                | 12 ++++++---
 .../intel/int340x_thermal/int3400_thermal.c   | 18 +++++--------
 3 files changed, 27 insertions(+), 30 deletions(-)

diff --git a/drivers/acpi/thermal.c b/drivers/acpi/thermal.c
index 19067a5e5293..a93b0412dd6b 100644
--- a/drivers/acpi/thermal.c
+++ b/drivers/acpi/thermal.c
@@ -172,7 +172,7 @@ struct acpi_thermal {
 	struct acpi_thermal_trips trips;
 	struct acpi_handle_list devices;
 	struct thermal_zone_device *thermal_zone;
-	int tz_enabled;
+	enum thermal_device_mode mode;
 	int kelvin_offset;	/* in millidegrees */
 	struct work_struct thermal_check_work;
 };
@@ -500,7 +500,7 @@ static void acpi_thermal_check(void *data)
 {
 	struct acpi_thermal *tz = data;
 
-	if (!tz->tz_enabled)
+	if (tz->mode != THERMAL_DEVICE_ENABLED)
 		return;
 
 	thermal_zone_device_update(tz->thermal_zone,
@@ -534,8 +534,7 @@ static int thermal_get_mode(struct thermal_zone_device *thermal,
 	if (!tz)
 		return -EINVAL;
 
-	*mode = tz->tz_enabled ? THERMAL_DEVICE_ENABLED :
-		THERMAL_DEVICE_DISABLED;
+	*mode = tz->mode;
 
 	return 0;
 }
@@ -544,27 +543,25 @@ static int thermal_set_mode(struct thermal_zone_device *thermal,
 				enum thermal_device_mode mode)
 {
 	struct acpi_thermal *tz = thermal->devdata;
-	int enable;
 
 	if (!tz)
 		return -EINVAL;
 
+	if (mode != THERMAL_DEVICE_DISABLED &&
+	    mode != THERMAL_DEVICE_ENABLED)
+		return -EINVAL;
 	/*
 	 * enable/disable thermal management from ACPI thermal driver
 	 */
-	if (mode == THERMAL_DEVICE_ENABLED)
-		enable = 1;
-	else if (mode == THERMAL_DEVICE_DISABLED) {
-		enable = 0;
+	if (mode == THERMAL_DEVICE_DISABLED)
 		pr_warn("thermal zone will be disabled\n");
-	} else
-		return -EINVAL;
 
-	if (enable != tz->tz_enabled) {
-		tz->tz_enabled = enable;
+	if (mode != tz->mode) {
+		tz->mode = mode;
 		ACPI_DEBUG_PRINT((ACPI_DB_INFO,
 			"%s kernel ACPI thermal control\n",
-			tz->tz_enabled ? "Enable" : "Disable"));
+			tz->mode == THERMAL_DEVICE_ENABLED ?
+			"Enable" : "Disable"));
 		acpi_thermal_check(tz);
 	}
 	return 0;
@@ -913,7 +910,7 @@ static int acpi_thermal_register_thermal_zone(struct acpi_thermal *tz)
 	if (ACPI_FAILURE(status))
 		return -ENODEV;
 
-	tz->tz_enabled = 1;
+	tz->mode = THERMAL_DEVICE_ENABLED;
 
 	dev_info(&tz->device->dev, "registered as thermal_zone%d\n",
 		 tz->thermal_zone->id);
diff --git a/drivers/platform/x86/acerhdf.c b/drivers/platform/x86/acerhdf.c
index d5188c1d688b..87e357017d4a 100644
--- a/drivers/platform/x86/acerhdf.c
+++ b/drivers/platform/x86/acerhdf.c
@@ -65,8 +65,10 @@
 
 #ifdef START_IN_KERNEL_MODE
 static int kernelmode = 1;
+static enum thermal_device_mode thermal_mode = THERMAL_DEVICE_ENABLED;
 #else
 static int kernelmode;
+static enum thermal_device_mode thermal_mode = THERMAL_DEVICE_DISABLED;
 #endif
 
 static unsigned int interval = 10;
@@ -416,8 +418,7 @@ static int acerhdf_get_mode(struct thermal_zone_device *thermal,
 	if (verbose)
 		pr_notice("kernel mode fan control %d\n", kernelmode);
 
-	*mode = (kernelmode) ? THERMAL_DEVICE_ENABLED
-			     : THERMAL_DEVICE_DISABLED;
+	*mode = thermal_mode;
 
 	return 0;
 }
@@ -435,10 +436,13 @@ static int acerhdf_set_mode(struct thermal_zone_device *thermal,
 	    mode != THERMAL_DEVICE_ENABLED)
 		return -EINVAL;
 
-	if (mode == THERMAL_DEVICE_DISABLED && kernelmode)
+	if (mode == THERMAL_DEVICE_DISABLED && kernelmode) {
 		acerhdf_revert_to_bios_mode();
-	else if (mode == THERMAL_DEVICE_ENABLED && !kernelmode)
+		thermal_mode = THERMAL_DEVICE_DISABLED;
+	} else if (mode == THERMAL_DEVICE_ENABLED && !kernelmode) {
 		acerhdf_enable_kernelmode();
+		thermal_mode = THERMAL_DEVICE_ENABLED;
+	}
 
 	return 0;
 }
diff --git a/drivers/thermal/intel/int340x_thermal/int3400_thermal.c b/drivers/thermal/intel/int340x_thermal/int3400_thermal.c
index 634b943e9e3d..fcbd1b14fa74 100644
--- a/drivers/thermal/intel/int340x_thermal/int3400_thermal.c
+++ b/drivers/thermal/intel/int340x_thermal/int3400_thermal.c
@@ -44,7 +44,7 @@ static char *int3400_thermal_uuids[INT3400_THERMAL_MAXIMUM_UUID] = {
 struct int3400_thermal_priv {
 	struct acpi_device *adev;
 	struct thermal_zone_device *thermal;
-	int mode;
+	enum thermal_device_mode mode;
 	int art_count;
 	struct art *arts;
 	int trt_count;
@@ -247,24 +247,20 @@ static int int3400_thermal_set_mode(struct thermal_zone_device *thermal,
 				enum thermal_device_mode mode)
 {
 	struct int3400_thermal_priv *priv = thermal->devdata;
-	bool enable;
 	int result = 0;
 
 	if (!priv)
 		return -EINVAL;
 
-	if (mode == THERMAL_DEVICE_ENABLED)
-		enable = true;
-	else if (mode == THERMAL_DEVICE_DISABLED)
-		enable = false;
-	else
+	if (mode != THERMAL_DEVICE_ENABLED &&
+	    mode != THERMAL_DEVICE_DISABLED)
 		return -EINVAL;
 
-	if (enable != priv->mode) {
-		priv->mode = enable;
+	if (mode != priv->mode) {
+		priv->mode = mode;
 		result = int3400_thermal_run_osc(priv->adev->handle,
-						 priv->current_uuid_index,
-						 enable);
+						priv->current_uuid_index,
+						mode == THERMAL_DEVICE_ENABLED);
 	}
 	return result;
 }
-- 
2.17.1


^ permalink raw reply	[flat|nested] 63+ messages in thread

* [RFC 4/8] thermal: core: Introduce THERMAL_DEVICE_INITIAL
  2020-04-07 17:49 [RFC 0/8] Stop monitoring disabled devices Andrzej Pietrasiewicz
                   ` (2 preceding siblings ...)
  2020-04-07 17:49 ` [RFC 3/8] thermal: Store thermal mode in a dedicated enum Andrzej Pietrasiewicz
@ 2020-04-07 17:49 ` Andrzej Pietrasiewicz
  2020-04-07 17:49 ` [RFC 5/8] thermal: core: Monitor thermal zone after mode change Andrzej Pietrasiewicz
                   ` (4 subsequent siblings)
  8 siblings, 0 replies; 63+ messages in thread
From: Andrzej Pietrasiewicz @ 2020-04-07 17:49 UTC (permalink / raw)
  To: linux-pm
  Cc: Zhang Rui, Rafael J . Wysocki, Len Brown, Jiri Pirko,
	Ido Schimmel, David S . Miller, Peter Kaestle, Darren Hart,
	Andy Shevchenko, Support Opensource, Daniel Lezcano,
	Amit Kucheria, Shawn Guo, Sascha Hauer, Pengutronix Kernel Team,
	Fabio Estevam, NXP Linux Team, Allison Randal, Enrico Weigelt,
	Gayatri Kammela, Thomas Gleixner, linux-acpi, netdev,
	platform-driver-x86, linux-arm-kernel, kernel,
	Andrzej Pietrasiewicz

Add a new mode: THERMAL_DEVICE_INITIAL. It is dedicated to handle devices
which must be initially DISABLED, but which are polled at startup
nonetheless. THERMAL_DEVICE_INITIAL shall be reported as "enabled" in
sysfs to keep the userspace interface intact.

Signed-off-by: Andrzej Pietrasiewicz <andrzej.p@collabora.com>
---
 drivers/thermal/thermal_sysfs.c | 4 ++--
 include/linux/thermal.h         | 3 ++-
 2 files changed, 4 insertions(+), 3 deletions(-)

diff --git a/drivers/thermal/thermal_sysfs.c b/drivers/thermal/thermal_sysfs.c
index aa99edb4dff7..6bfef21abce4 100644
--- a/drivers/thermal/thermal_sysfs.c
+++ b/drivers/thermal/thermal_sysfs.c
@@ -59,8 +59,8 @@ mode_show(struct device *dev, struct device_attribute *attr, char *buf)
 	if (result)
 		return result;
 
-	return sprintf(buf, "%s\n", mode == THERMAL_DEVICE_ENABLED ? "enabled"
-		       : "disabled");
+	return sprintf(buf, "%s\n", mode == THERMAL_DEVICE_DISABLED ? "disabled"
+		       : "enabled");
 }
 
 static ssize_t
diff --git a/include/linux/thermal.h b/include/linux/thermal.h
index 126913c6a53b..1bc6b7998093 100644
--- a/include/linux/thermal.h
+++ b/include/linux/thermal.h
@@ -48,8 +48,9 @@ struct thermal_cooling_device;
 struct thermal_instance;
 
 enum thermal_device_mode {
-	THERMAL_DEVICE_DISABLED = 0,
+	THERMAL_DEVICE_INITIAL = 0,
 	THERMAL_DEVICE_ENABLED,
+	THERMAL_DEVICE_DISABLED,
 };
 
 enum thermal_trip_type {
-- 
2.17.1


^ permalink raw reply	[flat|nested] 63+ messages in thread

* [RFC 5/8] thermal: core: Monitor thermal zone after mode change
  2020-04-07 17:49 [RFC 0/8] Stop monitoring disabled devices Andrzej Pietrasiewicz
                   ` (3 preceding siblings ...)
  2020-04-07 17:49 ` [RFC 4/8] thermal: core: Introduce THERMAL_DEVICE_INITIAL Andrzej Pietrasiewicz
@ 2020-04-07 17:49 ` Andrzej Pietrasiewicz
  2020-04-07 17:49 ` [RFC 6/8] thermal: Set initial state to THERMAL_DEVICE_INITIAL Andrzej Pietrasiewicz
                   ` (3 subsequent siblings)
  8 siblings, 0 replies; 63+ messages in thread
From: Andrzej Pietrasiewicz @ 2020-04-07 17:49 UTC (permalink / raw)
  To: linux-pm
  Cc: Zhang Rui, Rafael J . Wysocki, Len Brown, Jiri Pirko,
	Ido Schimmel, David S . Miller, Peter Kaestle, Darren Hart,
	Andy Shevchenko, Support Opensource, Daniel Lezcano,
	Amit Kucheria, Shawn Guo, Sascha Hauer, Pengutronix Kernel Team,
	Fabio Estevam, NXP Linux Team, Allison Randal, Enrico Weigelt,
	Gayatri Kammela, Thomas Gleixner, linux-acpi, netdev,
	platform-driver-x86, linux-arm-kernel, kernel,
	Andrzej Pietrasiewicz

Mode changing might imply a need to stop/start polling the device.
monitor_thermal_zone() when mode changes or if previous mode is unknown.

Signed-off-by: Andrzej Pietrasiewicz <andrzej.p@collabora.com>
---
 drivers/thermal/thermal_core.c  | 26 ++++++++++++++++++++++++++
 drivers/thermal/thermal_core.h  |  2 ++
 drivers/thermal/thermal_sysfs.c |  8 +++++---
 3 files changed, 33 insertions(+), 3 deletions(-)

diff --git a/drivers/thermal/thermal_core.c b/drivers/thermal/thermal_core.c
index 9a321dc548c8..aae2b049d45c 100644
--- a/drivers/thermal/thermal_core.c
+++ b/drivers/thermal/thermal_core.c
@@ -469,6 +469,32 @@ static void thermal_zone_device_reset(struct thermal_zone_device *tz)
 	thermal_zone_device_init(tz);
 }
 
+int thermal_zone_set_mode(struct thermal_zone_device *tz,
+			  enum thermal_device_mode mode)
+{
+	enum thermal_device_mode old_mode;
+	int result;
+
+	if (!tz->ops->set_mode)
+		return -EPERM;
+
+	if (tz->ops->get_mode) {
+		result = tz->ops->get_mode(tz, &old_mode);
+		if (result)
+			return result;
+	}
+
+	result = tz->ops->set_mode(tz, mode);
+	if (result)
+		return result;
+
+	/* old mode unknown or mode changed */
+	if (!tz->ops->get_mode || mode != old_mode)
+		monitor_thermal_zone(tz);
+
+	return 0;
+}
+
 void thermal_zone_device_update(struct thermal_zone_device *tz,
 				enum thermal_notify_event event)
 {
diff --git a/drivers/thermal/thermal_core.h b/drivers/thermal/thermal_core.h
index a9bf00e91d64..1ed0bdb812d8 100644
--- a/drivers/thermal/thermal_core.h
+++ b/drivers/thermal/thermal_core.h
@@ -74,6 +74,8 @@ int thermal_zone_create_device_groups(struct thermal_zone_device *, int);
 void thermal_zone_destroy_device_groups(struct thermal_zone_device *);
 void thermal_cooling_device_setup_sysfs(struct thermal_cooling_device *);
 void thermal_cooling_device_destroy_sysfs(struct thermal_cooling_device *cdev);
+int thermal_zone_set_mode(struct thermal_zone_device *tz,
+			  enum thermal_device_mode mode);
 /* used only at binding time */
 ssize_t trip_point_show(struct device *, struct device_attribute *, char *);
 ssize_t weight_show(struct device *, struct device_attribute *, char *);
diff --git a/drivers/thermal/thermal_sysfs.c b/drivers/thermal/thermal_sysfs.c
index 6bfef21abce4..cc1f808b48b3 100644
--- a/drivers/thermal/thermal_sysfs.c
+++ b/drivers/thermal/thermal_sysfs.c
@@ -68,18 +68,20 @@ mode_store(struct device *dev, struct device_attribute *attr,
 	   const char *buf, size_t count)
 {
 	struct thermal_zone_device *tz = to_thermal_zone(dev);
+	enum thermal_device_mode mode;
 	int result;
 
 	if (!tz->ops->set_mode)
 		return -EPERM;
 
 	if (!strncmp(buf, "enabled", sizeof("enabled") - 1))
-		result = tz->ops->set_mode(tz, THERMAL_DEVICE_ENABLED);
+		mode = THERMAL_DEVICE_ENABLED;
 	else if (!strncmp(buf, "disabled", sizeof("disabled") - 1))
-		result = tz->ops->set_mode(tz, THERMAL_DEVICE_DISABLED);
+		mode = THERMAL_DEVICE_DISABLED;
 	else
-		result = -EINVAL;
+		return -EINVAL;
 
+	result = thermal_zone_set_mode(tz, mode);
 	if (result)
 		return result;
 
-- 
2.17.1


^ permalink raw reply	[flat|nested] 63+ messages in thread

* [RFC 6/8] thermal: Set initial state to THERMAL_DEVICE_INITIAL
  2020-04-07 17:49 [RFC 0/8] Stop monitoring disabled devices Andrzej Pietrasiewicz
                   ` (4 preceding siblings ...)
  2020-04-07 17:49 ` [RFC 5/8] thermal: core: Monitor thermal zone after mode change Andrzej Pietrasiewicz
@ 2020-04-07 17:49 ` Andrzej Pietrasiewicz
  2020-04-07 17:49 ` [RFC 7/8] thermal: of: Monitor thermal zone after enabling it Andrzej Pietrasiewicz
                   ` (2 subsequent siblings)
  8 siblings, 0 replies; 63+ messages in thread
From: Andrzej Pietrasiewicz @ 2020-04-07 17:49 UTC (permalink / raw)
  To: linux-pm
  Cc: Zhang Rui, Rafael J . Wysocki, Len Brown, Jiri Pirko,
	Ido Schimmel, David S . Miller, Peter Kaestle, Darren Hart,
	Andy Shevchenko, Support Opensource, Daniel Lezcano,
	Amit Kucheria, Shawn Guo, Sascha Hauer, Pengutronix Kernel Team,
	Fabio Estevam, NXP Linux Team, Allison Randal, Enrico Weigelt,
	Gayatri Kammela, Thomas Gleixner, linux-acpi, netdev,
	platform-driver-x86, linux-arm-kernel, kernel,
	Andrzej Pietrasiewicz

Now that THERMAL_DEVICE_INITIAL is available use it.

Signed-off-by: Andrzej Pietrasiewicz <andrzej.p@collabora.com>
---
 drivers/acpi/thermal.c                                  | 1 +
 drivers/net/ethernet/mellanox/mlxsw/core_thermal.c      | 3 +++
 drivers/platform/x86/acerhdf.c                          | 1 +
 drivers/thermal/da9062-thermal.c                        | 2 +-
 drivers/thermal/imx_thermal.c                           | 1 +
 drivers/thermal/intel/int340x_thermal/int3400_thermal.c | 1 +
 drivers/thermal/intel/intel_quark_dts_thermal.c         | 1 +
 7 files changed, 9 insertions(+), 1 deletion(-)

diff --git a/drivers/acpi/thermal.c b/drivers/acpi/thermal.c
index a93b0412dd6b..0f352cef4898 100644
--- a/drivers/acpi/thermal.c
+++ b/drivers/acpi/thermal.c
@@ -881,6 +881,7 @@ static int acpi_thermal_register_thermal_zone(struct acpi_thermal *tz)
 	for (i = 0; i < ACPI_THERMAL_MAX_ACTIVE &&
 			tz->trips.active[i].flags.valid; i++, trips++);
 
+	tz->mode = THERMAL_DEVICE_INITIAL;
 	if (tz->trips.passive.flags.valid)
 		tz->thermal_zone =
 			thermal_zone_device_register("acpitz", trips, 0, tz,
diff --git a/drivers/net/ethernet/mellanox/mlxsw/core_thermal.c b/drivers/net/ethernet/mellanox/mlxsw/core_thermal.c
index cd435ca7adbe..a58ab4d18331 100644
--- a/drivers/net/ethernet/mellanox/mlxsw/core_thermal.c
+++ b/drivers/net/ethernet/mellanox/mlxsw/core_thermal.c
@@ -758,6 +758,7 @@ mlxsw_thermal_module_tz_init(struct mlxsw_thermal_module *module_tz)
 
 	snprintf(tz_name, sizeof(tz_name), "mlxsw-module%d",
 		 module_tz->module + 1);
+	module_tz->mode = THERMAL_DEVICE_INITIAL;
 	module_tz->tzdev = thermal_zone_device_register(tz_name,
 							MLXSW_THERMAL_NUM_TRIPS,
 							MLXSW_THERMAL_TRIP_MASK,
@@ -876,6 +877,7 @@ mlxsw_thermal_gearbox_tz_init(struct mlxsw_thermal_module *gearbox_tz)
 
 	snprintf(tz_name, sizeof(tz_name), "mlxsw-gearbox%d",
 		 gearbox_tz->module + 1);
+	gearbox_tz->mode = THERMAL_DEVICE_INITIAL;
 	gearbox_tz->tzdev = thermal_zone_device_register(tz_name,
 						MLXSW_THERMAL_NUM_TRIPS,
 						MLXSW_THERMAL_TRIP_MASK,
@@ -1033,6 +1035,7 @@ int mlxsw_thermal_init(struct mlxsw_core *core,
 				 MLXSW_THERMAL_SLOW_POLL_INT :
 				 MLXSW_THERMAL_POLL_INT;
 
+	thermal->mode = THERMAL_DEVICE_INITIAL;
 	thermal->tzdev = thermal_zone_device_register("mlxsw",
 						      MLXSW_THERMAL_NUM_TRIPS,
 						      MLXSW_THERMAL_TRIP_MASK,
diff --git a/drivers/platform/x86/acerhdf.c b/drivers/platform/x86/acerhdf.c
index 87e357017d4a..00751a0f5312 100644
--- a/drivers/platform/x86/acerhdf.c
+++ b/drivers/platform/x86/acerhdf.c
@@ -747,6 +747,7 @@ static int __init acerhdf_register_thermal(void)
 	if (IS_ERR(cl_dev))
 		return -EINVAL;
 
+	thermal_mode = THERMAL_DEVICE_INITIAL;
 	thz_dev = thermal_zone_device_register("acerhdf", 2, 0, NULL,
 					      &acerhdf_dev_ops,
 					      &acerhdf_zone_params, 0,
diff --git a/drivers/thermal/da9062-thermal.c b/drivers/thermal/da9062-thermal.c
index c32709badeda..2f876760d667 100644
--- a/drivers/thermal/da9062-thermal.c
+++ b/drivers/thermal/da9062-thermal.c
@@ -233,7 +233,7 @@ static int da9062_thermal_probe(struct platform_device *pdev)
 
 	thermal->config = match->data;
 	thermal->hw = chip;
-	thermal->mode = THERMAL_DEVICE_ENABLED;
+	thermal->mode = THERMAL_DEVICE_INITIAL;
 	thermal->dev = &pdev->dev;
 
 	INIT_DELAYED_WORK(&thermal->work, da9062_thermal_poll_on);
diff --git a/drivers/thermal/imx_thermal.c b/drivers/thermal/imx_thermal.c
index 014512581918..1e8fd56c2568 100644
--- a/drivers/thermal/imx_thermal.c
+++ b/drivers/thermal/imx_thermal.c
@@ -805,6 +805,7 @@ static int imx_thermal_probe(struct platform_device *pdev)
 		goto legacy_cleanup;
 	}
 
+	data->mode = THERMAL_DEVICE_INITIAL;
 	data->tz = thermal_zone_device_register("imx_thermal_zone",
 						IMX_TRIP_NUM,
 						BIT(IMX_TRIP_PASSIVE), data,
diff --git a/drivers/thermal/intel/int340x_thermal/int3400_thermal.c b/drivers/thermal/intel/int340x_thermal/int3400_thermal.c
index fcbd1b14fa74..9c8caa37ed13 100644
--- a/drivers/thermal/intel/int340x_thermal/int3400_thermal.c
+++ b/drivers/thermal/intel/int340x_thermal/int3400_thermal.c
@@ -307,6 +307,7 @@ static int int3400_thermal_probe(struct platform_device *pdev)
 
 	platform_set_drvdata(pdev, priv);
 
+	priv->mode = THERMAL_DEVICE_INITIAL;
 	priv->thermal = thermal_zone_device_register("INT3400 Thermal", 0, 0,
 						priv, &int3400_thermal_ops,
 						&int3400_thermal_params, 0, 0);
diff --git a/drivers/thermal/intel/intel_quark_dts_thermal.c b/drivers/thermal/intel/intel_quark_dts_thermal.c
index 5f4bcc0e4fd3..af588ff9aa76 100644
--- a/drivers/thermal/intel/intel_quark_dts_thermal.c
+++ b/drivers/thermal/intel/intel_quark_dts_thermal.c
@@ -411,6 +411,7 @@ static struct soc_sensor_entry *alloc_soc_dts(void)
 			goto err_ret;
 	}
 
+	aux_entry->mode = THERMAL_DEVICE_INITIAL;
 	aux_entry->tzone = thermal_zone_device_register("quark_dts",
 			QRK_MAX_DTS_TRIPS,
 			wr_mask,
-- 
2.17.1


^ permalink raw reply	[flat|nested] 63+ messages in thread

* [RFC 7/8] thermal: of: Monitor thermal zone after enabling it
  2020-04-07 17:49 [RFC 0/8] Stop monitoring disabled devices Andrzej Pietrasiewicz
                   ` (5 preceding siblings ...)
  2020-04-07 17:49 ` [RFC 6/8] thermal: Set initial state to THERMAL_DEVICE_INITIAL Andrzej Pietrasiewicz
@ 2020-04-07 17:49 ` Andrzej Pietrasiewicz
       [not found]   ` <CGME20200415101829eucas1p18e21324d3c39926fffc6c8b5dc52f206@eucas1p1.samsung.com>
  2020-04-07 17:49 ` [RFC 8/8] thermal: Stop polling DISABLED thermal devices Andrzej Pietrasiewicz
  2020-04-09 10:29 ` [RFC 0/8] Stop monitoring disabled devices Daniel Lezcano
  8 siblings, 1 reply; 63+ messages in thread
From: Andrzej Pietrasiewicz @ 2020-04-07 17:49 UTC (permalink / raw)
  To: linux-pm
  Cc: Zhang Rui, Rafael J . Wysocki, Len Brown, Jiri Pirko,
	Ido Schimmel, David S . Miller, Peter Kaestle, Darren Hart,
	Andy Shevchenko, Support Opensource, Daniel Lezcano,
	Amit Kucheria, Shawn Guo, Sascha Hauer, Pengutronix Kernel Team,
	Fabio Estevam, NXP Linux Team, Allison Randal, Enrico Weigelt,
	Gayatri Kammela, Thomas Gleixner, linux-acpi, netdev,
	platform-driver-x86, linux-arm-kernel, kernel,
	Andrzej Pietrasiewicz

thermal/of calls its own ->set_mode() method, so monitor thermal zone
afterwards. This is needed for the DISABLED->ENABLED transition.

Signed-off-by: Andrzej Pietrasiewicz <andrzej.p@collabora.com>
---
 drivers/thermal/of-thermal.c | 5 ++++-
 1 file changed, 4 insertions(+), 1 deletion(-)

diff --git a/drivers/thermal/of-thermal.c b/drivers/thermal/of-thermal.c
index b7621dfab17c..cf2c43ebcb78 100644
--- a/drivers/thermal/of-thermal.c
+++ b/drivers/thermal/of-thermal.c
@@ -523,8 +523,11 @@ thermal_zone_of_sensor_register(struct device *dev, int sensor_id, void *data,
 		if (sensor_specs.np == sensor_np && id == sensor_id) {
 			tzd = thermal_zone_of_add_sensor(child, sensor_np,
 							 data, ops);
-			if (!IS_ERR(tzd))
+			if (!IS_ERR(tzd)) {
 				tzd->ops->set_mode(tzd, THERMAL_DEVICE_ENABLED);
+				thermal_zone_device_update(tzd,
+						THERMAL_EVENT_UNSPECIFIED);
+			}
 
 			of_node_put(sensor_specs.np);
 			of_node_put(child);
-- 
2.17.1


^ permalink raw reply	[flat|nested] 63+ messages in thread

* [RFC 8/8] thermal: Stop polling DISABLED thermal devices
  2020-04-07 17:49 [RFC 0/8] Stop monitoring disabled devices Andrzej Pietrasiewicz
                   ` (6 preceding siblings ...)
  2020-04-07 17:49 ` [RFC 7/8] thermal: of: Monitor thermal zone after enabling it Andrzej Pietrasiewicz
@ 2020-04-07 17:49 ` Andrzej Pietrasiewicz
  2020-04-09 10:29 ` [RFC 0/8] Stop monitoring disabled devices Daniel Lezcano
  8 siblings, 0 replies; 63+ messages in thread
From: Andrzej Pietrasiewicz @ 2020-04-07 17:49 UTC (permalink / raw)
  To: linux-pm
  Cc: Zhang Rui, Rafael J . Wysocki, Len Brown, Jiri Pirko,
	Ido Schimmel, David S . Miller, Peter Kaestle, Darren Hart,
	Andy Shevchenko, Support Opensource, Daniel Lezcano,
	Amit Kucheria, Shawn Guo, Sascha Hauer, Pengutronix Kernel Team,
	Fabio Estevam, NXP Linux Team, Allison Randal, Enrico Weigelt,
	Gayatri Kammela, Thomas Gleixner, linux-acpi, netdev,
	platform-driver-x86, linux-arm-kernel, kernel,
	Andrzej Pietrasiewicz

Polling DISABLED devices is not desired, as all such "disabled" devices
are meant to be handled by userspace.

Signed-off-by: Andrzej Pietrasiewicz <andrzej.p@collabora.com>
---
 drivers/thermal/thermal_core.c | 26 ++++++++++++++++++++++++--
 1 file changed, 24 insertions(+), 2 deletions(-)

diff --git a/drivers/thermal/thermal_core.c b/drivers/thermal/thermal_core.c
index aae2b049d45c..f74b7a792be7 100644
--- a/drivers/thermal/thermal_core.c
+++ b/drivers/thermal/thermal_core.c
@@ -305,13 +305,32 @@ static void thermal_zone_device_set_polling(struct thermal_zone_device *tz,
 		cancel_delayed_work(&tz->poll_queue);
 }
 
+static bool should_stop_polling(struct thermal_zone_device *tz)
+{
+	enum thermal_device_mode mode;
+	int result;
+
+	if (!tz->ops->get_mode)
+		return false;
+
+	result = tz->ops->get_mode(tz, &mode);
+	if (result)
+		return false;
+
+	return mode == THERMAL_DEVICE_DISABLED;
+}
+
 static void monitor_thermal_zone(struct thermal_zone_device *tz)
 {
+	bool stop;
+
+	stop = should_stop_polling(tz);
+
 	mutex_lock(&tz->lock);
 
-	if (tz->passive)
+	if (!stop && tz->passive)
 		thermal_zone_device_set_polling(tz, tz->passive_delay);
-	else if (tz->polling_delay)
+	else if (!stop && tz->polling_delay)
 		thermal_zone_device_set_polling(tz, tz->polling_delay);
 	else
 		thermal_zone_device_set_polling(tz, 0);
@@ -500,6 +519,9 @@ void thermal_zone_device_update(struct thermal_zone_device *tz,
 {
 	int count;
 
+	if (should_stop_polling(tz))
+		return;
+
 	if (atomic_read(&in_suspend))
 		return;
 
-- 
2.17.1


^ permalink raw reply	[flat|nested] 63+ messages in thread

* Re: [RFC 0/8] Stop monitoring disabled devices
  2020-04-07 17:49 [RFC 0/8] Stop monitoring disabled devices Andrzej Pietrasiewicz
                   ` (7 preceding siblings ...)
  2020-04-07 17:49 ` [RFC 8/8] thermal: Stop polling DISABLED thermal devices Andrzej Pietrasiewicz
@ 2020-04-09 10:29 ` Daniel Lezcano
  2020-04-09 11:10   ` Andrzej Pietrasiewicz
  2020-04-14 18:00   ` [RFC v2 0/9] " Andrzej Pietrasiewicz
  8 siblings, 2 replies; 63+ messages in thread
From: Daniel Lezcano @ 2020-04-09 10:29 UTC (permalink / raw)
  To: Andrzej Pietrasiewicz, linux-pm
  Cc: Zhang Rui, Rafael J . Wysocki, Len Brown, Jiri Pirko,
	Ido Schimmel, David S . Miller, Peter Kaestle, Darren Hart,
	Andy Shevchenko, Support Opensource, Amit Kucheria, Shawn Guo,
	Sascha Hauer, Pengutronix Kernel Team, Fabio Estevam,
	NXP Linux Team, Allison Randal, Enrico Weigelt, Gayatri Kammela,
	Thomas Gleixner, linux-acpi, netdev, platform-driver-x86,
	linux-arm-kernel, kernel

On 07/04/2020 19:49, Andrzej Pietrasiewicz wrote:
> The current kernel behavior is to keep polling the thermal zone devices
> regardless of their current mode. This is not desired, as all such "disabled"
> devices are meant to be handled by userspace,> so polling them makes no sense.

Thanks for proposing these changes.

I've been (quickly) through the series and the description below. I have
the feeling the series makes more complex while the current code which
would deserve a cleanup.

Why not first:

 - Add a 'mode' field in the thermal zone device
 - Kill all set/get_mode callbacks in the drivers which are duplicated code.
 - Add a function:

 enum thermal_device_mode thermal_zone_get_mode( *tz)
 {
	...
	if (tz->ops->get_mode)
		return tz->ops->get_mode();

	return tz->mode;
 }


 int thermal_zone_set_mode(..*tz, enum thermal_device_mode mode)
 {
	...
	if (tz->ops->set_mode)
		return tz->ops->set_mode(tz, mode);

	tz->mode = mode;

	return 0;
 }

 static inline thermal_zone_enable(... *tz)
 {
	thermal_zone_set_mode(tz, THERMAL_DEVICE_ENABLED);
 }

 static inline thermal_zone_disable(... *tz) {
	thermal_zone_set_mode(tz, THERMAL_DEVICE_DISABLED);
 }

And then when the code is consolidated, use the mode to enable/disable
the polling and continue killing the duplicated code in of-thermal.c and
anywhere else.


> There was an attempt to solve this issue:
> 
> https://lkml.org/lkml/2018/2/26/498
> 
> and it ultimately has not succeeded:
> 
> https://lkml.org/lkml/2018/2/27/910
> 
> This is a new attempt addressing all the relevant drivers, and I have
> identified them with:
> 
> $ git grep "thermal_zone_device_ops" | grep "= {" | cut -f1 -d: | sort | uniq
> 
> The idea is to modify thermal_zone_device_update() and monitor_thermal_zone()
> in such a way that they stop polling a disabled device. To do decide what to
> do they should call ->get_mode() operation of the specialized thermal zone
> device in question (e.g. drivers/acpi/thermal.c's). But here comes problem:
> sometimes a thermal zone device must be initially disabled and becomes enabled
> only after its sensors appear on the system. If such thermal zone's
> ->get_mode() /* in the context of thermal_zone_device_update() or
> monitor_thermal_zone() */ is called _before_ the sensors are available, it will
> be reported as "disabled" and consequently polling it will be ceased. This is
> a change in behavior from userspace's perspective.
> 
> To solve the above described problem I want to introduce the third mode of a
> thermal_zone_device: initial. The idea is that when the device is in its
> initial mode, then its polling will be handled as it is now. This is a good
> thing: should the temperature be just about hitting the critical treshnold
> early during the boot process, it might be too late if we wait for the
> userspace to run to save the system from overheating. The initial mode should
> be reported in sysfs as "enabled" to keep the userspace interface intact.
> From the initial mode there will be two possible transitions: to enabled or
> disabled mode, but there will be no transition back to initial. If the
> transition is from initial to enabled, then keep polling. If the transition is
> from initial to disabled, then stop polling. If the transition is from enabled
> to disabled, then stop polling. The transition from disabled to enabled must
> be handled in a special way: there must be a mandatory call to
> monitor_thermal_zone(), otherwise the polling will not start. If this
> transition is triggeted from sysfs, then it can be easily handled at the
> thermal framework level. However, if drivers call their own ->set_mode()
> operation then they must also call "monitor_thermal_zone()" afterwards.
> The latter being a sensible thing anyway, so perhaps all/most of the drivers
> in question do. The plan for implementation is this:
> 
> - ensure ALL users use symbolic enum names (THERMAL_DEVICE_DISABLED,
> THERMAL_DEVICE_ENABLED) for thermal device mode rather than the numeric
> values of enum thermal_device_mode elements
> - add THERMAL_DEVICE_INITIAL to the said enum making its value 0 (so that
> kzalloc() results in the initial state)
> - modify thermal zone device's mode_show() (thermal framework level) so that
> it reports "enabled" for THERMAL_DEVICE_INITIAL
> - modify thermal zone device's mode_store() (thermal framework level) so that
> it calls monitor_thermal_zone() upon mode change
> - modify ALL thermal drivers so that their code is prepared to return
> THERMAL_DEVICE_INITIAL before they call thermal_zone_device_register(); when
> the invocation of the latter completes then polling is expected to be started
> - verify ALL drivers which call their own ->set_mode() to ensure they do call
> monitor_thermal_zone() afterwards
> - modify thermal_zone_device_update() and monitor_thermal_zone() so that they
> cancel polling for disabled thermal zone devices (but not for those in
> THERMAL_DEVICE_INITIAL mode)
> 
> This RFC series does all the above steps in more or less that order.
> 
> I kindly ask for comments/suggestions/improvements.
> 
> Rebased onto v5.6.
> 
> Andrzej Pietrasiewicz (8):
>   thermal: int3400_thermal: Statically initialize
>     .get_mode()/.set_mode() ops
>   thermal: Properly handle mode values in .set_mode()
>   thermal: Store thermal mode in a dedicated enum
>   thermal: core: Introduce THERMAL_DEVICE_INITIAL
>   thermal: core: Monitor thermal zone after mode change
>   thermal: Set initial state to THERMAL_DEVICE_INITIAL
>   thermal: of: Monitor thermal zone after enabling it
>   thermal: Stop polling DISABLED thermal devices
> 
>  drivers/acpi/thermal.c                        | 28 +++++-----
>  .../ethernet/mellanox/mlxsw/core_thermal.c    | 11 +++-
>  drivers/platform/x86/acerhdf.c                | 17 ++++--
>  drivers/thermal/da9062-thermal.c              |  2 +-
>  drivers/thermal/imx_thermal.c                 |  5 +-
>  .../intel/int340x_thermal/int3400_thermal.c   | 24 ++++-----
>  .../thermal/intel/intel_quark_dts_thermal.c   |  6 ++-
>  drivers/thermal/of-thermal.c                  |  9 +++-
>  drivers/thermal/thermal_core.c                | 52 ++++++++++++++++++-
>  drivers/thermal/thermal_core.h                |  2 +
>  drivers/thermal/thermal_sysfs.c               | 12 +++--
>  include/linux/thermal.h                       |  3 +-
>  12 files changed, 123 insertions(+), 48 deletions(-)
> 


-- 
<http://www.linaro.org/> Linaro.org │ Open source software for ARM SoCs

Follow Linaro:  <http://www.facebook.com/pages/Linaro> Facebook |
<http://twitter.com/#!/linaroorg> Twitter |
<http://www.linaro.org/linaro-blog/> Blog

^ permalink raw reply	[flat|nested] 63+ messages in thread

* Re: [RFC 0/8] Stop monitoring disabled devices
  2020-04-09 10:29 ` [RFC 0/8] Stop monitoring disabled devices Daniel Lezcano
@ 2020-04-09 11:10   ` Andrzej Pietrasiewicz
       [not found]     ` <CGME20200415104010eucas1p101278e53e34a2e56dfc7c82b533a9122@eucas1p1.samsung.com>
  2020-04-14 18:00   ` [RFC v2 0/9] " Andrzej Pietrasiewicz
  1 sibling, 1 reply; 63+ messages in thread
From: Andrzej Pietrasiewicz @ 2020-04-09 11:10 UTC (permalink / raw)
  To: Daniel Lezcano, linux-pm
  Cc: Zhang Rui, Rafael J . Wysocki, Len Brown, Jiri Pirko,
	Ido Schimmel, David S . Miller, Peter Kaestle, Darren Hart,
	Andy Shevchenko, Support Opensource, Amit Kucheria, Shawn Guo,
	Sascha Hauer, Pengutronix Kernel Team, Fabio Estevam,
	NXP Linux Team, Allison Randal, Enrico Weigelt, Gayatri Kammela,
	Thomas Gleixner, linux-acpi, netdev, platform-driver-x86,
	linux-arm-kernel, kernel

Hi Daniel,

W dniu 09.04.2020 o 12:29, Daniel Lezcano pisze:
> On 07/04/2020 19:49, Andrzej Pietrasiewicz wrote:
>> The current kernel behavior is to keep polling the thermal zone devices
>> regardless of their current mode. This is not desired, as all such "disabled"
>> devices are meant to be handled by userspace,> so polling them makes no sense.
> 
> Thanks for proposing these changes.
> 
> I've been (quickly) through the series and the description below. I have
> the feeling the series makes more complex while the current code which
> would deserve a cleanup.
> 
> Why not first:
> 
>   - Add a 'mode' field in the thermal zone device
>   - Kill all set/get_mode callbacks in the drivers which are duplicated code.
>   - Add a function:
> 
>   enum thermal_device_mode thermal_zone_get_mode( *tz)
>   {
> 	...
> 	if (tz->ops->get_mode)
> 		return tz->ops->get_mode();
> 
> 	return tz->mode;
>   }
> 
> 
>   int thermal_zone_set_mode(..*tz, enum thermal_device_mode mode)
>   {
> 	...
> 	if (tz->ops->set_mode)
> 		return tz->ops->set_mode(tz, mode);
> 
> 	tz->mode = mode;
> 
> 	return 0;
>   }
> 
>   static inline thermal_zone_enable(... *tz)
>   {
> 	thermal_zone_set_mode(tz, THERMAL_DEVICE_ENABLED);
>   }
> 
>   static inline thermal_zone_disable(... *tz) {
> 	thermal_zone_set_mode(tz, THERMAL_DEVICE_DISABLED);
>   }
> 
> And then when the code is consolidated, use the mode to enable/disable
> the polling and continue killing the duplicated code in of-thermal.c and
> anywhere else.
> 
> 

Thanks for feedback.

Anyone else?

Andrzej

^ permalink raw reply	[flat|nested] 63+ messages in thread

* [RFC v2 0/9] Stop monitoring disabled devices
  2020-04-09 10:29 ` [RFC 0/8] Stop monitoring disabled devices Daniel Lezcano
  2020-04-09 11:10   ` Andrzej Pietrasiewicz
@ 2020-04-14 18:00   ` Andrzej Pietrasiewicz
  2020-04-14 18:00     ` [RFC v2 1/9] thermal: int3400_thermal: Statically initialize .get_mode()/.set_mode() ops Andrzej Pietrasiewicz
                       ` (9 more replies)
  1 sibling, 10 replies; 63+ messages in thread
From: Andrzej Pietrasiewicz @ 2020-04-14 18:00 UTC (permalink / raw)
  To: linux-pm
  Cc: Zhang Rui, Rafael J . Wysocki, Len Brown, Jiri Pirko,
	Ido Schimmel, David S . Miller, Peter Kaestle, Darren Hart,
	Andy Shevchenko, Support Opensource, Daniel Lezcano,
	Amit Kucheria, Shawn Guo, Sascha Hauer, Pengutronix Kernel Team,
	Fabio Estevam, NXP Linux Team, Allison Randal, Enrico Weigelt,
	Gayatri Kammela, Thomas Gleixner, linux-acpi, netdev,
	platform-driver-x86, linux-arm-kernel, kernel,
	Andrzej Pietrasiewicz

This is the second iteration of this RFC.

The series now focuses on cleaning up the code in the first place.

After the cleanups in patches 1-3 struct thermal_zone_device is extended
so that it contains a "mode" member (patch 4/9).

The next patch (5/9) makes all thermal zone devices use the "mode" member.
This patch makes drivers' ->get_mode() methods redundant, so the next one
(6/9) removes the method altogether.

Patches 7-8/9 ensure that after changing thermal zone device's mode
an attempt will be made to monitor the device.

And finally patch 9/9 prevents DISABLED devices from being monitored.
It also adds THERMAL_DEVICE_INITIAL to accommodate the devices, which
should be monitored but cannot be initially ENABLED.

Andrzej Pietrasiewicz (9):
  thermal: int3400_thermal: Statically initialize
    .get_mode()/.set_mode() ops
  thermal: Eliminate an always-false condition
  thermal: Properly handle mode values in .set_mode()
  thermal: core: Let thermal zone device's mode be stored in its struct
  thermal: Store mode in thermal_zone_device
  thermal: Remove get_mode() method
  thermal: core: Monitor thermal zone after mode change
  thermal: of: Monitor thermal zone after enabling it
  thermal: core: Stop polling DISABLED thermal devices

 drivers/acpi/thermal.c                        | 44 +++++----------
 .../ethernet/mellanox/mlxsw/core_thermal.c    | 43 ++++-----------
 drivers/platform/x86/acerhdf.c                | 28 +++++-----
 drivers/thermal/da9062-thermal.c              | 12 +---
 drivers/thermal/imx_thermal.c                 | 30 ++++------
 .../intel/int340x_thermal/int3400_thermal.c   | 39 +++----------
 .../thermal/intel/intel_quark_dts_thermal.c   | 27 ++++-----
 drivers/thermal/of-thermal.c                  | 28 ++++------
 drivers/thermal/thermal_core.c                | 40 ++++++++++++--
 drivers/thermal/thermal_core.h                |  2 +
 drivers/thermal/thermal_sysfs.c               | 40 ++++----------
 include/linux/thermal.h                       | 55 ++++++++++++++++++-
 12 files changed, 180 insertions(+), 208 deletions(-)

-- 
2.17.1


^ permalink raw reply	[flat|nested] 63+ messages in thread

* [RFC v2 1/9] thermal: int3400_thermal: Statically initialize .get_mode()/.set_mode() ops
  2020-04-14 18:00   ` [RFC v2 0/9] " Andrzej Pietrasiewicz
@ 2020-04-14 18:00     ` Andrzej Pietrasiewicz
  2020-04-15  9:23       ` Daniel Lezcano
  2020-04-14 18:00     ` [RFC v2 2/9] thermal: Eliminate an always-false condition Andrzej Pietrasiewicz
                       ` (8 subsequent siblings)
  9 siblings, 1 reply; 63+ messages in thread
From: Andrzej Pietrasiewicz @ 2020-04-14 18:00 UTC (permalink / raw)
  To: linux-pm
  Cc: Zhang Rui, Rafael J . Wysocki, Len Brown, Jiri Pirko,
	Ido Schimmel, David S . Miller, Peter Kaestle, Darren Hart,
	Andy Shevchenko, Support Opensource, Daniel Lezcano,
	Amit Kucheria, Shawn Guo, Sascha Hauer, Pengutronix Kernel Team,
	Fabio Estevam, NXP Linux Team, Allison Randal, Enrico Weigelt,
	Gayatri Kammela, Thomas Gleixner, linux-acpi, netdev,
	platform-driver-x86, linux-arm-kernel, kernel,
	Andrzej Pietrasiewicz

int3400_thermal_ops is used inside int3400_thermal_probe() only after
the assignments, which can just as well be made statically at struct's
initizer.

Signed-off-by: Andrzej Pietrasiewicz <andrzej.p@collabora.com>
---
 drivers/thermal/intel/int340x_thermal/int3400_thermal.c | 5 ++---
 1 file changed, 2 insertions(+), 3 deletions(-)

diff --git a/drivers/thermal/intel/int340x_thermal/int3400_thermal.c b/drivers/thermal/intel/int340x_thermal/int3400_thermal.c
index ceef89c956bd..e802922a13cf 100644
--- a/drivers/thermal/intel/int340x_thermal/int3400_thermal.c
+++ b/drivers/thermal/intel/int340x_thermal/int3400_thermal.c
@@ -271,6 +271,8 @@ static int int3400_thermal_set_mode(struct thermal_zone_device *thermal,
 
 static struct thermal_zone_device_ops int3400_thermal_ops = {
 	.get_temp = int3400_thermal_get_temp,
+	.get_mode = int3400_thermal_get_mode,
+	.set_mode = int3400_thermal_set_mode,
 };
 
 static struct thermal_zone_params int3400_thermal_params = {
@@ -309,9 +311,6 @@ static int int3400_thermal_probe(struct platform_device *pdev)
 
 	platform_set_drvdata(pdev, priv);
 
-	int3400_thermal_ops.get_mode = int3400_thermal_get_mode;
-	int3400_thermal_ops.set_mode = int3400_thermal_set_mode;
-
 	priv->thermal = thermal_zone_device_register("INT3400 Thermal", 0, 0,
 						priv, &int3400_thermal_ops,
 						&int3400_thermal_params, 0, 0);
-- 
2.17.1


^ permalink raw reply	[flat|nested] 63+ messages in thread

* [RFC v2 2/9] thermal: Eliminate an always-false condition
  2020-04-14 18:00   ` [RFC v2 0/9] " Andrzej Pietrasiewicz
  2020-04-14 18:00     ` [RFC v2 1/9] thermal: int3400_thermal: Statically initialize .get_mode()/.set_mode() ops Andrzej Pietrasiewicz
@ 2020-04-14 18:00     ` Andrzej Pietrasiewicz
  2020-04-14 18:00     ` [RFC v2 3/9] thermal: Properly handle mode values in .set_mode() Andrzej Pietrasiewicz
                       ` (7 subsequent siblings)
  9 siblings, 0 replies; 63+ messages in thread
From: Andrzej Pietrasiewicz @ 2020-04-14 18:00 UTC (permalink / raw)
  To: linux-pm
  Cc: Zhang Rui, Rafael J . Wysocki, Len Brown, Jiri Pirko,
	Ido Schimmel, David S . Miller, Peter Kaestle, Darren Hart,
	Andy Shevchenko, Support Opensource, Daniel Lezcano,
	Amit Kucheria, Shawn Guo, Sascha Hauer, Pengutronix Kernel Team,
	Fabio Estevam, NXP Linux Team, Allison Randal, Enrico Weigelt,
	Gayatri Kammela, Thomas Gleixner, linux-acpi, netdev,
	platform-driver-x86, linux-arm-kernel, kernel,
	Andrzej Pietrasiewicz

This driver provides a non-NULL "devdata" argument for
thermal_zone_device_register(). Thermal core never sets it to NULL
afterwards, so checking for its being NULL in this driver makes no sense.

Signed-off-by: Andrzej Pietrasiewicz <andrzej.p@collabora.com>
---
 drivers/acpi/thermal.c                                  | 6 ------
 drivers/thermal/intel/int340x_thermal/int3400_thermal.c | 6 ------
 2 files changed, 12 deletions(-)

diff --git a/drivers/acpi/thermal.c b/drivers/acpi/thermal.c
index 19067a5e5293..328b479ce7f6 100644
--- a/drivers/acpi/thermal.c
+++ b/drivers/acpi/thermal.c
@@ -531,9 +531,6 @@ static int thermal_get_mode(struct thermal_zone_device *thermal,
 {
 	struct acpi_thermal *tz = thermal->devdata;
 
-	if (!tz)
-		return -EINVAL;
-
 	*mode = tz->tz_enabled ? THERMAL_DEVICE_ENABLED :
 		THERMAL_DEVICE_DISABLED;
 
@@ -546,9 +543,6 @@ static int thermal_set_mode(struct thermal_zone_device *thermal,
 	struct acpi_thermal *tz = thermal->devdata;
 	int enable;
 
-	if (!tz)
-		return -EINVAL;
-
 	/*
 	 * enable/disable thermal management from ACPI thermal driver
 	 */
diff --git a/drivers/thermal/intel/int340x_thermal/int3400_thermal.c b/drivers/thermal/intel/int340x_thermal/int3400_thermal.c
index e802922a13cf..fbb59dd09481 100644
--- a/drivers/thermal/intel/int340x_thermal/int3400_thermal.c
+++ b/drivers/thermal/intel/int340x_thermal/int3400_thermal.c
@@ -235,9 +235,6 @@ static int int3400_thermal_get_mode(struct thermal_zone_device *thermal,
 {
 	struct int3400_thermal_priv *priv = thermal->devdata;
 
-	if (!priv)
-		return -EINVAL;
-
 	*mode = priv->mode;
 
 	return 0;
@@ -250,9 +247,6 @@ static int int3400_thermal_set_mode(struct thermal_zone_device *thermal,
 	bool enable;
 	int result = 0;
 
-	if (!priv)
-		return -EINVAL;
-
 	if (mode == THERMAL_DEVICE_ENABLED)
 		enable = true;
 	else if (mode == THERMAL_DEVICE_DISABLED)
-- 
2.17.1


^ permalink raw reply	[flat|nested] 63+ messages in thread

* [RFC v2 3/9] thermal: Properly handle mode values in .set_mode()
  2020-04-14 18:00   ` [RFC v2 0/9] " Andrzej Pietrasiewicz
  2020-04-14 18:00     ` [RFC v2 1/9] thermal: int3400_thermal: Statically initialize .get_mode()/.set_mode() ops Andrzej Pietrasiewicz
  2020-04-14 18:00     ` [RFC v2 2/9] thermal: Eliminate an always-false condition Andrzej Pietrasiewicz
@ 2020-04-14 18:00     ` Andrzej Pietrasiewicz
  2020-04-14 22:14       ` Daniel Lezcano
  2020-04-14 18:01     ` [RFC v2 4/9] thermal: core: Let thermal zone device's mode be stored in its struct Andrzej Pietrasiewicz
                       ` (6 subsequent siblings)
  9 siblings, 1 reply; 63+ messages in thread
From: Andrzej Pietrasiewicz @ 2020-04-14 18:00 UTC (permalink / raw)
  To: linux-pm
  Cc: Zhang Rui, Rafael J . Wysocki, Len Brown, Jiri Pirko,
	Ido Schimmel, David S . Miller, Peter Kaestle, Darren Hart,
	Andy Shevchenko, Support Opensource, Daniel Lezcano,
	Amit Kucheria, Shawn Guo, Sascha Hauer, Pengutronix Kernel Team,
	Fabio Estevam, NXP Linux Team, Allison Randal, Enrico Weigelt,
	Gayatri Kammela, Thomas Gleixner, linux-acpi, netdev,
	platform-driver-x86, linux-arm-kernel, kernel,
	Andrzej Pietrasiewicz

Allow only THERMAL_DEVICE_ENABLED and THERMAL_DEVICE_DISABLED as valid
states to transition to.

Signed-off-by: Andrzej Pietrasiewicz <andrzej.p@collabora.com>
---
 drivers/net/ethernet/mellanox/mlxsw/core_thermal.c | 8 ++++++--
 drivers/platform/x86/acerhdf.c                     | 4 ++++
 drivers/thermal/imx_thermal.c                      | 4 +++-
 drivers/thermal/intel/intel_quark_dts_thermal.c    | 5 ++++-
 drivers/thermal/of-thermal.c                       | 4 +++-
 5 files changed, 20 insertions(+), 5 deletions(-)

diff --git a/drivers/net/ethernet/mellanox/mlxsw/core_thermal.c b/drivers/net/ethernet/mellanox/mlxsw/core_thermal.c
index ce0a6837daa3..cd435ca7adbe 100644
--- a/drivers/net/ethernet/mellanox/mlxsw/core_thermal.c
+++ b/drivers/net/ethernet/mellanox/mlxsw/core_thermal.c
@@ -296,8 +296,10 @@ static int mlxsw_thermal_set_mode(struct thermal_zone_device *tzdev,
 
 	if (mode == THERMAL_DEVICE_ENABLED)
 		tzdev->polling_delay = thermal->polling_delay;
-	else
+	else if (mode == THERMAL_DEVICE_DISABLED)
 		tzdev->polling_delay = 0;
+	else
+		return -EINVAL;
 
 	mutex_unlock(&tzdev->lock);
 
@@ -486,8 +488,10 @@ static int mlxsw_thermal_module_mode_set(struct thermal_zone_device *tzdev,
 
 	if (mode == THERMAL_DEVICE_ENABLED)
 		tzdev->polling_delay = thermal->polling_delay;
-	else
+	else if (mode == THERMAL_DEVICE_DISABLED)
 		tzdev->polling_delay = 0;
+	else
+		return -EINVAL;
 
 	mutex_unlock(&tzdev->lock);
 
diff --git a/drivers/platform/x86/acerhdf.c b/drivers/platform/x86/acerhdf.c
index 8cc86f4e3ac1..d5188c1d688b 100644
--- a/drivers/platform/x86/acerhdf.c
+++ b/drivers/platform/x86/acerhdf.c
@@ -431,6 +431,10 @@ static int acerhdf_get_mode(struct thermal_zone_device *thermal,
 static int acerhdf_set_mode(struct thermal_zone_device *thermal,
 			    enum thermal_device_mode mode)
 {
+	if (mode != THERMAL_DEVICE_DISABLED &&
+	    mode != THERMAL_DEVICE_ENABLED)
+		return -EINVAL;
+
 	if (mode == THERMAL_DEVICE_DISABLED && kernelmode)
 		acerhdf_revert_to_bios_mode();
 	else if (mode == THERMAL_DEVICE_ENABLED && !kernelmode)
diff --git a/drivers/thermal/imx_thermal.c b/drivers/thermal/imx_thermal.c
index e761c9b42217..36b1924f1938 100644
--- a/drivers/thermal/imx_thermal.c
+++ b/drivers/thermal/imx_thermal.c
@@ -361,7 +361,7 @@ static int imx_set_mode(struct thermal_zone_device *tz,
 			data->irq_enabled = true;
 			enable_irq(data->irq);
 		}
-	} else {
+	} else if (mode == THERMAL_DEVICE_DISABLED) {
 		regmap_write(map, soc_data->sensor_ctrl + REG_CLR,
 			     soc_data->measure_temp_mask);
 		regmap_write(map, soc_data->sensor_ctrl + REG_SET,
@@ -374,6 +374,8 @@ static int imx_set_mode(struct thermal_zone_device *tz,
 			disable_irq(data->irq);
 			data->irq_enabled = false;
 		}
+	} else {
+		return -EINVAL;
 	}
 
 	data->mode = mode;
diff --git a/drivers/thermal/intel/intel_quark_dts_thermal.c b/drivers/thermal/intel/intel_quark_dts_thermal.c
index d704fc104cfd..11d7db895125 100644
--- a/drivers/thermal/intel/intel_quark_dts_thermal.c
+++ b/drivers/thermal/intel/intel_quark_dts_thermal.c
@@ -325,8 +325,11 @@ static int sys_set_mode(struct thermal_zone_device *tzd,
 	mutex_lock(&dts_update_mutex);
 	if (mode == THERMAL_DEVICE_ENABLED)
 		ret = soc_dts_enable(tzd);
-	else
+	else if (mode == THERMAL_DEVICE_DISABLED)
 		ret = soc_dts_disable(tzd);
+	else
+		return -EINVAL;
+
 	mutex_unlock(&dts_update_mutex);
 
 	return ret;
diff --git a/drivers/thermal/of-thermal.c b/drivers/thermal/of-thermal.c
index 874a47d6923f..36bebf623980 100644
--- a/drivers/thermal/of-thermal.c
+++ b/drivers/thermal/of-thermal.c
@@ -289,9 +289,11 @@ static int of_thermal_set_mode(struct thermal_zone_device *tz,
 	if (mode == THERMAL_DEVICE_ENABLED) {
 		tz->polling_delay = data->polling_delay;
 		tz->passive_delay = data->passive_delay;
-	} else {
+	} else if (mode == THERMAL_DEVICE_DISABLED) {
 		tz->polling_delay = 0;
 		tz->passive_delay = 0;
+	} else {
+		return -EINVAL;
 	}
 
 	mutex_unlock(&tz->lock);
-- 
2.17.1


^ permalink raw reply	[flat|nested] 63+ messages in thread

* [RFC v2 4/9] thermal: core: Let thermal zone device's mode be stored in its struct
  2020-04-14 18:00   ` [RFC v2 0/9] " Andrzej Pietrasiewicz
                       ` (2 preceding siblings ...)
  2020-04-14 18:00     ` [RFC v2 3/9] thermal: Properly handle mode values in .set_mode() Andrzej Pietrasiewicz
@ 2020-04-14 18:01     ` Andrzej Pietrasiewicz
  2020-04-14 22:30       ` Daniel Lezcano
  2020-04-14 18:01     ` [RFC v2 5/9] thermal: Store mode in thermal_zone_device Andrzej Pietrasiewicz
                       ` (5 subsequent siblings)
  9 siblings, 1 reply; 63+ messages in thread
From: Andrzej Pietrasiewicz @ 2020-04-14 18:01 UTC (permalink / raw)
  To: linux-pm
  Cc: Zhang Rui, Rafael J . Wysocki, Len Brown, Jiri Pirko,
	Ido Schimmel, David S . Miller, Peter Kaestle, Darren Hart,
	Andy Shevchenko, Support Opensource, Daniel Lezcano,
	Amit Kucheria, Shawn Guo, Sascha Hauer, Pengutronix Kernel Team,
	Fabio Estevam, NXP Linux Team, Allison Randal, Enrico Weigelt,
	Gayatri Kammela, Thomas Gleixner, linux-acpi, netdev,
	platform-driver-x86, linux-arm-kernel, kernel,
	Andrzej Pietrasiewicz

All the drivers which provide ->get_mode()/->set_mode() methods store their
mode in a thermal_device_mode enum, so keep this information in struct
thermal_zone_device rather than scattered all over the place.

Signed-off-by: Andrzej Pietrasiewicz <andrzej.p@collabora.com>
---
 drivers/thermal/thermal_core.c  | 28 +++++++++++++++++++
 drivers/thermal/thermal_sysfs.c |  9 +++----
 include/linux/thermal.h         | 48 +++++++++++++++++++++++++++++++++
 3 files changed, 79 insertions(+), 6 deletions(-)

diff --git a/drivers/thermal/thermal_core.c b/drivers/thermal/thermal_core.c
index 9a321dc548c8..cb0ff47f0dbe 100644
--- a/drivers/thermal/thermal_core.c
+++ b/drivers/thermal/thermal_core.c
@@ -469,6 +469,34 @@ static void thermal_zone_device_reset(struct thermal_zone_device *tz)
 	thermal_zone_device_init(tz);
 }
 
+int thermal_zone_device_get_mode(struct thermal_zone_device *tz,
+				 enum thermal_device_mode *mode)
+{
+	if (tz->ops->get_mode)
+		return tz->ops->get_mode(tz, mode);
+
+	*mode = tz->mode;
+
+	return 0;
+}
+EXPORT_SYMBOL_GPL(thermal_zone_device_get_mode);
+
+int thermal_zone_device_set_mode(struct thermal_zone_device *tz,
+				 enum thermal_device_mode mode)
+{
+	if (mode != THERMAL_DEVICE_DISABLED &&
+	    mode != THERMAL_DEVICE_ENABLED)
+		return -EINVAL;
+
+	if (tz->ops->set_mode)
+		return tz->ops->set_mode(tz, mode);
+
+	tz->mode = mode;
+
+	return 0;
+}
+EXPORT_SYMBOL_GPL(thermal_zone_device_set_mode);
+
 void thermal_zone_device_update(struct thermal_zone_device *tz,
 				enum thermal_notify_event event)
 {
diff --git a/drivers/thermal/thermal_sysfs.c b/drivers/thermal/thermal_sysfs.c
index aa99edb4dff7..66d9691b8bd6 100644
--- a/drivers/thermal/thermal_sysfs.c
+++ b/drivers/thermal/thermal_sysfs.c
@@ -52,10 +52,7 @@ mode_show(struct device *dev, struct device_attribute *attr, char *buf)
 	enum thermal_device_mode mode;
 	int result;
 
-	if (!tz->ops->get_mode)
-		return -EPERM;
-
-	result = tz->ops->get_mode(tz, &mode);
+	result = thermal_zone_device_get_mode(tz, &mode);
 	if (result)
 		return result;
 
@@ -74,9 +71,9 @@ mode_store(struct device *dev, struct device_attribute *attr,
 		return -EPERM;
 
 	if (!strncmp(buf, "enabled", sizeof("enabled") - 1))
-		result = tz->ops->set_mode(tz, THERMAL_DEVICE_ENABLED);
+		result = thermal_zone_device_enable(tz);
 	else if (!strncmp(buf, "disabled", sizeof("disabled") - 1))
-		result = tz->ops->set_mode(tz, THERMAL_DEVICE_DISABLED);
+		result = thermal_zone_device_disable(tz);
 	else
 		result = -EINVAL;
 
diff --git a/include/linux/thermal.h b/include/linux/thermal.h
index c91b1e344d56..9ff8542b7e7d 100644
--- a/include/linux/thermal.h
+++ b/include/linux/thermal.h
@@ -143,6 +143,7 @@ struct thermal_attr {
  * @trip_temp_attrs:	attributes for trip points for sysfs: trip temperature
  * @trip_type_attrs:	attributes for trip points for sysfs: trip type
  * @trip_hyst_attrs:	attributes for trip points for sysfs: trip hysteresis
+ * @mode:		current mode of this thermal zone
  * @devdata:	private pointer for device private data
  * @trips:	number of trip points the thermal zone supports
  * @trips_disabled;	bitmap for disabled trips
@@ -185,6 +186,7 @@ struct thermal_zone_device {
 	struct thermal_attr *trip_temp_attrs;
 	struct thermal_attr *trip_type_attrs;
 	struct thermal_attr *trip_hyst_attrs;
+	enum thermal_device_mode mode;
 	void *devdata;
 	int trips;
 	unsigned long trips_disabled;	/* bitmap for disabled trips */
@@ -437,6 +439,19 @@ int thermal_zone_bind_cooling_device(struct thermal_zone_device *, int,
 				     unsigned int);
 int thermal_zone_unbind_cooling_device(struct thermal_zone_device *, int,
 				       struct thermal_cooling_device *);
+
+int thermal_zone_device_get_mode(struct thermal_zone_device *tz,
+				 enum thermal_device_mode *mode);
+int thermal_zone_device_set_mode(struct thermal_zone_device *tz,
+				 enum thermal_device_mode mode);
+
+static inline void
+thermal_zone_device_store_mode(struct thermal_zone_device *tz,
+			       enum thermal_device_mode mode)
+{
+	tz->mode = mode;
+}
+
 void thermal_zone_device_update(struct thermal_zone_device *,
 				enum thermal_notify_event);
 void thermal_zone_set_trips(struct thermal_zone_device *);
@@ -494,6 +509,17 @@ static inline int thermal_zone_unbind_cooling_device(
 	struct thermal_zone_device *tz, int trip,
 	struct thermal_cooling_device *cdev)
 { return -ENODEV; }
+static inline int thermal_zone_device_get_mode(struct thermal_zone_device *tz,
+					       enum thermal_device_mode *mode)
+{ return -ENODEV; }
+static inline int thermal_zone_device_set_mode(struct thermal_zone_device *tz,
+					       enum thermal_device_mode mode)
+{ return -ENODEV; }
+static inline void
+thermal_zone_device_store_mode(struct thermal_zone_device *tz,
+			       enum thermal_device_mode mode)
+{ }
+
 static inline void thermal_zone_device_update(struct thermal_zone_device *tz,
 					      enum thermal_notify_event event)
 { }
@@ -543,4 +569,26 @@ static inline void thermal_notify_framework(struct thermal_zone_device *tz,
 { }
 #endif /* CONFIG_THERMAL */
 
+static inline int thermal_zone_device_enable(struct thermal_zone_device *tz)
+{
+	return thermal_zone_device_set_mode(tz, THERMAL_DEVICE_ENABLED);
+}
+
+static inline int thermal_zone_device_disable(struct thermal_zone_device *tz)
+{
+	return thermal_zone_device_set_mode(tz, THERMAL_DEVICE_DISABLED);
+}
+
+static inline void
+thermal_zone_device_store_enabled(struct thermal_zone_device *tz)
+{
+	thermal_zone_device_store_mode(tz, THERMAL_DEVICE_ENABLED);
+}
+
+static inline void
+thermal_zone_device_store_disabled(struct thermal_zone_device *tz)
+{
+	thermal_zone_device_store_mode(tz, THERMAL_DEVICE_DISABLED);
+}
+
 #endif /* __THERMAL_H__ */
-- 
2.17.1


^ permalink raw reply	[flat|nested] 63+ messages in thread

* [RFC v2 5/9] thermal: Store mode in thermal_zone_device
  2020-04-14 18:00   ` [RFC v2 0/9] " Andrzej Pietrasiewicz
                       ` (3 preceding siblings ...)
  2020-04-14 18:01     ` [RFC v2 4/9] thermal: core: Let thermal zone device's mode be stored in its struct Andrzej Pietrasiewicz
@ 2020-04-14 18:01     ` Andrzej Pietrasiewicz
  2020-04-15 10:55       ` Daniel Lezcano
  2020-04-14 18:01     ` [RFC v2 6/9] thermal: Remove get_mode() method Andrzej Pietrasiewicz
                       ` (4 subsequent siblings)
  9 siblings, 1 reply; 63+ messages in thread
From: Andrzej Pietrasiewicz @ 2020-04-14 18:01 UTC (permalink / raw)
  To: linux-pm
  Cc: Zhang Rui, Rafael J . Wysocki, Len Brown, Jiri Pirko,
	Ido Schimmel, David S . Miller, Peter Kaestle, Darren Hart,
	Andy Shevchenko, Support Opensource, Daniel Lezcano,
	Amit Kucheria, Shawn Guo, Sascha Hauer, Pengutronix Kernel Team,
	Fabio Estevam, NXP Linux Team, Allison Randal, Enrico Weigelt,
	Gayatri Kammela, Thomas Gleixner, linux-acpi, netdev,
	platform-driver-x86, linux-arm-kernel, kernel,
	Andrzej Pietrasiewicz

struct thermal_zone_device has a "mode" member now, so use it.

Signed-off-by: Andrzej Pietrasiewicz <andrzej.p@collabora.com>
---
 drivers/acpi/thermal.c                        | 48 +++++++++----------
 .../ethernet/mellanox/mlxsw/core_thermal.c    | 35 ++------------
 drivers/platform/x86/acerhdf.c                | 24 ++++------
 drivers/thermal/da9062-thermal.c              | 12 +----
 drivers/thermal/imx_thermal.c                 | 30 +++++-------
 .../intel/int340x_thermal/int3400_thermal.c   | 34 +++++--------
 .../thermal/intel/intel_quark_dts_thermal.c   | 22 +++------
 drivers/thermal/of-thermal.c                  | 19 ++------
 8 files changed, 71 insertions(+), 153 deletions(-)

diff --git a/drivers/acpi/thermal.c b/drivers/acpi/thermal.c
index 328b479ce7f6..755f12b76c20 100644
--- a/drivers/acpi/thermal.c
+++ b/drivers/acpi/thermal.c
@@ -172,7 +172,6 @@ struct acpi_thermal {
 	struct acpi_thermal_trips trips;
 	struct acpi_handle_list devices;
 	struct thermal_zone_device *thermal_zone;
-	int tz_enabled;
 	int kelvin_offset;	/* in millidegrees */
 	struct work_struct thermal_check_work;
 };
@@ -499,8 +498,14 @@ static int acpi_thermal_get_trip_points(struct acpi_thermal *tz)
 static void acpi_thermal_check(void *data)
 {
 	struct acpi_thermal *tz = data;
+	enum thermal_device_mode mode;
 
-	if (!tz->tz_enabled)
+	/*
+	 * this driver does not provide ->get_mode(), so calling
+	 * thermal_zone_device_get_mode() always succeeds
+	 */
+	thermal_zone_device_get_mode(tz->thermal_zone, &mode);
+	if (mode != THERMAL_DEVICE_ENABLED)
 		return;
 
 	thermal_zone_device_update(tz->thermal_zone,
@@ -526,39 +531,33 @@ static int thermal_get_temp(struct thermal_zone_device *thermal, int *temp)
 	return 0;
 }
 
-static int thermal_get_mode(struct thermal_zone_device *thermal,
-				enum thermal_device_mode *mode)
-{
-	struct acpi_thermal *tz = thermal->devdata;
-
-	*mode = tz->tz_enabled ? THERMAL_DEVICE_ENABLED :
-		THERMAL_DEVICE_DISABLED;
-
-	return 0;
-}
-
 static int thermal_set_mode(struct thermal_zone_device *thermal,
 				enum thermal_device_mode mode)
 {
 	struct acpi_thermal *tz = thermal->devdata;
-	int enable;
+	enum thermal_device_mode old_mode;
 
+	if (mode != THERMAL_DEVICE_DISABLED &&
+	    mode != THERMAL_DEVICE_ENABLED)
+		return -EINVAL;
 	/*
 	 * enable/disable thermal management from ACPI thermal driver
 	 */
-	if (mode == THERMAL_DEVICE_ENABLED)
-		enable = 1;
-	else if (mode == THERMAL_DEVICE_DISABLED) {
-		enable = 0;
+	if (mode == THERMAL_DEVICE_DISABLED)
 		pr_warn("thermal zone will be disabled\n");
-	} else
-		return -EINVAL;
 
-	if (enable != tz->tz_enabled) {
-		tz->tz_enabled = enable;
+	/*
+	 * this driver does not provide ->get_mode(), so calling
+	 * thermal_zone_device_get_mode() always succeeds
+	 */
+	thermal_zone_device_get_mode(thermal, &old_mode);
+
+	if (mode != old_mode) {
+		thermal_zone_device_store_mode(thermal, mode);
 		ACPI_DEBUG_PRINT((ACPI_DB_INFO,
 			"%s kernel ACPI thermal control\n",
-			tz->tz_enabled ? "Enable" : "Disable"));
+			mode == THERMAL_DEVICE_ENABLED ?
+			"Enable" : "Disable"));
 		acpi_thermal_check(tz);
 	}
 	return 0;
@@ -850,7 +849,6 @@ static struct thermal_zone_device_ops acpi_thermal_zone_ops = {
 	.bind = acpi_thermal_bind_cooling_device,
 	.unbind	= acpi_thermal_unbind_cooling_device,
 	.get_temp = thermal_get_temp,
-	.get_mode = thermal_get_mode,
 	.set_mode = thermal_set_mode,
 	.get_trip_type = thermal_get_trip_type,
 	.get_trip_temp = thermal_get_trip_temp,
@@ -907,7 +905,7 @@ static int acpi_thermal_register_thermal_zone(struct acpi_thermal *tz)
 	if (ACPI_FAILURE(status))
 		return -ENODEV;
 
-	tz->tz_enabled = 1;
+	thermal_zone_device_store_enabled(tz->thermal_zone);
 
 	dev_info(&tz->device->dev, "registered as thermal_zone%d\n",
 		 tz->thermal_zone->id);
diff --git a/drivers/net/ethernet/mellanox/mlxsw/core_thermal.c b/drivers/net/ethernet/mellanox/mlxsw/core_thermal.c
index cd435ca7adbe..c4239b2ba16d 100644
--- a/drivers/net/ethernet/mellanox/mlxsw/core_thermal.c
+++ b/drivers/net/ethernet/mellanox/mlxsw/core_thermal.c
@@ -98,7 +98,6 @@ struct mlxsw_thermal_module {
 	struct mlxsw_thermal *parent;
 	struct thermal_zone_device *tzdev;
 	struct mlxsw_thermal_trip trips[MLXSW_THERMAL_NUM_TRIPS];
-	enum thermal_device_mode mode;
 	int module; /* Module or gearbox number */
 };
 
@@ -110,7 +109,6 @@ struct mlxsw_thermal {
 	struct thermal_cooling_device *cdevs[MLXSW_MFCR_PWMS_MAX];
 	u8 cooling_levels[MLXSW_THERMAL_MAX_STATE + 1];
 	struct mlxsw_thermal_trip trips[MLXSW_THERMAL_NUM_TRIPS];
-	enum thermal_device_mode mode;
 	struct mlxsw_thermal_module *tz_module_arr;
 	u8 tz_module_num;
 	struct mlxsw_thermal_module *tz_gearbox_arr;
@@ -277,16 +275,6 @@ static int mlxsw_thermal_unbind(struct thermal_zone_device *tzdev,
 	return 0;
 }
 
-static int mlxsw_thermal_get_mode(struct thermal_zone_device *tzdev,
-				  enum thermal_device_mode *mode)
-{
-	struct mlxsw_thermal *thermal = tzdev->devdata;
-
-	*mode = thermal->mode;
-
-	return 0;
-}
-
 static int mlxsw_thermal_set_mode(struct thermal_zone_device *tzdev,
 				  enum thermal_device_mode mode)
 {
@@ -303,7 +291,7 @@ static int mlxsw_thermal_set_mode(struct thermal_zone_device *tzdev,
 
 	mutex_unlock(&tzdev->lock);
 
-	thermal->mode = mode;
+	thermal_zone_device_store_mode(tzdev, mode);
 	thermal_zone_device_update(tzdev, THERMAL_EVENT_UNSPECIFIED);
 
 	return 0;
@@ -409,7 +397,6 @@ static int mlxsw_thermal_trend_get(struct thermal_zone_device *tzdev,
 static struct thermal_zone_device_ops mlxsw_thermal_ops = {
 	.bind = mlxsw_thermal_bind,
 	.unbind = mlxsw_thermal_unbind,
-	.get_mode = mlxsw_thermal_get_mode,
 	.set_mode = mlxsw_thermal_set_mode,
 	.get_temp = mlxsw_thermal_get_temp,
 	.get_trip_type	= mlxsw_thermal_get_trip_type,
@@ -468,16 +455,6 @@ static int mlxsw_thermal_module_unbind(struct thermal_zone_device *tzdev,
 	return err;
 }
 
-static int mlxsw_thermal_module_mode_get(struct thermal_zone_device *tzdev,
-					 enum thermal_device_mode *mode)
-{
-	struct mlxsw_thermal_module *tz = tzdev->devdata;
-
-	*mode = tz->mode;
-
-	return 0;
-}
-
 static int mlxsw_thermal_module_mode_set(struct thermal_zone_device *tzdev,
 					 enum thermal_device_mode mode)
 {
@@ -495,7 +472,7 @@ static int mlxsw_thermal_module_mode_set(struct thermal_zone_device *tzdev,
 
 	mutex_unlock(&tzdev->lock);
 
-	tz->mode = mode;
+	thermal_zone_device_store_mode(tzdev, mode);
 	thermal_zone_device_update(tzdev, THERMAL_EVENT_UNSPECIFIED);
 
 	return 0;
@@ -600,7 +577,6 @@ mlxsw_thermal_module_trip_hyst_set(struct thermal_zone_device *tzdev, int trip,
 static struct thermal_zone_device_ops mlxsw_thermal_module_ops = {
 	.bind		= mlxsw_thermal_module_bind,
 	.unbind		= mlxsw_thermal_module_unbind,
-	.get_mode	= mlxsw_thermal_module_mode_get,
 	.set_mode	= mlxsw_thermal_module_mode_set,
 	.get_temp	= mlxsw_thermal_module_temp_get,
 	.get_trip_type	= mlxsw_thermal_module_trip_type_get,
@@ -639,7 +615,6 @@ static int mlxsw_thermal_gearbox_temp_get(struct thermal_zone_device *tzdev,
 static struct thermal_zone_device_ops mlxsw_thermal_gearbox_ops = {
 	.bind		= mlxsw_thermal_module_bind,
 	.unbind		= mlxsw_thermal_module_unbind,
-	.get_mode	= mlxsw_thermal_module_mode_get,
 	.set_mode	= mlxsw_thermal_module_mode_set,
 	.get_temp	= mlxsw_thermal_gearbox_temp_get,
 	.get_trip_type	= mlxsw_thermal_module_trip_type_get,
@@ -769,7 +744,7 @@ mlxsw_thermal_module_tz_init(struct mlxsw_thermal_module *module_tz)
 		return err;
 	}
 
-	module_tz->mode = THERMAL_DEVICE_ENABLED;
+	thermal_zone_device_store_enabled(module_tz->tzdev);
 	return 0;
 }
 
@@ -885,7 +860,7 @@ mlxsw_thermal_gearbox_tz_init(struct mlxsw_thermal_module *gearbox_tz)
 	if (IS_ERR(gearbox_tz->tzdev))
 		return PTR_ERR(gearbox_tz->tzdev);
 
-	gearbox_tz->mode = THERMAL_DEVICE_ENABLED;
+	thermal_zone_device_store_enabled(gearbox_tz->tzdev);
 	return 0;
 }
 
@@ -1054,7 +1029,7 @@ int mlxsw_thermal_init(struct mlxsw_core *core,
 	if (err)
 		goto err_unreg_modules_tzdev;
 
-	thermal->mode = THERMAL_DEVICE_ENABLED;
+	thermal_zone_device_store_enabled(thermal->tzdev);
 	*p_thermal = thermal;
 	return 0;
 
diff --git a/drivers/platform/x86/acerhdf.c b/drivers/platform/x86/acerhdf.c
index d5188c1d688b..e5a6abdf62ca 100644
--- a/drivers/platform/x86/acerhdf.c
+++ b/drivers/platform/x86/acerhdf.c
@@ -65,8 +65,10 @@
 
 #ifdef START_IN_KERNEL_MODE
 static int kernelmode = 1;
+#define ACERHDF_DEFAULT_MODE THERMAL_DEVICE_ENABLED
 #else
 static int kernelmode;
+#define ACERHDF_DEFAULT_MODE THERMAL_DEVICE_DISABLED
 #endif
 
 static unsigned int interval = 10;
@@ -410,18 +412,6 @@ static inline void acerhdf_enable_kernelmode(void)
 	pr_notice("kernel mode fan control ON\n");
 }
 
-static int acerhdf_get_mode(struct thermal_zone_device *thermal,
-			    enum thermal_device_mode *mode)
-{
-	if (verbose)
-		pr_notice("kernel mode fan control %d\n", kernelmode);
-
-	*mode = (kernelmode) ? THERMAL_DEVICE_ENABLED
-			     : THERMAL_DEVICE_DISABLED;
-
-	return 0;
-}
-
 /*
  * set operation mode;
  * enabled: the thermal layer of the kernel takes care about
@@ -435,10 +425,13 @@ static int acerhdf_set_mode(struct thermal_zone_device *thermal,
 	    mode != THERMAL_DEVICE_ENABLED)
 		return -EINVAL;
 
-	if (mode == THERMAL_DEVICE_DISABLED && kernelmode)
+	if (mode == THERMAL_DEVICE_DISABLED && kernelmode) {
 		acerhdf_revert_to_bios_mode();
-	else if (mode == THERMAL_DEVICE_ENABLED && !kernelmode)
+		thermal_zone_device_store_enabled(thermal);
+	} else if (mode == THERMAL_DEVICE_ENABLED && !kernelmode) {
 		acerhdf_enable_kernelmode();
+		thermal_zone_device_store_disabled(thermal);
+	}
 
 	return 0;
 }
@@ -492,7 +485,6 @@ static struct thermal_zone_device_ops acerhdf_dev_ops = {
 	.bind = acerhdf_bind,
 	.unbind = acerhdf_unbind,
 	.get_temp = acerhdf_get_ec_temp,
-	.get_mode = acerhdf_get_mode,
 	.set_mode = acerhdf_set_mode,
 	.get_trip_type = acerhdf_get_trip_type,
 	.get_trip_hyst = acerhdf_get_trip_hyst,
@@ -757,6 +749,8 @@ static int __init acerhdf_register_thermal(void)
 		return -EINVAL;
 	}
 
+	thermal_zone_device_store_mode(thz_dev, ACERHDF_DEFAULT_MODE);
+
 	return 0;
 }
 
diff --git a/drivers/thermal/da9062-thermal.c b/drivers/thermal/da9062-thermal.c
index c32709badeda..279d393bb048 100644
--- a/drivers/thermal/da9062-thermal.c
+++ b/drivers/thermal/da9062-thermal.c
@@ -49,7 +49,6 @@ struct da9062_thermal {
 	struct da9062 *hw;
 	struct delayed_work work;
 	struct thermal_zone_device *zone;
-	enum thermal_device_mode mode;
 	struct mutex lock; /* protection for da9062_thermal temperature */
 	int temperature;
 	int irq;
@@ -121,14 +120,6 @@ static irqreturn_t da9062_thermal_irq_handler(int irq, void *data)
 	return IRQ_HANDLED;
 }
 
-static int da9062_thermal_get_mode(struct thermal_zone_device *z,
-				   enum thermal_device_mode *mode)
-{
-	struct da9062_thermal *thermal = z->devdata;
-	*mode = thermal->mode;
-	return 0;
-}
-
 static int da9062_thermal_get_trip_type(struct thermal_zone_device *z,
 					int trip,
 					enum thermal_trip_type *type)
@@ -181,7 +172,6 @@ static int da9062_thermal_get_temp(struct thermal_zone_device *z,
 
 static struct thermal_zone_device_ops da9062_thermal_ops = {
 	.get_temp	= da9062_thermal_get_temp,
-	.get_mode	= da9062_thermal_get_mode,
 	.get_trip_type	= da9062_thermal_get_trip_type,
 	.get_trip_temp	= da9062_thermal_get_trip_temp,
 };
@@ -233,7 +223,6 @@ static int da9062_thermal_probe(struct platform_device *pdev)
 
 	thermal->config = match->data;
 	thermal->hw = chip;
-	thermal->mode = THERMAL_DEVICE_ENABLED;
 	thermal->dev = &pdev->dev;
 
 	INIT_DELAYED_WORK(&thermal->work, da9062_thermal_poll_on);
@@ -248,6 +237,7 @@ static int da9062_thermal_probe(struct platform_device *pdev)
 		ret = PTR_ERR(thermal->zone);
 		goto err;
 	}
+	thermal_zone_device_store_enabled(thermal->zone);
 
 	dev_dbg(&pdev->dev,
 		"TJUNC temperature polling period set at %d ms\n",
diff --git a/drivers/thermal/imx_thermal.c b/drivers/thermal/imx_thermal.c
index 36b1924f1938..f3f602b4ece5 100644
--- a/drivers/thermal/imx_thermal.c
+++ b/drivers/thermal/imx_thermal.c
@@ -197,7 +197,6 @@ struct imx_thermal_data {
 	struct cpufreq_policy *policy;
 	struct thermal_zone_device *tz;
 	struct thermal_cooling_device *cdev;
-	enum thermal_device_mode mode;
 	struct regmap *tempmon;
 	u32 c1, c2; /* See formula in imx_init_calib() */
 	int temp_passive;
@@ -252,11 +251,17 @@ static int imx_get_temp(struct thermal_zone_device *tz, int *temp)
 	struct imx_thermal_data *data = tz->devdata;
 	const struct thermal_soc_data *soc_data = data->socdata;
 	struct regmap *map = data->tempmon;
+	enum thermal_device_mode mode;
 	unsigned int n_meas;
 	bool wait;
 	u32 val;
 
-	if (data->mode == THERMAL_DEVICE_ENABLED) {
+	/*
+	 * this driver does not provide ->get_mode(), so calling
+	 * thermal_zone_device_get_mode() always succeeds
+	 */
+	thermal_zone_device_get_mode(tz, &mode);
+	if (mode == THERMAL_DEVICE_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 +288,7 @@ static int imx_get_temp(struct thermal_zone_device *tz, int *temp)
 
 	regmap_read(map, soc_data->temp_data, &val);
 
-	if (data->mode != THERMAL_DEVICE_ENABLED) {
+	if (mode != THERMAL_DEVICE_ENABLED) {
 		regmap_write(map, soc_data->sensor_ctrl + REG_CLR,
 			     soc_data->measure_temp_mask);
 		regmap_write(map, soc_data->sensor_ctrl + REG_SET,
@@ -331,16 +336,6 @@ static int imx_get_temp(struct thermal_zone_device *tz, int *temp)
 	return 0;
 }
 
-static int imx_get_mode(struct thermal_zone_device *tz,
-			enum thermal_device_mode *mode)
-{
-	struct imx_thermal_data *data = tz->devdata;
-
-	*mode = data->mode;
-
-	return 0;
-}
-
 static int imx_set_mode(struct thermal_zone_device *tz,
 			enum thermal_device_mode mode)
 {
@@ -378,7 +373,7 @@ static int imx_set_mode(struct thermal_zone_device *tz,
 		return -EINVAL;
 	}
 
-	data->mode = mode;
+	thermal_zone_device_store_mode(tz, mode);
 	thermal_zone_device_update(tz, THERMAL_EVENT_UNSPECIFIED);
 
 	return 0;
@@ -469,7 +464,6 @@ static struct thermal_zone_device_ops imx_tz_ops = {
 	.bind = imx_bind,
 	.unbind = imx_unbind,
 	.get_temp = imx_get_temp,
-	.get_mode = imx_get_mode,
 	.set_mode = imx_set_mode,
 	.get_trip_type = imx_get_trip_type,
 	.get_trip_temp = imx_get_trip_temp,
@@ -833,7 +827,7 @@ static int imx_thermal_probe(struct platform_device *pdev)
 		     data->socdata->measure_temp_mask);
 
 	data->irq_enabled = true;
-	data->mode = THERMAL_DEVICE_ENABLED;
+	thermal_zone_device_store_enabled(data->tz);
 
 	ret = devm_request_threaded_irq(&pdev->dev, data->irq,
 			imx_thermal_alarm_irq, imx_thermal_alarm_irq_thread,
@@ -887,7 +881,7 @@ static int __maybe_unused imx_thermal_suspend(struct device *dev)
 		     data->socdata->measure_temp_mask);
 	regmap_write(map, data->socdata->sensor_ctrl + REG_SET,
 		     data->socdata->power_down_mask);
-	data->mode = THERMAL_DEVICE_DISABLED;
+	thermal_zone_device_store_disabled(data->tz);
 	clk_disable_unprepare(data->thermal_clk);
 
 	return 0;
@@ -907,7 +901,7 @@ static int __maybe_unused imx_thermal_resume(struct device *dev)
 		     data->socdata->power_down_mask);
 	regmap_write(map, data->socdata->sensor_ctrl + REG_SET,
 		     data->socdata->measure_temp_mask);
-	data->mode = THERMAL_DEVICE_ENABLED;
+	thermal_zone_device_store_enabled(data->tz);
 
 	return 0;
 }
diff --git a/drivers/thermal/intel/int340x_thermal/int3400_thermal.c b/drivers/thermal/intel/int340x_thermal/int3400_thermal.c
index fbb59dd09481..a7d9b42c060d 100644
--- a/drivers/thermal/intel/int340x_thermal/int3400_thermal.c
+++ b/drivers/thermal/intel/int340x_thermal/int3400_thermal.c
@@ -44,7 +44,6 @@ static char *int3400_thermal_uuids[INT3400_THERMAL_MAXIMUM_UUID] = {
 struct int3400_thermal_priv {
 	struct acpi_device *adev;
 	struct thermal_zone_device *thermal;
-	int mode;
 	int art_count;
 	struct art *arts;
 	int trt_count;
@@ -230,42 +229,33 @@ static int int3400_thermal_get_temp(struct thermal_zone_device *thermal,
 	return 0;
 }
 
-static int int3400_thermal_get_mode(struct thermal_zone_device *thermal,
-				enum thermal_device_mode *mode)
-{
-	struct int3400_thermal_priv *priv = thermal->devdata;
-
-	*mode = priv->mode;
-
-	return 0;
-}
-
 static int int3400_thermal_set_mode(struct thermal_zone_device *thermal,
 				enum thermal_device_mode mode)
 {
 	struct int3400_thermal_priv *priv = thermal->devdata;
-	bool enable;
+	enum thermal_device_mode old_mode;
 	int result = 0;
 
-	if (mode == THERMAL_DEVICE_ENABLED)
-		enable = true;
-	else if (mode == THERMAL_DEVICE_DISABLED)
-		enable = false;
-	else
+	if (mode != THERMAL_DEVICE_ENABLED &&
+	    mode != THERMAL_DEVICE_DISABLED)
 		return -EINVAL;
 
-	if (enable != priv->mode) {
-		priv->mode = enable;
+	/*
+	 * this driver does not provide ->get_mode(), so calling
+	 * thermal_zone_device_get_mode() always succeeds
+	 */
+	thermal_zone_device_get_mode(thermal, &old_mode);
+	if (mode != old_mode) {
+		thermal_zone_device_store_mode(thermal, mode);
 		result = int3400_thermal_run_osc(priv->adev->handle,
-						 priv->current_uuid_index,
-						 enable);
+						priv->current_uuid_index,
+						mode == THERMAL_DEVICE_ENABLED);
 	}
 	return result;
 }
 
 static struct thermal_zone_device_ops int3400_thermal_ops = {
 	.get_temp = int3400_thermal_get_temp,
-	.get_mode = int3400_thermal_get_mode,
 	.set_mode = int3400_thermal_set_mode,
 };
 
diff --git a/drivers/thermal/intel/intel_quark_dts_thermal.c b/drivers/thermal/intel/intel_quark_dts_thermal.c
index 11d7db895125..6d440ef3055f 100644
--- a/drivers/thermal/intel/intel_quark_dts_thermal.c
+++ b/drivers/thermal/intel/intel_quark_dts_thermal.c
@@ -103,7 +103,6 @@ struct soc_sensor_entry {
 	bool locked;
 	u32 store_ptps;
 	u32 store_dts_enable;
-	enum thermal_device_mode mode;
 	struct thermal_zone_device *tzone;
 };
 
@@ -128,7 +127,7 @@ static int soc_dts_enable(struct thermal_zone_device *tzd)
 		return ret;
 
 	if (out & QRK_DTS_ENABLE_BIT) {
-		aux_entry->mode = THERMAL_DEVICE_ENABLED;
+		thermal_zone_device_store_enabled(tzd);
 		return 0;
 	}
 
@@ -139,9 +138,9 @@ static int soc_dts_enable(struct thermal_zone_device *tzd)
 		if (ret)
 			return ret;
 
-		aux_entry->mode = THERMAL_DEVICE_ENABLED;
+		thermal_zone_device_store_enabled(tzd);
 	} else {
-		aux_entry->mode = THERMAL_DEVICE_DISABLED;
+		thermal_zone_device_store_disabled(tzd);
 		pr_info("DTS is locked. Cannot enable DTS\n");
 		ret = -EPERM;
 	}
@@ -161,7 +160,7 @@ static int soc_dts_disable(struct thermal_zone_device *tzd)
 		return ret;
 
 	if (!(out & QRK_DTS_ENABLE_BIT)) {
-		aux_entry->mode = THERMAL_DEVICE_DISABLED;
+		thermal_zone_device_store_disabled(tzd);
 		return 0;
 	}
 
@@ -173,9 +172,9 @@ static int soc_dts_disable(struct thermal_zone_device *tzd)
 		if (ret)
 			return ret;
 
-		aux_entry->mode = THERMAL_DEVICE_DISABLED;
+		thermal_zone_device_store_disabled(tzd);
 	} else {
-		aux_entry->mode = THERMAL_DEVICE_ENABLED;
+		thermal_zone_device_store_enabled(tzd);
 		pr_info("DTS is locked. Cannot disable DTS\n");
 		ret = -EPERM;
 	}
@@ -309,14 +308,6 @@ static int sys_get_curr_temp(struct thermal_zone_device *tzd,
 	return 0;
 }
 
-static int sys_get_mode(struct thermal_zone_device *tzd,
-				enum thermal_device_mode *mode)
-{
-	struct soc_sensor_entry *aux_entry = tzd->devdata;
-	*mode = aux_entry->mode;
-	return 0;
-}
-
 static int sys_set_mode(struct thermal_zone_device *tzd,
 				enum thermal_device_mode mode)
 {
@@ -341,7 +332,6 @@ static struct thermal_zone_device_ops tzone_ops = {
 	.get_trip_type = sys_get_trip_type,
 	.set_trip_temp = sys_set_trip_temp,
 	.get_crit_temp = sys_get_crit_temp,
-	.get_mode = sys_get_mode,
 	.set_mode = sys_set_mode,
 };
 
diff --git a/drivers/thermal/of-thermal.c b/drivers/thermal/of-thermal.c
index 36bebf623980..0f1e134e90ea 100644
--- a/drivers/thermal/of-thermal.c
+++ b/drivers/thermal/of-thermal.c
@@ -51,7 +51,6 @@ struct __thermal_bind_params {
 
 /**
  * struct __thermal_zone - internal representation of a thermal zone
- * @mode: current thermal zone device mode (enabled/disabled)
  * @passive_delay: polling interval while passive cooling is activated
  * @polling_delay: zone polling interval
  * @slope: slope of the temperature adjustment curve
@@ -65,7 +64,6 @@ struct __thermal_bind_params {
  */
 
 struct __thermal_zone {
-	enum thermal_device_mode mode;
 	int passive_delay;
 	int polling_delay;
 	int slope;
@@ -269,16 +267,6 @@ static int of_thermal_unbind(struct thermal_zone_device *thermal,
 	return 0;
 }
 
-static int of_thermal_get_mode(struct thermal_zone_device *tz,
-			       enum thermal_device_mode *mode)
-{
-	struct __thermal_zone *data = tz->devdata;
-
-	*mode = data->mode;
-
-	return 0;
-}
-
 static int of_thermal_set_mode(struct thermal_zone_device *tz,
 			       enum thermal_device_mode mode)
 {
@@ -298,7 +286,7 @@ static int of_thermal_set_mode(struct thermal_zone_device *tz,
 
 	mutex_unlock(&tz->lock);
 
-	data->mode = mode;
+	thermal_zone_device_store_mode(tz, mode);
 	thermal_zone_device_update(tz, THERMAL_EVENT_UNSPECIFIED);
 
 	return 0;
@@ -395,7 +383,6 @@ static int of_thermal_get_crit_temp(struct thermal_zone_device *tz,
 }
 
 static struct thermal_zone_device_ops of_thermal_ops = {
-	.get_mode = of_thermal_get_mode,
 	.set_mode = of_thermal_set_mode,
 
 	.get_trip_type = of_thermal_get_trip_type,
@@ -556,7 +543,7 @@ thermal_zone_of_sensor_register(struct device *dev, int sensor_id, void *data,
 			tzd = thermal_zone_of_add_sensor(child, sensor_np,
 							 data, ops);
 			if (!IS_ERR(tzd))
-				tzd->ops->set_mode(tzd, THERMAL_DEVICE_ENABLED);
+				thermal_zone_device_enable(tzd);
 
 			of_node_put(child);
 			goto exit;
@@ -981,7 +968,6 @@ __init *thermal_of_build_thermal_zone(struct device_node *np)
 
 finish:
 	of_node_put(child);
-	tz->mode = THERMAL_DEVICE_DISABLED;
 
 	return tz;
 
@@ -1136,6 +1122,7 @@ int __init of_parse_thermal_zones(void)
 			of_thermal_free_zone(tz);
 			/* attempting to build remaining zones still */
 		}
+		thermal_zone_device_store_disabled(zone);
 	}
 	of_node_put(np);
 
-- 
2.17.1


^ permalink raw reply	[flat|nested] 63+ messages in thread

* [RFC v2 6/9] thermal: Remove get_mode() method
  2020-04-14 18:00   ` [RFC v2 0/9] " Andrzej Pietrasiewicz
                       ` (4 preceding siblings ...)
  2020-04-14 18:01     ` [RFC v2 5/9] thermal: Store mode in thermal_zone_device Andrzej Pietrasiewicz
@ 2020-04-14 18:01     ` Andrzej Pietrasiewicz
  2020-04-14 18:01     ` [RFC v2 7/9] thermal: core: Monitor thermal zone after mode change Andrzej Pietrasiewicz
                       ` (3 subsequent siblings)
  9 siblings, 0 replies; 63+ messages in thread
From: Andrzej Pietrasiewicz @ 2020-04-14 18:01 UTC (permalink / raw)
  To: linux-pm
  Cc: Zhang Rui, Rafael J . Wysocki, Len Brown, Jiri Pirko,
	Ido Schimmel, David S . Miller, Peter Kaestle, Darren Hart,
	Andy Shevchenko, Support Opensource, Daniel Lezcano,
	Amit Kucheria, Shawn Guo, Sascha Hauer, Pengutronix Kernel Team,
	Fabio Estevam, NXP Linux Team, Allison Randal, Enrico Weigelt,
	Gayatri Kammela, Thomas Gleixner, linux-acpi, netdev,
	platform-driver-x86, linux-arm-kernel, kernel,
	Andrzej Pietrasiewicz

Now that mode of all thermal zone devices is stored in struct
thermal_zone_device the get_mode() method is not used nor necessary any
more. All its former users used it only to report the state of their
then-internal variable.

The sysfs "mode" attribute is always exposed from now on. It doesn't hurt
the drivers which don't provide their own set_mode(), because writing to
"mode" will result in -EPERM, as expected.

thermal_zone_device_get_mode() will always succeed, so let it return the
actual value rather than an always-zero return code.

Signed-off-by: Andrzej Pietrasiewicz <andrzej.p@collabora.com>
---
 drivers/acpi/thermal.c                        | 12 ++--------
 drivers/thermal/imx_thermal.c                 |  6 +----
 .../intel/int340x_thermal/int3400_thermal.c   |  6 +----
 drivers/thermal/thermal_core.c                | 16 +-------------
 drivers/thermal/thermal_sysfs.c               | 22 +------------------
 include/linux/thermal.h                       | 16 ++++++++------
 6 files changed, 15 insertions(+), 63 deletions(-)

diff --git a/drivers/acpi/thermal.c b/drivers/acpi/thermal.c
index 755f12b76c20..bfe573076a3f 100644
--- a/drivers/acpi/thermal.c
+++ b/drivers/acpi/thermal.c
@@ -500,11 +500,7 @@ static void acpi_thermal_check(void *data)
 	struct acpi_thermal *tz = data;
 	enum thermal_device_mode mode;
 
-	/*
-	 * this driver does not provide ->get_mode(), so calling
-	 * thermal_zone_device_get_mode() always succeeds
-	 */
-	thermal_zone_device_get_mode(tz->thermal_zone, &mode);
+	mode = thermal_zone_device_get_mode(tz->thermal_zone);
 	if (mode != THERMAL_DEVICE_ENABLED)
 		return;
 
@@ -546,11 +542,7 @@ static int thermal_set_mode(struct thermal_zone_device *thermal,
 	if (mode == THERMAL_DEVICE_DISABLED)
 		pr_warn("thermal zone will be disabled\n");
 
-	/*
-	 * this driver does not provide ->get_mode(), so calling
-	 * thermal_zone_device_get_mode() always succeeds
-	 */
-	thermal_zone_device_get_mode(thermal, &old_mode);
+	old_mode = thermal_zone_device_get_mode(thermal);
 
 	if (mode != old_mode) {
 		thermal_zone_device_store_mode(thermal, mode);
diff --git a/drivers/thermal/imx_thermal.c b/drivers/thermal/imx_thermal.c
index f3f602b4ece5..8b683c6585cf 100644
--- a/drivers/thermal/imx_thermal.c
+++ b/drivers/thermal/imx_thermal.c
@@ -256,11 +256,7 @@ static int imx_get_temp(struct thermal_zone_device *tz, int *temp)
 	bool wait;
 	u32 val;
 
-	/*
-	 * this driver does not provide ->get_mode(), so calling
-	 * thermal_zone_device_get_mode() always succeeds
-	 */
-	thermal_zone_device_get_mode(tz, &mode);
+	mode = thermal_zone_device_get_mode(tz);
 	if (mode == THERMAL_DEVICE_ENABLED) {
 		/* Check if a measurement is currently in progress */
 		regmap_read(map, soc_data->temp_data, &val);
diff --git a/drivers/thermal/intel/int340x_thermal/int3400_thermal.c b/drivers/thermal/intel/int340x_thermal/int3400_thermal.c
index a7d9b42c060d..20007fafc04b 100644
--- a/drivers/thermal/intel/int340x_thermal/int3400_thermal.c
+++ b/drivers/thermal/intel/int340x_thermal/int3400_thermal.c
@@ -240,11 +240,7 @@ static int int3400_thermal_set_mode(struct thermal_zone_device *thermal,
 	    mode != THERMAL_DEVICE_DISABLED)
 		return -EINVAL;
 
-	/*
-	 * this driver does not provide ->get_mode(), so calling
-	 * thermal_zone_device_get_mode() always succeeds
-	 */
-	thermal_zone_device_get_mode(thermal, &old_mode);
+	old_mode = thermal_zone_device_get_mode(thermal);
 	if (mode != old_mode) {
 		thermal_zone_device_store_mode(thermal, mode);
 		result = int3400_thermal_run_osc(priv->adev->handle,
diff --git a/drivers/thermal/thermal_core.c b/drivers/thermal/thermal_core.c
index cb0ff47f0dbe..a59c3411fb9c 100644
--- a/drivers/thermal/thermal_core.c
+++ b/drivers/thermal/thermal_core.c
@@ -469,18 +469,6 @@ static void thermal_zone_device_reset(struct thermal_zone_device *tz)
 	thermal_zone_device_init(tz);
 }
 
-int thermal_zone_device_get_mode(struct thermal_zone_device *tz,
-				 enum thermal_device_mode *mode)
-{
-	if (tz->ops->get_mode)
-		return tz->ops->get_mode(tz, mode);
-
-	*mode = tz->mode;
-
-	return 0;
-}
-EXPORT_SYMBOL_GPL(thermal_zone_device_get_mode);
-
 int thermal_zone_device_set_mode(struct thermal_zone_device *tz,
 				 enum thermal_device_mode mode)
 {
@@ -1507,9 +1495,7 @@ static int thermal_pm_notify(struct notifier_block *nb,
 	case PM_POST_SUSPEND:
 		atomic_set(&in_suspend, 0);
 		list_for_each_entry(tz, &thermal_tz_list, node) {
-			tz_mode = THERMAL_DEVICE_ENABLED;
-			if (tz->ops->get_mode)
-				tz->ops->get_mode(tz, &tz_mode);
+			tz_mode = thermal_zone_device_get_mode(tz);
 
 			if (tz_mode == THERMAL_DEVICE_DISABLED)
 				continue;
diff --git a/drivers/thermal/thermal_sysfs.c b/drivers/thermal/thermal_sysfs.c
index 66d9691b8bd6..cbb27b3c96d2 100644
--- a/drivers/thermal/thermal_sysfs.c
+++ b/drivers/thermal/thermal_sysfs.c
@@ -50,11 +50,8 @@ mode_show(struct device *dev, struct device_attribute *attr, char *buf)
 {
 	struct thermal_zone_device *tz = to_thermal_zone(dev);
 	enum thermal_device_mode mode;
-	int result;
 
-	result = thermal_zone_device_get_mode(tz, &mode);
-	if (result)
-		return result;
+	mode = thermal_zone_device_get_mode(tz);
 
 	return sprintf(buf, "%s\n", mode == THERMAL_DEVICE_ENABLED ? "enabled"
 		       : "disabled");
@@ -425,30 +422,13 @@ static struct attribute_group thermal_zone_attribute_group = {
 	.attrs = thermal_zone_dev_attrs,
 };
 
-/* We expose mode only if .get_mode is present */
 static struct attribute *thermal_zone_mode_attrs[] = {
 	&dev_attr_mode.attr,
 	NULL,
 };
 
-static umode_t thermal_zone_mode_is_visible(struct kobject *kobj,
-					    struct attribute *attr,
-					    int attrno)
-{
-	struct device *dev = container_of(kobj, struct device, kobj);
-	struct thermal_zone_device *tz;
-
-	tz = container_of(dev, struct thermal_zone_device, device);
-
-	if (tz->ops->get_mode)
-		return attr->mode;
-
-	return 0;
-}
-
 static struct attribute_group thermal_zone_mode_attribute_group = {
 	.attrs = thermal_zone_mode_attrs,
-	.is_visible = thermal_zone_mode_is_visible,
 };
 
 /* We expose passive only if passive trips are present */
diff --git a/include/linux/thermal.h b/include/linux/thermal.h
index 9ff8542b7e7d..efb481088035 100644
--- a/include/linux/thermal.h
+++ b/include/linux/thermal.h
@@ -86,8 +86,6 @@ struct thermal_zone_device_ops {
 		       struct thermal_cooling_device *);
 	int (*get_temp) (struct thermal_zone_device *, int *);
 	int (*set_trips) (struct thermal_zone_device *, int, int);
-	int (*get_mode) (struct thermal_zone_device *,
-			 enum thermal_device_mode *);
 	int (*set_mode) (struct thermal_zone_device *,
 		enum thermal_device_mode);
 	int (*get_trip_type) (struct thermal_zone_device *, int,
@@ -440,8 +438,12 @@ int thermal_zone_bind_cooling_device(struct thermal_zone_device *, int,
 int thermal_zone_unbind_cooling_device(struct thermal_zone_device *, int,
 				       struct thermal_cooling_device *);
 
-int thermal_zone_device_get_mode(struct thermal_zone_device *tz,
-				 enum thermal_device_mode *mode);
+static inline enum thermal_device_mode
+thermal_zone_device_get_mode(struct thermal_zone_device *tz)
+{
+	return tz->mode;
+}
+
 int thermal_zone_device_set_mode(struct thermal_zone_device *tz,
 				 enum thermal_device_mode mode);
 
@@ -509,9 +511,9 @@ static inline int thermal_zone_unbind_cooling_device(
 	struct thermal_zone_device *tz, int trip,
 	struct thermal_cooling_device *cdev)
 { return -ENODEV; }
-static inline int thermal_zone_device_get_mode(struct thermal_zone_device *tz,
-					       enum thermal_device_mode *mode)
-{ return -ENODEV; }
+static inline enum thermal_device_mode
+thermal_zone_device_get_mode(struct thermal_zone_device *tz)
+{ return THERMAL_DEVICE_DISABLED; }
 static inline int thermal_zone_device_set_mode(struct thermal_zone_device *tz,
 					       enum thermal_device_mode mode)
 { return -ENODEV; }
-- 
2.17.1


^ permalink raw reply	[flat|nested] 63+ messages in thread

* [RFC v2 7/9] thermal: core: Monitor thermal zone after mode change
  2020-04-14 18:00   ` [RFC v2 0/9] " Andrzej Pietrasiewicz
                       ` (5 preceding siblings ...)
  2020-04-14 18:01     ` [RFC v2 6/9] thermal: Remove get_mode() method Andrzej Pietrasiewicz
@ 2020-04-14 18:01     ` Andrzej Pietrasiewicz
  2020-04-14 18:01     ` [RFC v2 8/9] thermal: of: Monitor thermal zone after enabling it Andrzej Pietrasiewicz
                       ` (2 subsequent siblings)
  9 siblings, 0 replies; 63+ messages in thread
From: Andrzej Pietrasiewicz @ 2020-04-14 18:01 UTC (permalink / raw)
  To: linux-pm
  Cc: Zhang Rui, Rafael J . Wysocki, Len Brown, Jiri Pirko,
	Ido Schimmel, David S . Miller, Peter Kaestle, Darren Hart,
	Andy Shevchenko, Support Opensource, Daniel Lezcano,
	Amit Kucheria, Shawn Guo, Sascha Hauer, Pengutronix Kernel Team,
	Fabio Estevam, NXP Linux Team, Allison Randal, Enrico Weigelt,
	Gayatri Kammela, Thomas Gleixner, linux-acpi, netdev,
	platform-driver-x86, linux-arm-kernel, kernel,
	Andrzej Pietrasiewicz

Mode changing might imply a need to stop/start polling the device.
monitor_thermal_zone() when mode changes.

Signed-off-by: Andrzej Pietrasiewicz <andrzej.p@collabora.com>
---
 drivers/thermal/thermal_core.c  | 2 +-
 drivers/thermal/thermal_core.h  | 2 ++
 drivers/thermal/thermal_sysfs.c | 7 +++++++
 3 files changed, 10 insertions(+), 1 deletion(-)

diff --git a/drivers/thermal/thermal_core.c b/drivers/thermal/thermal_core.c
index a59c3411fb9c..7637ddb79813 100644
--- a/drivers/thermal/thermal_core.c
+++ b/drivers/thermal/thermal_core.c
@@ -305,7 +305,7 @@ static void thermal_zone_device_set_polling(struct thermal_zone_device *tz,
 		cancel_delayed_work(&tz->poll_queue);
 }
 
-static void monitor_thermal_zone(struct thermal_zone_device *tz)
+void monitor_thermal_zone(struct thermal_zone_device *tz)
 {
 	mutex_lock(&tz->lock);
 
diff --git a/drivers/thermal/thermal_core.h b/drivers/thermal/thermal_core.h
index a9bf00e91d64..469258778161 100644
--- a/drivers/thermal/thermal_core.h
+++ b/drivers/thermal/thermal_core.h
@@ -89,6 +89,8 @@ thermal_cooling_device_stats_update(struct thermal_cooling_device *cdev,
 				    unsigned long new_state) {}
 #endif /* CONFIG_THERMAL_STATISTICS */
 
+void monitor_thermal_zone(struct thermal_zone_device *tz);
+
 /* device tree support */
 #ifdef CONFIG_THERMAL_OF
 int of_parse_thermal_zones(void);
diff --git a/drivers/thermal/thermal_sysfs.c b/drivers/thermal/thermal_sysfs.c
index cbb27b3c96d2..bc34d0f9768b 100644
--- a/drivers/thermal/thermal_sysfs.c
+++ b/drivers/thermal/thermal_sysfs.c
@@ -62,11 +62,14 @@ mode_store(struct device *dev, struct device_attribute *attr,
 	   const char *buf, size_t count)
 {
 	struct thermal_zone_device *tz = to_thermal_zone(dev);
+	enum thermal_device_mode old_mode, mode;
 	int result;
 
 	if (!tz->ops->set_mode)
 		return -EPERM;
 
+	old_mode = thermal_zone_device_get_mode(tz);
+
 	if (!strncmp(buf, "enabled", sizeof("enabled") - 1))
 		result = thermal_zone_device_enable(tz);
 	else if (!strncmp(buf, "disabled", sizeof("disabled") - 1))
@@ -77,6 +80,10 @@ mode_store(struct device *dev, struct device_attribute *attr,
 	if (result)
 		return result;
 
+	mode = thermal_zone_device_get_mode(tz);
+	if (mode != old_mode)
+		monitor_thermal_zone(tz);
+
 	return count;
 }
 
-- 
2.17.1


^ permalink raw reply	[flat|nested] 63+ messages in thread

* [RFC v2 8/9] thermal: of: Monitor thermal zone after enabling it
  2020-04-14 18:00   ` [RFC v2 0/9] " Andrzej Pietrasiewicz
                       ` (6 preceding siblings ...)
  2020-04-14 18:01     ` [RFC v2 7/9] thermal: core: Monitor thermal zone after mode change Andrzej Pietrasiewicz
@ 2020-04-14 18:01     ` Andrzej Pietrasiewicz
  2020-04-14 18:01     ` [RFC v2 9/9] thermal: core: Stop polling DISABLED thermal devices Andrzej Pietrasiewicz
  2020-04-14 21:52     ` [RFC v2 0/9] Stop monitoring disabled devices Ezequiel Garcia
  9 siblings, 0 replies; 63+ messages in thread
From: Andrzej Pietrasiewicz @ 2020-04-14 18:01 UTC (permalink / raw)
  To: linux-pm
  Cc: Zhang Rui, Rafael J . Wysocki, Len Brown, Jiri Pirko,
	Ido Schimmel, David S . Miller, Peter Kaestle, Darren Hart,
	Andy Shevchenko, Support Opensource, Daniel Lezcano,
	Amit Kucheria, Shawn Guo, Sascha Hauer, Pengutronix Kernel Team,
	Fabio Estevam, NXP Linux Team, Allison Randal, Enrico Weigelt,
	Gayatri Kammela, Thomas Gleixner, linux-acpi, netdev,
	platform-driver-x86, linux-arm-kernel, kernel,
	Andrzej Pietrasiewicz

thermal/of calls its own ->set_mode() method, so monitor thermal zone
afterwards. This is needed for the DISABLED->ENABLED transition.

Signed-off-by: Andrzej Pietrasiewicz <andrzej.p@collabora.com>
---
 drivers/thermal/of-thermal.c | 5 ++++-
 1 file changed, 4 insertions(+), 1 deletion(-)

diff --git a/drivers/thermal/of-thermal.c b/drivers/thermal/of-thermal.c
index 0f1e134e90ea..aa4cbc904c5c 100644
--- a/drivers/thermal/of-thermal.c
+++ b/drivers/thermal/of-thermal.c
@@ -542,8 +542,11 @@ thermal_zone_of_sensor_register(struct device *dev, int sensor_id, void *data,
 		if (id == sensor_id) {
 			tzd = thermal_zone_of_add_sensor(child, sensor_np,
 							 data, ops);
-			if (!IS_ERR(tzd))
+			if (!IS_ERR(tzd)) {
 				thermal_zone_device_enable(tzd);
+				thermal_zone_device_update(tzd,
+						THERMAL_EVENT_UNSPECIFIED);
+			}
 
 			of_node_put(child);
 			goto exit;
-- 
2.17.1


^ permalink raw reply	[flat|nested] 63+ messages in thread

* [RFC v2 9/9] thermal: core: Stop polling DISABLED thermal devices
  2020-04-14 18:00   ` [RFC v2 0/9] " Andrzej Pietrasiewicz
                       ` (7 preceding siblings ...)
  2020-04-14 18:01     ` [RFC v2 8/9] thermal: of: Monitor thermal zone after enabling it Andrzej Pietrasiewicz
@ 2020-04-14 18:01     ` Andrzej Pietrasiewicz
  2020-04-14 21:52     ` [RFC v2 0/9] Stop monitoring disabled devices Ezequiel Garcia
  9 siblings, 0 replies; 63+ messages in thread
From: Andrzej Pietrasiewicz @ 2020-04-14 18:01 UTC (permalink / raw)
  To: linux-pm
  Cc: Zhang Rui, Rafael J . Wysocki, Len Brown, Jiri Pirko,
	Ido Schimmel, David S . Miller, Peter Kaestle, Darren Hart,
	Andy Shevchenko, Support Opensource, Daniel Lezcano,
	Amit Kucheria, Shawn Guo, Sascha Hauer, Pengutronix Kernel Team,
	Fabio Estevam, NXP Linux Team, Allison Randal, Enrico Weigelt,
	Gayatri Kammela, Thomas Gleixner, linux-acpi, netdev,
	platform-driver-x86, linux-arm-kernel, kernel,
	Andrzej Pietrasiewicz

Polling DISABLED devices is not desired, as all such "disabled" devices
are meant to be handled by userspace.

Add a new mode: THERMAL_DEVICE_INITIAL. It is dedicated to handle devices
which must be initially DISABLED, but which are polled at startup
nonetheless. THERMAL_DEVICE_INITIAL shall be reported as "enabled" in
sysfs to keep the userspace interface intact.

Signed-off-by: Andrzej Pietrasiewicz <andrzej.p@collabora.com>
---
 drivers/thermal/thermal_core.c  | 18 ++++++++++++++++--
 drivers/thermal/thermal_sysfs.c |  4 ++--
 include/linux/thermal.h         |  1 +
 3 files changed, 19 insertions(+), 4 deletions(-)

diff --git a/drivers/thermal/thermal_core.c b/drivers/thermal/thermal_core.c
index 7637ddb79813..c3c966a5a50b 100644
--- a/drivers/thermal/thermal_core.c
+++ b/drivers/thermal/thermal_core.c
@@ -305,13 +305,22 @@ static void thermal_zone_device_set_polling(struct thermal_zone_device *tz,
 		cancel_delayed_work(&tz->poll_queue);
 }
 
+static inline bool should_stop_polling(struct thermal_zone_device *tz)
+{
+	return thermal_zone_device_get_mode(tz) == THERMAL_DEVICE_DISABLED;
+}
+
 void monitor_thermal_zone(struct thermal_zone_device *tz)
 {
+	bool stop;
+
+	stop = should_stop_polling(tz);
+
 	mutex_lock(&tz->lock);
 
-	if (tz->passive)
+	if (!stop && tz->passive)
 		thermal_zone_device_set_polling(tz, tz->passive_delay);
-	else if (tz->polling_delay)
+	else if (!stop && tz->polling_delay)
 		thermal_zone_device_set_polling(tz, tz->polling_delay);
 	else
 		thermal_zone_device_set_polling(tz, 0);
@@ -490,6 +499,9 @@ void thermal_zone_device_update(struct thermal_zone_device *tz,
 {
 	int count;
 
+	if (should_stop_polling(tz))
+		return;
+
 	if (atomic_read(&in_suspend))
 		return;
 
@@ -1356,6 +1368,8 @@ thermal_zone_device_register(const char *type, int trips, int mask,
 	list_add_tail(&tz->node, &thermal_tz_list);
 	mutex_unlock(&thermal_list_lock);
 
+	tz->mode = THERMAL_DEVICE_INITIAL;
+
 	/* Bind cooling devices for this zone */
 	bind_tz(tz);
 
diff --git a/drivers/thermal/thermal_sysfs.c b/drivers/thermal/thermal_sysfs.c
index bc34d0f9768b..9d26196735bd 100644
--- a/drivers/thermal/thermal_sysfs.c
+++ b/drivers/thermal/thermal_sysfs.c
@@ -53,8 +53,8 @@ mode_show(struct device *dev, struct device_attribute *attr, char *buf)
 
 	mode = thermal_zone_device_get_mode(tz);
 
-	return sprintf(buf, "%s\n", mode == THERMAL_DEVICE_ENABLED ? "enabled"
-		       : "disabled");
+	return sprintf(buf, "%s\n", mode == THERMAL_DEVICE_DISABLED ? "disabled"
+		       : "enabled");
 }
 
 static ssize_t
diff --git a/include/linux/thermal.h b/include/linux/thermal.h
index efb481088035..2f61f461da50 100644
--- a/include/linux/thermal.h
+++ b/include/linux/thermal.h
@@ -50,6 +50,7 @@ struct thermal_instance;
 enum thermal_device_mode {
 	THERMAL_DEVICE_DISABLED = 0,
 	THERMAL_DEVICE_ENABLED,
+	THERMAL_DEVICE_INITIAL,
 };
 
 enum thermal_trip_type {
-- 
2.17.1


^ permalink raw reply	[flat|nested] 63+ messages in thread

* Re: [RFC v2 0/9] Stop monitoring disabled devices
  2020-04-14 18:00   ` [RFC v2 0/9] " Andrzej Pietrasiewicz
                       ` (8 preceding siblings ...)
  2020-04-14 18:01     ` [RFC v2 9/9] thermal: core: Stop polling DISABLED thermal devices Andrzej Pietrasiewicz
@ 2020-04-14 21:52     ` Ezequiel Garcia
  9 siblings, 0 replies; 63+ messages in thread
From: Ezequiel Garcia @ 2020-04-14 21:52 UTC (permalink / raw)
  To: Andrzej Pietrasiewicz
  Cc: Linux-pm mailing list, Rafael J . Wysocki, platform-driver-x86,
	kernel, Fabio Estevam, Amit Kucheria, Daniel Lezcano, linux-acpi,
	NXP Linux Team, Darren Hart, Zhang Rui, Gayatri Kammela,
	Len Brown, Sascha Hauer, Ido Schimmel, Jiri Pirko,
	Thomas Gleixner, Allison Randal, linux-arm-kernel,
	Support Opensource, Shawn Guo, Peter Kaestle,
	Pengutronix Kernel Team, Networking, Enrico Weigelt,
	David S . Miller, Andy Shevchenko

Hi Andrzej,

Thanks for your patches.

On Tue, 14 Apr 2020 at 15:01, Andrzej Pietrasiewicz
<andrzej.p@collabora.com> wrote:
>
> This is the second iteration of this RFC.
>
> The series now focuses on cleaning up the code in the first place.
>
[..]
>  12 files changed, 180 insertions(+), 208 deletions(-)
>

Compared with the previous iteration, and just judging
by this diffstat, I think it's a step in the right direction.

Nice job :-)

Ezequiel

^ permalink raw reply	[flat|nested] 63+ messages in thread

* Re: [RFC v2 3/9] thermal: Properly handle mode values in .set_mode()
  2020-04-14 18:00     ` [RFC v2 3/9] thermal: Properly handle mode values in .set_mode() Andrzej Pietrasiewicz
@ 2020-04-14 22:14       ` Daniel Lezcano
  0 siblings, 0 replies; 63+ messages in thread
From: Daniel Lezcano @ 2020-04-14 22:14 UTC (permalink / raw)
  To: Andrzej Pietrasiewicz, linux-pm
  Cc: Zhang Rui, Rafael J . Wysocki, Len Brown, Jiri Pirko,
	Ido Schimmel, David S . Miller, Peter Kaestle, Darren Hart,
	Andy Shevchenko, Support Opensource, Amit Kucheria, Shawn Guo,
	Sascha Hauer, Pengutronix Kernel Team, Fabio Estevam,
	NXP Linux Team, Allison Randal, Enrico Weigelt, Gayatri Kammela,
	Thomas Gleixner, linux-acpi, netdev, platform-driver-x86,
	linux-arm-kernel, kernel


Hi Andrzej,

you can drop this patch. It is not useful as the caller checks the
correctness of the values in the patch 4/9.

Moreover the patch is bogus because it returns before releasing the lock.

On 14/04/2020 20:00, Andrzej Pietrasiewicz wrote:
> Allow only THERMAL_DEVICE_ENABLED and THERMAL_DEVICE_DISABLED as valid
> states to transition to.




> Signed-off-by: Andrzej Pietrasiewicz <andrzej.p@collabora.com>
> ---
>  drivers/net/ethernet/mellanox/mlxsw/core_thermal.c | 8 ++++++--
>  drivers/platform/x86/acerhdf.c                     | 4 ++++
>  drivers/thermal/imx_thermal.c                      | 4 +++-
>  drivers/thermal/intel/intel_quark_dts_thermal.c    | 5 ++++-
>  drivers/thermal/of-thermal.c                       | 4 +++-
>  5 files changed, 20 insertions(+), 5 deletions(-)
> 
> diff --git a/drivers/net/ethernet/mellanox/mlxsw/core_thermal.c b/drivers/net/ethernet/mellanox/mlxsw/core_thermal.c
> index ce0a6837daa3..cd435ca7adbe 100644
> --- a/drivers/net/ethernet/mellanox/mlxsw/core_thermal.c
> +++ b/drivers/net/ethernet/mellanox/mlxsw/core_thermal.c
> @@ -296,8 +296,10 @@ static int mlxsw_thermal_set_mode(struct thermal_zone_device *tzdev,
>  
>  	if (mode == THERMAL_DEVICE_ENABLED)
>  		tzdev->polling_delay = thermal->polling_delay;
> -	else
> +	else if (mode == THERMAL_DEVICE_DISABLED)
>  		tzdev->polling_delay = 0;
> +	else
> +		return -EINVAL;
>  
>  	mutex_unlock(&tzdev->lock);
>  
> @@ -486,8 +488,10 @@ static int mlxsw_thermal_module_mode_set(struct thermal_zone_device *tzdev,
>  
>  	if (mode == THERMAL_DEVICE_ENABLED)
>  		tzdev->polling_delay = thermal->polling_delay;
> -	else
> +	else if (mode == THERMAL_DEVICE_DISABLED)
>  		tzdev->polling_delay = 0;
> +	else
> +		return -EINVAL;
>  
>  	mutex_unlock(&tzdev->lock);
>  
> diff --git a/drivers/platform/x86/acerhdf.c b/drivers/platform/x86/acerhdf.c
> index 8cc86f4e3ac1..d5188c1d688b 100644
> --- a/drivers/platform/x86/acerhdf.c
> +++ b/drivers/platform/x86/acerhdf.c
> @@ -431,6 +431,10 @@ static int acerhdf_get_mode(struct thermal_zone_device *thermal,
>  static int acerhdf_set_mode(struct thermal_zone_device *thermal,
>  			    enum thermal_device_mode mode)
>  {
> +	if (mode != THERMAL_DEVICE_DISABLED &&
> +	    mode != THERMAL_DEVICE_ENABLED)
> +		return -EINVAL;
> +
>  	if (mode == THERMAL_DEVICE_DISABLED && kernelmode)
>  		acerhdf_revert_to_bios_mode();
>  	else if (mode == THERMAL_DEVICE_ENABLED && !kernelmode)
> diff --git a/drivers/thermal/imx_thermal.c b/drivers/thermal/imx_thermal.c
> index e761c9b42217..36b1924f1938 100644
> --- a/drivers/thermal/imx_thermal.c
> +++ b/drivers/thermal/imx_thermal.c
> @@ -361,7 +361,7 @@ static int imx_set_mode(struct thermal_zone_device *tz,
>  			data->irq_enabled = true;
>  			enable_irq(data->irq);
>  		}
> -	} else {
> +	} else if (mode == THERMAL_DEVICE_DISABLED) {
>  		regmap_write(map, soc_data->sensor_ctrl + REG_CLR,
>  			     soc_data->measure_temp_mask);
>  		regmap_write(map, soc_data->sensor_ctrl + REG_SET,
> @@ -374,6 +374,8 @@ static int imx_set_mode(struct thermal_zone_device *tz,
>  			disable_irq(data->irq);
>  			data->irq_enabled = false;
>  		}
> +	} else {
> +		return -EINVAL;
>  	}
>  
>  	data->mode = mode;
> diff --git a/drivers/thermal/intel/intel_quark_dts_thermal.c b/drivers/thermal/intel/intel_quark_dts_thermal.c
> index d704fc104cfd..11d7db895125 100644
> --- a/drivers/thermal/intel/intel_quark_dts_thermal.c
> +++ b/drivers/thermal/intel/intel_quark_dts_thermal.c
> @@ -325,8 +325,11 @@ static int sys_set_mode(struct thermal_zone_device *tzd,
>  	mutex_lock(&dts_update_mutex);
>  	if (mode == THERMAL_DEVICE_ENABLED)
>  		ret = soc_dts_enable(tzd);
> -	else
> +	else if (mode == THERMAL_DEVICE_DISABLED)
>  		ret = soc_dts_disable(tzd);
> +	else
> +		return -EINVAL;
> +
>  	mutex_unlock(&dts_update_mutex);
>  
>  	return ret;
> diff --git a/drivers/thermal/of-thermal.c b/drivers/thermal/of-thermal.c
> index 874a47d6923f..36bebf623980 100644
> --- a/drivers/thermal/of-thermal.c
> +++ b/drivers/thermal/of-thermal.c
> @@ -289,9 +289,11 @@ static int of_thermal_set_mode(struct thermal_zone_device *tz,
>  	if (mode == THERMAL_DEVICE_ENABLED) {
>  		tz->polling_delay = data->polling_delay;
>  		tz->passive_delay = data->passive_delay;
> -	} else {
> +	} else if (mode == THERMAL_DEVICE_DISABLED) {
>  		tz->polling_delay = 0;
>  		tz->passive_delay = 0;
> +	} else {
> +		return -EINVAL;
>  	}
>  
>  	mutex_unlock(&tz->lock);
> 


-- 
<http://www.linaro.org/> Linaro.org │ Open source software for ARM SoCs

Follow Linaro:  <http://www.facebook.com/pages/Linaro> Facebook |
<http://twitter.com/#!/linaroorg> Twitter |
<http://www.linaro.org/linaro-blog/> Blog

^ permalink raw reply	[flat|nested] 63+ messages in thread

* Re: [RFC v2 4/9] thermal: core: Let thermal zone device's mode be stored in its struct
  2020-04-14 18:01     ` [RFC v2 4/9] thermal: core: Let thermal zone device's mode be stored in its struct Andrzej Pietrasiewicz
@ 2020-04-14 22:30       ` Daniel Lezcano
  0 siblings, 0 replies; 63+ messages in thread
From: Daniel Lezcano @ 2020-04-14 22:30 UTC (permalink / raw)
  To: Andrzej Pietrasiewicz, linux-pm
  Cc: Zhang Rui, Rafael J . Wysocki, Len Brown, Jiri Pirko,
	Ido Schimmel, David S . Miller, Peter Kaestle, Darren Hart,
	Andy Shevchenko, Support Opensource, Amit Kucheria, Shawn Guo,
	Sascha Hauer, Pengutronix Kernel Team, Fabio Estevam,
	NXP Linux Team, Allison Randal, Enrico Weigelt, Gayatri Kammela,
	Thomas Gleixner, linux-acpi, netdev, platform-driver-x86,
	linux-arm-kernel, kernel

On 14/04/2020 20:01, Andrzej Pietrasiewicz wrote:
> All the drivers which provide ->get_mode()/->set_mode() methods store their
> mode in a thermal_device_mode enum, so keep this information in struct
> thermal_zone_device rather than scattered all over the place.
> 
> Signed-off-by: Andrzej Pietrasiewicz <andrzej.p@collabora.com>
> ---
>  drivers/thermal/thermal_core.c  | 28 +++++++++++++++++++
>  drivers/thermal/thermal_sysfs.c |  9 +++----
>  include/linux/thermal.h         | 48 +++++++++++++++++++++++++++++++++
>  3 files changed, 79 insertions(+), 6 deletions(-)
> 
> diff --git a/drivers/thermal/thermal_core.c b/drivers/thermal/thermal_core.c
> index 9a321dc548c8..cb0ff47f0dbe 100644
> --- a/drivers/thermal/thermal_core.c
> +++ b/drivers/thermal/thermal_core.c
> @@ -469,6 +469,34 @@ static void thermal_zone_device_reset(struct thermal_zone_device *tz)
>  	thermal_zone_device_init(tz);
>  }
>  
> +int thermal_zone_device_get_mode(struct thermal_zone_device *tz,
> +				 enum thermal_device_mode *mode)
> +{
> +	if (tz->ops->get_mode)
> +		return tz->ops->get_mode(tz, mode);

I think we can get rid of the get_mode here.

locks missing.

and mode = tz->mode must be always set.

> +	*mode = tz->mode;
> +
> +	return 0;
> +}
> +EXPORT_SYMBOL_GPL(thermal_zone_device_get_mode);
> +
> +int thermal_zone_device_set_mode(struct thermal_zone_device *tz,
> +				 enum thermal_device_mode mode)
> +{
> +	if (mode != THERMAL_DEVICE_DISABLED &&
> +	    mode != THERMAL_DEVICE_ENABLED)
> +		return -EINVAL;

I'm not sure this is useful as 'mode' is an enum and this condition will
be always correct.

locks missing.

> +	if (tz->ops->set_mode)
> +		return tz->ops->set_mode(tz, mode);

> +	tz->mode = mode;

It should be like:

	int ret = 0;

	mutex_lock(&tz->lock);

	if (tz->ops->set_mode)
		ret = tz->ops->set_mode(tz, mode);

	*mode = tz->mode;

	mutex_unlock(&tz->lock);

	return ret;

> +
> +	return 0;
> +}
> +EXPORT_SYMBOL_GPL(thermal_zone_device_set_mode);
> +
>  void thermal_zone_device_update(struct thermal_zone_device *tz,
>  				enum thermal_notify_event event)
>  {
> diff --git a/drivers/thermal/thermal_sysfs.c b/drivers/thermal/thermal_sysfs.c
> index aa99edb4dff7..66d9691b8bd6 100644
> --- a/drivers/thermal/thermal_sysfs.c
> +++ b/drivers/thermal/thermal_sysfs.c
> @@ -52,10 +52,7 @@ mode_show(struct device *dev, struct device_attribute *attr, char *buf)
>  	enum thermal_device_mode mode;
>  	int result;
>  
> -	if (!tz->ops->get_mode)
> -		return -EPERM;
> -
> -	result = tz->ops->get_mode(tz, &mode);
> +	result = thermal_zone_device_get_mode(tz, &mode);
>  	if (result)
>  		return result;
>  
> @@ -74,9 +71,9 @@ mode_store(struct device *dev, struct device_attribute *attr,
>  		return -EPERM;
>  
>  	if (!strncmp(buf, "enabled", sizeof("enabled") - 1))
> -		result = tz->ops->set_mode(tz, THERMAL_DEVICE_ENABLED);
> +		result = thermal_zone_device_enable(tz);
>  	else if (!strncmp(buf, "disabled", sizeof("disabled") - 1))
> -		result = tz->ops->set_mode(tz, THERMAL_DEVICE_DISABLED);
> +		result = thermal_zone_device_disable(tz);
>  	else
>  		result = -EINVAL;
>  
> diff --git a/include/linux/thermal.h b/include/linux/thermal.h
> index c91b1e344d56..9ff8542b7e7d 100644
> --- a/include/linux/thermal.h
> +++ b/include/linux/thermal.h
> @@ -143,6 +143,7 @@ struct thermal_attr {
>   * @trip_temp_attrs:	attributes for trip points for sysfs: trip temperature
>   * @trip_type_attrs:	attributes for trip points for sysfs: trip type
>   * @trip_hyst_attrs:	attributes for trip points for sysfs: trip hysteresis
> + * @mode:		current mode of this thermal zone
>   * @devdata:	private pointer for device private data
>   * @trips:	number of trip points the thermal zone supports
>   * @trips_disabled;	bitmap for disabled trips
> @@ -185,6 +186,7 @@ struct thermal_zone_device {
>  	struct thermal_attr *trip_temp_attrs;
>  	struct thermal_attr *trip_type_attrs;
>  	struct thermal_attr *trip_hyst_attrs;
> +	enum thermal_device_mode mode;
>  	void *devdata;
>  	int trips;
>  	unsigned long trips_disabled;	/* bitmap for disabled trips */
> @@ -437,6 +439,19 @@ int thermal_zone_bind_cooling_device(struct thermal_zone_device *, int,
>  				     unsigned int);
>  int thermal_zone_unbind_cooling_device(struct thermal_zone_device *, int,
>  				       struct thermal_cooling_device *);
> +
> +int thermal_zone_device_get_mode(struct thermal_zone_device *tz,
> +				 enum thermal_device_mode *mode);
> +int thermal_zone_device_set_mode(struct thermal_zone_device *tz,
> +				 enum thermal_device_mode mode);
> +
> +static inline void
> +thermal_zone_device_store_mode(struct thermal_zone_device *tz,
> +			       enum thermal_device_mode mode)
> +{
> +	tz->mode = mode;
> +}
> +

Please remove this store_mode function, it is not needed.

Just:

thermal_zone_device_get_mode()
thermal_zone_device_set_mode()
thermal_zone_device_disable()
thermal_zone_device_enable()

And all of them in drivers/thermal/thermal_core.h

>  void thermal_zone_device_update(struct thermal_zone_device *,
>  				enum thermal_notify_event);
>  void thermal_zone_set_trips(struct thermal_zone_device *);
> @@ -494,6 +509,17 @@ static inline int thermal_zone_unbind_cooling_device(
>  	struct thermal_zone_device *tz, int trip,
>  	struct thermal_cooling_device *cdev)
>  { return -ENODEV; }
> +static inline int thermal_zone_device_get_mode(struct thermal_zone_device *tz,
> +					       enum thermal_device_mode *mode)
> +{ return -ENODEV; }
> +static inline int thermal_zone_device_set_mode(struct thermal_zone_device *tz,
> +					       enum thermal_device_mode mode)
> +{ return -ENODEV; }
> +static inline void
> +thermal_zone_device_store_mode(struct thermal_zone_device *tz,
> +			       enum thermal_device_mode mode)
> +{ }
> +
>  static inline void thermal_zone_device_update(struct thermal_zone_device *tz,
>  					      enum thermal_notify_event event)
>  { }
> @@ -543,4 +569,26 @@ static inline void thermal_notify_framework(struct thermal_zone_device *tz,
>  { }
>  #endif /* CONFIG_THERMAL */
>  
> +static inline int thermal_zone_device_enable(struct thermal_zone_device *tz)
> +{
> +	return thermal_zone_device_set_mode(tz, THERMAL_DEVICE_ENABLED);
> +}
> +
> +static inline int thermal_zone_device_disable(struct thermal_zone_device *tz)
> +{
> +	return thermal_zone_device_set_mode(tz, THERMAL_DEVICE_DISABLED);
> +}
> +
> +static inline void
> +thermal_zone_device_store_enabled(struct thermal_zone_device *tz)
> +{
> +	thermal_zone_device_store_mode(tz, THERMAL_DEVICE_ENABLED);
> +}
> +
> +static inline void
> +thermal_zone_device_store_disabled(struct thermal_zone_device *tz)
> +{
> +	thermal_zone_device_store_mode(tz, THERMAL_DEVICE_DISABLED);
> +}
> +
>  #endif /* __THERMAL_H__ */
> 


-- 
<http://www.linaro.org/> Linaro.org │ Open source software for ARM SoCs

Follow Linaro:  <http://www.facebook.com/pages/Linaro> Facebook |
<http://twitter.com/#!/linaroorg> Twitter |
<http://www.linaro.org/linaro-blog/> Blog

^ permalink raw reply	[flat|nested] 63+ messages in thread

* Re: [RFC 1/8] thermal: int3400_thermal: Statically initialize .get_mode()/.set_mode() ops
       [not found]   ` <CGME20200415091204eucas1p1983548c2db52d8d0c2a5367034ec80dd@eucas1p1.samsung.com>
@ 2020-04-15  9:12     ` Bartlomiej Zolnierkiewicz
  0 siblings, 0 replies; 63+ messages in thread
From: Bartlomiej Zolnierkiewicz @ 2020-04-15  9:12 UTC (permalink / raw)
  To: Andrzej Pietrasiewicz
  Cc: linux-pm, Zhang Rui, Rafael J . Wysocki, Len Brown, Jiri Pirko,
	Ido Schimmel, David S . Miller, Peter Kaestle, Darren Hart,
	Andy Shevchenko, Support Opensource, Daniel Lezcano,
	Amit Kucheria, Shawn Guo, Sascha Hauer, Pengutronix Kernel Team,
	Fabio Estevam, NXP Linux Team, Allison Randal, Enrico Weigelt,
	Gayatri Kammela, Thomas Gleixner, linux-acpi, netdev,
	platform-driver-x86, linux-arm-kernel, kernel


On 4/7/20 7:49 PM, Andrzej Pietrasiewicz wrote:
> int3400_thermal_ops is used inside int3400_thermal_probe() only after
> the assignments, which can just as well be made statically at struct's
> initizer.
> 
> Signed-off-by: Andrzej Pietrasiewicz <andrzej.p@collabora.com>

Reviewed-by: Bartlomiej Zolnierkiewicz <b.zolnierkie@samsung.com>

Best regards,
--
Bartlomiej Zolnierkiewicz
Samsung R&D Institute Poland
Samsung Electronics

> ---
>  drivers/thermal/intel/int340x_thermal/int3400_thermal.c | 5 ++---
>  1 file changed, 2 insertions(+), 3 deletions(-)
> 
> diff --git a/drivers/thermal/intel/int340x_thermal/int3400_thermal.c b/drivers/thermal/intel/int340x_thermal/int3400_thermal.c
> index efae0c02d898..634b943e9e3d 100644
> --- a/drivers/thermal/intel/int340x_thermal/int3400_thermal.c
> +++ b/drivers/thermal/intel/int340x_thermal/int3400_thermal.c
> @@ -271,6 +271,8 @@ static int int3400_thermal_set_mode(struct thermal_zone_device *thermal,
>  
>  static struct thermal_zone_device_ops int3400_thermal_ops = {
>  	.get_temp = int3400_thermal_get_temp,
> +	.get_mode = int3400_thermal_get_mode,
> +	.set_mode = int3400_thermal_set_mode,
>  };
>  
>  static struct thermal_zone_params int3400_thermal_params = {
> @@ -309,9 +311,6 @@ static int int3400_thermal_probe(struct platform_device *pdev)
>  
>  	platform_set_drvdata(pdev, priv);
>  
> -	int3400_thermal_ops.get_mode = int3400_thermal_get_mode;
> -	int3400_thermal_ops.set_mode = int3400_thermal_set_mode;
> -
>  	priv->thermal = thermal_zone_device_register("INT3400 Thermal", 0, 0,
>  						priv, &int3400_thermal_ops,
>  						&int3400_thermal_params, 0, 0);
> 

^ permalink raw reply	[flat|nested] 63+ messages in thread

* Re: [RFC v2 1/9] thermal: int3400_thermal: Statically initialize .get_mode()/.set_mode() ops
  2020-04-14 18:00     ` [RFC v2 1/9] thermal: int3400_thermal: Statically initialize .get_mode()/.set_mode() ops Andrzej Pietrasiewicz
@ 2020-04-15  9:23       ` Daniel Lezcano
  0 siblings, 0 replies; 63+ messages in thread
From: Daniel Lezcano @ 2020-04-15  9:23 UTC (permalink / raw)
  To: Andrzej Pietrasiewicz, linux-pm
  Cc: Zhang Rui, Rafael J . Wysocki, Len Brown, Jiri Pirko,
	Ido Schimmel, David S . Miller, Peter Kaestle, Darren Hart,
	Andy Shevchenko, Support Opensource, Amit Kucheria, Shawn Guo,
	Sascha Hauer, Pengutronix Kernel Team, Fabio Estevam,
	NXP Linux Team, Allison Randal, Enrico Weigelt, Gayatri Kammela,
	Thomas Gleixner, linux-acpi, netdev, platform-driver-x86,
	linux-arm-kernel, kernel, Bartlomiej Zolnierkiewicz

On 14/04/2020 20:00, Andrzej Pietrasiewicz wrote:
> int3400_thermal_ops is used inside int3400_thermal_probe() only after
> the assignments, which can just as well be made statically at struct's
> initizer.
> 
> Signed-off-by: Andrzej Pietrasiewicz <andrzej.p@collabora.com>
> ---

Applied this patch with Bartlomiej's tag.

Thanks

  -- Daniel



-- 
<http://www.linaro.org/> Linaro.org │ Open source software for ARM SoCs

Follow Linaro:  <http://www.facebook.com/pages/Linaro> Facebook |
<http://twitter.com/#!/linaroorg> Twitter |
<http://www.linaro.org/linaro-blog/> Blog

^ permalink raw reply	[flat|nested] 63+ messages in thread

* Re: [RFC 2/8] thermal: Properly handle mode values in .set_mode()
       [not found]   ` <CGME20200415100543eucas1p24e24293da39844ca8791db86af5365a7@eucas1p2.samsung.com>
@ 2020-04-15 10:05     ` Bartlomiej Zolnierkiewicz
  0 siblings, 0 replies; 63+ messages in thread
From: Bartlomiej Zolnierkiewicz @ 2020-04-15 10:05 UTC (permalink / raw)
  To: Andrzej Pietrasiewicz
  Cc: linux-pm, Zhang Rui, Rafael J . Wysocki, Len Brown, Jiri Pirko,
	Ido Schimmel, David S . Miller, Peter Kaestle, Darren Hart,
	Andy Shevchenko, Support Opensource, Daniel Lezcano,
	Amit Kucheria, Shawn Guo, Sascha Hauer, Pengutronix Kernel Team,
	Fabio Estevam, NXP Linux Team, Allison Randal, Enrico Weigelt,
	Gayatri Kammela, Thomas Gleixner, linux-acpi, netdev,
	platform-driver-x86, linux-arm-kernel, kernel


On 4/7/20 7:49 PM, Andrzej Pietrasiewicz wrote:
> Allow only THERMAL_DEVICE_ENABLED and THERMAL_DEVICE_DISABLED as valid
> states to transition to.
> 
> Signed-off-by: Andrzej Pietrasiewicz <andrzej.p@collabora.com>
> ---
>  drivers/net/ethernet/mellanox/mlxsw/core_thermal.c | 8 ++++++--
>  drivers/platform/x86/acerhdf.c                     | 4 ++++
>  drivers/thermal/imx_thermal.c                      | 4 +++-
>  drivers/thermal/intel/intel_quark_dts_thermal.c    | 5 ++++-
>  drivers/thermal/of-thermal.c                       | 4 +++-
>  5 files changed, 20 insertions(+), 5 deletions(-)
> 
> diff --git a/drivers/net/ethernet/mellanox/mlxsw/core_thermal.c b/drivers/net/ethernet/mellanox/mlxsw/core_thermal.c
> index ce0a6837daa3..cd435ca7adbe 100644
> --- a/drivers/net/ethernet/mellanox/mlxsw/core_thermal.c
> +++ b/drivers/net/ethernet/mellanox/mlxsw/core_thermal.c
> @@ -296,8 +296,10 @@ static int mlxsw_thermal_set_mode(struct thermal_zone_device *tzdev,
>  
>  	if (mode == THERMAL_DEVICE_ENABLED)
>  		tzdev->polling_delay = thermal->polling_delay;
> -	else
> +	else if (mode == THERMAL_DEVICE_DISABLED)
>  		tzdev->polling_delay = 0;
> +	else
> +		return -EINVAL;

Making sure that the valid parameters are passed to driver specific
->set_mode method should be handled in the higher layer (callers).

Best regards,
--
Bartlomiej Zolnierkiewicz
Samsung R&D Institute Poland
Samsung Electronics
 
>  	mutex_unlock(&tzdev->lock);
>  
> @@ -486,8 +488,10 @@ static int mlxsw_thermal_module_mode_set(struct thermal_zone_device *tzdev,
>  
>  	if (mode == THERMAL_DEVICE_ENABLED)
>  		tzdev->polling_delay = thermal->polling_delay;
> -	else
> +	else if (mode == THERMAL_DEVICE_DISABLED)
>  		tzdev->polling_delay = 0;
> +	else
> +		return -EINVAL;
>  
>  	mutex_unlock(&tzdev->lock);
>  
> diff --git a/drivers/platform/x86/acerhdf.c b/drivers/platform/x86/acerhdf.c
> index 8cc86f4e3ac1..d5188c1d688b 100644
> --- a/drivers/platform/x86/acerhdf.c
> +++ b/drivers/platform/x86/acerhdf.c
> @@ -431,6 +431,10 @@ static int acerhdf_get_mode(struct thermal_zone_device *thermal,
>  static int acerhdf_set_mode(struct thermal_zone_device *thermal,
>  			    enum thermal_device_mode mode)
>  {
> +	if (mode != THERMAL_DEVICE_DISABLED &&
> +	    mode != THERMAL_DEVICE_ENABLED)
> +		return -EINVAL;
> +
>  	if (mode == THERMAL_DEVICE_DISABLED && kernelmode)
>  		acerhdf_revert_to_bios_mode();
>  	else if (mode == THERMAL_DEVICE_ENABLED && !kernelmode)
> diff --git a/drivers/thermal/imx_thermal.c b/drivers/thermal/imx_thermal.c
> index bb6754a5342c..014512581918 100644
> --- a/drivers/thermal/imx_thermal.c
> +++ b/drivers/thermal/imx_thermal.c
> @@ -368,7 +368,7 @@ static int imx_set_mode(struct thermal_zone_device *tz,
>  			data->irq_enabled = true;
>  			enable_irq(data->irq);
>  		}
> -	} else {
> +	} else if (mode == THERMAL_DEVICE_DISABLED) {
>  		regmap_write(map, soc_data->sensor_ctrl + REG_CLR,
>  			     soc_data->measure_temp_mask);
>  		regmap_write(map, soc_data->sensor_ctrl + REG_SET,
> @@ -381,6 +381,8 @@ static int imx_set_mode(struct thermal_zone_device *tz,
>  			disable_irq(data->irq);
>  			data->irq_enabled = false;
>  		}
> +	} else {
> +		return -EINVAL;
>  	}
>  
>  	data->mode = mode;
> diff --git a/drivers/thermal/intel/intel_quark_dts_thermal.c b/drivers/thermal/intel/intel_quark_dts_thermal.c
> index 5d33b350da1c..5f4bcc0e4fd3 100644
> --- a/drivers/thermal/intel/intel_quark_dts_thermal.c
> +++ b/drivers/thermal/intel/intel_quark_dts_thermal.c
> @@ -328,8 +328,11 @@ static int sys_set_mode(struct thermal_zone_device *tzd,
>  	mutex_lock(&dts_update_mutex);
>  	if (mode == THERMAL_DEVICE_ENABLED)
>  		ret = soc_dts_enable(tzd);
> -	else
> +	else if (mode == THERMAL_DEVICE_DISABLED)
>  		ret = soc_dts_disable(tzd);
> +	else
> +		return -EINVAL;
> +
>  	mutex_unlock(&dts_update_mutex);
>  
>  	return ret;
> diff --git a/drivers/thermal/of-thermal.c b/drivers/thermal/of-thermal.c
> index ef0baa954ff0..b7621dfab17c 100644
> --- a/drivers/thermal/of-thermal.c
> +++ b/drivers/thermal/of-thermal.c
> @@ -289,9 +289,11 @@ static int of_thermal_set_mode(struct thermal_zone_device *tz,
>  	if (mode == THERMAL_DEVICE_ENABLED) {
>  		tz->polling_delay = data->polling_delay;
>  		tz->passive_delay = data->passive_delay;
> -	} else {
> +	} else if (mode == THERMAL_DEVICE_DISABLED) {
>  		tz->polling_delay = 0;
>  		tz->passive_delay = 0;
> +	} else {
> +		return -EINVAL;
>  	}
>  
>  	mutex_unlock(&tz->lock);
> 

^ permalink raw reply	[flat|nested] 63+ messages in thread

* Re: [RFC 3/8] thermal: Store thermal mode in a dedicated enum
       [not found]   ` <CGME20200415100944eucas1p1dcfeb784e790ca2fc3417fd2797e3f5d@eucas1p1.samsung.com>
@ 2020-04-15 10:09     ` Bartlomiej Zolnierkiewicz
  0 siblings, 0 replies; 63+ messages in thread
From: Bartlomiej Zolnierkiewicz @ 2020-04-15 10:09 UTC (permalink / raw)
  To: Andrzej Pietrasiewicz
  Cc: linux-pm, Zhang Rui, Rafael J . Wysocki, Len Brown, Jiri Pirko,
	Ido Schimmel, David S . Miller, Peter Kaestle, Darren Hart,
	Andy Shevchenko, Support Opensource, Daniel Lezcano,
	Amit Kucheria, Shawn Guo, Sascha Hauer, Pengutronix Kernel Team,
	Fabio Estevam, NXP Linux Team, Allison Randal, Enrico Weigelt,
	Gayatri Kammela, Thomas Gleixner, linux-acpi, netdev,
	platform-driver-x86, linux-arm-kernel, kernel


On 4/7/20 7:49 PM, Andrzej Pietrasiewicz wrote:
> Prepare for adding THERMAL_DEVICE_INITIAL mode.
> 
> Signed-off-by: Andrzej Pietrasiewicz <andrzej.p@collabora.com>
> ---
>  drivers/acpi/thermal.c                        | 27 +++++++++----------
>  drivers/platform/x86/acerhdf.c                | 12 ++++++---
>  .../intel/int340x_thermal/int3400_thermal.c   | 18 +++++--------
>  3 files changed, 27 insertions(+), 30 deletions(-)
> 
> diff --git a/drivers/acpi/thermal.c b/drivers/acpi/thermal.c
> index 19067a5e5293..a93b0412dd6b 100644
> --- a/drivers/acpi/thermal.c
> +++ b/drivers/acpi/thermal.c
> @@ -172,7 +172,7 @@ struct acpi_thermal {
>  	struct acpi_thermal_trips trips;
>  	struct acpi_handle_list devices;
>  	struct thermal_zone_device *thermal_zone;
> -	int tz_enabled;
> +	enum thermal_device_mode mode;
>  	int kelvin_offset;	/* in millidegrees */
>  	struct work_struct thermal_check_work;
>  };
> @@ -500,7 +500,7 @@ static void acpi_thermal_check(void *data)
>  {
>  	struct acpi_thermal *tz = data;
>  
> -	if (!tz->tz_enabled)
> +	if (tz->mode != THERMAL_DEVICE_ENABLED)
>  		return;
>  
>  	thermal_zone_device_update(tz->thermal_zone,
> @@ -534,8 +534,7 @@ static int thermal_get_mode(struct thermal_zone_device *thermal,
>  	if (!tz)
>  		return -EINVAL;
>  
> -	*mode = tz->tz_enabled ? THERMAL_DEVICE_ENABLED :
> -		THERMAL_DEVICE_DISABLED;
> +	*mode = tz->mode;
>  
>  	return 0;
>  }
> @@ -544,27 +543,25 @@ static int thermal_set_mode(struct thermal_zone_device *thermal,
>  				enum thermal_device_mode mode)
>  {
>  	struct acpi_thermal *tz = thermal->devdata;
> -	int enable;
>  
>  	if (!tz)
>  		return -EINVAL;
>  
> +	if (mode != THERMAL_DEVICE_DISABLED &&
> +	    mode != THERMAL_DEVICE_ENABLED)
> +		return -EINVAL;
>  	/*
>  	 * enable/disable thermal management from ACPI thermal driver
>  	 */
> -	if (mode == THERMAL_DEVICE_ENABLED)
> -		enable = 1;
> -	else if (mode == THERMAL_DEVICE_DISABLED) {
> -		enable = 0;
> +	if (mode == THERMAL_DEVICE_DISABLED)
>  		pr_warn("thermal zone will be disabled\n");
> -	} else
> -		return -EINVAL;
>  
> -	if (enable != tz->tz_enabled) {
> -		tz->tz_enabled = enable;
> +	if (mode != tz->mode) {
> +		tz->mode = mode;
>  		ACPI_DEBUG_PRINT((ACPI_DB_INFO,
>  			"%s kernel ACPI thermal control\n",
> -			tz->tz_enabled ? "Enable" : "Disable"));
> +			tz->mode == THERMAL_DEVICE_ENABLED ?
> +			"Enable" : "Disable"));
>  		acpi_thermal_check(tz);
>  	}
>  	return 0;
> @@ -913,7 +910,7 @@ static int acpi_thermal_register_thermal_zone(struct acpi_thermal *tz)
>  	if (ACPI_FAILURE(status))
>  		return -ENODEV;
>  
> -	tz->tz_enabled = 1;
> +	tz->mode = THERMAL_DEVICE_ENABLED;
>  
>  	dev_info(&tz->device->dev, "registered as thermal_zone%d\n",
>  		 tz->thermal_zone->id);
> diff --git a/drivers/platform/x86/acerhdf.c b/drivers/platform/x86/acerhdf.c
> index d5188c1d688b..87e357017d4a 100644
> --- a/drivers/platform/x86/acerhdf.c
> +++ b/drivers/platform/x86/acerhdf.c
> @@ -65,8 +65,10 @@
>  
>  #ifdef START_IN_KERNEL_MODE
>  static int kernelmode = 1;
> +static enum thermal_device_mode thermal_mode = THERMAL_DEVICE_ENABLED;
>  #else
>  static int kernelmode;
> +static enum thermal_device_mode thermal_mode = THERMAL_DEVICE_DISABLED;
>  #endif
>  
>  static unsigned int interval = 10;
> @@ -416,8 +418,7 @@ static int acerhdf_get_mode(struct thermal_zone_device *thermal,
>  	if (verbose)
>  		pr_notice("kernel mode fan control %d\n", kernelmode);
>  
> -	*mode = (kernelmode) ? THERMAL_DEVICE_ENABLED
> -			     : THERMAL_DEVICE_DISABLED;
> +	*mode = thermal_mode;
>  
>  	return 0;
>  }
> @@ -435,10 +436,13 @@ static int acerhdf_set_mode(struct thermal_zone_device *thermal,
>  	    mode != THERMAL_DEVICE_ENABLED)
>  		return -EINVAL;
>  
> -	if (mode == THERMAL_DEVICE_DISABLED && kernelmode)
> +	if (mode == THERMAL_DEVICE_DISABLED && kernelmode) {
>  		acerhdf_revert_to_bios_mode();
> -	else if (mode == THERMAL_DEVICE_ENABLED && !kernelmode)
> +		thermal_mode = THERMAL_DEVICE_DISABLED;
> +	} else if (mode == THERMAL_DEVICE_ENABLED && !kernelmode) {
>  		acerhdf_enable_kernelmode();
> +		thermal_mode = THERMAL_DEVICE_ENABLED;
> +	}
>  
>  	return 0;
>  }

The conversion missed:

* handling of "force_bios" and force_product" kernel parameters:

	if (force_bios[0]) {
		version = force_bios;
		pr_info("forcing BIOS version: %s\n", version);
		kernelmode = 0;
	}

	if (force_product[0]) {
		product = force_product;
		pr_info("forcing BIOS product: %s\n", product);
		kernelmode = 0;
	}

* acerhdf_revert_to_bios_mode() call on error in acerhdf_set_cur_state()

Best regards,
--
Bartlomiej Zolnierkiewicz
Samsung R&D Institute Poland
Samsung Electronics

> diff --git a/drivers/thermal/intel/int340x_thermal/int3400_thermal.c b/drivers/thermal/intel/int340x_thermal/int3400_thermal.c
> index 634b943e9e3d..fcbd1b14fa74 100644
> --- a/drivers/thermal/intel/int340x_thermal/int3400_thermal.c
> +++ b/drivers/thermal/intel/int340x_thermal/int3400_thermal.c
> @@ -44,7 +44,7 @@ static char *int3400_thermal_uuids[INT3400_THERMAL_MAXIMUM_UUID] = {
>  struct int3400_thermal_priv {
>  	struct acpi_device *adev;
>  	struct thermal_zone_device *thermal;
> -	int mode;
> +	enum thermal_device_mode mode;
>  	int art_count;
>  	struct art *arts;
>  	int trt_count;
> @@ -247,24 +247,20 @@ static int int3400_thermal_set_mode(struct thermal_zone_device *thermal,
>  				enum thermal_device_mode mode)
>  {
>  	struct int3400_thermal_priv *priv = thermal->devdata;
> -	bool enable;
>  	int result = 0;
>  
>  	if (!priv)
>  		return -EINVAL;
>  
> -	if (mode == THERMAL_DEVICE_ENABLED)
> -		enable = true;
> -	else if (mode == THERMAL_DEVICE_DISABLED)
> -		enable = false;
> -	else
> +	if (mode != THERMAL_DEVICE_ENABLED &&
> +	    mode != THERMAL_DEVICE_DISABLED)
>  		return -EINVAL;
>  
> -	if (enable != priv->mode) {
> -		priv->mode = enable;
> +	if (mode != priv->mode) {
> +		priv->mode = mode;
>  		result = int3400_thermal_run_osc(priv->adev->handle,
> -						 priv->current_uuid_index,
> -						 enable);
> +						priv->current_uuid_index,
> +						mode == THERMAL_DEVICE_ENABLED);
>  	}
>  	return result;
>  }
> 


^ permalink raw reply	[flat|nested] 63+ messages in thread

* Re: [RFC 7/8] thermal: of: Monitor thermal zone after enabling it
       [not found]   ` <CGME20200415101829eucas1p18e21324d3c39926fffc6c8b5dc52f206@eucas1p1.samsung.com>
@ 2020-04-15 10:18     ` Bartlomiej Zolnierkiewicz
  0 siblings, 0 replies; 63+ messages in thread
From: Bartlomiej Zolnierkiewicz @ 2020-04-15 10:18 UTC (permalink / raw)
  To: Andrzej Pietrasiewicz
  Cc: linux-pm, Zhang Rui, Rafael J . Wysocki, Len Brown, Jiri Pirko,
	Ido Schimmel, David S . Miller, Peter Kaestle, Darren Hart,
	Andy Shevchenko, Support Opensource, Daniel Lezcano,
	Amit Kucheria, Shawn Guo, Sascha Hauer, Pengutronix Kernel Team,
	Fabio Estevam, NXP Linux Team, Allison Randal, Enrico Weigelt,
	Gayatri Kammela, Thomas Gleixner, linux-acpi, netdev,
	platform-driver-x86, linux-arm-kernel, kernel


On 4/7/20 7:49 PM, Andrzej Pietrasiewicz wrote:
> thermal/of calls its own ->set_mode() method, so monitor thermal zone
> afterwards. This is needed for the DISABLED->ENABLED transition.
> 
> Signed-off-by: Andrzej Pietrasiewicz <andrzej.p@collabora.com>
> ---
>  drivers/thermal/of-thermal.c | 5 ++++-
>  1 file changed, 4 insertions(+), 1 deletion(-)
> 
> diff --git a/drivers/thermal/of-thermal.c b/drivers/thermal/of-thermal.c
> index b7621dfab17c..cf2c43ebcb78 100644
> --- a/drivers/thermal/of-thermal.c
> +++ b/drivers/thermal/of-thermal.c
> @@ -523,8 +523,11 @@ thermal_zone_of_sensor_register(struct device *dev, int sensor_id, void *data,
>  		if (sensor_specs.np == sensor_np && id == sensor_id) {
>  			tzd = thermal_zone_of_add_sensor(child, sensor_np,
>  							 data, ops);
> -			if (!IS_ERR(tzd))
> +			if (!IS_ERR(tzd)) {
>  				tzd->ops->set_mode(tzd, THERMAL_DEVICE_ENABLED);
> +				thermal_zone_device_update(tzd,
> +						THERMAL_EVENT_UNSPECIFIED);
> +			}
>  
>  			of_node_put(sensor_specs.np);
>  			of_node_put(child);
> 

This patch is bogus/redundant, please look at ->set_mode implementation for
thermal/of drivers:

static int of_thermal_set_mode(struct thermal_zone_device *tz,
			       enum thermal_device_mode mode)
{
	struct __thermal_zone *data = tz->devdata;

	mutex_lock(&tz->lock);

	if (mode == THERMAL_DEVICE_ENABLED) {
		tz->polling_delay = data->polling_delay;
		tz->passive_delay = data->passive_delay;
	} else {
		tz->polling_delay = 0;
		tz->passive_delay = 0;
	}

	mutex_unlock(&tz->lock);

	data->mode = mode;
	thermal_zone_device_update(tz, THERMAL_EVENT_UNSPECIFIED);

	return 0;
}

Best regards,
--
Bartlomiej Zolnierkiewicz
Samsung R&D Institute Poland
Samsung Electronics

^ permalink raw reply	[flat|nested] 63+ messages in thread

* Re: [RFC 0/8] Stop monitoring disabled devices
       [not found]     ` <CGME20200415104010eucas1p101278e53e34a2e56dfc7c82b533a9122@eucas1p1.samsung.com>
@ 2020-04-15 10:40       ` Bartlomiej Zolnierkiewicz
  2020-04-17 16:23         ` Andrzej Pietrasiewicz
  2020-04-17 21:11         ` Peter Kästle
  0 siblings, 2 replies; 63+ messages in thread
From: Bartlomiej Zolnierkiewicz @ 2020-04-15 10:40 UTC (permalink / raw)
  To: Andrzej Pietrasiewicz
  Cc: Daniel Lezcano, linux-pm, Zhang Rui, Rafael J . Wysocki,
	Len Brown, Jiri Pirko, Ido Schimmel, David S . Miller,
	Peter Kaestle, Darren Hart, Andy Shevchenko, Support Opensource,
	Amit Kucheria, Shawn Guo, Sascha Hauer, Pengutronix Kernel Team,
	Fabio Estevam, NXP Linux Team, Allison Randal, Enrico Weigelt,
	Gayatri Kammela, Thomas Gleixner, linux-acpi, netdev,
	platform-driver-x86, linux-arm-kernel, kernel


On 4/9/20 1:10 PM, Andrzej Pietrasiewicz wrote:
> Hi Daniel,
> 
> W dniu 09.04.2020 o 12:29, Daniel Lezcano pisze:
>> On 07/04/2020 19:49, Andrzej Pietrasiewicz wrote:
>>> The current kernel behavior is to keep polling the thermal zone devices
>>> regardless of their current mode. This is not desired, as all such "disabled"
>>> devices are meant to be handled by userspace,> so polling them makes no sense.
>>
>> Thanks for proposing these changes.
>>
>> I've been (quickly) through the series and the description below. I have
>> the feeling the series makes more complex while the current code which
>> would deserve a cleanup.
>>
>> Why not first:
>>
>>   - Add a 'mode' field in the thermal zone device
>>   - Kill all set/get_mode callbacks in the drivers which are duplicated code.
>>   - Add a function:
>>
>>   enum thermal_device_mode thermal_zone_get_mode( *tz)
>>   {
>>     ...
>>     if (tz->ops->get_mode)
>>         return tz->ops->get_mode();
>>
>>     return tz->mode;
>>   }
>>
>>
>>   int thermal_zone_set_mode(..*tz, enum thermal_device_mode mode)
>>   {
>>     ...
>>     if (tz->ops->set_mode)
>>         return tz->ops->set_mode(tz, mode);
>>
>>     tz->mode = mode;
>>
>>     return 0;
>>   }
>>
>>   static inline thermal_zone_enable(... *tz)
>>   {
>>     thermal_zone_set_mode(tz, THERMAL_DEVICE_ENABLED);
>>   }
>>
>>   static inline thermal_zone_disable(... *tz) {
>>     thermal_zone_set_mode(tz, THERMAL_DEVICE_DISABLED);
>>   }
>>
>> And then when the code is consolidated, use the mode to enable/disable
>> the polling and continue killing the duplicated code in of-thermal.c and
>> anywhere else.
>>
>>
> 
> Thanks for feedback.
> 
> Anyone else?

Yes. :)

Please take a look at the following patchset (which I'm reviving currently):

	https://lkml.org/lkml/2018/10/17/926

It overlaps partially with your work so we need to coordinate our efforts.

Best regards,
--
Bartlomiej Zolnierkiewicz
Samsung R&D Institute Poland
Samsung Electronics

^ permalink raw reply	[flat|nested] 63+ messages in thread

* Re: [RFC v2 5/9] thermal: Store mode in thermal_zone_device
  2020-04-14 18:01     ` [RFC v2 5/9] thermal: Store mode in thermal_zone_device Andrzej Pietrasiewicz
@ 2020-04-15 10:55       ` Daniel Lezcano
  2020-04-17 16:20         ` [RFC v3 0/2] Stop monitoring disabled devices Andrzej Pietrasiewicz
  0 siblings, 1 reply; 63+ messages in thread
From: Daniel Lezcano @ 2020-04-15 10:55 UTC (permalink / raw)
  To: Andrzej Pietrasiewicz, linux-pm
  Cc: Zhang Rui, Rafael J . Wysocki, Len Brown, Jiri Pirko,
	Ido Schimmel, David S . Miller, Peter Kaestle, Darren Hart,
	Andy Shevchenko, Support Opensource, Amit Kucheria, Shawn Guo,
	Sascha Hauer, Pengutronix Kernel Team, Fabio Estevam,
	NXP Linux Team, Allison Randal, Enrico Weigelt, Gayatri Kammela,
	Thomas Gleixner, linux-acpi, netdev, platform-driver-x86,
	linux-arm-kernel, kernel, Bartlomiej Zolnierkiewicz

On 14/04/2020 20:01, Andrzej Pietrasiewicz wrote:
> struct thermal_zone_device has a "mode" member now, so use it.
> 
> Signed-off-by: Andrzej Pietrasiewicz <andrzej.p@collabora.com>

At this point, I suggest to not go further with the changes from patch
5-9 but add a new 'mode' field in the struct thermal_zone_params.

And then in the function thermal_zone_device_register()

 {
	...
	if (tzp)
		thermal_zone_set_mode(tzp->mode);
	...
 }

The important thing is to prevent exporting the functions
thermal_zone_device_enable / disable, so they stay in the thermal
framework internals, thus forcing to centralize the control of the
thermal zones from the framework and not from the device drivers.

Temporarly, until the polling is disabled for disabled thermal zones,
the acpi driver can stay in the state it is. It may need special
attention afterwards.

But I believe setting the mode from the register function will help to
clean up a lot of drivers.

> ---
>  drivers/acpi/thermal.c                        | 48 +++++++++----------
>  .../ethernet/mellanox/mlxsw/core_thermal.c    | 35 ++------------
>  drivers/platform/x86/acerhdf.c                | 24 ++++------
>  drivers/thermal/da9062-thermal.c              | 12 +----
>  drivers/thermal/imx_thermal.c                 | 30 +++++-------
>  .../intel/int340x_thermal/int3400_thermal.c   | 34 +++++--------
>  .../thermal/intel/intel_quark_dts_thermal.c   | 22 +++------
>  drivers/thermal/of-thermal.c                  | 19 ++------
>  8 files changed, 71 insertions(+), 153 deletions(-)
> 
> diff --git a/drivers/acpi/thermal.c b/drivers/acpi/thermal.c
> index 328b479ce7f6..755f12b76c20 100644
> --- a/drivers/acpi/thermal.c
> +++ b/drivers/acpi/thermal.c
> @@ -172,7 +172,6 @@ struct acpi_thermal {
>  	struct acpi_thermal_trips trips;
>  	struct acpi_handle_list devices;
>  	struct thermal_zone_device *thermal_zone;
> -	int tz_enabled;
>  	int kelvin_offset;	/* in millidegrees */
>  	struct work_struct thermal_check_work;
>  };
> @@ -499,8 +498,14 @@ static int acpi_thermal_get_trip_points(struct acpi_thermal *tz)
>  static void acpi_thermal_check(void *data)
>  {
>  	struct acpi_thermal *tz = data;
> +	enum thermal_device_mode mode;
>  
> -	if (!tz->tz_enabled)
> +	/*
> +	 * this driver does not provide ->get_mode(), so calling
> +	 * thermal_zone_device_get_mode() always succeeds
> +	 */
> +	thermal_zone_device_get_mode(tz->thermal_zone, &mode);
> +	if (mode != THERMAL_DEVICE_ENABLED)
>  		return;
>  
>  	thermal_zone_device_update(tz->thermal_zone,
> @@ -526,39 +531,33 @@ static int thermal_get_temp(struct thermal_zone_device *thermal, int *temp)
>  	return 0;
>  }
>  
> -static int thermal_get_mode(struct thermal_zone_device *thermal,
> -				enum thermal_device_mode *mode)
> -{
> -	struct acpi_thermal *tz = thermal->devdata;
> -
> -	*mode = tz->tz_enabled ? THERMAL_DEVICE_ENABLED :
> -		THERMAL_DEVICE_DISABLED;
> -
> -	return 0;
> -}
> -
>  static int thermal_set_mode(struct thermal_zone_device *thermal,
>  				enum thermal_device_mode mode)
>  {
>  	struct acpi_thermal *tz = thermal->devdata;
> -	int enable;
> +	enum thermal_device_mode old_mode;
>  
> +	if (mode != THERMAL_DEVICE_DISABLED &&
> +	    mode != THERMAL_DEVICE_ENABLED)
> +		return -EINVAL;
>  	/*
>  	 * enable/disable thermal management from ACPI thermal driver
>  	 */
> -	if (mode == THERMAL_DEVICE_ENABLED)
> -		enable = 1;
> -	else if (mode == THERMAL_DEVICE_DISABLED) {
> -		enable = 0;
> +	if (mode == THERMAL_DEVICE_DISABLED)
>  		pr_warn("thermal zone will be disabled\n");
> -	} else
> -		return -EINVAL;
>  
> -	if (enable != tz->tz_enabled) {
> -		tz->tz_enabled = enable;
> +	/*
> +	 * this driver does not provide ->get_mode(), so calling
> +	 * thermal_zone_device_get_mode() always succeeds
> +	 */
> +	thermal_zone_device_get_mode(thermal, &old_mode);
> +
> +	if (mode != old_mode) {
> +		thermal_zone_device_store_mode(thermal, mode);
>  		ACPI_DEBUG_PRINT((ACPI_DB_INFO,
>  			"%s kernel ACPI thermal control\n",
> -			tz->tz_enabled ? "Enable" : "Disable"));
> +			mode == THERMAL_DEVICE_ENABLED ?
> +			"Enable" : "Disable"));
>  		acpi_thermal_check(tz);
>  	}
>  	return 0;
> @@ -850,7 +849,6 @@ static struct thermal_zone_device_ops acpi_thermal_zone_ops = {
>  	.bind = acpi_thermal_bind_cooling_device,
>  	.unbind	= acpi_thermal_unbind_cooling_device,
>  	.get_temp = thermal_get_temp,
> -	.get_mode = thermal_get_mode,
>  	.set_mode = thermal_set_mode,
>  	.get_trip_type = thermal_get_trip_type,
>  	.get_trip_temp = thermal_get_trip_temp,
> @@ -907,7 +905,7 @@ static int acpi_thermal_register_thermal_zone(struct acpi_thermal *tz)
>  	if (ACPI_FAILURE(status))
>  		return -ENODEV;
>  
> -	tz->tz_enabled = 1;
> +	thermal_zone_device_store_enabled(tz->thermal_zone);
>  
>  	dev_info(&tz->device->dev, "registered as thermal_zone%d\n",
>  		 tz->thermal_zone->id);
> diff --git a/drivers/net/ethernet/mellanox/mlxsw/core_thermal.c b/drivers/net/ethernet/mellanox/mlxsw/core_thermal.c
> index cd435ca7adbe..c4239b2ba16d 100644
> --- a/drivers/net/ethernet/mellanox/mlxsw/core_thermal.c
> +++ b/drivers/net/ethernet/mellanox/mlxsw/core_thermal.c
> @@ -98,7 +98,6 @@ struct mlxsw_thermal_module {
>  	struct mlxsw_thermal *parent;
>  	struct thermal_zone_device *tzdev;
>  	struct mlxsw_thermal_trip trips[MLXSW_THERMAL_NUM_TRIPS];
> -	enum thermal_device_mode mode;
>  	int module; /* Module or gearbox number */
>  };
>  
> @@ -110,7 +109,6 @@ struct mlxsw_thermal {
>  	struct thermal_cooling_device *cdevs[MLXSW_MFCR_PWMS_MAX];
>  	u8 cooling_levels[MLXSW_THERMAL_MAX_STATE + 1];
>  	struct mlxsw_thermal_trip trips[MLXSW_THERMAL_NUM_TRIPS];
> -	enum thermal_device_mode mode;
>  	struct mlxsw_thermal_module *tz_module_arr;
>  	u8 tz_module_num;
>  	struct mlxsw_thermal_module *tz_gearbox_arr;
> @@ -277,16 +275,6 @@ static int mlxsw_thermal_unbind(struct thermal_zone_device *tzdev,
>  	return 0;
>  }
>  
> -static int mlxsw_thermal_get_mode(struct thermal_zone_device *tzdev,
> -				  enum thermal_device_mode *mode)
> -{
> -	struct mlxsw_thermal *thermal = tzdev->devdata;
> -
> -	*mode = thermal->mode;
> -
> -	return 0;
> -}
> -
>  static int mlxsw_thermal_set_mode(struct thermal_zone_device *tzdev,
>  				  enum thermal_device_mode mode)
>  {
> @@ -303,7 +291,7 @@ static int mlxsw_thermal_set_mode(struct thermal_zone_device *tzdev,
>  
>  	mutex_unlock(&tzdev->lock);
>  
> -	thermal->mode = mode;
> +	thermal_zone_device_store_mode(tzdev, mode);
>  	thermal_zone_device_update(tzdev, THERMAL_EVENT_UNSPECIFIED);
>  
>  	return 0;
> @@ -409,7 +397,6 @@ static int mlxsw_thermal_trend_get(struct thermal_zone_device *tzdev,
>  static struct thermal_zone_device_ops mlxsw_thermal_ops = {
>  	.bind = mlxsw_thermal_bind,
>  	.unbind = mlxsw_thermal_unbind,
> -	.get_mode = mlxsw_thermal_get_mode,
>  	.set_mode = mlxsw_thermal_set_mode,
>  	.get_temp = mlxsw_thermal_get_temp,
>  	.get_trip_type	= mlxsw_thermal_get_trip_type,
> @@ -468,16 +455,6 @@ static int mlxsw_thermal_module_unbind(struct thermal_zone_device *tzdev,
>  	return err;
>  }
>  
> -static int mlxsw_thermal_module_mode_get(struct thermal_zone_device *tzdev,
> -					 enum thermal_device_mode *mode)
> -{
> -	struct mlxsw_thermal_module *tz = tzdev->devdata;
> -
> -	*mode = tz->mode;
> -
> -	return 0;
> -}
> -
>  static int mlxsw_thermal_module_mode_set(struct thermal_zone_device *tzdev,
>  					 enum thermal_device_mode mode)
>  {
> @@ -495,7 +472,7 @@ static int mlxsw_thermal_module_mode_set(struct thermal_zone_device *tzdev,
>  
>  	mutex_unlock(&tzdev->lock);
>  
> -	tz->mode = mode;
> +	thermal_zone_device_store_mode(tzdev, mode);
>  	thermal_zone_device_update(tzdev, THERMAL_EVENT_UNSPECIFIED);
>  
>  	return 0;
> @@ -600,7 +577,6 @@ mlxsw_thermal_module_trip_hyst_set(struct thermal_zone_device *tzdev, int trip,
>  static struct thermal_zone_device_ops mlxsw_thermal_module_ops = {
>  	.bind		= mlxsw_thermal_module_bind,
>  	.unbind		= mlxsw_thermal_module_unbind,
> -	.get_mode	= mlxsw_thermal_module_mode_get,
>  	.set_mode	= mlxsw_thermal_module_mode_set,
>  	.get_temp	= mlxsw_thermal_module_temp_get,
>  	.get_trip_type	= mlxsw_thermal_module_trip_type_get,
> @@ -639,7 +615,6 @@ static int mlxsw_thermal_gearbox_temp_get(struct thermal_zone_device *tzdev,
>  static struct thermal_zone_device_ops mlxsw_thermal_gearbox_ops = {
>  	.bind		= mlxsw_thermal_module_bind,
>  	.unbind		= mlxsw_thermal_module_unbind,
> -	.get_mode	= mlxsw_thermal_module_mode_get,
>  	.set_mode	= mlxsw_thermal_module_mode_set,
>  	.get_temp	= mlxsw_thermal_gearbox_temp_get,
>  	.get_trip_type	= mlxsw_thermal_module_trip_type_get,
> @@ -769,7 +744,7 @@ mlxsw_thermal_module_tz_init(struct mlxsw_thermal_module *module_tz)
>  		return err;
>  	}
>  
> -	module_tz->mode = THERMAL_DEVICE_ENABLED;
> +	thermal_zone_device_store_enabled(module_tz->tzdev);
>  	return 0;
>  }
>  
> @@ -885,7 +860,7 @@ mlxsw_thermal_gearbox_tz_init(struct mlxsw_thermal_module *gearbox_tz)
>  	if (IS_ERR(gearbox_tz->tzdev))
>  		return PTR_ERR(gearbox_tz->tzdev);
>  
> -	gearbox_tz->mode = THERMAL_DEVICE_ENABLED;
> +	thermal_zone_device_store_enabled(gearbox_tz->tzdev);
>  	return 0;
>  }
>  
> @@ -1054,7 +1029,7 @@ int mlxsw_thermal_init(struct mlxsw_core *core,
>  	if (err)
>  		goto err_unreg_modules_tzdev;
>  
> -	thermal->mode = THERMAL_DEVICE_ENABLED;
> +	thermal_zone_device_store_enabled(thermal->tzdev);
>  	*p_thermal = thermal;
>  	return 0;
>  
> diff --git a/drivers/platform/x86/acerhdf.c b/drivers/platform/x86/acerhdf.c
> index d5188c1d688b..e5a6abdf62ca 100644
> --- a/drivers/platform/x86/acerhdf.c
> +++ b/drivers/platform/x86/acerhdf.c
> @@ -65,8 +65,10 @@
>  
>  #ifdef START_IN_KERNEL_MODE
>  static int kernelmode = 1;
> +#define ACERHDF_DEFAULT_MODE THERMAL_DEVICE_ENABLED
>  #else
>  static int kernelmode;
> +#define ACERHDF_DEFAULT_MODE THERMAL_DEVICE_DISABLED
>  #endif
>  
>  static unsigned int interval = 10;
> @@ -410,18 +412,6 @@ static inline void acerhdf_enable_kernelmode(void)
>  	pr_notice("kernel mode fan control ON\n");
>  }
>  
> -static int acerhdf_get_mode(struct thermal_zone_device *thermal,
> -			    enum thermal_device_mode *mode)
> -{
> -	if (verbose)
> -		pr_notice("kernel mode fan control %d\n", kernelmode);
> -
> -	*mode = (kernelmode) ? THERMAL_DEVICE_ENABLED
> -			     : THERMAL_DEVICE_DISABLED;
> -
> -	return 0;
> -}
> -
>  /*
>   * set operation mode;
>   * enabled: the thermal layer of the kernel takes care about
> @@ -435,10 +425,13 @@ static int acerhdf_set_mode(struct thermal_zone_device *thermal,
>  	    mode != THERMAL_DEVICE_ENABLED)
>  		return -EINVAL;
>  
> -	if (mode == THERMAL_DEVICE_DISABLED && kernelmode)
> +	if (mode == THERMAL_DEVICE_DISABLED && kernelmode) {
>  		acerhdf_revert_to_bios_mode();
> -	else if (mode == THERMAL_DEVICE_ENABLED && !kernelmode)
> +		thermal_zone_device_store_enabled(thermal);
> +	} else if (mode == THERMAL_DEVICE_ENABLED && !kernelmode) {
>  		acerhdf_enable_kernelmode();
> +		thermal_zone_device_store_disabled(thermal);
> +	}
>  
>  	return 0;
>  }
> @@ -492,7 +485,6 @@ static struct thermal_zone_device_ops acerhdf_dev_ops = {
>  	.bind = acerhdf_bind,
>  	.unbind = acerhdf_unbind,
>  	.get_temp = acerhdf_get_ec_temp,
> -	.get_mode = acerhdf_get_mode,
>  	.set_mode = acerhdf_set_mode,
>  	.get_trip_type = acerhdf_get_trip_type,
>  	.get_trip_hyst = acerhdf_get_trip_hyst,
> @@ -757,6 +749,8 @@ static int __init acerhdf_register_thermal(void)
>  		return -EINVAL;
>  	}
>  
> +	thermal_zone_device_store_mode(thz_dev, ACERHDF_DEFAULT_MODE);
> +
>  	return 0;
>  }
>  
> diff --git a/drivers/thermal/da9062-thermal.c b/drivers/thermal/da9062-thermal.c
> index c32709badeda..279d393bb048 100644
> --- a/drivers/thermal/da9062-thermal.c
> +++ b/drivers/thermal/da9062-thermal.c
> @@ -49,7 +49,6 @@ struct da9062_thermal {
>  	struct da9062 *hw;
>  	struct delayed_work work;
>  	struct thermal_zone_device *zone;
> -	enum thermal_device_mode mode;
>  	struct mutex lock; /* protection for da9062_thermal temperature */
>  	int temperature;
>  	int irq;
> @@ -121,14 +120,6 @@ static irqreturn_t da9062_thermal_irq_handler(int irq, void *data)
>  	return IRQ_HANDLED;
>  }
>  
> -static int da9062_thermal_get_mode(struct thermal_zone_device *z,
> -				   enum thermal_device_mode *mode)
> -{
> -	struct da9062_thermal *thermal = z->devdata;
> -	*mode = thermal->mode;
> -	return 0;
> -}
> -
>  static int da9062_thermal_get_trip_type(struct thermal_zone_device *z,
>  					int trip,
>  					enum thermal_trip_type *type)
> @@ -181,7 +172,6 @@ static int da9062_thermal_get_temp(struct thermal_zone_device *z,
>  
>  static struct thermal_zone_device_ops da9062_thermal_ops = {
>  	.get_temp	= da9062_thermal_get_temp,
> -	.get_mode	= da9062_thermal_get_mode,
>  	.get_trip_type	= da9062_thermal_get_trip_type,
>  	.get_trip_temp	= da9062_thermal_get_trip_temp,
>  };
> @@ -233,7 +223,6 @@ static int da9062_thermal_probe(struct platform_device *pdev)
>  
>  	thermal->config = match->data;
>  	thermal->hw = chip;
> -	thermal->mode = THERMAL_DEVICE_ENABLED;
>  	thermal->dev = &pdev->dev;
>  
>  	INIT_DELAYED_WORK(&thermal->work, da9062_thermal_poll_on);
> @@ -248,6 +237,7 @@ static int da9062_thermal_probe(struct platform_device *pdev)
>  		ret = PTR_ERR(thermal->zone);
>  		goto err;
>  	}
> +	thermal_zone_device_store_enabled(thermal->zone);
>  
>  	dev_dbg(&pdev->dev,
>  		"TJUNC temperature polling period set at %d ms\n",
> diff --git a/drivers/thermal/imx_thermal.c b/drivers/thermal/imx_thermal.c
> index 36b1924f1938..f3f602b4ece5 100644
> --- a/drivers/thermal/imx_thermal.c
> +++ b/drivers/thermal/imx_thermal.c
> @@ -197,7 +197,6 @@ struct imx_thermal_data {
>  	struct cpufreq_policy *policy;
>  	struct thermal_zone_device *tz;
>  	struct thermal_cooling_device *cdev;
> -	enum thermal_device_mode mode;
>  	struct regmap *tempmon;
>  	u32 c1, c2; /* See formula in imx_init_calib() */
>  	int temp_passive;
> @@ -252,11 +251,17 @@ static int imx_get_temp(struct thermal_zone_device *tz, int *temp)
>  	struct imx_thermal_data *data = tz->devdata;
>  	const struct thermal_soc_data *soc_data = data->socdata;
>  	struct regmap *map = data->tempmon;
> +	enum thermal_device_mode mode;
>  	unsigned int n_meas;
>  	bool wait;
>  	u32 val;
>  
> -	if (data->mode == THERMAL_DEVICE_ENABLED) {
> +	/*
> +	 * this driver does not provide ->get_mode(), so calling
> +	 * thermal_zone_device_get_mode() always succeeds
> +	 */
> +	thermal_zone_device_get_mode(tz, &mode);
> +	if (mode == THERMAL_DEVICE_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 +288,7 @@ static int imx_get_temp(struct thermal_zone_device *tz, int *temp)
>  
>  	regmap_read(map, soc_data->temp_data, &val);
>  
> -	if (data->mode != THERMAL_DEVICE_ENABLED) {
> +	if (mode != THERMAL_DEVICE_ENABLED) {
>  		regmap_write(map, soc_data->sensor_ctrl + REG_CLR,
>  			     soc_data->measure_temp_mask);
>  		regmap_write(map, soc_data->sensor_ctrl + REG_SET,
> @@ -331,16 +336,6 @@ static int imx_get_temp(struct thermal_zone_device *tz, int *temp)
>  	return 0;
>  }
>  
> -static int imx_get_mode(struct thermal_zone_device *tz,
> -			enum thermal_device_mode *mode)
> -{
> -	struct imx_thermal_data *data = tz->devdata;
> -
> -	*mode = data->mode;
> -
> -	return 0;
> -}
> -
>  static int imx_set_mode(struct thermal_zone_device *tz,
>  			enum thermal_device_mode mode)
>  {
> @@ -378,7 +373,7 @@ static int imx_set_mode(struct thermal_zone_device *tz,
>  		return -EINVAL;
>  	}
>  
> -	data->mode = mode;
> +	thermal_zone_device_store_mode(tz, mode);
>  	thermal_zone_device_update(tz, THERMAL_EVENT_UNSPECIFIED);
>  
>  	return 0;
> @@ -469,7 +464,6 @@ static struct thermal_zone_device_ops imx_tz_ops = {
>  	.bind = imx_bind,
>  	.unbind = imx_unbind,
>  	.get_temp = imx_get_temp,
> -	.get_mode = imx_get_mode,
>  	.set_mode = imx_set_mode,
>  	.get_trip_type = imx_get_trip_type,
>  	.get_trip_temp = imx_get_trip_temp,
> @@ -833,7 +827,7 @@ static int imx_thermal_probe(struct platform_device *pdev)
>  		     data->socdata->measure_temp_mask);
>  
>  	data->irq_enabled = true;
> -	data->mode = THERMAL_DEVICE_ENABLED;
> +	thermal_zone_device_store_enabled(data->tz);
>  
>  	ret = devm_request_threaded_irq(&pdev->dev, data->irq,
>  			imx_thermal_alarm_irq, imx_thermal_alarm_irq_thread,
> @@ -887,7 +881,7 @@ static int __maybe_unused imx_thermal_suspend(struct device *dev)
>  		     data->socdata->measure_temp_mask);
>  	regmap_write(map, data->socdata->sensor_ctrl + REG_SET,
>  		     data->socdata->power_down_mask);
> -	data->mode = THERMAL_DEVICE_DISABLED;
> +	thermal_zone_device_store_disabled(data->tz);
>  	clk_disable_unprepare(data->thermal_clk);
>  
>  	return 0;
> @@ -907,7 +901,7 @@ static int __maybe_unused imx_thermal_resume(struct device *dev)
>  		     data->socdata->power_down_mask);
>  	regmap_write(map, data->socdata->sensor_ctrl + REG_SET,
>  		     data->socdata->measure_temp_mask);
> -	data->mode = THERMAL_DEVICE_ENABLED;
> +	thermal_zone_device_store_enabled(data->tz);
>  
>  	return 0;
>  }
> diff --git a/drivers/thermal/intel/int340x_thermal/int3400_thermal.c b/drivers/thermal/intel/int340x_thermal/int3400_thermal.c
> index fbb59dd09481..a7d9b42c060d 100644
> --- a/drivers/thermal/intel/int340x_thermal/int3400_thermal.c
> +++ b/drivers/thermal/intel/int340x_thermal/int3400_thermal.c
> @@ -44,7 +44,6 @@ static char *int3400_thermal_uuids[INT3400_THERMAL_MAXIMUM_UUID] = {
>  struct int3400_thermal_priv {
>  	struct acpi_device *adev;
>  	struct thermal_zone_device *thermal;
> -	int mode;
>  	int art_count;
>  	struct art *arts;
>  	int trt_count;
> @@ -230,42 +229,33 @@ static int int3400_thermal_get_temp(struct thermal_zone_device *thermal,
>  	return 0;
>  }
>  
> -static int int3400_thermal_get_mode(struct thermal_zone_device *thermal,
> -				enum thermal_device_mode *mode)
> -{
> -	struct int3400_thermal_priv *priv = thermal->devdata;
> -
> -	*mode = priv->mode;
> -
> -	return 0;
> -}
> -
>  static int int3400_thermal_set_mode(struct thermal_zone_device *thermal,
>  				enum thermal_device_mode mode)
>  {
>  	struct int3400_thermal_priv *priv = thermal->devdata;
> -	bool enable;
> +	enum thermal_device_mode old_mode;
>  	int result = 0;
>  
> -	if (mode == THERMAL_DEVICE_ENABLED)
> -		enable = true;
> -	else if (mode == THERMAL_DEVICE_DISABLED)
> -		enable = false;
> -	else
> +	if (mode != THERMAL_DEVICE_ENABLED &&
> +	    mode != THERMAL_DEVICE_DISABLED)
>  		return -EINVAL;
>  
> -	if (enable != priv->mode) {
> -		priv->mode = enable;
> +	/*
> +	 * this driver does not provide ->get_mode(), so calling
> +	 * thermal_zone_device_get_mode() always succeeds
> +	 */
> +	thermal_zone_device_get_mode(thermal, &old_mode);
> +	if (mode != old_mode) {
> +		thermal_zone_device_store_mode(thermal, mode);
>  		result = int3400_thermal_run_osc(priv->adev->handle,
> -						 priv->current_uuid_index,
> -						 enable);
> +						priv->current_uuid_index,
> +						mode == THERMAL_DEVICE_ENABLED);
>  	}
>  	return result;
>  }
>  
>  static struct thermal_zone_device_ops int3400_thermal_ops = {
>  	.get_temp = int3400_thermal_get_temp,
> -	.get_mode = int3400_thermal_get_mode,
>  	.set_mode = int3400_thermal_set_mode,
>  };
>  
> diff --git a/drivers/thermal/intel/intel_quark_dts_thermal.c b/drivers/thermal/intel/intel_quark_dts_thermal.c
> index 11d7db895125..6d440ef3055f 100644
> --- a/drivers/thermal/intel/intel_quark_dts_thermal.c
> +++ b/drivers/thermal/intel/intel_quark_dts_thermal.c
> @@ -103,7 +103,6 @@ struct soc_sensor_entry {
>  	bool locked;
>  	u32 store_ptps;
>  	u32 store_dts_enable;
> -	enum thermal_device_mode mode;
>  	struct thermal_zone_device *tzone;
>  };
>  
> @@ -128,7 +127,7 @@ static int soc_dts_enable(struct thermal_zone_device *tzd)
>  		return ret;
>  
>  	if (out & QRK_DTS_ENABLE_BIT) {
> -		aux_entry->mode = THERMAL_DEVICE_ENABLED;
> +		thermal_zone_device_store_enabled(tzd);
>  		return 0;
>  	}
>  
> @@ -139,9 +138,9 @@ static int soc_dts_enable(struct thermal_zone_device *tzd)
>  		if (ret)
>  			return ret;
>  
> -		aux_entry->mode = THERMAL_DEVICE_ENABLED;
> +		thermal_zone_device_store_enabled(tzd);
>  	} else {
> -		aux_entry->mode = THERMAL_DEVICE_DISABLED;
> +		thermal_zone_device_store_disabled(tzd);
>  		pr_info("DTS is locked. Cannot enable DTS\n");
>  		ret = -EPERM;
>  	}
> @@ -161,7 +160,7 @@ static int soc_dts_disable(struct thermal_zone_device *tzd)
>  		return ret;
>  
>  	if (!(out & QRK_DTS_ENABLE_BIT)) {
> -		aux_entry->mode = THERMAL_DEVICE_DISABLED;
> +		thermal_zone_device_store_disabled(tzd);
>  		return 0;
>  	}
>  
> @@ -173,9 +172,9 @@ static int soc_dts_disable(struct thermal_zone_device *tzd)
>  		if (ret)
>  			return ret;
>  
> -		aux_entry->mode = THERMAL_DEVICE_DISABLED;
> +		thermal_zone_device_store_disabled(tzd);
>  	} else {
> -		aux_entry->mode = THERMAL_DEVICE_ENABLED;
> +		thermal_zone_device_store_enabled(tzd);
>  		pr_info("DTS is locked. Cannot disable DTS\n");
>  		ret = -EPERM;
>  	}
> @@ -309,14 +308,6 @@ static int sys_get_curr_temp(struct thermal_zone_device *tzd,
>  	return 0;
>  }
>  
> -static int sys_get_mode(struct thermal_zone_device *tzd,
> -				enum thermal_device_mode *mode)
> -{
> -	struct soc_sensor_entry *aux_entry = tzd->devdata;
> -	*mode = aux_entry->mode;
> -	return 0;
> -}
> -
>  static int sys_set_mode(struct thermal_zone_device *tzd,
>  				enum thermal_device_mode mode)
>  {
> @@ -341,7 +332,6 @@ static struct thermal_zone_device_ops tzone_ops = {
>  	.get_trip_type = sys_get_trip_type,
>  	.set_trip_temp = sys_set_trip_temp,
>  	.get_crit_temp = sys_get_crit_temp,
> -	.get_mode = sys_get_mode,
>  	.set_mode = sys_set_mode,
>  };
>  
> diff --git a/drivers/thermal/of-thermal.c b/drivers/thermal/of-thermal.c
> index 36bebf623980..0f1e134e90ea 100644
> --- a/drivers/thermal/of-thermal.c
> +++ b/drivers/thermal/of-thermal.c
> @@ -51,7 +51,6 @@ struct __thermal_bind_params {
>  
>  /**
>   * struct __thermal_zone - internal representation of a thermal zone
> - * @mode: current thermal zone device mode (enabled/disabled)
>   * @passive_delay: polling interval while passive cooling is activated
>   * @polling_delay: zone polling interval
>   * @slope: slope of the temperature adjustment curve
> @@ -65,7 +64,6 @@ struct __thermal_bind_params {
>   */
>  
>  struct __thermal_zone {
> -	enum thermal_device_mode mode;
>  	int passive_delay;
>  	int polling_delay;
>  	int slope;
> @@ -269,16 +267,6 @@ static int of_thermal_unbind(struct thermal_zone_device *thermal,
>  	return 0;
>  }
>  
> -static int of_thermal_get_mode(struct thermal_zone_device *tz,
> -			       enum thermal_device_mode *mode)
> -{
> -	struct __thermal_zone *data = tz->devdata;
> -
> -	*mode = data->mode;
> -
> -	return 0;
> -}
> -
>  static int of_thermal_set_mode(struct thermal_zone_device *tz,
>  			       enum thermal_device_mode mode)
>  {
> @@ -298,7 +286,7 @@ static int of_thermal_set_mode(struct thermal_zone_device *tz,
>  
>  	mutex_unlock(&tz->lock);
>  
> -	data->mode = mode;
> +	thermal_zone_device_store_mode(tz, mode);
>  	thermal_zone_device_update(tz, THERMAL_EVENT_UNSPECIFIED);
>  
>  	return 0;
> @@ -395,7 +383,6 @@ static int of_thermal_get_crit_temp(struct thermal_zone_device *tz,
>  }
>  
>  static struct thermal_zone_device_ops of_thermal_ops = {
> -	.get_mode = of_thermal_get_mode,
>  	.set_mode = of_thermal_set_mode,
>  
>  	.get_trip_type = of_thermal_get_trip_type,
> @@ -556,7 +543,7 @@ thermal_zone_of_sensor_register(struct device *dev, int sensor_id, void *data,
>  			tzd = thermal_zone_of_add_sensor(child, sensor_np,
>  							 data, ops);
>  			if (!IS_ERR(tzd))
> -				tzd->ops->set_mode(tzd, THERMAL_DEVICE_ENABLED);
> +				thermal_zone_device_enable(tzd);
>  
>  			of_node_put(child);
>  			goto exit;
> @@ -981,7 +968,6 @@ __init *thermal_of_build_thermal_zone(struct device_node *np)
>  
>  finish:
>  	of_node_put(child);
> -	tz->mode = THERMAL_DEVICE_DISABLED;
>  
>  	return tz;
>  
> @@ -1136,6 +1122,7 @@ int __init of_parse_thermal_zones(void)
>  			of_thermal_free_zone(tz);
>  			/* attempting to build remaining zones still */
>  		}
> +		thermal_zone_device_store_disabled(zone);
>  	}
>  	of_node_put(np);
>  
> 


-- 
<http://www.linaro.org/> Linaro.org │ Open source software for ARM SoCs

Follow Linaro:  <http://www.facebook.com/pages/Linaro> Facebook |
<http://twitter.com/#!/linaroorg> Twitter |
<http://www.linaro.org/linaro-blog/> Blog

^ permalink raw reply	[flat|nested] 63+ messages in thread

* [RFC v3 0/2] Stop monitoring disabled devices
  2020-04-15 10:55       ` Daniel Lezcano
@ 2020-04-17 16:20         ` Andrzej Pietrasiewicz
  2020-04-17 16:20           ` [RFC v3 1/2] thermal: core: Let thermal zone device's mode be stored in its struct Andrzej Pietrasiewicz
                             ` (2 more replies)
  0 siblings, 3 replies; 63+ messages in thread
From: Andrzej Pietrasiewicz @ 2020-04-17 16:20 UTC (permalink / raw)
  To: linux-pm
  Cc: Zhang Rui, Rafael J . Wysocki, Len Brown, Jiri Pirko,
	Ido Schimmel, David S . Miller, Peter Kaestle, Darren Hart,
	Andy Shevchenko, Support Opensource, Daniel Lezcano,
	Amit Kucheria, Shawn Guo, Sascha Hauer, Pengutronix Kernel Team,
	Fabio Estevam, NXP Linux Team, Allison Randal, Enrico Weigelt,
	Gayatri Kammela, Thomas Gleixner, linux-acpi, netdev,
	platform-driver-x86, linux-arm-kernel, kernel,
	Andrzej Pietrasiewicz, Barlomiej Zolnierkiewicz

This is the third iteration of this RFC. It has been substantially
rewritten compared to v2.

The first patch makes all the drivers store their mode in struct
thermal_zone_device. Such a move has consequences: driver-specific
variables for storing mode are not necessary. Consequently get_mode()
methods become obsolete. Then sysfs "mode" attribute stops depending
on get_mode() being provided, because it is always provided from now on.

The first patch also introduces the initial mode to be optionally passed
to thermal_zone_device_register().

Given all the groundwork done in patch 1/2 patch 2/2 becomes very simple.

This series addresses comments from Daniel and Bartlomiej - thank you guys!

Andrzej Pietrasiewicz (2):
  thermal: core: Let thermal zone device's mode be stored in its struct
  thermal: core: Stop polling DISABLED thermal devices

 drivers/acpi/thermal.c                        | 46 +++++---------
 .../ethernet/mellanox/mlxsw/core_thermal.c    | 57 ++++--------------
 drivers/platform/x86/acerhdf.c                | 17 +-----
 drivers/thermal/da9062-thermal.c              | 16 ++---
 drivers/thermal/imx_thermal.c                 | 29 +++------
 .../intel/int340x_thermal/int3400_thermal.c   | 30 ++--------
 .../thermal/intel/intel_quark_dts_thermal.c   | 22 ++-----
 drivers/thermal/of-thermal.c                  | 30 +++-------
 drivers/thermal/thermal_core.c                | 60 +++++++++++++++++--
 drivers/thermal/thermal_core.h                | 16 +++++
 drivers/thermal/thermal_sysfs.c               | 29 +--------
 include/linux/thermal.h                       |  7 ++-
 12 files changed, 139 insertions(+), 220 deletions(-)

-- 
2.17.1


^ permalink raw reply	[flat|nested] 63+ messages in thread

* [RFC v3 1/2] thermal: core: Let thermal zone device's mode be stored in its struct
  2020-04-17 16:20         ` [RFC v3 0/2] Stop monitoring disabled devices Andrzej Pietrasiewicz
@ 2020-04-17 16:20           ` Andrzej Pietrasiewicz
  2020-04-17 20:44             ` Andy Shevchenko
                               ` (2 more replies)
  2020-04-17 16:20           ` [RFC v3 2/2] thermal: core: Stop polling DISABLED thermal devices Andrzej Pietrasiewicz
  2020-04-19 13:50           ` [RFC v3 1/2] thermal: core: Let thermal zone device's mode be stored in its struct Peter Kästle
  2 siblings, 3 replies; 63+ messages in thread
From: Andrzej Pietrasiewicz @ 2020-04-17 16:20 UTC (permalink / raw)
  To: linux-pm
  Cc: Zhang Rui, Rafael J . Wysocki, Len Brown, Jiri Pirko,
	Ido Schimmel, David S . Miller, Peter Kaestle, Darren Hart,
	Andy Shevchenko, Support Opensource, Daniel Lezcano,
	Amit Kucheria, Shawn Guo, Sascha Hauer, Pengutronix Kernel Team,
	Fabio Estevam, NXP Linux Team, Allison Randal, Enrico Weigelt,
	Gayatri Kammela, Thomas Gleixner, linux-acpi, netdev,
	platform-driver-x86, linux-arm-kernel, kernel,
	Andrzej Pietrasiewicz, Barlomiej Zolnierkiewicz

Thermal zone devices' mode is stored in individual drivers. This patch
changes it so that mode is stored in struct thermal_zone_device instead.

As a result all driver-specific variables storing the mode are not needed
and are removed. Consequently, the get_mode() implementations have nothing
to operate on and need to be removed, too.

Some thermal framework specific functions are introduced:

thermal_zone_device_get_mode()
thermal_zone_device_set_mode()
thermal_zone_device_enable()
thermal_zone_device_disable()

thermal_zone_device_get_mode() and its "set" counterpart take tzd's lock
and the "set" calls driver's set_mode() if provided, so the latter must
not take this lock again. At the end of the "set"
thermal_zone_device_update() is called so drivers don't need to repeat this
invocation in their specific set_mode() implementations.

The scope of the above 4 functions is purposedly limited to the thermal
framework and drivers are not supposed to call them. This encapsulation
does not fully work at the moment for some drivers, though:

- platform/x86/acerhdf.c
- drivers/thermal/imx_thermal.c
- drivers/thermal/intel/intel_quark_dts_thermal.c
- drivers/thermal/of-thermal.c

and they manipulate struct thermal_zone_device's members directly.

struct thermal_zone_params gains a new member called initial_mode, which
is used to set tzd's mode at registration time.

The sysfs "mode" attribute is always exposed from now on, because all
thermal zone devices now have their get_mode() implemented at the generic
level and it is always available. Exposing "mode" doesn't hurt the drivers
which don't provide their own set_mode(), because writing to "mode" will
result in -EPERM, as expected.

Signed-off-by: Andrzej Pietrasiewicz <andrzej.p@collabora.com>
---
 drivers/acpi/thermal.c                        | 46 +++++----------
 .../ethernet/mellanox/mlxsw/core_thermal.c    | 57 ++++---------------
 drivers/platform/x86/acerhdf.c                | 17 +-----
 drivers/thermal/da9062-thermal.c              | 16 ++----
 drivers/thermal/imx_thermal.c                 | 29 +++-------
 .../intel/int340x_thermal/int3400_thermal.c   | 30 ++--------
 .../thermal/intel/intel_quark_dts_thermal.c   | 22 ++-----
 drivers/thermal/of-thermal.c                  | 30 +++-------
 drivers/thermal/thermal_core.c                | 44 +++++++++++++-
 drivers/thermal/thermal_core.h                | 16 ++++++
 drivers/thermal/thermal_sysfs.c               | 29 +---------
 include/linux/thermal.h                       |  7 ++-
 12 files changed, 125 insertions(+), 218 deletions(-)

diff --git a/drivers/acpi/thermal.c b/drivers/acpi/thermal.c
index 19067a5e5293..67bc263332a5 100644
--- a/drivers/acpi/thermal.c
+++ b/drivers/acpi/thermal.c
@@ -172,7 +172,6 @@ struct acpi_thermal {
 	struct acpi_thermal_trips trips;
 	struct acpi_handle_list devices;
 	struct thermal_zone_device *thermal_zone;
-	int tz_enabled;
 	int kelvin_offset;	/* in millidegrees */
 	struct work_struct thermal_check_work;
 };
@@ -500,7 +499,7 @@ static void acpi_thermal_check(void *data)
 {
 	struct acpi_thermal *tz = data;
 
-	if (!tz->tz_enabled)
+	if (tz->thermal_zone->mode != THERMAL_DEVICE_ENABLED)
 		return;
 
 	thermal_zone_device_update(tz->thermal_zone,
@@ -526,46 +525,29 @@ static int thermal_get_temp(struct thermal_zone_device *thermal, int *temp)
 	return 0;
 }
 
-static int thermal_get_mode(struct thermal_zone_device *thermal,
-				enum thermal_device_mode *mode)
-{
-	struct acpi_thermal *tz = thermal->devdata;
-
-	if (!tz)
-		return -EINVAL;
-
-	*mode = tz->tz_enabled ? THERMAL_DEVICE_ENABLED :
-		THERMAL_DEVICE_DISABLED;
-
-	return 0;
-}
-
 static int thermal_set_mode(struct thermal_zone_device *thermal,
 				enum thermal_device_mode mode)
 {
 	struct acpi_thermal *tz = thermal->devdata;
-	int enable;
 
 	if (!tz)
 		return -EINVAL;
 
+	if (mode != THERMAL_DEVICE_DISABLED &&
+	    mode != THERMAL_DEVICE_ENABLED)
+		return -EINVAL;
+
 	/*
 	 * enable/disable thermal management from ACPI thermal driver
 	 */
-	if (mode == THERMAL_DEVICE_ENABLED)
-		enable = 1;
-	else if (mode == THERMAL_DEVICE_DISABLED) {
-		enable = 0;
+	if (mode == THERMAL_DEVICE_DISABLED)
 		pr_warn("thermal zone will be disabled\n");
-	} else
-		return -EINVAL;
 
-	if (enable != tz->tz_enabled) {
-		tz->tz_enabled = enable;
+	if (mode != thermal->mode) {
 		ACPI_DEBUG_PRINT((ACPI_DB_INFO,
 			"%s kernel ACPI thermal control\n",
-			tz->tz_enabled ? "Enable" : "Disable"));
-		acpi_thermal_check(tz);
+			mode == THERMAL_DEVICE_ENABLED ?
+			"Enable" : "Disable"));
 	}
 	return 0;
 }
@@ -856,7 +838,6 @@ static struct thermal_zone_device_ops acpi_thermal_zone_ops = {
 	.bind = acpi_thermal_bind_cooling_device,
 	.unbind	= acpi_thermal_unbind_cooling_device,
 	.get_temp = thermal_get_temp,
-	.get_mode = thermal_get_mode,
 	.set_mode = thermal_set_mode,
 	.get_trip_type = thermal_get_trip_type,
 	.get_trip_temp = thermal_get_trip_temp,
@@ -870,6 +851,9 @@ static int acpi_thermal_register_thermal_zone(struct acpi_thermal *tz)
 	int trips = 0;
 	int result;
 	acpi_status status;
+	struct thermal_zone_params prms = {
+		.initial_mode = THERMAL_DEVICE_ENABLED,
+	};
 	int i;
 
 	if (tz->trips.critical.flags.valid)
@@ -887,13 +871,13 @@ static int acpi_thermal_register_thermal_zone(struct acpi_thermal *tz)
 	if (tz->trips.passive.flags.valid)
 		tz->thermal_zone =
 			thermal_zone_device_register("acpitz", trips, 0, tz,
-						&acpi_thermal_zone_ops, NULL,
+						&acpi_thermal_zone_ops, &prms,
 						     tz->trips.passive.tsp*100,
 						     tz->polling_frequency*100);
 	else
 		tz->thermal_zone =
 			thermal_zone_device_register("acpitz", trips, 0, tz,
-						&acpi_thermal_zone_ops, NULL,
+						&acpi_thermal_zone_ops, &prms,
 						0, tz->polling_frequency*100);
 	if (IS_ERR(tz->thermal_zone))
 		return -ENODEV;
@@ -913,8 +897,6 @@ static int acpi_thermal_register_thermal_zone(struct acpi_thermal *tz)
 	if (ACPI_FAILURE(status))
 		return -ENODEV;
 
-	tz->tz_enabled = 1;
-
 	dev_info(&tz->device->dev, "registered as thermal_zone%d\n",
 		 tz->thermal_zone->id);
 	return 0;
diff --git a/drivers/net/ethernet/mellanox/mlxsw/core_thermal.c b/drivers/net/ethernet/mellanox/mlxsw/core_thermal.c
index ce0a6837daa3..50518048b86d 100644
--- a/drivers/net/ethernet/mellanox/mlxsw/core_thermal.c
+++ b/drivers/net/ethernet/mellanox/mlxsw/core_thermal.c
@@ -98,7 +98,6 @@ struct mlxsw_thermal_module {
 	struct mlxsw_thermal *parent;
 	struct thermal_zone_device *tzdev;
 	struct mlxsw_thermal_trip trips[MLXSW_THERMAL_NUM_TRIPS];
-	enum thermal_device_mode mode;
 	int module; /* Module or gearbox number */
 };
 
@@ -110,7 +109,6 @@ struct mlxsw_thermal {
 	struct thermal_cooling_device *cdevs[MLXSW_MFCR_PWMS_MAX];
 	u8 cooling_levels[MLXSW_THERMAL_MAX_STATE + 1];
 	struct mlxsw_thermal_trip trips[MLXSW_THERMAL_NUM_TRIPS];
-	enum thermal_device_mode mode;
 	struct mlxsw_thermal_module *tz_module_arr;
 	u8 tz_module_num;
 	struct mlxsw_thermal_module *tz_gearbox_arr;
@@ -277,33 +275,16 @@ static int mlxsw_thermal_unbind(struct thermal_zone_device *tzdev,
 	return 0;
 }
 
-static int mlxsw_thermal_get_mode(struct thermal_zone_device *tzdev,
-				  enum thermal_device_mode *mode)
-{
-	struct mlxsw_thermal *thermal = tzdev->devdata;
-
-	*mode = thermal->mode;
-
-	return 0;
-}
-
 static int mlxsw_thermal_set_mode(struct thermal_zone_device *tzdev,
 				  enum thermal_device_mode mode)
 {
 	struct mlxsw_thermal *thermal = tzdev->devdata;
 
-	mutex_lock(&tzdev->lock);
-
 	if (mode == THERMAL_DEVICE_ENABLED)
 		tzdev->polling_delay = thermal->polling_delay;
 	else
 		tzdev->polling_delay = 0;
 
-	mutex_unlock(&tzdev->lock);
-
-	thermal->mode = mode;
-	thermal_zone_device_update(tzdev, THERMAL_EVENT_UNSPECIFIED);
-
 	return 0;
 }
 
@@ -407,7 +388,6 @@ static int mlxsw_thermal_trend_get(struct thermal_zone_device *tzdev,
 static struct thermal_zone_device_ops mlxsw_thermal_ops = {
 	.bind = mlxsw_thermal_bind,
 	.unbind = mlxsw_thermal_unbind,
-	.get_mode = mlxsw_thermal_get_mode,
 	.set_mode = mlxsw_thermal_set_mode,
 	.get_temp = mlxsw_thermal_get_temp,
 	.get_trip_type	= mlxsw_thermal_get_trip_type,
@@ -466,34 +446,17 @@ static int mlxsw_thermal_module_unbind(struct thermal_zone_device *tzdev,
 	return err;
 }
 
-static int mlxsw_thermal_module_mode_get(struct thermal_zone_device *tzdev,
-					 enum thermal_device_mode *mode)
-{
-	struct mlxsw_thermal_module *tz = tzdev->devdata;
-
-	*mode = tz->mode;
-
-	return 0;
-}
-
 static int mlxsw_thermal_module_mode_set(struct thermal_zone_device *tzdev,
 					 enum thermal_device_mode mode)
 {
 	struct mlxsw_thermal_module *tz = tzdev->devdata;
 	struct mlxsw_thermal *thermal = tz->parent;
 
-	mutex_lock(&tzdev->lock);
-
 	if (mode == THERMAL_DEVICE_ENABLED)
 		tzdev->polling_delay = thermal->polling_delay;
 	else
 		tzdev->polling_delay = 0;
 
-	mutex_unlock(&tzdev->lock);
-
-	tz->mode = mode;
-	thermal_zone_device_update(tzdev, THERMAL_EVENT_UNSPECIFIED);
-
 	return 0;
 }
 
@@ -596,7 +559,6 @@ mlxsw_thermal_module_trip_hyst_set(struct thermal_zone_device *tzdev, int trip,
 static struct thermal_zone_device_ops mlxsw_thermal_module_ops = {
 	.bind		= mlxsw_thermal_module_bind,
 	.unbind		= mlxsw_thermal_module_unbind,
-	.get_mode	= mlxsw_thermal_module_mode_get,
 	.set_mode	= mlxsw_thermal_module_mode_set,
 	.get_temp	= mlxsw_thermal_module_temp_get,
 	.get_trip_type	= mlxsw_thermal_module_trip_type_get,
@@ -635,7 +597,6 @@ static int mlxsw_thermal_gearbox_temp_get(struct thermal_zone_device *tzdev,
 static struct thermal_zone_device_ops mlxsw_thermal_gearbox_ops = {
 	.bind		= mlxsw_thermal_module_bind,
 	.unbind		= mlxsw_thermal_module_unbind,
-	.get_mode	= mlxsw_thermal_module_mode_get,
 	.set_mode	= mlxsw_thermal_module_mode_set,
 	.get_temp	= mlxsw_thermal_gearbox_temp_get,
 	.get_trip_type	= mlxsw_thermal_module_trip_type_get,
@@ -749,6 +710,9 @@ static const struct thermal_cooling_device_ops mlxsw_cooling_ops = {
 static int
 mlxsw_thermal_module_tz_init(struct mlxsw_thermal_module *module_tz)
 {
+	struct thermal_zone_params tzp = {
+		.initial_mode = THERMAL_DEVICE_ENABLED,
+	};
 	char tz_name[MLXSW_THERMAL_ZONE_MAX_NAME];
 	int err;
 
@@ -759,13 +723,12 @@ mlxsw_thermal_module_tz_init(struct mlxsw_thermal_module *module_tz)
 							MLXSW_THERMAL_TRIP_MASK,
 							module_tz,
 							&mlxsw_thermal_module_ops,
-							NULL, 0, 0);
+							&tzp, 0, 0);
 	if (IS_ERR(module_tz->tzdev)) {
 		err = PTR_ERR(module_tz->tzdev);
 		return err;
 	}
 
-	module_tz->mode = THERMAL_DEVICE_ENABLED;
 	return 0;
 }
 
@@ -868,6 +831,9 @@ mlxsw_thermal_modules_fini(struct mlxsw_thermal *thermal)
 static int
 mlxsw_thermal_gearbox_tz_init(struct mlxsw_thermal_module *gearbox_tz)
 {
+	struct thermal_zone_params tzp = {
+		.initial_mode = THERMAL_DEVICE_ENABLED,
+	};
 	char tz_name[MLXSW_THERMAL_ZONE_MAX_NAME];
 
 	snprintf(tz_name, sizeof(tz_name), "mlxsw-gearbox%d",
@@ -877,11 +843,10 @@ mlxsw_thermal_gearbox_tz_init(struct mlxsw_thermal_module *gearbox_tz)
 						MLXSW_THERMAL_TRIP_MASK,
 						gearbox_tz,
 						&mlxsw_thermal_gearbox_ops,
-						NULL, 0, 0);
+						&tzp, 0, 0);
 	if (IS_ERR(gearbox_tz->tzdev))
 		return PTR_ERR(gearbox_tz->tzdev);
 
-	gearbox_tz->mode = THERMAL_DEVICE_ENABLED;
 	return 0;
 }
 
@@ -960,6 +925,9 @@ int mlxsw_thermal_init(struct mlxsw_core *core,
 		       const struct mlxsw_bus_info *bus_info,
 		       struct mlxsw_thermal **p_thermal)
 {
+	struct thermal_zone_params tzp = {
+		.initial_mode = THERMAL_DEVICE_ENABLED,
+	};
 	char mfcr_pl[MLXSW_REG_MFCR_LEN] = { 0 };
 	enum mlxsw_reg_mfcr_pwm_frequency freq;
 	struct device *dev = bus_info->dev;
@@ -1034,7 +1002,7 @@ int mlxsw_thermal_init(struct mlxsw_core *core,
 						      MLXSW_THERMAL_TRIP_MASK,
 						      thermal,
 						      &mlxsw_thermal_ops,
-						      NULL, 0,
+						      &tzp, 0,
 						      thermal->polling_delay);
 	if (IS_ERR(thermal->tzdev)) {
 		err = PTR_ERR(thermal->tzdev);
@@ -1050,7 +1018,6 @@ int mlxsw_thermal_init(struct mlxsw_core *core,
 	if (err)
 		goto err_unreg_modules_tzdev;
 
-	thermal->mode = THERMAL_DEVICE_ENABLED;
 	*p_thermal = thermal;
 	return 0;
 
diff --git a/drivers/platform/x86/acerhdf.c b/drivers/platform/x86/acerhdf.c
index 8cc86f4e3ac1..aaf8b845be90 100644
--- a/drivers/platform/x86/acerhdf.c
+++ b/drivers/platform/x86/acerhdf.c
@@ -406,22 +406,9 @@ static inline void acerhdf_enable_kernelmode(void)
 	kernelmode = 1;
 
 	thz_dev->polling_delay = interval*1000;
-	thermal_zone_device_update(thz_dev, THERMAL_EVENT_UNSPECIFIED);
 	pr_notice("kernel mode fan control ON\n");
 }
 
-static int acerhdf_get_mode(struct thermal_zone_device *thermal,
-			    enum thermal_device_mode *mode)
-{
-	if (verbose)
-		pr_notice("kernel mode fan control %d\n", kernelmode);
-
-	*mode = (kernelmode) ? THERMAL_DEVICE_ENABLED
-			     : THERMAL_DEVICE_DISABLED;
-
-	return 0;
-}
-
 /*
  * set operation mode;
  * enabled: the thermal layer of the kernel takes care about
@@ -488,7 +475,6 @@ static struct thermal_zone_device_ops acerhdf_dev_ops = {
 	.bind = acerhdf_bind,
 	.unbind = acerhdf_unbind,
 	.get_temp = acerhdf_get_ec_temp,
-	.get_mode = acerhdf_get_mode,
 	.set_mode = acerhdf_set_mode,
 	.get_trip_type = acerhdf_get_trip_type,
 	.get_trip_hyst = acerhdf_get_trip_hyst,
@@ -554,6 +540,7 @@ static int acerhdf_set_cur_state(struct thermal_cooling_device *cdev,
 
 err_out:
 	acerhdf_revert_to_bios_mode();
+	thz_dev->mode = THERMAL_DEVICE_DISABLED;
 	return -EINVAL;
 }
 
@@ -739,6 +726,8 @@ static int __init acerhdf_register_thermal(void)
 	if (IS_ERR(cl_dev))
 		return -EINVAL;
 
+	acerhdf_zone_params.initial_mode =
+		kernelmode ? THERMAL_DEVICE_ENABLED : THERMAL_DEVICE_DISABLED;
 	thz_dev = thermal_zone_device_register("acerhdf", 2, 0, NULL,
 					      &acerhdf_dev_ops,
 					      &acerhdf_zone_params, 0,
diff --git a/drivers/thermal/da9062-thermal.c b/drivers/thermal/da9062-thermal.c
index c32709badeda..4bdb6f9621c1 100644
--- a/drivers/thermal/da9062-thermal.c
+++ b/drivers/thermal/da9062-thermal.c
@@ -49,7 +49,6 @@ struct da9062_thermal {
 	struct da9062 *hw;
 	struct delayed_work work;
 	struct thermal_zone_device *zone;
-	enum thermal_device_mode mode;
 	struct mutex lock; /* protection for da9062_thermal temperature */
 	int temperature;
 	int irq;
@@ -121,14 +120,6 @@ static irqreturn_t da9062_thermal_irq_handler(int irq, void *data)
 	return IRQ_HANDLED;
 }
 
-static int da9062_thermal_get_mode(struct thermal_zone_device *z,
-				   enum thermal_device_mode *mode)
-{
-	struct da9062_thermal *thermal = z->devdata;
-	*mode = thermal->mode;
-	return 0;
-}
-
 static int da9062_thermal_get_trip_type(struct thermal_zone_device *z,
 					int trip,
 					enum thermal_trip_type *type)
@@ -181,7 +172,6 @@ static int da9062_thermal_get_temp(struct thermal_zone_device *z,
 
 static struct thermal_zone_device_ops da9062_thermal_ops = {
 	.get_temp	= da9062_thermal_get_temp,
-	.get_mode	= da9062_thermal_get_mode,
 	.get_trip_type	= da9062_thermal_get_trip_type,
 	.get_trip_temp	= da9062_thermal_get_trip_temp,
 };
@@ -199,6 +189,9 @@ MODULE_DEVICE_TABLE(of, da9062_compatible_reg_id_table);
 
 static int da9062_thermal_probe(struct platform_device *pdev)
 {
+	struct thermal_zone_params tzp = {
+		.initial_mode = THERMAL_DEVICE_ENABLED,
+	};
 	struct da9062 *chip = dev_get_drvdata(pdev->dev.parent);
 	struct da9062_thermal *thermal;
 	unsigned int pp_tmp = DA9062_DEFAULT_POLLING_MS_PERIOD;
@@ -233,7 +226,6 @@ static int da9062_thermal_probe(struct platform_device *pdev)
 
 	thermal->config = match->data;
 	thermal->hw = chip;
-	thermal->mode = THERMAL_DEVICE_ENABLED;
 	thermal->dev = &pdev->dev;
 
 	INIT_DELAYED_WORK(&thermal->work, da9062_thermal_poll_on);
@@ -241,7 +233,7 @@ static int da9062_thermal_probe(struct platform_device *pdev)
 
 	thermal->zone = thermal_zone_device_register(thermal->config->name,
 					1, 0, thermal,
-					&da9062_thermal_ops, NULL, pp_tmp,
+					&da9062_thermal_ops, &tzp, pp_tmp,
 					0);
 	if (IS_ERR(thermal->zone)) {
 		dev_err(&pdev->dev, "Cannot register thermal zone device\n");
diff --git a/drivers/thermal/imx_thermal.c b/drivers/thermal/imx_thermal.c
index e761c9b42217..3e02323c938b 100644
--- a/drivers/thermal/imx_thermal.c
+++ b/drivers/thermal/imx_thermal.c
@@ -197,7 +197,6 @@ struct imx_thermal_data {
 	struct cpufreq_policy *policy;
 	struct thermal_zone_device *tz;
 	struct thermal_cooling_device *cdev;
-	enum thermal_device_mode mode;
 	struct regmap *tempmon;
 	u32 c1, c2; /* See formula in imx_init_calib() */
 	int temp_passive;
@@ -256,7 +255,7 @@ static int imx_get_temp(struct thermal_zone_device *tz, int *temp)
 	bool wait;
 	u32 val;
 
-	if (data->mode == THERMAL_DEVICE_ENABLED) {
+	if (tz->mode == THERMAL_DEVICE_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 +282,7 @@ static int imx_get_temp(struct thermal_zone_device *tz, int *temp)
 
 	regmap_read(map, soc_data->temp_data, &val);
 
-	if (data->mode != THERMAL_DEVICE_ENABLED) {
+	if (tz->mode != THERMAL_DEVICE_ENABLED) {
 		regmap_write(map, soc_data->sensor_ctrl + REG_CLR,
 			     soc_data->measure_temp_mask);
 		regmap_write(map, soc_data->sensor_ctrl + REG_SET,
@@ -331,16 +330,6 @@ static int imx_get_temp(struct thermal_zone_device *tz, int *temp)
 	return 0;
 }
 
-static int imx_get_mode(struct thermal_zone_device *tz,
-			enum thermal_device_mode *mode)
-{
-	struct imx_thermal_data *data = tz->devdata;
-
-	*mode = data->mode;
-
-	return 0;
-}
-
 static int imx_set_mode(struct thermal_zone_device *tz,
 			enum thermal_device_mode mode)
 {
@@ -376,9 +365,6 @@ static int imx_set_mode(struct thermal_zone_device *tz,
 		}
 	}
 
-	data->mode = mode;
-	thermal_zone_device_update(tz, THERMAL_EVENT_UNSPECIFIED);
-
 	return 0;
 }
 
@@ -467,7 +453,6 @@ static struct thermal_zone_device_ops imx_tz_ops = {
 	.bind = imx_bind,
 	.unbind = imx_unbind,
 	.get_temp = imx_get_temp,
-	.get_mode = imx_get_mode,
 	.set_mode = imx_set_mode,
 	.get_trip_type = imx_get_trip_type,
 	.get_trip_temp = imx_get_trip_temp,
@@ -691,6 +676,9 @@ static inline void imx_thermal_unregister_legacy_cooling(struct imx_thermal_data
 
 static int imx_thermal_probe(struct platform_device *pdev)
 {
+	struct thermal_zone_params tzp = {
+		.initial_mode = THERMAL_DEVICE_ENABLED,
+	};
 	struct imx_thermal_data *data;
 	struct regmap *map;
 	int measure_freq;
@@ -799,7 +787,7 @@ static int imx_thermal_probe(struct platform_device *pdev)
 	data->tz = thermal_zone_device_register("imx_thermal_zone",
 						IMX_TRIP_NUM,
 						BIT(IMX_TRIP_PASSIVE), data,
-						&imx_tz_ops, NULL,
+						&imx_tz_ops, &tzp,
 						IMX_PASSIVE_DELAY,
 						IMX_POLLING_DELAY);
 	if (IS_ERR(data->tz)) {
@@ -831,7 +819,6 @@ static int imx_thermal_probe(struct platform_device *pdev)
 		     data->socdata->measure_temp_mask);
 
 	data->irq_enabled = true;
-	data->mode = THERMAL_DEVICE_ENABLED;
 
 	ret = devm_request_threaded_irq(&pdev->dev, data->irq,
 			imx_thermal_alarm_irq, imx_thermal_alarm_irq_thread,
@@ -885,7 +872,7 @@ static int __maybe_unused imx_thermal_suspend(struct device *dev)
 		     data->socdata->measure_temp_mask);
 	regmap_write(map, data->socdata->sensor_ctrl + REG_SET,
 		     data->socdata->power_down_mask);
-	data->mode = THERMAL_DEVICE_DISABLED;
+	data->tz->mode = THERMAL_DEVICE_DISABLED;
 	clk_disable_unprepare(data->thermal_clk);
 
 	return 0;
@@ -905,7 +892,7 @@ static int __maybe_unused imx_thermal_resume(struct device *dev)
 		     data->socdata->power_down_mask);
 	regmap_write(map, data->socdata->sensor_ctrl + REG_SET,
 		     data->socdata->measure_temp_mask);
-	data->mode = THERMAL_DEVICE_ENABLED;
+	data->tz->mode = THERMAL_DEVICE_ENABLED;
 
 	return 0;
 }
diff --git a/drivers/thermal/intel/int340x_thermal/int3400_thermal.c b/drivers/thermal/intel/int340x_thermal/int3400_thermal.c
index e802922a13cf..86a00598ed09 100644
--- a/drivers/thermal/intel/int340x_thermal/int3400_thermal.c
+++ b/drivers/thermal/intel/int340x_thermal/int3400_thermal.c
@@ -44,7 +44,6 @@ static char *int3400_thermal_uuids[INT3400_THERMAL_MAXIMUM_UUID] = {
 struct int3400_thermal_priv {
 	struct acpi_device *adev;
 	struct thermal_zone_device *thermal;
-	int mode;
 	int art_count;
 	struct art *arts;
 	int trt_count;
@@ -230,48 +229,29 @@ static int int3400_thermal_get_temp(struct thermal_zone_device *thermal,
 	return 0;
 }
 
-static int int3400_thermal_get_mode(struct thermal_zone_device *thermal,
-				enum thermal_device_mode *mode)
-{
-	struct int3400_thermal_priv *priv = thermal->devdata;
-
-	if (!priv)
-		return -EINVAL;
-
-	*mode = priv->mode;
-
-	return 0;
-}
-
 static int int3400_thermal_set_mode(struct thermal_zone_device *thermal,
 				enum thermal_device_mode mode)
 {
 	struct int3400_thermal_priv *priv = thermal->devdata;
-	bool enable;
 	int result = 0;
 
 	if (!priv)
 		return -EINVAL;
 
-	if (mode == THERMAL_DEVICE_ENABLED)
-		enable = true;
-	else if (mode == THERMAL_DEVICE_DISABLED)
-		enable = false;
-	else
+	if (mode != THERMAL_DEVICE_ENABLED &&
+	    mode != THERMAL_DEVICE_DISABLED)
 		return -EINVAL;
 
-	if (enable != priv->mode) {
-		priv->mode = enable;
+	if (mode != thermal->mode) {
 		result = int3400_thermal_run_osc(priv->adev->handle,
-						 priv->current_uuid_index,
-						 enable);
+						priv->current_uuid_index,
+						mode == THERMAL_DEVICE_ENABLED);
 	}
 	return result;
 }
 
 static struct thermal_zone_device_ops int3400_thermal_ops = {
 	.get_temp = int3400_thermal_get_temp,
-	.get_mode = int3400_thermal_get_mode,
 	.set_mode = int3400_thermal_set_mode,
 };
 
diff --git a/drivers/thermal/intel/intel_quark_dts_thermal.c b/drivers/thermal/intel/intel_quark_dts_thermal.c
index d704fc104cfd..c4879b4bfbf1 100644
--- a/drivers/thermal/intel/intel_quark_dts_thermal.c
+++ b/drivers/thermal/intel/intel_quark_dts_thermal.c
@@ -103,7 +103,6 @@ struct soc_sensor_entry {
 	bool locked;
 	u32 store_ptps;
 	u32 store_dts_enable;
-	enum thermal_device_mode mode;
 	struct thermal_zone_device *tzone;
 };
 
@@ -128,7 +127,7 @@ static int soc_dts_enable(struct thermal_zone_device *tzd)
 		return ret;
 
 	if (out & QRK_DTS_ENABLE_BIT) {
-		aux_entry->mode = THERMAL_DEVICE_ENABLED;
+		tzd->mode = THERMAL_DEVICE_ENABLED;
 		return 0;
 	}
 
@@ -139,9 +138,9 @@ static int soc_dts_enable(struct thermal_zone_device *tzd)
 		if (ret)
 			return ret;
 
-		aux_entry->mode = THERMAL_DEVICE_ENABLED;
+		tzd->mode = THERMAL_DEVICE_ENABLED;
 	} else {
-		aux_entry->mode = THERMAL_DEVICE_DISABLED;
+		tzd->mode = THERMAL_DEVICE_DISABLED;
 		pr_info("DTS is locked. Cannot enable DTS\n");
 		ret = -EPERM;
 	}
@@ -161,7 +160,7 @@ static int soc_dts_disable(struct thermal_zone_device *tzd)
 		return ret;
 
 	if (!(out & QRK_DTS_ENABLE_BIT)) {
-		aux_entry->mode = THERMAL_DEVICE_DISABLED;
+		tzd->mode = THERMAL_DEVICE_DISABLED;
 		return 0;
 	}
 
@@ -173,9 +172,9 @@ static int soc_dts_disable(struct thermal_zone_device *tzd)
 		if (ret)
 			return ret;
 
-		aux_entry->mode = THERMAL_DEVICE_DISABLED;
+		tzd->mode = THERMAL_DEVICE_DISABLED;
 	} else {
-		aux_entry->mode = THERMAL_DEVICE_ENABLED;
+		tzd->mode = THERMAL_DEVICE_ENABLED;
 		pr_info("DTS is locked. Cannot disable DTS\n");
 		ret = -EPERM;
 	}
@@ -309,14 +308,6 @@ static int sys_get_curr_temp(struct thermal_zone_device *tzd,
 	return 0;
 }
 
-static int sys_get_mode(struct thermal_zone_device *tzd,
-				enum thermal_device_mode *mode)
-{
-	struct soc_sensor_entry *aux_entry = tzd->devdata;
-	*mode = aux_entry->mode;
-	return 0;
-}
-
 static int sys_set_mode(struct thermal_zone_device *tzd,
 				enum thermal_device_mode mode)
 {
@@ -338,7 +329,6 @@ static struct thermal_zone_device_ops tzone_ops = {
 	.get_trip_type = sys_get_trip_type,
 	.set_trip_temp = sys_set_trip_temp,
 	.get_crit_temp = sys_get_crit_temp,
-	.get_mode = sys_get_mode,
 	.set_mode = sys_set_mode,
 };
 
diff --git a/drivers/thermal/of-thermal.c b/drivers/thermal/of-thermal.c
index 874a47d6923f..863b89546f81 100644
--- a/drivers/thermal/of-thermal.c
+++ b/drivers/thermal/of-thermal.c
@@ -51,7 +51,6 @@ struct __thermal_bind_params {
 
 /**
  * struct __thermal_zone - internal representation of a thermal zone
- * @mode: current thermal zone device mode (enabled/disabled)
  * @passive_delay: polling interval while passive cooling is activated
  * @polling_delay: zone polling interval
  * @slope: slope of the temperature adjustment curve
@@ -65,7 +64,6 @@ struct __thermal_bind_params {
  */
 
 struct __thermal_zone {
-	enum thermal_device_mode mode;
 	int passive_delay;
 	int polling_delay;
 	int slope;
@@ -269,23 +267,11 @@ static int of_thermal_unbind(struct thermal_zone_device *thermal,
 	return 0;
 }
 
-static int of_thermal_get_mode(struct thermal_zone_device *tz,
-			       enum thermal_device_mode *mode)
-{
-	struct __thermal_zone *data = tz->devdata;
-
-	*mode = data->mode;
-
-	return 0;
-}
-
 static int of_thermal_set_mode(struct thermal_zone_device *tz,
 			       enum thermal_device_mode mode)
 {
 	struct __thermal_zone *data = tz->devdata;
 
-	mutex_lock(&tz->lock);
-
 	if (mode == THERMAL_DEVICE_ENABLED) {
 		tz->polling_delay = data->polling_delay;
 		tz->passive_delay = data->passive_delay;
@@ -294,11 +280,6 @@ static int of_thermal_set_mode(struct thermal_zone_device *tz,
 		tz->passive_delay = 0;
 	}
 
-	mutex_unlock(&tz->lock);
-
-	data->mode = mode;
-	thermal_zone_device_update(tz, THERMAL_EVENT_UNSPECIFIED);
-
 	return 0;
 }
 
@@ -393,7 +374,6 @@ static int of_thermal_get_crit_temp(struct thermal_zone_device *tz,
 }
 
 static struct thermal_zone_device_ops of_thermal_ops = {
-	.get_mode = of_thermal_get_mode,
 	.set_mode = of_thermal_set_mode,
 
 	.get_trip_type = of_thermal_get_trip_type,
@@ -553,8 +533,14 @@ thermal_zone_of_sensor_register(struct device *dev, int sensor_id, void *data,
 		if (id == sensor_id) {
 			tzd = thermal_zone_of_add_sensor(child, sensor_np,
 							 data, ops);
-			if (!IS_ERR(tzd))
+			if (!IS_ERR(tzd)) {
+				mutex_lock(&tzd->lock);
 				tzd->ops->set_mode(tzd, THERMAL_DEVICE_ENABLED);
+				tzd->mode = THERMAL_DEVICE_ENABLED;
+				mutex_unlock(&tzd->lock);
+				thermal_zone_device_update(tzd,
+						THERMAL_EVENT_UNSPECIFIED);
+			}
 
 			of_node_put(child);
 			goto exit;
@@ -979,7 +965,6 @@ __init *thermal_of_build_thermal_zone(struct device_node *np)
 
 finish:
 	of_node_put(child);
-	tz->mode = THERMAL_DEVICE_DISABLED;
 
 	return tz;
 
@@ -1120,6 +1105,7 @@ int __init of_parse_thermal_zones(void)
 		/* these two are left for temperature drivers to use */
 		tzp->slope = tz->slope;
 		tzp->offset = tz->offset;
+		tzp->initial_mode = THERMAL_DEVICE_DISABLED;
 
 		zone = thermal_zone_device_register(child->name, tz->ntrips,
 						    mask, tz,
diff --git a/drivers/thermal/thermal_core.c b/drivers/thermal/thermal_core.c
index c06550930979..5ff98fcc0f6a 100644
--- a/drivers/thermal/thermal_core.c
+++ b/drivers/thermal/thermal_core.c
@@ -463,6 +463,43 @@ static void thermal_zone_device_reset(struct thermal_zone_device *tz)
 	thermal_zone_device_init(tz);
 }
 
+enum thermal_device_mode
+thermal_zone_device_get_mode(struct thermal_zone_device *tz)
+{
+	enum thermal_device_mode mode;
+
+	mutex_lock(&tz->lock);
+
+	mode = tz->mode;
+
+	mutex_unlock(&tz->lock);
+
+	return mode;
+}
+
+int thermal_zone_device_set_mode(struct thermal_zone_device *tz,
+				 enum thermal_device_mode mode)
+{
+	int ret = 0;
+
+	if (mode != THERMAL_DEVICE_DISABLED &&
+	    mode != THERMAL_DEVICE_ENABLED)
+		return -EINVAL;
+
+	mutex_lock(&tz->lock);
+
+	if (tz->ops->set_mode)
+		ret = tz->ops->set_mode(tz, mode);
+
+	tz->mode = mode;
+
+	mutex_unlock(&tz->lock);
+
+	thermal_zone_device_update(tz, THERMAL_EVENT_UNSPECIFIED);
+
+	return ret;
+}
+
 void thermal_zone_device_update(struct thermal_zone_device *tz,
 				enum thermal_notify_event event)
 {
@@ -1344,6 +1381,9 @@ thermal_zone_device_register(const char *type, int trips, int mask,
 	if (atomic_cmpxchg(&tz->need_update, 1, 0))
 		thermal_zone_device_update(tz, THERMAL_EVENT_UNSPECIFIED);
 
+	if (tzp)
+		thermal_zone_device_set_mode(tz, tzp->initial_mode);
+
 	return tz;
 
 unregister:
@@ -1473,9 +1513,7 @@ static int thermal_pm_notify(struct notifier_block *nb,
 	case PM_POST_SUSPEND:
 		atomic_set(&in_suspend, 0);
 		list_for_each_entry(tz, &thermal_tz_list, node) {
-			tz_mode = THERMAL_DEVICE_ENABLED;
-			if (tz->ops->get_mode)
-				tz->ops->get_mode(tz, &tz_mode);
+			tz_mode = thermal_zone_device_get_mode(tz);
 
 			if (tz_mode == THERMAL_DEVICE_DISABLED)
 				continue;
diff --git a/drivers/thermal/thermal_core.h b/drivers/thermal/thermal_core.h
index c95689586e19..8e561bac3133 100644
--- a/drivers/thermal/thermal_core.h
+++ b/drivers/thermal/thermal_core.h
@@ -141,6 +141,22 @@ thermal_cooling_device_stats_update(struct thermal_cooling_device *cdev,
 				    unsigned long new_state) {}
 #endif /* CONFIG_THERMAL_STATISTICS */
 
+enum thermal_device_mode
+thermal_zone_device_get_mode(struct thermal_zone_device *tz);
+
+int thermal_zone_device_set_mode(struct thermal_zone_device *tz,
+				 enum thermal_device_mode mode);
+
+static inline int thermal_zone_device_enable(struct thermal_zone_device *tz)
+{
+	return thermal_zone_device_set_mode(tz, THERMAL_DEVICE_ENABLED);
+}
+
+static inline int thermal_zone_device_disable(struct thermal_zone_device *tz)
+{
+	return thermal_zone_device_set_mode(tz, THERMAL_DEVICE_DISABLED);
+}
+
 /* device tree support */
 #ifdef CONFIG_THERMAL_OF
 int of_parse_thermal_zones(void);
diff --git a/drivers/thermal/thermal_sysfs.c b/drivers/thermal/thermal_sysfs.c
index aa99edb4dff7..cbb27b3c96d2 100644
--- a/drivers/thermal/thermal_sysfs.c
+++ b/drivers/thermal/thermal_sysfs.c
@@ -50,14 +50,8 @@ mode_show(struct device *dev, struct device_attribute *attr, char *buf)
 {
 	struct thermal_zone_device *tz = to_thermal_zone(dev);
 	enum thermal_device_mode mode;
-	int result;
-
-	if (!tz->ops->get_mode)
-		return -EPERM;
 
-	result = tz->ops->get_mode(tz, &mode);
-	if (result)
-		return result;
+	mode = thermal_zone_device_get_mode(tz);
 
 	return sprintf(buf, "%s\n", mode == THERMAL_DEVICE_ENABLED ? "enabled"
 		       : "disabled");
@@ -74,9 +68,9 @@ mode_store(struct device *dev, struct device_attribute *attr,
 		return -EPERM;
 
 	if (!strncmp(buf, "enabled", sizeof("enabled") - 1))
-		result = tz->ops->set_mode(tz, THERMAL_DEVICE_ENABLED);
+		result = thermal_zone_device_enable(tz);
 	else if (!strncmp(buf, "disabled", sizeof("disabled") - 1))
-		result = tz->ops->set_mode(tz, THERMAL_DEVICE_DISABLED);
+		result = thermal_zone_device_disable(tz);
 	else
 		result = -EINVAL;
 
@@ -428,30 +422,13 @@ static struct attribute_group thermal_zone_attribute_group = {
 	.attrs = thermal_zone_dev_attrs,
 };
 
-/* We expose mode only if .get_mode is present */
 static struct attribute *thermal_zone_mode_attrs[] = {
 	&dev_attr_mode.attr,
 	NULL,
 };
 
-static umode_t thermal_zone_mode_is_visible(struct kobject *kobj,
-					    struct attribute *attr,
-					    int attrno)
-{
-	struct device *dev = container_of(kobj, struct device, kobj);
-	struct thermal_zone_device *tz;
-
-	tz = container_of(dev, struct thermal_zone_device, device);
-
-	if (tz->ops->get_mode)
-		return attr->mode;
-
-	return 0;
-}
-
 static struct attribute_group thermal_zone_mode_attribute_group = {
 	.attrs = thermal_zone_mode_attrs,
-	.is_visible = thermal_zone_mode_is_visible,
 };
 
 /* We expose passive only if passive trips are present */
diff --git a/include/linux/thermal.h b/include/linux/thermal.h
index 216185bb3014..da4141697e2e 100644
--- a/include/linux/thermal.h
+++ b/include/linux/thermal.h
@@ -76,8 +76,6 @@ struct thermal_zone_device_ops {
 		       struct thermal_cooling_device *);
 	int (*get_temp) (struct thermal_zone_device *, int *);
 	int (*set_trips) (struct thermal_zone_device *, int, int);
-	int (*get_mode) (struct thermal_zone_device *,
-			 enum thermal_device_mode *);
 	int (*set_mode) (struct thermal_zone_device *,
 		enum thermal_device_mode);
 	int (*get_trip_type) (struct thermal_zone_device *, int,
@@ -128,6 +126,7 @@ struct thermal_cooling_device {
  * @trip_temp_attrs:	attributes for trip points for sysfs: trip temperature
  * @trip_type_attrs:	attributes for trip points for sysfs: trip type
  * @trip_hyst_attrs:	attributes for trip points for sysfs: trip hysteresis
+ * @mode:		current mode of this thermal zone
  * @devdata:	private pointer for device private data
  * @trips:	number of trip points the thermal zone supports
  * @trips_disabled;	bitmap for disabled trips
@@ -170,6 +169,7 @@ struct thermal_zone_device {
 	struct thermal_attr *trip_temp_attrs;
 	struct thermal_attr *trip_type_attrs;
 	struct thermal_attr *trip_hyst_attrs;
+	enum thermal_device_mode mode;
 	void *devdata;
 	int trips;
 	unsigned long trips_disabled;	/* bitmap for disabled trips */
@@ -264,6 +264,9 @@ struct thermal_zone_params {
 	int num_tbps;	/* Number of tbp entries */
 	struct thermal_bind_params *tbp;
 
+	/* Initial mode of this thermal zone device */
+	enum thermal_device_mode initial_mode;
+
 	/*
 	 * Sustainable power (heat) that this thermal zone can dissipate in
 	 * mW
-- 
2.17.1


^ permalink raw reply	[flat|nested] 63+ messages in thread

* [RFC v3 2/2] thermal: core: Stop polling DISABLED thermal devices
  2020-04-17 16:20         ` [RFC v3 0/2] Stop monitoring disabled devices Andrzej Pietrasiewicz
  2020-04-17 16:20           ` [RFC v3 1/2] thermal: core: Let thermal zone device's mode be stored in its struct Andrzej Pietrasiewicz
@ 2020-04-17 16:20           ` Andrzej Pietrasiewicz
  2020-04-19 13:50           ` [RFC v3 1/2] thermal: core: Let thermal zone device's mode be stored in its struct Peter Kästle
  2 siblings, 0 replies; 63+ messages in thread
From: Andrzej Pietrasiewicz @ 2020-04-17 16:20 UTC (permalink / raw)
  To: linux-pm
  Cc: Zhang Rui, Rafael J . Wysocki, Len Brown, Jiri Pirko,
	Ido Schimmel, David S . Miller, Peter Kaestle, Darren Hart,
	Andy Shevchenko, Support Opensource, Daniel Lezcano,
	Amit Kucheria, Shawn Guo, Sascha Hauer, Pengutronix Kernel Team,
	Fabio Estevam, NXP Linux Team, Allison Randal, Enrico Weigelt,
	Gayatri Kammela, Thomas Gleixner, linux-acpi, netdev,
	platform-driver-x86, linux-arm-kernel, kernel,
	Andrzej Pietrasiewicz, Barlomiej Zolnierkiewicz

Polling DISABLED devices is not desired, as all such "disabled" devices
are meant to be handled by userspace. This patch introduces and uses
should_stop_polling() to decide whether the device should be polled or not.

Signed-off-by: Andrzej Pietrasiewicz <andrzej.p@collabora.com>
---
 drivers/thermal/thermal_core.c | 16 ++++++++++++++--
 1 file changed, 14 insertions(+), 2 deletions(-)

diff --git a/drivers/thermal/thermal_core.c b/drivers/thermal/thermal_core.c
index 5ff98fcc0f6a..36abdc9ce1bb 100644
--- a/drivers/thermal/thermal_core.c
+++ b/drivers/thermal/thermal_core.c
@@ -305,13 +305,22 @@ static void thermal_zone_device_set_polling(struct thermal_zone_device *tz,
 		cancel_delayed_work(&tz->poll_queue);
 }
 
+static inline bool should_stop_polling(struct thermal_zone_device *tz)
+{
+	return thermal_zone_device_get_mode(tz) == THERMAL_DEVICE_DISABLED;
+}
+
 static void monitor_thermal_zone(struct thermal_zone_device *tz)
 {
+	bool stop;
+
+	stop = should_stop_polling(tz);
+
 	mutex_lock(&tz->lock);
 
-	if (tz->passive)
+	if (!stop && tz->passive)
 		thermal_zone_device_set_polling(tz, tz->passive_delay);
-	else if (tz->polling_delay)
+	else if (!stop && tz->polling_delay)
 		thermal_zone_device_set_polling(tz, tz->polling_delay);
 	else
 		thermal_zone_device_set_polling(tz, 0);
@@ -505,6 +514,9 @@ void thermal_zone_device_update(struct thermal_zone_device *tz,
 {
 	int count;
 
+	if (should_stop_polling(tz))
+		return;
+
 	if (atomic_read(&in_suspend))
 		return;
 
-- 
2.17.1


^ permalink raw reply	[flat|nested] 63+ messages in thread

* Re: [RFC 0/8] Stop monitoring disabled devices
  2020-04-15 10:40       ` Bartlomiej Zolnierkiewicz
@ 2020-04-17 16:23         ` Andrzej Pietrasiewicz
  2020-04-19 11:42           ` Bartlomiej Zolnierkiewicz
  2020-04-17 21:11         ` Peter Kästle
  1 sibling, 1 reply; 63+ messages in thread
From: Andrzej Pietrasiewicz @ 2020-04-17 16:23 UTC (permalink / raw)
  To: Bartlomiej Zolnierkiewicz
  Cc: Daniel Lezcano, linux-pm, Zhang Rui, Rafael J . Wysocki,
	Len Brown, Jiri Pirko, Ido Schimmel, David S . Miller,
	Peter Kaestle, Darren Hart, Andy Shevchenko, Support Opensource,
	Amit Kucheria, Shawn Guo, Sascha Hauer, Pengutronix Kernel Team,
	Fabio Estevam, NXP Linux Team, Allison Randal, Enrico Weigelt,
	Gayatri Kammela, Thomas Gleixner, linux-acpi, netdev,
	platform-driver-x86, linux-arm-kernel, kernel

Hi Barlomiej,

>> Thanks for feedback.
>>
>> Anyone else?
> 
> Yes. :)
> 
> Please take a look at the following patchset (which I'm reviving currently):
> 
> 	https://lkml.org/lkml/2018/10/17/926
> 
> It overlaps partially with your work so we need to coordinate our efforts.
> 

I've just sent a v3. After addressing your and Daniel's comments my series
now looks pretty compact. Let's see if there's more feedback. Is your work on
reviving the above mentioned 2018 series ready?

Andrzej

^ permalink raw reply	[flat|nested] 63+ messages in thread

* Re: [RFC v3 1/2] thermal: core: Let thermal zone device's mode be stored in its struct
  2020-04-17 16:20           ` [RFC v3 1/2] thermal: core: Let thermal zone device's mode be stored in its struct Andrzej Pietrasiewicz
@ 2020-04-17 20:44             ` Andy Shevchenko
  2020-04-19 11:38             ` Bartlomiej Zolnierkiewicz
  2020-05-23 21:24             ` Daniel Lezcano
  2 siblings, 0 replies; 63+ messages in thread
From: Andy Shevchenko @ 2020-04-17 20:44 UTC (permalink / raw)
  To: Andrzej Pietrasiewicz
  Cc: Linux PM, Zhang Rui, Rafael J . Wysocki, Len Brown, Jiri Pirko,
	Ido Schimmel, David S . Miller, Peter Kaestle, Darren Hart,
	Andy Shevchenko, Support Opensource, Daniel Lezcano,
	Amit Kucheria, Shawn Guo, Sascha Hauer, Pengutronix Kernel Team,
	Fabio Estevam, NXP Linux Team, Allison Randal, Enrico Weigelt,
	Gayatri Kammela, Thomas Gleixner, ACPI Devel Maling List, netdev,
	Platform Driver, linux-arm Mailing List, kernel,
	Barlomiej Zolnierkiewicz

On Fri, Apr 17, 2020 at 7:20 PM Andrzej Pietrasiewicz
<andrzej.p@collabora.com> wrote:
>
> Thermal zone devices' mode is stored in individual drivers. This patch
> changes it so that mode is stored in struct thermal_zone_device instead.
>
> As a result all driver-specific variables storing the mode are not needed
> and are removed. Consequently, the get_mode() implementations have nothing
> to operate on and need to be removed, too.
>
> Some thermal framework specific functions are introduced:
>
> thermal_zone_device_get_mode()
> thermal_zone_device_set_mode()
> thermal_zone_device_enable()
> thermal_zone_device_disable()
>
> thermal_zone_device_get_mode() and its "set" counterpart take tzd's lock
> and the "set" calls driver's set_mode() if provided, so the latter must
> not take this lock again. At the end of the "set"
> thermal_zone_device_update() is called so drivers don't need to repeat this
> invocation in their specific set_mode() implementations.
>
> The scope of the above 4 functions is purposedly limited to the thermal
> framework and drivers are not supposed to call them. This encapsulation
> does not fully work at the moment for some drivers, though:
>

> - platform/x86/acerhdf.c

Acked-by: Andy Shevchenko <andy.shevchenko@gmail.com>
for PDx86 bits.

> - drivers/thermal/imx_thermal.c
> - drivers/thermal/intel/intel_quark_dts_thermal.c
> - drivers/thermal/of-thermal.c
>
> and they manipulate struct thermal_zone_device's members directly.
>
> struct thermal_zone_params gains a new member called initial_mode, which
> is used to set tzd's mode at registration time.
>
> The sysfs "mode" attribute is always exposed from now on, because all
> thermal zone devices now have their get_mode() implemented at the generic
> level and it is always available. Exposing "mode" doesn't hurt the drivers
> which don't provide their own set_mode(), because writing to "mode" will
> result in -EPERM, as expected.
>
> Signed-off-by: Andrzej Pietrasiewicz <andrzej.p@collabora.com>
> ---
>  drivers/acpi/thermal.c                        | 46 +++++----------
>  .../ethernet/mellanox/mlxsw/core_thermal.c    | 57 ++++---------------
>  drivers/platform/x86/acerhdf.c                | 17 +-----
>  drivers/thermal/da9062-thermal.c              | 16 ++----
>  drivers/thermal/imx_thermal.c                 | 29 +++-------
>  .../intel/int340x_thermal/int3400_thermal.c   | 30 ++--------
>  .../thermal/intel/intel_quark_dts_thermal.c   | 22 ++-----
>  drivers/thermal/of-thermal.c                  | 30 +++-------
>  drivers/thermal/thermal_core.c                | 44 +++++++++++++-
>  drivers/thermal/thermal_core.h                | 16 ++++++
>  drivers/thermal/thermal_sysfs.c               | 29 +---------
>  include/linux/thermal.h                       |  7 ++-
>  12 files changed, 125 insertions(+), 218 deletions(-)
>
> diff --git a/drivers/acpi/thermal.c b/drivers/acpi/thermal.c
> index 19067a5e5293..67bc263332a5 100644
> --- a/drivers/acpi/thermal.c
> +++ b/drivers/acpi/thermal.c
> @@ -172,7 +172,6 @@ struct acpi_thermal {
>         struct acpi_thermal_trips trips;
>         struct acpi_handle_list devices;
>         struct thermal_zone_device *thermal_zone;
> -       int tz_enabled;
>         int kelvin_offset;      /* in millidegrees */
>         struct work_struct thermal_check_work;
>  };
> @@ -500,7 +499,7 @@ static void acpi_thermal_check(void *data)
>  {
>         struct acpi_thermal *tz = data;
>
> -       if (!tz->tz_enabled)
> +       if (tz->thermal_zone->mode != THERMAL_DEVICE_ENABLED)
>                 return;
>
>         thermal_zone_device_update(tz->thermal_zone,
> @@ -526,46 +525,29 @@ static int thermal_get_temp(struct thermal_zone_device *thermal, int *temp)
>         return 0;
>  }
>
> -static int thermal_get_mode(struct thermal_zone_device *thermal,
> -                               enum thermal_device_mode *mode)
> -{
> -       struct acpi_thermal *tz = thermal->devdata;
> -
> -       if (!tz)
> -               return -EINVAL;
> -
> -       *mode = tz->tz_enabled ? THERMAL_DEVICE_ENABLED :
> -               THERMAL_DEVICE_DISABLED;
> -
> -       return 0;
> -}
> -
>  static int thermal_set_mode(struct thermal_zone_device *thermal,
>                                 enum thermal_device_mode mode)
>  {
>         struct acpi_thermal *tz = thermal->devdata;
> -       int enable;
>
>         if (!tz)
>                 return -EINVAL;
>
> +       if (mode != THERMAL_DEVICE_DISABLED &&
> +           mode != THERMAL_DEVICE_ENABLED)
> +               return -EINVAL;
> +
>         /*
>          * enable/disable thermal management from ACPI thermal driver
>          */
> -       if (mode == THERMAL_DEVICE_ENABLED)
> -               enable = 1;
> -       else if (mode == THERMAL_DEVICE_DISABLED) {
> -               enable = 0;
> +       if (mode == THERMAL_DEVICE_DISABLED)
>                 pr_warn("thermal zone will be disabled\n");
> -       } else
> -               return -EINVAL;
>
> -       if (enable != tz->tz_enabled) {
> -               tz->tz_enabled = enable;
> +       if (mode != thermal->mode) {
>                 ACPI_DEBUG_PRINT((ACPI_DB_INFO,
>                         "%s kernel ACPI thermal control\n",
> -                       tz->tz_enabled ? "Enable" : "Disable"));
> -               acpi_thermal_check(tz);
> +                       mode == THERMAL_DEVICE_ENABLED ?
> +                       "Enable" : "Disable"));
>         }
>         return 0;
>  }
> @@ -856,7 +838,6 @@ static struct thermal_zone_device_ops acpi_thermal_zone_ops = {
>         .bind = acpi_thermal_bind_cooling_device,
>         .unbind = acpi_thermal_unbind_cooling_device,
>         .get_temp = thermal_get_temp,
> -       .get_mode = thermal_get_mode,
>         .set_mode = thermal_set_mode,
>         .get_trip_type = thermal_get_trip_type,
>         .get_trip_temp = thermal_get_trip_temp,
> @@ -870,6 +851,9 @@ static int acpi_thermal_register_thermal_zone(struct acpi_thermal *tz)
>         int trips = 0;
>         int result;
>         acpi_status status;
> +       struct thermal_zone_params prms = {
> +               .initial_mode = THERMAL_DEVICE_ENABLED,
> +       };
>         int i;
>
>         if (tz->trips.critical.flags.valid)
> @@ -887,13 +871,13 @@ static int acpi_thermal_register_thermal_zone(struct acpi_thermal *tz)
>         if (tz->trips.passive.flags.valid)
>                 tz->thermal_zone =
>                         thermal_zone_device_register("acpitz", trips, 0, tz,
> -                                               &acpi_thermal_zone_ops, NULL,
> +                                               &acpi_thermal_zone_ops, &prms,
>                                                      tz->trips.passive.tsp*100,
>                                                      tz->polling_frequency*100);
>         else
>                 tz->thermal_zone =
>                         thermal_zone_device_register("acpitz", trips, 0, tz,
> -                                               &acpi_thermal_zone_ops, NULL,
> +                                               &acpi_thermal_zone_ops, &prms,
>                                                 0, tz->polling_frequency*100);
>         if (IS_ERR(tz->thermal_zone))
>                 return -ENODEV;
> @@ -913,8 +897,6 @@ static int acpi_thermal_register_thermal_zone(struct acpi_thermal *tz)
>         if (ACPI_FAILURE(status))
>                 return -ENODEV;
>
> -       tz->tz_enabled = 1;
> -
>         dev_info(&tz->device->dev, "registered as thermal_zone%d\n",
>                  tz->thermal_zone->id);
>         return 0;
> diff --git a/drivers/net/ethernet/mellanox/mlxsw/core_thermal.c b/drivers/net/ethernet/mellanox/mlxsw/core_thermal.c
> index ce0a6837daa3..50518048b86d 100644
> --- a/drivers/net/ethernet/mellanox/mlxsw/core_thermal.c
> +++ b/drivers/net/ethernet/mellanox/mlxsw/core_thermal.c
> @@ -98,7 +98,6 @@ struct mlxsw_thermal_module {
>         struct mlxsw_thermal *parent;
>         struct thermal_zone_device *tzdev;
>         struct mlxsw_thermal_trip trips[MLXSW_THERMAL_NUM_TRIPS];
> -       enum thermal_device_mode mode;
>         int module; /* Module or gearbox number */
>  };
>
> @@ -110,7 +109,6 @@ struct mlxsw_thermal {
>         struct thermal_cooling_device *cdevs[MLXSW_MFCR_PWMS_MAX];
>         u8 cooling_levels[MLXSW_THERMAL_MAX_STATE + 1];
>         struct mlxsw_thermal_trip trips[MLXSW_THERMAL_NUM_TRIPS];
> -       enum thermal_device_mode mode;
>         struct mlxsw_thermal_module *tz_module_arr;
>         u8 tz_module_num;
>         struct mlxsw_thermal_module *tz_gearbox_arr;
> @@ -277,33 +275,16 @@ static int mlxsw_thermal_unbind(struct thermal_zone_device *tzdev,
>         return 0;
>  }
>
> -static int mlxsw_thermal_get_mode(struct thermal_zone_device *tzdev,
> -                                 enum thermal_device_mode *mode)
> -{
> -       struct mlxsw_thermal *thermal = tzdev->devdata;
> -
> -       *mode = thermal->mode;
> -
> -       return 0;
> -}
> -
>  static int mlxsw_thermal_set_mode(struct thermal_zone_device *tzdev,
>                                   enum thermal_device_mode mode)
>  {
>         struct mlxsw_thermal *thermal = tzdev->devdata;
>
> -       mutex_lock(&tzdev->lock);
> -
>         if (mode == THERMAL_DEVICE_ENABLED)
>                 tzdev->polling_delay = thermal->polling_delay;
>         else
>                 tzdev->polling_delay = 0;
>
> -       mutex_unlock(&tzdev->lock);
> -
> -       thermal->mode = mode;
> -       thermal_zone_device_update(tzdev, THERMAL_EVENT_UNSPECIFIED);
> -
>         return 0;
>  }
>
> @@ -407,7 +388,6 @@ static int mlxsw_thermal_trend_get(struct thermal_zone_device *tzdev,
>  static struct thermal_zone_device_ops mlxsw_thermal_ops = {
>         .bind = mlxsw_thermal_bind,
>         .unbind = mlxsw_thermal_unbind,
> -       .get_mode = mlxsw_thermal_get_mode,
>         .set_mode = mlxsw_thermal_set_mode,
>         .get_temp = mlxsw_thermal_get_temp,
>         .get_trip_type  = mlxsw_thermal_get_trip_type,
> @@ -466,34 +446,17 @@ static int mlxsw_thermal_module_unbind(struct thermal_zone_device *tzdev,
>         return err;
>  }
>
> -static int mlxsw_thermal_module_mode_get(struct thermal_zone_device *tzdev,
> -                                        enum thermal_device_mode *mode)
> -{
> -       struct mlxsw_thermal_module *tz = tzdev->devdata;
> -
> -       *mode = tz->mode;
> -
> -       return 0;
> -}
> -
>  static int mlxsw_thermal_module_mode_set(struct thermal_zone_device *tzdev,
>                                          enum thermal_device_mode mode)
>  {
>         struct mlxsw_thermal_module *tz = tzdev->devdata;
>         struct mlxsw_thermal *thermal = tz->parent;
>
> -       mutex_lock(&tzdev->lock);
> -
>         if (mode == THERMAL_DEVICE_ENABLED)
>                 tzdev->polling_delay = thermal->polling_delay;
>         else
>                 tzdev->polling_delay = 0;
>
> -       mutex_unlock(&tzdev->lock);
> -
> -       tz->mode = mode;
> -       thermal_zone_device_update(tzdev, THERMAL_EVENT_UNSPECIFIED);
> -
>         return 0;
>  }
>
> @@ -596,7 +559,6 @@ mlxsw_thermal_module_trip_hyst_set(struct thermal_zone_device *tzdev, int trip,
>  static struct thermal_zone_device_ops mlxsw_thermal_module_ops = {
>         .bind           = mlxsw_thermal_module_bind,
>         .unbind         = mlxsw_thermal_module_unbind,
> -       .get_mode       = mlxsw_thermal_module_mode_get,
>         .set_mode       = mlxsw_thermal_module_mode_set,
>         .get_temp       = mlxsw_thermal_module_temp_get,
>         .get_trip_type  = mlxsw_thermal_module_trip_type_get,
> @@ -635,7 +597,6 @@ static int mlxsw_thermal_gearbox_temp_get(struct thermal_zone_device *tzdev,
>  static struct thermal_zone_device_ops mlxsw_thermal_gearbox_ops = {
>         .bind           = mlxsw_thermal_module_bind,
>         .unbind         = mlxsw_thermal_module_unbind,
> -       .get_mode       = mlxsw_thermal_module_mode_get,
>         .set_mode       = mlxsw_thermal_module_mode_set,
>         .get_temp       = mlxsw_thermal_gearbox_temp_get,
>         .get_trip_type  = mlxsw_thermal_module_trip_type_get,
> @@ -749,6 +710,9 @@ static const struct thermal_cooling_device_ops mlxsw_cooling_ops = {
>  static int
>  mlxsw_thermal_module_tz_init(struct mlxsw_thermal_module *module_tz)
>  {
> +       struct thermal_zone_params tzp = {
> +               .initial_mode = THERMAL_DEVICE_ENABLED,
> +       };
>         char tz_name[MLXSW_THERMAL_ZONE_MAX_NAME];
>         int err;
>
> @@ -759,13 +723,12 @@ mlxsw_thermal_module_tz_init(struct mlxsw_thermal_module *module_tz)
>                                                         MLXSW_THERMAL_TRIP_MASK,
>                                                         module_tz,
>                                                         &mlxsw_thermal_module_ops,
> -                                                       NULL, 0, 0);
> +                                                       &tzp, 0, 0);
>         if (IS_ERR(module_tz->tzdev)) {
>                 err = PTR_ERR(module_tz->tzdev);
>                 return err;
>         }
>
> -       module_tz->mode = THERMAL_DEVICE_ENABLED;
>         return 0;
>  }
>
> @@ -868,6 +831,9 @@ mlxsw_thermal_modules_fini(struct mlxsw_thermal *thermal)
>  static int
>  mlxsw_thermal_gearbox_tz_init(struct mlxsw_thermal_module *gearbox_tz)
>  {
> +       struct thermal_zone_params tzp = {
> +               .initial_mode = THERMAL_DEVICE_ENABLED,
> +       };
>         char tz_name[MLXSW_THERMAL_ZONE_MAX_NAME];
>
>         snprintf(tz_name, sizeof(tz_name), "mlxsw-gearbox%d",
> @@ -877,11 +843,10 @@ mlxsw_thermal_gearbox_tz_init(struct mlxsw_thermal_module *gearbox_tz)
>                                                 MLXSW_THERMAL_TRIP_MASK,
>                                                 gearbox_tz,
>                                                 &mlxsw_thermal_gearbox_ops,
> -                                               NULL, 0, 0);
> +                                               &tzp, 0, 0);
>         if (IS_ERR(gearbox_tz->tzdev))
>                 return PTR_ERR(gearbox_tz->tzdev);
>
> -       gearbox_tz->mode = THERMAL_DEVICE_ENABLED;
>         return 0;
>  }
>
> @@ -960,6 +925,9 @@ int mlxsw_thermal_init(struct mlxsw_core *core,
>                        const struct mlxsw_bus_info *bus_info,
>                        struct mlxsw_thermal **p_thermal)
>  {
> +       struct thermal_zone_params tzp = {
> +               .initial_mode = THERMAL_DEVICE_ENABLED,
> +       };
>         char mfcr_pl[MLXSW_REG_MFCR_LEN] = { 0 };
>         enum mlxsw_reg_mfcr_pwm_frequency freq;
>         struct device *dev = bus_info->dev;
> @@ -1034,7 +1002,7 @@ int mlxsw_thermal_init(struct mlxsw_core *core,
>                                                       MLXSW_THERMAL_TRIP_MASK,
>                                                       thermal,
>                                                       &mlxsw_thermal_ops,
> -                                                     NULL, 0,
> +                                                     &tzp, 0,
>                                                       thermal->polling_delay);
>         if (IS_ERR(thermal->tzdev)) {
>                 err = PTR_ERR(thermal->tzdev);
> @@ -1050,7 +1018,6 @@ int mlxsw_thermal_init(struct mlxsw_core *core,
>         if (err)
>                 goto err_unreg_modules_tzdev;
>
> -       thermal->mode = THERMAL_DEVICE_ENABLED;
>         *p_thermal = thermal;
>         return 0;
>
> diff --git a/drivers/platform/x86/acerhdf.c b/drivers/platform/x86/acerhdf.c
> index 8cc86f4e3ac1..aaf8b845be90 100644
> --- a/drivers/platform/x86/acerhdf.c
> +++ b/drivers/platform/x86/acerhdf.c
> @@ -406,22 +406,9 @@ static inline void acerhdf_enable_kernelmode(void)
>         kernelmode = 1;
>
>         thz_dev->polling_delay = interval*1000;
> -       thermal_zone_device_update(thz_dev, THERMAL_EVENT_UNSPECIFIED);
>         pr_notice("kernel mode fan control ON\n");
>  }
>
> -static int acerhdf_get_mode(struct thermal_zone_device *thermal,
> -                           enum thermal_device_mode *mode)
> -{
> -       if (verbose)
> -               pr_notice("kernel mode fan control %d\n", kernelmode);
> -
> -       *mode = (kernelmode) ? THERMAL_DEVICE_ENABLED
> -                            : THERMAL_DEVICE_DISABLED;
> -
> -       return 0;
> -}
> -
>  /*
>   * set operation mode;
>   * enabled: the thermal layer of the kernel takes care about
> @@ -488,7 +475,6 @@ static struct thermal_zone_device_ops acerhdf_dev_ops = {
>         .bind = acerhdf_bind,
>         .unbind = acerhdf_unbind,
>         .get_temp = acerhdf_get_ec_temp,
> -       .get_mode = acerhdf_get_mode,
>         .set_mode = acerhdf_set_mode,
>         .get_trip_type = acerhdf_get_trip_type,
>         .get_trip_hyst = acerhdf_get_trip_hyst,
> @@ -554,6 +540,7 @@ static int acerhdf_set_cur_state(struct thermal_cooling_device *cdev,
>
>  err_out:
>         acerhdf_revert_to_bios_mode();
> +       thz_dev->mode = THERMAL_DEVICE_DISABLED;
>         return -EINVAL;
>  }
>
> @@ -739,6 +726,8 @@ static int __init acerhdf_register_thermal(void)
>         if (IS_ERR(cl_dev))
>                 return -EINVAL;
>
> +       acerhdf_zone_params.initial_mode =
> +               kernelmode ? THERMAL_DEVICE_ENABLED : THERMAL_DEVICE_DISABLED;
>         thz_dev = thermal_zone_device_register("acerhdf", 2, 0, NULL,
>                                               &acerhdf_dev_ops,
>                                               &acerhdf_zone_params, 0,
> diff --git a/drivers/thermal/da9062-thermal.c b/drivers/thermal/da9062-thermal.c
> index c32709badeda..4bdb6f9621c1 100644
> --- a/drivers/thermal/da9062-thermal.c
> +++ b/drivers/thermal/da9062-thermal.c
> @@ -49,7 +49,6 @@ struct da9062_thermal {
>         struct da9062 *hw;
>         struct delayed_work work;
>         struct thermal_zone_device *zone;
> -       enum thermal_device_mode mode;
>         struct mutex lock; /* protection for da9062_thermal temperature */
>         int temperature;
>         int irq;
> @@ -121,14 +120,6 @@ static irqreturn_t da9062_thermal_irq_handler(int irq, void *data)
>         return IRQ_HANDLED;
>  }
>
> -static int da9062_thermal_get_mode(struct thermal_zone_device *z,
> -                                  enum thermal_device_mode *mode)
> -{
> -       struct da9062_thermal *thermal = z->devdata;
> -       *mode = thermal->mode;
> -       return 0;
> -}
> -
>  static int da9062_thermal_get_trip_type(struct thermal_zone_device *z,
>                                         int trip,
>                                         enum thermal_trip_type *type)
> @@ -181,7 +172,6 @@ static int da9062_thermal_get_temp(struct thermal_zone_device *z,
>
>  static struct thermal_zone_device_ops da9062_thermal_ops = {
>         .get_temp       = da9062_thermal_get_temp,
> -       .get_mode       = da9062_thermal_get_mode,
>         .get_trip_type  = da9062_thermal_get_trip_type,
>         .get_trip_temp  = da9062_thermal_get_trip_temp,
>  };
> @@ -199,6 +189,9 @@ MODULE_DEVICE_TABLE(of, da9062_compatible_reg_id_table);
>
>  static int da9062_thermal_probe(struct platform_device *pdev)
>  {
> +       struct thermal_zone_params tzp = {
> +               .initial_mode = THERMAL_DEVICE_ENABLED,
> +       };
>         struct da9062 *chip = dev_get_drvdata(pdev->dev.parent);
>         struct da9062_thermal *thermal;
>         unsigned int pp_tmp = DA9062_DEFAULT_POLLING_MS_PERIOD;
> @@ -233,7 +226,6 @@ static int da9062_thermal_probe(struct platform_device *pdev)
>
>         thermal->config = match->data;
>         thermal->hw = chip;
> -       thermal->mode = THERMAL_DEVICE_ENABLED;
>         thermal->dev = &pdev->dev;
>
>         INIT_DELAYED_WORK(&thermal->work, da9062_thermal_poll_on);
> @@ -241,7 +233,7 @@ static int da9062_thermal_probe(struct platform_device *pdev)
>
>         thermal->zone = thermal_zone_device_register(thermal->config->name,
>                                         1, 0, thermal,
> -                                       &da9062_thermal_ops, NULL, pp_tmp,
> +                                       &da9062_thermal_ops, &tzp, pp_tmp,
>                                         0);
>         if (IS_ERR(thermal->zone)) {
>                 dev_err(&pdev->dev, "Cannot register thermal zone device\n");
> diff --git a/drivers/thermal/imx_thermal.c b/drivers/thermal/imx_thermal.c
> index e761c9b42217..3e02323c938b 100644
> --- a/drivers/thermal/imx_thermal.c
> +++ b/drivers/thermal/imx_thermal.c
> @@ -197,7 +197,6 @@ struct imx_thermal_data {
>         struct cpufreq_policy *policy;
>         struct thermal_zone_device *tz;
>         struct thermal_cooling_device *cdev;
> -       enum thermal_device_mode mode;
>         struct regmap *tempmon;
>         u32 c1, c2; /* See formula in imx_init_calib() */
>         int temp_passive;
> @@ -256,7 +255,7 @@ static int imx_get_temp(struct thermal_zone_device *tz, int *temp)
>         bool wait;
>         u32 val;
>
> -       if (data->mode == THERMAL_DEVICE_ENABLED) {
> +       if (tz->mode == THERMAL_DEVICE_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 +282,7 @@ static int imx_get_temp(struct thermal_zone_device *tz, int *temp)
>
>         regmap_read(map, soc_data->temp_data, &val);
>
> -       if (data->mode != THERMAL_DEVICE_ENABLED) {
> +       if (tz->mode != THERMAL_DEVICE_ENABLED) {
>                 regmap_write(map, soc_data->sensor_ctrl + REG_CLR,
>                              soc_data->measure_temp_mask);
>                 regmap_write(map, soc_data->sensor_ctrl + REG_SET,
> @@ -331,16 +330,6 @@ static int imx_get_temp(struct thermal_zone_device *tz, int *temp)
>         return 0;
>  }
>
> -static int imx_get_mode(struct thermal_zone_device *tz,
> -                       enum thermal_device_mode *mode)
> -{
> -       struct imx_thermal_data *data = tz->devdata;
> -
> -       *mode = data->mode;
> -
> -       return 0;
> -}
> -
>  static int imx_set_mode(struct thermal_zone_device *tz,
>                         enum thermal_device_mode mode)
>  {
> @@ -376,9 +365,6 @@ static int imx_set_mode(struct thermal_zone_device *tz,
>                 }
>         }
>
> -       data->mode = mode;
> -       thermal_zone_device_update(tz, THERMAL_EVENT_UNSPECIFIED);
> -
>         return 0;
>  }
>
> @@ -467,7 +453,6 @@ static struct thermal_zone_device_ops imx_tz_ops = {
>         .bind = imx_bind,
>         .unbind = imx_unbind,
>         .get_temp = imx_get_temp,
> -       .get_mode = imx_get_mode,
>         .set_mode = imx_set_mode,
>         .get_trip_type = imx_get_trip_type,
>         .get_trip_temp = imx_get_trip_temp,
> @@ -691,6 +676,9 @@ static inline void imx_thermal_unregister_legacy_cooling(struct imx_thermal_data
>
>  static int imx_thermal_probe(struct platform_device *pdev)
>  {
> +       struct thermal_zone_params tzp = {
> +               .initial_mode = THERMAL_DEVICE_ENABLED,
> +       };
>         struct imx_thermal_data *data;
>         struct regmap *map;
>         int measure_freq;
> @@ -799,7 +787,7 @@ static int imx_thermal_probe(struct platform_device *pdev)
>         data->tz = thermal_zone_device_register("imx_thermal_zone",
>                                                 IMX_TRIP_NUM,
>                                                 BIT(IMX_TRIP_PASSIVE), data,
> -                                               &imx_tz_ops, NULL,
> +                                               &imx_tz_ops, &tzp,
>                                                 IMX_PASSIVE_DELAY,
>                                                 IMX_POLLING_DELAY);
>         if (IS_ERR(data->tz)) {
> @@ -831,7 +819,6 @@ static int imx_thermal_probe(struct platform_device *pdev)
>                      data->socdata->measure_temp_mask);
>
>         data->irq_enabled = true;
> -       data->mode = THERMAL_DEVICE_ENABLED;
>
>         ret = devm_request_threaded_irq(&pdev->dev, data->irq,
>                         imx_thermal_alarm_irq, imx_thermal_alarm_irq_thread,
> @@ -885,7 +872,7 @@ static int __maybe_unused imx_thermal_suspend(struct device *dev)
>                      data->socdata->measure_temp_mask);
>         regmap_write(map, data->socdata->sensor_ctrl + REG_SET,
>                      data->socdata->power_down_mask);
> -       data->mode = THERMAL_DEVICE_DISABLED;
> +       data->tz->mode = THERMAL_DEVICE_DISABLED;
>         clk_disable_unprepare(data->thermal_clk);
>
>         return 0;
> @@ -905,7 +892,7 @@ static int __maybe_unused imx_thermal_resume(struct device *dev)
>                      data->socdata->power_down_mask);
>         regmap_write(map, data->socdata->sensor_ctrl + REG_SET,
>                      data->socdata->measure_temp_mask);
> -       data->mode = THERMAL_DEVICE_ENABLED;
> +       data->tz->mode = THERMAL_DEVICE_ENABLED;
>
>         return 0;
>  }
> diff --git a/drivers/thermal/intel/int340x_thermal/int3400_thermal.c b/drivers/thermal/intel/int340x_thermal/int3400_thermal.c
> index e802922a13cf..86a00598ed09 100644
> --- a/drivers/thermal/intel/int340x_thermal/int3400_thermal.c
> +++ b/drivers/thermal/intel/int340x_thermal/int3400_thermal.c
> @@ -44,7 +44,6 @@ static char *int3400_thermal_uuids[INT3400_THERMAL_MAXIMUM_UUID] = {
>  struct int3400_thermal_priv {
>         struct acpi_device *adev;
>         struct thermal_zone_device *thermal;
> -       int mode;
>         int art_count;
>         struct art *arts;
>         int trt_count;
> @@ -230,48 +229,29 @@ static int int3400_thermal_get_temp(struct thermal_zone_device *thermal,
>         return 0;
>  }
>
> -static int int3400_thermal_get_mode(struct thermal_zone_device *thermal,
> -                               enum thermal_device_mode *mode)
> -{
> -       struct int3400_thermal_priv *priv = thermal->devdata;
> -
> -       if (!priv)
> -               return -EINVAL;
> -
> -       *mode = priv->mode;
> -
> -       return 0;
> -}
> -
>  static int int3400_thermal_set_mode(struct thermal_zone_device *thermal,
>                                 enum thermal_device_mode mode)
>  {
>         struct int3400_thermal_priv *priv = thermal->devdata;
> -       bool enable;
>         int result = 0;
>
>         if (!priv)
>                 return -EINVAL;
>
> -       if (mode == THERMAL_DEVICE_ENABLED)
> -               enable = true;
> -       else if (mode == THERMAL_DEVICE_DISABLED)
> -               enable = false;
> -       else
> +       if (mode != THERMAL_DEVICE_ENABLED &&
> +           mode != THERMAL_DEVICE_DISABLED)
>                 return -EINVAL;
>
> -       if (enable != priv->mode) {
> -               priv->mode = enable;
> +       if (mode != thermal->mode) {
>                 result = int3400_thermal_run_osc(priv->adev->handle,
> -                                                priv->current_uuid_index,
> -                                                enable);
> +                                               priv->current_uuid_index,
> +                                               mode == THERMAL_DEVICE_ENABLED);
>         }
>         return result;
>  }
>
>  static struct thermal_zone_device_ops int3400_thermal_ops = {
>         .get_temp = int3400_thermal_get_temp,
> -       .get_mode = int3400_thermal_get_mode,
>         .set_mode = int3400_thermal_set_mode,
>  };
>
> diff --git a/drivers/thermal/intel/intel_quark_dts_thermal.c b/drivers/thermal/intel/intel_quark_dts_thermal.c
> index d704fc104cfd..c4879b4bfbf1 100644
> --- a/drivers/thermal/intel/intel_quark_dts_thermal.c
> +++ b/drivers/thermal/intel/intel_quark_dts_thermal.c
> @@ -103,7 +103,6 @@ struct soc_sensor_entry {
>         bool locked;
>         u32 store_ptps;
>         u32 store_dts_enable;
> -       enum thermal_device_mode mode;
>         struct thermal_zone_device *tzone;
>  };
>
> @@ -128,7 +127,7 @@ static int soc_dts_enable(struct thermal_zone_device *tzd)
>                 return ret;
>
>         if (out & QRK_DTS_ENABLE_BIT) {
> -               aux_entry->mode = THERMAL_DEVICE_ENABLED;
> +               tzd->mode = THERMAL_DEVICE_ENABLED;
>                 return 0;
>         }
>
> @@ -139,9 +138,9 @@ static int soc_dts_enable(struct thermal_zone_device *tzd)
>                 if (ret)
>                         return ret;
>
> -               aux_entry->mode = THERMAL_DEVICE_ENABLED;
> +               tzd->mode = THERMAL_DEVICE_ENABLED;
>         } else {
> -               aux_entry->mode = THERMAL_DEVICE_DISABLED;
> +               tzd->mode = THERMAL_DEVICE_DISABLED;
>                 pr_info("DTS is locked. Cannot enable DTS\n");
>                 ret = -EPERM;
>         }
> @@ -161,7 +160,7 @@ static int soc_dts_disable(struct thermal_zone_device *tzd)
>                 return ret;
>
>         if (!(out & QRK_DTS_ENABLE_BIT)) {
> -               aux_entry->mode = THERMAL_DEVICE_DISABLED;
> +               tzd->mode = THERMAL_DEVICE_DISABLED;
>                 return 0;
>         }
>
> @@ -173,9 +172,9 @@ static int soc_dts_disable(struct thermal_zone_device *tzd)
>                 if (ret)
>                         return ret;
>
> -               aux_entry->mode = THERMAL_DEVICE_DISABLED;
> +               tzd->mode = THERMAL_DEVICE_DISABLED;
>         } else {
> -               aux_entry->mode = THERMAL_DEVICE_ENABLED;
> +               tzd->mode = THERMAL_DEVICE_ENABLED;
>                 pr_info("DTS is locked. Cannot disable DTS\n");
>                 ret = -EPERM;
>         }
> @@ -309,14 +308,6 @@ static int sys_get_curr_temp(struct thermal_zone_device *tzd,
>         return 0;
>  }
>
> -static int sys_get_mode(struct thermal_zone_device *tzd,
> -                               enum thermal_device_mode *mode)
> -{
> -       struct soc_sensor_entry *aux_entry = tzd->devdata;
> -       *mode = aux_entry->mode;
> -       return 0;
> -}
> -
>  static int sys_set_mode(struct thermal_zone_device *tzd,
>                                 enum thermal_device_mode mode)
>  {
> @@ -338,7 +329,6 @@ static struct thermal_zone_device_ops tzone_ops = {
>         .get_trip_type = sys_get_trip_type,
>         .set_trip_temp = sys_set_trip_temp,
>         .get_crit_temp = sys_get_crit_temp,
> -       .get_mode = sys_get_mode,
>         .set_mode = sys_set_mode,
>  };
>
> diff --git a/drivers/thermal/of-thermal.c b/drivers/thermal/of-thermal.c
> index 874a47d6923f..863b89546f81 100644
> --- a/drivers/thermal/of-thermal.c
> +++ b/drivers/thermal/of-thermal.c
> @@ -51,7 +51,6 @@ struct __thermal_bind_params {
>
>  /**
>   * struct __thermal_zone - internal representation of a thermal zone
> - * @mode: current thermal zone device mode (enabled/disabled)
>   * @passive_delay: polling interval while passive cooling is activated
>   * @polling_delay: zone polling interval
>   * @slope: slope of the temperature adjustment curve
> @@ -65,7 +64,6 @@ struct __thermal_bind_params {
>   */
>
>  struct __thermal_zone {
> -       enum thermal_device_mode mode;
>         int passive_delay;
>         int polling_delay;
>         int slope;
> @@ -269,23 +267,11 @@ static int of_thermal_unbind(struct thermal_zone_device *thermal,
>         return 0;
>  }
>
> -static int of_thermal_get_mode(struct thermal_zone_device *tz,
> -                              enum thermal_device_mode *mode)
> -{
> -       struct __thermal_zone *data = tz->devdata;
> -
> -       *mode = data->mode;
> -
> -       return 0;
> -}
> -
>  static int of_thermal_set_mode(struct thermal_zone_device *tz,
>                                enum thermal_device_mode mode)
>  {
>         struct __thermal_zone *data = tz->devdata;
>
> -       mutex_lock(&tz->lock);
> -
>         if (mode == THERMAL_DEVICE_ENABLED) {
>                 tz->polling_delay = data->polling_delay;
>                 tz->passive_delay = data->passive_delay;
> @@ -294,11 +280,6 @@ static int of_thermal_set_mode(struct thermal_zone_device *tz,
>                 tz->passive_delay = 0;
>         }
>
> -       mutex_unlock(&tz->lock);
> -
> -       data->mode = mode;
> -       thermal_zone_device_update(tz, THERMAL_EVENT_UNSPECIFIED);
> -
>         return 0;
>  }
>
> @@ -393,7 +374,6 @@ static int of_thermal_get_crit_temp(struct thermal_zone_device *tz,
>  }
>
>  static struct thermal_zone_device_ops of_thermal_ops = {
> -       .get_mode = of_thermal_get_mode,
>         .set_mode = of_thermal_set_mode,
>
>         .get_trip_type = of_thermal_get_trip_type,
> @@ -553,8 +533,14 @@ thermal_zone_of_sensor_register(struct device *dev, int sensor_id, void *data,
>                 if (id == sensor_id) {
>                         tzd = thermal_zone_of_add_sensor(child, sensor_np,
>                                                          data, ops);
> -                       if (!IS_ERR(tzd))
> +                       if (!IS_ERR(tzd)) {
> +                               mutex_lock(&tzd->lock);
>                                 tzd->ops->set_mode(tzd, THERMAL_DEVICE_ENABLED);
> +                               tzd->mode = THERMAL_DEVICE_ENABLED;
> +                               mutex_unlock(&tzd->lock);
> +                               thermal_zone_device_update(tzd,
> +                                               THERMAL_EVENT_UNSPECIFIED);
> +                       }
>
>                         of_node_put(child);
>                         goto exit;
> @@ -979,7 +965,6 @@ __init *thermal_of_build_thermal_zone(struct device_node *np)
>
>  finish:
>         of_node_put(child);
> -       tz->mode = THERMAL_DEVICE_DISABLED;
>
>         return tz;
>
> @@ -1120,6 +1105,7 @@ int __init of_parse_thermal_zones(void)
>                 /* these two are left for temperature drivers to use */
>                 tzp->slope = tz->slope;
>                 tzp->offset = tz->offset;
> +               tzp->initial_mode = THERMAL_DEVICE_DISABLED;
>
>                 zone = thermal_zone_device_register(child->name, tz->ntrips,
>                                                     mask, tz,
> diff --git a/drivers/thermal/thermal_core.c b/drivers/thermal/thermal_core.c
> index c06550930979..5ff98fcc0f6a 100644
> --- a/drivers/thermal/thermal_core.c
> +++ b/drivers/thermal/thermal_core.c
> @@ -463,6 +463,43 @@ static void thermal_zone_device_reset(struct thermal_zone_device *tz)
>         thermal_zone_device_init(tz);
>  }
>
> +enum thermal_device_mode
> +thermal_zone_device_get_mode(struct thermal_zone_device *tz)
> +{
> +       enum thermal_device_mode mode;
> +
> +       mutex_lock(&tz->lock);
> +
> +       mode = tz->mode;
> +
> +       mutex_unlock(&tz->lock);
> +
> +       return mode;
> +}
> +
> +int thermal_zone_device_set_mode(struct thermal_zone_device *tz,
> +                                enum thermal_device_mode mode)
> +{
> +       int ret = 0;
> +
> +       if (mode != THERMAL_DEVICE_DISABLED &&
> +           mode != THERMAL_DEVICE_ENABLED)
> +               return -EINVAL;
> +
> +       mutex_lock(&tz->lock);
> +
> +       if (tz->ops->set_mode)
> +               ret = tz->ops->set_mode(tz, mode);
> +
> +       tz->mode = mode;
> +
> +       mutex_unlock(&tz->lock);
> +
> +       thermal_zone_device_update(tz, THERMAL_EVENT_UNSPECIFIED);
> +
> +       return ret;
> +}
> +
>  void thermal_zone_device_update(struct thermal_zone_device *tz,
>                                 enum thermal_notify_event event)
>  {
> @@ -1344,6 +1381,9 @@ thermal_zone_device_register(const char *type, int trips, int mask,
>         if (atomic_cmpxchg(&tz->need_update, 1, 0))
>                 thermal_zone_device_update(tz, THERMAL_EVENT_UNSPECIFIED);
>
> +       if (tzp)
> +               thermal_zone_device_set_mode(tz, tzp->initial_mode);
> +
>         return tz;
>
>  unregister:
> @@ -1473,9 +1513,7 @@ static int thermal_pm_notify(struct notifier_block *nb,
>         case PM_POST_SUSPEND:
>                 atomic_set(&in_suspend, 0);
>                 list_for_each_entry(tz, &thermal_tz_list, node) {
> -                       tz_mode = THERMAL_DEVICE_ENABLED;
> -                       if (tz->ops->get_mode)
> -                               tz->ops->get_mode(tz, &tz_mode);
> +                       tz_mode = thermal_zone_device_get_mode(tz);
>
>                         if (tz_mode == THERMAL_DEVICE_DISABLED)
>                                 continue;
> diff --git a/drivers/thermal/thermal_core.h b/drivers/thermal/thermal_core.h
> index c95689586e19..8e561bac3133 100644
> --- a/drivers/thermal/thermal_core.h
> +++ b/drivers/thermal/thermal_core.h
> @@ -141,6 +141,22 @@ thermal_cooling_device_stats_update(struct thermal_cooling_device *cdev,
>                                     unsigned long new_state) {}
>  #endif /* CONFIG_THERMAL_STATISTICS */
>
> +enum thermal_device_mode
> +thermal_zone_device_get_mode(struct thermal_zone_device *tz);
> +
> +int thermal_zone_device_set_mode(struct thermal_zone_device *tz,
> +                                enum thermal_device_mode mode);
> +
> +static inline int thermal_zone_device_enable(struct thermal_zone_device *tz)
> +{
> +       return thermal_zone_device_set_mode(tz, THERMAL_DEVICE_ENABLED);
> +}
> +
> +static inline int thermal_zone_device_disable(struct thermal_zone_device *tz)
> +{
> +       return thermal_zone_device_set_mode(tz, THERMAL_DEVICE_DISABLED);
> +}
> +
>  /* device tree support */
>  #ifdef CONFIG_THERMAL_OF
>  int of_parse_thermal_zones(void);
> diff --git a/drivers/thermal/thermal_sysfs.c b/drivers/thermal/thermal_sysfs.c
> index aa99edb4dff7..cbb27b3c96d2 100644
> --- a/drivers/thermal/thermal_sysfs.c
> +++ b/drivers/thermal/thermal_sysfs.c
> @@ -50,14 +50,8 @@ mode_show(struct device *dev, struct device_attribute *attr, char *buf)
>  {
>         struct thermal_zone_device *tz = to_thermal_zone(dev);
>         enum thermal_device_mode mode;
> -       int result;
> -
> -       if (!tz->ops->get_mode)
> -               return -EPERM;
>
> -       result = tz->ops->get_mode(tz, &mode);
> -       if (result)
> -               return result;
> +       mode = thermal_zone_device_get_mode(tz);
>
>         return sprintf(buf, "%s\n", mode == THERMAL_DEVICE_ENABLED ? "enabled"
>                        : "disabled");
> @@ -74,9 +68,9 @@ mode_store(struct device *dev, struct device_attribute *attr,
>                 return -EPERM;
>
>         if (!strncmp(buf, "enabled", sizeof("enabled") - 1))
> -               result = tz->ops->set_mode(tz, THERMAL_DEVICE_ENABLED);
> +               result = thermal_zone_device_enable(tz);
>         else if (!strncmp(buf, "disabled", sizeof("disabled") - 1))
> -               result = tz->ops->set_mode(tz, THERMAL_DEVICE_DISABLED);
> +               result = thermal_zone_device_disable(tz);
>         else
>                 result = -EINVAL;
>
> @@ -428,30 +422,13 @@ static struct attribute_group thermal_zone_attribute_group = {
>         .attrs = thermal_zone_dev_attrs,
>  };
>
> -/* We expose mode only if .get_mode is present */
>  static struct attribute *thermal_zone_mode_attrs[] = {
>         &dev_attr_mode.attr,
>         NULL,
>  };
>
> -static umode_t thermal_zone_mode_is_visible(struct kobject *kobj,
> -                                           struct attribute *attr,
> -                                           int attrno)
> -{
> -       struct device *dev = container_of(kobj, struct device, kobj);
> -       struct thermal_zone_device *tz;
> -
> -       tz = container_of(dev, struct thermal_zone_device, device);
> -
> -       if (tz->ops->get_mode)
> -               return attr->mode;
> -
> -       return 0;
> -}
> -
>  static struct attribute_group thermal_zone_mode_attribute_group = {
>         .attrs = thermal_zone_mode_attrs,
> -       .is_visible = thermal_zone_mode_is_visible,
>  };
>
>  /* We expose passive only if passive trips are present */
> diff --git a/include/linux/thermal.h b/include/linux/thermal.h
> index 216185bb3014..da4141697e2e 100644
> --- a/include/linux/thermal.h
> +++ b/include/linux/thermal.h
> @@ -76,8 +76,6 @@ struct thermal_zone_device_ops {
>                        struct thermal_cooling_device *);
>         int (*get_temp) (struct thermal_zone_device *, int *);
>         int (*set_trips) (struct thermal_zone_device *, int, int);
> -       int (*get_mode) (struct thermal_zone_device *,
> -                        enum thermal_device_mode *);
>         int (*set_mode) (struct thermal_zone_device *,
>                 enum thermal_device_mode);
>         int (*get_trip_type) (struct thermal_zone_device *, int,
> @@ -128,6 +126,7 @@ struct thermal_cooling_device {
>   * @trip_temp_attrs:   attributes for trip points for sysfs: trip temperature
>   * @trip_type_attrs:   attributes for trip points for sysfs: trip type
>   * @trip_hyst_attrs:   attributes for trip points for sysfs: trip hysteresis
> + * @mode:              current mode of this thermal zone
>   * @devdata:   private pointer for device private data
>   * @trips:     number of trip points the thermal zone supports
>   * @trips_disabled;    bitmap for disabled trips
> @@ -170,6 +169,7 @@ struct thermal_zone_device {
>         struct thermal_attr *trip_temp_attrs;
>         struct thermal_attr *trip_type_attrs;
>         struct thermal_attr *trip_hyst_attrs;
> +       enum thermal_device_mode mode;
>         void *devdata;
>         int trips;
>         unsigned long trips_disabled;   /* bitmap for disabled trips */
> @@ -264,6 +264,9 @@ struct thermal_zone_params {
>         int num_tbps;   /* Number of tbp entries */
>         struct thermal_bind_params *tbp;
>
> +       /* Initial mode of this thermal zone device */
> +       enum thermal_device_mode initial_mode;
> +
>         /*
>          * Sustainable power (heat) that this thermal zone can dissipate in
>          * mW
> --
> 2.17.1
>


-- 
With Best Regards,
Andy Shevchenko

^ permalink raw reply	[flat|nested] 63+ messages in thread

* Re: [RFC 0/8] Stop monitoring disabled devices
  2020-04-15 10:40       ` Bartlomiej Zolnierkiewicz
  2020-04-17 16:23         ` Andrzej Pietrasiewicz
@ 2020-04-17 21:11         ` Peter Kästle
  1 sibling, 0 replies; 63+ messages in thread
From: Peter Kästle @ 2020-04-17 21:11 UTC (permalink / raw)
  To: Andrzej Pietrasiewicz, Bartlomiej Zolnierkiewicz
  Cc: Daniel Lezcano, linux-pm, Zhang Rui, Rafael J . Wysocki,
	Len Brown, Jiri Pirko, Ido Schimmel, David S . Miller,
	Darren Hart, Andy Shevchenko, Support Opensource, Amit Kucheria,
	Shawn Guo, Sascha Hauer, Pengutronix Kernel Team, Fabio Estevam,
	NXP Linux Team, Allison Randal, Enrico Weigelt, Gayatri Kammela,
	Thomas Gleixner, linux-acpi, netdev, platform-driver-x86,
	linux-arm-kernel, kernel

Hi,

17. April 2020 18:23, "Andrzej Pietrasiewicz" <andrzej.p@collabora.com> schrieb:

[...]

> I've just sent a v3. After addressing your and Daniel's comments my series
> now looks pretty compact. Let's see if there's more feedback. Is your work on
> reviving the above mentioned 2018 series ready?

I agree, v3 looks pretty good, I will test it within next 2 days for acerhdf.  Thanks for your work!

-- 
--peter;

^ permalink raw reply	[flat|nested] 63+ messages in thread

* Re: [RFC v3 1/2] thermal: core: Let thermal zone device's mode be stored in its struct
  2020-04-17 16:20           ` [RFC v3 1/2] thermal: core: Let thermal zone device's mode be stored in its struct Andrzej Pietrasiewicz
  2020-04-17 20:44             ` Andy Shevchenko
@ 2020-04-19 11:38             ` Bartlomiej Zolnierkiewicz
  2020-04-19 13:10               ` Bartlomiej Zolnierkiewicz
  2020-04-20 11:03               ` [RFC v3 1/2] thermal: core: Let thermal zone device's mode be stored in its struct Andrzej Pietrasiewicz
  2020-05-23 21:24             ` Daniel Lezcano
  2 siblings, 2 replies; 63+ messages in thread
From: Bartlomiej Zolnierkiewicz @ 2020-04-19 11:38 UTC (permalink / raw)
  To: Andrzej Pietrasiewicz
  Cc: linux-pm, Zhang Rui, Rafael J . Wysocki, Len Brown, Jiri Pirko,
	Ido Schimmel, David S . Miller, Peter Kaestle, Darren Hart,
	Andy Shevchenko, Support Opensource, Daniel Lezcano,
	Amit Kucheria, Shawn Guo, Sascha Hauer, Pengutronix Kernel Team,
	Fabio Estevam, NXP Linux Team, Allison Randal, Enrico Weigelt,
	Gayatri Kammela, Thomas Gleixner, linux-acpi, netdev,
	platform-driver-x86, linux-arm-kernel, kernel


Hi Andrzej,

On 4/17/20 6:20 PM, Andrzej Pietrasiewicz wrote:
> Thermal zone devices' mode is stored in individual drivers. This patch
> changes it so that mode is stored in struct thermal_zone_device instead.
> 
> As a result all driver-specific variables storing the mode are not needed
> and are removed. Consequently, the get_mode() implementations have nothing
> to operate on and need to be removed, too.
> 
> Some thermal framework specific functions are introduced:
> 
> thermal_zone_device_get_mode()
> thermal_zone_device_set_mode()
> thermal_zone_device_enable()
> thermal_zone_device_disable()
> 
> thermal_zone_device_get_mode() and its "set" counterpart take tzd's lock
> and the "set" calls driver's set_mode() if provided, so the latter must
> not take this lock again. At the end of the "set"
> thermal_zone_device_update() is called so drivers don't need to repeat this
> invocation in their specific set_mode() implementations.
> 
> The scope of the above 4 functions is purposedly limited to the thermal
> framework and drivers are not supposed to call them. This encapsulation

This should be true only for thermal_zone_device_{get,set}_mode().

thermal_zone_device_{en,dis}able() should be available for device drivers:

* of/thermal device drivers need to enable thermal device itself
  (please refer to my patchset for details)

* device drivers need to call them on ->suspend and ->resume operations

> does not fully work at the moment for some drivers, though:
> 
> - platform/x86/acerhdf.c
> - drivers/thermal/imx_thermal.c
> - drivers/thermal/intel/intel_quark_dts_thermal.c
> - drivers/thermal/of-thermal.c
> 
> and they manipulate struct thermal_zone_device's members directly.
> 
> struct thermal_zone_params gains a new member called initial_mode, which
> is used to set tzd's mode at registration time.
> 
> The sysfs "mode" attribute is always exposed from now on, because all
> thermal zone devices now have their get_mode() implemented at the generic
> level and it is always available. Exposing "mode" doesn't hurt the drivers
> which don't provide their own set_mode(), because writing to "mode" will
> result in -EPERM, as expected.
> 
> Signed-off-by: Andrzej Pietrasiewicz <andrzej.p@collabora.com>
> ---
>  drivers/acpi/thermal.c                        | 46 +++++----------
>  .../ethernet/mellanox/mlxsw/core_thermal.c    | 57 ++++---------------
>  drivers/platform/x86/acerhdf.c                | 17 +-----
>  drivers/thermal/da9062-thermal.c              | 16 ++----
>  drivers/thermal/imx_thermal.c                 | 29 +++-------
>  .../intel/int340x_thermal/int3400_thermal.c   | 30 ++--------
>  .../thermal/intel/intel_quark_dts_thermal.c   | 22 ++-----
>  drivers/thermal/of-thermal.c                  | 30 +++-------
>  drivers/thermal/thermal_core.c                | 44 +++++++++++++-
>  drivers/thermal/thermal_core.h                | 16 ++++++
>  drivers/thermal/thermal_sysfs.c               | 29 +---------
>  include/linux/thermal.h                       |  7 ++-
>  12 files changed, 125 insertions(+), 218 deletions(-)
> 
> diff --git a/drivers/acpi/thermal.c b/drivers/acpi/thermal.c
> index 19067a5e5293..67bc263332a5 100644
> --- a/drivers/acpi/thermal.c
> +++ b/drivers/acpi/thermal.c
> @@ -172,7 +172,6 @@ struct acpi_thermal {
>  	struct acpi_thermal_trips trips;
>  	struct acpi_handle_list devices;
>  	struct thermal_zone_device *thermal_zone;
> -	int tz_enabled;
>  	int kelvin_offset;	/* in millidegrees */
>  	struct work_struct thermal_check_work;
>  };
> @@ -500,7 +499,7 @@ static void acpi_thermal_check(void *data)
>  {
>  	struct acpi_thermal *tz = data;
>  
> -	if (!tz->tz_enabled)
> +	if (tz->thermal_zone->mode != THERMAL_DEVICE_ENABLED)
>  		return;
>  
>  	thermal_zone_device_update(tz->thermal_zone,
> @@ -526,46 +525,29 @@ static int thermal_get_temp(struct thermal_zone_device *thermal, int *temp)
>  	return 0;
>  }
>  
> -static int thermal_get_mode(struct thermal_zone_device *thermal,
> -				enum thermal_device_mode *mode)
> -{
> -	struct acpi_thermal *tz = thermal->devdata;
> -
> -	if (!tz)
> -		return -EINVAL;
> -
> -	*mode = tz->tz_enabled ? THERMAL_DEVICE_ENABLED :
> -		THERMAL_DEVICE_DISABLED;
> -
> -	return 0;
> -}
> -
>  static int thermal_set_mode(struct thermal_zone_device *thermal,
>  				enum thermal_device_mode mode)
>  {
>  	struct acpi_thermal *tz = thermal->devdata;
> -	int enable;
>  
>  	if (!tz)
>  		return -EINVAL;
>  
> +	if (mode != THERMAL_DEVICE_DISABLED &&
> +	    mode != THERMAL_DEVICE_ENABLED)
> +		return -EINVAL;

These checks should be removed as they are already done in the caller
of ->set_mode method (thermal_zone_device_set_mode()).

> +
>  	/*
>  	 * enable/disable thermal management from ACPI thermal driver
>  	 */
> -	if (mode == THERMAL_DEVICE_ENABLED)
> -		enable = 1;
> -	else if (mode == THERMAL_DEVICE_DISABLED) {
> -		enable = 0;
> +	if (mode == THERMAL_DEVICE_DISABLED)
>  		pr_warn("thermal zone will be disabled\n");
> -	} else
> -		return -EINVAL;
>  
> -	if (enable != tz->tz_enabled) {
> -		tz->tz_enabled = enable;
> +	if (mode != thermal->mode) {
>  		ACPI_DEBUG_PRINT((ACPI_DB_INFO,
>  			"%s kernel ACPI thermal control\n",
> -			tz->tz_enabled ? "Enable" : "Disable"));
> -		acpi_thermal_check(tz);
> +			mode == THERMAL_DEVICE_ENABLED ?
> +			"Enable" : "Disable"));
>  	}
>  	return 0;
>  }
> @@ -856,7 +838,6 @@ static struct thermal_zone_device_ops acpi_thermal_zone_ops = {
>  	.bind = acpi_thermal_bind_cooling_device,
>  	.unbind	= acpi_thermal_unbind_cooling_device,
>  	.get_temp = thermal_get_temp,
> -	.get_mode = thermal_get_mode,
>  	.set_mode = thermal_set_mode,
>  	.get_trip_type = thermal_get_trip_type,
>  	.get_trip_temp = thermal_get_trip_temp,
> @@ -870,6 +851,9 @@ static int acpi_thermal_register_thermal_zone(struct acpi_thermal *tz)
>  	int trips = 0;
>  	int result;
>  	acpi_status status;
> +	struct thermal_zone_params prms = {
> +		.initial_mode = THERMAL_DEVICE_ENABLED,
> +	};
>  	int i;
>  
>  	if (tz->trips.critical.flags.valid)
> @@ -887,13 +871,13 @@ static int acpi_thermal_register_thermal_zone(struct acpi_thermal *tz)
>  	if (tz->trips.passive.flags.valid)
>  		tz->thermal_zone =
>  			thermal_zone_device_register("acpitz", trips, 0, tz,
> -						&acpi_thermal_zone_ops, NULL,
> +						&acpi_thermal_zone_ops, &prms,
>  						     tz->trips.passive.tsp*100,
>  						     tz->polling_frequency*100);
>  	else
>  		tz->thermal_zone =
>  			thermal_zone_device_register("acpitz", trips, 0, tz,
> -						&acpi_thermal_zone_ops, NULL,
> +						&acpi_thermal_zone_ops, &prms,
>  						0, tz->polling_frequency*100);
>  	if (IS_ERR(tz->thermal_zone))
>  		return -ENODEV;
> @@ -913,8 +897,6 @@ static int acpi_thermal_register_thermal_zone(struct acpi_thermal *tz)
>  	if (ACPI_FAILURE(status))
>  		return -ENODEV;
>  
> -	tz->tz_enabled = 1;
> -
>  	dev_info(&tz->device->dev, "registered as thermal_zone%d\n",
>  		 tz->thermal_zone->id);
>  	return 0;
> diff --git a/drivers/net/ethernet/mellanox/mlxsw/core_thermal.c b/drivers/net/ethernet/mellanox/mlxsw/core_thermal.c
> index ce0a6837daa3..50518048b86d 100644
> --- a/drivers/net/ethernet/mellanox/mlxsw/core_thermal.c
> +++ b/drivers/net/ethernet/mellanox/mlxsw/core_thermal.c
> @@ -98,7 +98,6 @@ struct mlxsw_thermal_module {
>  	struct mlxsw_thermal *parent;
>  	struct thermal_zone_device *tzdev;
>  	struct mlxsw_thermal_trip trips[MLXSW_THERMAL_NUM_TRIPS];
> -	enum thermal_device_mode mode;
>  	int module; /* Module or gearbox number */
>  };
>  
> @@ -110,7 +109,6 @@ struct mlxsw_thermal {
>  	struct thermal_cooling_device *cdevs[MLXSW_MFCR_PWMS_MAX];
>  	u8 cooling_levels[MLXSW_THERMAL_MAX_STATE + 1];
>  	struct mlxsw_thermal_trip trips[MLXSW_THERMAL_NUM_TRIPS];
> -	enum thermal_device_mode mode;
>  	struct mlxsw_thermal_module *tz_module_arr;
>  	u8 tz_module_num;
>  	struct mlxsw_thermal_module *tz_gearbox_arr;
> @@ -277,33 +275,16 @@ static int mlxsw_thermal_unbind(struct thermal_zone_device *tzdev,
>  	return 0;
>  }
>  
> -static int mlxsw_thermal_get_mode(struct thermal_zone_device *tzdev,
> -				  enum thermal_device_mode *mode)
> -{
> -	struct mlxsw_thermal *thermal = tzdev->devdata;
> -
> -	*mode = thermal->mode;
> -
> -	return 0;
> -}
> -
>  static int mlxsw_thermal_set_mode(struct thermal_zone_device *tzdev,
>  				  enum thermal_device_mode mode)
>  {
>  	struct mlxsw_thermal *thermal = tzdev->devdata;
>  
> -	mutex_lock(&tzdev->lock);
> -
>  	if (mode == THERMAL_DEVICE_ENABLED)
>  		tzdev->polling_delay = thermal->polling_delay;
>  	else
>  		tzdev->polling_delay = 0;
>  
> -	mutex_unlock(&tzdev->lock);
> -
> -	thermal->mode = mode;
> -	thermal_zone_device_update(tzdev, THERMAL_EVENT_UNSPECIFIED);
> -
>  	return 0;
>  }
>  
> @@ -407,7 +388,6 @@ static int mlxsw_thermal_trend_get(struct thermal_zone_device *tzdev,
>  static struct thermal_zone_device_ops mlxsw_thermal_ops = {
>  	.bind = mlxsw_thermal_bind,
>  	.unbind = mlxsw_thermal_unbind,
> -	.get_mode = mlxsw_thermal_get_mode,
>  	.set_mode = mlxsw_thermal_set_mode,
>  	.get_temp = mlxsw_thermal_get_temp,
>  	.get_trip_type	= mlxsw_thermal_get_trip_type,
> @@ -466,34 +446,17 @@ static int mlxsw_thermal_module_unbind(struct thermal_zone_device *tzdev,
>  	return err;
>  }
>  
> -static int mlxsw_thermal_module_mode_get(struct thermal_zone_device *tzdev,
> -					 enum thermal_device_mode *mode)
> -{
> -	struct mlxsw_thermal_module *tz = tzdev->devdata;
> -
> -	*mode = tz->mode;
> -
> -	return 0;
> -}
> -
>  static int mlxsw_thermal_module_mode_set(struct thermal_zone_device *tzdev,
>  					 enum thermal_device_mode mode)
>  {
>  	struct mlxsw_thermal_module *tz = tzdev->devdata;
>  	struct mlxsw_thermal *thermal = tz->parent;
>  
> -	mutex_lock(&tzdev->lock);
> -
>  	if (mode == THERMAL_DEVICE_ENABLED)
>  		tzdev->polling_delay = thermal->polling_delay;
>  	else
>  		tzdev->polling_delay = 0;
>  
> -	mutex_unlock(&tzdev->lock);
> -
> -	tz->mode = mode;
> -	thermal_zone_device_update(tzdev, THERMAL_EVENT_UNSPECIFIED);
> -
>  	return 0;
>  }
>  
> @@ -596,7 +559,6 @@ mlxsw_thermal_module_trip_hyst_set(struct thermal_zone_device *tzdev, int trip,
>  static struct thermal_zone_device_ops mlxsw_thermal_module_ops = {
>  	.bind		= mlxsw_thermal_module_bind,
>  	.unbind		= mlxsw_thermal_module_unbind,
> -	.get_mode	= mlxsw_thermal_module_mode_get,
>  	.set_mode	= mlxsw_thermal_module_mode_set,
>  	.get_temp	= mlxsw_thermal_module_temp_get,
>  	.get_trip_type	= mlxsw_thermal_module_trip_type_get,
> @@ -635,7 +597,6 @@ static int mlxsw_thermal_gearbox_temp_get(struct thermal_zone_device *tzdev,
>  static struct thermal_zone_device_ops mlxsw_thermal_gearbox_ops = {
>  	.bind		= mlxsw_thermal_module_bind,
>  	.unbind		= mlxsw_thermal_module_unbind,
> -	.get_mode	= mlxsw_thermal_module_mode_get,
>  	.set_mode	= mlxsw_thermal_module_mode_set,
>  	.get_temp	= mlxsw_thermal_gearbox_temp_get,
>  	.get_trip_type	= mlxsw_thermal_module_trip_type_get,
> @@ -749,6 +710,9 @@ static const struct thermal_cooling_device_ops mlxsw_cooling_ops = {
>  static int
>  mlxsw_thermal_module_tz_init(struct mlxsw_thermal_module *module_tz)
>  {
> +	struct thermal_zone_params tzp = {
> +		.initial_mode = THERMAL_DEVICE_ENABLED,
> +	};
>  	char tz_name[MLXSW_THERMAL_ZONE_MAX_NAME];
>  	int err;
>  
> @@ -759,13 +723,12 @@ mlxsw_thermal_module_tz_init(struct mlxsw_thermal_module *module_tz)
>  							MLXSW_THERMAL_TRIP_MASK,
>  							module_tz,
>  							&mlxsw_thermal_module_ops,
> -							NULL, 0, 0);
> +							&tzp, 0, 0);
>  	if (IS_ERR(module_tz->tzdev)) {
>  		err = PTR_ERR(module_tz->tzdev);
>  		return err;
>  	}
>  
> -	module_tz->mode = THERMAL_DEVICE_ENABLED;
>  	return 0;
>  }
>  
> @@ -868,6 +831,9 @@ mlxsw_thermal_modules_fini(struct mlxsw_thermal *thermal)
>  static int
>  mlxsw_thermal_gearbox_tz_init(struct mlxsw_thermal_module *gearbox_tz)
>  {
> +	struct thermal_zone_params tzp = {
> +		.initial_mode = THERMAL_DEVICE_ENABLED,
> +	};
>  	char tz_name[MLXSW_THERMAL_ZONE_MAX_NAME];
>  
>  	snprintf(tz_name, sizeof(tz_name), "mlxsw-gearbox%d",
> @@ -877,11 +843,10 @@ mlxsw_thermal_gearbox_tz_init(struct mlxsw_thermal_module *gearbox_tz)
>  						MLXSW_THERMAL_TRIP_MASK,
>  						gearbox_tz,
>  						&mlxsw_thermal_gearbox_ops,
> -						NULL, 0, 0);
> +						&tzp, 0, 0);
>  	if (IS_ERR(gearbox_tz->tzdev))
>  		return PTR_ERR(gearbox_tz->tzdev);
>  
> -	gearbox_tz->mode = THERMAL_DEVICE_ENABLED;
>  	return 0;
>  }
>  
> @@ -960,6 +925,9 @@ int mlxsw_thermal_init(struct mlxsw_core *core,
>  		       const struct mlxsw_bus_info *bus_info,
>  		       struct mlxsw_thermal **p_thermal)
>  {
> +	struct thermal_zone_params tzp = {
> +		.initial_mode = THERMAL_DEVICE_ENABLED,
> +	};
>  	char mfcr_pl[MLXSW_REG_MFCR_LEN] = { 0 };
>  	enum mlxsw_reg_mfcr_pwm_frequency freq;
>  	struct device *dev = bus_info->dev;
> @@ -1034,7 +1002,7 @@ int mlxsw_thermal_init(struct mlxsw_core *core,
>  						      MLXSW_THERMAL_TRIP_MASK,
>  						      thermal,
>  						      &mlxsw_thermal_ops,
> -						      NULL, 0,
> +						      &tzp, 0,
>  						      thermal->polling_delay);
>  	if (IS_ERR(thermal->tzdev)) {
>  		err = PTR_ERR(thermal->tzdev);
> @@ -1050,7 +1018,6 @@ int mlxsw_thermal_init(struct mlxsw_core *core,
>  	if (err)
>  		goto err_unreg_modules_tzdev;
>  
> -	thermal->mode = THERMAL_DEVICE_ENABLED;
>  	*p_thermal = thermal;
>  	return 0;
>  
> diff --git a/drivers/platform/x86/acerhdf.c b/drivers/platform/x86/acerhdf.c
> index 8cc86f4e3ac1..aaf8b845be90 100644
> --- a/drivers/platform/x86/acerhdf.c
> +++ b/drivers/platform/x86/acerhdf.c
> @@ -406,22 +406,9 @@ static inline void acerhdf_enable_kernelmode(void)
>  	kernelmode = 1;
>  
>  	thz_dev->polling_delay = interval*1000;
> -	thermal_zone_device_update(thz_dev, THERMAL_EVENT_UNSPECIFIED);
>  	pr_notice("kernel mode fan control ON\n");
>  }
>  
> -static int acerhdf_get_mode(struct thermal_zone_device *thermal,
> -			    enum thermal_device_mode *mode)
> -{
> -	if (verbose)
> -		pr_notice("kernel mode fan control %d\n", kernelmode);
> -
> -	*mode = (kernelmode) ? THERMAL_DEVICE_ENABLED
> -			     : THERMAL_DEVICE_DISABLED;
> -
> -	return 0;
> -}
> -
>  /*
>   * set operation mode;
>   * enabled: the thermal layer of the kernel takes care about
> @@ -488,7 +475,6 @@ static struct thermal_zone_device_ops acerhdf_dev_ops = {
>  	.bind = acerhdf_bind,
>  	.unbind = acerhdf_unbind,
>  	.get_temp = acerhdf_get_ec_temp,
> -	.get_mode = acerhdf_get_mode,
>  	.set_mode = acerhdf_set_mode,
>  	.get_trip_type = acerhdf_get_trip_type,
>  	.get_trip_hyst = acerhdf_get_trip_hyst,
> @@ -554,6 +540,7 @@ static int acerhdf_set_cur_state(struct thermal_cooling_device *cdev,
>  
>  err_out:
>  	acerhdf_revert_to_bios_mode();
> +	thz_dev->mode = THERMAL_DEVICE_DISABLED;
>  	return -EINVAL;
>  }
>  
> @@ -739,6 +726,8 @@ static int __init acerhdf_register_thermal(void)
>  	if (IS_ERR(cl_dev))
>  		return -EINVAL;
>  
> +	acerhdf_zone_params.initial_mode =
> +		kernelmode ? THERMAL_DEVICE_ENABLED : THERMAL_DEVICE_DISABLED;
>  	thz_dev = thermal_zone_device_register("acerhdf", 2, 0, NULL,
>  					      &acerhdf_dev_ops,
>  					      &acerhdf_zone_params, 0,
> diff --git a/drivers/thermal/da9062-thermal.c b/drivers/thermal/da9062-thermal.c
> index c32709badeda..4bdb6f9621c1 100644
> --- a/drivers/thermal/da9062-thermal.c
> +++ b/drivers/thermal/da9062-thermal.c
> @@ -49,7 +49,6 @@ struct da9062_thermal {
>  	struct da9062 *hw;
>  	struct delayed_work work;
>  	struct thermal_zone_device *zone;
> -	enum thermal_device_mode mode;
>  	struct mutex lock; /* protection for da9062_thermal temperature */
>  	int temperature;
>  	int irq;
> @@ -121,14 +120,6 @@ static irqreturn_t da9062_thermal_irq_handler(int irq, void *data)
>  	return IRQ_HANDLED;
>  }
>  
> -static int da9062_thermal_get_mode(struct thermal_zone_device *z,
> -				   enum thermal_device_mode *mode)
> -{
> -	struct da9062_thermal *thermal = z->devdata;
> -	*mode = thermal->mode;
> -	return 0;
> -}
> -
>  static int da9062_thermal_get_trip_type(struct thermal_zone_device *z,
>  					int trip,
>  					enum thermal_trip_type *type)
> @@ -181,7 +172,6 @@ static int da9062_thermal_get_temp(struct thermal_zone_device *z,
>  
>  static struct thermal_zone_device_ops da9062_thermal_ops = {
>  	.get_temp	= da9062_thermal_get_temp,
> -	.get_mode	= da9062_thermal_get_mode,
>  	.get_trip_type	= da9062_thermal_get_trip_type,
>  	.get_trip_temp	= da9062_thermal_get_trip_temp,
>  };
> @@ -199,6 +189,9 @@ MODULE_DEVICE_TABLE(of, da9062_compatible_reg_id_table);
>  
>  static int da9062_thermal_probe(struct platform_device *pdev)
>  {
> +	struct thermal_zone_params tzp = {
> +		.initial_mode = THERMAL_DEVICE_ENABLED,
> +	};
>  	struct da9062 *chip = dev_get_drvdata(pdev->dev.parent);
>  	struct da9062_thermal *thermal;
>  	unsigned int pp_tmp = DA9062_DEFAULT_POLLING_MS_PERIOD;
> @@ -233,7 +226,6 @@ static int da9062_thermal_probe(struct platform_device *pdev)
>  
>  	thermal->config = match->data;
>  	thermal->hw = chip;
> -	thermal->mode = THERMAL_DEVICE_ENABLED;
>  	thermal->dev = &pdev->dev;
>  
>  	INIT_DELAYED_WORK(&thermal->work, da9062_thermal_poll_on);
> @@ -241,7 +233,7 @@ static int da9062_thermal_probe(struct platform_device *pdev)
>  
>  	thermal->zone = thermal_zone_device_register(thermal->config->name,
>  					1, 0, thermal,
> -					&da9062_thermal_ops, NULL, pp_tmp,
> +					&da9062_thermal_ops, &tzp, pp_tmp,
>  					0);
>  	if (IS_ERR(thermal->zone)) {
>  		dev_err(&pdev->dev, "Cannot register thermal zone device\n");
> diff --git a/drivers/thermal/imx_thermal.c b/drivers/thermal/imx_thermal.c
> index e761c9b42217..3e02323c938b 100644
> --- a/drivers/thermal/imx_thermal.c
> +++ b/drivers/thermal/imx_thermal.c
> @@ -197,7 +197,6 @@ struct imx_thermal_data {
>  	struct cpufreq_policy *policy;
>  	struct thermal_zone_device *tz;
>  	struct thermal_cooling_device *cdev;
> -	enum thermal_device_mode mode;
>  	struct regmap *tempmon;
>  	u32 c1, c2; /* See formula in imx_init_calib() */
>  	int temp_passive;
> @@ -256,7 +255,7 @@ static int imx_get_temp(struct thermal_zone_device *tz, int *temp)
>  	bool wait;
>  	u32 val;
>  
> -	if (data->mode == THERMAL_DEVICE_ENABLED) {
> +	if (tz->mode == THERMAL_DEVICE_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 +282,7 @@ static int imx_get_temp(struct thermal_zone_device *tz, int *temp)
>  
>  	regmap_read(map, soc_data->temp_data, &val);
>  
> -	if (data->mode != THERMAL_DEVICE_ENABLED) {
> +	if (tz->mode != THERMAL_DEVICE_ENABLED) {
>  		regmap_write(map, soc_data->sensor_ctrl + REG_CLR,
>  			     soc_data->measure_temp_mask);
>  		regmap_write(map, soc_data->sensor_ctrl + REG_SET,
> @@ -331,16 +330,6 @@ static int imx_get_temp(struct thermal_zone_device *tz, int *temp)
>  	return 0;
>  }
>  
> -static int imx_get_mode(struct thermal_zone_device *tz,
> -			enum thermal_device_mode *mode)
> -{
> -	struct imx_thermal_data *data = tz->devdata;
> -
> -	*mode = data->mode;
> -
> -	return 0;
> -}
> -
>  static int imx_set_mode(struct thermal_zone_device *tz,
>  			enum thermal_device_mode mode)
>  {
> @@ -376,9 +365,6 @@ static int imx_set_mode(struct thermal_zone_device *tz,
>  		}
>  	}
>  
> -	data->mode = mode;
> -	thermal_zone_device_update(tz, THERMAL_EVENT_UNSPECIFIED);
> -
>  	return 0;
>  }
>  
> @@ -467,7 +453,6 @@ static struct thermal_zone_device_ops imx_tz_ops = {
>  	.bind = imx_bind,
>  	.unbind = imx_unbind,
>  	.get_temp = imx_get_temp,
> -	.get_mode = imx_get_mode,
>  	.set_mode = imx_set_mode,
>  	.get_trip_type = imx_get_trip_type,
>  	.get_trip_temp = imx_get_trip_temp,
> @@ -691,6 +676,9 @@ static inline void imx_thermal_unregister_legacy_cooling(struct imx_thermal_data
>  
>  static int imx_thermal_probe(struct platform_device *pdev)
>  {
> +	struct thermal_zone_params tzp = {
> +		.initial_mode = THERMAL_DEVICE_ENABLED,
> +	};
>  	struct imx_thermal_data *data;
>  	struct regmap *map;
>  	int measure_freq;
> @@ -799,7 +787,7 @@ static int imx_thermal_probe(struct platform_device *pdev)
>  	data->tz = thermal_zone_device_register("imx_thermal_zone",
>  						IMX_TRIP_NUM,
>  						BIT(IMX_TRIP_PASSIVE), data,
> -						&imx_tz_ops, NULL,
> +						&imx_tz_ops, &tzp,
>  						IMX_PASSIVE_DELAY,
>  						IMX_POLLING_DELAY);
>  	if (IS_ERR(data->tz)) {
> @@ -831,7 +819,6 @@ static int imx_thermal_probe(struct platform_device *pdev)
>  		     data->socdata->measure_temp_mask);
>  
>  	data->irq_enabled = true;
> -	data->mode = THERMAL_DEVICE_ENABLED;
>  
>  	ret = devm_request_threaded_irq(&pdev->dev, data->irq,
>  			imx_thermal_alarm_irq, imx_thermal_alarm_irq_thread,
> @@ -885,7 +872,7 @@ static int __maybe_unused imx_thermal_suspend(struct device *dev)
>  		     data->socdata->measure_temp_mask);
>  	regmap_write(map, data->socdata->sensor_ctrl + REG_SET,
>  		     data->socdata->power_down_mask);
> -	data->mode = THERMAL_DEVICE_DISABLED;
> +	data->tz->mode = THERMAL_DEVICE_DISABLED;
>  	clk_disable_unprepare(data->thermal_clk);
>  
>  	return 0;
> @@ -905,7 +892,7 @@ static int __maybe_unused imx_thermal_resume(struct device *dev)
>  		     data->socdata->power_down_mask);
>  	regmap_write(map, data->socdata->sensor_ctrl + REG_SET,
>  		     data->socdata->measure_temp_mask);
> -	data->mode = THERMAL_DEVICE_ENABLED;
> +	data->tz->mode = THERMAL_DEVICE_ENABLED;
>  
>  	return 0;
>  }
> diff --git a/drivers/thermal/intel/int340x_thermal/int3400_thermal.c b/drivers/thermal/intel/int340x_thermal/int3400_thermal.c
> index e802922a13cf..86a00598ed09 100644
> --- a/drivers/thermal/intel/int340x_thermal/int3400_thermal.c
> +++ b/drivers/thermal/intel/int340x_thermal/int3400_thermal.c
> @@ -44,7 +44,6 @@ static char *int3400_thermal_uuids[INT3400_THERMAL_MAXIMUM_UUID] = {
>  struct int3400_thermal_priv {
>  	struct acpi_device *adev;
>  	struct thermal_zone_device *thermal;
> -	int mode;
>  	int art_count;
>  	struct art *arts;
>  	int trt_count;
> @@ -230,48 +229,29 @@ static int int3400_thermal_get_temp(struct thermal_zone_device *thermal,
>  	return 0;
>  }
>  
> -static int int3400_thermal_get_mode(struct thermal_zone_device *thermal,
> -				enum thermal_device_mode *mode)
> -{
> -	struct int3400_thermal_priv *priv = thermal->devdata;
> -
> -	if (!priv)
> -		return -EINVAL;
> -
> -	*mode = priv->mode;
> -
> -	return 0;
> -}
> -
>  static int int3400_thermal_set_mode(struct thermal_zone_device *thermal,
>  				enum thermal_device_mode mode)
>  {
>  	struct int3400_thermal_priv *priv = thermal->devdata;
> -	bool enable;
>  	int result = 0;
>  
>  	if (!priv)
>  		return -EINVAL;
>  
> -	if (mode == THERMAL_DEVICE_ENABLED)
> -		enable = true;
> -	else if (mode == THERMAL_DEVICE_DISABLED)
> -		enable = false;
> -	else
> +	if (mode != THERMAL_DEVICE_ENABLED &&
> +	    mode != THERMAL_DEVICE_DISABLED)
>  		return -EINVAL;

These checks should be removed as they are already done in the caller
of ->set_mode method (thermal_zone_device_set_mode()).

> -	if (enable != priv->mode) {
> -		priv->mode = enable;
> +	if (mode != thermal->mode) {
>  		result = int3400_thermal_run_osc(priv->adev->handle,
> -						 priv->current_uuid_index,
> -						 enable);
> +						priv->current_uuid_index,
> +						mode == THERMAL_DEVICE_ENABLED);
>  	}
>  	return result;
>  }
>  
>  static struct thermal_zone_device_ops int3400_thermal_ops = {
>  	.get_temp = int3400_thermal_get_temp,
> -	.get_mode = int3400_thermal_get_mode,
>  	.set_mode = int3400_thermal_set_mode,
>  };
>  
> diff --git a/drivers/thermal/intel/intel_quark_dts_thermal.c b/drivers/thermal/intel/intel_quark_dts_thermal.c
> index d704fc104cfd..c4879b4bfbf1 100644
> --- a/drivers/thermal/intel/intel_quark_dts_thermal.c
> +++ b/drivers/thermal/intel/intel_quark_dts_thermal.c
> @@ -103,7 +103,6 @@ struct soc_sensor_entry {
>  	bool locked;
>  	u32 store_ptps;
>  	u32 store_dts_enable;
> -	enum thermal_device_mode mode;
>  	struct thermal_zone_device *tzone;
>  };
>  
> @@ -128,7 +127,7 @@ static int soc_dts_enable(struct thermal_zone_device *tzd)
>  		return ret;
>  
>  	if (out & QRK_DTS_ENABLE_BIT) {
> -		aux_entry->mode = THERMAL_DEVICE_ENABLED;
> +		tzd->mode = THERMAL_DEVICE_ENABLED;
>  		return 0;
>  	}
>  
> @@ -139,9 +138,9 @@ static int soc_dts_enable(struct thermal_zone_device *tzd)
>  		if (ret)
>  			return ret;
>  
> -		aux_entry->mode = THERMAL_DEVICE_ENABLED;
> +		tzd->mode = THERMAL_DEVICE_ENABLED;
>  	} else {
> -		aux_entry->mode = THERMAL_DEVICE_DISABLED;
> +		tzd->mode = THERMAL_DEVICE_DISABLED;
>  		pr_info("DTS is locked. Cannot enable DTS\n");
>  		ret = -EPERM;
>  	}
> @@ -161,7 +160,7 @@ static int soc_dts_disable(struct thermal_zone_device *tzd)
>  		return ret;
>  
>  	if (!(out & QRK_DTS_ENABLE_BIT)) {
> -		aux_entry->mode = THERMAL_DEVICE_DISABLED;
> +		tzd->mode = THERMAL_DEVICE_DISABLED;
>  		return 0;
>  	}
>  
> @@ -173,9 +172,9 @@ static int soc_dts_disable(struct thermal_zone_device *tzd)
>  		if (ret)
>  			return ret;
>  
> -		aux_entry->mode = THERMAL_DEVICE_DISABLED;
> +		tzd->mode = THERMAL_DEVICE_DISABLED;
>  	} else {
> -		aux_entry->mode = THERMAL_DEVICE_ENABLED;
> +		tzd->mode = THERMAL_DEVICE_ENABLED;
>  		pr_info("DTS is locked. Cannot disable DTS\n");
>  		ret = -EPERM;
>  	}
> @@ -309,14 +308,6 @@ static int sys_get_curr_temp(struct thermal_zone_device *tzd,
>  	return 0;
>  }
>  
> -static int sys_get_mode(struct thermal_zone_device *tzd,
> -				enum thermal_device_mode *mode)
> -{
> -	struct soc_sensor_entry *aux_entry = tzd->devdata;
> -	*mode = aux_entry->mode;
> -	return 0;
> -}
> -
>  static int sys_set_mode(struct thermal_zone_device *tzd,
>  				enum thermal_device_mode mode)
>  {
> @@ -338,7 +329,6 @@ static struct thermal_zone_device_ops tzone_ops = {
>  	.get_trip_type = sys_get_trip_type,
>  	.set_trip_temp = sys_set_trip_temp,
>  	.get_crit_temp = sys_get_crit_temp,
> -	.get_mode = sys_get_mode,
>  	.set_mode = sys_set_mode,
>  };
>  
> diff --git a/drivers/thermal/of-thermal.c b/drivers/thermal/of-thermal.c
> index 874a47d6923f..863b89546f81 100644
> --- a/drivers/thermal/of-thermal.c
> +++ b/drivers/thermal/of-thermal.c
> @@ -51,7 +51,6 @@ struct __thermal_bind_params {
>  
>  /**
>   * struct __thermal_zone - internal representation of a thermal zone
> - * @mode: current thermal zone device mode (enabled/disabled)
>   * @passive_delay: polling interval while passive cooling is activated
>   * @polling_delay: zone polling interval
>   * @slope: slope of the temperature adjustment curve
> @@ -65,7 +64,6 @@ struct __thermal_bind_params {
>   */
>  
>  struct __thermal_zone {
> -	enum thermal_device_mode mode;
>  	int passive_delay;
>  	int polling_delay;
>  	int slope;
> @@ -269,23 +267,11 @@ static int of_thermal_unbind(struct thermal_zone_device *thermal,
>  	return 0;
>  }
>  
> -static int of_thermal_get_mode(struct thermal_zone_device *tz,
> -			       enum thermal_device_mode *mode)
> -{
> -	struct __thermal_zone *data = tz->devdata;
> -
> -	*mode = data->mode;
> -
> -	return 0;
> -}
> -
>  static int of_thermal_set_mode(struct thermal_zone_device *tz,
>  			       enum thermal_device_mode mode)
>  {
>  	struct __thermal_zone *data = tz->devdata;
>  
> -	mutex_lock(&tz->lock);
> -
>  	if (mode == THERMAL_DEVICE_ENABLED) {
>  		tz->polling_delay = data->polling_delay;
>  		tz->passive_delay = data->passive_delay;
> @@ -294,11 +280,6 @@ static int of_thermal_set_mode(struct thermal_zone_device *tz,
>  		tz->passive_delay = 0;
>  	}
>  
> -	mutex_unlock(&tz->lock);
> -
> -	data->mode = mode;
> -	thermal_zone_device_update(tz, THERMAL_EVENT_UNSPECIFIED);
> -
>  	return 0;
>  }
>  
> @@ -393,7 +374,6 @@ static int of_thermal_get_crit_temp(struct thermal_zone_device *tz,
>  }
>  
>  static struct thermal_zone_device_ops of_thermal_ops = {
> -	.get_mode = of_thermal_get_mode,
>  	.set_mode = of_thermal_set_mode,
>  
>  	.get_trip_type = of_thermal_get_trip_type,
> @@ -553,8 +533,14 @@ thermal_zone_of_sensor_register(struct device *dev, int sensor_id, void *data,
>  		if (id == sensor_id) {
>  			tzd = thermal_zone_of_add_sensor(child, sensor_np,
>  							 data, ops);
> -			if (!IS_ERR(tzd))
> +			if (!IS_ERR(tzd)) {
> +				mutex_lock(&tzd->lock);
>  				tzd->ops->set_mode(tzd, THERMAL_DEVICE_ENABLED);
> +				tzd->mode = THERMAL_DEVICE_ENABLED;
> +				mutex_unlock(&tzd->lock);
> +				thermal_zone_device_update(tzd,
> +						THERMAL_EVENT_UNSPECIFIED);
> +			}

This should use thermal_zone_device_enable() instead of open-coding it:

			if (!IS_ERR(tzd))
				thermal_zone_device_enable(tzd);

Also because of of_thermal_set_mode() modifications following of/thermal
device drivers (which use ->set_mode directly):

drivers/thermal/hisi_thermal.c: tzd->ops->set_mode(tzd,
drivers/thermal/rockchip_thermal.c:     tzd->ops->set_mode(tzd,
drivers/thermal/sprd_thermal.c: tzd->ops->set_mode(tzd,

need to be converted to use thermal_zone_device_{en,dis}able() instead.

>  			of_node_put(child);
>  			goto exit;
> @@ -979,7 +965,6 @@ __init *thermal_of_build_thermal_zone(struct device_node *np)
>  
>  finish:
>  	of_node_put(child);
> -	tz->mode = THERMAL_DEVICE_DISABLED;
>  
>  	return tz;
>  
> @@ -1120,6 +1105,7 @@ int __init of_parse_thermal_zones(void)
>  		/* these two are left for temperature drivers to use */
>  		tzp->slope = tz->slope;
>  		tzp->offset = tz->offset;
> +		tzp->initial_mode = THERMAL_DEVICE_DISABLED;
>  
>  		zone = thermal_zone_device_register(child->name, tz->ntrips,
>  						    mask, tz,
> diff --git a/drivers/thermal/thermal_core.c b/drivers/thermal/thermal_core.c
> index c06550930979..5ff98fcc0f6a 100644
> --- a/drivers/thermal/thermal_core.c
> +++ b/drivers/thermal/thermal_core.c
> @@ -463,6 +463,43 @@ static void thermal_zone_device_reset(struct thermal_zone_device *tz)
>  	thermal_zone_device_init(tz);
>  }
>  
> +enum thermal_device_mode
> +thermal_zone_device_get_mode(struct thermal_zone_device *tz)
> +{
> +	enum thermal_device_mode mode;
> +
> +	mutex_lock(&tz->lock);
> +
> +	mode = tz->mode;
> +
> +	mutex_unlock(&tz->lock);
> +
> +	return mode;
> +}
> +
> +int thermal_zone_device_set_mode(struct thermal_zone_device *tz,
> +				 enum thermal_device_mode mode)
> +{
> +	int ret = 0;
> +
> +	if (mode != THERMAL_DEVICE_DISABLED &&
> +	    mode != THERMAL_DEVICE_ENABLED)
> +		return -EINVAL;

No need for these checks as enum thermal_device_mode has only two
possible values (we don't do "defensive coding" in the kernel).

> +	mutex_lock(&tz->lock);
> +
> +	if (tz->ops->set_mode)
> +		ret = tz->ops->set_mode(tz, mode);
> +
> +	tz->mode = mode;
> +
> +	mutex_unlock(&tz->lock);
> +
> +	thermal_zone_device_update(tz, THERMAL_EVENT_UNSPECIFIED);
> +
> +	return ret;
> +}

Please add:

EXPORT_SYMBOL_GPL(thermal_zone_device_set_mode);

here so device drivers can use thermal_zone_device_{en,dis}able().

>  void thermal_zone_device_update(struct thermal_zone_device *tz,
>  				enum thermal_notify_event event)
>  {
> @@ -1344,6 +1381,9 @@ thermal_zone_device_register(const char *type, int trips, int mask,
>  	if (atomic_cmpxchg(&tz->need_update, 1, 0))
>  		thermal_zone_device_update(tz, THERMAL_EVENT_UNSPECIFIED);
>  
> +	if (tzp)
> +		thermal_zone_device_set_mode(tz, tzp->initial_mode);

Please note that currently some device drivers don't access ->mode
at all so their default ->mode value is THERMAL_DEVICE_DISABLED but
in reality they are enabled (IOW after changes in this patch they
should default to THERMAL_DEVICE_ENABLED to reflect real device state
in "mode" sysfs attribue and not break after applying patch #2).

Therefore we should always call thermal_zone_device_set_mode() and
use the default value of THERMAL_DEVICE_ENABLED if tzp is NULL:

	mode = tzp ? tzp->initial_mode : THERMAL_DEVICE_ENABLED;
	thermal_zone_device_set_mode(tz, mode);

This would also simplify the patch further:

* setting tz->need_update and calling thermal_zone_device_update()
  directly can be removed from thermal_zone_device_register()

* tzp-s with only .initial_mode = THERMAL_DEVICE_ENABLED set can
  be removed from:

  drivers/thermal/acpi.c
  drivers/net/ethernet/mellanox/mlxsw/core_thermal.c
  drivers/thermal/da9062-thermal.c
  drivers/thermal/imx_thermal.c

The rest of the patch looks fine, thank you for working on this!

Best regards,
--
Bartlomiej Zolnierkiewicz
Samsung R&D Institute Poland
Samsung Electronics

> +
>  	return tz;
>  
>  unregister:
> @@ -1473,9 +1513,7 @@ static int thermal_pm_notify(struct notifier_block *nb,
>  	case PM_POST_SUSPEND:
>  		atomic_set(&in_suspend, 0);
>  		list_for_each_entry(tz, &thermal_tz_list, node) {
> -			tz_mode = THERMAL_DEVICE_ENABLED;
> -			if (tz->ops->get_mode)
> -				tz->ops->get_mode(tz, &tz_mode);
> +			tz_mode = thermal_zone_device_get_mode(tz);
>  
>  			if (tz_mode == THERMAL_DEVICE_DISABLED)
>  				continue;
> diff --git a/drivers/thermal/thermal_core.h b/drivers/thermal/thermal_core.h
> index c95689586e19..8e561bac3133 100644
> --- a/drivers/thermal/thermal_core.h
> +++ b/drivers/thermal/thermal_core.h
> @@ -141,6 +141,22 @@ thermal_cooling_device_stats_update(struct thermal_cooling_device *cdev,
>  				    unsigned long new_state) {}
>  #endif /* CONFIG_THERMAL_STATISTICS */
>  
> +enum thermal_device_mode
> +thermal_zone_device_get_mode(struct thermal_zone_device *tz);
> +
> +int thermal_zone_device_set_mode(struct thermal_zone_device *tz,
> +				 enum thermal_device_mode mode);
> +
> +static inline int thermal_zone_device_enable(struct thermal_zone_device *tz)
> +{
> +	return thermal_zone_device_set_mode(tz, THERMAL_DEVICE_ENABLED);
> +}
> +
> +static inline int thermal_zone_device_disable(struct thermal_zone_device *tz)
> +{
> +	return thermal_zone_device_set_mode(tz, THERMAL_DEVICE_DISABLED);
> +}
> +
>  /* device tree support */
>  #ifdef CONFIG_THERMAL_OF
>  int of_parse_thermal_zones(void);
> diff --git a/drivers/thermal/thermal_sysfs.c b/drivers/thermal/thermal_sysfs.c
> index aa99edb4dff7..cbb27b3c96d2 100644
> --- a/drivers/thermal/thermal_sysfs.c
> +++ b/drivers/thermal/thermal_sysfs.c
> @@ -50,14 +50,8 @@ mode_show(struct device *dev, struct device_attribute *attr, char *buf)
>  {
>  	struct thermal_zone_device *tz = to_thermal_zone(dev);
>  	enum thermal_device_mode mode;
> -	int result;
> -
> -	if (!tz->ops->get_mode)
> -		return -EPERM;
>  
> -	result = tz->ops->get_mode(tz, &mode);
> -	if (result)
> -		return result;
> +	mode = thermal_zone_device_get_mode(tz);
>  
>  	return sprintf(buf, "%s\n", mode == THERMAL_DEVICE_ENABLED ? "enabled"
>  		       : "disabled");
> @@ -74,9 +68,9 @@ mode_store(struct device *dev, struct device_attribute *attr,
>  		return -EPERM;
>  
>  	if (!strncmp(buf, "enabled", sizeof("enabled") - 1))
> -		result = tz->ops->set_mode(tz, THERMAL_DEVICE_ENABLED);
> +		result = thermal_zone_device_enable(tz);
>  	else if (!strncmp(buf, "disabled", sizeof("disabled") - 1))
> -		result = tz->ops->set_mode(tz, THERMAL_DEVICE_DISABLED);
> +		result = thermal_zone_device_disable(tz);
>  	else
>  		result = -EINVAL;
>  
> @@ -428,30 +422,13 @@ static struct attribute_group thermal_zone_attribute_group = {
>  	.attrs = thermal_zone_dev_attrs,
>  };
>  
> -/* We expose mode only if .get_mode is present */
>  static struct attribute *thermal_zone_mode_attrs[] = {
>  	&dev_attr_mode.attr,
>  	NULL,
>  };
>  
> -static umode_t thermal_zone_mode_is_visible(struct kobject *kobj,
> -					    struct attribute *attr,
> -					    int attrno)
> -{
> -	struct device *dev = container_of(kobj, struct device, kobj);
> -	struct thermal_zone_device *tz;
> -
> -	tz = container_of(dev, struct thermal_zone_device, device);
> -
> -	if (tz->ops->get_mode)
> -		return attr->mode;
> -
> -	return 0;
> -}
> -
>  static struct attribute_group thermal_zone_mode_attribute_group = {
>  	.attrs = thermal_zone_mode_attrs,
> -	.is_visible = thermal_zone_mode_is_visible,
>  };
>  
>  /* We expose passive only if passive trips are present */
> diff --git a/include/linux/thermal.h b/include/linux/thermal.h
> index 216185bb3014..da4141697e2e 100644
> --- a/include/linux/thermal.h
> +++ b/include/linux/thermal.h
> @@ -76,8 +76,6 @@ struct thermal_zone_device_ops {
>  		       struct thermal_cooling_device *);
>  	int (*get_temp) (struct thermal_zone_device *, int *);
>  	int (*set_trips) (struct thermal_zone_device *, int, int);
> -	int (*get_mode) (struct thermal_zone_device *,
> -			 enum thermal_device_mode *);
>  	int (*set_mode) (struct thermal_zone_device *,
>  		enum thermal_device_mode);
>  	int (*get_trip_type) (struct thermal_zone_device *, int,
> @@ -128,6 +126,7 @@ struct thermal_cooling_device {
>   * @trip_temp_attrs:	attributes for trip points for sysfs: trip temperature
>   * @trip_type_attrs:	attributes for trip points for sysfs: trip type
>   * @trip_hyst_attrs:	attributes for trip points for sysfs: trip hysteresis
> + * @mode:		current mode of this thermal zone
>   * @devdata:	private pointer for device private data
>   * @trips:	number of trip points the thermal zone supports
>   * @trips_disabled;	bitmap for disabled trips
> @@ -170,6 +169,7 @@ struct thermal_zone_device {
>  	struct thermal_attr *trip_temp_attrs;
>  	struct thermal_attr *trip_type_attrs;
>  	struct thermal_attr *trip_hyst_attrs;
> +	enum thermal_device_mode mode;
>  	void *devdata;
>  	int trips;
>  	unsigned long trips_disabled;	/* bitmap for disabled trips */
> @@ -264,6 +264,9 @@ struct thermal_zone_params {
>  	int num_tbps;	/* Number of tbp entries */
>  	struct thermal_bind_params *tbp;
>  
> +	/* Initial mode of this thermal zone device */
> +	enum thermal_device_mode initial_mode;
> +
>  	/*
>  	 * Sustainable power (heat) that this thermal zone can dissipate in
>  	 * mW
> 

^ permalink raw reply	[flat|nested] 63+ messages in thread

* Re: [RFC 0/8] Stop monitoring disabled devices
  2020-04-17 16:23         ` Andrzej Pietrasiewicz
@ 2020-04-19 11:42           ` Bartlomiej Zolnierkiewicz
  0 siblings, 0 replies; 63+ messages in thread
From: Bartlomiej Zolnierkiewicz @ 2020-04-19 11:42 UTC (permalink / raw)
  To: Andrzej Pietrasiewicz
  Cc: Daniel Lezcano, linux-pm, Zhang Rui, Rafael J . Wysocki,
	Len Brown, Jiri Pirko, Ido Schimmel, David S . Miller,
	Peter Kaestle, Darren Hart, Andy Shevchenko, Support Opensource,
	Amit Kucheria, Shawn Guo, Sascha Hauer, Pengutronix Kernel Team,
	Fabio Estevam, NXP Linux Team, Allison Randal, Enrico Weigelt,
	Gayatri Kammela, Thomas Gleixner, linux-acpi, netdev,
	platform-driver-x86, linux-arm-kernel, kernel


On 4/17/20 6:23 PM, Andrzej Pietrasiewicz wrote:
> Hi Barlomiej,
> 
>>> Thanks for feedback.
>>>
>>> Anyone else?
>>
>> Yes. :)
>>
>> Please take a look at the following patchset (which I'm reviving currently):
>>
>>     https://protect2.fireeye.com/url?k=5d37badf-00a92135-5d363190-0cc47a6cba04-376ae45aa028b19a&q=1&u=https%3A%2F%2Flkml.org%2Flkml%2F2018%2F10%2F17%2F926
>>
>> It overlaps partially with your work so we need to coordinate our efforts.
>>
> 
> I've just sent a v3. After addressing your and Daniel's comments my series
> now looks pretty compact. Let's see if there's more feedback. Is your work on
> reviving the above mentioned 2018 series ready?

Not yet, also I think now that it will be the best if I rebase my changes on
top of your patchset (once it is ready/finished).

Best regards,
--
Bartlomiej Zolnierkiewicz
Samsung R&D Institute Poland
Samsung Electronics

^ permalink raw reply	[flat|nested] 63+ messages in thread

* Re: [RFC v3 1/2] thermal: core: Let thermal zone device's mode be stored in its struct
  2020-04-19 11:38             ` Bartlomiej Zolnierkiewicz
@ 2020-04-19 13:10               ` Bartlomiej Zolnierkiewicz
  2020-04-20 18:17                 ` [PATCH 0/2] Stop monitoring disabled devices Andrzej Pietrasiewicz
  2020-04-20 11:03               ` [RFC v3 1/2] thermal: core: Let thermal zone device's mode be stored in its struct Andrzej Pietrasiewicz
  1 sibling, 1 reply; 63+ messages in thread
From: Bartlomiej Zolnierkiewicz @ 2020-04-19 13:10 UTC (permalink / raw)
  To: Andrzej Pietrasiewicz
  Cc: linux-pm, Zhang Rui, Rafael J . Wysocki, Len Brown, Jiri Pirko,
	Ido Schimmel, David S . Miller, Peter Kaestle, Darren Hart,
	Andy Shevchenko, Support Opensource, Daniel Lezcano,
	Amit Kucheria, Shawn Guo, Sascha Hauer, Pengutronix Kernel Team,
	Fabio Estevam, NXP Linux Team, Allison Randal, Enrico Weigelt,
	Gayatri Kammela, Thomas Gleixner, linux-acpi, netdev,
	platform-driver-x86, linux-arm-kernel, kernel


On 4/19/20 1:38 PM, Bartlomiej Zolnierkiewicz wrote:
> 
> Hi Andrzej,
> 
> On 4/17/20 6:20 PM, Andrzej Pietrasiewicz wrote:
>> Thermal zone devices' mode is stored in individual drivers. This patch
>> changes it so that mode is stored in struct thermal_zone_device instead.
>>
>> As a result all driver-specific variables storing the mode are not needed
>> and are removed. Consequently, the get_mode() implementations have nothing
>> to operate on and need to be removed, too.
>>
>> Some thermal framework specific functions are introduced:
>>
>> thermal_zone_device_get_mode()
>> thermal_zone_device_set_mode()
>> thermal_zone_device_enable()
>> thermal_zone_device_disable()
>>
>> thermal_zone_device_get_mode() and its "set" counterpart take tzd's lock
>> and the "set" calls driver's set_mode() if provided, so the latter must
>> not take this lock again. At the end of the "set"
>> thermal_zone_device_update() is called so drivers don't need to repeat this
>> invocation in their specific set_mode() implementations.
>>
>> The scope of the above 4 functions is purposedly limited to the thermal
>> framework and drivers are not supposed to call them. This encapsulation
> 
> This should be true only for thermal_zone_device_{get,set}_mode().
> 
> thermal_zone_device_{en,dis}able() should be available for device drivers:
> 
> * of/thermal device drivers need to enable thermal device itself
>   (please refer to my patchset for details)
> 
> * device drivers need to call them on ->suspend and ->resume operations
> 
>> does not fully work at the moment for some drivers, though:
>>
>> - platform/x86/acerhdf.c
>> - drivers/thermal/imx_thermal.c
>> - drivers/thermal/intel/intel_quark_dts_thermal.c
>> - drivers/thermal/of-thermal.c
>>
>> and they manipulate struct thermal_zone_device's members directly.
>>
>> struct thermal_zone_params gains a new member called initial_mode, which
>> is used to set tzd's mode at registration time.
>>
>> The sysfs "mode" attribute is always exposed from now on, because all
>> thermal zone devices now have their get_mode() implemented at the generic
>> level and it is always available. Exposing "mode" doesn't hurt the drivers
>> which don't provide their own set_mode(), because writing to "mode" will
>> result in -EPERM, as expected.
>>
>> Signed-off-by: Andrzej Pietrasiewicz <andrzej.p@collabora.com>
>> ---
>>  drivers/acpi/thermal.c                        | 46 +++++----------
>>  .../ethernet/mellanox/mlxsw/core_thermal.c    | 57 ++++---------------
>>  drivers/platform/x86/acerhdf.c                | 17 +-----
>>  drivers/thermal/da9062-thermal.c              | 16 ++----
>>  drivers/thermal/imx_thermal.c                 | 29 +++-------
>>  .../intel/int340x_thermal/int3400_thermal.c   | 30 ++--------
>>  .../thermal/intel/intel_quark_dts_thermal.c   | 22 ++-----
>>  drivers/thermal/of-thermal.c                  | 30 +++-------
>>  drivers/thermal/thermal_core.c                | 44 +++++++++++++-
>>  drivers/thermal/thermal_core.h                | 16 ++++++
>>  drivers/thermal/thermal_sysfs.c               | 29 +---------
>>  include/linux/thermal.h                       |  7 ++-
>>  12 files changed, 125 insertions(+), 218 deletions(-)
>>
>> diff --git a/drivers/acpi/thermal.c b/drivers/acpi/thermal.c
>> index 19067a5e5293..67bc263332a5 100644
>> --- a/drivers/acpi/thermal.c
>> +++ b/drivers/acpi/thermal.c
>> @@ -172,7 +172,6 @@ struct acpi_thermal {
>>  	struct acpi_thermal_trips trips;
>>  	struct acpi_handle_list devices;
>>  	struct thermal_zone_device *thermal_zone;
>> -	int tz_enabled;
>>  	int kelvin_offset;	/* in millidegrees */
>>  	struct work_struct thermal_check_work;
>>  };
>> @@ -500,7 +499,7 @@ static void acpi_thermal_check(void *data)
>>  {
>>  	struct acpi_thermal *tz = data;
>>  
>> -	if (!tz->tz_enabled)
>> +	if (tz->thermal_zone->mode != THERMAL_DEVICE_ENABLED)
>>  		return;
>>  
>>  	thermal_zone_device_update(tz->thermal_zone,
>> @@ -526,46 +525,29 @@ static int thermal_get_temp(struct thermal_zone_device *thermal, int *temp)
>>  	return 0;
>>  }
>>  
>> -static int thermal_get_mode(struct thermal_zone_device *thermal,
>> -				enum thermal_device_mode *mode)
>> -{
>> -	struct acpi_thermal *tz = thermal->devdata;
>> -
>> -	if (!tz)
>> -		return -EINVAL;
>> -
>> -	*mode = tz->tz_enabled ? THERMAL_DEVICE_ENABLED :
>> -		THERMAL_DEVICE_DISABLED;
>> -
>> -	return 0;
>> -}
>> -
>>  static int thermal_set_mode(struct thermal_zone_device *thermal,
>>  				enum thermal_device_mode mode)
>>  {
>>  	struct acpi_thermal *tz = thermal->devdata;
>> -	int enable;
>>  
>>  	if (!tz)
>>  		return -EINVAL;
>>  
>> +	if (mode != THERMAL_DEVICE_DISABLED &&
>> +	    mode != THERMAL_DEVICE_ENABLED)
>> +		return -EINVAL;
> 
> These checks should be removed as they are already done in the caller
> of ->set_mode method (thermal_zone_device_set_mode()).
> 
>> +
>>  	/*
>>  	 * enable/disable thermal management from ACPI thermal driver
>>  	 */
>> -	if (mode == THERMAL_DEVICE_ENABLED)
>> -		enable = 1;
>> -	else if (mode == THERMAL_DEVICE_DISABLED) {
>> -		enable = 0;
>> +	if (mode == THERMAL_DEVICE_DISABLED)
>>  		pr_warn("thermal zone will be disabled\n");
>> -	} else
>> -		return -EINVAL;
>>  
>> -	if (enable != tz->tz_enabled) {
>> -		tz->tz_enabled = enable;
>> +	if (mode != thermal->mode) {
>>  		ACPI_DEBUG_PRINT((ACPI_DB_INFO,
>>  			"%s kernel ACPI thermal control\n",
>> -			tz->tz_enabled ? "Enable" : "Disable"));
>> -		acpi_thermal_check(tz);
>> +			mode == THERMAL_DEVICE_ENABLED ?
>> +			"Enable" : "Disable"));
>>  	}
>>  	return 0;
>>  }
>> @@ -856,7 +838,6 @@ static struct thermal_zone_device_ops acpi_thermal_zone_ops = {
>>  	.bind = acpi_thermal_bind_cooling_device,
>>  	.unbind	= acpi_thermal_unbind_cooling_device,
>>  	.get_temp = thermal_get_temp,
>> -	.get_mode = thermal_get_mode,
>>  	.set_mode = thermal_set_mode,
>>  	.get_trip_type = thermal_get_trip_type,
>>  	.get_trip_temp = thermal_get_trip_temp,
>> @@ -870,6 +851,9 @@ static int acpi_thermal_register_thermal_zone(struct acpi_thermal *tz)
>>  	int trips = 0;
>>  	int result;
>>  	acpi_status status;
>> +	struct thermal_zone_params prms = {
>> +		.initial_mode = THERMAL_DEVICE_ENABLED,
>> +	};
>>  	int i;
>>  
>>  	if (tz->trips.critical.flags.valid)
>> @@ -887,13 +871,13 @@ static int acpi_thermal_register_thermal_zone(struct acpi_thermal *tz)
>>  	if (tz->trips.passive.flags.valid)
>>  		tz->thermal_zone =
>>  			thermal_zone_device_register("acpitz", trips, 0, tz,
>> -						&acpi_thermal_zone_ops, NULL,
>> +						&acpi_thermal_zone_ops, &prms,
>>  						     tz->trips.passive.tsp*100,
>>  						     tz->polling_frequency*100);
>>  	else
>>  		tz->thermal_zone =
>>  			thermal_zone_device_register("acpitz", trips, 0, tz,
>> -						&acpi_thermal_zone_ops, NULL,
>> +						&acpi_thermal_zone_ops, &prms,
>>  						0, tz->polling_frequency*100);
>>  	if (IS_ERR(tz->thermal_zone))
>>  		return -ENODEV;
>> @@ -913,8 +897,6 @@ static int acpi_thermal_register_thermal_zone(struct acpi_thermal *tz)
>>  	if (ACPI_FAILURE(status))
>>  		return -ENODEV;
>>  
>> -	tz->tz_enabled = 1;
>> -
>>  	dev_info(&tz->device->dev, "registered as thermal_zone%d\n",
>>  		 tz->thermal_zone->id);
>>  	return 0;
>> diff --git a/drivers/net/ethernet/mellanox/mlxsw/core_thermal.c b/drivers/net/ethernet/mellanox/mlxsw/core_thermal.c
>> index ce0a6837daa3..50518048b86d 100644
>> --- a/drivers/net/ethernet/mellanox/mlxsw/core_thermal.c
>> +++ b/drivers/net/ethernet/mellanox/mlxsw/core_thermal.c
>> @@ -98,7 +98,6 @@ struct mlxsw_thermal_module {
>>  	struct mlxsw_thermal *parent;
>>  	struct thermal_zone_device *tzdev;
>>  	struct mlxsw_thermal_trip trips[MLXSW_THERMAL_NUM_TRIPS];
>> -	enum thermal_device_mode mode;
>>  	int module; /* Module or gearbox number */
>>  };
>>  
>> @@ -110,7 +109,6 @@ struct mlxsw_thermal {
>>  	struct thermal_cooling_device *cdevs[MLXSW_MFCR_PWMS_MAX];
>>  	u8 cooling_levels[MLXSW_THERMAL_MAX_STATE + 1];
>>  	struct mlxsw_thermal_trip trips[MLXSW_THERMAL_NUM_TRIPS];
>> -	enum thermal_device_mode mode;
>>  	struct mlxsw_thermal_module *tz_module_arr;
>>  	u8 tz_module_num;
>>  	struct mlxsw_thermal_module *tz_gearbox_arr;
>> @@ -277,33 +275,16 @@ static int mlxsw_thermal_unbind(struct thermal_zone_device *tzdev,
>>  	return 0;
>>  }
>>  
>> -static int mlxsw_thermal_get_mode(struct thermal_zone_device *tzdev,
>> -				  enum thermal_device_mode *mode)
>> -{
>> -	struct mlxsw_thermal *thermal = tzdev->devdata;
>> -
>> -	*mode = thermal->mode;
>> -
>> -	return 0;
>> -}
>> -
>>  static int mlxsw_thermal_set_mode(struct thermal_zone_device *tzdev,
>>  				  enum thermal_device_mode mode)
>>  {
>>  	struct mlxsw_thermal *thermal = tzdev->devdata;
>>  
>> -	mutex_lock(&tzdev->lock);
>> -
>>  	if (mode == THERMAL_DEVICE_ENABLED)
>>  		tzdev->polling_delay = thermal->polling_delay;
>>  	else
>>  		tzdev->polling_delay = 0;
>>  
>> -	mutex_unlock(&tzdev->lock);
>> -
>> -	thermal->mode = mode;
>> -	thermal_zone_device_update(tzdev, THERMAL_EVENT_UNSPECIFIED);
>> -
>>  	return 0;
>>  }
>>  
>> @@ -407,7 +388,6 @@ static int mlxsw_thermal_trend_get(struct thermal_zone_device *tzdev,
>>  static struct thermal_zone_device_ops mlxsw_thermal_ops = {
>>  	.bind = mlxsw_thermal_bind,
>>  	.unbind = mlxsw_thermal_unbind,
>> -	.get_mode = mlxsw_thermal_get_mode,
>>  	.set_mode = mlxsw_thermal_set_mode,
>>  	.get_temp = mlxsw_thermal_get_temp,
>>  	.get_trip_type	= mlxsw_thermal_get_trip_type,
>> @@ -466,34 +446,17 @@ static int mlxsw_thermal_module_unbind(struct thermal_zone_device *tzdev,
>>  	return err;
>>  }
>>  
>> -static int mlxsw_thermal_module_mode_get(struct thermal_zone_device *tzdev,
>> -					 enum thermal_device_mode *mode)
>> -{
>> -	struct mlxsw_thermal_module *tz = tzdev->devdata;
>> -
>> -	*mode = tz->mode;
>> -
>> -	return 0;
>> -}
>> -
>>  static int mlxsw_thermal_module_mode_set(struct thermal_zone_device *tzdev,
>>  					 enum thermal_device_mode mode)
>>  {
>>  	struct mlxsw_thermal_module *tz = tzdev->devdata;
>>  	struct mlxsw_thermal *thermal = tz->parent;
>>  
>> -	mutex_lock(&tzdev->lock);
>> -
>>  	if (mode == THERMAL_DEVICE_ENABLED)
>>  		tzdev->polling_delay = thermal->polling_delay;
>>  	else
>>  		tzdev->polling_delay = 0;
>>  
>> -	mutex_unlock(&tzdev->lock);
>> -
>> -	tz->mode = mode;
>> -	thermal_zone_device_update(tzdev, THERMAL_EVENT_UNSPECIFIED);
>> -
>>  	return 0;
>>  }
>>  
>> @@ -596,7 +559,6 @@ mlxsw_thermal_module_trip_hyst_set(struct thermal_zone_device *tzdev, int trip,
>>  static struct thermal_zone_device_ops mlxsw_thermal_module_ops = {
>>  	.bind		= mlxsw_thermal_module_bind,
>>  	.unbind		= mlxsw_thermal_module_unbind,
>> -	.get_mode	= mlxsw_thermal_module_mode_get,
>>  	.set_mode	= mlxsw_thermal_module_mode_set,
>>  	.get_temp	= mlxsw_thermal_module_temp_get,
>>  	.get_trip_type	= mlxsw_thermal_module_trip_type_get,
>> @@ -635,7 +597,6 @@ static int mlxsw_thermal_gearbox_temp_get(struct thermal_zone_device *tzdev,
>>  static struct thermal_zone_device_ops mlxsw_thermal_gearbox_ops = {
>>  	.bind		= mlxsw_thermal_module_bind,
>>  	.unbind		= mlxsw_thermal_module_unbind,
>> -	.get_mode	= mlxsw_thermal_module_mode_get,
>>  	.set_mode	= mlxsw_thermal_module_mode_set,
>>  	.get_temp	= mlxsw_thermal_gearbox_temp_get,
>>  	.get_trip_type	= mlxsw_thermal_module_trip_type_get,
>> @@ -749,6 +710,9 @@ static const struct thermal_cooling_device_ops mlxsw_cooling_ops = {
>>  static int
>>  mlxsw_thermal_module_tz_init(struct mlxsw_thermal_module *module_tz)
>>  {
>> +	struct thermal_zone_params tzp = {
>> +		.initial_mode = THERMAL_DEVICE_ENABLED,
>> +	};
>>  	char tz_name[MLXSW_THERMAL_ZONE_MAX_NAME];
>>  	int err;
>>  
>> @@ -759,13 +723,12 @@ mlxsw_thermal_module_tz_init(struct mlxsw_thermal_module *module_tz)
>>  							MLXSW_THERMAL_TRIP_MASK,
>>  							module_tz,
>>  							&mlxsw_thermal_module_ops,
>> -							NULL, 0, 0);
>> +							&tzp, 0, 0);
>>  	if (IS_ERR(module_tz->tzdev)) {
>>  		err = PTR_ERR(module_tz->tzdev);
>>  		return err;
>>  	}
>>  
>> -	module_tz->mode = THERMAL_DEVICE_ENABLED;
>>  	return 0;
>>  }
>>  
>> @@ -868,6 +831,9 @@ mlxsw_thermal_modules_fini(struct mlxsw_thermal *thermal)
>>  static int
>>  mlxsw_thermal_gearbox_tz_init(struct mlxsw_thermal_module *gearbox_tz)
>>  {
>> +	struct thermal_zone_params tzp = {
>> +		.initial_mode = THERMAL_DEVICE_ENABLED,
>> +	};
>>  	char tz_name[MLXSW_THERMAL_ZONE_MAX_NAME];
>>  
>>  	snprintf(tz_name, sizeof(tz_name), "mlxsw-gearbox%d",
>> @@ -877,11 +843,10 @@ mlxsw_thermal_gearbox_tz_init(struct mlxsw_thermal_module *gearbox_tz)
>>  						MLXSW_THERMAL_TRIP_MASK,
>>  						gearbox_tz,
>>  						&mlxsw_thermal_gearbox_ops,
>> -						NULL, 0, 0);
>> +						&tzp, 0, 0);
>>  	if (IS_ERR(gearbox_tz->tzdev))
>>  		return PTR_ERR(gearbox_tz->tzdev);
>>  
>> -	gearbox_tz->mode = THERMAL_DEVICE_ENABLED;
>>  	return 0;
>>  }
>>  
>> @@ -960,6 +925,9 @@ int mlxsw_thermal_init(struct mlxsw_core *core,
>>  		       const struct mlxsw_bus_info *bus_info,
>>  		       struct mlxsw_thermal **p_thermal)
>>  {
>> +	struct thermal_zone_params tzp = {
>> +		.initial_mode = THERMAL_DEVICE_ENABLED,
>> +	};
>>  	char mfcr_pl[MLXSW_REG_MFCR_LEN] = { 0 };
>>  	enum mlxsw_reg_mfcr_pwm_frequency freq;
>>  	struct device *dev = bus_info->dev;
>> @@ -1034,7 +1002,7 @@ int mlxsw_thermal_init(struct mlxsw_core *core,
>>  						      MLXSW_THERMAL_TRIP_MASK,
>>  						      thermal,
>>  						      &mlxsw_thermal_ops,
>> -						      NULL, 0,
>> +						      &tzp, 0,
>>  						      thermal->polling_delay);
>>  	if (IS_ERR(thermal->tzdev)) {
>>  		err = PTR_ERR(thermal->tzdev);
>> @@ -1050,7 +1018,6 @@ int mlxsw_thermal_init(struct mlxsw_core *core,
>>  	if (err)
>>  		goto err_unreg_modules_tzdev;
>>  
>> -	thermal->mode = THERMAL_DEVICE_ENABLED;
>>  	*p_thermal = thermal;
>>  	return 0;
>>  
>> diff --git a/drivers/platform/x86/acerhdf.c b/drivers/platform/x86/acerhdf.c
>> index 8cc86f4e3ac1..aaf8b845be90 100644
>> --- a/drivers/platform/x86/acerhdf.c
>> +++ b/drivers/platform/x86/acerhdf.c
>> @@ -406,22 +406,9 @@ static inline void acerhdf_enable_kernelmode(void)
>>  	kernelmode = 1;
>>  
>>  	thz_dev->polling_delay = interval*1000;
>> -	thermal_zone_device_update(thz_dev, THERMAL_EVENT_UNSPECIFIED);
>>  	pr_notice("kernel mode fan control ON\n");
>>  }
>>  
>> -static int acerhdf_get_mode(struct thermal_zone_device *thermal,
>> -			    enum thermal_device_mode *mode)
>> -{
>> -	if (verbose)
>> -		pr_notice("kernel mode fan control %d\n", kernelmode);
>> -
>> -	*mode = (kernelmode) ? THERMAL_DEVICE_ENABLED
>> -			     : THERMAL_DEVICE_DISABLED;
>> -
>> -	return 0;
>> -}
>> -
>>  /*
>>   * set operation mode;
>>   * enabled: the thermal layer of the kernel takes care about
>> @@ -488,7 +475,6 @@ static struct thermal_zone_device_ops acerhdf_dev_ops = {
>>  	.bind = acerhdf_bind,
>>  	.unbind = acerhdf_unbind,
>>  	.get_temp = acerhdf_get_ec_temp,
>> -	.get_mode = acerhdf_get_mode,
>>  	.set_mode = acerhdf_set_mode,
>>  	.get_trip_type = acerhdf_get_trip_type,
>>  	.get_trip_hyst = acerhdf_get_trip_hyst,
>> @@ -554,6 +540,7 @@ static int acerhdf_set_cur_state(struct thermal_cooling_device *cdev,
>>  
>>  err_out:
>>  	acerhdf_revert_to_bios_mode();
>> +	thz_dev->mode = THERMAL_DEVICE_DISABLED;
>>  	return -EINVAL;
>>  }
>>  
>> @@ -739,6 +726,8 @@ static int __init acerhdf_register_thermal(void)
>>  	if (IS_ERR(cl_dev))
>>  		return -EINVAL;
>>  
>> +	acerhdf_zone_params.initial_mode =
>> +		kernelmode ? THERMAL_DEVICE_ENABLED : THERMAL_DEVICE_DISABLED;
>>  	thz_dev = thermal_zone_device_register("acerhdf", 2, 0, NULL,
>>  					      &acerhdf_dev_ops,
>>  					      &acerhdf_zone_params, 0,
>> diff --git a/drivers/thermal/da9062-thermal.c b/drivers/thermal/da9062-thermal.c
>> index c32709badeda..4bdb6f9621c1 100644
>> --- a/drivers/thermal/da9062-thermal.c
>> +++ b/drivers/thermal/da9062-thermal.c
>> @@ -49,7 +49,6 @@ struct da9062_thermal {
>>  	struct da9062 *hw;
>>  	struct delayed_work work;
>>  	struct thermal_zone_device *zone;
>> -	enum thermal_device_mode mode;
>>  	struct mutex lock; /* protection for da9062_thermal temperature */
>>  	int temperature;
>>  	int irq;
>> @@ -121,14 +120,6 @@ static irqreturn_t da9062_thermal_irq_handler(int irq, void *data)
>>  	return IRQ_HANDLED;
>>  }
>>  
>> -static int da9062_thermal_get_mode(struct thermal_zone_device *z,
>> -				   enum thermal_device_mode *mode)
>> -{
>> -	struct da9062_thermal *thermal = z->devdata;
>> -	*mode = thermal->mode;
>> -	return 0;
>> -}
>> -
>>  static int da9062_thermal_get_trip_type(struct thermal_zone_device *z,
>>  					int trip,
>>  					enum thermal_trip_type *type)
>> @@ -181,7 +172,6 @@ static int da9062_thermal_get_temp(struct thermal_zone_device *z,
>>  
>>  static struct thermal_zone_device_ops da9062_thermal_ops = {
>>  	.get_temp	= da9062_thermal_get_temp,
>> -	.get_mode	= da9062_thermal_get_mode,
>>  	.get_trip_type	= da9062_thermal_get_trip_type,
>>  	.get_trip_temp	= da9062_thermal_get_trip_temp,
>>  };
>> @@ -199,6 +189,9 @@ MODULE_DEVICE_TABLE(of, da9062_compatible_reg_id_table);
>>  
>>  static int da9062_thermal_probe(struct platform_device *pdev)
>>  {
>> +	struct thermal_zone_params tzp = {
>> +		.initial_mode = THERMAL_DEVICE_ENABLED,
>> +	};
>>  	struct da9062 *chip = dev_get_drvdata(pdev->dev.parent);
>>  	struct da9062_thermal *thermal;
>>  	unsigned int pp_tmp = DA9062_DEFAULT_POLLING_MS_PERIOD;
>> @@ -233,7 +226,6 @@ static int da9062_thermal_probe(struct platform_device *pdev)
>>  
>>  	thermal->config = match->data;
>>  	thermal->hw = chip;
>> -	thermal->mode = THERMAL_DEVICE_ENABLED;
>>  	thermal->dev = &pdev->dev;
>>  
>>  	INIT_DELAYED_WORK(&thermal->work, da9062_thermal_poll_on);
>> @@ -241,7 +233,7 @@ static int da9062_thermal_probe(struct platform_device *pdev)
>>  
>>  	thermal->zone = thermal_zone_device_register(thermal->config->name,
>>  					1, 0, thermal,
>> -					&da9062_thermal_ops, NULL, pp_tmp,
>> +					&da9062_thermal_ops, &tzp, pp_tmp,
>>  					0);
>>  	if (IS_ERR(thermal->zone)) {
>>  		dev_err(&pdev->dev, "Cannot register thermal zone device\n");
>> diff --git a/drivers/thermal/imx_thermal.c b/drivers/thermal/imx_thermal.c
>> index e761c9b42217..3e02323c938b 100644
>> --- a/drivers/thermal/imx_thermal.c
>> +++ b/drivers/thermal/imx_thermal.c
>> @@ -197,7 +197,6 @@ struct imx_thermal_data {
>>  	struct cpufreq_policy *policy;
>>  	struct thermal_zone_device *tz;
>>  	struct thermal_cooling_device *cdev;
>> -	enum thermal_device_mode mode;
>>  	struct regmap *tempmon;
>>  	u32 c1, c2; /* See formula in imx_init_calib() */
>>  	int temp_passive;
>> @@ -256,7 +255,7 @@ static int imx_get_temp(struct thermal_zone_device *tz, int *temp)
>>  	bool wait;
>>  	u32 val;
>>  
>> -	if (data->mode == THERMAL_DEVICE_ENABLED) {
>> +	if (tz->mode == THERMAL_DEVICE_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 +282,7 @@ static int imx_get_temp(struct thermal_zone_device *tz, int *temp)
>>  
>>  	regmap_read(map, soc_data->temp_data, &val);
>>  
>> -	if (data->mode != THERMAL_DEVICE_ENABLED) {
>> +	if (tz->mode != THERMAL_DEVICE_ENABLED) {
>>  		regmap_write(map, soc_data->sensor_ctrl + REG_CLR,
>>  			     soc_data->measure_temp_mask);
>>  		regmap_write(map, soc_data->sensor_ctrl + REG_SET,
>> @@ -331,16 +330,6 @@ static int imx_get_temp(struct thermal_zone_device *tz, int *temp)
>>  	return 0;
>>  }
>>  
>> -static int imx_get_mode(struct thermal_zone_device *tz,
>> -			enum thermal_device_mode *mode)
>> -{
>> -	struct imx_thermal_data *data = tz->devdata;
>> -
>> -	*mode = data->mode;
>> -
>> -	return 0;
>> -}
>> -
>>  static int imx_set_mode(struct thermal_zone_device *tz,
>>  			enum thermal_device_mode mode)
>>  {
>> @@ -376,9 +365,6 @@ static int imx_set_mode(struct thermal_zone_device *tz,
>>  		}
>>  	}
>>  
>> -	data->mode = mode;
>> -	thermal_zone_device_update(tz, THERMAL_EVENT_UNSPECIFIED);
>> -
>>  	return 0;
>>  }
>>  
>> @@ -467,7 +453,6 @@ static struct thermal_zone_device_ops imx_tz_ops = {
>>  	.bind = imx_bind,
>>  	.unbind = imx_unbind,
>>  	.get_temp = imx_get_temp,
>> -	.get_mode = imx_get_mode,
>>  	.set_mode = imx_set_mode,
>>  	.get_trip_type = imx_get_trip_type,
>>  	.get_trip_temp = imx_get_trip_temp,
>> @@ -691,6 +676,9 @@ static inline void imx_thermal_unregister_legacy_cooling(struct imx_thermal_data
>>  
>>  static int imx_thermal_probe(struct platform_device *pdev)
>>  {
>> +	struct thermal_zone_params tzp = {
>> +		.initial_mode = THERMAL_DEVICE_ENABLED,
>> +	};
>>  	struct imx_thermal_data *data;
>>  	struct regmap *map;
>>  	int measure_freq;
>> @@ -799,7 +787,7 @@ static int imx_thermal_probe(struct platform_device *pdev)
>>  	data->tz = thermal_zone_device_register("imx_thermal_zone",
>>  						IMX_TRIP_NUM,
>>  						BIT(IMX_TRIP_PASSIVE), data,
>> -						&imx_tz_ops, NULL,
>> +						&imx_tz_ops, &tzp,
>>  						IMX_PASSIVE_DELAY,
>>  						IMX_POLLING_DELAY);
>>  	if (IS_ERR(data->tz)) {
>> @@ -831,7 +819,6 @@ static int imx_thermal_probe(struct platform_device *pdev)
>>  		     data->socdata->measure_temp_mask);
>>  
>>  	data->irq_enabled = true;
>> -	data->mode = THERMAL_DEVICE_ENABLED;
>>  
>>  	ret = devm_request_threaded_irq(&pdev->dev, data->irq,
>>  			imx_thermal_alarm_irq, imx_thermal_alarm_irq_thread,
>> @@ -885,7 +872,7 @@ static int __maybe_unused imx_thermal_suspend(struct device *dev)
>>  		     data->socdata->measure_temp_mask);
>>  	regmap_write(map, data->socdata->sensor_ctrl + REG_SET,
>>  		     data->socdata->power_down_mask);
>> -	data->mode = THERMAL_DEVICE_DISABLED;
>> +	data->tz->mode = THERMAL_DEVICE_DISABLED;
>>  	clk_disable_unprepare(data->thermal_clk);
>>  
>>  	return 0;
>> @@ -905,7 +892,7 @@ static int __maybe_unused imx_thermal_resume(struct device *dev)
>>  		     data->socdata->power_down_mask);
>>  	regmap_write(map, data->socdata->sensor_ctrl + REG_SET,
>>  		     data->socdata->measure_temp_mask);
>> -	data->mode = THERMAL_DEVICE_ENABLED;
>> +	data->tz->mode = THERMAL_DEVICE_ENABLED;
>>  
>>  	return 0;
>>  }
>> diff --git a/drivers/thermal/intel/int340x_thermal/int3400_thermal.c b/drivers/thermal/intel/int340x_thermal/int3400_thermal.c
>> index e802922a13cf..86a00598ed09 100644
>> --- a/drivers/thermal/intel/int340x_thermal/int3400_thermal.c
>> +++ b/drivers/thermal/intel/int340x_thermal/int3400_thermal.c
>> @@ -44,7 +44,6 @@ static char *int3400_thermal_uuids[INT3400_THERMAL_MAXIMUM_UUID] = {
>>  struct int3400_thermal_priv {
>>  	struct acpi_device *adev;
>>  	struct thermal_zone_device *thermal;
>> -	int mode;
>>  	int art_count;
>>  	struct art *arts;
>>  	int trt_count;
>> @@ -230,48 +229,29 @@ static int int3400_thermal_get_temp(struct thermal_zone_device *thermal,
>>  	return 0;
>>  }
>>  
>> -static int int3400_thermal_get_mode(struct thermal_zone_device *thermal,
>> -				enum thermal_device_mode *mode)
>> -{
>> -	struct int3400_thermal_priv *priv = thermal->devdata;
>> -
>> -	if (!priv)
>> -		return -EINVAL;
>> -
>> -	*mode = priv->mode;
>> -
>> -	return 0;
>> -}
>> -
>>  static int int3400_thermal_set_mode(struct thermal_zone_device *thermal,
>>  				enum thermal_device_mode mode)
>>  {
>>  	struct int3400_thermal_priv *priv = thermal->devdata;
>> -	bool enable;
>>  	int result = 0;
>>  
>>  	if (!priv)
>>  		return -EINVAL;
>>  
>> -	if (mode == THERMAL_DEVICE_ENABLED)
>> -		enable = true;
>> -	else if (mode == THERMAL_DEVICE_DISABLED)
>> -		enable = false;
>> -	else
>> +	if (mode != THERMAL_DEVICE_ENABLED &&
>> +	    mode != THERMAL_DEVICE_DISABLED)
>>  		return -EINVAL;
> 
> These checks should be removed as they are already done in the caller
> of ->set_mode method (thermal_zone_device_set_mode()).
> 
>> -	if (enable != priv->mode) {
>> -		priv->mode = enable;
>> +	if (mode != thermal->mode) {
>>  		result = int3400_thermal_run_osc(priv->adev->handle,
>> -						 priv->current_uuid_index,
>> -						 enable);
>> +						priv->current_uuid_index,
>> +						mode == THERMAL_DEVICE_ENABLED);
>>  	}
>>  	return result;
>>  }
>>  
>>  static struct thermal_zone_device_ops int3400_thermal_ops = {
>>  	.get_temp = int3400_thermal_get_temp,
>> -	.get_mode = int3400_thermal_get_mode,
>>  	.set_mode = int3400_thermal_set_mode,
>>  };
>>  
>> diff --git a/drivers/thermal/intel/intel_quark_dts_thermal.c b/drivers/thermal/intel/intel_quark_dts_thermal.c
>> index d704fc104cfd..c4879b4bfbf1 100644
>> --- a/drivers/thermal/intel/intel_quark_dts_thermal.c
>> +++ b/drivers/thermal/intel/intel_quark_dts_thermal.c
>> @@ -103,7 +103,6 @@ struct soc_sensor_entry {
>>  	bool locked;
>>  	u32 store_ptps;
>>  	u32 store_dts_enable;
>> -	enum thermal_device_mode mode;
>>  	struct thermal_zone_device *tzone;
>>  };
>>  
>> @@ -128,7 +127,7 @@ static int soc_dts_enable(struct thermal_zone_device *tzd)
>>  		return ret;
>>  
>>  	if (out & QRK_DTS_ENABLE_BIT) {
>> -		aux_entry->mode = THERMAL_DEVICE_ENABLED;
>> +		tzd->mode = THERMAL_DEVICE_ENABLED;
>>  		return 0;
>>  	}
>>  
>> @@ -139,9 +138,9 @@ static int soc_dts_enable(struct thermal_zone_device *tzd)
>>  		if (ret)
>>  			return ret;
>>  
>> -		aux_entry->mode = THERMAL_DEVICE_ENABLED;
>> +		tzd->mode = THERMAL_DEVICE_ENABLED;
>>  	} else {
>> -		aux_entry->mode = THERMAL_DEVICE_DISABLED;
>> +		tzd->mode = THERMAL_DEVICE_DISABLED;
>>  		pr_info("DTS is locked. Cannot enable DTS\n");
>>  		ret = -EPERM;
>>  	}
>> @@ -161,7 +160,7 @@ static int soc_dts_disable(struct thermal_zone_device *tzd)
>>  		return ret;
>>  
>>  	if (!(out & QRK_DTS_ENABLE_BIT)) {
>> -		aux_entry->mode = THERMAL_DEVICE_DISABLED;
>> +		tzd->mode = THERMAL_DEVICE_DISABLED;
>>  		return 0;
>>  	}
>>  
>> @@ -173,9 +172,9 @@ static int soc_dts_disable(struct thermal_zone_device *tzd)
>>  		if (ret)
>>  			return ret;
>>  
>> -		aux_entry->mode = THERMAL_DEVICE_DISABLED;
>> +		tzd->mode = THERMAL_DEVICE_DISABLED;
>>  	} else {
>> -		aux_entry->mode = THERMAL_DEVICE_ENABLED;
>> +		tzd->mode = THERMAL_DEVICE_ENABLED;
>>  		pr_info("DTS is locked. Cannot disable DTS\n");
>>  		ret = -EPERM;
>>  	}
>> @@ -309,14 +308,6 @@ static int sys_get_curr_temp(struct thermal_zone_device *tzd,
>>  	return 0;
>>  }
>>  
>> -static int sys_get_mode(struct thermal_zone_device *tzd,
>> -				enum thermal_device_mode *mode)
>> -{
>> -	struct soc_sensor_entry *aux_entry = tzd->devdata;
>> -	*mode = aux_entry->mode;
>> -	return 0;
>> -}
>> -
>>  static int sys_set_mode(struct thermal_zone_device *tzd,
>>  				enum thermal_device_mode mode)
>>  {
>> @@ -338,7 +329,6 @@ static struct thermal_zone_device_ops tzone_ops = {
>>  	.get_trip_type = sys_get_trip_type,
>>  	.set_trip_temp = sys_set_trip_temp,
>>  	.get_crit_temp = sys_get_crit_temp,
>> -	.get_mode = sys_get_mode,
>>  	.set_mode = sys_set_mode,
>>  };
>>  
>> diff --git a/drivers/thermal/of-thermal.c b/drivers/thermal/of-thermal.c
>> index 874a47d6923f..863b89546f81 100644
>> --- a/drivers/thermal/of-thermal.c
>> +++ b/drivers/thermal/of-thermal.c
>> @@ -51,7 +51,6 @@ struct __thermal_bind_params {
>>  
>>  /**
>>   * struct __thermal_zone - internal representation of a thermal zone
>> - * @mode: current thermal zone device mode (enabled/disabled)
>>   * @passive_delay: polling interval while passive cooling is activated
>>   * @polling_delay: zone polling interval
>>   * @slope: slope of the temperature adjustment curve
>> @@ -65,7 +64,6 @@ struct __thermal_bind_params {
>>   */
>>  
>>  struct __thermal_zone {
>> -	enum thermal_device_mode mode;
>>  	int passive_delay;
>>  	int polling_delay;
>>  	int slope;
>> @@ -269,23 +267,11 @@ static int of_thermal_unbind(struct thermal_zone_device *thermal,
>>  	return 0;
>>  }
>>  
>> -static int of_thermal_get_mode(struct thermal_zone_device *tz,
>> -			       enum thermal_device_mode *mode)
>> -{
>> -	struct __thermal_zone *data = tz->devdata;
>> -
>> -	*mode = data->mode;
>> -
>> -	return 0;
>> -}
>> -
>>  static int of_thermal_set_mode(struct thermal_zone_device *tz,
>>  			       enum thermal_device_mode mode)
>>  {
>>  	struct __thermal_zone *data = tz->devdata;
>>  
>> -	mutex_lock(&tz->lock);
>> -
>>  	if (mode == THERMAL_DEVICE_ENABLED) {
>>  		tz->polling_delay = data->polling_delay;
>>  		tz->passive_delay = data->passive_delay;
>> @@ -294,11 +280,6 @@ static int of_thermal_set_mode(struct thermal_zone_device *tz,
>>  		tz->passive_delay = 0;
>>  	}
>>  
>> -	mutex_unlock(&tz->lock);
>> -
>> -	data->mode = mode;
>> -	thermal_zone_device_update(tz, THERMAL_EVENT_UNSPECIFIED);
>> -
>>  	return 0;
>>  }
>>  
>> @@ -393,7 +374,6 @@ static int of_thermal_get_crit_temp(struct thermal_zone_device *tz,
>>  }
>>  
>>  static struct thermal_zone_device_ops of_thermal_ops = {
>> -	.get_mode = of_thermal_get_mode,
>>  	.set_mode = of_thermal_set_mode,
>>  
>>  	.get_trip_type = of_thermal_get_trip_type,
>> @@ -553,8 +533,14 @@ thermal_zone_of_sensor_register(struct device *dev, int sensor_id, void *data,
>>  		if (id == sensor_id) {
>>  			tzd = thermal_zone_of_add_sensor(child, sensor_np,
>>  							 data, ops);
>> -			if (!IS_ERR(tzd))
>> +			if (!IS_ERR(tzd)) {
>> +				mutex_lock(&tzd->lock);
>>  				tzd->ops->set_mode(tzd, THERMAL_DEVICE_ENABLED);
>> +				tzd->mode = THERMAL_DEVICE_ENABLED;
>> +				mutex_unlock(&tzd->lock);
>> +				thermal_zone_device_update(tzd,
>> +						THERMAL_EVENT_UNSPECIFIED);
>> +			}
> 
> This should use thermal_zone_device_enable() instead of open-coding it:
> 
> 			if (!IS_ERR(tzd))
> 				thermal_zone_device_enable(tzd);
> 
> Also because of of_thermal_set_mode() modifications following of/thermal
> device drivers (which use ->set_mode directly):
> 
> drivers/thermal/hisi_thermal.c: tzd->ops->set_mode(tzd,
> drivers/thermal/rockchip_thermal.c:     tzd->ops->set_mode(tzd,
> drivers/thermal/sprd_thermal.c: tzd->ops->set_mode(tzd,
> 
> need to be converted to use thermal_zone_device_{en,dis}able() instead.
> 
>>  			of_node_put(child);
>>  			goto exit;
>> @@ -979,7 +965,6 @@ __init *thermal_of_build_thermal_zone(struct device_node *np)
>>  
>>  finish:
>>  	of_node_put(child);
>> -	tz->mode = THERMAL_DEVICE_DISABLED;
>>  
>>  	return tz;
>>  
>> @@ -1120,6 +1105,7 @@ int __init of_parse_thermal_zones(void)
>>  		/* these two are left for temperature drivers to use */
>>  		tzp->slope = tz->slope;
>>  		tzp->offset = tz->offset;
>> +		tzp->initial_mode = THERMAL_DEVICE_DISABLED;
>>  
>>  		zone = thermal_zone_device_register(child->name, tz->ntrips,
>>  						    mask, tz,
>> diff --git a/drivers/thermal/thermal_core.c b/drivers/thermal/thermal_core.c
>> index c06550930979..5ff98fcc0f6a 100644
>> --- a/drivers/thermal/thermal_core.c
>> +++ b/drivers/thermal/thermal_core.c
>> @@ -463,6 +463,43 @@ static void thermal_zone_device_reset(struct thermal_zone_device *tz)
>>  	thermal_zone_device_init(tz);
>>  }
>>  
>> +enum thermal_device_mode
>> +thermal_zone_device_get_mode(struct thermal_zone_device *tz)
>> +{
>> +	enum thermal_device_mode mode;
>> +
>> +	mutex_lock(&tz->lock);
>> +
>> +	mode = tz->mode;
>> +
>> +	mutex_unlock(&tz->lock);
>> +
>> +	return mode;
>> +}
>> +
>> +int thermal_zone_device_set_mode(struct thermal_zone_device *tz,
>> +				 enum thermal_device_mode mode)
>> +{
>> +	int ret = 0;
>> +
>> +	if (mode != THERMAL_DEVICE_DISABLED &&
>> +	    mode != THERMAL_DEVICE_ENABLED)
>> +		return -EINVAL;
> 
> No need for these checks as enum thermal_device_mode has only two
> possible values (we don't do "defensive coding" in the kernel).
> 
>> +	mutex_lock(&tz->lock);
>> +
>> +	if (tz->ops->set_mode)
>> +		ret = tz->ops->set_mode(tz, mode);
>> +
>> +	tz->mode = mode;
>> +
>> +	mutex_unlock(&tz->lock);
>> +
>> +	thermal_zone_device_update(tz, THERMAL_EVENT_UNSPECIFIED);
>> +
>> +	return ret;
>> +}
> 
> Please add:
> 
> EXPORT_SYMBOL_GPL(thermal_zone_device_set_mode);
> 
> here so device drivers can use thermal_zone_device_{en,dis}able().
> 
>>  void thermal_zone_device_update(struct thermal_zone_device *tz,
>>  				enum thermal_notify_event event)
>>  {
>> @@ -1344,6 +1381,9 @@ thermal_zone_device_register(const char *type, int trips, int mask,
>>  	if (atomic_cmpxchg(&tz->need_update, 1, 0))
>>  		thermal_zone_device_update(tz, THERMAL_EVENT_UNSPECIFIED);
>>  
>> +	if (tzp)
>> +		thermal_zone_device_set_mode(tz, tzp->initial_mode);
> 
> Please note that currently some device drivers don't access ->mode
> at all so their default ->mode value is THERMAL_DEVICE_DISABLED but
> in reality they are enabled (IOW after changes in this patch they
> should default to THERMAL_DEVICE_ENABLED to reflect real device state
> in "mode" sysfs attribue and not break after applying patch #2).
> 
> Therefore we should always call thermal_zone_device_set_mode() and
> use the default value of THERMAL_DEVICE_ENABLED if tzp is NULL:
> 
> 	mode = tzp ? tzp->initial_mode : THERMAL_DEVICE_ENABLED;
> 	thermal_zone_device_set_mode(tz, mode);
> 
> This would also simplify the patch further:
> 
> * setting tz->need_update and calling thermal_zone_device_update()
>   directly can be removed from thermal_zone_device_register()
> 
> * tzp-s with only .initial_mode = THERMAL_DEVICE_ENABLED set can
>   be removed from:
> 
>   drivers/thermal/acpi.c
>   drivers/net/ethernet/mellanox/mlxsw/core_thermal.c
>   drivers/thermal/da9062-thermal.c
>   drivers/thermal/imx_thermal.c
> 
> The rest of the patch looks fine, thank you for working on this!

Oops, one more thing, I've audited all existing users of
thermal_zone_device_register() with non-NULL tzp argument:

* following drivers should be updated to set .initial_mode to
  THERMAL_DEVICE_ENABLED in their tzp instance (no ->set_mode
  method and ->mode not set currently during initialization):

  drivers/thermal/intel/int340x_thermal/int340x_thermal_zone.c
  drivers/thermal/intel/x86_pkg_temp_thermal.c

* following driver may be updated to explicitly set .initial_mode
  to THERMAL_DEVICE_DISABLED in its tzp instance (has ->set_mode
  method but ->mode not set currently during initialization):

  drivers/thermal/intel/int340x_thermal/int3400_thermal.c

  (THERMAL_DEVICE_DISABLED == 0 is the default currently but
   lets document the behavior and prepare driver for potentially
   changing the default into more sane THERMAL_DEVICE_ENABLED in
   the future)

Best regards,
--
Bartlomiej Zolnierkiewicz
Samsung R&D Institute Poland
Samsung Electronics

> Best regards,
> --
> Bartlomiej Zolnierkiewicz
> Samsung R&D Institute Poland
> Samsung Electronics
> 
>> +
>>  	return tz;
>>  
>>  unregister:
>> @@ -1473,9 +1513,7 @@ static int thermal_pm_notify(struct notifier_block *nb,
>>  	case PM_POST_SUSPEND:
>>  		atomic_set(&in_suspend, 0);
>>  		list_for_each_entry(tz, &thermal_tz_list, node) {
>> -			tz_mode = THERMAL_DEVICE_ENABLED;
>> -			if (tz->ops->get_mode)
>> -				tz->ops->get_mode(tz, &tz_mode);
>> +			tz_mode = thermal_zone_device_get_mode(tz);
>>  
>>  			if (tz_mode == THERMAL_DEVICE_DISABLED)
>>  				continue;
>> diff --git a/drivers/thermal/thermal_core.h b/drivers/thermal/thermal_core.h
>> index c95689586e19..8e561bac3133 100644
>> --- a/drivers/thermal/thermal_core.h
>> +++ b/drivers/thermal/thermal_core.h
>> @@ -141,6 +141,22 @@ thermal_cooling_device_stats_update(struct thermal_cooling_device *cdev,
>>  				    unsigned long new_state) {}
>>  #endif /* CONFIG_THERMAL_STATISTICS */
>>  
>> +enum thermal_device_mode
>> +thermal_zone_device_get_mode(struct thermal_zone_device *tz);
>> +
>> +int thermal_zone_device_set_mode(struct thermal_zone_device *tz,
>> +				 enum thermal_device_mode mode);
>> +
>> +static inline int thermal_zone_device_enable(struct thermal_zone_device *tz)
>> +{
>> +	return thermal_zone_device_set_mode(tz, THERMAL_DEVICE_ENABLED);
>> +}
>> +
>> +static inline int thermal_zone_device_disable(struct thermal_zone_device *tz)
>> +{
>> +	return thermal_zone_device_set_mode(tz, THERMAL_DEVICE_DISABLED);
>> +}
>> +
>>  /* device tree support */
>>  #ifdef CONFIG_THERMAL_OF
>>  int of_parse_thermal_zones(void);
>> diff --git a/drivers/thermal/thermal_sysfs.c b/drivers/thermal/thermal_sysfs.c
>> index aa99edb4dff7..cbb27b3c96d2 100644
>> --- a/drivers/thermal/thermal_sysfs.c
>> +++ b/drivers/thermal/thermal_sysfs.c
>> @@ -50,14 +50,8 @@ mode_show(struct device *dev, struct device_attribute *attr, char *buf)
>>  {
>>  	struct thermal_zone_device *tz = to_thermal_zone(dev);
>>  	enum thermal_device_mode mode;
>> -	int result;
>> -
>> -	if (!tz->ops->get_mode)
>> -		return -EPERM;
>>  
>> -	result = tz->ops->get_mode(tz, &mode);
>> -	if (result)
>> -		return result;
>> +	mode = thermal_zone_device_get_mode(tz);
>>  
>>  	return sprintf(buf, "%s\n", mode == THERMAL_DEVICE_ENABLED ? "enabled"
>>  		       : "disabled");
>> @@ -74,9 +68,9 @@ mode_store(struct device *dev, struct device_attribute *attr,
>>  		return -EPERM;
>>  
>>  	if (!strncmp(buf, "enabled", sizeof("enabled") - 1))
>> -		result = tz->ops->set_mode(tz, THERMAL_DEVICE_ENABLED);
>> +		result = thermal_zone_device_enable(tz);
>>  	else if (!strncmp(buf, "disabled", sizeof("disabled") - 1))
>> -		result = tz->ops->set_mode(tz, THERMAL_DEVICE_DISABLED);
>> +		result = thermal_zone_device_disable(tz);
>>  	else
>>  		result = -EINVAL;
>>  
>> @@ -428,30 +422,13 @@ static struct attribute_group thermal_zone_attribute_group = {
>>  	.attrs = thermal_zone_dev_attrs,
>>  };
>>  
>> -/* We expose mode only if .get_mode is present */
>>  static struct attribute *thermal_zone_mode_attrs[] = {
>>  	&dev_attr_mode.attr,
>>  	NULL,
>>  };
>>  
>> -static umode_t thermal_zone_mode_is_visible(struct kobject *kobj,
>> -					    struct attribute *attr,
>> -					    int attrno)
>> -{
>> -	struct device *dev = container_of(kobj, struct device, kobj);
>> -	struct thermal_zone_device *tz;
>> -
>> -	tz = container_of(dev, struct thermal_zone_device, device);
>> -
>> -	if (tz->ops->get_mode)
>> -		return attr->mode;
>> -
>> -	return 0;
>> -}
>> -
>>  static struct attribute_group thermal_zone_mode_attribute_group = {
>>  	.attrs = thermal_zone_mode_attrs,
>> -	.is_visible = thermal_zone_mode_is_visible,
>>  };
>>  
>>  /* We expose passive only if passive trips are present */
>> diff --git a/include/linux/thermal.h b/include/linux/thermal.h
>> index 216185bb3014..da4141697e2e 100644
>> --- a/include/linux/thermal.h
>> +++ b/include/linux/thermal.h
>> @@ -76,8 +76,6 @@ struct thermal_zone_device_ops {
>>  		       struct thermal_cooling_device *);
>>  	int (*get_temp) (struct thermal_zone_device *, int *);
>>  	int (*set_trips) (struct thermal_zone_device *, int, int);
>> -	int (*get_mode) (struct thermal_zone_device *,
>> -			 enum thermal_device_mode *);
>>  	int (*set_mode) (struct thermal_zone_device *,
>>  		enum thermal_device_mode);
>>  	int (*get_trip_type) (struct thermal_zone_device *, int,
>> @@ -128,6 +126,7 @@ struct thermal_cooling_device {
>>   * @trip_temp_attrs:	attributes for trip points for sysfs: trip temperature
>>   * @trip_type_attrs:	attributes for trip points for sysfs: trip type
>>   * @trip_hyst_attrs:	attributes for trip points for sysfs: trip hysteresis
>> + * @mode:		current mode of this thermal zone
>>   * @devdata:	private pointer for device private data
>>   * @trips:	number of trip points the thermal zone supports
>>   * @trips_disabled;	bitmap for disabled trips
>> @@ -170,6 +169,7 @@ struct thermal_zone_device {
>>  	struct thermal_attr *trip_temp_attrs;
>>  	struct thermal_attr *trip_type_attrs;
>>  	struct thermal_attr *trip_hyst_attrs;
>> +	enum thermal_device_mode mode;
>>  	void *devdata;
>>  	int trips;
>>  	unsigned long trips_disabled;	/* bitmap for disabled trips */
>> @@ -264,6 +264,9 @@ struct thermal_zone_params {
>>  	int num_tbps;	/* Number of tbp entries */
>>  	struct thermal_bind_params *tbp;
>>  
>> +	/* Initial mode of this thermal zone device */
>> +	enum thermal_device_mode initial_mode;
>> +
>>  	/*
>>  	 * Sustainable power (heat) that this thermal zone can dissipate in
>>  	 * mW
>>


^ permalink raw reply	[flat|nested] 63+ messages in thread

* Re: [RFC v3 1/2] thermal: core: Let thermal zone device's mode be stored in its struct
  2020-04-17 16:20         ` [RFC v3 0/2] Stop monitoring disabled devices Andrzej Pietrasiewicz
  2020-04-17 16:20           ` [RFC v3 1/2] thermal: core: Let thermal zone device's mode be stored in its struct Andrzej Pietrasiewicz
  2020-04-17 16:20           ` [RFC v3 2/2] thermal: core: Stop polling DISABLED thermal devices Andrzej Pietrasiewicz
@ 2020-04-19 13:50           ` Peter Kästle
  2 siblings, 0 replies; 63+ messages in thread
From: Peter Kästle @ 2020-04-19 13:50 UTC (permalink / raw)
  To: Andrzej Pietrasiewicz, linux-pm
  Cc: Zhang Rui, Rafael J . Wysocki, Len Brown, Jiri Pirko,
	Ido Schimmel, David S . Miller, Darren Hart, Andy Shevchenko,
	Support Opensource, Daniel Lezcano, Amit Kucheria, Shawn Guo,
	Sascha Hauer, Pengutronix Kernel Team, Fabio Estevam,
	NXP Linux Team, Allison Randal, Enrico Weigelt, Gayatri Kammela,
	Thomas Gleixner, linux-acpi, netdev, platform-driver-x86,
	linux-arm-kernel, kernel, Barlomiej Zolnierkiewicz

17. April 2020 18:20, "Andrzej Pietrasiewicz" <andrzej.p@collabora.com> schrieb:

> Thermal zone devices' mode is stored in individual drivers. This patch
> changes it so that mode is stored in struct thermal_zone_device instead.
> 
> As a result all driver-specific variables storing the mode are not needed
> and are removed. Consequently, the get_mode() implementations have nothing
> to operate on and need to be removed, too.
> 
> Some thermal framework specific functions are introduced:
> 
> thermal_zone_device_get_mode()
> thermal_zone_device_set_mode()
> thermal_zone_device_enable()
> thermal_zone_device_disable()
> 
> thermal_zone_device_get_mode() and its "set" counterpart take tzd's lock
> and the "set" calls driver's set_mode() if provided, so the latter must
> not take this lock again. At the end of the "set"
> thermal_zone_device_update() is called so drivers don't need to repeat this
> invocation in their specific set_mode() implementations.
> 
> The scope of the above 4 functions is purposedly limited to the thermal
> framework and drivers are not supposed to call them. This encapsulation
> does not fully work at the moment for some drivers, though:
> 
> - platform/x86/acerhdf.c

Acked-by: Peter Kaestle <peter@piie.net>

[...]

-- 
--peter;

^ permalink raw reply	[flat|nested] 63+ messages in thread

* Re: [RFC v3 1/2] thermal: core: Let thermal zone device's mode be stored in its struct
  2020-04-19 11:38             ` Bartlomiej Zolnierkiewicz
  2020-04-19 13:10               ` Bartlomiej Zolnierkiewicz
@ 2020-04-20 11:03               ` Andrzej Pietrasiewicz
  2020-04-20 18:19                 ` Andrzej Pietrasiewicz
  1 sibling, 1 reply; 63+ messages in thread
From: Andrzej Pietrasiewicz @ 2020-04-20 11:03 UTC (permalink / raw)
  To: Bartlomiej Zolnierkiewicz
  Cc: linux-pm, Zhang Rui, Rafael J . Wysocki, Len Brown, Jiri Pirko,
	Ido Schimmel, David S . Miller, Peter Kaestle, Darren Hart,
	Andy Shevchenko, Support Opensource, Daniel Lezcano,
	Amit Kucheria, Shawn Guo, Sascha Hauer, Pengutronix Kernel Team,
	Fabio Estevam, NXP Linux Team, Allison Randal, Enrico Weigelt,
	Gayatri Kammela, Thomas Gleixner, linux-acpi, netdev,
	platform-driver-x86, linux-arm-kernel, kernel

Hi Barlomiej,

Thanks for looking into the series.

@Daniel can you see below?

W dniu 19.04.2020 o 13:38, Bartlomiej Zolnierkiewicz pisze:
> 
> Hi Andrzej,
> 
> On 4/17/20 6:20 PM, Andrzej Pietrasiewicz wrote:
>> Thermal zone devices' mode is stored in individual drivers. This patch
>> changes it so that mode is stored in struct thermal_zone_device instead.
>>
>> As a result all driver-specific variables storing the mode are not needed
>> and are removed. Consequently, the get_mode() implementations have nothing
>> to operate on and need to be removed, too.
>>
>> Some thermal framework specific functions are introduced:
>>
>> thermal_zone_device_get_mode()
>> thermal_zone_device_set_mode()
>> thermal_zone_device_enable()
>> thermal_zone_device_disable()
>>
>> thermal_zone_device_get_mode() and its "set" counterpart take tzd's lock
>> and the "set" calls driver's set_mode() if provided, so the latter must
>> not take this lock again. At the end of the "set"
>> thermal_zone_device_update() is called so drivers don't need to repeat this
>> invocation in their specific set_mode() implementations.
>>
>> The scope of the above 4 functions is purposedly limited to the thermal
>> framework and drivers are not supposed to call them. This encapsulation
> 
> This should be true only for thermal_zone_device_{get,set}_mode().
> 
> thermal_zone_device_{en,dis}able() should be available for device drivers:
> 
> * of/thermal device drivers need to enable thermal device itself
>    (please refer to my patchset for details)
> 
> * device drivers need to call them on ->suspend and ->resume operations
> 

@Daniel:

How does this compare to

"Just:

thermal_zone_device_get_mode()
thermal_zone_device_set_mode()
thermal_zone_device_disable()
thermal_zone_device_enable()

And all of them in drivers/thermal/thermal_core.h". Did I understand
you correctly?

Andrzej

^ permalink raw reply	[flat|nested] 63+ messages in thread

* [PATCH 0/2] Stop monitoring disabled devices
  2020-04-19 13:10               ` Bartlomiej Zolnierkiewicz
@ 2020-04-20 18:17                 ` Andrzej Pietrasiewicz
  2020-04-20 18:17                   ` [PATCH 1/2] thermal: core: Let thermal zone device's mode be stored in its struct Andrzej Pietrasiewicz
                                     ` (2 more replies)
  0 siblings, 3 replies; 63+ messages in thread
From: Andrzej Pietrasiewicz @ 2020-04-20 18:17 UTC (permalink / raw)
  To: linux-pm
  Cc: Zhang Rui, Rafael J . Wysocki, Len Brown, Jiri Pirko,
	Ido Schimmel, David S . Miller, Peter Kaestle, Darren Hart,
	Andy Shevchenko, Support Opensource, Daniel Lezcano,
	Amit Kucheria, Shawn Guo, Sascha Hauer, Pengutronix Kernel Team,
	Fabio Estevam, NXP Linux Team, Heiko Stuebner, Orson Zhai,
	Baolin Wang, Chunyan Zhang, linux-acpi, netdev,
	platform-driver-x86, linux-arm-kernel, kernel,
	Andrzej Pietrasiewicz, Barlomiej Zolnierkiewicz

After 3 revisions of an RFC I'm sending this as a PATCH series.

The first patch makes all the drivers store their mode in struct
thermal_zone_device. Such a move has consequences: driver-specific
variables for storing mode are not necessary. Consequently get_mode()
methods become obsolete. Then sysfs "mode" attribute stops depending
on get_mode() being provided, because it is always provided from now on.

The first patch also introduces the initial mode to be optionally passed
to thermal_zone_device_register().

Given all the groundwork done in patch 1/2 patch 2/2 becomes very simple.

Compared to RFC v3 this series addresses comments from Bartlomiej,
thank you Bartlomiej for your review!

RFCv3..this PATCH:

- export thermal_zone_device_{enable|disable}() for drivers
- don't check provided enum values in acpi's thermal_zet_mode()
and in int3400_thermal_set_mode()
- use thermal_zone_device_enable() in of_thermal instead of open coding it
- use thermal_zone_device_{enable|disable}() in hisi_thermal, rockchip_thermal
and sprd_thermal
- assume THERMAL_DEVICE_ENABLED is thermal_zone_params not provided at
tzd's register time
- eliminated tzp-s which contain only .initial_mode = THERMAL_DEVICE_ENABLED,
- don't set tz->need_update and don't call thermal_zone_device_update()
at the end of thermal_zone_device_register()
- used .initial_mode in int340x_thermal_zone, x86_pkg_temp_thermal and
int3400_thermal

Andrzej Pietrasiewicz (2):
  thermal: core: Let thermal zone device's mode be stored in its struct
  thermal: core: Stop polling DISABLED thermal devices

 drivers/acpi/thermal.c                        | 35 ++--------
 .../ethernet/mellanox/mlxsw/core_thermal.c    | 42 ------------
 drivers/platform/x86/acerhdf.c                | 17 +----
 drivers/thermal/da9062-thermal.c              | 11 ----
 drivers/thermal/hisi_thermal.c                |  6 +-
 drivers/thermal/imx_thermal.c                 | 24 ++-----
 .../intel/int340x_thermal/int3400_thermal.c   | 31 ++-------
 .../int340x_thermal/int340x_thermal_zone.c    |  1 +
 .../thermal/intel/intel_quark_dts_thermal.c   | 22 ++-----
 drivers/thermal/intel/x86_pkg_temp_thermal.c  |  1 +
 drivers/thermal/of-thermal.c                  | 24 +------
 drivers/thermal/rockchip_thermal.c            |  6 +-
 drivers/thermal/sprd_thermal.c                |  6 +-
 drivers/thermal/thermal_core.c                | 65 ++++++++++++++++---
 drivers/thermal/thermal_core.h                |  3 +
 drivers/thermal/thermal_sysfs.c               | 29 +--------
 include/linux/thermal.h                       | 22 ++++++-
 17 files changed, 121 insertions(+), 224 deletions(-)


base-commit: 79799562bf087b30d9dd0fddf5bed2d3b038be08
-- 
2.17.1


^ permalink raw reply	[flat|nested] 63+ messages in thread

* [PATCH 1/2] thermal: core: Let thermal zone device's mode be stored in its struct
  2020-04-20 18:17                 ` [PATCH 0/2] Stop monitoring disabled devices Andrzej Pietrasiewicz
@ 2020-04-20 18:17                   ` Andrzej Pietrasiewicz
  2020-04-22  7:49                     ` kbuild test robot
  2020-04-22 17:03                     ` kbuild test robot
  2020-04-20 18:17                   ` [PATCH 2/2] thermal: core: Stop polling DISABLED thermal devices Andrzej Pietrasiewicz
  2020-04-22 16:12                   ` [PATCH RESEND 1/2] thermal: core: Let thermal zone device's mode be stored in its struct Andrzej Pietrasiewicz
  2 siblings, 2 replies; 63+ messages in thread
From: Andrzej Pietrasiewicz @ 2020-04-20 18:17 UTC (permalink / raw)
  To: linux-pm
  Cc: Zhang Rui, Rafael J . Wysocki, Len Brown, Jiri Pirko,
	Ido Schimmel, David S . Miller, Peter Kaestle, Darren Hart,
	Andy Shevchenko, Support Opensource, Daniel Lezcano,
	Amit Kucheria, Shawn Guo, Sascha Hauer, Pengutronix Kernel Team,
	Fabio Estevam, NXP Linux Team, Heiko Stuebner, Orson Zhai,
	Baolin Wang, Chunyan Zhang, linux-acpi, netdev,
	platform-driver-x86, linux-arm-kernel, kernel,
	Andrzej Pietrasiewicz, Barlomiej Zolnierkiewicz

Thermal zone devices' mode is stored in individual drivers. This patch
changes it so that mode is stored in struct thermal_zone_device instead.

As a result all driver-specific variables storing the mode are not needed
and are removed. Consequently, the get_mode() implementations have nothing
to operate on and need to be removed, too.

Some thermal framework functions are introduced:

thermal_zone_device_get_mode()
thermal_zone_device_set_mode()
thermal_zone_device_enable()
thermal_zone_device_disable()

thermal_zone_device_get_mode() and its "set" counterpart take tzd's lock
and the "set" calls driver's set_mode() if provided, so the latter must
not take this lock again. At the end of the "set"
thermal_zone_device_update() is called so drivers don't need to repeat this
invocation in their specific set_mode() implementations.

struct thermal_zone_params gains a new member called initial_mode, which
is used to set tzd's mode at registration time and if tzp is not provided
to thermal_zone_device_register() then it is assumed that the initial
mode is THERMAL_DEVICE_ENABLED.

The sysfs "mode" attribute is always exposed from now on, because all
thermal zone devices now have their get_mode() implemented at the generic
level and it is always available. Exposing "mode" doesn't hurt the drivers
which don't provide their own set_mode(), because writing to "mode" will
result in -EPERM, as expected.

Signed-off-by: Andrzej Pietrasiewicz <andrzej.p@collabora.com>
---
 drivers/acpi/thermal.c                        | 35 ++-----------
 .../ethernet/mellanox/mlxsw/core_thermal.c    | 42 ----------------
 drivers/platform/x86/acerhdf.c                | 17 ++-----
 drivers/thermal/da9062-thermal.c              | 11 -----
 drivers/thermal/hisi_thermal.c                |  6 ++-
 drivers/thermal/imx_thermal.c                 | 24 ++-------
 .../intel/int340x_thermal/int3400_thermal.c   | 31 ++----------
 .../int340x_thermal/int340x_thermal_zone.c    |  1 +
 .../thermal/intel/intel_quark_dts_thermal.c   | 22 +++------
 drivers/thermal/intel/x86_pkg_temp_thermal.c  |  1 +
 drivers/thermal/of-thermal.c                  | 24 +--------
 drivers/thermal/rockchip_thermal.c            |  6 ++-
 drivers/thermal/sprd_thermal.c                |  6 ++-
 drivers/thermal/thermal_core.c                | 49 ++++++++++++++++---
 drivers/thermal/thermal_core.h                |  3 ++
 drivers/thermal/thermal_sysfs.c               | 29 ++---------
 include/linux/thermal.h                       | 22 ++++++++-
 17 files changed, 107 insertions(+), 222 deletions(-)

diff --git a/drivers/acpi/thermal.c b/drivers/acpi/thermal.c
index 19067a5e5293..d1f352ed5241 100644
--- a/drivers/acpi/thermal.c
+++ b/drivers/acpi/thermal.c
@@ -172,7 +172,6 @@ struct acpi_thermal {
 	struct acpi_thermal_trips trips;
 	struct acpi_handle_list devices;
 	struct thermal_zone_device *thermal_zone;
-	int tz_enabled;
 	int kelvin_offset;	/* in millidegrees */
 	struct work_struct thermal_check_work;
 };
@@ -500,7 +499,7 @@ static void acpi_thermal_check(void *data)
 {
 	struct acpi_thermal *tz = data;
 
-	if (!tz->tz_enabled)
+	if (tz->thermal_zone->mode != THERMAL_DEVICE_ENABLED)
 		return;
 
 	thermal_zone_device_update(tz->thermal_zone,
@@ -526,25 +525,10 @@ static int thermal_get_temp(struct thermal_zone_device *thermal, int *temp)
 	return 0;
 }
 
-static int thermal_get_mode(struct thermal_zone_device *thermal,
-				enum thermal_device_mode *mode)
-{
-	struct acpi_thermal *tz = thermal->devdata;
-
-	if (!tz)
-		return -EINVAL;
-
-	*mode = tz->tz_enabled ? THERMAL_DEVICE_ENABLED :
-		THERMAL_DEVICE_DISABLED;
-
-	return 0;
-}
-
 static int thermal_set_mode(struct thermal_zone_device *thermal,
 				enum thermal_device_mode mode)
 {
 	struct acpi_thermal *tz = thermal->devdata;
-	int enable;
 
 	if (!tz)
 		return -EINVAL;
@@ -552,20 +536,14 @@ static int thermal_set_mode(struct thermal_zone_device *thermal,
 	/*
 	 * enable/disable thermal management from ACPI thermal driver
 	 */
-	if (mode == THERMAL_DEVICE_ENABLED)
-		enable = 1;
-	else if (mode == THERMAL_DEVICE_DISABLED) {
-		enable = 0;
+	if (mode == THERMAL_DEVICE_DISABLED)
 		pr_warn("thermal zone will be disabled\n");
-	} else
-		return -EINVAL;
 
-	if (enable != tz->tz_enabled) {
-		tz->tz_enabled = enable;
+	if (mode != thermal->mode) {
 		ACPI_DEBUG_PRINT((ACPI_DB_INFO,
 			"%s kernel ACPI thermal control\n",
-			tz->tz_enabled ? "Enable" : "Disable"));
-		acpi_thermal_check(tz);
+			mode == THERMAL_DEVICE_ENABLED ?
+			"Enable" : "Disable"));
 	}
 	return 0;
 }
@@ -856,7 +834,6 @@ static struct thermal_zone_device_ops acpi_thermal_zone_ops = {
 	.bind = acpi_thermal_bind_cooling_device,
 	.unbind	= acpi_thermal_unbind_cooling_device,
 	.get_temp = thermal_get_temp,
-	.get_mode = thermal_get_mode,
 	.set_mode = thermal_set_mode,
 	.get_trip_type = thermal_get_trip_type,
 	.get_trip_temp = thermal_get_trip_temp,
@@ -913,8 +890,6 @@ static int acpi_thermal_register_thermal_zone(struct acpi_thermal *tz)
 	if (ACPI_FAILURE(status))
 		return -ENODEV;
 
-	tz->tz_enabled = 1;
-
 	dev_info(&tz->device->dev, "registered as thermal_zone%d\n",
 		 tz->thermal_zone->id);
 	return 0;
diff --git a/drivers/net/ethernet/mellanox/mlxsw/core_thermal.c b/drivers/net/ethernet/mellanox/mlxsw/core_thermal.c
index ce0a6837daa3..5d28384046da 100644
--- a/drivers/net/ethernet/mellanox/mlxsw/core_thermal.c
+++ b/drivers/net/ethernet/mellanox/mlxsw/core_thermal.c
@@ -98,7 +98,6 @@ struct mlxsw_thermal_module {
 	struct mlxsw_thermal *parent;
 	struct thermal_zone_device *tzdev;
 	struct mlxsw_thermal_trip trips[MLXSW_THERMAL_NUM_TRIPS];
-	enum thermal_device_mode mode;
 	int module; /* Module or gearbox number */
 };
 
@@ -110,7 +109,6 @@ struct mlxsw_thermal {
 	struct thermal_cooling_device *cdevs[MLXSW_MFCR_PWMS_MAX];
 	u8 cooling_levels[MLXSW_THERMAL_MAX_STATE + 1];
 	struct mlxsw_thermal_trip trips[MLXSW_THERMAL_NUM_TRIPS];
-	enum thermal_device_mode mode;
 	struct mlxsw_thermal_module *tz_module_arr;
 	u8 tz_module_num;
 	struct mlxsw_thermal_module *tz_gearbox_arr;
@@ -277,33 +275,16 @@ static int mlxsw_thermal_unbind(struct thermal_zone_device *tzdev,
 	return 0;
 }
 
-static int mlxsw_thermal_get_mode(struct thermal_zone_device *tzdev,
-				  enum thermal_device_mode *mode)
-{
-	struct mlxsw_thermal *thermal = tzdev->devdata;
-
-	*mode = thermal->mode;
-
-	return 0;
-}
-
 static int mlxsw_thermal_set_mode(struct thermal_zone_device *tzdev,
 				  enum thermal_device_mode mode)
 {
 	struct mlxsw_thermal *thermal = tzdev->devdata;
 
-	mutex_lock(&tzdev->lock);
-
 	if (mode == THERMAL_DEVICE_ENABLED)
 		tzdev->polling_delay = thermal->polling_delay;
 	else
 		tzdev->polling_delay = 0;
 
-	mutex_unlock(&tzdev->lock);
-
-	thermal->mode = mode;
-	thermal_zone_device_update(tzdev, THERMAL_EVENT_UNSPECIFIED);
-
 	return 0;
 }
 
@@ -407,7 +388,6 @@ static int mlxsw_thermal_trend_get(struct thermal_zone_device *tzdev,
 static struct thermal_zone_device_ops mlxsw_thermal_ops = {
 	.bind = mlxsw_thermal_bind,
 	.unbind = mlxsw_thermal_unbind,
-	.get_mode = mlxsw_thermal_get_mode,
 	.set_mode = mlxsw_thermal_set_mode,
 	.get_temp = mlxsw_thermal_get_temp,
 	.get_trip_type	= mlxsw_thermal_get_trip_type,
@@ -466,34 +446,17 @@ static int mlxsw_thermal_module_unbind(struct thermal_zone_device *tzdev,
 	return err;
 }
 
-static int mlxsw_thermal_module_mode_get(struct thermal_zone_device *tzdev,
-					 enum thermal_device_mode *mode)
-{
-	struct mlxsw_thermal_module *tz = tzdev->devdata;
-
-	*mode = tz->mode;
-
-	return 0;
-}
-
 static int mlxsw_thermal_module_mode_set(struct thermal_zone_device *tzdev,
 					 enum thermal_device_mode mode)
 {
 	struct mlxsw_thermal_module *tz = tzdev->devdata;
 	struct mlxsw_thermal *thermal = tz->parent;
 
-	mutex_lock(&tzdev->lock);
-
 	if (mode == THERMAL_DEVICE_ENABLED)
 		tzdev->polling_delay = thermal->polling_delay;
 	else
 		tzdev->polling_delay = 0;
 
-	mutex_unlock(&tzdev->lock);
-
-	tz->mode = mode;
-	thermal_zone_device_update(tzdev, THERMAL_EVENT_UNSPECIFIED);
-
 	return 0;
 }
 
@@ -596,7 +559,6 @@ mlxsw_thermal_module_trip_hyst_set(struct thermal_zone_device *tzdev, int trip,
 static struct thermal_zone_device_ops mlxsw_thermal_module_ops = {
 	.bind		= mlxsw_thermal_module_bind,
 	.unbind		= mlxsw_thermal_module_unbind,
-	.get_mode	= mlxsw_thermal_module_mode_get,
 	.set_mode	= mlxsw_thermal_module_mode_set,
 	.get_temp	= mlxsw_thermal_module_temp_get,
 	.get_trip_type	= mlxsw_thermal_module_trip_type_get,
@@ -635,7 +597,6 @@ static int mlxsw_thermal_gearbox_temp_get(struct thermal_zone_device *tzdev,
 static struct thermal_zone_device_ops mlxsw_thermal_gearbox_ops = {
 	.bind		= mlxsw_thermal_module_bind,
 	.unbind		= mlxsw_thermal_module_unbind,
-	.get_mode	= mlxsw_thermal_module_mode_get,
 	.set_mode	= mlxsw_thermal_module_mode_set,
 	.get_temp	= mlxsw_thermal_gearbox_temp_get,
 	.get_trip_type	= mlxsw_thermal_module_trip_type_get,
@@ -765,7 +726,6 @@ mlxsw_thermal_module_tz_init(struct mlxsw_thermal_module *module_tz)
 		return err;
 	}
 
-	module_tz->mode = THERMAL_DEVICE_ENABLED;
 	return 0;
 }
 
@@ -881,7 +841,6 @@ mlxsw_thermal_gearbox_tz_init(struct mlxsw_thermal_module *gearbox_tz)
 	if (IS_ERR(gearbox_tz->tzdev))
 		return PTR_ERR(gearbox_tz->tzdev);
 
-	gearbox_tz->mode = THERMAL_DEVICE_ENABLED;
 	return 0;
 }
 
@@ -1050,7 +1009,6 @@ int mlxsw_thermal_init(struct mlxsw_core *core,
 	if (err)
 		goto err_unreg_modules_tzdev;
 
-	thermal->mode = THERMAL_DEVICE_ENABLED;
 	*p_thermal = thermal;
 	return 0;
 
diff --git a/drivers/platform/x86/acerhdf.c b/drivers/platform/x86/acerhdf.c
index 8cc86f4e3ac1..aaf8b845be90 100644
--- a/drivers/platform/x86/acerhdf.c
+++ b/drivers/platform/x86/acerhdf.c
@@ -406,22 +406,9 @@ static inline void acerhdf_enable_kernelmode(void)
 	kernelmode = 1;
 
 	thz_dev->polling_delay = interval*1000;
-	thermal_zone_device_update(thz_dev, THERMAL_EVENT_UNSPECIFIED);
 	pr_notice("kernel mode fan control ON\n");
 }
 
-static int acerhdf_get_mode(struct thermal_zone_device *thermal,
-			    enum thermal_device_mode *mode)
-{
-	if (verbose)
-		pr_notice("kernel mode fan control %d\n", kernelmode);
-
-	*mode = (kernelmode) ? THERMAL_DEVICE_ENABLED
-			     : THERMAL_DEVICE_DISABLED;
-
-	return 0;
-}
-
 /*
  * set operation mode;
  * enabled: the thermal layer of the kernel takes care about
@@ -488,7 +475,6 @@ static struct thermal_zone_device_ops acerhdf_dev_ops = {
 	.bind = acerhdf_bind,
 	.unbind = acerhdf_unbind,
 	.get_temp = acerhdf_get_ec_temp,
-	.get_mode = acerhdf_get_mode,
 	.set_mode = acerhdf_set_mode,
 	.get_trip_type = acerhdf_get_trip_type,
 	.get_trip_hyst = acerhdf_get_trip_hyst,
@@ -554,6 +540,7 @@ static int acerhdf_set_cur_state(struct thermal_cooling_device *cdev,
 
 err_out:
 	acerhdf_revert_to_bios_mode();
+	thz_dev->mode = THERMAL_DEVICE_DISABLED;
 	return -EINVAL;
 }
 
@@ -739,6 +726,8 @@ static int __init acerhdf_register_thermal(void)
 	if (IS_ERR(cl_dev))
 		return -EINVAL;
 
+	acerhdf_zone_params.initial_mode =
+		kernelmode ? THERMAL_DEVICE_ENABLED : THERMAL_DEVICE_DISABLED;
 	thz_dev = thermal_zone_device_register("acerhdf", 2, 0, NULL,
 					      &acerhdf_dev_ops,
 					      &acerhdf_zone_params, 0,
diff --git a/drivers/thermal/da9062-thermal.c b/drivers/thermal/da9062-thermal.c
index c32709badeda..c3075d038095 100644
--- a/drivers/thermal/da9062-thermal.c
+++ b/drivers/thermal/da9062-thermal.c
@@ -49,7 +49,6 @@ struct da9062_thermal {
 	struct da9062 *hw;
 	struct delayed_work work;
 	struct thermal_zone_device *zone;
-	enum thermal_device_mode mode;
 	struct mutex lock; /* protection for da9062_thermal temperature */
 	int temperature;
 	int irq;
@@ -121,14 +120,6 @@ static irqreturn_t da9062_thermal_irq_handler(int irq, void *data)
 	return IRQ_HANDLED;
 }
 
-static int da9062_thermal_get_mode(struct thermal_zone_device *z,
-				   enum thermal_device_mode *mode)
-{
-	struct da9062_thermal *thermal = z->devdata;
-	*mode = thermal->mode;
-	return 0;
-}
-
 static int da9062_thermal_get_trip_type(struct thermal_zone_device *z,
 					int trip,
 					enum thermal_trip_type *type)
@@ -181,7 +172,6 @@ static int da9062_thermal_get_temp(struct thermal_zone_device *z,
 
 static struct thermal_zone_device_ops da9062_thermal_ops = {
 	.get_temp	= da9062_thermal_get_temp,
-	.get_mode	= da9062_thermal_get_mode,
 	.get_trip_type	= da9062_thermal_get_trip_type,
 	.get_trip_temp	= da9062_thermal_get_trip_temp,
 };
@@ -233,7 +223,6 @@ static int da9062_thermal_probe(struct platform_device *pdev)
 
 	thermal->config = match->data;
 	thermal->hw = chip;
-	thermal->mode = THERMAL_DEVICE_ENABLED;
 	thermal->dev = &pdev->dev;
 
 	INIT_DELAYED_WORK(&thermal->work, da9062_thermal_poll_on);
diff --git a/drivers/thermal/hisi_thermal.c b/drivers/thermal/hisi_thermal.c
index 2d26ae80e202..ee05950afd2f 100644
--- a/drivers/thermal/hisi_thermal.c
+++ b/drivers/thermal/hisi_thermal.c
@@ -549,8 +549,10 @@ static void hisi_thermal_toggle_sensor(struct hisi_thermal_sensor *sensor,
 {
 	struct thermal_zone_device *tzd = sensor->tzd;
 
-	tzd->ops->set_mode(tzd,
-		on ? THERMAL_DEVICE_ENABLED : THERMAL_DEVICE_DISABLED);
+	if (on)
+		thermal_zone_device_enable(tzd);
+	else
+		thermal_zone_device_disable(tzd);
 }
 
 static int hisi_thermal_probe(struct platform_device *pdev)
diff --git a/drivers/thermal/imx_thermal.c b/drivers/thermal/imx_thermal.c
index e761c9b42217..edbcb30815dc 100644
--- a/drivers/thermal/imx_thermal.c
+++ b/drivers/thermal/imx_thermal.c
@@ -197,7 +197,6 @@ struct imx_thermal_data {
 	struct cpufreq_policy *policy;
 	struct thermal_zone_device *tz;
 	struct thermal_cooling_device *cdev;
-	enum thermal_device_mode mode;
 	struct regmap *tempmon;
 	u32 c1, c2; /* See formula in imx_init_calib() */
 	int temp_passive;
@@ -256,7 +255,7 @@ static int imx_get_temp(struct thermal_zone_device *tz, int *temp)
 	bool wait;
 	u32 val;
 
-	if (data->mode == THERMAL_DEVICE_ENABLED) {
+	if (tz->mode == THERMAL_DEVICE_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 +282,7 @@ static int imx_get_temp(struct thermal_zone_device *tz, int *temp)
 
 	regmap_read(map, soc_data->temp_data, &val);
 
-	if (data->mode != THERMAL_DEVICE_ENABLED) {
+	if (tz->mode != THERMAL_DEVICE_ENABLED) {
 		regmap_write(map, soc_data->sensor_ctrl + REG_CLR,
 			     soc_data->measure_temp_mask);
 		regmap_write(map, soc_data->sensor_ctrl + REG_SET,
@@ -331,16 +330,6 @@ static int imx_get_temp(struct thermal_zone_device *tz, int *temp)
 	return 0;
 }
 
-static int imx_get_mode(struct thermal_zone_device *tz,
-			enum thermal_device_mode *mode)
-{
-	struct imx_thermal_data *data = tz->devdata;
-
-	*mode = data->mode;
-
-	return 0;
-}
-
 static int imx_set_mode(struct thermal_zone_device *tz,
 			enum thermal_device_mode mode)
 {
@@ -376,9 +365,6 @@ static int imx_set_mode(struct thermal_zone_device *tz,
 		}
 	}
 
-	data->mode = mode;
-	thermal_zone_device_update(tz, THERMAL_EVENT_UNSPECIFIED);
-
 	return 0;
 }
 
@@ -467,7 +453,6 @@ static struct thermal_zone_device_ops imx_tz_ops = {
 	.bind = imx_bind,
 	.unbind = imx_unbind,
 	.get_temp = imx_get_temp,
-	.get_mode = imx_get_mode,
 	.set_mode = imx_set_mode,
 	.get_trip_type = imx_get_trip_type,
 	.get_trip_temp = imx_get_trip_temp,
@@ -831,7 +816,6 @@ static int imx_thermal_probe(struct platform_device *pdev)
 		     data->socdata->measure_temp_mask);
 
 	data->irq_enabled = true;
-	data->mode = THERMAL_DEVICE_ENABLED;
 
 	ret = devm_request_threaded_irq(&pdev->dev, data->irq,
 			imx_thermal_alarm_irq, imx_thermal_alarm_irq_thread,
@@ -885,7 +869,7 @@ static int __maybe_unused imx_thermal_suspend(struct device *dev)
 		     data->socdata->measure_temp_mask);
 	regmap_write(map, data->socdata->sensor_ctrl + REG_SET,
 		     data->socdata->power_down_mask);
-	data->mode = THERMAL_DEVICE_DISABLED;
+	thermal_zone_device_disable(data->tz);
 	clk_disable_unprepare(data->thermal_clk);
 
 	return 0;
@@ -905,7 +889,7 @@ static int __maybe_unused imx_thermal_resume(struct device *dev)
 		     data->socdata->power_down_mask);
 	regmap_write(map, data->socdata->sensor_ctrl + REG_SET,
 		     data->socdata->measure_temp_mask);
-	data->mode = THERMAL_DEVICE_ENABLED;
+	thermal_zone_device_enable(data->tz);
 
 	return 0;
 }
diff --git a/drivers/thermal/intel/int340x_thermal/int3400_thermal.c b/drivers/thermal/intel/int340x_thermal/int3400_thermal.c
index e802922a13cf..50642f01e2bf 100644
--- a/drivers/thermal/intel/int340x_thermal/int3400_thermal.c
+++ b/drivers/thermal/intel/int340x_thermal/int3400_thermal.c
@@ -44,7 +44,6 @@ static char *int3400_thermal_uuids[INT3400_THERMAL_MAXIMUM_UUID] = {
 struct int3400_thermal_priv {
 	struct acpi_device *adev;
 	struct thermal_zone_device *thermal;
-	int mode;
 	int art_count;
 	struct art *arts;
 	int trt_count;
@@ -230,54 +229,32 @@ static int int3400_thermal_get_temp(struct thermal_zone_device *thermal,
 	return 0;
 }
 
-static int int3400_thermal_get_mode(struct thermal_zone_device *thermal,
-				enum thermal_device_mode *mode)
-{
-	struct int3400_thermal_priv *priv = thermal->devdata;
-
-	if (!priv)
-		return -EINVAL;
-
-	*mode = priv->mode;
-
-	return 0;
-}
-
 static int int3400_thermal_set_mode(struct thermal_zone_device *thermal,
 				enum thermal_device_mode mode)
 {
 	struct int3400_thermal_priv *priv = thermal->devdata;
-	bool enable;
 	int result = 0;
 
 	if (!priv)
 		return -EINVAL;
 
-	if (mode == THERMAL_DEVICE_ENABLED)
-		enable = true;
-	else if (mode == THERMAL_DEVICE_DISABLED)
-		enable = false;
-	else
-		return -EINVAL;
-
-	if (enable != priv->mode) {
-		priv->mode = enable;
+	if (mode != thermal->mode) {
 		result = int3400_thermal_run_osc(priv->adev->handle,
-						 priv->current_uuid_index,
-						 enable);
+						priv->current_uuid_index,
+						mode == THERMAL_DEVICE_ENABLED);
 	}
 	return result;
 }
 
 static struct thermal_zone_device_ops int3400_thermal_ops = {
 	.get_temp = int3400_thermal_get_temp,
-	.get_mode = int3400_thermal_get_mode,
 	.set_mode = int3400_thermal_set_mode,
 };
 
 static struct thermal_zone_params int3400_thermal_params = {
 	.governor_name = "user_space",
 	.no_hwmon = true,
+	.initial_mode = THERMAL_ZONE_DISABLED,
 };
 
 static int int3400_thermal_probe(struct platform_device *pdev)
diff --git a/drivers/thermal/intel/int340x_thermal/int340x_thermal_zone.c b/drivers/thermal/intel/int340x_thermal/int340x_thermal_zone.c
index 432213272f1e..b36da9bfbf8a 100644
--- a/drivers/thermal/intel/int340x_thermal/int340x_thermal_zone.c
+++ b/drivers/thermal/intel/int340x_thermal/int340x_thermal_zone.c
@@ -208,6 +208,7 @@ EXPORT_SYMBOL_GPL(int340x_thermal_read_trips);
 static struct thermal_zone_params int340x_thermal_params = {
 	.governor_name = "user_space",
 	.no_hwmon = true,
+	.initial_mode = THERMAL_DEVICE_ENABLED,
 };
 
 struct int34x_thermal_zone *int340x_thermal_zone_add(struct acpi_device *adev,
diff --git a/drivers/thermal/intel/intel_quark_dts_thermal.c b/drivers/thermal/intel/intel_quark_dts_thermal.c
index d704fc104cfd..c4879b4bfbf1 100644
--- a/drivers/thermal/intel/intel_quark_dts_thermal.c
+++ b/drivers/thermal/intel/intel_quark_dts_thermal.c
@@ -103,7 +103,6 @@ struct soc_sensor_entry {
 	bool locked;
 	u32 store_ptps;
 	u32 store_dts_enable;
-	enum thermal_device_mode mode;
 	struct thermal_zone_device *tzone;
 };
 
@@ -128,7 +127,7 @@ static int soc_dts_enable(struct thermal_zone_device *tzd)
 		return ret;
 
 	if (out & QRK_DTS_ENABLE_BIT) {
-		aux_entry->mode = THERMAL_DEVICE_ENABLED;
+		tzd->mode = THERMAL_DEVICE_ENABLED;
 		return 0;
 	}
 
@@ -139,9 +138,9 @@ static int soc_dts_enable(struct thermal_zone_device *tzd)
 		if (ret)
 			return ret;
 
-		aux_entry->mode = THERMAL_DEVICE_ENABLED;
+		tzd->mode = THERMAL_DEVICE_ENABLED;
 	} else {
-		aux_entry->mode = THERMAL_DEVICE_DISABLED;
+		tzd->mode = THERMAL_DEVICE_DISABLED;
 		pr_info("DTS is locked. Cannot enable DTS\n");
 		ret = -EPERM;
 	}
@@ -161,7 +160,7 @@ static int soc_dts_disable(struct thermal_zone_device *tzd)
 		return ret;
 
 	if (!(out & QRK_DTS_ENABLE_BIT)) {
-		aux_entry->mode = THERMAL_DEVICE_DISABLED;
+		tzd->mode = THERMAL_DEVICE_DISABLED;
 		return 0;
 	}
 
@@ -173,9 +172,9 @@ static int soc_dts_disable(struct thermal_zone_device *tzd)
 		if (ret)
 			return ret;
 
-		aux_entry->mode = THERMAL_DEVICE_DISABLED;
+		tzd->mode = THERMAL_DEVICE_DISABLED;
 	} else {
-		aux_entry->mode = THERMAL_DEVICE_ENABLED;
+		tzd->mode = THERMAL_DEVICE_ENABLED;
 		pr_info("DTS is locked. Cannot disable DTS\n");
 		ret = -EPERM;
 	}
@@ -309,14 +308,6 @@ static int sys_get_curr_temp(struct thermal_zone_device *tzd,
 	return 0;
 }
 
-static int sys_get_mode(struct thermal_zone_device *tzd,
-				enum thermal_device_mode *mode)
-{
-	struct soc_sensor_entry *aux_entry = tzd->devdata;
-	*mode = aux_entry->mode;
-	return 0;
-}
-
 static int sys_set_mode(struct thermal_zone_device *tzd,
 				enum thermal_device_mode mode)
 {
@@ -338,7 +329,6 @@ static struct thermal_zone_device_ops tzone_ops = {
 	.get_trip_type = sys_get_trip_type,
 	.set_trip_temp = sys_set_trip_temp,
 	.get_crit_temp = sys_get_crit_temp,
-	.get_mode = sys_get_mode,
 	.set_mode = sys_set_mode,
 };
 
diff --git a/drivers/thermal/intel/x86_pkg_temp_thermal.c b/drivers/thermal/intel/x86_pkg_temp_thermal.c
index a006b9fd1d72..cb810a02aab0 100644
--- a/drivers/thermal/intel/x86_pkg_temp_thermal.c
+++ b/drivers/thermal/intel/x86_pkg_temp_thermal.c
@@ -56,6 +56,7 @@ struct zone_device {
 
 static struct thermal_zone_params pkg_temp_tz_params = {
 	.no_hwmon	= true,
+	.initial_mode	= THERMAL_DEVICE_ENABLED,
 };
 
 /* Keep track of how many zone pointers we allocated in init() */
diff --git a/drivers/thermal/of-thermal.c b/drivers/thermal/of-thermal.c
index 874a47d6923f..48787a5576d8 100644
--- a/drivers/thermal/of-thermal.c
+++ b/drivers/thermal/of-thermal.c
@@ -51,7 +51,6 @@ struct __thermal_bind_params {
 
 /**
  * struct __thermal_zone - internal representation of a thermal zone
- * @mode: current thermal zone device mode (enabled/disabled)
  * @passive_delay: polling interval while passive cooling is activated
  * @polling_delay: zone polling interval
  * @slope: slope of the temperature adjustment curve
@@ -65,7 +64,6 @@ struct __thermal_bind_params {
  */
 
 struct __thermal_zone {
-	enum thermal_device_mode mode;
 	int passive_delay;
 	int polling_delay;
 	int slope;
@@ -269,23 +267,11 @@ static int of_thermal_unbind(struct thermal_zone_device *thermal,
 	return 0;
 }
 
-static int of_thermal_get_mode(struct thermal_zone_device *tz,
-			       enum thermal_device_mode *mode)
-{
-	struct __thermal_zone *data = tz->devdata;
-
-	*mode = data->mode;
-
-	return 0;
-}
-
 static int of_thermal_set_mode(struct thermal_zone_device *tz,
 			       enum thermal_device_mode mode)
 {
 	struct __thermal_zone *data = tz->devdata;
 
-	mutex_lock(&tz->lock);
-
 	if (mode == THERMAL_DEVICE_ENABLED) {
 		tz->polling_delay = data->polling_delay;
 		tz->passive_delay = data->passive_delay;
@@ -294,11 +280,6 @@ static int of_thermal_set_mode(struct thermal_zone_device *tz,
 		tz->passive_delay = 0;
 	}
 
-	mutex_unlock(&tz->lock);
-
-	data->mode = mode;
-	thermal_zone_device_update(tz, THERMAL_EVENT_UNSPECIFIED);
-
 	return 0;
 }
 
@@ -393,7 +374,6 @@ static int of_thermal_get_crit_temp(struct thermal_zone_device *tz,
 }
 
 static struct thermal_zone_device_ops of_thermal_ops = {
-	.get_mode = of_thermal_get_mode,
 	.set_mode = of_thermal_set_mode,
 
 	.get_trip_type = of_thermal_get_trip_type,
@@ -554,7 +534,7 @@ thermal_zone_of_sensor_register(struct device *dev, int sensor_id, void *data,
 			tzd = thermal_zone_of_add_sensor(child, sensor_np,
 							 data, ops);
 			if (!IS_ERR(tzd))
-				tzd->ops->set_mode(tzd, THERMAL_DEVICE_ENABLED);
+				thermal_zone_device_enable(tzd);
 
 			of_node_put(child);
 			goto exit;
@@ -979,7 +959,6 @@ __init *thermal_of_build_thermal_zone(struct device_node *np)
 
 finish:
 	of_node_put(child);
-	tz->mode = THERMAL_DEVICE_DISABLED;
 
 	return tz;
 
@@ -1120,6 +1099,7 @@ int __init of_parse_thermal_zones(void)
 		/* these two are left for temperature drivers to use */
 		tzp->slope = tz->slope;
 		tzp->offset = tz->offset;
+		tzp->initial_mode = THERMAL_DEVICE_DISABLED;
 
 		zone = thermal_zone_device_register(child->name, tz->ntrips,
 						    mask, tz,
diff --git a/drivers/thermal/rockchip_thermal.c b/drivers/thermal/rockchip_thermal.c
index 15a71ecc916c..aa9e0e31ef98 100644
--- a/drivers/thermal/rockchip_thermal.c
+++ b/drivers/thermal/rockchip_thermal.c
@@ -1068,8 +1068,10 @@ rockchip_thermal_toggle_sensor(struct rockchip_thermal_sensor *sensor, bool on)
 {
 	struct thermal_zone_device *tzd = sensor->tzd;
 
-	tzd->ops->set_mode(tzd,
-		on ? THERMAL_DEVICE_ENABLED : THERMAL_DEVICE_DISABLED);
+	if (on)
+		thermal_zone_device_enable(tzd);
+	else
+		thermal_zone_device_disable(tzd);
 }
 
 static irqreturn_t rockchip_thermal_alarm_irq_thread(int irq, void *dev)
diff --git a/drivers/thermal/sprd_thermal.c b/drivers/thermal/sprd_thermal.c
index a340374e8c51..58f995b0f804 100644
--- a/drivers/thermal/sprd_thermal.c
+++ b/drivers/thermal/sprd_thermal.c
@@ -322,8 +322,10 @@ static void sprd_thm_toggle_sensor(struct sprd_thermal_sensor *sen, bool on)
 {
 	struct thermal_zone_device *tzd = sen->tzd;
 
-	tzd->ops->set_mode(tzd,
-		on ? THERMAL_DEVICE_ENABLED : THERMAL_DEVICE_DISABLED);
+	if (on)
+		thermal_zone_device_enable(tzd);
+	else
+		thermal_zone_device_disable(tzd);
 }
 
 static int sprd_thm_probe(struct platform_device *pdev)
diff --git a/drivers/thermal/thermal_core.c b/drivers/thermal/thermal_core.c
index c06550930979..a012d77dd602 100644
--- a/drivers/thermal/thermal_core.c
+++ b/drivers/thermal/thermal_core.c
@@ -463,6 +463,44 @@ static void thermal_zone_device_reset(struct thermal_zone_device *tz)
 	thermal_zone_device_init(tz);
 }
 
+enum thermal_device_mode
+thermal_zone_device_get_mode(struct thermal_zone_device *tz)
+{
+	enum thermal_device_mode mode;
+
+	mutex_lock(&tz->lock);
+
+	mode = tz->mode;
+
+	mutex_unlock(&tz->lock);
+
+	return mode;
+}
+
+int thermal_zone_device_set_mode(struct thermal_zone_device *tz,
+				 enum thermal_device_mode mode)
+{
+	int ret = 0;
+
+	if (mode != THERMAL_DEVICE_DISABLED &&
+	    mode != THERMAL_DEVICE_ENABLED)
+		return -EINVAL;
+
+	mutex_lock(&tz->lock);
+
+	if (tz->ops->set_mode)
+		ret = tz->ops->set_mode(tz, mode);
+
+	tz->mode = mode;
+
+	mutex_unlock(&tz->lock);
+
+	thermal_zone_device_update(tz, THERMAL_EVENT_UNSPECIFIED);
+
+	return ret;
+}
+EXPORT_SYMBOL_GPL(thermal_zone_device_set_mode);
+
 void thermal_zone_device_update(struct thermal_zone_device *tz,
 				enum thermal_notify_event event)
 {
@@ -1236,6 +1274,7 @@ thermal_zone_device_register(const char *type, int trips, int mask,
 	int result;
 	int count;
 	struct thermal_governor *governor;
+	enum thermal_device_mode mode;
 
 	if (!type || strlen(type) == 0) {
 		pr_err("Error: No thermal zone type defined\n");
@@ -1340,9 +1379,9 @@ thermal_zone_device_register(const char *type, int trips, int mask,
 	INIT_DELAYED_WORK(&tz->poll_queue, thermal_zone_device_check);
 
 	thermal_zone_device_reset(tz);
-	/* Update the new thermal zone and mark it as already updated. */
-	if (atomic_cmpxchg(&tz->need_update, 1, 0))
-		thermal_zone_device_update(tz, THERMAL_EVENT_UNSPECIFIED);
+
+	mode = tzp ? tzp->initial_mode : THERMAL_DEVICE_ENABLED;
+	thermal_zone_device_set_mode(tz, mode);
 
 	return tz;
 
@@ -1473,9 +1512,7 @@ static int thermal_pm_notify(struct notifier_block *nb,
 	case PM_POST_SUSPEND:
 		atomic_set(&in_suspend, 0);
 		list_for_each_entry(tz, &thermal_tz_list, node) {
-			tz_mode = THERMAL_DEVICE_ENABLED;
-			if (tz->ops->get_mode)
-				tz->ops->get_mode(tz, &tz_mode);
+			tz_mode = thermal_zone_device_get_mode(tz);
 
 			if (tz_mode == THERMAL_DEVICE_DISABLED)
 				continue;
diff --git a/drivers/thermal/thermal_core.h b/drivers/thermal/thermal_core.h
index c95689586e19..ff5519adb68a 100644
--- a/drivers/thermal/thermal_core.h
+++ b/drivers/thermal/thermal_core.h
@@ -141,6 +141,9 @@ thermal_cooling_device_stats_update(struct thermal_cooling_device *cdev,
 				    unsigned long new_state) {}
 #endif /* CONFIG_THERMAL_STATISTICS */
 
+enum thermal_device_mode
+thermal_zone_device_get_mode(struct thermal_zone_device *tz);
+
 /* device tree support */
 #ifdef CONFIG_THERMAL_OF
 int of_parse_thermal_zones(void);
diff --git a/drivers/thermal/thermal_sysfs.c b/drivers/thermal/thermal_sysfs.c
index aa99edb4dff7..cbb27b3c96d2 100644
--- a/drivers/thermal/thermal_sysfs.c
+++ b/drivers/thermal/thermal_sysfs.c
@@ -50,14 +50,8 @@ mode_show(struct device *dev, struct device_attribute *attr, char *buf)
 {
 	struct thermal_zone_device *tz = to_thermal_zone(dev);
 	enum thermal_device_mode mode;
-	int result;
-
-	if (!tz->ops->get_mode)
-		return -EPERM;
 
-	result = tz->ops->get_mode(tz, &mode);
-	if (result)
-		return result;
+	mode = thermal_zone_device_get_mode(tz);
 
 	return sprintf(buf, "%s\n", mode == THERMAL_DEVICE_ENABLED ? "enabled"
 		       : "disabled");
@@ -74,9 +68,9 @@ mode_store(struct device *dev, struct device_attribute *attr,
 		return -EPERM;
 
 	if (!strncmp(buf, "enabled", sizeof("enabled") - 1))
-		result = tz->ops->set_mode(tz, THERMAL_DEVICE_ENABLED);
+		result = thermal_zone_device_enable(tz);
 	else if (!strncmp(buf, "disabled", sizeof("disabled") - 1))
-		result = tz->ops->set_mode(tz, THERMAL_DEVICE_DISABLED);
+		result = thermal_zone_device_disable(tz);
 	else
 		result = -EINVAL;
 
@@ -428,30 +422,13 @@ static struct attribute_group thermal_zone_attribute_group = {
 	.attrs = thermal_zone_dev_attrs,
 };
 
-/* We expose mode only if .get_mode is present */
 static struct attribute *thermal_zone_mode_attrs[] = {
 	&dev_attr_mode.attr,
 	NULL,
 };
 
-static umode_t thermal_zone_mode_is_visible(struct kobject *kobj,
-					    struct attribute *attr,
-					    int attrno)
-{
-	struct device *dev = container_of(kobj, struct device, kobj);
-	struct thermal_zone_device *tz;
-
-	tz = container_of(dev, struct thermal_zone_device, device);
-
-	if (tz->ops->get_mode)
-		return attr->mode;
-
-	return 0;
-}
-
 static struct attribute_group thermal_zone_mode_attribute_group = {
 	.attrs = thermal_zone_mode_attrs,
-	.is_visible = thermal_zone_mode_is_visible,
 };
 
 /* We expose passive only if passive trips are present */
diff --git a/include/linux/thermal.h b/include/linux/thermal.h
index 216185bb3014..36b80ef80674 100644
--- a/include/linux/thermal.h
+++ b/include/linux/thermal.h
@@ -76,8 +76,6 @@ struct thermal_zone_device_ops {
 		       struct thermal_cooling_device *);
 	int (*get_temp) (struct thermal_zone_device *, int *);
 	int (*set_trips) (struct thermal_zone_device *, int, int);
-	int (*get_mode) (struct thermal_zone_device *,
-			 enum thermal_device_mode *);
 	int (*set_mode) (struct thermal_zone_device *,
 		enum thermal_device_mode);
 	int (*get_trip_type) (struct thermal_zone_device *, int,
@@ -128,6 +126,7 @@ struct thermal_cooling_device {
  * @trip_temp_attrs:	attributes for trip points for sysfs: trip temperature
  * @trip_type_attrs:	attributes for trip points for sysfs: trip type
  * @trip_hyst_attrs:	attributes for trip points for sysfs: trip hysteresis
+ * @mode:		current mode of this thermal zone
  * @devdata:	private pointer for device private data
  * @trips:	number of trip points the thermal zone supports
  * @trips_disabled;	bitmap for disabled trips
@@ -170,6 +169,7 @@ struct thermal_zone_device {
 	struct thermal_attr *trip_temp_attrs;
 	struct thermal_attr *trip_type_attrs;
 	struct thermal_attr *trip_hyst_attrs;
+	enum thermal_device_mode mode;
 	void *devdata;
 	int trips;
 	unsigned long trips_disabled;	/* bitmap for disabled trips */
@@ -264,6 +264,9 @@ struct thermal_zone_params {
 	int num_tbps;	/* Number of tbp entries */
 	struct thermal_bind_params *tbp;
 
+	/* Initial mode of this thermal zone device */
+	enum thermal_device_mode initial_mode;
+
 	/*
 	 * Sustainable power (heat) that this thermal zone can dissipate in
 	 * mW
@@ -395,6 +398,8 @@ int thermal_zone_bind_cooling_device(struct thermal_zone_device *, int,
 				     unsigned int);
 int thermal_zone_unbind_cooling_device(struct thermal_zone_device *, int,
 				       struct thermal_cooling_device *);
+int thermal_zone_device_set_mode(struct thermal_zone_device *tz,
+				 enum thermal_device_mode mode);
 void thermal_zone_device_update(struct thermal_zone_device *,
 				enum thermal_notify_event);
 
@@ -426,6 +431,9 @@ static inline struct thermal_zone_device *thermal_zone_device_register(
 static inline void thermal_zone_device_unregister(
 	struct thermal_zone_device *tz)
 { }
+int thermal_zone_device_set_mode(struct thermal_zone_device *tz,
+				 enum thermal_device_mode mode)
+{ return -EINVAL }
 static inline struct thermal_cooling_device *
 thermal_cooling_device_register(char *type, void *devdata,
 	const struct thermal_cooling_device_ops *ops)
@@ -465,4 +473,14 @@ static inline void thermal_notify_framework(struct thermal_zone_device *tz,
 { }
 #endif /* CONFIG_THERMAL */
 
+static inline int thermal_zone_device_enable(struct thermal_zone_device *tz)
+{
+	return thermal_zone_device_set_mode(tz, THERMAL_DEVICE_ENABLED);
+}
+
+static inline int thermal_zone_device_disable(struct thermal_zone_device *tz)
+{
+	return thermal_zone_device_set_mode(tz, THERMAL_DEVICE_DISABLED);
+}
+
 #endif /* __THERMAL_H__ */
-- 
2.17.1


^ permalink raw reply	[flat|nested] 63+ messages in thread

* [PATCH 2/2] thermal: core: Stop polling DISABLED thermal devices
  2020-04-20 18:17                 ` [PATCH 0/2] Stop monitoring disabled devices Andrzej Pietrasiewicz
  2020-04-20 18:17                   ` [PATCH 1/2] thermal: core: Let thermal zone device's mode be stored in its struct Andrzej Pietrasiewicz
@ 2020-04-20 18:17                   ` Andrzej Pietrasiewicz
  2020-04-22 16:12                   ` [PATCH RESEND 1/2] thermal: core: Let thermal zone device's mode be stored in its struct Andrzej Pietrasiewicz
  2 siblings, 0 replies; 63+ messages in thread
From: Andrzej Pietrasiewicz @ 2020-04-20 18:17 UTC (permalink / raw)
  To: linux-pm
  Cc: Zhang Rui, Rafael J . Wysocki, Len Brown, Jiri Pirko,
	Ido Schimmel, David S . Miller, Peter Kaestle, Darren Hart,
	Andy Shevchenko, Support Opensource, Daniel Lezcano,
	Amit Kucheria, Shawn Guo, Sascha Hauer, Pengutronix Kernel Team,
	Fabio Estevam, NXP Linux Team, Heiko Stuebner, Orson Zhai,
	Baolin Wang, Chunyan Zhang, linux-acpi, netdev,
	platform-driver-x86, linux-arm-kernel, kernel,
	Andrzej Pietrasiewicz, Barlomiej Zolnierkiewicz

Polling DISABLED devices is not desired, as all such "disabled" devices
are meant to be handled by userspace. This patch introduces and uses
should_stop_polling() to decide whether the device should be polled or not.

Signed-off-by: Andrzej Pietrasiewicz <andrzej.p@collabora.com>
---
 drivers/thermal/thermal_core.c | 16 ++++++++++++++--
 1 file changed, 14 insertions(+), 2 deletions(-)

diff --git a/drivers/thermal/thermal_core.c b/drivers/thermal/thermal_core.c
index a012d77dd602..c2dd9c561cf5 100644
--- a/drivers/thermal/thermal_core.c
+++ b/drivers/thermal/thermal_core.c
@@ -305,13 +305,22 @@ static void thermal_zone_device_set_polling(struct thermal_zone_device *tz,
 		cancel_delayed_work(&tz->poll_queue);
 }
 
+static inline bool should_stop_polling(struct thermal_zone_device *tz)
+{
+	return thermal_zone_device_get_mode(tz) == THERMAL_DEVICE_DISABLED;
+}
+
 static void monitor_thermal_zone(struct thermal_zone_device *tz)
 {
+	bool stop;
+
+	stop = should_stop_polling(tz);
+
 	mutex_lock(&tz->lock);
 
-	if (tz->passive)
+	if (!stop && tz->passive)
 		thermal_zone_device_set_polling(tz, tz->passive_delay);
-	else if (tz->polling_delay)
+	else if (!stop && tz->polling_delay)
 		thermal_zone_device_set_polling(tz, tz->polling_delay);
 	else
 		thermal_zone_device_set_polling(tz, 0);
@@ -506,6 +515,9 @@ void thermal_zone_device_update(struct thermal_zone_device *tz,
 {
 	int count;
 
+	if (should_stop_polling(tz))
+		return;
+
 	if (atomic_read(&in_suspend))
 		return;
 
-- 
2.17.1


^ permalink raw reply	[flat|nested] 63+ messages in thread

* Re: [RFC v3 1/2] thermal: core: Let thermal zone device's mode be stored in its struct
  2020-04-20 11:03               ` [RFC v3 1/2] thermal: core: Let thermal zone device's mode be stored in its struct Andrzej Pietrasiewicz
@ 2020-04-20 18:19                 ` Andrzej Pietrasiewicz
  0 siblings, 0 replies; 63+ messages in thread
From: Andrzej Pietrasiewicz @ 2020-04-20 18:19 UTC (permalink / raw)
  To: Bartlomiej Zolnierkiewicz
  Cc: linux-pm, Zhang Rui, Rafael J . Wysocki, Len Brown, Jiri Pirko,
	Ido Schimmel, David S . Miller, Peter Kaestle, Darren Hart,
	Andy Shevchenko, Support Opensource, Daniel Lezcano,
	Amit Kucheria, Shawn Guo, Sascha Hauer, Pengutronix Kernel Team,
	Fabio Estevam, NXP Linux Team, Allison Randal, Enrico Weigelt,
	Gayatri Kammela, Thomas Gleixner, linux-acpi, netdev,
	platform-driver-x86, linux-arm-kernel, kernel

@Daniel

please see below

W dniu 20.04.2020 o 13:03, Andrzej Pietrasiewicz pisze:
> Hi Barlomiej,
> 
> Thanks for looking into the series.
> 
> @Daniel can you see below?
> 
> W dniu 19.04.2020 o 13:38, Bartlomiej Zolnierkiewicz pisze:
>>
>> Hi Andrzej,
>>
>> On 4/17/20 6:20 PM, Andrzej Pietrasiewicz wrote:
>>> Thermal zone devices' mode is stored in individual drivers. This patch
>>> changes it so that mode is stored in struct thermal_zone_device instead.
>>>
>>> As a result all driver-specific variables storing the mode are not needed
>>> and are removed. Consequently, the get_mode() implementations have nothing
>>> to operate on and need to be removed, too.
>>>
>>> Some thermal framework specific functions are introduced:
>>>
>>> thermal_zone_device_get_mode()
>>> thermal_zone_device_set_mode()
>>> thermal_zone_device_enable()
>>> thermal_zone_device_disable()
>>>
>>> thermal_zone_device_get_mode() and its "set" counterpart take tzd's lock
>>> and the "set" calls driver's set_mode() if provided, so the latter must
>>> not take this lock again. At the end of the "set"
>>> thermal_zone_device_update() is called so drivers don't need to repeat this
>>> invocation in their specific set_mode() implementations.
>>>
>>> The scope of the above 4 functions is purposedly limited to the thermal
>>> framework and drivers are not supposed to call them. This encapsulation
>>
>> This should be true only for thermal_zone_device_{get,set}_mode().
>>
>> thermal_zone_device_{en,dis}able() should be available for device drivers:
>>
>> * of/thermal device drivers need to enable thermal device itself
>>    (please refer to my patchset for details)
>>
>> * device drivers need to call them on ->suspend and ->resume operations
>>
> 
> @Daniel:
> 
> How does this compare to
> 
> "Just:
> 
> thermal_zone_device_get_mode()
> thermal_zone_device_set_mode()
> thermal_zone_device_disable()
> thermal_zone_device_enable()
> 
> And all of them in drivers/thermal/thermal_core.h". Did I understand
> you correctly?
> 

I sent a PATCH series (rather than next iteration of RFC) addressing
Bartlomiej's comments. They make sense to me.

Regards,

Andrzej

^ permalink raw reply	[flat|nested] 63+ messages in thread

* Re: [PATCH 1/2] thermal: core: Let thermal zone device's mode be stored in its struct
  2020-04-20 18:17                   ` [PATCH 1/2] thermal: core: Let thermal zone device's mode be stored in its struct Andrzej Pietrasiewicz
@ 2020-04-22  7:49                     ` kbuild test robot
  2020-04-22 17:14                       ` Andrzej Pietrasiewicz
  2020-04-22 17:03                     ` kbuild test robot
  1 sibling, 1 reply; 63+ messages in thread
From: kbuild test robot @ 2020-04-22  7:49 UTC (permalink / raw)
  To: Andrzej Pietrasiewicz, linux-pm
  Cc: kbuild-all, Zhang Rui, Rafael J . Wysocki, Len Brown, Jiri Pirko,
	Ido Schimmel, David S . Miller, Peter Kaestle, Darren Hart,
	Andy Shevchenko


[-- Attachment #1: Type: text/plain, Size: 3329 bytes --]

Hi Andrzej,

I love your patch! Yet something to improve:

[auto build test ERROR on 79799562bf087b30d9dd0fddf5bed2d3b038be08]

url:    https://github.com/0day-ci/linux/commits/Andrzej-Pietrasiewicz/Stop-monitoring-disabled-devices/20200422-133553
base:    79799562bf087b30d9dd0fddf5bed2d3b038be08
config: arm-iop32x_defconfig (attached as .config)
compiler: arm-linux-gnueabi-gcc (GCC) 9.3.0
reproduce:
        wget https://raw.githubusercontent.com/intel/lkp-tests/master/sbin/make.cross -O ~/bin/make.cross
        chmod +x ~/bin/make.cross
        # save the attached .config to linux build tree
        COMPILER_INSTALL_PATH=$HOME/0day GCC_VERSION=9.3.0 make.cross ARCH=arm 

If you fix the issue, kindly add following tag as appropriate
Reported-by: kbuild test robot <lkp@intel.com>

All errors (new ones prefixed by >>):

   In file included from drivers/hwmon/hwmon.c:22:
   include/linux/thermal.h: In function 'thermal_zone_device_set_mode':
>> include/linux/thermal.h:436:18: error: expected ';' before '}' token
     436 | { return -EINVAL }
         |                  ^

vim +436 include/linux/thermal.h

   421	
   422	void thermal_cdev_update(struct thermal_cooling_device *);
   423	void thermal_notify_framework(struct thermal_zone_device *, int);
   424	#else
   425	static inline struct thermal_zone_device *thermal_zone_device_register(
   426		const char *type, int trips, int mask, void *devdata,
   427		struct thermal_zone_device_ops *ops,
   428		struct thermal_zone_params *tzp,
   429		int passive_delay, int polling_delay)
   430	{ return ERR_PTR(-ENODEV); }
   431	static inline void thermal_zone_device_unregister(
   432		struct thermal_zone_device *tz)
   433	{ }
   434	int thermal_zone_device_set_mode(struct thermal_zone_device *tz,
   435					 enum thermal_device_mode mode)
 > 436	{ return -EINVAL }
   437	static inline struct thermal_cooling_device *
   438	thermal_cooling_device_register(char *type, void *devdata,
   439		const struct thermal_cooling_device_ops *ops)
   440	{ return ERR_PTR(-ENODEV); }
   441	static inline struct thermal_cooling_device *
   442	thermal_of_cooling_device_register(struct device_node *np,
   443		char *type, void *devdata, const struct thermal_cooling_device_ops *ops)
   444	{ return ERR_PTR(-ENODEV); }
   445	static inline struct thermal_cooling_device *
   446	devm_thermal_of_cooling_device_register(struct device *dev,
   447					struct device_node *np,
   448					char *type, void *devdata,
   449					const struct thermal_cooling_device_ops *ops)
   450	{
   451		return ERR_PTR(-ENODEV);
   452	}
   453	static inline void thermal_cooling_device_unregister(
   454		struct thermal_cooling_device *cdev)
   455	{ }
   456	static inline struct thermal_zone_device *thermal_zone_get_zone_by_name(
   457			const char *name)
   458	{ return ERR_PTR(-ENODEV); }
   459	static inline int thermal_zone_get_temp(
   460			struct thermal_zone_device *tz, int *temp)
   461	{ return -ENODEV; }
   462	static inline int thermal_zone_get_slope(
   463			struct thermal_zone_device *tz)
   464	{ return -ENODEV; }
   465	static inline int thermal_zone_get_offset(
   466			struct thermal_zone_device *tz)
   467	{ return -ENODEV; }
   468	

---
0-DAY CI Kernel Test Service, Intel Corporation
https://lists.01.org/hyperkitty/list/kbuild-all@lists.01.org

[-- Attachment #2: .config.gz --]
[-- Type: application/gzip, Size: 18793 bytes --]

^ permalink raw reply	[flat|nested] 63+ messages in thread

* [PATCH RESEND 1/2] thermal: core: Let thermal zone device's mode be stored in its struct
  2020-04-20 18:17                 ` [PATCH 0/2] Stop monitoring disabled devices Andrzej Pietrasiewicz
  2020-04-20 18:17                   ` [PATCH 1/2] thermal: core: Let thermal zone device's mode be stored in its struct Andrzej Pietrasiewicz
  2020-04-20 18:17                   ` [PATCH 2/2] thermal: core: Stop polling DISABLED thermal devices Andrzej Pietrasiewicz
@ 2020-04-22 16:12                   ` Andrzej Pietrasiewicz
  2020-04-23 14:39                     ` Bartlomiej Zolnierkiewicz
  2 siblings, 1 reply; 63+ messages in thread
From: Andrzej Pietrasiewicz @ 2020-04-22 16:12 UTC (permalink / raw)
  To: linux-pm
  Cc: Zhang Rui, Rafael J . Wysocki, Len Brown, Jiri Pirko,
	Ido Schimmel, David S . Miller, Peter Kaestle, Darren Hart,
	Andy Shevchenko, Support Opensource, Daniel Lezcano,
	Amit Kucheria, Shawn Guo, Sascha Hauer, Pengutronix Kernel Team,
	Fabio Estevam, NXP Linux Team, Heiko Stuebner, Orson Zhai,
	Baolin Wang, Chunyan Zhang, linux-acpi, netdev,
	platform-driver-x86, linux-arm-kernel, kernel,
	Andrzej Pietrasiewicz, Barlomiej Zolnierkiewicz

Thermal zone devices' mode is stored in individual drivers. This patch
changes it so that mode is stored in struct thermal_zone_device instead.

As a result all driver-specific variables storing the mode are not needed
and are removed. Consequently, the get_mode() implementations have nothing
to operate on and need to be removed, too.

Some thermal framework functions are introduced:

thermal_zone_device_get_mode()
thermal_zone_device_set_mode()
thermal_zone_device_enable()
thermal_zone_device_disable()

thermal_zone_device_get_mode() and its "set" counterpart take tzd's lock
and the "set" calls driver's set_mode() if provided, so the latter must
not take this lock again. At the end of the "set"
thermal_zone_device_update() is called so drivers don't need to repeat this
invocation in their specific set_mode() implementations.

struct thermal_zone_params gains a new member called initial_mode, which
is used to set tzd's mode at registration time and if tzp is not provided
to thermal_zone_device_register() then it is assumed that the initial
mode is THERMAL_DEVICE_ENABLED.

The sysfs "mode" attribute is always exposed from now on, because all
thermal zone devices now have their get_mode() implemented at the generic
level and it is always available. Exposing "mode" doesn't hurt the drivers
which don't provide their own set_mode(), because writing to "mode" will
result in -EPERM, as expected.

Signed-off-by: Andrzej Pietrasiewicz <andrzej.p@collabora.com>
---

Fixed two typos:

- one found by kbuild test robot <lkp@intel.com> (missing semicolon
in dummy implementation of thermal_zone_device_set_mode()

- one found by myself (.initial_mode in int3400_thermal_params set to
a nonexistent THERMAL_ZONE_DISABLED - should be THERMAL_DEVICE_DISABLED)

 drivers/acpi/thermal.c                        | 35 ++-----------
 .../ethernet/mellanox/mlxsw/core_thermal.c    | 42 ----------------
 drivers/platform/x86/acerhdf.c                | 17 ++-----
 drivers/thermal/da9062-thermal.c              | 11 -----
 drivers/thermal/hisi_thermal.c                |  6 ++-
 drivers/thermal/imx_thermal.c                 | 24 ++-------
 .../intel/int340x_thermal/int3400_thermal.c   | 31 ++----------
 .../int340x_thermal/int340x_thermal_zone.c    |  1 +
 .../thermal/intel/intel_quark_dts_thermal.c   | 22 +++------
 drivers/thermal/intel/x86_pkg_temp_thermal.c  |  1 +
 drivers/thermal/of-thermal.c                  | 24 +--------
 drivers/thermal/rockchip_thermal.c            |  6 ++-
 drivers/thermal/sprd_thermal.c                |  6 ++-
 drivers/thermal/thermal_core.c                | 49 ++++++++++++++++---
 drivers/thermal/thermal_core.h                |  3 ++
 drivers/thermal/thermal_sysfs.c               | 29 ++---------
 include/linux/thermal.h                       | 22 ++++++++-
 17 files changed, 107 insertions(+), 222 deletions(-)

diff --git a/drivers/acpi/thermal.c b/drivers/acpi/thermal.c
index 19067a5e5293..d1f352ed5241 100644
--- a/drivers/acpi/thermal.c
+++ b/drivers/acpi/thermal.c
@@ -172,7 +172,6 @@ struct acpi_thermal {
 	struct acpi_thermal_trips trips;
 	struct acpi_handle_list devices;
 	struct thermal_zone_device *thermal_zone;
-	int tz_enabled;
 	int kelvin_offset;	/* in millidegrees */
 	struct work_struct thermal_check_work;
 };
@@ -500,7 +499,7 @@ static void acpi_thermal_check(void *data)
 {
 	struct acpi_thermal *tz = data;
 
-	if (!tz->tz_enabled)
+	if (tz->thermal_zone->mode != THERMAL_DEVICE_ENABLED)
 		return;
 
 	thermal_zone_device_update(tz->thermal_zone,
@@ -526,25 +525,10 @@ static int thermal_get_temp(struct thermal_zone_device *thermal, int *temp)
 	return 0;
 }
 
-static int thermal_get_mode(struct thermal_zone_device *thermal,
-				enum thermal_device_mode *mode)
-{
-	struct acpi_thermal *tz = thermal->devdata;
-
-	if (!tz)
-		return -EINVAL;
-
-	*mode = tz->tz_enabled ? THERMAL_DEVICE_ENABLED :
-		THERMAL_DEVICE_DISABLED;
-
-	return 0;
-}
-
 static int thermal_set_mode(struct thermal_zone_device *thermal,
 				enum thermal_device_mode mode)
 {
 	struct acpi_thermal *tz = thermal->devdata;
-	int enable;
 
 	if (!tz)
 		return -EINVAL;
@@ -552,20 +536,14 @@ static int thermal_set_mode(struct thermal_zone_device *thermal,
 	/*
 	 * enable/disable thermal management from ACPI thermal driver
 	 */
-	if (mode == THERMAL_DEVICE_ENABLED)
-		enable = 1;
-	else if (mode == THERMAL_DEVICE_DISABLED) {
-		enable = 0;
+	if (mode == THERMAL_DEVICE_DISABLED)
 		pr_warn("thermal zone will be disabled\n");
-	} else
-		return -EINVAL;
 
-	if (enable != tz->tz_enabled) {
-		tz->tz_enabled = enable;
+	if (mode != thermal->mode) {
 		ACPI_DEBUG_PRINT((ACPI_DB_INFO,
 			"%s kernel ACPI thermal control\n",
-			tz->tz_enabled ? "Enable" : "Disable"));
-		acpi_thermal_check(tz);
+			mode == THERMAL_DEVICE_ENABLED ?
+			"Enable" : "Disable"));
 	}
 	return 0;
 }
@@ -856,7 +834,6 @@ static struct thermal_zone_device_ops acpi_thermal_zone_ops = {
 	.bind = acpi_thermal_bind_cooling_device,
 	.unbind	= acpi_thermal_unbind_cooling_device,
 	.get_temp = thermal_get_temp,
-	.get_mode = thermal_get_mode,
 	.set_mode = thermal_set_mode,
 	.get_trip_type = thermal_get_trip_type,
 	.get_trip_temp = thermal_get_trip_temp,
@@ -913,8 +890,6 @@ static int acpi_thermal_register_thermal_zone(struct acpi_thermal *tz)
 	if (ACPI_FAILURE(status))
 		return -ENODEV;
 
-	tz->tz_enabled = 1;
-
 	dev_info(&tz->device->dev, "registered as thermal_zone%d\n",
 		 tz->thermal_zone->id);
 	return 0;
diff --git a/drivers/net/ethernet/mellanox/mlxsw/core_thermal.c b/drivers/net/ethernet/mellanox/mlxsw/core_thermal.c
index ce0a6837daa3..5d28384046da 100644
--- a/drivers/net/ethernet/mellanox/mlxsw/core_thermal.c
+++ b/drivers/net/ethernet/mellanox/mlxsw/core_thermal.c
@@ -98,7 +98,6 @@ struct mlxsw_thermal_module {
 	struct mlxsw_thermal *parent;
 	struct thermal_zone_device *tzdev;
 	struct mlxsw_thermal_trip trips[MLXSW_THERMAL_NUM_TRIPS];
-	enum thermal_device_mode mode;
 	int module; /* Module or gearbox number */
 };
 
@@ -110,7 +109,6 @@ struct mlxsw_thermal {
 	struct thermal_cooling_device *cdevs[MLXSW_MFCR_PWMS_MAX];
 	u8 cooling_levels[MLXSW_THERMAL_MAX_STATE + 1];
 	struct mlxsw_thermal_trip trips[MLXSW_THERMAL_NUM_TRIPS];
-	enum thermal_device_mode mode;
 	struct mlxsw_thermal_module *tz_module_arr;
 	u8 tz_module_num;
 	struct mlxsw_thermal_module *tz_gearbox_arr;
@@ -277,33 +275,16 @@ static int mlxsw_thermal_unbind(struct thermal_zone_device *tzdev,
 	return 0;
 }
 
-static int mlxsw_thermal_get_mode(struct thermal_zone_device *tzdev,
-				  enum thermal_device_mode *mode)
-{
-	struct mlxsw_thermal *thermal = tzdev->devdata;
-
-	*mode = thermal->mode;
-
-	return 0;
-}
-
 static int mlxsw_thermal_set_mode(struct thermal_zone_device *tzdev,
 				  enum thermal_device_mode mode)
 {
 	struct mlxsw_thermal *thermal = tzdev->devdata;
 
-	mutex_lock(&tzdev->lock);
-
 	if (mode == THERMAL_DEVICE_ENABLED)
 		tzdev->polling_delay = thermal->polling_delay;
 	else
 		tzdev->polling_delay = 0;
 
-	mutex_unlock(&tzdev->lock);
-
-	thermal->mode = mode;
-	thermal_zone_device_update(tzdev, THERMAL_EVENT_UNSPECIFIED);
-
 	return 0;
 }
 
@@ -407,7 +388,6 @@ static int mlxsw_thermal_trend_get(struct thermal_zone_device *tzdev,
 static struct thermal_zone_device_ops mlxsw_thermal_ops = {
 	.bind = mlxsw_thermal_bind,
 	.unbind = mlxsw_thermal_unbind,
-	.get_mode = mlxsw_thermal_get_mode,
 	.set_mode = mlxsw_thermal_set_mode,
 	.get_temp = mlxsw_thermal_get_temp,
 	.get_trip_type	= mlxsw_thermal_get_trip_type,
@@ -466,34 +446,17 @@ static int mlxsw_thermal_module_unbind(struct thermal_zone_device *tzdev,
 	return err;
 }
 
-static int mlxsw_thermal_module_mode_get(struct thermal_zone_device *tzdev,
-					 enum thermal_device_mode *mode)
-{
-	struct mlxsw_thermal_module *tz = tzdev->devdata;
-
-	*mode = tz->mode;
-
-	return 0;
-}
-
 static int mlxsw_thermal_module_mode_set(struct thermal_zone_device *tzdev,
 					 enum thermal_device_mode mode)
 {
 	struct mlxsw_thermal_module *tz = tzdev->devdata;
 	struct mlxsw_thermal *thermal = tz->parent;
 
-	mutex_lock(&tzdev->lock);
-
 	if (mode == THERMAL_DEVICE_ENABLED)
 		tzdev->polling_delay = thermal->polling_delay;
 	else
 		tzdev->polling_delay = 0;
 
-	mutex_unlock(&tzdev->lock);
-
-	tz->mode = mode;
-	thermal_zone_device_update(tzdev, THERMAL_EVENT_UNSPECIFIED);
-
 	return 0;
 }
 
@@ -596,7 +559,6 @@ mlxsw_thermal_module_trip_hyst_set(struct thermal_zone_device *tzdev, int trip,
 static struct thermal_zone_device_ops mlxsw_thermal_module_ops = {
 	.bind		= mlxsw_thermal_module_bind,
 	.unbind		= mlxsw_thermal_module_unbind,
-	.get_mode	= mlxsw_thermal_module_mode_get,
 	.set_mode	= mlxsw_thermal_module_mode_set,
 	.get_temp	= mlxsw_thermal_module_temp_get,
 	.get_trip_type	= mlxsw_thermal_module_trip_type_get,
@@ -635,7 +597,6 @@ static int mlxsw_thermal_gearbox_temp_get(struct thermal_zone_device *tzdev,
 static struct thermal_zone_device_ops mlxsw_thermal_gearbox_ops = {
 	.bind		= mlxsw_thermal_module_bind,
 	.unbind		= mlxsw_thermal_module_unbind,
-	.get_mode	= mlxsw_thermal_module_mode_get,
 	.set_mode	= mlxsw_thermal_module_mode_set,
 	.get_temp	= mlxsw_thermal_gearbox_temp_get,
 	.get_trip_type	= mlxsw_thermal_module_trip_type_get,
@@ -765,7 +726,6 @@ mlxsw_thermal_module_tz_init(struct mlxsw_thermal_module *module_tz)
 		return err;
 	}
 
-	module_tz->mode = THERMAL_DEVICE_ENABLED;
 	return 0;
 }
 
@@ -881,7 +841,6 @@ mlxsw_thermal_gearbox_tz_init(struct mlxsw_thermal_module *gearbox_tz)
 	if (IS_ERR(gearbox_tz->tzdev))
 		return PTR_ERR(gearbox_tz->tzdev);
 
-	gearbox_tz->mode = THERMAL_DEVICE_ENABLED;
 	return 0;
 }
 
@@ -1050,7 +1009,6 @@ int mlxsw_thermal_init(struct mlxsw_core *core,
 	if (err)
 		goto err_unreg_modules_tzdev;
 
-	thermal->mode = THERMAL_DEVICE_ENABLED;
 	*p_thermal = thermal;
 	return 0;
 
diff --git a/drivers/platform/x86/acerhdf.c b/drivers/platform/x86/acerhdf.c
index 8cc86f4e3ac1..aaf8b845be90 100644
--- a/drivers/platform/x86/acerhdf.c
+++ b/drivers/platform/x86/acerhdf.c
@@ -406,22 +406,9 @@ static inline void acerhdf_enable_kernelmode(void)
 	kernelmode = 1;
 
 	thz_dev->polling_delay = interval*1000;
-	thermal_zone_device_update(thz_dev, THERMAL_EVENT_UNSPECIFIED);
 	pr_notice("kernel mode fan control ON\n");
 }
 
-static int acerhdf_get_mode(struct thermal_zone_device *thermal,
-			    enum thermal_device_mode *mode)
-{
-	if (verbose)
-		pr_notice("kernel mode fan control %d\n", kernelmode);
-
-	*mode = (kernelmode) ? THERMAL_DEVICE_ENABLED
-			     : THERMAL_DEVICE_DISABLED;
-
-	return 0;
-}
-
 /*
  * set operation mode;
  * enabled: the thermal layer of the kernel takes care about
@@ -488,7 +475,6 @@ static struct thermal_zone_device_ops acerhdf_dev_ops = {
 	.bind = acerhdf_bind,
 	.unbind = acerhdf_unbind,
 	.get_temp = acerhdf_get_ec_temp,
-	.get_mode = acerhdf_get_mode,
 	.set_mode = acerhdf_set_mode,
 	.get_trip_type = acerhdf_get_trip_type,
 	.get_trip_hyst = acerhdf_get_trip_hyst,
@@ -554,6 +540,7 @@ static int acerhdf_set_cur_state(struct thermal_cooling_device *cdev,
 
 err_out:
 	acerhdf_revert_to_bios_mode();
+	thz_dev->mode = THERMAL_DEVICE_DISABLED;
 	return -EINVAL;
 }
 
@@ -739,6 +726,8 @@ static int __init acerhdf_register_thermal(void)
 	if (IS_ERR(cl_dev))
 		return -EINVAL;
 
+	acerhdf_zone_params.initial_mode =
+		kernelmode ? THERMAL_DEVICE_ENABLED : THERMAL_DEVICE_DISABLED;
 	thz_dev = thermal_zone_device_register("acerhdf", 2, 0, NULL,
 					      &acerhdf_dev_ops,
 					      &acerhdf_zone_params, 0,
diff --git a/drivers/thermal/da9062-thermal.c b/drivers/thermal/da9062-thermal.c
index c32709badeda..c3075d038095 100644
--- a/drivers/thermal/da9062-thermal.c
+++ b/drivers/thermal/da9062-thermal.c
@@ -49,7 +49,6 @@ struct da9062_thermal {
 	struct da9062 *hw;
 	struct delayed_work work;
 	struct thermal_zone_device *zone;
-	enum thermal_device_mode mode;
 	struct mutex lock; /* protection for da9062_thermal temperature */
 	int temperature;
 	int irq;
@@ -121,14 +120,6 @@ static irqreturn_t da9062_thermal_irq_handler(int irq, void *data)
 	return IRQ_HANDLED;
 }
 
-static int da9062_thermal_get_mode(struct thermal_zone_device *z,
-				   enum thermal_device_mode *mode)
-{
-	struct da9062_thermal *thermal = z->devdata;
-	*mode = thermal->mode;
-	return 0;
-}
-
 static int da9062_thermal_get_trip_type(struct thermal_zone_device *z,
 					int trip,
 					enum thermal_trip_type *type)
@@ -181,7 +172,6 @@ static int da9062_thermal_get_temp(struct thermal_zone_device *z,
 
 static struct thermal_zone_device_ops da9062_thermal_ops = {
 	.get_temp	= da9062_thermal_get_temp,
-	.get_mode	= da9062_thermal_get_mode,
 	.get_trip_type	= da9062_thermal_get_trip_type,
 	.get_trip_temp	= da9062_thermal_get_trip_temp,
 };
@@ -233,7 +223,6 @@ static int da9062_thermal_probe(struct platform_device *pdev)
 
 	thermal->config = match->data;
 	thermal->hw = chip;
-	thermal->mode = THERMAL_DEVICE_ENABLED;
 	thermal->dev = &pdev->dev;
 
 	INIT_DELAYED_WORK(&thermal->work, da9062_thermal_poll_on);
diff --git a/drivers/thermal/hisi_thermal.c b/drivers/thermal/hisi_thermal.c
index 2d26ae80e202..ee05950afd2f 100644
--- a/drivers/thermal/hisi_thermal.c
+++ b/drivers/thermal/hisi_thermal.c
@@ -549,8 +549,10 @@ static void hisi_thermal_toggle_sensor(struct hisi_thermal_sensor *sensor,
 {
 	struct thermal_zone_device *tzd = sensor->tzd;
 
-	tzd->ops->set_mode(tzd,
-		on ? THERMAL_DEVICE_ENABLED : THERMAL_DEVICE_DISABLED);
+	if (on)
+		thermal_zone_device_enable(tzd);
+	else
+		thermal_zone_device_disable(tzd);
 }
 
 static int hisi_thermal_probe(struct platform_device *pdev)
diff --git a/drivers/thermal/imx_thermal.c b/drivers/thermal/imx_thermal.c
index e761c9b42217..edbcb30815dc 100644
--- a/drivers/thermal/imx_thermal.c
+++ b/drivers/thermal/imx_thermal.c
@@ -197,7 +197,6 @@ struct imx_thermal_data {
 	struct cpufreq_policy *policy;
 	struct thermal_zone_device *tz;
 	struct thermal_cooling_device *cdev;
-	enum thermal_device_mode mode;
 	struct regmap *tempmon;
 	u32 c1, c2; /* See formula in imx_init_calib() */
 	int temp_passive;
@@ -256,7 +255,7 @@ static int imx_get_temp(struct thermal_zone_device *tz, int *temp)
 	bool wait;
 	u32 val;
 
-	if (data->mode == THERMAL_DEVICE_ENABLED) {
+	if (tz->mode == THERMAL_DEVICE_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 +282,7 @@ static int imx_get_temp(struct thermal_zone_device *tz, int *temp)
 
 	regmap_read(map, soc_data->temp_data, &val);
 
-	if (data->mode != THERMAL_DEVICE_ENABLED) {
+	if (tz->mode != THERMAL_DEVICE_ENABLED) {
 		regmap_write(map, soc_data->sensor_ctrl + REG_CLR,
 			     soc_data->measure_temp_mask);
 		regmap_write(map, soc_data->sensor_ctrl + REG_SET,
@@ -331,16 +330,6 @@ static int imx_get_temp(struct thermal_zone_device *tz, int *temp)
 	return 0;
 }
 
-static int imx_get_mode(struct thermal_zone_device *tz,
-			enum thermal_device_mode *mode)
-{
-	struct imx_thermal_data *data = tz->devdata;
-
-	*mode = data->mode;
-
-	return 0;
-}
-
 static int imx_set_mode(struct thermal_zone_device *tz,
 			enum thermal_device_mode mode)
 {
@@ -376,9 +365,6 @@ static int imx_set_mode(struct thermal_zone_device *tz,
 		}
 	}
 
-	data->mode = mode;
-	thermal_zone_device_update(tz, THERMAL_EVENT_UNSPECIFIED);
-
 	return 0;
 }
 
@@ -467,7 +453,6 @@ static struct thermal_zone_device_ops imx_tz_ops = {
 	.bind = imx_bind,
 	.unbind = imx_unbind,
 	.get_temp = imx_get_temp,
-	.get_mode = imx_get_mode,
 	.set_mode = imx_set_mode,
 	.get_trip_type = imx_get_trip_type,
 	.get_trip_temp = imx_get_trip_temp,
@@ -831,7 +816,6 @@ static int imx_thermal_probe(struct platform_device *pdev)
 		     data->socdata->measure_temp_mask);
 
 	data->irq_enabled = true;
-	data->mode = THERMAL_DEVICE_ENABLED;
 
 	ret = devm_request_threaded_irq(&pdev->dev, data->irq,
 			imx_thermal_alarm_irq, imx_thermal_alarm_irq_thread,
@@ -885,7 +869,7 @@ static int __maybe_unused imx_thermal_suspend(struct device *dev)
 		     data->socdata->measure_temp_mask);
 	regmap_write(map, data->socdata->sensor_ctrl + REG_SET,
 		     data->socdata->power_down_mask);
-	data->mode = THERMAL_DEVICE_DISABLED;
+	thermal_zone_device_disable(data->tz);
 	clk_disable_unprepare(data->thermal_clk);
 
 	return 0;
@@ -905,7 +889,7 @@ static int __maybe_unused imx_thermal_resume(struct device *dev)
 		     data->socdata->power_down_mask);
 	regmap_write(map, data->socdata->sensor_ctrl + REG_SET,
 		     data->socdata->measure_temp_mask);
-	data->mode = THERMAL_DEVICE_ENABLED;
+	thermal_zone_device_enable(data->tz);
 
 	return 0;
 }
diff --git a/drivers/thermal/intel/int340x_thermal/int3400_thermal.c b/drivers/thermal/intel/int340x_thermal/int3400_thermal.c
index e802922a13cf..1751d4b103b1 100644
--- a/drivers/thermal/intel/int340x_thermal/int3400_thermal.c
+++ b/drivers/thermal/intel/int340x_thermal/int3400_thermal.c
@@ -44,7 +44,6 @@ static char *int3400_thermal_uuids[INT3400_THERMAL_MAXIMUM_UUID] = {
 struct int3400_thermal_priv {
 	struct acpi_device *adev;
 	struct thermal_zone_device *thermal;
-	int mode;
 	int art_count;
 	struct art *arts;
 	int trt_count;
@@ -230,54 +229,32 @@ static int int3400_thermal_get_temp(struct thermal_zone_device *thermal,
 	return 0;
 }
 
-static int int3400_thermal_get_mode(struct thermal_zone_device *thermal,
-				enum thermal_device_mode *mode)
-{
-	struct int3400_thermal_priv *priv = thermal->devdata;
-
-	if (!priv)
-		return -EINVAL;
-
-	*mode = priv->mode;
-
-	return 0;
-}
-
 static int int3400_thermal_set_mode(struct thermal_zone_device *thermal,
 				enum thermal_device_mode mode)
 {
 	struct int3400_thermal_priv *priv = thermal->devdata;
-	bool enable;
 	int result = 0;
 
 	if (!priv)
 		return -EINVAL;
 
-	if (mode == THERMAL_DEVICE_ENABLED)
-		enable = true;
-	else if (mode == THERMAL_DEVICE_DISABLED)
-		enable = false;
-	else
-		return -EINVAL;
-
-	if (enable != priv->mode) {
-		priv->mode = enable;
+	if (mode != thermal->mode) {
 		result = int3400_thermal_run_osc(priv->adev->handle,
-						 priv->current_uuid_index,
-						 enable);
+						priv->current_uuid_index,
+						mode == THERMAL_DEVICE_ENABLED);
 	}
 	return result;
 }
 
 static struct thermal_zone_device_ops int3400_thermal_ops = {
 	.get_temp = int3400_thermal_get_temp,
-	.get_mode = int3400_thermal_get_mode,
 	.set_mode = int3400_thermal_set_mode,
 };
 
 static struct thermal_zone_params int3400_thermal_params = {
 	.governor_name = "user_space",
 	.no_hwmon = true,
+	.initial_mode = THERMAL_DEVICE_DISABLED,
 };
 
 static int int3400_thermal_probe(struct platform_device *pdev)
diff --git a/drivers/thermal/intel/int340x_thermal/int340x_thermal_zone.c b/drivers/thermal/intel/int340x_thermal/int340x_thermal_zone.c
index 432213272f1e..b36da9bfbf8a 100644
--- a/drivers/thermal/intel/int340x_thermal/int340x_thermal_zone.c
+++ b/drivers/thermal/intel/int340x_thermal/int340x_thermal_zone.c
@@ -208,6 +208,7 @@ EXPORT_SYMBOL_GPL(int340x_thermal_read_trips);
 static struct thermal_zone_params int340x_thermal_params = {
 	.governor_name = "user_space",
 	.no_hwmon = true,
+	.initial_mode = THERMAL_DEVICE_ENABLED,
 };
 
 struct int34x_thermal_zone *int340x_thermal_zone_add(struct acpi_device *adev,
diff --git a/drivers/thermal/intel/intel_quark_dts_thermal.c b/drivers/thermal/intel/intel_quark_dts_thermal.c
index d704fc104cfd..c4879b4bfbf1 100644
--- a/drivers/thermal/intel/intel_quark_dts_thermal.c
+++ b/drivers/thermal/intel/intel_quark_dts_thermal.c
@@ -103,7 +103,6 @@ struct soc_sensor_entry {
 	bool locked;
 	u32 store_ptps;
 	u32 store_dts_enable;
-	enum thermal_device_mode mode;
 	struct thermal_zone_device *tzone;
 };
 
@@ -128,7 +127,7 @@ static int soc_dts_enable(struct thermal_zone_device *tzd)
 		return ret;
 
 	if (out & QRK_DTS_ENABLE_BIT) {
-		aux_entry->mode = THERMAL_DEVICE_ENABLED;
+		tzd->mode = THERMAL_DEVICE_ENABLED;
 		return 0;
 	}
 
@@ -139,9 +138,9 @@ static int soc_dts_enable(struct thermal_zone_device *tzd)
 		if (ret)
 			return ret;
 
-		aux_entry->mode = THERMAL_DEVICE_ENABLED;
+		tzd->mode = THERMAL_DEVICE_ENABLED;
 	} else {
-		aux_entry->mode = THERMAL_DEVICE_DISABLED;
+		tzd->mode = THERMAL_DEVICE_DISABLED;
 		pr_info("DTS is locked. Cannot enable DTS\n");
 		ret = -EPERM;
 	}
@@ -161,7 +160,7 @@ static int soc_dts_disable(struct thermal_zone_device *tzd)
 		return ret;
 
 	if (!(out & QRK_DTS_ENABLE_BIT)) {
-		aux_entry->mode = THERMAL_DEVICE_DISABLED;
+		tzd->mode = THERMAL_DEVICE_DISABLED;
 		return 0;
 	}
 
@@ -173,9 +172,9 @@ static int soc_dts_disable(struct thermal_zone_device *tzd)
 		if (ret)
 			return ret;
 
-		aux_entry->mode = THERMAL_DEVICE_DISABLED;
+		tzd->mode = THERMAL_DEVICE_DISABLED;
 	} else {
-		aux_entry->mode = THERMAL_DEVICE_ENABLED;
+		tzd->mode = THERMAL_DEVICE_ENABLED;
 		pr_info("DTS is locked. Cannot disable DTS\n");
 		ret = -EPERM;
 	}
@@ -309,14 +308,6 @@ static int sys_get_curr_temp(struct thermal_zone_device *tzd,
 	return 0;
 }
 
-static int sys_get_mode(struct thermal_zone_device *tzd,
-				enum thermal_device_mode *mode)
-{
-	struct soc_sensor_entry *aux_entry = tzd->devdata;
-	*mode = aux_entry->mode;
-	return 0;
-}
-
 static int sys_set_mode(struct thermal_zone_device *tzd,
 				enum thermal_device_mode mode)
 {
@@ -338,7 +329,6 @@ static struct thermal_zone_device_ops tzone_ops = {
 	.get_trip_type = sys_get_trip_type,
 	.set_trip_temp = sys_set_trip_temp,
 	.get_crit_temp = sys_get_crit_temp,
-	.get_mode = sys_get_mode,
 	.set_mode = sys_set_mode,
 };
 
diff --git a/drivers/thermal/intel/x86_pkg_temp_thermal.c b/drivers/thermal/intel/x86_pkg_temp_thermal.c
index a006b9fd1d72..cb810a02aab0 100644
--- a/drivers/thermal/intel/x86_pkg_temp_thermal.c
+++ b/drivers/thermal/intel/x86_pkg_temp_thermal.c
@@ -56,6 +56,7 @@ struct zone_device {
 
 static struct thermal_zone_params pkg_temp_tz_params = {
 	.no_hwmon	= true,
+	.initial_mode	= THERMAL_DEVICE_ENABLED,
 };
 
 /* Keep track of how many zone pointers we allocated in init() */
diff --git a/drivers/thermal/of-thermal.c b/drivers/thermal/of-thermal.c
index 874a47d6923f..48787a5576d8 100644
--- a/drivers/thermal/of-thermal.c
+++ b/drivers/thermal/of-thermal.c
@@ -51,7 +51,6 @@ struct __thermal_bind_params {
 
 /**
  * struct __thermal_zone - internal representation of a thermal zone
- * @mode: current thermal zone device mode (enabled/disabled)
  * @passive_delay: polling interval while passive cooling is activated
  * @polling_delay: zone polling interval
  * @slope: slope of the temperature adjustment curve
@@ -65,7 +64,6 @@ struct __thermal_bind_params {
  */
 
 struct __thermal_zone {
-	enum thermal_device_mode mode;
 	int passive_delay;
 	int polling_delay;
 	int slope;
@@ -269,23 +267,11 @@ static int of_thermal_unbind(struct thermal_zone_device *thermal,
 	return 0;
 }
 
-static int of_thermal_get_mode(struct thermal_zone_device *tz,
-			       enum thermal_device_mode *mode)
-{
-	struct __thermal_zone *data = tz->devdata;
-
-	*mode = data->mode;
-
-	return 0;
-}
-
 static int of_thermal_set_mode(struct thermal_zone_device *tz,
 			       enum thermal_device_mode mode)
 {
 	struct __thermal_zone *data = tz->devdata;
 
-	mutex_lock(&tz->lock);
-
 	if (mode == THERMAL_DEVICE_ENABLED) {
 		tz->polling_delay = data->polling_delay;
 		tz->passive_delay = data->passive_delay;
@@ -294,11 +280,6 @@ static int of_thermal_set_mode(struct thermal_zone_device *tz,
 		tz->passive_delay = 0;
 	}
 
-	mutex_unlock(&tz->lock);
-
-	data->mode = mode;
-	thermal_zone_device_update(tz, THERMAL_EVENT_UNSPECIFIED);
-
 	return 0;
 }
 
@@ -393,7 +374,6 @@ static int of_thermal_get_crit_temp(struct thermal_zone_device *tz,
 }
 
 static struct thermal_zone_device_ops of_thermal_ops = {
-	.get_mode = of_thermal_get_mode,
 	.set_mode = of_thermal_set_mode,
 
 	.get_trip_type = of_thermal_get_trip_type,
@@ -554,7 +534,7 @@ thermal_zone_of_sensor_register(struct device *dev, int sensor_id, void *data,
 			tzd = thermal_zone_of_add_sensor(child, sensor_np,
 							 data, ops);
 			if (!IS_ERR(tzd))
-				tzd->ops->set_mode(tzd, THERMAL_DEVICE_ENABLED);
+				thermal_zone_device_enable(tzd);
 
 			of_node_put(child);
 			goto exit;
@@ -979,7 +959,6 @@ __init *thermal_of_build_thermal_zone(struct device_node *np)
 
 finish:
 	of_node_put(child);
-	tz->mode = THERMAL_DEVICE_DISABLED;
 
 	return tz;
 
@@ -1120,6 +1099,7 @@ int __init of_parse_thermal_zones(void)
 		/* these two are left for temperature drivers to use */
 		tzp->slope = tz->slope;
 		tzp->offset = tz->offset;
+		tzp->initial_mode = THERMAL_DEVICE_DISABLED;
 
 		zone = thermal_zone_device_register(child->name, tz->ntrips,
 						    mask, tz,
diff --git a/drivers/thermal/rockchip_thermal.c b/drivers/thermal/rockchip_thermal.c
index 15a71ecc916c..aa9e0e31ef98 100644
--- a/drivers/thermal/rockchip_thermal.c
+++ b/drivers/thermal/rockchip_thermal.c
@@ -1068,8 +1068,10 @@ rockchip_thermal_toggle_sensor(struct rockchip_thermal_sensor *sensor, bool on)
 {
 	struct thermal_zone_device *tzd = sensor->tzd;
 
-	tzd->ops->set_mode(tzd,
-		on ? THERMAL_DEVICE_ENABLED : THERMAL_DEVICE_DISABLED);
+	if (on)
+		thermal_zone_device_enable(tzd);
+	else
+		thermal_zone_device_disable(tzd);
 }
 
 static irqreturn_t rockchip_thermal_alarm_irq_thread(int irq, void *dev)
diff --git a/drivers/thermal/sprd_thermal.c b/drivers/thermal/sprd_thermal.c
index a340374e8c51..58f995b0f804 100644
--- a/drivers/thermal/sprd_thermal.c
+++ b/drivers/thermal/sprd_thermal.c
@@ -322,8 +322,10 @@ static void sprd_thm_toggle_sensor(struct sprd_thermal_sensor *sen, bool on)
 {
 	struct thermal_zone_device *tzd = sen->tzd;
 
-	tzd->ops->set_mode(tzd,
-		on ? THERMAL_DEVICE_ENABLED : THERMAL_DEVICE_DISABLED);
+	if (on)
+		thermal_zone_device_enable(tzd);
+	else
+		thermal_zone_device_disable(tzd);
 }
 
 static int sprd_thm_probe(struct platform_device *pdev)
diff --git a/drivers/thermal/thermal_core.c b/drivers/thermal/thermal_core.c
index c06550930979..a012d77dd602 100644
--- a/drivers/thermal/thermal_core.c
+++ b/drivers/thermal/thermal_core.c
@@ -463,6 +463,44 @@ static void thermal_zone_device_reset(struct thermal_zone_device *tz)
 	thermal_zone_device_init(tz);
 }
 
+enum thermal_device_mode
+thermal_zone_device_get_mode(struct thermal_zone_device *tz)
+{
+	enum thermal_device_mode mode;
+
+	mutex_lock(&tz->lock);
+
+	mode = tz->mode;
+
+	mutex_unlock(&tz->lock);
+
+	return mode;
+}
+
+int thermal_zone_device_set_mode(struct thermal_zone_device *tz,
+				 enum thermal_device_mode mode)
+{
+	int ret = 0;
+
+	if (mode != THERMAL_DEVICE_DISABLED &&
+	    mode != THERMAL_DEVICE_ENABLED)
+		return -EINVAL;
+
+	mutex_lock(&tz->lock);
+
+	if (tz->ops->set_mode)
+		ret = tz->ops->set_mode(tz, mode);
+
+	tz->mode = mode;
+
+	mutex_unlock(&tz->lock);
+
+	thermal_zone_device_update(tz, THERMAL_EVENT_UNSPECIFIED);
+
+	return ret;
+}
+EXPORT_SYMBOL_GPL(thermal_zone_device_set_mode);
+
 void thermal_zone_device_update(struct thermal_zone_device *tz,
 				enum thermal_notify_event event)
 {
@@ -1236,6 +1274,7 @@ thermal_zone_device_register(const char *type, int trips, int mask,
 	int result;
 	int count;
 	struct thermal_governor *governor;
+	enum thermal_device_mode mode;
 
 	if (!type || strlen(type) == 0) {
 		pr_err("Error: No thermal zone type defined\n");
@@ -1340,9 +1379,9 @@ thermal_zone_device_register(const char *type, int trips, int mask,
 	INIT_DELAYED_WORK(&tz->poll_queue, thermal_zone_device_check);
 
 	thermal_zone_device_reset(tz);
-	/* Update the new thermal zone and mark it as already updated. */
-	if (atomic_cmpxchg(&tz->need_update, 1, 0))
-		thermal_zone_device_update(tz, THERMAL_EVENT_UNSPECIFIED);
+
+	mode = tzp ? tzp->initial_mode : THERMAL_DEVICE_ENABLED;
+	thermal_zone_device_set_mode(tz, mode);
 
 	return tz;
 
@@ -1473,9 +1512,7 @@ static int thermal_pm_notify(struct notifier_block *nb,
 	case PM_POST_SUSPEND:
 		atomic_set(&in_suspend, 0);
 		list_for_each_entry(tz, &thermal_tz_list, node) {
-			tz_mode = THERMAL_DEVICE_ENABLED;
-			if (tz->ops->get_mode)
-				tz->ops->get_mode(tz, &tz_mode);
+			tz_mode = thermal_zone_device_get_mode(tz);
 
 			if (tz_mode == THERMAL_DEVICE_DISABLED)
 				continue;
diff --git a/drivers/thermal/thermal_core.h b/drivers/thermal/thermal_core.h
index c95689586e19..ff5519adb68a 100644
--- a/drivers/thermal/thermal_core.h
+++ b/drivers/thermal/thermal_core.h
@@ -141,6 +141,9 @@ thermal_cooling_device_stats_update(struct thermal_cooling_device *cdev,
 				    unsigned long new_state) {}
 #endif /* CONFIG_THERMAL_STATISTICS */
 
+enum thermal_device_mode
+thermal_zone_device_get_mode(struct thermal_zone_device *tz);
+
 /* device tree support */
 #ifdef CONFIG_THERMAL_OF
 int of_parse_thermal_zones(void);
diff --git a/drivers/thermal/thermal_sysfs.c b/drivers/thermal/thermal_sysfs.c
index aa99edb4dff7..cbb27b3c96d2 100644
--- a/drivers/thermal/thermal_sysfs.c
+++ b/drivers/thermal/thermal_sysfs.c
@@ -50,14 +50,8 @@ mode_show(struct device *dev, struct device_attribute *attr, char *buf)
 {
 	struct thermal_zone_device *tz = to_thermal_zone(dev);
 	enum thermal_device_mode mode;
-	int result;
-
-	if (!tz->ops->get_mode)
-		return -EPERM;
 
-	result = tz->ops->get_mode(tz, &mode);
-	if (result)
-		return result;
+	mode = thermal_zone_device_get_mode(tz);
 
 	return sprintf(buf, "%s\n", mode == THERMAL_DEVICE_ENABLED ? "enabled"
 		       : "disabled");
@@ -74,9 +68,9 @@ mode_store(struct device *dev, struct device_attribute *attr,
 		return -EPERM;
 
 	if (!strncmp(buf, "enabled", sizeof("enabled") - 1))
-		result = tz->ops->set_mode(tz, THERMAL_DEVICE_ENABLED);
+		result = thermal_zone_device_enable(tz);
 	else if (!strncmp(buf, "disabled", sizeof("disabled") - 1))
-		result = tz->ops->set_mode(tz, THERMAL_DEVICE_DISABLED);
+		result = thermal_zone_device_disable(tz);
 	else
 		result = -EINVAL;
 
@@ -428,30 +422,13 @@ static struct attribute_group thermal_zone_attribute_group = {
 	.attrs = thermal_zone_dev_attrs,
 };
 
-/* We expose mode only if .get_mode is present */
 static struct attribute *thermal_zone_mode_attrs[] = {
 	&dev_attr_mode.attr,
 	NULL,
 };
 
-static umode_t thermal_zone_mode_is_visible(struct kobject *kobj,
-					    struct attribute *attr,
-					    int attrno)
-{
-	struct device *dev = container_of(kobj, struct device, kobj);
-	struct thermal_zone_device *tz;
-
-	tz = container_of(dev, struct thermal_zone_device, device);
-
-	if (tz->ops->get_mode)
-		return attr->mode;
-
-	return 0;
-}
-
 static struct attribute_group thermal_zone_mode_attribute_group = {
 	.attrs = thermal_zone_mode_attrs,
-	.is_visible = thermal_zone_mode_is_visible,
 };
 
 /* We expose passive only if passive trips are present */
diff --git a/include/linux/thermal.h b/include/linux/thermal.h
index 216185bb3014..c789d4ff6e63 100644
--- a/include/linux/thermal.h
+++ b/include/linux/thermal.h
@@ -76,8 +76,6 @@ struct thermal_zone_device_ops {
 		       struct thermal_cooling_device *);
 	int (*get_temp) (struct thermal_zone_device *, int *);
 	int (*set_trips) (struct thermal_zone_device *, int, int);
-	int (*get_mode) (struct thermal_zone_device *,
-			 enum thermal_device_mode *);
 	int (*set_mode) (struct thermal_zone_device *,
 		enum thermal_device_mode);
 	int (*get_trip_type) (struct thermal_zone_device *, int,
@@ -128,6 +126,7 @@ struct thermal_cooling_device {
  * @trip_temp_attrs:	attributes for trip points for sysfs: trip temperature
  * @trip_type_attrs:	attributes for trip points for sysfs: trip type
  * @trip_hyst_attrs:	attributes for trip points for sysfs: trip hysteresis
+ * @mode:		current mode of this thermal zone
  * @devdata:	private pointer for device private data
  * @trips:	number of trip points the thermal zone supports
  * @trips_disabled;	bitmap for disabled trips
@@ -170,6 +169,7 @@ struct thermal_zone_device {
 	struct thermal_attr *trip_temp_attrs;
 	struct thermal_attr *trip_type_attrs;
 	struct thermal_attr *trip_hyst_attrs;
+	enum thermal_device_mode mode;
 	void *devdata;
 	int trips;
 	unsigned long trips_disabled;	/* bitmap for disabled trips */
@@ -264,6 +264,9 @@ struct thermal_zone_params {
 	int num_tbps;	/* Number of tbp entries */
 	struct thermal_bind_params *tbp;
 
+	/* Initial mode of this thermal zone device */
+	enum thermal_device_mode initial_mode;
+
 	/*
 	 * Sustainable power (heat) that this thermal zone can dissipate in
 	 * mW
@@ -395,6 +398,8 @@ int thermal_zone_bind_cooling_device(struct thermal_zone_device *, int,
 				     unsigned int);
 int thermal_zone_unbind_cooling_device(struct thermal_zone_device *, int,
 				       struct thermal_cooling_device *);
+int thermal_zone_device_set_mode(struct thermal_zone_device *tz,
+				 enum thermal_device_mode mode);
 void thermal_zone_device_update(struct thermal_zone_device *,
 				enum thermal_notify_event);
 
@@ -426,6 +431,9 @@ static inline struct thermal_zone_device *thermal_zone_device_register(
 static inline void thermal_zone_device_unregister(
 	struct thermal_zone_device *tz)
 { }
+int thermal_zone_device_set_mode(struct thermal_zone_device *tz,
+				 enum thermal_device_mode mode)
+{ return -EINVAL; }
 static inline struct thermal_cooling_device *
 thermal_cooling_device_register(char *type, void *devdata,
 	const struct thermal_cooling_device_ops *ops)
@@ -465,4 +473,14 @@ static inline void thermal_notify_framework(struct thermal_zone_device *tz,
 { }
 #endif /* CONFIG_THERMAL */
 
+static inline int thermal_zone_device_enable(struct thermal_zone_device *tz)
+{
+	return thermal_zone_device_set_mode(tz, THERMAL_DEVICE_ENABLED);
+}
+
+static inline int thermal_zone_device_disable(struct thermal_zone_device *tz)
+{
+	return thermal_zone_device_set_mode(tz, THERMAL_DEVICE_DISABLED);
+}
+
 #endif /* __THERMAL_H__ */
-- 
2.17.1


^ permalink raw reply	[flat|nested] 63+ messages in thread

* Re: [PATCH 1/2] thermal: core: Let thermal zone device's mode be stored in its struct
  2020-04-20 18:17                   ` [PATCH 1/2] thermal: core: Let thermal zone device's mode be stored in its struct Andrzej Pietrasiewicz
  2020-04-22  7:49                     ` kbuild test robot
@ 2020-04-22 17:03                     ` kbuild test robot
  2020-04-22 17:15                       ` Andrzej Pietrasiewicz
  1 sibling, 1 reply; 63+ messages in thread
From: kbuild test robot @ 2020-04-22 17:03 UTC (permalink / raw)
  To: Andrzej Pietrasiewicz, linux-pm
  Cc: kbuild-all, Zhang Rui, Rafael J . Wysocki, Len Brown, Jiri Pirko,
	Ido Schimmel, David S . Miller, Peter Kaestle, Darren Hart,
	Andy Shevchenko


[-- Attachment #1: Type: text/plain, Size: 1327 bytes --]

Hi Andrzej,

I love your patch! Yet something to improve:

[auto build test ERROR on 79799562bf087b30d9dd0fddf5bed2d3b038be08]

url:    https://github.com/0day-ci/linux/commits/Andrzej-Pietrasiewicz/Stop-monitoring-disabled-devices/20200422-133553
base:    79799562bf087b30d9dd0fddf5bed2d3b038be08
config: i386-allyesconfig (attached as .config)
compiler: gcc-7 (Ubuntu 7.5.0-6ubuntu2) 7.5.0
reproduce:
        # save the attached .config to linux build tree
        make ARCH=i386 

If you fix the issue, kindly add following tag as appropriate
Reported-by: kbuild test robot <lkp@intel.com>

All errors (new ones prefixed by >>):

>> drivers/thermal/intel/int340x_thermal/int3400_thermal.c:257:18: error: 'THERMAL_ZONE_DISABLED' undeclared here (not in a function); did you mean 'THERMAL_DEVICE_DISABLED'?
     .initial_mode = THERMAL_ZONE_DISABLED,
                     ^~~~~~~~~~~~~~~~~~~~~
                     THERMAL_DEVICE_DISABLED

vim +257 drivers/thermal/intel/int340x_thermal/int3400_thermal.c

   253	
   254	static struct thermal_zone_params int3400_thermal_params = {
   255		.governor_name = "user_space",
   256		.no_hwmon = true,
 > 257		.initial_mode = THERMAL_ZONE_DISABLED,
   258	};
   259	

---
0-DAY CI Kernel Test Service, Intel Corporation
https://lists.01.org/hyperkitty/list/kbuild-all@lists.01.org

[-- Attachment #2: .config.gz --]
[-- Type: application/gzip, Size: 72271 bytes --]

^ permalink raw reply	[flat|nested] 63+ messages in thread

* Re: [PATCH 1/2] thermal: core: Let thermal zone device's mode be stored in its struct
  2020-04-22  7:49                     ` kbuild test robot
@ 2020-04-22 17:14                       ` Andrzej Pietrasiewicz
  0 siblings, 0 replies; 63+ messages in thread
From: Andrzej Pietrasiewicz @ 2020-04-22 17:14 UTC (permalink / raw)
  To: kbuild test robot, linux-pm
  Cc: kbuild-all, Zhang Rui, Rafael J . Wysocki, Len Brown, Jiri Pirko,
	Ido Schimmel, David S . Miller, Peter Kaestle, Darren Hart,
	Andy Shevchenko

W dniu 22.04.2020 o 09:49, kbuild test robot pisze:
> Hi Andrzej,
> 
> I love your patch! Yet something to improve:
> 
> [auto build test ERROR on 79799562bf087b30d9dd0fddf5bed2d3b038be08]
> 
> url:    https://github.com/0day-ci/linux/commits/Andrzej-Pietrasiewicz/Stop-monitoring-disabled-devices/20200422-133553
> base:    79799562bf087b30d9dd0fddf5bed2d3b038be08
> config: arm-iop32x_defconfig (attached as .config)
> compiler: arm-linux-gnueabi-gcc (GCC) 9.3.0
> reproduce:
>          wget https://raw.githubusercontent.com/intel/lkp-tests/master/sbin/make.cross -O ~/bin/make.cross
>          chmod +x ~/bin/make.cross
>          # save the attached .config to linux build tree
>          COMPILER_INSTALL_PATH=$HOME/0day GCC_VERSION=9.3.0 make.cross ARCH=arm
> 
> If you fix the issue, kindly add following tag as appropriate
> Reported-by: kbuild test robot <lkp@intel.com>
> 
> All errors (new ones prefixed by >>):
> 
>     In file included from drivers/hwmon/hwmon.c:22:
>     include/linux/thermal.h: In function 'thermal_zone_device_set_mode':
>>> include/linux/thermal.h:436:18: error: expected ';' before '}' token
>       436 | { return -EINVAL }
>           |                  ^
> 

Addressed in PATCH RESEND 1/2, in reply to PATCH 1/2.

Andrzej

^ permalink raw reply	[flat|nested] 63+ messages in thread

* Re: [PATCH 1/2] thermal: core: Let thermal zone device's mode be stored in its struct
  2020-04-22 17:03                     ` kbuild test robot
@ 2020-04-22 17:15                       ` Andrzej Pietrasiewicz
  0 siblings, 0 replies; 63+ messages in thread
From: Andrzej Pietrasiewicz @ 2020-04-22 17:15 UTC (permalink / raw)
  To: kbuild test robot, linux-pm
  Cc: kbuild-all, Zhang Rui, Rafael J . Wysocki, Len Brown, Jiri Pirko,
	Ido Schimmel, David S . Miller, Peter Kaestle, Darren Hart,
	Andy Shevchenko

W dniu 22.04.2020 o 19:03, kbuild test robot pisze:
> Hi Andrzej,
> 
> I love your patch! Yet something to improve:
> 
> [auto build test ERROR on 79799562bf087b30d9dd0fddf5bed2d3b038be08]
> 
> url:    https://github.com/0day-ci/linux/commits/Andrzej-Pietrasiewicz/Stop-monitoring-disabled-devices/20200422-133553
> base:    79799562bf087b30d9dd0fddf5bed2d3b038be08
> config: i386-allyesconfig (attached as .config)
> compiler: gcc-7 (Ubuntu 7.5.0-6ubuntu2) 7.5.0
> reproduce:
>          # save the attached .config to linux build tree
>          make ARCH=i386
> 
> If you fix the issue, kindly add following tag as appropriate
> Reported-by: kbuild test robot <lkp@intel.com>
> 
> All errors (new ones prefixed by >>):
> 
>>> drivers/thermal/intel/int340x_thermal/int3400_thermal.c:257:18: error: 'THERMAL_ZONE_DISABLED' undeclared here (not in a function); did you mean 'THERMAL_DEVICE_DISABLED'?
>       .initial_mode = THERMAL_ZONE_DISABLED,
>                       ^~~~~~~~~~~~~~~~~~~~~
>                       THERMAL_DEVICE_DISABLED

Addressed in PATCH RESEND 1/2, in reply to PATCH 1/2.

Andrzej


^ permalink raw reply	[flat|nested] 63+ messages in thread

* Re: [PATCH RESEND 1/2] thermal: core: Let thermal zone device's mode be stored in its struct
  2020-04-22 16:12                   ` [PATCH RESEND 1/2] thermal: core: Let thermal zone device's mode be stored in its struct Andrzej Pietrasiewicz
@ 2020-04-23 14:39                     ` Bartlomiej Zolnierkiewicz
  2020-04-23 16:57                       ` [PATCH v3 0/2] Stop monitoring disabled devices Andrzej Pietrasiewicz
  0 siblings, 1 reply; 63+ messages in thread
From: Bartlomiej Zolnierkiewicz @ 2020-04-23 14:39 UTC (permalink / raw)
  To: Andrzej Pietrasiewicz
  Cc: linux-pm, Zhang Rui, Rafael J . Wysocki, Len Brown, Jiri Pirko,
	Ido Schimmel, David S . Miller, Peter Kaestle, Darren Hart,
	Andy Shevchenko, Support Opensource, Daniel Lezcano,
	Amit Kucheria, Shawn Guo, Sascha Hauer, Pengutronix Kernel Team,
	Fabio Estevam, NXP Linux Team, Heiko Stuebner, Orson Zhai,
	Baolin Wang, Chunyan Zhang, linux-acpi, netdev,
	platform-driver-x86, linux-arm-kernel, kernel


Thank you for updating the patch, some more comments below.

On 4/22/20 6:12 PM, Andrzej Pietrasiewicz wrote:
> Thermal zone devices' mode is stored in individual drivers. This patch
> changes it so that mode is stored in struct thermal_zone_device instead.
> 
> As a result all driver-specific variables storing the mode are not needed
> and are removed. Consequently, the get_mode() implementations have nothing
> to operate on and need to be removed, too.
> 
> Some thermal framework functions are introduced:
> 
> thermal_zone_device_get_mode()
> thermal_zone_device_set_mode()
> thermal_zone_device_enable()
> thermal_zone_device_disable()
> 
> thermal_zone_device_get_mode() and its "set" counterpart take tzd's lock
> and the "set" calls driver's set_mode() if provided, so the latter must
> not take this lock again. At the end of the "set"
> thermal_zone_device_update() is called so drivers don't need to repeat this
> invocation in their specific set_mode() implementations.
> 
> struct thermal_zone_params gains a new member called initial_mode, which
> is used to set tzd's mode at registration time and if tzp is not provided
> to thermal_zone_device_register() then it is assumed that the initial
> mode is THERMAL_DEVICE_ENABLED.
> 
> The sysfs "mode" attribute is always exposed from now on, because all
> thermal zone devices now have their get_mode() implemented at the generic
> level and it is always available. Exposing "mode" doesn't hurt the drivers
> which don't provide their own set_mode(), because writing to "mode" will
> result in -EPERM, as expected.
> 
> Signed-off-by: Andrzej Pietrasiewicz <andrzej.p@collabora.com>
> ---
> 
> Fixed two typos:
> 
> - one found by kbuild test robot <lkp@intel.com> (missing semicolon
> in dummy implementation of thermal_zone_device_set_mode()
> 
> - one found by myself (.initial_mode in int3400_thermal_params set to
> a nonexistent THERMAL_ZONE_DISABLED - should be THERMAL_DEVICE_DISABLED)

BTW Due to the above fixes the patch should have been be marked as v2,
not RESEND (please use RESEND only when posting again unchanged patch).

>  drivers/acpi/thermal.c                        | 35 ++-----------
>  .../ethernet/mellanox/mlxsw/core_thermal.c    | 42 ----------------
>  drivers/platform/x86/acerhdf.c                | 17 ++-----
>  drivers/thermal/da9062-thermal.c              | 11 -----
>  drivers/thermal/hisi_thermal.c                |  6 ++-
>  drivers/thermal/imx_thermal.c                 | 24 ++-------
>  .../intel/int340x_thermal/int3400_thermal.c   | 31 ++----------
>  .../int340x_thermal/int340x_thermal_zone.c    |  1 +
>  .../thermal/intel/intel_quark_dts_thermal.c   | 22 +++------
>  drivers/thermal/intel/x86_pkg_temp_thermal.c  |  1 +
>  drivers/thermal/of-thermal.c                  | 24 +--------
>  drivers/thermal/rockchip_thermal.c            |  6 ++-
>  drivers/thermal/sprd_thermal.c                |  6 ++-
>  drivers/thermal/thermal_core.c                | 49 ++++++++++++++++---
>  drivers/thermal/thermal_core.h                |  3 ++
>  drivers/thermal/thermal_sysfs.c               | 29 ++---------
>  include/linux/thermal.h                       | 22 ++++++++-
>  17 files changed, 107 insertions(+), 222 deletions(-)
> 
> diff --git a/drivers/acpi/thermal.c b/drivers/acpi/thermal.c
> index 19067a5e5293..d1f352ed5241 100644
> --- a/drivers/acpi/thermal.c
> +++ b/drivers/acpi/thermal.c
> @@ -172,7 +172,6 @@ struct acpi_thermal {
>  	struct acpi_thermal_trips trips;
>  	struct acpi_handle_list devices;
>  	struct thermal_zone_device *thermal_zone;
> -	int tz_enabled;
>  	int kelvin_offset;	/* in millidegrees */
>  	struct work_struct thermal_check_work;
>  };
> @@ -500,7 +499,7 @@ static void acpi_thermal_check(void *data)
>  {
>  	struct acpi_thermal *tz = data;
>  
> -	if (!tz->tz_enabled)
> +	if (tz->thermal_zone->mode != THERMAL_DEVICE_ENABLED)
>  		return;
>  
>  	thermal_zone_device_update(tz->thermal_zone,
> @@ -526,25 +525,10 @@ static int thermal_get_temp(struct thermal_zone_device *thermal, int *temp)
>  	return 0;
>  }
>  
> -static int thermal_get_mode(struct thermal_zone_device *thermal,
> -				enum thermal_device_mode *mode)
> -{
> -	struct acpi_thermal *tz = thermal->devdata;
> -
> -	if (!tz)
> -		return -EINVAL;
> -
> -	*mode = tz->tz_enabled ? THERMAL_DEVICE_ENABLED :
> -		THERMAL_DEVICE_DISABLED;
> -
> -	return 0;
> -}
> -
>  static int thermal_set_mode(struct thermal_zone_device *thermal,
>  				enum thermal_device_mode mode)
>  {
>  	struct acpi_thermal *tz = thermal->devdata;
> -	int enable;
>  
>  	if (!tz)
>  		return -EINVAL;
> @@ -552,20 +536,14 @@ static int thermal_set_mode(struct thermal_zone_device *thermal,
>  	/*
>  	 * enable/disable thermal management from ACPI thermal driver
>  	 */
> -	if (mode == THERMAL_DEVICE_ENABLED)
> -		enable = 1;
> -	else if (mode == THERMAL_DEVICE_DISABLED) {
> -		enable = 0;
> +	if (mode == THERMAL_DEVICE_DISABLED)
>  		pr_warn("thermal zone will be disabled\n");
> -	} else
> -		return -EINVAL;
>  
> -	if (enable != tz->tz_enabled) {
> -		tz->tz_enabled = enable;
> +	if (mode != thermal->mode) {
>  		ACPI_DEBUG_PRINT((ACPI_DB_INFO,
>  			"%s kernel ACPI thermal control\n",
> -			tz->tz_enabled ? "Enable" : "Disable"));
> -		acpi_thermal_check(tz);
> +			mode == THERMAL_DEVICE_ENABLED ?
> +			"Enable" : "Disable"));
>  	}
>  	return 0;
>  }
> @@ -856,7 +834,6 @@ static struct thermal_zone_device_ops acpi_thermal_zone_ops = {
>  	.bind = acpi_thermal_bind_cooling_device,
>  	.unbind	= acpi_thermal_unbind_cooling_device,
>  	.get_temp = thermal_get_temp,
> -	.get_mode = thermal_get_mode,
>  	.set_mode = thermal_set_mode,
>  	.get_trip_type = thermal_get_trip_type,
>  	.get_trip_temp = thermal_get_trip_temp,
> @@ -913,8 +890,6 @@ static int acpi_thermal_register_thermal_zone(struct acpi_thermal *tz)
>  	if (ACPI_FAILURE(status))
>  		return -ENODEV;
>  
> -	tz->tz_enabled = 1;
> -
>  	dev_info(&tz->device->dev, "registered as thermal_zone%d\n",
>  		 tz->thermal_zone->id);
>  	return 0;
> diff --git a/drivers/net/ethernet/mellanox/mlxsw/core_thermal.c b/drivers/net/ethernet/mellanox/mlxsw/core_thermal.c
> index ce0a6837daa3..5d28384046da 100644
> --- a/drivers/net/ethernet/mellanox/mlxsw/core_thermal.c
> +++ b/drivers/net/ethernet/mellanox/mlxsw/core_thermal.c
> @@ -98,7 +98,6 @@ struct mlxsw_thermal_module {
>  	struct mlxsw_thermal *parent;
>  	struct thermal_zone_device *tzdev;
>  	struct mlxsw_thermal_trip trips[MLXSW_THERMAL_NUM_TRIPS];
> -	enum thermal_device_mode mode;
>  	int module; /* Module or gearbox number */
>  };
>  
> @@ -110,7 +109,6 @@ struct mlxsw_thermal {
>  	struct thermal_cooling_device *cdevs[MLXSW_MFCR_PWMS_MAX];
>  	u8 cooling_levels[MLXSW_THERMAL_MAX_STATE + 1];
>  	struct mlxsw_thermal_trip trips[MLXSW_THERMAL_NUM_TRIPS];
> -	enum thermal_device_mode mode;
>  	struct mlxsw_thermal_module *tz_module_arr;
>  	u8 tz_module_num;
>  	struct mlxsw_thermal_module *tz_gearbox_arr;
> @@ -277,33 +275,16 @@ static int mlxsw_thermal_unbind(struct thermal_zone_device *tzdev,
>  	return 0;
>  }
>  
> -static int mlxsw_thermal_get_mode(struct thermal_zone_device *tzdev,
> -				  enum thermal_device_mode *mode)
> -{
> -	struct mlxsw_thermal *thermal = tzdev->devdata;
> -
> -	*mode = thermal->mode;
> -
> -	return 0;
> -}
> -
>  static int mlxsw_thermal_set_mode(struct thermal_zone_device *tzdev,
>  				  enum thermal_device_mode mode)
>  {
>  	struct mlxsw_thermal *thermal = tzdev->devdata;
>  
> -	mutex_lock(&tzdev->lock);
> -
>  	if (mode == THERMAL_DEVICE_ENABLED)
>  		tzdev->polling_delay = thermal->polling_delay;
>  	else
>  		tzdev->polling_delay = 0;
>  
> -	mutex_unlock(&tzdev->lock);
> -
> -	thermal->mode = mode;
> -	thermal_zone_device_update(tzdev, THERMAL_EVENT_UNSPECIFIED);
> -
>  	return 0;
>  }
>  
> @@ -407,7 +388,6 @@ static int mlxsw_thermal_trend_get(struct thermal_zone_device *tzdev,
>  static struct thermal_zone_device_ops mlxsw_thermal_ops = {
>  	.bind = mlxsw_thermal_bind,
>  	.unbind = mlxsw_thermal_unbind,
> -	.get_mode = mlxsw_thermal_get_mode,
>  	.set_mode = mlxsw_thermal_set_mode,
>  	.get_temp = mlxsw_thermal_get_temp,
>  	.get_trip_type	= mlxsw_thermal_get_trip_type,
> @@ -466,34 +446,17 @@ static int mlxsw_thermal_module_unbind(struct thermal_zone_device *tzdev,
>  	return err;
>  }
>  
> -static int mlxsw_thermal_module_mode_get(struct thermal_zone_device *tzdev,
> -					 enum thermal_device_mode *mode)
> -{
> -	struct mlxsw_thermal_module *tz = tzdev->devdata;
> -
> -	*mode = tz->mode;
> -
> -	return 0;
> -}
> -
>  static int mlxsw_thermal_module_mode_set(struct thermal_zone_device *tzdev,
>  					 enum thermal_device_mode mode)
>  {
>  	struct mlxsw_thermal_module *tz = tzdev->devdata;
>  	struct mlxsw_thermal *thermal = tz->parent;
>  
> -	mutex_lock(&tzdev->lock);
> -
>  	if (mode == THERMAL_DEVICE_ENABLED)
>  		tzdev->polling_delay = thermal->polling_delay;
>  	else
>  		tzdev->polling_delay = 0;
>  
> -	mutex_unlock(&tzdev->lock);
> -
> -	tz->mode = mode;
> -	thermal_zone_device_update(tzdev, THERMAL_EVENT_UNSPECIFIED);
> -
>  	return 0;
>  }
>  
> @@ -596,7 +559,6 @@ mlxsw_thermal_module_trip_hyst_set(struct thermal_zone_device *tzdev, int trip,
>  static struct thermal_zone_device_ops mlxsw_thermal_module_ops = {
>  	.bind		= mlxsw_thermal_module_bind,
>  	.unbind		= mlxsw_thermal_module_unbind,
> -	.get_mode	= mlxsw_thermal_module_mode_get,
>  	.set_mode	= mlxsw_thermal_module_mode_set,
>  	.get_temp	= mlxsw_thermal_module_temp_get,
>  	.get_trip_type	= mlxsw_thermal_module_trip_type_get,
> @@ -635,7 +597,6 @@ static int mlxsw_thermal_gearbox_temp_get(struct thermal_zone_device *tzdev,
>  static struct thermal_zone_device_ops mlxsw_thermal_gearbox_ops = {
>  	.bind		= mlxsw_thermal_module_bind,
>  	.unbind		= mlxsw_thermal_module_unbind,
> -	.get_mode	= mlxsw_thermal_module_mode_get,
>  	.set_mode	= mlxsw_thermal_module_mode_set,
>  	.get_temp	= mlxsw_thermal_gearbox_temp_get,
>  	.get_trip_type	= mlxsw_thermal_module_trip_type_get,
> @@ -765,7 +726,6 @@ mlxsw_thermal_module_tz_init(struct mlxsw_thermal_module *module_tz)
>  		return err;
>  	}
>  
> -	module_tz->mode = THERMAL_DEVICE_ENABLED;
>  	return 0;
>  }
>  
> @@ -881,7 +841,6 @@ mlxsw_thermal_gearbox_tz_init(struct mlxsw_thermal_module *gearbox_tz)
>  	if (IS_ERR(gearbox_tz->tzdev))
>  		return PTR_ERR(gearbox_tz->tzdev);
>  
> -	gearbox_tz->mode = THERMAL_DEVICE_ENABLED;
>  	return 0;
>  }
>  
> @@ -1050,7 +1009,6 @@ int mlxsw_thermal_init(struct mlxsw_core *core,
>  	if (err)
>  		goto err_unreg_modules_tzdev;
>  
> -	thermal->mode = THERMAL_DEVICE_ENABLED;
>  	*p_thermal = thermal;
>  	return 0;
>  
> diff --git a/drivers/platform/x86/acerhdf.c b/drivers/platform/x86/acerhdf.c
> index 8cc86f4e3ac1..aaf8b845be90 100644
> --- a/drivers/platform/x86/acerhdf.c
> +++ b/drivers/platform/x86/acerhdf.c
> @@ -406,22 +406,9 @@ static inline void acerhdf_enable_kernelmode(void)
>  	kernelmode = 1;
>  
>  	thz_dev->polling_delay = interval*1000;
> -	thermal_zone_device_update(thz_dev, THERMAL_EVENT_UNSPECIFIED);
>  	pr_notice("kernel mode fan control ON\n");
>  }
>  
> -static int acerhdf_get_mode(struct thermal_zone_device *thermal,
> -			    enum thermal_device_mode *mode)
> -{
> -	if (verbose)
> -		pr_notice("kernel mode fan control %d\n", kernelmode);
> -
> -	*mode = (kernelmode) ? THERMAL_DEVICE_ENABLED
> -			     : THERMAL_DEVICE_DISABLED;
> -
> -	return 0;
> -}
> -
>  /*
>   * set operation mode;
>   * enabled: the thermal layer of the kernel takes care about
> @@ -488,7 +475,6 @@ static struct thermal_zone_device_ops acerhdf_dev_ops = {
>  	.bind = acerhdf_bind,
>  	.unbind = acerhdf_unbind,
>  	.get_temp = acerhdf_get_ec_temp,
> -	.get_mode = acerhdf_get_mode,
>  	.set_mode = acerhdf_set_mode,
>  	.get_trip_type = acerhdf_get_trip_type,
>  	.get_trip_hyst = acerhdf_get_trip_hyst,
> @@ -554,6 +540,7 @@ static int acerhdf_set_cur_state(struct thermal_cooling_device *cdev,
>  
>  err_out:
>  	acerhdf_revert_to_bios_mode();
> +	thz_dev->mode = THERMAL_DEVICE_DISABLED;
>  	return -EINVAL;
>  }
>  
> @@ -739,6 +726,8 @@ static int __init acerhdf_register_thermal(void)
>  	if (IS_ERR(cl_dev))
>  		return -EINVAL;
>  
> +	acerhdf_zone_params.initial_mode =
> +		kernelmode ? THERMAL_DEVICE_ENABLED : THERMAL_DEVICE_DISABLED;
>  	thz_dev = thermal_zone_device_register("acerhdf", 2, 0, NULL,
>  					      &acerhdf_dev_ops,
>  					      &acerhdf_zone_params, 0,
> diff --git a/drivers/thermal/da9062-thermal.c b/drivers/thermal/da9062-thermal.c
> index c32709badeda..c3075d038095 100644
> --- a/drivers/thermal/da9062-thermal.c
> +++ b/drivers/thermal/da9062-thermal.c
> @@ -49,7 +49,6 @@ struct da9062_thermal {
>  	struct da9062 *hw;
>  	struct delayed_work work;
>  	struct thermal_zone_device *zone;
> -	enum thermal_device_mode mode;
>  	struct mutex lock; /* protection for da9062_thermal temperature */
>  	int temperature;
>  	int irq;
> @@ -121,14 +120,6 @@ static irqreturn_t da9062_thermal_irq_handler(int irq, void *data)
>  	return IRQ_HANDLED;
>  }
>  
> -static int da9062_thermal_get_mode(struct thermal_zone_device *z,
> -				   enum thermal_device_mode *mode)
> -{
> -	struct da9062_thermal *thermal = z->devdata;
> -	*mode = thermal->mode;
> -	return 0;
> -}
> -
>  static int da9062_thermal_get_trip_type(struct thermal_zone_device *z,
>  					int trip,
>  					enum thermal_trip_type *type)
> @@ -181,7 +172,6 @@ static int da9062_thermal_get_temp(struct thermal_zone_device *z,
>  
>  static struct thermal_zone_device_ops da9062_thermal_ops = {
>  	.get_temp	= da9062_thermal_get_temp,
> -	.get_mode	= da9062_thermal_get_mode,
>  	.get_trip_type	= da9062_thermal_get_trip_type,
>  	.get_trip_temp	= da9062_thermal_get_trip_temp,
>  };
> @@ -233,7 +223,6 @@ static int da9062_thermal_probe(struct platform_device *pdev)
>  
>  	thermal->config = match->data;
>  	thermal->hw = chip;
> -	thermal->mode = THERMAL_DEVICE_ENABLED;
>  	thermal->dev = &pdev->dev;
>  
>  	INIT_DELAYED_WORK(&thermal->work, da9062_thermal_poll_on);
> diff --git a/drivers/thermal/hisi_thermal.c b/drivers/thermal/hisi_thermal.c
> index 2d26ae80e202..ee05950afd2f 100644
> --- a/drivers/thermal/hisi_thermal.c
> +++ b/drivers/thermal/hisi_thermal.c
> @@ -549,8 +549,10 @@ static void hisi_thermal_toggle_sensor(struct hisi_thermal_sensor *sensor,
>  {
>  	struct thermal_zone_device *tzd = sensor->tzd;
>  
> -	tzd->ops->set_mode(tzd,
> -		on ? THERMAL_DEVICE_ENABLED : THERMAL_DEVICE_DISABLED);
> +	if (on)
> +		thermal_zone_device_enable(tzd);
> +	else
> +		thermal_zone_device_disable(tzd);
>  }
>  
>  static int hisi_thermal_probe(struct platform_device *pdev)
> diff --git a/drivers/thermal/imx_thermal.c b/drivers/thermal/imx_thermal.c
> index e761c9b42217..edbcb30815dc 100644
> --- a/drivers/thermal/imx_thermal.c
> +++ b/drivers/thermal/imx_thermal.c
> @@ -197,7 +197,6 @@ struct imx_thermal_data {
>  	struct cpufreq_policy *policy;
>  	struct thermal_zone_device *tz;
>  	struct thermal_cooling_device *cdev;
> -	enum thermal_device_mode mode;
>  	struct regmap *tempmon;
>  	u32 c1, c2; /* See formula in imx_init_calib() */
>  	int temp_passive;
> @@ -256,7 +255,7 @@ static int imx_get_temp(struct thermal_zone_device *tz, int *temp)
>  	bool wait;
>  	u32 val;
>  
> -	if (data->mode == THERMAL_DEVICE_ENABLED) {
> +	if (tz->mode == THERMAL_DEVICE_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 +282,7 @@ static int imx_get_temp(struct thermal_zone_device *tz, int *temp)
>  
>  	regmap_read(map, soc_data->temp_data, &val);
>  
> -	if (data->mode != THERMAL_DEVICE_ENABLED) {
> +	if (tz->mode != THERMAL_DEVICE_ENABLED) {
>  		regmap_write(map, soc_data->sensor_ctrl + REG_CLR,
>  			     soc_data->measure_temp_mask);
>  		regmap_write(map, soc_data->sensor_ctrl + REG_SET,
> @@ -331,16 +330,6 @@ static int imx_get_temp(struct thermal_zone_device *tz, int *temp)
>  	return 0;
>  }
>  
> -static int imx_get_mode(struct thermal_zone_device *tz,
> -			enum thermal_device_mode *mode)
> -{
> -	struct imx_thermal_data *data = tz->devdata;
> -
> -	*mode = data->mode;
> -
> -	return 0;
> -}
> -
>  static int imx_set_mode(struct thermal_zone_device *tz,
>  			enum thermal_device_mode mode)
>  {
> @@ -376,9 +365,6 @@ static int imx_set_mode(struct thermal_zone_device *tz,
>  		}
>  	}
>  
> -	data->mode = mode;
> -	thermal_zone_device_update(tz, THERMAL_EVENT_UNSPECIFIED);
> -
>  	return 0;
>  }
>  
> @@ -467,7 +453,6 @@ static struct thermal_zone_device_ops imx_tz_ops = {
>  	.bind = imx_bind,
>  	.unbind = imx_unbind,
>  	.get_temp = imx_get_temp,
> -	.get_mode = imx_get_mode,
>  	.set_mode = imx_set_mode,
>  	.get_trip_type = imx_get_trip_type,
>  	.get_trip_temp = imx_get_trip_temp,
> @@ -831,7 +816,6 @@ static int imx_thermal_probe(struct platform_device *pdev)
>  		     data->socdata->measure_temp_mask);
>  
>  	data->irq_enabled = true;
> -	data->mode = THERMAL_DEVICE_ENABLED;
>  
>  	ret = devm_request_threaded_irq(&pdev->dev, data->irq,
>  			imx_thermal_alarm_irq, imx_thermal_alarm_irq_thread,
> @@ -885,7 +869,7 @@ static int __maybe_unused imx_thermal_suspend(struct device *dev)
>  		     data->socdata->measure_temp_mask);
>  	regmap_write(map, data->socdata->sensor_ctrl + REG_SET,
>  		     data->socdata->power_down_mask);
> -	data->mode = THERMAL_DEVICE_DISABLED;
> +	thermal_zone_device_disable(data->tz);

Since we now also (indirectly) call ->set_mode here the following code:

	regmap_write(map, data->socdata->sensor_ctrl + REG_CLR,
		     data->socdata->measure_temp_mask);
	regmap_write(map, data->socdata->sensor_ctrl + REG_SET,
		     data->socdata->power_down_mask);

should be removed from imx_thermal_suspend().

>  	clk_disable_unprepare(data->thermal_clk);
>  
>  	return 0;
> @@ -905,7 +889,7 @@ static int __maybe_unused imx_thermal_resume(struct device *dev)
>  		     data->socdata->power_down_mask);
>  	regmap_write(map, data->socdata->sensor_ctrl + REG_SET,
>  		     data->socdata->measure_temp_mask);
> -	data->mode = THERMAL_DEVICE_ENABLED;
> +	thermal_zone_device_enable(data->tz);

Since we now also (indirectly) call ->set_mode here the following code:

	regmap_write(map, data->socdata->sensor_ctrl + REG_CLR,
		     data->socdata->power_down_mask);
	regmap_write(map, data->socdata->sensor_ctrl + REG_SET,
		     data->socdata->measure_temp_mask);

should be removed from imx_thermal_resume().

>  
>  	return 0;
>  }
> diff --git a/drivers/thermal/intel/int340x_thermal/int3400_thermal.c b/drivers/thermal/intel/int340x_thermal/int3400_thermal.c
> index e802922a13cf..1751d4b103b1 100644
> --- a/drivers/thermal/intel/int340x_thermal/int3400_thermal.c
> +++ b/drivers/thermal/intel/int340x_thermal/int3400_thermal.c
> @@ -44,7 +44,6 @@ static char *int3400_thermal_uuids[INT3400_THERMAL_MAXIMUM_UUID] = {
>  struct int3400_thermal_priv {
>  	struct acpi_device *adev;
>  	struct thermal_zone_device *thermal;
> -	int mode;
>  	int art_count;
>  	struct art *arts;
>  	int trt_count;
> @@ -230,54 +229,32 @@ static int int3400_thermal_get_temp(struct thermal_zone_device *thermal,
>  	return 0;
>  }
>  
> -static int int3400_thermal_get_mode(struct thermal_zone_device *thermal,
> -				enum thermal_device_mode *mode)
> -{
> -	struct int3400_thermal_priv *priv = thermal->devdata;
> -
> -	if (!priv)
> -		return -EINVAL;
> -
> -	*mode = priv->mode;
> -
> -	return 0;
> -}
> -
>  static int int3400_thermal_set_mode(struct thermal_zone_device *thermal,
>  				enum thermal_device_mode mode)
>  {
>  	struct int3400_thermal_priv *priv = thermal->devdata;
> -	bool enable;
>  	int result = 0;
>  
>  	if (!priv)
>  		return -EINVAL;
>  
> -	if (mode == THERMAL_DEVICE_ENABLED)
> -		enable = true;
> -	else if (mode == THERMAL_DEVICE_DISABLED)
> -		enable = false;
> -	else
> -		return -EINVAL;
> -
> -	if (enable != priv->mode) {
> -		priv->mode = enable;
> +	if (mode != thermal->mode) {
>  		result = int3400_thermal_run_osc(priv->adev->handle,
> -						 priv->current_uuid_index,
> -						 enable);
> +						priv->current_uuid_index,
> +						mode == THERMAL_DEVICE_ENABLED);
>  	}
>  	return result;
>  }
>  
>  static struct thermal_zone_device_ops int3400_thermal_ops = {
>  	.get_temp = int3400_thermal_get_temp,
> -	.get_mode = int3400_thermal_get_mode,
>  	.set_mode = int3400_thermal_set_mode,
>  };
>  
>  static struct thermal_zone_params int3400_thermal_params = {
>  	.governor_name = "user_space",
>  	.no_hwmon = true,
> +	.initial_mode = THERMAL_DEVICE_DISABLED,
>  };
>  
>  static int int3400_thermal_probe(struct platform_device *pdev)
> diff --git a/drivers/thermal/intel/int340x_thermal/int340x_thermal_zone.c b/drivers/thermal/intel/int340x_thermal/int340x_thermal_zone.c
> index 432213272f1e..b36da9bfbf8a 100644
> --- a/drivers/thermal/intel/int340x_thermal/int340x_thermal_zone.c
> +++ b/drivers/thermal/intel/int340x_thermal/int340x_thermal_zone.c
> @@ -208,6 +208,7 @@ EXPORT_SYMBOL_GPL(int340x_thermal_read_trips);
>  static struct thermal_zone_params int340x_thermal_params = {
>  	.governor_name = "user_space",
>  	.no_hwmon = true,
> +	.initial_mode = THERMAL_DEVICE_ENABLED,
>  };
>  
>  struct int34x_thermal_zone *int340x_thermal_zone_add(struct acpi_device *adev,
> diff --git a/drivers/thermal/intel/intel_quark_dts_thermal.c b/drivers/thermal/intel/intel_quark_dts_thermal.c
> index d704fc104cfd..c4879b4bfbf1 100644
> --- a/drivers/thermal/intel/intel_quark_dts_thermal.c
> +++ b/drivers/thermal/intel/intel_quark_dts_thermal.c
> @@ -103,7 +103,6 @@ struct soc_sensor_entry {
>  	bool locked;
>  	u32 store_ptps;
>  	u32 store_dts_enable;
> -	enum thermal_device_mode mode;
>  	struct thermal_zone_device *tzone;
>  };
>  
> @@ -128,7 +127,7 @@ static int soc_dts_enable(struct thermal_zone_device *tzd)
>  		return ret;
>  
>  	if (out & QRK_DTS_ENABLE_BIT) {
> -		aux_entry->mode = THERMAL_DEVICE_ENABLED;
> +		tzd->mode = THERMAL_DEVICE_ENABLED;
>  		return 0;
>  	}
>  
> @@ -139,9 +138,9 @@ static int soc_dts_enable(struct thermal_zone_device *tzd)
>  		if (ret)
>  			return ret;
>  
> -		aux_entry->mode = THERMAL_DEVICE_ENABLED;
> +		tzd->mode = THERMAL_DEVICE_ENABLED;
>  	} else {
> -		aux_entry->mode = THERMAL_DEVICE_DISABLED;
> +		tzd->mode = THERMAL_DEVICE_DISABLED;
>  		pr_info("DTS is locked. Cannot enable DTS\n");
>  		ret = -EPERM;
>  	}
> @@ -161,7 +160,7 @@ static int soc_dts_disable(struct thermal_zone_device *tzd)
>  		return ret;
>  
>  	if (!(out & QRK_DTS_ENABLE_BIT)) {
> -		aux_entry->mode = THERMAL_DEVICE_DISABLED;
> +		tzd->mode = THERMAL_DEVICE_DISABLED;
>  		return 0;
>  	}
>  
> @@ -173,9 +172,9 @@ static int soc_dts_disable(struct thermal_zone_device *tzd)
>  		if (ret)
>  			return ret;
>  
> -		aux_entry->mode = THERMAL_DEVICE_DISABLED;
> +		tzd->mode = THERMAL_DEVICE_DISABLED;
>  	} else {
> -		aux_entry->mode = THERMAL_DEVICE_ENABLED;
> +		tzd->mode = THERMAL_DEVICE_ENABLED;
>  		pr_info("DTS is locked. Cannot disable DTS\n");
>  		ret = -EPERM;
>  	}
> @@ -309,14 +308,6 @@ static int sys_get_curr_temp(struct thermal_zone_device *tzd,
>  	return 0;
>  }
>  
> -static int sys_get_mode(struct thermal_zone_device *tzd,
> -				enum thermal_device_mode *mode)
> -{
> -	struct soc_sensor_entry *aux_entry = tzd->devdata;
> -	*mode = aux_entry->mode;
> -	return 0;
> -}
> -
>  static int sys_set_mode(struct thermal_zone_device *tzd,
>  				enum thermal_device_mode mode)
>  {
> @@ -338,7 +329,6 @@ static struct thermal_zone_device_ops tzone_ops = {
>  	.get_trip_type = sys_get_trip_type,
>  	.set_trip_temp = sys_set_trip_temp,
>  	.get_crit_temp = sys_get_crit_temp,
> -	.get_mode = sys_get_mode,
>  	.set_mode = sys_set_mode,
>  };

Please take a look at sys_set_mode():

static int sys_set_mode(struct thermal_zone_device *tzd,
				enum thermal_device_mode mode)
{
	int ret;

	mutex_lock(&dts_update_mutex);
	if (mode == THERMAL_DEVICE_ENABLED)
		ret = soc_dts_enable(tzd);
	else
		ret = soc_dts_disable(tzd);
	mutex_unlock(&dts_update_mutex);

	return ret;
}

and alloc_soc_dts():

static struct soc_sensor_entry *alloc_soc_dts(void)
{
...
	aux_entry->tzone = thermal_zone_device_register("quark_dts",
			QRK_MAX_DTS_TRIPS,
			wr_mask,
			aux_entry, &tzone_ops, NULL, 0, polling_delay);
	if (IS_ERR(aux_entry->tzone)) {
		err = PTR_ERR(aux_entry->tzone);
		goto err_ret;
	}

	mutex_lock(&dts_update_mutex);
	err = soc_dts_enable(aux_entry->tzone);
	mutex_unlock(&dts_update_mutex);
	if (err)
		goto err_aux_status;
...
}

Since ->set_mode is now called through thermal_zone_device_register()
the following code should be removed:

	mutex_lock(&dts_update_mutex);
	err = soc_dts_enable(aux_entry->tzone);
	mutex_unlock(&dts_update_mutex);
	if (err)
		goto err_aux_status;

> diff --git a/drivers/thermal/intel/x86_pkg_temp_thermal.c b/drivers/thermal/intel/x86_pkg_temp_thermal.c
> index a006b9fd1d72..cb810a02aab0 100644
> --- a/drivers/thermal/intel/x86_pkg_temp_thermal.c
> +++ b/drivers/thermal/intel/x86_pkg_temp_thermal.c
> @@ -56,6 +56,7 @@ struct zone_device {
>  
>  static struct thermal_zone_params pkg_temp_tz_params = {
>  	.no_hwmon	= true,
> +	.initial_mode	= THERMAL_DEVICE_ENABLED,
>  };
>  
>  /* Keep track of how many zone pointers we allocated in init() */
> diff --git a/drivers/thermal/of-thermal.c b/drivers/thermal/of-thermal.c
> index 874a47d6923f..48787a5576d8 100644
> --- a/drivers/thermal/of-thermal.c
> +++ b/drivers/thermal/of-thermal.c
> @@ -51,7 +51,6 @@ struct __thermal_bind_params {
>  
>  /**
>   * struct __thermal_zone - internal representation of a thermal zone
> - * @mode: current thermal zone device mode (enabled/disabled)
>   * @passive_delay: polling interval while passive cooling is activated
>   * @polling_delay: zone polling interval
>   * @slope: slope of the temperature adjustment curve
> @@ -65,7 +64,6 @@ struct __thermal_bind_params {
>   */
>  
>  struct __thermal_zone {
> -	enum thermal_device_mode mode;
>  	int passive_delay;
>  	int polling_delay;
>  	int slope;
> @@ -269,23 +267,11 @@ static int of_thermal_unbind(struct thermal_zone_device *thermal,
>  	return 0;
>  }
>  
> -static int of_thermal_get_mode(struct thermal_zone_device *tz,
> -			       enum thermal_device_mode *mode)
> -{
> -	struct __thermal_zone *data = tz->devdata;
> -
> -	*mode = data->mode;
> -
> -	return 0;
> -}
> -
>  static int of_thermal_set_mode(struct thermal_zone_device *tz,
>  			       enum thermal_device_mode mode)
>  {
>  	struct __thermal_zone *data = tz->devdata;
>  
> -	mutex_lock(&tz->lock);
> -
>  	if (mode == THERMAL_DEVICE_ENABLED) {
>  		tz->polling_delay = data->polling_delay;
>  		tz->passive_delay = data->passive_delay;
> @@ -294,11 +280,6 @@ static int of_thermal_set_mode(struct thermal_zone_device *tz,
>  		tz->passive_delay = 0;
>  	}
>  
> -	mutex_unlock(&tz->lock);
> -
> -	data->mode = mode;
> -	thermal_zone_device_update(tz, THERMAL_EVENT_UNSPECIFIED);
> -
>  	return 0;
>  }
>  
> @@ -393,7 +374,6 @@ static int of_thermal_get_crit_temp(struct thermal_zone_device *tz,
>  }
>  
>  static struct thermal_zone_device_ops of_thermal_ops = {
> -	.get_mode = of_thermal_get_mode,
>  	.set_mode = of_thermal_set_mode,
>  
>  	.get_trip_type = of_thermal_get_trip_type,
> @@ -554,7 +534,7 @@ thermal_zone_of_sensor_register(struct device *dev, int sensor_id, void *data,
>  			tzd = thermal_zone_of_add_sensor(child, sensor_np,
>  							 data, ops);
>  			if (!IS_ERR(tzd))
> -				tzd->ops->set_mode(tzd, THERMAL_DEVICE_ENABLED);
> +				thermal_zone_device_enable(tzd);
>  
>  			of_node_put(child);
>  			goto exit;
> @@ -979,7 +959,6 @@ __init *thermal_of_build_thermal_zone(struct device_node *np)
>  
>  finish:
>  	of_node_put(child);
> -	tz->mode = THERMAL_DEVICE_DISABLED;
>  
>  	return tz;
>  
> @@ -1120,6 +1099,7 @@ int __init of_parse_thermal_zones(void)
>  		/* these two are left for temperature drivers to use */
>  		tzp->slope = tz->slope;
>  		tzp->offset = tz->offset;
> +		tzp->initial_mode = THERMAL_DEVICE_DISABLED;
>  
>  		zone = thermal_zone_device_register(child->name, tz->ntrips,
>  						    mask, tz,
> diff --git a/drivers/thermal/rockchip_thermal.c b/drivers/thermal/rockchip_thermal.c
> index 15a71ecc916c..aa9e0e31ef98 100644
> --- a/drivers/thermal/rockchip_thermal.c
> +++ b/drivers/thermal/rockchip_thermal.c
> @@ -1068,8 +1068,10 @@ rockchip_thermal_toggle_sensor(struct rockchip_thermal_sensor *sensor, bool on)
>  {
>  	struct thermal_zone_device *tzd = sensor->tzd;
>  
> -	tzd->ops->set_mode(tzd,
> -		on ? THERMAL_DEVICE_ENABLED : THERMAL_DEVICE_DISABLED);
> +	if (on)
> +		thermal_zone_device_enable(tzd);
> +	else
> +		thermal_zone_device_disable(tzd);
>  }
>  
>  static irqreturn_t rockchip_thermal_alarm_irq_thread(int irq, void *dev)
> diff --git a/drivers/thermal/sprd_thermal.c b/drivers/thermal/sprd_thermal.c
> index a340374e8c51..58f995b0f804 100644
> --- a/drivers/thermal/sprd_thermal.c
> +++ b/drivers/thermal/sprd_thermal.c
> @@ -322,8 +322,10 @@ static void sprd_thm_toggle_sensor(struct sprd_thermal_sensor *sen, bool on)
>  {
>  	struct thermal_zone_device *tzd = sen->tzd;
>  
> -	tzd->ops->set_mode(tzd,
> -		on ? THERMAL_DEVICE_ENABLED : THERMAL_DEVICE_DISABLED);
> +	if (on)
> +		thermal_zone_device_enable(tzd);
> +	else
> +		thermal_zone_device_disable(tzd);
>  }
>  
>  static int sprd_thm_probe(struct platform_device *pdev)
> diff --git a/drivers/thermal/thermal_core.c b/drivers/thermal/thermal_core.c
> index c06550930979..a012d77dd602 100644
> --- a/drivers/thermal/thermal_core.c
> +++ b/drivers/thermal/thermal_core.c
> @@ -463,6 +463,44 @@ static void thermal_zone_device_reset(struct thermal_zone_device *tz)
>  	thermal_zone_device_init(tz);
>  }
>  
> +enum thermal_device_mode
> +thermal_zone_device_get_mode(struct thermal_zone_device *tz)
> +{
> +	enum thermal_device_mode mode;
> +
> +	mutex_lock(&tz->lock);
> +
> +	mode = tz->mode;
> +
> +	mutex_unlock(&tz->lock);
> +
> +	return mode;
> +}
> +
> +int thermal_zone_device_set_mode(struct thermal_zone_device *tz,
> +				 enum thermal_device_mode mode)
> +{
> +	int ret = 0;
> +
> +	if (mode != THERMAL_DEVICE_DISABLED &&
> +	    mode != THERMAL_DEVICE_ENABLED)
> +		return -EINVAL;

Please remove above checks, they really are redundant.

> +	mutex_lock(&tz->lock);
> +
> +	if (tz->ops->set_mode)
> +		ret = tz->ops->set_mode(tz, mode);
> +
> +	tz->mode = mode;

This should be:

	if (!ret)
		tz->mode = mode;

as we shouldn't change the mode information if ->set_mode has failed.

> +
> +	mutex_unlock(&tz->lock);
> +
> +	thermal_zone_device_update(tz, THERMAL_EVENT_UNSPECIFIED);
> +
> +	return ret;
> +}
> +EXPORT_SYMBOL_GPL(thermal_zone_device_set_mode);
> +
>  void thermal_zone_device_update(struct thermal_zone_device *tz,
>  				enum thermal_notify_event event)
>  {
> @@ -1236,6 +1274,7 @@ thermal_zone_device_register(const char *type, int trips, int mask,
>  	int result;
>  	int count;
>  	struct thermal_governor *governor;
> +	enum thermal_device_mode mode;
>  
>  	if (!type || strlen(type) == 0) {
>  		pr_err("Error: No thermal zone type defined\n");
> @@ -1340,9 +1379,9 @@ thermal_zone_device_register(const char *type, int trips, int mask,
>  	INIT_DELAYED_WORK(&tz->poll_queue, thermal_zone_device_check);
>  
>  	thermal_zone_device_reset(tz);
> -	/* Update the new thermal zone and mark it as already updated. */
> -	if (atomic_cmpxchg(&tz->need_update, 1, 0))
> -		thermal_zone_device_update(tz, THERMAL_EVENT_UNSPECIFIED);
> +
> +	mode = tzp ? tzp->initial_mode : THERMAL_DEVICE_ENABLED;
> +	thermal_zone_device_set_mode(tz, mode);

The setting of tz->need_update earlier in thermal_zone_device_register():

	/* A new thermal zone needs to be updated anyway. */
	atomic_set(&tz->need_update, 1);

should also be removed now.

Best regards,
--
Bartlomiej Zolnierkiewicz
Samsung R&D Institute Poland
Samsung Electronics

>  
>  	return tz;
>  
> @@ -1473,9 +1512,7 @@ static int thermal_pm_notify(struct notifier_block *nb,
>  	case PM_POST_SUSPEND:
>  		atomic_set(&in_suspend, 0);
>  		list_for_each_entry(tz, &thermal_tz_list, node) {
> -			tz_mode = THERMAL_DEVICE_ENABLED;
> -			if (tz->ops->get_mode)
> -				tz->ops->get_mode(tz, &tz_mode);
> +			tz_mode = thermal_zone_device_get_mode(tz);
>  
>  			if (tz_mode == THERMAL_DEVICE_DISABLED)
>  				continue;
> diff --git a/drivers/thermal/thermal_core.h b/drivers/thermal/thermal_core.h
> index c95689586e19..ff5519adb68a 100644
> --- a/drivers/thermal/thermal_core.h
> +++ b/drivers/thermal/thermal_core.h
> @@ -141,6 +141,9 @@ thermal_cooling_device_stats_update(struct thermal_cooling_device *cdev,
>  				    unsigned long new_state) {}
>  #endif /* CONFIG_THERMAL_STATISTICS */
>  
> +enum thermal_device_mode
> +thermal_zone_device_get_mode(struct thermal_zone_device *tz);
> +
>  /* device tree support */
>  #ifdef CONFIG_THERMAL_OF
>  int of_parse_thermal_zones(void);
> diff --git a/drivers/thermal/thermal_sysfs.c b/drivers/thermal/thermal_sysfs.c
> index aa99edb4dff7..cbb27b3c96d2 100644
> --- a/drivers/thermal/thermal_sysfs.c
> +++ b/drivers/thermal/thermal_sysfs.c
> @@ -50,14 +50,8 @@ mode_show(struct device *dev, struct device_attribute *attr, char *buf)
>  {
>  	struct thermal_zone_device *tz = to_thermal_zone(dev);
>  	enum thermal_device_mode mode;
> -	int result;
> -
> -	if (!tz->ops->get_mode)
> -		return -EPERM;
>  
> -	result = tz->ops->get_mode(tz, &mode);
> -	if (result)
> -		return result;
> +	mode = thermal_zone_device_get_mode(tz);
>  
>  	return sprintf(buf, "%s\n", mode == THERMAL_DEVICE_ENABLED ? "enabled"
>  		       : "disabled");
> @@ -74,9 +68,9 @@ mode_store(struct device *dev, struct device_attribute *attr,
>  		return -EPERM;
>  
>  	if (!strncmp(buf, "enabled", sizeof("enabled") - 1))
> -		result = tz->ops->set_mode(tz, THERMAL_DEVICE_ENABLED);
> +		result = thermal_zone_device_enable(tz);
>  	else if (!strncmp(buf, "disabled", sizeof("disabled") - 1))
> -		result = tz->ops->set_mode(tz, THERMAL_DEVICE_DISABLED);
> +		result = thermal_zone_device_disable(tz);
>  	else
>  		result = -EINVAL;
>  
> @@ -428,30 +422,13 @@ static struct attribute_group thermal_zone_attribute_group = {
>  	.attrs = thermal_zone_dev_attrs,
>  };
>  
> -/* We expose mode only if .get_mode is present */
>  static struct attribute *thermal_zone_mode_attrs[] = {
>  	&dev_attr_mode.attr,
>  	NULL,
>  };
>  
> -static umode_t thermal_zone_mode_is_visible(struct kobject *kobj,
> -					    struct attribute *attr,
> -					    int attrno)
> -{
> -	struct device *dev = container_of(kobj, struct device, kobj);
> -	struct thermal_zone_device *tz;
> -
> -	tz = container_of(dev, struct thermal_zone_device, device);
> -
> -	if (tz->ops->get_mode)
> -		return attr->mode;
> -
> -	return 0;
> -}
> -
>  static struct attribute_group thermal_zone_mode_attribute_group = {
>  	.attrs = thermal_zone_mode_attrs,
> -	.is_visible = thermal_zone_mode_is_visible,
>  };
>  
>  /* We expose passive only if passive trips are present */
> diff --git a/include/linux/thermal.h b/include/linux/thermal.h
> index 216185bb3014..c789d4ff6e63 100644
> --- a/include/linux/thermal.h
> +++ b/include/linux/thermal.h
> @@ -76,8 +76,6 @@ struct thermal_zone_device_ops {
>  		       struct thermal_cooling_device *);
>  	int (*get_temp) (struct thermal_zone_device *, int *);
>  	int (*set_trips) (struct thermal_zone_device *, int, int);
> -	int (*get_mode) (struct thermal_zone_device *,
> -			 enum thermal_device_mode *);
>  	int (*set_mode) (struct thermal_zone_device *,
>  		enum thermal_device_mode);
>  	int (*get_trip_type) (struct thermal_zone_device *, int,
> @@ -128,6 +126,7 @@ struct thermal_cooling_device {
>   * @trip_temp_attrs:	attributes for trip points for sysfs: trip temperature
>   * @trip_type_attrs:	attributes for trip points for sysfs: trip type
>   * @trip_hyst_attrs:	attributes for trip points for sysfs: trip hysteresis
> + * @mode:		current mode of this thermal zone
>   * @devdata:	private pointer for device private data
>   * @trips:	number of trip points the thermal zone supports
>   * @trips_disabled;	bitmap for disabled trips
> @@ -170,6 +169,7 @@ struct thermal_zone_device {
>  	struct thermal_attr *trip_temp_attrs;
>  	struct thermal_attr *trip_type_attrs;
>  	struct thermal_attr *trip_hyst_attrs;
> +	enum thermal_device_mode mode;
>  	void *devdata;
>  	int trips;
>  	unsigned long trips_disabled;	/* bitmap for disabled trips */
> @@ -264,6 +264,9 @@ struct thermal_zone_params {
>  	int num_tbps;	/* Number of tbp entries */
>  	struct thermal_bind_params *tbp;
>  
> +	/* Initial mode of this thermal zone device */
> +	enum thermal_device_mode initial_mode;
> +
>  	/*
>  	 * Sustainable power (heat) that this thermal zone can dissipate in
>  	 * mW
> @@ -395,6 +398,8 @@ int thermal_zone_bind_cooling_device(struct thermal_zone_device *, int,
>  				     unsigned int);
>  int thermal_zone_unbind_cooling_device(struct thermal_zone_device *, int,
>  				       struct thermal_cooling_device *);
> +int thermal_zone_device_set_mode(struct thermal_zone_device *tz,
> +				 enum thermal_device_mode mode);
>  void thermal_zone_device_update(struct thermal_zone_device *,
>  				enum thermal_notify_event);
>  
> @@ -426,6 +431,9 @@ static inline struct thermal_zone_device *thermal_zone_device_register(
>  static inline void thermal_zone_device_unregister(
>  	struct thermal_zone_device *tz)
>  { }
> +int thermal_zone_device_set_mode(struct thermal_zone_device *tz,
> +				 enum thermal_device_mode mode)
> +{ return -EINVAL; }
>  static inline struct thermal_cooling_device *
>  thermal_cooling_device_register(char *type, void *devdata,
>  	const struct thermal_cooling_device_ops *ops)
> @@ -465,4 +473,14 @@ static inline void thermal_notify_framework(struct thermal_zone_device *tz,
>  { }
>  #endif /* CONFIG_THERMAL */
>  
> +static inline int thermal_zone_device_enable(struct thermal_zone_device *tz)
> +{
> +	return thermal_zone_device_set_mode(tz, THERMAL_DEVICE_ENABLED);
> +}
> +
> +static inline int thermal_zone_device_disable(struct thermal_zone_device *tz)
> +{
> +	return thermal_zone_device_set_mode(tz, THERMAL_DEVICE_DISABLED);
> +}
> +
>  #endif /* __THERMAL_H__ */
> 

^ permalink raw reply	[flat|nested] 63+ messages in thread

* [PATCH v3 0/2] Stop monitoring disabled devices
  2020-04-23 14:39                     ` Bartlomiej Zolnierkiewicz
@ 2020-04-23 16:57                       ` Andrzej Pietrasiewicz
  2020-04-23 16:57                         ` [PATCH v3 1/2] thermal: core: Let thermal zone device's mode be stored in its struct Andrzej Pietrasiewicz
  2020-04-23 16:57                         ` [PATCH v3 2/2] thermal: core: Stop polling DISABLED thermal devices Andrzej Pietrasiewicz
  0 siblings, 2 replies; 63+ messages in thread
From: Andrzej Pietrasiewicz @ 2020-04-23 16:57 UTC (permalink / raw)
  To: linux-pm
  Cc: Zhang Rui, Rafael J . Wysocki, Len Brown, Jiri Pirko,
	Ido Schimmel, David S . Miller, Peter Kaestle, Darren Hart,
	Andy Shevchenko, Support Opensource, Daniel Lezcano,
	Amit Kucheria, Shawn Guo, Sascha Hauer, Pengutronix Kernel Team,
	Fabio Estevam, NXP Linux Team, Heiko Stuebner, Orson Zhai,
	Baolin Wang, Chunyan Zhang, linux-acpi, netdev,
	platform-driver-x86, linux-arm-kernel, kernel,
	Andrzej Pietrasiewicz, Barlomiej Zolnierkiewicz

This is the third iteration of this PATCH series (not counting RFCs).
It addresses comments from Bartlomiej - thanks, Bartlomiej!

The first patch makes all the drivers store their mode in struct
thermal_zone_device. Such a move has consequences: driver-specific
variables for storing mode are not necessary. Consequently get_mode()
methods become obsolete. Then sysfs "mode" attribute stops depending
on get_mode() being provided, because it is always provided from now on.

The first patch also introduces the initial mode to be optionally passed
to thermal_zone_device_register().

Given all the groundwork done in patch 1/2 patch 2/2 becomes very simple.

I incorrectly named PATCH v2 a PATCH RESEND 1/2, so now I'm counting that
as PATCH v2, hence this series is PATCH v3.

PATCH v2..PATCH v3:
- removed redundant regmap_write() in imx_thermal_suspend() and
imx_thermal_resume() (Bartlomiej)
- removed unnecessary call to soc_dts_enable() (now called indirectly
from thermal_zone_device_register()->set_mode()) (Bartlomiej)
- removed defensive-style checks for non-existent enum values in
thermal_zone_device_set_mode() (Bartlomiej)
- change mode only if driver's set_mode() succeeded in
thermal_zone_device_set_mode() (Bartlomiej)
- don't set tz->need_update in thermal_zone_device_register() - this
was supposed to be part of PATCH v1, but was omitted (Bartlomiej)

PATCH..PATCH v2:

- fixed typo (missing semicolon in dummy thermal_zone_device_set_mode()
implementation) (kbuild test robot)
- fixed misspelled enum value in int3400_thermal_params.initial_mode

RFCv3..this PATCH:

- export thermal_zone_device_{enable|disable}() for drivers (Bartlomiej)
- don't check provided enum values in acpi's thermal_zet_mode()
and in int3400_thermal_set_mode() (Bartlomiej)
- use thermal_zone_device_enable() in of_thermal instead of open coding it
(Bartlomiej)
- use thermal_zone_device_{enable|disable}() in hisi_thermal, rockchip_thermal
and sprd_thermal (Bartlomiej)
- assume THERMAL_DEVICE_ENABLED is thermal_zone_params not provided at
tzd's register time (Bartlomiej)
- eliminated tzp-s which contain only .initial_mode = THERMAL_DEVICE_ENABLED,
(Bartlomiej)
- don't set tz->need_update and don't call thermal_zone_device_update()
at the end of thermal_zone_device_register() (Bartlomiej)
- used .initial_mode in int340x_thermal_zone, x86_pkg_temp_thermal and
int3400_thermal (Bartlomiej)

Andrzej Pietrasiewicz (2):
  thermal: core: Let thermal zone device's mode be stored in its struct
  thermal: core: Stop polling DISABLED thermal devices

 drivers/acpi/thermal.c                        | 35 ++--------
 .../ethernet/mellanox/mlxsw/core_thermal.c    | 42 ------------
 drivers/platform/x86/acerhdf.c                | 17 +----
 drivers/thermal/da9062-thermal.c              | 11 ----
 drivers/thermal/hisi_thermal.c                |  6 +-
 drivers/thermal/imx_thermal.c                 | 36 ++--------
 .../intel/int340x_thermal/int3400_thermal.c   | 31 ++-------
 .../int340x_thermal/int340x_thermal_zone.c    |  1 +
 .../thermal/intel/intel_quark_dts_thermal.c   | 30 ++-------
 drivers/thermal/intel/x86_pkg_temp_thermal.c  |  1 +
 drivers/thermal/of-thermal.c                  | 24 +------
 drivers/thermal/rockchip_thermal.c            |  6 +-
 drivers/thermal/sprd_thermal.c                |  6 +-
 drivers/thermal/thermal_core.c                | 65 +++++++++++++++----
 drivers/thermal/thermal_core.h                |  3 +
 drivers/thermal/thermal_sysfs.c               | 29 +--------
 include/linux/thermal.h                       | 22 ++++++-
 17 files changed, 119 insertions(+), 246 deletions(-)


base-commit: 79799562bf087b30d9dd0fddf5bed2d3b038be08
-- 
2.17.1


^ permalink raw reply	[flat|nested] 63+ messages in thread

* [PATCH v3 1/2] thermal: core: Let thermal zone device's mode be stored in its struct
  2020-04-23 16:57                       ` [PATCH v3 0/2] Stop monitoring disabled devices Andrzej Pietrasiewicz
@ 2020-04-23 16:57                         ` Andrzej Pietrasiewicz
  2020-05-04  7:00                           ` Bartlomiej Zolnierkiewicz
  2020-04-23 16:57                         ` [PATCH v3 2/2] thermal: core: Stop polling DISABLED thermal devices Andrzej Pietrasiewicz
  1 sibling, 1 reply; 63+ messages in thread
From: Andrzej Pietrasiewicz @ 2020-04-23 16:57 UTC (permalink / raw)
  To: linux-pm
  Cc: Zhang Rui, Rafael J . Wysocki, Len Brown, Jiri Pirko,
	Ido Schimmel, David S . Miller, Peter Kaestle, Darren Hart,
	Andy Shevchenko, Support Opensource, Daniel Lezcano,
	Amit Kucheria, Shawn Guo, Sascha Hauer, Pengutronix Kernel Team,
	Fabio Estevam, NXP Linux Team, Heiko Stuebner, Orson Zhai,
	Baolin Wang, Chunyan Zhang, linux-acpi, netdev,
	platform-driver-x86, linux-arm-kernel, kernel,
	Andrzej Pietrasiewicz, Barlomiej Zolnierkiewicz

Thermal zone devices' mode is stored in individual drivers. This patch
changes it so that mode is stored in struct thermal_zone_device instead.

As a result all driver-specific variables storing the mode are not needed
and are removed. Consequently, the get_mode() implementations have nothing
to operate on and need to be removed, too.

Some thermal framework functions are introduced:

thermal_zone_device_get_mode()
thermal_zone_device_set_mode()
thermal_zone_device_enable()
thermal_zone_device_disable()

thermal_zone_device_get_mode() and its "set" counterpart take tzd's lock
and the "set" calls driver's set_mode() if provided, so the latter must
not take this lock again. At the end of the "set"
thermal_zone_device_update() is called so drivers don't need to repeat this
invocation in their specific set_mode() implementations.

struct thermal_zone_params gains a new member called initial_mode, which
is used to set tzd's mode at registration time and if tzp is not provided
to thermal_zone_device_register() then it is assumed that the initial
mode is THERMAL_DEVICE_ENABLED.

The sysfs "mode" attribute is always exposed from now on, because all
thermal zone devices now have their get_mode() implemented at the generic
level and it is always available. Exposing "mode" doesn't hurt the drivers
which don't provide their own set_mode(), because writing to "mode" will
result in -EPERM, as expected.

Signed-off-by: Andrzej Pietrasiewicz <andrzej.p@collabora.com>
---
 drivers/acpi/thermal.c                        | 35 ++-----------
 .../ethernet/mellanox/mlxsw/core_thermal.c    | 42 ----------------
 drivers/platform/x86/acerhdf.c                | 17 ++-----
 drivers/thermal/da9062-thermal.c              | 11 -----
 drivers/thermal/hisi_thermal.c                |  6 ++-
 drivers/thermal/imx_thermal.c                 | 36 ++------------
 .../intel/int340x_thermal/int3400_thermal.c   | 31 ++----------
 .../int340x_thermal/int340x_thermal_zone.c    |  1 +
 .../thermal/intel/intel_quark_dts_thermal.c   | 30 +++---------
 drivers/thermal/intel/x86_pkg_temp_thermal.c  |  1 +
 drivers/thermal/of-thermal.c                  | 24 +--------
 drivers/thermal/rockchip_thermal.c            |  6 ++-
 drivers/thermal/sprd_thermal.c                |  6 ++-
 drivers/thermal/thermal_core.c                | 49 +++++++++++++++----
 drivers/thermal/thermal_core.h                |  3 ++
 drivers/thermal/thermal_sysfs.c               | 29 ++---------
 include/linux/thermal.h                       | 22 ++++++++-
 17 files changed, 105 insertions(+), 244 deletions(-)

diff --git a/drivers/acpi/thermal.c b/drivers/acpi/thermal.c
index 19067a5e5293..d1f352ed5241 100644
--- a/drivers/acpi/thermal.c
+++ b/drivers/acpi/thermal.c
@@ -172,7 +172,6 @@ struct acpi_thermal {
 	struct acpi_thermal_trips trips;
 	struct acpi_handle_list devices;
 	struct thermal_zone_device *thermal_zone;
-	int tz_enabled;
 	int kelvin_offset;	/* in millidegrees */
 	struct work_struct thermal_check_work;
 };
@@ -500,7 +499,7 @@ static void acpi_thermal_check(void *data)
 {
 	struct acpi_thermal *tz = data;
 
-	if (!tz->tz_enabled)
+	if (tz->thermal_zone->mode != THERMAL_DEVICE_ENABLED)
 		return;
 
 	thermal_zone_device_update(tz->thermal_zone,
@@ -526,25 +525,10 @@ static int thermal_get_temp(struct thermal_zone_device *thermal, int *temp)
 	return 0;
 }
 
-static int thermal_get_mode(struct thermal_zone_device *thermal,
-				enum thermal_device_mode *mode)
-{
-	struct acpi_thermal *tz = thermal->devdata;
-
-	if (!tz)
-		return -EINVAL;
-
-	*mode = tz->tz_enabled ? THERMAL_DEVICE_ENABLED :
-		THERMAL_DEVICE_DISABLED;
-
-	return 0;
-}
-
 static int thermal_set_mode(struct thermal_zone_device *thermal,
 				enum thermal_device_mode mode)
 {
 	struct acpi_thermal *tz = thermal->devdata;
-	int enable;
 
 	if (!tz)
 		return -EINVAL;
@@ -552,20 +536,14 @@ static int thermal_set_mode(struct thermal_zone_device *thermal,
 	/*
 	 * enable/disable thermal management from ACPI thermal driver
 	 */
-	if (mode == THERMAL_DEVICE_ENABLED)
-		enable = 1;
-	else if (mode == THERMAL_DEVICE_DISABLED) {
-		enable = 0;
+	if (mode == THERMAL_DEVICE_DISABLED)
 		pr_warn("thermal zone will be disabled\n");
-	} else
-		return -EINVAL;
 
-	if (enable != tz->tz_enabled) {
-		tz->tz_enabled = enable;
+	if (mode != thermal->mode) {
 		ACPI_DEBUG_PRINT((ACPI_DB_INFO,
 			"%s kernel ACPI thermal control\n",
-			tz->tz_enabled ? "Enable" : "Disable"));
-		acpi_thermal_check(tz);
+			mode == THERMAL_DEVICE_ENABLED ?
+			"Enable" : "Disable"));
 	}
 	return 0;
 }
@@ -856,7 +834,6 @@ static struct thermal_zone_device_ops acpi_thermal_zone_ops = {
 	.bind = acpi_thermal_bind_cooling_device,
 	.unbind	= acpi_thermal_unbind_cooling_device,
 	.get_temp = thermal_get_temp,
-	.get_mode = thermal_get_mode,
 	.set_mode = thermal_set_mode,
 	.get_trip_type = thermal_get_trip_type,
 	.get_trip_temp = thermal_get_trip_temp,
@@ -913,8 +890,6 @@ static int acpi_thermal_register_thermal_zone(struct acpi_thermal *tz)
 	if (ACPI_FAILURE(status))
 		return -ENODEV;
 
-	tz->tz_enabled = 1;
-
 	dev_info(&tz->device->dev, "registered as thermal_zone%d\n",
 		 tz->thermal_zone->id);
 	return 0;
diff --git a/drivers/net/ethernet/mellanox/mlxsw/core_thermal.c b/drivers/net/ethernet/mellanox/mlxsw/core_thermal.c
index ce0a6837daa3..5d28384046da 100644
--- a/drivers/net/ethernet/mellanox/mlxsw/core_thermal.c
+++ b/drivers/net/ethernet/mellanox/mlxsw/core_thermal.c
@@ -98,7 +98,6 @@ struct mlxsw_thermal_module {
 	struct mlxsw_thermal *parent;
 	struct thermal_zone_device *tzdev;
 	struct mlxsw_thermal_trip trips[MLXSW_THERMAL_NUM_TRIPS];
-	enum thermal_device_mode mode;
 	int module; /* Module or gearbox number */
 };
 
@@ -110,7 +109,6 @@ struct mlxsw_thermal {
 	struct thermal_cooling_device *cdevs[MLXSW_MFCR_PWMS_MAX];
 	u8 cooling_levels[MLXSW_THERMAL_MAX_STATE + 1];
 	struct mlxsw_thermal_trip trips[MLXSW_THERMAL_NUM_TRIPS];
-	enum thermal_device_mode mode;
 	struct mlxsw_thermal_module *tz_module_arr;
 	u8 tz_module_num;
 	struct mlxsw_thermal_module *tz_gearbox_arr;
@@ -277,33 +275,16 @@ static int mlxsw_thermal_unbind(struct thermal_zone_device *tzdev,
 	return 0;
 }
 
-static int mlxsw_thermal_get_mode(struct thermal_zone_device *tzdev,
-				  enum thermal_device_mode *mode)
-{
-	struct mlxsw_thermal *thermal = tzdev->devdata;
-
-	*mode = thermal->mode;
-
-	return 0;
-}
-
 static int mlxsw_thermal_set_mode(struct thermal_zone_device *tzdev,
 				  enum thermal_device_mode mode)
 {
 	struct mlxsw_thermal *thermal = tzdev->devdata;
 
-	mutex_lock(&tzdev->lock);
-
 	if (mode == THERMAL_DEVICE_ENABLED)
 		tzdev->polling_delay = thermal->polling_delay;
 	else
 		tzdev->polling_delay = 0;
 
-	mutex_unlock(&tzdev->lock);
-
-	thermal->mode = mode;
-	thermal_zone_device_update(tzdev, THERMAL_EVENT_UNSPECIFIED);
-
 	return 0;
 }
 
@@ -407,7 +388,6 @@ static int mlxsw_thermal_trend_get(struct thermal_zone_device *tzdev,
 static struct thermal_zone_device_ops mlxsw_thermal_ops = {
 	.bind = mlxsw_thermal_bind,
 	.unbind = mlxsw_thermal_unbind,
-	.get_mode = mlxsw_thermal_get_mode,
 	.set_mode = mlxsw_thermal_set_mode,
 	.get_temp = mlxsw_thermal_get_temp,
 	.get_trip_type	= mlxsw_thermal_get_trip_type,
@@ -466,34 +446,17 @@ static int mlxsw_thermal_module_unbind(struct thermal_zone_device *tzdev,
 	return err;
 }
 
-static int mlxsw_thermal_module_mode_get(struct thermal_zone_device *tzdev,
-					 enum thermal_device_mode *mode)
-{
-	struct mlxsw_thermal_module *tz = tzdev->devdata;
-
-	*mode = tz->mode;
-
-	return 0;
-}
-
 static int mlxsw_thermal_module_mode_set(struct thermal_zone_device *tzdev,
 					 enum thermal_device_mode mode)
 {
 	struct mlxsw_thermal_module *tz = tzdev->devdata;
 	struct mlxsw_thermal *thermal = tz->parent;
 
-	mutex_lock(&tzdev->lock);
-
 	if (mode == THERMAL_DEVICE_ENABLED)
 		tzdev->polling_delay = thermal->polling_delay;
 	else
 		tzdev->polling_delay = 0;
 
-	mutex_unlock(&tzdev->lock);
-
-	tz->mode = mode;
-	thermal_zone_device_update(tzdev, THERMAL_EVENT_UNSPECIFIED);
-
 	return 0;
 }
 
@@ -596,7 +559,6 @@ mlxsw_thermal_module_trip_hyst_set(struct thermal_zone_device *tzdev, int trip,
 static struct thermal_zone_device_ops mlxsw_thermal_module_ops = {
 	.bind		= mlxsw_thermal_module_bind,
 	.unbind		= mlxsw_thermal_module_unbind,
-	.get_mode	= mlxsw_thermal_module_mode_get,
 	.set_mode	= mlxsw_thermal_module_mode_set,
 	.get_temp	= mlxsw_thermal_module_temp_get,
 	.get_trip_type	= mlxsw_thermal_module_trip_type_get,
@@ -635,7 +597,6 @@ static int mlxsw_thermal_gearbox_temp_get(struct thermal_zone_device *tzdev,
 static struct thermal_zone_device_ops mlxsw_thermal_gearbox_ops = {
 	.bind		= mlxsw_thermal_module_bind,
 	.unbind		= mlxsw_thermal_module_unbind,
-	.get_mode	= mlxsw_thermal_module_mode_get,
 	.set_mode	= mlxsw_thermal_module_mode_set,
 	.get_temp	= mlxsw_thermal_gearbox_temp_get,
 	.get_trip_type	= mlxsw_thermal_module_trip_type_get,
@@ -765,7 +726,6 @@ mlxsw_thermal_module_tz_init(struct mlxsw_thermal_module *module_tz)
 		return err;
 	}
 
-	module_tz->mode = THERMAL_DEVICE_ENABLED;
 	return 0;
 }
 
@@ -881,7 +841,6 @@ mlxsw_thermal_gearbox_tz_init(struct mlxsw_thermal_module *gearbox_tz)
 	if (IS_ERR(gearbox_tz->tzdev))
 		return PTR_ERR(gearbox_tz->tzdev);
 
-	gearbox_tz->mode = THERMAL_DEVICE_ENABLED;
 	return 0;
 }
 
@@ -1050,7 +1009,6 @@ int mlxsw_thermal_init(struct mlxsw_core *core,
 	if (err)
 		goto err_unreg_modules_tzdev;
 
-	thermal->mode = THERMAL_DEVICE_ENABLED;
 	*p_thermal = thermal;
 	return 0;
 
diff --git a/drivers/platform/x86/acerhdf.c b/drivers/platform/x86/acerhdf.c
index 8cc86f4e3ac1..aaf8b845be90 100644
--- a/drivers/platform/x86/acerhdf.c
+++ b/drivers/platform/x86/acerhdf.c
@@ -406,22 +406,9 @@ static inline void acerhdf_enable_kernelmode(void)
 	kernelmode = 1;
 
 	thz_dev->polling_delay = interval*1000;
-	thermal_zone_device_update(thz_dev, THERMAL_EVENT_UNSPECIFIED);
 	pr_notice("kernel mode fan control ON\n");
 }
 
-static int acerhdf_get_mode(struct thermal_zone_device *thermal,
-			    enum thermal_device_mode *mode)
-{
-	if (verbose)
-		pr_notice("kernel mode fan control %d\n", kernelmode);
-
-	*mode = (kernelmode) ? THERMAL_DEVICE_ENABLED
-			     : THERMAL_DEVICE_DISABLED;
-
-	return 0;
-}
-
 /*
  * set operation mode;
  * enabled: the thermal layer of the kernel takes care about
@@ -488,7 +475,6 @@ static struct thermal_zone_device_ops acerhdf_dev_ops = {
 	.bind = acerhdf_bind,
 	.unbind = acerhdf_unbind,
 	.get_temp = acerhdf_get_ec_temp,
-	.get_mode = acerhdf_get_mode,
 	.set_mode = acerhdf_set_mode,
 	.get_trip_type = acerhdf_get_trip_type,
 	.get_trip_hyst = acerhdf_get_trip_hyst,
@@ -554,6 +540,7 @@ static int acerhdf_set_cur_state(struct thermal_cooling_device *cdev,
 
 err_out:
 	acerhdf_revert_to_bios_mode();
+	thz_dev->mode = THERMAL_DEVICE_DISABLED;
 	return -EINVAL;
 }
 
@@ -739,6 +726,8 @@ static int __init acerhdf_register_thermal(void)
 	if (IS_ERR(cl_dev))
 		return -EINVAL;
 
+	acerhdf_zone_params.initial_mode =
+		kernelmode ? THERMAL_DEVICE_ENABLED : THERMAL_DEVICE_DISABLED;
 	thz_dev = thermal_zone_device_register("acerhdf", 2, 0, NULL,
 					      &acerhdf_dev_ops,
 					      &acerhdf_zone_params, 0,
diff --git a/drivers/thermal/da9062-thermal.c b/drivers/thermal/da9062-thermal.c
index c32709badeda..c3075d038095 100644
--- a/drivers/thermal/da9062-thermal.c
+++ b/drivers/thermal/da9062-thermal.c
@@ -49,7 +49,6 @@ struct da9062_thermal {
 	struct da9062 *hw;
 	struct delayed_work work;
 	struct thermal_zone_device *zone;
-	enum thermal_device_mode mode;
 	struct mutex lock; /* protection for da9062_thermal temperature */
 	int temperature;
 	int irq;
@@ -121,14 +120,6 @@ static irqreturn_t da9062_thermal_irq_handler(int irq, void *data)
 	return IRQ_HANDLED;
 }
 
-static int da9062_thermal_get_mode(struct thermal_zone_device *z,
-				   enum thermal_device_mode *mode)
-{
-	struct da9062_thermal *thermal = z->devdata;
-	*mode = thermal->mode;
-	return 0;
-}
-
 static int da9062_thermal_get_trip_type(struct thermal_zone_device *z,
 					int trip,
 					enum thermal_trip_type *type)
@@ -181,7 +172,6 @@ static int da9062_thermal_get_temp(struct thermal_zone_device *z,
 
 static struct thermal_zone_device_ops da9062_thermal_ops = {
 	.get_temp	= da9062_thermal_get_temp,
-	.get_mode	= da9062_thermal_get_mode,
 	.get_trip_type	= da9062_thermal_get_trip_type,
 	.get_trip_temp	= da9062_thermal_get_trip_temp,
 };
@@ -233,7 +223,6 @@ static int da9062_thermal_probe(struct platform_device *pdev)
 
 	thermal->config = match->data;
 	thermal->hw = chip;
-	thermal->mode = THERMAL_DEVICE_ENABLED;
 	thermal->dev = &pdev->dev;
 
 	INIT_DELAYED_WORK(&thermal->work, da9062_thermal_poll_on);
diff --git a/drivers/thermal/hisi_thermal.c b/drivers/thermal/hisi_thermal.c
index 2d26ae80e202..ee05950afd2f 100644
--- a/drivers/thermal/hisi_thermal.c
+++ b/drivers/thermal/hisi_thermal.c
@@ -549,8 +549,10 @@ static void hisi_thermal_toggle_sensor(struct hisi_thermal_sensor *sensor,
 {
 	struct thermal_zone_device *tzd = sensor->tzd;
 
-	tzd->ops->set_mode(tzd,
-		on ? THERMAL_DEVICE_ENABLED : THERMAL_DEVICE_DISABLED);
+	if (on)
+		thermal_zone_device_enable(tzd);
+	else
+		thermal_zone_device_disable(tzd);
 }
 
 static int hisi_thermal_probe(struct platform_device *pdev)
diff --git a/drivers/thermal/imx_thermal.c b/drivers/thermal/imx_thermal.c
index e761c9b42217..800d2388c440 100644
--- a/drivers/thermal/imx_thermal.c
+++ b/drivers/thermal/imx_thermal.c
@@ -197,7 +197,6 @@ struct imx_thermal_data {
 	struct cpufreq_policy *policy;
 	struct thermal_zone_device *tz;
 	struct thermal_cooling_device *cdev;
-	enum thermal_device_mode mode;
 	struct regmap *tempmon;
 	u32 c1, c2; /* See formula in imx_init_calib() */
 	int temp_passive;
@@ -256,7 +255,7 @@ static int imx_get_temp(struct thermal_zone_device *tz, int *temp)
 	bool wait;
 	u32 val;
 
-	if (data->mode == THERMAL_DEVICE_ENABLED) {
+	if (tz->mode == THERMAL_DEVICE_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 +282,7 @@ static int imx_get_temp(struct thermal_zone_device *tz, int *temp)
 
 	regmap_read(map, soc_data->temp_data, &val);
 
-	if (data->mode != THERMAL_DEVICE_ENABLED) {
+	if (tz->mode != THERMAL_DEVICE_ENABLED) {
 		regmap_write(map, soc_data->sensor_ctrl + REG_CLR,
 			     soc_data->measure_temp_mask);
 		regmap_write(map, soc_data->sensor_ctrl + REG_SET,
@@ -331,16 +330,6 @@ static int imx_get_temp(struct thermal_zone_device *tz, int *temp)
 	return 0;
 }
 
-static int imx_get_mode(struct thermal_zone_device *tz,
-			enum thermal_device_mode *mode)
-{
-	struct imx_thermal_data *data = tz->devdata;
-
-	*mode = data->mode;
-
-	return 0;
-}
-
 static int imx_set_mode(struct thermal_zone_device *tz,
 			enum thermal_device_mode mode)
 {
@@ -376,9 +365,6 @@ static int imx_set_mode(struct thermal_zone_device *tz,
 		}
 	}
 
-	data->mode = mode;
-	thermal_zone_device_update(tz, THERMAL_EVENT_UNSPECIFIED);
-
 	return 0;
 }
 
@@ -467,7 +453,6 @@ static struct thermal_zone_device_ops imx_tz_ops = {
 	.bind = imx_bind,
 	.unbind = imx_unbind,
 	.get_temp = imx_get_temp,
-	.get_mode = imx_get_mode,
 	.set_mode = imx_set_mode,
 	.get_trip_type = imx_get_trip_type,
 	.get_trip_temp = imx_get_trip_temp,
@@ -831,7 +816,6 @@ static int imx_thermal_probe(struct platform_device *pdev)
 		     data->socdata->measure_temp_mask);
 
 	data->irq_enabled = true;
-	data->mode = THERMAL_DEVICE_ENABLED;
 
 	ret = devm_request_threaded_irq(&pdev->dev, data->irq,
 			imx_thermal_alarm_irq, imx_thermal_alarm_irq_thread,
@@ -873,19 +857,14 @@ static int imx_thermal_remove(struct platform_device *pdev)
 static int __maybe_unused imx_thermal_suspend(struct device *dev)
 {
 	struct imx_thermal_data *data = dev_get_drvdata(dev);
-	struct regmap *map = data->tempmon;
 
 	/*
 	 * Need to disable thermal sensor, otherwise, when thermal core
 	 * try to get temperature before thermal sensor resume, a wrong
 	 * temperature will be read as the thermal sensor is powered
-	 * down.
+	 * down. This is done in thermal_zone_device_disable().
 	 */
-	regmap_write(map, data->socdata->sensor_ctrl + REG_CLR,
-		     data->socdata->measure_temp_mask);
-	regmap_write(map, data->socdata->sensor_ctrl + REG_SET,
-		     data->socdata->power_down_mask);
-	data->mode = THERMAL_DEVICE_DISABLED;
+	thermal_zone_device_disable(data->tz);
 	clk_disable_unprepare(data->thermal_clk);
 
 	return 0;
@@ -894,18 +873,13 @@ static int __maybe_unused imx_thermal_suspend(struct device *dev)
 static int __maybe_unused imx_thermal_resume(struct device *dev)
 {
 	struct imx_thermal_data *data = dev_get_drvdata(dev);
-	struct regmap *map = data->tempmon;
 	int ret;
 
 	ret = clk_prepare_enable(data->thermal_clk);
 	if (ret)
 		return ret;
 	/* Enabled thermal sensor after resume */
-	regmap_write(map, data->socdata->sensor_ctrl + REG_CLR,
-		     data->socdata->power_down_mask);
-	regmap_write(map, data->socdata->sensor_ctrl + REG_SET,
-		     data->socdata->measure_temp_mask);
-	data->mode = THERMAL_DEVICE_ENABLED;
+	thermal_zone_device_enable(data->tz);
 
 	return 0;
 }
diff --git a/drivers/thermal/intel/int340x_thermal/int3400_thermal.c b/drivers/thermal/intel/int340x_thermal/int3400_thermal.c
index e802922a13cf..1751d4b103b1 100644
--- a/drivers/thermal/intel/int340x_thermal/int3400_thermal.c
+++ b/drivers/thermal/intel/int340x_thermal/int3400_thermal.c
@@ -44,7 +44,6 @@ static char *int3400_thermal_uuids[INT3400_THERMAL_MAXIMUM_UUID] = {
 struct int3400_thermal_priv {
 	struct acpi_device *adev;
 	struct thermal_zone_device *thermal;
-	int mode;
 	int art_count;
 	struct art *arts;
 	int trt_count;
@@ -230,54 +229,32 @@ static int int3400_thermal_get_temp(struct thermal_zone_device *thermal,
 	return 0;
 }
 
-static int int3400_thermal_get_mode(struct thermal_zone_device *thermal,
-				enum thermal_device_mode *mode)
-{
-	struct int3400_thermal_priv *priv = thermal->devdata;
-
-	if (!priv)
-		return -EINVAL;
-
-	*mode = priv->mode;
-
-	return 0;
-}
-
 static int int3400_thermal_set_mode(struct thermal_zone_device *thermal,
 				enum thermal_device_mode mode)
 {
 	struct int3400_thermal_priv *priv = thermal->devdata;
-	bool enable;
 	int result = 0;
 
 	if (!priv)
 		return -EINVAL;
 
-	if (mode == THERMAL_DEVICE_ENABLED)
-		enable = true;
-	else if (mode == THERMAL_DEVICE_DISABLED)
-		enable = false;
-	else
-		return -EINVAL;
-
-	if (enable != priv->mode) {
-		priv->mode = enable;
+	if (mode != thermal->mode) {
 		result = int3400_thermal_run_osc(priv->adev->handle,
-						 priv->current_uuid_index,
-						 enable);
+						priv->current_uuid_index,
+						mode == THERMAL_DEVICE_ENABLED);
 	}
 	return result;
 }
 
 static struct thermal_zone_device_ops int3400_thermal_ops = {
 	.get_temp = int3400_thermal_get_temp,
-	.get_mode = int3400_thermal_get_mode,
 	.set_mode = int3400_thermal_set_mode,
 };
 
 static struct thermal_zone_params int3400_thermal_params = {
 	.governor_name = "user_space",
 	.no_hwmon = true,
+	.initial_mode = THERMAL_DEVICE_DISABLED,
 };
 
 static int int3400_thermal_probe(struct platform_device *pdev)
diff --git a/drivers/thermal/intel/int340x_thermal/int340x_thermal_zone.c b/drivers/thermal/intel/int340x_thermal/int340x_thermal_zone.c
index 432213272f1e..b36da9bfbf8a 100644
--- a/drivers/thermal/intel/int340x_thermal/int340x_thermal_zone.c
+++ b/drivers/thermal/intel/int340x_thermal/int340x_thermal_zone.c
@@ -208,6 +208,7 @@ EXPORT_SYMBOL_GPL(int340x_thermal_read_trips);
 static struct thermal_zone_params int340x_thermal_params = {
 	.governor_name = "user_space",
 	.no_hwmon = true,
+	.initial_mode = THERMAL_DEVICE_ENABLED,
 };
 
 struct int34x_thermal_zone *int340x_thermal_zone_add(struct acpi_device *adev,
diff --git a/drivers/thermal/intel/intel_quark_dts_thermal.c b/drivers/thermal/intel/intel_quark_dts_thermal.c
index d704fc104cfd..02dabd93f607 100644
--- a/drivers/thermal/intel/intel_quark_dts_thermal.c
+++ b/drivers/thermal/intel/intel_quark_dts_thermal.c
@@ -103,7 +103,6 @@ struct soc_sensor_entry {
 	bool locked;
 	u32 store_ptps;
 	u32 store_dts_enable;
-	enum thermal_device_mode mode;
 	struct thermal_zone_device *tzone;
 };
 
@@ -128,7 +127,7 @@ static int soc_dts_enable(struct thermal_zone_device *tzd)
 		return ret;
 
 	if (out & QRK_DTS_ENABLE_BIT) {
-		aux_entry->mode = THERMAL_DEVICE_ENABLED;
+		tzd->mode = THERMAL_DEVICE_ENABLED;
 		return 0;
 	}
 
@@ -139,9 +138,9 @@ static int soc_dts_enable(struct thermal_zone_device *tzd)
 		if (ret)
 			return ret;
 
-		aux_entry->mode = THERMAL_DEVICE_ENABLED;
+		tzd->mode = THERMAL_DEVICE_ENABLED;
 	} else {
-		aux_entry->mode = THERMAL_DEVICE_DISABLED;
+		tzd->mode = THERMAL_DEVICE_DISABLED;
 		pr_info("DTS is locked. Cannot enable DTS\n");
 		ret = -EPERM;
 	}
@@ -161,7 +160,7 @@ static int soc_dts_disable(struct thermal_zone_device *tzd)
 		return ret;
 
 	if (!(out & QRK_DTS_ENABLE_BIT)) {
-		aux_entry->mode = THERMAL_DEVICE_DISABLED;
+		tzd->mode = THERMAL_DEVICE_DISABLED;
 		return 0;
 	}
 
@@ -173,9 +172,9 @@ static int soc_dts_disable(struct thermal_zone_device *tzd)
 		if (ret)
 			return ret;
 
-		aux_entry->mode = THERMAL_DEVICE_DISABLED;
+		tzd->mode = THERMAL_DEVICE_DISABLED;
 	} else {
-		aux_entry->mode = THERMAL_DEVICE_ENABLED;
+		tzd->mode = THERMAL_DEVICE_ENABLED;
 		pr_info("DTS is locked. Cannot disable DTS\n");
 		ret = -EPERM;
 	}
@@ -309,14 +308,6 @@ static int sys_get_curr_temp(struct thermal_zone_device *tzd,
 	return 0;
 }
 
-static int sys_get_mode(struct thermal_zone_device *tzd,
-				enum thermal_device_mode *mode)
-{
-	struct soc_sensor_entry *aux_entry = tzd->devdata;
-	*mode = aux_entry->mode;
-	return 0;
-}
-
 static int sys_set_mode(struct thermal_zone_device *tzd,
 				enum thermal_device_mode mode)
 {
@@ -338,7 +329,6 @@ static struct thermal_zone_device_ops tzone_ops = {
 	.get_trip_type = sys_get_trip_type,
 	.set_trip_temp = sys_set_trip_temp,
 	.get_crit_temp = sys_get_crit_temp,
-	.get_mode = sys_get_mode,
 	.set_mode = sys_set_mode,
 };
 
@@ -414,16 +404,8 @@ static struct soc_sensor_entry *alloc_soc_dts(void)
 		goto err_ret;
 	}
 
-	mutex_lock(&dts_update_mutex);
-	err = soc_dts_enable(aux_entry->tzone);
-	mutex_unlock(&dts_update_mutex);
-	if (err)
-		goto err_aux_status;
-
 	return aux_entry;
 
-err_aux_status:
-	thermal_zone_device_unregister(aux_entry->tzone);
 err_ret:
 	kfree(aux_entry);
 	return ERR_PTR(err);
diff --git a/drivers/thermal/intel/x86_pkg_temp_thermal.c b/drivers/thermal/intel/x86_pkg_temp_thermal.c
index a006b9fd1d72..cb810a02aab0 100644
--- a/drivers/thermal/intel/x86_pkg_temp_thermal.c
+++ b/drivers/thermal/intel/x86_pkg_temp_thermal.c
@@ -56,6 +56,7 @@ struct zone_device {
 
 static struct thermal_zone_params pkg_temp_tz_params = {
 	.no_hwmon	= true,
+	.initial_mode	= THERMAL_DEVICE_ENABLED,
 };
 
 /* Keep track of how many zone pointers we allocated in init() */
diff --git a/drivers/thermal/of-thermal.c b/drivers/thermal/of-thermal.c
index 874a47d6923f..48787a5576d8 100644
--- a/drivers/thermal/of-thermal.c
+++ b/drivers/thermal/of-thermal.c
@@ -51,7 +51,6 @@ struct __thermal_bind_params {
 
 /**
  * struct __thermal_zone - internal representation of a thermal zone
- * @mode: current thermal zone device mode (enabled/disabled)
  * @passive_delay: polling interval while passive cooling is activated
  * @polling_delay: zone polling interval
  * @slope: slope of the temperature adjustment curve
@@ -65,7 +64,6 @@ struct __thermal_bind_params {
  */
 
 struct __thermal_zone {
-	enum thermal_device_mode mode;
 	int passive_delay;
 	int polling_delay;
 	int slope;
@@ -269,23 +267,11 @@ static int of_thermal_unbind(struct thermal_zone_device *thermal,
 	return 0;
 }
 
-static int of_thermal_get_mode(struct thermal_zone_device *tz,
-			       enum thermal_device_mode *mode)
-{
-	struct __thermal_zone *data = tz->devdata;
-
-	*mode = data->mode;
-
-	return 0;
-}
-
 static int of_thermal_set_mode(struct thermal_zone_device *tz,
 			       enum thermal_device_mode mode)
 {
 	struct __thermal_zone *data = tz->devdata;
 
-	mutex_lock(&tz->lock);
-
 	if (mode == THERMAL_DEVICE_ENABLED) {
 		tz->polling_delay = data->polling_delay;
 		tz->passive_delay = data->passive_delay;
@@ -294,11 +280,6 @@ static int of_thermal_set_mode(struct thermal_zone_device *tz,
 		tz->passive_delay = 0;
 	}
 
-	mutex_unlock(&tz->lock);
-
-	data->mode = mode;
-	thermal_zone_device_update(tz, THERMAL_EVENT_UNSPECIFIED);
-
 	return 0;
 }
 
@@ -393,7 +374,6 @@ static int of_thermal_get_crit_temp(struct thermal_zone_device *tz,
 }
 
 static struct thermal_zone_device_ops of_thermal_ops = {
-	.get_mode = of_thermal_get_mode,
 	.set_mode = of_thermal_set_mode,
 
 	.get_trip_type = of_thermal_get_trip_type,
@@ -554,7 +534,7 @@ thermal_zone_of_sensor_register(struct device *dev, int sensor_id, void *data,
 			tzd = thermal_zone_of_add_sensor(child, sensor_np,
 							 data, ops);
 			if (!IS_ERR(tzd))
-				tzd->ops->set_mode(tzd, THERMAL_DEVICE_ENABLED);
+				thermal_zone_device_enable(tzd);
 
 			of_node_put(child);
 			goto exit;
@@ -979,7 +959,6 @@ __init *thermal_of_build_thermal_zone(struct device_node *np)
 
 finish:
 	of_node_put(child);
-	tz->mode = THERMAL_DEVICE_DISABLED;
 
 	return tz;
 
@@ -1120,6 +1099,7 @@ int __init of_parse_thermal_zones(void)
 		/* these two are left for temperature drivers to use */
 		tzp->slope = tz->slope;
 		tzp->offset = tz->offset;
+		tzp->initial_mode = THERMAL_DEVICE_DISABLED;
 
 		zone = thermal_zone_device_register(child->name, tz->ntrips,
 						    mask, tz,
diff --git a/drivers/thermal/rockchip_thermal.c b/drivers/thermal/rockchip_thermal.c
index 15a71ecc916c..aa9e0e31ef98 100644
--- a/drivers/thermal/rockchip_thermal.c
+++ b/drivers/thermal/rockchip_thermal.c
@@ -1068,8 +1068,10 @@ rockchip_thermal_toggle_sensor(struct rockchip_thermal_sensor *sensor, bool on)
 {
 	struct thermal_zone_device *tzd = sensor->tzd;
 
-	tzd->ops->set_mode(tzd,
-		on ? THERMAL_DEVICE_ENABLED : THERMAL_DEVICE_DISABLED);
+	if (on)
+		thermal_zone_device_enable(tzd);
+	else
+		thermal_zone_device_disable(tzd);
 }
 
 static irqreturn_t rockchip_thermal_alarm_irq_thread(int irq, void *dev)
diff --git a/drivers/thermal/sprd_thermal.c b/drivers/thermal/sprd_thermal.c
index a340374e8c51..58f995b0f804 100644
--- a/drivers/thermal/sprd_thermal.c
+++ b/drivers/thermal/sprd_thermal.c
@@ -322,8 +322,10 @@ static void sprd_thm_toggle_sensor(struct sprd_thermal_sensor *sen, bool on)
 {
 	struct thermal_zone_device *tzd = sen->tzd;
 
-	tzd->ops->set_mode(tzd,
-		on ? THERMAL_DEVICE_ENABLED : THERMAL_DEVICE_DISABLED);
+	if (on)
+		thermal_zone_device_enable(tzd);
+	else
+		thermal_zone_device_disable(tzd);
 }
 
 static int sprd_thm_probe(struct platform_device *pdev)
diff --git a/drivers/thermal/thermal_core.c b/drivers/thermal/thermal_core.c
index c06550930979..a2a5034f76e7 100644
--- a/drivers/thermal/thermal_core.c
+++ b/drivers/thermal/thermal_core.c
@@ -463,6 +463,41 @@ static void thermal_zone_device_reset(struct thermal_zone_device *tz)
 	thermal_zone_device_init(tz);
 }
 
+enum thermal_device_mode
+thermal_zone_device_get_mode(struct thermal_zone_device *tz)
+{
+	enum thermal_device_mode mode;
+
+	mutex_lock(&tz->lock);
+
+	mode = tz->mode;
+
+	mutex_unlock(&tz->lock);
+
+	return mode;
+}
+
+int thermal_zone_device_set_mode(struct thermal_zone_device *tz,
+				 enum thermal_device_mode mode)
+{
+	int ret = 0;
+
+	mutex_lock(&tz->lock);
+
+	if (tz->ops->set_mode)
+		ret = tz->ops->set_mode(tz, mode);
+
+	if (!ret)
+		tz->mode = mode;
+
+	mutex_unlock(&tz->lock);
+
+	thermal_zone_device_update(tz, THERMAL_EVENT_UNSPECIFIED);
+
+	return ret;
+}
+EXPORT_SYMBOL_GPL(thermal_zone_device_set_mode);
+
 void thermal_zone_device_update(struct thermal_zone_device *tz,
 				enum thermal_notify_event event)
 {
@@ -1236,6 +1271,7 @@ thermal_zone_device_register(const char *type, int trips, int mask,
 	int result;
 	int count;
 	struct thermal_governor *governor;
+	enum thermal_device_mode mode;
 
 	if (!type || strlen(type) == 0) {
 		pr_err("Error: No thermal zone type defined\n");
@@ -1290,9 +1326,6 @@ thermal_zone_device_register(const char *type, int trips, int mask,
 	if (result)
 		goto remove_id;
 
-	/* A new thermal zone needs to be updated anyway. */
-	atomic_set(&tz->need_update, 1);
-
 	dev_set_name(&tz->device, "thermal_zone%d", tz->id);
 	result = device_register(&tz->device);
 	if (result)
@@ -1340,9 +1373,9 @@ thermal_zone_device_register(const char *type, int trips, int mask,
 	INIT_DELAYED_WORK(&tz->poll_queue, thermal_zone_device_check);
 
 	thermal_zone_device_reset(tz);
-	/* Update the new thermal zone and mark it as already updated. */
-	if (atomic_cmpxchg(&tz->need_update, 1, 0))
-		thermal_zone_device_update(tz, THERMAL_EVENT_UNSPECIFIED);
+
+	mode = tzp ? tzp->initial_mode : THERMAL_DEVICE_ENABLED;
+	thermal_zone_device_set_mode(tz, mode);
 
 	return tz;
 
@@ -1473,9 +1506,7 @@ static int thermal_pm_notify(struct notifier_block *nb,
 	case PM_POST_SUSPEND:
 		atomic_set(&in_suspend, 0);
 		list_for_each_entry(tz, &thermal_tz_list, node) {
-			tz_mode = THERMAL_DEVICE_ENABLED;
-			if (tz->ops->get_mode)
-				tz->ops->get_mode(tz, &tz_mode);
+			tz_mode = thermal_zone_device_get_mode(tz);
 
 			if (tz_mode == THERMAL_DEVICE_DISABLED)
 				continue;
diff --git a/drivers/thermal/thermal_core.h b/drivers/thermal/thermal_core.h
index c95689586e19..ff5519adb68a 100644
--- a/drivers/thermal/thermal_core.h
+++ b/drivers/thermal/thermal_core.h
@@ -141,6 +141,9 @@ thermal_cooling_device_stats_update(struct thermal_cooling_device *cdev,
 				    unsigned long new_state) {}
 #endif /* CONFIG_THERMAL_STATISTICS */
 
+enum thermal_device_mode
+thermal_zone_device_get_mode(struct thermal_zone_device *tz);
+
 /* device tree support */
 #ifdef CONFIG_THERMAL_OF
 int of_parse_thermal_zones(void);
diff --git a/drivers/thermal/thermal_sysfs.c b/drivers/thermal/thermal_sysfs.c
index aa99edb4dff7..cbb27b3c96d2 100644
--- a/drivers/thermal/thermal_sysfs.c
+++ b/drivers/thermal/thermal_sysfs.c
@@ -50,14 +50,8 @@ mode_show(struct device *dev, struct device_attribute *attr, char *buf)
 {
 	struct thermal_zone_device *tz = to_thermal_zone(dev);
 	enum thermal_device_mode mode;
-	int result;
-
-	if (!tz->ops->get_mode)
-		return -EPERM;
 
-	result = tz->ops->get_mode(tz, &mode);
-	if (result)
-		return result;
+	mode = thermal_zone_device_get_mode(tz);
 
 	return sprintf(buf, "%s\n", mode == THERMAL_DEVICE_ENABLED ? "enabled"
 		       : "disabled");
@@ -74,9 +68,9 @@ mode_store(struct device *dev, struct device_attribute *attr,
 		return -EPERM;
 
 	if (!strncmp(buf, "enabled", sizeof("enabled") - 1))
-		result = tz->ops->set_mode(tz, THERMAL_DEVICE_ENABLED);
+		result = thermal_zone_device_enable(tz);
 	else if (!strncmp(buf, "disabled", sizeof("disabled") - 1))
-		result = tz->ops->set_mode(tz, THERMAL_DEVICE_DISABLED);
+		result = thermal_zone_device_disable(tz);
 	else
 		result = -EINVAL;
 
@@ -428,30 +422,13 @@ static struct attribute_group thermal_zone_attribute_group = {
 	.attrs = thermal_zone_dev_attrs,
 };
 
-/* We expose mode only if .get_mode is present */
 static struct attribute *thermal_zone_mode_attrs[] = {
 	&dev_attr_mode.attr,
 	NULL,
 };
 
-static umode_t thermal_zone_mode_is_visible(struct kobject *kobj,
-					    struct attribute *attr,
-					    int attrno)
-{
-	struct device *dev = container_of(kobj, struct device, kobj);
-	struct thermal_zone_device *tz;
-
-	tz = container_of(dev, struct thermal_zone_device, device);
-
-	if (tz->ops->get_mode)
-		return attr->mode;
-
-	return 0;
-}
-
 static struct attribute_group thermal_zone_mode_attribute_group = {
 	.attrs = thermal_zone_mode_attrs,
-	.is_visible = thermal_zone_mode_is_visible,
 };
 
 /* We expose passive only if passive trips are present */
diff --git a/include/linux/thermal.h b/include/linux/thermal.h
index 216185bb3014..c789d4ff6e63 100644
--- a/include/linux/thermal.h
+++ b/include/linux/thermal.h
@@ -76,8 +76,6 @@ struct thermal_zone_device_ops {
 		       struct thermal_cooling_device *);
 	int (*get_temp) (struct thermal_zone_device *, int *);
 	int (*set_trips) (struct thermal_zone_device *, int, int);
-	int (*get_mode) (struct thermal_zone_device *,
-			 enum thermal_device_mode *);
 	int (*set_mode) (struct thermal_zone_device *,
 		enum thermal_device_mode);
 	int (*get_trip_type) (struct thermal_zone_device *, int,
@@ -128,6 +126,7 @@ struct thermal_cooling_device {
  * @trip_temp_attrs:	attributes for trip points for sysfs: trip temperature
  * @trip_type_attrs:	attributes for trip points for sysfs: trip type
  * @trip_hyst_attrs:	attributes for trip points for sysfs: trip hysteresis
+ * @mode:		current mode of this thermal zone
  * @devdata:	private pointer for device private data
  * @trips:	number of trip points the thermal zone supports
  * @trips_disabled;	bitmap for disabled trips
@@ -170,6 +169,7 @@ struct thermal_zone_device {
 	struct thermal_attr *trip_temp_attrs;
 	struct thermal_attr *trip_type_attrs;
 	struct thermal_attr *trip_hyst_attrs;
+	enum thermal_device_mode mode;
 	void *devdata;
 	int trips;
 	unsigned long trips_disabled;	/* bitmap for disabled trips */
@@ -264,6 +264,9 @@ struct thermal_zone_params {
 	int num_tbps;	/* Number of tbp entries */
 	struct thermal_bind_params *tbp;
 
+	/* Initial mode of this thermal zone device */
+	enum thermal_device_mode initial_mode;
+
 	/*
 	 * Sustainable power (heat) that this thermal zone can dissipate in
 	 * mW
@@ -395,6 +398,8 @@ int thermal_zone_bind_cooling_device(struct thermal_zone_device *, int,
 				     unsigned int);
 int thermal_zone_unbind_cooling_device(struct thermal_zone_device *, int,
 				       struct thermal_cooling_device *);
+int thermal_zone_device_set_mode(struct thermal_zone_device *tz,
+				 enum thermal_device_mode mode);
 void thermal_zone_device_update(struct thermal_zone_device *,
 				enum thermal_notify_event);
 
@@ -426,6 +431,9 @@ static inline struct thermal_zone_device *thermal_zone_device_register(
 static inline void thermal_zone_device_unregister(
 	struct thermal_zone_device *tz)
 { }
+int thermal_zone_device_set_mode(struct thermal_zone_device *tz,
+				 enum thermal_device_mode mode)
+{ return -EINVAL; }
 static inline struct thermal_cooling_device *
 thermal_cooling_device_register(char *type, void *devdata,
 	const struct thermal_cooling_device_ops *ops)
@@ -465,4 +473,14 @@ static inline void thermal_notify_framework(struct thermal_zone_device *tz,
 { }
 #endif /* CONFIG_THERMAL */
 
+static inline int thermal_zone_device_enable(struct thermal_zone_device *tz)
+{
+	return thermal_zone_device_set_mode(tz, THERMAL_DEVICE_ENABLED);
+}
+
+static inline int thermal_zone_device_disable(struct thermal_zone_device *tz)
+{
+	return thermal_zone_device_set_mode(tz, THERMAL_DEVICE_DISABLED);
+}
+
 #endif /* __THERMAL_H__ */
-- 
2.17.1


^ permalink raw reply	[flat|nested] 63+ messages in thread

* [PATCH v3 2/2] thermal: core: Stop polling DISABLED thermal devices
  2020-04-23 16:57                       ` [PATCH v3 0/2] Stop monitoring disabled devices Andrzej Pietrasiewicz
  2020-04-23 16:57                         ` [PATCH v3 1/2] thermal: core: Let thermal zone device's mode be stored in its struct Andrzej Pietrasiewicz
@ 2020-04-23 16:57                         ` Andrzej Pietrasiewicz
  2020-04-24  9:03                           ` Zhang, Rui
  1 sibling, 1 reply; 63+ messages in thread
From: Andrzej Pietrasiewicz @ 2020-04-23 16:57 UTC (permalink / raw)
  To: linux-pm
  Cc: Zhang Rui, Rafael J . Wysocki, Len Brown, Jiri Pirko,
	Ido Schimmel, David S . Miller, Peter Kaestle, Darren Hart,
	Andy Shevchenko, Support Opensource, Daniel Lezcano,
	Amit Kucheria, Shawn Guo, Sascha Hauer, Pengutronix Kernel Team,
	Fabio Estevam, NXP Linux Team, Heiko Stuebner, Orson Zhai,
	Baolin Wang, Chunyan Zhang, linux-acpi, netdev,
	platform-driver-x86, linux-arm-kernel, kernel,
	Andrzej Pietrasiewicz, Barlomiej Zolnierkiewicz

Polling DISABLED devices is not desired, as all such "disabled" devices
are meant to be handled by userspace. This patch introduces and uses
should_stop_polling() to decide whether the device should be polled or not.

Signed-off-by: Andrzej Pietrasiewicz <andrzej.p@collabora.com>
---
 drivers/thermal/thermal_core.c | 16 ++++++++++++++--
 1 file changed, 14 insertions(+), 2 deletions(-)

diff --git a/drivers/thermal/thermal_core.c b/drivers/thermal/thermal_core.c
index a2a5034f76e7..03c4d8d23284 100644
--- a/drivers/thermal/thermal_core.c
+++ b/drivers/thermal/thermal_core.c
@@ -305,13 +305,22 @@ static void thermal_zone_device_set_polling(struct thermal_zone_device *tz,
 		cancel_delayed_work(&tz->poll_queue);
 }
 
+static inline bool should_stop_polling(struct thermal_zone_device *tz)
+{
+	return thermal_zone_device_get_mode(tz) == THERMAL_DEVICE_DISABLED;
+}
+
 static void monitor_thermal_zone(struct thermal_zone_device *tz)
 {
+	bool stop;
+
+	stop = should_stop_polling(tz);
+
 	mutex_lock(&tz->lock);
 
-	if (tz->passive)
+	if (!stop && tz->passive)
 		thermal_zone_device_set_polling(tz, tz->passive_delay);
-	else if (tz->polling_delay)
+	else if (!stop && tz->polling_delay)
 		thermal_zone_device_set_polling(tz, tz->polling_delay);
 	else
 		thermal_zone_device_set_polling(tz, 0);
@@ -503,6 +512,9 @@ void thermal_zone_device_update(struct thermal_zone_device *tz,
 {
 	int count;
 
+	if (should_stop_polling(tz))
+		return;
+
 	if (atomic_read(&in_suspend))
 		return;
 
-- 
2.17.1


^ permalink raw reply	[flat|nested] 63+ messages in thread

* RE: [PATCH v3 2/2] thermal: core: Stop polling DISABLED thermal devices
  2020-04-23 16:57                         ` [PATCH v3 2/2] thermal: core: Stop polling DISABLED thermal devices Andrzej Pietrasiewicz
@ 2020-04-24  9:03                           ` Zhang, Rui
  2020-04-27 14:20                             ` Zhang, Rui
  0 siblings, 1 reply; 63+ messages in thread
From: Zhang, Rui @ 2020-04-24  9:03 UTC (permalink / raw)
  To: Andrzej Pietrasiewicz, linux-pm
  Cc: Rafael J . Wysocki, Len Brown, Jiri Pirko, Ido Schimmel,
	David S . Miller, Peter Kaestle, Darren Hart, Andy Shevchenko,
	Support Opensource, Daniel Lezcano, Amit Kucheria, Shawn Guo,
	Sascha Hauer, Pengutronix Kernel Team, Fabio Estevam,
	NXP Linux Team, Heiko Stuebner, Orson Zhai, Baolin Wang,
	Chunyan Zhang, linux-acpi, netdev, platform-driver-x86,
	linux-arm-kernel, kernel, Barlomiej Zolnierkiewicz

Hi, Andrzej,

Thanks for the patches. My Linux laptop was broken and won't get fixed till next
week, so I may lost some of the discussions previously.

> -----Original Message-----
> From: Andrzej Pietrasiewicz <andrzej.p@collabora.com>
> Sent: Friday, April 24, 2020 12:57 AM
> To: linux-pm@vger.kernel.org
> Cc: Zhang, Rui <rui.zhang@intel.com>; Rafael J . Wysocki
> <rjw@rjwysocki.net>; Len Brown <lenb@kernel.org>; Jiri Pirko
> <jiri@mellanox.com>; Ido Schimmel <idosch@mellanox.com>; David S .
> Miller <davem@davemloft.net>; Peter Kaestle <peter@piie.net>; Darren
> Hart <dvhart@infradead.org>; Andy Shevchenko <andy@infradead.org>;
> Support Opensource <support.opensource@diasemi.com>; Daniel Lezcano
> <daniel.lezcano@linaro.org>; Amit Kucheria
> <amit.kucheria@verdurent.com>; Shawn Guo <shawnguo@kernel.org>;
> Sascha Hauer <s.hauer@pengutronix.de>; Pengutronix Kernel Team
> <kernel@pengutronix.de>; Fabio Estevam <festevam@gmail.com>; NXP
> Linux Team <linux-imx@nxp.com>; Heiko Stuebner <heiko@sntech.de>;
> Orson Zhai <orsonzhai@gmail.com>; Baolin Wang
> <baolin.wang7@gmail.com>; Chunyan Zhang <zhang.lyra@gmail.com>; linux-
> acpi@vger.kernel.org; netdev@vger.kernel.org; platform-driver-
> x86@vger.kernel.org; linux-arm-kernel@lists.infradead.org;
> kernel@collabora.com; Andrzej Pietrasiewicz <andrzej.p@collabora.com>;
> Barlomiej Zolnierkiewicz <b.zolnierkie@samsung.com>
> Subject: [PATCH v3 2/2] thermal: core: Stop polling DISABLED thermal devices
> Importance: High
> 
> Polling DISABLED devices is not desired, as all such "disabled" devices are
> meant to be handled by userspace. This patch introduces and uses
> should_stop_polling() to decide whether the device should be polled or not.
> 
Thanks for the fix, and IMO, this reveal some more problems.
Say, we need to define "DISABLED" thermal zone.
Can we read the temperature? Can we trust the trip point value?

IMO, a disabled thermal zone does not mean it is handled by userspace, because
that is what the userspace governor designed for.
Instead, if a thermal zone is disabled, in thermal_zone_device_update(), we should
basically skip all the other operations as well.

I'll try your patches and probably make an incremental patch.

Thanks,
rui

> Signed-off-by: Andrzej Pietrasiewicz <andrzej.p@collabora.com>
> ---
>  drivers/thermal/thermal_core.c | 16 ++++++++++++++--
>  1 file changed, 14 insertions(+), 2 deletions(-)
> 
> diff --git a/drivers/thermal/thermal_core.c
> b/drivers/thermal/thermal_core.c index a2a5034f76e7..03c4d8d23284 100644
> --- a/drivers/thermal/thermal_core.c
> +++ b/drivers/thermal/thermal_core.c
> @@ -305,13 +305,22 @@ static void thermal_zone_device_set_polling(struct
> thermal_zone_device *tz,
>  		cancel_delayed_work(&tz->poll_queue);
>  }
> 
> +static inline bool should_stop_polling(struct thermal_zone_device *tz)
> +{
> +	return thermal_zone_device_get_mode(tz) ==
> THERMAL_DEVICE_DISABLED; }
> +
>  static void monitor_thermal_zone(struct thermal_zone_device *tz)  {
> +	bool stop;
> +
> +	stop = should_stop_polling(tz);
> +
>  	mutex_lock(&tz->lock);
> 
> -	if (tz->passive)
> +	if (!stop && tz->passive)
>  		thermal_zone_device_set_polling(tz, tz->passive_delay);
> -	else if (tz->polling_delay)
> +	else if (!stop && tz->polling_delay)
>  		thermal_zone_device_set_polling(tz, tz->polling_delay);
>  	else
>  		thermal_zone_device_set_polling(tz, 0); @@ -503,6 +512,9
> @@ void thermal_zone_device_update(struct thermal_zone_device *tz,  {
>  	int count;
> 
> +	if (should_stop_polling(tz))
> +		return;
> +
>  	if (atomic_read(&in_suspend))
>  		return;
> 
> --
> 2.17.1


^ permalink raw reply	[flat|nested] 63+ messages in thread

* RE: [PATCH v3 2/2] thermal: core: Stop polling DISABLED thermal devices
  2020-04-24  9:03                           ` Zhang, Rui
@ 2020-04-27 14:20                             ` Zhang, Rui
  2020-04-27 18:34                               ` Andrzej Pietrasiewicz
  0 siblings, 1 reply; 63+ messages in thread
From: Zhang, Rui @ 2020-04-27 14:20 UTC (permalink / raw)
  To: 'Andrzej Pietrasiewicz', 'linux-pm@vger.kernel.org'
  Cc: 'Rafael J . Wysocki', 'Len Brown',
	'Jiri Pirko', 'Ido Schimmel',
	'David S . Miller', 'Peter Kaestle',
	'Darren Hart', 'Andy Shevchenko',
	'Support Opensource', 'Daniel Lezcano',
	'Amit Kucheria', 'Shawn Guo',
	'Sascha Hauer', 'Pengutronix Kernel Team',
	'Fabio Estevam', 'NXP Linux Team',
	'Heiko Stuebner', 'Orson Zhai',
	'Baolin Wang', 'Chunyan Zhang',
	'linux-acpi@vger.kernel.org',
	'netdev@vger.kernel.org',
	'platform-driver-x86@vger.kernel.org',
	'linux-arm-kernel@lists.infradead.org',
	'kernel@collabora.com',
	'Barlomiej Zolnierkiewicz'



> -----Original Message-----
> From: Zhang, Rui
> Sent: Friday, April 24, 2020 5:03 PM
> To: Andrzej Pietrasiewicz <andrzej.p@collabora.com>; linux-
> pm@vger.kernel.org
> Cc: Rafael J . Wysocki <rjw@rjwysocki.net>; Len Brown <lenb@kernel.org>;
> Jiri Pirko <jiri@mellanox.com>; Ido Schimmel <idosch@mellanox.com>; David
> S . Miller <davem@davemloft.net>; Peter Kaestle <peter@piie.net>; Darren
> Hart <dvhart@infradead.org>; Andy Shevchenko <andy@infradead.org>;
> Support Opensource <support.opensource@diasemi.com>; Daniel Lezcano
> <daniel.lezcano@linaro.org>; Amit Kucheria
> <amit.kucheria@verdurent.com>; Shawn Guo <shawnguo@kernel.org>;
> Sascha Hauer <s.hauer@pengutronix.de>; Pengutronix Kernel Team
> <kernel@pengutronix.de>; Fabio Estevam <festevam@gmail.com>; NXP
> Linux Team <linux-imx@nxp.com>; Heiko Stuebner <heiko@sntech.de>;
> Orson Zhai <orsonzhai@gmail.com>; Baolin Wang
> <baolin.wang7@gmail.com>; Chunyan Zhang <zhang.lyra@gmail.com>; linux-
> acpi@vger.kernel.org; netdev@vger.kernel.org; platform-driver-
> x86@vger.kernel.org; linux-arm-kernel@lists.infradead.org;
> kernel@collabora.com; Barlomiej Zolnierkiewicz <b.zolnierkie@samsung.com>
> Subject: RE: [PATCH v3 2/2] thermal: core: Stop polling DISABLED thermal
> devices
> 
> Hi, Andrzej,
> 
> Thanks for the patches. My Linux laptop was broken and won't get fixed till
> next week, so I may lost some of the discussions previously.
> 
> > -----Original Message-----
> > From: Andrzej Pietrasiewicz <andrzej.p@collabora.com>
> > Sent: Friday, April 24, 2020 12:57 AM
> > To: linux-pm@vger.kernel.org
> > Cc: Zhang, Rui <rui.zhang@intel.com>; Rafael J . Wysocki
> > <rjw@rjwysocki.net>; Len Brown <lenb@kernel.org>; Jiri Pirko
> > <jiri@mellanox.com>; Ido Schimmel <idosch@mellanox.com>; David S .
> > Miller <davem@davemloft.net>; Peter Kaestle <peter@piie.net>; Darren
> > Hart <dvhart@infradead.org>; Andy Shevchenko <andy@infradead.org>;
> > Support Opensource <support.opensource@diasemi.com>; Daniel Lezcano
> > <daniel.lezcano@linaro.org>; Amit Kucheria
> > <amit.kucheria@verdurent.com>; Shawn Guo <shawnguo@kernel.org>;
> Sascha
> > Hauer <s.hauer@pengutronix.de>; Pengutronix Kernel Team
> > <kernel@pengutronix.de>; Fabio Estevam <festevam@gmail.com>; NXP
> Linux
> > Team <linux-imx@nxp.com>; Heiko Stuebner <heiko@sntech.de>; Orson
> Zhai
> > <orsonzhai@gmail.com>; Baolin Wang <baolin.wang7@gmail.com>;
> Chunyan
> > Zhang <zhang.lyra@gmail.com>; linux- acpi@vger.kernel.org;
> > netdev@vger.kernel.org; platform-driver- x86@vger.kernel.org;
> > linux-arm-kernel@lists.infradead.org;
> > kernel@collabora.com; Andrzej Pietrasiewicz <andrzej.p@collabora.com>;
> > Barlomiej Zolnierkiewicz <b.zolnierkie@samsung.com>
> > Subject: [PATCH v3 2/2] thermal: core: Stop polling DISABLED thermal
> > devices
> > Importance: High
> >
> > Polling DISABLED devices is not desired, as all such "disabled"
> > devices are meant to be handled by userspace. This patch introduces
> > and uses
> > should_stop_polling() to decide whether the device should be polled or
> not.
> >
> Thanks for the fix, and IMO, this reveal some more problems.
> Say, we need to define "DISABLED" thermal zone.
> Can we read the temperature? Can we trust the trip point value?
> 
> IMO, a disabled thermal zone does not mean it is handled by userspace,
> because that is what the userspace governor designed for.
> Instead, if a thermal zone is disabled, in thermal_zone_device_update(), we
> should basically skip all the other operations as well.
> 
I overlooked the last line of the patch. So thermal_zone_device_update() returns
immediately if the thermal zone is disabled, right?

But how can we stop polling in this case?
There is no chance to call into monitor_thermal_zone() in thermal_zone_device_update(),
or do I miss something?

> I'll try your patches and probably make an incremental patch.

I have finished a small patch set to improve this based on my understanding, and will post it
tomorrow after testing.

Thanks,
rui
> 
> Thanks,
> rui
> 
> > Signed-off-by: Andrzej Pietrasiewicz <andrzej.p@collabora.com>
> > ---
> >  drivers/thermal/thermal_core.c | 16 ++++++++++++++--
> >  1 file changed, 14 insertions(+), 2 deletions(-)
> >
> > diff --git a/drivers/thermal/thermal_core.c
> > b/drivers/thermal/thermal_core.c index a2a5034f76e7..03c4d8d23284
> > 100644
> > --- a/drivers/thermal/thermal_core.c
> > +++ b/drivers/thermal/thermal_core.c
> > @@ -305,13 +305,22 @@ static void
> > thermal_zone_device_set_polling(struct
> > thermal_zone_device *tz,
> >  		cancel_delayed_work(&tz->poll_queue);
> >  }
> >
> > +static inline bool should_stop_polling(struct thermal_zone_device
> > +*tz) {
> > +	return thermal_zone_device_get_mode(tz) ==
> > THERMAL_DEVICE_DISABLED; }
> > +
> >  static void monitor_thermal_zone(struct thermal_zone_device *tz)  {
> > +	bool stop;
> > +
> > +	stop = should_stop_polling(tz);
> > +
> >  	mutex_lock(&tz->lock);
> >
> > -	if (tz->passive)
> > +	if (!stop && tz->passive)
> >  		thermal_zone_device_set_polling(tz, tz->passive_delay);
> > -	else if (tz->polling_delay)
> > +	else if (!stop && tz->polling_delay)
> >  		thermal_zone_device_set_polling(tz, tz->polling_delay);
> >  	else
> >  		thermal_zone_device_set_polling(tz, 0); @@ -503,6 +512,9
> @@ void
> > thermal_zone_device_update(struct thermal_zone_device *tz,  {
> >  	int count;
> >
> > +	if (should_stop_polling(tz))
> > +		return;
> > +
> >  	if (atomic_read(&in_suspend))
> >  		return;
> >
> > --
> > 2.17.1


^ permalink raw reply	[flat|nested] 63+ messages in thread

* Re: [PATCH v3 2/2] thermal: core: Stop polling DISABLED thermal devices
  2020-04-27 14:20                             ` Zhang, Rui
@ 2020-04-27 18:34                               ` Andrzej Pietrasiewicz
  2020-04-28 13:55                                 ` Zhang, Rui
  0 siblings, 1 reply; 63+ messages in thread
From: Andrzej Pietrasiewicz @ 2020-04-27 18:34 UTC (permalink / raw)
  To: Zhang, Rui, 'linux-pm@vger.kernel.org'
  Cc: 'Rafael J . Wysocki', 'Len Brown',
	'Jiri Pirko', 'Ido Schimmel',
	'David S . Miller', 'Peter Kaestle',
	'Darren Hart', 'Andy Shevchenko',
	'Support Opensource', 'Daniel Lezcano',
	'Amit Kucheria', 'Shawn Guo',
	'Sascha Hauer', 'Pengutronix Kernel Team',
	'Fabio Estevam', 'NXP Linux Team',
	'Heiko Stuebner', 'Orson Zhai',
	'Baolin Wang', 'Chunyan Zhang',
	'linux-acpi@vger.kernel.org',
	'netdev@vger.kernel.org',
	'platform-driver-x86@vger.kernel.org',
	'linux-arm-kernel@lists.infradead.org',
	'kernel@collabora.com',
	'Barlomiej Zolnierkiewicz'

Hi,

W dniu 27.04.2020 o 16:20, Zhang, Rui pisze:
> 
> 
>> -----Original Message-----
>> From: Zhang, Rui
>> Sent: Friday, April 24, 2020 5:03 PM
>> To: Andrzej Pietrasiewicz <andrzej.p@collabora.com>; linux-
>> pm@vger.kernel.org
>> Cc: Rafael J . Wysocki <rjw@rjwysocki.net>; Len Brown <lenb@kernel.org>;
>> Jiri Pirko <jiri@mellanox.com>; Ido Schimmel <idosch@mellanox.com>; David
>> S . Miller <davem@davemloft.net>; Peter Kaestle <peter@piie.net>; Darren
>> Hart <dvhart@infradead.org>; Andy Shevchenko <andy@infradead.org>;
>> Support Opensource <support.opensource@diasemi.com>; Daniel Lezcano
>> <daniel.lezcano@linaro.org>; Amit Kucheria
>> <amit.kucheria@verdurent.com>; Shawn Guo <shawnguo@kernel.org>;
>> Sascha Hauer <s.hauer@pengutronix.de>; Pengutronix Kernel Team
>> <kernel@pengutronix.de>; Fabio Estevam <festevam@gmail.com>; NXP
>> Linux Team <linux-imx@nxp.com>; Heiko Stuebner <heiko@sntech.de>;
>> Orson Zhai <orsonzhai@gmail.com>; Baolin Wang
>> <baolin.wang7@gmail.com>; Chunyan Zhang <zhang.lyra@gmail.com>; linux-
>> acpi@vger.kernel.org; netdev@vger.kernel.org; platform-driver-
>> x86@vger.kernel.org; linux-arm-kernel@lists.infradead.org;
>> kernel@collabora.com; Barlomiej Zolnierkiewicz <b.zolnierkie@samsung.com>
>> Subject: RE: [PATCH v3 2/2] thermal: core: Stop polling DISABLED thermal
>> devices
>>
>> Hi, Andrzej,
>>
>> Thanks for the patches. My Linux laptop was broken and won't get fixed till
>> next week, so I may lost some of the discussions previously.
>>
>>> -----Original Message-----
>>> From: Andrzej Pietrasiewicz <andrzej.p@collabora.com>
>>> Sent: Friday, April 24, 2020 12:57 AM
>>> To: linux-pm@vger.kernel.org
>>> Cc: Zhang, Rui <rui.zhang@intel.com>; Rafael J . Wysocki
>>> <rjw@rjwysocki.net>; Len Brown <lenb@kernel.org>; Jiri Pirko
>>> <jiri@mellanox.com>; Ido Schimmel <idosch@mellanox.com>; David S .
>>> Miller <davem@davemloft.net>; Peter Kaestle <peter@piie.net>; Darren
>>> Hart <dvhart@infradead.org>; Andy Shevchenko <andy@infradead.org>;
>>> Support Opensource <support.opensource@diasemi.com>; Daniel Lezcano
>>> <daniel.lezcano@linaro.org>; Amit Kucheria
>>> <amit.kucheria@verdurent.com>; Shawn Guo <shawnguo@kernel.org>;
>> Sascha
>>> Hauer <s.hauer@pengutronix.de>; Pengutronix Kernel Team
>>> <kernel@pengutronix.de>; Fabio Estevam <festevam@gmail.com>; NXP
>> Linux
>>> Team <linux-imx@nxp.com>; Heiko Stuebner <heiko@sntech.de>; Orson
>> Zhai
>>> <orsonzhai@gmail.com>; Baolin Wang <baolin.wang7@gmail.com>;
>> Chunyan
>>> Zhang <zhang.lyra@gmail.com>; linux- acpi@vger.kernel.org;
>>> netdev@vger.kernel.org; platform-driver- x86@vger.kernel.org;
>>> linux-arm-kernel@lists.infradead.org;
>>> kernel@collabora.com; Andrzej Pietrasiewicz <andrzej.p@collabora.com>;
>>> Barlomiej Zolnierkiewicz <b.zolnierkie@samsung.com>
>>> Subject: [PATCH v3 2/2] thermal: core: Stop polling DISABLED thermal
>>> devices
>>> Importance: High
>>>
>>> Polling DISABLED devices is not desired, as all such "disabled"
>>> devices are meant to be handled by userspace. This patch introduces
>>> and uses
>>> should_stop_polling() to decide whether the device should be polled or
>> not.
>>>
>> Thanks for the fix, and IMO, this reveal some more problems.
>> Say, we need to define "DISABLED" thermal zone.
>> Can we read the temperature? Can we trust the trip point value?
>>
>> IMO, a disabled thermal zone does not mean it is handled by userspace,
>> because that is what the userspace governor designed for.
>> Instead, if a thermal zone is disabled, in thermal_zone_device_update(), we
>> should basically skip all the other operations as well.
>>
> I overlooked the last line of the patch. So thermal_zone_device_update() returns
> immediately if the thermal zone is disabled, right?
> 
> But how can we stop polling in this case?

It does stop. However, I indeed observe an extra call to
thermal_zone_device_update() before it fully stops.
I think what happens is this:

- storing "disabled" in mode ends up in thermal_zone_device_set_mode(),
which calls driver's ->set_mode() and then calls thermal_zone_device_update(),
which returns immediately and does not touch the tz->poll_queue delayed
work

- thermal_zone_device_update() is called from the delayed work when its
time comes and this time it also returns immediately, not modifying the
said delayed work, so polling effectively stops now.

> There is no chance to call into monitor_thermal_zone() in thermal_zone_device_update(),
> or do I miss something?

Without the last "if" statement in this patch polling stops with the
first call to thermal_zone_device_update() because it indeed disables
the delayed work.

So you are probably right - that last "if" should not be introduced.

> 
>> I'll try your patches and probably make an incremental patch.
> 
> I have finished a small patch set to improve this based on my understanding, and will post it
> tomorrow after testing.
> 

Is your small patchset based on top of this series or is it a completely
rewritten version?

Andrzej

^ permalink raw reply	[flat|nested] 63+ messages in thread

* RE: [PATCH v3 2/2] thermal: core: Stop polling DISABLED thermal devices
  2020-04-27 18:34                               ` Andrzej Pietrasiewicz
@ 2020-04-28 13:55                                 ` Zhang, Rui
  0 siblings, 0 replies; 63+ messages in thread
From: Zhang, Rui @ 2020-04-28 13:55 UTC (permalink / raw)
  To: Andrzej Pietrasiewicz, 'linux-pm@vger.kernel.org'
  Cc: 'Rafael J . Wysocki', 'Len Brown',
	'Jiri Pirko', 'Ido Schimmel',
	'David S . Miller', 'Peter Kaestle',
	'Darren Hart', 'Andy Shevchenko',
	'Support Opensource', 'Daniel Lezcano',
	'Amit Kucheria', 'Shawn Guo',
	'Sascha Hauer', 'Pengutronix Kernel Team',
	'Fabio Estevam', 'NXP Linux Team',
	'Heiko Stuebner', 'Orson Zhai',
	'Baolin Wang', 'Chunyan Zhang',
	'linux-acpi@vger.kernel.org',
	'netdev@vger.kernel.org',
	'platform-driver-x86@vger.kernel.org',
	'linux-arm-kernel@lists.infradead.org',
	'kernel@collabora.com',
	'Barlomiej Zolnierkiewicz'

The patch is on top of this patch set.
Run into an issue during test today, will send out after the issue resolved.

Thanks,
rui
> -----Original Message-----
> From: linux-acpi-owner@vger.kernel.org <linux-acpi-owner@vger.kernel.org>
> On Behalf Of Andrzej Pietrasiewicz
> Sent: Tuesday, April 28, 2020 2:35 AM
> To: Zhang, Rui <rui.zhang@intel.com>; 'linux-pm@vger.kernel.org' <linux-
> pm@vger.kernel.org>
> Cc: 'Rafael J . Wysocki' <rjw@rjwysocki.net>; 'Len Brown' <lenb@kernel.org>;
> 'Jiri Pirko' <jiri@mellanox.com>; 'Ido Schimmel' <idosch@mellanox.com>;
> 'David S . Miller' <davem@davemloft.net>; 'Peter Kaestle' <peter@piie.net>;
> 'Darren Hart' <dvhart@infradead.org>; 'Andy Shevchenko'
> <andy@infradead.org>; 'Support Opensource'
> <support.opensource@diasemi.com>; 'Daniel Lezcano'
> <daniel.lezcano@linaro.org>; 'Amit Kucheria'
> <amit.kucheria@verdurent.com>; 'Shawn Guo' <shawnguo@kernel.org>;
> 'Sascha Hauer' <s.hauer@pengutronix.de>; 'Pengutronix Kernel Team'
> <kernel@pengutronix.de>; 'Fabio Estevam' <festevam@gmail.com>; 'NXP
> Linux Team' <linux-imx@nxp.com>; 'Heiko Stuebner' <heiko@sntech.de>;
> 'Orson Zhai' <orsonzhai@gmail.com>; 'Baolin Wang'
> <baolin.wang7@gmail.com>; 'Chunyan Zhang' <zhang.lyra@gmail.com>;
> 'linux-acpi@vger.kernel.org' <linux-acpi@vger.kernel.org>;
> 'netdev@vger.kernel.org' <netdev@vger.kernel.org>; 'platform-driver-
> x86@vger.kernel.org' <platform-driver-x86@vger.kernel.org>; 'linux-arm-
> kernel@lists.infradead.org' <linux-arm-kernel@lists.infradead.org>;
> 'kernel@collabora.com' <kernel@collabora.com>; 'Barlomiej Zolnierkiewicz'
> <b.zolnierkie@samsung.com>
> Subject: Re: [PATCH v3 2/2] thermal: core: Stop polling DISABLED thermal
> devices
> Importance: High
> 
> Hi,
> 
> W dniu 27.04.2020 o 16:20, Zhang, Rui pisze:
> >
> >
> >> -----Original Message-----
> >> From: Zhang, Rui
> >> Sent: Friday, April 24, 2020 5:03 PM
> >> To: Andrzej Pietrasiewicz <andrzej.p@collabora.com>; linux-
> >> pm@vger.kernel.org
> >> Cc: Rafael J . Wysocki <rjw@rjwysocki.net>; Len Brown
> >> <lenb@kernel.org>; Jiri Pirko <jiri@mellanox.com>; Ido Schimmel
> >> <idosch@mellanox.com>; David S . Miller <davem@davemloft.net>;
> Peter
> >> Kaestle <peter@piie.net>; Darren Hart <dvhart@infradead.org>; Andy
> >> Shevchenko <andy@infradead.org>; Support Opensource
> >> <support.opensource@diasemi.com>; Daniel Lezcano
> >> <daniel.lezcano@linaro.org>; Amit Kucheria
> >> <amit.kucheria@verdurent.com>; Shawn Guo <shawnguo@kernel.org>;
> >> Sascha Hauer <s.hauer@pengutronix.de>; Pengutronix Kernel Team
> >> <kernel@pengutronix.de>; Fabio Estevam <festevam@gmail.com>; NXP
> >> Linux Team <linux-imx@nxp.com>; Heiko Stuebner <heiko@sntech.de>;
> >> Orson Zhai <orsonzhai@gmail.com>; Baolin Wang
> >> <baolin.wang7@gmail.com>; Chunyan Zhang <zhang.lyra@gmail.com>;
> >> linux- acpi@vger.kernel.org; netdev@vger.kernel.org; platform-driver-
> >> x86@vger.kernel.org; linux-arm-kernel@lists.infradead.org;
> >> kernel@collabora.com; Barlomiej Zolnierkiewicz
> >> <b.zolnierkie@samsung.com>
> >> Subject: RE: [PATCH v3 2/2] thermal: core: Stop polling DISABLED
> >> thermal devices
> >>
> >> Hi, Andrzej,
> >>
> >> Thanks for the patches. My Linux laptop was broken and won't get
> >> fixed till next week, so I may lost some of the discussions previously.
> >>
> >>> -----Original Message-----
> >>> From: Andrzej Pietrasiewicz <andrzej.p@collabora.com>
> >>> Sent: Friday, April 24, 2020 12:57 AM
> >>> To: linux-pm@vger.kernel.org
> >>> Cc: Zhang, Rui <rui.zhang@intel.com>; Rafael J . Wysocki
> >>> <rjw@rjwysocki.net>; Len Brown <lenb@kernel.org>; Jiri Pirko
> >>> <jiri@mellanox.com>; Ido Schimmel <idosch@mellanox.com>; David S .
> >>> Miller <davem@davemloft.net>; Peter Kaestle <peter@piie.net>;
> Darren
> >>> Hart <dvhart@infradead.org>; Andy Shevchenko <andy@infradead.org>;
> >>> Support Opensource <support.opensource@diasemi.com>; Daniel
> Lezcano
> >>> <daniel.lezcano@linaro.org>; Amit Kucheria
> >>> <amit.kucheria@verdurent.com>; Shawn Guo <shawnguo@kernel.org>;
> >> Sascha
> >>> Hauer <s.hauer@pengutronix.de>; Pengutronix Kernel Team
> >>> <kernel@pengutronix.de>; Fabio Estevam <festevam@gmail.com>; NXP
> >> Linux
> >>> Team <linux-imx@nxp.com>; Heiko Stuebner <heiko@sntech.de>;
> Orson
> >> Zhai
> >>> <orsonzhai@gmail.com>; Baolin Wang <baolin.wang7@gmail.com>;
> >> Chunyan
> >>> Zhang <zhang.lyra@gmail.com>; linux- acpi@vger.kernel.org;
> >>> netdev@vger.kernel.org; platform-driver- x86@vger.kernel.org;
> >>> linux-arm-kernel@lists.infradead.org;
> >>> kernel@collabora.com; Andrzej Pietrasiewicz
> >>> <andrzej.p@collabora.com>; Barlomiej Zolnierkiewicz
> >>> <b.zolnierkie@samsung.com>
> >>> Subject: [PATCH v3 2/2] thermal: core: Stop polling DISABLED thermal
> >>> devices
> >>> Importance: High
> >>>
> >>> Polling DISABLED devices is not desired, as all such "disabled"
> >>> devices are meant to be handled by userspace. This patch introduces
> >>> and uses
> >>> should_stop_polling() to decide whether the device should be polled
> >>> or
> >> not.
> >>>
> >> Thanks for the fix, and IMO, this reveal some more problems.
> >> Say, we need to define "DISABLED" thermal zone.
> >> Can we read the temperature? Can we trust the trip point value?
> >>
> >> IMO, a disabled thermal zone does not mean it is handled by
> >> userspace, because that is what the userspace governor designed for.
> >> Instead, if a thermal zone is disabled, in
> >> thermal_zone_device_update(), we should basically skip all the other
> operations as well.
> >>
> > I overlooked the last line of the patch. So
> > thermal_zone_device_update() returns immediately if the thermal zone is
> disabled, right?
> >
> > But how can we stop polling in this case?
> 
> It does stop. However, I indeed observe an extra call to
> thermal_zone_device_update() before it fully stops.
> I think what happens is this:
> 
> - storing "disabled" in mode ends up in thermal_zone_device_set_mode(),
> which calls driver's ->set_mode() and then calls
> thermal_zone_device_update(), which returns immediately and does not
> touch the tz->poll_queue delayed work
> 
> - thermal_zone_device_update() is called from the delayed work when its
> time comes and this time it also returns immediately, not modifying the said
> delayed work, so polling effectively stops now.
> 
> > There is no chance to call into monitor_thermal_zone() in
> > thermal_zone_device_update(), or do I miss something?
> 
> Without the last "if" statement in this patch polling stops with the first call to
> thermal_zone_device_update() because it indeed disables the delayed work.
> 
> So you are probably right - that last "if" should not be introduced.
> 
> >
> >> I'll try your patches and probably make an incremental patch.
> >
> > I have finished a small patch set to improve this based on my
> > understanding, and will post it tomorrow after testing.
> >
> 
> Is your small patchset based on top of this series or is it a completely
> rewritten version?
> 
> Andrzej

^ permalink raw reply	[flat|nested] 63+ messages in thread

* Re: [PATCH v3 1/2] thermal: core: Let thermal zone device's mode be stored in its struct
  2020-04-23 16:57                         ` [PATCH v3 1/2] thermal: core: Let thermal zone device's mode be stored in its struct Andrzej Pietrasiewicz
@ 2020-05-04  7:00                           ` Bartlomiej Zolnierkiewicz
  0 siblings, 0 replies; 63+ messages in thread
From: Bartlomiej Zolnierkiewicz @ 2020-05-04  7:00 UTC (permalink / raw)
  To: Andrzej Pietrasiewicz
  Cc: linux-pm, Zhang Rui, Rafael J . Wysocki, Len Brown, Jiri Pirko,
	Ido Schimmel, David S . Miller, Peter Kaestle, Darren Hart,
	Andy Shevchenko, Support Opensource, Daniel Lezcano,
	Amit Kucheria, Shawn Guo, Sascha Hauer, Pengutronix Kernel Team,
	Fabio Estevam, NXP Linux Team, Heiko Stuebner, Orson Zhai,
	Baolin Wang, Chunyan Zhang, linux-acpi, netdev,
	platform-driver-x86, linux-arm-kernel, kernel


On 4/23/20 6:57 PM, Andrzej Pietrasiewicz wrote:
> Thermal zone devices' mode is stored in individual drivers. This patch
> changes it so that mode is stored in struct thermal_zone_device instead.
> 
> As a result all driver-specific variables storing the mode are not needed
> and are removed. Consequently, the get_mode() implementations have nothing
> to operate on and need to be removed, too.
> 
> Some thermal framework functions are introduced:
> 
> thermal_zone_device_get_mode()
> thermal_zone_device_set_mode()
> thermal_zone_device_enable()
> thermal_zone_device_disable()
> 
> thermal_zone_device_get_mode() and its "set" counterpart take tzd's lock
> and the "set" calls driver's set_mode() if provided, so the latter must
> not take this lock again. At the end of the "set"
> thermal_zone_device_update() is called so drivers don't need to repeat this
> invocation in their specific set_mode() implementations.
> 
> struct thermal_zone_params gains a new member called initial_mode, which
> is used to set tzd's mode at registration time and if tzp is not provided
> to thermal_zone_device_register() then it is assumed that the initial
> mode is THERMAL_DEVICE_ENABLED.
> 
> The sysfs "mode" attribute is always exposed from now on, because all
> thermal zone devices now have their get_mode() implemented at the generic
> level and it is always available. Exposing "mode" doesn't hurt the drivers
> which don't provide their own set_mode(), because writing to "mode" will
> result in -EPERM, as expected.
> 
> Signed-off-by: Andrzej Pietrasiewicz <andrzej.p@collabora.com>

Reviewed-by: Bartlomiej Zolnierkiewicz <b.zolnierkie@samsung.com>

Best regards,
--
Bartlomiej Zolnierkiewicz
Samsung R&D Institute Poland
Samsung Electronics

> ---
>  drivers/acpi/thermal.c                        | 35 ++-----------
>  .../ethernet/mellanox/mlxsw/core_thermal.c    | 42 ----------------
>  drivers/platform/x86/acerhdf.c                | 17 ++-----
>  drivers/thermal/da9062-thermal.c              | 11 -----
>  drivers/thermal/hisi_thermal.c                |  6 ++-
>  drivers/thermal/imx_thermal.c                 | 36 ++------------
>  .../intel/int340x_thermal/int3400_thermal.c   | 31 ++----------
>  .../int340x_thermal/int340x_thermal_zone.c    |  1 +
>  .../thermal/intel/intel_quark_dts_thermal.c   | 30 +++---------
>  drivers/thermal/intel/x86_pkg_temp_thermal.c  |  1 +
>  drivers/thermal/of-thermal.c                  | 24 +--------
>  drivers/thermal/rockchip_thermal.c            |  6 ++-
>  drivers/thermal/sprd_thermal.c                |  6 ++-
>  drivers/thermal/thermal_core.c                | 49 +++++++++++++++----
>  drivers/thermal/thermal_core.h                |  3 ++
>  drivers/thermal/thermal_sysfs.c               | 29 ++---------
>  include/linux/thermal.h                       | 22 ++++++++-
>  17 files changed, 105 insertions(+), 244 deletions(-)
> 
> diff --git a/drivers/acpi/thermal.c b/drivers/acpi/thermal.c
> index 19067a5e5293..d1f352ed5241 100644
> --- a/drivers/acpi/thermal.c
> +++ b/drivers/acpi/thermal.c
> @@ -172,7 +172,6 @@ struct acpi_thermal {
>  	struct acpi_thermal_trips trips;
>  	struct acpi_handle_list devices;
>  	struct thermal_zone_device *thermal_zone;
> -	int tz_enabled;
>  	int kelvin_offset;	/* in millidegrees */
>  	struct work_struct thermal_check_work;
>  };
> @@ -500,7 +499,7 @@ static void acpi_thermal_check(void *data)
>  {
>  	struct acpi_thermal *tz = data;
>  
> -	if (!tz->tz_enabled)
> +	if (tz->thermal_zone->mode != THERMAL_DEVICE_ENABLED)
>  		return;
>  
>  	thermal_zone_device_update(tz->thermal_zone,
> @@ -526,25 +525,10 @@ static int thermal_get_temp(struct thermal_zone_device *thermal, int *temp)
>  	return 0;
>  }
>  
> -static int thermal_get_mode(struct thermal_zone_device *thermal,
> -				enum thermal_device_mode *mode)
> -{
> -	struct acpi_thermal *tz = thermal->devdata;
> -
> -	if (!tz)
> -		return -EINVAL;
> -
> -	*mode = tz->tz_enabled ? THERMAL_DEVICE_ENABLED :
> -		THERMAL_DEVICE_DISABLED;
> -
> -	return 0;
> -}
> -
>  static int thermal_set_mode(struct thermal_zone_device *thermal,
>  				enum thermal_device_mode mode)
>  {
>  	struct acpi_thermal *tz = thermal->devdata;
> -	int enable;
>  
>  	if (!tz)
>  		return -EINVAL;
> @@ -552,20 +536,14 @@ static int thermal_set_mode(struct thermal_zone_device *thermal,
>  	/*
>  	 * enable/disable thermal management from ACPI thermal driver
>  	 */
> -	if (mode == THERMAL_DEVICE_ENABLED)
> -		enable = 1;
> -	else if (mode == THERMAL_DEVICE_DISABLED) {
> -		enable = 0;
> +	if (mode == THERMAL_DEVICE_DISABLED)
>  		pr_warn("thermal zone will be disabled\n");
> -	} else
> -		return -EINVAL;
>  
> -	if (enable != tz->tz_enabled) {
> -		tz->tz_enabled = enable;
> +	if (mode != thermal->mode) {
>  		ACPI_DEBUG_PRINT((ACPI_DB_INFO,
>  			"%s kernel ACPI thermal control\n",
> -			tz->tz_enabled ? "Enable" : "Disable"));
> -		acpi_thermal_check(tz);
> +			mode == THERMAL_DEVICE_ENABLED ?
> +			"Enable" : "Disable"));
>  	}
>  	return 0;
>  }
> @@ -856,7 +834,6 @@ static struct thermal_zone_device_ops acpi_thermal_zone_ops = {
>  	.bind = acpi_thermal_bind_cooling_device,
>  	.unbind	= acpi_thermal_unbind_cooling_device,
>  	.get_temp = thermal_get_temp,
> -	.get_mode = thermal_get_mode,
>  	.set_mode = thermal_set_mode,
>  	.get_trip_type = thermal_get_trip_type,
>  	.get_trip_temp = thermal_get_trip_temp,
> @@ -913,8 +890,6 @@ static int acpi_thermal_register_thermal_zone(struct acpi_thermal *tz)
>  	if (ACPI_FAILURE(status))
>  		return -ENODEV;
>  
> -	tz->tz_enabled = 1;
> -
>  	dev_info(&tz->device->dev, "registered as thermal_zone%d\n",
>  		 tz->thermal_zone->id);
>  	return 0;
> diff --git a/drivers/net/ethernet/mellanox/mlxsw/core_thermal.c b/drivers/net/ethernet/mellanox/mlxsw/core_thermal.c
> index ce0a6837daa3..5d28384046da 100644
> --- a/drivers/net/ethernet/mellanox/mlxsw/core_thermal.c
> +++ b/drivers/net/ethernet/mellanox/mlxsw/core_thermal.c
> @@ -98,7 +98,6 @@ struct mlxsw_thermal_module {
>  	struct mlxsw_thermal *parent;
>  	struct thermal_zone_device *tzdev;
>  	struct mlxsw_thermal_trip trips[MLXSW_THERMAL_NUM_TRIPS];
> -	enum thermal_device_mode mode;
>  	int module; /* Module or gearbox number */
>  };
>  
> @@ -110,7 +109,6 @@ struct mlxsw_thermal {
>  	struct thermal_cooling_device *cdevs[MLXSW_MFCR_PWMS_MAX];
>  	u8 cooling_levels[MLXSW_THERMAL_MAX_STATE + 1];
>  	struct mlxsw_thermal_trip trips[MLXSW_THERMAL_NUM_TRIPS];
> -	enum thermal_device_mode mode;
>  	struct mlxsw_thermal_module *tz_module_arr;
>  	u8 tz_module_num;
>  	struct mlxsw_thermal_module *tz_gearbox_arr;
> @@ -277,33 +275,16 @@ static int mlxsw_thermal_unbind(struct thermal_zone_device *tzdev,
>  	return 0;
>  }
>  
> -static int mlxsw_thermal_get_mode(struct thermal_zone_device *tzdev,
> -				  enum thermal_device_mode *mode)
> -{
> -	struct mlxsw_thermal *thermal = tzdev->devdata;
> -
> -	*mode = thermal->mode;
> -
> -	return 0;
> -}
> -
>  static int mlxsw_thermal_set_mode(struct thermal_zone_device *tzdev,
>  				  enum thermal_device_mode mode)
>  {
>  	struct mlxsw_thermal *thermal = tzdev->devdata;
>  
> -	mutex_lock(&tzdev->lock);
> -
>  	if (mode == THERMAL_DEVICE_ENABLED)
>  		tzdev->polling_delay = thermal->polling_delay;
>  	else
>  		tzdev->polling_delay = 0;
>  
> -	mutex_unlock(&tzdev->lock);
> -
> -	thermal->mode = mode;
> -	thermal_zone_device_update(tzdev, THERMAL_EVENT_UNSPECIFIED);
> -
>  	return 0;
>  }
>  
> @@ -407,7 +388,6 @@ static int mlxsw_thermal_trend_get(struct thermal_zone_device *tzdev,
>  static struct thermal_zone_device_ops mlxsw_thermal_ops = {
>  	.bind = mlxsw_thermal_bind,
>  	.unbind = mlxsw_thermal_unbind,
> -	.get_mode = mlxsw_thermal_get_mode,
>  	.set_mode = mlxsw_thermal_set_mode,
>  	.get_temp = mlxsw_thermal_get_temp,
>  	.get_trip_type	= mlxsw_thermal_get_trip_type,
> @@ -466,34 +446,17 @@ static int mlxsw_thermal_module_unbind(struct thermal_zone_device *tzdev,
>  	return err;
>  }
>  
> -static int mlxsw_thermal_module_mode_get(struct thermal_zone_device *tzdev,
> -					 enum thermal_device_mode *mode)
> -{
> -	struct mlxsw_thermal_module *tz = tzdev->devdata;
> -
> -	*mode = tz->mode;
> -
> -	return 0;
> -}
> -
>  static int mlxsw_thermal_module_mode_set(struct thermal_zone_device *tzdev,
>  					 enum thermal_device_mode mode)
>  {
>  	struct mlxsw_thermal_module *tz = tzdev->devdata;
>  	struct mlxsw_thermal *thermal = tz->parent;
>  
> -	mutex_lock(&tzdev->lock);
> -
>  	if (mode == THERMAL_DEVICE_ENABLED)
>  		tzdev->polling_delay = thermal->polling_delay;
>  	else
>  		tzdev->polling_delay = 0;
>  
> -	mutex_unlock(&tzdev->lock);
> -
> -	tz->mode = mode;
> -	thermal_zone_device_update(tzdev, THERMAL_EVENT_UNSPECIFIED);
> -
>  	return 0;
>  }
>  
> @@ -596,7 +559,6 @@ mlxsw_thermal_module_trip_hyst_set(struct thermal_zone_device *tzdev, int trip,
>  static struct thermal_zone_device_ops mlxsw_thermal_module_ops = {
>  	.bind		= mlxsw_thermal_module_bind,
>  	.unbind		= mlxsw_thermal_module_unbind,
> -	.get_mode	= mlxsw_thermal_module_mode_get,
>  	.set_mode	= mlxsw_thermal_module_mode_set,
>  	.get_temp	= mlxsw_thermal_module_temp_get,
>  	.get_trip_type	= mlxsw_thermal_module_trip_type_get,
> @@ -635,7 +597,6 @@ static int mlxsw_thermal_gearbox_temp_get(struct thermal_zone_device *tzdev,
>  static struct thermal_zone_device_ops mlxsw_thermal_gearbox_ops = {
>  	.bind		= mlxsw_thermal_module_bind,
>  	.unbind		= mlxsw_thermal_module_unbind,
> -	.get_mode	= mlxsw_thermal_module_mode_get,
>  	.set_mode	= mlxsw_thermal_module_mode_set,
>  	.get_temp	= mlxsw_thermal_gearbox_temp_get,
>  	.get_trip_type	= mlxsw_thermal_module_trip_type_get,
> @@ -765,7 +726,6 @@ mlxsw_thermal_module_tz_init(struct mlxsw_thermal_module *module_tz)
>  		return err;
>  	}
>  
> -	module_tz->mode = THERMAL_DEVICE_ENABLED;
>  	return 0;
>  }
>  
> @@ -881,7 +841,6 @@ mlxsw_thermal_gearbox_tz_init(struct mlxsw_thermal_module *gearbox_tz)
>  	if (IS_ERR(gearbox_tz->tzdev))
>  		return PTR_ERR(gearbox_tz->tzdev);
>  
> -	gearbox_tz->mode = THERMAL_DEVICE_ENABLED;
>  	return 0;
>  }
>  
> @@ -1050,7 +1009,6 @@ int mlxsw_thermal_init(struct mlxsw_core *core,
>  	if (err)
>  		goto err_unreg_modules_tzdev;
>  
> -	thermal->mode = THERMAL_DEVICE_ENABLED;
>  	*p_thermal = thermal;
>  	return 0;
>  
> diff --git a/drivers/platform/x86/acerhdf.c b/drivers/platform/x86/acerhdf.c
> index 8cc86f4e3ac1..aaf8b845be90 100644
> --- a/drivers/platform/x86/acerhdf.c
> +++ b/drivers/platform/x86/acerhdf.c
> @@ -406,22 +406,9 @@ static inline void acerhdf_enable_kernelmode(void)
>  	kernelmode = 1;
>  
>  	thz_dev->polling_delay = interval*1000;
> -	thermal_zone_device_update(thz_dev, THERMAL_EVENT_UNSPECIFIED);
>  	pr_notice("kernel mode fan control ON\n");
>  }
>  
> -static int acerhdf_get_mode(struct thermal_zone_device *thermal,
> -			    enum thermal_device_mode *mode)
> -{
> -	if (verbose)
> -		pr_notice("kernel mode fan control %d\n", kernelmode);
> -
> -	*mode = (kernelmode) ? THERMAL_DEVICE_ENABLED
> -			     : THERMAL_DEVICE_DISABLED;
> -
> -	return 0;
> -}
> -
>  /*
>   * set operation mode;
>   * enabled: the thermal layer of the kernel takes care about
> @@ -488,7 +475,6 @@ static struct thermal_zone_device_ops acerhdf_dev_ops = {
>  	.bind = acerhdf_bind,
>  	.unbind = acerhdf_unbind,
>  	.get_temp = acerhdf_get_ec_temp,
> -	.get_mode = acerhdf_get_mode,
>  	.set_mode = acerhdf_set_mode,
>  	.get_trip_type = acerhdf_get_trip_type,
>  	.get_trip_hyst = acerhdf_get_trip_hyst,
> @@ -554,6 +540,7 @@ static int acerhdf_set_cur_state(struct thermal_cooling_device *cdev,
>  
>  err_out:
>  	acerhdf_revert_to_bios_mode();
> +	thz_dev->mode = THERMAL_DEVICE_DISABLED;
>  	return -EINVAL;
>  }
>  
> @@ -739,6 +726,8 @@ static int __init acerhdf_register_thermal(void)
>  	if (IS_ERR(cl_dev))
>  		return -EINVAL;
>  
> +	acerhdf_zone_params.initial_mode =
> +		kernelmode ? THERMAL_DEVICE_ENABLED : THERMAL_DEVICE_DISABLED;
>  	thz_dev = thermal_zone_device_register("acerhdf", 2, 0, NULL,
>  					      &acerhdf_dev_ops,
>  					      &acerhdf_zone_params, 0,
> diff --git a/drivers/thermal/da9062-thermal.c b/drivers/thermal/da9062-thermal.c
> index c32709badeda..c3075d038095 100644
> --- a/drivers/thermal/da9062-thermal.c
> +++ b/drivers/thermal/da9062-thermal.c
> @@ -49,7 +49,6 @@ struct da9062_thermal {
>  	struct da9062 *hw;
>  	struct delayed_work work;
>  	struct thermal_zone_device *zone;
> -	enum thermal_device_mode mode;
>  	struct mutex lock; /* protection for da9062_thermal temperature */
>  	int temperature;
>  	int irq;
> @@ -121,14 +120,6 @@ static irqreturn_t da9062_thermal_irq_handler(int irq, void *data)
>  	return IRQ_HANDLED;
>  }
>  
> -static int da9062_thermal_get_mode(struct thermal_zone_device *z,
> -				   enum thermal_device_mode *mode)
> -{
> -	struct da9062_thermal *thermal = z->devdata;
> -	*mode = thermal->mode;
> -	return 0;
> -}
> -
>  static int da9062_thermal_get_trip_type(struct thermal_zone_device *z,
>  					int trip,
>  					enum thermal_trip_type *type)
> @@ -181,7 +172,6 @@ static int da9062_thermal_get_temp(struct thermal_zone_device *z,
>  
>  static struct thermal_zone_device_ops da9062_thermal_ops = {
>  	.get_temp	= da9062_thermal_get_temp,
> -	.get_mode	= da9062_thermal_get_mode,
>  	.get_trip_type	= da9062_thermal_get_trip_type,
>  	.get_trip_temp	= da9062_thermal_get_trip_temp,
>  };
> @@ -233,7 +223,6 @@ static int da9062_thermal_probe(struct platform_device *pdev)
>  
>  	thermal->config = match->data;
>  	thermal->hw = chip;
> -	thermal->mode = THERMAL_DEVICE_ENABLED;
>  	thermal->dev = &pdev->dev;
>  
>  	INIT_DELAYED_WORK(&thermal->work, da9062_thermal_poll_on);
> diff --git a/drivers/thermal/hisi_thermal.c b/drivers/thermal/hisi_thermal.c
> index 2d26ae80e202..ee05950afd2f 100644
> --- a/drivers/thermal/hisi_thermal.c
> +++ b/drivers/thermal/hisi_thermal.c
> @@ -549,8 +549,10 @@ static void hisi_thermal_toggle_sensor(struct hisi_thermal_sensor *sensor,
>  {
>  	struct thermal_zone_device *tzd = sensor->tzd;
>  
> -	tzd->ops->set_mode(tzd,
> -		on ? THERMAL_DEVICE_ENABLED : THERMAL_DEVICE_DISABLED);
> +	if (on)
> +		thermal_zone_device_enable(tzd);
> +	else
> +		thermal_zone_device_disable(tzd);
>  }
>  
>  static int hisi_thermal_probe(struct platform_device *pdev)
> diff --git a/drivers/thermal/imx_thermal.c b/drivers/thermal/imx_thermal.c
> index e761c9b42217..800d2388c440 100644
> --- a/drivers/thermal/imx_thermal.c
> +++ b/drivers/thermal/imx_thermal.c
> @@ -197,7 +197,6 @@ struct imx_thermal_data {
>  	struct cpufreq_policy *policy;
>  	struct thermal_zone_device *tz;
>  	struct thermal_cooling_device *cdev;
> -	enum thermal_device_mode mode;
>  	struct regmap *tempmon;
>  	u32 c1, c2; /* See formula in imx_init_calib() */
>  	int temp_passive;
> @@ -256,7 +255,7 @@ static int imx_get_temp(struct thermal_zone_device *tz, int *temp)
>  	bool wait;
>  	u32 val;
>  
> -	if (data->mode == THERMAL_DEVICE_ENABLED) {
> +	if (tz->mode == THERMAL_DEVICE_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 +282,7 @@ static int imx_get_temp(struct thermal_zone_device *tz, int *temp)
>  
>  	regmap_read(map, soc_data->temp_data, &val);
>  
> -	if (data->mode != THERMAL_DEVICE_ENABLED) {
> +	if (tz->mode != THERMAL_DEVICE_ENABLED) {
>  		regmap_write(map, soc_data->sensor_ctrl + REG_CLR,
>  			     soc_data->measure_temp_mask);
>  		regmap_write(map, soc_data->sensor_ctrl + REG_SET,
> @@ -331,16 +330,6 @@ static int imx_get_temp(struct thermal_zone_device *tz, int *temp)
>  	return 0;
>  }
>  
> -static int imx_get_mode(struct thermal_zone_device *tz,
> -			enum thermal_device_mode *mode)
> -{
> -	struct imx_thermal_data *data = tz->devdata;
> -
> -	*mode = data->mode;
> -
> -	return 0;
> -}
> -
>  static int imx_set_mode(struct thermal_zone_device *tz,
>  			enum thermal_device_mode mode)
>  {
> @@ -376,9 +365,6 @@ static int imx_set_mode(struct thermal_zone_device *tz,
>  		}
>  	}
>  
> -	data->mode = mode;
> -	thermal_zone_device_update(tz, THERMAL_EVENT_UNSPECIFIED);
> -
>  	return 0;
>  }
>  
> @@ -467,7 +453,6 @@ static struct thermal_zone_device_ops imx_tz_ops = {
>  	.bind = imx_bind,
>  	.unbind = imx_unbind,
>  	.get_temp = imx_get_temp,
> -	.get_mode = imx_get_mode,
>  	.set_mode = imx_set_mode,
>  	.get_trip_type = imx_get_trip_type,
>  	.get_trip_temp = imx_get_trip_temp,
> @@ -831,7 +816,6 @@ static int imx_thermal_probe(struct platform_device *pdev)
>  		     data->socdata->measure_temp_mask);
>  
>  	data->irq_enabled = true;
> -	data->mode = THERMAL_DEVICE_ENABLED;
>  
>  	ret = devm_request_threaded_irq(&pdev->dev, data->irq,
>  			imx_thermal_alarm_irq, imx_thermal_alarm_irq_thread,
> @@ -873,19 +857,14 @@ static int imx_thermal_remove(struct platform_device *pdev)
>  static int __maybe_unused imx_thermal_suspend(struct device *dev)
>  {
>  	struct imx_thermal_data *data = dev_get_drvdata(dev);
> -	struct regmap *map = data->tempmon;
>  
>  	/*
>  	 * Need to disable thermal sensor, otherwise, when thermal core
>  	 * try to get temperature before thermal sensor resume, a wrong
>  	 * temperature will be read as the thermal sensor is powered
> -	 * down.
> +	 * down. This is done in thermal_zone_device_disable().
>  	 */
> -	regmap_write(map, data->socdata->sensor_ctrl + REG_CLR,
> -		     data->socdata->measure_temp_mask);
> -	regmap_write(map, data->socdata->sensor_ctrl + REG_SET,
> -		     data->socdata->power_down_mask);
> -	data->mode = THERMAL_DEVICE_DISABLED;
> +	thermal_zone_device_disable(data->tz);
>  	clk_disable_unprepare(data->thermal_clk);
>  
>  	return 0;
> @@ -894,18 +873,13 @@ static int __maybe_unused imx_thermal_suspend(struct device *dev)
>  static int __maybe_unused imx_thermal_resume(struct device *dev)
>  {
>  	struct imx_thermal_data *data = dev_get_drvdata(dev);
> -	struct regmap *map = data->tempmon;
>  	int ret;
>  
>  	ret = clk_prepare_enable(data->thermal_clk);
>  	if (ret)
>  		return ret;
>  	/* Enabled thermal sensor after resume */
> -	regmap_write(map, data->socdata->sensor_ctrl + REG_CLR,
> -		     data->socdata->power_down_mask);
> -	regmap_write(map, data->socdata->sensor_ctrl + REG_SET,
> -		     data->socdata->measure_temp_mask);
> -	data->mode = THERMAL_DEVICE_ENABLED;
> +	thermal_zone_device_enable(data->tz);
>  
>  	return 0;
>  }
> diff --git a/drivers/thermal/intel/int340x_thermal/int3400_thermal.c b/drivers/thermal/intel/int340x_thermal/int3400_thermal.c
> index e802922a13cf..1751d4b103b1 100644
> --- a/drivers/thermal/intel/int340x_thermal/int3400_thermal.c
> +++ b/drivers/thermal/intel/int340x_thermal/int3400_thermal.c
> @@ -44,7 +44,6 @@ static char *int3400_thermal_uuids[INT3400_THERMAL_MAXIMUM_UUID] = {
>  struct int3400_thermal_priv {
>  	struct acpi_device *adev;
>  	struct thermal_zone_device *thermal;
> -	int mode;
>  	int art_count;
>  	struct art *arts;
>  	int trt_count;
> @@ -230,54 +229,32 @@ static int int3400_thermal_get_temp(struct thermal_zone_device *thermal,
>  	return 0;
>  }
>  
> -static int int3400_thermal_get_mode(struct thermal_zone_device *thermal,
> -				enum thermal_device_mode *mode)
> -{
> -	struct int3400_thermal_priv *priv = thermal->devdata;
> -
> -	if (!priv)
> -		return -EINVAL;
> -
> -	*mode = priv->mode;
> -
> -	return 0;
> -}
> -
>  static int int3400_thermal_set_mode(struct thermal_zone_device *thermal,
>  				enum thermal_device_mode mode)
>  {
>  	struct int3400_thermal_priv *priv = thermal->devdata;
> -	bool enable;
>  	int result = 0;
>  
>  	if (!priv)
>  		return -EINVAL;
>  
> -	if (mode == THERMAL_DEVICE_ENABLED)
> -		enable = true;
> -	else if (mode == THERMAL_DEVICE_DISABLED)
> -		enable = false;
> -	else
> -		return -EINVAL;
> -
> -	if (enable != priv->mode) {
> -		priv->mode = enable;
> +	if (mode != thermal->mode) {
>  		result = int3400_thermal_run_osc(priv->adev->handle,
> -						 priv->current_uuid_index,
> -						 enable);
> +						priv->current_uuid_index,
> +						mode == THERMAL_DEVICE_ENABLED);
>  	}
>  	return result;
>  }
>  
>  static struct thermal_zone_device_ops int3400_thermal_ops = {
>  	.get_temp = int3400_thermal_get_temp,
> -	.get_mode = int3400_thermal_get_mode,
>  	.set_mode = int3400_thermal_set_mode,
>  };
>  
>  static struct thermal_zone_params int3400_thermal_params = {
>  	.governor_name = "user_space",
>  	.no_hwmon = true,
> +	.initial_mode = THERMAL_DEVICE_DISABLED,
>  };
>  
>  static int int3400_thermal_probe(struct platform_device *pdev)
> diff --git a/drivers/thermal/intel/int340x_thermal/int340x_thermal_zone.c b/drivers/thermal/intel/int340x_thermal/int340x_thermal_zone.c
> index 432213272f1e..b36da9bfbf8a 100644
> --- a/drivers/thermal/intel/int340x_thermal/int340x_thermal_zone.c
> +++ b/drivers/thermal/intel/int340x_thermal/int340x_thermal_zone.c
> @@ -208,6 +208,7 @@ EXPORT_SYMBOL_GPL(int340x_thermal_read_trips);
>  static struct thermal_zone_params int340x_thermal_params = {
>  	.governor_name = "user_space",
>  	.no_hwmon = true,
> +	.initial_mode = THERMAL_DEVICE_ENABLED,
>  };
>  
>  struct int34x_thermal_zone *int340x_thermal_zone_add(struct acpi_device *adev,
> diff --git a/drivers/thermal/intel/intel_quark_dts_thermal.c b/drivers/thermal/intel/intel_quark_dts_thermal.c
> index d704fc104cfd..02dabd93f607 100644
> --- a/drivers/thermal/intel/intel_quark_dts_thermal.c
> +++ b/drivers/thermal/intel/intel_quark_dts_thermal.c
> @@ -103,7 +103,6 @@ struct soc_sensor_entry {
>  	bool locked;
>  	u32 store_ptps;
>  	u32 store_dts_enable;
> -	enum thermal_device_mode mode;
>  	struct thermal_zone_device *tzone;
>  };
>  
> @@ -128,7 +127,7 @@ static int soc_dts_enable(struct thermal_zone_device *tzd)
>  		return ret;
>  
>  	if (out & QRK_DTS_ENABLE_BIT) {
> -		aux_entry->mode = THERMAL_DEVICE_ENABLED;
> +		tzd->mode = THERMAL_DEVICE_ENABLED;
>  		return 0;
>  	}
>  
> @@ -139,9 +138,9 @@ static int soc_dts_enable(struct thermal_zone_device *tzd)
>  		if (ret)
>  			return ret;
>  
> -		aux_entry->mode = THERMAL_DEVICE_ENABLED;
> +		tzd->mode = THERMAL_DEVICE_ENABLED;
>  	} else {
> -		aux_entry->mode = THERMAL_DEVICE_DISABLED;
> +		tzd->mode = THERMAL_DEVICE_DISABLED;
>  		pr_info("DTS is locked. Cannot enable DTS\n");
>  		ret = -EPERM;
>  	}
> @@ -161,7 +160,7 @@ static int soc_dts_disable(struct thermal_zone_device *tzd)
>  		return ret;
>  
>  	if (!(out & QRK_DTS_ENABLE_BIT)) {
> -		aux_entry->mode = THERMAL_DEVICE_DISABLED;
> +		tzd->mode = THERMAL_DEVICE_DISABLED;
>  		return 0;
>  	}
>  
> @@ -173,9 +172,9 @@ static int soc_dts_disable(struct thermal_zone_device *tzd)
>  		if (ret)
>  			return ret;
>  
> -		aux_entry->mode = THERMAL_DEVICE_DISABLED;
> +		tzd->mode = THERMAL_DEVICE_DISABLED;
>  	} else {
> -		aux_entry->mode = THERMAL_DEVICE_ENABLED;
> +		tzd->mode = THERMAL_DEVICE_ENABLED;
>  		pr_info("DTS is locked. Cannot disable DTS\n");
>  		ret = -EPERM;
>  	}
> @@ -309,14 +308,6 @@ static int sys_get_curr_temp(struct thermal_zone_device *tzd,
>  	return 0;
>  }
>  
> -static int sys_get_mode(struct thermal_zone_device *tzd,
> -				enum thermal_device_mode *mode)
> -{
> -	struct soc_sensor_entry *aux_entry = tzd->devdata;
> -	*mode = aux_entry->mode;
> -	return 0;
> -}
> -
>  static int sys_set_mode(struct thermal_zone_device *tzd,
>  				enum thermal_device_mode mode)
>  {
> @@ -338,7 +329,6 @@ static struct thermal_zone_device_ops tzone_ops = {
>  	.get_trip_type = sys_get_trip_type,
>  	.set_trip_temp = sys_set_trip_temp,
>  	.get_crit_temp = sys_get_crit_temp,
> -	.get_mode = sys_get_mode,
>  	.set_mode = sys_set_mode,
>  };
>  
> @@ -414,16 +404,8 @@ static struct soc_sensor_entry *alloc_soc_dts(void)
>  		goto err_ret;
>  	}
>  
> -	mutex_lock(&dts_update_mutex);
> -	err = soc_dts_enable(aux_entry->tzone);
> -	mutex_unlock(&dts_update_mutex);
> -	if (err)
> -		goto err_aux_status;
> -
>  	return aux_entry;
>  
> -err_aux_status:
> -	thermal_zone_device_unregister(aux_entry->tzone);
>  err_ret:
>  	kfree(aux_entry);
>  	return ERR_PTR(err);
> diff --git a/drivers/thermal/intel/x86_pkg_temp_thermal.c b/drivers/thermal/intel/x86_pkg_temp_thermal.c
> index a006b9fd1d72..cb810a02aab0 100644
> --- a/drivers/thermal/intel/x86_pkg_temp_thermal.c
> +++ b/drivers/thermal/intel/x86_pkg_temp_thermal.c
> @@ -56,6 +56,7 @@ struct zone_device {
>  
>  static struct thermal_zone_params pkg_temp_tz_params = {
>  	.no_hwmon	= true,
> +	.initial_mode	= THERMAL_DEVICE_ENABLED,
>  };
>  
>  /* Keep track of how many zone pointers we allocated in init() */
> diff --git a/drivers/thermal/of-thermal.c b/drivers/thermal/of-thermal.c
> index 874a47d6923f..48787a5576d8 100644
> --- a/drivers/thermal/of-thermal.c
> +++ b/drivers/thermal/of-thermal.c
> @@ -51,7 +51,6 @@ struct __thermal_bind_params {
>  
>  /**
>   * struct __thermal_zone - internal representation of a thermal zone
> - * @mode: current thermal zone device mode (enabled/disabled)
>   * @passive_delay: polling interval while passive cooling is activated
>   * @polling_delay: zone polling interval
>   * @slope: slope of the temperature adjustment curve
> @@ -65,7 +64,6 @@ struct __thermal_bind_params {
>   */
>  
>  struct __thermal_zone {
> -	enum thermal_device_mode mode;
>  	int passive_delay;
>  	int polling_delay;
>  	int slope;
> @@ -269,23 +267,11 @@ static int of_thermal_unbind(struct thermal_zone_device *thermal,
>  	return 0;
>  }
>  
> -static int of_thermal_get_mode(struct thermal_zone_device *tz,
> -			       enum thermal_device_mode *mode)
> -{
> -	struct __thermal_zone *data = tz->devdata;
> -
> -	*mode = data->mode;
> -
> -	return 0;
> -}
> -
>  static int of_thermal_set_mode(struct thermal_zone_device *tz,
>  			       enum thermal_device_mode mode)
>  {
>  	struct __thermal_zone *data = tz->devdata;
>  
> -	mutex_lock(&tz->lock);
> -
>  	if (mode == THERMAL_DEVICE_ENABLED) {
>  		tz->polling_delay = data->polling_delay;
>  		tz->passive_delay = data->passive_delay;
> @@ -294,11 +280,6 @@ static int of_thermal_set_mode(struct thermal_zone_device *tz,
>  		tz->passive_delay = 0;
>  	}
>  
> -	mutex_unlock(&tz->lock);
> -
> -	data->mode = mode;
> -	thermal_zone_device_update(tz, THERMAL_EVENT_UNSPECIFIED);
> -
>  	return 0;
>  }
>  
> @@ -393,7 +374,6 @@ static int of_thermal_get_crit_temp(struct thermal_zone_device *tz,
>  }
>  
>  static struct thermal_zone_device_ops of_thermal_ops = {
> -	.get_mode = of_thermal_get_mode,
>  	.set_mode = of_thermal_set_mode,
>  
>  	.get_trip_type = of_thermal_get_trip_type,
> @@ -554,7 +534,7 @@ thermal_zone_of_sensor_register(struct device *dev, int sensor_id, void *data,
>  			tzd = thermal_zone_of_add_sensor(child, sensor_np,
>  							 data, ops);
>  			if (!IS_ERR(tzd))
> -				tzd->ops->set_mode(tzd, THERMAL_DEVICE_ENABLED);
> +				thermal_zone_device_enable(tzd);
>  
>  			of_node_put(child);
>  			goto exit;
> @@ -979,7 +959,6 @@ __init *thermal_of_build_thermal_zone(struct device_node *np)
>  
>  finish:
>  	of_node_put(child);
> -	tz->mode = THERMAL_DEVICE_DISABLED;
>  
>  	return tz;
>  
> @@ -1120,6 +1099,7 @@ int __init of_parse_thermal_zones(void)
>  		/* these two are left for temperature drivers to use */
>  		tzp->slope = tz->slope;
>  		tzp->offset = tz->offset;
> +		tzp->initial_mode = THERMAL_DEVICE_DISABLED;
>  
>  		zone = thermal_zone_device_register(child->name, tz->ntrips,
>  						    mask, tz,
> diff --git a/drivers/thermal/rockchip_thermal.c b/drivers/thermal/rockchip_thermal.c
> index 15a71ecc916c..aa9e0e31ef98 100644
> --- a/drivers/thermal/rockchip_thermal.c
> +++ b/drivers/thermal/rockchip_thermal.c
> @@ -1068,8 +1068,10 @@ rockchip_thermal_toggle_sensor(struct rockchip_thermal_sensor *sensor, bool on)
>  {
>  	struct thermal_zone_device *tzd = sensor->tzd;
>  
> -	tzd->ops->set_mode(tzd,
> -		on ? THERMAL_DEVICE_ENABLED : THERMAL_DEVICE_DISABLED);
> +	if (on)
> +		thermal_zone_device_enable(tzd);
> +	else
> +		thermal_zone_device_disable(tzd);
>  }
>  
>  static irqreturn_t rockchip_thermal_alarm_irq_thread(int irq, void *dev)
> diff --git a/drivers/thermal/sprd_thermal.c b/drivers/thermal/sprd_thermal.c
> index a340374e8c51..58f995b0f804 100644
> --- a/drivers/thermal/sprd_thermal.c
> +++ b/drivers/thermal/sprd_thermal.c
> @@ -322,8 +322,10 @@ static void sprd_thm_toggle_sensor(struct sprd_thermal_sensor *sen, bool on)
>  {
>  	struct thermal_zone_device *tzd = sen->tzd;
>  
> -	tzd->ops->set_mode(tzd,
> -		on ? THERMAL_DEVICE_ENABLED : THERMAL_DEVICE_DISABLED);
> +	if (on)
> +		thermal_zone_device_enable(tzd);
> +	else
> +		thermal_zone_device_disable(tzd);
>  }
>  
>  static int sprd_thm_probe(struct platform_device *pdev)
> diff --git a/drivers/thermal/thermal_core.c b/drivers/thermal/thermal_core.c
> index c06550930979..a2a5034f76e7 100644
> --- a/drivers/thermal/thermal_core.c
> +++ b/drivers/thermal/thermal_core.c
> @@ -463,6 +463,41 @@ static void thermal_zone_device_reset(struct thermal_zone_device *tz)
>  	thermal_zone_device_init(tz);
>  }
>  
> +enum thermal_device_mode
> +thermal_zone_device_get_mode(struct thermal_zone_device *tz)
> +{
> +	enum thermal_device_mode mode;
> +
> +	mutex_lock(&tz->lock);
> +
> +	mode = tz->mode;
> +
> +	mutex_unlock(&tz->lock);
> +
> +	return mode;
> +}
> +
> +int thermal_zone_device_set_mode(struct thermal_zone_device *tz,
> +				 enum thermal_device_mode mode)
> +{
> +	int ret = 0;
> +
> +	mutex_lock(&tz->lock);
> +
> +	if (tz->ops->set_mode)
> +		ret = tz->ops->set_mode(tz, mode);
> +
> +	if (!ret)
> +		tz->mode = mode;
> +
> +	mutex_unlock(&tz->lock);
> +
> +	thermal_zone_device_update(tz, THERMAL_EVENT_UNSPECIFIED);
> +
> +	return ret;
> +}
> +EXPORT_SYMBOL_GPL(thermal_zone_device_set_mode);
> +
>  void thermal_zone_device_update(struct thermal_zone_device *tz,
>  				enum thermal_notify_event event)
>  {
> @@ -1236,6 +1271,7 @@ thermal_zone_device_register(const char *type, int trips, int mask,
>  	int result;
>  	int count;
>  	struct thermal_governor *governor;
> +	enum thermal_device_mode mode;
>  
>  	if (!type || strlen(type) == 0) {
>  		pr_err("Error: No thermal zone type defined\n");
> @@ -1290,9 +1326,6 @@ thermal_zone_device_register(const char *type, int trips, int mask,
>  	if (result)
>  		goto remove_id;
>  
> -	/* A new thermal zone needs to be updated anyway. */
> -	atomic_set(&tz->need_update, 1);
> -
>  	dev_set_name(&tz->device, "thermal_zone%d", tz->id);
>  	result = device_register(&tz->device);
>  	if (result)
> @@ -1340,9 +1373,9 @@ thermal_zone_device_register(const char *type, int trips, int mask,
>  	INIT_DELAYED_WORK(&tz->poll_queue, thermal_zone_device_check);
>  
>  	thermal_zone_device_reset(tz);
> -	/* Update the new thermal zone and mark it as already updated. */
> -	if (atomic_cmpxchg(&tz->need_update, 1, 0))
> -		thermal_zone_device_update(tz, THERMAL_EVENT_UNSPECIFIED);
> +
> +	mode = tzp ? tzp->initial_mode : THERMAL_DEVICE_ENABLED;
> +	thermal_zone_device_set_mode(tz, mode);
>  
>  	return tz;
>  
> @@ -1473,9 +1506,7 @@ static int thermal_pm_notify(struct notifier_block *nb,
>  	case PM_POST_SUSPEND:
>  		atomic_set(&in_suspend, 0);
>  		list_for_each_entry(tz, &thermal_tz_list, node) {
> -			tz_mode = THERMAL_DEVICE_ENABLED;
> -			if (tz->ops->get_mode)
> -				tz->ops->get_mode(tz, &tz_mode);
> +			tz_mode = thermal_zone_device_get_mode(tz);
>  
>  			if (tz_mode == THERMAL_DEVICE_DISABLED)
>  				continue;
> diff --git a/drivers/thermal/thermal_core.h b/drivers/thermal/thermal_core.h
> index c95689586e19..ff5519adb68a 100644
> --- a/drivers/thermal/thermal_core.h
> +++ b/drivers/thermal/thermal_core.h
> @@ -141,6 +141,9 @@ thermal_cooling_device_stats_update(struct thermal_cooling_device *cdev,
>  				    unsigned long new_state) {}
>  #endif /* CONFIG_THERMAL_STATISTICS */
>  
> +enum thermal_device_mode
> +thermal_zone_device_get_mode(struct thermal_zone_device *tz);
> +
>  /* device tree support */
>  #ifdef CONFIG_THERMAL_OF
>  int of_parse_thermal_zones(void);
> diff --git a/drivers/thermal/thermal_sysfs.c b/drivers/thermal/thermal_sysfs.c
> index aa99edb4dff7..cbb27b3c96d2 100644
> --- a/drivers/thermal/thermal_sysfs.c
> +++ b/drivers/thermal/thermal_sysfs.c
> @@ -50,14 +50,8 @@ mode_show(struct device *dev, struct device_attribute *attr, char *buf)
>  {
>  	struct thermal_zone_device *tz = to_thermal_zone(dev);
>  	enum thermal_device_mode mode;
> -	int result;
> -
> -	if (!tz->ops->get_mode)
> -		return -EPERM;
>  
> -	result = tz->ops->get_mode(tz, &mode);
> -	if (result)
> -		return result;
> +	mode = thermal_zone_device_get_mode(tz);
>  
>  	return sprintf(buf, "%s\n", mode == THERMAL_DEVICE_ENABLED ? "enabled"
>  		       : "disabled");
> @@ -74,9 +68,9 @@ mode_store(struct device *dev, struct device_attribute *attr,
>  		return -EPERM;
>  
>  	if (!strncmp(buf, "enabled", sizeof("enabled") - 1))
> -		result = tz->ops->set_mode(tz, THERMAL_DEVICE_ENABLED);
> +		result = thermal_zone_device_enable(tz);
>  	else if (!strncmp(buf, "disabled", sizeof("disabled") - 1))
> -		result = tz->ops->set_mode(tz, THERMAL_DEVICE_DISABLED);
> +		result = thermal_zone_device_disable(tz);
>  	else
>  		result = -EINVAL;
>  
> @@ -428,30 +422,13 @@ static struct attribute_group thermal_zone_attribute_group = {
>  	.attrs = thermal_zone_dev_attrs,
>  };
>  
> -/* We expose mode only if .get_mode is present */
>  static struct attribute *thermal_zone_mode_attrs[] = {
>  	&dev_attr_mode.attr,
>  	NULL,
>  };
>  
> -static umode_t thermal_zone_mode_is_visible(struct kobject *kobj,
> -					    struct attribute *attr,
> -					    int attrno)
> -{
> -	struct device *dev = container_of(kobj, struct device, kobj);
> -	struct thermal_zone_device *tz;
> -
> -	tz = container_of(dev, struct thermal_zone_device, device);
> -
> -	if (tz->ops->get_mode)
> -		return attr->mode;
> -
> -	return 0;
> -}
> -
>  static struct attribute_group thermal_zone_mode_attribute_group = {
>  	.attrs = thermal_zone_mode_attrs,
> -	.is_visible = thermal_zone_mode_is_visible,
>  };
>  
>  /* We expose passive only if passive trips are present */
> diff --git a/include/linux/thermal.h b/include/linux/thermal.h
> index 216185bb3014..c789d4ff6e63 100644
> --- a/include/linux/thermal.h
> +++ b/include/linux/thermal.h
> @@ -76,8 +76,6 @@ struct thermal_zone_device_ops {
>  		       struct thermal_cooling_device *);
>  	int (*get_temp) (struct thermal_zone_device *, int *);
>  	int (*set_trips) (struct thermal_zone_device *, int, int);
> -	int (*get_mode) (struct thermal_zone_device *,
> -			 enum thermal_device_mode *);
>  	int (*set_mode) (struct thermal_zone_device *,
>  		enum thermal_device_mode);
>  	int (*get_trip_type) (struct thermal_zone_device *, int,
> @@ -128,6 +126,7 @@ struct thermal_cooling_device {
>   * @trip_temp_attrs:	attributes for trip points for sysfs: trip temperature
>   * @trip_type_attrs:	attributes for trip points for sysfs: trip type
>   * @trip_hyst_attrs:	attributes for trip points for sysfs: trip hysteresis
> + * @mode:		current mode of this thermal zone
>   * @devdata:	private pointer for device private data
>   * @trips:	number of trip points the thermal zone supports
>   * @trips_disabled;	bitmap for disabled trips
> @@ -170,6 +169,7 @@ struct thermal_zone_device {
>  	struct thermal_attr *trip_temp_attrs;
>  	struct thermal_attr *trip_type_attrs;
>  	struct thermal_attr *trip_hyst_attrs;
> +	enum thermal_device_mode mode;
>  	void *devdata;
>  	int trips;
>  	unsigned long trips_disabled;	/* bitmap for disabled trips */
> @@ -264,6 +264,9 @@ struct thermal_zone_params {
>  	int num_tbps;	/* Number of tbp entries */
>  	struct thermal_bind_params *tbp;
>  
> +	/* Initial mode of this thermal zone device */
> +	enum thermal_device_mode initial_mode;
> +
>  	/*
>  	 * Sustainable power (heat) that this thermal zone can dissipate in
>  	 * mW
> @@ -395,6 +398,8 @@ int thermal_zone_bind_cooling_device(struct thermal_zone_device *, int,
>  				     unsigned int);
>  int thermal_zone_unbind_cooling_device(struct thermal_zone_device *, int,
>  				       struct thermal_cooling_device *);
> +int thermal_zone_device_set_mode(struct thermal_zone_device *tz,
> +				 enum thermal_device_mode mode);
>  void thermal_zone_device_update(struct thermal_zone_device *,
>  				enum thermal_notify_event);
>  
> @@ -426,6 +431,9 @@ static inline struct thermal_zone_device *thermal_zone_device_register(
>  static inline void thermal_zone_device_unregister(
>  	struct thermal_zone_device *tz)
>  { }
> +int thermal_zone_device_set_mode(struct thermal_zone_device *tz,
> +				 enum thermal_device_mode mode)
> +{ return -EINVAL; }
>  static inline struct thermal_cooling_device *
>  thermal_cooling_device_register(char *type, void *devdata,
>  	const struct thermal_cooling_device_ops *ops)
> @@ -465,4 +473,14 @@ static inline void thermal_notify_framework(struct thermal_zone_device *tz,
>  { }
>  #endif /* CONFIG_THERMAL */
>  
> +static inline int thermal_zone_device_enable(struct thermal_zone_device *tz)
> +{
> +	return thermal_zone_device_set_mode(tz, THERMAL_DEVICE_ENABLED);
> +}
> +
> +static inline int thermal_zone_device_disable(struct thermal_zone_device *tz)
> +{
> +	return thermal_zone_device_set_mode(tz, THERMAL_DEVICE_DISABLED);
> +}
> +
>  #endif /* __THERMAL_H__ */
> 


^ permalink raw reply	[flat|nested] 63+ messages in thread

* Re: [RFC v3 1/2] thermal: core: Let thermal zone device's mode be stored in its struct
  2020-04-17 16:20           ` [RFC v3 1/2] thermal: core: Let thermal zone device's mode be stored in its struct Andrzej Pietrasiewicz
  2020-04-17 20:44             ` Andy Shevchenko
  2020-04-19 11:38             ` Bartlomiej Zolnierkiewicz
@ 2020-05-23 21:24             ` Daniel Lezcano
  2020-05-25 19:35               ` Andrzej Pietrasiewicz
  2 siblings, 1 reply; 63+ messages in thread
From: Daniel Lezcano @ 2020-05-23 21:24 UTC (permalink / raw)
  To: Andrzej Pietrasiewicz, linux-pm
  Cc: Zhang Rui, Rafael J . Wysocki, Len Brown, Jiri Pirko,
	Ido Schimmel, David S . Miller, Peter Kaestle, Darren Hart,
	Andy Shevchenko, Support Opensource, Amit Kucheria, Shawn Guo,
	Sascha Hauer, Pengutronix Kernel Team, Fabio Estevam,
	NXP Linux Team, Allison Randal, Enrico Weigelt, Gayatri Kammela,
	Thomas Gleixner, linux-acpi, netdev, platform-driver-x86,
	linux-arm-kernel, kernel, Barlomiej Zolnierkiewicz

Hi Andrzej,

On 17/04/2020 18:20, Andrzej Pietrasiewicz wrote:
> Thermal zone devices' mode is stored in individual drivers. This patch
> changes it so that mode is stored in struct thermal_zone_device instead.
> 
> As a result all driver-specific variables storing the mode are not needed
> and are removed. Consequently, the get_mode() implementations have nothing
> to operate on and need to be removed, too.
> 
> Some thermal framework specific functions are introduced:
> 
> thermal_zone_device_get_mode()
> thermal_zone_device_set_mode()
> thermal_zone_device_enable()
> thermal_zone_device_disable()
> 
> thermal_zone_device_get_mode() and its "set" counterpart take tzd's lock
> and the "set" calls driver's set_mode() if provided, so the latter must
> not take this lock again. At the end of the "set"
> thermal_zone_device_update() is called so drivers don't need to repeat this
> invocation in their specific set_mode() implementations.
> 
> The scope of the above 4 functions is purposedly limited to the thermal
> framework and drivers are not supposed to call them. This encapsulation
> does not fully work at the moment for some drivers, though:
> 
> - platform/x86/acerhdf.c
> - drivers/thermal/imx_thermal.c
> - drivers/thermal/intel/intel_quark_dts_thermal.c
> - drivers/thermal/of-thermal.c
> 
> and they manipulate struct thermal_zone_device's members directly.
> 
> struct thermal_zone_params gains a new member called initial_mode, which
> is used to set tzd's mode at registration time.
> 
> The sysfs "mode" attribute is always exposed from now on, because all
> thermal zone devices now have their get_mode() implemented at the generic
> level and it is always available. Exposing "mode" doesn't hurt the drivers
> which don't provide their own set_mode(), because writing to "mode" will
> result in -EPERM, as expected.

The result is great, that is a nice cleanup of the thermal framework.

After review it appears there are still problems IMO, especially with
the suspend / resume path. The patch is big, it is a bit complex to
comment. I suggest to re-org the changes as following:

 - patch 1 : Add the four functions:

 * thermal_zone_device_set_mode()
 * thermal_zone_device_enable()
 * thermal_zone_device_disable()
 * thermal_zone_device_is_enabled()

*but* do not export thermal_zone_device_set_mode(), it must stay private
to the thermal framework ATM.

 - patch 2 : Add the mode THERMAL_DEVICE_SUSPENDED

In the thermal_pm_notify() in the:

 - PM_SUSPEND_PREPARE case, set the mode to THERMAL_DEVICE_SUSPENDED if
the mode is THERMAL_DEVICE_ENABLED

 - PM_POST_SUSPEND case, set the mode to THERMAL_DEVICE_ENABLED, if the
mode is THERMAL_DEVICE_SUSPENDED

 - patch 3 : Change the monitor function

Change monitor_thermal_zone() function to set the polling to zero if the
mode is THERMAL_DEVICE_DISABLED

 - patch 4 : Do the changes to remove get_mode() ops

Make sure there is no access to tz->mode from the drivers anymore but
use of the functions of patch 1. IMO, this is the tricky part because a
part of the drivers are not calling the update after setting the mode
while the function thermal_zone_device_enable()/disable() call update
via the thermal_zone_device_set_mode(), so we must be sure to not break
anything.

 - patch 5 : Do the changes to remove set_mode() ops users

As the patch 3 sets the polling to zero, the routine in the driver
setting the polling to zero is no longer needed (eg. in the mellanox
driver). I expect int300 to be the last user of this ops, hopefully we
can find a way to get rid of the specific call done inside and then
remove the ops.

The initial_mode approach looks hackish, I suggest to make the default
the thermal zone disabled after creating and then explicitly enable it.
Note that is what do a lot of drivers already.

Hopefully, these changes are git-bisect safe.

Does it make sense ?












-- 
<http://www.linaro.org/> Linaro.org │ Open source software for ARM SoCs

Follow Linaro:  <http://www.facebook.com/pages/Linaro> Facebook |
<http://twitter.com/#!/linaroorg> Twitter |
<http://www.linaro.org/linaro-blog/> Blog

^ permalink raw reply	[flat|nested] 63+ messages in thread

* Re: [RFC v3 1/2] thermal: core: Let thermal zone device's mode be stored in its struct
  2020-05-23 21:24             ` Daniel Lezcano
@ 2020-05-25 19:35               ` Andrzej Pietrasiewicz
  2020-05-25 22:08                 ` Daniel Lezcano
  0 siblings, 1 reply; 63+ messages in thread
From: Andrzej Pietrasiewicz @ 2020-05-25 19:35 UTC (permalink / raw)
  To: Daniel Lezcano, linux-pm
  Cc: Zhang Rui, Rafael J . Wysocki, Len Brown, Jiri Pirko,
	Ido Schimmel, David S . Miller, Peter Kaestle, Darren Hart,
	Andy Shevchenko, Support Opensource, Amit Kucheria, Shawn Guo,
	Sascha Hauer, Pengutronix Kernel Team, Fabio Estevam,
	NXP Linux Team, Allison Randal, Enrico Weigelt, Gayatri Kammela,
	Thomas Gleixner, linux-acpi, netdev, platform-driver-x86,
	linux-arm-kernel, kernel, Barlomiej Zolnierkiewicz

Hi Daniel,

W dniu 23.05.2020 o 23:24, Daniel Lezcano pisze:
> Hi Andrzej,
> 
> On 17/04/2020 18:20, Andrzej Pietrasiewicz wrote:
>> Thermal zone devices' mode is stored in individual drivers. This patch
>> changes it so that mode is stored in struct thermal_zone_device instead.
>>
>> As a result all driver-specific variables storing the mode are not needed
>> and are removed. Consequently, the get_mode() implementations have nothing
>> to operate on and need to be removed, too.
>>
>> Some thermal framework specific functions are introduced:
>>
>> thermal_zone_device_get_mode()
>> thermal_zone_device_set_mode()
>> thermal_zone_device_enable()
>> thermal_zone_device_disable()
>>
>> thermal_zone_device_get_mode() and its "set" counterpart take tzd's lock
>> and the "set" calls driver's set_mode() if provided, so the latter must
>> not take this lock again. At the end of the "set"
>> thermal_zone_device_update() is called so drivers don't need to repeat this
>> invocation in their specific set_mode() implementations.
>>
>> The scope of the above 4 functions is purposedly limited to the thermal
>> framework and drivers are not supposed to call them. This encapsulation
>> does not fully work at the moment for some drivers, though:
>>
>> - platform/x86/acerhdf.c
>> - drivers/thermal/imx_thermal.c
>> - drivers/thermal/intel/intel_quark_dts_thermal.c
>> - drivers/thermal/of-thermal.c
>>
>> and they manipulate struct thermal_zone_device's members directly.
>>
>> struct thermal_zone_params gains a new member called initial_mode, which
>> is used to set tzd's mode at registration time.
>>
>> The sysfs "mode" attribute is always exposed from now on, because all
>> thermal zone devices now have their get_mode() implemented at the generic
>> level and it is always available. Exposing "mode" doesn't hurt the drivers
>> which don't provide their own set_mode(), because writing to "mode" will
>> result in -EPERM, as expected.
> 
> The result is great, that is a nice cleanup of the thermal framework.
> 
> After review it appears there are still problems IMO, especially with
> the suspend / resume path. The patch is big, it is a bit complex to
> comment. I suggest to re-org the changes as following:
> 
>   - patch 1 : Add the four functions:
> 
>   * thermal_zone_device_set_mode()
>   * thermal_zone_device_enable()
>   * thermal_zone_device_disable()
>   * thermal_zone_device_is_enabled()
> 
> *but* do not export thermal_zone_device_set_mode(), it must stay private
> to the thermal framework ATM.

Not exporting thermal_zone_device_set_mode() implies not exporting
thermal_zone_device_enable()/thermal_zone_device_disable() because they
are implemented in terms of the former. Or do you have a different idea?

> 
>   - patch 2 : Add the mode THERMAL_DEVICE_SUSPENDED
> 
> In the thermal_pm_notify() in the:
> 
>   - PM_SUSPEND_PREPARE case, set the mode to THERMAL_DEVICE_SUSPENDED if
> the mode is THERMAL_DEVICE_ENABLED
> 
>   - PM_POST_SUSPEND case, set the mode to THERMAL_DEVICE_ENABLED, if the
> mode is THERMAL_DEVICE_SUSPENDED
> 
>   - patch 3 : Change the monitor function
> 
> Change monitor_thermal_zone() function to set the polling to zero if the
> mode is THERMAL_DEVICE_DISABLED

So we assume this: if a driver creates a tz which is initially ENABLED,
it will be polled. If a driver creates a tz which is initially DISABLED
(which is what you suggest the drivers should be doing, but not all of them
do), it won't be polled unless the driver explicitly enables its tz.

Am I concluding right that a suspended device will remain polled? Is it ok?

> 
>   - patch 4 : Do the changes to remove get_mode() ops
> 
> Make sure there is no access to tz->mode from the drivers anymore but
> use of the functions of patch 1. IMO, this is the tricky part because a
> part of the drivers are not calling the update after setting the mode
> while the function thermal_zone_device_enable()/disable() call update
> via the thermal_zone_device_set_mode(), so we must be sure to not break
> anything.

Ah, I guess now is the time to make the functions from patch 1 exported?

Ensuring no driver accesses tz->mode directly might be tricky, indeed.
If it can be shown that calling the update doesn't hurt a particular driver,
it can be converted to use the helpers instead of manipulating tz->mode
directly. If, however, it does make a difference then it all depends and
getting rid of accessing tz->mode directly might require help from the
respective maintainers.

This also calls for storing tz's mode in struct thermal_zone_device
rather than in individual drivers. In fact it seems the purpose
of ->get_mode() is to produce the state stored internally in drivers.
Removing ->get_mode() requires changing the place where the state is
stored. struct thermal_zone_device seems most appropriate. So this patch
is not going to be small.

Once we start storing tz's state in struct thermal_zone_device the
->set_mode() implementations need to be changed, too. To me it seems
awkward to split this change in two patches: if we keep the changes
split then in patch 4 we need to introduce code which implements
->set_mode() in terms of the new state location, only to remove it
in the very next patch.

While we are at it some drivers, namely acpi/thermal and int3400 store
their mode in an int rather than enum thermal_device_mode. So maybe
changing this should go even before patch 4? acerhdf does not store
its mode at all and on top of it it wants to manipulate the polling
delay directly and it has a module parameter which specifies it.

> 
>   - patch 5 : Do the changes to remove set_mode() ops users
> 
> As the patch 3 sets the polling to zero, the routine in the driver
> setting the polling to zero is no longer needed (eg. in the mellanox
> driver). I expect int300 to be the last user of this ops, hopefully we
> can find a way to get rid of the specific call done inside and then
> remove the ops.

acerhdf wants ->set_mode() desperately.

> 
> The initial_mode approach looks hackish, I suggest to make the default
> the thermal zone disabled after creating and then explicitly enable it.

Is it needed in drivers which create their thermal zone enabled?

Regards,

Andrzej

^ permalink raw reply	[flat|nested] 63+ messages in thread

* Re: [RFC v3 1/2] thermal: core: Let thermal zone device's mode be stored in its struct
  2020-05-25 19:35               ` Andrzej Pietrasiewicz
@ 2020-05-25 22:08                 ` Daniel Lezcano
  0 siblings, 0 replies; 63+ messages in thread
From: Daniel Lezcano @ 2020-05-25 22:08 UTC (permalink / raw)
  To: Andrzej Pietrasiewicz, linux-pm
  Cc: Zhang Rui, Rafael J . Wysocki, Len Brown, Jiri Pirko,
	Ido Schimmel, David S . Miller, Peter Kaestle, Darren Hart,
	Andy Shevchenko, Support Opensource, Amit Kucheria, Shawn Guo,
	Sascha Hauer, Pengutronix Kernel Team, Fabio Estevam,
	NXP Linux Team, Allison Randal, Enrico Weigelt, Gayatri Kammela,
	Thomas Gleixner, linux-acpi, netdev, platform-driver-x86,
	linux-arm-kernel, kernel, Barlomiej Zolnierkiewicz

On 25/05/2020 21:35, Andrzej Pietrasiewicz wrote:
> Hi Daniel,
> 
> W dniu 23.05.2020 o 23:24, Daniel Lezcano pisze:
>> Hi Andrzej,
>>
>> On 17/04/2020 18:20, Andrzej Pietrasiewicz wrote:
>>> Thermal zone devices' mode is stored in individual drivers. This patch
>>> changes it so that mode is stored in struct thermal_zone_device instead.
>>>
>>> As a result all driver-specific variables storing the mode are not
>>> needed
>>> and are removed. Consequently, the get_mode() implementations have
>>> nothing
>>> to operate on and need to be removed, too.
>>>
>>> Some thermal framework specific functions are introduced:
>>>
>>> thermal_zone_device_get_mode()
>>> thermal_zone_device_set_mode()
>>> thermal_zone_device_enable()
>>> thermal_zone_device_disable()
>>>
>>> thermal_zone_device_get_mode() and its "set" counterpart take tzd's lock
>>> and the "set" calls driver's set_mode() if provided, so the latter must
>>> not take this lock again. At the end of the "set"
>>> thermal_zone_device_update() is called so drivers don't need to
>>> repeat this
>>> invocation in their specific set_mode() implementations.
>>>
>>> The scope of the above 4 functions is purposedly limited to the thermal
>>> framework and drivers are not supposed to call them. This encapsulation
>>> does not fully work at the moment for some drivers, though:
>>>
>>> - platform/x86/acerhdf.c
>>> - drivers/thermal/imx_thermal.c
>>> - drivers/thermal/intel/intel_quark_dts_thermal.c
>>> - drivers/thermal/of-thermal.c
>>>
>>> and they manipulate struct thermal_zone_device's members directly.
>>>
>>> struct thermal_zone_params gains a new member called initial_mode, which
>>> is used to set tzd's mode at registration time.
>>>
>>> The sysfs "mode" attribute is always exposed from now on, because all
>>> thermal zone devices now have their get_mode() implemented at the
>>> generic
>>> level and it is always available. Exposing "mode" doesn't hurt the
>>> drivers
>>> which don't provide their own set_mode(), because writing to "mode" will
>>> result in -EPERM, as expected.
>>
>> The result is great, that is a nice cleanup of the thermal framework.
>>
>> After review it appears there are still problems IMO, especially with
>> the suspend / resume path. The patch is big, it is a bit complex to
>> comment. I suggest to re-org the changes as following:
>>
>>   - patch 1 : Add the four functions:
>>
>>   * thermal_zone_device_set_mode()
>>   * thermal_zone_device_enable()
>>   * thermal_zone_device_disable()
>>   * thermal_zone_device_is_enabled()
>>
>> *but* do not export thermal_zone_device_set_mode(), it must stay private
>> to the thermal framework ATM.
> 
> Not exporting thermal_zone_device_set_mode() implies not exporting
> thermal_zone_device_enable()/thermal_zone_device_disable() because they
> are implemented in terms of the former. Or do you have a different idea?

I meant no inline for them but as below:

in .h

extern int thermal_zone_device_enable();
extern int thermal_zone_device_disable();
extern int thermal_zone_device_is_enabled();

in .c

static int thermal_zone_device_set_mode()
{
	...
}

int thermal_zone_device_enable()
{
	thermal_zone_device_set_mode();
}
EXPORT_SYMBOL_GPL(thermal_zone_device_enable);


>>   - patch 2 : Add the mode THERMAL_DEVICE_SUSPENDED
>>
>> In the thermal_pm_notify() in the:
>>
>>   - PM_SUSPEND_PREPARE case, set the mode to THERMAL_DEVICE_SUSPENDED if
>> the mode is THERMAL_DEVICE_ENABLED
>>
>>   - PM_POST_SUSPEND case, set the mode to THERMAL_DEVICE_ENABLED, if the
>> mode is THERMAL_DEVICE_SUSPENDED
>>
>>   - patch 3 : Change the monitor function
>>
>> Change monitor_thermal_zone() function to set the polling to zero if the
>> mode is THERMAL_DEVICE_DISABLED
> 
> So we assume this: if a driver creates a tz which is initially ENABLED,
> it will be polled. If a driver creates a tz which is initially DISABLED
> (which is what you suggest the drivers should be doing, but not all of them
> do), it won't be polled unless the driver explicitly enables its tz.

Yes.

> Am I concluding right that a suspended device will remain polled? Is it ok?

Actually it is not ok but AFAICT, it is the current behavior. The
polling do not stop but the 'in_suspend' prevent an update. I thought we
can post-pone the suspend case later when the ENABLED/DISABLED changes
are consolidated, so SUSPENDED will act as DISABLED.

>>   - patch 4 : Do the changes to remove get_mode() ops
>>
>> Make sure there is no access to tz->mode from the drivers anymore but
>> use of the functions of patch 1. IMO, this is the tricky part because a
>> part of the drivers are not calling the update after setting the mode
>> while the function thermal_zone_device_enable()/disable() call update
>> via the thermal_zone_device_set_mode(), so we must be sure to not break
>> anything.
> 
> Ah, I guess now is the time to make the functions from patch 1 exported?

Yes :)

> Ensuring no driver accesses tz->mode directly might be tricky, indeed.
> If it can be shown that calling the update doesn't hurt a particular
> driver,
> it can be converted to use the helpers instead of manipulating tz->mode
> directly. If, however, it does make a difference then it all depends and
> getting rid of accessing tz->mode directly might require help from the
> respective maintainers.

Agree.

> This also calls for storing tz's mode in struct thermal_zone_device
> rather than in individual drivers. In fact it seems the purpose
> of ->get_mode() is to produce the state stored internally in drivers.
> Removing ->get_mode() requires changing the place where the state is
> stored. struct thermal_zone_device seems most appropriate. So this patch
> is not going to be small.

Yes, the patch can be big. It is fine if the changes are only to replace
tz->mode by their respective disable/enable/is_enabled functions. More
complex changes can be separate.

> Once we start storing tz's state in struct thermal_zone_device the
> ->set_mode() implementations need to be changed, too. To me it seems
> awkward to split this change in two patches: if we keep the changes
> split then in patch 4 we need to introduce code which implements
> ->set_mode() in terms of the new state location, only to remove it
> in the very next patch.

Yes, it is a valid point. May be you can do the changes in two patches
to see the results in terms of complexity for the review process, then
decide if it is worth to merge them before sending.

> While we are at it some drivers, namely acpi/thermal and int3400 store
> their mode in an int rather than enum thermal_device_mode. So maybe
> changing this should go even before patch 4?

I agree.

> acerhdf does not store
> its mode at all and on top of it it wants to manipulate the polling
> delay directly and it has a module parameter which specifies it.



>>   - patch 5 : Do the changes to remove set_mode() ops users
>>
>> As the patch 3 sets the polling to zero, the routine in the driver
>> setting the polling to zero is no longer needed (eg. in the mellanox
>> driver). I expect int300 to be the last user of this ops, hopefully we
>> can find a way to get rid of the specific call done inside and then
>> remove the ops.
> 
> acerhdf wants ->set_mode() desperately.

Yes, there is a couple of drivers which requires for the moment to keep
the ops->set_mode to be called: int3400 and acerhdf. Both of them will
be greatly simplified with the DISABLED / ENABLED changes.

>> The initial_mode approach looks hackish, I suggest to make the default
>> the thermal zone disabled after creating and then explicitly enable it.
> 
> Is it needed in drivers which create their thermal zone enabled?

IMO, yes. We are doing changes with a code prone to issues, so making
the steps: creation + enable will make things more clear. For instance,
the clk framework do the same.


-- 
<http://www.linaro.org/> Linaro.org │ Open source software for ARM SoCs

Follow Linaro:  <http://www.facebook.com/pages/Linaro> Facebook |
<http://twitter.com/#!/linaroorg> Twitter |
<http://www.linaro.org/linaro-blog/> Blog

^ permalink raw reply	[flat|nested] 63+ messages in thread

end of thread, back to index

Thread overview: 63+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2020-04-07 17:49 [RFC 0/8] Stop monitoring disabled devices Andrzej Pietrasiewicz
2020-04-07 17:49 ` [RFC 1/8] thermal: int3400_thermal: Statically initialize .get_mode()/.set_mode() ops Andrzej Pietrasiewicz
     [not found]   ` <CGME20200415091204eucas1p1983548c2db52d8d0c2a5367034ec80dd@eucas1p1.samsung.com>
2020-04-15  9:12     ` Bartlomiej Zolnierkiewicz
2020-04-07 17:49 ` [RFC 2/8] thermal: Properly handle mode values in .set_mode() Andrzej Pietrasiewicz
     [not found]   ` <CGME20200415100543eucas1p24e24293da39844ca8791db86af5365a7@eucas1p2.samsung.com>
2020-04-15 10:05     ` Bartlomiej Zolnierkiewicz
2020-04-07 17:49 ` [RFC 3/8] thermal: Store thermal mode in a dedicated enum Andrzej Pietrasiewicz
     [not found]   ` <CGME20200415100944eucas1p1dcfeb784e790ca2fc3417fd2797e3f5d@eucas1p1.samsung.com>
2020-04-15 10:09     ` Bartlomiej Zolnierkiewicz
2020-04-07 17:49 ` [RFC 4/8] thermal: core: Introduce THERMAL_DEVICE_INITIAL Andrzej Pietrasiewicz
2020-04-07 17:49 ` [RFC 5/8] thermal: core: Monitor thermal zone after mode change Andrzej Pietrasiewicz
2020-04-07 17:49 ` [RFC 6/8] thermal: Set initial state to THERMAL_DEVICE_INITIAL Andrzej Pietrasiewicz
2020-04-07 17:49 ` [RFC 7/8] thermal: of: Monitor thermal zone after enabling it Andrzej Pietrasiewicz
     [not found]   ` <CGME20200415101829eucas1p18e21324d3c39926fffc6c8b5dc52f206@eucas1p1.samsung.com>
2020-04-15 10:18     ` Bartlomiej Zolnierkiewicz
2020-04-07 17:49 ` [RFC 8/8] thermal: Stop polling DISABLED thermal devices Andrzej Pietrasiewicz
2020-04-09 10:29 ` [RFC 0/8] Stop monitoring disabled devices Daniel Lezcano
2020-04-09 11:10   ` Andrzej Pietrasiewicz
     [not found]     ` <CGME20200415104010eucas1p101278e53e34a2e56dfc7c82b533a9122@eucas1p1.samsung.com>
2020-04-15 10:40       ` Bartlomiej Zolnierkiewicz
2020-04-17 16:23         ` Andrzej Pietrasiewicz
2020-04-19 11:42           ` Bartlomiej Zolnierkiewicz
2020-04-17 21:11         ` Peter Kästle
2020-04-14 18:00   ` [RFC v2 0/9] " Andrzej Pietrasiewicz
2020-04-14 18:00     ` [RFC v2 1/9] thermal: int3400_thermal: Statically initialize .get_mode()/.set_mode() ops Andrzej Pietrasiewicz
2020-04-15  9:23       ` Daniel Lezcano
2020-04-14 18:00     ` [RFC v2 2/9] thermal: Eliminate an always-false condition Andrzej Pietrasiewicz
2020-04-14 18:00     ` [RFC v2 3/9] thermal: Properly handle mode values in .set_mode() Andrzej Pietrasiewicz
2020-04-14 22:14       ` Daniel Lezcano
2020-04-14 18:01     ` [RFC v2 4/9] thermal: core: Let thermal zone device's mode be stored in its struct Andrzej Pietrasiewicz
2020-04-14 22:30       ` Daniel Lezcano
2020-04-14 18:01     ` [RFC v2 5/9] thermal: Store mode in thermal_zone_device Andrzej Pietrasiewicz
2020-04-15 10:55       ` Daniel Lezcano
2020-04-17 16:20         ` [RFC v3 0/2] Stop monitoring disabled devices Andrzej Pietrasiewicz
2020-04-17 16:20           ` [RFC v3 1/2] thermal: core: Let thermal zone device's mode be stored in its struct Andrzej Pietrasiewicz
2020-04-17 20:44             ` Andy Shevchenko
2020-04-19 11:38             ` Bartlomiej Zolnierkiewicz
2020-04-19 13:10               ` Bartlomiej Zolnierkiewicz
2020-04-20 18:17                 ` [PATCH 0/2] Stop monitoring disabled devices Andrzej Pietrasiewicz
2020-04-20 18:17                   ` [PATCH 1/2] thermal: core: Let thermal zone device's mode be stored in its struct Andrzej Pietrasiewicz
2020-04-22  7:49                     ` kbuild test robot
2020-04-22 17:14                       ` Andrzej Pietrasiewicz
2020-04-22 17:03                     ` kbuild test robot
2020-04-22 17:15                       ` Andrzej Pietrasiewicz
2020-04-20 18:17                   ` [PATCH 2/2] thermal: core: Stop polling DISABLED thermal devices Andrzej Pietrasiewicz
2020-04-22 16:12                   ` [PATCH RESEND 1/2] thermal: core: Let thermal zone device's mode be stored in its struct Andrzej Pietrasiewicz
2020-04-23 14:39                     ` Bartlomiej Zolnierkiewicz
2020-04-23 16:57                       ` [PATCH v3 0/2] Stop monitoring disabled devices Andrzej Pietrasiewicz
2020-04-23 16:57                         ` [PATCH v3 1/2] thermal: core: Let thermal zone device's mode be stored in its struct Andrzej Pietrasiewicz
2020-05-04  7:00                           ` Bartlomiej Zolnierkiewicz
2020-04-23 16:57                         ` [PATCH v3 2/2] thermal: core: Stop polling DISABLED thermal devices Andrzej Pietrasiewicz
2020-04-24  9:03                           ` Zhang, Rui
2020-04-27 14:20                             ` Zhang, Rui
2020-04-27 18:34                               ` Andrzej Pietrasiewicz
2020-04-28 13:55                                 ` Zhang, Rui
2020-04-20 11:03               ` [RFC v3 1/2] thermal: core: Let thermal zone device's mode be stored in its struct Andrzej Pietrasiewicz
2020-04-20 18:19                 ` Andrzej Pietrasiewicz
2020-05-23 21:24             ` Daniel Lezcano
2020-05-25 19:35               ` Andrzej Pietrasiewicz
2020-05-25 22:08                 ` Daniel Lezcano
2020-04-17 16:20           ` [RFC v3 2/2] thermal: core: Stop polling DISABLED thermal devices Andrzej Pietrasiewicz
2020-04-19 13:50           ` [RFC v3 1/2] thermal: core: Let thermal zone device's mode be stored in its struct Peter Kästle
2020-04-14 18:01     ` [RFC v2 6/9] thermal: Remove get_mode() method Andrzej Pietrasiewicz
2020-04-14 18:01     ` [RFC v2 7/9] thermal: core: Monitor thermal zone after mode change Andrzej Pietrasiewicz
2020-04-14 18:01     ` [RFC v2 8/9] thermal: of: Monitor thermal zone after enabling it Andrzej Pietrasiewicz
2020-04-14 18:01     ` [RFC v2 9/9] thermal: core: Stop polling DISABLED thermal devices Andrzej Pietrasiewicz
2020-04-14 21:52     ` [RFC v2 0/9] Stop monitoring disabled devices Ezequiel Garcia

Linux-PM Archive on lore.kernel.org

Archives are clonable:
	git clone --mirror https://lore.kernel.org/linux-pm/0 linux-pm/git/0.git

	# If you have public-inbox 1.1+ installed, you may
	# initialize and index your mirror using the following commands:
	public-inbox-init -V2 linux-pm linux-pm/ https://lore.kernel.org/linux-pm \
		linux-pm@vger.kernel.org
	public-inbox-index linux-pm

Example config snippet for mirrors

Newsgroup available over NNTP:
	nntp://nntp.lore.kernel.org/org.kernel.vger.linux-pm


AGPL code for this site: git clone https://public-inbox.org/public-inbox.git