All of lore.kernel.org
 help / color / mirror / Atom feed
From: Anthony Liguori <anthony@codemonkey.ws>
To: Jan Kiszka <jan.kiszka@siemens.com>
Cc: Avi Kivity <avi@redhat.com>,
	Marcelo Tosatti <mtosatti@redhat.com>,
	Anthony Liguori <aliguori@us.ibm.com>,
	qemu-devel <qemu-devel@nongnu.org>,
	kvm@vger.kernel.org
Subject: Re: [Qemu-devel] [PATCH 1/4] i8254: Factor out base class for KVM reuse
Date: Tue, 31 Jan 2012 15:40:10 -0600	[thread overview]
Message-ID: <4F285FBA.5050607@codemonkey.ws> (raw)
In-Reply-To: <1e206a3b5dbd396606099fdbd9abd8c00bbdda31.1328035554.git.jan.kiszka@siemens.com>

On 01/31/2012 12:46 PM, Jan Kiszka wrote:
> 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>

Now that we have QOM bits, there's no need to factor out a common base class.

Just make the methods that you want to override virtual with the default 
implementation and then make a KVMPIT that inherits from the PIT and then 
overrides whatever virtual functions it needs to.

Regards,

Anthony Liguori

> ---
>   Makefile.objs       |    2 +-
>   hw/i8254.c          |  277 ++++++---------------------------------------
>   hw/i8254_common.c   |  311 +++++++++++++++++++++++++++++++++++++++++++++++++++
>   hw/i8254_internal.h |   87 ++++++++++++++
>   4 files changed, 434 insertions(+), 243 deletions(-)
>   create mode 100644 hw/i8254_common.c
>   create mode 100644 hw/i8254_internal.h
>
> diff --git a/Makefile.objs b/Makefile.objs
> index b942625..6a733fa 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 ff253bb..90e9a87 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,47 +300,44 @@ 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 void pit_class_initfn(ObjectClass *klass, void *data)
> +static void pit_class_init(ObjectClass *klass, void *data)
>   {
> -    ISADeviceClass *ic = ISA_DEVICE_CLASS(klass);
> -    ic->init = pit_initfn;
> +    PITCommonClass *k = PIT_COMMON_CLASS(klass);
> +
> +    k->init             = pit_initfn;
> +    k->set_channel_gate = pit_set_channel_gate;
> +    k->get_channel_info = pit_get_channel_info_common;
>   }
>
>   static DeviceInfo pit_info = {
> -    .name     = "isa-pit",
> -    .size     = sizeof(PITState),
> -    .vmsd     =&vmstate_pit,
> -    .reset    = pit_reset,
> -    .no_user  = 1,
> -    .class_init          = pit_class_initfn,
> +    .name       = "isa-pit",
> +    .size       = sizeof(PITCommonState),
> +    .reset      = pit_reset,
> +    .class_init = pit_class_init,
>       .props = (Property[]) {
> -        DEFINE_PROP_HEX32("iobase", PITState, iobase,  -1),
> +        DEFINE_PROP_HEX32("iobase", PITCommonState, iobase,  -1),
>           DEFINE_PROP_END_OF_LIST(),
>       },
>   };
>
>   static void pit_register(void)
>   {
> -    isa_qdev_register(&pit_info);
> +    pit_qdev_register(&pit_info);
>   }
>   device_init(pit_register)
> diff --git a/hw/i8254_common.c b/hw/i8254_common.c
> new file mode 100644
> index 0000000..6ff91fb
> --- /dev/null
> +++ b/hw/i8254_common.c
> @@ -0,0 +1,311 @@
> +/*
> + * 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);
> +
> +     ic->init = pit_init_common;
> +}
> +
> +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,
> +};
> +
> +void pit_qdev_register(DeviceInfo *info)
> +{
> +    info->vmsd =&vmstate_pit_common;
> +    info->no_user = 1;
> +    isa_qdev_register_subclass(info, TYPE_PIT_COMMON);
> +}
> +
> +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..a074aa0
> --- /dev/null
> +++ b/hw/i8254_internal.h
> @@ -0,0 +1,87 @@
> +/*
> + * 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);
> +
> +void pit_qdev_register(DeviceInfo *info);
> +
> +#endif /* !QEMU_I8254_INTERNAL_H */


