Skip to content
体验新版
项目
组织
正在加载...
登录
切换导航
打开侧边栏
OpenHarmony
kernel_linux
提交
a5acbfbd
K
kernel_linux
项目概览
OpenHarmony
/
kernel_linux
上一次同步 4 年多
通知
15
Star
8
Fork
2
代码
文件
提交
分支
Tags
贡献者
分支图
Diff
Issue
0
列表
看板
标记
里程碑
合并请求
0
DevOps
流水线
流水线任务
计划
Wiki
0
Wiki
分析
仓库
DevOps
项目成员
Pages
K
kernel_linux
项目概览
项目概览
详情
发布
仓库
仓库
文件
提交
分支
标签
贡献者
分支图
比较
Issue
0
Issue
0
列表
看板
标记
里程碑
合并请求
0
合并请求
0
Pages
DevOps
DevOps
流水线
流水线任务
计划
分析
分析
仓库分析
DevOps
Wiki
0
Wiki
成员
成员
收起侧边栏
关闭侧边栏
动态
分支图
创建新Issue
流水线任务
提交
Issue看板
提交
a5acbfbd
编写于
3月 10, 2016
作者:
R
Rafael J. Wysocki
浏览文件
操作
浏览文件
下载
差异文件
Merge branch 'pm-cpufreq-governor' into pm-cpufreq
上级
edd4a893
adaf9fcd
变更
17
隐藏空白更改
内联
并排
Showing
17 changed file
with
1031 addition
and
1148 deletion
+1031
-1148
drivers/cpufreq/Kconfig
drivers/cpufreq/Kconfig
+1
-0
drivers/cpufreq/amd_freq_sensitivity.c
drivers/cpufreq/amd_freq_sensitivity.c
+4
-4
drivers/cpufreq/cpufreq.c
drivers/cpufreq/cpufreq.c
+67
-98
drivers/cpufreq/cpufreq_conservative.c
drivers/cpufreq/cpufreq_conservative.c
+124
-152
drivers/cpufreq/cpufreq_governor.c
drivers/cpufreq/cpufreq_governor.c
+403
-363
drivers/cpufreq/cpufreq_governor.h
drivers/cpufreq/cpufreq_governor.h
+84
-177
drivers/cpufreq/cpufreq_ondemand.c
drivers/cpufreq/cpufreq_ondemand.c
+151
-284
drivers/cpufreq/cpufreq_ondemand.h
drivers/cpufreq/cpufreq_ondemand.h
+30
-0
drivers/cpufreq/intel_pstate.c
drivers/cpufreq/intel_pstate.c
+39
-64
include/linux/cpufreq.h
include/linux/cpufreq.h
+0
-5
include/linux/sched.h
include/linux/sched.h
+9
-0
kernel/sched/Makefile
kernel/sched/Makefile
+1
-0
kernel/sched/cpufreq.c
kernel/sched/cpufreq.c
+37
-0
kernel/sched/deadline.c
kernel/sched/deadline.c
+4
-0
kernel/sched/fair.c
kernel/sched/fair.c
+25
-1
kernel/sched/rt.c
kernel/sched/rt.c
+4
-0
kernel/sched/sched.h
kernel/sched/sched.h
+48
-0
未找到文件。
drivers/cpufreq/Kconfig
浏览文件 @
a5acbfbd
...
@@ -19,6 +19,7 @@ config CPU_FREQ
...
@@ -19,6 +19,7 @@ config CPU_FREQ
if CPU_FREQ
if CPU_FREQ
config CPU_FREQ_GOV_COMMON
config CPU_FREQ_GOV_COMMON
select IRQ_WORK
bool
bool
config CPU_FREQ_BOOST_SW
config CPU_FREQ_BOOST_SW
...
...
drivers/cpufreq/amd_freq_sensitivity.c
浏览文件 @
a5acbfbd
...
@@ -21,7 +21,7 @@
...
@@ -21,7 +21,7 @@
#include <asm/msr.h>
#include <asm/msr.h>
#include <asm/cpufeature.h>
#include <asm/cpufeature.h>
#include "cpufreq_
governor
.h"
#include "cpufreq_
ondemand
.h"
#define MSR_AMD64_FREQ_SENSITIVITY_ACTUAL 0xc0010080
#define MSR_AMD64_FREQ_SENSITIVITY_ACTUAL 0xc0010080
#define MSR_AMD64_FREQ_SENSITIVITY_REFERENCE 0xc0010081
#define MSR_AMD64_FREQ_SENSITIVITY_REFERENCE 0xc0010081
...
@@ -45,10 +45,10 @@ static unsigned int amd_powersave_bias_target(struct cpufreq_policy *policy,
...
@@ -45,10 +45,10 @@ static unsigned int amd_powersave_bias_target(struct cpufreq_policy *policy,
long
d_actual
,
d_reference
;
long
d_actual
,
d_reference
;
struct
msr
actual
,
reference
;
struct
msr
actual
,
reference
;
struct
cpu_data_t
*
data
=
&
per_cpu
(
cpu_data
,
policy
->
cpu
);
struct
cpu_data_t
*
data
=
&
per_cpu
(
cpu_data
,
policy
->
cpu
);
struct
dbs_data
*
od_data
=
policy
->
governor_data
;
struct
policy_dbs_info
*
policy_dbs
=
policy
->
governor_data
;
struct
dbs_data
*
od_data
=
policy_dbs
->
dbs_data
;
struct
od_dbs_tuners
*
od_tuners
=
od_data
->
tuners
;
struct
od_dbs_tuners
*
od_tuners
=
od_data
->
tuners
;
struct
od_cpu_dbs_info_s
*
od_info
=
struct
od_policy_dbs_info
*
od_info
=
to_dbs_info
(
policy_dbs
);
od_data
->
cdata
->
get_cpu_dbs_info_s
(
policy
->
cpu
);
if
(
!
od_info
->
freq_table
)
if
(
!
od_info
->
freq_table
)
return
freq_next
;
return
freq_next
;
...
...
drivers/cpufreq/cpufreq.c
浏览文件 @
a5acbfbd
...
@@ -64,7 +64,6 @@ static LIST_HEAD(cpufreq_governor_list);
...
@@ -64,7 +64,6 @@ static LIST_HEAD(cpufreq_governor_list);
static
struct
cpufreq_driver
*
cpufreq_driver
;
static
struct
cpufreq_driver
*
cpufreq_driver
;
static
DEFINE_PER_CPU
(
struct
cpufreq_policy
*
,
cpufreq_cpu_data
);
static
DEFINE_PER_CPU
(
struct
cpufreq_policy
*
,
cpufreq_cpu_data
);
static
DEFINE_RWLOCK
(
cpufreq_driver_lock
);
static
DEFINE_RWLOCK
(
cpufreq_driver_lock
);
DEFINE_MUTEX
(
cpufreq_governor_lock
);
/* Flag to suspend/resume CPUFreq governors */
/* Flag to suspend/resume CPUFreq governors */
static
bool
cpufreq_suspended
;
static
bool
cpufreq_suspended
;
...
@@ -75,10 +74,8 @@ static inline bool has_target(void)
...
@@ -75,10 +74,8 @@ static inline bool has_target(void)
}
}
/* internal prototypes */
/* internal prototypes */
static
int
__cpufreq_governor
(
struct
cpufreq_policy
*
policy
,
static
int
cpufreq_governor
(
struct
cpufreq_policy
*
policy
,
unsigned
int
event
);
unsigned
int
event
);
static
unsigned
int
__cpufreq_get
(
struct
cpufreq_policy
*
policy
);
static
unsigned
int
__cpufreq_get
(
struct
cpufreq_policy
*
policy
);
static
void
handle_update
(
struct
work_struct
*
work
);
/**
/**
* Two notifier lists: the "policy" list is involved in the
* Two notifier lists: the "policy" list is involved in the
...
@@ -955,30 +952,38 @@ static int cpufreq_add_policy_cpu(struct cpufreq_policy *policy, unsigned int cp
...
@@ -955,30 +952,38 @@ static int cpufreq_add_policy_cpu(struct cpufreq_policy *policy, unsigned int cp
if
(
cpumask_test_cpu
(
cpu
,
policy
->
cpus
))
if
(
cpumask_test_cpu
(
cpu
,
policy
->
cpus
))
return
0
;
return
0
;
down_write
(
&
policy
->
rwsem
);
if
(
has_target
())
{
if
(
has_target
())
{
ret
=
__
cpufreq_governor
(
policy
,
CPUFREQ_GOV_STOP
);
ret
=
cpufreq_governor
(
policy
,
CPUFREQ_GOV_STOP
);
if
(
ret
)
{
if
(
ret
)
{
pr_err
(
"%s: Failed to stop governor
\n
"
,
__func__
);
pr_err
(
"%s: Failed to stop governor
\n
"
,
__func__
);
return
ret
;
goto
unlock
;
}
}
}
}
down_write
(
&
policy
->
rwsem
);
cpumask_set_cpu
(
cpu
,
policy
->
cpus
);
cpumask_set_cpu
(
cpu
,
policy
->
cpus
);
up_write
(
&
policy
->
rwsem
);
if
(
has_target
())
{
if
(
has_target
())
{
ret
=
__
cpufreq_governor
(
policy
,
CPUFREQ_GOV_START
);
ret
=
cpufreq_governor
(
policy
,
CPUFREQ_GOV_START
);
if
(
!
ret
)
if
(
!
ret
)
ret
=
__
cpufreq_governor
(
policy
,
CPUFREQ_GOV_LIMITS
);
ret
=
cpufreq_governor
(
policy
,
CPUFREQ_GOV_LIMITS
);
if
(
ret
)
{
if
(
ret
)
pr_err
(
"%s: Failed to start governor
\n
"
,
__func__
);
pr_err
(
"%s: Failed to start governor
\n
"
,
__func__
);
return
ret
;
}
}
}
return
0
;
unlock:
up_write
(
&
policy
->
rwsem
);
return
ret
;
}
static
void
handle_update
(
struct
work_struct
*
work
)
{
struct
cpufreq_policy
*
policy
=
container_of
(
work
,
struct
cpufreq_policy
,
update
);
unsigned
int
cpu
=
policy
->
cpu
;
pr_debug
(
"handle_update for cpu %u called
\n
"
,
cpu
);
cpufreq_update_policy
(
cpu
);
}
}
static
struct
cpufreq_policy
*
cpufreq_policy_alloc
(
unsigned
int
cpu
)
static
struct
cpufreq_policy
*
cpufreq_policy_alloc
(
unsigned
int
cpu
)
...
@@ -1267,9 +1272,10 @@ static int cpufreq_add_dev(struct device *dev, struct subsys_interface *sif)
...
@@ -1267,9 +1272,10 @@ static int cpufreq_add_dev(struct device *dev, struct subsys_interface *sif)
return
ret
;
return
ret
;
}
}
static
void
cpufreq_offline
_prepare
(
unsigned
int
cpu
)
static
void
cpufreq_offline
(
unsigned
int
cpu
)
{
{
struct
cpufreq_policy
*
policy
;
struct
cpufreq_policy
*
policy
;
int
ret
;
pr_debug
(
"%s: unregistering CPU %u
\n
"
,
__func__
,
cpu
);
pr_debug
(
"%s: unregistering CPU %u
\n
"
,
__func__
,
cpu
);
...
@@ -1279,13 +1285,13 @@ static void cpufreq_offline_prepare(unsigned int cpu)
...
@@ -1279,13 +1285,13 @@ static void cpufreq_offline_prepare(unsigned int cpu)
return
;
return
;
}
}
down_write
(
&
policy
->
rwsem
);
if
(
has_target
())
{
if
(
has_target
())
{
int
ret
=
__
cpufreq_governor
(
policy
,
CPUFREQ_GOV_STOP
);
ret
=
cpufreq_governor
(
policy
,
CPUFREQ_GOV_STOP
);
if
(
ret
)
if
(
ret
)
pr_err
(
"%s: Failed to stop governor
\n
"
,
__func__
);
pr_err
(
"%s: Failed to stop governor
\n
"
,
__func__
);
}
}
down_write
(
&
policy
->
rwsem
);
cpumask_clear_cpu
(
cpu
,
policy
->
cpus
);
cpumask_clear_cpu
(
cpu
,
policy
->
cpus
);
if
(
policy_is_inactive
(
policy
))
{
if
(
policy_is_inactive
(
policy
))
{
...
@@ -1298,39 +1304,27 @@ static void cpufreq_offline_prepare(unsigned int cpu)
...
@@ -1298,39 +1304,27 @@ static void cpufreq_offline_prepare(unsigned int cpu)
/* Nominate new CPU */
/* Nominate new CPU */
policy
->
cpu
=
cpumask_any
(
policy
->
cpus
);
policy
->
cpu
=
cpumask_any
(
policy
->
cpus
);
}
}
up_write
(
&
policy
->
rwsem
);
/* Start governor again for active policy */
/* Start governor again for active policy */
if
(
!
policy_is_inactive
(
policy
))
{
if
(
!
policy_is_inactive
(
policy
))
{
if
(
has_target
())
{
if
(
has_target
())
{
int
ret
=
__
cpufreq_governor
(
policy
,
CPUFREQ_GOV_START
);
ret
=
cpufreq_governor
(
policy
,
CPUFREQ_GOV_START
);
if
(
!
ret
)
if
(
!
ret
)
ret
=
__
cpufreq_governor
(
policy
,
CPUFREQ_GOV_LIMITS
);
ret
=
cpufreq_governor
(
policy
,
CPUFREQ_GOV_LIMITS
);
if
(
ret
)
if
(
ret
)
pr_err
(
"%s: Failed to start governor
\n
"
,
__func__
);
pr_err
(
"%s: Failed to start governor
\n
"
,
__func__
);
}
}
}
else
if
(
cpufreq_driver
->
stop_cpu
)
{
cpufreq_driver
->
stop_cpu
(
policy
);
}
}
static
void
cpufreq_offline_finish
(
unsigned
int
cpu
)
goto
unlock
;
{
struct
cpufreq_policy
*
policy
=
per_cpu
(
cpufreq_cpu_data
,
cpu
);
if
(
!
policy
)
{
pr_debug
(
"%s: No cpu_data found
\n
"
,
__func__
);
return
;
}
}
/* Only proceed for inactive policies */
if
(
cpufreq_driver
->
stop_cpu
)
if
(
!
policy_is_inactive
(
policy
))
cpufreq_driver
->
stop_cpu
(
policy
);
return
;
/* If cpu is last user of policy, free policy */
/* If cpu is last user of policy, free policy */
if
(
has_target
())
{
if
(
has_target
())
{
int
ret
=
__
cpufreq_governor
(
policy
,
CPUFREQ_GOV_POLICY_EXIT
);
ret
=
cpufreq_governor
(
policy
,
CPUFREQ_GOV_POLICY_EXIT
);
if
(
ret
)
if
(
ret
)
pr_err
(
"%s: Failed to exit governor
\n
"
,
__func__
);
pr_err
(
"%s: Failed to exit governor
\n
"
,
__func__
);
}
}
...
@@ -1344,6 +1338,9 @@ static void cpufreq_offline_finish(unsigned int cpu)
...
@@ -1344,6 +1338,9 @@ static void cpufreq_offline_finish(unsigned int cpu)
cpufreq_driver
->
exit
(
policy
);
cpufreq_driver
->
exit
(
policy
);
policy
->
freq_table
=
NULL
;
policy
->
freq_table
=
NULL
;
}
}
unlock:
up_write
(
&
policy
->
rwsem
);
}
}
/**
/**
...
@@ -1359,10 +1356,8 @@ static void cpufreq_remove_dev(struct device *dev, struct subsys_interface *sif)
...
@@ -1359,10 +1356,8 @@ static void cpufreq_remove_dev(struct device *dev, struct subsys_interface *sif)
if
(
!
policy
)
if
(
!
policy
)
return
;
return
;
if
(
cpu_online
(
cpu
))
{
if
(
cpu_online
(
cpu
))
cpufreq_offline_prepare
(
cpu
);
cpufreq_offline
(
cpu
);
cpufreq_offline_finish
(
cpu
);
}
cpumask_clear_cpu
(
cpu
,
policy
->
real_cpus
);
cpumask_clear_cpu
(
cpu
,
policy
->
real_cpus
);
remove_cpu_dev_symlink
(
policy
,
cpu
);
remove_cpu_dev_symlink
(
policy
,
cpu
);
...
@@ -1371,15 +1366,6 @@ static void cpufreq_remove_dev(struct device *dev, struct subsys_interface *sif)
...
@@ -1371,15 +1366,6 @@ static void cpufreq_remove_dev(struct device *dev, struct subsys_interface *sif)
cpufreq_policy_free
(
policy
,
true
);
cpufreq_policy_free
(
policy
,
true
);
}
}
static
void
handle_update
(
struct
work_struct
*
work
)
{
struct
cpufreq_policy
*
policy
=
container_of
(
work
,
struct
cpufreq_policy
,
update
);
unsigned
int
cpu
=
policy
->
cpu
;
pr_debug
(
"handle_update for cpu %u called
\n
"
,
cpu
);
cpufreq_update_policy
(
cpu
);
}
/**
/**
* cpufreq_out_of_sync - If actual and saved CPU frequency differs, we're
* cpufreq_out_of_sync - If actual and saved CPU frequency differs, we're
* in deep trouble.
* in deep trouble.
...
@@ -1542,6 +1528,7 @@ EXPORT_SYMBOL(cpufreq_generic_suspend);
...
@@ -1542,6 +1528,7 @@ EXPORT_SYMBOL(cpufreq_generic_suspend);
void
cpufreq_suspend
(
void
)
void
cpufreq_suspend
(
void
)
{
{
struct
cpufreq_policy
*
policy
;
struct
cpufreq_policy
*
policy
;
int
ret
;
if
(
!
cpufreq_driver
)
if
(
!
cpufreq_driver
)
return
;
return
;
...
@@ -1552,7 +1539,11 @@ void cpufreq_suspend(void)
...
@@ -1552,7 +1539,11 @@ void cpufreq_suspend(void)
pr_debug
(
"%s: Suspending Governors
\n
"
,
__func__
);
pr_debug
(
"%s: Suspending Governors
\n
"
,
__func__
);
for_each_active_policy
(
policy
)
{
for_each_active_policy
(
policy
)
{
if
(
__cpufreq_governor
(
policy
,
CPUFREQ_GOV_STOP
))
down_write
(
&
policy
->
rwsem
);
ret
=
cpufreq_governor
(
policy
,
CPUFREQ_GOV_STOP
);
up_write
(
&
policy
->
rwsem
);
if
(
ret
)
pr_err
(
"%s: Failed to stop governor for policy: %p
\n
"
,
pr_err
(
"%s: Failed to stop governor for policy: %p
\n
"
,
__func__
,
policy
);
__func__
,
policy
);
else
if
(
cpufreq_driver
->
suspend
else
if
(
cpufreq_driver
->
suspend
...
@@ -1574,6 +1565,7 @@ void cpufreq_suspend(void)
...
@@ -1574,6 +1565,7 @@ void cpufreq_suspend(void)
void
cpufreq_resume
(
void
)
void
cpufreq_resume
(
void
)
{
{
struct
cpufreq_policy
*
policy
;
struct
cpufreq_policy
*
policy
;
int
ret
;
if
(
!
cpufreq_driver
)
if
(
!
cpufreq_driver
)
return
;
return
;
...
@@ -1586,13 +1578,20 @@ void cpufreq_resume(void)
...
@@ -1586,13 +1578,20 @@ void cpufreq_resume(void)
pr_debug
(
"%s: Resuming Governors
\n
"
,
__func__
);
pr_debug
(
"%s: Resuming Governors
\n
"
,
__func__
);
for_each_active_policy
(
policy
)
{
for_each_active_policy
(
policy
)
{
if
(
cpufreq_driver
->
resume
&&
cpufreq_driver
->
resume
(
policy
))
if
(
cpufreq_driver
->
resume
&&
cpufreq_driver
->
resume
(
policy
))
{
pr_err
(
"%s: Failed to resume driver: %p
\n
"
,
__func__
,
pr_err
(
"%s: Failed to resume driver: %p
\n
"
,
__func__
,
policy
);
policy
);
else
if
(
__cpufreq_governor
(
policy
,
CPUFREQ_GOV_START
)
}
else
{
||
__cpufreq_governor
(
policy
,
CPUFREQ_GOV_LIMITS
))
down_write
(
&
policy
->
rwsem
);
pr_err
(
"%s: Failed to start governor for policy: %p
\n
"
,
ret
=
cpufreq_governor
(
policy
,
CPUFREQ_GOV_START
);
__func__
,
policy
);
if
(
!
ret
)
cpufreq_governor
(
policy
,
CPUFREQ_GOV_LIMITS
);
up_write
(
&
policy
->
rwsem
);
if
(
ret
)
pr_err
(
"%s: Failed to start governor for policy: %p
\n
"
,
__func__
,
policy
);
}
}
}
/*
/*
...
@@ -1878,8 +1877,7 @@ __weak struct cpufreq_governor *cpufreq_fallback_governor(void)
...
@@ -1878,8 +1877,7 @@ __weak struct cpufreq_governor *cpufreq_fallback_governor(void)
return
NULL
;
return
NULL
;
}
}
static
int
__cpufreq_governor
(
struct
cpufreq_policy
*
policy
,
static
int
cpufreq_governor
(
struct
cpufreq_policy
*
policy
,
unsigned
int
event
)
unsigned
int
event
)
{
{
int
ret
;
int
ret
;
...
@@ -1913,21 +1911,6 @@ static int __cpufreq_governor(struct cpufreq_policy *policy,
...
@@ -1913,21 +1911,6 @@ static int __cpufreq_governor(struct cpufreq_policy *policy,
pr_debug
(
"%s: for CPU %u, event %u
\n
"
,
__func__
,
policy
->
cpu
,
event
);
pr_debug
(
"%s: for CPU %u, event %u
\n
"
,
__func__
,
policy
->
cpu
,
event
);
mutex_lock
(
&
cpufreq_governor_lock
);
if
((
policy
->
governor_enabled
&&
event
==
CPUFREQ_GOV_START
)
||
(
!
policy
->
governor_enabled
&&
(
event
==
CPUFREQ_GOV_LIMITS
||
event
==
CPUFREQ_GOV_STOP
)))
{
mutex_unlock
(
&
cpufreq_governor_lock
);
return
-
EBUSY
;
}
if
(
event
==
CPUFREQ_GOV_STOP
)
policy
->
governor_enabled
=
false
;
else
if
(
event
==
CPUFREQ_GOV_START
)
policy
->
governor_enabled
=
true
;
mutex_unlock
(
&
cpufreq_governor_lock
);
ret
=
policy
->
governor
->
governor
(
policy
,
event
);
ret
=
policy
->
governor
->
governor
(
policy
,
event
);
if
(
!
ret
)
{
if
(
!
ret
)
{
...
@@ -1935,14 +1918,6 @@ static int __cpufreq_governor(struct cpufreq_policy *policy,
...
@@ -1935,14 +1918,6 @@ static int __cpufreq_governor(struct cpufreq_policy *policy,
policy
->
governor
->
initialized
++
;
policy
->
governor
->
initialized
++
;
else
if
(
event
==
CPUFREQ_GOV_POLICY_EXIT
)
else
if
(
event
==
CPUFREQ_GOV_POLICY_EXIT
)
policy
->
governor
->
initialized
--
;
policy
->
governor
->
initialized
--
;
}
else
{
/* Restore original values */
mutex_lock
(
&
cpufreq_governor_lock
);
if
(
event
==
CPUFREQ_GOV_STOP
)
policy
->
governor_enabled
=
true
;
else
if
(
event
==
CPUFREQ_GOV_START
)
policy
->
governor_enabled
=
false
;
mutex_unlock
(
&
cpufreq_governor_lock
);
}
}
if
(((
event
==
CPUFREQ_GOV_POLICY_INIT
)
&&
ret
)
||
if
(((
event
==
CPUFREQ_GOV_POLICY_INIT
)
&&
ret
)
||
...
@@ -2097,7 +2072,7 @@ static int cpufreq_set_policy(struct cpufreq_policy *policy,
...
@@ -2097,7 +2072,7 @@ static int cpufreq_set_policy(struct cpufreq_policy *policy,
old_gov
=
policy
->
governor
;
old_gov
=
policy
->
governor
;
/* end old governor */
/* end old governor */
if
(
old_gov
)
{
if
(
old_gov
)
{
ret
=
__
cpufreq_governor
(
policy
,
CPUFREQ_GOV_STOP
);
ret
=
cpufreq_governor
(
policy
,
CPUFREQ_GOV_STOP
);
if
(
ret
)
{
if
(
ret
)
{
/* This can happen due to race with other operations */
/* This can happen due to race with other operations */
pr_debug
(
"%s: Failed to Stop Governor: %s (%d)
\n
"
,
pr_debug
(
"%s: Failed to Stop Governor: %s (%d)
\n
"
,
...
@@ -2105,10 +2080,7 @@ static int cpufreq_set_policy(struct cpufreq_policy *policy,
...
@@ -2105,10 +2080,7 @@ static int cpufreq_set_policy(struct cpufreq_policy *policy,
return
ret
;
return
ret
;
}
}
up_write
(
&
policy
->
rwsem
);
ret
=
cpufreq_governor
(
policy
,
CPUFREQ_GOV_POLICY_EXIT
);
ret
=
__cpufreq_governor
(
policy
,
CPUFREQ_GOV_POLICY_EXIT
);
down_write
(
&
policy
->
rwsem
);
if
(
ret
)
{
if
(
ret
)
{
pr_err
(
"%s: Failed to Exit Governor: %s (%d)
\n
"
,
pr_err
(
"%s: Failed to Exit Governor: %s (%d)
\n
"
,
__func__
,
old_gov
->
name
,
ret
);
__func__
,
old_gov
->
name
,
ret
);
...
@@ -2118,32 +2090,30 @@ static int cpufreq_set_policy(struct cpufreq_policy *policy,
...
@@ -2118,32 +2090,30 @@ static int cpufreq_set_policy(struct cpufreq_policy *policy,
/* start new governor */
/* start new governor */
policy
->
governor
=
new_policy
->
governor
;
policy
->
governor
=
new_policy
->
governor
;
ret
=
__
cpufreq_governor
(
policy
,
CPUFREQ_GOV_POLICY_INIT
);
ret
=
cpufreq_governor
(
policy
,
CPUFREQ_GOV_POLICY_INIT
);
if
(
!
ret
)
{
if
(
!
ret
)
{
ret
=
__
cpufreq_governor
(
policy
,
CPUFREQ_GOV_START
);
ret
=
cpufreq_governor
(
policy
,
CPUFREQ_GOV_START
);
if
(
!
ret
)
if
(
!
ret
)
goto
out
;
goto
out
;
up_write
(
&
policy
->
rwsem
);
cpufreq_governor
(
policy
,
CPUFREQ_GOV_POLICY_EXIT
);
__cpufreq_governor
(
policy
,
CPUFREQ_GOV_POLICY_EXIT
);
down_write
(
&
policy
->
rwsem
);
}
}
/* new governor failed, so re-start old one */
/* new governor failed, so re-start old one */
pr_debug
(
"starting governor %s failed
\n
"
,
policy
->
governor
->
name
);
pr_debug
(
"starting governor %s failed
\n
"
,
policy
->
governor
->
name
);
if
(
old_gov
)
{
if
(
old_gov
)
{
policy
->
governor
=
old_gov
;
policy
->
governor
=
old_gov
;
if
(
__
cpufreq_governor
(
policy
,
CPUFREQ_GOV_POLICY_INIT
))
if
(
cpufreq_governor
(
policy
,
CPUFREQ_GOV_POLICY_INIT
))
policy
->
governor
=
NULL
;
policy
->
governor
=
NULL
;
else
else
__
cpufreq_governor
(
policy
,
CPUFREQ_GOV_START
);
cpufreq_governor
(
policy
,
CPUFREQ_GOV_START
);
}
}
return
ret
;
return
ret
;
out:
out:
pr_debug
(
"governor: change or update limits
\n
"
);
pr_debug
(
"governor: change or update limits
\n
"
);
return
__
cpufreq_governor
(
policy
,
CPUFREQ_GOV_LIMITS
);
return
cpufreq_governor
(
policy
,
CPUFREQ_GOV_LIMITS
);
}
}
/**
/**
...
@@ -2210,11 +2180,7 @@ static int cpufreq_cpu_callback(struct notifier_block *nfb,
...
@@ -2210,11 +2180,7 @@ static int cpufreq_cpu_callback(struct notifier_block *nfb,
break
;
break
;
case
CPU_DOWN_PREPARE
:
case
CPU_DOWN_PREPARE
:
cpufreq_offline_prepare
(
cpu
);
cpufreq_offline
(
cpu
);
break
;
case
CPU_POST_DEAD
:
cpufreq_offline_finish
(
cpu
);
break
;
break
;
case
CPU_DOWN_FAILED
:
case
CPU_DOWN_FAILED
:
...
@@ -2247,8 +2213,11 @@ static int cpufreq_boost_set_sw(int state)
...
@@ -2247,8 +2213,11 @@ static int cpufreq_boost_set_sw(int state)
__func__
);
__func__
);
break
;
break
;
}
}
down_write
(
&
policy
->
rwsem
);
policy
->
user_policy
.
max
=
policy
->
max
;
policy
->
user_policy
.
max
=
policy
->
max
;
__cpufreq_governor
(
policy
,
CPUFREQ_GOV_LIMITS
);
cpufreq_governor
(
policy
,
CPUFREQ_GOV_LIMITS
);
up_write
(
&
policy
->
rwsem
);
}
}
}
}
...
...
drivers/cpufreq/cpufreq_conservative.c
浏览文件 @
a5acbfbd
...
@@ -14,6 +14,22 @@
...
@@ -14,6 +14,22 @@
#include <linux/slab.h>
#include <linux/slab.h>
#include "cpufreq_governor.h"
#include "cpufreq_governor.h"
struct
cs_policy_dbs_info
{
struct
policy_dbs_info
policy_dbs
;
unsigned
int
down_skip
;
unsigned
int
requested_freq
;
};
static
inline
struct
cs_policy_dbs_info
*
to_dbs_info
(
struct
policy_dbs_info
*
policy_dbs
)
{
return
container_of
(
policy_dbs
,
struct
cs_policy_dbs_info
,
policy_dbs
);
}
struct
cs_dbs_tuners
{
unsigned
int
down_threshold
;
unsigned
int
freq_step
;
};
/* Conservative governor macros */
/* Conservative governor macros */
#define DEF_FREQUENCY_UP_THRESHOLD (80)
#define DEF_FREQUENCY_UP_THRESHOLD (80)
#define DEF_FREQUENCY_DOWN_THRESHOLD (20)
#define DEF_FREQUENCY_DOWN_THRESHOLD (20)
...
@@ -21,18 +37,6 @@
...
@@ -21,18 +37,6 @@
#define DEF_SAMPLING_DOWN_FACTOR (1)
#define DEF_SAMPLING_DOWN_FACTOR (1)
#define MAX_SAMPLING_DOWN_FACTOR (10)
#define MAX_SAMPLING_DOWN_FACTOR (10)
static
DEFINE_PER_CPU
(
struct
cs_cpu_dbs_info_s
,
cs_cpu_dbs_info
);
static
int
cs_cpufreq_governor_dbs
(
struct
cpufreq_policy
*
policy
,
unsigned
int
event
);
static
struct
cpufreq_governor
cpufreq_gov_conservative
=
{
.
name
=
"conservative"
,
.
governor
=
cs_cpufreq_governor_dbs
,
.
max_transition_latency
=
TRANSITION_LATENCY_LIMIT
,
.
owner
=
THIS_MODULE
,
};
static
inline
unsigned
int
get_freq_target
(
struct
cs_dbs_tuners
*
cs_tuners
,
static
inline
unsigned
int
get_freq_target
(
struct
cs_dbs_tuners
*
cs_tuners
,
struct
cpufreq_policy
*
policy
)
struct
cpufreq_policy
*
policy
)
{
{
...
@@ -54,27 +58,28 @@ static inline unsigned int get_freq_target(struct cs_dbs_tuners *cs_tuners,
...
@@ -54,27 +58,28 @@ static inline unsigned int get_freq_target(struct cs_dbs_tuners *cs_tuners,
* Any frequency increase takes it to the maximum frequency. Frequency reduction
* Any frequency increase takes it to the maximum frequency. Frequency reduction
* happens at minimum steps of 5% (default) of maximum frequency
* happens at minimum steps of 5% (default) of maximum frequency
*/
*/
static
void
cs_check_cpu
(
int
cpu
,
unsigned
int
load
)
static
unsigned
int
cs_dbs_timer
(
struct
cpufreq_policy
*
policy
)
{
{
struct
cs_cpu_dbs_info_s
*
dbs_info
=
&
per_cpu
(
cs_cpu_dbs_info
,
cpu
)
;
struct
policy_dbs_info
*
policy_dbs
=
policy
->
governor_data
;
struct
c
pufreq_policy
*
policy
=
dbs_info
->
cdbs
.
shared
->
policy
;
struct
c
s_policy_dbs_info
*
dbs_info
=
to_dbs_info
(
policy_dbs
)
;
struct
dbs_data
*
dbs_data
=
policy
->
governor
_data
;
struct
dbs_data
*
dbs_data
=
policy
_dbs
->
dbs
_data
;
struct
cs_dbs_tuners
*
cs_tuners
=
dbs_data
->
tuners
;
struct
cs_dbs_tuners
*
cs_tuners
=
dbs_data
->
tuners
;
unsigned
int
load
=
dbs_update
(
policy
);
/*
/*
* break out if we 'cannot' reduce the speed as the user might
* break out if we 'cannot' reduce the speed as the user might
* want freq_step to be zero
* want freq_step to be zero
*/
*/
if
(
cs_tuners
->
freq_step
==
0
)
if
(
cs_tuners
->
freq_step
==
0
)
return
;
goto
out
;
/* Check for frequency increase */
/* Check for frequency increase */
if
(
load
>
cs_tuners
->
up_threshold
)
{
if
(
load
>
dbs_data
->
up_threshold
)
{
dbs_info
->
down_skip
=
0
;
dbs_info
->
down_skip
=
0
;
/* if we are already at full speed then break out early */
/* if we are already at full speed then break out early */
if
(
dbs_info
->
requested_freq
==
policy
->
max
)
if
(
dbs_info
->
requested_freq
==
policy
->
max
)
return
;
goto
out
;
dbs_info
->
requested_freq
+=
get_freq_target
(
cs_tuners
,
policy
);
dbs_info
->
requested_freq
+=
get_freq_target
(
cs_tuners
,
policy
);
...
@@ -83,12 +88,12 @@ static void cs_check_cpu(int cpu, unsigned int load)
...
@@ -83,12 +88,12 @@ static void cs_check_cpu(int cpu, unsigned int load)
__cpufreq_driver_target
(
policy
,
dbs_info
->
requested_freq
,
__cpufreq_driver_target
(
policy
,
dbs_info
->
requested_freq
,
CPUFREQ_RELATION_H
);
CPUFREQ_RELATION_H
);
return
;
goto
out
;
}
}
/* if sampling_down_factor is active break out early */
/* if sampling_down_factor is active break out early */
if
(
++
dbs_info
->
down_skip
<
cs_tuners
->
sampling_down_factor
)
if
(
++
dbs_info
->
down_skip
<
dbs_data
->
sampling_down_factor
)
return
;
goto
out
;
dbs_info
->
down_skip
=
0
;
dbs_info
->
down_skip
=
0
;
/* Check for frequency decrease */
/* Check for frequency decrease */
...
@@ -98,7 +103,7 @@ static void cs_check_cpu(int cpu, unsigned int load)
...
@@ -98,7 +103,7 @@ static void cs_check_cpu(int cpu, unsigned int load)
* if we cannot reduce the frequency anymore, break out early
* if we cannot reduce the frequency anymore, break out early
*/
*/
if
(
policy
->
cur
==
policy
->
min
)
if
(
policy
->
cur
==
policy
->
min
)
return
;
goto
out
;
freq_target
=
get_freq_target
(
cs_tuners
,
policy
);
freq_target
=
get_freq_target
(
cs_tuners
,
policy
);
if
(
dbs_info
->
requested_freq
>
freq_target
)
if
(
dbs_info
->
requested_freq
>
freq_target
)
...
@@ -108,58 +113,25 @@ static void cs_check_cpu(int cpu, unsigned int load)
...
@@ -108,58 +113,25 @@ static void cs_check_cpu(int cpu, unsigned int load)
__cpufreq_driver_target
(
policy
,
dbs_info
->
requested_freq
,
__cpufreq_driver_target
(
policy
,
dbs_info
->
requested_freq
,
CPUFREQ_RELATION_L
);
CPUFREQ_RELATION_L
);
return
;
}
}
}
static
unsigned
int
cs_dbs_timer
(
struct
cpufreq_policy
*
policy
,
bool
modify_all
)
{
struct
dbs_data
*
dbs_data
=
policy
->
governor_data
;
struct
cs_dbs_tuners
*
cs_tuners
=
dbs_data
->
tuners
;
if
(
modify_all
)
dbs_check_cpu
(
dbs_data
,
policy
->
cpu
);
return
delay_for_sampling_rate
(
cs_tuners
->
sampling_rate
);
out:
return
dbs_data
->
sampling_rate
;
}
}
static
int
dbs_cpufreq_notifier
(
struct
notifier_block
*
nb
,
unsigned
long
val
,
static
int
dbs_cpufreq_notifier
(
struct
notifier_block
*
nb
,
unsigned
long
val
,
void
*
data
)
void
*
data
);
{
struct
cpufreq_freqs
*
freq
=
data
;
struct
cs_cpu_dbs_info_s
*
dbs_info
=
&
per_cpu
(
cs_cpu_dbs_info
,
freq
->
cpu
);
struct
cpufreq_policy
*
policy
=
cpufreq_cpu_get_raw
(
freq
->
cpu
);
if
(
!
policy
)
return
0
;
/* policy isn't governed by conservative governor */
if
(
policy
->
governor
!=
&
cpufreq_gov_conservative
)
return
0
;
/*
* we only care if our internally tracked freq moves outside the 'valid'
* ranges of frequency available to us otherwise we do not change it
*/
if
(
dbs_info
->
requested_freq
>
policy
->
max
||
dbs_info
->
requested_freq
<
policy
->
min
)
dbs_info
->
requested_freq
=
freq
->
new
;
return
0
;
}
static
struct
notifier_block
cs_cpufreq_notifier_block
=
{
static
struct
notifier_block
cs_cpufreq_notifier_block
=
{
.
notifier_call
=
dbs_cpufreq_notifier
,
.
notifier_call
=
dbs_cpufreq_notifier
,
};
};
/************************** sysfs interface ************************/
/************************** sysfs interface ************************/
static
struct
common_dbs_data
cs_dbs_cdata
;
static
struct
dbs_governor
cs_dbs_gov
;
static
ssize_t
store_sampling_down_factor
(
struct
dbs_data
*
dbs_data
,
static
ssize_t
store_sampling_down_factor
(
struct
dbs_data
*
dbs_data
,
const
char
*
buf
,
size_t
count
)
const
char
*
buf
,
size_t
count
)
{
{
struct
cs_dbs_tuners
*
cs_tuners
=
dbs_data
->
tuners
;
unsigned
int
input
;
unsigned
int
input
;
int
ret
;
int
ret
;
ret
=
sscanf
(
buf
,
"%u"
,
&
input
);
ret
=
sscanf
(
buf
,
"%u"
,
&
input
);
...
@@ -167,22 +139,7 @@ static ssize_t store_sampling_down_factor(struct dbs_data *dbs_data,
...
@@ -167,22 +139,7 @@ static ssize_t store_sampling_down_factor(struct dbs_data *dbs_data,
if
(
ret
!=
1
||
input
>
MAX_SAMPLING_DOWN_FACTOR
||
input
<
1
)
if
(
ret
!=
1
||
input
>
MAX_SAMPLING_DOWN_FACTOR
||
input
<
1
)
return
-
EINVAL
;
return
-
EINVAL
;
cs_tuners
->
sampling_down_factor
=
input
;
dbs_data
->
sampling_down_factor
=
input
;
return
count
;
}
static
ssize_t
store_sampling_rate
(
struct
dbs_data
*
dbs_data
,
const
char
*
buf
,
size_t
count
)
{
struct
cs_dbs_tuners
*
cs_tuners
=
dbs_data
->
tuners
;
unsigned
int
input
;
int
ret
;
ret
=
sscanf
(
buf
,
"%u"
,
&
input
);
if
(
ret
!=
1
)
return
-
EINVAL
;
cs_tuners
->
sampling_rate
=
max
(
input
,
dbs_data
->
min_sampling_rate
);
return
count
;
return
count
;
}
}
...
@@ -197,7 +154,7 @@ static ssize_t store_up_threshold(struct dbs_data *dbs_data, const char *buf,
...
@@ -197,7 +154,7 @@ static ssize_t store_up_threshold(struct dbs_data *dbs_data, const char *buf,
if
(
ret
!=
1
||
input
>
100
||
input
<=
cs_tuners
->
down_threshold
)
if
(
ret
!=
1
||
input
>
100
||
input
<=
cs_tuners
->
down_threshold
)
return
-
EINVAL
;
return
-
EINVAL
;
cs_tuners
->
up_threshold
=
input
;
dbs_data
->
up_threshold
=
input
;
return
count
;
return
count
;
}
}
...
@@ -211,7 +168,7 @@ static ssize_t store_down_threshold(struct dbs_data *dbs_data, const char *buf,
...
@@ -211,7 +168,7 @@ static ssize_t store_down_threshold(struct dbs_data *dbs_data, const char *buf,
/* cannot be lower than 11 otherwise freq will not fall */
/* cannot be lower than 11 otherwise freq will not fall */
if
(
ret
!=
1
||
input
<
11
||
input
>
100
||
if
(
ret
!=
1
||
input
<
11
||
input
>
100
||
input
>=
cs_tuners
->
up_threshold
)
input
>=
dbs_data
->
up_threshold
)
return
-
EINVAL
;
return
-
EINVAL
;
cs_tuners
->
down_threshold
=
input
;
cs_tuners
->
down_threshold
=
input
;
...
@@ -221,8 +178,7 @@ static ssize_t store_down_threshold(struct dbs_data *dbs_data, const char *buf,
...
@@ -221,8 +178,7 @@ static ssize_t store_down_threshold(struct dbs_data *dbs_data, const char *buf,
static
ssize_t
store_ignore_nice_load
(
struct
dbs_data
*
dbs_data
,
static
ssize_t
store_ignore_nice_load
(
struct
dbs_data
*
dbs_data
,
const
char
*
buf
,
size_t
count
)
const
char
*
buf
,
size_t
count
)
{
{
struct
cs_dbs_tuners
*
cs_tuners
=
dbs_data
->
tuners
;
unsigned
int
input
;
unsigned
int
input
,
j
;
int
ret
;
int
ret
;
ret
=
sscanf
(
buf
,
"%u"
,
&
input
);
ret
=
sscanf
(
buf
,
"%u"
,
&
input
);
...
@@ -232,21 +188,14 @@ static ssize_t store_ignore_nice_load(struct dbs_data *dbs_data,
...
@@ -232,21 +188,14 @@ static ssize_t store_ignore_nice_load(struct dbs_data *dbs_data,
if
(
input
>
1
)
if
(
input
>
1
)
input
=
1
;
input
=
1
;
if
(
input
==
cs_tuners
->
ignore_nice_load
)
/* nothing to do */
if
(
input
==
dbs_data
->
ignore_nice_load
)
/* nothing to do */
return
count
;
return
count
;
cs_tuners
->
ignore_nice_load
=
input
;
dbs_data
->
ignore_nice_load
=
input
;
/* we need to re-evaluate prev_cpu_idle */
/* we need to re-evaluate prev_cpu_idle */
for_each_online_cpu
(
j
)
{
gov_update_cpu_data
(
dbs_data
);
struct
cs_cpu_dbs_info_s
*
dbs_info
;
dbs_info
=
&
per_cpu
(
cs_cpu_dbs_info
,
j
);
dbs_info
->
cdbs
.
prev_cpu_idle
=
get_cpu_idle_time
(
j
,
&
dbs_info
->
cdbs
.
prev_cpu_wall
,
0
);
if
(
cs_tuners
->
ignore_nice_load
)
dbs_info
->
cdbs
.
prev_cpu_nice
=
kcpustat_cpu
(
j
).
cpustat
[
CPUTIME_NICE
];
}
return
count
;
return
count
;
}
}
...
@@ -272,55 +221,47 @@ static ssize_t store_freq_step(struct dbs_data *dbs_data, const char *buf,
...
@@ -272,55 +221,47 @@ static ssize_t store_freq_step(struct dbs_data *dbs_data, const char *buf,
return
count
;
return
count
;
}
}
show_store_one
(
cs
,
sampling_rate
);
gov_show_one_common
(
sampling_rate
);
show_store_one
(
cs
,
sampling_down_factor
);
gov_show_one_common
(
sampling_down_factor
);
show_store_one
(
cs
,
up_threshold
);
gov_show_one_common
(
up_threshold
);
show_store_one
(
cs
,
down_threshol
d
);
gov_show_one_common
(
ignore_nice_loa
d
);
show_store_one
(
cs
,
ignore_nice_load
);
gov_show_one_common
(
min_sampling_rate
);
show_store_one
(
cs
,
freq_step
);
gov_show_one
(
cs
,
down_threshold
);
declare_show_sampling_rate_min
(
cs
);
gov_show_one
(
cs
,
freq_step
);
gov_
sys_pol_
attr_rw
(
sampling_rate
);
gov_attr_rw
(
sampling_rate
);
gov_
sys_pol_
attr_rw
(
sampling_down_factor
);
gov_attr_rw
(
sampling_down_factor
);
gov_
sys_pol_
attr_rw
(
up_threshold
);
gov_attr_rw
(
up_threshold
);
gov_
sys_pol_attr_rw
(
down_threshol
d
);
gov_
attr_rw
(
ignore_nice_loa
d
);
gov_
sys_pol_attr_rw
(
ignore_nice_load
);
gov_
attr_ro
(
min_sampling_rate
);
gov_
sys_pol_attr_rw
(
freq_step
);
gov_
attr_rw
(
down_threshold
);
gov_
sys_pol_attr_ro
(
sampling_rate_min
);
gov_
attr_rw
(
freq_step
);
static
struct
attribute
*
dbs_attributes_gov_sy
s
[]
=
{
static
struct
attribute
*
cs_attribute
s
[]
=
{
&
sampling_rate_min_gov_sys
.
attr
,
&
min_sampling_rate
.
attr
,
&
sampling_rate
_gov_sys
.
attr
,
&
sampling_rate
.
attr
,
&
sampling_down_factor
_gov_sys
.
attr
,
&
sampling_down_factor
.
attr
,
&
up_threshold
_gov_sys
.
attr
,
&
up_threshold
.
attr
,
&
down_threshold
_gov_sys
.
attr
,
&
down_threshold
.
attr
,
&
ignore_nice_load
_gov_sys
.
attr
,
&
ignore_nice_load
.
attr
,
&
freq_step
_gov_sys
.
attr
,
&
freq_step
.
attr
,
NULL
NULL
};
};
static
struct
attribute_group
cs_attr_group_gov_sys
=
{
/************************** sysfs end ************************/
.
attrs
=
dbs_attributes_gov_sys
,
.
name
=
"conservative"
,
};
static
struct
attribute
*
dbs_attributes_gov_pol
[]
=
{
static
struct
policy_dbs_info
*
cs_alloc
(
void
)
&
sampling_rate_min_gov_pol
.
attr
,
{
&
sampling_rate_gov_pol
.
attr
,
struct
cs_policy_dbs_info
*
dbs_info
;
&
sampling_down_factor_gov_pol
.
attr
,
&
up_threshold_gov_pol
.
attr
,
&
down_threshold_gov_pol
.
attr
,
&
ignore_nice_load_gov_pol
.
attr
,
&
freq_step_gov_pol
.
attr
,
NULL
};
static
struct
attribute_group
cs_attr_group_gov_pol
=
{
dbs_info
=
kzalloc
(
sizeof
(
*
dbs_info
),
GFP_KERNEL
);
.
attrs
=
dbs_attributes_gov_pol
,
return
dbs_info
?
&
dbs_info
->
policy_dbs
:
NULL
;
.
name
=
"conservative"
,
}
};
/************************** sysfs end ************************/
static
void
cs_free
(
struct
policy_dbs_info
*
policy_dbs
)
{
kfree
(
to_dbs_info
(
policy_dbs
));
}
static
int
cs_init
(
struct
dbs_data
*
dbs_data
,
bool
notify
)
static
int
cs_init
(
struct
dbs_data
*
dbs_data
,
bool
notify
)
{
{
...
@@ -332,11 +273,11 @@ static int cs_init(struct dbs_data *dbs_data, bool notify)
...
@@ -332,11 +273,11 @@ static int cs_init(struct dbs_data *dbs_data, bool notify)
return
-
ENOMEM
;
return
-
ENOMEM
;
}
}
tuners
->
up_threshold
=
DEF_FREQUENCY_UP_THRESHOLD
;
tuners
->
down_threshold
=
DEF_FREQUENCY_DOWN_THRESHOLD
;
tuners
->
down_threshold
=
DEF_FREQUENCY_DOWN_THRESHOLD
;
tuners
->
sampling_down_factor
=
DEF_SAMPLING_DOWN_FACTOR
;
tuners
->
ignore_nice_load
=
0
;
tuners
->
freq_step
=
DEF_FREQUENCY_STEP
;
tuners
->
freq_step
=
DEF_FREQUENCY_STEP
;
dbs_data
->
up_threshold
=
DEF_FREQUENCY_UP_THRESHOLD
;
dbs_data
->
sampling_down_factor
=
DEF_SAMPLING_DOWN_FACTOR
;
dbs_data
->
ignore_nice_load
=
0
;
dbs_data
->
tuners
=
tuners
;
dbs_data
->
tuners
=
tuners
;
dbs_data
->
min_sampling_rate
=
MIN_SAMPLING_RATE_RATIO
*
dbs_data
->
min_sampling_rate
=
MIN_SAMPLING_RATE_RATIO
*
...
@@ -358,35 +299,66 @@ static void cs_exit(struct dbs_data *dbs_data, bool notify)
...
@@ -358,35 +299,66 @@ static void cs_exit(struct dbs_data *dbs_data, bool notify)
kfree
(
dbs_data
->
tuners
);
kfree
(
dbs_data
->
tuners
);
}
}
define_get_cpu_dbs_routines
(
cs_cpu_dbs_info
);
static
void
cs_start
(
struct
cpufreq_policy
*
policy
)
{
struct
cs_policy_dbs_info
*
dbs_info
=
to_dbs_info
(
policy
->
governor_data
);
dbs_info
->
down_skip
=
0
;
dbs_info
->
requested_freq
=
policy
->
cur
;
}
static
struct
common_dbs_data
cs_dbs_cdata
=
{
static
struct
dbs_governor
cs_dbs_gov
=
{
.
governor
=
GOV_CONSERVATIVE
,
.
gov
=
{
.
attr_group_gov_sys
=
&
cs_attr_group_gov_sys
,
.
name
=
"conservative"
,
.
attr_group_gov_pol
=
&
cs_attr_group_gov_pol
,
.
governor
=
cpufreq_governor_dbs
,
.
get_cpu_cdbs
=
get_cpu_cdbs
,
.
max_transition_latency
=
TRANSITION_LATENCY_LIMIT
,
.
get_cpu_dbs_info_s
=
get_cpu_dbs_info_s
,
.
owner
=
THIS_MODULE
,
},
.
kobj_type
=
{
.
default_attrs
=
cs_attributes
},
.
gov_dbs_timer
=
cs_dbs_timer
,
.
gov_dbs_timer
=
cs_dbs_timer
,
.
gov_check_cpu
=
cs_check_cpu
,
.
alloc
=
cs_alloc
,
.
free
=
cs_free
,
.
init
=
cs_init
,
.
init
=
cs_init
,
.
exit
=
cs_exit
,
.
exit
=
cs_exit
,
.
mutex
=
__MUTEX_INITIALIZER
(
cs_dbs_cdata
.
mutex
)
,
.
start
=
cs_start
,
};
};
static
int
cs_cpufreq_governor_dbs
(
struct
cpufreq_policy
*
policy
,
#define CPU_FREQ_GOV_CONSERVATIVE (&cs_dbs_gov.gov)
unsigned
int
event
)
static
int
dbs_cpufreq_notifier
(
struct
notifier_block
*
nb
,
unsigned
long
val
,
void
*
data
)
{
{
return
cpufreq_governor_dbs
(
policy
,
&
cs_dbs_cdata
,
event
);
struct
cpufreq_freqs
*
freq
=
data
;
struct
cpufreq_policy
*
policy
=
cpufreq_cpu_get_raw
(
freq
->
cpu
);
struct
cs_policy_dbs_info
*
dbs_info
;
if
(
!
policy
)
return
0
;
/* policy isn't governed by conservative governor */
if
(
policy
->
governor
!=
CPU_FREQ_GOV_CONSERVATIVE
)
return
0
;
dbs_info
=
to_dbs_info
(
policy
->
governor_data
);
/*
* we only care if our internally tracked freq moves outside the 'valid'
* ranges of frequency available to us otherwise we do not change it
*/
if
(
dbs_info
->
requested_freq
>
policy
->
max
||
dbs_info
->
requested_freq
<
policy
->
min
)
dbs_info
->
requested_freq
=
freq
->
new
;
return
0
;
}
}
static
int
__init
cpufreq_gov_dbs_init
(
void
)
static
int
__init
cpufreq_gov_dbs_init
(
void
)
{
{
return
cpufreq_register_governor
(
&
cpufreq_gov_conservative
);
return
cpufreq_register_governor
(
CPU_FREQ_GOV_CONSERVATIVE
);
}
}
static
void
__exit
cpufreq_gov_dbs_exit
(
void
)
static
void
__exit
cpufreq_gov_dbs_exit
(
void
)
{
{
cpufreq_unregister_governor
(
&
cpufreq_gov_conservative
);
cpufreq_unregister_governor
(
CPU_FREQ_GOV_CONSERVATIVE
);
}
}
MODULE_AUTHOR
(
"Alexander Clouter <alex@digriz.org.uk>"
);
MODULE_AUTHOR
(
"Alexander Clouter <alex@digriz.org.uk>"
);
...
@@ -398,7 +370,7 @@ MODULE_LICENSE("GPL");
...
@@ -398,7 +370,7 @@ MODULE_LICENSE("GPL");
#ifdef CONFIG_CPU_FREQ_DEFAULT_GOV_CONSERVATIVE
#ifdef CONFIG_CPU_FREQ_DEFAULT_GOV_CONSERVATIVE
struct
cpufreq_governor
*
cpufreq_default_governor
(
void
)
struct
cpufreq_governor
*
cpufreq_default_governor
(
void
)
{
{
return
&
cpufreq_gov_conservative
;
return
CPU_FREQ_GOV_CONSERVATIVE
;
}
}
fs_initcall
(
cpufreq_gov_dbs_init
);
fs_initcall
(
cpufreq_gov_dbs_init
);
...
...
drivers/cpufreq/cpufreq_governor.c
浏览文件 @
a5acbfbd
...
@@ -18,95 +18,193 @@
...
@@ -18,95 +18,193 @@
#include <linux/export.h>
#include <linux/export.h>
#include <linux/kernel_stat.h>
#include <linux/kernel_stat.h>
#include <linux/sched.h>
#include <linux/slab.h>
#include <linux/slab.h>
#include "cpufreq_governor.h"
#include "cpufreq_governor.h"
static
struct
attribute_group
*
get_sysfs_attr
(
struct
dbs_data
*
dbs_data
)
static
DEFINE_PER_CPU
(
struct
cpu_dbs_info
,
cpu_dbs
);
{
if
(
have_governor_per_policy
())
static
DEFINE_MUTEX
(
gov_dbs_data_mutex
);
return
dbs_data
->
cdata
->
attr_group_gov_pol
;
else
return
dbs_data
->
cdata
->
attr_group_gov_sys
;
}
void
dbs_check_cpu
(
struct
dbs_data
*
dbs_data
,
int
cpu
)
/* Common sysfs tunables */
/**
* store_sampling_rate - update sampling rate effective immediately if needed.
*
* If new rate is smaller than the old, simply updating
* dbs.sampling_rate might not be appropriate. For example, if the
* original sampling_rate was 1 second and the requested new sampling rate is 10
* ms because the user needs immediate reaction from ondemand governor, but not
* sure if higher frequency will be required or not, then, the governor may
* change the sampling rate too late; up to 1 second later. Thus, if we are
* reducing the sampling rate, we need to make the new value effective
* immediately.
*
* This must be called with dbs_data->mutex held, otherwise traversing
* policy_dbs_list isn't safe.
*/
ssize_t
store_sampling_rate
(
struct
dbs_data
*
dbs_data
,
const
char
*
buf
,
size_t
count
)
{
{
struct
cpu_dbs_info
*
cdbs
=
dbs_data
->
cdata
->
get_cpu_cdbs
(
cpu
);
struct
policy_dbs_info
*
policy_dbs
;
struct
od_dbs_tuners
*
od_tuners
=
dbs_data
->
tuners
;
unsigned
int
rate
;
struct
cs_dbs_tuners
*
cs_tuners
=
dbs_data
->
tuners
;
int
ret
;
struct
cpufreq_policy
*
policy
=
cdbs
->
shared
->
policy
;
ret
=
sscanf
(
buf
,
"%u"
,
&
rate
);
unsigned
int
sampling_rate
;
if
(
ret
!=
1
)
unsigned
int
max_load
=
0
;
return
-
EINVAL
;
unsigned
int
ignore_nice
;
unsigned
int
j
;
if
(
dbs_data
->
cdata
->
governor
==
GOV_ONDEMAND
)
{
dbs_data
->
sampling_rate
=
max
(
rate
,
dbs_data
->
min_sampling_rate
);
struct
od_cpu_dbs_info_s
*
od_dbs_info
=
dbs_data
->
cdata
->
get_cpu_dbs_info_s
(
cpu
);
/*
* We are operating under dbs_data->mutex and so the list and its
* entries can't be freed concurrently.
*/
list_for_each_entry
(
policy_dbs
,
&
dbs_data
->
policy_dbs_list
,
list
)
{
mutex_lock
(
&
policy_dbs
->
timer_mutex
);
/*
/*
* Sometimes, the ondemand governor uses an additional
* On 32-bit architectures this may race with the
* multiplier to give long delays. So apply this multiplier to
* sample_delay_ns read in dbs_update_util_handler(), but that
* the 'sampling_rate', so as to keep the wake-up-from-idle
* really doesn't matter. If the read returns a value that's
* detection logic a bit conservative.
* too big, the sample will be skipped, but the next invocation
* of dbs_update_util_handler() (when the update has been
* completed) will take a sample.
*
* If this runs in parallel with dbs_work_handler(), we may end
* up overwriting the sample_delay_ns value that it has just
* written, but it will be corrected next time a sample is
* taken, so it shouldn't be significant.
*/
*/
sampling_rate
=
od_tuners
->
sampling_rate
;
gov_update_sample_delay
(
policy_dbs
,
0
);
sampling_rate
*=
od_dbs_info
->
rate_mult
;
mutex_unlock
(
&
policy_dbs
->
timer_mutex
);
}
ignore_nice
=
od_tuners
->
ignore_nice_load
;
return
count
;
}
else
{
}
sampling_rate
=
cs_tuners
->
sampling_rate
;
EXPORT_SYMBOL_GPL
(
store_sampling_rate
);
ignore_nice
=
cs_tuners
->
ignore_nice_load
;
/**
* gov_update_cpu_data - Update CPU load data.
* @dbs_data: Top-level governor data pointer.
*
* Update CPU load data for all CPUs in the domain governed by @dbs_data
* (that may be a single policy or a bunch of them if governor tunables are
* system-wide).
*
* Call under the @dbs_data mutex.
*/
void
gov_update_cpu_data
(
struct
dbs_data
*
dbs_data
)
{
struct
policy_dbs_info
*
policy_dbs
;
list_for_each_entry
(
policy_dbs
,
&
dbs_data
->
policy_dbs_list
,
list
)
{
unsigned
int
j
;
for_each_cpu
(
j
,
policy_dbs
->
policy
->
cpus
)
{
struct
cpu_dbs_info
*
j_cdbs
=
&
per_cpu
(
cpu_dbs
,
j
);
j_cdbs
->
prev_cpu_idle
=
get_cpu_idle_time
(
j
,
&
j_cdbs
->
prev_cpu_wall
,
dbs_data
->
io_is_busy
);
if
(
dbs_data
->
ignore_nice_load
)
j_cdbs
->
prev_cpu_nice
=
kcpustat_cpu
(
j
).
cpustat
[
CPUTIME_NICE
];
}
}
}
}
EXPORT_SYMBOL_GPL
(
gov_update_cpu_data
);
static
inline
struct
dbs_data
*
to_dbs_data
(
struct
kobject
*
kobj
)
{
return
container_of
(
kobj
,
struct
dbs_data
,
kobj
);
}
static
inline
struct
governor_attr
*
to_gov_attr
(
struct
attribute
*
attr
)
{
return
container_of
(
attr
,
struct
governor_attr
,
attr
);
}
static
ssize_t
governor_show
(
struct
kobject
*
kobj
,
struct
attribute
*
attr
,
char
*
buf
)
{
struct
dbs_data
*
dbs_data
=
to_dbs_data
(
kobj
);
struct
governor_attr
*
gattr
=
to_gov_attr
(
attr
);
return
gattr
->
show
(
dbs_data
,
buf
);
}
static
ssize_t
governor_store
(
struct
kobject
*
kobj
,
struct
attribute
*
attr
,
const
char
*
buf
,
size_t
count
)
{
struct
dbs_data
*
dbs_data
=
to_dbs_data
(
kobj
);
struct
governor_attr
*
gattr
=
to_gov_attr
(
attr
);
int
ret
=
-
EBUSY
;
mutex_lock
(
&
dbs_data
->
mutex
);
if
(
dbs_data
->
usage_count
)
ret
=
gattr
->
store
(
dbs_data
,
buf
,
count
);
mutex_unlock
(
&
dbs_data
->
mutex
);
return
ret
;
}
/*
* Sysfs Ops for accessing governor attributes.
*
* All show/store invocations for governor specific sysfs attributes, will first
* call the below show/store callbacks and the attribute specific callback will
* be called from within it.
*/
static
const
struct
sysfs_ops
governor_sysfs_ops
=
{
.
show
=
governor_show
,
.
store
=
governor_store
,
};
unsigned
int
dbs_update
(
struct
cpufreq_policy
*
policy
)
{
struct
policy_dbs_info
*
policy_dbs
=
policy
->
governor_data
;
struct
dbs_data
*
dbs_data
=
policy_dbs
->
dbs_data
;
unsigned
int
ignore_nice
=
dbs_data
->
ignore_nice_load
;
unsigned
int
max_load
=
0
;
unsigned
int
sampling_rate
,
io_busy
,
j
;
/*
* Sometimes governors may use an additional multiplier to increase
* sample delays temporarily. Apply that multiplier to sampling_rate
* so as to keep the wake-up-from-idle detection logic a bit
* conservative.
*/
sampling_rate
=
dbs_data
->
sampling_rate
*
policy_dbs
->
rate_mult
;
/*
* For the purpose of ondemand, waiting for disk IO is an indication
* that you're performance critical, and not that the system is actually
* idle, so do not add the iowait time to the CPU idle time then.
*/
io_busy
=
dbs_data
->
io_is_busy
;
/* Get Absolute Load */
/* Get Absolute Load */
for_each_cpu
(
j
,
policy
->
cpus
)
{
for_each_cpu
(
j
,
policy
->
cpus
)
{
struct
cpu_dbs_info
*
j_cdbs
;
struct
cpu_dbs_info
*
j_cdbs
=
&
per_cpu
(
cpu_dbs
,
j
)
;
u64
cur_wall_time
,
cur_idle_time
;
u64
cur_wall_time
,
cur_idle_time
;
unsigned
int
idle_time
,
wall_time
;
unsigned
int
idle_time
,
wall_time
;
unsigned
int
load
;
unsigned
int
load
;
int
io_busy
=
0
;
j_cdbs
=
dbs_data
->
cdata
->
get_cpu_cdbs
(
j
);
/*
* For the purpose of ondemand, waiting for disk IO is
* an indication that you're performance critical, and
* not that the system is actually idle. So do not add
* the iowait time to the cpu idle time.
*/
if
(
dbs_data
->
cdata
->
governor
==
GOV_ONDEMAND
)
io_busy
=
od_tuners
->
io_is_busy
;
cur_idle_time
=
get_cpu_idle_time
(
j
,
&
cur_wall_time
,
io_busy
);
cur_idle_time
=
get_cpu_idle_time
(
j
,
&
cur_wall_time
,
io_busy
);
wall_time
=
(
unsigned
int
)
wall_time
=
cur_wall_time
-
j_cdbs
->
prev_cpu_wall
;
(
cur_wall_time
-
j_cdbs
->
prev_cpu_wall
);
j_cdbs
->
prev_cpu_wall
=
cur_wall_time
;
j_cdbs
->
prev_cpu_wall
=
cur_wall_time
;
if
(
cur_idle_time
<
j_cdbs
->
prev_cpu_idle
)
if
(
cur_idle_time
<
=
j_cdbs
->
prev_cpu_idle
)
{
cur_idle_time
=
j_cdbs
->
prev_cpu_idle
;
idle_time
=
0
;
}
else
{
idle_time
=
(
unsigned
int
)
idle_time
=
cur_idle_time
-
j_cdbs
->
prev_cpu_idle
;
(
cur_idle_time
-
j_cdbs
->
prev_cpu_idle
)
;
j_cdbs
->
prev_cpu_idle
=
cur_idle_time
;
j_cdbs
->
prev_cpu_idle
=
cur_idle_time
;
}
if
(
ignore_nice
)
{
if
(
ignore_nice
)
{
u64
cur_nice
;
u64
cur_nice
=
kcpustat_cpu
(
j
).
cpustat
[
CPUTIME_NICE
];
unsigned
long
cur_nice_jiffies
;
cur_nice
=
kcpustat_cpu
(
j
).
cpustat
[
CPUTIME_NICE
]
-
cdbs
->
prev_cpu_nice
;
/*
* Assumption: nice time between sampling periods will
* be less than 2^32 jiffies for 32 bit sys
*/
cur_nice_jiffies
=
(
unsigned
long
)
cputime64_to_jiffies64
(
cur_nice
);
cdbs
->
prev_cpu_nice
=
idle_time
+=
cputime_to_usecs
(
cur_nice
-
j_cdbs
->
prev_cpu_nice
);
kcpustat_cpu
(
j
).
cpustat
[
CPUTIME_NICE
];
j_cdbs
->
prev_cpu_nice
=
cur_nice
;
idle_time
+=
jiffies_to_usecs
(
cur_nice_jiffies
);
}
}
if
(
unlikely
(
!
wall_time
||
wall_time
<
idle_time
))
if
(
unlikely
(
!
wall_time
||
wall_time
<
idle_time
))
...
@@ -128,10 +226,10 @@ void dbs_check_cpu(struct dbs_data *dbs_data, int cpu)
...
@@ -128,10 +226,10 @@ void dbs_check_cpu(struct dbs_data *dbs_data, int cpu)
* dropped down. So we perform the copy only once, upon the
* dropped down. So we perform the copy only once, upon the
* first wake-up from idle.)
* first wake-up from idle.)
*
*
* Detecting this situation is easy: the governor's
deferrable
* Detecting this situation is easy: the governor's
utilization
*
timer would not have fired during CPU-idle periods. Hence
*
update handler would not have run during CPU-idle periods.
*
an unusually large 'wall_time' (as compared to the sampling
*
Hence, an unusually large 'wall_time' (as compared to the
* rate) indicates this scenario.
*
sampling
rate) indicates this scenario.
*
*
* prev_load can be zero in two cases and we must recalculate it
* prev_load can be zero in two cases and we must recalculate it
* for both cases:
* for both cases:
...
@@ -156,222 +254,224 @@ void dbs_check_cpu(struct dbs_data *dbs_data, int cpu)
...
@@ -156,222 +254,224 @@ void dbs_check_cpu(struct dbs_data *dbs_data, int cpu)
if
(
load
>
max_load
)
if
(
load
>
max_load
)
max_load
=
load
;
max_load
=
load
;
}
}
return
max_load
;
dbs_data
->
cdata
->
gov_check_cpu
(
cpu
,
max_load
);
}
}
EXPORT_SYMBOL_GPL
(
dbs_
check_cpu
);
EXPORT_SYMBOL_GPL
(
dbs_
update
);
void
gov_add_timers
(
struct
cpufreq_policy
*
policy
,
unsigned
int
delay
)
static
void
gov_set_update_util
(
struct
policy_dbs_info
*
policy_dbs
,
unsigned
int
delay_us
)
{
{
struct
dbs_data
*
dbs_data
=
policy
->
governor_data
;
struct
cpufreq_policy
*
policy
=
policy_dbs
->
policy
;
struct
cpu_dbs_info
*
cdbs
;
int
cpu
;
int
cpu
;
gov_update_sample_delay
(
policy_dbs
,
delay_us
);
policy_dbs
->
last_sample_time
=
0
;
for_each_cpu
(
cpu
,
policy
->
cpus
)
{
for_each_cpu
(
cpu
,
policy
->
cpus
)
{
cdbs
=
dbs_data
->
cdata
->
get_cpu_cdbs
(
cpu
);
struct
cpu_dbs_info
*
cdbs
=
&
per_cpu
(
cpu_dbs
,
cpu
);
cdbs
->
timer
.
expires
=
jiffies
+
delay
;
add_timer_on
(
&
cdbs
->
timer
,
cpu
);
cpufreq_set_update_util_data
(
cpu
,
&
cdbs
->
update_util
);
}
}
}
}
EXPORT_SYMBOL_GPL
(
gov_add_timers
);
static
inline
void
gov_c
ancel_timers
(
struct
cpufreq_policy
*
policy
)
static
inline
void
gov_c
lear_update_util
(
struct
cpufreq_policy
*
policy
)
{
{
struct
dbs_data
*
dbs_data
=
policy
->
governor_data
;
struct
cpu_dbs_info
*
cdbs
;
int
i
;
int
i
;
for_each_cpu
(
i
,
policy
->
cpus
)
{
for_each_cpu
(
i
,
policy
->
cpus
)
cdbs
=
dbs_data
->
cdata
->
get_cpu_cdbs
(
i
);
cpufreq_set_update_util_data
(
i
,
NULL
);
del_timer_sync
(
&
cdbs
->
timer
);
}
}
void
gov_cancel_work
(
struct
cpu_common_dbs_info
*
shared
)
synchronize_sched
();
{
/* Tell dbs_timer_handler() to skip queuing up work items. */
atomic_inc
(
&
shared
->
skip_work
);
/*
* If dbs_timer_handler() is already running, it may not notice the
* incremented skip_work, so wait for it to complete to prevent its work
* item from being queued up after the cancel_work_sync() below.
*/
gov_cancel_timers
(
shared
->
policy
);
/*
* In case dbs_timer_handler() managed to run and spawn a work item
* before the timers have been canceled, wait for that work item to
* complete and then cancel all of the timers set up by it. If
* dbs_timer_handler() runs again at that point, it will see the
* positive value of skip_work and won't spawn any more work items.
*/
cancel_work_sync
(
&
shared
->
work
);
gov_cancel_timers
(
shared
->
policy
);
atomic_set
(
&
shared
->
skip_work
,
0
);
}
}
EXPORT_SYMBOL_GPL
(
gov_cancel_work
);
/* Will return if we need to evaluate cpu load again or not */
static
void
gov_cancel_work
(
struct
cpufreq_policy
*
policy
)
static
bool
need_load_eval
(
struct
cpu_common_dbs_info
*
shared
,
unsigned
int
sampling_rate
)
{
{
if
(
policy_is_shared
(
shared
->
policy
))
{
struct
policy_dbs_info
*
policy_dbs
=
policy
->
governor_data
;
ktime_t
time_now
=
ktime_get
();
s64
delta_us
=
ktime_us_delta
(
time_now
,
shared
->
time_stamp
);
/* Do nothing if we recently have sampled */
if
(
delta_us
<
(
s64
)(
sampling_rate
/
2
))
return
false
;
else
shared
->
time_stamp
=
time_now
;
}
return
true
;
gov_clear_update_util
(
policy_dbs
->
policy
);
irq_work_sync
(
&
policy_dbs
->
irq_work
);
cancel_work_sync
(
&
policy_dbs
->
work
);
atomic_set
(
&
policy_dbs
->
work_count
,
0
);
policy_dbs
->
work_in_progress
=
false
;
}
}
static
void
dbs_work_handler
(
struct
work_struct
*
work
)
static
void
dbs_work_handler
(
struct
work_struct
*
work
)
{
{
struct
cpu_common_dbs_info
*
shared
=
container_of
(
work
,
struct
struct
policy_dbs_info
*
policy_dbs
;
cpu_common_dbs_info
,
work
);
struct
cpufreq_policy
*
policy
;
struct
cpufreq_policy
*
policy
;
struct
dbs_data
*
dbs_data
;
struct
dbs_governor
*
gov
;
unsigned
int
sampling_rate
,
delay
;
bool
eval_load
;
policy
=
shared
->
policy
;
dbs_data
=
policy
->
governor_data
;
/* Kill all timers */
policy_dbs
=
container_of
(
work
,
struct
policy_dbs_info
,
work
);
gov_cancel_timers
(
policy
);
policy
=
policy_dbs
->
policy
;
gov
=
dbs_governor_of
(
policy
);
if
(
dbs_data
->
cdata
->
governor
==
GOV_CONSERVATIVE
)
{
/*
struct
cs_dbs_tuners
*
cs_tuners
=
dbs_data
->
tuners
;
* Make sure cpufreq_governor_limits() isn't evaluating load or the
* ondemand governor isn't updating the sampling rate in parallel.
sampling_rate
=
cs_tuners
->
sampling_rate
;
*/
}
else
{
mutex_lock
(
&
policy_dbs
->
timer_mutex
);
struct
od_dbs_tuners
*
od_tuners
=
dbs_data
->
tuners
;
gov_update_sample_delay
(
policy_dbs
,
gov
->
gov_dbs_timer
(
policy
));
mutex_unlock
(
&
policy_dbs
->
timer_mutex
);
sampling_rate
=
od_tuners
->
sampling_rate
;
}
eval_load
=
need_load_eval
(
shared
,
sampling_rate
);
/* Allow the utilization update handler to queue up more work. */
atomic_set
(
&
policy_dbs
->
work_count
,
0
);
/*
/*
* Make sure cpufreq_governor_limits() isn't evaluating load in
* If the update below is reordered with respect to the sample delay
* parallel.
* modification, the utilization update handler may end up using a stale
* sample delay value.
*/
*/
mutex_lock
(
&
shared
->
timer_mutex
);
smp_wmb
(
);
delay
=
dbs_data
->
cdata
->
gov_dbs_timer
(
policy
,
eval_load
)
;
policy_dbs
->
work_in_progress
=
false
;
mutex_unlock
(
&
shared
->
timer_mutex
);
}
atomic_dec
(
&
shared
->
skip_work
);
static
void
dbs_irq_work
(
struct
irq_work
*
irq_work
)
{
struct
policy_dbs_info
*
policy_dbs
;
gov_add_timers
(
policy
,
delay
);
policy_dbs
=
container_of
(
irq_work
,
struct
policy_dbs_info
,
irq_work
);
schedule_work
(
&
policy_dbs
->
work
);
}
}
static
void
dbs_timer_handler
(
unsigned
long
data
)
static
void
dbs_update_util_handler
(
struct
update_util_data
*
data
,
u64
time
,
unsigned
long
util
,
unsigned
long
max
)
{
{
struct
cpu_dbs_info
*
cdbs
=
(
struct
cpu_dbs_info
*
)
data
;
struct
cpu_dbs_info
*
cdbs
=
container_of
(
data
,
struct
cpu_dbs_info
,
update_util
);
struct
cpu_common_dbs_info
*
shared
=
cdbs
->
shared
;
struct
policy_dbs_info
*
policy_dbs
=
cdbs
->
policy_dbs
;
u64
delta_ns
,
lst
;
/*
/*
* Timer handler may not be allowed to queue the work at the moment,
* The work may not be allowed to be queued up right now.
* because:
* Possible reasons:
* - Another timer handler has done that
* - Work has already been queued up or is in progress.
* - We are stopping the governor
* - It is too early (too little time from the previous sample).
* - Or we are updating the sampling rate of the ondemand governor
*/
*/
if
(
atomic_inc_return
(
&
shared
->
skip_work
)
>
1
)
if
(
policy_dbs
->
work_in_progress
)
atomic_dec
(
&
shared
->
skip_work
);
return
;
else
queue_work
(
system_wq
,
&
shared
->
work
);
}
static
void
set_sampling_rate
(
struct
dbs_data
*
dbs_data
,
/*
unsigned
int
sampling_rate
)
* If the reads below are reordered before the check above, the value
{
* of sample_delay_ns used in the computation may be stale.
if
(
dbs_data
->
cdata
->
governor
==
GOV_CONSERVATIVE
)
{
*/
struct
cs_dbs_tuners
*
cs_tuners
=
dbs_data
->
tuners
;
smp_rmb
();
cs_tuners
->
sampling_rate
=
sampling_rate
;
lst
=
READ_ONCE
(
policy_dbs
->
last_sample_time
);
}
else
{
delta_ns
=
time
-
lst
;
struct
od_dbs_tuners
*
od_tuners
=
dbs_data
->
tuners
;
if
((
s64
)
delta_ns
<
policy_dbs
->
sample_delay_ns
)
od_tuners
->
sampling_rate
=
sampling_rate
;
return
;
/*
* If the policy is not shared, the irq_work may be queued up right away
* at this point. Otherwise, we need to ensure that only one of the
* CPUs sharing the policy will do that.
*/
if
(
policy_dbs
->
is_shared
)
{
if
(
!
atomic_add_unless
(
&
policy_dbs
->
work_count
,
1
,
1
))
return
;
/*
* If another CPU updated last_sample_time in the meantime, we
* shouldn't be here, so clear the work counter and bail out.
*/
if
(
unlikely
(
lst
!=
READ_ONCE
(
policy_dbs
->
last_sample_time
)))
{
atomic_set
(
&
policy_dbs
->
work_count
,
0
);
return
;
}
}
}
policy_dbs
->
last_sample_time
=
time
;
policy_dbs
->
work_in_progress
=
true
;
irq_work_queue
(
&
policy_dbs
->
irq_work
);
}
}
static
int
alloc_common
_dbs_info
(
struct
cpufreq_policy
*
policy
,
static
struct
policy_dbs_info
*
alloc_policy
_dbs_info
(
struct
cpufreq_policy
*
policy
,
struct
common_dbs_data
*
cdata
)
struct
dbs_governor
*
gov
)
{
{
struct
cpu_common_dbs_info
*
shared
;
struct
policy_dbs_info
*
policy_dbs
;
int
j
;
int
j
;
/* Allocate memory for
the common information for policy->cpus
*/
/* Allocate memory for
per-policy governor data.
*/
shared
=
kzalloc
(
sizeof
(
*
shared
),
GFP_KERNEL
);
policy_dbs
=
gov
->
alloc
(
);
if
(
!
shared
)
if
(
!
policy_dbs
)
return
-
ENOMEM
;
return
NULL
;
/* Set shared for all CPUs, online+offline */
policy_dbs
->
policy
=
policy
;
for_each_cpu
(
j
,
policy
->
related_cpus
)
mutex_init
(
&
policy_dbs
->
timer_mutex
);
cdata
->
get_cpu_cdbs
(
j
)
->
shared
=
shared
;
atomic_set
(
&
policy_dbs
->
work_count
,
0
);
init_irq_work
(
&
policy_dbs
->
irq_work
,
dbs_irq_work
);
INIT_WORK
(
&
policy_dbs
->
work
,
dbs_work_handler
);
mutex_init
(
&
shared
->
timer_mutex
);
/* Set policy_dbs for all CPUs, online+offline */
atomic_set
(
&
shared
->
skip_work
,
0
);
for_each_cpu
(
j
,
policy
->
related_cpus
)
{
INIT_WORK
(
&
shared
->
work
,
dbs_work_handler
);
struct
cpu_dbs_info
*
j_cdbs
=
&
per_cpu
(
cpu_dbs
,
j
);
return
0
;
j_cdbs
->
policy_dbs
=
policy_dbs
;
j_cdbs
->
update_util
.
func
=
dbs_update_util_handler
;
}
return
policy_dbs
;
}
}
static
void
free_
common_dbs_info
(
struct
cpufreq_policy
*
policy
,
static
void
free_
policy_dbs_info
(
struct
policy_dbs_info
*
policy_dbs
,
struct
common_dbs_data
*
cdata
)
struct
dbs_governor
*
gov
)
{
{
struct
cpu_dbs_info
*
cdbs
=
cdata
->
get_cpu_cdbs
(
policy
->
cpu
);
struct
cpu_common_dbs_info
*
shared
=
cdbs
->
shared
;
int
j
;
int
j
;
mutex_destroy
(
&
shared
->
timer_mutex
);
mutex_destroy
(
&
policy_dbs
->
timer_mutex
);
for_each_cpu
(
j
,
policy
->
cpus
)
for_each_cpu
(
j
,
policy
_dbs
->
policy
->
related_cpus
)
{
cdata
->
get_cpu_cdbs
(
j
)
->
shared
=
NULL
;
struct
cpu_dbs_info
*
j_cdbs
=
&
per_cpu
(
cpu_dbs
,
j
)
;
kfree
(
shared
);
j_cdbs
->
policy_dbs
=
NULL
;
j_cdbs
->
update_util
.
func
=
NULL
;
}
gov
->
free
(
policy_dbs
);
}
}
static
int
cpufreq_governor_init
(
struct
cpufreq_policy
*
policy
,
static
int
cpufreq_governor_init
(
struct
cpufreq_policy
*
policy
)
struct
dbs_data
*
dbs_data
,
struct
common_dbs_data
*
cdata
)
{
{
struct
dbs_governor
*
gov
=
dbs_governor_of
(
policy
);
struct
dbs_data
*
dbs_data
;
struct
policy_dbs_info
*
policy_dbs
;
unsigned
int
latency
;
unsigned
int
latency
;
int
ret
;
int
ret
=
0
;
/* State should be equivalent to EXIT */
/* State should be equivalent to EXIT */
if
(
policy
->
governor_data
)
if
(
policy
->
governor_data
)
return
-
EBUSY
;
return
-
EBUSY
;
if
(
dbs_data
)
{
policy_dbs
=
alloc_policy_dbs_info
(
policy
,
gov
);
if
(
WARN_ON
(
have_governor_per_policy
())
)
if
(
!
policy_dbs
)
return
-
EINVAL
;
return
-
ENOMEM
;
ret
=
alloc_common_dbs_info
(
policy
,
cdata
);
/* Protect gov->gdbs_data against concurrent updates. */
if
(
ret
)
mutex_lock
(
&
gov_dbs_data_mutex
);
return
ret
;
dbs_data
=
gov
->
gdbs_data
;
if
(
dbs_data
)
{
if
(
WARN_ON
(
have_governor_per_policy
()))
{
ret
=
-
EINVAL
;
goto
free_policy_dbs_info
;
}
policy_dbs
->
dbs_data
=
dbs_data
;
policy
->
governor_data
=
policy_dbs
;
mutex_lock
(
&
dbs_data
->
mutex
);
dbs_data
->
usage_count
++
;
dbs_data
->
usage_count
++
;
policy
->
governor_data
=
dbs_data
;
list_add
(
&
policy_dbs
->
list
,
&
dbs_data
->
policy_dbs_list
);
return
0
;
mutex_unlock
(
&
dbs_data
->
mutex
);
goto
out
;
}
}
dbs_data
=
kzalloc
(
sizeof
(
*
dbs_data
),
GFP_KERNEL
);
dbs_data
=
kzalloc
(
sizeof
(
*
dbs_data
),
GFP_KERNEL
);
if
(
!
dbs_data
)
if
(
!
dbs_data
)
{
return
-
ENOMEM
;
ret
=
-
ENOMEM
;
goto
free_policy_dbs_info
;
ret
=
alloc_common_dbs_info
(
policy
,
cdata
);
}
if
(
ret
)
goto
free_dbs_data
;
dbs_data
->
cdata
=
cdata
;
INIT_LIST_HEAD
(
&
dbs_data
->
policy_dbs_list
)
;
dbs_data
->
usage_count
=
1
;
mutex_init
(
&
dbs_data
->
mutex
)
;
ret
=
cdata
->
init
(
dbs_data
,
!
policy
->
governor
->
initialized
);
ret
=
gov
->
init
(
dbs_data
,
!
policy
->
governor
->
initialized
);
if
(
ret
)
if
(
ret
)
goto
free_
common
_dbs_info
;
goto
free_
policy
_dbs_info
;
/* policy latency is in ns. Convert it to us first */
/* policy latency is in ns. Convert it to us first */
latency
=
policy
->
cpuinfo
.
transition_latency
/
1000
;
latency
=
policy
->
cpuinfo
.
transition_latency
/
1000
;
...
@@ -381,216 +481,156 @@ static int cpufreq_governor_init(struct cpufreq_policy *policy,
...
@@ -381,216 +481,156 @@ static int cpufreq_governor_init(struct cpufreq_policy *policy,
/* Bring kernel and HW constraints together */
/* Bring kernel and HW constraints together */
dbs_data
->
min_sampling_rate
=
max
(
dbs_data
->
min_sampling_rate
,
dbs_data
->
min_sampling_rate
=
max
(
dbs_data
->
min_sampling_rate
,
MIN_LATENCY_MULTIPLIER
*
latency
);
MIN_LATENCY_MULTIPLIER
*
latency
);
set_sampling_rate
(
dbs_data
,
max
(
dbs_data
->
min_sampling_rate
,
dbs_data
->
sampling_rate
=
max
(
dbs_data
->
min_sampling_rate
,
latency
*
LATENCY_MULTIPLIER
)
);
LATENCY_MULTIPLIER
*
latency
);
if
(
!
have_governor_per_policy
())
if
(
!
have_governor_per_policy
())
cdata
->
gdbs_data
=
dbs_data
;
gov
->
gdbs_data
=
dbs_data
;
policy
->
governor_data
=
dbs_data
;
policy
->
governor_data
=
policy_dbs
;
ret
=
sysfs_create_group
(
get_governor_parent_kobj
(
policy
),
policy_dbs
->
dbs_data
=
dbs_data
;
get_sysfs_attr
(
dbs_data
));
dbs_data
->
usage_count
=
1
;
if
(
ret
)
list_add
(
&
policy_dbs
->
list
,
&
dbs_data
->
policy_dbs_list
);
goto
reset_gdbs_data
;
return
0
;
gov
->
kobj_type
.
sysfs_ops
=
&
governor_sysfs_ops
;
ret
=
kobject_init_and_add
(
&
dbs_data
->
kobj
,
&
gov
->
kobj_type
,
get_governor_parent_kobj
(
policy
),
"%s"
,
gov
->
gov
.
name
);
if
(
!
ret
)
goto
out
;
/* Failure, so roll back. */
pr_err
(
"cpufreq: Governor initialization failed (dbs_data kobject init error %d)
\n
"
,
ret
);
reset_gdbs_data:
policy
->
governor_data
=
NULL
;
policy
->
governor_data
=
NULL
;
if
(
!
have_governor_per_policy
())
if
(
!
have_governor_per_policy
())
cdata
->
gdbs_data
=
NULL
;
gov
->
gdbs_data
=
NULL
;
cdata
->
exit
(
dbs_data
,
!
policy
->
governor
->
initialized
);
gov
->
exit
(
dbs_data
,
!
policy
->
governor
->
initialized
);
free_common_dbs_info:
free_common_dbs_info
(
policy
,
cdata
);
free_dbs_data:
kfree
(
dbs_data
);
kfree
(
dbs_data
);
free_policy_dbs_info:
free_policy_dbs_info
(
policy_dbs
,
gov
);
out:
mutex_unlock
(
&
gov_dbs_data_mutex
);
return
ret
;
return
ret
;
}
}
static
int
cpufreq_governor_exit
(
struct
cpufreq_policy
*
policy
,
static
int
cpufreq_governor_exit
(
struct
cpufreq_policy
*
policy
)
struct
dbs_data
*
dbs_data
)
{
{
struct
common_dbs_data
*
cdata
=
dbs_data
->
cdata
;
struct
dbs_governor
*
gov
=
dbs_governor_of
(
policy
);
struct
cpu_dbs_info
*
cdbs
=
cdata
->
get_cpu_cdbs
(
policy
->
cpu
);
struct
policy_dbs_info
*
policy_dbs
=
policy
->
governor_data
;
struct
dbs_data
*
dbs_data
=
policy_dbs
->
dbs_data
;
int
count
;
/* State should be equivalent to INIT */
/* Protect gov->gdbs_data against concurrent updates. */
if
(
!
cdbs
->
shared
||
cdbs
->
shared
->
policy
)
mutex_lock
(
&
gov_dbs_data_mutex
);
return
-
EBUSY
;
mutex_lock
(
&
dbs_data
->
mutex
);
list_del
(
&
policy_dbs
->
list
);
count
=
--
dbs_data
->
usage_count
;
mutex_unlock
(
&
dbs_data
->
mutex
);
if
(
!--
dbs_data
->
usage_count
)
{
if
(
!
count
)
{
sysfs_remove_group
(
get_governor_parent_kobj
(
policy
),
kobject_put
(
&
dbs_data
->
kobj
);
get_sysfs_attr
(
dbs_data
));
policy
->
governor_data
=
NULL
;
policy
->
governor_data
=
NULL
;
if
(
!
have_governor_per_policy
())
if
(
!
have_governor_per_policy
())
cdata
->
gdbs_data
=
NULL
;
gov
->
gdbs_data
=
NULL
;
cdata
->
exit
(
dbs_data
,
policy
->
governor
->
initialized
==
1
);
gov
->
exit
(
dbs_data
,
policy
->
governor
->
initialized
==
1
);
mutex_destroy
(
&
dbs_data
->
mutex
);
kfree
(
dbs_data
);
kfree
(
dbs_data
);
}
else
{
}
else
{
policy
->
governor_data
=
NULL
;
policy
->
governor_data
=
NULL
;
}
}
free_common_dbs_info
(
policy
,
cdata
);
free_policy_dbs_info
(
policy_dbs
,
gov
);
mutex_unlock
(
&
gov_dbs_data_mutex
);
return
0
;
return
0
;
}
}
static
int
cpufreq_governor_start
(
struct
cpufreq_policy
*
policy
,
static
int
cpufreq_governor_start
(
struct
cpufreq_policy
*
policy
)
struct
dbs_data
*
dbs_data
)
{
{
struct
common_dbs_data
*
cdata
=
dbs_data
->
cdata
;
struct
dbs_governor
*
gov
=
dbs_governor_of
(
policy
)
;
unsigned
int
sampling_rate
,
ignore_nice
,
j
,
cpu
=
policy
->
cpu
;
struct
policy_dbs_info
*
policy_dbs
=
policy
->
governor_data
;
struct
cpu_dbs_info
*
cdbs
=
cdata
->
get_cpu_cdbs
(
cpu
)
;
struct
dbs_data
*
dbs_data
=
policy_dbs
->
dbs_data
;
struct
cpu_common_dbs_info
*
shared
=
cdbs
->
shared
;
unsigned
int
sampling_rate
,
ignore_nice
,
j
;
int
io_busy
=
0
;
unsigned
int
io_busy
;
if
(
!
policy
->
cur
)
if
(
!
policy
->
cur
)
return
-
EINVAL
;
return
-
EINVAL
;
/* State should be equivalent to INIT */
policy_dbs
->
is_shared
=
policy_is_shared
(
policy
);
if
(
!
shared
||
shared
->
policy
)
policy_dbs
->
rate_mult
=
1
;
return
-
EBUSY
;
if
(
cdata
->
governor
==
GOV_CONSERVATIVE
)
{
sampling_rate
=
dbs_data
->
sampling_rate
;
struct
cs_dbs_tuners
*
cs_tuners
=
dbs_data
->
tuners
;
ignore_nice
=
dbs_data
->
ignore_nice_load
;
io_busy
=
dbs_data
->
io_is_busy
;
sampling_rate
=
cs_tuners
->
sampling_rate
;
ignore_nice
=
cs_tuners
->
ignore_nice_load
;
}
else
{
struct
od_dbs_tuners
*
od_tuners
=
dbs_data
->
tuners
;
sampling_rate
=
od_tuners
->
sampling_rate
;
ignore_nice
=
od_tuners
->
ignore_nice_load
;
io_busy
=
od_tuners
->
io_is_busy
;
}
shared
->
policy
=
policy
;
shared
->
time_stamp
=
ktime_get
();
for_each_cpu
(
j
,
policy
->
cpus
)
{
for_each_cpu
(
j
,
policy
->
cpus
)
{
struct
cpu_dbs_info
*
j_cdbs
=
cdata
->
get_cpu_cdbs
(
j
);
struct
cpu_dbs_info
*
j_cdbs
=
&
per_cpu
(
cpu_dbs
,
j
);
unsigned
int
prev_load
;
unsigned
int
prev_load
;
j_cdbs
->
prev_cpu_idle
=
j_cdbs
->
prev_cpu_idle
=
get_cpu_idle_time
(
j
,
&
j_cdbs
->
prev_cpu_wall
,
io_busy
);
get_cpu_idle_time
(
j
,
&
j_cdbs
->
prev_cpu_wall
,
io_busy
);
prev_load
=
(
unsigned
int
)(
j_cdbs
->
prev_cpu_wall
-
prev_load
=
j_cdbs
->
prev_cpu_wall
-
j_cdbs
->
prev_cpu_idle
;
j_cdbs
->
prev_cpu_idle
);
j_cdbs
->
prev_load
=
100
*
prev_load
/
(
unsigned
int
)
j_cdbs
->
prev_cpu_wall
;
j_cdbs
->
prev_load
=
100
*
prev_load
/
(
unsigned
int
)
j_cdbs
->
prev_cpu_wall
;
if
(
ignore_nice
)
if
(
ignore_nice
)
j_cdbs
->
prev_cpu_nice
=
kcpustat_cpu
(
j
).
cpustat
[
CPUTIME_NICE
];
j_cdbs
->
prev_cpu_nice
=
kcpustat_cpu
(
j
).
cpustat
[
CPUTIME_NICE
];
__setup_timer
(
&
j_cdbs
->
timer
,
dbs_timer_handler
,
(
unsigned
long
)
j_cdbs
,
TIMER_DEFERRABLE
|
TIMER_IRQSAFE
);
}
}
if
(
cdata
->
governor
==
GOV_CONSERVATIVE
)
{
gov
->
start
(
policy
);
struct
cs_cpu_dbs_info_s
*
cs_dbs_info
=
cdata
->
get_cpu_dbs_info_s
(
cpu
);
cs_dbs_info
->
down_skip
=
0
;
cs_dbs_info
->
requested_freq
=
policy
->
cur
;
}
else
{
struct
od_ops
*
od_ops
=
cdata
->
gov_ops
;
struct
od_cpu_dbs_info_s
*
od_dbs_info
=
cdata
->
get_cpu_dbs_info_s
(
cpu
);
od_dbs_info
->
rate_mult
=
1
;
od_dbs_info
->
sample_type
=
OD_NORMAL_SAMPLE
;
od_ops
->
powersave_bias_init_cpu
(
cpu
);
}
gov_
add_timers
(
policy
,
delay_for_sampling_rate
(
sampling_rate
)
);
gov_
set_update_util
(
policy_dbs
,
sampling_rate
);
return
0
;
return
0
;
}
}
static
int
cpufreq_governor_stop
(
struct
cpufreq_policy
*
policy
,
static
int
cpufreq_governor_stop
(
struct
cpufreq_policy
*
policy
)
struct
dbs_data
*
dbs_data
)
{
{
struct
cpu_dbs_info
*
cdbs
=
dbs_data
->
cdata
->
get_cpu_cdbs
(
policy
->
cpu
);
gov_cancel_work
(
policy
);
struct
cpu_common_dbs_info
*
shared
=
cdbs
->
shared
;
/* State should be equivalent to START */
if
(
!
shared
||
!
shared
->
policy
)
return
-
EBUSY
;
gov_cancel_work
(
shared
);
shared
->
policy
=
NULL
;
return
0
;
return
0
;
}
}
static
int
cpufreq_governor_limits
(
struct
cpufreq_policy
*
policy
,
static
int
cpufreq_governor_limits
(
struct
cpufreq_policy
*
policy
)
struct
dbs_data
*
dbs_data
)
{
{
struct
common_dbs_data
*
cdata
=
dbs_data
->
cdata
;
struct
policy_dbs_info
*
policy_dbs
=
policy
->
governor_data
;
unsigned
int
cpu
=
policy
->
cpu
;
struct
cpu_dbs_info
*
cdbs
=
cdata
->
get_cpu_cdbs
(
cpu
);
/* State should be equivalent to START */
mutex_lock
(
&
policy_dbs
->
timer_mutex
);
if
(
!
cdbs
->
shared
||
!
cdbs
->
shared
->
policy
)
return
-
EBUSY
;
if
(
policy
->
max
<
policy
->
cur
)
__cpufreq_driver_target
(
policy
,
policy
->
max
,
CPUFREQ_RELATION_H
);
else
if
(
policy
->
min
>
policy
->
cur
)
__cpufreq_driver_target
(
policy
,
policy
->
min
,
CPUFREQ_RELATION_L
);
gov_update_sample_delay
(
policy_dbs
,
0
);
mutex_lock
(
&
cdbs
->
shared
->
timer_mutex
);
mutex_unlock
(
&
policy_dbs
->
timer_mutex
);
if
(
policy
->
max
<
cdbs
->
shared
->
policy
->
cur
)
__cpufreq_driver_target
(
cdbs
->
shared
->
policy
,
policy
->
max
,
CPUFREQ_RELATION_H
);
else
if
(
policy
->
min
>
cdbs
->
shared
->
policy
->
cur
)
__cpufreq_driver_target
(
cdbs
->
shared
->
policy
,
policy
->
min
,
CPUFREQ_RELATION_L
);
dbs_check_cpu
(
dbs_data
,
cpu
);
mutex_unlock
(
&
cdbs
->
shared
->
timer_mutex
);
return
0
;
return
0
;
}
}
int
cpufreq_governor_dbs
(
struct
cpufreq_policy
*
policy
,
int
cpufreq_governor_dbs
(
struct
cpufreq_policy
*
policy
,
unsigned
int
event
)
struct
common_dbs_data
*
cdata
,
unsigned
int
event
)
{
{
struct
dbs_data
*
dbs_data
;
if
(
event
==
CPUFREQ_GOV_POLICY_INIT
)
{
int
ret
;
return
cpufreq_governor_init
(
policy
);
}
else
if
(
policy
->
governor_data
)
{
/* Lock governor to block concurrent initialization of governor */
switch
(
event
)
{
mutex_lock
(
&
cdata
->
mutex
);
case
CPUFREQ_GOV_POLICY_EXIT
:
return
cpufreq_governor_exit
(
policy
);
if
(
have_governor_per_policy
())
case
CPUFREQ_GOV_START
:
dbs_data
=
policy
->
governor_data
;
return
cpufreq_governor_start
(
policy
);
else
case
CPUFREQ_GOV_STOP
:
dbs_data
=
cdata
->
gdbs_data
;
return
cpufreq_governor_stop
(
policy
);
case
CPUFREQ_GOV_LIMITS
:
if
(
!
dbs_data
&&
(
event
!=
CPUFREQ_GOV_POLICY_INIT
))
{
return
cpufreq_governor_limits
(
policy
);
ret
=
-
EINVAL
;
}
goto
unlock
;
}
switch
(
event
)
{
case
CPUFREQ_GOV_POLICY_INIT
:
ret
=
cpufreq_governor_init
(
policy
,
dbs_data
,
cdata
);
break
;
case
CPUFREQ_GOV_POLICY_EXIT
:
ret
=
cpufreq_governor_exit
(
policy
,
dbs_data
);
break
;
case
CPUFREQ_GOV_START
:
ret
=
cpufreq_governor_start
(
policy
,
dbs_data
);
break
;
case
CPUFREQ_GOV_STOP
:
ret
=
cpufreq_governor_stop
(
policy
,
dbs_data
);
break
;
case
CPUFREQ_GOV_LIMITS
:
ret
=
cpufreq_governor_limits
(
policy
,
dbs_data
);
break
;
default:
ret
=
-
EINVAL
;
}
}
return
-
EINVAL
;
unlock:
mutex_unlock
(
&
cdata
->
mutex
);
return
ret
;
}
}
EXPORT_SYMBOL_GPL
(
cpufreq_governor_dbs
);
EXPORT_SYMBOL_GPL
(
cpufreq_governor_dbs
);
drivers/cpufreq/cpufreq_governor.h
浏览文件 @
a5acbfbd
...
@@ -18,6 +18,7 @@
...
@@ -18,6 +18,7 @@
#define _CPUFREQ_GOVERNOR_H
#define _CPUFREQ_GOVERNOR_H
#include <linux/atomic.h>
#include <linux/atomic.h>
#include <linux/irq_work.h>
#include <linux/cpufreq.h>
#include <linux/cpufreq.h>
#include <linux/kernel_stat.h>
#include <linux/kernel_stat.h>
#include <linux/module.h>
#include <linux/module.h>
...
@@ -41,96 +42,68 @@
...
@@ -41,96 +42,68 @@
enum
{
OD_NORMAL_SAMPLE
,
OD_SUB_SAMPLE
};
enum
{
OD_NORMAL_SAMPLE
,
OD_SUB_SAMPLE
};
/*
/*
* Macro for creating governors sysfs routines
* Abbreviations:
*
* dbs: used as a shortform for demand based switching It helps to keep variable
* - gov_sys: One governor instance per whole system
* names smaller, simpler
* - gov_pol: One governor instance per policy
* cdbs: common dbs
* od_*: On-demand governor
* cs_*: Conservative governor
*/
*/
/* Create attributes */
/* Governor demand based switching data (per-policy or global). */
#define gov_sys_attr_ro(_name) \
struct
dbs_data
{
static struct global_attr _name##_gov_sys = \
int
usage_count
;
__ATTR(_name, 0444, show_##_name##_gov_sys, NULL)
void
*
tuners
;
unsigned
int
min_sampling_rate
;
#define gov_sys_attr_rw(_name) \
unsigned
int
ignore_nice_load
;
static struct global_attr _name##_gov_sys = \
unsigned
int
sampling_rate
;
__ATTR(_name, 0644, show_##_name##_gov_sys, store_##_name##_gov_sys)
unsigned
int
sampling_down_factor
;
unsigned
int
up_threshold
;
#define gov_pol_attr_ro(_name) \
unsigned
int
io_is_busy
;
static struct freq_attr _name##_gov_pol = \
__ATTR(_name, 0444, show_##_name##_gov_pol, NULL)
#define gov_pol_attr_rw(_name) \
static struct freq_attr _name##_gov_pol = \
__ATTR(_name, 0644, show_##_name##_gov_pol, store_##_name##_gov_pol)
#define gov_sys_pol_attr_rw(_name) \
struct
kobject
kobj
;
gov_sys_attr_rw(_name); \
struct
list_head
policy_dbs_list
;
gov_pol_attr_rw(_name)
/*
* Protect concurrent updates to governor tunables from sysfs,
* policy_dbs_list and usage_count.
*/
struct
mutex
mutex
;
};
#define gov_sys_pol_attr_ro(_name) \
/* Governor's specific attributes */
gov_sys_attr_ro(_name); \
struct
dbs_data
;
gov_pol_attr_ro(_name)
struct
governor_attr
{
struct
attribute
attr
;
ssize_t
(
*
show
)(
struct
dbs_data
*
dbs_data
,
char
*
buf
);
ssize_t
(
*
store
)(
struct
dbs_data
*
dbs_data
,
const
char
*
buf
,
size_t
count
);
};
/* Create show/store routines */
#define gov_show_one(_gov, file_name) \
#define show_one(_gov, file_name) \
static ssize_t show_##file_name \
static ssize_t show_##file_name##_gov_sys \
(struct dbs_data *dbs_data, char *buf) \
(struct kobject *kobj, struct attribute *attr, char *buf) \
{ \
{ \
struct _gov##_dbs_tuners *tuners = _gov##_dbs_cdata.gdbs_data->tuners; \
return sprintf(buf, "%u\n", tuners->file_name); \
} \
\
static ssize_t show_##file_name##_gov_pol \
(struct cpufreq_policy *policy, char *buf) \
{ \
struct dbs_data *dbs_data = policy->governor_data; \
struct _gov##_dbs_tuners *tuners = dbs_data->tuners; \
struct _gov##_dbs_tuners *tuners = dbs_data->tuners; \
return sprintf(buf, "%u\n", tuners->file_name); \
return sprintf(buf, "%u\n", tuners->file_name); \
}
}
#define store_one(_gov, file_name) \
#define gov_show_one_common(file_name) \
static ssize_t store_##file_name##_gov_sys \
static ssize_t show_##file_name \
(struct kobject *kobj, struct attribute *attr, const char *buf, size_t count) \
(struct dbs_data *dbs_data, char *buf) \
{ \
struct dbs_data *dbs_data = _gov##_dbs_cdata.gdbs_data; \
return store_##file_name(dbs_data, buf, count); \
} \
\
static ssize_t store_##file_name##_gov_pol \
(struct cpufreq_policy *policy, const char *buf, size_t count) \
{ \
{ \
struct dbs_data *dbs_data = policy->governor_data; \
return sprintf(buf, "%u\n", dbs_data->file_name); \
return store_##file_name(dbs_data, buf, count); \
}
}
#define
show_store_one(_gov, file_name)
\
#define
gov_attr_ro(_name)
\
s
how_one(_gov, file_name);
\
s
tatic struct governor_attr _name =
\
store_one(_gov, file_name
)
__ATTR(_name, 0444, show_##_name, NULL
)
/* create helper routines */
#define gov_attr_rw(_name) \
#define define_get_cpu_dbs_routines(_dbs_info) \
static struct governor_attr _name = \
static struct cpu_dbs_info *get_cpu_cdbs(int cpu) \
__ATTR(_name, 0644, show_##_name, store_##_name)
{ \
return &per_cpu(_dbs_info, cpu).cdbs; \
} \
\
static void *get_cpu_dbs_info_s(int cpu) \
{ \
return &per_cpu(_dbs_info, cpu); \
}
/*
* Abbreviations:
* dbs: used as a shortform for demand based switching It helps to keep variable
* names smaller, simpler
* cdbs: common dbs
* od_*: On-demand governor
* cs_*: Conservative governor
*/
/* Common to all CPUs of a policy */
/* Common to all CPUs of a policy */
struct
cpu_common
_dbs_info
{
struct
policy
_dbs_info
{
struct
cpufreq_policy
*
policy
;
struct
cpufreq_policy
*
policy
;
/*
/*
* Per policy mutex that serializes load evaluation from limit-change
* Per policy mutex that serializes load evaluation from limit-change
...
@@ -138,11 +111,27 @@ struct cpu_common_dbs_info {
...
@@ -138,11 +111,27 @@ struct cpu_common_dbs_info {
*/
*/
struct
mutex
timer_mutex
;
struct
mutex
timer_mutex
;
ktime_t
time_stamp
;
u64
last_sample_time
;
atomic_t
skip_work
;
s64
sample_delay_ns
;
atomic_t
work_count
;
struct
irq_work
irq_work
;
struct
work_struct
work
;
struct
work_struct
work
;
/* dbs_data may be shared between multiple policy objects */
struct
dbs_data
*
dbs_data
;
struct
list_head
list
;
/* Multiplier for increasing sample delay temporarily. */
unsigned
int
rate_mult
;
/* Status indicators */
bool
is_shared
;
/* This object is used by multiple CPUs */
bool
work_in_progress
;
/* Work is being queued up or in progress */
};
};
static
inline
void
gov_update_sample_delay
(
struct
policy_dbs_info
*
policy_dbs
,
unsigned
int
delay_us
)
{
policy_dbs
->
sample_delay_ns
=
delay_us
*
NSEC_PER_USEC
;
}
/* Per cpu structures */
/* Per cpu structures */
struct
cpu_dbs_info
{
struct
cpu_dbs_info
{
u64
prev_cpu_idle
;
u64
prev_cpu_idle
;
...
@@ -155,54 +144,14 @@ struct cpu_dbs_info {
...
@@ -155,54 +144,14 @@ struct cpu_dbs_info {
* wake-up from idle.
* wake-up from idle.
*/
*/
unsigned
int
prev_load
;
unsigned
int
prev_load
;
struct
timer_list
timer
;
struct
update_util_data
update_util
;
struct
cpu_common_dbs_info
*
shared
;
struct
policy_dbs_info
*
policy_dbs
;
};
struct
od_cpu_dbs_info_s
{
struct
cpu_dbs_info
cdbs
;
struct
cpufreq_frequency_table
*
freq_table
;
unsigned
int
freq_lo
;
unsigned
int
freq_lo_jiffies
;
unsigned
int
freq_hi_jiffies
;
unsigned
int
rate_mult
;
unsigned
int
sample_type
:
1
;
};
struct
cs_cpu_dbs_info_s
{
struct
cpu_dbs_info
cdbs
;
unsigned
int
down_skip
;
unsigned
int
requested_freq
;
};
/* Per policy Governors sysfs tunables */
struct
od_dbs_tuners
{
unsigned
int
ignore_nice_load
;
unsigned
int
sampling_rate
;
unsigned
int
sampling_down_factor
;
unsigned
int
up_threshold
;
unsigned
int
powersave_bias
;
unsigned
int
io_is_busy
;
};
struct
cs_dbs_tuners
{
unsigned
int
ignore_nice_load
;
unsigned
int
sampling_rate
;
unsigned
int
sampling_down_factor
;
unsigned
int
up_threshold
;
unsigned
int
down_threshold
;
unsigned
int
freq_step
;
};
};
/* Common Governor data across policies */
/* Common Governor data across policies */
struct
dbs_data
;
struct
dbs_governor
{
struct
common_dbs_data
{
struct
cpufreq_governor
gov
;
/* Common across governors */
struct
kobj_type
kobj_type
;
#define GOV_ONDEMAND 0
#define GOV_CONSERVATIVE 1
int
governor
;
struct
attribute_group
*
attr_group_gov_sys
;
/* one governor - system */
struct
attribute_group
*
attr_group_gov_pol
;
/* one governor - policy */
/*
/*
* Common data for platforms that don't set
* Common data for platforms that don't set
...
@@ -210,74 +159,32 @@ struct common_dbs_data {
...
@@ -210,74 +159,32 @@ struct common_dbs_data {
*/
*/
struct
dbs_data
*
gdbs_data
;
struct
dbs_data
*
gdbs_data
;
struct
cpu_dbs_info
*
(
*
get_cpu_cdbs
)(
int
cpu
);
unsigned
int
(
*
gov_dbs_timer
)(
struct
cpufreq_policy
*
policy
);
void
*
(
*
get_cpu_dbs_info_s
)(
int
cpu
);
struct
policy_dbs_info
*
(
*
alloc
)(
void
);
unsigned
int
(
*
gov_dbs_timer
)(
struct
cpufreq_policy
*
policy
,
void
(
*
free
)(
struct
policy_dbs_info
*
policy_dbs
);
bool
modify_all
);
void
(
*
gov_check_cpu
)(
int
cpu
,
unsigned
int
load
);
int
(
*
init
)(
struct
dbs_data
*
dbs_data
,
bool
notify
);
int
(
*
init
)(
struct
dbs_data
*
dbs_data
,
bool
notify
);
void
(
*
exit
)(
struct
dbs_data
*
dbs_data
,
bool
notify
);
void
(
*
exit
)(
struct
dbs_data
*
dbs_data
,
bool
notify
);
void
(
*
start
)(
struct
cpufreq_policy
*
policy
);
/* Governor specific ops, see below */
void
*
gov_ops
;
/*
* Protects governor's data (struct dbs_data and struct common_dbs_data)
*/
struct
mutex
mutex
;
};
};
/* Governor Per policy data */
static
inline
struct
dbs_governor
*
dbs_governor_of
(
struct
cpufreq_policy
*
policy
)
struct
dbs_data
{
{
struct
common_dbs_data
*
cdata
;
return
container_of
(
policy
->
governor
,
struct
dbs_governor
,
gov
);
unsigned
int
min_sampling_rate
;
}
int
usage_count
;
void
*
tuners
;
};
/* Governor specific op
s, will be passed to dbs_data->gov_op
s */
/* Governor specific op
eration
s */
struct
od_ops
{
struct
od_ops
{
void
(
*
powersave_bias_init_cpu
)(
int
cpu
);
unsigned
int
(
*
powersave_bias_target
)(
struct
cpufreq_policy
*
policy
,
unsigned
int
(
*
powersave_bias_target
)(
struct
cpufreq_policy
*
policy
,
unsigned
int
freq_next
,
unsigned
int
relation
);
unsigned
int
freq_next
,
unsigned
int
relation
);
void
(
*
freq_increase
)(
struct
cpufreq_policy
*
policy
,
unsigned
int
freq
);
};
};
static
inline
int
delay_for_sampling_rate
(
unsigned
int
sampling_rate
)
unsigned
int
dbs_update
(
struct
cpufreq_policy
*
policy
);
{
int
cpufreq_governor_dbs
(
struct
cpufreq_policy
*
policy
,
unsigned
int
event
);
int
delay
=
usecs_to_jiffies
(
sampling_rate
);
/* We want all CPUs to do sampling nearly on same jiffy */
if
(
num_online_cpus
()
>
1
)
delay
-=
jiffies
%
delay
;
return
delay
;
}
#define declare_show_sampling_rate_min(_gov) \
static ssize_t show_sampling_rate_min_gov_sys \
(struct kobject *kobj, struct attribute *attr, char *buf) \
{ \
struct dbs_data *dbs_data = _gov##_dbs_cdata.gdbs_data; \
return sprintf(buf, "%u\n", dbs_data->min_sampling_rate); \
} \
\
static ssize_t show_sampling_rate_min_gov_pol \
(struct cpufreq_policy *policy, char *buf) \
{ \
struct dbs_data *dbs_data = policy->governor_data; \
return sprintf(buf, "%u\n", dbs_data->min_sampling_rate); \
}
extern
struct
mutex
cpufreq_governor_lock
;
void
gov_add_timers
(
struct
cpufreq_policy
*
policy
,
unsigned
int
delay
);
void
gov_cancel_work
(
struct
cpu_common_dbs_info
*
shared
);
void
dbs_check_cpu
(
struct
dbs_data
*
dbs_data
,
int
cpu
);
int
cpufreq_governor_dbs
(
struct
cpufreq_policy
*
policy
,
struct
common_dbs_data
*
cdata
,
unsigned
int
event
);
void
od_register_powersave_bias_handler
(
unsigned
int
(
*
f
)
void
od_register_powersave_bias_handler
(
unsigned
int
(
*
f
)
(
struct
cpufreq_policy
*
,
unsigned
int
,
unsigned
int
),
(
struct
cpufreq_policy
*
,
unsigned
int
,
unsigned
int
),
unsigned
int
powersave_bias
);
unsigned
int
powersave_bias
);
void
od_unregister_powersave_bias_handler
(
void
);
void
od_unregister_powersave_bias_handler
(
void
);
ssize_t
store_sampling_rate
(
struct
dbs_data
*
dbs_data
,
const
char
*
buf
,
size_t
count
);
void
gov_update_cpu_data
(
struct
dbs_data
*
dbs_data
);
#endif
/* _CPUFREQ_GOVERNOR_H */
#endif
/* _CPUFREQ_GOVERNOR_H */
drivers/cpufreq/cpufreq_ondemand.c
浏览文件 @
a5acbfbd
...
@@ -16,7 +16,8 @@
...
@@ -16,7 +16,8 @@
#include <linux/percpu-defs.h>
#include <linux/percpu-defs.h>
#include <linux/slab.h>
#include <linux/slab.h>
#include <linux/tick.h>
#include <linux/tick.h>
#include "cpufreq_governor.h"
#include "cpufreq_ondemand.h"
/* On-demand governor macros */
/* On-demand governor macros */
#define DEF_FREQUENCY_UP_THRESHOLD (80)
#define DEF_FREQUENCY_UP_THRESHOLD (80)
...
@@ -27,22 +28,10 @@
...
@@ -27,22 +28,10 @@
#define MIN_FREQUENCY_UP_THRESHOLD (11)
#define MIN_FREQUENCY_UP_THRESHOLD (11)
#define MAX_FREQUENCY_UP_THRESHOLD (100)
#define MAX_FREQUENCY_UP_THRESHOLD (100)
static
DEFINE_PER_CPU
(
struct
od_cpu_dbs_info_s
,
od_cpu_dbs_info
);
static
struct
od_ops
od_ops
;
static
struct
od_ops
od_ops
;
static
struct
cpufreq_governor
cpufreq_gov_ondemand
;
static
unsigned
int
default_powersave_bias
;
static
unsigned
int
default_powersave_bias
;
static
void
ondemand_powersave_bias_init_cpu
(
int
cpu
)
{
struct
od_cpu_dbs_info_s
*
dbs_info
=
&
per_cpu
(
od_cpu_dbs_info
,
cpu
);
dbs_info
->
freq_table
=
cpufreq_frequency_get_table
(
cpu
);
dbs_info
->
freq_lo
=
0
;
}
/*
/*
* Not all CPUs want IO time to be accounted as busy; this depends on how
* Not all CPUs want IO time to be accounted as busy; this depends on how
* efficient idling at a higher frequency/voltage is.
* efficient idling at a higher frequency/voltage is.
...
@@ -68,8 +57,8 @@ static int should_io_be_busy(void)
...
@@ -68,8 +57,8 @@ static int should_io_be_busy(void)
/*
/*
* Find right freq to be set now with powersave_bias on.
* Find right freq to be set now with powersave_bias on.
* Returns the freq_hi to be used right now and will set freq_hi_
jiffie
s,
* Returns the freq_hi to be used right now and will set freq_hi_
delay_u
s,
* freq_lo, and freq_lo_
jiffie
s in percpu area for averaging freqs.
* freq_lo, and freq_lo_
delay_u
s in percpu area for averaging freqs.
*/
*/
static
unsigned
int
generic_powersave_bias_target
(
struct
cpufreq_policy
*
policy
,
static
unsigned
int
generic_powersave_bias_target
(
struct
cpufreq_policy
*
policy
,
unsigned
int
freq_next
,
unsigned
int
relation
)
unsigned
int
freq_next
,
unsigned
int
relation
)
...
@@ -77,15 +66,15 @@ static unsigned int generic_powersave_bias_target(struct cpufreq_policy *policy,
...
@@ -77,15 +66,15 @@ static unsigned int generic_powersave_bias_target(struct cpufreq_policy *policy,
unsigned
int
freq_req
,
freq_reduc
,
freq_avg
;
unsigned
int
freq_req
,
freq_reduc
,
freq_avg
;
unsigned
int
freq_hi
,
freq_lo
;
unsigned
int
freq_hi
,
freq_lo
;
unsigned
int
index
=
0
;
unsigned
int
index
=
0
;
unsigned
int
jiffies_total
,
jiffies_hi
,
jiffies_lo
;
unsigned
int
delay_hi_us
;
struct
od_cpu_dbs_info_s
*
dbs_info
=
&
per_cpu
(
od_cpu_dbs_info
,
struct
policy_dbs_info
*
policy_dbs
=
policy
->
governor_data
;
policy
->
cpu
);
struct
od_policy_dbs_info
*
dbs_info
=
to_dbs_info
(
policy_dbs
);
struct
dbs_data
*
dbs_data
=
policy
->
governor
_data
;
struct
dbs_data
*
dbs_data
=
policy
_dbs
->
dbs
_data
;
struct
od_dbs_tuners
*
od_tuners
=
dbs_data
->
tuners
;
struct
od_dbs_tuners
*
od_tuners
=
dbs_data
->
tuners
;
if
(
!
dbs_info
->
freq_table
)
{
if
(
!
dbs_info
->
freq_table
)
{
dbs_info
->
freq_lo
=
0
;
dbs_info
->
freq_lo
=
0
;
dbs_info
->
freq_lo_
jiffie
s
=
0
;
dbs_info
->
freq_lo_
delay_u
s
=
0
;
return
freq_next
;
return
freq_next
;
}
}
...
@@ -108,31 +97,30 @@ static unsigned int generic_powersave_bias_target(struct cpufreq_policy *policy,
...
@@ -108,31 +97,30 @@ static unsigned int generic_powersave_bias_target(struct cpufreq_policy *policy,
/* Find out how long we have to be in hi and lo freqs */
/* Find out how long we have to be in hi and lo freqs */
if
(
freq_hi
==
freq_lo
)
{
if
(
freq_hi
==
freq_lo
)
{
dbs_info
->
freq_lo
=
0
;
dbs_info
->
freq_lo
=
0
;
dbs_info
->
freq_lo_
jiffie
s
=
0
;
dbs_info
->
freq_lo_
delay_u
s
=
0
;
return
freq_lo
;
return
freq_lo
;
}
}
jiffies_total
=
usecs_to_jiffies
(
od_tuners
->
sampling_rate
);
delay_hi_us
=
(
freq_avg
-
freq_lo
)
*
dbs_data
->
sampling_rate
;
jiffies_hi
=
(
freq_avg
-
freq_lo
)
*
jiffies_total
;
delay_hi_us
+=
(
freq_hi
-
freq_lo
)
/
2
;
jiffies_hi
+=
((
freq_hi
-
freq_lo
)
/
2
);
delay_hi_us
/=
freq_hi
-
freq_lo
;
jiffies_hi
/=
(
freq_hi
-
freq_lo
);
dbs_info
->
freq_hi_delay_us
=
delay_hi_us
;
jiffies_lo
=
jiffies_total
-
jiffies_hi
;
dbs_info
->
freq_lo
=
freq_lo
;
dbs_info
->
freq_lo
=
freq_lo
;
dbs_info
->
freq_lo_jiffies
=
jiffies_lo
;
dbs_info
->
freq_lo_delay_us
=
dbs_data
->
sampling_rate
-
delay_hi_us
;
dbs_info
->
freq_hi_jiffies
=
jiffies_hi
;
return
freq_hi
;
return
freq_hi
;
}
}
static
void
ondemand_powersave_bias_init
(
void
)
static
void
ondemand_powersave_bias_init
(
struct
cpufreq_policy
*
policy
)
{
{
int
i
;
struct
od_policy_dbs_info
*
dbs_info
=
to_dbs_info
(
policy
->
governor_data
)
;
for_each_online_cpu
(
i
)
{
ondemand_powersave_bias_init_cpu
(
i
);
dbs_info
->
freq_table
=
cpufreq_frequency_get_table
(
policy
->
cpu
);
}
dbs_info
->
freq_lo
=
0
;
}
}
static
void
dbs_freq_increase
(
struct
cpufreq_policy
*
policy
,
unsigned
int
freq
)
static
void
dbs_freq_increase
(
struct
cpufreq_policy
*
policy
,
unsigned
int
freq
)
{
{
struct
dbs_data
*
dbs_data
=
policy
->
governor_data
;
struct
policy_dbs_info
*
policy_dbs
=
policy
->
governor_data
;
struct
dbs_data
*
dbs_data
=
policy_dbs
->
dbs_data
;
struct
od_dbs_tuners
*
od_tuners
=
dbs_data
->
tuners
;
struct
od_dbs_tuners
*
od_tuners
=
dbs_data
->
tuners
;
if
(
od_tuners
->
powersave_bias
)
if
(
od_tuners
->
powersave_bias
)
...
@@ -150,21 +138,21 @@ static void dbs_freq_increase(struct cpufreq_policy *policy, unsigned int freq)
...
@@ -150,21 +138,21 @@ static void dbs_freq_increase(struct cpufreq_policy *policy, unsigned int freq)
* (default), then we try to increase frequency. Else, we adjust the frequency
* (default), then we try to increase frequency. Else, we adjust the frequency
* proportional to load.
* proportional to load.
*/
*/
static
void
od_
check_cpu
(
int
cpu
,
unsigned
int
load
)
static
void
od_
update
(
struct
cpufreq_policy
*
policy
)
{
{
struct
od_cpu_dbs_info_s
*
dbs_info
=
&
per_cpu
(
od_cpu_dbs_info
,
cpu
)
;
struct
policy_dbs_info
*
policy_dbs
=
policy
->
governor_data
;
struct
cpufreq_policy
*
policy
=
dbs_info
->
cdbs
.
shared
->
policy
;
struct
od_policy_dbs_info
*
dbs_info
=
to_dbs_info
(
policy_dbs
)
;
struct
dbs_data
*
dbs_data
=
policy
->
governor
_data
;
struct
dbs_data
*
dbs_data
=
policy
_dbs
->
dbs
_data
;
struct
od_dbs_tuners
*
od_tuners
=
dbs_data
->
tuners
;
struct
od_dbs_tuners
*
od_tuners
=
dbs_data
->
tuners
;
unsigned
int
load
=
dbs_update
(
policy
);
dbs_info
->
freq_lo
=
0
;
dbs_info
->
freq_lo
=
0
;
/* Check for frequency increase */
/* Check for frequency increase */
if
(
load
>
od_tuners
->
up_threshold
)
{
if
(
load
>
dbs_data
->
up_threshold
)
{
/* If switching to max speed, apply sampling_down_factor */
/* If switching to max speed, apply sampling_down_factor */
if
(
policy
->
cur
<
policy
->
max
)
if
(
policy
->
cur
<
policy
->
max
)
dbs_info
->
rate_mult
=
policy_dbs
->
rate_mult
=
dbs_data
->
sampling_down_factor
;
od_tuners
->
sampling_down_factor
;
dbs_freq_increase
(
policy
,
policy
->
max
);
dbs_freq_increase
(
policy
,
policy
->
max
);
}
else
{
}
else
{
/* Calculate the next frequency proportional to load */
/* Calculate the next frequency proportional to load */
...
@@ -175,177 +163,70 @@ static void od_check_cpu(int cpu, unsigned int load)
...
@@ -175,177 +163,70 @@ static void od_check_cpu(int cpu, unsigned int load)
freq_next
=
min_f
+
load
*
(
max_f
-
min_f
)
/
100
;
freq_next
=
min_f
+
load
*
(
max_f
-
min_f
)
/
100
;
/* No longer fully busy, reset rate_mult */
/* No longer fully busy, reset rate_mult */
dbs_info
->
rate_mult
=
1
;
policy_dbs
->
rate_mult
=
1
;
if
(
!
od_tuners
->
powersave_bias
)
{
if
(
od_tuners
->
powersave_bias
)
__cpufreq_driver_target
(
policy
,
freq_next
,
freq_next
=
od_ops
.
powersave_bias_target
(
policy
,
CPUFREQ_RELATION_C
);
freq_next
,
return
;
CPUFREQ_RELATION_L
);
}
freq_next
=
od_ops
.
powersave_bias_target
(
policy
,
freq_next
,
CPUFREQ_RELATION_L
);
__cpufreq_driver_target
(
policy
,
freq_next
,
CPUFREQ_RELATION_C
);
__cpufreq_driver_target
(
policy
,
freq_next
,
CPUFREQ_RELATION_C
);
}
}
}
}
static
unsigned
int
od_dbs_timer
(
struct
cpufreq_policy
*
policy
,
bool
modify_all
)
static
unsigned
int
od_dbs_timer
(
struct
cpufreq_policy
*
policy
)
{
{
struct
dbs_data
*
dbs_data
=
policy
->
governor_data
;
struct
policy_dbs_info
*
policy_dbs
=
policy
->
governor_data
;
unsigned
int
cpu
=
policy
->
cpu
;
struct
dbs_data
*
dbs_data
=
policy_dbs
->
dbs_data
;
struct
od_cpu_dbs_info_s
*
dbs_info
=
&
per_cpu
(
od_cpu_dbs_info
,
struct
od_policy_dbs_info
*
dbs_info
=
to_dbs_info
(
policy_dbs
);
cpu
);
int
sample_type
=
dbs_info
->
sample_type
;
struct
od_dbs_tuners
*
od_tuners
=
dbs_data
->
tuners
;
int
delay
=
0
,
sample_type
=
dbs_info
->
sample_type
;
if
(
!
modify_all
)
goto
max_delay
;
/* Common NORMAL_SAMPLE setup */
/* Common NORMAL_SAMPLE setup */
dbs_info
->
sample_type
=
OD_NORMAL_SAMPLE
;
dbs_info
->
sample_type
=
OD_NORMAL_SAMPLE
;
if
(
sample_type
==
OD_SUB_SAMPLE
)
{
/*
delay
=
dbs_info
->
freq_lo_jiffies
;
* OD_SUB_SAMPLE doesn't make sense if sample_delay_ns is 0, so ignore
* it then.
*/
if
(
sample_type
==
OD_SUB_SAMPLE
&&
policy_dbs
->
sample_delay_ns
>
0
)
{
__cpufreq_driver_target
(
policy
,
dbs_info
->
freq_lo
,
__cpufreq_driver_target
(
policy
,
dbs_info
->
freq_lo
,
CPUFREQ_RELATION_H
);
CPUFREQ_RELATION_H
);
}
else
{
return
dbs_info
->
freq_lo_delay_us
;
dbs_check_cpu
(
dbs_data
,
cpu
);
if
(
dbs_info
->
freq_lo
)
{
/* Setup timer for SUB_SAMPLE */
dbs_info
->
sample_type
=
OD_SUB_SAMPLE
;
delay
=
dbs_info
->
freq_hi_jiffies
;
}
}
}
max_delay:
od_update
(
policy
);
if
(
!
delay
)
delay
=
delay_for_sampling_rate
(
od_tuners
->
sampling_rate
*
dbs_info
->
rate_mult
);
return
delay
;
}
/************************** sysfs interface ************************/
static
struct
common_dbs_data
od_dbs_cdata
;
/**
if
(
dbs_info
->
freq_lo
)
{
* update_sampling_rate - update sampling rate effective immediately if needed.
/* Setup timer for SUB_SAMPLE */
* @new_rate: new sampling rate
dbs_info
->
sample_type
=
OD_SUB_SAMPLE
;
*
return
dbs_info
->
freq_hi_delay_us
;
* If new rate is smaller than the old, simply updating
* dbs_tuners_int.sampling_rate might not be appropriate. For example, if the
* original sampling_rate was 1 second and the requested new sampling rate is 10
* ms because the user needs immediate reaction from ondemand governor, but not
* sure if higher frequency will be required or not, then, the governor may
* change the sampling rate too late; up to 1 second later. Thus, if we are
* reducing the sampling rate, we need to make the new value effective
* immediately.
*/
static
void
update_sampling_rate
(
struct
dbs_data
*
dbs_data
,
unsigned
int
new_rate
)
{
struct
od_dbs_tuners
*
od_tuners
=
dbs_data
->
tuners
;
struct
cpumask
cpumask
;
int
cpu
;
od_tuners
->
sampling_rate
=
new_rate
=
max
(
new_rate
,
dbs_data
->
min_sampling_rate
);
/*
* Lock governor so that governor start/stop can't execute in parallel.
*/
mutex_lock
(
&
od_dbs_cdata
.
mutex
);
cpumask_copy
(
&
cpumask
,
cpu_online_mask
);
for_each_cpu
(
cpu
,
&
cpumask
)
{
struct
cpufreq_policy
*
policy
;
struct
od_cpu_dbs_info_s
*
dbs_info
;
struct
cpu_dbs_info
*
cdbs
;
struct
cpu_common_dbs_info
*
shared
;
unsigned
long
next_sampling
,
appointed_at
;
dbs_info
=
&
per_cpu
(
od_cpu_dbs_info
,
cpu
);
cdbs
=
&
dbs_info
->
cdbs
;
shared
=
cdbs
->
shared
;
/*
* A valid shared and shared->policy means governor hasn't
* stopped or exited yet.
*/
if
(
!
shared
||
!
shared
->
policy
)
continue
;
policy
=
shared
->
policy
;
/* clear all CPUs of this policy */
cpumask_andnot
(
&
cpumask
,
&
cpumask
,
policy
->
cpus
);
/*
* Update sampling rate for CPUs whose policy is governed by
* dbs_data. In case of governor_per_policy, only a single
* policy will be governed by dbs_data, otherwise there can be
* multiple policies that are governed by the same dbs_data.
*/
if
(
dbs_data
!=
policy
->
governor_data
)
continue
;
/*
* Checking this for any CPU should be fine, timers for all of
* them are scheduled together.
*/
next_sampling
=
jiffies
+
usecs_to_jiffies
(
new_rate
);
appointed_at
=
dbs_info
->
cdbs
.
timer
.
expires
;
if
(
time_before
(
next_sampling
,
appointed_at
))
{
gov_cancel_work
(
shared
);
gov_add_timers
(
policy
,
usecs_to_jiffies
(
new_rate
));
}
}
}
mutex_unlock
(
&
od_dbs_cdata
.
mutex
)
;
return
dbs_data
->
sampling_rate
*
policy_dbs
->
rate_mult
;
}
}
static
ssize_t
store_sampling_rate
(
struct
dbs_data
*
dbs_data
,
const
char
*
buf
,
/************************** sysfs interface ************************/
size_t
count
)
static
struct
dbs_governor
od_dbs_gov
;
{
unsigned
int
input
;
int
ret
;
ret
=
sscanf
(
buf
,
"%u"
,
&
input
);
if
(
ret
!=
1
)
return
-
EINVAL
;
update_sampling_rate
(
dbs_data
,
input
);
return
count
;
}
static
ssize_t
store_io_is_busy
(
struct
dbs_data
*
dbs_data
,
const
char
*
buf
,
static
ssize_t
store_io_is_busy
(
struct
dbs_data
*
dbs_data
,
const
char
*
buf
,
size_t
count
)
size_t
count
)
{
{
struct
od_dbs_tuners
*
od_tuners
=
dbs_data
->
tuners
;
unsigned
int
input
;
unsigned
int
input
;
int
ret
;
int
ret
;
unsigned
int
j
;
ret
=
sscanf
(
buf
,
"%u"
,
&
input
);
ret
=
sscanf
(
buf
,
"%u"
,
&
input
);
if
(
ret
!=
1
)
if
(
ret
!=
1
)
return
-
EINVAL
;
return
-
EINVAL
;
od_tuners
->
io_is_busy
=
!!
input
;
dbs_data
->
io_is_busy
=
!!
input
;
/* we need to re-evaluate prev_cpu_idle */
/* we need to re-evaluate prev_cpu_idle */
for_each_online_cpu
(
j
)
{
gov_update_cpu_data
(
dbs_data
);
struct
od_cpu_dbs_info_s
*
dbs_info
=
&
per_cpu
(
od_cpu_dbs_info
,
j
);
dbs_info
->
cdbs
.
prev_cpu_idle
=
get_cpu_idle_time
(
j
,
&
dbs_info
->
cdbs
.
prev_cpu_wall
,
od_tuners
->
io_is_busy
);
}
return
count
;
return
count
;
}
}
static
ssize_t
store_up_threshold
(
struct
dbs_data
*
dbs_data
,
const
char
*
buf
,
static
ssize_t
store_up_threshold
(
struct
dbs_data
*
dbs_data
,
const
char
*
buf
,
size_t
count
)
size_t
count
)
{
{
struct
od_dbs_tuners
*
od_tuners
=
dbs_data
->
tuners
;
unsigned
int
input
;
unsigned
int
input
;
int
ret
;
int
ret
;
ret
=
sscanf
(
buf
,
"%u"
,
&
input
);
ret
=
sscanf
(
buf
,
"%u"
,
&
input
);
...
@@ -355,40 +236,43 @@ static ssize_t store_up_threshold(struct dbs_data *dbs_data, const char *buf,
...
@@ -355,40 +236,43 @@ static ssize_t store_up_threshold(struct dbs_data *dbs_data, const char *buf,
return
-
EINVAL
;
return
-
EINVAL
;
}
}
od_tuners
->
up_threshold
=
input
;
dbs_data
->
up_threshold
=
input
;
return
count
;
return
count
;
}
}
static
ssize_t
store_sampling_down_factor
(
struct
dbs_data
*
dbs_data
,
static
ssize_t
store_sampling_down_factor
(
struct
dbs_data
*
dbs_data
,
const
char
*
buf
,
size_t
count
)
const
char
*
buf
,
size_t
count
)
{
{
struct
od_dbs_tuners
*
od_tuners
=
dbs_data
->
tuner
s
;
struct
policy_dbs_info
*
policy_db
s
;
unsigned
int
input
,
j
;
unsigned
int
input
;
int
ret
;
int
ret
;
ret
=
sscanf
(
buf
,
"%u"
,
&
input
);
ret
=
sscanf
(
buf
,
"%u"
,
&
input
);
if
(
ret
!=
1
||
input
>
MAX_SAMPLING_DOWN_FACTOR
||
input
<
1
)
if
(
ret
!=
1
||
input
>
MAX_SAMPLING_DOWN_FACTOR
||
input
<
1
)
return
-
EINVAL
;
return
-
EINVAL
;
od_tuners
->
sampling_down_factor
=
input
;
dbs_data
->
sampling_down_factor
=
input
;
/* Reset down sampling multiplier in case it was active */
/* Reset down sampling multiplier in case it was active */
for_each_online_cpu
(
j
)
{
list_for_each_entry
(
policy_dbs
,
&
dbs_data
->
policy_dbs_list
,
list
)
{
struct
od_cpu_dbs_info_s
*
dbs_info
=
&
per_cpu
(
od_cpu_dbs_info
,
/*
j
);
* Doing this without locking might lead to using different
dbs_info
->
rate_mult
=
1
;
* rate_mult values in od_update() and od_dbs_timer().
*/
mutex_lock
(
&
policy_dbs
->
timer_mutex
);
policy_dbs
->
rate_mult
=
1
;
mutex_unlock
(
&
policy_dbs
->
timer_mutex
);
}
}
return
count
;
return
count
;
}
}
static
ssize_t
store_ignore_nice_load
(
struct
dbs_data
*
dbs_data
,
static
ssize_t
store_ignore_nice_load
(
struct
dbs_data
*
dbs_data
,
const
char
*
buf
,
size_t
count
)
const
char
*
buf
,
size_t
count
)
{
{
struct
od_dbs_tuners
*
od_tuners
=
dbs_data
->
tuners
;
unsigned
int
input
;
unsigned
int
input
;
int
ret
;
int
ret
;
unsigned
int
j
;
ret
=
sscanf
(
buf
,
"%u"
,
&
input
);
ret
=
sscanf
(
buf
,
"%u"
,
&
input
);
if
(
ret
!=
1
)
if
(
ret
!=
1
)
return
-
EINVAL
;
return
-
EINVAL
;
...
@@ -396,22 +280,14 @@ static ssize_t store_ignore_nice_load(struct dbs_data *dbs_data,
...
@@ -396,22 +280,14 @@ static ssize_t store_ignore_nice_load(struct dbs_data *dbs_data,
if
(
input
>
1
)
if
(
input
>
1
)
input
=
1
;
input
=
1
;
if
(
input
==
od_tuners
->
ignore_nice_load
)
{
/* nothing to do */
if
(
input
==
dbs_data
->
ignore_nice_load
)
{
/* nothing to do */
return
count
;
return
count
;
}
}
od_tuners
->
ignore_nice_load
=
input
;
dbs_data
->
ignore_nice_load
=
input
;
/* we need to re-evaluate prev_cpu_idle */
/* we need to re-evaluate prev_cpu_idle */
for_each_online_cpu
(
j
)
{
gov_update_cpu_data
(
dbs_data
);
struct
od_cpu_dbs_info_s
*
dbs_info
;
dbs_info
=
&
per_cpu
(
od_cpu_dbs_info
,
j
);
dbs_info
->
cdbs
.
prev_cpu_idle
=
get_cpu_idle_time
(
j
,
&
dbs_info
->
cdbs
.
prev_cpu_wall
,
od_tuners
->
io_is_busy
);
if
(
od_tuners
->
ignore_nice_load
)
dbs_info
->
cdbs
.
prev_cpu_nice
=
kcpustat_cpu
(
j
).
cpustat
[
CPUTIME_NICE
];
}
return
count
;
return
count
;
}
}
...
@@ -419,6 +295,7 @@ static ssize_t store_powersave_bias(struct dbs_data *dbs_data, const char *buf,
...
@@ -419,6 +295,7 @@ static ssize_t store_powersave_bias(struct dbs_data *dbs_data, const char *buf,
size_t
count
)
size_t
count
)
{
{
struct
od_dbs_tuners
*
od_tuners
=
dbs_data
->
tuners
;
struct
od_dbs_tuners
*
od_tuners
=
dbs_data
->
tuners
;
struct
policy_dbs_info
*
policy_dbs
;
unsigned
int
input
;
unsigned
int
input
;
int
ret
;
int
ret
;
ret
=
sscanf
(
buf
,
"%u"
,
&
input
);
ret
=
sscanf
(
buf
,
"%u"
,
&
input
);
...
@@ -430,59 +307,54 @@ static ssize_t store_powersave_bias(struct dbs_data *dbs_data, const char *buf,
...
@@ -430,59 +307,54 @@ static ssize_t store_powersave_bias(struct dbs_data *dbs_data, const char *buf,
input
=
1000
;
input
=
1000
;
od_tuners
->
powersave_bias
=
input
;
od_tuners
->
powersave_bias
=
input
;
ondemand_powersave_bias_init
();
list_for_each_entry
(
policy_dbs
,
&
dbs_data
->
policy_dbs_list
,
list
)
ondemand_powersave_bias_init
(
policy_dbs
->
policy
);
return
count
;
return
count
;
}
}
show_store_one
(
od
,
sampling_rate
);
gov_show_one_common
(
sampling_rate
);
show_store_one
(
od
,
io_is_busy
);
gov_show_one_common
(
up_threshold
);
show_store_one
(
od
,
up_threshold
);
gov_show_one_common
(
sampling_down_factor
);
show_store_one
(
od
,
sampling_down_factor
);
gov_show_one_common
(
ignore_nice_load
);
show_store_one
(
od
,
ignore_nice_load
);
gov_show_one_common
(
min_sampling_rate
);
show_store_one
(
od
,
powersave_bias
);
gov_show_one_common
(
io_is_busy
);
declare_show_sampling_rate_min
(
od
);
gov_show_one
(
od
,
powersave_bias
);
gov_
sys_pol_
attr_rw
(
sampling_rate
);
gov_attr_rw
(
sampling_rate
);
gov_
sys_pol_
attr_rw
(
io_is_busy
);
gov_attr_rw
(
io_is_busy
);
gov_
sys_pol_
attr_rw
(
up_threshold
);
gov_attr_rw
(
up_threshold
);
gov_
sys_pol_
attr_rw
(
sampling_down_factor
);
gov_attr_rw
(
sampling_down_factor
);
gov_
sys_pol_
attr_rw
(
ignore_nice_load
);
gov_attr_rw
(
ignore_nice_load
);
gov_
sys_pol_
attr_rw
(
powersave_bias
);
gov_attr_rw
(
powersave_bias
);
gov_
sys_pol_attr_ro
(
sampling_rate_min
);
gov_
attr_ro
(
min_sampling_rate
);
static
struct
attribute
*
dbs_attributes_gov_sy
s
[]
=
{
static
struct
attribute
*
od_attribute
s
[]
=
{
&
sampling_rate_min_gov_sys
.
attr
,
&
min_sampling_rate
.
attr
,
&
sampling_rate
_gov_sys
.
attr
,
&
sampling_rate
.
attr
,
&
up_threshold
_gov_sys
.
attr
,
&
up_threshold
.
attr
,
&
sampling_down_factor
_gov_sys
.
attr
,
&
sampling_down_factor
.
attr
,
&
ignore_nice_load
_gov_sys
.
attr
,
&
ignore_nice_load
.
attr
,
&
powersave_bias
_gov_sys
.
attr
,
&
powersave_bias
.
attr
,
&
io_is_busy
_gov_sys
.
attr
,
&
io_is_busy
.
attr
,
NULL
NULL
};
};
static
struct
attribute_group
od_attr_group_gov_sys
=
{
/************************** sysfs end ************************/
.
attrs
=
dbs_attributes_gov_sys
,
.
name
=
"ondemand"
,
};
static
struct
attribute
*
dbs_attributes_gov_pol
[]
=
{
static
struct
policy_dbs_info
*
od_alloc
(
void
)
&
sampling_rate_min_gov_pol
.
attr
,
{
&
sampling_rate_gov_pol
.
attr
,
struct
od_policy_dbs_info
*
dbs_info
;
&
up_threshold_gov_pol
.
attr
,
&
sampling_down_factor_gov_pol
.
attr
,
&
ignore_nice_load_gov_pol
.
attr
,
&
powersave_bias_gov_pol
.
attr
,
&
io_is_busy_gov_pol
.
attr
,
NULL
};
static
struct
attribute_group
od_attr_group_gov_pol
=
{
dbs_info
=
kzalloc
(
sizeof
(
*
dbs_info
),
GFP_KERNEL
);
.
attrs
=
dbs_attributes_gov_pol
,
return
dbs_info
?
&
dbs_info
->
policy_dbs
:
NULL
;
.
name
=
"ondemand"
,
}
};
/************************** sysfs end ************************/
static
void
od_free
(
struct
policy_dbs_info
*
policy_dbs
)
{
kfree
(
to_dbs_info
(
policy_dbs
));
}
static
int
od_init
(
struct
dbs_data
*
dbs_data
,
bool
notify
)
static
int
od_init
(
struct
dbs_data
*
dbs_data
,
bool
notify
)
{
{
...
@@ -501,7 +373,7 @@ static int od_init(struct dbs_data *dbs_data, bool notify)
...
@@ -501,7 +373,7 @@ static int od_init(struct dbs_data *dbs_data, bool notify)
put_cpu
();
put_cpu
();
if
(
idle_time
!=
-
1ULL
)
{
if
(
idle_time
!=
-
1ULL
)
{
/* Idle micro accounting is supported. Use finer thresholds */
/* Idle micro accounting is supported. Use finer thresholds */
tuners
->
up_threshold
=
MICRO_FREQUENCY_UP_THRESHOLD
;
dbs_data
->
up_threshold
=
MICRO_FREQUENCY_UP_THRESHOLD
;
/*
/*
* In nohz/micro accounting case we set the minimum frequency
* In nohz/micro accounting case we set the minimum frequency
* not depending on HZ, but fixed (very low). The deferred
* not depending on HZ, but fixed (very low). The deferred
...
@@ -509,17 +381,17 @@ static int od_init(struct dbs_data *dbs_data, bool notify)
...
@@ -509,17 +381,17 @@ static int od_init(struct dbs_data *dbs_data, bool notify)
*/
*/
dbs_data
->
min_sampling_rate
=
MICRO_FREQUENCY_MIN_SAMPLE_RATE
;
dbs_data
->
min_sampling_rate
=
MICRO_FREQUENCY_MIN_SAMPLE_RATE
;
}
else
{
}
else
{
tuners
->
up_threshold
=
DEF_FREQUENCY_UP_THRESHOLD
;
dbs_data
->
up_threshold
=
DEF_FREQUENCY_UP_THRESHOLD
;
/* For correct statistics, we need 10 ticks for each measure */
/* For correct statistics, we need 10 ticks for each measure */
dbs_data
->
min_sampling_rate
=
MIN_SAMPLING_RATE_RATIO
*
dbs_data
->
min_sampling_rate
=
MIN_SAMPLING_RATE_RATIO
*
jiffies_to_usecs
(
10
);
jiffies_to_usecs
(
10
);
}
}
tuners
->
sampling_down_factor
=
DEF_SAMPLING_DOWN_FACTOR
;
dbs_data
->
sampling_down_factor
=
DEF_SAMPLING_DOWN_FACTOR
;
tuners
->
ignore_nice_load
=
0
;
dbs_data
->
ignore_nice_load
=
0
;
tuners
->
powersave_bias
=
default_powersave_bias
;
tuners
->
powersave_bias
=
default_powersave_bias
;
tuners
->
io_is_busy
=
should_io_be_busy
();
dbs_data
->
io_is_busy
=
should_io_be_busy
();
dbs_data
->
tuners
=
tuners
;
dbs_data
->
tuners
=
tuners
;
return
0
;
return
0
;
...
@@ -530,46 +402,38 @@ static void od_exit(struct dbs_data *dbs_data, bool notify)
...
@@ -530,46 +402,38 @@ static void od_exit(struct dbs_data *dbs_data, bool notify)
kfree
(
dbs_data
->
tuners
);
kfree
(
dbs_data
->
tuners
);
}
}
define_get_cpu_dbs_routines
(
od_cpu_dbs_info
);
static
void
od_start
(
struct
cpufreq_policy
*
policy
)
{
struct
od_policy_dbs_info
*
dbs_info
=
to_dbs_info
(
policy
->
governor_data
);
dbs_info
->
sample_type
=
OD_NORMAL_SAMPLE
;
ondemand_powersave_bias_init
(
policy
);
}
static
struct
od_ops
od_ops
=
{
static
struct
od_ops
od_ops
=
{
.
powersave_bias_init_cpu
=
ondemand_powersave_bias_init_cpu
,
.
powersave_bias_target
=
generic_powersave_bias_target
,
.
powersave_bias_target
=
generic_powersave_bias_target
,
.
freq_increase
=
dbs_freq_increase
,
};
};
static
struct
common_dbs_data
od_dbs_cdata
=
{
static
struct
dbs_governor
od_dbs_gov
=
{
.
governor
=
GOV_ONDEMAND
,
.
gov
=
{
.
attr_group_gov_sys
=
&
od_attr_group_gov_sys
,
.
name
=
"ondemand"
,
.
attr_group_gov_pol
=
&
od_attr_group_gov_pol
,
.
governor
=
cpufreq_governor_dbs
,
.
get_cpu_cdbs
=
get_cpu_cdbs
,
.
max_transition_latency
=
TRANSITION_LATENCY_LIMIT
,
.
get_cpu_dbs_info_s
=
get_cpu_dbs_info_s
,
.
owner
=
THIS_MODULE
,
},
.
kobj_type
=
{
.
default_attrs
=
od_attributes
},
.
gov_dbs_timer
=
od_dbs_timer
,
.
gov_dbs_timer
=
od_dbs_timer
,
.
gov_check_cpu
=
od_check_cpu
,
.
alloc
=
od_alloc
,
.
gov_ops
=
&
od_ops
,
.
free
=
od_free
,
.
init
=
od_init
,
.
init
=
od_init
,
.
exit
=
od_exit
,
.
exit
=
od_exit
,
.
mutex
=
__MUTEX_INITIALIZER
(
od_dbs_cdata
.
mutex
)
,
.
start
=
od_start
,
};
};
static
int
od_cpufreq_governor_dbs
(
struct
cpufreq_policy
*
policy
,
#define CPU_FREQ_GOV_ONDEMAND (&od_dbs_gov.gov)
unsigned
int
event
)
{
return
cpufreq_governor_dbs
(
policy
,
&
od_dbs_cdata
,
event
);
}
static
struct
cpufreq_governor
cpufreq_gov_ondemand
=
{
.
name
=
"ondemand"
,
.
governor
=
od_cpufreq_governor_dbs
,
.
max_transition_latency
=
TRANSITION_LATENCY_LIMIT
,
.
owner
=
THIS_MODULE
,
};
static
void
od_set_powersave_bias
(
unsigned
int
powersave_bias
)
static
void
od_set_powersave_bias
(
unsigned
int
powersave_bias
)
{
{
struct
cpufreq_policy
*
policy
;
struct
dbs_data
*
dbs_data
;
struct
od_dbs_tuners
*
od_tuners
;
unsigned
int
cpu
;
unsigned
int
cpu
;
cpumask_t
done
;
cpumask_t
done
;
...
@@ -578,22 +442,25 @@ static void od_set_powersave_bias(unsigned int powersave_bias)
...
@@ -578,22 +442,25 @@ static void od_set_powersave_bias(unsigned int powersave_bias)
get_online_cpus
();
get_online_cpus
();
for_each_online_cpu
(
cpu
)
{
for_each_online_cpu
(
cpu
)
{
struct
cpu_common_dbs_info
*
shared
;
struct
cpufreq_policy
*
policy
;
struct
policy_dbs_info
*
policy_dbs
;
struct
dbs_data
*
dbs_data
;
struct
od_dbs_tuners
*
od_tuners
;
if
(
cpumask_test_cpu
(
cpu
,
&
done
))
if
(
cpumask_test_cpu
(
cpu
,
&
done
))
continue
;
continue
;
shared
=
per_cpu
(
od_cpu_dbs_info
,
cpu
).
cdbs
.
shared
;
policy
=
cpufreq_cpu_get_raw
(
cpu
)
;
if
(
!
shared
)
if
(
!
policy
||
policy
->
governor
!=
CPU_FREQ_GOV_ONDEMAND
)
continue
;
continue
;
policy
=
shared
->
policy
;
policy_dbs
=
policy
->
governor_data
;
cpumask_or
(
&
done
,
&
done
,
policy
->
cpus
);
if
(
!
policy_dbs
)
if
(
policy
->
governor
!=
&
cpufreq_gov_ondemand
)
continue
;
continue
;
dbs_data
=
policy
->
governor_data
;
cpumask_or
(
&
done
,
&
done
,
policy
->
cpus
);
dbs_data
=
policy_dbs
->
dbs_data
;
od_tuners
=
dbs_data
->
tuners
;
od_tuners
=
dbs_data
->
tuners
;
od_tuners
->
powersave_bias
=
default_powersave_bias
;
od_tuners
->
powersave_bias
=
default_powersave_bias
;
}
}
...
@@ -618,12 +485,12 @@ EXPORT_SYMBOL_GPL(od_unregister_powersave_bias_handler);
...
@@ -618,12 +485,12 @@ EXPORT_SYMBOL_GPL(od_unregister_powersave_bias_handler);
static
int
__init
cpufreq_gov_dbs_init
(
void
)
static
int
__init
cpufreq_gov_dbs_init
(
void
)
{
{
return
cpufreq_register_governor
(
&
cpufreq_gov_ondemand
);
return
cpufreq_register_governor
(
CPU_FREQ_GOV_ONDEMAND
);
}
}
static
void
__exit
cpufreq_gov_dbs_exit
(
void
)
static
void
__exit
cpufreq_gov_dbs_exit
(
void
)
{
{
cpufreq_unregister_governor
(
&
cpufreq_gov_ondemand
);
cpufreq_unregister_governor
(
CPU_FREQ_GOV_ONDEMAND
);
}
}
MODULE_AUTHOR
(
"Venkatesh Pallipadi <venkatesh.pallipadi@intel.com>"
);
MODULE_AUTHOR
(
"Venkatesh Pallipadi <venkatesh.pallipadi@intel.com>"
);
...
@@ -635,7 +502,7 @@ MODULE_LICENSE("GPL");
...
@@ -635,7 +502,7 @@ MODULE_LICENSE("GPL");
#ifdef CONFIG_CPU_FREQ_DEFAULT_GOV_ONDEMAND
#ifdef CONFIG_CPU_FREQ_DEFAULT_GOV_ONDEMAND
struct
cpufreq_governor
*
cpufreq_default_governor
(
void
)
struct
cpufreq_governor
*
cpufreq_default_governor
(
void
)
{
{
return
&
cpufreq_gov_ondemand
;
return
CPU_FREQ_GOV_ONDEMAND
;
}
}
fs_initcall
(
cpufreq_gov_dbs_init
);
fs_initcall
(
cpufreq_gov_dbs_init
);
...
...
drivers/cpufreq/cpufreq_ondemand.h
0 → 100644
浏览文件 @
a5acbfbd
/*
* Header file for CPUFreq ondemand governor and related code.
*
* Copyright (C) 2016, Intel Corporation
* Author: Rafael J. Wysocki <rafael.j.wysocki@intel.com>
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 as
* published by the Free Software Foundation.
*/
#include "cpufreq_governor.h"
struct
od_policy_dbs_info
{
struct
policy_dbs_info
policy_dbs
;
struct
cpufreq_frequency_table
*
freq_table
;
unsigned
int
freq_lo
;
unsigned
int
freq_lo_delay_us
;
unsigned
int
freq_hi_delay_us
;
unsigned
int
sample_type
:
1
;
};
static
inline
struct
od_policy_dbs_info
*
to_dbs_info
(
struct
policy_dbs_info
*
policy_dbs
)
{
return
container_of
(
policy_dbs
,
struct
od_policy_dbs_info
,
policy_dbs
);
}
struct
od_dbs_tuners
{
unsigned
int
powersave_bias
;
};
drivers/cpufreq/intel_pstate.c
浏览文件 @
a5acbfbd
...
@@ -71,7 +71,7 @@ struct sample {
...
@@ -71,7 +71,7 @@ struct sample {
u64
mperf
;
u64
mperf
;
u64
tsc
;
u64
tsc
;
int
freq
;
int
freq
;
ktime_t
time
;
u64
time
;
};
};
struct
pstate_data
{
struct
pstate_data
{
...
@@ -103,13 +103,13 @@ struct _pid {
...
@@ -103,13 +103,13 @@ struct _pid {
struct
cpudata
{
struct
cpudata
{
int
cpu
;
int
cpu
;
struct
timer_list
timer
;
struct
update_util_data
update_util
;
struct
pstate_data
pstate
;
struct
pstate_data
pstate
;
struct
vid_data
vid
;
struct
vid_data
vid
;
struct
_pid
pid
;
struct
_pid
pid
;
ktime_t
last_sample_time
;
u64
last_sample_time
;
u64
prev_aperf
;
u64
prev_aperf
;
u64
prev_mperf
;
u64
prev_mperf
;
u64
prev_tsc
;
u64
prev_tsc
;
...
@@ -120,6 +120,7 @@ struct cpudata {
...
@@ -120,6 +120,7 @@ struct cpudata {
static
struct
cpudata
**
all_cpu_data
;
static
struct
cpudata
**
all_cpu_data
;
struct
pstate_adjust_policy
{
struct
pstate_adjust_policy
{
int
sample_rate_ms
;
int
sample_rate_ms
;
s64
sample_rate_ns
;
int
deadband
;
int
deadband
;
int
setpoint
;
int
setpoint
;
int
p_gain_pct
;
int
p_gain_pct
;
...
@@ -718,7 +719,7 @@ static void core_set_pstate(struct cpudata *cpudata, int pstate)
...
@@ -718,7 +719,7 @@ static void core_set_pstate(struct cpudata *cpudata, int pstate)
if
(
limits
->
no_turbo
&&
!
limits
->
turbo_disabled
)
if
(
limits
->
no_turbo
&&
!
limits
->
turbo_disabled
)
val
|=
(
u64
)
1
<<
32
;
val
|=
(
u64
)
1
<<
32
;
wrmsrl
_on_cpu
(
cpudata
->
cpu
,
MSR_IA32_PERF_CTL
,
val
);
wrmsrl
(
MSR_IA32_PERF_CTL
,
val
);
}
}
static
int
knl_get_turbo_pstate
(
void
)
static
int
knl_get_turbo_pstate
(
void
)
...
@@ -889,7 +890,7 @@ static inline void intel_pstate_calc_busy(struct cpudata *cpu)
...
@@ -889,7 +890,7 @@ static inline void intel_pstate_calc_busy(struct cpudata *cpu)
sample
->
core_pct_busy
=
(
int32_t
)
core_pct
;
sample
->
core_pct_busy
=
(
int32_t
)
core_pct
;
}
}
static
inline
void
intel_pstate_sample
(
struct
cpudata
*
cpu
)
static
inline
void
intel_pstate_sample
(
struct
cpudata
*
cpu
,
u64
time
)
{
{
u64
aperf
,
mperf
;
u64
aperf
,
mperf
;
unsigned
long
flags
;
unsigned
long
flags
;
...
@@ -906,7 +907,7 @@ static inline void intel_pstate_sample(struct cpudata *cpu)
...
@@ -906,7 +907,7 @@ static inline void intel_pstate_sample(struct cpudata *cpu)
local_irq_restore
(
flags
);
local_irq_restore
(
flags
);
cpu
->
last_sample_time
=
cpu
->
sample
.
time
;
cpu
->
last_sample_time
=
cpu
->
sample
.
time
;
cpu
->
sample
.
time
=
ktime_get
()
;
cpu
->
sample
.
time
=
time
;
cpu
->
sample
.
aperf
=
aperf
;
cpu
->
sample
.
aperf
=
aperf
;
cpu
->
sample
.
mperf
=
mperf
;
cpu
->
sample
.
mperf
=
mperf
;
cpu
->
sample
.
tsc
=
tsc
;
cpu
->
sample
.
tsc
=
tsc
;
...
@@ -921,22 +922,6 @@ static inline void intel_pstate_sample(struct cpudata *cpu)
...
@@ -921,22 +922,6 @@ static inline void intel_pstate_sample(struct cpudata *cpu)
cpu
->
prev_tsc
=
tsc
;
cpu
->
prev_tsc
=
tsc
;
}
}
static
inline
void
intel_hwp_set_sample_time
(
struct
cpudata
*
cpu
)
{
int
delay
;
delay
=
msecs_to_jiffies
(
50
);
mod_timer_pinned
(
&
cpu
->
timer
,
jiffies
+
delay
);
}
static
inline
void
intel_pstate_set_sample_time
(
struct
cpudata
*
cpu
)
{
int
delay
;
delay
=
msecs_to_jiffies
(
pid_params
.
sample_rate_ms
);
mod_timer_pinned
(
&
cpu
->
timer
,
jiffies
+
delay
);
}
static
inline
int32_t
get_target_pstate_use_cpu_load
(
struct
cpudata
*
cpu
)
static
inline
int32_t
get_target_pstate_use_cpu_load
(
struct
cpudata
*
cpu
)
{
{
struct
sample
*
sample
=
&
cpu
->
sample
;
struct
sample
*
sample
=
&
cpu
->
sample
;
...
@@ -976,8 +961,7 @@ static inline int32_t get_target_pstate_use_cpu_load(struct cpudata *cpu)
...
@@ -976,8 +961,7 @@ static inline int32_t get_target_pstate_use_cpu_load(struct cpudata *cpu)
static
inline
int32_t
get_target_pstate_use_performance
(
struct
cpudata
*
cpu
)
static
inline
int32_t
get_target_pstate_use_performance
(
struct
cpudata
*
cpu
)
{
{
int32_t
core_busy
,
max_pstate
,
current_pstate
,
sample_ratio
;
int32_t
core_busy
,
max_pstate
,
current_pstate
,
sample_ratio
;
s64
duration_us
;
u64
duration_ns
;
u32
sample_time
;
/*
/*
* core_busy is the ratio of actual performance to max
* core_busy is the ratio of actual performance to max
...
@@ -996,18 +980,16 @@ static inline int32_t get_target_pstate_use_performance(struct cpudata *cpu)
...
@@ -996,18 +980,16 @@ static inline int32_t get_target_pstate_use_performance(struct cpudata *cpu)
core_busy
=
mul_fp
(
core_busy
,
div_fp
(
max_pstate
,
current_pstate
));
core_busy
=
mul_fp
(
core_busy
,
div_fp
(
max_pstate
,
current_pstate
));
/*
/*
* Since we have a deferred timer, it will not fire unless
* Since our utilization update callback will not run unless we are
* we are in C0. So, determine if the actual elapsed time
* in C0, check if the actual elapsed time is significantly greater (3x)
* is significantly greater (3x) than our sample interval. If it
* than our sample interval. If it is, then we were idle for a long
* is, then we were idle for a long enough period of time
* enough period of time to adjust our busyness.
* to adjust our busyness.
*/
*/
sample_time
=
pid_params
.
sample_rate_ms
*
USEC_PER_MSEC
;
duration_ns
=
cpu
->
sample
.
time
-
cpu
->
last_sample_time
;
duration_us
=
ktime_us_delta
(
cpu
->
sample
.
time
,
if
((
s64
)
duration_ns
>
pid_params
.
sample_rate_ns
*
3
cpu
->
last_sample_time
);
&&
cpu
->
last_sample_time
>
0
)
{
if
(
duration_us
>
sample_time
*
3
)
{
sample_ratio
=
div_fp
(
int_tofp
(
pid_params
.
sample_rate_ns
),
sample_ratio
=
div_fp
(
int_tofp
(
sample_time
),
int_tofp
(
duration_ns
));
int_tofp
(
duration_us
));
core_busy
=
mul_fp
(
core_busy
,
sample_ratio
);
core_busy
=
mul_fp
(
core_busy
,
sample_ratio
);
}
}
...
@@ -1037,23 +1019,17 @@ static inline void intel_pstate_adjust_busy_pstate(struct cpudata *cpu)
...
@@ -1037,23 +1019,17 @@ static inline void intel_pstate_adjust_busy_pstate(struct cpudata *cpu)
sample
->
freq
);
sample
->
freq
);
}
}
static
void
intel_hwp_timer_func
(
unsigned
long
__data
)
static
void
intel_pstate_update_util
(
struct
update_util_data
*
data
,
u64
time
,
{
unsigned
long
util
,
unsigned
long
max
)
struct
cpudata
*
cpu
=
(
struct
cpudata
*
)
__data
;
intel_pstate_sample
(
cpu
);
intel_hwp_set_sample_time
(
cpu
);
}
static
void
intel_pstate_timer_func
(
unsigned
long
__data
)
{
{
struct
cpudata
*
cpu
=
(
struct
cpudata
*
)
__data
;
struct
cpudata
*
cpu
=
container_of
(
data
,
struct
cpudata
,
update_util
);
u64
delta_ns
=
time
-
cpu
->
sample
.
time
;
intel_pstate_sample
(
cpu
);
intel_pstate_adjust_busy_pstate
(
cpu
);
if
((
s64
)
delta_ns
>=
pid_params
.
sample_rate_ns
)
{
intel_pstate_sample
(
cpu
,
time
);
intel_pstate_set_sample_time
(
cpu
);
if
(
!
hwp_active
)
intel_pstate_adjust_busy_pstate
(
cpu
);
}
}
}
#define ICPU(model, policy) \
#define ICPU(model, policy) \
...
@@ -1101,24 +1077,19 @@ static int intel_pstate_init_cpu(unsigned int cpunum)
...
@@ -1101,24 +1077,19 @@ static int intel_pstate_init_cpu(unsigned int cpunum)
cpu
->
cpu
=
cpunum
;
cpu
->
cpu
=
cpunum
;
if
(
hwp_active
)
if
(
hwp_active
)
{
intel_pstate_hwp_enable
(
cpu
);
intel_pstate_hwp_enable
(
cpu
);
pid_params
.
sample_rate_ms
=
50
;
pid_params
.
sample_rate_ns
=
50
*
NSEC_PER_MSEC
;
}
intel_pstate_get_cpu_pstates
(
cpu
);
intel_pstate_get_cpu_pstates
(
cpu
);
init_timer_deferrable
(
&
cpu
->
timer
);
cpu
->
timer
.
data
=
(
unsigned
long
)
cpu
;
cpu
->
timer
.
expires
=
jiffies
+
HZ
/
100
;
if
(
!
hwp_active
)
cpu
->
timer
.
function
=
intel_pstate_timer_func
;
else
cpu
->
timer
.
function
=
intel_hwp_timer_func
;
intel_pstate_busy_pid_reset
(
cpu
);
intel_pstate_busy_pid_reset
(
cpu
);
intel_pstate_sample
(
cpu
);
intel_pstate_sample
(
cpu
,
0
);
add_timer_on
(
&
cpu
->
timer
,
cpunum
);
cpu
->
update_util
.
func
=
intel_pstate_update_util
;
cpufreq_set_update_util_data
(
cpunum
,
&
cpu
->
update_util
);
pr_debug
(
"intel_pstate: controlling: cpu %d
\n
"
,
cpunum
);
pr_debug
(
"intel_pstate: controlling: cpu %d
\n
"
,
cpunum
);
...
@@ -1202,7 +1173,9 @@ static void intel_pstate_stop_cpu(struct cpufreq_policy *policy)
...
@@ -1202,7 +1173,9 @@ static void intel_pstate_stop_cpu(struct cpufreq_policy *policy)
pr_debug
(
"intel_pstate: CPU %d exiting
\n
"
,
cpu_num
);
pr_debug
(
"intel_pstate: CPU %d exiting
\n
"
,
cpu_num
);
del_timer_sync
(
&
all_cpu_data
[
cpu_num
]
->
timer
);
cpufreq_set_update_util_data
(
cpu_num
,
NULL
);
synchronize_sched
();
if
(
hwp_active
)
if
(
hwp_active
)
return
;
return
;
...
@@ -1266,6 +1239,7 @@ static int intel_pstate_msrs_not_valid(void)
...
@@ -1266,6 +1239,7 @@ static int intel_pstate_msrs_not_valid(void)
static
void
copy_pid_params
(
struct
pstate_adjust_policy
*
policy
)
static
void
copy_pid_params
(
struct
pstate_adjust_policy
*
policy
)
{
{
pid_params
.
sample_rate_ms
=
policy
->
sample_rate_ms
;
pid_params
.
sample_rate_ms
=
policy
->
sample_rate_ms
;
pid_params
.
sample_rate_ns
=
pid_params
.
sample_rate_ms
*
NSEC_PER_MSEC
;
pid_params
.
p_gain_pct
=
policy
->
p_gain_pct
;
pid_params
.
p_gain_pct
=
policy
->
p_gain_pct
;
pid_params
.
i_gain_pct
=
policy
->
i_gain_pct
;
pid_params
.
i_gain_pct
=
policy
->
i_gain_pct
;
pid_params
.
d_gain_pct
=
policy
->
d_gain_pct
;
pid_params
.
d_gain_pct
=
policy
->
d_gain_pct
;
...
@@ -1467,7 +1441,8 @@ static int __init intel_pstate_init(void)
...
@@ -1467,7 +1441,8 @@ static int __init intel_pstate_init(void)
get_online_cpus
();
get_online_cpus
();
for_each_online_cpu
(
cpu
)
{
for_each_online_cpu
(
cpu
)
{
if
(
all_cpu_data
[
cpu
])
{
if
(
all_cpu_data
[
cpu
])
{
del_timer_sync
(
&
all_cpu_data
[
cpu
]
->
timer
);
cpufreq_set_update_util_data
(
cpu
,
NULL
);
synchronize_sched
();
kfree
(
all_cpu_data
[
cpu
]);
kfree
(
all_cpu_data
[
cpu
]);
}
}
}
}
...
...
include/linux/cpufreq.h
浏览文件 @
a5acbfbd
...
@@ -80,7 +80,6 @@ struct cpufreq_policy {
...
@@ -80,7 +80,6 @@ struct cpufreq_policy {
unsigned
int
last_policy
;
/* policy before unplug */
unsigned
int
last_policy
;
/* policy before unplug */
struct
cpufreq_governor
*
governor
;
/* see below */
struct
cpufreq_governor
*
governor
;
/* see below */
void
*
governor_data
;
void
*
governor_data
;
bool
governor_enabled
;
/* governor start/stop flag */
char
last_governor
[
CPUFREQ_NAME_LEN
];
/* last governor used */
char
last_governor
[
CPUFREQ_NAME_LEN
];
/* last governor used */
struct
work_struct
update
;
/* if update_policy() needs to be
struct
work_struct
update
;
/* if update_policy() needs to be
...
@@ -100,10 +99,6 @@ struct cpufreq_policy {
...
@@ -100,10 +99,6 @@ struct cpufreq_policy {
* - Any routine that will write to the policy structure and/or may take away
* - Any routine that will write to the policy structure and/or may take away
* the policy altogether (eg. CPU hotplug), will hold this lock in write
* the policy altogether (eg. CPU hotplug), will hold this lock in write
* mode before doing so.
* mode before doing so.
*
* Additional rules:
* - Lock should not be held across
* __cpufreq_governor(data, CPUFREQ_GOV_POLICY_EXIT);
*/
*/
struct
rw_semaphore
rwsem
;
struct
rw_semaphore
rwsem
;
...
...
include/linux/sched.h
浏览文件 @
a5acbfbd
...
@@ -3207,4 +3207,13 @@ static inline unsigned long rlimit_max(unsigned int limit)
...
@@ -3207,4 +3207,13 @@ static inline unsigned long rlimit_max(unsigned int limit)
return
task_rlimit_max
(
current
,
limit
);
return
task_rlimit_max
(
current
,
limit
);
}
}
#ifdef CONFIG_CPU_FREQ
struct
update_util_data
{
void
(
*
func
)(
struct
update_util_data
*
data
,
u64
time
,
unsigned
long
util
,
unsigned
long
max
);
};
void
cpufreq_set_update_util_data
(
int
cpu
,
struct
update_util_data
*
data
);
#endif
/* CONFIG_CPU_FREQ */
#endif
#endif
kernel/sched/Makefile
浏览文件 @
a5acbfbd
...
@@ -19,3 +19,4 @@ obj-$(CONFIG_SCHED_AUTOGROUP) += auto_group.o
...
@@ -19,3 +19,4 @@ obj-$(CONFIG_SCHED_AUTOGROUP) += auto_group.o
obj-$(CONFIG_SCHEDSTATS)
+=
stats.o
obj-$(CONFIG_SCHEDSTATS)
+=
stats.o
obj-$(CONFIG_SCHED_DEBUG)
+=
debug.o
obj-$(CONFIG_SCHED_DEBUG)
+=
debug.o
obj-$(CONFIG_CGROUP_CPUACCT)
+=
cpuacct.o
obj-$(CONFIG_CGROUP_CPUACCT)
+=
cpuacct.o
obj-$(CONFIG_CPU_FREQ)
+=
cpufreq.o
kernel/sched/cpufreq.c
0 → 100644
浏览文件 @
a5acbfbd
/*
* Scheduler code and data structures related to cpufreq.
*
* Copyright (C) 2016, Intel Corporation
* Author: Rafael J. Wysocki <rafael.j.wysocki@intel.com>
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 as
* published by the Free Software Foundation.
*/
#include "sched.h"
DEFINE_PER_CPU
(
struct
update_util_data
*
,
cpufreq_update_util_data
);
/**
* cpufreq_set_update_util_data - Populate the CPU's update_util_data pointer.
* @cpu: The CPU to set the pointer for.
* @data: New pointer value.
*
* Set and publish the update_util_data pointer for the given CPU. That pointer
* points to a struct update_util_data object containing a callback function
* to call from cpufreq_update_util(). That function will be called from an RCU
* read-side critical section, so it must not sleep.
*
* Callers must use RCU-sched callbacks to free any memory that might be
* accessed via the old update_util_data pointer or invoke synchronize_sched()
* right after this function to avoid use-after-free.
*/
void
cpufreq_set_update_util_data
(
int
cpu
,
struct
update_util_data
*
data
)
{
if
(
WARN_ON
(
data
&&
!
data
->
func
))
return
;
rcu_assign_pointer
(
per_cpu
(
cpufreq_update_util_data
,
cpu
),
data
);
}
EXPORT_SYMBOL_GPL
(
cpufreq_set_update_util_data
);
kernel/sched/deadline.c
浏览文件 @
a5acbfbd
...
@@ -726,6 +726,10 @@ static void update_curr_dl(struct rq *rq)
...
@@ -726,6 +726,10 @@ static void update_curr_dl(struct rq *rq)
if
(
!
dl_task
(
curr
)
||
!
on_dl_rq
(
dl_se
))
if
(
!
dl_task
(
curr
)
||
!
on_dl_rq
(
dl_se
))
return
;
return
;
/* Kick cpufreq (see the comment in linux/cpufreq.h). */
if
(
cpu_of
(
rq
)
==
smp_processor_id
())
cpufreq_trigger_update
(
rq_clock
(
rq
));
/*
/*
* Consumed budget is computed considering the time as
* Consumed budget is computed considering the time as
* observed by schedulable tasks (excluding time spent
* observed by schedulable tasks (excluding time spent
...
...
kernel/sched/fair.c
浏览文件 @
a5acbfbd
...
@@ -2824,7 +2824,8 @@ static inline void update_load_avg(struct sched_entity *se, int update_tg)
...
@@ -2824,7 +2824,8 @@ static inline void update_load_avg(struct sched_entity *se, int update_tg)
{
{
struct
cfs_rq
*
cfs_rq
=
cfs_rq_of
(
se
);
struct
cfs_rq
*
cfs_rq
=
cfs_rq_of
(
se
);
u64
now
=
cfs_rq_clock_task
(
cfs_rq
);
u64
now
=
cfs_rq_clock_task
(
cfs_rq
);
int
cpu
=
cpu_of
(
rq_of
(
cfs_rq
));
struct
rq
*
rq
=
rq_of
(
cfs_rq
);
int
cpu
=
cpu_of
(
rq
);
/*
/*
* Track task load average for carrying it to new CPU after migrated, and
* Track task load average for carrying it to new CPU after migrated, and
...
@@ -2836,6 +2837,29 @@ static inline void update_load_avg(struct sched_entity *se, int update_tg)
...
@@ -2836,6 +2837,29 @@ static inline void update_load_avg(struct sched_entity *se, int update_tg)
if
(
update_cfs_rq_load_avg
(
now
,
cfs_rq
)
&&
update_tg
)
if
(
update_cfs_rq_load_avg
(
now
,
cfs_rq
)
&&
update_tg
)
update_tg_load_avg
(
cfs_rq
,
0
);
update_tg_load_avg
(
cfs_rq
,
0
);
if
(
cpu
==
smp_processor_id
()
&&
&
rq
->
cfs
==
cfs_rq
)
{
unsigned
long
max
=
rq
->
cpu_capacity_orig
;
/*
* There are a few boundary cases this might miss but it should
* get called often enough that that should (hopefully) not be
* a real problem -- added to that it only calls on the local
* CPU, so if we enqueue remotely we'll miss an update, but
* the next tick/schedule should update.
*
* It will not get called when we go idle, because the idle
* thread is a different class (!fair), nor will the utilization
* number include things like RT tasks.
*
* As is, the util number is not freq-invariant (we'd have to
* implement arch_scale_freq_capacity() for that).
*
* See cpu_util().
*/
cpufreq_update_util
(
rq_clock
(
rq
),
min
(
cfs_rq
->
avg
.
util_avg
,
max
),
max
);
}
}
}
static
void
attach_entity_load_avg
(
struct
cfs_rq
*
cfs_rq
,
struct
sched_entity
*
se
)
static
void
attach_entity_load_avg
(
struct
cfs_rq
*
cfs_rq
,
struct
sched_entity
*
se
)
...
...
kernel/sched/rt.c
浏览文件 @
a5acbfbd
...
@@ -945,6 +945,10 @@ static void update_curr_rt(struct rq *rq)
...
@@ -945,6 +945,10 @@ static void update_curr_rt(struct rq *rq)
if
(
curr
->
sched_class
!=
&
rt_sched_class
)
if
(
curr
->
sched_class
!=
&
rt_sched_class
)
return
;
return
;
/* Kick cpufreq (see the comment in linux/cpufreq.h). */
if
(
cpu_of
(
rq
)
==
smp_processor_id
())
cpufreq_trigger_update
(
rq_clock
(
rq
));
delta_exec
=
rq_clock_task
(
rq
)
-
curr
->
se
.
exec_start
;
delta_exec
=
rq_clock_task
(
rq
)
-
curr
->
se
.
exec_start
;
if
(
unlikely
((
s64
)
delta_exec
<=
0
))
if
(
unlikely
((
s64
)
delta_exec
<=
0
))
return
;
return
;
...
...
kernel/sched/sched.h
浏览文件 @
a5acbfbd
...
@@ -1738,3 +1738,51 @@ static inline u64 irq_time_read(int cpu)
...
@@ -1738,3 +1738,51 @@ static inline u64 irq_time_read(int cpu)
}
}
#endif
/* CONFIG_64BIT */
#endif
/* CONFIG_64BIT */
#endif
/* CONFIG_IRQ_TIME_ACCOUNTING */
#endif
/* CONFIG_IRQ_TIME_ACCOUNTING */
#ifdef CONFIG_CPU_FREQ
DECLARE_PER_CPU
(
struct
update_util_data
*
,
cpufreq_update_util_data
);
/**
* cpufreq_update_util - Take a note about CPU utilization changes.
* @time: Current time.
* @util: Current utilization.
* @max: Utilization ceiling.
*
* This function is called by the scheduler on every invocation of
* update_load_avg() on the CPU whose utilization is being updated.
*
* It can only be called from RCU-sched read-side critical sections.
*/
static
inline
void
cpufreq_update_util
(
u64
time
,
unsigned
long
util
,
unsigned
long
max
)
{
struct
update_util_data
*
data
;
data
=
rcu_dereference_sched
(
*
this_cpu_ptr
(
&
cpufreq_update_util_data
));
if
(
data
)
data
->
func
(
data
,
time
,
util
,
max
);
}
/**
* cpufreq_trigger_update - Trigger CPU performance state evaluation if needed.
* @time: Current time.
*
* The way cpufreq is currently arranged requires it to evaluate the CPU
* performance state (frequency/voltage) on a regular basis to prevent it from
* being stuck in a completely inadequate performance level for too long.
* That is not guaranteed to happen if the updates are only triggered from CFS,
* though, because they may not be coming in if RT or deadline tasks are active
* all the time (or there are RT and DL tasks only).
*
* As a workaround for that issue, this function is called by the RT and DL
* sched classes to trigger extra cpufreq updates to prevent it from stalling,
* but that really is a band-aid. Going forward it should be replaced with
* solutions targeted more specifically at RT and DL tasks.
*/
static
inline
void
cpufreq_trigger_update
(
u64
time
)
{
cpufreq_update_util
(
time
,
ULONG_MAX
,
0
);
}
#else
static
inline
void
cpufreq_update_util
(
u64
time
,
unsigned
long
util
,
unsigned
long
max
)
{}
static
inline
void
cpufreq_trigger_update
(
u64
time
)
{}
#endif
/* CONFIG_CPU_FREQ */
编辑
预览
Markdown
is supported
0%
请重试
或
添加新附件
.
添加附件
取消
You are about to add
0
people
to the discussion. Proceed with caution.
先完成此消息的编辑!
取消
想要评论请
注册
或
登录