Commit ca9153a3 authored by Ilya Yanok's avatar Ilya Yanok Committed by Paul Mackerras

powerpc/44x: Support 16K/64K base page sizes on 44x

This adds support for 16k and 64k page sizes on PowerPC 44x processors.

The PGDIR table is much smaller than a page when using 16k or 64k
pages (512 and 32 bytes respectively) so we allocate the PGDIR with
kzalloc() instead of __get_free_pages().

One PTE table covers rather a large memory area when using 16k or 64k
pages (32MB or 512MB respectively), so we can easily put FIXMAP and
PKMAP in the area covered by one PTE table.
Signed-off-by: default avatarYuri Tikhonov <yur@emcraft.com>
Signed-off-by: default avatarVladimir Panfilov <pvr@emcraft.com>
Signed-off-by: default avatarIlya Yanok <yanok@emcraft.com>
Acked-by: default avatarJosh Boyer <jwboyer@linux.vnet.ibm.com>
Signed-off-by: default avatarPaul Mackerras <paulus@samba.org>
parent 6ca4f749
...@@ -405,23 +405,53 @@ config PPC_HAS_HASH_64K ...@@ -405,23 +405,53 @@ config PPC_HAS_HASH_64K
depends on PPC64 depends on PPC64
default n default n
config PPC_64K_PAGES choice
bool "64k page size" prompt "Page size"
depends on PPC64 default PPC_4K_PAGES
select PPC_HAS_HASH_64K
help help
This option changes the kernel logical page size to 64k. On machines Select the kernel logical page size. Increasing the page size
without processor support for 64k pages, the kernel will simulate will reduce software overhead at each page boundary, allow
them by loading each individual 4k page on demand transparently, hardware prefetch mechanisms to be more effective, and allow
while on hardware with such support, it will be used to map larger dma transfers increasing IO efficiency and reducing
normal application pages. overhead. However the utilization of memory will increase.
For example, each cached file will using a multiple of the
page size to hold its contents and the difference between the
end of file and the end of page is wasted.
Some dedicated systems, such as software raid serving with
accelerated calculations, have shown significant increases.
If you configure a 64 bit kernel for 64k pages but the
processor does not support them, then the kernel will simulate
them with 4k pages, loading them on demand, but with the
reduced software overhead and larger internal fragmentation.
For the 32 bit kernel, a large page option will not be offered
unless it is supported by the configured processor.
If unsure, choose 4K_PAGES.
config PPC_4K_PAGES
bool "4k page size"
config PPC_16K_PAGES
bool "16k page size" if 44x
config PPC_64K_PAGES
bool "64k page size" if 44x || PPC_STD_MMU_64
select PPC_HAS_HASH_64K if PPC_STD_MMU_64
endchoice
config FORCE_MAX_ZONEORDER config FORCE_MAX_ZONEORDER
int "Maximum zone order" int "Maximum zone order"
range 9 64 if PPC_64K_PAGES range 9 64 if PPC_STD_MMU_64 && PPC_64K_PAGES
default "9" if PPC_64K_PAGES default "9" if PPC_STD_MMU_64 && PPC_64K_PAGES
range 13 64 if PPC64 && !PPC_64K_PAGES range 13 64 if PPC_STD_MMU_64 && !PPC_64K_PAGES
default "13" if PPC64 && !PPC_64K_PAGES default "13" if PPC_STD_MMU_64 && !PPC_64K_PAGES
range 9 64 if PPC_STD_MMU_32 && PPC_16K_PAGES
default "9" if PPC_STD_MMU_32 && PPC_16K_PAGES
range 7 64 if PPC_STD_MMU_32 && PPC_64K_PAGES
default "7" if PPC_STD_MMU_32 && PPC_64K_PAGES
range 11 64 range 11 64
default "11" default "11"
help help
...@@ -441,7 +471,7 @@ config FORCE_MAX_ZONEORDER ...@@ -441,7 +471,7 @@ config FORCE_MAX_ZONEORDER
config PPC_SUBPAGE_PROT config PPC_SUBPAGE_PROT
bool "Support setting protections for 4k subpages" bool "Support setting protections for 4k subpages"
depends on PPC_64K_PAGES depends on PPC_STD_MMU_64 && PPC_64K_PAGES
help help
This option adds support for a system call to allow user programs This option adds support for a system call to allow user programs
to set access permissions (read/write, readonly, or no access) to set access permissions (read/write, readonly, or no access)
......
...@@ -38,9 +38,24 @@ extern pte_t *pkmap_page_table; ...@@ -38,9 +38,24 @@ extern pte_t *pkmap_page_table;
* easily, subsequent pte tables have to be allocated in one physical * easily, subsequent pte tables have to be allocated in one physical
* chunk of RAM. * chunk of RAM.
*/ */
#define LAST_PKMAP (1 << PTE_SHIFT) /*
#define LAST_PKMAP_MASK (LAST_PKMAP-1) * We use one full pte table with 4K pages. And with 16K/64K pages pte
* table covers enough memory (32MB and 512MB resp.) that both FIXMAP
* and PKMAP can be placed in single pte table. We use 1024 pages for
* PKMAP in case of 16K/64K pages.
*/
#ifdef CONFIG_PPC_4K_PAGES
#define PKMAP_ORDER PTE_SHIFT
#else
#define PKMAP_ORDER 10
#endif
#define LAST_PKMAP (1 << PKMAP_ORDER)
#ifndef CONFIG_PPC_4K_PAGES
#define PKMAP_BASE (FIXADDR_START - PAGE_SIZE*(LAST_PKMAP + 1))
#else
#define PKMAP_BASE ((FIXADDR_START - PAGE_SIZE*(LAST_PKMAP + 1)) & PMD_MASK) #define PKMAP_BASE ((FIXADDR_START - PAGE_SIZE*(LAST_PKMAP + 1)) & PMD_MASK)
#endif
#define LAST_PKMAP_MASK (LAST_PKMAP-1)
#define PKMAP_NR(virt) ((virt-PKMAP_BASE) >> PAGE_SHIFT) #define PKMAP_NR(virt) ((virt-PKMAP_BASE) >> PAGE_SHIFT)
#define PKMAP_ADDR(nr) (PKMAP_BASE + ((nr) << PAGE_SHIFT)) #define PKMAP_ADDR(nr) (PKMAP_BASE + ((nr) << PAGE_SHIFT))
......
...@@ -4,6 +4,8 @@ ...@@ -4,6 +4,8 @@
* PPC440 support * PPC440 support
*/ */
#include <asm/page.h>
#define PPC44x_MMUCR_TID 0x000000ff #define PPC44x_MMUCR_TID 0x000000ff
#define PPC44x_MMUCR_STS 0x00010000 #define PPC44x_MMUCR_STS 0x00010000
...@@ -74,4 +76,19 @@ typedef struct { ...@@ -74,4 +76,19 @@ typedef struct {
/* Size of the TLBs used for pinning in lowmem */ /* Size of the TLBs used for pinning in lowmem */
#define PPC_PIN_SIZE (1 << 28) /* 256M */ #define PPC_PIN_SIZE (1 << 28) /* 256M */
#if (PAGE_SHIFT == 12)
#define PPC44x_TLBE_SIZE PPC44x_TLB_4K
#elif (PAGE_SHIFT == 14)
#define PPC44x_TLBE_SIZE PPC44x_TLB_16K
#elif (PAGE_SHIFT == 16)
#define PPC44x_TLBE_SIZE PPC44x_TLB_64K
#else
#error "Unsupported PAGE_SIZE"
#endif
#define PPC44x_PGD_OFF_SHIFT (32 - PGDIR_SHIFT + PGD_T_LOG2)
#define PPC44x_PGD_OFF_MASK_BIT (PGDIR_SHIFT - PGD_T_LOG2)
#define PPC44x_PTE_ADD_SHIFT (32 - PGDIR_SHIFT + PTE_SHIFT + PTE_T_LOG2)
#define PPC44x_PTE_ADD_MASK_BIT (32 - PTE_T_LOG2 - PTE_SHIFT)
#endif /* _ASM_POWERPC_MMU_44X_H_ */ #endif /* _ASM_POWERPC_MMU_44X_H_ */
...@@ -19,12 +19,15 @@ ...@@ -19,12 +19,15 @@
#include <asm/kdump.h> #include <asm/kdump.h>
/* /*
* On PPC32 page size is 4K. For PPC64 we support either 4K or 64K software * On regular PPC32 page size is 4K (but we support 4K/16K/64K pages
* on PPC44x). For PPC64 we support either 4K or 64K software
* page size. When using 64K pages however, whether we are really supporting * page size. When using 64K pages however, whether we are really supporting
* 64K pages in HW or not is irrelevant to those definitions. * 64K pages in HW or not is irrelevant to those definitions.
*/ */
#ifdef CONFIG_PPC_64K_PAGES #if defined(CONFIG_PPC_64K_PAGES)
#define PAGE_SHIFT 16 #define PAGE_SHIFT 16
#elif defined(CONFIG_PPC_16K_PAGES)
#define PAGE_SHIFT 14
#else #else
#define PAGE_SHIFT 12 #define PAGE_SHIFT 12
#endif #endif
...@@ -151,7 +154,7 @@ typedef struct { pte_basic_t pte; } pte_t; ...@@ -151,7 +154,7 @@ typedef struct { pte_basic_t pte; } pte_t;
/* 64k pages additionally define a bigger "real PTE" type that gathers /* 64k pages additionally define a bigger "real PTE" type that gathers
* the "second half" part of the PTE for pseudo 64k pages * the "second half" part of the PTE for pseudo 64k pages
*/ */
#ifdef CONFIG_PPC_64K_PAGES #if defined(CONFIG_PPC_64K_PAGES) && defined(CONFIG_PPC_STD_MMU_64)
typedef struct { pte_t pte; unsigned long hidx; } real_pte_t; typedef struct { pte_t pte; unsigned long hidx; } real_pte_t;
#else #else
typedef struct { pte_t pte; } real_pte_t; typedef struct { pte_t pte; } real_pte_t;
...@@ -191,10 +194,10 @@ typedef pte_basic_t pte_t; ...@@ -191,10 +194,10 @@ typedef pte_basic_t pte_t;
#define pte_val(x) (x) #define pte_val(x) (x)
#define __pte(x) (x) #define __pte(x) (x)
#ifdef CONFIG_PPC_64K_PAGES #if defined(CONFIG_PPC_64K_PAGES) && defined(CONFIG_PPC_STD_MMU_64)
typedef struct { pte_t pte; unsigned long hidx; } real_pte_t; typedef struct { pte_t pte; unsigned long hidx; } real_pte_t;
#else #else
typedef unsigned long real_pte_t; typedef pte_t real_pte_t;
#endif #endif
......
...@@ -19,6 +19,8 @@ ...@@ -19,6 +19,8 @@
#define PTE_FLAGS_OFFSET 0 #define PTE_FLAGS_OFFSET 0
#endif #endif
#define PTE_SHIFT (PAGE_SHIFT - PTE_T_LOG2) /* full page */
#ifndef __ASSEMBLY__ #ifndef __ASSEMBLY__
/* /*
* The basic type of a PTE - 64 bits for those CPUs with > 32 bit * The basic type of a PTE - 64 bits for those CPUs with > 32 bit
...@@ -26,10 +28,8 @@ ...@@ -26,10 +28,8 @@
*/ */
#ifdef CONFIG_PTE_64BIT #ifdef CONFIG_PTE_64BIT
typedef unsigned long long pte_basic_t; typedef unsigned long long pte_basic_t;
#define PTE_SHIFT (PAGE_SHIFT - 3) /* 512 ptes per page */
#else #else
typedef unsigned long pte_basic_t; typedef unsigned long pte_basic_t;
#define PTE_SHIFT (PAGE_SHIFT - 2) /* 1024 ptes per page */
#endif #endif
struct page; struct page;
...@@ -39,6 +39,9 @@ extern void copy_page(void *to, void *from); ...@@ -39,6 +39,9 @@ extern void copy_page(void *to, void *from);
#include <asm-generic/page.h> #include <asm-generic/page.h>
#define PGD_T_LOG2 (__builtin_ffs(sizeof(pgd_t)) - 1)
#define PTE_T_LOG2 (__builtin_ffs(sizeof(pte_t)) - 1)
#endif /* __ASSEMBLY__ */ #endif /* __ASSEMBLY__ */
#endif /* _ASM_POWERPC_PAGE_32_H */ #endif /* _ASM_POWERPC_PAGE_32_H */
...@@ -380,6 +380,10 @@ int main(void) ...@@ -380,6 +380,10 @@ int main(void)
DEFINE(VCPU_FAULT_DEAR, offsetof(struct kvm_vcpu, arch.fault_dear)); DEFINE(VCPU_FAULT_DEAR, offsetof(struct kvm_vcpu, arch.fault_dear));
DEFINE(VCPU_FAULT_ESR, offsetof(struct kvm_vcpu, arch.fault_esr)); DEFINE(VCPU_FAULT_ESR, offsetof(struct kvm_vcpu, arch.fault_esr));
#endif #endif
#ifdef CONFIG_44x
DEFINE(PGD_T_LOG2, PGD_T_LOG2);
DEFINE(PTE_T_LOG2, PTE_T_LOG2);
#endif
return 0; return 0;
} }
...@@ -402,12 +402,14 @@ interrupt_base: ...@@ -402,12 +402,14 @@ interrupt_base:
rlwimi r13,r12,10,30,30 rlwimi r13,r12,10,30,30
/* Load the PTE */ /* Load the PTE */
rlwinm r12, r10, 13, 19, 29 /* Compute pgdir/pmd offset */ /* Compute pgdir/pmd offset */
rlwinm r12, r10, PPC44x_PGD_OFF_SHIFT, PPC44x_PGD_OFF_MASK_BIT, 29
lwzx r11, r12, r11 /* Get pgd/pmd entry */ lwzx r11, r12, r11 /* Get pgd/pmd entry */
rlwinm. r12, r11, 0, 0, 20 /* Extract pt base address */ rlwinm. r12, r11, 0, 0, 20 /* Extract pt base address */
beq 2f /* Bail if no table */ beq 2f /* Bail if no table */
rlwimi r12, r10, 23, 20, 28 /* Compute pte address */ /* Compute pte address */
rlwimi r12, r10, PPC44x_PTE_ADD_SHIFT, PPC44x_PTE_ADD_MASK_BIT, 28
lwz r11, 0(r12) /* Get high word of pte entry */ lwz r11, 0(r12) /* Get high word of pte entry */
lwz r12, 4(r12) /* Get low word of pte entry */ lwz r12, 4(r12) /* Get low word of pte entry */
...@@ -496,12 +498,14 @@ tlb_44x_patch_hwater_D: ...@@ -496,12 +498,14 @@ tlb_44x_patch_hwater_D:
/* Make up the required permissions */ /* Make up the required permissions */
li r13,_PAGE_PRESENT | _PAGE_ACCESSED | _PAGE_HWEXEC li r13,_PAGE_PRESENT | _PAGE_ACCESSED | _PAGE_HWEXEC
rlwinm r12, r10, 13, 19, 29 /* Compute pgdir/pmd offset */ /* Compute pgdir/pmd offset */
rlwinm r12, r10, PPC44x_PGD_OFF_SHIFT, PPC44x_PGD_OFF_MASK_BIT, 29
lwzx r11, r12, r11 /* Get pgd/pmd entry */ lwzx r11, r12, r11 /* Get pgd/pmd entry */
rlwinm. r12, r11, 0, 0, 20 /* Extract pt base address */ rlwinm. r12, r11, 0, 0, 20 /* Extract pt base address */
beq 2f /* Bail if no table */ beq 2f /* Bail if no table */
rlwimi r12, r10, 23, 20, 28 /* Compute pte address */ /* Compute pte address */
rlwimi r12, r10, PPC44x_PTE_ADD_SHIFT, PPC44x_PTE_ADD_MASK_BIT, 28
lwz r11, 0(r12) /* Get high word of pte entry */ lwz r11, 0(r12) /* Get high word of pte entry */
lwz r12, 4(r12) /* Get low word of pte entry */ lwz r12, 4(r12) /* Get low word of pte entry */
...@@ -565,15 +569,16 @@ tlb_44x_patch_hwater_I: ...@@ -565,15 +569,16 @@ tlb_44x_patch_hwater_I:
*/ */
finish_tlb_load: finish_tlb_load:
/* Combine RPN & ERPN an write WS 0 */ /* Combine RPN & ERPN an write WS 0 */
rlwimi r11,r12,0,0,19 rlwimi r11,r12,0,0,31-PAGE_SHIFT
tlbwe r11,r13,PPC44x_TLB_XLAT tlbwe r11,r13,PPC44x_TLB_XLAT
/* /*
* Create WS1. This is the faulting address (EPN), * Create WS1. This is the faulting address (EPN),
* page size, and valid flag. * page size, and valid flag.
*/ */
li r11,PPC44x_TLB_VALID | PPC44x_TLB_4K li r11,PPC44x_TLB_VALID | PPC44x_TLBE_SIZE
rlwimi r10,r11,0,20,31 /* Insert valid and page size*/ /* Insert valid and page size */
rlwimi r10,r11,0,PPC44x_PTE_ADD_MASK_BIT,31
tlbwe r10,r13,PPC44x_TLB_PAGEID /* Write PAGEID */ tlbwe r10,r13,PPC44x_TLB_PAGEID /* Write PAGEID */
/* And WS 2 */ /* And WS 2 */
...@@ -645,12 +650,12 @@ _GLOBAL(set_context) ...@@ -645,12 +650,12 @@ _GLOBAL(set_context)
* goes at the beginning of the data segment, which is page-aligned. * goes at the beginning of the data segment, which is page-aligned.
*/ */
.data .data
.align 12 .align PAGE_SHIFT
.globl sdata .globl sdata
sdata: sdata:
.globl empty_zero_page .globl empty_zero_page
empty_zero_page: empty_zero_page:
.space 4096 .space PAGE_SIZE
/* /*
* To support >32-bit physical addresses, we use an 8KB pgdir. * To support >32-bit physical addresses, we use an 8KB pgdir.
......
...@@ -426,8 +426,8 @@ _GLOBAL(__flush_dcache_icache) ...@@ -426,8 +426,8 @@ _GLOBAL(__flush_dcache_icache)
BEGIN_FTR_SECTION BEGIN_FTR_SECTION
blr blr
END_FTR_SECTION_IFSET(CPU_FTR_COHERENT_ICACHE) END_FTR_SECTION_IFSET(CPU_FTR_COHERENT_ICACHE)
rlwinm r3,r3,0,0,19 /* Get page base address */ rlwinm r3,r3,0,0,31-PAGE_SHIFT /* Get page base address */
li r4,4096/L1_CACHE_BYTES /* Number of lines in a page */ li r4,PAGE_SIZE/L1_CACHE_BYTES /* Number of lines in a page */
mtctr r4 mtctr r4
mr r6,r3 mr r6,r3
0: dcbst 0,r3 /* Write line to ram */ 0: dcbst 0,r3 /* Write line to ram */
...@@ -467,8 +467,8 @@ END_FTR_SECTION_IFSET(CPU_FTR_COHERENT_ICACHE) ...@@ -467,8 +467,8 @@ END_FTR_SECTION_IFSET(CPU_FTR_COHERENT_ICACHE)
rlwinm r0,r10,0,28,26 /* clear DR */ rlwinm r0,r10,0,28,26 /* clear DR */
mtmsr r0 mtmsr r0
isync isync
rlwinm r3,r3,0,0,19 /* Get page base address */ rlwinm r3,r3,0,0,31-PAGE_SHIFT /* Get page base address */
li r4,4096/L1_CACHE_BYTES /* Number of lines in a page */ li r4,PAGE_SIZE/L1_CACHE_BYTES /* Number of lines in a page */
mtctr r4 mtctr r4
mr r6,r3 mr r6,r3
0: dcbst 0,r3 /* Write line to ram */ 0: dcbst 0,r3 /* Write line to ram */
...@@ -492,7 +492,7 @@ END_FTR_SECTION_IFSET(CPU_FTR_COHERENT_ICACHE) ...@@ -492,7 +492,7 @@ END_FTR_SECTION_IFSET(CPU_FTR_COHERENT_ICACHE)
* void clear_pages(void *page, int order) ; * void clear_pages(void *page, int order) ;
*/ */
_GLOBAL(clear_pages) _GLOBAL(clear_pages)
li r0,4096/L1_CACHE_BYTES li r0,PAGE_SIZE/L1_CACHE_BYTES
slw r0,r0,r4 slw r0,r0,r4
mtctr r0 mtctr r0
#ifdef CONFIG_8xx #ifdef CONFIG_8xx
...@@ -550,7 +550,7 @@ _GLOBAL(copy_page) ...@@ -550,7 +550,7 @@ _GLOBAL(copy_page)
dcbt r5,r4 dcbt r5,r4
li r11,L1_CACHE_BYTES+4 li r11,L1_CACHE_BYTES+4
#endif /* MAX_COPY_PREFETCH */ #endif /* MAX_COPY_PREFETCH */
li r0,4096/L1_CACHE_BYTES - MAX_COPY_PREFETCH li r0,PAGE_SIZE/L1_CACHE_BYTES - MAX_COPY_PREFETCH
crclr 4*cr0+eq crclr 4*cr0+eq
2: 2:
mtctr r0 mtctr r0
......
...@@ -68,24 +68,29 @@ extern unsigned long p_mapped_by_tlbcam(unsigned long pa); ...@@ -68,24 +68,29 @@ extern unsigned long p_mapped_by_tlbcam(unsigned long pa);
#define p_mapped_by_tlbcam(x) (0UL) #define p_mapped_by_tlbcam(x) (0UL)
#endif /* HAVE_TLBCAM */ #endif /* HAVE_TLBCAM */
#ifdef CONFIG_PTE_64BIT #define PGDIR_ORDER (32 + PGD_T_LOG2 - PGDIR_SHIFT)
/* Some processors use an 8kB pgdir because they have 8-byte Linux PTEs. */
#define PGDIR_ORDER 1
#else
#define PGDIR_ORDER 0
#endif
pgd_t *pgd_alloc(struct mm_struct *mm) pgd_t *pgd_alloc(struct mm_struct *mm)
{ {
pgd_t *ret; pgd_t *ret;
ret = (pgd_t *)__get_free_pages(GFP_KERNEL|__GFP_ZERO, PGDIR_ORDER); /* pgdir take page or two with 4K pages and a page fraction otherwise */
#ifndef CONFIG_PPC_4K_PAGES
ret = (pgd_t *)kzalloc(1 << PGDIR_ORDER, GFP_KERNEL);
#else
ret = (pgd_t *)__get_free_pages(GFP_KERNEL|__GFP_ZERO,
PGDIR_ORDER - PAGE_SHIFT);
#endif
return ret; return ret;
} }
void pgd_free(struct mm_struct *mm, pgd_t *pgd) void pgd_free(struct mm_struct *mm, pgd_t *pgd)
{ {
free_pages((unsigned long)pgd, PGDIR_ORDER); #ifndef CONFIG_PPC_4K_PAGES
kfree((void *)pgd);
#else
free_pages((unsigned long)pgd, PGDIR_ORDER - PAGE_SHIFT);
#endif
} }
__init_refok pte_t *pte_alloc_one_kernel(struct mm_struct *mm, unsigned long address) __init_refok pte_t *pte_alloc_one_kernel(struct mm_struct *mm, unsigned long address)
...@@ -385,7 +390,7 @@ void kernel_map_pages(struct page *page, int numpages, int enable) ...@@ -385,7 +390,7 @@ void kernel_map_pages(struct page *page, int numpages, int enable)
#endif /* CONFIG_DEBUG_PAGEALLOC */ #endif /* CONFIG_DEBUG_PAGEALLOC */
static int fixmaps; static int fixmaps;
unsigned long FIXADDR_TOP = 0xfffff000; unsigned long FIXADDR_TOP = (-PAGE_SIZE);
EXPORT_SYMBOL(FIXADDR_TOP); EXPORT_SYMBOL(FIXADDR_TOP);
void __set_fixmap (enum fixed_addresses idx, phys_addr_t phys, pgprot_t flags) void __set_fixmap (enum fixed_addresses idx, phys_addr_t phys, pgprot_t flags)
......
...@@ -212,7 +212,7 @@ config PPC_MMU_NOHASH ...@@ -212,7 +212,7 @@ config PPC_MMU_NOHASH
config PPC_MM_SLICES config PPC_MM_SLICES
bool bool
default y if HUGETLB_PAGE || PPC_64K_PAGES default y if HUGETLB_PAGE || (PPC_STD_MMU_64 && PPC_64K_PAGES)
default n default n
config VIRT_CPU_ACCOUNTING config VIRT_CPU_ACCOUNTING
......
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