Patchwork [RFC,v1,10/20] piix3, ich9: create the HPET through composition

login
register
mail settings
Submitter Hu Tao
Date May 22, 2013, 5:33 a.m.
Message ID <6b5230f6f9cab8ae01f7f99ed4011c6177d9823d.1369193012.git.hutao@cn.fujitsu.com>
Download mbox | patch
Permalink /patch/245518/
State New
Headers show

Comments

Hu Tao - May 22, 2013, 5:33 a.m.
Signed-off-by: Hu Tao <hutao@cn.fujitsu.com>
---
 hw/i386/pc.c            | 22 +---------------------
 hw/i386/pc_q35.c        |  9 ++++++---
 hw/isa/lpc_ich9.c       | 28 ++++++++++++++++++++++++++++
 hw/pci-host/piix.c      | 30 ++++++++++++++++++++++++++++++
 hw/timer/hpet.c         |  2 +-
 include/hw/i386/ich9.h  |  2 ++
 include/hw/timer/hpet.h |  3 +++
 7 files changed, 71 insertions(+), 25 deletions(-)

Patch

diff --git a/hw/i386/pc.c b/hw/i386/pc.c
index 197d218..d0e7a41 100644
--- a/hw/i386/pc.c
+++ b/hw/i386/pc.c
@@ -1130,8 +1130,6 @@  void pc_basic_device_init(ISABus *isa_bus, qemu_irq *gsi,
     int i;
     DriveInfo *fd[MAX_FD];
     DeviceState *hpet = NULL;
-    int pit_isa_irq = 0;
-    qemu_irq pit_alt_irq = NULL;
     qemu_irq rtc_irq = NULL;
     qemu_irq *a20_line;
     ISADevice *i8042, *port92, *vmmouse, *pit = NULL;
@@ -1145,24 +1143,6 @@  void pc_basic_device_init(ISABus *isa_bus, qemu_irq *gsi,
     memory_region_init_io(ioportF0_io, &ioportF0_io_ops, NULL, "ioportF0", 1);
     memory_region_add_subregion(isa_bus->address_space_io, 0xf0, ioportF0_io);
 
-    /*
-     * Check if an HPET shall be created.
-     *
-     * Without KVM_CAP_PIT_STATE2, we cannot switch off the in-kernel PIT
-     * when the HPET wants to take over. Thus we have to disable the latter.
-     */
-    if (!no_hpet && (!kvm_irqchip_in_kernel() || kvm_has_pit_state2())) {
-        hpet = sysbus_try_create_simple("hpet", HPET_BASE, NULL);
-
-        if (hpet) {
-            for (i = 0; i < GSI_NUM_PINS; i++) {
-                sysbus_connect_irq(SYS_BUS_DEVICE(hpet), i, gsi[i]);
-            }
-            pit_isa_irq = -1;
-            pit_alt_irq = qdev_get_gpio_in(hpet, HPET_LEGACY_PIT_INT);
-            rtc_irq = qdev_get_gpio_in(hpet, HPET_LEGACY_RTC_INT);
-        }
-    }
     *rtc_state = rtc_init(isa_bus, 2000, rtc_irq);
 
     qemu_register_boot_set(pc_boot_set, *rtc_state);
@@ -1171,7 +1151,7 @@  void pc_basic_device_init(ISABus *isa_bus, qemu_irq *gsi,
         if (kvm_irqchip_in_kernel()) {
             pit = kvm_pit_init(isa_bus, 0x40);
         } else {
-            pit = pit_init(isa_bus, 0x40, pit_isa_irq, pit_alt_irq);
+            pit = pit_init(isa_bus, 0x40, 0, NULL);
         }
         if (hpet) {
             /* connect PIT to output control line of the HPET */
diff --git a/hw/i386/pc_q35.c b/hw/i386/pc_q35.c
index 7888dfe..4797118 100644
--- a/hw/i386/pc_q35.c
+++ b/hw/i386/pc_q35.c
@@ -135,12 +135,15 @@  static void pc_q35_init(QEMUMachineInitArgs *args)
     qdev_init_nofail(DEVICE(q35_host));
     host_bus = q35_host->host.pci.bus;
     /* create ISA bus */
-    lpc = pci_create_simple_multifunction(host_bus, PCI_DEVFN(ICH9_LPC_DEV,
-                                          ICH9_LPC_FUNC), true,
-                                          TYPE_ICH9_LPC_DEVICE);
+    lpc = PCI_DEVICE(object_new(TYPE_ICH9_LPC_DEVICE));
     ich9_lpc = ICH9_LPC_DEVICE(lpc);
     ich9_lpc->pic = gsi;
+    qdev_prop_set_int32(DEVICE(ich9_lpc), "addr",
+                        PCI_DEVFN(ICH9_LPC_DEV, ICH9_LPC_FUNC));
+    qdev_prop_set_bit(DEVICE(ich9_lpc), "multifunction", true);
+    qdev_set_parent_bus(DEVICE(ich9_lpc), BUS(host_bus));
     ich9_lpc->ioapic = gsi_state->ioapic_irq;
+    qdev_init_nofail(DEVICE(ich9_lpc));
     pci_bus_irqs(host_bus, ich9_lpc_set_irq, ich9_lpc_map_irq, ich9_lpc,
                  ICH9_LPC_NB_PIRQS);
     pci_bus_set_route_irq_fn(host_bus, ich9_route_intx_pin_to_irq);
diff --git a/hw/isa/lpc_ich9.c b/hw/isa/lpc_ich9.c
index 9e44758..8d6da8d 100644
--- a/hw/isa/lpc_ich9.c
+++ b/hw/isa/lpc_ich9.c
@@ -44,6 +44,7 @@ 
 #include "hw/pci/pci_bus.h"
 #include "exec/address-spaces.h"
 #include "sysemu/sysemu.h"
+#include "hw/timer/hpet.h"
 
 static int ich9_lpc_sci_irq(ICH9LPCState *lpc);
 
@@ -551,6 +552,21 @@  static int ich9_lpc_realize(PCIDevice *d)
                                         ICH9_RST_CNT_IOPORT, &lpc->rst_cnt_mem,
                                         1);
 
+    /* Realize HPET */
+    if (lpc->hpet) {
+        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(lpc->hpet, sysbus_get_default());
+        qdev_init_nofail(lpc->hpet);
+
+        sysbus_mmio_map(SYS_BUS_DEVICE(lpc->hpet), 0, HPET_BASE);
+        for (i = 0; i < GSI_NUM_PINS; i++) {
+            sysbus_connect_irq(SYS_BUS_DEVICE(lpc->hpet), i, lpc->pic[i]);
+        }
+    }
+
     return 0;
 }
 
@@ -596,6 +612,18 @@  static const VMStateDescription vmstate_ich9_lpc = {
 
 static void ich9_lpc_initfn(Object *obj)
 {
+    ICH9LPCState *s = ICH9_LPC_DEVICE(obj);
+
+    /*
+     * Check if an HPET shall be created.
+     *
+     * Without KVM_CAP_PIT_STATE2, we cannot switch off the in-kernel PIT
+     * when the HPET wants to take over. Thus we have to disable the latter.
+     */
+    if (!no_hpet && (!kvm_irqchip_in_kernel() || kvm_has_pit_state2())) {
+        s->hpet = DEVICE(object_new(TYPE_HPET));
+        object_property_add_child(obj, "hpet", OBJECT(s->hpet), NULL);
+    }
 }
 
 static void ich9_lpc_class_init(ObjectClass *klass, void *data)
diff --git a/hw/pci-host/piix.c b/hw/pci-host/piix.c
index 6796cb5..b6bfdf0 100644
--- a/hw/pci-host/piix.c
+++ b/hw/pci-host/piix.c
@@ -32,6 +32,7 @@ 
 #include "hw/xen/xen.h"
 #include "hw/pci-host/pam.h"
 #include "sysemu/sysemu.h"
+#include "hw/timer/hpet.h"
 
 /*
  * I440FX chipset data sheet.
@@ -70,6 +71,7 @@  typedef struct PIIX3State {
     uint64_t pic_levels;
 
     ISABus *bus;
+    DeviceState *hpet;
 
     qemu_irq *pic;
 
@@ -580,6 +582,21 @@  static int piix3_realize(PCIDevice *dev)
 
     s->bus = isa_bus_new(DEVICE(s), pci_address_space_io(dev));
 
+    /* Realize HPET */
+    if (s->hpet) {
+        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(s->hpet, sysbus_get_default());
+        qdev_init_nofail(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]);
+        }
+    }
+
     memory_region_init_io(&s->rcr_mem, &rcr_ops, s, "piix3-reset-control", 1);
     memory_region_add_subregion_overlap(pci_address_space_io(dev), RCR_IOPORT,
                                         &s->rcr_mem, 1);
@@ -589,6 +606,19 @@  static int piix3_realize(PCIDevice *dev)
 
 static void piix3_initfn(Object *obj)
 {
+    PIIX3State *s = PIIX3(obj);
+
+    /*
+     * Check if an HPET shall be created.
+     *
+     * Without KVM_CAP_PIT_STATE2, we cannot switch off the in-kernel PIT
+     * when the HPET wants to take over. Thus we have to disable the latter.
+     */
+    if (!no_hpet && (!kvm_irqchip_in_kernel() || kvm_has_pit_state2())) {
+        s->hpet = DEVICE(object_new(TYPE_HPET));
+        object_property_add_child(obj, "hpet", OBJECT(s->hpet), NULL);
+    }
+
 }
 
 static void piix3_class_init(ObjectClass *klass, void *data)
diff --git a/hw/timer/hpet.c b/hw/timer/hpet.c
index 95dd01d..8fbbf9e 100644
--- a/hw/timer/hpet.c
+++ b/hw/timer/hpet.c
@@ -278,7 +278,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,
diff --git a/include/hw/i386/ich9.h b/include/hw/i386/ich9.h
index c5f637b..8dc7d51 100644
--- a/include/hw/i386/ich9.h
+++ b/include/hw/i386/ich9.h
@@ -62,6 +62,8 @@  typedef struct ICH9LPCState {
     MemoryRegion rbca_mem;
     Notifier machine_ready;
 
+    DeviceState *hpet;
+
     qemu_irq *pic;
     qemu_irq *ioapic;
 } ICH9LPCState;
diff --git a/include/hw/timer/hpet.h b/include/hw/timer/hpet.h
index 757f79f..ab17ed9 100644
--- a/include/hw/timer/hpet.h
+++ b/include/hw/timer/hpet.h
@@ -71,4 +71,7 @@  struct hpet_fw_config
 } QEMU_PACKED;
 
 extern struct hpet_fw_config hpet_cfg;
+
+#define TYPE_HPET "hpet"
+
 #endif