Patchwork [2/2] powerpc: support for 256K pages on PPC 44x

login
register
mail settings
Submitter Ilya Yanok
Date Oct. 16, 2008, 2:22 a.m.
Message ID <1224123753-20907-3-git-send-email-yanok@emcraft.com>
Download mbox | patch
Permalink /patch/4656/
State Superseded, archived
Delegated to: Josh Boyer
Headers show

Comments

Ilya Yanok - Oct. 16, 2008, 2:22 a.m.
This patch adds support for 256K pages on PPC 44x along with
some hacks needed for this.

Signed-off-by: Yuri Tikhonov <yur@emcraft.com>
Signed-off-by: Vladimir Panfilov <pvr@emcraft.com>
Signed-off-by: Ilya Yanok <yanok@emcraft.com>
---
 arch/powerpc/Kconfig                   |    8 ++++++++
 arch/powerpc/include/asm/highmem.h     |    3 ++-
 arch/powerpc/include/asm/mmu-44x.h     |    2 ++
 arch/powerpc/include/asm/page.h        |    6 ++++--
 arch/powerpc/include/asm/page_32.h     |    4 ++++
 arch/powerpc/include/asm/thread_info.h |    4 ++++
 arch/powerpc/kernel/head_booke.h       |   11 +++++++++--
 7 files changed, 33 insertions(+), 5 deletions(-)
Milton Miller - Nov. 10, 2008, 3:09 p.m.
On 2008-10-16 at 02:22:32, Ilya Yanok wrote:
>
> This patch adds support for 256K pages on PPC 44x along with
> some hacks needed for this.

This description is insufficient, it describes neither the hacks nor 
why they are required.

> diff --git a/arch/powerpc/Kconfig b/arch/powerpc/Kconfig
> index 9627cfd..7df5528 100644
> --- a/arch/powerpc/Kconfig
> +++ b/arch/powerpc/Kconfig
> @@ -425,6 +425,14 @@  config PPC_64K_PAGES
>         bool "64k page size" if 44x || PPC64
>         select PPC_HAS_HASH_64K if PPC64
>
> +config PPC_256K_PAGES
> +       bool "256k page size" if 44x
> +       depends on BROKEN

I know it was not your original choice, but I feel BROKEN is too 
strong.  It should be under embedded, and maybe a second choice "I am 
using standard binutils" that defaults to yes and is set to no (so that 
all yes config does not enable it by accident), but I feel labeling 
this BROKEN for an external dependency is wrong.

> +       help
> +         ELF standard supports only page sizes up to 64K so you need 
> a patched
> +         binutils in order to use 256K pages. Chose it only if you 
> know what
> +         you are doing.
> +
>  endchoice
>
>  config FORCE_MAX_ZONEORDER
> diff --git a/arch/powerpc/include/asm/highmem.h 
> b/arch/powerpc/include/asm/highmem.h
> index dc1132c..0b4ac6a 100644
> --- a/arch/powerpc/include/asm/highmem.h
> +++ b/arch/powerpc/include/asm/highmem.h
> @@ -38,7 +38,8 @@  extern pte_t *pkmap_page_table;
>   * easily, subsequent pte tables have to be allocated in one physical
>   * chunk of RAM.
>   */
> -#if defined(CONFIG_PPC_64K_PAGES) && !defined(CONFIG_PPC64)
> +#if defined(CONFIG_PPC_256K_PAGES) || \
> +       (defined(CONFIG_PPC_64K_PAGES) && !defined(CONFIG_PPC64))

Just because 256K pages is not selectable on PPC64 doesn't mean that 
this is the right grouping.   However, as I said on the previous patch, 
this file is never included on PPC64 so the clause should be removed.


> diff --git a/arch/powerpc/include/asm/page_32.h 
> b/arch/powerpc/include/asm/page_32.h
> index ebfae53..273369a 100644
> --- a/arch/powerpc/include/asm/page_32.h
> +++ b/arch/powerpc/include/asm/page_32.h
> @@ -20,7 +20,11 @@
>   */
>  #ifdef CONFIG_PTE_64BIT
>  typedef unsigned long long pte_basic_t;
> +#ifdef CONFIG_PPC_256K_PAGES
> +#define PTE_SHIFT       (PAGE_SHIFT - 7)

