All of lore.kernel.org
 help / color / mirror / Atom feed
* [RFC PATCH 0/7] Support for Multiple sensors per zone
@ 2012-11-17 10:45 Durgadoss R
  2012-11-17 10:45 ` [RFC PATCH 1/7] Thermal: Create sensor level APIs Durgadoss R
                   ` (8 more replies)
  0 siblings, 9 replies; 27+ messages in thread
From: Durgadoss R @ 2012-11-17 10:45 UTC (permalink / raw)
  To: rui.zhang, linux-pm
  Cc: wni, eduardo.valentin, amit.kachhap, hongbo.zhang, sachin.kamat,
	Durgadoss R

This patch series attempts to add support for multiple
sensors per zone. The work is based on the Thermal discussion
happened in plumbers conference 2012, here:
http://www.linuxplumbersconf.org/2012/schedule/
Title: "Enhancing the Thermal Management Infrastructure in Linux"

The intention is to make it easy for generic sensor drivers
to register with the framework, and let them participate in
platform thermal management. Another goal is to expose the
binding information in a consistent way so that user space
can consume the information and potentially manage platform thermals.

This series contains 7 patches:
Patch 1/7: Creates new sensor level APIs
Patch 2/7: Creates new zone level APIs. The existing tzd structure is
	   kept as such for clarity and compatibility purposes.
Patch 3/7: Creates functions to add/remove a cdev to/from a zone. The
	   existing tcd structure need not be modified.
Patch 4/7: Adds a thermal_trip sysfs node, which exposes various trip
	   points for all sensors present in a zone.
Patch 5/7: Adds a thermal_map sysfs node. It is a compact representation
	   of the binding relationship between a sensor and a cdev,
	   within a zone.
Patch 6/7: Creates Documentation for the new APIs. A new file is
	   created for clarity. Final goal is to merge with the existing
	   file or refactor the files, as whatever seems appropriate.
Patch 7/7: A dummy driver that can be used for testing. This is not for merge.

Next steps:
 1. Move all the existing drivers to the new implementation model.
    Help welcomed from individual driver authors/maintainers for this.
 2. Make the thermal governors work with this new model.
 3. Remove old/unused code from thermal_sys.c.
 4. Add more detailed documentation

 I didn't want to submit patches for all these in one-go, since it
 might end-up being difficult to comprehend, besides delaying the
 review process. The other obvious reason being I cannot test all
 the changes on various drivers for 1.

 All these patches have been tested on a Core-i5 desktop running
 ubuntu 12.04 and an atom notebook running ubuntu 11.10.
 Kindly help review.

Durgadoss R (7):
  Thermal: Create sensor level APIs
  Thermal: Create zone level APIs
  Thermal: Add APIs to bind cdev to new zone structure
  Thermal: Add Thermal_trip sysfs node
  Thermal: Add 'thermal_map' sysfs node
  Thermal: Add Documentation to new APIs
  Thermal: Dummy driver used for testing

 Documentation/thermal/sysfs-api2.txt |  213 ++++++++
 drivers/thermal/Kconfig              |    5 +
 drivers/thermal/Makefile             |    3 +
 drivers/thermal/thermal_sys.c        |  915 ++++++++++++++++++++++++++++++++++
 drivers/thermal/thermal_test.c       |  321 ++++++++++++
 include/linux/thermal.h              |  118 +++++
 6 files changed, 1575 insertions(+)
 create mode 100644 Documentation/thermal/sysfs-api2.txt
 create mode 100644 drivers/thermal/thermal_test.c

-- 
1.7.9.5


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

* [RFC PATCH 1/7] Thermal: Create sensor level APIs
  2012-11-17 10:45 [RFC PATCH 0/7] Support for Multiple sensors per zone Durgadoss R
@ 2012-11-17 10:45 ` Durgadoss R
  2012-11-17 10:45 ` [RFC PATCH 2/7] Thermal: Create zone " Durgadoss R
                   ` (7 subsequent siblings)
  8 siblings, 0 replies; 27+ messages in thread
From: Durgadoss R @ 2012-11-17 10:45 UTC (permalink / raw)
  To: rui.zhang, linux-pm
  Cc: wni, eduardo.valentin, amit.kachhap, hongbo.zhang, sachin.kamat,
	Durgadoss R

This patch creates sensor level APIs, in the
generic thermal framework. With this, thermal
sensor drivers can register/unregister themselves
with the thermal framework, and thus can participate
in platform thermal management.

Signed-off-by: Durgadoss R <durgadoss.r@intel.com>
---
 drivers/thermal/thermal_sys.c |  212 +++++++++++++++++++++++++++++++++++++++++
 include/linux/thermal.h       |   27 ++++++
 2 files changed, 239 insertions(+)

diff --git a/drivers/thermal/thermal_sys.c b/drivers/thermal/thermal_sys.c
index 8f0f37b..e726c8b 100644
--- a/drivers/thermal/thermal_sys.c
+++ b/drivers/thermal/thermal_sys.c
@@ -45,13 +45,16 @@ MODULE_LICENSE("GPL");
 
 static DEFINE_IDR(thermal_tz_idr);
 static DEFINE_IDR(thermal_cdev_idr);
+static DEFINE_IDR(thermal_sensor_idr);
 static DEFINE_MUTEX(thermal_idr_lock);
 
 static LIST_HEAD(thermal_tz_list);
+static LIST_HEAD(thermal_sensor_list);
 static LIST_HEAD(thermal_cdev_list);
 static LIST_HEAD(thermal_governor_list);
 
 static DEFINE_MUTEX(thermal_list_lock);
+static DEFINE_MUTEX(ts_list_lock);
 static DEFINE_MUTEX(thermal_governor_lock);
 
 static struct thermal_governor *__find_governor(const char *name)
@@ -421,6 +424,66 @@ static void thermal_zone_device_check(struct work_struct *work)
 #define to_thermal_zone(_dev) \
 	container_of(_dev, struct thermal_zone_device, device)
 
+#define to_thermal_sensor(_dev) \
+	container_of(_dev, struct thermal_sensor, device)
+
+static ssize_t
+sensor_name_show(struct device *dev, struct device_attribute *attr, char *buf)
+{
+	struct thermal_sensor *ts = to_thermal_sensor(dev);
+
+	return sprintf(buf, "%s\n", ts->name);
+}
+
+static ssize_t
+sensor_temp_show(struct device *dev, struct device_attribute *attr, char *buf)
+{
+	int ret;
+	long val;
+	struct thermal_sensor *ts = to_thermal_sensor(dev);
+
+	ret = ts->ops->get_temp(ts, &val);
+
+	return ret ? ret : sprintf(buf, "%ld\n", val);
+}
+
+static ssize_t
+threshold_show(struct device *dev, struct device_attribute *attr, char *buf)
+{
+	int indx, ret;
+	long val;
+	struct thermal_sensor *ts = to_thermal_sensor(dev);
+
+	if (!sscanf(attr->attr.name, "threshold%d", &indx))
+		return -EINVAL;
+
+	ret = ts->ops->get_threshold(ts, indx, &val);
+
+	return ret ? ret : sprintf(buf, "%ld\n", val);
+}
+
+static ssize_t
+threshold_store(struct device *dev, struct device_attribute *attr,
+				   const char *buf, size_t count)
+{
+	int indx, ret;
+	long val;
+	struct thermal_sensor *ts = to_thermal_sensor(dev);
+
+	if (!ts->ops->set_threshold)
+		return -EPERM;
+
+	if (!sscanf(attr->attr.name, "threshold%d", &indx))
+		return -EINVAL;
+
+	if (kstrtol(buf, 10, &val))
+		return -EINVAL;
+
+	ret = ts->ops->set_threshold(ts, indx, val);
+
+	return ret ? ret : count;
+}
+
 static ssize_t
 type_show(struct device *dev, struct device_attribute *attr, char *buf)
 {
@@ -705,6 +768,10 @@ 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);
 
+/* Thermal sensor attributes */
+static DEVICE_ATTR(sensor_name, 0444, sensor_name_show, NULL);
+static DEVICE_ATTR(temp_input, 0444, sensor_temp_show, NULL);
+
 /* sys I/F for cooling device */
 #define to_cooling_device(_dev)	\
 	container_of(_dev, struct thermal_cooling_device, device)
@@ -1491,6 +1558,151 @@ static void remove_trip_attrs(struct thermal_zone_device *tz)
 }
 
 /**
+ * thermal_sensor_register - register a new thermal sensor
+ * @name:	name of the thermal sensor
+ * @ops:	standard thermal sensor callbacks
+ * @devdata:	private device data
+ */
+struct thermal_sensor *thermal_sensor_register(const char *name,
+			struct thermal_sensor_ops *ops, void *devdata)
+{
+	struct thermal_sensor *ts;
+	int ret;
+
+	if (!name || (name && strlen(name) >= THERMAL_NAME_LENGTH))
+		return ERR_PTR(-EINVAL);
+
+	if (!ops || !ops->get_temp)
+		return ERR_PTR(-EINVAL);
+
+	ts = kzalloc(sizeof(*ts), GFP_KERNEL);
+	if (!ts)
+		return ERR_PTR(-ENOMEM);
+
+	idr_init(&ts->idr);
+	ret = get_idr(&thermal_sensor_idr, &thermal_idr_lock, &ts->id);
+	if (ret)
+		goto exit_free;
+
+	strcpy(ts->name, name);
+	ts->ops = ops;
+	ts->devdata = devdata;
+	ts->device.class = &thermal_class;
+
+	dev_set_name(&ts->device, "sensor%d", ts->id);
+	ret = device_register(&ts->device);
+	if (ret)
+		goto exit_idr;
+
+	ret = device_create_file(&ts->device, &dev_attr_sensor_name);
+	if (ret)
+		goto exit_unregister;
+
+	ret = device_create_file(&ts->device, &dev_attr_temp_input);
+	if (ret)
+		goto exit_name;
+
+	/* Add this sensor to the global list of sensors */
+	mutex_lock(&ts_list_lock);
+	list_add_tail(&ts->node, &thermal_sensor_list);
+	mutex_unlock(&ts_list_lock);
+
+	return ts;
+
+exit_name:
+	device_remove_file(&ts->device, &dev_attr_sensor_name);
+exit_unregister:
+	device_unregister(&ts->device);
+exit_idr:
+	release_idr(&thermal_sensor_idr, &thermal_idr_lock, ts->id);
+exit_free:
+	kfree(ts);
+	return ERR_PTR(ret);
+}
+EXPORT_SYMBOL(thermal_sensor_register);
+
+void thermal_sensor_unregister(struct thermal_sensor *ts)
+{
+	int i;
+	struct thermal_sensor *pos, *next;
+	bool found = false;
+
+	if (!ts)
+		return;
+
+	mutex_lock(&ts_list_lock);
+	list_for_each_entry_safe(pos, next, &thermal_sensor_list, node) {
+		if (pos == ts) {
+			list_del(&ts->node);
+			found = true;
+			break;
+		}
+	}
+	mutex_unlock(&ts_list_lock);
+
+	if (!found)
+		return;
+
+	for (i = 0; i < ts->thresholds; i++)
+		device_remove_file(&ts->device, &ts->thresh_attrs[i].attr);
+
+	device_remove_file(&ts->device, &dev_attr_sensor_name);
+	device_remove_file(&ts->device, &dev_attr_temp_input);
+
+	release_idr(&thermal_sensor_idr, &thermal_idr_lock, ts->id);
+	idr_destroy(&ts->idr);
+
+	device_unregister(&ts->device);
+
+	kfree(ts);
+	return;
+}
+EXPORT_SYMBOL(thermal_sensor_unregister);
+
+int enable_sensor_thresholds(struct thermal_sensor *ts, int count)
+{
+	int i, ret;
+	int size = sizeof(struct thermal_attr) * count;
+
+	if (count == 0)
+		return 0; /* Not an error */
+
+	if (unlikely(!ts) || !ts->ops->get_threshold)
+		return -EINVAL;
+
+	ts->thresh_attrs = kzalloc(size, GFP_KERNEL);
+	if (!ts->thresh_attrs)
+		return -ENOMEM;
+
+	ts->thresholds = count;
+
+	/* Create threshold attributes */
+	for (i = 0; i < count; i++) {
+		snprintf(ts->thresh_attrs[i].name, THERMAL_NAME_LENGTH,
+						 "threshold%d", i);
+
+		sysfs_attr_init(&ts->thresh_attrs[i].attr.attr);
+		ts->thresh_attrs[i].attr.attr.name =
+						ts->thresh_attrs[i].name;
+		ts->thresh_attrs[i].attr.attr.mode = S_IRUGO | S_IWUSR;
+		ts->thresh_attrs[i].attr.show = threshold_show;
+		ts->thresh_attrs[i].attr.store = threshold_store;
+
+		ret = device_create_file(&ts->device,
+					&ts->thresh_attrs[i].attr);
+		if (ret)
+			goto exit_fail;
+	}
+	return 0;
+
+exit_fail:
+	while (--i >= 0)
+		device_remove_file(&ts->device, &ts->thresh_attrs[i].attr);
+	return ret;
+}
+EXPORT_SYMBOL(enable_sensor_thresholds);
+
+/**
  * thermal_zone_device_register - register a new thermal zone device
  * @type:	the thermal zone device type
  * @trips:	the number of trip points the thermal zone support
diff --git a/include/linux/thermal.h b/include/linux/thermal.h
index 807f214..e2f85ec 100644
--- a/include/linux/thermal.h
+++ b/include/linux/thermal.h
@@ -49,6 +49,7 @@
 /* Default Thermal Governor: Does Linear Throttling */
 #define DEFAULT_THERMAL_GOVERNOR	"step_wise"
 
+struct thermal_sensor;
 struct thermal_zone_device;
 struct thermal_cooling_device;
 
@@ -127,6 +128,13 @@ struct thermal_cooling_device_ops {
 	int (*set_cur_state) (struct thermal_cooling_device *, unsigned long);
 };
 
+struct thermal_sensor_ops {
+	int (*get_temp) (struct thermal_sensor *, long *);
+	int (*get_trend) (struct thermal_sensor *, int, enum thermal_trend *);
+	int (*set_threshold) (struct thermal_sensor *, int, long);
+	int (*get_threshold) (struct thermal_sensor *, int, long *);
+};
+
 struct thermal_cooling_device {
 	int id;
 	char type[THERMAL_NAME_LENGTH];
@@ -144,6 +152,20 @@ struct thermal_attr {
 	char name[THERMAL_NAME_LENGTH];
 };
 
+struct thermal_sensor {
+	char name[THERMAL_NAME_LENGTH];
+	int id;
+	int temp;
+	int prev_temp;
+	int thresholds;
+	void *devdata;
+	struct idr idr;
+	struct device device;
+	struct list_head node;
+	struct thermal_sensor_ops *ops;
+	struct thermal_attr *thresh_attrs;
+};
+
 struct thermal_zone_device {
 	int id;
 	char type[THERMAL_NAME_LENGTH];
@@ -237,6 +259,11 @@ void notify_thermal_framework(struct thermal_zone_device *, int);
 int thermal_register_governor(struct thermal_governor *);
 void thermal_unregister_governor(struct thermal_governor *);
 
+struct thermal_sensor *thermal_sensor_register(const char *,
+				struct thermal_sensor_ops *, void *);
+void thermal_sensor_unregister(struct thermal_sensor *);
+int enable_sensor_thresholds(struct thermal_sensor *, int);
+
 #ifdef CONFIG_NET
 extern int thermal_generate_netlink_event(u32 orig, enum events event);
 #else
-- 
1.7.9.5


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

* [RFC PATCH 2/7] Thermal: Create zone level APIs
  2012-11-17 10:45 [RFC PATCH 0/7] Support for Multiple sensors per zone Durgadoss R
  2012-11-17 10:45 ` [RFC PATCH 1/7] Thermal: Create sensor level APIs Durgadoss R
@ 2012-11-17 10:45 ` Durgadoss R
  2012-12-03  7:42   ` Hongbo Zhang
  2012-12-13  6:23   ` Hongbo Zhang
  2012-11-17 10:45 ` [RFC PATCH 3/7] Thermal: Add APIs to bind cdev to new zone structure Durgadoss R
                   ` (6 subsequent siblings)
  8 siblings, 2 replies; 27+ messages in thread
From: Durgadoss R @ 2012-11-17 10:45 UTC (permalink / raw)
  To: rui.zhang, linux-pm
  Cc: wni, eduardo.valentin, amit.kachhap, hongbo.zhang, sachin.kamat,
	Durgadoss R

This patch adds a new thermal_zone structure to
thermal.h. Also, adds zone level APIs to the thermal
framework.

Signed-off-by: Durgadoss R <durgadoss.r@intel.com>
---
 drivers/thermal/thermal_sys.c |  206 +++++++++++++++++++++++++++++++++++++++++
 include/linux/thermal.h       |   25 +++++
 2 files changed, 231 insertions(+)

diff --git a/drivers/thermal/thermal_sys.c b/drivers/thermal/thermal_sys.c
index e726c8b..9d386d7 100644
--- a/drivers/thermal/thermal_sys.c
+++ b/drivers/thermal/thermal_sys.c
@@ -44,19 +44,28 @@ MODULE_DESCRIPTION("Generic thermal management sysfs support");
 MODULE_LICENSE("GPL");
 
 static DEFINE_IDR(thermal_tz_idr);
+static DEFINE_IDR(thermal_zone_idr);
 static DEFINE_IDR(thermal_cdev_idr);
 static DEFINE_IDR(thermal_sensor_idr);
 static DEFINE_MUTEX(thermal_idr_lock);
 
 static LIST_HEAD(thermal_tz_list);
 static LIST_HEAD(thermal_sensor_list);
+static LIST_HEAD(thermal_zone_list);
 static LIST_HEAD(thermal_cdev_list);
 static LIST_HEAD(thermal_governor_list);
 
 static DEFINE_MUTEX(thermal_list_lock);
 static DEFINE_MUTEX(ts_list_lock);
+static DEFINE_MUTEX(tz_list_lock);
 static DEFINE_MUTEX(thermal_governor_lock);
 
+#define for_each_thermal_sensor(pos) \
+	list_for_each_entry(pos, &thermal_sensor_list, node)
+
+#define for_each_thermal_zone(pos) \
+	list_for_each_entry(pos, &thermal_zone_list, node)
+
 static struct thermal_governor *__find_governor(const char *name)
 {
 	struct thermal_governor *pos;
@@ -419,15 +428,62 @@ static void thermal_zone_device_check(struct work_struct *work)
 	thermal_zone_device_update(tz);
 }
 
+static int get_sensor_indx(struct thermal_zone *tz, struct thermal_sensor *ts)
+{
+	int i, indx = -EINVAL;
+
+	if (!tz || !ts)
+		return -EINVAL;
+
+	mutex_lock(&ts_list_lock);
+	for (i = 0; i < tz->sensor_indx; i++) {
+		if (tz->sensors[i] == ts) {
+			indx = i;
+			break;
+		}
+	}
+	mutex_unlock(&ts_list_lock);
+	return indx;
+}
+
+static void remove_sensor_from_zone(struct thermal_zone *tz,
+				struct thermal_sensor *ts)
+{
+	int indx, j;
+
+	indx = get_sensor_indx(tz, ts);
+	if (indx < 0)
+		return;
+
+	sysfs_remove_link(&tz->device.kobj, kobject_name(&ts->device.kobj));
+
+	/* Shift the entries in the tz->sensors array */
+	for (j = indx; j < MAX_SENSORS_PER_ZONE - 1; j++)
+		tz->sensors[j] = tz->sensors[j + 1];
+
+	tz->sensor_indx--;
+}
+
 /* sys I/F for thermal zone */
 
 #define to_thermal_zone(_dev) \
 	container_of(_dev, struct thermal_zone_device, device)
 
+#define to_zone(_dev) \
+	container_of(_dev, struct thermal_zone, device)
+
 #define to_thermal_sensor(_dev) \
 	container_of(_dev, struct thermal_sensor, device)
 
 static ssize_t
+zone_name_show(struct device *dev, struct device_attribute *attr, char *buf)
+{
+	struct thermal_zone *tz = to_zone(dev);
+
+	return sprintf(buf, "%s\n", tz->name);
+}
+
+static ssize_t
 sensor_name_show(struct device *dev, struct device_attribute *attr, char *buf)
 {
 	struct thermal_sensor *ts = to_thermal_sensor(dev);
@@ -772,6 +828,8 @@ static DEVICE_ATTR(policy, S_IRUGO | S_IWUSR, policy_show, policy_store);
 static DEVICE_ATTR(sensor_name, 0444, sensor_name_show, NULL);
 static DEVICE_ATTR(temp_input, 0444, sensor_temp_show, NULL);
 
+static DEVICE_ATTR(zone_name, 0444, zone_name_show, NULL);
+
 /* sys I/F for cooling device */
 #define to_cooling_device(_dev)	\
 	container_of(_dev, struct thermal_cooling_device, device)
@@ -1557,6 +1615,146 @@ static void remove_trip_attrs(struct thermal_zone_device *tz)
 	kfree(tz->trip_hyst_attrs);
 }
 
+struct thermal_zone *create_thermal_zone(const char *name, void *devdata)
+{
+	struct thermal_zone *tz;
+	int ret;
+
+	if (!name || (name && strlen(name) >= THERMAL_NAME_LENGTH))
+		return ERR_PTR(-EINVAL);
+
+	tz = kzalloc(sizeof(*tz), GFP_KERNEL);
+	if (!tz)
+		return ERR_PTR(-ENOMEM);
+
+	idr_init(&tz->idr);
+	ret = get_idr(&thermal_zone_idr, &thermal_idr_lock, &tz->id);
+	if (ret)
+		goto exit_free;
+
+	strcpy(tz->name, name);
+	tz->devdata = devdata;
+	tz->device.class = &thermal_class;
+
+	dev_set_name(&tz->device, "zone%d", tz->id);
+	ret = device_register(&tz->device);
+	if (ret)
+		goto exit_idr;
+
+	ret = device_create_file(&tz->device, &dev_attr_zone_name);
+	if (ret)
+		goto exit_unregister;
+
+	/* Add this zone to the global list of thermal zones */
+	mutex_lock(&tz_list_lock);
+	list_add_tail(&tz->node, &thermal_zone_list);
+	mutex_unlock(&tz_list_lock);
+	return tz;
+
+exit_unregister:
+	device_unregister(&tz->device);
+exit_idr:
+	release_idr(&thermal_zone_idr, &thermal_idr_lock, tz->id);
+exit_free:
+	kfree(tz);
+	return ERR_PTR(ret);
+}
+EXPORT_SYMBOL(create_thermal_zone);
+
+void remove_thermal_zone(struct thermal_zone *tz)
+{
+	struct thermal_zone *pos, *next;
+	bool found = false;
+
+	if (!tz)
+		return;
+
+	mutex_lock(&tz_list_lock);
+
+	list_for_each_entry_safe(pos, next, &thermal_zone_list, node) {
+		if (pos == tz) {
+			list_del(&tz->node);
+			found = true;
+			break;
+		}
+	}
+
+	if (!found)
+		goto exit;
+
+	device_remove_file(&tz->device, &dev_attr_zone_name);
+
+	release_idr(&thermal_zone_idr, &thermal_idr_lock, tz->id);
+	idr_destroy(&tz->idr);
+
+	device_unregister(&tz->device);
+	kfree(tz);
+exit:
+	mutex_unlock(&tz_list_lock);
+	return;
+}
+EXPORT_SYMBOL(remove_thermal_zone);
+
+struct thermal_sensor *get_sensor_by_name(const char *name)
+{
+	struct thermal_sensor *pos;
+	struct thermal_sensor *ts = NULL;
+
+	mutex_lock(&ts_list_lock);
+	for_each_thermal_sensor(pos) {
+		if (!strnicmp(pos->name, name, THERMAL_NAME_LENGTH)) {
+			ts = pos;
+			break;
+		}
+	}
+	mutex_unlock(&ts_list_lock);
+	return ts;
+}
+EXPORT_SYMBOL(get_sensor_by_name);
+
+int add_sensor_to_zone_by_name(struct thermal_zone *tz, const char *name)
+{
+	int ret;
+	struct thermal_sensor *ts = get_sensor_by_name(name);
+
+	if (!tz || !ts)
+		return -EINVAL;
+
+	mutex_lock(&tz_list_lock);
+
+	/* Ensure we are not adding the same sensor again!! */
+	ret = get_sensor_indx(tz, ts);
+	if (ret >= 0) {
+		ret = -EEXIST;
+		goto exit_zone;
+	}
+
+	mutex_lock(&ts_list_lock);
+
+	ret = sysfs_create_link(&tz->device.kobj, &ts->device.kobj,
+				kobject_name(&ts->device.kobj));
+	if (ret)
+		goto exit_sensor;
+
+	tz->sensors[tz->sensor_indx++] = ts;
+
+exit_sensor:
+	mutex_unlock(&ts_list_lock);
+exit_zone:
+	mutex_unlock(&tz_list_lock);
+	return ret;
+}
+EXPORT_SYMBOL(add_sensor_to_zone_by_name);
+
+int add_sensor_to_zone(struct thermal_zone *tz, struct thermal_sensor *ts)
+{
+	if (!tz || !ts)
+		return -EINVAL;
+
+	return add_sensor_to_zone_by_name(tz, ts->name);
+}
+EXPORT_SYMBOL(add_sensor_to_zone);
+
 /**
  * thermal_sensor_register - register a new thermal sensor
  * @name:	name of the thermal sensor
@@ -1624,6 +1822,7 @@ EXPORT_SYMBOL(thermal_sensor_register);
 void thermal_sensor_unregister(struct thermal_sensor *ts)
 {
 	int i;
+	struct thermal_zone *tz;
 	struct thermal_sensor *pos, *next;
 	bool found = false;
 
@@ -1643,6 +1842,13 @@ void thermal_sensor_unregister(struct thermal_sensor *ts)
 	if (!found)
 		return;
 
+	mutex_lock(&tz_list_lock);
+
+	for_each_thermal_zone(tz)
+		remove_sensor_from_zone(tz, ts);
+
+	mutex_unlock(&tz_list_lock);
+
 	for (i = 0; i < ts->thresholds; i++)
 		device_remove_file(&ts->device, &ts->thresh_attrs[i].attr);
 
diff --git a/include/linux/thermal.h b/include/linux/thermal.h
index e2f85ec..38438be 100644
--- a/include/linux/thermal.h
+++ b/include/linux/thermal.h
@@ -49,6 +49,11 @@
 /* Default Thermal Governor: Does Linear Throttling */
 #define DEFAULT_THERMAL_GOVERNOR	"step_wise"
 
+/* Maximum number of sensors, allowed in a thermal zone
+ * We will start with 5, and increase if needed.
+ */
+#define MAX_SENSORS_PER_ZONE		5
+
 struct thermal_sensor;
 struct thermal_zone_device;
 struct thermal_cooling_device;
@@ -191,6 +196,21 @@ struct thermal_zone_device {
 	struct delayed_work poll_queue;
 };
 
+struct thermal_zone {
+	char name[THERMAL_NAME_LENGTH];
+	int id;
+	void *devdata;
+	struct thermal_zone *ops;
+	struct thermal_governor *governor;
+	struct idr idr;
+	struct device device;
+	struct list_head node;
+
+	/* Sensor level information */
+	int sensor_indx; /* index into 'sensors' array */
+	struct thermal_sensor *sensors[MAX_SENSORS_PER_ZONE];
+};
+
 /* Structure that holds thermal governor information */
 struct thermal_governor {
 	char name[THERMAL_NAME_LENGTH];
@@ -264,6 +284,11 @@ struct thermal_sensor *thermal_sensor_register(const char *,
 void thermal_sensor_unregister(struct thermal_sensor *);
 int enable_sensor_thresholds(struct thermal_sensor *, int);
 
+struct thermal_zone *create_thermal_zone(const char *, void *);
+void remove_thermal_zone(struct thermal_zone *);
+int add_sensor_to_zone(struct thermal_zone *, struct thermal_sensor *);
+int add_sensor_to_zone_by_name(struct thermal_zone *, const char *);
+
 #ifdef CONFIG_NET
 extern int thermal_generate_netlink_event(u32 orig, enum events event);
 #else
-- 
1.7.9.5


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

* [RFC PATCH 3/7] Thermal: Add APIs to bind cdev to new zone structure
  2012-11-17 10:45 [RFC PATCH 0/7] Support for Multiple sensors per zone Durgadoss R
  2012-11-17 10:45 ` [RFC PATCH 1/7] Thermal: Create sensor level APIs Durgadoss R
  2012-11-17 10:45 ` [RFC PATCH 2/7] Thermal: Create zone " Durgadoss R
@ 2012-11-17 10:45 ` Durgadoss R
  2012-11-17 10:45 ` [RFC PATCH 4/7] Thermal: Add Thermal_trip sysfs node Durgadoss R
                   ` (5 subsequent siblings)
  8 siblings, 0 replies; 27+ messages in thread
From: Durgadoss R @ 2012-11-17 10:45 UTC (permalink / raw)
  To: rui.zhang, linux-pm
  Cc: wni, eduardo.valentin, amit.kachhap, hongbo.zhang, sachin.kamat,
	Durgadoss R

This patch creates new APIs to add/remove a
cdev to/from a zone. This patch does not change
the old cooling_device implementation.

Signed-off-by: Durgadoss R <durgadoss.r@intel.com>
---
 drivers/thermal/thermal_sys.c |  109 +++++++++++++++++++++++++++++++++++++++++
 include/linux/thermal.h       |    9 ++++
 2 files changed, 118 insertions(+)

diff --git a/drivers/thermal/thermal_sys.c b/drivers/thermal/thermal_sys.c
index 9d386d7..70e5f5a 100644
--- a/drivers/thermal/thermal_sys.c
+++ b/drivers/thermal/thermal_sys.c
@@ -58,6 +58,7 @@ static LIST_HEAD(thermal_governor_list);
 static DEFINE_MUTEX(thermal_list_lock);
 static DEFINE_MUTEX(ts_list_lock);
 static DEFINE_MUTEX(tz_list_lock);
+static DEFINE_MUTEX(cdev_list_lock);
 static DEFINE_MUTEX(thermal_governor_lock);
 
 #define for_each_thermal_sensor(pos) \
@@ -66,6 +67,9 @@ static DEFINE_MUTEX(thermal_governor_lock);
 #define for_each_thermal_zone(pos) \
 	list_for_each_entry(pos, &thermal_zone_list, node)
 
+#define for_each_cdev(pos) \
+	list_for_each_entry(pos, &thermal_cdev_list, node)
+
 static struct thermal_governor *__find_governor(const char *name)
 {
 	struct thermal_governor *pos;
@@ -428,6 +432,25 @@ static void thermal_zone_device_check(struct work_struct *work)
 	thermal_zone_device_update(tz);
 }
 
+static int get_cdev_indx(struct thermal_zone *tz,
+			struct thermal_cooling_device *cdev)
+{
+	int i, indx = -EINVAL;
+
+	if (!tz || !cdev)
+		return -EINVAL;
+
+	mutex_lock(&cdev_list_lock);
+	for (i = 0; i < tz->cdev_indx; i++) {
+		if (tz->cdevs[i] == cdev) {
+			indx = i;
+			break;
+		}
+	}
+	mutex_unlock(&cdev_list_lock);
+	return indx;
+}
+
 static int get_sensor_indx(struct thermal_zone *tz, struct thermal_sensor *ts)
 {
 	int i, indx = -EINVAL;
@@ -464,6 +487,24 @@ static void remove_sensor_from_zone(struct thermal_zone *tz,
 	tz->sensor_indx--;
 }
 
+static void remove_cdev_from_zone(struct thermal_zone *tz,
+				struct thermal_cooling_device *cdev)
+{
+	int indx, j;
+
+	indx = get_cdev_indx(tz, cdev);
+	if (indx < 0)
+		return;
+
+	sysfs_remove_link(&tz->device.kobj, kobject_name(&cdev->device.kobj));
+
+	/* Shift the entries in the tz->cdevs array */
+	for (j = indx; j < MAX_CDEVS_PER_ZONE - 1; j++)
+		tz->cdevs[j] = tz->cdevs[j + 1];
+
+	tz->cdev_indx--;
+}
+
 /* sys I/F for thermal zone */
 
 #define to_thermal_zone(_dev) \
@@ -1423,6 +1464,7 @@ 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_zone *tmp_tz;
 	struct thermal_cooling_device *pos = NULL;
 
 	if (!cdev)
@@ -1460,6 +1502,13 @@ void thermal_cooling_device_unregister(struct thermal_cooling_device *cdev)
 
 	mutex_unlock(&thermal_list_lock);
 
+	mutex_lock(&tz_list_lock);
+
+	for_each_thermal_zone(tmp_tz)
+		remove_cdev_from_zone(tmp_tz, cdev);
+
+	mutex_unlock(&tz_list_lock);
+
 	if (cdev->type[0])
 		device_remove_file(&cdev->device, &dev_attr_cdev_type);
 	device_remove_file(&cdev->device, &dev_attr_max_state);
@@ -1695,6 +1744,23 @@ exit:
 }
 EXPORT_SYMBOL(remove_thermal_zone);
 
+struct thermal_cooling_device *get_cdev_by_name(const char *name)
+{
+	struct thermal_cooling_device *pos;
+	struct thermal_cooling_device *cdev = NULL;
+
+	mutex_lock(&cdev_list_lock);
+	for_each_cdev(pos) {
+		if (!strnicmp(pos->type, name, THERMAL_NAME_LENGTH)) {
+			cdev = pos;
+			break;
+		}
+	}
+	mutex_unlock(&cdev_list_lock);
+	return cdev;
+}
+EXPORT_SYMBOL(get_cdev_by_name);
+
 struct thermal_sensor *get_sensor_by_name(const char *name)
 {
 	struct thermal_sensor *pos;
@@ -1755,6 +1821,49 @@ int add_sensor_to_zone(struct thermal_zone *tz, struct thermal_sensor *ts)
 }
 EXPORT_SYMBOL(add_sensor_to_zone);
 
