* [PATCH] thermal: use integers rather than strings for thermal values
@ 2008-11-27 17:48 Matthew Garrett
2008-11-27 17:49 ` Matthew Garrett
2009-02-20 15:56 ` [PATCH] thermal: use integers rather than strings for thermal values Len Brown
0 siblings, 2 replies; 19+ messages in thread
From: Matthew Garrett @ 2008-11-27 17:48 UTC (permalink / raw)
To: len; +Cc: linux-acpi, rui.zhang, sujith.thomas
The thermal API currently uses strings to pass values to userspace. This
makes it difficult to use from within the kernel. Change the interface
to use integers and fix up the consumers.
Signed-off-by: Matthew Garrett <mjg@redhat.com>
---
drivers/acpi/fan.c | 20 +++++---
drivers/acpi/processor_thermal.c | 20 +++++----
drivers/acpi/thermal.c | 80 +++++++++++++++++++++------------
drivers/acpi/video.c | 22 +++++----
drivers/misc/intel_menlow.c | 29 ++++--------
drivers/thermal/thermal_sys.c | 91 ++++++++++++++++++++++++++++++++-----
include/linux/thermal.h | 32 ++++++++++---
7 files changed, 198 insertions(+), 96 deletions(-)
diff --git a/drivers/acpi/fan.c b/drivers/acpi/fan.c
index eaaee16..ae41cf3 100644
--- a/drivers/acpi/fan.c
+++ b/drivers/acpi/fan.c
@@ -68,31 +68,35 @@ static struct acpi_driver acpi_fan_driver = {
};
/* thermal cooling device callbacks */
-static int fan_get_max_state(struct thermal_cooling_device *cdev, char *buf)
+static int fan_get_max_state(struct thermal_cooling_device *cdev, unsigned long
+ *state)
{
/* ACPI fan device only support two states: ON/OFF */
- return sprintf(buf, "1\n");
+ *state = 1;
+ return 0;
}
-static int fan_get_cur_state(struct thermal_cooling_device *cdev, char *buf)
+static int fan_get_cur_state(struct thermal_cooling_device *cdev, unsigned long
+ *state)
{
struct acpi_device *device = cdev->devdata;
- int state;
int result;
+ int acpi_state;
if (!device)
return -EINVAL;
- result = acpi_bus_get_power(device->handle, &state);
+ result = acpi_bus_get_power(device->handle, &acpi_state);
if (result)
return result;
- return sprintf(buf, "%s\n", state == ACPI_STATE_D3 ? "0" :
- (state == ACPI_STATE_D0 ? "1" : "unknown"));
+ *state = (acpi_state == ACPI_STATE_D3 ? 0 :
+ (acpi_state == ACPI_STATE_D0 ? 1 : -1));
+ return 0;
}
static int
-fan_set_cur_state(struct thermal_cooling_device *cdev, unsigned int state)
+fan_set_cur_state(struct thermal_cooling_device *cdev, unsigned long state)
{
struct acpi_device *device = cdev->devdata;
int result;
diff --git a/drivers/acpi/processor_thermal.c b/drivers/acpi/processor_thermal.c
index b1eb376..0e47e29 100644
--- a/drivers/acpi/processor_thermal.c
+++ b/drivers/acpi/processor_thermal.c
@@ -373,7 +373,8 @@ static int acpi_processor_max_state(struct acpi_processor *pr)
return max_state;
}
static int
-processor_get_max_state(struct thermal_cooling_device *cdev, char *buf)
+processor_get_max_state(struct thermal_cooling_device *cdev,
+ unsigned long *state)
{
struct acpi_device *device = cdev->devdata;
struct acpi_processor *pr = acpi_driver_data(device);
@@ -381,28 +382,29 @@ processor_get_max_state(struct thermal_cooling_device *cdev, char *buf)
if (!device || !pr)
return -EINVAL;
- return sprintf(buf, "%d\n", acpi_processor_max_state(pr));
+ *state = acpi_processor_max_state(pr);
+ return 0;
}
static int
-processor_get_cur_state(struct thermal_cooling_device *cdev, char *buf)
+processor_get_cur_state(struct thermal_cooling_device *cdev,
+ unsigned long *cur_state)
{
struct acpi_device *device = cdev->devdata;
struct acpi_processor *pr = acpi_driver_data(device);
- int cur_state;
if (!device || !pr)
return -EINVAL;
- cur_state = cpufreq_get_cur_state(pr->id);
+ *cur_state = cpufreq_get_cur_state(pr->id);
if (pr->flags.throttling)
- cur_state += pr->throttling.state;
-
- return sprintf(buf, "%d\n", cur_state);
+ *cur_state += pr->throttling.state;
+ return 0;
}
static int
-processor_set_cur_state(struct thermal_cooling_device *cdev, unsigned int state)
+processor_set_cur_state(struct thermal_cooling_device *cdev,
+ unsigned long state)
{
struct acpi_device *device = cdev->devdata;
struct acpi_processor *pr = acpi_driver_data(device);
diff --git a/drivers/acpi/thermal.c b/drivers/acpi/thermal.c
index 073ff09..f24c7cc 100644
--- a/drivers/acpi/thermal.c
+++ b/drivers/acpi/thermal.c
@@ -946,7 +946,8 @@ static void acpi_thermal_check(void *data)
/* sys I/F for generic thermal sysfs support */
#define KELVIN_TO_MILLICELSIUS(t) (t * 100 - 273200)
-static int thermal_get_temp(struct thermal_zone_device *thermal, char *buf)
+static int thermal_get_temp(struct thermal_zone_device *thermal,
+ unsigned long *temp)
{
struct acpi_thermal *tz = thermal->devdata;
int result;
@@ -958,25 +959,28 @@ static int thermal_get_temp(struct thermal_zone_device *thermal, char *buf)
if (result)
return result;
- return sprintf(buf, "%ld\n", KELVIN_TO_MILLICELSIUS(tz->temperature));
+ *temp = KELVIN_TO_MILLICELSIUS(tz->temperature);
+ return 0;
}
static const char enabled[] = "kernel";
static const char disabled[] = "user";
static int thermal_get_mode(struct thermal_zone_device *thermal,
- char *buf)
+ enum thermal_device_mode *mode)
{
struct acpi_thermal *tz = thermal->devdata;
if (!tz)
return -EINVAL;
- return sprintf(buf, "%s\n", tz->tz_enabled ?
- enabled : disabled);
+ *mode = tz->tz_enabled ? THERMAL_DEVICE_ENABLED :
+ THERMAL_DEVICE_DISABLED;
+
+ return 0;
}
static int thermal_set_mode(struct thermal_zone_device *thermal,
- const char *buf)
+ enum thermal_device_mode mode)
{
struct acpi_thermal *tz = thermal->devdata;
int enable;
@@ -987,9 +991,9 @@ static int thermal_set_mode(struct thermal_zone_device *thermal,
/*
* enable/disable thermal management from ACPI thermal driver
*/
- if (!strncmp(buf, enabled, sizeof enabled - 1))
+ if (mode == THERMAL_DEVICE_ENABLED)
enable = 1;
- else if (!strncmp(buf, disabled, sizeof disabled - 1))
+ else if (mode == THERMAL_DEVICE_DISABLED)
enable = 0;
else
return -EINVAL;
@@ -1005,7 +1009,7 @@ static int thermal_set_mode(struct thermal_zone_device *thermal,
}
static int thermal_get_trip_type(struct thermal_zone_device *thermal,
- int trip, char *buf)
+ int trip, enum thermal_trip_type *type)
{
struct acpi_thermal *tz = thermal->devdata;
int i;
@@ -1014,27 +1018,35 @@ static int thermal_get_trip_type(struct thermal_zone_device *thermal,
return -EINVAL;
if (tz->trips.critical.flags.valid) {
- if (!trip)
- return sprintf(buf, "critical\n");
+ if (!trip) {
+ *type = THERMAL_TRIP_CRITICAL;
+ return 0;
+ }
trip--;
}
if (tz->trips.hot.flags.valid) {
- if (!trip)
- return sprintf(buf, "hot\n");
+ if (!trip) {
+ *type = THERMAL_TRIP_HOT;
+ return 0;
+ }
trip--;
}
if (tz->trips.passive.flags.valid) {
- if (!trip)
- return sprintf(buf, "passive\n");
+ if (!trip) {
+ *type = THERMAL_TRIP_PASSIVE;
+ return 0;
+ }
trip--;
}
for (i = 0; i < ACPI_THERMAL_MAX_ACTIVE &&
tz->trips.active[i].flags.valid; i++) {
- if (!trip)
- return sprintf(buf, "active%d\n", i);
+ if (!trip) {
+ *type = THERMAL_TRIP_ACTIVE;
+ return 0;
+ }
trip--;
}
@@ -1042,7 +1054,7 @@ static int thermal_get_trip_type(struct thermal_zone_device *thermal,
}
static int thermal_get_trip_temp(struct thermal_zone_device *thermal,
- int trip, char *buf)
+ int trip, unsigned long *temp)
{
struct acpi_thermal *tz = thermal->devdata;
int i;
@@ -1051,31 +1063,39 @@ static int thermal_get_trip_temp(struct thermal_zone_device *thermal,
return -EINVAL;
if (tz->trips.critical.flags.valid) {
- if (!trip)
- return sprintf(buf, "%ld\n", KELVIN_TO_MILLICELSIUS(
- tz->trips.critical.temperature));
+ if (!trip) {
+ *temp = KELVIN_TO_MILLICELSIUS(
+ tz->trips.critical.temperature);
+ return 0;
+ }
trip--;
}
if (tz->trips.hot.flags.valid) {
- if (!trip)
- return sprintf(buf, "%ld\n", KELVIN_TO_MILLICELSIUS(
- tz->trips.hot.temperature));
+ if (!trip) {
+ *temp = KELVIN_TO_MILLICELSIUS(
+ tz->trips.hot.temperature);
+ return 0;
+ }
trip--;
}
if (tz->trips.passive.flags.valid) {
- if (!trip)
- return sprintf(buf, "%ld\n", KELVIN_TO_MILLICELSIUS(
- tz->trips.passive.temperature));
+ if (!trip) {
+ *temp = KELVIN_TO_MILLICELSIUS(
+ tz->trips.passive.temperature);
+ return 0;
+ }
trip--;
}
for (i = 0; i < ACPI_THERMAL_MAX_ACTIVE &&
tz->trips.active[i].flags.valid; i++) {
- if (!trip)
- return sprintf(buf, "%ld\n", KELVIN_TO_MILLICELSIUS(
- tz->trips.active[i].temperature));
+ if (!trip) {
+ *temp = KELVIN_TO_MILLICELSIUS(
+ tz->trips.active[i].temperature);
+ return 0;
+ }
trip--;
}
diff --git a/drivers/acpi/video.c b/drivers/acpi/video.c
index baa4419..5b2f1f3 100644
--- a/drivers/acpi/video.c
+++ b/drivers/acpi/video.c
@@ -357,32 +357,36 @@ static struct output_properties acpi_output_properties = {
/* thermal cooling device callbacks */
-static int video_get_max_state(struct thermal_cooling_device *cdev, char *buf)
+static int video_get_max_state(struct thermal_cooling_device *cdev, unsigned
+ long *state)
{
struct acpi_device *device = cdev->devdata;
struct acpi_video_device *video = acpi_driver_data(device);
- return sprintf(buf, "%d\n", video->brightness->count - 3);
+ *state = video->brightness->count - 3;
+ return 0;
}
-static int video_get_cur_state(struct thermal_cooling_device *cdev, char *buf)
+static int video_get_cur_state(struct thermal_cooling_device *cdev, unsigned
+ long *state)
{
struct acpi_device *device = cdev->devdata;
struct acpi_video_device *video = acpi_driver_data(device);
unsigned long long level;
- int state;
+ int offset;
acpi_video_device_lcd_get_level_current(video, &level);
- for (state = 2; state < video->brightness->count; state++)
- if (level == video->brightness->levels[state])
- return sprintf(buf, "%d\n",
- video->brightness->count - state - 1);
+ for (offset = 2; offset < video->brightness->count; offset++)
+ if (level == video->brightness->levels[offset]) {
+ *state = video->brightness->count - offset - 1;
+ return 0;
+ }
return -EINVAL;
}
static int
-video_set_cur_state(struct thermal_cooling_device *cdev, unsigned int state)
+video_set_cur_state(struct thermal_cooling_device *cdev, unsigned long state)
{
struct acpi_device *device = cdev->devdata;
struct acpi_video_device *video = acpi_driver_data(device);
diff --git a/drivers/misc/intel_menlow.c b/drivers/misc/intel_menlow.c
index 27b7662..29432a5 100644
--- a/drivers/misc/intel_menlow.c
+++ b/drivers/misc/intel_menlow.c
@@ -57,8 +57,8 @@ MODULE_LICENSE("GPL");
* In that case max_cstate would be n-1
* GTHS returning '0' would mean that no bandwidth control states are supported
*/
-static int memory_get_int_max_bandwidth(struct thermal_cooling_device *cdev,
- unsigned long *max_state)
+static int memory_get_max_bandwidth(struct thermal_cooling_device *cdev,
+ unsigned long *max_state)
{
struct acpi_device *device = cdev->devdata;
acpi_handle handle = device->handle;
@@ -83,22 +83,12 @@ static int memory_get_int_max_bandwidth(struct thermal_cooling_device *cdev,
return 0;
}
-static int memory_get_max_bandwidth(struct thermal_cooling_device *cdev,
- char *buf)
-{
- unsigned long value;
- if (memory_get_int_max_bandwidth(cdev, &value))
- return -EINVAL;
-
- return sprintf(buf, "%ld\n", value);
-}
-
static int memory_get_cur_bandwidth(struct thermal_cooling_device *cdev,
- char *buf)
+ unsigned long *value)
{
struct acpi_device *device = cdev->devdata;
acpi_handle handle = device->handle;
- unsigned long long value;
+ unsigned long long result;
struct acpi_object_list arg_list;
union acpi_object arg;
acpi_status status = AE_OK;
@@ -108,15 +98,16 @@ static int memory_get_cur_bandwidth(struct thermal_cooling_device *cdev,
arg.type = ACPI_TYPE_INTEGER;
arg.integer.value = MEMORY_ARG_CUR_BANDWIDTH;
status = acpi_evaluate_integer(handle, MEMORY_GET_BANDWIDTH,
- &arg_list, &value);
+ &arg_list, &result);
if (ACPI_FAILURE(status))
return -EFAULT;
- return sprintf(buf, "%llu\n", value);
+ *value = result;
+ return 0;
}
static int memory_set_cur_bandwidth(struct thermal_cooling_device *cdev,
- unsigned int state)
+ unsigned long state)
{
struct acpi_device *device = cdev->devdata;
acpi_handle handle = device->handle;
@@ -126,7 +117,7 @@ static int memory_set_cur_bandwidth(struct thermal_cooling_device *cdev,
unsigned long long temp;
unsigned long max_state;
- if (memory_get_int_max_bandwidth(cdev, &max_state))
+ if (memory_get_max_bandwidth(cdev, &max_state))
return -EFAULT;
if (state > max_state)
@@ -142,7 +133,7 @@ static int memory_set_cur_bandwidth(struct thermal_cooling_device *cdev,
&temp);
printk(KERN_INFO
- "Bandwidth value was %d: status is %d\n", state, status);
+ "Bandwidth value was %ld: status is %d\n", state, status);
if (ACPI_FAILURE(status))
return -EFAULT;
diff --git a/drivers/thermal/thermal_sys.c b/drivers/thermal/thermal_sys.c
index fe07462..7bcf322 100644
--- a/drivers/thermal/thermal_sys.c
+++ b/drivers/thermal/thermal_sys.c
@@ -104,22 +104,36 @@ static ssize_t
temp_show(struct device *dev, struct device_attribute *attr, char *buf)
{
struct thermal_zone_device *tz = to_thermal_zone(dev);
+ long temperature;
+ int ret;
if (!tz->ops->get_temp)
return -EPERM;
- return tz->ops->get_temp(tz, buf);
+ ret = tz->ops->get_temp(tz, &temperature);
+
+ if (ret)
+ return ret;
+
+ return sprintf(buf, "%ld\n", temperature);
}
static ssize_t
mode_show(struct device *dev, struct device_attribute *attr, char *buf)
{
struct thermal_zone_device *tz = to_thermal_zone(dev);
+ enum thermal_device_mode mode;
+ int result;
if (!tz->ops->get_mode)
return -EPERM;
- return tz->ops->get_mode(tz, buf);
+ result = tz->ops->get_mode(tz, &mode);
+ if (result)
+ return result;
+
+ return sprintf(buf, "%s\n", mode == THERMAL_DEVICE_ENABLED ? "enabled"
+ : "disabled");
}
static ssize_t
@@ -132,7 +146,13 @@ mode_store(struct device *dev, struct device_attribute *attr,
if (!tz->ops->set_mode)
return -EPERM;
- result = tz->ops->set_mode(tz, buf);
+ if (!strncmp(buf, "enabled", sizeof("enabled")))
+ result = tz->ops->set_mode(tz, THERMAL_DEVICE_ENABLED);
+ else if (!strncmp(buf, "disabled", sizeof("disabled")))
+ result = tz->ops->set_mode(tz, THERMAL_DEVICE_DISABLED);
+ else
+ result = -EINVAL;
+
if (result)
return result;
@@ -144,7 +164,8 @@ trip_point_type_show(struct device *dev, struct device_attribute *attr,
char *buf)
{
struct thermal_zone_device *tz = to_thermal_zone(dev);
- int trip;
+ enum thermal_trip_type type;
+ int trip, result;
if (!tz->ops->get_trip_type)
return -EPERM;
@@ -152,7 +173,22 @@ trip_point_type_show(struct device *dev, struct device_attribute *attr,
if (!sscanf(attr->attr.name, "trip_point_%d_type", &trip))
return -EINVAL;
- return tz->ops->get_trip_type(tz, trip, buf);
+ result = tz->ops->get_trip_type(tz, trip, &type);
+ if (result)
+ return result;
+
+ switch (type) {
+ case THERMAL_TRIP_CRITICAL:
+ return sprintf(buf, "critical");
+ case THERMAL_TRIP_HOT:
+ return sprintf(buf, "hot");
+ case THERMAL_TRIP_PASSIVE:
+ return sprintf(buf, "passive");
+ case THERMAL_TRIP_ACTIVE:
+ return sprintf(buf, "active");
+ default:
+ return sprintf(buf, "unknown");
+ }
}
static ssize_t
@@ -160,7 +196,8 @@ trip_point_temp_show(struct device *dev, struct device_attribute *attr,
char *buf)
{
struct thermal_zone_device *tz = to_thermal_zone(dev);
- int trip;
+ int trip, ret;
+ long temperature;
if (!tz->ops->get_trip_temp)
return -EPERM;
@@ -168,7 +205,12 @@ trip_point_temp_show(struct device *dev, struct device_attribute *attr,
if (!sscanf(attr->attr.name, "trip_point_%d_temp", &trip))
return -EINVAL;
- return tz->ops->get_trip_temp(tz, trip, buf);
+ ret = tz->ops->get_trip_temp(tz, trip, &temperature);
+
+ if (ret)
+ return ret;
+
+ return sprintf(buf, "%ld\n", temperature);
}
static DEVICE_ATTR(type, 0444, type_show, NULL);
@@ -236,8 +278,13 @@ thermal_cooling_device_max_state_show(struct device *dev,
struct device_attribute *attr, char *buf)
{
struct thermal_cooling_device *cdev = to_cooling_device(dev);
+ unsigned long state;
+ int ret;
- return cdev->ops->get_max_state(cdev, buf);
+ ret = cdev->ops->get_max_state(cdev, &state);
+ if (ret)
+ return ret;
+ return sprintf(buf, "%ld\n", state);
}
static ssize_t
@@ -245,8 +292,13 @@ thermal_cooling_device_cur_state_show(struct device *dev,
struct device_attribute *attr, char *buf)
{
struct thermal_cooling_device *cdev = to_cooling_device(dev);
+ unsigned long state;
+ int ret;
- return cdev->ops->get_cur_state(cdev, buf);
+ ret = cdev->ops->get_cur_state(cdev, &state);
+ if (ret)
+ return ret;
+ return sprintf(buf, "%ld\n", state);
}
static ssize_t
@@ -255,10 +307,10 @@ thermal_cooling_device_cur_state_store(struct device *dev,
const char *buf, size_t count)
{
struct thermal_cooling_device *cdev = to_cooling_device(dev);
- int state;
+ unsigned long state;
int result;
- if (!sscanf(buf, "%d\n", &state))
+ if (!sscanf(buf, "%ld\n", &state))
return -EINVAL;
if (state < 0)
@@ -312,13 +364,20 @@ static DEVICE_ATTR(name, 0444, name_show, NULL);
static ssize_t
temp_input_show(struct device *dev, struct device_attribute *attr, char *buf)
{
+ long temperature;
+ int ret;
struct thermal_hwmon_attr *hwmon_attr
= container_of(attr, struct thermal_hwmon_attr, attr);
struct thermal_zone_device *tz
= container_of(hwmon_attr, struct thermal_zone_device,
temp_input);
- return tz->ops->get_temp(tz, buf);
+ ret = tz->ops->get_temp(tz, &temperature);
+
+ if (ret)
+ return ret;
+
+ return sprintf(buf, "%ld\n", temperature);
}
static ssize_t
@@ -330,8 +389,14 @@ temp_crit_show(struct device *dev, struct device_attribute *attr,
struct thermal_zone_device *tz
= container_of(hwmon_attr, struct thermal_zone_device,
temp_crit);
+ long temperature;
+ int ret;
+
+ ret = tz->ops->get_trip_temp(tz, 0, &temperature);
+ if (ret)
+ return ret;
- return tz->ops->get_trip_temp(tz, 0, buf);
+ return sprintf(buf, "%ld\n", temperature);
}
diff --git a/include/linux/thermal.h b/include/linux/thermal.h
index 917707e..4cb3292 100644
--- a/include/linux/thermal.h
+++ b/include/linux/thermal.h
@@ -31,23 +31,39 @@
struct thermal_zone_device;
struct thermal_cooling_device;
+enum thermal_device_mode {
+ THERMAL_DEVICE_DISABLED = 0,
+ THERMAL_DEVICE_ENABLED,
+};
+
+enum thermal_trip_type {
+ THERMAL_TRIP_ACTIVE = 0,
+ THERMAL_TRIP_PASSIVE,
+ THERMAL_TRIP_HOT,
+ THERMAL_TRIP_CRITICAL,
+};
+
struct thermal_zone_device_ops {
int (*bind) (struct thermal_zone_device *,
struct thermal_cooling_device *);
int (*unbind) (struct thermal_zone_device *,
struct thermal_cooling_device *);
- int (*get_temp) (struct thermal_zone_device *, char *);
- int (*get_mode) (struct thermal_zone_device *, char *);
- int (*set_mode) (struct thermal_zone_device *, const char *);
- int (*get_trip_type) (struct thermal_zone_device *, int, char *);
- int (*get_trip_temp) (struct thermal_zone_device *, int, char *);
+ int (*get_temp) (struct thermal_zone_device *, unsigned long *);
+ int (*get_mode) (struct thermal_zone_device *,
+ enum thermal_device_mode *);
+ int (*set_mode) (struct thermal_zone_device *,
+ enum thermal_device_mode);
+ int (*get_trip_type) (struct thermal_zone_device *, int,
+ enum thermal_trip_type *);
+ int (*get_trip_temp) (struct thermal_zone_device *, int,
+ unsigned long *);
int (*get_crit_temp) (struct thermal_zone_device *, unsigned long *);
};
struct thermal_cooling_device_ops {
- int (*get_max_state) (struct thermal_cooling_device *, char *);
- int (*get_cur_state) (struct thermal_cooling_device *, char *);
- int (*set_cur_state) (struct thermal_cooling_device *, unsigned int);
+ int (*get_max_state) (struct thermal_cooling_device *, unsigned long *);
+ int (*get_cur_state) (struct thermal_cooling_device *, unsigned long *);
+ int (*set_cur_state) (struct thermal_cooling_device *, unsigned long);
};
#define THERMAL_TRIPS_NONE -1
--
Matthew Garrett | mjg59@srcf.ucam.org
^ permalink raw reply related [flat|nested] 19+ messages in thread
* [PATCH] thermal: use integers rather than strings for thermal values
2008-11-27 17:48 [PATCH] thermal: use integers rather than strings for thermal values Matthew Garrett
@ 2008-11-27 17:49 ` Matthew Garrett
2008-11-28 2:52 ` Zhang Rui
2008-12-03 17:55 ` [PATCH] acpi: move thermal trip handling to generic thermal layer Matthew Garrett
2009-02-20 15:56 ` [PATCH] thermal: use integers rather than strings for thermal values Len Brown
1 sibling, 2 replies; 19+ messages in thread
From: Matthew Garrett @ 2008-11-27 17:49 UTC (permalink / raw)
To: lenb; +Cc: linux-acpi, rui.zhang, sujith.thomas
The thermal API currently uses strings to pass values to userspace. This makes
it difficult to use from within the kernel. Change the interface to use
integers and fix up the ACPI consumers.
Signed-off-by: Matthew Garrett <mjg@redhat.com>
---
Resend - managed to get Len's address wrong the first time.
drivers/acpi/fan.c | 20 +++++---
drivers/acpi/processor_thermal.c | 20 +++++----
drivers/acpi/thermal.c | 80 +++++++++++++++++++++------------
drivers/acpi/video.c | 22 +++++----
drivers/misc/intel_menlow.c | 29 ++++--------
drivers/thermal/thermal_sys.c | 91 ++++++++++++++++++++++++++++++++-----
include/linux/thermal.h | 32 ++++++++++---
7 files changed, 198 insertions(+), 96 deletions(-)
diff --git a/drivers/acpi/fan.c b/drivers/acpi/fan.c
index eaaee16..ae41cf3 100644
--- a/drivers/acpi/fan.c
+++ b/drivers/acpi/fan.c
@@ -68,31 +68,35 @@ static struct acpi_driver acpi_fan_driver = {
};
/* thermal cooling device callbacks */
-static int fan_get_max_state(struct thermal_cooling_device *cdev, char *buf)
+static int fan_get_max_state(struct thermal_cooling_device *cdev, unsigned long
+ *state)
{
/* ACPI fan device only support two states: ON/OFF */
- return sprintf(buf, "1\n");
+ *state = 1;
+ return 0;
}
-static int fan_get_cur_state(struct thermal_cooling_device *cdev, char *buf)
+static int fan_get_cur_state(struct thermal_cooling_device *cdev, unsigned long
+ *state)
{
struct acpi_device *device = cdev->devdata;
- int state;
int result;
+ int acpi_state;
if (!device)
return -EINVAL;
- result = acpi_bus_get_power(device->handle, &state);
+ result = acpi_bus_get_power(device->handle, &acpi_state);
if (result)
return result;
- return sprintf(buf, "%s\n", state == ACPI_STATE_D3 ? "0" :
- (state == ACPI_STATE_D0 ? "1" : "unknown"));
+ *state = (acpi_state == ACPI_STATE_D3 ? 0 :
+ (acpi_state == ACPI_STATE_D0 ? 1 : -1));
+ return 0;
}
static int
-fan_set_cur_state(struct thermal_cooling_device *cdev, unsigned int state)
+fan_set_cur_state(struct thermal_cooling_device *cdev, unsigned long state)
{
struct acpi_device *device = cdev->devdata;
int result;
diff --git a/drivers/acpi/processor_thermal.c b/drivers/acpi/processor_thermal.c
index b1eb376..0e47e29 100644
--- a/drivers/acpi/processor_thermal.c
+++ b/drivers/acpi/processor_thermal.c
@@ -373,7 +373,8 @@ static int acpi_processor_max_state(struct acpi_processor *pr)
return max_state;
}
static int
-processor_get_max_state(struct thermal_cooling_device *cdev, char *buf)
+processor_get_max_state(struct thermal_cooling_device *cdev,
+ unsigned long *state)
{
struct acpi_device *device = cdev->devdata;
struct acpi_processor *pr = acpi_driver_data(device);
@@ -381,28 +382,29 @@ processor_get_max_state(struct thermal_cooling_device *cdev, char *buf)
if (!device || !pr)
return -EINVAL;
- return sprintf(buf, "%d\n", acpi_processor_max_state(pr));
+ *state = acpi_processor_max_state(pr);
+ return 0;
}
static int
-processor_get_cur_state(struct thermal_cooling_device *cdev, char *buf)
+processor_get_cur_state(struct thermal_cooling_device *cdev,
+ unsigned long *cur_state)
{
struct acpi_device *device = cdev->devdata;
struct acpi_processor *pr = acpi_driver_data(device);
- int cur_state;
if (!device || !pr)
return -EINVAL;
- cur_state = cpufreq_get_cur_state(pr->id);
+ *cur_state = cpufreq_get_cur_state(pr->id);
if (pr->flags.throttling)
- cur_state += pr->throttling.state;
-
- return sprintf(buf, "%d\n", cur_state);
+ *cur_state += pr->throttling.state;
+ return 0;
}
static int
-processor_set_cur_state(struct thermal_cooling_device *cdev, unsigned int state)
+processor_set_cur_state(struct thermal_cooling_device *cdev,
+ unsigned long state)
{
struct acpi_device *device = cdev->devdata;
struct acpi_processor *pr = acpi_driver_data(device);
diff --git a/drivers/acpi/thermal.c b/drivers/acpi/thermal.c
index 073ff09..f24c7cc 100644
--- a/drivers/acpi/thermal.c
+++ b/drivers/acpi/thermal.c
@@ -946,7 +946,8 @@ static void acpi_thermal_check(void *data)
/* sys I/F for generic thermal sysfs support */
#define KELVIN_TO_MILLICELSIUS(t) (t * 100 - 273200)
-static int thermal_get_temp(struct thermal_zone_device *thermal, char *buf)
+static int thermal_get_temp(struct thermal_zone_device *thermal,
+ unsigned long *temp)
{
struct acpi_thermal *tz = thermal->devdata;
int result;
@@ -958,25 +959,28 @@ static int thermal_get_temp(struct thermal_zone_device *thermal, char *buf)
if (result)
return result;
- return sprintf(buf, "%ld\n", KELVIN_TO_MILLICELSIUS(tz->temperature));
+ *temp = KELVIN_TO_MILLICELSIUS(tz->temperature);
+ return 0;
}
static const char enabled[] = "kernel";
static const char disabled[] = "user";
static int thermal_get_mode(struct thermal_zone_device *thermal,
- char *buf)
+ enum thermal_device_mode *mode)
{
struct acpi_thermal *tz = thermal->devdata;
if (!tz)
return -EINVAL;
- return sprintf(buf, "%s\n", tz->tz_enabled ?
- enabled : disabled);
+ *mode = tz->tz_enabled ? THERMAL_DEVICE_ENABLED :
+ THERMAL_DEVICE_DISABLED;
+
+ return 0;
}
static int thermal_set_mode(struct thermal_zone_device *thermal,
- const char *buf)
+ enum thermal_device_mode mode)
{
struct acpi_thermal *tz = thermal->devdata;
int enable;
@@ -987,9 +991,9 @@ static int thermal_set_mode(struct thermal_zone_device *thermal,
/*
* enable/disable thermal management from ACPI thermal driver
*/
- if (!strncmp(buf, enabled, sizeof enabled - 1))
+ if (mode == THERMAL_DEVICE_ENABLED)
enable = 1;
- else if (!strncmp(buf, disabled, sizeof disabled - 1))
+ else if (mode == THERMAL_DEVICE_DISABLED)
enable = 0;
else
return -EINVAL;
@@ -1005,7 +1009,7 @@ static int thermal_set_mode(struct thermal_zone_device *thermal,
}
static int thermal_get_trip_type(struct thermal_zone_device *thermal,
- int trip, char *buf)
+ int trip, enum thermal_trip_type *type)
{
struct acpi_thermal *tz = thermal->devdata;
int i;
@@ -1014,27 +1018,35 @@ static int thermal_get_trip_type(struct thermal_zone_device *thermal,
return -EINVAL;
if (tz->trips.critical.flags.valid) {
- if (!trip)
- return sprintf(buf, "critical\n");
+ if (!trip) {
+ *type = THERMAL_TRIP_CRITICAL;
+ return 0;
+ }
trip--;
}
if (tz->trips.hot.flags.valid) {
- if (!trip)
- return sprintf(buf, "hot\n");
+ if (!trip) {
+ *type = THERMAL_TRIP_HOT;
+ return 0;
+ }
trip--;
}
if (tz->trips.passive.flags.valid) {
- if (!trip)
- return sprintf(buf, "passive\n");
+ if (!trip) {
+ *type = THERMAL_TRIP_PASSIVE;
+ return 0;
+ }
trip--;
}
for (i = 0; i < ACPI_THERMAL_MAX_ACTIVE &&
tz->trips.active[i].flags.valid; i++) {
- if (!trip)
- return sprintf(buf, "active%d\n", i);
+ if (!trip) {
+ *type = THERMAL_TRIP_ACTIVE;
+ return 0;
+ }
trip--;
}
@@ -1042,7 +1054,7 @@ static int thermal_get_trip_type(struct thermal_zone_device *thermal,
}
static int thermal_get_trip_temp(struct thermal_zone_device *thermal,
- int trip, char *buf)
+ int trip, unsigned long *temp)
{
struct acpi_thermal *tz = thermal->devdata;
int i;
@@ -1051,31 +1063,39 @@ static int thermal_get_trip_temp(struct thermal_zone_device *thermal,
return -EINVAL;
if (tz->trips.critical.flags.valid) {
- if (!trip)
- return sprintf(buf, "%ld\n", KELVIN_TO_MILLICELSIUS(
- tz->trips.critical.temperature));
+ if (!trip) {
+ *temp = KELVIN_TO_MILLICELSIUS(
+ tz->trips.critical.temperature);
+ return 0;
+ }
trip--;
}
if (tz->trips.hot.flags.valid) {
- if (!trip)
- return sprintf(buf, "%ld\n", KELVIN_TO_MILLICELSIUS(
- tz->trips.hot.temperature));
+ if (!trip) {
+ *temp = KELVIN_TO_MILLICELSIUS(
+ tz->trips.hot.temperature);
+ return 0;
+ }
trip--;
}
if (tz->trips.passive.flags.valid) {
- if (!trip)
- return sprintf(buf, "%ld\n", KELVIN_TO_MILLICELSIUS(
- tz->trips.passive.temperature));
+ if (!trip) {
+ *temp = KELVIN_TO_MILLICELSIUS(
+ tz->trips.passive.temperature);
+ return 0;
+ }
trip--;
}
for (i = 0; i < ACPI_THERMAL_MAX_ACTIVE &&
tz->trips.active[i].flags.valid; i++) {
- if (!trip)
- return sprintf(buf, "%ld\n", KELVIN_TO_MILLICELSIUS(
- tz->trips.active[i].temperature));
+ if (!trip) {
+ *temp = KELVIN_TO_MILLICELSIUS(
+ tz->trips.active[i].temperature);
+ return 0;
+ }
trip--;
}
diff --git a/drivers/acpi/video.c b/drivers/acpi/video.c
index baa4419..5b2f1f3 100644
--- a/drivers/acpi/video.c
+++ b/drivers/acpi/video.c
@@ -357,32 +357,36 @@ static struct output_properties acpi_output_properties = {
/* thermal cooling device callbacks */
-static int video_get_max_state(struct thermal_cooling_device *cdev, char *buf)
+static int video_get_max_state(struct thermal_cooling_device *cdev, unsigned
+ long *state)
{
struct acpi_device *device = cdev->devdata;
struct acpi_video_device *video = acpi_driver_data(device);
- return sprintf(buf, "%d\n", video->brightness->count - 3);
+ *state = video->brightness->count - 3;
+ return 0;
}
-static int video_get_cur_state(struct thermal_cooling_device *cdev, char *buf)
+static int video_get_cur_state(struct thermal_cooling_device *cdev, unsigned
+ long *state)
{
struct acpi_device *device = cdev->devdata;
struct acpi_video_device *video = acpi_driver_data(device);
unsigned long long level;
- int state;
+ int offset;
acpi_video_device_lcd_get_level_current(video, &level);
- for (state = 2; state < video->brightness->count; state++)
- if (level == video->brightness->levels[state])
- return sprintf(buf, "%d\n",
- video->brightness->count - state - 1);
+ for (offset = 2; offset < video->brightness->count; offset++)
+ if (level == video->brightness->levels[offset]) {
+ *state = video->brightness->count - offset - 1;
+ return 0;
+ }
return -EINVAL;
}
static int
-video_set_cur_state(struct thermal_cooling_device *cdev, unsigned int state)
+video_set_cur_state(struct thermal_cooling_device *cdev, unsigned long state)
{
struct acpi_device *device = cdev->devdata;
struct acpi_video_device *video = acpi_driver_data(device);
diff --git a/drivers/misc/intel_menlow.c b/drivers/misc/intel_menlow.c
index 27b7662..29432a5 100644
--- a/drivers/misc/intel_menlow.c
+++ b/drivers/misc/intel_menlow.c
@@ -57,8 +57,8 @@ MODULE_LICENSE("GPL");
* In that case max_cstate would be n-1
* GTHS returning '0' would mean that no bandwidth control states are supported
*/
-static int memory_get_int_max_bandwidth(struct thermal_cooling_device *cdev,
- unsigned long *max_state)
+static int memory_get_max_bandwidth(struct thermal_cooling_device *cdev,
+ unsigned long *max_state)
{
struct acpi_device *device = cdev->devdata;
acpi_handle handle = device->handle;
@@ -83,22 +83,12 @@ static int memory_get_int_max_bandwidth(struct thermal_cooling_device *cdev,
return 0;
}
-static int memory_get_max_bandwidth(struct thermal_cooling_device *cdev,
- char *buf)
-{
- unsigned long value;
- if (memory_get_int_max_bandwidth(cdev, &value))
- return -EINVAL;
-
- return sprintf(buf, "%ld\n", value);
-}
-
static int memory_get_cur_bandwidth(struct thermal_cooling_device *cdev,
- char *buf)
+ unsigned long *value)
{
struct acpi_device *device = cdev->devdata;
acpi_handle handle = device->handle;
- unsigned long long value;
+ unsigned long long result;
struct acpi_object_list arg_list;
union acpi_object arg;
acpi_status status = AE_OK;
@@ -108,15 +98,16 @@ static int memory_get_cur_bandwidth(struct thermal_cooling_device *cdev,
arg.type = ACPI_TYPE_INTEGER;
arg.integer.value = MEMORY_ARG_CUR_BANDWIDTH;
status = acpi_evaluate_integer(handle, MEMORY_GET_BANDWIDTH,
- &arg_list, &value);
+ &arg_list, &result);
if (ACPI_FAILURE(status))
return -EFAULT;
- return sprintf(buf, "%llu\n", value);
+ *value = result;
+ return 0;
}
static int memory_set_cur_bandwidth(struct thermal_cooling_device *cdev,
- unsigned int state)
+ unsigned long state)
{
struct acpi_device *device = cdev->devdata;
acpi_handle handle = device->handle;
@@ -126,7 +117,7 @@ static int memory_set_cur_bandwidth(struct thermal_cooling_device *cdev,
unsigned long long temp;
unsigned long max_state;
- if (memory_get_int_max_bandwidth(cdev, &max_state))
+ if (memory_get_max_bandwidth(cdev, &max_state))
return -EFAULT;
if (state > max_state)
@@ -142,7 +133,7 @@ static int memory_set_cur_bandwidth(struct thermal_cooling_device *cdev,
&temp);
printk(KERN_INFO
- "Bandwidth value was %d: status is %d\n", state, status);
+ "Bandwidth value was %ld: status is %d\n", state, status);
if (ACPI_FAILURE(status))
return -EFAULT;
diff --git a/drivers/thermal/thermal_sys.c b/drivers/thermal/thermal_sys.c
index fe07462..7bcf322 100644
--- a/drivers/thermal/thermal_sys.c
+++ b/drivers/thermal/thermal_sys.c
@@ -104,22 +104,36 @@ static ssize_t
temp_show(struct device *dev, struct device_attribute *attr, char *buf)
{
struct thermal_zone_device *tz = to_thermal_zone(dev);
+ long temperature;
+ int ret;
if (!tz->ops->get_temp)
return -EPERM;
- return tz->ops->get_temp(tz, buf);
+ ret = tz->ops->get_temp(tz, &temperature);
+
+ if (ret)
+ return ret;
+
+ return sprintf(buf, "%ld\n", temperature);
}
static ssize_t
mode_show(struct device *dev, struct device_attribute *attr, char *buf)
{
struct thermal_zone_device *tz = to_thermal_zone(dev);
+ enum thermal_device_mode mode;
+ int result;
if (!tz->ops->get_mode)
return -EPERM;
- return tz->ops->get_mode(tz, buf);
+ result = tz->ops->get_mode(tz, &mode);
+ if (result)
+ return result;
+
+ return sprintf(buf, "%s\n", mode == THERMAL_DEVICE_ENABLED ? "enabled"
+ : "disabled");
}
static ssize_t
@@ -132,7 +146,13 @@ mode_store(struct device *dev, struct device_attribute *attr,
if (!tz->ops->set_mode)
return -EPERM;
- result = tz->ops->set_mode(tz, buf);
+ if (!strncmp(buf, "enabled", sizeof("enabled")))
+ result = tz->ops->set_mode(tz, THERMAL_DEVICE_ENABLED);
+ else if (!strncmp(buf, "disabled", sizeof("disabled")))
+ result = tz->ops->set_mode(tz, THERMAL_DEVICE_DISABLED);
+ else
+ result = -EINVAL;
+
if (result)
return result;
@@ -144,7 +164,8 @@ trip_point_type_show(struct device *dev, struct device_attribute *attr,
char *buf)
{
struct thermal_zone_device *tz = to_thermal_zone(dev);
- int trip;
+ enum thermal_trip_type type;
+ int trip, result;
if (!tz->ops->get_trip_type)
return -EPERM;
@@ -152,7 +173,22 @@ trip_point_type_show(struct device *dev, struct device_attribute *attr,
if (!sscanf(attr->attr.name, "trip_point_%d_type", &trip))
return -EINVAL;
- return tz->ops->get_trip_type(tz, trip, buf);
+ result = tz->ops->get_trip_type(tz, trip, &type);
+ if (result)
+ return result;
+
+ switch (type) {
+ case THERMAL_TRIP_CRITICAL:
+ return sprintf(buf, "critical");
+ case THERMAL_TRIP_HOT:
+ return sprintf(buf, "hot");
+ case THERMAL_TRIP_PASSIVE:
+ return sprintf(buf, "passive");
+ case THERMAL_TRIP_ACTIVE:
+ return sprintf(buf, "active");
+ default:
+ return sprintf(buf, "unknown");
+ }
}
static ssize_t
@@ -160,7 +196,8 @@ trip_point_temp_show(struct device *dev, struct device_attribute *attr,
char *buf)
{
struct thermal_zone_device *tz = to_thermal_zone(dev);
- int trip;
+ int trip, ret;
+ long temperature;
if (!tz->ops->get_trip_temp)
return -EPERM;
@@ -168,7 +205,12 @@ trip_point_temp_show(struct device *dev, struct device_attribute *attr,
if (!sscanf(attr->attr.name, "trip_point_%d_temp", &trip))
return -EINVAL;
- return tz->ops->get_trip_temp(tz, trip, buf);
+ ret = tz->ops->get_trip_temp(tz, trip, &temperature);
+
+ if (ret)
+ return ret;
+
+ return sprintf(buf, "%ld\n", temperature);
}
static DEVICE_ATTR(type, 0444, type_show, NULL);
@@ -236,8 +278,13 @@ thermal_cooling_device_max_state_show(struct device *dev,
struct device_attribute *attr, char *buf)
{
struct thermal_cooling_device *cdev = to_cooling_device(dev);
+ unsigned long state;
+ int ret;
- return cdev->ops->get_max_state(cdev, buf);
+ ret = cdev->ops->get_max_state(cdev, &state);
+ if (ret)
+ return ret;
+ return sprintf(buf, "%ld\n", state);
}
static ssize_t
@@ -245,8 +292,13 @@ thermal_cooling_device_cur_state_show(struct device *dev,
struct device_attribute *attr, char *buf)
{
struct thermal_cooling_device *cdev = to_cooling_device(dev);
+ unsigned long state;
+ int ret;
- return cdev->ops->get_cur_state(cdev, buf);
+ ret = cdev->ops->get_cur_state(cdev, &state);
+ if (ret)
+ return ret;
+ return sprintf(buf, "%ld\n", state);
}
static ssize_t
@@ -255,10 +307,10 @@ thermal_cooling_device_cur_state_store(struct device *dev,
const char *buf, size_t count)
{
struct thermal_cooling_device *cdev = to_cooling_device(dev);
- int state;
+ unsigned long state;
int result;
- if (!sscanf(buf, "%d\n", &state))
+ if (!sscanf(buf, "%ld\n", &state))
return -EINVAL;
if (state < 0)
@@ -312,13 +364,20 @@ static DEVICE_ATTR(name, 0444, name_show, NULL);
static ssize_t
temp_input_show(struct device *dev, struct device_attribute *attr, char *buf)
{
+ long temperature;
+ int ret;
struct thermal_hwmon_attr *hwmon_attr
= container_of(attr, struct thermal_hwmon_attr, attr);
struct thermal_zone_device *tz
= container_of(hwmon_attr, struct thermal_zone_device,
temp_input);
- return tz->ops->get_temp(tz, buf);
+ ret = tz->ops->get_temp(tz, &temperature);
+
+ if (ret)
+ return ret;
+
+ return sprintf(buf, "%ld\n", temperature);
}
static ssize_t
@@ -330,8 +389,14 @@ temp_crit_show(struct device *dev, struct device_attribute *attr,
struct thermal_zone_device *tz
= container_of(hwmon_attr, struct thermal_zone_device,
temp_crit);
+ long temperature;
+ int ret;
+
+ ret = tz->ops->get_trip_temp(tz, 0, &temperature);
+ if (ret)
+ return ret;
- return tz->ops->get_trip_temp(tz, 0, buf);
+ return sprintf(buf, "%ld\n", temperature);
}
diff --git a/include/linux/thermal.h b/include/linux/thermal.h
index 917707e..4cb3292 100644
--- a/include/linux/thermal.h
+++ b/include/linux/thermal.h
@@ -31,23 +31,39 @@
struct thermal_zone_device;
struct thermal_cooling_device;
+enum thermal_device_mode {
+ THERMAL_DEVICE_DISABLED = 0,
+ THERMAL_DEVICE_ENABLED,
+};
+
+enum thermal_trip_type {
+ THERMAL_TRIP_ACTIVE = 0,
+ THERMAL_TRIP_PASSIVE,
+ THERMAL_TRIP_HOT,
+ THERMAL_TRIP_CRITICAL,
+};
+
struct thermal_zone_device_ops {
int (*bind) (struct thermal_zone_device *,
struct thermal_cooling_device *);
int (*unbind) (struct thermal_zone_device *,
struct thermal_cooling_device *);
- int (*get_temp) (struct thermal_zone_device *, char *);
- int (*get_mode) (struct thermal_zone_device *, char *);
- int (*set_mode) (struct thermal_zone_device *, const char *);
- int (*get_trip_type) (struct thermal_zone_device *, int, char *);
- int (*get_trip_temp) (struct thermal_zone_device *, int, char *);
+ int (*get_temp) (struct thermal_zone_device *, unsigned long *);
+ int (*get_mode) (struct thermal_zone_device *,
+ enum thermal_device_mode *);
+ int (*set_mode) (struct thermal_zone_device *,
+ enum thermal_device_mode);
+ int (*get_trip_type) (struct thermal_zone_device *, int,
+ enum thermal_trip_type *);
+ int (*get_trip_temp) (struct thermal_zone_device *, int,
+ unsigned long *);
int (*get_crit_temp) (struct thermal_zone_device *, unsigned long *);
};
struct thermal_cooling_device_ops {
- int (*get_max_state) (struct thermal_cooling_device *, char *);
- int (*get_cur_state) (struct thermal_cooling_device *, char *);
- int (*set_cur_state) (struct thermal_cooling_device *, unsigned int);
+ int (*get_max_state) (struct thermal_cooling_device *, unsigned long *);
+ int (*get_cur_state) (struct thermal_cooling_device *, unsigned long *);
+ int (*set_cur_state) (struct thermal_cooling_device *, unsigned long);
};
#define THERMAL_TRIPS_NONE -1
--
Matthew Garrett | mjg59@srcf.ucam.org
^ permalink raw reply related [flat|nested] 19+ messages in thread
* Re: [PATCH] thermal: use integers rather than strings for thermal values
2008-11-27 17:49 ` Matthew Garrett
@ 2008-11-28 2:52 ` Zhang Rui
2009-01-16 13:44 ` Thomas Renninger
2008-12-03 17:55 ` [PATCH] acpi: move thermal trip handling to generic thermal layer Matthew Garrett
1 sibling, 1 reply; 19+ messages in thread
From: Zhang Rui @ 2008-11-28 2:52 UTC (permalink / raw)
To: Matthew Garrett
Cc: lenb@kernel.org, linux-acpi@vger.kernel.org, Thomas, Sujith
On Fri, 2008-11-28 at 01:49 +0800, Matthew Garrett wrote:
> The thermal API currently uses strings to pass values to userspace. This makes
> it difficult to use from within the kernel. Change the interface to use
> integers and fix up the ACPI consumers.
>
> Signed-off-by: Matthew Garrett <mjg@redhat.com>
Signed-off-by: Zhang Rui <rui.zhang@intel.com>
> ---
>
> Resend - managed to get Len's address wrong the first time.
>
> drivers/acpi/fan.c | 20 +++++---
> drivers/acpi/processor_thermal.c | 20 +++++----
> drivers/acpi/thermal.c | 80 +++++++++++++++++++++------------
> drivers/acpi/video.c | 22 +++++----
> drivers/misc/intel_menlow.c | 29 ++++--------
> drivers/thermal/thermal_sys.c | 91 ++++++++++++++++++++++++++++++++-----
> include/linux/thermal.h | 32 ++++++++++---
> 7 files changed, 198 insertions(+), 96 deletions(-)
>
> diff --git a/drivers/acpi/fan.c b/drivers/acpi/fan.c
> index eaaee16..ae41cf3 100644
> --- a/drivers/acpi/fan.c
> +++ b/drivers/acpi/fan.c
> @@ -68,31 +68,35 @@ static struct acpi_driver acpi_fan_driver = {
> };
>
> /* thermal cooling device callbacks */
> -static int fan_get_max_state(struct thermal_cooling_device *cdev, char *buf)
> +static int fan_get_max_state(struct thermal_cooling_device *cdev, unsigned long
> + *state)
> {
> /* ACPI fan device only support two states: ON/OFF */
> - return sprintf(buf, "1\n");
> + *state = 1;
> + return 0;
> }
>
> -static int fan_get_cur_state(struct thermal_cooling_device *cdev, char *buf)
> +static int fan_get_cur_state(struct thermal_cooling_device *cdev, unsigned long
> + *state)
> {
> struct acpi_device *device = cdev->devdata;
> - int state;
> int result;
> + int acpi_state;
>
> if (!device)
> return -EINVAL;
>
> - result = acpi_bus_get_power(device->handle, &state);
> + result = acpi_bus_get_power(device->handle, &acpi_state);
> if (result)
> return result;
>
> - return sprintf(buf, "%s\n", state == ACPI_STATE_D3 ? "0" :
> - (state == ACPI_STATE_D0 ? "1" : "unknown"));
> + *state = (acpi_state == ACPI_STATE_D3 ? 0 :
> + (acpi_state == ACPI_STATE_D0 ? 1 : -1));
> + return 0;
> }
>
> static int
> -fan_set_cur_state(struct thermal_cooling_device *cdev, unsigned int state)
> +fan_set_cur_state(struct thermal_cooling_device *cdev, unsigned long state)
> {
> struct acpi_device *device = cdev->devdata;
> int result;
> diff --git a/drivers/acpi/processor_thermal.c b/drivers/acpi/processor_thermal.c
> index b1eb376..0e47e29 100644
> --- a/drivers/acpi/processor_thermal.c
> +++ b/drivers/acpi/processor_thermal.c
> @@ -373,7 +373,8 @@ static int acpi_processor_max_state(struct acpi_processor *pr)
> return max_state;
> }
> static int
> -processor_get_max_state(struct thermal_cooling_device *cdev, char *buf)
> +processor_get_max_state(struct thermal_cooling_device *cdev,
> + unsigned long *state)
> {
> struct acpi_device *device = cdev->devdata;
> struct acpi_processor *pr = acpi_driver_data(device);
> @@ -381,28 +382,29 @@ processor_get_max_state(struct thermal_cooling_device *cdev, char *buf)
> if (!device || !pr)
> return -EINVAL;
>
> - return sprintf(buf, "%d\n", acpi_processor_max_state(pr));
> + *state = acpi_processor_max_state(pr);
> + return 0;
> }
>
> static int
> -processor_get_cur_state(struct thermal_cooling_device *cdev, char *buf)
> +processor_get_cur_state(struct thermal_cooling_device *cdev,
> + unsigned long *cur_state)
> {
> struct acpi_device *device = cdev->devdata;
> struct acpi_processor *pr = acpi_driver_data(device);
> - int cur_state;
>
> if (!device || !pr)
> return -EINVAL;
>
> - cur_state = cpufreq_get_cur_state(pr->id);
> + *cur_state = cpufreq_get_cur_state(pr->id);
> if (pr->flags.throttling)
> - cur_state += pr->throttling.state;
> -
> - return sprintf(buf, "%d\n", cur_state);
> + *cur_state += pr->throttling.state;
> + return 0;
> }
>
> static int
> -processor_set_cur_state(struct thermal_cooling_device *cdev, unsigned int state)
> +processor_set_cur_state(struct thermal_cooling_device *cdev,
> + unsigned long state)
> {
> struct acpi_device *device = cdev->devdata;
> struct acpi_processor *pr = acpi_driver_data(device);
> diff --git a/drivers/acpi/thermal.c b/drivers/acpi/thermal.c
> index 073ff09..f24c7cc 100644
> --- a/drivers/acpi/thermal.c
> +++ b/drivers/acpi/thermal.c
> @@ -946,7 +946,8 @@ static void acpi_thermal_check(void *data)
> /* sys I/F for generic thermal sysfs support */
> #define KELVIN_TO_MILLICELSIUS(t) (t * 100 - 273200)
>
> -static int thermal_get_temp(struct thermal_zone_device *thermal, char *buf)
> +static int thermal_get_temp(struct thermal_zone_device *thermal,
> + unsigned long *temp)
> {
> struct acpi_thermal *tz = thermal->devdata;
> int result;
> @@ -958,25 +959,28 @@ static int thermal_get_temp(struct thermal_zone_device *thermal, char *buf)
> if (result)
> return result;
>
> - return sprintf(buf, "%ld\n", KELVIN_TO_MILLICELSIUS(tz->temperature));
> + *temp = KELVIN_TO_MILLICELSIUS(tz->temperature);
> + return 0;
> }
>
> static const char enabled[] = "kernel";
> static const char disabled[] = "user";
> static int thermal_get_mode(struct thermal_zone_device *thermal,
> - char *buf)
> + enum thermal_device_mode *mode)
> {
> struct acpi_thermal *tz = thermal->devdata;
>
> if (!tz)
> return -EINVAL;
>
> - return sprintf(buf, "%s\n", tz->tz_enabled ?
> - enabled : disabled);
> + *mode = tz->tz_enabled ? THERMAL_DEVICE_ENABLED :
> + THERMAL_DEVICE_DISABLED;
> +
> + return 0;
> }
>
> static int thermal_set_mode(struct thermal_zone_device *thermal,
> - const char *buf)
> + enum thermal_device_mode mode)
> {
> struct acpi_thermal *tz = thermal->devdata;
> int enable;
> @@ -987,9 +991,9 @@ static int thermal_set_mode(struct thermal_zone_device *thermal,
> /*
> * enable/disable thermal management from ACPI thermal driver
> */
> - if (!strncmp(buf, enabled, sizeof enabled - 1))
> + if (mode == THERMAL_DEVICE_ENABLED)
> enable = 1;
> - else if (!strncmp(buf, disabled, sizeof disabled - 1))
> + else if (mode == THERMAL_DEVICE_DISABLED)
> enable = 0;
> else
> return -EINVAL;
> @@ -1005,7 +1009,7 @@ static int thermal_set_mode(struct thermal_zone_device *thermal,
> }
>
> static int thermal_get_trip_type(struct thermal_zone_device *thermal,
> - int trip, char *buf)
> + int trip, enum thermal_trip_type *type)
> {
> struct acpi_thermal *tz = thermal->devdata;
> int i;
> @@ -1014,27 +1018,35 @@ static int thermal_get_trip_type(struct thermal_zone_device *thermal,
> return -EINVAL;
>
> if (tz->trips.critical.flags.valid) {
> - if (!trip)
> - return sprintf(buf, "critical\n");
> + if (!trip) {
> + *type = THERMAL_TRIP_CRITICAL;
> + return 0;
> + }
> trip--;
> }
>
> if (tz->trips.hot.flags.valid) {
> - if (!trip)
> - return sprintf(buf, "hot\n");
> + if (!trip) {
> + *type = THERMAL_TRIP_HOT;
> + return 0;
> + }
> trip--;
> }
>
> if (tz->trips.passive.flags.valid) {
> - if (!trip)
> - return sprintf(buf, "passive\n");
> + if (!trip) {
> + *type = THERMAL_TRIP_PASSIVE;
> + return 0;
> + }
> trip--;
> }
>
> for (i = 0; i < ACPI_THERMAL_MAX_ACTIVE &&
> tz->trips.active[i].flags.valid; i++) {
> - if (!trip)
> - return sprintf(buf, "active%d\n", i);
> + if (!trip) {
> + *type = THERMAL_TRIP_ACTIVE;
> + return 0;
> + }
> trip--;
> }
>
> @@ -1042,7 +1054,7 @@ static int thermal_get_trip_type(struct thermal_zone_device *thermal,
> }
>
> static int thermal_get_trip_temp(struct thermal_zone_device *thermal,
> - int trip, char *buf)
> + int trip, unsigned long *temp)
> {
> struct acpi_thermal *tz = thermal->devdata;
> int i;
> @@ -1051,31 +1063,39 @@ static int thermal_get_trip_temp(struct thermal_zone_device *thermal,
> return -EINVAL;
>
> if (tz->trips.critical.flags.valid) {
> - if (!trip)
> - return sprintf(buf, "%ld\n", KELVIN_TO_MILLICELSIUS(
> - tz->trips.critical.temperature));
> + if (!trip) {
> + *temp = KELVIN_TO_MILLICELSIUS(
> + tz->trips.critical.temperature);
> + return 0;
> + }
> trip--;
> }
>
> if (tz->trips.hot.flags.valid) {
> - if (!trip)
> - return sprintf(buf, "%ld\n", KELVIN_TO_MILLICELSIUS(
> - tz->trips.hot.temperature));
> + if (!trip) {
> + *temp = KELVIN_TO_MILLICELSIUS(
> + tz->trips.hot.temperature);
> + return 0;
> + }
> trip--;
> }
>
> if (tz->trips.passive.flags.valid) {
> - if (!trip)
> - return sprintf(buf, "%ld\n", KELVIN_TO_MILLICELSIUS(
> - tz->trips.passive.temperature));
> + if (!trip) {
> + *temp = KELVIN_TO_MILLICELSIUS(
> + tz->trips.passive.temperature);
> + return 0;
> + }
> trip--;
> }
>
> for (i = 0; i < ACPI_THERMAL_MAX_ACTIVE &&
> tz->trips.active[i].flags.valid; i++) {
> - if (!trip)
> - return sprintf(buf, "%ld\n", KELVIN_TO_MILLICELSIUS(
> - tz->trips.active[i].temperature));
> + if (!trip) {
> + *temp = KELVIN_TO_MILLICELSIUS(
> + tz->trips.active[i].temperature);
> + return 0;
> + }
> trip--;
> }
>
> diff --git a/drivers/acpi/video.c b/drivers/acpi/video.c
> index baa4419..5b2f1f3 100644
> --- a/drivers/acpi/video.c
> +++ b/drivers/acpi/video.c
> @@ -357,32 +357,36 @@ static struct output_properties acpi_output_properties = {
>
>
> /* thermal cooling device callbacks */
> -static int video_get_max_state(struct thermal_cooling_device *cdev, char *buf)
> +static int video_get_max_state(struct thermal_cooling_device *cdev, unsigned
> + long *state)
> {
> struct acpi_device *device = cdev->devdata;
> struct acpi_video_device *video = acpi_driver_data(device);
>
> - return sprintf(buf, "%d\n", video->brightness->count - 3);
> + *state = video->brightness->count - 3;
> + return 0;
> }
>
> -static int video_get_cur_state(struct thermal_cooling_device *cdev, char *buf)
> +static int video_get_cur_state(struct thermal_cooling_device *cdev, unsigned
> + long *state)
> {
> struct acpi_device *device = cdev->devdata;
> struct acpi_video_device *video = acpi_driver_data(device);
> unsigned long long level;
> - int state;
> + int offset;
>
> acpi_video_device_lcd_get_level_current(video, &level);
> - for (state = 2; state < video->brightness->count; state++)
> - if (level == video->brightness->levels[state])
> - return sprintf(buf, "%d\n",
> - video->brightness->count - state - 1);
> + for (offset = 2; offset < video->brightness->count; offset++)
> + if (level == video->brightness->levels[offset]) {
> + *state = video->brightness->count - offset - 1;
> + return 0;
> + }
>
> return -EINVAL;
> }
>
> static int
> -video_set_cur_state(struct thermal_cooling_device *cdev, unsigned int state)
> +video_set_cur_state(struct thermal_cooling_device *cdev, unsigned long state)
> {
> struct acpi_device *device = cdev->devdata;
> struct acpi_video_device *video = acpi_driver_data(device);
> diff --git a/drivers/misc/intel_menlow.c b/drivers/misc/intel_menlow.c
> index 27b7662..29432a5 100644
> --- a/drivers/misc/intel_menlow.c
> +++ b/drivers/misc/intel_menlow.c
> @@ -57,8 +57,8 @@ MODULE_LICENSE("GPL");
> * In that case max_cstate would be n-1
> * GTHS returning '0' would mean that no bandwidth control states are supported
> */
> -static int memory_get_int_max_bandwidth(struct thermal_cooling_device *cdev,
> - unsigned long *max_state)
> +static int memory_get_max_bandwidth(struct thermal_cooling_device *cdev,
> + unsigned long *max_state)
> {
> struct acpi_device *device = cdev->devdata;
> acpi_handle handle = device->handle;
> @@ -83,22 +83,12 @@ static int memory_get_int_max_bandwidth(struct thermal_cooling_device *cdev,
> return 0;
> }
>
> -static int memory_get_max_bandwidth(struct thermal_cooling_device *cdev,
> - char *buf)
> -{
> - unsigned long value;
> - if (memory_get_int_max_bandwidth(cdev, &value))
> - return -EINVAL;
> -
> - return sprintf(buf, "%ld\n", value);
> -}
> -
> static int memory_get_cur_bandwidth(struct thermal_cooling_device *cdev,
> - char *buf)
> + unsigned long *value)
> {
> struct acpi_device *device = cdev->devdata;
> acpi_handle handle = device->handle;
> - unsigned long long value;
> + unsigned long long result;
> struct acpi_object_list arg_list;
> union acpi_object arg;
> acpi_status status = AE_OK;
> @@ -108,15 +98,16 @@ static int memory_get_cur_bandwidth(struct thermal_cooling_device *cdev,
> arg.type = ACPI_TYPE_INTEGER;
> arg.integer.value = MEMORY_ARG_CUR_BANDWIDTH;
> status = acpi_evaluate_integer(handle, MEMORY_GET_BANDWIDTH,
> - &arg_list, &value);
> + &arg_list, &result);
> if (ACPI_FAILURE(status))
> return -EFAULT;
>
> - return sprintf(buf, "%llu\n", value);
> + *value = result;
> + return 0;
> }
>
> static int memory_set_cur_bandwidth(struct thermal_cooling_device *cdev,
> - unsigned int state)
> + unsigned long state)
> {
> struct acpi_device *device = cdev->devdata;
> acpi_handle handle = device->handle;
> @@ -126,7 +117,7 @@ static int memory_set_cur_bandwidth(struct thermal_cooling_device *cdev,
> unsigned long long temp;
> unsigned long max_state;
>
> - if (memory_get_int_max_bandwidth(cdev, &max_state))
> + if (memory_get_max_bandwidth(cdev, &max_state))
> return -EFAULT;
>
> if (state > max_state)
> @@ -142,7 +133,7 @@ static int memory_set_cur_bandwidth(struct thermal_cooling_device *cdev,
> &temp);
>
> printk(KERN_INFO
> - "Bandwidth value was %d: status is %d\n", state, status);
> + "Bandwidth value was %ld: status is %d\n", state, status);
> if (ACPI_FAILURE(status))
> return -EFAULT;
>
> diff --git a/drivers/thermal/thermal_sys.c b/drivers/thermal/thermal_sys.c
> index fe07462..7bcf322 100644
> --- a/drivers/thermal/thermal_sys.c
> +++ b/drivers/thermal/thermal_sys.c
> @@ -104,22 +104,36 @@ static ssize_t
> temp_show(struct device *dev, struct device_attribute *attr, char *buf)
> {
> struct thermal_zone_device *tz = to_thermal_zone(dev);
> + long temperature;
> + int ret;
>
> if (!tz->ops->get_temp)
> return -EPERM;
>
> - return tz->ops->get_temp(tz, buf);
> + ret = tz->ops->get_temp(tz, &temperature);
> +
> + if (ret)
> + return ret;
> +
> + return sprintf(buf, "%ld\n", temperature);
> }
>
> static ssize_t
> mode_show(struct device *dev, struct device_attribute *attr, char *buf)
> {
> struct thermal_zone_device *tz = to_thermal_zone(dev);
> + enum thermal_device_mode mode;
> + int result;
>
> if (!tz->ops->get_mode)
> return -EPERM;
>
> - return tz->ops->get_mode(tz, buf);
> + result = tz->ops->get_mode(tz, &mode);
> + if (result)
> + return result;
> +
> + return sprintf(buf, "%s\n", mode == THERMAL_DEVICE_ENABLED ? "enabled"
> + : "disabled");
> }
>
> static ssize_t
> @@ -132,7 +146,13 @@ mode_store(struct device *dev, struct device_attribute *attr,
> if (!tz->ops->set_mode)
> return -EPERM;
>
> - result = tz->ops->set_mode(tz, buf);
> + if (!strncmp(buf, "enabled", sizeof("enabled")))
> + result = tz->ops->set_mode(tz, THERMAL_DEVICE_ENABLED);
> + else if (!strncmp(buf, "disabled", sizeof("disabled")))
> + result = tz->ops->set_mode(tz, THERMAL_DEVICE_DISABLED);
> + else
> + result = -EINVAL;
> +
> if (result)
> return result;
>
> @@ -144,7 +164,8 @@ trip_point_type_show(struct device *dev, struct device_attribute *attr,
> char *buf)
> {
> struct thermal_zone_device *tz = to_thermal_zone(dev);
> - int trip;
> + enum thermal_trip_type type;
> + int trip, result;
>
> if (!tz->ops->get_trip_type)
> return -EPERM;
> @@ -152,7 +173,22 @@ trip_point_type_show(struct device *dev, struct device_attribute *attr,
> if (!sscanf(attr->attr.name, "trip_point_%d_type", &trip))
> return -EINVAL;
>
> - return tz->ops->get_trip_type(tz, trip, buf);
> + result = tz->ops->get_trip_type(tz, trip, &type);
> + if (result)
> + return result;
> +
> + switch (type) {
> + case THERMAL_TRIP_CRITICAL:
> + return sprintf(buf, "critical");
> + case THERMAL_TRIP_HOT:
> + return sprintf(buf, "hot");
> + case THERMAL_TRIP_PASSIVE:
> + return sprintf(buf, "passive");
> + case THERMAL_TRIP_ACTIVE:
> + return sprintf(buf, "active");
> + default:
> + return sprintf(buf, "unknown");
> + }
> }
>
> static ssize_t
> @@ -160,7 +196,8 @@ trip_point_temp_show(struct device *dev, struct device_attribute *attr,
> char *buf)
> {
> struct thermal_zone_device *tz = to_thermal_zone(dev);
> - int trip;
> + int trip, ret;
> + long temperature;
>
> if (!tz->ops->get_trip_temp)
> return -EPERM;
> @@ -168,7 +205,12 @@ trip_point_temp_show(struct device *dev, struct device_attribute *attr,
> if (!sscanf(attr->attr.name, "trip_point_%d_temp", &trip))
> return -EINVAL;
>
> - return tz->ops->get_trip_temp(tz, trip, buf);
> + ret = tz->ops->get_trip_temp(tz, trip, &temperature);
> +
> + if (ret)
> + return ret;
> +
> + return sprintf(buf, "%ld\n", temperature);
> }
>
> static DEVICE_ATTR(type, 0444, type_show, NULL);
> @@ -236,8 +278,13 @@ thermal_cooling_device_max_state_show(struct device *dev,
> struct device_attribute *attr, char *buf)
> {
> struct thermal_cooling_device *cdev = to_cooling_device(dev);
> + unsigned long state;
> + int ret;
>
> - return cdev->ops->get_max_state(cdev, buf);
> + ret = cdev->ops->get_max_state(cdev, &state);
> + if (ret)
> + return ret;
> + return sprintf(buf, "%ld\n", state);
> }
>
> static ssize_t
> @@ -245,8 +292,13 @@ thermal_cooling_device_cur_state_show(struct device *dev,
> struct device_attribute *attr, char *buf)
> {
> struct thermal_cooling_device *cdev = to_cooling_device(dev);
> + unsigned long state;
> + int ret;
>
> - return cdev->ops->get_cur_state(cdev, buf);
> + ret = cdev->ops->get_cur_state(cdev, &state);
> + if (ret)
> + return ret;
> + return sprintf(buf, "%ld\n", state);
> }
>
> static ssize_t
> @@ -255,10 +307,10 @@ thermal_cooling_device_cur_state_store(struct device *dev,
> const char *buf, size_t count)
> {
> struct thermal_cooling_device *cdev = to_cooling_device(dev);
> - int state;
> + unsigned long state;
> int result;
>
> - if (!sscanf(buf, "%d\n", &state))
> + if (!sscanf(buf, "%ld\n", &state))
> return -EINVAL;
>
> if (state < 0)
> @@ -312,13 +364,20 @@ static DEVICE_ATTR(name, 0444, name_show, NULL);
> static ssize_t
> temp_input_show(struct device *dev, struct device_attribute *attr, char *buf)
> {
> + long temperature;
> + int ret;
> struct thermal_hwmon_attr *hwmon_attr
> = container_of(attr, struct thermal_hwmon_attr, attr);
> struct thermal_zone_device *tz
> = container_of(hwmon_attr, struct thermal_zone_device,
> temp_input);
>
> - return tz->ops->get_temp(tz, buf);
> + ret = tz->ops->get_temp(tz, &temperature);
> +
> + if (ret)
> + return ret;
> +
> + return sprintf(buf, "%ld\n", temperature);
> }
>
> static ssize_t
> @@ -330,8 +389,14 @@ temp_crit_show(struct device *dev, struct device_attribute *attr,
> struct thermal_zone_device *tz
> = container_of(hwmon_attr, struct thermal_zone_device,
> temp_crit);
> + long temperature;
> + int ret;
> +
> + ret = tz->ops->get_trip_temp(tz, 0, &temperature);
> + if (ret)
> + return ret;
>
> - return tz->ops->get_trip_temp(tz, 0, buf);
> + return sprintf(buf, "%ld\n", temperature);
> }
>
>
> diff --git a/include/linux/thermal.h b/include/linux/thermal.h
> index 917707e..4cb3292 100644
> --- a/include/linux/thermal.h
> +++ b/include/linux/thermal.h
> @@ -31,23 +31,39 @@
> struct thermal_zone_device;
> struct thermal_cooling_device;
>
> +enum thermal_device_mode {
> + THERMAL_DEVICE_DISABLED = 0,
> + THERMAL_DEVICE_ENABLED,
> +};
> +
> +enum thermal_trip_type {
> + THERMAL_TRIP_ACTIVE = 0,
> + THERMAL_TRIP_PASSIVE,
> + THERMAL_TRIP_HOT,
> + THERMAL_TRIP_CRITICAL,
> +};
> +
> struct thermal_zone_device_ops {
> int (*bind) (struct thermal_zone_device *,
> struct thermal_cooling_device *);
> int (*unbind) (struct thermal_zone_device *,
> struct thermal_cooling_device *);
> - int (*get_temp) (struct thermal_zone_device *, char *);
> - int (*get_mode) (struct thermal_zone_device *, char *);
> - int (*set_mode) (struct thermal_zone_device *, const char *);
> - int (*get_trip_type) (struct thermal_zone_device *, int, char *);
> - int (*get_trip_temp) (struct thermal_zone_device *, int, char *);
> + int (*get_temp) (struct thermal_zone_device *, unsigned long *);
> + int (*get_mode) (struct thermal_zone_device *,
> + enum thermal_device_mode *);
> + int (*set_mode) (struct thermal_zone_device *,
> + enum thermal_device_mode);
> + int (*get_trip_type) (struct thermal_zone_device *, int,
> + enum thermal_trip_type *);
> + int (*get_trip_temp) (struct thermal_zone_device *, int,
> + unsigned long *);
> int (*get_crit_temp) (struct thermal_zone_device *, unsigned long *);
> };
>
> struct thermal_cooling_device_ops {
> - int (*get_max_state) (struct thermal_cooling_device *, char *);
> - int (*get_cur_state) (struct thermal_cooling_device *, char *);
> - int (*set_cur_state) (struct thermal_cooling_device *, unsigned int);
> + int (*get_max_state) (struct thermal_cooling_device *, unsigned long *);
> + int (*get_cur_state) (struct thermal_cooling_device *, unsigned long *);
> + int (*set_cur_state) (struct thermal_cooling_device *, unsigned long);
> };
>
> #define THERMAL_TRIPS_NONE -1
>
> --
> Matthew Garrett | mjg59@srcf.ucam.org
> --
> To unsubscribe from this list: send the line "unsubscribe linux-acpi" 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] 19+ messages in thread
* [PATCH] acpi: move thermal trip handling to generic thermal layer
2008-11-27 17:49 ` Matthew Garrett
2008-11-28 2:52 ` Zhang Rui
@ 2008-12-03 17:55 ` Matthew Garrett
2008-12-03 18:00 ` [PATCH] thermal: support forcing support for passive cooling Matthew Garrett
` (2 more replies)
1 sibling, 3 replies; 19+ messages in thread
From: Matthew Garrett @ 2008-12-03 17:55 UTC (permalink / raw)
To: lenb; +Cc: linux-acpi, rui.zhang, sujith.thomas
The ACPI code currently carries its own thermal trip handling, meaning that
any other thermal implementation will need to reimplement it. Move the code
to the generic thermal layer.
Signed-off-by: Matthew Garrett <mjg@redhat.com>
---
This depends on my earlier patch to rationalise the in-kernel thermal
interfaces.
drivers/acpi/thermal.c | 458 +++++------------------------------------
drivers/thermal/thermal_sys.c | 188 +++++++++++++++++-
include/linux/thermal.h | 15 ++-
3 files changed, 248 insertions(+), 413 deletions(-)
diff --git a/drivers/acpi/thermal.c b/drivers/acpi/thermal.c
index f24c7cc..0d311f1 100644
--- a/drivers/acpi/thermal.c
+++ b/drivers/acpi/thermal.c
@@ -37,7 +37,6 @@
#include <linux/init.h>
#include <linux/types.h>
#include <linux/proc_fs.h>
-#include <linux/timer.h>
#include <linux/jiffies.h>
#include <linux/kmod.h>
#include <linux/seq_file.h>
@@ -190,7 +189,6 @@ struct acpi_thermal {
struct acpi_thermal_state state;
struct acpi_thermal_trips trips;
struct acpi_handle_list devices;
- struct timer_list timer;
struct thermal_zone_device *thermal_zone;
int tz_enabled;
struct mutex lock;
@@ -290,6 +288,11 @@ static int acpi_thermal_set_polling(struct acpi_thermal *tz, int seconds)
tz->polling_frequency = seconds * 10; /* Convert value to deci-seconds */
+ tz->thermal_zone->polling_delay = seconds * 1000;
+
+ if (tz->tz_enabled)
+ thermal_zone_device_update(tz->thermal_zone);
+
ACPI_DEBUG_PRINT((ACPI_DB_INFO,
"Polling frequency set to %lu seconds\n",
tz->polling_frequency/10));
@@ -561,386 +564,11 @@ static int acpi_thermal_get_trip_points(struct acpi_thermal *tz)
return acpi_thermal_trips_update(tz, ACPI_TRIPS_INIT);
}
-static int acpi_thermal_critical(struct acpi_thermal *tz)
-{
- if (!tz || !tz->trips.critical.flags.valid)
- return -EINVAL;
-
- if (tz->temperature >= tz->trips.critical.temperature) {
- printk(KERN_WARNING PREFIX "Critical trip point\n");
- tz->trips.critical.flags.enabled = 1;
- } else if (tz->trips.critical.flags.enabled)
- tz->trips.critical.flags.enabled = 0;
-
- acpi_bus_generate_proc_event(tz->device, ACPI_THERMAL_NOTIFY_CRITICAL,
- tz->trips.critical.flags.enabled);
- acpi_bus_generate_netlink_event(tz->device->pnp.device_class,
- dev_name(&tz->device->dev),
- ACPI_THERMAL_NOTIFY_CRITICAL,
- tz->trips.critical.flags.enabled);
-
- /* take no action if nocrt is set */
- if(!nocrt) {
- printk(KERN_EMERG
- "Critical temperature reached (%ld C), shutting down.\n",
- KELVIN_TO_CELSIUS(tz->temperature));
- orderly_poweroff(true);
- }
-
- return 0;
-}
-
-static int acpi_thermal_hot(struct acpi_thermal *tz)
-{
- if (!tz || !tz->trips.hot.flags.valid)
- return -EINVAL;
-
- if (tz->temperature >= tz->trips.hot.temperature) {
- printk(KERN_WARNING PREFIX "Hot trip point\n");
- tz->trips.hot.flags.enabled = 1;
- } else if (tz->trips.hot.flags.enabled)
- tz->trips.hot.flags.enabled = 0;
-
- acpi_bus_generate_proc_event(tz->device, ACPI_THERMAL_NOTIFY_HOT,
- tz->trips.hot.flags.enabled);
- acpi_bus_generate_netlink_event(tz->device->pnp.device_class,
- dev_name(&tz->device->dev),
- ACPI_THERMAL_NOTIFY_HOT,
- tz->trips.hot.flags.enabled);
-
- /* TBD: Call user-mode "sleep(S4)" function if nocrt is cleared */
-
- return 0;
-}
-
-static void acpi_thermal_passive(struct acpi_thermal *tz)
-{
- int result = 1;
- struct acpi_thermal_passive *passive = NULL;
- int trend = 0;
- int i = 0;
-
-
- if (!tz || !tz->trips.passive.flags.valid)
- return;
-
- passive = &(tz->trips.passive);
-
- /*
- * Above Trip?
- * -----------
- * Calculate the thermal trend (using the passive cooling equation)
- * and modify the performance limit for all passive cooling devices
- * accordingly. Note that we assume symmetry.
- */
- if (tz->temperature >= passive->temperature) {
- trend =
- (passive->tc1 * (tz->temperature - tz->last_temperature)) +
- (passive->tc2 * (tz->temperature - passive->temperature));
- ACPI_DEBUG_PRINT((ACPI_DB_INFO,
- "trend[%d]=(tc1[%lu]*(tmp[%lu]-last[%lu]))+(tc2[%lu]*(tmp[%lu]-psv[%lu]))\n",
- trend, passive->tc1, tz->temperature,
- tz->last_temperature, passive->tc2,
- tz->temperature, passive->temperature));
- passive->flags.enabled = 1;
- /* Heating up? */
- if (trend > 0)
- for (i = 0; i < passive->devices.count; i++)
- acpi_processor_set_thermal_limit(passive->
- devices.
- handles[i],
- ACPI_PROCESSOR_LIMIT_INCREMENT);
- /* Cooling off? */
- else if (trend < 0) {
- for (i = 0; i < passive->devices.count; i++)
- /*
- * assume that we are on highest
- * freq/lowest thrott and can leave
- * passive mode, even in error case
- */
- if (!acpi_processor_set_thermal_limit
- (passive->devices.handles[i],
- ACPI_PROCESSOR_LIMIT_DECREMENT))
- result = 0;
- /*
- * Leave cooling mode, even if the temp might
- * higher than trip point This is because some
- * machines might have long thermal polling
- * frequencies (tsp) defined. We will fall back
- * into passive mode in next cycle (probably quicker)
- */
- if (result) {
- passive->flags.enabled = 0;
- ACPI_DEBUG_PRINT((ACPI_DB_INFO,
- "Disabling passive cooling, still above threshold,"
- " but we are cooling down\n"));
- }
- }
- return;
- }
-
- /*
- * Below Trip?
- * -----------
- * Implement passive cooling hysteresis to slowly increase performance
- * and avoid thrashing around the passive trip point. Note that we
- * assume symmetry.
- */
- if (!passive->flags.enabled)
- return;
- for (i = 0; i < passive->devices.count; i++)
- if (!acpi_processor_set_thermal_limit
- (passive->devices.handles[i],
- ACPI_PROCESSOR_LIMIT_DECREMENT))
- result = 0;
- if (result) {
- passive->flags.enabled = 0;
- ACPI_DEBUG_PRINT((ACPI_DB_INFO,
- "Disabling passive cooling (zone is cool)\n"));
- }
-}
-
-static void acpi_thermal_active(struct acpi_thermal *tz)
-{
- int result = 0;
- struct acpi_thermal_active *active = NULL;
- int i = 0;
- int j = 0;
- unsigned long maxtemp = 0;
-
-
- if (!tz)
- return;
-
- for (i = 0; i < ACPI_THERMAL_MAX_ACTIVE; i++) {
- active = &(tz->trips.active[i]);
- if (!active || !active->flags.valid)
- break;
- if (tz->temperature >= active->temperature) {
- /*
- * Above Threshold?
- * ----------------
- * If not already enabled, turn ON all cooling devices
- * associated with this active threshold.
- */
- if (active->temperature > maxtemp)
- tz->state.active_index = i;
- maxtemp = active->temperature;
- if (active->flags.enabled)
- continue;
- for (j = 0; j < active->devices.count; j++) {
- result =
- acpi_bus_set_power(active->devices.
- handles[j],
- ACPI_STATE_D0);
- if (result) {
- printk(KERN_WARNING PREFIX
- "Unable to turn cooling device [%p] 'on'\n",
- active->devices.
- handles[j]);
- continue;
- }
- active->flags.enabled = 1;
- ACPI_DEBUG_PRINT((ACPI_DB_INFO,
- "Cooling device [%p] now 'on'\n",
- active->devices.handles[j]));
- }
- continue;
- }
- if (!active->flags.enabled)
- continue;
- /*
- * Below Threshold?
- * ----------------
- * Turn OFF all cooling devices associated with this
- * threshold.
- */
- for (j = 0; j < active->devices.count; j++) {
- result = acpi_bus_set_power(active->devices.handles[j],
- ACPI_STATE_D3);
- if (result) {
- printk(KERN_WARNING PREFIX
- "Unable to turn cooling device [%p] 'off'\n",
- active->devices.handles[j]);
- continue;
- }
- active->flags.enabled = 0;
- ACPI_DEBUG_PRINT((ACPI_DB_INFO,
- "Cooling device [%p] now 'off'\n",
- active->devices.handles[j]));
- }
- }
-}
-
-static void acpi_thermal_check(void *context);
-
-static void acpi_thermal_run(unsigned long data)
-{
- struct acpi_thermal *tz = (struct acpi_thermal *)data;
- if (!tz->zombie)
- acpi_os_execute(OSL_GPE_HANDLER, acpi_thermal_check, (void *)data);
-}
-
-static void acpi_thermal_active_off(void *data)
-{
- int result = 0;
- struct acpi_thermal *tz = data;
- int i = 0;
- int j = 0;
- struct acpi_thermal_active *active = NULL;
-
- if (!tz) {
- printk(KERN_ERR PREFIX "Invalid (NULL) context\n");
- return;
- }
-
- result = acpi_thermal_get_temperature(tz);
- if (result)
- return;
-
- for (i = 0; i < ACPI_THERMAL_MAX_ACTIVE; i++) {
- active = &(tz->trips.active[i]);
- if (!active || !active->flags.valid)
- break;
- if (tz->temperature >= active->temperature) {
- /*
- * If the thermal temperature is greater than the
- * active threshod, unnecessary to turn off the
- * the active cooling device.
- */
- continue;
- }
- /*
- * Below Threshold?
- * ----------------
- * Turn OFF all cooling devices associated with this
- * threshold.
- */
- for (j = 0; j < active->devices.count; j++)
- result = acpi_bus_set_power(active->devices.handles[j],
- ACPI_STATE_D3);
- }
-}
-
static void acpi_thermal_check(void *data)
{
- int result = 0;
struct acpi_thermal *tz = data;
- unsigned long sleep_time = 0;
- unsigned long timeout_jiffies = 0;
- int i = 0;
- struct acpi_thermal_state state;
-
-
- if (!tz) {
- printk(KERN_ERR PREFIX "Invalid (NULL) context\n");
- return;
- }
-
- /* Check if someone else is already running */
- if (!mutex_trylock(&tz->lock))
- return;
-
- state = tz->state;
-
- result = acpi_thermal_get_temperature(tz);
- if (result)
- goto unlock;
-
- if (!tz->tz_enabled)
- goto unlock;
-
- memset(&tz->state, 0, sizeof(tz->state));
-
- /*
- * Check Trip Points
- * -----------------
- * Compare the current temperature to the trip point values to see
- * if we've entered one of the thermal policy states. Note that
- * this function determines when a state is entered, but the
- * individual policy decides when it is exited (e.g. hysteresis).
- */
- if (tz->trips.critical.flags.valid)
- state.critical |=
- (tz->temperature >= tz->trips.critical.temperature);
- if (tz->trips.hot.flags.valid)
- state.hot |= (tz->temperature >= tz->trips.hot.temperature);
- if (tz->trips.passive.flags.valid)
- state.passive |=
- (tz->temperature >= tz->trips.passive.temperature);
- for (i = 0; i < ACPI_THERMAL_MAX_ACTIVE; i++)
- if (tz->trips.active[i].flags.valid)
- state.active |=
- (tz->temperature >=
- tz->trips.active[i].temperature);
-
- /*
- * Invoke Policy
- * -------------
- * Separated from the above check to allow individual policy to
- * determine when to exit a given state.
- */
- if (state.critical)
- acpi_thermal_critical(tz);
- if (state.hot)
- acpi_thermal_hot(tz);
- if (state.passive)
- acpi_thermal_passive(tz);
- if (state.active)
- acpi_thermal_active(tz);
- /*
- * Calculate State
- * ---------------
- * Again, separated from the above two to allow independent policy
- * decisions.
- */
- tz->state.critical = tz->trips.critical.flags.enabled;
- tz->state.hot = tz->trips.hot.flags.enabled;
- tz->state.passive = tz->trips.passive.flags.enabled;
- tz->state.active = 0;
- for (i = 0; i < ACPI_THERMAL_MAX_ACTIVE; i++)
- tz->state.active |= tz->trips.active[i].flags.enabled;
-
- /*
- * Calculate Sleep Time
- * --------------------
- * If we're in the passive state, use _TSP's value. Otherwise
- * use the default polling frequency (e.g. _TZP). If no polling
- * frequency is specified then we'll wait forever (at least until
- * a thermal event occurs). Note that _TSP and _TZD values are
- * given in 1/10th seconds (we must covert to milliseconds).
- */
- if (tz->state.passive) {
- sleep_time = tz->trips.passive.tsp * 100;
- timeout_jiffies = jiffies + (HZ * sleep_time) / 1000;
- } else if (tz->polling_frequency > 0) {
- sleep_time = tz->polling_frequency * 100;
- timeout_jiffies = round_jiffies(jiffies + (HZ * sleep_time) / 1000);
- }
-
- ACPI_DEBUG_PRINT((ACPI_DB_INFO, "%s: temperature[%lu] sleep[%lu]\n",
- tz->name, tz->temperature, sleep_time));
-
- /*
- * Schedule Next Poll
- * ------------------
- */
- if (!sleep_time) {
- if (timer_pending(&(tz->timer)))
- del_timer(&(tz->timer));
- } else {
- if (timer_pending(&(tz->timer)))
- mod_timer(&(tz->timer), timeout_jiffies);
- else {
- tz->timer.data = (unsigned long)tz;
- tz->timer.function = acpi_thermal_run;
- tz->timer.expires = timeout_jiffies;
- add_timer(&(tz->timer));
- }
- }
- unlock:
- mutex_unlock(&tz->lock);
+ thermal_zone_device_update(tz->thermal_zone);
}
/* sys I/F for generic thermal sysfs support */
@@ -1114,6 +742,29 @@ static int thermal_get_crit_temp(struct thermal_zone_device *thermal,
return -EINVAL;
}
+static int thermal_notify(struct thermal_zone_device *thermal, int trip,
+ enum thermal_trip_type trip_type)
+{
+ u8 type = 0;
+ struct acpi_thermal *tz = thermal->devdata;
+
+ if (trip_type == THERMAL_TRIP_CRITICAL)
+ type = ACPI_THERMAL_NOTIFY_CRITICAL;
+ else if (trip_type == THERMAL_TRIP_HOT)
+ type = ACPI_THERMAL_NOTIFY_HOT;
+ else
+ return 0;
+
+ acpi_bus_generate_proc_event(tz->device, type, 1);
+ acpi_bus_generate_netlink_event(tz->device->pnp.device_class,
+ tz->device->dev.bus_id, type, 1);
+
+ if (trip_type == THERMAL_TRIP_CRITICAL && nocrt)
+ return 1;
+
+ return 0;
+}
+
typedef int (*cb)(struct thermal_zone_device *, int,
struct thermal_cooling_device *);
static int acpi_thermal_cooling_device_cb(struct thermal_zone_device *thermal,
@@ -1206,6 +857,7 @@ static struct thermal_zone_device_ops acpi_thermal_zone_ops = {
.get_trip_type = thermal_get_trip_type,
.get_trip_temp = thermal_get_trip_temp,
.get_crit_temp = thermal_get_crit_temp,
+ .notify = thermal_notify,
};
static int acpi_thermal_register_thermal_zone(struct acpi_thermal *tz)
@@ -1226,8 +878,21 @@ static int acpi_thermal_register_thermal_zone(struct acpi_thermal *tz)
for (i = 0; i < ACPI_THERMAL_MAX_ACTIVE &&
tz->trips.active[i].flags.valid; i++, trips++);
- tz->thermal_zone = thermal_zone_device_register("acpitz",
- trips, tz, &acpi_thermal_zone_ops);
+
+ if (tz->trips.passive.flags.valid)
+ tz->thermal_zone =
+ thermal_zone_device_register("acpitz", trips, tz,
+ &acpi_thermal_zone_ops,
+ tz->trips.passive.tc1,
+ tz->trips.passive.tc2,
+ tz->trips.passive.tsp*100,
+ tz->polling_frequency*100);
+ else
+ tz->thermal_zone =
+ thermal_zone_device_register("acpitz", trips, tz,
+ &acpi_thermal_zone_ops,
+ 0, 0, 0,
+ tz->polling_frequency);
if (IS_ERR(tz->thermal_zone))
return -ENODEV;
@@ -1459,13 +1124,13 @@ static int acpi_thermal_polling_seq_show(struct seq_file *seq, void *offset)
if (!tz)
goto end;
- if (!tz->polling_frequency) {
+ if (!tz->thermal_zone->polling_delay) {
seq_puts(seq, "<polling disabled>\n");
goto end;
}
- seq_printf(seq, "polling frequency: %lu seconds\n",
- (tz->polling_frequency / 10));
+ seq_printf(seq, "polling frequency: %d seconds\n",
+ (tz->thermal_zone->polling_delay / 1000));
end:
return 0;
@@ -1695,12 +1360,6 @@ static int acpi_thermal_add(struct acpi_device *device)
if (result)
goto unregister_thermal_zone;
- init_timer(&tz->timer);
-
- acpi_thermal_active_off(tz);
-
- acpi_thermal_check(tz);
-
status = acpi_install_notify_handler(device->handle,
ACPI_DEVICE_NOTIFY,
acpi_thermal_notify, tz);
@@ -1729,36 +1388,15 @@ static int acpi_thermal_remove(struct acpi_device *device, int type)
acpi_status status = AE_OK;
struct acpi_thermal *tz = NULL;
-
if (!device || !acpi_driver_data(device))
return -EINVAL;
tz = acpi_driver_data(device);
- /* avoid timer adding new defer task */
- tz->zombie = 1;
- /* wait for running timer (on other CPUs) finish */
- del_timer_sync(&(tz->timer));
- /* synchronize deferred task */
- acpi_os_wait_events_complete(NULL);
- /* deferred task may reinsert timer */
- del_timer_sync(&(tz->timer));
-
status = acpi_remove_notify_handler(device->handle,
ACPI_DEVICE_NOTIFY,
acpi_thermal_notify);
- /* Terminate policy */
- if (tz->trips.passive.flags.valid && tz->trips.passive.flags.enabled) {
- tz->trips.passive.flags.enabled = 0;
- acpi_thermal_passive(tz);
- }
- if (tz->trips.active[0].flags.valid
- && tz->trips.active[0].flags.enabled) {
- tz->trips.active[0].flags.enabled = 0;
- acpi_thermal_active(tz);
- }
-
acpi_thermal_remove_fs(device);
acpi_thermal_unregister_thermal_zone(tz);
mutex_destroy(&tz->lock);
diff --git a/drivers/thermal/thermal_sys.c b/drivers/thermal/thermal_sys.c
index 7bcf322..ac0f91f 100644
--- a/drivers/thermal/thermal_sys.c
+++ b/drivers/thermal/thermal_sys.c
@@ -30,6 +30,7 @@
#include <linux/idr.h>
#include <linux/thermal.h>
#include <linux/spinlock.h>
+#include <linux/reboot.h>
MODULE_AUTHOR("Zhang Rui");
MODULE_DESCRIPTION("Generic thermal management sysfs support");
@@ -517,6 +518,97 @@ thermal_remove_hwmon_sysfs(struct thermal_zone_device *tz)
}
#endif
+static void thermal_zone_device_set_polling(struct thermal_zone_device *tz,
+ int delay)
+{
+ cancel_delayed_work(&(tz->poll_queue));
+
+ if (!delay)
+ return;
+
+ if (delay > 1000)
+ schedule_delayed_work(&(tz->poll_queue),
+ round_jiffies(msecs_to_jiffies(delay)));
+ else
+ schedule_delayed_work(&(tz->poll_queue),
+ msecs_to_jiffies(delay));
+}
+
+static void thermal_zone_device_passive(struct thermal_zone_device *tz,
+ int temp, int trip_temp, int trip)
+{
+ int trend = 0;
+ struct thermal_cooling_device_instance *instance;
+ struct thermal_cooling_device *cdev;
+ long state, max_state;
+
+ /*
+ * Above Trip?
+ * -----------
+ * Calculate the thermal trend (using the passive cooling equation)
+ * and modify the performance limit for all passive cooling devices
+ * accordingly. Note that we assume symmetry.
+ */
+ if (temp >= trip_temp) {
+ tz->passive = true;
+
+ trend = (tz->tc1 * (temp - tz->last_temperature)) +
+ (tz->tc2 * (temp - trip_temp));
+
+ /* Heating up? */
+ if (trend > 0) {
+ list_for_each_entry(instance, &tz->cooling_devices,
+ node) {
+ if (instance->trip != trip)
+ continue;
+ cdev = instance->cdev;
+ cdev->ops->get_cur_state(cdev, &state);
+ cdev->ops->get_max_state(cdev, &max_state);
+ if (state++ < max_state)
+ cdev->ops->set_cur_state(cdev, state);
+ }
+ } else if (trend < 0) { /* Cooling off? */
+ list_for_each_entry(instance, &tz->cooling_devices,
+ node) {
+ if (instance->trip != trip)
+ continue;
+ cdev = instance->cdev;
+ cdev->ops->get_cur_state(cdev, &state);
+ cdev->ops->get_max_state(cdev, &max_state);
+ if (state > 0)
+ cdev->ops->set_cur_state(cdev, --state);
+ }
+ }
+ return;
+ }
+
+ /*
+ * Below Trip?
+ * -----------
+ * Implement passive cooling hysteresis to slowly increase performance
+ * and avoid thrashing around the passive trip point. Note that we
+ * assume symmetry.
+ */
+ list_for_each_entry(instance, &tz->cooling_devices, node) {
+ if (instance->trip != trip)
+ continue;
+ cdev = instance->cdev;
+ cdev->ops->get_cur_state(cdev, &state);
+ cdev->ops->get_max_state(cdev, &max_state);
+ if (state > 0)
+ cdev->ops->set_cur_state(cdev, --state);
+ if (state == 0)
+ tz->passive = false;
+ }
+}
+
+static void thermal_zone_device_check(struct work_struct *work)
+{
+ struct thermal_zone_device *tz = container_of(work, struct
+ thermal_zone_device,
+ poll_queue.work);
+ thermal_zone_device_update(tz);
+}
/**
* thermal_zone_bind_cooling_device - bind a cooling device to a thermal zone
@@ -787,20 +879,101 @@ void thermal_cooling_device_unregister(struct
EXPORT_SYMBOL(thermal_cooling_device_unregister);
/**
+ * thermal_zone_device_update - force an update of a thermal zone's state
+ * @ttz: the thermal zone to update
+ */
+
+void thermal_zone_device_update(struct thermal_zone_device *tz)
+{
+ int count, ret = 0;
+ long temp, trip_temp;
+ enum thermal_trip_type trip_type;
+ struct thermal_cooling_device_instance *instance;
+ struct thermal_cooling_device *cdev;
+
+ mutex_lock(&tz->lock);
+
+ tz->ops->get_temp(tz, &temp);
+
+ for (count = 0; count < tz->trips; count++) {
+ tz->ops->get_trip_type(tz, count, &trip_type);
+ tz->ops->get_trip_temp(tz, count, &trip_temp);
+
+ switch (trip_type) {
+ case THERMAL_TRIP_CRITICAL:
+ if (temp > trip_temp) {
+ if (tz->ops->notify)
+ ret = tz->ops->notify(tz, count,
+ trip_type);
+ if (!ret) {
+ printk(KERN_EMERG
+ "Critical temperature reached (%ld C), shutting down.\n",
+ temp/1000);
+ orderly_poweroff(true);
+ }
+ }
+ break;
+ case THERMAL_TRIP_HOT:
+ if (temp > trip_temp)
+ if (tz->ops->notify)
+ tz->ops->notify(tz, count, trip_type);
+ break;
+ case THERMAL_TRIP_ACTIVE:
+ list_for_each_entry(instance, &tz->cooling_devices,
+ node) {
+ if (instance->trip != count)
+ continue;
+
+ cdev = instance->cdev;
+
+ if (temp > trip_temp)
+ cdev->ops->set_cur_state(cdev, 1);
+ else
+ cdev->ops->set_cur_state(cdev, 0);
+ }
+ break;
+ case THERMAL_TRIP_PASSIVE:
+ if (temp > trip_temp || tz->passive)
+ thermal_zone_device_passive(tz, temp,
+ trip_temp, count);
+ break;
+ }
+ }
+ tz->last_temperature = temp;
+ if (tz->passive)
+ thermal_zone_device_set_polling(tz, tz->passive_delay);
+ else if (tz->polling_delay)
+ thermal_zone_device_set_polling(tz, tz->polling_delay);
+ mutex_unlock(&tz->lock);
+}
+EXPORT_SYMBOL(thermal_zone_device_update);
+
+/**
* 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
* @devdata: private device data
* @ops: standard thermal zone device callbacks
+ * @tc1: thermal coefficient 1 for passive calculations
+ * @tc2: thermal coefficient 2 for passive calculations
+ * @passive_delay: number of milliseconds to wait between polls when
+ * performing passive cooling
+ * @polling_delay: number of milliseconds to wait between polls when checking
+ * whether trip points have been crossed (0 for interrupt
+ * driven systems)
*
* thermal_zone_device_unregister() must be called when the device is no
- * longer needed.
+ * longer needed. The passive cooling formula uses tc1 and tc2 as described in
+ * section 11.1.5.1 of the ACPI specification 3.0.
*/
struct thermal_zone_device *thermal_zone_device_register(char *type,
int trips,
void *devdata, struct
thermal_zone_device_ops
- *ops)
+ *ops, int tc1, int
+ tc2,
+ int passive_delay,
+ int polling_delay)
{
struct thermal_zone_device *tz;
struct thermal_cooling_device *pos;
@@ -834,6 +1007,11 @@ struct thermal_zone_device *thermal_zone_device_register(char *type,
tz->device.class = &thermal_class;
tz->devdata = devdata;
tz->trips = trips;
+ tz->tc1 = tc1;
+ tz->tc2 = tc2;
+ tz->passive_delay = passive_delay;
+ tz->polling_delay = polling_delay;
+
sprintf(tz->device.bus_id, "thermal_zone%d", tz->id);
result = device_register(&tz->device);
if (result) {
@@ -879,6 +1057,10 @@ struct thermal_zone_device *thermal_zone_device_register(char *type,
}
mutex_unlock(&thermal_list_lock);
+ INIT_DELAYED_WORK(&(tz->poll_queue), thermal_zone_device_check);
+
+ thermal_zone_device_update(tz);
+
if (!result)
return tz;
@@ -918,6 +1100,8 @@ void thermal_zone_device_unregister(struct thermal_zone_device *tz)
tz->ops->unbind(tz, cdev);
mutex_unlock(&thermal_list_lock);
+ thermal_zone_device_set_polling(tz, 0);
+
if (tz->type[0])
device_remove_file(&tz->device, &dev_attr_type);
device_remove_file(&tz->device, &dev_attr_temp);
diff --git a/include/linux/thermal.h b/include/linux/thermal.h
index 4cb3292..a81c615 100644
--- a/include/linux/thermal.h
+++ b/include/linux/thermal.h
@@ -27,6 +27,7 @@
#include <linux/idr.h>
#include <linux/device.h>
+#include <linux/workqueue.h>
struct thermal_zone_device;
struct thermal_cooling_device;
@@ -58,6 +59,8 @@ struct thermal_zone_device_ops {
int (*get_trip_temp) (struct thermal_zone_device *, int,
unsigned long *);
int (*get_crit_temp) (struct thermal_zone_device *, unsigned long *);
+ int (*notify) (struct thermal_zone_device *, int,
+ enum thermal_trip_type);
};
struct thermal_cooling_device_ops {
@@ -104,11 +107,18 @@ struct thermal_zone_device {
struct device device;
void *devdata;
int trips;
+ int tc1;
+ int tc2;
+ int passive_delay;
+ int polling_delay;
+ int last_temperature;
+ bool passive;
struct thermal_zone_device_ops *ops;
struct list_head cooling_devices;
struct idr idr;
struct mutex lock; /* protect cooling devices list */
struct list_head node;
+ struct delayed_work poll_queue;
#if defined(CONFIG_THERMAL_HWMON)
struct list_head hwmon_node;
struct thermal_hwmon_device *hwmon;
@@ -120,13 +130,16 @@ struct thermal_zone_device {
struct thermal_zone_device *thermal_zone_device_register(char *, int, void *,
struct
thermal_zone_device_ops
- *);
+ *, int tc1, int tc2,
+ int passive_freq,
+ int polling_freq);
void thermal_zone_device_unregister(struct thermal_zone_device *);
int thermal_zone_bind_cooling_device(struct thermal_zone_device *, int,
struct thermal_cooling_device *);
int thermal_zone_unbind_cooling_device(struct thermal_zone_device *, int,
struct thermal_cooling_device *);
+void thermal_zone_device_update(struct thermal_zone_device *);
struct thermal_cooling_device *thermal_cooling_device_register(char *, void *,
struct
thermal_cooling_device_ops
--
Matthew Garrett | mjg59@srcf.ucam.org
^ permalink raw reply related [flat|nested] 19+ messages in thread
* [PATCH] thermal: support forcing support for passive cooling
2008-12-03 17:55 ` [PATCH] acpi: move thermal trip handling to generic thermal layer Matthew Garrett
@ 2008-12-03 18:00 ` Matthew Garrett
2008-12-17 3:19 ` Zhang Rui
` (2 more replies)
2008-12-08 6:59 ` [PATCH] acpi: move thermal trip handling to generic thermal layer Zhang Rui
2009-02-20 23:44 ` Len Brown
2 siblings, 3 replies; 19+ messages in thread
From: Matthew Garrett @ 2008-12-03 18:00 UTC (permalink / raw)
To: lenb; +Cc: linux-acpi, rui.zhang, sujith.thomas
Due to poor thermal design or Linux driving hardware outside its thermal
envelope, some systems will reach critical temperature and shut down
under high load. This patch adds support for forcing a polling-based
passive trip point if the firmware doesn't provide one. The assumption
is made that the processor is the most practical means to reduce the
dynamic heat generation, so hitting the passive thermal limit will cause
the CPU to be throttled until the temperature stabalises around the
defined value.
UI is provided via a "passive" sysfs entry in the thermal zone
directory. It accepts a decimal value in millidegrees celsius, or "0" to
disable the functionality. Default behaviour is for this functionality
to be disabled.
Signed-off-by: Matthew Garrett <mjg@redhat.com>
---
Depends on the code to move the trip handling into the generic layer.
Tested this on a couple of machines and it seems to work well - a
logical followup might be to allow the passive trip point to be
overridden on machines that provide it.
drivers/thermal/thermal_sys.c | 77 +++++++++++++++++++++++++++++++++++++++++
include/linux/thermal.h | 1 +
2 files changed, 78 insertions(+), 0 deletions(-)
diff --git a/drivers/thermal/thermal_sys.c b/drivers/thermal/thermal_sys.c
index ac0f91f..c5351e5 100644
--- a/drivers/thermal/thermal_sys.c
+++ b/drivers/thermal/thermal_sys.c
@@ -214,9 +214,69 @@ trip_point_temp_show(struct device *dev, struct device_attribute *attr,
return sprintf(buf, "%ld\n", temperature);
}
+static ssize_t
+passive_store(struct device *dev, struct device_attribute *attr,
+ const char *buf, size_t count)
+{
+ struct thermal_zone_device *tz = to_thermal_zone(dev);
+ struct thermal_cooling_device *cdev = NULL;
+ int state;
+
+ if (!sscanf(buf, "%d\n", &state))
+ return -EINVAL;
+
+ if (state && !tz->forced_passive) {
+ mutex_lock(&thermal_list_lock);
+ list_for_each_entry(cdev, &thermal_cdev_list, node) {
+ if (!strncmp("Processor", cdev->type,
+ sizeof("Processor")))
+ thermal_zone_bind_cooling_device(tz,
+ THERMAL_TRIPS_NONE,
+ cdev);
+ }
+ mutex_unlock(&thermal_list_lock);
+ } else if (!state && tz->forced_passive) {
+ mutex_lock(&thermal_list_lock);
+ list_for_each_entry(cdev, &thermal_cdev_list, node) {
+ if (!strncmp("Processor", cdev->type,
+ sizeof("Processor")))
+ thermal_zone_unbind_cooling_device(tz,
+ THERMAL_TRIPS_NONE,
+ cdev);
+ }
+ mutex_unlock(&thermal_list_lock);
+ }
+
+ tz->tc1 = 1;
+ tz->tc2 = 1;
+
+ if (!tz->passive_delay)
+ tz->passive_delay = 1000;
+
+ if (!tz->polling_delay)
+ tz->polling_delay = 10000;
+
+ tz->forced_passive = state;
+
+ thermal_zone_device_update(tz);
+
+ return count;
+}
+
+static ssize_t
+passive_show(struct device *dev, struct device_attribute *attr,
+ char *buf)
+{
+ struct thermal_zone_device *tz = to_thermal_zone(dev);
+
+ return sprintf(buf, "%d\n", tz->forced_passive);
+}
+
static DEVICE_ATTR(type, 0444, type_show, NULL);
static DEVICE_ATTR(temp, 0444, temp_show, NULL);
static DEVICE_ATTR(mode, 0644, mode_show, mode_store);
+static DEVICE_ATTR(passive, S_IRUGO | S_IWUSR, passive_show, \
+ passive_store);
static struct device_attribute trip_point_attrs[] = {
__ATTR(trip_point_0_type, 0444, trip_point_type_show, NULL),
@@ -939,6 +999,11 @@ void thermal_zone_device_update(struct thermal_zone_device *tz)
break;
}
}
+
+ if (tz->forced_passive)
+ thermal_zone_device_passive(tz, temp, tz->forced_passive,
+ THERMAL_TRIPS_NONE);
+
tz->last_temperature = temp;
if (tz->passive)
thermal_zone_device_set_polling(tz, tz->passive_delay);
@@ -977,8 +1042,10 @@ struct thermal_zone_device *thermal_zone_device_register(char *type,
{
struct thermal_zone_device *tz;
struct thermal_cooling_device *pos;
+ enum thermal_trip_type trip_type;
int result;
int count;
+ int passive=0;
if (strlen(type) >= THERMAL_NAME_LENGTH)
return ERR_PTR(-EINVAL);
@@ -1041,8 +1108,18 @@ struct thermal_zone_device *thermal_zone_device_register(char *type,
TRIP_POINT_ATTR_ADD(&tz->device, count, result);
if (result)
goto unregister;
+ tz->ops->get_trip_type(tz, count, &trip_type);
+ if (trip_type == THERMAL_TRIP_PASSIVE)
+ passive=1;
}
+ if (!passive)
+ result = device_create_file(&tz->device,
+ &dev_attr_passive);
+
+ if (result)
+ goto unregister;
+
result = thermal_add_hwmon_sysfs(tz);
if (result)
goto unregister;
diff --git a/include/linux/thermal.h b/include/linux/thermal.h
index a81c615..1de8b9e 100644
--- a/include/linux/thermal.h
+++ b/include/linux/thermal.h
@@ -113,6 +113,7 @@ struct thermal_zone_device {
int polling_delay;
int last_temperature;
bool passive;
+ unsigned int forced_passive;
struct thermal_zone_device_ops *ops;
struct list_head cooling_devices;
struct idr idr;
--
Matthew Garrett | mjg59@srcf.ucam.org
^ permalink raw reply related [flat|nested] 19+ messages in thread
* Re: [PATCH] acpi: move thermal trip handling to generic thermal layer
2008-12-03 17:55 ` [PATCH] acpi: move thermal trip handling to generic thermal layer Matthew Garrett
2008-12-03 18:00 ` [PATCH] thermal: support forcing support for passive cooling Matthew Garrett
@ 2008-12-08 6:59 ` Zhang Rui
2008-12-08 12:59 ` Matthew Garrett
2009-02-20 23:44 ` Len Brown
2 siblings, 1 reply; 19+ messages in thread
From: Zhang Rui @ 2008-12-08 6:59 UTC (permalink / raw)
To: Matthew Garrett
Cc: lenb@kernel.org, linux-acpi@vger.kernel.org, Thomas, Sujith
On Thu, 2008-12-04 at 01:55 +0800, Matthew Garrett wrote:
> The ACPI code currently carries its own thermal trip handling, meaning that
> any other thermal implementation will need to reimplement it. Move the code
> to the generic thermal layer.
>
Are these ACPI stuffs generic enough to be ported to the generic thermal
driver?
e.g. the tc1, tc2, tsp, they are mentioned in the ACPI spec,
so my question is if the thermal zones than ACPI still have these
concepts?
thanks,
rui
> Signed-off-by: Matthew Garrett <mjg@redhat.com>
> ---
>
> This depends on my earlier patch to rationalise the in-kernel thermal
> interfaces.
>
> drivers/acpi/thermal.c | 458 +++++------------------------------------
> drivers/thermal/thermal_sys.c | 188 +++++++++++++++++-
> include/linux/thermal.h | 15 ++-
> 3 files changed, 248 insertions(+), 413 deletions(-)
>
> diff --git a/drivers/acpi/thermal.c b/drivers/acpi/thermal.c
> index f24c7cc..0d311f1 100644
> --- a/drivers/acpi/thermal.c
> +++ b/drivers/acpi/thermal.c
> @@ -37,7 +37,6 @@
> #include <linux/init.h>
> #include <linux/types.h>
> #include <linux/proc_fs.h>
> -#include <linux/timer.h>
> #include <linux/jiffies.h>
> #include <linux/kmod.h>
> #include <linux/seq_file.h>
> @@ -190,7 +189,6 @@ struct acpi_thermal {
> struct acpi_thermal_state state;
> struct acpi_thermal_trips trips;
> struct acpi_handle_list devices;
> - struct timer_list timer;
> struct thermal_zone_device *thermal_zone;
> int tz_enabled;
> struct mutex lock;
> @@ -290,6 +288,11 @@ static int acpi_thermal_set_polling(struct acpi_thermal *tz, int seconds)
>
> tz->polling_frequency = seconds * 10; /* Convert value to deci-seconds */
>
> + tz->thermal_zone->polling_delay = seconds * 1000;
> +
> + if (tz->tz_enabled)
> + thermal_zone_device_update(tz->thermal_zone);
> +
> ACPI_DEBUG_PRINT((ACPI_DB_INFO,
> "Polling frequency set to %lu seconds\n",
> tz->polling_frequency/10));
> @@ -561,386 +564,11 @@ static int acpi_thermal_get_trip_points(struct acpi_thermal *tz)
> return acpi_thermal_trips_update(tz, ACPI_TRIPS_INIT);
> }
>
> -static int acpi_thermal_critical(struct acpi_thermal *tz)
> -{
> - if (!tz || !tz->trips.critical.flags.valid)
> - return -EINVAL;
> -
> - if (tz->temperature >= tz->trips.critical.temperature) {
> - printk(KERN_WARNING PREFIX "Critical trip point\n");
> - tz->trips.critical.flags.enabled = 1;
> - } else if (tz->trips.critical.flags.enabled)
> - tz->trips.critical.flags.enabled = 0;
> -
> - acpi_bus_generate_proc_event(tz->device, ACPI_THERMAL_NOTIFY_CRITICAL,
> - tz->trips.critical.flags.enabled);
> - acpi_bus_generate_netlink_event(tz->device->pnp.device_class,
> - dev_name(&tz->device->dev),
> - ACPI_THERMAL_NOTIFY_CRITICAL,
> - tz->trips.critical.flags.enabled);
> -
> - /* take no action if nocrt is set */
> - if(!nocrt) {
> - printk(KERN_EMERG
> - "Critical temperature reached (%ld C), shutting down.\n",
> - KELVIN_TO_CELSIUS(tz->temperature));
> - orderly_poweroff(true);
> - }
> -
> - return 0;
> -}
> -
> -static int acpi_thermal_hot(struct acpi_thermal *tz)
> -{
> - if (!tz || !tz->trips.hot.flags.valid)
> - return -EINVAL;
> -
> - if (tz->temperature >= tz->trips.hot.temperature) {
> - printk(KERN_WARNING PREFIX "Hot trip point\n");
> - tz->trips.hot.flags.enabled = 1;
> - } else if (tz->trips.hot.flags.enabled)
> - tz->trips.hot.flags.enabled = 0;
> -
> - acpi_bus_generate_proc_event(tz->device, ACPI_THERMAL_NOTIFY_HOT,
> - tz->trips.hot.flags.enabled);
> - acpi_bus_generate_netlink_event(tz->device->pnp.device_class,
> - dev_name(&tz->device->dev),
> - ACPI_THERMAL_NOTIFY_HOT,
> - tz->trips.hot.flags.enabled);
> -
> - /* TBD: Call user-mode "sleep(S4)" function if nocrt is cleared */
> -
> - return 0;
> -}
> -
> -static void acpi_thermal_passive(struct acpi_thermal *tz)
> -{
> - int result = 1;
> - struct acpi_thermal_passive *passive = NULL;
> - int trend = 0;
> - int i = 0;
> -
> -
> - if (!tz || !tz->trips.passive.flags.valid)
> - return;
> -
> - passive = &(tz->trips.passive);
> -
> - /*
> - * Above Trip?
> - * -----------
> - * Calculate the thermal trend (using the passive cooling equation)
> - * and modify the performance limit for all passive cooling devices
> - * accordingly. Note that we assume symmetry.
> - */
> - if (tz->temperature >= passive->temperature) {
> - trend =
> - (passive->tc1 * (tz->temperature - tz->last_temperature)) +
> - (passive->tc2 * (tz->temperature - passive->temperature));
> - ACPI_DEBUG_PRINT((ACPI_DB_INFO,
> - "trend[%d]=(tc1[%lu]*(tmp[%lu]-last[%lu]))+(tc2[%lu]*(tmp[%lu]-psv[%lu]))\n",
> - trend, passive->tc1, tz->temperature,
> - tz->last_temperature, passive->tc2,
> - tz->temperature, passive->temperature));
> - passive->flags.enabled = 1;
> - /* Heating up? */
> - if (trend > 0)
> - for (i = 0; i < passive->devices.count; i++)
> - acpi_processor_set_thermal_limit(passive->
> - devices.
> - handles[i],
> - ACPI_PROCESSOR_LIMIT_INCREMENT);
> - /* Cooling off? */
> - else if (trend < 0) {
> - for (i = 0; i < passive->devices.count; i++)
> - /*
> - * assume that we are on highest
> - * freq/lowest thrott and can leave
> - * passive mode, even in error case
> - */
> - if (!acpi_processor_set_thermal_limit
> - (passive->devices.handles[i],
> - ACPI_PROCESSOR_LIMIT_DECREMENT))
> - result = 0;
> - /*
> - * Leave cooling mode, even if the temp might
> - * higher than trip point This is because some
> - * machines might have long thermal polling
> - * frequencies (tsp) defined. We will fall back
> - * into passive mode in next cycle (probably quicker)
> - */
> - if (result) {
> - passive->flags.enabled = 0;
> - ACPI_DEBUG_PRINT((ACPI_DB_INFO,
> - "Disabling passive cooling, still above threshold,"
> - " but we are cooling down\n"));
> - }
> - }
> - return;
> - }
> -
> - /*
> - * Below Trip?
> - * -----------
> - * Implement passive cooling hysteresis to slowly increase performance
> - * and avoid thrashing around the passive trip point. Note that we
> - * assume symmetry.
> - */
> - if (!passive->flags.enabled)
> - return;
> - for (i = 0; i < passive->devices.count; i++)
> - if (!acpi_processor_set_thermal_limit
> - (passive->devices.handles[i],
> - ACPI_PROCESSOR_LIMIT_DECREMENT))
> - result = 0;
> - if (result) {
> - passive->flags.enabled = 0;
> - ACPI_DEBUG_PRINT((ACPI_DB_INFO,
> - "Disabling passive cooling (zone is cool)\n"));
> - }
> -}
> -
> -static void acpi_thermal_active(struct acpi_thermal *tz)
> -{
> - int result = 0;
> - struct acpi_thermal_active *active = NULL;
> - int i = 0;
> - int j = 0;
> - unsigned long maxtemp = 0;
> -
> -
> - if (!tz)
> - return;
> -
> - for (i = 0; i < ACPI_THERMAL_MAX_ACTIVE; i++) {
> - active = &(tz->trips.active[i]);
> - if (!active || !active->flags.valid)
> - break;
> - if (tz->temperature >= active->temperature) {
> - /*
> - * Above Threshold?
> - * ----------------
> - * If not already enabled, turn ON all cooling devices
> - * associated with this active threshold.
> - */
> - if (active->temperature > maxtemp)
> - tz->state.active_index = i;
> - maxtemp = active->temperature;
> - if (active->flags.enabled)
> - continue;
> - for (j = 0; j < active->devices.count; j++) {
> - result =
> - acpi_bus_set_power(active->devices.
> - handles[j],
> - ACPI_STATE_D0);
> - if (result) {
> - printk(KERN_WARNING PREFIX
> - "Unable to turn cooling device [%p] 'on'\n",
> - active->devices.
> - handles[j]);
> - continue;
> - }
> - active->flags.enabled = 1;
> - ACPI_DEBUG_PRINT((ACPI_DB_INFO,
> - "Cooling device [%p] now 'on'\n",
> - active->devices.handles[j]));
> - }
> - continue;
> - }
> - if (!active->flags.enabled)
> - continue;
> - /*
> - * Below Threshold?
> - * ----------------
> - * Turn OFF all cooling devices associated with this
> - * threshold.
> - */
> - for (j = 0; j < active->devices.count; j++) {
> - result = acpi_bus_set_power(active->devices.handles[j],
> - ACPI_STATE_D3);
> - if (result) {
> - printk(KERN_WARNING PREFIX
> - "Unable to turn cooling device [%p] 'off'\n",
> - active->devices.handles[j]);
> - continue;
> - }
> - active->flags.enabled = 0;
> - ACPI_DEBUG_PRINT((ACPI_DB_INFO,
> - "Cooling device [%p] now 'off'\n",
> - active->devices.handles[j]));
> - }
> - }
> -}
> -
> -static void acpi_thermal_check(void *context);
> -
> -static void acpi_thermal_run(unsigned long data)
> -{
> - struct acpi_thermal *tz = (struct acpi_thermal *)data;
> - if (!tz->zombie)
> - acpi_os_execute(OSL_GPE_HANDLER, acpi_thermal_check, (void *)data);
> -}
> -
> -static void acpi_thermal_active_off(void *data)
> -{
> - int result = 0;
> - struct acpi_thermal *tz = data;
> - int i = 0;
> - int j = 0;
> - struct acpi_thermal_active *active = NULL;
> -
> - if (!tz) {
> - printk(KERN_ERR PREFIX "Invalid (NULL) context\n");
> - return;
> - }
> -
> - result = acpi_thermal_get_temperature(tz);
> - if (result)
> - return;
> -
> - for (i = 0; i < ACPI_THERMAL_MAX_ACTIVE; i++) {
> - active = &(tz->trips.active[i]);
> - if (!active || !active->flags.valid)
> - break;
> - if (tz->temperature >= active->temperature) {
> - /*
> - * If the thermal temperature is greater than the
> - * active threshod, unnecessary to turn off the
> - * the active cooling device.
> - */
> - continue;
> - }
> - /*
> - * Below Threshold?
> - * ----------------
> - * Turn OFF all cooling devices associated with this
> - * threshold.
> - */
> - for (j = 0; j < active->devices.count; j++)
> - result = acpi_bus_set_power(active->devices.handles[j],
> - ACPI_STATE_D3);
> - }
> -}
> -
> static void acpi_thermal_check(void *data)
> {
> - int result = 0;
> struct acpi_thermal *tz = data;
> - unsigned long sleep_time = 0;
> - unsigned long timeout_jiffies = 0;
> - int i = 0;
> - struct acpi_thermal_state state;
> -
> -
> - if (!tz) {
> - printk(KERN_ERR PREFIX "Invalid (NULL) context\n");
> - return;
> - }
> -
> - /* Check if someone else is already running */
> - if (!mutex_trylock(&tz->lock))
> - return;
> -
> - state = tz->state;
> -
> - result = acpi_thermal_get_temperature(tz);
> - if (result)
> - goto unlock;
> -
> - if (!tz->tz_enabled)
> - goto unlock;
> -
> - memset(&tz->state, 0, sizeof(tz->state));
> -
> - /*
> - * Check Trip Points
> - * -----------------
> - * Compare the current temperature to the trip point values to see
> - * if we've entered one of the thermal policy states. Note that
> - * this function determines when a state is entered, but the
> - * individual policy decides when it is exited (e.g. hysteresis).
> - */
> - if (tz->trips.critical.flags.valid)
> - state.critical |=
> - (tz->temperature >= tz->trips.critical.temperature);
> - if (tz->trips.hot.flags.valid)
> - state.hot |= (tz->temperature >= tz->trips.hot.temperature);
> - if (tz->trips.passive.flags.valid)
> - state.passive |=
> - (tz->temperature >= tz->trips.passive.temperature);
> - for (i = 0; i < ACPI_THERMAL_MAX_ACTIVE; i++)
> - if (tz->trips.active[i].flags.valid)
> - state.active |=
> - (tz->temperature >=
> - tz->trips.active[i].temperature);
> -
> - /*
> - * Invoke Policy
> - * -------------
> - * Separated from the above check to allow individual policy to
> - * determine when to exit a given state.
> - */
> - if (state.critical)
> - acpi_thermal_critical(tz);
> - if (state.hot)
> - acpi_thermal_hot(tz);
> - if (state.passive)
> - acpi_thermal_passive(tz);
> - if (state.active)
> - acpi_thermal_active(tz);
>
> - /*
> - * Calculate State
> - * ---------------
> - * Again, separated from the above two to allow independent policy
> - * decisions.
> - */
> - tz->state.critical = tz->trips.critical.flags.enabled;
> - tz->state.hot = tz->trips.hot.flags.enabled;
> - tz->state.passive = tz->trips.passive.flags.enabled;
> - tz->state.active = 0;
> - for (i = 0; i < ACPI_THERMAL_MAX_ACTIVE; i++)
> - tz->state.active |= tz->trips.active[i].flags.enabled;
> -
> - /*
> - * Calculate Sleep Time
> - * --------------------
> - * If we're in the passive state, use _TSP's value. Otherwise
> - * use the default polling frequency (e.g. _TZP). If no polling
> - * frequency is specified then we'll wait forever (at least until
> - * a thermal event occurs). Note that _TSP and _TZD values are
> - * given in 1/10th seconds (we must covert to milliseconds).
> - */
> - if (tz->state.passive) {
> - sleep_time = tz->trips.passive.tsp * 100;
> - timeout_jiffies = jiffies + (HZ * sleep_time) / 1000;
> - } else if (tz->polling_frequency > 0) {
> - sleep_time = tz->polling_frequency * 100;
> - timeout_jiffies = round_jiffies(jiffies + (HZ * sleep_time) / 1000);
> - }
> -
> - ACPI_DEBUG_PRINT((ACPI_DB_INFO, "%s: temperature[%lu] sleep[%lu]\n",
> - tz->name, tz->temperature, sleep_time));
> -
> - /*
> - * Schedule Next Poll
> - * ------------------
> - */
> - if (!sleep_time) {
> - if (timer_pending(&(tz->timer)))
> - del_timer(&(tz->timer));
> - } else {
> - if (timer_pending(&(tz->timer)))
> - mod_timer(&(tz->timer), timeout_jiffies);
> - else {
> - tz->timer.data = (unsigned long)tz;
> - tz->timer.function = acpi_thermal_run;
> - tz->timer.expires = timeout_jiffies;
> - add_timer(&(tz->timer));
> - }
> - }
> - unlock:
> - mutex_unlock(&tz->lock);
> + thermal_zone_device_update(tz->thermal_zone);
> }
>
> /* sys I/F for generic thermal sysfs support */
> @@ -1114,6 +742,29 @@ static int thermal_get_crit_temp(struct thermal_zone_device *thermal,
> return -EINVAL;
> }
>
> +static int thermal_notify(struct thermal_zone_device *thermal, int trip,
> + enum thermal_trip_type trip_type)
> +{
> + u8 type = 0;
> + struct acpi_thermal *tz = thermal->devdata;
> +
> + if (trip_type == THERMAL_TRIP_CRITICAL)
> + type = ACPI_THERMAL_NOTIFY_CRITICAL;
> + else if (trip_type == THERMAL_TRIP_HOT)
> + type = ACPI_THERMAL_NOTIFY_HOT;
> + else
> + return 0;
> +
> + acpi_bus_generate_proc_event(tz->device, type, 1);
> + acpi_bus_generate_netlink_event(tz->device->pnp.device_class,
> + tz->device->dev.bus_id, type, 1);
> +
> + if (trip_type == THERMAL_TRIP_CRITICAL && nocrt)
> + return 1;
> +
> + return 0;
> +}
> +
> typedef int (*cb)(struct thermal_zone_device *, int,
> struct thermal_cooling_device *);
> static int acpi_thermal_cooling_device_cb(struct thermal_zone_device *thermal,
> @@ -1206,6 +857,7 @@ static struct thermal_zone_device_ops acpi_thermal_zone_ops = {
> .get_trip_type = thermal_get_trip_type,
> .get_trip_temp = thermal_get_trip_temp,
> .get_crit_temp = thermal_get_crit_temp,
> + .notify = thermal_notify,
> };
>
> static int acpi_thermal_register_thermal_zone(struct acpi_thermal *tz)
> @@ -1226,8 +878,21 @@ static int acpi_thermal_register_thermal_zone(struct acpi_thermal *tz)
>
> for (i = 0; i < ACPI_THERMAL_MAX_ACTIVE &&
> tz->trips.active[i].flags.valid; i++, trips++);
> - tz->thermal_zone = thermal_zone_device_register("acpitz",
> - trips, tz, &acpi_thermal_zone_ops);
> +
> + if (tz->trips.passive.flags.valid)
> + tz->thermal_zone =
> + thermal_zone_device_register("acpitz", trips, tz,
> + &acpi_thermal_zone_ops,
> + tz->trips.passive.tc1,
> + tz->trips.passive.tc2,
> + tz->trips.passive.tsp*100,
> + tz->polling_frequency*100);
> + else
> + tz->thermal_zone =
> + thermal_zone_device_register("acpitz", trips, tz,
> + &acpi_thermal_zone_ops,
> + 0, 0, 0,
> + tz->polling_frequency);
> if (IS_ERR(tz->thermal_zone))
> return -ENODEV;
>
> @@ -1459,13 +1124,13 @@ static int acpi_thermal_polling_seq_show(struct seq_file *seq, void *offset)
> if (!tz)
> goto end;
>
> - if (!tz->polling_frequency) {
> + if (!tz->thermal_zone->polling_delay) {
> seq_puts(seq, "<polling disabled>\n");
> goto end;
> }
>
> - seq_printf(seq, "polling frequency: %lu seconds\n",
> - (tz->polling_frequency / 10));
> + seq_printf(seq, "polling frequency: %d seconds\n",
> + (tz->thermal_zone->polling_delay / 1000));
>
> end:
> return 0;
> @@ -1695,12 +1360,6 @@ static int acpi_thermal_add(struct acpi_device *device)
> if (result)
> goto unregister_thermal_zone;
>
> - init_timer(&tz->timer);
> -
> - acpi_thermal_active_off(tz);
> -
> - acpi_thermal_check(tz);
> -
> status = acpi_install_notify_handler(device->handle,
> ACPI_DEVICE_NOTIFY,
> acpi_thermal_notify, tz);
> @@ -1729,36 +1388,15 @@ static int acpi_thermal_remove(struct acpi_device *device, int type)
> acpi_status status = AE_OK;
> struct acpi_thermal *tz = NULL;
>
> -
> if (!device || !acpi_driver_data(device))
> return -EINVAL;
>
> tz = acpi_driver_data(device);
>
> - /* avoid timer adding new defer task */
> - tz->zombie = 1;
> - /* wait for running timer (on other CPUs) finish */
> - del_timer_sync(&(tz->timer));
> - /* synchronize deferred task */
> - acpi_os_wait_events_complete(NULL);
> - /* deferred task may reinsert timer */
> - del_timer_sync(&(tz->timer));
> -
> status = acpi_remove_notify_handler(device->handle,
> ACPI_DEVICE_NOTIFY,
> acpi_thermal_notify);
>
> - /* Terminate policy */
> - if (tz->trips.passive.flags.valid && tz->trips.passive.flags.enabled) {
> - tz->trips.passive.flags.enabled = 0;
> - acpi_thermal_passive(tz);
> - }
> - if (tz->trips.active[0].flags.valid
> - && tz->trips.active[0].flags.enabled) {
> - tz->trips.active[0].flags.enabled = 0;
> - acpi_thermal_active(tz);
> - }
> -
> acpi_thermal_remove_fs(device);
> acpi_thermal_unregister_thermal_zone(tz);
> mutex_destroy(&tz->lock);
> diff --git a/drivers/thermal/thermal_sys.c b/drivers/thermal/thermal_sys.c
> index 7bcf322..ac0f91f 100644
> --- a/drivers/thermal/thermal_sys.c
> +++ b/drivers/thermal/thermal_sys.c
> @@ -30,6 +30,7 @@
> #include <linux/idr.h>
> #include <linux/thermal.h>
> #include <linux/spinlock.h>
> +#include <linux/reboot.h>
>
> MODULE_AUTHOR("Zhang Rui");
> MODULE_DESCRIPTION("Generic thermal management sysfs support");
> @@ -517,6 +518,97 @@ thermal_remove_hwmon_sysfs(struct thermal_zone_device *tz)
> }
> #endif
>
> +static void thermal_zone_device_set_polling(struct thermal_zone_device *tz,
> + int delay)
> +{
> + cancel_delayed_work(&(tz->poll_queue));
> +
> + if (!delay)
> + return;
> +
> + if (delay > 1000)
> + schedule_delayed_work(&(tz->poll_queue),
> + round_jiffies(msecs_to_jiffies(delay)));
> + else
> + schedule_delayed_work(&(tz->poll_queue),
> + msecs_to_jiffies(delay));
> +}
> +
> +static void thermal_zone_device_passive(struct thermal_zone_device *tz,
> + int temp, int trip_temp, int trip)
> +{
> + int trend = 0;
> + struct thermal_cooling_device_instance *instance;
> + struct thermal_cooling_device *cdev;
> + long state, max_state;
> +
> + /*
> + * Above Trip?
> + * -----------
> + * Calculate the thermal trend (using the passive cooling equation)
> + * and modify the performance limit for all passive cooling devices
> + * accordingly. Note that we assume symmetry.
> + */
> + if (temp >= trip_temp) {
> + tz->passive = true;
> +
> + trend = (tz->tc1 * (temp - tz->last_temperature)) +
> + (tz->tc2 * (temp - trip_temp));
> +
> + /* Heating up? */
> + if (trend > 0) {
> + list_for_each_entry(instance, &tz->cooling_devices,
> + node) {
> + if (instance->trip != trip)
> + continue;
> + cdev = instance->cdev;
> + cdev->ops->get_cur_state(cdev, &state);
> + cdev->ops->get_max_state(cdev, &max_state);
> + if (state++ < max_state)
> + cdev->ops->set_cur_state(cdev, state);
> + }
> + } else if (trend < 0) { /* Cooling off? */
> + list_for_each_entry(instance, &tz->cooling_devices,
> + node) {
> + if (instance->trip != trip)
> + continue;
> + cdev = instance->cdev;
> + cdev->ops->get_cur_state(cdev, &state);
> + cdev->ops->get_max_state(cdev, &max_state);
> + if (state > 0)
> + cdev->ops->set_cur_state(cdev, --state);
> + }
> + }
> + return;
> + }
> +
> + /*
> + * Below Trip?
> + * -----------
> + * Implement passive cooling hysteresis to slowly increase performance
> + * and avoid thrashing around the passive trip point. Note that we
> + * assume symmetry.
> + */
> + list_for_each_entry(instance, &tz->cooling_devices, node) {
> + if (instance->trip != trip)
> + continue;
> + cdev = instance->cdev;
> + cdev->ops->get_cur_state(cdev, &state);
> + cdev->ops->get_max_state(cdev, &max_state);
> + if (state > 0)
> + cdev->ops->set_cur_state(cdev, --state);
> + if (state == 0)
> + tz->passive = false;
> + }
> +}
> +
> +static void thermal_zone_device_check(struct work_struct *work)
> +{
> + struct thermal_zone_device *tz = container_of(work, struct
> + thermal_zone_device,
> + poll_queue.work);
> + thermal_zone_device_update(tz);
> +}
>
> /**
> * thermal_zone_bind_cooling_device - bind a cooling device to a thermal zone
> @@ -787,20 +879,101 @@ void thermal_cooling_device_unregister(struct
> EXPORT_SYMBOL(thermal_cooling_device_unregister);
>
> /**
> + * thermal_zone_device_update - force an update of a thermal zone's state
> + * @ttz: the thermal zone to update
> + */
> +
> +void thermal_zone_device_update(struct thermal_zone_device *tz)
> +{
> + int count, ret = 0;
> + long temp, trip_temp;
> + enum thermal_trip_type trip_type;
> + struct thermal_cooling_device_instance *instance;
> + struct thermal_cooling_device *cdev;
> +
> + mutex_lock(&tz->lock);
> +
> + tz->ops->get_temp(tz, &temp);
> +
> + for (count = 0; count < tz->trips; count++) {
> + tz->ops->get_trip_type(tz, count, &trip_type);
> + tz->ops->get_trip_temp(tz, count, &trip_temp);
> +
> + switch (trip_type) {
> + case THERMAL_TRIP_CRITICAL:
> + if (temp > trip_temp) {
> + if (tz->ops->notify)
> + ret = tz->ops->notify(tz, count,
> + trip_type);
> + if (!ret) {
> + printk(KERN_EMERG
> + "Critical temperature reached (%ld C), shutting down.\n",
> + temp/1000);
> + orderly_poweroff(true);
> + }
> + }
> + break;
> + case THERMAL_TRIP_HOT:
> + if (temp > trip_temp)
> + if (tz->ops->notify)
> + tz->ops->notify(tz, count, trip_type);
> + break;
> + case THERMAL_TRIP_ACTIVE:
> + list_for_each_entry(instance, &tz->cooling_devices,
> + node) {
> + if (instance->trip != count)
> + continue;
> +
> + cdev = instance->cdev;
> +
> + if (temp > trip_temp)
> + cdev->ops->set_cur_state(cdev, 1);
> + else
> + cdev->ops->set_cur_state(cdev, 0);
> + }
> + break;
> + case THERMAL_TRIP_PASSIVE:
> + if (temp > trip_temp || tz->passive)
> + thermal_zone_device_passive(tz, temp,
> + trip_temp, count);
> + break;
> + }
> + }
> + tz->last_temperature = temp;
> + if (tz->passive)
> + thermal_zone_device_set_polling(tz, tz->passive_delay);
> + else if (tz->polling_delay)
> + thermal_zone_device_set_polling(tz, tz->polling_delay);
> + mutex_unlock(&tz->lock);
> +}
> +EXPORT_SYMBOL(thermal_zone_device_update);
> +
> +/**
> * 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
> * @devdata: private device data
> * @ops: standard thermal zone device callbacks
> + * @tc1: thermal coefficient 1 for passive calculations
> + * @tc2: thermal coefficient 2 for passive calculations
> + * @passive_delay: number of milliseconds to wait between polls when
> + * performing passive cooling
> + * @polling_delay: number of milliseconds to wait between polls when checking
> + * whether trip points have been crossed (0 for interrupt
> + * driven systems)
> *
> * thermal_zone_device_unregister() must be called when the device is no
> - * longer needed.
> + * longer needed. The passive cooling formula uses tc1 and tc2 as described in
> + * section 11.1.5.1 of the ACPI specification 3.0.
> */
> struct thermal_zone_device *thermal_zone_device_register(char *type,
> int trips,
> void *devdata, struct
> thermal_zone_device_ops
> - *ops)
> + *ops, int tc1, int
> + tc2,
> + int passive_delay,
> + int polling_delay)
> {
> struct thermal_zone_device *tz;
> struct thermal_cooling_device *pos;
> @@ -834,6 +1007,11 @@ struct thermal_zone_device *thermal_zone_device_register(char *type,
> tz->device.class = &thermal_class;
> tz->devdata = devdata;
> tz->trips = trips;
> + tz->tc1 = tc1;
> + tz->tc2 = tc2;
> + tz->passive_delay = passive_delay;
> + tz->polling_delay = polling_delay;
> +
> sprintf(tz->device.bus_id, "thermal_zone%d", tz->id);
> result = device_register(&tz->device);
> if (result) {
> @@ -879,6 +1057,10 @@ struct thermal_zone_device *thermal_zone_device_register(char *type,
> }
> mutex_unlock(&thermal_list_lock);
>
> + INIT_DELAYED_WORK(&(tz->poll_queue), thermal_zone_device_check);
> +
> + thermal_zone_device_update(tz);
> +
> if (!result)
> return tz;
>
> @@ -918,6 +1100,8 @@ void thermal_zone_device_unregister(struct thermal_zone_device *tz)
> tz->ops->unbind(tz, cdev);
> mutex_unlock(&thermal_list_lock);
>
> + thermal_zone_device_set_polling(tz, 0);
> +
> if (tz->type[0])
> device_remove_file(&tz->device, &dev_attr_type);
> device_remove_file(&tz->device, &dev_attr_temp);
> diff --git a/include/linux/thermal.h b/include/linux/thermal.h
> index 4cb3292..a81c615 100644
> --- a/include/linux/thermal.h
> +++ b/include/linux/thermal.h
> @@ -27,6 +27,7 @@
>
> #include <linux/idr.h>
> #include <linux/device.h>
> +#include <linux/workqueue.h>
>
> struct thermal_zone_device;
> struct thermal_cooling_device;
> @@ -58,6 +59,8 @@ struct thermal_zone_device_ops {
> int (*get_trip_temp) (struct thermal_zone_device *, int,
> unsigned long *);
> int (*get_crit_temp) (struct thermal_zone_device *, unsigned long *);
> + int (*notify) (struct thermal_zone_device *, int,
> + enum thermal_trip_type);
> };
>
> struct thermal_cooling_device_ops {
> @@ -104,11 +107,18 @@ struct thermal_zone_device {
> struct device device;
> void *devdata;
> int trips;
> + int tc1;
> + int tc2;
> + int passive_delay;
> + int polling_delay;
> + int last_temperature;
> + bool passive;
> struct thermal_zone_device_ops *ops;
> struct list_head cooling_devices;
> struct idr idr;
> struct mutex lock; /* protect cooling devices list */
> struct list_head node;
> + struct delayed_work poll_queue;
> #if defined(CONFIG_THERMAL_HWMON)
> struct list_head hwmon_node;
> struct thermal_hwmon_device *hwmon;
> @@ -120,13 +130,16 @@ struct thermal_zone_device {
> struct thermal_zone_device *thermal_zone_device_register(char *, int, void *,
> struct
> thermal_zone_device_ops
> - *);
> + *, int tc1, int tc2,
> + int passive_freq,
> + int polling_freq);
> void thermal_zone_device_unregister(struct thermal_zone_device *);
>
> int thermal_zone_bind_cooling_device(struct thermal_zone_device *, int,
> struct thermal_cooling_device *);
> int thermal_zone_unbind_cooling_device(struct thermal_zone_device *, int,
> struct thermal_cooling_device *);
> +void thermal_zone_device_update(struct thermal_zone_device *);
> struct thermal_cooling_device *thermal_cooling_device_register(char *, void *,
> struct
> thermal_cooling_device_ops
>
> --
> Matthew Garrett | mjg59@srcf.ucam.org
^ permalink raw reply [flat|nested] 19+ messages in thread
* Re: [PATCH] acpi: move thermal trip handling to generic thermal layer
2008-12-08 6:59 ` [PATCH] acpi: move thermal trip handling to generic thermal layer Zhang Rui
@ 2008-12-08 12:59 ` Matthew Garrett
2008-12-17 3:02 ` Zhang Rui
0 siblings, 1 reply; 19+ messages in thread
From: Matthew Garrett @ 2008-12-08 12:59 UTC (permalink / raw)
To: Zhang Rui; +Cc: lenb@kernel.org, linux-acpi@vger.kernel.org, Thomas, Sujith
On Mon, Dec 08, 2008 at 02:59:00PM +0800, Zhang Rui wrote:
> On Thu, 2008-12-04 at 01:55 +0800, Matthew Garrett wrote:
> > The ACPI code currently carries its own thermal trip handling, meaning that
> > any other thermal implementation will need to reimplement it. Move the code
> > to the generic thermal layer.
> >
> Are these ACPI stuffs generic enough to be ported to the generic thermal
> driver?
> e.g. the tc1, tc2, tsp, they are mentioned in the ACPI spec,
> so my question is if the thermal zones than ACPI still have these
> concepts?
They're needed if you want to implement any sort of sensible
implementation of passive cooling. They might not be expressed in quite
the same way, but the basic concept is identical.
^ permalink raw reply [flat|nested] 19+ messages in thread
* Re: [PATCH] acpi: move thermal trip handling to generic thermal layer
2008-12-08 12:59 ` Matthew Garrett
@ 2008-12-17 3:02 ` Zhang Rui
2008-12-17 3:12 ` Matthew Garrett
0 siblings, 1 reply; 19+ messages in thread
From: Zhang Rui @ 2008-12-17 3:02 UTC (permalink / raw)
To: Matthew Garrett
Cc: lenb@kernel.org, linux-acpi@vger.kernel.org, Thomas, Sujith
On Mon, 2008-12-08 at 20:59 +0800, Matthew Garrett wrote:
> On Mon, Dec 08, 2008 at 02:59:00PM +0800, Zhang Rui wrote:
> > On Thu, 2008-12-04 at 01:55 +0800, Matthew Garrett wrote:
> > > The ACPI code currently carries its own thermal trip handling, meaning that
> > > any other thermal implementation will need to reimplement it. Move the code
> > > to the generic thermal layer.
> > >
> > Are these ACPI stuffs generic enough to be ported to the generic thermal
> > driver?
> > e.g. the tc1, tc2, tsp, they are mentioned in the ACPI spec,
> > so my question is if the thermal zones than ACPI still have these
> > concepts?
>
> They're needed if you want to implement any sort of sensible
> implementation of passive cooling. They might not be expressed in quite
> the same way, but the basic concept is identical.
Seeing tc1, tc2, tsp under /sys/class/thermal/ is not good because we
don't want to make the generic thermal driver too ACPI specific, before
we've really concluded some basic concepts for passive cooling.
so why not do this after we have another generic thermal user with
passive cooling support?
thanks,
rui
^ permalink raw reply [flat|nested] 19+ messages in thread
* Re: [PATCH] acpi: move thermal trip handling to generic thermal layer
2008-12-17 3:02 ` Zhang Rui
@ 2008-12-17 3:12 ` Matthew Garrett
2009-01-16 13:48 ` Thomas Renninger
0 siblings, 1 reply; 19+ messages in thread
From: Matthew Garrett @ 2008-12-17 3:12 UTC (permalink / raw)
To: Zhang Rui; +Cc: lenb@kernel.org, linux-acpi@vger.kernel.org, Thomas, Sujith
On Wed, Dec 17, 2008 at 11:02:18AM +0800, Zhang Rui wrote:
> On Mon, 2008-12-08 at 20:59 +0800, Matthew Garrett wrote:
> > They're needed if you want to implement any sort of sensible
> > implementation of passive cooling. They might not be expressed in quite
> > the same way, but the basic concept is identical.
>
> Seeing tc1, tc2, tsp under /sys/class/thermal/ is not good because we
> don't want to make the generic thermal driver too ACPI specific, before
> we've really concluded some basic concepts for passive cooling.
> so why not do this after we have another generic thermal user with
> passive cooling support?
They're not exposed in /sys/class, and I don't think doing so is a
sensible thing to do. If you know values for the hardware in question
then they should be supplied by the firmware. But even so, the generic
thermal layer needs a way of implementing passive cooling. Doing so
involves deriving a formula to describe the behaviour of the system
around the passive trip level, and the best used implementation of that
in Linux at the moment is the one described in the ACPI spec. I don't
see any real need to generate new terms to describe well documented
concepts, even if other implementations don't use ACPI.
--
Matthew Garrett | mjg59@srcf.ucam.org
^ permalink raw reply [flat|nested] 19+ messages in thread
* Re: [PATCH] thermal: support forcing support for passive cooling
2008-12-03 18:00 ` [PATCH] thermal: support forcing support for passive cooling Matthew Garrett
@ 2008-12-17 3:19 ` Zhang Rui
2008-12-28 15:22 ` Matthew Garrett
2009-02-20 23:45 ` Len Brown
2 siblings, 0 replies; 19+ messages in thread
From: Zhang Rui @ 2008-12-17 3:19 UTC (permalink / raw)
To: Matthew Garrett
Cc: lenb@kernel.org, linux-acpi@vger.kernel.org, Thomas, Sujith
Len,
yes it's true that it's polling-based which may be malfunction in some
cases.
but this mechanism works only in a system overheating/critical stage.
if the polling-base passive trip point doesn't work, the system goes to
critical shutdown just like it does without this patch.
But once it works, it can help a lot.
As it won't bring any side effect, I think this is a good enhancement
of the current thermal management.
Any comments on this?
thanks,
rui
On Thu, 2008-12-04 at 02:00 +0800, Matthew Garrett wrote:
> Due to poor thermal design or Linux driving hardware outside its thermal
> envelope, some systems will reach critical temperature and shut down
> under high load. This patch adds support for forcing a polling-based
> passive trip point if the firmware doesn't provide one. The assumption
> is made that the processor is the most practical means to reduce the
> dynamic heat generation, so hitting the passive thermal limit will cause
> the CPU to be throttled until the temperature stabalises around the
> defined value.
>
> UI is provided via a "passive" sysfs entry in the thermal zone
> directory. It accepts a decimal value in millidegrees celsius, or "0" to
> disable the functionality. Default behaviour is for this functionality
> to be disabled.
>
> Signed-off-by: Matthew Garrett <mjg@redhat.com>
> ---
>
> Depends on the code to move the trip handling into the generic layer.
> Tested this on a couple of machines and it seems to work well - a
> logical followup might be to allow the passive trip point to be
> overridden on machines that provide it.
>
> drivers/thermal/thermal_sys.c | 77 +++++++++++++++++++++++++++++++++++++++++
> include/linux/thermal.h | 1 +
> 2 files changed, 78 insertions(+), 0 deletions(-)
>
> diff --git a/drivers/thermal/thermal_sys.c b/drivers/thermal/thermal_sys.c
> index ac0f91f..c5351e5 100644
> --- a/drivers/thermal/thermal_sys.c
> +++ b/drivers/thermal/thermal_sys.c
> @@ -214,9 +214,69 @@ trip_point_temp_show(struct device *dev, struct device_attribute *attr,
> return sprintf(buf, "%ld\n", temperature);
> }
>
> +static ssize_t
> +passive_store(struct device *dev, struct device_attribute *attr,
> + const char *buf, size_t count)
> +{
> + struct thermal_zone_device *tz = to_thermal_zone(dev);
> + struct thermal_cooling_device *cdev = NULL;
> + int state;
> +
> + if (!sscanf(buf, "%d\n", &state))
> + return -EINVAL;
> +
> + if (state && !tz->forced_passive) {
> + mutex_lock(&thermal_list_lock);
> + list_for_each_entry(cdev, &thermal_cdev_list, node) {
> + if (!strncmp("Processor", cdev->type,
> + sizeof("Processor")))
> + thermal_zone_bind_cooling_device(tz,
> + THERMAL_TRIPS_NONE,
> + cdev);
> + }
> + mutex_unlock(&thermal_list_lock);
> + } else if (!state && tz->forced_passive) {
> + mutex_lock(&thermal_list_lock);
> + list_for_each_entry(cdev, &thermal_cdev_list, node) {
> + if (!strncmp("Processor", cdev->type,
> + sizeof("Processor")))
> + thermal_zone_unbind_cooling_device(tz,
> + THERMAL_TRIPS_NONE,
> + cdev);
> + }
> + mutex_unlock(&thermal_list_lock);
> + }
> +
> + tz->tc1 = 1;
> + tz->tc2 = 1;
> +
> + if (!tz->passive_delay)
> + tz->passive_delay = 1000;
> +
> + if (!tz->polling_delay)
> + tz->polling_delay = 10000;
> +
> + tz->forced_passive = state;
> +
> + thermal_zone_device_update(tz);
> +
> + return count;
> +}
> +
> +static ssize_t
> +passive_show(struct device *dev, struct device_attribute *attr,
> + char *buf)
> +{
> + struct thermal_zone_device *tz = to_thermal_zone(dev);
> +
> + return sprintf(buf, "%d\n", tz->forced_passive);
> +}
> +
> static DEVICE_ATTR(type, 0444, type_show, NULL);
> static DEVICE_ATTR(temp, 0444, temp_show, NULL);
> static DEVICE_ATTR(mode, 0644, mode_show, mode_store);
> +static DEVICE_ATTR(passive, S_IRUGO | S_IWUSR, passive_show, \
> + passive_store);
>
> static struct device_attribute trip_point_attrs[] = {
> __ATTR(trip_point_0_type, 0444, trip_point_type_show, NULL),
> @@ -939,6 +999,11 @@ void thermal_zone_device_update(struct thermal_zone_device *tz)
> break;
> }
> }
> +
> + if (tz->forced_passive)
> + thermal_zone_device_passive(tz, temp, tz->forced_passive,
> + THERMAL_TRIPS_NONE);
> +
> tz->last_temperature = temp;
> if (tz->passive)
> thermal_zone_device_set_polling(tz, tz->passive_delay);
> @@ -977,8 +1042,10 @@ struct thermal_zone_device *thermal_zone_device_register(char *type,
> {
> struct thermal_zone_device *tz;
> struct thermal_cooling_device *pos;
> + enum thermal_trip_type trip_type;
> int result;
> int count;
> + int passive=0;
>
> if (strlen(type) >= THERMAL_NAME_LENGTH)
> return ERR_PTR(-EINVAL);
> @@ -1041,8 +1108,18 @@ struct thermal_zone_device *thermal_zone_device_register(char *type,
> TRIP_POINT_ATTR_ADD(&tz->device, count, result);
> if (result)
> goto unregister;
> + tz->ops->get_trip_type(tz, count, &trip_type);
> + if (trip_type == THERMAL_TRIP_PASSIVE)
> + passive=1;
> }
>
> + if (!passive)
> + result = device_create_file(&tz->device,
> + &dev_attr_passive);
> +
> + if (result)
> + goto unregister;
> +
> result = thermal_add_hwmon_sysfs(tz);
> if (result)
> goto unregister;
> diff --git a/include/linux/thermal.h b/include/linux/thermal.h
> index a81c615..1de8b9e 100644
> --- a/include/linux/thermal.h
> +++ b/include/linux/thermal.h
> @@ -113,6 +113,7 @@ struct thermal_zone_device {
> int polling_delay;
> int last_temperature;
> bool passive;
> + unsigned int forced_passive;
> struct thermal_zone_device_ops *ops;
> struct list_head cooling_devices;
> struct idr idr;
>
--
To unsubscribe from this list: send the line "unsubscribe linux-acpi" 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] 19+ messages in thread
* Re: [PATCH] thermal: support forcing support for passive cooling
2008-12-03 18:00 ` [PATCH] thermal: support forcing support for passive cooling Matthew Garrett
2008-12-17 3:19 ` Zhang Rui
@ 2008-12-28 15:22 ` Matthew Garrett
2009-01-06 22:42 ` Matthew Garrett
2009-02-20 23:45 ` Len Brown
2 siblings, 1 reply; 19+ messages in thread
From: Matthew Garrett @ 2008-12-28 15:22 UTC (permalink / raw)
To: lenb; +Cc: linux-acpi, rui.zhang, sujith.thomas
Hi Len,
I'd be keen on getting these into .29. Is there any problem with them as
it stands?
--
Matthew Garrett | mjg59@srcf.ucam.org
^ permalink raw reply [flat|nested] 19+ messages in thread
* Re: [PATCH] thermal: support forcing support for passive cooling
2008-12-28 15:22 ` Matthew Garrett
@ 2009-01-06 22:42 ` Matthew Garrett
2009-02-13 1:21 ` Matthew Garrett
0 siblings, 1 reply; 19+ messages in thread
From: Matthew Garrett @ 2009-01-06 22:42 UTC (permalink / raw)
To: lenb; +Cc: linux-acpi, rui.zhang, sujith.thomas
On Sun, Dec 28, 2008 at 03:22:40PM +0000, Matthew Garrett wrote:
> Hi Len,
>
> I'd be keen on getting these into .29. Is there any problem with them as
> it stands?
Ping?
--
Matthew Garrett | mjg59@srcf.ucam.org
^ permalink raw reply [flat|nested] 19+ messages in thread
* Re: [PATCH] thermal: use integers rather than strings for thermal values
2008-11-28 2:52 ` Zhang Rui
@ 2009-01-16 13:44 ` Thomas Renninger
0 siblings, 0 replies; 19+ messages in thread
From: Thomas Renninger @ 2009-01-16 13:44 UTC (permalink / raw)
To: Zhang Rui
Cc: Matthew Garrett, lenb@kernel.org, linux-acpi@vger.kernel.org,
Thomas, Sujith
Hi,
can we get this patch for 2.6.29, please.
On Friday 28 November 2008 03:52:41 Zhang Rui wrote:
> On Fri, 2008-11-28 at 01:49 +0800, Matthew Garrett wrote:
> > The thermal API currently uses strings to pass values to userspace. This
> > makes it difficult to use from within the kernel. Change the interface to
> > use integers and fix up the ACPI consumers.
> >
> >
> > Signed-off-by: Matthew Garrett <mjg@redhat.com>
>
> Signed-off-by: Zhang Rui <rui.zhang@intel.com>
Signed-off-by: Thomas Renninger <trenn@suse.de>
Thanks,
Thomas
>
> > ---
> >
> > Resend - managed to get Len's address wrong the first time.
> >
> > drivers/acpi/fan.c | 20 +++++---
> > drivers/acpi/processor_thermal.c | 20 +++++----
> > drivers/acpi/thermal.c | 80
> > +++++++++++++++++++++------------ drivers/acpi/video.c | 22
> > +++++----
> > drivers/misc/intel_menlow.c | 29 ++++--------
> > drivers/thermal/thermal_sys.c | 91
> > ++++++++++++++++++++++++++++++++----- include/linux/thermal.h |
> > 32 ++++++++++---
> > 7 files changed, 198 insertions(+), 96 deletions(-)
> >
> > diff --git a/drivers/acpi/fan.c b/drivers/acpi/fan.c
> > index eaaee16..ae41cf3 100644
> > --- a/drivers/acpi/fan.c
> > +++ b/drivers/acpi/fan.c
> > @@ -68,31 +68,35 @@ static struct acpi_driver acpi_fan_driver = {
> > };
> >
> > /* thermal cooling device callbacks */
> > -static int fan_get_max_state(struct thermal_cooling_device *cdev, char
> > *buf) +static int fan_get_max_state(struct thermal_cooling_device *cdev,
> > unsigned long + *state)
> > {
> > /* ACPI fan device only support two states: ON/OFF */
> > - return sprintf(buf, "1\n");
> > + *state = 1;
> > + return 0;
> > }
> >
> > -static int fan_get_cur_state(struct thermal_cooling_device *cdev, char
> > *buf) +static int fan_get_cur_state(struct thermal_cooling_device *cdev,
> > unsigned long + *state)
> > {
> > struct acpi_device *device = cdev->devdata;
> > - int state;
> > int result;
> > + int acpi_state;
> >
> > if (!device)
> > return -EINVAL;
> >
> > - result = acpi_bus_get_power(device->handle, &state);
> > + result = acpi_bus_get_power(device->handle, &acpi_state);
> > if (result)
> > return result;
> >
> > - return sprintf(buf, "%s\n", state == ACPI_STATE_D3 ? "0" :
> > - (state == ACPI_STATE_D0 ? "1" : "unknown"));
> > + *state = (acpi_state == ACPI_STATE_D3 ? 0 :
> > + (acpi_state == ACPI_STATE_D0 ? 1 : -1));
> > + return 0;
> > }
> >
> > static int
> > -fan_set_cur_state(struct thermal_cooling_device *cdev, unsigned int
> > state) +fan_set_cur_state(struct thermal_cooling_device *cdev, unsigned
> > long state) {
> > struct acpi_device *device = cdev->devdata;
> > int result;
> > diff --git a/drivers/acpi/processor_thermal.c
> > b/drivers/acpi/processor_thermal.c index b1eb376..0e47e29 100644
> > --- a/drivers/acpi/processor_thermal.c
> > +++ b/drivers/acpi/processor_thermal.c
> > @@ -373,7 +373,8 @@ static int acpi_processor_max_state(struct
> > acpi_processor *pr) return max_state;
> > }
> > static int
> > -processor_get_max_state(struct thermal_cooling_device *cdev, char *buf)
> > +processor_get_max_state(struct thermal_cooling_device *cdev,
> > + unsigned long *state)
> > {
> > struct acpi_device *device = cdev->devdata;
> > struct acpi_processor *pr = acpi_driver_data(device);
> > @@ -381,28 +382,29 @@ processor_get_max_state(struct
> > thermal_cooling_device *cdev, char *buf) if (!device || !pr)
> > return -EINVAL;
> >
> > - return sprintf(buf, "%d\n", acpi_processor_max_state(pr));
> > + *state = acpi_processor_max_state(pr);
> > + return 0;
> > }
> >
> > static int
> > -processor_get_cur_state(struct thermal_cooling_device *cdev, char *buf)
> > +processor_get_cur_state(struct thermal_cooling_device *cdev,
> > + unsigned long *cur_state)
> > {
> > struct acpi_device *device = cdev->devdata;
> > struct acpi_processor *pr = acpi_driver_data(device);
> > - int cur_state;
> >
> > if (!device || !pr)
> > return -EINVAL;
> >
> > - cur_state = cpufreq_get_cur_state(pr->id);
> > + *cur_state = cpufreq_get_cur_state(pr->id);
> > if (pr->flags.throttling)
> > - cur_state += pr->throttling.state;
> > -
> > - return sprintf(buf, "%d\n", cur_state);
> > + *cur_state += pr->throttling.state;
> > + return 0;
> > }
> >
> > static int
> > -processor_set_cur_state(struct thermal_cooling_device *cdev, unsigned
> > int state) +processor_set_cur_state(struct thermal_cooling_device *cdev,
> > + unsigned long state)
> > {
> > struct acpi_device *device = cdev->devdata;
> > struct acpi_processor *pr = acpi_driver_data(device);
> > diff --git a/drivers/acpi/thermal.c b/drivers/acpi/thermal.c
> > index 073ff09..f24c7cc 100644
> > --- a/drivers/acpi/thermal.c
> > +++ b/drivers/acpi/thermal.c
> > @@ -946,7 +946,8 @@ static void acpi_thermal_check(void *data)
> > /* sys I/F for generic thermal sysfs support */
> > #define KELVIN_TO_MILLICELSIUS(t) (t * 100 - 273200)
> >
> > -static int thermal_get_temp(struct thermal_zone_device *thermal, char
> > *buf) +static int thermal_get_temp(struct thermal_zone_device *thermal, +
> > unsigned long *temp)
> > {
> > struct acpi_thermal *tz = thermal->devdata;
> > int result;
> > @@ -958,25 +959,28 @@ static int thermal_get_temp(struct
> > thermal_zone_device *thermal, char *buf) if (result)
> > return result;
> >
> > - return sprintf(buf, "%ld\n",
> > KELVIN_TO_MILLICELSIUS(tz->temperature)); + *temp =
> > KELVIN_TO_MILLICELSIUS(tz->temperature);
> > + return 0;
> > }
> >
> > static const char enabled[] = "kernel";
> > static const char disabled[] = "user";
> > static int thermal_get_mode(struct thermal_zone_device *thermal,
> > - char *buf)
> > + enum thermal_device_mode *mode)
> > {
> > struct acpi_thermal *tz = thermal->devdata;
> >
> > if (!tz)
> > return -EINVAL;
> >
> > - return sprintf(buf, "%s\n", tz->tz_enabled ?
> > - enabled : disabled);
> > + *mode = tz->tz_enabled ? THERMAL_DEVICE_ENABLED :
> > + THERMAL_DEVICE_DISABLED;
> > +
> > + return 0;
> > }
> >
> > static int thermal_set_mode(struct thermal_zone_device *thermal,
> > - const char *buf)
> > + enum thermal_device_mode mode)
> > {
> > struct acpi_thermal *tz = thermal->devdata;
> > int enable;
> > @@ -987,9 +991,9 @@ static int thermal_set_mode(struct
> > thermal_zone_device *thermal, /*
> > * enable/disable thermal management from ACPI thermal driver
> > */
> > - if (!strncmp(buf, enabled, sizeof enabled - 1))
> > + if (mode == THERMAL_DEVICE_ENABLED)
> > enable = 1;
> > - else if (!strncmp(buf, disabled, sizeof disabled - 1))
> > + else if (mode == THERMAL_DEVICE_DISABLED)
> > enable = 0;
> > else
> > return -EINVAL;
> > @@ -1005,7 +1009,7 @@ static int thermal_set_mode(struct
> > thermal_zone_device *thermal, }
> >
> > static int thermal_get_trip_type(struct thermal_zone_device *thermal,
> > - int trip, char *buf)
> > + int trip, enum thermal_trip_type *type)
> > {
> > struct acpi_thermal *tz = thermal->devdata;
> > int i;
> > @@ -1014,27 +1018,35 @@ static int thermal_get_trip_type(struct
> > thermal_zone_device *thermal, return -EINVAL;
> >
> > if (tz->trips.critical.flags.valid) {
> > - if (!trip)
> > - return sprintf(buf, "critical\n");
> > + if (!trip) {
> > + *type = THERMAL_TRIP_CRITICAL;
> > + return 0;
> > + }
> > trip--;
> > }
> >
> > if (tz->trips.hot.flags.valid) {
> > - if (!trip)
> > - return sprintf(buf, "hot\n");
> > + if (!trip) {
> > + *type = THERMAL_TRIP_HOT;
> > + return 0;
> > + }
> > trip--;
> > }
> >
> > if (tz->trips.passive.flags.valid) {
> > - if (!trip)
> > - return sprintf(buf, "passive\n");
> > + if (!trip) {
> > + *type = THERMAL_TRIP_PASSIVE;
> > + return 0;
> > + }
> > trip--;
> > }
> >
> > for (i = 0; i < ACPI_THERMAL_MAX_ACTIVE &&
> > tz->trips.active[i].flags.valid; i++) {
> > - if (!trip)
> > - return sprintf(buf, "active%d\n", i);
> > + if (!trip) {
> > + *type = THERMAL_TRIP_ACTIVE;
> > + return 0;
> > + }
> > trip--;
> > }
> >
> > @@ -1042,7 +1054,7 @@ static int thermal_get_trip_type(struct
> > thermal_zone_device *thermal, }
> >
> > static int thermal_get_trip_temp(struct thermal_zone_device *thermal,
> > - int trip, char *buf)
> > + int trip, unsigned long *temp)
> > {
> > struct acpi_thermal *tz = thermal->devdata;
> > int i;
> > @@ -1051,31 +1063,39 @@ static int thermal_get_trip_temp(struct
> > thermal_zone_device *thermal, return -EINVAL;
> >
> > if (tz->trips.critical.flags.valid) {
> > - if (!trip)
> > - return sprintf(buf, "%ld\n",
> > KELVIN_TO_MILLICELSIUS( -
> > tz->trips.critical.temperature)); + if (!trip) {
> > + *temp = KELVIN_TO_MILLICELSIUS(
> > + tz->trips.critical.temperature);
> > + return 0;
> > + }
> > trip--;
> > }
> >
> > if (tz->trips.hot.flags.valid) {
> > - if (!trip)
> > - return sprintf(buf, "%ld\n",
> > KELVIN_TO_MILLICELSIUS( -
> > tz->trips.hot.temperature)); + if (!trip) {
> > + *temp = KELVIN_TO_MILLICELSIUS(
> > + tz->trips.hot.temperature);
> > + return 0;
> > + }
> > trip--;
> > }
> >
> > if (tz->trips.passive.flags.valid) {
> > - if (!trip)
> > - return sprintf(buf, "%ld\n",
> > KELVIN_TO_MILLICELSIUS( -
> > tz->trips.passive.temperature)); + if (!trip) {
> > + *temp = KELVIN_TO_MILLICELSIUS(
> > + tz->trips.passive.temperature);
> > + return 0;
> > + }
> > trip--;
> > }
> >
> > for (i = 0; i < ACPI_THERMAL_MAX_ACTIVE &&
> > tz->trips.active[i].flags.valid; i++) {
> > - if (!trip)
> > - return sprintf(buf, "%ld\n",
> > KELVIN_TO_MILLICELSIUS( -
> > tz->trips.active[i].temperature)); + if (!trip) {
> > + *temp = KELVIN_TO_MILLICELSIUS(
> > + tz->trips.active[i].temperature);
> > + return 0;
> > + }
> > trip--;
> > }
> >
> > diff --git a/drivers/acpi/video.c b/drivers/acpi/video.c
> > index baa4419..5b2f1f3 100644
> > --- a/drivers/acpi/video.c
> > +++ b/drivers/acpi/video.c
> > @@ -357,32 +357,36 @@ static struct output_properties
> > acpi_output_properties = {
> >
> >
> > /* thermal cooling device callbacks */
> > -static int video_get_max_state(struct thermal_cooling_device *cdev, char
> > *buf) +static int video_get_max_state(struct thermal_cooling_device
> > *cdev, unsigned + long *state)
> > {
> > struct acpi_device *device = cdev->devdata;
> > struct acpi_video_device *video = acpi_driver_data(device);
> >
> > - return sprintf(buf, "%d\n", video->brightness->count - 3);
> > + *state = video->brightness->count - 3;
> > + return 0;
> > }
> >
> > -static int video_get_cur_state(struct thermal_cooling_device *cdev, char
> > *buf) +static int video_get_cur_state(struct thermal_cooling_device
> > *cdev, unsigned + long *state)
> > {
> > struct acpi_device *device = cdev->devdata;
> > struct acpi_video_device *video = acpi_driver_data(device);
> > unsigned long long level;
> > - int state;
> > + int offset;
> >
> > acpi_video_device_lcd_get_level_current(video, &level);
> > - for (state = 2; state < video->brightness->count; state++)
> > - if (level == video->brightness->levels[state])
> > - return sprintf(buf, "%d\n",
> > - video->brightness->count - state -
> > 1); + for (offset = 2; offset < video->brightness->count; offset++)
> > + if (level == video->brightness->levels[offset]) { +
> > *state = video->brightness->count - offset - 1; +
> > return 0;
> > + }
> >
> > return -EINVAL;
> > }
> >
> > static int
> > -video_set_cur_state(struct thermal_cooling_device *cdev, unsigned int
> > state) +video_set_cur_state(struct thermal_cooling_device *cdev, unsigned
> > long state) {
> > struct acpi_device *device = cdev->devdata;
> > struct acpi_video_device *video = acpi_driver_data(device);
> > diff --git a/drivers/misc/intel_menlow.c b/drivers/misc/intel_menlow.c
> > index 27b7662..29432a5 100644
> > --- a/drivers/misc/intel_menlow.c
> > +++ b/drivers/misc/intel_menlow.c
> > @@ -57,8 +57,8 @@ MODULE_LICENSE("GPL");
> > * In that case max_cstate would be n-1
> > * GTHS returning '0' would mean that no bandwidth control states are
> > supported */
> > -static int memory_get_int_max_bandwidth(struct thermal_cooling_device
> > *cdev, - unsigned long *max_state)
> > +static int memory_get_max_bandwidth(struct thermal_cooling_device *cdev,
> > + unsigned long *max_state)
> > {
> > struct acpi_device *device = cdev->devdata;
> > acpi_handle handle = device->handle;
> > @@ -83,22 +83,12 @@ static int memory_get_int_max_bandwidth(struct
> > thermal_cooling_device *cdev, return 0;
> > }
> >
> > -static int memory_get_max_bandwidth(struct thermal_cooling_device *cdev,
> > - char *buf)
> > -{
> > - unsigned long value;
> > - if (memory_get_int_max_bandwidth(cdev, &value))
> > - return -EINVAL;
> > -
> > - return sprintf(buf, "%ld\n", value);
> > -}
> > -
> > static int memory_get_cur_bandwidth(struct thermal_cooling_device *cdev,
> > - char *buf)
> > + unsigned long *value)
> > {
> > struct acpi_device *device = cdev->devdata;
> > acpi_handle handle = device->handle;
> > - unsigned long long value;
> > + unsigned long long result;
> > struct acpi_object_list arg_list;
> > union acpi_object arg;
> > acpi_status status = AE_OK;
> > @@ -108,15 +98,16 @@ static int memory_get_cur_bandwidth(struct
> > thermal_cooling_device *cdev, arg.type = ACPI_TYPE_INTEGER;
> > arg.integer.value = MEMORY_ARG_CUR_BANDWIDTH;
> > status = acpi_evaluate_integer(handle, MEMORY_GET_BANDWIDTH,
> > - &arg_list, &value);
> > + &arg_list, &result);
> > if (ACPI_FAILURE(status))
> > return -EFAULT;
> >
> > - return sprintf(buf, "%llu\n", value);
> > + *value = result;
> > + return 0;
> > }
> >
> > static int memory_set_cur_bandwidth(struct thermal_cooling_device *cdev,
> > - unsigned int state)
> > + unsigned long state)
> > {
> > struct acpi_device *device = cdev->devdata;
> > acpi_handle handle = device->handle;
> > @@ -126,7 +117,7 @@ static int memory_set_cur_bandwidth(struct
> > thermal_cooling_device *cdev, unsigned long long temp;
> > unsigned long max_state;
> >
> > - if (memory_get_int_max_bandwidth(cdev, &max_state))
> > + if (memory_get_max_bandwidth(cdev, &max_state))
> > return -EFAULT;
> >
> > if (state > max_state)
> > @@ -142,7 +133,7 @@ static int memory_set_cur_bandwidth(struct
> > thermal_cooling_device *cdev, &temp);
> >
> > printk(KERN_INFO
> > - "Bandwidth value was %d: status is %d\n", state, status);
> > + "Bandwidth value was %ld: status is %d\n", state, status);
> > if (ACPI_FAILURE(status))
> > return -EFAULT;
> >
> > diff --git a/drivers/thermal/thermal_sys.c
> > b/drivers/thermal/thermal_sys.c index fe07462..7bcf322 100644
> > --- a/drivers/thermal/thermal_sys.c
> > +++ b/drivers/thermal/thermal_sys.c
> > @@ -104,22 +104,36 @@ static ssize_t
> > temp_show(struct device *dev, struct device_attribute *attr, char *buf)
> > {
> > struct thermal_zone_device *tz = to_thermal_zone(dev);
> > + long temperature;
> > + int ret;
> >
> > if (!tz->ops->get_temp)
> > return -EPERM;
> >
> > - return tz->ops->get_temp(tz, buf);
> > + ret = tz->ops->get_temp(tz, &temperature);
> > +
> > + if (ret)
> > + return ret;
> > +
> > + return sprintf(buf, "%ld\n", temperature);
> > }
> >
> > static ssize_t
> > mode_show(struct device *dev, struct device_attribute *attr, char *buf)
> > {
> > struct thermal_zone_device *tz = to_thermal_zone(dev);
> > + enum thermal_device_mode mode;
> > + int result;
> >
> > if (!tz->ops->get_mode)
> > return -EPERM;
> >
> > - return tz->ops->get_mode(tz, buf);
> > + result = tz->ops->get_mode(tz, &mode);
> > + if (result)
> > + return result;
> > +
> > + return sprintf(buf, "%s\n", mode == THERMAL_DEVICE_ENABLED ?
> > "enabled" + : "disabled");
> > }
> >
> > static ssize_t
> > @@ -132,7 +146,13 @@ mode_store(struct device *dev, struct
> > device_attribute *attr, if (!tz->ops->set_mode)
> > return -EPERM;
> >
> > - result = tz->ops->set_mode(tz, buf);
> > + if (!strncmp(buf, "enabled", sizeof("enabled")))
> > + result = tz->ops->set_mode(tz, THERMAL_DEVICE_ENABLED);
> > + else if (!strncmp(buf, "disabled", sizeof("disabled")))
> > + result = tz->ops->set_mode(tz, THERMAL_DEVICE_DISABLED);
> > + else
> > + result = -EINVAL;
> > +
> > if (result)
> > return result;
> >
> > @@ -144,7 +164,8 @@ trip_point_type_show(struct device *dev, struct
> > device_attribute *attr, char *buf)
> > {
> > struct thermal_zone_device *tz = to_thermal_zone(dev);
> > - int trip;
> > + enum thermal_trip_type type;
> > + int trip, result;
> >
> > if (!tz->ops->get_trip_type)
> > return -EPERM;
> > @@ -152,7 +173,22 @@ trip_point_type_show(struct device *dev, struct
> > device_attribute *attr, if (!sscanf(attr->attr.name,
> > "trip_point_%d_type", &trip)) return -EINVAL;
> >
> > - return tz->ops->get_trip_type(tz, trip, buf);
> > + result = tz->ops->get_trip_type(tz, trip, &type);
> > + if (result)
> > + return result;
> > +
> > + switch (type) {
> > + case THERMAL_TRIP_CRITICAL:
> > + return sprintf(buf, "critical");
> > + case THERMAL_TRIP_HOT:
> > + return sprintf(buf, "hot");
> > + case THERMAL_TRIP_PASSIVE:
> > + return sprintf(buf, "passive");
> > + case THERMAL_TRIP_ACTIVE:
> > + return sprintf(buf, "active");
> > + default:
> > + return sprintf(buf, "unknown");
> > + }
> > }
> >
> > static ssize_t
> > @@ -160,7 +196,8 @@ trip_point_temp_show(struct device *dev, struct
> > device_attribute *attr, char *buf)
> > {
> > struct thermal_zone_device *tz = to_thermal_zone(dev);
> > - int trip;
> > + int trip, ret;
> > + long temperature;
> >
> > if (!tz->ops->get_trip_temp)
> > return -EPERM;
> > @@ -168,7 +205,12 @@ trip_point_temp_show(struct device *dev, struct
> > device_attribute *attr, if (!sscanf(attr->attr.name,
> > "trip_point_%d_temp", &trip)) return -EINVAL;
> >
> > - return tz->ops->get_trip_temp(tz, trip, buf);
> > + ret = tz->ops->get_trip_temp(tz, trip, &temperature);
> > +
> > + if (ret)
> > + return ret;
> > +
> > + return sprintf(buf, "%ld\n", temperature);
> > }
> >
> > static DEVICE_ATTR(type, 0444, type_show, NULL);
> > @@ -236,8 +278,13 @@ thermal_cooling_device_max_state_show(struct device
> > *dev, struct device_attribute *attr, char *buf) {
> > struct thermal_cooling_device *cdev = to_cooling_device(dev);
> > + unsigned long state;
> > + int ret;
> >
> > - return cdev->ops->get_max_state(cdev, buf);
> > + ret = cdev->ops->get_max_state(cdev, &state);
> > + if (ret)
> > + return ret;
> > + return sprintf(buf, "%ld\n", state);
> > }
> >
> > static ssize_t
> > @@ -245,8 +292,13 @@ thermal_cooling_device_cur_state_show(struct device
> > *dev, struct device_attribute *attr, char *buf) {
> > struct thermal_cooling_device *cdev = to_cooling_device(dev);
> > + unsigned long state;
> > + int ret;
> >
> > - return cdev->ops->get_cur_state(cdev, buf);
> > + ret = cdev->ops->get_cur_state(cdev, &state);
> > + if (ret)
> > + return ret;
> > + return sprintf(buf, "%ld\n", state);
> > }
> >
> > static ssize_t
> > @@ -255,10 +307,10 @@ thermal_cooling_device_cur_state_store(struct
> > device *dev, const char *buf, size_t count) {
> > struct thermal_cooling_device *cdev = to_cooling_device(dev);
> > - int state;
> > + unsigned long state;
> > int result;
> >
> > - if (!sscanf(buf, "%d\n", &state))
> > + if (!sscanf(buf, "%ld\n", &state))
> > return -EINVAL;
> >
> > if (state < 0)
> > @@ -312,13 +364,20 @@ static DEVICE_ATTR(name, 0444, name_show, NULL);
> > static ssize_t
> > temp_input_show(struct device *dev, struct device_attribute *attr, char
> > *buf) {
> > + long temperature;
> > + int ret;
> > struct thermal_hwmon_attr *hwmon_attr
> > = container_of(attr, struct thermal_hwmon_attr,
> > attr); struct thermal_zone_device *tz
> > = container_of(hwmon_attr, struct
> > thermal_zone_device, temp_input);
> >
> > - return tz->ops->get_temp(tz, buf);
> > + ret = tz->ops->get_temp(tz, &temperature);
> > +
> > + if (ret)
> > + return ret;
> > +
> > + return sprintf(buf, "%ld\n", temperature);
> > }
> >
> > static ssize_t
> > @@ -330,8 +389,14 @@ temp_crit_show(struct device *dev, struct
> > device_attribute *attr, struct thermal_zone_device *tz
> > = container_of(hwmon_attr, struct
> > thermal_zone_device, temp_crit);
> > + long temperature;
> > + int ret;
> > +
> > + ret = tz->ops->get_trip_temp(tz, 0, &temperature);
> > + if (ret)
> > + return ret;
> >
> > - return tz->ops->get_trip_temp(tz, 0, buf);
> > + return sprintf(buf, "%ld\n", temperature);
> > }
> >
> >
> > diff --git a/include/linux/thermal.h b/include/linux/thermal.h
> > index 917707e..4cb3292 100644
> > --- a/include/linux/thermal.h
> > +++ b/include/linux/thermal.h
> > @@ -31,23 +31,39 @@
> > struct thermal_zone_device;
> > struct thermal_cooling_device;
> >
> > +enum thermal_device_mode {
> > + THERMAL_DEVICE_DISABLED = 0,
> > + THERMAL_DEVICE_ENABLED,
> > +};
> > +
> > +enum thermal_trip_type {
> > + THERMAL_TRIP_ACTIVE = 0,
> > + THERMAL_TRIP_PASSIVE,
> > + THERMAL_TRIP_HOT,
> > + THERMAL_TRIP_CRITICAL,
> > +};
> > +
> > struct thermal_zone_device_ops {
> > int (*bind) (struct thermal_zone_device *,
> > struct thermal_cooling_device *);
> > int (*unbind) (struct thermal_zone_device *,
> > struct thermal_cooling_device *);
> > - int (*get_temp) (struct thermal_zone_device *, char *);
> > - int (*get_mode) (struct thermal_zone_device *, char *);
> > - int (*set_mode) (struct thermal_zone_device *, const char *);
> > - int (*get_trip_type) (struct thermal_zone_device *, int, char *);
> > - int (*get_trip_temp) (struct thermal_zone_device *, int, char *);
> > + int (*get_temp) (struct thermal_zone_device *, unsigned long *);
> > + int (*get_mode) (struct thermal_zone_device *,
> > + enum thermal_device_mode *);
> > + int (*set_mode) (struct thermal_zone_device *,
> > + enum thermal_device_mode);
> > + int (*get_trip_type) (struct thermal_zone_device *, int,
> > + enum thermal_trip_type *);
> > + int (*get_trip_temp) (struct thermal_zone_device *, int,
> > + unsigned long *);
> > int (*get_crit_temp) (struct thermal_zone_device *, unsigned long
> > *); };
> >
> > struct thermal_cooling_device_ops {
> > - int (*get_max_state) (struct thermal_cooling_device *, char *);
> > - int (*get_cur_state) (struct thermal_cooling_device *, char *);
> > - int (*set_cur_state) (struct thermal_cooling_device *, unsigned
> > int); + int (*get_max_state) (struct thermal_cooling_device *,
> > unsigned long *); + int (*get_cur_state) (struct
> > thermal_cooling_device *, unsigned long *); + int (*set_cur_state)
> > (struct thermal_cooling_device *, unsigned long); };
> >
> > #define THERMAL_TRIPS_NONE -1
> >
> > --
> > Matthew Garrett | mjg59@srcf.ucam.org
> > --
> > To unsubscribe from this list: send the line "unsubscribe linux-acpi" in
> > the body of a message to majordomo@vger.kernel.org
> > More majordomo info at http://vger.kernel.org/majordomo-info.html
>
> --
> To unsubscribe from this list: send the line "unsubscribe linux-acpi" 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] 19+ messages in thread
* Re: [PATCH] acpi: move thermal trip handling to generic thermal layer
2008-12-17 3:12 ` Matthew Garrett
@ 2009-01-16 13:48 ` Thomas Renninger
2009-02-20 16:53 ` Len Brown
0 siblings, 1 reply; 19+ messages in thread
From: Thomas Renninger @ 2009-01-16 13:48 UTC (permalink / raw)
To: Matthew Garrett
Cc: Zhang Rui, lenb@kernel.org, linux-acpi@vger.kernel.org,
Thomas, Sujith
On Wednesday 17 December 2008 04:12:15 Matthew Garrett wrote:
> On Wed, Dec 17, 2008 at 11:02:18AM +0800, Zhang Rui wrote:
> > On Mon, 2008-12-08 at 20:59 +0800, Matthew Garrett wrote:
> > > They're needed if you want to implement any sort of sensible
> > > implementation of passive cooling. They might not be expressed in quite
> > > the same way, but the basic concept is identical.
> >
> > Seeing tc1, tc2, tsp under /sys/class/thermal/ is not good because we
> > don't want to make the generic thermal driver too ACPI specific, before
> > we've really concluded some basic concepts for passive cooling.
> > so why not do this after we have another generic thermal user with
> > passive cooling support?
>
> They're not exposed in /sys/class, and I don't think doing so is a
> sensible thing to do. If you know values for the hardware in question
> then they should be supplied by the firmware. But even so, the generic
> thermal layer needs a way of implementing passive cooling. Doing so
> involves deriving a formula to describe the behaviour of the system
> around the passive trip level, and the best used implementation of that
> in Linux at the moment is the one described in the ACPI spec. I don't
> see any real need to generate new terms to describe well documented
> concepts, even if other implementations don't use ACPI.
If others need a specific algorithm, another (set of) callback function(s)
could be added later which would provide the possibility of
a platform specific override?
Thomas
^ permalink raw reply [flat|nested] 19+ messages in thread
* Re: [PATCH] thermal: support forcing support for passive cooling
2009-01-06 22:42 ` Matthew Garrett
@ 2009-02-13 1:21 ` Matthew Garrett
0 siblings, 0 replies; 19+ messages in thread
From: Matthew Garrett @ 2009-02-13 1:21 UTC (permalink / raw)
To: lenb; +Cc: linux-acpi, rui.zhang, sujith.thomas
On Tue, Jan 06, 2009 at 10:42:38PM +0000, Matthew Garrett wrote:
> On Sun, Dec 28, 2008 at 03:22:40PM +0000, Matthew Garrett wrote:
> > Hi Len,
> >
> > I'd be keen on getting these into .29. Is there any problem with them as
> > it stands?
>
> Ping?
Len? Looks like we're too late for .29, but I'd like to get some
indication whether you're happy to push these for .30.
--
Matthew Garrett | mjg59@srcf.ucam.org
^ permalink raw reply [flat|nested] 19+ messages in thread
* Re: [PATCH] thermal: use integers rather than strings for thermal values
2008-11-27 17:48 [PATCH] thermal: use integers rather than strings for thermal values Matthew Garrett
2008-11-27 17:49 ` Matthew Garrett
@ 2009-02-20 15:56 ` Len Brown
1 sibling, 0 replies; 19+ messages in thread
From: Len Brown @ 2009-02-20 15:56 UTC (permalink / raw)
To: Matthew Garrett; +Cc: linux-acpi, rui.zhang, sujith.thomas
applied
thanks
--
Len Brown, Intel Open Source Technology Center
On Thu, 27 Nov 2008, Matthew Garrett wrote:
> The thermal API currently uses strings to pass values to userspace. This
> makes it difficult to use from within the kernel. Change the interface
> to use integers and fix up the consumers.
>
> Signed-off-by: Matthew Garrett <mjg@redhat.com>
>
> ---
> drivers/acpi/fan.c | 20 +++++---
> drivers/acpi/processor_thermal.c | 20 +++++----
> drivers/acpi/thermal.c | 80 +++++++++++++++++++++------------
> drivers/acpi/video.c | 22 +++++----
> drivers/misc/intel_menlow.c | 29 ++++--------
> drivers/thermal/thermal_sys.c | 91 ++++++++++++++++++++++++++++++++-----
> include/linux/thermal.h | 32 ++++++++++---
> 7 files changed, 198 insertions(+), 96 deletions(-)
>
> diff --git a/drivers/acpi/fan.c b/drivers/acpi/fan.c
> index eaaee16..ae41cf3 100644
> --- a/drivers/acpi/fan.c
> +++ b/drivers/acpi/fan.c
> @@ -68,31 +68,35 @@ static struct acpi_driver acpi_fan_driver = {
> };
>
> /* thermal cooling device callbacks */
> -static int fan_get_max_state(struct thermal_cooling_device *cdev, char *buf)
> +static int fan_get_max_state(struct thermal_cooling_device *cdev, unsigned long
> + *state)
> {
> /* ACPI fan device only support two states: ON/OFF */
> - return sprintf(buf, "1\n");
> + *state = 1;
> + return 0;
> }
>
> -static int fan_get_cur_state(struct thermal_cooling_device *cdev, char *buf)
> +static int fan_get_cur_state(struct thermal_cooling_device *cdev, unsigned long
> + *state)
> {
> struct acpi_device *device = cdev->devdata;
> - int state;
> int result;
> + int acpi_state;
>
> if (!device)
> return -EINVAL;
>
> - result = acpi_bus_get_power(device->handle, &state);
> + result = acpi_bus_get_power(device->handle, &acpi_state);
> if (result)
> return result;
>
> - return sprintf(buf, "%s\n", state == ACPI_STATE_D3 ? "0" :
> - (state == ACPI_STATE_D0 ? "1" : "unknown"));
> + *state = (acpi_state == ACPI_STATE_D3 ? 0 :
> + (acpi_state == ACPI_STATE_D0 ? 1 : -1));
> + return 0;
> }
>
> static int
> -fan_set_cur_state(struct thermal_cooling_device *cdev, unsigned int state)
> +fan_set_cur_state(struct thermal_cooling_device *cdev, unsigned long state)
> {
> struct acpi_device *device = cdev->devdata;
> int result;
> diff --git a/drivers/acpi/processor_thermal.c b/drivers/acpi/processor_thermal.c
> index b1eb376..0e47e29 100644
> --- a/drivers/acpi/processor_thermal.c
> +++ b/drivers/acpi/processor_thermal.c
> @@ -373,7 +373,8 @@ static int acpi_processor_max_state(struct acpi_processor *pr)
> return max_state;
> }
> static int
> -processor_get_max_state(struct thermal_cooling_device *cdev, char *buf)
> +processor_get_max_state(struct thermal_cooling_device *cdev,
> + unsigned long *state)
> {
> struct acpi_device *device = cdev->devdata;
> struct acpi_processor *pr = acpi_driver_data(device);
> @@ -381,28 +382,29 @@ processor_get_max_state(struct thermal_cooling_device *cdev, char *buf)
> if (!device || !pr)
> return -EINVAL;
>
> - return sprintf(buf, "%d\n", acpi_processor_max_state(pr));
> + *state = acpi_processor_max_state(pr);
> + return 0;
> }
>
> static int
> -processor_get_cur_state(struct thermal_cooling_device *cdev, char *buf)
> +processor_get_cur_state(struct thermal_cooling_device *cdev,
> + unsigned long *cur_state)
> {
> struct acpi_device *device = cdev->devdata;
> struct acpi_processor *pr = acpi_driver_data(device);
> - int cur_state;
>
> if (!device || !pr)
> return -EINVAL;
>
> - cur_state = cpufreq_get_cur_state(pr->id);
> + *cur_state = cpufreq_get_cur_state(pr->id);
> if (pr->flags.throttling)
> - cur_state += pr->throttling.state;
> -
> - return sprintf(buf, "%d\n", cur_state);
> + *cur_state += pr->throttling.state;
> + return 0;
> }
>
> static int
> -processor_set_cur_state(struct thermal_cooling_device *cdev, unsigned int state)
> +processor_set_cur_state(struct thermal_cooling_device *cdev,
> + unsigned long state)
> {
> struct acpi_device *device = cdev->devdata;
> struct acpi_processor *pr = acpi_driver_data(device);
> diff --git a/drivers/acpi/thermal.c b/drivers/acpi/thermal.c
> index 073ff09..f24c7cc 100644
> --- a/drivers/acpi/thermal.c
> +++ b/drivers/acpi/thermal.c
> @@ -946,7 +946,8 @@ static void acpi_thermal_check(void *data)
> /* sys I/F for generic thermal sysfs support */
> #define KELVIN_TO_MILLICELSIUS(t) (t * 100 - 273200)
>
> -static int thermal_get_temp(struct thermal_zone_device *thermal, char *buf)
> +static int thermal_get_temp(struct thermal_zone_device *thermal,
> + unsigned long *temp)
> {
> struct acpi_thermal *tz = thermal->devdata;
> int result;
> @@ -958,25 +959,28 @@ static int thermal_get_temp(struct thermal_zone_device *thermal, char *buf)
> if (result)
> return result;
>
> - return sprintf(buf, "%ld\n", KELVIN_TO_MILLICELSIUS(tz->temperature));
> + *temp = KELVIN_TO_MILLICELSIUS(tz->temperature);
> + return 0;
> }
>
> static const char enabled[] = "kernel";
> static const char disabled[] = "user";
> static int thermal_get_mode(struct thermal_zone_device *thermal,
> - char *buf)
> + enum thermal_device_mode *mode)
> {
> struct acpi_thermal *tz = thermal->devdata;
>
> if (!tz)
> return -EINVAL;
>
> - return sprintf(buf, "%s\n", tz->tz_enabled ?
> - enabled : disabled);
> + *mode = tz->tz_enabled ? THERMAL_DEVICE_ENABLED :
> + THERMAL_DEVICE_DISABLED;
> +
> + return 0;
> }
>
> static int thermal_set_mode(struct thermal_zone_device *thermal,
> - const char *buf)
> + enum thermal_device_mode mode)
> {
> struct acpi_thermal *tz = thermal->devdata;
> int enable;
> @@ -987,9 +991,9 @@ static int thermal_set_mode(struct thermal_zone_device *thermal,
> /*
> * enable/disable thermal management from ACPI thermal driver
> */
> - if (!strncmp(buf, enabled, sizeof enabled - 1))
> + if (mode == THERMAL_DEVICE_ENABLED)
> enable = 1;
> - else if (!strncmp(buf, disabled, sizeof disabled - 1))
> + else if (mode == THERMAL_DEVICE_DISABLED)
> enable = 0;
> else
> return -EINVAL;
> @@ -1005,7 +1009,7 @@ static int thermal_set_mode(struct thermal_zone_device *thermal,
> }
>
> static int thermal_get_trip_type(struct thermal_zone_device *thermal,
> - int trip, char *buf)
> + int trip, enum thermal_trip_type *type)
> {
> struct acpi_thermal *tz = thermal->devdata;
> int i;
> @@ -1014,27 +1018,35 @@ static int thermal_get_trip_type(struct thermal_zone_device *thermal,
> return -EINVAL;
>
> if (tz->trips.critical.flags.valid) {
> - if (!trip)
> - return sprintf(buf, "critical\n");
> + if (!trip) {
> + *type = THERMAL_TRIP_CRITICAL;
> + return 0;
> + }
> trip--;
> }
>
> if (tz->trips.hot.flags.valid) {
> - if (!trip)
> - return sprintf(buf, "hot\n");
> + if (!trip) {
> + *type = THERMAL_TRIP_HOT;
> + return 0;
> + }
> trip--;
> }
>
> if (tz->trips.passive.flags.valid) {
> - if (!trip)
> - return sprintf(buf, "passive\n");
> + if (!trip) {
> + *type = THERMAL_TRIP_PASSIVE;
> + return 0;
> + }
> trip--;
> }
>
> for (i = 0; i < ACPI_THERMAL_MAX_ACTIVE &&
> tz->trips.active[i].flags.valid; i++) {
> - if (!trip)
> - return sprintf(buf, "active%d\n", i);
> + if (!trip) {
> + *type = THERMAL_TRIP_ACTIVE;
> + return 0;
> + }
> trip--;
> }
>
> @@ -1042,7 +1054,7 @@ static int thermal_get_trip_type(struct thermal_zone_device *thermal,
> }
>
> static int thermal_get_trip_temp(struct thermal_zone_device *thermal,
> - int trip, char *buf)
> + int trip, unsigned long *temp)
> {
> struct acpi_thermal *tz = thermal->devdata;
> int i;
> @@ -1051,31 +1063,39 @@ static int thermal_get_trip_temp(struct thermal_zone_device *thermal,
> return -EINVAL;
>
> if (tz->trips.critical.flags.valid) {
> - if (!trip)
> - return sprintf(buf, "%ld\n", KELVIN_TO_MILLICELSIUS(
> - tz->trips.critical.temperature));
> + if (!trip) {
> + *temp = KELVIN_TO_MILLICELSIUS(
> + tz->trips.critical.temperature);
> + return 0;
> + }
> trip--;
> }
>
> if (tz->trips.hot.flags.valid) {
> - if (!trip)
> - return sprintf(buf, "%ld\n", KELVIN_TO_MILLICELSIUS(
> - tz->trips.hot.temperature));
> + if (!trip) {
> + *temp = KELVIN_TO_MILLICELSIUS(
> + tz->trips.hot.temperature);
> + return 0;
> + }
> trip--;
> }
>
> if (tz->trips.passive.flags.valid) {
> - if (!trip)
> - return sprintf(buf, "%ld\n", KELVIN_TO_MILLICELSIUS(
> - tz->trips.passive.temperature));
> + if (!trip) {
> + *temp = KELVIN_TO_MILLICELSIUS(
> + tz->trips.passive.temperature);
> + return 0;
> + }
> trip--;
> }
>
> for (i = 0; i < ACPI_THERMAL_MAX_ACTIVE &&
> tz->trips.active[i].flags.valid; i++) {
> - if (!trip)
> - return sprintf(buf, "%ld\n", KELVIN_TO_MILLICELSIUS(
> - tz->trips.active[i].temperature));
> + if (!trip) {
> + *temp = KELVIN_TO_MILLICELSIUS(
> + tz->trips.active[i].temperature);
> + return 0;
> + }
> trip--;
> }
>
> diff --git a/drivers/acpi/video.c b/drivers/acpi/video.c
> index baa4419..5b2f1f3 100644
> --- a/drivers/acpi/video.c
> +++ b/drivers/acpi/video.c
> @@ -357,32 +357,36 @@ static struct output_properties acpi_output_properties = {
>
>
> /* thermal cooling device callbacks */
> -static int video_get_max_state(struct thermal_cooling_device *cdev, char *buf)
> +static int video_get_max_state(struct thermal_cooling_device *cdev, unsigned
> + long *state)
> {
> struct acpi_device *device = cdev->devdata;
> struct acpi_video_device *video = acpi_driver_data(device);
>
> - return sprintf(buf, "%d\n", video->brightness->count - 3);
> + *state = video->brightness->count - 3;
> + return 0;
> }
>
> -static int video_get_cur_state(struct thermal_cooling_device *cdev, char *buf)
> +static int video_get_cur_state(struct thermal_cooling_device *cdev, unsigned
> + long *state)
> {
> struct acpi_device *device = cdev->devdata;
> struct acpi_video_device *video = acpi_driver_data(device);
> unsigned long long level;
> - int state;
> + int offset;
>
> acpi_video_device_lcd_get_level_current(video, &level);
> - for (state = 2; state < video->brightness->count; state++)
> - if (level == video->brightness->levels[state])
> - return sprintf(buf, "%d\n",
> - video->brightness->count - state - 1);
> + for (offset = 2; offset < video->brightness->count; offset++)
> + if (level == video->brightness->levels[offset]) {
> + *state = video->brightness->count - offset - 1;
> + return 0;
> + }
>
> return -EINVAL;
> }
>
> static int
> -video_set_cur_state(struct thermal_cooling_device *cdev, unsigned int state)
> +video_set_cur_state(struct thermal_cooling_device *cdev, unsigned long state)
> {
> struct acpi_device *device = cdev->devdata;
> struct acpi_video_device *video = acpi_driver_data(device);
> diff --git a/drivers/misc/intel_menlow.c b/drivers/misc/intel_menlow.c
> index 27b7662..29432a5 100644
> --- a/drivers/misc/intel_menlow.c
> +++ b/drivers/misc/intel_menlow.c
> @@ -57,8 +57,8 @@ MODULE_LICENSE("GPL");
> * In that case max_cstate would be n-1
> * GTHS returning '0' would mean that no bandwidth control states are supported
> */
> -static int memory_get_int_max_bandwidth(struct thermal_cooling_device *cdev,
> - unsigned long *max_state)
> +static int memory_get_max_bandwidth(struct thermal_cooling_device *cdev,
> + unsigned long *max_state)
> {
> struct acpi_device *device = cdev->devdata;
> acpi_handle handle = device->handle;
> @@ -83,22 +83,12 @@ static int memory_get_int_max_bandwidth(struct thermal_cooling_device *cdev,
> return 0;
> }
>
> -static int memory_get_max_bandwidth(struct thermal_cooling_device *cdev,
> - char *buf)
> -{
> - unsigned long value;
> - if (memory_get_int_max_bandwidth(cdev, &value))
> - return -EINVAL;
> -
> - return sprintf(buf, "%ld\n", value);
> -}
> -
> static int memory_get_cur_bandwidth(struct thermal_cooling_device *cdev,
> - char *buf)
> + unsigned long *value)
> {
> struct acpi_device *device = cdev->devdata;
> acpi_handle handle = device->handle;
> - unsigned long long value;
> + unsigned long long result;
> struct acpi_object_list arg_list;
> union acpi_object arg;
> acpi_status status = AE_OK;
> @@ -108,15 +98,16 @@ static int memory_get_cur_bandwidth(struct thermal_cooling_device *cdev,
> arg.type = ACPI_TYPE_INTEGER;
> arg.integer.value = MEMORY_ARG_CUR_BANDWIDTH;
> status = acpi_evaluate_integer(handle, MEMORY_GET_BANDWIDTH,
> - &arg_list, &value);
> + &arg_list, &result);
> if (ACPI_FAILURE(status))
> return -EFAULT;
>
> - return sprintf(buf, "%llu\n", value);
> + *value = result;
> + return 0;
> }
>
> static int memory_set_cur_bandwidth(struct thermal_cooling_device *cdev,
> - unsigned int state)
> + unsigned long state)
> {
> struct acpi_device *device = cdev->devdata;
> acpi_handle handle = device->handle;
> @@ -126,7 +117,7 @@ static int memory_set_cur_bandwidth(struct thermal_cooling_device *cdev,
> unsigned long long temp;
> unsigned long max_state;
>
> - if (memory_get_int_max_bandwidth(cdev, &max_state))
> + if (memory_get_max_bandwidth(cdev, &max_state))
> return -EFAULT;
>
> if (state > max_state)
> @@ -142,7 +133,7 @@ static int memory_set_cur_bandwidth(struct thermal_cooling_device *cdev,
> &temp);
>
> printk(KERN_INFO
> - "Bandwidth value was %d: status is %d\n", state, status);
> + "Bandwidth value was %ld: status is %d\n", state, status);
> if (ACPI_FAILURE(status))
> return -EFAULT;
>
> diff --git a/drivers/thermal/thermal_sys.c b/drivers/thermal/thermal_sys.c
> index fe07462..7bcf322 100644
> --- a/drivers/thermal/thermal_sys.c
> +++ b/drivers/thermal/thermal_sys.c
> @@ -104,22 +104,36 @@ static ssize_t
> temp_show(struct device *dev, struct device_attribute *attr, char *buf)
> {
> struct thermal_zone_device *tz = to_thermal_zone(dev);
> + long temperature;
> + int ret;
>
> if (!tz->ops->get_temp)
> return -EPERM;
>
> - return tz->ops->get_temp(tz, buf);
> + ret = tz->ops->get_temp(tz, &temperature);
> +
> + if (ret)
> + return ret;
> +
> + return sprintf(buf, "%ld\n", temperature);
> }
>
> static ssize_t
> mode_show(struct device *dev, struct device_attribute *attr, char *buf)
> {
> struct thermal_zone_device *tz = to_thermal_zone(dev);
> + enum thermal_device_mode mode;
> + int result;
>
> if (!tz->ops->get_mode)
> return -EPERM;
>
> - return tz->ops->get_mode(tz, buf);
> + result = tz->ops->get_mode(tz, &mode);
> + if (result)
> + return result;
> +
> + return sprintf(buf, "%s\n", mode == THERMAL_DEVICE_ENABLED ? "enabled"
> + : "disabled");
> }
>
> static ssize_t
> @@ -132,7 +146,13 @@ mode_store(struct device *dev, struct device_attribute *attr,
> if (!tz->ops->set_mode)
> return -EPERM;
>
> - result = tz->ops->set_mode(tz, buf);
> + if (!strncmp(buf, "enabled", sizeof("enabled")))
> + result = tz->ops->set_mode(tz, THERMAL_DEVICE_ENABLED);
> + else if (!strncmp(buf, "disabled", sizeof("disabled")))
> + result = tz->ops->set_mode(tz, THERMAL_DEVICE_DISABLED);
> + else
> + result = -EINVAL;
> +
> if (result)
> return result;
>
> @@ -144,7 +164,8 @@ trip_point_type_show(struct device *dev, struct device_attribute *attr,
> char *buf)
> {
> struct thermal_zone_device *tz = to_thermal_zone(dev);
> - int trip;
> + enum thermal_trip_type type;
> + int trip, result;
>
> if (!tz->ops->get_trip_type)
> return -EPERM;
> @@ -152,7 +173,22 @@ trip_point_type_show(struct device *dev, struct device_attribute *attr,
> if (!sscanf(attr->attr.name, "trip_point_%d_type", &trip))
> return -EINVAL;
>
> - return tz->ops->get_trip_type(tz, trip, buf);
> + result = tz->ops->get_trip_type(tz, trip, &type);
> + if (result)
> + return result;
> +
> + switch (type) {
> + case THERMAL_TRIP_CRITICAL:
> + return sprintf(buf, "critical");
> + case THERMAL_TRIP_HOT:
> + return sprintf(buf, "hot");
> + case THERMAL_TRIP_PASSIVE:
> + return sprintf(buf, "passive");
> + case THERMAL_TRIP_ACTIVE:
> + return sprintf(buf, "active");
> + default:
> + return sprintf(buf, "unknown");
> + }
> }
>
> static ssize_t
> @@ -160,7 +196,8 @@ trip_point_temp_show(struct device *dev, struct device_attribute *attr,
> char *buf)
> {
> struct thermal_zone_device *tz = to_thermal_zone(dev);
> - int trip;
> + int trip, ret;
> + long temperature;
>
> if (!tz->ops->get_trip_temp)
> return -EPERM;
> @@ -168,7 +205,12 @@ trip_point_temp_show(struct device *dev, struct device_attribute *attr,
> if (!sscanf(attr->attr.name, "trip_point_%d_temp", &trip))
> return -EINVAL;
>
> - return tz->ops->get_trip_temp(tz, trip, buf);
> + ret = tz->ops->get_trip_temp(tz, trip, &temperature);
> +
> + if (ret)
> + return ret;
> +
> + return sprintf(buf, "%ld\n", temperature);
> }
>
> static DEVICE_ATTR(type, 0444, type_show, NULL);
> @@ -236,8 +278,13 @@ thermal_cooling_device_max_state_show(struct device *dev,
> struct device_attribute *attr, char *buf)
> {
> struct thermal_cooling_device *cdev = to_cooling_device(dev);
> + unsigned long state;
> + int ret;
>
> - return cdev->ops->get_max_state(cdev, buf);
> + ret = cdev->ops->get_max_state(cdev, &state);
> + if (ret)
> + return ret;
> + return sprintf(buf, "%ld\n", state);
> }
>
> static ssize_t
> @@ -245,8 +292,13 @@ thermal_cooling_device_cur_state_show(struct device *dev,
> struct device_attribute *attr, char *buf)
> {
> struct thermal_cooling_device *cdev = to_cooling_device(dev);
> + unsigned long state;
> + int ret;
>
> - return cdev->ops->get_cur_state(cdev, buf);
> + ret = cdev->ops->get_cur_state(cdev, &state);
> + if (ret)
> + return ret;
> + return sprintf(buf, "%ld\n", state);
> }
>
> static ssize_t
> @@ -255,10 +307,10 @@ thermal_cooling_device_cur_state_store(struct device *dev,
> const char *buf, size_t count)
> {
> struct thermal_cooling_device *cdev = to_cooling_device(dev);
> - int state;
> + unsigned long state;
> int result;
>
> - if (!sscanf(buf, "%d\n", &state))
> + if (!sscanf(buf, "%ld\n", &state))
> return -EINVAL;
>
> if (state < 0)
> @@ -312,13 +364,20 @@ static DEVICE_ATTR(name, 0444, name_show, NULL);
> static ssize_t
> temp_input_show(struct device *dev, struct device_attribute *attr, char *buf)
> {
> + long temperature;
> + int ret;
> struct thermal_hwmon_attr *hwmon_attr
> = container_of(attr, struct thermal_hwmon_attr, attr);
> struct thermal_zone_device *tz
> = container_of(hwmon_attr, struct thermal_zone_device,
> temp_input);
>
> - return tz->ops->get_temp(tz, buf);
> + ret = tz->ops->get_temp(tz, &temperature);
> +
> + if (ret)
> + return ret;
> +
> + return sprintf(buf, "%ld\n", temperature);
> }
>
> static ssize_t
> @@ -330,8 +389,14 @@ temp_crit_show(struct device *dev, struct device_attribute *attr,
> struct thermal_zone_device *tz
> = container_of(hwmon_attr, struct thermal_zone_device,
> temp_crit);
> + long temperature;
> + int ret;
> +
> + ret = tz->ops->get_trip_temp(tz, 0, &temperature);
> + if (ret)
> + return ret;
>
> - return tz->ops->get_trip_temp(tz, 0, buf);
> + return sprintf(buf, "%ld\n", temperature);
> }
>
>
> diff --git a/include/linux/thermal.h b/include/linux/thermal.h
> index 917707e..4cb3292 100644
> --- a/include/linux/thermal.h
> +++ b/include/linux/thermal.h
> @@ -31,23 +31,39 @@
> struct thermal_zone_device;
> struct thermal_cooling_device;
>
> +enum thermal_device_mode {
> + THERMAL_DEVICE_DISABLED = 0,
> + THERMAL_DEVICE_ENABLED,
> +};
> +
> +enum thermal_trip_type {
> + THERMAL_TRIP_ACTIVE = 0,
> + THERMAL_TRIP_PASSIVE,
> + THERMAL_TRIP_HOT,
> + THERMAL_TRIP_CRITICAL,
> +};
> +
> struct thermal_zone_device_ops {
> int (*bind) (struct thermal_zone_device *,
> struct thermal_cooling_device *);
> int (*unbind) (struct thermal_zone_device *,
> struct thermal_cooling_device *);
> - int (*get_temp) (struct thermal_zone_device *, char *);
> - int (*get_mode) (struct thermal_zone_device *, char *);
> - int (*set_mode) (struct thermal_zone_device *, const char *);
> - int (*get_trip_type) (struct thermal_zone_device *, int, char *);
> - int (*get_trip_temp) (struct thermal_zone_device *, int, char *);
> + int (*get_temp) (struct thermal_zone_device *, unsigned long *);
> + int (*get_mode) (struct thermal_zone_device *,
> + enum thermal_device_mode *);
> + int (*set_mode) (struct thermal_zone_device *,
> + enum thermal_device_mode);
> + int (*get_trip_type) (struct thermal_zone_device *, int,
> + enum thermal_trip_type *);
> + int (*get_trip_temp) (struct thermal_zone_device *, int,
> + unsigned long *);
> int (*get_crit_temp) (struct thermal_zone_device *, unsigned long *);
> };
>
> struct thermal_cooling_device_ops {
> - int (*get_max_state) (struct thermal_cooling_device *, char *);
> - int (*get_cur_state) (struct thermal_cooling_device *, char *);
> - int (*set_cur_state) (struct thermal_cooling_device *, unsigned int);
> + int (*get_max_state) (struct thermal_cooling_device *, unsigned long *);
> + int (*get_cur_state) (struct thermal_cooling_device *, unsigned long *);
> + int (*set_cur_state) (struct thermal_cooling_device *, unsigned long);
> };
>
> #define THERMAL_TRIPS_NONE -1
>
> --
> Matthew Garrett | mjg59@srcf.ucam.org
> --
> To unsubscribe from this list: send the line "unsubscribe linux-acpi" 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] 19+ messages in thread
* Re: [PATCH] acpi: move thermal trip handling to generic thermal layer
2009-01-16 13:48 ` Thomas Renninger
@ 2009-02-20 16:53 ` Len Brown
0 siblings, 0 replies; 19+ messages in thread
From: Len Brown @ 2009-02-20 16:53 UTC (permalink / raw)
To: Thomas Renninger
Cc: Matthew Garrett, Zhang Rui, linux-acpi@vger.kernel.org,
Thomas, Sujith
On Fri, 16 Jan 2009, Thomas Renninger wrote:
> On Wednesday 17 December 2008 04:12:15 Matthew Garrett wrote:
> > On Wed, Dec 17, 2008 at 11:02:18AM +0800, Zhang Rui wrote:
> > > On Mon, 2008-12-08 at 20:59 +0800, Matthew Garrett wrote:
> > > > They're needed if you want to implement any sort of sensible
> > > > implementation of passive cooling. They might not be expressed in quite
> > > > the same way, but the basic concept is identical.
> > >
> > > Seeing tc1, tc2, tsp under /sys/class/thermal/ is not good because we
> > > don't want to make the generic thermal driver too ACPI specific, before
> > > we've really concluded some basic concepts for passive cooling.
> > > so why not do this after we have another generic thermal user with
> > > passive cooling support?
> >
> > They're not exposed in /sys/class, and I don't think doing so is a
> > sensible thing to do. If you know values for the hardware in question
> > then they should be supplied by the firmware. But even so, the generic
> > thermal layer needs a way of implementing passive cooling. Doing so
> > involves deriving a formula to describe the behaviour of the system
> > around the passive trip level, and the best used implementation of that
> > in Linux at the moment is the one described in the ACPI spec. I don't
> > see any real need to generate new terms to describe well documented
> > concepts, even if other implementations don't use ACPI.
>
> If others need a specific algorithm, another (set of) callback function(s)
> could be added later which would provide the possibility of
> a platform specific override?
yeah, that is probalby the way to do it.
But until we have a 2nd customer besides ACPI,
we are kidding outselves if we think we can dream up a real "generic"
that will not need later modification...
--
Len Brown, Intel Open Source Technology Center
^ permalink raw reply [flat|nested] 19+ messages in thread
* Re: [PATCH] acpi: move thermal trip handling to generic thermal layer
2008-12-03 17:55 ` [PATCH] acpi: move thermal trip handling to generic thermal layer Matthew Garrett
2008-12-03 18:00 ` [PATCH] thermal: support forcing support for passive cooling Matthew Garrett
2008-12-08 6:59 ` [PATCH] acpi: move thermal trip handling to generic thermal layer Zhang Rui
@ 2009-02-20 23:44 ` Len Brown
2 siblings, 0 replies; 19+ messages in thread
From: Len Brown @ 2009-02-20 23:44 UTC (permalink / raw)
To: Matthew Garrett; +Cc: linux-acpi, rui.zhang, sujith.thomas
applied as below (some fuzz, whitespace, and minor merge conflict
with latest tree fixed)
thanks,
-Len
>From b1569e99c795bf83b4ddf41c4f1c42761ab7f75e Mon Sep 17 00:00:00 2001
From: Matthew Garrett <mjg59@srcf.ucam.org>
Date: Wed, 3 Dec 2008 17:55:32 +0000
Subject: [PATCH] ACPI: move thermal trip handling to generic thermal layer
Organization: Intel Open Source Technology Center
The ACPI code currently carries its own thermal trip handling, meaning that
any other thermal implementation will need to reimplement it. Move the code
to the generic thermal layer.
Signed-off-by: Matthew Garrett <mjg@redhat.com>
Signed-off-by: Len Brown <len.brown@intel.com>
---
drivers/acpi/thermal.c | 458 +++++------------------------------------
drivers/thermal/thermal_sys.c | 188 +++++++++++++++++-
include/linux/thermal.h | 15 ++-
3 files changed, 248 insertions(+), 413 deletions(-)
diff --git a/drivers/acpi/thermal.c b/drivers/acpi/thermal.c
index 1c410ef..0ec48d2 100644
--- a/drivers/acpi/thermal.c
+++ b/drivers/acpi/thermal.c
@@ -37,7 +37,6 @@
#include <linux/init.h>
#include <linux/types.h>
#include <linux/proc_fs.h>
-#include <linux/timer.h>
#include <linux/jiffies.h>
#include <linux/kmod.h>
#include <linux/seq_file.h>
@@ -190,7 +189,6 @@ struct acpi_thermal {
struct acpi_thermal_state state;
struct acpi_thermal_trips trips;
struct acpi_handle_list devices;
- struct timer_list timer;
struct thermal_zone_device *thermal_zone;
int tz_enabled;
struct mutex lock;
@@ -290,6 +288,11 @@ static int acpi_thermal_set_polling(struct acpi_thermal *tz, int seconds)
tz->polling_frequency = seconds * 10; /* Convert value to deci-seconds */
+ tz->thermal_zone->polling_delay = seconds * 1000;
+
+ if (tz->tz_enabled)
+ thermal_zone_device_update(tz->thermal_zone);
+
ACPI_DEBUG_PRINT((ACPI_DB_INFO,
"Polling frequency set to %lu seconds\n",
tz->polling_frequency/10));
@@ -569,386 +572,11 @@ static int acpi_thermal_get_trip_points(struct acpi_thermal *tz)
return acpi_thermal_trips_update(tz, ACPI_TRIPS_INIT);
}
-static int acpi_thermal_critical(struct acpi_thermal *tz)
-{
- if (!tz || !tz->trips.critical.flags.valid)
- return -EINVAL;
-
- if (tz->temperature >= tz->trips.critical.temperature) {
- printk(KERN_WARNING PREFIX "Critical trip point\n");
- tz->trips.critical.flags.enabled = 1;
- } else if (tz->trips.critical.flags.enabled)
- tz->trips.critical.flags.enabled = 0;
-
- acpi_bus_generate_proc_event(tz->device, ACPI_THERMAL_NOTIFY_CRITICAL,
- tz->trips.critical.flags.enabled);
- acpi_bus_generate_netlink_event(tz->device->pnp.device_class,
- dev_name(&tz->device->dev),
- ACPI_THERMAL_NOTIFY_CRITICAL,
- tz->trips.critical.flags.enabled);
-
- /* take no action if nocrt is set */
- if(!nocrt) {
- printk(KERN_EMERG
- "Critical temperature reached (%ld C), shutting down.\n",
- KELVIN_TO_CELSIUS(tz->temperature));
- orderly_poweroff(true);
- }
-
- return 0;
-}
-
-static int acpi_thermal_hot(struct acpi_thermal *tz)
-{
- if (!tz || !tz->trips.hot.flags.valid)
- return -EINVAL;
-
- if (tz->temperature >= tz->trips.hot.temperature) {
- printk(KERN_WARNING PREFIX "Hot trip point\n");
- tz->trips.hot.flags.enabled = 1;
- } else if (tz->trips.hot.flags.enabled)
- tz->trips.hot.flags.enabled = 0;
-
- acpi_bus_generate_proc_event(tz->device, ACPI_THERMAL_NOTIFY_HOT,
- tz->trips.hot.flags.enabled);
- acpi_bus_generate_netlink_event(tz->device->pnp.device_class,
- dev_name(&tz->device->dev),
- ACPI_THERMAL_NOTIFY_HOT,
- tz->trips.hot.flags.enabled);
-
- /* TBD: Call user-mode "sleep(S4)" function if nocrt is cleared */
-
- return 0;
-}
-
-static void acpi_thermal_passive(struct acpi_thermal *tz)
-{
- int result = 1;
- struct acpi_thermal_passive *passive = NULL;
- int trend = 0;
- int i = 0;
-
-
- if (!tz || !tz->trips.passive.flags.valid)
- return;
-
- passive = &(tz->trips.passive);
-
- /*
- * Above Trip?
- * -----------
- * Calculate the thermal trend (using the passive cooling equation)
- * and modify the performance limit for all passive cooling devices
- * accordingly. Note that we assume symmetry.
- */
- if (tz->temperature >= passive->temperature) {
- trend =
- (passive->tc1 * (tz->temperature - tz->last_temperature)) +
- (passive->tc2 * (tz->temperature - passive->temperature));
- ACPI_DEBUG_PRINT((ACPI_DB_INFO,
- "trend[%d]=(tc1[%lu]*(tmp[%lu]-last[%lu]))+(tc2[%lu]*(tmp[%lu]-psv[%lu]))\n",
- trend, passive->tc1, tz->temperature,
- tz->last_temperature, passive->tc2,
- tz->temperature, passive->temperature));
- passive->flags.enabled = 1;
- /* Heating up? */
- if (trend > 0)
- for (i = 0; i < passive->devices.count; i++)
- acpi_processor_set_thermal_limit(passive->
- devices.
- handles[i],
- ACPI_PROCESSOR_LIMIT_INCREMENT);
- /* Cooling off? */
- else if (trend < 0) {
- for (i = 0; i < passive->devices.count; i++)
- /*
- * assume that we are on highest
- * freq/lowest thrott and can leave
- * passive mode, even in error case
- */
- if (!acpi_processor_set_thermal_limit
- (passive->devices.handles[i],
- ACPI_PROCESSOR_LIMIT_DECREMENT))
- result = 0;
- /*
- * Leave cooling mode, even if the temp might
- * higher than trip point This is because some
- * machines might have long thermal polling
- * frequencies (tsp) defined. We will fall back
- * into passive mode in next cycle (probably quicker)
- */
- if (result) {
- passive->flags.enabled = 0;
- ACPI_DEBUG_PRINT((ACPI_DB_INFO,
- "Disabling passive cooling, still above threshold,"
- " but we are cooling down\n"));
- }
- }
- return;
- }
-
- /*
- * Below Trip?
- * -----------
- * Implement passive cooling hysteresis to slowly increase performance
- * and avoid thrashing around the passive trip point. Note that we
- * assume symmetry.
- */
- if (!passive->flags.enabled)
- return;
- for (i = 0; i < passive->devices.count; i++)
- if (!acpi_processor_set_thermal_limit
- (passive->devices.handles[i],
- ACPI_PROCESSOR_LIMIT_DECREMENT))
- result = 0;
- if (result) {
- passive->flags.enabled = 0;
- ACPI_DEBUG_PRINT((ACPI_DB_INFO,
- "Disabling passive cooling (zone is cool)\n"));
- }
-}
-
-static void acpi_thermal_active(struct acpi_thermal *tz)
-{
- int result = 0;
- struct acpi_thermal_active *active = NULL;
- int i = 0;
- int j = 0;
- unsigned long maxtemp = 0;
-
-
- if (!tz)
- return;
-
- for (i = 0; i < ACPI_THERMAL_MAX_ACTIVE; i++) {
- active = &(tz->trips.active[i]);
- if (!active || !active->flags.valid)
- break;
- if (tz->temperature >= active->temperature) {
- /*
- * Above Threshold?
- * ----------------
- * If not already enabled, turn ON all cooling devices
- * associated with this active threshold.
- */
- if (active->temperature > maxtemp)
- tz->state.active_index = i;
- maxtemp = active->temperature;
- if (active->flags.enabled)
- continue;
- for (j = 0; j < active->devices.count; j++) {
- result =
- acpi_bus_set_power(active->devices.
- handles[j],
- ACPI_STATE_D0);
- if (result) {
- printk(KERN_WARNING PREFIX
- "Unable to turn cooling device [%p] 'on'\n",
- active->devices.
- handles[j]);
- continue;
- }
- active->flags.enabled = 1;
- ACPI_DEBUG_PRINT((ACPI_DB_INFO,
- "Cooling device [%p] now 'on'\n",
- active->devices.handles[j]));
- }
- continue;
- }
- if (!active->flags.enabled)
- continue;
- /*
- * Below Threshold?
- * ----------------
- * Turn OFF all cooling devices associated with this
- * threshold.
- */
- for (j = 0; j < active->devices.count; j++) {
- result = acpi_bus_set_power(active->devices.handles[j],
- ACPI_STATE_D3);
- if (result) {
- printk(KERN_WARNING PREFIX
- "Unable to turn cooling device [%p] 'off'\n",
- active->devices.handles[j]);
- continue;
- }
- active->flags.enabled = 0;
- ACPI_DEBUG_PRINT((ACPI_DB_INFO,
- "Cooling device [%p] now 'off'\n",
- active->devices.handles[j]));
- }
- }
-}
-
-static void acpi_thermal_check(void *context);
-
-static void acpi_thermal_run(unsigned long data)
-{
- struct acpi_thermal *tz = (struct acpi_thermal *)data;
- if (!tz->zombie)
- acpi_os_execute(OSL_GPE_HANDLER, acpi_thermal_check, (void *)data);
-}
-
-static void acpi_thermal_active_off(void *data)
-{
- int result = 0;
- struct acpi_thermal *tz = data;
- int i = 0;
- int j = 0;
- struct acpi_thermal_active *active = NULL;
-
- if (!tz) {
- printk(KERN_ERR PREFIX "Invalid (NULL) context\n");
- return;
- }
-
- result = acpi_thermal_get_temperature(tz);
- if (result)
- return;
-
- for (i = 0; i < ACPI_THERMAL_MAX_ACTIVE; i++) {
- active = &(tz->trips.active[i]);
- if (!active || !active->flags.valid)
- break;
- if (tz->temperature >= active->temperature) {
- /*
- * If the thermal temperature is greater than the
- * active threshod, unnecessary to turn off the
- * the active cooling device.
- */
- continue;
- }
- /*
- * Below Threshold?
- * ----------------
- * Turn OFF all cooling devices associated with this
- * threshold.
- */
- for (j = 0; j < active->devices.count; j++)
- result = acpi_bus_set_power(active->devices.handles[j],
- ACPI_STATE_D3);
- }
-}
-
static void acpi_thermal_check(void *data)
{
- int result = 0;
struct acpi_thermal *tz = data;
- unsigned long sleep_time = 0;
- unsigned long timeout_jiffies = 0;
- int i = 0;
- struct acpi_thermal_state state;
-
-
- if (!tz) {
- printk(KERN_ERR PREFIX "Invalid (NULL) context\n");
- return;
- }
-
- /* Check if someone else is already running */
- if (!mutex_trylock(&tz->lock))
- return;
-
- state = tz->state;
-
- result = acpi_thermal_get_temperature(tz);
- if (result)
- goto unlock;
-
- if (!tz->tz_enabled)
- goto unlock;
-
- memset(&tz->state, 0, sizeof(tz->state));
-
- /*
- * Check Trip Points
- * -----------------
- * Compare the current temperature to the trip point values to see
- * if we've entered one of the thermal policy states. Note that
- * this function determines when a state is entered, but the
- * individual policy decides when it is exited (e.g. hysteresis).
- */
- if (tz->trips.critical.flags.valid)
- state.critical |=
- (tz->temperature >= tz->trips.critical.temperature);
- if (tz->trips.hot.flags.valid)
- state.hot |= (tz->temperature >= tz->trips.hot.temperature);
- if (tz->trips.passive.flags.valid)
- state.passive |=
- (tz->temperature >= tz->trips.passive.temperature);
- for (i = 0; i < ACPI_THERMAL_MAX_ACTIVE; i++)
- if (tz->trips.active[i].flags.valid)
- state.active |=
- (tz->temperature >=
- tz->trips.active[i].temperature);
-
- /*
- * Invoke Policy
- * -------------
- * Separated from the above check to allow individual policy to
- * determine when to exit a given state.
- */
- if (state.critical)
- acpi_thermal_critical(tz);
- if (state.hot)
- acpi_thermal_hot(tz);
- if (state.passive)
- acpi_thermal_passive(tz);
- if (state.active)
- acpi_thermal_active(tz);
-
- /*
- * Calculate State
- * ---------------
- * Again, separated from the above two to allow independent policy
- * decisions.
- */
- tz->state.critical = tz->trips.critical.flags.enabled;
- tz->state.hot = tz->trips.hot.flags.enabled;
- tz->state.passive = tz->trips.passive.flags.enabled;
- tz->state.active = 0;
- for (i = 0; i < ACPI_THERMAL_MAX_ACTIVE; i++)
- tz->state.active |= tz->trips.active[i].flags.enabled;
-
- /*
- * Calculate Sleep Time
- * --------------------
- * If we're in the passive state, use _TSP's value. Otherwise
- * use the default polling frequency (e.g. _TZP). If no polling
- * frequency is specified then we'll wait forever (at least until
- * a thermal event occurs). Note that _TSP and _TZD values are
- * given in 1/10th seconds (we must covert to milliseconds).
- */
- if (tz->state.passive) {
- sleep_time = tz->trips.passive.tsp * 100;
- timeout_jiffies = jiffies + (HZ * sleep_time) / 1000;
- } else if (tz->polling_frequency > 0) {
- sleep_time = tz->polling_frequency * 100;
- timeout_jiffies = round_jiffies(jiffies + (HZ * sleep_time) / 1000);
- }
-
- ACPI_DEBUG_PRINT((ACPI_DB_INFO, "%s: temperature[%lu] sleep[%lu]\n",
- tz->name, tz->temperature, sleep_time));
- /*
- * Schedule Next Poll
- * ------------------
- */
- if (!sleep_time) {
- if (timer_pending(&(tz->timer)))
- del_timer(&(tz->timer));
- } else {
- if (timer_pending(&(tz->timer)))
- mod_timer(&(tz->timer), timeout_jiffies);
- else {
- tz->timer.data = (unsigned long)tz;
- tz->timer.function = acpi_thermal_run;
- tz->timer.expires = timeout_jiffies;
- add_timer(&(tz->timer));
- }
- }
- unlock:
- mutex_unlock(&tz->lock);
+ thermal_zone_device_update(tz->thermal_zone);
}
/* sys I/F for generic thermal sysfs support */
@@ -1122,6 +750,29 @@ static int thermal_get_crit_temp(struct thermal_zone_device *thermal,
return -EINVAL;
}
+static int thermal_notify(struct thermal_zone_device *thermal, int trip,
+ enum thermal_trip_type trip_type)
+{
+ u8 type = 0;
+ struct acpi_thermal *tz = thermal->devdata;
+
+ if (trip_type == THERMAL_TRIP_CRITICAL)
+ type = ACPI_THERMAL_NOTIFY_CRITICAL;
+ else if (trip_type == THERMAL_TRIP_HOT)
+ type = ACPI_THERMAL_NOTIFY_HOT;
+ else
+ return 0;
+
+ acpi_bus_generate_proc_event(tz->device, type, 1);
+ acpi_bus_generate_netlink_event(tz->device->pnp.device_class,
+ tz->device->dev.bus_id, type, 1);
+
+ if (trip_type == THERMAL_TRIP_CRITICAL && nocrt)
+ return 1;
+
+ return 0;
+}
+
typedef int (*cb)(struct thermal_zone_device *, int,
struct thermal_cooling_device *);
static int acpi_thermal_cooling_device_cb(struct thermal_zone_device *thermal,
@@ -1214,6 +865,7 @@ static struct thermal_zone_device_ops acpi_thermal_zone_ops = {
.get_trip_type = thermal_get_trip_type,
.get_trip_temp = thermal_get_trip_temp,
.get_crit_temp = thermal_get_crit_temp,
+ .notify = thermal_notify,
};
static int acpi_thermal_register_thermal_zone(struct acpi_thermal *tz)
@@ -1234,8 +886,21 @@ static int acpi_thermal_register_thermal_zone(struct acpi_thermal *tz)
for (i = 0; i < ACPI_THERMAL_MAX_ACTIVE &&
tz->trips.active[i].flags.valid; i++, trips++);
- tz->thermal_zone = thermal_zone_device_register("acpitz",
- trips, tz, &acpi_thermal_zone_ops);
+
+ if (tz->trips.passive.flags.valid)
+ tz->thermal_zone =
+ thermal_zone_device_register("acpitz", trips, tz,
+ &acpi_thermal_zone_ops,
+ tz->trips.passive.tc1,
+ tz->trips.passive.tc2,
+ tz->trips.passive.tsp*100,
+ tz->polling_frequency*100);
+ else
+ tz->thermal_zone =
+ thermal_zone_device_register("acpitz", trips, tz,
+ &acpi_thermal_zone_ops,
+ 0, 0, 0,
+ tz->polling_frequency);
if (IS_ERR(tz->thermal_zone))
return -ENODEV;
@@ -1467,13 +1132,13 @@ static int acpi_thermal_polling_seq_show(struct seq_file *seq, void *offset)
if (!tz)
goto end;
- if (!tz->polling_frequency) {
+ if (!tz->thermal_zone->polling_delay) {
seq_puts(seq, "<polling disabled>\n");
goto end;
}
- seq_printf(seq, "polling frequency: %lu seconds\n",
- (tz->polling_frequency / 10));
+ seq_printf(seq, "polling frequency: %d seconds\n",
+ (tz->thermal_zone->polling_delay / 1000));
end:
return 0;
@@ -1703,12 +1368,6 @@ static int acpi_thermal_add(struct acpi_device *device)
if (result)
goto unregister_thermal_zone;
- init_timer(&tz->timer);
-
- acpi_thermal_active_off(tz);
-
- acpi_thermal_check(tz);
-
status = acpi_install_notify_handler(device->handle,
ACPI_DEVICE_NOTIFY,
acpi_thermal_notify, tz);
@@ -1737,36 +1396,15 @@ static int acpi_thermal_remove(struct acpi_device *device, int type)
acpi_status status = AE_OK;
struct acpi_thermal *tz = NULL;
-
if (!device || !acpi_driver_data(device))
return -EINVAL;
tz = acpi_driver_data(device);
- /* avoid timer adding new defer task */
- tz->zombie = 1;
- /* wait for running timer (on other CPUs) finish */
- del_timer_sync(&(tz->timer));
- /* synchronize deferred task */
- acpi_os_wait_events_complete(NULL);
- /* deferred task may reinsert timer */
- del_timer_sync(&(tz->timer));
-
status = acpi_remove_notify_handler(device->handle,
ACPI_DEVICE_NOTIFY,
acpi_thermal_notify);
- /* Terminate policy */
- if (tz->trips.passive.flags.valid && tz->trips.passive.flags.enabled) {
- tz->trips.passive.flags.enabled = 0;
- acpi_thermal_passive(tz);
- }
- if (tz->trips.active[0].flags.valid
- && tz->trips.active[0].flags.enabled) {
- tz->trips.active[0].flags.enabled = 0;
- acpi_thermal_active(tz);
- }
-
acpi_thermal_remove_fs(device);
acpi_thermal_unregister_thermal_zone(tz);
mutex_destroy(&tz->lock);
diff --git a/drivers/thermal/thermal_sys.c b/drivers/thermal/thermal_sys.c
index bd139ad..6378741 100644
--- a/drivers/thermal/thermal_sys.c
+++ b/drivers/thermal/thermal_sys.c
@@ -30,6 +30,7 @@
#include <linux/idr.h>
#include <linux/thermal.h>
#include <linux/spinlock.h>
+#include <linux/reboot.h>
MODULE_AUTHOR("Zhang Rui");
MODULE_DESCRIPTION("Generic thermal management sysfs support");
@@ -517,6 +518,97 @@ thermal_remove_hwmon_sysfs(struct thermal_zone_device *tz)
}
#endif
+static void thermal_zone_device_set_polling(struct thermal_zone_device *tz,
+ int delay)
+{
+ cancel_delayed_work(&(tz->poll_queue));
+
+ if (!delay)
+ return;
+
+ if (delay > 1000)
+ schedule_delayed_work(&(tz->poll_queue),
+ round_jiffies(msecs_to_jiffies(delay)));
+ else
+ schedule_delayed_work(&(tz->poll_queue),
+ msecs_to_jiffies(delay));
+}
+
+static void thermal_zone_device_passive(struct thermal_zone_device *tz,
+ int temp, int trip_temp, int trip)
+{
+ int trend = 0;
+ struct thermal_cooling_device_instance *instance;
+ struct thermal_cooling_device *cdev;
+ long state, max_state;
+
+ /*
+ * Above Trip?
+ * -----------
+ * Calculate the thermal trend (using the passive cooling equation)
+ * and modify the performance limit for all passive cooling devices
+ * accordingly. Note that we assume symmetry.
+ */
+ if (temp >= trip_temp) {
+ tz->passive = true;
+
+ trend = (tz->tc1 * (temp - tz->last_temperature)) +
+ (tz->tc2 * (temp - trip_temp));
+
+ /* Heating up? */
+ if (trend > 0) {
+ list_for_each_entry(instance, &tz->cooling_devices,
+ node) {
+ if (instance->trip != trip)
+ continue;
+ cdev = instance->cdev;
+ cdev->ops->get_cur_state(cdev, &state);
+ cdev->ops->get_max_state(cdev, &max_state);
+ if (state++ < max_state)
+ cdev->ops->set_cur_state(cdev, state);
+ }
+ } else if (trend < 0) { /* Cooling off? */
+ list_for_each_entry(instance, &tz->cooling_devices,
+ node) {
+ if (instance->trip != trip)
+ continue;
+ cdev = instance->cdev;
+ cdev->ops->get_cur_state(cdev, &state);
+ cdev->ops->get_max_state(cdev, &max_state);
+ if (state > 0)
+ cdev->ops->set_cur_state(cdev, --state);
+ }
+ }
+ return;
+ }
+
+ /*
+ * Below Trip?
+ * -----------
+ * Implement passive cooling hysteresis to slowly increase performance
+ * and avoid thrashing around the passive trip point. Note that we
+ * assume symmetry.
+ */
+ list_for_each_entry(instance, &tz->cooling_devices, node) {
+ if (instance->trip != trip)
+ continue;
+ cdev = instance->cdev;
+ cdev->ops->get_cur_state(cdev, &state);
+ cdev->ops->get_max_state(cdev, &max_state);
+ if (state > 0)
+ cdev->ops->set_cur_state(cdev, --state);
+ if (state == 0)
+ tz->passive = false;
+ }
+}
+
+static void thermal_zone_device_check(struct work_struct *work)
+{
+ struct thermal_zone_device *tz = container_of(work, struct
+ thermal_zone_device,
+ poll_queue.work);
+ thermal_zone_device_update(tz);
+}
/**
* thermal_zone_bind_cooling_device - bind a cooling device to a thermal zone
@@ -787,20 +879,101 @@ void thermal_cooling_device_unregister(struct
EXPORT_SYMBOL(thermal_cooling_device_unregister);
/**
+ * thermal_zone_device_update - force an update of a thermal zone's state
+ * @ttz: the thermal zone to update
+ */
+
+void thermal_zone_device_update(struct thermal_zone_device *tz)
+{
+ int count, ret = 0;
+ long temp, trip_temp;
+ enum thermal_trip_type trip_type;
+ struct thermal_cooling_device_instance *instance;
+ struct thermal_cooling_device *cdev;
+
+ mutex_lock(&tz->lock);
+
+ tz->ops->get_temp(tz, &temp);
+
+ for (count = 0; count < tz->trips; count++) {
+ tz->ops->get_trip_type(tz, count, &trip_type);
+ tz->ops->get_trip_temp(tz, count, &trip_temp);
+
+ switch (trip_type) {
+ case THERMAL_TRIP_CRITICAL:
+ if (temp > trip_temp) {
+ if (tz->ops->notify)
+ ret = tz->ops->notify(tz, count,
+ trip_type);
+ if (!ret) {
+ printk(KERN_EMERG
+ "Critical temperature reached (%ld C), shutting down.\n",
+ temp/1000);
+ orderly_poweroff(true);
+ }
+ }
+ break;
+ case THERMAL_TRIP_HOT:
+ if (temp > trip_temp)
+ if (tz->ops->notify)
+ tz->ops->notify(tz, count, trip_type);
+ break;
+ case THERMAL_TRIP_ACTIVE:
+ list_for_each_entry(instance, &tz->cooling_devices,
+ node) {
+ if (instance->trip != count)
+ continue;
+
+ cdev = instance->cdev;
+
+ if (temp > trip_temp)
+ cdev->ops->set_cur_state(cdev, 1);
+ else
+ cdev->ops->set_cur_state(cdev, 0);
+ }
+ break;
+ case THERMAL_TRIP_PASSIVE:
+ if (temp > trip_temp || tz->passive)
+ thermal_zone_device_passive(tz, temp,
+ trip_temp, count);
+ break;
+ }
+ }
+ tz->last_temperature = temp;
+ if (tz->passive)
+ thermal_zone_device_set_polling(tz, tz->passive_delay);
+ else if (tz->polling_delay)
+ thermal_zone_device_set_polling(tz, tz->polling_delay);
+ mutex_unlock(&tz->lock);
+}
+EXPORT_SYMBOL(thermal_zone_device_update);
+
+/**
* 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
* @devdata: private device data
* @ops: standard thermal zone device callbacks
+ * @tc1: thermal coefficient 1 for passive calculations
+ * @tc2: thermal coefficient 2 for passive calculations
+ * @passive_delay: number of milliseconds to wait between polls when
+ * performing passive cooling
+ * @polling_delay: number of milliseconds to wait between polls when checking
+ * whether trip points have been crossed (0 for interrupt
+ * driven systems)
*
* thermal_zone_device_unregister() must be called when the device is no
- * longer needed.
+ * longer needed. The passive cooling formula uses tc1 and tc2 as described in
+ * section 11.1.5.1 of the ACPI specification 3.0.
*/
struct thermal_zone_device *thermal_zone_device_register(char *type,
int trips,
void *devdata, struct
thermal_zone_device_ops
- *ops)
+ *ops, int tc1, int
+ tc2,
+ int passive_delay,
+ int polling_delay)
{
struct thermal_zone_device *tz;
struct thermal_cooling_device *pos;
@@ -834,6 +1007,11 @@ struct thermal_zone_device *thermal_zone_device_register(char *type,
tz->device.class = &thermal_class;
tz->devdata = devdata;
tz->trips = trips;
+ tz->tc1 = tc1;
+ tz->tc2 = tc2;
+ tz->passive_delay = passive_delay;
+ tz->polling_delay = polling_delay;
+
dev_set_name(&tz->device, "thermal_zone%d", tz->id);
result = device_register(&tz->device);
if (result) {
@@ -879,6 +1057,10 @@ struct thermal_zone_device *thermal_zone_device_register(char *type,
}
mutex_unlock(&thermal_list_lock);
+ INIT_DELAYED_WORK(&(tz->poll_queue), thermal_zone_device_check);
+
+ thermal_zone_device_update(tz);
+
if (!result)
return tz;
@@ -918,6 +1100,8 @@ void thermal_zone_device_unregister(struct thermal_zone_device *tz)
tz->ops->unbind(tz, cdev);
mutex_unlock(&thermal_list_lock);
+ thermal_zone_device_set_polling(tz, 0);
+
if (tz->type[0])
device_remove_file(&tz->device, &dev_attr_type);
device_remove_file(&tz->device, &dev_attr_temp);
diff --git a/include/linux/thermal.h b/include/linux/thermal.h
index 4cb3292..a81c615 100644
--- a/include/linux/thermal.h
+++ b/include/linux/thermal.h
@@ -27,6 +27,7 @@
#include <linux/idr.h>
#include <linux/device.h>
+#include <linux/workqueue.h>
struct thermal_zone_device;
struct thermal_cooling_device;
@@ -58,6 +59,8 @@ struct thermal_zone_device_ops {
int (*get_trip_temp) (struct thermal_zone_device *, int,
unsigned long *);
int (*get_crit_temp) (struct thermal_zone_device *, unsigned long *);
+ int (*notify) (struct thermal_zone_device *, int,
+ enum thermal_trip_type);
};
struct thermal_cooling_device_ops {
@@ -104,11 +107,18 @@ struct thermal_zone_device {
struct device device;
void *devdata;
int trips;
+ int tc1;
+ int tc2;
+ int passive_delay;
+ int polling_delay;
+ int last_temperature;
+ bool passive;
struct thermal_zone_device_ops *ops;
struct list_head cooling_devices;
struct idr idr;
struct mutex lock; /* protect cooling devices list */
struct list_head node;
+ struct delayed_work poll_queue;
#if defined(CONFIG_THERMAL_HWMON)
struct list_head hwmon_node;
struct thermal_hwmon_device *hwmon;
@@ -120,13 +130,16 @@ struct thermal_zone_device {
struct thermal_zone_device *thermal_zone_device_register(char *, int, void *,
struct
thermal_zone_device_ops
- *);
+ *, int tc1, int tc2,
+ int passive_freq,
+ int polling_freq);
void thermal_zone_device_unregister(struct thermal_zone_device *);
int thermal_zone_bind_cooling_device(struct thermal_zone_device *, int,
struct thermal_cooling_device *);
int thermal_zone_unbind_cooling_device(struct thermal_zone_device *, int,
struct thermal_cooling_device *);
+void thermal_zone_device_update(struct thermal_zone_device *);
struct thermal_cooling_device *thermal_cooling_device_register(char *, void *,
struct
thermal_cooling_device_ops
--
1.6.2.rc1.20.g8c5b
^ permalink raw reply related [flat|nested] 19+ messages in thread
* Re: [PATCH] thermal: support forcing support for passive cooling
2008-12-03 18:00 ` [PATCH] thermal: support forcing support for passive cooling Matthew Garrett
2008-12-17 3:19 ` Zhang Rui
2008-12-28 15:22 ` Matthew Garrett
@ 2009-02-20 23:45 ` Len Brown
2 siblings, 0 replies; 19+ messages in thread
From: Len Brown @ 2009-02-20 23:45 UTC (permalink / raw)
To: Matthew Garrett; +Cc: linux-acpi, rui.zhang, sujith.thomas
applied
thanks
--
Len Brown, Intel Open Source Technology Center
On Wed, 3 Dec 2008, Matthew Garrett wrote:
> Due to poor thermal design or Linux driving hardware outside its thermal
> envelope, some systems will reach critical temperature and shut down
> under high load. This patch adds support for forcing a polling-based
> passive trip point if the firmware doesn't provide one. The assumption
> is made that the processor is the most practical means to reduce the
> dynamic heat generation, so hitting the passive thermal limit will cause
> the CPU to be throttled until the temperature stabalises around the
> defined value.
>
> UI is provided via a "passive" sysfs entry in the thermal zone
> directory. It accepts a decimal value in millidegrees celsius, or "0" to
> disable the functionality. Default behaviour is for this functionality
> to be disabled.
>
> Signed-off-by: Matthew Garrett <mjg@redhat.com>
> ---
>
> Depends on the code to move the trip handling into the generic layer.
> Tested this on a couple of machines and it seems to work well - a
> logical followup might be to allow the passive trip point to be
> overridden on machines that provide it.
>
> drivers/thermal/thermal_sys.c | 77 +++++++++++++++++++++++++++++++++++++++++
> include/linux/thermal.h | 1 +
> 2 files changed, 78 insertions(+), 0 deletions(-)
>
> diff --git a/drivers/thermal/thermal_sys.c b/drivers/thermal/thermal_sys.c
> index ac0f91f..c5351e5 100644
> --- a/drivers/thermal/thermal_sys.c
> +++ b/drivers/thermal/thermal_sys.c
> @@ -214,9 +214,69 @@ trip_point_temp_show(struct device *dev, struct device_attribute *attr,
> return sprintf(buf, "%ld\n", temperature);
> }
>
> +static ssize_t
> +passive_store(struct device *dev, struct device_attribute *attr,
> + const char *buf, size_t count)
> +{
> + struct thermal_zone_device *tz = to_thermal_zone(dev);
> + struct thermal_cooling_device *cdev = NULL;
> + int state;
> +
> + if (!sscanf(buf, "%d\n", &state))
> + return -EINVAL;
> +
> + if (state && !tz->forced_passive) {
> + mutex_lock(&thermal_list_lock);
> + list_for_each_entry(cdev, &thermal_cdev_list, node) {
> + if (!strncmp("Processor", cdev->type,
> + sizeof("Processor")))
> + thermal_zone_bind_cooling_device(tz,
> + THERMAL_TRIPS_NONE,
> + cdev);
> + }
> + mutex_unlock(&thermal_list_lock);
> + } else if (!state && tz->forced_passive) {
> + mutex_lock(&thermal_list_lock);
> + list_for_each_entry(cdev, &thermal_cdev_list, node) {
> + if (!strncmp("Processor", cdev->type,
> + sizeof("Processor")))
> + thermal_zone_unbind_cooling_device(tz,
> + THERMAL_TRIPS_NONE,
> + cdev);
> + }
> + mutex_unlock(&thermal_list_lock);
> + }
> +
> + tz->tc1 = 1;
> + tz->tc2 = 1;
> +
> + if (!tz->passive_delay)
> + tz->passive_delay = 1000;
> +
> + if (!tz->polling_delay)
> + tz->polling_delay = 10000;
> +
> + tz->forced_passive = state;
> +
> + thermal_zone_device_update(tz);
> +
> + return count;
> +}
> +
> +static ssize_t
> +passive_show(struct device *dev, struct device_attribute *attr,
> + char *buf)
> +{
> + struct thermal_zone_device *tz = to_thermal_zone(dev);
> +
> + return sprintf(buf, "%d\n", tz->forced_passive);
> +}
> +
> static DEVICE_ATTR(type, 0444, type_show, NULL);
> static DEVICE_ATTR(temp, 0444, temp_show, NULL);
> static DEVICE_ATTR(mode, 0644, mode_show, mode_store);
> +static DEVICE_ATTR(passive, S_IRUGO | S_IWUSR, passive_show, \
> + passive_store);
>
> static struct device_attribute trip_point_attrs[] = {
> __ATTR(trip_point_0_type, 0444, trip_point_type_show, NULL),
> @@ -939,6 +999,11 @@ void thermal_zone_device_update(struct thermal_zone_device *tz)
> break;
> }
> }
> +
> + if (tz->forced_passive)
> + thermal_zone_device_passive(tz, temp, tz->forced_passive,
> + THERMAL_TRIPS_NONE);
> +
> tz->last_temperature = temp;
> if (tz->passive)
> thermal_zone_device_set_polling(tz, tz->passive_delay);
> @@ -977,8 +1042,10 @@ struct thermal_zone_device *thermal_zone_device_register(char *type,
> {
> struct thermal_zone_device *tz;
> struct thermal_cooling_device *pos;
> + enum thermal_trip_type trip_type;
> int result;
> int count;
> + int passive=0;
>
> if (strlen(type) >= THERMAL_NAME_LENGTH)
> return ERR_PTR(-EINVAL);
> @@ -1041,8 +1108,18 @@ struct thermal_zone_device *thermal_zone_device_register(char *type,
> TRIP_POINT_ATTR_ADD(&tz->device, count, result);
> if (result)
> goto unregister;
> + tz->ops->get_trip_type(tz, count, &trip_type);
> + if (trip_type == THERMAL_TRIP_PASSIVE)
> + passive=1;
> }
>
> + if (!passive)
> + result = device_create_file(&tz->device,
> + &dev_attr_passive);
> +
> + if (result)
> + goto unregister;
> +
> result = thermal_add_hwmon_sysfs(tz);
> if (result)
> goto unregister;
> diff --git a/include/linux/thermal.h b/include/linux/thermal.h
> index a81c615..1de8b9e 100644
> --- a/include/linux/thermal.h
> +++ b/include/linux/thermal.h
> @@ -113,6 +113,7 @@ struct thermal_zone_device {
> int polling_delay;
> int last_temperature;
> bool passive;
> + unsigned int forced_passive;
> struct thermal_zone_device_ops *ops;
> struct list_head cooling_devices;
> struct idr idr;
>
> --
> Matthew Garrett | mjg59@srcf.ucam.org
> --
> To unsubscribe from this list: send the line "unsubscribe linux-acpi" 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] 19+ messages in thread
end of thread, other threads:[~2009-02-20 23:45 UTC | newest]
Thread overview: 19+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2008-11-27 17:48 [PATCH] thermal: use integers rather than strings for thermal values Matthew Garrett
2008-11-27 17:49 ` Matthew Garrett
2008-11-28 2:52 ` Zhang Rui
2009-01-16 13:44 ` Thomas Renninger
2008-12-03 17:55 ` [PATCH] acpi: move thermal trip handling to generic thermal layer Matthew Garrett
2008-12-03 18:00 ` [PATCH] thermal: support forcing support for passive cooling Matthew Garrett
2008-12-17 3:19 ` Zhang Rui
2008-12-28 15:22 ` Matthew Garrett
2009-01-06 22:42 ` Matthew Garrett
2009-02-13 1:21 ` Matthew Garrett
2009-02-20 23:45 ` Len Brown
2008-12-08 6:59 ` [PATCH] acpi: move thermal trip handling to generic thermal layer Zhang Rui
2008-12-08 12:59 ` Matthew Garrett
2008-12-17 3:02 ` Zhang Rui
2008-12-17 3:12 ` Matthew Garrett
2009-01-16 13:48 ` Thomas Renninger
2009-02-20 16:53 ` Len Brown
2009-02-20 23:44 ` Len Brown
2009-02-20 15:56 ` [PATCH] thermal: use integers rather than strings for thermal values Len Brown
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).