qemu

Форк
0
/
ich9_tco.c 
275 строк · 7.6 Кб
1
/*
2
 * QEMU ICH9 TCO emulation
3
 *
4
 * Copyright (c) 2015 Paulo Alcantara <pcacjr@zytor.com>
5
 *
6
 * This work is licensed under the terms of the GNU GPL, version 2 or later.
7
 * See the COPYING file in the top-level directory.
8
 */
9

10
#include "qemu/osdep.h"
11
#include "sysemu/watchdog.h"
12
#include "hw/southbridge/ich9.h"
13
#include "migration/vmstate.h"
14

15
#include "hw/acpi/ich9_tco.h"
16
#include "trace.h"
17

18
enum {
19
    TCO_RLD_DEFAULT         = 0x0000,
20
    TCO_DAT_IN_DEFAULT      = 0x00,
21
    TCO_DAT_OUT_DEFAULT     = 0x00,
22
    TCO1_STS_DEFAULT        = 0x0000,
23
    TCO2_STS_DEFAULT        = 0x0000,
24
    TCO1_CNT_DEFAULT        = 0x0000,
25
    TCO2_CNT_DEFAULT        = 0x0008,
26
    TCO_MESSAGE1_DEFAULT    = 0x00,
27
    TCO_MESSAGE2_DEFAULT    = 0x00,
28
    TCO_WDCNT_DEFAULT       = 0x00,
29
    TCO_TMR_DEFAULT         = 0x0004,
30
    SW_IRQ_GEN_DEFAULT      = 0x03,
31
};
32

33
static inline void tco_timer_reload(TCOIORegs *tr)
34
{
35
    int ticks = tr->tco.tmr & TCO_TMR_MASK;
36
    int64_t nsec = (int64_t)ticks * TCO_TICK_NSEC;
37

38
    trace_tco_timer_reload(ticks, nsec / 1000000);
39
    tr->expire_time = qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL) + nsec;
40
    timer_mod(tr->tco_timer, tr->expire_time);
41
}
42

43
static inline void tco_timer_stop(TCOIORegs *tr)
44
{
45
    tr->expire_time = -1;
46
    timer_del(tr->tco_timer);
47
}
48

49
static void tco_timer_expired(void *opaque)
50
{
51
    TCOIORegs *tr = opaque;
52
    ICH9LPCPMRegs *pm = container_of(tr, ICH9LPCPMRegs, tco_regs);
53
    ICH9LPCState *lpc = container_of(pm, ICH9LPCState, pm);
54
    uint32_t gcs = pci_get_long(lpc->chip_config + ICH9_CC_GCS);
55

56
    trace_tco_timer_expired(tr->timeouts_no,
57
                            lpc->pin_strap.spkr_hi,
58
                            !!(gcs & ICH9_CC_GCS_NO_REBOOT));
59
    tr->tco.rld = 0;
60
    tr->tco.sts1 |= TCO_TIMEOUT;
61
    if (++tr->timeouts_no == 2) {
62
        tr->tco.sts2 |= TCO_SECOND_TO_STS;
63
        tr->tco.sts2 |= TCO_BOOT_STS;
64
        tr->timeouts_no = 0;
65

66
        if (!lpc->pin_strap.spkr_hi && !(gcs & ICH9_CC_GCS_NO_REBOOT)) {
67
            watchdog_perform_action();
68
            tco_timer_stop(tr);
69
            return;
70
        }
71
    }
72

73
    if (pm->smi_en & ICH9_PMIO_SMI_EN_TCO_EN) {
74
        ich9_generate_smi();
75
    }
76
    tr->tco.rld = tr->tco.tmr;
77
    tco_timer_reload(tr);
78
}
79

80
/* NOTE: values of 0 or 1 will be ignored by ICH */
81
static inline int can_start_tco_timer(TCOIORegs *tr)
82
{
83
    return !(tr->tco.cnt1 & TCO_TMR_HLT) && tr->tco.tmr > 1;
84
}
85

