[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: David S. Miller <davem@davemloft.net>
This commit is contained in:
parent
1d2f1f90a1
commit
d82ace7dc4
|
@ -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_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,6 +543,7 @@ setup_trap_table:
|
|||
sllx %o2, 32, %o2
|
||||
wr %o2, 0, %tick_cmpr
|
||||
|
||||
BRANCH_IF_SUN4V(o2, 1f)
|
||||
BRANCH_IF_ANY_CHEETAH(o2, o3, 1f)
|
||||
|
||||
ba,pt %xcc, 2f
|
||||
|
|
|
@ -150,6 +150,9 @@ void enable_irq(unsigned int irq)
|
|||
|
||||
preempt_disable();
|
||||
|
||||
if (tlb_type == hypervisor) {
|
||||
/* XXX SUN4V: implement me... XXX */
|
||||
} else {
|
||||
if (tlb_type == cheetah || tlb_type == cheetah_plus) {
|
||||
unsigned long ver;
|
||||
|
||||
|
@ -178,7 +181,8 @@ void enable_irq(unsigned int irq)
|
|||
tid = ((tid & UPA_CONFIG_MID) << 9);
|
||||
tid &= IMAP_TID_UPA;
|
||||
} else {
|
||||
tid = (starfire_translate(imap, smp_processor_id()) << 26);
|
||||
tid = (starfire_translate(imap,
|
||||
smp_processor_id()) << 26);
|
||||
tid &= IMAP_TID_UPA;
|
||||
}
|
||||
|
||||
|
@ -188,9 +192,11 @@ void enable_irq(unsigned int irq)
|
|||
* 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.
|
||||
* 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;
|
||||
|
||||
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,6 +35,7 @@ dtlb_load:
|
|||
sparc64_cpu_startup:
|
||||
flushw
|
||||
|
||||
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)
|
||||
|
||||
|
@ -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,7 +550,17 @@ static void __init remap_kernel(void)
|
|||
|
||||
kern_locked_tte_data = tte_data;
|
||||
|
||||
/* Now lock us into the TLBs via OBP. */
|
||||
/* 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) {
|
||||
|
@ -540,6 +573,7 @@ static void __init remap_kernel(void)
|
|||
tte_vaddr + 0x400000);
|
||||
}
|
||||
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,10 +40,6 @@ 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();
|
||||
|
@ -88,6 +83,7 @@ void __init prom_init(void *cif_handler, void *cif_stack)
|
|||
prom_prev = (ints[0] << 16) | (ints[1] << 8) | ints[2];
|
||||
|
||||
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[];
|
||||
|
|
Loading…
Reference in New Issue