From e9adf2605da1827b223807b4a2efafe97d7568e6 Mon Sep 17 00:00:00 2001
From: "Michael S. Tsirkin" <mst@redhat.com>
Date: Mon, 4 Jun 2012 17:29:54 +0300
Subject: [PATCH 01/12] shpc: unparent device before free

Recent core change removed unparent
so we need to do this in all callers now.

Signed-off-by: Michael S. Tsirkin <mst@redhat.com>
---
 hw/shpc.c | 1 +
 1 file changed, 1 insertion(+)

diff --git a/hw/shpc.c b/hw/shpc.c
index a5baf246f1..6b9884d544 100644
--- a/hw/shpc.c
+++ b/hw/shpc.c
@@ -253,6 +253,7 @@ static void shpc_free_devices_in_slot(SHPCDevice *shpc, int slot)
          ++devfn) {
         PCIDevice *affected_dev = shpc->sec_bus->devices[devfn];
         if (affected_dev) {
+            object_unparent(OBJECT(affected_dev));
             qdev_free(&affected_dev->qdev);
         }
     }

From fee9d348ffc5c9f80068086799a948996f633f7e Mon Sep 17 00:00:00 2001
From: Fernando Luis Vazquez Cao <fernando@oss.ntt.co.jp>
Date: Mon, 4 Jun 2012 17:35:11 +0300
Subject: [PATCH 02/12] rtl8139: honor RxOverflow flag in can_receive method

Some drivers (Linux' 8139too among them) rely on the NIC
injecting an interrupt in the event of a receive buffer overflow
and, accordingly, set the RxOverflow bit in the interrupt
mask. Unfortunately rtl8139's can_receive method ignores the
RxOverflow flag, which may lead to a situation where rtl8139
stops receiving packets (can_receive returns 0) when the receive
buffer becomes full.

If the driver eventually read from the receive buffer or reset
the card the emulator could recover from this situation. However
some implementations only do this upon receiving an interrupt
with either RxOK or RxOverflow set in the ISR; interrupt that
will never come because QEMU's flow control mechanisms would
prevent rtl8139 from receiving any packet.

Letting packets go through when the overflow interrupt is enabled
makes the QEMU emulator compliant to the spec and solves the
problem.

This patch should fix a relatively common (in our experience)
network stall observed when running enterprise distros with
rtl8139 as the NIC; in some cases the 8139too device driver gets
loaded and when under heavy load the network eventually stops
working.

Reported-by: Hayato Kakuta <kakuta.hayato@oss.ntt.co.jp>
Tested-by: Hayato Kakuta <kakuta.hayato@oss.ntt.co.jp>
Acked-by: Igor Kovalenko <igor.v.kovalenko@gmail.com>
Signed-off-by: Fernando Luis Vazquez Cao <fernando@oss.ntt.co.jp>
Signed-off-by: Michael S. Tsirkin <mst@redhat.com>
---
 hw/rtl8139.c | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/hw/rtl8139.c b/hw/rtl8139.c
index 2413bc3d25..060404c137 100644
--- a/hw/rtl8139.c
+++ b/hw/rtl8139.c
@@ -799,7 +799,7 @@ static int rtl8139_can_receive(VLANClientState *nc)
     } else {
         avail = MOD2(s->RxBufferSize + s->RxBufPtr - s->RxBufAddr,
                      s->RxBufferSize);
-        return (avail == 0 || avail >= 1514);
+        return (avail == 0 || avail >= 1514 || (s->IntrMask & RxOverflow));
     }
 }
 

From 868a1a52267daddf933ee18480ae036da029b561 Mon Sep 17 00:00:00 2001
From: Jan Kiszka <jan.kiszka@siemens.com>
Date: Fri, 11 May 2012 11:42:34 -0300
Subject: [PATCH 03/12] ahci: Fix reset of MSI function

Call msi_reset on device reset as still required by the core.

CC: Alexander Graf <agraf@suse.de>
CC: qemu-stable@nongnu.org
Signed-off-by: Jan Kiszka <jan.kiszka@siemens.com>
Signed-off-by: Michael S. Tsirkin <mst@redhat.com>
---
 hw/ide/ich.c | 12 ++++++++++--
 1 file changed, 10 insertions(+), 2 deletions(-)

diff --git a/hw/ide/ich.c b/hw/ide/ich.c
index 560ae37618..242254e8d8 100644
--- a/hw/ide/ich.c
+++ b/hw/ide/ich.c
@@ -84,6 +84,14 @@ static const VMStateDescription vmstate_ahci = {
     .unmigratable = 1,
 };
 