86
static uint32_t tco_ioport_readw(TCOIORegs *tr, uint32_t addr)
87
{
88
    uint16_t rld;
89
    uint32_t ret = 0;
90

91
    switch (addr) {
92
    case TCO_RLD:
93
        if (tr->expire_time != -1) {
94
            int64_t now = qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL);
95
            int64_t elapsed = (tr->expire_time - now) / TCO_TICK_NSEC;
96
            rld = (uint16_t)elapsed | (tr->tco.rld & ~TCO_RLD_MASK);
97
        } else {
98
            rld = tr->tco.rld;
99
        }
100
        ret = rld;
101
        break;
102
    case TCO_DAT_IN:
103
        ret = tr->tco.din;
104
        break;
105
    case TCO_DAT_OUT:
106
        ret = tr->tco.dout;
107
        break;
108
    case TCO1_STS:
109
        ret = tr->tco.sts1;
110
        break;
111
    case TCO2_STS:
112
        ret = tr->tco.sts2;
113
        break;
114
    case TCO1_CNT:
115
        ret = tr->tco.cnt1;
116
        break;
117
    case TCO2_CNT:
118
        ret = tr->tco.cnt2;
119
        break;
120
    case TCO_MESSAGE1:
121
        ret = tr->tco.msg1;
122
        break;
123
    case TCO_MESSAGE2:
124
        ret = tr->tco.msg2;
125
        break;
126
    case TCO_WDCNT:
127
        ret = tr->tco.wdcnt;
128
        break;
129
    case TCO_TMR:
130
        ret = tr->tco.tmr;
131
        break;
132
    case SW_IRQ_GEN:
133
        ret = tr->sw_irq_gen;
134
        break;
135
    }
136
    trace_tco_io_read(addr, ret);
137
    return ret;
138
}
139

140
static void tco_ioport_writew(TCOIORegs *tr, uint32_t addr, uint32_t val)
141
{
142
    trace_tco_io_write(addr, val);
143
    switch (addr) {
144
    case TCO_RLD:
145
        tr->timeouts_no = 0;
146
        if (can_start_tco_timer(tr)) {
147
            tr->tco.rld = tr->tco.tmr;
148
            tco_timer_reload(tr);
149
        } else {
150
            tr->tco.rld = val;
151
        }
152
        break;
153
    case TCO_DAT_IN:
154
        tr->tco.din = val;
155
        tr->tco.sts1 |= SW_TCO_SMI;
156
        ich9_generate_smi();
157
        break;
158
    case TCO_DAT_OUT:
159
        tr->tco.dout = val;
160
        tr->tco.sts1 |= TCO_INT_STS;
161
        /* TODO: cause an interrupt, as selected by the TCO_INT_SEL bits */
162
        break;
163
    case TCO1_STS:
164
        tr->tco.sts1 = val & TCO1_STS_MASK;
165
        break;
166
    case TCO2_STS:
167
        tr->tco.sts2 = val & TCO2_STS_MASK;
168
        break;
169
    case TCO1_CNT:
170
        val &= TCO1_CNT_MASK;
171
        /*
172
         * once TCO_LOCK bit is set, it can not be cleared by software. a reset
173
         * is required to change this bit from 1 to 0 -- it defaults to 0.
174
         */
175
        tr->tco.cnt1 = val | (tr->tco.cnt1 & TCO_LOCK);
176
        if (can_start_tco_timer(tr)) {
177
            tr->tco.rld = tr->tco.tmr;
178
            tco_timer_reload(tr);
179
        } else {
180
            tco_timer_stop(tr);
181
        }
182
        break;
183
    case TCO2_CNT:
184
        tr->tco.cnt2 = val;
185
        break;
186
    case TCO_MESSAGE1:
187
        tr->tco.msg1 = val;
188
        break;
189
    case TCO_MESSAGE2:
190
        tr->tco.msg2 = val;
191
        break;
192
    case TCO_WDCNT:
193
        tr->tco.wdcnt = val;
194
        break;
195
    case TCO_TMR:
196
        tr->tco.tmr = val;
197
        break;
198
    case SW_IRQ_GEN:
199
        tr->sw_irq_gen = val;
200
        break;
201
    }
202
}
203

204
static uint64_t tco_io_readw(void *opaque, hwaddr addr, unsigned width)
205
{
206
    TCOIORegs *tr = opaque;
207
    return tco_ioport_readw(tr, addr);
208
}
209

