xref: /openbmc/qemu/hw/pci-host/i440fx.c (revision d328fef93ae757a0dd65ed786a4086e27952eef3)
10f25d865SPhilippe Mathieu-Daudé /*
2cd3fdb7fSPhilippe Mathieu-Daudé  * QEMU i440FX PCI Bridge Emulation
30f25d865SPhilippe Mathieu-Daudé  *
40f25d865SPhilippe Mathieu-Daudé  * Copyright (c) 2006 Fabrice Bellard
50f25d865SPhilippe Mathieu-Daudé  *
60f25d865SPhilippe Mathieu-Daudé  * Permission is hereby granted, free of charge, to any person obtaining a copy
70f25d865SPhilippe Mathieu-Daudé  * of this software and associated documentation files (the "Software"), to deal
80f25d865SPhilippe Mathieu-Daudé  * in the Software without restriction, including without limitation the rights
90f25d865SPhilippe Mathieu-Daudé  * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
100f25d865SPhilippe Mathieu-Daudé  * copies of the Software, and to permit persons to whom the Software is
110f25d865SPhilippe Mathieu-Daudé  * furnished to do so, subject to the following conditions:
120f25d865SPhilippe Mathieu-Daudé  *
130f25d865SPhilippe Mathieu-Daudé  * The above copyright notice and this permission notice shall be included in
140f25d865SPhilippe Mathieu-Daudé  * all copies or substantial portions of the Software.
150f25d865SPhilippe Mathieu-Daudé  *
160f25d865SPhilippe Mathieu-Daudé  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
170f25d865SPhilippe Mathieu-Daudé  * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
180f25d865SPhilippe Mathieu-Daudé  * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
190f25d865SPhilippe Mathieu-Daudé  * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
200f25d865SPhilippe Mathieu-Daudé  * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
210f25d865SPhilippe Mathieu-Daudé  * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
220f25d865SPhilippe Mathieu-Daudé  * THE SOFTWARE.
230f25d865SPhilippe Mathieu-Daudé  */
240f25d865SPhilippe Mathieu-Daudé 
250f25d865SPhilippe Mathieu-Daudé #include "qemu/osdep.h"
2651eae1e7SPhilippe Mathieu-Daudé #include "qemu/units.h"
279a571161SPhilippe Mathieu-Daudé #include "qemu/range.h"
280f25d865SPhilippe Mathieu-Daudé #include "hw/i386/pc.h"
290f25d865SPhilippe Mathieu-Daudé #include "hw/pci/pci.h"
300f25d865SPhilippe Mathieu-Daudé #include "hw/pci/pci_host.h"
310f25d865SPhilippe Mathieu-Daudé #include "hw/pci-host/i440fx.h"
320f25d865SPhilippe Mathieu-Daudé #include "hw/qdev-properties.h"
330f25d865SPhilippe Mathieu-Daudé #include "hw/sysbus.h"
340f25d865SPhilippe Mathieu-Daudé #include "qapi/error.h"
350f25d865SPhilippe Mathieu-Daudé #include "migration/vmstate.h"
360f25d865SPhilippe Mathieu-Daudé #include "qapi/visitor.h"
370f25d865SPhilippe Mathieu-Daudé #include "qemu/error-report.h"
38db1015e9SEduardo Habkost #include "qom/object.h"
390f25d865SPhilippe Mathieu-Daudé 
400f25d865SPhilippe Mathieu-Daudé /*
410f25d865SPhilippe Mathieu-Daudé  * I440FX chipset data sheet.
420f25d865SPhilippe Mathieu-Daudé  * https://wiki.qemu.org/File:29054901.pdf
430f25d865SPhilippe Mathieu-Daudé  */
440f25d865SPhilippe Mathieu-Daudé 
458063396bSEduardo Habkost OBJECT_DECLARE_SIMPLE_TYPE(I440FXState, I440FX_PCI_HOST_BRIDGE)
460f25d865SPhilippe Mathieu-Daudé 
47db1015e9SEduardo Habkost struct I440FXState {
480f25d865SPhilippe Mathieu-Daudé     PCIHostState parent_obj;
4909f85b7bSBernhard Beschow 
5009f85b7bSBernhard Beschow     MemoryRegion *system_memory;
51c84858fdSBernhard Beschow     MemoryRegion *io_memory;
5209f85b7bSBernhard Beschow     MemoryRegion *pci_address_space;
5309f85b7bSBernhard Beschow     MemoryRegion *ram_memory;
540f25d865SPhilippe Mathieu-Daudé     Range pci_hole;
5582feef45SBernhard Beschow     uint64_t below_4g_mem_size;
5682feef45SBernhard Beschow     uint64_t above_4g_mem_size;
570f25d865SPhilippe Mathieu-Daudé     uint64_t pci_hole64_size;
580f25d865SPhilippe Mathieu-Daudé     bool pci_hole64_fix;
59ff0a8cc4SBernhard Beschow 
60ff0a8cc4SBernhard Beschow     char *pci_type;
61db1015e9SEduardo Habkost };
620f25d865SPhilippe Mathieu-Daudé 
630f25d865SPhilippe Mathieu-Daudé #define I440FX_PAM      0x59
640f25d865SPhilippe Mathieu-Daudé #define I440FX_PAM_SIZE 7
650f25d865SPhilippe Mathieu-Daudé #define I440FX_SMRAM    0x72
660f25d865SPhilippe Mathieu-Daudé 
670f25d865SPhilippe Mathieu-Daudé /* Keep it 2G to comply with older win32 guests */
680f25d865SPhilippe Mathieu-Daudé #define I440FX_PCI_HOST_HOLE64_SIZE_DEFAULT (1ULL << 31)
690f25d865SPhilippe Mathieu-Daudé 
700f25d865SPhilippe Mathieu-Daudé /* Older coreboot versions (4.0 and older) read a config register that doesn't
710f25d865SPhilippe Mathieu-Daudé  * exist in real hardware, to get the RAM size from QEMU.
720f25d865SPhilippe Mathieu-Daudé  */
730f25d865SPhilippe Mathieu-Daudé #define I440FX_COREBOOT_RAM_SIZE 0x57
740f25d865SPhilippe Mathieu-Daudé 
i440fx_realize(PCIDevice * dev,Error ** errp)7544df0552SBernhard Beschow static void i440fx_realize(PCIDevice *dev, Error **errp)
7644df0552SBernhard Beschow {
7744df0552SBernhard Beschow     dev->config[I440FX_SMRAM] = 0x02;
7844df0552SBernhard Beschow 
7944df0552SBernhard Beschow     if (object_property_get_bool(qdev_get_machine(), "iommu", NULL)) {
8044df0552SBernhard Beschow         warn_report("i440fx doesn't support emulated iommu");
8144df0552SBernhard Beschow     }
8244df0552SBernhard Beschow }
8344df0552SBernhard Beschow 
i440fx_update_memory_mappings(PCII440FXState * d)840f25d865SPhilippe Mathieu-Daudé static void i440fx_update_memory_mappings(PCII440FXState *d)
850f25d865SPhilippe Mathieu-Daudé {
860f25d865SPhilippe Mathieu-Daudé     int i;
870f25d865SPhilippe Mathieu-Daudé     PCIDevice *pd = PCI_DEVICE(d);
880f25d865SPhilippe Mathieu-Daudé 
890f25d865SPhilippe Mathieu-Daudé     memory_region_transaction_begin();
900f25d865SPhilippe Mathieu-Daudé     for (i = 0; i < ARRAY_SIZE(d->pam_regions); i++) {
910f25d865SPhilippe Mathieu-Daudé         pam_update(&d->pam_regions[i], i,
920f25d865SPhilippe Mathieu-Daudé                    pd->config[I440FX_PAM + DIV_ROUND_UP(i, 2)]);
930f25d865SPhilippe Mathieu-Daudé     }
940f25d865SPhilippe Mathieu-Daudé     memory_region_set_enabled(&d->smram_region,
950f25d865SPhilippe Mathieu-Daudé                               !(pd->config[I440FX_SMRAM] & SMRAM_D_OPEN));
960f25d865SPhilippe Mathieu-Daudé     memory_region_set_enabled(&d->smram,
970f25d865SPhilippe Mathieu-Daudé                               pd->config[I440FX_SMRAM] & SMRAM_G_SMRAME);
980f25d865SPhilippe Mathieu-Daudé     memory_region_transaction_commit();
990f25d865SPhilippe Mathieu-Daudé }
1000f25d865SPhilippe Mathieu-Daudé 
1010f25d865SPhilippe Mathieu-Daudé 
i440fx_write_config(PCIDevice * dev,uint32_t address,uint32_t val,int len)1020f25d865SPhilippe Mathieu-Daudé static void i440fx_write_config(PCIDevice *dev,
1030f25d865SPhilippe Mathieu-Daudé                                 uint32_t address, uint32_t val, int len)
1040f25d865SPhilippe Mathieu-Daudé {
1050f25d865SPhilippe Mathieu-Daudé     PCII440FXState *d = I440FX_PCI_DEVICE(dev);
1060f25d865SPhilippe Mathieu-Daudé 
1070f25d865SPhilippe Mathieu-Daudé     /* XXX: implement SMRAM.D_LOCK */
1080f25d865SPhilippe Mathieu-Daudé     pci_default_write_config(dev, address, val, len);
1090f25d865SPhilippe Mathieu-Daudé     if (ranges_overlap(address, len, I440FX_PAM, I440FX_PAM_SIZE) ||
1100f25d865SPhilippe Mathieu-Daudé         range_covers_byte(address, len, I440FX_SMRAM)) {
1110f25d865SPhilippe Mathieu-Daudé         i440fx_update_memory_mappings(d);
1120f25d865SPhilippe Mathieu-Daudé     }
1130f25d865SPhilippe Mathieu-Daudé }
1140f25d865SPhilippe Mathieu-Daudé 
i440fx_post_load(void * opaque,int version_id)1150f25d865SPhilippe Mathieu-Daudé static int i440fx_post_load(void *opaque, int version_id)
1160f25d865SPhilippe Mathieu-Daudé {
1170f25d865SPhilippe Mathieu-Daudé     PCII440FXState *d = opaque;
1180f25d865SPhilippe Mathieu-Daudé 
1190f25d865SPhilippe Mathieu-Daudé     i440fx_update_memory_mappings(d);
1200f25d865SPhilippe Mathieu-Daudé     return 0;
1210f25d865SPhilippe Mathieu-Daudé }
1220f25d865SPhilippe Mathieu-Daudé 
1230f25d865SPhilippe Mathieu-Daudé static const VMStateDescription vmstate_i440fx = {
1240f25d865SPhilippe Mathieu-Daudé     .name = "I440FX",
1250f25d865SPhilippe Mathieu-Daudé     .version_id = 3,
1260f25d865SPhilippe Mathieu-Daudé     .minimum_version_id = 3,
1270f25d865SPhilippe Mathieu-Daudé     .post_load = i440fx_post_load,
128*e2bd53a3SRichard Henderson     .fields = (const VMStateField[]) {
1290f25d865SPhilippe Mathieu-Daudé         VMSTATE_PCI_DEVICE(parent_obj, PCII440FXState),
1300f25d865SPhilippe Mathieu-Daudé         /* Used to be smm_enabled, which was basically always zero because
1310f25d865SPhilippe Mathieu-Daudé          * SeaBIOS hardly uses SMM.  SMRAM is now handled by CPU code.
1320f25d865SPhilippe Mathieu-Daudé          */
1330f25d865SPhilippe Mathieu-Daudé         VMSTATE_UNUSED(1),
1340f25d865SPhilippe Mathieu-Daudé         VMSTATE_END_OF_LIST()
1350f25d865SPhilippe Mathieu-Daudé     }
1360f25d865SPhilippe Mathieu-Daudé };
1370f25d865SPhilippe Mathieu-Daudé 
i440fx_pcihost_get_pci_hole_start(Object * obj,Visitor * v,const char * name,void * opaque,Error ** errp)1380f25d865SPhilippe Mathieu-Daudé static void i440fx_pcihost_get_pci_hole_start(Object *obj, Visitor *v,
1390f25d865SPhilippe Mathieu-Daudé                                               const char *name, void *opaque,
1400f25d865SPhilippe Mathieu-Daudé                                               Error **errp)
1410f25d865SPhilippe Mathieu-Daudé {
1420f25d865SPhilippe Mathieu-Daudé     I440FXState *s = I440FX_PCI_HOST_BRIDGE(obj);
1430f25d865SPhilippe Mathieu-Daudé     uint64_t val64;
1440f25d865SPhilippe Mathieu-Daudé     uint32_t value;
1450f25d865SPhilippe Mathieu-Daudé 
1460f25d865SPhilippe Mathieu-Daudé     val64 = range_is_empty(&s->pci_hole) ? 0 : range_lob(&s->pci_hole);
1470f25d865SPhilippe Mathieu-Daudé     value = val64;
1480f25d865SPhilippe Mathieu-Daudé     assert(value == val64);
1490f25d865SPhilippe Mathieu-Daudé     visit_type_uint32(v, name, &value, errp);
1500f25d865SPhilippe Mathieu-Daudé }
1510f25d865SPhilippe Mathieu-Daudé 
i440fx_pcihost_get_pci_hole_end(Object * obj,Visitor * v,const char * name,void * opaque,Error ** errp)1520f25d865SPhilippe Mathieu-Daudé static void i440fx_pcihost_get_pci_hole_end(Object *obj, Visitor *v,
1530f25d865SPhilippe Mathieu-Daudé                                             const char *name, void *opaque,
1540f25d865SPhilippe Mathieu-Daudé                                             Error **errp)
1550f25d865SPhilippe Mathieu-Daudé {
1560f25d865SPhilippe Mathieu-Daudé     I440FXState *s = I440FX_PCI_HOST_BRIDGE(obj);
1570f25d865SPhilippe Mathieu-Daudé     uint64_t val64;
1580f25d865SPhilippe Mathieu-Daudé     uint32_t value;
1590f25d865SPhilippe Mathieu-Daudé 
1600f25d865SPhilippe Mathieu-Daudé     val64 = range_is_empty(&s->pci_hole) ? 0 : range_upb(&s->pci_hole) + 1;
1610f25d865SPhilippe Mathieu-Daudé     value = val64;
1620f25d865SPhilippe Mathieu-Daudé     assert(value == val64);
1630f25d865SPhilippe Mathieu-Daudé     visit_type_uint32(v, name, &value, errp);
1640f25d865SPhilippe Mathieu-Daudé }
1650f25d865SPhilippe Mathieu-Daudé 
1660f25d865SPhilippe Mathieu-Daudé /*
1670f25d865SPhilippe Mathieu-Daudé  * The 64bit PCI hole start is set by the Guest firmware
1680f25d865SPhilippe Mathieu-Daudé  * as the address of the first 64bit PCI MEM resource.
1690f25d865SPhilippe Mathieu-Daudé  * If no PCI device has resources on the 64bit area,
1700f25d865SPhilippe Mathieu-Daudé  * the 64bit PCI hole will start after "over 4G RAM" and the
1710f25d865SPhilippe Mathieu-Daudé  * reserved space for memory hotplug if any.
1720f25d865SPhilippe Mathieu-Daudé  */
i440fx_pcihost_get_pci_hole64_start_value(Object * obj)1730f25d865SPhilippe Mathieu-Daudé static uint64_t i440fx_pcihost_get_pci_hole64_start_value(Object *obj)
1740f25d865SPhilippe Mathieu-Daudé {
1750f25d865SPhilippe Mathieu-Daudé     PCIHostState *h = PCI_HOST_BRIDGE(obj);
1760f25d865SPhilippe Mathieu-Daudé     I440FXState *s = I440FX_PCI_HOST_BRIDGE(obj);
1770f25d865SPhilippe Mathieu-Daudé     Range w64;
1780f25d865SPhilippe Mathieu-Daudé     uint64_t value;
1790f25d865SPhilippe Mathieu-Daudé 
1800f25d865SPhilippe Mathieu-Daudé     pci_bus_get_w64_range(h->bus, &w64);
1810f25d865SPhilippe Mathieu-Daudé     value = range_is_empty(&w64) ? 0 : range_lob(&w64);
1820f25d865SPhilippe Mathieu-Daudé     if (!value && s->pci_hole64_fix) {
1830f25d865SPhilippe Mathieu-Daudé         value = pc_pci_hole64_start();
1840f25d865SPhilippe Mathieu-Daudé     }
1850f25d865SPhilippe Mathieu-Daudé     return value;
1860f25d865SPhilippe Mathieu-Daudé }
1870f25d865SPhilippe Mathieu-Daudé 
i440fx_pcihost_get_pci_hole64_start(Object * obj,Visitor * v,const char * name,void * opaque,Error ** errp)1880f25d865SPhilippe Mathieu-Daudé static void i440fx_pcihost_get_pci_hole64_start(Object *obj, Visitor *v,
1890f25d865SPhilippe Mathieu-Daudé                                                 const char *name,
1900f25d865SPhilippe Mathieu-Daudé                                                 void *opaque, Error **errp)
1910f25d865SPhilippe Mathieu-Daudé {
1920f25d865SPhilippe Mathieu-Daudé     uint64_t hole64_start = i440fx_pcihost_get_pci_hole64_start_value(obj);
1930f25d865SPhilippe Mathieu-Daudé 
1940f25d865SPhilippe Mathieu-Daudé     visit_type_uint64(v, name, &hole64_start, errp);
1950f25d865SPhilippe Mathieu-Daudé }
1960f25d865SPhilippe Mathieu-Daudé 
1970f25d865SPhilippe Mathieu-Daudé /*
1980f25d865SPhilippe Mathieu-Daudé  * The 64bit PCI hole end is set by the Guest firmware
1990f25d865SPhilippe Mathieu-Daudé  * as the address of the last 64bit PCI MEM resource.
2000f25d865SPhilippe Mathieu-Daudé  * Then it is expanded to the PCI_HOST_PROP_PCI_HOLE64_SIZE
2010f25d865SPhilippe Mathieu-Daudé  * that can be configured by the user.
2020f25d865SPhilippe Mathieu-Daudé  */
i440fx_pcihost_get_pci_hole64_end(Object * obj,Visitor * v,const char * name,void * opaque,Error ** errp)2030f25d865SPhilippe Mathieu-Daudé static void i440fx_pcihost_get_pci_hole64_end(Object *obj, Visitor *v,
2040f25d865SPhilippe Mathieu-Daudé                                               const char *name, void *opaque,
2050f25d865SPhilippe Mathieu-Daudé                                               Error **errp)
2060f25d865SPhilippe Mathieu-Daudé {
2070f25d865SPhilippe Mathieu-Daudé     PCIHostState *h = PCI_HOST_BRIDGE(obj);
2080f25d865SPhilippe Mathieu-Daudé     I440FXState *s = I440FX_PCI_HOST_BRIDGE(obj);
2090f25d865SPhilippe Mathieu-Daudé     uint64_t hole64_start = i440fx_pcihost_get_pci_hole64_start_value(obj);
2100f25d865SPhilippe Mathieu-Daudé     Range w64;
2110f25d865SPhilippe Mathieu-Daudé     uint64_t value, hole64_end;
2120f25d865SPhilippe Mathieu-Daudé 
2130f25d865SPhilippe Mathieu-Daudé     pci_bus_get_w64_range(h->bus, &w64);
2140f25d865SPhilippe Mathieu-Daudé     value = range_is_empty(&w64) ? 0 : range_upb(&w64) + 1;
2150f25d865SPhilippe Mathieu-Daudé     hole64_end = ROUND_UP(hole64_start + s->pci_hole64_size, 1ULL << 30);
2160f25d865SPhilippe Mathieu-Daudé     if (s->pci_hole64_fix && value < hole64_end) {
2170f25d865SPhilippe Mathieu-Daudé         value = hole64_end;
2180f25d865SPhilippe Mathieu-Daudé     }
2190f25d865SPhilippe Mathieu-Daudé     visit_type_uint64(v, name, &value, errp);
2200f25d865SPhilippe Mathieu-Daudé }
2210f25d865SPhilippe Mathieu-Daudé 
i440fx_pcihost_initfn(Object * obj)2220f25d865SPhilippe Mathieu-Daudé static void i440fx_pcihost_initfn(Object *obj)
2230f25d865SPhilippe Mathieu-Daudé {
22409f85b7bSBernhard Beschow     I440FXState *s = I440FX_PCI_HOST_BRIDGE(obj);
225a707466dSBernhard Beschow     PCIHostState *phb = PCI_HOST_BRIDGE(obj);
2260f25d865SPhilippe Mathieu-Daudé 
227a707466dSBernhard Beschow     memory_region_init_io(&phb->conf_mem, obj, &pci_host_conf_le_ops, phb,
2280f25d865SPhilippe Mathieu-Daudé                           "pci-conf-idx", 4);
229a707466dSBernhard Beschow     memory_region_init_io(&phb->data_mem, obj, &pci_host_data_le_ops, phb,
2300f25d865SPhilippe Mathieu-Daudé                           "pci-conf-data", 4);
23109f85b7bSBernhard Beschow 
23209f85b7bSBernhard Beschow     object_property_add_link(obj, PCI_HOST_PROP_RAM_MEM, TYPE_MEMORY_REGION,
23309f85b7bSBernhard Beschow                              (Object **) &s->ram_memory,
23409f85b7bSBernhard Beschow                              qdev_prop_allow_set_link_before_realize, 0);
23509f85b7bSBernhard Beschow 
23609f85b7bSBernhard Beschow     object_property_add_link(obj, PCI_HOST_PROP_PCI_MEM, TYPE_MEMORY_REGION,
23709f85b7bSBernhard Beschow                              (Object **) &s->pci_address_space,
23809f85b7bSBernhard Beschow                              qdev_prop_allow_set_link_before_realize, 0);
23909f85b7bSBernhard Beschow 
24009f85b7bSBernhard Beschow     object_property_add_link(obj, PCI_HOST_PROP_SYSTEM_MEM, TYPE_MEMORY_REGION,
24109f85b7bSBernhard Beschow                              (Object **) &s->system_memory,
24209f85b7bSBernhard Beschow                              qdev_prop_allow_set_link_before_realize, 0);
243c84858fdSBernhard Beschow 
244c84858fdSBernhard Beschow     object_property_add_link(obj, PCI_HOST_PROP_IO_MEM, TYPE_MEMORY_REGION,
245c84858fdSBernhard Beschow                              (Object **) &s->io_memory,
246c84858fdSBernhard Beschow                              qdev_prop_allow_set_link_before_realize, 0);
2470f25d865SPhilippe Mathieu-Daudé }
2480f25d865SPhilippe Mathieu-Daudé 
i440fx_pcihost_realize(DeviceState * dev,Error ** errp)2490f25d865SPhilippe Mathieu-Daudé static void i440fx_pcihost_realize(DeviceState *dev, Error **errp)
2500f25d865SPhilippe Mathieu-Daudé {
251ce5ac09aSBernhard Beschow     ERRP_GUARD();
252c84858fdSBernhard Beschow     I440FXState *s = I440FX_PCI_HOST_BRIDGE(dev);
253a707466dSBernhard Beschow     PCIHostState *phb = PCI_HOST_BRIDGE(dev);
2540f25d865SPhilippe Mathieu-Daudé     SysBusDevice *sbd = SYS_BUS_DEVICE(dev);
255ce5ac09aSBernhard Beschow     PCIBus *b;
256ce5ac09aSBernhard Beschow     PCIDevice *d;
257ce5ac09aSBernhard Beschow     PCII440FXState *f;
258ce5ac09aSBernhard Beschow     unsigned i;
2590f25d865SPhilippe Mathieu-Daudé 
260c84858fdSBernhard Beschow     memory_region_add_subregion(s->io_memory, 0xcf8, &phb->conf_mem);
2610f25d865SPhilippe Mathieu-Daudé     sysbus_init_ioports(sbd, 0xcf8, 4);
2620f25d865SPhilippe Mathieu-Daudé 
263c84858fdSBernhard Beschow     memory_region_add_subregion(s->io_memory, 0xcfc, &phb->data_mem);
2640f25d865SPhilippe Mathieu-Daudé     sysbus_init_ioports(sbd, 0xcfc, 4);
2650f25d865SPhilippe Mathieu-Daudé 
2660f25d865SPhilippe Mathieu-Daudé     /* register i440fx 0xcf8 port as coalesced pio */
267a707466dSBernhard Beschow     memory_region_set_flush_coalesced(&phb->data_mem);
268a707466dSBernhard Beschow     memory_region_add_coalescing(&phb->conf_mem, 0, 4);
26909f85b7bSBernhard Beschow 
27009f85b7bSBernhard Beschow     b = pci_root_bus_new(dev, NULL, s->pci_address_space,
271c84858fdSBernhard Beschow                          s->io_memory, 0, TYPE_PCI_BUS);
272a707466dSBernhard Beschow     phb->bus = b;
2730f25d865SPhilippe Mathieu-Daudé 
274ff0a8cc4SBernhard Beschow     d = pci_create_simple(b, 0, s->pci_type);
275c92331bfSBernhard Beschow     f = I440FX_PCI_DEVICE(d);
2760f25d865SPhilippe Mathieu-Daudé 
27782feef45SBernhard Beschow     range_set_bounds(&s->pci_hole, s->below_4g_mem_size,
2780f25d865SPhilippe Mathieu-Daudé                      IO_APIC_DEFAULT_ADDRESS - 1);
2790f25d865SPhilippe Mathieu-Daudé 
2800f25d865SPhilippe Mathieu-Daudé     /* setup pci memory mapping */
28109f85b7bSBernhard Beschow     pc_pci_as_mapping_init(s->system_memory, s->pci_address_space);
2820f25d865SPhilippe Mathieu-Daudé 
2830f25d865SPhilippe Mathieu-Daudé     /* if *disabled* show SMRAM to all CPUs */
2840f25d865SPhilippe Mathieu-Daudé     memory_region_init_alias(&f->smram_region, OBJECT(d), "smram-region",
28509f85b7bSBernhard Beschow                              s->pci_address_space, SMRAM_C_BASE, SMRAM_C_SIZE);
28609f85b7bSBernhard Beschow     memory_region_add_subregion_overlap(s->system_memory, SMRAM_C_BASE,
2870f25d865SPhilippe Mathieu-Daudé                                         &f->smram_region, 1);
2880f25d865SPhilippe Mathieu-Daudé     memory_region_set_enabled(&f->smram_region, true);
2890f25d865SPhilippe Mathieu-Daudé 
2900f25d865SPhilippe Mathieu-Daudé     /* smram, as seen by SMM CPUs */
29151eae1e7SPhilippe Mathieu-Daudé     memory_region_init(&f->smram, OBJECT(d), "smram", 4 * GiB);
2920f25d865SPhilippe Mathieu-Daudé     memory_region_set_enabled(&f->smram, true);
2930f25d865SPhilippe Mathieu-Daudé     memory_region_init_alias(&f->low_smram, OBJECT(d), "smram-low",
29409f85b7bSBernhard Beschow                              s->ram_memory, SMRAM_C_BASE, SMRAM_C_SIZE);
2950f25d865SPhilippe Mathieu-Daudé     memory_region_set_enabled(&f->low_smram, true);
296cda39f13SBernhard Beschow     memory_region_add_subregion(&f->smram, SMRAM_C_BASE, &f->low_smram);
2970f25d865SPhilippe Mathieu-Daudé     object_property_add_const_link(qdev_get_machine(), "smram",
298d2623129SMarkus Armbruster                                    OBJECT(&f->smram));
2990f25d865SPhilippe Mathieu-Daudé 
30009f85b7bSBernhard Beschow     init_pam(&f->pam_regions[0], OBJECT(d), s->ram_memory, s->system_memory,
30109f85b7bSBernhard Beschow              s->pci_address_space, PAM_BIOS_BASE, PAM_BIOS_SIZE);
3020f25d865SPhilippe Mathieu-Daudé     for (i = 0; i < ARRAY_SIZE(f->pam_regions) - 1; ++i) {
30309f85b7bSBernhard Beschow         init_pam(&f->pam_regions[i + 1], OBJECT(d), s->ram_memory,
30409f85b7bSBernhard Beschow                  s->system_memory, s->pci_address_space,
3059e57b818SBernhard Beschow                  PAM_EXPAN_BASE + i * PAM_EXPAN_SIZE, PAM_EXPAN_SIZE);
3060f25d865SPhilippe Mathieu-Daudé     }
3070f25d865SPhilippe Mathieu-Daudé 
30882feef45SBernhard Beschow     ram_addr_t ram_size = s->below_4g_mem_size + s->above_4g_mem_size;
3090f25d865SPhilippe Mathieu-Daudé     ram_size = ram_size / 8 / 1024 / 1024;
3100f25d865SPhilippe Mathieu-Daudé     if (ram_size > 255) {
3110f25d865SPhilippe Mathieu-Daudé         ram_size = 255;
3120f25d865SPhilippe Mathieu-Daudé     }
3130f25d865SPhilippe Mathieu-Daudé     d->config[I440FX_COREBOOT_RAM_SIZE] = ram_size;
3140f25d865SPhilippe Mathieu-Daudé 
3150f25d865SPhilippe Mathieu-Daudé     i440fx_update_memory_mappings(f);
3160f25d865SPhilippe Mathieu-Daudé }
3170f25d865SPhilippe Mathieu-Daudé 
i440fx_class_init(ObjectClass * klass,void * data)3180f25d865SPhilippe Mathieu-Daudé static void i440fx_class_init(ObjectClass *klass, void *data)
3190f25d865SPhilippe Mathieu-Daudé {
3200f25d865SPhilippe Mathieu-Daudé     DeviceClass *dc = DEVICE_CLASS(klass);
3210f25d865SPhilippe Mathieu-Daudé     PCIDeviceClass *k = PCI_DEVICE_CLASS(klass);
3220f25d865SPhilippe Mathieu-Daudé 
3230f25d865SPhilippe Mathieu-Daudé     k->realize = i440fx_realize;
3240f25d865SPhilippe Mathieu-Daudé     k->config_write = i440fx_write_config;
3250f25d865SPhilippe Mathieu-Daudé     k->vendor_id = PCI_VENDOR_ID_INTEL;
3260f25d865SPhilippe Mathieu-Daudé     k->device_id = PCI_DEVICE_ID_INTEL_82441;
3270f25d865SPhilippe Mathieu-Daudé     k->revision = 0x02;
3280f25d865SPhilippe Mathieu-Daudé     k->class_id = PCI_CLASS_BRIDGE_HOST;
3290f25d865SPhilippe Mathieu-Daudé     dc->desc = "Host bridge";
3300f25d865SPhilippe Mathieu-Daudé     dc->vmsd = &vmstate_i440fx;
3310f25d865SPhilippe Mathieu-Daudé     /*
3320f25d865SPhilippe Mathieu-Daudé      * PCI-facing part of the host bridge, not usable without the
3330f25d865SPhilippe Mathieu-Daudé      * host-facing part, which can't be device_add'ed, yet.
3340f25d865SPhilippe Mathieu-Daudé      */
3350f25d865SPhilippe Mathieu-Daudé     dc->user_creatable = false;
3360f25d865SPhilippe Mathieu-Daudé     dc->hotpluggable   = false;
3370f25d865SPhilippe Mathieu-Daudé }
3380f25d865SPhilippe Mathieu-Daudé 
3390f25d865SPhilippe Mathieu-Daudé static const TypeInfo i440fx_info = {
3400f25d865SPhilippe Mathieu-Daudé     .name          = TYPE_I440FX_PCI_DEVICE,
3410f25d865SPhilippe Mathieu-Daudé     .parent        = TYPE_PCI_DEVICE,
3420f25d865SPhilippe Mathieu-Daudé     .instance_size = sizeof(PCII440FXState),
3430f25d865SPhilippe Mathieu-Daudé     .class_init    = i440fx_class_init,
3440f25d865SPhilippe Mathieu-Daudé     .interfaces = (InterfaceInfo[]) {
3450f25d865SPhilippe Mathieu-Daudé         { INTERFACE_CONVENTIONAL_PCI_DEVICE },
3460f25d865SPhilippe Mathieu-Daudé         { },
3470f25d865SPhilippe Mathieu-Daudé     },
3480f25d865SPhilippe Mathieu-Daudé };
3490f25d865SPhilippe Mathieu-Daudé 
i440fx_pcihost_root_bus_path(PCIHostState * host_bridge,PCIBus * rootbus)3500f25d865SPhilippe Mathieu-Daudé static const char *i440fx_pcihost_root_bus_path(PCIHostState *host_bridge,
3510f25d865SPhilippe Mathieu-Daudé                                                 PCIBus *rootbus)
3520f25d865SPhilippe Mathieu-Daudé {
3530f25d865SPhilippe Mathieu-Daudé     return "0000:00";
3540f25d865SPhilippe Mathieu-Daudé }
3550f25d865SPhilippe Mathieu-Daudé 
3560f25d865SPhilippe Mathieu-Daudé static Property i440fx_props[] = {
3570f25d865SPhilippe Mathieu-Daudé     DEFINE_PROP_SIZE(PCI_HOST_PROP_PCI_HOLE64_SIZE, I440FXState,
3580f25d865SPhilippe Mathieu-Daudé                      pci_hole64_size, I440FX_PCI_HOST_HOLE64_SIZE_DEFAULT),
35982feef45SBernhard Beschow     DEFINE_PROP_SIZE(PCI_HOST_BELOW_4G_MEM_SIZE, I440FXState,
36082feef45SBernhard Beschow                      below_4g_mem_size, 0),
36182feef45SBernhard Beschow     DEFINE_PROP_SIZE(PCI_HOST_ABOVE_4G_MEM_SIZE, I440FXState,
36282feef45SBernhard Beschow                      above_4g_mem_size, 0),
3630f25d865SPhilippe Mathieu-Daudé     DEFINE_PROP_BOOL("x-pci-hole64-fix", I440FXState, pci_hole64_fix, true),
364ff0a8cc4SBernhard Beschow     DEFINE_PROP_STRING(I440FX_HOST_PROP_PCI_TYPE, I440FXState, pci_type),
3650f25d865SPhilippe Mathieu-Daudé     DEFINE_PROP_END_OF_LIST(),
3660f25d865SPhilippe Mathieu-Daudé };
3670f25d865SPhilippe Mathieu-Daudé 
i440fx_pcihost_class_init(ObjectClass * klass,void * data)3680f25d865SPhilippe Mathieu-Daudé static void i440fx_pcihost_class_init(ObjectClass *klass, void *data)
3690f25d865SPhilippe Mathieu-Daudé {
3700f25d865SPhilippe Mathieu-Daudé     DeviceClass *dc = DEVICE_CLASS(klass);
3710f25d865SPhilippe Mathieu-Daudé     PCIHostBridgeClass *hc = PCI_HOST_BRIDGE_CLASS(klass);
3720f25d865SPhilippe Mathieu-Daudé 
3730f25d865SPhilippe Mathieu-Daudé     hc->root_bus_path = i440fx_pcihost_root_bus_path;
3740f25d865SPhilippe Mathieu-Daudé     dc->realize = i440fx_pcihost_realize;
3750f25d865SPhilippe Mathieu-Daudé     dc->fw_name = "pci";
3764f67d30bSMarc-André Lureau     device_class_set_props(dc, i440fx_props);
3770f25d865SPhilippe Mathieu-Daudé     /* Reason: needs to be wired up by pc_init1 */
3780f25d865SPhilippe Mathieu-Daudé     dc->user_creatable = false;
37953f64746SEduardo Habkost 
38053f64746SEduardo Habkost     object_class_property_add(klass, PCI_HOST_PROP_PCI_HOLE_START, "uint32",
38153f64746SEduardo Habkost                               i440fx_pcihost_get_pci_hole_start,
38253f64746SEduardo Habkost                               NULL, NULL, NULL);
38353f64746SEduardo Habkost 
38453f64746SEduardo Habkost     object_class_property_add(klass, PCI_HOST_PROP_PCI_HOLE_END, "uint32",
38553f64746SEduardo Habkost                               i440fx_pcihost_get_pci_hole_end,
38653f64746SEduardo Habkost                               NULL, NULL, NULL);
38753f64746SEduardo Habkost 
38853f64746SEduardo Habkost     object_class_property_add(klass, PCI_HOST_PROP_PCI_HOLE64_START, "uint64",
38953f64746SEduardo Habkost                               i440fx_pcihost_get_pci_hole64_start,
39053f64746SEduardo Habkost                               NULL, NULL, NULL);
39153f64746SEduardo Habkost 
39253f64746SEduardo Habkost     object_class_property_add(klass, PCI_HOST_PROP_PCI_HOLE64_END, "uint64",
39353f64746SEduardo Habkost                               i440fx_pcihost_get_pci_hole64_end,
39453f64746SEduardo Habkost                               NULL, NULL, NULL);
3950f25d865SPhilippe Mathieu-Daudé }
3960f25d865SPhilippe Mathieu-Daudé 
3970f25d865SPhilippe Mathieu-Daudé static const TypeInfo i440fx_pcihost_info = {
3980f25d865SPhilippe Mathieu-Daudé     .name          = TYPE_I440FX_PCI_HOST_BRIDGE,
3990f25d865SPhilippe Mathieu-Daudé     .parent        = TYPE_PCI_HOST_BRIDGE,
4000f25d865SPhilippe Mathieu-Daudé     .instance_size = sizeof(I440FXState),
4010f25d865SPhilippe Mathieu-Daudé     .instance_init = i440fx_pcihost_initfn,
4020f25d865SPhilippe Mathieu-Daudé     .class_init    = i440fx_pcihost_class_init,
4030f25d865SPhilippe Mathieu-Daudé };
4040f25d865SPhilippe Mathieu-Daudé 
i440fx_register_types(void)4050f25d865SPhilippe Mathieu-Daudé static void i440fx_register_types(void)
4060f25d865SPhilippe Mathieu-Daudé {
4070f25d865SPhilippe Mathieu-Daudé     type_register_static(&i440fx_info);
4080f25d865SPhilippe Mathieu-Daudé     type_register_static(&i440fx_pcihost_info);
4090f25d865SPhilippe Mathieu-Daudé }
4100f25d865SPhilippe Mathieu-Daudé 
4110f25d865SPhilippe Mathieu-Daudé type_init(i440fx_register_types)
412