diff mbox

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

Message ID 20111221013438.GL8378@schlenkerla.am.freescale.net
State New, archived
Headers show

Commit Message

Scott Wood Dec. 21, 2011, 1:34 a.m. UTC
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@freescale.com>.

Signed-off-by: Scott Wood <scottwood@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(-)

Comments

Alexander Graf Jan. 9, 2012, 4:23 p.m. UTC | #1
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@freescale.com>.
> 
> Signed-off-by: Scott Wood <scottwood@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

--
To unsubscribe from this list: send the line "unsubscribe kvm-ppc" in
the body of a message to majordomo@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html
diff mbox

Patch

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++) {
+		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) {
+		tlbilx_one(vcpu_e500, pid, ra, rb);
+	}
+
+	return EMULATE_DONE;
+}
+
 int kvmppc_e500_emul_tlbre(struct kvm_vcpu *vcpu)
 {
 	struct kvmppc_vcpu_e500 *vcpu_e500 = to_e500(vcpu);