[PATCH V3 04/10] powerpc/mm/hash: Support 68 bit VA

Balbir Singh bsingharora at gmail.com
Wed Feb 22 11:15:33 AEDT 2017


On Sun, Feb 19, 2017 at 03:37:11PM +0530, Aneesh Kumar K.V wrote:
> Inorder to support large effective address range (512TB), we want to increase
> the virtual address bits to 68. But we do have platforms like p4 and p5 that can
> only do 65 bit VA. We support those platforms by limiting context bits on them
> to 16.
> 
> The protovsid -> vsid conversion is verified to work with both 65 and 68 bit
> va values. I also documented the restrictions in a table format as part of code
> comments.
> 
> Signed-off-by: Aneesh Kumar K.V <aneesh.kumar at linux.vnet.ibm.com>
> ---
>  /*
>   * This should be computed such that protovosid * vsid_mulitplier
>   * doesn't overflow 64 bits. It should also be co-prime to vsid_modulus
> + * We also need to make sure that number of bits in divisor is less
> + * than twice the number of protovsid bits for our modulus optmization to work.

Could you please explain why?

I am also beginning to wonder if we need the modulus optimization.
On my compiler (a * b) % (2^n - 1) generated reasonable code with just
one multiplication and a few shifts and boolean operations.

> + * The below table shows the current values used.
> + *
> + * |-------+------------+----------------+------------+--------------|
> + * |       | Prime Bits | VSID_BITS_65VA | Total Bits | 2* VSID_BITS |
> + * |-------+------------+----------------+------------+--------------|
> + * | 1T    |         24 |             25 |         49 |           50 |
> + * |-------+------------+----------------+------------+--------------|
> + * | 256MB |         24 |             37 |         61 |           74 |
> + * |-------+------------+----------------+------------+--------------|
> + *
> + * |-------+------------+----------------+------------+--------------|
> + * |       | Prime Bits | VSID_BITS_68VA | Total Bits | 2* VSID_BITS |
> + * |-------+------------+----------------+------------+--------------|
> + * | 1T    |         24 |             28 |         52 |           56 |
> + * |-------+------------+----------------+------------+--------------|
> + * | 256MB |         24 |             40 |         64 |           80 |
> + * |-------+------------+----------------+------------+--------------|
> + *
>   */
>  #define VSID_MULTIPLIER_256M	ASM_CONST(12538073)	/* 24-bit prime */
> -#define VSID_BITS_256M		(CONTEXT_BITS + ESID_BITS)
> +#define VSID_BITS_256M		(VA_BITS - SID_SHIFT)
>  #define VSID_MODULUS_256M	((1UL<<VSID_BITS_256M)-1)
> +#define VSID_BITS_65_256M	(65 - SID_SHIFT)
>  
>  #define VSID_MULTIPLIER_1T	ASM_CONST(12538073)	/* 24-bit prime */
> -#define VSID_BITS_1T		(CONTEXT_BITS + ESID_BITS_1T)
> +#define VSID_BITS_1T		(VA_BITS - SID_SHIFT_1T)
>  #define VSID_MODULUS_1T		((1UL<<VSID_BITS_1T)-1)
> -
> +#define VSID_BITS_65_1T		(65 - SID_SHIFT_1T)
>  
>  #define USER_VSID_RANGE	(1UL << (ESID_BITS + SID_SHIFT))
>  
> -/*
> - * This macro generates asm code to compute the VSID scramble
> - * function.  Used in slb_allocate() and do_stab_bolted.  The function
> - * computed is: (protovsid*VSID_MULTIPLIER) % VSID_MODULUS
> - *
> - *	rt = register containing the proto-VSID and into which the
> - *		VSID will be stored
> - *	rx = scratch register (clobbered)
> - *
> - * 	- rt and rx must be different registers
> - * 	- The answer will end up in the low VSID_BITS bits of rt.  The higher
> - * 	  bits may contain other garbage, so you may need to mask the
> - * 	  result.
> - */
> -#define ASM_VSID_SCRAMBLE(rt, rx, size)					\
> -	lis	rx,VSID_MULTIPLIER_##size at h;				\
> -	ori	rx,rx,VSID_MULTIPLIER_##size at l;				\
> -	mulld	rt,rt,rx;		/* rt = rt * MULTIPLIER */	\
> -									\
> -	srdi	rx,rt,VSID_BITS_##size;					\
> -	clrldi	rt,rt,(64-VSID_BITS_##size);				\
> -	add	rt,rt,rx;		/* add high and low bits */	\
> -	/* NOTE: explanation based on VSID_BITS_##size = 36		\
> -	 * Now, r3 == VSID (mod 2^36-1), and lies between 0 and		\
> -	 * 2^36-1+2^28-1.  That in particular means that if r3 >=	\
> -	 * 2^36-1, then r3+1 has the 2^36 bit set.  So, if r3+1 has	\
> -	 * the bit clear, r3 already has the answer we want, if it	\
> -	 * doesn't, the answer is the low 36 bits of r3+1.  So in all	\
> -	 * cases the answer is the low 36 bits of (r3 + ((r3+1) >> 36))*/\

I see that this comment is lost in the new definition, could we please
retain it.

> -	addi	rx,rt,1;						\
> -	srdi	rx,rx,VSID_BITS_##size;	/* extract 2^VSID_BITS bit */	\
> -	add	rt,rt,rx
> -
>  /* 4 bits per slice and we have one slice per 1TB */
>  #define SLICE_ARRAY_SIZE  (H_PGTABLE_RANGE >> 41)
>  
> @@ -629,7 +632,7 @@ static inline void subpage_prot_init_new_context(struct mm_struct *mm) { }
>  #define vsid_scramble(protovsid, size) \
>  	((((protovsid) * VSID_MULTIPLIER_##size) % VSID_MODULUS_##size))
>  
> -#else /* 1 */
> +/* simplified form avoiding mod operation */
>  #define vsid_scramble(protovsid, size) \
>  	({								 \
>  		unsigned long x;					 \
> @@ -637,6 +640,21 @@ static inline void subpage_prot_init_new_context(struct mm_struct *mm) { }
>  		x = (x >> VSID_BITS_##size) + (x & VSID_MODULUS_##size); \
>  		(x + ((x+1) >> VSID_BITS_##size)) & VSID_MODULUS_##size; \
>  	})
> +
> +static inline unsigned long vsid_scramble(unsigned long protovsid,
> +				  unsigned long vsid_multiplier, int vsid_bits)
> +{
> +	unsigned long vsid;
> +	unsigned long vsid_modulus = ((1UL << vsid_bits) - 1);
> +	/*
> +	 * We have same multipler for both 256 and 1T segements now
> +	 */
> +	vsid = protovsid * vsid_multiplier;
> +	vsid = (vsid >> vsid_bits) + (vsid & vsid_modulus);
> +	return (vsid + ((vsid + 1) >> vsid_bits)) & vsid_modulus;
> +}
> +
>  #endif /* 1 */
>  
>  /* Returns the segment size indicator for a user address */
> @@ -651,17 +669,32 @@ static inline int user_segment_size(unsigned long addr)
>  static inline unsigned long get_vsid(unsigned long context, unsigned long ea,
>  				     int ssize)
>  {
> +	unsigned long va_bits = VA_BITS;

Is there a reason to convert the constant into unsigned long?

> +	unsigned long vsid_bits;
> +	unsigned long protovsid;
> +
>  	/*
>  	 * Bad address. We return VSID 0 for that
>  	 */
>  	if ((ea & ~REGION_MASK) >= H_PGTABLE_RANGE)
>  		return 0;
>  
> -	if (ssize == MMU_SEGSIZE_256M)
> -		return vsid_scramble((context << ESID_BITS)
> -				     | ((ea >> SID_SHIFT) & ESID_BITS_MASK), 256M);
> -	return vsid_scramble((context << ESID_BITS_1T)
> -			     | ((ea >> SID_SHIFT_1T) & ESID_BITS_1T_MASK), 1T);
> +	if (!mmu_has_feature(MMU_FTR_68_BIT_VA))
> +		va_bits = 65;
> +
> +	if (ssize == MMU_SEGSIZE_256M) {
> +		vsid_bits = va_bits - SID_SHIFT;
> +		protovsid = (context << ESID_BITS) |
> +			((ea >> SID_SHIFT) & ESID_BITS_MASK);
> +		return vsid_scramble(protovsid,
> +				     VSID_MULTIPLIER_256M, vsid_bits);
> +	}
> +	/* 1T segment */
> +	vsid_bits = va_bits - SID_SHIFT_1T;
> +	protovsid = (context << ESID_BITS_1T) |
> +		((ea >> SID_SHIFT_1T) & ESID_BITS_1T_MASK);
> +	return vsid_scramble(protovsid,
> +			     VSID_MULTIPLIER_1T, vsid_bits);

We seem to be passing an unsigned long to a prototype above that expects
an int

>  }
>  
>  /*
> diff --git a/arch/powerpc/include/asm/mmu.h b/arch/powerpc/include/asm/mmu.h
> index 065e762fae85..78260409dc9c 100644
> --- a/arch/powerpc/include/asm/mmu.h
> +++ b/arch/powerpc/include/asm/mmu.h
> @@ -29,6 +29,10 @@
>   */
>  
>  /*
> + * Support for 68 bit VA space. We added that from ISA 2.05
> + */
> +#define MMU_FTR_68_BIT_VA		ASM_CONST(0x00002000)
> +/*
>   * Kernel read only support.
>   * We added the ppp value 0b110 in ISA 2.04.
>   */
> @@ -109,10 +113,10 @@
>  #define MMU_FTRS_POWER4		MMU_FTRS_DEFAULT_HPTE_ARCH_V2
>  #define MMU_FTRS_PPC970		MMU_FTRS_POWER4 | MMU_FTR_TLBIE_CROP_VA
>  #define MMU_FTRS_POWER5		MMU_FTRS_POWER4 | MMU_FTR_LOCKLESS_TLBIE
> -#define MMU_FTRS_POWER6		MMU_FTRS_POWER4 | MMU_FTR_LOCKLESS_TLBIE | MMU_FTR_KERNEL_RO
> -#define MMU_FTRS_POWER7		MMU_FTRS_POWER4 | MMU_FTR_LOCKLESS_TLBIE | MMU_FTR_KERNEL_RO
> -#define MMU_FTRS_POWER8		MMU_FTRS_POWER4 | MMU_FTR_LOCKLESS_TLBIE | MMU_FTR_KERNEL_RO
> -#define MMU_FTRS_POWER9		MMU_FTRS_POWER4 | MMU_FTR_LOCKLESS_TLBIE | MMU_FTR_KERNEL_RO
> +#define MMU_FTRS_POWER6		MMU_FTRS_POWER5 | MMU_FTR_KERNEL_RO | MMU_FTR_68_BIT_VA
> +#define MMU_FTRS_POWER7		MMU_FTRS_POWER6
> +#define MMU_FTRS_POWER8		MMU_FTRS_POWER6
> +#define MMU_FTRS_POWER9		MMU_FTRS_POWER6
>  #define MMU_FTRS_CELL		MMU_FTRS_DEFAULT_HPTE_ARCH_V2 | \
>  				MMU_FTR_CI_LARGE_PAGE
>  #define MMU_FTRS_PA6T		MMU_FTRS_DEFAULT_HPTE_ARCH_V2 | \
> @@ -136,7 +140,7 @@ enum {
>  		MMU_FTR_NO_SLBIE_B | MMU_FTR_16M_PAGE | MMU_FTR_TLBIEL |
>  		MMU_FTR_LOCKLESS_TLBIE | MMU_FTR_CI_LARGE_PAGE |
>  		MMU_FTR_1T_SEGMENT | MMU_FTR_TLBIE_CROP_VA |
> -		MMU_FTR_KERNEL_RO |
> +		MMU_FTR_KERNEL_RO | MMU_FTR_68_BIT_VA |
>  #ifdef CONFIG_PPC_RADIX_MMU
>  		MMU_FTR_TYPE_RADIX |
>  #endif
> @@ -290,7 +294,10 @@ static inline bool early_radix_enabled(void)
>  #define MMU_PAGE_16G	14
>  #define MMU_PAGE_64G	15
>  
> -/* N.B. we need to change the type of hpte_page_sizes if this gets to be > 16 */
> +/*
> + * N.B. we need to change the type of hpte_page_sizes if this gets to be > 16
> + * Also we need to change he type of mm_context.low/high_slices_psize.
> + */
>  #define MMU_PAGE_COUNT	16
>  
>  #ifdef CONFIG_PPC_BOOK3S_64
> diff --git a/arch/powerpc/kvm/book3s_64_mmu_host.c b/arch/powerpc/kvm/book3s_64_mmu_host.c
> index d6041101a5e2..bed699ab7654 100644
> --- a/arch/powerpc/kvm/book3s_64_mmu_host.c
> +++ b/arch/powerpc/kvm/book3s_64_mmu_host.c
> @@ -229,6 +229,7 @@ void kvmppc_mmu_unmap_page(struct kvm_vcpu *vcpu, struct kvmppc_pte *pte)
>  
>  static struct kvmppc_sid_map *create_sid_map(struct kvm_vcpu *vcpu, u64 gvsid)
>  {
> +	unsigned long vsid_bits = VSID_BITS_65_256M;
>  	struct kvmppc_sid_map *map;
>  	struct kvmppc_vcpu_book3s *vcpu_book3s = to_book3s(vcpu);
>  	u16 sid_map_mask;
> @@ -257,7 +258,12 @@ static struct kvmppc_sid_map *create_sid_map(struct kvm_vcpu *vcpu, u64 gvsid)
>  		kvmppc_mmu_pte_flush(vcpu, 0, 0);
>  		kvmppc_mmu_flush_segments(vcpu);
>  	}
> -	map->host_vsid = vsid_scramble(vcpu_book3s->proto_vsid_next++, 256M);
> +
> +	if (mmu_has_feature(MMU_FTR_68_BIT_VA))
> +		vsid_bits = VSID_BITS_256M;
> +
> +	map->host_vsid = vsid_scramble(vcpu_book3s->proto_vsid_next++,
> +				       VSID_MULTIPLIER_256M, vsid_bits);
>  
>  	map->guest_vsid = gvsid;
>  	map->valid = true;
> diff --git a/arch/powerpc/mm/mmu_context_book3s64.c b/arch/powerpc/mm/mmu_context_book3s64.c
> index a6450c7f9cf3..e6a5bcbf8abe 100644
> --- a/arch/powerpc/mm/mmu_context_book3s64.c
> +++ b/arch/powerpc/mm/mmu_context_book3s64.c
> @@ -33,6 +33,12 @@ static DEFINE_IDA(mmu_context_ida);
>  int hash__get_new_context(void)
>  {
>  	int index, err;
> +	unsigned long max_user_context;
> +
> +	if (mmu_has_feature(MMU_FTR_68_BIT_VA))
> +		max_user_context = MAX_USER_CONTEXT;
> +	else
> +		max_user_context = MAX_USER_CONTEXT_65BIT_VA;
>  
>  again:
>  	if (!ida_pre_get(&mmu_context_ida, GFP_KERNEL))
> @@ -50,7 +56,7 @@ int hash__get_new_context(void)
>  	else if (err)
>  		return err;
>  
> -	if (index > MAX_USER_CONTEXT) {
> +	if (index > max_user_context) {
>  		spin_lock(&mmu_context_lock);
>  		ida_remove(&mmu_context_ida, index);
>  		spin_unlock(&mmu_context_lock);
> diff --git a/arch/powerpc/mm/slb_low.S b/arch/powerpc/mm/slb_low.S
> index 4ce050ea4200..bb75a667483e 100644
> --- a/arch/powerpc/mm/slb_low.S
> +++ b/arch/powerpc/mm/slb_low.S
> @@ -23,6 +23,48 @@
>  #include <asm/pgtable.h>
>  #include <asm/firmware.h>
>  
> +/*
> + * This macro generates asm code to compute the VSID scramble
> + * function.  Used in slb_allocate() and do_stab_bolted.  The function
> + * computed is: (protovsid*VSID_MULTIPLIER) % VSID_MODULUS
> + *
> + *	rt = register containing the proto-VSID and into which the
> + *		VSID will be stored
> + *	rx = scratch register (clobbered)
> + *	rf = flags
> + *
> + *	- rt and rx must be different registers
> + *	- The answer will end up in the low VSID_BITS bits of rt.  The higher
> + *	  bits may contain other garbage, so you may need to mask the
> + *	  result.
> + */
> +#define ASM_VSID_SCRAMBLE(rt, rx, rf, size)				\
> +	lis	rx,VSID_MULTIPLIER_##size at h;				\
> +	ori	rx,rx,VSID_MULTIPLIER_##size at l;				\
> +	mulld	rt,rt,rx;		/* rt = rt * MULTIPLIER */	\
> +/*									\
> + * powermac get slb fault before feature fixup, so make 65 bit part     \
> + * the default part of feature fixup					\
> + */									\
> +BEGIN_MMU_FTR_SECTION							\
> +	srdi	rx,rt,VSID_BITS_65_##size;				\
> +	clrldi	rt,rt,(64-VSID_BITS_65_##size);				\
> +	add	rt,rt,rx;						\
> +	addi	rx,rt,1;						\
> +	srdi	rx,rx,VSID_BITS_65_##size;				\
> +	add	rt,rt,rx;						\
> +	rldimi	rf,rt,SLB_VSID_SHIFT_##size,(64 - (SLB_VSID_SHIFT_##size + VSID_BITS_65_##size)); \
> +MMU_FTR_SECTION_ELSE							\
> +	srdi	rx,rt,VSID_BITS_##size;					\
> +	clrldi	rt,rt,(64-VSID_BITS_##size);				\
> +	add	rt,rt,rx;		/* add high and low bits */	\
> +	addi	rx,rt,1;						\
> +	srdi	rx,rx,VSID_BITS_##size;	/* extract 2^VSID_BITS bit */	\
> +	add	rt,rt,rx;						\
> +	rldimi	rf,rt,SLB_VSID_SHIFT_##size,(64 - (SLB_VSID_SHIFT_##size + VSID_BITS_##size)); \

Don't like this bit, it does more than scramble, it adds the flags to the generated
scramble bits, could we please revisit what ASM_VSID_SCRAMBLE should do?

Otherwise,

Acked-by: Balbir Singh <bsingharora at gmail.com>

Balbir


More information about the Linuxppc-dev mailing list