]> git.proxmox.com Git - qemu.git/blobdiff - hw/piix_pci.c
vnc_refresh: return if vd->timer is NULL
[qemu.git] / hw / piix_pci.c
index db40ed3b850acbdead329a139238f3aeb435a775..1b67475e03280f2203f23a5fa054ec4884e28f6d 100644 (file)
 #include "hw.h"
 #include "pc.h"
 #include "pci.h"
-#include "sysbus.h"
-
-typedef uint32_t pci_addr_t;
 #include "pci_host.h"
+#include "isa.h"
+#include "sysbus.h"
 
 typedef PCIHostState I440FXState;
 
-static void i440fx_addr_writel(void* opaque, uint32_t addr, uint32_t val)
-{
-    I440FXState *s = opaque;
-    s->config_reg = val;
-}
-
-static uint32_t i440fx_addr_readl(void* opaque, uint32_t addr)
-{
-    I440FXState *s = opaque;
-    return s->config_reg;
-}
+typedef struct PIIX3State {
+    PCIDevice dev;
+    int pci_irq_levels[4];
+    qemu_irq *pic;
+} PIIX3State;
+
+struct PCII440FXState {
+    PCIDevice dev;
+    target_phys_addr_t isa_page_descs[384 / 4];
+    uint8_t smm_enabled;
+    PIIX3State *piix3;
+};
 
-static void piix3_set_irq(qemu_irq *pic, int irq_num, int level);
+static void piix3_set_irq(void *opaque, int irq_num, int level);
 
 /* return the global irq number corresponding to a given device irq
    pin. We could also use the bus number to have a more precise
@@ -56,11 +56,7 @@ static int pci_slot_get_pirq(PCIDevice *pci_dev, int irq_num)
     return (irq_num + slot_addend) & 3;
 }
 
-static target_phys_addr_t isa_page_descs[384 / 4];
-static uint8_t smm_enabled;
-static int pci_irq_levels[4];
-
-static void update_pam(PCIDevice *d, uint32_t start, uint32_t end, int r)
+static void update_pam(PCII440FXState *d, uint32_t start, uint32_t end, int r)
 {
     uint32_t addr;
 
@@ -81,38 +77,38 @@ static void update_pam(PCIDevice *d, uint32_t start, uint32_t end, int r)
         /* XXX: should distinguish read/write cases */
         for(addr = start; addr < end; addr += 4096) {
             cpu_register_physical_memory(addr, 4096,
-                                         isa_page_descs[(addr - 0xa0000) >> 12]);
+                                         d->isa_page_descs[(addr - 0xa0000) >> 12]);
         }
         break;
     }
 }
 
-static void i440fx_update_memory_mappings(PCIDevice *d)
+static void i440fx_update_memory_mappings(PCII440FXState *d)
 {
     int i, r;
     uint32_t smram, addr;
 
-    update_pam(d, 0xf0000, 0x100000, (d->config[0x59] >> 4) & 3);
+    update_pam(d, 0xf0000, 0x100000, (d->dev.config[0x59] >> 4) & 3);
     for(i = 0; i < 12; i++) {
-        r = (d->config[(i >> 1) + 0x5a] >> ((i & 1) * 4)) & 3;
+        r = (d->dev.config[(i >> 1) + 0x5a] >> ((i & 1) * 4)) & 3;
         update_pam(d, 0xc0000 + 0x4000 * i, 0xc0000 + 0x4000 * (i + 1), r);
     }
-    smram = d->config[0x72];
-    if ((smm_enabled && (smram & 0x08)) || (smram & 0x40)) {
+    smram = d->dev.config[0x72];
+    if ((d->smm_enabled && (smram & 0x08)) || (smram & 0x40)) {
         cpu_register_physical_memory(0xa0000, 0x20000, 0xa0000);
     } else {
         for(addr = 0xa0000; addr < 0xc0000; addr += 4096) {
             cpu_register_physical_memory(addr, 4096,
-                                         isa_page_descs[(addr - 0xa0000) >> 12]);
+                                         d->isa_page_descs[(addr - 0xa0000) >> 12]);
         }
     }
 }
 
