qemu-devel
[Top][All Lists]
Advanced

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

Re: [Qemu-devel] [PATCH] watchdog: add support to emulate winbond w83627


From: Daniel Fahlgren
Subject: Re: [Qemu-devel] [PATCH] watchdog: add support to emulate winbond w83627thf
Date: Wed, 07 Oct 2015 10:49:11 +0200

Hi,

On Mon, 2015-09-14 at 22:07 +0200, Daniel Fahlgren wrote:
> This patch adds support to emulate the watchdog functionality on the
> Winbond w83627thf chip. The other features of the chip are not emulated.
> It has been tested with Ubuntu 6.06, 14.04 and 15.04 as guests using the
> w83627hf_wdt module.

Ping, who should I poke about this? The maintainers file does not
mention the watchdog system.

> Signed-off-by: Daniel Fahlgren <address@hidden>
> ---
>  default-configs/i386-softmmu.mak   |   1 +
>  default-configs/x86_64-softmmu.mak |   1 +
>  hw/watchdog/Makefile.objs          |   1 +
>  hw/watchdog/wdt_w83627thf.c        | 255 
> +++++++++++++++++++++++++++++++++++++
>  4 files changed, 258 insertions(+)
>  create mode 100644 hw/watchdog/wdt_w83627thf.c
> 
> diff --git a/default-configs/i386-softmmu.mak 
> b/default-configs/i386-softmmu.mak
> index 9393cf0..30abc6f 100644
> --- a/default-configs/i386-softmmu.mak
> +++ b/default-configs/i386-softmmu.mak
> @@ -35,6 +35,7 @@ CONFIG_MC146818RTC=y
>  CONFIG_PAM=y
>  CONFIG_PCI_PIIX=y
>  CONFIG_WDT_IB700=y
> +CONFIG_WDT_W83627THF=y
>  CONFIG_XEN_I386=$(CONFIG_XEN)
>  CONFIG_ISA_DEBUG=y
>  CONFIG_ISA_TESTDEV=y
> diff --git a/default-configs/x86_64-softmmu.mak 
> b/default-configs/x86_64-softmmu.mak
> index 28e2099..906d14b 100644
> --- a/default-configs/x86_64-softmmu.mak
> +++ b/default-configs/x86_64-softmmu.mak
> @@ -35,6 +35,7 @@ CONFIG_MC146818RTC=y
>  CONFIG_PAM=y
>  CONFIG_PCI_PIIX=y
>  CONFIG_WDT_IB700=y
> +CONFIG_WDT_W83627THF=y
>  CONFIG_XEN_I386=$(CONFIG_XEN)
>  CONFIG_ISA_DEBUG=y
>  CONFIG_ISA_TESTDEV=y
> diff --git a/hw/watchdog/Makefile.objs b/hw/watchdog/Makefile.objs
> index 72e3ffd..e021b24 100644
> --- a/hw/watchdog/Makefile.objs
> +++ b/hw/watchdog/Makefile.objs
> @@ -2,3 +2,4 @@ common-obj-y += watchdog.o
>  common-obj-$(CONFIG_WDT_IB6300ESB) += wdt_i6300esb.o
>  common-obj-$(CONFIG_WDT_IB700) += wdt_ib700.o
>  common-obj-$(CONFIG_WDT_DIAG288) += wdt_diag288.o
> +common-obj-$(CONFIG_WDT_W83627THF) += wdt_w83627thf.o
> diff --git a/hw/watchdog/wdt_w83627thf.c b/hw/watchdog/wdt_w83627thf.c
> new file mode 100644
> index 0000000..143bb8f
> --- /dev/null
> +++ b/hw/watchdog/wdt_w83627thf.c
> @@ -0,0 +1,255 @@
> +/*
> + * Virtual hardware watchdog.
> + *
> + * This program is free software; you can redistribute it and/or
> + * modify it under the terms of the GNU General Public License
> + * as published by the Free Software Foundation; either version 2
> + * of the License, or (at your option) any later version.
> + *
> + * This program is distributed in the hope that it will be useful,
> + * but WITHOUT ANY WARRANTY; without even the implied warranty of
> + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
> + * GNU General Public License for more details.
> + *
> + * You should have received a copy of the GNU General Public License
> + * along with this program; if not, see <http://www.gnu.org/licenses/>.
> + *
> + * By Daniel Fahlgren (address@hidden)
> + */
> +
> +#include <inttypes.h>
> +
> +#include "qemu-common.h"
> +#include "qemu/timer.h"
> +#include "sysemu/watchdog.h"
> +#include "hw/isa/isa.h"
> +
> +/* #define W83627THF_DEBUG 1 */
> +
> +#ifdef W83627THF_DEBUG
> +#define w83627thf_debug(fs, ...) \
> +    fprintf(stderr, "w83627thf: %s: "fs, __func__, ##__VA_ARGS__)
> +#else
> +#define w83627thf_debug(fs, ...)
> +#endif
> +
> +#define WATCHDOG_W83627THF_DEVICE(obj) \
> +    OBJECT_CHECK(W83627THFState, (obj), "w83627thf")
> +
> +#define CHIP_VERSION           0x82
> +
> +#define CHIP_VERSION_REGISTER  0x20
> +#define PLED_MODE_REGISTER     0xF5
> +#define TIMEOUT_REGISTER       0xF6
> +#define TIMER_REGISTER         0xF7
> +
> +#define PLED_MINUTE_MODE       0x08
> +
> +#define WDT_W83627THF_EFER     0x2E
> +#define WDT_W83627THF_EFDR     0x2F
> +
> +enum {
> +    normal_mode = 0,
> +    extended_mode1 = 1,
> +    extended_mode2 = 2
> +};
> +
> +/* Device state. */
> +typedef struct W83627THFState {
> +    ISADevice parent_obj;
> +
> +    QEMUTimer *timer;
> +
> +    PortioList port_list;
> +
> +    uint8_t running_mode;
> +
> +    uint8_t selected_register;
> +
> +    uint8_t pled_mode_register;
> +    uint8_t timeout_register;
> +    uint8_t timer_register;
> +
> +} W83627THFState;
> +
> +static WatchdogTimerModel model = {
> +    .wdt_name = "w83627thf",
> +    .wdt_description = "Winbond w83627thf",
> +};
> +
> +static const VMStateDescription vmstate_w83627thf = {
> +    .name = "vmstate_w83627thf",
> +    .version_id = 0,
> +    .minimum_version_id = 0,
> +    .fields = (VMStateField[]) {
> +        VMSTATE_TIMER_PTR(timer, W83627THFState),
> +        VMSTATE_UINT8(running_mode, W83627THFState),
> +        VMSTATE_UINT8(selected_register, W83627THFState),
> +        VMSTATE_UINT8(pled_mode_register, W83627THFState),
> +        VMSTATE_UINT8(timeout_register, W83627THFState),
> +        VMSTATE_UINT8(timer_register, W83627THFState),
> +        VMSTATE_END_OF_LIST()
> +    }
> +};
> +
> +/* This function is called when the watchdog has been changed, either when 
> the
> + * timer has expired or has been keep-alived.
> + */
> +static void wdt_w83627thf_restart_timer(W83627THFState *state)
> +{
> +    uint64_t timeout = 1000;
> +
> +    if (state->timeout_register == 0) {
> +        timer_del(state->timer);
> +        return;
> +    }
> +
> +    if (state->pled_mode_register & PLED_MINUTE_MODE) {
> +        timeout = 60000;
> +    }
> +
> +    timer_mod(state->timer, qemu_clock_get_ms(QEMU_CLOCK_VIRTUAL) + timeout);
> +}
> +
> +/* This function is called when the timer has expired. Will count down the
> + * counter and possibly fire the watchdog.
> + */
> +static void wdt_w83627thf_timer_tick(void *vp)
> +{
> +    W83627THFState *state = vp;
> +
> +    state->timeout_register--;
> +    if (state->timeout_register == 0) {
> +        state->timer_register |= 0x10;
> +        timer_del(state->timer);
> +        watchdog_perform_action();
> +        return;
> +    }
> +
> +    wdt_w83627thf_restart_timer(state);
> +}
> +
> +/* This function is called when writing to the Extended Function Enable
> + * Registers.
> + */
> +static void wdt_w83627thf_write_efer(void *vp, uint32_t addr, uint32_t data)
> +{
> +    W83627THFState *state = vp;
> +
> +    w83627thf_debug("data = %x\n", data);
> +
> +    if (data == 0x87) {
> +        if (state->running_mode == normal_mode) {
> +            state->running_mode = extended_mode1;
> +        } else {
> +            state->running_mode = extended_mode2;
> +        }
> +    } else if (data == 0xAA) {
> +        state->running_mode = normal_mode;
> +    } else if (state->running_mode == extended_mode2) {
> +        state->selected_register = data;
> +    }
> +}
> +
> +/* This function is called when reading from the Extended Function Data
> + * Register.
> + */
> +static uint32_t wdt_w83627thf_read_efdr(void *vp, uint32_t addr)
> +{
> +    uint8_t data = 0;
> +    const W83627THFState *state = vp;
> +
> +    switch (state->selected_register) {
> +    case CHIP_VERSION_REGISTER:
> +        data = CHIP_VERSION;
> +        break;
> +    case PLED_MODE_REGISTER:
> +        data = state->pled_mode_register;
> +        break;
> +    case TIMEOUT_REGISTER:
> +        data = state->timeout_register;
> +        break;
> +    case TIMER_REGISTER:
> +        data = state->timer_register;
> +        break;
> +    }
> +
> +    w83627thf_debug("reg = %x, data = %x\n", state->selected_register, data);
> +
> +    return data;
> +}
> +
> +/* This function is called when writing to the Extended Function Data 
> Register.
> + */
> +static void wdt_w83627thf_write_efdr(void *vp, uint32_t addr, uint32_t data)
> +{
> +    W83627THFState *state = vp;
> +
> +    w83627thf_debug("reg = %x, data = %x\n", state->selected_register, data);
> +
> +    switch (state->selected_register) {
> +    case PLED_MODE_REGISTER:
> +        state->pled_mode_register = data;
> +        break;
> +    case TIMEOUT_REGISTER:
> +        state->timeout_register = data;
> +        wdt_w83627thf_restart_timer(state);
> +        break;
> +    case TIMER_REGISTER:
> +        if (data & 0x20) {
> +            timer_del(state->timer);
> +            watchdog_perform_action();
> +        }
> +        state->timer_register = (data & ~0x20);
> +        break;
> +    }
> +}
> +
> +static const MemoryRegionPortio wdt_portio_list[] = {
> +    { WDT_W83627THF_EFER, 1, 1, .write = wdt_w83627thf_write_efer, },
> +    { WDT_W83627THF_EFDR, 1, 1, .read  = wdt_w83627thf_read_efdr,
> +                                .write = wdt_w83627thf_write_efdr },
> +    PORTIO_END_OF_LIST(),
> +};
> +
> +static void wdt_w83627thf_realize(DeviceState *dev, Error **errp)
> +{
> +    W83627THFState *d = WATCHDOG_W83627THF_DEVICE(dev);
> +
> +    d->timer = timer_new_ms(QEMU_CLOCK_VIRTUAL, wdt_w83627thf_timer_tick, d);
> +
> +    portio_list_init(&d->port_list, OBJECT(d), wdt_portio_list, d, 
> "w83627thf");
> +    portio_list_add(&d->port_list, isa_address_space_io(&d->parent_obj), 0);
> +}
> +
> +static void wdt_w83627thf_reset(DeviceState *dev)
> +{
> +    W83627THFState *d = WATCHDOG_W83627THF_DEVICE(dev);
> +
> +    timer_del(d->timer);
> +}
> +
> +static void wdt_w83627thf_class_init(ObjectClass *klass, void *data)
> +{
> +    DeviceClass *dc = DEVICE_CLASS(klass);
> +
> +    dc->realize = wdt_w83627thf_realize;
> +    dc->reset = wdt_w83627thf_reset;
> +    dc->vmsd = &vmstate_w83627thf;
> +    set_bit(DEVICE_CATEGORY_MISC, dc->categories);
> +}
> +
> +static const TypeInfo w83627thf_info = {
> +    .name          = "w83627thf",
> +    .parent        = TYPE_ISA_DEVICE,
> +    .instance_size = sizeof(W83627THFState),
> +    .class_init    = wdt_w83627thf_class_init,
> +};
> +
> +static void w83627thf_register_types(void)
> +{
> +    watchdog_add_model(&model);
> +    type_register_static(&w83627thf_info);
> +}
> +
> +type_init(w83627thf_register_types)

Best regards,
Daniel Fahlgren




reply via email to

[Prev in Thread] Current Thread [Next in Thread]