linux-kernel.vger.kernel.org archive mirror
 help / color / mirror / Atom feed
* [PATCHv3 0/8] Thermal Framework Enhancements
@ 2013-02-05 10:46 Durgadoss R
  2013-02-05 10:46 ` [PATCH 1/8] Thermal: Create sensor level APIs Durgadoss R
                   ` (11 more replies)
  0 siblings, 12 replies; 39+ messages in thread
From: Durgadoss R @ 2013-02-05 10:46 UTC (permalink / raw)
  To: rui.zhang, linux-pm
  Cc: linux-kernel, eduardo.valentin, hongbo.zhang, wni, Durgadoss R

This patch set is a v3 of the previous versions submitted here:
[v2]: http://lwn.net/Articles/531720/
[v1]: https://lkml.org/lkml/2012/12/18/108 
[RFC]:https://patchwork.kernel.org/patch/1758921/

This patch set is based on Rui's -next tree, and is
tested on a Core-i5 and an Atom netbook.

Changes since v2:
 * Reworked the map sysfs attributes in patch [5/8]
 * Dropped configuration for maximum sensors and
   cooling devices, through Kconfig.
 * Added __remove_trip_attr method
 * Renamed __clean_map_entry to __remove_map_entry
   for consistency in naming.
Changes Since v1:
 * Removed kobject creation for thermal_trip and thermal_map
   nodes as per Greg-KH's comments.
 * Added ABI Documentation under 'testing'.
 * Modified the GET_INDEX macro to be more linux-like, thanks
   to Joe Perches.
 * Added get_[sensor/cdev]_by_name APIs to thermal.h

This series contains 8 patches:
Patch 1/8: Creates new sensor level APIs
Patch 2/8: Creates new zone level APIs. The existing tzd structure is
           kept as such for clarity and compatibility purposes.
Patch 3/8: Creates functions to add/remove a cdev to/from a zone. The
           existing tcd structure need not be modified.
Patch 4/8: Adds sensorX_trip_[active/passive/hot/critical] sysfs nodes,
	   under /sys/class/thermal/zoneY/. This exposes various trip
           points for sensorX present in zoneY.
Patch 5/8: Adds mapY_* sysfs node. These attributes represent
           the binding relationship between a sensor and a cdev,
           within a zone.
Patch 6/8: 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/8: Add ABI documentation for sysfs interfaces introduced in this patch.
Patch 8/8: A dummy driver that can be used for testing. This is not for merge.

Durgadoss R (8):
  Thermal: Create sensor level APIs
  Thermal: Create zone level APIs
  Thermal: Add APIs to bind cdev to new zone structure
  Thermal: Add trip point sysfs nodes for sensor
  Thermal: Create Thermal map sysfs attributes for a zone
  Thermal: Add Documentation to new APIs
  Thermal: Add ABI Documentation for sysfs interfaces
  Thermal: Dummy driver used for testing

 Documentation/ABI/testing/sysfs-class-thermal |  137 ++++
 Documentation/thermal/sysfs-api2.txt          |  247 ++++++
 drivers/thermal/Kconfig                       |    5 +
 drivers/thermal/Makefile                      |    2 +
 drivers/thermal/thermal_sys.c                 |  994 +++++++++++++++++++++++++
 drivers/thermal/thermal_test.c                |  324 ++++++++
 include/linux/thermal.h                       |  123 ++-
 7 files changed, 1831 insertions(+), 1 deletion(-)
 create mode 100644 Documentation/ABI/testing/sysfs-class-thermal
 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] 39+ messages in thread

* [PATCH 1/8] Thermal: Create sensor level APIs
  2013-02-05 10:46 [PATCHv3 0/8] Thermal Framework Enhancements Durgadoss R
@ 2013-02-05 10:46 ` Durgadoss R
  2013-02-08  7:53   ` Zhang Rui
  2013-02-28 18:58   ` Eduardo Valentin
  2013-02-05 10:46 ` [PATCH 2/8] Thermal: Create zone " Durgadoss R
                   ` (10 subsequent siblings)
  11 siblings, 2 replies; 39+ messages in thread
From: Durgadoss R @ 2013-02-05 10:46 UTC (permalink / raw)
  To: rui.zhang, linux-pm
  Cc: linux-kernel, eduardo.valentin, hongbo.zhang, wni, Durgadoss R

This patch creates sensor level APIs, in the
generic thermal framework.

A Thermal sensor is a piece of hardware that can report
temperature of the spot in which it is placed. A thermal
sensor driver reads the temperature from this sensor
and reports it out. This kind of driver can be in
any subsystem. If the sensor needs to participate
in platform thermal management, the corresponding
driver can use the APIs introduced in this patch, to
register(or unregister) with the thermal framework.

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

diff --git a/drivers/thermal/thermal_sys.c b/drivers/thermal/thermal_sys.c
index 0a1bf6b..cb94497 100644
--- a/drivers/thermal/thermal_sys.c
+++ b/drivers/thermal/thermal_sys.c
@@ -44,13 +44,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(sensor_list_lock);
 static DEFINE_MUTEX(thermal_governor_lock);
 
 static struct thermal_governor *__find_governor(const char *name)
@@ -423,6 +426,103 @@ 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
+hyst_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_hyst", &indx))
+		return -EINVAL;
+
+	ret = ts->ops->get_hyst(ts, indx, &val);
+
+	return ret ? ret : sprintf(buf, "%ld\n", val);
+}
+
+static ssize_t
+hyst_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_hyst)
+		return -EPERM;
+
+	if (!sscanf(attr->attr.name, "threshold%d_hyst", &indx))
+		return -EINVAL;
+
+	if (kstrtol(buf, 10, &val))
+		return -EINVAL;
+
+	ret = ts->ops->set_hyst(ts, indx, val);
+
+	return ret ? ret : count;
+}
+
+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)
 {
@@ -707,6 +807,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)
@@ -1493,6 +1597,182 @@ static void remove_trip_attrs(struct thermal_zone_device *tz)
 }
 
 /**
+ * enable_sensor_thresholds - create sysfs nodes for thresholdX
+ * @ts:		the thermal sensor
+ * @count:	Number of thresholds supported by sensor hardware
+ *
+ * 'Thresholds' are temperatures programmed into the sensor hardware,
+ * on crossing which the sensor generates an interrupt. 'Trip points'
+ * are temperatures which the thermal manager/governor thinks, some
+ * action should be taken when the sensor reaches the value.
+ */
+static int enable_sensor_thresholds(struct thermal_sensor *ts, int count)
+{
+	int i;
+	int size = sizeof(struct thermal_attr) * count;
+
+	ts->thresh_attrs = kzalloc(size, GFP_KERNEL);
+	if (!ts->thresh_attrs)
+		return -ENOMEM;
+
+	if (ts->ops->get_hyst) {
+		ts->hyst_attrs = kzalloc(size, GFP_KERNEL);
+		if (!ts->hyst_attrs) {
+			kfree(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;
+
+		device_create_file(&ts->device, &ts->thresh_attrs[i].attr);
+
+		/* Create threshold_hyst attributes */
+		if (!ts->ops->get_hyst)
+			continue;
+
+		snprintf(ts->hyst_attrs[i].name, THERMAL_NAME_LENGTH,
+						 "threshold%d_hyst", i);
+
+		sysfs_attr_init(&ts->hyst_attrs[i].attr.attr);
+		ts->hyst_attrs[i].attr.attr.name = ts->hyst_attrs[i].name;
+		ts->hyst_attrs[i].attr.attr.mode = S_IRUGO | S_IWUSR;
+		ts->hyst_attrs[i].attr.show = hyst_show;
+		ts->hyst_attrs[i].attr.store = hyst_store;
+
+		device_create_file(&ts->device, &ts->hyst_attrs[i].attr);
+	}
+	return 0;
+}
+
+/**
+ * thermal_sensor_register - register a new thermal sensor
+ * @name:	name of the thermal sensor
+ * @count:	Number of thresholds supported by hardware
+ * @ops:	standard thermal sensor callbacks
+ * @devdata:	private device data
+ */
+struct thermal_sensor *thermal_sensor_register(const char *name, int count,
+			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;
+
+	if (count > 0 && ts->ops->get_threshold) {
+		ret = enable_sensor_thresholds(ts, count);
+		if (ret)
+			goto exit_temp;
+	}
+
+	/* Add this sensor to the global list of sensors */
+	mutex_lock(&sensor_list_lock);
+	list_add_tail(&ts->node, &thermal_sensor_list);
+	mutex_unlock(&sensor_list_lock);
+
+	return ts;
+
+exit_temp:
+	device_remove_file(&ts->device, &dev_attr_temp_input);
+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(&sensor_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(&sensor_list_lock);
+
+	if (!found)
+		return;
+
+	for (i = 0; i < ts->thresholds; i++) {
+		device_remove_file(&ts->device, &ts->thresh_attrs[i].attr);
+		if (ts->ops->get_hyst) {
+			device_remove_file(&ts->device,
+					&ts->hyst_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);
+
+/**
  * 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 9b78f8c..5470dae 100644
--- a/include/linux/thermal.h
+++ b/include/linux/thermal.h
@@ -55,6 +55,7 @@
 #define DEFAULT_THERMAL_GOVERNOR       "user_space"
 #endif
 
+struct thermal_sensor;
 struct thermal_zone_device;
 struct thermal_cooling_device;
 
@@ -135,6 +136,15 @@ 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 *);
+	int (*set_hyst) (struct thermal_sensor *, int, long);
+	int (*get_hyst) (struct thermal_sensor *, int, long *);
+};
+
 struct thermal_cooling_device {
 	int id;
 	char type[THERMAL_NAME_LENGTH];
@@ -152,6 +162,21 @@ 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_attr *hyst_attrs;
+};
+
 struct thermal_zone_device {
 	int id;
 	char type[THERMAL_NAME_LENGTH];
@@ -245,6 +270,10 @@ 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 *, int,
+				struct thermal_sensor_ops *, void *);
+void thermal_sensor_unregister(struct thermal_sensor *);
+
 #ifdef CONFIG_NET
 extern int thermal_generate_netlink_event(struct thermal_zone_device *tz,
 						enum events event);
-- 
1.7.9.5


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

* [PATCH 2/8] Thermal: Create zone level APIs
  2013-02-05 10:46 [PATCHv3 0/8] Thermal Framework Enhancements Durgadoss R
  2013-02-05 10:46 ` [PATCH 1/8] Thermal: Create sensor level APIs Durgadoss R
@ 2013-02-05 10:46 ` Durgadoss R
  2013-02-08  8:11   ` Zhang Rui
  2013-02-28 19:29   ` Eduardo Valentin
  2013-02-05 10:46 ` [PATCH 3/8] Thermal: Add APIs to bind cdev to new zone structure Durgadoss R
                   ` (9 subsequent siblings)
  11 siblings, 2 replies; 39+ messages in thread
From: Durgadoss R @ 2013-02-05 10:46 UTC (permalink / raw)
  To: rui.zhang, linux-pm
  Cc: linux-kernel, eduardo.valentin, hongbo.zhang, wni, Durgadoss R

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

A thermal zone is a hot spot on the platform, which
can have one or more sensors and cooling devices attached
to it. These sensors can be mapped to a set of cooling
devices, which when throttled, can help to bring down
the temperature of the hot spot.

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

diff --git a/drivers/thermal/thermal_sys.c b/drivers/thermal/thermal_sys.c
index cb94497..838d4fb 100644
--- a/drivers/thermal/thermal_sys.c
+++ b/drivers/thermal/thermal_sys.c
@@ -43,19 +43,46 @@ 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(sensor_list_lock);
+static DEFINE_MUTEX(zone_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)
+
+#define GET_INDEX(tz, ptr, type)			\
+({							\
+	int i, ret = -EINVAL;				\
+	do {						\
+		if (!tz || !ptr)			\
+			break;				\
+		mutex_lock(&type##_list_lock);		\
+		for (i = 0; i < tz->type##_indx; i++) {	\
+			if (tz->type##s[i] == ptr) {	\
+				ret = i;		\
+				break;			\
+			}				\
+		}					\
+		mutex_unlock(&type##_list_lock);	\
+	} while (0);					\
+	ret;						\
+})
+
 static struct thermal_governor *__find_governor(const char *name)
 {
 	struct thermal_governor *pos;
@@ -421,15 +448,44 @@ static void thermal_zone_device_check(struct work_struct *work)
 	thermal_zone_device_update(tz);
 }
 
+static void remove_sensor_from_zone(struct thermal_zone *tz,
+				struct thermal_sensor *ts)
+{
+	int j, indx;
+
+	indx = GET_INDEX(tz, ts, sensor);
+	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);
@@ -811,6 +867,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)
@@ -1656,6 +1714,136 @@ static int enable_sensor_thresholds(struct thermal_sensor *ts, int count)
 	return 0;
 }
 
+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(&zone_list_lock);
+	list_add_tail(&tz->node, &thermal_zone_list);
+	mutex_unlock(&zone_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(&zone_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(&zone_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(&sensor_list_lock);
+	for_each_thermal_sensor(pos) {
+		if (!strnicmp(pos->name, name, THERMAL_NAME_LENGTH)) {
+			ts = pos;
+			break;
+		}
+	}
+	mutex_unlock(&sensor_list_lock);
+	return ts;
+}
+EXPORT_SYMBOL(get_sensor_by_name);
+
+int add_sensor_to_zone(struct thermal_zone *tz, struct thermal_sensor *ts)
+{
+	int ret;
+
+	if (!tz || !ts)
+		return -EINVAL;
+
+	mutex_lock(&zone_list_lock);
+
+	/* Ensure we are not adding the same sensor again!! */
+	ret = GET_INDEX(tz, ts, sensor);
+	if (ret >= 0) {
+		ret = -EEXIST;
+		goto exit_zone;
+	}
+
+	mutex_lock(&sensor_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(&sensor_list_lock);
+exit_zone:
+	mutex_unlock(&zone_list_lock);
+	return ret;
+}
+EXPORT_SYMBOL(add_sensor_to_zone);
+
 /**
  * thermal_sensor_register - register a new thermal sensor
  * @name:	name of the thermal sensor
@@ -1732,6 +1920,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;
 
@@ -1751,6 +1940,13 @@ void thermal_sensor_unregister(struct thermal_sensor *ts)
 	if (!found)
 		return;
 
+	mutex_lock(&zone_list_lock);
+
+	for_each_thermal_zone(tz)
+		remove_sensor_from_zone(tz, ts);
+
+	mutex_unlock(&zone_list_lock);
+
 	for (i = 0; i < ts->thresholds; i++) {
 		device_remove_file(&ts->device, &ts->thresh_attrs[i].attr);
 		if (ts->ops->get_hyst) {
diff --git a/include/linux/thermal.h b/include/linux/thermal.h
index 5470dae..2194519 100644
--- a/include/linux/thermal.h
+++ b/include/linux/thermal.h
@@ -55,6 +55,8 @@
 #define DEFAULT_THERMAL_GOVERNOR       "user_space"
 #endif
 
+#define MAX_SENSORS_PER_ZONE		5
+
 struct thermal_sensor;
 struct thermal_zone_device;
 struct thermal_cooling_device;
@@ -202,6 +204,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];
@@ -274,6 +291,11 @@ struct thermal_sensor *thermal_sensor_register(const char *, int,
 				struct thermal_sensor_ops *, void *);
 void thermal_sensor_unregister(struct thermal_sensor *);
 
+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 *);
+struct thermal_sensor *get_sensor_by_name(const char *);
+
 #ifdef CONFIG_NET
 extern int thermal_generate_netlink_event(struct thermal_zone_device *tz,
 						enum events event);
-- 
1.7.9.5


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

* [PATCH 3/8] Thermal: Add APIs to bind cdev to new zone structure
  2013-02-05 10:46 [PATCHv3 0/8] Thermal Framework Enhancements Durgadoss R
  2013-02-05 10:46 ` [PATCH 1/8] Thermal: Create sensor level APIs Durgadoss R
  2013-02-05 10:46 ` [PATCH 2/8] Thermal: Create zone " Durgadoss R
@ 2013-02-05 10:46 ` Durgadoss R
  2013-02-08  8:28   ` Zhang Rui
  2013-02-28 19:35   ` Eduardo Valentin
  2013-02-05 10:46 ` [PATCH 4/8] Thermal: Add trip point sysfs nodes for sensor Durgadoss R
                   ` (8 subsequent siblings)
  11 siblings, 2 replies; 39+ messages in thread
From: Durgadoss R @ 2013-02-05 10:46 UTC (permalink / raw)
  To: rui.zhang, linux-pm
  Cc: linux-kernel, eduardo.valentin, hongbo.zhang, wni, 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 |   80 +++++++++++++++++++++++++++++++++++++++++
 include/linux/thermal.h       |    9 +++++
 2 files changed, 89 insertions(+)

diff --git a/drivers/thermal/thermal_sys.c b/drivers/thermal/thermal_sys.c
index 838d4fb..bf703b1 100644
--- a/drivers/thermal/thermal_sys.c
+++ b/drivers/thermal/thermal_sys.c
@@ -57,6 +57,7 @@ static LIST_HEAD(thermal_governor_list);
 static DEFINE_MUTEX(thermal_list_lock);
 static DEFINE_MUTEX(sensor_list_lock);
 static DEFINE_MUTEX(zone_list_lock);
+static DEFINE_MUTEX(cdev_list_lock);
 static DEFINE_MUTEX(thermal_governor_lock);
 
 #define for_each_thermal_sensor(pos) \
@@ -83,6 +84,9 @@ static DEFINE_MUTEX(thermal_governor_lock);
 	ret;						\
 })
 
+#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;
@@ -466,6 +470,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 j, indx;
+
+	indx = GET_INDEX(tz, cdev, 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) \
@@ -1462,6 +1484,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)
@@ -1499,6 +1522,13 @@ void thermal_cooling_device_unregister(struct thermal_cooling_device *cdev)
 
 	mutex_unlock(&thermal_list_lock);
 
+	mutex_lock(&zone_list_lock);
+
+	for_each_thermal_zone(tmp_tz)
+		remove_cdev_from_zone(tmp_tz, cdev);
+
+	mutex_unlock(&zone_list_lock);
+
 	if (cdev->type[0])
 		device_remove_file(&cdev->device, &dev_attr_cdev_type);
 	device_remove_file(&cdev->device, &dev_attr_max_state);
@@ -1794,6 +1824,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;
@@ -1844,6 +1891,39 @@ exit_zone:
 }
 EXPORT_SYMBOL(add_sensor_to_zone);
 
+int add_cdev_to_zone(struct thermal_zone *tz,
+			struct thermal_cooling_device *cdev)
+{
+	int ret;
+
+	if (!tz || !cdev)
+		return -EINVAL;
+
+	mutex_lock(&zone_list_lock);
+
+	/* Ensure we are not adding the same cdev again!! */
+	ret = GET_INDEX(tz, cdev, 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(&zone_list_lock);
+	return ret;
+}
+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 2194519..c841414 100644
--- a/include/linux/thermal.h
+++ b/include/linux/thermal.h
@@ -57,6 +57,8 @@
 
 #define MAX_SENSORS_PER_ZONE		5
 
+#define MAX_CDEVS_PER_ZONE		5
+
 struct thermal_sensor;
 struct thermal_zone_device;
 struct thermal_cooling_device;
@@ -217,6 +219,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 */
@@ -296,6 +302,9 @@ void remove_thermal_zone(struct thermal_zone *);
 int add_sensor_to_zone(struct thermal_zone *, struct thermal_sensor *);
 struct thermal_sensor *get_sensor_by_name(const char *);
 
+int add_cdev_to_zone(struct thermal_zone *, struct thermal_cooling_device *);
+struct thermal_cooling_device *get_cdev_by_name(const char *);
+
 #ifdef CONFIG_NET
 extern int thermal_generate_netlink_event(struct thermal_zone_device *tz,
 						enum events event);
-- 
1.7.9.5


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

* [PATCH 4/8] Thermal: Add trip point sysfs nodes for sensor
  2013-02-05 10:46 [PATCHv3 0/8] Thermal Framework Enhancements Durgadoss R
                   ` (2 preceding siblings ...)
  2013-02-05 10:46 ` [PATCH 3/8] Thermal: Add APIs to bind cdev to new zone structure Durgadoss R
@ 2013-02-05 10:46 ` Durgadoss R
  2013-02-08  8:50   ` Zhang Rui
  2013-02-28 19:51   ` Eduardo Valentin
  2013-02-05 10:46 ` [PATCH 5/8] Thermal: Create Thermal map sysfs attributes for a zone Durgadoss R
                   ` (7 subsequent siblings)
  11 siblings, 2 replies; 39+ messages in thread
From: Durgadoss R @ 2013-02-05 10:46 UTC (permalink / raw)
  To: rui.zhang, linux-pm
  Cc: linux-kernel, eduardo.valentin, hongbo.zhang, wni, Durgadoss R

This patch adds a trip point related sysfs nodes
for each sensor under a zone in /sys/class/thermal/zoneX/.
The nodes will be named, sensorX_trip_active,
sensorX_trip_passive, sensorX_trip_hot, sensorX_trip_critical
for active, passive, hot and critical trip points
respectively for sensorX.

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

diff --git a/drivers/thermal/thermal_sys.c b/drivers/thermal/thermal_sys.c
index bf703b1..69a60a4 100644
--- a/drivers/thermal/thermal_sys.c
+++ b/drivers/thermal/thermal_sys.c
@@ -452,6 +452,37 @@ static void thermal_zone_device_check(struct work_struct *work)
 	thermal_zone_device_update(tz);
 }
 
+static int get_sensor_indx_by_kobj(struct thermal_zone *tz, const char *name)
+{
+	int i, indx = -EINVAL;
+
+	mutex_lock(&sensor_list_lock);
+	for (i = 0; i < tz->sensor_indx; i++) {
+		if (!strnicmp(name, kobject_name(&tz->sensors[i]->device.kobj),
+					THERMAL_NAME_LENGTH)) {
+			indx = i;
+			break;
+		}
+	}
+	mutex_unlock(&sensor_list_lock);
+	return indx;
+}
+
+static void inline __remove_trip_attr(struct thermal_zone *tz, int indx)
+{
+	int i;
+	struct thermal_trip_attr *attr = tz->trip_attr[indx];
+
+	if (!attr)
+		return;
+
+	for (i = 0; i < NUM_TRIP_TYPES; i++)
+		device_remove_file(&tz->device, &attr->attrs[i].attr);
+
+	kfree(tz->trip_attr[indx]);
+	tz->trip_attr[indx] = NULL;
+}
+
 static void remove_sensor_from_zone(struct thermal_zone *tz,
 				struct thermal_sensor *ts)
 {
@@ -463,9 +494,15 @@ static void remove_sensor_from_zone(struct thermal_zone *tz,
 
 	sysfs_remove_link(&tz->device.kobj, kobject_name(&ts->device.kobj));
 
+	/* Remove trip point attributes associated with this sensor */
+	__remove_trip_attr(tz, 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->sensor_trip[j] = tz->sensor_trip[j + 1];
+		tz->trip_attr[j] = tz->trip_attr[j + 1];
+	}
 
 	tz->sensor_indx--;
 }
@@ -879,6 +916,99 @@ 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 device *dev, struct device_attribute *attr, char *buf)
+{
+	int i, indx, ret = 0;
+	char kobj_name[THERMAL_NAME_LENGTH];
+	struct thermal_zone *tz = to_zone(dev);
+
+	if (!sscanf(attr->attr.name, "sensor%d_trip_active", &i))
+		return -EINVAL;
+
+	snprintf(kobj_name, THERMAL_NAME_LENGTH, "sensor%d", i);
+	indx = get_sensor_indx_by_kobj(tz, kobj_name);
+	if (indx < 0)
+		return indx;
+
+	if (tz->sensor_trip[indx]->num_active_trips <= 0)
+		return sprintf(buf, "<Not available>\n");
+
+	ret += sprintf(buf, "0x%x", tz->sensor_trip[indx]->active_trip_mask);
+	for (i = 0; i < tz->sensor_trip[indx]->num_active_trips; i++) {
+		ret += sprintf(buf + ret, " %d",
+			tz->sensor_trip[indx]->active_trips[i]);
+	}
+
+	ret += sprintf(buf + ret, "\n");
+	return ret;
+}
+
+static ssize_t
+ptrip_show(struct device *dev, struct device_attribute *attr, char *buf)
+{
+	int i, indx, ret = 0;
+	char kobj_name[THERMAL_NAME_LENGTH];
+	struct thermal_zone *tz = to_zone(dev);
+
+	if (!sscanf(attr->attr.name, "sensor%d_trip_passive", &i))
+		return -EINVAL;
+
+	snprintf(kobj_name, THERMAL_NAME_LENGTH, "sensor%d", i);
+	indx = get_sensor_indx_by_kobj(tz, kobj_name);
+	if (indx < 0)
+		return indx;
+
+	if (tz->sensor_trip[indx]->num_passive_trips <= 0)
+		return sprintf(buf, "<Not available>\n");
+
+	for (i = 0; i < tz->sensor_trip[indx]->num_passive_trips; i++) {
+		ret += sprintf(buf + ret, "%d ",
+			tz->sensor_trip[indx]->passive_trips[i]);
+	}
+
+	ret += sprintf(buf + ret, "\n");
+	return ret;
+}
+
+static ssize_t
+hot_show(struct device *dev, struct device_attribute *attr, char *buf)
+{
+	int indx;
+	char kobj_name[THERMAL_NAME_LENGTH];
+	struct thermal_zone *tz = to_zone(dev);
+
+	if (!sscanf(attr->attr.name, "sensor%d_trip_hot", &indx))
+		return -EINVAL;
+
+	snprintf(kobj_name, THERMAL_NAME_LENGTH, "sensor%d", indx);
+
+	indx = get_sensor_indx_by_kobj(tz, kobj_name);
+	if (indx < 0)
+		return indx;
+
+	return sprintf(buf, "%d\n", tz->sensor_trip[indx]->hot);
+}
+
+static ssize_t
+critical_show(struct device *dev, struct device_attribute *attr, char *buf)
+{
+	int indx;
+	char kobj_name[THERMAL_NAME_LENGTH];
+	struct thermal_zone *tz = to_zone(dev);
+
+	if (!sscanf(attr->attr.name, "sensor%d_trip_critical", &indx))
+		return -EINVAL;
+
+	snprintf(kobj_name, THERMAL_NAME_LENGTH, "sensor%d", indx);
+
+	indx = get_sensor_indx_by_kobj(tz, kobj_name);
+	if (indx < 0)
+		return indx;
+
+	return sprintf(buf, "%d\n", tz->sensor_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);
@@ -889,7 +1019,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);
+/* Thermal zone attributes */
+static DEVICE_ATTR(zone_name, S_IRUGO, zone_name_show, NULL);
 
 /* sys I/F for cooling device */
 #define to_cooling_device(_dev)	\
@@ -1744,6 +1875,38 @@ static int enable_sensor_thresholds(struct thermal_sensor *ts, int count)
 	return 0;
 }
 
+static int create_sensor_trip_attrs(struct thermal_zone *tz,
+				struct thermal_trip_attr *attr, int indx)
+{
+	int i, ret;
+	static const char *const names[NUM_TRIP_TYPES] = {
+				"sensor%d_trip_active",
+				"sensor%d_trip_passive",
+				"sensor%d_trip_hot",
+				"sensor%d_trip_critical",
+				};
+	static ssize_t (*const rd_ptr[NUM_TRIP_TYPES]) (struct device *dev,
+			struct device_attribute *devattr, char *buf) = {
+			active_show, ptrip_show, hot_show, critical_show};
+
+	for (i = 0; i < NUM_TRIP_TYPES; i++) {
+		snprintf(attr->attrs[i].name, THERMAL_NAME_LENGTH, names[i],
+			indx);
+		sysfs_attr_init(&attr->attrs[i].attr.attr);
+		attr->attrs[i].attr.attr.name = attr->attrs[i].name;
+		attr->attrs[i].attr.attr.mode = S_IRUGO;
+		attr->attrs[i].attr.show = rd_ptr[i];
+		ret = device_create_file(&tz->device, &attr->attrs[i].attr);
+		if (ret)
+			goto exit;
+	}
+	return 0;
+exit:
+	while (--i >= 0)
+		device_remove_file(&tz->device, &attr->attrs[i].attr);
+	return ret;
+}
+
 struct thermal_zone *create_thermal_zone(const char *name, void *devdata)
 {
 	struct thermal_zone *tz;
@@ -1793,6 +1956,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)
@@ -1813,6 +1977,23 @@ 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) {
+		/* Remove /sys/class/thermal/zoneX/sensorY */
+		sysfs_remove_link(&tz->device.kobj,
+				kobject_name(&tz->sensors[i]->device.kobj));
+		__remove_trip_attr(tz, i);
+	}
+
+	/* Release the cdevs attached to this zone */
+	i = tz->cdev_indx;
+	while (--i >= 0) {
+		/* Remove /sys/class/thermal/zoneX/cooling_deviceY */
+		sysfs_remove_link(&tz->device.kobj,
+				kobject_name(&tz->cdevs[i]->device.kobj));
+	}
+
 	release_idr(&thermal_zone_idr, &thermal_idr_lock, tz->id);
 	idr_destroy(&tz->idr);
 
@@ -1924,6 +2105,46 @@ exit_zone:
 }
 EXPORT_SYMBOL(add_cdev_to_zone);
 
+int add_sensor_trip_info(struct thermal_zone *tz, struct thermal_sensor *ts,
+			struct thermal_trip_point *trip)
+{
+	int ret, indx, kobj_indx;
+
+	if (!tz || !ts || !trip)
+		return -EINVAL;
+
+	if (!sscanf(kobject_name(&ts->device.kobj), "sensor%d", &kobj_indx))
+		return -EINVAL;
+
+	mutex_lock(&zone_list_lock);
+
+	indx = GET_INDEX(tz, ts, sensor);
+	if (indx < 0) {
+		ret = -EINVAL;
+		goto exit;
+	}
+
+	tz->trip_attr[indx] = kzalloc(sizeof(struct thermal_trip_attr),
+					GFP_KERNEL);
+	if (!tz->trip_attr[indx]) {
+		ret = -ENOMEM;
+		goto exit;
+	}
+
+	ret = create_sensor_trip_attrs(tz, tz->trip_attr[indx], kobj_indx);
+	if (ret) {
+		kfree(tz->trip_attr[indx]);
+		goto exit;
+	}
+
+	tz->sensor_trip[indx] = trip;
+
+exit:
+	mutex_unlock(&zone_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 c841414..2f68018 100644
--- a/include/linux/thermal.h
+++ b/include/linux/thermal.h
@@ -31,7 +31,8 @@
 
 #define THERMAL_TRIPS_NONE	-1
 #define THERMAL_MAX_TRIPS	12
-#define THERMAL_NAME_LENGTH	20
+#define THERMAL_NAME_LENGTH	22
+#define NUM_TRIP_TYPES		4
 
 /* No upper/lower limit requirement */
 #define THERMAL_NO_LIMIT	-1UL
@@ -166,6 +167,34 @@ 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_trip_attr {
+	struct thermal_attr attrs[NUM_TRIP_TYPES];
+};
+
 struct thermal_sensor {
 	char name[THERMAL_NAME_LENGTH];
 	int id;
@@ -223,6 +252,10 @@ struct thermal_zone {
 	/* cdev level information */
 	int cdev_indx; /* index into 'cdevs' array */
 	struct thermal_cooling_device *cdevs[MAX_CDEVS_PER_ZONE];
+
+	/* Thermal sensors trip information */
+	struct thermal_trip_point *sensor_trip[MAX_SENSORS_PER_ZONE];
+	struct thermal_trip_attr *trip_attr[MAX_SENSORS_PER_ZONE];
 };
 
 /* Structure that holds thermal governor information */
@@ -305,6 +338,9 @@ struct thermal_sensor *get_sensor_by_name(const char *);
 int add_cdev_to_zone(struct thermal_zone *, struct thermal_cooling_device *);
 struct thermal_cooling_device *get_cdev_by_name(const char *);
 
+int add_sensor_trip_info(struct thermal_zone *, struct thermal_sensor *,
+			struct thermal_trip_point *);
+
 #ifdef CONFIG_NET
 extern int thermal_generate_netlink_event(struct thermal_zone_device *tz,
 						enum events event);
-- 
1.7.9.5


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

* [PATCH 5/8] Thermal: Create Thermal map sysfs attributes for a zone
  2013-02-05 10:46 [PATCHv3 0/8] Thermal Framework Enhancements Durgadoss R
                   ` (3 preceding siblings ...)
  2013-02-05 10:46 ` [PATCH 4/8] Thermal: Add trip point sysfs nodes for sensor Durgadoss R
@ 2013-02-05 10:46 ` Durgadoss R
  2013-02-08  9:04   ` Zhang Rui
  2013-02-28 21:30   ` Eduardo Valentin
  2013-02-05 10:46 ` [PATCH 6/8] Thermal: Add Documentation to new APIs Durgadoss R
                   ` (6 subsequent siblings)
  11 siblings, 2 replies; 39+ messages in thread
From: Durgadoss R @ 2013-02-05 10:46 UTC (permalink / raw)
  To: rui.zhang, linux-pm
  Cc: linux-kernel, eduardo.valentin, hongbo.zhang, wni, Durgadoss R

This patch creates a thermal map sysfs node under
/sys/class/thermal/zoneX/. This contains
entries named mapY_trip_type, mapY_sensor_name,
mapY_cdev_name, mapY_trip_mask, mapY_weights.

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

diff --git a/drivers/thermal/thermal_sys.c b/drivers/thermal/thermal_sys.c
index 69a60a4..e284b67 100644
--- a/drivers/thermal/thermal_sys.c
+++ b/drivers/thermal/thermal_sys.c
@@ -525,6 +525,44 @@ static void remove_cdev_from_zone(struct thermal_zone *tz,
 	tz->cdev_indx--;
 }
 
+static inline void __remove_map_entry(struct thermal_zone *tz, int indx)
+{
+	int i;
+	struct thermal_map_attr *attr = tz->map_attr[indx];
+
+	for (i = 0; i < NUM_MAP_ATTRS; i++)
+		device_remove_file(&tz->device, &attr->attrs[i].attr);
+
+	kfree(tz->map_attr[indx]);
+	tz->map[indx] = 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)) {
+			__remove_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)) {
+			__remove_map_entry(tz, i);
+		}
+	}
+}
+
 /* sys I/F for thermal zone */
 
 #define to_thermal_zone(_dev) \
@@ -917,6 +955,107 @@ policy_show(struct device *dev, struct device_attribute *devattr, char *buf)
 }
 
 static ssize_t
+map_ttype_show(struct device *dev, struct device_attribute *attr, char *buf)
+{
+	char *trip;
+	int indx;
+	struct thermal_zone *tz = to_zone(dev);
+
+	if (!sscanf(attr->attr.name, "map%d_trip_type", &indx))
+		return -EINVAL;
+
+	if (indx < 0 || indx >= MAX_MAPS_PER_ZONE)
+		return -EINVAL;
+
+	if (!tz->map[indx])
+		return sprintf(buf, "<Unavailable>\n");
+
+	trip = (tz->map[indx]->trip_type == THERMAL_TRIP_ACTIVE) ?
+						"active" : "passive";
+	return sprintf(buf, "%s\n", trip);
+}
+
+static ssize_t map_ts_name_show(struct device *dev,
+				struct device_attribute *attr, char *buf)
+{
+	int indx;
+	struct thermal_zone *tz = to_zone(dev);
+
+	if (!sscanf(attr->attr.name, "map%d_sensor_name", &indx))
+		return -EINVAL;
+
+	if (indx < 0 || indx >= MAX_MAPS_PER_ZONE)
+		return -EINVAL;
+
+	if (!tz->map[indx])
+		return sprintf(buf, "<Unavailable>\n");
+
+	return sprintf(buf, "%s\n", tz->map[indx]->sensor_name);
+}
+
+static ssize_t map_cdev_name_show(struct device *dev,
+				struct device_attribute *attr, char *buf)
+{
+	int indx;
+	struct thermal_zone *tz = to_zone(dev);
+
+	if (!sscanf(attr->attr.name, "map%d_cdev_name", &indx))
+		return -EINVAL;
+
+	if (indx < 0 || indx >= MAX_MAPS_PER_ZONE)
+		return -EINVAL;
+
+	if (!tz->map[indx])
+		return sprintf(buf, "<Unavailable>\n");
+
+	return sprintf(buf, "%s\n", tz->map[indx]->cdev_name);
+}
+
+static ssize_t map_trip_mask_show(struct device *dev,
+				struct device_attribute *attr, char *buf)
+{
+	int indx;
+	struct thermal_zone *tz = to_zone(dev);
+
+	if (!sscanf(attr->attr.name, "map%d_trip_mask", &indx))
+		return -EINVAL;
+
+	if (indx < 0 || indx >= MAX_MAPS_PER_ZONE)
+		return -EINVAL;
+
+	if (!tz->map[indx])
+		return sprintf(buf, "<Unavailable>\n");
+
+	return sprintf(buf, "0x%x\n", tz->map[indx]->trip_mask);
+}
+
+static ssize_t map_weights_show(struct device *dev,
+				struct device_attribute *attr, char *buf)
+{
+	int i, indx, ret = 0;
+	struct thermal_map *map;
+	struct thermal_zone *tz = to_zone(dev);
+
+	if (!sscanf(attr->attr.name, "map%d_weights", &indx))
+		return -EINVAL;
+
+	if (indx < 0 || indx >= MAX_MAPS_PER_ZONE)
+		return -EINVAL;
+
+	if (!tz->map[indx])
+		return sprintf(buf, "<Unavailable>\n");
+
+	map = tz->map[indx];
+
+	ret += sprintf(buf, "%d", map->weights[0]);
+	for (i = 1; 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 device *dev, struct device_attribute *attr, char *buf)
 {
 	int i, indx, ret = 0;
@@ -1655,8 +1794,10 @@ void thermal_cooling_device_unregister(struct thermal_cooling_device *cdev)
 
 	mutex_lock(&zone_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(&zone_list_lock);
 
@@ -1994,6 +2135,9 @@ void remove_thermal_zone(struct thermal_zone *tz)
 				kobject_name(&tz->cdevs[i]->device.kobj));
 	}
 
+	for (i = 0; i < MAX_MAPS_PER_ZONE; i++)
+		__remove_map_entry(tz, i);
+
 	release_idr(&thermal_zone_idr, &thermal_idr_lock, tz->id);
 	idr_destroy(&tz->idr);
 
@@ -2039,6 +2183,77 @@ struct thermal_sensor *get_sensor_by_name(const char *name)
 }
 EXPORT_SYMBOL(get_sensor_by_name);
 
+static int create_map_attrs(struct thermal_zone *tz, int indx)
+{
+	int ret, i;
+	struct thermal_map_attr *attr = tz->map_attr[indx];
+
+	static const char *const names[NUM_MAP_ATTRS] = { "map%d_trip_type",
+			"map%d_sensor_name", "map%d_cdev_name",
+			"map%d_trip_mask", "map%d_weights" };
+	static ssize_t (*const rd_ptr[NUM_MAP_ATTRS]) (struct device *dev,
+			struct device_attribute *devattr, char *buf) = {
+			map_ttype_show, map_ts_name_show, map_cdev_name_show,
+			map_trip_mask_show, map_weights_show };
+
+	for (i = 0; i < NUM_MAP_ATTRS; i++) {
+		snprintf(attr->attrs[i].name,
+			THERMAL_NAME_LENGTH, names[i], indx);
+		attr->attrs[i].attr.attr.name = attr->attrs[i].name;
+		attr->attrs[i].attr.attr.mode = S_IRUGO;
+		attr->attrs[i].attr.show = rd_ptr[i];
+		sysfs_attr_init(&attr->attrs[i].attr);
+
+		ret = device_create_file(&tz->device, &attr->attrs[i].attr);
+		if (ret)
+			goto exit_free;
+	}
+	return 0;
+exit_free:
+	while (--i >= 0)
+		device_remove_file(&tz->device, &attr->attrs[i].attr);
+	return ret;
+}
+
+int add_map_entry(struct thermal_zone *tz, struct thermal_map *map)
+{
+	int ret, indx;
+
+	if (!tz || !map)
+		return -EINVAL;
+
+	mutex_lock(&zone_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;
+	}
+
+	ret = create_map_attrs(tz, indx);
+	if (ret) {
+		kfree(tz->map_attr[indx]);
+		goto exit;
+	}
+
+	tz->map[indx] = map;
+exit:
+	mutex_unlock(&zone_list_lock);
+	return ret;
+}
+EXPORT_SYMBOL(add_map_entry);
+
 int add_sensor_to_zone(struct thermal_zone *tz, struct thermal_sensor *ts)
 {
 	int ret;
@@ -2243,8 +2458,10 @@ void thermal_sensor_unregister(struct thermal_sensor *ts)
 
 	mutex_lock(&zone_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(&zone_list_lock);
 
diff --git a/include/linux/thermal.h b/include/linux/thermal.h
index 2f68018..4389599 100644
--- a/include/linux/thermal.h
+++ b/include/linux/thermal.h
@@ -60,6 +60,11 @@
 
 #define MAX_CDEVS_PER_ZONE		5
 
+#define NUM_MAP_ATTRS			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;
@@ -167,6 +172,20 @@ struct thermal_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;
+};
+
+struct thermal_map_attr {
+	struct thermal_attr attrs[NUM_MAP_ATTRS];
+};
+
 /*
  * This structure defines the trip points for a sensor.
  * The actual values for these trip points come from
@@ -256,6 +275,10 @@ struct thermal_zone {
 	/* Thermal sensors trip information */
 	struct thermal_trip_point *sensor_trip[MAX_SENSORS_PER_ZONE];
 	struct thermal_trip_attr *trip_attr[MAX_SENSORS_PER_ZONE];
+
+	/* Thermal map information */
+	struct thermal_map *map[MAX_MAPS_PER_ZONE];
+	struct thermal_map_attr *map_attr[MAX_MAPS_PER_ZONE];
 };
 
 /* Structure that holds thermal governor information */
@@ -341,6 +364,8 @@ struct thermal_cooling_device *get_cdev_by_name(const char *);
 int add_sensor_trip_info(struct thermal_zone *, struct thermal_sensor *,
 			struct thermal_trip_point *);
 
+int add_map_entry(struct thermal_zone *, struct thermal_map *);
+
 #ifdef CONFIG_NET
 extern int thermal_generate_netlink_event(struct thermal_zone_device *tz,
 						enum events event);
-- 
1.7.9.5


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

* [PATCH 6/8] Thermal: Add Documentation to new APIs
  2013-02-05 10:46 [PATCHv3 0/8] Thermal Framework Enhancements Durgadoss R
                   ` (4 preceding siblings ...)
  2013-02-05 10:46 ` [PATCH 5/8] Thermal: Create Thermal map sysfs attributes for a zone Durgadoss R
@ 2013-02-05 10:46 ` Durgadoss R
  2013-02-08  9:21   ` Zhang Rui
  2013-02-05 10:46 ` [PATCH 7/8] Thermal: Add ABI Documentation for sysfs interfaces Durgadoss R
                   ` (5 subsequent siblings)
  11 siblings, 1 reply; 39+ messages in thread
From: Durgadoss R @ 2013-02-05 10:46 UTC (permalink / raw)
  To: rui.zhang, linux-pm
  Cc: linux-kernel, eduardo.valentin, hongbo.zhang, wni, 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 |  247 ++++++++++++++++++++++++++++++++++
 1 file changed, 247 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..24e23f4
--- /dev/null
+++ b/Documentation/thermal/sysfs-api2.txt
@@ -0,0 +1,247 @@
+Thermal Framework
+-----------------
+
+Written by Durgadoss R <durgadoss.r@intel.com>
+Copyright (c) 2012 Intel Corporation
+
+Created on: 4 November 2012
+Updated on: 5 February 2013
+
+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.
+
+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.
+
+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
+	count: Number of programmable thresholds associated with this 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
+		.get_hyst: get hysteresis value associated with a threshold
+		.set_hyst: set hysteresis value associated with a threshold
+
+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/.
+	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/mapY_*. Each map attribute helps
+	to describe 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/sensor[0-*]:
+		|---type:		Name of the thermal sensor
+		|---temp_input:		Current temperature in mC
+		|---threshold[0-*]:	Threshold temperature in mC
+		|---threshold[0-*]_hyst:Optional hysteresis value in mC
+
+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 a sensor(Y)
+	present in the thermal zone(X). All values are in mC.
+	/sys/class/thermal/zoneX/:
+		|---sensorY_trip_hot:		hot trip point
+		|---sensorY_trip_critical:	critical trip point
+		|---sensorY_trip_passive:	passive trip point
+		|---sensorY_trip_active:	active trip point
+
+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/:
+		|---mapY_trip_type:		active/passive
+		|---mapY_sensor_name:		cpu
+		|---mapY_cdev_name:		proc
+		|---mapY_trip_mask:		0x03
+		|---mapY_weights:		50 30
+
+	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] 39+ messages in thread

* [PATCH 7/8] Thermal: Add ABI Documentation for sysfs interfaces
  2013-02-05 10:46 [PATCHv3 0/8] Thermal Framework Enhancements Durgadoss R
                   ` (5 preceding siblings ...)
  2013-02-05 10:46 ` [PATCH 6/8] Thermal: Add Documentation to new APIs Durgadoss R
@ 2013-02-05 10:46 ` Durgadoss R
  2013-02-05 10:46 ` [PATCH 8/8] Thermal: Dummy driver used for testing Durgadoss R
                   ` (4 subsequent siblings)
  11 siblings, 0 replies; 39+ messages in thread
From: Durgadoss R @ 2013-02-05 10:46 UTC (permalink / raw)
  To: rui.zhang, linux-pm
  Cc: linux-kernel, eduardo.valentin, hongbo.zhang, wni, Durgadoss R

This patch adds Documentation for ABI's introduced
for thermal subsystem (under /sys/class/thermal/).

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

diff --git a/Documentation/ABI/testing/sysfs-class-thermal b/Documentation/ABI/testing/sysfs-class-thermal
new file mode 100644
index 0000000..00f033a
--- /dev/null
+++ b/Documentation/ABI/testing/sysfs-class-thermal
@@ -0,0 +1,137 @@
+What:		/sys/class/thermal/sensorX/temp
+Date:		February 2013
+KernelVersion:	3.8
+Contact:	Linux PM Mailing list <linux-pm@vger.kernel.org>
+Description:
+		Exposes 'temperature' of a thermal sensor in mC
+Users:		Kernel/User space thermal governors
+
+What:		/sys/class/thermal/sensorX/name
+Date:		February 2013
+KernelVersion:	3.8
+Contact:	Linux PM Mailing list <linux-pm@vger.kernel.org>
+Description:
+		Name of the thermal sensor
+Users:		Kernel/User space thermal governors
+
+What:		/sys/class/thermal/sensorX/thresholdY
+Date:		February 2013
+KernelVersion:	3.8
+Contact:	Linux PM Mailing list <linux-pm@vger.kernel.org>
+Description:
+		Programmable threshold (in terms of mC). On reaching
+		this, the thermal governors may take action to control
+		temperature.
+Users:		Kernel/User space thermal governors
+
+What:		/sys/class/thermal/zoneX/name
+Date:		February 2013
+KernelVersion:	3.8
+Contact:	Linux PM Mailing list <linux-pm@vger.kernel.org>
+Description:
+		Name of the thermal zone.
+Users:		Kernel/User space thermal governors
+
+What:		/sys/class/thermal/zoneX/sensorY
+Date:		February 2013
+KernelVersion:	3.8
+Contact:	Linux PM Mailing list <linux-pm@vger.kernel.org>
+Description:
+		Symlink to a sensor associated with this zone.
+Users:		User space thermal governors or applications
+
+What:		/sys/class/thermal/zoneX/cooling_deviceY
+Date:		February 2013
+KernelVersion:	3.8
+Contact:	Linux PM Mailing list <linux-pm@vger.kernel.org>
+Description:
+		Symlink to a cooling device associated with this zone.
+Users:		User space thermal governors or applications
+
+What:		/sys/class/thermal/zoneX/sensorY_trip_active
+Date:		February 2013
+KernelVersion:	3.8
+Contact:	Linux PM Mailing list <linux-pm@vger.kernel.org>
+Description:
+		Space separated list of active trip points for 'sensorY'
+		in 'zoneX' (in mC).
+Users:		Kernel/User space thermal governors
+
+What:		/sys/class/thermal/zoneX/sensorY_trip_passive
+Date:		February 2013
+KernelVersion:	3.8
+Contact:	Linux PM Mailing list <linux-pm@vger.kernel.org>
+Description:
+		Space separated list of passive trip points for 'sensorY'
+		in 'zoneX' (in mC).
+Users:		Kernel/User space thermal governors
+
+What:		/sys/class/thermal/zoneX/sensorY_trip_hot
+Date:		February 2013
+KernelVersion:	3.8
+Contact:	Linux PM Mailing list <linux-pm@vger.kernel.org>
+Description:
+		Hot trip point for 'sensorY' in 'zoneX' (in mC).
+Users:		Kernel/User space thermal governors
+
+What:		/sys/class/thermal/zoneX/sensorY_trip_critical
+Date:		February 2013
+KernelVersion:	3.8
+Contact:	Linux PM Mailing list <linux-pm@vger.kernel.org>
+Description:
+		Critical trip point for 'sensorY' in 'zoneX' (in mC).
+Users:		Kernel/User space thermal governors
+
+What:		/sys/class/thermal/zoneX/mapY_trip_type
+Date:		February 2013
+KernelVersion:	3.8
+Contact:	Linux PM Mailing list <linux-pm@vger.kernel.org>
+Description:
+		Mapping information between a sensor and a cooling device
+		in 'zoneX'. This interface provides the trip_type for a
+		particular map(Y).
+Users:		Kernel/User space thermal governors
+
+What:		/sys/class/thermal/zoneX/mapY_sensor_name
+Date:		February 2013
+KernelVersion:	3.8
+Contact:	Linux PM Mailing list <linux-pm@vger.kernel.org>
+Description:
+		Mapping information between a sensor and a cooling device
+		in 'zoneX'. This interface provides the name of the sensor
+		used in this map(Y).
+Users:		Kernel/User space thermal governors
+
+What:		/sys/class/thermal/zoneX/mapY_cdev_name
+Date:		February 2013
+KernelVersion:	3.8
+Contact:	Linux PM Mailing list <linux-pm@vger.kernel.org>
+Description:
+		Mapping information between a sensor and a cooling device
+		in 'zoneX'. This interface provides the name of the cooling
+		device used in this map(Y).
+Users:		Kernel/User space thermal governors
+
+What:		/sys/class/thermal/zoneX/mapY_trip_mask
+Date:		February 2013
+KernelVersion:	3.8
+Contact:	Linux PM Mailing list <linux-pm@vger.kernel.org>
+Description:
+		Mapping information between a sensor and a cooling device
+		in 'zoneX'. This interface provides the trip point mask,
+		which defines whether or not to throttle a particular
+		cooling device. See Documentation/thermal/sysfs-api2.txt
+		for more information on this interface.
+Users:		Kernel/User space thermal governors
+
+What:		/sys/class/thermal/zoneX/mapY_weights
+Date:		February 2013
+KernelVersion:	3.8
+Contact:	Linux PM Mailing list <linux-pm@vger.kernel.org>
+Description:
+		Mapping information between a sensor and a cooling device
+		in 'zoneX'. This interface provides the weights that can
+		be used to throttle a cooling device, on thermal violations.
+		See Documentation/thermal/sysfs-api2.txt for more details on
+		this interface.
+Users:		Kernel/User space thermal governors
-- 
1.7.9.5


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

* [PATCH 8/8] Thermal: Dummy driver used for testing
  2013-02-05 10:46 [PATCHv3 0/8] Thermal Framework Enhancements Durgadoss R
                   ` (6 preceding siblings ...)
  2013-02-05 10:46 ` [PATCH 7/8] Thermal: Add ABI Documentation for sysfs interfaces Durgadoss R
@ 2013-02-05 10:46 ` Durgadoss R
  2013-02-08  7:53 ` [PATCHv3 0/8] Thermal Framework Enhancements Zhang Rui
                   ` (3 subsequent siblings)
  11 siblings, 0 replies; 39+ messages in thread
From: Durgadoss R @ 2013-02-05 10:46 UTC (permalink / raw)
  To: rui.zhang, linux-pm
  Cc: linux-kernel, eduardo.valentin, hongbo.zhang, wni, 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       |    2 +
 drivers/thermal/thermal_test.c |  324 ++++++++++++++++++++++++++++++++++++++++
 3 files changed, 331 insertions(+)
 create mode 100644 drivers/thermal/thermal_test.c

diff --git a/drivers/thermal/Kconfig b/drivers/thermal/Kconfig
index faf38c5..eadef5b 100644
--- a/drivers/thermal/Kconfig
+++ b/drivers/thermal/Kconfig
@@ -141,4 +141,9 @@ config INTEL_POWERCLAMP
 	  enforce idle time which results in more package C-state residency. The
 	  user interface is exposed via generic thermal framework.
 
+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 574f5f5..ee0f687 100644
--- a/drivers/thermal/Makefile
+++ b/drivers/thermal/Makefile
@@ -20,3 +20,5 @@ obj-$(CONFIG_DB8500_THERMAL)	+= db8500_thermal.o
 obj-$(CONFIG_DB8500_CPUFREQ_COOLING)	+= db8500_cpufreq_cooling.o
 obj-$(CONFIG_INTEL_POWERCLAMP)	+= intel_powerclamp.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..d92b68b
--- /dev/null
+++ b/drivers/thermal/thermal_test.c
@@ -0,0 +1,324 @@
+/*
+ * 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.
+ * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+ * 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};
+int wts[5] = {50, 50, 50, 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 struct thermal_map map = {
+	.trip_type = THERMAL_TRIP_PASSIVE,
+	.sensor_name = "ts",
+	.cdev_name = "cdev",
+	.num_weights = 5,
+	.trip_mask = 0x0F,
+	.weights = wts,
+};
+
+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", NUM_THRESHOLDS, &ts_ops, &ts_data);
+	if (!ts) {
+		pr_err("thermal_sensor_register failed:\n");
+		return -EINVAL;
+	}
+
+	ts1 = thermal_sensor_register("ts1", NUM_THRESHOLDS, &ts1_ops, NULL);
+
+	cdev = thermal_cooling_device_register("cdev", NULL, &cdev_ops);
+	if (!cdev) {
+		pr_err("cdev_register failed:\n");
+		return -EINVAL;
+	}
+
+	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 -EINVAL;
+	}
+
+	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);
+
+	ret = add_map_entry(tz, &map);
+	pr_err("add_map_entry (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] 39+ messages in thread

* Re: [PATCHv3 0/8] Thermal Framework Enhancements
  2013-02-05 10:46 [PATCHv3 0/8] Thermal Framework Enhancements Durgadoss R
                   ` (7 preceding siblings ...)
  2013-02-05 10:46 ` [PATCH 8/8] Thermal: Dummy driver used for testing Durgadoss R
@ 2013-02-08  7:53 ` Zhang Rui
  2013-02-08  9:35 ` Zhang Rui
                   ` (2 subsequent siblings)
  11 siblings, 0 replies; 39+ messages in thread
From: Zhang Rui @ 2013-02-08  7:53 UTC (permalink / raw)
  To: Durgadoss R; +Cc: linux-pm, linux-kernel, eduardo.valentin, hongbo.zhang, wni

Hi, Durga,

thanks for your continuous effort on this.
comment in line.

thanks,
rui

On Tue, 2013-02-05 at 16:16 +0530, Durgadoss R wrote:
> This patch set is a v3 of the previous versions submitted here:
> [v2]: http://lwn.net/Articles/531720/
> [v1]: https://lkml.org/lkml/2012/12/18/108 
> [RFC]:https://patchwork.kernel.org/patch/1758921/
> 
> This patch set is based on Rui's -next tree, and is
> tested on a Core-i5 and an Atom netbook.
> 
> Changes since v2:
>  * Reworked the map sysfs attributes in patch [5/8]
>  * Dropped configuration for maximum sensors and
>    cooling devices, through Kconfig.
>  * Added __remove_trip_attr method
>  * Renamed __clean_map_entry to __remove_map_entry
>    for consistency in naming.
> Changes Since v1:
>  * Removed kobject creation for thermal_trip and thermal_map
>    nodes as per Greg-KH's comments.
>  * Added ABI Documentation under 'testing'.
>  * Modified the GET_INDEX macro to be more linux-like, thanks
>    to Joe Perches.
>  * Added get_[sensor/cdev]_by_name APIs to thermal.h
> 
> This series contains 8 patches:
> Patch 1/8: Creates new sensor level APIs
> Patch 2/8: Creates new zone level APIs. The existing tzd structure is
>            kept as such for clarity and compatibility purposes.
> Patch 3/8: Creates functions to add/remove a cdev to/from a zone. The
>            existing tcd structure need not be modified.
> Patch 4/8: Adds sensorX_trip_[active/passive/hot/critical] sysfs nodes,
> 	   under /sys/class/thermal/zoneY/. This exposes various trip
>            points for sensorX present in zoneY.
> Patch 5/8: Adds mapY_* sysfs node. These attributes represent
>            the binding relationship between a sensor and a cdev,
>            within a zone.
> Patch 6/8: 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/8: Add ABI documentation for sysfs interfaces introduced in this patch.
> Patch 8/8: A dummy driver that can be used for testing. This is not for merge.
> 
> Durgadoss R (8):
>   Thermal: Create sensor level APIs
>   Thermal: Create zone level APIs
>   Thermal: Add APIs to bind cdev to new zone structure
>   Thermal: Add trip point sysfs nodes for sensor
>   Thermal: Create Thermal map sysfs attributes for a zone
>   Thermal: Add Documentation to new APIs
>   Thermal: Add ABI Documentation for sysfs interfaces
>   Thermal: Dummy driver used for testing
> 
>  Documentation/ABI/testing/sysfs-class-thermal |  137 ++++
>  Documentation/thermal/sysfs-api2.txt          |  247 ++++++
>  drivers/thermal/Kconfig                       |    5 +
>  drivers/thermal/Makefile                      |    2 +
>  drivers/thermal/thermal_sys.c                 |  994 +++++++++++++++++++++++++
>  drivers/thermal/thermal_test.c                |  324 ++++++++
>  include/linux/thermal.h                       |  123 ++-
>  7 files changed, 1831 insertions(+), 1 deletion(-)
>  create mode 100644 Documentation/ABI/testing/sysfs-class-thermal
>  create mode 100644 Documentation/thermal/sysfs-api2.txt
>  create mode 100644 drivers/thermal/thermal_test.c
> 



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

* Re: [PATCH 1/8] Thermal: Create sensor level APIs
  2013-02-05 10:46 ` [PATCH 1/8] Thermal: Create sensor level APIs Durgadoss R
@ 2013-02-08  7:53   ` Zhang Rui
  2013-02-08  8:26     ` R, Durgadoss
  2013-02-28 18:58   ` Eduardo Valentin
  1 sibling, 1 reply; 39+ messages in thread
From: Zhang Rui @ 2013-02-08  7:53 UTC (permalink / raw)
  To: Durgadoss R; +Cc: linux-pm, linux-kernel, eduardo.valentin, hongbo.zhang, wni

On Tue, 2013-02-05 at 16:16 +0530, Durgadoss R wrote:
> This patch creates sensor level APIs, in the
> generic thermal framework.
> 
> A Thermal sensor is a piece of hardware that can report
> temperature of the spot in which it is placed. A thermal
> sensor driver reads the temperature from this sensor
> and reports it out. This kind of driver can be in
> any subsystem. If the sensor needs to participate
> in platform thermal management, the corresponding
> driver can use the APIs introduced in this patch, to
> register(or unregister) with the thermal framework.
> 
> Signed-off-by: Durgadoss R <durgadoss.r@intel.com>
> ---
>  drivers/thermal/thermal_sys.c |  280 +++++++++++++++++++++++++++++++++++++++++
>  include/linux/thermal.h       |   29 +++++
>  2 files changed, 309 insertions(+)
> 
> diff --git a/drivers/thermal/thermal_sys.c b/drivers/thermal/thermal_sys.c
> index 0a1bf6b..cb94497 100644
> --- a/drivers/thermal/thermal_sys.c
> +++ b/drivers/thermal/thermal_sys.c
> @@ -44,13 +44,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(sensor_list_lock);
>  static DEFINE_MUTEX(thermal_governor_lock);
>  
>  static struct thermal_governor *__find_governor(const char *name)
> @@ -423,6 +426,103 @@ 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
> +hyst_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_hyst", &indx))
> +		return -EINVAL;
> +
> +	ret = ts->ops->get_hyst(ts, indx, &val);
> +
> +	return ret ? ret : sprintf(buf, "%ld\n", val);
> +}
> +
> +static ssize_t
> +hyst_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_hyst)
> +		return -EPERM;
> +
> +	if (!sscanf(attr->attr.name, "threshold%d_hyst", &indx))
> +		return -EINVAL;
> +
> +	if (kstrtol(buf, 10, &val))
> +		return -EINVAL;
> +
> +	ret = ts->ops->set_hyst(ts, indx, val);
> +
> +	return ret ? ret : count;
> +}
> +
> +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)
>  {
> @@ -707,6 +807,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)
> @@ -1493,6 +1597,182 @@ static void remove_trip_attrs(struct thermal_zone_device *tz)
>  }
>  
>  /**
> + * enable_sensor_thresholds - create sysfs nodes for thresholdX

this is a little confusing.
I'd prefer
thermal_sensor_sysfs_add() and create sensor_name and temp_input
attribute in this function as well, and thermal_sensor_sysfs_remove()
to remove the sysfs I/F.
And further more, we can do this for thermal zones and cooling devices.

others look okay to me.

thanks,
rui


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

* Re: [PATCH 2/8] Thermal: Create zone level APIs
  2013-02-05 10:46 ` [PATCH 2/8] Thermal: Create zone " Durgadoss R
@ 2013-02-08  8:11   ` Zhang Rui
  2013-02-08  8:54     ` R, Durgadoss
  2013-02-28 19:29   ` Eduardo Valentin
  1 sibling, 1 reply; 39+ messages in thread
From: Zhang Rui @ 2013-02-08  8:11 UTC (permalink / raw)
  To: Durgadoss R; +Cc: linux-pm, linux-kernel, eduardo.valentin, hongbo.zhang, wni

On Tue, 2013-02-05 at 16:16 +0530, Durgadoss R wrote:
> This patch adds a new thermal_zone structure to
> thermal.h. Also, adds zone level APIs to the thermal
> framework.
> 
> A thermal zone is a hot spot on the platform, which
> can have one or more sensors and cooling devices attached
> to it. These sensors can be mapped to a set of cooling
> devices, which when throttled, can help to bring down
> the temperature of the hot spot.
> 
> Signed-off-by: Durgadoss R <durgadoss.r@intel.com>
> ---
>  drivers/thermal/thermal_sys.c |  196 +++++++++++++++++++++++++++++++++++++++++
>  include/linux/thermal.h       |   22 +++++
>  2 files changed, 218 insertions(+)
> 
> diff --git a/drivers/thermal/thermal_sys.c b/drivers/thermal/thermal_sys.c
> index cb94497..838d4fb 100644
> --- a/drivers/thermal/thermal_sys.c
> +++ b/drivers/thermal/thermal_sys.c
> @@ -43,19 +43,46 @@ 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(sensor_list_lock);
> +static DEFINE_MUTEX(zone_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)
> +
> +#define GET_INDEX(tz, ptr, type)			\
> +({							\
> +	int i, ret = -EINVAL;				\
> +	do {						\
> +		if (!tz || !ptr)			\
> +			break;				\
> +		mutex_lock(&type##_list_lock);		\
> +		for (i = 0; i < tz->type##_indx; i++) {	\
> +			if (tz->type##s[i] == ptr) {	\
> +				ret = i;		\
> +				break;			\
> +			}				\
> +		}					\
> +		mutex_unlock(&type##_list_lock);	\
> +	} while (0);					\
> +	ret;						\
> +})
> +
>  static struct thermal_governor *__find_governor(const char *name)
>  {
>  	struct thermal_governor *pos;
> @@ -421,15 +448,44 @@ static void thermal_zone_device_check(struct work_struct *work)
>  	thermal_zone_device_update(tz);
>  }
>  
> +static void remove_sensor_from_zone(struct thermal_zone *tz,
> +				struct thermal_sensor *ts)
> +{
> +	int j, indx;
> +
> +	indx = GET_INDEX(tz, ts, sensor);
> +	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);
> @@ -811,6 +867,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)
> @@ -1656,6 +1714,136 @@ static int enable_sensor_thresholds(struct thermal_sensor *ts, int count)
>  	return 0;
>  }
>  
> +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(&zone_list_lock);
> +	list_add_tail(&tz->node, &thermal_zone_list);
> +	mutex_unlock(&zone_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(&zone_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(&zone_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(&sensor_list_lock);
> +	for_each_thermal_sensor(pos) {
> +		if (!strnicmp(pos->name, name, THERMAL_NAME_LENGTH)) {
> +			ts = pos;
> +			break;

this function depends on the assumption that all the sensor names are
unique.
thus I prefer to go through all the list and return -EINVAL if duplicate
names found, because in this case, the pointer returned may be not the
sensor we want to get.

thanks,
rui
> +		}
> +	}
> +	mutex_unlock(&sensor_list_lock);
> +	return ts;
> +}
> +EXPORT_SYMBOL(get_sensor_by_name);
> +
> +int add_sensor_to_zone(struct thermal_zone *tz, struct thermal_sensor *ts)
> +{
> +	int ret;
> +
> +	if (!tz || !ts)
> +		return -EINVAL;
> +
> +	mutex_lock(&zone_list_lock);
> +
> +	/* Ensure we are not adding the same sensor again!! */
> +	ret = GET_INDEX(tz, ts, sensor);
> +	if (ret >= 0) {
> +		ret = -EEXIST;
> +		goto exit_zone;
> +	}
> +
> +	mutex_lock(&sensor_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(&sensor_list_lock);
> +exit_zone:
> +	mutex_unlock(&zone_list_lock);
> +	return ret;
> +}
> +EXPORT_SYMBOL(add_sensor_to_zone);
> +
>  /**
>   * thermal_sensor_register - register a new thermal sensor
>   * @name:	name of the thermal sensor
> @@ -1732,6 +1920,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;
>  
> @@ -1751,6 +1940,13 @@ void thermal_sensor_unregister(struct thermal_sensor *ts)
>  	if (!found)
>  		return;
>  
> +	mutex_lock(&zone_list_lock);
> +
> +	for_each_thermal_zone(tz)
> +		remove_sensor_from_zone(tz, ts);
> +
> +	mutex_unlock(&zone_list_lock);
> +
>  	for (i = 0; i < ts->thresholds; i++) {
>  		device_remove_file(&ts->device, &ts->thresh_attrs[i].attr);
>  		if (ts->ops->get_hyst) {
> diff --git a/include/linux/thermal.h b/include/linux/thermal.h
> index 5470dae..2194519 100644
> --- a/include/linux/thermal.h
> +++ b/include/linux/thermal.h
> @@ -55,6 +55,8 @@
>  #define DEFAULT_THERMAL_GOVERNOR       "user_space"
>  #endif
>  
> +#define MAX_SENSORS_PER_ZONE		5
> +
>  struct thermal_sensor;
>  struct thermal_zone_device;
>  struct thermal_cooling_device;
> @@ -202,6 +204,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];
> @@ -274,6 +291,11 @@ struct thermal_sensor *thermal_sensor_register(const char *, int,
>  				struct thermal_sensor_ops *, void *);
>  void thermal_sensor_unregister(struct thermal_sensor *);
>  
> +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 *);
> +struct thermal_sensor *get_sensor_by_name(const char *);
> +
>  #ifdef CONFIG_NET
>  extern int thermal_generate_netlink_event(struct thermal_zone_device *tz,
>  						enum events event);



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

* RE: [PATCH 1/8] Thermal: Create sensor level APIs
  2013-02-08  7:53   ` Zhang Rui
@ 2013-02-08  8:26     ` R, Durgadoss
  2013-02-08  9:54       ` Zhang Rui
  0 siblings, 1 reply; 39+ messages in thread
From: R, Durgadoss @ 2013-02-08  8:26 UTC (permalink / raw)
  To: Zhang, Rui; +Cc: linux-pm, linux-kernel, eduardo.valentin, hongbo.zhang, wni

[-- Warning: decoded text below may be mangled, UTF-8 assumed --]
[-- Attachment #1: Type: text/plain; charset="utf-8", Size: 1995 bytes --]

Hi Rui,

> -----Original Message-----
> From: Zhang, Rui
> Sent: Friday, February 08, 2013 1:24 PM
> To: R, Durgadoss
> Cc: linux-pm@vger.kernel.org; linux-kernel@vger.kernel.org;
> eduardo.valentin@ti.com; hongbo.zhang@linaro.org; wni@nvidia.com
> Subject: Re: [PATCH 1/8] Thermal: Create sensor level APIs
> 
> On Tue, 2013-02-05 at 16:16 +0530, Durgadoss R wrote:
> > This patch creates sensor level APIs, in the
> > generic thermal framework.

[snip.]

> > +
> >  static ssize_t
> >  type_show(struct device *dev, struct device_attribute *attr, char *buf)
> >  {
> > @@ -707,6 +807,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)
> > @@ -1493,6 +1597,182 @@ static void remove_trip_attrs(struct
> thermal_zone_device *tz)
> >  }
> >
> >  /**
> > + * enable_sensor_thresholds - create sysfs nodes for thresholdX
> 
> this is a little confusing.
> I'd prefer
> thermal_sensor_sysfs_add() and create sensor_name and temp_input
> attribute in this function as well, and thermal_sensor_sysfs_remove()
> to remove the sysfs I/F.
> And further more, we can do this for thermal zones and cooling devices.

I agree, and we will change this.
Since this involves change for all standard APIs, I think it is better to submit
a separate patch to do this. What do you think ?

> 
> others look okay to me.

Thank you :-)

> 
> thanks,
> rui

ÿôèº{.nÇ+‰·Ÿ®‰­†+%ŠËÿ±éݶ\x17¥Šwÿº{.nÇ+‰·¥Š{±þG«éÿŠ{ayº\x1dʇڙë,j\a­¢f£¢·hšïêÿ‘êçz_è®\x03(­éšŽŠÝ¢j"ú\x1a¶^[m§ÿÿ¾\a«þG«éÿ¢¸?™¨è­Ú&£ø§~á¶iO•æ¬z·švØ^\x14\x04\x1a¶^[m§ÿÿÃ\fÿ¶ìÿ¢¸?–I¥

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

* Re: [PATCH 3/8] Thermal: Add APIs to bind cdev to new zone structure
  2013-02-05 10:46 ` [PATCH 3/8] Thermal: Add APIs to bind cdev to new zone structure Durgadoss R
@ 2013-02-08  8:28   ` Zhang Rui
  2013-02-28 19:35   ` Eduardo Valentin
  1 sibling, 0 replies; 39+ messages in thread
From: Zhang Rui @ 2013-02-08  8:28 UTC (permalink / raw)
  To: Durgadoss R; +Cc: linux-pm, linux-kernel, eduardo.valentin, hongbo.zhang, wni

On Tue, 2013-02-05 at 16:16 +0530, Durgadoss R wrote:
> 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 |   80 +++++++++++++++++++++++++++++++++++++++++
>  include/linux/thermal.h       |    9 +++++
>  2 files changed, 89 insertions(+)
> 
> diff --git a/drivers/thermal/thermal_sys.c b/drivers/thermal/thermal_sys.c
> index 838d4fb..bf703b1 100644
> --- a/drivers/thermal/thermal_sys.c
> +++ b/drivers/thermal/thermal_sys.c
> @@ -57,6 +57,7 @@ static LIST_HEAD(thermal_governor_list);
>  static DEFINE_MUTEX(thermal_list_lock);
>  static DEFINE_MUTEX(sensor_list_lock);
>  static DEFINE_MUTEX(zone_list_lock);
> +static DEFINE_MUTEX(cdev_list_lock);
>  static DEFINE_MUTEX(thermal_governor_lock);
>  
>  #define for_each_thermal_sensor(pos) \
> @@ -83,6 +84,9 @@ static DEFINE_MUTEX(thermal_governor_lock);
>  	ret;						\
>  })
>  
> +#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;
> @@ -466,6 +470,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 j, indx;
> +
> +	indx = GET_INDEX(tz, cdev, 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) \
> @@ -1462,6 +1484,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)
> @@ -1499,6 +1522,13 @@ void thermal_cooling_device_unregister(struct thermal_cooling_device *cdev)
>  
>  	mutex_unlock(&thermal_list_lock);
>  
> +	mutex_lock(&zone_list_lock);
> +
> +	for_each_thermal_zone(tmp_tz)
> +		remove_cdev_from_zone(tmp_tz, cdev);
> +
> +	mutex_unlock(&zone_list_lock);
> +
>  	if (cdev->type[0])
>  		device_remove_file(&cdev->device, &dev_attr_cdev_type);
>  	device_remove_file(&cdev->device, &dev_attr_max_state);
> @@ -1794,6 +1824,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;
the same comments as the Patch 2/8.

> +		}
> +	}
> +	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;
> @@ -1844,6 +1891,39 @@ exit_zone:
>  }
>  EXPORT_SYMBOL(add_sensor_to_zone);
>  
> +int add_cdev_to_zone(struct thermal_zone *tz,
> +			struct thermal_cooling_device *cdev)
> +{
> +	int ret;
> +
> +	if (!tz || !cdev)
> +		return -EINVAL;
> +
> +	mutex_lock(&zone_list_lock);
> +
> +	/* Ensure we are not adding the same cdev again!! */
> +	ret = GET_INDEX(tz, cdev, 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(&zone_list_lock);
> +	return ret;
> +}
> +EXPORT_SYMBOL(add_cdev_to_zone);
> +
Hmmm,
I'd prefer to see the code organized in this way:
/* thermal zone APIs/
thermal_zone_device_register()
thermal_zone_device_unregister()
add_thermal_zone()
remove_thermal_zone()

/* sensor APIs */
thermal_sensor_register()
thermal_sensor_unregister()
add_sensor_to_zone()
remove_sensor_from_zone()

/* cdev APIs */
thermal_cooling_device_register()
thermal_cooling_device_unregister()
add_cdev_to_zone()
remove_cdev_from_zone()

/* helper APIs */
get_sensor_by_name()
get_cdev_by_name()

but if this makes your rebase MUCH more difficult, I think we can
generate an incremental cleanup patch instead.

thanks,
rui



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

* Re: [PATCH 4/8] Thermal: Add trip point sysfs nodes for sensor
  2013-02-05 10:46 ` [PATCH 4/8] Thermal: Add trip point sysfs nodes for sensor Durgadoss R
@ 2013-02-08  8:50   ` Zhang Rui
  2013-02-28 19:51   ` Eduardo Valentin
  1 sibling, 0 replies; 39+ messages in thread
From: Zhang Rui @ 2013-02-08  8:50 UTC (permalink / raw)
  To: Durgadoss R; +Cc: linux-pm, linux-kernel, eduardo.valentin, hongbo.zhang, wni

On Tue, 2013-02-05 at 16:16 +0530, Durgadoss R wrote:
> This patch adds a trip point related sysfs nodes
> for each sensor under a zone in /sys/class/thermal/zoneX/.
> The nodes will be named, sensorX_trip_active,
> sensorX_trip_passive, sensorX_trip_hot, sensorX_trip_critical
> for active, passive, hot and critical trip points
> respectively for sensorX.
> 
> Signed-off-by: Durgadoss R <durgadoss.r@intel.com>

this one looks good to me.

thanks,
rui
> ---
>  drivers/thermal/thermal_sys.c |  225 ++++++++++++++++++++++++++++++++++++++++-
>  include/linux/thermal.h       |   38 ++++++-
>  2 files changed, 260 insertions(+), 3 deletions(-)
> 
> diff --git a/drivers/thermal/thermal_sys.c b/drivers/thermal/thermal_sys.c
> index bf703b1..69a60a4 100644
> --- a/drivers/thermal/thermal_sys.c
> +++ b/drivers/thermal/thermal_sys.c
> @@ -452,6 +452,37 @@ static void thermal_zone_device_check(struct work_struct *work)
>  	thermal_zone_device_update(tz);
>  }
>  
> +static int get_sensor_indx_by_kobj(struct thermal_zone *tz, const char *name)
> +{
> +	int i, indx = -EINVAL;
> +
> +	mutex_lock(&sensor_list_lock);
> +	for (i = 0; i < tz->sensor_indx; i++) {
> +		if (!strnicmp(name, kobject_name(&tz->sensors[i]->device.kobj),
> +					THERMAL_NAME_LENGTH)) {
> +			indx = i;
> +			break;
> +		}
> +	}
> +	mutex_unlock(&sensor_list_lock);
> +	return indx;
> +}
> +
> +static void inline __remove_trip_attr(struct thermal_zone *tz, int indx)
> +{
> +	int i;
> +	struct thermal_trip_attr *attr = tz->trip_attr[indx];
> +
> +	if (!attr)
> +		return;
> +
> +	for (i = 0; i < NUM_TRIP_TYPES; i++)
> +		device_remove_file(&tz->device, &attr->attrs[i].attr);
> +
> +	kfree(tz->trip_attr[indx]);
> +	tz->trip_attr[indx] = NULL;
> +}
> +
>  static void remove_sensor_from_zone(struct thermal_zone *tz,
>  				struct thermal_sensor *ts)
>  {
> @@ -463,9 +494,15 @@ static void remove_sensor_from_zone(struct thermal_zone *tz,
>  
>  	sysfs_remove_link(&tz->device.kobj, kobject_name(&ts->device.kobj));
>  
> +	/* Remove trip point attributes associated with this sensor */
> +	__remove_trip_attr(tz, 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->sensor_trip[j] = tz->sensor_trip[j + 1];
> +		tz->trip_attr[j] = tz->trip_attr[j + 1];
> +	}
>  
>  	tz->sensor_indx--;
>  }
> @@ -879,6 +916,99 @@ 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 device *dev, struct device_attribute *attr, char *buf)
> +{
> +	int i, indx, ret = 0;
> +	char kobj_name[THERMAL_NAME_LENGTH];
> +	struct thermal_zone *tz = to_zone(dev);
> +
> +	if (!sscanf(attr->attr.name, "sensor%d_trip_active", &i))
> +		return -EINVAL;
> +
> +	snprintf(kobj_name, THERMAL_NAME_LENGTH, "sensor%d", i);
> +	indx = get_sensor_indx_by_kobj(tz, kobj_name);
> +	if (indx < 0)
> +		return indx;
> +
> +	if (tz->sensor_trip[indx]->num_active_trips <= 0)
> +		return sprintf(buf, "<Not available>\n");
> +
> +	ret += sprintf(buf, "0x%x", tz->sensor_trip[indx]->active_trip_mask);
> +	for (i = 0; i < tz->sensor_trip[indx]->num_active_trips; i++) {
> +		ret += sprintf(buf + ret, " %d",
> +			tz->sensor_trip[indx]->active_trips[i]);
> +	}
> +
> +	ret += sprintf(buf + ret, "\n");
> +	return ret;
> +}
> +
> +static ssize_t
> +ptrip_show(struct device *dev, struct device_attribute *attr, char *buf)
> +{
> +	int i, indx, ret = 0;
> +	char kobj_name[THERMAL_NAME_LENGTH];
> +	struct thermal_zone *tz = to_zone(dev);
> +
> +	if (!sscanf(attr->attr.name, "sensor%d_trip_passive", &i))
> +		return -EINVAL;
> +
> +	snprintf(kobj_name, THERMAL_NAME_LENGTH, "sensor%d", i);
> +	indx = get_sensor_indx_by_kobj(tz, kobj_name);
> +	if (indx < 0)
> +		return indx;
> +
> +	if (tz->sensor_trip[indx]->num_passive_trips <= 0)
> +		return sprintf(buf, "<Not available>\n");
> +
> +	for (i = 0; i < tz->sensor_trip[indx]->num_passive_trips; i++) {
> +		ret += sprintf(buf + ret, "%d ",
> +			tz->sensor_trip[indx]->passive_trips[i]);
> +	}
> +
> +	ret += sprintf(buf + ret, "\n");
> +	return ret;
> +}
> +
> +static ssize_t
> +hot_show(struct device *dev, struct device_attribute *attr, char *buf)
> +{
> +	int indx;
> +	char kobj_name[THERMAL_NAME_LENGTH];
> +	struct thermal_zone *tz = to_zone(dev);
> +
> +	if (!sscanf(attr->attr.name, "sensor%d_trip_hot", &indx))
> +		return -EINVAL;
> +
> +	snprintf(kobj_name, THERMAL_NAME_LENGTH, "sensor%d", indx);
> +
> +	indx = get_sensor_indx_by_kobj(tz, kobj_name);
> +	if (indx < 0)
> +		return indx;
> +
> +	return sprintf(buf, "%d\n", tz->sensor_trip[indx]->hot);
> +}
> +
> +static ssize_t
> +critical_show(struct device *dev, struct device_attribute *attr, char *buf)
> +{
> +	int indx;
> +	char kobj_name[THERMAL_NAME_LENGTH];
> +	struct thermal_zone *tz = to_zone(dev);
> +
> +	if (!sscanf(attr->attr.name, "sensor%d_trip_critical", &indx))
> +		return -EINVAL;
> +
> +	snprintf(kobj_name, THERMAL_NAME_LENGTH, "sensor%d", indx);
> +
> +	indx = get_sensor_indx_by_kobj(tz, kobj_name);
> +	if (indx < 0)
> +		return indx;
> +
> +	return sprintf(buf, "%d\n", tz->sensor_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);
> @@ -889,7 +1019,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);
> +/* Thermal zone attributes */
> +static DEVICE_ATTR(zone_name, S_IRUGO, zone_name_show, NULL);
>  
>  /* sys I/F for cooling device */
>  #define to_cooling_device(_dev)	\
> @@ -1744,6 +1875,38 @@ static int enable_sensor_thresholds(struct thermal_sensor *ts, int count)
>  	return 0;
>  }
>  
> +static int create_sensor_trip_attrs(struct thermal_zone *tz,
> +				struct thermal_trip_attr *attr, int indx)
> +{
> +	int i, ret;
> +	static const char *const names[NUM_TRIP_TYPES] = {
> +				"sensor%d_trip_active",
> +				"sensor%d_trip_passive",
> +				"sensor%d_trip_hot",
> +				"sensor%d_trip_critical",
> +				};
> +	static ssize_t (*const rd_ptr[NUM_TRIP_TYPES]) (struct device *dev,
> +			struct device_attribute *devattr, char *buf) = {
> +			active_show, ptrip_show, hot_show, critical_show};
> +
> +	for (i = 0; i < NUM_TRIP_TYPES; i++) {
> +		snprintf(attr->attrs[i].name, THERMAL_NAME_LENGTH, names[i],
> +			indx);
> +		sysfs_attr_init(&attr->attrs[i].attr.attr);
> +		attr->attrs[i].attr.attr.name = attr->attrs[i].name;
> +		attr->attrs[i].attr.attr.mode = S_IRUGO;
> +		attr->attrs[i].attr.show = rd_ptr[i];
> +		ret = device_create_file(&tz->device, &attr->attrs[i].attr);
> +		if (ret)
> +			goto exit;
> +	}
> +	return 0;
> +exit:
> +	while (--i >= 0)
> +		device_remove_file(&tz->device, &attr->attrs[i].attr);
> +	return ret;
> +}
> +
>  struct thermal_zone *create_thermal_zone(const char *name, void *devdata)
>  {
>  	struct thermal_zone *tz;
> @@ -1793,6 +1956,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)
> @@ -1813,6 +1977,23 @@ 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) {
> +		/* Remove /sys/class/thermal/zoneX/sensorY */
> +		sysfs_remove_link(&tz->device.kobj,
> +				kobject_name(&tz->sensors[i]->device.kobj));
> +		__remove_trip_attr(tz, i);
> +	}
> +
> +	/* Release the cdevs attached to this zone */
> +	i = tz->cdev_indx;
> +	while (--i >= 0) {
> +		/* Remove /sys/class/thermal/zoneX/cooling_deviceY */
> +		sysfs_remove_link(&tz->device.kobj,
> +				kobject_name(&tz->cdevs[i]->device.kobj));
> +	}
> +
>  	release_idr(&thermal_zone_idr, &thermal_idr_lock, tz->id);
>  	idr_destroy(&tz->idr);
>  
> @@ -1924,6 +2105,46 @@ exit_zone:
>  }
>  EXPORT_SYMBOL(add_cdev_to_zone);
>  
> +int add_sensor_trip_info(struct thermal_zone *tz, struct thermal_sensor *ts,
> +			struct thermal_trip_point *trip)
> +{
> +	int ret, indx, kobj_indx;
> +
> +	if (!tz || !ts || !trip)
> +		return -EINVAL;
> +
> +	if (!sscanf(kobject_name(&ts->device.kobj), "sensor%d", &kobj_indx))
> +		return -EINVAL;
> +
> +	mutex_lock(&zone_list_lock);
> +
> +	indx = GET_INDEX(tz, ts, sensor);
> +	if (indx < 0) {
> +		ret = -EINVAL;
> +		goto exit;
> +	}
> +
> +	tz->trip_attr[indx] = kzalloc(sizeof(struct thermal_trip_attr),
> +					GFP_KERNEL);
> +	if (!tz->trip_attr[indx]) {
> +		ret = -ENOMEM;
> +		goto exit;
> +	}
> +
> +	ret = create_sensor_trip_attrs(tz, tz->trip_attr[indx], kobj_indx);
> +	if (ret) {
> +		kfree(tz->trip_attr[indx]);
> +		goto exit;
> +	}
> +
> +	tz->sensor_trip[indx] = trip;
> +
> +exit:
> +	mutex_unlock(&zone_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 c841414..2f68018 100644
> --- a/include/linux/thermal.h
> +++ b/include/linux/thermal.h
> @@ -31,7 +31,8 @@
>  
>  #define THERMAL_TRIPS_NONE	-1
>  #define THERMAL_MAX_TRIPS	12
> -#define THERMAL_NAME_LENGTH	20
> +#define THERMAL_NAME_LENGTH	22
> +#define NUM_TRIP_TYPES		4
>  
>  /* No upper/lower limit requirement */
>  #define THERMAL_NO_LIMIT	-1UL
> @@ -166,6 +167,34 @@ 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_trip_attr {
> +	struct thermal_attr attrs[NUM_TRIP_TYPES];
> +};
> +
>  struct thermal_sensor {
>  	char name[THERMAL_NAME_LENGTH];
>  	int id;
> @@ -223,6 +252,10 @@ struct thermal_zone {
>  	/* cdev level information */
>  	int cdev_indx; /* index into 'cdevs' array */
>  	struct thermal_cooling_device *cdevs[MAX_CDEVS_PER_ZONE];
> +
> +	/* Thermal sensors trip information */
> +	struct thermal_trip_point *sensor_trip[MAX_SENSORS_PER_ZONE];
> +	struct thermal_trip_attr *trip_attr[MAX_SENSORS_PER_ZONE];
>  };
>  
>  /* Structure that holds thermal governor information */
> @@ -305,6 +338,9 @@ struct thermal_sensor *get_sensor_by_name(const char *);
>  int add_cdev_to_zone(struct thermal_zone *, struct thermal_cooling_device *);
>  struct thermal_cooling_device *get_cdev_by_name(const char *);
>  
> +int add_sensor_trip_info(struct thermal_zone *, struct thermal_sensor *,
> +			struct thermal_trip_point *);
> +
>  #ifdef CONFIG_NET
>  extern int thermal_generate_netlink_event(struct thermal_zone_device *tz,
>  						enum events event);



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

* RE: [PATCH 2/8] Thermal: Create zone level APIs
  2013-02-08  8:11   ` Zhang Rui
@ 2013-02-08  8:54     ` R, Durgadoss
  2013-02-08  9:54       ` Zhang Rui
  0 siblings, 1 reply; 39+ messages in thread
From: R, Durgadoss @ 2013-02-08  8:54 UTC (permalink / raw)
  To: Zhang, Rui; +Cc: linux-pm, linux-kernel, eduardo.valentin, hongbo.zhang, wni

[-- Warning: decoded text below may be mangled, UTF-8 assumed --]
[-- Attachment #1: Type: text/plain; charset="utf-8", Size: 1622 bytes --]

Hi Rui,

> -----Original Message-----
> From: Zhang, Rui
> Sent: Friday, February 08, 2013 1:42 PM
> To: R, Durgadoss
> Cc: linux-pm@vger.kernel.org; linux-kernel@vger.kernel.org;
> eduardo.valentin@ti.com; hongbo.zhang@linaro.org; wni@nvidia.com
> Subject: Re: [PATCH 2/8] Thermal: Create zone level APIs
> 
> On Tue, 2013-02-05 at 16:16 +0530, Durgadoss R wrote:
> > This patch adds a new thermal_zone structure to
> > thermal.h. Also, adds zone level APIs to the thermal
> > framework.
> >

[snip.]

> > +
> > +struct thermal_sensor *get_sensor_by_name(const char *name)
> > +{
> > +	struct thermal_sensor *pos;
> > +	struct thermal_sensor *ts = NULL;
> > +
> > +	mutex_lock(&sensor_list_lock);
> > +	for_each_thermal_sensor(pos) {
> > +		if (!strnicmp(pos->name, name, THERMAL_NAME_LENGTH))
> {
> > +			ts = pos;
> > +			break;
> 
> this function depends on the assumption that all the sensor names are
> unique.
> thus I prefer to go through all the list and return -EINVAL if duplicate
> names found, because in this case, the pointer returned may be not the
> sensor we want to get.

Yes, I agree with you. But I prefer having this check in the register API
itself, which then will not allow duplicates.

The reason being, we use this get* API (comparatively) a lot more than
the register APIs. And putting this check in the register APIs means doing
this check only once. Let me know what you think.

And the same for cooling devices too.

Thanks,
Durga
ÿôèº{.nÇ+‰·Ÿ®‰­†+%ŠËÿ±éݶ\x17¥Šwÿº{.nÇ+‰·¥Š{±þG«éÿŠ{ayº\x1dʇڙë,j\a­¢f£¢·hšïêÿ‘êçz_è®\x03(­éšŽŠÝ¢j"ú\x1a¶^[m§ÿÿ¾\a«þG«éÿ¢¸?™¨è­Ú&£ø§~á¶iO•æ¬z·švØ^\x14\x04\x1a¶^[m§ÿÿÃ\fÿ¶ìÿ¢¸?–I¥

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

* Re: [PATCH 5/8] Thermal: Create Thermal map sysfs attributes for a zone
  2013-02-05 10:46 ` [PATCH 5/8] Thermal: Create Thermal map sysfs attributes for a zone Durgadoss R
@ 2013-02-08  9:04   ` Zhang Rui
  2013-02-08  9:08     ` R, Durgadoss
  2013-02-28 21:30   ` Eduardo Valentin
  1 sibling, 1 reply; 39+ messages in thread
From: Zhang Rui @ 2013-02-08  9:04 UTC (permalink / raw)
  To: Durgadoss R; +Cc: linux-pm, linux-kernel, eduardo.valentin, hongbo.zhang, wni

On Tue, 2013-02-05 at 16:16 +0530, Durgadoss R wrote:
> This patch creates a thermal map sysfs node under
> /sys/class/thermal/zoneX/. This contains
> entries named mapY_trip_type, mapY_sensor_name,
> mapY_cdev_name, mapY_trip_mask, mapY_weights.
sorry I still not quite understand.

does it look like?
/sys/class/thermal/zoneX/
|
map-->|-->map0_trip_type
      |...
      |-->map0_weight
      |-->map1_trip_type
      |...
      |-->map1_weight
      |...

thanks,
rui
> 
> Signed-off-by: Durgadoss R <durgadoss.r@intel.com>
> ---
>  drivers/thermal/thermal_sys.c |  221 ++++++++++++++++++++++++++++++++++++++++-
>  include/linux/thermal.h       |   25 +++++
>  2 files changed, 244 insertions(+), 2 deletions(-)
> 
> diff --git a/drivers/thermal/thermal_sys.c b/drivers/thermal/thermal_sys.c
> index 69a60a4..e284b67 100644
> --- a/drivers/thermal/thermal_sys.c
> +++ b/drivers/thermal/thermal_sys.c
> @@ -525,6 +525,44 @@ static void remove_cdev_from_zone(struct thermal_zone *tz,
>  	tz->cdev_indx--;
>  }
>  
> +static inline void __remove_map_entry(struct thermal_zone *tz, int indx)
> +{
> +	int i;
> +	struct thermal_map_attr *attr = tz->map_attr[indx];
> +
> +	for (i = 0; i < NUM_MAP_ATTRS; i++)
> +		device_remove_file(&tz->device, &attr->attrs[i].attr);
> +
> +	kfree(tz->map_attr[indx]);
> +	tz->map[indx] = 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)) {
> +			__remove_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)) {
> +			__remove_map_entry(tz, i);
> +		}
> +	}
> +}
> +
>  /* sys I/F for thermal zone */
>  
>  #define to_thermal_zone(_dev) \
> @@ -917,6 +955,107 @@ policy_show(struct device *dev, struct device_attribute *devattr, char *buf)
>  }
>  
>  static ssize_t
> +map_ttype_show(struct device *dev, struct device_attribute *attr, char *buf)
> +{
> +	char *trip;
> +	int indx;
> +	struct thermal_zone *tz = to_zone(dev);
> +
> +	if (!sscanf(attr->attr.name, "map%d_trip_type", &indx))
> +		return -EINVAL;
> +
> +	if (indx < 0 || indx >= MAX_MAPS_PER_ZONE)
> +		return -EINVAL;
> +
> +	if (!tz->map[indx])
> +		return sprintf(buf, "<Unavailable>\n");
> +
> +	trip = (tz->map[indx]->trip_type == THERMAL_TRIP_ACTIVE) ?
> +						"active" : "passive";
> +	return sprintf(buf, "%s\n", trip);
> +}
> +
> +static ssize_t map_ts_name_show(struct device *dev,
> +				struct device_attribute *attr, char *buf)
> +{
> +	int indx;
> +	struct thermal_zone *tz = to_zone(dev);
> +
> +	if (!sscanf(attr->attr.name, "map%d_sensor_name", &indx))
> +		return -EINVAL;
> +
> +	if (indx < 0 || indx >= MAX_MAPS_PER_ZONE)
> +		return -EINVAL;
> +
> +	if (!tz->map[indx])
> +		return sprintf(buf, "<Unavailable>\n");
> +
> +	return sprintf(buf, "%s\n", tz->map[indx]->sensor_name);
> +}
> +
> +static ssize_t map_cdev_name_show(struct device *dev,
> +				struct device_attribute *attr, char *buf)
> +{
> +	int indx;
> +	struct thermal_zone *tz = to_zone(dev);
> +
> +	if (!sscanf(attr->attr.name, "map%d_cdev_name", &indx))
> +		return -EINVAL;
> +
> +	if (indx < 0 || indx >= MAX_MAPS_PER_ZONE)
> +		return -EINVAL;
> +
> +	if (!tz->map[indx])
> +		return sprintf(buf, "<Unavailable>\n");
> +
> +	return sprintf(buf, "%s\n", tz->map[indx]->cdev_name);
> +}
> +
> +static ssize_t map_trip_mask_show(struct device *dev,
> +				struct device_attribute *attr, char *buf)
> +{
> +	int indx;
> +	struct thermal_zone *tz = to_zone(dev);
> +
> +	if (!sscanf(attr->attr.name, "map%d_trip_mask", &indx))
> +		return -EINVAL;
> +
> +	if (indx < 0 || indx >= MAX_MAPS_PER_ZONE)
> +		return -EINVAL;
> +
> +	if (!tz->map[indx])
> +		return sprintf(buf, "<Unavailable>\n");
> +
> +	return sprintf(buf, "0x%x\n", tz->map[indx]->trip_mask);
> +}
> +
> +static ssize_t map_weights_show(struct device *dev,
> +				struct device_attribute *attr, char *buf)
> +{
> +	int i, indx, ret = 0;
> +	struct thermal_map *map;
> +	struct thermal_zone *tz = to_zone(dev);
> +
> +	if (!sscanf(attr->attr.name, "map%d_weights", &indx))
> +		return -EINVAL;
> +
> +	if (indx < 0 || indx >= MAX_MAPS_PER_ZONE)
> +		return -EINVAL;
> +
> +	if (!tz->map[indx])
> +		return sprintf(buf, "<Unavailable>\n");
> +
> +	map = tz->map[indx];
> +
> +	ret += sprintf(buf, "%d", map->weights[0]);
> +	for (i = 1; 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 device *dev, struct device_attribute *attr, char *buf)
>  {
>  	int i, indx, ret = 0;
> @@ -1655,8 +1794,10 @@ void thermal_cooling_device_unregister(struct thermal_cooling_device *cdev)
>  
>  	mutex_lock(&zone_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(&zone_list_lock);
>  
> @@ -1994,6 +2135,9 @@ void remove_thermal_zone(struct thermal_zone *tz)
>  				kobject_name(&tz->cdevs[i]->device.kobj));
>  	}
>  
> +	for (i = 0; i < MAX_MAPS_PER_ZONE; i++)
> +		__remove_map_entry(tz, i);
> +
>  	release_idr(&thermal_zone_idr, &thermal_idr_lock, tz->id);
>  	idr_destroy(&tz->idr);
>  
> @@ -2039,6 +2183,77 @@ struct thermal_sensor *get_sensor_by_name(const char *name)
>  }
>  EXPORT_SYMBOL(get_sensor_by_name);
>  
> +static int create_map_attrs(struct thermal_zone *tz, int indx)
> +{
> +	int ret, i;
> +	struct thermal_map_attr *attr = tz->map_attr[indx];
> +
> +	static const char *const names[NUM_MAP_ATTRS] = { "map%d_trip_type",
> +			"map%d_sensor_name", "map%d_cdev_name",
> +			"map%d_trip_mask", "map%d_weights" };
> +	static ssize_t (*const rd_ptr[NUM_MAP_ATTRS]) (struct device *dev,
> +			struct device_attribute *devattr, char *buf) = {
> +			map_ttype_show, map_ts_name_show, map_cdev_name_show,
> +			map_trip_mask_show, map_weights_show };
> +
> +	for (i = 0; i < NUM_MAP_ATTRS; i++) {
> +		snprintf(attr->attrs[i].name,
> +			THERMAL_NAME_LENGTH, names[i], indx);
> +		attr->attrs[i].attr.attr.name = attr->attrs[i].name;
> +		attr->attrs[i].attr.attr.mode = S_IRUGO;
> +		attr->attrs[i].attr.show = rd_ptr[i];
> +		sysfs_attr_init(&attr->attrs[i].attr);
> +
> +		ret = device_create_file(&tz->device, &attr->attrs[i].attr);
> +		if (ret)
> +			goto exit_free;
> +	}
> +	return 0;
> +exit_free:
> +	while (--i >= 0)
> +		device_remove_file(&tz->device, &attr->attrs[i].attr);
> +	return ret;
> +}
> +
> +int add_map_entry(struct thermal_zone *tz, struct thermal_map *map)
> +{
> +	int ret, indx;
> +
> +	if (!tz || !map)
> +		return -EINVAL;
> +
> +	mutex_lock(&zone_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;
> +	}
> +
> +	ret = create_map_attrs(tz, indx);
> +	if (ret) {
> +		kfree(tz->map_attr[indx]);
> +		goto exit;
> +	}
> +
> +	tz->map[indx] = map;
> +exit:
> +	mutex_unlock(&zone_list_lock);
> +	return ret;
> +}
> +EXPORT_SYMBOL(add_map_entry);
> +
>  int add_sensor_to_zone(struct thermal_zone *tz, struct thermal_sensor *ts)
>  {
>  	int ret;
> @@ -2243,8 +2458,10 @@ void thermal_sensor_unregister(struct thermal_sensor *ts)
>  
>  	mutex_lock(&zone_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(&zone_list_lock);
>  
> diff --git a/include/linux/thermal.h b/include/linux/thermal.h
> index 2f68018..4389599 100644
> --- a/include/linux/thermal.h
> +++ b/include/linux/thermal.h
> @@ -60,6 +60,11 @@
>  
>  #define MAX_CDEVS_PER_ZONE		5
>  
> +#define NUM_MAP_ATTRS			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;
> @@ -167,6 +172,20 @@ struct thermal_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;
> +};
> +
> +struct thermal_map_attr {
> +	struct thermal_attr attrs[NUM_MAP_ATTRS];
> +};
> +
>  /*
>   * This structure defines the trip points for a sensor.
>   * The actual values for these trip points come from
> @@ -256,6 +275,10 @@ struct thermal_zone {
>  	/* Thermal sensors trip information */
>  	struct thermal_trip_point *sensor_trip[MAX_SENSORS_PER_ZONE];
>  	struct thermal_trip_attr *trip_attr[MAX_SENSORS_PER_ZONE];
> +
> +	/* Thermal map information */
> +	struct thermal_map *map[MAX_MAPS_PER_ZONE];
> +	struct thermal_map_attr *map_attr[MAX_MAPS_PER_ZONE];
>  };
>  
>  /* Structure that holds thermal governor information */
> @@ -341,6 +364,8 @@ struct thermal_cooling_device *get_cdev_by_name(const char *);
>  int add_sensor_trip_info(struct thermal_zone *, struct thermal_sensor *,
>  			struct thermal_trip_point *);
>  
> +int add_map_entry(struct thermal_zone *, struct thermal_map *);
> +
>  #ifdef CONFIG_NET
>  extern int thermal_generate_netlink_event(struct thermal_zone_device *tz,
>  						enum events event);



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

* RE: [PATCH 5/8] Thermal: Create Thermal map sysfs attributes for a zone
  2013-02-08  9:04   ` Zhang Rui
@ 2013-02-08  9:08     ` R, Durgadoss
  2013-02-08  9:55       ` Zhang Rui
  0 siblings, 1 reply; 39+ messages in thread
From: R, Durgadoss @ 2013-02-08  9:08 UTC (permalink / raw)
  To: Zhang, Rui; +Cc: linux-pm, linux-kernel, eduardo.valentin, hongbo.zhang, wni

[-- Warning: decoded text below may be mangled, UTF-8 assumed --]
[-- Attachment #1: Type: text/plain; charset="utf-8", Size: 1194 bytes --]

Hi Rui,

> -----Original Message-----
> From: Zhang, Rui
> Sent: Friday, February 08, 2013 2:35 PM
> To: R, Durgadoss
> Cc: linux-pm@vger.kernel.org; linux-kernel@vger.kernel.org;
> eduardo.valentin@ti.com; hongbo.zhang@linaro.org; wni@nvidia.com
> Subject: Re: [PATCH 5/8] Thermal: Create Thermal map sysfs attributes for a
> zone
> 
> On Tue, 2013-02-05 at 16:16 +0530, Durgadoss R wrote:
> > This patch creates a thermal map sysfs node under
> > /sys/class/thermal/zoneX/. This contains
> > entries named mapY_trip_type, mapY_sensor_name,
> > mapY_cdev_name, mapY_trip_mask, mapY_weights.
> sorry I still not quite understand.
> 
> does it look like?
> /sys/class/thermal/zoneX/
> |
> map-->|-->map0_trip_type
>       |...
>       |-->map0_weight
>       |-->map1_trip_type
>       |...
>       |-->map1_weight
>       |...
> 

There is no separate 'map' directory.
So, everything is under /sys/class/thermal/zoneX/ directly,
named as map0_weight etc...

I think I should make the Doc/ABI patch should clarify this.

Thanks,
Durga
ÿôèº{.nÇ+‰·Ÿ®‰­†+%ŠËÿ±éݶ\x17¥Šwÿº{.nÇ+‰·¥Š{±þG«éÿŠ{ayº\x1dʇڙë,j\a­¢f£¢·hšïêÿ‘êçz_è®\x03(­éšŽŠÝ¢j"ú\x1a¶^[m§ÿÿ¾\a«þG«éÿ¢¸?™¨è­Ú&£ø§~á¶iO•æ¬z·švØ^\x14\x04\x1a¶^[m§ÿÿÃ\fÿ¶ìÿ¢¸?–I¥

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

* Re: [PATCH 6/8] Thermal: Add Documentation to new APIs
  2013-02-05 10:46 ` [PATCH 6/8] Thermal: Add Documentation to new APIs Durgadoss R
@ 2013-02-08  9:21   ` Zhang Rui
  0 siblings, 0 replies; 39+ messages in thread
From: Zhang Rui @ 2013-02-08  9:21 UTC (permalink / raw)
  To: Durgadoss R; +Cc: linux-pm, linux-kernel, eduardo.valentin, hongbo.zhang, wni

On Tue, 2013-02-05 at 16:16 +0530, Durgadoss R 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 |  247 ++++++++++++++++++++++++++++++++++
>  1 file changed, 247 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..24e23f4
> --- /dev/null
> +++ b/Documentation/thermal/sysfs-api2.txt
> @@ -0,0 +1,247 @@
> +Thermal Framework
> +-----------------
> +
> +Written by Durgadoss R <durgadoss.r@intel.com>
> +Copyright (c) 2012 Intel Corporation
> +
> +Created on: 4 November 2012
> +Updated on: 5 February 2013
> +
> +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.
> +
> +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.
> +
> +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
> +	count: Number of programmable thresholds associated with this 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
> +		.get_hyst: get hysteresis value associated with a threshold
> +		.set_hyst: set hysteresis value associated with a threshold
> +
> +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.

s/sensr/sensor

> +
> +	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/.
> +	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.
if this is true, actually it is, it breaks the sysfs "one value per
file" rule.
we should have multiple active/passive attributes if there are multiple
trip points.

thanks,
rui
> +
> +	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/mapY_*. Each map attribute helps
> +	to describe 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/sensor[0-*]:
> +		|---type:		Name of the thermal sensor
> +		|---temp_input:		Current temperature in mC
> +		|---threshold[0-*]:	Threshold temperature in mC
> +		|---threshold[0-*]_hyst:Optional hysteresis value in mC
> +
> +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 a sensor(Y)
> +	present in the thermal zone(X). All values are in mC.
> +	/sys/class/thermal/zoneX/:
> +		|---sensorY_trip_hot:		hot trip point
> +		|---sensorY_trip_critical:	critical trip point
> +		|---sensorY_trip_passive:	passive trip point
> +		|---sensorY_trip_active:	active trip point
> +
> +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/:
> +		|---mapY_trip_type:		active/passive
> +		|---mapY_sensor_name:		cpu
> +		|---mapY_cdev_name:		proc
> +		|---mapY_trip_mask:		0x03
> +		|---mapY_weights:		50 30
> +
> +	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].



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

* Re: [PATCHv3 0/8] Thermal Framework Enhancements
  2013-02-05 10:46 [PATCHv3 0/8] Thermal Framework Enhancements Durgadoss R
                   ` (8 preceding siblings ...)
  2013-02-08  7:53 ` [PATCHv3 0/8] Thermal Framework Enhancements Zhang Rui
@ 2013-02-08  9:35 ` Zhang Rui
  2013-02-28 21:33 ` Eduardo Valentin
  2013-08-29 19:38 ` Eduardo Valentin
  11 siblings, 0 replies; 39+ messages in thread
From: Zhang Rui @ 2013-02-08  9:35 UTC (permalink / raw)
  To: Durgadoss R; +Cc: linux-pm, linux-kernel, eduardo.valentin, hongbo.zhang, wni

On Tue, 2013-02-05 at 16:16 +0530, Durgadoss R wrote:
> This patch set is a v3 of the previous versions submitted here:
> [v2]: http://lwn.net/Articles/531720/
> [v1]: https://lkml.org/lkml/2012/12/18/108 
> [RFC]:https://patchwork.kernel.org/patch/1758921/
> 
> This patch set is based on Rui's -next tree, and is
> tested on a Core-i5 and an Atom netbook.
> 
> Changes since v2:
>  * Reworked the map sysfs attributes in patch [5/8]
>  * Dropped configuration for maximum sensors and
>    cooling devices, through Kconfig.
>  * Added __remove_trip_attr method
>  * Renamed __clean_map_entry to __remove_map_entry
>    for consistency in naming.
> Changes Since v1:
>  * Removed kobject creation for thermal_trip and thermal_map
>    nodes as per Greg-KH's comments.
>  * Added ABI Documentation under 'testing'.
>  * Modified the GET_INDEX macro to be more linux-like, thanks
>    to Joe Perches.
>  * Added get_[sensor/cdev]_by_name APIs to thermal.h
> 
> This series contains 8 patches:
> Patch 1/8: Creates new sensor level APIs
> Patch 2/8: Creates new zone level APIs. The existing tzd structure is
>            kept as such for clarity and compatibility purposes.
> Patch 3/8: Creates functions to add/remove a cdev to/from a zone. The
>            existing tcd structure need not be modified.
> Patch 4/8: Adds sensorX_trip_[active/passive/hot/critical] sysfs nodes,
> 	   under /sys/class/thermal/zoneY/. This exposes various trip
>            points for sensorX present in zoneY.
> Patch 5/8: Adds mapY_* sysfs node. These attributes represent
>            the binding relationship between a sensor and a cdev,
>            within a zone.
> Patch 6/8: 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/8: Add ABI documentation for sysfs interfaces introduced in this patch.
> Patch 8/8: A dummy driver that can be used for testing. This is not for merge.
> 
Generally, this patch set looks good to me.
But My suggestion would be:
1. introduce a new config option for the new framework.
2. If your patches are target for 3.9, you still need to introduce a
   wrapper so that platform thermal drivers can be redirect
   to either the new framework or the old one via the Kconfig option.
   (All the current platform thermal drivers should be zones with single
   sensor). And with this wrapper, users should be able to
   switching between the new ABI and old ABI via kernel config option,
   without touching the platform thermal driver code in 3.9 kernel.
3. in next release, make the old framework optional, and make the new
   framework set by default.
4. in next next release, remove the old framework.

thanks,
rui
> Durgadoss R (8):
>   Thermal: Create sensor level APIs
>   Thermal: Create zone level APIs
>   Thermal: Add APIs to bind cdev to new zone structure
>   Thermal: Add trip point sysfs nodes for sensor
>   Thermal: Create Thermal map sysfs attributes for a zone
>   Thermal: Add Documentation to new APIs
>   Thermal: Add ABI Documentation for sysfs interfaces
>   Thermal: Dummy driver used for testing
> 
>  Documentation/ABI/testing/sysfs-class-thermal |  137 ++++
>  Documentation/thermal/sysfs-api2.txt          |  247 ++++++
>  drivers/thermal/Kconfig                       |    5 +
>  drivers/thermal/Makefile                      |    2 +
>  drivers/thermal/thermal_sys.c                 |  994 +++++++++++++++++++++++++
>  drivers/thermal/thermal_test.c                |  324 ++++++++
>  include/linux/thermal.h                       |  123 ++-
>  7 files changed, 1831 insertions(+), 1 deletion(-)
>  create mode 100644 Documentation/ABI/testing/sysfs-class-thermal
>  create mode 100644 Documentation/thermal/sysfs-api2.txt
>  create mode 100644 drivers/thermal/thermal_test.c
> 



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

* RE: [PATCH 2/8] Thermal: Create zone level APIs
  2013-02-08  8:54     ` R, Durgadoss
@ 2013-02-08  9:54       ` Zhang Rui
  2013-02-08 10:27         ` R, Durgadoss
  0 siblings, 1 reply; 39+ messages in thread
From: Zhang Rui @ 2013-02-08  9:54 UTC (permalink / raw)
  To: R, Durgadoss; +Cc: linux-pm, linux-kernel, eduardo.valentin, hongbo.zhang, wni

On Fri, 2013-02-08 at 01:54 -0700, R, Durgadoss wrote:
> Hi Rui,
> 
> > -----Original Message-----
> > From: Zhang, Rui
> > Sent: Friday, February 08, 2013 1:42 PM
> > To: R, Durgadoss
> > Cc: linux-pm@vger.kernel.org; linux-kernel@vger.kernel.org;
> > eduardo.valentin@ti.com; hongbo.zhang@linaro.org; wni@nvidia.com
> > Subject: Re: [PATCH 2/8] Thermal: Create zone level APIs
> > 
> > On Tue, 2013-02-05 at 16:16 +0530, Durgadoss R wrote:
> > > This patch adds a new thermal_zone structure to
> > > thermal.h. Also, adds zone level APIs to the thermal
> > > framework.
> > >
> 
> [snip.]
> 
> > > +
> > > +struct thermal_sensor *get_sensor_by_name(const char *name)
> > > +{
> > > +	struct thermal_sensor *pos;
> > > +	struct thermal_sensor *ts = NULL;
> > > +
> > > +	mutex_lock(&sensor_list_lock);
> > > +	for_each_thermal_sensor(pos) {
> > > +		if (!strnicmp(pos->name, name, THERMAL_NAME_LENGTH))
> > {
> > > +			ts = pos;
> > > +			break;
> > 
> > this function depends on the assumption that all the sensor names are
> > unique.
> > thus I prefer to go through all the list and return -EINVAL if duplicate
> > names found, because in this case, the pointer returned may be not the
> > sensor we want to get.
> 
> Yes, I agree with you. But I prefer having this check in the register API
> itself, which then will not allow duplicates.
> 
No, I do not think so.

Unique cdev/sensor name is not a hard rule for generic thermal layer,
and will not be.
Because any cooling device driver does not have the technology that if
its name is platform unique or not.

Say, your platform thermal driver wants to use FAN cooling device, what
if another FAN cooling device has been registered before the FAN your
platform thermal driver wants to use get registered?
If the platform thermal driver wants to use get_cdev/sensor_by_name(),
it has already made the assumption that all the cooling devices have
unique names. Thus duplicate names are a big issue, we should abort the
platform thermal driver, rather than aborting the cooling device driver
with duplicate names.

> The reason being, we use this get* API (comparatively) a lot more than
> the register APIs.

why?
why can not invoke get_sensor/cdev_by_name once and cache the pointer in
the platform thermal driver?

thanks,
rui


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

* RE: [PATCH 1/8] Thermal: Create sensor level APIs
  2013-02-08  8:26     ` R, Durgadoss
@ 2013-02-08  9:54       ` Zhang Rui
  0 siblings, 0 replies; 39+ messages in thread
From: Zhang Rui @ 2013-02-08  9:54 UTC (permalink / raw)
  To: R, Durgadoss; +Cc: linux-pm, linux-kernel, eduardo.valentin, hongbo.zhang, wni

On Fri, 2013-02-08 at 01:26 -0700, R, Durgadoss wrote:
> Hi Rui,
> 
> > -----Original Message-----
> > From: Zhang, Rui
> > Sent: Friday, February 08, 2013 1:24 PM
> > To: R, Durgadoss
> > Cc: linux-pm@vger.kernel.org; linux-kernel@vger.kernel.org;
> > eduardo.valentin@ti.com; hongbo.zhang@linaro.org; wni@nvidia.com
> > Subject: Re: [PATCH 1/8] Thermal: Create sensor level APIs
> > 
> > On Tue, 2013-02-05 at 16:16 +0530, Durgadoss R wrote:
> > > This patch creates sensor level APIs, in the
> > > generic thermal framework.
> 
> [snip.]
> 
> > > +
> > >  static ssize_t
> > >  type_show(struct device *dev, struct device_attribute *attr, char *buf)
> > >  {
> > > @@ -707,6 +807,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)
> > > @@ -1493,6 +1597,182 @@ static void remove_trip_attrs(struct
> > thermal_zone_device *tz)
> > >  }
> > >
> > >  /**
> > > + * enable_sensor_thresholds - create sysfs nodes for thresholdX
> > 
> > this is a little confusing.
> > I'd prefer
> > thermal_sensor_sysfs_add() and create sensor_name and temp_input
> > attribute in this function as well, and thermal_sensor_sysfs_remove()
> > to remove the sysfs I/F.
> > And further more, we can do this for thermal zones and cooling devices.
> 
> I agree, and we will change this.
> Since this involves change for all standard APIs, I think it is better to submit
> a separate patch to do this. What do you think ?
> 
I'm okay with this.

thanks,
rui
> > 
> > others look okay to me.
> 
> Thank you :-)
> 
> > 
> > thanks,
> > rui
> 



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

* RE: [PATCH 5/8] Thermal: Create Thermal map sysfs attributes for a zone
  2013-02-08  9:08     ` R, Durgadoss
@ 2013-02-08  9:55       ` Zhang Rui
  0 siblings, 0 replies; 39+ messages in thread
From: Zhang Rui @ 2013-02-08  9:55 UTC (permalink / raw)
  To: R, Durgadoss; +Cc: linux-pm, linux-kernel, eduardo.valentin, hongbo.zhang, wni

On Fri, 2013-02-08 at 02:08 -0700, R, Durgadoss wrote:
> Hi Rui,
> 
> > -----Original Message-----
> > From: Zhang, Rui
> > Sent: Friday, February 08, 2013 2:35 PM
> > To: R, Durgadoss
> > Cc: linux-pm@vger.kernel.org; linux-kernel@vger.kernel.org;
> > eduardo.valentin@ti.com; hongbo.zhang@linaro.org; wni@nvidia.com
> > Subject: Re: [PATCH 5/8] Thermal: Create Thermal map sysfs attributes for a
> > zone
> > 
> > On Tue, 2013-02-05 at 16:16 +0530, Durgadoss R wrote:
> > > This patch creates a thermal map sysfs node under
> > > /sys/class/thermal/zoneX/. This contains
> > > entries named mapY_trip_type, mapY_sensor_name,
> > > mapY_cdev_name, mapY_trip_mask, mapY_weights.
> > sorry I still not quite understand.
> > 
> > does it look like?
> > /sys/class/thermal/zoneX/
> > |
> > map-->|-->map0_trip_type
> >       |...
> >       |-->map0_weight
> >       |-->map1_trip_type
> >       |...
> >       |-->map1_weight
> >       |...
> > 
> 
> There is no separate 'map' directory.
> So, everything is under /sys/class/thermal/zoneX/ directly,
> named as map0_weight etc...
> 
got it.

thanks,
rui

> I think I should make the Doc/ABI patch should clarify this.
> 
> Thanks,
> Durga



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

* RE: [PATCH 2/8] Thermal: Create zone level APIs
  2013-02-08  9:54       ` Zhang Rui
@ 2013-02-08 10:27         ` R, Durgadoss
  0 siblings, 0 replies; 39+ messages in thread
From: R, Durgadoss @ 2013-02-08 10:27 UTC (permalink / raw)
  To: Zhang, Rui; +Cc: linux-pm, linux-kernel, eduardo.valentin, hongbo.zhang, wni

[-- Warning: decoded text below may be mangled, UTF-8 assumed --]
[-- Attachment #1: Type: text/plain; charset="utf-8", Size: 2976 bytes --]

> -----Original Message-----
> From: Zhang, Rui
> Sent: Friday, February 08, 2013 3:24 PM
> To: R, Durgadoss
> Cc: linux-pm@vger.kernel.org; linux-kernel@vger.kernel.org;
> eduardo.valentin@ti.com; hongbo.zhang@linaro.org; wni@nvidia.com
> Subject: RE: [PATCH 2/8] Thermal: Create zone level APIs
> 
> On Fri, 2013-02-08 at 01:54 -0700, R, Durgadoss wrote:
> > Hi Rui,
> >
> > > -----Original Message-----
> > > From: Zhang, Rui
> > > Sent: Friday, February 08, 2013 1:42 PM
> > > To: R, Durgadoss
> > > Cc: linux-pm@vger.kernel.org; linux-kernel@vger.kernel.org;
> > > eduardo.valentin@ti.com; hongbo.zhang@linaro.org; wni@nvidia.com
> > > Subject: Re: [PATCH 2/8] Thermal: Create zone level APIs
> > >
> > > On Tue, 2013-02-05 at 16:16 +0530, Durgadoss R wrote:
> > > > This patch adds a new thermal_zone structure to
> > > > thermal.h. Also, adds zone level APIs to the thermal
> > > > framework.
> > > >
> >
> > [snip.]
> >
> > > > +
> > > > +struct thermal_sensor *get_sensor_by_name(const char *name)
> > > > +{
> > > > +	struct thermal_sensor *pos;
> > > > +	struct thermal_sensor *ts = NULL;
> > > > +
> > > > +	mutex_lock(&sensor_list_lock);
> > > > +	for_each_thermal_sensor(pos) {
> > > > +		if (!strnicmp(pos->name, name, THERMAL_NAME_LENGTH))
> > > {
> > > > +			ts = pos;
> > > > +			break;
> > >
> > > this function depends on the assumption that all the sensor names are
> > > unique.
> > > thus I prefer to go through all the list and return -EINVAL if duplicate
> > > names found, because in this case, the pointer returned may be not the
> > > sensor we want to get.
> >
> > Yes, I agree with you. But I prefer having this check in the register API
> > itself, which then will not allow duplicates.
> >
> No, I do not think so.
> 
> Unique cdev/sensor name is not a hard rule for generic thermal layer,
> and will not be.
> Because any cooling device driver does not have the technology that if
> its name is platform unique or not.
> 
> Say, your platform thermal driver wants to use FAN cooling device, what
> if another FAN cooling device has been registered before the FAN your
> platform thermal driver wants to use get registered?
> If the platform thermal driver wants to use get_cdev/sensor_by_name(),
> it has already made the assumption that all the cooling devices have
> unique names. Thus duplicate names are a big issue, we should abort the
> platform thermal driver, rather than aborting the cooling device driver
> with duplicate names.
> 
> > The reason being, we use this get* API (comparatively) a lot more than
> > the register APIs.
> 
> why?
> why can not invoke get_sensor/cdev_by_name once and cache the pointer
> in
> the platform thermal driver?

Okay, I did not think of this caching part ..
Then, I am fine with this change. Will fix it in next version.

Thanks,
Durga
ÿôèº{.nÇ+‰·Ÿ®‰­†+%ŠËÿ±éݶ\x17¥Šwÿº{.nÇ+‰·¥Š{±þG«éÿŠ{ayº\x1dʇڙë,j\a­¢f£¢·hšïêÿ‘êçz_è®\x03(­éšŽŠÝ¢j"ú\x1a¶^[m§ÿÿ¾\a«þG«éÿ¢¸?™¨è­Ú&£ø§~á¶iO•æ¬z·švØ^\x14\x04\x1a¶^[m§ÿÿÃ\fÿ¶ìÿ¢¸?–I¥

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

* Re: [PATCH 1/8] Thermal: Create sensor level APIs
  2013-02-05 10:46 ` [PATCH 1/8] Thermal: Create sensor level APIs Durgadoss R
  2013-02-08  7:53   ` Zhang Rui
@ 2013-02-28 18:58   ` Eduardo Valentin
  2013-03-01  5:08     ` R, Durgadoss
  1 sibling, 1 reply; 39+ messages in thread
From: Eduardo Valentin @ 2013-02-28 18:58 UTC (permalink / raw)
  To: Durgadoss R; +Cc: rui.zhang, linux-pm, linux-kernel, hongbo.zhang, wni

Durga,

On 05-02-2013 06:46, Durgadoss R wrote:
> This patch creates sensor level APIs, in the
> generic thermal framework.
>
> A Thermal sensor is a piece of hardware that can report
> temperature of the spot in which it is placed. A thermal
> sensor driver reads the temperature from this sensor
> and reports it out. This kind of driver can be in
> any subsystem. If the sensor needs to participate
> in platform thermal management, the corresponding
> driver can use the APIs introduced in this patch, to
> register(or unregister) with the thermal framework.

At first glance, patch seams reasonable. But I have one major concern as 
follows inline, apart from several minor comments.

>
> Signed-off-by: Durgadoss R <durgadoss.r@intel.com>
> ---
>   drivers/thermal/thermal_sys.c |  280 +++++++++++++++++++++++++++++++++++++++++
>   include/linux/thermal.h       |   29 +++++
>   2 files changed, 309 insertions(+)
>
> diff --git a/drivers/thermal/thermal_sys.c b/drivers/thermal/thermal_sys.c
> index 0a1bf6b..cb94497 100644
> --- a/drivers/thermal/thermal_sys.c
> +++ b/drivers/thermal/thermal_sys.c
> @@ -44,13 +44,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(sensor_list_lock);
>   static DEFINE_MUTEX(thermal_governor_lock);
>
>   static struct thermal_governor *__find_governor(const char *name)
> @@ -423,6 +426,103 @@ 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);

For security reasons:
s/sprintf/snprintf

> +}
> +
> +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);

ditto.

> +}
> +
> +static ssize_t
> +hyst_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_hyst", &indx))

I'd rather check if it returns 1.

> +		return -EINVAL;
> +
> +	ret = ts->ops->get_hyst(ts, indx, &val);

 From your probe, you won't check for devices registered with 
ops.get_hyst == NULL. This may lead to a NULL pointer access above.

> +
> +	return ret ? ret : sprintf(buf, "%ld\n", val);

snprintf.

> +}
> +
> +static ssize_t
> +hyst_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_hyst)
> +		return -EPERM;
> +
> +	if (!sscanf(attr->attr.name, "threshold%d_hyst", &indx))
> +		return -EINVAL;
> +
> +	if (kstrtol(buf, 10, &val))
> +		return -EINVAL;
> +
> +	ret = ts->ops->set_hyst(ts, indx, val);

 From your probe, you won't check for devices registered with
ops.set_hyst == NULL. This may lead to a NULL pointer access above.

> +
> +	return ret ? ret : count;
> +}
> +
> +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);
 From your probe, you won't check for devices registered with
ops.get_threshold == NULL. This may lead to a NULL pointer access above.

> +
> +	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;
> +}
> +

One may be careful with the above functions. Userland having control on 
these properties may lead to spurious events, depending on the 
programming sequence / value changing order. I believe, it would be 
wiser to disable the interrupt generation prior to changing the thresholds.

>   static ssize_t
>   type_show(struct device *dev, struct device_attribute *attr, char *buf)
>   {
> @@ -707,6 +807,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)
> @@ -1493,6 +1597,182 @@ static void remove_trip_attrs(struct thermal_zone_device *tz)
>   }
>
>   /**
> + * enable_sensor_thresholds - create sysfs nodes for thresholdX
> + * @ts:		the thermal sensor
> + * @count:	Number of thresholds supported by sensor hardware
> + *
> + * 'Thresholds' are temperatures programmed into the sensor hardware,
> + * on crossing which the sensor generates an interrupt. 'Trip points'
> + * are temperatures which the thermal manager/governor thinks, some
> + * action should be taken when the sensor reaches the value.
> + */
> +static int enable_sensor_thresholds(struct thermal_sensor *ts, int count)
> +{
> +	int i;
> +	int size = sizeof(struct thermal_attr) * count;
> +
> +	ts->thresh_attrs = kzalloc(size, GFP_KERNEL);

how about using devm_ helpers?

> +	if (!ts->thresh_attrs)
> +		return -ENOMEM;
> +
> +	if (ts->ops->get_hyst) {
> +		ts->hyst_attrs = kzalloc(size, GFP_KERNEL);
> +		if (!ts->hyst_attrs) {
> +			kfree(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;
> +
> +		device_create_file(&ts->device, &ts->thresh_attrs[i].attr);
> +
> +		/* Create threshold_hyst attributes */
> +		if (!ts->ops->get_hyst)
> +			continue;
> +
> +		snprintf(ts->hyst_attrs[i].name, THERMAL_NAME_LENGTH,
> +						 "threshold%d_hyst", i);
> +
> +		sysfs_attr_init(&ts->hyst_attrs[i].attr.attr);
> +		ts->hyst_attrs[i].attr.attr.name = ts->hyst_attrs[i].name;
> +		ts->hyst_attrs[i].attr.attr.mode = S_IRUGO | S_IWUSR;
> +		ts->hyst_attrs[i].attr.show = hyst_show;
> +		ts->hyst_attrs[i].attr.store = hyst_store;
> +
> +		device_create_file(&ts->device, &ts->hyst_attrs[i].attr);
> +	}
> +	return 0;
> +}
> +


I know there are people who is in favor of having the thermal policy 
controlled in userland.
Depending on which thermal zone we are talking about, I'd even consider 
it a valid approach.
On the other hand there are thermal zones that controls silicon junction 
temperature which
does not depend on any input from userland (like which kind of use case 
one may be running).


That said, I believe we may want to segregate which sensors we want to 
expose the write access
from userspace to their hyst and threshold values. Exposing all of them 
may lead to easy security leak.


> +/**
> + * thermal_sensor_register - register a new thermal sensor
> + * @name:	name of the thermal sensor
> + * @count:	Number of thresholds supported by hardware
> + * @ops:	standard thermal sensor callbacks
> + * @devdata:	private device data
> + */
> +struct thermal_sensor *thermal_sensor_register(const char *name, int count,
> +			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);
> +

Please consider additional checks (see my comments above)

> +	ts = kzalloc(sizeof(*ts), GFP_KERNEL);

devm_ helpers

> +	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);

s/strcpy/strlcpy

> +	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;
> +
> +	if (count > 0 && ts->ops->get_threshold) {
> +		ret = enable_sensor_thresholds(ts, count);
> +		if (ret)
> +			goto exit_temp;
> +	}
> +
> +	/* Add this sensor to the global list of sensors */
> +	mutex_lock(&sensor_list_lock);
> +	list_add_tail(&ts->node, &thermal_sensor_list);
> +	mutex_unlock(&sensor_list_lock);
> +
> +	return ts;
> +
> +exit_temp:
> +	device_remove_file(&ts->device, &dev_attr_temp_input);
> +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(&sensor_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(&sensor_list_lock);
> +
> +	if (!found)
> +		return;
> +
> +	for (i = 0; i < ts->thresholds; i++) {
> +		device_remove_file(&ts->device, &ts->thresh_attrs[i].attr);
> +		if (ts->ops->get_hyst) {
> +			device_remove_file(&ts->device,
> +					&ts->hyst_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);
> +
> +/**
>    * 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 9b78f8c..5470dae 100644
> --- a/include/linux/thermal.h
> +++ b/include/linux/thermal.h
> @@ -55,6 +55,7 @@
>   #define DEFAULT_THERMAL_GOVERNOR       "user_space"
>   #endif
>
> +struct thermal_sensor;
>   struct thermal_zone_device;
>   struct thermal_cooling_device;
>
> @@ -135,6 +136,15 @@ 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 *);
> +	int (*set_hyst) (struct thermal_sensor *, int, long);
> +	int (*get_hyst) (struct thermal_sensor *, int, long *);
> +};
> +
>   struct thermal_cooling_device {
>   	int id;
>   	char type[THERMAL_NAME_LENGTH];
> @@ -152,6 +162,21 @@ 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_attr *hyst_attrs;
> +};
> +
>   struct thermal_zone_device {
>   	int id;
>   	char type[THERMAL_NAME_LENGTH];
> @@ -245,6 +270,10 @@ 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 *, int,
> +				struct thermal_sensor_ops *, void *);
> +void thermal_sensor_unregister(struct thermal_sensor *);
> +
>   #ifdef CONFIG_NET
>   extern int thermal_generate_netlink_event(struct thermal_zone_device *tz,
>   						enum events event);
>


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

* Re: [PATCH 2/8] Thermal: Create zone level APIs
  2013-02-05 10:46 ` [PATCH 2/8] Thermal: Create zone " Durgadoss R
  2013-02-08  8:11   ` Zhang Rui
@ 2013-02-28 19:29   ` Eduardo Valentin
  2013-03-01 15:31     ` R, Durgadoss
  1 sibling, 1 reply; 39+ messages in thread
From: Eduardo Valentin @ 2013-02-28 19:29 UTC (permalink / raw)
  To: Durgadoss R; +Cc: rui.zhang, linux-pm, linux-kernel, hongbo.zhang, wni

On 05-02-2013 06:46, Durgadoss R wrote:
> This patch adds a new thermal_zone structure to
> thermal.h. Also, adds zone level APIs to the thermal
> framework.
>
> A thermal zone is a hot spot on the platform, which
> can have one or more sensors and cooling devices attached
> to it. These sensors can be mapped to a set of cooling
> devices, which when throttled, can help to bring down
> the temperature of the hot spot.
>
> Signed-off-by: Durgadoss R <durgadoss.r@intel.com>
> ---
>   drivers/thermal/thermal_sys.c |  196 +++++++++++++++++++++++++++++++++++++++++
>   include/linux/thermal.h       |   22 +++++
>   2 files changed, 218 insertions(+)
>
> diff --git a/drivers/thermal/thermal_sys.c b/drivers/thermal/thermal_sys.c
> index cb94497..838d4fb 100644
> --- a/drivers/thermal/thermal_sys.c
> +++ b/drivers/thermal/thermal_sys.c
> @@ -43,19 +43,46 @@ 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(sensor_list_lock);
> +static DEFINE_MUTEX(zone_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)
> +
> +#define GET_INDEX(tz, ptr, type)			\

Why do you need type? You seam to be using it only for sensors. It 
becomes a bit cryptic :-)

> +({							\
> +	int i, ret = -EINVAL;				\
> +	do {						\
> +		if (!tz || !ptr)			\
> +			break;				\
> +		mutex_lock(&type##_list_lock);		\
> +		for (i = 0; i < tz->type##_indx; i++) {	\
> +			if (tz->type##s[i] == ptr) {	\
> +				ret = i;		\
> +				break;			\
> +			}				\
> +		}					\
> +		mutex_unlock(&type##_list_lock);	\
> +	} while (0);					\
> +	ret;						\
> +})
> +
>   static struct thermal_governor *__find_governor(const char *name)
>   {
>   	struct thermal_governor *pos;
> @@ -421,15 +448,44 @@ static void thermal_zone_device_check(struct work_struct *work)
>   	thermal_zone_device_update(tz);
>   }
>
> +static void remove_sensor_from_zone(struct thermal_zone *tz,
> +				struct thermal_sensor *ts)
> +{
> +	int j, indx;
> +
> +	indx = GET_INDEX(tz, ts, sensor);
> +	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);
snprintf

> +}
> +
> +static ssize_t
>   sensor_name_show(struct device *dev, struct device_attribute *attr, char *buf)
>   {
>   	struct thermal_sensor *ts = to_thermal_sensor(dev);
> @@ -811,6 +867,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)
> @@ -1656,6 +1714,136 @@ static int enable_sensor_thresholds(struct thermal_sensor *ts, int count)
>   	return 0;
>   }
>
> +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);

devm_ helpers

> +	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);

strlcpy

> +	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(&zone_list_lock);
> +	list_add_tail(&tz->node, &thermal_zone_list);
> +	mutex_unlock(&zone_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(&zone_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(&zone_list_lock);
> +	return;
> +}
> +EXPORT_SYMBOL(remove_thermal_zone);

Do we need to impose removal ordering here? Meaning, what happens if the 
above is called with sensors registered?

> +
> +struct thermal_sensor *get_sensor_by_name(const char *name)
Why do you need this function? does not seam to be used anywhere in this 
patch. Besides it is unrelated to what this patch proposes itself to do.

> +{
> +	struct thermal_sensor *pos;
> +	struct thermal_sensor *ts = NULL;
> +
> +	mutex_lock(&sensor_list_lock);
> +	for_each_thermal_sensor(pos) {
> +		if (!strnicmp(pos->name, name, THERMAL_NAME_LENGTH)) {
> +			ts = pos;
> +			break;
> +		}
> +	}
> +	mutex_unlock(&sensor_list_lock);
> +	return ts;
> +}
> +EXPORT_SYMBOL(get_sensor_by_name);
> +
> +int add_sensor_to_zone(struct thermal_zone *tz, struct thermal_sensor *ts)
> +{
> +	int ret;
> +
> +	if (!tz || !ts)
> +		return -EINVAL;
> +
> +	mutex_lock(&zone_list_lock);
> +
> +	/* Ensure we are not adding the same sensor again!! */
> +	ret = GET_INDEX(tz, ts, sensor);
> +	if (ret >= 0) {
> +		ret = -EEXIST;
> +		goto exit_zone;
> +	}
> +
> +	mutex_lock(&sensor_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;

you may overflow your sensors buffer with the above implementation.

you may have a contention on sensors/sensor_indx.

Consider using linked lists.

> +
> +exit_sensor:
> +	mutex_unlock(&sensor_list_lock);
> +exit_zone:
> +	mutex_unlock(&zone_list_lock);
> +	return ret;
> +}
> +EXPORT_SYMBOL(add_sensor_to_zone);
> +
>   /**
>    * thermal_sensor_register - register a new thermal sensor
>    * @name:	name of the thermal sensor
> @@ -1732,6 +1920,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;
>
> @@ -1751,6 +1940,13 @@ void thermal_sensor_unregister(struct thermal_sensor *ts)
>   	if (!found)
>   		return;
>
> +	mutex_lock(&zone_list_lock);
> +
> +	for_each_thermal_zone(tz)
> +		remove_sensor_from_zone(tz, ts);
> +
> +	mutex_unlock(&zone_list_lock);
> +
>   	for (i = 0; i < ts->thresholds; i++) {
>   		device_remove_file(&ts->device, &ts->thresh_attrs[i].attr);
>   		if (ts->ops->get_hyst) {
> diff --git a/include/linux/thermal.h b/include/linux/thermal.h
> index 5470dae..2194519 100644
> --- a/include/linux/thermal.h
> +++ b/include/linux/thermal.h
> @@ -55,6 +55,8 @@
>   #define DEFAULT_THERMAL_GOVERNOR       "user_space"
>   #endif
>
> +#define MAX_SENSORS_PER_ZONE		5


Why not making it a linked list? Why does it need to be static? Just 
trying to avoid to maintain this number sane, as we cannot predict what 
happens in future :-)

> +
>   struct thermal_sensor;
>   struct thermal_zone_device;
>   struct thermal_cooling_device;
> @@ -202,6 +204,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];
> +};


Could you please add documentation for the above structure? Why it does 
not need locking? what is *ops?
> +
>   /* Structure that holds thermal governor information */
>   struct thermal_governor {
>   	char name[THERMAL_NAME_LENGTH];
> @@ -274,6 +291,11 @@ struct thermal_sensor *thermal_sensor_register(const char *, int,
>   				struct thermal_sensor_ops *, void *);
>   void thermal_sensor_unregister(struct thermal_sensor *);
>
> +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 *);
> +struct thermal_sensor *get_sensor_by_name(const char *);
> +

I believe we need a better naming for this API. First suggestion is to 
use same prefix on all of them. Probably this comment applies not only 
to this specific patch.

Besides, for all functions above, you may want to add comments 
documenting them and their parameters?

>   #ifdef CONFIG_NET
>   extern int thermal_generate_netlink_event(struct thermal_zone_device *tz,
>   						enum events event);
>


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

* Re: [PATCH 3/8] Thermal: Add APIs to bind cdev to new zone structure
  2013-02-05 10:46 ` [PATCH 3/8] Thermal: Add APIs to bind cdev to new zone structure Durgadoss R
  2013-02-08  8:28   ` Zhang Rui
@ 2013-02-28 19:35   ` Eduardo Valentin
  2013-03-01 15:33     ` R, Durgadoss
  1 sibling, 1 reply; 39+ messages in thread
From: Eduardo Valentin @ 2013-02-28 19:35 UTC (permalink / raw)
  To: Durgadoss R; +Cc: rui.zhang, linux-pm, linux-kernel, hongbo.zhang, wni

Durga,

On 05-02-2013 06:46, Durgadoss R wrote:
> This patch creates new APIs to add/remove a
> cdev to/from a zone. This patch does not change
> the old cooling device implementation.

Same comments on patch 02/08 I want to rise here:

- Consider using linked list
- You may have contention on your index/cdevs array
- overflow on your buffer (carefully check your implementation)
- zone removal condition. can we remove zones with cdevs registered?
- get_by_name, why do we need it? (at least not on this patch)
- Minors on strlcpy, snprintf, devm_ helpers
- documentation in the code for these helper functions and also better 
naming..

>
> Signed-off-by: Durgadoss R <durgadoss.r@intel.com>
> ---
>   drivers/thermal/thermal_sys.c |   80 +++++++++++++++++++++++++++++++++++++++++
>   include/linux/thermal.h       |    9 +++++
>   2 files changed, 89 insertions(+)
>
> diff --git a/drivers/thermal/thermal_sys.c b/drivers/thermal/thermal_sys.c
> index 838d4fb..bf703b1 100644
> --- a/drivers/thermal/thermal_sys.c
> +++ b/drivers/thermal/thermal_sys.c
> @@ -57,6 +57,7 @@ static LIST_HEAD(thermal_governor_list);
>   static DEFINE_MUTEX(thermal_list_lock);
>   static DEFINE_MUTEX(sensor_list_lock);
>   static DEFINE_MUTEX(zone_list_lock);
> +static DEFINE_MUTEX(cdev_list_lock);
>   static DEFINE_MUTEX(thermal_governor_lock);
>
>   #define for_each_thermal_sensor(pos) \
> @@ -83,6 +84,9 @@ static DEFINE_MUTEX(thermal_governor_lock);
>   	ret;						\
>   })
>
> +#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;
> @@ -466,6 +470,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 j, indx;
> +
> +	indx = GET_INDEX(tz, cdev, 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) \
> @@ -1462,6 +1484,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)
> @@ -1499,6 +1522,13 @@ void thermal_cooling_device_unregister(struct thermal_cooling_device *cdev)
>
>   	mutex_unlock(&thermal_list_lock);
>
> +	mutex_lock(&zone_list_lock);
> +
> +	for_each_thermal_zone(tmp_tz)
> +		remove_cdev_from_zone(tmp_tz, cdev);
> +
> +	mutex_unlock(&zone_list_lock);
> +
>   	if (cdev->type[0])
>   		device_remove_file(&cdev->device, &dev_attr_cdev_type);
>   	device_remove_file(&cdev->device, &dev_attr_max_state);
> @@ -1794,6 +1824,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;
> @@ -1844,6 +1891,39 @@ exit_zone:
>   }
>   EXPORT_SYMBOL(add_sensor_to_zone);
>
> +int add_cdev_to_zone(struct thermal_zone *tz,
> +			struct thermal_cooling_device *cdev)
> +{
> +	int ret;
> +
> +	if (!tz || !cdev)
> +		return -EINVAL;
> +
> +	mutex_lock(&zone_list_lock);
> +
> +	/* Ensure we are not adding the same cdev again!! */
> +	ret = GET_INDEX(tz, cdev, 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(&zone_list_lock);
> +	return ret;
> +}
> +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 2194519..c841414 100644
> --- a/include/linux/thermal.h
> +++ b/include/linux/thermal.h
> @@ -57,6 +57,8 @@
>
>   #define MAX_SENSORS_PER_ZONE		5
>
> +#define MAX_CDEVS_PER_ZONE		5
> +
>   struct thermal_sensor;
>   struct thermal_zone_device;
>   struct thermal_cooling_device;
> @@ -217,6 +219,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 */
> @@ -296,6 +302,9 @@ void remove_thermal_zone(struct thermal_zone *);
>   int add_sensor_to_zone(struct thermal_zone *, struct thermal_sensor *);
>   struct thermal_sensor *get_sensor_by_name(const char *);
>
> +int add_cdev_to_zone(struct thermal_zone *, struct thermal_cooling_device *);
> +struct thermal_cooling_device *get_cdev_by_name(const char *);
> +
>   #ifdef CONFIG_NET
>   extern int thermal_generate_netlink_event(struct thermal_zone_device *tz,
>   						enum events event);
>


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

* Re: [PATCH 4/8] Thermal: Add trip point sysfs nodes for sensor
  2013-02-05 10:46 ` [PATCH 4/8] Thermal: Add trip point sysfs nodes for sensor Durgadoss R
  2013-02-08  8:50   ` Zhang Rui
@ 2013-02-28 19:51   ` Eduardo Valentin
  2013-03-01 15:34     ` R, Durgadoss
  1 sibling, 1 reply; 39+ messages in thread
From: Eduardo Valentin @ 2013-02-28 19:51 UTC (permalink / raw)
  To: Durgadoss R; +Cc: rui.zhang, linux-pm, linux-kernel, hongbo.zhang, wni

Durga,


Same comments on patch 02/08 I want to rise here:
- Minors on strlcpy, snprintf, devm_ helpers
- documentation in the code for these helper functions and also better 
naming..


On 05-02-2013 06:46, Durgadoss R wrote:
> This patch adds a trip point related sysfs nodes
> for each sensor under a zone in /sys/class/thermal/zoneX/.
> The nodes will be named, sensorX_trip_active,
> sensorX_trip_passive, sensorX_trip_hot, sensorX_trip_critical
> for active, passive, hot and critical trip points
> respectively for sensorX.
>
> Signed-off-by: Durgadoss R <durgadoss.r@intel.com>
> ---
>   drivers/thermal/thermal_sys.c |  225 ++++++++++++++++++++++++++++++++++++++++-
>   include/linux/thermal.h       |   38 ++++++-
>   2 files changed, 260 insertions(+), 3 deletions(-)
>
> diff --git a/drivers/thermal/thermal_sys.c b/drivers/thermal/thermal_sys.c
> index bf703b1..69a60a4 100644
> --- a/drivers/thermal/thermal_sys.c
> +++ b/drivers/thermal/thermal_sys.c
> @@ -452,6 +452,37 @@ static void thermal_zone_device_check(struct work_struct *work)
>   	thermal_zone_device_update(tz);
>   }
>
> +static int get_sensor_indx_by_kobj(struct thermal_zone *tz, const char *name)
> +{
> +	int i, indx = -EINVAL;
> +
> +	mutex_lock(&sensor_list_lock);
> +	for (i = 0; i < tz->sensor_indx; i++) {
> +		if (!strnicmp(name, kobject_name(&tz->sensors[i]->device.kobj),
> +					THERMAL_NAME_LENGTH)) {
> +			indx = i;
> +			break;
> +		}
> +	}
> +	mutex_unlock(&sensor_list_lock);
> +	return indx;
> +}
> +
> +static void inline __remove_trip_attr(struct thermal_zone *tz, int indx)
I believe the preferred format would be:

static inline void __remove_trip_attr(struct thermal_zone *tz, int indx)

> +{
> +	int i;
> +	struct thermal_trip_attr *attr = tz->trip_attr[indx];
> +
> +	if (!attr)
> +		return;
> +
> +	for (i = 0; i < NUM_TRIP_TYPES; i++)
> +		device_remove_file(&tz->device, &attr->attrs[i].attr);
> +
> +	kfree(tz->trip_attr[indx]);
> +	tz->trip_attr[indx] = NULL;
> +}
> +
>   static void remove_sensor_from_zone(struct thermal_zone *tz,
>   				struct thermal_sensor *ts)
>   {
> @@ -463,9 +494,15 @@ static void remove_sensor_from_zone(struct thermal_zone *tz,
>
>   	sysfs_remove_link(&tz->device.kobj, kobject_name(&ts->device.kobj));
>
> +	/* Remove trip point attributes associated with this sensor */
> +	__remove_trip_attr(tz, 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->sensor_trip[j] = tz->sensor_trip[j + 1];
> +		tz->trip_attr[j] = tz->trip_attr[j + 1];
> +	}
>
>   	tz->sensor_indx--;
>   }
> @@ -879,6 +916,99 @@ 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 device *dev, struct device_attribute *attr, char *buf)
> +{
> +	int i, indx, ret = 0;
> +	char kobj_name[THERMAL_NAME_LENGTH];
> +	struct thermal_zone *tz = to_zone(dev);
> +
> +	if (!sscanf(attr->attr.name, "sensor%d_trip_active", &i))
> +		return -EINVAL;
> +
> +	snprintf(kobj_name, THERMAL_NAME_LENGTH, "sensor%d", i);
> +	indx = get_sensor_indx_by_kobj(tz, kobj_name);
> +	if (indx < 0)
> +		return indx;
> +
> +	if (tz->sensor_trip[indx]->num_active_trips <= 0)
> +		return sprintf(buf, "<Not available>\n");
> +
> +	ret += sprintf(buf, "0x%x", tz->sensor_trip[indx]->active_trip_mask);
> +	for (i = 0; i < tz->sensor_trip[indx]->num_active_trips; i++) {
> +		ret += sprintf(buf + ret, " %d",
> +			tz->sensor_trip[indx]->active_trips[i]);
> +	}
> +
> +	ret += sprintf(buf + ret, "\n");
> +	return ret;
> +}
> +

I believe the above function violates sysfs rules, no? Each and every 
file must contain only 1 value..

> +static ssize_t
> +ptrip_show(struct device *dev, struct device_attribute *attr, char *buf)
> +{
> +	int i, indx, ret = 0;
> +	char kobj_name[THERMAL_NAME_LENGTH];
> +	struct thermal_zone *tz = to_zone(dev);
> +
> +	if (!sscanf(attr->attr.name, "sensor%d_trip_passive", &i))
> +		return -EINVAL;
> +
> +	snprintf(kobj_name, THERMAL_NAME_LENGTH, "sensor%d", i);
> +	indx = get_sensor_indx_by_kobj(tz, kobj_name);
> +	if (indx < 0)
> +		return indx;
> +
> +	if (tz->sensor_trip[indx]->num_passive_trips <= 0)
> +		return sprintf(buf, "<Not available>\n");
> +
> +	for (i = 0; i < tz->sensor_trip[indx]->num_passive_trips; i++) {
> +		ret += sprintf(buf + ret, "%d ",
> +			tz->sensor_trip[indx]->passive_trips[i]);
> +	}
> +
> +	ret += sprintf(buf + ret, "\n");
> +	return ret;
> +}


ditto.

> +
> +static ssize_t
> +hot_show(struct device *dev, struct device_attribute *attr, char *buf)
> +{
> +	int indx;
> +	char kobj_name[THERMAL_NAME_LENGTH];
> +	struct thermal_zone *tz = to_zone(dev);
> +
> +	if (!sscanf(attr->attr.name, "sensor%d_trip_hot", &indx))
> +		return -EINVAL;
> +
> +	snprintf(kobj_name, THERMAL_NAME_LENGTH, "sensor%d", indx);
> +
> +	indx = get_sensor_indx_by_kobj(tz, kobj_name);
> +	if (indx < 0)
> +		return indx;
> +
> +	return sprintf(buf, "%d\n", tz->sensor_trip[indx]->hot);
> +}
> +
> +static ssize_t
> +critical_show(struct device *dev, struct device_attribute *attr, char *buf)
> +{
> +	int indx;
> +	char kobj_name[THERMAL_NAME_LENGTH];
> +	struct thermal_zone *tz = to_zone(dev);
> +
> +	if (!sscanf(attr->attr.name, "sensor%d_trip_critical", &indx))
> +		return -EINVAL;
> +
> +	snprintf(kobj_name, THERMAL_NAME_LENGTH, "sensor%d", indx);
> +
> +	indx = get_sensor_indx_by_kobj(tz, kobj_name);
> +	if (indx < 0)
> +		return indx;
> +
> +	return sprintf(buf, "%d\n", tz->sensor_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);
> @@ -889,7 +1019,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);
> +/* Thermal zone attributes */
> +static DEVICE_ATTR(zone_name, S_IRUGO, zone_name_show, NULL);
>
>   /* sys I/F for cooling device */
>   #define to_cooling_device(_dev)	\
> @@ -1744,6 +1875,38 @@ static int enable_sensor_thresholds(struct thermal_sensor *ts, int count)
>   	return 0;
>   }
>
> +static int create_sensor_trip_attrs(struct thermal_zone *tz,
> +				struct thermal_trip_attr *attr, int indx)
> +{
> +	int i, ret;
> +	static const char *const names[NUM_TRIP_TYPES] = {
> +				"sensor%d_trip_active",
> +				"sensor%d_trip_passive",
> +				"sensor%d_trip_hot",
> +				"sensor%d_trip_critical",
> +				};
> +	static ssize_t (*const rd_ptr[NUM_TRIP_TYPES]) (struct device *dev,
> +			struct device_attribute *devattr, char *buf) = {
> +			active_show, ptrip_show, hot_show, critical_show};
> +
> +	for (i = 0; i < NUM_TRIP_TYPES; i++) {
> +		snprintf(attr->attrs[i].name, THERMAL_NAME_LENGTH, names[i],
> +			indx);
> +		sysfs_attr_init(&attr->attrs[i].attr.attr);
> +		attr->attrs[i].attr.attr.name = attr->attrs[i].name;
> +		attr->attrs[i].attr.attr.mode = S_IRUGO;
> +		attr->attrs[i].attr.show = rd_ptr[i];
> +		ret = device_create_file(&tz->device, &attr->attrs[i].attr);
> +		if (ret)
> +			goto exit;
> +	}
> +	return 0;
> +exit:
> +	while (--i >= 0)
> +		device_remove_file(&tz->device, &attr->attrs[i].attr);
> +	return ret;
> +}
> +
>   struct thermal_zone *create_thermal_zone(const char *name, void *devdata)
>   {
>   	struct thermal_zone *tz;
> @@ -1793,6 +1956,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)
> @@ -1813,6 +1977,23 @@ 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) {
> +		/* Remove /sys/class/thermal/zoneX/sensorY */
> +		sysfs_remove_link(&tz->device.kobj,
> +				kobject_name(&tz->sensors[i]->device.kobj));
> +		__remove_trip_attr(tz, i);
> +	}
> +
> +	/* Release the cdevs attached to this zone */
> +	i = tz->cdev_indx;
> +	while (--i >= 0) {
> +		/* Remove /sys/class/thermal/zoneX/cooling_deviceY */
> +		sysfs_remove_link(&tz->device.kobj,
> +				kobject_name(&tz->cdevs[i]->device.kobj));
> +	}
> +
>   	release_idr(&thermal_zone_idr, &thermal_idr_lock, tz->id);
>   	idr_destroy(&tz->idr);
>
> @@ -1924,6 +2105,46 @@ exit_zone:
>   }
>   EXPORT_SYMBOL(add_cdev_to_zone);
>
> +int add_sensor_trip_info(struct thermal_zone *tz, struct thermal_sensor *ts,
> +			struct thermal_trip_point *trip)
> +{
> +	int ret, indx, kobj_indx;
> +
> +	if (!tz || !ts || !trip)
> +		return -EINVAL;
> +
> +	if (!sscanf(kobject_name(&ts->device.kobj), "sensor%d", &kobj_indx))
> +		return -EINVAL;
> +
> +	mutex_lock(&zone_list_lock);
> +
> +	indx = GET_INDEX(tz, ts, sensor);
> +	if (indx < 0) {
> +		ret = -EINVAL;
> +		goto exit;
> +	}
> +
> +	tz->trip_attr[indx] = kzalloc(sizeof(struct thermal_trip_attr),
> +					GFP_KERNEL);
> +	if (!tz->trip_attr[indx]) {
> +		ret = -ENOMEM;
> +		goto exit;
> +	}
> +
> +	ret = create_sensor_trip_attrs(tz, tz->trip_attr[indx], kobj_indx);
> +	if (ret) {
> +		kfree(tz->trip_attr[indx]);
> +		goto exit;
> +	}
> +
> +	tz->sensor_trip[indx] = trip;
> +
> +exit:
> +	mutex_unlock(&zone_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 c841414..2f68018 100644
> --- a/include/linux/thermal.h
> +++ b/include/linux/thermal.h
> @@ -31,7 +31,8 @@
>
>   #define THERMAL_TRIPS_NONE	-1
>   #define THERMAL_MAX_TRIPS	12
> -#define THERMAL_NAME_LENGTH	20
> +#define THERMAL_NAME_LENGTH	22
> +#define NUM_TRIP_TYPES		4
>
>   /* No upper/lower limit requirement */
>   #define THERMAL_NO_LIMIT	-1UL
> @@ -166,6 +167,34 @@ 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_trip_attr {
> +	struct thermal_attr attrs[NUM_TRIP_TYPES];
> +};
> +
>   struct thermal_sensor {
>   	char name[THERMAL_NAME_LENGTH];
>   	int id;
> @@ -223,6 +252,10 @@ struct thermal_zone {
>   	/* cdev level information */
>   	int cdev_indx; /* index into 'cdevs' array */
>   	struct thermal_cooling_device *cdevs[MAX_CDEVS_PER_ZONE];
> +
> +	/* Thermal sensors trip information */
> +	struct thermal_trip_point *sensor_trip[MAX_SENSORS_PER_ZONE];
> +	struct thermal_trip_attr *trip_attr[MAX_SENSORS_PER_ZONE];
>   };
>
>   /* Structure that holds thermal governor information */
> @@ -305,6 +338,9 @@ struct thermal_sensor *get_sensor_by_name(const char *);
>   int add_cdev_to_zone(struct thermal_zone *, struct thermal_cooling_device *);
>   struct thermal_cooling_device *get_cdev_by_name(const char *);
>
> +int add_sensor_trip_info(struct thermal_zone *, struct thermal_sensor *,
> +			struct thermal_trip_point *);
> +
>   #ifdef CONFIG_NET
>   extern int thermal_generate_netlink_event(struct thermal_zone_device *tz,
>   						enum events event);
>


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

* Re: [PATCH 5/8] Thermal: Create Thermal map sysfs attributes for a zone
  2013-02-05 10:46 ` [PATCH 5/8] Thermal: Create Thermal map sysfs attributes for a zone Durgadoss R
  2013-02-08  9:04   ` Zhang Rui
@ 2013-02-28 21:30   ` Eduardo Valentin
  1 sibling, 0 replies; 39+ messages in thread
From: Eduardo Valentin @ 2013-02-28 21:30 UTC (permalink / raw)
  To: Durgadoss R; +Cc: rui.zhang, linux-pm, linux-kernel, hongbo.zhang, wni

Durga,


On 05-02-2013 06:46, Durgadoss R wrote:
> This patch creates a thermal map sysfs node under
> /sys/class/thermal/zoneX/. This contains
> entries named mapY_trip_type, mapY_sensor_name,
> mapY_cdev_name, mapY_trip_mask, mapY_weights.


Some of the previous comments apply here as well, specially wrt to 
devm_, snprintf and strlcpy. Also the documentation for the exported 
functions are welcome.

>
> Signed-off-by: Durgadoss R <durgadoss.r@intel.com>
> ---
>   drivers/thermal/thermal_sys.c |  221 ++++++++++++++++++++++++++++++++++++++++-
>   include/linux/thermal.h       |   25 +++++
>   2 files changed, 244 insertions(+), 2 deletions(-)
>
> diff --git a/drivers/thermal/thermal_sys.c b/drivers/thermal/thermal_sys.c
> index 69a60a4..e284b67 100644
> --- a/drivers/thermal/thermal_sys.c
> +++ b/drivers/thermal/thermal_sys.c
> @@ -525,6 +525,44 @@ static void remove_cdev_from_zone(struct thermal_zone *tz,
>   	tz->cdev_indx--;
>   }
>
> +static inline void __remove_map_entry(struct thermal_zone *tz, int indx)
> +{
> +	int i;
> +	struct thermal_map_attr *attr = tz->map_attr[indx];
> +
> +	for (i = 0; i < NUM_MAP_ATTRS; i++)
> +		device_remove_file(&tz->device, &attr->attrs[i].attr);
> +
> +	kfree(tz->map_attr[indx]);
> +	tz->map[indx] = 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)) {
> +			__remove_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)) {
> +			__remove_map_entry(tz, i);
> +		}
> +	}
> +}
> +
>   /* sys I/F for thermal zone */
>
>   #define to_thermal_zone(_dev) \
> @@ -917,6 +955,107 @@ policy_show(struct device *dev, struct device_attribute *devattr, char *buf)
>   }
>
>   static ssize_t
> +map_ttype_show(struct device *dev, struct device_attribute *attr, char *buf)
> +{
> +	char *trip;
> +	int indx;
> +	struct thermal_zone *tz = to_zone(dev);
> +
> +	if (!sscanf(attr->attr.name, "map%d_trip_type", &indx))
> +		return -EINVAL;
> +
> +	if (indx < 0 || indx >= MAX_MAPS_PER_ZONE)
> +		return -EINVAL;
> +
> +	if (!tz->map[indx])
> +		return sprintf(buf, "<Unavailable>\n");

Is this condition possible? If yes, we probably need to change the code 
so that if the map is not present, the sysfs files are also removed.

> +
> +	trip = (tz->map[indx]->trip_type == THERMAL_TRIP_ACTIVE) ?
> +						"active" : "passive";
> +	return sprintf(buf, "%s\n", trip);
> +}
> +
> +static ssize_t map_ts_name_show(struct device *dev,
> +				struct device_attribute *attr, char *buf)
> +{
> +	int indx;
> +	struct thermal_zone *tz = to_zone(dev);
> +
> +	if (!sscanf(attr->attr.name, "map%d_sensor_name", &indx))
> +		return -EINVAL;
> +
> +	if (indx < 0 || indx >= MAX_MAPS_PER_ZONE)
> +		return -EINVAL;
> +
> +	if (!tz->map[indx])
> +		return sprintf(buf, "<Unavailable>\n");

ditto

> +
> +	return sprintf(buf, "%s\n", tz->map[indx]->sensor_name);
> +}
> +
> +static ssize_t map_cdev_name_show(struct device *dev,
> +				struct device_attribute *attr, char *buf)
> +{
> +	int indx;
> +	struct thermal_zone *tz = to_zone(dev);
> +
> +	if (!sscanf(attr->attr.name, "map%d_cdev_name", &indx))
> +		return -EINVAL;
> +
> +	if (indx < 0 || indx >= MAX_MAPS_PER_ZONE)
> +		return -EINVAL;
> +
> +	if (!tz->map[indx])
> +		return sprintf(buf, "<Unavailable>\n");

ditto

> +
> +	return sprintf(buf, "%s\n", tz->map[indx]->cdev_name);
> +}
> +
> +static ssize_t map_trip_mask_show(struct device *dev,
> +				struct device_attribute *attr, char *buf)
> +{
> +	int indx;
> +	struct thermal_zone *tz = to_zone(dev);
> +
> +	if (!sscanf(attr->attr.name, "map%d_trip_mask", &indx))
> +		return -EINVAL;
> +
> +	if (indx < 0 || indx >= MAX_MAPS_PER_ZONE)
> +		return -EINVAL;
> +
> +	if (!tz->map[indx])
> +		return sprintf(buf, "<Unavailable>\n");

ditto

> +
> +	return sprintf(buf, "0x%x\n", tz->map[indx]->trip_mask);
> +}
> +
> +static ssize_t map_weights_show(struct device *dev,
> +				struct device_attribute *attr, char *buf)
> +{
> +	int i, indx, ret = 0;
> +	struct thermal_map *map;
> +	struct thermal_zone *tz = to_zone(dev);
> +
> +	if (!sscanf(attr->attr.name, "map%d_weights", &indx))
> +		return -EINVAL;
> +
> +	if (indx < 0 || indx >= MAX_MAPS_PER_ZONE)
> +		return -EINVAL;
> +
> +	if (!tz->map[indx])
> +		return sprintf(buf, "<Unavailable>\n");
> +

ditto

> +	map = tz->map[indx];
> +
> +	ret += sprintf(buf, "%d", map->weights[0]);
> +	for (i = 1; i < map->num_weights; i++)
> +		ret += sprintf(buf + ret, " %d", map->weights[i]);
> +
> +	ret += sprintf(buf + ret, "\n");
> +	return ret;

this function violates sysfs rules.

> +}
> +
> +static ssize_t
>   active_show(struct device *dev, struct device_attribute *attr, char *buf)
>   {
>   	int i, indx, ret = 0;
> @@ -1655,8 +1794,10 @@ void thermal_cooling_device_unregister(struct thermal_cooling_device *cdev)
>
>   	mutex_lock(&zone_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(&zone_list_lock);
>
> @@ -1994,6 +2135,9 @@ void remove_thermal_zone(struct thermal_zone *tz)
>   				kobject_name(&tz->cdevs[i]->device.kobj));
>   	}
>
> +	for (i = 0; i < MAX_MAPS_PER_ZONE; i++)
> +		__remove_map_entry(tz, i);
> +
>   	release_idr(&thermal_zone_idr, &thermal_idr_lock, tz->id);
>   	idr_destroy(&tz->idr);
>
> @@ -2039,6 +2183,77 @@ struct thermal_sensor *get_sensor_by_name(const char *name)
>   }
>   EXPORT_SYMBOL(get_sensor_by_name);
>
> +static int create_map_attrs(struct thermal_zone *tz, int indx)
> +{
> +	int ret, i;
> +	struct thermal_map_attr *attr = tz->map_attr[indx];
> +
> +	static const char *const names[NUM_MAP_ATTRS] = { "map%d_trip_type",
> +			"map%d_sensor_name", "map%d_cdev_name",
> +			"map%d_trip_mask", "map%d_weights" };
> +	static ssize_t (*const rd_ptr[NUM_MAP_ATTRS]) (struct device *dev,
> +			struct device_attribute *devattr, char *buf) = {
> +			map_ttype_show, map_ts_name_show, map_cdev_name_show,
> +			map_trip_mask_show, map_weights_show };
> +
> +	for (i = 0; i < NUM_MAP_ATTRS; i++) {
> +		snprintf(attr->attrs[i].name,
> +			THERMAL_NAME_LENGTH, names[i], indx);
> +		attr->attrs[i].attr.attr.name = attr->attrs[i].name;
> +		attr->attrs[i].attr.attr.mode = S_IRUGO;
> +		attr->attrs[i].attr.show = rd_ptr[i];
> +		sysfs_attr_init(&attr->attrs[i].attr);
> +
> +		ret = device_create_file(&tz->device, &attr->attrs[i].attr);
> +		if (ret)
> +			goto exit_free;
> +	}
> +	return 0;
> +exit_free:
> +	while (--i >= 0)
> +		device_remove_file(&tz->device, &attr->attrs[i].attr);
> +	return ret;
> +}
> +
> +int add_map_entry(struct thermal_zone *tz, struct thermal_map *map)
> +{
> +	int ret, indx;
> +
> +	if (!tz || !map)
> +		return -EINVAL;
> +
> +	mutex_lock(&zone_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;
> +	}
> +
> +	ret = create_map_attrs(tz, indx);
> +	if (ret) {
> +		kfree(tz->map_attr[indx]);
> +		goto exit;
> +	}
> +
> +	tz->map[indx] = map;

userland must be aware that a file named:
/sys/class/thermal/zoneX/mapY_trip_type not aways refer to the same map. 
This is because one may add a map, it will create say:
/sys/class/thermal/zoneX/map0_trip_type

then for some odd reason that map gets removed. And for some other odd 
reason, one decides to add yet another map. It will reuse the number. 
But it is not the same map!

This must be well documented, otherwise things may get confusing.

I'd suggest using a unique id..

> +exit:
> +	mutex_unlock(&zone_list_lock);
> +	return ret;
> +}
> +EXPORT_SYMBOL(add_map_entry);
> +
>   int add_sensor_to_zone(struct thermal_zone *tz, struct thermal_sensor *ts)
>   {
>   	int ret;
> @@ -2243,8 +2458,10 @@ void thermal_sensor_unregister(struct thermal_sensor *ts)
>
>   	mutex_lock(&zone_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(&zone_list_lock);
>
> diff --git a/include/linux/thermal.h b/include/linux/thermal.h
> index 2f68018..4389599 100644
> --- a/include/linux/thermal.h
> +++ b/include/linux/thermal.h
> @@ -60,6 +60,11 @@
>
>   #define MAX_CDEVS_PER_ZONE		5
>
> +#define NUM_MAP_ATTRS			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;
> @@ -167,6 +172,20 @@ struct thermal_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;
> +};
> +
> +struct thermal_map_attr {
> +	struct thermal_attr attrs[NUM_MAP_ATTRS];
> +};
> +
>   /*
>    * This structure defines the trip points for a sensor.
>    * The actual values for these trip points come from
> @@ -256,6 +275,10 @@ struct thermal_zone {
>   	/* Thermal sensors trip information */
>   	struct thermal_trip_point *sensor_trip[MAX_SENSORS_PER_ZONE];
>   	struct thermal_trip_attr *trip_attr[MAX_SENSORS_PER_ZONE];
> +
> +	/* Thermal map information */
> +	struct thermal_map *map[MAX_MAPS_PER_ZONE];
> +	struct thermal_map_attr *map_attr[MAX_MAPS_PER_ZONE];
>   };
>
>   /* Structure that holds thermal governor information */
> @@ -341,6 +364,8 @@ struct thermal_cooling_device *get_cdev_by_name(const char *);
>   int add_sensor_trip_info(struct thermal_zone *, struct thermal_sensor *,
>   			struct thermal_trip_point *);
>
> +int add_map_entry(struct thermal_zone *, struct thermal_map *);
> +
>   #ifdef CONFIG_NET
>   extern int thermal_generate_netlink_event(struct thermal_zone_device *tz,
>   						enum events event);
>


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

