summary refs log tree commit diff stats
diff options
context:
space:
mode:
-rw-r--r--QMP/qmp-events.txt18
-rw-r--r--exec.c2
-rw-r--r--hw/alpha_typhoon.c2
-rw-r--r--hw/apb_pci.c4
-rw-r--r--hw/bonito.c2
-rw-r--r--hw/dec_pci.c7
-rw-r--r--hw/grackle_pci.c2
-rw-r--r--hw/gt64xxx.c2
-rw-r--r--hw/i82801b11.c2
-rw-r--r--hw/ioh3420.c2
-rw-r--r--hw/pci/pci.c121
-rw-r--r--hw/pci/pci.h34
-rw-r--r--hw/pci/pci_bridge.c51
-rw-r--r--hw/pci/pci_bridge.h17
-rw-r--r--hw/pci/pci_bus.h10
-rw-r--r--hw/pci/pcie.c16
-rw-r--r--hw/pci/pcie.h1
-rw-r--r--hw/pci/pcie_port.c18
-rw-r--r--hw/pci_bridge_dev.c11
-rw-r--r--hw/piix_pci.c2
-rw-r--r--hw/ppc4xx_pci.c2
-rw-r--r--hw/ppce500_pci.c2
-rw-r--r--hw/prep_pci.c2
-rw-r--r--hw/q35.c3
-rw-r--r--hw/qdev.c14
-rw-r--r--hw/sh_pci.c2
-rw-r--r--hw/spapr_pci.c2
-rw-r--r--hw/unin_pci.c4
-rw-r--r--hw/usb/hcd-xhci.c2
-rw-r--r--hw/versatile_pci.c2
-rw-r--r--hw/virtio-net.c23
-rw-r--r--hw/virtio-pci.c79
-rw-r--r--hw/xio3130_downstream.c2
-rw-r--r--hw/xio3130_upstream.c2
-rw-r--r--include/monitor/monitor.h1
-rw-r--r--monitor.c1
-rw-r--r--qapi-schema.json4
-rw-r--r--qom/object.c6
-rwxr-xr-xroms/configure-seabios.sh2
39 files changed, 348 insertions, 131 deletions
diff --git a/QMP/qmp-events.txt b/QMP/qmp-events.txt
index b2698e4153..dcc826d9f4 100644
--- a/QMP/qmp-events.txt
+++ b/QMP/qmp-events.txt
@@ -136,6 +136,24 @@ Example:
 Note: The "ready to complete" status is always reset by a BLOCK_JOB_ERROR
 event.
 
+DEVICE_DELETED
+-----------------
+
+Emitted whenever the device removal completion is acknowledged
+by the guest.
+At this point, it's safe to reuse the specified device ID.
+Device removal can be initiated by the guest or by HMP/QMP commands.
+
+Data:
+
+- "device": device name (json-string, optional)
+- "path": device path (json-string)
+
+{ "event": "DEVICE_DELETED",
+  "data": { "device": "virtio-net-pci-0",
+            "path": "/machine/peripheral/virtio-net-pci-0" },
+  "timestamp": { "seconds": 1265044230, "microseconds": 450486 } }
+
 DEVICE_TRAY_MOVED
 -----------------
 
diff --git a/exec.c b/exec.c
index 8a6aac36e3..786987a016 100644
--- a/exec.c
+++ b/exec.c
@@ -925,6 +925,8 @@ static ram_addr_t find_ram_offset(ram_addr_t size)
     RAMBlock *block, *next_block;
     ram_addr_t offset = RAM_ADDR_MAX, mingap = RAM_ADDR_MAX;
 
+    assert(size != 0); /* it would hand out same offset multiple times */
+
     if (QTAILQ_EMPTY(&ram_list.blocks))
         return 0;
 
diff --git a/hw/alpha_typhoon.c b/hw/alpha_typhoon.c
index 770dc8cf0d..b1e0044a35 100644
--- a/hw/alpha_typhoon.c
+++ b/hw/alpha_typhoon.c
@@ -775,7 +775,7 @@ PCIBus *typhoon_init(ram_addr_t ram_size, ISABus **isa_bus,
 
     b = pci_register_bus(dev, "pci",
                          typhoon_set_irq, sys_map_irq, s,
-                         &s->pchip.reg_mem, addr_space_io, 0, 64);
+                         &s->pchip.reg_mem, addr_space_io, 0, 64, TYPE_PCI_BUS);
     phb->bus = b;
 
     /* Pchip0 PCI special/interrupt acknowledge, 0x801.F800.0000, 64MB.  */
diff --git a/hw/apb_pci.c b/hw/apb_pci.c
index 7992d6f6fd..754ca6ca8f 100644
--- a/hw/apb_pci.c
+++ b/hw/apb_pci.c
@@ -329,7 +329,7 @@ static int apb_pci_bridge_initfn(PCIDevice *dev)
 {
     int rc;
 
-    rc = pci_bridge_initfn(dev);
+    rc = pci_bridge_initfn(dev, TYPE_PCI_BUS);
     if (rc < 0) {
         return rc;
     }
@@ -381,7 +381,7 @@ PCIBus *pci_apb_init(hwaddr special_base,
                               pci_apb_set_irq, pci_pbm_map_irq, d,
                               &d->pci_mmio,
                               get_system_io(),
-                              0, 32);
+                              0, 32, TYPE_PCI_BUS);
 
     *pbm_irqs = d->pbm_irqs;
     d->ivec_irqs = ivec_irqs;
diff --git a/hw/bonito.c b/hw/bonito.c
index 3456e7840e..e58655a64d 100644
--- a/hw/bonito.c
+++ b/hw/bonito.c
@@ -707,7 +707,7 @@ static int bonito_pcihost_initfn(SysBusDevice *dev)
     phb->bus = pci_register_bus(DEVICE(dev), "pci",
                                 pci_bonito_set_irq, pci_bonito_map_irq, dev,
                                 get_system_memory(), get_system_io(),
-                                0x28, 32);
+                                0x28, 32, TYPE_PCI_BUS);
 
     return 0;
 }
diff --git a/hw/dec_pci.c b/hw/dec_pci.c
index 64a50924f6..6ec3d226bd 100644
--- a/hw/dec_pci.c
+++ b/hw/dec_pci.c
@@ -51,12 +51,17 @@ static int dec_map_irq(PCIDevice *pci_dev, int irq_num)
     return irq_num;
 }
 
+static int dec_pci_bridge_initfn(PCIDevice *pci_dev)
+{
+    return pci_bridge_initfn(pci_dev, TYPE_PCI_BUS);
+}
+
 static void dec_21154_pci_bridge_class_init(ObjectClass *klass, void *data)
 {
     DeviceClass *dc = DEVICE_CLASS(klass);
     PCIDeviceClass *k = PCI_DEVICE_CLASS(klass);
 
-    k->init = pci_bridge_initfn;
+    k->init = dec_pci_bridge_initfn;
     k->exit = pci_bridge_exitfn;
     k->vendor_id = PCI_VENDOR_ID_DEC;
     k->device_id = PCI_DEVICE_ID_DEC_21154;
diff --git a/hw/grackle_pci.c b/hw/grackle_pci.c
index 11e47d560e..69344d9f6a 100644
--- a/hw/grackle_pci.c
+++ b/hw/grackle_pci.c
@@ -88,7 +88,7 @@ PCIBus *pci_grackle_init(uint32_t base, qemu_irq *pic,
                                 pic,
                                 &d->pci_mmio,
                                 address_space_io,
-                                0, 4);
+                                0, 4, TYPE_PCI_BUS);
 
     pci_create_simple(phb->bus, 0, "grackle");
 
diff --git a/hw/gt64xxx.c b/hw/gt64xxx.c
index c73a58a045..37be9c2a56 100644
--- a/hw/gt64xxx.c
+++ b/hw/gt64xxx.c
@@ -1107,7 +1107,7 @@ PCIBus *gt64120_register(qemu_irq *pic)
                                 pic,
                                 get_system_memory(),
                                 get_system_io(),