+int add_cdev_to_zone_by_name(struct thermal_zone *tz, const char *name)
+{
+	int ret;
+	struct thermal_cooling_device *cdev = get_cdev_by_name(name);
+
+	if (!tz || !cdev)
+		return -EINVAL;
+
+	mutex_lock(&tz_list_lock);
+
+	/* Ensure we are not adding the same cdev again!! */
+	ret = get_cdev_indx(tz, cdev);
+	if (ret >= 0) {
+		ret = -EEXIST;
+		goto exit_zone;
+	}
+
+	mutex_lock(&cdev_list_lock);
+	ret = sysfs_create_link(&tz->device.kobj, &cdev->device.kobj,
+				kobject_name(&cdev->device.kobj));
+	if (ret)
+		goto exit_cdev;
+
+	tz->cdevs[tz->cdev_indx++] = cdev;
+
+exit_cdev:
+	mutex_unlock(&cdev_list_lock);
+exit_zone:
+	mutex_unlock(&tz_list_lock);
+	return ret;
+}
+EXPORT_SYMBOL(add_cdev_to_zone_by_name);
+
+int add_cdev_to_zone(struct thermal_zone *tz,
+			struct thermal_cooling_device *cdev)
+{
+	if (!tz || !cdev)
+		return -EINVAL;
+
+	return add_cdev_to_zone_by_name(tz, cdev->type);
+}
+EXPORT_SYMBOL(add_cdev_to_zone);
+
 /**
  * thermal_sensor_register - register a new thermal sensor
  * @name:	name of the thermal sensor
diff --git a/include/linux/thermal.h b/include/linux/thermal.h
index 38438be..2913910 100644
--- a/include/linux/thermal.h
+++ b/include/linux/thermal.h
@@ -54,6 +54,8 @@
  */
 #define MAX_SENSORS_PER_ZONE		5
 
+#define MAX_CDEVS_PER_ZONE		5
+
 struct thermal_sensor;
 struct thermal_zone_device;
 struct thermal_cooling_device;
@@ -209,6 +211,10 @@ struct thermal_zone {
 	/* Sensor level information */
 	int sensor_indx; /* index into 'sensors' array */
 	struct thermal_sensor *sensors[MAX_SENSORS_PER_ZONE];
+
+	/* cdev level information */
+	int cdev_indx; /* index into 'cdevs' array */
+	struct thermal_cooling_device *cdevs[MAX_CDEVS_PER_ZONE];
 };
 
 /* Structure that holds thermal governor information */
@@ -289,6 +295,9 @@ void remove_thermal_zone(struct thermal_zone *);
 int add_sensor_to_zone(struct thermal_zone *, struct thermal_sensor *);
 int add_sensor_to_zone_by_name(struct thermal_zone *, const char *);
 
+int add_cdev_to_zone(struct thermal_zone *, struct thermal_cooling_device *);
+int add_cdev_to_zone_by_name(struct thermal_zone *, const char *);
+
 #ifdef CONFIG_NET
 extern int thermal_generate_netlink_event(u32 orig, enum events event);
 #else
-- 
1.7.9.5


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

* [RFC PATCH 4/7] Thermal: Add Thermal_trip sysfs node
  2012-11-17 10:45 [RFC PATCH 0/7] Support for Multiple sensors per zone Durgadoss R
                   ` (2 preceding siblings ...)
  2012-11-17 10:45 ` [RFC PATCH 3/7] Thermal: Add APIs to bind cdev to new zone structure Durgadoss R
@ 2012-11-17 10:45 ` Durgadoss R
  2012-12-04  8:30   ` Hongbo Zhang
  2012-11-17 10:45 ` [RFC PATCH 5/7] Thermal: Add 'thermal_map' " Durgadoss R
                   ` (4 subsequent siblings)
  8 siblings, 1 reply; 27+ messages in thread
From: Durgadoss R @ 2012-11-17 10:45 UTC (permalink / raw)
  To: rui.zhang, linux-pm
  Cc: wni, eduardo.valentin, amit.kachhap, hongbo.zhang, sachin.kamat,
	Durgadoss R

This patch adds a thermal_trip directory under
/sys/class/thermal/zoneX. This directory contains
the trip point values for sensors bound to this
zone.

Signed-off-by: Durgadoss R <durgadoss.r@intel.com>
---
 drivers/thermal/thermal_sys.c |  244 ++++++++++++++++++++++++++++++++++++++++-
 include/linux/thermal.h       |   32 ++++++
 2 files changed, 274 insertions(+), 2 deletions(-)

diff --git a/drivers/thermal/thermal_sys.c b/drivers/thermal/thermal_sys.c
index 70e5f5a..011588a 100644
--- a/drivers/thermal/thermal_sys.c
+++ b/drivers/thermal/thermal_sys.c
@@ -480,9 +480,15 @@ static void remove_sensor_from_zone(struct thermal_zone *tz,
 
 	sysfs_remove_link(&tz->device.kobj, kobject_name(&ts->device.kobj));
 
+	/* Delete this sensor's trip Kobject */
+	kobject_del(tz->kobj_trip[indx]);
+
 	/* Shift the entries in the tz->sensors array */
-	for (j = indx; j < MAX_SENSORS_PER_ZONE - 1; j++)
+	for (j = indx; j < MAX_SENSORS_PER_ZONE - 1; j++) {
 		tz->sensors[j] = tz->sensors[j + 1];
+		tz->trip[j] = tz->trip[j + 1];
+		tz->kobj_trip[j] = tz->kobj_trip[j + 1];
+	}
 
 	tz->sensor_indx--;
 }
@@ -505,6 +511,41 @@ static void remove_cdev_from_zone(struct thermal_zone *tz,
 	tz->cdev_indx--;
 }
 
+static struct thermal_zone *get_zone_by_trip_kobj(struct kobject *kobj)
+{
+	struct thermal_zone *pos;
+	struct thermal_zone *tz = NULL;
+
+	if (!kobj)
+		return NULL;
+
+	mutex_lock(&tz_list_lock);
+	for_each_thermal_zone(pos) {
+		if (pos->kobj_thermal_trip == kobj) {
+			tz = pos;
+			break;
+		}
+	}
+	mutex_unlock(&tz_list_lock);
+	return tz;
+}
+
+static struct thermal_sensor *get_sensor_by_kobj_name(const char *name)
+{
+	struct thermal_sensor *pos;
+	struct thermal_sensor *ts = NULL;
+
+	mutex_lock(&ts_list_lock);
+	for_each_thermal_sensor(pos) {
+		if (!strcmp(kobject_name(&pos->device.kobj), name)) {
+			ts = pos;
+			break;
+		}
+	}
+	mutex_unlock(&ts_list_lock);
+	return ts;
+}
+
 /* sys I/F for thermal zone */
 
 #define to_thermal_zone(_dev) \
@@ -859,6 +900,113 @@ policy_show(struct device *dev, struct device_attribute *devattr, char *buf)
 	return sprintf(buf, "%s\n", tz->governor->name);
 }
 
+static ssize_t
+active_show(struct kobject *kobj, struct kobj_attribute *attr, char *buf)
+{
+	int i, indx, ret = 0;
+	struct thermal_sensor *ts;
+	struct thermal_zone *tz;
+
+	ts = get_sensor_by_kobj_name(kobject_name(kobj));
+	if (!ts)
+		return -EINVAL;
+
+	tz = get_zone_by_trip_kobj(kobj->parent);
+	if (!tz)
+		return -EINVAL;
+
+	indx = get_sensor_indx(tz, ts);
+	if (indx < 0)
+		return indx;
+
+	if (tz->trip[indx]->num_active_trips <= 0)
+		return sprintf(buf, "<Not available>\n");
+
+	ret += sprintf(buf, "0x%x", tz->trip[indx]->active_trip_mask);
+	for (i = 0; i < tz->trip[indx]->num_active_trips; i++) {
+		ret += sprintf(buf + ret, " %d",
+			tz->trip[indx]->active_trips[i]);
+	}
+
+	ret += sprintf(buf + ret, "\n");
+	return ret;
+}
+
+static ssize_t
+ptrip_show(struct kobject *kobj, struct kobj_attribute *attr, char *buf)
+{
+	int i, indx, ret = 0;
+	struct thermal_sensor *ts;
+	struct thermal_zone *tz;
+
+	ts = get_sensor_by_kobj_name(kobject_name(kobj));
+	if (!ts)
+		return -EINVAL;
+
+	tz = get_zone_by_trip_kobj(kobj->parent);
+	if (!tz)
+		return -EINVAL;
+
+	indx = get_sensor_indx(tz, ts);
+	if (indx < 0)
+		return indx;
+
+	if (tz->trip[indx]->num_passive_trips <= 0)
+		return sprintf(buf, "<Not available>\n");
+
+	for (i = 0; i < tz->trip[indx]->num_passive_trips; i++) {
+		ret += sprintf(buf + ret, "%d ",
+			tz->trip[indx]->passive_trips[i]);
+	}
+
+	ret += sprintf(buf + ret, "\n");
+	return ret;
+}
+
+static ssize_t
+hot_show(struct kobject *kobj, struct kobj_attribute *attr, char *buf)
+{
+	int indx;
+	struct thermal_sensor *ts;
+	struct thermal_zone *tz;
+
+	ts = get_sensor_by_kobj_name(kobject_name(kobj));
+	if (!ts)
+		return -EINVAL;
+
+	tz = get_zone_by_trip_kobj(kobj->parent);
+	if (!tz)
+		return -EINVAL;
+
+	indx = get_sensor_indx(tz, ts);
+	if (indx < 0)
+		return indx;
+
+	return sprintf(buf, "%d\n", tz->trip[indx]->hot);
+}
+
+static ssize_t
+critical_show(struct kobject *kobj, struct kobj_attribute *attr, char *buf)
+{
+	int indx;
+	struct thermal_sensor *ts;
+	struct thermal_zone *tz;
+
+	ts = get_sensor_by_kobj_name(kobject_name(kobj));
+	if (!ts)
+		return -EINVAL;
+
+	tz = get_zone_by_trip_kobj(kobj->parent);
+	if (!tz)
+		return -EINVAL;
+
+	indx = get_sensor_indx(tz, ts);
+	if (indx < 0)
+		return indx;
+
+	return sprintf(buf, "%d\n", tz->trip[indx]->crit);
+}
+
 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);
@@ -869,7 +1017,26 @@ static DEVICE_ATTR(policy, S_IRUGO | S_IWUSR, policy_show, policy_store);
 static DEVICE_ATTR(sensor_name, 0444, sensor_name_show, NULL);
 static DEVICE_ATTR(temp_input, 0444, sensor_temp_show, NULL);
 
-static DEVICE_ATTR(zone_name, 0444, zone_name_show, NULL);
+/* Thermal zone attributes */
+static DEVICE_ATTR(zone_name, S_IRUGO, zone_name_show, NULL);
+
+/* Thermal trip attributes */
+static struct kobj_attribute active_attr = __ATTR_RO(active);
+static struct kobj_attribute passive_attr = __ATTR_RO(ptrip);
+static struct kobj_attribute hot_attr = __ATTR_RO(hot);
+static struct kobj_attribute crit_attr = __ATTR_RO(critical);
+
+static struct attribute *trip_attrs[] = {
+			&active_attr.attr,
+			&passive_attr.attr,
+			&hot_attr.attr,
+			&crit_attr.attr,
+			NULL,
+			};
+
+static struct attribute_group trip_attr_group = {
+			.attrs = trip_attrs,
+			};
 
 /* sys I/F for cooling device */
 #define to_cooling_device(_dev)	\
@@ -1694,12 +1861,19 @@ struct thermal_zone *create_thermal_zone(const char *name, void *devdata)
 	if (ret)
 		goto exit_unregister;
 
+	tz->kobj_thermal_trip = kobject_create_and_add("thermal_trip",
+					&tz->device.kobj);
+	if (!tz->kobj_thermal_trip)
+		goto exit_name;
+
 	/* Add this zone to the global list of thermal zones */
 	mutex_lock(&tz_list_lock);
 	list_add_tail(&tz->node, &thermal_zone_list);
 	mutex_unlock(&tz_list_lock);
 	return tz;
 
+exit_name:
+	device_remove_file(&tz->device, &dev_attr_zone_name);
 exit_unregister:
 	device_unregister(&tz->device);
 exit_idr:
@@ -1713,6 +1887,7 @@ EXPORT_SYMBOL(create_thermal_zone);
 void remove_thermal_zone(struct thermal_zone *tz)
 {
 	struct thermal_zone *pos, *next;
+	int i;
 	bool found = false;
 
 	if (!tz)
@@ -1733,6 +1908,29 @@ void remove_thermal_zone(struct thermal_zone *tz)
 
 	device_remove_file(&tz->device, &dev_attr_zone_name);
 
+	/* Just for ease of usage */
+	i = tz->sensor_indx;
+
+	while (--i >= 0) {
+		sysfs_remove_link(&tz->device.kobj,
+				kobject_name(&tz->sensors[i]->device.kobj));
+		if (tz->kobj_trip[i])
+			kobject_del(tz->kobj_trip[i]);
+	}
+
+	if (tz->kobj_thermal_trip)
+		kobject_del(tz->kobj_thermal_trip);
+
+	/* Release the cdevs attached to this zone */
+	i = tz->cdev_indx;
+
+	while (--i >= 0) {
+		sysfs_remove_link(&tz->device.kobj,
+				kobject_name(&tz->cdevs[i]->device.kobj));
+	}
+
+	tz->sensor_indx = tz->cdev_indx = 0;
+
 	release_idr(&thermal_zone_idr, &thermal_idr_lock, tz->id);
 	idr_destroy(&tz->idr);
 
@@ -1864,6 +2062,48 @@ int add_cdev_to_zone(struct thermal_zone *tz,
 }
 EXPORT_SYMBOL(add_cdev_to_zone);
 
+int add_sensor_trip_info(struct thermal_zone *tz, const char *sensor_name,
+			struct thermal_trip_point *trip)
+{
+	int indx, ret = -EINVAL;
+	struct thermal_sensor *ts = get_sensor_by_name(sensor_name);
+
+	if (!tz || !ts || !trip)
+		return ret;
+
+	mutex_lock(&tz_list_lock);
+
+	indx = get_sensor_indx(tz, ts);
+	if (indx < 0)
+		goto exit_indx;
+
+	tz->kobj_trip[indx] = kobject_create_and_add(
+					kobject_name(&ts->device.kobj),
+					tz->kobj_thermal_trip);
+	if (!tz->kobj_trip[indx]) {
+		ret = -ENOMEM;
+		goto exit_indx;
+	}
+
+	ret = sysfs_create_group(tz->kobj_trip[indx], &trip_attr_group);
+	if (ret) {
+		dev_err(&tz->device, "sysfs_create_group failed:%d\n", ret);
+		goto exit_kobj;
+	}
+
+	tz->trip[indx] = trip;
+	mutex_unlock(&tz_list_lock);
+	return 0;
+
+exit_kobj:
+	kobject_del(tz->kobj_trip[indx]);
+	tz->kobj_trip[indx] = NULL;
+exit_indx:
+	mutex_unlock(&tz_list_lock);
+	return ret;
+}
+EXPORT_SYMBOL(add_sensor_trip_info);
+
 /**
  * thermal_sensor_register - register a new thermal sensor
  * @name:	name of the thermal sensor
diff --git a/include/linux/thermal.h b/include/linux/thermal.h
index 2913910..7b2fe35 100644
--- a/include/linux/thermal.h
+++ b/include/linux/thermal.h
@@ -159,6 +159,30 @@ struct thermal_attr {
 	char name[THERMAL_NAME_LENGTH];
 };
 
+/*
+ * This structure defines the trip points for a sensor.
+ * The actual values for these trip points come from
+ * platform characterization. The thermal governors
+ * (either kernel or user space) may take appropriate
+ * actions when the sensors reach these trip points.
+ * See Documentation/thermal/sysfs-api2.txt for more details.
+ *
+ * As of now, For a particular sensor, we support:
+ * a) 1 hot trip point
+ * b) 1 critical trip point
+ * c) 'n' passive trip points
+ * d) 'm' active trip points
+ */
+struct thermal_trip_point {
+	int hot;
+	int crit;
+	int num_passive_trips;
+	int *passive_trips;
+	int num_active_trips;
+	int *active_trips;
+	int active_trip_mask;
+};
+
 struct thermal_sensor {
 	char name[THERMAL_NAME_LENGTH];
 	int id;
@@ -215,6 +239,11 @@ struct thermal_zone {
 	/* cdev level information */
 	int cdev_indx; /* index into 'cdevs' array */
 	struct thermal_cooling_device *cdevs[MAX_CDEVS_PER_ZONE];
+
+	/* Thermal trip information */
+	struct thermal_trip_point *trip[MAX_SENSORS_PER_ZONE];
+	struct kobject *kobj_trip[MAX_SENSORS_PER_ZONE];
+	struct kobject *kobj_thermal_trip;
 };
 
 /* Structure that holds thermal governor information */
@@ -298,6 +327,9 @@ int add_sensor_to_zone_by_name(struct thermal_zone *, const char *);
 int add_cdev_to_zone(struct thermal_zone *, struct thermal_cooling_device *);
 int add_cdev_to_zone_by_name(struct thermal_zone *, const char *);
 
+int add_sensor_trip_info(struct thermal_zone *, const char *,
+			struct thermal_trip_point *);
+
 #ifdef CONFIG_NET
 extern int thermal_generate_netlink_event(u32 orig, enum events event);
 #else
-- 
1.7.9.5


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

* [RFC PATCH 5/7] Thermal: Add 'thermal_map' sysfs node
  2012-11-17 10:45 [RFC PATCH 0/7] Support for Multiple sensors per zone Durgadoss R
                   ` (3 preceding siblings ...)
  2012-11-17 10:45 ` [RFC PATCH 4/7] Thermal: Add Thermal_trip sysfs node Durgadoss R
@ 2012-11-17 10:45 ` Durgadoss R
  2012-11-17 10:45 ` [RFC PATCH 6/7] Thermal: Add Documentation to new APIs Durgadoss R
                   ` (3 subsequent siblings)
  8 siblings, 0 replies; 27+ messages in thread
From: Durgadoss R @ 2012-11-17 10:45 UTC (permalink / raw)
  To: rui.zhang, linux-pm
  Cc: wni, eduardo.valentin, amit.kachhap, hongbo.zhang, sachin.kamat,
	Durgadoss R

This patch creates a thermal map sysfs node under
/sys/class/thermal/thermal_zoneX/. This contains
entries named map0, map1 .. mapN. Each map has the
following space separated values:
trip_type sensor_name cdev_name trip_mask weights

Signed-off-by: Durgadoss R <durgadoss.r@intel.com>
---
 drivers/thermal/thermal_sys.c |  158 +++++++++++++++++++++++++++++++++++++++--
 include/linux/thermal.h       |   25 +++++++
 2 files changed, 178 insertions(+), 5 deletions(-)

diff --git a/drivers/thermal/thermal_sys.c b/drivers/thermal/thermal_sys.c
index 011588a..af52a16 100644
--- a/drivers/thermal/thermal_sys.c
+++ b/drivers/thermal/thermal_sys.c
@@ -530,6 +530,25 @@ static struct thermal_zone *get_zone_by_trip_kobj(struct kobject *kobj)
 	return tz;
 }
 
+static struct thermal_zone *get_zone_by_map_kobj(struct kobject *kobj)
+{
+	struct thermal_zone *pos;
+	struct thermal_zone *tz = NULL;
+
+	if (!kobj)
+		return NULL;
+
+	mutex_lock(&tz_list_lock);
+	for_each_thermal_zone(pos) {
+		if (pos->kobj_thermal_map == kobj) {
+			tz = pos;
+			break;
+		}
+	}
+	mutex_unlock(&tz_list_lock);
+	return tz;
+}
+
 static struct thermal_sensor *get_sensor_by_kobj_name(const char *name)
 {
 	struct thermal_sensor *pos;
@@ -546,6 +565,41 @@ static struct thermal_sensor *get_sensor_by_kobj_name(const char *name)
 	return ts;
 }
 
+static void __clean_map_entry(struct thermal_zone *tz, int i)
+{
+	tz->map[i] = NULL;
+	sysfs_remove_file(tz->kobj_thermal_map, &tz->map_attr[i]->attr.attr);
+	/* Free map attributes */
+	kfree(tz->map_attr[i]);
+	tz->map_attr[i] = NULL;
+}
+
+static void remove_sensor_map_entry(struct thermal_zone *tz,
+				struct thermal_sensor *ts)
+{
+	int i;
+
+	for (i = 0; i < MAX_MAPS_PER_ZONE; i++) {
+		if (tz->map[i] && !strnicmp(ts->name, tz->map[i]->sensor_name,
+						THERMAL_NAME_LENGTH)) {
+			__clean_map_entry(tz, i);
+		}
+	}
+}
+
+static void remove_cdev_map_entry(struct thermal_zone *tz,
+				struct thermal_cooling_device *cdev)
+{
+	int i;
+
+	for (i = 0; i < MAX_MAPS_PER_ZONE; i++) {
+		if (tz->map[i] && !strnicmp(cdev->type, tz->map[i]->cdev_name,
+						THERMAL_NAME_LENGTH)) {
+			__clean_map_entry(tz, i);
+		}
+	}
+}
+
 /* sys I/F for thermal zone */
 
 #define to_thermal_zone(_dev) \
@@ -901,6 +955,42 @@ policy_show(struct device *dev, struct device_attribute *devattr, char *buf)
 }
 
 static ssize_t
+map_show(struct kobject *kobj, struct kobj_attribute *attr, char *buf)
+{
+	int i, indx, ret = 0;
+	struct thermal_zone *tz;
+	struct thermal_map *map;
+	char *trip;
+
+	tz = get_zone_by_map_kobj(kobj);
+	if (!tz)
+		return -EINVAL;
+
+	sscanf(attr->attr.name, "map%d", &indx);
+
+	if (indx < 0 || indx >= MAX_MAPS_PER_ZONE)
+		return -EINVAL;
+
+	if (!tz->map[indx])
+		return sprintf(buf, "<Unavailable>\n");
+
+	map = tz->map[indx];
+
+	trip = (map->trip_type == THERMAL_TRIP_ACTIVE) ?
+					"active" : "passive";
+	ret += sprintf(buf, "%s", trip);
+	ret += sprintf(buf + ret, " %s", map->sensor_name);
+	ret += sprintf(buf + ret, " %s", map->cdev_name);
+	ret += sprintf(buf + ret, " 0x%x", map->trip_mask);
+
+	for (i = 0; i < map->num_weights; i++)
+		ret += sprintf(buf + ret, " %d", map->weights[i]);
+
+	ret += sprintf(buf + ret, "\n");
+	return ret;
+}
+
+static ssize_t
 active_show(struct kobject *kobj, struct kobj_attribute *attr, char *buf)
 {
 	int i, indx, ret = 0;
@@ -1671,8 +1761,10 @@ void thermal_cooling_device_unregister(struct thermal_cooling_device *cdev)
 
 	mutex_lock(&tz_list_lock);
 
-	for_each_thermal_zone(tmp_tz)
+	for_each_thermal_zone(tmp_tz) {
 		remove_cdev_from_zone(tmp_tz, cdev);
+		remove_cdev_map_entry(tmp_tz, cdev);
+	}
 
 	mutex_unlock(&tz_list_lock);
 
@@ -1866,12 +1958,19 @@ struct thermal_zone *create_thermal_zone(const char *name, void *devdata)
 	if (!tz->kobj_thermal_trip)
 		goto exit_name;
 
+	tz->kobj_thermal_map = kobject_create_and_add("thermal_map",
+					&tz->device.kobj);
+	if (!tz->kobj_thermal_map)
+		goto exit_trip;
+
 	/* Add this zone to the global list of thermal zones */
 	mutex_lock(&tz_list_lock);
 	list_add_tail(&tz->node, &thermal_zone_list);
 	mutex_unlock(&tz_list_lock);
 	return tz;
 
+exit_trip:
+	kobject_del(tz->kobj_thermal_trip);
 exit_name:
 	device_remove_file(&tz->device, &dev_attr_zone_name);
 exit_unregister:
@@ -1918,9 +2017,6 @@ void remove_thermal_zone(struct thermal_zone *tz)
 			kobject_del(tz->kobj_trip[i]);
 	}
 
-	if (tz->kobj_thermal_trip)
-		kobject_del(tz->kobj_thermal_trip);
-
 	/* Release the cdevs attached to this zone */
 	i = tz->cdev_indx;
 
@@ -1931,6 +2027,9 @@ void remove_thermal_zone(struct thermal_zone *tz)
 
 	tz->sensor_indx = tz->cdev_indx = 0;
 
+	kobject_del(tz->kobj_thermal_trip);
+	kobject_del(tz->kobj_thermal_map);
+
 	release_idr(&thermal_zone_idr, &thermal_idr_lock, tz->id);
 	idr_destroy(&tz->idr);
 
@@ -1976,6 +2075,53 @@ struct thermal_sensor *get_sensor_by_name(const char *name)
 }
 EXPORT_SYMBOL(get_sensor_by_name);
 
+int add_map_entry(struct thermal_zone *tz, struct thermal_map *map)
+{
+	int ret, indx;
+
+	if (!tz || !map)
+		return -EINVAL;
+
+	mutex_lock(&tz_list_lock);
+
+	for (indx = 0; indx < MAX_MAPS_PER_ZONE; indx++) {
+		if (tz->map[indx] == NULL)
+			break;
+	}
+
+	if (indx >= MAX_MAPS_PER_ZONE) {
+		ret = -EINVAL;
+		goto exit;
+	}
+
+	tz->map_attr[indx] = kzalloc(sizeof(struct thermal_map_attr),
+					GFP_KERNEL);
+	if (!tz->map_attr[indx]) {
+		ret = -ENOMEM;
+		goto exit;
+	}
+
+	sprintf(tz->map_attr[indx]->name, "map%d", indx);
+
+	tz->map_attr[indx]->attr.attr.name = tz->map_attr[indx]->name;
+	tz->map_attr[indx]->attr.attr.mode = S_IRUGO;
+	tz->map_attr[indx]->attr.show = map_show;
+
+	sysfs_attr_init(&tz->map_attr[indx]->attr.attr);
+	ret = sysfs_create_file(tz->kobj_thermal_map,
+				&tz->map_attr[indx]->attr.attr);
+	if (ret) {
+		kfree(tz->map_attr[indx]);
+		goto exit;
+	}
+
+	tz->map[indx] = map;
+exit:
+	mutex_unlock(&tz_list_lock);
+	return ret;
+}
+EXPORT_SYMBOL(add_map_entry);
+
 int add_sensor_to_zone_by_name(struct thermal_zone *tz, const char *name)
 {
 	int ret;
@@ -2193,8 +2339,10 @@ void thermal_sensor_unregister(struct thermal_sensor *ts)
 
 	mutex_lock(&tz_list_lock);
 
-	for_each_thermal_zone(tz)
+	for_each_thermal_zone(tz) {
 		remove_sensor_from_zone(tz, ts);
+		remove_sensor_map_entry(tz, ts);
+	}
 
 	mutex_unlock(&tz_list_lock);
 
diff --git a/include/linux/thermal.h b/include/linux/thermal.h
index 7b2fe35..84763b5 100644
--- a/include/linux/thermal.h
+++ b/include/linux/thermal.h
@@ -56,6 +56,9 @@
 
 #define MAX_CDEVS_PER_ZONE		5
 
+/* If we map each sensor with every possible cdev for a zone */
+#define MAX_MAPS_PER_ZONE	(MAX_SENSORS_PER_ZONE * MAX_CDEVS_PER_ZONE)
+
 struct thermal_sensor;
 struct thermal_zone_device;
 struct thermal_cooling_device;
@@ -159,6 +162,21 @@ struct thermal_attr {
 	char name[THERMAL_NAME_LENGTH];
 };
 
+struct thermal_map_attr {
+	struct kobj_attribute attr;
+	char name[THERMAL_NAME_LENGTH];
+};
+
+struct thermal_map {
+	enum thermal_trip_type trip_type;
+	char cdev_name[THERMAL_NAME_LENGTH];
+	char sensor_name[THERMAL_NAME_LENGTH];
+
+	int trip_mask;
+	int num_weights;
+	int *weights;
+};
+
 /*
  * This structure defines the trip points for a sensor.
  * The actual values for these trip points come from
@@ -244,6 +262,11 @@ struct thermal_zone {
 	struct thermal_trip_point *trip[MAX_SENSORS_PER_ZONE];
 	struct kobject *kobj_trip[MAX_SENSORS_PER_ZONE];
 	struct kobject *kobj_thermal_trip;
+
+	/* Thermal map information */
+	struct thermal_map *map[MAX_MAPS_PER_ZONE];
+	struct thermal_map_attr *map_attr[MAX_MAPS_PER_ZONE];
+	struct kobject *kobj_thermal_map;
 };
 
 /* Structure that holds thermal governor information */
@@ -330,6 +353,8 @@ int add_cdev_to_zone_by_name(struct thermal_zone *, const char *);
 int add_sensor_trip_info(struct thermal_zone *, const char *,
 			struct thermal_trip_point *);
 
+int add_map_entry(struct thermal_zone *, struct thermal_map *);
+
 #ifdef CONFIG_NET
 extern int thermal_generate_netlink_event(u32 orig, enum events event);
 #else
-- 
1.7.9.5


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

* [RFC PATCH 6/7] Thermal: Add Documentation to new APIs
  2012-11-17 10:45 [RFC PATCH 0/7] Support for Multiple sensors per zone Durgadoss R
                   ` (4 preceding siblings ...)
  2012-11-17 10:45 ` [RFC PATCH 5/7] Thermal: Add 'thermal_map' " Durgadoss R
@ 2012-11-17 10:45 ` Durgadoss R
  2012-12-03  7:19   ` Hongbo Zhang
  2012-11-17 10:45 ` [RFC PATCH 7/7] Thermal: Dummy driver used for testing Durgadoss R
                   ` (2 subsequent siblings)
  8 siblings, 1 reply; 27+ messages in thread
From: Durgadoss R @ 2012-11-17 10:45 UTC (permalink / raw)
  To: rui.zhang, linux-pm
  Cc: wni, eduardo.valentin, amit.kachhap, hongbo.zhang, sachin.kamat,
	Durgadoss R

This patch adds Documentation for the new APIs
introduced in this patch set. The documentation
also has a model sysfs structure for reference.

Signed-off-by: Durgadoss R <durgadoss.r@intel.com>
---
 Documentation/thermal/sysfs-api2.txt |  213 ++++++++++++++++++++++++++++++++++
 1 file changed, 213 insertions(+)
 create mode 100644 Documentation/thermal/sysfs-api2.txt

diff --git a/Documentation/thermal/sysfs-api2.txt b/Documentation/thermal/sysfs-api2.txt
new file mode 100644
index 0000000..be67125
--- /dev/null
+++ b/Documentation/thermal/sysfs-api2.txt
@@ -0,0 +1,213 @@
+Thermal Framework
+-----------------
+
+Written by Durgadoss R <durgadoss.r@intel.com>
+Copyright (c) 2012 Intel Corporation
+
+Created on: 4 November 2012
+
+0. Introduction
+---------------
+The Linux thermal framework provides a set of interfaces for thermal
+sensors and thermal cooling devices (fan, processor...) to register
+with the thermal management solution and to be a part of it.
+
+This document focuses on how to enable new thermal sensors and cooling
+devices to participate in thermal management. This solution is intended
+to be 'light-weight' and platform/architecture independent. Any thermal
+sensor/cooling device should be able to use the infrastructure easily.
+
+The goal of thermal framework is to expose the thermal sensor/zone and
+cooling device attributes in a consistent way. This will help the
+thermal governors to make use of the information to manage platform
+thermals efficiently.
+
+1. Terminology
+--------------
+This section describes the terminology used in the rest of this
+document as well as the thermal framework code.
+
+thermal_sensor: Hardware that can report temperature of a particular
+		spot in the platform, where it is placed. The temperature
+		reported by the sensor is the 'real' temperature reported
+		by the hardware.
+thermal_zone:	A virtual area on the device, that gets heated up. It may
+		have one or more thermal sensors attached to it.
+cooling_device:	Any component that can help in reducing the temperature of
+		a 'hot spot' either by reducing its performance (passive
+		cooling) or by other means(Active cooling E.g. Fan)
+
+trip_points:	Various temperature levels for each sensor. As of now, we
+		have four levels namely active, passive, hot and critical.
+		Hot and critical trip point support only one value whereas
+		active and passive can have any number of values. These
+		temperature values can come from platform data, and are
+		exposed through sysfs in a consistent manner. Stand-alone
+		thermal sensor drivers are not expected to know these values.
+		These values are RO.
+thresholds:	These are programmable temperature limits, on reaching which
+		the thermal sensor generates an interrupt. The framework is
+		notified about this interrupt to take appropriate action.
+		There can be as many number of thresholds as that of the
+		hardware supports. These values are RW.
+
+thermal_map:	This provides the mapping (aka binding) information between
+		various sensors and cooling devices in a particular zone.
+		Typically, this also comes from platform data; Stand-alone
+		sensor drivers or cooling device drivers are not expected
+		to know these mapping information.
+
+2. Thermal framework APIs
+-------------------------
+2.1: For Thermal Sensors
+2.1.1 thermal_sensor_register:
+	This function creates a new sensor directory under /sys/class/thermal/
+	as sensor[0-*]. This API is expected to be called by thermal sensor
+	drivers. These drivers may or may not be in thermal subsystem. This
+	function returns a thermal_sensor structure on success and appropriate
+	error on failure.
+
+	name: Name of the sensor
+	devdata: Device private data
+	ops: Thermal sensor callbacks
+		.get_temp: obtain the current temperature of the sensor
+		.get_trend: obtain the trend of the sensor
+		.get_threshold: get a particular threshold temperature
+		.set_threshold: set a particular threshold temperature
+
+2.1.2 thermal_sensor_unregister:
+	This function deletes the sensor directory under /sys/class/thermal/
+	for the given sensor. Thermal sensor drivers may call this API
+	during the driver's 'exit' routine.
+
+	ts: Thermal sensor that has to be unregistered
+
+2.1.3 enable_sensor_thresholds:
+	This function creates 'threshold[0-*]' attributes under a particular
+	sensorX directory. These values are RW. This function is called by
+	the sensr driver only if the sensor supports interrupt mechanism.
+
+	ts: Thermal sensor for which thresholds have to be enabled
+	num_thresholds: Number of thresholds supported by the sensor
+
+2.2: For Cooling Devices
+2.2.1 thermal_cooling_device_register:
+	This function adds a new thermal cooling device (fan/processor/...)
+	to /sys/class/thermal/ folder as cooling_device[0-*]. This function
+	is expected to be called by cooling device drivers that may be
+	present in other subsystems also.
+
+	name: the cooling device name
+	devdata: device private data
+	ops: thermal cooling devices callbacks
+	.get_max_state: get the Maximum throttle state of the cooling device
+	.get_cur_state: get the Current throttle state of the cooling device
+	.set_cur_state: set the Current throttle state of the cooling device
+
+2.2.2 thermal_cooling_device_unregister:
+	This function deletes the given cdev entry form /sys/class/thermal;
+	and also cleans all the symlinks referred from various zones.
+
+	cdev: Cooling device to be unregistered
+
+2.3: For Thermal Zones
+2.3.1 create_thermal_zone:
+	This function adds a new 'zone' under /sys/class/thermal/
+	directory as zone[0-*]. This zone has at least one thermal
+	sensor and at most MAX_SENSORS_PER_ZONE number of sensors
+	attached to it. Similarly, this zone has at least one cdev
+	and at most MAX_CDEVS_PER_ZONE number of cdevs attached to it.
+	Both the MAX_*_PER_ZONE values are configurable, through
+	Kconfig option(during 'menuconfig').
+
+	name: Name of the thermal zone
+	devdata: Device private data
+
+2.3.2 add_sensor_to_zone
+	This function adds a 'sensorX' entry under /sys/class/thermal/
+	zoneY/ directory. This 'sensorX' is a symlink to the actual
+	sensor entry under /sys/class/thermal/. Correspondingly, the
+	method remove_sensor_from_zone deletes the symlink.
+
+	tz: thermal zone structure
+	ts: thermal sensor structure
+
+2.3.3 add_cdev_to_zone
+	This function adds a 'cdevX' entry under /sys/class/thermal/
+	zoneY/ directory. This 'cdevX' is a symlink to the actual
+	cdev entry under /sys/class/thermal/. Correspondingly, the
+	method remove_cdev_from_zone deletes the symlink.
+
+	tz: thermal zone structure
+	cdev: thermal cooling device structure
+
+2.4 For Thermal Trip
+2.4.1 add_sensor_trip_info
+	This function adds trip point information for the given sensor,
+	(under a given zone) under /sys/class/thermal/zoneX/thermal_trip/
+	This API creates 4 sysfs attributes namely active, passive, hot,
+	and critical. Each of these hold one or more trip point temperature
+	values, as provided from platform data.
+
+	tz: thermal zone structure
+	ts: thermal sensor to which the trip points are attached
+	trip: trip point structure. Usually obtained from platform data
+
+2.5 For Thermal Map
+2.5.1 add_map_entry
+	This function adds a 'map[0-*]' sysfs attribute under
+	/sys/class/thermal/zoneX/thermal_map/. Each map holds a space
+	separated list of values, that specify the binding relationship
+	between a sensor and a cdev in the given zone. The map structure
+	is typically obtained as platform data. For example, through
+	ACPI tables, SFI tables, Device tree etc.
+
+	tz: thermal zone to which a 'map' is being added
+	map: thermal_map structure
+
+3. Sysfs attributes structure
+-----------------------------
+Thermal sysfs attributes will be represented under /sys/class/thermal.
+
+3.1: For Thermal Sensors
+	/sys/class/thermal/thermal_zone[0-*]:
+		|---type:		Name of the thermal sensor
+		|---temp_input:		Current temperature in mC
+		|---threshold[0-*]:	Threshold temperature
+
+3.2: For Thermal Cooling Devices
+	/sys/class/thermal/cooling_device[0-*]:
+		|---type:		Type of the cooling device
+		|---max_state:		Maximum throttle state of the cdev
+		|---cur_state:		Current throttle state of the cdev
+
+3.3: For Thermal Zones
+	/sys/class/thermal/zone[0-*]:
+		|---name:		Name of the thermal
+		|---sensorX:		Symlink to ../sensorX
+		|---cdevY:		Symlink to ../cdevY
+		|---thermal_trip:	trip point values for sensors
+		|---thermal_map:	mapping info between sensors and cdevs
+
+3.4: For Thermal Trip
+	This attribute represents the trip point values for all sensors
+	present in the thermal zone. All values are in mC.
+	/sys/class/thermal/zoneX/thermal_trip/sensorY:
+		|---hot:		hot trip point value
+		|---critical:		critical trip point value
+		|---passive:		list of passive trip point values
+		|---active:		list of active trip point values
+
+3.5: For Thermal Map
+	Each attribute represents the mapping/binding information between
+	a sensor and a cdev, together with a trip type.
+	/sys/class/thermal/zoneX/thermal_map/:
+		|---mapX:		mapping information
+	A typical map entry is like below:
+
+	trip_type  sensor  cdev  trip_mask  weight(s)
+	passive    cpu     proc  0x03       50 30
+	active     cpu     fan0  0x03       50 70
+
+	The trip mask is a bit string; if 'n' th bit is set, then for
+	trip point 'n' this cdev is throttled with the given weight[n].
-- 
1.7.9.5


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

* [RFC PATCH 7/7] Thermal: Dummy driver used for testing
  2012-11-17 10:45 [RFC PATCH 0/7] Support for Multiple sensors per zone Durgadoss R
                   ` (5 preceding siblings ...)
  2012-11-17 10:45 ` [RFC PATCH 6/7] Thermal: Add Documentation to new APIs Durgadoss R
@ 2012-11-17 10:45 ` Durgadoss R
  2012-12-03  9:01 ` [RFC PATCH 0/7] Support for Multiple sensors per zone Hongbo Zhang
  2013-01-02 15:48 ` Eduardo Valentin
  8 siblings, 0 replies; 27+ messages in thread
From: Durgadoss R @ 2012-11-17 10:45 UTC (permalink / raw)
  To: rui.zhang, linux-pm
  Cc: wni, eduardo.valentin, amit.kachhap, hongbo.zhang, sachin.kamat,
	Durgadoss R

This patch has a dummy driver that can be used for
testing purposes. This patch is not for merge.

Signed-off-by: Durgadoss R <durgadoss.r@intel.com>
---
 drivers/thermal/Kconfig        |    5 +
 drivers/thermal/Makefile       |    3 +
 drivers/thermal/thermal_test.c |  321 ++++++++++++++++++++++++++++++++++++++++
 3 files changed, 329 insertions(+)
 create mode 100644 drivers/thermal/thermal_test.c

diff --git a/drivers/thermal/Kconfig b/drivers/thermal/Kconfig
index d96da07..9a083ae 100644
--- a/drivers/thermal/Kconfig
+++ b/drivers/thermal/Kconfig
@@ -122,4 +122,9 @@ config DB8500_CPUFREQ_COOLING
 	  bound cpufreq cooling device turns active to set CPU frequency low to
 	  cool down the CPU.
 
+config THERMAL_TEST
+	tristate "test driver"
+	help
+	  Enable this to test the thermal framework.
+
 endif
diff --git a/drivers/thermal/Makefile b/drivers/thermal/Makefile
index d8da683..02c3edb 100644
--- a/drivers/thermal/Makefile
+++ b/drivers/thermal/Makefile
@@ -18,3 +18,6 @@ obj-$(CONFIG_RCAR_THERMAL)	+= rcar_thermal.o
 obj-$(CONFIG_EXYNOS_THERMAL)	+= exynos_thermal.o
 obj-$(CONFIG_DB8500_THERMAL)	+= db8500_thermal.o
 obj-$(CONFIG_DB8500_CPUFREQ_COOLING)	+= db8500_cpufreq_cooling.o
+
+# dummy driver for testing
+obj-$(CONFIG_THERMAL_TEST)	+= thermal_test.o
diff --git a/drivers/thermal/thermal_test.c b/drivers/thermal/thermal_test.c
new file mode 100644
index 0000000..c1940b9
--- /dev/null
+++ b/drivers/thermal/thermal_test.c
@@ -0,0 +1,321 @@
+/*
+ * thermal_test.c - This driver can be used to test Thermal
+ *			   Framework changes. Not specific to any
+ *			   platform. Fills the log buffer generously ;)
+ *
+ * Copyright (C) 2012 Intel Corporation
+ *
+ * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+ *
+ * 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.
+ *
+ * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+ * Author: Durgadoss R <durgadoss.r@intel.com>
+ */
+
+#define pr_fmt(fmt)  "thermal_test: " fmt
+
+#include <linux/module.h>
+#include <linux/init.h>
+#include <linux/err.h>
+#include <linux/param.h>
+#include <linux/device.h>
+#include <linux/slab.h>
+#include <linux/pm.h>
+#include <linux/platform_device.h>
+#include <linux/thermal.h>
+
+#define MAX_THERMAL_ZONES	2
+#define MAX_THERMAL_SENSORS	2
+#define MAX_COOLING_DEVS	4
+#define NUM_THRESHOLDS		3
+
+static struct ts_data {
+	int curr_temp;
+	int flag;
+} ts_data;
+
+int active_trips[10] = {100, 90, 80, 70, 60, 50, 40, 30, 20, 10};
+int passive_trips[5] = {100, 90, 60, 50, 40};
+
+static struct platform_device *pdev;
+static unsigned long cur_cdev_state = 2;
+static struct thermal_sensor *ts, *ts1;
+static struct thermal_zone *tz;
+static struct thermal_cooling_device *cdev;
+
+static long thermal_thresholds[NUM_THRESHOLDS] = {30000, 40000, 50000};
+
+static struct thermal_trip_point trip = {
+	.hot = 90,
+	.crit = 100,
+	.num_passive_trips = 5,
+	.passive_trips = passive_trips,
+	.num_active_trips = 10,
+	.active_trips = active_trips,
+	.active_trip_mask = 0xCFF,
+};
+
+static struct thermal_trip_point trip1 = {
+	.hot = 95,
+	.crit = 125,
+	.num_passive_trips = 0,
+	.passive_trips = passive_trips,
+	.num_active_trips = 6,
+	.active_trips = active_trips,
+	.active_trip_mask = 0xFF,
+};
+
+static int read_cur_state(struct thermal_cooling_device *cdev,
+			unsigned long *state)
+{
+	*state = cur_cdev_state;
+	return 0;
+}
+
+static int write_cur_state(struct thermal_cooling_device *cdev,
+			unsigned long state)
+{
+	cur_cdev_state = state;
+	return 0;
+}
+
+static int read_max_state(struct thermal_cooling_device *cdev,
+			unsigned long *state)
+{
+	*state = 5;
+	return 0;
+}
+
+static int read_curr_temp(struct thermal_sensor *ts, long *temp)
+{
+	*temp = ts_data.curr_temp;
+	return 0;
+}
+
+static ssize_t
+flag_show(struct device *dev, struct device_attribute *devattr, char *buf)
+{
+	return sprintf(buf, "%d\n", ts_data.flag);
+}
+
+static ssize_t
+flag_store(struct device *dev, struct device_attribute *attr,
+		    const char *buf, size_t count)
+{
+	long flag;
+
+	if (kstrtol(buf, 10, &flag))
+		return -EINVAL;
+
+	ts_data.flag = flag;
+
+	if (flag == 0) {
+		thermal_sensor_unregister(ts);
+		ts = NULL;
+		pr_err("thermal_sensor_unregister (ts) done\n");
+	} else if (flag == 1) {
+		thermal_sensor_unregister(ts1);
+		ts1 = NULL;
+		pr_err("thermal_sensor_unregister (ts1) done\n");
+	} else if (flag == 2) {
+		thermal_cooling_device_unregister(cdev);
+		cdev = NULL;
+		pr_err("cdev unregister (cdev) done\n");
+	} else if (flag == 3) {
+		if (tz)
+			remove_thermal_zone(tz);
+		tz = NULL;
+		pr_err("removed thermal zone\n");
+	}
+
+	return count;
+}
+
+static ssize_t
+temp_show(struct device *dev, struct device_attribute *devattr, char *buf)
+{
+	return sprintf(buf, "%d\n", ts_data.curr_temp);
+}
+
+static int read_threshold(struct thermal_sensor *ts, int indx, long *val)
+{
+	if (indx < 0 || indx >= NUM_THRESHOLDS)
+		return -EINVAL;
+
+	*val = thermal_thresholds[indx];
+	return 0;
+}
+
+static int write_threshold(struct thermal_sensor *ts, int indx, long val)
+{
+	if (indx < 0 || indx >= NUM_THRESHOLDS)
+		return -EINVAL;
+
+	thermal_thresholds[indx] = val;
+	return 0;
+}
+
+static ssize_t
+temp_store(struct device *dev, struct device_attribute *attr,
+		    const char *buf, size_t count)
+{
+	long temp;
+
+	if (kstrtol(buf, 10, &temp))
+		return -EINVAL;
+
+	ts_data.curr_temp = temp;
+	return count;
+}
+
+static struct thermal_sensor_ops ts_ops = {
+	.get_temp = read_curr_temp,
+	.get_threshold = read_threshold,
+	.set_threshold = write_threshold,
+};
+
+static struct thermal_sensor_ops ts1_ops = {
+	.get_temp = read_curr_temp,
+	.get_threshold = read_threshold,
+	.set_threshold = write_threshold,
+};
+
+static struct thermal_cooling_device_ops cdev_ops = {
+	.get_cur_state = read_cur_state,
+	.set_cur_state = write_cur_state,
+	.get_max_state = read_max_state,
+};
+
+static DEVICE_ATTR(test_temp, S_IRUGO | S_IWUSR, temp_show, temp_store);
+static DEVICE_ATTR(sensor_enable, S_IRUGO | S_IWUSR, flag_show, flag_store);
+
+static int thermal_test_probe(struct platform_device *pdev)
+{
+	int ret;
+
+	ts_data.curr_temp = 30000;
+	ts_data.flag = 1;
+
+	ts = thermal_sensor_register("ts", &ts_ops, &ts_data);
+	if (!ts) {
+		pr_err("thermal_sensor_register failed:\n");
+		return -EINVAL;
+	}
+
+	ts1 = thermal_sensor_register("ts1", &ts1_ops, NULL);
+
+	cdev = thermal_cooling_device_register("cdev", NULL, &cdev_ops);
+	if (!cdev) {
+		pr_err("cdev_register failed:\n");
+		return -EINVAL;
+	}
+
+	ret = enable_sensor_thresholds(ts, NUM_THRESHOLDS);
+	if (ret) {
+		pr_err("enable_sensor_thresholds failed:%d\n", ret);
+		return ret;
+	}
+
+	device_create_file(&pdev->dev, &dev_attr_test_temp);
+	device_create_file(&pdev->dev, &dev_attr_sensor_enable);
+
+	/* Create a zone */
+	tz = create_thermal_zone("myZone", NULL);
+	if (!tz) {
+		pr_err("create_thermal_zone failed:\n");
+		return ret;
+	}
+
+	pr_err("Zone created successfully..\n");
+
+	ret = add_sensor_to_zone(tz, ts);
+	if (ret) {
+		pr_err("add_sensor_to_zone failed:%d\n", ret);
+		return ret;
+	}
+
+	ret = add_sensor_to_zone(tz, ts1);
+	pr_err("add_sensor (ts1) ret_val: %d\n", ret);
+
+	ret = add_cdev_to_zone(tz, cdev);
+	pr_err("add_cdev_to_zone (cdev) ret_val: %d\n", ret);
+
+	ret = add_sensor_trip_info(tz, "ts", &trip);
+	ret = add_sensor_trip_info(tz, "ts1", &trip1);
+	pr_err("add_sensor_trip_info (ts) ret_val: %d\n", ret);
+	return 0;
+}
+
+static int thermal_test_remove(struct platform_device *pdev)
+{
+	device_remove_file(&pdev->dev, &dev_attr_test_temp);
+	device_remove_file(&pdev->dev, &dev_attr_sensor_enable);
+
+	return 0;
+}
+
+/*********************************************************************
+ *		Driver initialization and finalization
+ *********************************************************************/
+
+#define DRIVER_NAME "thermal_test"
+
+static const struct platform_device_id therm_id_table[] = {
+	{ DRIVER_NAME, 1 },
+};
+
+static struct platform_driver thermal_test_driver = {
+	.driver = {
+		.name = DRIVER_NAME,
+		.owner = THIS_MODULE,
+	},
+	.probe = thermal_test_probe,
+	.remove = __devexit_p(thermal_test_remove),
+	.id_table = therm_id_table,
+};
+
+static int __init thermal_test_init(void)
+{
+	int ret;
+
+	ret = platform_driver_register(&thermal_test_driver);
+	if (ret) {
+		pr_err("platform driver register failed:%d\n", ret);
+		return ret;
+	}
+
+	pdev = platform_device_register_simple(DRIVER_NAME, -1, NULL, 0);
+	if (IS_ERR(pdev)) {
+		ret = PTR_ERR(pdev);
+		pr_err("platform device register failed:%d\n", ret);
+		platform_driver_unregister(&thermal_test_driver);
+	}
+
+	return ret;
+}
+
+static void __exit thermal_test_exit(void)
+{
+	pr_err("in thermal_test_exit\n");
+	platform_device_unregister(pdev);
+	platform_driver_unregister(&thermal_test_driver);
+}
+
+module_init(thermal_test_init);
+module_exit(thermal_test_exit);
+
+MODULE_AUTHOR("Durgadoss R <durgadoss.r@intel.com>");
+MODULE_DESCRIPTION("A dummy driver to test Thermal Framework");
+MODULE_LICENSE("GPL");
-- 
1.7.9.5


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

* Re: [RFC PATCH 6/7] Thermal: Add Documentation to new APIs
  2012-11-17 10:45 ` [RFC PATCH 6/7] Thermal: Add Documentation to new APIs Durgadoss R
@ 2012-12-03  7:19   ` Hongbo Zhang
  2012-12-03  7:44     ` R, Durgadoss
  0 siblings, 1 reply; 27+ messages in thread
From: Hongbo Zhang @ 2012-12-03  7:19 UTC (permalink / raw)
  To: Durgadoss R
  Cc: rui.zhang, linux-pm, wni, eduardo.valentin, amit.kachhap, sachin.kamat

On 17 November 2012 18:45, Durgadoss R <durgadoss.r@intel.com> wrote:
> This patch adds Documentation for the new APIs
> introduced in this patch set. The documentation
> also has a model sysfs structure for reference.
>
> Signed-off-by: Durgadoss R <durgadoss.r@intel.com>
> ---
>  Documentation/thermal/sysfs-api2.txt |  213 ++++++++++++++++++++++++++++++++++
>  1 file changed, 213 insertions(+)
>  create mode 100644 Documentation/thermal/sysfs-api2.txt
>
> diff --git a/Documentation/thermal/sysfs-api2.txt b/Documentation/thermal/sysfs-api2.txt
> new file mode 100644
> index 0000000..be67125
> --- /dev/null
> +++ b/Documentation/thermal/sysfs-api2.txt
> @@ -0,0 +1,213 @@
> +Thermal Framework
> +-----------------
> +
> +Written by Durgadoss R <durgadoss.r@intel.com>
> +Copyright (c) 2012 Intel Corporation
> +
> +Created on: 4 November 2012
> +
> +0. Introduction
> +---------------
> +The Linux thermal framework provides a set of interfaces for thermal
> +sensors and thermal cooling devices (fan, processor...) to register
> +with the thermal management solution and to be a part of it.
> +
> +This document focuses on how to enable new thermal sensors and cooling
> +devices to participate in thermal management. This solution is intended
> +to be 'light-weight' and platform/architecture independent. Any thermal
> +sensor/cooling device should be able to use the infrastructure easily.
> +
> +The goal of thermal framework is to expose the thermal sensor/zone and
> +cooling device attributes in a consistent way. This will help the
> +thermal governors to make use of the information to manage platform
> +thermals efficiently.
> +
> +1. Terminology
> +--------------
> +This section describes the terminology used in the rest of this
> +document as well as the thermal framework code.
> +
> +thermal_sensor: Hardware that can report temperature of a particular
> +               spot in the platform, where it is placed. The temperature
> +               reported by the sensor is the 'real' temperature reported
> +               by the hardware.
> +thermal_zone:  A virtual area on the device, that gets heated up. It may
> +               have one or more thermal sensors attached to it.
> +cooling_device:        Any component that can help in reducing the temperature of
> +               a 'hot spot' either by reducing its performance (passive
> +               cooling) or by other means(Active cooling E.g. Fan)
> +
> +trip_points:   Various temperature levels for each sensor. As of now, we
> +               have four levels namely active, passive, hot and critical.
> +               Hot and critical trip point support only one value whereas
> +               active and passive can have any number of values. These
> +               temperature values can come from platform data, and are
> +               exposed through sysfs in a consistent manner. Stand-alone
> +               thermal sensor drivers are not expected to know these values.
> +               These values are RO.
> +thresholds:    These are programmable temperature limits, on reaching which
> +               the thermal sensor generates an interrupt. The framework is
> +               notified about this interrupt to take appropriate action.
> +               There can be as many number of thresholds as that of the
> +               hardware supports. These values are RW.
> +
> +thermal_map:   This provides the mapping (aka binding) information between
> +               various sensors and cooling devices in a particular zone.
> +               Typically, this also comes from platform data; Stand-alone
> +               sensor drivers or cooling device drivers are not expected
> +               to know these mapping information.
> +
> +2. Thermal framework APIs
> +-------------------------
> +2.1: For Thermal Sensors
> +2.1.1 thermal_sensor_register:
> +       This function creates a new sensor directory under /sys/class/thermal/
> +       as sensor[0-*]. This API is expected to be called by thermal sensor
> +       drivers. These drivers may or may not be in thermal subsystem. This
> +       function returns a thermal_sensor structure on success and appropriate
> +       error on failure.
> +
> +       name: Name of the sensor
> +       devdata: Device private data
> +       ops: Thermal sensor callbacks
> +               .get_temp: obtain the current temperature of the sensor
> +               .get_trend: obtain the trend of the sensor
> +               .get_threshold: get a particular threshold temperature
> +               .set_threshold: set a particular threshold temperature
> +
> +2.1.2 thermal_sensor_unregister:
> +       This function deletes the sensor directory under /sys/class/thermal/
> +       for the given sensor. Thermal sensor drivers may call this API
> +       during the driver's 'exit' routine.
> +
> +       ts: Thermal sensor that has to be unregistered
> +
> +2.1.3 enable_sensor_thresholds:
> +       This function creates 'threshold[0-*]' attributes under a particular
> +       sensorX directory. These values are RW. This function is called by
> +       the sensr driver only if the sensor supports interrupt mechanism.
> +
> +       ts: Thermal sensor for which thresholds have to be enabled
> +       num_thresholds: Number of thresholds supported by the sensor
> +
> +2.2: For Cooling Devices
> +2.2.1 thermal_cooling_device_register:
> +       This function adds a new thermal cooling device (fan/processor/...)
> +       to /sys/class/thermal/ folder as cooling_device[0-*]. This function
> +       is expected to be called by cooling device drivers that may be
> +       present in other subsystems also.
> +
> +       name: the cooling device name
> +       devdata: device private data
> +       ops: thermal cooling devices callbacks
> +       .get_max_state: get the Maximum throttle state of the cooling device
> +       .get_cur_state: get the Current throttle state of the cooling device
> +       .set_cur_state: set the Current throttle state of the cooling device
> +
> +2.2.2 thermal_cooling_device_unregister:
> +       This function deletes the given cdev entry form /sys/class/thermal;
> +       and also cleans all the symlinks referred from various zones.
> +
> +       cdev: Cooling device to be unregistered
> +
> +2.3: For Thermal Zones
> +2.3.1 create_thermal_zone:
> +       This function adds a new 'zone' under /sys/class/thermal/
> +       directory as zone[0-*]. This zone has at least one thermal
> +       sensor and at most MAX_SENSORS_PER_ZONE number of sensors
> +       attached to it. Similarly, this zone has at least one cdev
> +       and at most MAX_CDEVS_PER_ZONE number of cdevs attached to it.
> +       Both the MAX_*_PER_ZONE values are configurable, through
> +       Kconfig option(during 'menuconfig').
> +
> +       name: Name of the thermal zone
> +       devdata: Device private data
> +
> +2.3.2 add_sensor_to_zone
> +       This function adds a 'sensorX' entry under /sys/class/thermal/
> +       zoneY/ directory. This 'sensorX' is a symlink to the actual
> +       sensor entry under /sys/class/thermal/. Correspondingly, the
> +       method remove_sensor_from_zone deletes the symlink.
> +
> +       tz: thermal zone structure
> +       ts: thermal sensor structure
> +
> +2.3.3 add_cdev_to_zone
> +       This function adds a 'cdevX' entry under /sys/class/thermal/
> +       zoneY/ directory. This 'cdevX' is a symlink to the actual
> +       cdev entry under /sys/class/thermal/. Correspondingly, the
> +       method remove_cdev_from_zone deletes the symlink.
> +
> +       tz: thermal zone structure
> +       cdev: thermal cooling device structure
> +
> +2.4 For Thermal Trip
> +2.4.1 add_sensor_trip_info
> +       This function adds trip point information for the given sensor,
> +       (under a given zone) under /sys/class/thermal/zoneX/thermal_trip/
> +       This API creates 4 sysfs attributes namely active, passive, hot,
> +       and critical. Each of these hold one or more trip point temperature
> +       values, as provided from platform data.
> +
> +       tz: thermal zone structure
> +       ts: thermal sensor to which the trip points are attached
> +       trip: trip point structure. Usually obtained from platform data
> +
> +2.5 For Thermal Map
> +2.5.1 add_map_entry
> +       This function adds a 'map[0-*]' sysfs attribute under
> +       /sys/class/thermal/zoneX/thermal_map/. Each map holds a space
> +       separated list of values, that specify the binding relationship
> +       between a sensor and a cdev in the given zone. The map structure
> +       is typically obtained as platform data. For example, through
> +       ACPI tables, SFI tables, Device tree etc.
> +
> +       tz: thermal zone to which a 'map' is being added
> +       map: thermal_map structure
> +
> +3. Sysfs attributes structure
> +-----------------------------
> +Thermal sysfs attributes will be represented under /sys/class/thermal.
> +
> +3.1: For Thermal Sensors
> +       /sys/class/thermal/thermal_zone[0-*]:
Should be /sys/class/thermal/sensor[0-*] ?

> +               |---type:               Name of the thermal sensor
> +               |---temp_input:         Current temperature in mC
> +               |---threshold[0-*]:     Threshold temperature
> +
> +3.2: For Thermal Cooling Devices
> +       /sys/class/thermal/cooling_device[0-*]:
> +               |---type:               Type of the cooling device
> +               |---max_state:          Maximum throttle state of the cdev
> +               |---cur_state:          Current throttle state of the cdev
> +
> +3.3: For Thermal Zones
> +       /sys/class/thermal/zone[0-*]:
> +               |---name:               Name of the thermal
> +               |---sensorX:            Symlink to ../sensorX
> +               |---cdevY:              Symlink to ../cdevY
> +               |---thermal_trip:       trip point values for sensors
> +               |---thermal_map:        mapping info between sensors and cdevs
> +
> +3.4: For Thermal Trip
> +       This attribute represents the trip point values for all sensors
> +       present in the thermal zone. All values are in mC.
> +       /sys/class/thermal/zoneX/thermal_trip/sensorY:
> +               |---hot:                hot trip point value
> +               |---critical:           critical trip point value
> +               |---passive:            list of passive trip point values
> +               |---active:             list of active trip point values
> +
> +3.5: For Thermal Map
> +       Each attribute represents the mapping/binding information between
> +       a sensor and a cdev, together with a trip type.
> +       /sys/class/thermal/zoneX/thermal_map/:
> +               |---mapX:               mapping information
> +       A typical map entry is like below:
> +
> +       trip_type  sensor  cdev  trip_mask  weight(s)
> +       passive    cpu     proc  0x03       50 30
> +       active     cpu     fan0  0x03       50 70
> +
> +       The trip mask is a bit string; if 'n' th bit is set, then for
> +       trip point 'n' this cdev is throttled with the given weight[n].
> --
> 1.7.9.5
>

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

* Re: [RFC PATCH 2/7] Thermal: Create zone level APIs
  2012-11-17 10:45 ` [RFC PATCH 2/7] Thermal: Create zone " Durgadoss R
@ 2012-12-03  7:42   ` Hongbo Zhang
  2012-12-03  7:47     ` R, Durgadoss
  2012-12-13  6:23   ` Hongbo Zhang
  1 sibling, 1 reply; 27+ messages in thread
From: Hongbo Zhang @ 2012-12-03  7:42 UTC (permalink / raw)
  To: Durgadoss R
  Cc: rui.zhang, linux-pm, wni, eduardo.valentin, amit.kachhap, sachin.kamat

On 17 November 2012 18:45, Durgadoss R <durgadoss.r@intel.com> wrote:
> This patch adds a new thermal_zone structure to
> thermal.h. Also, adds zone level APIs to the thermal
> framework.
>
> Signed-off-by: Durgadoss R <durgadoss.r@intel.com>
> ---
>  drivers/thermal/thermal_sys.c |  206 +++++++++++++++++++++++++++++++++++++++++
>  include/linux/thermal.h       |   25 +++++
>  2 files changed, 231 insertions(+)
>
> diff --git a/drivers/thermal/thermal_sys.c b/drivers/thermal/thermal_sys.c
> index e726c8b..9d386d7 100644
> --- a/drivers/thermal/thermal_sys.c
> +++ b/drivers/thermal/thermal_sys.c
> @@ -44,19 +44,28 @@ MODULE_DESCRIPTION("Generic thermal management sysfs support");
>  MODULE_LICENSE("GPL");
>
>  static DEFINE_IDR(thermal_tz_idr);
> +static DEFINE_IDR(thermal_zone_idr);
>  static DEFINE_IDR(thermal_cdev_idr);
>  static DEFINE_IDR(thermal_sensor_idr);
>  static DEFINE_MUTEX(thermal_idr_lock);
>
>  static LIST_HEAD(thermal_tz_list);
>  static LIST_HEAD(thermal_sensor_list);
> +static LIST_HEAD(thermal_zone_list);
>  static LIST_HEAD(thermal_cdev_list);
>  static LIST_HEAD(thermal_governor_list);
>
>  static DEFINE_MUTEX(thermal_list_lock);
>  static DEFINE_MUTEX(ts_list_lock);
> +static DEFINE_MUTEX(tz_list_lock);
>  static DEFINE_MUTEX(thermal_governor_lock);
>
> +#define for_each_thermal_sensor(pos) \
> +       list_for_each_entry(pos, &thermal_sensor_list, node)
> +
> +#define for_each_thermal_zone(pos) \
> +       list_for_each_entry(pos, &thermal_zone_list, node)
> +
>  static struct thermal_governor *__find_governor(const char *name)
>  {
>         struct thermal_governor *pos;
> @@ -419,15 +428,62 @@ static void thermal_zone_device_check(struct work_struct *work)
>         thermal_zone_device_update(tz);
>  }
>
> +static int get_sensor_indx(struct thermal_zone *tz, struct thermal_sensor *ts)
> +{
> +       int i, indx = -EINVAL;
> +
> +       if (!tz || !ts)
> +               return -EINVAL;
> +
> +       mutex_lock(&ts_list_lock);
> +       for (i = 0; i < tz->sensor_indx; i++) {
> +               if (tz->sensors[i] == ts) {
> +                       indx = i;
> +                       break;
> +               }
> +       }
> +       mutex_unlock(&ts_list_lock);
> +       return indx;
> +}
> +
> +static void remove_sensor_from_zone(struct thermal_zone *tz,
> +                               struct thermal_sensor *ts)
> +{
> +       int indx, j;
> +
> +       indx = get_sensor_indx(tz, ts);
> +       if (indx < 0)
> +               return;
> +
> +       sysfs_remove_link(&tz->device.kobj, kobject_name(&ts->device.kobj));
> +
> +       /* Shift the entries in the tz->sensors array */
> +       for (j = indx; j < MAX_SENSORS_PER_ZONE - 1; j++)
> +               tz->sensors[j] = tz->sensors[j + 1];
> +
> +       tz->sensor_indx--;
> +}
> +
>  /* sys I/F for thermal zone */
>
>  #define to_thermal_zone(_dev) \
>         container_of(_dev, struct thermal_zone_device, device)
>
> +#define to_zone(_dev) \
> +       container_of(_dev, struct thermal_zone, device)
> +
>  #define to_thermal_sensor(_dev) \
>         container_of(_dev, struct thermal_sensor, device)
>
>  static ssize_t
> +zone_name_show(struct device *dev, struct device_attribute *attr, char *buf)
> +{
> +       struct thermal_zone *tz = to_zone(dev);
> +
> +       return sprintf(buf, "%s\n", tz->name);
> +}
> +
> +static ssize_t
>  sensor_name_show(struct device *dev, struct device_attribute *attr, char *buf)
>  {
>         struct thermal_sensor *ts = to_thermal_sensor(dev);
> @@ -772,6 +828,8 @@ static DEVICE_ATTR(policy, S_IRUGO | S_IWUSR, policy_show, policy_store);
>  static DEVICE_ATTR(sensor_name, 0444, sensor_name_show, NULL);
>  static DEVICE_ATTR(temp_input, 0444, sensor_temp_show, NULL);
>
> +static DEVICE_ATTR(zone_name, 0444, zone_name_show, NULL);
> +
>  /* sys I/F for cooling device */
>  #define to_cooling_device(_dev)        \
>         container_of(_dev, struct thermal_cooling_device, device)
> @@ -1557,6 +1615,146 @@ static void remove_trip_attrs(struct thermal_zone_device *tz)
>         kfree(tz->trip_hyst_attrs);
>  }
>
> +struct thermal_zone *create_thermal_zone(const char *name, void *devdata)
> +{
> +       struct thermal_zone *tz;
> +       int ret;
> +
> +       if (!name || (name && strlen(name) >= THERMAL_NAME_LENGTH))
> +               return ERR_PTR(-EINVAL);
> +
> +       tz = kzalloc(sizeof(*tz), GFP_KERNEL);
> +       if (!tz)
> +               return ERR_PTR(-ENOMEM);
> +
> +       idr_init(&tz->idr);
> +       ret = get_idr(&thermal_zone_idr, &thermal_idr_lock, &tz->id);
> +       if (ret)
> +               goto exit_free;
> +
> +       strcpy(tz->name, name);
> +       tz->devdata = devdata;
> +       tz->device.class = &thermal_class;
> +
> +       dev_set_name(&tz->device, "zone%d", tz->id);
> +       ret = device_register(&tz->device);
> +       if (ret)
> +               goto exit_idr;
> +
> +       ret = device_create_file(&tz->device, &dev_attr_zone_name);
> +       if (ret)
> +               goto exit_unregister;
> +
> +       /* Add this zone to the global list of thermal zones */
> +       mutex_lock(&tz_list_lock);
> +       list_add_tail(&tz->node, &thermal_zone_list);
> +       mutex_unlock(&tz_list_lock);
> +       return tz;
> +
> +exit_unregister:
> +       device_unregister(&tz->device);
> +exit_idr:
> +       release_idr(&thermal_zone_idr, &thermal_idr_lock, tz->id);
> +exit_free:
> +       kfree(tz);
> +       return ERR_PTR(ret);
> +}
> +EXPORT_SYMBOL(create_thermal_zone);
> +
> +void remove_thermal_zone(struct thermal_zone *tz)
> +{
> +       struct thermal_zone *pos, *next;
> +       bool found = false;
> +
> +       if (!tz)
> +               return;
> +
> +       mutex_lock(&tz_list_lock);
> +
> +       list_for_each_entry_safe(pos, next, &thermal_zone_list, node) {
> +               if (pos == tz) {
> +                       list_del(&tz->node);
> +                       found = true;
> +                       break;
> +               }
> +       }
> +
> +       if (!found)
> +               goto exit;
> +
> +       device_remove_file(&tz->device, &dev_attr_zone_name);
> +
> +       release_idr(&thermal_zone_idr, &thermal_idr_lock, tz->id);
> +       idr_destroy(&tz->idr);
> +
> +       device_unregister(&tz->device);
> +       kfree(tz);
> +exit:
> +       mutex_unlock(&tz_list_lock);
> +       return;
> +}
> +EXPORT_SYMBOL(remove_thermal_zone);
> +
> +struct thermal_sensor *get_sensor_by_name(const char *name)
> +{
> +       struct thermal_sensor *pos;
> +       struct thermal_sensor *ts = NULL;
> +
> +       mutex_lock(&ts_list_lock);
> +       for_each_thermal_sensor(pos) {
> +               if (!strnicmp(pos->name, name, THERMAL_NAME_LENGTH)) {
> +                       ts = pos;
> +                       break;
> +               }
> +       }
> +       mutex_unlock(&ts_list_lock);
> +       return ts;
> +}
> +EXPORT_SYMBOL(get_sensor_by_name);
> +
> +int add_sensor_to_zone_by_name(struct thermal_zone *tz, const char *name)
> +{
> +       int ret;
> +       struct thermal_sensor *ts = get_sensor_by_name(name);
> +
> +       if (!tz || !ts)
> +               return -EINVAL;
> +
> +       mutex_lock(&tz_list_lock);
> +
> +       /* Ensure we are not adding the same sensor again!! */
> +       ret = get_sensor_indx(tz, ts);
> +       if (ret >= 0) {
> +               ret = -EEXIST;
> +               goto exit_zone;
> +       }
> +
> +       mutex_lock(&ts_list_lock);
> +
> +       ret = sysfs_create_link(&tz->device.kobj, &ts->device.kobj,
> +                               kobject_name(&ts->device.kobj));
> +       if (ret)
> +               goto exit_sensor;
> +
> +       tz->sensors[tz->sensor_indx++] = ts;
> +
> +exit_sensor:
> +       mutex_unlock(&ts_list_lock);
> +exit_zone:
> +       mutex_unlock(&tz_list_lock);
> +       return ret;
> +}
> +EXPORT_SYMBOL(add_sensor_to_zone_by_name);
> +
> +int add_sensor_to_zone(struct thermal_zone *tz, struct thermal_sensor *ts)
> +{
> +       if (!tz || !ts)
> +               return -EINVAL;
> +
> +       return add_sensor_to_zone_by_name(tz, ts->name);
> +}
> +EXPORT_SYMBOL(add_sensor_to_zone);
> +
>  /**
>   * thermal_sensor_register - register a new thermal sensor
>   * @name:      name of the thermal sensor
> @@ -1624,6 +1822,7 @@ EXPORT_SYMBOL(thermal_sensor_register);
>  void thermal_sensor_unregister(struct thermal_sensor *ts)
>  {
>         int i;
> +       struct thermal_zone *tz;
>         struct thermal_sensor *pos, *next;
>         bool found = false;
>
> @@ -1643,6 +1842,13 @@ void thermal_sensor_unregister(struct thermal_sensor *ts)
>         if (!found)
>                 return;
>
> +       mutex_lock(&tz_list_lock);
> +
> +       for_each_thermal_zone(tz)
> +               remove_sensor_from_zone(tz, ts);
> +
> +       mutex_unlock(&tz_list_lock);
> +
>         for (i = 0; i < ts->thresholds; i++)
>                 device_remove_file(&ts->device, &ts->thresh_attrs[i].attr);
>
> diff --git a/include/linux/thermal.h b/include/linux/thermal.h
> index e2f85ec..38438be 100644
> --- a/include/linux/thermal.h
> +++ b/include/linux/thermal.h
> @@ -49,6 +49,11 @@
>  /* Default Thermal Governor: Does Linear Throttling */
>  #define DEFAULT_THERMAL_GOVERNOR       "step_wise"
>
> +/* Maximum number of sensors, allowed in a thermal zone
> + * We will start with 5, and increase if needed.
> + */
> +#define MAX_SENSORS_PER_ZONE           5
> +
>  struct thermal_sensor;
>  struct thermal_zone_device;
>  struct thermal_cooling_device;
> @@ -191,6 +196,21 @@ struct thermal_zone_device {
>         struct delayed_work poll_queue;
>  };
>
> +struct thermal_zone {
> +       char name[THERMAL_NAME_LENGTH];
> +       int id;
> +       void *devdata;
> +       struct thermal_zone *ops;
What is this, thermal_zone_device_ops? and how to initialize this ops?

> +       struct thermal_governor *governor;
> +       struct idr idr;
> +       struct device device;
> +       struct list_head node;
> +
> +       /* Sensor level information */
> +       int sensor_indx; /* index into 'sensors' array */
> +       struct thermal_sensor *sensors[MAX_SENSORS_PER_ZONE];
> +};
> +
>  /* Structure that holds thermal governor information */
>  struct thermal_governor {
>         char name[THERMAL_NAME_LENGTH];
> @@ -264,6 +284,11 @@ struct thermal_sensor *thermal_sensor_register(const char *,
>  void thermal_sensor_unregister(struct thermal_sensor *);
>  int enable_sensor_thresholds(struct thermal_sensor *, int);
>
> +struct thermal_zone *create_thermal_zone(const char *, void *);
> +void remove_thermal_zone(struct thermal_zone *);
> +int add_sensor_to_zone(struct thermal_zone *, struct thermal_sensor *);
> +int add_sensor_to_zone_by_name(struct thermal_zone *, const char *);
> +
>  #ifdef CONFIG_NET
>  extern int thermal_generate_netlink_event(u32 orig, enum events event);
>  #else
> --
> 1.7.9.5
>

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

* RE: [RFC PATCH 6/7] Thermal: Add Documentation to new APIs
  2012-12-03  7:19   ` Hongbo Zhang
@ 2012-12-03  7:44     ` R, Durgadoss
  0 siblings, 0 replies; 27+ messages in thread
From: R, Durgadoss @ 2012-12-03  7:44 UTC (permalink / raw)
  To: Hongbo Zhang
  Cc: Zhang, Rui, linux-pm, wni, eduardo.valentin, amit.kachhap, sachin.kamat

Yes, it's a typo.
Will fix it in the next submission.

Thanks,
Durga

> -----Original Message-----
> From: Hongbo Zhang [mailto:hongbo.zhang@linaro.org]
> Sent: Monday, December 03, 2012 12:50 PM
> To: R, Durgadoss
> Cc: Zhang, Rui; linux-pm@vger.kernel.org; wni@nvidia.com;
> eduardo.valentin@ti.com; amit.kachhap@linaro.org;
> sachin.kamat@linaro.org
> Subject: Re: [RFC PATCH 6/7] Thermal: Add Documentation to new APIs
> 
> On 17 November 2012 18:45, Durgadoss R <durgadoss.r@intel.com> wrote:
> > This patch adds Documentation for the new APIs
> > introduced in this patch set. The documentation
> > also has a model sysfs structure for reference.
> >
> > Signed-off-by: Durgadoss R <durgadoss.r@intel.com>
> > ---
> >  Documentation/thermal/sysfs-api2.txt |  213
> ++++++++++++++++++++++++++++++++++
> >  1 file changed, 213 insertions(+)
> >  create mode 100644 Documentation/thermal/sysfs-api2.txt
> >
> > diff --git a/Documentation/thermal/sysfs-api2.txt
> b/Documentation/thermal/sysfs-api2.txt
> > new file mode 100644
> > index 0000000..be67125
> > --- /dev/null
> > +++ b/Documentation/thermal/sysfs-api2.txt
> > @@ -0,0 +1,213 @@
> > +Thermal Framework
> > +-----------------
> > +
> > +Written by Durgadoss R <durgadoss.r@intel.com>
> > +Copyright (c) 2012 Intel Corporation
> > +
> > +Created on: 4 November 2012
> > +
> > +0. Introduction
> > +---------------
> > +The Linux thermal framework provides a set of interfaces for thermal
> > +sensors and thermal cooling devices (fan, processor...) to register
> > +with the thermal management solution and to be a part of it.
> > +
> > +This document focuses on how to enable new thermal sensors and
> cooling
> > +devices to participate in thermal management. This solution is intended
> > +to be 'light-weight' and platform/architecture independent. Any thermal
> > +sensor/cooling device should be able to use the infrastructure easily.
> > +
> > +The goal of thermal framework is to expose the thermal sensor/zone and
> > +cooling device attributes in a consistent way. This will help the
> > +thermal governors to make use of the information to manage platform
> > +thermals efficiently.
> > +
> > +1. Terminology
> > +--------------
> > +This section describes the terminology used in the rest of this
> > +document as well as the thermal framework code.
> > +
> > +thermal_sensor: Hardware that can report temperature of a particular
> > +               spot in the platform, where it is placed. The temperature
> > +               reported by the sensor is the 'real' temperature reported
> > +               by the hardware.
> > +thermal_zone:  A virtual area on the device, that gets heated up. It may
> > +               have one or more thermal sensors attached to it.
> > +cooling_device:        Any component that can help in reducing the
> temperature of
> > +               a 'hot spot' either by reducing its performance (passive
> > +               cooling) or by other means(Active cooling E.g. Fan)
> > +
> > +trip_points:   Various temperature levels for each sensor. As of now, we
> > +               have four levels namely active, passive, hot and critical.
> > +               Hot and critical trip point support only one value whereas
> > +               active and passive can have any number of values. These
> > +               temperature values can come from platform data, and are
> > +               exposed through sysfs in a consistent manner. Stand-alone
> > +               thermal sensor drivers are not expected to know these values.
> > +               These values are RO.
> > +thresholds:    These are programmable temperature limits, on reaching
> which
> > +               the thermal sensor generates an interrupt. The framework is
> > +               notified about this interrupt to take appropriate action.
> > +               There can be as many number of thresholds as that of the
> > +               hardware supports. These values are RW.
> > +
> > +thermal_map:   This provides the mapping (aka binding) information
> between
> > +               various sensors and cooling devices in a particular zone.
> > +               Typically, this also comes from platform data; Stand-alone
> > +               sensor drivers or cooling device drivers are not expected
> > +               to know these mapping information.
> > +
> > +2. Thermal framework APIs
> > +-------------------------
> > +2.1: For Thermal Sensors
> > +2.1.1 thermal_sensor_register:
> > +       This function creates a new sensor directory under /sys/class/thermal/
> > +       as sensor[0-*]. This API is expected to be called by thermal sensor
> > +       drivers. These drivers may or may not be in thermal subsystem. This
> > +       function returns a thermal_sensor structure on success and
> appropriate
> > +       error on failure.
> > +
> > +       name: Name of the sensor
> > +       devdata: Device private data
> > +       ops: Thermal sensor callbacks
> > +               .get_temp: obtain the current temperature of the sensor
> > +               .get_trend: obtain the trend of the sensor
> > +               .get_threshold: get a particular threshold temperature
> > +               .set_threshold: set a particular threshold temperature
> > +
> > +2.1.2 thermal_sensor_unregister:
> > +       This function deletes the sensor directory under /sys/class/thermal/
> > +       for the given sensor. Thermal sensor drivers may call this API
> > +       during the driver's 'exit' routine.
> > +
> > +       ts: Thermal sensor that has to be unregistered
> > +
> > +2.1.3 enable_sensor_thresholds:
> > +       This function creates 'threshold[0-*]' attributes under a particular
> > +       sensorX directory. These values are RW. This function is called by
> > +       the sensr driver only if the sensor supports interrupt mechanism.
> > +
> > +       ts: Thermal sensor for which thresholds have to be enabled
> > +       num_thresholds: Number of thresholds supported by the sensor
> > +
> > +2.2: For Cooling Devices
> > +2.2.1 thermal_cooling_device_register:
> > +       This function adds a new thermal cooling device (fan/processor/...)
> > +       to /sys/class/thermal/ folder as cooling_device[0-*]. This function
> > +       is expected to be called by cooling device drivers that may be
> > +       present in other subsystems also.
> > +
> > +       name: the cooling device name
> > +       devdata: device private data
> > +       ops: thermal cooling devices callbacks
> > +       .get_max_state: get the Maximum throttle state of the cooling device
> > +       .get_cur_state: get the Current throttle state of the cooling device
> > +       .set_cur_state: set the Current throttle state of the cooling device
> > +
> > +2.2.2 thermal_cooling_device_unregister:
> > +       This function deletes the given cdev entry form /sys/class/thermal;
> > +       and also cleans all the symlinks referred from various zones.
> > +
> > +       cdev: Cooling device to be unregistered
> > +
> > +2.3: For Thermal Zones
> > +2.3.1 create_thermal_zone:
> > +       This function adds a new 'zone' under /sys/class/thermal/
> > +       directory as zone[0-*]. This zone has at least one thermal
> > +       sensor and at most MAX_SENSORS_PER_ZONE number of sensors
> > +       attached to it. Similarly, this zone has at least one cdev
> > +       and at most MAX_CDEVS_PER_ZONE number of cdevs attached to it.
> > +       Both the MAX_*_PER_ZONE values are configurable, through
> > +       Kconfig option(during 'menuconfig').
> > +
> > +       name: Name of the thermal zone
> > +       devdata: Device private data
> > +
> > +2.3.2 add_sensor_to_zone
> > +       This function adds a 'sensorX' entry under /sys/class/thermal/
> > +       zoneY/ directory. This 'sensorX' is a symlink to the actual
> > +       sensor entry under /sys/class/thermal/. Correspondingly, the
> > +       method remove_sensor_from_zone deletes the symlink.
> > +
> > +       tz: thermal zone structure
> > +       ts: thermal sensor structure
> > +
> > +2.3.3 add_cdev_to_zone
> > +       This function adds a 'cdevX' entry under /sys/class/thermal/
> > +       zoneY/ directory. This 'cdevX' is a symlink to the actual
> > +       cdev entry under /sys/class/thermal/. Correspondingly, the
> > +       method remove_cdev_from_zone deletes the symlink.
> > +
> > +       tz: thermal zone structure
> > +       cdev: thermal cooling device structure
> > +
> > +2.4 For Thermal Trip
> > +2.4.1 add_sensor_trip_info
> > +       This function adds trip point information for the given sensor,
> > +       (under a given zone) under /sys/class/thermal/zoneX/thermal_trip/
> > +       This API creates 4 sysfs attributes namely active, passive, hot,
> > +       and critical. Each of these hold one or more trip point temperature
> > +       values, as provided from platform data.
> > +
> > +       tz: thermal zone structure
> > +       ts: thermal sensor to which the trip points are attached
> > +       trip: trip point structure. Usually obtained from platform data
> > +
> > +2.5 For Thermal Map
> > +2.5.1 add_map_entry
> > +       This function adds a 'map[0-*]' sysfs attribute under
> > +       /sys/class/thermal/zoneX/thermal_map/. Each map holds a space
> > +       separated list of values, that specify the binding relationship
> > +       between a sensor and a cdev in the given zone. The map structure
> > +       is typically obtained as platform data. For example, through
> > +       ACPI tables, SFI tables, Device tree etc.
> > +
> > +       tz: thermal zone to which a 'map' is being added
> > +       map: thermal_map structure
> > +
> > +3. Sysfs attributes structure
> > +-----------------------------
> > +Thermal sysfs attributes will be represented under /sys/class/thermal.
> > +
> > +3.1: For Thermal Sensors
> > +       /sys/class/thermal/thermal_zone[0-*]:
> Should be /sys/class/thermal/sensor[0-*] ?
> 
> > +               |---type:               Name of the thermal sensor
> > +               |---temp_input:         Current temperature in mC
> > +               |---threshold[0-*]:     Threshold temperature
> > +
> > +3.2: For Thermal Cooling Devices
> > +       /sys/class/thermal/cooling_device[0-*]:
> > +               |---type:               Type of the cooling device
> > +               |---max_state:          Maximum throttle state of the cdev
> > +               |---cur_state:          Current throttle state of the cdev
> > +
> > +3.3: For Thermal Zones
> > +       /sys/class/thermal/zone[0-*]:
> > +               |---name:               Name of the thermal
> > +               |---sensorX:            Symlink to ../sensorX
> > +               |---cdevY:              Symlink to ../cdevY
> > +               |---thermal_trip:       trip point values for sensors
> > +               |---thermal_map:        mapping info between sensors and cdevs
> > +
> > +3.4: For Thermal Trip
> > +       This attribute represents the trip point values for all sensors
> > +       present in the thermal zone. All values are in mC.
> > +       /sys/class/thermal/zoneX/thermal_trip/sensorY:
> > +               |---hot:                hot trip point value
> > +               |---critical:           critical trip point value
> > +               |---passive:            list of passive trip point values
> > +               |---active:             list of active trip point values
> > +
> > +3.5: For Thermal Map
> > +       Each attribute represents the mapping/binding information between
> > +       a sensor and a cdev, together with a trip type.
> > +       /sys/class/thermal/zoneX/thermal_map/:
> > +               |---mapX:               mapping information
> > +       A typical map entry is like below:
> > +
> > +       trip_type  sensor  cdev  trip_mask  weight(s)
> > +       passive    cpu     proc  0x03       50 30
> > +       active     cpu     fan0  0x03       50 70
> > +
> > +       The trip mask is a bit string; if 'n' th bit is set, then for
> > +       trip point 'n' this cdev is throttled with the given weight[n].
> > --
> > 1.7.9.5
> >

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

* RE: [RFC PATCH 2/7] Thermal: Create zone level APIs
  2012-12-03  7:42   ` Hongbo Zhang
@ 2012-12-03  7:47     ` R, Durgadoss
  2012-12-03  8:21       ` Hongbo Zhang
  0 siblings, 1 reply; 27+ messages in thread
From: R, Durgadoss @ 2012-12-03  7:47 UTC (permalink / raw)
  To: Hongbo Zhang
  Cc: Zhang, Rui, linux-pm, wni, eduardo.valentin, amit.kachhap, sachin.kamat



> -----Original Message-----
> From: Hongbo Zhang [mailto:hongbo.zhang@linaro.org]
> Sent: Monday, December 03, 2012 1:13 PM
> To: R, Durgadoss
> Cc: Zhang, Rui; linux-pm@vger.kernel.org; wni@nvidia.com;
> eduardo.valentin@ti.com; amit.kachhap@linaro.org;
> sachin.kamat@linaro.org
> Subject: Re: [RFC PATCH 2/7] Thermal: Create zone level APIs
> 
> On 17 November 2012 18:45, Durgadoss R <durgadoss.r@intel.com> wrote:
> > This patch adds a new thermal_zone structure to
> > thermal.h. Also, adds zone level APIs to the thermal
> > framework.
> >
> > Signed-off-by: Durgadoss R <durgadoss.r@intel.com>
> > ---
> >  drivers/thermal/thermal_sys.c |  206
> +++++++++++++++++++++++++++++++++++++++++
> >  include/linux/thermal.h       |   25 +++++
> >  2 files changed, 231 insertions(+)
> >
> > diff --git a/drivers/thermal/thermal_sys.c b/drivers/thermal/thermal_sys.c
> > index e726c8b..9d386d7 100644
> > --- a/drivers/thermal/thermal_sys.c
> > +++ b/drivers/thermal/thermal_sys.c
> > @@ -44,19 +44,28 @@ MODULE_DESCRIPTION("Generic thermal
> management sysfs support");
> >  MODULE_LICENSE("GPL");
> >
> >  static DEFINE_IDR(thermal_tz_idr);
> > +static DEFINE_IDR(thermal_zone_idr);
> >  static DEFINE_IDR(thermal_cdev_idr);
> >  static DEFINE_IDR(thermal_sensor_idr);
> >  static DEFINE_MUTEX(thermal_idr_lock);
> >
> >  static LIST_HEAD(thermal_tz_list);
> >  static LIST_HEAD(thermal_sensor_list);
> > +static LIST_HEAD(thermal_zone_list);
> >  static LIST_HEAD(thermal_cdev_list);
> >  static LIST_HEAD(thermal_governor_list);
> >
> >  static DEFINE_MUTEX(thermal_list_lock);
> >  static DEFINE_MUTEX(ts_list_lock);
> > +static DEFINE_MUTEX(tz_list_lock);
> >  static DEFINE_MUTEX(thermal_governor_lock);
> >
> > +#define for_each_thermal_sensor(pos) \
> > +       list_for_each_entry(pos, &thermal_sensor_list, node)
> > +
> > +#define for_each_thermal_zone(pos) \
> > +       list_for_each_entry(pos, &thermal_zone_list, node)
> > +
> >  static struct thermal_governor *__find_governor(const char *name)
> >  {
> >         struct thermal_governor *pos;
> > @@ -419,15 +428,62 @@ static void thermal_zone_device_check(struct
> work_struct *work)
> >         thermal_zone_device_update(tz);
> >  }
> >
> > +static int get_sensor_indx(struct thermal_zone *tz, struct thermal_sensor
> *ts)
> > +{
> > +       int i, indx = -EINVAL;
> > +
> > +       if (!tz || !ts)
> > +               return -EINVAL;
> > +
> > +       mutex_lock(&ts_list_lock);
> > +       for (i = 0; i < tz->sensor_indx; i++) {
> > +               if (tz->sensors[i] == ts) {
> > +                       indx = i;
> > +                       break;
> > +               }
> > +       }
> > +       mutex_unlock(&ts_list_lock);
> > +       return indx;
> > +}
> > +
> > +static void remove_sensor_from_zone(struct thermal_zone *tz,
> > +                               struct thermal_sensor *ts)
> > +{
> > +       int indx, j;
> > +
> > +       indx = get_sensor_indx(tz, ts);
> > +       if (indx < 0)
> > +               return;
> > +
> > +       sysfs_remove_link(&tz->device.kobj, kobject_name(&ts-
> >device.kobj));
> > +
> > +       /* Shift the entries in the tz->sensors array */
> > +       for (j = indx; j < MAX_SENSORS_PER_ZONE - 1; j++)
> > +               tz->sensors[j] = tz->sensors[j + 1];
> > +
> > +       tz->sensor_indx--;
> > +}
> > +
> >  /* sys I/F for thermal zone */
> >
> >  #define to_thermal_zone(_dev) \
> >         container_of(_dev, struct thermal_zone_device, device)
> >
> > +#define to_zone(_dev) \
> > +       container_of(_dev, struct thermal_zone, device)
> > +
> >  #define to_thermal_sensor(_dev) \
> >         container_of(_dev, struct thermal_sensor, device)
> >
> >  static ssize_t
> > +zone_name_show(struct device *dev, struct device_attribute *attr, char
> *buf)
> > +{
> > +       struct thermal_zone *tz = to_zone(dev);
> > +
> > +       return sprintf(buf, "%s\n", tz->name);
> > +}
> > +
> > +static ssize_t
> >  sensor_name_show(struct device *dev, struct device_attribute *attr, char
> *buf)
> >  {
> >         struct thermal_sensor *ts = to_thermal_sensor(dev);
> > @@ -772,6 +828,8 @@ static DEVICE_ATTR(policy, S_IRUGO | S_IWUSR,
> policy_show, policy_store);
> >  static DEVICE_ATTR(sensor_name, 0444, sensor_name_show, NULL);
> >  static DEVICE_ATTR(temp_input, 0444, sensor_temp_show, NULL);
> >
> > +static DEVICE_ATTR(zone_name, 0444, zone_name_show, NULL);
> > +
> >  /* sys I/F for cooling device */
> >  #define to_cooling_device(_dev)        \
> >         container_of(_dev, struct thermal_cooling_device, device)
> > @@ -1557,6 +1615,146 @@ static void remove_trip_attrs(struct
> thermal_zone_device *tz)
> >         kfree(tz->trip_hyst_attrs);
> >  }
> >
> > +struct thermal_zone *create_thermal_zone(const char *name, void
> *devdata)
> > +{
> > +       struct thermal_zone *tz;
> > +       int ret;
> > +
> > +       if (!name || (name && strlen(name) >= THERMAL_NAME_LENGTH))
> > +               return ERR_PTR(-EINVAL);
> > +
> > +       tz = kzalloc(sizeof(*tz), GFP_KERNEL);
> > +       if (!tz)
> > +               return ERR_PTR(-ENOMEM);
> > +
> > +       idr_init(&tz->idr);
> > +       ret = get_idr(&thermal_zone_idr, &thermal_idr_lock, &tz->id);
> > +       if (ret)
> > +               goto exit_free;
> > +
> > +       strcpy(tz->name, name);
> > +       tz->devdata = devdata;
> > +       tz->device.class = &thermal_class;
> > +
> > +       dev_set_name(&tz->device, "zone%d", tz->id);
> > +       ret = device_register(&tz->device);
> > +       if (ret)
> > +               goto exit_idr;
> > +
> > +       ret = device_create_file(&tz->device, &dev_attr_zone_name);
> > +       if (ret)
> > +               goto exit_unregister;
> > +
> > +       /* Add this zone to the global list of thermal zones */
> > +       mutex_lock(&tz_list_lock);
> > +       list_add_tail(&tz->node, &thermal_zone_list);
> > +       mutex_unlock(&tz_list_lock);
> > +       return tz;
> > +
> > +exit_unregister:
> > +       device_unregister(&tz->device);
> > +exit_idr:
> > +       release_idr(&thermal_zone_idr, &thermal_idr_lock, tz->id);
> > +exit_free:
> > +       kfree(tz);
> > +       return ERR_PTR(ret);
> > +}
> > +EXPORT_SYMBOL(create_thermal_zone);
> > +
> > +void remove_thermal_zone(struct thermal_zone *tz)
> > +{
> > +       struct thermal_zone *pos, *next;
> > +       bool found = false;
> > +
> > +       if (!tz)
> > +               return;
> > +
> > +       mutex_lock(&tz_list_lock);
> > +
> > +       list_for_each_entry_safe(pos, next, &thermal_zone_list, node) {
> > +               if (pos == tz) {
> > +                       list_del(&tz->node);
> > +                       found = true;
> > +                       break;
> > +               }
> > +       }
> > +
> > +       if (!found)
> > +               goto exit;
> > +
> > +       device_remove_file(&tz->device, &dev_attr_zone_name);
> > +
> > +       release_idr(&thermal_zone_idr, &thermal_idr_lock, tz->id);
> > +       idr_destroy(&tz->idr);
> > +
> > +       device_unregister(&tz->device);
> > +       kfree(tz);
> > +exit:
> > +       mutex_unlock(&tz_list_lock);
> > +       return;
> > +}
> > +EXPORT_SYMBOL(remove_thermal_zone);
> > +
> > +struct thermal_sensor *get_sensor_by_name(const char *name)
> > +{
> > +       struct thermal_sensor *pos;
> > +       struct thermal_sensor *ts = NULL;
> > +
> > +       mutex_lock(&ts_list_lock);
> > +       for_each_thermal_sensor(pos) {
> > +               if (!strnicmp(pos->name, name, THERMAL_NAME_LENGTH)) {
> > +                       ts = pos;
> > +                       break;
> > +               }
> > +       }
> > +       mutex_unlock(&ts_list_lock);
> > +       return ts;
> > +}
> > +EXPORT_SYMBOL(get_sensor_by_name);
> > +
> > +int add_sensor_to_zone_by_name(struct thermal_zone *tz, const char
> *name)
> > +{
> > +       int ret;
> > +       struct thermal_sensor *ts = get_sensor_by_name(name);
> > +
> > +       if (!tz || !ts)
> > +               return -EINVAL;
> > +
> > +       mutex_lock(&tz_list_lock);
> > +
> > +       /* Ensure we are not adding the same sensor again!! */
> > +       ret = get_sensor_indx(tz, ts);
> > +       if (ret >= 0) {
> > +               ret = -EEXIST;
> > +               goto exit_zone;
> > +       }
> > +
> > +       mutex_lock(&ts_list_lock);
> > +
> > +       ret = sysfs_create_link(&tz->device.kobj, &ts->device.kobj,
> > +                               kobject_name(&ts->device.kobj));
> > +       if (ret)
> > +               goto exit_sensor;
> > +
> > +       tz->sensors[tz->sensor_indx++] = ts;
> > +
> > +exit_sensor:
> > +       mutex_unlock(&ts_list_lock);
> > +exit_zone:
> > +       mutex_unlock(&tz_list_lock);
> > +       return ret;
> > +}
> > +EXPORT_SYMBOL(add_sensor_to_zone_by_name);
> > +
> > +int add_sensor_to_zone(struct thermal_zone *tz, struct thermal_sensor
> *ts)
> > +{
> > +       if (!tz || !ts)
> > +               return -EINVAL;
> > +
> > +       return add_sensor_to_zone_by_name(tz, ts->name);
> > +}
> > +EXPORT_SYMBOL(add_sensor_to_zone);
> > +
> >  /**
> >   * thermal_sensor_register - register a new thermal sensor
> >   * @name:      name of the thermal sensor
> > @@ -1624,6 +1822,7 @@ EXPORT_SYMBOL(thermal_sensor_register);
> >  void thermal_sensor_unregister(struct thermal_sensor *ts)
> >  {
> >         int i;
> > +       struct thermal_zone *tz;
> >         struct thermal_sensor *pos, *next;
> >         bool found = false;
> >
> > @@ -1643,6 +1842,13 @@ void thermal_sensor_unregister(struct
> thermal_sensor *ts)
> >         if (!found)
> >                 return;
> >
> > +       mutex_lock(&tz_list_lock);
> > +
> > +       for_each_thermal_zone(tz)
> > +               remove_sensor_from_zone(tz, ts);
> > +
> > +       mutex_unlock(&tz_list_lock);
> > +
> >         for (i = 0; i < ts->thresholds; i++)
> >                 device_remove_file(&ts->device, &ts->thresh_attrs[i].attr);
> >
> > diff --git a/include/linux/thermal.h b/include/linux/thermal.h
> > index e2f85ec..38438be 100644
> > --- a/include/linux/thermal.h
> > +++ b/include/linux/thermal.h
> > @@ -49,6 +49,11 @@
> >  /* Default Thermal Governor: Does Linear Throttling */
> >  #define DEFAULT_THERMAL_GOVERNOR       "step_wise"
> >
> > +/* Maximum number of sensors, allowed in a thermal zone
> > + * We will start with 5, and increase if needed.
> > + */
> > +#define MAX_SENSORS_PER_ZONE           5
> > +
> >  struct thermal_sensor;
> >  struct thermal_zone_device;
> >  struct thermal_cooling_device;
> > @@ -191,6 +196,21 @@ struct thermal_zone_device {
> >         struct delayed_work poll_queue;
> >  };
> >
> > +struct thermal_zone {
> > +       char name[THERMAL_NAME_LENGTH];
> > +       int id;
> > +       void *devdata;
> > +       struct thermal_zone *ops;
> What is this, thermal_zone_device_ops? and how to initialize this ops?

oh, Not required, for now. Will remove it..
Good catch :-)

Thanks,
Durga
> 
> > +       struct thermal_governor *governor;
> > +       struct idr idr;
> > +       struct device device;
> > +       struct list_head node;
> > +
> > +       /* Sensor level information */
> > +       int sensor_indx; /* index into 'sensors' array */
> > +       struct thermal_sensor *sensors[MAX_SENSORS_PER_ZONE];
> > +};
> > +
> >  /* Structure that holds thermal governor information */
> >  struct thermal_governor {
> >         char name[THERMAL_NAME_LENGTH];
> > @@ -264,6 +284,11 @@ struct thermal_sensor
> *thermal_sensor_register(const char *,
> >  void thermal_sensor_unregister(struct thermal_sensor *);
> >  int enable_sensor_thresholds(struct thermal_sensor *, int);
> >
> > +struct thermal_zone *create_thermal_zone(const char *, void *);
> > +void remove_thermal_zone(struct thermal_zone *);
> > +int add_sensor_to_zone(struct thermal_zone *, struct thermal_sensor
> *);
> > +int add_sensor_to_zone_by_name(struct thermal_zone *, const char *);
> > +
> >  #ifdef CONFIG_NET
> >  extern int thermal_generate_netlink_event(u32 orig, enum events
> event);
> >  #else
> > --
> > 1.7.9.5
> >

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

* Re: [RFC PATCH 2/7] Thermal: Create zone level APIs
  2012-12-03  7:47     ` R, Durgadoss
@ 2012-12-03  8:21       ` Hongbo Zhang
  2012-12-03  9:51         ` R, Durgadoss
  0 siblings, 1 reply; 27+ messages in thread
From: Hongbo Zhang @ 2012-12-03  8:21 UTC (permalink / raw)
  To: R, Durgadoss
  Cc: Zhang, Rui, linux-pm, wni, eduardo.valentin, amit.kachhap, sachin.kamat

On 3 December 2012 15:47, R, Durgadoss <durgadoss.r@intel.com> wrote:
>
>
>> -----Original Message-----
>> From: Hongbo Zhang [mailto:hongbo.zhang@linaro.org]
>> Sent: Monday, December 03, 2012 1:13 PM
>> To: R, Durgadoss
>> Cc: Zhang, Rui; linux-pm@vger.kernel.org; wni@nvidia.com;
>> eduardo.valentin@ti.com; amit.kachhap@linaro.org;
>> sachin.kamat@linaro.org
>> Subject: Re: [RFC PATCH 2/7] Thermal: Create zone level APIs
>>
>> On 17 November 2012 18:45, Durgadoss R <durgadoss.r@intel.com> wrote:
>> > This patch adds a new thermal_zone structure to
>> > thermal.h. Also, adds zone level APIs to the thermal
>> > framework.
>> >
>> > Signed-off-by: Durgadoss R <durgadoss.r@intel.com>
>> > ---
>> >  drivers/thermal/thermal_sys.c |  206
>> +++++++++++++++++++++++++++++++++++++++++
>> >  include/linux/thermal.h       |   25 +++++
>> >  2 files changed, 231 insertions(+)
>> >
>> > diff --git a/drivers/thermal/thermal_sys.c b/drivers/thermal/thermal_sys.c
>> > index e726c8b..9d386d7 100644
>> > --- a/drivers/thermal/thermal_sys.c
>> > +++ b/drivers/thermal/thermal_sys.c
>> > @@ -44,19 +44,28 @@ MODULE_DESCRIPTION("Generic thermal
>> management sysfs support");
>> >  MODULE_LICENSE("GPL");
>> >
>> >  static DEFINE_IDR(thermal_tz_idr);
>> > +static DEFINE_IDR(thermal_zone_idr);
>> >  static DEFINE_IDR(thermal_cdev_idr);
>> >  static DEFINE_IDR(thermal_sensor_idr);
>> >  static DEFINE_MUTEX(thermal_idr_lock);
>> >
>> >  static LIST_HEAD(thermal_tz_list);
>> >  static LIST_HEAD(thermal_sensor_list);
>> > +static LIST_HEAD(thermal_zone_list);
>> >  static LIST_HEAD(thermal_cdev_list);
>> >  static LIST_HEAD(thermal_governor_list);
>> >
>> >  static DEFINE_MUTEX(thermal_list_lock);
>> >  static DEFINE_MUTEX(ts_list_lock);
>> > +static DEFINE_MUTEX(tz_list_lock);
>> >  static DEFINE_MUTEX(thermal_governor_lock);
>> >
>> > +#define for_each_thermal_sensor(pos) \
>> > +       list_for_each_entry(pos, &thermal_sensor_list, node)
>> > +
>> > +#define for_each_thermal_zone(pos) \
>> > +       list_for_each_entry(pos, &thermal_zone_list, node)
>> > +
>> >  static struct thermal_governor *__find_governor(const char *name)
>> >  {
>> >         struct thermal_governor *pos;
>> > @@ -419,15 +428,62 @@ static void thermal_zone_device_check(struct
>> work_struct *work)
>> >         thermal_zone_device_update(tz);
>> >  }
>> >
>> > +static int get_sensor_indx(struct thermal_zone *tz, struct thermal_sensor
>> *ts)
>> > +{
>> > +       int i, indx = -EINVAL;
>> > +
>> > +       if (!tz || !ts)
>> > +               return -EINVAL;
>> > +
>> > +       mutex_lock(&ts_list_lock);
>> > +       for (i = 0; i < tz->sensor_indx; i++) {
>> > +               if (tz->sensors[i] == ts) {
>> > +                       indx = i;
>> > +                       break;
>> > +               }
>> > +       }
>> > +       mutex_unlock(&ts_list_lock);
>> > +       return indx;
>> > +}
>> > +
>> > +static void remove_sensor_from_zone(struct thermal_zone *tz,
>> > +                               struct thermal_sensor *ts)
>> > +{
>> > +       int indx, j;
>> > +
>> > +       indx = get_sensor_indx(tz, ts);
>> > +       if (indx < 0)
>> > +               return;
>> > +
>> > +       sysfs_remove_link(&tz->device.kobj, kobject_name(&ts-
>> >device.kobj));
>> > +
>> > +       /* Shift the entries in the tz->sensors array */
>> > +       for (j = indx; j < MAX_SENSORS_PER_ZONE - 1; j++)
>> > +               tz->sensors[j] = tz->sensors[j + 1];
>> > +
>> > +       tz->sensor_indx--;
>> > +}
>> > +
>> >  /* sys I/F for thermal zone */
>> >
>> >  #define to_thermal_zone(_dev) \
>> >         container_of(_dev, struct thermal_zone_device, device)
>> >
>> > +#define to_zone(_dev) \
>> > +       container_of(_dev, struct thermal_zone, device)
>> > +
>> >  #define to_thermal_sensor(_dev) \
>> >         container_of(_dev, struct thermal_sensor, device)
>> >
>> >  static ssize_t
>> > +zone_name_show(struct device *dev, struct device_attribute *attr, char
>> *buf)
>> > +{
>> > +       struct thermal_zone *tz = to_zone(dev);
>> > +
>> > +       return sprintf(buf, "%s\n", tz->name);
>> > +}
>> > +
>> > +static ssize_t
>> >  sensor_name_show(struct device *dev, struct device_attribute *attr, char
>> *buf)
>> >  {
>> >         struct thermal_sensor *ts = to_thermal_sensor(dev);
>> > @@ -772,6 +828,8 @@ static DEVICE_ATTR(policy, S_IRUGO | S_IWUSR,
>> policy_show, policy_store);
>> >  static DEVICE_ATTR(sensor_name, 0444, sensor_name_show, NULL);
>> >  static DEVICE_ATTR(temp_input, 0444, sensor_temp_show, NULL);
>> >
>> > +static DEVICE_ATTR(zone_name, 0444, zone_name_show, NULL);
>> > +
>> >  /* sys I/F for cooling device */
>> >  #define to_cooling_device(_dev)        \
>> >         container_of(_dev, struct thermal_cooling_device, device)
>> > @@ -1557,6 +1615,146 @@ static void remove_trip_attrs(struct
>> thermal_zone_device *tz)
>> >         kfree(tz->trip_hyst_attrs);
>> >  }
>> >
>> > +struct thermal_zone *create_thermal_zone(const char *name, void
>> *devdata)
>> > +{
>> > +       struct thermal_zone *tz;
>> > +       int ret;
>> > +
>> > +       if (!name || (name && strlen(name) >= THERMAL_NAME_LENGTH))
>> > +               return ERR_PTR(-EINVAL);
>> > +
>> > +       tz = kzalloc(sizeof(*tz), GFP_KERNEL);
>> > +       if (!tz)
>> > +               return ERR_PTR(-ENOMEM);
>> > +
>> > +       idr_init(&tz->idr);
>> > +       ret = get_idr(&thermal_zone_idr, &thermal_idr_lock, &tz->id);
>> > +       if (ret)
>> > +               goto exit_free;
>> > +
>> > +       strcpy(tz->name, name);
>> > +       tz->devdata = devdata;
>> > +       tz->device.class = &thermal_class;
>> > +
>> > +       dev_set_name(&tz->device, "zone%d", tz->id);
>> > +       ret = device_register(&tz->device);
>> > +       if (ret)
>> > +               goto exit_idr;
>> > +
>> > +       ret = device_create_file(&tz->device, &dev_attr_zone_name);
>> > +       if (ret)
>> > +               goto exit_unregister;
>> > +
>> > +       /* Add this zone to the global list of thermal zones */
>> > +       mutex_lock(&tz_list_lock);
>> > +       list_add_tail(&tz->node, &thermal_zone_list);
>> > +       mutex_unlock(&tz_list_lock);
>> > +       return tz;
>> > +
>> > +exit_unregister:
>> > +       device_unregister(&tz->device);
>> > +exit_idr:
>> > +       release_idr(&thermal_zone_idr, &thermal_idr_lock, tz->id);
>> > +exit_free:
>> > +       kfree(tz);
>> > +       return ERR_PTR(ret);
>> > +}
>> > +EXPORT_SYMBOL(create_thermal_zone);
>> > +
>> > +void remove_thermal_zone(struct thermal_zone *tz)
>> > +{
>> > +       struct thermal_zone *pos, *next;
>> > +       bool found = false;
>> > +
>> > +       if (!tz)
>> > +               return;
>> > +
>> > +       mutex_lock(&tz_list_lock);
>> > +
>> > +       list_for_each_entry_safe(pos, next, &thermal_zone_list, node) {
>> > +               if (pos == tz) {
>> > +                       list_del(&tz->node);
>> > +                       found = true;
>> > +                       break;
>> > +               }
>> > +       }
>> > +
>> > +       if (!found)
>> > +               goto exit;
>> > +
>> > +       device_remove_file(&tz->device, &dev_attr_zone_name);
>> > +
>> > +       release_idr(&thermal_zone_idr, &thermal_idr_lock, tz->id);
>> > +       idr_destroy(&tz->idr);
>> > +
>> > +       device_unregister(&tz->device);
>> > +       kfree(tz);
>> > +exit:
>> > +       mutex_unlock(&tz_list_lock);
>> > +       return;
>> > +}
>> > +EXPORT_SYMBOL(remove_thermal_zone);
>> > +
>> > +struct thermal_sensor *get_sensor_by_name(const char *name)
>> > +{
>> > +       struct thermal_sensor *pos;
>> > +       struct thermal_sensor *ts = NULL;
>> > +
>> > +       mutex_lock(&ts_list_lock);
>> > +       for_each_thermal_sensor(pos) {
>> > +               if (!strnicmp(pos->name, name, THERMAL_NAME_LENGTH)) {
>> > +                       ts = pos;
>> > +                       break;
>> > +               }
>> > +       }
>> > +       mutex_unlock(&ts_list_lock);
>> > +       return ts;
>> > +}
>> > +EXPORT_SYMBOL(get_sensor_by_name);
>> > +
>> > +int add_sensor_to_zone_by_name(struct thermal_zone *tz, const char
>> *name)
>> > +{
>> > +       int ret;
>> > +       struct thermal_sensor *ts = get_sensor_by_name(name);
>> > +
>> > +       if (!tz || !ts)
>> > +               return -EINVAL;
>> > +
>> > +       mutex_lock(&tz_list_lock);
>> > +
>> > +       /* Ensure we are not adding the same sensor again!! */
>> > +       ret = get_sensor_indx(tz, ts);
>> > +       if (ret >= 0) {
>> > +               ret = -EEXIST;
>> > +               goto exit_zone;
>> > +       }
>> > +
>> > +       mutex_lock(&ts_list_lock);
>> > +
>> > +       ret = sysfs_create_link(&tz->device.kobj, &ts->device.kobj,
>> > +                               kobject_name(&ts->device.kobj));
>> > +       if (ret)
>> > +               goto exit_sensor;
>> > +
>> > +       tz->sensors[tz->sensor_indx++] = ts;
>> > +
>> > +exit_sensor:
>> > +       mutex_unlock(&ts_list_lock);
>> > +exit_zone:
>> > +       mutex_unlock(&tz_list_lock);
>> > +       return ret;
>> > +}
>> > +EXPORT_SYMBOL(add_sensor_to_zone_by_name);
>> > +
>> > +int add_sensor_to_zone(struct thermal_zone *tz, struct thermal_sensor
>> *ts)
>> > +{
>> > +       if (!tz || !ts)
>> > +               return -EINVAL;
>> > +
>> > +       return add_sensor_to_zone_by_name(tz, ts->name);
>> > +}
>> > +EXPORT_SYMBOL(add_sensor_to_zone);
>> > +
>> >  /**
>> >   * thermal_sensor_register - register a new thermal sensor
>> >   * @name:      name of the thermal sensor
>> > @@ -1624,6 +1822,7 @@ EXPORT_SYMBOL(thermal_sensor_register);
>> >  void thermal_sensor_unregister(struct thermal_sensor *ts)
>> >  {
>> >         int i;
>> > +       struct thermal_zone *tz;
>> >         struct thermal_sensor *pos, *next;
>> >         bool found = false;
>> >
>> > @@ -1643,6 +1842,13 @@ void thermal_sensor_unregister(struct
>> thermal_sensor *ts)
>> >         if (!found)
>> >                 return;
>> >
>> > +       mutex_lock(&tz_list_lock);
>> > +
>> > +       for_each_thermal_zone(tz)
>> > +               remove_sensor_from_zone(tz, ts);
>> > +
>> > +       mutex_unlock(&tz_list_lock);
>> > +
>> >         for (i = 0; i < ts->thresholds; i++)
>> >                 device_remove_file(&ts->device, &ts->thresh_attrs[i].attr);
>> >
>> > diff --git a/include/linux/thermal.h b/include/linux/thermal.h
>> > index e2f85ec..38438be 100644
>> > --- a/include/linux/thermal.h
>> > +++ b/include/linux/thermal.h
>> > @@ -49,6 +49,11 @@
>> >  /* Default Thermal Governor: Does Linear Throttling */
>> >  #define DEFAULT_THERMAL_GOVERNOR       "step_wise"
>> >
>> > +/* Maximum number of sensors, allowed in a thermal zone
>> > + * We will start with 5, and increase if needed.
>> > + */
>> > +#define MAX_SENSORS_PER_ZONE           5
>> > +
>> >  struct thermal_sensor;
>> >  struct thermal_zone_device;
>> >  struct thermal_cooling_device;
>> > @@ -191,6 +196,21 @@ struct thermal_zone_device {
>> >         struct delayed_work poll_queue;
>> >  };
>> >
>> > +struct thermal_zone {
>> > +       char name[THERMAL_NAME_LENGTH];
>> > +       int id;
>> > +       void *devdata;
>> > +       struct thermal_zone *ops;
>> What is this, thermal_zone_device_ops? and how to initialize this ops?
>
> oh, Not required, for now. Will remove it..
> Good catch :-)

I am still confused a bit.
Is this thermal_zone going to take the place of the old thermal_zone_device?
If yes, which functions/callbacks are used to access
thermal_zone->trip[] like the old get_trip_*?

>
> Thanks,
> Durga
>>
>> > +       struct thermal_governor *governor;
>> > +       struct idr idr;
>> > +       struct device device;
>> > +       struct list_head node;
>> > +
>> > +       /* Sensor level information */
>> > +       int sensor_indx; /* index into 'sensors' array */
>> > +       struct thermal_sensor *sensors[MAX_SENSORS_PER_ZONE];
>> > +};
>> > +
>> >  /* Structure that holds thermal governor information */
>> >  struct thermal_governor {
>> >         char name[THERMAL_NAME_LENGTH];
>> > @@ -264,6 +284,11 @@ struct thermal_sensor
>> *thermal_sensor_register(const char *,
>> >  void thermal_sensor_unregister(struct thermal_sensor *);
>> >  int enable_sensor_thresholds(struct thermal_sensor *, int);
>> >
>> > +struct thermal_zone *create_thermal_zone(const char *, void *);
>> > +void remove_thermal_zone(struct thermal_zone *);
>> > +int add_sensor_to_zone(struct thermal_zone *, struct thermal_sensor
>> *);
>> > +int add_sensor_to_zone_by_name(struct thermal_zone *, const char *);
>> > +
>> >  #ifdef CONFIG_NET
>> >  extern int thermal_generate_netlink_event(u32 orig, enum events
>> event);
>> >  #else
>> > --
>> > 1.7.9.5
>> >

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

* Re: [RFC PATCH 0/7] Support for Multiple sensors per zone
  2012-11-17 10:45 [RFC PATCH 0/7] Support for Multiple sensors per zone Durgadoss R
                   ` (6 preceding siblings ...)
  2012-11-17 10:45 ` [RFC PATCH 7/7] Thermal: Dummy driver used for testing Durgadoss R
@ 2012-12-03  9:01 ` Hongbo Zhang
  2012-12-03  9:56   ` R, Durgadoss
  2013-01-02 15:48 ` Eduardo Valentin
  8 siblings, 1 reply; 27+ messages in thread
From: Hongbo Zhang @ 2012-12-03  9:01 UTC (permalink / raw)
  To: Durgadoss R
  Cc: rui.zhang, linux-pm, wni, eduardo.valentin, amit.kachhap, sachin.kamat

On 17 November 2012 18:45, Durgadoss R <durgadoss.r@intel.com> wrote:
> This patch series attempts to add support for multiple
> sensors per zone. The work is based on the Thermal discussion
> happened in plumbers conference 2012, here:
> http://www.linuxplumbersconf.org/2012/schedule/
> Title: "Enhancing the Thermal Management Infrastructure in Linux"
>
> The intention is to make it easy for generic sensor drivers
> to register with the framework, and let them participate in
> platform thermal management. Another goal is to expose the
> binding information in a consistent way so that user space
> can consume the information and potentially manage platform thermals.
>
> This series contains 7 patches:
> Patch 1/7: Creates new sensor level APIs
> Patch 2/7: Creates new zone level APIs. The existing tzd structure is
>            kept as such for clarity and compatibility purposes.
> Patch 3/7: Creates functions to add/remove a cdev to/from a zone. The
>            existing tcd structure need not be modified.
> Patch 4/7: Adds a thermal_trip sysfs node, which exposes various trip
>            points for all sensors present in a zone.
> Patch 5/7: Adds a thermal_map sysfs node. It is a compact representation
>            of the binding relationship between a sensor and a cdev,
>            within a zone.
> Patch 6/7: Creates Documentation for the new APIs. A new file is
>            created for clarity. Final goal is to merge with the existing
>            file or refactor the files, as whatever seems appropriate.
> Patch 7/7: A dummy driver that can be used for testing. This is not for merge.
>
> Next steps:
Do you have milestone?
Because new thermal driver writers are wondering if to use the old
framework or can wait the new one.
>  1. Move all the existing drivers to the new implementation model.
>     Help welcomed from individual driver authors/maintainers for this.
>  2. Make the thermal governors work with this new model.
>  3. Remove old/unused code from thermal_sys.c.
>  4. Add more detailed documentation
>
>  I didn't want to submit patches for all these in one-go, since it
>  might end-up being difficult to comprehend, besides delaying the
>  review process. The other obvious reason being I cannot test all
>  the changes on various drivers for 1.
>
>  All these patches have been tested on a Core-i5 desktop running
>  ubuntu 12.04 and an atom notebook running ubuntu 11.10.
>  Kindly help review.
>
> Durgadoss R (7):
>   Thermal: Create sensor level APIs
>   Thermal: Create zone level APIs
>   Thermal: Add APIs to bind cdev to new zone structure
>   Thermal: Add Thermal_trip sysfs node
>   Thermal: Add 'thermal_map' sysfs node
>   Thermal: Add Documentation to new APIs
>   Thermal: Dummy driver used for testing
>
>  Documentation/thermal/sysfs-api2.txt |  213 ++++++++
>  drivers/thermal/Kconfig              |    5 +
>  drivers/thermal/Makefile             |    3 +
>  drivers/thermal/thermal_sys.c        |  915 ++++++++++++++++++++++++++++++++++
>  drivers/thermal/thermal_test.c       |  321 ++++++++++++
>  include/linux/thermal.h              |  118 +++++
>  6 files changed, 1575 insertions(+)
>  create mode 100644 Documentation/thermal/sysfs-api2.txt
>  create mode 100644 drivers/thermal/thermal_test.c
>
> --
> 1.7.9.5
>

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

* RE: [RFC PATCH 2/7] Thermal: Create zone level APIs
  2012-12-03  8:21       ` Hongbo Zhang
@ 2012-12-03  9:51         ` R, Durgadoss
  2012-12-03 11:50           ` Hongbo Zhang
  0 siblings, 1 reply; 27+ messages in thread
From: R, Durgadoss @ 2012-12-03  9:51 UTC (permalink / raw)
  To: Hongbo Zhang
  Cc: Zhang, Rui, linux-pm, wni, eduardo.valentin, amit.kachhap, sachin.kamat



> -----Original Message-----
> From: Hongbo Zhang [mailto:hongbo.zhang@linaro.org]
> Sent: Monday, December 03, 2012 1:51 PM
> To: R, Durgadoss
> Cc: Zhang, Rui; linux-pm@vger.kernel.org; wni@nvidia.com;
> eduardo.valentin@ti.com; amit.kachhap@linaro.org;
> sachin.kamat@linaro.org
> Subject: Re: [RFC PATCH 2/7] Thermal: Create zone level APIs
> 
> On 3 December 2012 15:47, R, Durgadoss <durgadoss.r@intel.com> wrote:
> >
> >
> >> -----Original Message-----
> >> From: Hongbo Zhang [mailto:hongbo.zhang@linaro.org]
> >> Sent: Monday, December 03, 2012 1:13 PM
> >> To: R, Durgadoss
> >> Cc: Zhang, Rui; linux-pm@vger.kernel.org; wni@nvidia.com;
> >> eduardo.valentin@ti.com; amit.kachhap@linaro.org;
> >> sachin.kamat@linaro.org
> >> Subject: Re: [RFC PATCH 2/7] Thermal: Create zone level APIs
> >>
> >> On 17 November 2012 18:45, Durgadoss R <durgadoss.r@intel.com>
> wrote:
> >> > This patch adds a new thermal_zone structure to
> >> > thermal.h. Also, adds zone level APIs to the thermal
> >> > framework.
> >> >
> >> > Signed-off-by: Durgadoss R <durgadoss.r@intel.com>
> >> > ---
> >> >  drivers/thermal/thermal_sys.c |  206
> >> +++++++++++++++++++++++++++++++++++++++++
> >> >  include/linux/thermal.h       |   25 +++++
> >> >  2 files changed, 231 insertions(+)
> >> >
> >> > diff --git a/drivers/thermal/thermal_sys.c
> b/drivers/thermal/thermal_sys.c
> >> > index e726c8b..9d386d7 100644
> >> > --- a/drivers/thermal/thermal_sys.c
> >> > +++ b/drivers/thermal/thermal_sys.c
> >> > @@ -44,19 +44,28 @@ MODULE_DESCRIPTION("Generic thermal
> >> management sysfs support");
> >> >  MODULE_LICENSE("GPL");
> >> >
> >> >  static DEFINE_IDR(thermal_tz_idr);
> >> > +static DEFINE_IDR(thermal_zone_idr);
> >> >  static DEFINE_IDR(thermal_cdev_idr);
> >> >  static DEFINE_IDR(thermal_sensor_idr);
> >> >  static DEFINE_MUTEX(thermal_idr_lock);
> >> >
> >> >  static LIST_HEAD(thermal_tz_list);
> >> >  static LIST_HEAD(thermal_sensor_list);
> >> > +static LIST_HEAD(thermal_zone_list);
> >> >  static LIST_HEAD(thermal_cdev_list);
> >> >  static LIST_HEAD(thermal_governor_list);
> >> >
> >> >  static DEFINE_MUTEX(thermal_list_lock);
> >> >  static DEFINE_MUTEX(ts_list_lock);
> >> > +static DEFINE_MUTEX(tz_list_lock);
> >> >  static DEFINE_MUTEX(thermal_governor_lock);
> >> >
> >> > +#define for_each_thermal_sensor(pos) \
> >> > +       list_for_each_entry(pos, &thermal_sensor_list, node)
> >> > +
> >> > +#define for_each_thermal_zone(pos) \
> >> > +       list_for_each_entry(pos, &thermal_zone_list, node)
> >> > +
> >> >  static struct thermal_governor *__find_governor(const char *name)
> >> >  {
> >> >         struct thermal_governor *pos;
> >> > @@ -419,15 +428,62 @@ static void thermal_zone_device_check(struct
> >> work_struct *work)
> >> >         thermal_zone_device_update(tz);
> >> >  }
> >> >
> >> > +static int get_sensor_indx(struct thermal_zone *tz, struct
> thermal_sensor
> >> *ts)
> >> > +{
> >> > +       int i, indx = -EINVAL;
> >> > +
> >> > +       if (!tz || !ts)
> >> > +               return -EINVAL;
> >> > +
> >> > +       mutex_lock(&ts_list_lock);
> >> > +       for (i = 0; i < tz->sensor_indx; i++) {
> >> > +               if (tz->sensors[i] == ts) {
> >> > +                       indx = i;
> >> > +                       break;
> >> > +               }
> >> > +       }
> >> > +       mutex_unlock(&ts_list_lock);
> >> > +       return indx;
> >> > +}
> >> > +
> >> > +static void remove_sensor_from_zone(struct thermal_zone *tz,
> >> > +                               struct thermal_sensor *ts)
> >> > +{
> >> > +       int indx, j;
> >> > +
> >> > +       indx = get_sensor_indx(tz, ts);
> >> > +       if (indx < 0)
> >> > +               return;
> >> > +
> >> > +       sysfs_remove_link(&tz->device.kobj, kobject_name(&ts-
> >> >device.kobj));
> >> > +
> >> > +       /* Shift the entries in the tz->sensors array */
> >> > +       for (j = indx; j < MAX_SENSORS_PER_ZONE - 1; j++)
> >> > +               tz->sensors[j] = tz->sensors[j + 1];
> >> > +
> >> > +       tz->sensor_indx--;
> >> > +}
> >> > +
> >> >  /* sys I/F for thermal zone */
> >> >
> >> >  #define to_thermal_zone(_dev) \
> >> >         container_of(_dev, struct thermal_zone_device, device)
> >> >
> >> > +#define to_zone(_dev) \
> >> > +       container_of(_dev, struct thermal_zone, device)
> >> > +
> >> >  #define to_thermal_sensor(_dev) \
> >> >         container_of(_dev, struct thermal_sensor, device)
> >> >
> >> >  static ssize_t
> >> > +zone_name_show(struct device *dev, struct device_attribute *attr,
> char
> >> *buf)
> >> > +{
> >> > +       struct thermal_zone *tz = to_zone(dev);
> >> > +
> >> > +       return sprintf(buf, "%s\n", tz->name);
> >> > +}
> >> > +
> >> > +static ssize_t
> >> >  sensor_name_show(struct device *dev, struct device_attribute *attr,
> char
> >> *buf)
> >> >  {
> >> >         struct thermal_sensor *ts = to_thermal_sensor(dev);
> >> > @@ -772,6 +828,8 @@ static DEVICE_ATTR(policy, S_IRUGO | S_IWUSR,
> >> policy_show, policy_store);
> >> >  static DEVICE_ATTR(sensor_name, 0444, sensor_name_show, NULL);
> >> >  static DEVICE_ATTR(temp_input, 0444, sensor_temp_show, NULL);
> >> >
> >> > +static DEVICE_ATTR(zone_name, 0444, zone_name_show, NULL);
> >> > +
> >> >  /* sys I/F for cooling device */
> >> >  #define to_cooling_device(_dev)        \
> >> >         container_of(_dev, struct thermal_cooling_device, device)
> >> > @@ -1557,6 +1615,146 @@ static void remove_trip_attrs(struct
> >> thermal_zone_device *tz)
> >> >         kfree(tz->trip_hyst_attrs);
> >> >  }
> >> >
> >> > +struct thermal_zone *create_thermal_zone(const char *name, void
> >> *devdata)
> >> > +{
> >> > +       struct thermal_zone *tz;
> >> > +       int ret;
> >> > +
> >> > +       if (!name || (name && strlen(name) >=
> THERMAL_NAME_LENGTH))
> >> > +               return ERR_PTR(-EINVAL);
> >> > +
> >> > +       tz = kzalloc(sizeof(*tz), GFP_KERNEL);
> >> > +       if (!tz)
> >> > +               return ERR_PTR(-ENOMEM);
> >> > +
> >> > +       idr_init(&tz->idr);
> >> > +       ret = get_idr(&thermal_zone_idr, &thermal_idr_lock, &tz->id);
> >> > +       if (ret)
> >> > +               goto exit_free;
> >> > +
> >> > +       strcpy(tz->name, name);
> >> > +       tz->devdata = devdata;
> >> > +       tz->device.class = &thermal_class;
> >> > +
> >> > +       dev_set_name(&tz->device, "zone%d", tz->id);
> >> > +       ret = device_register(&tz->device);
> >> > +       if (ret)
> >> > +               goto exit_idr;
> >> > +
> >> > +       ret = device_create_file(&tz->device, &dev_attr_zone_name);
> >> > +       if (ret)
> >> > +               goto exit_unregister;
> >> > +
> >> > +       /* Add this zone to the global list of thermal zones */
> >> > +       mutex_lock(&tz_list_lock);
> >> > +       list_add_tail(&tz->node, &thermal_zone_list);
> >> > +       mutex_unlock(&tz_list_lock);
> >> > +       return tz;
> >> > +
> >> > +exit_unregister:
> >> > +       device_unregister(&tz->device);
> >> > +exit_idr:
> >> > +       release_idr(&thermal_zone_idr, &thermal_idr_lock, tz->id);
> >> > +exit_free:
> >> > +       kfree(tz);
> >> > +       return ERR_PTR(ret);
> >> > +}
> >> > +EXPORT_SYMBOL(create_thermal_zone);
> >> > +
> >> > +void remove_thermal_zone(struct thermal_zone *tz)
> >> > +{
> >> > +       struct thermal_zone *pos, *next;
> >> > +       bool found = false;
> >> > +
> >> > +       if (!tz)
> >> > +               return;
> >> > +
> >> > +       mutex_lock(&tz_list_lock);
> >> > +
> >> > +       list_for_each_entry_safe(pos, next, &thermal_zone_list, node) {
> >> > +               if (pos == tz) {
> >> > +                       list_del(&tz->node);
> >> > +                       found = true;
> >> > +                       break;
> >> > +               }
> >> > +       }
> >> > +
> >> > +       if (!found)
> >> > +               goto exit;
> >> > +
> >> > +       device_remove_file(&tz->device, &dev_attr_zone_name);
> >> > +
> >> > +       release_idr(&thermal_zone_idr, &thermal_idr_lock, tz->id);
> >> > +       idr_destroy(&tz->idr);
> >> > +
> >> > +       device_unregister(&tz->device);
> >> > +       kfree(tz);
> >> > +exit:
> >> > +       mutex_unlock(&tz_list_lock);
> >> > +       return;
> >> > +}
> >> > +EXPORT_SYMBOL(remove_thermal_zone);
> >> > +
> >> > +struct thermal_sensor *get_sensor_by_name(const char *name)
> >> > +{
> >> > +       struct thermal_sensor *pos;
> >> > +       struct thermal_sensor *ts = NULL;
> >> > +
> >> > +       mutex_lock(&ts_list_lock);
> >> > +       for_each_thermal_sensor(pos) {
> >> > +               if (!strnicmp(pos->name, name, THERMAL_NAME_LENGTH)) {
> >> > +                       ts = pos;
> >> > +                       break;
> >> > +               }
> >> > +       }
> >> > +       mutex_unlock(&ts_list_lock);
> >> > +       return ts;
> >> > +}
> >> > +EXPORT_SYMBOL(get_sensor_by_name);
> >> > +
> >> > +int add_sensor_to_zone_by_name(struct thermal_zone *tz, const
> char
> >> *name)
> >> > +{
> >> > +       int ret;
> >> > +       struct thermal_sensor *ts = get_sensor_by_name(name);
> >> > +
> >> > +       if (!tz || !ts)
> >> > +               return -EINVAL;
> >> > +
> >> > +       mutex_lock(&tz_list_lock);
> >> > +
> >> > +       /* Ensure we are not adding the same sensor again!! */
> >> > +       ret = get_sensor_indx(tz, ts);
> >> > +       if (ret >= 0) {
> >> > +               ret = -EEXIST;
> >> > +               goto exit_zone;
> >> > +       }
> >> > +
> >> > +       mutex_lock(&ts_list_lock);
> >> > +
> >> > +       ret = sysfs_create_link(&tz->device.kobj, &ts->device.kobj,
> >> > +                               kobject_name(&ts->device.kobj));
> >> > +       if (ret)
> >> > +               goto exit_sensor;
> >> > +
> >> > +       tz->sensors[tz->sensor_indx++] = ts;
> >> > +
> >> > +exit_sensor:
> >> > +       mutex_unlock(&ts_list_lock);
> >> > +exit_zone:
> >> > +       mutex_unlock(&tz_list_lock);
> >> > +       return ret;
> >> > +}
> >> > +EXPORT_SYMBOL(add_sensor_to_zone_by_name);
> >> > +
> >> > +int add_sensor_to_zone(struct thermal_zone *tz, struct
> thermal_sensor
> >> *ts)
> >> > +{
> >> > +       if (!tz || !ts)
> >> > +               return -EINVAL;
> >> > +
> >> > +       return add_sensor_to_zone_by_name(tz, ts->name);
> >> > +}
> >> > +EXPORT_SYMBOL(add_sensor_to_zone);
> >> > +
> >> >  /**
> >> >   * thermal_sensor_register - register a new thermal sensor
> >> >   * @name:      name of the thermal sensor
> >> > @@ -1624,6 +1822,7 @@ EXPORT_SYMBOL(thermal_sensor_register);
> >> >  void thermal_sensor_unregister(struct thermal_sensor *ts)
> >> >  {
> >> >         int i;
> >> > +       struct thermal_zone *tz;
> >> >         struct thermal_sensor *pos, *next;
> >> >         bool found = false;
> >> >
> >> > @@ -1643,6 +1842,13 @@ void thermal_sensor_unregister(struct
> >> thermal_sensor *ts)
> >> >         if (!found)
> >> >                 return;
> >> >
> >> > +       mutex_lock(&tz_list_lock);
> >> > +
> >> > +       for_each_thermal_zone(tz)
> >> > +               remove_sensor_from_zone(tz, ts);
> >> > +
> >> > +       mutex_unlock(&tz_list_lock);
> >> > +
> >> >         for (i = 0; i < ts->thresholds; i++)
> >> >                 device_remove_file(&ts->device, &ts->thresh_attrs[i].attr);
> >> >
> >> > diff --git a/include/linux/thermal.h b/include/linux/thermal.h
> >> > index e2f85ec..38438be 100644
> >> > --- a/include/linux/thermal.h
> >> > +++ b/include/linux/thermal.h
> >> > @@ -49,6 +49,11 @@
> >> >  /* Default Thermal Governor: Does Linear Throttling */
> >> >  #define DEFAULT_THERMAL_GOVERNOR       "step_wise"
> >> >
> >> > +/* Maximum number of sensors, allowed in a thermal zone
> >> > + * We will start with 5, and increase if needed.
> >> > + */
> >> > +#define MAX_SENSORS_PER_ZONE           5
> >> > +
> >> >  struct thermal_sensor;
> >> >  struct thermal_zone_device;
> >> >  struct thermal_cooling_device;
> >> > @@ -191,6 +196,21 @@ struct thermal_zone_device {
> >> >         struct delayed_work poll_queue;
> >> >  };
> >> >
> >> > +struct thermal_zone {
> >> > +       char name[THERMAL_NAME_LENGTH];
> >> > +       int id;
> >> > +       void *devdata;
> >> > +       struct thermal_zone *ops;
> >> What is this, thermal_zone_device_ops? and how to initialize this ops?
> >
> > oh, Not required, for now. Will remove it..
> > Good catch :-)
> 
> I am still confused a bit.
> Is this thermal_zone going to take the place of the old
> thermal_zone_device?

Yes, it will replace the older one.

> If yes, which functions/callbacks are used to access
> thermal_zone->trip[] like the old get_trip_*?

We will not have call backs associated with 'zone'.
A zone is kind of a virtual entity, which can have one or
more sensors associated with it.

Trip points are attached to 'a sensor' which can be in
any zone. So, thermal_sensor_ops functions will help you
access the trip values.

Thanks,
Durga

> 
> >
> > Thanks,
> > Durga
> >>
> >> > +       struct thermal_governor *governor;
> >> > +       struct idr idr;
> >> > +       struct device device;
> >> > +       struct list_head node;
> >> > +
> >> > +       /* Sensor level information */
> >> > +       int sensor_indx; /* index into 'sensors' array */
> >> > +       struct thermal_sensor *sensors[MAX_SENSORS_PER_ZONE];
> >> > +};
> >> > +
> >> >  /* Structure that holds thermal governor information */
> >> >  struct thermal_governor {
> >> >         char name[THERMAL_NAME_LENGTH];
> >> > @@ -264,6 +284,11 @@ struct thermal_sensor
> >> *thermal_sensor_register(const char *,
> >> >  void thermal_sensor_unregister(struct thermal_sensor *);
> >> >  int enable_sensor_thresholds(struct thermal_sensor *, int);
> >> >
> >> > +struct thermal_zone *create_thermal_zone(const char *, void *);
> >> > +void remove_thermal_zone(struct thermal_zone *);
> >> > +int add_sensor_to_zone(struct thermal_zone *, struct thermal_sensor
> >> *);
> >> > +int add_sensor_to_zone_by_name(struct thermal_zone *, const char
> *);
> >> > +
> >> >  #ifdef CONFIG_NET
> >> >  extern int thermal_generate_netlink_event(u32 orig, enum events
> >> event);
> >> >  #else
> >> > --
> >> > 1.7.9.5
> >> >

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

* RE: [RFC PATCH 0/7] Support for Multiple sensors per zone
  2012-12-03  9:01 ` [RFC PATCH 0/7] Support for Multiple sensors per zone Hongbo Zhang
@ 2012-12-03  9:56   ` R, Durgadoss
  0 siblings, 0 replies; 27+ messages in thread
From: R, Durgadoss @ 2012-12-03  9:56 UTC (permalink / raw)
  To: Hongbo Zhang
  Cc: Zhang, Rui, linux-pm, wni, eduardo.valentin, amit.kachhap, sachin.kamat



> -----Original Message-----
> From: Hongbo Zhang [mailto:hongbo.zhang@linaro.org]
> Sent: Monday, December 03, 2012 2:31 PM
> To: R, Durgadoss
> Cc: Zhang, Rui; linux-pm@vger.kernel.org; wni@nvidia.com;
> eduardo.valentin@ti.com; amit.kachhap@linaro.org;
> sachin.kamat@linaro.org
> Subject: Re: [RFC PATCH 0/7] Support for Multiple sensors per zone
> 
> On 17 November 2012 18:45, Durgadoss R <durgadoss.r@intel.com> wrote:
> > This patch series attempts to add support for multiple
> > sensors per zone. The work is based on the Thermal discussion
> > happened in plumbers conference 2012, here:
> > http://www.linuxplumbersconf.org/2012/schedule/
> > Title: "Enhancing the Thermal Management Infrastructure in Linux"
> >
> > The intention is to make it easy for generic sensor drivers
> > to register with the framework, and let them participate in
> > platform thermal management. Another goal is to expose the
> > binding information in a consistent way so that user space
> > can consume the information and potentially manage platform thermals.
> >
> > This series contains 7 patches:
> > Patch 1/7: Creates new sensor level APIs
> > Patch 2/7: Creates new zone level APIs. The existing tzd structure is
> >            kept as such for clarity and compatibility purposes.
> > Patch 3/7: Creates functions to add/remove a cdev to/from a zone. The
> >            existing tcd structure need not be modified.
> > Patch 4/7: Adds a thermal_trip sysfs node, which exposes various trip
> >            points for all sensors present in a zone.
> > Patch 5/7: Adds a thermal_map sysfs node. It is a compact representation
> >            of the binding relationship between a sensor and a cdev,
> >            within a zone.
> > Patch 6/7: Creates Documentation for the new APIs. A new file is
> >            created for clarity. Final goal is to merge with the existing
> >            file or refactor the files, as whatever seems appropriate.
> > Patch 7/7: A dummy driver that can be used for testing. This is not for
> merge.
> >
> > Next steps:
> Do you have milestone?

Good question :-)
I would like these new APIs to get merged for 3.9 release.
Then we can work on migrating the old drivers + governors to
use this new API.

But, We should together ask for Rui's help here :-)

> Because new thermal driver writers are wondering if to use the old
> framework or can wait the new one.

We should move towards the new APIs. 

Thanks for your review.

Thanks,
Durga

> >  1. Move all the existing drivers to the new implementation model.
> >     Help welcomed from individual driver authors/maintainers for this.
> >  2. Make the thermal governors work with this new model.
> >  3. Remove old/unused code from thermal_sys.c.
> >  4. Add more detailed documentation
> >
> >  I didn't want to submit patches for all these in one-go, since it
> >  might end-up being difficult to comprehend, besides delaying the
> >  review process. The other obvious reason being I cannot test all
> >  the changes on various drivers for 1.
> >
> >  All these patches have been tested on a Core-i5 desktop running
> >  ubuntu 12.04 and an atom notebook running ubuntu 11.10.
> >  Kindly help review.
> >
> > Durgadoss R (7):
> >   Thermal: Create sensor level APIs
> >   Thermal: Create zone level APIs
> >   Thermal: Add APIs to bind cdev to new zone structure
> >   Thermal: Add Thermal_trip sysfs node
> >   Thermal: Add 'thermal_map' sysfs node
> >   Thermal: Add Documentation to new APIs
> >   Thermal: Dummy driver used for testing
> >
> >  Documentation/thermal/sysfs-api2.txt |  213 ++++++++
> >  drivers/thermal/Kconfig              |    5 +
> >  drivers/thermal/Makefile             |    3 +
> >  drivers/thermal/thermal_sys.c        |  915
> ++++++++++++++++++++++++++++++++++
> >  drivers/thermal/thermal_test.c       |  321 ++++++++++++
> >  include/linux/thermal.h              |  118 +++++
> >  6 files changed, 1575 insertions(+)
> >  create mode 100644 Documentation/thermal/sysfs-api2.txt
> >  create mode 100644 drivers/thermal/thermal_test.c
> >
> > --
> > 1.7.9.5
> >

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

* Re: [RFC PATCH 2/7] Thermal: Create zone level APIs
  2012-12-03  9:51         ` R, Durgadoss
@ 2012-12-03 11:50           ` Hongbo Zhang
  2012-12-03 13:12             ` R, Durgadoss
  0 siblings, 1 reply; 27+ messages in thread
From: Hongbo Zhang @ 2012-12-03 11:50 UTC (permalink / raw)
  To: R, Durgadoss
  Cc: Zhang, Rui, linux-pm, wni, eduardo.valentin, amit.kachhap, sachin.kamat

On 3 December 2012 17:51, R, Durgadoss <durgadoss.r@intel.com> wrote:
>
>
>> -----Original Message-----
>> From: Hongbo Zhang [mailto:hongbo.zhang@linaro.org]
>> Sent: Monday, December 03, 2012 1:51 PM
>> To: R, Durgadoss
>> Cc: Zhang, Rui; linux-pm@vger.kernel.org; wni@nvidia.com;
>> eduardo.valentin@ti.com; amit.kachhap@linaro.org;
>> sachin.kamat@linaro.org
>> Subject: Re: [RFC PATCH 2/7] Thermal: Create zone level APIs
>>
>> On 3 December 2012 15:47, R, Durgadoss <durgadoss.r@intel.com> wrote:
>> >
>> >
>> >> -----Original Message-----
>> >> From: Hongbo Zhang [mailto:hongbo.zhang@linaro.org]
>> >> Sent: Monday, December 03, 2012 1:13 PM
>> >> To: R, Durgadoss
>> >> Cc: Zhang, Rui; linux-pm@vger.kernel.org; wni@nvidia.com;
>> >> eduardo.valentin@ti.com; amit.kachhap@linaro.org;
>> >> sachin.kamat@linaro.org
>> >> Subject: Re: [RFC PATCH 2/7] Thermal: Create zone level APIs
>> >>
>> >> On 17 November 2012 18:45, Durgadoss R <durgadoss.r@intel.com>
>> wrote:
>> >> > This patch adds a new thermal_zone structure to
>> >> > thermal.h. Also, adds zone level APIs to the thermal
>> >> > framework.
>> >> >
>> >> > Signed-off-by: Durgadoss R <durgadoss.r@intel.com>
>> >> > ---
>> >> >  drivers/thermal/thermal_sys.c |  206
>> >> +++++++++++++++++++++++++++++++++++++++++
>> >> >  include/linux/thermal.h       |   25 +++++
>> >> >  2 files changed, 231 insertions(+)
>> >> >
>> >> > diff --git a/drivers/thermal/thermal_sys.c
>> b/drivers/thermal/thermal_sys.c
>> >> > index e726c8b..9d386d7 100644
>> >> > --- a/drivers/thermal/thermal_sys.c
>> >> > +++ b/drivers/thermal/thermal_sys.c
>> >> > @@ -44,19 +44,28 @@ MODULE_DESCRIPTION("Generic thermal
>> >> management sysfs support");
>> >> >  MODULE_LICENSE("GPL");
>> >> >
>> >> >  static DEFINE_IDR(thermal_tz_idr);
>> >> > +static DEFINE_IDR(thermal_zone_idr);
>> >> >  static DEFINE_IDR(thermal_cdev_idr);
>> >> >  static DEFINE_IDR(thermal_sensor_idr);
>> >> >  static DEFINE_MUTEX(thermal_idr_lock);
>> >> >
>> >> >  static LIST_HEAD(thermal_tz_list);
>> >> >  static LIST_HEAD(thermal_sensor_list);
>> >> > +static LIST_HEAD(thermal_zone_list);
>> >> >  static LIST_HEAD(thermal_cdev_list);
>> >> >  static LIST_HEAD(thermal_governor_list);
>> >> >
>> >> >  static DEFINE_MUTEX(thermal_list_lock);
>> >> >  static DEFINE_MUTEX(ts_list_lock);
>> >> > +static DEFINE_MUTEX(tz_list_lock);
>> >> >  static DEFINE_MUTEX(thermal_governor_lock);
>> >> >
>> >> > +#define for_each_thermal_sensor(pos) \
>> >> > +       list_for_each_entry(pos, &thermal_sensor_list, node)
>> >> > +
>> >> > +#define for_each_thermal_zone(pos) \
>> >> > +       list_for_each_entry(pos, &thermal_zone_list, node)
>> >> > +
>> >> >  static struct thermal_governor *__find_governor(const char *name)
>> >> >  {
>> >> >         struct thermal_governor *pos;
>> >> > @@ -419,15 +428,62 @@ static void thermal_zone_device_check(struct
>> >> work_struct *work)
>> >> >         thermal_zone_device_update(tz);
>> >> >  }
>> >> >
>> >> > +static int get_sensor_indx(struct thermal_zone *tz, struct
>> thermal_sensor
>> >> *ts)
>> >> > +{
>> >> > +       int i, indx = -EINVAL;
>> >> > +
>> >> > +       if (!tz || !ts)
>> >> > +               return -EINVAL;
>> >> > +
>> >> > +       mutex_lock(&ts_list_lock);
>> >> > +       for (i = 0; i < tz->sensor_indx; i++) {
>> >> > +               if (tz->sensors[i] == ts) {
>> >> > +                       indx = i;
>> >> > +                       break;
>> >> > +               }
>> >> > +       }
>> >> > +       mutex_unlock(&ts_list_lock);
>> >> > +       return indx;
>> >> > +}
>> >> > +
>> >> > +static void remove_sensor_from_zone(struct thermal_zone *tz,
>> >> > +                               struct thermal_sensor *ts)
>> >> > +{
>> >> > +       int indx, j;
>> >> > +
>> >> > +       indx = get_sensor_indx(tz, ts);
>> >> > +       if (indx < 0)
>> >> > +               return;
>> >> > +
>> >> > +       sysfs_remove_link(&tz->device.kobj, kobject_name(&ts-
>> >> >device.kobj));
>> >> > +
>> >> > +       /* Shift the entries in the tz->sensors array */
>> >> > +       for (j = indx; j < MAX_SENSORS_PER_ZONE - 1; j++)
>> >> > +               tz->sensors[j] = tz->sensors[j + 1];
>> >> > +
>> >> > +       tz->sensor_indx--;
>> >> > +}
>> >> > +
>> >> >  /* sys I/F for thermal zone */
>> >> >
>> >> >  #define to_thermal_zone(_dev) \
>> >> >         container_of(_dev, struct thermal_zone_device, device)
>> >> >
>> >> > +#define to_zone(_dev) \
>> >> > +       container_of(_dev, struct thermal_zone, device)
>> >> > +
>> >> >  #define to_thermal_sensor(_dev) \
>> >> >         container_of(_dev, struct thermal_sensor, device)
>> >> >
>> >> >  static ssize_t
>> >> > +zone_name_show(struct device *dev, struct device_attribute *attr,
>> char
>> >> *buf)
>> >> > +{
>> >> > +       struct thermal_zone *tz = to_zone(dev);
>> >> > +
>> >> > +       return sprintf(buf, "%s\n", tz->name);
>> >> > +}
>> >> > +
>> >> > +static ssize_t
>> >> >  sensor_name_show(struct device *dev, struct device_attribute *attr,
>> char
>> >> *buf)
>> >> >  {
>> >> >         struct thermal_sensor *ts = to_thermal_sensor(dev);
>> >> > @@ -772,6 +828,8 @@ static DEVICE_ATTR(policy, S_IRUGO | S_IWUSR,
>> >> policy_show, policy_store);
>> >> >  static DEVICE_ATTR(sensor_name, 0444, sensor_name_show, NULL);
>> >> >  static DEVICE_ATTR(temp_input, 0444, sensor_temp_show, NULL);
>> >> >
>> >> > +static DEVICE_ATTR(zone_name, 0444, zone_name_show, NULL);
>> >> > +
>> >> >  /* sys I/F for cooling device */
>> >> >  #define to_cooling_device(_dev)        \
>> >> >         container_of(_dev, struct thermal_cooling_device, device)
>> >> > @@ -1557,6 +1615,146 @@ static void remove_trip_attrs(struct
>> >> thermal_zone_device *tz)
>> >> >         kfree(tz->trip_hyst_attrs);
>> >> >  }
>> >> >
>> >> > +struct thermal_zone *create_thermal_zone(const char *name, void
>> >> *devdata)
>> >> > +{
>> >> > +       struct thermal_zone *tz;
>> >> > +       int ret;
>> >> > +
>> >> > +       if (!name || (name && strlen(name) >=
>> THERMAL_NAME_LENGTH))
>> >> > +               return ERR_PTR(-EINVAL);
>> >> > +
>> >> > +       tz = kzalloc(sizeof(*tz), GFP_KERNEL);
>> >> > +       if (!tz)
>> >> > +               return ERR_PTR(-ENOMEM);
>> >> > +
>> >> > +       idr_init(&tz->idr);
>> >> > +       ret = get_idr(&thermal_zone_idr, &thermal_idr_lock, &tz->id);
>> >> > +       if (ret)
>> >> > +               goto exit_free;
>> >> > +
>> >> > +       strcpy(tz->name, name);
>> >> > +       tz->devdata = devdata;
>> >> > +       tz->device.class = &thermal_class;
>> >> > +
>> >> > +       dev_set_name(&tz->device, "zone%d", tz->id);
>> >> > +       ret = device_register(&tz->device);
>> >> > +       if (ret)
>> >> > +               goto exit_idr;
>> >> > +
>> >> > +       ret = device_create_file(&tz->device, &dev_attr_zone_name);
>> >> > +       if (ret)
>> >> > +               goto exit_unregister;
>> >> > +
>> >> > +       /* Add this zone to the global list of thermal zones */
>> >> > +       mutex_lock(&tz_list_lock);
>> >> > +       list_add_tail(&tz->node, &thermal_zone_list);
>> >> > +       mutex_unlock(&tz_list_lock);
>> >> > +       return tz;
>> >> > +
>> >> > +exit_unregister:
>> >> > +       device_unregister(&tz->device);
>> >> > +exit_idr:
>> >> > +       release_idr(&thermal_zone_idr, &thermal_idr_lock, tz->id);
>> >> > +exit_free:
>> >> > +       kfree(tz);
>> >> > +       return ERR_PTR(ret);
>> >> > +}
>> >> > +EXPORT_SYMBOL(create_thermal_zone);
>> >> > +
>> >> > +void remove_thermal_zone(struct thermal_zone *tz)
>> >> > +{
>> >> > +       struct thermal_zone *pos, *next;
>> >> > +       bool found = false;
>> >> > +
>> >> > +       if (!tz)
>> >> > +               return;
>> >> > +
>> >> > +       mutex_lock(&tz_list_lock);
>> >> > +
>> >> > +       list_for_each_entry_safe(pos, next, &thermal_zone_list, node) {
>> >> > +               if (pos == tz) {
>> >> > +                       list_del(&tz->node);
>> >> > +                       found = true;
>> >> > +                       break;
>> >> > +               }
>> >> > +       }
>> >> > +
>> >> > +       if (!found)
>> >> > +               goto exit;
>> >> > +
>> >> > +       device_remove_file(&tz->device, &dev_attr_zone_name);
>> >> > +
>> >> > +       release_idr(&thermal_zone_idr, &thermal_idr_lock, tz->id);
>> >> > +       idr_destroy(&tz->idr);
>> >> > +
>> >> > +       device_unregister(&tz->device);
>> >> > +       kfree(tz);
>> >> > +exit:
>> >> > +       mutex_unlock(&tz_list_lock);
>> >> > +       return;
>> >> > +}
>> >> > +EXPORT_SYMBOL(remove_thermal_zone);
>> >> > +
>> >> > +struct thermal_sensor *get_sensor_by_name(const char *name)
>> >> > +{
>> >> > +       struct thermal_sensor *pos;
>> >> > +       struct thermal_sensor *ts = NULL;
>> >> > +
>> >> > +       mutex_lock(&ts_list_lock);
>> >> > +       for_each_thermal_sensor(pos) {
>> >> > +               if (!strnicmp(pos->name, name, THERMAL_NAME_LENGTH)) {
>> >> > +                       ts = pos;
>> >> > +                       break;
>> >> > +               }
>> >> > +       }
>> >> > +       mutex_unlock(&ts_list_lock);
>> >> > +       return ts;
>> >> > +}
>> >> > +EXPORT_SYMBOL(get_sensor_by_name);
>> >> > +
>> >> > +int add_sensor_to_zone_by_name(struct thermal_zone *tz, const
>> char
>> >> *name)
>> >> > +{
>> >> > +       int ret;
>> >> > +       struct thermal_sensor *ts = get_sensor_by_name(name);
>> >> > +
>> >> > +       if (!tz || !ts)
>> >> > +               return -EINVAL;
>> >> > +
>> >> > +       mutex_lock(&tz_list_lock);
>> >> > +
>> >> > +       /* Ensure we are not adding the same sensor again!! */
>> >> > +       ret = get_sensor_indx(tz, ts);
>> >> > +       if (ret >= 0) {
>> >> > +               ret = -EEXIST;
>> >> > +               goto exit_zone;
>> >> > +       }
>> >> > +
>> >> > +       mutex_lock(&ts_list_lock);
>> >> > +
>> >> > +       ret = sysfs_create_link(&tz->device.kobj, &ts->device.kobj,
>> >> > +                               kobject_name(&ts->device.kobj));
>> >> > +       if (ret)
>> >> > +               goto exit_sensor;
>> >> > +
>> >> > +       tz->sensors[tz->sensor_indx++] = ts;
>> >> > +
>> >> > +exit_sensor:
>> >> > +       mutex_unlock(&ts_list_lock);
>> >> > +exit_zone:
>> >> > +       mutex_unlock(&tz_list_lock);
>> >> > +       return ret;
>> >> > +}
>> >> > +EXPORT_SYMBOL(add_sensor_to_zone_by_name);
>> >> > +
>> >> > +int add_sensor_to_zone(struct thermal_zone *tz, struct
>> thermal_sensor
>> >> *ts)
>> >> > +{
>> >> > +       if (!tz || !ts)
>> >> > +               return -EINVAL;
>> >> > +
>> >> > +       return add_sensor_to_zone_by_name(tz, ts->name);
>> >> > +}
>> >> > +EXPORT_SYMBOL(add_sensor_to_zone);
>> >> > +
>> >> >  /**
>> >> >   * thermal_sensor_register - register a new thermal sensor
>> >> >   * @name:      name of the thermal sensor
>> >> > @@ -1624,6 +1822,7 @@ EXPORT_SYMBOL(thermal_sensor_register);
>> >> >  void thermal_sensor_unregister(struct thermal_sensor *ts)
>> >> >  {
>> >> >         int i;
>> >> > +       struct thermal_zone *tz;
>> >> >         struct thermal_sensor *pos, *next;
>> >> >         bool found = false;
>> >> >
>> >> > @@ -1643,6 +1842,13 @@ void thermal_sensor_unregister(struct
>> >> thermal_sensor *ts)
>> >> >         if (!found)
>> >> >                 return;
>> >> >
>> >> > +       mutex_lock(&tz_list_lock);
>> >> > +
>> >> > +       for_each_thermal_zone(tz)
>> >> > +               remove_sensor_from_zone(tz, ts);
>> >> > +
>> >> > +       mutex_unlock(&tz_list_lock);
>> >> > +
>> >> >         for (i = 0; i < ts->thresholds; i++)
>> >> >                 device_remove_file(&ts->device, &ts->thresh_attrs[i].attr);
>> >> >
>> >> > diff --git a/include/linux/thermal.h b/include/linux/thermal.h
>> >> > index e2f85ec..38438be 100644
>> >> > --- a/include/linux/thermal.h
>> >> > +++ b/include/linux/thermal.h
>> >> > @@ -49,6 +49,11 @@
>> >> >  /* Default Thermal Governor: Does Linear Throttling */
>> >> >  #define DEFAULT_THERMAL_GOVERNOR       "step_wise"
>> >> >
>> >> > +/* Maximum number of sensors, allowed in a thermal zone
>> >> > + * We will start with 5, and increase if needed.
>> >> > + */
>> >> > +#define MAX_SENSORS_PER_ZONE           5
>> >> > +
>> >> >  struct thermal_sensor;
>> >> >  struct thermal_zone_device;
>> >> >  struct thermal_cooling_device;
>> >> > @@ -191,6 +196,21 @@ struct thermal_zone_device {
>> >> >         struct delayed_work poll_queue;
>> >> >  };
>> >> >
>> >> > +struct thermal_zone {
>> >> > +       char name[THERMAL_NAME_LENGTH];
>> >> > +       int id;
>> >> > +       void *devdata;
>> >> > +       struct thermal_zone *ops;
>> >> What is this, thermal_zone_device_ops? and how to initialize this ops?
>> >
>> > oh, Not required, for now. Will remove it..
>> > Good catch :-)
>>
>> I am still confused a bit.
>> Is this thermal_zone going to take the place of the old
>> thermal_zone_device?
>
> Yes, it will replace the older one.
>
>> If yes, which functions/callbacks are used to access
>> thermal_zone->trip[] like the old get_trip_*?
>
> We will not have call backs associated with 'zone'.
> A zone is kind of a virtual entity, which can have one or
> more sensors associated with it.
>
> Trip points are attached to 'a sensor' which can be in
> any zone. So, thermal_sensor_ops functions will help you
> access the trip values.
But I didn't find such functions in the current thermal_sensor_ops for
access trip points, only functions for thresholds now.
Will you add these functions when you update the governors?

>
> Thanks,
> Durga
>
>>
>> >
>> > Thanks,
>> > Durga
>> >>
>> >> > +       struct thermal_governor *governor;
>> >> > +       struct idr idr;
>> >> > +       struct device device;
>> >> > +       struct list_head node;
>> >> > +
>> >> > +       /* Sensor level information */
>> >> > +       int sensor_indx; /* index into 'sensors' array */
>> >> > +       struct thermal_sensor *sensors[MAX_SENSORS_PER_ZONE];
>> >> > +};
>> >> > +
>> >> >  /* Structure that holds thermal governor information */
>> >> >  struct thermal_governor {
>> >> >         char name[THERMAL_NAME_LENGTH];
>> >> > @@ -264,6 +284,11 @@ struct thermal_sensor
>> >> *thermal_sensor_register(const char *,
>> >> >  void thermal_sensor_unregister(struct thermal_sensor *);
>> >> >  int enable_sensor_thresholds(struct thermal_sensor *, int);
>> >> >
>> >> > +struct thermal_zone *create_thermal_zone(const char *, void *);
>> >> > +void remove_thermal_zone(struct thermal_zone *);
>> >> > +int add_sensor_to_zone(struct thermal_zone *, struct thermal_sensor
>> >> *);
>> >> > +int add_sensor_to_zone_by_name(struct thermal_zone *, const char
>> *);
>> >> > +
>> >> >  #ifdef CONFIG_NET
>> >> >  extern int thermal_generate_netlink_event(u32 orig, enum events
>> >> event);
>> >> >  #else
>> >> > --
>> >> > 1.7.9.5
>> >> >

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

* RE: [RFC PATCH 2/7] Thermal: Create zone level APIs
  2012-12-03 11:50           ` Hongbo Zhang
@ 2012-12-03 13:12             ` R, Durgadoss
  0 siblings, 0 replies; 27+ messages in thread
From: R, Durgadoss @ 2012-12-03 13:12 UTC (permalink / raw)
  To: Hongbo Zhang
  Cc: Zhang, Rui, linux-pm, wni, eduardo.valentin, amit.kachhap, sachin.kamat

Hi,

[big cut.]
> >> >> > +struct thermal_zone {
> >> >> > +       char name[THERMAL_NAME_LENGTH];
> >> >> > +       int id;
> >> >> > +       void *devdata;
> >> >> > +       struct thermal_zone *ops;
> >> >> What is this, thermal_zone_device_ops? and how to initialize this ops?
> >> >
> >> > oh, Not required, for now. Will remove it..
> >> > Good catch :-)
> >>
> >> I am still confused a bit.
> >> Is this thermal_zone going to take the place of the old
> >> thermal_zone_device?
> >
> > Yes, it will replace the older one.
> >
> >> If yes, which functions/callbacks are used to access
> >> thermal_zone->trip[] like the old get_trip_*?
> >
> > We will not have call backs associated with 'zone'.
> > A zone is kind of a virtual entity, which can have one or
> > more sensors associated with it.
> >
> > Trip points are attached to 'a sensor' which can be in
> > any zone. So, thermal_sensor_ops functions will help you
> > access the trip values.
> But I didn't find such functions in the current thermal_sensor_ops for
> access trip points, only functions for thresholds now.
> Will you add these functions when you update the governors?

The idea is the governors need these values to calculate the trend
of the thermal zone. And these are embedded inside thermal zone
structure. So, when required a zone can 'know' about its sensors and
their trip points through these pointers.

Having said that, when we modify governors, if a need arises to
implement these functions, we will implement it.

Thanks,
Durga

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

* Re: [RFC PATCH 4/7] Thermal: Add Thermal_trip sysfs node
  2012-11-17 10:45 ` [RFC PATCH 4/7] Thermal: Add Thermal_trip sysfs node Durgadoss R
@ 2012-12-04  8:30   ` Hongbo Zhang
  2012-12-04  8:41     ` R, Durgadoss
  0 siblings, 1 reply; 27+ messages in thread
From: Hongbo Zhang @ 2012-12-04  8:30 UTC (permalink / raw)
  To: Durgadoss R
  Cc: rui.zhang, linux-pm, wni, eduardo.valentin, amit.kachhap, sachin.kamat

On 17 November 2012 18:45, Durgadoss R <durgadoss.r@intel.com> wrote:
> This patch adds a thermal_trip directory under
> /sys/class/thermal/zoneX. This directory contains
> the trip point values for sensors bound to this
> zone.
>
> Signed-off-by: Durgadoss R <durgadoss.r@intel.com>
> ---
>  drivers/thermal/thermal_sys.c |  244 ++++++++++++++++++++++++++++++++++++++++-
>  include/linux/thermal.h       |   32 ++++++
>  2 files changed, 274 insertions(+), 2 deletions(-)
>
> diff --git a/drivers/thermal/thermal_sys.c b/drivers/thermal/thermal_sys.c
> index 70e5f5a..011588a 100644
> --- a/drivers/thermal/thermal_sys.c
> +++ b/drivers/thermal/thermal_sys.c
> @@ -480,9 +480,15 @@ static void remove_sensor_from_zone(struct thermal_zone *tz,
>
>         sysfs_remove_link(&tz->device.kobj, kobject_name(&ts->device.kobj));
>
> +       /* Delete this sensor's trip Kobject */
> +       kobject_del(tz->kobj_trip[indx]);
> +
>         /* Shift the entries in the tz->sensors array */
> -       for (j = indx; j < MAX_SENSORS_PER_ZONE - 1; j++)
> +       for (j = indx; j < MAX_SENSORS_PER_ZONE - 1; j++) {
>                 tz->sensors[j] = tz->sensors[j + 1];
> +               tz->trip[j] = tz->trip[j + 1];
> +               tz->kobj_trip[j] = tz->kobj_trip[j + 1];
> +       }
>
>         tz->sensor_indx--;
>  }
> @@ -505,6 +511,41 @@ static void remove_cdev_from_zone(struct thermal_zone *tz,
>         tz->cdev_indx--;
>  }
>
> +static struct thermal_zone *get_zone_by_trip_kobj(struct kobject *kobj)
> +{
> +       struct thermal_zone *pos;
> +       struct thermal_zone *tz = NULL;
> +
> +       if (!kobj)
> +               return NULL;
> +
> +       mutex_lock(&tz_list_lock);
> +       for_each_thermal_zone(pos) {
> +               if (pos->kobj_thermal_trip == kobj) {
> +                       tz = pos;
> +                       break;
> +               }
> +       }
> +       mutex_unlock(&tz_list_lock);
> +       return tz;
> +}
> +
> +static struct thermal_sensor *get_sensor_by_kobj_name(const char *name)
> +{
> +       struct thermal_sensor *pos;
> +       struct thermal_sensor *ts = NULL;
> +
> +       mutex_lock(&ts_list_lock);
> +       for_each_thermal_sensor(pos) {
> +               if (!strcmp(kobject_name(&pos->device.kobj), name)) {
> +                       ts = pos;
> +                       break;
> +               }
> +       }
> +       mutex_unlock(&ts_list_lock);
> +       return ts;
> +}
> +
>  /* sys I/F for thermal zone */
>
>  #define to_thermal_zone(_dev) \
> @@ -859,6 +900,113 @@ policy_show(struct device *dev, struct device_attribute *devattr, char *buf)
>         return sprintf(buf, "%s\n", tz->governor->name);
>  }
>
> +static ssize_t
> +active_show(struct kobject *kobj, struct kobj_attribute *attr, char *buf)
> +{
> +       int i, indx, ret = 0;
> +       struct thermal_sensor *ts;
> +       struct thermal_zone *tz;
> +
> +       ts = get_sensor_by_kobj_name(kobject_name(kobj));
> +       if (!ts)
> +               return -EINVAL;
> +
> +       tz = get_zone_by_trip_kobj(kobj->parent);
> +       if (!tz)
> +               return -EINVAL;
> +
> +       indx = get_sensor_indx(tz, ts);
> +       if (indx < 0)
> +               return indx;
> +
> +       if (tz->trip[indx]->num_active_trips <= 0)
> +               return sprintf(buf, "<Not available>\n");
> +
> +       ret += sprintf(buf, "0x%x", tz->trip[indx]->active_trip_mask);
> +       for (i = 0; i < tz->trip[indx]->num_active_trips; i++) {
> +               ret += sprintf(buf + ret, " %d",
> +                       tz->trip[indx]->active_trips[i]);
> +       }
> +
> +       ret += sprintf(buf + ret, "\n");
> +       return ret;
> +}
> +
> +static ssize_t
> +ptrip_show(struct kobject *kobj, struct kobj_attribute *attr, char *buf)
Just remind you it is better to use passive_show instead of ptrip_show
when you remove the unused old codes.

> +{
> +       int i, indx, ret = 0;
> +       struct thermal_sensor *ts;
> +       struct thermal_zone *tz;
> +
> +       ts = get_sensor_by_kobj_name(kobject_name(kobj));
> +       if (!ts)
> +               return -EINVAL;
> +
> +       tz = get_zone_by_trip_kobj(kobj->parent);
> +       if (!tz)
> +               return -EINVAL;
> +
> +       indx = get_sensor_indx(tz, ts);
> +       if (indx < 0)
> +               return indx;
> +
> +       if (tz->trip[indx]->num_passive_trips <= 0)
> +               return sprintf(buf, "<Not available>\n");
> +
> +       for (i = 0; i < tz->trip[indx]->num_passive_trips; i++) {
> +               ret += sprintf(buf + ret, "%d ",
> +                       tz->trip[indx]->passive_trips[i]);
> +       }
> +
> +       ret += sprintf(buf + ret, "\n");
> +       return ret;
> +}
> +
> +static ssize_t
> +hot_show(struct kobject *kobj, struct kobj_attribute *attr, char *buf)
> +{
> +       int indx;
> +       struct thermal_sensor *ts;
> +       struct thermal_zone *tz;
> +
> +       ts = get_sensor_by_kobj_name(kobject_name(kobj));
> +       if (!ts)
> +               return -EINVAL;
> +
> +       tz = get_zone_by_trip_kobj(kobj->parent);
> +       if (!tz)
> +               return -EINVAL;
> +
> +       indx = get_sensor_indx(tz, ts);
> +       if (indx < 0)
> +               return indx;
> +
> +       return sprintf(buf, "%d\n", tz->trip[indx]->hot);
> +}
> +
> +static ssize_t
> +critical_show(struct kobject *kobj, struct kobj_attribute *attr, char *buf)
> +{
> +       int indx;
> +       struct thermal_sensor *ts;
> +       struct thermal_zone *tz;
> +
> +       ts = get_sensor_by_kobj_name(kobject_name(kobj));
> +       if (!ts)
> +               return -EINVAL;
> +
> +       tz = get_zone_by_trip_kobj(kobj->parent);
> +       if (!tz)
> +               return -EINVAL;
> +
> +       indx = get_sensor_indx(tz, ts);
> +       if (indx < 0)
> +               return indx;
> +
> +       return sprintf(buf, "%d\n", tz->trip[indx]->crit);
> +}
> +
>  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);
> @@ -869,7 +1017,26 @@ static DEVICE_ATTR(policy, S_IRUGO | S_IWUSR, policy_show, policy_store);
>  static DEVICE_ATTR(sensor_name, 0444, sensor_name_show, NULL);
>  static DEVICE_ATTR(temp_input, 0444, sensor_temp_show, NULL);
>
> -static DEVICE_ATTR(zone_name, 0444, zone_name_show, NULL);
> +/* Thermal zone attributes */
> +static DEVICE_ATTR(zone_name, S_IRUGO, zone_name_show, NULL);
> +
> +/* Thermal trip attributes */
> +static struct kobj_attribute active_attr = __ATTR_RO(active);
> +static struct kobj_attribute passive_attr = __ATTR_RO(ptrip);
> +static struct kobj_attribute hot_attr = __ATTR_RO(hot);
> +static struct kobj_attribute crit_attr = __ATTR_RO(critical);
> +
> +static struct attribute *trip_attrs[] = {
> +                       &active_attr.attr,
> +                       &passive_attr.attr,
> +                       &hot_attr.attr,
> +                       &crit_attr.attr,
> +                       NULL,
> +                       };
> +
> +static struct attribute_group trip_attr_group = {
> +                       .attrs = trip_attrs,
> +                       };
>
>  /* sys I/F for cooling device */
>  #define to_cooling_device(_dev)        \
> @@ -1694,12 +1861,19 @@ struct thermal_zone *create_thermal_zone(const char *name, void *devdata)
>         if (ret)
>                 goto exit_unregister;
>
> +       tz->kobj_thermal_trip = kobject_create_and_add("thermal_trip",
> +                                       &tz->device.kobj);
> +       if (!tz->kobj_thermal_trip)
> +               goto exit_name;
> +
>         /* Add this zone to the global list of thermal zones */
>         mutex_lock(&tz_list_lock);
>         list_add_tail(&tz->node, &thermal_zone_list);
>         mutex_unlock(&tz_list_lock);
>         return tz;
>
> +exit_name:
> +       device_remove_file(&tz->device, &dev_attr_zone_name);
>  exit_unregister:
>         device_unregister(&tz->device);
>  exit_idr:
> @@ -1713,6 +1887,7 @@ EXPORT_SYMBOL(create_thermal_zone);
>  void remove_thermal_zone(struct thermal_zone *tz)
>  {
>         struct thermal_zone *pos, *next;
> +       int i;
>         bool found = false;
>
>         if (!tz)
> @@ -1733,6 +1908,29 @@ void remove_thermal_zone(struct thermal_zone *tz)
>
>         device_remove_file(&tz->device, &dev_attr_zone_name);
>
> +       /* Just for ease of usage */
> +       i = tz->sensor_indx;
> +
> +       while (--i >= 0) {
> +               sysfs_remove_link(&tz->device.kobj,
> +                               kobject_name(&tz->sensors[i]->device.kobj));
> +               if (tz->kobj_trip[i])
> +                       kobject_del(tz->kobj_trip[i]);
> +       }
> +
> +       if (tz->kobj_thermal_trip)
> +               kobject_del(tz->kobj_thermal_trip);
> +
> +       /* Release the cdevs attached to this zone */
> +       i = tz->cdev_indx;
> +
> +       while (--i >= 0) {
> +               sysfs_remove_link(&tz->device.kobj,
> +                               kobject_name(&tz->cdevs[i]->device.kobj));
> +       }
> +
> +       tz->sensor_indx = tz->cdev_indx = 0;
> +
>         release_idr(&thermal_zone_idr, &thermal_idr_lock, tz->id);
>         idr_destroy(&tz->idr);
>
> @@ -1864,6 +2062,48 @@ int add_cdev_to_zone(struct thermal_zone *tz,
>  }
>  EXPORT_SYMBOL(add_cdev_to_zone);
>
> +int add_sensor_trip_info(struct thermal_zone *tz, const char *sensor_name,
> +                       struct thermal_trip_point *trip)
> +{
> +       int indx, ret = -EINVAL;
> +       struct thermal_sensor *ts = get_sensor_by_name(sensor_name);
> +
> +       if (!tz || !ts || !trip)
> +               return ret;
> +
> +       mutex_lock(&tz_list_lock);
> +
> +       indx = get_sensor_indx(tz, ts);
> +       if (indx < 0)
> +               goto exit_indx;
> +
> +       tz->kobj_trip[indx] = kobject_create_and_add(
> +                                       kobject_name(&ts->device.kobj),
> +                                       tz->kobj_thermal_trip);
> +       if (!tz->kobj_trip[indx]) {
> +               ret = -ENOMEM;
> +               goto exit_indx;
> +       }
> +
> +       ret = sysfs_create_group(tz->kobj_trip[indx], &trip_attr_group);
> +       if (ret) {
> +               dev_err(&tz->device, "sysfs_create_group failed:%d\n", ret);
> +               goto exit_kobj;
> +       }
> +
> +       tz->trip[indx] = trip;
> +       mutex_unlock(&tz_list_lock);
> +       return 0;
> +
> +exit_kobj:
> +       kobject_del(tz->kobj_trip[indx]);
> +       tz->kobj_trip[indx] = NULL;
> +exit_indx:
> +       mutex_unlock(&tz_list_lock);
> +       return ret;
> +}
> +EXPORT_SYMBOL(add_sensor_trip_info);
> +
>  /**
>   * thermal_sensor_register - register a new thermal sensor
>   * @name:      name of the thermal sensor
> diff --git a/include/linux/thermal.h b/include/linux/thermal.h
> index 2913910..7b2fe35 100644
> --- a/include/linux/thermal.h
> +++ b/include/linux/thermal.h
> @@ -159,6 +159,30 @@ struct thermal_attr {
>         char name[THERMAL_NAME_LENGTH];
>  };
>
> +/*
> + * This structure defines the trip points for a sensor.
> + * The actual values for these trip points come from
> + * platform characterization. The thermal governors
> + * (either kernel or user space) may take appropriate
> + * actions when the sensors reach these trip points.
> + * See Documentation/thermal/sysfs-api2.txt for more details.
> + *
> + * As of now, For a particular sensor, we support:
> + * a) 1 hot trip point
> + * b) 1 critical trip point
> + * c) 'n' passive trip points
> + * d) 'm' active trip points
> + */
> +struct thermal_trip_point {
> +       int hot;
> +       int crit;
> +       int num_passive_trips;
> +       int *passive_trips;
> +       int num_active_trips;
> +       int *active_trips;
> +       int active_trip_mask;
> +};
> +
>  struct thermal_sensor {
>         char name[THERMAL_NAME_LENGTH];
>         int id;
> @@ -215,6 +239,11 @@ struct thermal_zone {
>         /* cdev level information */
>         int cdev_indx; /* index into 'cdevs' array */
>         struct thermal_cooling_device *cdevs[MAX_CDEVS_PER_ZONE];
> +
> +       /* Thermal trip information */
> +       struct thermal_trip_point *trip[MAX_SENSORS_PER_ZONE];
> +       struct kobject *kobj_trip[MAX_SENSORS_PER_ZONE];
> +       struct kobject *kobj_thermal_trip;
>  };
>
>  /* Structure that holds thermal governor information */
> @@ -298,6 +327,9 @@ int add_sensor_to_zone_by_name(struct thermal_zone *, const char *);
>  int add_cdev_to_zone(struct thermal_zone *, struct thermal_cooling_device *);
>  int add_cdev_to_zone_by_name(struct thermal_zone *, const char *);
>
> +int add_sensor_trip_info(struct thermal_zone *, const char *,
> +                       struct thermal_trip_point *);
> +
>  #ifdef CONFIG_NET
>  extern int thermal_generate_netlink_event(u32 orig, enum events event);
>  #else
> --
> 1.7.9.5
>

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

* RE: [RFC PATCH 4/7] Thermal: Add Thermal_trip sysfs node
  2012-12-04  8:30   ` Hongbo Zhang
@ 2012-12-04  8:41     ` R, Durgadoss
  0 siblings, 0 replies; 27+ messages in thread
From: R, Durgadoss @ 2012-12-04  8:41 UTC (permalink / raw)
  To: Hongbo Zhang
  Cc: Zhang, Rui, linux-pm, wni, eduardo.valentin, amit.kachhap, sachin.kamat


> -----Original Message-----
> From: Hongbo Zhang [mailto:hongbo.zhang@linaro.org]
> Sent: Tuesday, December 04, 2012 2:01 PM
> To: R, Durgadoss
> Cc: Zhang, Rui; linux-pm@vger.kernel.org; wni@nvidia.com;
> eduardo.valentin@ti.com; amit.kachhap@linaro.org;
> sachin.kamat@linaro.org
> Subject: Re: [RFC PATCH 4/7] Thermal: Add Thermal_trip sysfs node
> 
> On 17 November 2012 18:45, Durgadoss R <durgadoss.r@intel.com> wrote:
> > This patch adds a thermal_trip directory under
> > /sys/class/thermal/zoneX. This directory contains
> > the trip point values for sensors bound to this
> > zone.
> >
> > Signed-off-by: Durgadoss R <durgadoss.r@intel.com>
> > ---
> >  drivers/thermal/thermal_sys.c |  244
> ++++++++++++++++++++++++++++++++++++++++-
> >  include/linux/thermal.h       |   32 ++++++
> >  2 files changed, 274 insertions(+), 2 deletions(-)
> >
> > diff --git a/drivers/thermal/thermal_sys.c b/drivers/thermal/thermal_sys.c
> > index 70e5f5a..011588a 100644
> > --- a/drivers/thermal/thermal_sys.c
> > +++ b/drivers/thermal/thermal_sys.c
> > @@ -480,9 +480,15 @@ static void remove_sensor_from_zone(struct
> thermal_zone *tz,
> >
> >         sysfs_remove_link(&tz->device.kobj, kobject_name(&ts-
> >device.kobj));
> >
> > +       /* Delete this sensor's trip Kobject */
> > +       kobject_del(tz->kobj_trip[indx]);
> > +
> >         /* Shift the entries in the tz->sensors array */
> > -       for (j = indx; j < MAX_SENSORS_PER_ZONE - 1; j++)
> > +       for (j = indx; j < MAX_SENSORS_PER_ZONE - 1; j++) {
> >                 tz->sensors[j] = tz->sensors[j + 1];
> > +               tz->trip[j] = tz->trip[j + 1];
> > +               tz->kobj_trip[j] = tz->kobj_trip[j + 1];
> > +       }
> >
> >         tz->sensor_indx--;
> >  }
> > @@ -505,6 +511,41 @@ static void remove_cdev_from_zone(struct
> thermal_zone *tz,
> >         tz->cdev_indx--;
> >  }
> >
> > +static struct thermal_zone *get_zone_by_trip_kobj(struct kobject *kobj)
> > +{
> > +       struct thermal_zone *pos;
> > +       struct thermal_zone *tz = NULL;
> > +
> > +       if (!kobj)
> > +               return NULL;
> > +
> > +       mutex_lock(&tz_list_lock);
> > +       for_each_thermal_zone(pos) {
> > +               if (pos->kobj_thermal_trip == kobj) {
> > +                       tz = pos;
> > +                       break;
> > +               }
> > +       }
> > +       mutex_unlock(&tz_list_lock);
> > +       return tz;
> > +}
> > +
> > +static struct thermal_sensor *get_sensor_by_kobj_name(const char
> *name)
> > +{
> > +       struct thermal_sensor *pos;
> > +       struct thermal_sensor *ts = NULL;
> > +
> > +       mutex_lock(&ts_list_lock);
> > +       for_each_thermal_sensor(pos) {
> > +               if (!strcmp(kobject_name(&pos->device.kobj), name)) {
> > +                       ts = pos;
> > +                       break;
> > +               }
> > +       }
> > +       mutex_unlock(&ts_list_lock);
> > +       return ts;
> > +}
> > +
> >  /* sys I/F for thermal zone */
> >
> >  #define to_thermal_zone(_dev) \
> > @@ -859,6 +900,113 @@ policy_show(struct device *dev, struct
> device_attribute *devattr, char *buf)
> >         return sprintf(buf, "%s\n", tz->governor->name);
> >  }
> >
> > +static ssize_t
> > +active_show(struct kobject *kobj, struct kobj_attribute *attr, char *buf)
> > +{
> > +       int i, indx, ret = 0;
> > +       struct thermal_sensor *ts;
> > +       struct thermal_zone *tz;
> > +
> > +       ts = get_sensor_by_kobj_name(kobject_name(kobj));
> > +       if (!ts)
> > +               return -EINVAL;
> > +
> > +       tz = get_zone_by_trip_kobj(kobj->parent);
> > +       if (!tz)
> > +               return -EINVAL;
> > +
> > +       indx = get_sensor_indx(tz, ts);
> > +       if (indx < 0)
> > +               return indx;
> > +
> > +       if (tz->trip[indx]->num_active_trips <= 0)
> > +               return sprintf(buf, "<Not available>\n");
> > +
> > +       ret += sprintf(buf, "0x%x", tz->trip[indx]->active_trip_mask);
> > +       for (i = 0; i < tz->trip[indx]->num_active_trips; i++) {
> > +               ret += sprintf(buf + ret, " %d",
> > +                       tz->trip[indx]->active_trips[i]);
> > +       }
> > +
> > +       ret += sprintf(buf + ret, "\n");
> > +       return ret;
> > +}
> > +
> > +static ssize_t
> > +ptrip_show(struct kobject *kobj, struct kobj_attribute *attr, char *buf)
> Just remind you it is better to use passive_show instead of ptrip_show
> when you remove the unused old codes.

Yes, you told the reason also :-)
I did that because we have another function named passive_show.
So, when we remove the old code, we will change this name also :-)

Thanks,
Durga

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

* Re: [RFC PATCH 2/7] Thermal: Create zone level APIs
  2012-11-17 10:45 ` [RFC PATCH 2/7] Thermal: Create zone " Durgadoss R
  2012-12-03  7:42   ` Hongbo Zhang
@ 2012-12-13  6:23   ` Hongbo Zhang
  2012-12-13 15:00     ` R, Durgadoss
  1 sibling, 1 reply; 27+ messages in thread
From: Hongbo Zhang @ 2012-12-13  6:23 UTC (permalink / raw)
  To: Durgadoss R
  Cc: rui.zhang, linux-pm, wni, eduardo.valentin, amit.kachhap, sachin.kamat

On 17 November 2012 18:45, Durgadoss R <durgadoss.r@intel.com> wrote:
> This patch adds a new thermal_zone structure to
> thermal.h. Also, adds zone level APIs to the thermal
> framework.
>
> Signed-off-by: Durgadoss R <durgadoss.r@intel.com>
> ---
>  drivers/thermal/thermal_sys.c |  206 +++++++++++++++++++++++++++++++++++++++++
>  include/linux/thermal.h       |   25 +++++
>  2 files changed, 231 insertions(+)
>
> diff --git a/drivers/thermal/thermal_sys.c b/drivers/thermal/thermal_sys.c
> index e726c8b..9d386d7 100644
> --- a/drivers/thermal/thermal_sys.c
> +++ b/drivers/thermal/thermal_sys.c
> @@ -44,19 +44,28 @@ MODULE_DESCRIPTION("Generic thermal management sysfs support");
>  MODULE_LICENSE("GPL");
>
>  static DEFINE_IDR(thermal_tz_idr);
> +static DEFINE_IDR(thermal_zone_idr);
>  static DEFINE_IDR(thermal_cdev_idr);
>  static DEFINE_IDR(thermal_sensor_idr);
>  static DEFINE_MUTEX(thermal_idr_lock);
>
>  static LIST_HEAD(thermal_tz_list);
>  static LIST_HEAD(thermal_sensor_list);
> +static LIST_HEAD(thermal_zone_list);
>  static LIST_HEAD(thermal_cdev_list);
>  static LIST_HEAD(thermal_governor_list);
>
>  static DEFINE_MUTEX(thermal_list_lock);
>  static DEFINE_MUTEX(ts_list_lock);
> +static DEFINE_MUTEX(tz_list_lock);
>  static DEFINE_MUTEX(thermal_governor_lock);
>
> +#define for_each_thermal_sensor(pos) \
> +       list_for_each_entry(pos, &thermal_sensor_list, node)
> +
> +#define for_each_thermal_zone(pos) \
> +       list_for_each_entry(pos, &thermal_zone_list, node)
> +
>  static struct thermal_governor *__find_governor(const char *name)
>  {
>         struct thermal_governor *pos;
> @@ -419,15 +428,62 @@ static void thermal_zone_device_check(struct work_struct *work)
>         thermal_zone_device_update(tz);
>  }
>
> +static int get_sensor_indx(struct thermal_zone *tz, struct thermal_sensor *ts)
> +{
> +       int i, indx = -EINVAL;
> +
> +       if (!tz || !ts)
> +               return -EINVAL;
> +
> +       mutex_lock(&ts_list_lock);
> +       for (i = 0; i < tz->sensor_indx; i++) {
> +               if (tz->sensors[i] == ts) {
> +                       indx = i;
> +                       break;
> +               }
> +       }
> +       mutex_unlock(&ts_list_lock);
> +       return indx;
> +}
> +
> +static void remove_sensor_from_zone(struct thermal_zone *tz,
> +                               struct thermal_sensor *ts)
> +{
> +       int indx, j;
> +
> +       indx = get_sensor_indx(tz, ts);
> +       if (indx < 0)
> +               return;
> +
> +       sysfs_remove_link(&tz->device.kobj, kobject_name(&ts->device.kobj));
> +
> +       /* Shift the entries in the tz->sensors array */
> +       for (j = indx; j < MAX_SENSORS_PER_ZONE - 1; j++)
> +               tz->sensors[j] = tz->sensors[j + 1];
> +
> +       tz->sensor_indx--;
> +}
> +
>  /* sys I/F for thermal zone */
>
>  #define to_thermal_zone(_dev) \
>         container_of(_dev, struct thermal_zone_device, device)
>
> +#define to_zone(_dev) \
> +       container_of(_dev, struct thermal_zone, device)
> +
>  #define to_thermal_sensor(_dev) \
>         container_of(_dev, struct thermal_sensor, device)
>
>  static ssize_t
> +zone_name_show(struct device *dev, struct device_attribute *attr, char *buf)
> +{
> +       struct thermal_zone *tz = to_zone(dev);
> +
> +       return sprintf(buf, "%s\n", tz->name);
> +}
> +
> +static ssize_t
>  sensor_name_show(struct device *dev, struct device_attribute *attr, char *buf)
>  {
>         struct thermal_sensor *ts = to_thermal_sensor(dev);
> @@ -772,6 +828,8 @@ static DEVICE_ATTR(policy, S_IRUGO | S_IWUSR, policy_show, policy_store);
>  static DEVICE_ATTR(sensor_name, 0444, sensor_name_show, NULL);
>  static DEVICE_ATTR(temp_input, 0444, sensor_temp_show, NULL);
>
> +static DEVICE_ATTR(zone_name, 0444, zone_name_show, NULL);
> +
>  /* sys I/F for cooling device */
>  #define to_cooling_device(_dev)        \
>         container_of(_dev, struct thermal_cooling_device, device)
> @@ -1557,6 +1615,146 @@ static void remove_trip_attrs(struct thermal_zone_device *tz)
>         kfree(tz->trip_hyst_attrs);
>  }
>
> +struct thermal_zone *create_thermal_zone(const char *name, void *devdata)
Durgaross,
Since more sensors can be added into one thermal zone, think about
this situation that every sensor is in itself file separately:

sensorA_file.c:
if common_zone_for_AB not there;
create common_zone_for_AB;
add sensorA into common_zone_for_AB;

sensorB_file.c:
if common_zone_for_AB not there;
create common_zone_for_AB;
add sensorB into common_zone_for_AB;

But how to check dedicate thermal zone is created or not? we are
lacking of this interface.
Here are two ways to achieve this from my point of view:
a)
add interface get_thermal_zone_byname(const char *name) which will
walk through the thermal_zone_list.
b)
add one more parameter for current interface, like this
create_thermal_zone(const char *name, void *devdata, bool reuse)
if reuse==ture {
if thermal zone already created, return it;
else create thermal zone;
} else {
if thermal zone already created, return error;
else create thermal zone;
}

I prefer a), how do you think about it?

> +{
> +       struct thermal_zone *tz;
> +       int ret;
> +
> +       if (!name || (name && strlen(name) >= THERMAL_NAME_LENGTH))
> +               return ERR_PTR(-EINVAL);
> +
> +       tz = kzalloc(sizeof(*tz), GFP_KERNEL);
> +       if (!tz)
> +               return ERR_PTR(-ENOMEM);
> +
> +       idr_init(&tz->idr);
> +       ret = get_idr(&thermal_zone_idr, &thermal_idr_lock, &tz->id);
> +       if (ret)
> +               goto exit_free;
> +
> +       strcpy(tz->name, name);
> +       tz->devdata = devdata;
> +       tz->device.class = &thermal_class;
> +
> +       dev_set_name(&tz->device, "zone%d", tz->id);
> +       ret = device_register(&tz->device);
> +       if (ret)
> +               goto exit_idr;
> +
> +       ret = device_create_file(&tz->device, &dev_attr_zone_name);
> +       if (ret)
> +               goto exit_unregister;
> +
> +       /* Add this zone to the global list of thermal zones */
> +       mutex_lock(&tz_list_lock);
> +       list_add_tail(&tz->node, &thermal_zone_list);
> +       mutex_unlock(&tz_list_lock);
> +       return tz;
> +
> +exit_unregister:
> +       device_unregister(&tz->device);
> +exit_idr:
> +       release_idr(&thermal_zone_idr, &thermal_idr_lock, tz->id);
> +exit_free:
> +       kfree(tz);
> +       return ERR_PTR(ret);
> +}
> +EXPORT_SYMBOL(create_thermal_zone);
> +
> +void remove_thermal_zone(struct thermal_zone *tz)
> +{
> +       struct thermal_zone *pos, *next;
> +       bool found = false;
> +
> +       if (!tz)
> +               return;
> +
> +       mutex_lock(&tz_list_lock);
> +
> +       list_for_each_entry_safe(pos, next, &thermal_zone_list, node) {
> +               if (pos == tz) {
> +                       list_del(&tz->node);
> +                       found = true;
> +                       break;
> +               }
> +       }
> +
> +       if (!found)
> +               goto exit;
> +
> +       device_remove_file(&tz->device, &dev_attr_zone_name);
> +
> +       release_idr(&thermal_zone_idr, &thermal_idr_lock, tz->id);
> +       idr_destroy(&tz->idr);
> +
> +       device_unregister(&tz->device);
> +       kfree(tz);
> +exit:
> +       mutex_unlock(&tz_list_lock);
> +       return;
> +}
> +EXPORT_SYMBOL(remove_thermal_zone);
> +
> +struct thermal_sensor *get_sensor_by_name(const char *name)
> +{
> +       struct thermal_sensor *pos;
> +       struct thermal_sensor *ts = NULL;
> +
> +       mutex_lock(&ts_list_lock);
> +       for_each_thermal_sensor(pos) {
> +               if (!strnicmp(pos->name, name, THERMAL_NAME_LENGTH)) {
> +                       ts = pos;
> +                       break;
> +               }
> +       }
> +       mutex_unlock(&ts_list_lock);
> +       return ts;
> +}
> +EXPORT_SYMBOL(get_sensor_by_name);
> +
> +int add_sensor_to_zone_by_name(struct thermal_zone *tz, const char *name)
> +{
> +       int ret;
> +       struct thermal_sensor *ts = get_sensor_by_name(name);
> +
> +       if (!tz || !ts)
> +               return -EINVAL;
> +
> +       mutex_lock(&tz_list_lock);
> +
> +       /* Ensure we are not adding the same sensor again!! */
> +       ret = get_sensor_indx(tz, ts);
> +       if (ret >= 0) {
> +               ret = -EEXIST;
> +               goto exit_zone;
> +       }
> +
> +       mutex_lock(&ts_list_lock);
> +
> +       ret = sysfs_create_link(&tz->device.kobj, &ts->device.kobj,
> +                               kobject_name(&ts->device.kobj));
> +       if (ret)
> +               goto exit_sensor;
> +
> +       tz->sensors[tz->sensor_indx++] = ts;
> +
> +exit_sensor:
> +       mutex_unlock(&ts_list_lock);
> +exit_zone:
> +       mutex_unlock(&tz_list_lock);
> +       return ret;
> +}
> +EXPORT_SYMBOL(add_sensor_to_zone_by_name);
> +
> +int add_sensor_to_zone(struct thermal_zone *tz, struct thermal_sensor *ts)
> +{
> +       if (!tz || !ts)
> +               return -EINVAL;
> +
> +       return add_sensor_to_zone_by_name(tz, ts->name);
> +}
> +EXPORT_SYMBOL(add_sensor_to_zone);
> +
>  /**
>   * thermal_sensor_register - register a new thermal sensor
>   * @name:      name of the thermal sensor
> @@ -1624,6 +1822,7 @@ EXPORT_SYMBOL(thermal_sensor_register);
>  void thermal_sensor_unregister(struct thermal_sensor *ts)
>  {
>         int i;
> +       struct thermal_zone *tz;
>         struct thermal_sensor *pos, *next;
>         bool found = false;
>
> @@ -1643,6 +1842,13 @@ void thermal_sensor_unregister(struct thermal_sensor *ts)
>         if (!found)
>                 return;
>
> +       mutex_lock(&tz_list_lock);
> +
> +       for_each_thermal_zone(tz)
> +               remove_sensor_from_zone(tz, ts);
> +
> +       mutex_unlock(&tz_list_lock);
> +
>         for (i = 0; i < ts->thresholds; i++)
>                 device_remove_file(&ts->device, &ts->thresh_attrs[i].attr);
>
> diff --git a/include/linux/thermal.h b/include/linux/thermal.h
> index e2f85ec..38438be 100644
> --- a/include/linux/thermal.h
> +++ b/include/linux/thermal.h
> @@ -49,6 +49,11 @@
>  /* Default Thermal Governor: Does Linear Throttling */
>  #define DEFAULT_THERMAL_GOVERNOR       "step_wise"
>
> +/* Maximum number of sensors, allowed in a thermal zone
> + * We will start with 5, and increase if needed.
> + */
> +#define MAX_SENSORS_PER_ZONE           5
> +
>  struct thermal_sensor;
>  struct thermal_zone_device;
>  struct thermal_cooling_device;
> @@ -191,6 +196,21 @@ struct thermal_zone_device {
>         struct delayed_work poll_queue;
>  };
>
> +struct thermal_zone {
> +       char name[THERMAL_NAME_LENGTH];
> +       int id;
> +       void *devdata;
> +       struct thermal_zone *ops;
> +       struct thermal_governor *governor;
> +       struct idr idr;
> +       struct device device;
> +       struct list_head node;
> +
> +       /* Sensor level information */
> +       int sensor_indx; /* index into 'sensors' array */
> +       struct thermal_sensor *sensors[MAX_SENSORS_PER_ZONE];
> +};
> +
>  /* Structure that holds thermal governor information */
>  struct thermal_governor {
>         char name[THERMAL_NAME_LENGTH];
> @@ -264,6 +284,11 @@ struct thermal_sensor *thermal_sensor_register(const char *,
>  void thermal_sensor_unregister(struct thermal_sensor *);
>  int enable_sensor_thresholds(struct thermal_sensor *, int);
>
> +struct thermal_zone *create_thermal_zone(const char *, void *);
> +void remove_thermal_zone(struct thermal_zone *);
> +int add_sensor_to_zone(struct thermal_zone *, struct thermal_sensor *);
> +int add_sensor_to_zone_by_name(struct thermal_zone *, const char *);
> +
>  #ifdef CONFIG_NET
>  extern int thermal_generate_netlink_event(u32 orig, enum events event);
>  #else
> --
> 1.7.9.5
>

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

* RE: [RFC PATCH 2/7] Thermal: Create zone level APIs
  2012-12-13  6:23   ` Hongbo Zhang
@ 2012-12-13 15:00     ` R, Durgadoss
  2012-12-14  4:10       ` Hongbo Zhang
  0 siblings, 1 reply; 27+ messages in thread
From: R, Durgadoss @ 2012-12-13 15:00 UTC (permalink / raw)
  To: Hongbo Zhang
  Cc: Zhang, Rui, linux-pm, wni, eduardo.valentin, amit.kachhap, sachin.kamat

Hi,


> -----Original Message-----
> From: linux-pm-owner@vger.kernel.org [mailto:linux-pm-
> owner@vger.kernel.org] On Behalf Of Hongbo Zhang
> Sent: Thursday, December 13, 2012 11:53 AM
> To: R, Durgadoss
> Cc: Zhang, Rui; linux-pm@vger.kernel.org; wni@nvidia.com;
> eduardo.valentin@ti.com; amit.kachhap@linaro.org;
> sachin.kamat@linaro.org
> Subject: Re: [RFC PATCH 2/7] Thermal: Create zone level APIs
> 
> On 17 November 2012 18:45, Durgadoss R <durgadoss.r@intel.com> wrote:
> > This patch adds a new thermal_zone structure to
> > thermal.h. Also, adds zone level APIs to the thermal
> > framework.
> >
> > Signed-off-by: Durgadoss R <durgadoss.r@intel.com>

[A big cut.]

> >  #define to_cooling_device(_dev)        \
> >         container_of(_dev, struct thermal_cooling_device, device)
> > @@ -1557,6 +1615,146 @@ static void remove_trip_attrs(struct
> thermal_zone_device *tz)
> >         kfree(tz->trip_hyst_attrs);
> >  }
> >
> > +struct thermal_zone *create_thermal_zone(const char *name, void
> *devdata)
> Durgaross,
> Since more sensors can be added into one thermal zone, think about
> this situation that every sensor is in itself file separately:

Yes, we thought about this scenario.
The way the new framework is designed is like below:

The thermal sensor source file can be generic (can be any sensor driver, in any
subsystem). This driver will use the sensor APIs and register with thermal
framework to participate in platform Thermal management. This does not
(and should not) know about which zone it belongs to, or any other information
about platform thermals. A sensor driver is a standalone piece of code, which
can optionally register with thermal framework.

However, for any platform, there should be a platformX_thermal.c file,
which will know about the platform thermal characteristics (like how many sensors,
zones, cooling devices, etc.. And how they are related to each other i.e the
mapping information). Only in this file, the zone level APIs should be used, in
which case the file will have all information required to attach various sensors
to a particular zone.

This way, we can have one platform level thermal file, which can support
multiple platforms (may be)using the same set of sensors (but)binded in a different way.
This file can get the platform thermal information through Firmware,
ACPI tables, device tree etc.

Unfortunately, today we don't have many drivers that can be clearly differentiated
as 'sensor_file.c' and 'platform_thermal_file.c'. But very soon we will need/have.
The reason I am saying this is because we are seeing a lot of chip drivers,
starting to use thermal framework, and we should keep it really light-weight
for them to do so.

An Example: drivers/hwmon/emc1403.c - a generic thermal chip driver
In one platform this sensor can belong to 'ZoneA' and in another the
same can belong to 'ZoneB'. But, emc1403.c does not really care about
where does it belong. It just reports temperature.
[Okay, I just picked an example, it doesn't register with framework,
as of today :-)]

> 
> sensorA_file.c:
> if common_zone_for_AB not there;
> create common_zone_for_AB;

This create_zone should not even be in sensorA_file.c.
It should be moved to platform level file.

> add sensorA into common_zone_for_AB;
> 
> sensorB_file.c:
> if common_zone_for_AB not there;
> create common_zone_for_AB;
> add sensorB into common_zone_for_AB;
> 

Same here..

> But how to check dedicate thermal zone is created or not? we are
> lacking of this interface.
> Here are two ways to achieve this from my point of view:
> a)
> add interface get_thermal_zone_byname(const char *name) which will
> walk through the thermal_zone_list.

However, (despite this problem we are talking about)
we can introduce this API, if needed.

> b)
> add one more parameter for current interface, like this
> create_thermal_zone(const char *name, void *devdata, bool reuse)
> if reuse==ture {
> if thermal zone already created, return it;
> else create thermal zone;
> } else {
> if thermal zone already created, return error;
> else create thermal zone;
> }
> 
> I prefer a), how do you think about it?

I know I wrote a lengthy explanation. Let me know if it makes sense.
If it does, then probably I will add it to our Documentation file.

Thanks,
Durga

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

* Re: [RFC PATCH 2/7] Thermal: Create zone level APIs
  2012-12-13 15:00     ` R, Durgadoss
@ 2012-12-14  4:10       ` Hongbo Zhang
  2012-12-14  5:10         ` R, Durgadoss
  0 siblings, 1 reply; 27+ messages in thread
From: Hongbo Zhang @ 2012-12-14  4:10 UTC (permalink / raw)
  To: R, Durgadoss
  Cc: Zhang, Rui, linux-pm, wni, eduardo.valentin, amit.kachhap, sachin.kamat

On 13 December 2012 23:00, R, Durgadoss <durgadoss.r@intel.com> wrote:
> Hi,
>
>
>> -----Original Message-----
>> From: linux-pm-owner@vger.kernel.org [mailto:linux-pm-
>> owner@vger.kernel.org] On Behalf Of Hongbo Zhang
>> Sent: Thursday, December 13, 2012 11:53 AM
>> To: R, Durgadoss
>> Cc: Zhang, Rui; linux-pm@vger.kernel.org; wni@nvidia.com;
>> eduardo.valentin@ti.com; amit.kachhap@linaro.org;
>> sachin.kamat@linaro.org
>> Subject: Re: [RFC PATCH 2/7] Thermal: Create zone level APIs
>>
>> On 17 November 2012 18:45, Durgadoss R <durgadoss.r@intel.com> wrote:
>> > This patch adds a new thermal_zone structure to
>> > thermal.h. Also, adds zone level APIs to the thermal
>> > framework.
>> >
>> > Signed-off-by: Durgadoss R <durgadoss.r@intel.com>
>
> [A big cut.]
>
>> >  #define to_cooling_device(_dev)        \
>> >         container_of(_dev, struct thermal_cooling_device, device)
>> > @@ -1557,6 +1615,146 @@ static void remove_trip_attrs(struct
>> thermal_zone_device *tz)
>> >         kfree(tz->trip_hyst_attrs);
>> >  }
>> >
>> > +struct thermal_zone *create_thermal_zone(const char *name, void
>> *devdata)
>> Durgaross,
>> Since more sensors can be added into one thermal zone, think about
>> this situation that every sensor is in itself file separately:
>
> Yes, we thought about this scenario.
> The way the new framework is designed is like below:
>
> The thermal sensor source file can be generic (can be any sensor driver, in any
> subsystem). This driver will use the sensor APIs and register with thermal
> framework to participate in platform Thermal management. This does not
> (and should not) know about which zone it belongs to, or any other information
> about platform thermals. A sensor driver is a standalone piece of code, which
> can optionally register with thermal framework.
>
> However, for any platform, there should be a platformX_thermal.c file,
> which will know about the platform thermal characteristics (like how many sensors,
> zones, cooling devices, etc.. And how they are related to each other i.e the
> mapping information). Only in this file, the zone level APIs should be used, in
> which case the file will have all information required to attach various sensors
> to a particular zone.
I guess you will remove the bind callback, I suggest to remove it if
you don't have this plan.
A match callback or/and mapping data can be used to identify the
binding relationship, the current binding process is abundant and
strange a bit.
>
> This way, we can have one platform level thermal file, which can support
> multiple platforms (may be)using the same set of sensors (but)binded in a different way.
> This file can get the platform thermal information through Firmware,
> ACPI tables, device tree etc.
>
> Unfortunately, today we don't have many drivers that can be clearly differentiated
> as 'sensor_file.c' and 'platform_thermal_file.c'. But very soon we will need/have.
> The reason I am saying this is because we are seeing a lot of chip drivers,
> starting to use thermal framework, and we should keep it really light-weight
> for them to do so.
>
> An Example: drivers/hwmon/emc1403.c - a generic thermal chip driver
> In one platform this sensor can belong to 'ZoneA' and in another the
> same can belong to 'ZoneB'. But, emc1403.c does not really care about
> where does it belong. It just reports temperature.
> [Okay, I just picked an example, it doesn't register with framework,
> as of today :-)]
Clear about the above information.
This is a good design, I believe more and more drivers will use this.
But much efforts are needed.
>
>>
>> sensorA_file.c:
>> if common_zone_for_AB not there;
>> create common_zone_for_AB;
>
> This create_zone should not even be in sensorA_file.c.
> It should be moved to platform level file.
>
>> add sensorA into common_zone_for_AB;
>>
>> sensorB_file.c:
>> if common_zone_for_AB not there;
>> create common_zone_for_AB;
>> add sensorB into common_zone_for_AB;
>>
>
> Same here..
>
>> But how to check dedicate thermal zone is created or not? we are
>> lacking of this interface.
>> Here are two ways to achieve this from my point of view:
>> a)
>> add interface get_thermal_zone_byname(const char *name) which will
>> walk through the thermal_zone_list.
>
> However, (despite this problem we are talking about)
> we can introduce this API, if needed.
>
>> b)
>> add one more parameter for current interface, like this
>> create_thermal_zone(const char *name, void *devdata, bool reuse)
>> if reuse==ture {
>> if thermal zone already created, return it;
>> else create thermal zone;
>> } else {
>> if thermal zone already created, return error;
>> else create thermal zone;
>> }
>>
>> I prefer a), how do you think about it?
>
> I know I wrote a lengthy explanation. Let me know if it makes sense.
> If it does, then probably I will add it to our Documentation file.
Yes, It really makes sense.
Thanks.
>
> Thanks,
> Durga

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

* RE: [RFC PATCH 2/7] Thermal: Create zone level APIs
  2012-12-14  4:10       ` Hongbo Zhang
@ 2012-12-14  5:10         ` R, Durgadoss
  0 siblings, 0 replies; 27+ messages in thread
From: R, Durgadoss @ 2012-12-14  5:10 UTC (permalink / raw)
  To: Hongbo Zhang
  Cc: Zhang, Rui, linux-pm, wni, eduardo.valentin, amit.kachhap, sachin.kamat

Hi,


> -----Original Message-----
> From: Hongbo Zhang [mailto:hongbo.zhang@linaro.org]
> Sent: Friday, December 14, 2012 9:41 AM
> To: R, Durgadoss
> Cc: Zhang, Rui; linux-pm@vger.kernel.org; wni@nvidia.com;
> eduardo.valentin@ti.com; amit.kachhap@linaro.org;
> sachin.kamat@linaro.org
> Subject: Re: [RFC PATCH 2/7] Thermal: Create zone level APIs
> 
> On 13 December 2012 23:00, R, Durgadoss <durgadoss.r@intel.com> wrote:
> > Hi,
> >
> >
> >> -----Original Message-----
> >> From: linux-pm-owner@vger.kernel.org [mailto:linux-pm-
> >> owner@vger.kernel.org] On Behalf Of Hongbo Zhang
> >> Sent: Thursday, December 13, 2012 11:53 AM
> >> To: R, Durgadoss
> >> Cc: Zhang, Rui; linux-pm@vger.kernel.org; wni@nvidia.com;
> >> eduardo.valentin@ti.com; amit.kachhap@linaro.org;
> >> sachin.kamat@linaro.org
> >> Subject: Re: [RFC PATCH 2/7] Thermal: Create zone level APIs
> >>
> >> On 17 November 2012 18:45, Durgadoss R <durgadoss.r@intel.com>
> wrote:
> >> > This patch adds a new thermal_zone structure to
> >> > thermal.h. Also, adds zone level APIs to the thermal
> >> > framework.
> >> >
> >> > Signed-off-by: Durgadoss R <durgadoss.r@intel.com>
> >
> > [A big cut.]
> >
> >> >  #define to_cooling_device(_dev)        \
> >> >         container_of(_dev, struct thermal_cooling_device, device)
> >> > @@ -1557,6 +1615,146 @@ static void remove_trip_attrs(struct
> >> thermal_zone_device *tz)
> >> >         kfree(tz->trip_hyst_attrs);
> >> >  }
> >> >
> >> > +struct thermal_zone *create_thermal_zone(const char *name, void
> >> *devdata)
> >> Durgaross,
> >> Since more sensors can be added into one thermal zone, think about
> >> this situation that every sensor is in itself file separately:
> >
> > Yes, we thought about this scenario.
> > The way the new framework is designed is like below:
> >
> > The thermal sensor source file can be generic (can be any sensor driver, in
> any
> > subsystem). This driver will use the sensor APIs and register with thermal
> > framework to participate in platform Thermal management. This does not
> > (and should not) know about which zone it belongs to, or any other
> information
> > about platform thermals. A sensor driver is a standalone piece of code,
> which
> > can optionally register with thermal framework.
> >
> > However, for any platform, there should be a platformX_thermal.c file,
> > which will know about the platform thermal characteristics (like how many
> sensors,
> > zones, cooling devices, etc.. And how they are related to each other i.e the
> > mapping information). Only in this file, the zone level APIs should be used,
> in
> > which case the file will have all information required to attach various
> sensors
> > to a particular zone.
> I guess you will remove the bind callback, I suggest to remove it if
> you don't have this plan.

Yes, We will remove this.

> A match callback or/and mapping data can be used to identify the
> binding relationship, the current binding process is abundant and
> strange a bit.

Yes, the mapping data can be used.

> >
> > This way, we can have one platform level thermal file, which can support
> > multiple platforms (may be)using the same set of sensors (but)binded in a
> different way.
> > This file can get the platform thermal information through Firmware,
> > ACPI tables, device tree etc.
> >
> > Unfortunately, today we don't have many drivers that can be clearly
> differentiated
> > as 'sensor_file.c' and 'platform_thermal_file.c'. But very soon we will
> need/have.
> > The reason I am saying this is because we are seeing a lot of chip drivers,
> > starting to use thermal framework, and we should keep it really light-
> weight
> > for them to do so.
> >
> > An Example: drivers/hwmon/emc1403.c - a generic thermal chip driver
> > In one platform this sensor can belong to 'ZoneA' and in another the
> > same can belong to 'ZoneB'. But, emc1403.c does not really care about
> > where does it belong. It just reports temperature.
> > [Okay, I just picked an example, it doesn't register with framework,
> > as of today :-)]

> Clear about the above information.

Thank you :-)

> This is a good design, I believe more and more drivers will use this.
> But much efforts are needed.

Yes, we need quite some code modifications.

> >
> >>
> >> sensorA_file.c:
> >> if common_zone_for_AB not there;
> >> create common_zone_for_AB;
> >
> > This create_zone should not even be in sensorA_file.c.
> > It should be moved to platform level file.
> >
> >> add sensorA into common_zone_for_AB;
> >>
> >> sensorB_file.c:
> >> if common_zone_for_AB not there;
> >> create common_zone_for_AB;
> >> add sensorB into common_zone_for_AB;
> >>
> >
> > Same here..
> >
> >> But how to check dedicate thermal zone is created or not? we are
> >> lacking of this interface.
> >> Here are two ways to achieve this from my point of view:
> >> a)
> >> add interface get_thermal_zone_byname(const char *name) which will
> >> walk through the thermal_zone_list.
> >
> > However, (despite this problem we are talking about)
> > we can introduce this API, if needed.
> >
> >> b)
> >> add one more parameter for current interface, like this
> >> create_thermal_zone(const char *name, void *devdata, bool reuse)
> >> if reuse==ture {
> >> if thermal zone already created, return it;
> >> else create thermal zone;
> >> } else {
> >> if thermal zone already created, return error;
> >> else create thermal zone;
> >> }
> >>
> >> I prefer a), how do you think about it?
> >
> > I know I wrote a lengthy explanation. Let me know if it makes sense.
> > If it does, then probably I will add it to our Documentation file.
> Yes, It really makes sense.
> Thanks.

Okay, Then I am adding this to our Documentation file.

Thanks,
Durga

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

* Re: [RFC PATCH 0/7] Support for Multiple sensors per zone
  2012-11-17 10:45 [RFC PATCH 0/7] Support for Multiple sensors per zone Durgadoss R
                   ` (7 preceding siblings ...)
  2012-12-03  9:01 ` [RFC PATCH 0/7] Support for Multiple sensors per zone Hongbo Zhang
@ 2013-01-02 15:48 ` Eduardo Valentin
  2013-01-02 16:29   ` R, Durgadoss
  8 siblings, 1 reply; 27+ messages in thread
From: Eduardo Valentin @ 2013-01-02 15:48 UTC (permalink / raw)
  To: Durgadoss R
  Cc: rui.zhang, linux-pm, wni, amit.kachhap, hongbo.zhang, sachin.kamat


Hello Durga,

First of all, sorry for the late answer. Happy New Year to you BTW. :-)

On 17-11-2012 12:45, Durgadoss R wrote:
> This patch series attempts to add support for multiple
> sensors per zone. The work is based on the Thermal discussion
> happened in plumbers conference 2012, here:
> http://www.linuxplumbersconf.org/2012/schedule/
> Title: "Enhancing the Thermal Management Infrastructure in Linux"
>

On the above discussion one point which was not really clear was if we 
would create virtual thermal zones, with a fop to determine its 
temperature in a given time, or if we would write APIs to fetch 
temperature from a thermal zone and then in the platform code to would 
derive the real temperature.

 From this patch series, looks like we are going to both directions at 
the same time. Let me try to understand your proposal by introducing a 
simple example.

Let us assume a simple scenario which we have a thermal zone with 2 
sensors, say, for skin management, one for back cover and one for LCD. 
Assume also you have two different HW sensors, for whatever reason. By 
your proposal, we would have two simple sensor drivers, one for each HW, 
which is good. A platform driver that would add these two sensor 
instances into a thermal zone.

Now. what I don't know is how to determine the temperature of that zone. 
I believe we need to have a thermal zone fops with get temperature. I am 
assuming the platform driver would be the one who introduces the thermal 
zone, and adds the sensors, and knows how to determine the temperature 
of that zone. This way, one can easily write a function to determine the 
"summary temperature". Remember that using index to select one specific 
temperature sensor for a given time may not be enough, as there are 
scenarios in which one may write an equation which uses all sensors 
temperature values to determine the ending zone temperature.

> The intention is to make it easy for generic sensor drivers
> to register with the framework, and let them participate in
> platform thermal management. Another goal is to expose the
> binding information in a consistent way so that user space
> can consume the information and potentially manage platform thermals.
>
> This series contains 7 patches:
> Patch 1/7: Creates new sensor level APIs
> Patch 2/7: Creates new zone level APIs. The existing tzd structure is
> 	   kept as such for clarity and compatibility purposes.
> Patch 3/7: Creates functions to add/remove a cdev to/from a zone. The
> 	   existing tcd structure need not be modified.
> Patch 4/7: Adds a thermal_trip sysfs node, which exposes various trip
> 	   points for all sensors present in a zone.
> Patch 5/7: Adds a thermal_map sysfs node. It is a compact representation
> 	   of the binding relationship between a sensor and a cdev,
> 	   within a zone.
> Patch 6/7: Creates Documentation for the new APIs. A new file is
> 	   created for clarity. Final goal is to merge with the existing
> 	   file or refactor the files, as whatever seems appropriate.
> Patch 7/7: A dummy driver that can be used for testing. This is not for merge.
>
> Next steps:
>   1. Move all the existing drivers to the new implementation model.
>      Help welcomed from individual driver authors/maintainers for this.
>   2. Make the thermal governors work with this new model.
>   3. Remove old/unused code from thermal_sys.c.
>   4. Add more detailed documentation
>
>   I didn't want to submit patches for all these in one-go, since it
>   might end-up being difficult to comprehend, besides delaying the
>   review process. The other obvious reason being I cannot test all
>   the changes on various drivers for 1.
>
>   All these patches have been tested on a Core-i5 desktop running
>   ubuntu 12.04 and an atom notebook running ubuntu 11.10.
>   Kindly help review.
>
> Durgadoss R (7):
>    Thermal: Create sensor level APIs
>    Thermal: Create zone level APIs
>    Thermal: Add APIs to bind cdev to new zone structure
>    Thermal: Add Thermal_trip sysfs node
>    Thermal: Add 'thermal_map' sysfs node
>    Thermal: Add Documentation to new APIs
>    Thermal: Dummy driver used for testing
>
>   Documentation/thermal/sysfs-api2.txt |  213 ++++++++
>   drivers/thermal/Kconfig              |    5 +
>   drivers/thermal/Makefile             |    3 +
>   drivers/thermal/thermal_sys.c        |  915 ++++++++++++++++++++++++++++++++++
>   drivers/thermal/thermal_test.c       |  321 ++++++++++++
>   include/linux/thermal.h              |  118 +++++
>   6 files changed, 1575 insertions(+)
>   create mode 100644 Documentation/thermal/sysfs-api2.txt
>   create mode 100644 drivers/thermal/thermal_test.c
>


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

* RE: [RFC PATCH 0/7] Support for Multiple sensors per zone
  2013-01-02 15:48 ` Eduardo Valentin
@ 2013-01-02 16:29   ` R, Durgadoss
  2013-01-02 16:46     ` Eduardo Valentin
  0 siblings, 1 reply; 27+ messages in thread
From: R, Durgadoss @ 2013-01-02 16:29 UTC (permalink / raw)
  To: Eduardo Valentin
  Cc: Zhang, Rui, linux-pm, wni, amit.kachhap, hongbo.zhang, sachin.kamat

Hello Eduardo,

> -----Original Message-----
> From: Eduardo Valentin [mailto:eduardo.valentin@ti.com]
> Sent: Wednesday, January 02, 2013 9:18 PM
> To: R, Durgadoss
> Cc: Zhang, Rui; linux-pm@vger.kernel.org; wni@nvidia.com;
> amit.kachhap@linaro.org; hongbo.zhang@linaro.org;
> sachin.kamat@linaro.org
> Subject: Re: [RFC PATCH 0/7] Support for Multiple sensors per zone
> 
> 
> Hello Durga,
> 
> First of all, sorry for the late answer. Happy New Year to you BTW. :-)

