diff options
author | Paul Mackerras <paulus@samba.org> | 2006-06-14 20:45:18 -0400 |
---|---|---|
committer | Paul Mackerras <paulus@samba.org> | 2006-06-14 20:45:18 -0400 |
commit | bf72aeba2ffef599d1d386425c9e46b82be657cd (patch) | |
tree | ead8e5111dbcfa22e156999d1bb8a96e50f06fef /arch/powerpc/mm/hash_low_64.S | |
parent | 31925323b1b51bb65db729e029472a8b1f635b7d (diff) |
powerpc: Use 64k pages without needing cache-inhibited large pages
Some POWER5+ machines can do 64k hardware pages for normal memory but
not for cache-inhibited pages. This patch lets us use 64k hardware
pages for most user processes on such machines (assuming the kernel
has been configured with CONFIG_PPC_64K_PAGES=y). User processes
start out using 64k pages and get switched to 4k pages if they use any
non-cacheable mappings.
With this, we use 64k pages for the vmalloc region and 4k pages for
the imalloc region. If anything creates a non-cacheable mapping in
the vmalloc region, the vmalloc region will get switched to 4k pages.
I don't know of any driver other than the DRM that would do this,
though, and these machines don't have AGP.
When a region gets switched from 64k pages to 4k pages, we do not have
to clear out all the 64k HPTEs from the hash table immediately. We
use the _PAGE_COMBO bit in the Linux PTE to indicate whether the page
was hashed in as a 64k page or a set of 4k pages. If hash_page is
trying to insert a 4k page for a Linux PTE and it sees that it has
already been inserted as a 64k page, it first invalidates the 64k HPTE
before inserting the 4k HPTE. The hash invalidation routines also use
the _PAGE_COMBO bit, to determine whether to look for a 64k HPTE or a
set of 4k HPTEs to remove. With those two changes, we can tolerate a
mix of 4k and 64k HPTEs in the hash table, and they will all get
removed when the address space is torn down.
Signed-off-by: Paul Mackerras <paulus@samba.org>
Diffstat (limited to 'arch/powerpc/mm/hash_low_64.S')
-rw-r--r-- | arch/powerpc/mm/hash_low_64.S | 28 |
1 files changed, 28 insertions, 0 deletions
diff --git a/arch/powerpc/mm/hash_low_64.S b/arch/powerpc/mm/hash_low_64.S index 106fba391987..52e914238959 100644 --- a/arch/powerpc/mm/hash_low_64.S +++ b/arch/powerpc/mm/hash_low_64.S | |||
@@ -369,6 +369,7 @@ _GLOBAL(__hash_page_4K) | |||
369 | rlwinm r30,r4,32-9+7,31-7,31-7 /* _PAGE_RW -> _PAGE_DIRTY */ | 369 | rlwinm r30,r4,32-9+7,31-7,31-7 /* _PAGE_RW -> _PAGE_DIRTY */ |
370 | or r30,r30,r31 | 370 | or r30,r30,r31 |
371 | ori r30,r30,_PAGE_BUSY | _PAGE_ACCESSED | _PAGE_HASHPTE | 371 | ori r30,r30,_PAGE_BUSY | _PAGE_ACCESSED | _PAGE_HASHPTE |
372 | oris r30,r30,_PAGE_COMBO@h | ||
372 | /* Write the linux PTE atomically (setting busy) */ | 373 | /* Write the linux PTE atomically (setting busy) */ |
373 | stdcx. r30,0,r6 | 374 | stdcx. r30,0,r6 |
374 | bne- 1b | 375 | bne- 1b |
@@ -428,6 +429,14 @@ END_FTR_SECTION(CPU_FTR_NOEXECUTE|CPU_FTR_COHERENT_ICACHE, CPU_FTR_NOEXECUTE) | |||
428 | andi. r0,r31,_PAGE_HASHPTE | 429 | andi. r0,r31,_PAGE_HASHPTE |
429 | li r26,0 /* Default hidx */ | 430 | li r26,0 /* Default hidx */ |
430 | beq htab_insert_pte | 431 | beq htab_insert_pte |
432 | |||
433 | /* | ||
434 | * Check if the pte was already inserted into the hash table | ||
435 | * as a 64k HW page, and invalidate the 64k HPTE if so. | ||
436 | */ | ||
437 | andis. r0,r31,_PAGE_COMBO@h | ||
438 | beq htab_inval_old_hpte | ||
439 | |||
431 | ld r6,STK_PARM(r6)(r1) | 440 | ld r6,STK_PARM(r6)(r1) |
432 | ori r26,r6,0x8000 /* Load the hidx mask */ | 441 | ori r26,r6,0x8000 /* Load the hidx mask */ |
433 | ld r26,0(r26) | 442 | ld r26,0(r26) |
@@ -498,6 +507,19 @@ _GLOBAL(htab_call_hpte_remove) | |||
498 | /* Try all again */ | 507 | /* Try all again */ |
499 | b htab_insert_pte | 508 | b htab_insert_pte |
500 | 509 | ||
510 | /* | ||
511 | * Call out to C code to invalidate an 64k HW HPTE that is | ||
512 | * useless now that the segment has been switched to 4k pages. | ||
513 | */ | ||
514 | htab_inval_old_hpte: | ||
515 | mr r3,r29 /* virtual addr */ | ||
516 | mr r4,r31 /* PTE.pte */ | ||
517 | li r5,0 /* PTE.hidx */ | ||
518 | li r6,MMU_PAGE_64K /* psize */ | ||
519 | ld r7,STK_PARM(r8)(r1) /* local */ | ||
520 | bl .flush_hash_page | ||
521 | b htab_insert_pte | ||
522 | |||
501 | htab_bail_ok: | 523 | htab_bail_ok: |
502 | li r3,0 | 524 | li r3,0 |
503 | b htab_bail | 525 | b htab_bail |
@@ -638,6 +660,12 @@ _GLOBAL(__hash_page_64K) | |||
638 | * is changing this PTE anyway and might hash it. | 660 | * is changing this PTE anyway and might hash it. |
639 | */ | 661 | */ |
640 | bne- ht64_bail_ok | 662 | bne- ht64_bail_ok |
663 | BEGIN_FTR_SECTION | ||
664 | /* Check if PTE has the cache-inhibit bit set */ | ||
665 | andi. r0,r31,_PAGE_NO_CACHE | ||
666 | /* If so, bail out and refault as a 4k page */ | ||
667 | bne- ht64_bail_ok | ||
668 | END_FTR_SECTION_IFCLR(CPU_FTR_CI_LARGE_PAGE) | ||
641 | /* Prepare new PTE value (turn access RW into DIRTY, then | 669 | /* Prepare new PTE value (turn access RW into DIRTY, then |
642 | * add BUSY,HASHPTE and ACCESSED) | 670 | * add BUSY,HASHPTE and ACCESSED) |
643 | */ | 671 | */ |