-                                PCI_DEVFN(18, 0), 4);
+                                PCI_DEVFN(18, 0), 4, TYPE_PCI_BUS);
     memory_region_init_io(&d->ISD_mem, &isd_mem_ops, d, "isd-mem", 0x1000);
 
     pci_create_simple(phb->bus, PCI_DEVFN(0, 0), "gt64120_pci");
diff --git a/hw/i82801b11.c b/hw/i82801b11.c
index 992095c80f..8b4a9c6e54 100644
--- a/hw/i82801b11.c
+++ b/hw/i82801b11.c
@@ -59,7 +59,7 @@ static int i82801b11_bridge_initfn(PCIDevice *d)
 {
     int rc;
 
-    rc = pci_bridge_initfn(d);
+    rc = pci_bridge_initfn(d, TYPE_PCI_BUS);
     if (rc < 0) {
         return rc;
     }
diff --git a/hw/ioh3420.c b/hw/ioh3420.c
index 43f855427b..5cff61e095 100644
--- a/hw/ioh3420.c
+++ b/hw/ioh3420.c
@@ -97,7 +97,7 @@ static int ioh3420_initfn(PCIDevice *d)
     PCIESlot *s = DO_UPCAST(PCIESlot, port, p);
     int rc;
 
-    rc = pci_bridge_initfn(d);
+    rc = pci_bridge_initfn(d, TYPE_PCIE_BUS);
     if (rc < 0) {
         return rc;
     }
diff --git a/hw/pci/pci.c b/hw/pci/pci.c
index 2f45c8f02f..d5257ed4c5 100644
--- a/hw/pci/pci.c
+++ b/hw/pci/pci.c
@@ -75,6 +75,11 @@ static const TypeInfo pci_bus_info = {
     .class_init = pci_bus_class_init,
 };
 
+static const TypeInfo pcie_bus_info = {
+    .name = TYPE_PCIE_BUS,
+    .parent = TYPE_PCI_BUS,
+};
+
 static PCIBus *pci_find_bus_nr(PCIBus *bus, int bus_num);
 static void pci_update_mappings(PCIDevice *d);
 static void pci_set_irq(void *opaque, int irq_num, int level);
@@ -292,13 +297,23 @@ static void pci_bus_init(PCIBus *bus, DeviceState *parent,
     vmstate_register(NULL, -1, &vmstate_pcibus, bus);
 }
 
+bool pci_bus_is_express(PCIBus *bus)
+{
+    return object_dynamic_cast(OBJECT(bus), TYPE_PCIE_BUS);
+}
+
+bool pci_bus_is_root(PCIBus *bus)
+{
+    return !bus->parent_dev;
+}
+
 void pci_bus_new_inplace(PCIBus *bus, DeviceState *parent,
                          const char *name,
                          MemoryRegion *address_space_mem,
                          MemoryRegion *address_space_io,
-                         uint8_t devfn_min)
+                         uint8_t devfn_min, const char *typename)
 {
-    qbus_create_inplace(bus, TYPE_PCI_BUS, parent, name);
+    qbus_create_inplace(bus, typename, parent, name);
     pci_bus_init(bus, parent, name, address_space_mem,
                  address_space_io, devfn_min);
 }
@@ -306,11 +321,11 @@ void pci_bus_new_inplace(PCIBus *bus, DeviceState *parent,
 PCIBus *pci_bus_new(DeviceState *parent, const char *name,
                     MemoryRegion *address_space_mem,
                     MemoryRegion *address_space_io,
-                    uint8_t devfn_min)
+                    uint8_t devfn_min, const char *typename)
 {
     PCIBus *bus;
 
-    bus = PCI_BUS(qbus_create(TYPE_PCI_BUS, parent, name));
+    bus = PCI_BUS(qbus_create(typename, parent, name));
     pci_bus_init(bus, parent, name, address_space_mem,
                  address_space_io, devfn_min);
     return bus;
@@ -338,19 +353,19 @@ PCIBus *pci_register_bus(DeviceState *parent, const char *name,
                          void *irq_opaque,
                          MemoryRegion *address_space_mem,
                          MemoryRegion *address_space_io,
-                         uint8_t devfn_min, int nirq)
+                         uint8_t devfn_min, int nirq, const char *typename)
 {
     PCIBus *bus;
 
     bus = pci_bus_new(parent, name, address_space_mem,
-                      address_space_io, devfn_min);
+                      address_space_io, devfn_min, typename);
     pci_bus_irqs(bus, set_irq, map_irq, irq_opaque, nirq);
     return bus;
 }
 
 int pci_bus_num(PCIBus *s)
 {
-    if (!s->parent_dev)
+    if (pci_bus_is_root(s))
         return 0;       /* pci host bridge */
     return s->parent_dev->config[PCI_SECONDARY_BUS];
 }
@@ -668,12 +683,10 @@ static void pci_init_mask_bridge(PCIDevice *d)
     pci_word_test_and_set_mask(d->config + PCI_PREF_MEMORY_LIMIT,
                                PCI_PREF_RANGE_TYPE_64);
 
-/* TODO: add this define to pci_regs.h in linux and then in qemu. */
-#define  PCI_BRIDGE_CTL_VGA_16BIT	0x10	/* VGA 16-bit decode */
-#define  PCI_BRIDGE_CTL_DISCARD		0x100	/* Primary discard timer */
-#define  PCI_BRIDGE_CTL_SEC_DISCARD	0x200	/* Secondary discard timer */
-#define  PCI_BRIDGE_CTL_DISCARD_STATUS	0x400	/* Discard timer status */
-#define  PCI_BRIDGE_CTL_DISCARD_SERR	0x800	/* Discard timer SERR# enable */
+    /*
+     * TODO: Bridges default to 10-bit VGA decoding but we currently only
+     * implement 16-bit decoding (no alias support).
+     */
     pci_set_word(d->wmask + PCI_BRIDGE_CONTROL,
                  PCI_BRIDGE_CTL_PARITY |
                  PCI_BRIDGE_CTL_SERR |
@@ -875,6 +888,8 @@ static void pci_unregister_io_regions(PCIDevice *pci_dev)
             continue;
         memory_region_del_subregion(r->address_space, r->memory);
     }
+
+    pci_unregister_vga(pci_dev);
 }
 
 static int pci_unregister_device(DeviceState *dev)
@@ -937,6 +952,63 @@ void pci_register_bar(PCIDevice *pci_dev, int region_num,
         : pci_dev->bus->address_space_mem;
 }
 