210
static void tco_io_writew(void *opaque, hwaddr addr, uint64_t val,
211
                          unsigned width)
212
{
213
    TCOIORegs *tr = opaque;
214
    tco_ioport_writew(tr, addr, val);
215
}
216

217
static const MemoryRegionOps tco_io_ops = {
218
    .read = tco_io_readw,
219
    .write = tco_io_writew,
220
    .valid.min_access_size = 1,
221
    .valid.max_access_size = 4,
222
    .impl.min_access_size = 1,
223
    .impl.max_access_size = 2,
224
    .endianness = DEVICE_LITTLE_ENDIAN,
225
};
226

227
void acpi_pm_tco_init(TCOIORegs *tr, MemoryRegion *parent)
228
{
229
    *tr = (TCOIORegs) {
230
        .tco = {
231
            .rld      = TCO_RLD_DEFAULT,
232
            .din      = TCO_DAT_IN_DEFAULT,
233
            .dout     = TCO_DAT_OUT_DEFAULT,
234
            .sts1     = TCO1_STS_DEFAULT,
235
            .sts2     = TCO2_STS_DEFAULT,
236
            .cnt1     = TCO1_CNT_DEFAULT,
237
            .cnt2     = TCO2_CNT_DEFAULT,
238
            .msg1     = TCO_MESSAGE1_DEFAULT,
239
            .msg2     = TCO_MESSAGE2_DEFAULT,
240
            .wdcnt    = TCO_WDCNT_DEFAULT,
241
            .tmr      = TCO_TMR_DEFAULT,
242
        },
243
        .sw_irq_gen    = SW_IRQ_GEN_DEFAULT,
244
        .tco_timer     = timer_new_ns(QEMU_CLOCK_VIRTUAL, tco_timer_expired, tr),
245
        .expire_time   = -1,
246
        .timeouts_no   = 0,
247
    };
248
    memory_region_init_io(&tr->io, memory_region_owner(parent),
249
                          &tco_io_ops, tr, "sm-tco", ICH9_PMIO_TCO_LEN);
250
    memory_region_add_subregion(parent, ICH9_PMIO_TCO_RLD, &tr->io);
251
}
252

253
const VMStateDescription vmstate_tco_io_sts = {
254
    .name = "tco io device status",
255
    .version_id = 1,
256
    .minimum_version_id = 1,
257
    .fields = (const VMStateField[]) {
258
        VMSTATE_UINT16(tco.rld, TCOIORegs),
259
        VMSTATE_UINT8(tco.din, TCOIORegs),
260
        VMSTATE_UINT8(tco.dout, TCOIORegs),
261
        VMSTATE_UINT16(tco.sts1, TCOIORegs),
262
        VMSTATE_UINT16(tco.sts2, TCOIORegs),
263
        VMSTATE_UINT16(tco.cnt1, TCOIORegs),
264
        VMSTATE_UINT16(tco.cnt2, TCOIORegs),
265
        VMSTATE_UINT8(tco.msg1, TCOIORegs),
266
        VMSTATE_UINT8(tco.msg2, TCOIORegs),
267
        VMSTATE_UINT8(tco.wdcnt, TCOIORegs),
268
        VMSTATE_UINT16(tco.tmr, TCOIORegs),
269
        VMSTATE_UINT8(sw_irq_gen, TCOIORegs),
270
        VMSTATE_TIMER_PTR(tco_timer, TCOIORegs),
271
        VMSTATE_INT64(expire_time, TCOIORegs),
272
        VMSTATE_UINT8(timeouts_no, TCOIORegs),
273
        VMSTATE_END_OF_LIST()
274
    }
275
};
276

Использование cookies

Мы используем файлы cookie в соответствии с Политикой конфиденциальности и Политикой использования cookies.

Нажимая кнопку «Принимаю», Вы даете АО «СберТех» согласие на обработку Ваших персональных данных в целях совершенствования нашего веб-сайта и Сервиса GitVerse, а также повышения удобства их использования.

Запретить использование cookies Вы можете самостоятельно в настройках Вашего браузера.