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
8c882f17
Commit
8c882f17
authored
Apr 26, 2024
by
Rafael J. Wysocki
Browse files
Options
Browse Files
Download
Plain Diff
Merge back earlier thermal core changes for v6.10.
parents
d351eb0a
f831892e
Changes
19
Hide whitespace changes
Inline
Side-by-side
Showing
19 changed files
with
602 additions
and
416 deletions
+602
-416
drivers/thermal/gov_bang_bang.c
drivers/thermal/gov_bang_bang.c
+38
-59
drivers/thermal/gov_fair_share.c
drivers/thermal/gov_fair_share.c
+48
-34
drivers/thermal/gov_power_allocator.c
drivers/thermal/gov_power_allocator.c
+13
-24
drivers/thermal/gov_step_wise.c
drivers/thermal/gov_step_wise.c
+48
-52
drivers/thermal/gov_user_space.c
drivers/thermal/gov_user_space.c
+5
-5
drivers/thermal/intel/int340x_thermal/acpi_thermal_rel.c
drivers/thermal/intel/int340x_thermal/acpi_thermal_rel.c
+2
-2
drivers/thermal/intel/intel_hfi.c
drivers/thermal/intel/intel_hfi.c
+89
-8
drivers/thermal/thermal_core.c
drivers/thermal/thermal_core.c
+101
-57
drivers/thermal/thermal_core.h
drivers/thermal/thermal_core.h
+119
-2
drivers/thermal/thermal_debugfs.c
drivers/thermal/thermal_debugfs.c
+32
-26
drivers/thermal/thermal_debugfs.h
drivers/thermal/thermal_debugfs.h
+2
-2
drivers/thermal/thermal_helpers.c
drivers/thermal/thermal_helpers.c
+5
-3
drivers/thermal/thermal_netlink.c
drivers/thermal/thermal_netlink.c
+50
-18
drivers/thermal/thermal_netlink.h
drivers/thermal/thermal_netlink.h
+26
-0
drivers/thermal/thermal_sysfs.c
drivers/thermal/thermal_sysfs.c
+10
-10
drivers/thermal/thermal_trace.h
drivers/thermal/thermal_trace.h
+2
-0
drivers/thermal/thermal_trace_ipa.h
drivers/thermal/thermal_trace_ipa.h
+2
-0
drivers/thermal/thermal_trip.c
drivers/thermal/thermal_trip.c
+8
-7
include/linux/thermal.h
include/linux/thermal.h
+2
-107
No files found.
drivers/thermal/gov_bang_bang.c
View file @
8c882f17
...
...
@@ -13,60 +13,11 @@
#include "thermal_core.h"
static
int
thermal_zone_trip_update
(
struct
thermal_zone_device
*
tz
,
const
struct
thermal_trip
*
trip
)
{
int
trip_index
=
thermal_zone_trip_id
(
tz
,
trip
);
struct
thermal_instance
*
instance
;
if
(
!
trip
->
hysteresis
)
dev_info_once
(
&
tz
->
device
,
"Zero hysteresis value for thermal zone %s
\n
"
,
tz
->
type
);
dev_dbg
(
&
tz
->
device
,
"Trip%d[temp=%d]:temp=%d:hyst=%d
\n
"
,
trip_index
,
trip
->
temperature
,
tz
->
temperature
,
trip
->
hysteresis
);
list_for_each_entry
(
instance
,
&
tz
->
thermal_instances
,
tz_node
)
{
if
(
instance
->
trip
!=
trip
)
continue
;
/* in case fan is in initial state, switch the fan off */
if
(
instance
->
target
==
THERMAL_NO_TARGET
)
instance
->
target
=
0
;
/* in case fan is neither on nor off set the fan to active */
if
(
instance
->
target
!=
0
&&
instance
->
target
!=
1
)
{
pr_warn
(
"Thermal instance %s controlled by bang-bang has unexpected state: %ld
\n
"
,
instance
->
name
,
instance
->
target
);
instance
->
target
=
1
;
}
/*
* enable fan when temperature exceeds trip_temp and disable
* the fan in case it falls below trip_temp minus hysteresis
*/
if
(
instance
->
target
==
0
&&
tz
->
temperature
>=
trip
->
temperature
)
instance
->
target
=
1
;
else
if
(
instance
->
target
==
1
&&
tz
->
temperature
<
trip
->
temperature
-
trip
->
hysteresis
)
instance
->
target
=
0
;
dev_dbg
(
&
instance
->
cdev
->
device
,
"target=%d
\n
"
,
(
int
)
instance
->
target
);
mutex_lock
(
&
instance
->
cdev
->
lock
);
instance
->
cdev
->
updated
=
false
;
/* cdev needs update */
mutex_unlock
(
&
instance
->
cdev
->
lock
);
}
return
0
;
}
/**
* bang_bang_control - controls devices associated with the given zone
* @tz: thermal_zone_device
* @trip: the trip point
* @crossed_up: whether or not the trip has been crossed on the way up
*
* Regulation Logic: a two point regulation, deliver cooling state depending
* on the previous state shown in this diagram:
...
...
@@ -90,26 +41,54 @@ static int thermal_zone_trip_update(struct thermal_zone_device *tz,
* (trip_temp - hyst) so that the fan gets turned off again.
*
*/
static
int
bang_bang_control
(
struct
thermal_zone_device
*
tz
,
const
struct
thermal_trip
*
trip
)
static
void
bang_bang_control
(
struct
thermal_zone_device
*
tz
,
const
struct
thermal_trip
*
trip
,
bool
crossed_up
)
{
struct
thermal_instance
*
instance
;
int
ret
;
lockdep_assert_held
(
&
tz
->
lock
);
ret
=
thermal_zone_trip_update
(
tz
,
trip
);
if
(
ret
)
return
ret
;
dev_dbg
(
&
tz
->
device
,
"Trip%d[temp=%d]:temp=%d:hyst=%d
\n
"
,
thermal_zone_trip_id
(
tz
,
trip
),
trip
->
temperature
,
tz
->
temperature
,
trip
->
hysteresis
);
list_for_each_entry
(
instance
,
&
tz
->
thermal_instances
,
tz_node
)
{
if
(
instance
->
trip
!=
trip
)
continue
;
if
(
instance
->
target
==
THERMAL_NO_TARGET
)
instance
->
target
=
0
;
if
(
instance
->
target
!=
0
&&
instance
->
target
!=
1
)
{
pr_debug
(
"Unexpected state %ld of thermal instance %s in bang-bang
\n
"
,
instance
->
target
,
instance
->
name
);
instance
->
target
=
1
;
}
/*
* Enable the fan when the trip is crossed on the way up and
* disable it when the trip is crossed on the way down.
*/
if
(
instance
->
target
==
0
&&
crossed_up
)
instance
->
target
=
1
;
else
if
(
instance
->
target
==
1
&&
!
crossed_up
)
instance
->
target
=
0
;
dev_dbg
(
&
instance
->
cdev
->
device
,
"target=%ld
\n
"
,
instance
->
target
);
mutex_lock
(
&
instance
->
cdev
->
lock
);
instance
->
cdev
->
updated
=
false
;
/* cdev needs update */
mutex_unlock
(
&
instance
->
cdev
->
lock
);
}
list_for_each_entry
(
instance
,
&
tz
->
thermal_instances
,
tz_node
)
thermal_cdev_update
(
instance
->
cdev
);
return
0
;
}
static
struct
thermal_governor
thermal_gov_bang_bang
=
{
.
name
=
"bang_bang"
,
.
t
hrottle
=
bang_bang_control
,
.
t
rip_crossed
=
bang_bang_control
,
};
THERMAL_GOVERNOR_DECLARE
(
thermal_gov_bang_bang
);
drivers/thermal/gov_fair_share.c
View file @
8c882f17
...
...
@@ -17,97 +17,111 @@
static
int
get_trip_level
(
struct
thermal_zone_device
*
tz
)
{
const
struct
thermal_trip
*
trip
,
*
level_trip
=
NULL
;
const
struct
thermal_trip_desc
*
level_td
=
NULL
;
const
struct
thermal_trip_desc
*
td
;
int
trip_level
=
-
1
;
for_each_trip
(
tz
,
trip
)
{
if
(
t
rip
->
temperature
>=
tz
->
temperature
)
for_each_trip
_desc
(
tz
,
td
)
{
if
(
t
d
->
threshold
>
tz
->
temperature
)
continue
;
trip_level
++
;
if
(
!
level_t
rip
||
trip
->
temperature
>
level_trip
->
temperature
)
level_t
rip
=
trip
;
if
(
!
level_t
d
||
td
->
threshold
>
level_td
->
threshold
)
level_t
d
=
td
;
}
/* Bail out if the temperature is not greater than any trips. */
if
(
trip_level
<
0
)
return
0
;
trace_thermal_zone_trip
(
tz
,
thermal_zone_trip_id
(
tz
,
level_
trip
),
level_t
rip
->
type
);
trace_thermal_zone_trip
(
tz
,
thermal_zone_trip_id
(
tz
,
&
level_td
->
trip
),
level_t
d
->
trip
.
type
);
return
trip_level
;
}
static
long
get_target_state
(
struct
thermal_zone_device
*
tz
,
struct
thermal_cooling_device
*
cdev
,
int
percentage
,
int
level
)
{
return
(
long
)(
percentage
*
level
*
cdev
->
max_state
)
/
(
100
*
tz
->
num_trips
);
}
/**
* fair_share_throttle - throttles devices associated with the given zone
* @tz: thermal_zone_device
* @trip: trip point
* @trip_level: number of trips crossed by the zone temperature
*
* Throttling Logic: This uses three parameters to calculate the new
* throttle state of the cooling devices associated with the given zone.
*
* Parameters used for Throttling:
* P1. max_state: Maximum throttle state exposed by the cooling device.
* P2.
percentage[i]/100
:
* P2.
weight[i]/total_weight
:
* How 'effective' the 'i'th device is, in cooling the given zone.
* P3.
cur_
trip_level/max_no_of_trips:
* P3. trip_level/max_no_of_trips:
* This describes the extent to which the devices should be throttled.
* We do not want to throttle too much when we trip a lower temperature,
* whereas the throttling is at full swing if we trip critical levels.
* (Heavily assumes the trip points are in ascending order)
* new_state of cooling device = P3 * P2 * P1
*/
static
int
fair_share_throttle
(
struct
thermal_zone_device
*
tz
,
const
struct
thermal_trip
*
trip
)
static
void
fair_share_throttle
(
struct
thermal_zone_device
*
tz
,
const
struct
thermal_trip
*
trip
,
int
trip_level
)
{
struct
thermal_instance
*
instance
;
int
total_weight
=
0
;
int
total_instance
=
0
;
int
cur_trip_level
=
get_trip_level
(
tz
);
lockdep_assert_held
(
&
tz
->
lock
);
int
nr_instances
=
0
;
list_for_each_entry
(
instance
,
&
tz
->
thermal_instances
,
tz_node
)
{
if
(
instance
->
trip
!=
trip
)
continue
;
total_weight
+=
instance
->
weight
;
total_instance
++
;
nr_instances
++
;
}
list_for_each_entry
(
instance
,
&
tz
->
thermal_instances
,
tz_node
)
{
int
percentage
;
struct
thermal_cooling_device
*
cdev
=
instance
->
cdev
;
u64
dividend
;
u32
divisor
;
if
(
instance
->
trip
!=
trip
)
continue
;
if
(
!
total_weight
)
percentage
=
100
/
total_instance
;
else
percentage
=
(
instance
->
weight
*
100
)
/
total_weight
;
instance
->
target
=
get_target_state
(
tz
,
cdev
,
percentage
,
cur_trip_level
);
dividend
=
trip_level
;
dividend
*=
cdev
->
max_state
;
divisor
=
tz
->
num_trips
;
if
(
total_weight
)
{
dividend
*=
instance
->
weight
;
divisor
*=
total_weight
;
}
else
{
divisor
*=
nr_instances
;
}
instance
->
target
=
div_u64
(
dividend
,
divisor
);
mutex_lock
(
&
cdev
->
lock
);
__thermal_cdev_update
(
cdev
);
mutex_unlock
(
&
cdev
->
lock
);
}
}
return
0
;
static
void
fair_share_manage
(
struct
thermal_zone_device
*
tz
)
{
int
trip_level
=
get_trip_level
(
tz
);
const
struct
thermal_trip_desc
*
td
;
lockdep_assert_held
(
&
tz
->
lock
);
for_each_trip_desc
(
tz
,
td
)
{
const
struct
thermal_trip
*
trip
=
&
td
->
trip
;
if
(
trip
->
temperature
==
THERMAL_TEMP_INVALID
||
trip
->
type
==
THERMAL_TRIP_CRITICAL
||
trip
->
type
==
THERMAL_TRIP_HOT
)
continue
;
fair_share_throttle
(
tz
,
trip
,
trip_level
);
}
}
static
struct
thermal_governor
thermal_gov_fair_share
=
{
.
name
=
"fair_share"
,
.
throttle
=
fair_share_throttl
e
,
.
name
=
"fair_share"
,
.
manage
=
fair_share_manag
e
,
};
THERMAL_GOVERNOR_DECLARE
(
thermal_gov_fair_share
);
drivers/thermal/gov_power_allocator.c
View file @
8c882f17
...
...
@@ -395,7 +395,7 @@ static void divvy_up_power(struct power_actor *power, int num_actors,
}
}
static
int
allocate_power
(
struct
thermal_zone_device
*
tz
,
int
control_temp
)
static
void
allocate_power
(
struct
thermal_zone_device
*
tz
,
int
control_temp
)
{
struct
power_allocator_params
*
params
=
tz
->
governor_data
;
unsigned
int
num_actors
=
params
->
num_actors
;
...
...
@@ -410,7 +410,7 @@ static int allocate_power(struct thermal_zone_device *tz, int control_temp)
int
i
=
0
,
ret
;
if
(
!
num_actors
)
return
-
ENODEV
;
return
;
/* Clean all buffers for new power estimations */
memset
(
power
,
0
,
params
->
buffer_size
);
...
...
@@ -471,8 +471,6 @@ static int allocate_power(struct thermal_zone_device *tz, int control_temp)
num_actors
,
power_range
,
max_allocatable_power
,
tz
->
temperature
,
control_temp
-
tz
->
temperature
);
return
0
;
}
/**
...
...
@@ -496,9 +494,11 @@ static void get_governor_trips(struct thermal_zone_device *tz,
const
struct
thermal_trip
*
first_passive
=
NULL
;
const
struct
thermal_trip
*
last_passive
=
NULL
;
const
struct
thermal_trip
*
last_active
=
NULL
;
const
struct
thermal_trip
*
trip
;
const
struct
thermal_trip_desc
*
td
;
for_each_trip_desc
(
tz
,
td
)
{
const
struct
thermal_trip
*
trip
=
&
td
->
trip
;
for_each_trip
(
tz
,
trip
)
{
switch
(
trip
->
type
)
{
case
THERMAL_TRIP_PASSIVE
:
if
(
!
first_passive
)
{
...
...
@@ -743,40 +743,29 @@ static void power_allocator_unbind(struct thermal_zone_device *tz)
tz
->
governor_data
=
NULL
;
}
static
int
power_allocator_throttle
(
struct
thermal_zone_device
*
tz
,
const
struct
thermal_trip
*
trip
)
static
void
power_allocator_manage
(
struct
thermal_zone_device
*
tz
)
{
struct
power_allocator_params
*
params
=
tz
->
governor_data
;
bool
update
;
const
struct
thermal_trip
*
trip
=
params
->
trip_switch_on
;
lockdep_assert_held
(
&
tz
->
lock
);
/*
* We get called for every trip point but we only need to do
* our calculations once
*/
if
(
trip
!=
params
->
trip_max
)
return
0
;
trip
=
params
->
trip_switch_on
;
if
(
trip
&&
tz
->
temperature
<
trip
->
temperature
)
{
update
=
tz
->
passive
;
tz
->
passive
=
0
;
reset_pid_controller
(
params
);
allow_maximum_power
(
tz
,
update
);
return
0
;
allow_maximum_power
(
tz
,
tz
->
passive
);
tz
->
passive
=
0
;
return
;
}
allocate_power
(
tz
,
params
->
trip_max
->
temperature
);
tz
->
passive
=
1
;
return
allocate_power
(
tz
,
params
->
trip_max
->
temperature
);
}
static
struct
thermal_governor
thermal_gov_power_allocator
=
{
.
name
=
"power_allocator"
,
.
bind_to_tz
=
power_allocator_bind
,
.
unbind_from_tz
=
power_allocator_unbind
,
.
throttle
=
power_allocator_throttl
e
,
.
manage
=
power_allocator_manag
e
,
.
update_tz
=
power_allocator_update_tz
,
};
THERMAL_GOVERNOR_DECLARE
(
thermal_gov_power_allocator
);
drivers/thermal/gov_step_wise.c
View file @
8c882f17
...
...
@@ -32,7 +32,6 @@ static unsigned long get_target_state(struct thermal_instance *instance,
{
struct
thermal_cooling_device
*
cdev
=
instance
->
cdev
;
unsigned
long
cur_state
;
unsigned
long
next_target
;
/*
* We keep this instance the way it is by default.
...
...
@@ -40,112 +39,109 @@ static unsigned long get_target_state(struct thermal_instance *instance,
* cdev in use to determine the next_target.
*/
cdev
->
ops
->
get_cur_state
(
cdev
,
&
cur_state
);
next_target
=
instance
->
target
;
dev_dbg
(
&
cdev
->
device
,
"cur_state=%ld
\n
"
,
cur_state
);
if
(
!
instance
->
initialized
)
{
if
(
throttle
)
{
next_target
=
clamp
((
cur_state
+
1
),
instance
->
lower
,
instance
->
upper
);
}
else
{
next_target
=
THERMAL_NO_TARGET
;
}
if
(
throttle
)
return
clamp
(
cur_state
+
1
,
instance
->
lower
,
instance
->
upper
);
return
next_target
;
return
THERMAL_NO_TARGET
;
}
if
(
throttle
)
{
if
(
trend
==
THERMAL_TREND_RAISING
)
next_target
=
clamp
((
cur_state
+
1
),
instance
->
lower
,
instance
->
upper
);
}
else
{
if
(
trend
==
THERMAL_TREND_DROPPING
)
{
if
(
cur_state
<=
instance
->
lower
)
next_target
=
THERMAL_NO_TARGET
;
else
next_target
=
clamp
((
cur_state
-
1
),
instance
->
lower
,
instance
->
upper
);
}
return
clamp
(
cur_state
+
1
,
instance
->
lower
,
instance
->
upper
);
}
else
if
(
trend
==
THERMAL_TREND_DROPPING
)
{
if
(
cur_state
<=
instance
->
lower
)
return
THERMAL_NO_TARGET
;
return
clamp
(
cur_state
-
1
,
instance
->
lower
,
instance
->
upper
);
}
return
next_
target
;
return
instance
->
target
;
}
static
void
thermal_zone_trip_update
(
struct
thermal_zone_device
*
tz
,
const
struct
thermal_trip
*
trip
)
const
struct
thermal_trip
*
trip
,
int
trip_threshold
)
{
enum
thermal_trend
trend
=
get_tz_trend
(
tz
,
trip
);
int
trip_id
=
thermal_zone_trip_id
(
tz
,
trip
);
enum
thermal_trend
trend
;
struct
thermal_instance
*
instance
;
bool
throttle
=
false
;
int
old_target
;
trend
=
get_tz_trend
(
tz
,
trip
);
if
(
tz
->
temperature
>=
trip
->
temperature
)
{
if
(
tz
->
temperature
>=
trip
_threshold
)
{
throttle
=
true
;
trace_thermal_zone_trip
(
tz
,
trip_id
,
trip
->
type
);
}
dev_dbg
(
&
tz
->
device
,
"Trip%d[type=%d,temp=%d]:trend=%d,throttle=%d
\n
"
,
trip_id
,
trip
->
type
,
trip
->
temperature
,
trend
,
throttle
);
trip_id
,
trip
->
type
,
trip
_threshold
,
trend
,
throttle
);
list_for_each_entry
(
instance
,
&
tz
->
thermal_instances
,
tz_node
)
{
int
old_target
;
if
(
instance
->
trip
!=
trip
)
continue
;
old_target
=
instance
->
target
;
instance
->
target
=
get_target_state
(
instance
,
trend
,
throttle
);
dev_dbg
(
&
instance
->
cdev
->
device
,
"old_target=%d, target=%d
\n
"
,
old_target
,
(
int
)
instance
->
target
);
dev_dbg
(
&
instance
->
cdev
->
device
,
"old_target=%d, target=%ld
\n
"
,
old_target
,
instance
->
target
);
if
(
instance
->
initialized
&&
old_target
==
instance
->
target
)
continue
;
if
(
old_target
==
THERMAL_NO_TARGET
&&
instance
->
target
!=
THERMAL_NO_TARGET
)
{
/* Activate a passive thermal instance */
if
(
trip
->
type
==
THERMAL_TRIP_PASSIVE
)
if
(
trip
->
type
==
THERMAL_TRIP_PASSIVE
)
{
/* If needed, update the status of passive polling. */
if
(
old_target
==
THERMAL_NO_TARGET
&&
instance
->
target
!=
THERMAL_NO_TARGET
)
tz
->
passive
++
;
}
else
if
(
old_target
!=
THERMAL_NO_TARGET
&&
instance
->
target
==
THERMAL_NO_TARGET
)
{
/* Deactivate a passive thermal instance */
if
(
trip
->
type
==
THERMAL_TRIP_PASSIVE
)
else
if
(
old_target
!=
THERMAL_NO_TARGET
&&
instance
->
target
==
THERMAL_NO_TARGET
)
tz
->
passive
--
;
}
instance
->
initialized
=
true
;
mutex_lock
(
&
instance
->
cdev
->
lock
);
instance
->
cdev
->
updated
=
false
;
/* cdev needs update */
mutex_unlock
(
&
instance
->
cdev
->
lock
);
}
}
/**
* step_wise_throttle - throttles devices associated with the given zone
* @tz: thermal_zone_device
* @trip: trip point
*
* Throttling Logic: This uses the trend of the thermal zone to throttle.
* If the thermal zone is 'heating up' this throttles all the cooling
* devices associated with the zone and its particular trip point, by one
* step. If the zone is 'cooling down' it brings back the performance of
* the devices by one step.
*/
static
int
step_wise_throttle
(
struct
thermal_zone_device
*
tz
,
const
struct
thermal_trip
*
trip
)
static
void
step_wise_manage
(
struct
thermal_zone_device
*
tz
)
{
const
struct
thermal_trip_desc
*
td
;
struct
thermal_instance
*
instance
;
lockdep_assert_held
(
&
tz
->
lock
);
thermal_zone_trip_update
(
tz
,
trip
);
/*
* Throttling Logic: Use the trend of the thermal zone to throttle.
* If the thermal zone is 'heating up', throttle all of the cooling
* devices associated with each trip point by one step. If the zone
* is 'cooling down', it brings back the performance of the devices
* by one step.
*/
for_each_trip_desc
(
tz
,
td
)
{
const
struct
thermal_trip
*
trip
=
&
td
->
trip
;
if
(
trip
->
temperature
==
THERMAL_TEMP_INVALID
||
trip
->
type
==
THERMAL_TRIP_CRITICAL
||
trip
->
type
==
THERMAL_TRIP_HOT
)
continue
;
thermal_zone_trip_update
(
tz
,
trip
,
td
->
threshold
);
}
list_for_each_entry
(
instance
,
&
tz
->
thermal_instances
,
tz_node
)
thermal_cdev_update
(
instance
->
cdev
);
return
0
;
}
static
struct
thermal_governor
thermal_gov_step_wise
=
{
.
name
=
"step_wise"
,
.
throttle
=
step_wise_throttl
e
,
.
name
=
"step_wise"
,
.
manage
=
step_wise_manag
e
,
};
THERMAL_GOVERNOR_DECLARE
(
thermal_gov_step_wise
);
drivers/thermal/gov_user_space.c
View file @
8c882f17
...
...
@@ -26,11 +26,13 @@ static int user_space_bind(struct thermal_zone_device *tz)
* notify_user_space - Notifies user space about thermal events
* @tz: thermal_zone_device
* @trip: trip point
* @crossed_up: whether or not the trip has been crossed on the way up
*
* This function notifies the user space through UEvents.
*/
static
int
notify_user_space
(
struct
thermal_zone_device
*
tz
,
const
struct
thermal_trip
*
trip
)
static
void
notify_user_space
(
struct
thermal_zone_device
*
tz
,
const
struct
thermal_trip
*
trip
,
bool
crossed_up
)
{
char
*
thermal_prop
[
5
];
int
i
;
...
...
@@ -46,13 +48,11 @@ static int notify_user_space(struct thermal_zone_device *tz,
kobject_uevent_env
(
&
tz
->
device
.
kobj
,
KOBJ_CHANGE
,
thermal_prop
);
for
(
i
=
0
;
i
<
4
;
++
i
)
kfree
(
thermal_prop
[
i
]);
return
0
;
}
static
struct
thermal_governor
thermal_gov_user_space
=
{
.
name
=
"user_space"
,
.
t
hrottle
=
notify_user_space
,
.
t
rip_crossed
=
notify_user_space
,
.
bind_to_tz
=
user_space_bind
,
};
THERMAL_GOVERNOR_DECLARE
(
thermal_gov_user_space
);
drivers/thermal/intel/int340x_thermal/acpi_thermal_rel.c
View file @
8c882f17
...
...
@@ -309,7 +309,7 @@ static int acpi_parse_psvt(acpi_handle handle, int *psvt_count, struct psvt **ps
if
(
knob
->
type
==
ACPI_TYPE_STRING
)
{
memset
(
&
psvt
->
limit
,
0
,
sizeof
(
u64
));
str
ncpy
(
psvt
->
limit
.
string
,
psvt_ptr
->
limit
.
str_ptr
,
knob
->
string
.
length
);
str
scpy
(
psvt
->
limit
.
string
,
psvt_ptr
->
limit
.
str_ptr
,
ACPI_LIMIT_STR_MAX_LEN
);
}
else
{
psvt
->
limit
.
integer
=
psvt_ptr
->
limit
.
integer
;
}
...
...
@@ -468,7 +468,7 @@ static int fill_psvt(char __user *ubuf)
psvt_user
[
i
].
unlimit_coeff
=
psvts
[
i
].
unlimit_coeff
;
psvt_user
[
i
].
control_knob_type
=
psvts
[
i
].
control_knob_type
;
if
(
psvt_user
[
i
].
control_knob_type
==
ACPI_TYPE_STRING
)
str
n
cpy
(
psvt_user
[
i
].
limit
.
string
,
psvts
[
i
].
limit
.
string
,
str
s
cpy
(
psvt_user
[
i
].
limit
.
string
,
psvts
[
i
].
limit
.
string
,
ACPI_LIMIT_STR_MAX_LEN
);
else
psvt_user
[
i
].
limit
.
integer
=
psvts
[
i
].
limit
.
integer
;
...
...
drivers/thermal/intel/intel_hfi.c
View file @
8c882f17
...
...
@@ -159,6 +159,7 @@ struct hfi_cpu_info {
static
DEFINE_PER_CPU
(
struct
hfi_cpu_info
,
hfi_cpu_info
)
=
{
.
index
=
-
1
};
static
int
max_hfi_instances
;
static
int
hfi_clients_nr
;
static
struct
hfi_instance
*
hfi_instances
;
static
struct
hfi_features
hfi_features
;
...
...
@@ -477,8 +478,11 @@ void intel_hfi_online(unsigned int cpu)
enable:
cpumask_set_cpu
(
cpu
,
hfi_instance
->
cpus
);
/* Enable this HFI instance if this is its first online CPU. */
if
(
cpumask_weight
(
hfi_instance
->
cpus
)
==
1
)
{
/*
* Enable this HFI instance if this is its first online CPU and
* there are user-space clients of thermal events.
*/
if
(
cpumask_weight
(
hfi_instance
->
cpus
)
==
1
&&
hfi_clients_nr
>
0
)
{
hfi_set_hw_table
(
hfi_instance
);
hfi_enable
();
}
...
...
@@ -573,18 +577,33 @@ static __init int hfi_parse_features(void)
return
0
;
}
static
void
hfi_do_enable
(
void
)
/*
* If concurrency is not prevented by other means, the HFI enable/disable
* routines must be called under hfi_instance_lock."
*/
static
void
hfi_enable_instance
(
void
*
ptr
)
{
hfi_set_hw_table
(
ptr
);
hfi_enable
();
}
static
void
hfi_disable_instance
(
void
*
ptr
)
{
hfi_disable
();
}
static
void
hfi_syscore_resume
(
void
)
{
/* This code runs only on the boot CPU. */
struct
hfi_cpu_info
*
info
=
&
per_cpu
(
hfi_cpu_info
,
0
);
struct
hfi_instance
*
hfi_instance
=
info
->
hfi_instance
;
/* No locking needed. There is no concurrency with CPU online. */
hfi_set_hw_table
(
hfi_instance
);
hfi_enable
(
);
if
(
hfi_clients_nr
>
0
)
hfi_enable_instance
(
hfi_instance
);
}
static
int
hfi_
do_disable
(
void
)
static
int
hfi_
syscore_suspend
(
void
)
{
/* No locking needed. There is no concurrency with CPU offline. */
hfi_disable
();
...
...
@@ -593,8 +612,58 @@ static int hfi_do_disable(void)
}
static
struct
syscore_ops
hfi_pm_ops
=
{
.
resume
=
hfi_do_enable
,
.
suspend
=
hfi_do_disable
,
.
resume
=
hfi_syscore_resume
,
.
suspend
=
hfi_syscore_suspend
,
};
static
int
hfi_thermal_notify
(
struct
notifier_block
*
nb
,
unsigned
long
state
,
void
*
_notify
)
{
struct
thermal_genl_notify
*
notify
=
_notify
;
struct
hfi_instance
*
hfi_instance
;
smp_call_func_t
func
=
NULL
;
unsigned
int
cpu
;
int
i
;
if
(
notify
->
mcgrp
!=
THERMAL_GENL_EVENT_GROUP
)
return
NOTIFY_DONE
;
if
(
state
!=
THERMAL_NOTIFY_BIND
&&
state
!=
THERMAL_NOTIFY_UNBIND
)
return
NOTIFY_DONE
;
mutex_lock
(
&
hfi_instance_lock
);
switch
(
state
)
{
case
THERMAL_NOTIFY_BIND
:
if
(
++
hfi_clients_nr
==
1
)
func
=
hfi_enable_instance
;
break
;
case
THERMAL_NOTIFY_UNBIND
:
if
(
--
hfi_clients_nr
==
0
)
func
=
hfi_disable_instance
;
break
;
}
if
(
!
func
)
goto
out
;
for
(
i
=
0
;
i
<
max_hfi_instances
;
i
++
)
{
hfi_instance
=
&
hfi_instances
[
i
];
if
(
cpumask_empty
(
hfi_instance
->
cpus
))
continue
;
cpu
=
cpumask_any
(
hfi_instance
->
cpus
);
smp_call_function_single
(
cpu
,
func
,
hfi_instance
,
true
);
}
out:
mutex_unlock
(
&
hfi_instance_lock
);
return
NOTIFY_OK
;
}
static
struct
notifier_block
hfi_thermal_nb
=
{
.
notifier_call
=
hfi_thermal_notify
,
};
void
__init
intel_hfi_init
(
void
)
...
...
@@ -628,10 +697,22 @@ void __init intel_hfi_init(void)
if
(
!
hfi_updates_wq
)
goto
err_nomem
;
/*
* Both thermal core and Intel HFI can not be build as modules.
* As kernel build-in drivers they are initialized before user-space
* starts, hence we can not miss BIND/UNBIND events when applications
* add/remove thermal multicast group to/from a netlink socket.
*/
if
(
thermal_genl_register_notifier
(
&
hfi_thermal_nb
))
goto
err_nl_notif
;
register_syscore_ops
(
&
hfi_pm_ops
);
return
;
err_nl_notif:
destroy_workqueue
(
hfi_updates_wq
);
err_nomem:
for
(
j
=
0
;
j
<
i
;
++
j
)
{
hfi_instance
=
&
hfi_instances
[
j
];
...
...
drivers/thermal/thermal_core.c
View file @
8c882f17
...
...
@@ -15,6 +15,7 @@
#include <linux/slab.h>
#include <linux/kdev_t.h>
#include <linux/idr.h>
#include <linux/list_sort.h>
#include <linux/thermal.h>
#include <linux/reboot.h>
#include <linux/string.h>
...
...
@@ -301,11 +302,12 @@ static void monitor_thermal_zone(struct thermal_zone_device *tz)
thermal_zone_device_set_polling
(
tz
,
tz
->
polling_delay_jiffies
);
}
static
void
handle_non_critical_trips
(
struct
thermal_zone_device
*
tz
,
const
struct
thermal_trip
*
trip
)
static
struct
thermal_governor
*
thermal_get_tz_governor
(
struct
thermal_zone_device
*
tz
)
{
tz
->
governor
?
tz
->
governor
->
throttle
(
tz
,
trip
)
:
def_governor
->
throttle
(
tz
,
trip
);
if
(
tz
->
governor
)
return
tz
->
governor
;
return
def_governor
;
}
void
thermal_governor_update_tz
(
struct
thermal_zone_device
*
tz
,
...
...
@@ -348,10 +350,6 @@ void thermal_zone_device_critical_reboot(struct thermal_zone_device *tz)
static
void
handle_critical_trips
(
struct
thermal_zone_device
*
tz
,
const
struct
thermal_trip
*
trip
)
{
/* If we have not crossed the trip_temp, we do not care. */
if
(
trip
->
temperature
<=
0
||
tz
->
temperature
<
trip
->
temperature
)
return
;
trace_thermal_zone_trip
(
tz
,
thermal_zone_trip_id
(
tz
,
trip
),
trip
->
type
);
if
(
trip
->
type
==
THERMAL_TRIP_CRITICAL
)
...
...
@@ -361,55 +359,53 @@ static void handle_critical_trips(struct thermal_zone_device *tz,
}
static
void
handle_thermal_trip
(
struct
thermal_zone_device
*
tz
,
struct
thermal_trip
*
trip
)
struct
thermal_trip_desc
*
td
,
struct
list_head
*
way_up_list
,
struct
list_head
*
way_down_list
)
{
const
struct
thermal_trip
*
trip
=
&
td
->
trip
;
int
old_threshold
;
if
(
trip
->
temperature
==
THERMAL_TEMP_INVALID
)
return
;
if
(
tz
->
last_temperature
==
THERMAL_TEMP_INVALID
)
{
/* Initialization. */
trip
->
threshold
=
trip
->
temperature
;
if
(
tz
->
temperature
>=
trip
->
threshold
)
trip
->
threshold
-=
trip
->
hysteresis
;
}
else
if
(
tz
->
last_temperature
<
trip
->
threshold
)
{
/*
* If the trip temperature or hysteresis has been updated recently,
* the threshold needs to be computed again using the new values.
* However, its initial value still reflects the old ones and that
* is what needs to be compared with the previous zone temperature
* to decide which action to take.
*/
old_threshold
=
td
->
threshold
;
td
->
threshold
=
trip
->
temperature
;
if
(
tz
->
last_temperature
>=
old_threshold
&&
tz
->
last_temperature
!=
THERMAL_TEMP_INVALID
)
{
/*
* The trip threshold is equal to the trip temperature, unless
* the latter has changed in the meantime. In either case,
* the trip is crossed if the current zone temperature is at
* least equal to its temperature, but otherwise ensure that
* the threshold and the trip temperature will be equal.
* Mitigation is under way, so it needs to stop if the zone
* temperature falls below the low temperature of the trip.
* In that case, the trip temperature becomes the new threshold.
*/
if
(
tz
->
temperature
>=
trip
->
temperature
)
{
thermal_notify_tz_trip_up
(
tz
,
trip
);
thermal_debug_tz_trip_up
(
tz
,
trip
);
trip
->
threshold
=
trip
->
temperature
-
trip
->
hysteresis
;
if
(
tz
->
temperature
<
trip
->
temperature
-
trip
->
hysteresis
)
{
list_add
(
&
td
->
notify_list_node
,
way_down_list
);
td
->
notify_temp
=
trip
->
temperature
-
trip
->
hysteresis
;
}
else
{
t
rip
->
threshold
=
trip
->
temperature
;
t
d
->
threshold
-=
trip
->
hysteresis
;
}
}
else
{
}
else
if
(
tz
->
temperature
>=
trip
->
temperature
)
{
/*
* The previous zone temperature was above or equal to the trip
* threshold, which would be equal to the "low temperature" of
* the trip (its temperature minus its hysteresis), unless the
* trip temperature or hysteresis had changed. In either case,
* the trip is crossed if the current zone temperature is below
* the low temperature of the trip, but otherwise ensure that
* the trip threshold will be equal to the low temperature of
* the trip.
* There is no mitigation under way, so it needs to be started
* if the zone temperature exceeds the trip one. The new
* threshold is then set to the low temperature of the trip.
*/
if
(
tz
->
temperature
<
trip
->
temperature
-
trip
->
hysteresis
)
{
thermal_notify_tz_trip_down
(
tz
,
trip
);
thermal_debug_tz_trip_down
(
tz
,
trip
);
trip
->
threshold
=
trip
->
temperature
;
}
else
{
trip
->
threshold
=
trip
->
temperature
-
trip
->
hysteresis
;
}
}
list_add_tail
(
&
td
->
notify_list_node
,
way_up_list
);
td
->
notify_temp
=
trip
->
temperature
;
td
->
threshold
-=
trip
->
hysteresis
;
if
(
trip
->
type
==
THERMAL_TRIP_CRITICAL
||
trip
->
type
==
THERMAL_TRIP_HOT
)
handle_critical_trips
(
tz
,
trip
);
else
handle_non_critical_trips
(
tz
,
trip
);
if
(
trip
->
type
==
THERMAL_TRIP_CRITICAL
||
trip
->
type
==
THERMAL_TRIP_HOT
)
handle_critical_trips
(
tz
,
trip
);
}
}
static
void
update_temperature
(
struct
thermal_zone_device
*
tz
)
...
...
@@ -431,7 +427,6 @@ static void update_temperature(struct thermal_zone_device *tz)
trace_thermal_temperature
(
tz
);
thermal_genl_sampling_temp
(
tz
->
id
,
temp
);
thermal_debug_update_temp
(
tz
);
}
static
void
thermal_zone_device_check
(
struct
work_struct
*
work
)
...
...
@@ -455,10 +450,34 @@ static void thermal_zone_device_init(struct thermal_zone_device *tz)
pos
->
initialized
=
false
;
}
static
void
thermal_governor_trip_crossed
(
struct
thermal_governor
*
governor
,
struct
thermal_zone_device
*
tz
,
const
struct
thermal_trip
*
trip
,
bool
crossed_up
)
{
if
(
governor
->
trip_crossed
)
governor
->
trip_crossed
(
tz
,
trip
,
crossed_up
);
}
static
int
thermal_trip_notify_cmp
(
void
*
ascending
,
const
struct
list_head
*
a
,
const
struct
list_head
*
b
)
{
struct
thermal_trip_desc
*
tda
=
container_of
(
a
,
struct
thermal_trip_desc
,
notify_list_node
);
struct
thermal_trip_desc
*
tdb
=
container_of
(
b
,
struct
thermal_trip_desc
,
notify_list_node
);
int
ret
=
tdb
->
notify_temp
-
tda
->
notify_temp
;
return
ascending
?
ret
:
-
ret
;
}
void
__thermal_zone_device_update
(
struct
thermal_zone_device
*
tz
,
enum
thermal_notify_event
event
)
{
struct
thermal_trip
*
trip
;
struct
thermal_governor
*
governor
=
thermal_get_tz_governor
(
tz
);
struct
thermal_trip_desc
*
td
;
LIST_HEAD
(
way_down_list
);
LIST_HEAD
(
way_up_list
);
if
(
tz
->
suspended
)
return
;
...
...
@@ -472,8 +491,27 @@ void __thermal_zone_device_update(struct thermal_zone_device *tz,
tz
->
notify_event
=
event
;
for_each_trip
(
tz
,
trip
)
handle_thermal_trip
(
tz
,
trip
);
for_each_trip_desc
(
tz
,
td
)
handle_thermal_trip
(
tz
,
td
,
&
way_up_list
,
&
way_down_list
);
list_sort
(
&
way_up_list
,
&
way_up_list
,
thermal_trip_notify_cmp
);
list_for_each_entry
(
td
,
&
way_up_list
,
notify_list_node
)
{
thermal_notify_tz_trip_up
(
tz
,
&
td
->
trip
);
thermal_debug_tz_trip_up
(
tz
,
&
td
->
trip
);
thermal_governor_trip_crossed
(
governor
,
tz
,
&
td
->
trip
,
true
);
}
list_sort
(
NULL
,
&
way_down_list
,
thermal_trip_notify_cmp
);
list_for_each_entry
(
td
,
&
way_down_list
,
notify_list_node
)
{
thermal_notify_tz_trip_down
(
tz
,
&
td
->
trip
);
thermal_debug_tz_trip_down
(
tz
,
&
td
->
trip
);
thermal_governor_trip_crossed
(
governor
,
tz
,
&
td
->
trip
,
false
);
}
if
(
governor
->
manage
)
governor
->
manage
(
tz
);
thermal_debug_update_trip_stats
(
tz
);
monitor_thermal_zone
(
tz
);
}
...
...
@@ -766,7 +804,7 @@ int thermal_zone_bind_cooling_device(struct thermal_zone_device *tz,
if
(
trip_index
<
0
||
trip_index
>=
tz
->
num_trips
)
return
-
EINVAL
;
return
thermal_bind_cdev_to_trip
(
tz
,
&
tz
->
trips
[
trip_index
],
cdev
,
return
thermal_bind_cdev_to_trip
(
tz
,
&
tz
->
trips
[
trip_index
]
.
trip
,
cdev
,
upper
,
lower
,
weight
);
}
EXPORT_SYMBOL_GPL
(
thermal_zone_bind_cooling_device
);
...
...
@@ -825,7 +863,7 @@ int thermal_zone_unbind_cooling_device(struct thermal_zone_device *tz,
if
(
trip_index
<
0
||
trip_index
>=
tz
->
num_trips
)
return
-
EINVAL
;
return
thermal_unbind_cdev_from_trip
(
tz
,
&
tz
->
trips
[
trip_index
],
cdev
);
return
thermal_unbind_cdev_from_trip
(
tz
,
&
tz
->
trips
[
trip_index
]
.
trip
,
cdev
);
}
EXPORT_SYMBOL_GPL
(
thermal_zone_unbind_cooling_device
);
...
...
@@ -1221,16 +1259,19 @@ static void thermal_set_delay_jiffies(unsigned long *delay_jiffies, int delay_ms
int
thermal_zone_get_crit_temp
(
struct
thermal_zone_device
*
tz
,
int
*
temp
)
{
int
i
,
ret
=
-
EINVAL
;
const
struct
thermal_trip_desc
*
td
;
int
ret
=
-
EINVAL
;
if
(
tz
->
ops
.
get_crit_temp
)
return
tz
->
ops
.
get_crit_temp
(
tz
,
temp
);
mutex_lock
(
&
tz
->
lock
);
for
(
i
=
0
;
i
<
tz
->
num_trips
;
i
++
)
{
if
(
tz
->
trips
[
i
].
type
==
THERMAL_TRIP_CRITICAL
)
{
*
temp
=
tz
->
trips
[
i
].
temperature
;
for_each_trip_desc
(
tz
,
td
)
{
const
struct
thermal_trip
*
trip
=
&
td
->
trip
;
if
(
trip
->
type
==
THERMAL_TRIP_CRITICAL
)
{
*
temp
=
trip
->
temperature
;
ret
=
0
;
break
;
}
...
...
@@ -1274,7 +1315,9 @@ thermal_zone_device_register_with_trips(const char *type,
const
struct
thermal_zone_params
*
tzp
,
int
passive_delay
,
int
polling_delay
)
{
const
struct
thermal_trip
*
trip
=
trips
;
struct
thermal_zone_device
*
tz
;
struct
thermal_trip_desc
*
td
;
int
id
;
int
result
;
struct
thermal_governor
*
governor
;
...
...
@@ -1339,7 +1382,8 @@ thermal_zone_device_register_with_trips(const char *type,
tz
->
device
.
class
=
thermal_class
;
tz
->
devdata
=
devdata
;
tz
->
num_trips
=
num_trips
;
memcpy
(
tz
->
trips
,
trips
,
num_trips
*
sizeof
(
*
trips
));
for_each_trip_desc
(
tz
,
td
)
td
->
trip
=
*
trip
++
;
thermal_set_delay_jiffies
(
&
tz
->
passive_delay_jiffies
,
passive_delay
);
thermal_set_delay_jiffies
(
&
tz
->
polling_delay_jiffies
,
polling_delay
);
...
...
drivers/thermal/thermal_core.h
View file @
8c882f17
...
...
@@ -15,6 +15,120 @@
#include "thermal_netlink.h"
#include "thermal_debugfs.h"
struct
thermal_trip_desc
{
struct
thermal_trip
trip
;
struct
list_head
notify_list_node
;
int
notify_temp
;
int
threshold
;
};
/**
* struct thermal_governor - structure that holds thermal governor information
* @name: name of the governor
* @bind_to_tz: callback called when binding to a thermal zone. If it
* returns 0, the governor is bound to the thermal zone,
* otherwise it fails.
* @unbind_from_tz: callback called when a governor is unbound from a
* thermal zone.
* @trip_crossed: called for trip points that have just been crossed
* @manage: called on thermal zone temperature updates
* @update_tz: callback called when thermal zone internals have changed, e.g.
* thermal cooling instance was added/removed
* @governor_list: node in thermal_governor_list (in thermal_core.c)
*/
struct
thermal_governor
{
const
char
*
name
;
int
(
*
bind_to_tz
)(
struct
thermal_zone_device
*
tz
);
void
(
*
unbind_from_tz
)(
struct
thermal_zone_device
*
tz
);
void
(
*
trip_crossed
)(
struct
thermal_zone_device
*
tz
,
const
struct
thermal_trip
*
trip
,
bool
crossed_up
);
void
(
*
manage
)(
struct
thermal_zone_device
*
tz
);
void
(
*
update_tz
)(
struct
thermal_zone_device
*
tz
,
enum
thermal_notify_event
reason
);
struct
list_head
governor_list
;
};
/**
* struct thermal_zone_device - structure for a thermal zone
* @id: unique id number for each thermal zone
* @type: the thermal zone device type
* @device: &struct device for this thermal zone
* @removal: removal completion
* @trip_temp_attrs: attributes for trip points for sysfs: trip temperature
* @trip_type_attrs: attributes for trip points for sysfs: trip type
* @trip_hyst_attrs: attributes for trip points for sysfs: trip hysteresis
* @mode: current mode of this thermal zone
* @devdata: private pointer for device private data
* @num_trips: number of trip points the thermal zone supports
* @passive_delay_jiffies: number of jiffies to wait between polls when
* performing passive cooling.
* @polling_delay_jiffies: number of jiffies to wait between polls when
* checking whether trip points have been crossed (0 for
* interrupt driven systems)
* @temperature: current temperature. This is only for core code,
* drivers should use thermal_zone_get_temp() to get the
* current temperature
* @last_temperature: previous temperature read
* @emul_temperature: emulated temperature when using CONFIG_THERMAL_EMULATION
* @passive: 1 if you've crossed a passive trip point, 0 otherwise.
* @prev_low_trip: the low current temperature if you've crossed a passive
trip point.
* @prev_high_trip: the above current temperature if you've crossed a
passive trip point.
* @need_update: if equals 1, thermal_zone_device_update needs to be invoked.
* @ops: operations this &thermal_zone_device supports
* @tzp: thermal zone parameters
* @governor: pointer to the governor for this thermal zone
* @governor_data: private pointer for governor data
* @thermal_instances: list of &struct thermal_instance of this thermal zone
* @ida: &struct ida to generate unique id for this zone's cooling
* devices
* @lock: lock to protect thermal_instances list
* @node: node in thermal_tz_list (in thermal_core.c)
* @poll_queue: delayed work for polling
* @notify_event: Last notification event
* @suspended: thermal zone suspend indicator
* @trips: array of struct thermal_trip objects
*/
struct
thermal_zone_device
{
int
id
;
char
type
[
THERMAL_NAME_LENGTH
];
struct
device
device
;
struct
completion
removal
;
struct
attribute_group
trips_attribute_group
;
struct
thermal_attr
*
trip_temp_attrs
;
struct
thermal_attr
*
trip_type_attrs
;
struct
thermal_attr
*
trip_hyst_attrs
;
enum
thermal_device_mode
mode
;
void
*
devdata
;
int
num_trips
;
unsigned
long
passive_delay_jiffies
;
unsigned
long
polling_delay_jiffies
;
int
temperature
;
int
last_temperature
;
int
emul_temperature
;
int
passive
;
int
prev_low_trip
;
int
prev_high_trip
;
atomic_t
need_update
;
struct
thermal_zone_device_ops
ops
;
struct
thermal_zone_params
*
tzp
;
struct
thermal_governor
*
governor
;
void
*
governor_data
;
struct
list_head
thermal_instances
;
struct
ida
ida
;
struct
mutex
lock
;
struct
list_head
node
;
struct
delayed_work
poll_queue
;
enum
thermal_notify_event
notify_event
;
bool
suspended
;
#ifdef CONFIG_THERMAL_DEBUGFS
struct
thermal_debugfs
*
debugfs
;
#endif
struct
thermal_trip_desc
trips
[]
__counted_by
(
num_trips
);
};
/* Default Thermal Governor */
#if defined(CONFIG_THERMAL_DEFAULT_GOV_STEP_WISE)
#define DEFAULT_THERMAL_GOVERNOR "step_wise"
...
...
@@ -120,8 +234,11 @@ void thermal_governor_update_tz(struct thermal_zone_device *tz,
enum
thermal_notify_event
reason
);
/* Helpers */
#define for_each_trip(__tz, __trip) \
for (__trip = __tz->trips; __trip - __tz->trips < __tz->num_trips; __trip++)
#define for_each_trip_desc(__tz, __td) \
for (__td = __tz->trips; __td - __tz->trips < __tz->num_trips; __td++)
#define trip_to_trip_desc(__trip) \
container_of(__trip, struct thermal_trip_desc, trip)
void
__thermal_zone_set_trips
(
struct
thermal_zone_device
*
tz
);
int
thermal_zone_trip_id
(
const
struct
thermal_zone_device
*
tz
,
...
...
drivers/thermal/thermal_debugfs.c
View file @
8c882f17
...
...
@@ -555,7 +555,6 @@ void thermal_debug_tz_trip_up(struct thermal_zone_device *tz,
struct
tz_episode
*
tze
;
struct
tz_debugfs
*
tz_dbg
;
struct
thermal_debugfs
*
thermal_dbg
=
tz
->
debugfs
;
int
temperature
=
tz
->
temperature
;
int
trip_id
=
thermal_zone_trip_id
(
tz
,
trip
);
ktime_t
now
=
ktime_get
();
...
...
@@ -624,12 +623,6 @@ void thermal_debug_tz_trip_up(struct thermal_zone_device *tz,
tze
=
list_first_entry
(
&
tz_dbg
->
tz_episodes
,
struct
tz_episode
,
node
);
tze
->
trip_stats
[
trip_id
].
timestamp
=
now
;
tze
->
trip_stats
[
trip_id
].
max
=
max
(
tze
->
trip_stats
[
trip_id
].
max
,
temperature
);
tze
->
trip_stats
[
trip_id
].
min
=
min
(
tze
->
trip_stats
[
trip_id
].
min
,
temperature
);
tze
->
trip_stats
[
trip_id
].
count
++
;
tze
->
trip_stats
[
trip_id
].
avg
=
tze
->
trip_stats
[
trip_id
].
avg
+
(
temperature
-
tze
->
trip_stats
[
trip_id
].
avg
)
/
tze
->
trip_stats
[
trip_id
].
count
;
unlock:
mutex_unlock
(
&
thermal_dbg
->
lock
);
...
...
@@ -693,12 +686,12 @@ void thermal_debug_tz_trip_down(struct thermal_zone_device *tz,
mutex_unlock
(
&
thermal_dbg
->
lock
);
}
void
thermal_debug_update_t
emp
(
struct
thermal_zone_device
*
tz
)
void
thermal_debug_update_t
rip_stats
(
struct
thermal_zone_device
*
tz
)
{
struct
thermal_debugfs
*
thermal_dbg
=
tz
->
debugfs
;
struct
tz_episode
*
tze
;
struct
tz_debugfs
*
tz_dbg
;
int
trip_id
,
i
;
struct
tz_episode
*
tze
;
int
i
;
if
(
!
thermal_dbg
)
return
;
...
...
@@ -710,15 +703,16 @@ void thermal_debug_update_temp(struct thermal_zone_device *tz)
if
(
!
tz_dbg
->
nr_trips
)
goto
out
;
tze
=
list_first_entry
(
&
tz_dbg
->
tz_episodes
,
struct
tz_episode
,
node
);
for
(
i
=
0
;
i
<
tz_dbg
->
nr_trips
;
i
++
)
{
trip_id
=
tz_dbg
->
trips_crossed
[
i
];
tze
=
list_first_entry
(
&
tz_dbg
->
tz_episodes
,
struct
tz_episode
,
node
);
tze
->
trip_stats
[
trip_id
].
count
++
;
tze
->
trip_stats
[
trip_id
].
max
=
max
(
tze
->
trip_stats
[
trip_id
].
max
,
tz
->
temperature
);
tze
->
trip_stats
[
trip_id
].
min
=
min
(
tze
->
trip_stats
[
trip_id
].
min
,
tz
->
temperature
);
tze
->
trip_stats
[
trip_id
].
avg
=
tze
->
trip_stats
[
trip_id
].
avg
+
(
tz
->
temperature
-
tze
->
trip_stats
[
trip_id
].
avg
)
/
tze
->
trip_stats
[
trip_id
].
count
;
int
trip_id
=
tz_dbg
->
trips_crossed
[
i
];
struct
trip_stats
*
trip_stats
=
&
tze
->
trip_stats
[
trip_id
];
trip_stats
->
max
=
max
(
trip_stats
->
max
,
tz
->
temperature
);
trip_stats
->
min
=
min
(
trip_stats
->
min
,
tz
->
temperature
);
trip_stats
->
avg
+=
(
tz
->
temperature
-
trip_stats
->
avg
)
/
++
trip_stats
->
count
;
}
out:
mutex_unlock
(
&
thermal_dbg
->
lock
);
...
...
@@ -753,7 +747,7 @@ static int tze_seq_show(struct seq_file *s, void *v)
{
struct
thermal_debugfs
*
thermal_dbg
=
s
->
private
;
struct
thermal_zone_device
*
tz
=
thermal_dbg
->
tz_dbg
.
tz
;
struct
thermal_trip
*
trip
;
struct
thermal_trip
_desc
*
td
;
struct
tz_episode
*
tze
;
const
char
*
type
;
int
trip_id
;
...
...
@@ -766,7 +760,14 @@ static int tze_seq_show(struct seq_file *s, void *v)
seq_printf
(
s
,
"| trip | type | temp(°mC) | hyst(°mC) | duration | avg(°mC) | min(°mC) | max(°mC) |
\n
"
);
for_each_trip
(
tz
,
trip
)
{
for_each_trip_desc
(
tz
,
td
)
{
const
struct
thermal_trip
*
trip
=
&
td
->
trip
;
struct
trip_stats
*
trip_stats
;
/* Skip invalid trips. */
if
(
trip
->
temperature
==
THERMAL_TEMP_INVALID
)
continue
;
/*
* There is no possible mitigation happening at the
* critical trip point, so the stats will be always
...
...
@@ -775,6 +776,13 @@ static int tze_seq_show(struct seq_file *s, void *v)
if
(
trip
->
type
==
THERMAL_TRIP_CRITICAL
)
continue
;
trip_id
=
thermal_zone_trip_id
(
tz
,
trip
);
trip_stats
=
&
tze
->
trip_stats
[
trip_id
];
/* Skip trips without any stats. */
if
(
trip_stats
->
min
>
trip_stats
->
max
)
continue
;
if
(
trip
->
type
==
THERMAL_TRIP_PASSIVE
)
type
=
"passive"
;
else
if
(
trip
->
type
==
THERMAL_TRIP_ACTIVE
)
...
...
@@ -782,17 +790,15 @@ static int tze_seq_show(struct seq_file *s, void *v)
else
type
=
"hot"
;
trip_id
=
thermal_zone_trip_id
(
tz
,
trip
);
seq_printf
(
s
,
"| %*d | %*s | %*d | %*d | %*lld | %*d | %*d | %*d |
\n
"
,
4
,
trip_id
,
8
,
type
,
9
,
trip
->
temperature
,
9
,
trip
->
hysteresis
,
10
,
ktime_to_ms
(
t
ze
->
trip_stats
[
trip_id
].
duration
),
9
,
t
ze
->
trip_stats
[
trip_id
].
avg
,
9
,
t
ze
->
trip_stats
[
trip_id
].
min
,
9
,
t
ze
->
trip_stats
[
trip_id
].
max
);
10
,
ktime_to_ms
(
t
rip_stats
->
duration
),
9
,
t
rip_stats
->
avg
,
9
,
t
rip_stats
->
min
,
9
,
t
rip_stats
->
max
);
}
return
0
;
...
...
drivers/thermal/thermal_debugfs.h
View file @
8c882f17
...
...
@@ -11,7 +11,7 @@ void thermal_debug_tz_trip_up(struct thermal_zone_device *tz,
const
struct
thermal_trip
*
trip
);
void
thermal_debug_tz_trip_down
(
struct
thermal_zone_device
*
tz
,
const
struct
thermal_trip
*
trip
);
void
thermal_debug_update_t
emp
(
struct
thermal_zone_device
*
tz
);
void
thermal_debug_update_t
rip_stats
(
struct
thermal_zone_device
*
tz
);
#else
static
inline
void
thermal_debug_init
(
void
)
{}
static
inline
void
thermal_debug_cdev_add
(
struct
thermal_cooling_device
*
cdev
)
{}
...
...
@@ -24,5 +24,5 @@ static inline void thermal_debug_tz_trip_up(struct thermal_zone_device *tz,
const
struct
thermal_trip
*
trip
)
{};
static
inline
void
thermal_debug_tz_trip_down
(
struct
thermal_zone_device
*
tz
,
const
struct
thermal_trip
*
trip
)
{}
static
inline
void
thermal_debug_update_t
emp
(
struct
thermal_zone_device
*
tz
)
{}
static
inline
void
thermal_debug_update_t
rip_stats
(
struct
thermal_zone_device
*
tz
)
{}
#endif
/* CONFIG_THERMAL_DEBUGFS */
drivers/thermal/thermal_helpers.c
View file @
8c882f17
...
...
@@ -50,7 +50,7 @@ get_thermal_instance(struct thermal_zone_device *tz,
mutex_lock
(
&
tz
->
lock
);
mutex_lock
(
&
cdev
->
lock
);
trip
=
&
tz
->
trips
[
trip_index
];
trip
=
&
tz
->
trips
[
trip_index
]
.
trip
;
list_for_each_entry
(
pos
,
&
tz
->
thermal_instances
,
tz_node
)
{
if
(
pos
->
tz
==
tz
&&
pos
->
trip
==
trip
&&
pos
->
cdev
==
cdev
)
{
...
...
@@ -82,7 +82,7 @@ EXPORT_SYMBOL(get_thermal_instance);
*/
int
__thermal_zone_get_temp
(
struct
thermal_zone_device
*
tz
,
int
*
temp
)
{
const
struct
thermal_trip
*
trip
;
const
struct
thermal_trip
_desc
*
td
;
int
crit_temp
=
INT_MAX
;
int
ret
=
-
EINVAL
;
...
...
@@ -91,7 +91,9 @@ int __thermal_zone_get_temp(struct thermal_zone_device *tz, int *temp)
ret
=
tz
->
ops
.
get_temp
(
tz
,
temp
);
if
(
IS_ENABLED
(
CONFIG_THERMAL_EMULATION
)
&&
tz
->
emul_temperature
)
{
for_each_trip
(
tz
,
trip
)
{
for_each_trip_desc
(
tz
,
td
)
{
const
struct
thermal_trip
*
trip
=
&
td
->
trip
;
if
(
trip
->
type
==
THERMAL_TRIP_CRITICAL
)
{
crit_temp
=
trip
->
temperature
;
break
;
...
...
drivers/thermal/thermal_netlink.c
View file @
8c882f17
...
...
@@ -7,17 +7,13 @@
* Generic netlink for thermal management framework
*/
#include <linux/module.h>
#include <linux/notifier.h>
#include <linux/kernel.h>
#include <net/genetlink.h>
#include <uapi/linux/thermal.h>
#include "thermal_core.h"
enum
thermal_genl_multicast_groups
{
THERMAL_GENL_SAMPLING_GROUP
=
0
,
THERMAL_GENL_EVENT_GROUP
=
1
,
};
static
const
struct
genl_multicast_group
thermal_genl_mcgrps
[]
=
{
[
THERMAL_GENL_SAMPLING_GROUP
]
=
{
.
name
=
THERMAL_GENL_SAMPLING_GROUP_NAME
,
},
[
THERMAL_GENL_EVENT_GROUP
]
=
{
.
name
=
THERMAL_GENL_EVENT_GROUP_NAME
,
},
...
...
@@ -74,11 +70,12 @@ struct param {
typedef
int
(
*
cb_t
)(
struct
param
*
);
static
struct
genl_family
thermal_gnl_family
;
static
struct
genl_family
thermal_genl_family
;
static
BLOCKING_NOTIFIER_HEAD
(
thermal_genl_chain
);
static
int
thermal_group_has_listeners
(
enum
thermal_genl_multicast_groups
group
)
{
return
genl_has_listeners
(
&
thermal_gnl_family
,
&
init_net
,
group
);
return
genl_has_listeners
(
&
thermal_g
e
nl_family
,
&
init_net
,
group
);
}
/************************** Sampling encoding *******************************/
...
...
@@ -95,7 +92,7 @@ int thermal_genl_sampling_temp(int id, int temp)
if
(
!
skb
)
return
-
ENOMEM
;
hdr
=
genlmsg_put
(
skb
,
0
,
0
,
&
thermal_gnl_family
,
0
,
hdr
=
genlmsg_put
(
skb
,
0
,
0
,
&
thermal_g
e
nl_family
,
0
,
THERMAL_GENL_SAMPLING_TEMP
);
if
(
!
hdr
)
goto
out_free
;
...
...
@@ -108,7 +105,7 @@ int thermal_genl_sampling_temp(int id, int temp)
genlmsg_end
(
skb
,
hdr
);
genlmsg_multicast
(
&
thermal_gnl_family
,
skb
,
0
,
THERMAL_GENL_SAMPLING_GROUP
,
GFP_KERNEL
);
genlmsg_multicast
(
&
thermal_g
e
nl_family
,
skb
,
0
,
THERMAL_GENL_SAMPLING_GROUP
,
GFP_KERNEL
);
return
0
;
out_cancel:
...
...
@@ -282,7 +279,7 @@ static int thermal_genl_send_event(enum thermal_genl_event event,
return
-
ENOMEM
;
p
->
msg
=
msg
;
hdr
=
genlmsg_put
(
msg
,
0
,
0
,
&
thermal_gnl_family
,
0
,
event
);
hdr
=
genlmsg_put
(
msg
,
0
,
0
,
&
thermal_g
e
nl_family
,
0
,
event
);
if
(
!
hdr
)
goto
out_free_msg
;
...
...
@@ -292,7 +289,7 @@ static int thermal_genl_send_event(enum thermal_genl_event event,
genlmsg_end
(
msg
,
hdr
);
genlmsg_multicast
(
&
thermal_gnl_family
,
msg
,
0
,
THERMAL_GENL_EVENT_GROUP
,
GFP_KERNEL
);
genlmsg_multicast
(
&
thermal_g
e
nl_family
,
msg
,
0
,
THERMAL_GENL_EVENT_GROUP
,
GFP_KERNEL
);
return
0
;
...
...
@@ -445,7 +442,7 @@ static int thermal_genl_cmd_tz_get_id(struct param *p)
static
int
thermal_genl_cmd_tz_get_trip
(
struct
param
*
p
)
{
struct
sk_buff
*
msg
=
p
->
msg
;
const
struct
thermal_trip
*
trip
;
const
struct
thermal_trip
_desc
*
td
;
struct
thermal_zone_device
*
tz
;
struct
nlattr
*
start_trip
;
int
id
;
...
...
@@ -465,7 +462,9 @@ static int thermal_genl_cmd_tz_get_trip(struct param *p)
mutex_lock
(
&
tz
->
lock
);
for_each_trip
(
tz
,
trip
)
{
for_each_trip_desc
(
tz
,
td
)
{
const
struct
thermal_trip
*
trip
=
&
td
->
trip
;
if
(
nla_put_u32
(
msg
,
THERMAL_GENL_ATTR_TZ_TRIP_ID
,
thermal_zone_trip_id
(
tz
,
trip
))
||
nla_put_u32
(
msg
,
THERMAL_GENL_ATTR_TZ_TRIP_TYPE
,
trip
->
type
)
||
...
...
@@ -593,7 +592,7 @@ static int thermal_genl_cmd_dumpit(struct sk_buff *skb,
int
ret
;
void
*
hdr
;
hdr
=
genlmsg_put
(
skb
,
0
,
0
,
&
thermal_gnl_family
,
0
,
cmd
);
hdr
=
genlmsg_put
(
skb
,
0
,
0
,
&
thermal_g
e
nl_family
,
0
,
cmd
);
if
(
!
hdr
)
return
-
EMSGSIZE
;
...
...
@@ -625,7 +624,7 @@ static int thermal_genl_cmd_doit(struct sk_buff *skb,
return
-
ENOMEM
;
p
.
msg
=
msg
;
hdr
=
genlmsg_put_reply
(
msg
,
info
,
&
thermal_gnl_family
,
0
,
cmd
);
hdr
=
genlmsg_put_reply
(
msg
,
info
,
&
thermal_g
e
nl_family
,
0
,
cmd
);
if
(
!
hdr
)
goto
out_free_msg
;
...
...
@@ -645,6 +644,27 @@ static int thermal_genl_cmd_doit(struct sk_buff *skb,
return
ret
;
}
static
int
thermal_genl_bind
(
int
mcgrp
)
{
struct
thermal_genl_notify
n
=
{
.
mcgrp
=
mcgrp
};
if
(
WARN_ON_ONCE
(
mcgrp
>
THERMAL_GENL_MAX_GROUP
))
return
-
EINVAL
;
blocking_notifier_call_chain
(
&
thermal_genl_chain
,
THERMAL_NOTIFY_BIND
,
&
n
);
return
0
;
}
static
void
thermal_genl_unbind
(
int
mcgrp
)
{
struct
thermal_genl_notify
n
=
{
.
mcgrp
=
mcgrp
};
if
(
WARN_ON_ONCE
(
mcgrp
>
THERMAL_GENL_MAX_GROUP
))
return
;
blocking_notifier_call_chain
(
&
thermal_genl_chain
,
THERMAL_NOTIFY_UNBIND
,
&
n
);
}
static
const
struct
genl_small_ops
thermal_genl_ops
[]
=
{
{
.
cmd
=
THERMAL_GENL_CMD_TZ_GET_ID
,
...
...
@@ -673,12 +693,14 @@ static const struct genl_small_ops thermal_genl_ops[] = {
},
};
static
struct
genl_family
thermal_gnl_family
__ro_after_init
=
{
static
struct
genl_family
thermal_g
e
nl_family
__ro_after_init
=
{
.
hdrsize
=
0
,
.
name
=
THERMAL_GENL_FAMILY_NAME
,
.
version
=
THERMAL_GENL_VERSION
,
.
maxattr
=
THERMAL_GENL_ATTR_MAX
,
.
policy
=
thermal_genl_policy
,
.
bind
=
thermal_genl_bind
,
.
unbind
=
thermal_genl_unbind
,
.
small_ops
=
thermal_genl_ops
,
.
n_small_ops
=
ARRAY_SIZE
(
thermal_genl_ops
),
.
resv_start_op
=
THERMAL_GENL_CMD_CDEV_GET
+
1
,
...
...
@@ -686,12 +708,22 @@ static struct genl_family thermal_gnl_family __ro_after_init = {
.
n_mcgrps
=
ARRAY_SIZE
(
thermal_genl_mcgrps
),
};
int
thermal_genl_register_notifier
(
struct
notifier_block
*
nb
)
{
return
blocking_notifier_chain_register
(
&
thermal_genl_chain
,
nb
);
}
int
thermal_genl_unregister_notifier
(
struct
notifier_block
*
nb
)
{
return
blocking_notifier_chain_unregister
(
&
thermal_genl_chain
,
nb
);
}
int
__init
thermal_netlink_init
(
void
)
{
return
genl_register_family
(
&
thermal_gnl_family
);
return
genl_register_family
(
&
thermal_g
e
nl_family
);
}
void
__init
thermal_netlink_exit
(
void
)
{
genl_unregister_family
(
&
thermal_gnl_family
);
genl_unregister_family
(
&
thermal_g
e
nl_family
);
}
drivers/thermal/thermal_netlink.h
View file @
8c882f17
...
...
@@ -10,6 +10,19 @@ struct thermal_genl_cpu_caps {
int
efficiency
;
};
enum
thermal_genl_multicast_groups
{
THERMAL_GENL_SAMPLING_GROUP
=
0
,
THERMAL_GENL_EVENT_GROUP
=
1
,
THERMAL_GENL_MAX_GROUP
=
THERMAL_GENL_EVENT_GROUP
,
};
#define THERMAL_NOTIFY_BIND 0
#define THERMAL_NOTIFY_UNBIND 1
struct
thermal_genl_notify
{
int
mcgrp
;
};
struct
thermal_zone_device
;
struct
thermal_trip
;
struct
thermal_cooling_device
;
...
...
@@ -18,6 +31,9 @@ struct thermal_cooling_device;
#ifdef CONFIG_THERMAL_NETLINK
int
__init
thermal_netlink_init
(
void
);
void
__init
thermal_netlink_exit
(
void
);
int
thermal_genl_register_notifier
(
struct
notifier_block
*
nb
);
int
thermal_genl_unregister_notifier
(
struct
notifier_block
*
nb
);
int
thermal_notify_tz_create
(
const
struct
thermal_zone_device
*
tz
);
int
thermal_notify_tz_delete
(
const
struct
thermal_zone_device
*
tz
);
int
thermal_notify_tz_enable
(
const
struct
thermal_zone_device
*
tz
);
...
...
@@ -48,6 +64,16 @@ static inline int thermal_notify_tz_create(const struct thermal_zone_device *tz)
return
0
;
}
static
inline
int
thermal_genl_register_notifier
(
struct
notifier_block
*
nb
)
{
return
0
;
}
static
inline
int
thermal_genl_unregister_notifier
(
struct
notifier_block
*
nb
)
{
return
0
;
}
static
inline
int
thermal_notify_tz_delete
(
const
struct
thermal_zone_device
*
tz
)
{
return
0
;
...
...
drivers/thermal/thermal_sysfs.c
View file @
8c882f17
...
...
@@ -88,7 +88,7 @@ trip_point_type_show(struct device *dev, struct device_attribute *attr,
if
(
sscanf
(
attr
->
attr
.
name
,
"trip_point_%d_type"
,
&
trip_id
)
!=
1
)
return
-
EINVAL
;
switch
(
tz
->
trips
[
trip_id
].
type
)
{
switch
(
tz
->
trips
[
trip_id
].
t
rip
.
t
ype
)
{
case
THERMAL_TRIP_CRITICAL
:
return
sprintf
(
buf
,
"critical
\n
"
);
case
THERMAL_TRIP_HOT
:
...
...
@@ -120,7 +120,7 @@ trip_point_temp_store(struct device *dev, struct device_attribute *attr,
mutex_lock
(
&
tz
->
lock
);
trip
=
&
tz
->
trips
[
trip_id
];
trip
=
&
tz
->
trips
[
trip_id
]
.
trip
;
if
(
temp
!=
trip
->
temperature
)
{
if
(
tz
->
ops
.
set_trip_temp
)
{
...
...
@@ -150,7 +150,7 @@ trip_point_temp_show(struct device *dev, struct device_attribute *attr,
if
(
sscanf
(
attr
->
attr
.
name
,
"trip_point_%d_temp"
,
&
trip_id
)
!=
1
)
return
-
EINVAL
;
return
sprintf
(
buf
,
"%d
\n
"
,
tz
->
trips
[
trip_id
].
temperature
);
return
sprintf
(
buf
,
"%d
\n
"
,
tz
->
trips
[
trip_id
].
t
rip
.
t
emperature
);
}
static
ssize_t
...
...
@@ -171,7 +171,7 @@ trip_point_hyst_store(struct device *dev, struct device_attribute *attr,
mutex_lock
(
&
tz
->
lock
);
trip
=
&
tz
->
trips
[
trip_id
];
trip
=
&
tz
->
trips
[
trip_id
]
.
trip
;
if
(
hyst
!=
trip
->
hysteresis
)
{
trip
->
hysteresis
=
hyst
;
...
...
@@ -194,7 +194,7 @@ trip_point_hyst_show(struct device *dev, struct device_attribute *attr,
if
(
sscanf
(
attr
->
attr
.
name
,
"trip_point_%d_hyst"
,
&
trip_id
)
!=
1
)
return
-
EINVAL
;
return
sprintf
(
buf
,
"%d
\n
"
,
tz
->
trips
[
trip_id
].
hysteresis
);
return
sprintf
(
buf
,
"%d
\n
"
,
tz
->
trips
[
trip_id
].
trip
.
hysteresis
);
}
static
ssize_t
...
...
@@ -393,7 +393,7 @@ static const struct attribute_group *thermal_zone_attribute_groups[] = {
*/
static
int
create_trip_attrs
(
struct
thermal_zone_device
*
tz
)
{
const
struct
thermal_trip
*
trip
;
const
struct
thermal_trip
_desc
*
td
;
struct
attribute
**
attrs
;
/* This function works only for zones with at least one trip */
...
...
@@ -429,8 +429,8 @@ static int create_trip_attrs(struct thermal_zone_device *tz)
return
-
ENOMEM
;
}
for_each_trip
(
tz
,
trip
)
{
int
indx
=
thermal_zone_trip_id
(
tz
,
trip
);
for_each_trip
_desc
(
tz
,
td
)
{
int
indx
=
thermal_zone_trip_id
(
tz
,
&
td
->
trip
);
/* create trip type attribute */
snprintf
(
tz
->
trip_type_attrs
[
indx
].
name
,
THERMAL_NAME_LENGTH
,
...
...
@@ -452,7 +452,7 @@ static int create_trip_attrs(struct thermal_zone_device *tz)
tz
->
trip_temp_attrs
[
indx
].
name
;
tz
->
trip_temp_attrs
[
indx
].
attr
.
attr
.
mode
=
S_IRUGO
;
tz
->
trip_temp_attrs
[
indx
].
attr
.
show
=
trip_point_temp_show
;
if
(
t
rip
->
flags
&
THERMAL_TRIP_FLAG_RW_TEMP
)
{
if
(
t
d
->
trip
.
flags
&
THERMAL_TRIP_FLAG_RW_TEMP
)
{
tz
->
trip_temp_attrs
[
indx
].
attr
.
attr
.
mode
|=
S_IWUSR
;
tz
->
trip_temp_attrs
[
indx
].
attr
.
store
=
trip_point_temp_store
;
...
...
@@ -467,7 +467,7 @@ static int create_trip_attrs(struct thermal_zone_device *tz)
tz
->
trip_hyst_attrs
[
indx
].
name
;
tz
->
trip_hyst_attrs
[
indx
].
attr
.
attr
.
mode
=
S_IRUGO
;
tz
->
trip_hyst_attrs
[
indx
].
attr
.
show
=
trip_point_hyst_show
;
if
(
t
rip
->
flags
&
THERMAL_TRIP_FLAG_RW_HYST
)
{
if
(
t
d
->
trip
.
flags
&
THERMAL_TRIP_FLAG_RW_HYST
)
{
tz
->
trip_hyst_attrs
[
indx
].
attr
.
attr
.
mode
|=
S_IWUSR
;
tz
->
trip_hyst_attrs
[
indx
].
attr
.
store
=
trip_point_hyst_store
;
...
...
drivers/thermal/thermal_trace.h
View file @
8c882f17
...
...
@@ -9,6 +9,8 @@
#include <linux/thermal.h>
#include <linux/tracepoint.h>
#include "thermal_core.h"
TRACE_DEFINE_ENUM
(
THERMAL_TRIP_CRITICAL
);
TRACE_DEFINE_ENUM
(
THERMAL_TRIP_HOT
);
TRACE_DEFINE_ENUM
(
THERMAL_TRIP_PASSIVE
);
...
...
drivers/thermal/thermal_trace_ipa.h
View file @
8c882f17
...
...
@@ -7,6 +7,8 @@
#include <linux/tracepoint.h>
#include "thermal_core.h"
TRACE_EVENT
(
thermal_power_allocator
,
TP_PROTO
(
struct
thermal_zone_device
*
tz
,
u32
total_req_power
,
u32
total_granted_power
,
int
num_actors
,
u32
power_range
,
...
...
drivers/thermal/thermal_trip.c
View file @
8c882f17
...
...
@@ -13,11 +13,11 @@ int for_each_thermal_trip(struct thermal_zone_device *tz,
int
(
*
cb
)(
struct
thermal_trip
*
,
void
*
),
void
*
data
)
{
struct
thermal_trip
*
trip
;
struct
thermal_trip
_desc
*
td
;
int
ret
;
for_each_trip
(
tz
,
trip
)
{
ret
=
cb
(
trip
,
data
);
for_each_trip
_desc
(
tz
,
td
)
{
ret
=
cb
(
&
td
->
trip
,
data
);
if
(
ret
)
return
ret
;
}
...
...
@@ -63,7 +63,7 @@ EXPORT_SYMBOL_GPL(thermal_zone_get_num_trips);
*/
void
__thermal_zone_set_trips
(
struct
thermal_zone_device
*
tz
)
{
const
struct
thermal_trip
*
trip
;
const
struct
thermal_trip
_desc
*
td
;
int
low
=
-
INT_MAX
,
high
=
INT_MAX
;
int
ret
;
...
...
@@ -72,7 +72,8 @@ void __thermal_zone_set_trips(struct thermal_zone_device *tz)
if
(
!
tz
->
ops
.
set_trips
)
return
;
for_each_trip
(
tz
,
trip
)
{
for_each_trip_desc
(
tz
,
td
)
{
const
struct
thermal_trip
*
trip
=
&
td
->
trip
;
int
trip_low
;
trip_low
=
trip
->
temperature
-
trip
->
hysteresis
;
...
...
@@ -110,7 +111,7 @@ int __thermal_zone_get_trip(struct thermal_zone_device *tz, int trip_id,
if
(
!
tz
||
trip_id
<
0
||
trip_id
>=
tz
->
num_trips
||
!
trip
)
return
-
EINVAL
;
*
trip
=
tz
->
trips
[
trip_id
];
*
trip
=
tz
->
trips
[
trip_id
]
.
trip
;
return
0
;
}
EXPORT_SYMBOL_GPL
(
__thermal_zone_get_trip
);
...
...
@@ -135,7 +136,7 @@ int thermal_zone_trip_id(const struct thermal_zone_device *tz,
* Assume the trip to be located within the bounds of the thermal
* zone's trips[] table.
*/
return
trip
-
tz
->
trips
;
return
trip
_to_trip_desc
(
trip
)
-
tz
->
trips
;
}
void
thermal_zone_trip_updated
(
struct
thermal_zone_device
*
tz
,
const
struct
thermal_trip
*
trip
)
...
...
include/linux/thermal.h
View file @
8c882f17
...
...
@@ -61,7 +61,6 @@ enum thermal_notify_event {
* struct thermal_trip - representation of a point in temperature domain
* @temperature: temperature value in miliCelsius
* @hysteresis: relative hysteresis in miliCelsius
* @threshold: trip crossing notification threshold miliCelsius
* @type: trip point type
* @priv: pointer to driver data associated with this trip
* @flags: flags representing binary properties of the trip
...
...
@@ -69,7 +68,6 @@ enum thermal_notify_event {
struct
thermal_trip
{
int
temperature
;
int
hysteresis
;
int
threshold
;
enum
thermal_trip_type
type
;
u8
flags
;
void
*
priv
;
...
...
@@ -81,6 +79,8 @@ struct thermal_trip {
#define THERMAL_TRIP_FLAG_RW (THERMAL_TRIP_FLAG_RW_TEMP | \
THERMAL_TRIP_FLAG_RW_HYST)
struct
thermal_zone_device
;
struct
thermal_zone_device_ops
{
int
(
*
bind
)
(
struct
thermal_zone_device
*
,
struct
thermal_cooling_device
*
);
...
...
@@ -126,111 +126,6 @@ struct thermal_cooling_device {
#endif
};
/**
* struct thermal_zone_device - structure for a thermal zone
* @id: unique id number for each thermal zone
* @type: the thermal zone device type
* @device: &struct device for this thermal zone
* @removal: removal completion
* @trip_temp_attrs: attributes for trip points for sysfs: trip temperature
* @trip_type_attrs: attributes for trip points for sysfs: trip type
* @trip_hyst_attrs: attributes for trip points for sysfs: trip hysteresis
* @mode: current mode of this thermal zone
* @devdata: private pointer for device private data
* @num_trips: number of trip points the thermal zone supports
* @passive_delay_jiffies: number of jiffies to wait between polls when
* performing passive cooling.
* @polling_delay_jiffies: number of jiffies to wait between polls when
* checking whether trip points have been crossed (0 for
* interrupt driven systems)
* @temperature: current temperature. This is only for core code,
* drivers should use thermal_zone_get_temp() to get the
* current temperature
* @last_temperature: previous temperature read
* @emul_temperature: emulated temperature when using CONFIG_THERMAL_EMULATION
* @passive: 1 if you've crossed a passive trip point, 0 otherwise.
* @prev_low_trip: the low current temperature if you've crossed a passive
trip point.
* @prev_high_trip: the above current temperature if you've crossed a
passive trip point.
* @need_update: if equals 1, thermal_zone_device_update needs to be invoked.
* @ops: operations this &thermal_zone_device supports
* @tzp: thermal zone parameters
* @governor: pointer to the governor for this thermal zone
* @governor_data: private pointer for governor data
* @thermal_instances: list of &struct thermal_instance of this thermal zone
* @ida: &struct ida to generate unique id for this zone's cooling
* devices
* @lock: lock to protect thermal_instances list
* @node: node in thermal_tz_list (in thermal_core.c)
* @poll_queue: delayed work for polling
* @notify_event: Last notification event
* @suspended: thermal zone suspend indicator
* @trips: array of struct thermal_trip objects
*/
struct
thermal_zone_device
{
int
id
;
char
type
[
THERMAL_NAME_LENGTH
];
struct
device
device
;
struct
completion
removal
;
struct
attribute_group
trips_attribute_group
;
struct
thermal_attr
*
trip_temp_attrs
;
struct
thermal_attr
*
trip_type_attrs
;
struct
thermal_attr
*
trip_hyst_attrs
;
enum
thermal_device_mode
mode
;
void
*
devdata
;
int
num_trips
;
unsigned
long
passive_delay_jiffies
;
unsigned
long
polling_delay_jiffies
;
int
temperature
;
int
last_temperature
;
int
emul_temperature
;
int
passive
;
int
prev_low_trip
;
int
prev_high_trip
;
atomic_t
need_update
;
struct
thermal_zone_device_ops
ops
;
struct
thermal_zone_params
*
tzp
;
struct
thermal_governor
*
governor
;
void
*
governor_data
;
struct
list_head
thermal_instances
;
struct
ida
ida
;
struct
mutex
lock
;
struct
list_head
node
;
struct
delayed_work
poll_queue
;
enum
thermal_notify_event
notify_event
;
bool
suspended
;
#ifdef CONFIG_THERMAL_DEBUGFS
struct
thermal_debugfs
*
debugfs
;
#endif
struct
thermal_trip
trips
[]
__counted_by
(
num_trips
);
};
/**
* struct thermal_governor - structure that holds thermal governor information
* @name: name of the governor
* @bind_to_tz: callback called when binding to a thermal zone. If it
* returns 0, the governor is bound to the thermal zone,
* otherwise it fails.
* @unbind_from_tz: callback called when a governor is unbound from a
* thermal zone.
* @throttle: callback called for every trip point even if temperature is
* below the trip point temperature
* @update_tz: callback called when thermal zone internals have changed, e.g.
* thermal cooling instance was added/removed
* @governor_list: node in thermal_governor_list (in thermal_core.c)
*/
struct
thermal_governor
{
const
char
*
name
;
int
(
*
bind_to_tz
)(
struct
thermal_zone_device
*
tz
);
void
(
*
unbind_from_tz
)(
struct
thermal_zone_device
*
tz
);
int
(
*
throttle
)(
struct
thermal_zone_device
*
tz
,
const
struct
thermal_trip
*
trip
);
void
(
*
update_tz
)(
struct
thermal_zone_device
*
tz
,
enum
thermal_notify_event
reason
);
struct
list_head
governor_list
;
};
/* Structure to define Thermal Zone parameters */
struct
thermal_zone_params
{
const
char
*
governor_name
;
...
...
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