diff mbox series

[v1,1/2] thermal: Add generic device cooling support

Message ID 20230105082234.16962-2-alice.guo@oss.nxp.com (mailing list archive)
State New, archived
Delegated to: Daniel Lezcano
Headers show
Series add device cooling | expand

Commit Message

Alice Guo (OSS) Jan. 5, 2023, 8:22 a.m. UTC
From: Anson Huang <Anson.Huang@nxp.com>

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 <Anson.Huang@nxp.com>
Signed-off-by: Dong Aisheng <aisheng.dong@nxp.com>
Signed-off-by: Alice Guo <alice.guo@nxp.com>
---
 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

Comments

Daniel Lezcano Jan. 5, 2023, 9:59 a.m. UTC | #1
On 05/01/2023 09:22, Alice Guo (OSS) wrote:
> From: Anson Huang <Anson.Huang@nxp.com>
> 
> 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 ?
Alice Guo (OSS) Jan. 5, 2023, 10:07 a.m. UTC | #2
Hi,

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

Best Regards,
Alice Guo

> -----Original Message-----
> From: Daniel Lezcano <daniel.lezcano@linaro.org>
> Sent: Thursday, January 5, 2023 5:59 PM
> To: Alice Guo (OSS) <alice.guo@oss.nxp.com>; rafael@kernel.org;
> amitk@kernel.org; rui.zhang@intel.com; Aisheng Dong
> <aisheng.dong@nxp.com>; shawnguo@kernel.org; Leo Li
> <leoyang.li@nxp.com>
> Cc: linux-arm-kernel@lists.infradead.org; linux-pm@vger.kernel.org;
> linux-kernel@vger.kernel.org
> 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 <Anson.Huang@nxp.com>
> >
> > 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
diff mbox series

Patch

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__ */