This seems to be missing the comment on how many ptes are actually in 
the page that are in the other if and else cases.

> +#else
>  #define PTE_SHIFT      (PAGE_SHIFT - 3)        /* 512 ptes per page */
> +#endif
>  #else
>  typedef unsigned long pte_basic_t;
>  #define PTE_SHIFT      (PAGE_SHIFT - 2)        /* 1024 ptes per page 
> */
> diff --git a/arch/powerpc/include/asm/thread_info.h 
> b/arch/powerpc/include/asm/thread_info.h
> index 9665a26..3c8bbab 100644
> --- a/arch/powerpc/include/asm/thread_info.h
> +++ b/arch/powerpc/include/asm/thread_info.h
> @@ -15,8 +15,12 @@
>  #ifdef CONFIG_PPC64
>  #define THREAD_SHIFT           14
>  #else
> +#ifdef CONFIG_PPC_256K_PAGES
> +#define THREAD_SHIFT           15
> +#else
>  #define THREAD_SHIFT           13
>  #endif
> +#endif
>
>  #define THREAD_SIZE            (1 << THREAD_SHIFT)


So this appears to be the one hack.  For some unknown reason, you are 
increasing the kernel stack from 8k to 32k when selecting 256k pages.   
What data structure is ballooning in size so much that you need the 
additional kernel stack space on 256k pages but not on 64k pages?  Is 
this really tied to 256k base page size?

>
> diff --git a/arch/powerpc/kernel/head_booke.h 
> b/arch/powerpc/kernel/head_booke.h
> index fce2df9..acd4b47 100644
> --- a/arch/powerpc/kernel/head_booke.h
> +++ b/arch/powerpc/kernel/head_booke.h
> @@ -9,6 +9,13 @@
>                 li      r26,vector_label@l;             \
>                 mtspr   SPRN_IVOR##vector_number,r26;   \
>                 sync
> +#ifndef CONFIG_PPC_256K_PAGES
> +#define ALLOC_STACK_FRAME(reg, val)    addi    reg,reg,val
> +#else
> +#define ALLOC_STACK_FRAME(reg, val)                    \
> +               addis   reg,reg,val@ha;                 \
> +               addi    reg,reg,val@l
> +#endif

And this is directly related to choosing the stack size of 32k, which 
can not be added in a single instruction and larger even than what the 
64 bit kernel uses.  So even further explanation of the analysis is 
required.

>
>  #define NORMAL_EXCEPTION_PROLOG                                       
>               \
>         mtspr   SPRN_SPRG0,r10;         /* save two registers to work 
> with */\
> @@ -20,7 +27,7 @@
>         beq     1f;                                                    
>       \
>         mfspr   r1,SPRN_SPRG3;          /* if from user, start at top 
> of   */\
>         lwz     r1,THREAD_INFO-THREAD(r1); /* this thread's kernel 
> stack   */\
> -       addi    r1,r1,THREAD_SIZE;                                     
>       \
> +       ALLOC_STACK_FRAME(r1, THREAD_SIZE);                            
>               \
>  1:     subi    r1,r1,INT_FRAME_SIZE;   /* Allocate an exception frame 
>     */\
>         mr      r11,r1;                                                
>       \
>         stw     r10,_CCR(r11);          /* save various registers      
>     */\
> @@ -112,7 +119,7 @@
>         andi.   r10,r10,MSR_PR;                                        
>       \
>         mfspr   r11,SPRN_SPRG3;         /* if from user, start at top 
> of   */\
>         lwz     r11,THREAD_INFO-THREAD(r11); /* this thread's kernel 
> stack */\
> -       addi    r11,r11,EXC_LVL_FRAME_OVERHEAD; /* allocate stack 
> frame    */\
> +       ALLOC_STACK_FRAME(r11 ,EXC_LVL_FRAME_OVERHEAD); /* allocate 
> stack frame    */\
>         beq     1f;                                                    
>       \
>         /* COMING FROM USER MODE */                                    
>       \
>         stw     r9,_CCR(r11);           /* save CR                     
>     */\

