Skip to contentSkip to conversation

powerpc: add 16K/64K pages support for the 44x PPC32 architectures.

PATCH In review Ilya Yanok 5 participants 15 messages Nov 27, 2008 – Dec 27, 2008 PowerPC

lore
Share & tools
lore

Ilya Yanok

author
#0 lore raw

PATCH 1/1 powerpc: add 16K/64K pages support for the 44x PPC32 architectures.

This patch adds support for page sizes bigger than 4K (16K/64K) on PPC 44x.
PGDIR table is much smaller than page in case of 16K/64K pages (512 and 32 bytes resp.) so we allocate PGDIR with kzalloc() instead of __get_free_pages().
PTE table covers rather big memory area in case of 16K/64K pages (32MB and 512MB resp.) so we can easily put FIXMAP and PKMAP in area covered by one PTE table.

---
 arch/powerpc/Kconfig                   |   54 ++++++++++++++++++++++++-------
 arch/powerpc/include/asm/highmem.h     |   15 ++++++++-
 arch/powerpc/include/asm/mmu-44x.h     |   18 ++++++++++
 arch/powerpc/include/asm/page.h        |   13 +++++---
 arch/powerpc/include/asm/page_32.h     |    3 +-
 arch/powerpc/include/asm/pgtable.h     |    2 +
 arch/powerpc/kernel/asm-offsets.c      |    4 ++
 arch/powerpc/kernel/head_44x.S         |   22 ++++++++-----
 arch/powerpc/kernel/misc_32.S          |   12 +++---
 arch/powerpc/mm/pgtable_32.c           |   13 ++-----
 arch/powerpc/platforms/Kconfig.cputype |    2 +-
 11 files changed, 112 insertions(+), 46 deletions(-)
arch/powerpc/Kconfig +42 -12
index 525c13a..aa2eb46 100644
@@ -401,23 +401,53 @@ config PPC_HAS_HASH_64K
 	depends on PPC64
 	default n
 
-config PPC_64K_PAGES
-	bool "64k page size"
-	depends on PPC64
-	select PPC_HAS_HASH_64K
+choice
+	prompt "Page size"
+	default PPC_4K_PAGES
 	help
-	  This option changes the kernel logical page size to 64k. On machines
-	  without processor support for 64k pages, the kernel will simulate
-	  them by loading each individual 4k page on demand transparently,
-	  while on hardware with such support, it will be used to map
-	  normal application pages.
+	  Select the kernel logical page size. Increasing the page size
+	  will reduce software overhead at each page boundary, allow
+	  hardware prefetch mechanisms to be more effective, and allow
+	  larger dma transfers increasing IO efficiency and reducing
+	  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 || PPC64
+	select PPC_HAS_HASH_64K if PPC64
+
+endchoice
 
 config FORCE_MAX_ZONEORDER
 	int "Maximum zone order"
-	range 9 64 if PPC_64K_PAGES
-	default "9" if PPC_64K_PAGES
+	range 9 64 if PPC64 && PPC_64K_PAGES
+	default "9" if PPC64 && PPC_64K_PAGES
 	range 13 64 if PPC64 && !PPC_64K_PAGES
 	default "13" if PPC64 && !PPC_64K_PAGES
+	range 9 64 if PPC32 && PPC_16K_PAGES
+	default "9" if PPC32 && PPC_16K_PAGES
+	range 7 64 if PPC32 && PPC_64K_PAGES
+	default "7" if PPC32 && PPC_64K_PAGES
 	range 11 64
 	default "11"
 	help
@@ -437,7 +467,7 @@ config FORCE_MAX_ZONEORDER
 
 config PPC_SUBPAGE_PROT
 	bool "Support setting protections for 4k subpages"
-	depends on PPC_64K_PAGES
+	depends on PPC64 && PPC_64K_PAGES
 	help
 	  This option adds support for a system call to allow user programs
 	  to set access permissions (read/write, readonly, or no access)
arch/powerpc/include/asm/highmem.h +13 -2
index 91c5895..9875540 100644
@@ -38,9 +38,20 @@ extern pte_t *pkmap_page_table;
  * easily, subsequent pte tables have to be allocated in one physical
  * 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.
+ */
+#define PKMAP_ORDER	min(PTE_SHIFT, 10)
+#define LAST_PKMAP	(1 << PKMAP_ORDER)
+#if !defined(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)
+#endif
+#define LAST_PKMAP_MASK	(LAST_PKMAP-1)
 #define PKMAP_NR(virt)  ((virt-PKMAP_BASE) >> PAGE_SHIFT)
 #define PKMAP_ADDR(nr)  (PKMAP_BASE + ((nr) << PAGE_SHIFT))
 
arch/powerpc/include/asm/mmu-44x.h +18 -0
index a825524..89d285d 100644
@@ -4,6 +4,8 @@
  * PPC440 support
  */
 
+#include <asm/page.h>
+
 #define PPC44x_MMUCR_TID	0x000000ff
 #define PPC44x_MMUCR_STS	0x00010000
 
