Skip to content
Projects
Groups
Snippets
Help
Loading...
Help
Support
Keyboard shortcuts
?
Submit feedback
Contribute to GitLab
Sign in / Register
Toggle navigation
L
linux
Project overview
Project overview
Details
Activity
Releases
Repository
Repository
Files
Commits
Branches
Tags
Contributors
Graph
Compare
Issues
0
Issues
0
List
Boards
Labels
Milestones
Merge Requests
0
Merge Requests
0
Analytics
Analytics
Repository
Value Stream
Wiki
Wiki
Snippets
Snippets
Members
Members
Collapse sidebar
Close sidebar
Activity
Graph
Create a new issue
Commits
Issue Boards
Open sidebar
Kirill Smelkov
linux
Commits
de1bb03a
Commit
de1bb03a
authored
Nov 15, 2012
by
Benjamin Herrenschmidt
Browse files
Options
Browse Files
Download
Plain Diff
Merge branch 'dt' into next
parents
11ee7e99
f459d63e
Changes
25
Hide whitespace changes
Inline
Side-by-side
Showing
25 changed files
with
267 additions
and
292 deletions
+267
-292
arch/arm/mach-mxs/mach-mxs.c
arch/arm/mach-mxs/mach-mxs.c
+1
-1
arch/powerpc/include/asm/pSeries_reconfig.h
arch/powerpc/include/asm/pSeries_reconfig.h
+0
-47
arch/powerpc/include/asm/prom.h
arch/powerpc/include/asm/prom.h
+16
-0
arch/powerpc/include/asm/rtas.h
arch/powerpc/include/asm/rtas.h
+5
-0
arch/powerpc/kernel/machine_kexec.c
arch/powerpc/kernel/machine_kexec.c
+7
-7
arch/powerpc/kernel/machine_kexec_64.c
arch/powerpc/kernel/machine_kexec_64.c
+4
-4
arch/powerpc/kernel/pci_32.c
arch/powerpc/kernel/pci_32.c
+1
-1
arch/powerpc/kernel/prom.c
arch/powerpc/kernel/prom.c
+3
-3
arch/powerpc/kernel/rtas.c
arch/powerpc/kernel/rtas.c
+0
-1
arch/powerpc/mm/numa.c
arch/powerpc/mm/numa.c
+0
-12
arch/powerpc/platforms/85xx/p1022_ds.c
arch/powerpc/platforms/85xx/p1022_ds.c
+3
-3
arch/powerpc/platforms/ps3/os-area.c
arch/powerpc/platforms/ps3/os-area.c
+3
-3
arch/powerpc/platforms/pseries/dlpar.c
arch/powerpc/platforms/pseries/dlpar.c
+6
-28
arch/powerpc/platforms/pseries/hotplug-cpu.c
arch/powerpc/platforms/pseries/hotplug-cpu.c
+4
-4
arch/powerpc/platforms/pseries/hotplug-memory.c
arch/powerpc/platforms/pseries/hotplug-memory.c
+43
-17
arch/powerpc/platforms/pseries/iommu.c
arch/powerpc/platforms/pseries/iommu.c
+5
-5
arch/powerpc/platforms/pseries/mobility.c
arch/powerpc/platforms/pseries/mobility.c
+2
-2
arch/powerpc/platforms/pseries/reconfig.c
arch/powerpc/platforms/pseries/reconfig.c
+6
-113
arch/powerpc/platforms/pseries/setup.c
arch/powerpc/platforms/pseries/setup.c
+3
-3
arch/powerpc/platforms/pseries/smp.c
arch/powerpc/platforms/pseries/smp.c
+0
-1
drivers/crypto/nx/nx-842.c
drivers/crypto/nx/nx-842.c
+8
-12
drivers/crypto/nx/nx.c
drivers/crypto/nx/nx.c
+0
-1
drivers/macintosh/smu.c
drivers/macintosh/smu.c
+1
-1
drivers/of/base.c
drivers/of/base.c
+125
-15
include/linux/of.h
include/linux/of.h
+21
-8
No files found.
arch/arm/mach-mxs/mach-mxs.c
View file @
de1bb03a
...
...
@@ -211,7 +211,7 @@ static void __init update_fec_mac_prop(enum mac_oui oui)
macaddr
[
4
]
=
(
val
>>
8
)
&
0xff
;
macaddr
[
5
]
=
(
val
>>
0
)
&
0xff
;
prom
_update_property
(
np
,
newmac
);
of
_update_property
(
np
,
newmac
);
}
}
...
...
arch/powerpc/include/asm/pSeries_reconfig.h
deleted
100644 → 0
View file @
11ee7e99
#ifndef _PPC64_PSERIES_RECONFIG_H
#define _PPC64_PSERIES_RECONFIG_H
#ifdef __KERNEL__
#include <linux/notifier.h>
/*
* Use this API if your code needs to know about OF device nodes being
* added or removed on pSeries systems.
*/
#define PSERIES_RECONFIG_ADD 0x0001
#define PSERIES_RECONFIG_REMOVE 0x0002
#define PSERIES_DRCONF_MEM_ADD 0x0003
#define PSERIES_DRCONF_MEM_REMOVE 0x0004
#define PSERIES_UPDATE_PROPERTY 0x0005
/**
* pSeries_reconfig_notify - Notifier value structure for OFDT property updates
*
* @node: Device tree node which owns the property being updated
* @property: Updated property
*/
struct
pSeries_reconfig_prop_update
{
struct
device_node
*
node
;
struct
property
*
property
;
};
#ifdef CONFIG_PPC_PSERIES
extern
int
pSeries_reconfig_notifier_register
(
struct
notifier_block
*
);
extern
void
pSeries_reconfig_notifier_unregister
(
struct
notifier_block
*
);
extern
int
pSeries_reconfig_notify
(
unsigned
long
action
,
void
*
p
);
/* Not the best place to put this, will be fixed when we move some
* of the rtas suspend-me stuff to pseries */
extern
void
pSeries_coalesce_init
(
void
);
#else
/* !CONFIG_PPC_PSERIES */
static
inline
int
pSeries_reconfig_notifier_register
(
struct
notifier_block
*
nb
)
{
return
0
;
}
static
inline
void
pSeries_reconfig_notifier_unregister
(
struct
notifier_block
*
nb
)
{
}
static
inline
void
pSeries_coalesce_init
(
void
)
{
}
#endif
/* CONFIG_PPC_PSERIES */
#endif
/* __KERNEL__ */
#endif
/* _PPC64_PSERIES_RECONFIG_H */
arch/powerpc/include/asm/prom.h
View file @
de1bb03a
...
...
@@ -58,6 +58,22 @@ static inline int of_node_to_nid(struct device_node *device) { return 0; }
extern
void
of_instantiate_rtc
(
void
);
/* The of_drconf_cell struct defines the layout of the LMB array
* specified in the device tree property
* ibm,dynamic-reconfiguration-memory/ibm,dynamic-memory
*/
struct
of_drconf_cell
{
u64
base_addr
;
u32
drc_index
;
u32
reserved
;
u32
aa_index
;
u32
flags
;
};
#define DRCONF_MEM_ASSIGNED 0x00000008
#define DRCONF_MEM_AI_INVALID 0x00000040
#define DRCONF_MEM_RESERVED 0x00000080
/* These includes are put at the bottom because they may contain things
* that are overridden by this file. Ideally they shouldn't be included
* by this file, but there are a bunch of .c files that currently depend
...
...
arch/powerpc/include/asm/rtas.h
View file @
de1bb03a
...
...
@@ -353,8 +353,13 @@ static inline int page_is_rtas_user_buf(unsigned long pfn)
return
1
;
return
0
;
}
/* Not the best place to put pSeries_coalesce_init, will be fixed when we
* move some of the rtas suspend-me stuff to pseries */
extern
void
pSeries_coalesce_init
(
void
);
#else
static
inline
int
page_is_rtas_user_buf
(
unsigned
long
pfn
)
{
return
0
;}
static
inline
void
pSeries_coalesce_init
(
void
)
{
}
#endif
extern
int
call_rtas
(
const
char
*
,
int
,
int
,
unsigned
long
*
,
...);
...
...
arch/powerpc/kernel/machine_kexec.c
View file @
de1bb03a
...
...
@@ -218,23 +218,23 @@ static void __init export_crashk_values(struct device_node *node)
* be sure what's in them, so remove them. */
prop
=
of_find_property
(
node
,
"linux,crashkernel-base"
,
NULL
);
if
(
prop
)
prom
_remove_property
(
node
,
prop
);
of
_remove_property
(
node
,
prop
);
prop
=
of_find_property
(
node
,
"linux,crashkernel-size"
,
NULL
);
if
(
prop
)
prom
_remove_property
(
node
,
prop
);
of
_remove_property
(
node
,
prop
);
if
(
crashk_res
.
start
!=
0
)
{
prom
_add_property
(
node
,
&
crashk_base_prop
);
of
_add_property
(
node
,
&
crashk_base_prop
);
crashk_size
=
resource_size
(
&
crashk_res
);
prom
_add_property
(
node
,
&
crashk_size_prop
);
of
_add_property
(
node
,
&
crashk_size_prop
);
}
/*
* memory_limit is required by the kexec-tools to limit the
* crash regions to the actual memory used.
*/
prom
_update_property
(
node
,
&
memory_limit_prop
);
of
_update_property
(
node
,
&
memory_limit_prop
);
}
static
int
__init
kexec_setup
(
void
)
...
...
@@ -249,11 +249,11 @@ static int __init kexec_setup(void)
/* remove any stale properties so ours can be found */
prop
=
of_find_property
(
node
,
kernel_end_prop
.
name
,
NULL
);
if
(
prop
)
prom
_remove_property
(
node
,
prop
);
of
_remove_property
(
node
,
prop
);
/* information needed by userspace when using default_machine_kexec */
kernel_end
=
__pa
(
_end
);
prom
_add_property
(
node
,
&
kernel_end_prop
);
of
_add_property
(
node
,
&
kernel_end_prop
);
export_crashk_values
(
node
);
...
...
arch/powerpc/kernel/machine_kexec_64.c
View file @
de1bb03a
...
...
@@ -389,14 +389,14 @@ static int __init export_htab_values(void)
/* remove any stale propertys so ours can be found */
prop
=
of_find_property
(
node
,
htab_base_prop
.
name
,
NULL
);
if
(
prop
)
prom
_remove_property
(
node
,
prop
);
of
_remove_property
(
node
,
prop
);
prop
=
of_find_property
(
node
,
htab_size_prop
.
name
,
NULL
);
if
(
prop
)
prom
_remove_property
(
node
,
prop
);
of
_remove_property
(
node
,
prop
);
htab_base
=
__pa
(
htab_address
);
prom
_add_property
(
node
,
&
htab_base_prop
);
prom
_add_property
(
node
,
&
htab_size_prop
);
of
_add_property
(
node
,
&
htab_base_prop
);
of
_add_property
(
node
,
&
htab_size_prop
);
of_node_put
(
node
);
return
0
;
...
...
arch/powerpc/kernel/pci_32.c
View file @
de1bb03a
...
...
@@ -208,7 +208,7 @@ pci_create_OF_bus_map(void)
of_prop
->
name
=
"pci-OF-bus-map"
;
of_prop
->
length
=
256
;
of_prop
->
value
=
&
of_prop
[
1
];
prom
_add_property
(
dn
,
of_prop
);
of
_add_property
(
dn
,
of_prop
);
of_node_put
(
dn
);
}
}
...
...
arch/powerpc/kernel/prom.c
View file @
de1bb03a
...
...
@@ -32,6 +32,7 @@
#include <linux/debugfs.h>
#include <linux/irq.h>
#include <linux/memblock.h>
#include <linux/of.h>
#include <asm/prom.h>
#include <asm/rtas.h>
...
...
@@ -49,7 +50,6 @@
#include <asm/btext.h>
#include <asm/sections.h>
#include <asm/machdep.h>
#include <asm/pSeries_reconfig.h>
#include <asm/pci-bridge.h>
#include <asm/kexec.h>
#include <asm/opal.h>
...
...
@@ -803,7 +803,7 @@ static int prom_reconfig_notifier(struct notifier_block *nb,
int
err
;
switch
(
action
)
{
case
PSERIES_RECONFIG_ADD
:
case
OF_RECONFIG_ATTACH_NODE
:
err
=
of_finish_dynamic_node
(
node
);
if
(
err
<
0
)
printk
(
KERN_ERR
"finish_node returned %d
\n
"
,
err
);
...
...
@@ -822,7 +822,7 @@ static struct notifier_block prom_reconfig_nb = {
static
int
__init
prom_reconfig_setup
(
void
)
{
return
pSeries
_reconfig_notifier_register
(
&
prom_reconfig_nb
);
return
of
_reconfig_notifier_register
(
&
prom_reconfig_nb
);
}
__initcall
(
prom_reconfig_setup
);
#endif
...
...
arch/powerpc/kernel/rtas.c
View file @
de1bb03a
...
...
@@ -42,7 +42,6 @@
#include <asm/time.h>
#include <asm/mmu.h>
#include <asm/topology.h>
#include <asm/pSeries_reconfig.h>
struct
rtas_t
rtas
=
{
.
lock
=
__ARCH_SPIN_LOCK_UNLOCKED
...
...
arch/powerpc/mm/numa.c
View file @
de1bb03a
...
...
@@ -399,18 +399,6 @@ static unsigned long read_n_cells(int n, const unsigned int **buf)
return
result
;
}
struct
of_drconf_cell
{
u64
base_addr
;
u32
drc_index
;
u32
reserved
;
u32
aa_index
;
u32
flags
;
};
#define DRCONF_MEM_ASSIGNED 0x00000008
#define DRCONF_MEM_AI_INVALID 0x00000040
#define DRCONF_MEM_RESERVED 0x00000080
/*
* Read the next memblock list entry from the ibm,dynamic-memory property
* and return the information in the provided of_drconf_cell structure.
...
...
arch/powerpc/platforms/85xx/p1022_ds.c
View file @
de1bb03a
...
...
@@ -539,7 +539,7 @@ static void __init p1022_ds_setup_arch(void)
};
/*
*
prom
_update_property() is called before
*
of
_update_property() is called before
* kmalloc() is available, so the 'new' object
* should be allocated in the global area.
* The easiest way is to do that is to
...
...
@@ -548,7 +548,7 @@ static void __init p1022_ds_setup_arch(void)
*/
pr_info
(
"p1022ds: disabling %s node"
,
np2
->
full_name
);
prom
_update_property
(
np2
,
&
nor_status
);
of
_update_property
(
np2
,
&
nor_status
);
of_node_put
(
np2
);
}
...
...
@@ -564,7 +564,7 @@ static void __init p1022_ds_setup_arch(void)
pr_info
(
"p1022ds: disabling %s node"
,
np2
->
full_name
);
prom
_update_property
(
np2
,
&
nand_status
);
of
_update_property
(
np2
,
&
nand_status
);
of_node_put
(
np2
);
}
...
...
arch/powerpc/platforms/ps3/os-area.c
View file @
de1bb03a
...
...
@@ -280,13 +280,13 @@ static void os_area_set_property(struct device_node *node,
if
(
tmp
)
{
pr_debug
(
"%s:%d found %s
\n
"
,
__func__
,
__LINE__
,
prop
->
name
);
prom
_remove_property
(
node
,
tmp
);
of
_remove_property
(
node
,
tmp
);
}
result
=
prom
_add_property
(
node
,
prop
);
result
=
of
_add_property
(
node
,
prop
);
if
(
result
)
pr_debug
(
"%s:%d
prom
_set_property failed
\n
"
,
__func__
,
pr_debug
(
"%s:%d
of
_set_property failed
\n
"
,
__func__
,
__LINE__
);
}
...
...
arch/powerpc/platforms/pseries/dlpar.c
View file @
de1bb03a
...
...
@@ -13,17 +13,16 @@
#include <linux/kernel.h>
#include <linux/kref.h>
#include <linux/notifier.h>
#include <linux/proc_fs.h>
#include <linux/spinlock.h>
#include <linux/cpu.h>
#include <linux/slab.h>
#include <linux/of.h>
#include "offline_states.h"
#include <asm/prom.h>
#include <asm/machdep.h>
#include <asm/uaccess.h>
#include <asm/rtas.h>
#include <asm/pSeries_reconfig.h>
struct
cc_workarea
{
u32
drc_index
;
...
...
@@ -255,9 +254,6 @@ static struct device_node *derive_parent(const char *path)
int
dlpar_attach_node
(
struct
device_node
*
dn
)
{
#ifdef CONFIG_PROC_DEVICETREE
struct
proc_dir_entry
*
ent
;
#endif
int
rc
;
of_node_set_flag
(
dn
,
OF_DYNAMIC
);
...
...
@@ -266,44 +262,26 @@ int dlpar_attach_node(struct device_node *dn)
if
(
!
dn
->
parent
)
return
-
ENOMEM
;
rc
=
pSeries_reconfig_notify
(
PSERIES_RECONFIG_ADD
,
dn
);
rc
=
of_attach_node
(
dn
);
if
(
rc
)
{
printk
(
KERN_ERR
"Failed to add device node %s
\n
"
,
dn
->
full_name
);
return
rc
;
}
of_attach_node
(
dn
);
#ifdef CONFIG_PROC_DEVICETREE
ent
=
proc_mkdir
(
strrchr
(
dn
->
full_name
,
'/'
)
+
1
,
dn
->
parent
->
pde
);
if
(
ent
)
proc_device_tree_add_node
(
dn
,
ent
);
#endif
of_node_put
(
dn
->
parent
);
return
0
;
}
int
dlpar_detach_node
(
struct
device_node
*
dn
)
{
#ifdef CONFIG_PROC_DEVICETREE
struct
device_node
*
parent
=
dn
->
parent
;
struct
property
*
prop
=
dn
->
properties
;
while
(
prop
)
{
remove_proc_entry
(
prop
->
name
,
dn
->
pde
);
prop
=
prop
->
next
;
}
int
rc
;
if
(
dn
->
pde
)
remove_proc_entry
(
dn
->
pde
->
name
,
parent
->
pde
);
#endif
rc
=
of_detach_node
(
dn
);
if
(
rc
)
return
rc
;
pSeries_reconfig_notify
(
PSERIES_RECONFIG_REMOVE
,
dn
);
of_detach_node
(
dn
);
of_node_put
(
dn
);
/* Must decrement the refcount */
return
0
;
}
...
...
arch/powerpc/platforms/pseries/hotplug-cpu.c
View file @
de1bb03a
...
...
@@ -23,12 +23,12 @@
#include <linux/delay.h>
#include <linux/sched.h>
/* for idle_task_exit */
#include <linux/cpu.h>
#include <linux/of.h>
#include <asm/prom.h>
#include <asm/rtas.h>
#include <asm/firmware.h>
#include <asm/machdep.h>
#include <asm/vdso_datapage.h>
#include <asm/pSeries_reconfig.h>
#include <asm/xics.h>
#include "plpar_wrappers.h"
#include "offline_states.h"
...
...
@@ -333,10 +333,10 @@ static int pseries_smp_notifier(struct notifier_block *nb,
int
err
=
0
;
switch
(
action
)
{
case
PSERIES_RECONFIG_ADD
:
case
OF_RECONFIG_ATTACH_NODE
:
err
=
pseries_add_processor
(
node
);
break
;
case
PSERIES_RECONFIG_REMOV
E
:
case
OF_RECONFIG_DETACH_NOD
E
:
pseries_remove_processor
(
node
);
break
;
}
...
...
@@ -399,7 +399,7 @@ static int __init pseries_cpu_hotplug_init(void)
/* Processors can be added/removed only on LPAR */
if
(
firmware_has_feature
(
FW_FEATURE_LPAR
))
{
pSeries
_reconfig_notifier_register
(
&
pseries_smp_nb
);
of
_reconfig_notifier_register
(
&
pseries_smp_nb
);
cpu_maps_update_begin
();
if
(
cede_offline_enabled
&&
parse_cede_parameters
()
==
0
)
{
default_offline_state
=
CPU_STATE_INACTIVE
;
...
...
arch/powerpc/platforms/pseries/hotplug-memory.c
View file @
de1bb03a
...
...
@@ -16,7 +16,6 @@
#include <asm/firmware.h>
#include <asm/machdep.h>
#include <asm/pSeries_reconfig.h>
#include <asm/sparsemem.h>
static
unsigned
long
get_memblock_size
(
void
)
...
...
@@ -187,42 +186,69 @@ static int pseries_add_memory(struct device_node *np)
return
(
ret
<
0
)
?
-
EINVAL
:
0
;
}
static
int
pseries_
drconf_memory
(
unsigned
long
*
base
,
unsigned
int
action
)
static
int
pseries_
update_drconf_memory
(
struct
of_prop_reconfig
*
pr
)
{
struct
of_drconf_cell
*
new_drmem
,
*
old_drmem
;
unsigned
long
memblock_size
;
int
rc
;
u32
entries
;
u32
*
p
;
int
i
,
rc
=
-
EINVAL
;
memblock_size
=
get_memblock_size
();
if
(
!
memblock_size
)
return
-
EINVAL
;
if
(
action
==
PSERIES_DRCONF_MEM_ADD
)
{
rc
=
memblock_add
(
*
base
,
memblock_size
);
rc
=
(
rc
<
0
)
?
-
EINVAL
:
0
;
}
else
if
(
action
==
PSERIES_DRCONF_MEM_REMOVE
)
{
rc
=
pseries_remove_memblock
(
*
base
,
memblock_size
);
}
else
{
rc
=
-
EINVAL
;
p
=
(
u32
*
)
of_get_property
(
pr
->
dn
,
"ibm,dynamic-memory"
,
NULL
);
if
(
!
p
)
return
-
EINVAL
;
/* The first int of the property is the number of lmb's described
* by the property. This is followed by an array of of_drconf_cell
* entries. Get the niumber of entries and skip to the array of
* of_drconf_cell's.
*/
entries
=
*
p
++
;
old_drmem
=
(
struct
of_drconf_cell
*
)
p
;
p
=
(
u32
*
)
pr
->
prop
->
value
;
p
++
;
new_drmem
=
(
struct
of_drconf_cell
*
)
p
;
for
(
i
=
0
;
i
<
entries
;
i
++
)
{
if
((
old_drmem
[
i
].
flags
&
DRCONF_MEM_ASSIGNED
)
&&
(
!
(
new_drmem
[
i
].
flags
&
DRCONF_MEM_ASSIGNED
)))
{
rc
=
pseries_remove_memblock
(
old_drmem
[
i
].
base_addr
,
memblock_size
);
break
;
}
else
if
((
!
(
old_drmem
[
i
].
flags
&
DRCONF_MEM_ASSIGNED
))
&&
(
new_drmem
[
i
].
flags
&
DRCONF_MEM_ASSIGNED
))
{
rc
=
memblock_add
(
old_drmem
[
i
].
base_addr
,
memblock_size
);
rc
=
(
rc
<
0
)
?
-
EINVAL
:
0
;
break
;
}
}
return
rc
;
}
static
int
pseries_memory_notifier
(
struct
notifier_block
*
nb
,
unsigned
long
action
,
void
*
node
)
unsigned
long
action
,
void
*
node
)
{
struct
of_prop_reconfig
*
pr
;
int
err
=
0
;
switch
(
action
)
{
case
PSERIES_RECONFIG_ADD
:
case
OF_RECONFIG_ATTACH_NODE
:
err
=
pseries_add_memory
(
node
);
break
;
case
PSERIES_RECONFIG_REMOV
E
:
case
OF_RECONFIG_DETACH_NOD
E
:
err
=
pseries_remove_memory
(
node
);
break
;
case
PSERIES_DRCONF_MEM_ADD
:
case
PSERIES_DRCONF_MEM_REMOVE
:
err
=
pseries_drconf_memory
(
node
,
action
);
case
OF_RECONFIG_UPDATE_PROPERTY
:
pr
=
(
struct
of_prop_reconfig
*
)
node
;
if
(
!
strcmp
(
pr
->
prop
->
name
,
"ibm,dynamic-memory"
))
err
=
pseries_update_drconf_memory
(
pr
);
break
;
}
return
notifier_from_errno
(
err
);
...
...
@@ -235,7 +261,7 @@ static struct notifier_block pseries_mem_nb = {
static
int
__init
pseries_memory_hotplug_init
(
void
)
{
if
(
firmware_has_feature
(
FW_FEATURE_LPAR
))
pSeries
_reconfig_notifier_register
(
&
pseries_mem_nb
);
of
_reconfig_notifier_register
(
&
pseries_mem_nb
);
return
0
;
}
...
...
arch/powerpc/platforms/pseries/iommu.c
View file @
de1bb03a
...
...
@@ -36,13 +36,13 @@
#include <linux/dma-mapping.h>
#include <linux/crash_dump.h>
#include <linux/memory.h>
#include <linux/of.h>
#include <asm/io.h>
#include <asm/prom.h>
#include <asm/rtas.h>
#include <asm/iommu.h>
#include <asm/pci-bridge.h>
#include <asm/machdep.h>
#include <asm/pSeries_reconfig.h>
#include <asm/firmware.h>
#include <asm/tce.h>
#include <asm/ppc-pci.h>
...
...
@@ -760,7 +760,7 @@ static void remove_ddw(struct device_node *np)
__remove_ddw
(
np
,
ddw_avail
,
liobn
);
delprop:
ret
=
prom
_remove_property
(
np
,
win64
);
ret
=
of
_remove_property
(
np
,
win64
);
if
(
ret
)
pr_warning
(
"%s: failed to remove direct window property: %d
\n
"
,
np
->
full_name
,
ret
);
...
...
@@ -1070,7 +1070,7 @@ static u64 enable_ddw(struct pci_dev *dev, struct device_node *pdn)
goto
out_free_window
;
}
ret
=
prom
_add_property
(
pdn
,
win64
);
ret
=
of
_add_property
(
pdn
,
win64
);
if
(
ret
)
{
dev_err
(
&
dev
->
dev
,
"unable to add dma window property for %s: %d"
,
pdn
->
full_name
,
ret
);
...
...
@@ -1294,7 +1294,7 @@ static int iommu_reconfig_notifier(struct notifier_block *nb, unsigned long acti
struct
direct_window
*
window
;
switch
(
action
)
{
case
PSERIES_RECONFIG_REMOV
E
:
case
OF_RECONFIG_DETACH_NOD
E
:
if
(
pci
&&
pci
->
iommu_table
)
iommu_free_table
(
pci
->
iommu_table
,
np
->
full_name
);
...
...
@@ -1357,7 +1357,7 @@ void iommu_init_early_pSeries(void)
}
pSeries
_reconfig_notifier_register
(
&
iommu_reconfig_nb
);
of
_reconfig_notifier_register
(
&
iommu_reconfig_nb
);
register_memory_notifier
(
&
iommu_mem_nb
);
set_pci_dma_ops
(
&
dma_iommu_ops
);
...
...
arch/powerpc/platforms/pseries/mobility.c
View file @
de1bb03a
...
...
@@ -116,7 +116,7 @@ static int update_dt_property(struct device_node *dn, struct property **prop,
}
if
(
!
more
)
{
prom
_update_property
(
dn
,
new_prop
);
of
_update_property
(
dn
,
new_prop
);
new_prop
=
NULL
;
}
...
...
@@ -172,7 +172,7 @@ static int update_dt_node(u32 phandle)
case
0x80000000
:
prop
=
of_find_property
(
dn
,
prop_name
,
NULL
);
prom
_remove_property
(
dn
,
prop
);
of
_remove_property
(
dn
,
prop
);
prop
=
NULL
;
break
;
...
...
arch/powerpc/platforms/pseries/reconfig.c
View file @
de1bb03a
...
...
@@ -16,55 +16,13 @@
#include <linux/notifier.h>
#include <linux/proc_fs.h>
#include <linux/slab.h>
#include <linux/of.h>
#include <asm/prom.h>
#include <asm/machdep.h>
#include <asm/uaccess.h>
#include <asm/pSeries_reconfig.h>
#include <asm/mmu.h>
/*
* Routines for "runtime" addition and removal of device tree nodes.
*/
#ifdef CONFIG_PROC_DEVICETREE
/*
* Add a node to /proc/device-tree.
*/
static
void
add_node_proc_entries
(
struct
device_node
*
np
)
{
struct
proc_dir_entry
*
ent
;
ent
=
proc_mkdir
(
strrchr
(
np
->
full_name
,
'/'
)
+
1
,
np
->
parent
->
pde
);
if
(
ent
)
proc_device_tree_add_node
(
np
,
ent
);
}
static
void
remove_node_proc_entries
(
struct
device_node
*
np
)
{
struct
property
*
pp
=
np
->
properties
;
struct
device_node
*
parent
=
np
->
parent
;
while
(
pp
)
{
remove_proc_entry
(
pp
->
name
,
np
->
pde
);
pp
=
pp
->
next
;
}
if
(
np
->
pde
)
remove_proc_entry
(
np
->
pde
->
name
,
parent
->
pde
);
}
#else
/* !CONFIG_PROC_DEVICETREE */
static
void
add_node_proc_entries
(
struct
device_node
*
np
)
{
return
;
}
static
void
remove_node_proc_entries
(
struct
device_node
*
np
)
{
return
;
}
#endif
/* CONFIG_PROC_DEVICETREE */
/**
* derive_parent - basically like dirname(1)
* @path: the full_name of a node to be added to the tree
...
...
@@ -97,28 +55,6 @@ static struct device_node *derive_parent(const char *path)
return
parent
;
}
static
BLOCKING_NOTIFIER_HEAD
(
pSeries_reconfig_chain
);
int
pSeries_reconfig_notifier_register
(
struct
notifier_block
*
nb
)
{
return
blocking_notifier_chain_register
(
&
pSeries_reconfig_chain
,
nb
);
}
EXPORT_SYMBOL_GPL
(
pSeries_reconfig_notifier_register
);
void
pSeries_reconfig_notifier_unregister
(
struct
notifier_block
*
nb
)
{
blocking_notifier_chain_unregister
(
&
pSeries_reconfig_chain
,
nb
);
}
EXPORT_SYMBOL_GPL
(
pSeries_reconfig_notifier_unregister
);
int
pSeries_reconfig_notify
(
unsigned
long
action
,
void
*
p
)
{
int
err
=
blocking_notifier_call_chain
(
&
pSeries_reconfig_chain
,
action
,
p
);
return
notifier_to_errno
(
err
);
}
static
int
pSeries_reconfig_add_node
(
const
char
*
path
,
struct
property
*
proplist
)
{
struct
device_node
*
np
;
...
...
@@ -142,16 +78,12 @@ static int pSeries_reconfig_add_node(const char *path, struct property *proplist
goto
out_err
;
}
err
=
pSeries_reconfig_notify
(
PSERIES_RECONFIG_ADD
,
np
);
err
=
of_attach_node
(
np
);
if
(
err
)
{
printk
(
KERN_ERR
"Failed to add device node %s
\n
"
,
path
);
goto
out_err
;
}
of_attach_node
(
np
);
add_node_proc_entries
(
np
);
of_node_put
(
np
->
parent
);
return
0
;
...
...
@@ -179,11 +111,7 @@ static int pSeries_reconfig_remove_node(struct device_node *np)
return
-
EBUSY
;
}
remove_node_proc_entries
(
np
);
pSeries_reconfig_notify
(
PSERIES_RECONFIG_REMOVE
,
np
);
of_detach_node
(
np
);
of_node_put
(
parent
);
of_node_put
(
np
);
/* Must decrement the refcount */
return
0
;
...
...
@@ -398,7 +326,7 @@ static int do_add_property(char *buf, size_t bufsize)
if
(
!
prop
)
return
-
ENOMEM
;
prom
_add_property
(
np
,
prop
);
of
_add_property
(
np
,
prop
);
return
0
;
}
...
...
@@ -422,16 +350,15 @@ static int do_remove_property(char *buf, size_t bufsize)
prop
=
of_find_property
(
np
,
buf
,
NULL
);
return
prom
_remove_property
(
np
,
prop
);
return
of
_remove_property
(
np
,
prop
);
}
static
int
do_update_property
(
char
*
buf
,
size_t
bufsize
)
{
struct
device_node
*
np
;
struct
pSeries_reconfig_prop_update
upd_value
;
unsigned
char
*
value
;
char
*
name
,
*
end
,
*
next_prop
;
int
rc
,
length
;
int
length
;
struct
property
*
newprop
;
buf
=
parse_node
(
buf
,
bufsize
,
&
np
);
end
=
buf
+
bufsize
;
...
...
@@ -453,41 +380,7 @@ static int do_update_property(char *buf, size_t bufsize)
if
(
!
strcmp
(
name
,
"slb-size"
)
||
!
strcmp
(
name
,
"ibm,slb-size"
))
slb_set_size
(
*
(
int
*
)
value
);
upd_value
.
node
=
np
;
upd_value
.
property
=
newprop
;
pSeries_reconfig_notify
(
PSERIES_UPDATE_PROPERTY
,
&
upd_value
);
rc
=
prom_update_property
(
np
,
newprop
);
if
(
rc
)
return
rc
;
/* For memory under the ibm,dynamic-reconfiguration-memory node
* of the device tree, adding and removing memory is just an update
* to the ibm,dynamic-memory property instead of adding/removing a
* memory node in the device tree. For these cases we still need to
* involve the notifier chain.
*/
if
(
!
strcmp
(
name
,
"ibm,dynamic-memory"
))
{
int
action
;
next_prop
=
parse_next_property
(
next_prop
,
end
,
&
name
,
&
length
,
&
value
);
if
(
!
next_prop
)
return
-
EINVAL
;
if
(
!
strcmp
(
name
,
"add"
))
action
=
PSERIES_DRCONF_MEM_ADD
;
else
action
=
PSERIES_DRCONF_MEM_REMOVE
;
rc
=
pSeries_reconfig_notify
(
action
,
value
);
if
(
rc
)
{
prom_update_property
(
np
,
newprop
);
return
rc
;
}
}
return
0
;
return
of_update_property
(
np
,
newprop
);
}
/**
...
...
arch/powerpc/platforms/pseries/setup.c
View file @
de1bb03a
...
...
@@ -40,6 +40,7 @@
#include <linux/seq_file.h>
#include <linux/root_dev.h>
#include <linux/cpuidle.h>
#include <linux/of.h>
#include <asm/mmu.h>
#include <asm/processor.h>
...
...
@@ -63,7 +64,6 @@
#include <asm/smp.h>
#include <asm/firmware.h>
#include <asm/eeh.h>
#include <asm/pSeries_reconfig.h>
#include "plpar_wrappers.h"
#include "pseries.h"
...
...
@@ -258,7 +258,7 @@ static int pci_dn_reconfig_notifier(struct notifier_block *nb, unsigned long act
int
err
=
NOTIFY_OK
;
switch
(
action
)
{
case
PSERIES_RECONFIG_ADD
:
case
OF_RECONFIG_ATTACH_NODE
:
pci
=
np
->
parent
->
data
;
if
(
pci
)
{
update_dn_pci_info
(
np
,
pci
->
phb
);
...
...
@@ -389,7 +389,7 @@ static void __init pSeries_setup_arch(void)
/* Find and initialize PCI host bridges */
init_pci_config_tokens
();
find_and_init_phbs
();
pSeries
_reconfig_notifier_register
(
&
pci_dn_reconfig_nb
);
of
_reconfig_notifier_register
(
&
pci_dn_reconfig_nb
);
pSeries_nvram_init
();
...
...
arch/powerpc/platforms/pseries/smp.c
View file @
de1bb03a
...
...
@@ -38,7 +38,6 @@
#include <asm/cputable.h>
#include <asm/firmware.h>
#include <asm/rtas.h>
#include <asm/pSeries_reconfig.h>
#include <asm/mpic.h>
#include <asm/vdso_datapage.h>
#include <asm/cputhreads.h>
...
...
drivers/crypto/nx/nx-842.c
View file @
de1bb03a
...
...
@@ -28,7 +28,6 @@
#include <linux/slab.h>
#include <asm/page.h>
#include <asm/pSeries_reconfig.h>
#include <asm/vio.h>
#include "nx_csbcpb.h"
/* struct nx_csbcpb */
...
...
@@ -1014,26 +1013,23 @@ static int nx842_OF_upd(struct property *new_prop)
* NOTIFY_BAD encoded with error number on failure, use
* notifier_to_errno() to decode this value
*/
static
int
nx842_OF_notifier
(
struct
notifier_block
*
np
,
unsigned
long
action
,
void
*
update
)
static
int
nx842_OF_notifier
(
struct
notifier_block
*
np
,
unsigned
long
action
,
void
*
update
)
{
struct
pSeries_reconfig_prop_update
*
upd
;
struct
of_prop_reconfig
*
upd
=
update
;
struct
nx842_devdata
*
local_devdata
;
struct
device_node
*
node
=
NULL
;
upd
=
(
struct
pSeries_reconfig_prop_update
*
)
update
;
rcu_read_lock
();
local_devdata
=
rcu_dereference
(
devdata
);
if
(
local_devdata
)
node
=
local_devdata
->
dev
->
of_node
;
if
(
local_devdata
&&
action
==
PSERIES
_UPDATE_PROPERTY
&&
!
strcmp
(
upd
->
node
->
name
,
node
->
name
))
{
action
==
OF_RECONFIG
_UPDATE_PROPERTY
&&
!
strcmp
(
upd
->
dn
->
name
,
node
->
name
))
{
rcu_read_unlock
();
nx842_OF_upd
(
upd
->
prop
erty
);
nx842_OF_upd
(
upd
->
prop
);
}
else
rcu_read_unlock
();
...
...
@@ -1182,7 +1178,7 @@ static int __init nx842_probe(struct vio_dev *viodev,
synchronize_rcu
();
kfree
(
old_devdata
);
pSeries
_reconfig_notifier_register
(
&
nx842_of_nb
);
of
_reconfig_notifier_register
(
&
nx842_of_nb
);
ret
=
nx842_OF_upd
(
NULL
);
if
(
ret
&&
ret
!=
-
ENODEV
)
{
...
...
@@ -1228,7 +1224,7 @@ static int __exit nx842_remove(struct vio_dev *viodev)
spin_lock_irqsave
(
&
devdata_mutex
,
flags
);
old_devdata
=
rcu_dereference_check
(
devdata
,
lockdep_is_held
(
&
devdata_mutex
));
pSeries
_reconfig_notifier_unregister
(
&
nx842_of_nb
);
of
_reconfig_notifier_unregister
(
&
nx842_of_nb
);
rcu_assign_pointer
(
devdata
,
NULL
);
spin_unlock_irqrestore
(
&
devdata_mutex
,
flags
);
synchronize_rcu
();
...
...
drivers/crypto/nx/nx.c
View file @
de1bb03a
...
...
@@ -33,7 +33,6 @@
#include <linux/scatterlist.h>
#include <linux/device.h>
#include <linux/of.h>
#include <asm/pSeries_reconfig.h>
#include <asm/hvcall.h>
#include <asm/vio.h>
...
...
drivers/macintosh/smu.c
View file @
de1bb03a
...
...
@@ -997,7 +997,7 @@ static struct smu_sdbp_header *smu_create_sdb_partition(int id)
"%02x !
\n
"
,
id
,
hdr
->
id
);
goto
failure
;
}
if
(
prom
_add_property
(
smu
->
of_node
,
prop
))
{
if
(
of
_add_property
(
smu
->
of_node
,
prop
))
{
printk
(
KERN_DEBUG
"SMU: Failed creating sdb-partition-%02x "
"property !
\n
"
,
id
);
goto
failure
;
...
...
drivers/of/base.c
View file @
de1bb03a
...
...
@@ -1028,13 +1028,36 @@ int of_parse_phandle_with_args(struct device_node *np, const char *list_name,
}
EXPORT_SYMBOL
(
of_parse_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
;
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
/**
*
prom
_add_property - Add a property to a node
*
of
_add_property - Add a property to a node
*/
int
prom
_add_property
(
struct
device_node
*
np
,
struct
property
*
prop
)
int
of
_add_property
(
struct
device_node
*
np
,
struct
property
*
prop
)
{
struct
property
**
next
;
unsigned
long
flags
;
int
rc
;
rc
=
of_property_notify
(
OF_RECONFIG_ADD_PROPERTY
,
np
,
prop
);
if
(
rc
)
return
rc
;
prop
->
next
=
NULL
;
write_lock_irqsave
(
&
devtree_lock
,
flags
);
...
...
@@ -1060,18 +1083,23 @@ int prom_add_property(struct device_node *np, struct property *prop)
}
/**
*
prom
_remove_property - Remove a property from a node.
*
of
_remove_property - Remove a property from a node.
*
* 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, so it won't be found any more.
*/
int
prom
_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
;
int
found
=
0
;
int
rc
;
rc
=
of_property_notify
(
OF_RECONFIG_REMOVE_PROPERTY
,
np
,
prop
);
if
(
rc
)
return
rc
;
write_lock_irqsave
(
&
devtree_lock
,
flags
);
next
=
&
np
->
properties
;
...
...
@@ -1101,7 +1129,7 @@ int prom_remove_property(struct device_node *np, struct property *prop)
}
/*
*
prom
_update_property - Update a property in a node, if the property does
*
of
_update_property - Update a property in a node, if the property does
* not exist, add it.
*
* Note that we don't actually remove it, since we have given out
...
...
@@ -1109,19 +1137,22 @@ int prom_remove_property(struct device_node *np, struct property *prop)
* Instead we just move the property to the "dead properties" list,
* and add the new property to the property list
*/
int
prom_update_property
(
struct
device_node
*
np
,
struct
property
*
newprop
)
int
of_update_property
(
struct
device_node
*
np
,
struct
property
*
newprop
)
{
struct
property
**
next
,
*
oldprop
;
unsigned
long
flags
;
int
found
=
0
;
int
rc
,
found
=
0
;
rc
=
of_property_notify
(
OF_RECONFIG_UPDATE_PROPERTY
,
np
,
newprop
);
if
(
rc
)
return
rc
;
if
(
!
newprop
->
name
)
return
-
EINVAL
;
oldprop
=
of_find_property
(
np
,
newprop
->
name
,
NULL
);
if
(
!
oldprop
)
return
prom
_add_property
(
np
,
newprop
);
return
of
_add_property
(
np
,
newprop
);
write_lock_irqsave
(
&
devtree_lock
,
flags
);
next
=
&
np
->
properties
;
...
...
@@ -1160,12 +1191,53 @@ int prom_update_property(struct device_node *np,
* device tree nodes.
*/
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
);
}
int
of_reconfig_notifier_unregister
(
struct
notifier_block
*
nb
)
{
return
blocking_notifier_chain_unregister
(
&
of_reconfig_chain
,
nb
);
}
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
);
}
#ifdef CONFIG_PROC_DEVICETREE
static
void
of_add_proc_dt_entry
(
struct
device_node
*
dn
)
{
struct
proc_dir_entry
*
ent
;
ent
=
proc_mkdir
(
strrchr
(
dn
->
full_name
,
'/'
)
+
1
,
dn
->
parent
->
pde
);
if
(
ent
)
proc_device_tree_add_node
(
dn
,
ent
);
}
#else
static
void
of_add_proc_dt_entry
(
struct
device_node
*
dn
)
{
return
;
}
#endif
/**
* of_attach_node - Plug a device node into the tree and global list.
*/
void
of_attach_node
(
struct
device_node
*
np
)
int
of_attach_node
(
struct
device_node
*
np
)
{
unsigned
long
flags
;
int
rc
;
rc
=
of_reconfig_notify
(
OF_RECONFIG_ATTACH_NODE
,
np
);
if
(
rc
)
return
rc
;
write_lock_irqsave
(
&
devtree_lock
,
flags
);
np
->
sibling
=
np
->
parent
->
child
;
...
...
@@ -1173,24 +1245,61 @@ void of_attach_node(struct device_node *np)
np
->
parent
->
child
=
np
;
allnodes
=
np
;
write_unlock_irqrestore
(
&
devtree_lock
,
flags
);
of_add_proc_dt_entry
(
np
);
return
0
;
}
#ifdef CONFIG_PROC_DEVICETREE
static
void
of_remove_proc_dt_entry
(
struct
device_node
*
dn
)
{
struct
device_node
*
parent
=
dn
->
parent
;
struct
property
*
prop
=
dn
->
properties
;
while
(
prop
)
{
remove_proc_entry
(
prop
->
name
,
dn
->
pde
);
prop
=
prop
->
next
;
}
if
(
dn
->
pde
)
remove_proc_entry
(
dn
->
pde
->
name
,
parent
->
pde
);
}
#else
static
void
of_remove_proc_dt_entry
(
struct
device_node
*
dn
)
{
return
;
}
#endif
/**
* 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.
*/
void
of_detach_node
(
struct
device_node
*
np
)
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
);
if
(
rc
)
return
rc
;
write_lock_irqsave
(
&
devtree_lock
,
flags
);
if
(
of_node_check_flag
(
np
,
OF_DETACHED
))
{
/* someone already detached it */
write_unlock_irqrestore
(
&
devtree_lock
,
flags
);
return
rc
;
}
parent
=
np
->
parent
;
if
(
!
parent
)
goto
out_unlock
;
if
(
!
parent
)
{
write_unlock_irqrestore
(
&
devtree_lock
,
flags
);
return
rc
;
}
if
(
allnodes
==
np
)
allnodes
=
np
->
allnext
;
...
...
@@ -1215,9 +1324,10 @@ void of_detach_node(struct device_node *np)
}
of_node_set_flag
(
np
,
OF_DETACHED
);
out_unlock:
write_unlock_irqrestore
(
&
devtree_lock
,
flags
);
of_remove_proc_dt_entry
(
np
);
return
rc
;
}
#endif
/* defined(CONFIG_OF_DYNAMIC) */
...
...
include/linux/of.h
View file @
de1bb03a
...
...
@@ -22,6 +22,7 @@
#include <linux/mod_devicetable.h>
#include <linux/spinlock.h>
#include <linux/topology.h>
#include <linux/notifier.h>
#include <asm/byteorder.h>
#include <asm/errno.h>
...
...
@@ -267,16 +268,28 @@ extern int of_alias_get_id(struct device_node *np, const char *stem);
extern
int
of_machine_is_compatible
(
const
char
*
compat
);
extern
int
prom_add_property
(
struct
device_node
*
np
,
struct
property
*
prop
);
extern
int
prom_remove_property
(
struct
device_node
*
np
,
struct
property
*
prop
);
extern
int
prom_update_property
(
struct
device_node
*
np
,
struct
property
*
newprop
);
extern
int
of_add_property
(
struct
device_node
*
np
,
struct
property
*
prop
);
extern
int
of_remove_property
(
struct
device_node
*
np
,
struct
property
*
prop
);
extern
int
of_update_property
(
struct
device_node
*
np
,
struct
property
*
newprop
);
#if defined(CONFIG_OF_DYNAMIC)
/* For updating the device tree at runtime */
extern
void
of_attach_node
(
struct
device_node
*
);
extern
void
of_detach_node
(
struct
device_node
*
);
#endif
#define OF_RECONFIG_ATTACH_NODE 0x0001
#define OF_RECONFIG_DETACH_NODE 0x0002
#define OF_RECONFIG_ADD_PROPERTY 0x0003
#define OF_RECONFIG_REMOVE_PROPERTY 0x0004
#define OF_RECONFIG_UPDATE_PROPERTY 0x0005
struct
of_prop_reconfig
{
struct
device_node
*
dn
;
struct
property
*
prop
;
};
extern
int
of_reconfig_notifier_register
(
struct
notifier_block
*
);
extern
int
of_reconfig_notifier_unregister
(
struct
notifier_block
*
);
extern
int
of_reconfig_notify
(
unsigned
long
,
void
*
);
extern
int
of_attach_node
(
struct
device_node
*
);
extern
int
of_detach_node
(
struct
device_node
*
);
#define of_match_ptr(_ptr) (_ptr)
...
...
Write
Preview
Markdown
is supported
0%
Try again
or
attach a new file
Attach a file
Cancel
You are about to add
0
people
to the discussion. Proceed with caution.
Finish editing this message first!
Cancel
Please
register
or
sign in
to comment