WARNING: multiple messages have this Message-ID (diff)
From: Anthony Liguori <anthony@codemonkey.ws>
To: Jan Kiszka <jan.kiszka@siemens.com>
Cc: Anthony Liguori <aliguori@us.ibm.com>,
	Marcelo Tosatti <mtosatti@redhat.com>,
	Avi Kivity <avi@redhat.com>,
	kvm@vger.kernel.org, qemu-devel <qemu-devel@nongnu.org>
Subject: Re: [Qemu-devel] [PATCH 1/4] i8254: Factor out base class for KVM reuse
Date: Tue, 31 Jan 2012 15:40:10 -0600	[thread overview]
Message-ID: <4F285FBA.5050607@codemonkey.ws> (raw)
In-Reply-To: <1e206a3b5dbd396606099fdbd9abd8c00bbdda31.1328035554.git.jan.kiszka@siemens.com>

On 01/31/2012 12:46 PM, Jan Kiszka wrote:
> 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>

Now that we have QOM bits, there's no need to factor out a common base class.

Just make the methods that you want to override virtual with the default 
implementation and then make a KVMPIT that inherits from the PIT and then 
overrides whatever virtual functions it needs to.

Regards,

Anthony Liguori

> ---
>   Makefile.objs       |    2 +-
>   hw/i8254.c          |  277 ++++++---------------------------------------
>   hw/i8254_common.c   |  311 +++++++++++++++++++++++++++++++++++++++++++++++++++
>   hw/i8254_internal.h |   87 ++++++++++++++
>   4 files changed, 434 insertions(+), 243 deletions(-)
>   create mode 100644 hw/i8254_common.c
>   create mode 100644 hw/i8254_internal.h
>
> diff --git a/Makefile.objs b/Makefile.objs
> index b942625..6a733fa 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 ff253bb..90e9a87 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,47 +300,44 @@ 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 void pit_class_initfn(ObjectClass *klass, void *data)
> +static void pit_class_init(ObjectClass *klass, void *data)
>   {
> -    ISADeviceClass *ic = ISA_DEVICE_CLASS(klass);
> -    ic->init = pit_initfn;
> +    PITCommonClass *k = PIT_COMMON_CLASS(klass);
> +
> +    k->init             = pit_initfn;
> +    k->set_channel_gate = pit_set_channel_gate;
> +    k->get_channel_info = pit_get_channel_info_common;
>   }
>
>   static DeviceInfo pit_info = {
> -    .name     = "isa-pit",
> -    .size     = sizeof(PITState),
> -    .vmsd     =&vmstate_pit,
> -    .reset    = pit_reset,
> -    .no_user  = 1,
> -    .class_init          = pit_class_initfn,
> +    .name       = "isa-pit",
> +    .size       = sizeof(PITCommonState),
> +    .reset      = pit_reset,
> +    .class_init = pit_class_init,
>       .props = (Property[]) {
> -        DEFINE_PROP_HEX32("iobase", PITState, iobase,  -1),
> +        DEFINE_PROP_HEX32("iobase", PITCommonState, iobase,  -1),
>           DEFINE_PROP_END_OF_LIST(),
>       },
>   };
>
>   static void pit_register(void)
>   {
> -    isa_qdev_register(&pit_info);
> +    pit_qdev_register(&pit_info);
>   }
>   device_init(pit_register)
> diff --git a/hw/i8254_common.c b/hw/i8254_common.c
> new file mode 100644
> index 0000000..6ff91fb
> --- /dev/null
> +++ b/hw/i8254_common.c
> @@ -0,0 +1,311 @@
> +/*
> + * 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);
> +
> +     ic->init = pit_init_common;
> +}
> +
> +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,
> +};
> +
> +void pit_qdev_register(DeviceInfo *info)
> +{
> +    info->vmsd =&vmstate_pit_common;
> +    info->no_user = 1;
> +    isa_qdev_register_subclass(info, TYPE_PIT_COMMON);
> +}
> +
> +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..a074aa0
> --- /dev/null
> +++ b/hw/i8254_internal.h
> @@ -0,0 +1,87 @@
> +/*
> + * 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);
> +
> +void pit_qdev_register(DeviceInfo *info);
> +
> +#endif /* !QEMU_I8254_INTERNAL_H */

  reply	other threads:[~2012-01-31 21:40 UTC|newest]

