diff options
| -rw-r--r-- | arch/sparc64/kernel/dtlb_base.S | 14 | ||||
| -rw-r--r-- | arch/sparc64/kernel/dtlb_prot.S | 12 | ||||
| -rw-r--r-- | arch/sparc64/kernel/head.S | 61 | ||||
| -rw-r--r-- | arch/sparc64/kernel/itlb_base.S | 26 | ||||
| -rw-r--r-- | arch/sparc64/kernel/ktlb.S | 92 | ||||
| -rw-r--r-- | arch/sparc64/mm/init.c | 187 |
6 files changed, 166 insertions, 226 deletions
diff --git a/arch/sparc64/kernel/dtlb_base.S b/arch/sparc64/kernel/dtlb_base.S index 702d349c1e88..6528786840c0 100644 --- a/arch/sparc64/kernel/dtlb_base.S +++ b/arch/sparc64/kernel/dtlb_base.S | |||
| @@ -53,19 +53,18 @@ | |||
| 53 | * be guaranteed to be 0 ... mmu_context.h does guarantee this | 53 | * be guaranteed to be 0 ... mmu_context.h does guarantee this |
| 54 | * by only using 10 bits in the hwcontext value. | 54 | * by only using 10 bits in the hwcontext value. |
| 55 | */ | 55 | */ |
| 56 | #define CREATE_VPTE_OFFSET1(r1, r2) | 56 | #define CREATE_VPTE_OFFSET1(r1, r2) nop |
| 57 | #define CREATE_VPTE_OFFSET2(r1, r2) \ | 57 | #define CREATE_VPTE_OFFSET2(r1, r2) \ |
| 58 | srax r1, 10, r2 | 58 | srax r1, 10, r2 |
| 59 | #define CREATE_VPTE_NOP nop | ||
| 60 | #else | 59 | #else |
| 61 | #define CREATE_VPTE_OFFSET1(r1, r2) \ | 60 | #define CREATE_VPTE_OFFSET1(r1, r2) \ |
| 62 | srax r1, PAGE_SHIFT, r2 | 61 | srax r1, PAGE_SHIFT, r2 |
| 63 | #define CREATE_VPTE_OFFSET2(r1, r2) \ | 62 | #define CREATE_VPTE_OFFSET2(r1, r2) \ |
| 64 | sllx r2, 3, r2 | 63 | sllx r2, 3, r2 |
| 65 | #define CREATE_VPTE_NOP | ||
| 66 | #endif | 64 | #endif |
| 67 | 65 | ||
| 68 | /* DTLB ** ICACHE line 1: Quick user TLB misses */ | 66 | /* DTLB ** ICACHE line 1: Quick user TLB misses */ |
| 67 | mov TLB_SFSR, %g1 | ||
| 69 | ldxa [%g1 + %g1] ASI_DMMU, %g4 ! Get TAG_ACCESS | 68 | ldxa [%g1 + %g1] ASI_DMMU, %g4 ! Get TAG_ACCESS |
| 70 | andcc %g4, TAG_CONTEXT_BITS, %g0 ! From Nucleus? | 69 | andcc %g4, TAG_CONTEXT_BITS, %g0 ! From Nucleus? |
| 71 | from_tl1_trap: | 70 | from_tl1_trap: |
| @@ -74,18 +73,16 @@ from_tl1_trap: | |||
| 74 | be,pn %xcc, kvmap ! Yep, special processing | 73 | be,pn %xcc, kvmap ! Yep, special processing |
| 75 | CREATE_VPTE_OFFSET2(%g4, %g6) ! Create VPTE offset | 74 | CREATE_VPTE_OFFSET2(%g4, %g6) ! Create VPTE offset |
| 76 | cmp %g5, 4 ! Last trap level? | 75 | cmp %g5, 4 ! Last trap level? |
| 77 | be,pn %xcc, longpath ! Yep, cannot risk VPTE miss | ||
| 78 | nop ! delay slot | ||
| 79 | 76 | ||
| 80 | /* DTLB ** ICACHE line 2: User finish + quick kernel TLB misses */ | 77 | /* DTLB ** ICACHE line 2: User finish + quick kernel TLB misses */ |
| 78 | be,pn %xcc, longpath ! Yep, cannot risk VPTE miss | ||
| 79 | nop ! delay slot | ||
| 81 | ldxa [%g3 + %g6] ASI_S, %g5 ! Load VPTE | 80 | ldxa [%g3 + %g6] ASI_S, %g5 ! Load VPTE |
| 82 | 1: brgez,pn %g5, longpath ! Invalid, branch out | 81 | 1: brgez,pn %g5, longpath ! Invalid, branch out |
| 83 | nop ! Delay-slot | 82 | nop ! Delay-slot |
| 84 | 9: stxa %g5, [%g0] ASI_DTLB_DATA_IN ! Reload TLB | 83 | 9: stxa %g5, [%g0] ASI_DTLB_DATA_IN ! Reload TLB |
| 85 | retry ! Trap return | 84 | retry ! Trap return |
| 86 | nop | 85 | nop |
| 87 | nop | ||
| 88 | nop | ||
| 89 | 86 | ||
| 90 | /* DTLB ** ICACHE line 3: winfixups+real_faults */ | 87 | /* DTLB ** ICACHE line 3: winfixups+real_faults */ |
| 91 | longpath: | 88 | longpath: |
| @@ -106,8 +103,7 @@ longpath: | |||
| 106 | nop | 103 | nop |
| 107 | nop | 104 | nop |
| 108 | nop | 105 | nop |
| 109 | CREATE_VPTE_NOP | 106 | nop |
| 110 | 107 | ||
| 111 | #undef CREATE_VPTE_OFFSET1 | 108 | #undef CREATE_VPTE_OFFSET1 |
| 112 | #undef CREATE_VPTE_OFFSET2 | 109 | #undef CREATE_VPTE_OFFSET2 |
| 113 | #undef CREATE_VPTE_NOP | ||
diff --git a/arch/sparc64/kernel/dtlb_prot.S b/arch/sparc64/kernel/dtlb_prot.S index d848bb7374bb..e0a920162604 100644 --- a/arch/sparc64/kernel/dtlb_prot.S +++ b/arch/sparc64/kernel/dtlb_prot.S | |||
| @@ -14,14 +14,14 @@ | |||
| 14 | */ | 14 | */ |
| 15 | 15 | ||
| 16 | /* PROT ** ICACHE line 1: User DTLB protection trap */ | 16 | /* PROT ** ICACHE line 1: User DTLB protection trap */ |
| 17 | stxa %g0, [%g1] ASI_DMMU ! Clear SFSR FaultValid bit | 17 | mov TLB_SFSR, %g1 |
| 18 | membar #Sync ! Synchronize ASI stores | 18 | stxa %g0, [%g1] ASI_DMMU ! Clear FaultValid bit |
| 19 | rdpr %pstate, %g5 ! Move into alternate globals | 19 | membar #Sync ! Synchronize stores |
| 20 | rdpr %pstate, %g5 ! Move into alt-globals | ||
| 20 | wrpr %g5, PSTATE_AG|PSTATE_MG, %pstate | 21 | wrpr %g5, PSTATE_AG|PSTATE_MG, %pstate |
| 21 | rdpr %tl, %g1 ! Need to do a winfixup? | 22 | rdpr %tl, %g1 ! Need a winfixup? |
| 22 | cmp %g1, 1 ! Trap level >1? | 23 | cmp %g1, 1 ! Trap level >1? |
| 23 | mov TLB_TAG_ACCESS, %g4 ! Prepare reload of vaddr | 24 | mov TLB_TAG_ACCESS, %g4 ! For reload of vaddr |
| 24 | nop | ||
| 25 | 25 | ||
| 26 | /* PROT ** ICACHE line 2: More real fault processing */ | 26 | /* PROT ** ICACHE line 2: More real fault processing */ |
| 27 | bgu,pn %xcc, winfix_trampoline ! Yes, perform winfixup | 27 | bgu,pn %xcc, winfix_trampoline ! Yes, perform winfixup |
diff --git a/arch/sparc64/kernel/head.S b/arch/sparc64/kernel/head.S index 4c942f71184d..b49dcd4504b0 100644 --- a/arch/sparc64/kernel/head.S +++ b/arch/sparc64/kernel/head.S | |||
| @@ -28,19 +28,14 @@ | |||
| 28 | #include <asm/mmu.h> | 28 | #include <asm/mmu.h> |
| 29 | 29 | ||
| 30 | /* This section from from _start to sparc64_boot_end should fit into | 30 | /* This section from from _start to sparc64_boot_end should fit into |
| 31 | * 0x0000.0000.0040.4000 to 0x0000.0000.0040.8000 and will be sharing space | 31 | * 0x0000000000404000 to 0x0000000000408000. |
| 32 | * with bootup_user_stack, which is from 0x0000.0000.0040.4000 to | ||
| 33 | * 0x0000.0000.0040.6000 and empty_bad_page, which is from | ||
| 34 | * 0x0000.0000.0040.6000 to 0x0000.0000.0040.8000. | ||
| 35 | */ | 32 | */ |
| 36 | |||
| 37 | .text | 33 | .text |
| 38 | .globl start, _start, stext, _stext | 34 | .globl start, _start, stext, _stext |
| 39 | _start: | 35 | _start: |
| 40 | start: | 36 | start: |
| 41 | _stext: | 37 | _stext: |
| 42 | stext: | 38 | stext: |
| 43 | bootup_user_stack: | ||
| 44 | ! 0x0000000000404000 | 39 | ! 0x0000000000404000 |
| 45 | b sparc64_boot | 40 | b sparc64_boot |
| 46 | flushw /* Flush register file. */ | 41 | flushw /* Flush register file. */ |
| @@ -392,31 +387,30 @@ tlb_fixup_done: | |||
| 392 | * former does use this code, the latter does not yet due | 387 | * former does use this code, the latter does not yet due |
| 393 | * to some complexities. That should be fixed up at some | 388 | * to some complexities. That should be fixed up at some |
| 394 | * point. | 389 | * point. |
| 390 | * | ||
| 391 | * There used to be enormous complexity wrt. transferring | ||
| 392 | * over from the firwmare's trap table to the Linux kernel's. | ||
| 393 | * For example, there was a chicken & egg problem wrt. building | ||
| 394 | * the OBP page tables, yet needing to be on the Linux kernel | ||
| 395 | * trap table (to translate PAGE_OFFSET addresses) in order to | ||
| 396 | * do that. | ||
| 397 | * | ||
| 398 | * We now handle OBP tlb misses differently, via linear lookups | ||
| 399 | * into the prom_trans[] array. So that specific problem no | ||
| 400 | * longer exists. Yet, unfortunately there are still some issues | ||
| 401 | * preventing trampoline.S from using this code... ho hum. | ||
| 395 | */ | 402 | */ |
| 396 | .globl setup_trap_table | 403 | .globl setup_trap_table |
| 397 | setup_trap_table: | 404 | setup_trap_table: |
| 398 | save %sp, -192, %sp | 405 | save %sp, -192, %sp |
| 399 | 406 | ||
| 400 | /* Force interrupts to be disabled. Transferring over to | 407 | /* Force interrupts to be disabled. */ |
| 401 | * the Linux trap table is a very delicate operation. | ||
| 402 | * Until we are actually on the Linux trap table, we cannot | ||
| 403 | * get the PAGE_OFFSET linear mappings translated. We need | ||
| 404 | * that mapping to be setup in order to initialize the firmware | ||
| 405 | * page tables. | ||
| 406 | * | ||
| 407 | * So there is this window of time, from the return from | ||
| 408 | * prom_set_trap_table() until inherit_prom_mappings_post() | ||
| 409 | * (in arch/sparc64/mm/init.c) completes, during which no | ||
| 410 | * firmware address space accesses can be made. | ||
| 411 | */ | ||
| 412 | rdpr %pstate, %o1 | 408 | rdpr %pstate, %o1 |
| 413 | andn %o1, PSTATE_IE, %o1 | 409 | andn %o1, PSTATE_IE, %o1 |
| 414 | wrpr %o1, 0x0, %pstate | 410 | wrpr %o1, 0x0, %pstate |
| 415 | wrpr %g0, 15, %pil | 411 | wrpr %g0, 15, %pil |
| 416 | 412 | ||
| 417 | /* Ok, now make the final valid firmware call to jump over | 413 | /* Make the firmware call to jump over to the Linux trap table. */ |
| 418 | * to the Linux trap table. | ||
| 419 | */ | ||
| 420 | call prom_set_trap_table | 414 | call prom_set_trap_table |
| 421 | sethi %hi(sparc64_ttable_tl0), %o0 | 415 | sethi %hi(sparc64_ttable_tl0), %o0 |
| 422 | 416 | ||
| @@ -540,15 +534,21 @@ setup_tba: /* i0 = is_starfire */ | |||
| 540 | 534 | ||
| 541 | ret | 535 | ret |
| 542 | restore | 536 | restore |
| 537 | sparc64_boot_end: | ||
| 538 | |||
| 539 | #include "systbls.S" | ||
| 540 | #include "ktlb.S" | ||
| 541 | #include "etrap.S" | ||
| 542 | #include "rtrap.S" | ||
| 543 | #include "winfixup.S" | ||
| 544 | #include "entry.S" | ||
| 543 | 545 | ||
| 544 | /* | 546 | /* |
| 545 | * The following skips make sure the trap table in ttable.S is aligned | 547 | * The following skip makes sure the trap table in ttable.S is aligned |
| 546 | * on a 32K boundary as required by the v9 specs for TBA register. | 548 | * on a 32K boundary as required by the v9 specs for TBA register. |
| 547 | */ | 549 | */ |
| 548 | sparc64_boot_end: | 550 | 1: |
| 549 | .skip 0x2000 + _start - sparc64_boot_end | 551 | .skip 0x4000 + _start - 1b |
| 550 | bootup_user_stack_end: | ||
| 551 | .skip 0x2000 | ||
| 552 | 552 | ||
| 553 | #ifdef CONFIG_SBUS | 553 | #ifdef CONFIG_SBUS |
| 554 | /* This is just a hack to fool make depend config.h discovering | 554 | /* This is just a hack to fool make depend config.h discovering |
| @@ -560,15 +560,6 @@ bootup_user_stack_end: | |||
| 560 | ! 0x0000000000408000 | 560 | ! 0x0000000000408000 |
| 561 | 561 | ||
| 562 | #include "ttable.S" | 562 | #include "ttable.S" |
| 563 | #include "systbls.S" | ||
| 564 | #include "ktlb.S" | ||
| 565 | #include "etrap.S" | ||
| 566 | #include "rtrap.S" | ||
| 567 | #include "winfixup.S" | ||
| 568 | #include "entry.S" | ||
| 569 | |||
| 570 | /* This is just anal retentiveness on my part... */ | ||
| 571 | .align 16384 | ||
| 572 | 563 | ||
| 573 | .data | 564 | .data |
| 574 | .align 8 | 565 | .align 8 |
diff --git a/arch/sparc64/kernel/itlb_base.S b/arch/sparc64/kernel/itlb_base.S index b5e32dfa4fbc..4951ff8f6877 100644 --- a/arch/sparc64/kernel/itlb_base.S +++ b/arch/sparc64/kernel/itlb_base.S | |||
| @@ -15,14 +15,12 @@ | |||
| 15 | */ | 15 | */ |
| 16 | #define CREATE_VPTE_OFFSET1(r1, r2) \ | 16 | #define CREATE_VPTE_OFFSET1(r1, r2) \ |
| 17 | srax r1, 10, r2 | 17 | srax r1, 10, r2 |
| 18 | #define CREATE_VPTE_OFFSET2(r1, r2) | 18 | #define CREATE_VPTE_OFFSET2(r1, r2) nop |
| 19 | #define CREATE_VPTE_NOP nop | ||
| 20 | #else /* PAGE_SHIFT */ | 19 | #else /* PAGE_SHIFT */ |
| 21 | #define CREATE_VPTE_OFFSET1(r1, r2) \ | 20 | #define CREATE_VPTE_OFFSET1(r1, r2) \ |
| 22 | srax r1, PAGE_SHIFT, r2 | 21 | srax r1, PAGE_SHIFT, r2 |
| 23 | #define CREATE_VPTE_OFFSET2(r1, r2) \ | 22 | #define CREATE_VPTE_OFFSET2(r1, r2) \ |
| 24 | sllx r2, 3, r2 | 23 | sllx r2, 3, r2 |
| 25 | #define CREATE_VPTE_NOP | ||
| 26 | #endif /* PAGE_SHIFT */ | 24 | #endif /* PAGE_SHIFT */ |
| 27 | 25 | ||
| 28 | 26 | ||
| @@ -36,6 +34,7 @@ | |||
| 36 | */ | 34 | */ |
| 37 | 35 | ||
| 38 | /* ITLB ** ICACHE line 1: Quick user TLB misses */ | 36 | /* ITLB ** ICACHE line 1: Quick user TLB misses */ |
| 37 | mov TLB_SFSR, %g1 | ||
| 39 | ldxa [%g1 + %g1] ASI_IMMU, %g4 ! Get TAG_ACCESS | 38 | ldxa [%g1 + %g1] ASI_IMMU, %g4 ! Get TAG_ACCESS |
| 40 | CREATE_VPTE_OFFSET1(%g4, %g6) ! Create VPTE offset | 39 | CREATE_VPTE_OFFSET1(%g4, %g6) ! Create VPTE offset |
| 41 | CREATE_VPTE_OFFSET2(%g4, %g6) ! Create VPTE offset | 40 | CREATE_VPTE_OFFSET2(%g4, %g6) ! Create VPTE offset |
| @@ -43,41 +42,38 @@ | |||
| 43 | 1: brgez,pn %g5, 3f ! Not valid, branch out | 42 | 1: brgez,pn %g5, 3f ! Not valid, branch out |
| 44 | sethi %hi(_PAGE_EXEC), %g4 ! Delay-slot | 43 | sethi %hi(_PAGE_EXEC), %g4 ! Delay-slot |
| 45 | andcc %g5, %g4, %g0 ! Executable? | 44 | andcc %g5, %g4, %g0 ! Executable? |
| 45 | |||
| 46 | /* ITLB ** ICACHE line 2: Real faults */ | ||
| 46 | be,pn %xcc, 3f ! Nope, branch. | 47 | be,pn %xcc, 3f ! Nope, branch. |
| 47 | nop ! Delay-slot | 48 | nop ! Delay-slot |
| 48 | 2: stxa %g5, [%g0] ASI_ITLB_DATA_IN ! Load PTE into TLB | 49 | 2: stxa %g5, [%g0] ASI_ITLB_DATA_IN ! Load PTE into TLB |
| 49 | retry ! Trap return | 50 | retry ! Trap return |
| 50 | 3: rdpr %pstate, %g4 ! Move into alternate globals | 51 | 3: rdpr %pstate, %g4 ! Move into alt-globals |
| 51 | |||
| 52 | /* ITLB ** ICACHE line 2: Real faults */ | ||
| 53 | wrpr %g4, PSTATE_AG|PSTATE_MG, %pstate | 52 | wrpr %g4, PSTATE_AG|PSTATE_MG, %pstate |
| 54 | rdpr %tpc, %g5 ! And load faulting VA | 53 | rdpr %tpc, %g5 ! And load faulting VA |
| 55 | mov FAULT_CODE_ITLB, %g4 ! It was read from ITLB | 54 | mov FAULT_CODE_ITLB, %g4 ! It was read from ITLB |
| 56 | sparc64_realfault_common: ! Called by TL0 dtlb_miss too | 55 | |
| 56 | /* ITLB ** ICACHE line 3: Finish faults */ | ||
| 57 | sparc64_realfault_common: ! Called by dtlb_miss | ||
| 57 | stb %g4, [%g6 + TI_FAULT_CODE] | 58 | stb %g4, [%g6 + TI_FAULT_CODE] |
| 58 | stx %g5, [%g6 + TI_FAULT_ADDR] | 59 | stx %g5, [%g6 + TI_FAULT_ADDR] |
| 59 | ba,pt %xcc, etrap ! Save state | 60 | ba,pt %xcc, etrap ! Save state |
| 60 | 1: rd %pc, %g7 ! ... | 61 | 1: rd %pc, %g7 ! ... |
| 61 | nop | ||
| 62 | |||
| 63 | /* ITLB ** ICACHE line 3: Finish faults + window fixups */ | ||
| 64 | call do_sparc64_fault ! Call fault handler | 62 | call do_sparc64_fault ! Call fault handler |
| 65 | add %sp, PTREGS_OFF, %o0! Compute pt_regs arg | 63 | add %sp, PTREGS_OFF, %o0! Compute pt_regs arg |
| 66 | ba,pt %xcc, rtrap_clr_l6 ! Restore cpu state | 64 | ba,pt %xcc, rtrap_clr_l6 ! Restore cpu state |
| 67 | nop | 65 | nop |
| 66 | |||
| 67 | /* ITLB ** ICACHE line 4: Window fixups */ | ||
| 68 | winfix_trampoline: | 68 | winfix_trampoline: |
| 69 | rdpr %tpc, %g3 ! Prepare winfixup TNPC | 69 | rdpr %tpc, %g3 ! Prepare winfixup TNPC |
| 70 | or %g3, 0x7c, %g3 ! Compute offset to branch | 70 | or %g3, 0x7c, %g3 ! Compute branch offset |
| 71 | wrpr %g3, %tnpc ! Write it into TNPC | 71 | wrpr %g3, %tnpc ! Write it into TNPC |
| 72 | done ! Do it to it | 72 | done ! Do it to it |
| 73 | |||
| 74 | /* ITLB ** ICACHE line 4: Unused... */ | ||
| 75 | nop | 73 | nop |
| 76 | nop | 74 | nop |
| 77 | nop | 75 | nop |
| 78 | nop | 76 | nop |
| 79 | CREATE_VPTE_NOP | ||
| 80 | 77 | ||
| 81 | #undef CREATE_VPTE_OFFSET1 | 78 | #undef CREATE_VPTE_OFFSET1 |
| 82 | #undef CREATE_VPTE_OFFSET2 | 79 | #undef CREATE_VPTE_OFFSET2 |
| 83 | #undef CREATE_VPTE_NOP | ||
diff --git a/arch/sparc64/kernel/ktlb.S b/arch/sparc64/kernel/ktlb.S index 7796b37f478c..d9244d3c9f73 100644 --- a/arch/sparc64/kernel/ktlb.S +++ b/arch/sparc64/kernel/ktlb.S | |||
| @@ -58,9 +58,6 @@ vpte_noent: | |||
| 58 | done | 58 | done |
| 59 | 59 | ||
| 60 | vpte_insn_obp: | 60 | vpte_insn_obp: |
| 61 | sethi %hi(prom_pmd_phys), %g5 | ||
| 62 | ldx [%g5 + %lo(prom_pmd_phys)], %g5 | ||
| 63 | |||
| 64 | /* Behave as if we are at TL0. */ | 61 | /* Behave as if we are at TL0. */ |
| 65 | wrpr %g0, 1, %tl | 62 | wrpr %g0, 1, %tl |
| 66 | rdpr %tpc, %g4 /* Find original faulting iaddr */ | 63 | rdpr %tpc, %g4 /* Find original faulting iaddr */ |
| @@ -71,58 +68,57 @@ vpte_insn_obp: | |||
| 71 | mov TLB_SFSR, %g1 | 68 | mov TLB_SFSR, %g1 |
| 72 | stxa %g4, [%g1 + %g1] ASI_IMMU | 69 | stxa %g4, [%g1 + %g1] ASI_IMMU |
| 73 | 70 | ||
| 74 | /* Get PMD offset. */ | 71 | sethi %hi(prom_trans), %g5 |
| 75 | srlx %g4, 23, %g6 | 72 | or %g5, %lo(prom_trans), %g5 |
| 76 | and %g6, 0x7ff, %g6 | 73 | |
| 77 | sllx %g6, 2, %g6 | 74 | 1: ldx [%g5 + 0x00], %g6 ! base |
| 78 | 75 | brz,a,pn %g6, longpath ! no more entries, fail | |
| 79 | /* Load PMD, is it valid? */ | 76 | mov TLB_SFSR, %g1 ! and restore %g1 |
| 80 | lduwa [%g5 + %g6] ASI_PHYS_USE_EC, %g5 | 77 | ldx [%g5 + 0x08], %g1 ! len |
| 81 | brz,pn %g5, longpath | 78 | add %g6, %g1, %g1 ! end |
| 82 | sllx %g5, 11, %g5 | 79 | cmp %g6, %g4 |
| 83 | 80 | bgu,pt %xcc, 2f | |
| 84 | /* Get PTE offset. */ | 81 | cmp %g4, %g1 |
| 85 | srlx %g4, 13, %g6 | 82 | bgeu,pt %xcc, 2f |
| 86 | and %g6, 0x3ff, %g6 | 83 | ldx [%g5 + 0x10], %g1 ! PTE |
| 87 | sllx %g6, 3, %g6 | 84 | |
| 88 | 85 | /* TLB load, restore %g1, and return from trap. */ | |
| 89 | /* Load PTE. */ | 86 | sub %g4, %g6, %g6 |
| 90 | ldxa [%g5 + %g6] ASI_PHYS_USE_EC, %g5 | 87 | add %g1, %g6, %g5 |
| 91 | brgez,pn %g5, longpath | 88 | mov TLB_SFSR, %g1 |
| 92 | nop | ||
| 93 | |||
| 94 | /* TLB load and return from trap. */ | ||
| 95 | stxa %g5, [%g0] ASI_ITLB_DATA_IN | 89 | stxa %g5, [%g0] ASI_ITLB_DATA_IN |
| 96 | retry | 90 | retry |
| 97 | 91 | ||
| 98 | kvmap_do_obp: | 92 | 2: ba,pt %xcc, 1b |
| 99 | sethi %hi(prom_pmd_phys), %g5 | 93 | add %g5, (3 * 8), %g5 ! next entry |
| 100 | ldx [%g5 + %lo(prom_pmd_phys)], %g5 | ||
| 101 | |||
| 102 | /* Get PMD offset. */ | ||
| 103 | srlx %g4, 23, %g6 | ||
| 104 | and %g6, 0x7ff, %g6 | ||
| 105 | sllx %g6, 2, %g6 | ||
| 106 | |||
| 107 | /* Load PMD, is it valid? */ | ||
| 108 | lduwa [%g5 + %g6] ASI_PHYS_USE_EC, %g5 | ||
| 109 | brz,pn %g5, longpath | ||
| 110 | sllx %g5, 11, %g5 | ||
| 111 | |||
| 112 | /* Get PTE offset. */ | ||
| 113 | srlx %g4, 13, %g6 | ||
| 114 | and %g6, 0x3ff, %g6 | ||
| 115 | sllx %g6, 3, %g6 | ||
| 116 | |||
| 117 | /* Load PTE. */ | ||
| 118 | ldxa [%g5 + %g6] ASI_PHYS_USE_EC, %g5 | ||
| 119 | brgez,pn %g5, longpath | ||
| 120 | nop | ||
| 121 | 94 | ||
| 122 | /* TLB load and return from trap. */ | 95 | kvmap_do_obp: |
| 96 | sethi %hi(prom_trans), %g5 | ||
| 97 | or %g5, %lo(prom_trans), %g5 | ||
| 98 | srlx %g4, 13, %g4 | ||
| 99 | sllx %g4, 13, %g4 | ||
| 100 | |||
| 101 | 1: ldx [%g5 + 0x00], %g6 ! base | ||
| 102 | brz,a,pn %g6, longpath ! no more entries, fail | ||
| 103 | mov TLB_SFSR, %g1 ! and restore %g1 | ||
| 104 | ldx [%g5 + 0x08], %g1 ! len | ||
| 105 | add %g6, %g1, %g1 ! end | ||
| 106 | cmp %g6, %g4 | ||
| 107 | bgu,pt %xcc, 2f | ||
| 108 | cmp %g4, %g1 | ||
| 109 | bgeu,pt %xcc, 2f | ||
| 110 | ldx [%g5 + 0x10], %g1 ! PTE | ||
| 111 | |||
| 112 | /* TLB load, restore %g1, and return from trap. */ | ||
| 113 | sub %g4, %g6, %g6 | ||
| 114 | add %g1, %g6, %g5 | ||
| 115 | mov TLB_SFSR, %g1 | ||
| 123 | stxa %g5, [%g0] ASI_DTLB_DATA_IN | 116 | stxa %g5, [%g0] ASI_DTLB_DATA_IN |
| 124 | retry | 117 | retry |
| 125 | 118 | ||
| 119 | 2: ba,pt %xcc, 1b | ||
| 120 | add %g5, (3 * 8), %g5 ! next entry | ||
| 121 | |||
| 126 | /* | 122 | /* |
| 127 | * On a first level data miss, check whether this is to the OBP range (note | 123 | * On a first level data miss, check whether this is to the OBP range (note |
| 128 | * that such accesses can be made by prom, as well as by kernel using | 124 | * that such accesses can be made by prom, as well as by kernel using |
diff --git a/arch/sparc64/mm/init.c b/arch/sparc64/mm/init.c index 0d2e967c7200..1e44ee26cee8 100644 --- a/arch/sparc64/mm/init.c +++ b/arch/sparc64/mm/init.c | |||
| @@ -105,7 +105,7 @@ static void __init read_obp_memory(const char *property, | |||
| 105 | regs[i].phys_addr = base; | 105 | regs[i].phys_addr = base; |
| 106 | regs[i].reg_size = size; | 106 | regs[i].reg_size = size; |
| 107 | } | 107 | } |
| 108 | sort(regs, ents, sizeof(struct linux_prom64_registers), | 108 | sort(regs, ents, sizeof(struct linux_prom64_registers), |
| 109 | cmp_p64, NULL); | 109 | cmp_p64, NULL); |
| 110 | } | 110 | } |
| 111 | 111 | ||
| @@ -367,8 +367,11 @@ struct linux_prom_translation { | |||
| 367 | unsigned long size; | 367 | unsigned long size; |
| 368 | unsigned long data; | 368 | unsigned long data; |
| 369 | }; | 369 | }; |
| 370 | static struct linux_prom_translation prom_trans[512] __initdata; | 370 | |
| 371 | static unsigned int prom_trans_ents __initdata; | 371 | /* Exported for kernel TLB miss handling in ktlb.S */ |
| 372 | struct linux_prom_translation prom_trans[512] __read_mostly; | ||
| 373 | unsigned int prom_trans_ents __read_mostly; | ||
| 374 | unsigned int swapper_pgd_zero __read_mostly; | ||
| 372 | 375 | ||
| 373 | extern unsigned long prom_boot_page; | 376 | extern unsigned long prom_boot_page; |
| 374 | extern void prom_remap(unsigned long physpage, unsigned long virtpage, int mmu_ihandle); | 377 | extern void prom_remap(unsigned long physpage, unsigned long virtpage, int mmu_ihandle); |
| @@ -378,122 +381,57 @@ extern void register_prom_callbacks(void); | |||
| 378 | /* Exported for SMP bootup purposes. */ | 381 | /* Exported for SMP bootup purposes. */ |
| 379 | unsigned long kern_locked_tte_data; | 382 | unsigned long kern_locked_tte_data; |
| 380 | 383 | ||
| 381 | /* Exported for kernel TLB miss handling in ktlb.S */ | ||
| 382 | unsigned long prom_pmd_phys __read_mostly; | ||
| 383 | unsigned int swapper_pgd_zero __read_mostly; | ||
| 384 | |||
| 385 | static pmd_t *prompmd __read_mostly; | ||
| 386 | |||
| 387 | #define BASE_PAGE_SIZE 8192 | ||
| 388 | |||
| 389 | /* | 384 | /* |
| 390 | * Translate PROM's mapping we capture at boot time into physical address. | 385 | * Translate PROM's mapping we capture at boot time into physical address. |
| 391 | * The second parameter is only set from prom_callback() invocations. | 386 | * The second parameter is only set from prom_callback() invocations. |
| 392 | */ | 387 | */ |
| 393 | unsigned long prom_virt_to_phys(unsigned long promva, int *error) | 388 | unsigned long prom_virt_to_phys(unsigned long promva, int *error) |
| 394 | { | 389 | { |
| 395 | pmd_t *pmdp = prompmd + ((promva >> 23) & 0x7ff); | 390 | int i; |
| 396 | pte_t *ptep; | ||
| 397 | unsigned long base; | ||
| 398 | |||
| 399 | if (pmd_none(*pmdp)) { | ||
| 400 | if (error) | ||
| 401 | *error = 1; | ||
| 402 | return 0; | ||
| 403 | } | ||
| 404 | ptep = (pte_t *)__pmd_page(*pmdp) + ((promva >> 13) & 0x3ff); | ||
| 405 | if (!pte_present(*ptep)) { | ||
| 406 | if (error) | ||
| 407 | *error = 1; | ||
| 408 | return 0; | ||
| 409 | } | ||
| 410 | if (error) { | ||
| 411 | *error = 0; | ||
| 412 | return pte_val(*ptep); | ||
| 413 | } | ||
| 414 | base = pte_val(*ptep) & _PAGE_PADDR; | ||
| 415 | |||
| 416 | return base + (promva & (BASE_PAGE_SIZE - 1)); | ||
| 417 | } | ||
| 418 | 391 | ||
| 419 | /* The obp translations are saved based on 8k pagesize, since obp can | 392 | for (i = 0; i < prom_trans_ents; i++) { |
| 420 | * use a mixture of pagesizes. Misses to the LOW_OBP_ADDRESS -> | 393 | struct linux_prom_translation *p = &prom_trans[i]; |
| 421 | * HI_OBP_ADDRESS range are handled in entry.S and do not use the vpte | ||
| 422 | * scheme (also, see rant in inherit_locked_prom_mappings()). | ||
| 423 | */ | ||
| 424 | static void __init build_obp_range(unsigned long start, unsigned long end, unsigned long data) | ||
| 425 | { | ||
| 426 | unsigned long vaddr; | ||
| 427 | 394 | ||
| 428 | for (vaddr = start; vaddr < end; vaddr += BASE_PAGE_SIZE) { | 395 | if (promva >= p->virt && |
| 429 | unsigned long val; | 396 | promva < (p->virt + p->size)) { |
| 430 | pmd_t *pmd; | 397 | unsigned long base = p->data & _PAGE_PADDR; |
| 431 | pte_t *pte; | ||
| 432 | 398 | ||
| 433 | pmd = prompmd + ((vaddr >> 23) & 0x7ff); | 399 | if (error) |
| 434 | if (pmd_none(*pmd)) { | 400 | *error = 0; |
| 435 | pte = __alloc_bootmem(BASE_PAGE_SIZE, BASE_PAGE_SIZE, | 401 | return base + (promva & (8192 - 1)); |
| 436 | PAGE_SIZE); | ||
| 437 | if (!pte) | ||
| 438 | prom_halt(); | ||
| 439 | memset(pte, 0, BASE_PAGE_SIZE); | ||
| 440 | pmd_set(pmd, pte); | ||
| 441 | } | 402 | } |
| 442 | pte = (pte_t *) __pmd_page(*pmd) + ((vaddr >> 13) & 0x3ff); | ||
| 443 | |||
| 444 | val = data; | ||
| 445 | |||
| 446 | /* Clear diag TTE bits. */ | ||
| 447 | if (tlb_type == spitfire) | ||
| 448 | val &= ~0x0003fe0000000000UL; | ||
| 449 | |||
| 450 | set_pte_at(&init_mm, vaddr, pte, | ||
| 451 | __pte(val | _PAGE_MODIFIED)); | ||
| 452 | |||
| 453 | data += BASE_PAGE_SIZE; | ||
| 454 | } | 403 | } |
| 404 | if (error) | ||
| 405 | *error = 1; | ||
| 406 | return 0UL; | ||
| 455 | } | 407 | } |
| 456 | 408 | ||
| 409 | /* The obp translations are saved based on 8k pagesize, since obp can | ||
| 410 | * use a mixture of pagesizes. Misses to the LOW_OBP_ADDRESS -> | ||
| 411 | * HI_OBP_ADDRESS range are handled in ktlb.S and do not use the vpte | ||
| 412 | * scheme (also, see rant in inherit_locked_prom_mappings()). | ||
| 413 | */ | ||
| 457 | static inline int in_obp_range(unsigned long vaddr) | 414 | static inline int in_obp_range(unsigned long vaddr) |
| 458 | { | 415 | { |
| 459 | return (vaddr >= LOW_OBP_ADDRESS && | 416 | return (vaddr >= LOW_OBP_ADDRESS && |
| 460 | vaddr < HI_OBP_ADDRESS); | 417 | vaddr < HI_OBP_ADDRESS); |
| 461 | } | 418 | } |
| 462 | 419 | ||
| 463 | #define OBP_PMD_SIZE 2048 | 420 | static int cmp_ptrans(const void *a, const void *b) |
| 464 | static void __init build_obp_pgtable(void) | ||
| 465 | { | 421 | { |
| 466 | unsigned long i; | 422 | const struct linux_prom_translation *x = a, *y = b; |
| 467 | |||
| 468 | prompmd = __alloc_bootmem(OBP_PMD_SIZE, OBP_PMD_SIZE, PAGE_SIZE); | ||
| 469 | if (!prompmd) | ||
| 470 | prom_halt(); | ||
| 471 | |||
| 472 | memset(prompmd, 0, OBP_PMD_SIZE); | ||
| 473 | |||
| 474 | prom_pmd_phys = __pa(prompmd); | ||
| 475 | |||
| 476 | for (i = 0; i < prom_trans_ents; i++) { | ||
| 477 | unsigned long start, end; | ||
| 478 | |||
| 479 | if (!in_obp_range(prom_trans[i].virt)) | ||
| 480 | continue; | ||
| 481 | 423 | ||
| 482 | start = prom_trans[i].virt; | 424 | if (x->virt > y->virt) |
| 483 | end = start + prom_trans[i].size; | 425 | return 1; |
| 484 | if (end > HI_OBP_ADDRESS) | 426 | if (x->virt < y->virt) |
| 485 | end = HI_OBP_ADDRESS; | 427 | return -1; |
| 486 | 428 | return 0; | |
| 487 | build_obp_range(start, end, prom_trans[i].data); | ||
| 488 | } | ||
| 489 | } | 429 | } |
| 490 | 430 | ||
| 491 | /* Read OBP translations property into 'prom_trans[]'. | 431 | /* Read OBP translations property into 'prom_trans[]'. */ |
| 492 | * Return the number of entries. | ||
| 493 | */ | ||
| 494 | static void __init read_obp_translations(void) | 432 | static void __init read_obp_translations(void) |
| 495 | { | 433 | { |
| 496 | int n, node; | 434 | int n, node, ents, first, last, i; |
| 497 | 435 | ||
| 498 | node = prom_finddevice("/virtual-memory"); | 436 | node = prom_finddevice("/virtual-memory"); |
| 499 | n = prom_getproplen(node, "translations"); | 437 | n = prom_getproplen(node, "translations"); |
| @@ -515,7 +453,41 @@ static void __init read_obp_translations(void) | |||
| 515 | 453 | ||
| 516 | n = n / sizeof(struct linux_prom_translation); | 454 | n = n / sizeof(struct linux_prom_translation); |
| 517 | 455 | ||
| 518 | prom_trans_ents = n; | 456 | ents = n; |
| 457 | |||
| 458 | sort(prom_trans, ents, sizeof(struct linux_prom_translation), | ||
| 459 | cmp_ptrans, NULL); | ||
| 460 | |||
| 461 | /* Now kick out all the non-OBP entries. */ | ||
| 462 | for (i = 0; i < ents; i++) { | ||
| 463 | if (in_obp_range(prom_trans[i].virt)) | ||
| 464 | break; | ||
| 465 | } | ||
| 466 | first = i; | ||
| 467 | for (; i < ents; i++) { | ||
| 468 | if (!in_obp_range(prom_trans[i].virt)) | ||
| 469 | break; | ||
| 470 | } | ||
| 471 | last = i; | ||
| 472 | |||
| 473 | for (i = 0; i < (last - first); i++) { | ||
| 474 | struct linux_prom_translation *src = &prom_trans[i + first]; | ||
| 475 | struct linux_prom_translation *dest = &prom_trans[i]; | ||
| 476 | |||
| 477 | *dest = *src; | ||
| 478 | } | ||
| 479 | for (; i < ents; i++) { | ||
| 480 | struct linux_prom_translation *dest = &prom_trans[i]; | ||
| 481 | dest->virt = dest->size = dest->data = 0x0UL; | ||
| 482 | } | ||
| 483 | |||
| 484 | prom_trans_ents = last - first; | ||
| 485 | |||
| 486 | if (tlb_type == spitfire) { | ||
| 487 | /* Clear diag TTE bits. */ | ||
| 488 | for (i = 0; i < prom_trans_ents; i++) | ||
| 489 | prom_trans[i].data &= ~0x0003fe0000000000UL; | ||
| 490 | } | ||
| 519 | } | 491 | } |
| 520 | 492 | ||
| 521 | static void __init remap_kernel(void) | 493 | static void __init remap_kernel(void) |
| @@ -553,21 +525,18 @@ static void __init remap_kernel(void) | |||
| 553 | } | 525 | } |
| 554 | 526 | ||
| 555 | 527 | ||
| 556 | static void __init inherit_prom_mappings_pre(void) | 528 | static void __init inherit_prom_mappings(void) |
| 557 | { | 529 | { |
| 558 | read_obp_translations(); | 530 | read_obp_translations(); |
| 559 | 531 | ||
| 560 | /* Now fixup OBP's idea about where we really are mapped. */ | 532 | /* Now fixup OBP's idea about where we really are mapped. */ |
| 561 | prom_printf("Remapping the kernel... "); | 533 | prom_printf("Remapping the kernel... "); |
| 562 | remap_kernel(); | 534 | remap_kernel(); |
| 563 | |||
| 564 | prom_printf("done.\n"); | 535 | prom_printf("done.\n"); |
| 565 | } | ||
| 566 | 536 | ||
| 567 | static void __init inherit_prom_mappings_post(void) | 537 | prom_printf("Registering callbacks... "); |
| 568 | { | ||
| 569 | build_obp_pgtable(); | ||
| 570 | register_prom_callbacks(); | 538 | register_prom_callbacks(); |
| 539 | prom_printf("done.\n"); | ||
| 571 | } | 540 | } |
| 572 | 541 | ||
| 573 | /* The OBP specifications for sun4u mark 0xfffffffc00000000 and | 542 | /* The OBP specifications for sun4u mark 0xfffffffc00000000 and |
| @@ -1519,7 +1488,7 @@ void __init paging_init(void) | |||
| 1519 | 1488 | ||
| 1520 | swapper_pgd_zero = pgd_val(swapper_pg_dir[0]); | 1489 | swapper_pgd_zero = pgd_val(swapper_pg_dir[0]); |
| 1521 | 1490 | ||
| 1522 | inherit_prom_mappings_pre(); | 1491 | inherit_prom_mappings(); |
| 1523 | 1492 | ||
| 1524 | /* Ok, we can use our TLB miss and window trap handlers safely. | 1493 | /* Ok, we can use our TLB miss and window trap handlers safely. |
| 1525 | * We need to do a quick peek here to see if we are on StarFire | 1494 | * We need to do a quick peek here to see if we are on StarFire |
| @@ -1530,23 +1499,15 @@ void __init paging_init(void) | |||
| 1530 | extern void setup_tba(int); | 1499 | extern void setup_tba(int); |
| 1531 | setup_tba(this_is_starfire); | 1500 | setup_tba(this_is_starfire); |
| 1532 | } | 1501 | } |
| 1533 | __flush_tlb_all(); | ||
| 1534 | 1502 | ||
| 1535 | /* Everything from this point forward, until we are done with | 1503 | inherit_locked_prom_mappings(1); |
| 1536 | * inherit_prom_mappings_post(), must complete successfully | 1504 | |
| 1537 | * without calling into the firmware. The firwmare page tables | 1505 | __flush_tlb_all(); |
| 1538 | * have not been built, but we are running on the Linux kernel's | ||
| 1539 | * trap table. | ||
| 1540 | */ | ||
| 1541 | 1506 | ||
| 1542 | /* Setup bootmem... */ | 1507 | /* Setup bootmem... */ |
| 1543 | pages_avail = 0; | 1508 | pages_avail = 0; |
| 1544 | last_valid_pfn = end_pfn = bootmem_init(&pages_avail); | 1509 | last_valid_pfn = end_pfn = bootmem_init(&pages_avail); |
| 1545 | 1510 | ||
| 1546 | inherit_prom_mappings_post(); | ||
| 1547 | |||
| 1548 | inherit_locked_prom_mappings(1); | ||
| 1549 | |||
| 1550 | #ifdef CONFIG_DEBUG_PAGEALLOC | 1511 | #ifdef CONFIG_DEBUG_PAGEALLOC |
| 1551 | kernel_physical_mapping_init(); | 1512 | kernel_physical_mapping_init(); |
| 1552 | #endif | 1513 | #endif |
