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
cd21dfcf
Commit
cd21dfcf
authored
Apr 28, 2005
by
Ralf Baechle
Browse files
Options
Browse Files
Download
Email Patches
Plain Diff
Fix preemption and SMP problems in the FP emulator code.
Signed-off-by:
Ralf Baechle
<
ralf@linux-mips.org
>
parent
63b2d2f4
Changes
5
Hide whitespace changes
Inline
Side-by-side
Showing
5 changed files
with
122 additions
and
119 deletions
+122
-119
arch/mips/kernel/traps.c
arch/mips/kernel/traps.c
+17
-2
arch/mips/math-emu/cp1emu.c
arch/mips/math-emu/cp1emu.c
+27
-14
arch/mips/math-emu/dp_sqrt.c
arch/mips/math-emu/dp_sqrt.c
+1
-1
arch/mips/math-emu/ieee754.c
arch/mips/math-emu/ieee754.c
+0
-4
arch/mips/math-emu/ieee754.h
arch/mips/math-emu/ieee754.h
+77
-98
No files found.
arch/mips/kernel/traps.c
View file @
cd21dfcf
...
...
@@ -551,6 +551,14 @@ asmlinkage void do_fpe(struct pt_regs *regs, unsigned long fcr31)
preempt_disable
();
#ifdef CONFIG_PREEMPT
if
(
!
is_fpu_owner
())
{
/* We might lose fpu before disabling preempt... */
own_fpu
();
BUG_ON
(
!
used_math
());
restore_fp
(
current
);
}
#endif
/*
* Unimplemented operation exception. If we've got the full
* software emulator on-board, let's use it...
...
...
@@ -562,11 +570,18 @@ asmlinkage void do_fpe(struct pt_regs *regs, unsigned long fcr31)
* a bit extreme for what should be an infrequent event.
*/
save_fp
(
current
);
/* Ensure 'resume' not overwrite saved fp context again. */
lose_fpu
();
preempt_enable
();
/* Run the emulator */
sig
=
fpu_emulator_cop1Handler
(
0
,
regs
,
&
current
->
thread
.
fpu
.
soft
);
preempt_disable
();
own_fpu
();
/* Using the FPU again. */
/*
* We can't allow the emulated instruction to leave any of
* the cause bit set in $fcr31.
...
...
@@ -712,6 +727,8 @@ asmlinkage void do_cpu(struct pt_regs *regs)
set_used_math
();
}
preempt_enable
();
if
(
!
cpu_has_fpu
)
{
int
sig
=
fpu_emulator_cop1Handler
(
0
,
regs
,
&
current
->
thread
.
fpu
.
soft
);
...
...
@@ -719,8 +736,6 @@ asmlinkage void do_cpu(struct pt_regs *regs)
force_sig
(
sig
,
current
);
}
preempt_enable
();
return
;
case
2
:
...
...
arch/mips/math-emu/cp1emu.c
View file @
cd21dfcf
...
...
@@ -79,7 +79,17 @@ struct mips_fpu_emulator_private fpuemuprivate;
/* Convert Mips rounding mode (0..3) to IEEE library modes. */
static
const
unsigned
char
ieee_rm
[
4
]
=
{
IEEE754_RN
,
IEEE754_RZ
,
IEEE754_RU
,
IEEE754_RD
[
FPU_CSR_RN
]
=
IEEE754_RN
,
[
FPU_CSR_RZ
]
=
IEEE754_RZ
,
[
FPU_CSR_RU
]
=
IEEE754_RU
,
[
FPU_CSR_RD
]
=
IEEE754_RD
,
};
/* Convert IEEE library modes to Mips rounding mode (0..3). */
static
const
unsigned
char
mips_rm
[
4
]
=
{
[
IEEE754_RN
]
=
FPU_CSR_RN
,
[
IEEE754_RZ
]
=
FPU_CSR_RZ
,
[
IEEE754_RD
]
=
FPU_CSR_RD
,
[
IEEE754_RU
]
=
FPU_CSR_RU
,
};
#if __mips >= 4
...
...
@@ -368,6 +378,7 @@ static int cop1Emulate(struct pt_regs *xcp, struct mips_fpu_soft_struct *ctx)
}
if
(
MIPSInst_RD
(
ir
)
==
FPCREG_CSR
)
{
value
=
ctx
->
fcr31
;
value
=
(
value
&
~
0x3
)
|
mips_rm
[
value
&
0x3
];
#ifdef CSRTRACE
printk
(
"%p gpr[%d]<-csr=%08x
\n
"
,
(
void
*
)
(
xcp
->
cp0_epc
),
...
...
@@ -400,11 +411,10 @@ static int cop1Emulate(struct pt_regs *xcp, struct mips_fpu_soft_struct *ctx)
(
void
*
)
(
xcp
->
cp0_epc
),
MIPSInst_RT
(
ir
),
value
);
#endif
ctx
->
fcr31
=
value
;
/* copy new rounding mode and
flush bit to ieee library state! */
ieee754_csr
.
nod
=
(
ctx
->
fcr31
&
0x1000000
)
!=
0
;
ieee754_csr
.
rm
=
ieee_rm
[
value
&
0x3
];
value
&=
(
FPU_CSR_FLUSH
|
FPU_CSR_ALL_E
|
FPU_CSR_ALL_S
|
0x03
);
ctx
->
fcr31
&=
~
(
FPU_CSR_FLUSH
|
FPU_CSR_ALL_E
|
FPU_CSR_ALL_S
|
0x03
);
/* convert to ieee library modes */
ctx
->
fcr31
|=
(
value
&
~
0x3
)
|
ieee_rm
[
value
&
0x3
];
}
if
((
ctx
->
fcr31
>>
5
)
&
ctx
->
fcr31
&
FPU_CSR_ALL_E
)
{
return
SIGFPE
;
...
...
@@ -570,7 +580,7 @@ static const unsigned char cmptab[8] = {
static ieee754##p fpemu_##p##_##name (ieee754##p r, ieee754##p s, \
ieee754##p t) \
{ \
struct ieee754_csr ieee754_csr_save; \
struct
_
ieee754_csr ieee754_csr_save; \
s = f1 (s, t); \
ieee754_csr_save = ieee754_csr; \
s = f2 (s, r); \
...
...
@@ -699,8 +709,6 @@ static int fpux_emu(struct pt_regs *xcp, struct mips_fpu_soft_struct *ctx,
rcsr
|=
FPU_CSR_INV_X
|
FPU_CSR_INV_S
;
ctx
->
fcr31
=
(
ctx
->
fcr31
&
~
FPU_CSR_ALL_X
)
|
rcsr
;
if
(
ieee754_csr
.
nod
)
ctx
->
fcr31
|=
0x1000000
;
if
((
ctx
->
fcr31
>>
5
)
&
ctx
->
fcr31
&
FPU_CSR_ALL_E
)
{
/*printk ("SIGFPE: fpu csr = %08x\n",
ctx->fcr31); */
...
...
@@ -1297,12 +1305,17 @@ int fpu_emulator_cop1Handler(int xcptno, struct pt_regs *xcp,
if
(
insn
==
0
)
xcp
->
cp0_epc
+=
4
;
/* skip nops */
else
{
/* Update ieee754_csr. Only relevant if we have a
h/w FPU */
ieee754_csr
.
nod
=
(
ctx
->
fcr31
&
0x1000000
)
!=
0
;
ieee754_csr
.
rm
=
ieee_rm
[
ctx
->
fcr31
&
0x3
];
ieee754_csr
.
cx
=
(
ctx
->
fcr31
>>
12
)
&
0x1f
;
/*
* The 'ieee754_csr' is an alias of
* ctx->fcr31. No need to copy ctx->fcr31 to
* ieee754_csr. But ieee754_csr.rm is ieee
* library modes. (not mips rounding mode)
*/
/* convert to ieee library modes */
ieee754_csr
.
rm
=
ieee_rm
[
ieee754_csr
.
rm
];
sig
=
cop1Emulate
(
xcp
,
ctx
);
/* revert to mips rounding mode */
ieee754_csr
.
rm
=
mips_rm
[
ieee754_csr
.
rm
];
}
if
(
cpu_has_fpu
)
...
...
arch/mips/math-emu/dp_sqrt.c
View file @
cd21dfcf
...
...
@@ -37,7 +37,7 @@ static const unsigned table[] = {
ieee754dp
ieee754dp_sqrt
(
ieee754dp
x
)
{
struct
ieee754_csr
oldcsr
;
struct
_
ieee754_csr
oldcsr
;
ieee754dp
y
,
z
,
t
;
unsigned
scalx
,
yh
;
COMPXDP
;
...
...
arch/mips/math-emu/ieee754.c
View file @
cd21dfcf
...
...
@@ -50,10 +50,6 @@ const char *const ieee754_cname[] = {
"SNaN"
,
};
/* the control status register
*/
struct
ieee754_csr
ieee754_csr
;
/* special constants
*/
...
...
arch/mips/math-emu/ieee754.h
View file @
cd21dfcf
/* single and double precision fp ops
* missing extended precision.
*/
/*
* MIPS floating point support
* Copyright (C) 1994-2000 Algorithmics Ltd.
* http://www.algor.co.uk
*
* ########################################################################
*
* This program is free software; you can distribute it and/or modify it
* under the terms of the GNU General Public License (Version 2) as
* published by the Free Software Foundation.
...
...
@@ -21,20 +16,16 @@
* with this program; if not, write to the Free Software Foundation, Inc.,
* 59 Temple Place - Suite 330, Boston MA 02111-1307, USA.
*
* ########################################################################
*/
/**************************************************************************
* Nov 7, 2000
* Modification to allow integration with Linux kernel
*
* Kevin D. Kissell, kevink@mips.com and Carsten Langgard, carstenl@mips.com
* Copyright (C) 2000 MIPS Technologies, Inc. All rights reserved.
*
************************************************************************
/
*/
#ifdef __KERNEL__
/* Going from Algorithmics to Linux native environment, add this */
#include <asm/byteorder.h>
#include <linux/types.h>
#include <linux/sched.h>
/*
* Not very pretty, but the Linux kernel's normal va_list definition
...
...
@@ -44,18 +35,7 @@
#include <stdarg.h>
#endif
#else
/* Note that __KERNEL__ is taken to mean Linux kernel */
#if #system(OpenBSD)
#include <machine/types.h>
#endif
#include <machine/endian.h>
#endif
/* __KERNEL__ */
#if (defined(BYTE_ORDER) && BYTE_ORDER == LITTLE_ENDIAN) || defined(__MIPSEL__)
#ifdef __LITTLE_ENDIAN
struct
ieee754dp_konst
{
unsigned
mantlo
:
32
;
unsigned
manthi
:
20
;
...
...
@@ -86,13 +66,14 @@ typedef union _ieee754sp {
}
ieee754sp
;
#endif
#if
(defined(BYTE_ORDER) && BYTE_ORDER == BIG_ENDIAN) || defined(__MIPSEB__)
#if
def __BIG_ENDIAN
struct
ieee754dp_konst
{
unsigned
sign
:
1
;
unsigned
bexp
:
11
;
unsigned
manthi
:
20
;
unsigned
mantlo
:
32
;
};
typedef
union
_ieee754dp
{
struct
ieee754dp_konst
oparts
;
struct
{
...
...
@@ -251,93 +232,109 @@ extern const char *const ieee754_cname[];
/* "normal" comparisons
*/
static
__
inline
int
ieee754sp_eq
(
ieee754sp
x
,
ieee754sp
y
)
static
inline
int
ieee754sp_eq
(
ieee754sp
x
,
ieee754sp
y
)
{
return
ieee754sp_cmp
(
x
,
y
,
IEEE754_CEQ
,
0
);
}
static
__
inline
int
ieee754sp_ne
(
ieee754sp
x
,
ieee754sp
y
)
static
inline
int
ieee754sp_ne
(
ieee754sp
x
,
ieee754sp
y
)
{
return
ieee754sp_cmp
(
x
,
y
,
IEEE754_CLT
|
IEEE754_CGT
|
IEEE754_CUN
,
0
);
}
static
__
inline
int
ieee754sp_lt
(
ieee754sp
x
,
ieee754sp
y
)
static
inline
int
ieee754sp_lt
(
ieee754sp
x
,
ieee754sp
y
)
{
return
ieee754sp_cmp
(
x
,
y
,
IEEE754_CLT
,
0
);
}
static
__
inline
int
ieee754sp_le
(
ieee754sp
x
,
ieee754sp
y
)
static
inline
int
ieee754sp_le
(
ieee754sp
x
,
ieee754sp
y
)
{
return
ieee754sp_cmp
(
x
,
y
,
IEEE754_CLT
|
IEEE754_CEQ
,
0
);
}
static
__
inline
int
ieee754sp_gt
(
ieee754sp
x
,
ieee754sp
y
)
static
inline
int
ieee754sp_gt
(
ieee754sp
x
,
ieee754sp
y
)
{
return
ieee754sp_cmp
(
x
,
y
,
IEEE754_CGT
,
0
);
}
static
__
inline
int
ieee754sp_ge
(
ieee754sp
x
,
ieee754sp
y
)
static
inline
int
ieee754sp_ge
(
ieee754sp
x
,
ieee754sp
y
)
{
return
ieee754sp_cmp
(
x
,
y
,
IEEE754_CGT
|
IEEE754_CEQ
,
0
);
}
static
__
inline
int
ieee754dp_eq
(
ieee754dp
x
,
ieee754dp
y
)
static
inline
int
ieee754dp_eq
(
ieee754dp
x
,
ieee754dp
y
)
{
return
ieee754dp_cmp
(
x
,
y
,
IEEE754_CEQ
,
0
);
}
static
__
inline
int
ieee754dp_ne
(
ieee754dp
x
,
ieee754dp
y
)
static
inline
int
ieee754dp_ne
(
ieee754dp
x
,
ieee754dp
y
)
{
return
ieee754dp_cmp
(
x
,
y
,
IEEE754_CLT
|
IEEE754_CGT
|
IEEE754_CUN
,
0
);
}
static
__
inline
int
ieee754dp_lt
(
ieee754dp
x
,
ieee754dp
y
)
static
inline
int
ieee754dp_lt
(
ieee754dp
x
,
ieee754dp
y
)
{
return
ieee754dp_cmp
(
x
,
y
,
IEEE754_CLT
,
0
);
}
static
__
inline
int
ieee754dp_le
(
ieee754dp
x
,
ieee754dp
y
)
static
inline
int
ieee754dp_le
(
ieee754dp
x
,
ieee754dp
y
)
{
return
ieee754dp_cmp
(
x
,
y
,
IEEE754_CLT
|
IEEE754_CEQ
,
0
);
}
static
__
inline
int
ieee754dp_gt
(
ieee754dp
x
,
ieee754dp
y
)
static
inline
int
ieee754dp_gt
(
ieee754dp
x
,
ieee754dp
y
)
{
return
ieee754dp_cmp
(
x
,
y
,
IEEE754_CGT
,
0
);
}
static
__
inline
int
ieee754dp_ge
(
ieee754dp
x
,
ieee754dp
y
)
static
inline
int
ieee754dp_ge
(
ieee754dp
x
,
ieee754dp
y
)
{
return
ieee754dp_cmp
(
x
,
y
,
IEEE754_CGT
|
IEEE754_CEQ
,
0
);
}
/* like strtod
*/
/*
* Like strtod
*/
ieee754dp
ieee754dp_fstr
(
const
char
*
s
,
char
**
endp
);
char
*
ieee754dp_tstr
(
ieee754dp
x
,
int
prec
,
int
fmt
,
int
af
);
/* the control status register
*/
struct
ieee754_csr
{
unsigned
pad
:
13
;
/*
* The control status register
*/
struct
_ieee754_csr
{
#ifdef __BIG_ENDIAN
unsigned
pad0
:
7
;
unsigned
nod
:
1
;
/* set 1 for no denormalised numbers */
unsigned
cx
:
5
;
/* exceptions this operation */
unsigned
c
:
1
;
/* condition */
unsigned
pad1
:
5
;
unsigned
cx
:
6
;
/* exceptions this operation */
unsigned
mx
:
5
;
/* exception enable mask */
unsigned
sx
:
5
;
/* exceptions total */
unsigned
rm
:
2
;
/* current rounding mode */
#endif
#ifdef __LITTLE_ENDIAN
unsigned
rm
:
2
;
/* current rounding mode */
unsigned
sx
:
5
;
/* exceptions total */
unsigned
mx
:
5
;
/* exception enable mask */
unsigned
cx
:
6
;
/* exceptions this operation */
unsigned
pad1
:
5
;
unsigned
c
:
1
;
/* condition */
unsigned
nod
:
1
;
/* set 1 for no denormalised numbers */
unsigned
pad0
:
7
;
#endif
};
extern
struct
ieee754_csr
ieee754_csr
;
#define ieee754_csr (*(struct _ieee754_csr *)(¤t->thread.fpu.soft.fcr31))
static
__
inline
unsigned
ieee754_getrm
(
void
)
static
inline
unsigned
ieee754_getrm
(
void
)
{
return
(
ieee754_csr
.
rm
);
}
static
__
inline
unsigned
ieee754_setrm
(
unsigned
rm
)
static
inline
unsigned
ieee754_setrm
(
unsigned
rm
)
{
return
(
ieee754_csr
.
rm
=
rm
);
}
...
...
@@ -345,14 +342,14 @@ static __inline unsigned ieee754_setrm(unsigned rm)
/*
* get current exceptions
*/
static
__
inline
unsigned
ieee754_getcx
(
void
)
static
inline
unsigned
ieee754_getcx
(
void
)
{
return
(
ieee754_csr
.
cx
);
}
/* test for current exception condition
*/
static
__
inline
int
ieee754_cxtest
(
unsigned
n
)
static
inline
int
ieee754_cxtest
(
unsigned
n
)
{
return
(
ieee754_csr
.
cx
&
n
);
}
...
...
@@ -360,21 +357,21 @@ static __inline int ieee754_cxtest(unsigned n)
/*
* get sticky exceptions
*/
static
__
inline
unsigned
ieee754_getsx
(
void
)
static
inline
unsigned
ieee754_getsx
(
void
)
{
return
(
ieee754_csr
.
sx
);
}
/* clear sticky conditions
*/
static
__
inline
unsigned
ieee754_clrsx
(
void
)
static
inline
unsigned
ieee754_clrsx
(
void
)
{
return
(
ieee754_csr
.
sx
=
0
);
}
/* test for sticky exception condition
*/
static
__
inline
int
ieee754_sxtest
(
unsigned
n
)
static
inline
int
ieee754_sxtest
(
unsigned
n
)
{
return
(
ieee754_csr
.
sx
&
n
);
}
...
...
@@ -406,52 +403,34 @@ extern const struct ieee754sp_konst __ieee754sp_spcvals[];
#define ieee754dp_spcvals ((const ieee754dp *)__ieee754dp_spcvals)
#define ieee754sp_spcvals ((const ieee754sp *)__ieee754sp_spcvals)
/* return infinity with given sign
*/
#define ieee754dp_inf(sn) \
(ieee754dp_spcvals[IEEE754_SPCVAL_PINFINITY+(sn)])
#define ieee754dp_zero(sn) \
(ieee754dp_spcvals[IEEE754_SPCVAL_PZERO+(sn)])
#define ieee754dp_one(sn) \
(ieee754dp_spcvals[IEEE754_SPCVAL_PONE+(sn)])
#define ieee754dp_ten(sn) \
(ieee754dp_spcvals[IEEE754_SPCVAL_PTEN+(sn)])
#define ieee754dp_indef() \
(ieee754dp_spcvals[IEEE754_SPCVAL_INDEF])
#define ieee754dp_max(sn) \
(ieee754dp_spcvals[IEEE754_SPCVAL_PMAX+(sn)])
#define ieee754dp_min(sn) \
(ieee754dp_spcvals[IEEE754_SPCVAL_PMIN+(sn)])
#define ieee754dp_mind(sn) \
(ieee754dp_spcvals[IEEE754_SPCVAL_PMIND+(sn)])
#define ieee754dp_1e31() \
(ieee754dp_spcvals[IEEE754_SPCVAL_P1E31])
#define ieee754dp_1e63() \
(ieee754dp_spcvals[IEEE754_SPCVAL_P1E63])
#define ieee754sp_inf(sn) \
(ieee754sp_spcvals[IEEE754_SPCVAL_PINFINITY+(sn)])
#define ieee754sp_zero(sn) \
(ieee754sp_spcvals[IEEE754_SPCVAL_PZERO+(sn)])
#define ieee754sp_one(sn) \
(ieee754sp_spcvals[IEEE754_SPCVAL_PONE+(sn)])
#define ieee754sp_ten(sn) \
(ieee754sp_spcvals[IEEE754_SPCVAL_PTEN+(sn)])
#define ieee754sp_indef() \
(ieee754sp_spcvals[IEEE754_SPCVAL_INDEF])
#define ieee754sp_max(sn) \
(ieee754sp_spcvals[IEEE754_SPCVAL_PMAX+(sn)])
#define ieee754sp_min(sn) \
(ieee754sp_spcvals[IEEE754_SPCVAL_PMIN+(sn)])
#define ieee754sp_mind(sn) \
(ieee754sp_spcvals[IEEE754_SPCVAL_PMIND+(sn)])
#define ieee754sp_1e31() \
(ieee754sp_spcvals[IEEE754_SPCVAL_P1E31])
#define ieee754sp_1e63() \
(ieee754sp_spcvals[IEEE754_SPCVAL_P1E63])
/* indefinite integer value
*/
/*
* Return infinity with given sign
*/
#define ieee754dp_inf(sn) (ieee754dp_spcvals[IEEE754_SPCVAL_PINFINITY+(sn)])
#define ieee754dp_zero(sn) (ieee754dp_spcvals[IEEE754_SPCVAL_PZERO+(sn)])
#define ieee754dp_one(sn) (ieee754dp_spcvals[IEEE754_SPCVAL_PONE+(sn)])
#define ieee754dp_ten(sn) (ieee754dp_spcvals[IEEE754_SPCVAL_PTEN+(sn)])
#define ieee754dp_indef() (ieee754dp_spcvals[IEEE754_SPCVAL_INDEF])
#define ieee754dp_max(sn) (ieee754dp_spcvals[IEEE754_SPCVAL_PMAX+(sn)])
#define ieee754dp_min(sn) (ieee754dp_spcvals[IEEE754_SPCVAL_PMIN+(sn)])
#define ieee754dp_mind(sn) (ieee754dp_spcvals[IEEE754_SPCVAL_PMIND+(sn)])
#define ieee754dp_1e31() (ieee754dp_spcvals[IEEE754_SPCVAL_P1E31])
#define ieee754dp_1e63() (ieee754dp_spcvals[IEEE754_SPCVAL_P1E63])
#define ieee754sp_inf(sn) (ieee754sp_spcvals[IEEE754_SPCVAL_PINFINITY+(sn)])
#define ieee754sp_zero(sn) (ieee754sp_spcvals[IEEE754_SPCVAL_PZERO+(sn)])
#define ieee754sp_one(sn) (ieee754sp_spcvals[IEEE754_SPCVAL_PONE+(sn)])
#define ieee754sp_ten(sn) (ieee754sp_spcvals[IEEE754_SPCVAL_PTEN+(sn)])
#define ieee754sp_indef() (ieee754sp_spcvals[IEEE754_SPCVAL_INDEF])
#define ieee754sp_max(sn) (ieee754sp_spcvals[IEEE754_SPCVAL_PMAX+(sn)])
#define ieee754sp_min(sn) (ieee754sp_spcvals[IEEE754_SPCVAL_PMIN+(sn)])
#define ieee754sp_mind(sn) (ieee754sp_spcvals[IEEE754_SPCVAL_PMIND+(sn)])
#define ieee754sp_1e31() (ieee754sp_spcvals[IEEE754_SPCVAL_P1E31])
#define ieee754sp_1e63() (ieee754sp_spcvals[IEEE754_SPCVAL_P1E63])
/*
* Indefinite integer value
*/
#define ieee754si_indef() INT_MAX
#ifdef LONG_LONG_MAX
#define ieee754di_indef() LONG_LONG_MAX
...
...
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