@@ -73,4 +75,20 @@ typedef struct {
 /* Size of the TLBs used for pinning in lowmem */
 #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	(PGDIR_SHIFT - PGD_T_LOG2)
+#define PPC44x_PTE_ADD_SHIFT	(32 - PGDIR_SHIFT + PTE_SHIFT + PTE_T_LOG2)
+#define PPC44x_PTE_ADD_MASK	(32 - PTE_T_LOG2 - PTE_SHIFT)
+#define PPC44x_RPN_MASK		(31 - PAGE_SHIFT)
+
 #endif /* _ASM_POWERPC_MMU_44X_H_ */
arch/powerpc/include/asm/page.h +8 -5
index c0b8d4a..c714881 100644
@@ -19,12 +19,15 @@
 #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
  * 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
+#elif defined(CONFIG_PPC_16K_PAGES)
+#define PAGE_SHIFT		14
 #else
 #define PAGE_SHIFT		12
 #endif
@@ -151,7 +154,7 @@ typedef struct { pte_basic_t pte; } pte_t;
 /* 64k pages additionally define a bigger "real PTE" type that gathers
  * the "second half" part of the PTE for pseudo 64k pages
  */
-#ifdef CONFIG_PPC_64K_PAGES
+#if defined(CONFIG_PPC_64K_PAGES) && defined(CONFIG_PPC64)
 typedef struct { pte_t pte; unsigned long hidx; } real_pte_t;
 #else
 typedef struct { pte_t pte; } real_pte_t;
@@ -191,10 +194,10 @@ typedef pte_basic_t pte_t;
 #define pte_val(x)	(x)
 #define __pte(x)	(x)
 
-#ifdef CONFIG_PPC_64K_PAGES
+#if defined(CONFIG_PPC_64K_PAGES) && defined(CONFIG_PPC64)
 typedef struct { pte_t pte; unsigned long hidx; } real_pte_t;
 #else
-typedef unsigned long real_pte_t;
+typedef pte_t real_pte_t;
 #endif
 
 
arch/powerpc/include/asm/page_32.h +1 -2
index d77072a..74b097b 100644
@@ -19,6 +19,7 @@
 #define PTE_FLAGS_OFFSET	0
 #endif
 
+#define PTE_SHIFT	(PAGE_SHIFT - PTE_T_LOG2)	/* full page */
 #ifndef __ASSEMBLY__
 /*
  * The basic type of a PTE - 64 bits for those CPUs with > 32 bit
@@ -26,10 +27,8 @@
  */
 #ifdef CONFIG_PTE_64BIT
 typedef unsigned long long pte_basic_t;
-#define PTE_SHIFT	(PAGE_SHIFT - 3)	/* 512 ptes per page */
 #else
 typedef unsigned long pte_basic_t;
-#define PTE_SHIFT	(PAGE_SHIFT - 2)	/* 1024 ptes per page */
 #endif
 
 struct page;
arch/powerpc/include/asm/pgtable.h +2 -0
index dbb8ca1..a202043 100644
@@ -39,6 +39,8 @@ extern void paging_init(void);
 
 #include <asm-generic/pgtable.h>
 
+#define PGD_T_LOG2	(__builtin_ffs(sizeof(pgd_t)) - 1)
+#define PTE_T_LOG2	(__builtin_ffs(sizeof(pte_t)) - 1)
 
 /*
  * This gets called at the end of handling a page fault, when
arch/powerpc/kernel/asm-offsets.c +4 -0
index 75c5dd0..0142318 100644
@@ -378,6 +378,10 @@ int main(void)
 	DEFINE(VCPU_FAULT_DEAR, offsetof(struct kvm_vcpu, arch.fault_dear));
 	DEFINE(VCPU_FAULT_ESR, offsetof(struct kvm_vcpu, arch.fault_esr));
 #endif
+#ifdef CONFIG_44x
+	DEFINE(PGD_T_LOG2, PGD_T_LOG2);
+	DEFINE(PTE_T_LOG2, PTE_T_LOG2);
+#endif
 
 	return 0;
 }
arch/powerpc/kernel/head_44x.S +13 -9
index f3a1ea9..6525124 100644
@@ -391,12 +391,14 @@ interrupt_base:
 	rlwimi	r13,r12,10,30,30
 
 	/* 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, 29
 	lwzx	r11, r12, r11		/* Get pgd/pmd entry */
 	rlwinm.	r12, r11, 0, 0, 20	/* Extract pt base address */
 	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, 28
 	lwz	r11, 0(r12)		/* Get high word of pte entry */
 	lwz	r12, 4(r12)		/* Get low word of pte entry */
 
@@ -485,12 +487,14 @@ tlb_44x_patch_hwater_D:
 	/* Make up the required permissions */
 	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, 29
 	lwzx	r11, r12, r11		/* Get pgd/pmd entry */
 	rlwinm.	r12, r11, 0, 0, 20	/* Extract pt base address */
 	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, 28
 	lwz	r11, 0(r12)		/* Get high word of pte entry */
 	lwz	r12, 4(r12)		/* Get low word of pte entry */
 
@@ -554,15 +558,15 @@ tlb_44x_patch_hwater_I:
  */
 finish_tlb_load:
 	/* Combine RPN & ERPN an write WS 0 */
-	rlwimi	r11,r12,0,0,19
+	rlwimi	r11,r12,0,0,PPC44x_RPN_MASK
 	tlbwe	r11,r13,PPC44x_TLB_XLAT
 
 	/*
 	 * Create WS1. This is the faulting address (EPN),
 	 * page size, and valid flag.
 	 */
-	li	r11,PPC44x_TLB_VALID | PPC44x_TLB_4K
-	rlwimi	r10,r11,0,20,31			/* Insert valid and page size*/
+	li	r11,PPC44x_TLB_VALID | PPC44x_TLBE_SIZE
+	rlwimi	r10,r11,0,PPC44x_PTE_ADD_MASK,31/* Insert valid and page size*/
 	tlbwe	r10,r13,PPC44x_TLB_PAGEID	/* Write PAGEID */
 
 	/* And WS 2 */
@@ -634,12 +638,12 @@ _GLOBAL(set_context)
  * goes at the beginning of the data segment, which is page-aligned.
  */
 	.data
-	.align	12
+	.align	PAGE_SHIFT
 	.globl	sdata
 sdata:
 	.globl	empty_zero_page
 empty_zero_page:
-	.space	4096
+	.space	PAGE_SIZE
 
 /*
  * To support >32-bit physical addresses, we use an 8KB pgdir.
arch/powerpc/kernel/misc_32.S +6 -6
index bdc8b0e..42f99d2 100644
@@ -647,8 +647,8 @@ _GLOBAL(__flush_dcache_icache)
 BEGIN_FTR_SECTION
 	blr
 END_FTR_SECTION_IFSET(CPU_FTR_COHERENT_ICACHE)
-	rlwinm	r3,r3,0,0,19			/* Get page base address */
-	li	r4,4096/L1_CACHE_BYTES	/* Number of lines in a page */
+	rlwinm	r3,r3,0,0,PPC44x_RPN_MASK	/* Get page base address */
+	li	r4,PAGE_SIZE/L1_CACHE_BYTES	/* Number of lines in a page */
 	mtctr	r4
 	mr	r6,r3
 0:	dcbst	0,r3				/* Write line to ram */
@@ -688,8 +688,8 @@ END_FTR_SECTION_IFSET(CPU_FTR_COHERENT_ICACHE)
 	rlwinm	r0,r10,0,28,26			/* clear DR */
 	mtmsr	r0
 	isync
-	rlwinm	r3,r3,0,0,19			/* Get page base address */
-	li	r4,4096/L1_CACHE_BYTES	/* Number of lines in a page */
+	rlwinm	r3,r3,0,0,PPC44x_RPN_MASK	/* Get page base address */
+	li	r4,PAGE_SIZE/L1_CACHE_BYTES	/* Number of lines in a page */
 	mtctr	r4
 	mr	r6,r3
 0:	dcbst	0,r3				/* Write line to ram */
@@ -713,7 +713,7 @@ END_FTR_SECTION_IFSET(CPU_FTR_COHERENT_ICACHE)
  * void clear_pages(void *page, int order) ;
  */
 _GLOBAL(clear_pages)
-	li	r0,4096/L1_CACHE_BYTES
+	li	r0,PAGE_SIZE/L1_CACHE_BYTES
 	slw	r0,r0,r4
 	mtctr	r0
 #ifdef CONFIG_8xx
@@ -771,7 +771,7 @@ _GLOBAL(copy_page)
 	dcbt	r5,r4
 	li	r11,L1_CACHE_BYTES+4
 #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
 2:
 	mtctr	r0
arch/powerpc/mm/pgtable_32.c +4 -9
index c31d6d2..10d21c3 100644
@@ -72,24 +72,19 @@ extern unsigned long p_mapped_by_tlbcam(unsigned long pa);
 #define p_mapped_by_tlbcam(x)	(0UL)
 #endif /* HAVE_TLBCAM */
 
-#ifdef CONFIG_PTE_64BIT
-/* Some processors use an 8kB pgdir because they have 8-byte Linux PTEs. */
-#define PGDIR_ORDER	1
-#else
-#define PGDIR_ORDER	0
-#endif
+#define PGDIR_ORDER	(32 + PGD_T_LOG2 - PGDIR_SHIFT)
 
 pgd_t *pgd_alloc(struct mm_struct *mm)
 {
 	pgd_t *ret;
 
-	ret = (pgd_t *)__get_free_pages(GFP_KERNEL|__GFP_ZERO, PGDIR_ORDER);
+	ret = (pgd_t *)kzalloc(1 << PGDIR_ORDER, GFP_KERNEL);
 	return ret;
 }
 
 void pgd_free(struct mm_struct *mm, pgd_t *pgd)
 {
-	free_pages((unsigned long)pgd, PGDIR_ORDER);
+	kfree((void *)pgd);
 }
 
 __init_refok pte_t *pte_alloc_one_kernel(struct mm_struct *mm, unsigned long address)
@@ -400,7 +395,7 @@ void kernel_map_pages(struct page *page, int numpages, int enable)
 #endif /* CONFIG_DEBUG_PAGEALLOC */
 
 static int fixmaps;
-unsigned long FIXADDR_TOP = 0xfffff000;
+unsigned long FIXADDR_TOP = (-PAGE_SIZE);
 EXPORT_SYMBOL(FIXADDR_TOP);
 
 void __set_fixmap (enum fixed_addresses idx, phys_addr_t phys, pgprot_t flags)
arch/powerpc/platforms/Kconfig.cputype +1 -1
index 548efa5..73a5aa9 100644
@@ -204,7 +204,7 @@ config PPC_STD_MMU_32
 
 config PPC_MM_SLICES
 	bool
-	default y if HUGETLB_PAGE || PPC_64K_PAGES
+	default y if HUGETLB_PAGE || (PPC64 && PPC_64K_PAGES)
 	default n
 
 config VIRT_CPU_ACCOUNTING
Signature · 1 line
1.5.6.1
#1 lore raw
Quoted 8 lines · Ilya Yanok

This patch adds support for page sizes bigger than 4K (16K/64K) on PPC 44x.
PGDIR table is much smaller than page in case of 16K/64K pages (512 and 32 bytes resp.) so we allocate PGDIR with kzalloc() instead of __get_free_pages().
PTE table covers rather big memory area in case of 16K/64K pages (32MB and 512MB resp.) so we can easily put FIXMAP and PKMAP in area covered by one PTE table.

Ben, you had some comments on the previous version of this patch. Have those been addressed to your satisfaction? If so, could you please queue this for 2.6.29?

-Hollis

#2 lore raw
Quoted 10 lines · Hollis Blanchard
Quoted 8 lines · Ilya Yanok

This patch adds support for page sizes bigger than 4K (16K/64K) on PPC 44x.
PGDIR table is much smaller than page in case of 16K/64K pages (512 and 32 bytes resp.) so we allocate PGDIR with kzalloc() instead of __get_free_pages().
PTE table covers rather big memory area in case of 16K/64K pages (32MB and 512MB resp.) so we can easily put FIXMAP and PKMAP in area covered by one PTE table.

Quoted 3 lines

Ben, you had some comments on the previous version of this patch. Have those been addressed to your satisfaction? If so, could you please queue this for 2.6.29?

Milton had some comments too. And I'd also like to review it and add and Acked-by since I'll be the one getting bug reports if it's broken :).

I've been sick for the past few days, but this is the first thing to review on my list tomorrow.

josh

#3 lore raw
In reply to Hollis Blanchard
Quoted 5 lines · Hollis Blanchard

Ben, you had some comments on the previous version of this patch. Have those been addressed to your satisfaction? If so, could you please queue this for 2.6.29?

From the description, they have, however I haven't had a chance to look

in details at the code yet. I would like to see these in 2.6.29 too though, I'll have a look asap.

Cheers,
Ben.

#4 lore raw
In reply to Ilya Yanok

Hi Ilya !

Looks good overall. A few minor comments.

arch/powerpc/Kconfig config PPC_HAS_HASH_64K · line 437

Quoted 9 lines
arch/powerpc/Kconfig +9 -0
+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 || PPC64
+	select PPC_HAS_HASH_64K if PPC64

I'd rather if the PPC64 references were instead PPC_STD_MMU_64 (which may or may not be defined in Kconfig depending on what you are based on, but is trivial to add.

I want to clearly differenciate what is MMU from what CPU architecture and there may (will ... ahem) at some point be 64-bit BookE.

In the same vein, we should probably rework some of the above so that the CPU/MMU type actually defines what page sizes are allowed (PPC_CAN_16K, PPC_CAN_64K, ...) but let's keep that for a later patch.

arch/powerpc/Kconfig config FORCE_MAX_ZONEORDER · line 473

Quoted 7 lines

config PPC_SUBPAGE_PROT

arch/powerpc/Kconfig +1 -1
 	bool "Support setting protections for 4k subpages"
-	depends on PPC_64K_PAGES
+	depends on PPC64 && PPC_64K_PAGES
 	help
 	  This option adds support for a system call to allow user programs
 	  to set access permissions (read/write, readonly, or no access)

Same comment here.

Quoted 13 lines
arch/powerpc/include/asm/highmem.h +3 -2
index 91c5895..9875540 100644
@@ -38,9 +38,20 @@ extern pte_t *pkmap_page_table;
  * easily, subsequent pte tables have to be allocated in one physical
  * 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

arch/powerpc/include/asm/highmem.h extern pte_t *pkmap_page_table; · line 53

Quoted 10 lines
arch/powerpc/include/asm/highmem.h +9 -0
+ * and PKMAP can be placed in single pte table. We use 1024 pages for
+ * PKMAP in case of 16K/64K pages.
+ */
+#define PKMAP_ORDER	min(PTE_SHIFT, 10)
+#define LAST_PKMAP	(1 << PKMAP_ORDER)
+#if !defined(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)
+#endif

I'm not sure about the above & PMD_MASK. Shouldn't we instead make it not build if (PKMAP_BASE & PMD_MASK) != 0 ? IE, somebody set FIXADDR_START to something wrong... and avoid the ifdef alltogether ? Or am I missing something ? (it's early morning and I may not have all my wits with me right now !)

arch/powerpc/include/asm/highmem.h extern pte_t *pkmap_page_table; · line 56

Quoted 4 lines
arch/powerpc/include/asm/highmem.h +1 -1
-#ifdef CONFIG_PPC_64K_PAGES
+#if defined(CONFIG_PPC_64K_PAGES) && defined(CONFIG_PPC64)
 typedef struct { pte_t pte; unsigned long hidx; } real_pte_t;
 #else

Same comment about using PPC_STD_MMU_64, it's going to make my life easier later on :-) And in various other places, I won't quote them all.

arch/powerpc/include/asm/page_32.h line 23

Quoted 10 lines
arch/powerpc/include/asm/page_32.h +1 -0
index d77072a..74b097b 100644
@@ -19,6 +19,7 @@
 #define PTE_FLAGS_OFFSET	0
 #endif
 
+#define PTE_SHIFT	(PAGE_SHIFT - PTE_T_LOG2)	/* full page */
 #ifndef __ASSEMBLY__

Stick a blank line between the two above statements.

Quoted 18 lines
arch/powerpc/include/asm/page_32.h +0 -2
 /*
  * The basic type of a PTE - 64 bits for those CPUs with > 32 bit
@@ -26,10 +27,8 @@
  */
 #ifdef CONFIG_PTE_64BIT
 typedef unsigned long long pte_basic_t;
-#define PTE_SHIFT	(PAGE_SHIFT - 3)	/* 512 ptes per page */
 #else
 typedef unsigned long pte_basic_t;
-#define PTE_SHIFT	(PAGE_SHIFT - 2)	/* 1024 ptes per page */
 #endif
 
 struct page;
arch/powerpc/include/asm/pgtable.h +0 -0
index dbb8ca1..a202043 100644

arch/powerpc/include/asm/pgtable.h extern void paging_init(void); · line 43

Quoted 5 lines
arch/powerpc/include/asm/pgtable.h +2 -0
@@ -39,6 +39,8 @@ extern void paging_init(void);
 
 #include <asm-generic/pgtable.h>
 
+#define PGD_T_LOG2	(__builtin_ffs(sizeof(pgd_t)) - 1)
+#define PTE_T_LOG2	(__builtin_ffs(sizeof(pte_t)) - 1)

I'm surprised the above actually work :-) Why not having these next to the definition of pte_t in page_32.h ?

Also, you end up having to do an asm-offset trick to get those to asm, I wonder if it's worth it or if we aren't better off just #defining the sizes with actual numbers next to the type definitions. No big deal either way.

Quoted 7 lines
arch/powerpc/include/asm/pgtable.h +0 -0
 /*
  * To support >32-bit physical addresses, we use an 8KB pgdir.
arch/powerpc/kernel/misc_32.S +0 -0
index bdc8b0e..42f99d2 100644

arch/powerpc/kernel/misc_32.S _GLOBAL(__flush_dcache_icache) · line 651

Quoted 7 lines
arch/powerpc/kernel/misc_32.S +2 -2
@@ -647,8 +647,8 @@ _GLOBAL(__flush_dcache_icache)
 BEGIN_FTR_SECTION
 	blr
 END_FTR_SECTION_IFSET(CPU_FTR_COHERENT_ICACHE)
-	rlwinm	r3,r3,0,0,19			/* Get page base address */
-	li	r4,4096/L1_CACHE_BYTES	/* Number of lines in a page */
+	rlwinm	r3,r3,0,0,PPC44x_RPN_MASK	/* Get page base address */
+	li	r4,PAGE_SIZE/L1_CACHE_BYTES	/* Number of lines in a page */

Now, the problem here is the name of the constant. IE. This is more or less generic ppc code and you are using something called "PPC4xx_RPN_MASK", doesn't look right.

I'r rather you do the right arithmetic using PAGE_SHIFT straight in here. In general, those _MASK constants you use aren't really masks, they are bit numbers in PPC notation which is very confusing. Maybe you should call those constants something like

PPC_xxxx_MASK_BIT

Dunno ... it's a bit verbose. But I'm not too happy with that naming at this stage. In any case, the above is definitely wrong in misc_32.S

arch/powerpc/kernel/misc_32.S END_FTR_SECTION_IFSET(CPU_FTR_COHERENT_ICACHE) · line 692

Quoted 11 lines
arch/powerpc/kernel/misc_32.S +2 -2
 	mtctr	r4
 	mr	r6,r3
 0:	dcbst	0,r3				/* Write line to ram */
@@ -688,8 +688,8 @@ END_FTR_SECTION_IFSET(CPU_FTR_COHERENT_ICACHE)
 	rlwinm	r0,r10,0,28,26			/* clear DR */
 	mtmsr	r0
 	isync
-	rlwinm	r3,r3,0,0,19			/* Get page base address */
-	li	r4,4096/L1_CACHE_BYTES	/* Number of lines in a page */
+	rlwinm	r3,r3,0,0,PPC44x_RPN_MASK	/* Get page base address */
+	li	r4,PAGE_SIZE/L1_CACHE_BYTES	/* Number of lines in a page */

Same comment.

arch/powerpc/kernel/misc_32.S END_FTR_SECTION_IFSET(CPU_FTR_COHERENT_ICACHE)

Quoted 8 lines
arch/powerpc/kernel/misc_32.S +1 -1
 pgd_t *pgd_alloc(struct mm_struct *mm)
 {
 	pgd_t *ret;
 
-	ret = (pgd_t *)__get_free_pages(GFP_KERNEL|__GFP_ZERO, PGDIR_ORDER);
+	ret = (pgd_t *)kzalloc(1 << PGDIR_ORDER, GFP_KERNEL);
 	return ret;
 }

We may want to consider using a slab cache. Maybe an area where we want to merge 32 and 64 bit code, though it doesn't have to be right now.

Do we know the impact of using kzalloc instead of gfp for when it's really just a single page though ? Does it have overhead or will kzalloc just fallback to gfp ? If it has overhead, then we probably want to ifdef and keep using gfp for the 1-page case.

Quoted 15 lines

__init_refok pte_t *pte_alloc_one_kernel(struct mm_struct *mm, unsigned long address)

arch/powerpc/kernel/misc_32.S +1 -1
@@ -400,7 +395,7 @@ void kernel_map_pages(struct page *page, int numpages, int enable)
 #endif /* CONFIG_DEBUG_PAGEALLOC */
 
 static int fixmaps;
-unsigned long FIXADDR_TOP = 0xfffff000;
+unsigned long FIXADDR_TOP = (-PAGE_SIZE);
 EXPORT_SYMBOL(FIXADDR_TOP);
 
 void __set_fixmap (enum fixed_addresses idx, phys_addr_t phys, pgprot_t flags)
arch/powerpc/platforms/Kconfig.cputype +0 -0
index 548efa5..73a5aa9 100644

arch/powerpc/platforms/Kconfig.cputype config PPC_STD_MMU_32 · line 208

Quoted 6 lines
arch/powerpc/platforms/Kconfig.cputype +1 -1
@@ -204,7 +204,7 @@ config PPC_STD_MMU_32
 
 config PPC_MM_SLICES
 	bool
-	default y if HUGETLB_PAGE || PPC_64K_PAGES
+	default y if HUGETLB_PAGE || (PPC64 && PPC_64K_PAGES)
 	default n

I would make it PPC_64 && (HUGETLB_PAGE || PPC_64K_PAGES) for now, I don't think we want to use the existing slice code on anything else.

Make it even PPC_STD_MMU_64

Cheers,
Ben.

#5 lore raw

Hello Ben,

Quoted 18 lines · On Wednesday, December 10, 2008 you wrote:

Hi Ilya !

Looks good overall. A few minor comments.

arch/powerpc/Kconfig config PPC_HAS_HASH_64K · line 437

Quoted 9 lines
arch/powerpc/Kconfig +9 -0
+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 || PPC64
+     select PPC_HAS_HASH_64K if PPC64

I'd rather if the PPC64 references were instead PPC_STD_MMU_64 (which may or may not be defined in Kconfig depending on what you are based on, but is trivial to add.

Quoted 2 lines

I want to clearly differenciate what is MMU from what CPU architecture and there may (will ... ahem) at some point be 64-bit BookE.

Understood. We'll fix this, and re-post the patch then.

[snip]

Quoted 1 line

arch/powerpc/include/a=

Quoted 1 line
arch/powerpc/include/a= renamed from arch/powerpc/include/asm/highmem.h +0 -0

sm/highmem.h

Quoted 13 lines
Quoted 13 lines

index 91c5895..9875540 100644

arch/powerpc/include/asm/highmem.h +4 -2
@@ -38,9 +38,20 @@ extern pte_t *pkmap_page_table;
  * easily, subsequent pte tables have to be allocated in one physical
  * 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
Quoted 8 lines

arch/powerpc/include/asm/highmem.h extern pte_t *pkmap_page_table;

Quoted 8 lines
arch/powerpc/include/asm/highmem.h +7 -0
+ * PKMAP in case of 16K/64K pages.
+ */
+#define PKMAP_ORDER  min(PTE_SHIFT, 10)
+#define LAST_PKMAP   (1 << PKMAP_ORDER)
+#if !defined(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)) & PM=

D_MASK)

Quoted 4 lines

arch/powerpc/include/asm/highmem.h extern pte_t *pkmap_page_table; · line 53

Quoted 1 line
arch/powerpc/include/asm/highmem.h +1 -0
+#endif

I'm not sure about the above & PMD_MASK. Shouldn't we instead make it not build if (PKMAP_BASE & PMD_MASK) !=3D 0 ?=20

We separated the !4K_PAGES case here exactly because (PKMAP_BASE &=20
PMD_MASK) !=3D 0 [see the comment to this chunk - why]. So, this'll turn=20 out to be broken if we follow your suggestion. Are there any reasons=20 why we should have PKMAP_BASE aligned on the PMD_SIZE boundary ?

Quoted 4 lines

IE, somebody set
FIXADDR_START to something wrong... and avoid the ifdef alltogether ? Or am I missing something ? (it's early morning and I may not have all my wits with me right now !)

[snip]

Quoted 1 line

arch/powerpc/include/a=

Quoted 1 line
arch/powerpc/include/a= renamed from arch/powerpc/include/asm/pgtable.h +0 -0

sm/pgtable.h

Quoted 4 lines
Quoted 4 lines

index dbb8ca1..a202043 100644

arch/powerpc/include/asm/pgtable.h +0 -0
@@ -39,6 +39,8 @@ extern void paging_init(void);
Quoted 8 lines

arch/powerpc/include/asm/pgtable.h extern void paging_init(void); · line 43

Quoted 5 lines

=20
#include <asm-generic/pgtable.h>
=20

arch/powerpc/include/asm/pgtable.h +2 -0
+#define PGD_T_LOG2   (__builtin_ffs(sizeof(pgd_t)) - 1)
+#define PTE_T_LOG2   (__builtin_ffs(sizeof(pte_t)) - 1)

I'm surprised the above actually work :-) Why not having these next to the definition of pte_t in page_32.h ?

These definitions seem to be related to the page table, so, as for me,=20
then pgtable.h is the better place for them. Though, as you want;=20 we'll move this to page_32.h.

Quoted 2 lines

Also, you end up having to do an asm-offset trick to get those to asm, I wonder if it's worth it or if we aren't better off just #defining the siz=

es

Quoted 4 lines

with actual numbers next to the type definitions. No big deal either way.

arch/powerpc/kernel/misc_32=

Quoted 3 lines

/*
* To support >32-bit physical addresses, we use an 8KB pgdir.

arch/powerpc/kernel/misc_32= renamed from arch/powerpc/kernel/misc_32.S +0 -0

.S

Quoted 11 lines

arch/powerpc/kernel/misc_32.S _GLOBAL(__flush_dcache_icache) · line 651

Quoted 11 lines

index bdc8b0e..42f99d2 100644

arch/powerpc/kernel/misc_32.S +2 -2
@@ -647,8 +647,8 @@ _GLOBAL(__flush_dcache_icache)
 BEGIN_FTR_SECTION
      blr
 END_FTR_SECTION_IFSET(CPU_FTR_COHERENT_ICACHE)
-     rlwinm  r3,r3,0,0,19                    /* Get page base address */
-     li      r4,4096/L1_CACHE_BYTES  /* Number of lines in a page */
+     rlwinm  r3,r3,0,0,PPC44x_RPN_MASK       /* Get page base address */
+     li      r4,PAGE_SIZE/L1_CACHE_BYTES     /* Number of lines in a pa=

ge */

Quoted 10 lines

Now, the problem here is the name of the constant. IE. This is more or less generic ppc code and you are using something called "PPC4xx_RPN_MASK", doesn't look right.

I'r rather you do the right arithmetic using PAGE_SHIFT straight in here. In general, those _MASK constants you use aren't really masks, they are bit numbers in PPC notation which is very confusing. Maybe you should call those constants something like

PPC_xxxx_MASK_BIT

OK.

Quoted 14 lines

Dunno ... it's a bit verbose. But I'm not too happy with that naming at this stage. In any case, the above is definitely wrong in misc_32.S=20

arch/powerpc/kernel/misc_32.S END_FTR_SECTION_IFSET(CPU_FTR_COHERENT_ICACHE) · line 692

Quoted 11 lines
arch/powerpc/kernel/misc_32.S +2 -2
      mtctr   r4
      mr      r6,r3
 0:   dcbst   0,r3                            /* Write line to ram */
@@ -688,8 +688,8 @@ END_FTR_SECTION_IFSET(CPU_FTR_COHERENT_ICACHE)
      rlwinm  r0,r10,0,28,26                  /* clear DR */
      mtmsr   r0
      isync
-     rlwinm  r3,r3,0,0,19                    /* Get page base address */
-     li      r4,4096/L1_CACHE_BYTES  /* Number of lines in a page */
+     rlwinm  r3,r3,0,0,PPC44x_RPN_MASK       /* Get page base address */
+     li      r4,PAGE_SIZE/L1_CACHE_BYTES     /* Number of lines in a pa=

ge */

Quoted 7 lines

Same comment.

Quoted 5 lines
arch/powerpc/kernel/misc_32.S +0 -0
 pgd_t *pgd_alloc(struct mm_struct *mm)
 {
      pgd_t *ret;

=20
- ret =3D (pgd_t *)__get_free_pages(GFP_KERNEL|__GFP_ZERO, PGDIR_ORD=

ER);

Quoted 11 lines
Quoted 3 lines
+     ret =3D (pgd_t *)kzalloc(1 << PGDIR_ORDER, GFP_KERNEL);
      return ret;

}

We may want to consider using a slab cache. Maybe an area where we want to merge 32 and 64 bit code, though it doesn't have to be right now.

Do we know the impact of using kzalloc instead of gfp for when it's really just a single page though ? Does it have overhead or will kzalloc just fallback to gfp ? If it has overhead, then we probably want to ifdef and keep using gfp for the 1-page case.

This depends on allocator: SLUB looks calling __get_free_pages() if=20
size > PAGE_SIZE [note, not >=3D !], but SLAB doesn't. So, we'll add=20 ifdef here.

Quoted 1 line
Quoted 1 line

__init_refok pte_t *pte_alloc_one_kernel(struct mm_struct *mm, unsigned=

long address)

Quoted 1 line

arch/powerpc/kernel/misc_32.S void kernel_map_pages(struct page *page, int numpage=

Quoted 1 line
arch/powerpc/kernel/misc_32.S +0 -0
@@ -400,7 +395,7 @@ void kernel_map_pages(struct page *page, int numpage=

s, int enable)

Quoted 8 lines
Quoted 8 lines
arch/powerpc/kernel/misc_32.S +0 -0
 #endif /* CONFIG_DEBUG_PAGEALLOC */

=20
static int fixmaps;

arch/powerpc/kernel/misc_32.S +1 -1
-unsigned long FIXADDR_TOP =3D 0xfffff000;
+unsigned long FIXADDR_TOP =3D (-PAGE_SIZE);
 EXPORT_SYMBOL(FIXADDR_TOP);

=20
void __set_fixmap (enum fixed_addresses idx, phys_addr_t phys, pgprot_t=

flags)

Quoted 1 line

arch/powerpc/platf=

Quoted 1 line
arch/powerpc/platf= renamed from arch/powerpc/platforms/Kconfig.cputype +0 -0

orms/Kconfig.cputype

Quoted 14 lines

arch/powerpc/platforms/Kconfig.cputype config PPC_STD_MMU_32 · line 208

Quoted 10 lines

index 548efa5..73a5aa9 100644

arch/powerpc/platforms/Kconfig.cputype +0 -0
@@ -204,7 +204,7 @@ config PPC_STD_MMU_32

=20
config PPC_MM_SLICES
bool

arch/powerpc/platforms/Kconfig.cputype +1 -1
-     default y if HUGETLB_PAGE || PPC_64K_PAGES
+     default y if HUGETLB_PAGE || (PPC64 && PPC_64K_PAGES)
      default n

I would make it PPC_64 && (HUGETLB_PAGE || PPC_64K_PAGES) for now, I don't think we want to use the existing slice code on anything else.

Quoted 4 lines

Make it even PPC_STD_MMU_64

Cheers,
Ben.

Regards, Yuri

--
Yuri Tikhonov, Senior Software Engineer
Emcraft Systems, www.emcraft.com

#6 lore raw
Quoted 8 lines · Yuri Tikhonov
Quoted 3 lines

I'm not sure about the above & PMD_MASK. Shouldn't we instead make it not build if (PKMAP_BASE & PMD_MASK) != 0 ?

We separated the !4K_PAGES case here exactly because (PKMAP_BASE &
PMD_MASK) != 0 [see the comment to this chunk - why]. So, this'll turn out to be broken if we follow your suggestion. Are there any reasons why we should have PKMAP_BASE aligned on the PMD_SIZE boundary ?

No, you are right, so why do we need the & PMD_MASK in the 4k case ?

What I don't get is why do we need a different formula for 4k and 64k but I might just be stupid :-)

Quoted 3 lines

These definitions seem to be related to the page table, so, as for me,
then pgtable.h is the better place for them. Though, as you want; we'll move this to page_32.h.

Well, I like having them next to the pte_t/pgd_t definitions since they relate directly to the size of those structures.

Cheers,
Ben.

author
#7 lore raw

Hi Benjamin,

Quoted 9 lines · Benjamin Herrenschmidt
Quoted 8 lines
Quoted 3 lines

I'm not sure about the above & PMD_MASK. Shouldn't we instead make it not build if (PKMAP_BASE & PMD_MASK) != 0 ?

We separated the !4K_PAGES case here exactly because (PKMAP_BASE &
PMD_MASK) != 0 [see the comment to this chunk - why]. So, this'll turn out to be broken if we follow your suggestion. Are there any reasons why we should have PKMAP_BASE aligned on the PMD_SIZE boundary ?

Quoted 5 lines

No, you are right, so why do we need the & PMD_MASK in the 4k case ?

What I don't get is why do we need a different formula for 4k and 64k but I might just be stupid :-)

Because we want full PTE table for PKMAP with 4K pages (it's pretty small - only 512 pages so we really want to use all). And as current code doesn't support PKMAP being in different PTE tables we want to align to full PTE table not to lost part of it.

Quoted 8 lines
Quoted 4 lines

These definitions seem to be related to the page table, so, as for me,
then pgtable.h is the better place for them. Though, as you want; we'll move this to page_32.h.

Well, I like having them next to the pte_t/pgd_t definitions since they relate directly to the size of those structures.

Well. But pte_t/pgd_t are actually in page.h not page_32.h (along with pmd/pud for 64bit)... So maybe we need to put definitions for PMD_T_LOG2/PUD_T_LOG2 too...

Regards, Ilya.

author
#8 lore raw

PATCH 1/1 powerpc: add 16K/64K pages support for the 44x PPC32 architectures.

In reply to Benjamin Herrenschmidt

This patch adds support for page sizes bigger than 4K (16K/64K) on PPC 44x.
PGDIR table is much smaller than page in case of 16K/64K pages (512 and 32 bytes resp.) so we allocate PGDIR with kzalloc() instead of __get_free_pages().
PTE table covers rather big memory area in case of 16K/64K pages (32MB and 512MB resp.) so we can easily put FIXMAP and PKMAP in area covered by one PTE table.

---
 arch/powerpc/Kconfig                   |   58 ++++++++++++++++++++++++--------
 arch/powerpc/include/asm/highmem.h     |   15 +++++++-
 arch/powerpc/include/asm/mmu-44x.h     |   17 +++++++++
 arch/powerpc/include/asm/page.h        |   13 ++++---
 arch/powerpc/include/asm/page_32.h     |    7 +++-
 arch/powerpc/kernel/asm-offsets.c      |    4 ++
 arch/powerpc/kernel/head_44x.S         |   23 ++++++++-----
 arch/powerpc/kernel/misc_32.S          |   12 +++---
 arch/powerpc/mm/pgtable_32.c           |   23 ++++++++-----
 arch/powerpc/platforms/Kconfig.cputype |    2 +-
 10 files changed, 126 insertions(+), 48 deletions(-)
arch/powerpc/Kconfig +44 -14
index 525c13a..cd8ff7c 100644
@@ -401,23 +401,53 @@ config PPC_HAS_HASH_64K
 	depends on PPC64
 	default n
 
-config PPC_64K_PAGES
-	bool "64k page size"
-	depends on PPC64
-	select PPC_HAS_HASH_64K
+choice
+	prompt "Page size"
+	default PPC_4K_PAGES
 	help
-	  This option changes the kernel logical page size to 64k. On machines
-	  without processor support for 64k pages, the kernel will simulate
-	  them by loading each individual 4k page on demand transparently,
-	  while on hardware with such support, it will be used to map
-	  normal application pages.
+	  Select the kernel logical page size. Increasing the page size
+	  will reduce software overhead at each page boundary, allow
+	  hardware prefetch mechanisms to be more effective, and allow
+	  larger dma transfers increasing IO efficiency and reducing
+	  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
 	int "Maximum zone order"
-	range 9 64 if PPC_64K_PAGES
-	default "9" if PPC_64K_PAGES
-	range 13 64 if PPC64 && !PPC_64K_PAGES
-	default "13" if PPC64 && !PPC_64K_PAGES
+	range 9 64 if PPC_STD_MMU_64 && PPC_64K_PAGES
+	default "9" if PPC_STD_MMU_64 && PPC_64K_PAGES
+	range 13 64 if PPC_STD_MMU_64 && !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
 	default "11"
 	help
@@ -437,7 +467,7 @@ config FORCE_MAX_ZONEORDER
 
 config PPC_SUBPAGE_PROT
 	bool "Support setting protections for 4k subpages"
-	depends on PPC_64K_PAGES
+	depends on PPC_STD_MMU_64 && PPC_64K_PAGES
 	help
 	  This option adds support for a system call to allow user programs
 	  to set access permissions (read/write, readonly, or no access)
arch/powerpc/include/asm/highmem.h +13 -2
index 91c5895..9875540 100644
@@ -38,9 +38,20 @@ extern pte_t *pkmap_page_table;
  * easily, subsequent pte tables have to be allocated in one physical
  * 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.
+ */
+#define PKMAP_ORDER	min(PTE_SHIFT, 10)
+#define LAST_PKMAP	(1 << PKMAP_ORDER)
+#if !defined(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)
+#endif
+#define LAST_PKMAP_MASK	(LAST_PKMAP-1)
 #define PKMAP_NR(virt)  ((virt-PKMAP_BASE) >> PAGE_SHIFT)
 #define PKMAP_ADDR(nr)  (PKMAP_BASE + ((nr) << PAGE_SHIFT))
 
arch/powerpc/include/asm/mmu-44x.h +17 -0
index a825524..73e1909 100644
@@ -4,6 +4,8 @@
  * PPC440 support
  */
 
+#include <asm/page.h>
+
 #define PPC44x_MMUCR_TID	0x000000ff
 #define PPC44x_MMUCR_STS	0x00010000
 
@@ -73,4 +75,19 @@ typedef struct {
 /* Size of the TLBs used for pinning in lowmem */
 #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_ */
arch/powerpc/include/asm/page.h +8 -5
index c0b8d4a..197d569 100644
@@ -19,12 +19,15 @@
 #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
  * 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
+#elif defined(CONFIG_PPC_16K_PAGES)
+#define PAGE_SHIFT		14
 #else
 #define PAGE_SHIFT		12
 #endif
@@ -151,7 +154,7 @@ typedef struct { pte_basic_t pte; } pte_t;
 /* 64k pages additionally define a bigger "real PTE" type that gathers
  * 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;
 #else
 typedef struct { pte_t pte; } real_pte_t;
@@ -191,10 +194,10 @@ typedef pte_basic_t pte_t;
 #define pte_val(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;
 #else
-typedef unsigned long real_pte_t;
+typedef pte_t real_pte_t;
 #endif
 
 
arch/powerpc/include/asm/page_32.h +5 -2
index d77072a..1458d95 100644
@@ -19,6 +19,8 @@
 #define PTE_FLAGS_OFFSET	0
 #endif
 
+#define PTE_SHIFT	(PAGE_SHIFT - PTE_T_LOG2)	/* full page */
+
 #ifndef __ASSEMBLY__
 /*
  * The basic type of a PTE - 64 bits for those CPUs with > 32 bit
@@ -26,10 +28,8 @@
  */
 #ifdef CONFIG_PTE_64BIT
 typedef unsigned long long pte_basic_t;
-#define PTE_SHIFT	(PAGE_SHIFT - 3)	/* 512 ptes per page */
 #else
 typedef unsigned long pte_basic_t;
-#define PTE_SHIFT	(PAGE_SHIFT - 2)	/* 1024 ptes per page */
 #endif
 
 struct page;
@@ -39,6 +39,9 @@ extern void copy_page(void *to, void *from);
 
 #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 /* _ASM_POWERPC_PAGE_32_H */
arch/powerpc/kernel/asm-offsets.c +4 -0
index 75c5dd0..0142318 100644
@@ -378,6 +378,10 @@ int main(void)
 	DEFINE(VCPU_FAULT_DEAR, offsetof(struct kvm_vcpu, arch.fault_dear));
 	DEFINE(VCPU_FAULT_ESR, offsetof(struct kvm_vcpu, arch.fault_esr));
 #endif
+#ifdef CONFIG_44x
+	DEFINE(PGD_T_LOG2, PGD_T_LOG2);
+	DEFINE(PTE_T_LOG2, PTE_T_LOG2);
+#endif
 
 	return 0;
 }
arch/powerpc/kernel/head_44x.S +14 -9
index f3a1ea9..3bf6bd1 100644
@@ -391,12 +391,14 @@ interrupt_base:
 	rlwimi	r13,r12,10,30,30
 
 	/* 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 */
 	rlwinm.	r12, r11, 0, 0, 20	/* Extract pt base address */
 	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	r12, 4(r12)		/* Get low word of pte entry */
 
@@ -485,12 +487,14 @@ tlb_44x_patch_hwater_D:
 	/* Make up the required permissions */
 	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 */
 	rlwinm.	r12, r11, 0, 0, 20	/* Extract pt base address */
 	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	r12, 4(r12)		/* Get low word of pte entry */
 
@@ -554,15 +558,16 @@ tlb_44x_patch_hwater_I:
  */
 finish_tlb_load:
 	/* 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
 
 	/*
 	 * Create WS1. This is the faulting address (EPN),
 	 * page size, and valid flag.
 	 */
-	li	r11,PPC44x_TLB_VALID | PPC44x_TLB_4K
-	rlwimi	r10,r11,0,20,31			/* Insert valid and page size*/
+	li	r11,PPC44x_TLB_VALID | PPC44x_TLBE_SIZE
+	/* Insert valid and page size */
+	rlwimi	r10,r11,0,PPC44x_PTE_ADD_MASK_BIT,31
 	tlbwe	r10,r13,PPC44x_TLB_PAGEID	/* Write PAGEID */
 
 	/* And WS 2 */
@@ -634,12 +639,12 @@ _GLOBAL(set_context)
  * goes at the beginning of the data segment, which is page-aligned.
  */
 	.data
-	.align	12
+	.align	PAGE_SHIFT
 	.globl	sdata
 sdata:
 	.globl	empty_zero_page
 empty_zero_page:
-	.space	4096
+	.space	PAGE_SIZE
 
 /*
  * To support >32-bit physical addresses, we use an 8KB pgdir.
arch/powerpc/kernel/misc_32.S +6 -6
index bdc8b0e..950b708 100644
@@ -647,8 +647,8 @@ _GLOBAL(__flush_dcache_icache)
 BEGIN_FTR_SECTION
 	blr
 END_FTR_SECTION_IFSET(CPU_FTR_COHERENT_ICACHE)
-	rlwinm	r3,r3,0,0,19			/* Get page base address */
-	li	r4,4096/L1_CACHE_BYTES	/* Number of lines in a page */
+	rlwinm	r3,r3,0,0,31-PAGE_SHIFT		/* Get page base address */
+	li	r4,PAGE_SIZE/L1_CACHE_BYTES	/* Number of lines in a page */
 	mtctr	r4
 	mr	r6,r3
 0:	dcbst	0,r3				/* Write line to ram */
@@ -688,8 +688,8 @@ END_FTR_SECTION_IFSET(CPU_FTR_COHERENT_ICACHE)
 	rlwinm	r0,r10,0,28,26			/* clear DR */
 	mtmsr	r0
 	isync
-	rlwinm	r3,r3,0,0,19			/* Get page base address */
-	li	r4,4096/L1_CACHE_BYTES	/* Number of lines in a page */
+	rlwinm	r3,r3,0,0,31-PAGE_SHIFT		/* Get page base address */
+	li	r4,PAGE_SIZE/L1_CACHE_BYTES	/* Number of lines in a page */
 	mtctr	r4
 	mr	r6,r3
 0:	dcbst	0,r3				/* Write line to ram */
@@ -713,7 +713,7 @@ END_FTR_SECTION_IFSET(CPU_FTR_COHERENT_ICACHE)
  * void clear_pages(void *page, int order) ;
  */
 _GLOBAL(clear_pages)
-	li	r0,4096/L1_CACHE_BYTES
+	li	r0,PAGE_SIZE/L1_CACHE_BYTES
 	slw	r0,r0,r4
 	mtctr	r0
 #ifdef CONFIG_8xx
@@ -771,7 +771,7 @@ _GLOBAL(copy_page)
 	dcbt	r5,r4
 	li	r11,L1_CACHE_BYTES+4
 #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
 2:
 	mtctr	r0
arch/powerpc/mm/pgtable_32.c +14 -9
index c31d6d2..f966a5e 100644
@@ -72,24 +72,29 @@ extern unsigned long p_mapped_by_tlbcam(unsigned long pa);
 #define p_mapped_by_tlbcam(x)	(0UL)
 #endif /* HAVE_TLBCAM */
 
-#ifdef CONFIG_PTE_64BIT
-/* Some processors use an 8kB pgdir because they have 8-byte Linux PTEs. */
-#define PGDIR_ORDER	1
-#else
-#define PGDIR_ORDER	0
-#endif
+#define PGDIR_ORDER	(32 + PGD_T_LOG2 - PGDIR_SHIFT)
 
 pgd_t *pgd_alloc(struct mm_struct *mm)
 {
 	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;
 }
 
 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)
@@ -400,7 +405,7 @@ void kernel_map_pages(struct page *page, int numpages, int enable)
 #endif /* CONFIG_DEBUG_PAGEALLOC */
 
 static int fixmaps;
-unsigned long FIXADDR_TOP = 0xfffff000;
+unsigned long FIXADDR_TOP = (-PAGE_SIZE);
 EXPORT_SYMBOL(FIXADDR_TOP);
 
 void __set_fixmap (enum fixed_addresses idx, phys_addr_t phys, pgprot_t flags)
arch/powerpc/platforms/Kconfig.cputype +1 -1
index 548efa5..51098bc 100644
@@ -204,7 +204,7 @@ config PPC_STD_MMU_32
 
 config PPC_MM_SLICES
 	bool
-	default y if HUGETLB_PAGE || PPC_64K_PAGES
+	default y if HUGETLB_PAGE || (PPC_STD_MMU_64 && PPC_64K_PAGES)
 	default n
 
 config VIRT_CPU_ACCOUNTING
Signature · 1 line
1.5.6.1
author
#9 lore raw

Hello guys,

please discard this patch. It just doesn't compile with CONFIG_HIGHMEM set. I'll post updated patch in a short time.

Excuse me.

Regards, Ilya.

author
#10 lore raw

PATCH 1/1 powerpc: add 16K/64K pages support for the 44x PPC32 architectures.

This patch adds support for page sizes bigger than 4K (16K/64K) on PPC 44x.
PGDIR table is much smaller than page in case of 16K/64K pages (512 and 32 bytes resp.) so we allocate PGDIR with kzalloc() instead of __get_free_pages().
PTE table covers rather big memory area in case of 16K/64K pages (32MB and 512MB resp.) so we can easily put FIXMAP and PKMAP in area covered by one PTE table.

---
 arch/powerpc/Kconfig                   |   58 ++++++++++++++++++++++++--------
 arch/powerpc/include/asm/highmem.h     |   19 +++++++++-
 arch/powerpc/include/asm/mmu-44x.h     |   17 +++++++++
 arch/powerpc/include/asm/page.h        |   13 ++++---
 arch/powerpc/include/asm/page_32.h     |    7 +++-
 arch/powerpc/kernel/asm-offsets.c      |    4 ++
 arch/powerpc/kernel/head_44x.S         |   23 ++++++++-----
 arch/powerpc/kernel/misc_32.S          |   12 +++---
 arch/powerpc/mm/pgtable_32.c           |   23 ++++++++-----
 arch/powerpc/platforms/Kconfig.cputype |    2 +-
 10 files changed, 130 insertions(+), 48 deletions(-)
arch/powerpc/Kconfig +44 -14
index 525c13a..cd8ff7c 100644
@@ -401,23 +401,53 @@ config PPC_HAS_HASH_64K
 	depends on PPC64
 	default n
 
-config PPC_64K_PAGES
-	bool "64k page size"
-	depends on PPC64
-	select PPC_HAS_HASH_64K
+choice
+	prompt "Page size"
+	default PPC_4K_PAGES
 	help
-	  This option changes the kernel logical page size to 64k. On machines
-	  without processor support for 64k pages, the kernel will simulate
-	  them by loading each individual 4k page on demand transparently,
-	  while on hardware with such support, it will be used to map
-	  normal application pages.
+	  Select the kernel logical page size. Increasing the page size
+	  will reduce software overhead at each page boundary, allow
+	  hardware prefetch mechanisms to be more effective, and allow
+	  larger dma transfers increasing IO efficiency and reducing
+	  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
 	int "Maximum zone order"
-	range 9 64 if PPC_64K_PAGES
-	default "9" if PPC_64K_PAGES
-	range 13 64 if PPC64 && !PPC_64K_PAGES
-	default "13" if PPC64 && !PPC_64K_PAGES
+	range 9 64 if PPC_STD_MMU_64 && PPC_64K_PAGES
+	default "9" if PPC_STD_MMU_64 && PPC_64K_PAGES
+	range 13 64 if PPC_STD_MMU_64 && !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
 	default "11"
 	help
@@ -437,7 +467,7 @@ config FORCE_MAX_ZONEORDER
 
 config PPC_SUBPAGE_PROT
 	bool "Support setting protections for 4k subpages"
-	depends on PPC_64K_PAGES
+	depends on PPC_STD_MMU_64 && PPC_64K_PAGES
 	help
 	  This option adds support for a system call to allow user programs
 	  to set access permissions (read/write, readonly, or no access)
arch/powerpc/include/asm/highmem.h +17 -2
index 91c5895..7d6bb37 100644
@@ -38,9 +38,24 @@ extern pte_t *pkmap_page_table;
  * easily, subsequent pte tables have to be allocated in one physical
  * 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)
+#endif
+#define LAST_PKMAP_MASK	(LAST_PKMAP-1)
 #define PKMAP_NR(virt)  ((virt-PKMAP_BASE) >> PAGE_SHIFT)
 #define PKMAP_ADDR(nr)  (PKMAP_BASE + ((nr) << PAGE_SHIFT))
 
arch/powerpc/include/asm/mmu-44x.h +17 -0
index a825524..73e1909 100644
@@ -4,6 +4,8 @@
  * PPC440 support
  */
 
+#include <asm/page.h>
+
 #define PPC44x_MMUCR_TID	0x000000ff
 #define PPC44x_MMUCR_STS	0x00010000
 
@@ -73,4 +75,19 @@ typedef struct {
 /* Size of the TLBs used for pinning in lowmem */
 #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_ */
arch/powerpc/include/asm/page.h +8 -5
index c0b8d4a..197d569 100644
@@ -19,12 +19,15 @@
 #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
  * 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
+#elif defined(CONFIG_PPC_16K_PAGES)
+#define PAGE_SHIFT		14
 #else
 #define PAGE_SHIFT		12
 #endif
@@ -151,7 +154,7 @@ typedef struct { pte_basic_t pte; } pte_t;
 /* 64k pages additionally define a bigger "real PTE" type that gathers
  * 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;
 #else
 typedef struct { pte_t pte; } real_pte_t;
@@ -191,10 +194,10 @@ typedef pte_basic_t pte_t;
 #define pte_val(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;
 #else
-typedef unsigned long real_pte_t;
+typedef pte_t real_pte_t;
 #endif
 
 
arch/powerpc/include/asm/page_32.h +5 -2
index d77072a..1458d95 100644
@@ -19,6 +19,8 @@
 #define PTE_FLAGS_OFFSET	0
 #endif
 
+#define PTE_SHIFT	(PAGE_SHIFT - PTE_T_LOG2)	/* full page */
+
 #ifndef __ASSEMBLY__
 /*
  * The basic type of a PTE - 64 bits for those CPUs with > 32 bit
@@ -26,10 +28,8 @@
  */
 #ifdef CONFIG_PTE_64BIT
 typedef unsigned long long pte_basic_t;
-#define PTE_SHIFT	(PAGE_SHIFT - 3)	/* 512 ptes per page */
 #else
 typedef unsigned long pte_basic_t;
-#define PTE_SHIFT	(PAGE_SHIFT - 2)	/* 1024 ptes per page */
 #endif
 
 struct page;
@@ -39,6 +39,9 @@ extern void copy_page(void *to, void *from);
 
 #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 /* _ASM_POWERPC_PAGE_32_H */
arch/powerpc/kernel/asm-offsets.c +4 -0
index 75c5dd0..0142318 100644
@@ -378,6 +378,10 @@ int main(void)
 	DEFINE(VCPU_FAULT_DEAR, offsetof(struct kvm_vcpu, arch.fault_dear));
 	DEFINE(VCPU_FAULT_ESR, offsetof(struct kvm_vcpu, arch.fault_esr));
 #endif
+#ifdef CONFIG_44x
+	DEFINE(PGD_T_LOG2, PGD_T_LOG2);
+	DEFINE(PTE_T_LOG2, PTE_T_LOG2);
+#endif
 
 	return 0;
 }
arch/powerpc/kernel/head_44x.S +14 -9
index f3a1ea9..3bf6bd1 100644
@@ -391,12 +391,14 @@ interrupt_base:
 	rlwimi	r13,r12,10,30,30
 
 	/* 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 */
 	rlwinm.	r12, r11, 0, 0, 20	/* Extract pt base address */
 	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	r12, 4(r12)		/* Get low word of pte entry */
 
@@ -485,12 +487,14 @@ tlb_44x_patch_hwater_D:
 	/* Make up the required permissions */
 	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 */
 	rlwinm.	r12, r11, 0, 0, 20	/* Extract pt base address */
 	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	r12, 4(r12)		/* Get low word of pte entry */
 
@@ -554,15 +558,16 @@ tlb_44x_patch_hwater_I:
  */
 finish_tlb_load:
 	/* 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
 
 	/*
 	 * Create WS1. This is the faulting address (EPN),
 	 * page size, and valid flag.
 	 */
-	li	r11,PPC44x_TLB_VALID | PPC44x_TLB_4K
-	rlwimi	r10,r11,0,20,31			/* Insert valid and page size*/
+	li	r11,PPC44x_TLB_VALID | PPC44x_TLBE_SIZE
+	/* Insert valid and page size */
+	rlwimi	r10,r11,0,PPC44x_PTE_ADD_MASK_BIT,31
 	tlbwe	r10,r13,PPC44x_TLB_PAGEID	/* Write PAGEID */
 
 	/* And WS 2 */
@@ -634,12 +639,12 @@ _GLOBAL(set_context)
  * goes at the beginning of the data segment, which is page-aligned.
  */
 	.data
-	.align	12
+	.align	PAGE_SHIFT
 	.globl	sdata
 sdata:
 	.globl	empty_zero_page
 empty_zero_page:
-	.space	4096
+	.space	PAGE_SIZE
 
 /*
  * To support >32-bit physical addresses, we use an 8KB pgdir.
arch/powerpc/kernel/misc_32.S +6 -6
index bdc8b0e..950b708 100644
@@ -647,8 +647,8 @@ _GLOBAL(__flush_dcache_icache)
 BEGIN_FTR_SECTION
 	blr
 END_FTR_SECTION_IFSET(CPU_FTR_COHERENT_ICACHE)
-	rlwinm	r3,r3,0,0,19			/* Get page base address */
-	li	r4,4096/L1_CACHE_BYTES	/* Number of lines in a page */
+	rlwinm	r3,r3,0,0,31-PAGE_SHIFT		/* Get page base address */
+	li	r4,PAGE_SIZE/L1_CACHE_BYTES	/* Number of lines in a page */
 	mtctr	r4
 	mr	r6,r3
 0:	dcbst	0,r3				/* Write line to ram */
@@ -688,8 +688,8 @@ END_FTR_SECTION_IFSET(CPU_FTR_COHERENT_ICACHE)
 	rlwinm	r0,r10,0,28,26			/* clear DR */
 	mtmsr	r0
 	isync
-	rlwinm	r3,r3,0,0,19			/* Get page base address */
-	li	r4,4096/L1_CACHE_BYTES	/* Number of lines in a page */
+	rlwinm	r3,r3,0,0,31-PAGE_SHIFT		/* Get page base address */
+	li	r4,PAGE_SIZE/L1_CACHE_BYTES	/* Number of lines in a page */
 	mtctr	r4
 	mr	r6,r3
 0:	dcbst	0,r3				/* Write line to ram */
@@ -713,7 +713,7 @@ END_FTR_SECTION_IFSET(CPU_FTR_COHERENT_ICACHE)
  * void clear_pages(void *page, int order) ;
  */
 _GLOBAL(clear_pages)
-	li	r0,4096/L1_CACHE_BYTES
+	li	r0,PAGE_SIZE/L1_CACHE_BYTES
 	slw	r0,r0,r4
 	mtctr	r0
 #ifdef CONFIG_8xx
@@ -771,7 +771,7 @@ _GLOBAL(copy_page)
 	dcbt	r5,r4
 	li	r11,L1_CACHE_BYTES+4
 #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
 2:
 	mtctr	r0
arch/powerpc/mm/pgtable_32.c +14 -9
index c31d6d2..f966a5e 100644
@@ -72,24 +72,29 @@ extern unsigned long p_mapped_by_tlbcam(unsigned long pa);
 #define p_mapped_by_tlbcam(x)	(0UL)
 #endif /* HAVE_TLBCAM */
 
-#ifdef CONFIG_PTE_64BIT
-/* Some processors use an 8kB pgdir because they have 8-byte Linux PTEs. */
-#define PGDIR_ORDER	1
-#else
-#define PGDIR_ORDER	0
-#endif
+#define PGDIR_ORDER	(32 + PGD_T_LOG2 - PGDIR_SHIFT)
 
 pgd_t *pgd_alloc(struct mm_struct *mm)
 {
 	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;
 }
 
 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)
@@ -400,7 +405,7 @@ void kernel_map_pages(struct page *page, int numpages, int enable)
 #endif /* CONFIG_DEBUG_PAGEALLOC */
 
 static int fixmaps;
-unsigned long FIXADDR_TOP = 0xfffff000;
+unsigned long FIXADDR_TOP = (-PAGE_SIZE);
 EXPORT_SYMBOL(FIXADDR_TOP);
 
 void __set_fixmap (enum fixed_addresses idx, phys_addr_t phys, pgprot_t flags)
arch/powerpc/platforms/Kconfig.cputype +1 -1
index 548efa5..51098bc 100644
@@ -204,7 +204,7 @@ config PPC_STD_MMU_32
 
 config PPC_MM_SLICES
 	bool
-	default y if HUGETLB_PAGE || PPC_64K_PAGES
+	default y if HUGETLB_PAGE || (PPC_STD_MMU_64 && PPC_64K_PAGES)
 	default n
 
 config VIRT_CPU_ACCOUNTING
Signature · 1 line
1.5.6.1
Acked-by on v1 1/1
#11 lore raw
Quoted 9 lines · Ilya Yanok

This patch adds support for page sizes bigger than 4K (16K/64K) on PPC 44x.
PGDIR table is much smaller than page in case of 16K/64K pages (512 and 32 bytes resp.) so we allocate PGDIR with kzalloc() instead of __get_free_pages().
PTE table covers rather big memory area in case of 16K/64K pages (32MB and 512MB resp.) so we can easily put FIXMAP and PKMAP in area covered by one PTE table.

Quoted 3 lines

I tested this a bit today on a Bamboo board. Overall, it functioned well enough to not crash :). Note that I also included Hollis' memory size alignment patch which is required.

