aboutsummaryrefslogtreecommitdiffstats
path: root/arch/powerpc/mm
diff options
context:
space:
mode:
authorBenjamin Herrenschmidt <benh@kernel.crashing.org>2007-04-12 01:30:22 -0400
committerPaul Mackerras <paulus@samba.org>2007-04-12 14:09:39 -0400
commitee4f2ea48674b6c9d91bc854edc51a3e6a7168c4 (patch)
tree098c91278dd3c2cff10350c6e7bde835fb657405 /arch/powerpc/mm
parent3be4e6990edf65624cfcbf8f7e33810626b2eefa (diff)
[POWERPC] Fix 32-bit mm operations when not using BATs
On hash table based 32 bits powerpc's, the hash management code runs with a big spinlock. It's thus important that it never causes itself a hash fault. That code is generally safe (it does memory accesses in real mode among other things) with the exception of the actual access to the code itself. That is, the kernel text needs to be accessible without taking a hash miss exceptions. This is currently guaranteed by having a BAT register mapping part of the linear mapping permanently, which includes the kernel text. But this is not true if using the "nobats" kernel command line option (which can be useful for debugging) and will not be true when using DEBUG_PAGEALLOC implemented in a subsequent patch. This patch fixes this by pre-faulting in the hash table pages that hit the kernel text, and making sure we never evict such a page under hash pressure. Signed-off-by: Benjamin Herrenchmidt <benh@kernel.crashing.org> arch/powerpc/mm/hash_low_32.S | 22 ++++++++++++++++++++-- arch/powerpc/mm/mem.c | 3 --- arch/powerpc/mm/mmu_decl.h | 4 ++++ arch/powerpc/mm/pgtable_32.c | 11 +++++++---- 4 files changed, 31 insertions(+), 9 deletions(-) Signed-off-by: Paul Mackerras <paulus@samba.org>
Diffstat (limited to 'arch/powerpc/mm')
-rw-r--r--arch/powerpc/mm/hash_low_32.S22
-rw-r--r--arch/powerpc/mm/mem.c3
-rw-r--r--arch/powerpc/mm/mmu_decl.h4
-rw-r--r--arch/powerpc/mm/pgtable_32.c11
4 files changed, 31 insertions, 9 deletions
diff --git a/arch/powerpc/mm/hash_low_32.S b/arch/powerpc/mm/hash_low_32.S
index bd68df5fa78a..ddceefc06ecc 100644
--- a/arch/powerpc/mm/hash_low_32.S
+++ b/arch/powerpc/mm/hash_low_32.S
@@ -283,6 +283,7 @@ Hash_msk = (((1 << Hash_bits) - 1) * 64)
283#define PTEG_SIZE 64 283#define PTEG_SIZE 64
284#define LG_PTEG_SIZE 6 284#define LG_PTEG_SIZE 6
285#define LDPTEu lwzu 285#define LDPTEu lwzu
286#define LDPTE lwz
286#define STPTE stw 287#define STPTE stw
287#define CMPPTE cmpw 288#define CMPPTE cmpw
288#define PTE_H 0x40 289#define PTE_H 0x40
@@ -389,13 +390,30 @@ _GLOBAL(hash_page_patch_C)
389 * and we know there is a definite (although small) speed 390 * and we know there is a definite (although small) speed
390 * advantage to putting the PTE in the primary PTEG, we always 391 * advantage to putting the PTE in the primary PTEG, we always
391 * put the PTE in the primary PTEG. 392 * put the PTE in the primary PTEG.
393 *
394 * In addition, we skip any slot that is mapping kernel text in
395 * order to avoid a deadlock when not using BAT mappings if
396 * trying to hash in the kernel hash code itself after it has
397 * already taken the hash table lock. This works in conjunction
398 * with pre-faulting of the kernel text.
399 *
400 * If the hash table bucket is full of kernel text entries, we'll
401 * lockup here but that shouldn't happen
392 */ 402 */
393 addis r4,r7,next_slot@ha 403
4041: addis r4,r7,next_slot@ha /* get next evict slot */
394 lwz r6,next_slot@l(r4) 405 lwz r6,next_slot@l(r4)
395 addi r6,r6,PTE_SIZE 406 addi r6,r6,PTE_SIZE /* search for candidate */
396 andi. r6,r6,7*PTE_SIZE 407 andi. r6,r6,7*PTE_SIZE
397 stw r6,next_slot@l(r4) 408 stw r6,next_slot@l(r4)
398 add r4,r3,r6 409 add r4,r3,r6
410 LDPTE r0,PTE_SIZE/2(r4) /* get PTE second word */
411 clrrwi r0,r0,12
412 lis r6,etext@h
413 ori r6,r6,etext@l /* get etext */
414 tophys(r6,r6)
415 cmpl cr0,r0,r6 /* compare and try again */
416 blt 1b
399 417
400#ifndef CONFIG_SMP 418#ifndef CONFIG_SMP
401 /* Store PTE in PTEG */ 419 /* Store PTE in PTEG */
diff --git a/arch/powerpc/mm/mem.c b/arch/powerpc/mm/mem.c
index 52f397c108a7..c4bcd7546424 100644
--- a/arch/powerpc/mm/mem.c
+++ b/arch/powerpc/mm/mem.c
@@ -58,9 +58,6 @@ int init_bootmem_done;
58int mem_init_done; 58int mem_init_done;
59unsigned long memory_limit; 59unsigned long memory_limit;
60 60
61extern void hash_preload(struct mm_struct *mm, unsigned long ea,
62 unsigned long access, unsigned long trap);
63
64int page_is_ram(unsigned long pfn) 61int page_is_ram(unsigned long pfn)
65{ 62{
66 unsigned long paddr = (pfn << PAGE_SHIFT); 63 unsigned long paddr = (pfn << PAGE_SHIFT);
diff --git a/arch/powerpc/mm/mmu_decl.h b/arch/powerpc/mm/mmu_decl.h
index bea2d21ac6f7..ee55e0bb28bc 100644
--- a/arch/powerpc/mm/mmu_decl.h
+++ b/arch/powerpc/mm/mmu_decl.h
@@ -22,6 +22,10 @@
22#include <asm/tlbflush.h> 22#include <asm/tlbflush.h>
23#include <asm/mmu.h> 23#include <asm/mmu.h>
24 24
25extern void hash_preload(struct mm_struct *mm, unsigned long ea,
26 unsigned long access, unsigned long trap);
27
28
25#ifdef CONFIG_PPC32 29#ifdef CONFIG_PPC32
26extern void mapin_ram(void); 30extern void mapin_ram(void);
27extern int map_page(unsigned long va, phys_addr_t pa, int flags); 31extern int map_page(unsigned long va, phys_addr_t pa, int flags);
diff --git a/arch/powerpc/mm/pgtable_32.c b/arch/powerpc/mm/pgtable_32.c
index 95d3afe36b51..f75f2fc7bc7e 100644
--- a/arch/powerpc/mm/pgtable_32.c
+++ b/arch/powerpc/mm/pgtable_32.c
@@ -282,16 +282,19 @@ int map_page(unsigned long va, phys_addr_t pa, int flags)
282void __init mapin_ram(void) 282void __init mapin_ram(void)
283{ 283{
284 unsigned long v, p, s, f; 284 unsigned long v, p, s, f;
285 int ktext;
285 286
286 s = mmu_mapin_ram(); 287 s = mmu_mapin_ram();
287 v = KERNELBASE + s; 288 v = KERNELBASE + s;
288 p = PPC_MEMSTART + s; 289 p = PPC_MEMSTART + s;
289 for (; s < total_lowmem; s += PAGE_SIZE) { 290 for (; s < total_lowmem; s += PAGE_SIZE) {
290 if ((char *) v >= _stext && (char *) v < etext) 291 ktext = ((char *) v >= _stext && (char *) v < etext);
291 f = _PAGE_RAM_TEXT; 292 f = ktext ?_PAGE_RAM_TEXT : _PAGE_RAM;
292 else
293 f = _PAGE_RAM;
294 map_page(v, p, f); 293 map_page(v, p, f);
294#ifdef CONFIG_PPC_STD_MMU_32
295 if (ktext)
296 hash_preload(&init_mm, v, 0, 0x300);
297#endif
295 v += PAGE_SIZE; 298 v += PAGE_SIZE;
296 p += PAGE_SIZE; 299 p += PAGE_SIZE;
297 } 300 }