-void i440fx_set_smm(PCIDevice *d, int val)
+void i440fx_set_smm(PCII440FXState *d, int val)
 {
     val = (val != 0);
-    if (smm_enabled != val) {
-        smm_enabled = val;
+    if (d->smm_enabled != val) {
+        d->smm_enabled = val;
         i440fx_update_memory_mappings(d);
     }
 }
@@ -121,133 +117,146 @@ void i440fx_set_smm(PCIDevice *d, int val)
 /* XXX: suppress when better memory API. We make the assumption that
    no device (in particular the VGA) changes the memory mappings in
    the 0xa0000-0x100000 range */
-void i440fx_init_memory_mappings(PCIDevice *d)
+void i440fx_init_memory_mappings(PCII440FXState *d)
 {
     int i;
     for(i = 0; i < 96; i++) {
-        isa_page_descs[i] = cpu_get_physical_page_desc(0xa0000 + i * 0x1000);
+        d->isa_page_descs[i] = cpu_get_physical_page_desc(0xa0000 + i * 0x1000);
     }
 }
 
-static void i440fx_write_config(PCIDevice *d,
+static void i440fx_write_config(PCIDevice *dev,
                                 uint32_t address, uint32_t val, int len)
 {
+    PCII440FXState *d = DO_UPCAST(PCII440FXState, dev, dev);
+
     /* XXX: implement SMRAM.D_LOCK */
-    pci_default_write_config(d, address, val, len);
+    pci_default_write_config(dev, address, val, len);
     if ((address >= 0x59 && address <= 0x5f) || address == 0x72)
         i440fx_update_memory_mappings(d);
 }
 
-static void i440fx_save(QEMUFile* f, void *opaque)
-{
-    PCIDevice *d = opaque;
-    int i;
-
-    pci_device_save(d, f);
-    qemu_put_8s(f, &smm_enabled);
-
-    for (i = 0; i < 4; i++)
-        qemu_put_be32(f, pci_irq_levels[i]);
-}
-
-static int i440fx_load(QEMUFile* f, void *opaque, int version_id)
+static int i440fx_load_old(QEMUFile* f, void *opaque, int version_id)
 {
-    PCIDevice *d = opaque;
+    PCII440FXState *d = opaque;
     int ret, i;
 
-    if (version_id > 2)
-        return -EINVAL;
-    ret = pci_device_load(d, f);
+    ret = pci_device_load(&d->dev, f);
     if (ret < 0)
         return ret;
     i440fx_update_memory_mappings(d);
-    qemu_get_8s(f, &smm_enabled);
+    qemu_get_8s(f, &d->smm_enabled);
 
-    if (version_id >= 2)
+    if (version_id == 2)
         for (i = 0; i < 4; i++)
-            pci_irq_levels[i] = qemu_get_be32(f);
+            d->piix3->pci_irq_levels[i] = qemu_get_be32(f);
+
+    return 0;
+}
+
+static int i440fx_post_load(void *opaque, int version_id)
+{
+    PCII440FXState *d = opaque;
 
+    i440fx_update_memory_mappings(d);
     return 0;
 }
 
-static void i440fx_pcihost_initfn(SysBusDevice *dev)
+static const VMStateDescription vmstate_i440fx = {
+    .name = "I440FX",
+    .version_id = 3,
+    .minimum_version_id = 3,
+    .minimum_version_id_old = 1,
+    .load_state_old = i440fx_load_old,
+    .post_load = i440fx_post_load,
+    .fields      = (VMStateField []) {
+        VMSTATE_PCI_DEVICE(dev, PCII440FXState),
+        VMSTATE_UINT8(smm_enabled, PCII440FXState),
+        VMSTATE_END_OF_LIST()
+    }
+};
+
+static int i440fx_pcihost_initfn(SysBusDevice *dev)
 {
     I440FXState *s = FROM_SYSBUS(I440FXState, dev);
 
-    register_ioport_write(0xcf8, 4, 4, i440fx_addr_writel, s);
-    register_ioport_read(0xcf8, 4, 4, i440fx_addr_readl, s);
+    pci_host_conf_register_ioport(0xcf8, s);
 
-    register_ioport_write(0xcfc, 4, 1, pci_host_data_writeb, s);
-    register_ioport_write(0xcfc, 4, 2, pci_host_data_writew, s);
-    register_ioport_write(0xcfc, 4, 4, pci_host_data_writel, s);
-    register_ioport_read(0xcfc, 4, 1, pci_host_data_readb, s);
-    register_ioport_read(0xcfc, 4, 2, pci_host_data_readw, s);
-    register_ioport_read(0xcfc, 4, 4, pci_host_data_readl, s);
+    pci_host_data_register_ioport(0xcfc, s);
+    return 0;
 }
 
-static void i440fx_initfn(PCIDevice *d)
+static int i440fx_initfn(PCIDevice *dev)
 {
-    pci_config_set_vendor_id(d->config, PCI_VENDOR_ID_INTEL);
-    pci_config_set_device_id(d->config, PCI_DEVICE_ID_INTEL_82441);
-    d->config[0x08] = 0x02; // revision
-    pci_config_set_class(d->config, PCI_CLASS_BRIDGE_HOST);
-    d->config[PCI_HEADER_TYPE] = PCI_HEADER_TYPE_NORMAL; // header_type
+    PCII440FXState *d = DO_UPCAST(PCII440FXState, dev, dev);
 
-    d->config[0x72] = 0x02; /* SMRAM */
+    pci_config_set_vendor_id(d->dev.config, PCI_VENDOR_ID_INTEL);
+    pci_config_set_device_id(d->dev.config, PCI_DEVICE_ID_INTEL_82441);
+    d->dev.config[0x08] = 0x02; // revision
+    pci_config_set_class(d->dev.config, PCI_CLASS_BRIDGE_HOST);
+    d->dev.config[PCI_HEADER_TYPE] = PCI_HEADER_TYPE_NORMAL; // header_type
 
-    register_savevm("I440FX", 0, 2, i440fx_save, i440fx_load, d);
+    d->dev.config[0x72] = 0x02; /* SMRAM */
+
+    return 0;
 }
 
-PCIBus *i440fx_init(PCIDevice **pi440fx_state, qemu_irq *pic)
+PCIBus *i440fx_init(PCII440FXState **pi440fx_state, int *piix3_devfn, qemu_irq *pic)
 {
     DeviceState *dev;
     PCIBus *b;
     PCIDevice *d;
     I440FXState *s;
+    PIIX3State *piix3;
 
     dev = qdev_create(NULL, "i440FX-pcihost");
     s = FROM_SYSBUS(I440FXState, sysbus_from_qdev(dev));
-    b = pci_register_bus(&s->busdev.qdev, "pci.0",
-                         piix3_set_irq, pci_slot_get_pirq, pic, 0, 4);
+    b = pci_bus_new(&s->busdev.qdev, NULL, 0);
     s->bus = b;
-    qdev_init(dev);
+    qdev_init_nofail(dev);
 
     d = pci_create_simple(b, 0, "i440FX");
-    *pi440fx_state = d;
+    *pi440fx_state = DO_UPCAST(PCII440FXState, dev, d);
+
+    piix3 = DO_UPCAST(PIIX3State, dev,
+                                 pci_create_simple(b, -1, "PIIX3"));
+    piix3->pic = pic;
+    pci_bus_irqs(b, piix3_set_irq, pci_slot_get_pirq, piix3, 4);
+    (*pi440fx_state)->piix3 = piix3;
+
+    *piix3_devfn = piix3->dev.devfn;
 
     return b;
 }
 
 /* PIIX3 PCI to ISA bridge */
 
-static PCIDevice *piix3_dev;
-PCIDevice *piix4_dev;
-
-static void piix3_set_irq(qemu_irq *pic, int irq_num, int level)
+static void piix3_set_irq(void *opaque, int irq_num, int level)
 {
     int i, pic_irq, pic_level;
+    PIIX3State *piix3 = opaque;
 
-    pci_irq_levels[irq_num] = level;
+    piix3->pci_irq_levels[irq_num] = level;
 
     /* now we change the pic irq level according to the piix irq mappings */
     /* XXX: optimize */
-    pic_irq = piix3_dev->config[0x60 + irq_num];
+    pic_irq = piix3->dev.config[0x60 + irq_num];
     if (pic_irq < 16) {
         /* The pic level is the logical OR of all the PCI irqs mapped
            to it */
         pic_level = 0;
         for (i = 0; i < 4; i++) {
-            if (pic_irq == piix3_dev->config[0x60 + i])
-                pic_level |= pci_irq_levels[i];
+            if (pic_irq == piix3->dev.config[0x60 + i])
+                pic_level |= piix3->pci_irq_levels[i];
         }
-        qemu_set_irq(pic[pic_irq], pic_level);
+        qemu_set_irq(piix3->pic[pic_irq], pic_level);
     }
 }
 
 static void piix3_reset(void *opaque)
 {
-    PCIDevice *d = opaque;
-    uint8_t *pci_conf = d->config;
+    PIIX3State *d = opaque;
+    uint8_t *pci_conf = d->dev.config;
 
     pci_conf[0x04] = 0x07; // master, memory and I/O
     pci_conf[0x05] = 0x00;
@@ -281,135 +290,55 @@ static void piix3_reset(void *opaque)
     pci_conf[0xac] = 0x00;
     pci_conf[0xae] = 0x00;
 
-    memset(pci_irq_levels, 0, sizeof(pci_irq_levels));
-}
-
-static void piix4_reset(void *opaque)
-{
-    PCIDevice *d = opaque;
-    uint8_t *pci_conf = d->config;
-
-    pci_conf[0x04] = 0x07; // master, memory and I/O
-    pci_conf[0x05] = 0x00;
-    pci_conf[0x06] = 0x00;
-    pci_conf[0x07] = 0x02; // PCI_status_devsel_medium
-    pci_conf[0x4c] = 0x4d;
-    pci_conf[0x4e] = 0x03;
-    pci_conf[0x4f] = 0x00;
-    pci_conf[0x60] = 0x0a; // PCI A -> IRQ 10
-    pci_conf[0x61] = 0x0a; // PCI B -> IRQ 10
-    pci_conf[0x62] = 0x0b; // PCI C -> IRQ 11
-    pci_conf[0x63] = 0x0b; // PCI D -> IRQ 11
-    pci_conf[0x69] = 0x02;
-    pci_conf[0x70] = 0x80;
-    pci_conf[0x76] = 0x0c;
-    pci_conf[0x77] = 0x0c;
-    pci_conf[0x78] = 0x02;
-    pci_conf[0x79] = 0x00;
-    pci_conf[0x80] = 0x00;
-    pci_conf[0x82] = 0x00;
-    pci_conf[0xa0] = 0x08;
-    pci_conf[0xa2] = 0x00;
-    pci_conf[0xa3] = 0x00;
-    pci_conf[0xa4] = 0x00;
-    pci_conf[0xa5] = 0x00;
-    pci_conf[0xa6] = 0x00;
-    pci_conf[0xa7] = 0x00;
-    pci_conf[0xa8] = 0x0f;
-    pci_conf[0xaa] = 0x00;
-    pci_conf[0xab] = 0x00;
-    pci_conf[0xac] = 0x00;
-    pci_conf[0xae] = 0x00;
-
-    memset(pci_irq_levels, 0, sizeof(pci_irq_levels));
-}
-
-static void piix_save(QEMUFile* f, void *opaque)
-{
-    PCIDevice *d = opaque;
-    pci_device_save(d, f);
+    memset(d->pci_irq_levels, 0, sizeof(d->pci_irq_levels));
 }
 
-static int piix_load(QEMUFile* f, void *opaque, int version_id)
-{
-    PCIDevice *d = opaque;
-    if (version_id != 2)
-        return -EINVAL;
-    return pci_device_load(d, f);
-}
+static const VMStateDescription vmstate_piix3 = {
+    .name = "PIIX3",
+    .version_id = 3,
+    .minimum_version_id = 2,
+    .minimum_version_id_old = 2,
+    .fields      = (VMStateField []) {
+        VMSTATE_PCI_DEVICE(dev, PIIX3State),
+        VMSTATE_INT32_ARRAY_V(pci_irq_levels, PIIX3State, 4, 3),
+        VMSTATE_END_OF_LIST()
+    }
+};
 
-static void piix3_initfn(PCIDevice *d)
+static int piix3_initfn(PCIDevice *dev)
 {
+    PIIX3State *d = DO_UPCAST(PIIX3State, dev, dev);
     uint8_t *pci_conf;
 
-    register_savevm("PIIX3", 0, 2, piix_save, piix_load, d);
+    isa_bus_new(&d->dev.qdev);
 
-    pci_conf = d->config;
+    pci_conf = d->dev.config;
     pci_config_set_vendor_id(pci_conf, PCI_VENDOR_ID_INTEL);
     pci_config_set_device_id(pci_conf, PCI_DEVICE_ID_INTEL_82371SB_0); // 82371SB PIIX3 PCI-to-ISA bridge (Step A1)
     pci_config_set_class(pci_conf, PCI_CLASS_BRIDGE_ISA);
     pci_conf[PCI_HEADER_TYPE] =
         PCI_HEADER_TYPE_NORMAL | PCI_HEADER_TYPE_MULTI_FUNCTION; // header_type = PCI_multifunction, generic
 
-    piix3_dev = d;
-    piix3_reset(d);
     qemu_register_reset(piix3_reset, d);
-}
-
-static void piix4_initfn(PCIDevice *d)
-{
-    uint8_t *pci_conf;
-
-    register_savevm("PIIX4", 0, 2, piix_save, piix_load, d);
-
-    pci_conf = d->config;
-    pci_config_set_vendor_id(pci_conf, PCI_VENDOR_ID_INTEL);
-    pci_config_set_device_id(pci_conf, PCI_DEVICE_ID_INTEL_82371AB_0); // 82371AB/EB/MB PIIX4 PCI-to-ISA bridge
-    pci_config_set_class(pci_conf, PCI_CLASS_BRIDGE_ISA);
-    pci_conf[PCI_HEADER_TYPE] =
-        PCI_HEADER_TYPE_NORMAL | PCI_HEADER_TYPE_MULTI_FUNCTION; // header_type = PCI_multifunction, generic
-
-    piix4_dev = d;
-    piix4_reset(d);
-    qemu_register_reset(piix4_reset, d);
-}
-
-int piix3_init(PCIBus *bus, int devfn)
-{
-    PCIDevice *d;
-
-    d = pci_create_simple(bus, devfn, "PIIX3");
-    return d->devfn;
-}
-
-int piix4_init(PCIBus *bus, int devfn)
-{
-    PCIDevice *d;
-
-    d = pci_create_simple(bus, devfn, "PIIX4");
-    return d->devfn;
+    return 0;
 }
 
 static PCIDeviceInfo i440fx_info[] = {
     {
         .qdev.name    = "i440FX",
         .qdev.desc    = "Host bridge",
-        .qdev.size    = sizeof(PCIDevice),
+        .qdev.size    = sizeof(PCII440FXState),
+        .qdev.vmsd    = &vmstate_i440fx,
         .qdev.no_user = 1,
         .init         = i440fx_initfn,
         .config_write = i440fx_write_config,
     },{
         .qdev.name    = "PIIX3",
         .qdev.desc    = "ISA bridge",
-        .qdev.size    = sizeof(PCIDevice),
+        .qdev.size    = sizeof(PIIX3State),
+        .qdev.vmsd    = &vmstate_piix3,
         .qdev.no_user = 1,
         .init         = piix3_initfn,
-    },{
-        .qdev.name    = "PIIX4",
-        .qdev.desc    = "ISA bridge",
-        .qdev.size    = sizeof(PCIDevice),
-        .qdev.no_user = 1,
-        .init         = piix4_initfn,
     },{
         /* end of list */
     }