Wish you a Happy New Year too :-)
Yeah, we are talking after a long time!!

> 
> On 17-11-2012 12:45, Durgadoss R wrote:
> > This patch series attempts to add support for multiple
> > sensors per zone. The work is based on the Thermal discussion
> > happened in plumbers conference 2012, here:
> > http://www.linuxplumbersconf.org/2012/schedule/
> > Title: "Enhancing the Thermal Management Infrastructure in Linux"
> >
> 
> On the above discussion one point which was not really clear was if we
> would create virtual thermal zones, with a fop to determine its
> temperature in a given time, or if we would write APIs to fetch
> temperature from a thermal zone and then in the platform code to would
> derive the real temperature.

A really difficult but interesting question; Happy to answer :-)
Actually we discussed this very same point various times internally,
before coming up with this new framework. Let me explain that in
brief to you.

> 
>  From this patch series, looks like we are going to both directions at
> the same time. Let me try to understand your proposal by introducing a
> simple example.
> 
> Let us assume a simple scenario which we have a thermal zone with 2
> sensors, say, for skin management, one for back cover and one for LCD.
> Assume also you have two different HW sensors, for whatever reason. By
> your proposal, we would have two simple sensor drivers, one for each HW,
> which is good. A platform driver that would add these two sensor
> instances into a thermal zone.

Perfect. Valid example.

> 
> Now. what I don't know is how to determine the temperature of that zone.

Yeah. Here we are.
>From the new framework onwards, we are treating the 'zone' as a complete
virtual concept. A zone can have multiple sensors reporting temperature.

To compute the 'theoretical zone temperature', consider 'zone' as a 'virtual
sensor'. This means, the platform driver will register one more sensor using
thermal_sensor_register API with a name 'virtual_XXXX' (or something like
that; we have not finalized the name yet). This sensor can be added to the
required zone also. Now, to compute the zone temperature, the 'get_temp'
callback of this sensor (inside the platform driver) can do 'whatever magic
it wants to do'. 
A rather simple magic could be:
temp_of_virtual_sensor = (sum of all sensor
temperatures in this zone)/num_sensors_in_this_zone.

This way, we could provide trip_points & thresholds for this virtual sensor
also. i.e. everything else remains same.

> I believe we need to have a thermal zone fops with get temperature. I am

We thought through this to some extent.
Assume we introduce a 'temp' sysfs interface (and the fops) for zone temperature.
Now, we have to provide trip_points and thresholds also for this; Then, in the
governors, what should we refer to ? on what basis shall we take actions ?
Based on sensor temperature crossing a trip point ? or
Based on the zone temperature crossing its own trip point ?
If it is zone based, then it has to be 'polled' because a virtual zone
cannot support programmable thresholds.

