Skip to content
体验新版
项目
组织
正在加载...
登录
切换导航
打开侧边栏
OpenHarmony
kernel_linux
提交
663d3f7c
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看板
提交
663d3f7c
编写于
8月 11, 2014
作者:
G
Grant Likely
浏览文件
操作
浏览文件
下载
差异文件
Merge branch 'devicetree/next-overlay' into devicetree/next
Conflicts: drivers/of/testcase-data/testcases.dts
上级
b775e642
b6ae5dc5
变更
14
隐藏空白更改
内联
并排
Showing
14 changed file
with
1054 addition
and
443 deletion
+1054
-443
Documentation/devicetree/changesets.txt
Documentation/devicetree/changesets.txt
+40
-0
arch/powerpc/kernel/prom.c
arch/powerpc/kernel/prom.c
+0
-70
arch/powerpc/platforms/pseries/hotplug-memory.c
arch/powerpc/platforms/pseries/hotplug-memory.c
+1
-1
drivers/crypto/nx/nx-842.c
drivers/crypto/nx/nx-842.c
+8
-22
drivers/of/Makefile
drivers/of/Makefile
+1
-0
drivers/of/base.c
drivers/of/base.c
+106
-317
drivers/of/device.c
drivers/of/device.c
+2
-2
drivers/of/dynamic.c
drivers/of/dynamic.c
+660
-0
drivers/of/of_private.h
drivers/of/of_private.h
+58
-1
drivers/of/platform.c
drivers/of/platform.c
+9
-23
drivers/of/selftest.c
drivers/of/selftest.c
+79
-0
drivers/of/testcase-data/testcases.dts
drivers/of/testcase-data/testcases.dts
+10
-0
include/linux/of.h
include/linux/of.h
+78
-2
include/linux/of_platform.h
include/linux/of_platform.h
+2
-5
未找到文件。
Documentation/devicetree/changesets.txt
0 → 100644
浏览文件 @
663d3f7c
A DT changeset is a method which allows one to apply changes
in the live tree in such a way that either the full set of changes
will be applied, or none of them will be. If an error occurs partway
through applying the changeset, then the tree will be rolled back to the
previous state. A changeset can also be removed after it has been
applied.
When a changeset is applied, all of the changes get applied to the tree
at once before emitting OF_RECONFIG notifiers. This is so that the
receiver sees a complete and consistent state of the tree when it
receives the notifier.
The sequence of a changeset is as follows.
1. of_changeset_init() - initializes a changeset
2. A number of DT tree change calls, of_changeset_attach_node(),
of_changeset_detach_node(), of_changeset_add_property(),
of_changeset_remove_property, of_changeset_update_property() to prepare
a set of changes. No changes to the active tree are made at this point.
All the change operations are recorded in the of_changeset 'entries'
list.
3. mutex_lock(of_mutex) - starts a changeset; The global of_mutex
ensures there can only be one editor at a time.
4. of_changeset_apply() - Apply the changes to the tree. Either the
entire changeset will get applied, or if there is an error the tree will
be restored to the previous state
5. mutex_unlock(of_mutex) - All operations complete, release the mutex
If a successfully applied changeset needs to be removed, it can be done
with the following sequence.
1. mutex_lock(of_mutex)
2. of_changeset_revert()
3. mutex_unlock(of_mutex)
arch/powerpc/kernel/prom.c
浏览文件 @
663d3f7c
...
@@ -821,76 +821,6 @@ int cpu_to_chip_id(int cpu)
...
@@ -821,76 +821,6 @@ int cpu_to_chip_id(int cpu)
}
}
EXPORT_SYMBOL
(
cpu_to_chip_id
);
EXPORT_SYMBOL
(
cpu_to_chip_id
);
#ifdef CONFIG_PPC_PSERIES
/*
* Fix up the uninitialized fields in a new device node:
* name, type and pci-specific fields
*/
static
int
of_finish_dynamic_node
(
struct
device_node
*
node
)
{
struct
device_node
*
parent
=
of_get_parent
(
node
);
int
err
=
0
;
const
phandle
*
ibm_phandle
;
node
->
name
=
of_get_property
(
node
,
"name"
,
NULL
);
node
->
type
=
of_get_property
(
node
,
"device_type"
,
NULL
);
if
(
!
node
->
name
)
node
->
name
=
"<NULL>"
;
if
(
!
node
->
type
)
node
->
type
=
"<NULL>"
;
if
(
!
parent
)
{
err
=
-
ENODEV
;
goto
out
;
}
/* We don't support that function on PowerMac, at least
* not yet
*/
if
(
machine_is
(
powermac
))
return
-
ENODEV
;
/* fix up new node's phandle field */
if
((
ibm_phandle
=
of_get_property
(
node
,
"ibm,phandle"
,
NULL
)))
node
->
phandle
=
*
ibm_phandle
;
out:
of_node_put
(
parent
);
return
err
;
}
static
int
prom_reconfig_notifier
(
struct
notifier_block
*
nb
,
unsigned
long
action
,
void
*
node
)
{
int
err
;
switch
(
action
)
{
case
OF_RECONFIG_ATTACH_NODE
:
err
=
of_finish_dynamic_node
(
node
);
if
(
err
<
0
)
printk
(
KERN_ERR
"finish_node returned %d
\n
"
,
err
);
break
;
default:
err
=
0
;
break
;
}
return
notifier_from_errno
(
err
);
}
static
struct
notifier_block
prom_reconfig_nb
=
{
.
notifier_call
=
prom_reconfig_notifier
,
.
priority
=
10
,
/* This one needs to run first */
};
static
int
__init
prom_reconfig_setup
(
void
)
{
return
of_reconfig_notifier_register
(
&
prom_reconfig_nb
);
}
__initcall
(
prom_reconfig_setup
);
#endif
bool
arch_match_cpu_phys_id
(
int
cpu
,
u64
phys_id
)
bool
arch_match_cpu_phys_id
(
int
cpu
,
u64
phys_id
)
{
{
return
(
int
)
phys_id
==
get_hard_smp_processor_id
(
cpu
);
return
(
int
)
phys_id
==
get_hard_smp_processor_id
(
cpu
);
...
...
arch/powerpc/platforms/pseries/hotplug-memory.c
浏览文件 @
663d3f7c
...
@@ -194,7 +194,7 @@ static int pseries_update_drconf_memory(struct of_prop_reconfig *pr)
...
@@ -194,7 +194,7 @@ static int pseries_update_drconf_memory(struct of_prop_reconfig *pr)
if
(
!
memblock_size
)
if
(
!
memblock_size
)
return
-
EINVAL
;
return
-
EINVAL
;
p
=
(
u32
*
)
of_get_property
(
pr
->
dn
,
"ibm,dynamic-memory"
,
NULL
)
;
p
=
(
u32
*
)
pr
->
old_prop
->
value
;
if
(
!
p
)
if
(
!
p
)
return
-
EINVAL
;
return
-
EINVAL
;
...
...
drivers/crypto/nx/nx-842.c
浏览文件 @
663d3f7c
...
@@ -936,28 +936,14 @@ static int nx842_OF_upd(struct property *new_prop)
...
@@ -936,28 +936,14 @@ static int nx842_OF_upd(struct property *new_prop)
goto
error_out
;
goto
error_out
;
}
}
/* Set ptr to new property if provided */
/*
if
(
new_prop
)
{
* If this is a property update, there are only certain properties that
/* Single property */
* we care about. Bail if it isn't in the below list
if
(
!
strncmp
(
new_prop
->
name
,
"status"
,
new_prop
->
length
))
{
*/
status
=
new_prop
;
if
(
new_prop
&&
(
strncmp
(
new_prop
->
name
,
"status"
,
new_prop
->
length
)
||
strncmp
(
new_prop
->
name
,
"ibm,max-sg-len"
,
new_prop
->
length
)
||
}
else
if
(
!
strncmp
(
new_prop
->
name
,
"ibm,max-sg-len"
,
strncmp
(
new_prop
->
name
,
"ibm,max-sync-cop"
,
new_prop
->
length
)))
new_prop
->
length
))
{
goto
out
;
maxsglen
=
new_prop
;
}
else
if
(
!
strncmp
(
new_prop
->
name
,
"ibm,max-sync-cop"
,
new_prop
->
length
))
{
maxsyncop
=
new_prop
;
}
else
{
/*
* Skip the update, the property being updated
* has no impact.
*/
goto
out
;
}
}
/* Perform property updates */
/* Perform property updates */
ret
=
nx842_OF_upd_status
(
new_devdata
,
status
);
ret
=
nx842_OF_upd_status
(
new_devdata
,
status
);
...
...
drivers/of/Makefile
浏览文件 @
663d3f7c
obj-y
=
base.o device.o platform.o
obj-y
=
base.o device.o platform.o
obj-$(CONFIG_OF_DYNAMIC)
+=
dynamic.o
obj-$(CONFIG_OF_FLATTREE)
+=
fdt.o
obj-$(CONFIG_OF_FLATTREE)
+=
fdt.o
obj-$(CONFIG_OF_EARLY_FLATTREE)
+=
fdt_address.o
obj-$(CONFIG_OF_EARLY_FLATTREE)
+=
fdt_address.o
obj-$(CONFIG_OF_PROMTREE)
+=
pdt.o
obj-$(CONFIG_OF_PROMTREE)
+=
pdt.o
...
...
drivers/of/base.c
浏览文件 @
663d3f7c
...
@@ -38,13 +38,15 @@ struct device_node *of_chosen;
...
@@ -38,13 +38,15 @@ struct device_node *of_chosen;
struct
device_node
*
of_aliases
;
struct
device_node
*
of_aliases
;
struct
device_node
*
of_stdout
;
struct
device_node
*
of_stdout
;
st
atic
st
ruct
kset
*
of_kset
;
struct
kset
*
of_kset
;
/*
/*
* Used to protect the of_aliases; but also overloaded to hold off addition of
* Used to protect the of_aliases, to hold off addition of nodes to sysfs.
* nodes to sysfs
* This mutex must be held whenever modifications are being made to the
* device tree. The of_{attach,detach}_node() and
* of_{add,remove,update}_property() helpers make sure this happens.
*/
*/
DEFINE_MUTEX
(
of_
aliases_
mutex
);
DEFINE_MUTEX
(
of_mutex
);
/* use when traversing tree through the allnext, child, sibling,
/* use when traversing tree through the allnext, child, sibling,
* or parent members of struct device_node.
* or parent members of struct device_node.
...
@@ -90,79 +92,7 @@ int __weak of_node_to_nid(struct device_node *np)
...
@@ -90,79 +92,7 @@ int __weak of_node_to_nid(struct device_node *np)
}
}
#endif
#endif
#if defined(CONFIG_OF_DYNAMIC)
#ifndef CONFIG_OF_DYNAMIC
/**
* of_node_get - Increment refcount of a node
* @node: Node to inc refcount, NULL is supported to
* simplify writing of callers
*
* Returns node.
*/
struct
device_node
*
of_node_get
(
struct
device_node
*
node
)
{
if
(
node
)
kobject_get
(
&
node
->
kobj
);
return
node
;
}
EXPORT_SYMBOL
(
of_node_get
);
static
inline
struct
device_node
*
kobj_to_device_node
(
struct
kobject
*
kobj
)
{
return
container_of
(
kobj
,
struct
device_node
,
kobj
);
}
/**
* of_node_release - release a dynamically allocated node
* @kref: kref element of the node to be released
*
* In of_node_put() this function is passed to kref_put()
* as the destructor.
*/
static
void
of_node_release
(
struct
kobject
*
kobj
)
{
struct
device_node
*
node
=
kobj_to_device_node
(
kobj
);
struct
property
*
prop
=
node
->
properties
;
/* We should never be releasing nodes that haven't been detached. */
if
(
!
of_node_check_flag
(
node
,
OF_DETACHED
))
{
pr_err
(
"ERROR: Bad of_node_put() on %s
\n
"
,
node
->
full_name
);
dump_stack
();
return
;
}
if
(
!
of_node_check_flag
(
node
,
OF_DYNAMIC
))
return
;
while
(
prop
)
{
struct
property
*
next
=
prop
->
next
;
kfree
(
prop
->
name
);
kfree
(
prop
->
value
);
kfree
(
prop
);
prop
=
next
;
if
(
!
prop
)
{
prop
=
node
->
deadprops
;
node
->
deadprops
=
NULL
;
}
}
kfree
(
node
->
full_name
);
kfree
(
node
->
data
);
kfree
(
node
);
}
/**
* of_node_put - Decrement refcount of a node
* @node: Node to dec refcount, NULL is supported to
* simplify writing of callers
*
*/
void
of_node_put
(
struct
device_node
*
node
)
{
if
(
node
)
kobject_put
(
&
node
->
kobj
);
}
EXPORT_SYMBOL
(
of_node_put
);
#else
static
void
of_node_release
(
struct
kobject
*
kobj
)
static
void
of_node_release
(
struct
kobject
*
kobj
)
{
{
/* Without CONFIG_OF_DYNAMIC, no nodes gets freed */
/* Without CONFIG_OF_DYNAMIC, no nodes gets freed */
...
@@ -201,13 +131,16 @@ static const char *safe_name(struct kobject *kobj, const char *orig_name)
...
@@ -201,13 +131,16 @@ static const char *safe_name(struct kobject *kobj, const char *orig_name)
return
name
;
return
name
;
}
}
static
int
__of_add_property_sysfs
(
struct
device_node
*
np
,
struct
property
*
pp
)
int
__of_add_property_sysfs
(
struct
device_node
*
np
,
struct
property
*
pp
)
{
{
int
rc
;
int
rc
;
/* Important: Don't leak passwords */
/* Important: Don't leak passwords */
bool
secure
=
strncmp
(
pp
->
name
,
"security-"
,
9
)
==
0
;
bool
secure
=
strncmp
(
pp
->
name
,
"security-"
,
9
)
==
0
;
if
(
!
of_kset
||
!
of_node_is_attached
(
np
))
return
0
;
sysfs_bin_attr_init
(
&
pp
->
attr
);
sysfs_bin_attr_init
(
&
pp
->
attr
);
pp
->
attr
.
attr
.
name
=
safe_name
(
&
np
->
kobj
,
pp
->
name
);
pp
->
attr
.
attr
.
name
=
safe_name
(
&
np
->
kobj
,
pp
->
name
);
pp
->
attr
.
attr
.
mode
=
secure
?
S_IRUSR
:
S_IRUGO
;
pp
->
attr
.
attr
.
mode
=
secure
?
S_IRUSR
:
S_IRUGO
;
...
@@ -219,12 +152,15 @@ static int __of_add_property_sysfs(struct device_node *np, struct property *pp)
...
@@ -219,12 +152,15 @@ static int __of_add_property_sysfs(struct device_node *np, struct property *pp)
return
rc
;
return
rc
;
}
}
static
int
__of_node_add
(
struct
device_node
*
np
)
int
__of_attach_node_sysfs
(
struct
device_node
*
np
)
{
{
const
char
*
name
;
const
char
*
name
;
struct
property
*
pp
;
struct
property
*
pp
;
int
rc
;
int
rc
;
if
(
!
of_kset
)
return
0
;
np
->
kobj
.
kset
=
of_kset
;
np
->
kobj
.
kset
=
of_kset
;
if
(
!
np
->
parent
)
{
if
(
!
np
->
parent
)
{
/* Nodes without parents are new top level trees */
/* Nodes without parents are new top level trees */
...
@@ -246,59 +182,20 @@ static int __of_node_add(struct device_node *np)
...
@@ -246,59 +182,20 @@ static int __of_node_add(struct device_node *np)
return
0
;
return
0
;
}
}
int
of_node_add
(
struct
device_node
*
np
)
{
int
rc
=
0
;
BUG_ON
(
!
of_node_is_initialized
(
np
));
/*
* Grab the mutex here so that in a race condition between of_init() and
* of_node_add(), node addition will still be consistent.
*/
mutex_lock
(
&
of_aliases_mutex
);
if
(
of_kset
)
rc
=
__of_node_add
(
np
);
else
/* This scenario may be perfectly valid, but report it anyway */
pr_info
(
"of_node_add(%s) before of_init()
\n
"
,
np
->
full_name
);
mutex_unlock
(
&
of_aliases_mutex
);
return
rc
;
}
#if defined(CONFIG_OF_DYNAMIC)
static
void
of_node_remove
(
struct
device_node
*
np
)
{
struct
property
*
pp
;
BUG_ON
(
!
of_node_is_initialized
(
np
));
/* only remove properties if on sysfs */
if
(
of_node_is_attached
(
np
))
{
for_each_property_of_node
(
np
,
pp
)
sysfs_remove_bin_file
(
&
np
->
kobj
,
&
pp
->
attr
);
kobject_del
(
&
np
->
kobj
);
}
/* finally remove the kobj_init ref */
of_node_put
(
np
);
}
#endif
static
int
__init
of_init
(
void
)
static
int
__init
of_init
(
void
)
{
{
struct
device_node
*
np
;
struct
device_node
*
np
;
/* Create the kset, and register existing nodes */
/* Create the kset, and register existing nodes */
mutex_lock
(
&
of_
aliases_
mutex
);
mutex_lock
(
&
of_mutex
);
of_kset
=
kset_create_and_add
(
"devicetree"
,
NULL
,
firmware_kobj
);
of_kset
=
kset_create_and_add
(
"devicetree"
,
NULL
,
firmware_kobj
);
if
(
!
of_kset
)
{
if
(
!
of_kset
)
{
mutex_unlock
(
&
of_
aliases_
mutex
);
mutex_unlock
(
&
of_mutex
);
return
-
ENOMEM
;
return
-
ENOMEM
;
}
}
for_each_of_allnodes
(
np
)
for_each_of_allnodes
(
np
)
__of_
node_add
(
np
);
__of_
attach_node_sysfs
(
np
);
mutex_unlock
(
&
of_
aliases_
mutex
);
mutex_unlock
(
&
of_mutex
);
/* Symlink in /proc as required by userspace ABI */
/* Symlink in /proc as required by userspace ABI */
if
(
of_allnodes
)
if
(
of_allnodes
)
...
@@ -370,8 +267,8 @@ EXPORT_SYMBOL(of_find_all_nodes);
...
@@ -370,8 +267,8 @@ EXPORT_SYMBOL(of_find_all_nodes);
* Find a property with a given name for a given node
* Find a property with a given name for a given node
* and return the value.
* and return the value.
*/
*/
static
const
void
*
__of_get_property
(
const
struct
device_node
*
np
,
const
void
*
__of_get_property
(
const
struct
device_node
*
np
,
const
char
*
name
,
int
*
lenp
)
const
char
*
name
,
int
*
lenp
)
{
{
struct
property
*
pp
=
__of_find_property
(
np
,
name
,
lenp
);
struct
property
*
pp
=
__of_find_property
(
np
,
name
,
lenp
);
...
@@ -1749,32 +1646,10 @@ int of_count_phandle_with_args(const struct device_node *np, const char *list_na
...
@@ -1749,32 +1646,10 @@ int of_count_phandle_with_args(const struct device_node *np, const char *list_na
}
}
EXPORT_SYMBOL
(
of_count_phandle_with_args
);
EXPORT_SYMBOL
(
of_count_phandle_with_args
);
#if defined(CONFIG_OF_DYNAMIC)
static
int
of_property_notify
(
int
action
,
struct
device_node
*
np
,
struct
property
*
prop
)
{
struct
of_prop_reconfig
pr
;
/* only call notifiers if the node is attached */
if
(
!
of_node_is_attached
(
np
))
return
0
;
pr
.
dn
=
np
;
pr
.
prop
=
prop
;
return
of_reconfig_notify
(
action
,
&
pr
);
}
#else
static
int
of_property_notify
(
int
action
,
struct
device_node
*
np
,
struct
property
*
prop
)
{
return
0
;
}
#endif
/**
/**
* __of_add_property - Add a property to a node without lock operations
* __of_add_property - Add a property to a node without lock operations
*/
*/
static
int
__of_add_property
(
struct
device_node
*
np
,
struct
property
*
prop
)
int
__of_add_property
(
struct
device_node
*
np
,
struct
property
*
prop
)
{
{
struct
property
**
next
;
struct
property
**
next
;
...
@@ -1800,22 +1675,49 @@ int of_add_property(struct device_node *np, struct property *prop)
...
@@ -1800,22 +1675,49 @@ int of_add_property(struct device_node *np, struct property *prop)
unsigned
long
flags
;
unsigned
long
flags
;
int
rc
;
int
rc
;
rc
=
of_property_notify
(
OF_RECONFIG_ADD_PROPERTY
,
np
,
prop
);
mutex_lock
(
&
of_mutex
);
if
(
rc
)
return
rc
;
raw_spin_lock_irqsave
(
&
devtree_lock
,
flags
);
raw_spin_lock_irqsave
(
&
devtree_lock
,
flags
);
rc
=
__of_add_property
(
np
,
prop
);
rc
=
__of_add_property
(
np
,
prop
);
raw_spin_unlock_irqrestore
(
&
devtree_lock
,
flags
);
raw_spin_unlock_irqrestore
(
&
devtree_lock
,
flags
);
if
(
rc
)
return
rc
;
if
(
of_node_is_attached
(
np
)
)
if
(
!
rc
)
__of_add_property_sysfs
(
np
,
prop
);
__of_add_property_sysfs
(
np
,
prop
);
mutex_unlock
(
&
of_mutex
);
if
(
!
rc
)
of_property_notify
(
OF_RECONFIG_ADD_PROPERTY
,
np
,
prop
,
NULL
);
return
rc
;
return
rc
;
}
}
int
__of_remove_property
(
struct
device_node
*
np
,
struct
property
*
prop
)
{
struct
property
**
next
;
for
(
next
=
&
np
->
properties
;
*
next
;
next
=
&
(
*
next
)
->
next
)
{
if
(
*
next
==
prop
)
break
;
}
if
(
*
next
==
NULL
)
return
-
ENODEV
;
/* found the node */
*
next
=
prop
->
next
;
prop
->
next
=
np
->
deadprops
;
np
->
deadprops
=
prop
;
return
0
;
}
void
__of_remove_property_sysfs
(
struct
device_node
*
np
,
struct
property
*
prop
)
{
/* at early boot, bail here and defer setup to of_init() */
if
(
of_kset
&&
of_node_is_attached
(
np
))
sysfs_remove_bin_file
(
&
np
->
kobj
,
&
prop
->
attr
);
}
/**
/**
* of_remove_property - Remove a property from a node.
* of_remove_property - Remove a property from a node.
*
*
...
@@ -1826,211 +1728,98 @@ int of_add_property(struct device_node *np, struct property *prop)
...
@@ -1826,211 +1728,98 @@ int of_add_property(struct device_node *np, struct property *prop)
*/
*/
int
of_remove_property
(
struct
device_node
*
np
,
struct
property
*
prop
)
int
of_remove_property
(
struct
device_node
*
np
,
struct
property
*
prop
)
{
{
struct
property
**
next
;
unsigned
long
flags
;
unsigned
long
flags
;
int
found
=
0
;
int
rc
;
int
rc
;
rc
=
of_property_notify
(
OF_RECONFIG_REMOVE_PROPERTY
,
np
,
prop
);
mutex_lock
(
&
of_mutex
);
if
(
rc
)
return
rc
;
raw_spin_lock_irqsave
(
&
devtree_lock
,
flags
);
raw_spin_lock_irqsave
(
&
devtree_lock
,
flags
);
next
=
&
np
->
properties
;
rc
=
__of_remove_property
(
np
,
prop
);
while
(
*
next
)
{
if
(
*
next
==
prop
)
{
/* found the node */
*
next
=
prop
->
next
;
prop
->
next
=
np
->
deadprops
;
np
->
deadprops
=
prop
;
found
=
1
;
break
;
}
next
=
&
(
*
next
)
->
next
;
}
raw_spin_unlock_irqrestore
(
&
devtree_lock
,
flags
);
raw_spin_unlock_irqrestore
(
&
devtree_lock
,
flags
);
if
(
!
found
)
if
(
!
rc
)
return
-
ENODEV
;
__of_remove_property_sysfs
(
np
,
prop
)
;
/* at early boot, bail hear and defer setup to of_init() */
mutex_unlock
(
&
of_mutex
);
if
(
!
of_kset
)
return
0
;
sysfs_remove_bin_file
(
&
np
->
kobj
,
&
prop
->
attr
);
if
(
!
rc
)
of_property_notify
(
OF_RECONFIG_REMOVE_PROPERTY
,
np
,
prop
,
NULL
);
return
0
;
return
rc
;
}
}
/*
int
__of_update_property
(
struct
device_node
*
np
,
struct
property
*
newprop
,
* of_update_property - Update a property in a node, if the property does
struct
property
**
oldpropp
)
* not exist, add it.
*
* Note that we don't actually remove it, since we have given out
* who-knows-how-many pointers to the data using get-property.
* Instead we just move the property to the "dead properties" list,
* and add the new property to the property list
*/
int
of_update_property
(
struct
device_node
*
np
,
struct
property
*
newprop
)
{
{
struct
property
**
next
,
*
oldprop
;
struct
property
**
next
,
*
oldprop
;
unsigned
long
flags
;
int
rc
;
rc
=
of_property_notify
(
OF_RECONFIG_UPDATE_PROPERTY
,
np
,
newprop
);
if
(
rc
)
return
rc
;
if
(
!
newprop
->
name
)
for
(
next
=
&
np
->
properties
;
*
next
;
next
=
&
(
*
next
)
->
next
)
{
return
-
EINVAL
;
if
(
of_prop_cmp
((
*
next
)
->
name
,
newprop
->
name
)
==
0
)
break
;
}
*
oldpropp
=
oldprop
=
*
next
;
raw_spin_lock_irqsave
(
&
devtree_lock
,
flags
);
if
(
oldprop
)
{
next
=
&
np
->
properties
;
oldprop
=
__of_find_property
(
np
,
newprop
->
name
,
NULL
);
if
(
!
oldprop
)
{
/* add the new node */
rc
=
__of_add_property
(
np
,
newprop
);
}
else
while
(
*
next
)
{
/* replace the node */
/* replace the node */
if
(
*
next
==
oldprop
)
{
newprop
->
next
=
oldprop
->
next
;
newprop
->
next
=
oldprop
->
next
;
*
next
=
newprop
;
*
next
=
newprop
;
oldprop
->
next
=
np
->
deadprops
;
oldprop
->
next
=
np
->
deadprops
;
np
->
deadprops
=
oldprop
;
np
->
deadprops
=
oldprop
;
}
else
{
break
;
/* new node */
}
newprop
->
next
=
NULL
;
next
=
&
(
*
next
)
->
next
;
*
next
=
newprop
;
}
}
raw_spin_unlock_irqrestore
(
&
devtree_lock
,
flags
);
if
(
rc
)
return
rc
;
return
0
;
}
void
__of_update_property_sysfs
(
struct
device_node
*
np
,
struct
property
*
newprop
,
struct
property
*
oldprop
)
{
/* At early boot, bail out and defer setup to of_init() */
/* At early boot, bail out and defer setup to of_init() */
if
(
!
of_kset
)
if
(
!
of_kset
)
return
0
;
return
;
/* Update the sysfs attribute */
if
(
oldprop
)
if
(
oldprop
)
sysfs_remove_bin_file
(
&
np
->
kobj
,
&
oldprop
->
attr
);
sysfs_remove_bin_file
(
&
np
->
kobj
,
&
oldprop
->
attr
);
__of_add_property_sysfs
(
np
,
newprop
);
__of_add_property_sysfs
(
np
,
newprop
);
return
0
;
}
}
#if defined(CONFIG_OF_DYNAMIC)
/*
/*
* Support for dynamic device trees.
* of_update_property - Update a property in a node, if the property does
* not exist, add it.
*
*
* On some platforms, the device tree can be manipulated at runtime.
* Note that we don't actually remove it, since we have given out
* The routines in this section support adding, removing and changing
* who-knows-how-many pointers to the data using get-property.
* device tree nodes.
* Instead we just move the property to the "dead properties" list,
*/
* and add the new property to the property list
static
BLOCKING_NOTIFIER_HEAD
(
of_reconfig_chain
);
int
of_reconfig_notifier_register
(
struct
notifier_block
*
nb
)
{
return
blocking_notifier_chain_register
(
&
of_reconfig_chain
,
nb
);
}
EXPORT_SYMBOL_GPL
(
of_reconfig_notifier_register
);
int
of_reconfig_notifier_unregister
(
struct
notifier_block
*
nb
)
{
return
blocking_notifier_chain_unregister
(
&
of_reconfig_chain
,
nb
);
}
EXPORT_SYMBOL_GPL
(
of_reconfig_notifier_unregister
);
int
of_reconfig_notify
(
unsigned
long
action
,
void
*
p
)
{
int
rc
;
rc
=
blocking_notifier_call_chain
(
&
of_reconfig_chain
,
action
,
p
);
return
notifier_to_errno
(
rc
);
}
/**
* of_attach_node - Plug a device node into the tree and global list.
*/
*/
int
of_
attach_node
(
struct
device_node
*
n
p
)
int
of_
update_property
(
struct
device_node
*
np
,
struct
property
*
newpro
p
)
{
{
struct
property
*
oldprop
;
unsigned
long
flags
;
unsigned
long
flags
;
int
rc
;
int
rc
;
rc
=
of_reconfig_notify
(
OF_RECONFIG_ATTACH_NODE
,
np
);
if
(
!
newprop
->
name
)
if
(
rc
)
return
-
EINVAL
;
return
rc
;
raw_spin_lock_irqsave
(
&
devtree_lock
,
flags
);
np
->
sibling
=
np
->
parent
->
child
;
np
->
allnext
=
np
->
parent
->
allnext
;
np
->
parent
->
allnext
=
np
;
np
->
parent
->
child
=
np
;
of_node_clear_flag
(
np
,
OF_DETACHED
);
raw_spin_unlock_irqrestore
(
&
devtree_lock
,
flags
);
of_node_add
(
np
);
return
0
;
}
/**
* of_detach_node - "Unplug" a node from the device tree.
*
* The caller must hold a reference to the node. The memory associated with
* the node is not freed until its refcount goes to zero.
*/
int
of_detach_node
(
struct
device_node
*
np
)
{
struct
device_node
*
parent
;
unsigned
long
flags
;
int
rc
=
0
;
rc
=
of_reconfig_notify
(
OF_RECONFIG_DETACH_NODE
,
np
);
mutex_lock
(
&
of_mutex
);
if
(
rc
)
return
rc
;
raw_spin_lock_irqsave
(
&
devtree_lock
,
flags
);
raw_spin_lock_irqsave
(
&
devtree_lock
,
flags
);
rc
=
__of_update_property
(
np
,
newprop
,
&
oldprop
);
raw_spin_unlock_irqrestore
(
&
devtree_lock
,
flags
);
if
(
of_node_check_flag
(
np
,
OF_DETACHED
))
{
if
(
!
rc
)
/* someone already detached it */
__of_update_property_sysfs
(
np
,
newprop
,
oldprop
);
raw_spin_unlock_irqrestore
(
&
devtree_lock
,
flags
);
return
rc
;
}
parent
=
np
->
parent
;
if
(
!
parent
)
{
raw_spin_unlock_irqrestore
(
&
devtree_lock
,
flags
);
return
rc
;
}
if
(
of_allnodes
==
np
)
of_allnodes
=
np
->
allnext
;
else
{
struct
device_node
*
prev
;
for
(
prev
=
of_allnodes
;
prev
->
allnext
!=
np
;
prev
=
prev
->
allnext
)
;
prev
->
allnext
=
np
->
allnext
;
}
if
(
parent
->
child
==
np
)
mutex_unlock
(
&
of_mutex
);
parent
->
child
=
np
->
sibling
;
else
{
struct
device_node
*
prevsib
;
for
(
prevsib
=
np
->
parent
->
child
;
prevsib
->
sibling
!=
np
;
prevsib
=
prevsib
->
sibling
)
;
prevsib
->
sibling
=
np
->
sibling
;
}
of_node_set_flag
(
np
,
OF_DETACHED
);
if
(
!
rc
)
raw_spin_unlock_irqrestore
(
&
devtree_lock
,
flags
);
of_property_notify
(
OF_RECONFIG_UPDATE_PROPERTY
,
np
,
newprop
,
oldprop
);
of_node_remove
(
np
);
return
rc
;
return
rc
;
}
}
#endif
/* defined(CONFIG_OF_DYNAMIC) */
static
void
of_alias_add
(
struct
alias_prop
*
ap
,
struct
device_node
*
np
,
static
void
of_alias_add
(
struct
alias_prop
*
ap
,
struct
device_node
*
np
,
int
id
,
const
char
*
stem
,
int
stem_len
)
int
id
,
const
char
*
stem
,
int
stem_len
)
...
@@ -2126,7 +1915,7 @@ int of_alias_get_id(struct device_node *np, const char *stem)
...
@@ -2126,7 +1915,7 @@ int of_alias_get_id(struct device_node *np, const char *stem)
struct
alias_prop
*
app
;
struct
alias_prop
*
app
;
int
id
=
-
ENODEV
;
int
id
=
-
ENODEV
;
mutex_lock
(
&
of_
aliases_
mutex
);
mutex_lock
(
&
of_mutex
);
list_for_each_entry
(
app
,
&
aliases_lookup
,
link
)
{
list_for_each_entry
(
app
,
&
aliases_lookup
,
link
)
{
if
(
strcmp
(
app
->
stem
,
stem
)
!=
0
)
if
(
strcmp
(
app
->
stem
,
stem
)
!=
0
)
continue
;
continue
;
...
@@ -2136,7 +1925,7 @@ int of_alias_get_id(struct device_node *np, const char *stem)
...
@@ -2136,7 +1925,7 @@ int of_alias_get_id(struct device_node *np, const char *stem)
break
;
break
;
}
}
}
}
mutex_unlock
(
&
of_
aliases_
mutex
);
mutex_unlock
(
&
of_mutex
);
return
id
;
return
id
;
}
}
...
...
drivers/of/device.c
浏览文件 @
663d3f7c
...
@@ -160,7 +160,7 @@ void of_device_uevent(struct device *dev, struct kobj_uevent_env *env)
...
@@ -160,7 +160,7 @@ void of_device_uevent(struct device *dev, struct kobj_uevent_env *env)
add_uevent_var
(
env
,
"OF_COMPATIBLE_N=%d"
,
seen
);
add_uevent_var
(
env
,
"OF_COMPATIBLE_N=%d"
,
seen
);
seen
=
0
;
seen
=
0
;
mutex_lock
(
&
of_
aliases_
mutex
);
mutex_lock
(
&
of_mutex
);
list_for_each_entry
(
app
,
&
aliases_lookup
,
link
)
{
list_for_each_entry
(
app
,
&
aliases_lookup
,
link
)
{
if
(
dev
->
of_node
==
app
->
np
)
{
if
(
dev
->
of_node
==
app
->
np
)
{
add_uevent_var
(
env
,
"OF_ALIAS_%d=%s"
,
seen
,
add_uevent_var
(
env
,
"OF_ALIAS_%d=%s"
,
seen
,
...
@@ -168,7 +168,7 @@ void of_device_uevent(struct device *dev, struct kobj_uevent_env *env)
...
@@ -168,7 +168,7 @@ void of_device_uevent(struct device *dev, struct kobj_uevent_env *env)
seen
++
;
seen
++
;
}
}
}
}
mutex_unlock
(
&
of_
aliases_
mutex
);
mutex_unlock
(
&
of_mutex
);
}
}
int
of_device_uevent_modalias
(
struct
device
*
dev
,
struct
kobj_uevent_env
*
env
)
int
of_device_uevent_modalias
(
struct
device
*
dev
,
struct
kobj_uevent_env
*
env
)
...
...
drivers/of/dynamic.c
0 → 100644
浏览文件 @
663d3f7c
/*
* Support for dynamic device trees.
*
* On some platforms, the device tree can be manipulated at runtime.
* The routines in this section support adding, removing and changing
* device tree nodes.
*/
#include <linux/of.h>
#include <linux/spinlock.h>
#include <linux/slab.h>
#include <linux/string.h>
#include <linux/proc_fs.h>
#include "of_private.h"
/**
* of_node_get() - Increment refcount of a node
* @node: Node to inc refcount, NULL is supported to simplify writing of
* callers
*
* Returns node.
*/
struct
device_node
*
of_node_get
(
struct
device_node
*
node
)
{
if
(
node
)
kobject_get
(
&
node
->
kobj
);
return
node
;
}
EXPORT_SYMBOL
(
of_node_get
);
/**
* of_node_put() - Decrement refcount of a node
* @node: Node to dec refcount, NULL is supported to simplify writing of
* callers
*/
void
of_node_put
(
struct
device_node
*
node
)
{
if
(
node
)
kobject_put
(
&
node
->
kobj
);
}
EXPORT_SYMBOL
(
of_node_put
);
void
__of_detach_node_sysfs
(
struct
device_node
*
np
)
{
struct
property
*
pp
;
BUG_ON
(
!
of_node_is_initialized
(
np
));
if
(
!
of_kset
)
return
;
/* only remove properties if on sysfs */
if
(
of_node_is_attached
(
np
))
{
for_each_property_of_node
(
np
,
pp
)
sysfs_remove_bin_file
(
&
np
->
kobj
,
&
pp
->
attr
);
kobject_del
(
&
np
->
kobj
);
}
/* finally remove the kobj_init ref */
of_node_put
(
np
);
}
static
BLOCKING_NOTIFIER_HEAD
(
of_reconfig_chain
);
int
of_reconfig_notifier_register
(
struct
notifier_block
*
nb
)
{
return
blocking_notifier_chain_register
(
&
of_reconfig_chain
,
nb
);
}
EXPORT_SYMBOL_GPL
(
of_reconfig_notifier_register
);
int
of_reconfig_notifier_unregister
(
struct
notifier_block
*
nb
)
{
return
blocking_notifier_chain_unregister
(
&
of_reconfig_chain
,
nb
);
}
EXPORT_SYMBOL_GPL
(
of_reconfig_notifier_unregister
);
int
of_reconfig_notify
(
unsigned
long
action
,
void
*
p
)
{
int
rc
;
rc
=
blocking_notifier_call_chain
(
&
of_reconfig_chain
,
action
,
p
);
return
notifier_to_errno
(
rc
);
}
int
of_property_notify
(
int
action
,
struct
device_node
*
np
,
struct
property
*
prop
,
struct
property
*
oldprop
)
{
struct
of_prop_reconfig
pr
;
/* only call notifiers if the node is attached */
if
(
!
of_node_is_attached
(
np
))
return
0
;
pr
.
dn
=
np
;
pr
.
prop
=
prop
;
pr
.
old_prop
=
oldprop
;
return
of_reconfig_notify
(
action
,
&
pr
);
}
void
__of_attach_node
(
struct
device_node
*
np
)
{
const
__be32
*
phandle
;
int
sz
;
np
->
name
=
__of_get_property
(
np
,
"name"
,
NULL
)
?
:
"<NULL>"
;
np
->
type
=
__of_get_property
(
np
,
"device_type"
,
NULL
)
?
:
"<NULL>"
;
phandle
=
__of_get_property
(
np
,
"phandle"
,
&
sz
);
if
(
!
phandle
)
phandle
=
__of_get_property
(
np
,
"linux,phandle"
,
&
sz
);
if
(
IS_ENABLED
(
PPC_PSERIES
)
&&
!
phandle
)
phandle
=
__of_get_property
(
np
,
"ibm,phandle"
,
&
sz
);
np
->
phandle
=
(
phandle
&&
(
sz
>=
4
))
?
be32_to_cpup
(
phandle
)
:
0
;
np
->
child
=
NULL
;
np
->
sibling
=
np
->
parent
->
child
;
np
->
allnext
=
np
->
parent
->
allnext
;
np
->
parent
->
allnext
=
np
;
np
->
parent
->
child
=
np
;
of_node_clear_flag
(
np
,
OF_DETACHED
);
}
/**
* of_attach_node() - Plug a device node into the tree and global list.
*/
int
of_attach_node
(
struct
device_node
*
np
)
{
unsigned
long
flags
;
mutex_lock
(
&
of_mutex
);
raw_spin_lock_irqsave
(
&
devtree_lock
,
flags
);
__of_attach_node
(
np
);
raw_spin_unlock_irqrestore
(
&
devtree_lock
,
flags
);
__of_attach_node_sysfs
(
np
);
mutex_unlock
(
&
of_mutex
);
of_reconfig_notify
(
OF_RECONFIG_ATTACH_NODE
,
np
);
return
0
;
}
void
__of_detach_node
(
struct
device_node
*
np
)
{
struct
device_node
*
parent
;
if
(
WARN_ON
(
of_node_check_flag
(
np
,
OF_DETACHED
)))
return
;
parent
=
np
->
parent
;
if
(
WARN_ON
(
!
parent
))
return
;
if
(
of_allnodes
==
np
)
of_allnodes
=
np
->
allnext
;
else
{
struct
device_node
*
prev
;
for
(
prev
=
of_allnodes
;
prev
->
allnext
!=
np
;
prev
=
prev
->
allnext
)
;
prev
->
allnext
=
np
->
allnext
;
}
if
(
parent
->
child
==
np
)
parent
->
child
=
np
->
sibling
;
else
{
struct
device_node
*
prevsib
;
for
(
prevsib
=
np
->
parent
->
child
;
prevsib
->
sibling
!=
np
;
prevsib
=
prevsib
->
sibling
)
;
prevsib
->
sibling
=
np
->
sibling
;
}
of_node_set_flag
(
np
,
OF_DETACHED
);
}
/**
* of_detach_node() - "Unplug" a node from the device tree.
*
* The caller must hold a reference to the node. The memory associated with
* the node is not freed until its refcount goes to zero.
*/
int
of_detach_node
(
struct
device_node
*
np
)
{
unsigned
long
flags
;
int
rc
=
0
;
mutex_lock
(
&
of_mutex
);
raw_spin_lock_irqsave
(
&
devtree_lock
,
flags
);
__of_detach_node
(
np
);
raw_spin_unlock_irqrestore
(
&
devtree_lock
,
flags
);
__of_detach_node_sysfs
(
np
);
mutex_unlock
(
&
of_mutex
);
of_reconfig_notify
(
OF_RECONFIG_DETACH_NODE
,
np
);
return
rc
;
}
/**
* of_node_release() - release a dynamically allocated node
* @kref: kref element of the node to be released
*
* In of_node_put() this function is passed to kref_put() as the destructor.
*/
void
of_node_release
(
struct
kobject
*
kobj
)
{
struct
device_node
*
node
=
kobj_to_device_node
(
kobj
);
struct
property
*
prop
=
node
->
properties
;
/* We should never be releasing nodes that haven't been detached. */
if
(
!
of_node_check_flag
(
node
,
OF_DETACHED
))
{
pr_err
(
"ERROR: Bad of_node_put() on %s
\n
"
,
node
->
full_name
);
dump_stack
();
return
;
}
if
(
!
of_node_check_flag
(
node
,
OF_DYNAMIC
))
return
;
while
(
prop
)
{
struct
property
*
next
=
prop
->
next
;
kfree
(
prop
->
name
);
kfree
(
prop
->
value
);
kfree
(
prop
);
prop
=
next
;
if
(
!
prop
)
{
prop
=
node
->
deadprops
;
node
->
deadprops
=
NULL
;
}
}
kfree
(
node
->
full_name
);
kfree
(
node
->
data
);
kfree
(
node
);
}
/**
* __of_prop_dup - Copy a property dynamically.
* @prop: Property to copy
* @allocflags: Allocation flags (typically pass GFP_KERNEL)
*
* Copy a property by dynamically allocating the memory of both the
* property stucture and the property name & contents. The property's
* flags have the OF_DYNAMIC bit set so that we can differentiate between
* dynamically allocated properties and not.
* Returns the newly allocated property or NULL on out of memory error.
*/
struct
property
*
__of_prop_dup
(
const
struct
property
*
prop
,
gfp_t
allocflags
)
{
struct
property
*
new
;
new
=
kzalloc
(
sizeof
(
*
new
),
allocflags
);
if
(
!
new
)
return
NULL
;
/*
* NOTE: There is no check for zero length value.
* In case of a boolean property, this will allocate a value
* of zero bytes. We do this to work around the use
* of of_get_property() calls on boolean values.
*/
new
->
name
=
kstrdup
(
prop
->
name
,
allocflags
);
new
->
value
=
kmemdup
(
prop
->
value
,
prop
->
length
,
allocflags
);
new
->
length
=
prop
->
length
;
if
(
!
new
->
name
||
!
new
->
value
)
goto
err_free
;
/* mark the property as dynamic */
of_property_set_flag
(
new
,
OF_DYNAMIC
);
return
new
;
err_free:
kfree
(
new
->
name
);
kfree
(
new
->
value
);
kfree
(
new
);
return
NULL
;
}
/**
* __of_node_alloc() - Create an empty device node dynamically.
* @full_name: Full name of the new device node
* @allocflags: Allocation flags (typically pass GFP_KERNEL)
*
* Create an empty device tree node, suitable for further modification.
* The node data are dynamically allocated and all the node flags
* have the OF_DYNAMIC & OF_DETACHED bits set.
* Returns the newly allocated node or NULL on out of memory error.
*/
struct
device_node
*
__of_node_alloc
(
const
char
*
full_name
,
gfp_t
allocflags
)
{
struct
device_node
*
node
;
node
=
kzalloc
(
sizeof
(
*
node
),
allocflags
);
if
(
!
node
)
return
NULL
;
node
->
full_name
=
kstrdup
(
full_name
,
allocflags
);
of_node_set_flag
(
node
,
OF_DYNAMIC
);
of_node_set_flag
(
node
,
OF_DETACHED
);
if
(
!
node
->
full_name
)
goto
err_free
;
of_node_init
(
node
);
return
node
;
err_free:
kfree
(
node
->
full_name
);
kfree
(
node
);
return
NULL
;
}
static
void
__of_changeset_entry_destroy
(
struct
of_changeset_entry
*
ce
)
{
of_node_put
(
ce
->
np
);
list_del
(
&
ce
->
node
);
kfree
(
ce
);
}
#ifdef DEBUG
static
void
__of_changeset_entry_dump
(
struct
of_changeset_entry
*
ce
)
{
switch
(
ce
->
action
)
{
case
OF_RECONFIG_ADD_PROPERTY
:
pr_debug
(
"%p: %s %s/%s
\n
"
,
ce
,
"ADD_PROPERTY "
,
ce
->
np
->
full_name
,
ce
->
prop
->
name
);
break
;
case
OF_RECONFIG_REMOVE_PROPERTY
:
pr_debug
(
"%p: %s %s/%s
\n
"
,
ce
,
"REMOVE_PROPERTY"
,
ce
->
np
->
full_name
,
ce
->
prop
->
name
);
break
;
case
OF_RECONFIG_UPDATE_PROPERTY
:
pr_debug
(
"%p: %s %s/%s
\n
"
,
ce
,
"UPDATE_PROPERTY"
,
ce
->
np
->
full_name
,
ce
->
prop
->
name
);
break
;
case
OF_RECONFIG_ATTACH_NODE
:
pr_debug
(
"%p: %s %s
\n
"
,
ce
,
"ATTACH_NODE "
,
ce
->
np
->
full_name
);
break
;
case
OF_RECONFIG_DETACH_NODE
:
pr_debug
(
"%p: %s %s
\n
"
,
ce
,
"DETACH_NODE "
,
ce
->
np
->
full_name
);
break
;
}
}
#else
static
inline
void
__of_changeset_entry_dump
(
struct
of_changeset_entry
*
ce
)
{
/* empty */
}
#endif
static
void
__of_changeset_entry_invert
(
struct
of_changeset_entry
*
ce
,
struct
of_changeset_entry
*
rce
)
{
memcpy
(
rce
,
ce
,
sizeof
(
*
rce
));
switch
(
ce
->
action
)
{
case
OF_RECONFIG_ATTACH_NODE
:
rce
->
action
=
OF_RECONFIG_DETACH_NODE
;
break
;
case
OF_RECONFIG_DETACH_NODE
:
rce
->
action
=
OF_RECONFIG_ATTACH_NODE
;
break
;
case
OF_RECONFIG_ADD_PROPERTY
:
rce
->
action
=
OF_RECONFIG_REMOVE_PROPERTY
;
break
;
case
OF_RECONFIG_REMOVE_PROPERTY
:
rce
->
action
=
OF_RECONFIG_ADD_PROPERTY
;
break
;
case
OF_RECONFIG_UPDATE_PROPERTY
:
rce
->
old_prop
=
ce
->
prop
;
rce
->
prop
=
ce
->
old_prop
;
break
;
}
}
static
void
__of_changeset_entry_notify
(
struct
of_changeset_entry
*
ce
,
bool
revert
)
{
struct
of_changeset_entry
ce_inverted
;
int
ret
;
if
(
revert
)
{
__of_changeset_entry_invert
(
ce
,
&
ce_inverted
);
ce
=
&
ce_inverted
;
}
switch
(
ce
->
action
)
{
case
OF_RECONFIG_ATTACH_NODE
:
case
OF_RECONFIG_DETACH_NODE
:
ret
=
of_reconfig_notify
(
ce
->
action
,
ce
->
np
);
break
;
case
OF_RECONFIG_ADD_PROPERTY
:
case
OF_RECONFIG_REMOVE_PROPERTY
:
case
OF_RECONFIG_UPDATE_PROPERTY
:
ret
=
of_property_notify
(
ce
->
action
,
ce
->
np
,
ce
->
prop
,
ce
->
old_prop
);
break
;
default:
pr_err
(
"%s: invalid devicetree changeset action: %i
\n
"
,
__func__
,
(
int
)
ce
->
action
);
return
;
}
if
(
ret
)
pr_err
(
"%s: notifier error @%s
\n
"
,
__func__
,
ce
->
np
->
full_name
);
}
static
int
__of_changeset_entry_apply
(
struct
of_changeset_entry
*
ce
)
{
struct
property
*
old_prop
,
**
propp
;
unsigned
long
flags
;
int
ret
=
0
;
__of_changeset_entry_dump
(
ce
);
raw_spin_lock_irqsave
(
&
devtree_lock
,
flags
);
switch
(
ce
->
action
)
{
case
OF_RECONFIG_ATTACH_NODE
:
__of_attach_node
(
ce
->
np
);
break
;
case
OF_RECONFIG_DETACH_NODE
:
__of_detach_node
(
ce
->
np
);
break
;
case
OF_RECONFIG_ADD_PROPERTY
:
/* If the property is in deadprops then it must be removed */
for
(
propp
=
&
ce
->
np
->
deadprops
;
*
propp
;
propp
=
&
(
*
propp
)
->
next
)
{
if
(
*
propp
==
ce
->
prop
)
{
*
propp
=
ce
->
prop
->
next
;
ce
->
prop
->
next
=
NULL
;
break
;
}
}
ret
=
__of_add_property
(
ce
->
np
,
ce
->
prop
);
if
(
ret
)
{
pr_err
(
"%s: add_property failed @%s/%s
\n
"
,
__func__
,
ce
->
np
->
full_name
,
ce
->
prop
->
name
);
break
;
}
break
;
case
OF_RECONFIG_REMOVE_PROPERTY
:
ret
=
__of_remove_property
(
ce
->
np
,
ce
->
prop
);
if
(
ret
)
{
pr_err
(
"%s: remove_property failed @%s/%s
\n
"
,
__func__
,
ce
->
np
->
full_name
,
ce
->
prop
->
name
);
break
;
}
break
;
case
OF_RECONFIG_UPDATE_PROPERTY
:
/* If the property is in deadprops then it must be removed */
for
(
propp
=
&
ce
->
np
->
deadprops
;
*
propp
;
propp
=
&
(
*
propp
)
->
next
)
{
if
(
*
propp
==
ce
->
prop
)
{
*
propp
=
ce
->
prop
->
next
;
ce
->
prop
->
next
=
NULL
;
break
;
}
}
ret
=
__of_update_property
(
ce
->
np
,
ce
->
prop
,
&
old_prop
);
if
(
ret
)
{
pr_err
(
"%s: update_property failed @%s/%s
\n
"
,
__func__
,
ce
->
np
->
full_name
,
ce
->
prop
->
name
);
break
;
}
break
;
default:
ret
=
-
EINVAL
;
}
raw_spin_unlock_irqrestore
(
&
devtree_lock
,
flags
);
if
(
ret
)
return
ret
;
switch
(
ce
->
action
)
{
case
OF_RECONFIG_ATTACH_NODE
:
__of_attach_node_sysfs
(
ce
->
np
);
break
;
case
OF_RECONFIG_DETACH_NODE
:
__of_detach_node_sysfs
(
ce
->
np
);
break
;
case
OF_RECONFIG_ADD_PROPERTY
:
/* ignore duplicate names */
__of_add_property_sysfs
(
ce
->
np
,
ce
->
prop
);
break
;
case
OF_RECONFIG_REMOVE_PROPERTY
:
__of_remove_property_sysfs
(
ce
->
np
,
ce
->
prop
);
break
;
case
OF_RECONFIG_UPDATE_PROPERTY
:
__of_update_property_sysfs
(
ce
->
np
,
ce
->
prop
,
ce
->
old_prop
);
break
;
}
return
0
;
}
static
inline
int
__of_changeset_entry_revert
(
struct
of_changeset_entry
*
ce
)
{
struct
of_changeset_entry
ce_inverted
;
__of_changeset_entry_invert
(
ce
,
&
ce_inverted
);
return
__of_changeset_entry_apply
(
&
ce_inverted
);
}
/**
* of_changeset_init - Initialize a changeset for use
*
* @ocs: changeset pointer
*
* Initialize a changeset structure
*/
void
of_changeset_init
(
struct
of_changeset
*
ocs
)
{
memset
(
ocs
,
0
,
sizeof
(
*
ocs
));
INIT_LIST_HEAD
(
&
ocs
->
entries
);
}
/**
* of_changeset_destroy - Destroy a changeset
*
* @ocs: changeset pointer
*
* Destroys a changeset. Note that if a changeset is applied,
* its changes to the tree cannot be reverted.
*/
void
of_changeset_destroy
(
struct
of_changeset
*
ocs
)
{
struct
of_changeset_entry
*
ce
,
*
cen
;
list_for_each_entry_safe_reverse
(
ce
,
cen
,
&
ocs
->
entries
,
node
)
__of_changeset_entry_destroy
(
ce
);
}
/**
* of_changeset_apply - Applies a changeset
*
* @ocs: changeset pointer
*
* Applies a changeset to the live tree.
* Any side-effects of live tree state changes are applied here on
* sucess, like creation/destruction of devices and side-effects
* like creation of sysfs properties and directories.
* Returns 0 on success, a negative error value in case of an error.
* On error the partially applied effects are reverted.
*/
int
of_changeset_apply
(
struct
of_changeset
*
ocs
)
{
struct
of_changeset_entry
*
ce
;
int
ret
;
/* perform the rest of the work */
pr_debug
(
"of_changeset: applying...
\n
"
);
list_for_each_entry
(
ce
,
&
ocs
->
entries
,
node
)
{
ret
=
__of_changeset_entry_apply
(
ce
);
if
(
ret
)
{
pr_err
(
"%s: Error applying changeset (%d)
\n
"
,
__func__
,
ret
);
list_for_each_entry_continue_reverse
(
ce
,
&
ocs
->
entries
,
node
)
__of_changeset_entry_revert
(
ce
);
return
ret
;
}
}
pr_debug
(
"of_changeset: applied, emitting notifiers.
\n
"
);
/* drop the global lock while emitting notifiers */
mutex_unlock
(
&
of_mutex
);
list_for_each_entry
(
ce
,
&
ocs
->
entries
,
node
)
__of_changeset_entry_notify
(
ce
,
0
);
mutex_lock
(
&
of_mutex
);
pr_debug
(
"of_changeset: notifiers sent.
\n
"
);
return
0
;
}
/**
* of_changeset_revert - Reverts an applied changeset
*
* @ocs: changeset pointer
*
* Reverts a changeset returning the state of the tree to what it
* was before the application.
* Any side-effects like creation/destruction of devices and
* removal of sysfs properties and directories are applied.
* Returns 0 on success, a negative error value in case of an error.
*/
int
of_changeset_revert
(
struct
of_changeset
*
ocs
)
{
struct
of_changeset_entry
*
ce
;
int
ret
;
pr_debug
(
"of_changeset: reverting...
\n
"
);
list_for_each_entry_reverse
(
ce
,
&
ocs
->
entries
,
node
)
{
ret
=
__of_changeset_entry_revert
(
ce
);
if
(
ret
)
{
pr_err
(
"%s: Error reverting changeset (%d)
\n
"
,
__func__
,
ret
);
list_for_each_entry_continue
(
ce
,
&
ocs
->
entries
,
node
)
__of_changeset_entry_apply
(
ce
);
return
ret
;
}
}
pr_debug
(
"of_changeset: reverted, emitting notifiers.
\n
"
);
/* drop the global lock while emitting notifiers */
mutex_unlock
(
&
of_mutex
);
list_for_each_entry_reverse
(
ce
,
&
ocs
->
entries
,
node
)
__of_changeset_entry_notify
(
ce
,
1
);
mutex_lock
(
&
of_mutex
);
pr_debug
(
"of_changeset: notifiers sent.
\n
"
);
return
0
;
}
/**
* of_changeset_action - Perform a changeset action
*
* @ocs: changeset pointer
* @action: action to perform
* @np: Pointer to device node
* @prop: Pointer to property
*
* On action being one of:
* + OF_RECONFIG_ATTACH_NODE
* + OF_RECONFIG_DETACH_NODE,
* + OF_RECONFIG_ADD_PROPERTY
* + OF_RECONFIG_REMOVE_PROPERTY,
* + OF_RECONFIG_UPDATE_PROPERTY
* Returns 0 on success, a negative error value in case of an error.
*/
int
of_changeset_action
(
struct
of_changeset
*
ocs
,
unsigned
long
action
,
struct
device_node
*
np
,
struct
property
*
prop
)
{
struct
of_changeset_entry
*
ce
;
ce
=
kzalloc
(
sizeof
(
*
ce
),
GFP_KERNEL
);
if
(
!
ce
)
{
pr_err
(
"%s: Failed to allocate
\n
"
,
__func__
);
return
-
ENOMEM
;
}
/* get a reference to the node */
ce
->
action
=
action
;
ce
->
np
=
of_node_get
(
np
);
ce
->
prop
=
prop
;
if
(
action
==
OF_RECONFIG_UPDATE_PROPERTY
&&
prop
)
ce
->
old_prop
=
of_find_property
(
np
,
prop
->
name
,
NULL
);
/* add it to the list */
list_add_tail
(
&
ce
->
node
,
&
ocs
->
entries
);
return
0
;
}
drivers/of/of_private.h
浏览文件 @
663d3f7c
...
@@ -31,6 +31,63 @@ struct alias_prop {
...
@@ -31,6 +31,63 @@ struct alias_prop {
char
stem
[
0
];
char
stem
[
0
];
};
};
extern
struct
mutex
of_
aliases_
mutex
;
extern
struct
mutex
of_mutex
;
extern
struct
list_head
aliases_lookup
;
extern
struct
list_head
aliases_lookup
;
extern
struct
kset
*
of_kset
;
static
inline
struct
device_node
*
kobj_to_device_node
(
struct
kobject
*
kobj
)
{
return
container_of
(
kobj
,
struct
device_node
,
kobj
);
}
#if defined(CONFIG_OF_DYNAMIC)
extern
int
of_property_notify
(
int
action
,
struct
device_node
*
np
,
struct
property
*
prop
,
struct
property
*
old_prop
);
extern
void
of_node_release
(
struct
kobject
*
kobj
);
#else
/* CONFIG_OF_DYNAMIC */
static
inline
int
of_property_notify
(
int
action
,
struct
device_node
*
np
,
struct
property
*
prop
,
struct
property
*
old_prop
)
{
return
0
;
}
#endif
/* CONFIG_OF_DYNAMIC */
/**
* General utilities for working with live trees.
*
* All functions with two leading underscores operate
* without taking node references, so you either have to
* own the devtree lock or work on detached trees only.
*/
struct
property
*
__of_prop_dup
(
const
struct
property
*
prop
,
gfp_t
allocflags
);
struct
device_node
*
__of_node_alloc
(
const
char
*
full_name
,
gfp_t
allocflags
);
extern
const
void
*
__of_get_property
(
const
struct
device_node
*
np
,
const
char
*
name
,
int
*
lenp
);
extern
int
__of_add_property
(
struct
device_node
*
np
,
struct
property
*
prop
);
extern
int
__of_add_property_sysfs
(
struct
device_node
*
np
,
struct
property
*
prop
);
extern
int
__of_remove_property
(
struct
device_node
*
np
,
struct
property
*
prop
);
extern
void
__of_remove_property_sysfs
(
struct
device_node
*
np
,
struct
property
*
prop
);
extern
int
__of_update_property
(
struct
device_node
*
np
,
struct
property
*
newprop
,
struct
property
**
oldprop
);
extern
void
__of_update_property_sysfs
(
struct
device_node
*
np
,
struct
property
*
newprop
,
struct
property
*
oldprop
);
extern
void
__of_attach_node
(
struct
device_node
*
np
);
extern
int
__of_attach_node_sysfs
(
struct
device_node
*
np
);
extern
void
__of_detach_node
(
struct
device_node
*
np
);
extern
void
__of_detach_node_sysfs
(
struct
device_node
*
np
);
/* iterators for transactions, used for overlays */
/* forward iterator */
#define for_each_transaction_entry(_oft, _te) \
list_for_each_entry(_te, &(_oft)->te_list, node)
/* reverse iterator */
#define for_each_transaction_entry_reverse(_oft, _te) \
list_for_each_entry_reverse(_te, &(_oft)->te_list, node)
#endif
/* _LINUX_OF_PRIVATE_H */
#endif
/* _LINUX_OF_PRIVATE_H */
drivers/of/platform.c
浏览文件 @
663d3f7c
...
@@ -422,6 +422,7 @@ static int of_platform_bus_create(struct device_node *bus,
...
@@ -422,6 +422,7 @@ static int of_platform_bus_create(struct device_node *bus,
break
;
break
;
}
}
}
}
of_node_set_flag
(
bus
,
OF_POPULATED_BUS
);
return
rc
;
return
rc
;
}
}
...
@@ -508,19 +509,13 @@ EXPORT_SYMBOL_GPL(of_platform_populate);
...
@@ -508,19 +509,13 @@ EXPORT_SYMBOL_GPL(of_platform_populate);
static
int
of_platform_device_destroy
(
struct
device
*
dev
,
void
*
data
)
static
int
of_platform_device_destroy
(
struct
device
*
dev
,
void
*
data
)
{
{
bool
*
children_left
=
data
;
/* Do not touch devices not populated from the device tree */
/* Do not touch devices not populated from the device tree */
if
(
!
dev
->
of_node
||
!
of_node_check_flag
(
dev
->
of_node
,
OF_POPULATED
))
{
if
(
!
dev
->
of_node
||
!
of_node_check_flag
(
dev
->
of_node
,
OF_POPULATED
))
*
children_left
=
true
;
return
0
;
return
0
;
}
/* Recurse, but don't touch this device if it has any children left */
/* Recurse for any nodes that were treated as busses */
if
(
of_platform_depopulate
(
dev
)
!=
0
)
{
if
(
of_node_check_flag
(
dev
->
of_node
,
OF_POPULATED_BUS
))
*
children_left
=
true
;
device_for_each_child
(
dev
,
NULL
,
of_platform_device_destroy
);
return
0
;
}
if
(
dev
->
bus
==
&
platform_bus_type
)
if
(
dev
->
bus
==
&
platform_bus_type
)
platform_device_unregister
(
to_platform_device
(
dev
));
platform_device_unregister
(
to_platform_device
(
dev
));
...
@@ -528,19 +523,15 @@ static int of_platform_device_destroy(struct device *dev, void *data)
...
@@ -528,19 +523,15 @@ static int of_platform_device_destroy(struct device *dev, void *data)
else
if
(
dev
->
bus
==
&
amba_bustype
)
else
if
(
dev
->
bus
==
&
amba_bustype
)
amba_device_unregister
(
to_amba_device
(
dev
));
amba_device_unregister
(
to_amba_device
(
dev
));
#endif
#endif
else
{
*
children_left
=
true
;
return
0
;
}
of_node_clear_flag
(
dev
->
of_node
,
OF_POPULATED
);
of_node_clear_flag
(
dev
->
of_node
,
OF_POPULATED
);
of_node_clear_flag
(
dev
->
of_node
,
OF_POPULATED_BUS
);
return
0
;
return
0
;
}
}
/**
/**
* of_platform_depopulate() - Remove devices populated from device tree
* of_platform_depopulate() - Remove devices populated from device tree
* @parent: device which childre
d
will be removed
* @parent: device which childre
n
will be removed
*
*
* Complementary to of_platform_populate(), this function removes children
* Complementary to of_platform_populate(), this function removes children
* of the given device (and, recurrently, their children) that have been
* of the given device (and, recurrently, their children) that have been
...
@@ -550,14 +541,9 @@ static int of_platform_device_destroy(struct device *dev, void *data)
...
@@ -550,14 +541,9 @@ static int of_platform_device_destroy(struct device *dev, void *data)
* Returns 0 when all children devices have been removed or
* Returns 0 when all children devices have been removed or
* -EBUSY when some children remained.
* -EBUSY when some children remained.
*/
*/
int
of_platform_depopulate
(
struct
device
*
parent
)
void
of_platform_depopulate
(
struct
device
*
parent
)
{
{
bool
children_left
=
false
;
device_for_each_child
(
parent
,
NULL
,
of_platform_device_destroy
);
device_for_each_child
(
parent
,
&
children_left
,
of_platform_device_destroy
);
return
children_left
?
-
EBUSY
:
0
;
}
}
EXPORT_SYMBOL_GPL
(
of_platform_depopulate
);
EXPORT_SYMBOL_GPL
(
of_platform_depopulate
);
...
...
drivers/of/selftest.c
浏览文件 @
663d3f7c
...
@@ -17,6 +17,8 @@
...
@@ -17,6 +17,8 @@
#include <linux/slab.h>
#include <linux/slab.h>
#include <linux/device.h>
#include <linux/device.h>
#include "of_private.h"
static
struct
selftest_results
{
static
struct
selftest_results
{
int
passed
;
int
passed
;
int
failed
;
int
failed
;
...
@@ -271,6 +273,81 @@ static void __init of_selftest_property_match_string(void)
...
@@ -271,6 +273,81 @@ static void __init of_selftest_property_match_string(void)
selftest
(
rc
==
-
EILSEQ
,
"unterminated string; rc=%i"
,
rc
);
selftest
(
rc
==
-
EILSEQ
,
"unterminated string; rc=%i"
,
rc
);
}
}
#define propcmp(p1, p2) (((p1)->length == (p2)->length) && \
(p1)->value && (p2)->value && \
!memcmp((p1)->value, (p2)->value, (p1)->length) && \
!strcmp((p1)->name, (p2)->name))
static
void
__init
of_selftest_property_copy
(
void
)
{
#ifdef CONFIG_OF_DYNAMIC
struct
property
p1
=
{
.
name
=
"p1"
,
.
length
=
0
,
.
value
=
""
};
struct
property
p2
=
{
.
name
=
"p2"
,
.
length
=
5
,
.
value
=
"abcd"
};
struct
property
*
new
;
new
=
__of_prop_dup
(
&
p1
,
GFP_KERNEL
);
selftest
(
new
&&
propcmp
(
&
p1
,
new
),
"empty property didn't copy correctly
\n
"
);
kfree
(
new
->
value
);
kfree
(
new
->
name
);
kfree
(
new
);
new
=
__of_prop_dup
(
&
p2
,
GFP_KERNEL
);
selftest
(
new
&&
propcmp
(
&
p2
,
new
),
"non-empty property didn't copy correctly
\n
"
);
kfree
(
new
->
value
);
kfree
(
new
->
name
);
kfree
(
new
);
#endif
}
static
void
__init
of_selftest_changeset
(
void
)
{
#ifdef CONFIG_OF_DYNAMIC
struct
property
*
ppadd
,
padd
=
{
.
name
=
"prop-add"
,
.
length
=
0
,
.
value
=
""
};
struct
property
*
ppupdate
,
pupdate
=
{
.
name
=
"prop-update"
,
.
length
=
5
,
.
value
=
"abcd"
};
struct
property
*
ppremove
;
struct
device_node
*
n1
,
*
n2
,
*
n21
,
*
nremove
,
*
parent
;
struct
of_changeset
chgset
;
of_changeset_init
(
&
chgset
);
n1
=
__of_node_alloc
(
"/testcase-data/changeset/n1"
,
GFP_KERNEL
);
selftest
(
n1
,
"testcase setup failure
\n
"
);
n2
=
__of_node_alloc
(
"/testcase-data/changeset/n2"
,
GFP_KERNEL
);
selftest
(
n2
,
"testcase setup failure
\n
"
);
n21
=
__of_node_alloc
(
"/testcase-data/changeset/n2/n21"
,
GFP_KERNEL
);
selftest
(
n21
,
"testcase setup failure %p
\n
"
,
n21
);
nremove
=
of_find_node_by_path
(
"/testcase-data/changeset/node-remove"
);
selftest
(
nremove
,
"testcase setup failure
\n
"
);
ppadd
=
__of_prop_dup
(
&
padd
,
GFP_KERNEL
);
selftest
(
ppadd
,
"testcase setup failure
\n
"
);
ppupdate
=
__of_prop_dup
(
&
pupdate
,
GFP_KERNEL
);
selftest
(
ppupdate
,
"testcase setup failure
\n
"
);
parent
=
nremove
->
parent
;
n1
->
parent
=
parent
;
n2
->
parent
=
parent
;
n21
->
parent
=
n2
;
n2
->
child
=
n21
;
ppremove
=
of_find_property
(
parent
,
"prop-remove"
,
NULL
);
selftest
(
ppremove
,
"failed to find removal prop"
);
of_changeset_init
(
&
chgset
);
selftest
(
!
of_changeset_attach_node
(
&
chgset
,
n1
),
"fail attach n1
\n
"
);
selftest
(
!
of_changeset_attach_node
(
&
chgset
,
n2
),
"fail attach n2
\n
"
);
selftest
(
!
of_changeset_detach_node
(
&
chgset
,
nremove
),
"fail remove node
\n
"
);
selftest
(
!
of_changeset_attach_node
(
&
chgset
,
n21
),
"fail attach n21
\n
"
);
selftest
(
!
of_changeset_add_property
(
&
chgset
,
parent
,
ppadd
),
"fail add prop
\n
"
);
selftest
(
!
of_changeset_update_property
(
&
chgset
,
parent
,
ppupdate
),
"fail update prop
\n
"
);
selftest
(
!
of_changeset_remove_property
(
&
chgset
,
parent
,
ppremove
),
"fail remove prop
\n
"
);
mutex_lock
(
&
of_mutex
);
selftest
(
!
of_changeset_apply
(
&
chgset
),
"apply failed
\n
"
);
mutex_unlock
(
&
of_mutex
);
mutex_lock
(
&
of_mutex
);
selftest
(
!
of_changeset_revert
(
&
chgset
),
"revert failed
\n
"
);
mutex_unlock
(
&
of_mutex
);
of_changeset_destroy
(
&
chgset
);
#endif
}
static
void
__init
of_selftest_parse_interrupts
(
void
)
static
void
__init
of_selftest_parse_interrupts
(
void
)
{
{
struct
device_node
*
np
;
struct
device_node
*
np
;
...
@@ -685,6 +762,8 @@ static int __init of_selftest(void)
...
@@ -685,6 +762,8 @@ static int __init of_selftest(void)
of_selftest_dynamic
();
of_selftest_dynamic
();
of_selftest_parse_phandle_with_args
();
of_selftest_parse_phandle_with_args
();
of_selftest_property_match_string
();
of_selftest_property_match_string
();
of_selftest_property_copy
();
of_selftest_changeset
();
of_selftest_parse_interrupts
();
of_selftest_parse_interrupts
();
of_selftest_parse_interrupts_extended
();
of_selftest_parse_interrupts_extended
();
of_selftest_match_node
();
of_selftest_match_node
();
...
...
drivers/of/testcase-data/testcases.dts
浏览文件 @
663d3f7c
/dts-v1/;
/dts-v1/;
/ {
testcase-data {
changeset {
prop-update = "hello";
prop-remove = "world";
node-remove {
};
};
};
};
#include "tests-phandle.dtsi"
#include "tests-phandle.dtsi"
#include "tests-interrupts.dtsi"
#include "tests-interrupts.dtsi"
#include "tests-match.dtsi"
#include "tests-match.dtsi"
...
...
include/linux/of.h
浏览文件 @
663d3f7c
...
@@ -74,8 +74,6 @@ struct of_phandle_args {
...
@@ -74,8 +74,6 @@ struct of_phandle_args {
uint32_t
args
[
MAX_PHANDLE_ARGS
];
uint32_t
args
[
MAX_PHANDLE_ARGS
];
};
};
extern
int
of_node_add
(
struct
device_node
*
node
);
/* initialize a node */
/* initialize a node */
extern
struct
kobj_type
of_node_ktype
;
extern
struct
kobj_type
of_node_ktype
;
static
inline
void
of_node_init
(
struct
device_node
*
node
)
static
inline
void
of_node_init
(
struct
device_node
*
node
)
...
@@ -205,6 +203,7 @@ static inline unsigned long of_read_ulong(const __be32 *cell, int size)
...
@@ -205,6 +203,7 @@ static inline unsigned long of_read_ulong(const __be32 *cell, int size)
#define OF_DYNAMIC 1
/* node and properties were allocated via kmalloc */
#define OF_DYNAMIC 1
/* node and properties were allocated via kmalloc */
#define OF_DETACHED 2
/* node has been detached from the device tree */
#define OF_DETACHED 2
/* node has been detached from the device tree */
#define OF_POPULATED 3
/* device already created for the node */
#define OF_POPULATED 3
/* device already created for the node */
#define OF_POPULATED_BUS 4
/* of_platform_populate recursed to children of this node */
#define OF_IS_DYNAMIC(x) test_bit(OF_DYNAMIC, &x->_flags)
#define OF_IS_DYNAMIC(x) test_bit(OF_DYNAMIC, &x->_flags)
#define OF_MARK_DYNAMIC(x) set_bit(OF_DYNAMIC, &x->_flags)
#define OF_MARK_DYNAMIC(x) set_bit(OF_DYNAMIC, &x->_flags)
...
@@ -323,6 +322,7 @@ extern int of_update_property(struct device_node *np, struct property *newprop);
...
@@ -323,6 +322,7 @@ extern int of_update_property(struct device_node *np, struct property *newprop);
struct
of_prop_reconfig
{
struct
of_prop_reconfig
{
struct
device_node
*
dn
;
struct
device_node
*
dn
;
struct
property
*
prop
;
struct
property
*
prop
;
struct
property
*
old_prop
;
};
};
extern
int
of_reconfig_notifier_register
(
struct
notifier_block
*
);
extern
int
of_reconfig_notifier_register
(
struct
notifier_block
*
);
...
@@ -787,4 +787,80 @@ typedef void (*of_init_fn_1)(struct device_node *);
...
@@ -787,4 +787,80 @@ typedef void (*of_init_fn_1)(struct device_node *);
#define OF_DECLARE_2(table, name, compat, fn) \
#define OF_DECLARE_2(table, name, compat, fn) \
_OF_DECLARE(table, name, compat, fn, of_init_fn_2)
_OF_DECLARE(table, name, compat, fn, of_init_fn_2)
/**
* struct of_changeset_entry - Holds a changeset entry
*
* @node: list_head for the log list
* @action: notifier action
* @np: pointer to the device node affected
* @prop: pointer to the property affected
* @old_prop: hold a pointer to the original property
*
* Every modification of the device tree during a changeset
* is held in a list of of_changeset_entry structures.
* That way we can recover from a partial application, or we can
* revert the changeset
*/
struct
of_changeset_entry
{
struct
list_head
node
;
unsigned
long
action
;
struct
device_node
*
np
;
struct
property
*
prop
;
struct
property
*
old_prop
;
};
/**
* struct of_changeset - changeset tracker structure
*
* @entries: list_head for the changeset entries
*
* changesets are a convenient way to apply bulk changes to the
* live tree. In case of an error, changes are rolled-back.
* changesets live on after initial application, and if not
* destroyed after use, they can be reverted in one single call.
*/
struct
of_changeset
{
struct
list_head
entries
;
};
#ifdef CONFIG_OF_DYNAMIC
extern
void
of_changeset_init
(
struct
of_changeset
*
ocs
);
extern
void
of_changeset_destroy
(
struct
of_changeset
*
ocs
);
extern
int
of_changeset_apply
(
struct
of_changeset
*
ocs
);
extern
int
of_changeset_revert
(
struct
of_changeset
*
ocs
);
extern
int
of_changeset_action
(
struct
of_changeset
*
ocs
,
unsigned
long
action
,
struct
device_node
*
np
,
struct
property
*
prop
);
static
inline
int
of_changeset_attach_node
(
struct
of_changeset
*
ocs
,
struct
device_node
*
np
)
{
return
of_changeset_action
(
ocs
,
OF_RECONFIG_ATTACH_NODE
,
np
,
NULL
);
}
static
inline
int
of_changeset_detach_node
(
struct
of_changeset
*
ocs
,
struct
device_node
*
np
)
{
return
of_changeset_action
(
ocs
,
OF_RECONFIG_DETACH_NODE
,
np
,
NULL
);
}
static
inline
int
of_changeset_add_property
(
struct
of_changeset
*
ocs
,
struct
device_node
*
np
,
struct
property
*
prop
)
{
return
of_changeset_action
(
ocs
,
OF_RECONFIG_ADD_PROPERTY
,
np
,
prop
);
}
static
inline
int
of_changeset_remove_property
(
struct
of_changeset
*
ocs
,
struct
device_node
*
np
,
struct
property
*
prop
)
{
return
of_changeset_action
(
ocs
,
OF_RECONFIG_REMOVE_PROPERTY
,
np
,
prop
);
}
static
inline
int
of_changeset_update_property
(
struct
of_changeset
*
ocs
,
struct
device_node
*
np
,
struct
property
*
prop
)
{
return
of_changeset_action
(
ocs
,
OF_RECONFIG_UPDATE_PROPERTY
,
np
,
prop
);
}
#endif
#endif
/* _LINUX_OF_H */
#endif
/* _LINUX_OF_H */
include/linux/of_platform.h
浏览文件 @
663d3f7c
...
@@ -72,7 +72,7 @@ extern int of_platform_populate(struct device_node *root,
...
@@ -72,7 +72,7 @@ extern int of_platform_populate(struct device_node *root,
const
struct
of_device_id
*
matches
,
const
struct
of_device_id
*
matches
,
const
struct
of_dev_auxdata
*
lookup
,
const
struct
of_dev_auxdata
*
lookup
,
struct
device
*
parent
);
struct
device
*
parent
);
extern
int
of_platform_depopulate
(
struct
device
*
parent
);
extern
void
of_platform_depopulate
(
struct
device
*
parent
);
#else
#else
static
inline
int
of_platform_populate
(
struct
device_node
*
root
,
static
inline
int
of_platform_populate
(
struct
device_node
*
root
,
const
struct
of_device_id
*
matches
,
const
struct
of_device_id
*
matches
,
...
@@ -81,10 +81,7 @@ static inline int of_platform_populate(struct device_node *root,
...
@@ -81,10 +81,7 @@ static inline int of_platform_populate(struct device_node *root,
{
{
return
-
ENODEV
;
return
-
ENODEV
;
}
}
static
inline
int
of_platform_depopulate
(
struct
device
*
parent
)
static
inline
void
of_platform_depopulate
(
struct
device
*
parent
)
{
}
{
return
-
ENODEV
;
}
#endif
#endif
#endif
/* _LINUX_OF_PLATFORM_H */
#endif
/* _LINUX_OF_PLATFORM_H */
编辑
预览
Markdown
is supported
0%
请重试
或
添加新附件
.
添加附件
取消
You are about to add
0
people
to the discussion. Proceed with caution.
先完成此消息的编辑!
取消
想要评论请
注册
或
登录