+static void pci_update_vga(PCIDevice *pci_dev)
+{
+    uint16_t cmd;
+
+    if (!pci_dev->has_vga) {
+        return;
+    }
+
+    cmd = pci_get_word(pci_dev->config + PCI_COMMAND);
+
+    memory_region_set_enabled(pci_dev->vga_regions[QEMU_PCI_VGA_MEM],
+                              cmd & PCI_COMMAND_MEMORY);
+    memory_region_set_enabled(pci_dev->vga_regions[QEMU_PCI_VGA_IO_LO],
+                              cmd & PCI_COMMAND_IO);
+    memory_region_set_enabled(pci_dev->vga_regions[QEMU_PCI_VGA_IO_HI],
+                              cmd & PCI_COMMAND_IO);
+}
+
+void pci_register_vga(PCIDevice *pci_dev, MemoryRegion *mem,
+                      MemoryRegion *io_lo, MemoryRegion *io_hi)
+{
+    assert(!pci_dev->has_vga);
+
+    assert(memory_region_size(mem) == QEMU_PCI_VGA_MEM_SIZE);
+    pci_dev->vga_regions[QEMU_PCI_VGA_MEM] = mem;
+    memory_region_add_subregion_overlap(pci_dev->bus->address_space_mem,
+                                        QEMU_PCI_VGA_MEM_BASE, mem, 1);
+
+    assert(memory_region_size(io_lo) == QEMU_PCI_VGA_IO_LO_SIZE);
+    pci_dev->vga_regions[QEMU_PCI_VGA_IO_LO] = io_lo;
+    memory_region_add_subregion_overlap(pci_dev->bus->address_space_io,
+                                        QEMU_PCI_VGA_IO_LO_BASE, io_lo, 1);
+
+    assert(memory_region_size(io_hi) == QEMU_PCI_VGA_IO_HI_SIZE);
+    pci_dev->vga_regions[QEMU_PCI_VGA_IO_HI] = io_hi;
+    memory_region_add_subregion_overlap(pci_dev->bus->address_space_io,
+                                        QEMU_PCI_VGA_IO_HI_BASE, io_hi, 1);
+    pci_dev->has_vga = true;
+
+    pci_update_vga(pci_dev);
+}
+
+void pci_unregister_vga(PCIDevice *pci_dev)
+{
+    if (!pci_dev->has_vga) {
+        return;
+    }
+
+    memory_region_del_subregion(pci_dev->bus->address_space_mem,
+                                pci_dev->vga_regions[QEMU_PCI_VGA_MEM]);
+    memory_region_del_subregion(pci_dev->bus->address_space_io,
+                                pci_dev->vga_regions[QEMU_PCI_VGA_IO_LO]);
+    memory_region_del_subregion(pci_dev->bus->address_space_io,
+                                pci_dev->vga_regions[QEMU_PCI_VGA_IO_HI]);
+    pci_dev->has_vga = false;
+}
+
 pcibus_t pci_get_bar_addr(PCIDevice *pci_dev, int region_num)
 {
     return pci_dev->io_regions[region_num].addr;
@@ -1036,6 +1108,8 @@ static void pci_update_mappings(PCIDevice *d)
                                                 r->addr, r->memory, 1);
         }
     }
+
+    pci_update_vga(d);
 }
 
 static inline int pci_irq_disabled(PCIDevice *d)
@@ -1117,7 +1191,7 @@ static void pci_set_irq(void *opaque, int irq_num, int level)
 /* Special hooks used by device assignment */
 void pci_bus_set_route_irq_fn(PCIBus *bus, pci_route_irq_fn route_intx_to_irq)
 {
-    assert(!bus->parent_dev);
+    assert(pci_bus_is_root(bus));
     bus->route_intx_to_irq = route_intx_to_irq;
 }
 
@@ -1156,9 +1230,10 @@ void pci_bus_fire_intx_routing_notifier(PCIBus *bus)
         if (dev && dev->intx_routing_notifier) {
             dev->intx_routing_notifier(dev);
         }
-        QLIST_FOREACH(sec, &bus->child, sibling) {
-            pci_bus_fire_intx_routing_notifier(sec);
-        }
+    }
+
+    QLIST_FOREACH(sec, &bus->child, sibling) {
+        pci_bus_fire_intx_routing_notifier(sec);
     }
 }
 
@@ -1581,7 +1656,7 @@ static PCIBus *pci_find_bus_nr(PCIBus *bus, int bus_num)
     }
 
     /* Consider all bus numbers in range for the host pci bridge. */
