194 lines
6.4 KiB
Diff
194 lines
6.4 KiB
Diff
From: Paul Mackerras <paulus@samba.org>
|
|
Date: Mon, 30 Jun 2014 20:51:14 +1000
|
|
Subject: KVM: PPC: Enable IRQFD support for the XICS interrupt
|
|
controller
|
|
Origin: https://git.kernel.org/linus/25a2150bee00b4d996487552948b9b3ba21d0257
|
|
|
|
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 | 2 ++
|
|
arch/powerpc/kvm/book3s_hv_rm_xics.c | 5 ++++
|
|
arch/powerpc/kvm/book3s_xics.c | 55 ++++++++++++++++++++++++++++------
|
|
arch/powerpc/kvm/book3s_xics.h | 2 ++
|
|
4 files changed, 55 insertions(+), 9 deletions(-)
|
|
|
|
diff --git a/arch/powerpc/kvm/Kconfig b/arch/powerpc/kvm/Kconfig
|
|
index d4741db..602eb51 100644
|
|
--- a/arch/powerpc/kvm/Kconfig
|
|
+++ b/arch/powerpc/kvm/Kconfig
|
|
@@ -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
|
|
diff --git a/arch/powerpc/kvm/book3s_hv_rm_xics.c b/arch/powerpc/kvm/book3s_hv_rm_xics.c
|
|
index b4b0082..3ee38e6 100644
|
|
--- a/arch/powerpc/kvm/book3s_hv_rm_xics.c
|
|
+++ b/arch/powerpc/kvm/book3s_hv_rm_xics.c
|
|
@@ -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);
|
|
}
|
|
diff --git a/arch/powerpc/kvm/book3s_xics.c b/arch/powerpc/kvm/book3s_xics.c
|
|
index d1acd32..eaeb780 100644
|
|
--- a/arch/powerpc/kvm/book3s_xics.c
|
|
+++ b/arch/powerpc/kvm/book3s_xics.c
|
|
@@ -64,8 +64,12 @@
|
|
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;
|
|
+}
|
|
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.7.10.4
|
|
|