2023-01-05 08:37:53

by Alice Guo (OSS)

[permalink] [raw]
Subject: [PATCH v1 0/2] add device cooling

From: Alice Guo <[email protected]>

Anson Huang (2):
thermal: Add generic device cooling support
thermal: qoriq: Add device cooling support

drivers/thermal/Kconfig | 7 ++
drivers/thermal/Makefile | 1 +
drivers/thermal/device_cooling.c | 154 +++++++++++++++++++++++++++++++
drivers/thermal/qoriq_thermal.c | 83 ++++++++++++++++-
include/linux/device_cooling.h | 46 +++++++++
5 files changed, 290 insertions(+), 1 deletion(-)
create mode 100644 drivers/thermal/device_cooling.c
create mode 100644 include/linux/device_cooling.h

--
2.17.1


2023-01-05 08:40:13

by Alice Guo (OSS)

[permalink] [raw]
Subject: [PATCH v1 1/2] thermal: Add generic device cooling support

From: Anson Huang <[email protected]>

To compatible with previous implementation, add generic device
cooling support, each thermal zone will register a cooling
device, and when temperature exceed passive trip, the device
cooling driver will send out a system wide notification, each
device supporting cooling will need to register device cooling
and takes action when passive trip is exceeded;

Signed-off-by: Anson Huang <[email protected]>
Signed-off-by: Dong Aisheng <[email protected]>
Signed-off-by: Alice Guo <[email protected]>
---
drivers/thermal/Kconfig | 7 ++
drivers/thermal/Makefile | 1 +
drivers/thermal/device_cooling.c | 154 +++++++++++++++++++++++++++++++
include/linux/device_cooling.h | 46 +++++++++
4 files changed, 208 insertions(+)
create mode 100644 drivers/thermal/device_cooling.c
create mode 100644 include/linux/device_cooling.h

diff --git a/drivers/thermal/Kconfig b/drivers/thermal/Kconfig
index e052dae614eb..2625903b56f5 100644
--- a/drivers/thermal/Kconfig
+++ b/drivers/thermal/Kconfig
@@ -284,6 +284,13 @@ config K3_THERMAL

This includes temperature reading functionality.

