Linux Power Management development
 help / color / mirror / Atom feed
* [PATCH 27/34] Exynos: Add missing dependency
From: Zhang Rui @ 2012-12-02 14:45 UTC (permalink / raw)
  To: linux-pm; +Cc: Zhang Rui
In-Reply-To: <1354459508-3707-1-git-send-email-rui.zhang@intel.com>

CPU_FREQ_TABLE depends on CPU_FREQ. Selecting CPU_FREQ_TABLE without checking
for dependencies gives the following compilation warnings:
warning: (ARCH_TEGRA_2x_SOC && ARCH_TEGRA_3x_SOC && UX500_SOC_DB8500 &&
CPU_THERMAL && EXYNOS_THERMAL) selects CPU_FREQ_TABLE which has unmet
direct dependencies (ARCH_HAS_CPUFREQ && CPU_FREQ)

Based-on-patch-by: Sachin Kamat <sachin.kamat@linaro.org>
Signed-off-by: Zhang Rui <rui.zhang@intel.com>
---
 drivers/thermal/Kconfig |    2 +-
 1 files changed, 1 insertions(+), 1 deletions(-)

diff --git a/drivers/thermal/Kconfig b/drivers/thermal/Kconfig
index 937a23d..99b6587 100644
--- a/drivers/thermal/Kconfig
+++ b/drivers/thermal/Kconfig
@@ -96,7 +96,7 @@ config RCAR_THERMAL
 config EXYNOS_THERMAL
 	tristate "Temperature sensor on Samsung EXYNOS"
 	depends on (ARCH_EXYNOS4 || ARCH_EXYNOS5)
-	select CPU_FREQ_TABLE
+	depends on CPU_THERMAL
 	help
 	  If you say yes here you get support for TMU (Thermal Managment
 	  Unit) on SAMSUNG EXYNOS series of SoC.
-- 
1.7.7.6


^ permalink raw reply related

* [PATCH 26/34] Refactor drivers/thermal/Kconfig
From: Zhang Rui @ 2012-12-02 14:45 UTC (permalink / raw)
  To: linux-pm; +Cc: Zhang Rui
In-Reply-To: <1354459508-3707-1-git-send-email-rui.zhang@intel.com>

Signed-off-by: Zhang Rui <rui.zhang@intel.com>
---
 drivers/thermal/Kconfig |  103 +++++++++++++++++++++++------------------------
 1 files changed, 51 insertions(+), 52 deletions(-)

diff --git a/drivers/thermal/Kconfig b/drivers/thermal/Kconfig
index 266c15e..937a23d 100644
--- a/drivers/thermal/Kconfig
+++ b/drivers/thermal/Kconfig
@@ -13,15 +13,62 @@ menuconfig THERMAL
 	  All platforms with ACPI thermal support can use this driver.
 	  If you want this support, you should say Y or M here.
 
+if THERMAL
+
 config THERMAL_HWMON
 	bool
-	depends on THERMAL
 	depends on HWMON=y || HWMON=THERMAL
 	default y
 
+choice
+	prompt "Default Thermal governor"
+	default THERMAL_DEFAULT_GOV_STEP_WISE
+	help
+	  This option sets which thermal governor shall be loaded at
+	  startup. If in doubt, select 'step_wise'.
+
+config THERMAL_DEFAULT_GOV_STEP_WISE
+	bool "step_wise"
+	select STEP_WISE
+	help
+	  Use the step_wise governor as default. This throttles the
+	  devices one step at a time.
+
+config THERMAL_DEFAULT_GOV_FAIR_SHARE
+	bool "fair_share"
+	select FAIR_SHARE
+	help
+	  Use the fair_share governor as default. This throttles the
+	  devices based on their 'contribution' to a zone. The
+	  contribution should be provided through platform data.
+
+config THERMAL_DEFAULT_GOV_USER_SPACE
+	bool "user_space"
+	select USER_SPACE
+	help
+	  Select this if you want to let the user space manage the
+	  lpatform thermals.
+
+endchoice
+
+config FAIR_SHARE
+	bool "Fair-share thermal governor"
+	help
+	  Enable this to manage platform thermals using fair-share governor.
+
+config STEP_WISE
+	bool "Step_wise thermal governor"
+	help
+	  Enable this to manage platform thermals using a simple linear
+
+config USER_SPACE
+	bool "User_space thermal governor"
+	help
+	  Enable this to let the user space manage the platform thermals.
+
 config CPU_THERMAL
 	bool "generic cpu cooling support"
-	depends on THERMAL && CPU_FREQ
+	depends on CPU_FREQ
 	select CPU_FREQ_TABLE
 	help
 	  This implements the generic cpu cooling mechanism through frequency
@@ -33,7 +80,6 @@ config CPU_THERMAL
 
 config SPEAR_THERMAL
 	bool "SPEAr thermal sensor driver"
-	depends on THERMAL
 	depends on PLAT_SPEAR
 	depends on OF
 	help
@@ -42,7 +88,6 @@ config SPEAR_THERMAL
 
 config RCAR_THERMAL
 	tristate "Renesas R-Car thermal driver"
-	depends on THERMAL
 	depends on ARCH_SHMOBILE
 	help
 	  Enable this to plug the R-Car thermal sensor driver into the Linux
@@ -50,57 +95,11 @@ config RCAR_THERMAL
 
 config EXYNOS_THERMAL
 	tristate "Temperature sensor on Samsung EXYNOS"
-	depends on (ARCH_EXYNOS4 || ARCH_EXYNOS5) && THERMAL
+	depends on (ARCH_EXYNOS4 || ARCH_EXYNOS5)
 	select CPU_FREQ_TABLE
 	help
 	  If you say yes here you get support for TMU (Thermal Managment
 	  Unit) on SAMSUNG EXYNOS series of SoC.
 
-config FAIR_SHARE
-	bool "Fair-share thermal governor"
-	depends on THERMAL
-	help
-	  Enable this to manage platform thermals using fair-share governor.
-
-config STEP_WISE
-	bool "Step_wise thermal governor"
-	depends on THERMAL
-	help
-	  Enable this to manage platform thermals using a simple linear
-
-config USER_SPACE
-	bool "User_space thermal governor"
-	depends on THERMAL
-	help
-	  Enable this to let the user space manage the platform thermals.
-
-choice
-	prompt "Default Thermal governor"
-	depends on THERMAL
-	default THERMAL_DEFAULT_GOV_STEP_WISE
-	help
-	  This option sets which thermal governor shall be loaded at
-	  startup. If in doubt, select 'step_wise'.
-
-config THERMAL_DEFAULT_GOV_STEP_WISE
-	bool "step_wise"
-	select STEP_WISE
-	help
-	  Use the step_wise governor as default. This throttles the
-	  devices one step at a time.
-
-config THERMAL_DEFAULT_GOV_FAIR_SHARE
-	bool "fair_share"
-	select FAIR_SHARE
-	help
-	  Use the fair_share governor as default. This throttles the
-	  devices based on their 'contribution' to a zone. The
-	  contribution should be provided through platform data.
 
-config THERMAL_DEFAULT_GOV_USER_SPACE
-	bool "user_space"
-	select USER_SPACE
-	help
-	  Select this if you want to let the user space manage the
-	  platform thermals.
-endchoice
+endif
-- 
1.7.7.6


^ permalink raw reply related

* [PATCH 25/34] thermal: cpu_cooling: Make 'notify_device' static
From: Zhang Rui @ 2012-12-02 14:44 UTC (permalink / raw)
  To: linux-pm; +Cc: Sachin Kamat, Zhang Rui
In-Reply-To: <1354459508-3707-1-git-send-email-rui.zhang@intel.com>

From: Sachin Kamat <sachin.kamat@linaro.org>

Silences the following sparse warning:

drivers/thermal/cpu_cooling.c:67:31: warning:
symbol 'notify_device' was not declared. Should it be static?

Signed-off-by: Sachin Kamat <sachin.kamat@linaro.org>
Signed-off-by: Zhang Rui <rui.zhang@intel.com>
---
 drivers/thermal/cpu_cooling.c |    2 +-
 1 files changed, 1 insertions(+), 1 deletions(-)

diff --git a/drivers/thermal/cpu_cooling.c b/drivers/thermal/cpu_cooling.c
index 392d57d..6f94c2c 100644
--- a/drivers/thermal/cpu_cooling.c
+++ b/drivers/thermal/cpu_cooling.c
@@ -64,7 +64,7 @@ static unsigned int cpufreq_dev_count;
 
 /* notify_table passes value to the CPUFREQ_ADJUST callback function. */
 #define NOTIFY_INVALID NULL
-struct cpufreq_cooling_device *notify_device;
+static struct cpufreq_cooling_device *notify_device;
 
 /**
  * get_idr - function to get a unique id.
-- 
1.7.7.6


^ permalink raw reply related

* [PATCH 24/34] Thermal: Remove the cooling_cpufreq_list.
From: Zhang Rui @ 2012-12-02 14:44 UTC (permalink / raw)
  To: linux-pm; +Cc: hongbo.zhang, Zhang Rui
In-Reply-To: <1354459508-3707-1-git-send-email-rui.zhang@intel.com>

From: "hongbo.zhang" <hongbo.zhang@linaro.com>

Problem of using this list is that the cpufreq_get_max_state callback will be
called when register cooling device by thermal_cooling_device_register, but
this list isn't ready at this moment. What's more, there is no need to maintain
such a list, we can get cpufreq_cooling_device instance by the private
thermal_cooling_device.devdata.

Signed-off-by: hongbo.zhang <hongbo.zhang@linaro.com>
Reviewed-by: Francesco Lavra <francescolavra.fl@gmail.com>
Reviewed-by: Amit Daniel Kachhap <amit.kachhap@linaro.org>
Signed-off-by: Zhang Rui <rui.zhang@intel.com>
---
 drivers/thermal/cpu_cooling.c |   91 +++++++++--------------------------------
 1 files changed, 19 insertions(+), 72 deletions(-)

diff --git a/drivers/thermal/cpu_cooling.c b/drivers/thermal/cpu_cooling.c
index bfd62b7..392d57d 100644
--- a/drivers/thermal/cpu_cooling.c
+++ b/drivers/thermal/cpu_cooling.c
@@ -58,8 +58,9 @@ struct cpufreq_cooling_device {
 };
 static LIST_HEAD(cooling_cpufreq_list);
 static DEFINE_IDR(cpufreq_idr);
+static DEFINE_MUTEX(cooling_cpufreq_lock);
 
-static struct mutex cooling_cpufreq_lock;
+static unsigned int cpufreq_dev_count;
 
 /* notify_table passes value to the CPUFREQ_ADJUST callback function. */
 #define NOTIFY_INVALID NULL