* Re: [PATCHv3 0/8] Thermal Framework Enhancements
  2013-02-05 10:46 [PATCHv3 0/8] Thermal Framework Enhancements Durgadoss R
                   ` (9 preceding siblings ...)
  2013-02-08  9:35 ` Zhang Rui
@ 2013-02-28 21:33 ` Eduardo Valentin
  2013-03-01  5:12   ` R, Durgadoss
  2013-08-29 19:38 ` Eduardo Valentin
  11 siblings, 1 reply; 39+ messages in thread
From: Eduardo Valentin @ 2013-02-28 21:33 UTC (permalink / raw)
  To: Durgadoss R; +Cc: rui.zhang, linux-pm, linux-kernel, hongbo.zhang, wni


Durga,



On 05-02-2013 06:46, Durgadoss R wrote:
> This patch set is a v3 of the previous versions submitted here:
> [v2]: http://lwn.net/Articles/531720/
> [v1]: https://lkml.org/lkml/2012/12/18/108
> [RFC]:https://patchwork.kernel.org/patch/1758921/

On this version I have some implementation details which applies mostly 
for the series. So, I am replying to patch 0 to summarize:

- Consider using linked list
- You may have contention on your indexes and arrays
- overflow on your buffer (carefully check your implementation)
- zone removal condition. can we remove zones with sensors/cdevs/maps 
registered?
- Minors on strlcpy, snprintf, devm_ helpers
- documentation in the code for these helper functions and also better 
naming..


>
> This patch set is based on Rui's -next tree, and is
> tested on a Core-i5 and an Atom netbook.
>
> Changes since v2:
>   * Reworked the map sysfs attributes in patch [5/8]
>   * Dropped configuration for maximum sensors and
>     cooling devices, through Kconfig.
>   * Added __remove_trip_attr method
>   * Renamed __clean_map_entry to __remove_map_entry
>     for consistency in naming.
> Changes Since v1:
>   * Removed kobject creation for thermal_trip and thermal_map
>     nodes as per Greg-KH's comments.
>   * Added ABI Documentation under 'testing'.
>   * Modified the GET_INDEX macro to be more linux-like, thanks
>     to Joe Perches.
>   * Added get_[sensor/cdev]_by_name APIs to thermal.h
>
> This series contains 8 patches:
> Patch 1/8: Creates new sensor level APIs
> Patch 2/8: Creates new zone level APIs. The existing tzd structure is
>             kept as such for clarity and compatibility purposes.
> Patch 3/8: Creates functions to add/remove a cdev to/from a zone. The
>             existing tcd structure need not be modified.
> Patch 4/8: Adds sensorX_trip_[active/passive/hot/critical] sysfs nodes,
> 	   under /sys/class/thermal/zoneY/. This exposes various trip
>             points for sensorX present in zoneY.
> Patch 5/8: Adds mapY_* sysfs node. These attributes represent
>             the binding relationship between a sensor and a cdev,
>             within a zone.
> Patch 6/8: 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/8: Add ABI documentation for sysfs interfaces introduced in this patch.
> Patch 8/8: A dummy driver that can be used for testing. This is not for merge.
>
> Durgadoss R (8):
>    Thermal: Create sensor level APIs
>    Thermal: Create zone level APIs
>    Thermal: Add APIs to bind cdev to new zone structure
>    Thermal: Add trip point sysfs nodes for sensor
>    Thermal: Create Thermal map sysfs attributes for a zone
>    Thermal: Add Documentation to new APIs
>    Thermal: Add ABI Documentation for sysfs interfaces
>    Thermal: Dummy driver used for testing
>
>   Documentation/ABI/testing/sysfs-class-thermal |  137 ++++
>   Documentation/thermal/sysfs-api2.txt          |  247 ++++++
>   drivers/thermal/Kconfig                       |    5 +
>   drivers/thermal/Makefile                      |    2 +
>   drivers/thermal/thermal_sys.c                 |  994 +++++++++++++++++++++++++
>   drivers/thermal/thermal_test.c                |  324 ++++++++
>   include/linux/thermal.h                       |  123 ++-
>   7 files changed, 1831 insertions(+), 1 deletion(-)
>   create mode 100644 Documentation/ABI/testing/sysfs-class-thermal
>   create mode 100644 Documentation/thermal/sysfs-api2.txt
>   create mode 100644 drivers/thermal/thermal_test.c
>


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

* RE: [PATCH 1/8] Thermal: Create sensor level APIs
  2013-02-28 18:58   ` Eduardo Valentin
@ 2013-03-01  5:08     ` R, Durgadoss
  0 siblings, 0 replies; 39+ messages in thread
From: R, Durgadoss @ 2013-03-01  5:08 UTC (permalink / raw)
  To: Eduardo Valentin; +Cc: Zhang, Rui, linux-pm, linux-kernel, hongbo.zhang, wni

Hi Eduardo,

> -----Original Message-----
> From: Eduardo Valentin [mailto:eduardo.valentin@ti.com]
> Sent: Friday, March 01, 2013 12:29 AM
> To: R, Durgadoss
> Cc: Zhang, Rui; linux-pm@vger.kernel.org; linux-kernel@vger.kernel.org;
> hongbo.zhang@linaro.org; wni@nvidia.com
> Subject: Re: [PATCH 1/8] Thermal: Create sensor level APIs
> 
> Durga,
> 
> On 05-02-2013 06:46, Durgadoss R wrote:
> > This patch creates sensor level APIs, in the
> > generic thermal framework.
> >
> > A Thermal sensor is a piece of hardware that can report
> > temperature of the spot in which it is placed. A thermal
> > sensor driver reads the temperature from this sensor
> > and reports it out. This kind of driver can be in
> > any subsystem. If the sensor needs to participate
> > in platform thermal management, the corresponding
> > driver can use the APIs introduced in this patch, to
> > register(or unregister) with the thermal framework.
> 
> At first glance, patch seams reasonable. But I have one major concern as
> follows inline, apart from several minor comments.
> 
> >
> > Signed-off-by: Durgadoss R <durgadoss.r@intel.com>
> > ---
> >   drivers/thermal/thermal_sys.c |  280
> +++++++++++++++++++++++++++++++++++++++++
> >   include/linux/thermal.h       |   29 +++++
> >   2 files changed, 309 insertions(+)
> >
> > diff --git a/drivers/thermal/thermal_sys.c b/drivers/thermal/thermal_sys.c
> > index 0a1bf6b..cb94497 100644
> > --- a/drivers/thermal/thermal_sys.c
> > +++ b/drivers/thermal/thermal_sys.c
> > @@ -44,13 +44,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(sensor_list_lock);
> >   static DEFINE_MUTEX(thermal_governor_lock);
> >
> >   static struct thermal_governor *__find_governor(const char *name)
> > @@ -423,6 +426,103 @@ 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);
> 
> For security reasons:
> s/sprintf/snprintf
> 
> > +}
> > +
> > +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);
> 
> ditto.
> 
> > +}
> > +
> > +static ssize_t
> > +hyst_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_hyst", &indx))
> 
> I'd rather check if it returns 1.
> 
> > +		return -EINVAL;
> > +
> > +	ret = ts->ops->get_hyst(ts, indx, &val);
> 
>  From your probe, you won't check for devices registered with
> ops.get_hyst == NULL. This may lead to a NULL pointer access above.

if ops.get_hyst is NULL, we don't even create these sysfs interfaces.
This check is in enable_sensor_thresholds function.

> 
> > +
> > +	return ret ? ret : sprintf(buf, "%ld\n", val);
> 
> snprintf.
> 
> > +}
> > +
> > +static ssize_t
> > +hyst_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_hyst)
> > +		return -EPERM;
> > +
> > +	if (!sscanf(attr->attr.name, "threshold%d_hyst", &indx))
> > +		return -EINVAL;
> > +
> > +	if (kstrtol(buf, 10, &val))
> > +		return -EINVAL;
> > +
> > +	ret = ts->ops->set_hyst(ts, indx, val);
> 
>  From your probe, you won't check for devices registered with
> ops.set_hyst == NULL. This may lead to a NULL pointer access above.
> 
> > +
> > +	return ret ? ret : count;
> > +}
> > +
> > +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);
>  From your probe, you won't check for devices registered with
> ops.get_threshold == NULL. This may lead to a NULL pointer access above.

It checks for ops.get_threshold, but not for the setter method.
Will take of that in next version.

> 
> > +
> > +	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;
> > +}
> > +
> 
> One may be careful with the above functions. Userland having control on
> these properties may lead to spurious events, depending on the
> programming sequence / value changing order. I believe, it would be
> wiser to disable the interrupt generation prior to changing the thresholds.

Valid case. We call set_threshold from the framework layer, and leave it to the
sensor driver to take care of rest of the things.

> 
> >   static ssize_t
> >   type_show(struct device *dev, struct device_attribute *attr, char *buf)
> >   {
> > @@ -707,6 +807,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)
> > @@ -1493,6 +1597,182 @@ static void remove_trip_attrs(struct
> thermal_zone_device *tz)
> >   }
> >
> >   /**
> > + * enable_sensor_thresholds - create sysfs nodes for thresholdX
> > + * @ts:		the thermal sensor
> > + * @count:	Number of thresholds supported by sensor hardware
> > + *
> > + * 'Thresholds' are temperatures programmed into the sensor hardware,
> > + * on crossing which the sensor generates an interrupt. 'Trip points'
> > + * are temperatures which the thermal manager/governor thinks, some
> > + * action should be taken when the sensor reaches the value.
> > + */
> > +static int enable_sensor_thresholds(struct thermal_sensor *ts, int count)
> > +{
> > +	int i;
> > +	int size = sizeof(struct thermal_attr) * count;
> > +
> > +	ts->thresh_attrs = kzalloc(size, GFP_KERNEL);
> 
> how about using devm_ helpers?

Yes, I will use.

> 
> > +	if (!ts->thresh_attrs)
> > +		return -ENOMEM;
> > +
> > +	if (ts->ops->get_hyst) {
> > +		ts->hyst_attrs = kzalloc(size, GFP_KERNEL);
> > +		if (!ts->hyst_attrs) {
> > +			kfree(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;
> > +
> > +		device_create_file(&ts->device, &ts->thresh_attrs[i].attr);
> > +
> > +		/* Create threshold_hyst attributes */
> > +		if (!ts->ops->get_hyst)
> > +			continue;
> > +
> > +		snprintf(ts->hyst_attrs[i].name, THERMAL_NAME_LENGTH,
> > +						 "threshold%d_hyst", i);
> > +
> > +		sysfs_attr_init(&ts->hyst_attrs[i].attr.attr);
> > +		ts->hyst_attrs[i].attr.attr.name = ts->hyst_attrs[i].name;
> > +		ts->hyst_attrs[i].attr.attr.mode = S_IRUGO | S_IWUSR;
> > +		ts->hyst_attrs[i].attr.show = hyst_show;
> > +		ts->hyst_attrs[i].attr.store = hyst_store;
> > +
> > +		device_create_file(&ts->device, &ts->hyst_attrs[i].attr);
> > +	}
> > +	return 0;
> > +}
> > +
> 
> 
> I know there are people who is in favor of having the thermal policy
> controlled in userland.
> Depending on which thermal zone we are talking about, I'd even consider
> it a valid approach.

agreed.

> On the other hand there are thermal zones that controls silicon junction
> temperature which
> does not depend on any input from userland (like which kind of use case
> one may be running).
> 
> 
> That said, I believe we may want to segregate which sensors we want to
> expose the write access
> from userspace to their hyst and threshold values. Exposing all of them
> may lead to easy security leak.

If the sensor driver does not want this hysteresis to be writeable,
it can provide a NULL pointer in ops.set_hyst. 

Most of sprintf, strcpy I used them for consistency, as rest of the
framework code is already using these APIs.
We can do a separate clean up patch for these functions, IMHO.

That said, I also get hurt by static checkers on these :-)So, I agree with
you that these should be fixed, but not in this series.

Thanks,
Durga

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

* RE: [PATCHv3 0/8] Thermal Framework Enhancements
  2013-02-28 21:33 ` Eduardo Valentin
