xref: /openbmc/qemu/hw/acpi/ich9.c (revision 51e72bc1)
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
1349ab747fSPaolo Bonzini  * License version 2 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  */
26b6a0aa05SPeter Maydell #include "qemu/osdep.h"
2749ab747fSPaolo Bonzini #include "hw/hw.h"
286f1426abSMichael S. Tsirkin #include "qapi/visitor.h"
2949ab747fSPaolo Bonzini #include "hw/i386/pc.h"
3049ab747fSPaolo Bonzini #include "hw/pci/pci.h"
3149ab747fSPaolo Bonzini #include "qemu/timer.h"
3249ab747fSPaolo Bonzini #include "sysemu/sysemu.h"
3349ab747fSPaolo Bonzini #include "hw/acpi/acpi.h"
3492055797SPaulo Alcantara #include "hw/acpi/tco.h"
3549ab747fSPaolo Bonzini #include "sysemu/kvm.h"
3649ab747fSPaolo Bonzini #include "exec/address-spaces.h"
3749ab747fSPaolo Bonzini 
3849ab747fSPaolo Bonzini #include "hw/i386/ich9.h"
391f862184SIgor Mammedov #include "hw/mem/pc-dimm.h"
4049ab747fSPaolo Bonzini 
4149ab747fSPaolo Bonzini //#define DEBUG
4249ab747fSPaolo Bonzini 
4349ab747fSPaolo Bonzini #ifdef DEBUG
4449ab747fSPaolo Bonzini #define ICH9_DEBUG(fmt, ...) \
4549ab747fSPaolo Bonzini do { printf("%s "fmt, __func__, ## __VA_ARGS__); } while (0)
4649ab747fSPaolo Bonzini #else
4749ab747fSPaolo Bonzini #define ICH9_DEBUG(fmt, ...)    do { } while (0)
4849ab747fSPaolo Bonzini #endif
4949ab747fSPaolo Bonzini 
5049ab747fSPaolo Bonzini static void ich9_pm_update_sci_fn(ACPIREGS *regs)
5149ab747fSPaolo Bonzini {
5249ab747fSPaolo Bonzini     ICH9LPCPMRegs *pm = container_of(regs, ICH9LPCPMRegs, acpi_regs);
5306313503SIgor Mammedov     acpi_update_sci(&pm->acpi_regs, pm->irq);
5449ab747fSPaolo Bonzini }
5549ab747fSPaolo Bonzini 
5649ab747fSPaolo Bonzini static uint64_t ich9_gpe_readb(void *opaque, hwaddr addr, unsigned width)
5749ab747fSPaolo Bonzini {
5849ab747fSPaolo Bonzini     ICH9LPCPMRegs *pm = opaque;
5949ab747fSPaolo Bonzini     return acpi_gpe_ioport_readb(&pm->acpi_regs, addr);
6049ab747fSPaolo Bonzini }
6149ab747fSPaolo Bonzini 
6249ab747fSPaolo Bonzini static void ich9_gpe_writeb(void *opaque, hwaddr addr, uint64_t val,
6349ab747fSPaolo Bonzini                             unsigned width)
6449ab747fSPaolo Bonzini {
6549ab747fSPaolo Bonzini     ICH9LPCPMRegs *pm = opaque;
6649ab747fSPaolo Bonzini     acpi_gpe_ioport_writeb(&pm->acpi_regs, addr, val);
672c047956SIgor Mammedov     acpi_update_sci(&pm->acpi_regs, pm->irq);
6849ab747fSPaolo Bonzini }
6949ab747fSPaolo Bonzini 
7049ab747fSPaolo Bonzini static const MemoryRegionOps ich9_gpe_ops = {
7149ab747fSPaolo Bonzini     .read = ich9_gpe_readb,
7249ab747fSPaolo Bonzini     .write = ich9_gpe_writeb,
7349ab747fSPaolo Bonzini     .valid.min_access_size = 1,
7449ab747fSPaolo Bonzini     .valid.max_access_size = 4,
7549ab747fSPaolo Bonzini     .impl.min_access_size = 1,
7649ab747fSPaolo Bonzini     .impl.max_access_size = 1,
7749ab747fSPaolo Bonzini     .endianness = DEVICE_LITTLE_ENDIAN,
7849ab747fSPaolo Bonzini };
7949ab747fSPaolo Bonzini 
8049ab747fSPaolo Bonzini static uint64_t ich9_smi_readl(void *opaque, hwaddr addr, unsigned width)
8149ab747fSPaolo Bonzini {
8249ab747fSPaolo Bonzini     ICH9LPCPMRegs *pm = opaque;
8349ab747fSPaolo Bonzini     switch (addr) {
8449ab747fSPaolo Bonzini     case 0:
8549ab747fSPaolo Bonzini         return pm->smi_en;
8649ab747fSPaolo Bonzini     case 4:
8749ab747fSPaolo Bonzini         return pm->smi_sts;
8849ab747fSPaolo Bonzini     default:
8949ab747fSPaolo Bonzini         return 0;
9049ab747fSPaolo Bonzini     }
9149ab747fSPaolo Bonzini }
9249ab747fSPaolo Bonzini 
9349ab747fSPaolo Bonzini static void ich9_smi_writel(void *opaque, hwaddr addr, uint64_t val,
9449ab747fSPaolo Bonzini                             unsigned width)
9549ab747fSPaolo Bonzini {
9649ab747fSPaolo Bonzini     ICH9LPCPMRegs *pm = opaque;
9792055797SPaulo Alcantara     TCOIORegs *tr = &pm->tco_regs;
9892055797SPaulo Alcantara     uint64_t tco_en;
9992055797SPaulo Alcantara 
10049ab747fSPaolo Bonzini     switch (addr) {
10149ab747fSPaolo Bonzini     case 0:
10292055797SPaulo Alcantara         tco_en = pm->smi_en & ICH9_PMIO_SMI_EN_TCO_EN;
10392055797SPaulo Alcantara         /* once TCO_LOCK bit is set, TCO_EN bit cannot be overwritten */
10492055797SPaulo Alcantara         if (tr->tco.cnt1 & TCO_LOCK) {
10592055797SPaulo Alcantara             val = (val & ~ICH9_PMIO_SMI_EN_TCO_EN) | tco_en;
10692055797SPaulo Alcantara         }
10711e66a15SGerd Hoffmann         pm->smi_en &= ~pm->smi_en_wmask;
10811e66a15SGerd Hoffmann         pm->smi_en |= (val & pm->smi_en_wmask);
10949ab747fSPaolo Bonzini         break;
11049ab747fSPaolo Bonzini     }
11149ab747fSPaolo Bonzini }
11249ab747fSPaolo Bonzini 
11349ab747fSPaolo Bonzini static const MemoryRegionOps ich9_smi_ops = {
11449ab747fSPaolo Bonzini     .read = ich9_smi_readl,
11549ab747fSPaolo Bonzini     .write = ich9_smi_writel,
11649ab747fSPaolo Bonzini     .valid.min_access_size = 4,
11749ab747fSPaolo Bonzini     .valid.max_access_size = 4,
11849ab747fSPaolo Bonzini     .endianness = DEVICE_LITTLE_ENDIAN,
11949ab747fSPaolo Bonzini };
12049ab747fSPaolo Bonzini 
12149ab747fSPaolo Bonzini void ich9_pm_iospace_update(ICH9LPCPMRegs *pm, uint32_t pm_io_base)
12249ab747fSPaolo Bonzini {
12349ab747fSPaolo Bonzini     ICH9_DEBUG("to 0x%x\n", pm_io_base);
12449ab747fSPaolo Bonzini 
12549ab747fSPaolo Bonzini     assert((pm_io_base & ICH9_PMIO_MASK) == 0);
12649ab747fSPaolo Bonzini 
12749ab747fSPaolo Bonzini     pm->pm_io_base = pm_io_base;
12849ab747fSPaolo Bonzini     memory_region_transaction_begin();
12949ab747fSPaolo Bonzini     memory_region_set_enabled(&pm->io, pm->pm_io_base != 0);
13049ab747fSPaolo Bonzini     memory_region_set_address(&pm->io, pm->pm_io_base);
13149ab747fSPaolo Bonzini     memory_region_transaction_commit();
13249ab747fSPaolo Bonzini }
13349ab747fSPaolo Bonzini 
13449ab747fSPaolo Bonzini static int ich9_pm_post_load(void *opaque, int version_id)
13549ab747fSPaolo Bonzini {
13649ab747fSPaolo Bonzini     ICH9LPCPMRegs *pm = opaque;
13749ab747fSPaolo Bonzini     uint32_t pm_io_base = pm->pm_io_base;
13849ab747fSPaolo Bonzini     pm->pm_io_base = 0;
13949ab747fSPaolo Bonzini     ich9_pm_iospace_update(pm, pm_io_base);
14049ab747fSPaolo Bonzini     return 0;
14149ab747fSPaolo Bonzini }
14249ab747fSPaolo Bonzini 
14349ab747fSPaolo Bonzini #define VMSTATE_GPE_ARRAY(_field, _state)                            \
14449ab747fSPaolo Bonzini  {                                                                   \
14549ab747fSPaolo Bonzini      .name       = (stringify(_field)),                              \
14649ab747fSPaolo Bonzini      .version_id = 0,                                                \
14749ab747fSPaolo Bonzini      .num        = ICH9_PMIO_GPE0_LEN,                               \
14849ab747fSPaolo Bonzini      .info       = &vmstate_info_uint8,                              \
14949ab747fSPaolo Bonzini      .size       = sizeof(uint8_t),                                  \
15049ab747fSPaolo Bonzini      .flags      = VMS_ARRAY | VMS_POINTER,                          \
15149ab747fSPaolo Bonzini      .offset     = vmstate_offset_pointer(_state, _field, uint8_t),  \
15249ab747fSPaolo Bonzini  }
15349ab747fSPaolo Bonzini 
154f816a62dSIgor Mammedov static bool vmstate_test_use_memhp(void *opaque)
155f816a62dSIgor Mammedov {
156f816a62dSIgor Mammedov     ICH9LPCPMRegs *s = opaque;
157f816a62dSIgor Mammedov     return s->acpi_memory_hotplug.is_enabled;
158f816a62dSIgor Mammedov }
159f816a62dSIgor Mammedov 
160f816a62dSIgor Mammedov static const VMStateDescription vmstate_memhp_state = {
161f816a62dSIgor Mammedov     .name = "ich9_pm/memhp",
162f816a62dSIgor Mammedov     .version_id = 1,
163f816a62dSIgor Mammedov     .minimum_version_id = 1,
164f816a62dSIgor Mammedov     .minimum_version_id_old = 1,
1655cd8cadaSJuan Quintela     .needed = vmstate_test_use_memhp,
166f816a62dSIgor Mammedov     .fields      = (VMStateField[]) {
167f816a62dSIgor Mammedov         VMSTATE_MEMORY_HOTPLUG(acpi_memory_hotplug, ICH9LPCPMRegs),
168f816a62dSIgor Mammedov         VMSTATE_END_OF_LIST()
169f816a62dSIgor Mammedov     }
170f816a62dSIgor Mammedov };
171f816a62dSIgor Mammedov 
17292055797SPaulo Alcantara static bool vmstate_test_use_tco(void *opaque)
17392055797SPaulo Alcantara {
17492055797SPaulo Alcantara     ICH9LPCPMRegs *s = opaque;
17592055797SPaulo Alcantara     return s->enable_tco;
17692055797SPaulo Alcantara }
17792055797SPaulo Alcantara 
17892055797SPaulo Alcantara static const VMStateDescription vmstate_tco_io_state = {
17992055797SPaulo Alcantara     .name = "ich9_pm/tco",
18092055797SPaulo Alcantara     .version_id = 1,
18192055797SPaulo Alcantara     .minimum_version_id = 1,
18292055797SPaulo Alcantara     .minimum_version_id_old = 1,
18392055797SPaulo Alcantara     .needed = vmstate_test_use_tco,
18492055797SPaulo Alcantara     .fields      = (VMStateField[]) {
18592055797SPaulo Alcantara         VMSTATE_STRUCT(tco_regs, ICH9LPCPMRegs, 1, vmstate_tco_io_sts,
18692055797SPaulo Alcantara                        TCOIORegs),
18792055797SPaulo Alcantara         VMSTATE_END_OF_LIST()
18892055797SPaulo Alcantara     }
18992055797SPaulo Alcantara };
19092055797SPaulo Alcantara 
19149ab747fSPaolo Bonzini const VMStateDescription vmstate_ich9_pm = {
19249ab747fSPaolo Bonzini     .name = "ich9_pm",
19349ab747fSPaolo Bonzini     .version_id = 1,
19449ab747fSPaolo Bonzini     .minimum_version_id = 1,
19549ab747fSPaolo Bonzini     .post_load = ich9_pm_post_load,
19649ab747fSPaolo Bonzini     .fields = (VMStateField[]) {
19749ab747fSPaolo Bonzini         VMSTATE_UINT16(acpi_regs.pm1.evt.sts, ICH9LPCPMRegs),
19849ab747fSPaolo Bonzini         VMSTATE_UINT16(acpi_regs.pm1.evt.en, ICH9LPCPMRegs),
19949ab747fSPaolo Bonzini         VMSTATE_UINT16(acpi_regs.pm1.cnt.cnt, ICH9LPCPMRegs),
200e720677eSPaolo Bonzini         VMSTATE_TIMER_PTR(acpi_regs.tmr.timer, ICH9LPCPMRegs),
20149ab747fSPaolo Bonzini         VMSTATE_INT64(acpi_regs.tmr.overflow_time, ICH9LPCPMRegs),
20249ab747fSPaolo Bonzini         VMSTATE_GPE_ARRAY(acpi_regs.gpe.sts, ICH9LPCPMRegs),
20349ab747fSPaolo Bonzini         VMSTATE_GPE_ARRAY(acpi_regs.gpe.en, ICH9LPCPMRegs),
20449ab747fSPaolo Bonzini         VMSTATE_UINT32(smi_en, ICH9LPCPMRegs),
20549ab747fSPaolo Bonzini         VMSTATE_UINT32(smi_sts, ICH9LPCPMRegs),
20649ab747fSPaolo Bonzini         VMSTATE_END_OF_LIST()
207f816a62dSIgor Mammedov     },
2085cd8cadaSJuan Quintela     .subsections = (const VMStateDescription*[]) {
2095cd8cadaSJuan Quintela         &vmstate_memhp_state,
21092055797SPaulo Alcantara         &vmstate_tco_io_state,
21192055797SPaulo Alcantara         NULL
21249ab747fSPaolo Bonzini     }
21349ab747fSPaolo Bonzini };
21449ab747fSPaolo Bonzini 
21549ab747fSPaolo Bonzini static void pm_reset(void *opaque)
21649ab747fSPaolo Bonzini {
21749ab747fSPaolo Bonzini     ICH9LPCPMRegs *pm = opaque;
21849ab747fSPaolo Bonzini     ich9_pm_iospace_update(pm, 0);
21949ab747fSPaolo Bonzini 
22049ab747fSPaolo Bonzini     acpi_pm1_evt_reset(&pm->acpi_regs);
22149ab747fSPaolo Bonzini     acpi_pm1_cnt_reset(&pm->acpi_regs);
22249ab747fSPaolo Bonzini     acpi_pm_tmr_reset(&pm->acpi_regs);
22349ab747fSPaolo Bonzini     acpi_gpe_reset(&pm->acpi_regs);
22449ab747fSPaolo Bonzini 
225be66680eSLaszlo Ersek     pm->smi_en = 0;
226fba72476SPaolo Bonzini     if (!pm->smm_enabled) {
227f3c30aeaSLaszlo Ersek         /* Mark SMM as already inited to prevent SMM from running. */
22849ab747fSPaolo Bonzini         pm->smi_en |= ICH9_PMIO_SMI_EN_APMC_EN;
22949ab747fSPaolo Bonzini     }
23011e66a15SGerd Hoffmann     pm->smi_en_wmask = ~0;
23149ab747fSPaolo Bonzini 
23206313503SIgor Mammedov     acpi_update_sci(&pm->acpi_regs, pm->irq);
23349ab747fSPaolo Bonzini }
23449ab747fSPaolo Bonzini 
23549ab747fSPaolo Bonzini static void pm_powerdown_req(Notifier *n, void *opaque)
23649ab747fSPaolo Bonzini {
23749ab747fSPaolo Bonzini     ICH9LPCPMRegs *pm = container_of(n, ICH9LPCPMRegs, powerdown_notifier);
23849ab747fSPaolo Bonzini 
23949ab747fSPaolo Bonzini     acpi_pm1_evt_power_down(&pm->acpi_regs);
24049ab747fSPaolo Bonzini }
24149ab747fSPaolo Bonzini 
24292055797SPaulo Alcantara void ich9_pm_init(PCIDevice *lpc_pci, ICH9LPCPMRegs *pm,
24392055797SPaulo Alcantara                   bool smm_enabled, bool enable_tco,
244a3ac6b53SHu Tao                   qemu_irq sci_irq)
24549ab747fSPaolo Bonzini {
24664bde0f3SPaolo Bonzini     memory_region_init(&pm->io, OBJECT(lpc_pci), "ich9-pm", ICH9_PMIO_SIZE);
24749ab747fSPaolo Bonzini     memory_region_set_enabled(&pm->io, false);
24849ab747fSPaolo Bonzini     memory_region_add_subregion(pci_address_space_io(lpc_pci),
24949ab747fSPaolo Bonzini                                 0, &pm->io);
25049ab747fSPaolo Bonzini 
25149ab747fSPaolo Bonzini     acpi_pm_tmr_init(&pm->acpi_regs, ich9_pm_update_sci_fn, &pm->io);
25249ab747fSPaolo Bonzini     acpi_pm1_evt_init(&pm->acpi_regs, ich9_pm_update_sci_fn, &pm->io);
2539a10bbb4SLaszlo Ersek     acpi_pm1_cnt_init(&pm->acpi_regs, &pm->io, pm->disable_s3, pm->disable_s4,
2549a10bbb4SLaszlo Ersek                       pm->s4_val);
25549ab747fSPaolo Bonzini 
25649ab747fSPaolo Bonzini     acpi_gpe_init(&pm->acpi_regs, ICH9_PMIO_GPE0_LEN);
25764bde0f3SPaolo Bonzini     memory_region_init_io(&pm->io_gpe, OBJECT(lpc_pci), &ich9_gpe_ops, pm,
25875902802SHu Tao                           "acpi-gpe0", ICH9_PMIO_GPE0_LEN);
25949ab747fSPaolo Bonzini     memory_region_add_subregion(&pm->io, ICH9_PMIO_GPE0_STS, &pm->io_gpe);
26049ab747fSPaolo Bonzini 
26164bde0f3SPaolo Bonzini     memory_region_init_io(&pm->io_smi, OBJECT(lpc_pci), &ich9_smi_ops, pm,
26275902802SHu Tao                           "acpi-smi", 8);
26349ab747fSPaolo Bonzini     memory_region_add_subregion(&pm->io, ICH9_PMIO_SMI_EN, &pm->io_smi);
26449ab747fSPaolo Bonzini 
265fba72476SPaolo Bonzini     pm->smm_enabled = smm_enabled;
26692055797SPaulo Alcantara 
26792055797SPaulo Alcantara     pm->enable_tco = enable_tco;
26892055797SPaulo Alcantara     if (pm->enable_tco) {
26992055797SPaulo Alcantara         acpi_pm_tco_init(&pm->tco_regs, &pm->io);
27092055797SPaulo Alcantara     }
27192055797SPaulo Alcantara 
27249ab747fSPaolo Bonzini     pm->irq = sci_irq;
27349ab747fSPaolo Bonzini     qemu_register_reset(pm_reset, pm);
27449ab747fSPaolo Bonzini     pm->powerdown_notifier.notify = pm_powerdown_req;
27549ab747fSPaolo Bonzini     qemu_register_powerdown_notifier(&pm->powerdown_notifier);
276d6610bc2SIgor Mammedov 
277411b5db8SGu Zheng     acpi_cpu_hotplug_init(pci_address_space_io(lpc_pci), OBJECT(lpc_pci),
278d6610bc2SIgor Mammedov                           &pm->gpe_cpu, ICH9_CPU_HOTPLUG_IO_BASE);
2791f862184SIgor Mammedov 
2801f862184SIgor Mammedov     if (pm->acpi_memory_hotplug.is_enabled) {
2811f862184SIgor Mammedov         acpi_memory_hotplug_init(pci_address_space_io(lpc_pci), OBJECT(lpc_pci),
2821f862184SIgor Mammedov                                  &pm->acpi_memory_hotplug);
2831f862184SIgor Mammedov     }
28449ab747fSPaolo Bonzini }
2856f1426abSMichael S. Tsirkin 
2866f1426abSMichael S. Tsirkin static void ich9_pm_get_gpe0_blk(Object *obj, Visitor *v,
2876f1426abSMichael S. Tsirkin                                  void *opaque, const char *name,
2886f1426abSMichael S. Tsirkin                                  Error **errp)
2896f1426abSMichael S. Tsirkin {
2906f1426abSMichael S. Tsirkin     ICH9LPCPMRegs *pm = opaque;
2916f1426abSMichael S. Tsirkin     uint32_t value = pm->pm_io_base + ICH9_PMIO_GPE0_STS;
2926f1426abSMichael S. Tsirkin 
293*51e72bc1SEric Blake     visit_type_uint32(v, name, &value, errp);
2946f1426abSMichael S. Tsirkin }
2956f1426abSMichael S. Tsirkin 
2961f862184SIgor Mammedov static bool ich9_pm_get_memory_hotplug_support(Object *obj, Error **errp)
2971f862184SIgor Mammedov {
2981f862184SIgor Mammedov     ICH9LPCState *s = ICH9_LPC_DEVICE(obj);
2991f862184SIgor Mammedov 
3001f862184SIgor Mammedov     return s->pm.acpi_memory_hotplug.is_enabled;
3011f862184SIgor Mammedov }
3021f862184SIgor Mammedov 
3031f862184SIgor Mammedov static void ich9_pm_set_memory_hotplug_support(Object *obj, bool value,
3041f862184SIgor Mammedov                                                Error **errp)
3051f862184SIgor Mammedov {
3061f862184SIgor Mammedov     ICH9LPCState *s = ICH9_LPC_DEVICE(obj);
3071f862184SIgor Mammedov 
3081f862184SIgor Mammedov     s->pm.acpi_memory_hotplug.is_enabled = value;
3091f862184SIgor Mammedov }
3101f862184SIgor Mammedov 
3116ac0d8d4SAmit Shah static void ich9_pm_get_disable_s3(Object *obj, Visitor *v,
3126ac0d8d4SAmit Shah                                    void *opaque, const char *name,
3136ac0d8d4SAmit Shah                                    Error **errp)
3146ac0d8d4SAmit Shah {
3156ac0d8d4SAmit Shah     ICH9LPCPMRegs *pm = opaque;
3166ac0d8d4SAmit Shah     uint8_t value = pm->disable_s3;
3176ac0d8d4SAmit Shah 
318*51e72bc1SEric Blake     visit_type_uint8(v, name, &value, errp);
3196ac0d8d4SAmit Shah }
3206ac0d8d4SAmit Shah 
3216ac0d8d4SAmit Shah static void ich9_pm_set_disable_s3(Object *obj, Visitor *v,
3226ac0d8d4SAmit Shah                                    void *opaque, const char *name,
3236ac0d8d4SAmit Shah                                    Error **errp)
3246ac0d8d4SAmit Shah {
3256ac0d8d4SAmit Shah     ICH9LPCPMRegs *pm = opaque;
3266ac0d8d4SAmit Shah     Error *local_err = NULL;
3276ac0d8d4SAmit Shah     uint8_t value;
3286ac0d8d4SAmit Shah 
329*51e72bc1SEric Blake     visit_type_uint8(v, name, &value, &local_err);
3306ac0d8d4SAmit Shah     if (local_err) {
3316ac0d8d4SAmit Shah         goto out;
3326ac0d8d4SAmit Shah     }
3336ac0d8d4SAmit Shah     pm->disable_s3 = value;
3346ac0d8d4SAmit Shah out:
3356ac0d8d4SAmit Shah     error_propagate(errp, local_err);
3366ac0d8d4SAmit Shah }
3376ac0d8d4SAmit Shah 
3386ac0d8d4SAmit Shah static void ich9_pm_get_disable_s4(Object *obj, Visitor *v,
3396ac0d8d4SAmit Shah                                    void *opaque, const char *name,
3406ac0d8d4SAmit Shah                                    Error **errp)
3416ac0d8d4SAmit Shah {
3426ac0d8d4SAmit Shah     ICH9LPCPMRegs *pm = opaque;
3436ac0d8d4SAmit Shah     uint8_t value = pm->disable_s4;
3446ac0d8d4SAmit Shah 
345*51e72bc1SEric Blake     visit_type_uint8(v, name, &value, errp);
3466ac0d8d4SAmit Shah }
3476ac0d8d4SAmit Shah 
3486ac0d8d4SAmit Shah static void ich9_pm_set_disable_s4(Object *obj, Visitor *v,
3496ac0d8d4SAmit Shah                                    void *opaque, const char *name,
3506ac0d8d4SAmit Shah                                    Error **errp)
3516ac0d8d4SAmit Shah {
3526ac0d8d4SAmit Shah     ICH9LPCPMRegs *pm = opaque;
3536ac0d8d4SAmit Shah     Error *local_err = NULL;
3546ac0d8d4SAmit Shah     uint8_t value;
3556ac0d8d4SAmit Shah 
356*51e72bc1SEric Blake     visit_type_uint8(v, name, &value, &local_err);
3576ac0d8d4SAmit Shah     if (local_err) {
3586ac0d8d4SAmit Shah         goto out;
3596ac0d8d4SAmit Shah     }
3606ac0d8d4SAmit Shah     pm->disable_s4 = value;
3616ac0d8d4SAmit Shah out:
3626ac0d8d4SAmit Shah     error_propagate(errp, local_err);
3636ac0d8d4SAmit Shah }
3646ac0d8d4SAmit Shah 
3656ac0d8d4SAmit Shah static void ich9_pm_get_s4_val(Object *obj, Visitor *v,
3666ac0d8d4SAmit Shah                                void *opaque, const char *name,
3676ac0d8d4SAmit Shah                                Error **errp)
3686ac0d8d4SAmit Shah {
3696ac0d8d4SAmit Shah     ICH9LPCPMRegs *pm = opaque;
3706ac0d8d4SAmit Shah     uint8_t value = pm->s4_val;
3716ac0d8d4SAmit Shah 
372*51e72bc1SEric Blake     visit_type_uint8(v, name, &value, errp);
3736ac0d8d4SAmit Shah }
3746ac0d8d4SAmit Shah 
3756ac0d8d4SAmit Shah static void ich9_pm_set_s4_val(Object *obj, Visitor *v,
3766ac0d8d4SAmit Shah                                void *opaque, const char *name,
3776ac0d8d4SAmit Shah                                Error **errp)
3786ac0d8d4SAmit Shah {
3796ac0d8d4SAmit Shah     ICH9LPCPMRegs *pm = opaque;
3806ac0d8d4SAmit Shah     Error *local_err = NULL;
3816ac0d8d4SAmit Shah     uint8_t value;
3826ac0d8d4SAmit Shah 
383*51e72bc1SEric Blake     visit_type_uint8(v, name, &value, &local_err);
3846ac0d8d4SAmit Shah     if (local_err) {
3856ac0d8d4SAmit Shah         goto out;
3866ac0d8d4SAmit Shah     }
3876ac0d8d4SAmit Shah     pm->s4_val = value;
3886ac0d8d4SAmit Shah out:
3896ac0d8d4SAmit Shah     error_propagate(errp, local_err);
3906ac0d8d4SAmit Shah }
3916ac0d8d4SAmit Shah 
39292055797SPaulo Alcantara static bool ich9_pm_get_enable_tco(Object *obj, Error **errp)
39392055797SPaulo Alcantara {
39492055797SPaulo Alcantara     ICH9LPCState *s = ICH9_LPC_DEVICE(obj);
39592055797SPaulo Alcantara     return s->pm.enable_tco;
39692055797SPaulo Alcantara }
39792055797SPaulo Alcantara 
39892055797SPaulo Alcantara static void ich9_pm_set_enable_tco(Object *obj, bool value, Error **errp)
39992055797SPaulo Alcantara {
40092055797SPaulo Alcantara     ICH9LPCState *s = ICH9_LPC_DEVICE(obj);
40192055797SPaulo Alcantara     s->pm.enable_tco = value;
40292055797SPaulo Alcantara }
40392055797SPaulo Alcantara 
4046f1426abSMichael S. Tsirkin void ich9_pm_add_properties(Object *obj, ICH9LPCPMRegs *pm, Error **errp)
4056f1426abSMichael S. Tsirkin {
4066f1426abSMichael S. Tsirkin     static const uint32_t gpe0_len = ICH9_PMIO_GPE0_LEN;
4071f862184SIgor Mammedov     pm->acpi_memory_hotplug.is_enabled = true;
4086ac0d8d4SAmit Shah     pm->disable_s3 = 0;
4096ac0d8d4SAmit Shah     pm->disable_s4 = 0;
4106ac0d8d4SAmit Shah     pm->s4_val = 2;
4116f1426abSMichael S. Tsirkin 
4126f1426abSMichael S. Tsirkin     object_property_add_uint32_ptr(obj, ACPI_PM_PROP_PM_IO_BASE,
4136f1426abSMichael S. Tsirkin                                    &pm->pm_io_base, errp);
4146f1426abSMichael S. Tsirkin     object_property_add(obj, ACPI_PM_PROP_GPE0_BLK, "uint32",
4156f1426abSMichael S. Tsirkin                         ich9_pm_get_gpe0_blk,
4166f1426abSMichael S. Tsirkin                         NULL, NULL, pm, NULL);
4176f1426abSMichael S. Tsirkin     object_property_add_uint32_ptr(obj, ACPI_PM_PROP_GPE0_BLK_LEN,
4186f1426abSMichael S. Tsirkin                                    &gpe0_len, errp);
4191f862184SIgor Mammedov     object_property_add_bool(obj, "memory-hotplug-support",
4201f862184SIgor Mammedov                              ich9_pm_get_memory_hotplug_support,
4211f862184SIgor Mammedov                              ich9_pm_set_memory_hotplug_support,
4221f862184SIgor Mammedov                              NULL);
4236ac0d8d4SAmit Shah     object_property_add(obj, ACPI_PM_PROP_S3_DISABLED, "uint8",
4246ac0d8d4SAmit Shah                         ich9_pm_get_disable_s3,
4256ac0d8d4SAmit Shah                         ich9_pm_set_disable_s3,
4266ac0d8d4SAmit Shah                         NULL, pm, NULL);
4276ac0d8d4SAmit Shah     object_property_add(obj, ACPI_PM_PROP_S4_DISABLED, "uint8",
4286ac0d8d4SAmit Shah                         ich9_pm_get_disable_s4,
4296ac0d8d4SAmit Shah                         ich9_pm_set_disable_s4,
4306ac0d8d4SAmit Shah                         NULL, pm, NULL);
4316ac0d8d4SAmit Shah     object_property_add(obj, ACPI_PM_PROP_S4_VAL, "uint8",
4326ac0d8d4SAmit Shah                         ich9_pm_get_s4_val,
4336ac0d8d4SAmit Shah                         ich9_pm_set_s4_val,
4346ac0d8d4SAmit Shah                         NULL, pm, NULL);
43592055797SPaulo Alcantara     object_property_add_bool(obj, ACPI_PM_PROP_TCO_ENABLED,
43692055797SPaulo Alcantara                              ich9_pm_get_enable_tco,
43792055797SPaulo Alcantara                              ich9_pm_set_enable_tco,
43892055797SPaulo Alcantara                              NULL);
4391f862184SIgor Mammedov }
4401f862184SIgor Mammedov 
4411f862184SIgor Mammedov void ich9_pm_device_plug_cb(ICH9LPCPMRegs *pm, DeviceState *dev, Error **errp)
4421f862184SIgor Mammedov {
4431f862184SIgor Mammedov     if (pm->acpi_memory_hotplug.is_enabled &&
4441f862184SIgor Mammedov         object_dynamic_cast(OBJECT(dev), TYPE_PC_DIMM)) {
4451f862184SIgor Mammedov         acpi_memory_plug_cb(&pm->acpi_regs, pm->irq, &pm->acpi_memory_hotplug,
4461f862184SIgor Mammedov                             dev, errp);
447c5171ed0SGu Zheng     } else if (object_dynamic_cast(OBJECT(dev), TYPE_CPU)) {
448c5171ed0SGu Zheng         acpi_cpu_plug_cb(&pm->acpi_regs, pm->irq, &pm->gpe_cpu, dev, errp);
4491f862184SIgor Mammedov     } else {
4501f862184SIgor Mammedov         error_setg(errp, "acpi: device plug request for not supported device"
4511f862184SIgor Mammedov                    " type: %s", object_get_typename(OBJECT(dev)));
4521f862184SIgor Mammedov     }
4536f1426abSMichael S. Tsirkin }
45443f50410SIgor Mammedov 
455469b8ad2STang Chen void ich9_pm_device_unplug_request_cb(ICH9LPCPMRegs *pm, DeviceState *dev,
456469b8ad2STang Chen                                       Error **errp)
457469b8ad2STang Chen {
45864fec58eSTang Chen     if (pm->acpi_memory_hotplug.is_enabled &&
45964fec58eSTang Chen         object_dynamic_cast(OBJECT(dev), TYPE_PC_DIMM)) {
46064fec58eSTang Chen         acpi_memory_unplug_request_cb(&pm->acpi_regs, pm->irq,
46164fec58eSTang Chen                                       &pm->acpi_memory_hotplug, dev, errp);
46264fec58eSTang Chen     } else {
463469b8ad2STang Chen         error_setg(errp, "acpi: device unplug request for not supported device"
464469b8ad2STang Chen                    " type: %s", object_get_typename(OBJECT(dev)));
465469b8ad2STang Chen     }
46664fec58eSTang Chen }
467469b8ad2STang Chen 
46891a734a6STang Chen void ich9_pm_device_unplug_cb(ICH9LPCPMRegs *pm, DeviceState *dev,
46991a734a6STang Chen                               Error **errp)
47091a734a6STang Chen {
471f7d3e29dSTang Chen     if (pm->acpi_memory_hotplug.is_enabled &&
472f7d3e29dSTang Chen         object_dynamic_cast(OBJECT(dev), TYPE_PC_DIMM)) {
473f7d3e29dSTang Chen         acpi_memory_unplug_cb(&pm->acpi_memory_hotplug, dev, errp);
474f7d3e29dSTang Chen     } else {
47591a734a6STang Chen         error_setg(errp, "acpi: device unplug for not supported device"
47691a734a6STang Chen                    " type: %s", object_get_typename(OBJECT(dev)));
47791a734a6STang Chen     }
478f7d3e29dSTang Chen }
47991a734a6STang Chen 
48043f50410SIgor Mammedov void ich9_pm_ospm_status(AcpiDeviceIf *adev, ACPIOSTInfoList ***list)
48143f50410SIgor Mammedov {
48243f50410SIgor Mammedov     ICH9LPCState *s = ICH9_LPC_DEVICE(adev);
48343f50410SIgor Mammedov 
48443f50410SIgor Mammedov     acpi_memory_ospm_status(&s->pm.acpi_memory_hotplug, list);
48543f50410SIgor Mammedov }
486