All of lore.kernel.org
 help / color / mirror / Atom feed
* [PATCH 0/4] uq/master: Introduce KVM PIT support
@ 2012-02-05 10:46 ` Jan Kiszka
  0 siblings, 0 replies; 23+ messages in thread
From: Jan Kiszka @ 2012-02-05 10:46 UTC (permalink / raw)
  To: Avi Kivity, Marcelo Tosatti; +Cc: kvm, qemu-devel, Anthony Liguori

This adds another piece of qemu-kvm to upstream: The accelerated
in-kernel model of the i8254. It does this in the same fashion as the
interrupt controllers were already introduced. And it even has one bug
less than qemu-kvm: PC speaker output still works with KVM acceleration
enabled.

Changes in v2:
 - Rebased over recent upstream master to reflect QOM changes

The patches depend on the follow upstream or uq/master patches:
 - pit, hpet, pcspk: fixes & preparation for KVM (v4, 7 patches)
   http://thread.gmane.org/gmane.comp.emulators.kvm.devel/86006
 - kvm: Implement kvm_irqchip_in_kernel
   http://thread.gmane.org/gmane.comp.emulators.qemu/134399
 - KVM: Fix breakages of QOM conversion
   http://permalink.gmane.org/gmane.comp.emulators.qemu/134844

It is based on upstream commit cb437e48ab (before the VGA breakage). The
series plus dependencies is also available at

    git://git.kiszka.org/qemu-kvm.git queues/kvm-pit

Please review / merge.

Jan Kiszka (4):
  i8254: Factor out base class for KVM reuse
  i8254: Open-code timer restore
  kvm: Add kvm_has_pit_state2 helper
  kvm: x86: Add user space part for in-kernel i8254

 Makefile.objs       |    2 +-
 Makefile.target     |    2 +-
 hw/i8254.c          |  281 +++++++---------------------------------------
 hw/i8254.h          |   11 ++
 hw/i8254_common.c   |  307 +++++++++++++++++++++++++++++++++++++++++++++++++++
 hw/i8254_internal.h |   85 ++++++++++++++
 hw/kvm/i8254.c      |  241 ++++++++++++++++++++++++++++++++++++++++
 hw/pc.c             |   14 ++-
 kvm-all.c           |   10 ++
 kvm-stub.c          |    5 +
 kvm.h               |    1 +
 11 files changed, 717 insertions(+), 242 deletions(-)
 create mode 100644 hw/i8254_common.c
 create mode 100644 hw/i8254_internal.h
 create mode 100644 hw/kvm/i8254.c

-- 
1.7.3.4


^ permalink raw reply	[flat|nested] 23+ messages in thread

* [Qemu-devel] [PATCH 0/4] uq/master: Introduce KVM PIT support
@ 2012-02-05 10:46 ` Jan Kiszka
  0 siblings, 0 replies; 23+ messages in thread
From: Jan Kiszka @ 2012-02-05 10:46 UTC (permalink / raw)
  To: Avi Kivity, Marcelo Tosatti; +Cc: Anthony Liguori, qemu-devel, kvm

This adds another piece of qemu-kvm to upstream: The accelerated
in-kernel model of the i8254. It does this in the same fashion as the
interrupt controllers were already introduced. And it even has one bug
less than qemu-kvm: PC speaker output still works with KVM acceleration
enabled.

Changes in v2:
 - Rebased over recent upstream master to reflect QOM changes

The patches depend on the follow upstream or uq/master patches:
 - pit, hpet, pcspk: fixes & preparation for KVM (v4, 7 patches)
   http://thread.gmane.org/gmane.comp.emulators.kvm.devel/86006
 - kvm: Implement kvm_irqchip_in_kernel
   http://thread.gmane.org/gmane.comp.emulators.qemu/134399
 - KVM: Fix breakages of QOM conversion
   http://permalink.gmane.org/gmane.comp.emulators.qemu/134844

It is based on upstream commit cb437e48ab (before the VGA breakage). The
series plus dependencies is also available at

    git://git.kiszka.org/qemu-kvm.git queues/kvm-pit

Please review / merge.

Jan Kiszka (4):
  i8254: Factor out base class for KVM reuse
  i8254: Open-code timer restore
  kvm: Add kvm_has_pit_state2 helper
  kvm: x86: Add user space part for in-kernel i8254

 Makefile.objs       |    2 +-
 Makefile.target     |    2 +-
 hw/i8254.c          |  281 +++++++---------------------------------------
 hw/i8254.h          |   11 ++
 hw/i8254_common.c   |  307 +++++++++++++++++++++++++++++++++++++++++++++++++++
 hw/i8254_internal.h |   85 ++++++++++++++
 hw/kvm/i8254.c      |  241 ++++++++++++++++++++++++++++++++++++++++
 hw/pc.c             |   14 ++-
 kvm-all.c           |   10 ++
 kvm-stub.c          |    5 +
 kvm.h               |    1 +
 11 files changed, 717 insertions(+), 242 deletions(-)
 create mode 100644 hw/i8254_common.c
 create mode 100644 hw/i8254_internal.h
 create mode 100644 hw/kvm/i8254.c

-- 
1.7.3.4

^ permalink raw reply	[flat|nested] 23+ messages in thread

* [PATCH 1/4] i8254: Factor out base class for KVM reuse
  2012-02-05 10:46 ` [Qemu-devel] " Jan Kiszka
@ 2012-02-05 10:46   ` Jan Kiszka
  -1 siblings, 0 replies; 23+ messages in thread
From: Jan Kiszka @ 2012-02-05 10:46 UTC (permalink / raw)
  To: Avi Kivity, Marcelo Tosatti; +Cc: kvm, qemu-devel, Anthony Liguori

From: Jan Kiszka <jan.kiszka@siemens.com>

Applying the concept used for the *PICs once again: establish a base
class for the i8254 that can be used both by the current user space
emulation and the upcoming KVM in-kernel version. We share most of the
public interface of the i8254, specifically to the pcspk, vmstate, reset
and certain init parts.

Signed-off-by: Jan Kiszka <jan.kiszka@siemens.com>
---
 Makefile.objs       |    2 +-
 hw/i8254.c          |  269 +++++---------------------------------------
 hw/i8254_common.c   |  307 +++++++++++++++++++++++++++++++++++++++++++++++++++
 hw/i8254_internal.h |   85 ++++++++++++++
 4 files changed, 424 insertions(+), 239 deletions(-)
 create mode 100644 hw/i8254_common.c
 create mode 100644 hw/i8254_internal.h

diff --git a/Makefile.objs b/Makefile.objs
index ec35320..15c3915 100644
--- a/Makefile.objs
+++ b/Makefile.objs
@@ -210,7 +210,7 @@ hw-obj-$(CONFIG_EMPTY_SLOT) += empty_slot.o
 
 hw-obj-$(CONFIG_SERIAL) += serial.o
 hw-obj-$(CONFIG_PARALLEL) += parallel.o
-hw-obj-$(CONFIG_I8254) += i8254.o
+hw-obj-$(CONFIG_I8254) += i8254_common.o i8254.o
 hw-obj-$(CONFIG_PCSPK) += pcspk.o
 hw-obj-$(CONFIG_PCKBD) += pckbd.o
 hw-obj-$(CONFIG_USB_UHCI) += usb-uhci.o
diff --git a/hw/i8254.c b/hw/i8254.c
index be39c55..f9f58e0 100644
--- a/hw/i8254.c
+++ b/hw/i8254.c
@@ -26,6 +26,7 @@
 #include "isa.h"
 #include "qemu-timer.h"
 #include "i8254.h"
+#include "i8254_internal.h"
 
 //#define DEBUG_PIT
 
@@ -34,34 +35,6 @@
 #define RW_STATE_WORD0 3
 #define RW_STATE_WORD1 4
 
-typedef struct PITChannelState {
-    int count; /* can be 65536 */
-    uint16_t latched_count;
-    uint8_t count_latched;
-    uint8_t status_latched;
-    uint8_t status;
-    uint8_t read_state;
-    uint8_t write_state;
-    uint8_t write_latch;
-    uint8_t rw_mode;
-    uint8_t mode;
-    uint8_t bcd; /* not supported */
-    uint8_t gate; /* timer start */
-    int64_t count_load_time;
-    /* irq handling */
-    int64_t next_transition_time;
-    QEMUTimer *irq_timer;
-    qemu_irq irq;
-    uint32_t irq_disabled;
-} PITChannelState;
-
-typedef struct PITState {
-    ISADevice dev;
-    MemoryRegion ioports;
-    uint32_t iobase;
-    PITChannelState channels[3];
-} PITState;
-
 static void pit_irq_timer_update(PITChannelState *s, int64_t current_time);
 
 static int pit_get_count(PITChannelState *s)
@@ -89,99 +62,11 @@ static int pit_get_count(PITChannelState *s)
     return counter;
 }
 
-/* get pit output bit */
-static int pit_get_out(PITChannelState *s, int64_t current_time)
-{
-    uint64_t d;
-    int out;
-
-    d = muldiv64(current_time - s->count_load_time, PIT_FREQ,
-                 get_ticks_per_sec());
-    switch(s->mode) {
-    default:
-    case 0:
-        out = (d >= s->count);
-        break;
-    case 1:
-        out = (d < s->count);
-        break;
-    case 2:
-        if ((d % s->count) == 0 && d != 0)
-            out = 1;
-        else
-            out = 0;
-        break;
-    case 3:
-        out = (d % s->count) < ((s->count + 1) >> 1);
-        break;
-    case 4:
-    case 5:
-        out = (d == s->count);
-        break;
-    }
-    return out;
-}
-
-/* return -1 if no transition will occur.  */
-static int64_t pit_get_next_transition_time(PITChannelState *s,
-                                            int64_t current_time)
-{
-    uint64_t d, next_time, base;
-    int period2;
-
-    d = muldiv64(current_time - s->count_load_time, PIT_FREQ,
-                 get_ticks_per_sec());
-    switch(s->mode) {
-    default:
-    case 0:
-    case 1:
-        if (d < s->count)
-            next_time = s->count;
-        else
-            return -1;
-        break;
-    case 2:
-        base = (d / s->count) * s->count;
-        if ((d - base) == 0 && d != 0)
-            next_time = base + s->count;
-        else
-            next_time = base + s->count + 1;
-        break;
-    case 3:
-        base = (d / s->count) * s->count;
-        period2 = ((s->count + 1) >> 1);
-        if ((d - base) < period2)
-            next_time = base + period2;
-        else
-            next_time = base + s->count;
-        break;
-    case 4:
-    case 5:
-        if (d < s->count)
-            next_time = s->count;
-        else if (d == s->count)
-            next_time = s->count + 1;
-        else
-            return -1;
-        break;
-    }
-    /* convert to timer units */
-    next_time = s->count_load_time + muldiv64(next_time, get_ticks_per_sec(),
-                                              PIT_FREQ);
-    /* fix potential rounding problems */
-    /* XXX: better solution: use a clock at PIT_FREQ Hz */
-    if (next_time <= current_time)
-        next_time = current_time + 1;
-    return next_time;
-}
-
 /* val must be 0 or 1 */
