Commit db3a528d authored by Christophe Leroy's avatar Christophe Leroy Committed by Michael Ellerman

powerpc/mm/slice: Enhance for supporting PPC32

In preparation for the following patch which will fix an issue on
the 8xx by re-using the 'slices', this patch enhances the
'slices' implementation to support 32 bits CPUs.

On PPC32, the address space is limited to 4Gbytes, hence only the low
slices will be used.

The high slices use bitmaps. As bitmap functions are not prepared to
handle bitmaps of size 0, this patch ensures that bitmap functions
are called only when SLICE_NUM_HIGH is not nul.
Signed-off-by: default avatarChristophe Leroy <christophe.leroy@c-s.fr>
Reviewed-by: default avatarNicholas Piggin <npiggin@gmail.com>
Signed-off-by: default avatarMichael Ellerman <mpe@ellerman.id.au>
parent a3286f05
/* SPDX-License-Identifier: GPL-2.0 */
#ifndef _ASM_POWERPC_NOHASH_32_SLICE_H
#define _ASM_POWERPC_NOHASH_32_SLICE_H
#ifdef CONFIG_PPC_MM_SLICES
#define SLICE_LOW_SHIFT 28
#define SLICE_LOW_TOP (0x100000000ull)
#define SLICE_NUM_LOW (SLICE_LOW_TOP >> SLICE_LOW_SHIFT)
#define GET_LOW_SLICE_INDEX(addr) ((addr) >> SLICE_LOW_SHIFT)
#define SLICE_HIGH_SHIFT 0
#define SLICE_NUM_HIGH 0ul
#define GET_HIGH_SLICE_INDEX(addr) (addr & 0)
#endif /* CONFIG_PPC_MM_SLICES */
#endif /* _ASM_POWERPC_NOHASH_32_SLICE_H */
...@@ -4,8 +4,10 @@ ...@@ -4,8 +4,10 @@
#ifdef CONFIG_PPC_BOOK3S_64 #ifdef CONFIG_PPC_BOOK3S_64
#include <asm/book3s/64/slice.h> #include <asm/book3s/64/slice.h>
#else #elif defined(CONFIG_PPC64)
#include <asm/nohash/64/slice.h> #include <asm/nohash/64/slice.h>
#elif defined(CONFIG_PPC_MMU_NOHASH)
#include <asm/nohash/32/slice.h>
#endif #endif
#ifdef CONFIG_PPC_MM_SLICES #ifdef CONFIG_PPC_MM_SLICES
......
...@@ -73,10 +73,12 @@ static void slice_range_to_mask(unsigned long start, unsigned long len, ...@@ -73,10 +73,12 @@ static void slice_range_to_mask(unsigned long start, unsigned long len,
unsigned long end = start + len - 1; unsigned long end = start + len - 1;
ret->low_slices = 0; ret->low_slices = 0;
bitmap_zero(ret->high_slices, SLICE_NUM_HIGH); if (SLICE_NUM_HIGH)
bitmap_zero(ret->high_slices, SLICE_NUM_HIGH);
if (start < SLICE_LOW_TOP) { if (start < SLICE_LOW_TOP) {
unsigned long mend = min(end, (SLICE_LOW_TOP - 1)); unsigned long mend = min(end,
(unsigned long)(SLICE_LOW_TOP - 1));
ret->low_slices = (1u << (GET_LOW_SLICE_INDEX(mend) + 1)) ret->low_slices = (1u << (GET_LOW_SLICE_INDEX(mend) + 1))
- (1u << GET_LOW_SLICE_INDEX(start)); - (1u << GET_LOW_SLICE_INDEX(start));
...@@ -113,11 +115,13 @@ static int slice_high_has_vma(struct mm_struct *mm, unsigned long slice) ...@@ -113,11 +115,13 @@ static int slice_high_has_vma(struct mm_struct *mm, unsigned long slice)
unsigned long start = slice << SLICE_HIGH_SHIFT; unsigned long start = slice << SLICE_HIGH_SHIFT;
unsigned long end = start + (1ul << SLICE_HIGH_SHIFT); unsigned long end = start + (1ul << SLICE_HIGH_SHIFT);
#ifdef CONFIG_PPC64
/* Hack, so that each addresses is controlled by exactly one /* Hack, so that each addresses is controlled by exactly one
* of the high or low area bitmaps, the first high area starts * of the high or low area bitmaps, the first high area starts
* at 4GB, not 0 */ * at 4GB, not 0 */
if (start == 0) if (start == 0)
start = SLICE_LOW_TOP; start = SLICE_LOW_TOP;
#endif
return !slice_area_is_free(mm, start, end - start); return !slice_area_is_free(mm, start, end - start);
} }
...@@ -128,7 +132,8 @@ static void slice_mask_for_free(struct mm_struct *mm, struct slice_mask *ret, ...@@ -128,7 +132,8 @@ static void slice_mask_for_free(struct mm_struct *mm, struct slice_mask *ret,
unsigned long i; unsigned long i;
ret->low_slices = 0; ret->low_slices = 0;
bitmap_zero(ret->high_slices, SLICE_NUM_HIGH); if (SLICE_NUM_HIGH)
bitmap_zero(ret->high_slices, SLICE_NUM_HIGH);
for (i = 0; i < SLICE_NUM_LOW; i++) for (i = 0; i < SLICE_NUM_LOW; i++)
if (!slice_low_has_vma(mm, i)) if (!slice_low_has_vma(mm, i))
...@@ -151,7 +156,8 @@ static void slice_mask_for_size(struct mm_struct *mm, int psize, struct slice_ma ...@@ -151,7 +156,8 @@ static void slice_mask_for_size(struct mm_struct *mm, int psize, struct slice_ma
u64 lpsizes; u64 lpsizes;
ret->low_slices = 0; ret->low_slices = 0;
bitmap_zero(ret->high_slices, SLICE_NUM_HIGH); if (SLICE_NUM_HIGH)
bitmap_zero(ret->high_slices, SLICE_NUM_HIGH);
lpsizes = mm->context.low_slices_psize; lpsizes = mm->context.low_slices_psize;
for (i = 0; i < SLICE_NUM_LOW; i++) for (i = 0; i < SLICE_NUM_LOW; i++)
...@@ -180,6 +186,10 @@ static int slice_check_fit(struct mm_struct *mm, ...@@ -180,6 +186,10 @@ static int slice_check_fit(struct mm_struct *mm,
*/ */
unsigned long slice_count = GET_HIGH_SLICE_INDEX(mm->context.slb_addr_limit); unsigned long slice_count = GET_HIGH_SLICE_INDEX(mm->context.slb_addr_limit);
if (!SLICE_NUM_HIGH)
return (mask.low_slices & available.low_slices) ==
mask.low_slices;
bitmap_and(result, mask.high_slices, bitmap_and(result, mask.high_slices,
available.high_slices, slice_count); available.high_slices, slice_count);
...@@ -189,6 +199,7 @@ static int slice_check_fit(struct mm_struct *mm, ...@@ -189,6 +199,7 @@ static int slice_check_fit(struct mm_struct *mm,
static void slice_flush_segments(void *parm) static void slice_flush_segments(void *parm)
{ {
#ifdef CONFIG_PPC64
struct mm_struct *mm = parm; struct mm_struct *mm = parm;
unsigned long flags; unsigned long flags;
...@@ -200,6 +211,7 @@ static void slice_flush_segments(void *parm) ...@@ -200,6 +211,7 @@ static void slice_flush_segments(void *parm)
local_irq_save(flags); local_irq_save(flags);
slb_flush_and_rebolt(); slb_flush_and_rebolt();
local_irq_restore(flags); local_irq_restore(flags);
#endif
} }
static void slice_convert(struct mm_struct *mm, struct slice_mask mask, int psize) static void slice_convert(struct mm_struct *mm, struct slice_mask mask, int psize)
...@@ -389,6 +401,8 @@ static unsigned long slice_find_area(struct mm_struct *mm, unsigned long len, ...@@ -389,6 +401,8 @@ static unsigned long slice_find_area(struct mm_struct *mm, unsigned long len,
static inline void slice_or_mask(struct slice_mask *dst, struct slice_mask *src) static inline void slice_or_mask(struct slice_mask *dst, struct slice_mask *src)
{ {
dst->low_slices |= src->low_slices; dst->low_slices |= src->low_slices;
if (!SLICE_NUM_HIGH)
return;
bitmap_or(dst->high_slices, dst->high_slices, src->high_slices, bitmap_or(dst->high_slices, dst->high_slices, src->high_slices,
SLICE_NUM_HIGH); SLICE_NUM_HIGH);
} }
...@@ -397,6 +411,8 @@ static inline void slice_andnot_mask(struct slice_mask *dst, struct slice_mask * ...@@ -397,6 +411,8 @@ static inline void slice_andnot_mask(struct slice_mask *dst, struct slice_mask *
{ {
dst->low_slices &= ~src->low_slices; dst->low_slices &= ~src->low_slices;
if (!SLICE_NUM_HIGH)
return;
bitmap_andnot(dst->high_slices, dst->high_slices, src->high_slices, bitmap_andnot(dst->high_slices, dst->high_slices, src->high_slices,
SLICE_NUM_HIGH); SLICE_NUM_HIGH);
} }
...@@ -446,14 +462,17 @@ unsigned long slice_get_unmapped_area(unsigned long addr, unsigned long len, ...@@ -446,14 +462,17 @@ unsigned long slice_get_unmapped_area(unsigned long addr, unsigned long len,
* init different masks * init different masks
*/ */
mask.low_slices = 0; mask.low_slices = 0;
bitmap_zero(mask.high_slices, SLICE_NUM_HIGH);
/* silence stupid warning */; /* silence stupid warning */;
potential_mask.low_slices = 0; potential_mask.low_slices = 0;
bitmap_zero(potential_mask.high_slices, SLICE_NUM_HIGH);
compat_mask.low_slices = 0; compat_mask.low_slices = 0;
bitmap_zero(compat_mask.high_slices, SLICE_NUM_HIGH);
if (SLICE_NUM_HIGH) {
bitmap_zero(mask.high_slices, SLICE_NUM_HIGH);
bitmap_zero(potential_mask.high_slices, SLICE_NUM_HIGH);
bitmap_zero(compat_mask.high_slices, SLICE_NUM_HIGH);
}
/* Sanity checks */ /* Sanity checks */
BUG_ON(mm->task_size == 0); BUG_ON(mm->task_size == 0);
...@@ -591,7 +610,9 @@ unsigned long slice_get_unmapped_area(unsigned long addr, unsigned long len, ...@@ -591,7 +610,9 @@ unsigned long slice_get_unmapped_area(unsigned long addr, unsigned long len,
convert: convert:
slice_andnot_mask(&mask, &good_mask); slice_andnot_mask(&mask, &good_mask);
slice_andnot_mask(&mask, &compat_mask); slice_andnot_mask(&mask, &compat_mask);
if (mask.low_slices || !bitmap_empty(mask.high_slices, SLICE_NUM_HIGH)) { if (mask.low_slices ||
(SLICE_NUM_HIGH &&
!bitmap_empty(mask.high_slices, SLICE_NUM_HIGH))) {
slice_convert(mm, mask, psize); slice_convert(mm, mask, psize);
if (psize > MMU_PAGE_BASE) if (psize > MMU_PAGE_BASE)
on_each_cpu(slice_flush_segments, mm, 1); on_each_cpu(slice_flush_segments, mm, 1);
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment