Commit 872d64fa authored by David S. Miller's avatar David S. Miller

SPARC64: Initial Cheetah+ cpu support.

parent a4cd62e8
...@@ -424,7 +424,7 @@ static int __init chmc_init(void) ...@@ -424,7 +424,7 @@ static int __init chmc_init(void)
int index; int index;
/* This driver is only for cheetah platforms. */ /* This driver is only for cheetah platforms. */
if (tlb_type != cheetah) if (tlb_type != cheetah && tlb_type != cheetah_plus)
return -ENODEV; return -ENODEV;
index = probe_for_string("memory-controller", 0); index = probe_for_string("memory-controller", 0);
......
...@@ -33,6 +33,7 @@ struct cpu_fp_info linux_sparc_fpu[] = { ...@@ -33,6 +33,7 @@ struct cpu_fp_info linux_sparc_fpu[] = {
{ 0x17, 0x12, 0, "UltraSparc IIi integrated FPU"}, { 0x17, 0x12, 0, "UltraSparc IIi integrated FPU"},
{ 0x17, 0x13, 0, "UltraSparc IIe integrated FPU"}, { 0x17, 0x13, 0, "UltraSparc IIe integrated FPU"},
{ 0x3e, 0x14, 0, "UltraSparc III integrated FPU"}, { 0x3e, 0x14, 0, "UltraSparc III integrated FPU"},
{ 0x3e, 0x15, 0, "UltraSparc III+ integrated FPU"},
}; };
#define NSPARCFPU (sizeof(linux_sparc_fpu)/sizeof(struct cpu_fp_info)) #define NSPARCFPU (sizeof(linux_sparc_fpu)/sizeof(struct cpu_fp_info))
...@@ -44,6 +45,7 @@ struct cpu_iu_info linux_sparc_chips[] = { ...@@ -44,6 +45,7 @@ struct cpu_iu_info linux_sparc_chips[] = {
{ 0x17, 0x12, "TI UltraSparc IIi"}, { 0x17, 0x12, "TI UltraSparc IIi"},
{ 0x17, 0x13, "TI UltraSparc IIe"}, { 0x17, 0x13, "TI UltraSparc IIe"},
{ 0x3e, 0x14, "TI UltraSparc III (Cheetah)"}, { 0x3e, 0x14, "TI UltraSparc III (Cheetah)"},
{ 0x3e, 0x15, "TI UltraSparc III+ (Cheetah+)"},
}; };
#define NSPARCCHIPS (sizeof(linux_sparc_chips)/sizeof(struct cpu_iu_info)) #define NSPARCCHIPS (sizeof(linux_sparc_chips)/sizeof(struct cpu_iu_info))
......
...@@ -63,7 +63,8 @@ void __init device_scan(void) ...@@ -63,7 +63,8 @@ void __init device_scan(void)
if (tlb_type == spitfire) { if (tlb_type == spitfire) {
prom_getproperty(scan, "upa-portid", prom_getproperty(scan, "upa-portid",
(char *) &thismid, sizeof(thismid)); (char *) &thismid, sizeof(thismid));
} else if (tlb_type == cheetah) { } else if (tlb_type == cheetah ||
tlb_type == cheetah_plus) {
prom_getproperty(scan, "portid", prom_getproperty(scan, "portid",
(char *) &thismid, sizeof(thismid)); (char *) &thismid, sizeof(thismid));
} }
......
...@@ -73,7 +73,7 @@ from_tl1_trap: ...@@ -73,7 +73,7 @@ from_tl1_trap:
CREATE_VPTE_OFFSET1(%g4, %g6) ! Create VPTE offset CREATE_VPTE_OFFSET1(%g4, %g6) ! Create VPTE offset
be,pn %xcc, 3f ! Yep, special processing be,pn %xcc, 3f ! Yep, special processing
CREATE_VPTE_OFFSET2(%g4, %g6) ! Create VPTE offset CREATE_VPTE_OFFSET2(%g4, %g6) ! Create VPTE offset
cmp %g5, 3 ! Last trap level? cmp %g5, 4 ! Last trap level?
be,pn %xcc, longpath ! Yep, cannot risk VPTE miss be,pn %xcc, longpath ! Yep, cannot risk VPTE miss
nop ! delay slot nop ! delay slot
......
...@@ -1074,6 +1074,161 @@ cheetah_deferred_trap_vector_tl1: ...@@ -1074,6 +1074,161 @@ cheetah_deferred_trap_vector_tl1:
jmpl %g2 + %lo(cheetah_deferred_trap), %g0 jmpl %g2 + %lo(cheetah_deferred_trap), %g0
mov 1, %g1 mov 1, %g1
/* Cheetah+ specific traps. These are for the new I/D cache parity
* error traps. The first argument to cheetah_plus_parity_handler
* is encoded as follows:
*
* Bit0: 0=dcache,1=icache
* Bit1: 0=recoverable,1=unrecoverable
*/
.globl cheetah_plus_dcpe_trap_vector, cheetah_plus_dcpe_trap_vector_tl1
cheetah_plus_dcpe_trap_vector:
membar #Sync
ba,pt %xcc, etrap
rd %pc, %g7
mov 0x0, %o0
call cheetah_plus_parity_error
add %sp, STACK_BIAS + REGWIN_SZ, %o1
ba,pt %xcc, rtrap
clr %l6
cheetah_plus_dcpe_trap_vector_tl1:
membar #Sync
wrpr PSTATE_IG | PSTATE_PEF | PSTATE_PRIV, %pstate
sethi %hi(do_dcpe_tl1), %g3
jmpl %g3 + %lo(do_dcpe_tl1), %g0
nop
nop
nop
nop
.globl cheetah_plus_icpe_trap_vector, cheetah_plus_icpe_trap_vector_tl1
cheetah_plus_icpe_trap_vector:
membar #Sync
ba,pt %xcc, etrap
rd %pc, %g7
mov 0x1, %o0
call cheetah_plus_parity_error
add %sp, STACK_BIAS + REGWIN_SZ, %o1
ba,pt %xcc, rtrap
clr %l6
cheetah_plus_icpe_trap_vector_tl1:
membar #Sync
wrpr PSTATE_IG | PSTATE_PEF | PSTATE_PRIV, %pstate
sethi %hi(do_icpe_tl1), %g3
jmpl %g3 + %lo(do_icpe_tl1), %g0
nop
nop
nop
nop
/* If we take one of these traps when tl >= 1, then we
* jump to interrupt globals. If some trap level above us
* was also using interrupt globals, we cannot recover.
* We may use all interrupt global registers except %g6.
*/
.globl do_dcpe_tl1, do_icpe_tl1
do_dcpe_tl1:
rdpr %tl, %g1 ! Save original trap level
mov 1, %g2 ! Setup TSTATE checking loop
sethi %hi(TSTATE_IG), %g3 ! TSTATE mask bit
1: wrpr %g2, %tl ! Set trap level to check
rdpr %tstate, %g4 ! Read TSTATE for this level
andcc %g4, %g3, %g0 ! Interrupt globals in use?
bne,a,pn %xcc, do_dcpe_tl1_fatal ! Yep, irrecoverable
wrpr %g1, %tl ! Restore original trap level
add %g2, 1, %g2 ! Next trap level
cmp %g2, %g1 ! Hit them all yet?
ble,pt %icc, 1b ! Not yet
nop
wrpr %g1, %tl ! Restore original trap level
do_dcpe_tl1_nonfatal: /* Ok we may use interrupt globals safely. */
/* Reset D-cache parity */
sethi %hi(1 << 16), %g1 ! D-cache size
mov (1 << 5), %g2 ! D-cache line size
sub %g1, %g2, %g1 ! Move down 1 cacheline
1: srl %g1, 14, %g3 ! Compute UTAG
membar #Sync
stxa %g3, [%g1] ASI_DCACHE_UTAG
membar #Sync
sub %g2, 8, %g3 ! 64-bit data word within line
2: membar #Sync
stxa %g0, [%g1 + %g3] ASI_DCACHE_DATA
membar #Sync
subcc %g3, 8, %g3 ! Next 64-bit data word
bge,pt %icc, 2b
nop
subcc %g1, %g2, %g1 ! Next cacheline
bge,pt %icc, 1b
nop
ba,pt %xcc, dcpe_icpe_tl1_common
nop
do_dcpe_tl1_fatal:
sethi %hi(1f), %g7
ba,pt %xcc, etraptl1
1: or %g7, %lo(1b), %g7
mov 0x2, %o0
call cheetah_plus_parity_error
add %sp, STACK_BIAS + REGWIN_SZ, %o1
ba,pt %xcc, rtrap
clr %l6
do_icpe_tl1:
rdpr %tl, %g1 ! Save original trap level
mov 1, %g2 ! Setup TSTATE checking loop
sethi %hi(TSTATE_IG), %g3 ! TSTATE mask bit
1: wrpr %g2, %tl ! Set trap level to check
rdpr %tstate, %g4 ! Read TSTATE for this level
andcc %g4, %g3, %g0 ! Interrupt globals in use?
bne,a,pn %xcc, do_icpe_tl1_fatal ! Yep, irrecoverable
wrpr %g1, %tl ! Restore original trap level
add %g2, 1, %g2 ! Next trap level
cmp %g2, %g1 ! Hit them all yet?
ble,pt %icc, 1b ! Not yet
nop
wrpr %g1, %tl ! Restore original trap level
do_icpe_tl1_nonfatal: /* Ok we may use interrupt globals safely. */
/* Flush I-cache */
sethi %hi(1 << 15), %g1 ! I-cache size
mov (1 << 5), %g2 ! I-cache line size
sub %g1, %g2, %g1
1: or %g1, (2 << 3), %g3
stxa %g0, [%g3] ASI_IC_TAG
membar #Sync
subcc %g1, %g2, %g1
bge,pt %icc, 1b
nop
ba,pt %xcc, dcpe_icpe_tl1_common
nop
do_icpe_tl1_fatal:
sethi %hi(1f), %g7
ba,pt %xcc, etraptl1
1: or %g7, %lo(1b), %g7
mov 0x3, %o0
call cheetah_plus_parity_error
add %sp, STACK_BIAS + REGWIN_SZ, %o1
ba,pt %xcc, rtrap
clr %l6
dcpe_icpe_tl1_common:
/* Flush D-cache, re-enable D/I caches in DCU and finally
* retry the trapping instruction.
*/
sethi %hi(1 << 16), %g1 ! D-cache size
mov (1 << 5), %g2 ! D-cache line size
sub %g1, %g2, %g1
1: stxa %g0, [%g1] ASI_DCACHE_TAG
membar #Sync
subcc %g1, %g2, %g1
bge,pt %icc, 1b
nop
ldxa [%g0] ASI_DCU_CONTROL_REG, %g1
or %g1, (DCU_DC | DCU_IC), %g1
stxa %g1, [%g0] ASI_DCU_CONTROL_REG
membar #Sync
retry
/* Cheetah FECC trap handling, we get here from tl{0,1}_fecc /* Cheetah FECC trap handling, we get here from tl{0,1}_fecc
* in the trap table. That code has done a memory barrier * in the trap table. That code has done a memory barrier
* and has disabled both the I-cache and D-cache in the DCU * and has disabled both the I-cache and D-cache in the DCU
...@@ -1639,12 +1794,17 @@ do_gettimeofday: /* %o0 = timevalp */ ...@@ -1639,12 +1794,17 @@ do_gettimeofday: /* %o0 = timevalp */
or %g2, %lo(xtime), %g2 or %g2, %lo(xtime), %g2
or %g1, %lo(timer_tick_compare), %g1 or %g1, %lo(timer_tick_compare), %g1
1: rdpr %ver, %o2 1: rdpr %ver, %o2
sethi %hi(0x003e0014), %o1 sethi %hi(CHEETAH_ID), %o1
srlx %o2, 32, %o2 srlx %o2, 32, %o2
or %o1, %lo(0x003e0014), %o1 or %o1, %lo(CHEETAH_ID), %o1
membar #Sync membar #Sync
ldda [%g2] ASI_NUCLEUS_QUAD_LDD, %o4 ldda [%g2] ASI_NUCLEUS_QUAD_LDD, %o4
cmp %o2, %o1 cmp %o2, %o1
be,a,pn %xcc, 3f
rd %asr24, %o1
sethi %hi(CHEETAH_PLUS_ID), %o1
or %o1, %lo(CHEETAH_PLUS_ID), %o1
cmp %o2, %o1
bne,pt %xcc, 2f bne,pt %xcc, 2f
nop nop
ba,pt %xcc, 3f ba,pt %xcc, 3f
......
...@@ -79,24 +79,34 @@ sparc_ramdisk_size: ...@@ -79,24 +79,34 @@ sparc_ramdisk_size:
*/ */
sparc64_boot: sparc64_boot:
rdpr %ver, %g1 rdpr %ver, %g1
sethi %hi(0x003e0014), %g5 sethi %hi(CHEETAH_ID), %g5
srlx %g1, 32, %g1 srlx %g1, 32, %g1
or %g5, %lo(0x003e0014), %g5 or %g5, %lo(CHEETAH_ID), %g5
cmp %g1, %g5
be,pn %icc, cheetah_boot
sethi %hi(CHEETAH_PLUS_ID), %g5
or %g5, %lo(CHEETAH_PLUS_ID), %g5
cmp %g1, %g5 cmp %g1, %g5
bne,pt %icc, spitfire_boot bne,pt %icc, spitfire_boot
nop nop
cheetah_plus_boot:
/* Preserve OBP choosen DCU and DCR register settings. */
ba,pt %xcc, cheetah_generic_boot
nop
cheetah_boot: cheetah_boot:
mov DCR_BPE | DCR_RPE | DCR_SI | DCR_IFPOE | DCR_MS, %g1 mov DCR_BPE | DCR_RPE | DCR_SI | DCR_IFPOE | DCR_MS, %g1
wr %g1, %asr18 wr %g1, %asr18
sethi %uhi(DCU_ME | DCU_RE | /*DCU_PE |*/ DCU_HPE | DCU_SPE | DCU_SL | DCU_WE), %g5 sethi %uhi(DCU_ME|DCU_RE|DCU_HPE|DCU_SPE|DCU_SL|DCU_WE), %g5
or %g5, %ulo(DCU_ME | DCU_RE | /*DCU_PE |*/ DCU_HPE | DCU_SPE | DCU_SL | DCU_WE), %g5 or %g5, %ulo(DCU_ME|DCU_RE|DCU_HPE|DCU_SPE|DCU_SL|DCU_WE), %g5
sllx %g5, 32, %g5 sllx %g5, 32, %g5
or %g5, DCU_DM | DCU_IM | DCU_DC | DCU_IC, %g5 or %g5, DCU_DM | DCU_IM | DCU_DC | DCU_IC, %g5
stxa %g5, [%g0] ASI_DCU_CONTROL_REG stxa %g5, [%g0] ASI_DCU_CONTROL_REG
membar #Sync membar #Sync
cheetah_generic_boot:
mov TSB_EXTENSION_P, %g3 mov TSB_EXTENSION_P, %g3
stxa %g0, [%g3] ASI_DMMU stxa %g0, [%g3] ASI_DMMU
stxa %g0, [%g3] ASI_IMMU stxa %g0, [%g3] ASI_IMMU
...@@ -149,6 +159,7 @@ cheetah_boot: ...@@ -149,6 +159,7 @@ cheetah_boot:
add %l0, (1 << 3), %l0 add %l0, (1 << 3), %l0
cheetah_got_tlbentry: cheetah_got_tlbentry:
ldxa [%l0] ASI_ITLB_DATA_ACCESS, %g0
ldxa [%l0] ASI_ITLB_DATA_ACCESS, %g1 ldxa [%l0] ASI_ITLB_DATA_ACCESS, %g1
membar #Sync membar #Sync
and %g1, %g3, %g1 and %g1, %g3, %g1
...@@ -200,6 +211,36 @@ cheetah_got_tlbentry: ...@@ -200,6 +211,36 @@ cheetah_got_tlbentry:
blu,pt %xcc, 1b blu,pt %xcc, 1b
add %l0, (1 << 3), %l0 add %l0, (1 << 3), %l0
/* On Cheetah+, have to check second DTLB. */
rdpr %ver, %g1
srlx %g1, 32, %g1
sethi %hi(CHEETAH_PLUS_ID), %l0
or %l0, %lo(CHEETAH_PLUS_ID), %l0
cmp %g1, %l0
bne,pt %icc, 9f
nop
set 3 << 16, %l0
1: ldxa [%l0] ASI_DTLB_TAG_READ, %g1
membar #Sync
andn %g1, %l2, %g1
cmp %g1, %g3
blu,pn %xcc, 2f
cmp %g1, %g7
bgeu,pn %xcc, 2f
nop
stxa %g0, [%l7] ASI_DMMU
membar #Sync
stxa %g0, [%l0] ASI_DTLB_DATA_ACCESS
membar #Sync
2: and %l0, (511 << 3), %g1
cmp %g1, (511 << 3)
blu,pt %xcc, 1b
add %l0, (1 << 3), %l0
9:
/* Now lock the TTE we created into ITLB-0 and DTLB-0, /* Now lock the TTE we created into ITLB-0 and DTLB-0,
* entry 15 (and maybe 14 too). * entry 15 (and maybe 14 too).
*/ */
...@@ -429,20 +470,26 @@ sun4u_init: ...@@ -429,20 +470,26 @@ sun4u_init:
membar #Sync membar #Sync
rdpr %ver, %g1 rdpr %ver, %g1
sethi %hi(0x003e0014), %g5 sethi %hi(CHEETAH_ID), %g5
srlx %g1, 32, %g1 srlx %g1, 32, %g1
or %g5, %lo(0x003e0014), %g5 or %g5, %lo(CHEETAH_ID), %g5
cmp %g1, %g5
be,pn %icc, cheetah_tlb_fixup
sethi %hi(CHEETAH_PLUS_ID), %g5
or %g5, %lo(CHEETAH_PLUS_ID), %g5
cmp %g1, %g5 cmp %g1, %g5
bne,pt %icc, spitfire_tlb_fixup bne,pt %icc, spitfire_tlb_fixup
nop nop
cheetah_tlb_fixup: cheetah_tlb_fixup:
set (0 << 16) | (15 << 3), %g7 set (0 << 16) | (15 << 3), %g7
ldxa [%g7] ASI_ITLB_DATA_ACCESS, %g0
ldxa [%g7] ASI_ITLB_DATA_ACCESS, %g1 ldxa [%g7] ASI_ITLB_DATA_ACCESS, %g1
andn %g1, (_PAGE_G), %g1 andn %g1, (_PAGE_G), %g1
stxa %g1, [%g7] ASI_ITLB_DATA_ACCESS stxa %g1, [%g7] ASI_ITLB_DATA_ACCESS
membar #Sync membar #Sync
ldxa [%g7] ASI_DTLB_DATA_ACCESS, %g0
ldxa [%g7] ASI_DTLB_DATA_ACCESS, %g1 ldxa [%g7] ASI_DTLB_DATA_ACCESS, %g1
andn %g1, (_PAGE_G), %g1 andn %g1, (_PAGE_G), %g1
stxa %g1, [%g7] ASI_DTLB_DATA_ACCESS stxa %g1, [%g7] ASI_DTLB_DATA_ACCESS
...@@ -452,9 +499,17 @@ cheetah_tlb_fixup: ...@@ -452,9 +499,17 @@ cheetah_tlb_fixup:
flush %g3 flush %g3
membar #Sync membar #Sync
/* Set TLB type to cheetah. */ sethi %hi(CHEETAH_PLUS_ID), %g5
mov 1, %g2 or %g5, %lo(CHEETAH_PLUS_ID), %g5
sethi %hi(tlb_type), %g5 rdpr %ver, %g2
srlx %g2, 32, %g2
cmp %g2, %g5
bne,a,pt %icc, 1f
mov 1, %g2 /* Set TLB type to cheetah. */
mov 2, %g2 /* Set TLB type to cheetah+. */
1: sethi %hi(tlb_type), %g5
stw %g2, [%g5 + %lo(tlb_type)] stw %g2, [%g5 + %lo(tlb_type)]
/* Patch copy/page operations to cheetah optimized versions. */ /* Patch copy/page operations to cheetah optimized versions. */
...@@ -462,6 +517,8 @@ cheetah_tlb_fixup: ...@@ -462,6 +517,8 @@ cheetah_tlb_fixup:
nop nop
call cheetah_patch_pgcopyops call cheetah_patch_pgcopyops
nop nop
call cheetah_patch_cachetlbops
nop
ba,pt %xcc, tlb_fixup_done ba,pt %xcc, tlb_fixup_done
nop nop
...@@ -575,18 +632,23 @@ setup_tba: /* i0 = is_starfire */ ...@@ -575,18 +632,23 @@ setup_tba: /* i0 = is_starfire */
or %g2, KERN_LOWBITS, %g2 or %g2, KERN_LOWBITS, %g2
rdpr %ver, %g3 rdpr %ver, %g3
sethi %hi(0x003e0014), %g7 sethi %hi(CHEETAH_ID), %g7
srlx %g3, 32, %g3 srlx %g3, 32, %g3
or %g7, %lo(0x003e0014), %g7 or %g7, %lo(CHEETAH_ID), %g7
cmp %g3, %g7
be,pn %icc, cheetah_vpte_base
sethi %hi(CHEETAH_PLUS_ID), %g7
or %g7, %lo(CHEETAH_PLUS_ID), %g7
cmp %g3, %g7 cmp %g3, %g7
bne,pt %icc, 1f bne,pt %icc, spitfire_vpte_base
nop nop
cheetah_vpte_base:
sethi %uhi(VPTE_BASE_CHEETAH), %g3 sethi %uhi(VPTE_BASE_CHEETAH), %g3
or %g3, %ulo(VPTE_BASE_CHEETAH), %g3 or %g3, %ulo(VPTE_BASE_CHEETAH), %g3
ba,pt %xcc, 2f ba,pt %xcc, 2f
sllx %g3, 32, %g3 sllx %g3, 32, %g3
1: spitfire_vpte_base:
sethi %uhi(VPTE_BASE_SPITFIRE), %g3 sethi %uhi(VPTE_BASE_SPITFIRE), %g3
or %g3, %ulo(VPTE_BASE_SPITFIRE), %g3 or %g3, %ulo(VPTE_BASE_SPITFIRE), %g3
sllx %g3, 32, %g3 sllx %g3, 32, %g3
...@@ -614,13 +676,18 @@ setup_tba: /* i0 = is_starfire */ ...@@ -614,13 +676,18 @@ setup_tba: /* i0 = is_starfire */
not_starfire: not_starfire:
rdpr %ver, %g1 rdpr %ver, %g1
sethi %hi(0x003e0014), %g5 sethi %hi(CHEETAH_ID), %g5
srlx %g1, 32, %g1 srlx %g1, 32, %g1
or %g7, %lo(0x003e0014), %g5 or %g5, %lo(CHEETAH_ID), %g5
cmp %g1, %g5
be,pn %icc, is_cheetah
sethi %hi(CHEETAH_PLUS_ID), %g5
or %g5, %lo(CHEETAH_PLUS_ID), %g5
cmp %g1, %g5 cmp %g1, %g5
bne,pt %icc, not_cheetah bne,pt %icc, not_cheetah
nop nop
is_cheetah:
ldxa [%g0] ASI_SAFARI_CONFIG, %g1 ldxa [%g0] ASI_SAFARI_CONFIG, %g1
srlx %g1, 17, %g1 srlx %g1, 17, %g1
ba,pt %xcc, set_worklist ba,pt %xcc, set_worklist
...@@ -644,14 +711,19 @@ set_worklist: ...@@ -644,14 +711,19 @@ set_worklist:
wr %g0, 0, %tick_cmpr wr %g0, 0, %tick_cmpr
rdpr %ver, %g1 rdpr %ver, %g1
sethi %hi(0x003e0014), %g5 sethi %hi(CHEETAH_ID), %g5
srlx %g1, 32, %g1 srlx %g1, 32, %g1
or %g7, %lo(0x003e0014), %g5 or %g5, %lo(CHEETAH_ID), %g5
cmp %g1, %g5 cmp %g1, %g5
bne,pt %icc, 1f be,pn %icc, 1f
sethi %hi(CHEETAH_PLUS_ID), %g5
or %g5, %lo(CHEETAH_PLUS_ID), %g5
cmp %g1, %g5
bne,pt %icc, 2f
nop nop
/* Disable STICK_INT interrupts. */ /* Disable STICK_INT interrupts. */
1:
sethi %hi(0x80000000), %g1 sethi %hi(0x80000000), %g1
sllx %g1, 32, %g1 sllx %g1, 32, %g1
wr %g1, %asr25 wr %g1, %asr25
...@@ -659,7 +731,7 @@ set_worklist: ...@@ -659,7 +731,7 @@ set_worklist:
/* Ok, we're done setting up all the state our trap mechanims needs, /* Ok, we're done setting up all the state our trap mechanims needs,
* now get back into normal globals and let the PROM know what is up. * now get back into normal globals and let the PROM know what is up.
*/ */
1: 2:
wrpr %g0, %g0, %wstate wrpr %g0, %g0, %wstate
wrpr %o1, PSTATE_IE, %pstate wrpr %o1, PSTATE_IE, %pstate
......
...@@ -162,7 +162,7 @@ void enable_irq(unsigned int irq) ...@@ -162,7 +162,7 @@ void enable_irq(unsigned int irq)
if (imap == 0UL) if (imap == 0UL)
return; return;
if (tlb_type == cheetah) { if (tlb_type == cheetah || tlb_type == cheetah_plus) {
/* We set it to our Safari AID. */ /* We set it to our Safari AID. */
__asm__ __volatile__("ldxa [%%g0] %1, %0" __asm__ __volatile__("ldxa [%%g0] %1, %0"
: "=r" (tid) : "=r" (tid)
...@@ -1068,7 +1068,7 @@ static int retarget_one_irq(struct irqaction *p, int goal_cpu) ...@@ -1068,7 +1068,7 @@ static int retarget_one_irq(struct irqaction *p, int goal_cpu)
goal_cpu = 0; goal_cpu = 0;
} }
if (tlb_type == cheetah) { if (tlb_type == cheetah || tlb_type == cheetah_plus) {
tid = goal_cpu << 26; tid = goal_cpu << 26;
tid &= IMAP_AID_SAFARI; tid &= IMAP_AID_SAFARI;
} else if (this_is_starfire == 0) { } else if (this_is_starfire == 0) {
......
...@@ -570,7 +570,7 @@ asmlinkage void do_ptrace(struct pt_regs *regs) ...@@ -570,7 +570,7 @@ asmlinkage void do_ptrace(struct pt_regs *regs)
{ {
unsigned long va; unsigned long va;
if (tlb_type == cheetah) { if (tlb_type == cheetah || tlb_type == cheetah_plus) {
for (va = 0; va < (1 << 16); va += (1 << 5)) for (va = 0; va < (1 << 16); va += (1 << 5))
spitfire_put_dcache_tag(va, 0x0); spitfire_put_dcache_tag(va, 0x0);
/* No need to mess with I-cache on Cheetah. */ /* No need to mess with I-cache on Cheetah. */
......
...@@ -193,7 +193,7 @@ int prom_callback(long *args) ...@@ -193,7 +193,7 @@ int prom_callback(long *args)
if (tlb_type == spitfire) if (tlb_type == spitfire)
tte = spitfire_get_dtlb_data(SPITFIRE_HIGHEST_LOCKED_TLBENT); tte = spitfire_get_dtlb_data(SPITFIRE_HIGHEST_LOCKED_TLBENT);
else if (tlb_type == cheetah) else if (tlb_type == cheetah || tlb_type == cheetah_plus)
tte = cheetah_get_ldtlb_data(CHEETAH_HIGHEST_LOCKED_TLBENT); tte = cheetah_get_ldtlb_data(CHEETAH_HIGHEST_LOCKED_TLBENT);
res = PROM_TRUE; res = PROM_TRUE;
......
...@@ -558,9 +558,9 @@ extern unsigned long xcall_flush_tlb_page; ...@@ -558,9 +558,9 @@ extern unsigned long xcall_flush_tlb_page;
extern unsigned long xcall_flush_tlb_mm; extern unsigned long xcall_flush_tlb_mm;
extern unsigned long xcall_flush_tlb_range; extern unsigned long xcall_flush_tlb_range;
extern unsigned long xcall_flush_tlb_kernel_range; extern unsigned long xcall_flush_tlb_kernel_range;
extern unsigned long xcall_flush_tlb_all; extern unsigned long xcall_flush_tlb_all_spitfire;
extern unsigned long xcall_tlbcachesync; extern unsigned long xcall_flush_tlb_all_cheetah;
extern unsigned long xcall_flush_cache_all; extern unsigned long xcall_flush_cache_all_spitfire;
extern unsigned long xcall_report_regs; extern unsigned long xcall_report_regs;
extern unsigned long xcall_receive_signal; extern unsigned long xcall_receive_signal;
extern unsigned long xcall_flush_dcache_page_cheetah; extern unsigned long xcall_flush_dcache_page_cheetah;
...@@ -676,13 +676,19 @@ void smp_report_regs(void) ...@@ -676,13 +676,19 @@ void smp_report_regs(void)
void smp_flush_cache_all(void) void smp_flush_cache_all(void)
{ {
smp_cross_call(&xcall_flush_cache_all, 0, 0, 0); /* Cheetah need do nothing. */
__flush_cache_all(); if (tlb_type == spitfire) {
smp_cross_call(&xcall_flush_cache_all_spitfire, 0, 0, 0);
__flush_cache_all();
}
} }
void smp_flush_tlb_all(void) void smp_flush_tlb_all(void)
{ {
smp_cross_call(&xcall_flush_tlb_all, 0, 0, 0); if (tlb_type == spitfire)
smp_cross_call(&xcall_flush_tlb_all_spitfire, 0, 0, 0);
else
smp_cross_call(&xcall_flush_tlb_all_cheetah, 0, 0, 0);
__flush_tlb_all(); __flush_tlb_all();
} }
......
...@@ -34,13 +34,22 @@ sparc64_cpu_startup: ...@@ -34,13 +34,22 @@ sparc64_cpu_startup:
flushw flushw
rdpr %ver, %g1 rdpr %ver, %g1
sethi %hi(0x003e0014), %g5 sethi %hi(CHEETAH_ID), %g5
srlx %g1, 32, %g1 srlx %g1, 32, %g1
or %g5, %lo(0x003e0014), %g5 or %g5, %lo(CHEETAH_ID), %g5
cmp %g1, %g5
be,pn %icc, cheetah_startup
sethi %hi(CHEETAH_PLUS_ID), %g5
or %g5, %lo(CHEETAH_PLUS_ID), %g5
cmp %g1, %g5 cmp %g1, %g5
bne,pt %icc, spitfire_startup bne,pt %icc, spitfire_startup
nop nop
cheetah_plus_startup:
/* Preserve OBP choosen DCU and DCR register settings. */
ba,pt %xcc, cheetah_generic_startup
nop
cheetah_startup: cheetah_startup:
mov DCR_BPE | DCR_RPE | DCR_SI | DCR_IFPOE | DCR_MS, %g1 mov DCR_BPE | DCR_RPE | DCR_SI | DCR_IFPOE | DCR_MS, %g1
wr %g1, %asr18 wr %g1, %asr18
...@@ -52,6 +61,7 @@ cheetah_startup: ...@@ -52,6 +61,7 @@ cheetah_startup:
stxa %g5, [%g0] ASI_DCU_CONTROL_REG stxa %g5, [%g0] ASI_DCU_CONTROL_REG
membar #Sync membar #Sync
cheetah_generic_startup:
mov TSB_EXTENSION_P, %g3 mov TSB_EXTENSION_P, %g3
stxa %g0, [%g3] ASI_DMMU stxa %g0, [%g3] ASI_DMMU
stxa %g0, [%g3] ASI_IMMU stxa %g0, [%g3] ASI_IMMU
...@@ -118,9 +128,14 @@ startup_continue: ...@@ -118,9 +128,14 @@ startup_continue:
stx %g2, [%sp + 2047 + 128 + 0x30] stx %g2, [%sp + 2047 + 128 + 0x30]
rdpr %ver, %g1 rdpr %ver, %g1
sethi %hi(0x003e0014), %g5 sethi %hi(CHEETAH_ID), %g5
srlx %g1, 32, %g1 srlx %g1, 32, %g1
or %g5, %lo(0x003e0014), %g5 or %g5, %lo(CHEETAH_ID), %g5
cmp %g1, %g5
be,a,pn %icc, 1f
mov 15, %g2
sethi %hi(CHEETAH_PLUS_ID), %g5
or %g5, %lo(CHEETAH_PLUS_ID), %g5
cmp %g1, %g5 cmp %g1, %g5
bne,a,pt %icc, 1f bne,a,pt %icc, 1f
mov 63, %g2 mov 63, %g2
...@@ -153,9 +168,14 @@ startup_continue: ...@@ -153,9 +168,14 @@ startup_continue:
stx %g2, [%sp + 2047 + 128 + 0x30] stx %g2, [%sp + 2047 + 128 + 0x30]
rdpr %ver, %g1 rdpr %ver, %g1
sethi %hi(0x003e0014), %g5 sethi %hi(CHEETAH_ID), %g5
srlx %g1, 32, %g1 srlx %g1, 32, %g1
or %g5, %lo(0x003e0014), %g5 or %g5, %lo(CHEETAH_ID), %g5
cmp %g1, %g5
be,a,pn %icc, 1f
mov 15, %g2
sethi %hi(CHEETAH_PLUS_ID), %g5
or %g5, %lo(CHEETAH_PLUS_ID), %g5
cmp %g1, %g5 cmp %g1, %g5
bne,a,pt %icc, 1f bne,a,pt %icc, 1f
mov 63, %g2 mov 63, %g2
...@@ -225,13 +245,18 @@ startup_continue: ...@@ -225,13 +245,18 @@ startup_continue:
or %g2, KERN_LOWBITS, %g2 or %g2, KERN_LOWBITS, %g2
rdpr %ver, %g3 rdpr %ver, %g3
sethi %hi(0x003e0014), %g7 sethi %hi(CHEETAH_ID), %g7
srlx %g3, 32, %g3 srlx %g3, 32, %g3
or %g7, %lo(0x003e0014), %g7 or %g7, %lo(CHEETAH_ID), %g7
cmp %g3, %g7
be,pn %icc, 9f
sethi %hi(CHEETAH_PLUS_ID), %g7
or %g7, %lo(CHEETAH_PLUS_ID), %g7
cmp %g3, %g7 cmp %g3, %g7
bne,pt %icc, 1f bne,pt %icc, 1f
nop nop
9:
sethi %uhi(VPTE_BASE_CHEETAH), %g3 sethi %uhi(VPTE_BASE_CHEETAH), %g3
or %g3, %ulo(VPTE_BASE_CHEETAH), %g3 or %g3, %ulo(VPTE_BASE_CHEETAH), %g3
ba,pt %xcc, 2f ba,pt %xcc, 2f
......
...@@ -167,7 +167,7 @@ static void clean_and_reenable_l1_caches(void) ...@@ -167,7 +167,7 @@ static void clean_and_reenable_l1_caches(void)
LSU_CONTROL_IM | LSU_CONTROL_DM), LSU_CONTROL_IM | LSU_CONTROL_DM),
"i" (ASI_LSU_CONTROL) "i" (ASI_LSU_CONTROL)
: "memory"); : "memory");
} else if (tlb_type == cheetah) { } else if (tlb_type == cheetah || tlb_type == cheetah_plus) {
/* Flush D-cache */ /* Flush D-cache */
for (va = 0; va < (1 << 16); va += (1 << 5)) { for (va = 0; va < (1 << 16); va += (1 << 5)) {
__asm__ __volatile__("stxa %%g0, [%0] %1\n\t" __asm__ __volatile__("stxa %%g0, [%0] %1\n\t"
...@@ -201,7 +201,7 @@ void do_dae(struct pt_regs *regs) ...@@ -201,7 +201,7 @@ void do_dae(struct pt_regs *regs)
pci_poke_faulted = 1; pci_poke_faulted = 1;
/* Why the fuck did they have to change this? */ /* Why the fuck did they have to change this? */
if (tlb_type == cheetah) if (tlb_type == cheetah || tlb_type == cheetah_plus)
regs->tpc += 4; regs->tpc += 4;
regs->tnpc = regs->tpc + 4; regs->tnpc = regs->tpc + 4;
...@@ -390,10 +390,14 @@ static __inline__ struct cheetah_err_info *cheetah_get_error_log(unsigned long a ...@@ -390,10 +390,14 @@ static __inline__ struct cheetah_err_info *cheetah_get_error_log(unsigned long a
return p; return p;
} }
extern unsigned int tl0_icpe[], tl1_icpe[];
extern unsigned int tl0_dcpe[], tl1_dcpe[];
extern unsigned int tl0_fecc[], tl1_fecc[]; extern unsigned int tl0_fecc[], tl1_fecc[];
extern unsigned int tl0_cee[], tl1_cee[]; extern unsigned int tl0_cee[], tl1_cee[];
extern unsigned int tl0_iae[], tl1_iae[]; extern unsigned int tl0_iae[], tl1_iae[];
extern unsigned int tl0_dae[], tl1_dae[]; extern unsigned int tl0_dae[], tl1_dae[];
extern unsigned int cheetah_plus_icpe_trap_vector[], cheetah_plus_icpe_trap_vector_tl1[];
extern unsigned int cheetah_plus_dcpe_trap_vector[], cheetah_plus_dcpe_trap_vector_tl1[];
extern unsigned int cheetah_fecc_trap_vector[], cheetah_fecc_trap_vector_tl1[]; extern unsigned int cheetah_fecc_trap_vector[], cheetah_fecc_trap_vector_tl1[];
extern unsigned int cheetah_cee_trap_vector[], cheetah_cee_trap_vector_tl1[]; extern unsigned int cheetah_cee_trap_vector[], cheetah_cee_trap_vector_tl1[];
extern unsigned int cheetah_deferred_trap_vector[], cheetah_deferred_trap_vector_tl1[]; extern unsigned int cheetah_deferred_trap_vector[], cheetah_deferred_trap_vector_tl1[];
...@@ -487,6 +491,12 @@ void __init cheetah_ecache_flush_init(void) ...@@ -487,6 +491,12 @@ void __init cheetah_ecache_flush_init(void)
memcpy(tl1_iae, cheetah_deferred_trap_vector_tl1, (8 * 4)); memcpy(tl1_iae, cheetah_deferred_trap_vector_tl1, (8 * 4));
memcpy(tl0_dae, cheetah_deferred_trap_vector, (8 * 4)); memcpy(tl0_dae, cheetah_deferred_trap_vector, (8 * 4));
memcpy(tl1_dae, cheetah_deferred_trap_vector_tl1, (8 * 4)); memcpy(tl1_dae, cheetah_deferred_trap_vector_tl1, (8 * 4));
if (tlb_type == cheetah_plus) {
memcpy(tl0_dcpe, cheetah_plus_dcpe_trap_vector, (8 * 4));
memcpy(tl1_dcpe, cheetah_plus_dcpe_trap_vector_tl1, (8 * 4));
memcpy(tl0_icpe, cheetah_plus_icpe_trap_vector, (8 * 4));
memcpy(tl1_icpe, cheetah_plus_icpe_trap_vector_tl1, (8 * 4));
}
flushi(PAGE_OFFSET); flushi(PAGE_OFFSET);
} }
...@@ -567,9 +577,22 @@ unsigned long __init cheetah_tune_scheduling(void) ...@@ -567,9 +577,22 @@ unsigned long __init cheetah_tune_scheduling(void)
* *
* So we must only flush the I-cache when it is disabled. * So we must only flush the I-cache when it is disabled.
*/ */
static void __cheetah_flush_icache(void)
{
unsigned long i;
/* Clear the valid bits in all the tags. */
for (i = 0; i < (1 << 15); i += (1 << 5)) {
__asm__ __volatile__("stxa %%g0, [%0] %1\n\t"
"membar #Sync"
: /* no outputs */
: "r" (i | (2 << 3)), "i" (ASI_IC_TAG));
}
}
static void cheetah_flush_icache(void) static void cheetah_flush_icache(void)
{ {
unsigned long dcu_save, i; unsigned long dcu_save;
/* Save current DCU, disable I-cache. */ /* Save current DCU, disable I-cache. */
__asm__ __volatile__("ldxa [%%g0] %1, %0\n\t" __asm__ __volatile__("ldxa [%%g0] %1, %0\n\t"
...@@ -580,13 +603,7 @@ static void cheetah_flush_icache(void) ...@@ -580,13 +603,7 @@ static void cheetah_flush_icache(void)
: "i" (ASI_DCU_CONTROL_REG), "i" (DCU_IC) : "i" (ASI_DCU_CONTROL_REG), "i" (DCU_IC)
: "g1"); : "g1");
/* Clear the valid bits in all the tags. */ __cheetah_flush_icache();
for (i = 0; i < (1 << 16); i += (1 << 5)) {
__asm__ __volatile__("stxa %%g0, [%0] %1\n\t"
"membar #Sync"
: /* no outputs */
: "r" (i | (2 << 3)), "i" (ASI_IC_TAG));
}
/* Restore DCU register */ /* Restore DCU register */
__asm__ __volatile__("stxa %0, [%%g0] %1\n\t" __asm__ __volatile__("stxa %0, [%%g0] %1\n\t"
...@@ -607,6 +624,34 @@ static void cheetah_flush_dcache(void) ...@@ -607,6 +624,34 @@ static void cheetah_flush_dcache(void)
} }
} }
/* In order to make the even parity correct we must do two things.
* First, we clear DC_data_parity and set DC_utag to an appropriate value.
* Next, we clear out all 32-bytes of data for that line. Data of
* all-zero + tag parity value of zero == correct parity.
*/
static void cheetah_plus_zap_dcache_parity(void)
{
unsigned long i;
for (i = 0; i < (1 << 16); i += (1 << 5)) {
unsigned long tag = (i >> 14);
unsigned long j;
__asm__ __volatile__("membar #Sync\n\t"
"stxa %0, [%1] %2\n\t"
"membar #Sync"
: /* no outputs */
: "r" (tag), "r" (i),
"i" (ASI_DCACHE_UTAG));
for (j = i; j < i + (1 << 5); j += (1 << 3))
__asm__ __volatile__("membar #Sync\n\t"
"stxa %%g0, [%0] %1\n\t"
"membar #Sync"
: /* no outputs */
: "r" (j), "i" (ASI_DCACHE_DATA));
}
}
/* Conversion tables used to frob Cheetah AFSR syndrome values into /* Conversion tables used to frob Cheetah AFSR syndrome values into
* something palatable to the memory controller driver get_unumber * something palatable to the memory controller driver get_unumber
* routine. * routine.
...@@ -1327,6 +1372,46 @@ void cheetah_deferred_handler(struct pt_regs *regs, unsigned long afsr, unsigned ...@@ -1327,6 +1372,46 @@ void cheetah_deferred_handler(struct pt_regs *regs, unsigned long afsr, unsigned
panic("Irrecoverable deferred error trap.\n"); panic("Irrecoverable deferred error trap.\n");
} }
/* Handle a D/I cache parity error trap. TYPE is encoded as:
*
* Bit0: 0=dcache,1=icache
* Bit1: 0=recoverable,1=unrecoverable
*
* The hardware has disabled both the I-cache and D-cache in
* the %dcr register.
*/
void cheetah_plus_parity_error(int type, struct pt_regs *regs)
{
if (type & 0x1)
__cheetah_flush_icache();
else
cheetah_plus_zap_dcache_parity();
cheetah_flush_dcache();
/* Re-enable I-cache/D-cache */
__asm__ __volatile__("ldxa [%%g0] %0, %%g1\n\t"
"or %%g1, %1, %%g1\n\t"
"stxa %%g1, [%%g0] %0\n\t"
"membar #Sync"
: /* no outputs */
: "i" (ASI_DCU_CONTROL_REG),
"i" (DCU_DC | DCU_IC)
: "g1");
if (type & 0x2) {
printk(KERN_EMERG "CPU[%d]: Cheetah+ %c-cache parity error at TPC[%016lx]\n",
smp_processor_id(),
(type & 0x1) ? 'I' : 'D',
regs->tpc);
panic("Irrecoverable Cheetah+ parity error.");
}
printk(KERN_WARNING "CPU[%d]: Cheetah+ %c-cache parity error at TPC[%016lx]\n",
smp_processor_id(),
(type & 0x1) ? 'I' : 'D',
regs->tpc);
}
void do_fpe_common(struct pt_regs *regs) void do_fpe_common(struct pt_regs *regs)
{ {
if (regs->tstate & TSTATE_PRIV) { if (regs->tstate & TSTATE_PRIV) {
......
...@@ -7,6 +7,8 @@ ...@@ -7,6 +7,8 @@
#include <linux/config.h> #include <linux/config.h>
.globl sparc64_ttable_tl0, sparc64_ttable_tl1 .globl sparc64_ttable_tl0, sparc64_ttable_tl1
.globl tl0_icpe, tl1_icpe
.globl tl0_dcpe, tl1_dcpe
.globl tl0_fecc, tl1_fecc .globl tl0_fecc, tl1_fecc
.globl tl0_cee, tl1_cee .globl tl0_cee, tl1_cee
.globl tl0_iae, tl1_iae .globl tl0_iae, tl1_iae
...@@ -79,7 +81,9 @@ tl0_damiss: ...@@ -79,7 +81,9 @@ tl0_damiss:
tl0_daprot: tl0_daprot:
#include "dtlb_prot.S" #include "dtlb_prot.S"
tl0_fecc: BTRAP(0x70) /* Fast-ECC on Cheetah */ tl0_fecc: BTRAP(0x70) /* Fast-ECC on Cheetah */
tl0_resv071: BTRAP(0x71) BTRAP(0x72) BTRAP(0x73) BTRAP(0x74) BTRAP(0x75) tl0_dcpe: BTRAP(0x71) /* D-cache Parity Error on Cheetah+ */
tl0_icpe: BTRAP(0x72) /* I-cache Parity Error on Cheetah+ */
tl0_resv073: BTRAP(0x73) BTRAP(0x74) BTRAP(0x75)
tl0_resv076: BTRAP(0x76) BTRAP(0x77) BTRAP(0x78) BTRAP(0x79) BTRAP(0x7a) BTRAP(0x7b) tl0_resv076: BTRAP(0x76) BTRAP(0x77) BTRAP(0x78) BTRAP(0x79) BTRAP(0x7a) BTRAP(0x7b)
tl0_resv07c: BTRAP(0x7c) BTRAP(0x7d) BTRAP(0x7e) BTRAP(0x7f) tl0_resv07c: BTRAP(0x7c) BTRAP(0x7d) BTRAP(0x7e) BTRAP(0x7f)
tl0_s0n: SPILL_0_NORMAL tl0_s0n: SPILL_0_NORMAL
...@@ -235,8 +239,10 @@ tl1_damiss: ...@@ -235,8 +239,10 @@ tl1_damiss:
#include "dtlb_backend.S" #include "dtlb_backend.S"
tl1_daprot: tl1_daprot:
#include "dtlb_prot.S" #include "dtlb_prot.S"
tl1_fecc: BTRAP(0x70) /* Fast-ECC on Cheetah */ tl1_fecc: BTRAPTL1(0x70) /* Fast-ECC on Cheetah */
tl1_resc071: BTRAPTL1(0x71) BTRAPTL1(0x72) BTRAPTL1(0x73) tl1_dcpe: BTRAPTL1(0x71) /* D-cache Parity Error on Cheetah+ */
tl1_icpe: BTRAPTL1(0x72) /* I-cache Parity Error on Cheetah+ */
tl1_resv073: BTRAPTL1(0x73)
tl1_resv074: BTRAPTL1(0x74) BTRAPTL1(0x75) BTRAPTL1(0x76) BTRAPTL1(0x77) tl1_resv074: BTRAPTL1(0x74) BTRAPTL1(0x75) BTRAPTL1(0x76) BTRAPTL1(0x77)
tl1_resv078: BTRAPTL1(0x78) BTRAPTL1(0x79) BTRAPTL1(0x7a) BTRAPTL1(0x7b) tl1_resv078: BTRAPTL1(0x78) BTRAPTL1(0x79) BTRAPTL1(0x7a) BTRAPTL1(0x7b)
tl1_resv07c: BTRAPTL1(0x7c) BTRAPTL1(0x7d) BTRAPTL1(0x7e) BTRAPTL1(0x7f) tl1_resv07c: BTRAPTL1(0x7c) BTRAPTL1(0x7d) BTRAPTL1(0x7e) BTRAPTL1(0x7f)
......
...@@ -66,14 +66,14 @@ cheetah_patch_1: ...@@ -66,14 +66,14 @@ cheetah_patch_1:
ldx [%g6 + TI_FLAGS], %g3 ldx [%g6 + TI_FLAGS], %g3
/* Spitfire Errata #32 workaround */ /* Spitfire Errata #32 workaround */
mov 0x8, %o4 mov PRIMARY_CONTEXT, %o4
stxa %g0, [%o4] ASI_DMMU stxa %g0, [%o4] ASI_DMMU
membar #Sync membar #Sync
ldxa [%o3] ASI_DTLB_TAG_READ, %o4 ldxa [%o3] ASI_DTLB_TAG_READ, %o4
/* Spitfire Errata #32 workaround */ /* Spitfire Errata #32 workaround */
mov 0x8, %o5 mov PRIMARY_CONTEXT, %o5
stxa %g0, [%o5] ASI_DMMU stxa %g0, [%o5] ASI_DMMU
membar #Sync membar #Sync
...@@ -85,14 +85,14 @@ cheetah_patch_1: ...@@ -85,14 +85,14 @@ cheetah_patch_1:
add %o3, (TLBTEMP_ENTSZ), %o3 add %o3, (TLBTEMP_ENTSZ), %o3
/* Spitfire Errata #32 workaround */ /* Spitfire Errata #32 workaround */
mov 0x8, %g5 mov PRIMARY_CONTEXT, %g5
stxa %g0, [%g5] ASI_DMMU stxa %g0, [%g5] ASI_DMMU
membar #Sync membar #Sync
ldxa [%o3] ASI_DTLB_TAG_READ, %g5 ldxa [%o3] ASI_DTLB_TAG_READ, %g5
/* Spitfire Errata #32 workaround */ /* Spitfire Errata #32 workaround */
mov 0x8, %g7 mov PRIMARY_CONTEXT, %g7
stxa %g0, [%g7] ASI_DMMU stxa %g0, [%g7] ASI_DMMU
membar #Sync membar #Sync
...@@ -109,7 +109,9 @@ cheetah_patch_1: ...@@ -109,7 +109,9 @@ cheetah_patch_1:
rdpr %ver, %g3 rdpr %ver, %g3
sllx %g3, 16, %g3 sllx %g3, 16, %g3
srlx %g3, 32 + 16, %g3 srlx %g3, 32 + 16, %g3
cmp %g3, 0x14 cmp %g3, 0x14 ! CHEETAH_ID
be,pn %icc, cheetah_copy_user_page
cmp %g3, 0x15 ! CHEETAH_PLUS_ID
bne,pt %icc, spitfire_copy_user_page bne,pt %icc, spitfire_copy_user_page
nop nop
...@@ -357,14 +359,14 @@ cheetah_patch_2: ...@@ -357,14 +359,14 @@ cheetah_patch_2:
wrpr %g3, PSTATE_IE, %pstate wrpr %g3, PSTATE_IE, %pstate
/* Spitfire Errata #32 workaround */ /* Spitfire Errata #32 workaround */
mov 0x8, %g5 mov PRIMARY_CONTEXT, %g5
stxa %g0, [%g5] ASI_DMMU stxa %g0, [%g5] ASI_DMMU
membar #Sync membar #Sync
ldxa [%o3] ASI_DTLB_TAG_READ, %g5 ldxa [%o3] ASI_DTLB_TAG_READ, %g5
/* Spitfire Errata #32 workaround */ /* Spitfire Errata #32 workaround */
mov 0x8, %g7 mov PRIMARY_CONTEXT, %g7
stxa %g0, [%g7] ASI_DMMU stxa %g0, [%g7] ASI_DMMU
membar #Sync membar #Sync
...@@ -409,7 +411,8 @@ clear_page_common: ...@@ -409,7 +411,8 @@ clear_page_common:
retl retl
nop nop
1: stxa %g5, [%o2] ASI_DMMU 1:
stxa %g5, [%o2] ASI_DMMU
stxa %g7, [%o3] ASI_DTLB_DATA_ACCESS stxa %g7, [%o3] ASI_DTLB_DATA_ACCESS
membar #Sync membar #Sync
jmpl %o7 + 0x8, %g0 jmpl %o7 + 0x8, %g0
......
...@@ -345,6 +345,8 @@ void mmu_info(struct seq_file *m) ...@@ -345,6 +345,8 @@ void mmu_info(struct seq_file *m)
{ {
if (tlb_type == cheetah) if (tlb_type == cheetah)
seq_printf(m, "MMU Type\t: Cheetah\n"); seq_printf(m, "MMU Type\t: Cheetah\n");
else if (tlb_type == cheetah_plus)
seq_printf(m, "MMU Type\t: Cheetah+\n");
else if (tlb_type == spitfire) else if (tlb_type == spitfire)
seq_printf(m, "MMU Type\t: Spitfire\n"); seq_printf(m, "MMU Type\t: Spitfire\n");
else else
...@@ -514,6 +516,7 @@ static void inherit_prom_mappings(void) ...@@ -514,6 +516,7 @@ static void inherit_prom_mappings(void)
break; break;
case cheetah: case cheetah:
case cheetah_plus:
phys_page = cheetah_get_litlb_data(sparc64_highest_locked_tlbent()); phys_page = cheetah_get_litlb_data(sparc64_highest_locked_tlbent());
break; break;
}; };
...@@ -539,7 +542,7 @@ static void inherit_prom_mappings(void) ...@@ -539,7 +542,7 @@ static void inherit_prom_mappings(void)
"i" (ASI_DMMU), "i" (ASI_DTLB_DATA_ACCESS), "i" (ASI_DMMU), "i" (ASI_DTLB_DATA_ACCESS),
"i" (ASI_IMMU), "i" (ASI_ITLB_DATA_ACCESS) "i" (ASI_IMMU), "i" (ASI_ITLB_DATA_ACCESS)
: "memory"); : "memory");
} else if (tlb_type == cheetah) { } else if (tlb_type == cheetah || tlb_type == cheetah_plus) {
/* Lock this into i/d tlb-0 entry 11 */ /* Lock this into i/d tlb-0 entry 11 */
__asm__ __volatile__( __asm__ __volatile__(
"stxa %%g0, [%2] %3\n\t" "stxa %%g0, [%2] %3\n\t"
...@@ -684,9 +687,9 @@ static void __flush_nucleus_vptes(void) ...@@ -684,9 +687,9 @@ static void __flush_nucleus_vptes(void)
spitfire_put_dtlb_data(i, 0x0UL); spitfire_put_dtlb_data(i, 0x0UL);
} }
} }
} else if (tlb_type == cheetah) { } else if (tlb_type == cheetah || tlb_type == cheetah_plus) {
for (i = 0; i < 512; i++) { for (i = 0; i < 512; i++) {
unsigned long tag = cheetah_get_dtlb_tag(i); unsigned long tag = cheetah_get_dtlb_tag(i, 2);
if ((tag & ~PAGE_MASK) == 0 && if ((tag & ~PAGE_MASK) == 0 &&
(tag & PAGE_MASK) >= prom_reserved_base) { (tag & PAGE_MASK) >= prom_reserved_base) {
...@@ -694,7 +697,21 @@ static void __flush_nucleus_vptes(void) ...@@ -694,7 +697,21 @@ static void __flush_nucleus_vptes(void)
"membar #Sync" "membar #Sync"
: /* no outputs */ : /* no outputs */
: "r" (TLB_TAG_ACCESS), "i" (ASI_DMMU)); : "r" (TLB_TAG_ACCESS), "i" (ASI_DMMU));
cheetah_put_dtlb_data(i, 0x0UL); cheetah_put_dtlb_data(i, 0x0UL, 2);
}
if (tlb_type != cheetah_plus)
continue;
tag = cheetah_get_dtlb_tag(i, 3);
if ((tag & ~PAGE_MASK) == 0 &&
(tag & PAGE_MASK) >= prom_reserved_base) {
__asm__ __volatile__("stxa %%g0, [%0] %1\n\t"
"membar #Sync"
: /* no outputs */
: "r" (TLB_TAG_ACCESS), "i" (ASI_DMMU));
cheetah_put_dtlb_data(i, 0x0UL, 3);
} }
} }
} else { } else {
...@@ -743,7 +760,7 @@ void prom_world(int enter) ...@@ -743,7 +760,7 @@ void prom_world(int enter)
if (tlb_type == spitfire) if (tlb_type == spitfire)
spitfire_put_dtlb_data(prom_dtlb[i].tlb_ent, spitfire_put_dtlb_data(prom_dtlb[i].tlb_ent,
prom_dtlb[i].tlb_data); prom_dtlb[i].tlb_data);
else if (tlb_type == cheetah) else if (tlb_type == cheetah || tlb_type == cheetah_plus)
cheetah_put_ldtlb_data(prom_dtlb[i].tlb_ent, cheetah_put_ldtlb_data(prom_dtlb[i].tlb_ent,
prom_dtlb[i].tlb_data); prom_dtlb[i].tlb_data);
} }
...@@ -756,7 +773,7 @@ void prom_world(int enter) ...@@ -756,7 +773,7 @@ void prom_world(int enter)
if (tlb_type == spitfire) if (tlb_type == spitfire)
spitfire_put_itlb_data(prom_itlb[i].tlb_ent, spitfire_put_itlb_data(prom_itlb[i].tlb_ent,
prom_itlb[i].tlb_data); prom_itlb[i].tlb_data);
else if (tlb_type == cheetah) else if (tlb_type == cheetah || tlb_type == cheetah_plus)
cheetah_put_litlb_data(prom_itlb[i].tlb_ent, cheetah_put_litlb_data(prom_itlb[i].tlb_ent,
prom_itlb[i].tlb_data); prom_itlb[i].tlb_data);
} }
...@@ -891,7 +908,7 @@ void inherit_locked_prom_mappings(int save_p) ...@@ -891,7 +908,7 @@ void inherit_locked_prom_mappings(int save_p)
break; break;
} }
} }
} else if (tlb_type == cheetah) { } else if (tlb_type == cheetah || tlb_type == cheetah_plus) {
int high = CHEETAH_HIGHEST_LOCKED_TLBENT - bigkernel; int high = CHEETAH_HIGHEST_LOCKED_TLBENT - bigkernel;
for (i = 0; i < high; i++) { for (i = 0; i < high; i++) {
...@@ -963,7 +980,7 @@ void prom_reload_locked(void) ...@@ -963,7 +980,7 @@ void prom_reload_locked(void)
if (tlb_type == spitfire) if (tlb_type == spitfire)
spitfire_put_dtlb_data(prom_dtlb[i].tlb_ent, spitfire_put_dtlb_data(prom_dtlb[i].tlb_ent,
prom_dtlb[i].tlb_data); prom_dtlb[i].tlb_data);
else if (tlb_type == cheetah) else if (tlb_type == cheetah || tlb_type == cheetah_plus)
cheetah_put_ldtlb_data(prom_dtlb[i].tlb_ent, cheetah_put_ldtlb_data(prom_dtlb[i].tlb_ent,
prom_dtlb[i].tlb_data); prom_dtlb[i].tlb_data);
} }
...@@ -1064,7 +1081,7 @@ void __flush_tlb_all(void) ...@@ -1064,7 +1081,7 @@ void __flush_tlb_all(void)
spitfire_put_itlb_data(i, 0x0UL); spitfire_put_itlb_data(i, 0x0UL);
} }
} }
} else if (tlb_type == cheetah) { } else if (tlb_type == cheetah || tlb_type == cheetah_plus) {
cheetah_flush_dtlb_all(); cheetah_flush_dtlb_all();
cheetah_flush_itlb_all(); cheetah_flush_itlb_all();
} }
...@@ -1208,7 +1225,7 @@ void sparc_ultra_dump_itlb(void) ...@@ -1208,7 +1225,7 @@ void sparc_ultra_dump_itlb(void)
slot+2, slot+2,
spitfire_get_itlb_tag(slot+2), spitfire_get_itlb_data(slot+2)); spitfire_get_itlb_tag(slot+2), spitfire_get_itlb_data(slot+2));
} }
} else if (tlb_type == cheetah) { } else if (tlb_type == cheetah || tlb_type == cheetah_plus) {
printk ("Contents of itlb0:\n"); printk ("Contents of itlb0:\n");
for (slot = 0; slot < 16; slot+=2) { for (slot = 0; slot < 16; slot+=2) {
printk ("%2x:%016lx,%016lx %2x:%016lx,%016lx\n", printk ("%2x:%016lx,%016lx %2x:%016lx,%016lx\n",
...@@ -1246,7 +1263,7 @@ void sparc_ultra_dump_dtlb(void) ...@@ -1246,7 +1263,7 @@ void sparc_ultra_dump_dtlb(void)
slot+2, slot+2,
spitfire_get_dtlb_tag(slot+2), spitfire_get_dtlb_data(slot+2)); spitfire_get_dtlb_tag(slot+2), spitfire_get_dtlb_data(slot+2));
} }
} else if (tlb_type == cheetah) { } else if (tlb_type == cheetah || tlb_type == cheetah_plus) {
printk ("Contents of dtlb0:\n"); printk ("Contents of dtlb0:\n");
for (slot = 0; slot < 16; slot+=2) { for (slot = 0; slot < 16; slot+=2) {
printk ("%2x:%016lx,%016lx %2x:%016lx,%016lx\n", printk ("%2x:%016lx,%016lx %2x:%016lx,%016lx\n",
...@@ -1259,9 +1276,19 @@ void sparc_ultra_dump_dtlb(void) ...@@ -1259,9 +1276,19 @@ void sparc_ultra_dump_dtlb(void)
for (slot = 0; slot < 512; slot+=2) { for (slot = 0; slot < 512; slot+=2) {
printk ("%2x:%016lx,%016lx %2x:%016lx,%016lx\n", printk ("%2x:%016lx,%016lx %2x:%016lx,%016lx\n",
slot, slot,
cheetah_get_dtlb_tag(slot), cheetah_get_dtlb_data(slot), cheetah_get_dtlb_tag(slot, 2), cheetah_get_dtlb_data(slot, 2),
slot+1, slot+1,
cheetah_get_dtlb_tag(slot+1), cheetah_get_dtlb_data(slot+1)); cheetah_get_dtlb_tag(slot+1, 2), cheetah_get_dtlb_data(slot+1, 2));
}
if (tlb_type == cheetah_plus) {
printk ("Contents of dtlb3:\n");
for (slot = 0; slot < 512; slot+=2) {
printk ("%2x:%016lx,%016lx %2x:%016lx,%016lx\n",
slot,
cheetah_get_dtlb_tag(slot, 3), cheetah_get_dtlb_data(slot, 3),
slot+1,
cheetah_get_dtlb_tag(slot+1, 3), cheetah_get_dtlb_data(slot+1, 3));
}
} }
} }
} }
...@@ -1439,7 +1466,7 @@ void __init paging_init(void) ...@@ -1439,7 +1466,7 @@ void __init paging_init(void)
"i" (ASI_DMMU), "i" (ASI_DTLB_DATA_ACCESS), "r" (60 << 3) "i" (ASI_DMMU), "i" (ASI_DTLB_DATA_ACCESS), "r" (60 << 3)
: "memory"); : "memory");
} }
} else if (tlb_type == cheetah) { } else if (tlb_type == cheetah || tlb_type == cheetah_plus) {
__asm__ __volatile__( __asm__ __volatile__(
" stxa %1, [%0] %3\n" " stxa %1, [%0] %3\n"
" stxa %2, [%5] %4\n" " stxa %2, [%5] %4\n"
...@@ -1745,7 +1772,7 @@ void __init mem_init(void) ...@@ -1745,7 +1772,7 @@ void __init mem_init(void)
initpages << (PAGE_SHIFT-10), initpages << (PAGE_SHIFT-10),
PAGE_OFFSET, (last_valid_pfn << PAGE_SHIFT)); PAGE_OFFSET, (last_valid_pfn << PAGE_SHIFT));
if (tlb_type == cheetah) if (tlb_type == cheetah || tlb_type == cheetah_plus)
cheetah_ecache_flush_init(); cheetah_ecache_flush_init();
} }
......
...@@ -14,21 +14,12 @@ ...@@ -14,21 +14,12 @@
#include <asm/head.h> #include <asm/head.h>
#include <asm/thread_info.h> #include <asm/thread_info.h>
/* Basically, all this madness has to do with the /* Basically, most of the Spitfire vs. Cheetah madness
* fact that Cheetah does not support IMMU flushes * has to do with the fact that Cheetah does not support
* out of the secondary context. Someone needs to * IMMU flushes out of the secondary context. Someone needs
* throw a south lake birthday party for the folks * to throw a south lake birthday party for the folks
* in Microelectronics who refused to fix this shit. * in Microelectronics who refused to fix this shit.
*/ */
#define BRANCH_IF_CHEETAH(tmp1, tmp2, label) \
rdpr %ver, %tmp1; \
sethi %hi(0x003e0014), %tmp2; \
srlx %tmp1, 32, %tmp1; \
or %tmp2, %lo(0x003e0014), %tmp2; \
cmp %tmp1, %tmp2; \
be,pn %icc, label; \
nop; \
nop;
/* This file is meant to be read efficiently by the CPU, not humans. /* This file is meant to be read efficiently by the CPU, not humans.
* Staraj sie tego nikomu nie pierdolnac... * Staraj sie tego nikomu nie pierdolnac...
...@@ -37,9 +28,7 @@ ...@@ -37,9 +28,7 @@
.align 32 .align 32
.globl __flush_tlb_page, __flush_tlb_mm, __flush_tlb_range .globl __flush_tlb_page, __flush_tlb_mm, __flush_tlb_range
__flush_tlb_page: /* %o0=(ctx & TAG_CONTEXT_BITS), %o1=page&PAGE_MASK, %o2=SECONDARY_CONTEXT */ __flush_tlb_page: /* %o0=(ctx & TAG_CONTEXT_BITS), %o1=page&PAGE_MASK, %o2=SECONDARY_CONTEXT */
/*IC1*/ BRANCH_IF_CHEETAH(g2, g3, __cheetah_flush_tlb_page) ldxa [%o2] ASI_DMMU, %g2
__spitfire_flush_tlb_page:
/*IC2*/ ldxa [%o2] ASI_DMMU, %g2
cmp %g2, %o0 cmp %g2, %o0
bne,pn %icc, __spitfire_flush_tlb_page_slow bne,pn %icc, __spitfire_flush_tlb_page_slow
or %o1, 0x10, %g3 or %o1, 0x10, %g3
...@@ -47,27 +36,17 @@ __spitfire_flush_tlb_page: ...@@ -47,27 +36,17 @@ __spitfire_flush_tlb_page:
stxa %g0, [%g3] ASI_IMMU_DEMAP stxa %g0, [%g3] ASI_IMMU_DEMAP
retl retl
flush %g6 flush %g6
__cheetah_flush_tlb_page:
/*IC3*/ rdpr %pstate, %g5
andn %g5, PSTATE_IE, %g2
wrpr %g2, 0x0, %pstate
wrpr %g0, 1, %tl
mov PRIMARY_CONTEXT, %o2
ldxa [%o2] ASI_DMMU, %g2
stxa %o0, [%o2] ASI_DMMU
stxa %g0, [%o1] ASI_DMMU_DEMAP
/*IC4*/ stxa %g0, [%o1] ASI_IMMU_DEMAP
stxa %g2, [%o2] ASI_DMMU
flush %g6
wrpr %g0, 0, %tl
retl
wrpr %g5, 0x0, %pstate
nop nop
nop nop
nop
nop
nop
nop
nop
nop
__flush_tlb_mm: /* %o0=(ctx & TAG_CONTEXT_BITS), %o1=SECONDARY_CONTEXT */ __flush_tlb_mm: /* %o0=(ctx & TAG_CONTEXT_BITS), %o1=SECONDARY_CONTEXT */
/*IC5*/ BRANCH_IF_CHEETAH(g2, g3, __cheetah_flush_tlb_mm) ldxa [%o1] ASI_DMMU, %g2
__spitfire_flush_tlb_mm:
/*IC6*/ ldxa [%o1] ASI_DMMU, %g2
cmp %g2, %o0 cmp %g2, %o0
bne,pn %icc, __spitfire_flush_tlb_mm_slow bne,pn %icc, __spitfire_flush_tlb_mm_slow
mov 0x50, %g3 mov 0x50, %g3
...@@ -75,30 +54,20 @@ __spitfire_flush_tlb_mm: ...@@ -75,30 +54,20 @@ __spitfire_flush_tlb_mm:
stxa %g0, [%g3] ASI_IMMU_DEMAP stxa %g0, [%g3] ASI_IMMU_DEMAP
retl retl
flush %g6 flush %g6
__cheetah_flush_tlb_mm:
/*IC7*/ rdpr %pstate, %g5
andn %g5, PSTATE_IE, %g2
wrpr %g2, 0x0, %pstate
wrpr %g0, 1, %tl
mov PRIMARY_CONTEXT, %o2
mov 0x40, %g3
ldxa [%o2] ASI_DMMU, %g2
stxa %o0, [%o2] ASI_DMMU
/*IC8*/ stxa %g0, [%g3] ASI_DMMU_DEMAP
stxa %g0, [%g3] ASI_IMMU_DEMAP
stxa %g2, [%o2] ASI_DMMU
flush %g6
wrpr %g0, 0, %tl
retl
wrpr %g5, 0x0, %pstate
nop nop
nop
nop
nop
nop
nop
nop
nop
__flush_tlb_range: /* %o0=(ctx&TAG_CONTEXT_BITS), %o1=start&PAGE_MASK, %o2=SECONDARY_CONTEXT, __flush_tlb_range: /* %o0=(ctx&TAG_CONTEXT_BITS), %o1=start&PAGE_MASK, %o2=SECONDARY_CONTEXT,
* %o3=end&PAGE_MASK, %o4=PAGE_SIZE, %o5=(end - start) * %o3=end&PAGE_MASK, %o4=PAGE_SIZE, %o5=(end - start)
*/ */
/*IC9*/ BRANCH_IF_CHEETAH(g2, g3, __cheetah_flush_tlb_range)
__spitfire_flush_tlb_range:
#define TLB_MAGIC 207 /* Students, do you know how I calculated this? -DaveM */ #define TLB_MAGIC 207 /* Students, do you know how I calculated this? -DaveM */
/*IC10*/cmp %o5, %o4 cmp %o5, %o4
bleu,pt %xcc, __flush_tlb_page bleu,pt %xcc, __flush_tlb_page
srlx %o5, PAGE_SHIFT, %g5 srlx %o5, PAGE_SHIFT, %g5
cmp %g5, TLB_MAGIC cmp %g5, TLB_MAGIC
...@@ -107,7 +76,7 @@ __spitfire_flush_tlb_range: ...@@ -107,7 +76,7 @@ __spitfire_flush_tlb_range:
ldxa [%o2] ASI_DMMU, %g2 ldxa [%o2] ASI_DMMU, %g2
cmp %g2, %o0 cmp %g2, %o0
__spitfire_flush_tlb_range_page_by_page: __spitfire_flush_tlb_range_page_by_page:
/*IC11*/bne,pn %icc, __spitfire_flush_tlb_range_pbp_slow bne,pn %icc, __spitfire_flush_tlb_range_pbp_slow
sub %o5, %o4, %o5 sub %o5, %o4, %o5
1: stxa %g0, [%g5 + %o5] ASI_DMMU_DEMAP 1: stxa %g0, [%g5 + %o5] ASI_DMMU_DEMAP
stxa %g0, [%g5 + %o5] ASI_IMMU_DEMAP stxa %g0, [%g5 + %o5] ASI_IMMU_DEMAP
...@@ -116,10 +85,9 @@ __spitfire_flush_tlb_range_page_by_page: ...@@ -116,10 +85,9 @@ __spitfire_flush_tlb_range_page_by_page:
retl retl
flush %g6 flush %g6
__spitfire_flush_tlb_range_constant_time: /* %o0=ctx, %o1=start, %o3=end */ __spitfire_flush_tlb_range_constant_time: /* %o0=ctx, %o1=start, %o3=end */
/*IC12*/rdpr %pstate, %g1 rdpr %pstate, %g1
wrpr %g1, PSTATE_IE, %pstate wrpr %g1, PSTATE_IE, %pstate
mov TLB_TAG_ACCESS, %g3 mov TLB_TAG_ACCESS, %g3
/* XXX Spitfire dependency... */
mov ((SPITFIRE_HIGHEST_LOCKED_TLBENT-1) << 3), %g2 mov ((SPITFIRE_HIGHEST_LOCKED_TLBENT-1) << 3), %g2
/* Spitfire Errata #32 workaround. */ /* Spitfire Errata #32 workaround. */
...@@ -131,7 +99,7 @@ __spitfire_flush_tlb_range_constant_time: /* %o0=ctx, %o1=start, %o3=end */ ...@@ -131,7 +99,7 @@ __spitfire_flush_tlb_range_constant_time: /* %o0=ctx, %o1=start, %o3=end */
and %o4, TAG_CONTEXT_BITS, %o5 and %o4, TAG_CONTEXT_BITS, %o5
cmp %o5, %o0 cmp %o5, %o0
bne,pt %icc, 2f bne,pt %icc, 2f
/*IC13*/ andn %o4, TAG_CONTEXT_BITS, %o4 andn %o4, TAG_CONTEXT_BITS, %o4
cmp %o4, %o1 cmp %o4, %o1
blu,pt %xcc, 2f blu,pt %xcc, 2f
cmp %o4, %o3 cmp %o4, %o3
...@@ -139,7 +107,7 @@ __spitfire_flush_tlb_range_constant_time: /* %o0=ctx, %o1=start, %o3=end */ ...@@ -139,7 +107,7 @@ __spitfire_flush_tlb_range_constant_time: /* %o0=ctx, %o1=start, %o3=end */
2: ldxa [%g2] ASI_DTLB_TAG_READ, %o4 2: ldxa [%g2] ASI_DTLB_TAG_READ, %o4
and %o4, TAG_CONTEXT_BITS, %o5 and %o4, TAG_CONTEXT_BITS, %o5
cmp %o5, %o0 cmp %o5, %o0
/*IC14*/andn %o4, TAG_CONTEXT_BITS, %o4 andn %o4, TAG_CONTEXT_BITS, %o4
bne,pt %icc, 3f bne,pt %icc, 3f
cmp %o4, %o1 cmp %o4, %o1
blu,pt %xcc, 3f blu,pt %xcc, 3f
...@@ -147,7 +115,7 @@ __spitfire_flush_tlb_range_constant_time: /* %o0=ctx, %o1=start, %o3=end */ ...@@ -147,7 +115,7 @@ __spitfire_flush_tlb_range_constant_time: /* %o0=ctx, %o1=start, %o3=end */
blu,pn %xcc, 5f blu,pn %xcc, 5f
nop nop
3: brnz,pt %g2, 1b 3: brnz,pt %g2, 1b
/*IC15*/ sub %g2, (1 << 3), %g2 sub %g2, (1 << 3), %g2
retl retl
wrpr %g1, 0x0, %pstate wrpr %g1, 0x0, %pstate
4: stxa %g0, [%g3] ASI_IMMU 4: stxa %g0, [%g3] ASI_IMMU
...@@ -163,7 +131,7 @@ __spitfire_flush_tlb_range_constant_time: /* %o0=ctx, %o1=start, %o3=end */ ...@@ -163,7 +131,7 @@ __spitfire_flush_tlb_range_constant_time: /* %o0=ctx, %o1=start, %o3=end */
nop nop
5: stxa %g0, [%g3] ASI_DMMU 5: stxa %g0, [%g3] ASI_DMMU
/*IC16*/stxa %g0, [%g2] ASI_DTLB_DATA_ACCESS stxa %g0, [%g2] ASI_DTLB_DATA_ACCESS
flush %g6 flush %g6
/* Spitfire Errata #32 workaround. */ /* Spitfire Errata #32 workaround. */
...@@ -175,33 +143,6 @@ __spitfire_flush_tlb_range_constant_time: /* %o0=ctx, %o1=start, %o3=end */ ...@@ -175,33 +143,6 @@ __spitfire_flush_tlb_range_constant_time: /* %o0=ctx, %o1=start, %o3=end */
nop nop
.align 32 .align 32
__cheetah_flush_tlb_range:
cmp %o5, %o4
bleu,pt %xcc, __cheetah_flush_tlb_page
nop
/*IC17*/rdpr %pstate, %g5
andn %g5, PSTATE_IE, %g2
wrpr %g2, 0x0, %pstate
wrpr %g0, 1, %tl
mov PRIMARY_CONTEXT, %o2
sub %o5, %o4, %o5
ldxa [%o2] ASI_DMMU, %g2
stxa %o0, [%o2] ASI_DMMU
/*IC18*/
1: stxa %g0, [%o1 + %o5] ASI_DMMU_DEMAP
stxa %g0, [%o1 + %o5] ASI_IMMU_DEMAP
membar #Sync
brnz,pt %o5, 1b
sub %o5, %o4, %o5
stxa %g2, [%o2] ASI_DMMU
flush %g6
wrpr %g0, 0, %tl
retl
/*IC19*/ wrpr %g5, 0x0, %pstate
.align 32
.globl __flush_tlb_kernel_range .globl __flush_tlb_kernel_range
__flush_tlb_kernel_range: /* %o0=start, %o1=end */ __flush_tlb_kernel_range: /* %o0=start, %o1=end */
cmp %o0, %o1 cmp %o0, %o1
...@@ -226,7 +167,7 @@ __spitfire_flush_tlb_mm_slow: ...@@ -226,7 +167,7 @@ __spitfire_flush_tlb_mm_slow:
stxa %g0, [%g3] ASI_IMMU_DEMAP stxa %g0, [%g3] ASI_IMMU_DEMAP
flush %g6 flush %g6
stxa %g2, [%o1] ASI_DMMU stxa %g2, [%o1] ASI_DMMU
/*IC18*/flush %g6 flush %g6
retl retl
wrpr %g1, 0, %pstate wrpr %g1, 0, %pstate
...@@ -236,7 +177,7 @@ __spitfire_flush_tlb_page_slow: ...@@ -236,7 +177,7 @@ __spitfire_flush_tlb_page_slow:
stxa %o0, [%o2] ASI_DMMU stxa %o0, [%o2] ASI_DMMU
stxa %g0, [%g3] ASI_DMMU_DEMAP stxa %g0, [%g3] ASI_DMMU_DEMAP
stxa %g0, [%g3] ASI_IMMU_DEMAP stxa %g0, [%g3] ASI_IMMU_DEMAP
/*IC20*/flush %g6 flush %g6
stxa %g2, [%o2] ASI_DMMU stxa %g2, [%o2] ASI_DMMU
flush %g6 flush %g6
retl retl
...@@ -246,7 +187,7 @@ __spitfire_flush_tlb_range_pbp_slow: ...@@ -246,7 +187,7 @@ __spitfire_flush_tlb_range_pbp_slow:
rdpr %pstate, %g1 rdpr %pstate, %g1
wrpr %g1, PSTATE_IE, %pstate wrpr %g1, PSTATE_IE, %pstate
stxa %o0, [%o2] ASI_DMMU stxa %o0, [%o2] ASI_DMMU
/*IC21*/
2: stxa %g0, [%g5 + %o5] ASI_DMMU_DEMAP 2: stxa %g0, [%g5 + %o5] ASI_DMMU_DEMAP
stxa %g0, [%g5 + %o5] ASI_IMMU_DEMAP stxa %g0, [%g5 + %o5] ASI_IMMU_DEMAP
brnz,pt %o5, 2b brnz,pt %o5, 2b
...@@ -255,7 +196,7 @@ __spitfire_flush_tlb_range_pbp_slow: ...@@ -255,7 +196,7 @@ __spitfire_flush_tlb_range_pbp_slow:
stxa %g2, [%o2] ASI_DMMU stxa %g2, [%o2] ASI_DMMU
flush %g6 flush %g6
retl retl
/*IC22*/ wrpr %g1, 0x0, %pstate wrpr %g1, 0x0, %pstate
/* /*
* The following code flushes one page_size worth. * The following code flushes one page_size worth.
...@@ -318,32 +259,6 @@ iflush2:sub %o1, 0x20, %g3 ...@@ -318,32 +259,6 @@ iflush2:sub %o1, 0x20, %g3
flush %g6 flush %g6
ba,a,pt %xcc, 3b ba,a,pt %xcc, 3b
.align 64
.globl __flush_dcache_page
__flush_dcache_page: /* %o0=kaddr, %o1=flush_icache */
sethi %uhi(PAGE_OFFSET), %g1
sllx %g1, 32, %g1
sub %o0, %g1, %o0
rdpr %ver, %g1
sethi %hi(0x003e0014), %g2
srlx %g1, 32, %g1
or %g2, %lo(0x003e0014), %g2
cmp %g1, %g2
bne,pt %icc, flush_dcpage_spitfire
nop
flush_dcpage_cheetah:
sethi %hi(PAGE_SIZE), %o4
1: subcc %o4, (1 << 5), %o4
stxa %g0, [%o0 + %o4] ASI_DCACHE_INVALIDATE
bne,pt %icc, 1b
nop
membar #Sync
/* I-cache flush never needed on Cheetah, see callers. */
retl
nop
#if (PAGE_SHIFT == 13) #if (PAGE_SHIFT == 13)
#define DTAG_MASK 0x3 #define DTAG_MASK 0x3
#elif (PAGE_SHIFT == 16) #elif (PAGE_SHIFT == 16)
...@@ -354,7 +269,12 @@ flush_dcpage_cheetah: ...@@ -354,7 +269,12 @@ flush_dcpage_cheetah:
#define DTAG_MASK 0x3ff #define DTAG_MASK 0x3ff
#endif #endif
flush_dcpage_spitfire: .align 64
.globl __flush_dcache_page
__flush_dcache_page: /* %o0=kaddr, %o1=flush_icache */
sethi %uhi(PAGE_OFFSET), %g1
sllx %g1, 32, %g1
sub %o0, %g1, %o0
clr %o4 clr %o4
srlx %o0, 11, %o0 srlx %o0, 11, %o0
sethi %hi(1 << 14), %o2 sethi %hi(1 << 14), %o2
...@@ -435,6 +355,121 @@ __update_mmu_cache: /* %o0=hw_context, %o1=address, %o2=pte, %o3=fault_code */ ...@@ -435,6 +355,121 @@ __update_mmu_cache: /* %o0=hw_context, %o1=address, %o2=pte, %o3=fault_code */
or %o5, %o0, %o5 or %o5, %o0, %o5
ba,a,pt %xcc, __prefill_itlb ba,a,pt %xcc, __prefill_itlb
/* Cheetah specific versions, patched at boot time. */
__cheetah_flush_tlb_page: /* 14 insns */
rdpr %pstate, %g5
andn %g5, PSTATE_IE, %g2
wrpr %g2, 0x0, %pstate
wrpr %g0, 1, %tl
mov PRIMARY_CONTEXT, %o2
ldxa [%o2] ASI_DMMU, %g2
stxa %o0, [%o2] ASI_DMMU
stxa %g0, [%o1] ASI_DMMU_DEMAP
stxa %g0, [%o1] ASI_IMMU_DEMAP
stxa %g2, [%o2] ASI_DMMU
flush %g6
wrpr %g0, 0, %tl
retl
wrpr %g5, 0x0, %pstate
__cheetah_flush_tlb_mm: /* 15 insns */
rdpr %pstate, %g5
andn %g5, PSTATE_IE, %g2
wrpr %g2, 0x0, %pstate
wrpr %g0, 1, %tl
mov PRIMARY_CONTEXT, %o2
mov 0x40, %g3
ldxa [%o2] ASI_DMMU, %g2
stxa %o0, [%o2] ASI_DMMU
stxa %g0, [%g3] ASI_DMMU_DEMAP
stxa %g0, [%g3] ASI_IMMU_DEMAP
stxa %g2, [%o2] ASI_DMMU
flush %g6
wrpr %g0, 0, %tl
retl
wrpr %g5, 0x0, %pstate
__cheetah_flush_tlb_range: /* 20 insns */
cmp %o5, %o4
blu,pt %xcc, 9f
rdpr %pstate, %g5
andn %g5, PSTATE_IE, %g2
wrpr %g2, 0x0, %pstate
wrpr %g0, 1, %tl
mov PRIMARY_CONTEXT, %o2
sub %o5, %o4, %o5
ldxa [%o2] ASI_DMMU, %g2
stxa %o0, [%o2] ASI_DMMU
1: stxa %g0, [%o1 + %o5] ASI_DMMU_DEMAP
stxa %g0, [%o1 + %o5] ASI_IMMU_DEMAP
membar #Sync
brnz,pt %o5, 1b
sub %o5, %o4, %o5
stxa %g2, [%o2] ASI_DMMU
flush %g6
wrpr %g0, 0, %tl
9: retl
wrpr %g5, 0x0, %pstate
flush_dcpage_cheetah: /* 9 insns */
sethi %uhi(PAGE_OFFSET), %g1
sllx %g1, 32, %g1
sub %o0, %g1, %o0
sethi %hi(PAGE_SIZE), %o4
1: subcc %o4, (1 << 5), %o4
stxa %g0, [%o0 + %o4] ASI_DCACHE_INVALIDATE
bne,pt %icc, 1b
nop
membar #Sync
retl /* I-cache flush never needed on Cheetah, see callers. */
nop
cheetah_patch_one:
1: lduw [%o1], %g1
stw %g1, [%o0]
flush %o0
subcc %o2, 1, %o2
add %o1, 4, %o1
bne,pt %icc, 1b
add %o0, 4, %o0
retl
nop
.globl cheetah_patch_cachetlbops
cheetah_patch_cachetlbops:
save %sp, -128, %sp
sethi %hi(__flush_tlb_page), %o0
or %o0, %lo(__flush_tlb_page), %o0
sethi %hi(__cheetah_flush_tlb_page), %o1
or %o1, %lo(__cheetah_flush_tlb_page), %o1
call cheetah_patch_one
mov 14, %o2
sethi %hi(__flush_tlb_mm), %o0
or %o0, %lo(__flush_tlb_mm), %o0
sethi %hi(__cheetah_flush_tlb_mm), %o1
or %o1, %lo(__cheetah_flush_tlb_mm), %o1
call cheetah_patch_one
mov 15, %o2
sethi %hi(__flush_tlb_range), %o0
or %o0, %lo(__flush_tlb_range), %o0
sethi %hi(__cheetah_flush_tlb_range), %o1
or %o1, %lo(__cheetah_flush_tlb_range), %o1
call cheetah_patch_one
mov 20, %o2
sethi %hi(__flush_dcache_page), %o0
or %o0, %lo(__flush_dcache_page), %o0
sethi %hi(flush_dcpage_cheetah), %o1
or %o1, %lo(flush_dcpage_cheetah), %o1
call cheetah_patch_one
mov 9, %o2
ret
restore
#ifdef CONFIG_SMP #ifdef CONFIG_SMP
/* These are all called by the slaves of a cross call, at /* These are all called by the slaves of a cross call, at
* trap level 1, with interrupts fully disabled. * trap level 1, with interrupts fully disabled.
...@@ -618,10 +653,8 @@ errata32_hwbug: ...@@ -618,10 +653,8 @@ errata32_hwbug:
.text .text
/* These two are not performance critical... */ /* These two are not performance critical... */
.globl xcall_flush_tlb_all .globl xcall_flush_tlb_all_spitfire
xcall_flush_tlb_all: xcall_flush_tlb_all_spitfire:
BRANCH_IF_CHEETAH(g2, g3, __cheetah_xcall_flush_tlb_all)
__spitfire_xcall_flush_tlb_all:
/* Spitfire Errata #32 workaround. */ /* Spitfire Errata #32 workaround. */
sethi %hi(errata32_hwbug), %g4 sethi %hi(errata32_hwbug), %g4
stx %g0, [%g4 + %lo(errata32_hwbug)] stx %g0, [%g4 + %lo(errata32_hwbug)]
...@@ -663,16 +696,15 @@ __spitfire_xcall_flush_tlb_all: ...@@ -663,16 +696,15 @@ __spitfire_xcall_flush_tlb_all:
flush %g6 flush %g6
retry retry
__cheetah_xcall_flush_tlb_all: .globl xcall_flush_tlb_all_cheetah
xcall_flush_tlb_all_cheetah:
mov 0x80, %g2 mov 0x80, %g2
stxa %g0, [%g2] ASI_DMMU_DEMAP stxa %g0, [%g2] ASI_DMMU_DEMAP
stxa %g0, [%g2] ASI_IMMU_DEMAP stxa %g0, [%g2] ASI_IMMU_DEMAP
retry retry
.globl xcall_flush_cache_all .globl xcall_flush_cache_all_spitfire
xcall_flush_cache_all: xcall_flush_cache_all_spitfire:
BRANCH_IF_CHEETAH(g2, g3, __cheetah_xcall_flush_cache_all)
__spitfire_xcall_flush_cache_all:
sethi %hi(16383), %g2 sethi %hi(16383), %g2
or %g2, %lo(16383), %g2 or %g2, %lo(16383), %g2
clr %g3 clr %g3
...@@ -685,13 +717,6 @@ __spitfire_xcall_flush_cache_all: ...@@ -685,13 +717,6 @@ __spitfire_xcall_flush_cache_all:
flush %g6 flush %g6
retry retry
/* Cheetah's caches are fully coherent in the sense that
* caches are flushed here. We need to verify this and
* really just not even send out the xcall at the top level.
*/
__cheetah_xcall_flush_cache_all:
retry
/* These just get rescheduled to PIL vectors. */ /* These just get rescheduled to PIL vectors. */
.globl xcall_call_function .globl xcall_call_function
xcall_call_function: xcall_call_function:
......
...@@ -40,6 +40,7 @@ ...@@ -40,6 +40,7 @@
#define ASI_WCACHE_DATA 0x39 /* (III) WCache data RAM diag */ #define ASI_WCACHE_DATA 0x39 /* (III) WCache data RAM diag */
#define ASI_WCACHE_TAG 0x3a /* (III) WCache tag RAM diag */ #define ASI_WCACHE_TAG 0x3a /* (III) WCache tag RAM diag */
#define ASI_WCACHE_SNOOP_TAG 0x3b /* (III) WCache snoop tag RAM diag */ #define ASI_WCACHE_SNOOP_TAG 0x3b /* (III) WCache snoop tag RAM diag */
#define ASI_SRAM_FAST_INIT 0x40 /* (III+) Fast SRAM init */
#define ASI_DCACHE_INVALIDATE 0x42 /* (III) DCache Invalidate diag */ #define ASI_DCACHE_INVALIDATE 0x42 /* (III) DCache Invalidate diag */
#define ASI_DCACHE_UTAG 0x43 /* (III) DCache uTag diag */ #define ASI_DCACHE_UTAG 0x43 /* (III) DCache uTag diag */
#define ASI_DCACHE_SNOOP_TAG 0x44 /* (III) DCache snoop tag RAM diag */ #define ASI_DCACHE_SNOOP_TAG 0x44 /* (III) DCache snoop tag RAM diag */
......
...@@ -2,11 +2,13 @@ ...@@ -2,11 +2,13 @@
#ifndef _SPARC64_DCR_H #ifndef _SPARC64_DCR_H
#define _SPARC64_DCR_H #define _SPARC64_DCR_H
/* UltraSparc-III Dispatch Control Register, ASR 0x12 */ /* UltraSparc-III/III+ Dispatch Control Register, ASR 0x12 */
#define DCR_DPE 0x0000000000001000 /* III+: D$ Parity Error Enable */
#define DCR_OBS 0x0000000000000fc0 /* Observability Bus Controls */ #define DCR_OBS 0x0000000000000fc0 /* Observability Bus Controls */
#define DCR_BPE 0x0000000000000020 /* Branch Predict Enable */ #define DCR_BPE 0x0000000000000020 /* Branch Predict Enable */
#define DCR_RPE 0x0000000000000010 /* Return Address Prediction Enable */ #define DCR_RPE 0x0000000000000010 /* Return Address Prediction Enable */
#define DCR_SI 0x0000000000000008 /* Single Instruction Disable */ #define DCR_SI 0x0000000000000008 /* Single Instruction Disable */
#define DCR_IPE 0x0000000000000004 /* III+: I$ Parity Error Enable */
#define DCR_IFPOE 0x0000000000000002 /* IRQ FP Operation Enable */ #define DCR_IFPOE 0x0000000000000002 /* IRQ FP Operation Enable */
#define DCR_MS 0x0000000000000001 /* Multi-Scalar dispatch */ #define DCR_MS 0x0000000000000001 /* Multi-Scalar dispatch */
......
...@@ -89,7 +89,8 @@ typedef struct { ...@@ -89,7 +89,8 @@ typedef struct {
#define ELF_HWCAP ((HWCAP_SPARC_FLUSH | HWCAP_SPARC_STBAR | \ #define ELF_HWCAP ((HWCAP_SPARC_FLUSH | HWCAP_SPARC_STBAR | \
HWCAP_SPARC_SWAP | HWCAP_SPARC_MULDIV | \ HWCAP_SPARC_SWAP | HWCAP_SPARC_MULDIV | \
HWCAP_SPARC_V9) | \ HWCAP_SPARC_V9) | \
((tlb_type == cheetah) ? HWCAP_SPARC_ULTRA3 : 0)) ((tlb_type == cheetah || tlb_type == cheetah_plus) ? \
HWCAP_SPARC_ULTRA3 : 0))
/* This yields a string that ld.so will use to load implementation /* This yields a string that ld.so will use to load implementation
specific libraries for optimization. This is more specific in specific libraries for optimization. This is more specific in
......
...@@ -8,4 +8,7 @@ ...@@ -8,4 +8,7 @@
#define PTREGS_OFF (STACK_BIAS + REGWIN_SZ) #define PTREGS_OFF (STACK_BIAS + REGWIN_SZ)
#define CHEETAH_ID 0x003e0014
#define CHEETAH_PLUS_ID 0x003e0015
#endif /* !(_SPARC64_HEAD_H) */ #endif /* !(_SPARC64_HEAD_H) */
...@@ -91,7 +91,7 @@ static inline int any_online_cpu(unsigned long mask) ...@@ -91,7 +91,7 @@ static inline int any_online_cpu(unsigned long mask)
extern __inline__ int hard_smp_processor_id(void) extern __inline__ int hard_smp_processor_id(void)
{ {
if (tlb_type == cheetah) { if (tlb_type == cheetah || tlb_type == cheetah_plus) {
unsigned long safari_config; unsigned long safari_config;
__asm__ __volatile__("ldxa [%%g0] %1, %0" __asm__ __volatile__("ldxa [%%g0] %1, %0"
: "=r" (safari_config) : "=r" (safari_config)
......
...@@ -22,6 +22,7 @@ ...@@ -22,6 +22,7 @@
#define TSB_EXTENSION_P 0x0000000000000048 /* Ultra-III and later */ #define TSB_EXTENSION_P 0x0000000000000048 /* Ultra-III and later */
#define TSB_EXTENSION_S 0x0000000000000050 /* Ultra-III and later, D-TLB only */ #define TSB_EXTENSION_S 0x0000000000000050 /* Ultra-III and later, D-TLB only */
#define TSB_EXTENSION_N 0x0000000000000058 /* Ultra-III and later */ #define TSB_EXTENSION_N 0x0000000000000058 /* Ultra-III and later */
#define TLB_TAG_ACCESS_EXT 0x0000000000000060 /* Ultra-III+ and later */
/* These registers only exist as one entity, and are accessed /* These registers only exist as one entity, and are accessed
* via ASI_DMMU only. * via ASI_DMMU only.
...@@ -38,12 +39,13 @@ ...@@ -38,12 +39,13 @@
enum ultra_tlb_layout { enum ultra_tlb_layout {
spitfire = 0, spitfire = 0,
cheetah = 1 cheetah = 1,
cheetah_plus = 2,
}; };
extern enum ultra_tlb_layout tlb_type; extern enum ultra_tlb_layout tlb_type;
#define SPARC64_USE_STICK (tlb_type == cheetah) #define SPARC64_USE_STICK (tlb_type != spitfire)
#define CHEETAH_HIGHEST_LOCKED_TLBENT (16 - 1) #define CHEETAH_HIGHEST_LOCKED_TLBENT (16 - 1)
...@@ -433,35 +435,35 @@ extern __inline__ void cheetah_put_litlb_data(int entry, unsigned long data) ...@@ -433,35 +435,35 @@ extern __inline__ void cheetah_put_litlb_data(int entry, unsigned long data)
"i" (ASI_ITLB_DATA_ACCESS)); "i" (ASI_ITLB_DATA_ACCESS));
} }
extern __inline__ unsigned long cheetah_get_dtlb_data(int entry) extern __inline__ unsigned long cheetah_get_dtlb_data(int entry, int tlb)
{ {
unsigned long data; unsigned long data;
__asm__ __volatile__("ldxa [%1] %2, %%g0\n\t" __asm__ __volatile__("ldxa [%1] %2, %%g0\n\t"
"ldxa [%1] %2, %0" "ldxa [%1] %2, %0"
: "=r" (data) : "=r" (data)
: "r" ((2 << 16) | (entry << 3)), "i" (ASI_DTLB_DATA_ACCESS)); : "r" ((tlb << 16) | (entry << 3)), "i" (ASI_DTLB_DATA_ACCESS));
return data; return data;
} }
extern __inline__ unsigned long cheetah_get_dtlb_tag(int entry) extern __inline__ unsigned long cheetah_get_dtlb_tag(int entry, int tlb)
{ {
unsigned long tag; unsigned long tag;
__asm__ __volatile__("ldxa [%1] %2, %0" __asm__ __volatile__("ldxa [%1] %2, %0"
: "=r" (tag) : "=r" (tag)
: "r" ((2 << 16) | (entry << 3)), "i" (ASI_DTLB_TAG_READ)); : "r" ((tlb << 16) | (entry << 3)), "i" (ASI_DTLB_TAG_READ));
return tag; return tag;
} }
extern __inline__ void cheetah_put_dtlb_data(int entry, unsigned long data) extern __inline__ void cheetah_put_dtlb_data(int entry, unsigned long data, int tlb)
{ {
__asm__ __volatile__("stxa %0, [%1] %2\n\t" __asm__ __volatile__("stxa %0, [%1] %2\n\t"
"membar #Sync" "membar #Sync"
: /* No outputs */ : /* No outputs */
: "r" (data), : "r" (data),
"r" ((2 << 16) | (entry << 3)), "r" ((tlb << 16) | (entry << 3)),
"i" (ASI_DTLB_DATA_ACCESS)); "i" (ASI_DTLB_DATA_ACCESS));
} }
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment