Skip to content
体验新版
项目
组织
正在加载...
登录
切换导航
打开侧边栏
openeuler
Kernel
提交
40aa4db6
K
Kernel
项目概览
openeuler
/
Kernel
1 年多 前同步成功
通知
8
Star
0
Fork
0
代码
文件
提交
分支
Tags
贡献者
分支图
Diff
Issue
0
列表
看板
标记
里程碑
合并请求
0
DevOps
流水线
流水线任务
计划
Wiki
0
Wiki
分析
仓库
DevOps
项目成员
Pages
K
Kernel
项目概览
项目概览
详情
发布
仓库
仓库
文件
提交
分支
标签
贡献者
分支图
比较
Issue
0
Issue
0
列表
看板
标记
里程碑
合并请求
0
合并请求
0
Pages
DevOps
DevOps
流水线
流水线任务
计划
分析
分析
仓库分析
DevOps
Wiki
0
Wiki
成员
成员
收起侧边栏
关闭侧边栏
动态
分支图
创建新Issue
流水线任务
提交
Issue看板
提交
40aa4db6
编写于
4月 25, 2019
作者:
R
Rafael J. Wysocki
浏览文件
操作
浏览文件
下载
差异文件
Merge cpuidle material depended on by the subsequent changes.
上级
3ccf3f0c
e9499968
变更
8
隐藏空白更改
内联
并排
Showing
8 changed file
with
197 addition
and
9 deletion
+197
-9
drivers/base/power/domain.c
drivers/base/power/domain.c
+74
-3
drivers/base/power/domain_governor.c
drivers/base/power/domain_governor.c
+66
-1
drivers/cpuidle/cpuidle-exynos.c
drivers/cpuidle/cpuidle-exynos.c
+1
-1
drivers/cpuidle/cpuidle.c
drivers/cpuidle/cpuidle.c
+17
-2
include/linux/cpuidle.h
include/linux/cpuidle.h
+1
-0
include/linux/pm_domain.h
include/linux/pm_domain.h
+20
-1
include/linux/tick.h
include/linux/tick.h
+6
-1
kernel/time/tick-sched.c
kernel/time/tick-sched.c
+12
-0
未找到文件。
drivers/base/power/domain.c
浏览文件 @
40aa4db6
...
...
@@ -22,6 +22,7 @@
#include <linux/sched.h>
#include <linux/suspend.h>
#include <linux/export.h>
#include <linux/cpu.h>
#include "power.h"
...
...
@@ -128,6 +129,7 @@ static const struct genpd_lock_ops genpd_spin_ops = {
#define genpd_is_irq_safe(genpd) (genpd->flags & GENPD_FLAG_IRQ_SAFE)
#define genpd_is_always_on(genpd) (genpd->flags & GENPD_FLAG_ALWAYS_ON)
#define genpd_is_active_wakeup(genpd) (genpd->flags & GENPD_FLAG_ACTIVE_WAKEUP)
#define genpd_is_cpu_domain(genpd) (genpd->flags & GENPD_FLAG_CPU_DOMAIN)
static
inline
bool
irq_safe_dev_in_no_sleep_domain
(
struct
device
*
dev
,
const
struct
generic_pm_domain
*
genpd
)
...
...
@@ -1452,6 +1454,56 @@ static void genpd_free_dev_data(struct device *dev,
dev_pm_put_subsys_data
(
dev
);
}
static
void
__genpd_update_cpumask
(
struct
generic_pm_domain
*
genpd
,
int
cpu
,
bool
set
,
unsigned
int
depth
)
{
struct
gpd_link
*
link
;
if
(
!
genpd_is_cpu_domain
(
genpd
))
return
;
list_for_each_entry
(
link
,
&
genpd
->
slave_links
,
slave_node
)
{
struct
generic_pm_domain
*
master
=
link
->
master
;
genpd_lock_nested
(
master
,
depth
+
1
);
__genpd_update_cpumask
(
master
,
cpu
,
set
,
depth
+
1
);
genpd_unlock
(
master
);
}
if
(
set
)
cpumask_set_cpu
(
cpu
,
genpd
->
cpus
);
else
cpumask_clear_cpu
(
cpu
,
genpd
->
cpus
);
}
static
void
genpd_update_cpumask
(
struct
generic_pm_domain
*
genpd
,
struct
device
*
dev
,
bool
set
)
{
int
cpu
;
if
(
!
genpd_is_cpu_domain
(
genpd
))
return
;
for_each_possible_cpu
(
cpu
)
{
if
(
get_cpu_device
(
cpu
)
==
dev
)
{
__genpd_update_cpumask
(
genpd
,
cpu
,
set
,
0
);
return
;
}
}
}
static
void
genpd_set_cpumask
(
struct
generic_pm_domain
*
genpd
,
struct
device
*
dev
)
{
genpd_update_cpumask
(
genpd
,
dev
,
true
);
}
static
void
genpd_clear_cpumask
(
struct
generic_pm_domain
*
genpd
,
struct
device
*
dev
)
{
genpd_update_cpumask
(
genpd
,
dev
,
false
);
}
static
int
genpd_add_device
(
struct
generic_pm_domain
*
genpd
,
struct
device
*
dev
,
struct
gpd_timing_data
*
td
)
{
...
...
@@ -1473,6 +1525,7 @@ static int genpd_add_device(struct generic_pm_domain *genpd, struct device *dev,
genpd_lock
(
genpd
);
genpd_set_cpumask
(
genpd
,
dev
);
dev_pm_domain_set
(
dev
,
&
genpd
->
domain
);
genpd
->
device_count
++
;
...
...
@@ -1530,6 +1583,7 @@ static int genpd_remove_device(struct generic_pm_domain *genpd,
genpd
->
device_count
--
;
genpd
->
max_off_time_changed
=
true
;
genpd_clear_cpumask
(
genpd
,
dev
);
dev_pm_domain_set
(
dev
,
NULL
);
list_del_init
(
&
pdd
->
list_node
);
...
...
@@ -1684,6 +1738,12 @@ int pm_genpd_remove_subdomain(struct generic_pm_domain *genpd,
}
EXPORT_SYMBOL_GPL
(
pm_genpd_remove_subdomain
);
static
void
genpd_free_default_power_state
(
struct
genpd_power_state
*
states
,
unsigned
int
state_count
)
{
kfree
(
states
);
}
static
int
genpd_set_default_power_state
(
struct
generic_pm_domain
*
genpd
)
{
struct
genpd_power_state
*
state
;
...
...
@@ -1694,7 +1754,7 @@ static int genpd_set_default_power_state(struct generic_pm_domain *genpd)
genpd
->
states
=
state
;
genpd
->
state_count
=
1
;
genpd
->
free
=
state
;
genpd
->
free
_states
=
genpd_free_default_power_
state
;
return
0
;
}
...
...
@@ -1760,11 +1820,18 @@ int pm_genpd_init(struct generic_pm_domain *genpd,
if
(
genpd_is_always_on
(
genpd
)
&&
!
genpd_status_on
(
genpd
))
return
-
EINVAL
;
if
(
genpd_is_cpu_domain
(
genpd
)
&&
!
zalloc_cpumask_var
(
&
genpd
->
cpus
,
GFP_KERNEL
))
return
-
ENOMEM
;
/* Use only one "off" state if there were no states declared */
if
(
genpd
->
state_count
==
0
)
{
ret
=
genpd_set_default_power_state
(
genpd
);
if
(
ret
)
if
(
ret
)
{
if
(
genpd_is_cpu_domain
(
genpd
))
free_cpumask_var
(
genpd
->
cpus
);
return
ret
;
}
}
else
if
(
!
gov
&&
genpd
->
state_count
>
1
)
{
pr_warn
(
"%s: no governor for states
\n
"
,
genpd
->
name
);
}
...
...
@@ -1810,7 +1877,11 @@ static int genpd_remove(struct generic_pm_domain *genpd)
list_del
(
&
genpd
->
gpd_list_node
);
genpd_unlock
(
genpd
);
cancel_work_sync
(
&
genpd
->
power_off_work
);
kfree
(
genpd
->
free
);
if
(
genpd_is_cpu_domain
(
genpd
))
free_cpumask_var
(
genpd
->
cpus
);
if
(
genpd
->
free_states
)
genpd
->
free_states
(
genpd
->
states
,
genpd
->
state_count
);
pr_debug
(
"%s: removed %s
\n
"
,
__func__
,
genpd
->
name
);
return
0
;
...
...
drivers/base/power/domain_governor.c
浏览文件 @
40aa4db6
...
...
@@ -10,6 +10,9 @@
#include <linux/pm_domain.h>
#include <linux/pm_qos.h>
#include <linux/hrtimer.h>
#include <linux/cpuidle.h>
#include <linux/cpumask.h>
#include <linux/ktime.h>
static
int
dev_update_qos_constraint
(
struct
device
*
dev
,
void
*
data
)
{
...
...
@@ -210,8 +213,10 @@ static bool default_power_down_ok(struct dev_pm_domain *pd)
struct
generic_pm_domain
*
genpd
=
pd_to_genpd
(
pd
);
struct
gpd_link
*
link
;
if
(
!
genpd
->
max_off_time_changed
)
if
(
!
genpd
->
max_off_time_changed
)
{
genpd
->
state_idx
=
genpd
->
cached_power_down_state_idx
;
return
genpd
->
cached_power_down_ok
;
}
/*
* We have to invalidate the cached results for the masters, so
...
...
@@ -236,6 +241,7 @@ static bool default_power_down_ok(struct dev_pm_domain *pd)
genpd
->
state_idx
--
;
}
genpd
->
cached_power_down_state_idx
=
genpd
->
state_idx
;
return
genpd
->
cached_power_down_ok
;
}
...
...
@@ -244,6 +250,65 @@ static bool always_on_power_down_ok(struct dev_pm_domain *domain)
return
false
;
}
#ifdef CONFIG_CPU_IDLE
static
bool
cpu_power_down_ok
(
struct
dev_pm_domain
*
pd
)
{
struct
generic_pm_domain
*
genpd
=
pd_to_genpd
(
pd
);
struct
cpuidle_device
*
dev
;
ktime_t
domain_wakeup
,
next_hrtimer
;
s64
idle_duration_ns
;
int
cpu
,
i
;
/* Validate dev PM QoS constraints. */
if
(
!
default_power_down_ok
(
pd
))
return
false
;
if
(
!
(
genpd
->
flags
&
GENPD_FLAG_CPU_DOMAIN
))
return
true
;
/*
* Find the next wakeup for any of the online CPUs within the PM domain
* and its subdomains. Note, we only need the genpd->cpus, as it already
* contains a mask of all CPUs from subdomains.
*/
domain_wakeup
=
ktime_set
(
KTIME_SEC_MAX
,
0
);
for_each_cpu_and
(
cpu
,
genpd
->
cpus
,
cpu_online_mask
)
{
dev
=
per_cpu
(
cpuidle_devices
,
cpu
);
if
(
dev
)
{
next_hrtimer
=
READ_ONCE
(
dev
->
next_hrtimer
);
if
(
ktime_before
(
next_hrtimer
,
domain_wakeup
))
domain_wakeup
=
next_hrtimer
;
}
}
/* The minimum idle duration is from now - until the next wakeup. */
idle_duration_ns
=
ktime_to_ns
(
ktime_sub
(
domain_wakeup
,
ktime_get
()));
if
(
idle_duration_ns
<=
0
)
return
false
;
/*
* Find the deepest idle state that has its residency value satisfied
* and by also taking into account the power off latency for the state.
* Start at the state picked by the dev PM QoS constraint validation.
*/
i
=
genpd
->
state_idx
;
do
{
if
(
idle_duration_ns
>=
(
genpd
->
states
[
i
].
residency_ns
+
genpd
->
states
[
i
].
power_off_latency_ns
))
{
genpd
->
state_idx
=
i
;
return
true
;
}
}
while
(
--
i
>=
0
);
return
false
;
}
struct
dev_power_governor
pm_domain_cpu_gov
=
{
.
suspend_ok
=
default_suspend_ok
,
.
power_down_ok
=
cpu_power_down_ok
,
};
#endif
struct
dev_power_governor
simple_qos_governor
=
{
.
suspend_ok
=
default_suspend_ok
,
.
power_down_ok
=
default_power_down_ok
,
...
...
drivers/cpuidle/cpuidle-exynos.c
浏览文件 @
40aa4db6
...
...
@@ -84,7 +84,7 @@ static struct cpuidle_driver exynos_idle_driver = {
[
1
]
=
{
.
enter
=
exynos_enter_lowpower
,
.
exit_latency
=
300
,
.
target_residency
=
10000
0
,
.
target_residency
=
10000
,
.
name
=
"C1"
,
.
desc
=
"ARM power down"
,
},
...
...
drivers/cpuidle/cpuidle.c
浏览文件 @
40aa4db6
...
...
@@ -328,9 +328,23 @@ int cpuidle_select(struct cpuidle_driver *drv, struct cpuidle_device *dev,
int
cpuidle_enter
(
struct
cpuidle_driver
*
drv
,
struct
cpuidle_device
*
dev
,
int
index
)
{
int
ret
=
0
;
/*
* Store the next hrtimer, which becomes either next tick or the next
* timer event, whatever expires first. Additionally, to make this data
* useful for consumers outside cpuidle, we rely on that the governor's
* ->select() callback have decided, whether to stop the tick or not.
*/
WRITE_ONCE
(
dev
->
next_hrtimer
,
tick_nohz_get_next_hrtimer
());
if
(
cpuidle_state_is_coupled
(
drv
,
index
))
return
cpuidle_enter_state_coupled
(
dev
,
drv
,
index
);
return
cpuidle_enter_state
(
dev
,
drv
,
index
);
ret
=
cpuidle_enter_state_coupled
(
dev
,
drv
,
index
);
else
ret
=
cpuidle_enter_state
(
dev
,
drv
,
index
);
WRITE_ONCE
(
dev
->
next_hrtimer
,
0
);
return
ret
;
}
/**
...
...
@@ -511,6 +525,7 @@ static void __cpuidle_device_init(struct cpuidle_device *dev)
{
memset
(
dev
->
states_usage
,
0
,
sizeof
(
dev
->
states_usage
));
dev
->
last_residency
=
0
;
dev
->
next_hrtimer
=
0
;
}
/**
...
...
include/linux/cpuidle.h
浏览文件 @
40aa4db6
...
...
@@ -83,6 +83,7 @@ struct cpuidle_device {
unsigned
int
use_deepest_state
:
1
;
unsigned
int
poll_time_limit
:
1
;
unsigned
int
cpu
;
ktime_t
next_hrtimer
;
int
last_residency
;
struct
cpuidle_state_usage
states_usage
[
CPUIDLE_STATE_MAX
];
...
...
include/linux/pm_domain.h
浏览文件 @
40aa4db6
...
...
@@ -16,6 +16,7 @@
#include <linux/of.h>
#include <linux/notifier.h>
#include <linux/spinlock.h>
#include <linux/cpumask.h>
/*
* Flags to control the behaviour of a genpd.
...
...
@@ -42,11 +43,22 @@
* GENPD_FLAG_ACTIVE_WAKEUP: Instructs genpd to keep the PM domain powered
* on, in case any of its attached devices is used
* in the wakeup path to serve system wakeups.
*
* GENPD_FLAG_CPU_DOMAIN: Instructs genpd that it should expect to get
* devices attached, which may belong to CPUs or
* possibly have subdomains with CPUs attached.
* This flag enables the genpd backend driver to
* deploy idle power management support for CPUs
* and groups of CPUs. Note that, the backend
* driver must then comply with the so called,
* last-man-standing algorithm, for the CPUs in the
* PM domain.
*/
#define GENPD_FLAG_PM_CLK (1U << 0)
#define GENPD_FLAG_IRQ_SAFE (1U << 1)
#define GENPD_FLAG_ALWAYS_ON (1U << 2)
#define GENPD_FLAG_ACTIVE_WAKEUP (1U << 3)
#define GENPD_FLAG_CPU_DOMAIN (1U << 4)
enum
gpd_status
{
GPD_STATE_ACTIVE
=
0
,
/* PM domain is active */
...
...
@@ -69,6 +81,7 @@ struct genpd_power_state {
s64
residency_ns
;
struct
fwnode_handle
*
fwnode
;
ktime_t
idle_time
;
void
*
data
;
};
struct
genpd_lock_ops
;
...
...
@@ -93,6 +106,7 @@ struct generic_pm_domain {
unsigned
int
suspended_count
;
/* System suspend device counter */
unsigned
int
prepared_count
;
/* Suspend counter of prepared devices */
unsigned
int
performance_state
;
/* Aggregated max performance state */
cpumask_var_t
cpus
;
/* A cpumask of the attached CPUs */
int
(
*
power_off
)(
struct
generic_pm_domain
*
domain
);
int
(
*
power_on
)(
struct
generic_pm_domain
*
domain
);
struct
opp_table
*
opp_table
;
/* OPP table of the genpd */
...
...
@@ -104,15 +118,17 @@ struct generic_pm_domain {
s64
max_off_time_ns
;
/* Maximum allowed "suspended" time. */
bool
max_off_time_changed
;
bool
cached_power_down_ok
;
bool
cached_power_down_state_idx
;
int
(
*
attach_dev
)(
struct
generic_pm_domain
*
domain
,
struct
device
*
dev
);
void
(
*
detach_dev
)(
struct
generic_pm_domain
*
domain
,
struct
device
*
dev
);
unsigned
int
flags
;
/* Bit field of configs for genpd */
struct
genpd_power_state
*
states
;
void
(
*
free_states
)(
struct
genpd_power_state
*
states
,
unsigned
int
state_count
);
unsigned
int
state_count
;
/* number of states */
unsigned
int
state_idx
;
/* state that genpd will go to when off */
void
*
free
;
/* Free the state that was allocated for default */
ktime_t
on_time
;
ktime_t
accounting_time
;
const
struct
genpd_lock_ops
*
lock_ops
;
...
...
@@ -187,6 +203,9 @@ int dev_pm_genpd_set_performance_state(struct device *dev, unsigned int state);
extern
struct
dev_power_governor
simple_qos_governor
;
extern
struct
dev_power_governor
pm_domain_always_on_gov
;
#ifdef CONFIG_CPU_IDLE
extern
struct
dev_power_governor
pm_domain_cpu_gov
;
#endif
#else
static
inline
struct
generic_pm_domain_data
*
dev_gpd_data
(
struct
device
*
dev
)
...
...
include/linux/tick.h
浏览文件 @
40aa4db6
...
...
@@ -122,6 +122,7 @@ extern void tick_nohz_idle_enter(void);
extern
void
tick_nohz_idle_exit
(
void
);
extern
void
tick_nohz_irq_exit
(
void
);
extern
bool
tick_nohz_idle_got_tick
(
void
);
extern
ktime_t
tick_nohz_get_next_hrtimer
(
void
);
extern
ktime_t
tick_nohz_get_sleep_length
(
ktime_t
*
delta_next
);
extern
unsigned
long
tick_nohz_get_idle_calls
(
void
);
extern
unsigned
long
tick_nohz_get_idle_calls_cpu
(
int
cpu
);
...
...
@@ -145,7 +146,11 @@ static inline void tick_nohz_idle_restart_tick(void) { }
static
inline
void
tick_nohz_idle_enter
(
void
)
{
}
static
inline
void
tick_nohz_idle_exit
(
void
)
{
}
static
inline
bool
tick_nohz_idle_got_tick
(
void
)
{
return
false
;
}
static
inline
ktime_t
tick_nohz_get_next_hrtimer
(
void
)
{
/* Next wake up is the tick period, assume it starts now */
return
ktime_add
(
ktime_get
(),
TICK_NSEC
);
}
static
inline
ktime_t
tick_nohz_get_sleep_length
(
ktime_t
*
delta_next
)
{
*
delta_next
=
TICK_NSEC
;
...
...
kernel/time/tick-sched.c
浏览文件 @
40aa4db6
...
...
@@ -1022,6 +1022,18 @@ bool tick_nohz_idle_got_tick(void)
return
false
;
}
/**
* tick_nohz_get_next_hrtimer - return the next expiration time for the hrtimer
* or the tick, whatever that expires first. Note that, if the tick has been
* stopped, it returns the next hrtimer.
*
* Called from power state control code with interrupts disabled
*/
ktime_t
tick_nohz_get_next_hrtimer
(
void
)
{
return
__this_cpu_read
(
tick_cpu_device
.
evtdev
)
->
next_event
;
}
/**
* tick_nohz_get_sleep_length - return the expected length of the current sleep
* @delta_next: duration until the next event if the tick cannot be stopped
...
...
编辑
预览
Markdown
is supported
0%
请重试
或
添加新附件
.
添加附件
取消
You are about to add
0
people
to the discussion. Proceed with caution.
先完成此消息的编辑!
取消
想要评论请
注册
或
登录