The code looks pretty clean now. I think if we're going to include this patch it should go in now.

Quoted 438 lines

---

arch/powerpc/Kconfig                   |   58 ++++++++++++++++++++++++--------
arch/powerpc/include/asm/highmem.h     |   19 +++++++++-
arch/powerpc/include/asm/mmu-44x.h     |   17 +++++++++
arch/powerpc/include/asm/page.h        |   13 ++++---
arch/powerpc/include/asm/page_32.h     |    7 +++-
arch/powerpc/kernel/asm-offsets.c      |    4 ++
arch/powerpc/kernel/head_44x.S         |   23 ++++++++-----
arch/powerpc/kernel/misc_32.S          |   12 +++---
arch/powerpc/mm/pgtable_32.c           |   23 ++++++++-----
arch/powerpc/platforms/Kconfig.cputype |    2 +-
10 files changed, 130 insertions(+), 48 deletions(-)
arch/powerpc/Kconfig +35 -9
index 525c13a..cd8ff7c 100644
@@ -401,23 +401,53 @@ config PPC_HAS_HASH_64K
 	depends on PPC64
 	default n
 
-config PPC_64K_PAGES
-	bool "64k page size"
-	depends on PPC64
-	select PPC_HAS_HASH_64K
+choice
+	prompt "Page size"
+	default PPC_4K_PAGES
 	help
