Skip to content
Projects
Groups
Snippets
Help
Loading...
Help
Support
Keyboard shortcuts
?
Submit feedback
Contribute to GitLab
Sign in / Register
Toggle navigation
L
linux
Project overview
Project overview
Details
Activity
Releases
Repository
Repository
Files
Commits
Branches
Tags
Contributors
Graph
Compare
Issues
0
Issues
0
List
Boards
Labels
Milestones
Merge Requests
0
Merge Requests
0
Analytics
Analytics
Repository
Value Stream
Wiki
Wiki
Snippets
Snippets
Members
Members
Collapse sidebar
Close sidebar
Activity
Graph
Create a new issue
Commits
Issue Boards
Open sidebar
Kirill Smelkov
linux
Commits
4f3bff70
Commit
4f3bff70
authored
Apr 05, 2009
by
Len Brown
Browse files
Options
Browse Files
Download
Plain Diff
Merge branch 'thermal' into release
parents
2ddb9f17
03a971a2
Changes
7
Hide whitespace changes
Inline
Side-by-side
Showing
7 changed files
with
525 additions
and
509 deletions
+525
-509
drivers/acpi/fan.c
drivers/acpi/fan.c
+12
-8
drivers/acpi/processor_thermal.c
drivers/acpi/processor_thermal.c
+11
-9
drivers/acpi/thermal.c
drivers/acpi/thermal.c
+99
-440
drivers/acpi/video.c
drivers/acpi/video.c
+13
-9
drivers/platform/x86/intel_menlow.c
drivers/platform/x86/intel_menlow.c
+10
-19
drivers/thermal/thermal_sys.c
drivers/thermal/thermal_sys.c
+341
-15
include/linux/thermal.h
include/linux/thermal.h
+39
-9
No files found.
drivers/acpi/fan.c
View file @
4f3bff70
...
...
@@ -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
;
...
...
drivers/acpi/processor_thermal.c
View file @
4f3bff70
...
...
@@ -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
);
...
...
drivers/acpi/thermal.c
View file @
4f3bff70
...
...
@@ -37,11 +37,11 @@
#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>
#include <linux/reboot.h>
#include <linux/device.h>
#include <asm/uaccess.h>
#include <linux/thermal.h>
#include <acpi/acpi_bus.h>
...
...
@@ -190,7 +190,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 +289,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,392 +573,18 @@ 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 */
#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
;
...
...
@@ -966,25 +596,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
;
...
...
@@ -995,9 +628,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
;
...
...
@@ -1013,7 +646,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
;
...
...
@@ -1022,27 +655,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
--
;
}
...
...
@@ -1050,7 +691,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
;
...
...
@@ -1059,31 +700,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
--
;
}
...
...
@@ -1102,6 +751,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
,
dev_name
(
&
tz
->
device
->
dev
),
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
,
...
...
@@ -1194,6 +866,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
)
...
...
@@ -1214,8 +887,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
;
...
...
@@ -1447,13 +1133,13 @@ static int acpi_thermal_polling_seq_show(struct seq_file *seq, void *offset)
if
(
!
tz
)
goto
end
;
if
(
!
tz
->
polling_frequenc
y
)
{
if
(
!
tz
->
thermal_zone
->
polling_dela
y
)
{
seq_puts
(
seq
,
"<polling disabled>
\n
"
);
goto
end
;
}
seq_printf
(
seq
,
"polling frequency: %
lu
seconds
\n
"
,
(
tz
->
polling_frequency
/
1
0
));
seq_printf
(
seq
,
"polling frequency: %
d
seconds
\n
"
,
(
tz
->
thermal_zone
->
polling_delay
/
100
0
));
end:
return
0
;
...
...
@@ -1683,12 +1369,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
);
...
...
@@ -1717,36 +1397,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
);
...
...
drivers/acpi/video.c
View file @
4f3bff70
...
...
@@ -358,32 +358,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
);
...
...
drivers/platform/x86/intel_menlow.c
View file @
4f3bff70
...
...
@@ -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 %
l
d: status is %d
\n
"
,
state
,
status
);
if
(
ACPI_FAILURE
(
status
))
return
-
EFAULT
;
...
...
drivers/thermal/thermal_sys.c
View file @
4f3bff70
...
...
@@ -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"
);
...
...
@@ -104,22 +105,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 +147,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 +165,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 +174,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 +197,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,12 +206,77 @@ 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
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
),
...
...
@@ -236,8 +339,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 +353,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 +368,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
,
"%
l
d
\n
"
,
&
state
))
return
-
EINVAL
;
if
(
state
<
0
)
...
...
@@ -312,13 +425,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 +450,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
);
}
...
...
@@ -452,6 +578,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
...
...
@@ -721,26 +938,114 @@ 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
;
}
}
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
);
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
;
enum
thermal_trip_type
trip_type
;
int
result
;
int
count
;
int
passive
=
0
;
if
(
strlen
(
type
)
>=
THERMAL_NAME_LENGTH
)
return
ERR_PTR
(
-
EINVAL
);
...
...
@@ -769,6 +1074,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
)
{
...
...
@@ -798,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
;
...
...
@@ -814,6 +1134,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
;
...
...
@@ -853,6 +1177,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
);
...
...
include/linux/thermal.h
View file @
4f3bff70
...
...
@@ -27,27 +27,46 @@
#include <linux/idr.h>
#include <linux/device.h>
#include <linux/workqueue.h>
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
*
);
int
(
*
notify
)
(
struct
thermal_zone_device
*
,
int
,
enum
thermal_trip_type
);
};
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
...
...
@@ -88,11 +107,19 @@ 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
;
unsigned
int
forced_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
;
...
...
@@ -104,13 +131,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
...
...
Write
Preview
Markdown
is supported
0%
Try again
or
attach a new file
Attach a file
Cancel
You are about to add
0
people
to the discussion. Proceed with caution.
Finish editing this message first!
Cancel
Please
register
or
sign in
to comment