]> Git Repo - qemu.git/blob - hw/acpi_ich9.c
apci: switch evt to memory api
[qemu.git] / hw / acpi_ich9.c
1 /*
2  * ACPI implementation
3  *
4  * Copyright (c) 2006 Fabrice Bellard
5  *
6  * This library is free software; you can redistribute it and/or
7  * modify it under the terms of the GNU Lesser General Public
8  * License version 2 as published by the Free Software Foundation.
9  *
10  * This library is distributed in the hope that it will be useful,
11  * but WITHOUT ANY WARRANTY; without even the implied warranty of
12  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
13  * Lesser General Public License for more details.
14  *
15  * You should have received a copy of the GNU Lesser General Public
16  * License along with this library; if not, see <http://www.gnu.org/licenses/>
17  */
18 /*
19  *  Copyright (c) 2009 Isaku Yamahata <yamahata at valinux co jp>
20  *                     VA Linux Systems Japan K.K.
21  *  Copyright (C) 2012 Jason Baron <[email protected]>
22  *
23  *  This is based on acpi.c.
24  */
25 #include "hw.h"
26 #include "pc.h"
27 #include "pci.h"
28 #include "qemu-timer.h"
29 #include "sysemu.h"
30 #include "acpi.h"
31 #include "kvm.h"
32 #include "exec-memory.h"
33
34 #include "ich9.h"
35
36 //#define DEBUG
37
38 #ifdef DEBUG
39 #define ICH9_DEBUG(fmt, ...) \
40 do { printf("%s "fmt, __func__, ## __VA_ARGS__); } while (0)
41 #else
42 #define ICH9_DEBUG(fmt, ...)    do { } while (0)
43 #endif
44
45 static void pm_ioport_write_fallback(void *opaque, uint32_t addr, int len,
46                                      uint32_t val);
47 static uint32_t pm_ioport_read_fallback(void *opaque, uint32_t addr, int len);
48
49 static void pm_update_sci(ICH9LPCPMRegs *pm)
50 {
51     int sci_level, pm1a_sts;
52
53     pm1a_sts = acpi_pm1_evt_get_sts(&pm->acpi_regs);
54
55     sci_level = (((pm1a_sts & pm->acpi_regs.pm1.evt.en) &
56                   (ACPI_BITMASK_RT_CLOCK_ENABLE |
57                    ACPI_BITMASK_POWER_BUTTON_ENABLE |
58                    ACPI_BITMASK_GLOBAL_LOCK_ENABLE |
59                    ACPI_BITMASK_TIMER_ENABLE)) != 0);
60     qemu_set_irq(pm->irq, sci_level);
61
62     /* schedule a timer interruption if needed */
63     acpi_pm_tmr_update(&pm->acpi_regs,
64                        (pm->acpi_regs.pm1.evt.en & ACPI_BITMASK_TIMER_ENABLE) &&
65                        !(pm1a_sts & ACPI_BITMASK_TIMER_STATUS));
66 }
67
68 static void ich9_pm_update_sci_fn(ACPIREGS *regs)
69 {
70     ICH9LPCPMRegs *pm = container_of(regs, ICH9LPCPMRegs, acpi_regs);
71     pm_update_sci(pm);
72 }
73
74 static void pm_ioport_writeb(void *opaque, uint32_t addr, uint32_t val)
75 {
76     ICH9LPCPMRegs *pm = opaque;
77
78     switch (addr & ICH9_PMIO_MASK) {
79     case ICH9_PMIO_GPE0_STS ... (ICH9_PMIO_GPE0_STS + ICH9_PMIO_GPE0_LEN - 1):
80         acpi_gpe_ioport_writeb(&pm->acpi_regs, addr, val);
81         break;
82     default:
83         break;
84     }
85
86     ICH9_DEBUG("port=0x%04x val=0x%04x\n", addr, val);
87 }
88
89 static uint32_t pm_ioport_readb(void *opaque, uint32_t addr)
90 {
91     ICH9LPCPMRegs *pm = opaque;
92     uint32_t val = 0;
93
94     switch (addr & ICH9_PMIO_MASK) {
95     case ICH9_PMIO_GPE0_STS ... (ICH9_PMIO_GPE0_STS + ICH9_PMIO_GPE0_LEN - 1):
96         val = acpi_gpe_ioport_readb(&pm->acpi_regs, addr);
97         break;
98     default:
99         val = 0;
100         break;
101     }
102     ICH9_DEBUG("port=0x%04x val=0x%04x\n", addr, val);
103     return val;
104 }
105
106 static void pm_ioport_writew(void *opaque, uint32_t addr, uint32_t val)
107 {
108     switch (addr & ICH9_PMIO_MASK) {
109     default:
110         pm_ioport_write_fallback(opaque, addr, 2, val);
111         break;
112     }
113     ICH9_DEBUG("port=0x%04x val=0x%04x\n", addr, val);
114 }
115
116 static uint32_t pm_ioport_readw(void *opaque, uint32_t addr)
117 {
118     uint32_t val;
119
120     switch (addr & ICH9_PMIO_MASK) {
121     default:
122         val = pm_ioport_read_fallback(opaque, addr, 2);
123         break;
124     }
125     ICH9_DEBUG("port=0x%04x val=0x%04x\n", addr, val);
126     return val;
127 }
128
129 static void pm_ioport_writel(void *opaque, uint32_t addr, uint32_t val)
130 {
131     ICH9LPCPMRegs *pm = opaque;
132
133     switch (addr & ICH9_PMIO_MASK) {
134     case ICH9_PMIO_SMI_EN:
135         pm->smi_en = val;
136         break;
137     default:
138         pm_ioport_write_fallback(opaque, addr, 4, val);
139         break;
140     }
141     ICH9_DEBUG("port=0x%04x val=0x%08x\n", addr, val);
142 }
143
144 static uint32_t pm_ioport_readl(void *opaque, uint32_t addr)
145 {
146     ICH9LPCPMRegs *pm = opaque;
147     uint32_t val;
148
149     switch (addr & ICH9_PMIO_MASK) {
150     case ICH9_PMIO_SMI_EN:
151         val = pm->smi_en;
152         break;
153
154     default:
155         val = pm_ioport_read_fallback(opaque, addr, 4);
156         break;
157     }
158     ICH9_DEBUG("port=0x%04x val=0x%08x\n", addr, val);
159     return val;
160 }
161
162 static void pm_ioport_write_fallback(void *opaque, uint32_t addr, int len,
163                                      uint32_t val)
164  {
165     int subsize = (len == 4) ? 2 : 1;
166     IOPortWriteFunc *ioport_write =
167         (subsize == 2) ? pm_ioport_writew : pm_ioport_writeb;
168
169     int i;
170
171     for (i = 0; i < len; i += subsize) {
172         ioport_write(opaque, addr, val);
173         val >>= 8 * subsize;
174     }
175 }
176
177 static uint32_t pm_ioport_read_fallback(void *opaque, uint32_t addr, int len)
178 {
179     int subsize = (len == 4) ? 2 : 1;
180     IOPortReadFunc *ioport_read =
181         (subsize == 2) ? pm_ioport_readw : pm_ioport_readb;
182
183     uint32_t val;
184     int i;
185
186     val = 0;
187     for (i = 0; i < len; i += subsize) {
188         val <<= 8 * subsize;
189         val |= ioport_read(opaque, addr);
190     }
191
192     return val;
193 }
194
195 static const MemoryRegionOps pm_io_ops = {
196     .old_portio = (MemoryRegionPortio[]) {
197         { .offset = 0, .len = ICH9_PMIO_SIZE, .size = 1,
198           .read = pm_ioport_readb, .write = pm_ioport_writeb },
199         { .offset = 0, .len = ICH9_PMIO_SIZE, .size = 2,
200           .read = pm_ioport_readw, .write = pm_ioport_writew },
201         { .offset = 0, .len = ICH9_PMIO_SIZE, .size = 4,
202           .read = pm_ioport_readl, .write = pm_ioport_writel },
203         PORTIO_END_OF_LIST(),
204     },
205     .valid.min_access_size = 1,
206     .valid.max_access_size = 4,
207     .impl.min_access_size = 1,
208     .impl.max_access_size = 4,
209     .endianness = DEVICE_LITTLE_ENDIAN,
210 };
211
212 void ich9_pm_iospace_update(ICH9LPCPMRegs *pm, uint32_t pm_io_base)
213 {
214     ICH9_DEBUG("to 0x%x\n", pm_io_base);
215
216     assert((pm_io_base & ICH9_PMIO_MASK) == 0);
217
218     pm->pm_io_base = pm_io_base;
219     memory_region_transaction_begin();
220     memory_region_set_enabled(&pm->io, pm->pm_io_base != 0);
221     memory_region_set_address(&pm->io, pm->pm_io_base);
222     memory_region_transaction_commit();
223 }
224
225 static int ich9_pm_post_load(void *opaque, int version_id)
226 {
227     ICH9LPCPMRegs *pm = opaque;
228     uint32_t pm_io_base = pm->pm_io_base;
229     pm->pm_io_base = 0;
230     ich9_pm_iospace_update(pm, pm_io_base);
231     return 0;
232 }
233
234 #define VMSTATE_GPE_ARRAY(_field, _state)                            \
235  {                                                                   \
236      .name       = (stringify(_field)),                              \
237      .version_id = 0,                                                \
238      .num        = ICH9_PMIO_GPE0_LEN,                               \
239      .info       = &vmstate_info_uint8,                              \
240      .size       = sizeof(uint8_t),                                  \
241      .flags      = VMS_ARRAY | VMS_POINTER,                          \
242      .offset     = vmstate_offset_pointer(_state, _field, uint8_t),  \
243  }
244
245 const VMStateDescription vmstate_ich9_pm = {
246     .name = "ich9_pm",
247     .version_id = 1,
248     .minimum_version_id = 1,
249     .minimum_version_id_old = 1,
250     .post_load = ich9_pm_post_load,
251     .fields = (VMStateField[]) {
252         VMSTATE_UINT16(acpi_regs.pm1.evt.sts, ICH9LPCPMRegs),
253         VMSTATE_UINT16(acpi_regs.pm1.evt.en, ICH9LPCPMRegs),
254         VMSTATE_UINT16(acpi_regs.pm1.cnt.cnt, ICH9LPCPMRegs),
255         VMSTATE_TIMER(acpi_regs.tmr.timer, ICH9LPCPMRegs),
256         VMSTATE_INT64(acpi_regs.tmr.overflow_time, ICH9LPCPMRegs),
257         VMSTATE_GPE_ARRAY(acpi_regs.gpe.sts, ICH9LPCPMRegs),
258         VMSTATE_GPE_ARRAY(acpi_regs.gpe.en, ICH9LPCPMRegs),
259         VMSTATE_UINT32(smi_en, ICH9LPCPMRegs),
260         VMSTATE_UINT32(smi_sts, ICH9LPCPMRegs),
261         VMSTATE_END_OF_LIST()
262     }
263 };
264
265 static void pm_reset(void *opaque)
266 {
267     ICH9LPCPMRegs *pm = opaque;
268     ich9_pm_iospace_update(pm, 0);
269
270     acpi_pm1_evt_reset(&pm->acpi_regs);
271     acpi_pm1_cnt_reset(&pm->acpi_regs);
272     acpi_pm_tmr_reset(&pm->acpi_regs);
273     acpi_gpe_reset(&pm->acpi_regs);
274
275     if (kvm_enabled()) {
276         /* Mark SMM as already inited to prevent SMM from running. KVM does not
277          * support SMM mode. */
278         pm->smi_en |= ICH9_PMIO_SMI_EN_APMC_EN;
279     }
280
281     pm_update_sci(pm);
282 }
283
284 static void pm_powerdown_req(Notifier *n, void *opaque)
285 {
286     ICH9LPCPMRegs *pm = container_of(n, ICH9LPCPMRegs, powerdown_notifier);
287
288     acpi_pm1_evt_power_down(&pm->acpi_regs);
289 }
290
291 void ich9_pm_init(ICH9LPCPMRegs *pm, qemu_irq sci_irq, qemu_irq cmos_s3)
292 {
293     memory_region_init_io(&pm->io, &pm_io_ops, pm, "ich9-pm", ICH9_PMIO_SIZE);
294     memory_region_set_enabled(&pm->io, false);
295     memory_region_add_subregion(get_system_io(), 0, &pm->io);
296
297     acpi_pm_tmr_init(&pm->acpi_regs, ich9_pm_update_sci_fn, &pm->io);
298     acpi_pm1_evt_init(&pm->acpi_regs, ich9_pm_update_sci_fn, &pm->io);
299     acpi_pm1_cnt_init(&pm->acpi_regs, &pm->io);
300     acpi_gpe_init(&pm->acpi_regs, ICH9_PMIO_GPE0_LEN);
301     acpi_gpe_blk(&pm->acpi_regs, ICH9_PMIO_GPE0_STS);
302
303     pm->irq = sci_irq;
304     qemu_register_reset(pm_reset, pm);
305     pm->powerdown_notifier.notify = pm_powerdown_req;
306     qemu_register_powerdown_notifier(&pm->powerdown_notifier);
307 }
This page took 0.041708 seconds and 4 git commands to generate.