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" 3792055797SPaulo Alcantara #include "hw/acpi/tco.h" 3849ab747fSPaolo Bonzini #include "exec/address-spaces.h" 3949ab747fSPaolo Bonzini 4049ab747fSPaolo Bonzini #include "hw/i386/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 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 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 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 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 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); 11249ab747fSPaolo Bonzini break; 11349ab747fSPaolo Bonzini } 11449ab747fSPaolo Bonzini } 11549ab747fSPaolo Bonzini 11649ab747fSPaolo Bonzini static const MemoryRegionOps ich9_smi_ops = { 11749ab747fSPaolo Bonzini .read = ich9_smi_readl, 11849ab747fSPaolo Bonzini .write = ich9_smi_writel, 11949ab747fSPaolo Bonzini .valid.min_access_size = 4, 12049ab747fSPaolo Bonzini .valid.max_access_size = 4, 12149ab747fSPaolo Bonzini .endianness = DEVICE_LITTLE_ENDIAN, 12249ab747fSPaolo Bonzini }; 12349ab747fSPaolo Bonzini 12449ab747fSPaolo Bonzini void ich9_pm_iospace_update(ICH9LPCPMRegs *pm, uint32_t pm_io_base) 12549ab747fSPaolo Bonzini { 12649ab747fSPaolo Bonzini ICH9_DEBUG("to 0x%x\n", pm_io_base); 12749ab747fSPaolo Bonzini 12849ab747fSPaolo Bonzini assert((pm_io_base & ICH9_PMIO_MASK) == 0); 12949ab747fSPaolo Bonzini 13049ab747fSPaolo Bonzini pm->pm_io_base = pm_io_base; 13149ab747fSPaolo Bonzini memory_region_transaction_begin(); 13249ab747fSPaolo Bonzini memory_region_set_enabled(&pm->io, pm->pm_io_base != 0); 13349ab747fSPaolo Bonzini memory_region_set_address(&pm->io, pm->pm_io_base); 13449ab747fSPaolo Bonzini memory_region_transaction_commit(); 13549ab747fSPaolo Bonzini } 13649ab747fSPaolo Bonzini 13749ab747fSPaolo Bonzini static int ich9_pm_post_load(void *opaque, int version_id) 13849ab747fSPaolo Bonzini { 13949ab747fSPaolo Bonzini ICH9LPCPMRegs *pm = opaque; 14049ab747fSPaolo Bonzini uint32_t pm_io_base = pm->pm_io_base; 14149ab747fSPaolo Bonzini pm->pm_io_base = 0; 14249ab747fSPaolo Bonzini ich9_pm_iospace_update(pm, pm_io_base); 14349ab747fSPaolo Bonzini return 0; 14449ab747fSPaolo Bonzini } 14549ab747fSPaolo Bonzini 14649ab747fSPaolo Bonzini #define VMSTATE_GPE_ARRAY(_field, _state) \ 14749ab747fSPaolo Bonzini { \ 14849ab747fSPaolo Bonzini .name = (stringify(_field)), \ 14949ab747fSPaolo Bonzini .version_id = 0, \ 15049ab747fSPaolo Bonzini .num = ICH9_PMIO_GPE0_LEN, \ 15149ab747fSPaolo Bonzini .info = &vmstate_info_uint8, \ 15249ab747fSPaolo Bonzini .size = sizeof(uint8_t), \ 15349ab747fSPaolo Bonzini .flags = VMS_ARRAY | VMS_POINTER, \ 15449ab747fSPaolo Bonzini .offset = vmstate_offset_pointer(_state, _field, uint8_t), \ 15549ab747fSPaolo Bonzini } 15649ab747fSPaolo Bonzini 157f816a62dSIgor Mammedov static bool vmstate_test_use_memhp(void *opaque) 158f816a62dSIgor Mammedov { 159f816a62dSIgor Mammedov ICH9LPCPMRegs *s = opaque; 160f816a62dSIgor Mammedov return s->acpi_memory_hotplug.is_enabled; 161f816a62dSIgor Mammedov } 162f816a62dSIgor Mammedov 163f816a62dSIgor Mammedov static const VMStateDescription vmstate_memhp_state = { 164f816a62dSIgor Mammedov .name = "ich9_pm/memhp", 165f816a62dSIgor Mammedov .version_id = 1, 166f816a62dSIgor Mammedov .minimum_version_id = 1, 167f816a62dSIgor Mammedov .minimum_version_id_old = 1, 1685cd8cadaSJuan Quintela .needed = vmstate_test_use_memhp, 169f816a62dSIgor Mammedov .fields = (VMStateField[]) { 170f816a62dSIgor Mammedov VMSTATE_MEMORY_HOTPLUG(acpi_memory_hotplug, ICH9LPCPMRegs), 171f816a62dSIgor Mammedov VMSTATE_END_OF_LIST() 172f816a62dSIgor Mammedov } 173f816a62dSIgor Mammedov }; 174f816a62dSIgor Mammedov 17592055797SPaulo Alcantara static bool vmstate_test_use_tco(void *opaque) 17692055797SPaulo Alcantara { 17792055797SPaulo Alcantara ICH9LPCPMRegs *s = opaque; 17892055797SPaulo Alcantara return s->enable_tco; 17992055797SPaulo Alcantara } 18092055797SPaulo Alcantara 18192055797SPaulo Alcantara static const VMStateDescription vmstate_tco_io_state = { 18292055797SPaulo Alcantara .name = "ich9_pm/tco", 18392055797SPaulo Alcantara .version_id = 1, 18492055797SPaulo Alcantara .minimum_version_id = 1, 18592055797SPaulo Alcantara .minimum_version_id_old = 1, 18692055797SPaulo Alcantara .needed = vmstate_test_use_tco, 18792055797SPaulo Alcantara .fields = (VMStateField[]) { 18892055797SPaulo Alcantara VMSTATE_STRUCT(tco_regs, ICH9LPCPMRegs, 1, vmstate_tco_io_sts, 18992055797SPaulo Alcantara TCOIORegs), 19092055797SPaulo Alcantara VMSTATE_END_OF_LIST() 19192055797SPaulo Alcantara } 19292055797SPaulo Alcantara }; 19392055797SPaulo Alcantara 194679dd1a9SIgor Mammedov static bool vmstate_test_use_cpuhp(void *opaque) 195679dd1a9SIgor Mammedov { 196679dd1a9SIgor Mammedov ICH9LPCPMRegs *s = opaque; 197679dd1a9SIgor Mammedov return !s->cpu_hotplug_legacy; 198679dd1a9SIgor Mammedov } 199679dd1a9SIgor Mammedov 200679dd1a9SIgor Mammedov static int vmstate_cpuhp_pre_load(void *opaque) 201679dd1a9SIgor Mammedov { 202679dd1a9SIgor Mammedov ICH9LPCPMRegs *s = opaque; 203679dd1a9SIgor Mammedov Object *obj = OBJECT(s->gpe_cpu.device); 2045325cc34SMarkus Armbruster object_property_set_bool(obj, "cpu-hotplug-legacy", false, &error_abort); 205679dd1a9SIgor Mammedov return 0; 206679dd1a9SIgor Mammedov } 207679dd1a9SIgor Mammedov 208679dd1a9SIgor Mammedov static const VMStateDescription vmstate_cpuhp_state = { 209679dd1a9SIgor Mammedov .name = "ich9_pm/cpuhp", 210679dd1a9SIgor Mammedov .version_id = 1, 211679dd1a9SIgor Mammedov .minimum_version_id = 1, 212679dd1a9SIgor Mammedov .minimum_version_id_old = 1, 213679dd1a9SIgor Mammedov .needed = vmstate_test_use_cpuhp, 214679dd1a9SIgor Mammedov .pre_load = vmstate_cpuhp_pre_load, 215679dd1a9SIgor Mammedov .fields = (VMStateField[]) { 216679dd1a9SIgor Mammedov VMSTATE_CPU_HOTPLUG(cpuhp_state, ICH9LPCPMRegs), 217679dd1a9SIgor Mammedov VMSTATE_END_OF_LIST() 218679dd1a9SIgor Mammedov } 219679dd1a9SIgor Mammedov }; 220679dd1a9SIgor Mammedov 22149ab747fSPaolo Bonzini const VMStateDescription vmstate_ich9_pm = { 22249ab747fSPaolo Bonzini .name = "ich9_pm", 22349ab747fSPaolo Bonzini .version_id = 1, 22449ab747fSPaolo Bonzini .minimum_version_id = 1, 22549ab747fSPaolo Bonzini .post_load = ich9_pm_post_load, 22649ab747fSPaolo Bonzini .fields = (VMStateField[]) { 22749ab747fSPaolo Bonzini VMSTATE_UINT16(acpi_regs.pm1.evt.sts, ICH9LPCPMRegs), 22849ab747fSPaolo Bonzini VMSTATE_UINT16(acpi_regs.pm1.evt.en, ICH9LPCPMRegs), 22949ab747fSPaolo Bonzini VMSTATE_UINT16(acpi_regs.pm1.cnt.cnt, ICH9LPCPMRegs), 230e720677eSPaolo Bonzini VMSTATE_TIMER_PTR(acpi_regs.tmr.timer, ICH9LPCPMRegs), 23149ab747fSPaolo Bonzini VMSTATE_INT64(acpi_regs.tmr.overflow_time, ICH9LPCPMRegs), 23249ab747fSPaolo Bonzini VMSTATE_GPE_ARRAY(acpi_regs.gpe.sts, ICH9LPCPMRegs), 23349ab747fSPaolo Bonzini VMSTATE_GPE_ARRAY(acpi_regs.gpe.en, ICH9LPCPMRegs), 23449ab747fSPaolo Bonzini VMSTATE_UINT32(smi_en, ICH9LPCPMRegs), 23549ab747fSPaolo Bonzini VMSTATE_UINT32(smi_sts, ICH9LPCPMRegs), 23649ab747fSPaolo Bonzini VMSTATE_END_OF_LIST() 237f816a62dSIgor Mammedov }, 2385cd8cadaSJuan Quintela .subsections = (const VMStateDescription*[]) { 2395cd8cadaSJuan Quintela &vmstate_memhp_state, 24092055797SPaulo Alcantara &vmstate_tco_io_state, 241679dd1a9SIgor Mammedov &vmstate_cpuhp_state, 24292055797SPaulo Alcantara NULL 24349ab747fSPaolo Bonzini } 24449ab747fSPaolo Bonzini }; 24549ab747fSPaolo Bonzini 24649ab747fSPaolo Bonzini static void pm_reset(void *opaque) 24749ab747fSPaolo Bonzini { 24849ab747fSPaolo Bonzini ICH9LPCPMRegs *pm = opaque; 24949ab747fSPaolo Bonzini ich9_pm_iospace_update(pm, 0); 25049ab747fSPaolo Bonzini 25149ab747fSPaolo Bonzini acpi_pm1_evt_reset(&pm->acpi_regs); 25249ab747fSPaolo Bonzini acpi_pm1_cnt_reset(&pm->acpi_regs); 25349ab747fSPaolo Bonzini acpi_pm_tmr_reset(&pm->acpi_regs); 25449ab747fSPaolo Bonzini acpi_gpe_reset(&pm->acpi_regs); 25549ab747fSPaolo Bonzini 256be66680eSLaszlo Ersek pm->smi_en = 0; 257fba72476SPaolo Bonzini if (!pm->smm_enabled) { 258f3c30aeaSLaszlo Ersek /* Mark SMM as already inited to prevent SMM from running. */ 25949ab747fSPaolo Bonzini pm->smi_en |= ICH9_PMIO_SMI_EN_APMC_EN; 26049ab747fSPaolo Bonzini } 26111e66a15SGerd Hoffmann pm->smi_en_wmask = ~0; 26249ab747fSPaolo Bonzini 26306313503SIgor Mammedov acpi_update_sci(&pm->acpi_regs, pm->irq); 26449ab747fSPaolo Bonzini } 26549ab747fSPaolo Bonzini 26649ab747fSPaolo Bonzini static void pm_powerdown_req(Notifier *n, void *opaque) 26749ab747fSPaolo Bonzini { 26849ab747fSPaolo Bonzini ICH9LPCPMRegs *pm = container_of(n, ICH9LPCPMRegs, powerdown_notifier); 26949ab747fSPaolo Bonzini 27049ab747fSPaolo Bonzini acpi_pm1_evt_power_down(&pm->acpi_regs); 27149ab747fSPaolo Bonzini } 27249ab747fSPaolo Bonzini 27392055797SPaulo Alcantara void ich9_pm_init(PCIDevice *lpc_pci, ICH9LPCPMRegs *pm, 27418d6abaeSEduardo Habkost bool smm_enabled, 275a3ac6b53SHu Tao qemu_irq sci_irq) 27649ab747fSPaolo Bonzini { 27764bde0f3SPaolo Bonzini memory_region_init(&pm->io, OBJECT(lpc_pci), "ich9-pm", ICH9_PMIO_SIZE); 27849ab747fSPaolo Bonzini memory_region_set_enabled(&pm->io, false); 27949ab747fSPaolo Bonzini memory_region_add_subregion(pci_address_space_io(lpc_pci), 28049ab747fSPaolo Bonzini 0, &pm->io); 28149ab747fSPaolo Bonzini 28249ab747fSPaolo Bonzini acpi_pm_tmr_init(&pm->acpi_regs, ich9_pm_update_sci_fn, &pm->io); 28349ab747fSPaolo Bonzini acpi_pm1_evt_init(&pm->acpi_regs, ich9_pm_update_sci_fn, &pm->io); 2849a10bbb4SLaszlo Ersek acpi_pm1_cnt_init(&pm->acpi_regs, &pm->io, pm->disable_s3, pm->disable_s4, 285*6be8cf56SIsaku Yamahata pm->s4_val, !pm->smm_compat && !smm_enabled); 28649ab747fSPaolo Bonzini 28749ab747fSPaolo Bonzini acpi_gpe_init(&pm->acpi_regs, ICH9_PMIO_GPE0_LEN); 28864bde0f3SPaolo Bonzini memory_region_init_io(&pm->io_gpe, OBJECT(lpc_pci), &ich9_gpe_ops, pm, 28975902802SHu Tao "acpi-gpe0", ICH9_PMIO_GPE0_LEN); 29049ab747fSPaolo Bonzini memory_region_add_subregion(&pm->io, ICH9_PMIO_GPE0_STS, &pm->io_gpe); 29149ab747fSPaolo Bonzini 29264bde0f3SPaolo Bonzini memory_region_init_io(&pm->io_smi, OBJECT(lpc_pci), &ich9_smi_ops, pm, 29375902802SHu Tao "acpi-smi", 8); 29449ab747fSPaolo Bonzini memory_region_add_subregion(&pm->io, ICH9_PMIO_SMI_EN, &pm->io_smi); 29549ab747fSPaolo Bonzini 296fba72476SPaolo Bonzini pm->smm_enabled = smm_enabled; 29792055797SPaulo Alcantara 29818d6abaeSEduardo Habkost pm->enable_tco = true; 29992055797SPaulo Alcantara acpi_pm_tco_init(&pm->tco_regs, &pm->io); 30092055797SPaulo Alcantara 30149ab747fSPaolo Bonzini pm->irq = sci_irq; 30249ab747fSPaolo Bonzini qemu_register_reset(pm_reset, pm); 30349ab747fSPaolo Bonzini pm->powerdown_notifier.notify = pm_powerdown_req; 30449ab747fSPaolo Bonzini qemu_register_powerdown_notifier(&pm->powerdown_notifier); 305d6610bc2SIgor Mammedov 30696e3e12bSIgor Mammedov legacy_acpi_cpu_hotplug_init(pci_address_space_io(lpc_pci), 30796e3e12bSIgor Mammedov OBJECT(lpc_pci), &pm->gpe_cpu, ICH9_CPU_HOTPLUG_IO_BASE); 3081f862184SIgor Mammedov 3091f862184SIgor Mammedov if (pm->acpi_memory_hotplug.is_enabled) { 3101f862184SIgor Mammedov acpi_memory_hotplug_init(pci_address_space_io(lpc_pci), OBJECT(lpc_pci), 31180db0e78SIgor Mammedov &pm->acpi_memory_hotplug, 31280db0e78SIgor Mammedov ACPI_MEMORY_HOTPLUG_BASE); 3131f862184SIgor Mammedov } 31449ab747fSPaolo Bonzini } 3156f1426abSMichael S. Tsirkin 316d7bce999SEric Blake static void ich9_pm_get_gpe0_blk(Object *obj, Visitor *v, const char *name, 317d7bce999SEric Blake void *opaque, Error **errp) 3186f1426abSMichael S. Tsirkin { 3196f1426abSMichael S. Tsirkin ICH9LPCPMRegs *pm = opaque; 3206f1426abSMichael S. Tsirkin uint32_t value = pm->pm_io_base + ICH9_PMIO_GPE0_STS; 3216f1426abSMichael S. Tsirkin 32251e72bc1SEric Blake visit_type_uint32(v, name, &value, errp); 3236f1426abSMichael S. Tsirkin } 3246f1426abSMichael S. Tsirkin 3251f862184SIgor Mammedov static bool ich9_pm_get_memory_hotplug_support(Object *obj, Error **errp) 3261f862184SIgor Mammedov { 3271f862184SIgor Mammedov ICH9LPCState *s = ICH9_LPC_DEVICE(obj); 3281f862184SIgor Mammedov 3291f862184SIgor Mammedov return s->pm.acpi_memory_hotplug.is_enabled; 3301f862184SIgor Mammedov } 3311f862184SIgor Mammedov 3321f862184SIgor Mammedov static void ich9_pm_set_memory_hotplug_support(Object *obj, bool value, 3331f862184SIgor Mammedov Error **errp) 3341f862184SIgor Mammedov { 3351f862184SIgor Mammedov ICH9LPCState *s = ICH9_LPC_DEVICE(obj); 3361f862184SIgor Mammedov 3371f862184SIgor Mammedov s->pm.acpi_memory_hotplug.is_enabled = value; 3381f862184SIgor Mammedov } 3391f862184SIgor Mammedov 34016bcab97SIgor Mammedov static bool ich9_pm_get_cpu_hotplug_legacy(Object *obj, Error **errp) 34116bcab97SIgor Mammedov { 34216bcab97SIgor Mammedov ICH9LPCState *s = ICH9_LPC_DEVICE(obj); 34316bcab97SIgor Mammedov 34416bcab97SIgor Mammedov return s->pm.cpu_hotplug_legacy; 34516bcab97SIgor Mammedov } 34616bcab97SIgor Mammedov 34716bcab97SIgor Mammedov static void ich9_pm_set_cpu_hotplug_legacy(Object *obj, bool value, 34816bcab97SIgor Mammedov Error **errp) 34916bcab97SIgor Mammedov { 35016bcab97SIgor Mammedov ICH9LPCState *s = ICH9_LPC_DEVICE(obj); 35116bcab97SIgor Mammedov 352679dd1a9SIgor Mammedov assert(!value); 353679dd1a9SIgor Mammedov if (s->pm.cpu_hotplug_legacy && value == false) { 354679dd1a9SIgor Mammedov acpi_switch_to_modern_cphp(&s->pm.gpe_cpu, &s->pm.cpuhp_state, 355679dd1a9SIgor Mammedov ICH9_CPU_HOTPLUG_IO_BASE); 356679dd1a9SIgor Mammedov } 35716bcab97SIgor Mammedov s->pm.cpu_hotplug_legacy = value; 35816bcab97SIgor Mammedov } 35916bcab97SIgor Mammedov 36092055797SPaulo Alcantara static bool ich9_pm_get_enable_tco(Object *obj, Error **errp) 36192055797SPaulo Alcantara { 36292055797SPaulo Alcantara ICH9LPCState *s = ICH9_LPC_DEVICE(obj); 36392055797SPaulo Alcantara return s->pm.enable_tco; 36492055797SPaulo Alcantara } 36592055797SPaulo Alcantara 36692055797SPaulo Alcantara static void ich9_pm_set_enable_tco(Object *obj, bool value, Error **errp) 36792055797SPaulo Alcantara { 36892055797SPaulo Alcantara ICH9LPCState *s = ICH9_LPC_DEVICE(obj); 36992055797SPaulo Alcantara s->pm.enable_tco = value; 37092055797SPaulo Alcantara } 37192055797SPaulo Alcantara 37240c2281cSMarkus Armbruster void ich9_pm_add_properties(Object *obj, ICH9LPCPMRegs *pm) 3736f1426abSMichael S. Tsirkin { 3746f1426abSMichael S. Tsirkin static const uint32_t gpe0_len = ICH9_PMIO_GPE0_LEN; 3751f862184SIgor Mammedov pm->acpi_memory_hotplug.is_enabled = true; 37616bcab97SIgor Mammedov pm->cpu_hotplug_legacy = true; 3776ac0d8d4SAmit Shah pm->disable_s3 = 0; 3786ac0d8d4SAmit Shah pm->disable_s4 = 0; 3796ac0d8d4SAmit Shah pm->s4_val = 2; 3806f1426abSMichael S. Tsirkin 3816f1426abSMichael S. Tsirkin object_property_add_uint32_ptr(obj, ACPI_PM_PROP_PM_IO_BASE, 382d2623129SMarkus Armbruster &pm->pm_io_base, OBJ_PROP_FLAG_READ); 3836f1426abSMichael S. Tsirkin object_property_add(obj, ACPI_PM_PROP_GPE0_BLK, "uint32", 3846f1426abSMichael S. Tsirkin ich9_pm_get_gpe0_blk, 385d2623129SMarkus Armbruster NULL, NULL, pm); 3866f1426abSMichael S. Tsirkin object_property_add_uint32_ptr(obj, ACPI_PM_PROP_GPE0_BLK_LEN, 387d2623129SMarkus Armbruster &gpe0_len, OBJ_PROP_FLAG_READ); 3881f862184SIgor Mammedov object_property_add_bool(obj, "memory-hotplug-support", 3891f862184SIgor Mammedov ich9_pm_get_memory_hotplug_support, 390d2623129SMarkus Armbruster ich9_pm_set_memory_hotplug_support); 39116bcab97SIgor Mammedov object_property_add_bool(obj, "cpu-hotplug-legacy", 39216bcab97SIgor Mammedov ich9_pm_get_cpu_hotplug_legacy, 393d2623129SMarkus Armbruster ich9_pm_set_cpu_hotplug_legacy); 39464a7b8deSFelipe Franciosi object_property_add_uint8_ptr(obj, ACPI_PM_PROP_S3_DISABLED, 395d2623129SMarkus Armbruster &pm->disable_s3, OBJ_PROP_FLAG_READWRITE); 39664a7b8deSFelipe Franciosi object_property_add_uint8_ptr(obj, ACPI_PM_PROP_S4_DISABLED, 397d2623129SMarkus Armbruster &pm->disable_s4, OBJ_PROP_FLAG_READWRITE); 39864a7b8deSFelipe Franciosi object_property_add_uint8_ptr(obj, ACPI_PM_PROP_S4_VAL, 399d2623129SMarkus Armbruster &pm->s4_val, OBJ_PROP_FLAG_READWRITE); 40092055797SPaulo Alcantara object_property_add_bool(obj, ACPI_PM_PROP_TCO_ENABLED, 40192055797SPaulo Alcantara ich9_pm_get_enable_tco, 402d2623129SMarkus Armbruster ich9_pm_set_enable_tco); 4031f862184SIgor Mammedov } 4041f862184SIgor Mammedov 4059040e6dfSWei Yang void ich9_pm_device_pre_plug_cb(HotplugHandler *hotplug_dev, DeviceState *dev, 4069040e6dfSWei Yang Error **errp) 4079040e6dfSWei Yang { 4089040e6dfSWei Yang ICH9LPCState *lpc = ICH9_LPC_DEVICE(hotplug_dev); 4099040e6dfSWei Yang 4109040e6dfSWei Yang if (object_dynamic_cast(OBJECT(dev), TYPE_PC_DIMM) && 411c5be7517SIgor Mammedov !lpc->pm.acpi_memory_hotplug.is_enabled) { 4129040e6dfSWei Yang error_setg(errp, 4139040e6dfSWei Yang "memory hotplug is not enabled: %s.memory-hotplug-support " 4149040e6dfSWei Yang "is not set", object_get_typename(OBJECT(lpc))); 415c5be7517SIgor Mammedov } else if (object_dynamic_cast(OBJECT(dev), TYPE_CPU)) { 416c5be7517SIgor Mammedov uint64_t negotiated = lpc->smi_negotiated_features; 417c5be7517SIgor Mammedov 418c5be7517SIgor Mammedov if (negotiated & BIT_ULL(ICH9_LPC_SMI_F_BROADCAST_BIT) && 419c5be7517SIgor Mammedov !(negotiated & BIT_ULL(ICH9_LPC_SMI_F_CPU_HOTPLUG_BIT))) { 420c5be7517SIgor Mammedov error_setg(errp, "cpu hotplug with SMI wasn't enabled by firmware"); 421c5be7517SIgor Mammedov error_append_hint(errp, "update machine type to newer than 5.1 " 422c5be7517SIgor Mammedov "and firmware that suppors CPU hotplug with SMM"); 423c5be7517SIgor Mammedov } 424c5be7517SIgor Mammedov } 4259040e6dfSWei Yang } 4269040e6dfSWei Yang 4270058c082SIgor Mammedov void ich9_pm_device_plug_cb(HotplugHandler *hotplug_dev, DeviceState *dev, 4280058c082SIgor Mammedov Error **errp) 4291f862184SIgor Mammedov { 4300058c082SIgor Mammedov ICH9LPCState *lpc = ICH9_LPC_DEVICE(hotplug_dev); 4310058c082SIgor Mammedov 4329040e6dfSWei Yang if (object_dynamic_cast(OBJECT(dev), TYPE_PC_DIMM)) { 43375f27498SXiao Guangrong if (object_dynamic_cast(OBJECT(dev), TYPE_NVDIMM)) { 43475f27498SXiao Guangrong nvdimm_acpi_plug_cb(hotplug_dev, dev); 43575f27498SXiao Guangrong } else { 4360058c082SIgor Mammedov acpi_memory_plug_cb(hotplug_dev, &lpc->pm.acpi_memory_hotplug, 4371f862184SIgor Mammedov dev, errp); 43875f27498SXiao Guangrong } 4395e1b5d93SIgor Mammedov } else if (object_dynamic_cast(OBJECT(dev), TYPE_CPU)) { 4405e1b5d93SIgor Mammedov if (lpc->pm.cpu_hotplug_legacy) { 4410058c082SIgor Mammedov legacy_acpi_cpu_plug_cb(hotplug_dev, &lpc->pm.gpe_cpu, dev, errp); 4421f862184SIgor Mammedov } else { 4435e1b5d93SIgor Mammedov acpi_cpu_plug_cb(hotplug_dev, &lpc->pm.cpuhp_state, dev, errp); 4445e1b5d93SIgor Mammedov } 4455e1b5d93SIgor Mammedov } else { 4461f862184SIgor Mammedov error_setg(errp, "acpi: device plug request for not supported device" 4471f862184SIgor Mammedov " type: %s", object_get_typename(OBJECT(dev))); 4481f862184SIgor Mammedov } 4496f1426abSMichael S. Tsirkin } 45043f50410SIgor Mammedov 4510058c082SIgor Mammedov void ich9_pm_device_unplug_request_cb(HotplugHandler *hotplug_dev, 4520058c082SIgor Mammedov DeviceState *dev, Error **errp) 453469b8ad2STang Chen { 4540058c082SIgor Mammedov ICH9LPCState *lpc = ICH9_LPC_DEVICE(hotplug_dev); 4550058c082SIgor Mammedov 4560058c082SIgor Mammedov if (lpc->pm.acpi_memory_hotplug.is_enabled && 45764fec58eSTang Chen object_dynamic_cast(OBJECT(dev), TYPE_PC_DIMM)) { 4580058c082SIgor Mammedov acpi_memory_unplug_request_cb(hotplug_dev, 4590058c082SIgor Mammedov &lpc->pm.acpi_memory_hotplug, dev, 4600058c082SIgor Mammedov errp); 4618872c25aSIgor Mammedov } else if (object_dynamic_cast(OBJECT(dev), TYPE_CPU) && 4628872c25aSIgor Mammedov !lpc->pm.cpu_hotplug_legacy) { 463b48ad7c0SIgor Mammedov uint64_t negotiated = lpc->smi_negotiated_features; 464b48ad7c0SIgor Mammedov 465b48ad7c0SIgor Mammedov if (negotiated & BIT_ULL(ICH9_LPC_SMI_F_BROADCAST_BIT) && 466b48ad7c0SIgor Mammedov !(negotiated & BIT_ULL(ICH9_LPC_SMI_F_CPU_HOT_UNPLUG_BIT))) { 467b48ad7c0SIgor Mammedov error_setg(errp, "cpu hot-unplug with SMI wasn't enabled " 468b48ad7c0SIgor Mammedov "by firmware"); 469b48ad7c0SIgor Mammedov error_append_hint(errp, "update machine type to a version having " 470b48ad7c0SIgor Mammedov "x-smi-cpu-hotunplug=on and firmware that " 471b48ad7c0SIgor Mammedov "supports CPU hot-unplug with SMM"); 472b48ad7c0SIgor Mammedov return; 473b48ad7c0SIgor Mammedov } 474b48ad7c0SIgor Mammedov 4758872c25aSIgor Mammedov acpi_cpu_unplug_request_cb(hotplug_dev, &lpc->pm.cpuhp_state, 4768872c25aSIgor Mammedov dev, errp); 47764fec58eSTang Chen } else { 478469b8ad2STang Chen error_setg(errp, "acpi: device unplug request for not supported device" 479469b8ad2STang Chen " type: %s", object_get_typename(OBJECT(dev))); 480469b8ad2STang Chen } 48164fec58eSTang Chen } 482469b8ad2STang Chen 4830058c082SIgor Mammedov void ich9_pm_device_unplug_cb(HotplugHandler *hotplug_dev, DeviceState *dev, 48491a734a6STang Chen Error **errp) 48591a734a6STang Chen { 4860058c082SIgor Mammedov ICH9LPCState *lpc = ICH9_LPC_DEVICE(hotplug_dev); 4870058c082SIgor Mammedov 4880058c082SIgor Mammedov if (lpc->pm.acpi_memory_hotplug.is_enabled && 489f7d3e29dSTang Chen object_dynamic_cast(OBJECT(dev), TYPE_PC_DIMM)) { 4900058c082SIgor Mammedov acpi_memory_unplug_cb(&lpc->pm.acpi_memory_hotplug, dev, errp); 4918872c25aSIgor Mammedov } else if (object_dynamic_cast(OBJECT(dev), TYPE_CPU) && 4928872c25aSIgor Mammedov !lpc->pm.cpu_hotplug_legacy) { 4938872c25aSIgor Mammedov acpi_cpu_unplug_cb(&lpc->pm.cpuhp_state, dev, errp); 494f7d3e29dSTang Chen } else { 49591a734a6STang Chen error_setg(errp, "acpi: device unplug for not supported device" 49691a734a6STang Chen " type: %s", object_get_typename(OBJECT(dev))); 49791a734a6STang Chen } 498f7d3e29dSTang Chen } 49991a734a6STang Chen 50043f50410SIgor Mammedov void ich9_pm_ospm_status(AcpiDeviceIf *adev, ACPIOSTInfoList ***list) 50143f50410SIgor Mammedov { 50243f50410SIgor Mammedov ICH9LPCState *s = ICH9_LPC_DEVICE(adev); 50343f50410SIgor Mammedov 50443f50410SIgor Mammedov acpi_memory_ospm_status(&s->pm.acpi_memory_hotplug, list); 50576623d00SIgor Mammedov if (!s->pm.cpu_hotplug_legacy) { 50676623d00SIgor Mammedov acpi_cpu_ospm_status(&s->pm.cpuhp_state, list); 50776623d00SIgor Mammedov } 50843f50410SIgor Mammedov } 509