-    if (bus->parent_dev &&
+    if (!pci_bus_is_root(bus) &&
         !pci_secondary_bus_in_range(bus->parent_dev, bus_num)) {
         return NULL;
     }
@@ -1589,7 +1664,7 @@ static PCIBus *pci_find_bus_nr(PCIBus *bus, int bus_num)
     /* try child bus */
     for (; bus; bus = sec) {
         QLIST_FOREACH(sec, &bus->child, sibling) {
-            assert(sec->parent_dev);
+            assert(!pci_bus_is_root(sec));
             if (sec->parent_dev->config[PCI_SECONDARY_BUS] == bus_num) {
                 return sec;
             }
@@ -1852,7 +1927,12 @@ static int pci_add_option_rom(PCIDevice *pdev, bool is_default_rom)
     size = get_image_size(path);
     if (size < 0) {
         error_report("%s: failed to find romfile \"%s\"",
-                     __FUNCTION__, pdev->romfile);
+                     __func__, pdev->romfile);
+        g_free(path);
+        return -1;
+    } else if (size == 0) {
+        error_report("%s: ignoring empty romfile \"%s\"",
+                     __func__, pdev->romfile);
         g_free(path);
         return -1;
     }
@@ -2171,6 +2251,7 @@ static const TypeInfo pci_device_type_info = {
 static void pci_register_types(void)
 {
     type_register_static(&pci_bus_info);
+    type_register_static(&pcie_bus_info);
     type_register_static(&pci_device_type_info);
 }
 
diff --git a/hw/pci/pci.h b/hw/pci/pci.h
index 3beb70bf9a..9ea67a3832 100644
--- a/hw/pci/pci.h
+++ b/hw/pci/pci.h
@@ -109,6 +109,20 @@ typedef struct PCIIORegion {
 #define PCI_ROM_SLOT 6
 #define PCI_NUM_REGIONS 7
 
+enum {
+    QEMU_PCI_VGA_MEM,
+    QEMU_PCI_VGA_IO_LO,
+    QEMU_PCI_VGA_IO_HI,
+    QEMU_PCI_VGA_NUM_REGIONS,
+};
+
+#define QEMU_PCI_VGA_MEM_BASE 0xa0000
+#define QEMU_PCI_VGA_MEM_SIZE 0x20000
+#define QEMU_PCI_VGA_IO_LO_BASE 0x3b0
+#define QEMU_PCI_VGA_IO_LO_SIZE 0xc
+#define QEMU_PCI_VGA_IO_HI_BASE 0x3c0
+#define QEMU_PCI_VGA_IO_HI_SIZE 0x20
+
 #include "hw/pci/pci_regs.h"
 
 /* PCI HEADER_TYPE */
@@ -235,6 +249,10 @@ struct PCIDevice {
     /* IRQ objects for the INTA-INTD pins.  */
     qemu_irq *irq;
 
+    /* Legacy PCI VGA regions */
+    MemoryRegion *vga_regions[QEMU_PCI_VGA_NUM_REGIONS];
+    bool has_vga;
+
     /* Current IRQ levels.  Used internally by the generic PCI code.  */
     uint8_t irq_state;
 
@@ -288,6 +306,9 @@ struct PCIDevice {
 
 void pci_register_bar(PCIDevice *pci_dev, int region_num,
                       uint8_t attr, MemoryRegion *memory);
+void pci_register_vga(PCIDevice *pci_dev, MemoryRegion *mem,
+                      MemoryRegion *io_lo, MemoryRegion *io_hi);
+void pci_unregister_vga(PCIDevice *pci_dev);
 pcibus_t pci_get_bar_addr(PCIDevice *pci_dev, int region_num);
 
 int pci_add_capability(PCIDevice *pdev, uint8_t cap_id,
@@ -319,15 +340,22 @@ typedef enum {
 
 typedef int (*pci_hotplug_fn)(DeviceState *qdev, PCIDevice *pci_dev,
                               PCIHotplugState state);
+
+#define TYPE_PCI_BUS "PCI"
+#define PCI_BUS(obj) OBJECT_CHECK(PCIBus, (obj), TYPE_PCI_BUS)
+#define TYPE_PCIE_BUS "PCIE"
+
+bool pci_bus_is_express(PCIBus *bus);
+bool pci_bus_is_root(PCIBus *bus);
 void pci_bus_new_inplace(PCIBus *bus, DeviceState *parent,
                          const char *name,
                          MemoryRegion *address_space_mem,
                          MemoryRegion *address_space_io,
-                         uint8_t devfn_min);
+                         uint8_t devfn_min, const char *typename);
 PCIBus *pci_bus_new(DeviceState *parent, const char *name,
                     MemoryRegion *address_space_mem,
                     MemoryRegion *address_space_io,
-                    uint8_t devfn_min);
+                    uint8_t devfn_min, const char *typename);
 void pci_bus_irqs(PCIBus *bus, pci_set_irq_fn set_irq, pci_map_irq_fn map_irq,
                   void *irq_opaque, int nirq);
 int pci_bus_get_irq_level(PCIBus *bus, int irq_num);
@@ -339,7 +367,7 @@ PCIBus *pci_register_bus(DeviceState *parent, const char *name,
                          void *irq_opaque,
                          MemoryRegion *address_space_mem,
                          MemoryRegion *address_space_io,
-                         uint8_t devfn_min, int nirq);
+                         uint8_t devfn_min, int nirq, const char *typename);
 void pci_bus_set_route_irq_fn(PCIBus *, pci_route_irq_fn);
 PCIINTxRoute pci_device_route_intx_to_irq(PCIDevice *dev, int pin);
 bool pci_intx_route_changed(PCIINTxRoute *old, PCIINTxRoute *new);
diff --git a/hw/pci/pci_bridge.c b/hw/pci/pci_bridge.c
index 995842a72d..24be6c5067 100644
--- a/hw/pci/pci_bridge.c
+++ b/hw/pci/pci_bridge.c
@@ -151,6 +151,28 @@ static void pci_bridge_init_alias(PCIBridge *bridge, MemoryRegion *alias,
     memory_region_add_subregion_overlap(parent_space, base, alias, 1);
 }
 
+static void pci_bridge_init_vga_aliases(PCIBridge *br, PCIBus *parent,
+                                        MemoryRegion *alias_vga)
+{
+    uint16_t brctl = pci_get_word(br->dev.config + PCI_BRIDGE_CONTROL);
+
+    memory_region_init_alias(&alias_vga[QEMU_PCI_VGA_IO_LO],
+                             "pci_bridge_vga_io_lo", &br->address_space_io,
+                             QEMU_PCI_VGA_IO_LO_BASE, QEMU_PCI_VGA_IO_LO_SIZE);
+    memory_region_init_alias(&alias_vga[QEMU_PCI_VGA_IO_HI],
+                             "pci_bridge_vga_io_hi", &br->address_space_io,
+                             QEMU_PCI_VGA_IO_HI_BASE, QEMU_PCI_VGA_IO_HI_SIZE);
+    memory_region_init_alias(&alias_vga[QEMU_PCI_VGA_MEM],
+                             "pci_bridge_vga_mem", &br->address_space_mem,
+                             QEMU_PCI_VGA_MEM_BASE, QEMU_PCI_VGA_MEM_SIZE);
+
+    if (brctl & PCI_BRIDGE_CTL_VGA) {
+        pci_register_vga(&br->dev, &alias_vga[QEMU_PCI_VGA_MEM],
+                         &alias_vga[QEMU_PCI_VGA_IO_LO],
+                         &alias_vga[QEMU_PCI_VGA_IO_HI]);
+    }
+}
+
 static PCIBridgeWindows *pci_bridge_region_init(PCIBridge *br)
 {
     PCIBus *parent = br->dev.bus;
@@ -175,7 +197,8 @@ static PCIBridgeWindows *pci_bridge_region_init(PCIBridge *br)
                           &br->address_space_io,
                           parent->address_space_io,
                           cmd & PCI_COMMAND_IO);
-   /* TODO: optinal VGA and VGA palette snooping support. */
+
+    pci_bridge_init_vga_aliases(br, parent, w->alias_vga);
 
     return w;
 }
@@ -187,6 +210,7 @@ static void pci_bridge_region_del(PCIBridge *br, PCIBridgeWindows *w)
     memory_region_del_subregion(parent->address_space_io, &w->alias_io);
     memory_region_del_subregion(parent->address_space_mem, &w->alias_mem);
     memory_region_del_subregion(parent->address_space_mem, &w->alias_pref_mem);
+    pci_unregister_vga(&br->dev);
 }
 
 static void pci_bridge_region_cleanup(PCIBridge *br, PCIBridgeWindows *w)
@@ -194,6 +218,9 @@ static void pci_bridge_region_cleanup(PCIBridge *br, PCIBridgeWindows *w)
     memory_region_destroy(&w->alias_io);
     memory_region_destroy(&w->alias_mem);
     memory_region_destroy(&w->alias_pref_mem);
+    memory_region_destroy(&w->alias_vga[QEMU_PCI_VGA_IO_LO]);
+    memory_region_destroy(&w->alias_vga[QEMU_PCI_VGA_IO_HI]);
+    memory_region_destroy(&w->alias_vga[QEMU_PCI_VGA_MEM]);
     g_free(w);
 }
 
@@ -227,7 +254,10 @@ void pci_bridge_write_config(PCIDevice *d,
 
         /* memory base/limit, prefetchable base/limit and
            io base/limit upper 16 */
-        ranges_overlap(address, len, PCI_MEMORY_BASE, 20)) {
+        ranges_overlap(address, len, PCI_MEMORY_BASE, 20) ||
+
+        /* vga enable */
+        ranges_overlap(address, len, PCI_BRIDGE_CONTROL, 2)) {
         pci_bridge_update_mappings(s);
     }
 
@@ -298,7 +328,7 @@ void pci_bridge_reset(DeviceState *qdev)
 }
 
 /* default qdev initialization function for PCI-to-PCI bridge */
-int pci_bridge_initfn(PCIDevice *dev)
+int pci_bridge_initfn(PCIDevice *dev, const char *typename)
 {
     PCIBus *parent = dev->bus;
     PCIBridge *br = DO_UPCAST(PCIBridge, dev, dev);
@@ -306,6 +336,16 @@ int pci_bridge_initfn(PCIDevice *dev)
 
     pci_word_test_and_set_mask(dev->config + PCI_STATUS,
                                PCI_STATUS_66MHZ | PCI_STATUS_FAST_BACK);
+
+    /*
+     * TODO: We implement VGA Enable in the Bridge Control Register
+     * therefore per the PCI to PCI bridge spec we must also implement
+     * VGA Palette Snooping.  When done, set this bit writable:
+     *
+     * pci_word_test_and_set_mask(dev->wmask + PCI_COMMAND,
+     *                            PCI_COMMAND_VGA_PALETTE);
+     */
+
     pci_config_set_class(dev->config, PCI_CLASS_BRIDGE_PCI);
     dev->config[PCI_HEADER_TYPE] =
         (dev->config[PCI_HEADER_TYPE] & PCI_HEADER_TYPE_MULTI_FUNCTION) |
@@ -323,10 +363,9 @@ int pci_bridge_initfn(PCIDevice *dev)
 	    br->bus_name = dev->qdev.id;
     }
 
-    qbus_create_inplace(&sec_bus->qbus, TYPE_PCI_BUS, &dev->qdev,
-                        br->bus_name);
+    qbus_create_inplace(&sec_bus->qbus, typename, &dev->qdev, br->bus_name);
     sec_bus->parent_dev = dev;
-    sec_bus->map_irq = br->map_irq;
+    sec_bus->map_irq = br->map_irq ? br->map_irq : pci_swizzle_map_irq_fn;
     sec_bus->address_space_mem = &br->address_space_mem;
     memory_region_init(&br->address_space_mem, "pci_bridge_pci", INT64_MAX);
     sec_bus->address_space_io = &br->address_space_io;
diff --git a/hw/pci/pci_bridge.h b/hw/pci/pci_bridge.h
index 455cb6677a..1868f7aea8 100644
--- a/hw/pci/pci_bridge.h
+++ b/hw/pci/pci_bridge.h
@@ -43,7 +43,7 @@ void pci_bridge_disable_base_limit(PCIDevice *dev);
 void pci_bridge_reset_reg(PCIDevice *dev);
 void pci_bridge_reset(DeviceState *qdev);
 
-int pci_bridge_initfn(PCIDevice *pci_dev);
+int pci_bridge_initfn(PCIDevice *pci_dev, const char *typename);
 void pci_bridge_exitfn(PCIDevice *pci_dev);
 
 
@@ -55,12 +55,11 @@ void pci_bridge_exitfn(PCIDevice *pci_dev);
 void pci_bridge_map_irq(PCIBridge *br, const char* bus_name,
                         pci_map_irq_fn map_irq);
 
+/* TODO: add this define to pci_regs.h in linux and then in qemu. */
+#define  PCI_BRIDGE_CTL_VGA_16BIT	0x10	/* VGA 16-bit decode */
+#define  PCI_BRIDGE_CTL_DISCARD		0x100	/* Primary discard timer */
+#define  PCI_BRIDGE_CTL_SEC_DISCARD	0x200	/* Secondary discard timer */
+#define  PCI_BRIDGE_CTL_DISCARD_STATUS	0x400	/* Discard timer status */
+#define  PCI_BRIDGE_CTL_DISCARD_SERR	0x800	/* Discard timer SERR# enable */
+
 #endif  /* QEMU_PCI_BRIDGE_H */
-/*
- * Local variables:
- *  c-indent-level: 4
- *  c-basic-offset: 4
- *  tab-width: 8
- *  indent-tab-mode: nil
- * End:
- */
diff --git a/hw/pci/pci_bus.h b/hw/pci/pci_bus.h
index f905b9e11e..6ee443cf88 100644
--- a/hw/pci/pci_bus.h
+++ b/hw/pci/pci_bus.h
@@ -8,9 +8,6 @@
  * use accessor functions in pci.h, pci_bridge.h
  */
 
-#define TYPE_PCI_BUS "PCI"
-#define PCI_BUS(obj) OBJECT_CHECK(PCIBus, (obj), TYPE_PCI_BUS)
-
 struct PCIBus {
     BusState qbus;
     PCIDMAContextFunc dma_context_fn;
@@ -47,6 +44,13 @@ struct PCIBridgeWindows {
     MemoryRegion alias_pref_mem;
     MemoryRegion alias_mem;
     MemoryRegion alias_io;
+    /*
+     * When bridge control VGA forwarding is enabled, bridges will
+     * provide positive decode on the PCI VGA defined I/O port and
+     * MMIO ranges.  When enabled forwarding is only qualified on the
+     * I/O and memory enable bits in the bridge command register.
+     */
+    MemoryRegion alias_vga[QEMU_PCI_VGA_NUM_REGIONS];
 };
 
 struct PCIBridge {
diff --git a/hw/pci/pcie.c b/hw/pci/pcie.c
index 485c94c1b2..62bd0b8b3e 100644
--- a/hw/pci/pcie.c
+++ b/hw/pci/pcie.c
@@ -87,6 +87,22 @@ int pcie_cap_init(PCIDevice *dev, uint8_t offset, uint8_t type, uint8_t port)
     return pos;
 }
 
+int pcie_endpoint_cap_init(PCIDevice *dev, uint8_t offset)
+{
+    uint8_t type = PCI_EXP_TYPE_ENDPOINT;
+
+    /*
+     * Windows guests will report Code 10, device cannot start, if
+     * a regular Endpoint type is exposed on a root complex.  These
+     * should instead be Root Complex Integrated Endpoints.
+     */
+    if (pci_bus_is_express(dev->bus) && pci_bus_is_root(dev->bus)) {
+        type = PCI_EXP_TYPE_RC_END;
+    }
+
+    return pcie_cap_init(dev, offset, type, 0);
+}
+
 void pcie_cap_exit(PCIDevice *dev)
 {
     pci_del_capability(dev, PCI_CAP_ID_EXP, PCI_EXP_VER2_SIZEOF);
diff --git a/hw/pci/pcie.h b/hw/pci/pcie.h
index 31604e2742..c010007c5e 100644
--- a/hw/pci/pcie.h
+++ b/hw/pci/pcie.h
@@ -95,6 +95,7 @@ struct PCIExpressDevice {
 
 /* PCI express capability helper functions */
 int pcie_cap_init(PCIDevice *dev, uint8_t offset, uint8_t type, uint8_t port);
+int pcie_endpoint_cap_init(PCIDevice *dev, uint8_t offset);
 void pcie_cap_exit(PCIDevice *dev);
 uint8_t pcie_cap_get_type(const PCIDevice *dev);
 void pcie_cap_flags_set_vector(PCIDevice *dev, uint8_t vector);
diff --git a/hw/pci/pcie_port.c b/hw/pci/pcie_port.c
index 33a6b0a08a..91b53a0fc2 100644
--- a/hw/pci/pcie_port.c
+++ b/hw/pci/pcie_port.c
@@ -27,13 +27,17 @@ void pcie_port_init_reg(PCIDevice *d)
     pci_set_word(d->config + PCI_STATUS, 0);
     pci_set_word(d->config + PCI_SEC_STATUS, 0);
 
-    /* Unlike conventional pci bridge, some bits are hardwired to 0. */
-    pci_set_word(d->wmask + PCI_BRIDGE_CONTROL,
-                 PCI_BRIDGE_CTL_PARITY |
-                 PCI_BRIDGE_CTL_ISA |
-                 PCI_BRIDGE_CTL_VGA |
-                 PCI_BRIDGE_CTL_SERR |
-                 PCI_BRIDGE_CTL_BUS_RESET);
+    /*
+     * Unlike conventional pci bridge, for some bits the spec states:
+     * Does not apply to PCI Express and must be hardwired to 0.
+     */
+    pci_word_test_and_clear_mask(d->wmask + PCI_BRIDGE_CONTROL,
+                                 PCI_BRIDGE_CTL_MASTER_ABORT |
+                                 PCI_BRIDGE_CTL_FAST_BACK |
+                                 PCI_BRIDGE_CTL_DISCARD |
+                                 PCI_BRIDGE_CTL_SEC_DISCARD |
+                                 PCI_BRIDGE_CTL_DISCARD_STATUS |
+                                 PCI_BRIDGE_CTL_DISCARD_SERR);
 }
 
 /**************************************************************************
diff --git a/hw/pci_bridge_dev.c b/hw/pci_bridge_dev.c
index 9cc6a4082d..971b432474 100644
--- a/hw/pci_bridge_dev.c
+++ b/hw/pci_bridge_dev.c
@@ -36,22 +36,13 @@ struct PCIBridgeDev {
 };
 typedef struct PCIBridgeDev PCIBridgeDev;
 
-/* Mapping mandated by PCI-to-PCI Bridge architecture specification,
- * revision 1.2 */
-/* Table 9-1: Interrupt Binding for Devices Behind a Bridge */
-static int pci_bridge_dev_map_irq_fn(PCIDevice *dev, int irq_num)
-{
-    return (irq_num + PCI_SLOT(dev->devfn)) % PCI_NUM_PINS;
-}
-
 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;
 
-    pci_bridge_map_irq(br, NULL, pci_bridge_dev_map_irq_fn);
-    err = pci_bridge_initfn(dev);
+    err = pci_bridge_initfn(dev, TYPE_PCI_BUS);
     if (err) {
         goto bridge_error;
     }
diff --git a/hw/piix_pci.c b/hw/piix_pci.c
index e10bc1c6a0..ce397797fc 100644
--- a/hw/piix_pci.c
+++ b/hw/piix_pci.c
@@ -245,7 +245,7 @@ static PCIBus *i440fx_common_init(const char *device_name,
     dev = qdev_create(NULL, "i440FX-pcihost");
     s = PCI_HOST_BRIDGE(dev);
     b = pci_bus_new(dev, NULL, pci_address_space,
-                    address_space_io, 0);
+                    address_space_io, 0, TYPE_PCI_BUS);
     s->bus = b;
     object_property_add_child(qdev_get_machine(), "i440fx", OBJECT(dev), NULL);
     qdev_init_nofail(dev);
diff --git a/hw/ppc4xx_pci.c b/hw/ppc4xx_pci.c
index f3bbe88529..854e17048f 100644
--- a/hw/ppc4xx_pci.c
+++ b/hw/ppc4xx_pci.c
@@ -349,7 +349,7 @@ static int ppc4xx_pcihost_initfn(SysBusDevice *dev)
 
     b = pci_register_bus(DEVICE(dev), NULL, ppc4xx_pci_set_irq,
                          ppc4xx_pci_map_irq, s->irq, get_system_memory(),
-                         get_system_io(), 0, 4);
+                         get_system_io(), 0, 4, TYPE_PCI_BUS);
     h->bus = b;
 
     pci_create_simple(b, 0, "ppc4xx-host-bridge");
diff --git a/hw/ppce500_pci.c b/hw/ppce500_pci.c
index 310ae1c03d..abc7ebe1bf 100644
--- a/hw/ppce500_pci.c
+++ b/hw/ppce500_pci.c
@@ -356,7 +356,7 @@ static int e500_pcihost_initfn(SysBusDevice *dev)
 
     b = pci_register_bus(DEVICE(dev), NULL, mpc85xx_pci_set_irq,
                          mpc85xx_pci_map_irq, s->irq, address_space_mem,
-                         &s->pio, PCI_DEVFN(s->first_slot, 0), 4);
+                         &s->pio, PCI_DEVFN(s->first_slot, 0), 4, TYPE_PCI_BUS);
     h->bus = b;
 
     pci_create_simple(b, 0, "e500-host-bridge");
diff --git a/hw/prep_pci.c b/hw/prep_pci.c
index d21e87671e..58df2452cd 100644
--- a/hw/prep_pci.c
+++ b/hw/prep_pci.c
@@ -154,7 +154,7 @@ static void raven_pcihost_initfn(Object *obj)
     DeviceState *pci_dev;
 
     pci_bus_new_inplace(&s->pci_bus, DEVICE(obj), NULL,
-                        address_space_mem, address_space_io, 0);
+                        address_space_mem, address_space_io, 0, TYPE_PCI_BUS);
     h->bus = &s->pci_bus;
 
     object_initialize(&s->pci_dev, TYPE_RAVEN_PCI_DEVICE);
diff --git a/hw/q35.c b/hw/q35.c
index 0a25b8bf1f..6ea081aaa3 100644
--- a/hw/q35.c
+++ b/hw/q35.c
@@ -54,7 +54,8 @@ static int q35_host_init(SysBusDevice *dev)
         return -1;
     }
     b = pci_bus_new(&s->host.pci.busdev.qdev, "pcie.0",
-                    s->mch.pci_address_space, s->mch.address_space_io, 0);
+                    s->mch.pci_address_space, s->mch.address_space_io,
+                    0, TYPE_PCIE_BUS);
     s->host.pci.bus = b;
     qdev_set_parent_bus(DEVICE(&s->mch), BUS(b));
     qdev_init_nofail(DEVICE(&s->mch));
diff --git a/hw/qdev.c b/hw/qdev.c
index 6b1947ebe1..9b0f65246a 100644
--- a/hw/qdev.c
+++ b/hw/qdev.c
@@ -30,6 +30,8 @@
 #include "qapi/error.h"
 #include "qapi/qmp/qerror.h"
 #include "qapi/visitor.h"
+#include "qapi/qmp/qjson.h"
+#include "monitor/monitor.h"
 
 int qdev_hotplug = 0;
 static bool qdev_hot_added = false;
@@ -764,6 +766,8 @@ static void device_unparent(Object *obj)
     DeviceState *dev = DEVICE(obj);
     DeviceClass *dc = DEVICE_GET_CLASS(dev);
     BusState *bus;