milton
Ilya Yanok - Nov. 10, 2008, 4:24 p.m.
Hello Milton,

Milton Miller wrote:
>> This patch adds support for 256K pages on PPC 44x along with
>> some hacks needed for this.
>
> This description is insufficient, it describes neither the hacks nor
> why they are required.

Ok. Actually there is only one hack -- increasing kernel stack size. We
do this because with 256K pages we get division by zero in kernel/fork.c:

        /*
         * The default maximum number of threads is set to a safe
         * value: the thread structures can take up at most half
         * of memory.
         */
        max_threads = mempages / (8 * THREAD_SIZE / PAGE_SIZE);

so setting THREAD_SIZE to bigger value we can avoid this. I don't think
it's very clean solution but at least we stay powerpc-specific.

>> diff --git a/arch/powerpc/Kconfig b/arch/powerpc/Kconfig
>> index 9627cfd..7df5528 100644
>> --- a/arch/powerpc/Kconfig
>> +++ b/arch/powerpc/Kconfig
>> @@ -425,6 +425,14 @@  config PPC_64K_PAGES
>>         bool "64k page size" if 44x || PPC64
>>         select PPC_HAS_HASH_64K if PPC64
>>
>> +config PPC_256K_PAGES
>> +       bool "256k page size" if 44x
>> +       depends on BROKEN
>
> I know it was not your original choice, but I feel BROKEN is too
> strong.  It should be under embedded, and maybe a second choice "I am
> using standard binutils" that defaults to yes and is set to no (so
> that all yes config does not enable it by accident), but I feel
> labeling this BROKEN for an external dependency is wrong.

Hm... maybe you are right. I'm looking forward for additional comments
on this.

>> +       help
>> +         ELF standard supports only page sizes up to 64K so you need
>> a patched
>> +         binutils in order to use 256K pages. Chose it only if you
>> know what
>> +         you are doing.
>> +
>>  endchoice
>>
>>  config FORCE_MAX_ZONEORDER
>> diff --git a/arch/powerpc/include/asm/highmem.h
>> b/arch/powerpc/include/asm/highmem.h
>> index dc1132c..0b4ac6a 100644
>> --- a/arch/powerpc/include/asm/highmem.h
>> +++ b/arch/powerpc/include/asm/highmem.h
>> @@ -38,7 +38,8 @@  extern pte_t *pkmap_page_table;
>>   * easily, subsequent pte tables have to be allocated in one physical
>>   * chunk of RAM.
>>   */
>> -#if defined(CONFIG_PPC_64K_PAGES) && !defined(CONFIG_PPC64)
>> +#if defined(CONFIG_PPC_256K_PAGES) || \
>> +       (defined(CONFIG_PPC_64K_PAGES) && !defined(CONFIG_PPC64))
>
> Just because 256K pages is not selectable on PPC64 doesn't mean that
> this is the right grouping.   However, as I said on the previous
> patch, this file is never included on PPC64 so the clause should be
> removed.

Ok.

>> diff --git a/arch/powerpc/include/asm/page_32.h
>> b/arch/powerpc/include/asm/page_32.h
>> index ebfae53..273369a 100644
>> --- a/arch/powerpc/include/asm/page_32.h
>> +++ b/arch/powerpc/include/asm/page_32.h
>> @@ -20,7 +20,11 @@
>>   */
>>  #ifdef CONFIG_PTE_64BIT
>>  typedef unsigned long long pte_basic_t;
>> +#ifdef CONFIG_PPC_256K_PAGES
>> +#define PTE_SHIFT       (PAGE_SHIFT - 7)
>
> This seems to be missing the comment on how many ptes are actually in
> the page that are in the other if and else cases.

Ok. I'll fix this. Actually it's another hack: we don't use full page
for PTE table because we need to reserve something for PGD