Moreover, the platform data mapping is also between sensors and
cooling devices. A close look at patches 4 & 5 will explain this.
So, If we go by 'zone' = 'virtual sensor',
the governors can work as usual, and the way we provide platform data
remains the same etc.. Hence, this idea was chosen.

This 'virtual sensor' is also one important reason why we want to
maintain the separation between 'sensor drivers' and 'platform drivers'.
One that works for the hardware, and the other which can do magic :-)

Let me know if this makes sense.

Thanks again for the question!!

Thanks,
Durga

> assuming the platform driver would be the one who introduces the thermal
> zone, and adds the sensors, and knows how to determine the temperature
> of that zone. This way, one can easily write a function to determine the
> "summary temperature". Remember that using index to select one specific
> temperature sensor for a given time may not be enough, as there are
> scenarios in which one may write an equation which uses all sensors
> temperature values to determine the ending zone temperature.
> 
> > The intention is to make it easy for generic sensor drivers
> > to register with the framework, and let them participate in
> > platform thermal management. Another goal is to expose the
> > binding information in a consistent way so that user space
> > can consume the information and potentially manage platform thermals.
> >
> > This series contains 7 patches:
> > Patch 1/7: Creates new sensor level APIs
> > Patch 2/7: Creates new zone level APIs. The existing tzd structure is
> > 	   kept as such for clarity and compatibility purposes.
> > Patch 3/7: Creates functions to add/remove a cdev to/from a zone. The
> > 	   existing tcd structure need not be modified.
> > Patch 4/7: Adds a thermal_trip sysfs node, which exposes various trip
> > 	   points for all sensors present in a zone.
> > Patch 5/7: Adds a thermal_map sysfs node. It is a compact representation
> > 	   of the binding relationship between a sensor and a cdev,
> > 	   within a zone.
> > Patch 6/7: Creates Documentation for the new APIs. A new file is
> > 	   created for clarity. Final goal is to merge with the existing
> > 	   file or refactor the files, as whatever seems appropriate.
> > Patch 7/7: A dummy driver that can be used for testing. This is not for
> merge.
> >
> > Next steps:
> >   1. Move all the existing drivers to the new implementation model.
> >      Help welcomed from individual driver authors/maintainers for this.
> >   2. Make the thermal governors work with this new model.
> >   3. Remove old/unused code from thermal_sys.c.
> >   4. Add more detailed documentation
> >
> >   I didn't want to submit patches for all these in one-go, since it
> >   might end-up being difficult to comprehend, besides delaying the
> >   review process. The other obvious reason being I cannot test all
> >   the changes on various drivers for 1.
> >
> >   All these patches have been tested on a Core-i5 desktop running
> >   ubuntu 12.04 and an atom notebook running ubuntu 11.10.
> >   Kindly help review.
> >
> > Durgadoss R (7):
> >    Thermal: Create sensor level APIs
> >    Thermal: Create zone level APIs
> >    Thermal: Add APIs to bind cdev to new zone structure
> >    Thermal: Add Thermal_trip sysfs node
> >    Thermal: Add 'thermal_map' sysfs node
> >    Thermal: Add Documentation to new APIs
> >    Thermal: Dummy driver used for testing
> >
> >   Documentation/thermal/sysfs-api2.txt |  213 ++++++++
> >   drivers/thermal/Kconfig              |    5 +
> >   drivers/thermal/Makefile             |    3 +
> >   drivers/thermal/thermal_sys.c        |  915
> ++++++++++++++++++++++++++++++++++
> >   drivers/thermal/thermal_test.c       |  321 ++++++++++++
> >   include/linux/thermal.h              |  118 +++++
> >   6 files changed, 1575 insertions(+)
> >   create mode 100644 Documentation/thermal/sysfs-api2.txt
> >   create mode 100644 drivers/thermal/thermal_test.c
> >


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

* Re: [RFC PATCH 0/7] Support for Multiple sensors per zone
  2013-01-02 16:29   ` R, Durgadoss
@ 2013-01-02 16:46     ` Eduardo Valentin
  0 siblings, 0 replies; 27+ messages in thread
From: Eduardo Valentin @ 2013-01-02 16:46 UTC (permalink / raw)
  To: R, Durgadoss
  Cc: Zhang, Rui, linux-pm, wni, amit.kachhap, hongbo.zhang, sachin.kamat

Hello Durga,

On 02-01-2013 18:29, R, Durgadoss wrote:
> Hello Eduardo,
>
>> -----Original Message-----
>> From: Eduardo Valentin [mailto:eduardo.valentin@ti.com]
>> Sent: Wednesday, January 02, 2013 9:18 PM
>> To: R, Durgadoss
>> Cc: Zhang, Rui; linux-pm@vger.kernel.org; wni@nvidia.com;
>> amit.kachhap@linaro.org; hongbo.zhang@linaro.org;
>> sachin.kamat@linaro.org
>> Subject: Re: [RFC PATCH 0/7] Support for Multiple sensors per zone
>>
>>
>> Hello Durga,
>>
>> First of all, sorry for the late answer. Happy New Year to you BTW. :-)
>
> Wish you a Happy New Year too :-)

