mirror of
https://git.kernel.org/pub/scm/linux/kernel/git/stable/linux.git
synced 2025-01-14 17:35:42 +00:00
Merge master.kernel.org:/pub/scm/linux/kernel/git/davem/sparc-2.6
This commit is contained in:
commit
aac372de6b
@ -53,19 +53,18 @@
|
|||||||
* be guaranteed to be 0 ... mmu_context.h does guarantee this
|
* be guaranteed to be 0 ... mmu_context.h does guarantee this
|
||||||
* by only using 10 bits in the hwcontext value.
|
* by only using 10 bits in the hwcontext value.
|
||||||
*/
|
*/
|
||||||
#define CREATE_VPTE_OFFSET1(r1, r2)
|
#define CREATE_VPTE_OFFSET1(r1, r2) nop
|
||||||
#define CREATE_VPTE_OFFSET2(r1, r2) \
|
#define CREATE_VPTE_OFFSET2(r1, r2) \
|
||||||
srax r1, 10, r2
|
srax r1, 10, r2
|
||||||
#define CREATE_VPTE_NOP nop
|
|
||||||
#else
|
#else
|
||||||
#define CREATE_VPTE_OFFSET1(r1, r2) \
|
#define CREATE_VPTE_OFFSET1(r1, r2) \
|
||||||
srax r1, PAGE_SHIFT, r2
|
srax r1, PAGE_SHIFT, r2
|
||||||
#define CREATE_VPTE_OFFSET2(r1, r2) \
|
#define CREATE_VPTE_OFFSET2(r1, r2) \
|
||||||
sllx r2, 3, r2
|
sllx r2, 3, r2
|
||||||
#define CREATE_VPTE_NOP
|
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
/* DTLB ** ICACHE line 1: Quick user TLB misses */
|
/* DTLB ** ICACHE line 1: Quick user TLB misses */
|
||||||
|
mov TLB_SFSR, %g1
|
||||||
ldxa [%g1 + %g1] ASI_DMMU, %g4 ! Get TAG_ACCESS
|
ldxa [%g1 + %g1] ASI_DMMU, %g4 ! Get TAG_ACCESS
|
||||||
andcc %g4, TAG_CONTEXT_BITS, %g0 ! From Nucleus?
|
andcc %g4, TAG_CONTEXT_BITS, %g0 ! From Nucleus?
|
||||||
from_tl1_trap:
|
from_tl1_trap:
|
||||||
@ -74,18 +73,16 @@ from_tl1_trap:
|
|||||||
be,pn %xcc, kvmap ! Yep, special processing
|
be,pn %xcc, kvmap ! Yep, special processing
|
||||||
CREATE_VPTE_OFFSET2(%g4, %g6) ! Create VPTE offset
|
CREATE_VPTE_OFFSET2(%g4, %g6) ! Create VPTE offset
|
||||||
cmp %g5, 4 ! Last trap level?
|
cmp %g5, 4 ! Last trap level?
|
||||||
be,pn %xcc, longpath ! Yep, cannot risk VPTE miss
|
|
||||||
nop ! delay slot
|
|
||||||
|
|
||||||
/* DTLB ** ICACHE line 2: User finish + quick kernel TLB misses */
|
/* DTLB ** ICACHE line 2: User finish + quick kernel TLB misses */
|
||||||
|
be,pn %xcc, longpath ! Yep, cannot risk VPTE miss
|
||||||
|
nop ! delay slot
|
||||||
ldxa [%g3 + %g6] ASI_S, %g5 ! Load VPTE
|
ldxa [%g3 + %g6] ASI_S, %g5 ! Load VPTE
|
||||||
1: brgez,pn %g5, longpath ! Invalid, branch out
|
1: brgez,pn %g5, longpath ! Invalid, branch out
|
||||||
nop ! Delay-slot
|
nop ! Delay-slot
|
||||||
9: stxa %g5, [%g0] ASI_DTLB_DATA_IN ! Reload TLB
|
9: stxa %g5, [%g0] ASI_DTLB_DATA_IN ! Reload TLB
|
||||||
retry ! Trap return
|
retry ! Trap return
|
||||||
nop
|
nop
|
||||||
nop
|
|
||||||
nop
|
|
||||||
|
|
||||||
/* DTLB ** ICACHE line 3: winfixups+real_faults */
|
/* DTLB ** ICACHE line 3: winfixups+real_faults */
|
||||||
longpath:
|
longpath:
|
||||||
@ -106,8 +103,7 @@ longpath:
|
|||||||
nop
|
nop
|
||||||
nop
|
nop
|
||||||
nop
|
nop
|
||||||
CREATE_VPTE_NOP
|
nop
|
||||||
|
|
||||||
#undef CREATE_VPTE_OFFSET1
|
#undef CREATE_VPTE_OFFSET1
|
||||||
#undef CREATE_VPTE_OFFSET2
|
#undef CREATE_VPTE_OFFSET2
|
||||||
#undef CREATE_VPTE_NOP
|
|
||||||
|
@ -14,14 +14,14 @@
|
|||||||
*/
|
*/
|
||||||
|
|
||||||
/* PROT ** ICACHE line 1: User DTLB protection trap */
|
/* PROT ** ICACHE line 1: User DTLB protection trap */
|
||||||
stxa %g0, [%g1] ASI_DMMU ! Clear SFSR FaultValid bit
|
mov TLB_SFSR, %g1
|
||||||
membar #Sync ! Synchronize ASI stores
|
stxa %g0, [%g1] ASI_DMMU ! Clear FaultValid bit
|
||||||
rdpr %pstate, %g5 ! Move into alternate globals
|
membar #Sync ! Synchronize stores
|
||||||
|
rdpr %pstate, %g5 ! Move into alt-globals
|
||||||
wrpr %g5, PSTATE_AG|PSTATE_MG, %pstate
|
wrpr %g5, PSTATE_AG|PSTATE_MG, %pstate
|
||||||
rdpr %tl, %g1 ! Need to do a winfixup?
|
rdpr %tl, %g1 ! Need a winfixup?
|
||||||
cmp %g1, 1 ! Trap level >1?
|
cmp %g1, 1 ! Trap level >1?
|
||||||
mov TLB_TAG_ACCESS, %g4 ! Prepare reload of vaddr
|
mov TLB_TAG_ACCESS, %g4 ! For reload of vaddr
|
||||||
nop
|
|
||||||
|
|
||||||
/* PROT ** ICACHE line 2: More real fault processing */
|
/* PROT ** ICACHE line 2: More real fault processing */
|
||||||
bgu,pn %xcc, winfix_trampoline ! Yes, perform winfixup
|
bgu,pn %xcc, winfix_trampoline ! Yes, perform winfixup
|
||||||
|
@ -28,19 +28,14 @@
|
|||||||
#include <asm/mmu.h>
|
#include <asm/mmu.h>
|
||||||
|
|
||||||
/* This section from from _start to sparc64_boot_end should fit into
|
/* This section from from _start to sparc64_boot_end should fit into
|
||||||
* 0x0000.0000.0040.4000 to 0x0000.0000.0040.8000 and will be sharing space
|
* 0x0000000000404000 to 0x0000000000408000.
|
||||||
* with bootup_user_stack, which is from 0x0000.0000.0040.4000 to
|
|
||||||
* 0x0000.0000.0040.6000 and empty_bad_page, which is from
|
|
||||||
* 0x0000.0000.0040.6000 to 0x0000.0000.0040.8000.
|
|
||||||
*/
|
*/
|
||||||
|
|
||||||
.text
|
.text
|
||||||
.globl start, _start, stext, _stext
|
.globl start, _start, stext, _stext
|
||||||
_start:
|
_start:
|
||||||
start:
|
start:
|
||||||
_stext:
|
_stext:
|
||||||
stext:
|
stext:
|
||||||
bootup_user_stack:
|
|
||||||
! 0x0000000000404000
|
! 0x0000000000404000
|
||||||
b sparc64_boot
|
b sparc64_boot
|
||||||
flushw /* Flush register file. */
|
flushw /* Flush register file. */
|
||||||
@ -392,31 +387,30 @@ tlb_fixup_done:
|
|||||||
* former does use this code, the latter does not yet due
|
* former does use this code, the latter does not yet due
|
||||||
* to some complexities. That should be fixed up at some
|
* to some complexities. That should be fixed up at some
|
||||||
* point.
|
* point.
|
||||||
|
*
|
||||||
|
* There used to be enormous complexity wrt. transferring
|
||||||
|
* over from the firwmare's trap table to the Linux kernel's.
|
||||||
|
* For example, there was a chicken & egg problem wrt. building
|
||||||
|
* the OBP page tables, yet needing to be on the Linux kernel
|
||||||
|
* trap table (to translate PAGE_OFFSET addresses) in order to
|
||||||
|
* do that.
|
||||||
|
*
|
||||||
|
* We now handle OBP tlb misses differently, via linear lookups
|
||||||
|
* into the prom_trans[] array. So that specific problem no
|
||||||
|
* longer exists. Yet, unfortunately there are still some issues
|
||||||
|
* preventing trampoline.S from using this code... ho hum.
|
||||||
*/
|
*/
|
||||||
.globl setup_trap_table
|
.globl setup_trap_table
|
||||||
setup_trap_table:
|
setup_trap_table:
|
||||||
save %sp, -192, %sp
|
save %sp, -192, %sp
|
||||||
|
|
||||||
/* Force interrupts to be disabled. Transferring over to
|
/* Force interrupts to be disabled. */
|
||||||
* the Linux trap table is a very delicate operation.
|
|
||||||
* Until we are actually on the Linux trap table, we cannot
|
|
||||||
* get the PAGE_OFFSET linear mappings translated. We need
|
|
||||||
* that mapping to be setup in order to initialize the firmware
|
|
||||||
* page tables.
|
|
||||||
*
|
|
||||||
* So there is this window of time, from the return from
|
|
||||||
* prom_set_trap_table() until inherit_prom_mappings_post()
|
|
||||||
* (in arch/sparc64/mm/init.c) completes, during which no
|
|
||||||
* firmware address space accesses can be made.
|
|
||||||
*/
|
|
||||||
rdpr %pstate, %o1
|
rdpr %pstate, %o1
|
||||||
andn %o1, PSTATE_IE, %o1
|
andn %o1, PSTATE_IE, %o1
|
||||||
wrpr %o1, 0x0, %pstate
|
wrpr %o1, 0x0, %pstate
|
||||||
wrpr %g0, 15, %pil
|
wrpr %g0, 15, %pil
|
||||||
|
|
||||||
/* Ok, now make the final valid firmware call to jump over
|
/* Make the firmware call to jump over to the Linux trap table. */
|
||||||
* to the Linux trap table.
|
|
||||||
*/
|
|
||||||
call prom_set_trap_table
|
call prom_set_trap_table
|
||||||
sethi %hi(sparc64_ttable_tl0), %o0
|
sethi %hi(sparc64_ttable_tl0), %o0
|
||||||
|
|
||||||
@ -540,15 +534,21 @@ setup_tba: /* i0 = is_starfire */
|
|||||||
|
|
||||||
ret
|
ret
|
||||||
restore
|
restore
|
||||||
|
sparc64_boot_end:
|
||||||
|
|
||||||
|
#include "systbls.S"
|
||||||
|
#include "ktlb.S"
|
||||||
|
#include "etrap.S"
|
||||||
|
#include "rtrap.S"
|
||||||
|
#include "winfixup.S"
|
||||||
|
#include "entry.S"
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* The following skips make sure the trap table in ttable.S is aligned
|
* The following skip makes sure the trap table in ttable.S is aligned
|
||||||
* on a 32K boundary as required by the v9 specs for TBA register.
|
* on a 32K boundary as required by the v9 specs for TBA register.
|
||||||
*/
|
*/
|
||||||
sparc64_boot_end:
|
1:
|
||||||
.skip 0x2000 + _start - sparc64_boot_end
|
.skip 0x4000 + _start - 1b
|
||||||
bootup_user_stack_end:
|
|
||||||
.skip 0x2000
|
|
||||||
|
|
||||||
#ifdef CONFIG_SBUS
|
#ifdef CONFIG_SBUS
|
||||||
/* This is just a hack to fool make depend config.h discovering
|
/* This is just a hack to fool make depend config.h discovering
|
||||||
@ -560,15 +560,6 @@ bootup_user_stack_end:
|
|||||||
! 0x0000000000408000
|
! 0x0000000000408000
|
||||||
|
|
||||||
#include "ttable.S"
|
#include "ttable.S"
|
||||||
#include "systbls.S"
|
|
||||||
#include "ktlb.S"
|
|
||||||
#include "etrap.S"
|
|
||||||
#include "rtrap.S"
|
|
||||||
#include "winfixup.S"
|
|
||||||
#include "entry.S"
|
|
||||||
|
|
||||||
/* This is just anal retentiveness on my part... */
|
|
||||||
.align 16384
|
|
||||||
|
|
||||||
.data
|
.data
|
||||||
.align 8
|
.align 8
|
||||||
|
@ -15,14 +15,12 @@
|
|||||||
*/
|
*/
|
||||||
#define CREATE_VPTE_OFFSET1(r1, r2) \
|
#define CREATE_VPTE_OFFSET1(r1, r2) \
|
||||||
srax r1, 10, r2
|
srax r1, 10, r2
|
||||||
#define CREATE_VPTE_OFFSET2(r1, r2)
|
#define CREATE_VPTE_OFFSET2(r1, r2) nop
|
||||||
#define CREATE_VPTE_NOP nop
|
|
||||||
#else /* PAGE_SHIFT */
|
#else /* PAGE_SHIFT */
|
||||||
#define CREATE_VPTE_OFFSET1(r1, r2) \
|
#define CREATE_VPTE_OFFSET1(r1, r2) \
|
||||||
srax r1, PAGE_SHIFT, r2
|
srax r1, PAGE_SHIFT, r2
|
||||||
#define CREATE_VPTE_OFFSET2(r1, r2) \
|
#define CREATE_VPTE_OFFSET2(r1, r2) \
|
||||||
sllx r2, 3, r2
|
sllx r2, 3, r2
|
||||||
#define CREATE_VPTE_NOP
|
|
||||||
#endif /* PAGE_SHIFT */
|
#endif /* PAGE_SHIFT */
|
||||||
|
|
||||||
|
|
||||||
@ -36,6 +34,7 @@
|
|||||||
*/
|
*/
|
||||||
|
|
||||||
/* ITLB ** ICACHE line 1: Quick user TLB misses */
|
/* ITLB ** ICACHE line 1: Quick user TLB misses */
|
||||||
|
mov TLB_SFSR, %g1
|
||||||
ldxa [%g1 + %g1] ASI_IMMU, %g4 ! Get TAG_ACCESS
|
ldxa [%g1 + %g1] ASI_IMMU, %g4 ! Get TAG_ACCESS
|
||||||
CREATE_VPTE_OFFSET1(%g4, %g6) ! Create VPTE offset
|
CREATE_VPTE_OFFSET1(%g4, %g6) ! Create VPTE offset
|
||||||
CREATE_VPTE_OFFSET2(%g4, %g6) ! Create VPTE offset
|
CREATE_VPTE_OFFSET2(%g4, %g6) ! Create VPTE offset
|
||||||
@ -43,41 +42,38 @@
|
|||||||
1: brgez,pn %g5, 3f ! Not valid, branch out
|
1: brgez,pn %g5, 3f ! Not valid, branch out
|
||||||
sethi %hi(_PAGE_EXEC), %g4 ! Delay-slot
|
sethi %hi(_PAGE_EXEC), %g4 ! Delay-slot
|
||||||
andcc %g5, %g4, %g0 ! Executable?
|
andcc %g5, %g4, %g0 ! Executable?
|
||||||
|
|
||||||
|
/* ITLB ** ICACHE line 2: Real faults */
|
||||||
be,pn %xcc, 3f ! Nope, branch.
|
be,pn %xcc, 3f ! Nope, branch.
|
||||||
nop ! Delay-slot
|
nop ! Delay-slot
|
||||||
2: stxa %g5, [%g0] ASI_ITLB_DATA_IN ! Load PTE into TLB
|
2: stxa %g5, [%g0] ASI_ITLB_DATA_IN ! Load PTE into TLB
|
||||||
retry ! Trap return
|
retry ! Trap return
|
||||||
3: rdpr %pstate, %g4 ! Move into alternate globals
|
3: rdpr %pstate, %g4 ! Move into alt-globals
|
||||||
|
|
||||||
/* ITLB ** ICACHE line 2: Real faults */
|
|
||||||
wrpr %g4, PSTATE_AG|PSTATE_MG, %pstate
|
wrpr %g4, PSTATE_AG|PSTATE_MG, %pstate
|
||||||
rdpr %tpc, %g5 ! And load faulting VA
|
rdpr %tpc, %g5 ! And load faulting VA
|
||||||
mov FAULT_CODE_ITLB, %g4 ! It was read from ITLB
|
mov FAULT_CODE_ITLB, %g4 ! It was read from ITLB
|
||||||
sparc64_realfault_common: ! Called by TL0 dtlb_miss too
|
|
||||||
|
/* ITLB ** ICACHE line 3: Finish faults */
|
||||||
|
sparc64_realfault_common: ! Called by dtlb_miss
|
||||||
stb %g4, [%g6 + TI_FAULT_CODE]
|
stb %g4, [%g6 + TI_FAULT_CODE]
|
||||||
stx %g5, [%g6 + TI_FAULT_ADDR]
|
stx %g5, [%g6 + TI_FAULT_ADDR]
|
||||||
ba,pt %xcc, etrap ! Save state
|
ba,pt %xcc, etrap ! Save state
|
||||||
1: rd %pc, %g7 ! ...
|
1: rd %pc, %g7 ! ...
|
||||||
nop
|
|
||||||
|
|
||||||
/* ITLB ** ICACHE line 3: Finish faults + window fixups */
|
|
||||||
call do_sparc64_fault ! Call fault handler
|
call do_sparc64_fault ! Call fault handler
|
||||||
add %sp, PTREGS_OFF, %o0! Compute pt_regs arg
|
add %sp, PTREGS_OFF, %o0! Compute pt_regs arg
|
||||||
ba,pt %xcc, rtrap_clr_l6 ! Restore cpu state
|
ba,pt %xcc, rtrap_clr_l6 ! Restore cpu state
|
||||||
nop
|
nop
|
||||||
|
|
||||||
|
/* ITLB ** ICACHE line 4: Window fixups */
|
||||||
winfix_trampoline:
|
winfix_trampoline:
|
||||||
rdpr %tpc, %g3 ! Prepare winfixup TNPC
|
rdpr %tpc, %g3 ! Prepare winfixup TNPC
|
||||||
or %g3, 0x7c, %g3 ! Compute offset to branch
|
or %g3, 0x7c, %g3 ! Compute branch offset
|
||||||
wrpr %g3, %tnpc ! Write it into TNPC
|
wrpr %g3, %tnpc ! Write it into TNPC
|
||||||
done ! Do it to it
|
done ! Do it to it
|
||||||
|
|
||||||
/* ITLB ** ICACHE line 4: Unused... */
|
|
||||||
nop
|
nop
|
||||||
nop
|
nop
|
||||||
nop
|
nop
|
||||||
nop
|
nop
|
||||||
CREATE_VPTE_NOP
|
|
||||||
|
|
||||||
#undef CREATE_VPTE_OFFSET1
|
#undef CREATE_VPTE_OFFSET1
|
||||||
#undef CREATE_VPTE_OFFSET2
|
#undef CREATE_VPTE_OFFSET2
|
||||||
#undef CREATE_VPTE_NOP
|
|
||||||
|
@ -58,9 +58,6 @@ vpte_noent:
|
|||||||
done
|
done
|
||||||
|
|
||||||
vpte_insn_obp:
|
vpte_insn_obp:
|
||||||
sethi %hi(prom_pmd_phys), %g5
|
|
||||||
ldx [%g5 + %lo(prom_pmd_phys)], %g5
|
|
||||||
|
|
||||||
/* Behave as if we are at TL0. */
|
/* Behave as if we are at TL0. */
|
||||||
wrpr %g0, 1, %tl
|
wrpr %g0, 1, %tl
|
||||||
rdpr %tpc, %g4 /* Find original faulting iaddr */
|
rdpr %tpc, %g4 /* Find original faulting iaddr */
|
||||||
@ -71,58 +68,57 @@ vpte_insn_obp:
|
|||||||
mov TLB_SFSR, %g1
|
mov TLB_SFSR, %g1
|
||||||
stxa %g4, [%g1 + %g1] ASI_IMMU
|
stxa %g4, [%g1 + %g1] ASI_IMMU
|
||||||
|
|
||||||
/* Get PMD offset. */
|
sethi %hi(prom_trans), %g5
|
||||||
srlx %g4, 23, %g6
|
or %g5, %lo(prom_trans), %g5
|
||||||
and %g6, 0x7ff, %g6
|
|
||||||
sllx %g6, 2, %g6
|
|
||||||
|
|
||||||
/* Load PMD, is it valid? */
|
1: ldx [%g5 + 0x00], %g6 ! base
|
||||||
lduwa [%g5 + %g6] ASI_PHYS_USE_EC, %g5
|
brz,a,pn %g6, longpath ! no more entries, fail
|
||||||
brz,pn %g5, longpath
|
mov TLB_SFSR, %g1 ! and restore %g1
|
||||||
sllx %g5, 11, %g5
|
ldx [%g5 + 0x08], %g1 ! len
|
||||||
|
add %g6, %g1, %g1 ! end
|
||||||
|
cmp %g6, %g4
|
||||||
|
bgu,pt %xcc, 2f
|
||||||
|
cmp %g4, %g1
|
||||||
|
bgeu,pt %xcc, 2f
|
||||||
|
ldx [%g5 + 0x10], %g1 ! PTE
|
||||||
|
|
||||||
/* Get PTE offset. */
|
/* TLB load, restore %g1, and return from trap. */
|
||||||
srlx %g4, 13, %g6
|
sub %g4, %g6, %g6
|
||||||
and %g6, 0x3ff, %g6
|
add %g1, %g6, %g5
|
||||||
sllx %g6, 3, %g6
|
mov TLB_SFSR, %g1
|
||||||
|
|
||||||
/* Load PTE. */
|
|
||||||
ldxa [%g5 + %g6] ASI_PHYS_USE_EC, %g5
|
|
||||||
brgez,pn %g5, longpath
|
|
||||||
nop
|
|
||||||
|
|
||||||
/* TLB load and return from trap. */
|
|
||||||
stxa %g5, [%g0] ASI_ITLB_DATA_IN
|
stxa %g5, [%g0] ASI_ITLB_DATA_IN
|
||||||
retry
|
retry
|
||||||
|
|
||||||
|
2: ba,pt %xcc, 1b
|
||||||
|
add %g5, (3 * 8), %g5 ! next entry
|
||||||
|
|
||||||
kvmap_do_obp:
|
kvmap_do_obp:
|
||||||
sethi %hi(prom_pmd_phys), %g5
|
sethi %hi(prom_trans), %g5
|
||||||
ldx [%g5 + %lo(prom_pmd_phys)], %g5
|
or %g5, %lo(prom_trans), %g5
|
||||||
|
srlx %g4, 13, %g4
|
||||||
|
sllx %g4, 13, %g4
|
||||||
|
|
||||||
/* Get PMD offset. */
|
1: ldx [%g5 + 0x00], %g6 ! base
|
||||||
srlx %g4, 23, %g6
|
brz,a,pn %g6, longpath ! no more entries, fail
|
||||||
and %g6, 0x7ff, %g6
|
mov TLB_SFSR, %g1 ! and restore %g1
|
||||||
sllx %g6, 2, %g6
|
ldx [%g5 + 0x08], %g1 ! len
|
||||||
|
add %g6, %g1, %g1 ! end
|
||||||
|
cmp %g6, %g4
|
||||||
|
bgu,pt %xcc, 2f
|
||||||
|
cmp %g4, %g1
|
||||||
|
bgeu,pt %xcc, 2f
|
||||||
|
ldx [%g5 + 0x10], %g1 ! PTE
|
||||||
|
|
||||||
/* Load PMD, is it valid? */
|
/* TLB load, restore %g1, and return from trap. */
|
||||||
lduwa [%g5 + %g6] ASI_PHYS_USE_EC, %g5
|
sub %g4, %g6, %g6
|
||||||
brz,pn %g5, longpath
|
add %g1, %g6, %g5
|
||||||
sllx %g5, 11, %g5
|
mov TLB_SFSR, %g1
|
||||||
|
|
||||||
/* Get PTE offset. */
|
|
||||||
srlx %g4, 13, %g6
|
|
||||||
and %g6, 0x3ff, %g6
|
|
||||||
sllx %g6, 3, %g6
|
|
||||||
|
|
||||||
/* Load PTE. */
|
|
||||||
ldxa [%g5 + %g6] ASI_PHYS_USE_EC, %g5
|
|
||||||
brgez,pn %g5, longpath
|
|
||||||
nop
|
|
||||||
|
|
||||||
/* TLB load and return from trap. */
|
|
||||||
stxa %g5, [%g0] ASI_DTLB_DATA_IN
|
stxa %g5, [%g0] ASI_DTLB_DATA_IN
|
||||||
retry
|
retry
|
||||||
|
|
||||||
|
2: ba,pt %xcc, 1b
|
||||||
|
add %g5, (3 * 8), %g5 ! next entry
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* On a first level data miss, check whether this is to the OBP range (note
|
* On a first level data miss, check whether this is to the OBP range (note
|
||||||
* that such accesses can be made by prom, as well as by kernel using
|
* that such accesses can be made by prom, as well as by kernel using
|
||||||
|
@ -367,8 +367,11 @@ struct linux_prom_translation {
|
|||||||
unsigned long size;
|
unsigned long size;
|
||||||
unsigned long data;
|
unsigned long data;
|
||||||
};
|
};
|
||||||
static struct linux_prom_translation prom_trans[512] __initdata;
|
|
||||||
static unsigned int prom_trans_ents __initdata;
|
/* Exported for kernel TLB miss handling in ktlb.S */
|
||||||
|
struct linux_prom_translation prom_trans[512] __read_mostly;
|
||||||
|
unsigned int prom_trans_ents __read_mostly;
|
||||||
|
unsigned int swapper_pgd_zero __read_mostly;
|
||||||
|
|
||||||
extern unsigned long prom_boot_page;
|
extern unsigned long prom_boot_page;
|
||||||
extern void prom_remap(unsigned long physpage, unsigned long virtpage, int mmu_ihandle);
|
extern void prom_remap(unsigned long physpage, unsigned long virtpage, int mmu_ihandle);
|
||||||
@ -378,122 +381,57 @@ extern void register_prom_callbacks(void);
|
|||||||
/* Exported for SMP bootup purposes. */
|
/* Exported for SMP bootup purposes. */
|
||||||
unsigned long kern_locked_tte_data;
|
unsigned long kern_locked_tte_data;
|
||||||
|
|
||||||
/* Exported for kernel TLB miss handling in ktlb.S */
|
|
||||||
unsigned long prom_pmd_phys __read_mostly;
|
|
||||||
unsigned int swapper_pgd_zero __read_mostly;
|
|
||||||
|
|
||||||
static pmd_t *prompmd __read_mostly;
|
|
||||||
|
|
||||||
#define BASE_PAGE_SIZE 8192
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Translate PROM's mapping we capture at boot time into physical address.
|
* Translate PROM's mapping we capture at boot time into physical address.
|
||||||
* The second parameter is only set from prom_callback() invocations.
|
* The second parameter is only set from prom_callback() invocations.
|
||||||
*/
|
*/
|
||||||
unsigned long prom_virt_to_phys(unsigned long promva, int *error)
|
unsigned long prom_virt_to_phys(unsigned long promva, int *error)
|
||||||
{
|
{
|
||||||
pmd_t *pmdp = prompmd + ((promva >> 23) & 0x7ff);
|
int i;
|
||||||
pte_t *ptep;
|
|
||||||
unsigned long base;
|
for (i = 0; i < prom_trans_ents; i++) {
|
||||||
|
struct linux_prom_translation *p = &prom_trans[i];
|
||||||
|
|
||||||
|
if (promva >= p->virt &&
|
||||||
|
promva < (p->virt + p->size)) {
|
||||||
|
unsigned long base = p->data & _PAGE_PADDR;
|
||||||
|
|
||||||
if (pmd_none(*pmdp)) {
|
|
||||||
if (error)
|
if (error)
|
||||||
*error = 1;
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
ptep = (pte_t *)__pmd_page(*pmdp) + ((promva >> 13) & 0x3ff);
|
|
||||||
if (!pte_present(*ptep)) {
|
|
||||||
if (error)
|
|
||||||
*error = 1;
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
if (error) {
|
|
||||||
*error = 0;
|
*error = 0;
|
||||||
return pte_val(*ptep);
|
return base + (promva & (8192 - 1));
|
||||||
}
|
}
|
||||||
base = pte_val(*ptep) & _PAGE_PADDR;
|
}
|
||||||
|
if (error)
|
||||||
return base + (promva & (BASE_PAGE_SIZE - 1));
|
*error = 1;
|
||||||
|
return 0UL;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* The obp translations are saved based on 8k pagesize, since obp can
|
/* The obp translations are saved based on 8k pagesize, since obp can
|
||||||
* use a mixture of pagesizes. Misses to the LOW_OBP_ADDRESS ->
|
* use a mixture of pagesizes. Misses to the LOW_OBP_ADDRESS ->
|
||||||
* HI_OBP_ADDRESS range are handled in entry.S and do not use the vpte
|
* HI_OBP_ADDRESS range are handled in ktlb.S and do not use the vpte
|
||||||
* scheme (also, see rant in inherit_locked_prom_mappings()).
|
* scheme (also, see rant in inherit_locked_prom_mappings()).
|
||||||
*/
|
*/
|
||||||
static void __init build_obp_range(unsigned long start, unsigned long end, unsigned long data)
|
|
||||||
{
|
|
||||||
unsigned long vaddr;
|
|
||||||
|
|
||||||
for (vaddr = start; vaddr < end; vaddr += BASE_PAGE_SIZE) {
|
|
||||||
unsigned long val;
|
|
||||||
pmd_t *pmd;
|
|
||||||
pte_t *pte;
|
|
||||||
|
|
||||||
pmd = prompmd + ((vaddr >> 23) & 0x7ff);
|
|
||||||
if (pmd_none(*pmd)) {
|
|
||||||
pte = __alloc_bootmem(BASE_PAGE_SIZE, BASE_PAGE_SIZE,
|
|
||||||
PAGE_SIZE);
|
|
||||||
if (!pte)
|
|
||||||
prom_halt();
|
|
||||||
memset(pte, 0, BASE_PAGE_SIZE);
|
|
||||||
pmd_set(pmd, pte);
|
|
||||||
}
|
|
||||||
pte = (pte_t *) __pmd_page(*pmd) + ((vaddr >> 13) & 0x3ff);
|
|
||||||
|
|
||||||
val = data;
|
|
||||||
|
|
||||||
/* Clear diag TTE bits. */
|
|
||||||
if (tlb_type == spitfire)
|
|
||||||
val &= ~0x0003fe0000000000UL;
|
|
||||||
|
|
||||||
set_pte_at(&init_mm, vaddr, pte,
|
|
||||||
__pte(val | _PAGE_MODIFIED));
|
|
||||||
|
|
||||||
data += BASE_PAGE_SIZE;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
static inline int in_obp_range(unsigned long vaddr)
|
static inline int in_obp_range(unsigned long vaddr)
|
||||||
{
|
{
|
||||||
return (vaddr >= LOW_OBP_ADDRESS &&
|
return (vaddr >= LOW_OBP_ADDRESS &&
|
||||||
vaddr < HI_OBP_ADDRESS);
|
vaddr < HI_OBP_ADDRESS);
|
||||||
}
|
}
|
||||||
|
|
||||||
#define OBP_PMD_SIZE 2048
|
static int cmp_ptrans(const void *a, const void *b)
|
||||||
static void __init build_obp_pgtable(void)
|
|
||||||
{
|
{
|
||||||
unsigned long i;
|
const struct linux_prom_translation *x = a, *y = b;
|
||||||
|
|
||||||
prompmd = __alloc_bootmem(OBP_PMD_SIZE, OBP_PMD_SIZE, PAGE_SIZE);
|
if (x->virt > y->virt)
|
||||||
if (!prompmd)
|
return 1;
|
||||||
prom_halt();
|
if (x->virt < y->virt)
|
||||||
|
return -1;
|
||||||
memset(prompmd, 0, OBP_PMD_SIZE);
|
return 0;
|
||||||
|
|
||||||
prom_pmd_phys = __pa(prompmd);
|
|
||||||
|
|
||||||
for (i = 0; i < prom_trans_ents; i++) {
|
|
||||||
unsigned long start, end;
|
|
||||||
|
|
||||||
if (!in_obp_range(prom_trans[i].virt))
|
|
||||||
continue;
|
|
||||||
|
|
||||||
start = prom_trans[i].virt;
|
|
||||||
end = start + prom_trans[i].size;
|
|
||||||
if (end > HI_OBP_ADDRESS)
|
|
||||||
end = HI_OBP_ADDRESS;
|
|
||||||
|
|
||||||
build_obp_range(start, end, prom_trans[i].data);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Read OBP translations property into 'prom_trans[]'.
|
/* Read OBP translations property into 'prom_trans[]'. */
|
||||||
* Return the number of entries.
|
|
||||||
*/
|
|
||||||
static void __init read_obp_translations(void)
|
static void __init read_obp_translations(void)
|
||||||
{
|
{
|
||||||
int n, node;
|
int n, node, ents, first, last, i;
|
||||||
|
|
||||||
node = prom_finddevice("/virtual-memory");
|
node = prom_finddevice("/virtual-memory");
|
||||||
n = prom_getproplen(node, "translations");
|
n = prom_getproplen(node, "translations");
|
||||||
@ -515,7 +453,41 @@ static void __init read_obp_translations(void)
|
|||||||
|
|
||||||
n = n / sizeof(struct linux_prom_translation);
|
n = n / sizeof(struct linux_prom_translation);
|
||||||
|
|
||||||
prom_trans_ents = n;
|
ents = n;
|
||||||
|
|
||||||
|
sort(prom_trans, ents, sizeof(struct linux_prom_translation),
|
||||||
|
cmp_ptrans, NULL);
|
||||||
|
|
||||||
|
/* Now kick out all the non-OBP entries. */
|
||||||
|
for (i = 0; i < ents; i++) {
|
||||||
|
if (in_obp_range(prom_trans[i].virt))
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
first = i;
|
||||||
|
for (; i < ents; i++) {
|
||||||
|
if (!in_obp_range(prom_trans[i].virt))
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
last = i;
|
||||||
|
|
||||||
|
for (i = 0; i < (last - first); i++) {
|
||||||
|
struct linux_prom_translation *src = &prom_trans[i + first];
|
||||||
|
struct linux_prom_translation *dest = &prom_trans[i];
|
||||||
|
|
||||||
|
*dest = *src;
|
||||||
|
}
|
||||||
|
for (; i < ents; i++) {
|
||||||
|
struct linux_prom_translation *dest = &prom_trans[i];
|
||||||
|
dest->virt = dest->size = dest->data = 0x0UL;
|
||||||
|
}
|
||||||
|
|
||||||
|
prom_trans_ents = last - first;
|
||||||
|
|
||||||
|
if (tlb_type == spitfire) {
|
||||||
|
/* Clear diag TTE bits. */
|
||||||
|
for (i = 0; i < prom_trans_ents; i++)
|
||||||
|
prom_trans[i].data &= ~0x0003fe0000000000UL;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
static void __init remap_kernel(void)
|
static void __init remap_kernel(void)
|
||||||
@ -553,21 +525,18 @@ static void __init remap_kernel(void)
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
static void __init inherit_prom_mappings_pre(void)
|
static void __init inherit_prom_mappings(void)
|
||||||
{
|
{
|
||||||
read_obp_translations();
|
read_obp_translations();
|
||||||
|
|
||||||
/* Now fixup OBP's idea about where we really are mapped. */
|
/* Now fixup OBP's idea about where we really are mapped. */
|
||||||
prom_printf("Remapping the kernel... ");
|
prom_printf("Remapping the kernel... ");
|
||||||
remap_kernel();
|
remap_kernel();
|
||||||
|
|
||||||
prom_printf("done.\n");
|
prom_printf("done.\n");
|
||||||
}
|
|
||||||
|
|
||||||
static void __init inherit_prom_mappings_post(void)
|
prom_printf("Registering callbacks... ");
|
||||||
{
|
|
||||||
build_obp_pgtable();
|
|
||||||
register_prom_callbacks();
|
register_prom_callbacks();
|
||||||
|
prom_printf("done.\n");
|
||||||
}
|
}
|
||||||
|
|
||||||
/* The OBP specifications for sun4u mark 0xfffffffc00000000 and
|
/* The OBP specifications for sun4u mark 0xfffffffc00000000 and
|
||||||
@ -1519,7 +1488,7 @@ void __init paging_init(void)
|
|||||||
|
|
||||||
swapper_pgd_zero = pgd_val(swapper_pg_dir[0]);
|
swapper_pgd_zero = pgd_val(swapper_pg_dir[0]);
|
||||||
|
|
||||||
inherit_prom_mappings_pre();
|
inherit_prom_mappings();
|
||||||
|
|
||||||
/* Ok, we can use our TLB miss and window trap handlers safely.
|
/* Ok, we can use our TLB miss and window trap handlers safely.
|
||||||
* We need to do a quick peek here to see if we are on StarFire
|
* We need to do a quick peek here to see if we are on StarFire
|
||||||
@ -1530,23 +1499,15 @@ void __init paging_init(void)
|
|||||||
extern void setup_tba(int);
|
extern void setup_tba(int);
|
||||||
setup_tba(this_is_starfire);
|
setup_tba(this_is_starfire);
|
||||||
}
|
}
|
||||||
__flush_tlb_all();
|
|
||||||
|
|
||||||
/* Everything from this point forward, until we are done with
|
inherit_locked_prom_mappings(1);
|
||||||
* inherit_prom_mappings_post(), must complete successfully
|
|
||||||
* without calling into the firmware. The firwmare page tables
|
__flush_tlb_all();
|
||||||
* have not been built, but we are running on the Linux kernel's
|
|
||||||
* trap table.
|
|
||||||
*/
|
|
||||||
|
|
||||||
/* Setup bootmem... */
|
/* Setup bootmem... */
|
||||||
pages_avail = 0;
|
pages_avail = 0;
|
||||||
last_valid_pfn = end_pfn = bootmem_init(&pages_avail);
|
last_valid_pfn = end_pfn = bootmem_init(&pages_avail);
|
||||||
|
|
||||||
inherit_prom_mappings_post();
|
|
||||||
|
|
||||||
inherit_locked_prom_mappings(1);
|
|
||||||
|
|
||||||
#ifdef CONFIG_DEBUG_PAGEALLOC
|
#ifdef CONFIG_DEBUG_PAGEALLOC
|
||||||
kernel_physical_mapping_init();
|
kernel_physical_mapping_init();
|
||||||
#endif
|
#endif
|
||||||
|
Loading…
x
Reference in New Issue
Block a user