@@ -240,28 +241,18 @@ static int cpufreq_thermal_notifier(struct notifier_block *nb,
 static int cpufreq_get_max_state(struct thermal_cooling_device *cdev,
 				 unsigned long *state)
 {
-	int ret = -EINVAL, i = 0;
-	struct cpufreq_cooling_device *cpufreq_device;
-	struct cpumask *maskPtr;
+	struct cpufreq_cooling_device *cpufreq_device = cdev->devdata;
+	struct cpumask *maskPtr = &cpufreq_device->allowed_cpus;
 	unsigned int cpu;
 	struct cpufreq_frequency_table *table;
 	unsigned long count = 0;
+	int i = 0;
 
-	mutex_lock(&cooling_cpufreq_lock);
-	list_for_each_entry(cpufreq_device, &cooling_cpufreq_list, node) {
-		if (cpufreq_device && cpufreq_device->cool_dev == cdev)
-			break;
-	}
-	if (cpufreq_device == NULL)
-		goto return_get_max_state;
-
-	maskPtr = &cpufreq_device->allowed_cpus;
 	cpu = cpumask_any(maskPtr);
 	table = cpufreq_frequency_get_table(cpu);
 	if (!table) {
 		*state = 0;
-		ret = 0;
-		goto return_get_max_state;
+		return 0;
 	}
 
 	for (i = 0; (table[i].frequency != CPUFREQ_TABLE_END); i++) {
@@ -272,12 +263,10 @@ static int cpufreq_get_max_state(struct thermal_cooling_device *cdev,
 
 	if (count > 0) {
 		*state = --count;
-		ret = 0;
+		return 0;
 	}
 
-return_get_max_state:
-	mutex_unlock(&cooling_cpufreq_lock);
-	return ret;
+	return -EINVAL;
 }
 
 /**
@@ -288,20 +277,10 @@ static int cpufreq_get_max_state(struct thermal_cooling_device *cdev,
 static int cpufreq_get_cur_state(struct thermal_cooling_device *cdev,
 				 unsigned long *state)
 {
-	int ret = -EINVAL;
-	struct cpufreq_cooling_device *cpufreq_device;
+	struct cpufreq_cooling_device *cpufreq_device = cdev->devdata;
 
-	mutex_lock(&cooling_cpufreq_lock);
-	list_for_each_entry(cpufreq_device, &cooling_cpufreq_list, node) {
-		if (cpufreq_device && cpufreq_device->cool_dev == cdev) {
-			*state = cpufreq_device->cpufreq_state;
-			ret = 0;
-			break;
-		}
-	}
-	mutex_unlock(&cooling_cpufreq_lock);
-
-	return ret;
+	*state = cpufreq_device->cpufreq_state;
+	return 0;
 }
 
 /**
@@ -312,22 +291,9 @@ static int cpufreq_get_cur_state(struct thermal_cooling_device *cdev,
 static int cpufreq_set_cur_state(struct thermal_cooling_device *cdev,
 				 unsigned long state)
 {
-	int ret = -EINVAL;
-	struct cpufreq_cooling_device *cpufreq_device;
+	struct cpufreq_cooling_device *cpufreq_device = cdev->devdata;
 
-	mutex_lock(&cooling_cpufreq_lock);
-	list_for_each_entry(cpufreq_device, &cooling_cpufreq_list, node) {
-		if (cpufreq_device && cpufreq_device->cool_dev == cdev) {
-			ret = 0;
-			break;
-		}
-	}
-	if (!ret)
-		ret = cpufreq_apply_cooling(cpufreq_device, state);
-
-	mutex_unlock(&cooling_cpufreq_lock);
-
-	return ret;
+	return cpufreq_apply_cooling(cpufreq_device, state);
 }
 
 /* Bind cpufreq callbacks to thermal cooling device ops */
@@ -351,14 +317,11 @@ struct thermal_cooling_device *cpufreq_cooling_register(
 {
 	struct thermal_cooling_device *cool_dev;
 	struct cpufreq_cooling_device *cpufreq_dev = NULL;
-	unsigned int cpufreq_dev_count = 0, min = 0, max = 0;
+	unsigned int min = 0, max = 0;
 	char dev_name[THERMAL_NAME_LENGTH];
 	int ret = 0, i;
 	struct cpufreq_policy policy;
 
-	list_for_each_entry(cpufreq_dev, &cooling_cpufreq_list, node)
-		cpufreq_dev_count++;
-
 	/*Verify that all the clip cpus have same freq_min, freq_max limit*/
 	for_each_cpu(i, clip_cpus) {
 		/*continue if cpufreq policy not found and not return error*/
@@ -380,9 +343,6 @@ struct thermal_cooling_device *cpufreq_cooling_register(
 
 	cpumask_copy(&cpufreq_dev->allowed_cpus, clip_cpus);
 
-	if (cpufreq_dev_count == 0)
-		mutex_init(&cooling_cpufreq_lock);
-
 	ret = get_idr(&cpufreq_idr, &cpufreq_dev->id);
 	if (ret) {
 		kfree(cpufreq_dev);
@@ -401,12 +361,12 @@ struct thermal_cooling_device *cpufreq_cooling_register(
 	cpufreq_dev->cool_dev = cool_dev;
 	cpufreq_dev->cpufreq_state = 0;
 	mutex_lock(&cooling_cpufreq_lock);
-	list_add_tail(&cpufreq_dev->node, &cooling_cpufreq_list);
 
 	/* Register the notifier for first cpufreq cooling device */
 	if (cpufreq_dev_count == 0)
 		cpufreq_register_notifier(&thermal_cpufreq_notifier_block,
 						CPUFREQ_POLICY_NOTIFIER);
+	cpufreq_dev_count++;
 
 	mutex_unlock(&cooling_cpufreq_lock);
 	return cool_dev;
@@ -419,33 +379,20 @@ EXPORT_SYMBOL(cpufreq_cooling_register);
  */
 void cpufreq_cooling_unregister(struct thermal_cooling_device *cdev)
 {
-	struct cpufreq_cooling_device *cpufreq_dev = NULL;
-	unsigned int cpufreq_dev_count = 0;
+	struct cpufreq_cooling_device *cpufreq_dev = cdev->devdata;
 
 	mutex_lock(&cooling_cpufreq_lock);
-	list_for_each_entry(cpufreq_dev, &cooling_cpufreq_list, node) {
-		if (cpufreq_dev && cpufreq_dev->cool_dev == cdev)
-			break;
-		cpufreq_dev_count++;
-	}
-
-	if (!cpufreq_dev || cpufreq_dev->cool_dev != cdev) {
-		mutex_unlock(&cooling_cpufreq_lock);
-		return;
-	}
-
-	list_del(&cpufreq_dev->node);
+	cpufreq_dev_count--;
 
 	/* Unregister the notifier for the last cpufreq cooling device */
-	if (cpufreq_dev_count == 1) {
+	if (cpufreq_dev_count == 0) {
 		cpufreq_unregister_notifier(&thermal_cpufreq_notifier_block,
 					CPUFREQ_POLICY_NOTIFIER);
 	}
 	mutex_unlock(&cooling_cpufreq_lock);
+
 	thermal_cooling_device_unregister(cpufreq_dev->cool_dev);
 	release_idr(&cpufreq_idr, cpufreq_dev->id);
-	if (cpufreq_dev_count == 1)
-		mutex_destroy(&cooling_cpufreq_lock);
 	kfree(cpufreq_dev);
 }
 EXPORT_SYMBOL(cpufreq_cooling_unregister);
-- 
1.7.7.6


^ permalink raw reply related

* [PATCH 23/34] Thermal: fix bug of counting cpu frequencies.
From: Zhang Rui @ 2012-12-02 14:44 UTC (permalink / raw)
  To: linux-pm; +Cc: hongbo.zhang, Zhang Rui
In-Reply-To: <1354459508-3707-1-git-send-email-rui.zhang@intel.com>

From: "hongbo.zhang" <hongbo.zhang@linaro.com>

In the while loop for counting cpu frequencies, if table[i].frequency equals
CPUFREQ_ENTRY_INVALID, index i won't be increased, so this leads to an endless
loop, what's more the index i cannot be referred as cpu frequencies number if
there is CPUFREQ_ENTRY_INVALID case.

Signed-off-by: hongbo.zhang <hongbo.zhang@linaro.com>
Reviewed-by: Viresh Kumar <viresh.kumar@linaro.org>
Reviewed-by: Amit Daniel Kachhap <amit.kachhap@linaro.org>
Signed-off-by: Zhang Rui <rui.zhang@intel.com>
---
 drivers/thermal/cpu_cooling.c |   10 ++++++----
 1 files changed, 6 insertions(+), 4 deletions(-)

diff --git a/drivers/thermal/cpu_cooling.c b/drivers/thermal/cpu_cooling.c
index b6b4c2a..bfd62b7 100644
--- a/drivers/thermal/cpu_cooling.c
+++ b/drivers/thermal/cpu_cooling.c
@@ -245,6 +245,7 @@ static int cpufreq_get_max_state(struct thermal_cooling_device *cdev,
 	struct cpumask *maskPtr;
 	unsigned int cpu;
 	struct cpufreq_frequency_table *table;
+	unsigned long count = 0;
 
 	mutex_lock(&cooling_cpufreq_lock);
 	list_for_each_entry(cpufreq_device, &cooling_cpufreq_list, node) {
@@ -263,13 +264,14 @@ static int cpufreq_get_max_state(struct thermal_cooling_device *cdev,
 		goto return_get_max_state;
 	}
 
-	while (table[i].frequency != CPUFREQ_TABLE_END) {
+	for (i = 0; (table[i].frequency != CPUFREQ_TABLE_END); i++) {
 		if (table[i].frequency == CPUFREQ_ENTRY_INVALID)
 			continue;
-		i++;
+		count++;
 	}
-	if (i > 0) {
-		*state = --i;
+
+	if (count > 0) {
+		*state = --count;
 		ret = 0;
 	}
 
-- 
1.7.7.6


^ permalink raw reply related

* [PATCH 22/34] Thermal: add indent for code alignment.
From: Zhang Rui @ 2012-12-02 14:44 UTC (permalink / raw)
  To: linux-pm; +Cc: hongbo.zhang, Zhang Rui
In-Reply-To: <1354459508-3707-1-git-send-email-rui.zhang@intel.com>

From: "hongbo.zhang" <hongbo.zhang@linaro.com>

The curly bracket should be aligned with corresponding if else statements.

Signed-off-by: hongbo.zhang <hongbo.zhang@linaro.com>
Reviewed-by: Viresh Kumar <viresh.kumar@linaro.org>
Signed-off-by: Zhang Rui <rui.zhang@intel.com>
---
 drivers/thermal/cpu_cooling.c |    2 +-
 1 files changed, 1 insertions(+), 1 deletions(-)

diff --git a/drivers/thermal/cpu_cooling.c b/drivers/thermal/cpu_cooling.c
index cc1c930..b6b4c2a 100644
--- a/drivers/thermal/cpu_cooling.c
+++ b/drivers/thermal/cpu_cooling.c
@@ -369,7 +369,7 @@ struct thermal_cooling_device *cpufreq_cooling_register(
 			if (min != policy.cpuinfo.min_freq ||
 				max != policy.cpuinfo.max_freq)
 				return ERR_PTR(-EINVAL);
-}
+		}
 	}
 	cpufreq_dev = kzalloc(sizeof(struct cpufreq_cooling_device),
 			GFP_KERNEL);
-- 
1.7.7.6


^ permalink raw reply related

* [PATCH 21/34] thermal: rcar_thermal: remove explicitly used devm_kfree/iounap()
From: Zhang Rui @ 2012-12-02 14:44 UTC (permalink / raw)
  To: linux-pm; +Cc: Kuninori Morimoto, Zhang Rui
In-Reply-To: <1354459508-3707-1-git-send-email-rui.zhang@intel.com>

From: Kuninori Morimoto <kuninori.morimoto.gx@renesas.com>

devm_kfree and devm_iounmap should not have to be explicitly used

Signed-off-by: Kuninori Morimoto <kuninori.morimoto.gx@renesas.com>
Signed-off-by: Zhang Rui <rui.zhang@intel.com>
---
 drivers/thermal/rcar_thermal.c |   18 ++----------------
 1 files changed, 2 insertions(+), 16 deletions(-)

diff --git a/drivers/thermal/rcar_thermal.c b/drivers/thermal/rcar_thermal.c
index 762f637..81dce23 100644
--- a/drivers/thermal/rcar_thermal.c
+++ b/drivers/thermal/rcar_thermal.c
@@ -185,7 +185,6 @@ static int rcar_thermal_probe(struct platform_device *pdev)
 	struct thermal_zone_device *zone;
 	struct rcar_thermal_priv *priv;
 	struct resource *res;
-	int ret;
 
 	res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
 	if (!res) {
@@ -206,16 +205,14 @@ static int rcar_thermal_probe(struct platform_device *pdev)
 					  res->start, resource_size(res));
 	if (!priv->base) {
 		dev_err(&pdev->dev, "Unable to ioremap thermal register\n");
-		ret = -ENOMEM;
-		goto error_free_priv;
+		return -ENOMEM;
 	}
 
 	zone = thermal_zone_device_register("rcar_thermal", 0, 0, priv,
 				    &rcar_thermal_zone_ops, NULL, 0, 0);
 	if (IS_ERR(zone)) {
 		dev_err(&pdev->dev, "thermal zone device is NULL\n");
-		ret = PTR_ERR(zone);
-		goto error_iounmap;
+		return PTR_ERR(zone);
 	}
 
 	platform_set_drvdata(pdev, zone);
@@ -223,26 +220,15 @@ static int rcar_thermal_probe(struct platform_device *pdev)
 	dev_info(&pdev->dev, "proved\n");
 
 	return 0;
-
-error_iounmap:
-	devm_iounmap(&pdev->dev, priv->base);
-error_free_priv:
-	devm_kfree(&pdev->dev, priv);
-
-	return ret;
 }
 
 static int rcar_thermal_remove(struct platform_device *pdev)
 {
 	struct thermal_zone_device *zone = platform_get_drvdata(pdev);
-	struct rcar_thermal_priv *priv = zone->devdata;
 
 	thermal_zone_device_unregister(zone);
 	platform_set_drvdata(pdev, NULL);
 
-	devm_iounmap(&pdev->dev, priv->base);
-	devm_kfree(&pdev->dev, priv);
-
 	return 0;
 }
 
-- 
1.7.7.6


^ permalink raw reply related

* [PATCH 20/34] thermal: user_space: Add missing static storage class specifiers
From: Zhang Rui @ 2012-12-02 14:44 UTC (permalink / raw)
  To: linux-pm; +Cc: Sachin Kamat, Zhang Rui
In-Reply-To: <1354459508-3707-1-git-send-email-rui.zhang@intel.com>

From: Sachin Kamat <sachin.kamat@linaro.org>

Fixes the following sparse warnings:
drivers/thermal/user_space.c:38:5: warning:
symbol 'notify_user_space' was not declared. Should it be static?
drivers/thermal/user_space.c:46:25: warning:
symbol 'thermal_gov_user_space' was not declared. Should it be static?

Signed-off-by: Sachin Kamat <sachin.kamat@linaro.org>
Acked-by: Durgadoss R <durgadoss.r@intel.com>
Signed-off-by: Zhang Rui <rui.zhang@intel.com>
---
 drivers/thermal/user_space.c |    4 ++--
 1 files changed, 2 insertions(+), 2 deletions(-)

diff --git a/drivers/thermal/user_space.c b/drivers/thermal/user_space.c
index fb246b90..6bbb380 100644
--- a/drivers/thermal/user_space.c
+++ b/drivers/thermal/user_space.c
@@ -35,7 +35,7 @@
  *
  * This function notifies the user space through UEvents.
  */
-int notify_user_space(struct thermal_zone_device *tz, int trip)
+static int notify_user_space(struct thermal_zone_device *tz, int trip)
 {
 	mutex_lock(&tz->lock);
 	kobject_uevent(&tz->device.kobj, KOBJ_CHANGE);
@@ -43,7 +43,7 @@ int notify_user_space(struct thermal_zone_device *tz, int trip)
 	return 0;
 }
 
-struct thermal_governor thermal_gov_user_space = {
+static struct thermal_governor thermal_gov_user_space = {
 	.name		= "user_space",
 	.throttle	= notify_user_space,
 	.owner		= THIS_MODULE,
-- 
1.7.7.6


^ permalink raw reply related

* [PATCH 17/34] Thermal: Fix oops and unlocking in thermal_sys.c
From: Zhang Rui @ 2012-12-02 14:44 UTC (permalink / raw)
  To: linux-pm; +Cc: Hugh Dickins, Durgadoss R, Sedat Dilek, Zhang Rui
In-Reply-To: <1354459508-3707-1-git-send-email-rui.zhang@intel.com>

From: Hugh Dickins <hughd@google.com>

This patch fixes the following mutex and NULL pointer
problems in thermal_sys.c:

 * mutex_unlock fix in update_temperature function
 * mutex_unlock fix in bind_cdev function
 * Correct early return to continue in bind_cdev function
 * NULL check fix in bind_cdev function
 * NULL check fix in bind_tz function

Reported-by: Dan Carpenter <dan.carpenter@oracle.com>
Reported-by: Sedat Dilek <sedat.dilek@gmail.com>
Reported-by: Hugh Dickins <hughd@google.com>
Signed-off-by: Durgadoss R <durgadoss.r@intel.com>
Signed-off-by: Sedat Dilek <sedat.dilek@gmail.com>
Signed-off-by: Hugh Dickins <hughd@google.com>
Signed-off-by: Zhang Rui <rui.zhang@intel.com>
---
 drivers/thermal/thermal_sys.c |    9 +++++----
 1 files changed, 5 insertions(+), 4 deletions(-)

diff --git a/drivers/thermal/thermal_sys.c b/drivers/thermal/thermal_sys.c
index a69f24c..8f0f37b 100644
--- a/drivers/thermal/thermal_sys.c
+++ b/drivers/thermal/thermal_sys.c
@@ -252,8 +252,8 @@ static void bind_cdev(struct thermal_cooling_device *cdev)
 		}
 
 		tzp = pos->tzp;
-		if (!tzp->tbp)
-			return;
+		if (!tzp || !tzp->tbp)
+			continue;
 
 		for (i = 0; i < tzp->num_tbps; i++) {
 			if (tzp->tbp[i].cdev || !tzp->tbp[i].match)
@@ -289,7 +289,7 @@ static void bind_tz(struct thermal_zone_device *tz)
 		goto exit;
 	}
 
-	if (!tzp->tbp)
+	if (!tzp || !tzp->tbp)
 		goto exit;
 
 	list_for_each_entry(pos, &thermal_cdev_list, node) {
@@ -387,12 +387,13 @@ static void update_temperature(struct thermal_zone_device *tz)
 	ret = tz->ops->get_temp(tz, &temp);
 	if (ret) {
 		pr_warn("failed to read out thermal zone %d\n", tz->id);
-		return;
+		goto exit;
 	}
 
 	tz->last_temperature = tz->temperature;
 	tz->temperature = temp;
 
+exit:
 	mutex_unlock(&tz->lock);
 }
 
-- 
1.7.7.6


^ permalink raw reply related

* [PATCH 15/34] Thermal: Add documentation for platform layer data
From: Zhang Rui @ 2012-12-02 14:44 UTC (permalink / raw)
  To: linux-pm; +Cc: Durgadoss R, Zhang Rui
In-Reply-To: <1354459508-3707-1-git-send-email-rui.zhang@intel.com>

From: Durgadoss R <durgadoss.r@intel.com>

This patch adds documentation for thermal_bind_params
and thermal_zone_params structures. Also, adds details
on EXPORT_SYMBOL APIs.

Signed-off-by: Durgadoss R <durgadoss.r@intel.com>
Signed-off-by: Zhang Rui <rui.zhang@intel.com>
---
 Documentation/thermal/sysfs-api.txt |   64 +++++++++++++++++++++++++++++++++++
 1 files changed, 64 insertions(+), 0 deletions(-)

diff --git a/Documentation/thermal/sysfs-api.txt b/Documentation/thermal/sysfs-api.txt
index ca1a1a3..88c0233 100644
--- a/Documentation/thermal/sysfs-api.txt
+++ b/Documentation/thermal/sysfs-api.txt
@@ -112,6 +112,29 @@ temperature) and throttle appropriate devices.
     trip: indicates which trip point the cooling devices is associated with
 	  in this thermal zone.
 
+1.4 Thermal Zone Parameters
+1.4.1 struct thermal_bind_params
+    This structure defines the following parameters that are used to bind
+    a zone with a cooling device for a particular trip point.
+    .cdev: The cooling device pointer
+    .weight: The 'influence' of a particular cooling device on this zone.
+             This is on a percentage scale. The sum of all these weights
+             (for a particular zone) cannot exceed 100.
+    .trip_mask:This is a bit mask that gives the binding relation between
+               this thermal zone and cdev, for a particular trip point.
+               If nth bit is set, then the cdev and thermal zone are bound
+               for trip point n.
+    .match: This call back returns success(0) if the 'tz and cdev' need to
+	    be bound, as per platform data.
+1.4.2 struct thermal_zone_params
+    This structure defines the platform level parameters for a thermal zone.
+    This data, for each thermal zone should come from the platform layer.
+    This is an optional feature where some platforms can choose not to
+    provide this data.
+    .governor_name: Name of the thermal governor used for this zone
+    .num_tbps: Number of thermal_bind_params entries for this zone
+    .tbp: thermal_bind_params entries
+
 2. sysfs attributes structure
 
 RO	read only value
@@ -126,6 +149,7 @@ if hwmon is compiled in or built as a module.
     |---type:			Type of the thermal zone
     |---temp:			Current temperature
     |---mode:			Working mode of the thermal zone
+    |---policy:			Thermal governor used for this zone
     |---trip_point_[0-*]_temp:	Trip point temperature
     |---trip_point_[0-*]_type:	Trip point type
     |---trip_point_[0-*]_hyst:	Hysteresis value for this trip point
@@ -187,6 +211,10 @@ mode
 			  charge of the thermal management.
 	RW, Optional
 
+policy
+	One of the various thermal governors used for a particular zone.
+	RW, Required
+
 trip_point_[0-*]_temp
 	The temperature above which trip point will be fired.
 	Unit: millidegree Celsius
@@ -264,6 +292,7 @@ If the processor is listed in _PSL method, and the fan is listed in _AL0
     |---type:			acpitz
     |---temp:			37000
     |---mode:			enabled
+    |---policy:			step_wise
     |---trip_point_0_temp:	100000
     |---trip_point_0_type:	critical
     |---trip_point_1_temp:	80000
@@ -305,3 +334,38 @@ to a thermal_zone_device when it registers itself with the framework. The
 event will be one of:{THERMAL_AUX0, THERMAL_AUX1, THERMAL_CRITICAL,
 THERMAL_DEV_FAULT}. Notification can be sent when the current temperature
 crosses any of the configured thresholds.
+
+5. Export Symbol APIs:
+
+5.1: get_tz_trend:
+This function returns the trend of a thermal zone, i.e the rate of change
+of temperature of the thermal zone. Ideally, the thermal sensor drivers
+are supposed to implement the callback. If they don't, the thermal
+framework calculated the trend by comparing the previous and the current
+temperature values.
+
+5.2:get_thermal_instance:
+This function returns the thermal_instance corresponding to a given
+{thermal_zone, cooling_device, trip_point} combination. Returns NULL
+if such an instance does not exist.
+
+5.3:notify_thermal_framework:
+This function handles the trip events from sensor drivers. It starts
+throttling the cooling devices according to the policy configured.
+For CRITICAL and HOT trip points, this notifies the respective drivers,
+and does actual throttling for other trip points i.e ACTIVE and PASSIVE.
+The throttling policy is based on the configured platform data; if no
+platform data is provided, this uses the step_wise throttling policy.
+
+5.4:thermal_cdev_update:
+This function serves as an arbitrator to set the state of a cooling
+device. It sets the cooling device to the deepest cooling state if
+possible.
+
+5.5:thermal_register_governor:
+This function lets the various thermal governors to register themselves
+with the Thermal framework. At run time, depending on a zone's platform
+data, a particular governor is used for throttling.
+
+5.6:thermal_unregister_governor:
+This function unregisters a governor from the thermal framework.
-- 
1.7.7.6


^ permalink raw reply related

* [PATCH 13/34] Thermal: Remove throttling logic out of thermal_sys.c
From: Zhang Rui @ 2012-12-02 14:44 UTC (permalink / raw)
  To: linux-pm; +Cc: Durgadoss R, Zhang Rui
In-Reply-To: <1354459508-3707-1-git-send-email-rui.zhang@intel.com>

From: Durgadoss R <durgadoss.r@intel.com>

This patch removes the throttling logic out of
thermal_sys.c; also refactors the code into smaller
functions so that are easy to read/maintain.
 * Seperates the handling of critical and non-critical trips
 * Re-arranges the set_polling and device_check methods, so
   that all related functions are arranged in one place.
 * Removes the 'do_update' and 'trip_update' method, as part
   of moving the throttling logic out of thermal_sys.c

Signed-off-by: Durgadoss R <durgadoss.r@intel.com>
Signed-off-by: Zhang Rui <rui.zhang@intel.com>
---
 drivers/thermal/thermal_sys.c |  307 +++++++++++++++--------------------------
 1 files changed, 109 insertions(+), 198 deletions(-)

diff --git a/drivers/thermal/thermal_sys.c b/drivers/thermal/thermal_sys.c
index 9d21f82..64f3e97 100644
--- a/drivers/thermal/thermal_sys.c
+++ b/drivers/thermal/thermal_sys.c
@@ -306,6 +306,115 @@ static void bind_tz(struct thermal_zone_device *tz)
 	mutex_unlock(&thermal_list_lock);
 }
 
+static void thermal_zone_device_set_polling(struct thermal_zone_device *tz,
+					    int delay)
+{
+	if (delay > 1000)
+		mod_delayed_work(system_freezable_wq, &tz->poll_queue,
+				 round_jiffies(msecs_to_jiffies(delay)));
+	else if (delay)
+		mod_delayed_work(system_freezable_wq, &tz->poll_queue,
+				 msecs_to_jiffies(delay));
+	else
+		cancel_delayed_work(&tz->poll_queue);
+}
+
+static void monitor_thermal_zone(struct thermal_zone_device *tz)
+{
+	mutex_lock(&tz->lock);
+
+	if (tz->passive)
+		thermal_zone_device_set_polling(tz, tz->passive_delay);
+	else if (tz->polling_delay)
+		thermal_zone_device_set_polling(tz, tz->polling_delay);
+	else
+		thermal_zone_device_set_polling(tz, 0);
+
+	mutex_unlock(&tz->lock);
+}
+
+static void handle_non_critical_trips(struct thermal_zone_device *tz,
+			int trip, enum thermal_trip_type trip_type)
+{
+	tz->governor->throttle(tz, trip);
+}
+
+static void handle_critical_trips(struct thermal_zone_device *tz,
+				int trip, enum thermal_trip_type trip_type)
+{
+	long trip_temp;
+
+	tz->ops->get_trip_temp(tz, trip, &trip_temp);
+
+	/* If we have not crossed the trip_temp, we do not care. */
+	if (tz->temperature < trip_temp)
+		return;
+
+	if (tz->ops->notify)
+		tz->ops->notify(tz, trip, trip_type);
+
+	if (trip_type == THERMAL_TRIP_CRITICAL) {
+		pr_emerg("Critical temperature reached(%d C),shutting down\n",
+			 tz->temperature / 1000);
+		orderly_poweroff(true);
+	}
+}
+
+static void handle_thermal_trip(struct thermal_zone_device *tz, int trip)
+{
+	enum thermal_trip_type type;
+
+	tz->ops->get_trip_type(tz, trip, &type);
+
+	if (type == THERMAL_TRIP_CRITICAL || type == THERMAL_TRIP_HOT)
+		handle_critical_trips(tz, trip, type);
+	else
+		handle_non_critical_trips(tz, trip, type);
+	/*
+	 * Alright, we handled this trip successfully.
+	 * So, start monitoring again.
+	 */
+	monitor_thermal_zone(tz);
+}
+
+static void update_temperature(struct thermal_zone_device *tz)
+{
+	long temp;
+	int ret;
+
+	mutex_lock(&tz->lock);
+
+	ret = tz->ops->get_temp(tz, &temp);
+	if (ret) {
+		pr_warn("failed to read out thermal zone %d\n", tz->id);
+		return;
+	}
+
+	tz->last_temperature = tz->temperature;
+	tz->temperature = temp;
+
+	mutex_unlock(&tz->lock);
+}
+
+void thermal_zone_device_update(struct thermal_zone_device *tz)
+{
+	int count;
+
+	update_temperature(tz);
+
+	for (count = 0; count < tz->trips; count++)
+		handle_thermal_trip(tz, count);
+}
+EXPORT_SYMBOL(thermal_zone_device_update);
+
+static void thermal_zone_device_check(struct work_struct *work)
+{
+	struct thermal_zone_device *tz = container_of(work, struct
+						      thermal_zone_device,
+						      poll_queue.work);
+	thermal_zone_device_update(tz);
+}
+
 /* sys I/F for thermal zone */
 
 #define to_thermal_zone(_dev) \
@@ -936,27 +1045,6 @@ thermal_remove_hwmon_sysfs(struct thermal_zone_device *tz)
 }
 #endif
 
-static void thermal_zone_device_set_polling(struct thermal_zone_device *tz,
-					    int delay)
-{
-	if (delay > 1000)
-		mod_delayed_work(system_freezable_wq, &tz->poll_queue,
-				 round_jiffies(msecs_to_jiffies(delay)));
-	else if (delay)
-		mod_delayed_work(system_freezable_wq, &tz->poll_queue,
-				 msecs_to_jiffies(delay));
-	else
-		cancel_delayed_work(&tz->poll_queue);
-}
-
-static void thermal_zone_device_check(struct work_struct *work)
-{
-	struct thermal_zone_device *tz = container_of(work, struct
-						      thermal_zone_device,
-						      poll_queue.work);
-	thermal_zone_device_update(tz);
-}
-
 /**
  * thermal_zone_bind_cooling_device - bind a cooling device to a thermal zone
  * @tz:		thermal zone device
@@ -1280,183 +1368,6 @@ void thermal_cdev_update(struct thermal_cooling_device *cdev)
 }
 EXPORT_SYMBOL(thermal_cdev_update);
 
-static void thermal_zone_do_update(struct thermal_zone_device *tz)
-{
-	struct thermal_instance *instance;
-
-	list_for_each_entry(instance, &tz->thermal_instances, tz_node)
-		thermal_cdev_update(instance->cdev);
-}
-
-/*
- * Cooling algorithm for both active and passive cooling
- *
- * 1. if the temperature is higher than a trip point,
- *    a. if the trend is THERMAL_TREND_RAISING, use higher cooling
- *       state for this trip point
- *    b. if the trend is THERMAL_TREND_DROPPING, use lower cooling
- *       state for this trip point
- *
- * 2. if the temperature is lower than a trip point, use lower
- *    cooling state for this trip point
- *
- * Note that this behaves the same as the previous passive cooling
- * algorithm.
- */
-
-static void thermal_zone_trip_update(struct thermal_zone_device *tz,
-				     int trip, long temp)
-{
-	struct thermal_instance *instance;
-	struct thermal_cooling_device *cdev = NULL;
-	unsigned long cur_state, max_state;
-	long trip_temp;
-	enum thermal_trip_type trip_type;
-	enum thermal_trend trend;
-
-	if (trip == THERMAL_TRIPS_NONE) {
-		trip_temp = tz->forced_passive;
-		trip_type = THERMAL_TRIPS_NONE;
-	} else {
-		tz->ops->get_trip_temp(tz, trip, &trip_temp);
-		tz->ops->get_trip_type(tz, trip, &trip_type);
-	}
-
-	if (!tz->ops->get_trend || tz->ops->get_trend(tz, trip, &trend)) {
-		/*
-		 * compare the current temperature and previous temperature
-		 * to get the thermal trend, if no special requirement
-		 */
-		if (tz->temperature > tz->last_temperature)
-			trend = THERMAL_TREND_RAISING;
-		else if (tz->temperature < tz->last_temperature)
-			trend = THERMAL_TREND_DROPPING;
-		else
-			trend = THERMAL_TREND_STABLE;
-	}
-
-	if (temp >= trip_temp) {
-		list_for_each_entry(instance, &tz->thermal_instances, tz_node) {
-			if (instance->trip != trip)
-				continue;
-
-			cdev = instance->cdev;
-
-			cdev->ops->get_cur_state(cdev, &cur_state);
-			cdev->ops->get_max_state(cdev, &max_state);
-
-			if (trend == THERMAL_TREND_RAISING) {
-				cur_state = cur_state < instance->upper ?
-					    (cur_state + 1) : instance->upper;
-			} else if (trend == THERMAL_TREND_DROPPING) {
-				cur_state = cur_state > instance->lower ?
-				    (cur_state - 1) : instance->lower;
-			}
-
-			/* activate a passive thermal instance */
-			if ((trip_type == THERMAL_TRIP_PASSIVE ||
-			     trip_type == THERMAL_TRIPS_NONE) &&
-			     instance->target == THERMAL_NO_TARGET)
-				tz->passive++;
-
-			instance->target = cur_state;
-			cdev->updated = false; /* cooling device needs update */
-		}
-	} else {	/* below trip */
-		list_for_each_entry(instance, &tz->thermal_instances, tz_node) {
-			if (instance->trip != trip)
-				continue;
-
-			/* Do not use the inactive thermal instance */
-			if (instance->target == THERMAL_NO_TARGET)
-				continue;
-			cdev = instance->cdev;
-			cdev->ops->get_cur_state(cdev, &cur_state);
-
-			cur_state = cur_state > instance->lower ?
-				    (cur_state - 1) : THERMAL_NO_TARGET;
-
-			/* deactivate a passive thermal instance */
-			if ((trip_type == THERMAL_TRIP_PASSIVE ||
-			     trip_type == THERMAL_TRIPS_NONE) &&
-			     cur_state == THERMAL_NO_TARGET)
-				tz->passive--;
-			instance->target = cur_state;
-			cdev->updated = false; /* cooling device needs update */
-		}
-	}
-
-	return;
-}
-/**
- * thermal_zone_device_update - force an update of a thermal zone's state
- * @ttz:	the thermal zone to update
- */
-
-void thermal_zone_device_update(struct thermal_zone_device *tz)
-{
-	int count, ret = 0;
-	long temp, trip_temp;
-	enum thermal_trip_type trip_type;
-
-	mutex_lock(&tz->lock);
-
-	if (tz->ops->get_temp(tz, &temp)) {
-		/* get_temp failed - retry it later */
-		pr_warn("failed to read out thermal zone %d\n", tz->id);
-		goto leave;
-	}
-
-	tz->last_temperature = tz->temperature;
-	tz->temperature = temp;
-
-	for (count = 0; count < tz->trips; count++) {
-		tz->ops->get_trip_type(tz, count, &trip_type);
-		tz->ops->get_trip_temp(tz, count, &trip_temp);
-
-		switch (trip_type) {
-		case THERMAL_TRIP_CRITICAL:
-			if (temp >= trip_temp) {
-				if (tz->ops->notify)
-					ret = tz->ops->notify(tz, count,
-							      trip_type);
-				if (!ret) {
-					pr_emerg("Critical temperature reached (%ld C), shutting down\n",
-						 temp/1000);
-					orderly_poweroff(true);
-				}
-			}
-			break;
-		case THERMAL_TRIP_HOT:
-			if (temp >= trip_temp)
-				if (tz->ops->notify)
-					tz->ops->notify(tz, count, trip_type);
-			break;
-		case THERMAL_TRIP_ACTIVE:
-			thermal_zone_trip_update(tz, count, temp);
-			break;
-		case THERMAL_TRIP_PASSIVE:
-			if (temp >= trip_temp || tz->passive)
-				thermal_zone_trip_update(tz, count, temp);
-			break;
-		}
-	}
-
-	if (tz->forced_passive)
-		thermal_zone_trip_update(tz, THERMAL_TRIPS_NONE, temp);
-	thermal_zone_do_update(tz);
-
-leave:
-	if (tz->passive)
-		thermal_zone_device_set_polling(tz, tz->passive_delay);
-	else if (tz->polling_delay)
-		thermal_zone_device_set_polling(tz, tz->polling_delay);
-	else
-		thermal_zone_device_set_polling(tz, 0);
-	mutex_unlock(&tz->lock);
-}
-EXPORT_SYMBOL(thermal_zone_device_update);
-
 /**
  * create_trip_attrs - create attributes for trip points
  * @tz:		the thermal zone device
-- 
1.7.7.6


^ permalink raw reply related

* [PATCH 19/34] thermal: fair_share: Add missing static storage class specifiers
From: Zhang Rui @ 2012-12-02 14:44 UTC (permalink / raw)
  To: linux-pm; +Cc: Sachin Kamat, Zhang Rui
In-Reply-To: <1354459508-3707-1-git-send-email-rui.zhang@intel.com>

From: Sachin Kamat <sachin.kamat@linaro.org>

Fixes the following sparse warnings:
drivers/thermal/fair_share.c:80:5: warning:
symbol 'fair_share_throttle' was not declared. Should it be static?
drivers/thermal/fair_share.c:111:25: warning:
symbol 'thermal_gov_fair_share' was not declared. Should it be static?

Signed-off-by: Sachin Kamat <sachin.kamat@linaro.org>
Acked-by: Durgadoss R <durgadoss.r@intel.com>
Signed-off-by: Zhang Rui <rui.zhang@intel.com>
---
 drivers/thermal/fair_share.c |    4 ++--
 1 files changed, 2 insertions(+), 2 deletions(-)

diff --git a/drivers/thermal/fair_share.c b/drivers/thermal/fair_share.c
index 5d3a7a3..792479f 100644
--- a/drivers/thermal/fair_share.c
+++ b/drivers/thermal/fair_share.c
@@ -77,7 +77,7 @@ static long get_target_state(struct thermal_zone_device *tz,
  *	(Heavily assumes the trip points are in ascending order)
  * new_state of cooling device = P3 * P2 * P1
  */
-int fair_share_throttle(struct thermal_zone_device *tz, int trip)
+static int fair_share_throttle(struct thermal_zone_device *tz, int trip)
 {
 	const struct thermal_zone_params *tzp;
 	struct thermal_cooling_device *cdev;
@@ -108,7 +108,7 @@ int fair_share_throttle(struct thermal_zone_device *tz, int trip)
 	return 0;
 }
 
-struct thermal_governor thermal_gov_fair_share = {
+static struct thermal_governor thermal_gov_fair_share = {
 	.name		= "fair_share",
 	.throttle	= fair_share_throttle,
 	.owner		= THIS_MODULE,
-- 
1.7.7.6


^ permalink raw reply related

* [PATCH 16/34] Thermal: Provide option to choose default thermal governor
From: Zhang Rui @ 2012-12-02 14:44 UTC (permalink / raw)
  To: linux-pm; +Cc: Durgadoss R, Zhang Rui
In-Reply-To: <1354459508-3707-1-git-send-email-rui.zhang@intel.com>

From: Durgadoss R <durgadoss.r@intel.com>

This patch provides option to choose the default thermal
governor. If no option is provided, the step_wise
governor is selected by default.

Signed-off-by: Durgadoss R <durgadoss.r@intel.com>
Signed-off-by: Zhang Rui <rui.zhang@intel.com>
---
 drivers/thermal/Kconfig |   31 +++++++++++++++++++++++++++++++
 1 files changed, 31 insertions(+), 0 deletions(-)

diff --git a/drivers/thermal/Kconfig b/drivers/thermal/Kconfig
index f679eea..266c15e 100644
--- a/drivers/thermal/Kconfig
+++ b/drivers/thermal/Kconfig
@@ -73,3 +73,34 @@ config USER_SPACE
 	depends on THERMAL
 	help
 	  Enable this to let the user space manage the platform thermals.
+
+choice
+	prompt "Default Thermal governor"
+	depends on THERMAL
+	default THERMAL_DEFAULT_GOV_STEP_WISE
+	help
+	  This option sets which thermal governor shall be loaded at
+	  startup. If in doubt, select 'step_wise'.
+
+config THERMAL_DEFAULT_GOV_STEP_WISE
+	bool "step_wise"
+	select STEP_WISE
+	help
+	  Use the step_wise governor as default. This throttles the
+	  devices one step at a time.
+
+config THERMAL_DEFAULT_GOV_FAIR_SHARE
+	bool "fair_share"
+	select FAIR_SHARE
+	help
+	  Use the fair_share governor as default. This throttles the
+	  devices based on their 'contribution' to a zone. The
+	  contribution should be provided through platform data.
+
+config THERMAL_DEFAULT_GOV_USER_SPACE
+	bool "user_space"
+	select USER_SPACE
+	help
+	  Select this if you want to let the user space manage the
+	  platform thermals.
+endchoice
-- 
1.7.7.6


^ permalink raw reply related

* [PATCH 14/34] Thermal: Add a notification API
From: Zhang Rui @ 2012-12-02 14:44 UTC (permalink / raw)
  To: linux-pm; +Cc: Durgadoss R, Zhang Rui
In-Reply-To: <1354459508-3707-1-git-send-email-rui.zhang@intel.com>

From: Durgadoss R <durgadoss.r@intel.com>

This patch adds a notification API which the sensor drivers'
can use to notify the framework. The framework then takes
care of the throttling according to the configured policy.

Signed-off-by: Durgadoss R <durgadoss.r@intel.com>
Signed-off-by: Zhang Rui <rui.zhang@intel.com>
---
 drivers/thermal/thermal_sys.c |   18 ++++++++++++++++++
 include/linux/thermal.h       |    1 +
 2 files changed, 19 insertions(+), 0 deletions(-)

diff --git a/drivers/thermal/thermal_sys.c b/drivers/thermal/thermal_sys.c
index 64f3e97..a69f24c 100644
--- a/drivers/thermal/thermal_sys.c
+++ b/drivers/thermal/thermal_sys.c
@@ -1369,6 +1369,24 @@ void thermal_cdev_update(struct thermal_cooling_device *cdev)
 EXPORT_SYMBOL(thermal_cdev_update);
 
 /**
+ * notify_thermal_framework - Sensor drivers use this API to notify framework
+ * @tz:		thermal zone device
+ * @trip:	indicates which trip point has been crossed
+ *
+ * This function handles the trip events from sensor drivers. It starts
+ * throttling the cooling devices according to the policy configured.
+ * For CRITICAL and HOT trip points, this notifies the respective drivers,
+ * and does actual throttling for other trip points i.e ACTIVE and PASSIVE.
+ * The throttling policy is based on the configured platform data; if no
+ * platform data is provided, this uses the step_wise throttling policy.
+ */
+void notify_thermal_framework(struct thermal_zone_device *tz, int trip)
+{
+	handle_thermal_trip(tz, trip);
+}
+EXPORT_SYMBOL(notify_thermal_framework);
+
+/**
  * create_trip_attrs - create attributes for trip points
  * @tz:		the thermal zone device
  * @mask:	Writeable trip point bitmap.
diff --git a/include/linux/thermal.h b/include/linux/thermal.h
index 2bd9158..807f214 100644
--- a/include/linux/thermal.h
+++ b/include/linux/thermal.h
@@ -232,6 +232,7 @@ int get_tz_trend(struct thermal_zone_device *, int);
 struct thermal_instance *get_thermal_instance(struct thermal_zone_device *,
 		struct thermal_cooling_device *, int);
 void thermal_cdev_update(struct thermal_cooling_device *);
+void notify_thermal_framework(struct thermal_zone_device *, int);
 
 int thermal_register_governor(struct thermal_governor *);
 void thermal_unregister_governor(struct thermal_governor *);
-- 
1.7.7.6


^ permalink raw reply related

* [PATCH 18/34] thermal: step_wise: Add missing static storage class specifiers
From: Zhang Rui @ 2012-12-02 14:44 UTC (permalink / raw)
  To: linux-pm; +Cc: Sachin Kamat, Zhang Rui
In-Reply-To: <1354459508-3707-1-git-send-email-rui.zhang@intel.com>

From: Sachin Kamat <sachin.kamat@linaro.org>

Fixes the following sparse warnings:
drivers/thermal/step_wise.c:153:5: warning:
symbol 'step_wise_throttle' was not declared. Should it be static?
drivers/thermal/step_wise.c:172:25: warning:
symbol 'thermal_gov_step_wise' was not declared. Should it be static?

Signed-off-by: Sachin Kamat <sachin.kamat@linaro.org>
Acked-by: Durgadoss R <durgadoss.r@intel.com>
Signed-off-by: Zhang Rui <rui.zhang@intel.com>
---
 drivers/thermal/step_wise.c |    4 ++--
 1 files changed, 2 insertions(+), 2 deletions(-)

diff --git a/drivers/thermal/step_wise.c b/drivers/thermal/step_wise.c
index 3f9cfcf..1242cff 100644
--- a/drivers/thermal/step_wise.c
+++ b/drivers/thermal/step_wise.c
@@ -150,7 +150,7 @@ static void thermal_zone_trip_update(struct thermal_zone_device *tz, int trip)
  * step. If the zone is 'cooling down' it brings back the performance of
  * the devices by one step.
  */
-int step_wise_throttle(struct thermal_zone_device *tz, int trip)
+static int step_wise_throttle(struct thermal_zone_device *tz, int trip)
 {
 	struct thermal_instance *instance;
 
@@ -169,7 +169,7 @@ int step_wise_throttle(struct thermal_zone_device *tz, int trip)
 	return 0;
 }
 
-struct thermal_governor thermal_gov_step_wise = {
+static struct thermal_governor thermal_gov_step_wise = {
 	.name		= DEFAULT_THERMAL_GOVERNOR,
 	.throttle	= step_wise_throttle,
 	.owner		= THIS_MODULE,
-- 
1.7.7.6


^ permalink raw reply related

* [PATCH 11/34] Thermal: Introduce a step_wise thermal governor
From: Zhang Rui @ 2012-12-02 14:44 UTC (permalink / raw)
  To: linux-pm; +Cc: Durgadoss R, Zhang Rui
In-Reply-To: <1354459508-3707-1-git-send-email-rui.zhang@intel.com>

From: Durgadoss R <durgadoss.r@intel.com>

This patch adds a simple step_wise governor to the
generic thermal layer. This algorithm throttles the
cooling devices in a linear fashion. If the 'trend'
is heating, it throttles by one step. And if the
thermal trend is cooling it de-throttles by one step.

This actually moves the throttling logic from thermal_sys.c
and puts inside step_wise.c, without any change.

Signed-off-by: Durgadoss R <durgadoss.r@intel.com>
Signed-off-by: Zhang Rui <rui.zhang@intel.com>
---
 drivers/thermal/Kconfig     |    6 ++
 drivers/thermal/Makefile    |    1 +
 drivers/thermal/step_wise.c |  194 +++++++++++++++++++++++++++++++++++++++++++
 3 files changed, 201 insertions(+), 0 deletions(-)
 create mode 100644 drivers/thermal/step_wise.c

diff --git a/drivers/thermal/Kconfig b/drivers/thermal/Kconfig
index 84b0f03..7e1b6de 100644
--- a/drivers/thermal/Kconfig
+++ b/drivers/thermal/Kconfig
@@ -61,3 +61,9 @@ config FAIR_SHARE
 	depends on THERMAL
 	help
 	  Enable this to manage platform thermals using fair-share governor.
+
+config STEP_WISE
+	bool "Step_wise thermal governor"
+	depends on THERMAL
+	help
+	  Enable this to manage platform thermals using a simple linear
diff --git a/drivers/thermal/Makefile b/drivers/thermal/Makefile
index 30540dd..4e53c00 100644
--- a/drivers/thermal/Makefile
+++ b/drivers/thermal/Makefile
@@ -8,3 +8,4 @@ obj-$(CONFIG_SPEAR_THERMAL)		+= spear_thermal.o
 obj-$(CONFIG_RCAR_THERMAL)	+= rcar_thermal.o
 obj-$(CONFIG_EXYNOS_THERMAL)		+= exynos_thermal.o
 obj-$(CONFIG_FAIR_SHARE)		+= fair_share.o
+obj-$(CONFIG_STEP_WISE)			+= step_wise.o
diff --git a/drivers/thermal/step_wise.c b/drivers/thermal/step_wise.c
new file mode 100644
index 0000000..3f9cfcf
--- /dev/null
+++ b/drivers/thermal/step_wise.c
@@ -0,0 +1,194 @@
+/*
+ *  step_wise.c - A step-by-step Thermal throttling governor
+ *
+ *  Copyright (C) 2012 Intel Corp
+ *  Copyright (C) 2012 Durgadoss R <durgadoss.r@intel.com>
+ *
+ *  ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+ *
+ *  This program is free software; you can redistribute it and/or modify
+ *  it under the terms of the GNU General Public License as published by
+ *  the Free Software Foundation; version 2 of the License.
+ *
+ *  This program is distributed in the hope that it will be useful, but
+ *  WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ *  General Public License for more details.
+ *
+ *  You should have received a copy of the GNU General Public License along
+ *  with this program; if not, write to the Free Software Foundation, Inc.,
+ *  59 Temple Place, Suite 330, Boston, MA 02111-1307 USA.
+ *
+ * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+ */
+
+#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
+
+#include <linux/module.h>
+#include <linux/thermal.h>
+
+#include "thermal_core.h"
+
+/*
+ * If the temperature is higher than a trip point,
+ *    a. if the trend is THERMAL_TREND_RAISING, use higher cooling
+ *       state for this trip point
+ *    b. if the trend is THERMAL_TREND_DROPPING, use lower cooling
+ *       state for this trip point
+ */
+static unsigned long get_target_state(struct thermal_instance *instance,
+					enum thermal_trend trend)
+{
+	struct thermal_cooling_device *cdev = instance->cdev;
+	unsigned long cur_state;
+
+	cdev->ops->get_cur_state(cdev, &cur_state);
+
+	if (trend == THERMAL_TREND_RAISING) {
+		cur_state = cur_state < instance->upper ?
+			    (cur_state + 1) : instance->upper;
+	} else if (trend == THERMAL_TREND_DROPPING) {
+		cur_state = cur_state > instance->lower ?
+			    (cur_state - 1) : instance->lower;
+	}
+
+	return cur_state;
+}
+
+static void update_passive_instance(struct thermal_zone_device *tz,
+				enum thermal_trip_type type, int value)
+{
+	/*
+	 * If value is +1, activate a passive instance.
+	 * If value is -1, deactivate a passive instance.
+	 */
+	if (type == THERMAL_TRIP_PASSIVE || type == THERMAL_TRIPS_NONE)
+		tz->passive += value;
+}
+
+static void update_instance_for_throttle(struct thermal_zone_device *tz,
+				int trip, enum thermal_trip_type trip_type,
+				enum thermal_trend trend)
+{
+	struct thermal_instance *instance;
+
+	list_for_each_entry(instance, &tz->thermal_instances, tz_node) {
+		if (instance->trip != trip)
+			continue;
+
+		instance->target = get_target_state(instance, trend);
+
+		/* Activate a passive thermal instance */
+		if (instance->target == THERMAL_NO_TARGET)
+			update_passive_instance(tz, trip_type, 1);
+
+		instance->cdev->updated = false; /* cdev needs update */
+	}
+}
+
+static void update_instance_for_dethrottle(struct thermal_zone_device *tz,
+				int trip, enum thermal_trip_type trip_type)
+{
+	struct thermal_instance *instance;
+	struct thermal_cooling_device *cdev;
+	unsigned long cur_state;
+
+	list_for_each_entry(instance, &tz->thermal_instances, tz_node) {
+		if (instance->trip != trip ||
+			instance->target == THERMAL_NO_TARGET)
+			continue;
+
+		cdev = instance->cdev;
+		cdev->ops->get_cur_state(cdev, &cur_state);
+
+		instance->target = cur_state > instance->lower ?
+			    (cur_state - 1) : THERMAL_NO_TARGET;
+
+		/* Deactivate a passive thermal instance */
+		if (instance->target == THERMAL_NO_TARGET)
+			update_passive_instance(tz, trip_type, -1);
+
+		cdev->updated = false; /* cdev needs update */
+	}
+}
+
+static void thermal_zone_trip_update(struct thermal_zone_device *tz, int trip)
+{
+	long trip_temp;
+	enum thermal_trip_type trip_type;
+	enum thermal_trend trend;
+
+	if (trip == THERMAL_TRIPS_NONE) {
+		trip_temp = tz->forced_passive;
+		trip_type = THERMAL_TRIPS_NONE;
+	} else {
+		tz->ops->get_trip_temp(tz, trip, &trip_temp);
+		tz->ops->get_trip_type(tz, trip, &trip_type);
+	}
+
+	trend = get_tz_trend(tz, trip);
+
+	mutex_lock(&tz->lock);
+
+	if (tz->temperature >= trip_temp)
+		update_instance_for_throttle(tz, trip, trip_type, trend);
+	else
+		update_instance_for_dethrottle(tz, trip, trip_type);
+
+	mutex_unlock(&tz->lock);
+}
+
+/**
+ * step_wise_throttle - throttles devices asscciated with the given zone
+ * @tz - thermal_zone_device
+ * @trip - the trip point
+ * @trip_type - type of the trip point
+ *
+ * Throttling Logic: This uses the trend of the thermal zone to throttle.
+ * If the thermal zone is 'heating up' this throttles all the cooling
+ * devices associated with the zone and its particular trip point, by one
+ * step. If the zone is 'cooling down' it brings back the performance of
+ * the devices by one step.
+ */
+int step_wise_throttle(struct thermal_zone_device *tz, int trip)
+{
+	struct thermal_instance *instance;
+
+	thermal_zone_trip_update(tz, trip);
+
+	if (tz->forced_passive)
+		thermal_zone_trip_update(tz, THERMAL_TRIPS_NONE);
+
+	mutex_lock(&tz->lock);
+
+	list_for_each_entry(instance, &tz->thermal_instances, tz_node)
+		thermal_cdev_update(instance->cdev);
+
+	mutex_unlock(&tz->lock);
+
+	return 0;
+}
+
+struct thermal_governor thermal_gov_step_wise = {
+	.name		= DEFAULT_THERMAL_GOVERNOR,
+	.throttle	= step_wise_throttle,
+	.owner		= THIS_MODULE,
+};
+
+static int __init thermal_gov_step_wise_init(void)
+{
+	return thermal_register_governor(&thermal_gov_step_wise);
+}
+
+static void __exit thermal_gov_step_wise_exit(void)
+{
+	thermal_unregister_governor(&thermal_gov_step_wise);
+}
+
+/* This should load after thermal framework */
+fs_initcall(thermal_gov_step_wise_init);
+module_exit(thermal_gov_step_wise_exit);
+
+MODULE_AUTHOR("Durgadoss R");
+MODULE_DESCRIPTION("A step-by-step thermal throttling governor");
+MODULE_LICENSE("GPL");
-- 
1.7.7.6


^ permalink raw reply related

* [PATCH 07/34] Thermal: Add a policy sysfs attribute
From: Zhang Rui @ 2012-12-02 14:44 UTC (permalink / raw)
  To: linux-pm; +Cc: Durgadoss R, Zhang Rui
In-Reply-To: <1354459508-3707-1-git-send-email-rui.zhang@intel.com>

From: Durgadoss R <durgadoss.r@intel.com>

This patch adds a policy sysfs attribute to a thermal zone.
This attribute denotes the throttling governor used for the
zone. This is a RW attribute.

Signed-off-by: Durgadoss R <durgadoss.r@intel.com>
Signed-off-by: Zhang Rui <rui.zhang@intel.com>
---
 drivers/thermal/thermal_sys.c |   42 ++++++++++++++++++++++++++++++++++++++--
 1 files changed, 39 insertions(+), 3 deletions(-)

diff --git a/drivers/thermal/thermal_sys.c b/drivers/thermal/thermal_sys.c
index 0afd84c..a6933da 100644
--- a/drivers/thermal/thermal_sys.c
+++ b/drivers/thermal/thermal_sys.c
@@ -454,10 +454,41 @@ passive_show(struct device *dev, struct device_attribute *attr,
 	return sprintf(buf, "%d\n", tz->forced_passive);
 }
 
+static ssize_t
+policy_store(struct device *dev, struct device_attribute *attr,
+		    const char *buf, size_t count)
+{
+	int ret = -EINVAL;
+	struct thermal_zone_device *tz = to_thermal_zone(dev);
+	struct thermal_governor *gov;
+
+	mutex_lock(&thermal_governor_lock);
+
+	gov = __find_governor(buf);
+	if (!gov)
+		goto exit;
+
+	tz->governor = gov;
+	ret = count;
+
+exit:
+	mutex_unlock(&thermal_governor_lock);
+	return ret;
+}
+
+static ssize_t
+policy_show(struct device *dev, struct device_attribute *devattr, char *buf)
+{
+	struct thermal_zone_device *tz = to_thermal_zone(dev);
+
+	return sprintf(buf, "%s\n", tz->governor->name);
+}
+
 static DEVICE_ATTR(type, 0444, type_show, NULL);
 static DEVICE_ATTR(temp, 0444, temp_show, NULL);
 static DEVICE_ATTR(mode, 0644, mode_show, mode_store);
 static DEVICE_ATTR(passive, S_IRUGO | S_IWUSR, passive_show, passive_store);
+static DEVICE_ATTR(policy, S_IRUGO | S_IWUSR, policy_show, policy_store);
 
 /* sys I/F for cooling device */
 #define to_cooling_device(_dev)	\
@@ -1509,10 +1540,14 @@ struct thermal_zone_device *thermal_zone_device_register(const char *type,
 			passive = 1;
 	}
 
-	if (!passive)
-		result = device_create_file(&tz->device,
-					    &dev_attr_passive);
+	if (!passive) {
+		result = device_create_file(&tz->device, &dev_attr_passive);
+		if (result)
+			goto unregister;
+	}
 
+	/* Create policy attribute */
+	result = device_create_file(&tz->device, &dev_attr_policy);
 	if (result)
 		goto unregister;
 
@@ -1588,6 +1623,7 @@ void thermal_zone_device_unregister(struct thermal_zone_device *tz)
 	device_remove_file(&tz->device, &dev_attr_temp);
 	if (tz->ops->get_mode)
 		device_remove_file(&tz->device, &dev_attr_mode);
+	device_remove_file(&tz->device, &dev_attr_policy);
 	remove_trip_attrs(tz);
 	tz->governor = NULL;
 
-- 
1.7.7.6


^ permalink raw reply related

* [PATCH 10/34] Thermal: Introduce fair_share thermal governor
From: Zhang Rui @ 2012-12-02 14:44 UTC (permalink / raw)
  To: linux-pm; +Cc: Durgadoss R, Zhang Rui
In-Reply-To: <1354459508-3707-1-git-send-email-rui.zhang@intel.com>

From: Durgadoss R <durgadoss.r@intel.com>

This patch introduces a simple 'weight' based
governor named fair_share governor. Whenever the
thermal framework gets notified of the trip point
violation, this governor (if configured), throttles
the cooling devices associated with a thermal zone.

This mapping between a thermal zone and a cooling device
and the effectiveness of cooling are provided in the
platform layer.

Signed-off-by: Durgadoss R <durgadoss.r@intel.com>
Signed-off-by: Zhang Rui <rui.zhang@intel.com>
---
 drivers/thermal/Kconfig      |    6 ++
 drivers/thermal/Makefile     |    1 +
 drivers/thermal/fair_share.c |  133 ++++++++++++++++++++++++++++++++++++++++++
 3 files changed, 140 insertions(+), 0 deletions(-)
 create mode 100644 drivers/thermal/fair_share.c

diff --git a/drivers/thermal/Kconfig b/drivers/thermal/Kconfig
index e1cb6bd..84b0f03 100644
--- a/drivers/thermal/Kconfig
+++ b/drivers/thermal/Kconfig
@@ -55,3 +55,9 @@ config EXYNOS_THERMAL
 	help
 	  If you say yes here you get support for TMU (Thermal Managment
 	  Unit) on SAMSUNG EXYNOS series of SoC.
+
+config FAIR_SHARE
+	bool "Fair-share thermal governor"
+	depends on THERMAL
+	help
+	  Enable this to manage platform thermals using fair-share governor.
diff --git a/drivers/thermal/Makefile b/drivers/thermal/Makefile
index 885550d..30540dd 100644
--- a/drivers/thermal/Makefile
+++ b/drivers/thermal/Makefile
@@ -7,3 +7,4 @@ obj-$(CONFIG_CPU_THERMAL)		+= cpu_cooling.o
 obj-$(CONFIG_SPEAR_THERMAL)		+= spear_thermal.o
 obj-$(CONFIG_RCAR_THERMAL)	+= rcar_thermal.o
 obj-$(CONFIG_EXYNOS_THERMAL)		+= exynos_thermal.o
+obj-$(CONFIG_FAIR_SHARE)		+= fair_share.o
diff --git a/drivers/thermal/fair_share.c b/drivers/thermal/fair_share.c
new file mode 100644
index 0000000..5d3a7a3
--- /dev/null
+++ b/drivers/thermal/fair_share.c
@@ -0,0 +1,133 @@
+/*
+ *  fair_share.c - A simple weight based Thermal governor
+ *
+ *  Copyright (C) 2012 Intel Corp
+ *  Copyright (C) 2012 Durgadoss R <durgadoss.r@intel.com>
+ *
+ *  ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+ *
+ *  This program is free software; you can redistribute it and/or modify
+ *  it under the terms of the GNU General Public License as published by
+ *  the Free Software Foundation; version 2 of the License.
+ *
+ *  This program is distributed in the hope that it will be useful, but
+ *  WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ *  General Public License for more details.
+ *
+ *  You should have received a copy of the GNU General Public License along
+ *  with this program; if not, write to the Free Software Foundation, Inc.,
+ *  59 Temple Place, Suite 330, Boston, MA 02111-1307 USA.
+ *
+ * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+ */
+
+#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
+
+#include <linux/module.h>
+#include <linux/thermal.h>
+
+#include "thermal_core.h"
+
+/**
+ * get_trip_level: - obtains the current trip level for a zone
+ * @tz:		thermal zone device
+ */
+static int get_trip_level(struct thermal_zone_device *tz)
+{
+	int count = 0;
+	unsigned long trip_temp;
+
+	if (tz->trips == 0 || !tz->ops->get_trip_temp)
+		return 0;
+
+	for (count = 0; count < tz->trips; count++) {
+		tz->ops->get_trip_temp(tz, count, &trip_temp);
+		if (tz->temperature < trip_temp)
+			break;
+	}
+	return count;
+}
+
+static long get_target_state(struct thermal_zone_device *tz,
+		struct thermal_cooling_device *cdev, int weight, int level)
+{
+	unsigned long max_state;
+
+	cdev->ops->get_max_state(cdev, &max_state);
+
+	return (long)(weight * level * max_state) / (100 * tz->trips);
+}
+
+/**
+ * fair_share_throttle - throttles devices asscciated with the given zone
+ * @tz - thermal_zone_device
+ *
+ * Throttling Logic: This uses three parameters to calculate the new
+ * throttle state of the cooling devices associated with the given zone.
+ *
+ * Parameters used for Throttling:
+ * P1. max_state: Maximum throttle state exposed by the cooling device.
+ * P2. weight[i]/100:
+ *	How 'effective' the 'i'th device is, in cooling the given zone.
+ * P3. cur_trip_level/max_no_of_trips:
+ *	This describes the extent to which the devices should be throttled.
+ *	We do not want to throttle too much when we trip a lower temperature,
+ *	whereas the throttling is at full swing if we trip critical levels.
+ *	(Heavily assumes the trip points are in ascending order)
+ * new_state of cooling device = P3 * P2 * P1
+ */
+int fair_share_throttle(struct thermal_zone_device *tz, int trip)
+{
+	const struct thermal_zone_params *tzp;
+	struct thermal_cooling_device *cdev;
+	struct thermal_instance *instance;
+	int i;
+	int cur_trip_level = get_trip_level(tz);
+
+	if (!tz->tzp || !tz->tzp->tbp)
+		return -EINVAL;
+
+	tzp = tz->tzp;
+
+	for (i = 0; i < tzp->num_tbps; i++) {
+		if (!tzp->tbp[i].cdev)
+			continue;
+
+		cdev = tzp->tbp[i].cdev;
+		instance = get_thermal_instance(tz, cdev, trip);
+		if (!instance)
+			continue;
+
+		instance->target = get_target_state(tz, cdev,
+					tzp->tbp[i].weight, cur_trip_level);
+
+		instance->cdev->updated = false;
+		thermal_cdev_update(cdev);
+	}
+	return 0;
+}
+
+struct thermal_governor thermal_gov_fair_share = {
+	.name		= "fair_share",
+	.throttle	= fair_share_throttle,
+	.owner		= THIS_MODULE,
+};
+
+static int __init thermal_gov_fair_share_init(void)
+{
+	return thermal_register_governor(&thermal_gov_fair_share);
+}
+
+static void __exit thermal_gov_fair_share_exit(void)
+{
+	thermal_unregister_governor(&thermal_gov_fair_share);
+}
+
+/* This should load after thermal framework */
+fs_initcall(thermal_gov_fair_share_init);
+module_exit(thermal_gov_fair_share_exit);
+
+MODULE_AUTHOR("Durgadoss R");
+MODULE_DESCRIPTION("A simple weight based thermal throttling governor");
+MODULE_LICENSE("GPL");
-- 
1.7.7.6


^ permalink raw reply related

* [PATCH 09/34] Thermal: Make thermal_cdev_update as a global function
From: Zhang Rui @ 2012-12-02 14:44 UTC (permalink / raw)
  To: linux-pm; +Cc: Durgadoss R, Zhang Rui
In-Reply-To: <1354459508-3707-1-git-send-email-rui.zhang@intel.com>

From: Durgadoss R <durgadoss.r@intel.com>

This patch makes the thermal_cdev_update function as a
global one, so that other files can use it. This function
serves as a single arbitrator to set the state of a cooling
device.

Signed-off-by: Durgadoss R <durgadoss.r@intel.com>
Signed-off-by: Zhang Rui <rui.zhang@intel.com>
---
 drivers/thermal/thermal_sys.c |    5 +++--
 include/linux/thermal.h       |    1 +
 2 files changed, 4 insertions(+), 2 deletions(-)

diff --git a/drivers/thermal/thermal_sys.c b/drivers/thermal/thermal_sys.c
index a328032..9d21f82 100644
--- a/drivers/thermal/thermal_sys.c
+++ b/drivers/thermal/thermal_sys.c
@@ -1257,7 +1257,7 @@ void thermal_cooling_device_unregister(struct thermal_cooling_device *cdev)
 }
 EXPORT_SYMBOL(thermal_cooling_device_unregister);
 
-static void thermal_cdev_do_update(struct thermal_cooling_device *cdev)
+void thermal_cdev_update(struct thermal_cooling_device *cdev)
 {
 	struct thermal_instance *instance;
 	unsigned long target = 0;
@@ -1278,13 +1278,14 @@ static void thermal_cdev_do_update(struct thermal_cooling_device *cdev)
 	cdev->ops->set_cur_state(cdev, target);
 	cdev->updated = true;
 }
+EXPORT_SYMBOL(thermal_cdev_update);
 
 static void thermal_zone_do_update(struct thermal_zone_device *tz)
 {
 	struct thermal_instance *instance;
 
 	list_for_each_entry(instance, &tz->thermal_instances, tz_node)
-		thermal_cdev_do_update(instance->cdev);
+		thermal_cdev_update(instance->cdev);
 }
 
 /*
diff --git a/include/linux/thermal.h b/include/linux/thermal.h
index 6182bd5..2bd9158 100644
--- a/include/linux/thermal.h
+++ b/include/linux/thermal.h
@@ -231,6 +231,7 @@ void thermal_cooling_device_unregister(struct thermal_cooling_device *);
 int get_tz_trend(struct thermal_zone_device *, int);
 struct thermal_instance *get_thermal_instance(struct thermal_zone_device *,
 		struct thermal_cooling_device *, int);
+void thermal_cdev_update(struct thermal_cooling_device *);
 
 int thermal_register_governor(struct thermal_governor *);
 void thermal_unregister_governor(struct thermal_governor *);
-- 
1.7.7.6


^ permalink raw reply related

* [PATCH 12/34] Thermal: Add a thermal notifier for user space
From: Zhang Rui @ 2012-12-02 14:44 UTC (permalink / raw)
  To: linux-pm; +Cc: Durgadoss R, Zhang Rui
In-Reply-To: <1354459508-3707-1-git-send-email-rui.zhang@intel.com>

From: Durgadoss R <durgadoss.r@intel.com>

This patch registers a governor which will let the
user land manage the platform thermals. Whenever a
trip happens, this governor just notifies the user
space using kobj_uevent().

Signed-off-by: Durgadoss R <durgadoss.r@intel.com>
Signed-off-by: Zhang Rui <rui.zhang@intel.com>
---
 drivers/thermal/Kconfig      |    6 ++++
 drivers/thermal/Makefile     |    1 +
 drivers/thermal/user_space.c |   68 ++++++++++++++++++++++++++++++++++++++++++
 3 files changed, 75 insertions(+), 0 deletions(-)
 create mode 100644 drivers/thermal/user_space.c

diff --git a/drivers/thermal/Kconfig b/drivers/thermal/Kconfig
index 7e1b6de..f679eea 100644
--- a/drivers/thermal/Kconfig
+++ b/drivers/thermal/Kconfig
@@ -67,3 +67,9 @@ config STEP_WISE
 	depends on THERMAL
 	help
 	  Enable this to manage platform thermals using a simple linear
+
+config USER_SPACE
+	bool "User_space thermal governor"
+	depends on THERMAL
+	help
+	  Enable this to let the user space manage the platform thermals.
diff --git a/drivers/thermal/Makefile b/drivers/thermal/Makefile
index 4e53c00..e5f7974 100644
--- a/drivers/thermal/Makefile
+++ b/drivers/thermal/Makefile
@@ -9,3 +9,4 @@ obj-$(CONFIG_RCAR_THERMAL)	+= rcar_thermal.o
 obj-$(CONFIG_EXYNOS_THERMAL)		+= exynos_thermal.o
 obj-$(CONFIG_FAIR_SHARE)		+= fair_share.o
 obj-$(CONFIG_STEP_WISE)			+= step_wise.o
+obj-$(CONFIG_USER_SPACE)		+= user_space.o
diff --git a/drivers/thermal/user_space.c b/drivers/thermal/user_space.c
new file mode 100644
index 0000000..fb246b90
--- /dev/null
+++ b/drivers/thermal/user_space.c
@@ -0,0 +1,68 @@
+/*
+ *  user_space.c - A simple user space Thermal events notifier
+ *
+ *  Copyright (C) 2012 Intel Corp
+ *  Copyright (C) 2012 Durgadoss R <durgadoss.r@intel.com>
+ *
+ *  ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+ *
+ *  This program is free software; you can redistribute it and/or modify
+ *  it under the terms of the GNU General Public License as published by
+ *  the Free Software Foundation; version 2 of the License.
+ *
+ *  This program is distributed in the hope that it will be useful, but
+ *  WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ *  General Public License for more details.
+ *
+ *  You should have received a copy of the GNU General Public License along
+ *  with this program; if not, write to the Free Software Foundation, Inc.,
+ *  59 Temple Place, Suite 330, Boston, MA 02111-1307 USA.
+ *
+ * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+ */
+
+#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
+
+#include <linux/module.h>
+#include <linux/thermal.h>
+
+#include "thermal_core.h"
+
+/**
+ * notify_user_space - Notifies user space about thermal events
+ * @tz - thermal_zone_device
+ *
+ * This function notifies the user space through UEvents.
+ */
+int notify_user_space(struct thermal_zone_device *tz, int trip)
+{
+	mutex_lock(&tz->lock);
+	kobject_uevent(&tz->device.kobj, KOBJ_CHANGE);
+	mutex_unlock(&tz->lock);
+	return 0;
+}
+
+struct thermal_governor thermal_gov_user_space = {
+	.name		= "user_space",
+	.throttle	= notify_user_space,
+	.owner		= THIS_MODULE,
+};
+
+static int __init thermal_gov_user_space_init(void)
+{
+	return thermal_register_governor(&thermal_gov_user_space);
+}
+
+static void __exit thermal_gov_user_space_exit(void)
+{
+	thermal_unregister_governor(&thermal_gov_user_space);
+}
+
+/* This should load after thermal framework */
+fs_initcall(thermal_gov_user_space_init);
+module_exit(thermal_gov_user_space_exit);
+
+MODULE_AUTHOR("Durgadoss R");
+MODULE_DESCRIPTION("A user space Thermal notifier");
+MODULE_LICENSE("GPL");
-- 
1.7.7.6


^ permalink raw reply related

* [PATCH 05/34] Thermal: Pass zone parameters as argument to tzd_register
From: Zhang Rui @ 2012-12-02 14:44 UTC (permalink / raw)
  To: linux-pm; +Cc: Durgadoss R, Zhang Rui
In-Reply-To: <1354459508-3707-1-git-send-email-rui.zhang@intel.com>

From: Durgadoss R <durgadoss.r@intel.com>

This patch adds the thermal zone parameter as an argument to
the tzd_register() function call; and updates other drivers
using this function.

Signed-off-by: Durgadoss R <durgadoss.r@intel.com>
Signed-off-by: Zhang Rui <rui.zhang@intel.com>
---
 drivers/acpi/thermal.c                             |    6 +++---
 drivers/platform/x86/acerhdf.c                     |    2 +-
 drivers/platform/x86/intel_mid_thermal.c           |    2 +-
 drivers/power/power_supply_core.c                  |    2 +-
 drivers/staging/omap-thermal/omap-thermal-common.c |    2 +-
 drivers/thermal/exynos_thermal.c                   |    2 +-
 drivers/thermal/rcar_thermal.c                     |    2 +-
 drivers/thermal/spear_thermal.c                    |    2 +-
 drivers/thermal/thermal_sys.c                      |    3 +++
 include/linux/thermal.h                            |    3 ++-
 10 files changed, 15 insertions(+), 11 deletions(-)

diff --git a/drivers/acpi/thermal.c b/drivers/acpi/thermal.c
index 804204d..1794468 100644
--- a/drivers/acpi/thermal.c
+++ b/drivers/acpi/thermal.c
@@ -900,14 +900,14 @@ 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,
+						&acpi_thermal_zone_ops, NULL,
 						     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, 0,
-						     tz->polling_frequency*100);
+						&acpi_thermal_zone_ops, NULL,
+						0, tz->polling_frequency*100);
 	if (IS_ERR(tz->thermal_zone))
 		return -ENODEV;
 
diff --git a/drivers/platform/x86/acerhdf.c b/drivers/platform/x86/acerhdf.c
index 84c5688..c2e3e63 100644
--- a/drivers/platform/x86/acerhdf.c
+++ b/drivers/platform/x86/acerhdf.c
@@ -662,7 +662,7 @@ static int acerhdf_register_thermal(void)
 		return -EINVAL;
 
 	thz_dev = thermal_zone_device_register("acerhdf", 1, 0, NULL,
-					      &acerhdf_dev_ops, 0,
+					      &acerhdf_dev_ops, NULL, 0,
 					      (kernelmode) ? interval*1000 : 0);
 	if (IS_ERR(thz_dev))
 		return -EINVAL;
diff --git a/drivers/platform/x86/intel_mid_thermal.c b/drivers/platform/x86/intel_mid_thermal.c
index c809761..93de090 100644
--- a/drivers/platform/x86/intel_mid_thermal.c
+++ b/drivers/platform/x86/intel_mid_thermal.c
@@ -502,7 +502,7 @@ static int mid_thermal_probe(struct platform_device *pdev)
 			goto err;
 		}
 		pinfo->tzd[i] = thermal_zone_device_register(name[i],
-				0, 0, td_info, &tzd_ops, 0, 0);
+				0, 0, td_info, &tzd_ops, NULL, 0, 0);
 		if (IS_ERR(pinfo->tzd[i])) {
 			kfree(td_info);
 			ret = PTR_ERR(pinfo->tzd[i]);
diff --git a/drivers/power/power_supply_core.c b/drivers/power/power_supply_core.c
index 2436f13..f77a412 100644
--- a/drivers/power/power_supply_core.c
+++ b/drivers/power/power_supply_core.c
@@ -201,7 +201,7 @@ static int psy_register_thermal(struct power_supply *psy)
 	for (i = 0; i < psy->num_properties; i++) {
 		if (psy->properties[i] == POWER_SUPPLY_PROP_TEMP) {
 			psy->tzd = thermal_zone_device_register(psy->name, 0, 0,
-					psy, &psy_tzd_ops, 0, 0);
+					psy, &psy_tzd_ops, NULL, 0, 0);
 			if (IS_ERR(psy->tzd))
 				return PTR_ERR(psy->tzd);
 			break;
diff --git a/drivers/staging/omap-thermal/omap-thermal-common.c b/drivers/staging/omap-thermal/omap-thermal-common.c
index 5c0c203b..788f64f 100644
--- a/drivers/staging/omap-thermal/omap-thermal-common.c
+++ b/drivers/staging/omap-thermal/omap-thermal-common.c
@@ -270,7 +270,7 @@ int omap_thermal_expose_sensor(struct omap_bandgap *bg_ptr, int id,
 	/* Create thermal zone */
 	data->omap_thermal = thermal_zone_device_register(domain,
 				OMAP_TRIP_NUMBER, 0, data, &omap_thermal_ops,
-				FAST_TEMP_MONITORING_RATE,
+				NULL, FAST_TEMP_MONITORING_RATE,
 				FAST_TEMP_MONITORING_RATE);
 	if (IS_ERR_OR_NULL(data->omap_thermal)) {
 		dev_err(bg_ptr->dev, "thermal zone device is NULL\n");
diff --git a/drivers/thermal/exynos_thermal.c b/drivers/thermal/exynos_thermal.c
index 6dd29e4..7772d16 100644
--- a/drivers/thermal/exynos_thermal.c
+++ b/drivers/thermal/exynos_thermal.c
@@ -451,7 +451,7 @@ static int exynos_register_thermal(struct thermal_sensor_conf *sensor_conf)
 	th_zone->cool_dev_size++;
 
 	th_zone->therm_dev = thermal_zone_device_register(sensor_conf->name,
-			EXYNOS_ZONE_COUNT, 0, NULL, &exynos_dev_ops, 0,
+			EXYNOS_ZONE_COUNT, 0, NULL, &exynos_dev_ops, NULL, 0,
 			IDLE_INTERVAL);
 
 	if (IS_ERR(th_zone->therm_dev)) {
diff --git a/drivers/thermal/rcar_thermal.c b/drivers/thermal/rcar_thermal.c
index f7a1b57..762f637 100644
--- a/drivers/thermal/rcar_thermal.c
+++ b/drivers/thermal/rcar_thermal.c
@@ -211,7 +211,7 @@ static int rcar_thermal_probe(struct platform_device *pdev)
 	}
 
 	zone = thermal_zone_device_register("rcar_thermal", 0, 0, priv,
-					    &rcar_thermal_zone_ops, 0, 0);
+				    &rcar_thermal_zone_ops, NULL, 0, 0);
 	if (IS_ERR(zone)) {
 		dev_err(&pdev->dev, "thermal zone device is NULL\n");
 		ret = PTR_ERR(zone);
diff --git a/drivers/thermal/spear_thermal.c b/drivers/thermal/spear_thermal.c
index 9bc9692..6b2d8b2 100644
--- a/drivers/thermal/spear_thermal.c
+++ b/drivers/thermal/spear_thermal.c
@@ -147,7 +147,7 @@ static int spear_thermal_probe(struct platform_device *pdev)
 	writel_relaxed(stdev->flags, stdev->thermal_base);
 
 	spear_thermal = thermal_zone_device_register("spear_thermal", 0, 0,
-				stdev, &ops, 0, 0);
+				stdev, &ops, NULL, 0, 0);
 	if (IS_ERR(spear_thermal)) {
 		dev_err(&pdev->dev, "thermal zone device is NULL\n");
 		ret = PTR_ERR(spear_thermal);
diff --git a/drivers/thermal/thermal_sys.c b/drivers/thermal/thermal_sys.c
index 1f98c56..dca3bfc 100644
--- a/drivers/thermal/thermal_sys.c
+++ b/drivers/thermal/thermal_sys.c
@@ -1341,6 +1341,7 @@ static void remove_trip_attrs(struct thermal_zone_device *tz)
  * @mask:	a bit string indicating the writeablility of trip points
  * @devdata:	private device data
  * @ops:	standard thermal zone device callbacks
+ * @tzp:	thermal zone platform parameters
  * @passive_delay: number of milliseconds to wait between polls when
  *		   performing passive cooling
  * @polling_delay: number of milliseconds to wait between polls when checking
@@ -1353,6 +1354,7 @@ static void remove_trip_attrs(struct thermal_zone_device *tz)
 struct thermal_zone_device *thermal_zone_device_register(const char *type,
 	int trips, int mask, void *devdata,
 	const struct thermal_zone_device_ops *ops,
+	const struct thermal_zone_params *tzp,
 	int passive_delay, int polling_delay)
 {
 	struct thermal_zone_device *tz;
@@ -1386,6 +1388,7 @@ struct thermal_zone_device *thermal_zone_device_register(const char *type,
 
 	strcpy(tz->type, type ? : "");
 	tz->ops = ops;
+	tz->tzp = tzp;
 	tz->device.class = &thermal_class;
 	tz->devdata = devdata;
 	tz->trips = trips;
diff --git a/include/linux/thermal.h b/include/linux/thermal.h
index 4caa32e..58cb1c0 100644
--- a/include/linux/thermal.h
+++ b/include/linux/thermal.h
@@ -200,7 +200,8 @@ struct thermal_genl_event {
 
 /* Function declarations */
 struct thermal_zone_device *thermal_zone_device_register(const char *, int, int,
-		void *, const struct thermal_zone_device_ops *, int, int);
+		void *, const struct thermal_zone_device_ops *,
+		const struct thermal_zone_params *, int, int);
 void thermal_zone_device_unregister(struct thermal_zone_device *);
 
 int thermal_zone_bind_cooling_device(struct thermal_zone_device *, int,
-- 
1.7.7.6


^ permalink raw reply related

* [PATCH 06/34] Thermal: Add thermal governor registration APIs
From: Zhang Rui @ 2012-12-02 14:44 UTC (permalink / raw)
  To: linux-pm; +Cc: Durgadoss R, Zhang Rui
In-Reply-To: <1354459508-3707-1-git-send-email-rui.zhang@intel.com>

From: Durgadoss R <durgadoss.r@intel.com>

This patch creates a structure to hold platform
thermal governor information, and provides APIs
for individual thermal governors to register/unregister
with the Thermal framework.

Signed-off-by: Durgadoss R <durgadoss.r@intel.com>
Signed-off-by: Zhang Rui <rui.zhang@intel.com>
---
 drivers/thermal/thermal_sys.c |   90 +++++++++++++++++++++++++++++++++++++++++
 include/linux/thermal.h       |   16 +++++++
 2 files changed, 106 insertions(+), 0 deletions(-)

diff --git a/drivers/thermal/thermal_sys.c b/drivers/thermal/thermal_sys.c
index dca3bfc..0afd84c 100644
--- a/drivers/thermal/thermal_sys.c
+++ b/drivers/thermal/thermal_sys.c
@@ -49,7 +49,86 @@ static DEFINE_MUTEX(thermal_idr_lock);
 
 static LIST_HEAD(thermal_tz_list);
 static LIST_HEAD(thermal_cdev_list);
+static LIST_HEAD(thermal_governor_list);
+
 static DEFINE_MUTEX(thermal_list_lock);
+static DEFINE_MUTEX(thermal_governor_lock);
+
+static struct thermal_governor *__find_governor(const char *name)
+{
+	struct thermal_governor *pos;
+
+	list_for_each_entry(pos, &thermal_governor_list, governor_list)
+		if (!strnicmp(name, pos->name, THERMAL_NAME_LENGTH))
+			return pos;
+
+	return NULL;
+}
+
+int thermal_register_governor(struct thermal_governor *governor)
+{
+	int err;
+	const char *name;
+	struct thermal_zone_device *pos;
+
+	if (!governor)
+		return -EINVAL;
+
+	mutex_lock(&thermal_governor_lock);
+
+	err = -EBUSY;
+	if (__find_governor(governor->name) == NULL) {
+		err = 0;
+		list_add(&governor->governor_list, &thermal_governor_list);
+	}
+
+	mutex_lock(&thermal_list_lock);
+
+	list_for_each_entry(pos, &thermal_tz_list, node) {
+		if (pos->governor)
+			continue;
+		if (pos->tzp)
+			name = pos->tzp->governor_name;
+		else
+			name = DEFAULT_THERMAL_GOVERNOR;
+		if (!strnicmp(name, governor->name, THERMAL_NAME_LENGTH))
+			pos->governor = governor;
+	}
+
+	mutex_unlock(&thermal_list_lock);
+	mutex_unlock(&thermal_governor_lock);
+
+	return err;
+}
+EXPORT_SYMBOL_GPL(thermal_register_governor);
+
+void thermal_unregister_governor(struct thermal_governor *governor)
+{
+	struct thermal_zone_device *pos;
+
+	if (!governor)
+		return;
+
+	mutex_lock(&thermal_governor_lock);
+
+	if (__find_governor(governor->name) == NULL)
+		goto exit;
+
+	mutex_lock(&thermal_list_lock);
+
+	list_for_each_entry(pos, &thermal_tz_list, node) {
+		if (!strnicmp(pos->governor->name, governor->name,
+						THERMAL_NAME_LENGTH))
+			pos->governor = NULL;
+	}
+
+	mutex_unlock(&thermal_list_lock);
+	list_del(&governor->governor_list);
+exit:
+	mutex_unlock(&thermal_governor_lock);
+	return;
+}
+EXPORT_SYMBOL_GPL(thermal_unregister_governor);
 
 static int get_idr(struct idr *idr, struct mutex *lock, int *id)
 {
@@ -1437,6 +1516,16 @@ struct thermal_zone_device *thermal_zone_device_register(const char *type,
 	if (result)
 		goto unregister;
 
+	/* Update 'this' zone's governor information */
+	mutex_lock(&thermal_governor_lock);
+
+	if (tz->tzp)
+		tz->governor = __find_governor(tz->tzp->governor_name);
+	else
+		tz->governor = __find_governor(DEFAULT_THERMAL_GOVERNOR);
+
+	mutex_unlock(&thermal_governor_lock);
+
 	result = thermal_add_hwmon_sysfs(tz);
 	if (result)
 		goto unregister;
@@ -1500,6 +1589,7 @@ void thermal_zone_device_unregister(struct thermal_zone_device *tz)
 	if (tz->ops->get_mode)
 		device_remove_file(&tz->device, &dev_attr_mode);
 	remove_trip_attrs(tz);
+	tz->governor = NULL;
 
 	thermal_remove_hwmon_sysfs(tz);
 	release_idr(&thermal_tz_idr, &thermal_idr_lock, tz->id);
diff --git a/include/linux/thermal.h b/include/linux/thermal.h
index 58cb1c0..6182bd5 100644
--- a/include/linux/thermal.h
+++ b/include/linux/thermal.h
@@ -46,6 +46,9 @@
 #define THERMAL_GENL_VERSION                    0x01
 #define THERMAL_GENL_MCAST_GROUP_NAME           "thermal_mc_group"
 
+/* Default Thermal Governor: Does Linear Throttling */
+#define DEFAULT_THERMAL_GOVERNOR	"step_wise"
+
 struct thermal_zone_device;
 struct thermal_cooling_device;
 
@@ -158,6 +161,7 @@ struct thermal_zone_device {
 	unsigned int forced_passive;
 	const struct thermal_zone_device_ops *ops;
 	const struct thermal_zone_params *tzp;
+	struct thermal_governor *governor;
 	struct list_head thermal_instances;
 	struct idr idr;
 	struct mutex lock; /* protect thermal_instances list */
@@ -165,6 +169,14 @@ struct thermal_zone_device {
 	struct delayed_work poll_queue;
 };
 
+/* Structure that holds thermal governor information */
+struct thermal_governor {
+	char name[THERMAL_NAME_LENGTH];
+	int (*throttle)(struct thermal_zone_device *tz, int trip);
+	struct list_head	governor_list;
+	struct module		*owner;
+};
+
 /* Structure that holds binding parameters for a zone */
 struct thermal_bind_params {
 	struct thermal_cooling_device *cdev;
@@ -189,6 +201,7 @@ struct thermal_bind_params {
 
 /* Structure to define Thermal Zone parameters */
 struct thermal_zone_params {
+	char governor_name[THERMAL_NAME_LENGTH];
 	int num_tbps;	/* Number of tbp entries */
 	struct thermal_bind_params *tbp;
 };
@@ -219,6 +232,9 @@ int get_tz_trend(struct thermal_zone_device *, int);
 struct thermal_instance *get_thermal_instance(struct thermal_zone_device *,
 		struct thermal_cooling_device *, int);
 
+int thermal_register_governor(struct thermal_governor *);
+void thermal_unregister_governor(struct thermal_governor *);
+
 #ifdef CONFIG_NET
 extern int thermal_generate_netlink_event(u32 orig, enum events event);
 #else
-- 
1.7.7.6


^ permalink raw reply related

* [PATCH 08/34] Thermal: Update binding logic based on platform data
From: Zhang Rui @ 2012-12-02 14:44 UTC (permalink / raw)
  To: linux-pm; +Cc: Durgadoss R, Zhang Rui
In-Reply-To: <1354459508-3707-1-git-send-email-rui.zhang@intel.com>

From: Durgadoss R <durgadoss.r@intel.com>

This patch updates the binding logic in thermal_sys.c
It uses the platform layer data to bind a thermal zone
to a cdev for a particular trip point.

 * If we do not have platform data and do not have
   .bind defined, do not bind.
 * If we do not have platform data but .bind is
   defined, then use tz->ops->bind.
 * If we have platform data, use it to create binding.

The same logic sequence is followed for unbind also.

Signed-off-by: Durgadoss R <durgadoss.r@intel.com>
Signed-off-by: Zhang Rui <rui.zhang@intel.com>
---
 drivers/thermal/thermal_sys.c |  183 +++++++++++++++++++++++++++++++++++------
 1 files changed, 157 insertions(+), 26 deletions(-)

diff --git a/drivers/thermal/thermal_sys.c b/drivers/thermal/thermal_sys.c
index a6933da..a328032 100644
--- a/drivers/thermal/thermal_sys.c
+++ b/drivers/thermal/thermal_sys.c
@@ -201,6 +201,111 @@ struct thermal_instance *get_thermal_instance(struct thermal_zone_device *tz,
 }
 EXPORT_SYMBOL(get_thermal_instance);
 
+static void print_bind_err_msg(struct thermal_zone_device *tz,
+			struct thermal_cooling_device *cdev, int ret)
+{
+	dev_err(&tz->device, "binding zone %s with cdev %s failed:%d\n",
+				tz->type, cdev->type, ret);
+}
+
+static void __bind(struct thermal_zone_device *tz, int mask,
+			struct thermal_cooling_device *cdev)
+{
+	int i, ret;
+
+	for (i = 0; i < tz->trips; i++) {
+		if (mask & (1 << i)) {
+			ret = thermal_zone_bind_cooling_device(tz, i, cdev,
+					THERMAL_NO_LIMIT, THERMAL_NO_LIMIT);
+			if (ret)
+				print_bind_err_msg(tz, cdev, ret);
+		}
+	}
+}
+
+static void __unbind(struct thermal_zone_device *tz, int mask,
+			struct thermal_cooling_device *cdev)
+{
+	int i;
+
+	for (i = 0; i < tz->trips; i++)
+		if (mask & (1 << i))
+			thermal_zone_unbind_cooling_device(tz, i, cdev);
+}
+
+static void bind_cdev(struct thermal_cooling_device *cdev)
+{
+	int i, ret;
+	const struct thermal_zone_params *tzp;
+	struct thermal_zone_device *pos = NULL;
+
+	mutex_lock(&thermal_list_lock);
+
+	list_for_each_entry(pos, &thermal_tz_list, node) {
+		if (!pos->tzp && !pos->ops->bind)
+			continue;
+
+		if (!pos->tzp && pos->ops->bind) {
+			ret = pos->ops->bind(pos, cdev);
+			if (ret)
+				print_bind_err_msg(pos, cdev, ret);
+		}
+
+		tzp = pos->tzp;
+		if (!tzp->tbp)
+			return;
+
+		for (i = 0; i < tzp->num_tbps; i++) {
+			if (tzp->tbp[i].cdev || !tzp->tbp[i].match)
+				continue;
+			if (tzp->tbp[i].match(pos, cdev))
+				continue;
+			tzp->tbp[i].cdev = cdev;
+			__bind(pos, tzp->tbp[i].trip_mask, cdev);
+		}
+	}
+
+	mutex_unlock(&thermal_list_lock);
+}
+
+static void bind_tz(struct thermal_zone_device *tz)
+{
+	int i, ret;
+	struct thermal_cooling_device *pos = NULL;
+	const struct thermal_zone_params *tzp = tz->tzp;
+
+	if (!tzp && !tz->ops->bind)
+		return;
+
+	mutex_lock(&thermal_list_lock);
+
+	/* If there is no platform data, try to use ops->bind */
+	if (!tzp && tz->ops->bind) {
+		list_for_each_entry(pos, &thermal_cdev_list, node) {
+			ret = tz->ops->bind(tz, pos);
+			if (ret)
+				print_bind_err_msg(tz, pos, ret);
+		}
+		goto exit;
+	}
+
+	if (!tzp->tbp)
+		goto exit;
+
+	list_for_each_entry(pos, &thermal_cdev_list, node) {
+		for (i = 0; i < tzp->num_tbps; i++) {
+			if (tzp->tbp[i].cdev || !tzp->tbp[i].match)
+				continue;
+			if (tzp->tbp[i].match(tz, pos))
+				continue;
+			tzp->tbp[i].cdev = pos;
+			__bind(tz, tzp->tbp[i].trip_mask, pos);
+		}
+	}
+exit:
+	mutex_unlock(&thermal_list_lock);
+}
+
 /* sys I/F for thermal zone */
 
 #define to_thermal_zone(_dev) \
@@ -1026,7 +1131,6 @@ thermal_cooling_device_register(char *type, void *devdata,
 				const struct thermal_cooling_device_ops *ops)
 {
 	struct thermal_cooling_device *cdev;
-	struct thermal_zone_device *pos;
 	int result;
 
 	if (type && strlen(type) >= THERMAL_NAME_LENGTH)
@@ -1076,20 +1180,15 @@ thermal_cooling_device_register(char *type, void *devdata,
 	if (result)
 		goto unregister;
 
+	/* Add 'this' new cdev to the global cdev list */
 	mutex_lock(&thermal_list_lock);
 	list_add(&cdev->node, &thermal_cdev_list);
-	list_for_each_entry(pos, &thermal_tz_list, node) {
-		if (!pos->ops->bind)
-			continue;
-		result = pos->ops->bind(pos, cdev);
-		if (result)
-			break;
-
-	}
 	mutex_unlock(&thermal_list_lock);
 
-	if (!result)
-		return cdev;
+	/* Update binding information for 'this' new cdev */
+	bind_cdev(cdev);
+
+	return cdev;
 
 unregister:
 	release_idr(&thermal_cdev_idr, &thermal_idr_lock, cdev->id);
@@ -1105,10 +1204,10 @@ EXPORT_SYMBOL(thermal_cooling_device_register);
  * thermal_cooling_device_unregister() must be called when the device is no
  * longer needed.
  */
-void thermal_cooling_device_unregister(struct
-				       thermal_cooling_device
-				       *cdev)
+void thermal_cooling_device_unregister(struct thermal_cooling_device *cdev)
 {
+	int i;
+	const struct thermal_zone_params *tzp;
 	struct thermal_zone_device *tz;
 	struct thermal_cooling_device *pos = NULL;
 
@@ -1125,12 +1224,28 @@ void thermal_cooling_device_unregister(struct
 		return;
 	}
 	list_del(&cdev->node);
+
+	/* Unbind all thermal zones associated with 'this' cdev */
 	list_for_each_entry(tz, &thermal_tz_list, node) {
-		if (!tz->ops->unbind)
+		if (tz->ops->unbind) {
+			tz->ops->unbind(tz, cdev);
+			continue;
+		}
+
+		if (!tz->tzp || !tz->tzp->tbp)
 			continue;
-		tz->ops->unbind(tz, cdev);
+
+		tzp = tz->tzp;
+		for (i = 0; i < tzp->num_tbps; i++) {
+			if (tzp->tbp[i].cdev == cdev) {
+				__unbind(tz, tzp->tbp[i].trip_mask, cdev);
+				tzp->tbp[i].cdev = NULL;
+			}
+		}
 	}
+
 	mutex_unlock(&thermal_list_lock);
+
 	if (cdev->type[0])
 		device_remove_file(&cdev->device, &dev_attr_cdev_type);
 	device_remove_file(&cdev->device, &dev_attr_max_state);
@@ -1468,7 +1583,6 @@ struct thermal_zone_device *thermal_zone_device_register(const char *type,
 	int passive_delay, int polling_delay)
 {
 	struct thermal_zone_device *tz;
-	struct thermal_cooling_device *pos;
 	enum thermal_trip_type trip_type;
 	int result;
 	int count;
@@ -1567,14 +1681,11 @@ struct thermal_zone_device *thermal_zone_device_register(const char *type,
 
 	mutex_lock(&thermal_list_lock);
 	list_add_tail(&tz->node, &thermal_tz_list);
-	if (ops->bind)
-		list_for_each_entry(pos, &thermal_cdev_list, node) {
-		result = ops->bind(tz, pos);
-		if (result)
-			break;
-		}
 	mutex_unlock(&thermal_list_lock);
 
+	/* Bind cooling devices for this zone */
+	bind_tz(tz);
+
 	INIT_DELAYED_WORK(&(tz->poll_queue), thermal_zone_device_check);
 
 	thermal_zone_device_update(tz);
@@ -1595,12 +1706,16 @@ EXPORT_SYMBOL(thermal_zone_device_register);
  */
 void thermal_zone_device_unregister(struct thermal_zone_device *tz)
 {
+	int i;
+	const struct thermal_zone_params *tzp;
 	struct thermal_cooling_device *cdev;
 	struct thermal_zone_device *pos = NULL;
 
 	if (!tz)
 		return;
 
+	tzp = tz->tzp;
+
 	mutex_lock(&thermal_list_lock);
 	list_for_each_entry(pos, &thermal_tz_list, node)
 	    if (pos == tz)
@@ -1611,9 +1726,25 @@ void thermal_zone_device_unregister(struct thermal_zone_device *tz)
 		return;
 	}
 	list_del(&tz->node);
-	if (tz->ops->unbind)
-		list_for_each_entry(cdev, &thermal_cdev_list, node)
-		    tz->ops->unbind(tz, cdev);
+
+	/* Unbind all cdevs associated with 'this' thermal zone */
+	list_for_each_entry(cdev, &thermal_cdev_list, node) {
+		if (tz->ops->unbind) {
+			tz->ops->unbind(tz, cdev);
+			continue;
+		}
+
+		if (!tzp || !tzp->tbp)
+			break;
+
+		for (i = 0; i < tzp->num_tbps; i++) {
+			if (tzp->tbp[i].cdev == cdev) {
+				__unbind(tz, tzp->tbp[i].trip_mask, cdev);
+				tzp->tbp[i].cdev = NULL;
+			}
+		}
+	}
+
 	mutex_unlock(&thermal_list_lock);
 
 	thermal_zone_device_set_polling(tz, 0);
-- 
1.7.7.6


^ permalink raw reply related

* [PATCH 03/34] Thermal: Add get trend, get instance API's to thermal_sys
From: Zhang Rui @ 2012-12-02 14:44 UTC (permalink / raw)
  To: linux-pm; +Cc: Durgadoss R, Zhang Rui
In-Reply-To: <1354459508-3707-1-git-send-email-rui.zhang@intel.com>

From: Durgadoss R <durgadoss.r@intel.com>

This patch adds the following API's to thermal_sys.c, that
can be used by other Thermal drivers.
 * get_tz_trend: obtain the trend of the given thermal zone
 * get_thermal_instance: obtain the instance corresponding
   to the given tz, cdev and the trip point.

Signed-off-by: Durgadoss R <durgadoss.r@intel.com>
Signed-off-by: Zhang Rui <rui.zhang@intel.com>
---
 drivers/thermal/thermal_sys.c |   40 ++++++++++++++++++++++++++++++++++++++++
 include/linux/thermal.h       |    4 ++++
 2 files changed, 44 insertions(+), 0 deletions(-)

diff --git a/drivers/thermal/thermal_sys.c b/drivers/thermal/thermal_sys.c
index bbc8346..1f98c56 100644
--- a/drivers/thermal/thermal_sys.c
+++ b/drivers/thermal/thermal_sys.c
@@ -82,6 +82,46 @@ static void release_idr(struct idr *idr, struct mutex *lock, int id)
 		mutex_unlock(lock);
 }
 
+int get_tz_trend(struct thermal_zone_device *tz, int trip)
+{
+	enum thermal_trend trend;
+
+	if (!tz->ops->get_trend || tz->ops->get_trend(tz, trip, &trend)) {
+		if (tz->temperature > tz->last_temperature)
+			trend = THERMAL_TREND_RAISING;
+		else if (tz->temperature < tz->last_temperature)
+			trend = THERMAL_TREND_DROPPING;
+		else
+			trend = THERMAL_TREND_STABLE;
+	}
+
+	return trend;
+}
+EXPORT_SYMBOL(get_tz_trend);
+
+struct thermal_instance *get_thermal_instance(struct thermal_zone_device *tz,
+			struct thermal_cooling_device *cdev, int trip)
+{
+	struct thermal_instance *pos = NULL;
+	struct thermal_instance *target_instance = NULL;
+
+	mutex_lock(&tz->lock);
+	mutex_lock(&cdev->lock);
+
+	list_for_each_entry(pos, &tz->thermal_instances, tz_node) {
+		if (pos->tz == tz && pos->trip == trip && pos->cdev == cdev) {
+			target_instance = pos;
+			break;
+		}
+	}
+
+	mutex_unlock(&cdev->lock);
+	mutex_unlock(&tz->lock);
+
+	return target_instance;
+}
+EXPORT_SYMBOL(get_thermal_instance);
+
 /* sys I/F for thermal zone */
 
 #define to_thermal_zone(_dev) \
diff --git a/include/linux/thermal.h b/include/linux/thermal.h
index 8611e3e..32af124 100644
--- a/include/linux/thermal.h
+++ b/include/linux/thermal.h
@@ -185,6 +185,10 @@ struct thermal_cooling_device *thermal_cooling_device_register(char *, void *,
 		const struct thermal_cooling_device_ops *);
 void thermal_cooling_device_unregister(struct thermal_cooling_device *);
 
+int get_tz_trend(struct thermal_zone_device *, int);
+struct thermal_instance *get_thermal_instance(struct thermal_zone_device *,
+		struct thermal_cooling_device *, int);
+
 #ifdef CONFIG_NET
 extern int thermal_generate_netlink_event(u32 orig, enum events event);
 #else
-- 
1.7.7.6


^ permalink raw reply related

* [PATCH 04/34] Thermal: Add platform level information to thermal.h
From: Zhang Rui @ 2012-12-02 14:44 UTC (permalink / raw)
  To: linux-pm; +Cc: Durgadoss R, Zhang Rui
In-Reply-To: <1354459508-3707-1-git-send-email-rui.zhang@intel.com>

From: Durgadoss R <durgadoss.r@intel.com>

This patch adds platform level information to thermal.h
by introducing two structures to hold:
 * bind parameters for a thermal zone,
 * zone level platform parameters

Signed-off-by: Durgadoss R <durgadoss.r@intel.com>
Signed-off-by: Zhang Rui <rui.zhang@intel.com>
---
 include/linux/thermal.h |   29 +++++++++++++++++++++++++++++
 1 files changed, 29 insertions(+), 0 deletions(-)

diff --git a/include/linux/thermal.h b/include/linux/thermal.h
index 32af124..4caa32e 100644
--- a/include/linux/thermal.h
+++ b/include/linux/thermal.h
@@ -157,6 +157,7 @@ struct thermal_zone_device {
 	int passive;
 	unsigned int forced_passive;
 	const struct thermal_zone_device_ops *ops;
+	const struct thermal_zone_params *tzp;
 	struct list_head thermal_instances;
 	struct idr idr;
 	struct mutex lock; /* protect thermal_instances list */
@@ -164,6 +165,34 @@ struct thermal_zone_device {
 	struct delayed_work poll_queue;
 };
 
+/* Structure that holds binding parameters for a zone */
+struct thermal_bind_params {
+	struct thermal_cooling_device *cdev;
+
+	/*
+	 * This is a measure of 'how effectively these devices can
+	 * cool 'this' thermal zone. The shall be determined by platform
+	 * characterization. This is on a 'percentage' scale.
+	 * See Documentation/thermal/sysfs-api.txt for more information.
+	 */
+	int weight;
+
+	/*
+	 * This is a bit mask that gives the binding relation between this
+	 * thermal zone and cdev, for a particular trip point.
+	 * See Documentation/thermal/sysfs-api.txt for more information.
+	 */
+	int trip_mask;
+	int (*match) (struct thermal_zone_device *tz,
+			struct thermal_cooling_device *cdev);
+};
+
+/* Structure to define Thermal Zone parameters */
+struct thermal_zone_params {
+	int num_tbps;	/* Number of tbp entries */
+	struct thermal_bind_params *tbp;
+};
+
 struct thermal_genl_event {
 	u32 orig;
 	enum events event;
-- 
1.7.7.6


^ permalink raw reply related


This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox