@@ -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
@@ -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);
}
@@ -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;
+}
@@ -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;
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 <paulus@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(-)