-	  This option changes the kernel logical page size to 64k. On machines
-	  without processor support for 64k pages, the kernel will simulate
-	  them by loading each individual 4k page on demand transparently,
-	  while on hardware with such support, it will be used to map
-	  normal application pages.
+	  Select the kernel logical page size. Increasing the page size
+	  will reduce software overhead at each page boundary, allow
+	  hardware prefetch mechanisms to be more effective, and allow
+	  larger dma transfers increasing IO efficiency and reducing
+	  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
int "Maximum zone order"

arch/powerpc/Kconfig +8 -4
-	range 9 64 if PPC_64K_PAGES
-	default "9" if PPC_64K_PAGES
-	range 13 64 if PPC64 && !PPC_64K_PAGES
-	default "13" if PPC64 && !PPC_64K_PAGES
+	range 9 64 if PPC_STD_MMU_64 && PPC_64K_PAGES
+	default "9" if PPC_STD_MMU_64 && PPC_64K_PAGES
+	range 13 64 if PPC_STD_MMU_64 && !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
	default "11"
	help
arch/powerpc/Kconfig +0 -0
@@ -437,7 +467,7 @@ config FORCE_MAX_ZONEORDER
 

config PPC_SUBPAGE_PROT
bool "Support setting protections for 4k subpages"