+    QObject *event_data;
+    gchar *path = object_get_canonical_path(obj);
 
     while (dev->num_child_bus) {
         bus = QLIST_FIRST(&dev->child_bus);
@@ -782,6 +786,16 @@ static void device_unparent(Object *obj)
         object_unref(OBJECT(dev->parent_bus));
         dev->parent_bus = NULL;
     }
+
+    if (dev->id) {
+        event_data = qobject_from_jsonf("{ 'device': %s, 'path': %s }",
+                                        dev->id, path);
+    } else {
+        event_data = qobject_from_jsonf("{ 'path': %s }", path);
+    }
+    monitor_protocol_event(QEVENT_DEVICE_DELETED, event_data);
+    qobject_decref(event_data);
+    g_free(path);
 }
 
 static void device_class_init(ObjectClass *class, void *data)
diff --git a/hw/sh_pci.c b/hw/sh_pci.c
index 96535dbe01..e3e7550ae7 100644
--- a/hw/sh_pci.c
+++ b/hw/sh_pci.c
@@ -124,7 +124,7 @@ static int sh_pci_device_init(SysBusDevice *dev)
                               s->irq,
                               get_system_memory(),
                               get_system_io(),
-                              PCI_DEVFN(0, 0), 4);
+                              PCI_DEVFN(0, 0), 4, TYPE_PCI_BUS);
     memory_region_init_io(&s->memconfig_p4, &sh_pci_reg_ops, s,
                           "sh_pci", 0x224);
     memory_region_init_alias(&s->memconfig_a7, "sh_pci.2", &s->memconfig_p4,
diff --git a/hw/spapr_pci.c b/hw/spapr_pci.c
index 42c8b61c74..3e0d8d12fb 100644
--- a/hw/spapr_pci.c
+++ b/hw/spapr_pci.c
@@ -641,7 +641,7 @@ static int spapr_phb_init(SysBusDevice *s)
     bus = pci_register_bus(DEVICE(s), busname,
                            pci_spapr_set_irq, pci_spapr_map_irq, sphb,
                            &sphb->memspace, &sphb->iospace,
-                           PCI_DEVFN(0, 0), PCI_NUM_PINS);
+                           PCI_DEVFN(0, 0), PCI_NUM_PINS, TYPE_PCI_BUS);
     phb->bus = bus;
 
     sphb->dma_window_start = 0;
diff --git a/hw/unin_pci.c b/hw/unin_pci.c
index cb95ad1f5e..fff235d523 100644
--- a/hw/unin_pci.c
+++ b/hw/unin_pci.c
@@ -239,7 +239,7 @@ PCIBus *pci_pmac_init(qemu_irq *pic,
                               pic,
                               &d->pci_mmio,
                               address_space_io,
-                              PCI_DEVFN(11, 0), 4);
+                              PCI_DEVFN(11, 0), 4, TYPE_PCI_BUS);
 
 #if 0
     pci_create_simple(h->bus, PCI_DEVFN(11, 0), "uni-north");
@@ -305,7 +305,7 @@ PCIBus *pci_pmac_u3_init(qemu_irq *pic,
                               pic,
                               &d->pci_mmio,
                               address_space_io,
-                              PCI_DEVFN(11, 0), 4);
+                              PCI_DEVFN(11, 0), 4, TYPE_PCI_BUS);
 
     sysbus_mmio_map(s, 0, 0xf0800000);
     sysbus_mmio_map(s, 1, 0xf0c00000);
diff --git a/hw/usb/hcd-xhci.c b/hw/usb/hcd-xhci.c
index 07afdeef5b..5aa342bda5 100644
--- a/hw/usb/hcd-xhci.c
+++ b/hw/usb/hcd-xhci.c
@@ -3332,7 +3332,7 @@ static int usb_xhci_initfn(struct PCIDevice *dev)
                      PCI_BASE_ADDRESS_SPACE_MEMORY|PCI_BASE_ADDRESS_MEM_TYPE_64,
                      &xhci->mem);
 
