[RFC PATCH 12/16] KVM: PPC: e500: emulate tlbilx

Alexander Graf agraf at suse.de
Tue Jan 10 03:23:52 EST 2012


On 21.12.2011, at 02:34, Scott Wood wrote:

> tlbilx is the new, preferred invalidation instruction.  It is not
> found on e500 prior to e500mc, but there should be no harm in
> supporting it on all e500.
> 
> Based on code from Ashish Kalra <Ashish.Kalra at freescale.com>.
> 
> Signed-off-by: Scott Wood <scottwood at freescale.com>
> ---
> arch/powerpc/kvm/e500.h         |    1 +
> arch/powerpc/kvm/e500_emulate.c |    9 ++++++
> arch/powerpc/kvm/e500_tlb.c     |   52 +++++++++++++++++++++++++++++++++++++++
> 3 files changed, 62 insertions(+), 0 deletions(-)
> 
> diff --git a/arch/powerpc/kvm/e500.h b/arch/powerpc/kvm/e500.h
> index f4dee55..ce3f163 100644
> --- a/arch/powerpc/kvm/e500.h
> +++ b/arch/powerpc/kvm/e500.h
> @@ -124,6 +124,7 @@ int kvmppc_e500_emul_mt_mmucsr0(struct kvmppc_vcpu_e500 *vcpu_e500,
> int kvmppc_e500_emul_tlbwe(struct kvm_vcpu *vcpu);
> int kvmppc_e500_emul_tlbre(struct kvm_vcpu *vcpu);
> int kvmppc_e500_emul_tlbivax(struct kvm_vcpu *vcpu, int ra, int rb);
> +int kvmppc_e500_emul_tlbilx(struct kvm_vcpu *vcpu, int rt, int ra, int rb);
> int kvmppc_e500_emul_tlbsx(struct kvm_vcpu *vcpu, int rb);
> int kvmppc_e500_tlb_init(struct kvmppc_vcpu_e500 *vcpu_e500);
> void kvmppc_e500_tlb_uninit(struct kvmppc_vcpu_e500 *vcpu_e500);
> diff --git a/arch/powerpc/kvm/e500_emulate.c b/arch/powerpc/kvm/e500_emulate.c
> index c80794d..af02c18 100644
> --- a/arch/powerpc/kvm/e500_emulate.c
> +++ b/arch/powerpc/kvm/e500_emulate.c
> @@ -22,6 +22,7 @@
> #define XOP_TLBSX   914
> #define XOP_TLBRE   946
> #define XOP_TLBWE   978
> +#define XOP_TLBILX  18
> 
> int kvmppc_core_emulate_op(struct kvm_run *run, struct kvm_vcpu *vcpu,
>                            unsigned int inst, int *advance)
> @@ -29,6 +30,7 @@ int kvmppc_core_emulate_op(struct kvm_run *run, struct kvm_vcpu *vcpu,
> 	int emulated = EMULATE_DONE;
> 	int ra;
> 	int rb;
> +	int rt;
> 
> 	switch (get_op(inst)) {
> 	case 31:
> @@ -47,6 +49,13 @@ int kvmppc_core_emulate_op(struct kvm_run *run, struct kvm_vcpu *vcpu,
> 			emulated = kvmppc_e500_emul_tlbsx(vcpu,rb);
> 			break;
> 
> +		case XOP_TLBILX:
> +			ra = get_ra(inst);
> +			rb = get_rb(inst);
> +			rt = get_rt(inst);
> +			emulated = kvmppc_e500_emul_tlbilx(vcpu, rt, ra, rb);
> +			break;
> +
> 		case XOP_TLBIVAX:
> 			ra = get_ra(inst);
> 			rb = get_rb(inst);
> diff --git a/arch/powerpc/kvm/e500_tlb.c b/arch/powerpc/kvm/e500_tlb.c
> index 031fd5b..121cd68 100644
> --- a/arch/powerpc/kvm/e500_tlb.c
> +++ b/arch/powerpc/kvm/e500_tlb.c
> @@ -631,6 +631,58 @@ int kvmppc_e500_emul_tlbivax(struct kvm_vcpu *vcpu, int ra, int rb)
> 	return EMULATE_DONE;
> }
> 
> +static void tlbilx_all(struct kvmppc_vcpu_e500 *vcpu_e500, int tlbsel,
> +		       int pid, int rt)
> +{
> +	struct kvm_book3e_206_tlb_entry *tlbe;
> +	int tid, esel;
> +
> +	/* invalidate all entries */
> +	for (esel = 0; esel < vcpu_e500->gtlb_params[tlbsel].entries; esel++) {

By dereferencing the struct inside the loop you're creating a new load on every iteration. Please use a variable for entries.

> +		tlbe = get_entry(vcpu_e500, tlbsel, esel);
> +		tid = get_tlb_tid(tlbe);
> +		if (rt == 0 || tid == pid) {
> +			inval_gtlbe_on_host(vcpu_e500, tlbsel, esel);
> +			kvmppc_e500_gtlbe_invalidate(vcpu_e500, tlbsel, esel);
> +		}
> +	}
> +}
> +
> +static void tlbilx_one(struct kvmppc_vcpu_e500 *vcpu_e500, int pid,
> +		       int ra, int rb)
> +{
> +	int tlbsel, esel;
> +	gva_t ea;
> +
> +	ea = kvmppc_get_gpr(&vcpu_e500->vcpu, rb);
> +	if (ra)
> +		ea += kvmppc_get_gpr(&vcpu_e500->vcpu, ra);
> +
> +	for (tlbsel = 0; tlbsel < 2; tlbsel++) {
> +		esel = kvmppc_e500_tlb_index(vcpu_e500, ea, tlbsel, pid, -1);
> +		if (esel >= 0) {
> +			inval_gtlbe_on_host(vcpu_e500, tlbsel, esel);
> +			kvmppc_e500_gtlbe_invalidate(vcpu_e500, tlbsel, esel);
> +			break;
> +		}
> +	}
> +}
> +
> +int kvmppc_e500_emul_tlbilx(struct kvm_vcpu *vcpu, int rt, int ra, int rb)
> +{
> +	struct kvmppc_vcpu_e500 *vcpu_e500 = to_e500(vcpu);
> +	int pid = get_cur_spid(vcpu);
> +
> +	if (rt == 0 || rt == 1) {
> +		tlbilx_all(vcpu_e500, 0, pid, rt);
> +		tlbilx_all(vcpu_e500, 1, pid, rt);
> +	} else if (rt == 3) {

too many magic constants :)


Alex



More information about the Linuxppc-dev mailing list