149ab747fSPaolo Bonzini /*
249ab747fSPaolo Bonzini * ACPI implementation
349ab747fSPaolo Bonzini *
449ab747fSPaolo Bonzini * Copyright (c) 2006 Fabrice Bellard
549ab747fSPaolo Bonzini * Copyright (c) 2009 Isaku Yamahata <yamahata at valinux co jp>
649ab747fSPaolo Bonzini * VA Linux Systems Japan K.K.
749ab747fSPaolo Bonzini * Copyright (C) 2012 Jason Baron <jbaron@redhat.com>
849ab747fSPaolo Bonzini *
949ab747fSPaolo Bonzini * This is based on acpi.c.
1049ab747fSPaolo Bonzini *
1149ab747fSPaolo Bonzini * This library is free software; you can redistribute it and/or
1249ab747fSPaolo Bonzini * modify it under the terms of the GNU Lesser General Public
1361f3c91aSChetan Pant * License version 2.1 as published by the Free Software Foundation.
1449ab747fSPaolo Bonzini *
1549ab747fSPaolo Bonzini * This library is distributed in the hope that it will be useful,
1649ab747fSPaolo Bonzini * but WITHOUT ANY WARRANTY; without even the implied warranty of
1749ab747fSPaolo Bonzini * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
1849ab747fSPaolo Bonzini * Lesser General Public License for more details.
1949ab747fSPaolo Bonzini *
2049ab747fSPaolo Bonzini * You should have received a copy of the GNU Lesser General Public
2149ab747fSPaolo Bonzini * License along with this library; if not, see <http://www.gnu.org/licenses/>
2249ab747fSPaolo Bonzini *
2349ab747fSPaolo Bonzini * Contributions after 2012-01-13 are licensed under the terms of the
2449ab747fSPaolo Bonzini * GNU GPL, version 2 or (at your option) any later version.
2549ab747fSPaolo Bonzini */
2671e8a915SMarkus Armbruster
27b6a0aa05SPeter Maydell #include "qemu/osdep.h"
28da34e65cSMarkus Armbruster #include "qapi/error.h"
296f1426abSMichael S. Tsirkin #include "qapi/visitor.h"
3049ab747fSPaolo Bonzini #include "hw/pci/pci.h"
31d6454270SMarkus Armbruster #include "migration/vmstate.h"
3249ab747fSPaolo Bonzini #include "qemu/timer.h"
332e5b09fdSMarkus Armbruster #include "hw/core/cpu.h"
3471e8a915SMarkus Armbruster #include "sysemu/reset.h"
3554d31236SMarkus Armbruster #include "sysemu/runstate.h"
3649ab747fSPaolo Bonzini #include "hw/acpi/acpi.h"
37fbae27e8SPhilippe Mathieu-Daudé #include "hw/acpi/ich9_tco.h"
38*6e3c2d58SDominic Prinz #include "hw/acpi/ich9_timer.h"
3949ab747fSPaolo Bonzini
401a6981bbSBernhard Beschow #include "hw/southbridge/ich9.h"
411f862184SIgor Mammedov #include "hw/mem/pc-dimm.h"
42132a908bSPhilippe Mathieu-Daudé #include "hw/mem/nvdimm.h"
4349ab747fSPaolo Bonzini
4449ab747fSPaolo Bonzini //#define DEBUG
4549ab747fSPaolo Bonzini
4649ab747fSPaolo Bonzini #ifdef DEBUG
4749ab747fSPaolo Bonzini #define ICH9_DEBUG(fmt, ...) \
4849ab747fSPaolo Bonzini do { printf("%s "fmt, __func__, ## __VA_ARGS__); } while (0)
4949ab747fSPaolo Bonzini #else
5049ab747fSPaolo Bonzini #define ICH9_DEBUG(fmt, ...) do { } while (0)
5149ab747fSPaolo Bonzini #endif
5249ab747fSPaolo Bonzini
ich9_pm_update_sci_fn(ACPIREGS * regs)5349ab747fSPaolo Bonzini static void ich9_pm_update_sci_fn(ACPIREGS *regs)
5449ab747fSPaolo Bonzini {
5549ab747fSPaolo Bonzini ICH9LPCPMRegs *pm = container_of(regs, ICH9LPCPMRegs, acpi_regs);
5606313503SIgor Mammedov acpi_update_sci(&pm->acpi_regs, pm->irq);
5749ab747fSPaolo Bonzini }
5849ab747fSPaolo Bonzini
ich9_gpe_readb(void * opaque,hwaddr addr,unsigned width)5949ab747fSPaolo Bonzini static uint64_t ich9_gpe_readb(void *opaque, hwaddr addr, unsigned width)
6049ab747fSPaolo Bonzini {
6149ab747fSPaolo Bonzini ICH9LPCPMRegs *pm = opaque;
6249ab747fSPaolo Bonzini return acpi_gpe_ioport_readb(&pm->acpi_regs, addr);
6349ab747fSPaolo Bonzini }
6449ab747fSPaolo Bonzini
ich9_gpe_writeb(void * opaque,hwaddr addr,uint64_t val,unsigned width)6549ab747fSPaolo Bonzini static void ich9_gpe_writeb(void *opaque, hwaddr addr, uint64_t val,
6649ab747fSPaolo Bonzini unsigned width)
6749ab747fSPaolo Bonzini {
6849ab747fSPaolo Bonzini ICH9LPCPMRegs *pm = opaque;
6949ab747fSPaolo Bonzini acpi_gpe_ioport_writeb(&pm->acpi_regs, addr, val);
702c047956SIgor Mammedov acpi_update_sci(&pm->acpi_regs, pm->irq);
7149ab747fSPaolo Bonzini }
7249ab747fSPaolo Bonzini
7349ab747fSPaolo Bonzini static const MemoryRegionOps ich9_gpe_ops = {
7449ab747fSPaolo Bonzini .read = ich9_gpe_readb,
7549ab747fSPaolo Bonzini .write = ich9_gpe_writeb,
7649ab747fSPaolo Bonzini .valid.min_access_size = 1,
7749ab747fSPaolo Bonzini .valid.max_access_size = 4,
7849ab747fSPaolo Bonzini .impl.min_access_size = 1,
7949ab747fSPaolo Bonzini .impl.max_access_size = 1,
8049ab747fSPaolo Bonzini .endianness = DEVICE_LITTLE_ENDIAN,
8149ab747fSPaolo Bonzini };
8249ab747fSPaolo Bonzini
ich9_smi_readl(void * opaque,hwaddr addr,unsigned width)8349ab747fSPaolo Bonzini static uint64_t ich9_smi_readl(void *opaque, hwaddr addr, unsigned width)
8449ab747fSPaolo Bonzini {
8549ab747fSPaolo Bonzini ICH9LPCPMRegs *pm = opaque;
8649ab747fSPaolo Bonzini switch (addr) {
8749ab747fSPaolo Bonzini case 0:
8849ab747fSPaolo Bonzini return pm->smi_en;
8949ab747fSPaolo Bonzini case 4:
9049ab747fSPaolo Bonzini return pm->smi_sts;
9149ab747fSPaolo Bonzini default:
9249ab747fSPaolo Bonzini return 0;
9349ab747fSPaolo Bonzini }
9449ab747fSPaolo Bonzini }
9549ab747fSPaolo Bonzini
ich9_smi_writel(void * opaque,hwaddr addr,uint64_t val,unsigned width)9649ab747fSPaolo Bonzini static void ich9_smi_writel(void *opaque, hwaddr addr, uint64_t val,
9749ab747fSPaolo Bonzini unsigned width)
9849ab747fSPaolo Bonzini {
9949ab747fSPaolo Bonzini ICH9LPCPMRegs *pm = opaque;
10092055797SPaulo Alcantara TCOIORegs *tr = &pm->tco_regs;
10192055797SPaulo Alcantara uint64_t tco_en;
10292055797SPaulo Alcantara
10349ab747fSPaolo Bonzini switch (addr) {
10449ab747fSPaolo Bonzini case 0:
10592055797SPaulo Alcantara tco_en = pm->smi_en & ICH9_PMIO_SMI_EN_TCO_EN;
10692055797SPaulo Alcantara /* once TCO_LOCK bit is set, TCO_EN bit cannot be overwritten */
10792055797SPaulo Alcantara if (tr->tco.cnt1 & TCO_LOCK) {
10892055797SPaulo Alcantara val = (val & ~ICH9_PMIO_SMI_EN_TCO_EN) | tco_en;
10992055797SPaulo Alcantara }
11011e66a15SGerd Hoffmann pm->smi_en &= ~pm->smi_en_wmask;
11111e66a15SGerd Hoffmann pm->smi_en |= (val & pm->smi_en_wmask);
112*6e3c2d58SDominic Prinz if (pm->swsmi_timer_enabled) {
113*6e3c2d58SDominic Prinz ich9_pm_update_swsmi_timer(pm, pm->smi_en &
114*6e3c2d58SDominic Prinz ICH9_PMIO_SMI_EN_SWSMI_EN);
115*6e3c2d58SDominic Prinz }
116*6e3c2d58SDominic Prinz if (pm->periodic_timer_enabled) {
117*6e3c2d58SDominic Prinz ich9_pm_update_periodic_timer(pm, pm->smi_en &
118*6e3c2d58SDominic Prinz ICH9_PMIO_SMI_EN_PERIODIC_EN);
119*6e3c2d58SDominic Prinz }
120*6e3c2d58SDominic Prinz break;
121*6e3c2d58SDominic Prinz case 4:
122*6e3c2d58SDominic Prinz pm->smi_sts &= ~pm->smi_sts_wmask;
123*6e3c2d58SDominic Prinz pm->smi_sts |= (val & pm->smi_sts_wmask);
12449ab747fSPaolo Bonzini break;
12549ab747fSPaolo Bonzini }
12649ab747fSPaolo Bonzini }
12749ab747fSPaolo Bonzini
12849ab747fSPaolo Bonzini static const MemoryRegionOps ich9_smi_ops = {
12949ab747fSPaolo Bonzini .read = ich9_smi_readl,
13049ab747fSPaolo Bonzini .write = ich9_smi_writel,
13149ab747fSPaolo Bonzini .valid.min_access_size = 4,
13249ab747fSPaolo Bonzini .valid.max_access_size = 4,
13349ab747fSPaolo Bonzini .endianness = DEVICE_LITTLE_ENDIAN,
13449ab747fSPaolo Bonzini };
13549ab747fSPaolo Bonzini
ich9_pm_iospace_update(ICH9LPCPMRegs * pm,uint32_t pm_io_base)13649ab747fSPaolo Bonzini void ich9_pm_iospace_update(ICH9LPCPMRegs *pm, uint32_t pm_io_base)
13749ab747fSPaolo Bonzini {
13849ab747fSPaolo Bonzini ICH9_DEBUG("to 0x%x\n", pm_io_base);
13949ab747fSPaolo Bonzini
14049ab747fSPaolo Bonzini assert((pm_io_base & ICH9_PMIO_MASK) == 0);
14149ab747fSPaolo Bonzini
14249ab747fSPaolo Bonzini pm->pm_io_base = pm_io_base;
14349ab747fSPaolo Bonzini memory_region_transaction_begin();
14449ab747fSPaolo Bonzini memory_region_set_enabled(&pm->io, pm->pm_io_base != 0);
14549ab747fSPaolo Bonzini memory_region_set_address(&pm->io, pm->pm_io_base);
14649ab747fSPaolo Bonzini memory_region_transaction_commit();
14749ab747fSPaolo Bonzini }
14849ab747fSPaolo Bonzini
ich9_pm_post_load(void * opaque,int version_id)14949ab747fSPaolo Bonzini static int ich9_pm_post_load(void *opaque, int version_id)
15049ab747fSPaolo Bonzini {
15149ab747fSPaolo Bonzini ICH9LPCPMRegs *pm = opaque;
15249ab747fSPaolo Bonzini uint32_t pm_io_base = pm->pm_io_base;
15349ab747fSPaolo Bonzini pm->pm_io_base = 0;
15449ab747fSPaolo Bonzini ich9_pm_iospace_update(pm, pm_io_base);
15549ab747fSPaolo Bonzini return 0;
15649ab747fSPaolo Bonzini }
15749ab747fSPaolo Bonzini
15849ab747fSPaolo Bonzini #define VMSTATE_GPE_ARRAY(_field, _state) \
15949ab747fSPaolo Bonzini { \
16049ab747fSPaolo Bonzini .name = (stringify(_field)), \
16149ab747fSPaolo Bonzini .version_id = 0, \
16249ab747fSPaolo Bonzini .num = ICH9_PMIO_GPE0_LEN, \
16349ab747fSPaolo Bonzini .info = &vmstate_info_uint8, \
16449ab747fSPaolo Bonzini .size = sizeof(uint8_t), \
16549ab747fSPaolo Bonzini .flags = VMS_ARRAY | VMS_POINTER, \
16649ab747fSPaolo Bonzini .offset = vmstate_offset_pointer(_state, _field, uint8_t), \
16749ab747fSPaolo Bonzini }
16849ab747fSPaolo Bonzini
169f816a62dSIgor Mammedov static const VMStateDescription vmstate_memhp_state = {
170f816a62dSIgor Mammedov .name = "ich9_pm/memhp",
171f816a62dSIgor Mammedov .version_id = 1,
172f816a62dSIgor Mammedov .minimum_version_id = 1,
173c559ba57SRichard Henderson .fields = (const VMStateField[]) {
174f816a62dSIgor Mammedov VMSTATE_MEMORY_HOTPLUG(acpi_memory_hotplug, ICH9LPCPMRegs),
175f816a62dSIgor Mammedov VMSTATE_END_OF_LIST()
176f816a62dSIgor Mammedov }
177f816a62dSIgor Mammedov };
178f816a62dSIgor Mammedov
vmstate_test_use_tco(void * opaque)17992055797SPaulo Alcantara static bool vmstate_test_use_tco(void *opaque)
18092055797SPaulo Alcantara {
18192055797SPaulo Alcantara ICH9LPCPMRegs *s = opaque;
18292055797SPaulo Alcantara return s->enable_tco;
18392055797SPaulo Alcantara }
18492055797SPaulo Alcantara
18592055797SPaulo Alcantara static const VMStateDescription vmstate_tco_io_state = {
18692055797SPaulo Alcantara .name = "ich9_pm/tco",
18792055797SPaulo Alcantara .version_id = 1,
18892055797SPaulo Alcantara .minimum_version_id = 1,
18992055797SPaulo Alcantara .needed = vmstate_test_use_tco,
190c559ba57SRichard Henderson .fields = (const VMStateField[]) {
19192055797SPaulo Alcantara VMSTATE_STRUCT(tco_regs, ICH9LPCPMRegs, 1, vmstate_tco_io_sts,
19292055797SPaulo Alcantara TCOIORegs),
19392055797SPaulo Alcantara VMSTATE_END_OF_LIST()
19492055797SPaulo Alcantara }
19592055797SPaulo Alcantara };
19692055797SPaulo Alcantara
vmstate_test_use_cpuhp(void * opaque)197679dd1a9SIgor Mammedov static bool vmstate_test_use_cpuhp(void *opaque)
198679dd1a9SIgor Mammedov {
199679dd1a9SIgor Mammedov ICH9LPCPMRegs *s = opaque;
200679dd1a9SIgor Mammedov return !s->cpu_hotplug_legacy;
201679dd1a9SIgor Mammedov }
202679dd1a9SIgor Mammedov
vmstate_cpuhp_pre_load(void * opaque)203679dd1a9SIgor Mammedov static int vmstate_cpuhp_pre_load(void *opaque)
204679dd1a9SIgor Mammedov {
205679dd1a9SIgor Mammedov ICH9LPCPMRegs *s = opaque;
206679dd1a9SIgor Mammedov Object *obj = OBJECT(s->gpe_cpu.device);
2075325cc34SMarkus Armbruster object_property_set_bool(obj, "cpu-hotplug-legacy", false, &error_abort);
208679dd1a9SIgor Mammedov return 0;
209679dd1a9SIgor Mammedov }
210679dd1a9SIgor Mammedov
211679dd1a9SIgor Mammedov static const VMStateDescription vmstate_cpuhp_state = {
212679dd1a9SIgor Mammedov .name = "ich9_pm/cpuhp",
213679dd1a9SIgor Mammedov .version_id = 1,
214679dd1a9SIgor Mammedov .minimum_version_id = 1,
215679dd1a9SIgor Mammedov .needed = vmstate_test_use_cpuhp,
216679dd1a9SIgor Mammedov .pre_load = vmstate_cpuhp_pre_load,
217c559ba57SRichard Henderson .fields = (const VMStateField[]) {
218679dd1a9SIgor Mammedov VMSTATE_CPU_HOTPLUG(cpuhp_state, ICH9LPCPMRegs),
219679dd1a9SIgor Mammedov VMSTATE_END_OF_LIST()
220679dd1a9SIgor Mammedov }
221679dd1a9SIgor Mammedov };
222679dd1a9SIgor Mammedov
vmstate_test_use_pcihp(void * opaque)223c0e427d6SJulia Suvorova static bool vmstate_test_use_pcihp(void *opaque)
224c0e427d6SJulia Suvorova {
225c0e427d6SJulia Suvorova ICH9LPCPMRegs *s = opaque;
226c0e427d6SJulia Suvorova
2276536e427SIgor Mammedov return s->acpi_pci_hotplug.use_acpi_hotplug_bridge;
228c0e427d6SJulia Suvorova }
229c0e427d6SJulia Suvorova
230c0e427d6SJulia Suvorova static const VMStateDescription vmstate_pcihp_state = {
231c0e427d6SJulia Suvorova .name = "ich9_pm/pcihp",
232c0e427d6SJulia Suvorova .version_id = 1,
233c0e427d6SJulia Suvorova .minimum_version_id = 1,
234c0e427d6SJulia Suvorova .needed = vmstate_test_use_pcihp,
235c559ba57SRichard Henderson .fields = (const VMStateField[]) {
236c0e427d6SJulia Suvorova VMSTATE_PCI_HOTPLUG(acpi_pci_hotplug,
237c0e427d6SJulia Suvorova ICH9LPCPMRegs,
238c0e427d6SJulia Suvorova NULL, NULL),
239c0e427d6SJulia Suvorova VMSTATE_END_OF_LIST()
240c0e427d6SJulia Suvorova }
241c0e427d6SJulia Suvorova };
242c0e427d6SJulia Suvorova
24349ab747fSPaolo Bonzini const VMStateDescription vmstate_ich9_pm = {
24449ab747fSPaolo Bonzini .name = "ich9_pm",
24549ab747fSPaolo Bonzini .version_id = 1,
24649ab747fSPaolo Bonzini .minimum_version_id = 1,
24749ab747fSPaolo Bonzini .post_load = ich9_pm_post_load,
248c559ba57SRichard Henderson .fields = (const VMStateField[]) {
24949ab747fSPaolo Bonzini VMSTATE_UINT16(acpi_regs.pm1.evt.sts, ICH9LPCPMRegs),
25049ab747fSPaolo Bonzini VMSTATE_UINT16(acpi_regs.pm1.evt.en, ICH9LPCPMRegs),
25149ab747fSPaolo Bonzini VMSTATE_UINT16(acpi_regs.pm1.cnt.cnt, ICH9LPCPMRegs),
252e720677eSPaolo Bonzini VMSTATE_TIMER_PTR(acpi_regs.tmr.timer, ICH9LPCPMRegs),
25349ab747fSPaolo Bonzini VMSTATE_INT64(acpi_regs.tmr.overflow_time, ICH9LPCPMRegs),
25449ab747fSPaolo Bonzini VMSTATE_GPE_ARRAY(acpi_regs.gpe.sts, ICH9LPCPMRegs),
25549ab747fSPaolo Bonzini VMSTATE_GPE_ARRAY(acpi_regs.gpe.en, ICH9LPCPMRegs),
25649ab747fSPaolo Bonzini VMSTATE_UINT32(smi_en, ICH9LPCPMRegs),
25749ab747fSPaolo Bonzini VMSTATE_UINT32(smi_sts, ICH9LPCPMRegs),
25849ab747fSPaolo Bonzini VMSTATE_END_OF_LIST()
259f816a62dSIgor Mammedov },
260c559ba57SRichard Henderson .subsections = (const VMStateDescription * const []) {
2615cd8cadaSJuan Quintela &vmstate_memhp_state,
26292055797SPaulo Alcantara &vmstate_tco_io_state,
263679dd1a9SIgor Mammedov &vmstate_cpuhp_state,
264c0e427d6SJulia Suvorova &vmstate_pcihp_state,
26592055797SPaulo Alcantara NULL
26649ab747fSPaolo Bonzini }
26749ab747fSPaolo Bonzini };
26849ab747fSPaolo Bonzini
pm_reset(void * opaque)26949ab747fSPaolo Bonzini static void pm_reset(void *opaque)
27049ab747fSPaolo Bonzini {
27149ab747fSPaolo Bonzini ICH9LPCPMRegs *pm = opaque;
27249ab747fSPaolo Bonzini ich9_pm_iospace_update(pm, 0);
27349ab747fSPaolo Bonzini
27449ab747fSPaolo Bonzini acpi_pm1_evt_reset(&pm->acpi_regs);
27549ab747fSPaolo Bonzini acpi_pm1_cnt_reset(&pm->acpi_regs);
27649ab747fSPaolo Bonzini acpi_pm_tmr_reset(&pm->acpi_regs);
27749ab747fSPaolo Bonzini acpi_gpe_reset(&pm->acpi_regs);
27849ab747fSPaolo Bonzini
279be66680eSLaszlo Ersek pm->smi_en = 0;
280fba72476SPaolo Bonzini if (!pm->smm_enabled) {
281f3c30aeaSLaszlo Ersek /* Mark SMM as already inited to prevent SMM from running. */
28249ab747fSPaolo Bonzini pm->smi_en |= ICH9_PMIO_SMI_EN_APMC_EN;
28349ab747fSPaolo Bonzini }
28411e66a15SGerd Hoffmann pm->smi_en_wmask = ~0;
28549ab747fSPaolo Bonzini
2866536e427SIgor Mammedov if (pm->acpi_pci_hotplug.use_acpi_hotplug_bridge) {
2876536e427SIgor Mammedov acpi_pcihp_reset(&pm->acpi_pci_hotplug);
288c0e427d6SJulia Suvorova }
289c0e427d6SJulia Suvorova
29006313503SIgor Mammedov acpi_update_sci(&pm->acpi_regs, pm->irq);
29149ab747fSPaolo Bonzini }
29249ab747fSPaolo Bonzini
pm_powerdown_req(Notifier * n,void * opaque)29349ab747fSPaolo Bonzini static void pm_powerdown_req(Notifier *n, void *opaque)
29449ab747fSPaolo Bonzini {
29549ab747fSPaolo Bonzini ICH9LPCPMRegs *pm = container_of(n, ICH9LPCPMRegs, powerdown_notifier);
29649ab747fSPaolo Bonzini
29749ab747fSPaolo Bonzini acpi_pm1_evt_power_down(&pm->acpi_regs);
29849ab747fSPaolo Bonzini }
29949ab747fSPaolo Bonzini
ich9_pm_init(PCIDevice * lpc_pci,ICH9LPCPMRegs * pm,qemu_irq sci_irq)30020fe3af2SBernhard Beschow void ich9_pm_init(PCIDevice *lpc_pci, ICH9LPCPMRegs *pm, qemu_irq sci_irq)
30149ab747fSPaolo Bonzini {
302*6e3c2d58SDominic Prinz pm->smi_sts_wmask = 0;
303*6e3c2d58SDominic Prinz
30464bde0f3SPaolo Bonzini memory_region_init(&pm->io, OBJECT(lpc_pci), "ich9-pm", ICH9_PMIO_SIZE);
30549ab747fSPaolo Bonzini memory_region_set_enabled(&pm->io, false);
30649ab747fSPaolo Bonzini memory_region_add_subregion(pci_address_space_io(lpc_pci),
30749ab747fSPaolo Bonzini 0, &pm->io);
30849ab747fSPaolo Bonzini
30949ab747fSPaolo Bonzini acpi_pm_tmr_init(&pm->acpi_regs, ich9_pm_update_sci_fn, &pm->io);
31049ab747fSPaolo Bonzini acpi_pm1_evt_init(&pm->acpi_regs, ich9_pm_update_sci_fn, &pm->io);
3119a10bbb4SLaszlo Ersek acpi_pm1_cnt_init(&pm->acpi_regs, &pm->io, pm->disable_s3, pm->disable_s4,
31220fe3af2SBernhard Beschow pm->s4_val, !pm->smm_compat && !pm->smm_enabled);
31349ab747fSPaolo Bonzini
31449ab747fSPaolo Bonzini acpi_gpe_init(&pm->acpi_regs, ICH9_PMIO_GPE0_LEN);
31564bde0f3SPaolo Bonzini memory_region_init_io(&pm->io_gpe, OBJECT(lpc_pci), &ich9_gpe_ops, pm,
31675902802SHu Tao "acpi-gpe0", ICH9_PMIO_GPE0_LEN);
31749ab747fSPaolo Bonzini memory_region_add_subregion(&pm->io, ICH9_PMIO_GPE0_STS, &pm->io_gpe);
31849ab747fSPaolo Bonzini
31964bde0f3SPaolo Bonzini memory_region_init_io(&pm->io_smi, OBJECT(lpc_pci), &ich9_smi_ops, pm,
32075902802SHu Tao "acpi-smi", 8);
32149ab747fSPaolo Bonzini memory_region_add_subregion(&pm->io, ICH9_PMIO_SMI_EN, &pm->io_smi);
32249ab747fSPaolo Bonzini
323*6e3c2d58SDominic Prinz if (pm->swsmi_timer_enabled) {
324*6e3c2d58SDominic Prinz ich9_pm_swsmi_timer_init(pm);
325*6e3c2d58SDominic Prinz }
326*6e3c2d58SDominic Prinz
327*6e3c2d58SDominic Prinz if (pm->periodic_timer_enabled) {
328*6e3c2d58SDominic Prinz ich9_pm_periodic_timer_init(pm);
329*6e3c2d58SDominic Prinz }
330*6e3c2d58SDominic Prinz
331ee1c08bdSDaniel P. Berrangé if (pm->enable_tco) {
33292055797SPaulo Alcantara acpi_pm_tco_init(&pm->tco_regs, &pm->io);
333ee1c08bdSDaniel P. Berrangé }
33492055797SPaulo Alcantara
3356536e427SIgor Mammedov if (pm->acpi_pci_hotplug.use_acpi_hotplug_bridge) {
336c0e427d6SJulia Suvorova acpi_pcihp_init(OBJECT(lpc_pci),
337c0e427d6SJulia Suvorova &pm->acpi_pci_hotplug,
338c0e427d6SJulia Suvorova pci_get_bus(lpc_pci),
339c0e427d6SJulia Suvorova pci_address_space_io(lpc_pci),
340c0e427d6SJulia Suvorova ACPI_PCIHP_ADDR_ICH9);
341c0e427d6SJulia Suvorova
342c0e427d6SJulia Suvorova qbus_set_hotplug_handler(BUS(pci_get_bus(lpc_pci)),
343c0e427d6SJulia Suvorova OBJECT(lpc_pci));
344c0e427d6SJulia Suvorova }
345c0e427d6SJulia Suvorova
34649ab747fSPaolo Bonzini pm->irq = sci_irq;
34749ab747fSPaolo Bonzini qemu_register_reset(pm_reset, pm);
34849ab747fSPaolo Bonzini pm->powerdown_notifier.notify = pm_powerdown_req;
34949ab747fSPaolo Bonzini qemu_register_powerdown_notifier(&pm->powerdown_notifier);
350d6610bc2SIgor Mammedov
35196e3e12bSIgor Mammedov legacy_acpi_cpu_hotplug_init(pci_address_space_io(lpc_pci),
35296e3e12bSIgor Mammedov OBJECT(lpc_pci), &pm->gpe_cpu, ICH9_CPU_HOTPLUG_IO_BASE);
3531f862184SIgor Mammedov
3541f862184SIgor Mammedov acpi_memory_hotplug_init(pci_address_space_io(lpc_pci), OBJECT(lpc_pci),
35580db0e78SIgor Mammedov &pm->acpi_memory_hotplug,
35680db0e78SIgor Mammedov ACPI_MEMORY_HOTPLUG_BASE);
3571f862184SIgor Mammedov }
3586f1426abSMichael S. Tsirkin
ich9_pm_get_gpe0_blk(Object * obj,Visitor * v,const char * name,void * opaque,Error ** errp)359d7bce999SEric Blake static void ich9_pm_get_gpe0_blk(Object *obj, Visitor *v, const char *name,
360d7bce999SEric Blake void *opaque, Error **errp)
3616f1426abSMichael S. Tsirkin {
3626f1426abSMichael S. Tsirkin ICH9LPCPMRegs *pm = opaque;
3636f1426abSMichael S. Tsirkin uint32_t value = pm->pm_io_base + ICH9_PMIO_GPE0_STS;
3646f1426abSMichael S. Tsirkin
36551e72bc1SEric Blake visit_type_uint32(v, name, &value, errp);
3666f1426abSMichael S. Tsirkin }
3676f1426abSMichael S. Tsirkin
ich9_pm_get_cpu_hotplug_legacy(Object * obj,Error ** errp)36816bcab97SIgor Mammedov static bool ich9_pm_get_cpu_hotplug_legacy(Object *obj, Error **errp)
36916bcab97SIgor Mammedov {
37016bcab97SIgor Mammedov ICH9LPCState *s = ICH9_LPC_DEVICE(obj);
37116bcab97SIgor Mammedov
37216bcab97SIgor Mammedov return s->pm.cpu_hotplug_legacy;
37316bcab97SIgor Mammedov }
37416bcab97SIgor Mammedov
ich9_pm_set_cpu_hotplug_legacy(Object * obj,bool value,Error ** errp)37516bcab97SIgor Mammedov static void ich9_pm_set_cpu_hotplug_legacy(Object *obj, bool value,
37616bcab97SIgor Mammedov Error **errp)
37716bcab97SIgor Mammedov {
37816bcab97SIgor Mammedov ICH9LPCState *s = ICH9_LPC_DEVICE(obj);
37916bcab97SIgor Mammedov
380679dd1a9SIgor Mammedov assert(!value);
381679dd1a9SIgor Mammedov if (s->pm.cpu_hotplug_legacy && value == false) {
382679dd1a9SIgor Mammedov acpi_switch_to_modern_cphp(&s->pm.gpe_cpu, &s->pm.cpuhp_state,
383679dd1a9SIgor Mammedov ICH9_CPU_HOTPLUG_IO_BASE);
384679dd1a9SIgor Mammedov }
38516bcab97SIgor Mammedov s->pm.cpu_hotplug_legacy = value;
38616bcab97SIgor Mammedov }
38716bcab97SIgor Mammedov
ich9_pm_get_enable_tco(Object * obj,Error ** errp)38892055797SPaulo Alcantara static bool ich9_pm_get_enable_tco(Object *obj, Error **errp)
38992055797SPaulo Alcantara {
39092055797SPaulo Alcantara ICH9LPCState *s = ICH9_LPC_DEVICE(obj);
39192055797SPaulo Alcantara return s->pm.enable_tco;
39292055797SPaulo Alcantara }
39392055797SPaulo Alcantara
ich9_pm_set_enable_tco(Object * obj,bool value,Error ** errp)39492055797SPaulo Alcantara static void ich9_pm_set_enable_tco(Object *obj, bool value, Error **errp)
39592055797SPaulo Alcantara {
39692055797SPaulo Alcantara ICH9LPCState *s = ICH9_LPC_DEVICE(obj);
39792055797SPaulo Alcantara s->pm.enable_tco = value;
39892055797SPaulo Alcantara }
39992055797SPaulo Alcantara
ich9_pm_get_acpi_pci_hotplug(Object * obj,Error ** errp)400c0e427d6SJulia Suvorova static bool ich9_pm_get_acpi_pci_hotplug(Object *obj, Error **errp)
401c0e427d6SJulia Suvorova {
402c0e427d6SJulia Suvorova ICH9LPCState *s = ICH9_LPC_DEVICE(obj);
403c0e427d6SJulia Suvorova
4046536e427SIgor Mammedov return s->pm.acpi_pci_hotplug.use_acpi_hotplug_bridge;
405c0e427d6SJulia Suvorova }
406c0e427d6SJulia Suvorova
ich9_pm_set_acpi_pci_hotplug(Object * obj,bool value,Error ** errp)407c0e427d6SJulia Suvorova static void ich9_pm_set_acpi_pci_hotplug(Object *obj, bool value, Error **errp)
408c0e427d6SJulia Suvorova {
409c0e427d6SJulia Suvorova ICH9LPCState *s = ICH9_LPC_DEVICE(obj);
410c0e427d6SJulia Suvorova
4116536e427SIgor Mammedov s->pm.acpi_pci_hotplug.use_acpi_hotplug_bridge = value;
412c0e427d6SJulia Suvorova }
413c0e427d6SJulia Suvorova
ich9_pm_get_keep_pci_slot_hpc(Object * obj,Error ** errp)414c318bef7SJulia Suvorova static bool ich9_pm_get_keep_pci_slot_hpc(Object *obj, Error **errp)
415c318bef7SJulia Suvorova {
416c318bef7SJulia Suvorova ICH9LPCState *s = ICH9_LPC_DEVICE(obj);
417c318bef7SJulia Suvorova
418c318bef7SJulia Suvorova return s->pm.keep_pci_slot_hpc;
419c318bef7SJulia Suvorova }
420c318bef7SJulia Suvorova
ich9_pm_set_keep_pci_slot_hpc(Object * obj,bool value,Error ** errp)421c318bef7SJulia Suvorova static void ich9_pm_set_keep_pci_slot_hpc(Object *obj, bool value, Error **errp)
422c318bef7SJulia Suvorova {
423c318bef7SJulia Suvorova ICH9LPCState *s = ICH9_LPC_DEVICE(obj);
424c318bef7SJulia Suvorova
425c318bef7SJulia Suvorova s->pm.keep_pci_slot_hpc = value;
426c318bef7SJulia Suvorova }
427c318bef7SJulia Suvorova
ich9_pm_add_properties(Object * obj,ICH9LPCPMRegs * pm)42840c2281cSMarkus Armbruster void ich9_pm_add_properties(Object *obj, ICH9LPCPMRegs *pm)
4296f1426abSMichael S. Tsirkin {
4306f1426abSMichael S. Tsirkin static const uint32_t gpe0_len = ICH9_PMIO_GPE0_LEN;
4311f862184SIgor Mammedov pm->acpi_memory_hotplug.is_enabled = true;
43216bcab97SIgor Mammedov pm->cpu_hotplug_legacy = true;
4336ac0d8d4SAmit Shah pm->disable_s3 = 0;
4346ac0d8d4SAmit Shah pm->disable_s4 = 0;
4356ac0d8d4SAmit Shah pm->s4_val = 2;
4366536e427SIgor Mammedov pm->acpi_pci_hotplug.use_acpi_hotplug_bridge = true;
437c318bef7SJulia Suvorova pm->keep_pci_slot_hpc = true;
438ee1c08bdSDaniel P. Berrangé pm->enable_tco = true;
4396f1426abSMichael S. Tsirkin
4406f1426abSMichael S. Tsirkin object_property_add_uint32_ptr(obj, ACPI_PM_PROP_PM_IO_BASE,
441d2623129SMarkus Armbruster &pm->pm_io_base, OBJ_PROP_FLAG_READ);
4426f1426abSMichael S. Tsirkin object_property_add(obj, ACPI_PM_PROP_GPE0_BLK, "uint32",
4436f1426abSMichael S. Tsirkin ich9_pm_get_gpe0_blk,
444d2623129SMarkus Armbruster NULL, NULL, pm);
4456f1426abSMichael S. Tsirkin object_property_add_uint32_ptr(obj, ACPI_PM_PROP_GPE0_BLK_LEN,
446d2623129SMarkus Armbruster &gpe0_len, OBJ_PROP_FLAG_READ);
44716bcab97SIgor Mammedov object_property_add_bool(obj, "cpu-hotplug-legacy",
44816bcab97SIgor Mammedov ich9_pm_get_cpu_hotplug_legacy,
449d2623129SMarkus Armbruster ich9_pm_set_cpu_hotplug_legacy);
45064a7b8deSFelipe Franciosi object_property_add_uint8_ptr(obj, ACPI_PM_PROP_S3_DISABLED,
451d2623129SMarkus Armbruster &pm->disable_s3, OBJ_PROP_FLAG_READWRITE);
45264a7b8deSFelipe Franciosi object_property_add_uint8_ptr(obj, ACPI_PM_PROP_S4_DISABLED,
453d2623129SMarkus Armbruster &pm->disable_s4, OBJ_PROP_FLAG_READWRITE);
45464a7b8deSFelipe Franciosi object_property_add_uint8_ptr(obj, ACPI_PM_PROP_S4_VAL,
455d2623129SMarkus Armbruster &pm->s4_val, OBJ_PROP_FLAG_READWRITE);
45692055797SPaulo Alcantara object_property_add_bool(obj, ACPI_PM_PROP_TCO_ENABLED,
45792055797SPaulo Alcantara ich9_pm_get_enable_tco,
458d2623129SMarkus Armbruster ich9_pm_set_enable_tco);
459aa29466bSAni Sinha object_property_add_bool(obj, ACPI_PM_PROP_ACPI_PCIHP_BRIDGE,
460c0e427d6SJulia Suvorova ich9_pm_get_acpi_pci_hotplug,
461c0e427d6SJulia Suvorova ich9_pm_set_acpi_pci_hotplug);
462c318bef7SJulia Suvorova object_property_add_bool(obj, "x-keep-pci-slot-hpc",
463c318bef7SJulia Suvorova ich9_pm_get_keep_pci_slot_hpc,
464c318bef7SJulia Suvorova ich9_pm_set_keep_pci_slot_hpc);
4651f862184SIgor Mammedov }
4661f862184SIgor Mammedov
ich9_pm_device_pre_plug_cb(HotplugHandler * hotplug_dev,DeviceState * dev,Error ** errp)4679040e6dfSWei Yang void ich9_pm_device_pre_plug_cb(HotplugHandler *hotplug_dev, DeviceState *dev,
4689040e6dfSWei Yang Error **errp)
4699040e6dfSWei Yang {
4709040e6dfSWei Yang ICH9LPCState *lpc = ICH9_LPC_DEVICE(hotplug_dev);
4719040e6dfSWei Yang
472c0e427d6SJulia Suvorova if (object_dynamic_cast(OBJECT(dev), TYPE_PCI_DEVICE)) {
473c0e427d6SJulia Suvorova acpi_pcihp_device_pre_plug_cb(hotplug_dev, dev, errp);
474c0e427d6SJulia Suvorova return;
475c0e427d6SJulia Suvorova }
476c0e427d6SJulia Suvorova
4772529ea2dSPhilippe Mathieu-Daudé if (object_dynamic_cast(OBJECT(dev), TYPE_CPU)) {
478c5be7517SIgor Mammedov uint64_t negotiated = lpc->smi_negotiated_features;
479c5be7517SIgor Mammedov
480c5be7517SIgor Mammedov if (negotiated & BIT_ULL(ICH9_LPC_SMI_F_BROADCAST_BIT) &&
481c5be7517SIgor Mammedov !(negotiated & BIT_ULL(ICH9_LPC_SMI_F_CPU_HOTPLUG_BIT))) {
482c5be7517SIgor Mammedov error_setg(errp, "cpu hotplug with SMI wasn't enabled by firmware");
483c5be7517SIgor Mammedov error_append_hint(errp, "update machine type to newer than 5.1 "
484c5be7517SIgor Mammedov "and firmware that suppors CPU hotplug with SMM");
485c5be7517SIgor Mammedov }
486c5be7517SIgor Mammedov }
4879040e6dfSWei Yang }
4889040e6dfSWei Yang
ich9_pm_device_plug_cb(HotplugHandler * hotplug_dev,DeviceState * dev,Error ** errp)4890058c082SIgor Mammedov void ich9_pm_device_plug_cb(HotplugHandler *hotplug_dev, DeviceState *dev,
4900058c082SIgor Mammedov Error **errp)
4911f862184SIgor Mammedov {
4920058c082SIgor Mammedov ICH9LPCState *lpc = ICH9_LPC_DEVICE(hotplug_dev);
4930058c082SIgor Mammedov
4949040e6dfSWei Yang if (object_dynamic_cast(OBJECT(dev), TYPE_PC_DIMM)) {
49575f27498SXiao Guangrong if (object_dynamic_cast(OBJECT(dev), TYPE_NVDIMM)) {
49675f27498SXiao Guangrong nvdimm_acpi_plug_cb(hotplug_dev, dev);
49775f27498SXiao Guangrong } else {
4980058c082SIgor Mammedov acpi_memory_plug_cb(hotplug_dev, &lpc->pm.acpi_memory_hotplug,
4991f862184SIgor Mammedov dev, errp);
50075f27498SXiao Guangrong }
5015e1b5d93SIgor Mammedov } else if (object_dynamic_cast(OBJECT(dev), TYPE_CPU)) {
5025e1b5d93SIgor Mammedov if (lpc->pm.cpu_hotplug_legacy) {
5030058c082SIgor Mammedov legacy_acpi_cpu_plug_cb(hotplug_dev, &lpc->pm.gpe_cpu, dev, errp);
5041f862184SIgor Mammedov } else {
5055e1b5d93SIgor Mammedov acpi_cpu_plug_cb(hotplug_dev, &lpc->pm.cpuhp_state, dev, errp);
5065e1b5d93SIgor Mammedov }
507c0e427d6SJulia Suvorova } else if (object_dynamic_cast(OBJECT(dev), TYPE_PCI_DEVICE)) {
508c0e427d6SJulia Suvorova acpi_pcihp_device_plug_cb(hotplug_dev, &lpc->pm.acpi_pci_hotplug,
509c0e427d6SJulia Suvorova dev, errp);
5105e1b5d93SIgor Mammedov } else {
5111f862184SIgor Mammedov error_setg(errp, "acpi: device plug request for not supported device"
5121f862184SIgor Mammedov " type: %s", object_get_typename(OBJECT(dev)));
5131f862184SIgor Mammedov }
5146f1426abSMichael S. Tsirkin }
51543f50410SIgor Mammedov
ich9_pm_device_unplug_request_cb(HotplugHandler * hotplug_dev,DeviceState * dev,Error ** errp)5160058c082SIgor Mammedov void ich9_pm_device_unplug_request_cb(HotplugHandler *hotplug_dev,
5170058c082SIgor Mammedov DeviceState *dev, Error **errp)
518469b8ad2STang Chen {
5190058c082SIgor Mammedov ICH9LPCState *lpc = ICH9_LPC_DEVICE(hotplug_dev);
5200058c082SIgor Mammedov
5212529ea2dSPhilippe Mathieu-Daudé if (object_dynamic_cast(OBJECT(dev), TYPE_PC_DIMM)) {
5220058c082SIgor Mammedov acpi_memory_unplug_request_cb(hotplug_dev,
5230058c082SIgor Mammedov &lpc->pm.acpi_memory_hotplug, dev,
5240058c082SIgor Mammedov errp);
5258872c25aSIgor Mammedov } else if (object_dynamic_cast(OBJECT(dev), TYPE_CPU) &&
5268872c25aSIgor Mammedov !lpc->pm.cpu_hotplug_legacy) {
527b48ad7c0SIgor Mammedov uint64_t negotiated = lpc->smi_negotiated_features;
528b48ad7c0SIgor Mammedov
529b48ad7c0SIgor Mammedov if (negotiated & BIT_ULL(ICH9_LPC_SMI_F_BROADCAST_BIT) &&
530b48ad7c0SIgor Mammedov !(negotiated & BIT_ULL(ICH9_LPC_SMI_F_CPU_HOT_UNPLUG_BIT))) {
531b48ad7c0SIgor Mammedov error_setg(errp, "cpu hot-unplug with SMI wasn't enabled "
532b48ad7c0SIgor Mammedov "by firmware");
533b48ad7c0SIgor Mammedov error_append_hint(errp, "update machine type to a version having "
534b48ad7c0SIgor Mammedov "x-smi-cpu-hotunplug=on and firmware that "
535b48ad7c0SIgor Mammedov "supports CPU hot-unplug with SMM");
536b48ad7c0SIgor Mammedov return;
537b48ad7c0SIgor Mammedov }
538b48ad7c0SIgor Mammedov
5398872c25aSIgor Mammedov acpi_cpu_unplug_request_cb(hotplug_dev, &lpc->pm.cpuhp_state,
5408872c25aSIgor Mammedov dev, errp);
541c0e427d6SJulia Suvorova } else if (object_dynamic_cast(OBJECT(dev), TYPE_PCI_DEVICE)) {
542c0e427d6SJulia Suvorova acpi_pcihp_device_unplug_request_cb(hotplug_dev,
543c0e427d6SJulia Suvorova &lpc->pm.acpi_pci_hotplug,
544c0e427d6SJulia Suvorova dev, errp);
54564fec58eSTang Chen } else {
546469b8ad2STang Chen error_setg(errp, "acpi: device unplug request for not supported device"
547469b8ad2STang Chen " type: %s", object_get_typename(OBJECT(dev)));
548469b8ad2STang Chen }
54964fec58eSTang Chen }
550469b8ad2STang Chen
ich9_pm_device_unplug_cb(HotplugHandler * hotplug_dev,DeviceState * dev,Error ** errp)5510058c082SIgor Mammedov void ich9_pm_device_unplug_cb(HotplugHandler *hotplug_dev, DeviceState *dev,
55291a734a6STang Chen Error **errp)
55391a734a6STang Chen {
5540058c082SIgor Mammedov ICH9LPCState *lpc = ICH9_LPC_DEVICE(hotplug_dev);
5550058c082SIgor Mammedov
5562529ea2dSPhilippe Mathieu-Daudé if (object_dynamic_cast(OBJECT(dev), TYPE_PC_DIMM)) {
5570058c082SIgor Mammedov acpi_memory_unplug_cb(&lpc->pm.acpi_memory_hotplug, dev, errp);
5588872c25aSIgor Mammedov } else if (object_dynamic_cast(OBJECT(dev), TYPE_CPU) &&
5598872c25aSIgor Mammedov !lpc->pm.cpu_hotplug_legacy) {
5608872c25aSIgor Mammedov acpi_cpu_unplug_cb(&lpc->pm.cpuhp_state, dev, errp);
561c0e427d6SJulia Suvorova } else if (object_dynamic_cast(OBJECT(dev), TYPE_PCI_DEVICE)) {
562c0e427d6SJulia Suvorova acpi_pcihp_device_unplug_cb(hotplug_dev, &lpc->pm.acpi_pci_hotplug,
563c0e427d6SJulia Suvorova dev, errp);
564f7d3e29dSTang Chen } else {
56591a734a6STang Chen error_setg(errp, "acpi: device unplug for not supported device"
56691a734a6STang Chen " type: %s", object_get_typename(OBJECT(dev)));
56791a734a6STang Chen }
568f7d3e29dSTang Chen }
56991a734a6STang Chen
ich9_pm_is_hotpluggable_bus(HotplugHandler * hotplug_dev,BusState * bus)570f18e29fcSIgor Mammedov bool ich9_pm_is_hotpluggable_bus(HotplugHandler *hotplug_dev, BusState *bus)
571f18e29fcSIgor Mammedov {
572f18e29fcSIgor Mammedov ICH9LPCState *lpc = ICH9_LPC_DEVICE(hotplug_dev);
573f18e29fcSIgor Mammedov return acpi_pcihp_is_hotpluggbale_bus(&lpc->pm.acpi_pci_hotplug, bus);
574f18e29fcSIgor Mammedov }
575f18e29fcSIgor Mammedov
ich9_pm_ospm_status(AcpiDeviceIf * adev,ACPIOSTInfoList *** list)57643f50410SIgor Mammedov void ich9_pm_ospm_status(AcpiDeviceIf *adev, ACPIOSTInfoList ***list)
57743f50410SIgor Mammedov {
57843f50410SIgor Mammedov ICH9LPCState *s = ICH9_LPC_DEVICE(adev);
57943f50410SIgor Mammedov
58043f50410SIgor Mammedov acpi_memory_ospm_status(&s->pm.acpi_memory_hotplug, list);
58176623d00SIgor Mammedov if (!s->pm.cpu_hotplug_legacy) {
58276623d00SIgor Mammedov acpi_cpu_ospm_status(&s->pm.cpuhp_state, list);
58376623d00SIgor Mammedov }
58443f50410SIgor Mammedov }
585