Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit 4ab96919 authored by Alexander Graf's avatar Alexander Graf Committed by Avi Kivity
Browse files

KVM: PPC: e500mc: Add doorbell emulation support



When one vcpu wants to kick another, it can issue a special IPI instruction
called msgsnd. This patch emulates this instruction, its clearing counterpart
and the infrastructure required to actually trigger that interrupt inside
a guest vcpu.

With this patch, SMP guests on e500mc work.

Signed-off-by: default avatarAlexander Graf <agraf@suse.de>
Signed-off-by: default avatarAvi Kivity <avi@redhat.com>
parent 73196cd3
Loading
Loading
Loading
Loading
+2 −0
Original line number Diff line number Diff line
@@ -19,7 +19,9 @@

#define PPC_DBELL_MSG_BRDCAST	(0x04000000)
#define PPC_DBELL_TYPE(x)	(((x) & 0xf) << (63-36))
#define PPC_DBELL_TYPE_MASK	PPC_DBELL_TYPE(0xf)
#define PPC_DBELL_LPID(x)	((x) << (63 - 49))
#define PPC_DBELL_PIR_MASK	0x3fff
enum ppc_dbell {
	PPC_DBELL = 0,		/* doorbell */
	PPC_DBELL_CRIT = 1,	/* critical doorbell */
+2 −0
Original line number Diff line number Diff line
@@ -326,6 +326,7 @@ static int kvmppc_booke_irqprio_deliver(struct kvm_vcpu *vcpu,
		int_class = INT_CLASS_NONCRIT;
		break;
	case BOOKE_IRQPRIO_CRITICAL:
	case BOOKE_IRQPRIO_DBELL_CRIT:
		allowed = vcpu->arch.shared->msr & MSR_CE;
		allowed = allowed && !crit;
		msr_mask = MSR_GS | MSR_ME;
@@ -342,6 +343,7 @@ static int kvmppc_booke_irqprio_deliver(struct kvm_vcpu *vcpu,
		keep_irq = true;
		/* fall through */
	case BOOKE_IRQPRIO_EXTERNAL:
	case BOOKE_IRQPRIO_DBELL:
		allowed = vcpu->arch.shared->msr & MSR_EE;
		allowed = allowed && !crit;
		msr_mask = MSR_GS | MSR_CE | MSR_ME | MSR_DE;
+68 −0
Original line number Diff line number Diff line
@@ -14,16 +14,74 @@

#include <asm/kvm_ppc.h>
#include <asm/disassemble.h>
#include <asm/dbell.h>

#include "booke.h"
#include "e500.h"

#define XOP_MSGSND  206
#define XOP_MSGCLR  238
#define XOP_TLBIVAX 786
#define XOP_TLBSX   914
#define XOP_TLBRE   946
#define XOP_TLBWE   978
#define XOP_TLBILX  18

#ifdef CONFIG_KVM_E500MC
static int dbell2prio(ulong param)
{
	int msg = param & PPC_DBELL_TYPE_MASK;
	int prio = -1;

	switch (msg) {
	case PPC_DBELL_TYPE(PPC_DBELL):
		prio = BOOKE_IRQPRIO_DBELL;
		break;
	case PPC_DBELL_TYPE(PPC_DBELL_CRIT):
		prio = BOOKE_IRQPRIO_DBELL_CRIT;
		break;
	default:
		break;
	}

	return prio;
}

static int kvmppc_e500_emul_msgclr(struct kvm_vcpu *vcpu, int rb)
{
	ulong param = vcpu->arch.gpr[rb];
	int prio = dbell2prio(param);

	if (prio < 0)
		return EMULATE_FAIL;

	clear_bit(prio, &vcpu->arch.pending_exceptions);
	return EMULATE_DONE;
}

static int kvmppc_e500_emul_msgsnd(struct kvm_vcpu *vcpu, int rb)
{
	ulong param = vcpu->arch.gpr[rb];
	int prio = dbell2prio(rb);
	int pir = param & PPC_DBELL_PIR_MASK;
	int i;
	struct kvm_vcpu *cvcpu;

	if (prio < 0)
		return EMULATE_FAIL;

	kvm_for_each_vcpu(i, cvcpu, vcpu->kvm) {
		int cpir = cvcpu->arch.shared->pir;
		if ((param & PPC_DBELL_MSG_BRDCAST) || (cpir == pir)) {
			set_bit(prio, &cvcpu->arch.pending_exceptions);
			kvm_vcpu_kick(cvcpu);
		}
	}

	return EMULATE_DONE;
}
#endif

int kvmppc_core_emulate_op(struct kvm_run *run, struct kvm_vcpu *vcpu,
                           unsigned int inst, int *advance)
{
@@ -36,6 +94,16 @@ int kvmppc_core_emulate_op(struct kvm_run *run, struct kvm_vcpu *vcpu,
	case 31:
		switch (get_xop(inst)) {

#ifdef CONFIG_KVM_E500MC
		case XOP_MSGSND:
			emulated = kvmppc_e500_emul_msgsnd(vcpu, get_rb(inst));
			break;

		case XOP_MSGCLR:
			emulated = kvmppc_e500_emul_msgclr(vcpu, get_rb(inst));
			break;
#endif

		case XOP_TLBRE:
			emulated = kvmppc_e500_emul_tlbre(vcpu);
			break;