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
nexedi
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