From patchwork Tue Oct 9 03:30:33 2012 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Jason Baron X-Patchwork-Id: 190204 Return-Path: X-Original-To: incoming@patchwork.ozlabs.org Delivered-To: patchwork-incoming@bilbo.ozlabs.org Received: from lists.gnu.org (lists.gnu.org [208.118.235.17]) (using TLSv1 with cipher AES256-SHA (256/256 bits)) (Client did not present a certificate) by ozlabs.org (Postfix) with ESMTPS id B2D6E2C008E for ; Tue, 9 Oct 2012 16:16:29 +1100 (EST) Received: from localhost ([::1]:51552 helo=lists.gnu.org) by lists.gnu.org with esmtp (Exim 4.71) (envelope-from ) id 1TLQXc-0002j5-LF for incoming@patchwork.ozlabs.org; Mon, 08 Oct 2012 23:31:32 -0400 Received: from eggs.gnu.org ([208.118.235.92]:57878) by lists.gnu.org with esmtp (Exim 4.71) (envelope-from ) id 1TLQWt-0001Jp-1S for qemu-devel@nongnu.org; Mon, 08 Oct 2012 23:30:52 -0400 Received: from Debian-exim by eggs.gnu.org with spam-scanned (Exim 4.71) (envelope-from ) id 1TLQWk-0001rE-Hy for qemu-devel@nongnu.org; Mon, 08 Oct 2012 23:30:46 -0400 Received: from mx1.redhat.com ([209.132.183.28]:59363) by eggs.gnu.org with esmtp (Exim 4.71) (envelope-from ) id 1TLQWk-0001qx-0k for qemu-devel@nongnu.org; Mon, 08 Oct 2012 23:30:38 -0400 Received: from int-mx10.intmail.prod.int.phx2.redhat.com (int-mx10.intmail.prod.int.phx2.redhat.com [10.5.11.23]) by mx1.redhat.com (8.14.4/8.14.4) with ESMTP id q993UYDg015300 (version=TLSv1/SSLv3 cipher=DHE-RSA-AES256-SHA bits=256 verify=OK); Mon, 8 Oct 2012 23:30:34 -0400 Received: from redhat.com (dhcp-185-114.bos.redhat.com [10.16.185.114]) by int-mx10.intmail.prod.int.phx2.redhat.com (8.14.4/8.14.4) with ESMTP id q993UXQh007332; Mon, 8 Oct 2012 23:30:34 -0400 Date: Mon, 8 Oct 2012 23:30:33 -0400 From: Jason Baron To: qemu-devel@nongnu.org Message-Id: In-Reply-To: References: X-Scanned-By: MIMEDefang 2.68 on 10.5.11.23 X-detected-operating-system: by eggs.gnu.org: Genre and OS details not recognized. X-Received-From: 209.132.183.28 Cc: aliguori@us.ibm.com, juzhang@redhat.com, mst@redhat.com, jan.kiszka@siemens.com, armbru@redhat.com, agraf@suse.de, blauwirbel@gmail.com, yamahata@valinux.co.jp, alex.williamson@redhat.com, kevin@koconnor.net, avi@redhat.com, mkletzan@redhat.com, pbonzini@redhat.com, lcapitulino@redhat.com, afaerber@suse.de, kraxel@redhat.com Subject: [Qemu-devel] [PATCH v2 13/21] q35: Re-base q35 X-BeenThere: qemu-devel@nongnu.org X-Mailman-Version: 2.1.14 Precedence: list List-Id: List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Errors-To: qemu-devel-bounces+incoming=patchwork.ozlabs.org@nongnu.org Sender: qemu-devel-bounces+incoming=patchwork.ozlabs.org@nongnu.org From: Jason Baron Rebase q35 - memory api updates, acpi updates, qom, update pci window 0xb0000000 Signed-off-by: Jason Baron --- hw/acpi_ich9.c | 98 +++++----- hw/acpi_ich9.h | 18 +- hw/i386/Makefile.objs | 1 + hw/pc.h | 2 + hw/pc_piix.c | 4 +- hw/pc_q35.c | 203 ++++++++++++------ hw/q35.c | 566 +++++++++++++++++++++++++++---------------------- hw/q35.h | 92 ++++++++- hw/q35_smbus.c | 78 ++++--- 9 files changed, 644 insertions(+), 418 deletions(-) diff --git a/hw/acpi_ich9.c b/hw/acpi_ich9.c index 59c0807..9e78b60 100644 --- a/hw/acpi_ich9.c +++ b/hw/acpi_ich9.c @@ -18,6 +18,7 @@ /* * Copyright (c) 2009 Isaku Yamahata * VA Linux Systems Japan K.K. + * Copyright (C) 2012 Jason Baron * * 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); } diff --git a/hw/acpi_ich9.h b/hw/acpi_ich9.h index f55c0e9..180c406 100644 --- a/hw/acpi_ich9.h +++ b/hw/acpi_ich9.h @@ -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 */ diff --git a/hw/i386/Makefile.objs b/hw/i386/Makefile.objs index 2f0c172..f24dc6b 100644 --- a/hw/i386/Makefile.objs +++ b/hw/i386/Makefile.objs @@ -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 diff --git a/hw/pc.h b/hw/pc.h index c78923c..125c1fd 100644 --- a/hw/pc.h +++ b/hw/pc.h @@ -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 */ diff --git a/hw/pc_piix.c b/hw/pc_piix.c index 668dccf..e133630 100644 --- a/hw/pc_piix.c +++ b/hw/pc_piix.c @@ -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; diff --git a/hw/pc_q35.c b/hw/pc_q35.c index 4f75d97..b6a619a 100644 --- a/hw/pc_q35.c +++ b/hw/pc_q35.c @@ -27,6 +27,7 @@ * Copyright (c) 2009, 2010 * Isaku Yamahata * VA Linux Systems Japan K.K. + * Copyright (C) 2012 Jason Baron * * 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) diff --git a/hw/q35.c b/hw/q35.c index 1776ac3..ff570ce 100644 --- a/hw/q35.c +++ b/hw/q35.c @@ -25,6 +25,7 @@ * Copyright (c) 2009, 2010, 2011 * Isaku Yamahata * VA Linux Systems Japan K.K. + * Copyright (C) 2012 Jason Baron * * 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); diff --git a/hw/q35.h b/hw/q35.h index be2e96b..75c8f0e 100644 --- a/hw/q35.h +++ b/hw/q35.h @@ -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 diff --git a/hw/q35_smbus.c b/hw/q35_smbus.c index fe445ac..5efbe6c 100644 --- a/hw/q35_smbus.c +++ b/hw/q35_smbus.c @@ -18,6 +18,7 @@ /* * Copyright (c) 2009 Isaku Yamahata * VA Linux Systems Japan K.K. + * Copyright (C) 2012 Jason Baron * * 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);