Skip to content

Commit

Permalink
powerpc/mm: Increase the slice range to 64TB
Browse files Browse the repository at this point in the history
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

Reviewed-by: Paul Mackerras <paulus@samba.org>
Signed-off-by: Aneesh Kumar K.V <aneesh.kumar@linux.vnet.ibm.com>
Signed-off-by: Benjamin Herrenschmidt <benh@kernel.crashing.org>
  • Loading branch information
Aneesh Kumar K.V authored and Benjamin Herrenschmidt committed Sep 17, 2012
1 parent 6755008 commit 7aa0727
Show file tree
Hide file tree
Showing 5 changed files with 109 additions and 55 deletions.
6 changes: 5 additions & 1 deletion arch/powerpc/include/asm/mmu-hash64.h
Original file line number Diff line number Diff line change
Expand Up @@ -460,7 +460,11 @@ 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 */
/*
* 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
Expand Down
6 changes: 5 additions & 1 deletion arch/powerpc/include/asm/page_64.h
Original file line number Diff line number Diff line change
Expand Up @@ -82,7 +82,11 @@ extern u64 ppc64_pft_size;

struct slice_mask {
u16 low_slices;
u16 high_slices;
/*
* This should be derived out of PGTABLE_RANGE. For the current
* max 64TB, u64 should be ok.
*/
u64 high_slices;
};

struct mm_struct;
Expand Down
15 changes: 9 additions & 6 deletions arch/powerpc/mm/hash_utils_64.c
Original file line number Diff line number Diff line change
Expand Up @@ -803,16 +803,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);
mask_index = index & 0x1;
return (hpsizes[index >> 1] >> (mask_index * 4)) & 0xF;
}

#else
Expand Down
30 changes: 22 additions & 8 deletions arch/powerpc/mm/slb_low.S
Original file line number Diff line number Diff line change
Expand Up @@ -108,17 +108,31 @@ 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
/*
* Handle hpsizes,
* r9 is get_paca()->context.high_slices_psize[index], r11 is mask_index
*/
srdi r11,r10,(SLICE_HIGH_SHIFT - SLICE_LOW_SHIFT + 1) /* index */
addi r9,r11,PACAHIGHSLICEPSIZE
lbzx r9,r13,r9 /* r9 is hpsizes[r11] */
/* r11 = (r10 >> (SLICE_HIGH_SHIFT - SLICE_LOW_SHIFT)) & 0x1 */
rldicl r11,r10,(64 - (SLICE_HIGH_SHIFT - SLICE_LOW_SHIFT)),63
b 6f

5: /* Extract the psize and multiply to get an array offset */
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
Expand Down
107 changes: 68 additions & 39 deletions arch/powerpc/mm/slice.c
Original file line number Diff line number Diff line change
Expand Up @@ -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)
Expand All @@ -54,7 +54,7 @@ static void slice_print_mask(const char *label, struct slice_mask mask)
*(p++) = '-';
*(p++) = ' ';
for (i = 0; i < SLICE_NUM_HIGH; i++)
*(p++) = (mask.high_slices & (1 << i)) ? '1' : '0';
*(p++) = (mask.high_slices & (1ul << i)) ? '1' : '0';
*(p++) = 0;

printk(KERN_DEBUG "%s:%s\n", label, buf);
Expand Down Expand Up @@ -84,8 +84,8 @@ static struct slice_mask slice_range_to_mask(unsigned long start,
}

if ((start + len) > SLICE_LOW_TOP)
ret.high_slices = (1u << (GET_HIGH_SLICE_INDEX(end) + 1))
- (1u << GET_HIGH_SLICE_INDEX(start));
ret.high_slices = (1ul << (GET_HIGH_SLICE_INDEX(end) + 1))
- (1ul << GET_HIGH_SLICE_INDEX(start));

return ret;
}
Expand Down Expand Up @@ -135,26 +135,31 @@ static struct slice_mask slice_mask_for_free(struct mm_struct *mm)

for (i = 0; i < SLICE_NUM_HIGH; i++)
if (!slice_high_has_vma(mm, i))
ret.high_slices |= 1u << i;
ret.high_slices |= 1ul << i;

return ret;
}

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)
ret.high_slices |= 1u << i;
hpsizes = mm->context.high_slices_psize;
for (i = 0; i < SLICE_NUM_HIGH; i++) {
mask_index = i & 0x1;
index = i >> 1;
if (((hpsizes[index] >> (mask_index * 4)) & 0xf) == psize)
ret.high_slices |= 1ul << i;
}

return ret;
}
Expand Down Expand Up @@ -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);
Expand All @@ -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));

hpsizes = mm->context.high_slices_psize;
for (i = 0; i < SLICE_NUM_HIGH; i++)
if (mask.high_slices & (1u << i))
hpsizes = (hpsizes & ~(0xful << (i * 4))) |
(((unsigned long)psize) << (i * 4));

/* Assign the value back */
mm->context.low_slices_psize = lpsizes;
mm->context.high_slices_psize = hpsizes;

hpsizes = mm->context.high_slices_psize;
for (i = 0; i < SLICE_NUM_HIGH; i++) {
mask_index = i & 0x1;
index = i >> 1;
if (mask.high_slices & (1ul << i))
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,
Expand Down Expand Up @@ -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);
mask_index = index & 0x1;
return (hpsizes[index >> 1] >> (mask_index * 4)) & 0xf;
}
EXPORT_SYMBOL_GPL(get_slice_psize);

Expand All @@ -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;

Expand All @@ -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++) {
mask_index = i & 0x1;
index = i >> 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,
Expand All @@ -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;
mask_index = i & 0x1;
index = i >> 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
Expand Down

0 comments on commit 7aa0727

Please sign in to comment.