Commit d82ace7d authored by David S. Miller's avatar David S. Miller

[SPARC64]: Detect sun4v early in boot process.

We look for "SUNW,sun4v" in the 'compatible' property
of the root OBP device tree node.

Protect every %ver register access, to make sure it is
not touched on sun4v, as %ver is hyperprivileged there.

Lock kernel TLB entries using hypervisor calls instead of
calls into OBP.
Signed-off-by: default avatarDavid S. Miller <davem@davemloft.net>
parent 1d2f1f90
......@@ -71,6 +71,12 @@ void __init cpu_probe(void)
unsigned long ver, fpu_vers, manuf, impl, fprs;
int i;
if (tlb_type == hypervisor) {
sparc_cpu_type = "UltraSparc T1 (Niagara)";
sparc_fpu_type = "UltraSparc T1 integrated FPU";
return;
}
fprs = fprs_read();
fprs_write(FPRS_FEF);
__asm__ __volatile__ ("rdpr %%ver, %0; stx %%fsr, [%1]"
......
......@@ -95,12 +95,17 @@ sparc64_boot:
wrpr %g1, 0x0, %pstate
ba,a,pt %xcc, 1f
.globl prom_finddev_name, prom_chosen_path
.globl prom_getprop_name, prom_mmu_name
.globl prom_callmethod_name, prom_translate_name
.globl prom_finddev_name, prom_chosen_path, prom_root_node
.globl prom_getprop_name, prom_mmu_name, prom_peer_name
.globl prom_callmethod_name, prom_translate_name, prom_root_compatible
.globl prom_map_name, prom_unmap_name, prom_mmu_ihandle_cache
.globl prom_boot_mapped_pc, prom_boot_mapping_mode
.globl prom_boot_mapping_phys_high, prom_boot_mapping_phys_low
.globl is_sun4v
prom_peer_name:
.asciz "peer"
prom_compatible_name:
.asciz "compatible"
prom_finddev_name:
.asciz "finddevice"
prom_chosen_path:
......@@ -117,7 +122,13 @@ prom_map_name:
.asciz "map"
prom_unmap_name:
.asciz "unmap"
prom_sun4v_name:
.asciz "SUNW,sun4v"
.align 4
prom_root_compatible:
.skip 64
prom_root_node:
.word 0
prom_mmu_ihandle_cache:
.word 0
prom_boot_mapped_pc:
......@@ -129,8 +140,54 @@ prom_boot_mapping_phys_high:
.xword 0
prom_boot_mapping_phys_low:
.xword 0
is_sun4v:
.word 0
1:
rd %pc, %l0
mov (1b - prom_peer_name), %l1
sub %l0, %l1, %l1
mov 0, %l2
/* prom_root_node = prom_peer(0) */
stx %l1, [%sp + 2047 + 128 + 0x00] ! service, "peer"
mov 1, %l3
stx %l3, [%sp + 2047 + 128 + 0x08] ! num_args, 1
stx %l3, [%sp + 2047 + 128 + 0x10] ! num_rets, 1
stx %l2, [%sp + 2047 + 128 + 0x18] ! arg1, 0
stx %g0, [%sp + 2047 + 128 + 0x20] ! ret1
call %l7
add %sp, (2047 + 128), %o0 ! argument array
ldx [%sp + 2047 + 128 + 0x20], %l4 ! prom root node
mov (1b - prom_root_node), %l1
sub %l0, %l1, %l1
stw %l4, [%l1]
mov (1b - prom_getprop_name), %l1
mov (1b - prom_compatible_name), %l2
mov (1b - prom_root_compatible), %l5
sub %l0, %l1, %l1
sub %l0, %l2, %l2
sub %l0, %l5, %l5
/* prom_getproperty(prom_root_node, "compatible",
* &prom_root_compatible, 64)
*/
stx %l1, [%sp + 2047 + 128 + 0x00] ! service, "getprop"
mov 4, %l3
stx %l3, [%sp + 2047 + 128 + 0x08] ! num_args, 4
mov 1, %l3
stx %l3, [%sp + 2047 + 128 + 0x10] ! num_rets, 1
stx %l4, [%sp + 2047 + 128 + 0x18] ! arg1, prom_root_node
stx %l2, [%sp + 2047 + 128 + 0x20] ! arg2, "compatible"
stx %l5, [%sp + 2047 + 128 + 0x28] ! arg3, &prom_root_compatible
mov 64, %l3
stx %l3, [%sp + 2047 + 128 + 0x30] ! arg4, size
stx %g0, [%sp + 2047 + 128 + 0x38] ! ret1
call %l7
add %sp, (2047 + 128), %o0 ! argument array
mov (1b - prom_finddev_name), %l1
mov (1b - prom_chosen_path), %l2
mov (1b - prom_boot_mapped_pc), %l3
......@@ -239,6 +296,27 @@ prom_boot_mapping_phys_low:
add %sp, (192 + 128), %sp
sparc64_boot_after_remap:
sethi %hi(prom_root_compatible), %g1
or %g1, %lo(prom_root_compatible), %g1
sethi %hi(prom_sun4v_name), %g7
or %g7, %lo(prom_sun4v_name), %g7
mov 10, %g3
1: ldub [%g7], %g2
ldub [%g1], %g4
cmp %g2, %g4
bne,pn %icc, 2f
add %g7, 1, %g7
subcc %g3, 1, %g3
bne,pt %xcc, 1b
add %g1, 1, %g1
sethi %hi(is_sun4v), %g1
or %g1, %lo(is_sun4v), %g1
mov 1, %g7
stw %g7, [%g1]
2:
BRANCH_IF_SUN4V(g1, jump_to_sun4u_init)
BRANCH_IF_CHEETAH_BASE(g1,g7,cheetah_boot)
BRANCH_IF_CHEETAH_PLUS_OR_FOLLOWON(g1,g7,cheetah_plus_boot)
ba,pt %xcc, spitfire_boot
......@@ -323,14 +401,12 @@ sun4u_init:
membar #Sync
BRANCH_IF_ANY_CHEETAH(g1,g7,cheetah_tlb_fixup)
BRANCH_IF_SUN4V(g1, niagara_tlb_fixup)
BRANCH_IF_ANY_CHEETAH(g1, g7, cheetah_tlb_fixup)
ba,pt %xcc, spitfire_tlb_fixup
nop
/* XXX Nothing branches to here yet, when %ver register indicates
* XXX Niagara we should do this.
*/
niagara_tlb_fixup:
mov 3, %g2 /* Set TLB type to hypervisor. */
sethi %hi(tlb_type), %g1
......@@ -346,6 +422,9 @@ niagara_tlb_fixup:
call hypervisor_patch_cachetlbops
nop
ba,pt %xcc, tlb_fixup_done
nop
cheetah_tlb_fixup:
mov 2, %g2 /* Set TLB type to cheetah+. */
BRANCH_IF_CHEETAH_PLUS_OR_FOLLOWON(g1,g7,1f)
......@@ -464,7 +543,8 @@ setup_trap_table:
sllx %o2, 32, %o2
wr %o2, 0, %tick_cmpr
BRANCH_IF_ANY_CHEETAH(o2,o3,1f)
BRANCH_IF_SUN4V(o2, 1f)
BRANCH_IF_ANY_CHEETAH(o2, o3, 1f)
ba,pt %xcc, 2f
nop
......
......@@ -150,47 +150,53 @@ void enable_irq(unsigned int irq)
preempt_disable();
if (tlb_type == cheetah || tlb_type == cheetah_plus) {
unsigned long ver;
__asm__ ("rdpr %%ver, %0" : "=r" (ver));
if ((ver >> 32) == __JALAPENO_ID ||
(ver >> 32) == __SERRANO_ID) {
/* We set it to our JBUS ID. */
if (tlb_type == hypervisor) {
/* XXX SUN4V: implement me... XXX */
} else {
if (tlb_type == cheetah || tlb_type == cheetah_plus) {
unsigned long ver;
__asm__ ("rdpr %%ver, %0" : "=r" (ver));
if ((ver >> 32) == __JALAPENO_ID ||
(ver >> 32) == __SERRANO_ID) {
/* We set it to our JBUS ID. */
__asm__ __volatile__("ldxa [%%g0] %1, %0"
: "=r" (tid)
: "i" (ASI_JBUS_CONFIG));
tid = ((tid & (0x1fUL<<17)) << 9);
tid &= IMAP_TID_JBUS;
} else {
/* We set it to our Safari AID. */
__asm__ __volatile__("ldxa [%%g0] %1, %0"
: "=r" (tid)
: "i"(ASI_SAFARI_CONFIG));
tid = ((tid & (0x3ffUL<<17)) << 9);
tid &= IMAP_AID_SAFARI;
}
} else if (this_is_starfire == 0) {
/* We set it to our UPA MID. */
__asm__ __volatile__("ldxa [%%g0] %1, %0"
: "=r" (tid)
: "i" (ASI_JBUS_CONFIG));
tid = ((tid & (0x1fUL<<17)) << 9);
tid &= IMAP_TID_JBUS;
: "i" (ASI_UPA_CONFIG));
tid = ((tid & UPA_CONFIG_MID) << 9);
tid &= IMAP_TID_UPA;
} else {
/* We set it to our Safari AID. */
__asm__ __volatile__("ldxa [%%g0] %1, %0"
: "=r" (tid)
: "i" (ASI_SAFARI_CONFIG));
tid = ((tid & (0x3ffUL<<17)) << 9);
tid &= IMAP_AID_SAFARI;
tid = (starfire_translate(imap,
smp_processor_id()) << 26);
tid &= IMAP_TID_UPA;
}
} else if (this_is_starfire == 0) {
/* We set it to our UPA MID. */
__asm__ __volatile__("ldxa [%%g0] %1, %0"
: "=r" (tid)
: "i" (ASI_UPA_CONFIG));
tid = ((tid & UPA_CONFIG_MID) << 9);
tid &= IMAP_TID_UPA;
} else {
tid = (starfire_translate(imap, smp_processor_id()) << 26);
tid &= IMAP_TID_UPA;
}
/* NOTE NOTE NOTE, IGN and INO are read-only, IGN is a product
* of this SYSIO's preconfigured IGN in the SYSIO Control
* Register, the hardware just mirrors that value here.
* However for Graphics and UPA Slave devices the full
* IMAP_INR field can be set by the programmer here.
*
* Things like FFB can now be handled via the new IRQ mechanism.
*/
upa_writel(tid | IMAP_VALID, imap);
/* NOTE NOTE NOTE, IGN and INO are read-only, IGN is a product
* of this SYSIO's preconfigured IGN in the SYSIO Control
* Register, the hardware just mirrors that value here.
* However for Graphics and UPA Slave devices the full
* IMAP_INR field can be set by the programmer here.
*
* Things like FFB can now be handled via the new IRQ
* mechanism.
*/
upa_writel(tid | IMAP_VALID, imap);
}
preempt_enable();
}
......
......@@ -504,9 +504,12 @@ static void __init per_cpu_patch(void)
if (tlb_type == spitfire && !this_is_starfire)
return;
__asm__ ("rdpr %%ver, %0" : "=r" (ver));
is_jbus = ((ver >> 32) == __JALAPENO_ID ||
(ver >> 32) == __SERRANO_ID);
is_jbus = 0;
if (tlb_type != hypervisor) {
__asm__ ("rdpr %%ver, %0" : "=r" (ver));
is_jbus = ((ver >> 32) == __JALAPENO_ID ||
(ver >> 32) == __SERRANO_ID);
}
p = &__cpuid_patch;
while (p < &__cpuid_patch_end) {
......
......@@ -16,6 +16,7 @@
#include <asm/processor.h>
#include <asm/thread_info.h>
#include <asm/mmu.h>
#include <asm/hypervisor.h>
.data
.align 8
......@@ -34,8 +35,9 @@ dtlb_load:
sparc64_cpu_startup:
flushw
BRANCH_IF_CHEETAH_BASE(g1,g5,cheetah_startup)
BRANCH_IF_CHEETAH_PLUS_OR_FOLLOWON(g1,g5,cheetah_plus_startup)
BRANCH_IF_SUN4V(g1, niagara_startup)
BRANCH_IF_CHEETAH_BASE(g1, g5, cheetah_startup)
BRANCH_IF_CHEETAH_PLUS_OR_FOLLOWON(g1, g5, cheetah_plus_startup)
ba,pt %xcc, spitfire_startup
nop
......@@ -70,7 +72,9 @@ cheetah_generic_startup:
stxa %g0, [%g3] ASI_DMMU
stxa %g0, [%g3] ASI_IMMU
membar #Sync
/* fallthru */
niagara_startup:
/* Disable STICK_INT interrupts. */
sethi %hi(0x80000000), %g5
sllx %g5, 32, %g5
......@@ -91,6 +95,8 @@ startup_continue:
sllx %g2, 32, %g2
wr %g2, 0, %tick_cmpr
BRANCH_IF_SUN4V(g1, niagara_lock_tlb)
/* Call OBP by hand to lock KERNBASE into i/d tlbs.
* We lock 2 consequetive entries if we are 'bigkernel'.
*/
......@@ -142,8 +148,7 @@ startup_continue:
sethi %hi(bigkernel), %g2
lduw [%g2 + %lo(bigkernel)], %g2
cmp %g2, 0
be,pt %icc, do_dtlb
brz,pt %g2, do_dtlb
nop
sethi %hi(call_method), %g2
......@@ -214,8 +219,7 @@ do_dtlb:
sethi %hi(bigkernel), %g2
lduw [%g2 + %lo(bigkernel)], %g2
cmp %g2, 0
be,pt %icc, do_unlock
brz,pt %g2, do_unlock
nop
sethi %hi(call_method), %g2
......@@ -257,6 +261,52 @@ do_unlock:
stb %g0, [%g2 + %lo(prom_entry_lock)]
membar #StoreStore | #StoreLoad
ba,pt %xcc, after_lock_tlb
nop
niagara_lock_tlb:
mov HV_FAST_MMU_MAP_PERM_ADDR, %o0
sethi %hi(KERNBASE), %o1
clr %o2
sethi %hi(kern_locked_tte_data), %o3
ldx [%o3 + %lo(kern_locked_tte_data)], %o3
mov HV_MMU_IMMU, %o4
ta HV_FAST_TRAP
mov HV_FAST_MMU_MAP_PERM_ADDR, %o0
sethi %hi(KERNBASE), %o1
clr %o2
sethi %hi(kern_locked_tte_data), %o3
ldx [%o3 + %lo(kern_locked_tte_data)], %o3
mov HV_MMU_DMMU, %o4
ta HV_FAST_TRAP
sethi %hi(bigkernel), %g2
lduw [%g2 + %lo(bigkernel)], %g2
brz,pt %g2, after_lock_tlb
nop
mov HV_FAST_MMU_MAP_PERM_ADDR, %o0
sethi %hi(KERNBASE + 0x400000), %o1
clr %o2
sethi %hi(kern_locked_tte_data), %o3
ldx [%o3 + %lo(kern_locked_tte_data)], %o3
sethi %hi(0x400000), %o4
add %o3, %o4, %o3
mov HV_MMU_IMMU, %o4
ta HV_FAST_TRAP
mov HV_FAST_MMU_MAP_PERM_ADDR, %o0
sethi %hi(KERNBASE + 0x400000), %o1
clr %o2
sethi %hi(kern_locked_tte_data), %o3
ldx [%o3 + %lo(kern_locked_tte_data)], %o3
sethi %hi(0x400000), %o4
add %o3, %o4, %o3
mov HV_MMU_DMMU, %o4
ta HV_FAST_TRAP
after_lock_tlb:
mov %l1, %sp
flushw
......
......@@ -346,6 +346,9 @@ static int __init us2e_freq_init(void)
unsigned long manuf, impl, ver;
int ret;
if (tlb_type != spitfire)
return -ENODEV;
__asm__("rdpr %%ver, %0" : "=r" (ver));
manuf = ((ver >> 48) & 0xffff);
impl = ((ver >> 32) & 0xffff);
......
......@@ -203,6 +203,9 @@ static int __init us3_freq_init(void)
unsigned long manuf, impl, ver;
int ret;
if (tlb_type != cheetah && tlb_type != cheetah_plus)
return -ENODEV;
__asm__("rdpr %%ver, %0" : "=r" (ver));
manuf = ((ver >> 48) & 0xffff);
impl = ((ver >> 32) & 0xffff);
......
......@@ -514,6 +514,29 @@ static void __init read_obp_translations(void)
}
}
static void __init hypervisor_tlb_lock(unsigned long vaddr,
unsigned long pte,
unsigned long mmu)
{
register unsigned long func asm("%o0");
register unsigned long arg0 asm("%o1");
register unsigned long arg1 asm("%o2");
register unsigned long arg2 asm("%o3");
register unsigned long arg3 asm("%o4");
func = HV_FAST_MMU_MAP_PERM_ADDR;
arg0 = vaddr;
arg1 = 0;
arg2 = pte;
arg3 = mmu;
__asm__ __volatile__("ta 0x80"
: "=&r" (func), "=&r" (arg0),
"=&r" (arg1), "=&r" (arg2),
"=&r" (arg3)
: "0" (func), "1" (arg0), "2" (arg1),
"3" (arg2), "4" (arg3));
}
static void __init remap_kernel(void)
{
unsigned long phys_page, tte_vaddr, tte_data;
......@@ -527,19 +550,30 @@ static void __init remap_kernel(void)
kern_locked_tte_data = tte_data;
/* Now lock us into the TLBs via OBP. */
prom_dtlb_load(tlb_ent, tte_data, tte_vaddr);
prom_itlb_load(tlb_ent, tte_data, tte_vaddr);
if (bigkernel) {
tlb_ent -= 1;
prom_dtlb_load(tlb_ent,
tte_data + 0x400000,
tte_vaddr + 0x400000);
prom_itlb_load(tlb_ent,
tte_data + 0x400000,
tte_vaddr + 0x400000);
/* Now lock us into the TLBs via Hypervisor or OBP. */
if (tlb_type == hypervisor) {
hypervisor_tlb_lock(tte_vaddr, tte_data, HV_MMU_DMMU);
hypervisor_tlb_lock(tte_vaddr, tte_data, HV_MMU_IMMU);
if (bigkernel) {
tte_vaddr += 0x400000;
tte_data += 0x400000;
hypervisor_tlb_lock(tte_vaddr, tte_data, HV_MMU_DMMU);
hypervisor_tlb_lock(tte_vaddr, tte_data, HV_MMU_IMMU);
}
} else {
prom_dtlb_load(tlb_ent, tte_data, tte_vaddr);
prom_itlb_load(tlb_ent, tte_data, tte_vaddr);
if (bigkernel) {
tlb_ent -= 1;
prom_dtlb_load(tlb_ent,
tte_data + 0x400000,
tte_vaddr + 0x400000);
prom_itlb_load(tlb_ent,
tte_data + 0x400000,
tte_vaddr + 0x400000);
}
sparc64_highest_unlocked_tlb_ent = tlb_ent - 1;
}
sparc64_highest_unlocked_tlb_ent = tlb_ent - 1;
if (tlb_type == cheetah_plus) {
sparc64_kern_pri_context = (CTX_CHEETAH_PLUS_CTX0 |
CTX_CHEETAH_PLUS_NUC);
......
......@@ -18,7 +18,6 @@ enum prom_major_version prom_vers;
unsigned int prom_rev, prom_prev;
/* The root node of the prom device tree. */
int prom_root_node;
int prom_stdin, prom_stdout;
int prom_chosen_node;
......@@ -41,26 +40,22 @@ void __init prom_init(void *cif_handler, void *cif_stack)
prom_cif_init(cif_handler, cif_stack);
prom_root_node = prom_getsibling(0);
if((prom_root_node == 0) || (prom_root_node == -1))
prom_halt();
prom_chosen_node = prom_finddevice(prom_chosen_path);
if (!prom_chosen_node || prom_chosen_node == -1)
prom_halt();
prom_stdin = prom_getint (prom_chosen_node, "stdin");
prom_stdout = prom_getint (prom_chosen_node, "stdout");
prom_stdin = prom_getint(prom_chosen_node, "stdin");
prom_stdout = prom_getint(prom_chosen_node, "stdout");
node = prom_finddevice("/openprom");
if (!node || node == -1)
prom_halt();
prom_getstring (node, "version", buffer, sizeof (buffer));
prom_getstring(node, "version", buffer, sizeof (buffer));
prom_printf ("\n");
prom_printf("\n");
if (strncmp (buffer, "OBP ", 4))
if (strncmp(buffer, "OBP ", 4))
goto strange_version;
/*
......@@ -70,7 +65,7 @@ void __init prom_init(void *cif_handler, void *cif_stack)
* accordingly. -spot
*/
if (strncmp (buffer, "OBP ", 5))
if (strncmp(buffer, "OBP ", 5))
bufadjust = 4;
else
bufadjust = 5;
......@@ -87,7 +82,8 @@ void __init prom_init(void *cif_handler, void *cif_stack)
prom_rev = ints[1];
prom_prev = (ints[0] << 16) | (ints[1] << 8) | ints[2];
printk ("PROMLIB: Sun IEEE Boot Prom %s\n", buffer + bufadjust);
printk("PROMLIB: Sun IEEE Boot Prom %s\n", buffer + bufadjust);
printk("PROMLIB: Root node compatible: %s\n", prom_root_compatible);
/* Initialization successful. */
return;
......
......@@ -51,7 +51,7 @@ prom_getparent(int node)
__inline__ int
__prom_getsibling(int node)
{
return p1275_cmd ("peer", P1275_INOUT(1, 1), node);
return p1275_cmd(prom_peer_name, P1275_INOUT(1, 1), node);
}
__inline__ int
......@@ -59,9 +59,12 @@ prom_getsibling(int node)
{
int sibnode;
if(node == -1) return 0;
if (node == -1)
return 0;
sibnode = __prom_getsibling(node);
if(sibnode == -1) return 0;
if (sibnode == -1)
return 0;
return sibnode;
}
......
......@@ -24,6 +24,12 @@
#define PANTHER_IMPL 0x0019 /* Ultra-IV+ */
#define SERRANO_IMPL 0x0022 /* Ultra-IIIi+ */
#define BRANCH_IF_SUN4V(tmp1,label) \
sethi %hi(is_sun4v), %tmp1; \
lduw [%tmp1 + %lo(is_sun4v)], %tmp1; \
brnz,pn %tmp1, label; \
nop
#define BRANCH_IF_CHEETAH_BASE(tmp1,tmp2,label) \
rdpr %ver, %tmp1; \
sethi %hi(__CHEETAH_ID), %tmp2; \
......
......@@ -39,6 +39,9 @@ extern int prom_stdin, prom_stdout;
extern int prom_chosen_node;
/* Helper values and strings in arch/sparc64/kernel/head.S */
extern const char prom_peer_name[];
extern const char prom_compatible_name[];
extern const char prom_root_compatible[];
extern const char prom_finddev_name[];
extern const char prom_chosen_path[];
extern const char prom_getprop_name[];
......
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