@ 2013-03-01  5:12   ` R, Durgadoss
  0 siblings, 0 replies; 39+ messages in thread
From: R, Durgadoss @ 2013-03-01  5:12 UTC (permalink / raw)
  To: Eduardo Valentin; +Cc: Zhang, Rui, linux-pm, linux-kernel, hongbo.zhang, wni

Hi Eduardo,

> -----Original Message-----
> From: Eduardo Valentin [mailto:eduardo.valentin@ti.com]
> Sent: Friday, March 01, 2013 3:04 AM
> To: R, Durgadoss
> Cc: Zhang, Rui; linux-pm@vger.kernel.org; linux-kernel@vger.kernel.org;
> hongbo.zhang@linaro.org; wni@nvidia.com
> Subject: Re: [PATCHv3 0/8] Thermal Framework Enhancements
> 
> 
> Durga,
> 
> 
> 
> On 05-02-2013 06:46, Durgadoss R wrote:
> > This patch set is a v3 of the previous versions submitted here:
> > [v2]: http://lwn.net/Articles/531720/
> > [v1]: https://lkml.org/lkml/2012/12/18/108
> > [RFC]:https://patchwork.kernel.org/patch/1758921/
> 
> On this version I have some implementation details which applies mostly
> for the series. So, I am replying to patch 0 to summarize:
> 
> - Consider using linked list

This I thought through on my RFC itself.
I know we have arrays, but using list adds too many members
to the structures, and protection becomes really cryptic.

> - You may have contention on your indexes and arrays
> - overflow on your buffer (carefully check your implementation)
> - zone removal condition. can we remove zones with sensors/cdevs/maps
> registered?
> - Minors on strlcpy, snprintf, devm_ helpers
> - documentation in the code for these helper functions and also better
> naming..

I will try to take care of these in my next version, as far as I can see.
But would really help if you can point the specific code that needs
improvement.

Thanks,
Durga

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

* RE: [PATCH 2/8] Thermal: Create zone level APIs
  2013-02-28 19:29   ` Eduardo Valentin
@ 2013-03-01 15:31     ` R, Durgadoss
  0 siblings, 0 replies; 39+ messages in thread
From: R, Durgadoss @ 2013-03-01 15:31 UTC (permalink / raw)
  To: Eduardo Valentin; +Cc: Zhang, Rui, linux-pm, linux-kernel, hongbo.zhang, wni

> -----Original Message-----
> From: linux-pm-owner@vger.kernel.org [mailto:linux-pm-
> owner@vger.kernel.org] On Behalf Of Eduardo Valentin
> Sent: Friday, March 01, 2013 1:00 AM
> To: R, Durgadoss
> Cc: Zhang, Rui; linux-pm@vger.kernel.org; linux-kernel@vger.kernel.org;
> hongbo.zhang@linaro.org; wni@nvidia.com
> Subject: Re: [PATCH 2/8] Thermal: Create zone level APIs
> 
> On 05-02-2013 06:46, Durgadoss R wrote:
> > This patch adds a new thermal_zone structure to
> > thermal.h. Also, adds zone level APIs to the thermal
> > framework.
> >
> > A thermal zone is a hot spot on the platform, which
> > can have one or more sensors and cooling devices attached
> > to it. These sensors can be mapped to a set of cooling
> > devices, which when throttled, can help to bring down
> > the temperature of the hot spot.
> >
> > Signed-off-by: Durgadoss R <durgadoss.r@intel.com>
> > ---
> >   drivers/thermal/thermal_sys.c |  196
> +++++++++++++++++++++++++++++++++++++++++
> >   include/linux/thermal.h       |   22 +++++
> >   2 files changed, 218 insertions(+)
> >
> > diff --git a/drivers/thermal/thermal_sys.c b/drivers/thermal/thermal_sys.c
> > index cb94497..838d4fb 100644
> > --- a/drivers/thermal/thermal_sys.c
> > +++ b/drivers/thermal/thermal_sys.c
> > @@ -43,19 +43,46 @@ 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(sensor_list_lock);
> > +static DEFINE_MUTEX(zone_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)
> > +
> > +#define GET_INDEX(tz, ptr, type)			\
> 
> Why do you need type? You seam to be using it only for sensors. It
> becomes a bit cryptic :-)

In the next patch, we use it for cooling devices also.

> 
> > +({							\
> > +	int i, ret = -EINVAL;				\
> > +	do {						\
> > +		if (!tz || !ptr)			\
> > +			break;				\
> > +		mutex_lock(&type##_list_lock);		\
> > +		for (i = 0; i < tz->type##_indx; i++) {	\
> > +			if (tz->type##s[i] == ptr) {	\
> > +				ret = i;		\
> > +				break;			\
> > +			}				\
> > +		}					\
> > +		mutex_unlock(&type##_list_lock);	\
> > +	} while (0);					\
> > +	ret;						\
> > +})
> > +
> >   static struct thermal_governor *__find_governor(const char *name)
> >   {
> >   	struct thermal_governor *pos;
> > @@ -421,15 +448,44 @@ static void thermal_zone_device_check(struct
> work_struct *work)
> >   	thermal_zone_device_update(tz);
> >   }
> >
> > +static void remove_sensor_from_zone(struct thermal_zone *tz,
> > +				struct thermal_sensor *ts)
> > +{
> > +	int j, indx;
> > +
> > +	indx = GET_INDEX(tz, ts, sensor);
> > +	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);
> snprintf
> 
> > +}
> > +
> > +static ssize_t
> >   sensor_name_show(struct device *dev, struct device_attribute *attr,
> char *buf)
> >   {
> >   	struct thermal_sensor *ts = to_thermal_sensor(dev);
> > @@ -811,6 +867,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)
> > @@ -1656,6 +1714,136 @@ static int enable_sensor_thresholds(struct
> thermal_sensor *ts, int count)
> >   	return 0;
> >   }
> >
> > +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);
> 
> devm_ helpers
> 
> > +	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);
> 
> strlcpy
> 
> > +	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(&zone_list_lock);
> > +	list_add_tail(&tz->node, &thermal_zone_list);
> > +	mutex_unlock(&zone_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(&zone_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(&zone_list_lock);
> > +	return;
> > +}
> > +EXPORT_SYMBOL(remove_thermal_zone);
> 
> Do we need to impose removal ordering here? Meaning, what happens if
> the
> above is called with sensors registered?

A zone only contains a symbolic link to a sensor. So, when this is called with
sensors registered, all the symbolic links will go away i.e /sys/../zone/sensorX
will go but /sys/../sensorX will remain as such.

> 
> > +
> > +struct thermal_sensor *get_sensor_by_name(const char *name)
> Why do you need this function? does not seam to be used anywhere in this
> patch. Besides it is unrelated to what this patch proposes itself to do.
> 
> > +{
> > +	struct thermal_sensor *pos;
> > +	struct thermal_sensor *ts = NULL;
> > +
> > +	mutex_lock(&sensor_list_lock);
> > +	for_each_thermal_sensor(pos) {
> > +		if (!strnicmp(pos->name, name, THERMAL_NAME_LENGTH))
> {
> > +			ts = pos;
> > +			break;
> > +		}
> > +	}
> > +	mutex_unlock(&sensor_list_lock);
> > +	return ts;
> > +}
> > +EXPORT_SYMBOL(get_sensor_by_name);
> > +
> > +int add_sensor_to_zone(struct thermal_zone *tz, struct thermal_sensor
> *ts)
> > +{
> > +	int ret;
> > +
> > +	if (!tz || !ts)
> > +		return -EINVAL;
> > +
> > +	mutex_lock(&zone_list_lock);
> > +
> > +	/* Ensure we are not adding the same sensor again!! */
> > +	ret = GET_INDEX(tz, ts, sensor);
> > +	if (ret >= 0) {
> > +		ret = -EEXIST;
> > +		goto exit_zone;
> > +	}
> > +
> > +	mutex_lock(&sensor_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;
> 
> you may overflow your sensors buffer with the above implementation.

Will add a check before the increment.

> 
> you may have a contention on sensors/sensor_indx.
> 
> Consider using linked lists.
> 
> > +
> > +exit_sensor:
> > +	mutex_unlock(&sensor_list_lock);
> > +exit_zone:
> > +	mutex_unlock(&zone_list_lock);
> > +	return ret;
> > +}
> > +EXPORT_SYMBOL(add_sensor_to_zone);
> > +
> >   /**
> >    * thermal_sensor_register - register a new thermal sensor
> >    * @name:	name of the thermal sensor
> > @@ -1732,6 +1920,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;
> >
> > @@ -1751,6 +1940,13 @@ void thermal_sensor_unregister(struct
> thermal_sensor *ts)
> >   	if (!found)
> >   		return;
> >
> > +	mutex_lock(&zone_list_lock);
> > +
> > +	for_each_thermal_zone(tz)
> > +		remove_sensor_from_zone(tz, ts);
> > +
> > +	mutex_unlock(&zone_list_lock);
> > +
> >   	for (i = 0; i < ts->thresholds; i++) {
> >   		device_remove_file(&ts->device, &ts->thresh_attrs[i].attr);
> >   		if (ts->ops->get_hyst) {
> > diff --git a/include/linux/thermal.h b/include/linux/thermal.h
> > index 5470dae..2194519 100644
> > --- a/include/linux/thermal.h
> > +++ b/include/linux/thermal.h
> > @@ -55,6 +55,8 @@
> >   #define DEFAULT_THERMAL_GOVERNOR       "user_space"
> >   #endif
> >
> > +#define MAX_SENSORS_PER_ZONE		5
> 
> 
> Why not making it a linked list? Why does it need to be static? Just
> trying to avoid to maintain this number sane, as we cannot predict what
> happens in future :-)

As I said earlier, making it a list makes things even more complex.
But I wanted this to be configurable through Kconfig, for which I
submitted a patch in my v2. But we had some comments against it.
So, we removed it, and need to revisit this later.

Thanks,
Durga

> 
> > +
> >   struct thermal_sensor;
> >   struct thermal_zone_device;
> >   struct thermal_cooling_device;
> > @@ -202,6 +204,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];
> > +};
> 
> 
> Could you please add documentation for the above structure? Why it does
> not need locking? what is *ops?
> > +
> >   /* Structure that holds thermal governor information */
> >   struct thermal_governor {
> >   	char name[THERMAL_NAME_LENGTH];
> > @@ -274,6 +291,11 @@ struct thermal_sensor
> *thermal_sensor_register(const char *, int,
> >   				struct thermal_sensor_ops *, void *);
> >   void thermal_sensor_unregister(struct thermal_sensor *);
> >
> > +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
> *);
> > +struct thermal_sensor *get_sensor_by_name(const char *);
> > +
> 
> I believe we need a better naming for this API. First suggestion is to
> use same prefix on all of them. Probably this comment applies not only
> to this specific patch.
> 
> Besides, for all functions above, you may want to add comments
> documenting them and their parameters?
> 
> >   #ifdef CONFIG_NET
> >   extern int thermal_generate_netlink_event(struct thermal_zone_device
> *tz,
> >   						enum events event);
> >
> 
> --
> To unsubscribe from this list: send the line "unsubscribe linux-pm" in
> the body of a message to majordomo@vger.kernel.org
> More majordomo info at  http://vger.kernel.org/majordomo-info.html

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

* RE: [PATCH 3/8] Thermal: Add APIs to bind cdev to new zone structure
  2013-02-28 19:35   ` Eduardo Valentin
@ 2013-03-01 15:33     ` R, Durgadoss
  0 siblings, 0 replies; 39+ messages in thread
From: R, Durgadoss @ 2013-03-01 15:33 UTC (permalink / raw)
  To: Eduardo Valentin; +Cc: Zhang, Rui, linux-pm, linux-kernel, hongbo.zhang, wni


> -----Original Message-----
> From: Eduardo Valentin [mailto:eduardo.valentin@ti.com]
> Sent: Friday, March 01, 2013 1:06 AM
> To: R, Durgadoss
> Cc: Zhang, Rui; linux-pm@vger.kernel.org; linux-kernel@vger.kernel.org;
> hongbo.zhang@linaro.org; wni@nvidia.com
> Subject: Re: [PATCH 3/8] Thermal: Add APIs to bind cdev to new zone
> structure
> 
> Durga,
> 
> On 05-02-2013 06:46, Durgadoss R wrote:
> > This patch creates new APIs to add/remove a
> > cdev to/from a zone. This patch does not change
> > the old cooling device implementation.
> 
> Same comments on patch 02/08 I want to rise here:
> 
> - Consider using linked list
> - You may have contention on your index/cdevs array
> - overflow on your buffer (carefully check your implementation)
> - zone removal condition. can we remove zones with cdevs registered?

Yes, as I said in 02/08.

> - get_by_name, why do we need it? (at least not on this patch)

The platform drivers need this API to query the pointer for cdevs,
sensors.

Thanks,
Durga

> - Minors on strlcpy, snprintf, devm_ helpers
> - documentation in the code for these helper functions and also better
> naming..
> 
> >
> > Signed-off-by: Durgadoss R <durgadoss.r@intel.com>
> > ---
> >   drivers/thermal/thermal_sys.c |   80
> +++++++++++++++++++++++++++++++++++++++++
> >   include/linux/thermal.h       |    9 +++++
> >   2 files changed, 89 insertions(+)
> >
> > diff --git a/drivers/thermal/thermal_sys.c b/drivers/thermal/thermal_sys.c
> > index 838d4fb..bf703b1 100644
> > --- a/drivers/thermal/thermal_sys.c
> > +++ b/drivers/thermal/thermal_sys.c
> > @@ -57,6 +57,7 @@ static LIST_HEAD(thermal_governor_list);
> >   static DEFINE_MUTEX(thermal_list_lock);
> >   static DEFINE_MUTEX(sensor_list_lock);
> >   static DEFINE_MUTEX(zone_list_lock);
> > +static DEFINE_MUTEX(cdev_list_lock);
> >   static DEFINE_MUTEX(thermal_governor_lock);
> >
> >   #define for_each_thermal_sensor(pos) \
> > @@ -83,6 +84,9 @@ static DEFINE_MUTEX(thermal_governor_lock);
> >   	ret;						\
> >   })
> >
> > +#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;
> > @@ -466,6 +470,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 j, indx;
> > +
> > +	indx = GET_INDEX(tz, cdev, 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) \
> > @@ -1462,6 +1484,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)
> > @@ -1499,6 +1522,13 @@ void thermal_cooling_device_unregister(struct
> thermal_cooling_device *cdev)
> >
> >   	mutex_unlock(&thermal_list_lock);
> >
> > +	mutex_lock(&zone_list_lock);
> > +
> > +	for_each_thermal_zone(tmp_tz)
> > +		remove_cdev_from_zone(tmp_tz, cdev);
> > +
> > +	mutex_unlock(&zone_list_lock);
> > +
> >   	if (cdev->type[0])
> >   		device_remove_file(&cdev->device, &dev_attr_cdev_type);
> >   	device_remove_file(&cdev->device, &dev_attr_max_state);
> > @@ -1794,6 +1824,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;
> > @@ -1844,6 +1891,39 @@ exit_zone:
> >   }
> >   EXPORT_SYMBOL(add_sensor_to_zone);
> >
> > +int add_cdev_to_zone(struct thermal_zone *tz,
> > +			struct thermal_cooling_device *cdev)
> > +{
> > +	int ret;
> > +
> > +	if (!tz || !cdev)
> > +		return -EINVAL;
> > +
> > +	mutex_lock(&zone_list_lock);
> > +
> > +	/* Ensure we are not adding the same cdev again!! */
> > +	ret = GET_INDEX(tz, cdev, 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(&zone_list_lock);
> > +	return ret;
> > +}
> > +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 2194519..c841414 100644
> > --- a/include/linux/thermal.h
> > +++ b/include/linux/thermal.h
> > @@ -57,6 +57,8 @@
> >
> >   #define MAX_SENSORS_PER_ZONE		5
> >
> > +#define MAX_CDEVS_PER_ZONE		5
> > +
> >   struct thermal_sensor;
> >   struct thermal_zone_device;
> >   struct thermal_cooling_device;
> > @@ -217,6 +219,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 */
> > @@ -296,6 +302,9 @@ void remove_thermal_zone(struct thermal_zone
> *);
> >   int add_sensor_to_zone(struct thermal_zone *, struct thermal_sensor *);
> >   struct thermal_sensor *get_sensor_by_name(const char *);
> >
> > +int add_cdev_to_zone(struct thermal_zone *, struct
> thermal_cooling_device *);
> > +struct thermal_cooling_device *get_cdev_by_name(const char *);
> > +
> >   #ifdef CONFIG_NET
> >   extern int thermal_generate_netlink_event(struct thermal_zone_device
> *tz,
> >   						enum events event);
> >


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

* RE: [PATCH 4/8] Thermal: Add trip point sysfs nodes for sensor
  2013-02-28 19:51   ` Eduardo Valentin
@ 2013-03-01 15:34     ` R, Durgadoss
  0 siblings, 0 replies; 39+ messages in thread
From: R, Durgadoss @ 2013-03-01 15:34 UTC (permalink / raw)
  To: Eduardo Valentin; +Cc: Zhang, Rui, linux-pm, linux-kernel, hongbo.zhang, wni

> -----Original Message-----
> From: linux-pm-owner@vger.kernel.org [mailto:linux-pm-
> owner@vger.kernel.org] On Behalf Of Eduardo Valentin
> Sent: Friday, March 01, 2013 1:21 AM
> To: R, Durgadoss
> Cc: Zhang, Rui; linux-pm@vger.kernel.org; linux-kernel@vger.kernel.org;
> hongbo.zhang@linaro.org; wni@nvidia.com
> Subject: Re: [PATCH 4/8] Thermal: Add trip point sysfs nodes for sensor
> 
> Durga,
> 
> 
> Same comments on patch 02/08 I want to rise here:
> - Minors on strlcpy, snprintf, devm_ helpers
> - documentation in the code for these helper functions and also better
> naming..
> 
> 
> On 05-02-2013 06:46, Durgadoss R wrote:
> > This patch adds a trip point related sysfs nodes
> > for each sensor under a zone in /sys/class/thermal/zoneX/.
> > The nodes will be named, sensorX_trip_active,
> > sensorX_trip_passive, sensorX_trip_hot, sensorX_trip_critical
> > for active, passive, hot and critical trip points
> > respectively for sensorX.
> >
> > Signed-off-by: Durgadoss R <durgadoss.r@intel.com>
> > ---
> >   drivers/thermal/thermal_sys.c |  225
> ++++++++++++++++++++++++++++++++++++++++-
> >   include/linux/thermal.h       |   38 ++++++-
> >   2 files changed, 260 insertions(+), 3 deletions(-)
> >
> > diff --git a/drivers/thermal/thermal_sys.c b/drivers/thermal/thermal_sys.c
> > index bf703b1..69a60a4 100644
> > --- a/drivers/thermal/thermal_sys.c
> > +++ b/drivers/thermal/thermal_sys.c
> > @@ -452,6 +452,37 @@ static void thermal_zone_device_check(struct
> work_struct *work)
> >   	thermal_zone_device_update(tz);
> >   }
> >
> > +static int get_sensor_indx_by_kobj(struct thermal_zone *tz, const char
> *name)
> > +{
> > +	int i, indx = -EINVAL;
> > +
> > +	mutex_lock(&sensor_list_lock);
> > +	for (i = 0; i < tz->sensor_indx; i++) {
> > +		if (!strnicmp(name, kobject_name(&tz->sensors[i]-
> >device.kobj),
> > +					THERMAL_NAME_LENGTH)) {
> > +			indx = i;
> > +			break;
> > +		}
> > +	}
> > +	mutex_unlock(&sensor_list_lock);
> > +	return indx;
> > +}
> > +
> > +static void inline __remove_trip_attr(struct thermal_zone *tz, int indx)
> I believe the preferred format would be:

Ok, will change..

> 
> static inline void __remove_trip_attr(struct thermal_zone *tz, int indx)
> 
> > +{
> > +	int i;
> > +	struct thermal_trip_attr *attr = tz->trip_attr[indx];
> > +
> > +	if (!attr)
> > +		return;
> > +
> > +	for (i = 0; i < NUM_TRIP_TYPES; i++)
> > +		device_remove_file(&tz->device, &attr->attrs[i].attr);
> > +
> > +	kfree(tz->trip_attr[indx]);
> > +	tz->trip_attr[indx] = NULL;
> > +}
> > +
> >   static void remove_sensor_from_zone(struct thermal_zone *tz,
> >   				struct thermal_sensor *ts)
> >   {
> > @@ -463,9 +494,15 @@ static void remove_sensor_from_zone(struct
> thermal_zone *tz,
> >
> >   	sysfs_remove_link(&tz->device.kobj, kobject_name(&ts-
> >device.kobj));
> >
> > +	/* Remove trip point attributes associated with this sensor */
> > +	__remove_trip_attr(tz, 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->sensor_trip[j] = tz->sensor_trip[j + 1];
> > +		tz->trip_attr[j] = tz->trip_attr[j + 1];
> > +	}
> >
> >   	tz->sensor_indx--;
> >   }
> > @@ -879,6 +916,99 @@ 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 device *dev, struct device_attribute *attr, char *buf)
> > +{
> > +	int i, indx, ret = 0;
> > +	char kobj_name[THERMAL_NAME_LENGTH];
> > +	struct thermal_zone *tz = to_zone(dev);
> > +
> > +	if (!sscanf(attr->attr.name, "sensor%d_trip_active", &i))
> > +		return -EINVAL;
> > +
> > +	snprintf(kobj_name, THERMAL_NAME_LENGTH, "sensor%d", i);
> > +	indx = get_sensor_indx_by_kobj(tz, kobj_name);
> > +	if (indx < 0)
> > +		return indx;
> > +
> > +	if (tz->sensor_trip[indx]->num_active_trips <= 0)
> > +		return sprintf(buf, "<Not available>\n");
> > +
> > +	ret += sprintf(buf, "0x%x", tz->sensor_trip[indx]->active_trip_mask);
> > +	for (i = 0; i < tz->sensor_trip[indx]->num_active_trips; i++) {
> > +		ret += sprintf(buf + ret, " %d",
> > +			tz->sensor_trip[indx]->active_trips[i]);
> > +	}
> > +
> > +	ret += sprintf(buf + ret, "\n");
> > +	return ret;
> > +}
> > +
> 
> I believe the above function violates sysfs rules, no? Each and every
> file must contain only 1 value..

Yes, re-working this and similar thing in 05/08 in next version.

Thanks,
Durga

> 
> > +static ssize_t
> > +ptrip_show(struct device *dev, struct device_attribute *attr, char *buf)
> > +{
> > +	int i, indx, ret = 0;
> > +	char kobj_name[THERMAL_NAME_LENGTH];
> > +	struct thermal_zone *tz = to_zone(dev);
> > +
> > +	if (!sscanf(attr->attr.name, "sensor%d_trip_passive", &i))
> > +		return -EINVAL;
> > +
> > +	snprintf(kobj_name, THERMAL_NAME_LENGTH, "sensor%d", i);
> > +	indx = get_sensor_indx_by_kobj(tz, kobj_name);
> > +	if (indx < 0)
> > +		return indx;
> > +
> > +	if (tz->sensor_trip[indx]->num_passive_trips <= 0)
> > +		return sprintf(buf, "<Not available>\n");
> > +
> > +	for (i = 0; i < tz->sensor_trip[indx]->num_passive_trips; i++) {
> > +		ret += sprintf(buf + ret, "%d ",
> > +			tz->sensor_trip[indx]->passive_trips[i]);
> > +	}
> > +
> > +	ret += sprintf(buf + ret, "\n");
> > +	return ret;
> > +}
> 
> 
> ditto.
> 
> > +
> > +static ssize_t
> > +hot_show(struct device *dev, struct device_attribute *attr, char *buf)
> > +{
> > +	int indx;
> > +	char kobj_name[THERMAL_NAME_LENGTH];
> > +	struct thermal_zone *tz = to_zone(dev);
> > +
> > +	if (!sscanf(attr->attr.name, "sensor%d_trip_hot", &indx))
> > +		return -EINVAL;
> > +
> > +	snprintf(kobj_name, THERMAL_NAME_LENGTH, "sensor%d", indx);
> > +
> > +	indx = get_sensor_indx_by_kobj(tz, kobj_name);
> > +	if (indx < 0)
> > +		return indx;
> > +
> > +	return sprintf(buf, "%d\n", tz->sensor_trip[indx]->hot);
> > +}
> > +
> > +static ssize_t
> > +critical_show(struct device *dev, struct device_attribute *attr, char *buf)
> > +{
> > +	int indx;
> > +	char kobj_name[THERMAL_NAME_LENGTH];
> > +	struct thermal_zone *tz = to_zone(dev);
> > +
> > +	if (!sscanf(attr->attr.name, "sensor%d_trip_critical", &indx))
> > +		return -EINVAL;
> > +
> > +	snprintf(kobj_name, THERMAL_NAME_LENGTH, "sensor%d", indx);
> > +
> > +	indx = get_sensor_indx_by_kobj(tz, kobj_name);
> > +	if (indx < 0)
> > +		return indx;
> > +
> > +	return sprintf(buf, "%d\n", tz->sensor_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);
> > @@ -889,7 +1019,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);
> > +/* Thermal zone attributes */
> > +static DEVICE_ATTR(zone_name, S_IRUGO, zone_name_show, NULL);
> >
> >   /* sys I/F for cooling device */
> >   #define to_cooling_device(_dev)	\
> > @@ -1744,6 +1875,38 @@ static int enable_sensor_thresholds(struct
> thermal_sensor *ts, int count)
> >   	return 0;
> >   }
> >
> > +static int create_sensor_trip_attrs(struct thermal_zone *tz,
> > +				struct thermal_trip_attr *attr, int indx)
> > +{
> > +	int i, ret;
> > +	static const char *const names[NUM_TRIP_TYPES] = {
> > +				"sensor%d_trip_active",
> > +				"sensor%d_trip_passive",
> > +				"sensor%d_trip_hot",
> > +				"sensor%d_trip_critical",
> > +				};
> > +	static ssize_t (*const rd_ptr[NUM_TRIP_TYPES]) (struct device *dev,
> > +			struct device_attribute *devattr, char *buf) = {
> > +			active_show, ptrip_show, hot_show, critical_show};
> > +
> > +	for (i = 0; i < NUM_TRIP_TYPES; i++) {
> > +		snprintf(attr->attrs[i].name, THERMAL_NAME_LENGTH,
> names[i],
> > +			indx);
> > +		sysfs_attr_init(&attr->attrs[i].attr.attr);
> > +		attr->attrs[i].attr.attr.name = attr->attrs[i].name;
> > +		attr->attrs[i].attr.attr.mode = S_IRUGO;
> > +		attr->attrs[i].attr.show = rd_ptr[i];
> > +		ret = device_create_file(&tz->device, &attr->attrs[i].attr);
> > +		if (ret)
> > +			goto exit;
> > +	}
> > +	return 0;
> > +exit:
> > +	while (--i >= 0)
> > +		device_remove_file(&tz->device, &attr->attrs[i].attr);
> > +	return ret;
> > +}
> > +
> >   struct thermal_zone *create_thermal_zone(const char *name, void
> *devdata)
> >   {
> >   	struct thermal_zone *tz;
> > @@ -1793,6 +1956,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)
> > @@ -1813,6 +1977,23 @@ 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) {
> > +		/* Remove /sys/class/thermal/zoneX/sensorY */
> > +		sysfs_remove_link(&tz->device.kobj,
> > +				kobject_name(&tz->sensors[i]-
> >device.kobj));
> > +		__remove_trip_attr(tz, i);
> > +	}
> > +
> > +	/* Release the cdevs attached to this zone */
> > +	i = tz->cdev_indx;
> > +	while (--i >= 0) {
> > +		/* Remove /sys/class/thermal/zoneX/cooling_deviceY */
> > +		sysfs_remove_link(&tz->device.kobj,
> > +				kobject_name(&tz->cdevs[i]->device.kobj));
> > +	}
> > +
> >   	release_idr(&thermal_zone_idr, &thermal_idr_lock, tz->id);
> >   	idr_destroy(&tz->idr);
> >
> > @@ -1924,6 +2105,46 @@ exit_zone:
> >   }
> >   EXPORT_SYMBOL(add_cdev_to_zone);
> >
> > +int add_sensor_trip_info(struct thermal_zone *tz, struct thermal_sensor
> *ts,
> > +			struct thermal_trip_point *trip)
> > +{
> > +	int ret, indx, kobj_indx;
> > +
> > +	if (!tz || !ts || !trip)
> > +		return -EINVAL;
> > +
> > +	if (!sscanf(kobject_name(&ts->device.kobj), "sensor%d",
> &kobj_indx))
> > +		return -EINVAL;
> > +
> > +	mutex_lock(&zone_list_lock);
> > +
> > +	indx = GET_INDEX(tz, ts, sensor);
> > +	if (indx < 0) {
> > +		ret = -EINVAL;
> > +		goto exit;
> > +	}
> > +
> > +	tz->trip_attr[indx] = kzalloc(sizeof(struct thermal_trip_attr),
> > +					GFP_KERNEL);
> > +	if (!tz->trip_attr[indx]) {
> > +		ret = -ENOMEM;
> > +		goto exit;
> > +	}
> > +
> > +	ret = create_sensor_trip_attrs(tz, tz->trip_attr[indx], kobj_indx);
> > +	if (ret) {
> > +		kfree(tz->trip_attr[indx]);
> > +		goto exit;
> > +	}
> > +
> > +	tz->sensor_trip[indx] = trip;
> > +
> > +exit:
> > +	mutex_unlock(&zone_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 c841414..2f68018 100644
> > --- a/include/linux/thermal.h
> > +++ b/include/linux/thermal.h
> > @@ -31,7 +31,8 @@
> >
> >   #define THERMAL_TRIPS_NONE	-1
> >   #define THERMAL_MAX_TRIPS	12
> > -#define THERMAL_NAME_LENGTH	20
> > +#define THERMAL_NAME_LENGTH	22
> > +#define NUM_TRIP_TYPES		4
> >
> >   /* No upper/lower limit requirement */
> >   #define THERMAL_NO_LIMIT	-1UL
> > @@ -166,6 +167,34 @@ 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_trip_attr {
> > +	struct thermal_attr attrs[NUM_TRIP_TYPES];
> > +};
> > +
> >   struct thermal_sensor {
> >   	char name[THERMAL_NAME_LENGTH];
> >   	int id;
> > @@ -223,6 +252,10 @@ struct thermal_zone {
> >   	/* cdev level information */
> >   	int cdev_indx; /* index into 'cdevs' array */
> >   	struct thermal_cooling_device *cdevs[MAX_CDEVS_PER_ZONE];
> > +
> > +	/* Thermal sensors trip information */
> > +	struct thermal_trip_point *sensor_trip[MAX_SENSORS_PER_ZONE];
> > +	struct thermal_trip_attr *trip_attr[MAX_SENSORS_PER_ZONE];
> >   };
> >
> >   /* Structure that holds thermal governor information */
> > @@ -305,6 +338,9 @@ struct thermal_sensor
> *get_sensor_by_name(const char *);
> >   int add_cdev_to_zone(struct thermal_zone *, struct
> thermal_cooling_device *);
> >   struct thermal_cooling_device *get_cdev_by_name(const char *);
> >
> > +int add_sensor_trip_info(struct thermal_zone *, struct thermal_sensor *,
> > +			struct thermal_trip_point *);
> > +
> >   #ifdef CONFIG_NET
> >   extern int thermal_generate_netlink_event(struct thermal_zone_device
> *tz,
> >   						enum events event);
> >
> 
> --
> To unsubscribe from this list: send the line "unsubscribe linux-pm" in
> the body of a message to majordomo@vger.kernel.org
> More majordomo info at  http://vger.kernel.org/majordomo-info.html

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

* Re: [PATCHv3 0/8] Thermal Framework Enhancements
  2013-02-05 10:46 [PATCHv3 0/8] Thermal Framework Enhancements Durgadoss R
                   ` (10 preceding siblings ...)
  2013-02-28 21:33 ` Eduardo Valentin
@ 2013-08-29 19:38 ` Eduardo Valentin
  2013-08-30  9:20   ` R, Durgadoss
  11 siblings, 1 reply; 39+ messages in thread
From: Eduardo Valentin @ 2013-08-29 19:38 UTC (permalink / raw)
  To: Durgadoss R
  Cc: rui.zhang, linux-pm, linux-kernel, eduardo.valentin, hongbo.zhang, wni

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

Durga,

On 05-02-2013 06:46, Durgadoss R wrote:
> This patch set is a v3 of the previous versions submitted here:
> [v2]: http://lwn.net/Articles/531720/
> [v1]: https://lkml.org/lkml/2012/12/18/108 
> [RFC]:https://patchwork.kernel.org/patch/1758921/
> 

Long time this work is not moving forward. While writing the device tree
parser, I thought of using your work as baseline to see how the multiple
sensor per zone would look like (also in DT).

But while checking your code again, I realized that you are actually
creating a new API, that is probably why you named it sysfs-api2. While
I understand the motivation (they are pretty different), I believe this
is not a good thing to do. I would suggest making so that we have a
single API.

> This patch set is based on Rui's -next tree, and is
> tested on a Core-i5 and an Atom netbook.
> 
> Changes since v2:
>  * Reworked the map sysfs attributes in patch [5/8]
>  * Dropped configuration for maximum sensors and
>    cooling devices, through Kconfig.
>  * Added __remove_trip_attr method
>  * Renamed __clean_map_entry to __remove_map_entry
>    for consistency in naming.
> Changes Since v1:
>  * Removed kobject creation for thermal_trip and thermal_map
>    nodes as per Greg-KH's comments.
>  * Added ABI Documentation under 'testing'.
>  * Modified the GET_INDEX macro to be more linux-like, thanks
>    to Joe Perches.
>  * Added get_[sensor/cdev]_by_name APIs to thermal.h
> 
> This series contains 8 patches:
> Patch 1/8: Creates new sensor level APIs
> Patch 2/8: Creates new zone level APIs. The existing tzd structure is
>            kept as such for clarity and compatibility purposes.
> Patch 3/8: Creates functions to add/remove a cdev to/from a zone. The
>            existing tcd structure need not be modified.
> Patch 4/8: Adds sensorX_trip_[active/passive/hot/critical] sysfs nodes,
> 	   under /sys/class/thermal/zoneY/. This exposes various trip
>            points for sensorX present in zoneY.
> Patch 5/8: Adds mapY_* sysfs node. These attributes represent
>            the binding relationship between a sensor and a cdev,
>            within a zone.
> Patch 6/8: 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/8: Add ABI documentation for sysfs interfaces introduced in this patch.
> Patch 8/8: A dummy driver that can be used for testing. This is not for merge.
> 
> Durgadoss R (8):
>   Thermal: Create sensor level APIs
>   Thermal: Create zone level APIs
>   Thermal: Add APIs to bind cdev to new zone structure
>   Thermal: Add trip point sysfs nodes for sensor
>   Thermal: Create Thermal map sysfs attributes for a zone
>   Thermal: Add Documentation to new APIs
>   Thermal: Add ABI Documentation for sysfs interfaces
>   Thermal: Dummy driver used for testing
> 
>  Documentation/ABI/testing/sysfs-class-thermal |  137 ++++
>  Documentation/thermal/sysfs-api2.txt          |  247 ++++++
>  drivers/thermal/Kconfig                       |    5 +
>  drivers/thermal/Makefile                      |    2 +
>  drivers/thermal/thermal_sys.c                 |  994 +++++++++++++++++++++++++
>  drivers/thermal/thermal_test.c                |  324 ++++++++
>  include/linux/thermal.h                       |  123 ++-
>  7 files changed, 1831 insertions(+), 1 deletion(-)
>  create mode 100644 Documentation/ABI/testing/sysfs-class-thermal
>  create mode 100644 Documentation/thermal/sysfs-api2.txt
>  create mode 100644 drivers/thermal/thermal_test.c
> 


-- 
You have got to be excited about what you are doing. (L. Lamport)

Eduardo Valentin


[-- Attachment #2: OpenPGP digital signature --]
[-- Type: application/pgp-signature, Size: 295 bytes --]

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

* RE: [PATCHv3 0/8] Thermal Framework Enhancements
  2013-08-29 19:38 ` Eduardo Valentin
@ 2013-08-30  9:20   ` R, Durgadoss
  2013-08-30 12:34     ` Eduardo Valentin
  0 siblings, 1 reply; 39+ messages in thread
From: R, Durgadoss @ 2013-08-30  9:20 UTC (permalink / raw)
  To: Eduardo Valentin; +Cc: Zhang, Rui, linux-pm, linux-kernel, hongbo.zhang, wni

Hi Eduardo,

> -----Original Message-----
> From: Eduardo Valentin [mailto:eduardo.valentin@ti.com]
> Sent: Friday, August 30, 2013 1:08 AM
> To: R, Durgadoss
> Cc: Zhang, Rui; linux-pm@vger.kernel.org; linux-kernel@vger.kernel.org;
> eduardo.valentin@ti.com; hongbo.zhang@linaro.org; wni@nvidia.com
> Subject: Re: [PATCHv3 0/8] Thermal Framework Enhancements
> 
> Durga,
> 
> On 05-02-2013 06:46, Durgadoss R wrote:
> > This patch set is a v3 of the previous versions submitted here:
> > [v2]: http://lwn.net/Articles/531720/
> > [v1]: https://lkml.org/lkml/2012/12/18/108
> > [RFC]:https://patchwork.kernel.org/patch/1758921/
> >
> 
> Long time this work is not moving forward. While writing the device tree

I am trying my best to get to this,
Will try to refresh in a couple of weeks.

> parser, I thought of using your work as baseline to see how the multiple
> sensor per zone would look like (also in DT).
> 
> But while checking your code again, I realized that you are actually
> creating a new API, that is probably why you named it sysfs-api2. While
> I understand the motivation (they are pretty different), I believe this
> is not a good thing to do. I would suggest making so that we have a
> single API.

As in the sensor APIs ? or the zone level APIs ?
The sensor level APIs are anyway new; the zone level ones
we have to work out a way for them.

Is this what you are referring to ? Could you confirm/explain a bit more ?

Thanks,
Durga

> 
> > This patch set is based on Rui's -next tree, and is
> > tested on a Core-i5 and an Atom netbook.
> >
> > Changes since v2:
> >  * Reworked the map sysfs attributes in patch [5/8]
> >  * Dropped configuration for maximum sensors and
> >    cooling devices, through Kconfig.
> >  * Added __remove_trip_attr method
> >  * Renamed __clean_map_entry to __remove_map_entry
> >    for consistency in naming.
> > Changes Since v1:
> >  * Removed kobject creation for thermal_trip and thermal_map
> >    nodes as per Greg-KH's comments.
> >  * Added ABI Documentation under 'testing'.
> >  * Modified the GET_INDEX macro to be more linux-like, thanks
> >    to Joe Perches.
> >  * Added get_[sensor/cdev]_by_name APIs to thermal.h
> >
> > This series contains 8 patches:
> > Patch 1/8: Creates new sensor level APIs
> > Patch 2/8: Creates new zone level APIs. The existing tzd structure is
> >            kept as such for clarity and compatibility purposes.
> > Patch 3/8: Creates functions to add/remove a cdev to/from a zone. The
> >            existing tcd structure need not be modified.
> > Patch 4/8: Adds sensorX_trip_[active/passive/hot/critical] sysfs nodes,
> > 	   under /sys/class/thermal/zoneY/. This exposes various trip
> >            points for sensorX present in zoneY.
> > Patch 5/8: Adds mapY_* sysfs node. These attributes represent
> >            the binding relationship between a sensor and a cdev,
> >            within a zone.
> > Patch 6/8: 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/8: Add ABI documentation for sysfs interfaces introduced in this patch.
> > Patch 8/8: A dummy driver that can be used for testing. This is not for merge.
> >
> > Durgadoss R (8):
> >   Thermal: Create sensor level APIs
> >   Thermal: Create zone level APIs
> >   Thermal: Add APIs to bind cdev to new zone structure
> >   Thermal: Add trip point sysfs nodes for sensor
> >   Thermal: Create Thermal map sysfs attributes for a zone
> >   Thermal: Add Documentation to new APIs
> >   Thermal: Add ABI Documentation for sysfs interfaces
> >   Thermal: Dummy driver used for testing
> >
> >  Documentation/ABI/testing/sysfs-class-thermal |  137 ++++
> >  Documentation/thermal/sysfs-api2.txt          |  247 ++++++
> >  drivers/thermal/Kconfig                       |    5 +
> >  drivers/thermal/Makefile                      |    2 +
> >  drivers/thermal/thermal_sys.c                 |  994 +++++++++++++++++++++++++
> >  drivers/thermal/thermal_test.c                |  324 ++++++++
> >  include/linux/thermal.h                       |  123 ++-
> >  7 files changed, 1831 insertions(+), 1 deletion(-)
> >  create mode 100644 Documentation/ABI/testing/sysfs-class-thermal
> >  create mode 100644 Documentation/thermal/sysfs-api2.txt
> >  create mode 100644 drivers/thermal/thermal_test.c
> >
> 
> 
> --
> You have got to be excited about what you are doing. (L. Lamport)
> 
> Eduardo Valentin


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

* Re: [PATCHv3 0/8] Thermal Framework Enhancements
  2013-08-30  9:20   ` R, Durgadoss
@ 2013-08-30 12:34     ` Eduardo Valentin
  2013-08-30 13:21       ` R, Durgadoss
  0 siblings, 1 reply; 39+ messages in thread
From: Eduardo Valentin @ 2013-08-30 12:34 UTC (permalink / raw)
  To: R, Durgadoss
  Cc: Eduardo Valentin, Zhang, Rui, linux-pm, linux-kernel, hongbo.zhang, wni

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

On 30-08-2013 05:20, R, Durgadoss wrote:
> Hi Eduardo,
> 
>> -----Original Message-----
>> From: Eduardo Valentin [mailto:eduardo.valentin@ti.com]
>> Sent: Friday, August 30, 2013 1:08 AM
>> To: R, Durgadoss
>> Cc: Zhang, Rui; linux-pm@vger.kernel.org; linux-kernel@vger.kernel.org;
>> eduardo.valentin@ti.com; hongbo.zhang@linaro.org; wni@nvidia.com
>> Subject: Re: [PATCHv3 0/8] Thermal Framework Enhancements
>>
>> Durga,
>>
>> On 05-02-2013 06:46, Durgadoss R wrote:
>>> This patch set is a v3 of the previous versions submitted here:
>>> [v2]: http://lwn.net/Articles/531720/
>>> [v1]: https://lkml.org/lkml/2012/12/18/108
>>> [RFC]:https://patchwork.kernel.org/patch/1758921/
>>>
>>
>> Long time this work is not moving forward. While writing the device tree
> 
> I am trying my best to get to this,
> Will try to refresh in a couple of weeks.
> 
>> parser, I thought of using your work as baseline to see how the multiple
>> sensor per zone would look like (also in DT).
>>
>> But while checking your code again, I realized that you are actually
>> creating a new API, that is probably why you named it sysfs-api2. While
>> I understand the motivation (they are pretty different), I believe this
>> is not a good thing to do. I would suggest making so that we have a
>> single API.
> 
> As in the sensor APIs ? or the zone level APIs ?
> The sensor level APIs are anyway new; the zone level ones
> we have to work out a way for them.
> 
> Is this what you are referring to ? Could you confirm/explain a bit more ?

OK. Let's assume that maybe I didn't quite get your proposal then. Let
me step back and ask you what is the relation between existing
thermal_zone_device and thermal_zone? Would existing drivers be
complaint with new API?

> 
> Thanks,
> Durga
> 
>>
>>> This patch set is based on Rui's -next tree, and is
>>> tested on a Core-i5 and an Atom netbook.
>>>
>>> Changes since v2:
>>>  * Reworked the map sysfs attributes in patch [5/8]
>>>  * Dropped configuration for maximum sensors and
>>>    cooling devices, through Kconfig.
>>>  * Added __remove_trip_attr method
>>>  * Renamed __clean_map_entry to __remove_map_entry
>>>    for consistency in naming.
>>> Changes Since v1:
>>>  * Removed kobject creation for thermal_trip and thermal_map
>>>    nodes as per Greg-KH's comments.
>>>  * Added ABI Documentation under 'testing'.
>>>  * Modified the GET_INDEX macro to be more linux-like, thanks
>>>    to Joe Perches.
>>>  * Added get_[sensor/cdev]_by_name APIs to thermal.h
>>>
>>> This series contains 8 patches:
>>> Patch 1/8: Creates new sensor level APIs
>>> Patch 2/8: Creates new zone level APIs. The existing tzd structure is
>>>            kept as such for clarity and compatibility purposes.
>>> Patch 3/8: Creates functions to add/remove a cdev to/from a zone. The
>>>            existing tcd structure need not be modified.
>>> Patch 4/8: Adds sensorX_trip_[active/passive/hot/critical] sysfs nodes,
>>> 	   under /sys/class/thermal/zoneY/. This exposes various trip
>>>            points for sensorX present in zoneY.
>>> Patch 5/8: Adds mapY_* sysfs node. These attributes represent
>>>            the binding relationship between a sensor and a cdev,
>>>            within a zone.
>>> Patch 6/8: 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/8: Add ABI documentation for sysfs interfaces introduced in this patch.
>>> Patch 8/8: A dummy driver that can be used for testing. This is not for merge.
>>>
>>> Durgadoss R (8):
>>>   Thermal: Create sensor level APIs
>>>   Thermal: Create zone level APIs
>>>   Thermal: Add APIs to bind cdev to new zone structure
>>>   Thermal: Add trip point sysfs nodes for sensor
>>>   Thermal: Create Thermal map sysfs attributes for a zone
>>>   Thermal: Add Documentation to new APIs
>>>   Thermal: Add ABI Documentation for sysfs interfaces
>>>   Thermal: Dummy driver used for testing
>>>
>>>  Documentation/ABI/testing/sysfs-class-thermal |  137 ++++
>>>  Documentation/thermal/sysfs-api2.txt          |  247 ++++++
>>>  drivers/thermal/Kconfig                       |    5 +
>>>  drivers/thermal/Makefile                      |    2 +
>>>  drivers/thermal/thermal_sys.c                 |  994 +++++++++++++++++++++++++
>>>  drivers/thermal/thermal_test.c                |  324 ++++++++
>>>  include/linux/thermal.h                       |  123 ++-
>>>  7 files changed, 1831 insertions(+), 1 deletion(-)
>>>  create mode 100644 Documentation/ABI/testing/sysfs-class-thermal
>>>  create mode 100644 Documentation/thermal/sysfs-api2.txt
>>>  create mode 100644 drivers/thermal/thermal_test.c
>>>
>>
>>
>> --
>> You have got to be excited about what you are doing. (L. Lamport)
>>
>> Eduardo Valentin
> 
> 
> 


-- 
You have got to be excited about what you are doing. (L. Lamport)

Eduardo Valentin


[-- Attachment #2: OpenPGP digital signature --]
[-- Type: application/pgp-signature, Size: 295 bytes --]

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

* RE: [PATCHv3 0/8] Thermal Framework Enhancements
  2013-08-30 12:34     ` Eduardo Valentin
@ 2013-08-30 13:21       ` R, Durgadoss
  0 siblings, 0 replies; 39+ messages in thread
From: R, Durgadoss @ 2013-08-30 13:21 UTC (permalink / raw)
  To: Eduardo Valentin; +Cc: Zhang, Rui, linux-pm, linux-kernel, hongbo.zhang, wni

> -----Original Message-----
> From: linux-pm-owner@vger.kernel.org [mailto:linux-pm-
> owner@vger.kernel.org] On Behalf Of Eduardo Valentin
> Sent: Friday, August 30, 2013 6:04 PM
> To: R, Durgadoss
> Cc: Eduardo Valentin; Zhang, Rui; linux-pm@vger.kernel.org; linux-
> kernel@vger.kernel.org; hongbo.zhang@linaro.org; wni@nvidia.com
> Subject: Re: [PATCHv3 0/8] Thermal Framework Enhancements
> 
> On 30-08-2013 05:20, R, Durgadoss wrote:
> > Hi Eduardo,
> >
> >> -----Original Message-----
> >> From: Eduardo Valentin [mailto:eduardo.valentin@ti.com]
> >> Sent: Friday, August 30, 2013 1:08 AM
> >> To: R, Durgadoss
> >> Cc: Zhang, Rui; linux-pm@vger.kernel.org; linux-kernel@vger.kernel.org;
> >> eduardo.valentin@ti.com; hongbo.zhang@linaro.org; wni@nvidia.com
> >> Subject: Re: [PATCHv3 0/8] Thermal Framework Enhancements
> >>
> >> Durga,
> >>
> >> On 05-02-2013 06:46, Durgadoss R wrote:
> >>> This patch set is a v3 of the previous versions submitted here:
> >>> [v2]: http://lwn.net/Articles/531720/
> >>> [v1]: https://lkml.org/lkml/2012/12/18/108
> >>> [RFC]:https://patchwork.kernel.org/patch/1758921/
> >>>
> >>
> >> Long time this work is not moving forward. While writing the device tree
> >
> > I am trying my best to get to this,
> > Will try to refresh in a couple of weeks.
> >
> >> parser, I thought of using your work as baseline to see how the multiple
> >> sensor per zone would look like (also in DT).
> >>
> >> But while checking your code again, I realized that you are actually
> >> creating a new API, that is probably why you named it sysfs-api2. While
> >> I understand the motivation (they are pretty different), I believe this
> >> is not a good thing to do. I would suggest making so that we have a
> >> single API.
> >
> > As in the sensor APIs ? or the zone level APIs ?
> > The sensor level APIs are anyway new; the zone level ones
> > we have to work out a way for them.
> >
> > Is this what you are referring to ? Could you confirm/explain a bit more ?
> 
> OK. Let's assume that maybe I didn't quite get your proposal then. Let
> me step back and ask you what is the relation between existing
> thermal_zone_device and thermal_zone? Would existing drivers be

The existing thermal_zone_device would be a new thermal zone
with one sensor in it.

> complaint with new API?

Okay got it. This is what myself & Rui discussed a while ago to address
this.

When these patches are merged, they will co-exist for some time.
Rui had an idea to write a wrapper on top of these, which will
make the existing drivers complaint with new API. 
This wrapper can be a Kconfig option, to select on what we need;
new/existing APIs.

Thanks,
Durga

> >
> >>
> >>> This patch set is based on Rui's -next tree, and is
> >>> tested on a Core-i5 and an Atom netbook.
> >>>
> >>> Changes since v2:
> >>>  * Reworked the map sysfs attributes in patch [5/8]
> >>>  * Dropped configuration for maximum sensors and
> >>>    cooling devices, through Kconfig.
> >>>  * Added __remove_trip_attr method
> >>>  * Renamed __clean_map_entry to __remove_map_entry
> >>>    for consistency in naming.
> >>> Changes Since v1:
> >>>  * Removed kobject creation for thermal_trip and thermal_map
> >>>    nodes as per Greg-KH's comments.
> >>>  * Added ABI Documentation under 'testing'.
> >>>  * Modified the GET_INDEX macro to be more linux-like, thanks
> >>>    to Joe Perches.
> >>>  * Added get_[sensor/cdev]_by_name APIs to thermal.h
> >>>
> >>> This series contains 8 patches:
> >>> Patch 1/8: Creates new sensor level APIs
> >>> Patch 2/8: Creates new zone level APIs. The existing tzd structure is
> >>>            kept as such for clarity and compatibility purposes.
> >>> Patch 3/8: Creates functions to add/remove a cdev to/from a zone. The
> >>>            existing tcd structure need not be modified.
> >>> Patch 4/8: Adds sensorX_trip_[active/passive/hot/critical] sysfs nodes,
> >>> 	   under /sys/class/thermal/zoneY/. This exposes various trip
> >>>            points for sensorX present in zoneY.
> >>> Patch 5/8: Adds mapY_* sysfs node. These attributes represent
> >>>            the binding relationship between a sensor and a cdev,
> >>>            within a zone.
> >>> Patch 6/8: 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/8: Add ABI documentation for sysfs interfaces introduced in this
> patch.
> >>> Patch 8/8: A dummy driver that can be used for testing. This is not for merge.
> >>>
> >>> Durgadoss R (8):
> >>>   Thermal: Create sensor level APIs
> >>>   Thermal: Create zone level APIs
> >>>   Thermal: Add APIs to bind cdev to new zone structure
> >>>   Thermal: Add trip point sysfs nodes for sensor
> >>>   Thermal: Create Thermal map sysfs attributes for a zone
> >>>   Thermal: Add Documentation to new APIs
> >>>   Thermal: Add ABI Documentation for sysfs interfaces
> >>>   Thermal: Dummy driver used for testing
> >>>
> >>>  Documentation/ABI/testing/sysfs-class-thermal |  137 ++++
> >>>  Documentation/thermal/sysfs-api2.txt          |  247 ++++++
> >>>  drivers/thermal/Kconfig                       |    5 +
> >>>  drivers/thermal/Makefile                      |    2 +
> >>>  drivers/thermal/thermal_sys.c                 |  994
> +++++++++++++++++++++++++
> >>>  drivers/thermal/thermal_test.c                |  324 ++++++++
> >>>  include/linux/thermal.h                       |  123 ++-
> >>>  7 files changed, 1831 insertions(+), 1 deletion(-)
> >>>  create mode 100644 Documentation/ABI/testing/sysfs-class-thermal
> >>>  create mode 100644 Documentation/thermal/sysfs-api2.txt
> >>>  create mode 100644 drivers/thermal/thermal_test.c
> >>>
> >>
> >>
> >> --
> >> You have got to be excited about what you are doing. (L. Lamport)
> >>
> >> Eduardo Valentin
> >
> >
> >
> 
> 
> --
> You have got to be excited about what you are doing. (L. Lamport)
> 
> Eduardo Valentin


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

end of thread, other threads:[~2013-08-30 13:21 UTC | newest]

Thread overview: 39+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2013-02-05 10:46 [PATCHv3 0/8] Thermal Framework Enhancements Durgadoss R
2013-02-05 10:46 ` [PATCH 1/8] Thermal: Create sensor level APIs Durgadoss R
2013-02-08  7:53   ` Zhang Rui
2013-02-08  8:26     ` R, Durgadoss
2013-02-08  9:54       ` Zhang Rui
2013-02-28 18:58   ` Eduardo Valentin
2013-03-01  5:08     ` R, Durgadoss
2013-02-05 10:46 ` [PATCH 2/8] Thermal: Create zone " Durgadoss R
2013-02-08  8:11   ` Zhang Rui
2013-02-08  8:54     ` R, Durgadoss
2013-02-08  9:54       ` Zhang Rui
2013-02-08 10:27         ` R, Durgadoss
2013-02-28 19:29   ` Eduardo Valentin
2013-03-01 15:31     ` R, Durgadoss
2013-02-05 10:46 ` [PATCH 3/8] Thermal: Add APIs to bind cdev to new zone structure Durgadoss R
2013-02-08  8:28   ` Zhang Rui
2013-02-28 19:35   ` Eduardo Valentin
2013-03-01 15:33     ` R, Durgadoss
2013-02-05 10:46 ` [PATCH 4/8] Thermal: Add trip point sysfs nodes for sensor Durgadoss R
2013-02-08  8:50   ` Zhang Rui
2013-02-28 19:51   ` Eduardo Valentin
2013-03-01 15:34     ` R, Durgadoss
2013-02-05 10:46 ` [PATCH 5/8] Thermal: Create Thermal map sysfs attributes for a zone Durgadoss R
2013-02-08  9:04   ` Zhang Rui
2013-02-08  9:08     ` R, Durgadoss
2013-02-08  9:55       ` Zhang Rui
2013-02-28 21:30   ` Eduardo Valentin
2013-02-05 10:46 ` [PATCH 6/8] Thermal: Add Documentation to new APIs Durgadoss R
2013-02-08  9:21   ` Zhang Rui
2013-02-05 10:46 ` [PATCH 7/8] Thermal: Add ABI Documentation for sysfs interfaces Durgadoss R
2013-02-05 10:46 ` [PATCH 8/8] Thermal: Dummy driver used for testing Durgadoss R
2013-02-08  7:53 ` [PATCHv3 0/8] Thermal Framework Enhancements Zhang Rui
2013-02-08  9:35 ` Zhang Rui
2013-02-28 21:33 ` Eduardo Valentin
2013-03-01  5:12   ` R, Durgadoss
2013-08-29 19:38 ` Eduardo Valentin
2013-08-30  9:20   ` R, Durgadoss
2013-08-30 12:34     ` Eduardo Valentin
2013-08-30 13:21       ` R, Durgadoss

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for NNTP newsgroup(s).