arch/powerpc/Kconfig +1 -1
-	depends on PPC_64K_PAGES
+	depends on PPC_STD_MMU_64 && PPC_64K_PAGES

help
This option adds support for a system call to allow user programs to set access permissions (read/write, readonly, or no access)

arch/powerpc/include/asm/highmem.h +17 -2
index 91c5895..7d6bb37 100644
@@ -38,9 +38,24 @@ extern pte_t *pkmap_page_table;
 * easily, subsequent pte tables have to be allocated in one physical
 * 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)
+#endif
+#define LAST_PKMAP_MASK	(LAST_PKMAP-1)
 #define PKMAP_NR(virt)  ((virt-PKMAP_BASE) >> PAGE_SHIFT)
 #define PKMAP_ADDR(nr)  (PKMAP_BASE + ((nr) << PAGE_SHIFT))
 
arch/powerpc/include/asm/mmu-44x.h +17 -0
index a825524..73e1909 100644
@@ -4,6 +4,8 @@
 * PPC440 support
 */
 
+#include <asm/page.h>
+
 #define PPC44x_MMUCR_TID	0x000000ff
 #define PPC44x_MMUCR_STS	0x00010000
 
@@ -73,4 +75,19 @@ typedef struct {
 /* Size of the TLBs used for pinning in lowmem */
 #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_ */
arch/powerpc/include/asm/page.h +8 -5
index c0b8d4a..197d569 100644
@@ -19,12 +19,15 @@
 #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
 * 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
+#elif defined(CONFIG_PPC_16K_PAGES)
+#define PAGE_SHIFT		14
 #else
 #define PAGE_SHIFT		12
 #endif
@@ -151,7 +154,7 @@ typedef struct { pte_basic_t pte; } pte_t;
 /* 64k pages additionally define a bigger "real PTE" type that gathers
 * 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;
 #else
 typedef struct { pte_t pte; } real_pte_t;
@@ -191,10 +194,10 @@ typedef pte_basic_t pte_t;
 #define pte_val(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;
 #else
-typedef unsigned long real_pte_t;
+typedef pte_t real_pte_t;
 #endif
 
 
arch/powerpc/include/asm/page_32.h +5 -2
index d77072a..1458d95 100644
@@ -19,6 +19,8 @@
 #define PTE_FLAGS_OFFSET	0
 #endif
 
+#define PTE_SHIFT	(PAGE_SHIFT - PTE_T_LOG2)	/* full page */
+
 #ifndef __ASSEMBLY__
 /*
 * The basic type of a PTE - 64 bits for those CPUs with > 32 bit
@@ -26,10 +28,8 @@
 */
 #ifdef CONFIG_PTE_64BIT
 typedef unsigned long long pte_basic_t;
-#define PTE_SHIFT	(PAGE_SHIFT - 3)	/* 512 ptes per page */
 #else
 typedef unsigned long pte_basic_t;
-#define PTE_SHIFT	(PAGE_SHIFT - 2)	/* 1024 ptes per page */
 #endif
 
 struct page;
@@ -39,6 +39,9 @@ extern void copy_page(void *to, void *from);
 
 #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 /* _ASM_POWERPC_PAGE_32_H */
arch/powerpc/kernel/asm-offsets.c +4 -0
index 75c5dd0..0142318 100644
@@ -378,6 +378,10 @@ int main(void)
 	DEFINE(VCPU_FAULT_DEAR, offsetof(struct kvm_vcpu, arch.fault_dear));
 	DEFINE(VCPU_FAULT_ESR, offsetof(struct kvm_vcpu, arch.fault_esr));
 #endif
+#ifdef CONFIG_44x
+	DEFINE(PGD_T_LOG2, PGD_T_LOG2);
+	DEFINE(PTE_T_LOG2, PTE_T_LOG2);
+#endif
 
 	return 0;
 }
