qdev/pci: add pci_create_noinit()
[qemu] / hw / pci.c
index a6fb957..64d70ed 100644 (file)
--- a/hw/pci.c
+++ b/hw/pci.c
 #include "sysemu.h"
 
 //#define DEBUG_PCI
+#ifdef DEBUG_PCI
+# define PCI_DPRINTF(format, ...)       printf(format, __VA_ARGS__)
+#else
+# define PCI_DPRINTF(format, ...)       do { } while (0)
+#endif
 
 struct PCIBus {
     BusState qbus;
@@ -36,9 +41,7 @@ struct PCIBus {
     pci_set_irq_fn set_irq;
     pci_map_irq_fn map_irq;
     uint32_t config_reg; /* XXX: suppress */
-    /* low level pic */
-    SetIRQFunc *low_set_irq;
-    qemu_irq *irq_opaque;
+    void *irq_opaque;
     PCIDevice *devices[256];
     PCIDevice *parent_dev;
     PCIBus *next;
@@ -54,6 +57,10 @@ static struct BusInfo pci_bus_info = {
     .name       = "PCI",
     .size       = sizeof(PCIBus),
     .print_dev  = pcibus_dev_print,
+    .props      = (Property[]) {
+        DEFINE_PROP_PCI_DEVFN("addr", PCIDevice, devfn, -1),
+        DEFINE_PROP_END_OF_LIST()
+    }
 };
 
 static void pci_update_mappings(PCIDevice *d);
@@ -64,40 +71,21 @@ 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;
 static PCIBus *first_bus;
 
-static void pcibus_save(QEMUFile *f, void *opaque)
-{
-    PCIBus *bus = (PCIBus *)opaque;
-    int i;
-
-    qemu_put_be32(f, bus->nirq);
-    for (i = 0; i < bus->nirq; i++)
-        qemu_put_be32(f, bus->irq_count[i]);
-}
-
-static int  pcibus_load(QEMUFile *f, void *opaque, int version_id)
-{
-    PCIBus *bus = (PCIBus *)opaque;
-    int i, nirq;
-
-    if (version_id != 1)
-        return -EINVAL;
-
-    nirq = qemu_get_be32(f);
-    if (bus->nirq != nirq) {
-        fprintf(stderr, "pcibus_load: nirq mismatch: src=%d dst=%d\n",
-                nirq, bus->nirq);
-        return -EINVAL;
+static const VMStateDescription vmstate_pcibus = {
+    .name = "PCIBUS",
+    .version_id = 1,
+    .minimum_version_id = 1,
+    .minimum_version_id_old = 1,
+    .fields      = (VMStateField []) {
+        VMSTATE_INT32_EQUAL(nirq, PCIBus),
+        VMSTATE_INT32_VARRAY(irq_count, PCIBus, nirq),
+        VMSTATE_END_OF_LIST()
     }
-
-    for (i = 0; i < nirq; i++)
-        bus->irq_count[i] = qemu_get_be32(f);
-
-    return 0;
-}
+};
 
 static void pci_bus_reset(void *opaque)
 {
-    PCIBus *bus = (PCIBus *)opaque;
+    PCIBus *bus = opaque;
     int i;
 
     for (i = 0; i < bus->nirq; i++) {
@@ -112,7 +100,7 @@ static void pci_bus_reset(void *opaque)
 
 PCIBus *pci_register_bus(DeviceState *parent, const char *name,
                          pci_set_irq_fn set_irq, pci_map_irq_fn map_irq,
-                         qemu_irq *pic, int devfn_min, int nirq)
+                         void *irq_opaque, int devfn_min, int nirq)
 {
     PCIBus *bus;
     static int nbus = 0;
@@ -120,22 +108,24 @@ PCIBus *pci_register_bus(DeviceState *parent, const char *name,
     bus = FROM_QBUS(PCIBus, qbus_create(&pci_bus_info, parent, name));
     bus->set_irq = set_irq;
     bus->map_irq = map_irq;
-    bus->irq_opaque = pic;
+    bus->irq_opaque = irq_opaque;
     bus->devfn_min = devfn_min;
     bus->nirq = nirq;
     bus->irq_count = qemu_mallocz(nirq * sizeof(bus->irq_count[0]));
     bus->next = first_bus;
     first_bus = bus;
-    register_savevm("PCIBUS", nbus++, 1, pcibus_save, pcibus_load, bus);
+    vmstate_register(nbus++, &vmstate_pcibus, bus);
     qemu_register_reset(pci_bus_reset, bus);
     return bus;
 }
 
-static PCIBus *pci_register_secondary_bus(PCIDevice *dev, pci_map_irq_fn map_irq)
+static PCIBus *pci_register_secondary_bus(PCIDevice *dev,
+                                          pci_map_irq_fn map_irq,
+                                          const char *name)
 {
     PCIBus *bus;
 
-    bus = qemu_mallocz(sizeof(PCIBus));
+    bus = FROM_QBUS(PCIBus, qbus_create(&pci_bus_info, &dev->qdev, name));
     bus->map_irq = map_irq;
     bus->parent_dev = dev;
     bus->next = dev->bus->next;
@@ -148,39 +138,60 @@ int pci_bus_num(PCIBus *s)
     return s->bus_num;
 }
 
-void pci_device_save(PCIDevice *s, QEMUFile *f)
+static int get_pci_config_device(QEMUFile *f, void *pv, size_t size)
 {
+    PCIDevice *s = container_of(pv, PCIDevice, config);
+    uint8_t config[size];
     int i;
 
-    qemu_put_be32(f, 2); /* PCI device version */
-    qemu_put_buffer(f, s->config, 256);
-    for (i = 0; i < 4; i++)
-        qemu_put_be32(f, s->irq_state[i]);
-}
-
-int pci_device_load(PCIDevice *s, QEMUFile *f)
-{
-    uint8_t config[PCI_CONFIG_SPACE_SIZE];
-    uint32_t version_id;
-    int i;
-
-    version_id = qemu_get_be32(f);
-    if (version_id > 2)
-        return -EINVAL;
-    qemu_get_buffer(f, config, sizeof config);
-    for (i = 0; i < sizeof config; ++i)
+    qemu_get_buffer(f, config, size);
+    for (i = 0; i < size; ++i)
         if ((config[i] ^ s->config[i]) & s->cmask[i] & ~s->wmask[i])
             return -EINVAL;
-    memcpy(s->config, config, sizeof config);
+    memcpy(s->config, config, size);
 
     pci_update_mappings(s);
 
-    if (version_id >= 2)
-        for (i = 0; i < 4; i ++)
-            s->irq_state[i] = qemu_get_be32(f);
     return 0;
 }
 
+/* just put buffer */
+static void put_pci_config_device(QEMUFile *f, const void *pv, size_t size)
+{
+    const uint8_t *v = pv;
+    qemu_put_buffer(f, v, size);
+}
+
+static VMStateInfo vmstate_info_pci_config = {
+    .name = "pci config",
+    .get  = get_pci_config_device,
+    .put  = put_pci_config_device,
+};
+
+const VMStateDescription vmstate_pci_device = {
+    .name = "PCIDevice",
+    .version_id = 2,
+    .minimum_version_id = 1,
+    .minimum_version_id_old = 1,
+    .fields      = (VMStateField []) {
+        VMSTATE_INT32_LE(version_id, PCIDevice),
+        VMSTATE_SINGLE(config, PCIDevice, 0, vmstate_info_pci_config,
+                       typeof_field(PCIDevice,config)),
+        VMSTATE_INT32_ARRAY_V(irq_state, PCIDevice, 4, 2),
+        VMSTATE_END_OF_LIST()
+    }
+};
+
+void pci_device_save(PCIDevice *s, QEMUFile *f)
+{
+    vmstate_save_state(f, &vmstate_pci_device, s);
+}
+
+int pci_device_load(PCIDevice *s, QEMUFile *f)
+{
+    return vmstate_load_state(f, &vmstate_pci_device, s, s->version_id);
+}
+
 static int pci_set_default_subsystem_id(PCIDevice *pci_dev)
 {
     uint16_t *id;
@@ -327,6 +338,7 @@ static PCIDevice *do_pci_register_device(PCIDevice *pci_dev, PCIBus *bus,
     pci_dev->config_write = config_write;
     bus->devices[devfn] = pci_dev;
     pci_dev->irq = qemu_allocate_irqs(pci_set_irq, pci_dev, 4);
+    pci_dev->version_id = 2; /* Current pci device vmstate version */
     return pci_dev;
 }
 
@@ -548,9 +560,9 @@ void pci_data_write(void *opaque, uint32_t addr, uint32_t val, int len)
     PCIDevice *pci_dev;
     int config_addr, bus_num;
 
-#if defined(DEBUG_PCI) && 0
-    printf("pci_data_write: addr=%08x val=%08x len=%d\n",
-           addr, val, len);
+#if 0
+    PCI_DPRINTF("pci_data_write: addr=%08x val=%08x len=%d\n",
+                addr, val, len);
 #endif
     bus_num = (addr >> 16) & 0xff;
     while (s && s->bus_num != bus_num)
@@ -561,10 +573,8 @@ void pci_data_write(void *opaque, uint32_t addr, uint32_t val, int len)
     if (!pci_dev)
         return;
     config_addr = addr & 0xff;
-#if defined(DEBUG_PCI)
-    printf("pci_config_write: %s: addr=%02x val=%08x len=%d\n",
-           pci_dev->name, config_addr, val, len);
-#endif
+    PCI_DPRINTF("pci_config_write: %s: addr=%02x val=%08x len=%d\n",
+                pci_dev->name, config_addr, val, len);
     pci_dev->config_write(pci_dev, config_addr, val, len);
 }
 
@@ -599,14 +609,12 @@ uint32_t pci_data_read(void *opaque, uint32_t addr, int len)
     }
     config_addr = addr & 0xff;
     val = pci_dev->config_read(pci_dev, config_addr, len);
-#if defined(DEBUG_PCI)
-    printf("pci_config_read: %s: addr=%02x val=%08x len=%d\n",
-           pci_dev->name, config_addr, val, len);
-#endif
+    PCI_DPRINTF("pci_config_read: %s: addr=%02x val=%08x len=%d\n",
+                pci_dev->name, config_addr, val, len);
  the_end:
-#if defined(DEBUG_PCI) && 0
-    printf("pci_data_read: addr=%08x val=%08x len=%d\n",
-           addr, val, len);
+#if 0
+    PCI_DPRINTF("pci_data_read: addr=%08x val=%08x len=%d\n",
+                addr, val, len);
 #endif
     return val;
 }
@@ -617,7 +625,7 @@ uint32_t pci_data_read(void *opaque, uint32_t addr, int len)
 /* 0 <= irq_num <= 3. level must be 0 or 1 */
 static void pci_set_irq(void *opaque, int irq_num, int level)
 {
-    PCIDevice *pci_dev = (PCIDevice *)opaque;
+    PCIDevice *pci_dev = opaque;
     PCIBus *bus;
     int change;
 
@@ -728,6 +736,7 @@ static void pci_info_device(PCIDevice *d)
             }
         }
     }
+    monitor_printf(mon, "      id \"%s\"\n", d->qdev.id ? d->qdev.id : "");
     if (class == 0x0604 && d->config[0x19] != 0) {
         pci_for_each_device(d->config[0x19], pci_info_device);
     }
@@ -769,7 +778,7 @@ PCIDevice *pci_create(const char *name, const char *devaddr)
     }
 
     dev = qdev_create(&bus->qbus, name);
