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
00acc832
Commit
00acc832
authored
Feb 01, 2005
by
Linus Torvalds
Browse files
Options
Browse Files
Download
Plain Diff
Merge
bk://kernel.bkbits.net/davem/sparc-2.6
into ppc970.osdl.org:/home/torvalds/v2.6/linux
parents
282388bc
86ca2ffe
Changes
13
Hide whitespace changes
Inline
Side-by-side
Showing
13 changed files
with
109 additions
and
62 deletions
+109
-62
arch/sparc64/kernel/process.c
arch/sparc64/kernel/process.c
+5
-6
arch/sparc64/kernel/setup.c
arch/sparc64/kernel/setup.c
+10
-2
arch/sparc64/kernel/signal32.c
arch/sparc64/kernel/signal32.c
+4
-2
arch/sparc64/lib/atomic.S
arch/sparc64/lib/atomic.S
+21
-7
arch/sparc64/mm/fault.c
arch/sparc64/mm/fault.c
+5
-1
arch/sparc64/mm/generic.c
arch/sparc64/mm/generic.c
+24
-3
arch/sparc64/mm/hugetlbpage.c
arch/sparc64/mm/hugetlbpage.c
+14
-6
arch/sparc64/mm/init.c
arch/sparc64/mm/init.c
+2
-1
include/asm-sparc64/page.h
include/asm-sparc64/page.h
+6
-15
include/asm-sparc64/pgalloc.h
include/asm-sparc64/pgalloc.h
+1
-1
include/asm-sparc64/pgtable.h
include/asm-sparc64/pgtable.h
+14
-12
include/asm-sparc64/tlb.h
include/asm-sparc64/tlb.h
+1
-0
mm/memory.c
mm/memory.c
+2
-6
No files found.
arch/sparc64/kernel/process.c
View file @
00acc832
...
...
@@ -434,14 +434,13 @@ void flush_thread(void)
if
(
test_thread_flag
(
TIF_32BIT
))
{
struct
mm_struct
*
mm
=
t
->
task
->
mm
;
pgd_t
*
pgd0
=
&
mm
->
pgd
[
0
];
pud_t
*
pud0
=
pud_offset
(
pgd0
,
0
);
if
(
pgd_none
(
*
pgd0
))
{
pmd_t
*
page
=
pmd_alloc_one_fast
(
NULL
,
0
);
if
(
!
page
)
page
=
pmd_alloc_one
(
NULL
,
0
);
pgd_set
(
pgd0
,
page
);
if
(
pud_none
(
*
pud0
))
{
pmd_t
*
page
=
pmd_alloc_one
(
mm
,
0
);
pud_set
(
pud0
,
page
);
}
pgd_cache
=
((
unsigned
long
)
p
gd_val
(
*
pg
d0
))
<<
11UL
;
pgd_cache
=
((
unsigned
long
)
p
ud_val
(
*
pu
d0
))
<<
11UL
;
}
__asm__
__volatile__
(
"stxa %0, [%1] %2
\n\t
"
"membar #Sync"
...
...
arch/sparc64/kernel/setup.c
View file @
00acc832
...
...
@@ -151,6 +151,7 @@ int prom_callback(long *args)
struct
task_struct
*
p
;
struct
mm_struct
*
mm
=
NULL
;
pgd_t
*
pgdp
;
pud_t
*
pudp
;
pmd_t
*
pmdp
;
pte_t
*
ptep
;
...
...
@@ -166,7 +167,10 @@ int prom_callback(long *args)
pgdp
=
pgd_offset
(
mm
,
va
);
if
(
pgd_none
(
*
pgdp
))
goto
done
;
pmdp
=
pmd_offset
(
pgdp
,
va
);
pudp
=
pud_offset
(
pgdp
,
va
);
if
(
pud_none
(
*
pudp
))
goto
done
;
pmdp
=
pmd_offset
(
pudp
,
va
);
if
(
pmd_none
(
*
pmdp
))
goto
done
;
...
...
@@ -208,6 +212,7 @@ int prom_callback(long *args)
* vmalloc or prom_inherited mapping.
*/
pgd_t
*
pgdp
;
pud_t
*
pudp
;
pmd_t
*
pmdp
;
pte_t
*
ptep
;
int
error
;
...
...
@@ -221,7 +226,10 @@ int prom_callback(long *args)
pgdp
=
pgd_offset_k
(
va
);
if
(
pgd_none
(
*
pgdp
))
goto
done
;
pmdp
=
pmd_offset
(
pgdp
,
va
);
pudp
=
pud_offset
(
pgdp
,
va
);
if
(
pud_none
(
*
pudp
))
goto
done
;
pmdp
=
pmd_offset
(
pudp
,
va
);
if
(
pmd_none
(
*
pmdp
))
goto
done
;
...
...
arch/sparc64/kernel/signal32.c
View file @
00acc832
...
...
@@ -857,7 +857,8 @@ static void new_setup_frame32(struct k_sigaction *ka, struct pt_regs *regs,
/* Flush instruction space. */
unsigned
long
address
=
((
unsigned
long
)
&
(
sf
->
insns
[
0
]));
pgd_t
*
pgdp
=
pgd_offset
(
current
->
mm
,
address
);
pmd_t
*
pmdp
=
pmd_offset
(
pgdp
,
address
);
pud_t
*
pudp
=
pud_offset
(
pgdp
,
address
);
pmd_t
*
pmdp
=
pmd_offset
(
pudp
,
address
);
pte_t
*
ptep
;
regs
->
u_regs
[
UREG_I7
]
=
(
unsigned
long
)
(
&
(
sf
->
insns
[
0
])
-
2
);
...
...
@@ -1268,7 +1269,8 @@ static void setup_rt_frame32(struct k_sigaction *ka, struct pt_regs *regs,
/* Flush instruction space. */
unsigned
long
address
=
((
unsigned
long
)
&
(
sf
->
insns
[
0
]));
pgd_t
*
pgdp
=
pgd_offset
(
current
->
mm
,
address
);
pmd_t
*
pmdp
=
pmd_offset
(
pgdp
,
address
);
pud_t
*
pudp
=
pud_offset
(
pgdp
,
address
);
pmd_t
*
pmdp
=
pmd_offset
(
pudp
,
address
);
pte_t
*
ptep
;
regs
->
u_regs
[
UREG_I7
]
=
(
unsigned
long
)
(
&
(
sf
->
insns
[
0
])
-
2
);
...
...
arch/sparc64/lib/atomic.S
View file @
00acc832
...
...
@@ -7,8 +7,22 @@
#include <asm/asi.h>
.
text
.
align
64
/
*
We
use
these
stubs
for
the
uncommon
case
*
of
contention
on
the
atomic
value
.
This
is
*
so
that
we
can
keep
the
main
fast
path
8
*
instructions
long
and
thus
fit
into
a
single
*
L2
cache
line
.
*/
__atomic_add_membar
:
ba
,
pt
%
xcc
,
__atomic_add
membar
#
StoreLoad
|
#
StoreStore
__atomic_sub_membar
:
ba
,
pt
%
xcc
,
__atomic_sub
membar
#
StoreLoad
|
#
StoreStore
.
align
64
.
globl
__atomic_add
.
type
__atomic_add
,#
function
__atomic_add
:
/
*
%
o0
=
increment
,
%
o1
=
atomic_ptr
*/
...
...
@@ -16,10 +30,10 @@ __atomic_add: /* %o0 = increment, %o1 = atomic_ptr */
add
%
g5
,
%
o0
,
%
g7
cas
[%
o1
],
%
g5
,
%
g7
cmp
%
g5
,
%
g7
bne
,
pn
%
icc
,
__atomic_add
membar
#
StoreLoad
|
#
StoreStore
bne
,
pn
%
icc
,
__atomic_add
_membar
add
%
g7
,
%
o0
,
%
g7
retl
add
%
g7
,
%
o
0
,
%
o0
sra
%
g7
,
0
,
%
o0
.
size
__atomic_add
,
.
-
__atomic_add
.
globl
__atomic_sub
...
...
@@ -29,10 +43,10 @@ __atomic_sub: /* %o0 = increment, %o1 = atomic_ptr */
sub
%
g5
,
%
o0
,
%
g7
cas
[%
o1
],
%
g5
,
%
g7
cmp
%
g5
,
%
g7
bne
,
pn
%
icc
,
__atomic_sub
membar
#
StoreLoad
|
#
StoreStore
bne
,
pn
%
icc
,
__atomic_sub
_membar
sub
%
g7
,
%
o0
,
%
g7
retl
s
ub
%
g7
,
%
o
0
,
%
o0
s
ra
%
g7
,
0
,
%
o0
.
size
__atomic_sub
,
.
-
__atomic_sub
.
globl
__atomic64_add
...
...
arch/sparc64/mm/fault.c
View file @
00acc832
...
...
@@ -175,6 +175,7 @@ static void bad_kernel_pc(struct pt_regs *regs)
static
unsigned
int
get_user_insn
(
unsigned
long
tpc
)
{
pgd_t
*
pgdp
=
pgd_offset
(
current
->
mm
,
tpc
);
pud_t
*
pudp
;
pmd_t
*
pmdp
;
pte_t
*
ptep
,
pte
;
unsigned
long
pa
;
...
...
@@ -183,7 +184,10 @@ static unsigned int get_user_insn(unsigned long tpc)
if
(
pgd_none
(
*
pgdp
))
goto
outret
;
pmdp
=
pmd_offset
(
pgdp
,
tpc
);
pudp
=
pud_offset
(
pgdp
,
tpc
);
if
(
pud_none
(
*
pudp
))
goto
outret
;
pmdp
=
pmd_offset
(
pudp
,
tpc
);
if
(
pmd_none
(
*
pmdp
))
goto
outret
;
...
...
arch/sparc64/mm/generic.c
View file @
00acc832
...
...
@@ -96,6 +96,27 @@ static inline int io_remap_pmd_range(pmd_t * pmd, unsigned long address, unsigne
return
0
;
}
static
inline
int
io_remap_pud_range
(
pud_t
*
pud
,
unsigned
long
address
,
unsigned
long
size
,
unsigned
long
offset
,
pgprot_t
prot
,
int
space
)
{
unsigned
long
end
;
address
&=
~
PUD_MASK
;
end
=
address
+
size
;
if
(
end
>
PUD_SIZE
)
end
=
PUD_SIZE
;
offset
-=
address
;
do
{
pmd_t
*
pmd
=
pmd_alloc
(
current
->
mm
,
pud
,
address
);
if
(
!
pud
)
return
-
ENOMEM
;
io_remap_pmd_range
(
pmd
,
address
,
end
-
address
,
address
+
offset
,
prot
,
space
);
address
=
(
address
+
PUD_SIZE
)
&
PUD_MASK
;
pud
++
;
}
while
(
address
<
end
);
return
0
;
}
int
io_remap_page_range
(
struct
vm_area_struct
*
vma
,
unsigned
long
from
,
unsigned
long
offset
,
unsigned
long
size
,
pgprot_t
prot
,
int
space
)
{
int
error
=
0
;
...
...
@@ -111,11 +132,11 @@ int io_remap_page_range(struct vm_area_struct *vma, unsigned long from, unsigned
spin_lock
(
&
mm
->
page_table_lock
);
while
(
from
<
end
)
{
p
md_t
*
pmd
=
pm
d_alloc
(
current
->
mm
,
dir
,
from
);
p
ud_t
*
pud
=
pu
d_alloc
(
current
->
mm
,
dir
,
from
);
error
=
-
ENOMEM
;
if
(
!
p
m
d
)
if
(
!
p
u
d
)
break
;
error
=
io_remap_p
md_range
(
pm
d
,
from
,
end
-
from
,
offset
+
from
,
prot
,
space
);
error
=
io_remap_p
ud_range
(
pu
d
,
from
,
end
-
from
,
offset
+
from
,
prot
,
space
);
if
(
error
)
break
;
from
=
(
from
+
PGDIR_SIZE
)
&
PGDIR_MASK
;
...
...
arch/sparc64/mm/hugetlbpage.c
View file @
00acc832
...
...
@@ -24,14 +24,18 @@
static
pte_t
*
huge_pte_alloc
(
struct
mm_struct
*
mm
,
unsigned
long
addr
)
{
pgd_t
*
pgd
;
pud_t
*
pud
;
pmd_t
*
pmd
;
pte_t
*
pte
=
NULL
;
pgd
=
pgd_offset
(
mm
,
addr
);
if
(
pgd
)
{
pmd
=
pmd_alloc
(
mm
,
pgd
,
addr
);
if
(
pmd
)
pte
=
pte_alloc_map
(
mm
,
pmd
,
addr
);
pud
=
pud_offset
(
pgd
,
addr
);
if
(
pud
)
{
pmd
=
pmd_alloc
(
mm
,
pud
,
addr
);
if
(
pmd
)
pte
=
pte_alloc_map
(
mm
,
pmd
,
addr
);
}
}
return
pte
;
}
...
...
@@ -39,14 +43,18 @@ static pte_t *huge_pte_alloc(struct mm_struct *mm, unsigned long addr)
static
pte_t
*
huge_pte_offset
(
struct
mm_struct
*
mm
,
unsigned
long
addr
)
{
pgd_t
*
pgd
;
pud_t
*
pud
;
pmd_t
*
pmd
;
pte_t
*
pte
=
NULL
;
pgd
=
pgd_offset
(
mm
,
addr
);
if
(
pgd
)
{
pmd
=
pmd_offset
(
pgd
,
addr
);
if
(
pmd
)
pte
=
pte_offset_map
(
pmd
,
addr
);
pud
=
pud_offset
(
pgd
,
addr
);
if
(
pud
)
{
pmd
=
pmd_offset
(
pud
,
addr
);
if
(
pmd
)
pte
=
pte_offset_map
(
pmd
,
addr
);
}
}
return
pte
;
}
...
...
arch/sparc64/mm/init.c
View file @
00acc832
...
...
@@ -1462,7 +1462,8 @@ void __init paging_init(void)
memset
(
swapper_pmd_dir
,
0
,
sizeof
(
swapper_pmd_dir
));
/* Now can init the kernel/bad page tables. */
pgd_set
(
&
swapper_pg_dir
[
0
],
swapper_pmd_dir
+
(
shift
/
sizeof
(
pgd_t
)));
pud_set
(
pud_offset
(
&
swapper_pg_dir
[
0
],
0
),
swapper_pmd_dir
+
(
shift
/
sizeof
(
pgd_t
)));
sparc64_vpte_patchme1
[
0
]
|=
(((
unsigned
long
)
pgd_val
(
init_mm
.
pgd
[
0
]))
>>
10
);
...
...
include/asm-sparc64/page.h
View file @
00acc832
...
...
@@ -21,11 +21,14 @@ extern void clear_user_page(void *addr, unsigned long vaddr, struct page *page);
#define copy_page(X,Y) memcpy((void *)(X), (void *)(Y), PAGE_SIZE)
extern
void
copy_user_page
(
void
*
to
,
void
*
from
,
unsigned
long
vaddr
,
struct
page
*
topage
);
/* GROSS, defining this makes gcc pass these types as aggregates,
* and thus on the stack, turn this crap off... -DaveM
/* Unlike sparc32, sparc64's parameter passing API is more
* sane in that structures which as small enough are passed
* in registers instead of on the stack. Thus, setting
* STRICT_MM_TYPECHECKS does not generate worse code so
* let's enable it to get the type checking.
*/
/* #define STRICT_MM_TYPECHECKS */
#define STRICT_MM_TYPECHECKS
#ifdef STRICT_MM_TYPECHECKS
/* These are used to make use of C type-checking.. */
...
...
@@ -33,25 +36,19 @@ typedef struct { unsigned long pte; } pte_t;
typedef
struct
{
unsigned
long
iopte
;
}
iopte_t
;
typedef
struct
{
unsigned
int
pmd
;
}
pmd_t
;
typedef
struct
{
unsigned
int
pgd
;
}
pgd_t
;
typedef
struct
{
unsigned
long
ctxd
;
}
ctxd_t
;
typedef
struct
{
unsigned
long
pgprot
;
}
pgprot_t
;
typedef
struct
{
unsigned
long
iopgprot
;
}
iopgprot_t
;
#define pte_val(x) ((x).pte)
#define iopte_val(x) ((x).iopte)
#define pmd_val(x) ((x).pmd)
#define pgd_val(x) ((x).pgd)
#define ctxd_val(x) ((x).ctxd)
#define pgprot_val(x) ((x).pgprot)
#define iopgprot_val(x) ((x).iopgprot)
#define __pte(x) ((pte_t) { (x) } )
#define __iopte(x) ((iopte_t) { (x) } )
#define __pmd(x) ((pmd_t) { (x) } )
#define __pgd(x) ((pgd_t) { (x) } )
#define __ctxd(x) ((ctxd_t) { (x) } )
#define __pgprot(x) ((pgprot_t) { (x) } )
#define __iopgprot(x) ((iopgprot_t) { (x) } )
#else
/* .. while these make it easier on the compiler */
...
...
@@ -59,25 +56,19 @@ typedef unsigned long pte_t;
typedef
unsigned
long
iopte_t
;
typedef
unsigned
int
pmd_t
;
typedef
unsigned
int
pgd_t
;
typedef
unsigned
long
ctxd_t
;
typedef
unsigned
long
pgprot_t
;
typedef
unsigned
long
iopgprot_t
;
#define pte_val(x) (x)
#define iopte_val(x) (x)
#define pmd_val(x) (x)
#define pgd_val(x) (x)
#define ctxd_val(x) (x)
#define pgprot_val(x) (x)
#define iopgprot_val(x) (x)
#define __pte(x) (x)
#define __iopte(x) (x)
#define __pmd(x) (x)
#define __pgd(x) (x)
#define __ctxd(x) (x)
#define __pgprot(x) (x)
#define __iopgprot(x) (x)
#endif
/* (STRICT_MM_TYPECHECKS) */
...
...
include/asm-sparc64/pgalloc.h
View file @
00acc832
...
...
@@ -133,7 +133,7 @@ static __inline__ void free_pgd_slow(pgd_t *pgd)
#define DCACHE_COLOR(address) 0
#endif
#define p
gd_populate(MM, PGD, PMD) pgd_set(PG
D, PMD)
#define p
ud_populate(MM, PUD, PMD) pud_set(PU
D, PMD)
static
__inline__
pmd_t
*
pmd_alloc_one_fast
(
struct
mm_struct
*
mm
,
unsigned
long
address
)
{
...
...
include/asm-sparc64/pgtable.h
View file @
00acc832
...
...
@@ -12,7 +12,7 @@
* the SpitFire page tables.
*/
#include <asm-generic/
4level-fixup
.h>
#include <asm-generic/
pgtable-nopud
.h>
#include <linux/config.h>
#include <asm/spitfire.h>
...
...
@@ -263,23 +263,23 @@ static inline pte_t pte_modify(pte_t orig_pte, pgprot_t new_prot)
}
#define pmd_set(pmdp, ptep) \
(pmd_val(*(pmdp)) = (__pa((unsigned long) (ptep)) >> 11UL))
#define p
gd_set(pg
dp, pmdp) \
(p
gd_val(*(pg
dp)) = (__pa((unsigned long) (pmdp)) >> 11UL))
#define p
ud_set(pu
dp, pmdp) \
(p
ud_val(*(pu
dp)) = (__pa((unsigned long) (pmdp)) >> 11UL))
#define __pmd_page(pmd) \
((unsigned long) __va((((unsigned long)pmd_val(pmd))<<11UL)))
#define pmd_page(pmd) virt_to_page((void *)__pmd_page(pmd))
#define p
gd_page(pg
d) \
((unsigned long) __va((((unsigned long)p
gd_val(pg
d))<<11UL)))
#define p
ud_page(pu
d) \
((unsigned long) __va((((unsigned long)p
ud_val(pu
d))<<11UL)))
#define pte_none(pte) (!pte_val(pte))
#define pte_present(pte) (pte_val(pte) & _PAGE_PRESENT)
#define pmd_none(pmd) (!pmd_val(pmd))
#define pmd_bad(pmd) (0)
#define pmd_present(pmd) (pmd_val(pmd) != 0U)
#define pmd_clear(pmdp) (pmd_val(*(pmdp)) = 0U)
#define p
gd_none(pgd) (!pgd_val(pg
d))
#define p
gd_bad(pg
d) (0)
#define p
gd_present(pgd) (pgd_val(pg
d) != 0U)
#define p
gd_clear(pgdp) (pgd_val(*(pg
dp)) = 0U)
#define p
ud_none(pud) (!pud_val(pu
d))
#define p
ud_bad(pu
d) (0)
#define p
ud_present(pud) (pud_val(pu
d) != 0U)
#define p
ud_clear(pudp) (pud_val(*(pu
dp)) = 0U)
/* The following only work if pte_present() is true.
* Undefined behaviour if not..
...
...
@@ -313,8 +313,8 @@ static inline pte_t pte_modify(pte_t orig_pte, pgprot_t new_prot)
#define pgd_offset_k(address) pgd_offset(&init_mm, address)
/* Find an entry in the second-level page table.. */
#define pmd_offset(
dir
, address) \
((pmd_t *) p
gd_page(*(dir
)) + \
#define pmd_offset(
pudp
, address) \
((pmd_t *) p
ud_page(*(pudp
)) + \
(((address) >> PMD_SHIFT) & (REAL_PTRS_PER_PMD-1)))
/* Find an entry in the third-level page table.. */
...
...
@@ -384,6 +384,7 @@ static __inline__ unsigned long
sun4u_get_pte
(
unsigned
long
addr
)
{
pgd_t
*
pgdp
;
pud_t
*
pudp
;
pmd_t
*
pmdp
;
pte_t
*
ptep
;
...
...
@@ -392,7 +393,8 @@ sun4u_get_pte (unsigned long addr)
if
((
addr
>=
LOW_OBP_ADDRESS
)
&&
(
addr
<
HI_OBP_ADDRESS
))
return
prom_virt_to_phys
(
addr
,
NULL
);
pgdp
=
pgd_offset_k
(
addr
);
pmdp
=
pmd_offset
(
pgdp
,
addr
);
pudp
=
pud_offset
(
pgdp
,
addr
);
pmdp
=
pmd_offset
(
pudp
,
addr
);
ptep
=
pte_offset_kernel
(
pmdp
,
addr
);
return
pte_val
(
*
ptep
)
&
_PAGE_PADDR
;
}
...
...
include/asm-sparc64/tlb.h
View file @
00acc832
...
...
@@ -121,6 +121,7 @@ static inline void tlb_remove_page(struct mmu_gather *mp, struct page *page)
#define tlb_remove_tlb_entry(mp,ptep,addr) do { } while (0)
#define pte_free_tlb(mp,ptepage) pte_free(ptepage)
#define pmd_free_tlb(mp,pmdp) pmd_free(pmdp)
#define pud_free_tlb(tlb,pudp) __pud_free_tlb(tlb,pudp)
#define tlb_migrate_finish(mm) do { } while (0)
#define tlb_start_vma(tlb, vma) do { } while (0)
...
...
mm/memory.c
View file @
00acc832
...
...
@@ -2096,7 +2096,6 @@ int handle_mm_fault(struct mm_struct *mm, struct vm_area_struct * vma,
}
#ifndef __ARCH_HAS_4LEVEL_HACK
#if (PTRS_PER_PUD > 1)
/*
* Allocate page upper directory.
*
...
...
@@ -2125,12 +2124,10 @@ pud_t fastcall *__pud_alloc(struct mm_struct *mm, pgd_t *pgd, unsigned long addr
goto
out
;
}
pgd_populate
(
mm
,
pgd
,
new
);
out:
out:
return
pud_offset
(
pgd
,
address
);
}
#endif
#if (PTRS_PER_PMD > 1)
/*
* Allocate page middle directory.
*
...
...
@@ -2159,10 +2156,9 @@ pmd_t fastcall *__pmd_alloc(struct mm_struct *mm, pud_t *pud, unsigned long addr
goto
out
;
}
pud_populate
(
mm
,
pud
,
new
);
out:
out:
return
pmd_offset
(
pud
,
address
);
}
#endif
#else
pmd_t
fastcall
*
__pmd_alloc
(
struct
mm_struct
*
mm
,
pud_t
*
pud
,
unsigned
long
address
)
{
...
...
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