arch/powerpc/kernel/head_44x.S +8 -4
index f3a1ea9..3bf6bd1 100644
@@ -391,12 +391,14 @@ interrupt_base:
 	rlwimi	r13,r12,10,30,30
 
 	/* 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 */
 	rlwinm.	r12, r11, 0, 0, 20	/* Extract pt base address */
 	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	r12, 4(r12)		/* Get low word of pte entry */
 
@@ -485,12 +487,14 @@ tlb_44x_patch_hwater_D:
 	/* Make up the required permissions */
 	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 */
 	rlwinm.	r12, r11, 0, 0, 20	/* Extract pt base address */
 	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	r12, 4(r12)		/* Get low word of pte entry */
 
@@ -554,15 +558,16 @@ tlb_44x_patch_hwater_I:
 */

finish_tlb_load:

	/* Combine RPN & ERPN an write WS 0 */
arch/powerpc/kernel/head_44x.S +1 -1
-	rlwimi	r11,r12,0,0,19
+	rlwimi	r11,r12,0,0,31-PAGE_SHIFT
	tlbwe	r11,r13,PPC44x_TLB_XLAT

	/*
	 * Create WS1. This is the faulting address (EPN),
	 * page size, and valid flag.
	 */
arch/powerpc/kernel/head_44x.S +3 -2
-	li	r11,PPC44x_TLB_VALID | PPC44x_TLB_4K
-	rlwimi	r10,r11,0,20,31			/* Insert valid and page size*/
+	li	r11,PPC44x_TLB_VALID | PPC44x_TLBE_SIZE
+	/* Insert valid and page size */
+	rlwimi	r10,r11,0,PPC44x_PTE_ADD_MASK_BIT,31
	tlbwe	r10,r13,PPC44x_TLB_PAGEID	/* Write PAGEID */

	/* And WS 2 */
