diff options
Diffstat (limited to 'arch/powerpc/kvm')
| -rw-r--r-- | arch/powerpc/kvm/book3s_64_mmu_host.c | 4 | ||||
| -rw-r--r-- | arch/powerpc/kvm/e500.h | 24 | ||||
| -rw-r--r-- | arch/powerpc/kvm/e500_mmu_host.c | 84 | ||||
| -rw-r--r-- | arch/powerpc/kvm/e500mc.c | 7 | 
4 files changed, 43 insertions, 76 deletions
diff --git a/arch/powerpc/kvm/book3s_64_mmu_host.c b/arch/powerpc/kvm/book3s_64_mmu_host.c index ead58e31729..5d7d29a313e 100644 --- a/arch/powerpc/kvm/book3s_64_mmu_host.c +++ b/arch/powerpc/kvm/book3s_64_mmu_host.c @@ -326,8 +326,8 @@ int kvmppc_mmu_init(struct kvm_vcpu *vcpu)  	vcpu3s->context_id[0] = err;  	vcpu3s->proto_vsid_max = ((vcpu3s->context_id[0] + 1) -				  << USER_ESID_BITS) - 1; -	vcpu3s->proto_vsid_first = vcpu3s->context_id[0] << USER_ESID_BITS; +				  << ESID_BITS) - 1; +	vcpu3s->proto_vsid_first = vcpu3s->context_id[0] << ESID_BITS;  	vcpu3s->proto_vsid_next = vcpu3s->proto_vsid_first;  	kvmppc_mmu_hpte_init(vcpu); diff --git a/arch/powerpc/kvm/e500.h b/arch/powerpc/kvm/e500.h index 41cefd43655..33db48a8ce2 100644 --- a/arch/powerpc/kvm/e500.h +++ b/arch/powerpc/kvm/e500.h @@ -26,17 +26,20 @@  #define E500_PID_NUM   3  #define E500_TLB_NUM   2 -#define E500_TLB_VALID 1 -#define E500_TLB_BITMAP 2 +/* entry is mapped somewhere in host TLB */ +#define E500_TLB_VALID		(1 << 0) +/* TLB1 entry is mapped by host TLB1, tracked by bitmaps */ +#define E500_TLB_BITMAP		(1 << 1) +/* TLB1 entry is mapped by host TLB0 */  #define E500_TLB_TLB0		(1 << 2)  struct tlbe_ref { -	pfn_t pfn; -	unsigned int flags; /* E500_TLB_* */ +	pfn_t pfn;		/* valid only for TLB0, except briefly */ +	unsigned int flags;	/* E500_TLB_* */  };  struct tlbe_priv { -	struct tlbe_ref ref; /* TLB0 only -- TLB1 uses tlb_refs */ +	struct tlbe_ref ref;  };  #ifdef CONFIG_KVM_E500V2 @@ -63,17 +66,6 @@ struct kvmppc_vcpu_e500 {  	unsigned int gtlb_nv[E500_TLB_NUM]; -	/* -	 * information associated with each host TLB entry -- -	 * TLB1 only for now.  If/when guest TLB1 entries can be -	 * mapped with host TLB0, this will be used for that too. -	 * -	 * We don't want to use this for guest TLB0 because then we'd -	 * have the overhead of doing the translation again even if -	 * the entry is still in the guest TLB (e.g. we swapped out -	 * and back, and our host TLB entries got evicted). -	 */ -	struct tlbe_ref *tlb_refs[E500_TLB_NUM];  	unsigned int host_tlb1_nv;  	u32 svr; diff --git a/arch/powerpc/kvm/e500_mmu_host.c b/arch/powerpc/kvm/e500_mmu_host.c index a222edfb9a9..1c6a9d729df 100644 --- a/arch/powerpc/kvm/e500_mmu_host.c +++ b/arch/powerpc/kvm/e500_mmu_host.c @@ -193,8 +193,11 @@ void inval_gtlbe_on_host(struct kvmppc_vcpu_e500 *vcpu_e500, int tlbsel,  	struct tlbe_ref *ref = &vcpu_e500->gtlb_priv[tlbsel][esel].ref;  	/* Don't bother with unmapped entries */ -	if (!(ref->flags & E500_TLB_VALID)) -		return; +	if (!(ref->flags & E500_TLB_VALID)) { +		WARN(ref->flags & (E500_TLB_BITMAP | E500_TLB_TLB0), +		     "%s: flags %x\n", __func__, ref->flags); +		WARN_ON(tlbsel == 1 && vcpu_e500->g2h_tlb1_map[esel]); +	}  	if (tlbsel == 1 && ref->flags & E500_TLB_BITMAP) {  		u64 tmp = vcpu_e500->g2h_tlb1_map[esel]; @@ -248,7 +251,7 @@ static inline void kvmppc_e500_ref_setup(struct tlbe_ref *ref,  					 pfn_t pfn)  {  	ref->pfn = pfn; -	ref->flags = E500_TLB_VALID; +	ref->flags |= E500_TLB_VALID;  	if (tlbe_is_writable(gtlbe))  		kvm_set_pfn_dirty(pfn); @@ -257,6 +260,7 @@ static inline void kvmppc_e500_ref_setup(struct tlbe_ref *ref,  static inline void kvmppc_e500_ref_release(struct tlbe_ref *ref)  {  	if (ref->flags & E500_TLB_VALID) { +		/* FIXME: don't log bogus pfn for TLB1 */  		trace_kvm_booke206_ref_release(ref->pfn, ref->flags);  		ref->flags = 0;  	} @@ -274,36 +278,23 @@ static void clear_tlb1_bitmap(struct kvmppc_vcpu_e500 *vcpu_e500)  static void clear_tlb_privs(struct kvmppc_vcpu_e500 *vcpu_e500)  { -	int tlbsel = 0; -	int i; - -	for (i = 0; i < vcpu_e500->gtlb_params[tlbsel].entries; i++) { -		struct tlbe_ref *ref = -			&vcpu_e500->gtlb_priv[tlbsel][i].ref; -		kvmppc_e500_ref_release(ref); -	} -} - -static void clear_tlb_refs(struct kvmppc_vcpu_e500 *vcpu_e500) -{ -	int stlbsel = 1; +	int tlbsel;  	int i; -	kvmppc_e500_tlbil_all(vcpu_e500); - -	for (i = 0; i < host_tlb_params[stlbsel].entries; i++) { -		struct tlbe_ref *ref = -			&vcpu_e500->tlb_refs[stlbsel][i]; -		kvmppc_e500_ref_release(ref); +	for (tlbsel = 0; tlbsel <= 1; tlbsel++) { +		for (i = 0; i < vcpu_e500->gtlb_params[tlbsel].entries; i++) { +			struct tlbe_ref *ref = +				&vcpu_e500->gtlb_priv[tlbsel][i].ref; +			kvmppc_e500_ref_release(ref); +		}  	} - -	clear_tlb_privs(vcpu_e500);  }  void kvmppc_core_flush_tlb(struct kvm_vcpu *vcpu)  {  	struct kvmppc_vcpu_e500 *vcpu_e500 = to_e500(vcpu); -	clear_tlb_refs(vcpu_e500); +	kvmppc_e500_tlbil_all(vcpu_e500); +	clear_tlb_privs(vcpu_e500);  	clear_tlb1_bitmap(vcpu_e500);  } @@ -458,8 +449,6 @@ static inline int kvmppc_e500_shadow_map(struct kvmppc_vcpu_e500 *vcpu_e500,  		gvaddr &= ~((tsize_pages << PAGE_SHIFT) - 1);  	} -	/* Drop old ref and setup new one. */ -	kvmppc_e500_ref_release(ref);  	kvmppc_e500_ref_setup(ref, gtlbe, pfn);  	kvmppc_e500_setup_stlbe(&vcpu_e500->vcpu, gtlbe, tsize, @@ -507,14 +496,15 @@ static int kvmppc_e500_tlb1_map_tlb1(struct kvmppc_vcpu_e500 *vcpu_e500,  	if (unlikely(vcpu_e500->host_tlb1_nv >= tlb1_max_shadow_size()))  		vcpu_e500->host_tlb1_nv = 0; -	vcpu_e500->tlb_refs[1][sesel] = *ref; -	vcpu_e500->g2h_tlb1_map[esel] |= (u64)1 << sesel; -	vcpu_e500->gtlb_priv[1][esel].ref.flags |= E500_TLB_BITMAP;  	if (vcpu_e500->h2g_tlb1_rmap[sesel]) { -		unsigned int idx = vcpu_e500->h2g_tlb1_rmap[sesel]; +		unsigned int idx = vcpu_e500->h2g_tlb1_rmap[sesel] - 1;  		vcpu_e500->g2h_tlb1_map[idx] &= ~(1ULL << sesel);  	} -	vcpu_e500->h2g_tlb1_rmap[sesel] = esel; + +	vcpu_e500->gtlb_priv[1][esel].ref.flags |= E500_TLB_BITMAP; +	vcpu_e500->g2h_tlb1_map[esel] |= (u64)1 << sesel; +	vcpu_e500->h2g_tlb1_rmap[sesel] = esel + 1; +	WARN_ON(!(ref->flags & E500_TLB_VALID));  	return sesel;  } @@ -526,13 +516,12 @@ static int kvmppc_e500_tlb1_map(struct kvmppc_vcpu_e500 *vcpu_e500,  		u64 gvaddr, gfn_t gfn, struct kvm_book3e_206_tlb_entry *gtlbe,  		struct kvm_book3e_206_tlb_entry *stlbe, int esel)  { -	struct tlbe_ref ref; +	struct tlbe_ref *ref = &vcpu_e500->gtlb_priv[1][esel].ref;  	int sesel;  	int r; -	ref.flags = 0;  	r = kvmppc_e500_shadow_map(vcpu_e500, gvaddr, gfn, gtlbe, 1, stlbe, -				   &ref); +				   ref);  	if (r)  		return r; @@ -544,7 +533,7 @@ static int kvmppc_e500_tlb1_map(struct kvmppc_vcpu_e500 *vcpu_e500,  	}  	/* Otherwise map into TLB1 */ -	sesel = kvmppc_e500_tlb1_map_tlb1(vcpu_e500, &ref, esel); +	sesel = kvmppc_e500_tlb1_map_tlb1(vcpu_e500, ref, esel);  	write_stlbe(vcpu_e500, gtlbe, stlbe, 1, sesel);  	return 0; @@ -565,7 +554,7 @@ void kvmppc_mmu_map(struct kvm_vcpu *vcpu, u64 eaddr, gpa_t gpaddr,  	case 0:  		priv = &vcpu_e500->gtlb_priv[tlbsel][esel]; -		/* Triggers after clear_tlb_refs or on initial mapping */ +		/* Triggers after clear_tlb_privs or on initial mapping */  		if (!(priv->ref.flags & E500_TLB_VALID)) {  			kvmppc_e500_tlb0_map(vcpu_e500, esel, &stlbe);  		} else { @@ -665,35 +654,16 @@ int e500_mmu_host_init(struct kvmppc_vcpu_e500 *vcpu_e500)  		host_tlb_params[0].entries / host_tlb_params[0].ways;  	host_tlb_params[1].sets = 1; -	vcpu_e500->tlb_refs[0] = -		kzalloc(sizeof(struct tlbe_ref) * host_tlb_params[0].entries, -			GFP_KERNEL); -	if (!vcpu_e500->tlb_refs[0]) -		goto err; - -	vcpu_e500->tlb_refs[1] = -		kzalloc(sizeof(struct tlbe_ref) * host_tlb_params[1].entries, -			GFP_KERNEL); -	if (!vcpu_e500->tlb_refs[1]) -		goto err; -  	vcpu_e500->h2g_tlb1_rmap = kzalloc(sizeof(unsigned int) *  					   host_tlb_params[1].entries,  					   GFP_KERNEL);  	if (!vcpu_e500->h2g_tlb1_rmap) -		goto err; +		return -EINVAL;  	return 0; - -err: -	kfree(vcpu_e500->tlb_refs[0]); -	kfree(vcpu_e500->tlb_refs[1]); -	return -EINVAL;  }  void e500_mmu_host_uninit(struct kvmppc_vcpu_e500 *vcpu_e500)  {  	kfree(vcpu_e500->h2g_tlb1_rmap); -	kfree(vcpu_e500->tlb_refs[0]); -	kfree(vcpu_e500->tlb_refs[1]);  } diff --git a/arch/powerpc/kvm/e500mc.c b/arch/powerpc/kvm/e500mc.c index 1f89d26e65f..2f4baa074b2 100644 --- a/arch/powerpc/kvm/e500mc.c +++ b/arch/powerpc/kvm/e500mc.c @@ -108,6 +108,8 @@ void kvmppc_mmu_msr_notify(struct kvm_vcpu *vcpu, u32 old_msr)  {  } +static DEFINE_PER_CPU(struct kvm_vcpu *, last_vcpu_on_cpu); +  void kvmppc_core_vcpu_load(struct kvm_vcpu *vcpu, int cpu)  {  	struct kvmppc_vcpu_e500 *vcpu_e500 = to_e500(vcpu); @@ -136,8 +138,11 @@ void kvmppc_core_vcpu_load(struct kvm_vcpu *vcpu, int cpu)  	mtspr(SPRN_GDEAR, vcpu->arch.shared->dar);  	mtspr(SPRN_GESR, vcpu->arch.shared->esr); -	if (vcpu->arch.oldpir != mfspr(SPRN_PIR)) +	if (vcpu->arch.oldpir != mfspr(SPRN_PIR) || +	    __get_cpu_var(last_vcpu_on_cpu) != vcpu) {  		kvmppc_e500_tlbil_all(vcpu_e500); +		__get_cpu_var(last_vcpu_on_cpu) = vcpu; +	}  	kvmppc_load_guest_fp(vcpu);  }  |