]> git.proxmox.com Git - mirror_qemu.git/blobdiff - hw/pci.c
Merge branch 'pci' into for_anthony
[mirror_qemu.git] / hw / pci.c
index 6d94286a46f88c62728bf0a7f91d72b3563a6cba..962886e767921d6bfe9a7f4318af72b6340c2749 100644 (file)
--- a/hw/pci.c
+++ b/hw/pci.c
  */
 #include "hw.h"
 #include "pci.h"
+#include "pci_bridge.h"
+#include "pci_internals.h"
+#include "msix.h"
+#include "msi.h"
 #include "monitor.h"
 #include "net.h"
 #include "sysemu.h"
+#include "loader.h"
+#include "qemu-objects.h"
+#include "range.h"
 
 //#define DEBUG_PCI
 #ifdef DEBUG_PCI
 # define PCI_DPRINTF(format, ...)       do { } while (0)
 #endif
 
-struct PCIBus {
-    BusState qbus;
-    int devfn_min;
-    pci_set_irq_fn set_irq;
-    pci_map_irq_fn map_irq;
-    pci_hotplug_fn hotplug;
-    uint32_t config_reg; /* XXX: suppress */
-    void *irq_opaque;
-    PCIDevice *devices[256];
-    PCIDevice *parent_dev;
-
-    QLIST_HEAD(, PCIBus) child; /* this will be replaced by qdev later */
-    QLIST_ENTRY(PCIBus) sibling;/* this will be replaced by qdev later */
-
-    /* The bus IRQ state is the logical OR of the connected devices.
-       Keep a count of the number of devices with raised IRQs.  */
-    int nirq;
-    int *irq_count;
-};
-
 static void pcibus_dev_print(Monitor *mon, DeviceState *dev, int indent);
+static char *pcibus_get_dev_path(DeviceState *dev);
 
-static struct BusInfo pci_bus_info = {
+struct BusInfo pci_bus_info = {
     .name       = "PCI",
     .size       = sizeof(PCIBus),
     .print_dev  = pcibus_dev_print,
+    .get_dev_path = pcibus_get_dev_path,
     .props      = (Property[]) {
         DEFINE_PROP_PCI_DEVFN("addr", PCIDevice, devfn, -1),
+        DEFINE_PROP_STRING("romfile", PCIDevice, romfile),
+        DEFINE_PROP_UINT32("rombar",  PCIDevice, rom_bar, 1),
+        DEFINE_PROP_BIT("multifunction", PCIDevice, cap_present,
+                        QEMU_PCI_CAP_MULTIFUNCTION_BITNR, false),
         DEFINE_PROP_END_OF_LIST()
     }
 };
 
 static void pci_update_mappings(PCIDevice *d);
 static void pci_set_irq(void *opaque, int irq_num, int level);
+static int pci_add_option_rom(PCIDevice *pdev);
+static void pci_del_option_rom(PCIDevice *pdev);
 
-target_phys_addr_t pci_mem_base;
 static uint16_t pci_default_sub_vendor_id = PCI_SUBVENDOR_ID_REDHAT_QUMRANET;
 static uint16_t pci_default_sub_device_id = PCI_SUBDEVICE_ID_QEMU;
 
@@ -103,20 +97,66 @@ static int pci_bar(PCIDevice *d, int reg)
     return type == PCI_HEADER_TYPE_BRIDGE ? PCI_ROM_ADDRESS1 : PCI_ROM_ADDRESS;
 }
 
+static inline int pci_irq_state(PCIDevice *d, int irq_num)
+{
+       return (d->irq_state >> irq_num) & 0x1;
+}
+
+static inline void pci_set_irq_state(PCIDevice *d, int irq_num, int level)
+{
+       d->irq_state &= ~(0x1 << irq_num);
+       d->irq_state |= level << irq_num;
+}
+
+static void pci_change_irq_level(PCIDevice *pci_dev, int irq_num, int change)
+{
+    PCIBus *bus;
+    for (;;) {
+        bus = pci_dev->bus;
+        irq_num = bus->map_irq(pci_dev, irq_num);
+        if (bus->set_irq)
+            break;
+        pci_dev = bus->parent_dev;
+    }
+    bus->irq_count[irq_num] += change;
+    bus->set_irq(bus->irq_opaque, irq_num, bus->irq_count[irq_num] != 0);
+}
+
+/* Update interrupt status bit in config space on interrupt
+ * state change. */
+static void pci_update_irq_status(PCIDevice *dev)
+{
+    if (dev->irq_state) {
+        dev->config[PCI_STATUS] |= PCI_STATUS_INTERRUPT;
+    } else {
+        dev->config[PCI_STATUS] &= ~PCI_STATUS_INTERRUPT;
+    }
+}
+
 static void pci_device_reset(PCIDevice *dev)
 {
     int r;
 
-    memset(dev->irq_state, 0, sizeof dev->irq_state);
-    dev->config[PCI_COMMAND] &= ~(PCI_COMMAND_IO | PCI_COMMAND_MEMORY |
-                                  PCI_COMMAND_MASTER);
+    dev->irq_state = 0;
+    pci_update_irq_status(dev);
+    /* Clear all writeable bits */
+    pci_word_test_and_clear_mask(dev->config + PCI_COMMAND,
+                                 pci_get_word(dev->wmask + PCI_COMMAND) |
+                                 pci_get_word(dev->w1cmask + PCI_COMMAND));
     dev->config[PCI_CACHE_LINE_SIZE] = 0x0;
     dev->config[PCI_INTERRUPT_LINE] = 0x0;
     for (r = 0; r < PCI_NUM_REGIONS; ++r) {
-        if (!dev->io_regions[r].size) {
+        PCIIORegion *region = &dev->io_regions[r];
+        if (!region->size) {
             continue;
         }
-        pci_set_long(dev->config + pci_bar(dev, r), dev->io_regions[r].type);
+
+        if (!(region->type & PCI_BASE_ADDRESS_SPACE_IO) &&
+            region->type & PCI_BASE_ADDRESS_MEM_TYPE_64) {
+            pci_set_quad(dev->config + pci_bar(dev, r), region->type);
+        } else {
+            pci_set_long(dev->config + pci_bar(dev, r), region->type);
+        }
     }
     pci_update_mappings(dev);
 }
@@ -158,19 +198,38 @@ PCIBus *pci_find_root_bus(int domain)
     return NULL;
 }
 
+int pci_find_domain(const PCIBus *bus)
+{
+    PCIDevice *d;
+    struct PCIHostBus *host;
+
+    /* obtain root bus */
+    while ((d = bus->parent_dev) != NULL) {
+        bus = d->bus;
+    }
+
+    QLIST_FOREACH(host, &host_buses, next) {
+        if (host->bus == bus) {
+            return host->domain;
+        }
+    }
+
+    abort();    /* should not be reached */
+    return -1;
+}
+
 void pci_bus_new_inplace(PCIBus *bus, DeviceState *parent,
                          const char *name, int devfn_min)
 {
-    static int nbus = 0;
-
     qbus_create_inplace(&bus->qbus, &pci_bus_info, parent, name);
+    assert(PCI_FUNC(devfn_min) == 0);
     bus->devfn_min = devfn_min;
 
     /* host bridge */
     QLIST_INIT(&bus->child);
     pci_host_bus_register(0, bus); /* for now only pci domain 0 is supported */
 
-    vmstate_register(nbus++, &vmstate_pcibus, bus);
+    vmstate_register(NULL, -1, &vmstate_pcibus, bus);
     qemu_register_reset(pci_bus_reset, bus);
 }
 
@@ -194,10 +253,16 @@ void pci_bus_irqs(PCIBus *bus, pci_set_irq_fn set_irq, pci_map_irq_fn map_irq,
     bus->irq_count = qemu_mallocz(nirq * sizeof(bus->irq_count[0]));
 }
 