-    qdev_set_prop_int(dev, "devfn", devfn);
+    qdev_prop_set_uint32(dev, "addr", devfn);
     return (PCIDevice *)dev;
 }
 
@@ -812,7 +821,9 @@ PCIDevice *pci_nic_init(NICInfo *nd, const char *default_model,
         if (strcmp(nd->model, pci_nic_models[i]) == 0) {
             pci_dev = pci_create(pci_nic_names[i], devaddr);
             dev = &pci_dev->qdev;
-            qdev_set_netdev(dev, nd);
+            if (nd->id)
+                dev->id = qemu_strdup(nd->id);
+            dev->nd = nd;
             qdev_init(dev);
             nd->private = dev;
             return pci_dev;
@@ -878,11 +889,11 @@ PCIBus *pci_bridge_init(PCIBus *bus, int devfn, uint16_t vid, uint16_t did,
         PCI_HEADER_TYPE_MULTI_FUNCTION | PCI_HEADER_TYPE_BRIDGE; // header_type
     s->dev.config[0x1E] = 0xa0; // secondary status
 
-    s->bus = pci_register_secondary_bus(&s->dev, map_irq);
+    s->bus = pci_register_secondary_bus(&s->dev, map_irq, name);
     return s->bus;
 }
 
-static void pci_qdev_init(DeviceState *qdev, DeviceInfo *base)
+static int pci_qdev_init(DeviceState *qdev, DeviceInfo *base)
 {
     PCIDevice *pci_dev = (PCIDevice *)qdev;
     PCIDeviceInfo *info = container_of(base, PCIDeviceInfo, qdev);
@@ -890,11 +901,11 @@ static void pci_qdev_init(DeviceState *qdev, DeviceInfo *base)
     int devfn;
 
     bus = FROM_QBUS(PCIBus, qdev_get_parent_bus(qdev));
-    devfn = qdev_get_prop_int(qdev, "devfn", -1);
+    devfn = pci_dev->devfn;
     pci_dev = do_pci_register_device(pci_dev, bus, base->name, devfn,
                                      info->config_read, info->config_write);
     assert(pci_dev);
-    info->init(pci_dev);
+    return info->init(pci_dev);
 }
 
 void pci_qdev_register(PCIDeviceInfo *info)
@@ -912,15 +923,20 @@ void pci_qdev_register_many(PCIDeviceInfo *info)
     }
 }
 
-PCIDevice *pci_create_simple(PCIBus *bus, int devfn, const char *name)
+PCIDevice *pci_create_noinit(PCIBus *bus, int devfn, const char *name)
 {
     DeviceState *dev;
 
     dev = qdev_create(&bus->qbus, name);
-    qdev_set_prop_int(dev, "devfn", devfn);
-    qdev_init(dev);
+    qdev_prop_set_uint32(dev, "addr", devfn);
+    return DO_UPCAST(PCIDevice, qdev, dev);
+}
 
-    return (PCIDevice *)dev;
+PCIDevice *pci_create_simple(PCIBus *bus, int devfn, const char *name)
+{
+    PCIDevice *dev = pci_create_noinit(bus, devfn, name);
+    qdev_init(&dev->qdev);
+    return dev;
 }
 
 static int pci_find_space(PCIDevice *pdev, uint8_t size)