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