KVM: PPC: Enable IRQFD support for the XICS interrupt controller
authorPaul Mackerras <paulus@samba.org>
Mon, 30 Jun 2014 10:51:14 +0000 (20:51 +1000)
committerPaolo Bonzini <pbonzini@redhat.com>
Tue, 5 Aug 2014 12:26:33 +0000 (14:26 +0200)
This makes it possible to use IRQFDs on platforms that use the XICS
interrupt controller.  To do this we implement kvm_irq_map_gsi() and
kvm_irq_map_chip_pin() in book3s_xics.c, so as to provide a 1-1 mapping
between global interrupt numbers and XICS interrupt source numbers.
For now, all interrupts are mapped as "IRQCHIP" interrupts, and no
MSI support is provided.

This means that kvm_set_irq can now get called with level == 0 or 1
as well as the powerpc-specific values KVM_INTERRUPT_SET,
KVM_INTERRUPT_UNSET and KVM_INTERRUPT_SET_LEVEL.  We change
ics_deliver_irq() to accept all those values, and remove its
report_status argument, as it is always false, given that we don't
support KVM_IRQ_LINE_STATUS.

This also adds support for interrupt ack notifiers to the XICS code
so that the IRQFD resampler functionality can be supported.

Signed-off-by: Paul Mackerras <paulus@samba.org>
Tested-by: Eric Auger <eric.auger@linaro.org>
Tested-by: Cornelia Huck <cornelia.huck@de.ibm.com>
Signed-off-by: Paolo Bonzini <pbonzini@redhat.com>
arch/powerpc/kvm/Kconfig
arch/powerpc/kvm/book3s_hv_rm_xics.c
arch/powerpc/kvm/book3s_xics.c
arch/powerpc/kvm/book3s_xics.h

index d4741db..602eb51 100644 (file)
@@ -170,6 +170,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_IRQFD
        ---help---
          Include support for the XICS (eXternal Interrupt Controller
          Specification) interrupt controller architecture used on
index b4b0082..3ee38e6 100644 (file)
@@ -401,6 +401,11 @@ 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);
 }
index d1acd32..eaeb780 100644 (file)
 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)
+/*
+ * 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 ics_deliver_irq(struct kvmppc_xics *xics, u32 irq, u32 level)
 {
        struct ics_irq_state *state;
        struct kvmppc_ics *ics;
@@ -82,17 +86,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 +101,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 +773,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 +792,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;
 
@@ -1170,7 +1175,16 @@ int kvm_set_irq(struct kvm *kvm, int irq_source_id, u32 irq, int level,
 {
        struct kvmppc_xics *xics = kvm->arch.xics;
 
-       return ics_deliver_irq(xics, irq, level, line_status);
+       return ics_deliver_irq(xics, irq, level);
+}
+
+int kvm_set_msi(struct kvm_kernel_irq_routing_entry *irq_entry, struct kvm *kvm,
+               int irq_source_id, int level, bool line_status)
+{
+       if (!level)
+               return -1;
+       return kvm_set_irq(kvm, irq_source_id, irq_entry->gsi,
+                          level, line_status);
 }
 
 static int xics_set_attr(struct kvm_device *dev, struct kvm_device_attr *attr)
@@ -1301,3 +1315,26 @@ void kvmppc_xics_free_icp(struct kvm_vcpu *vcpu)
        vcpu->arch.icp = NULL;
        vcpu->arch.irq_type = KVMPPC_IRQ_DEFAULT;
 }
+
+static int xics_set_irq(struct kvm_kernel_irq_routing_entry *e,
+                       struct kvm *kvm, int irq_source_id, int level,
+                       bool line_status)
+{
+       return kvm_set_irq(kvm, irq_source_id, e->gsi, level, line_status);
+}
+
+int kvm_irq_map_gsi(struct kvm *kvm,
+                   struct kvm_kernel_irq_routing_entry *entries, int gsi)
+{
+       entries->gsi = gsi;
+       entries->type = KVM_IRQ_ROUTING_IRQCHIP;
+       entries->set = xics_set_irq;
+       entries->irqchip.irqchip = 0;
+       entries->irqchip.pin = gsi;
+       return 1;
+}
+
+int kvm_irq_map_chip_pin(struct kvm *kvm, unsigned irqchip, unsigned pin)
+{
+       return pin;
+}
index dd9326c..e8aaa7a 100644 (file)
@@ -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;