+config DEVICE_THERMAL
+ tristate "generic device cooling support"
+ help
+ Support for device cooling.
+ It supports notification of crossing passive trip for devices,
+ devices need to do their own actions to cool down the SOC.
+
config MAX77620_THERMAL
tristate "Temperature sensor driver for Maxim MAX77620 PMIC"
depends on MFD_MAX77620
diff --git a/drivers/thermal/Makefile b/drivers/thermal/Makefile
index 2506c6c8ca83..77c4b2e525a4 100644
--- a/drivers/thermal/Makefile
+++ b/drivers/thermal/Makefile
@@ -46,6 +46,7 @@ obj-$(CONFIG_ARMADA_THERMAL) += armada_thermal.o
obj-$(CONFIG_IMX_THERMAL) += imx_thermal.o
obj-$(CONFIG_IMX_SC_THERMAL) += imx_sc_thermal.o
obj-$(CONFIG_IMX8MM_THERMAL) += imx8mm_thermal.o
+obj-$(CONFIG_DEVICE_THERMAL) += device_cooling.o
obj-$(CONFIG_MAX77620_THERMAL) += max77620_thermal.o
obj-$(CONFIG_QORIQ_THERMAL) += qoriq_thermal.o
obj-$(CONFIG_DA9062_THERMAL) += da9062-thermal.o
diff --git a/drivers/thermal/device_cooling.c b/drivers/thermal/device_cooling.c
new file mode 100644
index 000000000000..6bd668ee545e
--- /dev/null
+++ b/drivers/thermal/device_cooling.c
@@ -0,0 +1,154 @@
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * Copyright (C) 2013-2015 Freescale Semiconductor, Inc.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ *
+ * Copyright 2023 NXP
+ */
+
+#include <linux/module.h>
+#include <linux/thermal.h>
+#include <linux/err.h>
+#include <linux/slab.h>
+
+struct devfreq_cooling_device {
+ int id;
+ struct thermal_cooling_device *cool_dev;
+ unsigned int devfreq_state;
+};
+
+static DEFINE_IDR(devfreq_idr);
+static DEFINE_MUTEX(devfreq_cooling_lock);
+
+#define MAX_STATE 1
+
+static BLOCKING_NOTIFIER_HEAD(devfreq_cooling_chain_head);
+
+int register_devfreq_cooling_notifier(struct notifier_block *nb)
+{
+ return blocking_notifier_chain_register(
+ &devfreq_cooling_chain_head, nb);
+}
+EXPORT_SYMBOL_GPL(register_devfreq_cooling_notifier);
+
+int unregister_devfreq_cooling_notifier(struct notifier_block *nb)
+{
+ return blocking_notifier_chain_unregister(
+ &devfreq_cooling_chain_head, nb);
+}
+EXPORT_SYMBOL_GPL(unregister_devfreq_cooling_notifier);
+
+static int devfreq_cooling_notifier_call_chain(unsigned long val)
+{
+ return (blocking_notifier_call_chain(
+ &devfreq_cooling_chain_head, val, NULL)
+ == NOTIFY_BAD) ? -EINVAL : 0;
+}
+
+static int devfreq_set_cur_state(struct thermal_cooling_device *cdev,
+ unsigned long state)
+{
+ struct devfreq_cooling_device *devfreq_device = cdev->devdata;
+ int ret;
+
+ ret = devfreq_cooling_notifier_call_chain(state);
+ if (ret)
+ return -EINVAL;
+
+ devfreq_device->devfreq_state = state;
+
+ return 0;
+}
+
+static int devfreq_get_max_state(struct thermal_cooling_device *cdev,
+ unsigned long *state)
+{
+ *state = MAX_STATE;
+
+ return 0;
+}
+
+static int devfreq_get_cur_state(struct thermal_cooling_device *cdev,
+ unsigned long *state)
+{
+ struct devfreq_cooling_device *devfreq_device = cdev->devdata;
+
+ *state = devfreq_device->devfreq_state;
+
+ return 0;
+}
+
+static const struct thermal_cooling_device_ops devfreq_cooling_ops = {
+ .get_max_state = devfreq_get_max_state,
+ .get_cur_state = devfreq_get_cur_state,
+ .set_cur_state = devfreq_set_cur_state,
+};
+
+static int get_idr(struct idr *idr, int *id)
+{
+ int ret;
+
+ mutex_lock(&devfreq_cooling_lock);
+ ret = idr_alloc(idr, NULL, 0, 0, GFP_KERNEL);
+ mutex_unlock(&devfreq_cooling_lock);
+ if (unlikely(ret < 0))
+ return ret;
+ *id = ret;
+
+ return 0;
+}
+
+static void release_idr(struct idr *idr, int id)
+{
+ mutex_lock(&devfreq_cooling_lock);
+ idr_remove(idr, id);
+ mutex_unlock(&devfreq_cooling_lock);
+}
+
+struct thermal_cooling_device *devfreq_cooling_register(void)
+{
+ struct thermal_cooling_device *cool_dev;
+ struct devfreq_cooling_device *devfreq_dev = NULL;
+ char dev_name[THERMAL_NAME_LENGTH];
+ int ret = 0;
+
+ devfreq_dev = kzalloc(sizeof(struct devfreq_cooling_device),
+ GFP_KERNEL);
+ if (!devfreq_dev)
+ return ERR_PTR(-ENOMEM);
+
+ ret = get_idr(&devfreq_idr, &devfreq_dev->id);
+ if (ret) {
+ kfree(devfreq_dev);
+ return ERR_PTR(-EINVAL);
+ }
+
+ snprintf(dev_name, sizeof(dev_name), "thermal-devfreq-%d",
+ devfreq_dev->id);
+
+ cool_dev = thermal_cooling_device_register(dev_name, devfreq_dev,
+ &devfreq_cooling_ops);
+ if (!cool_dev) {
+ release_idr(&devfreq_idr, devfreq_dev->id);
+ kfree(devfreq_dev);
+ return ERR_PTR(-EINVAL);
+ }
+ devfreq_dev->cool_dev = cool_dev;
+ devfreq_dev->devfreq_state = 0;
+
+ return cool_dev;
+}
+EXPORT_SYMBOL_GPL(devfreq_cooling_register);
+
+void devfreq_cooling_unregister(struct thermal_cooling_device *cdev)
+{
+ struct devfreq_cooling_device *devfreq_dev = cdev->devdata;
+
+ thermal_cooling_device_unregister(devfreq_dev->cool_dev);
+ release_idr(&devfreq_idr, devfreq_dev->id);
+ kfree(devfreq_dev);
+}
+EXPORT_SYMBOL_GPL(devfreq_cooling_unregister);
diff --git a/include/linux/device_cooling.h b/include/linux/device_cooling.h
new file mode 100644
index 000000000000..83b709e7c893
--- /dev/null
+++ b/include/linux/device_cooling.h
@@ -0,0 +1,46 @@
+/* SPDX-License-Identifier: GPL-2.0 */
+/*
+ * Copyright (C) 2013-2015 Freescale Semiconductor, Inc.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ *
+ * Copyright 2023 NXP
+ */
+
+#ifndef __DEVICE_THERMAL_H__
+#define __DEVICE_THERMAL_H__
+
+#include <linux/thermal.h>
+
+#ifdef CONFIG_DEVICE_THERMAL
+int register_devfreq_cooling_notifier(struct notifier_block *nb);
+int unregister_devfreq_cooling_notifier(struct notifier_block *nb);
+struct thermal_cooling_device *devfreq_cooling_register(void);
+void devfreq_cooling_unregister(struct thermal_cooling_device *cdev);
+#else
+static inline
+int register_devfreq_cooling_notifier(struct notifier_block *nb)
+{
+ return 0;
+}
+
+static inline
+int unregister_devfreq_cooling_notifier(struct notifier_block *nb)
+{
+ return 0;
+}
+
+static inline
+struct thermal_cooling_device *devfreq_cooling_register(void)
+{
+ return ERR_PTR(-EINVAL);
+}
+
+static inline
+void devfreq_cooling_unregister(struct thermal_cooling_device *cdev)
+{
+}
+#endif
+#endif /* __DEVICE_THERMAL_H__ */
--
2.17.1