arch/powerpc/kernel/head_44x.S +1 -1
@@ -634,12 +639,12 @@ _GLOBAL(set_context)
 * goes at the beginning of the data segment, which is page-aligned.
 */
 	.data
-	.align	12
+	.align	PAGE_SHIFT
 	.globl	sdata

sdata:
.globl empty_zero_page
empty_zero_page:

arch/powerpc/kernel/head_44x.S +1 -1
-	.space	4096
+	.space	PAGE_SIZE

/*
* To support >32-bit physical addresses, we use an 8KB pgdir.

arch/powerpc/kernel/misc_32.S +0 -0
index bdc8b0e..950b708 100644
@@ -647,8 +647,8 @@ _GLOBAL(__flush_dcache_icache)

BEGIN_FTR_SECTION
blr
END_FTR_SECTION_IFSET(CPU_FTR_COHERENT_ICACHE)

arch/powerpc/kernel/misc_32.S +2 -2
-	rlwinm	r3,r3,0,0,19			/* Get page base address */
-	li	r4,4096/L1_CACHE_BYTES	/* Number of lines in a page */
+	rlwinm	r3,r3,0,0,31-PAGE_SHIFT		/* Get page base address */
+	li	r4,PAGE_SIZE/L1_CACHE_BYTES	/* Number of lines in a page */
	mtctr	r4
	mr	r6,r3

