Commit b327e1b3 authored by Paul Mackerras's avatar Paul Mackerras

PPC32: Use non-pinned large-page TLB entries for kernel RAM mapping.

parent f348ef4e
...@@ -555,33 +555,40 @@ label: ...@@ -555,33 +555,40 @@ label:
4: 4:
tophys(r11, r11) tophys(r11, r11)
rlwimi r11, r10, 12, 20, 29 /* Create L1 (pgdir/pmd) address */ rlwimi r11, r10, 12, 20, 29 /* Create L1 (pgdir/pmd) address */
lwz r11, 0(r11) /* Get L1 entry */ lwz r12, 0(r11) /* Get L1 entry */
rlwinm. r12, r11, 0, 0, 19 /* Extract L2 (pte) base address */ andi. r9, r12, _PMD_PRESENT /* Check if it points to a PTE page */
beq 2f /* Bail if no table */ beq 2f /* Bail if no table */
rlwimi r12, r10, 22, 20, 29 /* Compute PTE address */ rlwimi r12, r10, 22, 20, 29 /* Compute PTE address */
lwz r11, 0(r12) /* Get Linux PTE */ lwz r11, 0(r12) /* Get Linux PTE */
andi. r9, r11, _PAGE_PRESENT andi. r9, r11, _PAGE_PRESENT
beq 2f beq 5f
ori r11, r11, _PAGE_ACCESSED ori r11, r11, _PAGE_ACCESSED
stw r11, 0(r12) stw r11, 0(r12)
/* Most of the Linux PTE is ready to load into the TLB LO. /* Create TLB tag. This is the faulting address plus a static
* We set ZSEL, where only the LS-bit determines user access. * set of bits. These are size, valid, E, U0.
* We set execute, because we don't have the granularity to
* properly set this at the page level (Linux problem).
* If shared is set, we cause a zero PID->TID load.
* Many of these bits are software only. Bits we don't set
* here we (properly should) assume have the appropriate value.
*/ */
li r12, 0x0ce2 li r12, 0x00c0
andc r11, r11, r12 /* Make sure 20, 21 are zero */ rlwimi r10, r12, 0, 20, 31
b finish_tlb_load b finish_tlb_load
2: /* Check for possible large-page pmd entry */
rlwinm. r9, r12, 2, 22, 24
beq 5f
2: /* Create TLB tag. This is the faulting address, plus a static
* set of bits (valid, E, U0) plus the size from the PMD.
*/
ori r9, r9, 0x40
rlwimi r10, r9, 0, 20, 31
mr r11, r12
b finish_tlb_load
5:
/* The bailout. Restore registers to pre-exception conditions /* The bailout. Restore registers to pre-exception conditions
* and call the heavyweights to help us out. * and call the heavyweights to help us out.
*/ */
...@@ -647,55 +654,40 @@ label: ...@@ -647,55 +654,40 @@ label:
4: 4:
tophys(r11, r11) tophys(r11, r11)
rlwimi r11, r10, 12, 20, 29 /* Create L1 (pgdir/pmd) address */ rlwimi r11, r10, 12, 20, 29 /* Create L1 (pgdir/pmd) address */
lwz r11, 0(r11) /* Get L1 entry */ lwz r12, 0(r11) /* Get L1 entry */
rlwinm. r12, r11, 0, 0, 19 /* Extract L2 (pte) base address */ andi. r9, r12, _PMD_PRESENT /* Check if it points to a PTE page */
beq 2f /* Bail if no table */ beq 2f /* Bail if no table */
rlwimi r12, r10, 22, 20, 29 /* Compute PTE address */ rlwimi r12, r10, 22, 20, 29 /* Compute PTE address */
lwz r11, 0(r12) /* Get Linux PTE */ lwz r11, 0(r12) /* Get Linux PTE */
andi. r9, r11, _PAGE_PRESENT andi. r9, r11, _PAGE_PRESENT
beq 2f beq 5f
ori r11, r11, _PAGE_ACCESSED ori r11, r11, _PAGE_ACCESSED
stw r11, 0(r12) stw r11, 0(r12)
/* Most of the Linux PTE is ready to load into the TLB LO. /* Create TLB tag. This is the faulting address plus a static
* We set ZSEL, where only the LS-bit determines user access. * set of bits. These are size, valid, E, U0.
* We set execute, because we don't have the granularity to
* properly set this at the page level (Linux problem).
* If shared is set, we cause a zero PID->TID load.
* Many of these bits are software only. Bits we don't set
* here we (properly should) assume have the appropriate value.
*/ */
li r12, 0x0ce2 li r12, 0x00c0
andc r11, r11, r12 /* Make sure 20, 21 are zero */ rlwimi r10, r12, 0, 20, 31
b finish_tlb_load b finish_tlb_load
/* Done...restore registers and get out of here. 2: /* Check for possible large-page pmd entry */
rlwinm. r9, r12, 2, 22, 24
beq 5f
/* Create TLB tag. This is the faulting address, plus a static
* set of bits (valid, E, U0) plus the size from the PMD.
*/ */
#ifdef CONFIG_403GCX ori r9, r9, 0x40
lwz r12, 12(r0) rlwimi r10, r9, 0, 20, 31
lwz r11, 8(r0) mr r11, r12
mtspr SPRN_PID, r12
mtcr r11
lwz r9, 4(r0)
lwz r12, 0(r0)
#else
mfspr r12, SPRG6
mfspr r11, SPRG7
mtspr SPRN_PID, r12
mtcr r11
mfspr r9, SPRG5
mfspr r12, SPRG4
#endif
mfspr r11, SPRG1
mfspr r10, SPRG0
PPC405_ERR77_SYNC
rfi /* Should sync shadow TLBs */
b . /* prevent prefetch past rfi */
2: b finish_tlb_load
5:
/* The bailout. Restore registers to pre-exception conditions /* The bailout. Restore registers to pre-exception conditions
* and call the heavyweights to help us out. * and call the heavyweights to help us out.
*/ */
...@@ -818,8 +810,8 @@ check_single_step_in_exception: ...@@ -818,8 +810,8 @@ check_single_step_in_exception:
/* Damn, I came up one instruction too many to fit into the /* Damn, I came up one instruction too many to fit into the
* exception space :-). Both the instruction and data TLB * exception space :-). Both the instruction and data TLB
* miss get to this point to load the TLB. * miss get to this point to load the TLB.
* r10 - EA of fault * r10 - TLB_TAG value
* r11 - TLB LO (info from Linux PTE) * r11 - Linux PTE
* r12, r9 - avilable to use * r12, r9 - avilable to use
* PID - loaded with proper value when we get here * PID - loaded with proper value when we get here
* Upon exit, we reload everything and RFI. * Upon exit, we reload everything and RFI.
...@@ -833,21 +825,19 @@ finish_tlb_load: ...@@ -833,21 +825,19 @@ finish_tlb_load:
*/ */
lwz r9, tlb_4xx_index@l(0) lwz r9, tlb_4xx_index@l(0)
addi r9, r9, 1 addi r9, r9, 1
cmpwi 0, r9, 61 /* reserve entries 62, 63 for kernel */ andi. r9, r9, (PPC4XX_TLB_SIZE-1)
ble 7f
li r9, 0
7:
stw r9, tlb_4xx_index@l(0) stw r9, tlb_4xx_index@l(0)
6: 6:
tlbwe r11, r9, TLB_DATA /* Load TLB LO */ /*
* Clear out the software-only bits in the PTE to generate the
/* Create EPN. This is the faulting address plus a static * TLB_DATA value. These are the bottom 2 bits of the RPM, the
* set of bits. These are size, valid, E, U0, and ensure * top 3 bits of the zone field, and M.
* bits 20 and 21 are zero.
*/ */
li r12, 0x00c0 li r12, 0x0ce2
rlwimi r10, r12, 0, 20, 31 andc r11, r11, r12
tlbwe r11, r9, TLB_DATA /* Load TLB LO */
tlbwe r10, r9, TLB_TAG /* Load TLB HI */ tlbwe r10, r9, TLB_TAG /* Load TLB HI */
/* Done...restore registers and get out of here. /* Done...restore registers and get out of here.
...@@ -929,7 +919,9 @@ start_here: ...@@ -929,7 +919,9 @@ start_here:
/* Load up the kernel context */ /* Load up the kernel context */
2: 2:
SYNC /* Force all PTE updates to finish */ sync /* Flush to memory before changing TLB */
tlbia
isync /* Flush shadow TLBs */
/* set up the PTE pointers for the Abatron bdiGDB. /* set up the PTE pointers for the Abatron bdiGDB.
*/ */
...@@ -956,7 +948,7 @@ start_here: ...@@ -956,7 +948,7 @@ start_here:
*/ */
initial_mmu: initial_mmu:
tlbia /* Invalidate all TLB entries */ tlbia /* Invalidate all TLB entries */
sync isync
/* We should still be executing code at physical address 0x0000xxxx /* We should still be executing code at physical address 0x0000xxxx
* at this point. However, start_here is at virtual address * at this point. However, start_here is at virtual address
...@@ -985,18 +977,30 @@ initial_mmu: ...@@ -985,18 +977,30 @@ initial_mmu:
clrrwi r3,r3,10 /* Mask off the effective page number */ clrrwi r3,r3,10 /* Mask off the effective page number */
ori r3,r3,(TLB_VALID | TLB_PAGESZ(PAGESZ_16M)) ori r3,r3,(TLB_VALID | TLB_PAGESZ(PAGESZ_16M))
li r0,62 /* TLB slot 62 */ li r0,63 /* TLB slot 63 */
tlbwe r4,r0,TLB_DATA /* Load the data portion of the entry */ tlbwe r4,r0,TLB_DATA /* Load the data portion of the entry */
tlbwe r3,r0,TLB_TAG /* Load the tag portion of the entry */ tlbwe r3,r0,TLB_TAG /* Load the tag portion of the entry */
addis r4, r4, 0x0100 /* Map next 16 M entries */ #if defined(CONFIG_SERIAL_TEXT_DEBUG) && defined(SERIAL_DEBUG_IO_BASE)
addis r3, r3, 0x0100
li r0,63 /* TLB slot 63 */ /* Load a TLB entry for the UART, so that ppc4xx_progress() can use
* the UARTs nice and early. We use a 4k real==virtual mapping. */
lis r3,SERIAL_DEBUG_IO_BASE@h
ori r3,r3,SERIAL_DEBUG_IO_BASE@l
mr r4,r3
clrrwi r4,r4,12
ori r4,r4,(TLB_WR|TLB_I|TLB_M|TLB_G)
clrrwi r3,r3,12
ori r3,r3,(TLB_VALID | TLB_PAGESZ(PAGESZ_4K))
li r0,0 /* TLB slot 0 */
tlbwe r4,r0,TLB_DATA tlbwe r4,r0,TLB_DATA
tlbwe r3,r0,TLB_TAG tlbwe r3,r0,TLB_TAG
#endif /* CONFIG_SERIAL_DEBUG_TEXT && SERIAL_DEBUG_IO_BASE */
isync isync
/* Establish the exception vector base /* Establish the exception vector base
......
...@@ -348,18 +348,9 @@ _GLOBAL(_nmask_and_or_msr) ...@@ -348,18 +348,9 @@ _GLOBAL(_nmask_and_or_msr)
*/ */
_GLOBAL(_tlbia) _GLOBAL(_tlbia)
#if defined(CONFIG_40x) #if defined(CONFIG_40x)
/* This needs to be coordinated with other pinning functions since sync /* Flush to memory before changing mapping */
* we don't keep a memory location of number of entries to reduce tlbia
* cache pollution during these operations. isync /* Flush shadow TLB */
*/
lis r3, 0
sync
1:
tlbwe r3, r3, TLB_TAG /* just ensure V is clear */
addi r3, r3, 1 /* so r3 works fine for that */
cmpwi 0, r3, 61 /* reserve last two entries */
ble 1b
isync
#else /* ! defined(CONFIG_40x) */ #else /* ! defined(CONFIG_40x) */
#if defined(CONFIG_SMP) #if defined(CONFIG_SMP)
rlwinm r8,r1,0,0,18 rlwinm r8,r1,0,0,18
......
...@@ -50,6 +50,7 @@ ...@@ -50,6 +50,7 @@
#include <asm/bootx.h> #include <asm/bootx.h>
#include <asm/machdep.h> #include <asm/machdep.h>
#include <asm/setup.h> #include <asm/setup.h>
#include "mmu_decl.h"
/* /*
* MMU_init_hw does the chip-specific initialization of the MMU hardware. * MMU_init_hw does the chip-specific initialization of the MMU hardware.
...@@ -88,3 +89,49 @@ void __init MMU_init_hw(void) ...@@ -88,3 +89,49 @@ void __init MMU_init_hw(void)
mtspr(SPRN_DCCR, 0xF0000000); /* 512 MB of data space at 0x0. */ mtspr(SPRN_DCCR, 0xF0000000); /* 512 MB of data space at 0x0. */
mtspr(SPRN_ICCR, 0xF0000000); /* 512 MB of instr. space at 0x0. */ mtspr(SPRN_ICCR, 0xF0000000); /* 512 MB of instr. space at 0x0. */
} }
#define LARGE_PAGE_SIZE_16M (1<<24)
#define LARGE_PAGE_SIZE_4M (1<<22)
unsigned long __init mmu_mapin_ram(void)
{
unsigned long v, s;
phys_addr_t p;
v = KERNELBASE;
p = PPC_MEMSTART;
s = 0;
while (s <= (total_lowmem - LARGE_PAGE_SIZE_16M)) {
pmd_t *pmdp;
unsigned long val = p | _PMD_SIZE_16M | _PAGE_HWEXEC | _PAGE_HWWRITE;
spin_lock(&init_mm.page_table_lock);
pmdp = pmd_offset(pgd_offset_k(v), v);
pmd_val(*pmdp++) = val;
pmd_val(*pmdp++) = val;
pmd_val(*pmdp++) = val;
pmd_val(*pmdp++) = val;
spin_unlock(&init_mm.page_table_lock);
v += LARGE_PAGE_SIZE_16M;
p += LARGE_PAGE_SIZE_16M;
s += LARGE_PAGE_SIZE_16M;
}
while (s <= (total_lowmem - LARGE_PAGE_SIZE_4M)) {
pmd_t *pmdp;
unsigned long val = p | _PMD_SIZE_4M | _PAGE_HWEXEC | _PAGE_HWWRITE;
spin_lock(&init_mm.page_table_lock);
pmdp = pmd_offset(pgd_offset_k(v), v);
pmd_val(*pmdp) = val;
spin_unlock(&init_mm.page_table_lock);
v += LARGE_PAGE_SIZE_4M;
p += LARGE_PAGE_SIZE_4M;
s += LARGE_PAGE_SIZE_4M;
}
return s;
}
...@@ -50,7 +50,7 @@ extern unsigned long Hash_size, Hash_mask; ...@@ -50,7 +50,7 @@ extern unsigned long Hash_size, Hash_mask;
#elif defined(CONFIG_4xx) #elif defined(CONFIG_4xx)
#define flush_HPTE(X, va, pg) _tlbie(va) #define flush_HPTE(X, va, pg) _tlbie(va)
extern void MMU_init_hw(void); extern void MMU_init_hw(void);
#define mmu_mapin_ram() (0UL) extern unsigned long mmu_mapin_ram(void);
#else #else
/* anything except 4xx or 8xx */ /* anything except 4xx or 8xx */
......
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