master
c 522 lines 18.4 KB
Raw
1 /*
2 * ACPI implementation
3 *
4 * Copyright (c) 2006 Fabrice Bellard
5 * Copyright (c) 2009 Isaku Yamahata <yamahata at valinux co jp>
6 * VA Linux Systems Japan K.K.
7 * Copyright (C) 2012 Jason Baron <jbaron@redhat.com>
8 *
9 * This is based on acpi.c.
10 *
11 * This library is free software; you can redistribute it and/or
12 * modify it under the terms of the GNU Lesser General Public
13 * License version 2.1 as published by the Free Software Foundation.
14 *
15 * This library is distributed in the hope that it will be useful,
16 * but WITHOUT ANY WARRANTY; without even the implied warranty of
17 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
18 * Lesser General Public License for more details.
19 *
20 * You should have received a copy of the GNU Lesser General Public
21 * License along with this library; if not, see <http://www.gnu.org/licenses/>
22 *
23 * Contributions after 2012-01-13 are licensed under the terms of the
24 * GNU GPL, version 2 or (at your option) any later version.
25 */
26
27 #include "qemu/osdep.h"
28 #include "qapi/error.h"
29 #include "qapi/visitor.h"
30 #include "hw/pci/pci.h"
31 #include "migration/vmstate.h"
32 #include "qemu/timer.h"
33 #include "hw/core/cpu.h"
34 #include "system/reset.h"
35 #include "system/runstate.h"
36 #include "hw/acpi/acpi.h"
37 #include "hw/acpi/ich9_tco.h"
38 #include "hw/acpi/ich9_timer.h"
39
40 #include "hw/southbridge/ich9.h"
41 #include "hw/mem/pc-dimm.h"
42 #include "hw/mem/nvdimm.h"
43 #include "hw/acpi/pc-hotplug.h"
44
45 static void ich9_pm_update_sci_fn(ACPIREGS *regs)
46 {
47 ICH9LPCPMRegs *pm = container_of(regs, ICH9LPCPMRegs, acpi_regs);
48 acpi_update_sci(&pm->acpi_regs, pm->irq);
49 }
50
51 static uint64_t ich9_gpe_readb(void *opaque, hwaddr addr, unsigned width)
52 {
53 ICH9LPCPMRegs *pm = opaque;
54 return acpi_gpe_ioport_readb(&pm->acpi_regs, addr);
55 }
56
57 static void ich9_gpe_writeb(void *opaque, hwaddr addr, uint64_t val,
58 unsigned width)
59 {
60 ICH9LPCPMRegs *pm = opaque;
61 acpi_gpe_ioport_writeb(&pm->acpi_regs, addr, val);
62 acpi_update_sci(&pm->acpi_regs, pm->irq);
63 }
64
65 static const MemoryRegionOps ich9_gpe_ops = {
66 .read = ich9_gpe_readb,
67 .write = ich9_gpe_writeb,
68 .valid.min_access_size = 1,
69 .valid.max_access_size = 4,
70 .impl.min_access_size = 1,
71 .impl.max_access_size = 1,
72 .endianness = DEVICE_LITTLE_ENDIAN,
73 };
74
75 static uint64_t ich9_smi_readl(void *opaque, hwaddr addr, unsigned width)
76 {
77 ICH9LPCPMRegs *pm = opaque;
78 switch (addr) {
79 case 0:
80 return pm->smi_en;
81 case 4:
82 return pm->smi_sts;
83 default:
84 return 0;
85 }
86 }
87
88 static void ich9_smi_writel(void *opaque, hwaddr addr, uint64_t val,
89 unsigned width)
90 {
91 ICH9LPCPMRegs *pm = opaque;
92 TCOIORegs *tr = &pm->tco_regs;
93 uint64_t tco_en;
94
95 switch (addr) {
96 case 0:
97 tco_en = pm->smi_en & ICH9_PMIO_SMI_EN_TCO_EN;
98 /* once TCO_LOCK bit is set, TCO_EN bit cannot be overwritten */
99 if (tr->tco.cnt1 & TCO_LOCK) {
100 val = (val & ~ICH9_PMIO_SMI_EN_TCO_EN) | tco_en;
101 }
102 pm->smi_en &= ~pm->smi_en_wmask;
103 pm->smi_en |= (val & pm->smi_en_wmask);
104 if (pm->swsmi_timer_enabled) {
105 ich9_pm_update_swsmi_timer(pm, pm->smi_en &
106 ICH9_PMIO_SMI_EN_SWSMI_EN);
107 }
108 if (pm->periodic_timer_enabled) {
109 ich9_pm_update_periodic_timer(pm, pm->smi_en &
110 ICH9_PMIO_SMI_EN_PERIODIC_EN);
111 }
112 break;
113 case 4:
114 pm->smi_sts &= ~pm->smi_sts_wmask;
115 pm->smi_sts |= (val & pm->smi_sts_wmask);
116 break;
117 }
118 }
119
120 static const MemoryRegionOps ich9_smi_ops = {
121 .read = ich9_smi_readl,
122 .write = ich9_smi_writel,
123 .valid.min_access_size = 4,
124 .valid.max_access_size = 4,
125 .endianness = DEVICE_LITTLE_ENDIAN,
126 };
127
128 void ich9_pm_iospace_update(ICH9LPCPMRegs *pm, uint32_t pm_io_base)
129 {
130 assert((pm_io_base & ICH9_PMIO_MASK) == 0);
131
132 pm->pm_io_base = pm_io_base;
133 memory_region_transaction_begin();
134 memory_region_set_enabled(&pm->io, pm->pm_io_base != 0);
135 memory_region_set_address(&pm->io, pm->pm_io_base);
136 memory_region_transaction_commit();
137 }
138
139 static int ich9_pm_post_load(void *opaque, int version_id)
140 {
141 ICH9LPCPMRegs *pm = opaque;
142 uint32_t pm_io_base = pm->pm_io_base;
143 pm->pm_io_base = 0;
144 ich9_pm_iospace_update(pm, pm_io_base);
145 return 0;
146 }
147
148 #define VMSTATE_GPE_ARRAY(_field, _state) \
149 { \
150 .name = (stringify(_field)), \
151 .version_id = 0, \
152 .num = ICH9_PMIO_GPE0_LEN, \
153 .info = &vmstate_info_uint8, \
154 .size = sizeof(uint8_t), \
155 .flags = VMS_ARRAY | VMS_POINTER, \
156 .offset = vmstate_offset_pointer(_state, _field, uint8_t), \
157 }
158
159 static const VMStateDescription vmstate_memhp_state = {
160 .name = "ich9_pm/memhp",
161 .version_id = 1,
162 .minimum_version_id = 1,
163 .fields = (const VMStateField[]) {
164 VMSTATE_MEMORY_HOTPLUG(acpi_memory_hotplug, ICH9LPCPMRegs),
165 VMSTATE_END_OF_LIST()
166 }
167 };
168
169 static bool vmstate_test_use_tco(void *opaque)
170 {
171 ICH9LPCPMRegs *s = opaque;
172 return s->enable_tco;
173 }
174
175 static const VMStateDescription vmstate_tco_io_state = {
176 .name = "ich9_pm/tco",
177 .version_id = 1,
178 .minimum_version_id = 1,
179 .needed = vmstate_test_use_tco,
180 .fields = (const VMStateField[]) {
181 VMSTATE_STRUCT(tco_regs, ICH9LPCPMRegs, 1, vmstate_tco_io_sts,
182 TCOIORegs),
183 VMSTATE_END_OF_LIST()
184 }
185 };
186
187 static bool cpuhp_needed(void *opaque)
188 {
189 MachineClass *mc = MACHINE_GET_CLASS(qdev_get_machine());
190
191 return mc->has_hotpluggable_cpus;
192 }
193
194 static const VMStateDescription vmstate_cpuhp_state = {
195 .name = "ich9_pm/cpuhp",
196 .version_id = 1,
197 .minimum_version_id = 1,
198 .needed = cpuhp_needed,
199 .fields = (const VMStateField[]) {
200 VMSTATE_CPU_HOTPLUG(cpuhp_state, ICH9LPCPMRegs),
201 VMSTATE_END_OF_LIST()
202 }
203 };
204
205 static bool vmstate_test_use_pcihp(void *opaque)
206 {
207 ICH9LPCPMRegs *s = opaque;
208
209 return s->acpi_pci_hotplug.use_acpi_hotplug_bridge;
210 }
211
212 static const VMStateDescription vmstate_pcihp_state = {
213 .name = "ich9_pm/pcihp",
214 .version_id = 1,
215 .minimum_version_id = 1,
216 .needed = vmstate_test_use_pcihp,
217 .fields = (const VMStateField[]) {
218 VMSTATE_PCI_HOTPLUG(acpi_pci_hotplug,
219 ICH9LPCPMRegs,
220 NULL, NULL),
221 VMSTATE_END_OF_LIST()
222 }
223 };
224
225 const VMStateDescription vmstate_ich9_pm = {
226 .name = "ich9_pm",
227 .version_id = 1,
228 .minimum_version_id = 1,
229 .post_load = ich9_pm_post_load,
230 .fields = (const VMStateField[]) {
231 VMSTATE_UINT16(acpi_regs.pm1.evt.sts, ICH9LPCPMRegs),
232 VMSTATE_UINT16(acpi_regs.pm1.evt.en, ICH9LPCPMRegs),
233 VMSTATE_UINT16(acpi_regs.pm1.cnt.cnt, ICH9LPCPMRegs),
234 VMSTATE_TIMER_PTR(acpi_regs.tmr.timer, ICH9LPCPMRegs),
235 VMSTATE_INT64(acpi_regs.tmr.overflow_time, ICH9LPCPMRegs),
236 VMSTATE_GPE_ARRAY(acpi_regs.gpe.sts, ICH9LPCPMRegs),
237 VMSTATE_GPE_ARRAY(acpi_regs.gpe.en, ICH9LPCPMRegs),
238 VMSTATE_UINT32(smi_en, ICH9LPCPMRegs),
239 VMSTATE_UINT32(smi_sts, ICH9LPCPMRegs),
240 VMSTATE_END_OF_LIST()
241 },
242 .subsections = (const VMStateDescription * const []) {
243 &vmstate_memhp_state,
244 &vmstate_tco_io_state,
245 &vmstate_cpuhp_state,
246 &vmstate_pcihp_state,
247 NULL
248 }
249 };
250
251 static void pm_reset(void *opaque)
252 {
253 ICH9LPCPMRegs *pm = opaque;
254 ich9_pm_iospace_update(pm, 0);
255
256 acpi_pm1_evt_reset(&pm->acpi_regs);
257 acpi_pm1_cnt_reset(&pm->acpi_regs);
258 acpi_pm_tmr_reset(&pm->acpi_regs);
259 acpi_gpe_reset(&pm->acpi_regs);
260
261 pm->smi_en = 0;
262 if (!pm->smm_enabled) {
263 /* Mark SMM as already inited to prevent SMM from running. */
264 pm->smi_en |= ICH9_PMIO_SMI_EN_APMC_EN;
265 }
266 pm->smi_en_wmask = ~0;
267
268 if (pm->acpi_pci_hotplug.use_acpi_hotplug_bridge) {
269 acpi_pcihp_reset(&pm->acpi_pci_hotplug);
270 }
271
272 acpi_update_sci(&pm->acpi_regs, pm->irq);
273 }
274
275 static void pm_powerdown_req(Notifier *n, void *opaque)
276 {
277 ICH9LPCPMRegs *pm = container_of(n, ICH9LPCPMRegs, powerdown_notifier);
278
279 acpi_pm1_evt_power_down(&pm->acpi_regs);
280 }
281
282 void ich9_pm_init(PCIDevice *lpc_pci, ICH9LPCPMRegs *pm, qemu_irq sci_irq)
283 {
284 pm->smi_sts_wmask = 0;
285
286 memory_region_init(&pm->io, OBJECT(lpc_pci), "ich9-pm", ICH9_PMIO_SIZE);
287 memory_region_set_enabled(&pm->io, false);
288 memory_region_add_subregion(pci_address_space_io(lpc_pci),
289 0, &pm->io);
290
291 acpi_pm_tmr_init(&pm->acpi_regs, ich9_pm_update_sci_fn, &pm->io);
292 acpi_pm1_evt_init(&pm->acpi_regs, ich9_pm_update_sci_fn, &pm->io);
293 acpi_pm1_cnt_init(&pm->acpi_regs, &pm->io, pm->disable_s3, pm->disable_s4,
294 pm->s4_val, !pm->smm_compat && !pm->smm_enabled);
295
296 acpi_gpe_init(&pm->acpi_regs, ICH9_PMIO_GPE0_LEN);
297 memory_region_init_io(&pm->io_gpe, OBJECT(lpc_pci), &ich9_gpe_ops, pm,
298 "acpi-gpe0", ICH9_PMIO_GPE0_LEN);
299 memory_region_add_subregion(&pm->io, ICH9_PMIO_GPE0_STS, &pm->io_gpe);
300
301 memory_region_init_io(&pm->io_smi, OBJECT(lpc_pci), &ich9_smi_ops, pm,
302 "acpi-smi", 8);
303 memory_region_add_subregion(&pm->io, ICH9_PMIO_SMI_EN, &pm->io_smi);
304
305 if (pm->swsmi_timer_enabled) {
306 ich9_pm_swsmi_timer_init(pm);
307 }
308
309 if (pm->periodic_timer_enabled) {
310 ich9_pm_periodic_timer_init(pm);
311 }
312
313 if (pm->enable_tco) {
314 acpi_pm_tco_init(&pm->tco_regs, &pm->io);
315 }
316
317 if (pm->acpi_pci_hotplug.use_acpi_hotplug_bridge) {
318 object_property_set_link(OBJECT(lpc_pci), "bus",
319 OBJECT(pci_get_bus(lpc_pci)), &error_abort);
320 acpi_pcihp_init(OBJECT(lpc_pci),
321 &pm->acpi_pci_hotplug,
322 pci_address_space_io(lpc_pci),
323 ACPI_PCIHP_ADDR_ICH9);
324
325 qbus_set_hotplug_handler(BUS(pci_get_bus(lpc_pci)),
326 OBJECT(lpc_pci));
327 }
328
329 pm->irq = sci_irq;
330 qemu_register_reset(pm_reset, pm);
331 pm->powerdown_notifier.notify = pm_powerdown_req;
332 qemu_register_powerdown_notifier(&pm->powerdown_notifier);
333
334 cpu_hotplug_hw_init(pci_address_space_io(lpc_pci),
335 OBJECT(lpc_pci), &pm->cpuhp_state, ICH9_CPU_HOTPLUG_IO_BASE);
336
337 acpi_memory_hotplug_init(pci_address_space_io(lpc_pci), OBJECT(lpc_pci),
338 &pm->acpi_memory_hotplug,
339 ACPI_MEMORY_HOTPLUG_BASE);
340 }
341
342 static void ich9_pm_get_gpe0_blk(Object *obj, Visitor *v, const char *name,
343 void *opaque, Error **errp)
344 {
345 ICH9LPCState *s = ICH9_LPC_DEVICE(obj);
346 ICH9LPCPMRegs *pm = &s->pm;
347 uint32_t value = pm->pm_io_base + ICH9_PMIO_GPE0_STS;
348
349 visit_type_uint32(v, name, &value, errp);
350 }
351
352 void ich9_pm_reset_properties(ICH9LPCPMRegs *pm)
353 {
354 pm->acpi_memory_hotplug.is_enabled = true;
355 pm->disable_s3 = 0;
356 pm->disable_s4 = 0;
357 pm->s4_val = 2;
358 pm->acpi_pci_hotplug.use_acpi_hotplug_bridge = true;
359 pm->keep_pci_slot_hpc = true;
360 pm->enable_tco = true;
361 }
362
363 #define PM_REG_FIELD(n) \
364 (pm_offset + offsetof(ICH9LPCPMRegs, n))
365
366 void ich9_pm_add_class_properties(ObjectClass *oc, ptrdiff_t pm_offset)
367 {
368 static const uint32_t gpe0_len = ICH9_PMIO_GPE0_LEN;
369
370 object_class_static_property_add_uint32_ptr(oc,
371 ACPI_PM_PROP_GPE0_BLK_LEN,
372 &gpe0_len,
373 OBJ_PROP_FLAG_READ);
374 object_class_property_add_uint32_ptr(oc, ACPI_PM_PROP_PM_IO_BASE,
375 PM_REG_FIELD(pm_io_base),
376 OBJ_PROP_FLAG_READ);
377 object_class_property_add_link(oc, "bus",
378 TYPE_PCI_BUS,
379 PM_REG_FIELD(acpi_pci_hotplug.root),
380 object_property_allow_set_link,
381 OBJ_PROP_LINK_STRONG);
382 object_class_property_add(oc, ACPI_PM_PROP_GPE0_BLK, "uint32",
383 ich9_pm_get_gpe0_blk,
384 NULL, NULL, NULL);
385 object_class_property_add_uint8_ptr(oc, ACPI_PM_PROP_S3_DISABLED,
386 PM_REG_FIELD(disable_s3),
387 OBJ_PROP_FLAG_READWRITE);
388 object_class_property_add_uint8_ptr(oc, ACPI_PM_PROP_S4_DISABLED,
389 PM_REG_FIELD(disable_s4),
390 OBJ_PROP_FLAG_READWRITE);
391 object_class_property_add_uint8_ptr(oc, ACPI_PM_PROP_S4_VAL,
392 PM_REG_FIELD(s4_val),
393 OBJ_PROP_FLAG_READWRITE);
394 object_class_property_add_bool_ptr(oc, ACPI_PM_PROP_TCO_ENABLED,
395 PM_REG_FIELD(enable_tco),
396 OBJ_PROP_FLAG_READWRITE);
397 object_class_property_add_bool_ptr(oc, ACPI_PM_PROP_ACPI_PCIHP_BRIDGE,
398 PM_REG_FIELD(acpi_pci_hotplug.use_acpi_hotplug_bridge),
399 OBJ_PROP_FLAG_READWRITE);
400 object_class_property_add_bool_ptr(oc, "x-keep-pci-slot-hpc",
401 PM_REG_FIELD(keep_pci_slot_hpc),
402 OBJ_PROP_FLAG_READWRITE);
403 object_class_property_add_uint16_ptr(oc, ACPI_PCIHP_IO_BASE_PROP,
404 PM_REG_FIELD(acpi_pci_hotplug.io_base),
405 OBJ_PROP_FLAG_READ);
406 object_class_property_add_uint16_ptr(oc, ACPI_PCIHP_IO_LEN_PROP,
407 PM_REG_FIELD(acpi_pci_hotplug.io_len),
408 OBJ_PROP_FLAG_READ);
409 }
410
411 #undef PM_REG_FIELD
412
413 void ich9_pm_device_pre_plug_cb(HotplugHandler *hotplug_dev, DeviceState *dev,
414 Error **errp)
415 {
416 ICH9LPCState *lpc = ICH9_LPC_DEVICE(hotplug_dev);
417
418 if (object_dynamic_cast(OBJECT(dev), TYPE_PCI_DEVICE)) {
419 acpi_pcihp_device_pre_plug_cb(hotplug_dev, dev, errp);
420 return;
421 }
422
423 if (object_dynamic_cast(OBJECT(dev), TYPE_CPU)) {
424 uint64_t negotiated = lpc->smi_negotiated_features;
425
426 if (negotiated & BIT_ULL(ICH9_LPC_SMI_F_BROADCAST_BIT) &&
427 !(negotiated & BIT_ULL(ICH9_LPC_SMI_F_CPU_HOTPLUG_BIT))) {
428 error_setg(errp, "cpu hotplug with SMI wasn't enabled by firmware");
429 error_append_hint(errp, "update machine type to newer than 5.1 "
430 "and firmware that suppors CPU hotplug with SMM");
431 }
432 }
433 }
434
435 void ich9_pm_device_plug_cb(HotplugHandler *hotplug_dev, DeviceState *dev,
436 Error **errp)
437 {
438 ICH9LPCState *lpc = ICH9_LPC_DEVICE(hotplug_dev);
439
440 if (object_dynamic_cast(OBJECT(dev), TYPE_PC_DIMM)) {
441 if (object_dynamic_cast(OBJECT(dev), TYPE_NVDIMM)) {
442 nvdimm_acpi_plug_cb(hotplug_dev, dev);
443 } else {
444 acpi_memory_plug_cb(hotplug_dev, &lpc->pm.acpi_memory_hotplug,
445 dev, errp);
446 }
447 } else if (object_dynamic_cast(OBJECT(dev), TYPE_CPU)) {
448 acpi_cpu_plug_cb(hotplug_dev, &lpc->pm.cpuhp_state, dev, errp);
449 } else if (object_dynamic_cast(OBJECT(dev), TYPE_PCI_DEVICE)) {
450 acpi_pcihp_device_plug_cb(hotplug_dev, &lpc->pm.acpi_pci_hotplug,
451 dev, errp);
452 } else {
453 error_setg(errp, "acpi: device plug request for not supported device"
454 " type: %s", object_get_typename(OBJECT(dev)));
455 }
456 }
457
458 void ich9_pm_device_unplug_request_cb(HotplugHandler *hotplug_dev,
459 DeviceState *dev, Error **errp)
460 {
461 ICH9LPCState *lpc = ICH9_LPC_DEVICE(hotplug_dev);
462
463 if (object_dynamic_cast(OBJECT(dev), TYPE_PC_DIMM)) {
464 acpi_memory_unplug_request_cb(hotplug_dev,
465 &lpc->pm.acpi_memory_hotplug, dev,
466 errp);
467 } else if (object_dynamic_cast(OBJECT(dev), TYPE_CPU)) {
468 uint64_t negotiated = lpc->smi_negotiated_features;
469
470 if (negotiated & BIT_ULL(ICH9_LPC_SMI_F_BROADCAST_BIT) &&
471 !(negotiated & BIT_ULL(ICH9_LPC_SMI_F_CPU_HOT_UNPLUG_BIT))) {
472 error_setg(errp, "cpu hot-unplug with SMI wasn't enabled "
473 "by firmware");
474 error_append_hint(errp, "update machine type to a version having "
475 "x-smi-cpu-hotunplug=on and firmware that "
476 "supports CPU hot-unplug with SMM");
477 return;
478 }
479
480 acpi_cpu_unplug_request_cb(hotplug_dev, &lpc->pm.cpuhp_state,
481 dev, errp);
482 } else if (object_dynamic_cast(OBJECT(dev), TYPE_PCI_DEVICE)) {
483 acpi_pcihp_device_unplug_request_cb(hotplug_dev,
484 &lpc->pm.acpi_pci_hotplug,
485 dev, errp);
486 } else {
487 error_setg(errp, "acpi: device unplug request for not supported device"
488 " type: %s", object_get_typename(OBJECT(dev)));
489 }
490 }
491
492 void ich9_pm_device_unplug_cb(HotplugHandler *hotplug_dev, DeviceState *dev,
493 Error **errp)
494 {
495 ICH9LPCState *lpc = ICH9_LPC_DEVICE(hotplug_dev);
496
497 if (object_dynamic_cast(OBJECT(dev), TYPE_PC_DIMM)) {
498 acpi_memory_unplug_cb(&lpc->pm.acpi_memory_hotplug, dev, errp);
499 } else if (object_dynamic_cast(OBJECT(dev), TYPE_CPU)) {
500 acpi_cpu_unplug_cb(&lpc->pm.cpuhp_state, dev, errp);
501 } else if (object_dynamic_cast(OBJECT(dev), TYPE_PCI_DEVICE)) {
502 acpi_pcihp_device_unplug_cb(hotplug_dev, &lpc->pm.acpi_pci_hotplug,
503 dev, errp);
504 } else {
505 error_setg(errp, "acpi: device unplug for not supported device"
506 " type: %s", object_get_typename(OBJECT(dev)));
507 }
508 }
509
510 bool ich9_pm_is_hotpluggable_bus(HotplugHandler *hotplug_dev, BusState *bus)
511 {
512 ICH9LPCState *lpc = ICH9_LPC_DEVICE(hotplug_dev);
513 return acpi_pcihp_is_hotpluggable_bus(&lpc->pm.acpi_pci_hotplug, bus);
514 }
515
516 void ich9_pm_ospm_status(AcpiDeviceIf *adev, ACPIOSTInfoList ***list)
517 {
518 ICH9LPCState *s = ICH9_LPC_DEVICE(adev);
519
520 acpi_memory_ospm_status(&s->pm.acpi_memory_hotplug, list);
521 acpi_cpu_ospm_status(&s->pm.cpuhp_state, list);
522 }