Thanks.

> Yeah, we are talking after a long time!!
>

Indeed.

>>
>> On 17-11-2012 12:45, Durgadoss R wrote:
>>> This patch series attempts to add support for multiple
>>> sensors per zone. The work is based on the Thermal discussion
>>> happened in plumbers conference 2012, here:
>>> http://www.linuxplumbersconf.org/2012/schedule/
>>> Title: "Enhancing the Thermal Management Infrastructure in Linux"
>>>
>>
>> On the above discussion one point which was not really clear was if we
>> would create virtual thermal zones, with a fop to determine its
>> temperature in a given time, or if we would write APIs to fetch
>> temperature from a thermal zone and then in the platform code to would
>> derive the real temperature.

Forgot to mention that the agreement during the thermal session was to 
use the concept of virtual thermal zone/sensor as agregator.

>
> A really difficult but interesting question; Happy to answer :-)
> Actually we discussed this very same point various times internally,
> before coming up with this new framework. Let me explain that in
> brief to you.
>
>>
>>   From this patch series, looks like we are going to both directions at
>> the same time. Let me try to understand your proposal by introducing a
>> simple example.
>>
>> Let us assume a simple scenario which we have a thermal zone with 2
>> sensors, say, for skin management, one for back cover and one for LCD.
>> Assume also you have two different HW sensors, for whatever reason. By
>> your proposal, we would have two simple sensor drivers, one for each HW,
>> which is good. A platform driver that would add these two sensor
>> instances into a thermal zone.
>
> Perfect. Valid example.
>
>>
>> Now. what I don't know is how to determine the temperature of that zone.
>
> Yeah. Here we are.
>  From the new framework onwards, we are treating the 'zone' as a complete
> virtual concept. A zone can have multiple sensors reporting temperature.
>
> To compute the 'theoretical zone temperature', consider 'zone' as a 'virtual
> sensor'. This means, the platform driver will register one more sensor using
> thermal_sensor_register API with a name 'virtual_XXXX' (or something like
> that; we have not finalized the name yet). This sensor can be added to the
> required zone also. Now, to compute the zone temperature, the 'get_temp'
> callback of this sensor (inside the platform driver) can do 'whatever magic
> it wants to do'.

OK. then we are going to do same thing we discussed in LPC. Just that I 
got a bit confused on the patch set. Reusing get_temp is actually ideal 
because we can keep the remaining API as it is.

> A rather simple magic could be:
> temp_of_virtual_sensor = (sum of all sensor
> temperatures in this zone)/num_sensors_in_this_zone.
>

Yeah.

> This way, we could provide trip_points & thresholds for this virtual sensor
> also. i.e. everything else remains same.

Exactly.

>
>> I believe we need to have a thermal zone fops with get temperature. I am
>
> We thought through this to some extent.
> Assume we introduce a 'temp' sysfs interface (and the fops) for zone temperature.
> Now, we have to provide trip_points and thresholds also for this; Then, in the
> governors, what should we refer to ? on what basis shall we take actions ?
> Based on sensor temperature crossing a trip point ? or
> Based on the zone temperature crossing its own trip point ?
> If it is zone based, then it has to be 'polled' because a virtual zone
> cannot support programmable thresholds.

Yeah, I think using the concept of virtual thermal zone is the best. The 
trips and cooling actions are bound to the provided computed 
temperature, and then everything else remains the same, except that the 
zone temperature is actually synthetic.

>
> Moreover, the platform data mapping is also between sensors and
> cooling devices. A close look at patches 4 & 5 will explain this.
> So, If we go by 'zone' = 'virtual sensor',
> the governors can work as usual, and the way we provide platform data
> remains the same etc.. Hence, this idea was chosen.
>

good. that was also my suggestion during LPC.

> This 'virtual sensor' is also one important reason why we want to
> maintain the separation between 'sensor drivers' and 'platform drivers'.
> One that works for the hardware, and the other which can do magic :-)
>
> Let me know if this makes sense.

Yes it does. I will have a closer look on your series and come back later.

>
> Thanks again for the question!!
>
> Thanks,
> Durga
>
>> assuming the platform driver would be the one who introduces the thermal
>> zone, and adds the sensors, and knows how to determine the temperature
>> of that zone. This way, one can easily write a function to determine the
>> "summary temperature". Remember that using index to select one specific
>> temperature sensor for a given time may not be enough, as there are
>> scenarios in which one may write an equation which uses all sensors
>> temperature values to determine the ending zone temperature.
>>
>>> The intention is to make it easy for generic sensor drivers
>>> to register with the framework, and let them participate in
>>> platform thermal management. Another goal is to expose the
>>> binding information in a consistent way so that user space
>>> can consume the information and potentially manage platform thermals.
>>>
>>> This series contains 7 patches:
>>> Patch 1/7: Creates new sensor level APIs
>>> Patch 2/7: Creates new zone level APIs. The existing tzd structure is
>>> 	   kept as such for clarity and compatibility purposes.
>>> Patch 3/7: Creates functions to add/remove a cdev to/from a zone. The
>>> 	   existing tcd structure need not be modified.
>>> Patch 4/7: Adds a thermal_trip sysfs node, which exposes various trip
>>> 	   points for all sensors present in a zone.
>>> Patch 5/7: Adds a thermal_map sysfs node. It is a compact representation
>>> 	   of the binding relationship between a sensor and a cdev,
>>> 	   within a zone.
>>> Patch 6/7: Creates Documentation for the new APIs. A new file is
>>> 	   created for clarity. Final goal is to merge with the existing
>>> 	   file or refactor the files, as whatever seems appropriate.
>>> Patch 7/7: A dummy driver that can be used for testing. This is not for
>> merge.
>>>
>>> Next steps:
>>>    1. Move all the existing drivers to the new implementation model.
>>>       Help welcomed from individual driver authors/maintainers for this.
>>>    2. Make the thermal governors work with this new model.
>>>    3. Remove old/unused code from thermal_sys.c.
>>>    4. Add more detailed documentation
>>>
>>>    I didn't want to submit patches for all these in one-go, since it
>>>    might end-up being difficult to comprehend, besides delaying the
>>>    review process. The other obvious reason being I cannot test all
>>>    the changes on various drivers for 1.
>>>
>>>    All these patches have been tested on a Core-i5 desktop running
>>>    ubuntu 12.04 and an atom notebook running ubuntu 11.10.
>>>    Kindly help review.
>>>
>>> Durgadoss R (7):
>>>     Thermal: Create sensor level APIs
>>>     Thermal: Create zone level APIs
>>>     Thermal: Add APIs to bind cdev to new zone structure
>>>     Thermal: Add Thermal_trip sysfs node
>>>     Thermal: Add 'thermal_map' sysfs node
>>>     Thermal: Add Documentation to new APIs
>>>     Thermal: Dummy driver used for testing
>>>
>>>    Documentation/thermal/sysfs-api2.txt |  213 ++++++++
>>>    drivers/thermal/Kconfig              |    5 +
>>>    drivers/thermal/Makefile             |    3 +
>>>    drivers/thermal/thermal_sys.c        |  915
>> ++++++++++++++++++++++++++++++++++
>>>    drivers/thermal/thermal_test.c       |  321 ++++++++++++
>>>    include/linux/thermal.h              |  118 +++++
>>>    6 files changed, 1575 insertions(+)
>>>    create mode 100644 Documentation/thermal/sysfs-api2.txt
>>>    create mode 100644 drivers/thermal/thermal_test.c
>>>
>


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

end of thread, other threads:[~2013-01-02 16:46 UTC | newest]

Thread overview: 27+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2012-11-17 10:45 [RFC PATCH 0/7] Support for Multiple sensors per zone Durgadoss R
2012-11-17 10:45 ` [RFC PATCH 1/7] Thermal: Create sensor level APIs Durgadoss R
2012-11-17 10:45 ` [RFC PATCH 2/7] Thermal: Create zone " Durgadoss R
2012-12-03  7:42   ` Hongbo Zhang
2012-12-03  7:47     ` R, Durgadoss
2012-12-03  8:21       ` Hongbo Zhang
2012-12-03  9:51         ` R, Durgadoss
2012-12-03 11:50           ` Hongbo Zhang
2012-12-03 13:12             ` R, Durgadoss
2012-12-13  6:23   ` Hongbo Zhang
2012-12-13 15:00     ` R, Durgadoss
2012-12-14  4:10       ` Hongbo Zhang
2012-12-14  5:10         ` R, Durgadoss
2012-11-17 10:45 ` [RFC PATCH 3/7] Thermal: Add APIs to bind cdev to new zone structure Durgadoss R
2012-11-17 10:45 ` [RFC PATCH 4/7] Thermal: Add Thermal_trip sysfs node Durgadoss R
2012-12-04  8:30   ` Hongbo Zhang
2012-12-04  8:41     ` R, Durgadoss
2012-11-17 10:45 ` [RFC PATCH 5/7] Thermal: Add 'thermal_map' " Durgadoss R
2012-11-17 10:45 ` [RFC PATCH 6/7] Thermal: Add Documentation to new APIs Durgadoss R
2012-12-03  7:19   ` Hongbo Zhang
2012-12-03  7:44     ` R, Durgadoss
2012-11-17 10:45 ` [RFC PATCH 7/7] Thermal: Dummy driver used for testing Durgadoss R
2012-12-03  9:01 ` [RFC PATCH 0/7] Support for Multiple sensors per zone Hongbo Zhang
2012-12-03  9:56   ` R, Durgadoss
2013-01-02 15:48 ` Eduardo Valentin
2013-01-02 16:29   ` R, Durgadoss
2013-01-02 16:46     ` Eduardo Valentin

This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.