-    ret = pcie_cap_init(&xhci->pci_dev, 0xa0, PCI_EXP_TYPE_ENDPOINT, 0);
+    ret = pcie_endpoint_cap_init(&xhci->pci_dev, 0xa0);
     assert(ret >= 0);
 
     if (xhci->flags & (1 << XHCI_FLAG_USE_MSI)) {
diff --git a/hw/versatile_pci.c b/hw/versatile_pci.c
index 0b97a4073d..d67ca796fb 100644
--- a/hw/versatile_pci.c
+++ b/hw/versatile_pci.c
@@ -70,7 +70,7 @@ static int pci_vpb_init(SysBusDevice *dev)
     bus = pci_register_bus(&dev->qdev, "pci",
                            pci_vpb_set_irq, pci_vpb_map_irq, s->irq,
                            get_system_memory(), get_system_io(),
-                           PCI_DEVFN(11, 0), 4);
+                           PCI_DEVFN(11, 0), 4, TYPE_PCI_BUS);
 
     /* ??? Register memory space.  */
 
diff --git a/hw/virtio-net.c b/hw/virtio-net.c
index 4bb49eb545..5917740d9d 100644
--- a/hw/virtio-net.c
+++ b/hw/virtio-net.c
@@ -528,13 +528,14 @@ static int virtio_net_handle_vlan_table(VirtIONet *n, uint8_t cmd,
 }
 
 static int virtio_net_handle_mq(VirtIONet *n, uint8_t cmd,
-                                VirtQueueElement *elem)
+                                struct iovec *iov, unsigned int iov_cnt)
 {
-    struct virtio_net_ctrl_mq s;
+    struct virtio_net_ctrl_mq mq;
+    size_t s;
+    uint16_t queues;
 
-    if (elem->out_num != 2 ||
-        elem->out_sg[1].iov_len != sizeof(struct virtio_net_ctrl_mq)) {
-        error_report("virtio-net ctrl invalid steering command");
+    s = iov_to_buf(iov, iov_cnt, 0, &mq, sizeof(mq));
+    if (s != sizeof(mq)) {
         return VIRTIO_NET_ERR;
     }
 
@@ -542,16 +543,16 @@ static int virtio_net_handle_mq(VirtIONet *n, uint8_t cmd,
         return VIRTIO_NET_ERR;
     }
 
-    memcpy(&s, elem->out_sg[1].iov_base, sizeof(struct virtio_net_ctrl_mq));
+    queues = lduw_p(&mq.virtqueue_pairs);
 
-    if (s.virtqueue_pairs < VIRTIO_NET_CTRL_MQ_VQ_PAIRS_MIN ||
-        s.virtqueue_pairs > VIRTIO_NET_CTRL_MQ_VQ_PAIRS_MAX ||
-        s.virtqueue_pairs > n->max_queues ||
+    if (queues < VIRTIO_NET_CTRL_MQ_VQ_PAIRS_MIN ||
+        queues > VIRTIO_NET_CTRL_MQ_VQ_PAIRS_MAX ||
+        queues > n->max_queues ||
         !n->multiqueue) {
         return VIRTIO_NET_ERR;
     }
 
-    n->curr_queues = s.virtqueue_pairs;
+    n->curr_queues = queues;
     /* stop the backend before changing the number of queues to avoid handling a
      * disabled queue */
     virtio_net_set_status(&n->vdev, n->vdev.status);
@@ -589,7 +590,7 @@ static void virtio_net_handle_ctrl(VirtIODevice *vdev, VirtQueue *vq)
         } else if (ctrl.class == VIRTIO_NET_CTRL_VLAN) {
             status = virtio_net_handle_vlan_table(n, ctrl.cmd, iov, iov_cnt);
         } else if (ctrl.class == VIRTIO_NET_CTRL_MQ) {
-            status = virtio_net_handle_mq(n, ctrl.cmd, &elem);
+            status = virtio_net_handle_mq(n, ctrl.cmd, iov, iov_cnt);
         }
 
         s = iov_from_buf(elem.in_sg, elem.in_num, 0, &status, sizeof(status));
diff --git a/hw/virtio-pci.c b/hw/virtio-pci.c
index 668060d991..736a9bf07d 100644
--- a/hw/virtio-pci.c
+++ b/hw/virtio-pci.c
@@ -609,20 +609,23 @@ static void kvm_virtio_pci_vector_release(VirtIOPCIProxy *proxy, int nvqs)
     }
 }
 
