Skip to contentSkip to conversation

pit, hpet, pcspk: fixes & preparation for KVM

PATCH Applied Jan Kiszka 2 participants 10 messages Feb 1, 2012 – Feb 17, 2012 KVM

lore
Share & tools
lore

Jan Kiszka

author
#0 lore raw

v4 cover pit, hpet, pcspk: fixes & preparation for KVM

Changes in V4:
- rebased over qom-upstream.13
- comment on rtc_irq_level clearing on reset
- fix call to isa_register_ioport by passing the pcspk device

Not changed:
- PIT pointer property of pcspk
(Paolo will port it together with other PROP_PTR users)

CC Paolo Bonzini <[email protected]>

Jan Kiszka (7):
i8254: Do not raise IRQ level on reset
hpet: Save/restore cached RTC IRQ level
i8254: Factor out interface header
i8254: Pass alternative IRQ output object on initialization
i8254: Rework & fix interaction with HPET in legacy mode
pcspk: Convert to qdev
i8254: Factor out pit_get_channel_info

 arch_init.c        |    1 +
 hw/alpha_dp264.c   |    3 +-
 hw/hpet.c          |   68 ++++++++++++++++++++++++++++----------
 hw/hpet_emul.h     |    3 ++
 hw/i82378.c        |    6 ++-
 hw/i8254.c         |   92 ++++++++++++++++++++++-----------------------------
 hw/i8254.h         |   57 ++++++++++++++++++++++++++++++++
 hw/mips_fulong2e.c |    3 +-
 hw/mips_jazz.c     |    6 ++-
 hw/mips_malta.c    |    3 +-
 hw/mips_r4k.c      |    3 +-
 hw/pc.c            |   19 ++++++++--
 hw/pc.h            |   29 ----------------
 hw/pcspk.c         |   84 +++++++++++++++++++++++++++++++++++++++--------
 hw/pcspk.h         |   45 +++++++++++++++++++++++++
 15 files changed, 296 insertions(+), 126 deletions(-)
 create mode 100644 hw/i8254.h
 create mode 100644 hw/pcspk.h
Signature · 1 line
1.7.3.4
author
#1 lore raw

PATCH v4 1/7 i8254: Do not raise IRQ level on reset

Avoid changing the IRQ level to high on reset as it may trigger spurious events. Instead, open-code the effects of pit_load_count(0) in the reset handler.

---
 hw/i8254.c |    8 +++++++-
 1 files changed, 7 insertions(+), 1 deletions(-)
hw/i8254.c +7 -1
index 522fed8..bfb303e 100644
@@ -481,7 +481,13 @@ static void pit_reset(DeviceState *dev)
         s = &pit->channels[i];
         s->mode = 3;
         s->gate = (i != 2);
-        pit_load_count(s, 0);
+        s->count_load_time = qemu_get_clock_ns(vm_clock);
+        s->count = 0x10000;
+        if (i == 0) {
+            s->next_transition_time =
+                pit_get_next_transition_time(s, s->count_load_time);
+            qemu_mod_timer(s->irq_timer, s->next_transition_time);
+        }
     }
 }
 
Signature · 1 line
1.7.3.4
author
#2 lore raw

PATCH v4 2/7 hpet: Save/restore cached RTC IRQ level

In reply to Jan Kiszka

In legacy mode, the HPET suppresses the RTC interrupt delivery via IRQ 8 but keeps track of the RTC output level and applies it when legacy mode is turned off again. This value has to be preserved across save/ restore as it cannot be reconstructed otherwise.

To document that a raised rtc_irq_level won't survive a vmload without a hpet/rtc_irq_level subsection, add an explicit clearing to the reset handler.

---
 hw/hpet.c |   29 +++++++++++++++++++++++++++++
 1 files changed, 29 insertions(+), 0 deletions(-)
hw/hpet.c +29 -0
index b6ace4e..ce981cc 100644
@@ -240,6 +240,24 @@ static int hpet_post_load(void *opaque, int version_id)
     return 0;
 }
 
+static bool hpet_rtc_irq_level_needed(void *opaque)
+{
+    HPETState *s = opaque;
+
+    return s->rtc_irq_level != 0;
+}
+
+static const VMStateDescription vmstate_hpet_rtc_irq_level = {
+    .name = "hpet/rtc_irq_level",
+    .version_id = 1,
+    .minimum_version_id = 1,
+    .minimum_version_id_old = 1,
+    .fields      = (VMStateField[]) {
+        VMSTATE_UINT8(rtc_irq_level, HPETState),
+        VMSTATE_END_OF_LIST()
+    }
+};
+
 static const VMStateDescription vmstate_hpet_timer = {
     .name = "hpet_timer",
     .version_id = 1,
@@ -273,6 +291,14 @@ static const VMStateDescription vmstate_hpet = {
         VMSTATE_STRUCT_VARRAY_UINT8(timer, HPETState, num_timers, 0,
                                     vmstate_hpet_timer, HPETTimer),
         VMSTATE_END_OF_LIST()
+    },
+    .subsections = (VMStateSubsection[]) {
+        {
+            .vmsd = &vmstate_hpet_rtc_irq_level,
+            .needed = hpet_rtc_irq_level_needed,
+        }, {
+            /* empty */
+        }
     }
 };
 
@@ -636,6 +662,9 @@ static void hpet_reset(DeviceState *d)
     hpet_cfg.hpet[s->hpet_id].event_timer_block_id = (uint32_t)s->capability;
     hpet_cfg.hpet[s->hpet_id].address = sysbus_from_qdev(d)->mmio[0].addr;
     count = 1;
+
+    /* to document that the RTC lowers its output on reset as well */
+    s->rtc_irq_level = 0;
 }
 
 static void hpet_handle_rtc_irq(void *opaque, int n, int level)
Signature · 1 line
1.7.3.4
author
#3 lore raw

PATCH v4 3/7 i8254: Factor out interface header

In reply to Jan Kiszka

Move the public interface of the PIT into its own header file and update all users.

---
 hw/alpha_dp264.c   |    1 +
 hw/hpet.c          |    1 +
 hw/i82378.c        |    1 +
 hw/i8254.c         |    1 +
 hw/i8254.h         |   54 ++++++++++++++++++++++++++++++++++++++++++++++++++++
 hw/mips_fulong2e.c |    1 +
 hw/mips_jazz.c     |    1 +
 hw/mips_malta.c    |    1 +
 hw/mips_r4k.c      |    1 +
 hw/pc.c            |    1 +
 hw/pc.h            |   25 ------------------------
 hw/pcspk.c         |    1 +
 12 files changed, 64 insertions(+), 25 deletions(-)
 create mode 100644 hw/i8254.h
hw/alpha_dp264.c +1 -0
index 876335a..4c0efd3 100644
@@ -14,6 +14,7 @@
 #include "sysemu.h"
 #include "mc146818rtc.h"
 #include "ide.h"
+#include "i8254.h"
 
 #define MAX_IDE_BUS 2
 
hw/hpet.c +1 -0
index ce981cc..884043c 100644
@@ -31,6 +31,7 @@
 #include "hpet_emul.h"
 #include "sysbus.h"
 #include "mc146818rtc.h"
+#include "i8254.h"
 
 //#define HPET_DEBUG
 #ifdef HPET_DEBUG
hw/i82378.c +1 -0
index 9c3efe8..eb02963 100644
@@ -19,6 +19,7 @@
 
 #include "pci.h"
 #include "pc.h"
+#include "i8254.h"
 
 //#define DEBUG_I82378
 
hw/i8254.c +1 -0
index bfb303e..17ceba7 100644
@@ -25,6 +25,7 @@
 #include "pc.h"
 #include "isa.h"
 #include "qemu-timer.h"
+#include "i8254.h"
 
 //#define DEBUG_PIT
 
hw/i8254.h new file +54 -0

54 lines not on this page · raw message

hw/mips_fulong2e.c +1 -0
index 163a668..ead72ae 100644
@@ -40,6 +40,7 @@
 #include "elf.h"
 #include "vt82c686.h"
 #include "mc146818rtc.h"
+#include "i8254.h"
 #include "blockdev.h"
 #include "exec-memory.h"
 
hw/mips_jazz.c +1 -0
index 63165b9..61dee4d 100644
@@ -36,6 +36,7 @@
 #include "mips-bios.h"
 #include "loader.h"
 #include "mc146818rtc.h"
+#include "i8254.h"
 #include "blockdev.h"
 #include "sysbus.h"
 #include "exec-memory.h"
hw/mips_malta.c +1 -0
index d232630..c868d90 100644
@@ -45,6 +45,7 @@
 #include "loader.h"
 #include "elf.h"
 #include "mc146818rtc.h"
+#include "i8254.h"
 #include "blockdev.h"
 #include "exec-memory.h"
 #include "sysbus.h"             /* SysBusDevice */
hw/mips_r4k.c +1 -0
index 1c0615c..1b3ec2d 100644
@@ -22,6 +22,7 @@
 #include "loader.h"
 #include "elf.h"
 #include "mc146818rtc.h"
+#include "i8254.h"
 #include "blockdev.h"
 #include "exec-memory.h"
 
hw/pc.c +1 -0
index 7f3aa65..4140f05 100644
@@ -36,6 +36,7 @@
 #include "elf.h"
 #include "multiboot.h"
 #include "mc146818rtc.h"
+#include "i8254.h"
 #include "msi.h"
 #include "sysbus.h"
 #include "sysemu.h"
