This adds support for using IRQFD with the in-kernel XICS emulation.
To do this, we have to tie the XICS in to the generic IRQ routing
infrastructure, meaning that we now have a xics_set_irq() function
and we use the generic kvm_set_irq() instead of defining our own.
We do not support emulated MSIs at this stage.  The level argument to
xics_set_irq can be 0 or 1, or can be one of the powerpc-specific
values KVM_INTERRUPT_SET, KVM_INTERRUPT_UNSET or
KVM_INTERRUPT_SET_LEVEL.

This also removes the `report_status' argument to ics_deliver_irq()
since it is always false, given that we don't support
KVM_IRQ_LINE_STATUS.

We also have to arrange to call kvm_notify_acked_irq() when an
interrupt has been processed, that is, when the guest does the H_EOI
hypercall.  If we are processing the XICS hypercalls in real mode then
we need to exit the guest to do that call.

Signed-off-by: Paul Mackerras <pau...@samba.org>
---
 arch/powerpc/kvm/Kconfig             |  2 +
 arch/powerpc/kvm/book3s_hv_rm_xics.c |  6 +++
 arch/powerpc/kvm/book3s_xics.c       | 80 ++++++++++++++++++++++++++++--------
 arch/powerpc/kvm/book3s_xics.h       |  2 +
 4 files changed, 74 insertions(+), 16 deletions(-)

diff --git a/arch/powerpc/kvm/Kconfig b/arch/powerpc/kvm/Kconfig
index ffaef2c..7bbb9c0 100644
--- a/arch/powerpc/kvm/Kconfig
+++ b/arch/powerpc/kvm/Kconfig
@@ -167,6 +167,8 @@ config KVM_MPIC
 config KVM_XICS
        bool "KVM in-kernel XICS emulation"
        depends on KVM_BOOK3S_64 && !KVM_MPIC
+       select HAVE_KVM_IRQCHIP
+       select HAVE_KVM_IRQ_ROUTING
        ---help---
          Include support for the XICS (eXternal Interrupt Controller
          Specification) interrupt controller architecture used on
diff --git a/arch/powerpc/kvm/book3s_hv_rm_xics.c 
b/arch/powerpc/kvm/book3s_hv_rm_xics.c
index b4b0082..d3eb4bd 100644
--- a/arch/powerpc/kvm/book3s_hv_rm_xics.c
+++ b/arch/powerpc/kvm/book3s_hv_rm_xics.c
@@ -401,6 +401,12 @@ int kvmppc_rm_h_eoi(struct kvm_vcpu *vcpu, unsigned long 
xirr)
                icp->rm_action |= XICS_RM_REJECT;
                icp->rm_reject = irq;
        }
+
+       if (!hlist_empty(&vcpu->kvm->irq_ack_notifier_list)) {
+               icp->rm_action |= XICS_RM_NOTIFY_EOI;
+               icp->rm_eoied_irq = irq;
+       }
+
  bail:
        return check_too_hard(xics, icp);
 }
diff --git a/arch/powerpc/kvm/book3s_xics.c b/arch/powerpc/kvm/book3s_xics.c
index a3a5cb8..324da28 100644
--- a/arch/powerpc/kvm/book3s_xics.c
+++ b/arch/powerpc/kvm/book3s_xics.c
@@ -35,6 +35,10 @@
 #define ENABLE_REALMODE        true
 #define DEBUG_REALMODE false
 
+static int xics_set_irq(struct kvm_kernel_irq_routing_entry *e,
+                       struct kvm *kvm, int irq_source_id, int level,
+                       bool line_status);
+
 /*
  * LOCKING
  * =======
@@ -64,8 +68,7 @@
 static void icp_deliver_irq(struct kvmppc_xics *xics, struct kvmppc_icp *icp,
                            u32 new_irq);
 
-static int ics_deliver_irq(struct kvmppc_xics *xics, u32 irq, u32 level,
-                          bool report_status)
+static int ics_deliver_irq(struct kvmppc_xics *xics, u32 irq, u32 level)
 {
        struct ics_irq_state *state;
        struct kvmppc_ics *ics;
@@ -82,17 +85,14 @@ static int ics_deliver_irq(struct kvmppc_xics *xics, u32 
irq, u32 level,
        if (!state->exists)
                return -EINVAL;
 
-       if (report_status)
-               return state->asserted;
-
        /*
         * We set state->asserted locklessly. This should be fine as
         * we are the only setter, thus concurrent access is undefined
         * to begin with.
         */
-       if (level == KVM_INTERRUPT_SET_LEVEL)
+       if (level == 1 || level == KVM_INTERRUPT_SET_LEVEL)
                state->asserted = 1;
-       else if (level == KVM_INTERRUPT_UNSET) {
+       else if (level == 0 || level == KVM_INTERRUPT_UNSET) {
                state->asserted = 0;
                return 0;
        }
@@ -100,7 +100,7 @@ static int ics_deliver_irq(struct kvmppc_xics *xics, u32 
irq, u32 level,
        /* Attempt delivery */
        icp_deliver_irq(xics, NULL, irq);
 
-       return state->asserted;
+       return 0;
 }
 
 static void ics_check_resend(struct kvmppc_xics *xics, struct kvmppc_ics *ics,
@@ -772,6 +772,8 @@ static noinline int kvmppc_h_eoi(struct kvm_vcpu *vcpu, 
unsigned long xirr)
        if (state->asserted)
                icp_deliver_irq(xics, icp, irq);
 
+       kvm_notify_acked_irq(vcpu->kvm, 0, irq);
+
        return H_SUCCESS;
 }
 
@@ -789,6 +791,8 @@ static noinline int kvmppc_xics_rm_complete(struct kvm_vcpu 
*vcpu, u32 hcall)
                icp_check_resend(xics, icp);
        if (icp->rm_action & XICS_RM_REJECT)
                icp_deliver_irq(xics, icp, icp->rm_reject);
+       if (icp->rm_action & XICS_RM_NOTIFY_EOI)
+               kvm_notify_acked_irq(vcpu->kvm, 0, icp->rm_eoied_irq);
 
        icp->rm_action = 0;
 
@@ -1164,14 +1168,6 @@ static int xics_set_source(struct kvmppc_xics *xics, 
long irq, u64 addr)
        return 0;
 }
 
-int kvm_set_irq(struct kvm *kvm, int irq_source_id, u32 irq, int level,
-               bool line_status)
-{
-       struct kvmppc_xics *xics = kvm->arch.xics;
-
-       return ics_deliver_irq(xics, irq, level, line_status);
-}
-
 static int xics_set_attr(struct kvm_device *dev, struct kvm_device_attr *attr)
 {
        struct kvmppc_xics *xics = dev->private;
@@ -1248,6 +1244,10 @@ static int kvmppc_xics_create(struct kvm_device *dev, 
u32 type)
        if (ret)
                return ret;
 
+       kvm->default_irq_route.type = KVM_IRQ_ROUTING_IRQCHIP;
+       kvm->default_irq_route.set = xics_set_irq;
+       kvm->default_irq_route.irqchip.irqchip = 0;
+
        xics_debugfs_init(xics);
 
 #ifdef CONFIG_KVM_BOOK3S_64_HV
@@ -1298,3 +1298,51 @@ void kvmppc_xics_free_icp(struct kvm_vcpu *vcpu)
        vcpu->arch.icp = NULL;
        vcpu->arch.irq_type = KVMPPC_IRQ_DEFAULT;
 }
+
+/*
+ * Return value ideally indicates how the interrupt was handled, but no
+ * callers look at it (given that we don't implement KVM_IRQ_LINE_STATUS),
+ * so just return 0.
+ */
+static int xics_set_irq(struct kvm_kernel_irq_routing_entry *e,
+                       struct kvm *kvm, int irq_source_id, int level,
+                       bool line_status)
+{
+       struct kvmppc_xics *xics = kvm->arch.xics;
+       u32 irq = e->irqchip.pin;
+
+       return ics_deliver_irq(xics, irq, level);
+}
+
+int kvm_set_msi(struct kvm_kernel_irq_routing_entry *e,
+               struct kvm *kvm, int irq_source_id, int level, bool line_status)
+{
+       return -EINVAL;
+}
+
+int kvm_set_routing_entry(struct kvm_irq_routing_table *rt,
+                         struct kvm_kernel_irq_routing_entry *e,
+                         const struct kvm_irq_routing_entry *ue)
+{
+       int r = -EINVAL;
+
+       switch (ue->type) {
+       case KVM_IRQ_ROUTING_IRQCHIP:
+               e->set = xics_set_irq;
+               e->irqchip.irqchip = ue->u.irqchip.irqchip;
+               e->irqchip.pin = ue->u.irqchip.pin;
+               if (e->irqchip.pin >= KVM_IRQCHIP_NUM_PINS)
+                       goto out;
+               rt->chip[ue->u.irqchip.irqchip][e->irqchip.pin] = ue->gsi;
+               break;
+       case KVM_IRQ_ROUTING_MSI:
+               /* No MSI support for now */
+               goto out;
+       default:
+               goto out;
+       }
+
+       r = 0;
+out:
+       return r;
+}
diff --git a/arch/powerpc/kvm/book3s_xics.h b/arch/powerpc/kvm/book3s_xics.h
index dd9326c..e8aaa7a 100644
--- a/arch/powerpc/kvm/book3s_xics.h
+++ b/arch/powerpc/kvm/book3s_xics.h
@@ -71,9 +71,11 @@ struct kvmppc_icp {
 #define XICS_RM_KICK_VCPU      0x1
 #define XICS_RM_CHECK_RESEND   0x2
 #define XICS_RM_REJECT         0x4
+#define XICS_RM_NOTIFY_EOI     0x8
        u32 rm_action;
        struct kvm_vcpu *rm_kick_target;
        u32  rm_reject;
+       u32  rm_eoied_irq;
 
        /* Debug stuff for real mode */
        union kvmppc_icp_state rm_dbgstate;
-- 
1.8.4.rc3

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

Reply via email to