-static int kvm_virtio_pci_vq_vector_unmask(VirtIOPCIProxy *proxy,
-                                        unsigned int queue_no,
-                                        unsigned int vector,
-                                        MSIMessage msg)
+static int virtio_pci_vq_vector_unmask(VirtIOPCIProxy *proxy,
+                                       unsigned int queue_no,
+                                       unsigned int vector,
+                                       MSIMessage msg)
 {
     VirtQueue *vq = virtio_get_queue(proxy->vdev, queue_no);
     EventNotifier *n = virtio_queue_get_guest_notifier(vq);
-    VirtIOIRQFD *irqfd = &proxy->vector_irqfd[vector];
+    VirtIOIRQFD *irqfd;
     int ret = 0;
 
-    if (irqfd->msg.data != msg.data || irqfd->msg.address != msg.address) {
-        ret = kvm_irqchip_update_msi_route(kvm_state, irqfd->virq, msg);
-        if (ret < 0) {
-            return ret;
+    if (proxy->vector_irqfd) {
+        irqfd = &proxy->vector_irqfd[vector];
+        if (irqfd->msg.data != msg.data || irqfd->msg.address != msg.address) {
+            ret = kvm_irqchip_update_msi_route(kvm_state, irqfd->virq, msg);
+            if (ret < 0) {
+                return ret;
+            }
         }
     }
 
@@ -642,7 +645,7 @@ static int kvm_virtio_pci_vq_vector_unmask(VirtIOPCIProxy *proxy,
     return ret;
 }
 
-static void kvm_virtio_pci_vq_vector_mask(VirtIOPCIProxy *proxy,
+static void virtio_pci_vq_vector_mask(VirtIOPCIProxy *proxy,
                                              unsigned int queue_no,
                                              unsigned int vector)
 {
@@ -656,8 +659,8 @@ static void kvm_virtio_pci_vq_vector_mask(VirtIOPCIProxy *proxy,
     }
 }
 
-static int kvm_virtio_pci_vector_unmask(PCIDevice *dev, unsigned vector,
-                                     MSIMessage msg)
+static int virtio_pci_vector_unmask(PCIDevice *dev, unsigned vector,
+                                    MSIMessage msg)
 {
     VirtIOPCIProxy *proxy = container_of(dev, VirtIOPCIProxy, pci_dev);
     VirtIODevice *vdev = proxy->vdev;
@@ -670,7 +673,7 @@ static int kvm_virtio_pci_vector_unmask(PCIDevice *dev, unsigned vector,
         if (virtio_queue_vector(vdev, queue_no) != vector) {
             continue;
         }
-        ret = kvm_virtio_pci_vq_vector_unmask(proxy, queue_no, vector, msg);
+        ret = virtio_pci_vq_vector_unmask(proxy, queue_no, vector, msg);
         if (ret < 0) {
             goto undo;
         }
@@ -682,12 +685,12 @@ undo:
         if (virtio_queue_vector(vdev, queue_no) != vector) {
             continue;
         }
-        kvm_virtio_pci_vq_vector_mask(proxy, queue_no, vector);
+        virtio_pci_vq_vector_mask(proxy, queue_no, vector);
     }
     return ret;
 }
 
-static void kvm_virtio_pci_vector_mask(PCIDevice *dev, unsigned vector)
+static void virtio_pci_vector_mask(PCIDevice *dev, unsigned vector)
 {
     VirtIOPCIProxy *proxy = container_of(dev, VirtIOPCIProxy, pci_dev);
     VirtIODevice *vdev = proxy->vdev;
@@ -700,13 +703,13 @@ static void kvm_virtio_pci_vector_mask(PCIDevice *dev, unsigned vector)
         if (virtio_queue_vector(vdev, queue_no) != vector) {
             continue;
         }
-        kvm_virtio_pci_vq_vector_mask(proxy, queue_no, vector);
+        virtio_pci_vq_vector_mask(proxy, queue_no, vector);
     }
 }
 
-static void kvm_virtio_pci_vector_poll(PCIDevice *dev,
-                                       unsigned int vector_start,
-                                       unsigned int vector_end)
+static void virtio_pci_vector_poll(PCIDevice *dev,
+                                   unsigned int vector_start,
+                                   unsigned int vector_end)
 {
     VirtIOPCIProxy *proxy = container_of(dev, VirtIOPCIProxy, pci_dev);
     VirtIODevice *vdev = proxy->vdev;
@@ -781,11 +784,13 @@ static int virtio_pci_set_guest_notifiers(DeviceState *d, int nvqs, bool assign)
     proxy->nvqs_with_notifiers = nvqs;
 
     /* Must unset vector notifier while guest notifier is still assigned */
-    if (proxy->vector_irqfd && !assign) {
+    if ((proxy->vector_irqfd || vdev->guest_notifier_mask) && !assign) {
         msix_unset_vector_notifiers(&proxy->pci_dev);
-        kvm_virtio_pci_vector_release(proxy, nvqs);
-        g_free(proxy->vector_irqfd);
-        proxy->vector_irqfd = NULL;
+        if (proxy->vector_irqfd) {
+            kvm_virtio_pci_vector_release(proxy, nvqs);
+            g_free(proxy->vector_irqfd);
+            proxy->vector_irqfd = NULL;
+        }
     }
 
     for (n = 0; n < nvqs; n++) {
@@ -801,18 +806,20 @@ static int virtio_pci_set_guest_notifiers(DeviceState *d, int nvqs, bool assign)
     }
 
     /* Must set vector notifier after guest notifier has been assigned */
-    if (with_irqfd && assign) {
-        proxy->vector_irqfd =
-            g_malloc0(sizeof(*proxy->vector_irqfd) *
-                      msix_nr_vectors_allocated(&proxy->pci_dev));
-        r = kvm_virtio_pci_vector_use(proxy, nvqs);
-        if (r < 0) {
-            goto assign_error;
+    if ((with_irqfd || vdev->guest_notifier_mask) && assign) {
+        if (with_irqfd) {
+            proxy->vector_irqfd =
+                g_malloc0(sizeof(*proxy->vector_irqfd) *
+                          msix_nr_vectors_allocated(&proxy->pci_dev));
+            r = kvm_virtio_pci_vector_use(proxy, nvqs);
+            if (r < 0) {
+                goto assign_error;
+            }
         }
         r = msix_set_vector_notifiers(&proxy->pci_dev,
-                                      kvm_virtio_pci_vector_unmask,
-                                      kvm_virtio_pci_vector_mask,
-                                      kvm_virtio_pci_vector_poll);
+                                      virtio_pci_vector_unmask,
+                                      virtio_pci_vector_mask,
+                                      virtio_pci_vector_poll);
         if (r < 0) {
             goto notifiers_error;
         }
@@ -821,8 +828,10 @@ static int virtio_pci_set_guest_notifiers(DeviceState *d, int nvqs, bool assign)
     return 0;
 
 notifiers_error:
-    assert(assign);
-    kvm_virtio_pci_vector_release(proxy, nvqs);
+    if (with_irqfd) {
+        assert(assign);
+        kvm_virtio_pci_vector_release(proxy, nvqs);
+    }
 
 assign_error:
     /* We get here on assignment failure. Recover by undoing for VQs 0 .. n. */
diff --git a/hw/xio3130_downstream.c b/hw/xio3130_downstream.c
index 4bccd0ddcd..b868f56ff9 100644
--- a/hw/xio3130_downstream.c
+++ b/hw/xio3130_downstream.c
@@ -61,7 +61,7 @@ static int xio3130_downstream_initfn(PCIDevice *d)
     PCIESlot *s = DO_UPCAST(PCIESlot, port, p);
     int rc;
 
-    rc = pci_bridge_initfn(d);
+    rc = pci_bridge_initfn(d, TYPE_PCIE_BUS);
     if (rc < 0) {
         return rc;
     }
diff --git a/hw/xio3130_upstream.c b/hw/xio3130_upstream.c
index 82556aaadc..cd5d97d211 100644
--- a/hw/xio3130_upstream.c
+++ b/hw/xio3130_upstream.c
@@ -57,7 +57,7 @@ static int xio3130_upstream_initfn(PCIDevice *d)
     PCIEPort *p = DO_UPCAST(PCIEPort, br, br);
     int rc;
 
-    rc = pci_bridge_initfn(d);
+    rc = pci_bridge_initfn(d, TYPE_PCIE_BUS);
     if (rc < 0) {
         return rc;
     }
diff --git a/include/monitor/monitor.h b/include/monitor/monitor.h
index 87fb49c092..b868760d7c 100644
--- a/include/monitor/monitor.h
+++ b/include/monitor/monitor.h
@@ -39,6 +39,7 @@ typedef enum MonitorEvent {
     QEVENT_BLOCK_JOB_CANCELLED,
     QEVENT_BLOCK_JOB_ERROR,
     QEVENT_BLOCK_JOB_READY,
+    QEVENT_DEVICE_DELETED,
     QEVENT_DEVICE_TRAY_MOVED,
     QEVENT_SUSPEND,
     QEVENT_SUSPEND_DISK,
diff --git a/monitor.c b/monitor.c
index e450919269..5dfae2a172 100644
--- a/monitor.c
+++ b/monitor.c
@@ -477,6 +477,7 @@ static const char *monitor_event_names[] = {
     [QEVENT_BLOCK_JOB_CANCELLED] = "BLOCK_JOB_CANCELLED",
     [QEVENT_BLOCK_JOB_ERROR] = "BLOCK_JOB_ERROR",
     [QEVENT_BLOCK_JOB_READY] = "BLOCK_JOB_READY",
+    [QEVENT_DEVICE_DELETED] = "DEVICE_DELETED",
     [QEVENT_DEVICE_TRAY_MOVED] = "DEVICE_TRAY_MOVED",
     [QEVENT_SUSPEND] = "SUSPEND",
     [QEVENT_SUSPEND_DISK] = "SUSPEND_DISK",
diff --git a/qapi-schema.json b/qapi-schema.json
index 6494787714..f629a249de 100644
--- a/qapi-schema.json
+++ b/qapi-schema.json
@@ -2367,7 +2367,9 @@
 # Notes: When this command completes, the device may not be removed from the
 #        guest.  Hot removal is an operation that requires guest cooperation.
 #        This command merely requests that the guest begin the hot removal
-#        process.
+#        process.  Completion of the device removal process is signaled with a
+#        DEVICE_DELETED event. Guest reset will automatically complete removal
+#        for all devices.
 #
 # Since: 0.14.0
 ##
diff --git a/qom/object.c b/qom/object.c
index 3f77968560..881814943b 100644
--- a/qom/object.c
+++ b/qom/object.c
@@ -363,12 +363,12 @@ static void object_property_del_child(Object *obj, Object *child, Error **errp)
 void object_unparent(Object *obj)
 {
     object_ref(obj);
-    if (obj->parent) {
-        object_property_del_child(obj->parent, obj, NULL);
-    }
     if (obj->class->unparent) {
         (obj->class->unparent)(obj);
     }
+    if (obj->parent) {
+        object_property_del_child(obj->parent, obj, NULL);
+    }
     object_unref(obj);
 }
 
diff --git a/roms/configure-seabios.sh b/roms/configure-seabios.sh
index 98f59a24ba..4bb6c2b90f 100755
--- a/roms/configure-seabios.sh
+++ b/roms/configure-seabios.sh
@@ -2,4 +2,4 @@
 config="$1"
 make -C seabios clean distclean
 cp "$config" seabios/.config
-make -C seabios oldnoconfig
+make -C seabios olddefconfig