diff options
Diffstat (limited to 'arch/powerpc/mm/slice.c')
| -rw-r--r-- | arch/powerpc/mm/slice.c | 112 | 
1 files changed, 73 insertions, 39 deletions
diff --git a/arch/powerpc/mm/slice.c b/arch/powerpc/mm/slice.c index 73709f7ce92..5829d2a950d 100644 --- a/arch/powerpc/mm/slice.c +++ b/arch/powerpc/mm/slice.c @@ -34,6 +34,11 @@  #include <asm/mmu.h>  #include <asm/spu.h> +/* some sanity checks */ +#if (PGTABLE_RANGE >> 43) > SLICE_MASK_SIZE +#error PGTABLE_RANGE exceeds slice_mask high_slices size +#endif +  static DEFINE_SPINLOCK(slice_convert_lock); @@ -42,7 +47,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) @@ -54,7 +59,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); @@ -84,8 +89,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;  } @@ -135,26 +140,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;  } @@ -183,8 +193,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 +213,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, @@ -587,18 +603,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); @@ -618,7 +635,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 +658,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, @@ -660,18 +685,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  |