diff options
author | Isaku Yamahata <yamahata@valinux.co.jp> | 2012-11-14 15:54:06 -0500 |
---|---|---|
committer | Anthony Liguori <aliguori@us.ibm.com> | 2012-11-26 09:35:36 -0600 |
commit | df2d8b3ed4d2b6406335d274f9537d78ac4e3c0c (patch) | |
tree | a2a693831e61f1afecccfbcaa227615388da10dd /hw | |
parent | 678e7b94b182f846de61e38e8a6499f9c55dbcf0 (diff) |
q35: Introduce q35 pc based chipset emulator
pc q35 based chipset emulator to support pci express natively. Based on
Anthony Liguori's suggestion, the machine name is 'q35-next', with an alias
of 'q35'. At this point, there are no compatibility guarantees. When the
chipset stabilizes more, we will begin to version the machine names.
Major features which still need to be added:
-Migration support (mostly around ahci)
-ACPI hotplug support (pcie hotplug support is working)
-Passthrough support
Signed-off-by: Isaku Yamahata <yamahata@valinux.co.jp>
Signed-off-by: Jason Baron <jbaron@redhat.com>
Signed-off-by: Anthony Liguori <aliguori@us.ibm.com>
Diffstat (limited to 'hw')
-rw-r--r-- | hw/i386/Makefile.objs | 2 | ||||
-rw-r--r-- | hw/pc_q35.c | 220 | ||||
-rw-r--r-- | hw/pci_ids.h | 2 | ||||
-rw-r--r-- | hw/q35.c | 309 | ||||
-rw-r--r-- | hw/q35.h | 150 |
5 files changed, 682 insertions, 1 deletions
diff --git a/hw/i386/Makefile.objs b/hw/i386/Makefile.objs index 9543a69022..0d3f6a8e84 100644 --- a/hw/i386/Makefile.objs +++ b/hw/i386/Makefile.objs @@ -6,7 +6,7 @@ obj-y += pci-hotplug.o smbios.o wdt_ib700.o obj-y += debugcon.o multiboot.o obj-y += pc_piix.o obj-y += pc_sysfw.o -obj-y += lpc_ich9.o +obj-y += lpc_ich9.o q35.o pc_q35.o obj-$(CONFIG_XEN) += xen_platform.o xen_apic.o obj-$(CONFIG_XEN_PCI_PASSTHROUGH) += xen-host-pci-device.o obj-$(CONFIG_XEN_PCI_PASSTHROUGH) += xen_pt.o xen_pt_config_init.o xen_pt_msi.o diff --git a/hw/pc_q35.c b/hw/pc_q35.c new file mode 100644 index 0000000000..142bf8aa1b --- /dev/null +++ b/hw/pc_q35.c @@ -0,0 +1,220 @@ +/* + * Q35 chipset based pc system emulator + * + * Copyright (c) 2003-2004 Fabrice Bellard + * Copyright (c) 2009, 2010 + * Isaku Yamahata <yamahata at valinux co jp> + * VA Linux Systems Japan K.K. + * Copyright (C) 2012 Jason Baron <jbaron@redhat.com> + * + * This is based on pc.c, but heavily modified. + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL + * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ +#include "hw.h" +#include "arch_init.h" +#include "smbus.h" +#include "boards.h" +#include "mc146818rtc.h" +#include "xen.h" +#include "kvm.h" +#include "q35.h" +#include "exec-memory.h" +#include "ich9.h" +#include "hw/ide/pci.h" +#include "hw/ide/ahci.h" +#include "hw/usb.h" + +/* ICH9 AHCI has 6 ports */ +#define MAX_SATA_PORTS 6 + +/* set CMOS shutdown status register (index 0xF) as S3_resume(0xFE) + * BIOS will read it and start S3 resume at POST Entry */ +static void pc_cmos_set_s3_resume(void *opaque, int irq, int level) +{ + ISADevice *s = opaque; + + if (level) { + rtc_set_memory(s, 0xF, 0xFE); + } +} + +/* PC hardware initialisation */ +static void pc_q35_init(QEMUMachineInitArgs *args) +{ + ram_addr_t ram_size = args->ram_size; + const char *cpu_model = args->cpu_model; + const char *kernel_filename = args->kernel_filename; + const char *kernel_cmdline = args->kernel_cmdline; + const char *initrd_filename = args->initrd_filename; + const char *boot_device = args->boot_device; + ram_addr_t below_4g_mem_size, above_4g_mem_size; + Q35PCIHost *q35_host; + PCIBus *host_bus; + PCIDevice *lpc; + BusState *idebus[MAX_SATA_PORTS]; + ISADevice *rtc_state; + ISADevice *floppy; + MemoryRegion *pci_memory; + MemoryRegion *rom_memory; + MemoryRegion *ram_memory; + GSIState *gsi_state; + ISABus *isa_bus; + int pci_enabled = 1; + qemu_irq *cpu_irq; + qemu_irq *gsi; + qemu_irq *i8259; + int i; + ICH9LPCState *ich9_lpc; + PCIDevice *ahci; + qemu_irq *cmos_s3; + + pc_cpus_init(cpu_model); + + if (ram_size >= 0xb0000000) { + above_4g_mem_size = ram_size - 0xb0000000; + below_4g_mem_size = 0xb0000000; + } else { + above_4g_mem_size = 0; + below_4g_mem_size = ram_size; + } + + /* pci enabled */ + if (pci_enabled) { + pci_memory = g_new(MemoryRegion, 1); + memory_region_init(pci_memory, "pci", INT64_MAX); + rom_memory = pci_memory; + } else { + pci_memory = NULL; + rom_memory = get_system_memory(); + } + + /* allocate ram and load rom/bios */ + if (!xen_enabled()) { + pc_memory_init(get_system_memory(), kernel_filename, kernel_cmdline, + initrd_filename, below_4g_mem_size, above_4g_mem_size, + rom_memory, &ram_memory); + } + + /* irq lines */ + gsi_state = g_malloc0(sizeof(*gsi_state)); + if (kvm_irqchip_in_kernel()) { + kvm_pc_setup_irq_routing(pci_enabled); + gsi = qemu_allocate_irqs(kvm_pc_gsi_handler, gsi_state, + GSI_NUM_PINS); + } else { + gsi = qemu_allocate_irqs(gsi_handler, gsi_state, GSI_NUM_PINS); + } + + /* create pci host bus */ + q35_host = Q35_HOST_DEVICE(qdev_create(NULL, TYPE_Q35_HOST_DEVICE)); + + q35_host->mch.ram_memory = ram_memory; + q35_host->mch.pci_address_space = pci_memory; + q35_host->mch.system_memory = get_system_memory(); + q35_host->mch.address_space_io = get_system_io();; + q35_host->mch.below_4g_mem_size = below_4g_mem_size; + q35_host->mch.above_4g_mem_size = above_4g_mem_size; + /* pci */ + qdev_init_nofail(DEVICE(q35_host)); + host_bus = q35_host->host.pci.bus; + /* create ISA bus */ + lpc = pci_create_simple_multifunction(host_bus, PCI_DEVFN(ICH9_LPC_DEV, + ICH9_LPC_FUNC), true, + TYPE_ICH9_LPC_DEVICE); + ich9_lpc = ICH9_LPC_DEVICE(lpc); + ich9_lpc->pic = gsi; + ich9_lpc->ioapic = gsi_state->ioapic_irq; + pci_bus_irqs(host_bus, ich9_lpc_set_irq, ich9_lpc_map_irq, ich9_lpc, + ICH9_LPC_NB_PIRQS); + isa_bus = ich9_lpc->isa_bus; + + /*end early*/ + isa_bus_irqs(isa_bus, gsi); + + if (kvm_irqchip_in_kernel()) { + i8259 = kvm_i8259_init(isa_bus); + } else if (xen_enabled()) { + i8259 = xen_interrupt_controller_init(); + } else { + cpu_irq = pc_allocate_cpu_irq(); + i8259 = i8259_init(isa_bus, cpu_irq[0]); + } + + for (i = 0; i < ISA_NUM_IRQS; i++) { + gsi_state->i8259_irq[i] = i8259[i]; + } + if (pci_enabled) { + ioapic_init_gsi(gsi_state, NULL); + } + + pc_register_ferr_irq(gsi[13]); + + /* init basic PC hardware */ + pc_basic_device_init(isa_bus, gsi, &rtc_state, &floppy, false); + + /* connect pm stuff to lpc */ + cmos_s3 = qemu_allocate_irqs(pc_cmos_set_s3_resume, rtc_state, 1); + ich9_lpc_pm_init(lpc, *cmos_s3); + + /* ahci and SATA device, for q35 1 ahci controller is built-in */ + ahci = pci_create_simple_multifunction(host_bus, + PCI_DEVFN(ICH9_SATA1_DEV, + ICH9_SATA1_FUNC), + true, "ich9-ahci"); + idebus[0] = qdev_get_child_bus(&ahci->qdev, "ide.0"); + idebus[1] = qdev_get_child_bus(&ahci->qdev, "ide.1"); + + if (usb_enabled(false)) { + /* Should we create 6 UHCI according to ich9 spec? */ + ehci_create_ich9_with_companions(host_bus, 0x1d); + } + + /* TODO: Populate SPD eeprom data. */ + smbus_eeprom_init(ich9_smb_init(host_bus, + PCI_DEVFN(ICH9_SMB_DEV, ICH9_SMB_FUNC), + 0xb100), + 8, NULL, 0); + + pc_cmos_init(below_4g_mem_size, above_4g_mem_size, boot_device, + floppy, idebus[0], idebus[1], rtc_state); + + /* the rest devices to which pci devfn is automatically assigned */ + pc_vga_init(isa_bus, host_bus); + audio_init(isa_bus, host_bus); + pc_nic_init(isa_bus, host_bus); + if (pci_enabled) { + pc_pci_device_init(host_bus); + } +} + +static QEMUMachine pc_q35_machine = { + .name = "q35-next", + .alias = "q35", + .desc = "Q35 chipset PC", + .init = pc_q35_init, + .max_cpus = 255, +}; + +static void pc_q35_machine_init(void) +{ + qemu_register_machine(&pc_q35_machine); +} + +machine_init(pc_q35_machine_init); diff --git a/hw/pci_ids.h b/hw/pci_ids.h index d1e83ddd06..5df7245349 100644 --- a/hw/pci_ids.h +++ b/hw/pci_ids.h @@ -138,6 +138,8 @@ #define PCI_DEVICE_ID_INTEL_82801I_EHCI2 0x293c #define PCI_DEVICE_ID_INTEL_82599_SFP_VF 0x10ed +#define PCI_DEVICE_ID_INTEL_Q35_MCH 0x29c0 + #define PCI_VENDOR_ID_XEN 0x5853 #define PCI_DEVICE_ID_XEN_PLATFORM 0x0001 diff --git a/hw/q35.c b/hw/q35.c new file mode 100644 index 0000000000..efebc2786a --- /dev/null +++ b/hw/q35.c @@ -0,0 +1,309 @@ +/* + * QEMU MCH/ICH9 PCI Bridge Emulation + * + * Copyright (c) 2006 Fabrice Bellard + * Copyright (c) 2009, 2010, 2011 + * Isaku Yamahata <yamahata at valinux co jp> + * VA Linux Systems Japan K.K. + * Copyright (C) 2012 Jason Baron <jbaron@redhat.com> + * + * This is based on piix_pci.c, but heavily modified. + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL + * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ +#include "hw.h" +#include "q35.h" + +/**************************************************************************** + * Q35 host + */ + +static int q35_host_init(SysBusDevice *dev) +{ + PCIBus *b; + PCIHostState *pci = FROM_SYSBUS(PCIHostState, dev); + Q35PCIHost *s = Q35_HOST_DEVICE(&dev->qdev); + + memory_region_init_io(&pci->conf_mem, &pci_host_conf_le_ops, pci, + "pci-conf-idx", 4); + sysbus_add_io(dev, MCH_HOST_BRIDGE_CONFIG_ADDR, &pci->conf_mem); + sysbus_init_ioports(&pci->busdev, MCH_HOST_BRIDGE_CONFIG_ADDR, 4); + + memory_region_init_io(&pci->data_mem, &pci_host_data_le_ops, pci, + "pci-conf-data", 4); + sysbus_add_io(dev, MCH_HOST_BRIDGE_CONFIG_DATA, &pci->data_mem); + sysbus_init_ioports(&pci->busdev, MCH_HOST_BRIDGE_CONFIG_DATA, 4); + + if (pcie_host_init(&s->host) < 0) { + return -1; + } + b = pci_bus_new(&s->host.pci.busdev.qdev, "pcie.0", + s->mch.pci_address_space, s->mch.address_space_io, 0); + s->host.pci.bus = b; + qdev_set_parent_bus(DEVICE(&s->mch), BUS(b)); + qdev_init_nofail(DEVICE(&s->mch)); + + return 0; +} + +static Property mch_props[] = { + DEFINE_PROP_UINT64("MCFG", Q35PCIHost, host.base_addr, + MCH_HOST_BRIDGE_PCIEXBAR_DEFAULT), + DEFINE_PROP_END_OF_LIST(), +}; + +static void q35_host_class_init(ObjectClass *klass, void *data) +{ + DeviceClass *dc = DEVICE_CLASS(klass); + SysBusDeviceClass *k = SYS_BUS_DEVICE_CLASS(klass); + + k->init = q35_host_init; + dc->props = mch_props; +} + +static void q35_host_initfn(Object *obj) +{ + Q35PCIHost *s = Q35_HOST_DEVICE(obj); + + object_initialize(&s->mch, TYPE_MCH_PCI_DEVICE); + object_property_add_child(OBJECT(s), "mch", OBJECT(&s->mch), NULL); + qdev_prop_set_uint32(DEVICE(&s->mch), "addr", PCI_DEVFN(0, 0)); + qdev_prop_set_bit(DEVICE(&s->mch), "multifunction", false); +} + +static const TypeInfo q35_host_info = { + .name = TYPE_Q35_HOST_DEVICE, + .parent = TYPE_PCIE_HOST_BRIDGE, + .instance_size = sizeof(Q35PCIHost), + .instance_init = q35_host_initfn, + .class_init = q35_host_class_init, +}; + +/**************************************************************************** + * MCH D0:F0 + */ + +/* PCIe MMCFG */ +static void mch_update_pciexbar(MCHPCIState *mch) +{ + PCIDevice *pci_dev = &mch->d; + BusState *bus = qdev_get_parent_bus(&pci_dev->qdev); + DeviceState *qdev = bus->parent; + Q35PCIHost *s = Q35_HOST_DEVICE(qdev); + + uint64_t pciexbar; + int enable; + uint64_t addr; + uint64_t addr_mask; + uint32_t length; + + pciexbar = pci_get_quad(pci_dev->config + MCH_HOST_BRIDGE_PCIEXBAR); + enable = pciexbar & MCH_HOST_BRIDGE_PCIEXBAREN; + addr_mask = MCH_HOST_BRIDGE_PCIEXBAR_ADMSK; + switch (pciexbar & MCH_HOST_BRIDGE_PCIEXBAR_LENGTH_MASK) { + case MCH_HOST_BRIDGE_PCIEXBAR_LENGTH_256M: + length = 256 * 1024 * 1024; + break; + case MCH_HOST_BRIDGE_PCIEXBAR_LENGTH_128M: + length = 128 * 1024 * 1024; + addr_mask |= MCH_HOST_BRIDGE_PCIEXBAR_128ADMSK | + MCH_HOST_BRIDGE_PCIEXBAR_64ADMSK; + break; + case MCH_HOST_BRIDGE_PCIEXBAR_LENGTH_64M: + length = 64 * 1024 * 1024; + addr_mask |= MCH_HOST_BRIDGE_PCIEXBAR_64ADMSK; + break; + case MCH_HOST_BRIDGE_PCIEXBAR_LENGTH_RVD: + default: + enable = 0; + length = 0; + abort(); + break; + } + addr = pciexbar & addr_mask; + pcie_host_mmcfg_update(&s->host, enable, addr, length); +} + +/* PAM */ +static void mch_update_pam(MCHPCIState *mch) +{ + int i; + + memory_region_transaction_begin(); + for (i = 0; i < 13; i++) { + pam_update(&mch->pam_regions[i], i, + mch->d.config[MCH_HOST_BRIDGE_PAM0 + ((i + 1) / 2)]); + } + memory_region_transaction_commit(); +} + +/* SMRAM */ +static void mch_update_smram(MCHPCIState *mch) +{ + memory_region_transaction_begin(); + smram_update(&mch->smram_region, mch->d.config[MCH_HOST_BRDIGE_SMRAM], + mch->smm_enabled); + memory_region_transaction_commit(); +} + +static void mch_set_smm(int smm, void *arg) +{ + MCHPCIState *mch = arg; + + memory_region_transaction_begin(); + smram_set_smm(&mch->smm_enabled, smm, mch->d.config[MCH_HOST_BRDIGE_SMRAM], + &mch->smram_region); + memory_region_transaction_commit(); +} + +static void mch_write_config(PCIDevice *d, + uint32_t address, uint32_t val, int len) +{ + MCHPCIState *mch = MCH_PCI_DEVICE(d); + + /* XXX: implement SMRAM.D_LOCK */ + pci_default_write_config(d, address, val, len); + + if (ranges_overlap(address, len, MCH_HOST_BRIDGE_PAM0, + MCH_HOST_BRIDGE_PAM_SIZE)) { + mch_update_pam(mch); + } + + if (ranges_overlap(address, len, MCH_HOST_BRIDGE_PCIEXBAR, + MCH_HOST_BRIDGE_PCIEXBAR_SIZE)) { + mch_update_pciexbar(mch); + } + + if (ranges_overlap(address, len, MCH_HOST_BRDIGE_SMRAM, + MCH_HOST_BRDIGE_SMRAM_SIZE)) { + mch_update_smram(mch); + } +} + +static void mch_update(MCHPCIState *mch) +{ + mch_update_pciexbar(mch); + mch_update_pam(mch); + mch_update_smram(mch); +} + +static int mch_post_load(void *opaque, int version_id) +{ + MCHPCIState *mch = opaque; + mch_update(mch); + return 0; +} + +static const VMStateDescription vmstate_mch = { + .name = "mch", + .version_id = 1, + .minimum_version_id = 1, + .minimum_version_id_old = 1, + .post_load = mch_post_load, + .fields = (VMStateField []) { + VMSTATE_PCI_DEVICE(d, MCHPCIState), + VMSTATE_UINT8(smm_enabled, MCHPCIState), + VMSTATE_END_OF_LIST() + } +}; + +static void mch_reset(DeviceState *qdev) +{ + PCIDevice *d = PCI_DEVICE(qdev); + MCHPCIState *mch = MCH_PCI_DEVICE(d); + + pci_set_quad(d->config + MCH_HOST_BRIDGE_PCIEXBAR, + MCH_HOST_BRIDGE_PCIEXBAR_DEFAULT); + + d->config[MCH_HOST_BRDIGE_SMRAM] = MCH_HOST_BRIDGE_SMRAM_DEFAULT; + + mch_update(mch); +} + +static int mch_init(PCIDevice *d) +{ + int i; + hwaddr pci_hole64_size; + MCHPCIState *mch = MCH_PCI_DEVICE(d); + + /* setup pci memory regions */ + memory_region_init_alias(&mch->pci_hole, "pci-hole", + mch->pci_address_space, + mch->below_4g_mem_size, + 0x100000000ULL - mch->below_4g_mem_size); + memory_region_add_subregion(mch->system_memory, mch->below_4g_mem_size, + &mch->pci_hole); + pci_hole64_size = (sizeof(hwaddr) == 4 ? 0 : + ((uint64_t)1 << 62)); + memory_region_init_alias(&mch->pci_hole_64bit, "pci-hole64", + mch->pci_address_space, + 0x100000000ULL + mch->above_4g_mem_size, + pci_hole64_size); + if (pci_hole64_size) { + memory_region_add_subregion(mch->system_memory, + 0x100000000ULL + mch->above_4g_mem_size, + &mch->pci_hole_64bit); + } + /* smram */ + cpu_smm_register(&mch_set_smm, mch); + memory_region_init_alias(&mch->smram_region, "smram-region", + mch->pci_address_space, 0xa0000, 0x20000); + memory_region_add_subregion_overlap(mch->system_memory, 0xa0000, + &mch->smram_region, 1); + memory_region_set_enabled(&mch->smram_region, false); + init_pam(mch->ram_memory, mch->system_memory, mch->pci_address_space, + &mch->pam_regions[0], PAM_BIOS_BASE, PAM_BIOS_SIZE); + for (i = 0; i < 12; ++i) { + init_pam(mch->ram_memory, mch->system_memory, mch->pci_address_space, + &mch->pam_regions[i+1], PAM_EXPAN_BASE + i * PAM_EXPAN_SIZE, + PAM_EXPAN_SIZE); + } + return 0; +} + +static void mch_class_init(ObjectClass *klass, void *data) +{ + PCIDeviceClass *k = PCI_DEVICE_CLASS(klass); + DeviceClass *dc = DEVICE_CLASS(klass); + + k->init = mch_init; + k->config_write = mch_write_config; + dc->reset = mch_reset; + dc->desc = "Host bridge"; + dc->vmsd = &vmstate_mch; + k->vendor_id = PCI_VENDOR_ID_INTEL; + k->device_id = PCI_DEVICE_ID_INTEL_Q35_MCH; + k->revision = MCH_HOST_BRIDGE_REVISION_DEFUALT; + k->class_id = PCI_CLASS_BRIDGE_HOST; +} + +static const TypeInfo mch_info = { + .name = TYPE_MCH_PCI_DEVICE, + .parent = TYPE_PCI_DEVICE, + .instance_size = sizeof(MCHPCIState), + .class_init = mch_class_init, +}; + +static void q35_register(void) +{ + type_register_static(&mch_info); + type_register_static(&q35_host_info); +} + +type_init(q35_register); diff --git a/hw/q35.h b/hw/q35.h new file mode 100644 index 0000000000..e34f7c165f --- /dev/null +++ b/hw/q35.h @@ -0,0 +1,150 @@ +/* + * q35.h + * + * Copyright (c) 2009 Isaku Yamahata <yamahata at valinux co jp> + * VA Linux Systems Japan K.K. + * Copyright (C) 2012 Jason Baron <jbaron@redhat.com> + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, see <http://www.gnu.org/licenses/> + */ + +#ifndef HW_Q35_H +#define HW_Q35_H + +#include "hw.h" +#include "range.h" +#include "isa.h" +#include "sysbus.h" +#include "pc.h" +#include "apm.h" +#include "apic.h" +#include "pci.h" +#include "pcie_host.h" +#include "acpi.h" +#include "acpi_ich9.h" +#include "pam.h" + +#define TYPE_Q35_HOST_DEVICE "q35-pcihost" +#define Q35_HOST_DEVICE(obj) \ + OBJECT_CHECK(Q35PCIHost, (obj), TYPE_Q35_HOST_DEVICE) + +#define TYPE_MCH_PCI_DEVICE "mch" +#define MCH_PCI_DEVICE(obj) \ + OBJECT_CHECK(MCHPCIState, (obj), TYPE_MCH_PCI_DEVICE) + +typedef struct MCHPCIState { + PCIDevice d; + MemoryRegion *ram_memory; + MemoryRegion *pci_address_space; + MemoryRegion *system_memory; + MemoryRegion *address_space_io; + PAMMemoryRegion pam_regions[13]; + MemoryRegion smram_region; + MemoryRegion pci_hole; + MemoryRegion pci_hole_64bit; + uint8_t smm_enabled; + ram_addr_t below_4g_mem_size; + ram_addr_t above_4g_mem_size; +} MCHPCIState; + +typedef struct Q35PCIHost { + PCIExpressHost host; + MCHPCIState mch; +} Q35PCIHost; + +#define Q35_MASK(bit, ms_bit, ls_bit) \ +((uint##bit##_t)(((1ULL << ((ms_bit) + 1)) - 1) & ~((1ULL << ls_bit) - 1))) + +/* + * gmch part + */ + +/* PCI configuration */ +#define MCH_HOST_BRIDGE "MCH" + +#define MCH_HOST_BRIDGE_CONFIG_ADDR 0xcf8 +#define MCH_HOST_BRIDGE_CONFIG_DATA 0xcfc + +/* D0:F0 configuration space */ +#define MCH_HOST_BRIDGE_REVISION_DEFUALT 0x0 + +#define MCH_HOST_BRIDGE_PCIEXBAR 0x60 /* 64bit register */ +#define MCH_HOST_BRIDGE_PCIEXBAR_SIZE 8 /* 64bit register */ +#define MCH_HOST_BRIDGE_PCIEXBAR_DEFAULT 0xb0000000 +#define MCH_HOST_BRIDGE_PCIEXBAR_ADMSK Q35_MASK(64, 35, 28) +#define MCH_HOST_BRIDGE_PCIEXBAR_128ADMSK ((uint64_t)(1 << 26)) +#define MCH_HOST_BRIDGE_PCIEXBAR_64ADMSK ((uint64_t)(1 << 25)) +#define MCH_HOST_BRIDGE_PCIEXBAR_LENGTH_MASK ((uint64_t)(0x3 << 1)) +#define MCH_HOST_BRIDGE_PCIEXBAR_LENGTH_256M ((uint64_t)(0x0 << 1)) +#define MCH_HOST_BRIDGE_PCIEXBAR_LENGTH_128M ((uint64_t)(0x1 << 1)) +#define MCH_HOST_BRIDGE_PCIEXBAR_LENGTH_64M ((uint64_t)(0x2 << 1)) +#define MCH_HOST_BRIDGE_PCIEXBAR_LENGTH_RVD ((uint64_t)(0x3 << 1)) +#define MCH_HOST_BRIDGE_PCIEXBAREN ((uint64_t)1) + +#define MCH_HOST_BRIDGE_PAM_NB 7 +#define MCH_HOST_BRIDGE_PAM_SIZE 7 +#define MCH_HOST_BRIDGE_PAM0 0x90 +#define MCH_HOST_BRIDGE_PAM_BIOS_AREA 0xf0000 +#define MCH_HOST_BRIDGE_PAM_AREA_SIZE 0x10000 /* 16KB */ +#define MCH_HOST_BRIDGE_PAM1 0x91 +#define MCH_HOST_BRIDGE_PAM_EXPAN_AREA 0xc0000 +#define MCH_HOST_BRIDGE_PAM_EXPAN_SIZE 0x04000 +#define MCH_HOST_BRIDGE_PAM2 0x92 +#define MCH_HOST_BRIDGE_PAM3 0x93 +#define MCH_HOST_BRIDGE_PAM4 0x94 +#define MCH_HOST_BRIDGE_PAM_EXBIOS_AREA 0xe0000 +#define MCH_HOST_BRIDGE_PAM_EXBIOS_SIZE 0x04000 +#define MCH_HOST_BRIDGE_PAM5 0x95 +#define MCH_HOST_BRIDGE_PAM6 0x96 +#define MCH_HOST_BRIDGE_PAM_WE_HI ((uint8_t)(0x2 << 4)) +#define MCH_HOST_BRIDGE_PAM_RE_HI ((uint8_t)(0x1 << 4)) +#define MCH_HOST_BRIDGE_PAM_HI_MASK ((uint8_t)(0x3 << 4)) +#define MCH_HOST_BRIDGE_PAM_WE_LO ((uint8_t)0x2) +#define MCH_HOST_BRIDGE_PAM_RE_LO ((uint8_t)0x1) +#define MCH_HOST_BRIDGE_PAM_LO_MASK ((uint8_t)0x3) +#define MCH_HOST_BRIDGE_PAM_WE ((uint8_t)0x2) +#define MCH_HOST_BRIDGE_PAM_RE ((uint8_t)0x1) +#define MCH_HOST_BRIDGE_PAM_MASK ((uint8_t)0x3) + +#define MCH_HOST_BRDIGE_SMRAM 0x9d +#define MCH_HOST_BRDIGE_SMRAM_SIZE 1 +#define MCH_HOST_BRIDGE_SMRAM_DEFAULT ((uint8_t)0x2) +#define MCH_HOST_BRIDGE_SMRAM_D_OPEN ((uint8_t)(1 << 6)) +#define MCH_HOST_BRIDGE_SMRAM_D_CLS ((uint8_t)(1 << 5)) +#define MCH_HOST_BRIDGE_SMRAM_D_LCK ((uint8_t)(1 << 4)) +#define MCH_HOST_BRIDGE_SMRAM_G_SMRAME ((uint8_t)(1 << 3)) +#define MCH_HOST_BRIDGE_SMRAM_C_BASE_SEG_MASK ((uint8_t)0x7) +#define MCH_HOST_BRIDGE_SMRAM_C_BASE_SEG ((uint8_t)0x2) /* hardwired to b010 */ +#define MCH_HOST_BRIDGE_SMRAM_C_BASE 0xa0000 +#define MCH_HOST_BRIDGE_SMRAM_C_END 0xc0000 +#define MCH_HOST_BRIDGE_SMRAM_C_SIZE 0x20000 +#define MCH_HOST_BRIDGE_UPPER_SYSTEM_BIOS_END 0x100000 + +#define MCH_HOST_BRIDGE_ESMRAMC 0x9e +#define MCH_HOST_BRDIGE_ESMRAMC_H_SMRAME ((uint8_t)(1 << 6)) +#define MCH_HOST_BRDIGE_ESMRAMC_E_SMERR ((uint8_t)(1 << 5)) +#define MCH_HOST_BRDIGE_ESMRAMC_SM_CACHE ((uint8_t)(1 << 4)) +#define MCH_HOST_BRDIGE_ESMRAMC_SM_L1 ((uint8_t)(1 << 3)) +#define MCH_HOST_BRDIGE_ESMRAMC_SM_L2 ((uint8_t)(1 << 2)) +#define MCH_HOST_BRDIGE_ESMRAMC_TSEG_SZ_MASK ((uint8_t)(0x3 << 1)) +#define MCH_HOST_BRDIGE_ESMRAMC_TSEG_SZ_1MB ((uint8_t)(0x0 << 1)) +#define MCH_HOST_BRDIGE_ESMRAMC_TSEG_SZ_2MB ((uint8_t)(0x1 << 1)) +#define MCH_HOST_BRDIGE_ESMRAMC_TSEG_SZ_8MB ((uint8_t)(0x2 << 1)) +#define MCH_HOST_BRDIGE_ESMRAMC_T_EN ((uint8_t)1) + +/* D1:F0 PCIE* port*/ +#define MCH_PCIE_DEV 1 +#define MCH_PCIE_FUNC 0 + +#endif /* HW_Q35_H */ |