2023-01-05 09:00:45

by Alice Guo (OSS)

[permalink] [raw]
Subject: [PATCH v1 2/2] thermal: qoriq: Add device cooling support

From: Anson Huang <[email protected]>

Register device cooling for first thermal zone manually, when
temperature exceeds passive trip, system wide cooling notification
will be triggered.

Signed-off-by: Anson Huang <[email protected]>
Signed-off-by: Alice Guo <[email protected]>
Reviewed-by: Jacky Bai <[email protected]>
---
drivers/thermal/qoriq_thermal.c | 83 ++++++++++++++++++++++++++++++++-
1 file changed, 82 insertions(+), 1 deletion(-)

diff --git a/drivers/thermal/qoriq_thermal.c b/drivers/thermal/qoriq_thermal.c
index d111e218f362..3c21b2d184eb 100644
--- a/drivers/thermal/qoriq_thermal.c
+++ b/drivers/thermal/qoriq_thermal.c
@@ -3,6 +3,7 @@
// Copyright 2016 Freescale Semiconductor, Inc.

#include <linux/clk.h>
+#include <linux/device_cooling.h>
#include <linux/err.h>
#include <linux/io.h>
#include <linux/module.h>
@@ -27,6 +28,7 @@
#define TMSARA_V2 0xe
#define TMU_VER1 0x1
#define TMU_VER2 0x2
+#define TMU_TEMP_PASSIVE_COOL_DELTA 10000

#define REGS_TMR 0x000 /* Mode Register */
#define TMR_DISABLE 0x0
@@ -68,6 +70,10 @@
*/
struct qoriq_sensor {
int id;
+ struct thermal_zone_device *tzd;
+ int temp_passive;
+ int temp_critical;
+ struct thermal_cooling_device *cdev;
};

