aboutsummaryrefslogtreecommitdiff
path: root/hw/intc
diff options
context:
space:
mode:
authorGreg Kurz <groug@kaod.org>2019-02-19 18:18:03 +0100
committerDavid Gibson <david@gibson.dropbear.id.au>2019-02-26 09:21:25 +1100
commit6cead90c5c9c462c56ddc41a0bd0b4cfef9f62a8 (patch)
treed1e5651c0c61339b3d86c61e1c2981a561c4d6bc /hw/intc
parent09d876ce2c8ea3efd34e02d898c3122e04b814bc (diff)
xics: Write source state to KVM at claim time
The pseries machine only uses LSIs to support legacy PCI devices. Every PHB claims 4 LSIs at realize time. When using in-kernel XICS (or upcoming in-kernel XIVE), QEMU synchronizes the state of all irqs, including these LSIs, later on at machine reset. In order to support PHB hotplug, we need a way to tell KVM about the LSIs that doesn't require a machine reset. An easy way to do that is to always inform KVM when an interrupt is claimed, which really isn't a performance path. Signed-off-by: Greg Kurz <groug@kaod.org> Message-Id: <155059668360.1466090.5969630516627776426.stgit@bahia.lab.toulouse-stg.fr.ibm.com> Reviewed-by: Cédric Le Goater <clg@kaod.org> Signed-off-by: David Gibson <david@gibson.dropbear.id.au>
Diffstat (limited to 'hw/intc')
-rw-r--r--hw/intc/xics.c4
-rw-r--r--hw/intc/xics_kvm.c74
2 files changed, 47 insertions, 31 deletions
diff --git a/hw/intc/xics.c b/hw/intc/xics.c
index 767fdeb829..af7dc709ab 100644
--- a/hw/intc/xics.c
+++ b/hw/intc/xics.c
@@ -758,6 +758,10 @@ void ics_set_irq_type(ICSState *ics, int srcno, bool lsi)
ics->irqs[srcno].flags |=
lsi ? XICS_FLAGS_IRQ_LSI : XICS_FLAGS_IRQ_MSI;
+
+ if (kvm_irqchip_in_kernel()) {
+ ics_set_kvm_state_one(ics, srcno);
+ }
}
static void xics_register_types(void)
diff --git a/hw/intc/xics_kvm.c b/hw/intc/xics_kvm.c
index a00d0a7962..c6e1b630a4 100644
--- a/hw/intc/xics_kvm.c
+++ b/hw/intc/xics_kvm.c
@@ -213,45 +213,57 @@ void ics_synchronize_state(ICSState *ics)
ics_get_kvm_state(ics);
}
-int ics_set_kvm_state(ICSState *ics)
+int ics_set_kvm_state_one(ICSState *ics, int srcno)
{
uint64_t state;
- int i;
Error *local_err = NULL;
+ ICSIRQState *irq = &ics->irqs[srcno];
+ int ret;
- for (i = 0; i < ics->nr_irqs; i++) {
- ICSIRQState *irq = &ics->irqs[i];
- int ret;
-
- state = irq->server;
- state |= (uint64_t)(irq->saved_priority & KVM_XICS_PRIORITY_MASK)
- << KVM_XICS_PRIORITY_SHIFT;
- if (irq->priority != irq->saved_priority) {
- assert(irq->priority == 0xff);
- state |= KVM_XICS_MASKED;
- }
+ state = irq->server;
+ state |= (uint64_t)(irq->saved_priority & KVM_XICS_PRIORITY_MASK)
+ << KVM_XICS_PRIORITY_SHIFT;
+ if (irq->priority != irq->saved_priority) {
+ assert(irq->priority == 0xff);
+ state |= KVM_XICS_MASKED;
+ }
- if (ics->irqs[i].flags & XICS_FLAGS_IRQ_LSI) {
- state |= KVM_XICS_LEVEL_SENSITIVE;
- if (irq->status & XICS_STATUS_ASSERTED) {
- state |= KVM_XICS_PENDING;
- }
- } else {
- if (irq->status & XICS_STATUS_MASKED_PENDING) {
- state |= KVM_XICS_PENDING;
- }
+ if (irq->flags & XICS_FLAGS_IRQ_LSI) {
+ state |= KVM_XICS_LEVEL_SENSITIVE;
+ if (irq->status & XICS_STATUS_ASSERTED) {
+ state |= KVM_XICS_PENDING;
}
- if (irq->status & XICS_STATUS_PRESENTED) {
- state |= KVM_XICS_PRESENTED;
- }
- if (irq->status & XICS_STATUS_QUEUED) {
- state |= KVM_XICS_QUEUED;
+ } else {
+ if (irq->status & XICS_STATUS_MASKED_PENDING) {
+ state |= KVM_XICS_PENDING;
}
+ }
+ if (irq->status & XICS_STATUS_PRESENTED) {
+ state |= KVM_XICS_PRESENTED;
+ }
+ if (irq->status & XICS_STATUS_QUEUED) {
+ state |= KVM_XICS_QUEUED;
+ }
+
+ ret = kvm_device_access(kernel_xics_fd, KVM_DEV_XICS_GRP_SOURCES,
+ srcno + ics->offset, &state, true, &local_err);
+ if (local_err) {
+ error_report_err(local_err);
+ return ret;
+ }
+
+ return 0;
+}
+
+int ics_set_kvm_state(ICSState *ics)
+{
+ int i;
+
+ for (i = 0; i < ics->nr_irqs; i++) {
+ int ret;
- ret = kvm_device_access(kernel_xics_fd, KVM_DEV_XICS_GRP_SOURCES,
- i + ics->offset, &state, true, &local_err);
- if (local_err) {
- error_report_err(local_err);
+ ret = ics_set_kvm_state_one(ics, i);
+ if (ret) {
return ret;
}
}