Skip to content
体验新版
项目
组织
正在加载...
登录
切换导航
打开侧边栏
openeuler
raspberrypi-kernel
提交
437574c9
R
raspberrypi-kernel
项目概览
openeuler
/
raspberrypi-kernel
通知
13
Star
1
Fork
0
代码
文件
提交
分支
Tags
贡献者
分支图
Diff
Issue
0
列表
看板
标记
里程碑
合并请求
0
Wiki
0
Wiki
分析
仓库
DevOps
项目成员
Pages
R
raspberrypi-kernel
项目概览
项目概览
详情
发布
仓库
仓库
文件
提交
分支
标签
贡献者
分支图
比较
Issue
0
Issue
0
列表
看板
标记
里程碑
合并请求
0
合并请求
0
Pages
分析
分析
仓库分析
DevOps
Wiki
0
Wiki
成员
成员
收起侧边栏
关闭侧边栏
动态
分支图
创建新Issue
提交
Issue看板
提交
437574c9
编写于
12月 18, 2014
作者:
R
Rafael J. Wysocki
浏览文件
操作
浏览文件
下载
差异文件
Merge branch 'pm-opp' into pm-cpufreq
上级
7c1ac18d
b4718c02
变更
1
隐藏空白更改
内联
并排
Showing
1 changed file
with
75 addition
and
42 deletion
+75
-42
drivers/base/power/opp.c
drivers/base/power/opp.c
+75
-42
未找到文件。
drivers/base/power/opp.c
浏览文件 @
437574c9
...
@@ -84,7 +84,11 @@ struct dev_pm_opp {
...
@@ -84,7 +84,11 @@ struct dev_pm_opp {
*
*
* This is an internal data structure maintaining the link to opps attached to
* This is an internal data structure maintaining the link to opps attached to
* a device. This structure is not meant to be shared to users as it is
* a device. This structure is not meant to be shared to users as it is
* meant for book keeping and private to OPP library
* meant for book keeping and private to OPP library.
*
* Because the opp structures can be used from both rcu and srcu readers, we
* need to wait for the grace period of both of them before freeing any
* resources. And so we have used kfree_rcu() from within call_srcu() handlers.
*/
*/
struct
device_opp
{
struct
device_opp
{
struct
list_head
node
;
struct
list_head
node
;
...
@@ -104,6 +108,14 @@ static LIST_HEAD(dev_opp_list);
...
@@ -104,6 +108,14 @@ static LIST_HEAD(dev_opp_list);
/* Lock to allow exclusive modification to the device and opp lists */
/* Lock to allow exclusive modification to the device and opp lists */
static
DEFINE_MUTEX
(
dev_opp_list_lock
);
static
DEFINE_MUTEX
(
dev_opp_list_lock
);
#define opp_rcu_lockdep_assert() \
do { \
rcu_lockdep_assert(rcu_read_lock_held() || \
lockdep_is_held(&dev_opp_list_lock), \
"Missing rcu_read_lock() or " \
"dev_opp_list_lock protection"); \
} while (0)
/**
/**
* find_device_opp() - find device_opp struct using device pointer
* find_device_opp() - find device_opp struct using device pointer
* @dev: device pointer used to lookup device OPPs
* @dev: device pointer used to lookup device OPPs
...
@@ -204,9 +216,7 @@ EXPORT_SYMBOL_GPL(dev_pm_opp_get_freq);
...
@@ -204,9 +216,7 @@ EXPORT_SYMBOL_GPL(dev_pm_opp_get_freq);
* This function returns the number of available opps if there are any,
* This function returns the number of available opps if there are any,
* else returns 0 if none or the corresponding error value.
* else returns 0 if none or the corresponding error value.
*
*
* Locking: This function must be called under rcu_read_lock(). This function
* Locking: This function takes rcu_read_lock().
* internally references two RCU protected structures: device_opp and opp which
* are safe as long as we are under a common RCU locked section.
*/
*/
int
dev_pm_opp_get_opp_count
(
struct
device
*
dev
)
int
dev_pm_opp_get_opp_count
(
struct
device
*
dev
)
{
{
...
@@ -214,11 +224,14 @@ int dev_pm_opp_get_opp_count(struct device *dev)
...
@@ -214,11 +224,14 @@ int dev_pm_opp_get_opp_count(struct device *dev)
struct
dev_pm_opp
*
temp_opp
;
struct
dev_pm_opp
*
temp_opp
;
int
count
=
0
;
int
count
=
0
;
rcu_read_lock
();
dev_opp
=
find_device_opp
(
dev
);
dev_opp
=
find_device_opp
(
dev
);
if
(
IS_ERR
(
dev_opp
))
{
if
(
IS_ERR
(
dev_opp
))
{
int
r
=
PTR_ERR
(
dev_opp
);
count
=
PTR_ERR
(
dev_opp
);
dev_err
(
dev
,
"%s: device OPP not found (%d)
\n
"
,
__func__
,
r
);
dev_err
(
dev
,
"%s: device OPP not found (%d)
\n
"
,
return
r
;
__func__
,
count
);
goto
out_unlock
;
}
}
list_for_each_entry_rcu
(
temp_opp
,
&
dev_opp
->
opp_list
,
node
)
{
list_for_each_entry_rcu
(
temp_opp
,
&
dev_opp
->
opp_list
,
node
)
{
...
@@ -226,6 +239,8 @@ int dev_pm_opp_get_opp_count(struct device *dev)
...
@@ -226,6 +239,8 @@ int dev_pm_opp_get_opp_count(struct device *dev)
count
++
;
count
++
;
}
}
out_unlock:
rcu_read_unlock
();
return
count
;
return
count
;
}
}
EXPORT_SYMBOL_GPL
(
dev_pm_opp_get_opp_count
);
EXPORT_SYMBOL_GPL
(
dev_pm_opp_get_opp_count
);
...
@@ -263,6 +278,8 @@ struct dev_pm_opp *dev_pm_opp_find_freq_exact(struct device *dev,
...
@@ -263,6 +278,8 @@ struct dev_pm_opp *dev_pm_opp_find_freq_exact(struct device *dev,
struct
device_opp
*
dev_opp
;
struct
device_opp
*
dev_opp
;
struct
dev_pm_opp
*
temp_opp
,
*
opp
=
ERR_PTR
(
-
ERANGE
);
struct
dev_pm_opp
*
temp_opp
,
*
opp
=
ERR_PTR
(
-
ERANGE
);
opp_rcu_lockdep_assert
();
dev_opp
=
find_device_opp
(
dev
);
dev_opp
=
find_device_opp
(
dev
);
if
(
IS_ERR
(
dev_opp
))
{
if
(
IS_ERR
(
dev_opp
))
{
int
r
=
PTR_ERR
(
dev_opp
);
int
r
=
PTR_ERR
(
dev_opp
);
...
@@ -309,6 +326,8 @@ struct dev_pm_opp *dev_pm_opp_find_freq_ceil(struct device *dev,
...
@@ -309,6 +326,8 @@ struct dev_pm_opp *dev_pm_opp_find_freq_ceil(struct device *dev,
struct
device_opp
*
dev_opp
;
struct
device_opp
*
dev_opp
;
struct
dev_pm_opp
*
temp_opp
,
*
opp
=
ERR_PTR
(
-
ERANGE
);
struct
dev_pm_opp
*
temp_opp
,
*
opp
=
ERR_PTR
(
-
ERANGE
);
opp_rcu_lockdep_assert
();
if
(
!
dev
||
!
freq
)
{
if
(
!
dev
||
!
freq
)
{
dev_err
(
dev
,
"%s: Invalid argument freq=%p
\n
"
,
__func__
,
freq
);
dev_err
(
dev
,
"%s: Invalid argument freq=%p
\n
"
,
__func__
,
freq
);
return
ERR_PTR
(
-
EINVAL
);
return
ERR_PTR
(
-
EINVAL
);
...
@@ -357,6 +376,8 @@ struct dev_pm_opp *dev_pm_opp_find_freq_floor(struct device *dev,
...
@@ -357,6 +376,8 @@ struct dev_pm_opp *dev_pm_opp_find_freq_floor(struct device *dev,
struct
device_opp
*
dev_opp
;
struct
device_opp
*
dev_opp
;
struct
dev_pm_opp
*
temp_opp
,
*
opp
=
ERR_PTR
(
-
ERANGE
);
struct
dev_pm_opp
*
temp_opp
,
*
opp
=
ERR_PTR
(
-
ERANGE
);
opp_rcu_lockdep_assert
();
if
(
!
dev
||
!
freq
)
{
if
(
!
dev
||
!
freq
)
{
dev_err
(
dev
,
"%s: Invalid argument freq=%p
\n
"
,
__func__
,
freq
);
dev_err
(
dev
,
"%s: Invalid argument freq=%p
\n
"
,
__func__
,
freq
);
return
ERR_PTR
(
-
EINVAL
);
return
ERR_PTR
(
-
EINVAL
);
...
@@ -382,12 +403,34 @@ struct dev_pm_opp *dev_pm_opp_find_freq_floor(struct device *dev,
...
@@ -382,12 +403,34 @@ struct dev_pm_opp *dev_pm_opp_find_freq_floor(struct device *dev,
}
}
EXPORT_SYMBOL_GPL
(
dev_pm_opp_find_freq_floor
);
EXPORT_SYMBOL_GPL
(
dev_pm_opp_find_freq_floor
);
static
struct
device_opp
*
add_device_opp
(
struct
device
*
dev
)
{
struct
device_opp
*
dev_opp
;
/*
* Allocate a new device OPP table. In the infrequent case where a new
* device is needed to be added, we pay this penalty.
*/
dev_opp
=
kzalloc
(
sizeof
(
*
dev_opp
),
GFP_KERNEL
);
if
(
!
dev_opp
)
return
NULL
;
dev_opp
->
dev
=
dev
;
srcu_init_notifier_head
(
&
dev_opp
->
srcu_head
);
INIT_LIST_HEAD
(
&
dev_opp
->
opp_list
);
/* Secure the device list modification */
list_add_rcu
(
&
dev_opp
->
node
,
&
dev_opp_list
);
return
dev_opp
;
}
static
int
dev_pm_opp_add_dynamic
(
struct
device
*
dev
,
unsigned
long
freq
,
static
int
dev_pm_opp_add_dynamic
(
struct
device
*
dev
,
unsigned
long
freq
,
unsigned
long
u_volt
,
bool
dynamic
)
unsigned
long
u_volt
,
bool
dynamic
)
{
{
struct
device_opp
*
dev_opp
=
NULL
;
struct
device_opp
*
dev_opp
=
NULL
;
struct
dev_pm_opp
*
opp
,
*
new_opp
;
struct
dev_pm_opp
*
opp
,
*
new_opp
;
struct
list_head
*
head
;
struct
list_head
*
head
;
int
ret
;
/* allocate new OPP node */
/* allocate new OPP node */
new_opp
=
kzalloc
(
sizeof
(
*
new_opp
),
GFP_KERNEL
);
new_opp
=
kzalloc
(
sizeof
(
*
new_opp
),
GFP_KERNEL
);
...
@@ -400,7 +443,6 @@ static int dev_pm_opp_add_dynamic(struct device *dev, unsigned long freq,
...
@@ -400,7 +443,6 @@ static int dev_pm_opp_add_dynamic(struct device *dev, unsigned long freq,
mutex_lock
(
&
dev_opp_list_lock
);
mutex_lock
(
&
dev_opp_list_lock
);
/* populate the opp table */
/* populate the opp table */
new_opp
->
dev_opp
=
dev_opp
;
new_opp
->
rate
=
freq
;
new_opp
->
rate
=
freq
;
new_opp
->
u_volt
=
u_volt
;
new_opp
->
u_volt
=
u_volt
;
new_opp
->
available
=
true
;
new_opp
->
available
=
true
;
...
@@ -409,27 +451,12 @@ static int dev_pm_opp_add_dynamic(struct device *dev, unsigned long freq,
...
@@ -409,27 +451,12 @@ static int dev_pm_opp_add_dynamic(struct device *dev, unsigned long freq,
/* Check for existing list for 'dev' */
/* Check for existing list for 'dev' */
dev_opp
=
find_device_opp
(
dev
);
dev_opp
=
find_device_opp
(
dev
);
if
(
IS_ERR
(
dev_opp
))
{
if
(
IS_ERR
(
dev_opp
))
{
/*
dev_opp
=
add_device_opp
(
dev
);
* Allocate a new device OPP table. In the infrequent case
* where a new device is needed to be added, we pay this
* penalty.
*/
dev_opp
=
kzalloc
(
sizeof
(
struct
device_opp
),
GFP_KERNEL
);
if
(
!
dev_opp
)
{
if
(
!
dev_opp
)
{
mutex_unlock
(
&
dev_opp_list_lock
);
ret
=
-
ENOMEM
;
kfree
(
new_opp
);
goto
free_opp
;
dev_warn
(
dev
,
"%s: Unable to create device OPP structure
\n
"
,
__func__
);
return
-
ENOMEM
;
}
}
dev_opp
->
dev
=
dev
;
srcu_init_notifier_head
(
&
dev_opp
->
srcu_head
);
INIT_LIST_HEAD
(
&
dev_opp
->
opp_list
);
/* Secure the device list modification */
list_add_rcu
(
&
dev_opp
->
node
,
&
dev_opp_list
);
head
=
&
dev_opp
->
opp_list
;
head
=
&
dev_opp
->
opp_list
;
goto
list_add
;
goto
list_add
;
}
}
...
@@ -448,18 +475,17 @@ static int dev_pm_opp_add_dynamic(struct device *dev, unsigned long freq,
...
@@ -448,18 +475,17 @@ static int dev_pm_opp_add_dynamic(struct device *dev, unsigned long freq,
/* Duplicate OPPs ? */
/* Duplicate OPPs ? */
if
(
new_opp
->
rate
==
opp
->
rate
)
{
if
(
new_opp
->
rate
==
opp
->
rate
)
{
int
ret
=
opp
->
available
&&
new_opp
->
u_volt
==
opp
->
u_volt
?
ret
=
opp
->
available
&&
new_opp
->
u_volt
==
opp
->
u_volt
?
0
:
-
EEXIST
;
0
:
-
EEXIST
;
dev_warn
(
dev
,
"%s: duplicate OPPs detected. Existing: freq: %lu, volt: %lu, enabled: %d. New: freq: %lu, volt: %lu, enabled: %d
\n
"
,
dev_warn
(
dev
,
"%s: duplicate OPPs detected. Existing: freq: %lu, volt: %lu, enabled: %d. New: freq: %lu, volt: %lu, enabled: %d
\n
"
,
__func__
,
opp
->
rate
,
opp
->
u_volt
,
opp
->
available
,
__func__
,
opp
->
rate
,
opp
->
u_volt
,
opp
->
available
,
new_opp
->
rate
,
new_opp
->
u_volt
,
new_opp
->
available
);
new_opp
->
rate
,
new_opp
->
u_volt
,
new_opp
->
available
);
mutex_unlock
(
&
dev_opp_list_lock
);
goto
free_opp
;
kfree
(
new_opp
);
return
ret
;
}
}
list_add:
list_add:
new_opp
->
dev_opp
=
dev_opp
;
list_add_rcu
(
&
new_opp
->
node
,
head
);
list_add_rcu
(
&
new_opp
->
node
,
head
);
mutex_unlock
(
&
dev_opp_list_lock
);
mutex_unlock
(
&
dev_opp_list_lock
);
...
@@ -469,6 +495,11 @@ static int dev_pm_opp_add_dynamic(struct device *dev, unsigned long freq,
...
@@ -469,6 +495,11 @@ static int dev_pm_opp_add_dynamic(struct device *dev, unsigned long freq,
*/
*/
srcu_notifier_call_chain
(
&
dev_opp
->
srcu_head
,
OPP_EVENT_ADD
,
new_opp
);
srcu_notifier_call_chain
(
&
dev_opp
->
srcu_head
,
OPP_EVENT_ADD
,
new_opp
);
return
0
;
return
0
;
free_opp:
mutex_unlock
(
&
dev_opp_list_lock
);
kfree
(
new_opp
);
return
ret
;
}
}
/**
/**
...
@@ -511,10 +542,11 @@ static void kfree_device_rcu(struct rcu_head *head)
...
@@ -511,10 +542,11 @@ static void kfree_device_rcu(struct rcu_head *head)
{
{
struct
device_opp
*
device_opp
=
container_of
(
head
,
struct
device_opp
,
rcu_head
);
struct
device_opp
*
device_opp
=
container_of
(
head
,
struct
device_opp
,
rcu_head
);
kfree
(
device_opp
);
kfree
_rcu
(
device_opp
,
rcu_head
);
}
}
void
__dev_pm_opp_remove
(
struct
device_opp
*
dev_opp
,
struct
dev_pm_opp
*
opp
)
static
void
__dev_pm_opp_remove
(
struct
device_opp
*
dev_opp
,
struct
dev_pm_opp
*
opp
)
{
{
/*
/*
* Notify the changes in the availability of the operable
* Notify the changes in the availability of the operable
...
@@ -592,7 +624,7 @@ EXPORT_SYMBOL_GPL(dev_pm_opp_remove);
...
@@ -592,7 +624,7 @@ EXPORT_SYMBOL_GPL(dev_pm_opp_remove);
static
int
opp_set_availability
(
struct
device
*
dev
,
unsigned
long
freq
,
static
int
opp_set_availability
(
struct
device
*
dev
,
unsigned
long
freq
,
bool
availability_req
)
bool
availability_req
)
{
{
struct
device_opp
*
tmp_dev_opp
,
*
dev_opp
=
ERR_PTR
(
-
ENODEV
)
;
struct
device_opp
*
dev_opp
;
struct
dev_pm_opp
*
new_opp
,
*
tmp_opp
,
*
opp
=
ERR_PTR
(
-
ENODEV
);
struct
dev_pm_opp
*
new_opp
,
*
tmp_opp
,
*
opp
=
ERR_PTR
(
-
ENODEV
);
int
r
=
0
;
int
r
=
0
;
...
@@ -606,12 +638,7 @@ static int opp_set_availability(struct device *dev, unsigned long freq,
...
@@ -606,12 +638,7 @@ static int opp_set_availability(struct device *dev, unsigned long freq,
mutex_lock
(
&
dev_opp_list_lock
);
mutex_lock
(
&
dev_opp_list_lock
);
/* Find the device_opp */
/* Find the device_opp */
list_for_each_entry
(
tmp_dev_opp
,
&
dev_opp_list
,
node
)
{
dev_opp
=
find_device_opp
(
dev
);
if
(
dev
==
tmp_dev_opp
->
dev
)
{
dev_opp
=
tmp_dev_opp
;
break
;
}
}
if
(
IS_ERR
(
dev_opp
))
{
if
(
IS_ERR
(
dev_opp
))
{
r
=
PTR_ERR
(
dev_opp
);
r
=
PTR_ERR
(
dev_opp
);
dev_warn
(
dev
,
"%s: Device OPP not found (%d)
\n
"
,
__func__
,
r
);
dev_warn
(
dev
,
"%s: Device OPP not found (%d)
\n
"
,
__func__
,
r
);
...
@@ -768,14 +795,20 @@ EXPORT_SYMBOL_GPL(of_init_opp_table);
...
@@ -768,14 +795,20 @@ EXPORT_SYMBOL_GPL(of_init_opp_table);
*/
*/
void
of_free_opp_table
(
struct
device
*
dev
)
void
of_free_opp_table
(
struct
device
*
dev
)
{
{
struct
device_opp
*
dev_opp
=
find_device_opp
(
dev
)
;
struct
device_opp
*
dev_opp
;
struct
dev_pm_opp
*
opp
,
*
tmp
;
struct
dev_pm_opp
*
opp
,
*
tmp
;
/* Check for existing list for 'dev' */
/* Check for existing list for 'dev' */
dev_opp
=
find_device_opp
(
dev
);
dev_opp
=
find_device_opp
(
dev
);
if
(
WARN
(
IS_ERR
(
dev_opp
),
"%s: dev_opp: %ld
\n
"
,
dev_name
(
dev
),
if
(
IS_ERR
(
dev_opp
))
{
PTR_ERR
(
dev_opp
)))
int
error
=
PTR_ERR
(
dev_opp
);
if
(
error
!=
-
ENODEV
)
WARN
(
1
,
"%s: dev_opp: %d
\n
"
,
IS_ERR_OR_NULL
(
dev
)
?
"Invalid device"
:
dev_name
(
dev
),
error
);
return
;
return
;
}
/* Hold our list modification lock here */
/* Hold our list modification lock here */
mutex_lock
(
&
dev_opp_list_lock
);
mutex_lock
(
&
dev_opp_list_lock
);
...
...
编辑
预览
Markdown
is supported
0%
请重试
或
添加新附件
.
添加附件
取消
You are about to add
0
people
to the discussion. Proceed with caution.
先完成此消息的编辑!
取消
想要评论请
注册
或
登录