struct qoriq_tmu_data {
@@ -77,6 +83,12 @@ struct qoriq_tmu_data {
struct qoriq_sensor sensor[SITES_MAX];
};

+enum tmu_trip {
+ TMU_TRIP_PASSIVE,
+ TMU_TRIP_CRITICAL,
+ TMU_TRIP_NUM,
+};
+
static struct qoriq_tmu_data *qoriq_sensor_to_data(struct qoriq_sensor *s)
{
return container_of(s, struct qoriq_tmu_data, sensor[s->id]);
@@ -122,14 +134,53 @@ static int tmu_get_temp(struct thermal_zone_device *tz, int *temp)
return 0;
}

+static int tmu_get_trend(struct thermal_zone_device *tz, int trip,
+ enum thermal_trend *trend)
+
+{
+ struct qoriq_sensor *qsensor = tz->devdata;
+ int trip_temp;
+
+ if (!qsensor->tzd)
+ return 0;
+
+ trip_temp = (trip == TMU_TRIP_PASSIVE) ? qsensor->temp_passive :
+ qsensor->temp_critical;
+
+ if (qsensor->tzd->temperature >=
+ (trip_temp - TMU_TEMP_PASSIVE_COOL_DELTA))
+ *trend = THERMAL_TREND_RAISING;
+ else
+ *trend = THERMAL_TREND_DROPPING;
+
+ return 0;
+}
+
+static int tmu_set_trip_temp(struct thermal_zone_device *tz, int trip,
+ int temp)
+{
+ struct qoriq_sensor *qsensor = tz->devdata;
+
+ if (trip == TMU_TRIP_CRITICAL)
+ qsensor->temp_critical = temp;
+
+ if (trip == TMU_TRIP_PASSIVE)
+ qsensor->temp_passive = temp;
+
+ return 0;
+}
+
static const struct thermal_zone_device_ops tmu_tz_ops = {
.get_temp = tmu_get_temp,
+ .get_trend = tmu_get_trend,
+ .set_trip_temp = tmu_set_trip_temp,
};

static int qoriq_tmu_register_tmu_zone(struct device *dev,
struct qoriq_tmu_data *qdata)
{
int id;
+ const struct thermal_trip *trip;

if (qdata->ver == TMU_VER1) {
regmap_write(qdata->regmap, REGS_TMR,
@@ -158,10 +209,40 @@ static int qoriq_tmu_register_tmu_zone(struct device *dev,
return ret;
}

+ sensor->tzd = tzd;
+
if (devm_thermal_add_hwmon_sysfs(tzd))
dev_warn(dev,
"Failed to add hwmon sysfs attributes\n");
-
+ /* first thermal zone takes care of system-wide device cooling */
+ if (id == 0) {
+ sensor->cdev = devfreq_cooling_register();
+ if (IS_ERR(sensor->cdev)) {
+ ret = PTR_ERR(sensor->cdev);
+ pr_err("failed to register devfreq cooling device: %d\n",
+ ret);
+ return ret;
+ }
+
+ ret = thermal_zone_bind_cooling_device(sensor->tzd,
+ TMU_TRIP_PASSIVE,
+ sensor->cdev,
+ THERMAL_NO_LIMIT,
+ THERMAL_NO_LIMIT,
+ THERMAL_WEIGHT_DEFAULT);
+ if (ret) {
+ pr_err("binding zone %s with cdev %s failed:%d\n",
+ sensor->tzd->type,
+ sensor->cdev->type,
+ ret);
+ devfreq_cooling_unregister(sensor->cdev);
+ return ret;
+ }
+
+ trip = of_thermal_get_trip_points(sensor->tzd);
+ sensor->temp_passive = trip[0].temperature;
+ sensor->temp_critical = trip[1].temperature;
+ }
}

return 0;
--
2.17.1

2023-01-05 10:41:11

by Daniel Lezcano

[permalink] [raw]
Subject: Re: [PATCH v1 1/2] thermal: Add generic device cooling support

On 05/01/2023 09:22, Alice Guo (OSS) wrote:
> From: Anson Huang <[email protected]>
>
> To compatible with previous implementation, add generic device
> cooling support, each thermal zone will register a cooling
> device, and when temperature exceed passive trip, the device
> cooling driver will send out a system wide notification, each
> device supporting cooling will need to register device cooling
> and takes action when passive trip is exceeded;

Can you explain the use case you want to solve with this solution and
the limitations of the existing ones ?


--
<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

2023-01-05 11:02:02

by Alice Guo (OSS)

[permalink] [raw]
Subject: RE: [PATCH v1 1/2] thermal: Add generic device cooling support

Hi,

I did not reply in time. Sorry to bother you. Please ignore this patchset.

Best Regards,
Alice Guo

> -----Original Message-----
> From: Daniel Lezcano <[email protected]>
> Sent: Thursday, January 5, 2023 5:59 PM
> To: Alice Guo (OSS) <[email protected]>; [email protected];
> [email protected]; [email protected]; Aisheng Dong
> <[email protected]>; [email protected]; Leo Li
> <[email protected]>
> Cc: [email protected]; [email protected];
> [email protected]
> Subject: Re: [PATCH v1 1/2] thermal: Add generic device cooling support
>
> On 05/01/2023 09:22, Alice Guo (OSS) wrote:
> > From: Anson Huang <[email protected]>
> >
> > To compatible with previous implementation, add generic device cooling
> > support, each thermal zone will register a cooling device, and when
> > temperature exceed passive trip, the device cooling driver will send
> > out a system wide notification, each device supporting cooling will
> > need to register device cooling and takes action when passive trip is
> > exceeded;
>
> Can you explain the use case you want to solve with this solution and the
> limitations of the existing ones ?
>
>
> --
> <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