>> +#else
>>  #define PTE_SHIFT      (PAGE_SHIFT - 3)        /* 512 ptes per page */
>> +#endif
>>  #else
>>  typedef unsigned long pte_basic_t;
>>  #define PTE_SHIFT      (PAGE_SHIFT - 2)        /* 1024 ptes per page */
>> diff --git a/arch/powerpc/include/asm/thread_info.h
>> b/arch/powerpc/include/asm/thread_info.h
>> index 9665a26..3c8bbab 100644
>> --- a/arch/powerpc/include/asm/thread_info.h
>> +++ b/arch/powerpc/include/asm/thread_info.h
>> @@ -15,8 +15,12 @@
>>  #ifdef CONFIG_PPC64
>>  #define THREAD_SHIFT           14
>>  #else
>> +#ifdef CONFIG_PPC_256K_PAGES
>> +#define THREAD_SHIFT           15
>> +#else
>>  #define THREAD_SHIFT           13
>>  #endif
>> +#endif
>>
>>  #define THREAD_SIZE            (1 << THREAD_SHIFT)
>
>
> So this appears to be the one hack.  For some unknown reason, you are
> increasing the kernel stack from 8k to 32k when selecting 256k
> pages.   What data structure is ballooning in size so much that you
> need the additional kernel stack space on 256k pages but not on 64k
> pages?  Is this really tied to 256k base page size?

We don't really need additional stack space. Just trying to avoid
division by zero.

Regards, Ilya.

Patch

diff --git a/arch/powerpc/Kconfig b/arch/powerpc/Kconfig
index 9627cfd..7df5528 100644
--- a/arch/powerpc/Kconfig
+++ b/arch/powerpc/Kconfig
@@ -425,6 +425,14 @@  config PPC_64K_PAGES
 	bool "64k page size" if 44x || PPC64
 	select PPC_HAS_HASH_64K if PPC64
 
+config PPC_256K_PAGES
+	bool "256k page size" if 44x
+	depends on BROKEN
+	help
+	  ELF standard supports only page sizes up to 64K so you need a patched
+	  binutils in order to use 256K pages. Chose it only if you know what
+	  you are doing.
+
 endchoice
 
 config FORCE_MAX_ZONEORDER
diff --git a/arch/powerpc/include/asm/highmem.h b/arch/powerpc/include/asm/highmem.h
index dc1132c..0b4ac6a 100644
--- a/arch/powerpc/include/asm/highmem.h
+++ b/arch/powerpc/include/asm/highmem.h
@@ -38,7 +38,8 @@  extern pte_t *pkmap_page_table;
  * easily, subsequent pte tables have to be allocated in one physical
  * chunk of RAM.
  */
-#if defined(CONFIG_PPC_64K_PAGES) && !defined(CONFIG_PPC64)
+#if defined(CONFIG_PPC_256K_PAGES) || \
+	(defined(CONFIG_PPC_64K_PAGES) && !defined(CONFIG_PPC64))
 #define PKMAP_ORDER	(27 - PAGE_SHIFT)
 #define LAST_PKMAP	(1 << PKMAP_ORDER)
 #define PKMAP_BASE	(FIXADDR_START - PAGE_SIZE*(LAST_PKMAP + 1))
