@@ -18,6 +18,7 @@
/*
* 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 is based on acpi.c.
*/
@@ -43,13 +44,13 @@ static void pm_ioport_write_fallback(void *opaque, uint32_t addr, int len,
uint32_t val);
static uint32_t pm_ioport_read_fallback(void *opaque, uint32_t addr, int len);
-static void pm_update_sci(ICH9_LPCPmRegs *pm)
+static void pm_update_sci(ICH9LPCPMRegs *pm)
{
int sci_level, pm1a_sts;
- pm1a_sts = acpi_pm1_evt_get_sts(&pm->pm1a, pm->tmr.overflow_time);
+ pm1a_sts = acpi_pm1_evt_get_sts(&pm->acpi_regs);
- sci_level = (((pm1a_sts & pm->pm1a.en) &
+ sci_level = (((pm1a_sts & pm->acpi_regs.pm1.evt.en) &
(ACPI_BITMASK_RT_CLOCK_ENABLE |
ACPI_BITMASK_POWER_BUTTON_ENABLE |
ACPI_BITMASK_GLOBAL_LOCK_ENABLE |
@@ -57,24 +58,24 @@ static void pm_update_sci(ICH9_LPCPmRegs *pm)
qemu_set_irq(pm->irq, sci_level);
/* schedule a timer interruption if needed */
- acpi_pm_tmr_update(&pm->tmr,
- (pm->pm1a.en & ACPI_BITMASK_TIMER_ENABLE) &&
+ acpi_pm_tmr_update(&pm->acpi_regs,
+ (pm->acpi_regs.pm1.evt.en & ACPI_BITMASK_TIMER_ENABLE) &&
!(pm1a_sts & ACPI_BITMASK_TIMER_STATUS));
}
-static void ich9_pm_update_sci_fn(ACPIPMTimer *tmr)
+static void ich9_pm_update_sci_fn(ACPIREGS *regs)
{
- ICH9_LPCPmRegs *pm = container_of(tmr, ICH9_LPCPmRegs, tmr);
+ ICH9LPCPMRegs *pm = container_of(regs, ICH9LPCPMRegs, acpi_regs);
pm_update_sci(pm);
}
static void pm_ioport_writeb(void *opaque, uint32_t addr, uint32_t val)
{
- ICH9_LPCPmRegs *pm = opaque;
+ ICH9LPCPMRegs *pm = opaque;
switch (addr & ICH9_PMIO_MASK) {
case ICH9_PMIO_GPE0_STS ... (ICH9_PMIO_GPE0_STS + ICH9_PMIO_GPE0_LEN - 1):
- acpi_gpe_ioport_writeb(&pm->gpe0, addr, val);
+ acpi_gpe_ioport_writeb(&pm->acpi_regs, addr, val);
break;
default:
break;
@@ -85,12 +86,12 @@ static void pm_ioport_writeb(void *opaque, uint32_t addr, uint32_t val)
static uint32_t pm_ioport_readb(void *opaque, uint32_t addr)
{
- ICH9_LPCPmRegs *pm = opaque;
+ ICH9LPCPMRegs *pm = opaque;
uint32_t val = 0;
switch (addr & ICH9_PMIO_MASK) {
case ICH9_PMIO_GPE0_STS ... (ICH9_PMIO_GPE0_STS + ICH9_PMIO_GPE0_LEN - 1):
- val = acpi_gpe_ioport_readb(&pm->gpe0, addr);
+ val = acpi_gpe_ioport_readb(&pm->acpi_regs, addr);
break;
default:
val = 0;
@@ -102,19 +103,19 @@ static uint32_t pm_ioport_readb(void *opaque, uint32_t addr)
static void pm_ioport_writew(void *opaque, uint32_t addr, uint32_t val)
{
- ICH9_LPCPmRegs *pm = opaque;
+ ICH9LPCPMRegs *pm = opaque;
switch (addr & ICH9_PMIO_MASK) {
case ICH9_PMIO_PM1_STS:
- acpi_pm1_evt_write_sts(&pm->pm1a, &pm->tmr, val);
+ acpi_pm1_evt_write_sts(&pm->acpi_regs, val);
pm_update_sci(pm);
break;
case ICH9_PMIO_PM1_EN:
- pm->pm1a.en = val;
+ pm->acpi_regs.pm1.evt.en = val;
pm_update_sci(pm);
break;
case ICH9_PMIO_PM1_CNT:
- acpi_pm1_cnt_write(&pm->pm1a, &pm->pm1_cnt, val);
+ acpi_pm1_cnt_write(&pm->acpi_regs, val, 0);
break;
default:
pm_ioport_write_fallback(opaque, addr, 2, val);
@@ -125,18 +126,18 @@ static void pm_ioport_writew(void *opaque, uint32_t addr, uint32_t val)
static uint32_t pm_ioport_readw(void *opaque, uint32_t addr)
{
- ICH9_LPCPmRegs *pm = opaque;
+ ICH9LPCPMRegs *pm = opaque;
uint32_t val;
switch (addr & ICH9_PMIO_MASK) {
case ICH9_PMIO_PM1_STS:
- val = acpi_pm1_evt_get_sts(&pm->pm1a, pm->tmr.overflow_time);
+ val = acpi_pm1_evt_get_sts(&pm->acpi_regs);
break;
case ICH9_PMIO_PM1_EN:
- val = pm->pm1a.en;
+ val = pm->acpi_regs.pm1.evt.en;
break;
case ICH9_PMIO_PM1_CNT:
- val = pm->pm1_cnt.cnt;
+ val = pm->acpi_regs.pm1.cnt.cnt;
break;
default:
val = pm_ioport_read_fallback(opaque, addr, 2);
@@ -148,7 +149,7 @@ static uint32_t pm_ioport_readw(void *opaque, uint32_t addr)
static void pm_ioport_writel(void *opaque, uint32_t addr, uint32_t val)
{
- ICH9_LPCPmRegs *pm = opaque;
+ ICH9LPCPMRegs *pm = opaque;
switch (addr & ICH9_PMIO_MASK) {
case ICH9_PMIO_SMI_EN:
@@ -163,12 +164,12 @@ static void pm_ioport_writel(void *opaque, uint32_t addr, uint32_t val)
static uint32_t pm_ioport_readl(void *opaque, uint32_t addr)
{
- ICH9_LPCPmRegs *pm = opaque;
+ ICH9LPCPMRegs *pm = opaque;
uint32_t val;
switch (addr & ICH9_PMIO_MASK) {
case ICH9_PMIO_PM1_TMR:
- val = acpi_pm_tmr_get(&pm->tmr);
+ val = acpi_pm_tmr_get(&pm->acpi_regs);
break;
case ICH9_PMIO_SMI_EN:
val = pm->smi_en;
@@ -215,7 +216,7 @@ static uint32_t pm_ioport_read_fallback(void *opaque, uint32_t addr, int len)
return val;
}
-void ich9_pm_iospace_update(ICH9_LPCPmRegs *pm, uint32_t pm_io_base)
+void ich9_pm_iospace_update(ICH9LPCPMRegs *pm, uint32_t pm_io_base)
{
ICH9_DEBUG("to 0x%x\n", pm_io_base);
@@ -238,12 +239,12 @@ void ich9_pm_iospace_update(ICH9_LPCPmRegs *pm, uint32_t pm_io_base)
register_ioport_read(pm_io_base, ICH9_PMIO_SIZE, 4, pm_ioport_readl, pm);
pm->pm_io_base = pm_io_base;
- acpi_gpe_blk(&pm->gpe0, pm_io_base + ICH9_PMIO_GPE0_STS);
+ acpi_gpe_blk(&pm->acpi_regs, pm_io_base + ICH9_PMIO_GPE0_STS);
}
static int ich9_pm_post_load(void *opaque, int version_id)
{
- ICH9_LPCPmRegs *pm = opaque;
+ ICH9LPCPMRegs *pm = opaque;
uint32_t pm_io_base = pm->pm_io_base;
pm->pm_io_base = 0;
ich9_pm_iospace_update(pm, pm_io_base);
@@ -268,48 +269,47 @@ const VMStateDescription vmstate_ich9_pm = {
.minimum_version_id_old = 1,
.post_load = ich9_pm_post_load,
.fields = (VMStateField[]) {
- VMSTATE_UINT16(pm1a.sts, ICH9_LPCPmRegs),
- VMSTATE_UINT16(pm1a.en, ICH9_LPCPmRegs),
- VMSTATE_UINT16(pm1_cnt.cnt, ICH9_LPCPmRegs),
- VMSTATE_TIMER(tmr.timer, ICH9_LPCPmRegs),
- VMSTATE_INT64(tmr.overflow_time, ICH9_LPCPmRegs),
- VMSTATE_GPE_ARRAY(gpe0.sts, ICH9_LPCPmRegs),
- VMSTATE_GPE_ARRAY(gpe0.en, ICH9_LPCPmRegs),
- VMSTATE_UINT32(smi_en, ICH9_LPCPmRegs),
- VMSTATE_UINT32(smi_sts, ICH9_LPCPmRegs),
+ VMSTATE_UINT16(acpi_regs.pm1.evt.sts, ICH9LPCPMRegs),
+ VMSTATE_UINT16(acpi_regs.pm1.evt.en, ICH9LPCPMRegs),
+ VMSTATE_UINT16(acpi_regs.pm1.cnt.cnt, ICH9LPCPMRegs),
+ VMSTATE_TIMER(acpi_regs.tmr.timer, ICH9LPCPMRegs),
+ VMSTATE_INT64(acpi_regs.tmr.overflow_time, ICH9LPCPMRegs),
+ VMSTATE_GPE_ARRAY(acpi_regs.gpe.sts, ICH9LPCPMRegs),
+ VMSTATE_GPE_ARRAY(acpi_regs.gpe.en, ICH9LPCPMRegs),
+ VMSTATE_UINT32(smi_en, ICH9LPCPMRegs),
+ VMSTATE_UINT32(smi_sts, ICH9LPCPMRegs),
VMSTATE_END_OF_LIST()
}
};
static void pm_reset(void *opaque)
{
- ICH9_LPCPmRegs *pm = opaque;
+ ICH9LPCPMRegs *pm = opaque;
ich9_pm_iospace_update(pm, 0);
- acpi_pm1_evt_reset(&pm->pm1a);
- acpi_pm1_cnt_reset(&pm->pm1_cnt);
- acpi_pm_tmr_reset(&pm->tmr);
- acpi_gpe_reset(&pm->gpe0);
+ acpi_pm1_evt_reset(&pm->acpi_regs);
+ acpi_pm1_cnt_reset(&pm->acpi_regs);
+ acpi_pm_tmr_reset(&pm->acpi_regs);
+ acpi_gpe_reset(&pm->acpi_regs);
pm_update_sci(pm);
}
-static void pm_powerdown(void *opaque, int irq, int power_failing)
+static void pm_powerdown_req(Notifier *n, void *opaque)
{
- ICH9_LPCPmRegs *pm = opaque;
- ACPIPM1EVT *pm1a = pm ? &pm->pm1a : NULL;
- ACPIPMTimer *tmr = pm ? &pm->tmr : NULL;
+ ICH9LPCPMRegs *pm = container_of(n, ICH9LPCPMRegs, powerdown_notifier);
- acpi_pm1_evt_power_down(pm1a, tmr);
+ acpi_pm1_evt_power_down(&pm->acpi_regs);
}
-void ich9_pm_init(ICH9_LPCPmRegs *pm, qemu_irq sci_irq, qemu_irq cmos_s3)
+void ich9_pm_init(ICH9LPCPMRegs *pm, qemu_irq sci_irq, qemu_irq cmos_s3)
{
- acpi_pm_tmr_init(&pm->tmr, ich9_pm_update_sci_fn);
- acpi_pm1_cnt_init(&pm->pm1_cnt, cmos_s3);
- acpi_gpe_init(&pm->gpe0, ICH9_PMIO_GPE0_LEN);
+ acpi_pm_tmr_init(&pm->acpi_regs, ich9_pm_update_sci_fn);
+ acpi_pm1_cnt_init(&pm->acpi_regs);
+ acpi_gpe_init(&pm->acpi_regs, ICH9_PMIO_GPE0_LEN);
pm->irq = sci_irq;
qemu_register_reset(pm_reset, pm);
- qemu_system_powerdown = *qemu_allocate_irqs(pm_powerdown, pm, 1);
+ pm->powerdown_notifier.notify = pm_powerdown_req;
+ qemu_register_powerdown_notifier(&pm->powerdown_notifier);
}
@@ -23,31 +23,25 @@
#include "acpi.h"
-typedef struct ICH9_LPCPmRegs {
- ACPIPM1EVT pm1a;
-
+typedef struct ICH9LPCPMRegs {
/*
* In ich9 spec says that pm1_cnt register is 32bit width and
* that the upper 16bits are reserved and unused.
* PM1a_CNT_BLK = 2 in FADT so it is defined as uint16_t.
*/
- ACPIPM1CNT pm1_cnt;
-
- ACPIPMTimer tmr;
-
- ACPIGPE gpe0;
-
+ ACPIREGS acpi_regs;
uint32_t smi_en;
uint32_t smi_sts;
qemu_irq irq; /* SCI */
uint32_t pm_io_base;
-} ICH9_LPCPmRegs;
+ Notifier powerdown_notifier;
+} ICH9LPCPMRegs;
-void ich9_pm_init(ICH9_LPCPmRegs *pm,
+void ich9_pm_init(ICH9LPCPMRegs *pm,
qemu_irq sci_irq, qemu_irq cmos_s3_resume);
-void ich9_pm_iospace_update(ICH9_LPCPmRegs *pm, uint32_t pm_io_base);
+void ich9_pm_iospace_update(ICH9LPCPMRegs *pm, uint32_t pm_io_base);
extern const VMStateDescription vmstate_ich9_pm;
#endif /* HW_ACPI_ICH9_H */
@@ -7,6 +7,7 @@ obj-y += debugcon.o multiboot.o
obj-y += pc_piix.o
obj-y += pc_sysfw.o
obj-y += pam.o
+obj-y += pc_q35.o q35.o q35_smbus.o acpi_ich9.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
@@ -69,6 +69,8 @@ int pic_read_irq(DeviceState *d);
int pic_get_output(DeviceState *d);
void pic_info(Monitor *mon);
void irq_info(Monitor *mon);
+void kvm_piix3_gsi_handler(void *opaque, int n, int level);
+void kvm_piix3_setup_irq_routing(bool pci_enabled);
/* Global System Interrupts */
@@ -53,7 +53,7 @@ static const int ide_iobase[MAX_IDE_BUS] = { 0x1f0, 0x170 };
static const int ide_iobase2[MAX_IDE_BUS] = { 0x3f6, 0x376 };
static const int ide_irq[MAX_IDE_BUS] = { 14, 15 };
-static void kvm_piix3_setup_irq_routing(bool pci_enabled)
+void kvm_piix3_setup_irq_routing(bool pci_enabled)
{
#ifdef CONFIG_KVM
KVMState *s = kvm_state;
@@ -82,7 +82,7 @@ static void kvm_piix3_setup_irq_routing(bool pci_enabled)
#endif /* CONFIG_KVM */
}
-static void kvm_piix3_gsi_handler(void *opaque, int n, int level)
+void kvm_piix3_gsi_handler(void *opaque, int n, int level)
{
GSIState *s = opaque;
@@ -27,6 +27,7 @@
* 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.
*
@@ -49,7 +50,6 @@
#include "fdc.h"
#include "pci.h"
#include "pci_bridge.h"
-#include "pci_p2pbr.h"
#include "ioh3420.h"
#include "xio3130_upstream.h"
#include "xio3130_downstream.h"
@@ -66,36 +66,16 @@
#include "watchdog.h"
#include "smbios.h"
#include "ide.h"
-#include "usb-uhci.h"
+#include "mc146818rtc.h"
+#include "xen.h"
+#include "kvm.h"
#include "q35.h"
+#include "exec-memory.h"
/* ICH9 AHCI has 6 ports */
#define MAX_SATA_PORTS 6
-#define I21154_REV 0x05
-#define I21154_PI 0x00
-
-static PCIBridge *i21154_init(PCIBus *bus, int devfn, const char *bus_name,
- bool multifunction)
-{
- const PCIP2PBridgeInit init = {
- .bus = bus,
- .devfn = devfn,
- .multifunction = multifunction,
-
- .bus_name = bus_name,
- .map_irq = pci_swizzle_map_irq_fn,
- };
- const PCIP2PBridgeProp prop = {
- .vendor_id = PCI_VENDOR_ID_DEC,
- .device_id = PCI_DEVICE_ID_DEC_21154,
- .revision_id = I21154_REV,
- .prog_interface = I21154_PI,
- };
- return pci_p2pbr_create_simple(&init, &prop);
-}
-
static void pc_q35_bridge_init(PCIBus *host_bus, PCIBus *pci_bus)
{
uint8_t dev;
@@ -104,7 +84,6 @@ static void pc_q35_bridge_init(PCIBus *host_bus, PCIBus *pci_bus)
uint8_t chassis = 0;
uint16_t slot = 0;
uint8_t upstream_port;
- PCIESlot *s;
uint8_t fn;
PCIESlot *root_port;
PCIBus *root_port_bus;
@@ -116,11 +95,10 @@ static void pc_q35_bridge_init(PCIBus *host_bus, PCIBus *pci_bus)
#define Q35_P2P_BRDIGE_DEV_MAX 32
#define Q35_P2P_BRDIGE_SUBBUS_BASE (ICH9_D2P_SECONDARY_DEFAULT + 1)
for (dev = Q35_P2P_BRDIGE_DEV_BASE; dev < Q35_P2P_BRDIGE_DEV_MAX; dev++) {
- PCIBridge *br;
sec_bus = Q35_P2P_BRDIGE_SUBBUS_BASE + dev - Q35_P2P_BRDIGE_DEV_BASE;
snprintf(buf, sizeof(buf), "pci.%d", sec_bus);
- br = i21154_init(pci_bus, PCI_DEVFN(dev, 0), buf, true);
+ i21154_init(pci_bus, PCI_DEVFN(dev, 0), buf, true);
}
/* PCIe root port b0:d1:f0 in GMCH.
@@ -128,8 +106,8 @@ static void pc_q35_bridge_init(PCIBus *host_bus, PCIBus *pci_bus)
*/
sec_bus = 32;
snprintf(buf, sizeof(buf), "pcie.%d", sec_bus);
- s = ioh3420_init(host_bus, PCI_DEVFN(GMCH_PCIE_DEV, GMCH_PCIE_FUNC), true,
- buf, pci_swizzle_map_irq_fn, port, chassis, slot);
+ ioh3420_init(host_bus, PCI_DEVFN(GMCH_PCIE_DEV, GMCH_PCIE_FUNC), true,
+ buf, pci_swizzle_map_irq_fn, port, chassis, slot);
/* more slots. ICH9 doesn't have those, but many slots are wanted. */
@@ -153,8 +131,8 @@ static void pc_q35_bridge_init(PCIBus *host_bus, PCIBus *pci_bus)
slot++;
snprintf(buf, sizeof(buf), "pcie.%d", sec_bus);
- s = ioh3420_init(host_bus, PCI_DEVFN(23, fn), true,
- buf, pci_swizzle_map_irq_fn, port, chassis, slot);
+ ioh3420_init(host_bus, PCI_DEVFN(23, fn), true,
+ buf, pci_swizzle_map_irq_fn, port, chassis, slot);
}
/* PCIe root port b0:d24:f0 */
@@ -219,27 +197,38 @@ static void pc_q35_bridge_init(PCIBus *host_bus, PCIBus *pci_bus)
slot++;
snprintf(buf, sizeof(buf), "pcie.%d", sec_bus);
- s = ioh3420_init(host_bus, PCI_DEVFN(ICH9_PCIE_DEV, fn), true,
- buf, pci_swizzle_map_irq_fn,
- port, chassis, slot);
+ ioh3420_init(host_bus, PCI_DEVFN(ICH9_PCIE_DEV, fn), true,
+ buf, pci_swizzle_map_irq_fn,
+ port, chassis, slot);
}
}
-static void pc_q35_init_early(qemu_irq *isa_irq, IsaIrqState *isa_irq_state,
+static void pc_q35_init_early(qemu_irq *gsi, GSIState *gsi_state,
DeviceState **gmch_host_p,
PCIBus **host_bus_p, PCIBus **pci_bus_p,
- PCIDevice **lpc_p)
+ PCIDevice **lpc_p, ISABus **isa_bus,
+ MemoryRegion *system_memory,
+ MemoryRegion *pci_address_space,
+ MemoryRegion *address_space_io,
+ MemoryRegion *ram_memory,
+ ram_addr_t below_4g_mem_size,
+ ram_addr_t above_4g_mem_size)
{
+ target_phys_addr_t pci_hole64_size;
DeviceState *gmch_host;
PCIBus *host_bus;
PCIBus *pci_bus;
PCIDevice *gmch_state;
PCIDevice *lpc;
+ GMCHPCIState *gmps;
+ ICH9LPCState *ich9_lpc;
/* create pci host bus */
- host_bus = gmch_host_init(&gmch_host, isa_irq, isa_irq_state->ioapic);
+ host_bus = gmch_host_init(&gmch_host, gsi, gsi_state->ioapic_irq,
+ pci_address_space, address_space_io);
gmch_state = gmch_init(gmch_host, host_bus);
+ gmps = GMCH_PCI_DEVICE(gmch_state);
/* create conventional pci bus: pcie2pci bridge */
pci_bus = ich9_d2pbr_init(host_bus, PCI_DEVFN(ICH9_D2P_BRIDGE_DEV,
@@ -252,10 +241,53 @@ static void pc_q35_init_early(qemu_irq *isa_irq, IsaIrqState *isa_irq_state,
/* create ISA bus */
lpc = gmch_lpc_init(gmch_host, host_bus);
+ gmps->ram_memory = ram_memory;
+ gmps->pci_address_space = pci_address_space;
+ gmps->system_memory = system_memory;
+ /* pci */
+ memory_region_init_alias(&gmps->pci_hole, "pci-hole",
+ gmps->pci_address_space,
+ below_4g_mem_size,
+ 0x100000000ULL - below_4g_mem_size);
+ memory_region_add_subregion(gmps->system_memory, below_4g_mem_size,
+ &gmps->pci_hole);
+ pci_hole64_size = (sizeof(target_phys_addr_t) == 4 ? 0 :
+ ((uint64_t)1 << 62));
+ memory_region_init_alias(&gmps->pci_hole_64bit, "pci-hole64",
+ gmps->pci_address_space,
+ 0x100000000ULL + above_4g_mem_size,
+ pci_hole64_size);
+ if (pci_hole64_size) {
+ memory_region_add_subregion(gmps->system_memory,
+ 0x100000000ULL + above_4g_mem_size,
+ &gmps->pci_hole_64bit);
+ }
+
+ /* smram */
+ memory_region_init_alias(&gmps->smram_region, "smram-region",
+ pci_address_space, 0xa0000, 0x20000);
+ memory_region_add_subregion_overlap(system_memory, 0xa0000,
+ &gmps->smram_region, 1);
+ memory_region_set_enabled(&gmps->smram_region, false);
+
*gmch_host_p = gmch_host;
*host_bus_p = host_bus;
*pci_bus_p = pci_bus;
*lpc_p = lpc;
+ ich9_lpc = ICH9_LPC_DEVICE(lpc);
+ *isa_bus = ich9_lpc->isa_bus;
+}
+
+
+/* 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);
+ }
}
static void pc_q35_init_late(BusState **idebus, ISADevice *rtc_state,
@@ -271,13 +303,13 @@ static void pc_q35_init_late(BusState **idebus, ISADevice *rtc_state,
cmos_s3 = qemu_allocate_irqs(pc_cmos_set_s3_resume, rtc_state, 1);
ich9_lpc_pm_init(gmch_host, lpc, *cmos_s3);
- /* ahci and SATA device */
- ide_drive_get(hd, MAX_SATA_PORTS);
+ /* ahci and SATA device, for q35 1 ahci controller is built-in */
+ ahci_drive_get(hd, 1);
ahci = pci_create_simple_multifunction(host_bus,
PCI_DEVFN(ICH9_SATA1_DEV,
ICH9_SATA1_FUNC),
true, "ich9-ahci");
- pci_ahci_ide_create_devs(ahci, hd);
+ pci_ahci_create_devs(ahci, hd);
idebus[0] = qdev_get_child_bus(&ahci->qdev, "ide.0");
idebus[1] = qdev_get_child_bus(&ahci->qdev, "ide.1");
@@ -309,58 +341,96 @@ static void pc_q35_init(ram_addr_t ram_size,
PCIBus *host_bus;
PCIBus *pci_bus;
PCIDevice *lpc;
- qemu_irq *isa_irq;
- IsaIrqState *isa_irq_state;
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;
pc_cpus_init(cpu_model);
- /* FIXME: add kvm clock ? */
-
- if (ram_size >= 0xe0000000) {
- above_4g_mem_size = ram_size - 0xe0000000;
- below_4g_mem_size = 0xe0000000;
+ 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 */
- pci_memory = g_new(MemoryRegion, 1);
- memory_region_init(pci_memory, "pci", INT64_MAX);
- rom_memory = pci_memory;
+ 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 */
- pc_memory_init(get_system_memory(), kernel_filename, kernel_cmdline,
- initrd_filename, below_4g_mem_size, above_4g_mem_size,
- rom_memory, &ram_memory);
+ 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 */
- isa_irq = pc_isa_irq(&isa_irq_state);
- ioapic_init(isa_irq_state);
+ gsi_state = g_malloc0(sizeof(*gsi_state));
+ if (kvm_irqchip_in_kernel()) {
+ kvm_piix3_setup_irq_routing(pci_enabled);
+ gsi = qemu_allocate_irqs(kvm_piix3_gsi_handler, gsi_state,
+ GSI_NUM_PINS);
+ } else {
+ gsi = qemu_allocate_irqs(gsi_handler, gsi_state, GSI_NUM_PINS);
+ }
+
+ pc_q35_init_early(gsi, gsi_state,
+ &gmch_host, &host_bus, &pci_bus, &lpc, &isa_bus,
+ get_system_memory(), pci_memory, get_system_io(),
+ ram_memory, below_4g_mem_size, above_4g_mem_size);
+ isa_bus_irqs(isa_bus, gsi);
- pc_q35_init_early(isa_irq, isa_irq_state,
- &gmch_host, &host_bus, &pci_bus, &lpc);
- isa_bus_irqs(isa_irq);
- pc_register_ferr_irq(isa_get_irq(13));
+ 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_irq, &rtc_state, false);
+ pc_basic_device_init(isa_bus, gsi, &rtc_state, &floppy, false);
pc_q35_init_late(idebus, rtc_state, gmch_host, host_bus, pci_bus, lpc);
pc_cmos_init(below_4g_mem_size, above_4g_mem_size, boot_device,
- idebus[0], idebus[1], rtc_state);
+ floppy, idebus[0], idebus[1], rtc_state);
/* the rest devices to which pci devfn is automatically assigned */
- pc_vga_init(host_bus);
- audio_init(isa_irq, pci_bus);
- pc_nic_init(pci_bus);
- pc_pci_device_init(pci_bus);
+ pc_vga_init(isa_bus, host_bus);
+ audio_init(isa_bus, pci_bus);
+ pc_nic_init(isa_bus, pci_bus);
+ if (pci_enabled) {
+ pc_pci_device_init(pci_bus);
+ }
}
static QEMUMachine pc_q35_machine = {
@@ -368,6 +438,7 @@ static QEMUMachine pc_q35_machine = {
.desc = "Q35 chipset PC",
.init = pc_q35_init,
.max_cpus = 255,
+ .mach_if = IF_AHCI,
};
static void pc_q35_machine_init(void)
@@ -25,6 +25,7 @@
* 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.
*
@@ -52,85 +53,39 @@
#include "pci.h"
#include "pcie_host.h"
#include "pci_bridge.h"
-#include "pci_p2pbr.h"
#include "q35.h"
#include "acpi.h"
#include "acpi_ich9.h"
#include "pam.h"
+#include "pci_internals.h"
+#include "exec-memory.h"
+#include "isa.h"
+#include "qemu-common.h"
-struct ICH9_LPCState;
-
-typedef struct ICH9_LPCIrqState {
- struct ICH9_LPCState *lpc;
- qemu_irq *pic;
- qemu_irq *ioapic;
-} ICH9_LPCIrqState;
-
-typedef struct GMCH_PCIHost {
- PCIExpressHost host;
-
- PCIDevice *dev;
- ICH9_LPCIrqState irq_state;
-} GMCH_PCIHost;
-
-typedef struct GMCH_PCIState {
- PCIDevice d;
- /*
- * GMCH_PCIHost *gmch_host;
- * In order to get GMCH_PCIHost
- * PCIDevice -> qdev -> parent_bus -> qdev -upcast-> GMCH_PCIHost
- */
-
- PAM pam;
-} GMCH_PCIState;
-
-typedef struct ICH9_LPCState {
- /* ICH9 LPC PCI to ISA bridge */
- PCIDevice d;
-
- /* (pci device, intx) -> pirq
- * In real chipset case, the unused slots are never used
- * as ICH9 supports only D25-D32 irq routing.
- * On the other hand in qemu case, any slot/function can be populated
- * via command line option.
- * So fallback interrupt routing for any devices in any slots is necessary.
- */
- uint8_t irr[PCI_SLOT_MAX][PCI_NUM_PINS];
-
- APMState apm;
- ICH9_LPCPmRegs pm;
- uint32_t sci_level; /* track sci level */
-
- /* 10.1 Chipset Configuration registers(Memory Space)
- which is pointed by RCBA */
- uint8_t chip_config[ICH9_CC_SIZE];
- int rbca_index;
-} ICH9_LPCState;
-
/****************************************************************************
* GMCH PCI host
*/
/* ich9 irq */
-static int ich9_lpc_map_irq(void *opaque, PCIDevice *pci_dev, int intx);
+static int ich9_lpc_map_irq(PCIDevice *pci_dev, int intx);
static void ich9_lpc_set_irq(void *opaque, int irq_num, int level);
-static int ich9_lpc_sci_irq(ICH9_LPCState *lpc);
-
-static GMCH_PCIHost *gmch_pcihost_from_qdev(DeviceState *gmch_host_qdev)
-{
- SysBusDevice *sysdev = sysbus_from_qdev(gmch_host_qdev);
- PCIHostState *pci = FROM_SYSBUS(PCIHostState, sysdev);
- PCIExpressHost *pcie = DO_UPCAST(PCIExpressHost, pci, pci);
- return DO_UPCAST(GMCH_PCIHost, host, pcie);
-}
+static int ich9_lpc_sci_irq(ICH9LPCState *lpc);
static int gmch_pcihost_initfn(SysBusDevice *dev)
{
- GMCH_PCIHost *s = gmch_pcihost_from_qdev(&dev->qdev);
+ PCIHostState *pci = FROM_SYSBUS(PCIHostState, dev);
+ GMCHPCIHost *s = GMCH_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, GMCH_HOST_BRIDGE_CONFIG_ADDR, &pci->conf_mem);
+ sysbus_init_ioports(&pci->busdev, GMCH_HOST_BRIDGE_CONFIG_ADDR, 4);
- pci_host_conf_register_ioport(GMCH_HOST_BRIDGE_CONFIG_ADDR, &s->host.pci);
- pci_host_data_register_ioport(GMCH_HOST_BRIDGE_CONFIG_DATA, &s->host.pci);
+ memory_region_init_io(&pci->data_mem, &pci_host_data_le_ops, pci,
+ "pci-conf-data", 4);
+ sysbus_add_io(dev, GMCH_HOST_BRIDGE_CONFIG_DATA, &pci->data_mem);
+ sysbus_init_ioports(&pci->busdev, GMCH_HOST_BRIDGE_CONFIG_DATA, 4);
if (pcie_host_init(&s->host) < 0) {
abort();
@@ -139,36 +94,52 @@ static int gmch_pcihost_initfn(SysBusDevice *dev)
return 0;
}
-static SysBusDeviceInfo gmch_pcihost_info = {
- .init = gmch_pcihost_initfn,
- .qdev.name = "gmch-pcihost",
- .qdev.size = sizeof(GMCH_PCIHost),
- .qdev.no_user = 1,
- .qdev.props = (Property[]) {
- {
- .name = "MCFG",
- .info = &qdev_prop_uint64,
- .offset = offsetof(GMCH_PCIHost, host.base_addr),
- .defval = (uint64_t[]){ GMCH_HOST_BRIDGE_PCIEXBAR_DEFAULT },
- },
- DEFINE_PROP_END_OF_LIST(),
- },
+static Property gmch_props[] = {
+ DEFINE_PROP_UINT64("MCFG", GMCHPCIHost, host.base_addr,
+ GMCH_HOST_BRIDGE_PCIEXBAR_DEFAULT),
+ DEFINE_PROP_END_OF_LIST(),
+};
+
+static Property gmch_pcihost_properties[] = {
+ DEFINE_PROP_PTR("lpc state", GMCHPCIHost, irq_state.lpc),
+ DEFINE_PROP_END_OF_LIST(),
+};
+
+static void gmch_pcihost_class_init(ObjectClass *klass, void *data)
+{
+ DeviceClass *dc = DEVICE_CLASS(klass);
+ SysBusDeviceClass *k = SYS_BUS_DEVICE_CLASS(klass);
+
+ k->init = gmch_pcihost_initfn;
+ dc->props = gmch_props;
+ dc->no_user = 1;
+ dc->props = gmch_pcihost_properties;
+}
+
+static const TypeInfo gmch_pcihost_info = {
+ .name = TYPE_GMCH_HOST_DEVICE,
+ .parent = TYPE_PCIE_HOST_BRIDGE,
+ .instance_size = sizeof(GMCHPCIHost),
+ .class_init = gmch_pcihost_class_init,
};
/* host bridge */
PCIBus *gmch_host_init(DeviceState **gmch_hostp,
- qemu_irq *pic, qemu_irq *ioapic)
+ qemu_irq *pic, qemu_irq *ioapic,
+ MemoryRegion *pci_address_space,
+ MemoryRegion *address_space_io)
{
DeviceState *dev;
- GMCH_PCIHost *s;
+ GMCHPCIHost *s;
PCIBus *b;
- dev = qdev_create(NULL, "gmch-pcihost");
- s = gmch_pcihost_from_qdev(dev);
+ dev = qdev_create(NULL, TYPE_GMCH_HOST_DEVICE);
+ s = GMCH_HOST_DEVICE(dev);
s->irq_state.pic = pic;
s->irq_state.ioapic = ioapic;
- b = pci_bus_new(dev, "pcie.0", 0);
+ b = pci_bus_new(&s->host.pci.busdev.qdev, "pcie.0", pci_address_space,
+ address_space_io, 0);
pci_bus_irqs(b, ich9_lpc_set_irq, ich9_lpc_map_irq, &s->irq_state,
ICH9_LPC_NB_PIRQS);
s->host.pci.bus = b;
@@ -180,20 +151,16 @@ PCIBus *gmch_host_init(DeviceState **gmch_hostp,
/****************************************************************************
- * GMCH
+ * GMCH D0:F0
*/
-static GMCH_PCIState *gmch_from_pci(PCIDevice *gmch_pci)
-{
- return DO_UPCAST(GMCH_PCIState, d, gmch_pci);
-}
/* PCIE MMCFG */
-static void gmch_update_pciexbar(GMCH_PCIState *gs)
+static void gmch_update_pciexbar(GMCHPCIState *gs)
{
PCIDevice *pci_dev = &gs->d;
BusState *bus = qdev_get_parent_bus(&pci_dev->qdev);
DeviceState *qdev = bus->parent;
- GMCH_PCIHost *s = gmch_pcihost_from_qdev(qdev);
+ GMCHPCIHost *s = GMCH_HOST_DEVICE(qdev);
uint64_t pciexbar;
int enable;
@@ -231,30 +198,42 @@ static void gmch_update_pciexbar(GMCH_PCIState *gs)
}
/* PAM */
-static void gmch_update_pam(GMCH_PCIState *gs)
+static void gmch_update_pam(GMCHPCIState *gs)
{
int i;
+
+ memory_region_transaction_begin();
for (i = 0; i <= PAM_IDX_MAX; i++) {
- pam_update(&gs->pam, i, gs->d.config[GMCH_HOST_BRIDGE_PAM0 + i]);
+ pam_update(&gs->pam_regions[0], i,
+ gs->d.config[GMCH_HOST_BRIDGE_PAM0 + i],
+ gs->ram_memory, gs->pci_address_space, gs->system_memory);
}
+ memory_region_transaction_commit();
}
/* SMRAM */
-static void gmch_update_smram(GMCH_PCIState *gs)
+static void gmch_update_smram(GMCHPCIState *gs)
{
- smram_update(&gs->pam, gs->d.config[GMCH_HOST_BRDIGE_SMRAM]);
+ memory_region_transaction_begin();
+ smram_update(&gs->smram_region, gs->d.config[GMCH_HOST_BRDIGE_SMRAM],
+ gs->smm_enabled);
+ memory_region_transaction_commit();
}
static void gmch_set_smm(int smm, void *arg)
{
- GMCH_PCIState *gs = arg;
- smram_set_smm(&gs->pam, smm, gs->d.config[GMCH_HOST_BRDIGE_SMRAM]);
+ GMCHPCIState *gs = arg;
+
+ memory_region_transaction_begin();
+ smram_set_smm(&gs->smm_enabled, smm, gs->d.config[GMCH_HOST_BRDIGE_SMRAM],
+ &gs->smram_region);
+ memory_region_transaction_commit();
}
static void gmch_write_config(PCIDevice *d,
uint32_t address, uint32_t val, int len)
{
- GMCH_PCIState *gs = gmch_from_pci(d);
+ GMCHPCIState *gs = GMCH_PCI_DEVICE(d);
/* XXX: implement SMRAM.D_LOCK */
pci_default_write_config(d, address, val, len);
@@ -275,7 +254,7 @@ static void gmch_write_config(PCIDevice *d,
}
}
-static void gmch_update(GMCH_PCIState *gs)
+static void gmch_update(GMCHPCIState *gs)
{
gmch_update_pciexbar(gs);
gmch_update_pam(gs);
@@ -284,7 +263,7 @@ static void gmch_update(GMCH_PCIState *gs)
static int gmch_post_load(void *opaque, int version_id)
{
- GMCH_PCIState *gs = opaque;
+ GMCHPCIState *gs = opaque;
gmch_update(gs);
return 0;
}
@@ -296,16 +275,16 @@ static const VMStateDescription vmstate_gmch = {
.minimum_version_id_old = 1,
.post_load = gmch_post_load,
.fields = (VMStateField []) {
- VMSTATE_PCI_DEVICE(d, GMCH_PCIState),
- VMSTATE_UINT8(pam.smm_enabled, GMCH_PCIState),
+ VMSTATE_PCI_DEVICE(d, GMCHPCIState),
+ VMSTATE_UINT8(smm_enabled, GMCHPCIState),
VMSTATE_END_OF_LIST()
}
};
static void gmch_reset(DeviceState *qdev)
{
- PCIDevice *d = DO_UPCAST(PCIDevice, qdev, qdev);
- GMCH_PCIState *gs = gmch_from_pci(d);
+ PCIDevice *d = PCI_DEVICE(qdev);
+ GMCHPCIState *gs = GMCH_PCI_DEVICE(d);
pci_set_quad(d->config + GMCH_HOST_BRIDGE_PCIEXBAR,
GMCH_HOST_BRIDGE_PCIEXBAR_DEFAULT);
@@ -315,39 +294,46 @@ static void gmch_reset(DeviceState *qdev)
gmch_update(gs);
}
-static int gmch_initfn(PCIDevice *d)
+static int pci_gmch_initfn(PCIDevice *d)
{
- GMCH_PCIState *gs = gmch_from_pci(d);
-
- pci_config_set_vendor_id(d->config, PCI_VENDOR_ID_INTEL);
- pci_config_set_device_id(d->config, PCI_DEVICE_ID_INTEL_Q35_MCH);
- pci_config_set_revision(d->config, GMCH_HOST_BRIDGE_REVISION_DEFUALT);
- pci_config_set_class(d->config, PCI_CLASS_BRIDGE_HOST);
+ GMCHPCIState *gs = GMCH_PCI_DEVICE(d);
cpu_smm_register(&gmch_set_smm, gs);
- pam_init_memory_mappings(&gs->pam);
return 0;
}
-static PCIDeviceInfo gmch_info = {
- .qdev.name = "gmch",
- .qdev.desc = "Host bridge",
- .qdev.size = sizeof(GMCH_PCIState),
- .qdev.vmsd = &vmstate_gmch,
- .qdev.no_user = 1,
- .init = gmch_initfn,
- .config_write = gmch_write_config,
- .qdev.reset = gmch_reset,
+static void pci_gmch_class_init(ObjectClass *klass, void *data)
+{
+ PCIDeviceClass *k = PCI_DEVICE_CLASS(klass);
+ DeviceClass *dc = DEVICE_CLASS(klass);
+
+ k->init = pci_gmch_initfn;
+ k->config_write = gmch_write_config;
+ dc->reset = gmch_reset;
+ dc->desc = "Host bridge";
+ dc->vmsd = &vmstate_gmch;
+ dc->no_user = 1;
+ k->vendor_id = PCI_VENDOR_ID_INTEL;
+ k->device_id = PCI_DEVICE_ID_INTEL_Q35_MCH;
+ k->revision = GMCH_HOST_BRIDGE_REVISION_DEFUALT;
+ k->class_id = PCI_CLASS_BRIDGE_HOST;
+}
+
+static const TypeInfo pci_gmch_info = {
+ .name = TYPE_GMCH_PCI_DEVICE,
+ .parent = TYPE_PCI_DEVICE,
+ .instance_size = sizeof(GMCHPCIState),
+ .class_init = pci_gmch_class_init,
};
/* host bridge */
PCIDevice *gmch_init(DeviceState *gmch_host, PCIBus *b)
{
- GMCH_PCIHost *s = gmch_pcihost_from_qdev(gmch_host);
+ GMCHPCIHost *s = GMCH_HOST_DEVICE(gmch_host);
PCIDevice *d;
- d = pci_create_simple_multifunction(b, 0, false, "gmch");
+ d = pci_create_simple_multifunction(b, 0, false, TYPE_GMCH_PCI_DEVICE);
s->dev = d;
return d;
@@ -359,54 +345,135 @@ PCIDevice *gmch_init(DeviceState *gmch_host, PCIBus *b)
#define I82801ba_SSVID_SVID 0
#define I82801ba_SSVID_SSID 0
-static PCIBridge *i82801ba11_init(PCIBus *bus, int devfn, const char *bus_name,
- bool multifunction)
+typedef struct I82801b11Bridge {
+ PCIBridge br;
+} I82801b11Bridge;
+
+static int i82801b11_bridge_initfn(PCIDevice *d)
{
- const PCIP2PBridgeInit init = {
- .bus = bus,
- .devfn = devfn,
- .multifunction = multifunction,
+ int rc;
+
+ rc = pci_bridge_initfn(d);
+ if (rc < 0) {
+ return rc;
+ }
+
+ rc = pci_bridge_ssvid_init(d, I82801ba_SSVID_OFFSET,
+ I82801ba_SSVID_SVID, I82801ba_SSVID_SSID);
+ if (rc < 0) {
+ goto err_bridge;
+ }
+ return 0;
- .bus_name = bus_name,
- .map_irq = pci_swizzle_map_irq_fn,
- };
- const PCIP2PBridgeProp prop = {
- .vendor_id = PCI_VENDOR_ID_INTEL,
- .device_id = PCI_DEVICE_ID_INTEL_82801BA_11,
- .revision_id = ICH9_D2P_A2_REVISION,
- .prog_interface = PCI_CLASS_BRDIGE_PCI_INF_SUB,
+err_bridge:
+ pci_bridge_exitfn(d);
- .ssvid_cap = I82801ba_SSVID_OFFSET,
- .svid = I82801ba_SSVID_SVID,
- .ssid = I82801ba_SSVID_SSID,
- };
- return pci_p2pbr_create_simple(&init, &prop);
+ return rc;
}
+static void i82801b11_bridge_class_init(ObjectClass *klass, void *data)
+{
+ PCIDeviceClass *k = PCI_DEVICE_CLASS(klass);
+
+ k->is_bridge = 1;
+ k->vendor_id = PCI_VENDOR_ID_INTEL;
+ k->device_id = PCI_DEVICE_ID_INTEL_82801BA_11;
+ k->revision = ICH9_D2P_A2_REVISION;
+ k->init = i82801b11_bridge_initfn;
+}
+
+static const TypeInfo i82801b11_bridge_info = {
+ .name = "i82801b11-bridge",
+ .parent = TYPE_PCI_DEVICE,
+ .instance_size = sizeof(I82801b11Bridge),
+ .class_init = i82801b11_bridge_class_init,
+};
+
PCIBus *ich9_d2pbr_init(PCIBus *bus, int devfn, int sec_bus)
{
+ PCIDevice *d;
PCIBridge *br;
char buf[16];
+ DeviceState *qdev;
- snprintf(buf, sizeof(buf), "pci.%d", sec_bus);
- br = i82801ba11_init(bus, devfn, buf, true);
- if (br == NULL) {
+ d = pci_create_multifunction(bus, devfn, true, "i82801b11-bridge");
+ if (!d) {
return NULL;
}
+ br = DO_UPCAST(PCIBridge, dev, d);
+ qdev = &br->dev.qdev;
+
+ snprintf(buf, sizeof(buf), "pci.%d", sec_bus);
+ pci_bridge_map_irq(br, buf, pci_swizzle_map_irq_fn);
+ qdev_init_nofail(qdev);
+
return pci_bridge_get_sec_bus(br);
}
+/*****************************************************************************/
+/* i21154 pci bridge*/
+
+typedef struct I21154Bridge {
+ PCIBridge br;
+} I21154Bridge;
+
+static int i21154_bridge_initfn(PCIDevice *d)
+{
+ int rc;
+
+ rc = pci_bridge_initfn(d);
+ if (rc < 0) {
+ return rc;
+ }
+
+ return 0;
+}
+#define I21154_REV 0x05
+#define I21154_PI 0x00
-/*****************************************************************************/
-/* ICH9 LPC PCI to ISA bridge */
+static void i21154_bridge_class_init(ObjectClass *klass, void *data)
+{
+ PCIDeviceClass *k = PCI_DEVICE_CLASS(klass);
-static void ich9_lpc_reset(DeviceState *qdev);
+ k->is_bridge = 1;
+ k->vendor_id = PCI_VENDOR_ID_DEC;
+ k->device_id = PCI_DEVICE_ID_DEC_21154;
+ k->revision = I21154_REV;
+ k->init = i21154_bridge_initfn;
+}
-static ICH9_LPCState *ich9_lpc_from_pci(PCIDevice *lpc_pci)
+static const TypeInfo i21154_bridge_info = {
+ .name = "i21154-bridge",
+ .parent = TYPE_PCI_DEVICE,
+ .instance_size = sizeof(I21154Bridge),
+ .class_init = i21154_bridge_class_init,
+};
+
+PCIBridge *i21154_init(PCIBus *bus, int devfn, const char *bus_name,
+ bool multifunction)
{
- return DO_UPCAST(ICH9_LPCState, d, lpc_pci);
+ PCIDevice *d;
+ PCIBridge *br;
+ DeviceState *qdev;
+
+ d = pci_create_multifunction(bus, devfn, multifunction, "i21154-bridge");
+ if (!d) {
+ return NULL;
+ }
+ br = DO_UPCAST(PCIBridge, dev, d);
+ qdev = &br->dev.qdev;
+
+ pci_bridge_map_irq(br, bus_name, pci_swizzle_map_irq_fn);
+ qdev_init_nofail(qdev);
+
+ return br;
}
+/*****************************************************************************/
+/* ICH9 LPC PCI to ISA bridge */
+
+static void ich9_lpc_reset(DeviceState *qdev);
+
/* chipset configuration register
* to access chipset configuration registers, pci_[sg]et_{byte, word, long}
* are used.
@@ -421,7 +488,7 @@ static void ich9_cc_update_ir(uint8_t irr[PCI_NUM_PINS], uint32_t ir)
}
}
-static void ich9_cc_update(ICH9_LPCState *lpc)
+static void ich9_cc_update(ICH9LPCState *lpc)
{
int slot;
int reg_offset;
@@ -446,7 +513,7 @@ static void ich9_cc_update(ICH9_LPCState *lpc)
}
}
-static void ich9_cc_init(ICH9_LPCState *lpc)
+static void ich9_cc_init(ICH9LPCState *lpc)
{
int slot;
int intx;
@@ -468,7 +535,7 @@ static void ich9_cc_init(ICH9_LPCState *lpc)
ich9_cc_update(lpc);
}
-static void ich9_cc_reset(ICH9_LPCState *lpc)
+static void ich9_cc_reset(ICH9LPCState *lpc)
{
uint8_t *c = lpc->chip_config;
@@ -485,7 +552,7 @@ static void ich9_cc_reset(ICH9_LPCState *lpc)
ich9_cc_update(lpc);
}
-static void ich9_cc_addr_len(uint32_t *addr, int *len)
+static void ich9_cc_addr_len(uint64_t *addr, unsigned *len)
{
*addr &= ICH9_CC_ADDR_MASK;
if (*addr + *len >= ICH9_CC_SIZE) {
@@ -494,56 +561,27 @@ static void ich9_cc_addr_len(uint32_t *addr, int *len)
}
/* val: little endian */
-static void ich9_cc_write(ICH9_LPCState *lpc, uint32_t addr,
- uint32_t val, int len)
+static void ich9_cc_write(void *opaque, target_phys_addr_t addr,
+ uint64_t val, unsigned len)
{
+ ICH9LPCState *lpc = (ICH9LPCState *)opaque;
+
ich9_cc_addr_len(&addr, &len);
memcpy(lpc->chip_config + addr, &val, len);
}
/* return value: little endian */
-static uint32_t ich9_cc_read(ICH9_LPCState *lpc, uint32_t addr, int len)
+static uint64_t ich9_cc_read(void *opaque, target_phys_addr_t addr,
+ unsigned len)
{
+ ICH9LPCState *lpc = (ICH9LPCState *)opaque;
+
uint32_t val = 0;
ich9_cc_addr_len(&addr, &len);
memcpy(&val, lpc->chip_config + addr, len);
return val;
}
-#define ICH9_CC_MMIO_WRITE(type, len) \
- static void ich9_cc_mmio_write ## type \
- (void *opaque, target_phys_addr_t addr, uint32_t val) \
- { \
- ich9_cc_write(opaque, addr, val, len); \
- }
-
-#define ICH9_CC_MMIO_READ(type, len) \
- static uint32_t ich9_cc_mmio_read ## type \
- (void *opaque, target_phys_addr_t addr) \
- { \
- return ich9_cc_read(opaque, addr, len); \
- }
-
-ICH9_CC_MMIO_WRITE(b, 1)
-ICH9_CC_MMIO_WRITE(w, 2)
-ICH9_CC_MMIO_WRITE(l, 4)
-
-ICH9_CC_MMIO_READ(b, 1)
-ICH9_CC_MMIO_READ(w, 2)
-ICH9_CC_MMIO_READ(l, 4)
-
-static CPUWriteMemoryFunc * const ich9_cc_mmio_write[] = {
- ich9_cc_mmio_writeb,
- ich9_cc_mmio_writew,
- ich9_cc_mmio_writel,
-};
-
-static CPUReadMemoryFunc * const ich9_cc_mmio_read[] = {
- ich9_cc_mmio_readb,
- ich9_cc_mmio_readw,
- ich9_cc_mmio_readl,
-};
-
/* IRQ routing */
/* */
static void ich9_lpc_rout(uint8_t pirq_rout, int *pic_irq, int *pic_dis)
@@ -552,7 +590,7 @@ static void ich9_lpc_rout(uint8_t pirq_rout, int *pic_irq, int *pic_dis)
*pic_dis = pirq_rout & ICH9_LPC_PIRQ_ROUT_IRQEN;
}
-static void ich9_lpc_pic_irq(ICH9_LPCState *lpc, int irq_num,
+static void ich9_lpc_pic_irq(ICH9LPCState *lpc, int irq_num,
int *pic_irq, int *pic_dis)
{
switch (irq_num) {
@@ -571,10 +609,10 @@ static void ich9_lpc_pic_irq(ICH9_LPCState *lpc, int irq_num,
}
/* pic_irq: i8254 irq 0-15 */
-static void ich9_lpc_update_pic(ICH9_LPCIrqState *irq_state, int pic_irq)
+static void ich9_lpc_update_pic(ICH9LPCIrqState *irq_state, int pic_irq)
{
- GMCH_PCIHost *s = container_of(irq_state, GMCH_PCIHost, irq_state);
- ICH9_LPCState *lpc = irq_state->lpc;
+ GMCHPCIHost *s = container_of(irq_state, GMCHPCIHost, irq_state);
+ ICH9LPCState *lpc = irq_state->lpc;
int i, pic_level;
/* The pic level is the logical OR of all the PCI irqs mapped to it */
@@ -595,9 +633,9 @@ static void ich9_lpc_update_pic(ICH9_LPCIrqState *irq_state, int pic_irq)
}
/* pirq: pirq[A-H] 0-7*/
-static void ich9_lpc_update_by_pirq(ICH9_LPCIrqState *irq_state, int pirq)
+static void ich9_lpc_update_by_pirq(ICH9LPCIrqState *irq_state, int pirq)
{
- ICH9_LPCState *lpc = irq_state->lpc;
+ ICH9LPCState *lpc = irq_state->lpc;
int pic_irq;
int pic_dis;
@@ -621,10 +659,10 @@ static int ich9_gsi_to_pirq(int gsi)
return gsi - ICH9_LPC_PIC_NUM_PINS;
}
-static void ich9_lpc_update_apic(ICH9_LPCIrqState *irq_state, int gsi)
+static void ich9_lpc_update_apic(ICH9LPCIrqState *irq_state, int gsi)
{
- GMCH_PCIHost *s = container_of(irq_state, GMCH_PCIHost, irq_state);
- ICH9_LPCState *lpc = irq_state->lpc;
+ GMCHPCIHost *s = container_of(irq_state, GMCHPCIHost, irq_state);
+ ICH9LPCState *lpc = irq_state->lpc;
int level;
level = pci_bus_get_irq_level(s->host.pci.bus, ich9_gsi_to_pirq(gsi));
@@ -637,15 +675,20 @@ static void ich9_lpc_update_apic(ICH9_LPCIrqState *irq_state, int gsi)
/* return the pirq number (PIRQ[A-H]:0-7) corresponding to
a given device irq pin. */
-static int ich9_lpc_map_irq(void *opaque, PCIDevice *pci_dev, int intx)
+static int ich9_lpc_map_irq(PCIDevice *pci_dev, int intx)
{
- ICH9_LPCIrqState *irq_state = opaque;
- return irq_state->lpc->irr[PCI_SLOT(pci_dev->devfn)][intx];
+ BusState *bus = qdev_get_parent_bus(&pci_dev->qdev);
+ DeviceState *qdev = bus->parent;
+ GMCHPCIHost *s = GMCH_HOST_DEVICE(qdev);
+ ICH9LPCIrqState *irq_state = &s->irq_state;
+ ICH9LPCState *lpc = (ICH9LPCState *)irq_state->lpc;
+
+ return lpc->irr[PCI_SLOT(pci_dev->devfn)][intx];
}
static void ich9_lpc_set_irq(void *opaque, int pirq, int level)
{
- ICH9_LPCIrqState *irq_state = opaque;
+ ICH9LPCIrqState *irq_state = opaque;
assert(0 <= pirq);
assert(pirq < ICH9_LPC_NB_PIRQS);
@@ -654,7 +697,7 @@ static void ich9_lpc_set_irq(void *opaque, int pirq, int level)
ich9_lpc_update_by_pirq(irq_state, pirq);
}
-static int ich9_lpc_sci_irq(ICH9_LPCState *lpc)
+static int ich9_lpc_sci_irq(ICH9LPCState *lpc)
{
switch (lpc->d.config[ICH9_LPC_ACPI_CTRL] &
ICH9_LPC_ACPI_CTRL_SCI_IRQ_SEL_MASK) {
@@ -677,8 +720,8 @@ static int ich9_lpc_sci_irq(ICH9_LPCState *lpc)
static void ich9_set_sci(void *opaque, int irq_num, int level)
{
- ICH9_LPCIrqState *irq_state = opaque;
- ICH9_LPCState *lpc = irq_state->lpc;
+ ICH9LPCIrqState *irq_state = opaque;
+ ICH9LPCState *lpc = irq_state->lpc;
int irq;
assert(irq_num == 0);
@@ -702,8 +745,8 @@ static void ich9_set_sci(void *opaque, int irq_num, int level)
void ich9_lpc_pm_init(DeviceState *gmch_host, PCIDevice *lpc_pci,
qemu_irq cmos_s3)
{
- GMCH_PCIHost *s = gmch_pcihost_from_qdev(gmch_host);
- ICH9_LPCState *lpc = ich9_lpc_from_pci(lpc_pci);
+ GMCHPCIHost *s = GMCH_HOST_DEVICE(gmch_host);
+ ICH9LPCState *lpc = ICH9_LPC_DEVICE(lpc_pci);
qemu_irq *sci_irq;
sci_irq = qemu_allocate_irqs(ich9_set_sci, &s->irq_state, 1);
@@ -713,12 +756,14 @@ void ich9_lpc_pm_init(DeviceState *gmch_host, PCIDevice *lpc_pci,
}
/* APM */
+
+
static void ich9_apm_ctrl_changed(uint32_t val, void *arg)
{
- ICH9_LPCState *lpc = arg;
+ ICH9LPCState *lpc = arg;
/* ACPI specs 3.0, 4.7.2.5 */
- acpi_pm1_cnt_update(&lpc->pm.pm1_cnt,
+ acpi_pm1_cnt_update(&lpc->pm.acpi_regs,
val == ICH9_APM_ACPI_ENABLE,
val == ICH9_APM_ACPI_DISABLE);
@@ -730,7 +775,7 @@ static void ich9_apm_ctrl_changed(uint32_t val, void *arg)
/* config:PMBASE */
static void
-ich9_lpc_pmbase_update(ICH9_LPCState *lpc)
+ich9_lpc_pmbase_update(ICH9LPCState *lpc)
{
uint32_t pm_io_base = pci_get_long(lpc->d.config + ICH9_LPC_PMBASE);
pm_io_base &= ICH9_LPC_PMBASE_BASE_ADDRESS_MASK;
@@ -739,23 +784,23 @@ ich9_lpc_pmbase_update(ICH9_LPCState *lpc)
}
/* config:RBCA */
-static void ich9_lpc_rcba_update(ICH9_LPCState *lpc, uint32_t rbca_old)
+static void ich9_lpc_rcba_update(ICH9LPCState *lpc, uint32_t rbca_old)
{
uint32_t rbca = pci_get_long(lpc->d.config + ICH9_LPC_RCBA);
if (rbca_old & ICH9_LPC_RCBA_EN) {
- cpu_register_physical_memory(rbca_old & ICH9_LPC_RCBA_BA_MASK,
- ICH9_CC_SIZE, IO_MEM_UNASSIGNED);
+ memory_region_del_subregion(get_system_memory(), &lpc->rbca_mem);
}
if (rbca & ICH9_LPC_RCBA_EN) {
- cpu_register_physical_memory(rbca & ICH9_LPC_RCBA_BA_MASK,
- ICH9_CC_SIZE, lpc->rbca_index);
+ memory_region_add_subregion_overlap(get_system_memory(),
+ rbca & ICH9_LPC_RCBA_BA_MASK,
+ &lpc->rbca_mem, 1);
}
}
static int ich9_lpc_post_load(void *opaque, int version_id)
{
- ICH9_LPCState *lpc = opaque;
+ ICH9LPCState *lpc = opaque;
ich9_lpc_pmbase_update(lpc);
ich9_lpc_rcba_update(lpc, 0 /* disabled ICH9_LPC_RBCA_EN */);
@@ -765,7 +810,7 @@ static int ich9_lpc_post_load(void *opaque, int version_id)
static void ich9_lpc_config_write(PCIDevice *d,
uint32_t addr, uint32_t val, int len)
{
- ICH9_LPCState *lpc = ich9_lpc_from_pci(d);
+ ICH9LPCState *lpc = ICH9_LPC_DEVICE(d);
uint32_t rbca_old = pci_get_long(d->config + ICH9_LPC_RCBA);
pci_default_write_config(d, addr, val, len);
@@ -779,8 +824,8 @@ static void ich9_lpc_config_write(PCIDevice *d,
static void ich9_lpc_reset(DeviceState *qdev)
{
- PCIDevice *d = DO_UPCAST(PCIDevice, qdev, qdev);
- ICH9_LPCState *lpc = ich9_lpc_from_pci(d);
+ PCIDevice *d = PCI_DEVICE(qdev);
+ ICH9LPCState *lpc = ICH9_LPC_DEVICE(d);
uint32_t rbca_old = pci_get_long(d->config + ICH9_LPC_RCBA);
int i;
@@ -805,22 +850,26 @@ static void ich9_lpc_reset(DeviceState *qdev)
lpc->sci_level = 0;
}
+static const MemoryRegionOps rbca_mmio_ops = {
+ .read = ich9_cc_read,
+ .write = ich9_cc_write,
+ .endianness = DEVICE_LITTLE_ENDIAN,
+};
+
static int ich9_lpc_initfn(PCIDevice *d)
{
- ICH9_LPCState *lpc = ich9_lpc_from_pci(d);
+ ICH9LPCState *lpc = ICH9_LPC_DEVICE(d);
+ ISABus *isa_bus;
- isa_bus_new(&d->qdev);
- pci_config_set_vendor_id(d->config, PCI_VENDOR_ID_INTEL);
- pci_config_set_device_id(d->config, PCI_DEVICE_ID_INTEL_ICH9_8); /* ICH9 LPC */
- pci_config_set_revision(d->config, ICH9_A2_LPC_REVISION);
- pci_config_set_class(d->config, PCI_CLASS_BRIDGE_ISA);
+ isa_bus = isa_bus_new(&d->qdev, get_system_io());
pci_set_long(d->wmask + ICH9_LPC_PMBASE,
ICH9_LPC_PMBASE_BASE_ADDRESS_MASK);
- lpc->rbca_index = cpu_register_io_memory(ich9_cc_mmio_read,
- ich9_cc_mmio_write,
- lpc, DEVICE_LITTLE_ENDIAN);
+ memory_region_init_io(&lpc->rbca_mem, &rbca_mmio_ops, lpc,
+ "lpc-rbca-mmio", ICH9_CC_SIZE);
+
+ lpc->isa_bus = isa_bus;
ich9_cc_init(lpc);
apm_init(&lpc->apm, ich9_apm_ctrl_changed, lpc);
@@ -834,44 +883,61 @@ static const VMStateDescription vmstate_ich9_lpc = {
.minimum_version_id_old = 1,
.post_load = ich9_lpc_post_load,
.fields = (VMStateField[]) {
- VMSTATE_PCI_DEVICE(d, ICH9_LPCState),
- VMSTATE_STRUCT(apm, ICH9_LPCState, 0, vmstate_apm, APMState),
- VMSTATE_STRUCT(pm, ICH9_LPCState, 0, vmstate_ich9_pm, ICH9_LPCPmRegs),
- VMSTATE_UINT8_ARRAY(chip_config, ICH9_LPCState, ICH9_CC_SIZE),
- VMSTATE_UINT32(sci_level, ICH9_LPCState),
+ VMSTATE_PCI_DEVICE(d, ICH9LPCState),
+ VMSTATE_STRUCT(apm, ICH9LPCState, 0, vmstate_apm, APMState),
+ VMSTATE_STRUCT(pm, ICH9LPCState, 0, vmstate_ich9_pm, ICH9LPCPMRegs),
+ VMSTATE_UINT8_ARRAY(chip_config, ICH9LPCState, ICH9_CC_SIZE),
+ VMSTATE_UINT32(sci_level, ICH9LPCState),
VMSTATE_END_OF_LIST()
}
};
PCIDevice *gmch_lpc_init(DeviceState *gmch_host, PCIBus *bus)
{
- GMCH_PCIHost *s = gmch_pcihost_from_qdev(gmch_host);
+ GMCHPCIHost *s = GMCH_HOST_DEVICE(gmch_host);
PCIDevice *d;
- ICH9_LPCState *lpc;
+ ICH9LPCState *lpc;
d = pci_create_simple_multifunction(bus, PCI_DEVFN(ICH9_LPC_DEV,
ICH9_LPC_FUNC),
- true, "ICH9 LPC");
- lpc = ich9_lpc_from_pci(d);
+ true, TYPE_ICH9_LPC_DEVICE);
+ lpc = ICH9_LPC_DEVICE(d);
s->irq_state.lpc = lpc;
return &lpc->d;
}
-static PCIDeviceInfo ich9_lpc_info = {
- .qdev.name = "ICH9 LPC",
- .qdev.desc = "ICH9 LPC bridge",
- .qdev.size = sizeof(ICH9_LPCState),
- .qdev.vmsd = &vmstate_ich9_lpc,
- .qdev.no_user = 1,
- .init = ich9_lpc_initfn,
- .config_write = ich9_lpc_config_write,
- .qdev.reset = ich9_lpc_reset,
+static void ich9_lpc_class_init(ObjectClass *klass, void *data)
+{
+ DeviceClass *dc = DEVICE_CLASS(klass);
+ PCIDeviceClass *k = PCI_DEVICE_CLASS(klass);
+
+ dc->reset = ich9_lpc_reset;
+ k->init = ich9_lpc_initfn;
+ dc->vmsd = &vmstate_ich9_lpc;
+ dc->no_user = 1;
+ k->config_write = ich9_lpc_config_write;
+ dc->desc = "ICH9 LPC bridge";
+ k->vendor_id = PCI_VENDOR_ID_INTEL;
+ k->device_id = PCI_DEVICE_ID_INTEL_ICH9_8;
+ k->revision = ICH9_A2_LPC_REVISION;
+ k->class_id = PCI_CLASS_BRIDGE_ISA;
+
+}
+
+static const TypeInfo ich9_lpc_info = {
+ .name = TYPE_ICH9_LPC_DEVICE,
+ .parent = TYPE_PCI_DEVICE,
+ .instance_size = sizeof(struct ICH9LPCState),
+ .class_init = ich9_lpc_class_init,
};
static void q35_register(void)
{
- sysbus_register_withprop(&gmch_pcihost_info);
- pci_qdev_register(&gmch_info);
- pci_qdev_register(&ich9_lpc_info);
+ type_register_static(&pci_gmch_info);
+ type_register_static(&gmch_pcihost_info);
+ type_register_static(&i82801b11_bridge_info);
+ type_register_static(&i21154_bridge_info);
+ type_register_static(&ich9_lpc_info);
}
-device_init(q35_register);
+
+type_init(q35_register);
@@ -21,19 +21,104 @@
#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 "pci_bridge.h"
+#include "q35.h"
+#include "acpi.h"
#include "acpi_ich9.h"
+#include "pam.h"
+#include "pci_internals.h"
-PCIBus *gmch_host_init(DeviceState **gmch_hostp,
- qemu_irq *pic, qemu_irq *ioapic);
+#define ICH9_CC_SIZE (16 * 1024) /* 16KB */
+
+#define TYPE_GMCH_HOST_DEVICE "gmch-pcihost"
+#define GMCH_HOST_DEVICE(obj) \
+ OBJECT_CHECK(GMCHPCIHost, (obj), TYPE_GMCH_HOST_DEVICE)
+
+#define TYPE_GMCH_PCI_DEVICE "gmch"
+#define GMCH_PCI_DEVICE(obj) \
+ OBJECT_CHECK(GMCHPCIState, (obj), TYPE_GMCH_PCI_DEVICE)
+
+#define TYPE_ICH9_LPC_DEVICE "ICH9 LPC"
+#define ICH9_LPC_DEVICE(obj) \
+ OBJECT_CHECK(ICH9LPCState, (obj), TYPE_ICH9_LPC_DEVICE)
+
+typedef struct ICH9LPCState {
+ /* ICH9 LPC PCI to ISA bridge */
+ PCIDevice d;
+
+ /* (pci device, intx) -> pirq
+ * In real chipset case, the unused slots are never used
+ * as ICH9 supports only D25-D32 irq routing.
+ * On the other hand in qemu case, any slot/function can be populated
+ * via command line option.
+ * So fallback interrupt routing for any devices in any slots is necessary.
+ */
+ uint8_t irr[PCI_SLOT_MAX][PCI_NUM_PINS];
+
+ APMState apm;
+ ICH9LPCPMRegs pm;
+ uint32_t sci_level; /* track sci level */
+
+ /* 10.1 Chipset Configuration registers(Memory Space)
+ which is pointed by RCBA */
+ uint8_t chip_config[ICH9_CC_SIZE];
+ /* isa bus */
+ ISABus *isa_bus;
+ MemoryRegion rbca_mem;
+} ICH9LPCState;
+
+typedef struct ICH9LPCIrqState {
+ /* points to ICH9LPCState */
+ void *lpc;
+ qemu_irq *pic;
+ qemu_irq *ioapic;
+} ICH9LPCIrqState;
+
+typedef struct GMCHPCIHost {
+ PCIExpressHost host;
+ PCIDevice *dev;
+ ICH9LPCIrqState irq_state;
+} GMCHPCIHost;
+
+typedef struct GMCHPCIState {
+ PCIDevice d;
+ /*
+ * GMCH_PCIHost *gmch_host;
+ * In order to get GMCH_PCIHost
+ * PCIDevice -> qdev -> parent_bus -> qdev -upcast-> GMCH_PCIHost
+ */
+ MemoryRegion *ram_memory;
+ MemoryRegion *pci_address_space;
+ MemoryRegion *system_memory;
+ PAMMemoryRegion pam_regions[13];
+ MemoryRegion smram_region;
+ MemoryRegion pci_hole;
+ MemoryRegion pci_hole_64bit;
+ uint8_t smm_enabled;
+} GMCHPCIState;
+
+PCIBus *gmch_host_init(DeviceState **gmch_hostp,
+ qemu_irq *pic, qemu_irq *ioapic,
+ MemoryRegion *pci_address_space,
+ MemoryRegion *address_space_io);
PCIDevice *gmch_init(DeviceState *gmch_host, PCIBus *b);
PCIBus *ich9_d2pbr_init(PCIBus *bus, int devfn, int sec_bus);
PCIDevice *gmch_lpc_init(DeviceState *gmch_host, PCIBus *bus);
void ich9_lpc_pm_init(DeviceState *gmch_host, PCIDevice *pci_lpc,
qemu_irq cmos_s3);
-
i2c_bus *ich9_smb_init(PCIBus *bus, int devfn, uint32_t smb_io_base);
+PCIBridge *i21154_init(PCIBus *bus, int devfn, const char *bus_name,
+ bool multifunction);
#define Q35_MASK(bit, ms_bit, ls_bit) \
((uint##bit##_t)(((1ULL << ((ms_bit) + 1)) - 1) & ~((1ULL << ls_bit) - 1)))
@@ -124,7 +209,6 @@ i2c_bus *ich9_smb_init(PCIBus *bus, int devfn, uint32_t smb_io_base);
*/
/* ICH9: Chipset Configuration Registers */
-#define ICH9_CC_SIZE (16 * 1024) /* 16KB */
#define ICH9_CC_ADDR_MASK (ICH9_CC_SIZE - 1)
#define ICH9_CC
@@ -18,6 +18,7 @@
/*
* 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 is based on acpi.c, but heavily rewritten.
*/
@@ -35,6 +36,7 @@ typedef struct ICH9_SMBState {
PCIDevice dev;
PMSMBus smb;
+ MemoryRegion mem_bar;
} ICH9_SMBState;
static ICH9_SMBState *ich9_pci_to_smb(PCIDevice* pci_dev)
@@ -53,7 +55,8 @@ static const VMStateDescription vmstate_ich9_smbus = {
}
};
-static void ich9_smb_ioport_writeb(void *opaque, uint32_t addr, uint32_t val)
+static void ich9_smb_ioport_writeb(void *opaque, target_phys_addr_t addr,
+ uint64_t val, unsigned size)
{
ICH9_SMBState *s = opaque;
uint8_t hostc = s->dev.config[ICH9_SMB_HOSTC];
@@ -64,7 +67,8 @@ static void ich9_smb_ioport_writeb(void *opaque, uint32_t addr, uint32_t val)
}
}
-static uint32_t ich9_smb_ioport_readb(void *opaque, uint32_t addr)
+static uint64_t ich9_smb_ioport_readb(void *opaque, target_phys_addr_t addr,
+ unsigned size)
{
ICH9_SMBState *s = opaque;
uint8_t hostc = s->dev.config[ICH9_SMB_HOSTC];
@@ -77,32 +81,22 @@ static uint32_t ich9_smb_ioport_readb(void *opaque, uint32_t addr)
return 0xff;
}
-static void ich9_smb_map_ioport(PCIDevice *dev, int region_num,
- uint64_t addr, uint64_t size, int type)
-{
- ICH9_SMBState *s = ich9_pci_to_smb(dev);
-
- assert(size == ICH9_SMB_SMB_BASE_SIZE);
- assert(type == PCI_BASE_ADDRESS_SPACE_IO);
-
- register_ioport_write(addr, 64, 1, ich9_smb_ioport_writeb, s);
- register_ioport_read(addr, 64, 1, ich9_smb_ioport_readb, s);
-}
+static const MemoryRegionOps lpc_smb_mmio_ops = {
+ .read = ich9_smb_ioport_readb,
+ .write = ich9_smb_ioport_writeb,
+ .endianness = DEVICE_LITTLE_ENDIAN,
+ .impl = {
+ .min_access_size = 1,
+ .max_access_size = 1,
+ },
+};
-static int ich9_smb_initfn(PCIDevice *d)
+static int ich9_smbus_initfn(PCIDevice *d)
{
ICH9_SMBState *s = ich9_pci_to_smb(d);
- pci_config_set_vendor_id(d->config, PCI_VENDOR_ID_INTEL);
- pci_config_set_device_id(d->config, PCI_DEVICE_ID_INTEL_ICH9_6);
-
pci_set_word(d->wmask + PCI_STATUS,
- PCI_STATUS_SIG_SYSTEM_ERROR | PCI_STATUS_DETECTED_PARITY);
-
- pci_config_set_revision(d->config, ICH9_A2_SMB_REVISION);
- pci_config_set_prog_interface(d->config, ICH9_SMB_PI);
- pci_config_set_class(d->config, PCI_CLASS_SERIAL_SMBUS);
-
+ PCI_STATUS_SIG_SYSTEM_ERROR | PCI_STATUS_DETECTED_PARITY);
/* TODO? D31IP.SMIP in chipset configuration space */
pci_config_set_interrupt_pin(d->config, 0x01); /* interrupt pin 1 */
@@ -121,14 +115,30 @@ static int ich9_smb_initfn(PCIDevice *d)
/* TODO smb_io_base */
pci_set_byte(d->config + ICH9_SMB_HOSTC, 0);
/* TODO bar0, bar1: 64bit BAR support*/
- pci_register_bar(d, ICH9_SMB_SMB_BASE_BAR,
- ICH9_SMB_SMB_BASE_SIZE, PCI_BASE_ADDRESS_SPACE_IO,
- &ich9_smb_map_ioport);
+ memory_region_init_io(&s->mem_bar, &lpc_smb_mmio_ops, s, "ich9-smbus-bar",
+ ICH9_SMB_SMB_BASE_SIZE);
+ pci_register_bar(d, ICH9_SMB_SMB_BASE_BAR, PCI_BASE_ADDRESS_SPACE_IO,
+ &s->mem_bar);
pm_smbus_init(&d->qdev, &s->smb);
return 0;
}
+static void ich9_smb_class_init(ObjectClass *klass, void *data)
+{
+ DeviceClass *dc = DEVICE_CLASS(klass);
+ PCIDeviceClass *k = PCI_DEVICE_CLASS(klass);
+
+ k->vendor_id = PCI_VENDOR_ID_INTEL;
+ k->device_id = PCI_DEVICE_ID_INTEL_ICH9_6;
+ k->revision = ICH9_A2_SMB_REVISION;
+ k->class_id = PCI_CLASS_SERIAL_SMBUS;
+ dc->no_user = 1;
+ dc->vmsd = &vmstate_ich9_smbus;
+ dc->desc = "ICH9 SMBUS Bridge";
+ k->init = ich9_smbus_initfn;
+}
+
i2c_bus *ich9_smb_init(PCIBus *bus, int devfn, uint32_t smb_io_base)
{
PCIDevice *d =
@@ -137,18 +147,16 @@ i2c_bus *ich9_smb_init(PCIBus *bus, int devfn, uint32_t smb_io_base)
return s->smb.smbus;
}
-static PCIDeviceInfo ich9_smb_info = {
- .qdev.name = "ICH9 SMB",
- .qdev.desc = "ICH9 SMBUS Bridge",
- .qdev.size = sizeof(ICH9_SMBState),
- .qdev.vmsd = &vmstate_ich9_smbus,
- .qdev.no_user = 1,
- .init = ich9_smb_initfn,
+static const TypeInfo ich9_smb_info = {
+ .name = "ICH9 SMB",
+ .parent = TYPE_PCI_DEVICE,
+ .instance_size = sizeof(ICH9_SMBState),
+ .class_init = ich9_smb_class_init,
};
static void ich9_smb_register(void)
{
- pci_qdev_register(&ich9_smb_info);
+ type_register_static(&ich9_smb_info);
}
-device_init(ich9_smb_register);
+type_init(ich9_smb_register);