[PATCH 4/9] KVM: PPC: Book3S: Generalize interfaces to interrupt controller emulation

Paul Mackerras
2013-02-15T00:01:42Z

This makes the XICS interrupt controller emulation code export a struct
containing function pointers for the various calls into the XICS code.
The generic book3s code then uses these function pointers instead of
calling directly into the XICS code (except for the XICS instantiation
function).

This should make it possible for other interrupt controller emulations
to coexist with the XICS emulation.

Signed-off-by: Paul Mackerras <paulus@samba.org>
---
arch/powerpc/include/asm/kvm_host.h | 11 ++++-
arch/powerpc/include/asm/kvm_ppc.h | 14 ------
arch/powerpc/kvm/book3s_hv.c | 18 +++----
arch/powerpc/kvm/book3s_pr.c | 14 +++---
arch/powerpc/kvm/book3s_pr_papr.c | 10 ++--
arch/powerpc/kvm/book3s_xics.c | 93 +++++++++++++++++++----------------
arch/powerpc/kvm/powerpc.c | 4 +-
7 files changed, 85 insertions(+), 79 deletions(-)

diff --git a/arch/powerpc/include/asm/kvm_host.h b/arch/powerpc/include/asm/kvm_host.h
index b05e7cd..8af4c0b 100644
--- a/arch/powerpc/include/asm/kvm_host.h
+++ b/arch/powerpc/include/asm/kvm_host.h
@@ -230,8 +230,18 @@ struct kvm_arch_memory_slot {
#endif /* CONFIG_KVM_BOOK3S_64_HV */
};