0: dcbst 0,r3 /* Write line to ram */

arch/powerpc/kernel/misc_32.S +2 -2
@@ -688,8 +688,8 @@ END_FTR_SECTION_IFSET(CPU_FTR_COHERENT_ICACHE)
 	rlwinm	r0,r10,0,28,26			/* clear DR */
 	mtmsr	r0
 	isync
-	rlwinm	r3,r3,0,0,19			/* Get page base address */
-	li	r4,4096/L1_CACHE_BYTES	/* Number of lines in a page */
+	rlwinm	r3,r3,0,0,31-PAGE_SHIFT		/* Get page base address */
+	li	r4,PAGE_SIZE/L1_CACHE_BYTES	/* Number of lines in a page */
 	mtctr	r4
 	mr	r6,r3

0: dcbst 0,r3 /* Write line to ram */

arch/powerpc/kernel/misc_32.S +2 -2
@@ -713,7 +713,7 @@ END_FTR_SECTION_IFSET(CPU_FTR_COHERENT_ICACHE)
 * void clear_pages(void *page, int order) ;
 */
 _GLOBAL(clear_pages)
-	li	r0,4096/L1_CACHE_BYTES
+	li	r0,PAGE_SIZE/L1_CACHE_BYTES
 	slw	r0,r0,r4
 	mtctr	r0
 #ifdef CONFIG_8xx
@@ -771,7 +771,7 @@ _GLOBAL(copy_page)
 	dcbt	r5,r4
 	li	r11,L1_CACHE_BYTES+4
 #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

2:
mtctr r0

arch/powerpc/mm/pgtable_32.c +14 -9
index c31d6d2..f966a5e 100644
@@ -72,24 +72,29 @@ extern unsigned long p_mapped_by_tlbcam(unsigned long pa);
 #define p_mapped_by_tlbcam(x)	(0UL)
 #endif /* HAVE_TLBCAM */
 
-#ifdef CONFIG_PTE_64BIT
-/* Some processors use an 8kB pgdir because they have 8-byte Linux PTEs. */
-#define PGDIR_ORDER	1
-#else
-#define PGDIR_ORDER	0
-#endif
+#define PGDIR_ORDER	(32 + PGD_T_LOG2 - PGDIR_SHIFT)
 
 pgd_t *pgd_alloc(struct mm_struct *mm)
 {
 	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;
 }
 
 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)
@@ -400,7 +405,7 @@ void kernel_map_pages(struct page *page, int numpages, int enable)
 #endif /* CONFIG_DEBUG_PAGEALLOC */
 
 static int fixmaps;
-unsigned long FIXADDR_TOP = 0xfffff000;
+unsigned long FIXADDR_TOP = (-PAGE_SIZE);
 EXPORT_SYMBOL(FIXADDR_TOP);
 
 void __set_fixmap (enum fixed_addresses idx, phys_addr_t phys, pgprot_t flags)
arch/powerpc/platforms/Kconfig.cputype +0 -0
index 548efa5..51098bc 100644
@@ -204,7 +204,7 @@ config PPC_STD_MMU_32
 

config PPC_MM_SLICES
bool

arch/powerpc/platforms/Kconfig.cputype +1 -1
-	default y if HUGETLB_PAGE || PPC_64K_PAGES
+	default y if HUGETLB_PAGE || (PPC_STD_MMU_64 && PPC_64K_PAGES)

default n

config VIRT_CPU_ACCOUNTING

Signature · 6 lines
1.5.6.1

_______________________________________________
Linuxppc-dev mailing list
[email protected]
https://ozlabs.org/mailman/listinfo/linuxppc-dev
#12 lore raw
Quoted 14 lines · Josh Boyer
Quoted 9 lines · Ilya Yanok

This patch adds support for page sizes bigger than 4K (16K/64K) on PPC 44x.
PGDIR table is much smaller than page in case of 16K/64K pages (512 and 32 bytes resp.) so we allocate PGDIR with kzalloc() instead of __get_free_pages().
PTE table covers rather big memory area in case of 16K/64K pages (32MB and 512MB resp.) so we can easily put FIXMAP and PKMAP in area covered by one PTE table.

Quoted 3 lines
Quoted 8 lines

I tested this a bit today on a Bamboo board. Overall, it functioned well enough to not crash :). Note that I also included Hollis' memory size alignment patch which is required.

The code looks pretty clean now. I think if we're going to include this patch it should go in now.

Ben, Paul,

What else is needed to get this patch included?

josh

#13 lore raw
Quoted 9 lines
Quoted 5 lines

The code looks pretty clean now. I think if we're going to include this patch it should go in now.

Ben, Paul,

What else is needed to get this patch included?

Can you remind us the pre-req ?

Cheers,
Ben.