aboutsummaryrefslogtreecommitdiff
path: root/hw/pci-host
diff options
context:
space:
mode:
authorPavel Dovgalyuk <Pavel.Dovgaluk@ispras.ru>2014-08-28 15:19:19 +0400
committerPaolo Bonzini <pbonzini@redhat.com>2014-09-11 12:20:32 +0200
commit2c9ecdeb9fbad9e414c2a7da676804992b568d13 (patch)
tree52bccb6b217a73f4c14469a0884f15c6aa039883 /hw/pci-host
parent7385b275d9ae8bdf3c012bc4e2ae9779fcea6312 (diff)
piix: do not set irq while loading vmstate
This patch avoids setting an irq while loading the state of the ISA bridge. Because the i8259 has not been deserialized yet, raising an interrupt could bring the system out-of-sync with the migration source. For example, the migration source could have masked the interrupt in the i8259. On the destination, the i8259 device model would not know that yet and would trigger an interrupt in the CPU. This patch eliminates setting the irq and just restores the calculated state fields in post_load function. Interrupt state will be deserialized separately through the IRR field of the i8259. Signed-off-by: Pavel Dovgalyuk <Pavel.Dovgaluk@ispras.ru> Reviewed-by: Michael S. Tsirkin <mst@redhat.com> Signed-off-by: Paolo Bonzini <pbonzini@redhat.com>
Diffstat (limited to 'hw/pci-host')
-rw-r--r--hw/pci-host/piix.c30
1 files changed, 28 insertions, 2 deletions
diff --git a/hw/pci-host/piix.c b/hw/pci-host/piix.c
index e0e0946092..1530038cb0 100644
--- a/hw/pci-host/piix.c
+++ b/hw/pci-host/piix.c
@@ -409,7 +409,7 @@ static void piix3_set_irq_pic(PIIX3State *piix3, int pic_irq)
(pic_irq * PIIX_NUM_PIRQS))));
}
-static void piix3_set_irq_level(PIIX3State *piix3, int pirq, int level)
+static void piix3_set_irq_level_internal(PIIX3State *piix3, int pirq, int level)
{
int pic_irq;
uint64_t mask;
@@ -422,6 +422,18 @@ static void piix3_set_irq_level(PIIX3State *piix3, int pirq, int level)
mask = 1ULL << ((pic_irq * PIIX_NUM_PIRQS) + pirq);
piix3->pic_levels &= ~mask;
piix3->pic_levels |= mask * !!level;
+}
+
+static void piix3_set_irq_level(PIIX3State *piix3, int pirq, int level)
+{
+ int pic_irq;
+
+ pic_irq = piix3->dev.config[PIIX_PIRQC + pirq];
+ if (pic_irq >= PIIX_NUM_PIC_IRQS) {
+ return;
+ }
+
+ piix3_set_irq_level_internal(piix3, pirq, level);
piix3_set_irq_pic(piix3, pic_irq);
}
@@ -527,7 +539,21 @@ static void piix3_reset(void *opaque)
static int piix3_post_load(void *opaque, int version_id)
{
PIIX3State *piix3 = opaque;
- piix3_update_irq_levels(piix3);
+ int pirq;
+
+ /* Because the i8259 has not been deserialized yet, qemu_irq_raise
+ * might bring the system to a different state than the saved one;
+ * for example, the interrupt could be masked but the i8259 would
+ * not know that yet and would trigger an interrupt in the CPU.
+ *
+ * Here, we update irq levels without raising the interrupt.
+ * Interrupt state will be deserialized separately through the i8259.
+ */
+ piix3->pic_levels = 0;
+ for (pirq = 0; pirq < PIIX_NUM_PIRQS; pirq++) {
+ piix3_set_irq_level_internal(piix3, pirq,
+ pci_bus_get_irq_level(piix3->dev.bus, pirq));
+ }
return 0;
}