Thread overview: 28+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2012-01-31 18:46 [PATCH 0/4] uq/master: Introduce KVM PIT support Jan Kiszka
2012-01-31 18:46 ` [Qemu-devel] " Jan Kiszka
2012-01-31 18:46 ` [PATCH 1/4] i8254: Factor out base class for KVM reuse Jan Kiszka
2012-01-31 18:46   ` [Qemu-devel] " Jan Kiszka
2012-01-31 21:40   ` Anthony Liguori [this message]
2012-01-31 21:40     ` Anthony Liguori
2012-01-31 21:49     ` Jan Kiszka
2012-01-31 21:49       ` Jan Kiszka
2012-01-31 21:59       ` Anthony Liguori
2012-01-31 21:59         ` [Qemu-devel] " Anthony Liguori
2012-02-01 12:23       ` Paolo Bonzini
2012-02-01 12:43         ` Jan Kiszka
2012-02-01 12:43           ` [Qemu-devel] " Jan Kiszka
2012-02-01 12:55           ` Paolo Bonzini
2012-02-01 12:55             ` Paolo Bonzini
2012-02-01 13:10             ` Jan Kiszka
2012-02-01 13:10               ` Jan Kiszka
2012-02-01 13:11               ` Jan Kiszka
2012-02-01 13:11                 ` Jan Kiszka
2012-02-01 13:19           ` Anthony Liguori
2012-02-01 13:19             ` [Qemu-devel] " Anthony Liguori
2012-01-31 18:46 ` [PATCH 2/4] i8254: Open-code timer restore Jan Kiszka
2012-01-31 18:46   ` [Qemu-devel] " Jan Kiszka
2012-01-31 18:46 ` [PATCH 3/4] kvm: Add kvm_has_pit_state2 helper Jan Kiszka
2012-01-31 18:46   ` [Qemu-devel] " Jan Kiszka
2012-01-31 18:46 ` [PATCH 4/4] kvm: x86: Add user space part for in-kernel i8254 Jan Kiszka
2012-01-31 18:46   ` [Qemu-devel] " Jan Kiszka
  -- strict thread matches above, loose matches on Subject: below --
2012-02-05 10:46 [PATCH 0/4] uq/master: Introduce KVM PIT support Jan Kiszka
2012-02-05 10:46 ` [Qemu-devel] [PATCH 1/4] i8254: Factor out base class for KVM reuse Jan Kiszka

Reply instructions:

You may reply publicly to this message via plain-text email
using any one of the following methods:

* Save the following mbox file, import it into your mail client,
  and reply-to-all from there: mbox

  Avoid top-posting and favor interleaved quoting:
  https://en.wikipedia.org/wiki/Posting_style#Interleaved_style

* Reply using the --to, --cc, and --in-reply-to
  switches of git-send-email(1):

  git send-email \
    --in-reply-to=4F285FBA.5050607@codemonkey.ws \
    --to=anthony@codemonkey.ws \
    --cc=aliguori@us.ibm.com \
    --cc=avi@redhat.com \
    --cc=jan.kiszka@siemens.com \
    --cc=kvm@vger.kernel.org \
    --cc=mtosatti@redhat.com \
    --cc=qemu-devel@nongnu.org \
    /path/to/YOUR_REPLY

  https://kernel.org/pub/software/scm/git/docs/git-send-email.html

* If your mail client supports setting the In-Reply-To header
  via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line before the message body.
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.