From: "Aneesh Kumar K.V" <aneesh.ku...@linux.vnet.ibm.com>

This patch makes the high psizes mask as an unsigned char array
so that we can have more than 16TB. Currently we support upto
64TB

Signed-off-by: Aneesh Kumar K.V <aneesh.ku...@linux.vnet.ibm.com>
---
 arch/powerpc/include/asm/mmu-hash64.h |    7 ++-
 arch/powerpc/include/asm/page_64.h    |    7 ++-
 arch/powerpc/mm/hash_utils_64.c       |   15 +++---
 arch/powerpc/mm/slb_low.S             |   35 ++++++++----
 arch/powerpc/mm/slice.c               |   95 +++++++++++++++++++++------------
 5 files changed, 109 insertions(+), 50 deletions(-)

diff --git a/arch/powerpc/include/asm/mmu-hash64.h 
b/arch/powerpc/include/asm/mmu-hash64.h
index e48c66b..47ddfa1 100644
--- a/arch/powerpc/include/asm/mmu-hash64.h
+++ b/arch/powerpc/include/asm/mmu-hash64.h
@@ -456,7 +456,12 @@ typedef struct {
 
 #ifdef CONFIG_PPC_MM_SLICES
        u64 low_slices_psize;   /* SLB page size encodings */
-       u64 high_slices_psize;  /* 4 bits per slice for now */
+       /*
+        * FIXME!! it should be derived from PGTABLE_RANGE
+        * Right now we support 64TB and 4 bits for each
+        * 1TB slice we need 32 bytes for 64TB.
+        */
+       unsigned char high_slices_psize[32];  /* 4 bits per slice for now */
 #else
        u16 sllp;               /* SLB page size encoding */
 #endif
diff --git a/arch/powerpc/include/asm/page_64.h 
b/arch/powerpc/include/asm/page_64.h
index fed85e6..8806e87 100644
--- a/arch/powerpc/include/asm/page_64.h
+++ b/arch/powerpc/include/asm/page_64.h
@@ -82,7 +82,12 @@ extern u64 ppc64_pft_size;
 
 struct slice_mask {
        u16 low_slices;
-       u16 high_slices;
+       /*
+        * FIXME!!
+        * This should be derived out of PGTABLE_RANGE. For the current
+        * max 64TB, u64 should be ok.
+        */
+       u64 high_slices;
 };
 
 struct mm_struct;
diff --git a/arch/powerpc/mm/hash_utils_64.c b/arch/powerpc/mm/hash_utils_64.c
index 8b5d3c2..beace0b 100644
--- a/arch/powerpc/mm/hash_utils_64.c
+++ b/arch/powerpc/mm/hash_utils_64.c
@@ -804,16 +804,19 @@ unsigned int hash_page_do_lazy_icache(unsigned int pp, 
pte_t pte, int trap)
 #ifdef CONFIG_PPC_MM_SLICES
 unsigned int get_paca_psize(unsigned long addr)
 {
-       unsigned long index, slices;
+       u64 lpsizes;
+       unsigned char *hpsizes;
+       unsigned long index, mask_index;
 
        if (addr < SLICE_LOW_TOP) {
-               slices = get_paca()->context.low_slices_psize;
+               lpsizes = get_paca()->context.low_slices_psize;
                index = GET_LOW_SLICE_INDEX(addr);
-       } else {
-               slices = get_paca()->context.high_slices_psize;
-               index = GET_HIGH_SLICE_INDEX(addr);
+               return (lpsizes >> (index * 4)) & 0xF;
        }
-       return (slices >> (index * 4)) & 0xF;
+       hpsizes = get_paca()->context.high_slices_psize;
+       index = GET_HIGH_SLICE_INDEX(addr) >> 1;
+       mask_index = GET_HIGH_SLICE_INDEX(addr) - (index << 1);
+       return (hpsizes[index] >> (mask_index * 4)) & 0xF;
 }
 
 #else
diff --git a/arch/powerpc/mm/slb_low.S b/arch/powerpc/mm/slb_low.S
index b9ee79ce..c355af6 100644
--- a/arch/powerpc/mm/slb_low.S
+++ b/arch/powerpc/mm/slb_low.S
@@ -108,17 +108,34 @@ END_MMU_FTR_SECTION_IFCLR(MMU_FTR_1T_SEGMENT)
         * between 4k and 64k standard page size
         */
 #ifdef CONFIG_PPC_MM_SLICES
+       /* r10 have esid */
        cmpldi  r10,16
-
-       /* Get the slice index * 4 in r11 and matching slice size mask in r9 */
-       ld      r9,PACALOWSLICESPSIZE(r13)
-       sldi    r11,r10,2
+       /* below SLICE_LOW_TOP */
        blt     5f
-       ld      r9,PACAHIGHSLICEPSIZE(r13)
-       srdi    r11,r10,(SLICE_HIGH_SHIFT - SLICE_LOW_SHIFT - 2)
-       andi.   r11,r11,0x3c
-
-5:     /* Extract the psize and multiply to get an array offset */
+       /*
+        * Handle hpsizes,
+        * r9 is get_paca()->context.high_slices_psize[index], r11 is mask_index
+        * We use r10 here, later we restore it to esid.
+        * Can we use other register instead of r10 ?
+        */
+       srdi    r10,r10,(SLICE_HIGH_SHIFT - SLICE_LOW_SHIFT) /* index */
+       srdi    r11,r10,1                       /* r11 is array index */
+       addi    r9,r11,PACAHIGHSLICEPSIZE
+       lbzx    r9,r9,r13                       /* r9 is hpsizes[r11] */
+       sldi    r11,r11,1
+       subf    r11,r11,r10     /* mask_index = index - (array_index << 1) */
+       srdi    r10,r3,28       /* restore r10 with esid */
+       b       6f
+5:
+       /*
+        * Handle lpsizes
+        * r9 is get_paca()->context.low_slices_psize, r11 is index
+        */
+       ld      r9,PACALOWSLICESPSIZE(r13)
+       mr      r11,r10
+6:
+       sldi    r11,r11,2  /* index * 4 */
+       /* Extract the psize and multiply to get an array offset */
        srd     r9,r9,r11
        andi.   r9,r9,0xf
        mulli   r9,r9,MMUPSIZEDEFSIZE
diff --git a/arch/powerpc/mm/slice.c b/arch/powerpc/mm/slice.c
index 73709f7..302a481 100644
--- a/arch/powerpc/mm/slice.c
+++ b/arch/powerpc/mm/slice.c
@@ -42,7 +42,7 @@ int _slice_debug = 1;
 
 static void slice_print_mask(const char *label, struct slice_mask mask)
 {
-       char    *p, buf[16 + 3 + 16 + 1];
+       char    *p, buf[16 + 3 + 64 + 1];
        int     i;
 
        if (!_slice_debug)
@@ -142,19 +142,24 @@ static struct slice_mask slice_mask_for_free(struct 
mm_struct *mm)
 
 static struct slice_mask slice_mask_for_size(struct mm_struct *mm, int psize)
 {
+       unsigned char *hpsizes;
+       int index, mask_index;
        struct slice_mask ret = { 0, 0 };
        unsigned long i;
-       u64 psizes;
+       u64 lpsizes;
 
-       psizes = mm->context.low_slices_psize;
+       lpsizes = mm->context.low_slices_psize;
        for (i = 0; i < SLICE_NUM_LOW; i++)
-               if (((psizes >> (i * 4)) & 0xf) == psize)
+               if (((lpsizes >> (i * 4)) & 0xf) == psize)
                        ret.low_slices |= 1u << i;
 
-       psizes = mm->context.high_slices_psize;
-       for (i = 0; i < SLICE_NUM_HIGH; i++)
-               if (((psizes >> (i * 4)) & 0xf) == psize)
+       hpsizes = mm->context.high_slices_psize;
+       for (i = 0; i < SLICE_NUM_HIGH; i++) {
+               index = i >> 1;
+               mask_index = i - (index << 1);
+               if (((hpsizes[index] >> (mask_index * 4)) & 0xf) == psize)
                        ret.high_slices |= 1u << i;
+       }
 
        return ret;
 }
@@ -183,8 +188,10 @@ static void slice_flush_segments(void *parm)
 
 static void slice_convert(struct mm_struct *mm, struct slice_mask mask, int 
psize)
 {
+       int index, mask_index;
        /* Write the new slice psize bits */
-       u64 lpsizes, hpsizes;
+       unsigned char *hpsizes;
+       u64 lpsizes;
        unsigned long i, flags;
 
        slice_dbg("slice_convert(mm=%p, psize=%d)\n", mm, psize);
@@ -201,14 +208,18 @@ static void slice_convert(struct mm_struct *mm, struct 
slice_mask mask, int psiz
                        lpsizes = (lpsizes & ~(0xful << (i * 4))) |
                                (((unsigned long)psize) << (i * 4));
 
+       /* Assign the value back */
+       mm->context.low_slices_psize = lpsizes;
+
        hpsizes = mm->context.high_slices_psize;
-       for (i = 0; i < SLICE_NUM_HIGH; i++)
+       for (i = 0; i < SLICE_NUM_HIGH; i++) {
+               index = i >> 1;
+               mask_index = i - (index << 1);
                if (mask.high_slices & (1u << i))
-                       hpsizes = (hpsizes & ~(0xful << (i * 4))) |
-                               (((unsigned long)psize) << (i * 4));
-
-       mm->context.low_slices_psize = lpsizes;
-       mm->context.high_slices_psize = hpsizes;
+                       hpsizes[index] = (hpsizes[index] &
+                                         ~(0xf << (mask_index * 4))) |
+                               (((unsigned long)psize) << (mask_index * 4));
+       }
 
        slice_dbg(" lsps=%lx, hsps=%lx\n",
                  mm->context.low_slices_psize,
@@ -587,18 +598,19 @@ unsigned long arch_get_unmapped_area_topdown(struct file 
*filp,
 
 unsigned int get_slice_psize(struct mm_struct *mm, unsigned long addr)
 {
-       u64 psizes;
-       int index;
+       unsigned char *hpsizes;
+       int index, mask_index;
 
        if (addr < SLICE_LOW_TOP) {
-               psizes = mm->context.low_slices_psize;
+               u64 lpsizes;
+               lpsizes = mm->context.low_slices_psize;
                index = GET_LOW_SLICE_INDEX(addr);
-       } else {
-               psizes = mm->context.high_slices_psize;
-               index = GET_HIGH_SLICE_INDEX(addr);
+               return (lpsizes >> (index * 4)) & 0xf;
        }
-
-       return (psizes >> (index * 4)) & 0xf;
+       hpsizes = mm->context.high_slices_psize;
+       index = GET_HIGH_SLICE_INDEX(addr) >> 1;
+       mask_index = GET_HIGH_SLICE_INDEX(addr) - (index << 1);
+       return (hpsizes[index] >> (mask_index * 4)) & 0xf;
 }
 EXPORT_SYMBOL_GPL(get_slice_psize);
 
@@ -618,7 +630,9 @@ EXPORT_SYMBOL_GPL(get_slice_psize);
  */
 void slice_set_user_psize(struct mm_struct *mm, unsigned int psize)
 {
-       unsigned long flags, lpsizes, hpsizes;
+       int index, mask_index;
+       unsigned char *hpsizes;
+       unsigned long flags, lpsizes;
        unsigned int old_psize;
        int i;
 
@@ -639,15 +653,21 @@ void slice_set_user_psize(struct mm_struct *mm, unsigned 
int psize)
                if (((lpsizes >> (i * 4)) & 0xf) == old_psize)
                        lpsizes = (lpsizes & ~(0xful << (i * 4))) |
                                (((unsigned long)psize) << (i * 4));
+       /* Assign the value back */
+       mm->context.low_slices_psize = lpsizes;
 
        hpsizes = mm->context.high_slices_psize;
-       for (i = 0; i < SLICE_NUM_HIGH; i++)
-               if (((hpsizes >> (i * 4)) & 0xf) == old_psize)
-                       hpsizes = (hpsizes & ~(0xful << (i * 4))) |
-                               (((unsigned long)psize) << (i * 4));
+       for (i = 0; i < SLICE_NUM_HIGH; i++) {
+               index = i >> 1;
+               mask_index = i - (index << 1);
+               if (((hpsizes[index] >> (mask_index * 4)) & 0xf) == old_psize)
+                       hpsizes[index] = (hpsizes[index] &
+                                         ~(0xf << (mask_index * 4))) |
+                               (((unsigned long)psize) << (mask_index * 4));
+       }
+
+
 
-       mm->context.low_slices_psize = lpsizes;
-       mm->context.high_slices_psize = hpsizes;
 
        slice_dbg(" lsps=%lx, hsps=%lx\n",
                  mm->context.low_slices_psize,
@@ -660,18 +680,27 @@ void slice_set_user_psize(struct mm_struct *mm, unsigned 
int psize)
 void slice_set_psize(struct mm_struct *mm, unsigned long address,
                     unsigned int psize)
 {
+       unsigned char *hpsizes;
        unsigned long i, flags;
-       u64 *p;
+       u64 *lpsizes;
 
        spin_lock_irqsave(&slice_convert_lock, flags);
        if (address < SLICE_LOW_TOP) {
                i = GET_LOW_SLICE_INDEX(address);
-               p = &mm->context.low_slices_psize;
+               lpsizes = &mm->context.low_slices_psize;
+               *lpsizes = (*lpsizes & ~(0xful << (i * 4))) |
+                       ((unsigned long) psize << (i * 4));
        } else {
+               int index, mask_index;
                i = GET_HIGH_SLICE_INDEX(address);
-               p = &mm->context.high_slices_psize;
+               hpsizes = mm->context.high_slices_psize;
+               index = i >> 1;
+               mask_index = i - (index << 1);
+               hpsizes[index] = (hpsizes[index] &
+                                 ~(0xf << (mask_index * 4))) |
+                       (((unsigned long)psize) << (mask_index * 4));
        }
-       *p = (*p & ~(0xful << (i * 4))) | ((unsigned long) psize << (i * 4));
+
        spin_unlock_irqrestore(&slice_convert_lock, flags);
 
 #ifdef CONFIG_SPU_BASE
-- 
1.7.10

_______________________________________________
Linuxppc-dev mailing list
Linuxppc-dev@lists.ozlabs.org
https://lists.ozlabs.org/listinfo/linuxppc-dev

Reply via email to