|
@@ -1076,7 +1076,9 @@ static int openpic_cpu_write_internal(void *opaque, gpa_t addr,
|
|
|
case 0xA0: /* IACK */
|
|
|
/* Read-only register */
|
|
|
break;
|
|
|
- case 0xB0: /* EOI */
|
|
|
+ case 0xB0: { /* EOI */
|
|
|
+ int notify_eoi;
|
|
|
+
|
|
|
pr_debug("EOI\n");
|
|
|
s_IRQ = IRQ_get_next(opp, &dst->servicing);
|
|
|
|
|
@@ -1087,6 +1089,8 @@ static int openpic_cpu_write_internal(void *opaque, gpa_t addr,
|
|
|
}
|
|
|
|
|
|
IRQ_resetbit(&dst->servicing, s_IRQ);
|
|
|
+ /* Notify listeners that the IRQ is over */
|
|
|
+ notify_eoi = s_IRQ;
|
|
|
/* Set up next servicing IRQ */
|
|
|
s_IRQ = IRQ_get_next(opp, &dst->servicing);
|
|
|
/* Check queued interrupts. */
|
|
@@ -1099,7 +1103,13 @@ static int openpic_cpu_write_internal(void *opaque, gpa_t addr,
|
|
|
idx, n_IRQ);
|
|
|
mpic_irq_raise(opp, dst, ILR_INTTGT_INT);
|
|
|
}
|
|
|
+
|
|
|
+ spin_unlock(&opp->lock);
|
|
|
+ kvm_notify_acked_irq(opp->kvm, 0, notify_eoi);
|
|
|
+ spin_lock(&opp->lock);
|
|
|
+
|
|
|
break;
|
|
|
+ }
|
|
|
default:
|
|
|
break;
|
|
|
}
|
|
@@ -1639,14 +1649,34 @@ static void mpic_destroy(struct kvm_device *dev)
|
|
|
unmap_mmio(opp);
|
|
|
}
|
|
|
|
|
|
+ dev->kvm->arch.mpic = NULL;
|
|
|
kfree(opp);
|
|
|
}
|
|
|
|
|
|
+static int mpic_set_default_irq_routing(struct openpic *opp)
|
|
|
+{
|
|
|
+ struct kvm_irq_routing_entry *routing;
|
|
|
+
|
|
|
+ /* Create a nop default map, so that dereferencing it still works */
|
|
|
+ routing = kzalloc((sizeof(*routing)), GFP_KERNEL);
|
|
|
+ if (!routing)
|
|
|
+ return -ENOMEM;
|
|
|
+
|
|
|
+ kvm_set_irq_routing(opp->kvm, routing, 0, 0);
|
|
|
+
|
|
|
+ kfree(routing);
|
|
|
+ return 0;
|
|
|
+}
|
|
|
+
|
|
|
static int mpic_create(struct kvm_device *dev, u32 type)
|
|
|
{
|
|
|
struct openpic *opp;
|
|
|
int ret;
|
|
|
|
|
|
+ /* We only support one MPIC at a time for now */
|
|
|
+ if (dev->kvm->arch.mpic)
|
|
|
+ return -EINVAL;
|
|
|
+
|
|
|
opp = kzalloc(sizeof(struct openpic), GFP_KERNEL);
|
|
|
if (!opp)
|
|
|
return -ENOMEM;
|
|
@@ -1691,7 +1721,15 @@ static int mpic_create(struct kvm_device *dev, u32 type)
|
|
|
goto err;
|
|
|
}
|
|
|
|
|
|
+ ret = mpic_set_default_irq_routing(opp);
|
|
|
+ if (ret)
|
|
|
+ goto err;
|
|
|
+
|
|
|
openpic_reset(opp);
|
|
|
+
|
|
|
+ smp_wmb();
|
|
|
+ dev->kvm->arch.mpic = opp;
|
|
|
+
|
|
|
return 0;
|
|
|
|
|
|
err:
|
|
@@ -1761,3 +1799,74 @@ void kvmppc_mpic_disconnect_vcpu(struct openpic *opp, struct kvm_vcpu *vcpu)
|
|
|
opp->dst[vcpu->arch.irq_cpu_id].vcpu = NULL;
|
|
|
kvm_device_put(opp->dev);
|
|
|
}
|
|
|
+
|
|
|
+/*
|
|
|
+ * Return value:
|
|
|
+ * < 0 Interrupt was ignored (masked or not delivered for other reasons)
|
|
|
+ * = 0 Interrupt was coalesced (previous irq is still pending)
|
|
|
+ * > 0 Number of CPUs interrupt was delivered to
|
|
|
+ */
|
|
|
+static int mpic_set_irq(struct kvm_kernel_irq_routing_entry *e,
|
|
|
+ struct kvm *kvm, int irq_source_id, int level,
|
|
|
+ bool line_status)
|
|
|
+{
|
|
|
+ u32 irq = e->irqchip.pin;
|
|
|
+ struct openpic *opp = kvm->arch.mpic;
|
|
|
+ unsigned long flags;
|
|
|
+
|
|
|
+ spin_lock_irqsave(&opp->lock, flags);
|
|
|
+ openpic_set_irq(opp, irq, level);
|
|
|
+ spin_unlock_irqrestore(&opp->lock, flags);
|
|
|
+
|
|
|
+ /* All code paths we care about don't check for the return value */
|
|
|
+ return 0;
|
|
|
+}
|
|
|
+
|
|
|
+int kvm_set_msi(struct kvm_kernel_irq_routing_entry *e,
|
|
|
+ struct kvm *kvm, int irq_source_id, int level, bool line_status)
|
|
|
+{
|
|
|
+ struct openpic *opp = kvm->arch.mpic;
|
|
|
+ unsigned long flags;
|
|
|
+
|
|
|
+ spin_lock_irqsave(&opp->lock, flags);
|
|
|
+
|
|
|
+ /*
|
|
|
+ * XXX We ignore the target address for now, as we only support
|
|
|
+ * a single MSI bank.
|
|
|
+ */
|
|
|
+ openpic_msi_write(kvm->arch.mpic, MSIIR_OFFSET, e->msi.data);
|
|
|
+ spin_unlock_irqrestore(&opp->lock, flags);
|
|
|
+
|
|
|
+ /* All code paths we care about don't check for the return value */
|
|
|
+ return 0;
|
|
|
+}
|
|
|
+
|
|
|
+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 = mpic_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:
|
|
|
+ e->set = kvm_set_msi;
|
|
|
+ e->msi.address_lo = ue->u.msi.address_lo;
|
|
|
+ e->msi.address_hi = ue->u.msi.address_hi;
|
|
|
+ e->msi.data = ue->u.msi.data;
|
|
|
+ break;
|
|
|
+ default:
|
|
|
+ goto out;
|
|
|
+ }
|
|
|
+
|
|
|
+ r = 0;
|
|
|
+out:
|
|
|
+ return r;
|
|
|
+}
|