+static void pci_ich9_reset(void *opaque)
+{
+    struct AHCIPCIState *d = opaque;
+
+    msi_reset(&d->card);
+    ahci_reset(opaque);
+}
+
 static int pci_ich9_ahci_init(PCIDevice *dev)
 {
     struct AHCIPCIState *d;
@@ -102,7 +110,7 @@ static int pci_ich9_ahci_init(PCIDevice *dev)
     /* XXX Software should program this register */
     d->card.config[0x90]   = 1 << 6; /* Address Map Register - AHCI mode */
 
-    qemu_register_reset(ahci_reset, d);
+    qemu_register_reset(pci_ich9_reset, d);
 
     msi_init(dev, 0x50, 1, true, false);
     d->ahci.irq = d->card.irq[0];
@@ -133,7 +141,7 @@ static int pci_ich9_uninit(PCIDevice *dev)
     d = DO_UPCAST(struct AHCIPCIState, card, dev);
 
     msi_uninit(dev);
-    qemu_unregister_reset(ahci_reset, d);
+    qemu_unregister_reset(pci_ich9_reset, d);
     ahci_uninit(&d->ahci);
 
     return 0;

From 8e729e3b521d9fcd87fc2e40b6322e684f58bb2e Mon Sep 17 00:00:00 2001
From: Jan Kiszka <jan.kiszka@siemens.com>
Date: Fri, 11 May 2012 11:42:35 -0300
Subject: [PATCH 04/12] intel-hda: Fix reset of MSI function

Call msi_reset on device reset as still required by the core.

CC: Gerd Hoffmann <kraxel@redhat.com>
CC: qemu-stable@nongnu.org
Signed-off-by: Jan Kiszka <jan.kiszka@siemens.com>
Signed-off-by: Michael S. Tsirkin <mst@redhat.com>
---
 hw/intel-hda.c | 3 +++
 1 file changed, 3 insertions(+)

diff --git a/hw/intel-hda.c b/hw/intel-hda.c
index bb11af286a..e38861e5de 100644
--- a/hw/intel-hda.c
+++ b/hw/intel-hda.c
@@ -1107,6 +1107,9 @@ static void intel_hda_reset(DeviceState *dev)
     DeviceState *qdev;
     HDACodecDevice *cdev;
 
+    if (d->msi) {
+        msi_reset(&d->pci);
+    }
     intel_hda_regs_reset(d);
     d->wall_base_ns = qemu_get_clock_ns(vm_clock);
 

From 8ab60a0703d182d61a0c4e3db35cf70ab57d89aa Mon Sep 17 00:00:00 2001
From: Jan Kiszka <jan.kiszka@siemens.com>
Date: Fri, 11 May 2012 11:42:36 -0300
Subject: [PATCH 05/12] ahci: Clean up reset functions

Properly register reset functions via the device class.

CC: Alexander Graf <agraf@suse.de>
Signed-off-by: Jan Kiszka <jan.kiszka@siemens.com>
Signed-off-by: Michael S. Tsirkin <mst@redhat.com>
---
 hw/ide/ahci.c | 25 +++++++++++++++----------
 hw/ide/ahci.h |  2 +-
 hw/ide/ich.c  | 10 ++++------
 3 files changed, 20 insertions(+), 17 deletions(-)

diff --git a/hw/ide/ahci.c b/hw/ide/ahci.c
index 2d7d03d772..e275e68934 100644
--- a/hw/ide/ahci.c
+++ b/hw/ide/ahci.c
@@ -339,7 +339,7 @@ static void ahci_mem_write(void *opaque, target_phys_addr_t addr,
             case HOST_CTL: /* R/W */
                 if (val & HOST_CTL_RESET) {
                     DPRINTF(-1, "HBA Reset\n");
-                    ahci_reset(container_of(s, AHCIPCIState, ahci));
+                    ahci_reset(s);
                 } else {
                     s->control_regs.ghc = (val & 0x3) | HOST_CTL_AHCI_EN;
                     ahci_check_irq(s);
@@ -1149,21 +1149,20 @@ void ahci_uninit(AHCIState *s)
     g_free(s->dev);
 }
 
-void ahci_reset(void *opaque)
+void ahci_reset(AHCIState *s)
 {
-    struct AHCIPCIState *d = opaque;
     AHCIPortRegs *pr;
     int i;
 
-    d->ahci.control_regs.irqstatus = 0;
-    d->ahci.control_regs.ghc = 0;
+    s->control_regs.irqstatus = 0;
+    s->control_regs.ghc = 0;
 
-    for (i = 0; i < d->ahci.ports; i++) {
-        pr = &d->ahci.dev[i].port_regs;
+    for (i = 0; i < s->ports; i++) {
+        pr = &s->dev[i].port_regs;
         pr->irq_stat = 0;
         pr->irq_mask = 0;
         pr->scr_ctl = 0;
-        ahci_reset_port(&d->ahci, i);
+        ahci_reset_port(s, i);
     }
 }
 
@@ -1178,6 +1177,13 @@ static const VMStateDescription vmstate_sysbus_ahci = {
     .unmigratable = 1,
 };
 
+static void sysbus_ahci_reset(DeviceState *dev)
+{
+    SysbusAHCIState *s = DO_UPCAST(SysbusAHCIState, busdev.qdev, dev);
+
+    ahci_reset(&s->ahci);
+}
+
 static int sysbus_ahci_init(SysBusDevice *dev)
 {
     SysbusAHCIState *s = FROM_SYSBUS(SysbusAHCIState, dev);
@@ -1185,8 +1191,6 @@ static int sysbus_ahci_init(SysBusDevice *dev)
 
     sysbus_init_mmio(dev, &s->ahci.mem);
     sysbus_init_irq(dev, &s->ahci.irq);
-
-    qemu_register_reset(ahci_reset, &s->ahci);
     return 0;
 }
 
@@ -1203,6 +1207,7 @@ static void sysbus_ahci_class_init(ObjectClass *klass, void *data)
     sbc->init = sysbus_ahci_init;
     dc->vmsd = &vmstate_sysbus_ahci;
     dc->props = sysbus_ahci_properties;
+    dc->reset = sysbus_ahci_reset;
 }
 
 static TypeInfo sysbus_ahci_info = {
diff --git a/hw/ide/ahci.h b/hw/ide/ahci.h
index b223d2c055..ec1b6a5f66 100644
--- a/hw/ide/ahci.h
+++ b/hw/ide/ahci.h
@@ -332,6 +332,6 @@ typedef struct NCQFrame {
 void ahci_init(AHCIState *s, DeviceState *qdev, int ports);
 void ahci_uninit(AHCIState *s);
 
-void ahci_reset(void *opaque);
+void ahci_reset(AHCIState *s);
 
 #endif /* HW_IDE_AHCI_H */
diff --git a/hw/ide/ich.c b/hw/ide/ich.c
index 242254e8d8..e7026bb414 100644
--- a/hw/ide/ich.c
+++ b/hw/ide/ich.c
@@ -84,12 +84,12 @@ static const VMStateDescription vmstate_ahci = {
     .unmigratable = 1,
 };
 
-static void pci_ich9_reset(void *opaque)
+static void pci_ich9_reset(DeviceState *dev)
 {
-    struct AHCIPCIState *d = opaque;
+    struct AHCIPCIState *d = DO_UPCAST(struct AHCIPCIState, card.qdev, dev);
 
     msi_reset(&d->card);
-    ahci_reset(opaque);
+    ahci_reset(&d->ahci);
 }
 
 static int pci_ich9_ahci_init(PCIDevice *dev)
@@ -110,8 +110,6 @@ static int pci_ich9_ahci_init(PCIDevice *dev)
     /* XXX Software should program this register */
     d->card.config[0x90]   = 1 << 6; /* Address Map Register - AHCI mode */
 
-    qemu_register_reset(pci_ich9_reset, d);
-
     msi_init(dev, 0x50, 1, true, false);
     d->ahci.irq = d->card.irq[0];
 
@@ -141,7 +139,6 @@ static int pci_ich9_uninit(PCIDevice *dev)
     d = DO_UPCAST(struct AHCIPCIState, card, dev);
 
     msi_uninit(dev);
-    qemu_unregister_reset(pci_ich9_reset, d);
     ahci_uninit(&d->ahci);
 
     return 0;
@@ -167,6 +164,7 @@ static void ich_ahci_class_init(ObjectClass *klass, void *data)
     k->revision = 0x02;
     k->class_id = PCI_CLASS_STORAGE_SATA;
     dc->vmsd = &vmstate_ahci;
+    dc->reset = pci_ich9_reset;
 }
 
 static TypeInfo ich_ahci_info = {

From 520064c8b15504fb75babce7be6b5800b54ec490 Mon Sep 17 00:00:00 2001
From: Jan Kiszka <jan.kiszka@siemens.com>
Date: Fri, 11 May 2012 11:42:37 -0300
Subject: [PATCH 06/12] msi: Guard msi_reset with msi_present

Signed-off-by: Jan Kiszka <jan.kiszka@siemens.com>
Signed-off-by: Michael S. Tsirkin <mst@redhat.com>
---
 hw/msi.c | 4 ++++
 1 file changed, 4 insertions(+)

diff --git a/hw/msi.c b/hw/msi.c
index 5d6ceb6df0..b2903fc93c 100644
--- a/hw/msi.c
+++ b/hw/msi.c
@@ -191,6 +191,10 @@ void msi_reset(PCIDevice *dev)
     uint16_t flags;
     bool msi64bit;
 
+    if (!msi_present(dev)) {
+        return;
+    }
+
     flags = pci_get_word(dev->config + msi_flags_off(dev));
     flags &= ~(PCI_MSI_FLAGS_QSIZE | PCI_MSI_FLAGS_ENABLE);
     msi64bit = flags & PCI_MSI_FLAGS_64BIT;

From cbd2d4342b3d42ab33baa99f5b7a23491b5692f2 Mon Sep 17 00:00:00 2001
From: Jan Kiszka <jan.kiszka@siemens.com>
Date: Tue, 15 May 2012 20:09:56 -0300
Subject: [PATCH 07/12] msi: Invoke msi/msix_reset from PCI core

There is no point in pushing this burden to the devices, they tend to
forget to call them (like intel-hda, ahci, xhci did). Instead, reset
functions are now called from pci_device_reset. They do nothing if
MSI/MSI-X is not in use.

CC: Alexander Graf <agraf@suse.de>
CC: Gerd Hoffmann <kraxel@redhat.com>
CC: Isaku Yamahata <yamahata@valinux.co.jp>
Signed-off-by: Jan Kiszka <jan.kiszka@siemens.com>
Signed-off-by: Michael S. Tsirkin <mst@redhat.com>
---
 hw/ide/ich.c            |  1 -
 hw/intel-hda.c          |  3 ---
 hw/ioh3420.c            |  2 +-
 hw/ivshmem.c            |  1 -
 hw/pci.c                |  5 +++++
 hw/pci_bridge.c         | 10 ++--------
 hw/pci_bridge_dev.c     |  4 +---
 hw/virtio-pci.c         |  1 -
 hw/xio3130_downstream.c |  2 +-
 hw/xio3130_upstream.c   |  2 +-
 10 files changed, 11 insertions(+), 20 deletions(-)

diff --git a/hw/ide/ich.c b/hw/ide/ich.c
index e7026bb414..d3bc822831 100644
--- a/hw/ide/ich.c
+++ b/hw/ide/ich.c
@@ -88,7 +88,6 @@ static void pci_ich9_reset(DeviceState *dev)
 {
     struct AHCIPCIState *d = DO_UPCAST(struct AHCIPCIState, card.qdev, dev);
 
-    msi_reset(&d->card);
     ahci_reset(&d->ahci);
 }
 
diff --git a/hw/intel-hda.c b/hw/intel-hda.c
index e38861e5de..bb11af286a 100644
--- a/hw/intel-hda.c
+++ b/hw/intel-hda.c
@@ -1107,9 +1107,6 @@ static void intel_hda_reset(DeviceState *dev)
     DeviceState *qdev;
     HDACodecDevice *cdev;
 
-    if (d->msi) {
-        msi_reset(&d->pci);
-    }
     intel_hda_regs_reset(d);
     d->wall_base_ns = qemu_get_clock_ns(vm_clock);
 
diff --git a/hw/ioh3420.c b/hw/ioh3420.c
index 1632d31c19..d1499da4ac 100644
--- a/hw/ioh3420.c
+++ b/hw/ioh3420.c
@@ -81,7 +81,7 @@ static void ioh3420_write_config(PCIDevice *d,
 static void ioh3420_reset(DeviceState *qdev)
 {
     PCIDevice *d = PCI_DEVICE(qdev);
-    msi_reset(d);
+
     ioh3420_aer_vector_update(d);
     pcie_cap_root_reset(d);
     pcie_cap_deverr_reset(d);
diff --git a/hw/ivshmem.c b/hw/ivshmem.c
index d48e5f9906..05559b639c 100644
--- a/hw/ivshmem.c
+++ b/hw/ivshmem.c
@@ -530,7 +530,6 @@ static void ivshmem_reset(DeviceState *d)
     IVShmemState *s = DO_UPCAST(IVShmemState, dev.qdev, d);
 
     s->intrstatus = 0;
-    msix_reset(&s->dev);
     ivshmem_use_msix(s);
     return;
 }
diff --git a/hw/pci.c b/hw/pci.c
index c1ebdde91e..2b429c03d1 100644
--- a/hw/pci.c
+++ b/hw/pci.c
@@ -31,6 +31,8 @@
 #include "loader.h"
 #include "range.h"
 #include "qmp-commands.h"
+#include "msi.h"
+#include "msix.h"
 
 //#define DEBUG_PCI
 #ifdef DEBUG_PCI
@@ -188,6 +190,9 @@ void pci_device_reset(PCIDevice *dev)
         }
     }
     pci_update_mappings(dev);
+
+    msi_reset(dev);
+    msix_reset(dev);
 }
 
 /*
diff --git a/hw/pci_bridge.c b/hw/pci_bridge.c
index 866f0b6c52..e0832b4a67 100644
--- a/hw/pci_bridge.c
+++ b/hw/pci_bridge.c
@@ -254,8 +254,9 @@ void pci_bridge_disable_base_limit(PCIDevice *dev)
 }
 
 /* reset bridge specific configuration registers */
-void pci_bridge_reset_reg(PCIDevice *dev)
+void pci_bridge_reset(DeviceState *qdev)
 {
+    PCIDevice *dev = PCI_DEVICE(qdev);
     uint8_t *conf = dev->config;
 
     conf[PCI_PRIMARY_BUS] = 0;
@@ -291,13 +292,6 @@ void pci_bridge_reset_reg(PCIDevice *dev)
     pci_set_word(conf + PCI_BRIDGE_CONTROL, 0);
 }
 
-/* default reset function for PCI-to-PCI bridge */
-void pci_bridge_reset(DeviceState *qdev)
-{
-    PCIDevice *dev = PCI_DEVICE(qdev);
-    pci_bridge_reset_reg(dev);
-}
-
 /* default qdev initialization function for PCI-to-PCI bridge */
 int pci_bridge_initfn(PCIDevice *dev)
 {
diff --git a/hw/pci_bridge_dev.c b/hw/pci_bridge_dev.c
index eccaa5831e..b6d5fb7388 100644
--- a/hw/pci_bridge_dev.c
+++ b/hw/pci_bridge_dev.c
@@ -119,10 +119,8 @@ static void pci_bridge_dev_write_config(PCIDevice *d,
 static void qdev_pci_bridge_dev_reset(DeviceState *qdev)
 {
     PCIDevice *dev = DO_UPCAST(PCIDevice, qdev, qdev);
+
     pci_bridge_reset(qdev);
-    if (msi_present(dev)) {
-        msi_reset(dev);
-    }
     shpc_reset(dev);
 }
 
diff --git a/hw/virtio-pci.c b/hw/virtio-pci.c
index d08c1590d2..4736ba3898 100644
--- a/hw/virtio-pci.c
+++ b/hw/virtio-pci.c
@@ -278,7 +278,6 @@ void virtio_pci_reset(DeviceState *d)
     VirtIOPCIProxy *proxy = container_of(d, VirtIOPCIProxy, pci_dev.qdev);
     virtio_pci_stop_ioeventfd(proxy);
     virtio_reset(proxy->vdev);
-    msix_reset(&proxy->pci_dev);
     proxy->flags &= ~VIRTIO_PCI_FLAG_BUS_MASTER_BUG;
 }
 
diff --git a/hw/xio3130_downstream.c b/hw/xio3130_downstream.c
index 319624f212..3716e4541a 100644
--- a/hw/xio3130_downstream.c
+++ b/hw/xio3130_downstream.c
@@ -48,7 +48,7 @@ static void xio3130_downstream_write_config(PCIDevice *d, uint32_t address,
 static void xio3130_downstream_reset(DeviceState *qdev)
 {
     PCIDevice *d = PCI_DEVICE(qdev);
-    msi_reset(d);
+
     pcie_cap_deverr_reset(d);
     pcie_cap_slot_reset(d);
     pcie_cap_ari_reset(d);
diff --git a/hw/xio3130_upstream.c b/hw/xio3130_upstream.c
index 34a99bba08..962d48e63e 100644
--- a/hw/xio3130_upstream.c
+++ b/hw/xio3130_upstream.c
@@ -47,7 +47,7 @@ static void xio3130_upstream_write_config(PCIDevice *d, uint32_t address,
 static void xio3130_upstream_reset(DeviceState *qdev)
 {
     PCIDevice *d = PCI_DEVICE(qdev);
-    msi_reset(d);
+
     pci_bridge_reset(qdev);
     pcie_cap_deverr_reset(d);
 }

From 7c9958b04333a79a1fdb11583aca48a6df2edeb9 Mon Sep 17 00:00:00 2001
From: Jan Kiszka <jan.kiszka@siemens.com>
Date: Fri, 11 May 2012 11:42:39 -0300
Subject: [PATCH 08/12] msi: Guard msi/msix_write_config with msi_present

Terminate msi/msix_write_config early if support is not enabled. This
allows to remove checks at the caller site if MSI is optional.

Signed-off-by: Jan Kiszka <jan.kiszka@siemens.com>
Signed-off-by: Michael S. Tsirkin <mst@redhat.com>
---
 hw/msi.c  | 3 ++-
 hw/msix.c | 2 +-
 2 files changed, 3 insertions(+), 2 deletions(-)

diff --git a/hw/msi.c b/hw/msi.c
index b2903fc93c..da12f33728 100644
--- a/hw/msi.c
+++ b/hw/msi.c
@@ -276,7 +276,8 @@ void msi_write_config(PCIDevice *dev, uint32_t addr, uint32_t val, int len)
     unsigned int vector;
     uint32_t pending;
 
-    if (!ranges_overlap(addr, len, dev->msi_cap, msi_cap_sizeof(flags))) {
+    if (!msi_present(dev) ||
+        !ranges_overlap(addr, len, dev->msi_cap, msi_cap_sizeof(flags))) {
         return;
     }
 
diff --git a/hw/msix.c b/hw/msix.c
index 59c7a8388f..339e652b81 100644
--- a/hw/msix.c
+++ b/hw/msix.c
@@ -187,7 +187,7 @@ void msix_write_config(PCIDevice *dev, uint32_t addr,
     int vector;
     bool was_masked;
 
-    if (!range_covers_byte(addr, len, enable_pos)) {
+    if (!msix_present(dev) || !range_covers_byte(addr, len, enable_pos)) {
         return;
     }
 

From 95d658002401e2e47a5404298ebe9508846e8a39 Mon Sep 17 00:00:00 2001
From: Jan Kiszka <jan.kiszka@siemens.com>
Date: Fri, 11 May 2012 11:42:40 -0300
Subject: [PATCH 09/12] msi: Invoke msi/msix_write_config from PCI core

Also this functions is better invoked by the core than by each and every
device. This allows to drop the config_write callbacks from ich and
intel-hda.

CC: Alexander Graf <agraf@suse.de>
CC: Gerd Hoffmann <kraxel@redhat.com>
CC: Isaku Yamahata <yamahata@valinux.co.jp>
Signed-off-by: Jan Kiszka <jan.kiszka@siemens.com>
Signed-off-by: Michael S. Tsirkin <mst@redhat.com>
---
 hw/ide/ich.c            |  8 --------
 hw/intel-hda.c          | 12 ------------
 hw/ioh3420.c            |  1 -
 hw/msi.c                |  2 +-
 hw/pci.c                |  3 +++
 hw/virtio-pci.c         |  2 --
 hw/xio3130_downstream.c |  1 -
 hw/xio3130_upstream.c   |  1 -
 8 files changed, 4 insertions(+), 26 deletions(-)

diff --git a/hw/ide/ich.c b/hw/ide/ich.c
index d3bc822831..e3eaaea882 100644
--- a/hw/ide/ich.c
+++ b/hw/ide/ich.c
@@ -143,13 +143,6 @@ static int pci_ich9_uninit(PCIDevice *dev)
     return 0;
 }
 
-static void pci_ich9_write_config(PCIDevice *pci, uint32_t addr,
-                                  uint32_t val, int len)
-{
-    pci_default_write_config(pci, addr, val, len);
-    msi_write_config(pci, addr, val, len);
-}
-
 static void ich_ahci_class_init(ObjectClass *klass, void *data)
 {
     DeviceClass *dc = DEVICE_CLASS(klass);
@@ -157,7 +150,6 @@ static void ich_ahci_class_init(ObjectClass *klass, void *data)
 
     k->init = pci_ich9_ahci_init;
     k->exit = pci_ich9_uninit;
-    k->config_write = pci_ich9_write_config;
     k->vendor_id = PCI_VENDOR_ID_INTEL;
     k->device_id = PCI_DEVICE_ID_INTEL_82801IR;
     k->revision = 0x02;
diff --git a/hw/intel-hda.c b/hw/intel-hda.c
index bb11af286a..8f3b70bd14 100644
--- a/hw/intel-hda.c
+++ b/hw/intel-hda.c
@@ -1153,17 +1153,6 @@ static int intel_hda_exit(PCIDevice *pci)
     return 0;
 }
 
-static void intel_hda_write_config(PCIDevice *pci, uint32_t addr,
-                                   uint32_t val, int len)
-{
-    IntelHDAState *d = DO_UPCAST(IntelHDAState, pci, pci);
-
-    pci_default_write_config(pci, addr, val, len);
-    if (d->msi) {
-        msi_write_config(pci, addr, val, len);
-    }
-}
-
 static int intel_hda_post_load(void *opaque, int version)
 {
     IntelHDAState* d = opaque;
@@ -1252,7 +1241,6 @@ static void intel_hda_class_init(ObjectClass *klass, void *data)
 
     k->init = intel_hda_init;
     k->exit = intel_hda_exit;
-    k->config_write = intel_hda_write_config;
     k->vendor_id = PCI_VENDOR_ID_INTEL;
     k->device_id = 0x2668;
     k->revision = 1;
diff --git a/hw/ioh3420.c b/hw/ioh3420.c
index d1499da4ac..0a2601cac4 100644
--- a/hw/ioh3420.c
+++ b/hw/ioh3420.c
@@ -71,7 +71,6 @@ static void ioh3420_write_config(PCIDevice *d,
         pci_get_long(d->config + d->exp.aer_cap + PCI_ERR_ROOT_COMMAND);
 
     pci_bridge_write_config(d, address, val, len);
-    msi_write_config(d, address, val, len);
     ioh3420_aer_vector_update(d);
     pcie_cap_slot_write_config(d, address, val, len);
     pcie_aer_write_config(d, address, val, len);
diff --git a/hw/msi.c b/hw/msi.c
index da12f33728..556c7c4ae8 100644
--- a/hw/msi.c
+++ b/hw/msi.c
@@ -264,7 +264,7 @@ void msi_notify(PCIDevice *dev, unsigned int vector)
     stl_le_phys(address, data);
 }
 
-/* call this function after updating configs by pci_default_write_config(). */
+/* Normally called by pci_default_write_config(). */
 void msi_write_config(PCIDevice *dev, uint32_t addr, uint32_t val, int len)
 {
     uint16_t flags = pci_get_word(dev->config + msi_flags_off(dev));
diff --git a/hw/pci.c b/hw/pci.c
index 2b429c03d1..d5c664c9cd 100644
--- a/hw/pci.c
+++ b/hw/pci.c
@@ -1042,6 +1042,9 @@ void pci_default_write_config(PCIDevice *d, uint32_t addr, uint32_t val, int l)
 
     if (range_covers_byte(addr, l, PCI_COMMAND))
         pci_update_irq_disabled(d, was_irq_disabled);
+
+    msi_write_config(d, addr, val, l);
+    msix_write_config(d, addr, val, l);
 }
 
 /***********************************************************/
diff --git a/hw/virtio-pci.c b/hw/virtio-pci.c
index 4736ba3898..9342eed070 100644
--- a/hw/virtio-pci.c
+++ b/hw/virtio-pci.c
@@ -520,8 +520,6 @@ static void virtio_write_config(PCIDevice *pci_dev, uint32_t address,
         virtio_set_status(proxy->vdev,
                           proxy->vdev->status & ~VIRTIO_CONFIG_S_DRIVER_OK);
     }
-
-    msix_write_config(pci_dev, address, val, len);
 }
 
 static unsigned virtio_pci_get_features(void *opaque)
diff --git a/hw/xio3130_downstream.c b/hw/xio3130_downstream.c
index 3716e4541a..56d1b353d0 100644
--- a/hw/xio3130_downstream.c
+++ b/hw/xio3130_downstream.c
@@ -41,7 +41,6 @@ static void xio3130_downstream_write_config(PCIDevice *d, uint32_t address,
     pci_bridge_write_config(d, address, val, len);
     pcie_cap_flr_write_config(d, address, val, len);
     pcie_cap_slot_write_config(d, address, val, len);
-    msi_write_config(d, address, val, len);
     pcie_aer_write_config(d, address, val, len);
 }
 
diff --git a/hw/xio3130_upstream.c b/hw/xio3130_upstream.c
index 962d48e63e..79725813a2 100644
--- a/hw/xio3130_upstream.c
+++ b/hw/xio3130_upstream.c
@@ -40,7 +40,6 @@ static void xio3130_upstream_write_config(PCIDevice *d, uint32_t address,
 {
     pci_bridge_write_config(d, address, val, len);
     pcie_cap_flr_write_config(d, address, val, len);
-    msi_write_config(d, address, val, len);
     pcie_aer_write_config(d, address, val, len);
 }
 

From 44701ab71ad854e6be567a6294f4665f36651076 Mon Sep 17 00:00:00 2001
From: Jan Kiszka <jan.kiszka@siemens.com>
Date: Mon, 4 Jun 2012 16:53:48 +0200
Subject: [PATCH 10/12] msi: Use msi/msix_present more consistently

Replace some open-coded msi/msix_present checks.

Signed-off-by: Jan Kiszka <jan.kiszka@siemens.com>
Signed-off-by: Michael S. Tsirkin <mst@redhat.com>
---
 hw/msi.c  |  2 +-
 hw/msix.c | 13 ++++++++-----
 2 files changed, 9 insertions(+), 6 deletions(-)

diff --git a/hw/msi.c b/hw/msi.c
index 556c7c4ae8..52332041e7 100644
--- a/hw/msi.c
+++ b/hw/msi.c
@@ -175,7 +175,7 @@ void msi_uninit(struct PCIDevice *dev)
     uint16_t flags;
     uint8_t cap_size;
 
-    if (!(dev->cap_present & QEMU_PCI_CAP_MSI)) {
+    if (!msi_present(dev)) {
         return;
     }
     flags = pci_get_word(dev->config + msi_flags_off(dev));
diff --git a/hw/msix.c b/hw/msix.c
index 339e652b81..ded3c55b92 100644
--- a/hw/msix.c
+++ b/hw/msix.c
@@ -319,8 +319,9 @@ static void msix_free_irq_entries(PCIDevice *dev)
 /* Clean up resources for the device. */
 int msix_uninit(PCIDevice *dev, MemoryRegion *bar)
 {
-    if (!(dev->cap_present & QEMU_PCI_CAP_MSIX))
+    if (!msix_present(dev)) {
         return 0;
+    }
     pci_del_capability(dev, PCI_CAP_ID_MSIX, MSIX_CAP_LENGTH);
     dev->msix_cap = 0;
     msix_free_irq_entries(dev);
@@ -339,7 +340,7 @@ void msix_save(PCIDevice *dev, QEMUFile *f)
 {
     unsigned n = dev->msix_entries_nr;
 
-    if (!(dev->cap_present & QEMU_PCI_CAP_MSIX)) {
+    if (!msix_present(dev)) {
         return;
     }
 
@@ -353,7 +354,7 @@ void msix_load(PCIDevice *dev, QEMUFile *f)
     unsigned n = dev->msix_entries_nr;
     unsigned int vector;
 
-    if (!(dev->cap_present & QEMU_PCI_CAP_MSIX)) {
+    if (!msix_present(dev)) {
         return;
     }
 
@@ -407,8 +408,9 @@ void msix_notify(PCIDevice *dev, unsigned vector)
 
 void msix_reset(PCIDevice *dev)
 {
-    if (!(dev->cap_present & QEMU_PCI_CAP_MSIX))
+    if (!msix_present(dev)) {
         return;
+    }
     msix_free_irq_entries(dev);
     dev->config[dev->msix_cap + MSIX_CONTROL_OFFSET] &=
 	    ~dev->wmask[dev->msix_cap + MSIX_CONTROL_OFFSET];
@@ -447,8 +449,9 @@ void msix_vector_unuse(PCIDevice *dev, unsigned vector)
 
 void msix_unuse_all_vectors(PCIDevice *dev)
 {
-    if (!(dev->cap_present & QEMU_PCI_CAP_MSIX))
+    if (!msix_present(dev)) {
         return;
+    }
     msix_free_irq_entries(dev);
 }
 

From 266ca11a0433643a3cc3146a9837d9f2b0bfbe3b Mon Sep 17 00:00:00 2001
From: Jason Baron <jbaron@redhat.com>
Date: Wed, 2 May 2012 22:42:10 -0400
Subject: [PATCH 11/12] qdev: release parent properties on dc->init failure

While looking into hot-plugging bridges, I can create a qemu segfault via:

$ device_add pci-bridge

Bridge chassis not specified. Each bridge is required to be assigned a unique chassis id > 0.
**
ERROR:qom/object.c:389:object_delete: assertion failed: (obj->ref == 0)

I'm proposing to fix this by adding a call to 'object_unparent()', before the
call to qdev_free(). I see there is already a precedent for this usage pattern as
seen in qdev_simple_unplug_cb():

/* can be used as ->unplug() callback for the simple cases */
int qdev_simple_unplug_cb(DeviceState *dev)
{
    /* just zap it */
    object_unparent(OBJECT(dev));
    qdev_free(dev);
    return 0;
}

Signed-off-by: Jason Baron <jbaron@redhat.com>
Signed-off-by: Michael S. Tsirkin <mst@redhat.com>
---
 hw/qdev.c | 1 +
 1 file changed, 1 insertion(+)

diff --git a/hw/qdev.c b/hw/qdev.c
index 6a8f6bda2b..af419b9c13 100644
--- a/hw/qdev.c
+++ b/hw/qdev.c
@@ -150,6 +150,7 @@ int qdev_init(DeviceState *dev)
 
     rc = dc->init(dev);
     if (rc < 0) {
+        object_unparent(OBJECT(dev));
         qdev_free(dev);
         return rc;
     }

From 80aa796bf38b7ef21daa42673b4711510c450d8a Mon Sep 17 00:00:00 2001
From: Jason Baron <jbaron@redhat.com>
Date: Wed, 2 May 2012 22:42:15 -0400
Subject: [PATCH 12/12] pci_bridge_dev: fix error path in
 pci_bridge_dev_initfn()

Currently, we do not properly cleanup, if pci_bridge_dev_initfn
fails to initialize properly. Make sure to call pci_bridge_exitfn()
in the error path.

Signed-off-by: Jason Baron <jbaron@redhat.com>
Signed-off-by: Michael S. Tsirkin <mst@redhat.com>
---
 hw/pci_bridge_dev.c | 4 +++-
 1 file changed, 3 insertions(+), 1 deletion(-)

diff --git a/hw/pci_bridge_dev.c b/hw/pci_bridge_dev.c
index b6d5fb7388..1cc1d2049c 100644
--- a/hw/pci_bridge_dev.c
+++ b/hw/pci_bridge_dev.c
@@ -52,7 +52,7 @@ static int pci_bridge_dev_initfn(PCIDevice *dev)
 {
     PCIBridge *br = DO_UPCAST(PCIBridge, dev, dev);
     PCIBridgeDev *bridge_dev = DO_UPCAST(PCIBridgeDev, bridge, br);
-    int err;
+    int err, ret;
     pci_bridge_map_irq(br, NULL, pci_bridge_dev_map_irq_fn);
     err = pci_bridge_initfn(dev);
     if (err) {
@@ -86,6 +86,8 @@ slotid_error:
     shpc_cleanup(dev, &bridge_dev->bar);
 shpc_error:
     memory_region_destroy(&bridge_dev->bar);
+    ret = pci_bridge_exitfn(dev);
+    assert(!ret);
 bridge_error:
     return err;
 }