-void pit_set_gate(ISADevice *dev, int channel, int val)
+static void pit_set_channel_gate(PITCommonState *s, PITChannelState *sc,
+                                 int val)
 {
-    PITState *pit = DO_UPCAST(PITState, dev, dev);
-    PITChannelState *s = &pit->channels[channel];
-
-    switch(s->mode) {
+    switch (sc->mode) {
     default:
     case 0:
     case 4:
@@ -189,34 +74,23 @@ void pit_set_gate(ISADevice *dev, int channel, int val)
         break;
     case 1:
     case 5:
-        if (s->gate < val) {
+        if (sc->gate < val) {
             /* restart counting on rising edge */
-            s->count_load_time = qemu_get_clock_ns(vm_clock);
-            pit_irq_timer_update(s, s->count_load_time);
+            sc->count_load_time = qemu_get_clock_ns(vm_clock);
+            pit_irq_timer_update(sc, sc->count_load_time);
         }
         break;
     case 2:
     case 3:
-        if (s->gate < val) {
+        if (sc->gate < val) {
             /* restart counting on rising edge */
-            s->count_load_time = qemu_get_clock_ns(vm_clock);
-            pit_irq_timer_update(s, s->count_load_time);
+            sc->count_load_time = qemu_get_clock_ns(vm_clock);
+            pit_irq_timer_update(sc, sc->count_load_time);
         }
         /* XXX: disable/enable counting */
         break;
     }
-    s->gate = val;
-}
-
-void pit_get_channel_info(ISADevice *dev, int channel, PITChannelInfo *info)
-{
-    PITState *pit = DO_UPCAST(PITState, dev, dev);
-    PITChannelState *s = &pit->channels[channel];
-
-    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));
+    sc->gate = val;
 }
 
 static inline void pit_load_count(PITChannelState *s, int val)
@@ -239,7 +113,7 @@ static void pit_latch_count(PITChannelState *s)
 
 static void pit_ioport_write(void *opaque, uint32_t addr, uint32_t val)
 {
-    PITState *pit = opaque;
+    PITCommonState *pit = opaque;
     int channel, access;
     PITChannelState *s;
 
@@ -306,7 +180,7 @@ static void pit_ioport_write(void *opaque, uint32_t addr, uint32_t val)
 
 static uint32_t pit_ioport_read(void *opaque, uint32_t addr)
 {
-    PITState *pit = opaque;
+    PITCommonState *pit = opaque;
     int ret, count;
     PITChannelState *s;
 
@@ -387,94 +261,16 @@ static void pit_irq_timer(void *opaque)
     pit_irq_timer_update(s, s->next_transition_time);
 }
 
-static const VMStateDescription vmstate_pit_channel = {
-    .name = "pit channel",
-    .version_id = 2,
-    .minimum_version_id = 2,
-    .minimum_version_id_old = 2,
-    .fields      = (VMStateField []) {
-        VMSTATE_INT32(count, PITChannelState),
-        VMSTATE_UINT16(latched_count, PITChannelState),
-        VMSTATE_UINT8(count_latched, PITChannelState),
-        VMSTATE_UINT8(status_latched, PITChannelState),
-        VMSTATE_UINT8(status, PITChannelState),
-        VMSTATE_UINT8(read_state, PITChannelState),
-        VMSTATE_UINT8(write_state, PITChannelState),
-        VMSTATE_UINT8(write_latch, PITChannelState),
-        VMSTATE_UINT8(rw_mode, PITChannelState),
-        VMSTATE_UINT8(mode, PITChannelState),
-        VMSTATE_UINT8(bcd, PITChannelState),
-        VMSTATE_UINT8(gate, PITChannelState),
-        VMSTATE_INT64(count_load_time, PITChannelState),
-        VMSTATE_INT64(next_transition_time, PITChannelState),
-        VMSTATE_END_OF_LIST()
-    }
-};
-
-static int pit_load_old(QEMUFile *f, void *opaque, int version_id)
+static void pit_reset(DeviceState *dev)
 {
-    PITState *pit = opaque;
+    PITCommonState *pit = DO_UPCAST(PITCommonState, dev.qdev, dev);
     PITChannelState *s;
-    int i;
-
-    if (version_id != 1)
-        return -EINVAL;
-
-    for(i = 0; i < 3; i++) {
-        s = &pit->channels[i];
-        s->count=qemu_get_be32(f);
-        qemu_get_be16s(f, &s->latched_count);
-        qemu_get_8s(f, &s->count_latched);
-        qemu_get_8s(f, &s->status_latched);
-        qemu_get_8s(f, &s->status);
-        qemu_get_8s(f, &s->read_state);
-        qemu_get_8s(f, &s->write_state);
-        qemu_get_8s(f, &s->write_latch);
-        qemu_get_8s(f, &s->rw_mode);
-        qemu_get_8s(f, &s->mode);
-        qemu_get_8s(f, &s->bcd);
-        qemu_get_8s(f, &s->gate);
-        s->count_load_time=qemu_get_be64(f);
-        s->irq_disabled = 0;
-        if (s->irq_timer) {
-            s->next_transition_time=qemu_get_be64(f);
-            qemu_get_timer(f, s->irq_timer);
-        }
-    }
-    return 0;
-}
 
-static const VMStateDescription vmstate_pit = {
-    .name = "i8254",
-    .version_id = 3,
-    .minimum_version_id = 2,
-    .minimum_version_id_old = 1,
-    .load_state_old = pit_load_old,
-    .fields      = (VMStateField []) {
-        VMSTATE_UINT32_V(channels[0].irq_disabled, PITState, 3),
-        VMSTATE_STRUCT_ARRAY(channels, PITState, 3, 2, vmstate_pit_channel, PITChannelState),
-        VMSTATE_TIMER(channels[0].irq_timer, PITState),
-        VMSTATE_END_OF_LIST()
-    }
-};
+    pit_reset_common(pit);
 
-static void pit_reset(DeviceState *dev)
-{
-    PITState *pit = container_of(dev, PITState, dev.qdev);
-    PITChannelState *s;
-    int i;
-
-    for(i = 0;i < 3; i++) {
-        s = &pit->channels[i];
-        s->mode = 3;
-        s->gate = (i != 2);
-        s->count_load_time = qemu_get_clock_ns(vm_clock);
-        s->count = 0x10000;
-        if (i == 0 && !s->irq_disabled) {
-            s->next_transition_time =
-                pit_get_next_transition_time(s, s->count_load_time);
-            qemu_mod_timer(s->irq_timer, s->next_transition_time);
-        }
+    s = &pit->channels[0];
+    if (!s->irq_disabled) {
+        qemu_mod_timer(s->irq_timer, s->next_transition_time);
     }
 }
 
@@ -482,7 +278,7 @@ static void pit_reset(DeviceState *dev)
  * reenable it when legacy mode is left again. */
 static void pit_irq_control(void *opaque, int n, int enable)
 {
-    PITState *pit = opaque;
+    PITCommonState *pit = opaque;
     PITChannelState *s = &pit->channels[0];
 
     if (enable) {
@@ -504,46 +300,43 @@ static const MemoryRegionOps pit_ioport_ops = {
     .old_portio = pit_portio
 };
 
-static int pit_initfn(ISADevice *dev)
+static int pit_initfn(PITCommonState *pit)
 {
-    PITState *pit = DO_UPCAST(PITState, dev, dev);
     PITChannelState *s;
 
     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);
-    qdev_init_gpio_out(&dev->qdev, &s->irq, 1);
+    qdev_init_gpio_out(&pit->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);
-
-    qdev_init_gpio_in(&dev->qdev, pit_irq_control, 1);
 
-    qdev_set_legacy_instance_id(&dev->qdev, pit->iobase, 2);
+    qdev_init_gpio_in(&pit->dev.qdev, pit_irq_control, 1);
 
     return 0;
 }
 
 static Property pit_properties[] = {
-    DEFINE_PROP_HEX32("iobase", PITState, iobase,  -1),
+    DEFINE_PROP_HEX32("iobase", PITCommonState, iobase,  -1),
     DEFINE_PROP_END_OF_LIST(),
 };
 
 static void pit_class_initfn(ObjectClass *klass, void *data)
 {
+    PITCommonClass *k = PIT_COMMON_CLASS(klass);
     DeviceClass *dc = DEVICE_CLASS(klass);
-    ISADeviceClass *ic = ISA_DEVICE_CLASS(klass);
-    ic->init = pit_initfn;
-    dc->no_user = 1;
+
+    k->init = pit_initfn;
+    k->set_channel_gate = pit_set_channel_gate;
+    k->get_channel_info = pit_get_channel_info_common;
     dc->reset = pit_reset;
-    dc->vmsd = &vmstate_pit;
     dc->props = pit_properties;
 }
 
 static TypeInfo pit_info = {
     .name          = "isa-pit",
-    .parent        = TYPE_ISA_DEVICE,
-    .instance_size = sizeof(PITState),
+    .parent        = TYPE_PIT_COMMON,
+    .instance_size = sizeof(PITCommonState),
     .class_init    = pit_class_initfn,
 };
 
diff --git a/hw/i8254_common.c b/hw/i8254_common.c
new file mode 100644
index 0000000..0601d88
--- /dev/null
+++ b/hw/i8254_common.c
@@ -0,0 +1,307 @@
+/*
+ * QEMU 8253/8254 - common bits of emulated and KVM kernel model
+ *
+ * Copyright (c) 2003-2004 Fabrice Bellard
+ * Copyright (c) 2012      Jan Kiszka, Siemens AG
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
+ * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+ * THE SOFTWARE.
+ */
+#include "hw.h"
+#include "pc.h"
+#include "isa.h"
+#include "qemu-timer.h"
+#include "i8254.h"
+#include "i8254_internal.h"
+
+/* val must be 0 or 1 */
+void pit_set_gate(ISADevice *dev, int channel, int val)
+{
+    PITCommonState *pit = PIT_COMMON(dev);
+    PITChannelState *s = &pit->channels[channel];
+    PITCommonClass *c = PIT_COMMON_GET_CLASS(pit);
+
+    c->set_channel_gate(pit, s, val);
+}
+
+/* get pit output bit */
+int pit_get_out(PITChannelState *s, int64_t current_time)
+{
+    uint64_t d;
+    int out;
+
+    d = muldiv64(current_time - s->count_load_time, PIT_FREQ,
+                 get_ticks_per_sec());
+    switch (s->mode) {
+    default:
+    case 0:
+        out = (d >= s->count);
+        break;
+    case 1:
+        out = (d < s->count);
+        break;
+    case 2:
+        if ((d % s->count) == 0 && d != 0) {
+            out = 1;
+        } else {
+            out = 0;
+        }
+        break;
+    case 3:
+        out = (d % s->count) < ((s->count + 1) >> 1);
+        break;
+    case 4:
+    case 5:
+        out = (d == s->count);
+        break;
+    }
+    return out;
+}
+
+/* return -1 if no transition will occur.  */
+int64_t pit_get_next_transition_time(PITChannelState *s, int64_t current_time)
+{
+    uint64_t d, next_time, base;
+    int period2;
+
+    d = muldiv64(current_time - s->count_load_time, PIT_FREQ,
+                 get_ticks_per_sec());
+    switch (s->mode) {
+    default:
+    case 0:
+    case 1:
+        if (d < s->count) {
+            next_time = s->count;
+        } else {
+            return -1;
+        }
+        break;
+    case 2:
+        base = (d / s->count) * s->count;
+        if ((d - base) == 0 && d != 0) {
+            next_time = base + s->count;
+        } else {
+            next_time = base + s->count + 1;
+        }
+        break;
+    case 3:
+        base = (d / s->count) * s->count;
+        period2 = ((s->count + 1) >> 1);
+        if ((d - base) < period2) {
+            next_time = base + period2;
+        } else {
+            next_time = base + s->count;
+        }
+        break;
+    case 4:
+    case 5:
+        if (d < s->count) {
+            next_time = s->count;
+        } else if (d == s->count) {
+            next_time = s->count + 1;
+        } else {
+            return -1;
+        }
+        break;
+    }
+    /* convert to timer units */
+    next_time = s->count_load_time + muldiv64(next_time, get_ticks_per_sec(),
+                                              PIT_FREQ);
+    /* fix potential rounding problems */
+    /* XXX: better solution: use a clock at PIT_FREQ Hz */
+    if (next_time <= current_time) {
+        next_time = current_time + 1;
+    }
+    return next_time;
+}
+
+void pit_get_channel_info_common(PITCommonState *s, PITChannelState *sc,
+                                 PITChannelInfo *info)
+{
+    info->gate = sc->gate;
+    info->mode = sc->mode;
+    info->initial_count = sc->count;
+    info->out = pit_get_out(sc, qemu_get_clock_ns(vm_clock));
+}
+
+void pit_get_channel_info(ISADevice *dev, int channel, PITChannelInfo *info)
+{
+    PITCommonState *pit = PIT_COMMON(dev);
+    PITChannelState *s = &pit->channels[channel];
+    PITCommonClass *c = PIT_COMMON_GET_CLASS(pit);
+
+    c->get_channel_info(pit, s, info);
+}
+
+void pit_reset_common(PITCommonState *pit)
+{
+    PITChannelState *s;
+    int i;
+
+    for (i = 0; i < 3; i++) {
+        s = &pit->channels[i];
+        s->mode = 3;
+        s->gate = (i != 2);
+        s->count_load_time = qemu_get_clock_ns(vm_clock);
+        s->count = 0x10000;
+        if (i == 0 && !s->irq_disabled) {
+            s->next_transition_time =
+                pit_get_next_transition_time(s, s->count_load_time);
+        }
+    }
+}
+
+static int pit_init_common(ISADevice *dev)
+{
+    PITCommonState *pit = PIT_COMMON(dev);
+    PITCommonClass *c = PIT_COMMON_GET_CLASS(pit);
+    int ret;
+
+    ret = c->init(pit);
+    if (ret < 0) {
+        return ret;
+    }
+
+    isa_register_ioport(dev, &pit->ioports, pit->iobase);
+
+    qdev_set_legacy_instance_id(&dev->qdev, pit->iobase, 2);
+
+    return 0;
+}
+
+static const VMStateDescription vmstate_pit_channel = {
+    .name = "pit channel",
+    .version_id = 2,
+    .minimum_version_id = 2,
+    .minimum_version_id_old = 2,
+    .fields = (VMStateField[]) {
+        VMSTATE_INT32(count, PITChannelState),
+        VMSTATE_UINT16(latched_count, PITChannelState),
+        VMSTATE_UINT8(count_latched, PITChannelState),
+        VMSTATE_UINT8(status_latched, PITChannelState),
+        VMSTATE_UINT8(status, PITChannelState),
+        VMSTATE_UINT8(read_state, PITChannelState),
+        VMSTATE_UINT8(write_state, PITChannelState),
+        VMSTATE_UINT8(write_latch, PITChannelState),
+        VMSTATE_UINT8(rw_mode, PITChannelState),
+        VMSTATE_UINT8(mode, PITChannelState),
+        VMSTATE_UINT8(bcd, PITChannelState),
+        VMSTATE_UINT8(gate, PITChannelState),
+        VMSTATE_INT64(count_load_time, PITChannelState),
+        VMSTATE_INT64(next_transition_time, PITChannelState),
+        VMSTATE_END_OF_LIST()
+    }
+};
+
+static int pit_load_old(QEMUFile *f, void *opaque, int version_id)
+{
+    PITCommonState *pit = opaque;
+    PITChannelState *s;
+    int i;
+
+    if (version_id != 1) {
+        return -EINVAL;
+    }
+
+    for (i = 0; i < 3; i++) {
+        s = &pit->channels[i];
+        s->count = qemu_get_be32(f);
+        qemu_get_be16s(f, &s->latched_count);
+        qemu_get_8s(f, &s->count_latched);
+        qemu_get_8s(f, &s->status_latched);
+        qemu_get_8s(f, &s->status);
+        qemu_get_8s(f, &s->read_state);
+        qemu_get_8s(f, &s->write_state);
+        qemu_get_8s(f, &s->write_latch);
+        qemu_get_8s(f, &s->rw_mode);
+        qemu_get_8s(f, &s->mode);
+        qemu_get_8s(f, &s->bcd);
+        qemu_get_8s(f, &s->gate);
+        s->count_load_time = qemu_get_be64(f);
+        s->irq_disabled = 0;
+        if (s->irq_timer) {
+            s->next_transition_time = qemu_get_be64(f);
+            qemu_get_timer(f, s->irq_timer);
+        }
+    }
+    return 0;
+}
+
+static void pit_dispatch_pre_save(void *opaque)
+{
+    PITCommonState *s = opaque;
+    PITCommonClass *c = PIT_COMMON_GET_CLASS(s);
+
+    if (c->pre_save) {
+        c->pre_save(s);
+    }
+}
+
+static int pit_dispatch_post_load(void *opaque, int version_id)
+{
+    PITCommonState *s = opaque;
+    PITCommonClass *c = PIT_COMMON_GET_CLASS(s);
+
+    if (c->post_load) {
+        c->post_load(s);
+    }
+    return 0;
+}
+
+static const VMStateDescription vmstate_pit_common = {
+    .name = "i8254",
+    .version_id = 3,
+    .minimum_version_id = 2,
+    .minimum_version_id_old = 1,
+    .load_state_old = pit_load_old,
+    .pre_save = pit_dispatch_pre_save,
+    .post_load = pit_dispatch_post_load,
+    .fields = (VMStateField[]) {
+        VMSTATE_UINT32_V(channels[0].irq_disabled, PITCommonState, 3),
+        VMSTATE_STRUCT_ARRAY(channels, PITCommonState, 3, 2,
+                             vmstate_pit_channel, PITChannelState),
+        VMSTATE_TIMER(channels[0].irq_timer, PITCommonState),
+        VMSTATE_END_OF_LIST()
+    }
+};
+
+static void pit_common_class_init(ObjectClass *klass, void *data)
+{
+    ISADeviceClass *ic = ISA_DEVICE_CLASS(klass);
+    DeviceClass *dc = DEVICE_CLASS(klass);
+
+    ic->init = pit_init_common;
+    dc->vmsd = &vmstate_pit_common;
+    dc->no_user = 1;
+}
+
+static TypeInfo pit_common_type = {
+    .name          = TYPE_PIT_COMMON,
+    .parent        = TYPE_ISA_DEVICE,
+    .instance_size = sizeof(PITCommonState),
+    .class_size    = sizeof(PITCommonClass),
+    .class_init    = pit_common_class_init,
+    .abstract      = true,
+};
+
+static void register_devices(void)
+{
+    type_register_static(&pit_common_type);
+}
+
+device_init(register_devices);
diff --git a/hw/i8254_internal.h b/hw/i8254_internal.h
new file mode 100644
index 0000000..686f0c2
--- /dev/null
+++ b/hw/i8254_internal.h
@@ -0,0 +1,85 @@
+/*
+ * QEMU 8253/8254 - internal interfaces
+ *
+ * Copyright (c) 2011 Jan Kiszka, Siemens AG
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
+ * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+ * THE SOFTWARE.
+ */
+
+#ifndef QEMU_I8254_INTERNAL_H
+#define QEMU_I8254_INTERNAL_H
+
+#include "hw.h"
+#include "pc.h"
+#include "isa.h"
+
+typedef struct PITChannelState {
+    int count; /* can be 65536 */
+    uint16_t latched_count;
+    uint8_t count_latched;
+    uint8_t status_latched;
+    uint8_t status;
+    uint8_t read_state;
+    uint8_t write_state;
+    uint8_t write_latch;
+    uint8_t rw_mode;
+    uint8_t mode;
+    uint8_t bcd; /* not supported */
+    uint8_t gate; /* timer start */
+    int64_t count_load_time;
+    /* irq handling */
+    int64_t next_transition_time;
+    QEMUTimer *irq_timer;
+    qemu_irq irq;
+    uint32_t irq_disabled;
+} PITChannelState;
+
+typedef struct PITCommonState {
+    ISADevice dev;
+    MemoryRegion ioports;
+    uint32_t iobase;
+    PITChannelState channels[3];
+} PITCommonState;
+
+#define TYPE_PIT_COMMON "pit-common"
+#define PIT_COMMON(obj) \
+     OBJECT_CHECK(PITCommonState, (obj), TYPE_PIT_COMMON)
+#define PIT_COMMON_CLASS(klass) \
+     OBJECT_CLASS_CHECK(PITCommonClass, (klass), TYPE_PIT_COMMON)
+#define PIT_COMMON_GET_CLASS(obj) \
+     OBJECT_GET_CLASS(PITCommonClass, (obj), TYPE_PIT_COMMON)
+
+typedef struct PITCommonClass {
+    ISADeviceClass parent_class;
+
+    int (*init)(PITCommonState *s);
+    void (*set_channel_gate)(PITCommonState *s, PITChannelState *sc, int val);
+    void (*get_channel_info)(PITCommonState *s, PITChannelState *sc,
+                             PITChannelInfo *info);
+    void (*pre_save)(PITCommonState *s);
+    void (*post_load)(PITCommonState *s);
+} PITCommonClass;
+
+int pit_get_out(PITChannelState *s, int64_t current_time);
+int64_t pit_get_next_transition_time(PITChannelState *s, int64_t current_time);
+void pit_get_channel_info_common(PITCommonState *s, PITChannelState *sc,
+                                 PITChannelInfo *info);
+void pit_reset_common(PITCommonState *s);
+
+#endif /* !QEMU_I8254_INTERNAL_H */
-- 
1.7.3.4


^ permalink raw reply related	[flat|nested] 23+ messages in thread

* [Qemu-devel] [PATCH 1/4] i8254: Factor out base class for KVM reuse
@ 2012-02-05 10:46   ` Jan Kiszka
  0 siblings, 0 replies; 23+ messages in thread
From: Jan Kiszka @ 2012-02-05 10:46 UTC (permalink / raw)
  To: Avi Kivity, Marcelo Tosatti; +Cc: Anthony Liguori, qemu-devel, kvm

From: Jan Kiszka <jan.kiszka@siemens.com>

Applying the concept used for the *PICs once again: establish a base
class for the i8254 that can be used both by the current user space
emulation and the upcoming KVM in-kernel version. We share most of the
public interface of the i8254, specifically to the pcspk, vmstate, reset
and certain init parts.

Signed-off-by: Jan Kiszka <jan.kiszka@siemens.com>
---
 Makefile.objs       |    2 +-
 hw/i8254.c          |  269 +++++---------------------------------------
 hw/i8254_common.c   |  307 +++++++++++++++++++++++++++++++++++++++++++++++++++
 hw/i8254_internal.h |   85 ++++++++++++++
 4 files changed, 424 insertions(+), 239 deletions(-)
 create mode 100644 hw/i8254_common.c
 create mode 100644 hw/i8254_internal.h

diff --git a/Makefile.objs b/Makefile.objs
index ec35320..15c3915 100644
--- a/Makefile.objs
+++ b/Makefile.objs
@@ -210,7 +210,7 @@ hw-obj-$(CONFIG_EMPTY_SLOT) += empty_slot.o
 
 hw-obj-$(CONFIG_SERIAL) += serial.o
 hw-obj-$(CONFIG_PARALLEL) += parallel.o
-hw-obj-$(CONFIG_I8254) += i8254.o
+hw-obj-$(CONFIG_I8254) += i8254_common.o i8254.o
 hw-obj-$(CONFIG_PCSPK) += pcspk.o
 hw-obj-$(CONFIG_PCKBD) += pckbd.o
 hw-obj-$(CONFIG_USB_UHCI) += usb-uhci.o
diff --git a/hw/i8254.c b/hw/i8254.c
index be39c55..f9f58e0 100644
--- a/hw/i8254.c
+++ b/hw/i8254.c
@@ -26,6 +26,7 @@
 #include "isa.h"
 #include "qemu-timer.h"
 #include "i8254.h"
+#include "i8254_internal.h"
 
 //#define DEBUG_PIT
 
@@ -34,34 +35,6 @@
 #define RW_STATE_WORD0 3
 #define RW_STATE_WORD1 4
 
-typedef struct PITChannelState {
-    int count; /* can be 65536 */
-    uint16_t latched_count;
-    uint8_t count_latched;
-    uint8_t status_latched;
-    uint8_t status;
-    uint8_t read_state;
-    uint8_t write_state;
-    uint8_t write_latch;
-    uint8_t rw_mode;
-    uint8_t mode;
-    uint8_t bcd; /* not supported */
-    uint8_t gate; /* timer start */
-    int64_t count_load_time;
-    /* irq handling */
-    int64_t next_transition_time;
-    QEMUTimer *irq_timer;
-    qemu_irq irq;
-    uint32_t irq_disabled;
-} PITChannelState;
-
-typedef struct PITState {
-    ISADevice dev;
-    MemoryRegion ioports;
-    uint32_t iobase;
-    PITChannelState channels[3];
-} PITState;
-
 static void pit_irq_timer_update(PITChannelState *s, int64_t current_time);
 
 static int pit_get_count(PITChannelState *s)
@@ -89,99 +62,11 @@ static int pit_get_count(PITChannelState *s)
     return counter;
 }
 
-/* get pit output bit */
-static int pit_get_out(PITChannelState *s, int64_t current_time)
-{
-    uint64_t d;
-    int out;
-
-    d = muldiv64(current_time - s->count_load_time, PIT_FREQ,
-                 get_ticks_per_sec());
-    switch(s->mode) {
-    default:
-    case 0:
-        out = (d >= s->count);
-        break;
-    case 1:
-        out = (d < s->count);
-        break;
-    case 2:
-        if ((d % s->count) == 0 && d != 0)
-            out = 1;
-        else
-            out = 0;
-        break;
-    case 3:
-        out = (d % s->count) < ((s->count + 1) >> 1);
-        break;
-    case 4:
-    case 5:
-        out = (d == s->count);
-        break;
-    }
-    return out;
-}
-
-/* return -1 if no transition will occur.  */
-static int64_t pit_get_next_transition_time(PITChannelState *s,
-                                            int64_t current_time)
-{
-    uint64_t d, next_time, base;
-    int period2;
-
-    d = muldiv64(current_time - s->count_load_time, PIT_FREQ,
-                 get_ticks_per_sec());
-    switch(s->mode) {
-    default:
-    case 0:
-    case 1:
-        if (d < s->count)
-            next_time = s->count;
-        else
-            return -1;
-        break;
-    case 2:
-        base = (d / s->count) * s->count;
-        if ((d - base) == 0 && d != 0)
-            next_time = base + s->count;
-        else
-            next_time = base + s->count + 1;
-        break;
-    case 3:
-        base = (d / s->count) * s->count;
-        period2 = ((s->count + 1) >> 1);
-        if ((d - base) < period2)
-            next_time = base + period2;
-        else
-            next_time = base + s->count;
-        break;
-    case 4:
-    case 5:
-        if (d < s->count)
-            next_time = s->count;
-        else if (d == s->count)
-            next_time = s->count + 1;
-        else
-            return -1;
-        break;
-    }
-    /* convert to timer units */
-    next_time = s->count_load_time + muldiv64(next_time, get_ticks_per_sec(),
-                                              PIT_FREQ);
-    /* fix potential rounding problems */
-    /* XXX: better solution: use a clock at PIT_FREQ Hz */
-    if (next_time <= current_time)
-        next_time = current_time + 1;
-    return next_time;
-}
-
 /* val must be 0 or 1 */
-void pit_set_gate(ISADevice *dev, int channel, int val)
+static void pit_set_channel_gate(PITCommonState *s, PITChannelState *sc,
+                                 int val)
 {
-    PITState *pit = DO_UPCAST(PITState, dev, dev);
-    PITChannelState *s = &pit->channels[channel];
-
-    switch(s->mode) {
+    switch (sc->mode) {
     default:
     case 0:
     case 4:
@@ -189,34 +74,23 @@ void pit_set_gate(ISADevice *dev, int channel, int val)
         break;
     case 1:
     case 5:
-        if (s->gate < val) {
+        if (sc->gate < val) {
             /* restart counting on rising edge */
-            s->count_load_time = qemu_get_clock_ns(vm_clock);
-            pit_irq_timer_update(s, s->count_load_time);
+            sc->count_load_time = qemu_get_clock_ns(vm_clock);
+            pit_irq_timer_update(sc, sc->count_load_time);
         }
         break;
     case 2:
     case 3:
-        if (s->gate < val) {
+        if (sc->gate < val) {
             /* restart counting on rising edge */
-            s->count_load_time = qemu_get_clock_ns(vm_clock);
-            pit_irq_timer_update(s, s->count_load_time);
+            sc->count_load_time = qemu_get_clock_ns(vm_clock);
+            pit_irq_timer_update(sc, sc->count_load_time);
         }
         /* XXX: disable/enable counting */
         break;
     }
-    s->gate = val;
-}
-
-void pit_get_channel_info(ISADevice *dev, int channel, PITChannelInfo *info)
-{
-    PITState *pit = DO_UPCAST(PITState, dev, dev);
-    PITChannelState *s = &pit->channels[channel];
-
-    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));
+    sc->gate = val;
 }
 
 static inline void pit_load_count(PITChannelState *s, int val)
@@ -239,7 +113,7 @@ static void pit_latch_count(PITChannelState *s)
 
 static void pit_ioport_write(void *opaque, uint32_t addr, uint32_t val)
 {
-    PITState *pit = opaque;
+    PITCommonState *pit = opaque;
     int channel, access;
     PITChannelState *s;
 
@@ -306,7 +180,7 @@ static void pit_ioport_write(void *opaque, uint32_t addr, uint32_t val)
 
 static uint32_t pit_ioport_read(void *opaque, uint32_t addr)
 {
-    PITState *pit = opaque;
+    PITCommonState *pit = opaque;
     int ret, count;
     PITChannelState *s;
 
@@ -387,94 +261,16 @@ static void pit_irq_timer(void *opaque)
     pit_irq_timer_update(s, s->next_transition_time);
 }
 
-static const VMStateDescription vmstate_pit_channel = {
-    .name = "pit channel",
-    .version_id = 2,
-    .minimum_version_id = 2,
-    .minimum_version_id_old = 2,
-    .fields      = (VMStateField []) {
-        VMSTATE_INT32(count, PITChannelState),
-        VMSTATE_UINT16(latched_count, PITChannelState),
-        VMSTATE_UINT8(count_latched, PITChannelState),
-        VMSTATE_UINT8(status_latched, PITChannelState),
-        VMSTATE_UINT8(status, PITChannelState),
-        VMSTATE_UINT8(read_state, PITChannelState),
-        VMSTATE_UINT8(write_state, PITChannelState),
-        VMSTATE_UINT8(write_latch, PITChannelState),
-        VMSTATE_UINT8(rw_mode, PITChannelState),
-        VMSTATE_UINT8(mode, PITChannelState),
-        VMSTATE_UINT8(bcd, PITChannelState),
-        VMSTATE_UINT8(gate, PITChannelState),
-        VMSTATE_INT64(count_load_time, PITChannelState),
-        VMSTATE_INT64(next_transition_time, PITChannelState),
-        VMSTATE_END_OF_LIST()
-    }
-};
-
-static int pit_load_old(QEMUFile *f, void *opaque, int version_id)
+static void pit_reset(DeviceState *dev)
 {
-    PITState *pit = opaque;
+    PITCommonState *pit = DO_UPCAST(PITCommonState, dev.qdev, dev);
     PITChannelState *s;
-    int i;
-
-    if (version_id != 1)
-        return -EINVAL;
-
-    for(i = 0; i < 3; i++) {
-        s = &pit->channels[i];
-        s->count=qemu_get_be32(f);
-        qemu_get_be16s(f, &s->latched_count);
-        qemu_get_8s(f, &s->count_latched);
-        qemu_get_8s(f, &s->status_latched);
-        qemu_get_8s(f, &s->status);
-        qemu_get_8s(f, &s->read_state);
-        qemu_get_8s(f, &s->write_state);
-        qemu_get_8s(f, &s->write_latch);
-        qemu_get_8s(f, &s->rw_mode);
-        qemu_get_8s(f, &s->mode);
-        qemu_get_8s(f, &s->bcd);
-        qemu_get_8s(f, &s->gate);
-        s->count_load_time=qemu_get_be64(f);
-        s->irq_disabled = 0;
-        if (s->irq_timer) {
-            s->next_transition_time=qemu_get_be64(f);
-            qemu_get_timer(f, s->irq_timer);
-        }
-    }
-    return 0;
-}
 
-static const VMStateDescription vmstate_pit = {
-    .name = "i8254",
-    .version_id = 3,
-    .minimum_version_id = 2,
-    .minimum_version_id_old = 1,
-    .load_state_old = pit_load_old,
-    .fields      = (VMStateField []) {
-        VMSTATE_UINT32_V(channels[0].irq_disabled, PITState, 3),
-        VMSTATE_STRUCT_ARRAY(channels, PITState, 3, 2, vmstate_pit_channel, PITChannelState),
-        VMSTATE_TIMER(channels[0].irq_timer, PITState),
-        VMSTATE_END_OF_LIST()
-    }
-};
+    pit_reset_common(pit);
 
-static void pit_reset(DeviceState *dev)
-{
-    PITState *pit = container_of(dev, PITState, dev.qdev);
-    PITChannelState *s;
-    int i;
-
-    for(i = 0;i < 3; i++) {
-        s = &pit->channels[i];
-        s->mode = 3;
-        s->gate = (i != 2);
-        s->count_load_time = qemu_get_clock_ns(vm_clock);
-        s->count = 0x10000;
-        if (i == 0 && !s->irq_disabled) {
-            s->next_transition_time =
-                pit_get_next_transition_time(s, s->count_load_time);
-            qemu_mod_timer(s->irq_timer, s->next_transition_time);
-        }
+    s = &pit->channels[0];
+    if (!s->irq_disabled) {
+        qemu_mod_timer(s->irq_timer, s->next_transition_time);
     }
 }
 
@@ -482,7 +278,7 @@ static void pit_reset(DeviceState *dev)
  * reenable it when legacy mode is left again. */
 static void pit_irq_control(void *opaque, int n, int enable)
 {
-    PITState *pit = opaque;
+    PITCommonState *pit = opaque;
     PITChannelState *s = &pit->channels[0];
 
     if (enable) {
@@ -504,46 +300,43 @@ static const MemoryRegionOps pit_ioport_ops = {
     .old_portio = pit_portio
 };
 
-static int pit_initfn(ISADevice *dev)
+static int pit_initfn(PITCommonState *pit)
 {
-    PITState *pit = DO_UPCAST(PITState, dev, dev);
     PITChannelState *s;
 
     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);
-    qdev_init_gpio_out(&dev->qdev, &s->irq, 1);
+    qdev_init_gpio_out(&pit->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);
-
-    qdev_init_gpio_in(&dev->qdev, pit_irq_control, 1);
 
-    qdev_set_legacy_instance_id(&dev->qdev, pit->iobase, 2);
+    qdev_init_gpio_in(&pit->dev.qdev, pit_irq_control, 1);
 
     return 0;
 }
 
 static Property pit_properties[] = {
-    DEFINE_PROP_HEX32("iobase", PITState, iobase,  -1),
+    DEFINE_PROP_HEX32("iobase", PITCommonState, iobase,  -1),
     DEFINE_PROP_END_OF_LIST(),
 };
 
 static void pit_class_initfn(ObjectClass *klass, void *data)
 {
+    PITCommonClass *k = PIT_COMMON_CLASS(klass);
     DeviceClass *dc = DEVICE_CLASS(klass);
-    ISADeviceClass *ic = ISA_DEVICE_CLASS(klass);
-    ic->init = pit_initfn;
-    dc->no_user = 1;
+
+    k->init = pit_initfn;
+    k->set_channel_gate = pit_set_channel_gate;
+    k->get_channel_info = pit_get_channel_info_common;
     dc->reset = pit_reset;
-    dc->vmsd = &vmstate_pit;
     dc->props = pit_properties;
 }
 
 static TypeInfo pit_info = {
     .name          = "isa-pit",
-    .parent        = TYPE_ISA_DEVICE,
-    .instance_size = sizeof(PITState),
+    .parent        = TYPE_PIT_COMMON,
+    .instance_size = sizeof(PITCommonState),
     .class_init    = pit_class_initfn,
 };
 
diff --git a/hw/i8254_common.c b/hw/i8254_common.c
new file mode 100644
index 0000000..0601d88
--- /dev/null
+++ b/hw/i8254_common.c
@@ -0,0 +1,307 @@
+/*
+ * QEMU 8253/8254 - common bits of emulated and KVM kernel model
+ *
+ * Copyright (c) 2003-2004 Fabrice Bellard
+ * Copyright (c) 2012      Jan Kiszka, Siemens AG
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
+ * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+ * THE SOFTWARE.
+ */
+#include "hw.h"
+#include "pc.h"
+#include "isa.h"
+#include "qemu-timer.h"
+#include "i8254.h"
+#include "i8254_internal.h"
+
+/* val must be 0 or 1 */
+void pit_set_gate(ISADevice *dev, int channel, int val)
+{
+    PITCommonState *pit = PIT_COMMON(dev);
+    PITChannelState *s = &pit->channels[channel];
+    PITCommonClass *c = PIT_COMMON_GET_CLASS(pit);
+
+    c->set_channel_gate(pit, s, val);
+}
+
+/* get pit output bit */
+int pit_get_out(PITChannelState *s, int64_t current_time)
+{
+    uint64_t d;
+    int out;
+
+    d = muldiv64(current_time - s->count_load_time, PIT_FREQ,
+                 get_ticks_per_sec());
+    switch (s->mode) {
+    default:
+    case 0:
+        out = (d >= s->count);
+        break;
+    case 1:
+        out = (d < s->count);
+        break;
+    case 2:
+        if ((d % s->count) == 0 && d != 0) {
+            out = 1;
+        } else {
+            out = 0;
+        }
+        break;
+    case 3:
+        out = (d % s->count) < ((s->count + 1) >> 1);
+        break;
+    case 4:
+    case 5:
+        out = (d == s->count);
+        break;
+    }
+    return out;
+}
+
+/* return -1 if no transition will occur.  */
+int64_t pit_get_next_transition_time(PITChannelState *s, int64_t current_time)
+{
+    uint64_t d, next_time, base;
+    int period2;
+
+    d = muldiv64(current_time - s->count_load_time, PIT_FREQ,
+                 get_ticks_per_sec());
+    switch (s->mode) {
+    default:
+    case 0:
+    case 1:
+        if (d < s->count) {
+            next_time = s->count;
+        } else {
+            return -1;
+        }
+        break;
+    case 2:
+        base = (d / s->count) * s->count;
+        if ((d - base) == 0 && d != 0) {
+            next_time = base + s->count;
+        } else {
+            next_time = base + s->count + 1;
+        }
+        break;
+    case 3:
+        base = (d / s->count) * s->count;
+        period2 = ((s->count + 1) >> 1);
+        if ((d - base) < period2) {
+            next_time = base + period2;
+        } else {
+            next_time = base + s->count;
+        }
+        break;
+    case 4:
+    case 5:
+        if (d < s->count) {
+            next_time = s->count;
+        } else if (d == s->count) {
+            next_time = s->count + 1;
+        } else {
+            return -1;
+        }
+        break;
+    }
+    /* convert to timer units */
+    next_time = s->count_load_time + muldiv64(next_time, get_ticks_per_sec(),
+                                              PIT_FREQ);
+    /* fix potential rounding problems */
+    /* XXX: better solution: use a clock at PIT_FREQ Hz */
+    if (next_time <= current_time) {
+        next_time = current_time + 1;
+    }
+    return next_time;
+}
+
+void pit_get_channel_info_common(PITCommonState *s, PITChannelState *sc,
+                                 PITChannelInfo *info)
+{
+    info->gate = sc->gate;
+    info->mode = sc->mode;
+    info->initial_count = sc->count;
+    info->out = pit_get_out(sc, qemu_get_clock_ns(vm_clock));
+}
+
+void pit_get_channel_info(ISADevice *dev, int channel, PITChannelInfo *info)
+{
+    PITCommonState *pit = PIT_COMMON(dev);
+    PITChannelState *s = &pit->channels[channel];
+    PITCommonClass *c = PIT_COMMON_GET_CLASS(pit);
+
+    c->get_channel_info(pit, s, info);
+}
+
+void pit_reset_common(PITCommonState *pit)
+{
+    PITChannelState *s;
+    int i;
+
+    for (i = 0; i < 3; i++) {
+        s = &pit->channels[i];
+        s->mode = 3;
+        s->gate = (i != 2);
+        s->count_load_time = qemu_get_clock_ns(vm_clock);
+        s->count = 0x10000;
+        if (i == 0 && !s->irq_disabled) {
+            s->next_transition_time =
+                pit_get_next_transition_time(s, s->count_load_time);
+        }
+    }
+}
+
+static int pit_init_common(ISADevice *dev)
+{
+    PITCommonState *pit = PIT_COMMON(dev);
+    PITCommonClass *c = PIT_COMMON_GET_CLASS(pit);
+    int ret;
+
+    ret = c->init(pit);
+    if (ret < 0) {
+        return ret;
+    }
+
+    isa_register_ioport(dev, &pit->ioports, pit->iobase);
+
+    qdev_set_legacy_instance_id(&dev->qdev, pit->iobase, 2);
+
+    return 0;
+}
+
+static const VMStateDescription vmstate_pit_channel = {
+    .name = "pit channel",
+    .version_id = 2,
+    .minimum_version_id = 2,
+    .minimum_version_id_old = 2,
+    .fields = (VMStateField[]) {
+        VMSTATE_INT32(count, PITChannelState),
+        VMSTATE_UINT16(latched_count, PITChannelState),
+        VMSTATE_UINT8(count_latched, PITChannelState),
+        VMSTATE_UINT8(status_latched, PITChannelState),
+        VMSTATE_UINT8(status, PITChannelState),
+        VMSTATE_UINT8(read_state, PITChannelState),
+        VMSTATE_UINT8(write_state, PITChannelState),
+        VMSTATE_UINT8(write_latch, PITChannelState),
+        VMSTATE_UINT8(rw_mode, PITChannelState),
+        VMSTATE_UINT8(mode, PITChannelState),
+        VMSTATE_UINT8(bcd, PITChannelState),
+        VMSTATE_UINT8(gate, PITChannelState),
+        VMSTATE_INT64(count_load_time, PITChannelState),
+        VMSTATE_INT64(next_transition_time, PITChannelState),
+        VMSTATE_END_OF_LIST()
+    }
+};
+
+static int pit_load_old(QEMUFile *f, void *opaque, int version_id)
+{
+    PITCommonState *pit = opaque;
+    PITChannelState *s;
+    int i;
+
+    if (version_id != 1) {
+        return -EINVAL;
+    }
+
+    for (i = 0; i < 3; i++) {
+        s = &pit->channels[i];
+        s->count = qemu_get_be32(f);
+        qemu_get_be16s(f, &s->latched_count);
+        qemu_get_8s(f, &s->count_latched);
+        qemu_get_8s(f, &s->status_latched);
+        qemu_get_8s(f, &s->status);
+        qemu_get_8s(f, &s->read_state);
+        qemu_get_8s(f, &s->write_state);
+        qemu_get_8s(f, &s->write_latch);
+        qemu_get_8s(f, &s->rw_mode);
+        qemu_get_8s(f, &s->mode);
+        qemu_get_8s(f, &s->bcd);
+        qemu_get_8s(f, &s->gate);
+        s->count_load_time = qemu_get_be64(f);
+        s->irq_disabled = 0;
+        if (s->irq_timer) {
+            s->next_transition_time = qemu_get_be64(f);
+            qemu_get_timer(f, s->irq_timer);
+        }
+    }
+    return 0;
+}
+
+static void pit_dispatch_pre_save(void *opaque)
+{
+    PITCommonState *s = opaque;
+    PITCommonClass *c = PIT_COMMON_GET_CLASS(s);
+
+    if (c->pre_save) {
+        c->pre_save(s);
+    }
+}
+
+static int pit_dispatch_post_load(void *opaque, int version_id)
+{
+    PITCommonState *s = opaque;
+    PITCommonClass *c = PIT_COMMON_GET_CLASS(s);
+
+    if (c->post_load) {
+        c->post_load(s);
+    }
+    return 0;
+}
+
+static const VMStateDescription vmstate_pit_common = {
+    .name = "i8254",
+    .version_id = 3,
+    .minimum_version_id = 2,
+    .minimum_version_id_old = 1,
+    .load_state_old = pit_load_old,
+    .pre_save = pit_dispatch_pre_save,
+    .post_load = pit_dispatch_post_load,
+    .fields = (VMStateField[]) {
+        VMSTATE_UINT32_V(channels[0].irq_disabled, PITCommonState, 3),
+        VMSTATE_STRUCT_ARRAY(channels, PITCommonState, 3, 2,
+                             vmstate_pit_channel, PITChannelState),
+        VMSTATE_TIMER(channels[0].irq_timer, PITCommonState),
+        VMSTATE_END_OF_LIST()
+    }
+};
+
+static void pit_common_class_init(ObjectClass *klass, void *data)
+{
+    ISADeviceClass *ic = ISA_DEVICE_CLASS(klass);
+    DeviceClass *dc = DEVICE_CLASS(klass);
+
+    ic->init = pit_init_common;
+    dc->vmsd = &vmstate_pit_common;
+    dc->no_user = 1;
+}
+
+static TypeInfo pit_common_type = {
+    .name          = TYPE_PIT_COMMON,
+    .parent        = TYPE_ISA_DEVICE,
+    .instance_size = sizeof(PITCommonState),
+    .class_size    = sizeof(PITCommonClass),
+    .class_init    = pit_common_class_init,
+    .abstract      = true,
+};
+
+static void register_devices(void)
+{
+    type_register_static(&pit_common_type);
+}
+
+device_init(register_devices);
diff --git a/hw/i8254_internal.h b/hw/i8254_internal.h
new file mode 100644
index 0000000..686f0c2
--- /dev/null
+++ b/hw/i8254_internal.h
@@ -0,0 +1,85 @@
+/*
+ * QEMU 8253/8254 - internal interfaces
+ *
+ * Copyright (c) 2011 Jan Kiszka, Siemens AG
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
+ * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+ * THE SOFTWARE.
+ */
+
+#ifndef QEMU_I8254_INTERNAL_H
+#define QEMU_I8254_INTERNAL_H
+
+#include "hw.h"
+#include "pc.h"
+#include "isa.h"
+
+typedef struct PITChannelState {
+    int count; /* can be 65536 */
+    uint16_t latched_count;
+    uint8_t count_latched;
+    uint8_t status_latched;
+    uint8_t status;
+    uint8_t read_state;
+    uint8_t write_state;
+    uint8_t write_latch;
+    uint8_t rw_mode;
+    uint8_t mode;
+    uint8_t bcd; /* not supported */
+    uint8_t gate; /* timer start */
+    int64_t count_load_time;
+    /* irq handling */
+    int64_t next_transition_time;
+    QEMUTimer *irq_timer;
+    qemu_irq irq;
+    uint32_t irq_disabled;
+} PITChannelState;
+
+typedef struct PITCommonState {
+    ISADevice dev;
+    MemoryRegion ioports;
+    uint32_t iobase;
+    PITChannelState channels[3];
+} PITCommonState;
+
+#define TYPE_PIT_COMMON "pit-common"
+#define PIT_COMMON(obj) \
+     OBJECT_CHECK(PITCommonState, (obj), TYPE_PIT_COMMON)
+#define PIT_COMMON_CLASS(klass) \
+     OBJECT_CLASS_CHECK(PITCommonClass, (klass), TYPE_PIT_COMMON)
+#define PIT_COMMON_GET_CLASS(obj) \
+     OBJECT_GET_CLASS(PITCommonClass, (obj), TYPE_PIT_COMMON)
+
+typedef struct PITCommonClass {
+    ISADeviceClass parent_class;
+
+    int (*init)(PITCommonState *s);
+    void (*set_channel_gate)(PITCommonState *s, PITChannelState *sc, int val);
+    void (*get_channel_info)(PITCommonState *s, PITChannelState *sc,
+                             PITChannelInfo *info);
+    void (*pre_save)(PITCommonState *s);
+    void (*post_load)(PITCommonState *s);
+} PITCommonClass;
+
+int pit_get_out(PITChannelState *s, int64_t current_time);
+int64_t pit_get_next_transition_time(PITChannelState *s, int64_t current_time);
+void pit_get_channel_info_common(PITCommonState *s, PITChannelState *sc,
+                                 PITChannelInfo *info);
+void pit_reset_common(PITCommonState *s);
+
+#endif /* !QEMU_I8254_INTERNAL_H */
-- 
1.7.3.4

^ permalink raw reply related	[flat|nested] 23+ messages in thread

* [PATCH 2/4] i8254: Open-code timer restore
  2012-02-05 10:46 ` [Qemu-devel] " Jan Kiszka
@ 2012-02-05 10:46   ` Jan Kiszka
  -1 siblings, 0 replies; 23+ messages in thread
From: Jan Kiszka @ 2012-02-05 10:46 UTC (permalink / raw)
  To: Avi Kivity, Marcelo Tosatti; +Cc: kvm, qemu-devel, Anthony Liguori

From: Jan Kiszka <jan.kiszka@siemens.com>

Same as for the APIC: To enable migration between accelerated and
non-accelerated models, we need to arm the channel 0 timer only inside
the emulated PIT model. The common code just saves/restores that timer
to the the next_transition_time field.

Signed-off-by: Jan Kiszka <jan.kiszka@siemens.com>
---
 hw/i8254.c        |   12 ++++++++++++
 hw/i8254_common.c |    6 +++---
 2 files changed, 15 insertions(+), 3 deletions(-)

diff --git a/hw/i8254.c b/hw/i8254.c
index f9f58e0..d41ee05 100644
--- a/hw/i8254.c
+++ b/hw/i8254.c
@@ -300,6 +300,17 @@ static const MemoryRegionOps pit_ioport_ops = {
     .old_portio = pit_portio
 };
 
+static void pit_post_load(PITCommonState *s)
+{
+    PITChannelState *sc = &s->channels[0];
+
+    if (sc->next_transition_time != -1) {
+        qemu_mod_timer(sc->irq_timer, sc->next_transition_time);
+    } else {
+        qemu_del_timer(sc->irq_timer);
+    }
+}
+
 static int pit_initfn(PITCommonState *pit)
 {
     PITChannelState *s;
@@ -329,6 +340,7 @@ static void pit_class_initfn(ObjectClass *klass, void *data)
     k->init = pit_initfn;
     k->set_channel_gate = pit_set_channel_gate;
     k->get_channel_info = pit_get_channel_info_common;
+    k->post_load = pit_post_load;
     dc->reset = pit_reset;
     dc->props = pit_properties;
 }
diff --git a/hw/i8254_common.c b/hw/i8254_common.c
index 0601d88..b60fbda 100644
--- a/hw/i8254_common.c
+++ b/hw/i8254_common.c
@@ -234,9 +234,8 @@ static int pit_load_old(QEMUFile *f, void *opaque, int version_id)
         qemu_get_8s(f, &s->gate);
         s->count_load_time = qemu_get_be64(f);
         s->irq_disabled = 0;
-        if (s->irq_timer) {
+        if (i == 0) {
             s->next_transition_time = qemu_get_be64(f);
-            qemu_get_timer(f, s->irq_timer);
         }
     }
     return 0;
@@ -275,7 +274,8 @@ static const VMStateDescription vmstate_pit_common = {
         VMSTATE_UINT32_V(channels[0].irq_disabled, PITCommonState, 3),
         VMSTATE_STRUCT_ARRAY(channels, PITCommonState, 3, 2,
                              vmstate_pit_channel, PITChannelState),
-        VMSTATE_TIMER(channels[0].irq_timer, PITCommonState),
+        VMSTATE_INT64(channels[0].next_transition_time,
+                      PITCommonState), /* formerly irq_timer */
         VMSTATE_END_OF_LIST()
     }
 };
-- 
1.7.3.4


^ permalink raw reply related	[flat|nested] 23+ messages in thread

* [Qemu-devel] [PATCH 2/4] i8254: Open-code timer restore
@ 2012-02-05 10:46   ` Jan Kiszka
  0 siblings, 0 replies; 23+ messages in thread
From: Jan Kiszka @ 2012-02-05 10:46 UTC (permalink / raw)
  To: Avi Kivity, Marcelo Tosatti; +Cc: Anthony Liguori, qemu-devel, kvm

From: Jan Kiszka <jan.kiszka@siemens.com>

Same as for the APIC: To enable migration between accelerated and
non-accelerated models, we need to arm the channel 0 timer only inside
the emulated PIT model. The common code just saves/restores that timer
to the the next_transition_time field.

Signed-off-by: Jan Kiszka <jan.kiszka@siemens.com>
---
 hw/i8254.c        |   12 ++++++++++++
 hw/i8254_common.c |    6 +++---
 2 files changed, 15 insertions(+), 3 deletions(-)

diff --git a/hw/i8254.c b/hw/i8254.c
index f9f58e0..d41ee05 100644
--- a/hw/i8254.c
+++ b/hw/i8254.c
@@ -300,6 +300,17 @@ static const MemoryRegionOps pit_ioport_ops = {
     .old_portio = pit_portio
 };
 
+static void pit_post_load(PITCommonState *s)
+{
+    PITChannelState *sc = &s->channels[0];
+
+    if (sc->next_transition_time != -1) {
+        qemu_mod_timer(sc->irq_timer, sc->next_transition_time);
+    } else {
+        qemu_del_timer(sc->irq_timer);
+    }
+}
+
 static int pit_initfn(PITCommonState *pit)
 {
     PITChannelState *s;
@@ -329,6 +340,7 @@ static void pit_class_initfn(ObjectClass *klass, void *data)
     k->init = pit_initfn;
     k->set_channel_gate = pit_set_channel_gate;
     k->get_channel_info = pit_get_channel_info_common;
+    k->post_load = pit_post_load;
     dc->reset = pit_reset;
     dc->props = pit_properties;
 }
diff --git a/hw/i8254_common.c b/hw/i8254_common.c
index 0601d88..b60fbda 100644
--- a/hw/i8254_common.c
+++ b/hw/i8254_common.c
@@ -234,9 +234,8 @@ static int pit_load_old(QEMUFile *f, void *opaque, int version_id)
         qemu_get_8s(f, &s->gate);
         s->count_load_time = qemu_get_be64(f);
         s->irq_disabled = 0;
-        if (s->irq_timer) {
+        if (i == 0) {
             s->next_transition_time = qemu_get_be64(f);
-            qemu_get_timer(f, s->irq_timer);
         }
     }
     return 0;
@@ -275,7 +274,8 @@ static const VMStateDescription vmstate_pit_common = {
         VMSTATE_UINT32_V(channels[0].irq_disabled, PITCommonState, 3),
         VMSTATE_STRUCT_ARRAY(channels, PITCommonState, 3, 2,
                              vmstate_pit_channel, PITChannelState),
-        VMSTATE_TIMER(channels[0].irq_timer, PITCommonState),
+        VMSTATE_INT64(channels[0].next_transition_time,
+                      PITCommonState), /* formerly irq_timer */
         VMSTATE_END_OF_LIST()
     }
 };
-- 
1.7.3.4

^ permalink raw reply related	[flat|nested] 23+ messages in thread

* [PATCH 3/4] kvm: Add kvm_has_pit_state2 helper
  2012-02-05 10:46 ` [Qemu-devel] " Jan Kiszka
@ 2012-02-05 10:46   ` Jan Kiszka
  -1 siblings, 0 replies; 23+ messages in thread
From: Jan Kiszka @ 2012-02-05 10:46 UTC (permalink / raw)
  To: Avi Kivity, Marcelo Tosatti; +Cc: kvm, qemu-devel, Anthony Liguori

From: Jan Kiszka <jan.kiszka@siemens.com>

To be used for in-kernel PIT emulation.

Signed-off-by: Jan Kiszka <jan.kiszka@siemens.com>
---
 kvm-all.c  |   10 ++++++++++
 kvm-stub.c |    5 +++++
 kvm.h      |    1 +
 3 files changed, 16 insertions(+), 0 deletions(-)

diff --git a/kvm-all.c b/kvm-all.c
index c4babda..bddf922 100644
--- a/kvm-all.c
+++ b/kvm-all.c
@@ -75,6 +75,7 @@ struct KVMState
     struct kvm_sw_breakpoint_head kvm_sw_breakpoints;
 #endif
     int pit_in_kernel;
+    int pit_state2;
     int xsave, xcrs;
     int many_ioeventfds;
     int irqchip_inject_ioctl;
@@ -954,6 +955,10 @@ int kvm_init(void)
     s->xcrs = kvm_check_extension(s, KVM_CAP_XCRS);
 #endif
 
+#ifdef KVM_CAP_PIT_STATE2
+    s->pit_state2 = kvm_check_extension(s, KVM_CAP_PIT_STATE2);
+#endif
+
     ret = kvm_arch_init(s);
     if (ret < 0) {
         goto err;
@@ -1291,6 +1296,11 @@ int kvm_has_xcrs(void)
     return kvm_state->xcrs;
 }
 
+int kvm_has_pit_state2(void)
+{
+    return kvm_state->pit_state2;
+}
+
 int kvm_has_many_ioeventfds(void)
 {
     if (!kvm_enabled()) {
diff --git a/kvm-stub.c b/kvm-stub.c
index f63a0d2..1f1c686 100644
--- a/kvm-stub.c
+++ b/kvm-stub.c
@@ -78,6 +78,11 @@ int kvm_allows_irq0_override(void)
     return 1;
 }
 
+int kvm_has_pit_state2(void)
+{
+    return 0;
+}
+
 void kvm_setup_guest_memory(void *start, size_t size)
 {
 }
diff --git a/kvm.h b/kvm.h
index f9f1dc8..8ef4476 100644
--- a/kvm.h
+++ b/kvm.h
@@ -54,6 +54,7 @@ int kvm_has_robust_singlestep(void);
 int kvm_has_debugregs(void);
 int kvm_has_xsave(void);
 int kvm_has_xcrs(void);
+int kvm_has_pit_state2(void);
 int kvm_has_many_ioeventfds(void);
 int kvm_has_gsi_routing(void);
 
-- 
1.7.3.4


^ permalink raw reply related	[flat|nested] 23+ messages in thread

* [Qemu-devel] [PATCH 3/4] kvm: Add kvm_has_pit_state2 helper
@ 2012-02-05 10:46   ` Jan Kiszka
  0 siblings, 0 replies; 23+ messages in thread
From: Jan Kiszka @ 2012-02-05 10:46 UTC (permalink / raw)
  To: Avi Kivity, Marcelo Tosatti; +Cc: Anthony Liguori, qemu-devel, kvm

From: Jan Kiszka <jan.kiszka@siemens.com>

To be used for in-kernel PIT emulation.

Signed-off-by: Jan Kiszka <jan.kiszka@siemens.com>
---
 kvm-all.c  |   10 ++++++++++
 kvm-stub.c |    5 +++++
 kvm.h      |    1 +
 3 files changed, 16 insertions(+), 0 deletions(-)

diff --git a/kvm-all.c b/kvm-all.c
index c4babda..bddf922 100644
--- a/kvm-all.c
+++ b/kvm-all.c
@@ -75,6 +75,7 @@ struct KVMState
     struct kvm_sw_breakpoint_head kvm_sw_breakpoints;
 #endif
     int pit_in_kernel;
+    int pit_state2;
     int xsave, xcrs;
     int many_ioeventfds;
     int irqchip_inject_ioctl;
@@ -954,6 +955,10 @@ int kvm_init(void)
     s->xcrs = kvm_check_extension(s, KVM_CAP_XCRS);
 #endif
 
+#ifdef KVM_CAP_PIT_STATE2
+    s->pit_state2 = kvm_check_extension(s, KVM_CAP_PIT_STATE2);
+#endif
+
     ret = kvm_arch_init(s);
     if (ret < 0) {
         goto err;
@@ -1291,6 +1296,11 @@ int kvm_has_xcrs(void)
     return kvm_state->xcrs;
 }
 
+int kvm_has_pit_state2(void)
+{
+    return kvm_state->pit_state2;
+}
+
 int kvm_has_many_ioeventfds(void)
 {
     if (!kvm_enabled()) {
diff --git a/kvm-stub.c b/kvm-stub.c
index f63a0d2..1f1c686 100644
--- a/kvm-stub.c
+++ b/kvm-stub.c
@@ -78,6 +78,11 @@ int kvm_allows_irq0_override(void)
     return 1;
 }
 
+int kvm_has_pit_state2(void)
+{
+    return 0;
+}
+
 void kvm_setup_guest_memory(void *start, size_t size)
 {
 }
diff --git a/kvm.h b/kvm.h
index f9f1dc8..8ef4476 100644
--- a/kvm.h
+++ b/kvm.h
@@ -54,6 +54,7 @@ int kvm_has_robust_singlestep(void);
 int kvm_has_debugregs(void);
 int kvm_has_xsave(void);
 int kvm_has_xcrs(void);
+int kvm_has_pit_state2(void);
 int kvm_has_many_ioeventfds(void);
 int kvm_has_gsi_routing(void);
 
-- 
1.7.3.4

^ permalink raw reply related	[flat|nested] 23+ messages in thread

* [PATCH 4/4] kvm: x86: Add user space part for in-kernel i8254
  2012-02-05 10:46 ` [Qemu-devel] " Jan Kiszka
@ 2012-02-05 10:46   ` Jan Kiszka
  -1 siblings, 0 replies; 23+ messages in thread
From: Jan Kiszka @ 2012-02-05 10:46 UTC (permalink / raw)
  To: Avi Kivity, Marcelo Tosatti; +Cc: kvm, qemu-devel, Anthony Liguori

From: Jan Kiszka <jan.kiszka@siemens.com>

This provides the required user space stubs to enable the in-kernel
i8254 emulation of KVM.

The in-kernel model supports lost tick compensation according to the
"delay" policy. This is enabled by default and can be switched off via a
device property.

Depending on the feature set of the host kernel (before 2.6.32), we may
have to disable the HPET or lack sound output from the PC speaker.

Signed-off-by: Jan Kiszka <jan.kiszka@siemens.com>
---
 Makefile.target |    2 +-
 hw/i8254.h      |   11 +++
 hw/kvm/i8254.c  |  241 +++++++++++++++++++++++++++++++++++++++++++++++++++++++
 hw/pc.c         |   14 +++-
 4 files changed, 265 insertions(+), 3 deletions(-)
 create mode 100644 hw/kvm/i8254.c

diff --git a/Makefile.target b/Makefile.target
index 68481a3..2af5511 100644
--- a/Makefile.target
+++ b/Makefile.target
@@ -235,7 +235,7 @@ obj-i386-y += vmport.o
 obj-i386-y += pci-hotplug.o smbios.o wdt_ib700.o
 obj-i386-y += debugcon.o multiboot.o
 obj-i386-y += pc_piix.o
-obj-i386-$(CONFIG_KVM) += kvm/clock.o kvm/apic.o kvm/i8259.o kvm/ioapic.o
+obj-i386-$(CONFIG_KVM) += kvm/clock.o kvm/apic.o kvm/i8259.o kvm/ioapic.o kvm/i8254.o
 obj-i386-$(CONFIG_SPICE) += qxl.o qxl-logger.o qxl-render.o
 
 # shared objects
diff --git a/hw/i8254.h b/hw/i8254.h
index a1d2e98..ba6b598 100644
--- a/hw/i8254.h
+++ b/hw/i8254.h
@@ -51,6 +51,17 @@ static inline ISADevice *pit_init(ISABus *bus, int base, int isa_irq,
     return dev;
 }
 
+static inline ISADevice *kvm_pit_init(ISABus *bus, int base)
+{
+    ISADevice *dev;
+
+    dev = isa_create(bus, "kvm-pit");
+    qdev_prop_set_uint32(&dev->qdev, "iobase", base);
+    qdev_init_nofail(&dev->qdev);
+
+    return dev;
+}
+
 void pit_set_gate(ISADevice *dev, int channel, int val);
 void pit_get_channel_info(ISADevice *dev, int channel, PITChannelInfo *info);
 
diff --git a/hw/kvm/i8254.c b/hw/kvm/i8254.c
new file mode 100644
index 0000000..a1e06d5
--- /dev/null
+++ b/hw/kvm/i8254.c
@@ -0,0 +1,241 @@
+/*
+ * KVM in-kernel PIT (i8254) support
+ *
+ * Copyright (c) 2012 Siemens AG
+ *
+ * Authors:
+ *  Jan Kiszka          <jan.kiszka@siemens.com>
+ *
+ * This work is licensed under the terms of the GNU GPL version 2.
+ * See the COPYING file in the top-level directory.
+ */
+#include "qemu-timer.h"
+#include "hw/i8254.h"
+#include "hw/i8254_internal.h"
+#include "kvm.h"
+
+#define KVM_PIT_REINJECT_BIT 0
+
+typedef struct KVMPITState {
+    PITCommonState pit;
+    LostTickPolicy lost_tick_policy;
+} KVMPITState;
+
+static void kvm_pit_get(PITCommonState *s)
+{
+    struct kvm_pit_state2 kpit;
+    struct kvm_pit_channel_state *kchan;
+    struct PITChannelState *sc;
+    int i, ret;
+
+    if (kvm_has_pit_state2()) {
+        ret = kvm_vm_ioctl(kvm_state, KVM_GET_PIT2, &kpit);
+        if (ret < 0) {
+            fprintf(stderr, "KVM_GET_PIT2 failed: %s\n", strerror(ret));
+            abort();
+        }
+        s->channels[0].irq_disabled = kpit.flags & KVM_PIT_FLAGS_HPET_LEGACY;
+    } else {
+        /*
+         * kvm_pit_state2 is superset of kvm_pit_state struct,
+         * so we can use it for KVM_GET_PIT as well.
+         */
+        ret = kvm_vm_ioctl(kvm_state, KVM_GET_PIT, &kpit);
+        if (ret < 0) {
+            fprintf(stderr, "KVM_GET_PIT failed: %s\n", strerror(ret));
+            abort();
+        }
+    }
+    for (i = 0; i < 3; i++) {
+        kchan = &kpit.channels[i];
+        sc = &s->channels[i];
+        sc->count = kchan->count;
+        sc->latched_count = kchan->latched_count;
+        sc->count_latched = kchan->count_latched;
+        sc->status_latched = kchan->status_latched;
+        sc->status = kchan->status;
+        sc->read_state = kchan->read_state;
+        sc->write_state = kchan->write_state;
+        sc->write_latch = kchan->write_latch;
+        sc->rw_mode = kchan->rw_mode;
+        sc->mode = kchan->mode;
+        sc->bcd = kchan->bcd;
+        sc->gate = kchan->gate;
+        sc->count_load_time = kchan->count_load_time;
+    }
+
+    sc = &s->channels[0];
+    sc->next_transition_time =
+        pit_get_next_transition_time(sc, sc->count_load_time);
+}
+
+static void kvm_pit_put(PITCommonState *s)
+{
+    struct kvm_pit_state2 kpit;
+    struct kvm_pit_channel_state *kchan;
+    struct PITChannelState *sc;
+    int i, ret;
+
+    kpit.flags = s->channels[0].irq_disabled ? KVM_PIT_FLAGS_HPET_LEGACY : 0;
+    for (i = 0; i < 3; i++) {
+        kchan = &kpit.channels[i];
+        sc = &s->channels[i];
+        kchan->count = sc->count;
+        kchan->latched_count = sc->latched_count;
+        kchan->count_latched = sc->count_latched;
+        kchan->status_latched = sc->status_latched;
+        kchan->status = sc->status;
+        kchan->read_state = sc->read_state;
+        kchan->write_state = sc->write_state;
+        kchan->write_latch = sc->write_latch;
+        kchan->rw_mode = sc->rw_mode;
+        kchan->mode = sc->mode;
+        kchan->bcd = sc->bcd;
+        kchan->gate = sc->gate;
+        kchan->count_load_time = sc->count_load_time;
+    }
+
+    ret = kvm_vm_ioctl(kvm_state,
+                       kvm_has_pit_state2() ? KVM_SET_PIT2 : KVM_SET_PIT,
+                       &kpit);
+    if (ret < 0) {
+        fprintf(stderr, "%s failed: %s\n",
+                kvm_has_pit_state2() ? "KVM_SET_PIT2" : "KVM_SET_PIT",
+                strerror(ret));
+        abort();
+    }
+}
+
+static void kvm_pit_set_gate(PITCommonState *s, PITChannelState *sc, int val)
+{
+    kvm_pit_get(s);
+
+    switch (sc->mode) {
+    default:
+    case 0:
+    case 4:
+        /* XXX: just disable/enable counting */
+        break;
+    case 1:
+    case 2:
+    case 3:
+    case 5:
+        if (sc->gate < val) {
+            /* restart counting on rising edge */
+            sc->count_load_time = qemu_get_clock_ns(vm_clock);
+        }
+        break;
+    }
+    sc->gate = val;
+
+    kvm_pit_put(s);
+}
+
+static void kvm_pit_get_channel_info(PITCommonState *s, PITChannelState *sc,
+                                     PITChannelInfo *info)
+{
+    kvm_pit_get(s);
+
+    pit_get_channel_info_common(s, sc, info);
+}
+
+static void kvm_pit_reset(DeviceState *dev)
+{
+    PITCommonState *s = DO_UPCAST(PITCommonState, dev.qdev, dev);
+
+    pit_reset_common(s);
+
+    kvm_pit_put(s);
+}
+
+static void kvm_pit_irq_control(void *opaque, int n, int enable)
+{
+    PITCommonState *pit = opaque;
+    PITChannelState *s = &pit->channels[0];
+
+    kvm_pit_get(pit);
+
+    s->irq_disabled = !enable;
+
+    kvm_pit_put(pit);
+}
+
+static int kvm_pit_initfn(PITCommonState *pit)
+{
+    KVMPITState *s = DO_UPCAST(KVMPITState, pit, pit);
+    struct kvm_pit_config config = {
+        .flags = 0,
+    };
+    int ret;
+
+    if (kvm_check_extension(kvm_state, KVM_CAP_PIT2)) {
+        ret = kvm_vm_ioctl(kvm_state, KVM_CREATE_PIT2, &config);
+    } else {
+        ret = kvm_vm_ioctl(kvm_state, KVM_CREATE_PIT);
+    }
+    if (ret < 0) {
+        fprintf(stderr, "Create kernel PIC irqchip failed: %s\n",
+                strerror(ret));
+        return ret;
+    }
+    switch (s->lost_tick_policy) {
+    case LOST_TICK_DELAY:
+        break; /* enabled by default */
+    case LOST_TICK_DISCARD:
+        if (kvm_check_extension(kvm_state, KVM_CAP_REINJECT_CONTROL)) {
+            struct kvm_reinject_control control = { .pit_reinject = 0 };
+
+            ret = kvm_vm_ioctl(kvm_state, KVM_REINJECT_CONTROL, &control);
+            if (ret < 0) {
+                fprintf(stderr,
+                        "Can't disable in-kernel PIT reinjection: %s\n",
+                        strerror(ret));
+                return ret;
+            }
+        }
+        break;
+    default:
+        return -EINVAL;
+    }
+
+    memory_region_init_reservation(&pit->ioports, "kvm-pit", 4);
+
+    qdev_init_gpio_in(&pit->dev.qdev, kvm_pit_irq_control, 1);
+
+    return 0;
+}
+
+static Property kvm_pit_properties[] = {
+    DEFINE_PROP_HEX32("iobase", KVMPITState, pit.iobase,  -1),
+    DEFINE_PROP_LOSTTICKPOLICY("lost_tick_policy", KVMPITState,
+                               lost_tick_policy, LOST_TICK_DELAY),
+    DEFINE_PROP_END_OF_LIST(),
+};
+
+static void kvm_pit_class_init(ObjectClass *klass, void *data)
+{
+    PITCommonClass *k = PIT_COMMON_CLASS(klass);
+    DeviceClass *dc = DEVICE_CLASS(klass);
+
+    k->init = kvm_pit_initfn;
+    k->set_channel_gate = kvm_pit_set_gate;
+    k->get_channel_info = kvm_pit_get_channel_info;
+    k->pre_save = kvm_pit_get;
+    k->post_load = kvm_pit_put;
+    dc->reset = kvm_pit_reset;
+    dc->props = kvm_pit_properties;
+}
+
+static TypeInfo kvm_pit_info = {
+    .name          = "kvm-pit",
+    .parent        = TYPE_PIT_COMMON,
+    .instance_size = sizeof(KVMPITState),
+    .class_init = kvm_pit_class_init,
+};
+
+static void kvm_pit_register(void)
+{
+    type_register_static(&kvm_pit_info);
+}
+
+device_init(kvm_pit_register)
diff --git a/hw/pc.c b/hw/pc.c
index e2b6560..94952a4 100644
--- a/hw/pc.c
+++ b/hw/pc.c
@@ -1151,7 +1151,13 @@ void pc_basic_device_init(ISABus *isa_bus, qemu_irq *gsi,
 
     register_ioport_write(0xf0, 1, 1, ioportF0_write, NULL);
 
-    if (!no_hpet) {
+    /*
+     * 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) {
@@ -1167,7 +1173,11 @@ 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, pit_isa_irq, pit_alt_irq);
+    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);
+    }
     if (hpet) {
         /* connect PIT to output control line of the HPET */
         qdev_connect_gpio_out(hpet, 0, qdev_get_gpio_in(&pit->qdev, 0));
-- 
1.7.3.4


^ permalink raw reply related	[flat|nested] 23+ messages in thread

* [Qemu-devel] [PATCH 4/4] kvm: x86: Add user space part for in-kernel i8254
@ 2012-02-05 10:46   ` Jan Kiszka
  0 siblings, 0 replies; 23+ messages in thread
From: Jan Kiszka @ 2012-02-05 10:46 UTC (permalink / raw)
  To: Avi Kivity, Marcelo Tosatti; +Cc: Anthony Liguori, qemu-devel, kvm

From: Jan Kiszka <jan.kiszka@siemens.com>

This provides the required user space stubs to enable the in-kernel
i8254 emulation of KVM.

The in-kernel model supports lost tick compensation according to the
"delay" policy. This is enabled by default and can be switched off via a
device property.

Depending on the feature set of the host kernel (before 2.6.32), we may
have to disable the HPET or lack sound output from the PC speaker.

Signed-off-by: Jan Kiszka <jan.kiszka@siemens.com>
---
 Makefile.target |    2 +-
 hw/i8254.h      |   11 +++
 hw/kvm/i8254.c  |  241 +++++++++++++++++++++++++++++++++++++++++++++++++++++++
 hw/pc.c         |   14 +++-
 4 files changed, 265 insertions(+), 3 deletions(-)
 create mode 100644 hw/kvm/i8254.c

diff --git a/Makefile.target b/Makefile.target
index 68481a3..2af5511 100644
--- a/Makefile.target
+++ b/Makefile.target
@@ -235,7 +235,7 @@ obj-i386-y += vmport.o
 obj-i386-y += pci-hotplug.o smbios.o wdt_ib700.o
 obj-i386-y += debugcon.o multiboot.o
 obj-i386-y += pc_piix.o
-obj-i386-$(CONFIG_KVM) += kvm/clock.o kvm/apic.o kvm/i8259.o kvm/ioapic.o
+obj-i386-$(CONFIG_KVM) += kvm/clock.o kvm/apic.o kvm/i8259.o kvm/ioapic.o kvm/i8254.o
 obj-i386-$(CONFIG_SPICE) += qxl.o qxl-logger.o qxl-render.o
 
 # shared objects
diff --git a/hw/i8254.h b/hw/i8254.h
index a1d2e98..ba6b598 100644
--- a/hw/i8254.h
+++ b/hw/i8254.h
@@ -51,6 +51,17 @@ static inline ISADevice *pit_init(ISABus *bus, int base, int isa_irq,
     return dev;
 }
 
+static inline ISADevice *kvm_pit_init(ISABus *bus, int base)
+{
+    ISADevice *dev;
+
+    dev = isa_create(bus, "kvm-pit");
+    qdev_prop_set_uint32(&dev->qdev, "iobase", base);
+    qdev_init_nofail(&dev->qdev);
+
+    return dev;
+}
+
 void pit_set_gate(ISADevice *dev, int channel, int val);
 void pit_get_channel_info(ISADevice *dev, int channel, PITChannelInfo *info);
 
diff --git a/hw/kvm/i8254.c b/hw/kvm/i8254.c
new file mode 100644
index 0000000..a1e06d5
--- /dev/null
+++ b/hw/kvm/i8254.c
@@ -0,0 +1,241 @@
+/*
+ * KVM in-kernel PIT (i8254) support
+ *
+ * Copyright (c) 2012 Siemens AG
+ *
+ * Authors:
+ *  Jan Kiszka          <jan.kiszka@siemens.com>
+ *
+ * This work is licensed under the terms of the GNU GPL version 2.
+ * See the COPYING file in the top-level directory.
+ */
+#include "qemu-timer.h"
+#include "hw/i8254.h"
+#include "hw/i8254_internal.h"
+#include "kvm.h"
+
+#define KVM_PIT_REINJECT_BIT 0
+
+typedef struct KVMPITState {
+    PITCommonState pit;
+    LostTickPolicy lost_tick_policy;
+} KVMPITState;
+
+static void kvm_pit_get(PITCommonState *s)
+{
+    struct kvm_pit_state2 kpit;
+    struct kvm_pit_channel_state *kchan;
+    struct PITChannelState *sc;
+    int i, ret;
+
+    if (kvm_has_pit_state2()) {
+        ret = kvm_vm_ioctl(kvm_state, KVM_GET_PIT2, &kpit);
+        if (ret < 0) {
+            fprintf(stderr, "KVM_GET_PIT2 failed: %s\n", strerror(ret));
+            abort();
+        }
+        s->channels[0].irq_disabled = kpit.flags & KVM_PIT_FLAGS_HPET_LEGACY;
+    } else {
+        /*
+         * kvm_pit_state2 is superset of kvm_pit_state struct,
+         * so we can use it for KVM_GET_PIT as well.
+         */
+        ret = kvm_vm_ioctl(kvm_state, KVM_GET_PIT, &kpit);
+        if (ret < 0) {
+            fprintf(stderr, "KVM_GET_PIT failed: %s\n", strerror(ret));
+            abort();
+        }
+    }
+    for (i = 0; i < 3; i++) {
+        kchan = &kpit.channels[i];
+        sc = &s->channels[i];
+        sc->count = kchan->count;
+        sc->latched_count = kchan->latched_count;
+        sc->count_latched = kchan->count_latched;
+        sc->status_latched = kchan->status_latched;
+        sc->status = kchan->status;
+        sc->read_state = kchan->read_state;
+        sc->write_state = kchan->write_state;
+        sc->write_latch = kchan->write_latch;
+        sc->rw_mode = kchan->rw_mode;
+        sc->mode = kchan->mode;
+        sc->bcd = kchan->bcd;
+        sc->gate = kchan->gate;
+        sc->count_load_time = kchan->count_load_time;
+    }
+
+    sc = &s->channels[0];
+    sc->next_transition_time =
+        pit_get_next_transition_time(sc, sc->count_load_time);
+}
+
+static void kvm_pit_put(PITCommonState *s)
+{
+    struct kvm_pit_state2 kpit;
+    struct kvm_pit_channel_state *kchan;
+    struct PITChannelState *sc;
+    int i, ret;
+
+    kpit.flags = s->channels[0].irq_disabled ? KVM_PIT_FLAGS_HPET_LEGACY : 0;
+    for (i = 0; i < 3; i++) {
+        kchan = &kpit.channels[i];
+        sc = &s->channels[i];
+        kchan->count = sc->count;
+        kchan->latched_count = sc->latched_count;
+        kchan->count_latched = sc->count_latched;
+        kchan->status_latched = sc->status_latched;
+        kchan->status = sc->status;
+        kchan->read_state = sc->read_state;
+        kchan->write_state = sc->write_state;
+        kchan->write_latch = sc->write_latch;
+        kchan->rw_mode = sc->rw_mode;
+        kchan->mode = sc->mode;
+        kchan->bcd = sc->bcd;
+        kchan->gate = sc->gate;
+        kchan->count_load_time = sc->count_load_time;
+    }
+
+    ret = kvm_vm_ioctl(kvm_state,
+                       kvm_has_pit_state2() ? KVM_SET_PIT2 : KVM_SET_PIT,
+                       &kpit);
+    if (ret < 0) {
+        fprintf(stderr, "%s failed: %s\n",
+                kvm_has_pit_state2() ? "KVM_SET_PIT2" : "KVM_SET_PIT",
+                strerror(ret));
+        abort();
+    }
+}
+
+static void kvm_pit_set_gate(PITCommonState *s, PITChannelState *sc, int val)
+{
+    kvm_pit_get(s);
+
+    switch (sc->mode) {
+    default:
+    case 0:
+    case 4:
+        /* XXX: just disable/enable counting */
+        break;
+    case 1:
+    case 2:
+    case 3:
+    case 5:
+        if (sc->gate < val) {
+            /* restart counting on rising edge */
+            sc->count_load_time = qemu_get_clock_ns(vm_clock);
+        }
+        break;
+    }
+    sc->gate = val;
+
+    kvm_pit_put(s);
+}
+
+static void kvm_pit_get_channel_info(PITCommonState *s, PITChannelState *sc,
+                                     PITChannelInfo *info)
+{
+    kvm_pit_get(s);
+
+    pit_get_channel_info_common(s, sc, info);
+}
+
+static void kvm_pit_reset(DeviceState *dev)
+{
+    PITCommonState *s = DO_UPCAST(PITCommonState, dev.qdev, dev);
+
+    pit_reset_common(s);
+
+    kvm_pit_put(s);
+}
+
+static void kvm_pit_irq_control(void *opaque, int n, int enable)
+{
+    PITCommonState *pit = opaque;
+    PITChannelState *s = &pit->channels[0];
+
+    kvm_pit_get(pit);
+
+    s->irq_disabled = !enable;
+
+    kvm_pit_put(pit);
+}
+
+static int kvm_pit_initfn(PITCommonState *pit)
+{
+    KVMPITState *s = DO_UPCAST(KVMPITState, pit, pit);
+    struct kvm_pit_config config = {
+        .flags = 0,
+    };
+    int ret;
+
+    if (kvm_check_extension(kvm_state, KVM_CAP_PIT2)) {
+        ret = kvm_vm_ioctl(kvm_state, KVM_CREATE_PIT2, &config);
+    } else {
+        ret = kvm_vm_ioctl(kvm_state, KVM_CREATE_PIT);
+    }
+    if (ret < 0) {
+        fprintf(stderr, "Create kernel PIC irqchip failed: %s\n",
+                strerror(ret));
+        return ret;
+    }
+    switch (s->lost_tick_policy) {
+    case LOST_TICK_DELAY:
+        break; /* enabled by default */
+    case LOST_TICK_DISCARD:
+        if (kvm_check_extension(kvm_state, KVM_CAP_REINJECT_CONTROL)) {
+            struct kvm_reinject_control control = { .pit_reinject = 0 };
+
+            ret = kvm_vm_ioctl(kvm_state, KVM_REINJECT_CONTROL, &control);
+            if (ret < 0) {
+                fprintf(stderr,
+                        "Can't disable in-kernel PIT reinjection: %s\n",
+                        strerror(ret));
+                return ret;
+            }
+        }
+        break;
+    default:
+        return -EINVAL;
+    }
+
+    memory_region_init_reservation(&pit->ioports, "kvm-pit", 4);
+
+    qdev_init_gpio_in(&pit->dev.qdev, kvm_pit_irq_control, 1);
+
+    return 0;
+}
+
+static Property kvm_pit_properties[] = {
+    DEFINE_PROP_HEX32("iobase", KVMPITState, pit.iobase,  -1),
+    DEFINE_PROP_LOSTTICKPOLICY("lost_tick_policy", KVMPITState,
+                               lost_tick_policy, LOST_TICK_DELAY),
+    DEFINE_PROP_END_OF_LIST(),
+};
+
+static void kvm_pit_class_init(ObjectClass *klass, void *data)
+{
+    PITCommonClass *k = PIT_COMMON_CLASS(klass);
+    DeviceClass *dc = DEVICE_CLASS(klass);
+
+    k->init = kvm_pit_initfn;
+    k->set_channel_gate = kvm_pit_set_gate;
+    k->get_channel_info = kvm_pit_get_channel_info;
+    k->pre_save = kvm_pit_get;
+    k->post_load = kvm_pit_put;
+    dc->reset = kvm_pit_reset;
+    dc->props = kvm_pit_properties;
+}
+
+static TypeInfo kvm_pit_info = {
+    .name          = "kvm-pit",
+    .parent        = TYPE_PIT_COMMON,
+    .instance_size = sizeof(KVMPITState),
+    .class_init = kvm_pit_class_init,
+};
+
+static void kvm_pit_register(void)
+{
+    type_register_static(&kvm_pit_info);
+}
+
+device_init(kvm_pit_register)
diff --git a/hw/pc.c b/hw/pc.c
index e2b6560..94952a4 100644
--- a/hw/pc.c
+++ b/hw/pc.c
@@ -1151,7 +1151,13 @@ void pc_basic_device_init(ISABus *isa_bus, qemu_irq *gsi,
 
     register_ioport_write(0xf0, 1, 1, ioportF0_write, NULL);
 
-    if (!no_hpet) {
+    /*
+     * 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) {
@@ -1167,7 +1173,11 @@ 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, pit_isa_irq, pit_alt_irq);
+    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);
+    }
     if (hpet) {
         /* connect PIT to output control line of the HPET */
         qdev_connect_gpio_out(hpet, 0, qdev_get_gpio_in(&pit->qdev, 0));
-- 
1.7.3.4

^ permalink raw reply related	[flat|nested] 23+ messages in thread

* Re: [PATCH 2/4] i8254: Open-code timer restore
  2012-02-05 10:46   ` [Qemu-devel] " Jan Kiszka
@ 2012-02-05 11:23     ` Paolo Bonzini
  -1 siblings, 0 replies; 23+ messages in thread
From: Paolo Bonzini @ 2012-02-05 11:23 UTC (permalink / raw)
  To: kvm; +Cc: qemu-devel

On 02/05/2012 11:46 AM, Jan Kiszka wrote:
> diff --git a/hw/i8254_common.c b/hw/i8254_common.c
> index 0601d88..b60fbda 100644
> --- a/hw/i8254_common.c
> +++ b/hw/i8254_common.c
> @@ -234,9 +234,8 @@ static int pit_load_old(QEMUFile *f, void *opaque, int version_id)
>           qemu_get_8s(f,&s->gate);
>           s->count_load_time = qemu_get_be64(f);
>           s->irq_disabled = 0;
> -        if (s->irq_timer) {
> +        if (i == 0) {
>               s->next_transition_time = qemu_get_be64(f);
> -            qemu_get_timer(f, s->irq_timer);
>           }
>       }
>       return 0;

You need to invoke the post load callback manually in the load_old 
callback; see vmstate_load_state:

     if  (version_id < vmsd->minimum_version_id) {
         return vmsd->load_state_old(f, opaque, version_id);
     }

I noticed that in apic_common's apic_load_old you don't have the bug, 
but on the other hand you're unconditionally loading into s->timer, so 
"old" migration to a destination with in-kernel APIC doesn't work:

     if (version_id >= 2) {
         qemu_get_timer(f, s->timer);
     }

Paolo


^ permalink raw reply	[flat|nested] 23+ messages in thread

* Re: [Qemu-devel] [PATCH 2/4] i8254: Open-code timer restore
@ 2012-02-05 11:23     ` Paolo Bonzini
  0 siblings, 0 replies; 23+ messages in thread
From: Paolo Bonzini @ 2012-02-05 11:23 UTC (permalink / raw)
  To: Jan Kiszka; +Cc: Anthony Liguori, Marcelo Tosatti, Avi Kivity, kvm, qemu-devel

On 02/05/2012 11:46 AM, Jan Kiszka wrote:
> diff --git a/hw/i8254_common.c b/hw/i8254_common.c
> index 0601d88..b60fbda 100644
> --- a/hw/i8254_common.c
> +++ b/hw/i8254_common.c
> @@ -234,9 +234,8 @@ static int pit_load_old(QEMUFile *f, void *opaque, int version_id)
>           qemu_get_8s(f,&s->gate);
>           s->count_load_time = qemu_get_be64(f);
>           s->irq_disabled = 0;
> -        if (s->irq_timer) {
> +        if (i == 0) {
>               s->next_transition_time = qemu_get_be64(f);
> -            qemu_get_timer(f, s->irq_timer);
>           }
>       }
>       return 0;

You need to invoke the post load callback manually in the load_old 
callback; see vmstate_load_state:

     if  (version_id < vmsd->minimum_version_id) {
         return vmsd->load_state_old(f, opaque, version_id);
     }

I noticed that in apic_common's apic_load_old you don't have the bug, 
but on the other hand you're unconditionally loading into s->timer, so 
"old" migration to a destination with in-kernel APIC doesn't work:

     if (version_id >= 2) {
         qemu_get_timer(f, s->timer);
     }

Paolo

^ permalink raw reply	[flat|nested] 23+ messages in thread

* Re: [PATCH 2/4] i8254: Open-code timer restore
  2012-02-05 11:23     ` [Qemu-devel] " Paolo Bonzini
@ 2012-02-05 11:33       ` Jan Kiszka
  -1 siblings, 0 replies; 23+ messages in thread
From: Jan Kiszka @ 2012-02-05 11:33 UTC (permalink / raw)
  To: Paolo Bonzini
  Cc: Avi Kivity, Marcelo Tosatti, kvm, qemu-devel, Anthony Liguori

[-- Attachment #1: Type: text/plain, Size: 1374 bytes --]

On 2012-02-05 12:23, Paolo Bonzini wrote:
> On 02/05/2012 11:46 AM, Jan Kiszka wrote:
>> diff --git a/hw/i8254_common.c b/hw/i8254_common.c
>> index 0601d88..b60fbda 100644
>> --- a/hw/i8254_common.c
>> +++ b/hw/i8254_common.c
>> @@ -234,9 +234,8 @@ static int pit_load_old(QEMUFile *f, void *opaque,
>> int version_id)
>>           qemu_get_8s(f,&s->gate);
>>           s->count_load_time = qemu_get_be64(f);
>>           s->irq_disabled = 0;
>> -        if (s->irq_timer) {
>> +        if (i == 0) {
>>               s->next_transition_time = qemu_get_be64(f);
>> -            qemu_get_timer(f, s->irq_timer);
>>           }
>>       }
>>       return 0;
> 
> You need to invoke the post load callback manually in the load_old
> callback; see vmstate_load_state:
> 
>     if  (version_id < vmsd->minimum_version_id) {
>         return vmsd->load_state_old(f, opaque, version_id);
>     }
> 
> I noticed that in apic_common's apic_load_old you don't have the bug,
> but on the other hand you're unconditionally loading into s->timer, so
> "old" migration to a destination with in-kernel APIC doesn't work:
> 
>     if (version_id >= 2) {
>         qemu_get_timer(f, s->timer);
>     }
> 

Hmm, true. The whole load_old is broken, in both APIC and PIT. Need to
call the post_load callbacks from there as well. Will fix, thanks.

Jan


[-- Attachment #2: OpenPGP digital signature --]
[-- Type: application/pgp-signature, Size: 262 bytes --]

^ permalink raw reply	[flat|nested] 23+ messages in thread

* Re: [Qemu-devel] [PATCH 2/4] i8254: Open-code timer restore
@ 2012-02-05 11:33       ` Jan Kiszka
  0 siblings, 0 replies; 23+ messages in thread
From: Jan Kiszka @ 2012-02-05 11:33 UTC (permalink / raw)
  To: Paolo Bonzini
  Cc: Anthony Liguori, Marcelo Tosatti, Avi Kivity, kvm, qemu-devel

[-- Attachment #1: Type: text/plain, Size: 1374 bytes --]

On 2012-02-05 12:23, Paolo Bonzini wrote:
> On 02/05/2012 11:46 AM, Jan Kiszka wrote:
>> diff --git a/hw/i8254_common.c b/hw/i8254_common.c
>> index 0601d88..b60fbda 100644
>> --- a/hw/i8254_common.c
>> +++ b/hw/i8254_common.c
>> @@ -234,9 +234,8 @@ static int pit_load_old(QEMUFile *f, void *opaque,
>> int version_id)
>>           qemu_get_8s(f,&s->gate);
>>           s->count_load_time = qemu_get_be64(f);
>>           s->irq_disabled = 0;
>> -        if (s->irq_timer) {
>> +        if (i == 0) {
>>               s->next_transition_time = qemu_get_be64(f);
>> -            qemu_get_timer(f, s->irq_timer);
>>           }
>>       }
>>       return 0;
> 
> You need to invoke the post load callback manually in the load_old
> callback; see vmstate_load_state:
> 
>     if  (version_id < vmsd->minimum_version_id) {
>         return vmsd->load_state_old(f, opaque, version_id);
>     }
> 
> I noticed that in apic_common's apic_load_old you don't have the bug,
> but on the other hand you're unconditionally loading into s->timer, so
> "old" migration to a destination with in-kernel APIC doesn't work:
> 
>     if (version_id >= 2) {
>         qemu_get_timer(f, s->timer);
>     }
> 

Hmm, true. The whole load_old is broken, in both APIC and PIT. Need to
call the post_load callbacks from there as well. Will fix, thanks.

Jan


[-- Attachment #2: OpenPGP digital signature --]
[-- Type: application/pgp-signature, Size: 262 bytes --]

^ permalink raw reply	[flat|nested] 23+ messages in thread

* [PATCH 2/4 v3] i8254: Open-code timer restore
  2012-02-05 10:46   ` [Qemu-devel] " Jan Kiszka
@ 2012-02-05 12:03     ` Jan Kiszka
  -1 siblings, 0 replies; 23+ messages in thread
From: Jan Kiszka @ 2012-02-05 12:03 UTC (permalink / raw)
  To: Avi Kivity, Marcelo Tosatti
  Cc: Paolo Bonzini, Anthony Liguori, qemu-devel, kvm

From: Jan Kiszka <jan.kiszka@siemens.com>

Same as for the APIC: To enable migration between accelerated and
non-accelerated models, we need to arm the channel 0 timer only inside
the emulated PIT model. The common code just saves/restores that timer
to the the next_transition_time field.

Signed-off-by: Jan Kiszka <jan.kiszka@siemens.com>
---

Changes in v3:
 - invoke post_load callback from load_old (as noted by Paolo)

 hw/i8254.c        |   12 ++++++++++++
 hw/i8254_common.c |   10 +++++++---
 2 files changed, 19 insertions(+), 3 deletions(-)

diff --git a/hw/i8254.c b/hw/i8254.c
index f9f58e0..d41ee05 100644
--- a/hw/i8254.c
+++ b/hw/i8254.c
@@ -300,6 +300,17 @@ static const MemoryRegionOps pit_ioport_ops = {
     .old_portio = pit_portio
 };
 
+static void pit_post_load(PITCommonState *s)
+{
+    PITChannelState *sc = &s->channels[0];
+
+    if (sc->next_transition_time != -1) {
+        qemu_mod_timer(sc->irq_timer, sc->next_transition_time);
+    } else {
+        qemu_del_timer(sc->irq_timer);
+    }
+}
+
 static int pit_initfn(PITCommonState *pit)
 {
     PITChannelState *s;
@@ -329,6 +340,7 @@ static void pit_class_initfn(ObjectClass *klass, void *data)
     k->init = pit_initfn;
     k->set_channel_gate = pit_set_channel_gate;
     k->get_channel_info = pit_get_channel_info_common;
+    k->post_load = pit_post_load;
     dc->reset = pit_reset;
     dc->props = pit_properties;
 }
diff --git a/hw/i8254_common.c b/hw/i8254_common.c
index 0601d88..2517db6 100644
--- a/hw/i8254_common.c
+++ b/hw/i8254_common.c
@@ -211,6 +211,7 @@ static const VMStateDescription vmstate_pit_channel = {
 static int pit_load_old(QEMUFile *f, void *opaque, int version_id)
 {
     PITCommonState *pit = opaque;
+    PITCommonClass *c = PIT_COMMON_GET_CLASS(pit);
     PITChannelState *s;
     int i;
 
@@ -234,11 +235,13 @@ static int pit_load_old(QEMUFile *f, void *opaque, int version_id)
         qemu_get_8s(f, &s->gate);
         s->count_load_time = qemu_get_be64(f);
         s->irq_disabled = 0;
-        if (s->irq_timer) {
+        if (i == 0) {
             s->next_transition_time = qemu_get_be64(f);
-            qemu_get_timer(f, s->irq_timer);
         }
     }
+    if (c->post_load) {
+        c->post_load(pit);
+    }
     return 0;
 }
 
@@ -275,7 +278,8 @@ static const VMStateDescription vmstate_pit_common = {
         VMSTATE_UINT32_V(channels[0].irq_disabled, PITCommonState, 3),
         VMSTATE_STRUCT_ARRAY(channels, PITCommonState, 3, 2,
                              vmstate_pit_channel, PITChannelState),
-        VMSTATE_TIMER(channels[0].irq_timer, PITCommonState),
+        VMSTATE_INT64(channels[0].next_transition_time,
+                      PITCommonState), /* formerly irq_timer */
         VMSTATE_END_OF_LIST()
     }
 };

^ permalink raw reply related	[flat|nested] 23+ messages in thread

* [Qemu-devel] [PATCH 2/4 v3] i8254: Open-code timer restore
@ 2012-02-05 12:03     ` Jan Kiszka
  0 siblings, 0 replies; 23+ messages in thread
From: Jan Kiszka @ 2012-02-05 12:03 UTC (permalink / raw)
  To: Avi Kivity, Marcelo Tosatti
  Cc: Paolo Bonzini, Anthony Liguori, qemu-devel, kvm

From: Jan Kiszka <jan.kiszka@siemens.com>

Same as for the APIC: To enable migration between accelerated and
non-accelerated models, we need to arm the channel 0 timer only inside
the emulated PIT model. The common code just saves/restores that timer
to the the next_transition_time field.

Signed-off-by: Jan Kiszka <jan.kiszka@siemens.com>
---

Changes in v3:
 - invoke post_load callback from load_old (as noted by Paolo)

 hw/i8254.c        |   12 ++++++++++++
 hw/i8254_common.c |   10 +++++++---
 2 files changed, 19 insertions(+), 3 deletions(-)

diff --git a/hw/i8254.c b/hw/i8254.c
index f9f58e0..d41ee05 100644
--- a/hw/i8254.c
+++ b/hw/i8254.c
@@ -300,6 +300,17 @@ static const MemoryRegionOps pit_ioport_ops = {
     .old_portio = pit_portio
 };
 
+static void pit_post_load(PITCommonState *s)
+{
+    PITChannelState *sc = &s->channels[0];
+
+    if (sc->next_transition_time != -1) {
+        qemu_mod_timer(sc->irq_timer, sc->next_transition_time);
+    } else {
+        qemu_del_timer(sc->irq_timer);
+    }
+}
+
 static int pit_initfn(PITCommonState *pit)
 {
     PITChannelState *s;
@@ -329,6 +340,7 @@ static void pit_class_initfn(ObjectClass *klass, void *data)
     k->init = pit_initfn;
     k->set_channel_gate = pit_set_channel_gate;
     k->get_channel_info = pit_get_channel_info_common;
+    k->post_load = pit_post_load;
     dc->reset = pit_reset;
     dc->props = pit_properties;
 }
diff --git a/hw/i8254_common.c b/hw/i8254_common.c
index 0601d88..2517db6 100644
--- a/hw/i8254_common.c
+++ b/hw/i8254_common.c
@@ -211,6 +211,7 @@ static const VMStateDescription vmstate_pit_channel = {
 static int pit_load_old(QEMUFile *f, void *opaque, int version_id)
 {
     PITCommonState *pit = opaque;
+    PITCommonClass *c = PIT_COMMON_GET_CLASS(pit);
     PITChannelState *s;
     int i;
 
@@ -234,11 +235,13 @@ static int pit_load_old(QEMUFile *f, void *opaque, int version_id)
         qemu_get_8s(f, &s->gate);
         s->count_load_time = qemu_get_be64(f);
         s->irq_disabled = 0;
-        if (s->irq_timer) {
+        if (i == 0) {
             s->next_transition_time = qemu_get_be64(f);
-            qemu_get_timer(f, s->irq_timer);
         }
     }
+    if (c->post_load) {
+        c->post_load(pit);
+    }
     return 0;
 }
 
@@ -275,7 +278,8 @@ static const VMStateDescription vmstate_pit_common = {
         VMSTATE_UINT32_V(channels[0].irq_disabled, PITCommonState, 3),
         VMSTATE_STRUCT_ARRAY(channels, PITCommonState, 3, 2,
                              vmstate_pit_channel, PITChannelState),
-        VMSTATE_TIMER(channels[0].irq_timer, PITCommonState),
+        VMSTATE_INT64(channels[0].next_transition_time,
+                      PITCommonState), /* formerly irq_timer */
         VMSTATE_END_OF_LIST()
     }
 };

^ permalink raw reply related	[flat|nested] 23+ messages in thread

* Re: [PATCH 3/4] kvm: Add kvm_has_pit_state2 helper
  2012-02-05 10:46   ` [Qemu-devel] " Jan Kiszka
@ 2012-02-05 20:03     ` Juan Quintela
  -1 siblings, 0 replies; 23+ messages in thread
From: Juan Quintela @ 2012-02-05 20:03 UTC (permalink / raw)
  To: Jan Kiszka; +Cc: Avi Kivity, Marcelo Tosatti, Anthony Liguori, qemu-devel, kvm

Jan Kiszka <jan.kiszka@web.de> wrote:
> From: Jan Kiszka <jan.kiszka@siemens.com>
>
> To be used for in-kernel PIT emulation.

....

> +    int pit_state2;

This is used as a bool.

>      int xsave, xcrs;
>      int many_ioeventfds;
>      int irqchip_inject_ioctl;
> @@ -954,6 +955,10 @@ int kvm_init(void)
>      s->xcrs = kvm_check_extension(s, KVM_CAP_XCRS);
>  #endif
>  
> +#ifdef KVM_CAP_PIT_STATE2
> +    s->pit_state2 = kvm_check_extension(s, KVM_CAP_PIT_STATE2);
> +#endif
> +

[ this happened to me when I was reviewing this patch, but culprit is
not this patch]

really kvm_check_extension() should also return a bool, but that is a
bigger change that this patch series tend to introduce.

So, I went to "man ioctl"

> RETURN VALUE
>        Usually, on success zero is returned.  A few ioctl() requests  use  the
>        return  value  as an output parameter and return a nonnegative value on
>       success.  On error, -1 is returned, and errno is set appropriately.

Usually is the important word there.

And then went to kvm-all.c

int kvm_check_extension(KVMState *s, unsigned int extension)
{
    int ret;

    ret = kvm_ioctl(s, KVM_CHECK_EXTENSION, extension);
    if (ret < 0) {
        ret = 0;
    }

    return ret;
}

What? it allways return zero?  Something should be wrong here.  I will
expect kvm_check_extension() to work by now.

Yes, kvm_ioctl() return 1 went the extension is there, just for the
people confused like me.

Later, Juan.


^ permalink raw reply	[flat|nested] 23+ messages in thread

* Re: [Qemu-devel] [PATCH 3/4] kvm: Add kvm_has_pit_state2 helper
@ 2012-02-05 20:03     ` Juan Quintela
  0 siblings, 0 replies; 23+ messages in thread
From: Juan Quintela @ 2012-02-05 20:03 UTC (permalink / raw)
  To: Jan Kiszka; +Cc: Anthony Liguori, Marcelo Tosatti, Avi Kivity, kvm, qemu-devel

Jan Kiszka <jan.kiszka@web.de> wrote:
> From: Jan Kiszka <jan.kiszka@siemens.com>
>
> To be used for in-kernel PIT emulation.

....

> +    int pit_state2;

This is used as a bool.

>      int xsave, xcrs;
>      int many_ioeventfds;
>      int irqchip_inject_ioctl;
> @@ -954,6 +955,10 @@ int kvm_init(void)
>      s->xcrs = kvm_check_extension(s, KVM_CAP_XCRS);
>  #endif
>  
> +#ifdef KVM_CAP_PIT_STATE2
> +    s->pit_state2 = kvm_check_extension(s, KVM_CAP_PIT_STATE2);
> +#endif
> +

[ this happened to me when I was reviewing this patch, but culprit is
not this patch]

really kvm_check_extension() should also return a bool, but that is a
bigger change that this patch series tend to introduce.

So, I went to "man ioctl"

> RETURN VALUE
>        Usually, on success zero is returned.  A few ioctl() requests  use  the
>        return  value  as an output parameter and return a nonnegative value on
>       success.  On error, -1 is returned, and errno is set appropriately.

Usually is the important word there.

And then went to kvm-all.c

int kvm_check_extension(KVMState *s, unsigned int extension)
{
    int ret;

    ret = kvm_ioctl(s, KVM_CHECK_EXTENSION, extension);
    if (ret < 0) {
        ret = 0;
    }

    return ret;
}

What? it allways return zero?  Something should be wrong here.  I will
expect kvm_check_extension() to work by now.

Yes, kvm_ioctl() return 1 went the extension is there, just for the
people confused like me.

Later, Juan.

^ permalink raw reply	[flat|nested] 23+ messages in thread

* Re: [PATCH 3/4] kvm: Add kvm_has_pit_state2 helper
  2012-02-05 20:03     ` [Qemu-devel] " Juan Quintela
@ 2012-02-05 20:36       ` Jan Kiszka
  -1 siblings, 0 replies; 23+ messages in thread
From: Jan Kiszka @ 2012-02-05 20:36 UTC (permalink / raw)
  To: quintela; +Cc: Anthony Liguori, Marcelo Tosatti, Avi Kivity, kvm, qemu-devel

[-- Attachment #1: Type: text/plain, Size: 1654 bytes --]

On 2012-02-05 21:03, Juan Quintela wrote:
> Jan Kiszka <jan.kiszka@web.de> wrote:
>> From: Jan Kiszka <jan.kiszka@siemens.com>
>>
>> To be used for in-kernel PIT emulation.
> 
> ....
> 
>> +    int pit_state2;
> 
> This is used as a bool.
> 
>>      int xsave, xcrs;
>>      int many_ioeventfds;
>>      int irqchip_inject_ioctl;
>> @@ -954,6 +955,10 @@ int kvm_init(void)
>>      s->xcrs = kvm_check_extension(s, KVM_CAP_XCRS);
>>  #endif
>>  
>> +#ifdef KVM_CAP_PIT_STATE2
>> +    s->pit_state2 = kvm_check_extension(s, KVM_CAP_PIT_STATE2);
>> +#endif
>> +
> 
> [ this happened to me when I was reviewing this patch, but culprit is
> not this patch]
> 
> really kvm_check_extension() should also return a bool, but that is a
> bigger change that this patch series tend to introduce.
> 
> So, I went to "man ioctl"
> 
>> RETURN VALUE
>>        Usually, on success zero is returned.  A few ioctl() requests  use  the
>>        return  value  as an output parameter and return a nonnegative value on
>>       success.  On error, -1 is returned, and errno is set appropriately.
> 
> Usually is the important word there.

Right, because the driver decides in the end what is returned.

In case of KVM_CHECK_EXTENSION, it is > 0 for supported. Sometimes it
returns an integer value that encode "how much" is supported, e.g.
KVM_CAP_IRQ_ROUTING provides the number of supported GSI routes.

That said, all those boolean caps could indeed be encoded as such. Some
smarter way to initialize and retrieve them would also be nice. Too much
boilerplate code.

Thanks for bending your brain around this :)

Jan


[-- Attachment #2: OpenPGP digital signature --]
[-- Type: application/pgp-signature, Size: 262 bytes --]

^ permalink raw reply	[flat|nested] 23+ messages in thread

* Re: [Qemu-devel] [PATCH 3/4] kvm: Add kvm_has_pit_state2 helper
@ 2012-02-05 20:36       ` Jan Kiszka
  0 siblings, 0 replies; 23+ messages in thread
From: Jan Kiszka @ 2012-02-05 20:36 UTC (permalink / raw)
  To: quintela; +Cc: Anthony Liguori, Marcelo Tosatti, Avi Kivity, kvm, qemu-devel

[-- Attachment #1: Type: text/plain, Size: 1654 bytes --]

On 2012-02-05 21:03, Juan Quintela wrote:
> Jan Kiszka <jan.kiszka@web.de> wrote:
>> From: Jan Kiszka <jan.kiszka@siemens.com>
>>
>> To be used for in-kernel PIT emulation.
> 
> ....
> 
>> +    int pit_state2;
> 
> This is used as a bool.
> 
>>      int xsave, xcrs;
>>      int many_ioeventfds;
>>      int irqchip_inject_ioctl;
>> @@ -954,6 +955,10 @@ int kvm_init(void)
>>      s->xcrs = kvm_check_extension(s, KVM_CAP_XCRS);
>>  #endif
>>  
>> +#ifdef KVM_CAP_PIT_STATE2
>> +    s->pit_state2 = kvm_check_extension(s, KVM_CAP_PIT_STATE2);
>> +#endif
>> +
> 
> [ this happened to me when I was reviewing this patch, but culprit is
> not this patch]
> 
> really kvm_check_extension() should also return a bool, but that is a
> bigger change that this patch series tend to introduce.
> 
> So, I went to "man ioctl"
> 
>> RETURN VALUE
>>        Usually, on success zero is returned.  A few ioctl() requests  use  the
>>        return  value  as an output parameter and return a nonnegative value on
>>       success.  On error, -1 is returned, and errno is set appropriately.
> 
> Usually is the important word there.

Right, because the driver decides in the end what is returned.

In case of KVM_CHECK_EXTENSION, it is > 0 for supported. Sometimes it
returns an integer value that encode "how much" is supported, e.g.
KVM_CAP_IRQ_ROUTING provides the number of supported GSI routes.

That said, all those boolean caps could indeed be encoded as such. Some
smarter way to initialize and retrieve them would also be nice. Too much
boilerplate code.

Thanks for bending your brain around this :)

Jan


[-- Attachment #2: OpenPGP digital signature --]
[-- Type: application/pgp-signature, Size: 262 bytes --]

^ permalink raw reply	[flat|nested] 23+ messages in thread

* Re: [PATCH 0/4] uq/master: Introduce KVM PIT support
  2012-02-05 10:46 ` [Qemu-devel] " Jan Kiszka
@ 2012-02-08 18:24   ` Marcelo Tosatti
  -1 siblings, 0 replies; 23+ messages in thread
From: Marcelo Tosatti @ 2012-02-08 18:24 UTC (permalink / raw)
  To: Jan Kiszka; +Cc: Anthony Liguori, Avi Kivity, kvm, qemu-devel

On Sun, Feb 05, 2012 at 11:46:26AM +0100, Jan Kiszka wrote:
> This adds another piece of qemu-kvm to upstream: The accelerated
> in-kernel model of the i8254. It does this in the same fashion as the
> interrupt controllers were already introduced. And it even has one bug
> less than qemu-kvm: PC speaker output still works with KVM acceleration
> enabled.
> 
> Changes in v2:
>  - Rebased over recent upstream master to reflect QOM changes
> 
> The patches depend on the follow upstream or uq/master patches:
>  - pit, hpet, pcspk: fixes & preparation for KVM (v4, 7 patches)
>    http://thread.gmane.org/gmane.comp.emulators.kvm.devel/86006
>  - kvm: Implement kvm_irqchip_in_kernel
>    http://thread.gmane.org/gmane.comp.emulators.qemu/134399
>  - KVM: Fix breakages of QOM conversion
>    http://permalink.gmane.org/gmane.comp.emulators.qemu/134844
> 
> It is based on upstream commit cb437e48ab (before the VGA breakage). The
> series plus dependencies is also available at
> 
>     git://git.kiszka.org/qemu-kvm.git queues/kvm-pit
> 
> Please review / merge.

Looks good.

^ permalink raw reply	[flat|nested] 23+ messages in thread

* Re: [Qemu-devel] [PATCH 0/4] uq/master: Introduce KVM PIT support
@ 2012-02-08 18:24   ` Marcelo Tosatti
  0 siblings, 0 replies; 23+ messages in thread
From: Marcelo Tosatti @ 2012-02-08 18:24 UTC (permalink / raw)
  To: Jan Kiszka; +Cc: Anthony Liguori, Avi Kivity, kvm, qemu-devel

On Sun, Feb 05, 2012 at 11:46:26AM +0100, Jan Kiszka wrote:
> This adds another piece of qemu-kvm to upstream: The accelerated
> in-kernel model of the i8254. It does this in the same fashion as the
> interrupt controllers were already introduced. And it even has one bug
> less than qemu-kvm: PC speaker output still works with KVM acceleration
> enabled.
> 
> Changes in v2:
>  - Rebased over recent upstream master to reflect QOM changes
> 
> The patches depend on the follow upstream or uq/master patches:
>  - pit, hpet, pcspk: fixes & preparation for KVM (v4, 7 patches)
>    http://thread.gmane.org/gmane.comp.emulators.kvm.devel/86006
>  - kvm: Implement kvm_irqchip_in_kernel
>    http://thread.gmane.org/gmane.comp.emulators.qemu/134399
>  - KVM: Fix breakages of QOM conversion
>    http://permalink.gmane.org/gmane.comp.emulators.qemu/134844
> 
> It is based on upstream commit cb437e48ab (before the VGA breakage). The
> series plus dependencies is also available at
> 
>     git://git.kiszka.org/qemu-kvm.git queues/kvm-pit
> 
> Please review / merge.

Looks good.

^ permalink raw reply	[flat|nested] 23+ messages in thread

* [PATCH 0/4] uq/master: Introduce KVM PIT support
@ 2012-01-31 18:46 Jan Kiszka
  0 siblings, 0 replies; 23+ messages in thread
From: Jan Kiszka @ 2012-01-31 18:46 UTC (permalink / raw)
  To: Avi Kivity, Marcelo Tosatti; +Cc: Anthony Liguori, qemu-devel, kvm

This adds another piece of qemu-kvm to upstream: The accelerated
in-kernel model of the i8254. It does this in the same fashion as the
interrupt controllers were already introduced. And it even has one bug
less than qemu-kvm: PC speaker output still works with KVM acceleration
enabled.

The patches depend on the follow upstream or uq/master patches:
- pit, hpet, pcspk: fixes & preparation for KVM (v7, 7 patches)
  http://thread.gmane.org/gmane.comp.emulators.qemu/134393
- Generic tick reinjection control (2 patches)
  http://thread.gmane.org/gmane.comp.emulators.qemu/133306
- kvm: Implement kvm_irqchip_in_kernel
  http://thread.gmane.org/gmane.comp.emulators.qemu/134399

The series plus dependencies is also available at

    git://git.kiszka.org/qemu-kvm.git queues/kvm-pit

Please review / merge.

Jan Kiszka (4):
  i8254: Factor out base class for KVM reuse
  i8254: Open-code timer restore
  kvm: Add kvm_has_pit_state2 helper
  kvm: x86: Add user space part for in-kernel i8254

 Makefile.objs       |    2 +-
 Makefile.target     |    2 +-
 hw/i8254.c          |  289 ++++++++---------------------------------------
 hw/i8254.h          |   11 ++
 hw/i8254_common.c   |  311 +++++++++++++++++++++++++++++++++++++++++++++++++++
 hw/i8254_internal.h |   87 ++++++++++++++
 hw/kvm/i8254.c      |  237 +++++++++++++++++++++++++++++++++++++++
 hw/pc.c             |   14 ++-
 kvm-all.c           |   10 ++
 kvm-stub.c          |    5 +
 kvm.h               |    1 +
 11 files changed, 723 insertions(+), 246 deletions(-)
 create mode 100644 hw/i8254_common.c
 create mode 100644 hw/i8254_internal.h
 create mode 100644 hw/kvm/i8254.c

-- 
1.7.3.4

^ permalink raw reply	[flat|nested] 23+ messages in thread

end of thread, other threads:[~2012-02-08 18:26 UTC | newest]

Thread overview: 23+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2012-02-05 10:46 [PATCH 0/4] uq/master: Introduce KVM PIT support Jan Kiszka
2012-02-05 10:46 ` [Qemu-devel] " Jan Kiszka
2012-02-05 10:46 ` [PATCH 1/4] i8254: Factor out base class for KVM reuse Jan Kiszka
2012-02-05 10:46   ` [Qemu-devel] " Jan Kiszka
2012-02-05 10:46 ` [PATCH 2/4] i8254: Open-code timer restore Jan Kiszka
2012-02-05 10:46   ` [Qemu-devel] " Jan Kiszka
2012-02-05 11:23   ` Paolo Bonzini
2012-02-05 11:23     ` [Qemu-devel] " Paolo Bonzini
2012-02-05 11:33     ` Jan Kiszka
2012-02-05 11:33       ` [Qemu-devel] " Jan Kiszka
2012-02-05 12:03   ` [PATCH 2/4 v3] " Jan Kiszka
2012-02-05 12:03     ` [Qemu-devel] " Jan Kiszka
2012-02-05 10:46 ` [PATCH 3/4] kvm: Add kvm_has_pit_state2 helper Jan Kiszka
2012-02-05 10:46   ` [Qemu-devel] " Jan Kiszka
2012-02-05 20:03   ` Juan Quintela
2012-02-05 20:03     ` [Qemu-devel] " Juan Quintela
2012-02-05 20:36     ` Jan Kiszka
2012-02-05 20:36       ` [Qemu-devel] " Jan Kiszka
2012-02-05 10:46 ` [PATCH 4/4] kvm: x86: Add user space part for in-kernel i8254 Jan Kiszka
2012-02-05 10:46   ` [Qemu-devel] " Jan Kiszka
2012-02-08 18:24 ` [PATCH 0/4] uq/master: Introduce KVM PIT support Marcelo Tosatti
2012-02-08 18:24   ` [Qemu-devel] " Marcelo Tosatti
  -- strict thread matches above, loose matches on Subject: below --
2012-01-31 18:46 Jan Kiszka

This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.