summaryrefslogtreecommitdiff
path: root/arch/powerpc/kvm/book3s_xics.c
diff options
context:
space:
mode:
Diffstat (limited to 'arch/powerpc/kvm/book3s_xics.c')
-rw-r--r--arch/powerpc/kvm/book3s_xics.c55
1 files changed, 46 insertions, 9 deletions
diff --git a/arch/powerpc/kvm/book3s_xics.c b/arch/powerpc/kvm/book3s_xics.c
index d1acd32a64c0..eaeb78047fb8 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;
+}