-void pci_bus_hotplug(PCIBus *bus, pci_hotplug_fn hotplug)
+void pci_bus_hotplug(PCIBus *bus, pci_hotplug_fn hotplug, DeviceState *qdev)
 {
     bus->qbus.allow_hotplug = 1;
     bus->hotplug = hotplug;
+    bus->hotplug_qdev = qdev;
+}
+
+void pci_bus_set_mem_base(PCIBus *bus, target_phys_addr_t base)
+{
+    bus->mem_base = base;
 }
 
 PCIBus *pci_register_bus(DeviceState *parent, const char *name,
@@ -211,26 +276,6 @@ PCIBus *pci_register_bus(DeviceState *parent, const char *name,
     return bus;
 }
 
-static void pci_register_secondary_bus(PCIBus *parent,
-                                       PCIBus *bus,
-                                       PCIDevice *dev,
-                                       pci_map_irq_fn map_irq,
-                                       const char *name)
-{
-    qbus_create_inplace(&bus->qbus, &pci_bus_info, &dev->qdev, name);
-    bus->map_irq = map_irq;
-    bus->parent_dev = dev;
-
-    QLIST_INIT(&bus->child);
-    QLIST_INSERT_HEAD(&parent->child, bus, sibling);
-}
-
-static void pci_unregister_secondary_bus(PCIBus *bus)
-{
-    assert(QLIST_EMPTY(&bus->child));
-    QLIST_REMOVE(bus, sibling);
-}
-
 int pci_bus_num(PCIBus *s)
 {
     if (!s->parent_dev)
@@ -249,7 +294,8 @@ static int get_pci_config_device(QEMUFile *f, void *pv, size_t size)
 
     qemu_get_buffer(f, config, size);
     for (i = 0; i < size; ++i) {
-        if ((config[i] ^ s->config[i]) & s->cmask[i] & ~s->wmask[i]) {
+        if ((config[i] ^ s->config[i]) &
+            s->cmask[i] & ~s->wmask[i] & ~s->w1cmask[i]) {
             qemu_free(config);
             return -EINVAL;
         }
@@ -276,6 +322,43 @@ static VMStateInfo vmstate_info_pci_config = {
     .put  = put_pci_config_device,
 };
 
+static int get_pci_irq_state(QEMUFile *f, void *pv, size_t size)
+{
+    PCIDevice *s = container_of(pv, PCIDevice, irq_state);
+    uint32_t irq_state[PCI_NUM_PINS];
+    int i;
+    for (i = 0; i < PCI_NUM_PINS; ++i) {
+        irq_state[i] = qemu_get_be32(f);
+        if (irq_state[i] != 0x1 && irq_state[i] != 0) {
+            fprintf(stderr, "irq state %d: must be 0 or 1.\n",
+                    irq_state[i]);
+            return -EINVAL;
+        }
+    }
+
+    for (i = 0; i < PCI_NUM_PINS; ++i) {
+        pci_set_irq_state(s, i, irq_state[i]);
+    }
+
+    return 0;
+}
+
+static void put_pci_irq_state(QEMUFile *f, void *pv, size_t size)
+{
+    int i;
+    PCIDevice *s = container_of(pv, PCIDevice, irq_state);
+
+    for (i = 0; i < PCI_NUM_PINS; ++i) {
+        qemu_put_be32(f, pci_irq_state(s, i));
+    }
+}
+
+static VMStateInfo vmstate_info_pci_irq_state = {
+    .name = "pci irq state",
+    .get  = get_pci_irq_state,
+    .put  = put_pci_irq_state,
+};
+
 const VMStateDescription vmstate_pci_device = {
     .name = "PCIDevice",
     .version_id = 2,
@@ -286,7 +369,9 @@ const VMStateDescription vmstate_pci_device = {
         VMSTATE_BUFFER_UNSAFE_INFO(config, PCIDevice, 0,
                                    vmstate_info_pci_config,
                                    PCI_CONFIG_SPACE_SIZE),
-        VMSTATE_INT32_ARRAY_V(irq_state, PCIDevice, PCI_NUM_PINS, 2),
+        VMSTATE_BUFFER_UNSAFE_INFO(irq_state, PCIDevice, 2,
+                                  vmstate_info_pci_irq_state,
+                                  PCI_NUM_PINS * sizeof(int32_t)),
         VMSTATE_END_OF_LIST()
     }
 };
@@ -301,7 +386,9 @@ const VMStateDescription vmstate_pcie_device = {
         VMSTATE_BUFFER_UNSAFE_INFO(config, PCIDevice, 0,
                                    vmstate_info_pci_config,
                                    PCIE_CONFIG_SPACE_SIZE),
-        VMSTATE_INT32_ARRAY_V(irq_state, PCIDevice, PCI_NUM_PINS, 2),
+        VMSTATE_BUFFER_UNSAFE_INFO(irq_state, PCIDevice, 2,
+                                  vmstate_info_pci_irq_state,
+                                  PCI_NUM_PINS * sizeof(int32_t)),
         VMSTATE_END_OF_LIST()
     }
 };
@@ -313,34 +400,46 @@ static inline const VMStateDescription *pci_get_vmstate(PCIDevice *s)
 
 void pci_device_save(PCIDevice *s, QEMUFile *f)
 {
+    /* Clear interrupt status bit: it is implicit
+     * in irq_state which we are saving.
+     * This makes us compatible with old devices
+     * which never set or clear this bit. */
+    s->config[PCI_STATUS] &= ~PCI_STATUS_INTERRUPT;
     vmstate_save_state(f, pci_get_vmstate(s), s);
+    /* Restore the interrupt status bit. */
+    pci_update_irq_status(s);
 }
 
 int pci_device_load(PCIDevice *s, QEMUFile *f)
 {
-    return vmstate_load_state(f, pci_get_vmstate(s), s, s->version_id);
+    int ret;
+    ret = vmstate_load_state(f, pci_get_vmstate(s), s, s->version_id);
+    /* Restore the interrupt status bit. */
+    pci_update_irq_status(s);
+    return ret;
 }
 
-static int pci_set_default_subsystem_id(PCIDevice *pci_dev)
+static void pci_set_default_subsystem_id(PCIDevice *pci_dev)
 {
-    uint16_t *id;
-
-    id = (void*)(&pci_dev->config[PCI_SUBVENDOR_ID]);
-    id[0] = cpu_to_le16(pci_default_sub_vendor_id);
-    id[1] = cpu_to_le16(pci_default_sub_device_id);
-    return 0;
+    pci_set_word(pci_dev->config + PCI_SUBSYSTEM_VENDOR_ID,
+                 pci_default_sub_vendor_id);
+    pci_set_word(pci_dev->config + PCI_SUBSYSTEM_ID,
+                 pci_default_sub_device_id);
 }
 
 /*
- * Parse [[<domain>:]<bus>:]<slot>, return -1 on error
+ * Parse [[<domain>:]<bus>:]<slot>, return -1 on error if funcp == NULL
+ *       [[<domain>:]<bus>:]<slot>.<func>, return -1 on error
  */
-static int pci_parse_devaddr(const char *addr, int *domp, int *busp, unsigned *slotp)
+int pci_parse_devaddr(const char *addr, int *domp, int *busp,
+                      unsigned int *slotp, unsigned int *funcp)
 {
     const char *p;
     char *e;
     unsigned long val;
     unsigned long dom = 0, bus = 0;
-    unsigned slot = 0;
+    unsigned int slot = 0;
+    unsigned int func = 0;
 
     p = addr;
     val = strtoul(p, &e, 16);
@@ -362,11 +461,24 @@ static int pci_parse_devaddr(const char *addr, int *domp, int *busp, unsigned *s
        }
     }
 
-    if (dom > 0xffff || bus > 0xff || val > 0x1f)
-       return -1;
-
     slot = val;
 
+    if (funcp != NULL) {
+        if (*e != '.')
+            return -1;
+
+        p = e + 1;
+        val = strtoul(p, &e, 16);
+        if (e == p)
+            return -1;
+
+        func = val;
+    }
+
+    /* if funcp == NULL func is 0 */
+    if (dom > 0xffff || bus > 0xff || slot > 0x1f || func > 7)
+       return -1;
+
     if (*e)
        return -1;
 
@@ -377,6 +489,8 @@ static int pci_parse_devaddr(const char *addr, int *domp, int *busp, unsigned *s
     *domp = dom;
     *busp = bus;
     *slotp = slot;
+    if (funcp != NULL)
+        *funcp = func;
     return 0;
 }
 
@@ -387,7 +501,7 @@ int pci_read_devaddr(Monitor *mon, const char *addr, int *domp, int *busp,
     if (!strncmp(addr, "pci_addr=", 9)) {
         addr += 9;
     }
-    if (pci_parse_devaddr(addr, domp, busp, slotp)) {
+    if (pci_parse_devaddr(addr, domp, busp, slotp, NULL)) {
         monitor_printf(mon, "Invalid pci address\n");
         return -1;
     }
@@ -404,12 +518,12 @@ PCIBus *pci_get_bus_devfn(int *devfnp, const char *devaddr)
         return pci_find_bus(pci_find_root_bus(0), 0);
     }
 
-    if (pci_parse_devaddr(devaddr, &dom, &bus, &slot) < 0) {
+    if (pci_parse_devaddr(devaddr, &dom, &bus, &slot, NULL) < 0) {
         return NULL;
     }
 
     *devfnp = slot << 3;
-    return pci_find_bus(pci_find_root_bus(0), bus);
+    return pci_find_bus(pci_find_root_bus(dom), bus);
 }
 
 static void pci_init_cmask(PCIDevice *dev)
@@ -431,7 +545,8 @@ static void pci_init_wmask(PCIDevice *dev)
     dev->wmask[PCI_CACHE_LINE_SIZE] = 0xff;
     dev->wmask[PCI_INTERRUPT_LINE] = 0xff;
     pci_set_word(dev->wmask + PCI_COMMAND,
-                 PCI_COMMAND_IO | PCI_COMMAND_MEMORY | PCI_COMMAND_MASTER);
+                 PCI_COMMAND_IO | PCI_COMMAND_MEMORY | PCI_COMMAND_MASTER |
+                 PCI_COMMAND_INTX_DISABLE);
 
     memset(dev->wmask + PCI_CONFIG_HEADER_SIZE, 0xff,
            config_size - PCI_CONFIG_HEADER_SIZE);
@@ -461,6 +576,54 @@ static void pci_init_wmask_bridge(PCIDevice *d)
     pci_set_word(d->wmask + PCI_BRIDGE_CONTROL, 0xffff);
 }
 
+static int pci_init_multifunction(PCIBus *bus, PCIDevice *dev)
+{
+    uint8_t slot = PCI_SLOT(dev->devfn);
+    uint8_t func;
+
+    if (dev->cap_present & QEMU_PCI_CAP_MULTIFUNCTION) {
+        dev->config[PCI_HEADER_TYPE] |= PCI_HEADER_TYPE_MULTI_FUNCTION;
+    }
+
+    /*
+     * multifunction bit is interpreted in two ways as follows.
+     *   - all functions must set the bit to 1.
+     *     Example: Intel X53
+     *   - function 0 must set the bit, but the rest function (> 0)
+     *     is allowed to leave the bit to 0.
+     *     Example: PIIX3(also in qemu), PIIX4(also in qemu), ICH10,
+     *
+     * So OS (at least Linux) checks the bit of only function 0,
+     * and doesn't see the bit of function > 0.
+     *
+     * The below check allows both interpretation.
+     */
+    if (PCI_FUNC(dev->devfn)) {
+        PCIDevice *f0 = bus->devices[PCI_DEVFN(slot, 0)];
+        if (f0 && !(f0->cap_present & QEMU_PCI_CAP_MULTIFUNCTION)) {
+            /* function 0 should set multifunction bit */
+            error_report("PCI: single function device can't be populated "
+                         "in function %x.%x", slot, PCI_FUNC(dev->devfn));
+            return -1;
+        }
+        return 0;
+    }
+
+    if (dev->cap_present & QEMU_PCI_CAP_MULTIFUNCTION) {
+        return 0;
+    }
+    /* function 0 indicates single function, so function > 0 must be NULL */
+    for (func = 1; func < PCI_FUNC_MAX; ++func) {
+        if (bus->devices[PCI_DEVFN(slot, func)]) {
+            error_report("PCI: %x.0 indicates single function, "
+                         "but %x.%x is already populated.",
+                         slot, slot, func);
+            return -1;
+        }
+    }
+    return 0;
+}
+
 static void pci_config_alloc(PCIDevice *pci_dev)
 {
     int config_size = pci_config_size(pci_dev);
@@ -468,6 +631,7 @@ static void pci_config_alloc(PCIDevice *pci_dev)
     pci_dev->config = qemu_mallocz(config_size);
     pci_dev->cmask = qemu_mallocz(config_size);
     pci_dev->wmask = qemu_mallocz(config_size);
+    pci_dev->w1cmask = qemu_mallocz(config_size);
     pci_dev->used = qemu_mallocz(config_size);
 }
 
@@ -476,6 +640,7 @@ static void pci_config_free(PCIDevice *pci_dev)
     qemu_free(pci_dev->config);
     qemu_free(pci_dev->cmask);
     qemu_free(pci_dev->wmask);
+    qemu_free(pci_dev->w1cmask);
     qemu_free(pci_dev->used);
 }
 
@@ -484,35 +649,40 @@ static PCIDevice *do_pci_register_device(PCIDevice *pci_dev, PCIBus *bus,
                                          const char *name, int devfn,
                                          PCIConfigReadFunc *config_read,
                                          PCIConfigWriteFunc *config_write,
-                                         uint8_t header_type)
+                                         bool is_bridge)
 {
     if (devfn < 0) {
         for(devfn = bus->devfn_min ; devfn < ARRAY_SIZE(bus->devices);
-            devfn += 8) {
+            devfn += PCI_FUNC_MAX) {
             if (!bus->devices[devfn])
                 goto found;
         }
-        hw_error("PCI: no devfn available for %s, all in use\n", name);
+        error_report("PCI: no slot/function available for %s, all in use", name);
+        return NULL;
     found: ;
     } else if (bus->devices[devfn]) {
-        hw_error("PCI: devfn %d not available for %s, in use by %s\n", devfn,
-                 name, bus->devices[devfn]->name);
+        error_report("PCI: slot %d function %d not available for %s, in use by %s",
+                     PCI_SLOT(devfn), PCI_FUNC(devfn), name, bus->devices[devfn]->name);
+        return NULL;
     }
     pci_dev->bus = bus;
     pci_dev->devfn = devfn;
     pstrcpy(pci_dev->name, sizeof(pci_dev->name), name);
-    memset(pci_dev->irq_state, 0, sizeof(pci_dev->irq_state));
+    pci_dev->irq_state = 0;
     pci_config_alloc(pci_dev);
 
-    header_type &= ~PCI_HEADER_TYPE_MULTI_FUNCTION;
-    if (header_type == PCI_HEADER_TYPE_NORMAL) {
+    if (!is_bridge) {
         pci_set_default_subsystem_id(pci_dev);
     }
     pci_init_cmask(pci_dev);
     pci_init_wmask(pci_dev);
-    if (header_type == PCI_HEADER_TYPE_BRIDGE) {
+    if (is_bridge) {
         pci_init_wmask_bridge(pci_dev);
     }
+    if (pci_init_multifunction(bus, pci_dev)) {
+        pci_config_free(pci_dev);
+        return NULL;
+    }
 
     if (!config_read)
         config_read = pci_default_read_config;
@@ -526,6 +696,13 @@ static PCIDevice *do_pci_register_device(PCIDevice *pci_dev, PCIBus *bus,
     return pci_dev;
 }
 
+static void do_pci_unregister_device(PCIDevice *pci_dev)
+{
+    qemu_free_irqs(pci_dev->irq);
+    pci_dev->bus->devices[pci_dev->devfn] = NULL;
+    pci_config_free(pci_dev);
+}
+
 PCIDevice *pci_register_device(PCIBus *bus, const char *name,
                                int instance_size, int devfn,
                                PCIConfigReadFunc *config_read,
@@ -537,11 +714,16 @@ PCIDevice *pci_register_device(PCIBus *bus, const char *name,
     pci_dev = do_pci_register_device(pci_dev, bus, name, devfn,
                                      config_read, config_write,
                                      PCI_HEADER_TYPE_NORMAL);
+    if (pci_dev == NULL) {
+        hw_error("PCI: can't register device\n");
+    }
     return pci_dev;
 }
-static target_phys_addr_t pci_to_cpu_addr(target_phys_addr_t addr)
+
+static target_phys_addr_t pci_to_cpu_addr(PCIBus *bus,
+                                          target_phys_addr_t addr)
 {
-    return addr + pci_mem_base;
+    return addr + bus->mem_base;
 }
 
 static void pci_unregister_io_regions(PCIDevice *pci_dev)
@@ -556,9 +738,10 @@ static void pci_unregister_io_regions(PCIDevice *pci_dev)
         if (r->type == PCI_BASE_ADDRESS_SPACE_IO) {
             isa_unassign_ioport(r->addr, r->filtered_size);
         } else {
-            cpu_register_physical_memory(pci_to_cpu_addr(r->addr),
-                                                     r->filtered_size,
-                                                     IO_MEM_UNASSIGNED);
+            cpu_register_physical_memory(pci_to_cpu_addr(pci_dev->bus,
+                                                         r->addr),
+                                         r->filtered_size,
+                                         IO_MEM_UNASSIGNED);
         }
     }
 }
@@ -575,24 +758,21 @@ static int pci_unregister_device(DeviceState *dev)
         return ret;
 
     pci_unregister_io_regions(pci_dev);
-
-    qemu_free_irqs(pci_dev->irq);
-    pci_dev->bus->devices[pci_dev->devfn] = NULL;
-    pci_config_free(pci_dev);
+    pci_del_option_rom(pci_dev);
+    do_pci_unregister_device(pci_dev);
     return 0;
 }
 
 void pci_register_bar(PCIDevice *pci_dev, int region_num,
-                            pcibus_t size, int type,
+                            pcibus_t size, uint8_t type,
                             PCIMapIORegionFunc *map_func)
 {
     PCIIORegion *r;
     uint32_t addr;
-    pcibus_t wmask;
-
-    if ((unsigned int)region_num >= PCI_NUM_REGIONS)
-        return;
+    uint64_t wmask;
 
+    assert(region_num >= 0);
+    assert(region_num < PCI_NUM_REGIONS);
     if (size & (size-1)) {
         fprintf(stderr, "ERROR: PCI region size must be pow2 "
                     "type=0x%x, size=0x%"FMT_PCIBUS"\n", type, size);
@@ -623,71 +803,6 @@ void pci_register_bar(PCIDevice *pci_dev, int region_num,
     }
 }
 
-static uint32_t pci_config_get_io_base(PCIDevice *d,
-                                       uint32_t base, uint32_t base_upper16)
-{
-    uint32_t val;
-
-    val = ((uint32_t)d->config[base] & PCI_IO_RANGE_MASK) << 8;
-    if (d->config[base] & PCI_IO_RANGE_TYPE_32) {
-        val |= (uint32_t)pci_get_word(d->config + PCI_IO_BASE_UPPER16) << 16;
-    }
-    return val;
-}
-
-static uint64_t pci_config_get_memory_base(PCIDevice *d, uint32_t base)
-{
-    return ((uint64_t)pci_get_word(d->config + base) & PCI_MEMORY_RANGE_MASK)
-        << 16;
-}
-
-static uint64_t pci_config_get_pref_base(PCIDevice *d,
-                                         uint32_t base, uint32_t upper)
-{
-    uint64_t val;
-    val = ((uint64_t)pci_get_word(d->config + base) &
-           PCI_PREF_RANGE_MASK) << 16;
-    val |= (uint64_t)pci_get_long(d->config + upper) << 32;
-    return val;
-}
-
-static pcibus_t pci_bridge_get_base(PCIDevice *bridge, uint8_t type)
-{
-    pcibus_t base;
-    if (type & PCI_BASE_ADDRESS_SPACE_IO) {
-        base = pci_config_get_io_base(bridge,
-                                      PCI_IO_BASE, PCI_IO_BASE_UPPER16);
-    } else {
-        if (type & PCI_BASE_ADDRESS_MEM_PREFETCH) {
-            base = pci_config_get_pref_base(
-                bridge, PCI_PREF_MEMORY_BASE, PCI_PREF_BASE_UPPER32);
-        } else {
-            base = pci_config_get_memory_base(bridge, PCI_MEMORY_BASE);
-        }
-    }
-
-    return base;
-}
-
-static pcibus_t pci_bridge_get_limit(PCIDevice *bridge, uint8_t type)
-{
-    pcibus_t limit;
-    if (type & PCI_BASE_ADDRESS_SPACE_IO) {
-        limit = pci_config_get_io_base(bridge,
-                                      PCI_IO_LIMIT, PCI_IO_LIMIT_UPPER16);
-        limit |= 0xfff;         /* PCI bridge spec 3.2.5.6. */
-    } else {
-        if (type & PCI_BASE_ADDRESS_MEM_PREFETCH) {
-            limit = pci_config_get_pref_base(
-                bridge, PCI_PREF_MEMORY_LIMIT, PCI_PREF_LIMIT_UPPER32);
-        } else {
-            limit = pci_config_get_memory_base(bridge, PCI_MEMORY_LIMIT);
-        }
-        limit |= 0xfffff;       /* PCI bridge spec 3.2.5.{1, 8}. */
-    }
-    return limit;
-}
-
 static void pci_bridge_filter(PCIDevice *d, pcibus_t *addr, pcibus_t *size,
                               uint8_t type)
 {
@@ -713,13 +828,14 @@ static void pci_bridge_filter(PCIDevice *d, pcibus_t *addr, pcibus_t *size,
     }
 
     if (base > limit) {
-    no_map:
-        *addr = PCI_BAR_UNMAPPED;
-        *size = 0;
-    } else {
-        *addr = base;
-        *size = limit - base + 1;
+        goto no_map;
     }
+    *addr = base;
+    *size = limit - base + 1;
+    return;
+no_map:
+    *addr = PCI_BAR_UNMAPPED;
+    *size = 0;
 }
 
 static pcibus_t pci_bar_address(PCIDevice *d,
@@ -825,7 +941,7 @@ static void pci_update_mappings(PCIDevice *d)
                     isa_unassign_ioport(r->addr, r->filtered_size);
                 }
             } else {
-                cpu_register_physical_memory(pci_to_cpu_addr(r->addr),
+                cpu_register_physical_memory(pci_to_cpu_addr(d->bus, r->addr),
                                              r->filtered_size,
                                              IO_MEM_UNASSIGNED);
                 qemu_unregister_coalesced_mmio(r->addr, r->filtered_size);
@@ -841,11 +957,35 @@ static void pci_update_mappings(PCIDevice *d)
              * Teach them such cases, such that filtered_size < size and
              * addr & (size - 1) != 0.
              */
-            r->map_func(d, i, r->addr, r->filtered_size, r->type);
+            if (r->type & PCI_BASE_ADDRESS_SPACE_IO) {
+                r->map_func(d, i, r->addr, r->filtered_size, r->type);
+            } else {
+                r->map_func(d, i, pci_to_cpu_addr(d->bus, r->addr),
+                            r->filtered_size, r->type);
+            }
         }
     }
 }
 
+static inline int pci_irq_disabled(PCIDevice *d)
+{
+    return pci_get_word(d->config + PCI_COMMAND) & PCI_COMMAND_INTX_DISABLE;
+}
+
+/* Called after interrupt disabled field update in config space,
+ * assert/deassert interrupts if necessary.
+ * Gets original interrupt disable bit value (before update). */
+static void pci_update_irq_disabled(PCIDevice *d, int was_irq_disabled)
+{
+    int i, disabled = pci_irq_disabled(d);
+    if (disabled == was_irq_disabled)
+        return;
+    for (i = 0; i < PCI_NUM_PINS; ++i) {
+        int state = pci_irq_state(d, i);
+        pci_change_irq_level(d, i, disabled ? -state : state);
+    }
+}
+
 uint32_t pci_default_read_config(PCIDevice *d,
                                  uint32_t address, int len)
 {
@@ -858,18 +998,24 @@ uint32_t pci_default_read_config(PCIDevice *d,
 
 void pci_default_write_config(PCIDevice *d, uint32_t addr, uint32_t val, int l)
 {
-    int i;
+    int i, was_irq_disabled = pci_irq_disabled(d);
     uint32_t config_size = pci_config_size(d);
 
     for (i = 0; i < l && addr + i < config_size; val >>= 8, ++i) {
         uint8_t wmask = d->wmask[addr + i];
+        uint8_t w1cmask = d->w1cmask[addr + i];
+        assert(!(wmask & w1cmask));
         d->config[addr + i] = (d->config[addr + i] & ~wmask) | (val & wmask);
+        d->config[addr + i] &= ~(val & w1cmask); /* W1C: Write 1 to Clear */
     }
     if (ranges_overlap(addr, l, PCI_BASE_ADDRESS_0, 24) ||
         ranges_overlap(addr, l, PCI_ROM_ADDRESS, 4) ||
         ranges_overlap(addr, l, PCI_ROM_ADDRESS1, 4) ||
         range_covers_byte(addr, l, PCI_COMMAND))
         pci_update_mappings(d);
+
+    if (range_covers_byte(addr, l, PCI_COMMAND))
+        pci_update_irq_disabled(d, was_irq_disabled);
 }
 
 /***********************************************************/
@@ -879,23 +1025,34 @@ void pci_default_write_config(PCIDevice *d, uint32_t addr, uint32_t val, int l)
 static void pci_set_irq(void *opaque, int irq_num, int level)
 {
     PCIDevice *pci_dev = opaque;
-    PCIBus *bus;
     int change;
 
-    change = level - pci_dev->irq_state[irq_num];
+    change = level - pci_irq_state(pci_dev, irq_num);
     if (!change)
         return;
 
-    pci_dev->irq_state[irq_num] = level;
-    for (;;) {
-        bus = pci_dev->bus;
-        irq_num = bus->map_irq(pci_dev, irq_num);
-        if (bus->set_irq)
-            break;
-        pci_dev = bus->parent_dev;
+    pci_set_irq_state(pci_dev, irq_num, level);
+    pci_update_irq_status(pci_dev);
+    if (pci_irq_disabled(pci_dev))
+        return;
+    pci_change_irq_level(pci_dev, irq_num, change);
+}
+
+bool pci_msi_enabled(PCIDevice *dev)
+{
+    return msix_enabled(dev) || msi_enabled(dev);
+}
+
+void pci_msi_notify(PCIDevice *dev, unsigned int vector)
+{
+    if (msix_enabled(dev)) {
+        msix_notify(dev, vector);
+    } else if (msi_enabled(dev)) {
+        msi_notify(dev, vector);
+    } else {
+        /* MSI/MSI-X must be enabled */
+        abort();
     }
-    bus->irq_count[irq_num] += change;
-    bus->set_irq(bus->irq_opaque, irq_num, bus->irq_count[irq_num] != 0);
 }
 
 /***********************************************************/
@@ -946,119 +1103,300 @@ static const pci_class_desc pci_class_descriptions[] =
     { 0, NULL}
 };
 
-static void pci_info_device(PCIBus *bus, PCIDevice *d)
+static void pci_for_each_device_under_bus(PCIBus *bus,
+                                          void (*fn)(PCIBus *b, PCIDevice *d))
 {
-    Monitor *mon = cur_mon;
-    int i, class;
-    PCIIORegion *r;
-    const pci_class_desc *desc;
+    PCIDevice *d;
+    int devfn;
 
-    monitor_printf(mon, "  Bus %2d, device %3d, function %d:\n",
-                   pci_bus_num(d->bus),
-                   PCI_SLOT(d->devfn), PCI_FUNC(d->devfn));
-    class = pci_get_word(d->config + PCI_CLASS_DEVICE);
+    for(devfn = 0; devfn < ARRAY_SIZE(bus->devices); devfn++) {
+        d = bus->devices[devfn];
+        if (d) {
+            fn(bus, d);
+        }
+    }
+}
+
+void pci_for_each_device(PCIBus *bus, int bus_num,
+                         void (*fn)(PCIBus *b, PCIDevice *d))
+{
+    bus = pci_find_bus(bus, bus_num);
+
+    if (bus) {
+        pci_for_each_device_under_bus(bus, fn);
+    }
+}
+
+static void pci_device_print(Monitor *mon, QDict *device)
+{
+    QDict *qdict;
+    QListEntry *entry;
+    uint64_t addr, size;
+
+    monitor_printf(mon, "  Bus %2" PRId64 ", ", qdict_get_int(device, "bus"));
+    monitor_printf(mon, "device %3" PRId64 ", function %" PRId64 ":\n",
+                        qdict_get_int(device, "slot"),
+                        qdict_get_int(device, "function"));
     monitor_printf(mon, "    ");
-    desc = pci_class_descriptions;
-    while (desc->desc && class != desc->class)
-        desc++;
-    if (desc->desc) {
-        monitor_printf(mon, "%s", desc->desc);
+
+    qdict = qdict_get_qdict(device, "class_info");
+    if (qdict_haskey(qdict, "desc")) {
+        monitor_printf(mon, "%s", qdict_get_str(qdict, "desc"));
     } else {
-        monitor_printf(mon, "Class %04x", class);
+        monitor_printf(mon, "Class %04" PRId64, qdict_get_int(qdict, "class"));
     }
-    monitor_printf(mon, ": PCI device %04x:%04x\n",
-           pci_get_word(d->config + PCI_VENDOR_ID),
-           pci_get_word(d->config + PCI_DEVICE_ID));
 
-    if (d->config[PCI_INTERRUPT_PIN] != 0) {
-        monitor_printf(mon, "      IRQ %d.\n",
-                       d->config[PCI_INTERRUPT_LINE]);
+    qdict = qdict_get_qdict(device, "id");
+    monitor_printf(mon, ": PCI device %04" PRIx64 ":%04" PRIx64 "\n",
+                        qdict_get_int(qdict, "device"),
+                        qdict_get_int(qdict, "vendor"));
+
+    if (qdict_haskey(device, "irq")) {
+        monitor_printf(mon, "      IRQ %" PRId64 ".\n",
+                            qdict_get_int(device, "irq"));
     }
-    if (class == 0x0604) {
-        uint64_t base;
-        uint64_t limit;
 
-        monitor_printf(mon, "      BUS %d.\n", d->config[0x19]);
-        monitor_printf(mon, "      secondary bus %d.\n",
-                       d->config[PCI_SECONDARY_BUS]);
-        monitor_printf(mon, "      subordinate bus %d.\n",
-                       d->config[PCI_SUBORDINATE_BUS]);
+    if (qdict_haskey(device, "pci_bridge")) {
+        QDict *info;
+
+        qdict = qdict_get_qdict(device, "pci_bridge");
+
+        info = qdict_get_qdict(qdict, "bus");
+        monitor_printf(mon, "      BUS %" PRId64 ".\n",
+                            qdict_get_int(info, "number"));
+        monitor_printf(mon, "      secondary bus %" PRId64 ".\n",
+                            qdict_get_int(info, "secondary"));
+        monitor_printf(mon, "      subordinate bus %" PRId64 ".\n",
+                            qdict_get_int(info, "subordinate"));
 
-        base = pci_bridge_get_base(d, PCI_BASE_ADDRESS_SPACE_IO);
-        limit = pci_bridge_get_limit(d, PCI_BASE_ADDRESS_SPACE_IO);
+        info = qdict_get_qdict(qdict, "io_range");
         monitor_printf(mon, "      IO range [0x%04"PRIx64", 0x%04"PRIx64"]\n",
-                       base, limit);
+                       qdict_get_int(info, "base"),
+                       qdict_get_int(info, "limit"));
 
-        base = pci_bridge_get_base(d, PCI_BASE_ADDRESS_SPACE_MEMORY);
-        limit= pci_bridge_get_limit(d, PCI_BASE_ADDRESS_SPACE_MEMORY);
+        info = qdict_get_qdict(qdict, "memory_range");
         monitor_printf(mon,
                        "      memory range [0x%08"PRIx64", 0x%08"PRIx64"]\n",
-                       base, limit);
+                       qdict_get_int(info, "base"),
+                       qdict_get_int(info, "limit"));
 
-        base = pci_bridge_get_base(d, PCI_BASE_ADDRESS_SPACE_MEMORY |
-                                   PCI_BASE_ADDRESS_MEM_PREFETCH);
-        limit = pci_bridge_get_limit(d, PCI_BASE_ADDRESS_SPACE_MEMORY |
-                                     PCI_BASE_ADDRESS_MEM_PREFETCH);
+        info = qdict_get_qdict(qdict, "prefetchable_range");
         monitor_printf(mon, "      prefetchable memory range "
-                       "[0x%08"PRIx64", 0x%08"PRIx64"]\n", base, limit);
+                       "[0x%08"PRIx64", 0x%08"PRIx64"]\n",
+                       qdict_get_int(info, "base"),
+        qdict_get_int(info, "limit"));
     }
-    for(i = 0;i < PCI_NUM_REGIONS; i++) {
-        r = &d->io_regions[i];
-        if (r->size != 0) {
-            monitor_printf(mon, "      BAR%d: ", i);
-            if (r->type & PCI_BASE_ADDRESS_SPACE_IO) {
-                monitor_printf(mon, "I/O at 0x%04"FMT_PCIBUS
-                               " [0x%04"FMT_PCIBUS"].\n",
-                               r->addr, r->addr + r->size - 1);
-            } else {
-                const char *type = r->type & PCI_BASE_ADDRESS_MEM_TYPE_64 ?
-                    "64 bit" : "32 bit";
-                const char *prefetch =
-                    r->type & PCI_BASE_ADDRESS_MEM_PREFETCH ?
-                    " prefetchable" : "";
 
-                monitor_printf(mon, "%s%s memory at 0x%08"FMT_PCIBUS
+    QLIST_FOREACH_ENTRY(qdict_get_qlist(device, "regions"), entry) {
+        qdict = qobject_to_qdict(qlist_entry_obj(entry));
+        monitor_printf(mon, "      BAR%d: ", (int) qdict_get_int(qdict, "bar"));
+
+        addr = qdict_get_int(qdict, "address");
+        size = qdict_get_int(qdict, "size");
+
+        if (!strcmp(qdict_get_str(qdict, "type"), "io")) {
+            monitor_printf(mon, "I/O at 0x%04"FMT_PCIBUS
+                                " [0x%04"FMT_PCIBUS"].\n",
+                                addr, addr + size - 1);
+        } else {
+            monitor_printf(mon, "%d bit%s memory at 0x%08"FMT_PCIBUS
                                " [0x%08"FMT_PCIBUS"].\n",
-                               type, prefetch,
-                               r->addr, r->addr + r->size - 1);
+                                qdict_get_bool(qdict, "mem_type_64") ? 64 : 32,
+                                qdict_get_bool(qdict, "prefetch") ?
+                                " prefetchable" : "", addr, addr + size - 1);
+        }
+    }
+
+    monitor_printf(mon, "      id \"%s\"\n", qdict_get_str(device, "qdev_id"));
+
+    if (qdict_haskey(device, "pci_bridge")) {
+        qdict = qdict_get_qdict(device, "pci_bridge");
+        if (qdict_haskey(qdict, "devices")) {
+            QListEntry *dev;
+            QLIST_FOREACH_ENTRY(qdict_get_qlist(qdict, "devices"), dev) {
+                pci_device_print(mon, qobject_to_qdict(qlist_entry_obj(dev)));
             }
         }
     }
-    monitor_printf(mon, "      id \"%s\"\n", d->qdev.id ? d->qdev.id : "");
-    if (class == 0x0604 && d->config[0x19] != 0) {
-        pci_for_each_device(bus, d->config[0x19], pci_info_device);
+}
+
+void do_pci_info_print(Monitor *mon, const QObject *data)
+{
+    QListEntry *bus, *dev;
+
+    QLIST_FOREACH_ENTRY(qobject_to_qlist(data), bus) {
+        QDict *qdict = qobject_to_qdict(qlist_entry_obj(bus));
+        QLIST_FOREACH_ENTRY(qdict_get_qlist(qdict, "devices"), dev) {
+            pci_device_print(mon, qobject_to_qdict(qlist_entry_obj(dev)));
+        }
     }
 }
 
-static void pci_for_each_device_under_bus(PCIBus *bus,
-                                          void (*fn)(PCIBus *b, PCIDevice *d))
+static QObject *pci_get_dev_class(const PCIDevice *dev)
+{
+    int class;
+    const pci_class_desc *desc;
+
+    class = pci_get_word(dev->config + PCI_CLASS_DEVICE);
+    desc = pci_class_descriptions;
+    while (desc->desc && class != desc->class)
+        desc++;
+
+    if (desc->desc) {
+        return qobject_from_jsonf("{ 'desc': %s, 'class': %d }",
+                                  desc->desc, class);
+    } else {
+        return qobject_from_jsonf("{ 'class': %d }", class);
+    }
+}
+
+static QObject *pci_get_dev_id(const PCIDevice *dev)
+{
+    return qobject_from_jsonf("{ 'device': %d, 'vendor': %d }",
+                              pci_get_word(dev->config + PCI_VENDOR_ID),
+                              pci_get_word(dev->config + PCI_DEVICE_ID));
+}
+
+static QObject *pci_get_regions_list(const PCIDevice *dev)
+{
+    int i;
+    QList *regions_list;
+
+    regions_list = qlist_new();
+
+    for (i = 0; i < PCI_NUM_REGIONS; i++) {
+        QObject *obj;
+        const PCIIORegion *r = &dev->io_regions[i];
+
+        if (!r->size) {
+            continue;
+        }
+
+        if (r->type & PCI_BASE_ADDRESS_SPACE_IO) {
+            obj = qobject_from_jsonf("{ 'bar': %d, 'type': 'io', "
+                                     "'address': %" PRId64 ", "
+                                     "'size': %" PRId64 " }",
+                                     i, r->addr, r->size);
+        } else {
+            int mem_type_64 = r->type & PCI_BASE_ADDRESS_MEM_TYPE_64;
+
+            obj = qobject_from_jsonf("{ 'bar': %d, 'type': 'memory', "
+                                     "'mem_type_64': %i, 'prefetch': %i, "
+                                     "'address': %" PRId64 ", "
+                                     "'size': %" PRId64 " }",
+                                     i, mem_type_64,
+                                     r->type & PCI_BASE_ADDRESS_MEM_PREFETCH,
+                                     r->addr, r->size);
+        }
+
+        qlist_append_obj(regions_list, obj);
+    }
+
+    return QOBJECT(regions_list);
+}
+
+static QObject *pci_get_devices_list(PCIBus *bus, int bus_num);
+
+static QObject *pci_get_dev_dict(PCIDevice *dev, PCIBus *bus, int bus_num)
+{
+    uint8_t type;
+    QObject *obj;
+
+    obj = qobject_from_jsonf("{ 'bus': %d, 'slot': %d, 'function': %d,"                                       "'class_info': %p, 'id': %p, 'regions': %p,"
+                              " 'qdev_id': %s }",
+                              bus_num,
+                              PCI_SLOT(dev->devfn), PCI_FUNC(dev->devfn),
+                              pci_get_dev_class(dev), pci_get_dev_id(dev),
+                              pci_get_regions_list(dev),
+                              dev->qdev.id ? dev->qdev.id : "");
+
+    if (dev->config[PCI_INTERRUPT_PIN] != 0) {
+        QDict *qdict = qobject_to_qdict(obj);
+        qdict_put(qdict, "irq", qint_from_int(dev->config[PCI_INTERRUPT_LINE]));
+    }
+
+    type = dev->config[PCI_HEADER_TYPE] & ~PCI_HEADER_TYPE_MULTI_FUNCTION;
+    if (type == PCI_HEADER_TYPE_BRIDGE) {
+        QDict *qdict;
+        QObject *pci_bridge;
+
+        pci_bridge = qobject_from_jsonf("{ 'bus': "
+        "{ 'number': %d, 'secondary': %d, 'subordinate': %d }, "
+        "'io_range': { 'base': %" PRId64 ", 'limit': %" PRId64 "}, "
+        "'memory_range': { 'base': %" PRId64 ", 'limit': %" PRId64 "}, "
+        "'prefetchable_range': { 'base': %" PRId64 ", 'limit': %" PRId64 "} }",
+        dev->config[PCI_PRIMARY_BUS], dev->config[PCI_SECONDARY_BUS],
+        dev->config[PCI_SUBORDINATE_BUS],
+        pci_bridge_get_base(dev, PCI_BASE_ADDRESS_SPACE_IO),
+        pci_bridge_get_limit(dev, PCI_BASE_ADDRESS_SPACE_IO),
+        pci_bridge_get_base(dev, PCI_BASE_ADDRESS_SPACE_MEMORY),
+        pci_bridge_get_limit(dev, PCI_BASE_ADDRESS_SPACE_MEMORY),
+        pci_bridge_get_base(dev, PCI_BASE_ADDRESS_SPACE_MEMORY |
+                               PCI_BASE_ADDRESS_MEM_PREFETCH),
+        pci_bridge_get_limit(dev, PCI_BASE_ADDRESS_SPACE_MEMORY |
+                                PCI_BASE_ADDRESS_MEM_PREFETCH));
+
+        if (dev->config[PCI_SECONDARY_BUS] != 0) {
+            PCIBus *child_bus = pci_find_bus(bus, dev->config[PCI_SECONDARY_BUS]);
+
+            if (child_bus) {
+                qdict = qobject_to_qdict(pci_bridge);
+                qdict_put_obj(qdict, "devices",
+                              pci_get_devices_list(child_bus,
+                                                   dev->config[PCI_SECONDARY_BUS]));
+            }
+        }
+        qdict = qobject_to_qdict(obj);
+        qdict_put_obj(qdict, "pci_bridge", pci_bridge);
+    }
+
+    return obj;
+}
+
+static QObject *pci_get_devices_list(PCIBus *bus, int bus_num)
 {
-    PCIDevice *d;
     int devfn;
+    PCIDevice *dev;
+    QList *dev_list;
 
-    for(devfn = 0; devfn < ARRAY_SIZE(bus->devices); devfn++) {
-        d = bus->devices[devfn];
-        if (d)
-            fn(bus, d);
+    dev_list = qlist_new();
+
+    for (devfn = 0; devfn < ARRAY_SIZE(bus->devices); devfn++) {
+        dev = bus->devices[devfn];
+        if (dev) {
+            qlist_append_obj(dev_list, pci_get_dev_dict(dev, bus, bus_num));
+        }
     }
+
+    return QOBJECT(dev_list);
 }
 
-void pci_for_each_device(PCIBus *bus, int bus_num,
-                         void (*fn)(PCIBus *b, PCIDevice *d))
+static QObject *pci_get_bus_dict(PCIBus *bus, int bus_num)
 {
     bus = pci_find_bus(bus, bus_num);
-
     if (bus) {
-        pci_for_each_device_under_bus(bus, fn);
+        return qobject_from_jsonf("{ 'bus': %d, 'devices': %p }",
+                                  bus_num, pci_get_devices_list(bus, bus_num));
     }
+
+    return NULL;
 }
 
-void pci_info(Monitor *mon)
+void do_pci_info(Monitor *mon, QObject **ret_data)
 {
+    QList *bus_list;
     struct PCIHostBus *host;
+
+    bus_list = qlist_new();
+
     QLIST_FOREACH(host, &host_buses, next) {
-        pci_for_each_device(host->bus, 0, pci_info_device);
+        QObject *obj = pci_get_bus_dict(host->bus, 0);
+        if (obj) {
+            qlist_append_obj(bus_list, obj);
+        }
     }
+
+    *ret_data = QOBJECT(bus_list);
 }
 
 static const char * const pci_nic_models[] = {
@@ -1103,15 +1441,13 @@ PCIDevice *pci_nic_init(NICInfo *nd, const char *default_model,
 
     bus = pci_get_bus_devfn(&devfn, devaddr);
     if (!bus) {
-        qemu_error("Invalid PCI device address %s for device %s\n",
-                   devaddr, pci_nic_names[i]);
+        error_report("Invalid PCI device address %s for device %s",
+                     devaddr, pci_nic_names[i]);
         return NULL;
     }
 
     pci_dev = pci_create(bus, devfn, pci_nic_names[i]);
     dev = &pci_dev->qdev;
-    if (nd->name)
-        dev->id = qemu_strdup(nd->name);
     qdev_set_nic_properties(dev, nd);
     if (qdev_init(dev) < 0)
         return NULL;
@@ -1132,20 +1468,12 @@ PCIDevice *pci_nic_init_nofail(NICInfo *nd, const char *default_model,
     return res;
 }
 
-typedef struct {
-    PCIDevice dev;
-    PCIBus bus;
-    uint32_t vid;
-    uint32_t did;
-} PCIBridge;
-
-
 static void pci_bridge_update_mappings_fn(PCIBus *b, PCIDevice *d)
 {
     pci_update_mappings(d);
 }
 
-static void pci_bridge_update_mappings(PCIBus *b)
+void pci_bridge_update_mappings(PCIBus *b)
 {
     PCIBus *child;
 
@@ -1156,39 +1484,33 @@ static void pci_bridge_update_mappings(PCIBus *b)
     }
 }
 
-static void pci_bridge_write_config(PCIDevice *d,
-                             uint32_t address, uint32_t val, int len)
-{
-    pci_default_write_config(d, address, val, len);
-
-    if (/* io base/limit */
-        ranges_overlap(address, len, PCI_IO_BASE, 2) ||
-
-        /* memory base/limit, prefetchable base/limit and
-           io base/limit upper 16 */
-        ranges_overlap(address, len, PCI_MEMORY_BASE, 20)) {
-        pci_bridge_update_mappings(d->bus);
-    }
-}
-
 PCIBus *pci_find_bus(PCIBus *bus, int bus_num)
 {
     PCIBus *sec;
 
-    if (!bus)
+    if (!bus) {
         return NULL;
+    }
 
     if (pci_bus_num(bus) == bus_num) {
         return bus;
     }
 
     /* try child bus */
-    QLIST_FOREACH(sec, &bus->child, sibling) {
-
-        if (!bus->parent_dev /* pci host bridge */
-            || (pci_bus_num(sec) <= bus_num &&
-                bus->parent_dev->config[PCI_SUBORDINATE_BUS])) {
-            return pci_find_bus(sec, bus_num);
+    if (!bus->parent_dev /* host pci bridge */ ||
+        (bus->parent_dev->config[PCI_SECONDARY_BUS] < bus_num &&
+         bus_num <= bus->parent_dev->config[PCI_SUBORDINATE_BUS])) {
+        for (; bus; bus = sec) {
+            QLIST_FOREACH(sec, &bus->child, sibling) {
+                assert(sec->parent_dev);
+                if (sec->parent_dev->config[PCI_SECONDARY_BUS] == bus_num) {
+                    return sec;
+                }
+                if (sec->parent_dev->config[PCI_SECONDARY_BUS] < bus_num &&
+                    bus_num <= sec->parent_dev->config[PCI_SUBORDINATE_BUS]) {
+                    break;
+                }
+            }
         }
     }
 
@@ -1205,65 +1527,6 @@ PCIDevice *pci_find_device(PCIBus *bus, int bus_num, int slot, int function)
     return bus->devices[PCI_DEVFN(slot, function)];
 }
 
-static int pci_bridge_initfn(PCIDevice *dev)
-{
-    PCIBridge *s = DO_UPCAST(PCIBridge, dev, dev);
-
-    pci_config_set_vendor_id(s->dev.config, s->vid);
-    pci_config_set_device_id(s->dev.config, s->did);
-
-    /* TODO: intial value
-     * command register:
-     * According to PCI bridge spec, after reset
-     *   bus master bit is off
-     *   memory space enable bit is off
-     * According to manual (805-1251.pdf).(See abp_pbi.c for its links.)
-     *   the reset value should be zero unless the boot pin is tied high
-     *   (which is tru) and thus it should be PCI_COMMAND_MEMORY.
-     *
-     * For now, don't touch the value.
-     * Later command register will be set to zero and apb_pci.c will
-     * override the value.
-     * Same for latency timer, and multi function bit of header type.
-     */
-    pci_set_word(dev->config + PCI_COMMAND,
-                 PCI_COMMAND_MEMORY | PCI_COMMAND_MASTER);
-
-    pci_set_word(dev->config + PCI_STATUS,
-                 PCI_STATUS_66MHZ | PCI_STATUS_FAST_BACK);
-    pci_config_set_class(dev->config, PCI_CLASS_BRIDGE_PCI);
-    dev->config[PCI_LATENCY_TIMER] = 0x10;
-    dev->config[PCI_HEADER_TYPE] =
-        PCI_HEADER_TYPE_MULTI_FUNCTION | PCI_HEADER_TYPE_BRIDGE;
-    pci_set_word(dev->config + PCI_SEC_STATUS,
-                 PCI_STATUS_66MHZ | PCI_STATUS_FAST_BACK);
-    return 0;
-}
-
-static int pci_bridge_exitfn(PCIDevice *pci_dev)
-{
-    PCIBridge *s = DO_UPCAST(PCIBridge, dev, pci_dev);
-    PCIBus *bus = &s->bus;
-    pci_unregister_secondary_bus(bus);
-    return 0;
-}
-
-PCIBus *pci_bridge_init(PCIBus *bus, int devfn, uint16_t vid, uint16_t did,
-                        pci_map_irq_fn map_irq, const char *name)
-{
-    PCIDevice *dev;
-    PCIBridge *s;
-
-    dev = pci_create(bus, devfn, "pci-bridge");
-    qdev_prop_set_uint32(&dev->qdev, "vendorid", vid);
-    qdev_prop_set_uint32(&dev->qdev, "deviceid", did);
-    qdev_init_nofail(&dev->qdev);
-
-    s = DO_UPCAST(PCIBridge, dev, dev);
-    pci_register_secondary_bus(bus, &s->bus, &s->dev, map_irq, name);
-    return &s->bus;
-}
-
 static int pci_qdev_init(DeviceState *qdev, DeviceInfo *base)
 {
     PCIDevice *pci_dev = (PCIDevice *)qdev;
@@ -1280,12 +1543,29 @@ static int pci_qdev_init(DeviceState *qdev, DeviceInfo *base)
     devfn = pci_dev->devfn;
     pci_dev = do_pci_register_device(pci_dev, bus, base->name, devfn,
                                      info->config_read, info->config_write,
-                                     info->header_type);
+                                     info->is_bridge);
+    if (pci_dev == NULL)
+        return -1;
     rc = info->init(pci_dev);
-    if (rc != 0)
+    if (rc != 0) {
+        do_pci_unregister_device(pci_dev);
         return rc;
-    if (qdev->hotplugged)
-        bus->hotplug(pci_dev, 1);
+    }
+
+    /* rom loading */
+    if (pci_dev->romfile == NULL && info->romfile != NULL)
+        pci_dev->romfile = qemu_strdup(info->romfile);
+    pci_add_option_rom(pci_dev);
+
+    if (bus->hotplug) {
+        /* lower layer must check qdev->hotplugged */
+        rc = bus->hotplug(bus->hotplug_qdev, pci_dev, 1);
+        if (rc != 0) {
+            int r = pci_unregister_device(&pci_dev->qdev);
+            assert(!r);
+            return rc;
+        }
+    }
     return 0;
 }
 
@@ -1293,8 +1573,7 @@ static int pci_unplug_device(DeviceState *qdev)
 {
     PCIDevice *dev = DO_UPCAST(PCIDevice, qdev, qdev);
 
-    dev->bus->hotplug(dev, 0);
-    return 0;
+    return dev->bus->hotplug(dev->bus->hotplug_qdev, dev, 0);
 }
 
 void pci_qdev_register(PCIDeviceInfo *info)
@@ -1314,22 +1593,36 @@ void pci_qdev_register_many(PCIDeviceInfo *info)
     }
 }
 
-PCIDevice *pci_create(PCIBus *bus, int devfn, const char *name)
+PCIDevice *pci_create_multifunction(PCIBus *bus, int devfn, bool multifunction,
+                                    const char *name)
 {
     DeviceState *dev;
 
     dev = qdev_create(&bus->qbus, name);
     qdev_prop_set_uint32(dev, "addr", devfn);
+    qdev_prop_set_bit(dev, "multifunction", multifunction);
     return DO_UPCAST(PCIDevice, qdev, dev);
 }
 
-PCIDevice *pci_create_simple(PCIBus *bus, int devfn, const char *name)
+PCIDevice *pci_create_simple_multifunction(PCIBus *bus, int devfn,
+                                           bool multifunction,
+                                           const char *name)
 {
-    PCIDevice *dev = pci_create(bus, devfn, name);
+    PCIDevice *dev = pci_create_multifunction(bus, devfn, multifunction, name);
     qdev_init_nofail(&dev->qdev);
     return dev;
 }
 
+PCIDevice *pci_create(PCIBus *bus, int devfn, const char *name)
+{
+    return pci_create_multifunction(bus, devfn, false, name);
+}
+
+PCIDevice *pci_create_simple(PCIBus *bus, int devfn, const char *name)
+{
+    return pci_create_simple_multifunction(bus, devfn, false, name);
+}
+
 static int pci_find_space(PCIDevice *pdev, uint8_t size)
 {
     int config_size = pci_config_size(pdev);
@@ -1361,13 +1654,97 @@ static uint8_t pci_find_capability_list(PCIDevice *pdev, uint8_t cap_id,
     return next;
 }
 
-/* Reserve space and add capability to the linked list in pci config space */
-int pci_add_capability(PCIDevice *pdev, uint8_t cap_id, uint8_t size)
+static void pci_map_option_rom(PCIDevice *pdev, int region_num, pcibus_t addr, pcibus_t size, int type)
 {
-    uint8_t offset = pci_find_space(pdev, size);
-    uint8_t *config = pdev->config + offset;
-    if (!offset)
-        return -ENOSPC;
+    cpu_register_physical_memory(addr, size, pdev->rom_offset);
+}
+
+/* Add an option rom for the device */
+static int pci_add_option_rom(PCIDevice *pdev)
+{
+    int size;
+    char *path;
+    void *ptr;
+    char name[32];
+
+    if (!pdev->romfile)
+        return 0;
+    if (strlen(pdev->romfile) == 0)
+        return 0;
+
+    if (!pdev->rom_bar) {
+        /*
+         * Load rom via fw_cfg instead of creating a rom bar,
+         * for 0.11 compatibility.
+         */
+        int class = pci_get_word(pdev->config + PCI_CLASS_DEVICE);
+        if (class == 0x0300) {
+            rom_add_vga(pdev->romfile);
+        } else {
+            rom_add_option(pdev->romfile);
+        }
+        return 0;
+    }
+
+    path = qemu_find_file(QEMU_FILE_TYPE_BIOS, pdev->romfile);
+    if (path == NULL) {
+        path = qemu_strdup(pdev->romfile);
+    }
+
+    size = get_image_size(path);
+    if (size < 0) {
+        error_report("%s: failed to find romfile \"%s\"",
+                     __FUNCTION__, pdev->romfile);
+        return -1;
+    }
+    if (size & (size - 1)) {
+        size = 1 << qemu_fls(size);
+    }
+
+    if (pdev->qdev.info->vmsd)
+        snprintf(name, sizeof(name), "%s.rom", pdev->qdev.info->vmsd->name);
+    else
+        snprintf(name, sizeof(name), "%s.rom", pdev->qdev.info->name);
+    pdev->rom_offset = qemu_ram_alloc(&pdev->qdev, name, size);
+
+    ptr = qemu_get_ram_ptr(pdev->rom_offset);
+    load_image(path, ptr);
+    qemu_free(path);
+
+    pci_register_bar(pdev, PCI_ROM_SLOT, size,
+                     0, pci_map_option_rom);
+
+    return 0;
+}
+
+static void pci_del_option_rom(PCIDevice *pdev)
+{
+    if (!pdev->rom_offset)
+        return;
+
+    qemu_ram_free(pdev->rom_offset);
+    pdev->rom_offset = 0;
+}
+
+/*
+ * if !offset
+ * Reserve space and add capability to the linked list in pci config space
+ *
+ * if offset = 0,
+ * Find and reserve space and add capability to the linked list
+ * in pci config space */
+int pci_add_capability(PCIDevice *pdev, uint8_t cap_id,
+                       uint8_t offset, uint8_t size)
+{
+    uint8_t *config;
+    if (!offset) {
+        offset = pci_find_space(pdev, size);
+        if (!offset) {
+            return -ENOSPC;
+        }
+    }
+
+    config = pdev->config + offset;
     config[PCI_CAP_LIST_ID] = cap_id;
     config[PCI_CAP_LIST_NEXT] = pdev->config[PCI_CAPABILITY_LIST];
     pdev->config[PCI_CAPABILITY_LIST] = offset;
@@ -1389,6 +1766,7 @@ void pci_del_capability(PCIDevice *pdev, uint8_t cap_id, uint8_t size)
     pdev->config[prev] = pdev->config[offset + PCI_CAP_LIST_NEXT];
     /* Make capability writeable again */
     memset(pdev->wmask + offset, 0xff, size);
+    memset(pdev->w1cmask + offset, 0, size);
     /* Clear cmask as device-specific registers can't be checked */
     memset(pdev->cmask + offset, 0, size);
     memset(pdev->used + offset, 0, size);
@@ -1447,22 +1825,15 @@ static void pcibus_dev_print(Monitor *mon, DeviceState *dev, int indent)
     }
 }
 
-static PCIDeviceInfo bridge_info = {
-    .qdev.name    = "pci-bridge",
-    .qdev.size    = sizeof(PCIBridge),
-    .init         = pci_bridge_initfn,
-    .exit         = pci_bridge_exitfn,
-    .config_write = pci_bridge_write_config,
-    .qdev.props   = (Property[]) {
-        DEFINE_PROP_HEX32("vendorid", PCIBridge, vid, 0),
-        DEFINE_PROP_HEX32("deviceid", PCIBridge, did, 0),
-        DEFINE_PROP_END_OF_LIST(),
-    }
-};
-
-static void pci_register_devices(void)
+static char *pcibus_get_dev_path(DeviceState *dev)
 {
-    pci_qdev_register(&bridge_info);
+    PCIDevice *d = (PCIDevice *)dev;
+    char path[16];
+
+    snprintf(path, sizeof(path), "%04x:%02x:%02x.%x",
+             pci_find_domain(d->bus), d->config[PCI_SECONDARY_BUS],
+             PCI_SLOT(d->devfn), PCI_FUNC(d->devfn));
+
+    return strdup(path);
 }
 
-device_init(pci_register_devices)