hw/pc.h +0 -25
index c666ec9..b08708d 100644
@@ -81,31 +81,6 @@ typedef struct GSIState {
 
 void gsi_handler(void *opaque, int n, int level);
 
-/* i8254.c */
-
-#define PIT_FREQ 1193182
-
-static inline ISADevice *pit_init(ISABus *bus, int base, int irq)
-{
-    ISADevice *dev;
-
-    dev = isa_create(bus, "isa-pit");
-    qdev_prop_set_uint32(&dev->qdev, "iobase", base);
-    qdev_prop_set_uint32(&dev->qdev, "irq", irq);
-    qdev_init_nofail(&dev->qdev);
-
-    return dev;
-}
-
-void pit_set_gate(ISADevice *dev, int channel, int val);
-int pit_get_gate(ISADevice *dev, int channel);
-int pit_get_initial_count(ISADevice *dev, int channel);
-int pit_get_mode(ISADevice *dev, int channel);
-int pit_get_out(ISADevice *dev, int channel, int64_t current_time);
-
-void hpet_pit_disable(void);
-void hpet_pit_enable(void);
-
 /* vmport.c */
 static inline void vmport_init(ISABus *bus)
 {
hw/pcspk.c +1 -0
index acb0167..43df818 100644
@@ -27,6 +27,7 @@
 #include "isa.h"
 #include "audio/audio.h"
 #include "qemu-timer.h"
+#include "i8254.h"
 
 #define PCSPK_BUF_LEN 1792
 #define PCSPK_SAMPLE_RATE 32000
Signature · 1 line
1.7.3.4
author
#4 lore raw

PATCH v4 4/7 i8254: Pass alternative IRQ output object on initialization

In reply to Jan Kiszka

HPET legacy emulation will require control over the PIT IRQ output. To enable this, add support for an alternative IRQ output object to the PIT factory function. If the isa_irq number is < 0, this object will be used.

This also removes the IRQ number property from the PIT class as we now use a generic GPIO output pin that is connected by the factory function.

---
 hw/alpha_dp264.c   |    2 +-
 hw/i82378.c        |    2 +-
 hw/i8254.c         |    4 +---
 hw/i8254.h         |    6 ++++--
 hw/mips_fulong2e.c |    2 +-
 hw/mips_jazz.c     |    2 +-
 hw/mips_malta.c    |    2 +-
 hw/mips_r4k.c      |    2 +-
 hw/pc.c            |    2 +-
 9 files changed, 12 insertions(+), 12 deletions(-)
hw/alpha_dp264.c +1 -1
index 4c0efd3..ea0fd95 100644
@@ -73,7 +73,7 @@ static void clipper_init(ram_addr_t ram_size,
                            clipper_pci_map_irq);
 
     rtc_init(isa_bus, 1980, rtc_irq);
-    pit_init(isa_bus, 0x40, 0);
+    pit_init(isa_bus, 0x40, 0, NULL);
     isa_create_simple(isa_bus, "i8042");
 
     /* VGA setup.  Don't bother loading the bios.  */
hw/i82378.c +1 -1
index eb02963..ce64767 100644
@@ -192,7 +192,7 @@ static void i82378_init(DeviceState *dev, I82378State *s)
     isa_bus_irqs(isabus, s->i8259);
 
     /* 1 82C54 (pit) */
-    pit = pit_init(isabus, 0x40, 0);
+    pit = pit_init(isabus, 0x40, 0, NULL);
 
     /* speaker */
     pcspk_init(pit);
hw/i8254.c +1 -3
index 17ceba7..7ce27bb 100644
@@ -57,7 +57,6 @@ typedef struct PITChannelState {
 typedef struct PITState {
     ISADevice dev;
     MemoryRegion ioports;
-    uint32_t irq;
     uint32_t iobase;
     PITChannelState channels[3];
 } PITState;
@@ -532,7 +531,7 @@ static int pit_initfn(ISADevice *dev)
     s = &pit->channels[0];
     /* the timer 0 is connected to an IRQ */
     s->irq_timer = qemu_new_timer_ns(vm_clock, pit_irq_timer, s);
-    s->irq = isa_get_irq(dev, pit->irq);
+    qdev_init_gpio_out(&dev->qdev, &s->irq, 1);
 
     memory_region_init_io(&pit->ioports, &pit_ioport_ops, pit, "pit", 4);
     isa_register_ioport(dev, &pit->ioports, pit->iobase);
@@ -543,7 +542,6 @@ static int pit_initfn(ISADevice *dev)
 }
 
 static Property pit_properties[] = {
-    DEFINE_PROP_UINT32("irq", PITState, irq,  -1),
     DEFINE_PROP_HEX32("iobase", PITState, iobase,  -1),
     DEFINE_PROP_END_OF_LIST(),
 };
hw/i8254.h +4 -2
index cd3111c..fc64a63 100644
@@ -30,14 +30,16 @@
 
 #define PIT_FREQ 1193182
 
-static inline ISADevice *pit_init(ISABus *bus, int base, int irq)
+static inline ISADevice *pit_init(ISABus *bus, int base, int isa_irq,
+                                  qemu_irq alt_irq)
 {
     ISADevice *dev;
 
     dev = isa_create(bus, "isa-pit");
     qdev_prop_set_uint32(&dev->qdev, "iobase", base);
-    qdev_prop_set_uint32(&dev->qdev, "irq", irq);
     qdev_init_nofail(&dev->qdev);
+    qdev_connect_gpio_out(&dev->qdev, 0,
+                          isa_irq >= 0 ? isa_get_irq(dev, isa_irq) : alt_irq);
 
     return dev;
 }
hw/mips_fulong2e.c +1 -1
index ead72ae..e3ba9dd 100644
@@ -364,7 +364,7 @@ static void mips_fulong2e_init(ram_addr_t ram_size, const char *boot_device,
     smbus_eeprom_init(smbus, 1, eeprom_spd, sizeof(eeprom_spd));
 
     /* init other devices */
-    pit = pit_init(isa_bus, 0x40, 0);
+    pit = pit_init(isa_bus, 0x40, 0, NULL);
     cpu_exit_irq = qemu_allocate_irqs(cpu_request_exit, NULL, 1);
     DMA_init(0, cpu_exit_irq);
 
hw/mips_jazz.c +1 -1
index 61dee4d..b61b218 100644
@@ -192,7 +192,7 @@ static void mips_jazz_init(MemoryRegion *address_space,
     isa_bus_irqs(isa_bus, i8259);
     cpu_exit_irq = qemu_allocate_irqs(cpu_request_exit, NULL, 1);
     DMA_init(0, cpu_exit_irq);
-    pit = pit_init(isa_bus, 0x40, 0);
+    pit = pit_init(isa_bus, 0x40, 0, NULL);
     pcspk_init(pit);
 
     /* ISA IO space at 0x90000000 */
hw/mips_malta.c +1 -1
index c868d90..feae684 100644
@@ -970,7 +970,7 @@ void mips_malta_init (ram_addr_t ram_size,
                           isa_get_irq(NULL, 9), NULL, NULL, 0);
     /* TODO: Populate SPD eeprom data.  */
     smbus_eeprom_init(smbus, 8, NULL, 0);
-    pit = pit_init(isa_bus, 0x40, 0);
+    pit = pit_init(isa_bus, 0x40, 0, NULL);
     cpu_exit_irq = qemu_allocate_irqs(cpu_request_exit, NULL, 1);
     DMA_init(0, cpu_exit_irq);
 
hw/mips_r4k.c +1 -1
index 1b3ec2d..83401f0 100644
@@ -270,7 +270,7 @@ void mips_r4k_init (ram_addr_t ram_size,
     isa_mmio_init(0x14000000, 0x00010000);
     isa_mem_base = 0x10000000;
 
-    pit = pit_init(isa_bus, 0x40, 0);
+    pit = pit_init(isa_bus, 0x40, 0, NULL);
 
     for(i = 0; i < MAX_SERIAL_PORTS; i++) {
         if (serial_hds[i]) {
hw/pc.c +1 -1
index 4140f05..6218733 100644
@@ -1161,7 +1161,7 @@ void pc_basic_device_init(ISABus *isa_bus, qemu_irq *gsi,
 
     qemu_register_boot_set(pc_boot_set, *rtc_state);
 
-    pit = pit_init(isa_bus, 0x40, 0);
+    pit = pit_init(isa_bus, 0x40, 0, NULL);
     pcspk_init(pit);
 
     for(i = 0; i < MAX_SERIAL_PORTS; i++) {
Signature · 1 line
1.7.3.4
author
#5 lore raw

PATCH v4 5/7 i8254: Rework & fix interaction with HPET in legacy mode

In reply to Jan Kiszka

When the HPET enters legacy mode, the IRQ output of the PIT is suppressed and replaced by the HPET timer 0. But the current code to emulate this was broken in many ways. It reset the PIT state after re-enabling, it worked against a stale static PIT structure, and it did not properly saved/restored the IRQ output mask in the PIT vmstate.

This patch solves the PIT IRQ control in a different way. On x86, it both redirects the PIT IRQ to the HPET, just like the RTC. But it also keeps the control line from the HPET to the PIT. This allows to disable the PIT QEMU timer when it is not needed. The PIT's view on the control line state is now saved in the same format that qemu-kvm is already using.

Note that, in contrast to the suppressed RTC IRQ line, we do not need to save/restore the PIT line state in the HPET. As we trigger a PIT IRQ update via the control line, the line state is reconstructed on mode switch.

---
 hw/hpet.c      |   38 ++++++++++++++++++++------------------
 hw/hpet_emul.h |    3 +++
 hw/i8254.c     |   46 ++++++++++++++++++++++------------------------
 hw/i8254.h     |    3 ---
 hw/pc.c        |   15 ++++++++++++---
 5 files changed, 57 insertions(+), 48 deletions(-)
hw/hpet.c +20 -18
index 884043c..4636d50 100644
@@ -65,6 +65,7 @@ typedef struct HPETState {
     qemu_irq irqs[HPET_NUM_IRQ_ROUTES];
     uint32_t flags;
     uint8_t rtc_irq_level;
+    qemu_irq pit_enabled;
     uint8_t num_timers;
     HPETTimer timer[HPET_MAX_TIMERS];
 
@@ -573,12 +574,15 @@ static void hpet_ram_write(void *opaque, target_phys_addr_t addr,
                     hpet_del_timer(&s->timer[i]);
                 }
             }
-            /* i8254 and RTC are disabled when HPET is in legacy mode */
+            /* i8254 and RTC output pins are disabled
+             * when HPET is in legacy mode */
             if (activating_bit(old_val, new_val, HPET_CFG_LEGACY)) {
-                hpet_pit_disable();
+                qemu_set_irq(s->pit_enabled, 0);
+                qemu_irq_lower(s->irqs[0]);
                 qemu_irq_lower(s->irqs[RTC_ISA_IRQ]);
             } else if (deactivating_bit(old_val, new_val, HPET_CFG_LEGACY)) {
-                hpet_pit_enable();
+                qemu_irq_lower(s->irqs[0]);
+                qemu_set_irq(s->pit_enabled, 1);
                 qemu_set_irq(s->irqs[RTC_ISA_IRQ], s->rtc_irq_level);
             }
             break;
@@ -632,7 +636,6 @@ static void hpet_reset(DeviceState *d)
 {
     HPETState *s = FROM_SYSBUS(HPETState, sysbus_from_qdev(d));
     int i;
-    static int count = 0;
 
     for (i = 0; i < s->num_timers; i++) {
         HPETTimer *timer = &s->timer[i];
@@ -649,32 +652,30 @@ static void hpet_reset(DeviceState *d)
         timer->wrap_flag = 0;
     }
 
+    qemu_set_irq(s->pit_enabled, 1);
     s->hpet_counter = 0ULL;
     s->hpet_offset = 0ULL;
     s->config = 0ULL;
-    if (count > 0) {
-        /* we don't enable pit when hpet_reset is first called (by hpet_init)
-         * because hpet is taking over for pit here. On subsequent invocations,
-         * hpet_reset is called due to system reset. At this point control must
-         * be returned to pit until SW reenables hpet.
-         */
-        hpet_pit_enable();
-    }
     hpet_cfg.hpet[s->hpet_id].event_timer_block_id = (uint32_t)s->capability;
     hpet_cfg.hpet[s->hpet_id].address = sysbus_from_qdev(d)->mmio[0].addr;
-    count = 1;
 
     /* to document that the RTC lowers its output on reset as well */
     s->rtc_irq_level = 0;
 }
 
-static void hpet_handle_rtc_irq(void *opaque, int n, int level)
+static void hpet_handle_legacy_irq(void *opaque, int n, int level)
 {
     HPETState *s = FROM_SYSBUS(HPETState, opaque);
 
-    s->rtc_irq_level = level;
-    if (!hpet_in_legacy_mode(s)) {
-        qemu_set_irq(s->irqs[RTC_ISA_IRQ], level);
+    if (n == HPET_LEGACY_PIT_INT) {
+        if (!hpet_in_legacy_mode(s)) {
+            qemu_set_irq(s->irqs[0], level);
+        }
+    } else {
+        s->rtc_irq_level = level;
+        if (!hpet_in_legacy_mode(s)) {
+            qemu_set_irq(s->irqs[RTC_ISA_IRQ], level);
+        }
     }
 }
 
@@ -717,7 +718,8 @@ static int hpet_init(SysBusDevice *dev)
     s->capability |= (s->num_timers - 1) << HPET_ID_NUM_TIM_SHIFT;
     s->capability |= ((HPET_CLK_PERIOD) << 32);
 
-    qdev_init_gpio_in(&dev->qdev, hpet_handle_rtc_irq, 1);
+    qdev_init_gpio_in(&dev->qdev, hpet_handle_legacy_irq, 2);
+    qdev_init_gpio_out(&dev->qdev, &s->pit_enabled, 1);
 
     /* HPET Area */
     memory_region_init_io(&s->iomem, &hpet_ram_ops, s, "hpet", 0x400);
hw/hpet_emul.h +3 -0
index 6128702..757f79f 100644
@@ -22,6 +22,9 @@
 
 #define HPET_NUM_IRQ_ROUTES     32
 
+#define HPET_LEGACY_PIT_INT     0
+#define HPET_LEGACY_RTC_INT     1
+
 #define HPET_CFG_ENABLE 0x001
 #define HPET_CFG_LEGACY 0x002
 
hw/i8254.c +22 -24

100 lines not on this page · raw message

hw/i8254.h +0 -3
index fc64a63..8ad8e07 100644
@@ -50,7 +50,4 @@ int pit_get_initial_count(ISADevice *dev, int channel);
 int pit_get_mode(ISADevice *dev, int channel);
 int pit_get_out(ISADevice *dev, int channel, int64_t current_time);
 
-void hpet_pit_disable(void);
-void hpet_pit_enable(void);
-
 #endif /* !HW_I8254_H */
hw/pc.c +12 -3
index 6218733..571e6c3 100644
@@ -1138,6 +1138,9 @@ 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;
@@ -1148,20 +1151,26 @@ 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);
+        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);
+            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);
 
-    pit = pit_init(isa_bus, 0x40, 0, NULL);
+    pit = pit_init(isa_bus, 0x40, pit_isa_irq, pit_alt_irq);
+    if (hpet) {
+        /* connect PIT to output control line of the HPET */
+        qdev_connect_gpio_out(hpet, 0, qdev_get_gpio_in(&pit->qdev, 0));
+    }
     pcspk_init(pit);
 
     for(i = 0; i < MAX_SERIAL_PORTS; i++) {
Signature · 1 line
1.7.3.4
author
#6 lore raw

PATCH v4 6/7 pcspk: Convert to qdev

In reply to Jan Kiszka

Convert the PC speaker device to a qdev ISA model. Move the public interface to a dedicated header file at this chance.

CC Paolo Bonzini <[email protected]>
---
 arch_init.c    |    1 +
 hw/i82378.c    |    3 +-
 hw/mips_jazz.c |    3 +-
 hw/pc.c        |    3 +-
 hw/pc.h        |    4 ---
 hw/pcspk.c     |   67 +++++++++++++++++++++++++++++++++++++++++++++++--------
 hw/pcspk.h     |   45 +++++++++++++++++++++++++++++++++++++
 7 files changed, 109 insertions(+), 17 deletions(-)
 create mode 100644 hw/pcspk.h
arch_init.c +1 -0
index 2366511..a45485b 100644
@@ -42,6 +42,7 @@
 #include "gdbstub.h"
 #include "hw/smbios.h"
 #include "exec-memory.h"
+#include "hw/pcspk.h"
 
 #ifdef TARGET_SPARC
 int graphic_width = 1024;
hw/i82378.c +2 -1
index ce64767..e01acc1 100644
@@ -20,6 +20,7 @@
 #include "pci.h"
 #include "pc.h"
 #include "i8254.h"
+#include "pcspk.h"
 
 //#define DEBUG_I82378
 
@@ -195,7 +196,7 @@ static void i82378_init(DeviceState *dev, I82378State *s)
     pit = pit_init(isabus, 0x40, 0, NULL);
 
     /* speaker */
-    pcspk_init(pit);
+    pcspk_init(isabus, pit);
 
     /* 2 82C37 (dma) */
     DMA_init(1, &s->out[1]);
hw/mips_jazz.c +2 -1
index b61b218..65608dc 100644
@@ -37,6 +37,7 @@
 #include "loader.h"
 #include "mc146818rtc.h"
 #include "i8254.h"
+#include "pcspk.h"
 #include "blockdev.h"
 #include "sysbus.h"
 #include "exec-memory.h"
@@ -193,7 +194,7 @@ static void mips_jazz_init(MemoryRegion *address_space,
     cpu_exit_irq = qemu_allocate_irqs(cpu_request_exit, NULL, 1);
     DMA_init(0, cpu_exit_irq);
     pit = pit_init(isa_bus, 0x40, 0, NULL);
-    pcspk_init(pit);
+    pcspk_init(isa_bus, pit);
 
     /* ISA IO space at 0x90000000 */
     isa_mmio_init(0x90000000, 0x01000000);
hw/pc.c +2 -1
index 571e6c3..a04f9ca 100644
@@ -37,6 +37,7 @@
 #include "multiboot.h"
 #include "mc146818rtc.h"
 #include "i8254.h"
+#include "pcspk.h"
 #include "msi.h"
 #include "sysbus.h"
 #include "sysemu.h"
@@ -1171,7 +1172,7 @@ void pc_basic_device_init(ISABus *isa_bus, qemu_irq *gsi,
         /* connect PIT to output control line of the HPET */
         qdev_connect_gpio_out(hpet, 0, qdev_get_gpio_in(&pit->qdev, 0));
     }
-    pcspk_init(pit);
+    pcspk_init(isa_bus, pit);
 
     for(i = 0; i < MAX_SERIAL_PORTS; i++) {
         if (serial_hds[i]) {
hw/pc.h +0 -4
index b08708d..1b47bbd 100644
@@ -149,10 +149,6 @@ void piix4_smbus_register_device(SMBusDevice *dev, uint8_t addr);
 /* hpet.c */
 extern int no_hpet;
 
-/* pcspk.c */
-void pcspk_init(ISADevice *pit);
-int pcspk_audio_init(ISABus *bus);
-
 /* piix_pci.c */
 struct PCII440FXState;
 typedef struct PCII440FXState PCII440FXState;
hw/pcspk.c +57 -10

112 lines not on this page · raw message

hw/pcspk.h new file +45 -0

45 lines not on this page · raw message

Signature · 1 line
1.7.3.4
author
#7 lore raw

PATCH v5 6/7 pcspk: Convert to qdev

Convert the PC speaker device to a qdev ISA model. Move the public interface to a dedicated header file at this chance.

CC Paolo Bonzini <[email protected]>

---

Trivial rebase over git head. Would be great if this series could be merged now quickly.

 arch_init.c    |    1 +
 hw/i82378.c    |    3 +-
 hw/mips_jazz.c |    3 +-
 hw/pc.c        |    3 +-
 hw/pc.h        |    4 ---
 hw/pcspk.c     |   67 +++++++++++++++++++++++++++++++++++++++++++++++--------
 hw/pcspk.h     |   45 +++++++++++++++++++++++++++++++++++++
 7 files changed, 109 insertions(+), 17 deletions(-)
 create mode 100644 hw/pcspk.h
arch_init.c +1 -0
index 699bdd1..a95ef49 100644
@@ -42,6 +42,7 @@
 #include "gdbstub.h"
 #include "hw/smbios.h"
 #include "exec-memory.h"
+#include "hw/pcspk.h"
 
 #ifdef TARGET_SPARC
 int graphic_width = 1024;
hw/i82378.c +2 -1
index cc41564..faad1a3 100644
@@ -20,6 +20,7 @@
 #include "pci.h"
 #include "pc.h"
 #include "i8254.h"
+#include "pcspk.h"
 
 //#define DEBUG_I82378
 
@@ -195,7 +196,7 @@ static void i82378_init(DeviceState *dev, I82378State *s)
     pit = pit_init(isabus, 0x40, 0, NULL);
 
     /* speaker */
-    pcspk_init(pit);
+    pcspk_init(isabus, pit);
 
     /* 2 82C37 (dma) */
     DMA_init(1, &s->out[1]);
hw/mips_jazz.c +2 -1
index b61b218..65608dc 100644
@@ -37,6 +37,7 @@
 #include "loader.h"
 #include "mc146818rtc.h"
 #include "i8254.h"
+#include "pcspk.h"
 #include "blockdev.h"
 #include "sysbus.h"
 #include "exec-memory.h"
@@ -193,7 +194,7 @@ static void mips_jazz_init(MemoryRegion *address_space,
     cpu_exit_irq = qemu_allocate_irqs(cpu_request_exit, NULL, 1);
     DMA_init(0, cpu_exit_irq);
     pit = pit_init(isa_bus, 0x40, 0, NULL);
-    pcspk_init(pit);
+    pcspk_init(isa_bus, pit);
 
     /* ISA IO space at 0x90000000 */
     isa_mmio_init(0x90000000, 0x01000000);
hw/pc.c +2 -1
index 8e26563..5746129 100644
@@ -37,6 +37,7 @@
 #include "multiboot.h"
 #include "mc146818rtc.h"
 #include "i8254.h"
+#include "pcspk.h"
 #include "msi.h"
 #include "sysbus.h"
 #include "sysemu.h"
@@ -1172,7 +1173,7 @@ void pc_basic_device_init(ISABus *isa_bus, qemu_irq *gsi,
         /* connect PIT to output control line of the HPET */
         qdev_connect_gpio_out(hpet, 0, qdev_get_gpio_in(&pit->qdev, 0));
     }
-    pcspk_init(pit);
+    pcspk_init(isa_bus, pit);
 
     for(i = 0; i < MAX_SERIAL_PORTS; i++) {
         if (serial_hds[i]) {
hw/pc.h +0 -4
index b08708d..1b47bbd 100644
@@ -149,10 +149,6 @@ void piix4_smbus_register_device(SMBusDevice *dev, uint8_t addr);
 /* hpet.c */
 extern int no_hpet;
 
-/* pcspk.c */
-void pcspk_init(ISADevice *pit);
-int pcspk_audio_init(ISABus *bus);
-
 /* piix_pci.c */
 struct PCII440FXState;
 typedef struct PCII440FXState PCII440FXState;
hw/pcspk.c +57 -10

112 lines not on this page · raw message

hw/pcspk.h new file +45 -0

45 lines not on this page · raw message

Signature · 1 line
1.7.3.4
author
#8 lore raw

PATCH v4 7/7 i8254: Factor out pit_get_channel_info

In reply to Jan Kiszka

Instead of providing 4 individual query functions for mode, gate, output and initial counter state, introduce a service that queries all information at once. This comes with tiny additional costs for pcspk_callback but with a much cleaner interface. Also, it will simplify the implementation of the KVM in-kernel PIT model.

---
 hw/i8254.c |   35 ++++++++++-------------------------
 hw/i8254.h |   12 ++++++++----
 hw/pcspk.c |   16 +++++++++++-----
 3 files changed, 29 insertions(+), 34 deletions(-)
hw/i8254.c +10 -25
index ac5432c..be39c55 100644
@@ -90,7 +90,7 @@ static int pit_get_count(PITChannelState *s)
 }
 
 /* get pit output bit */
-static int pit_get_out1(PITChannelState *s, int64_t current_time)
+static int pit_get_out(PITChannelState *s, int64_t current_time)
 {
     uint64_t d;
     int out;
@@ -122,13 +122,6 @@ static int pit_get_out1(PITChannelState *s, int64_t current_time)
     return out;
 }
 
-int pit_get_out(ISADevice *dev, int channel, int64_t current_time)
-{
-    PITState *pit = DO_UPCAST(PITState, dev, dev);
-    PITChannelState *s = &pit->channels[channel];
-    return pit_get_out1(s, current_time);
-}
-
 /* return -1 if no transition will occur.  */
 static int64_t pit_get_next_transition_time(PITChannelState *s,
                                             int64_t current_time)
@@ -215,25 +208,15 @@ void pit_set_gate(ISADevice *dev, int channel, int val)
     s->gate = val;
 }
 
-int pit_get_gate(ISADevice *dev, int channel)
-{
-    PITState *pit = DO_UPCAST(PITState, dev, dev);
-    PITChannelState *s = &pit->channels[channel];
-    return s->gate;
-}
-
-int pit_get_initial_count(ISADevice *dev, int channel)
+void pit_get_channel_info(ISADevice *dev, int channel, PITChannelInfo *info)
 {
     PITState *pit = DO_UPCAST(PITState, dev, dev);
     PITChannelState *s = &pit->channels[channel];
-    return s->count;
-}
 
-int pit_get_mode(ISADevice *dev, int channel)
-{
-    PITState *pit = DO_UPCAST(PITState, dev, dev);
-    PITChannelState *s = &pit->channels[channel];
-    return s->mode;
+    info->gate = s->gate;
+    info->mode = s->mode;
+    info->initial_count = s->count;
+    info->out = pit_get_out(s, qemu_get_clock_ns(vm_clock));
 }
 
 static inline void pit_load_count(PITChannelState *s, int val)
@@ -274,7 +257,9 @@ static void pit_ioport_write(void *opaque, uint32_t addr, uint32_t val)
                     if (!(val & 0x10) && !s->status_latched) {
                         /* status latch */
                         /* XXX: add BCD and null count */
-                        s->status =  (pit_get_out1(s, qemu_get_clock_ns(vm_clock)) << 7) |
+                        s->status =
+                            (pit_get_out(s,
+                                         qemu_get_clock_ns(vm_clock)) << 7) |
                             (s->rw_mode << 4) |
                             (s->mode << 1) |
                             s->bcd;
@@ -381,7 +366,7 @@ static void pit_irq_timer_update(PITChannelState *s, int64_t current_time)
         return;
     }
     expire_time = pit_get_next_transition_time(s, current_time);
-    irq_level = pit_get_out1(s, current_time);
+    irq_level = pit_get_out(s, current_time);
     qemu_set_irq(s->irq, irq_level);
 #ifdef DEBUG_PIT
     printf("irq_level=%d next_delay=%f\n",
hw/i8254.h +8 -4
index 8ad8e07..a1d2e98 100644
@@ -30,6 +30,13 @@
 
 #define PIT_FREQ 1193182
 
+typedef struct PITChannelInfo {
+    int gate;
+    int mode;
+    int initial_count;
+    int out;
+} PITChannelInfo;
+
 static inline ISADevice *pit_init(ISABus *bus, int base, int isa_irq,
                                   qemu_irq alt_irq)
 {
@@ -45,9 +52,6 @@ static inline ISADevice *pit_init(ISABus *bus, int base, int isa_irq,
 }
 
 void pit_set_gate(ISADevice *dev, int channel, int val);
-int pit_get_gate(ISADevice *dev, int channel);
-int pit_get_initial_count(ISADevice *dev, int channel);
-int pit_get_mode(ISADevice *dev, int channel);
-int pit_get_out(ISADevice *dev, int channel, int64_t current_time);
+void pit_get_channel_info(ISADevice *dev, int channel, PITChannelInfo *info);
 
 #endif /* !HW_I8254_H */
hw/pcspk.c +11 -5
index d406c68..caa21a8 100644
@@ -75,12 +75,16 @@ static inline void generate_samples(PCSpkState *s)
 static void pcspk_callback(void *opaque, int free)
 {
     PCSpkState *s = opaque;
+    PITChannelInfo ch;
     unsigned int n;
 
-    if (pit_get_mode(s->pit, 2) != 3)
+    pit_get_channel_info(s->pit, 2, &ch);
+
+    if (ch.mode != 3) {
         return;
+    }
 
-    n = pit_get_initial_count(s->pit, 2);
+    n = ch.initial_count;
     /* avoid frequencies that are not reproducible with sample rate */
     if (n < PCSPK_MIN_COUNT)
         n = 0;
@@ -121,12 +125,14 @@ static uint64_t pcspk_io_read(void *opaque, target_phys_addr_t addr,
                               unsigned size)
 {
     PCSpkState *s = opaque;
-    int out;
+    PITChannelInfo ch;
+
+    pit_get_channel_info(s->pit, 2, &ch);
 
     s->dummy_refresh_clock ^= (1 << 4);
-    out = pit_get_out(s->pit, 2, qemu_get_clock_ns(vm_clock)) << 5;
 
-    return pit_get_gate(s->pit, 2) | (s->data_on << 1) | s->dummy_refresh_clock | out;
+    return ch.gate | (s->data_on << 1) | s->dummy_refresh_clock |
+       (ch.out << 5);
 }
 
 static void pcspk_io_write(void *opaque, target_phys_addr_t addr, uint64_t val,
Signature · 1 line
1.7.3.4
#9 lore raw
In reply to Jan Kiszka
Quoted 10 lines · Jan Kiszka

Changes in V4:
- rebased over qom-upstream.13
- comment on rtc_irq_level clearing on reset
- fix call to isa_register_ioport by passing the pcspk device

Not changed:
- PIT pointer property of pcspk
(Paolo will port it together with other PROP_PTR users)

CC Paolo Bonzini<[email protected]>

Applied. Thanks.

Regards,

Anthony Liguori

Quoted 29 lines

Jan Kiszka (7):
i8254: Do not raise IRQ level on reset
hpet: Save/restore cached RTC IRQ level
i8254: Factor out interface header
i8254: Pass alternative IRQ output object on initialization
i8254: Rework& fix interaction with HPET in legacy mode
pcspk: Convert to qdev
i8254: Factor out pit_get_channel_info

  arch_init.c        |    1 +
  hw/alpha_dp264.c   |    3 +-
  hw/hpet.c          |   68 ++++++++++++++++++++++++++++----------
  hw/hpet_emul.h     |    3 ++
  hw/i82378.c        |    6 ++-
  hw/i8254.c         |   92 ++++++++++++++++++++++-----------------------------
  hw/i8254.h         |   57 ++++++++++++++++++++++++++++++++
  hw/mips_fulong2e.c |    3 +-
  hw/mips_jazz.c     |    6 ++-
  hw/mips_malta.c    |    3 +-
  hw/mips_r4k.c      |    3 +-
  hw/pc.c            |   19 ++++++++--
  hw/pc.h            |   29 ----------------
  hw/pcspk.c         |   84 +++++++++++++++++++++++++++++++++++++++--------
  hw/pcspk.h         |   45 +++++++++++++++++++++++++
  15 files changed, 296 insertions(+), 126 deletions(-)

create mode 100644 hw/i8254.h
create mode 100644 hw/pcspk.h