From patchwork Thu Jan 26 19:00:50 2012 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Anthony Liguori X-Patchwork-Id: 138068 Return-Path: X-Original-To: incoming@patchwork.ozlabs.org Delivered-To: patchwork-incoming@bilbo.ozlabs.org Received: from lists.gnu.org (lists.gnu.org [140.186.70.17]) (using TLSv1 with cipher AES256-SHA (256/256 bits)) (Client did not present a certificate) by ozlabs.org (Postfix) with ESMTPS id BEE2D1007D5 for ; Fri, 27 Jan 2012 08:27:57 +1100 (EST) Received: from localhost ([::1]:50734 helo=lists.gnu.org) by lists.gnu.org with esmtp (Exim 4.71) (envelope-from ) id 1RqUaR-0000tU-HN for incoming@patchwork.ozlabs.org; Thu, 26 Jan 2012 14:02:19 -0500 Received: from [140.186.70.92] (port=53493 helo=eggs.gnu.org) by lists.gnu.org with esmtp (Exim 4.71) (envelope-from ) id 1RqUZl-00089f-JO for qemu-devel@nongnu.org; Thu, 26 Jan 2012 14:01:47 -0500 Received: from Debian-exim by eggs.gnu.org with spam-scanned (Exim 4.71) (envelope-from ) id 1RqUZf-0007R9-Ko for qemu-devel@nongnu.org; Thu, 26 Jan 2012 14:01:34 -0500 Received: from cpe-70-123-132-139.austin.res.rr.com ([70.123.132.139]:42878 helo=localhost6.localdomain6) by eggs.gnu.org with esmtp (Exim 4.71) (envelope-from ) id 1RqUZf-0007Qz-Df for qemu-devel@nongnu.org; Thu, 26 Jan 2012 14:01:31 -0500 Received: from localhost6.localdomain6 (localhost.localdomain [127.0.0.1]) by localhost6.localdomain6 (8.14.4/8.14.4/Debian-2ubuntu1) with ESMTP id q0QJ1QDH031368; Thu, 26 Jan 2012 13:01:26 -0600 Received: (from anthony@localhost) by localhost6.localdomain6 (8.14.4/8.14.4/Submit) id q0QJ1OQe031367; Thu, 26 Jan 2012 13:01:24 -0600 From: Anthony Liguori To: qemu-devel@nongnu.org Date: Thu, 26 Jan 2012 13:00:50 -0600 Message-Id: <1327604460-31142-6-git-send-email-aliguori@us.ibm.com> X-Mailer: git-send-email 1.7.4.1 In-Reply-To: <1327604460-31142-1-git-send-email-aliguori@us.ibm.com> References: <1327604460-31142-1-git-send-email-aliguori@us.ibm.com> X-detected-operating-system: by eggs.gnu.org: Genre and OS details not recognized. X-Received-From: 70.123.132.139 Cc: Peter Maydell , Anthony Liguori , Jan Kiszka , Markus Armbruster , Avi Kivity , Paolo Bonzini Subject: [Qemu-devel] [PATCH 05/15] piix: create the HPET and RTC through composition 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 Signed-off-by: Anthony Liguori --- hw/hpet.c | 38 +------------------------- hw/hpet_emul.h | 40 ++++++++++++++++++++++++++++ hw/mc146818rtc.c | 30 ++------------------- hw/mc146818rtc.h | 27 +++++++++++++++++++ hw/pc.c | 38 +++++---------------------- hw/piix_pci.c | 76 ++++++++++++++++++++++++++++++++++++++++++++++------- 6 files changed, 145 insertions(+), 104 deletions(-) diff --git a/hw/hpet.c b/hw/hpet.c index b6ace4e..c5b8b9e 100644 --- a/hw/hpet.c +++ b/hw/hpet.c @@ -41,40 +41,6 @@ #define HPET_MSI_SUPPORT 0 -struct HPETState; -typedef struct HPETTimer { /* timers */ - uint8_t tn; /*timer number*/ - QEMUTimer *qemu_timer; - struct HPETState *state; - /* Memory-mapped, software visible timer registers */ - uint64_t config; /* configuration/cap */ - uint64_t cmp; /* comparator */ - uint64_t fsb; /* FSB route */ - /* Hidden register state */ - uint64_t period; /* Last value written to comparator */ - uint8_t wrap_flag; /* timer pop will indicate wrap for one-shot 32-bit - * mode. Next pop will be actual timer expiration. - */ -} HPETTimer; - -typedef struct HPETState { - SysBusDevice busdev; - MemoryRegion iomem; - uint64_t hpet_offset; - qemu_irq irqs[HPET_NUM_IRQ_ROUTES]; - uint32_t flags; - uint8_t rtc_irq_level; - uint8_t num_timers; - HPETTimer timer[HPET_MAX_TIMERS]; - - /* Memory-mapped, software visible registers */ - uint64_t capability; /* capabilities */ - uint64_t config; /* configuration */ - uint64_t isr; /* interrupt status reg */ - uint64_t hpet_counter; /* main counter */ - uint8_t hpet_id; /* instance id */ -} HPETState; - static uint32_t hpet_in_legacy_mode(HPETState *s) { return s->config & HPET_CFG_LEGACY; @@ -258,7 +224,7 @@ static const VMStateDescription vmstate_hpet_timer = { }; static const VMStateDescription vmstate_hpet = { - .name = "hpet", + .name = TYPE_HPET, .version_id = 2, .minimum_version_id = 1, .minimum_version_id_old = 1, @@ -714,7 +680,7 @@ static void hpet_device_class_init(ObjectClass *klass, void *data) } static TypeInfo hpet_device_info = { - .name = "hpet", + .name = TYPE_HPET, .parent = TYPE_SYS_BUS_DEVICE, .instance_size = sizeof(HPETState), .class_init = hpet_device_class_init, diff --git a/hw/hpet_emul.h b/hw/hpet_emul.h index 6128702..da8ecdc 100644 --- a/hw/hpet_emul.h +++ b/hw/hpet_emul.h @@ -13,6 +13,9 @@ #ifndef QEMU_HPET_EMUL_H #define QEMU_HPET_EMUL_H +#include "hw.h" +#include "sysbus.h" + #define HPET_BASE 0xfed00000 #define HPET_CLK_PERIOD 10000000ULL /* 10000000 femtoseconds == 10ns*/ @@ -68,4 +71,41 @@ struct hpet_fw_config } QEMU_PACKED; extern struct hpet_fw_config hpet_cfg; + +#define TYPE_HPET "hpet" + +struct HPETState; +typedef struct HPETTimer { /* timers */ + uint8_t tn; /*timer number*/ + QEMUTimer *qemu_timer; + struct HPETState *state; + /* Memory-mapped, software visible timer registers */ + uint64_t config; /* configuration/cap */ + uint64_t cmp; /* comparator */ + uint64_t fsb; /* FSB route */ + /* Hidden register state */ + uint64_t period; /* Last value written to comparator */ + uint8_t wrap_flag; /* timer pop will indicate wrap for one-shot 32-bit + * mode. Next pop will be actual timer expiration. + */ +} HPETTimer; + +typedef struct HPETState { + SysBusDevice busdev; + MemoryRegion iomem; + uint64_t hpet_offset; + qemu_irq irqs[HPET_NUM_IRQ_ROUTES]; + uint32_t flags; + uint8_t rtc_irq_level; + uint8_t num_timers; + HPETTimer timer[HPET_MAX_TIMERS]; + + /* Memory-mapped, software visible registers */ + uint64_t capability; /* capabilities */ + uint64_t config; /* configuration */ + uint64_t isr; /* interrupt status reg */ + uint64_t hpet_counter; /* main counter */ + uint8_t hpet_id; /* instance id */ +} HPETState; + #endif diff --git a/hw/mc146818rtc.c b/hw/mc146818rtc.c index 346a95e..f967e05 100644 --- a/hw/mc146818rtc.c +++ b/hw/mc146818rtc.c @@ -79,30 +79,6 @@ #define REG_C_PF 0x40 #define REG_C_AF 0x20 -typedef struct RTCState { - ISADevice dev; - MemoryRegion io; - uint8_t cmos_data[128]; - uint8_t cmos_index; - struct tm current_tm; - int32_t base_year; - qemu_irq irq; - qemu_irq sqw_irq; - int it_shift; - /* periodic timer */ - QEMUTimer *periodic_timer; - int64_t next_periodic_time; - /* second update */ - int64_t next_second_time; - uint16_t irq_reinject_on_ack_count; - uint32_t irq_coalesced; - uint32_t period; - QEMUTimer *coalesced_timer; - QEMUTimer *second_timer; - QEMUTimer *second_timer2; - Notifier clock_reset_notifier; -} RTCState; - static void rtc_set_time(RTCState *s); static void rtc_copy_date(RTCState *s); @@ -553,7 +529,7 @@ static int rtc_post_load(void *opaque, int version_id) } static const VMStateDescription vmstate_rtc = { - .name = "mc146818rtc", + .name = TYPE_RTC, .version_id = 2, .minimum_version_id = 1, .minimum_version_id_old = 1, @@ -687,7 +663,7 @@ ISADevice *rtc_init(ISABus *bus, int base_year, qemu_irq intercept_irq) ISADevice *dev; RTCState *s; - dev = isa_create(bus, "mc146818rtc"); + dev = isa_create(bus, TYPE_RTC); s = DO_UPCAST(RTCState, dev, dev); qdev_prop_set_int32(&dev->qdev, "base_year", base_year); qdev_init_nofail(&dev->qdev); @@ -715,7 +691,7 @@ static void rtc_class_initfn(ObjectClass *klass, void *data) } static TypeInfo mc146818rtc_info = { - .name = "mc146818rtc", + .name = TYPE_RTC, .parent = TYPE_ISA_DEVICE, .instance_size = sizeof(RTCState), .class_init = rtc_class_initfn, diff --git a/hw/mc146818rtc.h b/hw/mc146818rtc.h index f119930..ce807c0 100644 --- a/hw/mc146818rtc.h +++ b/hw/mc146818rtc.h @@ -2,9 +2,36 @@ #define MC146818RTC_H #include "isa.h" +#include "notify.h" #define RTC_ISA_IRQ 8 +#define TYPE_RTC "mc146818rtc" + +typedef struct RTCState { + ISADevice dev; + MemoryRegion io; + uint8_t cmos_data[128]; + uint8_t cmos_index; + struct tm current_tm; + int32_t base_year; + qemu_irq irq; + qemu_irq sqw_irq; + int it_shift; + /* periodic timer */ + QEMUTimer *periodic_timer; + int64_t next_periodic_time; + /* second update */ + int64_t next_second_time; + uint16_t irq_reinject_on_ack_count; + uint32_t irq_coalesced; + uint32_t period; + QEMUTimer *coalesced_timer; + QEMUTimer *second_timer; + QEMUTimer *second_timer2; + Notifier clock_reset_notifier; +} RTCState; + ISADevice *rtc_init(ISABus *bus, int base_year, qemu_irq intercept_irq); void rtc_set_memory(ISADevice *dev, int addr, int val); void rtc_set_date(ISADevice *dev, const struct tm *tm); diff --git a/hw/pc.c b/hw/pc.c index 4b11e44..d3eba63 100644 --- a/hw/pc.c +++ b/hw/pc.c @@ -1143,13 +1143,11 @@ static void cpu_request_exit(void *opaque, int irq, int level) } static void pc_basic_device_init(ISABus *isa_bus, qemu_irq *gsi, - ISADevice **rtc_state, - ISADevice **floppy, - bool no_vmport) + ISADevice **floppy, + bool no_vmport) { int i; DriveInfo *fd[MAX_FD]; - qemu_irq rtc_irq = NULL; qemu_irq *a20_line; ISADevice *i8042, *port92, *vmmouse, *pit; qemu_irq *cpu_exit_irq; @@ -1158,20 +1156,6 @@ static void pc_basic_device_init(ISABus *isa_bus, qemu_irq *gsi, register_ioport_write(0xf0, 1, 1, ioportF0_write, NULL); - if (!no_hpet) { - DeviceState *hpet = sysbus_try_create_simple("hpet", HPET_BASE, NULL); - - if (hpet) { - for (i = 0; i < GSI_NUM_PINS; i++) { - sysbus_connect_irq(sysbus_from_qdev(hpet), i, gsi[i]); - } - rtc_irq = qdev_get_gpio_in(hpet, 0); - } - } - *rtc_state = rtc_init(isa_bus, 2000, rtc_irq); - - qemu_register_boot_set(pc_boot_set, *rtc_state); - pit = pit_init(isa_bus, 0x40, 0); pcspk_init(pit); @@ -1377,7 +1361,6 @@ static void pc_init1(MemoryRegion *system_memory, isa_bus = isa_bus_new(NULL, system_io); no_hpet = 1; } - isa_bus_irqs(isa_bus, gsi); if (kvm_enabled() && kvm_irqchip_in_kernel()) { i8259 = kvm_i8259_init(isa_bus); @@ -1407,7 +1390,7 @@ static void pc_init1(MemoryRegion *system_memory, } /* init basic PC hardware */ - pc_basic_device_init(isa_bus, gsi, &rtc_state, &floppy, xen_enabled()); + pc_basic_device_init(isa_bus, gsi, &floppy, xen_enabled()); for(i = 0; i < nb_nics; i++) { NICInfo *nd = &nd_table[i]; @@ -1428,17 +1411,6 @@ static void pc_init1(MemoryRegion *system_memory, } idebus[0] = qdev_get_child_bus(&dev->qdev, "ide.0"); idebus[1] = qdev_get_child_bus(&dev->qdev, "ide.1"); - - /* FIXME there's some major spaghetti here. Somehow we create the - * devices on the PIIX before we actually create it. We create the - * PIIX3 deep in the recess of the i440fx creation too and then lose - * the DeviceState. - * - * For now, let's "fix" this by making judicious use of paths. This - * is not generally the right way to do this. - */ - object_property_add_child(object_resolve_path("/i440fx/piix3", NULL), - "rtc", (Object *)rtc_state, NULL); } else { for(i = 0; i < MAX_IDE_BUS; i++) { ISADevice *dev; @@ -1449,6 +1421,10 @@ static void pc_init1(MemoryRegion *system_memory, } } + /* FIXME */ + rtc_state = ISA_DEVICE(object_resolve_path("rtc", NULL)); + qemu_register_boot_set(pc_boot_set, rtc_state); + audio_init(isa_bus, pci_enabled ? pci_bus : NULL); pc_cmos_init(below_4g_mem_size, above_4g_mem_size, boot_device, diff --git a/hw/piix_pci.c b/hw/piix_pci.c index ec75725..5d7d175 100644 --- a/hw/piix_pci.c +++ b/hw/piix_pci.c @@ -30,6 +30,8 @@ #include "sysbus.h" #include "range.h" #include "xen.h" +#include "hpet_emul.h" +#include "mc146818rtc.h" /* * I440FX chipset data sheet. @@ -63,6 +65,13 @@ typedef struct PIIX3State { #endif uint64_t pic_levels; + bool hpet_enable; + + HPETState hpet; + RTCState rtc; + + ISABus *bus; + qemu_irq *pic; /* This member isn't used. Just for save/load compatibility */ @@ -309,20 +318,28 @@ static PCIBus *i440fx_common_init(const char *device_name, * connected to the IOAPIC directly. * These additional routes can be discovered through ACPI. */ if (xen_enabled()) { - piix3 = DO_UPCAST(PIIX3State, dev, - pci_create_simple_multifunction(b, -1, true, "PIIX3-xen")); + piix3 = PIIX3(object_new("PIIX3-xen")); + } else { + piix3 = PIIX3(object_new("PIIX3")); + } + + /* FIXME make this a property */ + piix3->pic = pic; + qdev_prop_set_uint32(DEVICE(piix3), "addr", PCI_DEVFN(1, 0)); + qdev_prop_set_bit(DEVICE(piix3), "multifunction", true); + qdev_set_parent_bus(DEVICE(piix3), BUS(s->bus)); + qdev_init_nofail(DEVICE(piix3)); + + if (xen_enabled()) { pci_bus_irqs(b, xen_piix3_set_irq, xen_pci_slot_get_pirq, - piix3, XEN_PIIX_NUM_PIRQS); + piix3, XEN_PIIX_NUM_PIRQS); } else { - piix3 = DO_UPCAST(PIIX3State, dev, - pci_create_simple_multifunction(b, -1, true, "PIIX3")); pci_bus_irqs(b, piix3_set_irq, pci_slot_get_pirq, piix3, PIIX_NUM_PIRQS); } + object_property_add_child(OBJECT(dev), "piix3", OBJECT(piix3), NULL); - piix3->pic = pic; - *isa_bus = DO_UPCAST(ISABus, qbus, - qdev_get_child_bus(&piix3->dev.qdev, "isa.0")); + *isa_bus = piix3->bus; *piix3_devfn = piix3->dev.devfn; @@ -498,14 +515,53 @@ static const VMStateDescription vmstate_piix3 = { static int piix3_realize(PCIDevice *dev) { - PIIX3State *d = DO_UPCAST(PIIX3State, dev, dev); + PIIX3State *s = PIIX3(dev); + qemu_irq rtc_irq; + + /* Initialize ISA Bus */ + s->bus = isa_bus_new(DEVICE(dev), pci_address_space_io(dev)); + isa_bus_irqs(s->bus, s->pic); + + /* Realize the RTC */ + qdev_set_parent_bus(DEVICE(&s->rtc), BUS(s->bus)); + qdev_init_nofail(DEVICE(&s->rtc)); + + /* Realize HPET */ + if (s->hpet_enable) { + int i; + + /* We need to introduce a proper IRQ and Memory QOM infrastructure + * so that the HPET isn't a sysbus device */ + qdev_set_parent_bus(DEVICE(&s->hpet), sysbus_get_default()); + qdev_init_nofail(DEVICE(&s->hpet)); + + sysbus_mmio_map(SYS_BUS_DEVICE(&s->hpet), 0, HPET_BASE); + for (i = 0; i < GSI_NUM_PINS; i++) { + sysbus_connect_irq(SYS_BUS_DEVICE(&s->hpet), i, s->pic[i]); + } + + rtc_irq = qdev_get_gpio_in(DEVICE(&s->hpet), 0); + } else { + isa_init_irq(ISA_DEVICE(&s->rtc), &rtc_irq, RTC_ISA_IRQ); + } + + /* Setup the RTC IRQ */ + s->rtc.irq = rtc_irq; - isa_bus_new(&d->dev.qdev, pci_address_space_io(dev)); return 0; } static void piix3_initfn(Object *obj) { + PIIX3State *s = PIIX3(obj); + + object_initialize(&s->hpet, TYPE_HPET); + object_property_add_child(obj, "hpet", OBJECT(&s->hpet), NULL); + + object_initialize(&s->rtc, TYPE_RTC); + object_property_add_child(obj, "rtc", OBJECT(&s->rtc), NULL); + + qdev_prop_set_int32(DEVICE(&s->rtc), "base_year", 2000); } static void piix3_class_init(ObjectClass *klass, void *data)