diff --git a/arch/powerpc/include/asm/mmu-44x.h b/arch/powerpc/include/asm/mmu-44x.h
index 2ca18e8..b943462 100644
--- a/arch/powerpc/include/asm/mmu-44x.h
+++ b/arch/powerpc/include/asm/mmu-44x.h
@@ -81,6 +81,8 @@  typedef struct {
 #define PPC44x_TLBE_SIZE	PPC44x_TLB_16K
 #elif (PAGE_SHIFT == 16)
 #define PPC44x_TLBE_SIZE	PPC44x_TLB_64K
+#elif (PAGE_SHIFT == 18)
+#define PPC44x_TLBE_SIZE	PPC44x_TLB_256K
 #else
 #error "Unsupported PAGE_SIZE"
 #endif
diff --git a/arch/powerpc/include/asm/page.h b/arch/powerpc/include/asm/page.h
index 537d5b1..f42c918 100644
--- a/arch/powerpc/include/asm/page.h
+++ b/arch/powerpc/include/asm/page.h
@@ -15,12 +15,14 @@ 
 #include <asm/types.h>
 
 /*
- * On regular PPC32 page size is 4K (but we support 4K/16K/64K pages
+ * On regular PPC32 page size is 4K (but we support 4K/16K/64K/256K 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.
  */
-#if defined(CONFIG_PPC_64K_PAGES)
+#if defined(CONFIG_PPC_256K_PAGES)
+#define PAGE_SHIFT		18
+#elif defined(CONFIG_PPC_64K_PAGES)
 #define PAGE_SHIFT		16
 #elif defined(CONFIG_PPC_16K_PAGES)
 #define PAGE_SHIFT		14
diff --git a/arch/powerpc/include/asm/page_32.h b/arch/powerpc/include/asm/page_32.h
index ebfae53..273369a 100644
--- a/arch/powerpc/include/asm/page_32.h
+++ b/arch/powerpc/include/asm/page_32.h
@@ -20,7 +20,11 @@ 
  */
 #ifdef CONFIG_PTE_64BIT
 typedef unsigned long long pte_basic_t;
+#ifdef CONFIG_PPC_256K_PAGES
+#define PTE_SHIFT       (PAGE_SHIFT - 7)
+#else
 #define PTE_SHIFT	(PAGE_SHIFT - 3)	/* 512 ptes per page */
+#endif
 #else
 typedef unsigned long pte_basic_t;
 #define PTE_SHIFT	(PAGE_SHIFT - 2)	/* 1024 ptes per page */
diff --git a/arch/powerpc/include/asm/thread_info.h b/arch/powerpc/include/asm/thread_info.h
index 9665a26..3c8bbab 100644
--- a/arch/powerpc/include/asm/thread_info.h
+++ b/arch/powerpc/include/asm/thread_info.h
@@ -15,8 +15,12 @@ 
 #ifdef CONFIG_PPC64
 #define THREAD_SHIFT		14
 #else
+#ifdef CONFIG_PPC_256K_PAGES
+#define THREAD_SHIFT		15
+#else
 #define THREAD_SHIFT		13
 #endif
+#endif
 
 #define THREAD_SIZE		(1 << THREAD_SHIFT)
 
diff --git a/arch/powerpc/kernel/head_booke.h b/arch/powerpc/kernel/head_booke.h
index fce2df9..acd4b47 100644
--- a/arch/powerpc/kernel/head_booke.h
+++ b/arch/powerpc/kernel/head_booke.h
@@ -9,6 +9,13 @@ 
 		li	r26,vector_label@l; 		\
 		mtspr	SPRN_IVOR##vector_number,r26;	\
 		sync
+#ifndef CONFIG_PPC_256K_PAGES
+#define ALLOC_STACK_FRAME(reg, val)	addi	reg,reg,val
+#else
+#define ALLOC_STACK_FRAME(reg, val)			\
+		addis	reg,reg,val@ha;			\
+		addi	reg,reg,val@l
+#endif
 
 #define NORMAL_EXCEPTION_PROLOG						     \
 	mtspr	SPRN_SPRG0,r10;		/* save two registers to work with */\
@@ -20,7 +27,7 @@ 
 	beq	1f;							     \
 	mfspr	r1,SPRN_SPRG3;		/* if from user, start at top of   */\
 	lwz	r1,THREAD_INFO-THREAD(r1); /* this thread's kernel stack   */\
-	addi	r1,r1,THREAD_SIZE;					     \
+	ALLOC_STACK_FRAME(r1, THREAD_SIZE);					     \
 1:	subi	r1,r1,INT_FRAME_SIZE;	/* Allocate an exception frame     */\
 	mr	r11,r1;							     \
 	stw	r10,_CCR(r11);          /* save various registers	   */\
@@ -112,7 +119,7 @@ 
 	andi.	r10,r10,MSR_PR;						     \
 	mfspr	r11,SPRN_SPRG3;		/* if from user, start at top of   */\
 	lwz	r11,THREAD_INFO-THREAD(r11); /* this thread's kernel stack */\
-	addi	r11,r11,EXC_LVL_FRAME_OVERHEAD;	/* allocate stack frame    */\
+	ALLOC_STACK_FRAME(r11 ,EXC_LVL_FRAME_OVERHEAD);	/* allocate stack frame    */\
 	beq	1f;							     \
 	/* COMING FROM USER MODE */					     \
 	stw	r9,_CCR(r11);		/* save CR			   */\