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: Paolo Bonzini
Subject: Re: [Qemu-devel] [PATCH] watchdog: add support to emulate winbond w83627thf
Date: Wed, 7 Oct 2015 11:09:29 +0200
User-agent: Mozilla/5.0 (X11; Linux x86_64; rv:38.0) Gecko/20100101 Thunderbird/38.3.0


On 07/10/2015 10:49, Daniel Fahlgren wrote:
> 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.

Hi,

sorry for missing this patch.

I have a couple of questions.  First, where can I find a spec for this
chip in order to review the code, and what are the other features?
Second, what are the advantages over the existing watchdog devices?

Paolo

>> 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]