+struct kvm_irq_ctrler {
+ int (*setup_vcpu)(struct kvm_vcpu *vcpu);
+ void (*teardown_vcpu)(struct kvm_vcpu *vcpu);
+ void (*free_ctrler)(struct kvm *kvm);
+ int (*hcall)(struct kvm_vcpu *vcpu, unsigned long req);
+ int (*ioctl)(struct kvm *kvm, unsigned int ioctl, unsigned long arg);
+};
+
struct kvm_arch {
unsigned int lpid;
+ struct kvm_irq_ctrler *irq_ctrler;
+ void *irq_ctrler_private;
#ifdef CONFIG_KVM_BOOK3S_64_HV
unsigned long hpt_virt;
struct revmap_entry *revmap;
@@ -260,7 +270,6 @@ struct kvm_arch {
#ifdef CONFIG_PPC_BOOK3S_64
struct list_head spapr_tce_tables;
struct list_head rtas_tokens;
- struct kvmppc_xics *xics;
#endif
};

diff --git a/arch/powerpc/include/asm/kvm_ppc.h b/arch/powerpc/include/asm/kvm_ppc.h
index f0fd22b..2308fff 100644
--- a/arch/powerpc/include/asm/kvm_ppc.h
+++ b/arch/powerpc/include/asm/kvm_ppc.h
@@ -130,12 +130,7 @@ extern long kvmppc_prepare_vrma(struct kvm *kvm,
extern void kvmppc_map_vrma(struct kvm_vcpu *vcpu,
struct kvm_memory_slot *memslot, unsigned long porder);
extern int kvmppc_pseries_do_hcall(struct kvm_vcpu *vcpu);
-extern int kvmppc_xics_hcall(struct kvm_vcpu *vcpu, u32 cmd);
-extern int kvmppc_xics_ioctl(struct kvm *kvm, unsigned ioctl, unsigned long arg);
extern int kvmppc_xics_create(struct kvm *kvm, struct kvm_irqchip_args *args);
-extern void kvmppc_xics_free_icp(struct kvm_vcpu *vcpu);
-extern int kvmppc_xics_create_icp(struct kvm_vcpu *vcpu);
-extern void kvmppc_xics_free(struct kvm *kvm);

extern long kvm_vm_ioctl_create_spapr_tce(struct kvm *kvm,
struct kvm_create_spapr_tce *args);
@@ -275,15 +270,6 @@ static inline void kvm_linear_init(void)

#endif

-#ifdef CONFIG_PPC_BOOK3S_64
-static inline int kvmppc_xics_enabled(struct kvm *kvm)
-{
- return kvm->arch.xics != NULL;
-}
-#else
-static inline int kvmppc_xics_enabled(struct kvm *kvm) { return 0; }
-#endif
-
static inline void kvmppc_set_epr(struct kvm_vcpu *vcpu, u32 epr)
{
#ifdef CONFIG_KVM_BOOKE_HV
diff --git a/arch/powerpc/kvm/book3s_hv.c b/arch/powerpc/kvm/book3s_hv.c
index aa3a0db..8f09c36 100644
--- a/arch/powerpc/kvm/book3s_hv.c
+++ b/arch/powerpc/kvm/book3s_hv.c
@@ -532,8 +532,8 @@ int kvmppc_pseries_do_hcall(struct kvm_vcpu *vcpu)
case H_CPPR:
case H_EOI:
case H_IPI:
- if (kvmppc_xics_enabled(vcpu->kvm)) {
- ret = kvmppc_xics_hcall(vcpu, req);
+ if (vcpu->kvm->arch.irq_ctrler) {
+ ret = vcpu->kvm->arch.irq_ctrler->hcall(vcpu, req);
break;
} /* fallthrough */
default:
@@ -894,9 +894,9 @@ struct kvm_vcpu *kvmppc_core_vcpu_create(struct kvm *kvm, unsigned int id)
spin_lock_init(&vcpu->arch.tbacct_lock);
vcpu->arch.busy_preempt = TB_NIL;

- /* Create the XICS */
- if (kvmppc_xics_enabled(kvm)) {
- err = kvmppc_xics_create_icp(vcpu);
+ /* Create the interrupt-controller-specific state */
+ if (kvm->arch.irq_ctrler) {
+ err = kvm->arch.irq_ctrler->setup_vcpu(vcpu);
if (err < 0)
goto free_vcpu;
}
@@ -952,8 +952,8 @@ void kvmppc_core_vcpu_free(struct kvm_vcpu *vcpu)
kvmppc_unpin_guest_page(vcpu->kvm, vcpu->arch.vpa.pinned_addr);
spin_unlock(&vcpu->arch.vpa_update_lock);
kvm_vcpu_uninit(vcpu);
- if (kvmppc_xics_enabled(vcpu->kvm))
- kvmppc_xics_free_icp(vcpu);
+ if (vcpu->kvm->arch.irq_ctrler)
+ vcpu->kvm->arch.irq_ctrler->teardown_vcpu(vcpu);
kmem_cache_free(kvm_vcpu_cache, vcpu);
}

@@ -1899,8 +1899,8 @@ void kvmppc_core_destroy_vm(struct kvm *kvm)

kvmppc_rtas_tokens_free(kvm);

- if (kvmppc_xics_enabled(kvm))
- kvmppc_xics_free(kvm);
+ if (kvm->arch.irq_ctrler)
+ kvm->arch.irq_ctrler->free_ctrler(kvm);

kvmppc_free_hpt(kvm);
WARN_ON(!list_empty(&kvm->arch.spapr_tce_tables));
diff --git a/arch/powerpc/kvm/book3s_pr.c b/arch/powerpc/kvm/book3s_pr.c
index 9b2237f..0c84242 100644
--- a/arch/powerpc/kvm/book3s_pr.c
+++ b/arch/powerpc/kvm/book3s_pr.c
@@ -1069,9 +1069,9 @@ struct kvm_vcpu *kvmppc_core_vcpu_create(struct kvm *kvm, unsigned int id)
if (err < 0)
goto uninit_vcpu;

- /* Create the XICS */
- if (kvmppc_xics_enabled(kvm)) {
- err = kvmppc_xics_create_icp(vcpu);
+ /* Create the interrupt-controller-specific vcpu state */
+ if (kvm->arch.irq_ctrler) {
+ err = kvm->arch.irq_ctrler->setup_vcpu(vcpu);
if (err < 0)
goto free_vcpu;
}
@@ -1092,8 +1092,8 @@ void kvmppc_core_vcpu_free(struct kvm_vcpu *vcpu)
{
struct kvmppc_vcpu_book3s *vcpu_book3s = to_book3s(vcpu);

- if (kvmppc_xics_enabled(vcpu->kvm))
- kvmppc_xics_free_icp(vcpu);
+ if (vcpu->kvm->arch.irq_ctrler)
+ vcpu->kvm->arch.irq_ctrler->teardown_vcpu(vcpu);
free_page((unsigned long)vcpu->arch.shared & PAGE_MASK);
kvm_vcpu_uninit(vcpu);
kfree(vcpu_book3s->shadow_vcpu);
@@ -1313,8 +1313,8 @@ void kvmppc_core_destroy_vm(struct kvm *kvm)
#ifdef CONFIG_PPC64
WARN_ON(!list_empty(&kvm->arch.spapr_tce_tables));
#endif
- if (kvmppc_xics_enabled(kvm))
- kvmppc_xics_free(kvm);
+ if (kvm->arch.irq_ctrler)
+ kvm->arch.irq_ctrler->free_ctrler(kvm);

}

diff --git a/arch/powerpc/kvm/book3s_pr_papr.c b/arch/powerpc/kvm/book3s_pr_papr.c
index 94cec5b..c423b51 100644
--- a/arch/powerpc/kvm/book3s_pr_papr.c
+++ b/arch/powerpc/kvm/book3s_pr_papr.c
@@ -229,7 +229,11 @@ static int kvmppc_h_pr_put_tce(struct kvm_vcpu *vcpu)

static int kvmppc_h_pr_xics_hcall(struct kvm_vcpu *vcpu, u32 cmd)
{
- long rc = kvmppc_xics_hcall(vcpu, cmd);
+ long rc;
+
+ if (!vcpu->kvm->arch.irq_ctrler)
+ return EMULATE_FAIL;
+ rc = vcpu->kvm->arch.irq_ctrler->hcall(vcpu, cmd);
if (rc = H_TOO_HARD)
return EMULATE_FAIL;
kvmppc_set_gpr(vcpu, 3, rc);
@@ -259,9 +263,7 @@ int kvmppc_h_pr(struct kvm_vcpu *vcpu, unsigned long cmd)
case H_CPPR:
case H_EOI:
case H_IPI:
- if (kvmppc_xics_enabled(vcpu->kvm))
- return kvmppc_h_pr_xics_hcall(vcpu, cmd);
- break;
+ return kvmppc_h_pr_xics_hcall(vcpu, cmd);
case H_RTAS:
if (list_empty(&vcpu->kvm->arch.rtas_tokens))
return RESUME_HOST;
diff --git a/arch/powerpc/kvm/book3s_xics.c b/arch/powerpc/kvm/book3s_xics.c
index 7749060..2312b56 100644
--- a/arch/powerpc/kvm/book3s_xics.c
+++ b/arch/powerpc/kvm/book3s_xics.c
@@ -115,7 +115,7 @@ static void ics_check_resend(struct kvmppc_xics *xics, struct kvmppc_ics *ics,

int kvmppc_xics_set_xive(struct kvm *kvm, u32 irq, u32 server, u32 priority)
{
- struct kvmppc_xics *xics = kvm->arch.xics;
+ struct kvmppc_xics *xics = kvm->arch.irq_ctrler_private;
struct kvmppc_icp *icp;
struct kvmppc_ics *ics;
struct ics_irq_state *state;
@@ -158,7 +158,7 @@ int kvmppc_xics_set_xive(struct kvm *kvm, u32 irq, u32 server, u32 priority)

int kvmppc_xics_get_xive(struct kvm *kvm, u32 irq, u32 *server, u32 *priority)
{
- struct kvmppc_xics *xics = kvm->arch.xics;
+ struct kvmppc_xics *xics = kvm->arch.irq_ctrler_private;
struct kvmppc_ics *ics;
struct ics_irq_state *state;
u16 src;
@@ -514,7 +514,7 @@ static noinline int h_ipi(struct kvm_vcpu *vcpu, unsigned long server,
unsigned long mfrr)
{
union kvmppc_icp_state old_state, new_state;
- struct kvmppc_xics *xics = vcpu->kvm->arch.xics;
+ struct kvmppc_xics *xics = vcpu->kvm->arch.irq_ctrler_private;
struct kvmppc_icp *icp;
u32 reject;
bool resend;
@@ -582,7 +582,7 @@ static noinline int h_ipi(struct kvm_vcpu *vcpu, unsigned long server,
static noinline void h_cppr(struct kvm_vcpu *vcpu, unsigned long cppr)
{
union kvmppc_icp_state old_state, new_state;
- struct kvmppc_xics *xics = vcpu->kvm->arch.xics;
+ struct kvmppc_xics *xics = vcpu->kvm->arch.irq_ctrler_private;
struct kvmppc_icp *icp = vcpu->arch.icp;
u32 reject;

@@ -638,7 +638,7 @@ static noinline void h_cppr(struct kvm_vcpu *vcpu, unsigned long cppr)

static noinline int h_eoi(struct kvm_vcpu *vcpu, unsigned long xirr)
{
- struct kvmppc_xics *xics = vcpu->kvm->arch.xics;
+ struct kvmppc_xics *xics = vcpu->kvm->arch.irq_ctrler_private;
struct kvmppc_icp *icp = vcpu->arch.icp;
struct kvmppc_ics *ics;
struct ics_irq_state *state;
@@ -686,13 +686,13 @@ static noinline int h_eoi(struct kvm_vcpu *vcpu, unsigned long xirr)
return H_SUCCESS;
}

-int kvmppc_xics_hcall(struct kvm_vcpu *vcpu, u32 req)
+static int kvmppc_xics_hcall(struct kvm_vcpu *vcpu, unsigned long req)
{
unsigned long res;
int rc = H_SUCCESS;

/* Check if we have an ICP */
- if (!vcpu->arch.icp || !vcpu->kvm->arch.xics)
+ if (!vcpu->arch.icp || !vcpu->kvm->arch.irq_ctrler_private)
return H_HARDWARE;

switch (req) {
@@ -838,7 +838,7 @@ static struct kvmppc_ics *kvmppc_xics_create_ics(struct kvmppc_xics *xics,
return xics->ics[icsid];
}

-int kvmppc_xics_create_icp(struct kvm_vcpu *vcpu)
+static int kvmppc_xics_create_icp(struct kvm_vcpu *vcpu)
{
struct kvmppc_icp *icp;

@@ -856,7 +856,7 @@ int kvmppc_xics_create_icp(struct kvm_vcpu *vcpu)
return 0;
}

-void kvmppc_xics_free_icp(struct kvm_vcpu *vcpu)
+static void kvmppc_xics_free_icp(struct kvm_vcpu *vcpu)
{
if (!vcpu->arch.icp)
return;
@@ -864,9 +864,9 @@ void kvmppc_xics_free_icp(struct kvm_vcpu *vcpu)
vcpu->arch.icp = NULL;
}

-void kvmppc_xics_free(struct kvm *kvm)
+static void kvmppc_xics_free(struct kvm *kvm)
{
- struct kvmppc_xics *xics = kvm->arch.xics;
+ struct kvmppc_xics *xics = kvm->arch.irq_ctrler_private;
int i;

if (!xics)
@@ -877,7 +877,7 @@ void kvmppc_xics_free(struct kvm *kvm)
debugfs_remove(xics->dentry);

if (xics->kvm) {
- xics->kvm->arch.xics = NULL;
+ xics->kvm->arch.irq_ctrler_private = NULL;
xics->kvm = NULL;
}

@@ -891,7 +891,7 @@ void kvmppc_xics_free(struct kvm *kvm)
static int kvm_xics_get_sources(struct kvm *kvm, struct kvm_irq_sources *srcs)
{
int ret = 0;
- struct kvmppc_xics *xics = kvm->arch.xics;
+ struct kvmppc_xics *xics = kvm->arch.irq_ctrler_private;
struct kvmppc_ics *ics;
struct ics_irq_state *irqp;
u64 __user *ubufp;
@@ -941,7 +941,7 @@ static int kvm_xics_get_sources(struct kvm *kvm, struct kvm_irq_sources *srcs)
static int kvm_xics_set_sources(struct kvm *kvm, struct kvm_irq_sources *srcs)
{
int ret = 0;
- struct kvmppc_xics *xics = kvm->arch.xics;
+ struct kvmppc_xics *xics = kvm->arch.irq_ctrler_private;
struct kvmppc_ics *ics;
struct ics_irq_state *irqp;
u64 __user *ubufp;
@@ -999,39 +999,13 @@ static int kvm_xics_set_sources(struct kvm *kvm, struct kvm_irq_sources *srcs)

/* -- ioctls -- */

-int kvmppc_xics_create(struct kvm *kvm, struct kvm_irqchip_args *args)
-{
- struct kvmppc_xics *xics;
- int rc = 0;
-
- mutex_lock(&kvm->lock);
-
- /* Already there ? */
- if (kvm->arch.xics)
- return -EEXIST;
-
- xics = kzalloc(sizeof(*xics), GFP_KERNEL);
- if (!xics) {
- rc = -ENOMEM;
- goto out;
- }
-
- xics->kvm = kvm;
- kvm->arch.xics = xics;
- xics_debugfs_init(xics);
-
-out:
- mutex_unlock(&kvm->lock);
- return rc;
-}
-
static int kvm_vm_ioctl_xics_irq(struct kvm *kvm, struct kvm_irq_level *args)
{
struct kvmppc_xics *xics;

/* locking against multiple callers? */

- xics = kvm->arch.xics;
+ xics = kvm->arch.irq_ctrler_private;
if (!xics)
return -ENODEV;

@@ -1048,7 +1022,7 @@ static int kvm_vm_ioctl_xics_irq(struct kvm *kvm, struct kvm_irq_level *args)
return 0;
}

-int kvmppc_xics_ioctl(struct kvm *kvm, unsigned ioctl, unsigned long arg)
+static int kvmppc_xics_ioctl(struct kvm *kvm, unsigned ioctl, unsigned long arg)
{
void __user *argp = (void __user *)arg;
int rc;
@@ -1099,3 +1073,38 @@ int kvmppc_xics_ioctl(struct kvm *kvm, unsigned ioctl, unsigned long arg)

return rc;
}
+
+static struct kvm_irq_ctrler xics_ctrler = {
+ .setup_vcpu = kvmppc_xics_create_icp,
+ .teardown_vcpu = kvmppc_xics_free_icp,
+ .free_ctrler = kvmppc_xics_free,
+ .hcall = kvmppc_xics_hcall,
+ .ioctl = kvmppc_xics_ioctl,
+};
+
+int kvmppc_xics_create(struct kvm *kvm, struct kvm_irqchip_args *args)
+{
+ struct kvmppc_xics *xics;
+ int rc = 0;
+
+ mutex_lock(&kvm->lock);
+
+ /* Already there ? */
+ if (kvm->arch.irq_ctrler)
+ return -EEXIST;
+
+ xics = kzalloc(sizeof(*xics), GFP_KERNEL);
+ if (!xics) {
+ rc = -ENOMEM;
+ goto out;
+ }
+
+ xics->kvm = kvm;
+ kvm->arch.irq_ctrler = &xics_ctrler;
+ kvm->arch.irq_ctrler_private = xics;
+ xics_debugfs_init(xics);
+
+out:
+ mutex_unlock(&kvm->lock);
+ return rc;
+}
diff --git a/arch/powerpc/kvm/powerpc.c b/arch/powerpc/kvm/powerpc.c
index 3bcc030..e429839 100644
--- a/arch/powerpc/kvm/powerpc.c
+++ b/arch/powerpc/kvm/powerpc.c
@@ -1009,8 +1009,8 @@ long kvm_arch_vm_ioctl(struct file *filp,
struct kvm *kvm = filp->private_data;

r = -ENOTTY;
- if (kvmppc_xics_enabled(kvm))
- r = kvmppc_xics_ioctl(kvm, ioctl, arg);
+ if (kvm->arch.irq_ctrler)
+ r = kvm->arch.irq_ctrler->ioctl(kvm, ioctl, arg);
break;
}
case KVM_CREATE_IRQCHIP_ARGS: {
--
1.7.10.rc3.219.g53414