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 3949ab747fSPaolo Bonzini #include "hw/i386/ich9.h" 401f862184SIgor Mammedov #include "hw/mem/pc-dimm.h" 41132a908bSPhilippe Mathieu-Daudé #include "hw/mem/nvdimm.h" 4249ab747fSPaolo Bonzini 4349ab747fSPaolo Bonzini //#define DEBUG 4449ab747fSPaolo Bonzini 4549ab747fSPaolo Bonzini #ifdef DEBUG 4649ab747fSPaolo Bonzini #define ICH9_DEBUG(fmt, ...) \ 4749ab747fSPaolo Bonzini do { printf("%s "fmt, __func__, ## __VA_ARGS__); } while (0) 4849ab747fSPaolo Bonzini #else 4949ab747fSPaolo Bonzini #define ICH9_DEBUG(fmt, ...) do { } while (0) 5049ab747fSPaolo Bonzini #endif 5149ab747fSPaolo Bonzini 5249ab747fSPaolo Bonzini static void ich9_pm_update_sci_fn(ACPIREGS *regs) 5349ab747fSPaolo Bonzini { 5449ab747fSPaolo Bonzini ICH9LPCPMRegs *pm = container_of(regs, ICH9LPCPMRegs, acpi_regs); 5506313503SIgor Mammedov acpi_update_sci(&pm->acpi_regs, pm->irq); 5649ab747fSPaolo Bonzini } 5749ab747fSPaolo Bonzini 5849ab747fSPaolo Bonzini static uint64_t ich9_gpe_readb(void *opaque, hwaddr addr, unsigned width) 5949ab747fSPaolo Bonzini { 6049ab747fSPaolo Bonzini ICH9LPCPMRegs *pm = opaque; 6149ab747fSPaolo Bonzini return acpi_gpe_ioport_readb(&pm->acpi_regs, addr); 6249ab747fSPaolo Bonzini } 6349ab747fSPaolo Bonzini 6449ab747fSPaolo Bonzini static void ich9_gpe_writeb(void *opaque, hwaddr addr, uint64_t val, 6549ab747fSPaolo Bonzini unsigned width) 6649ab747fSPaolo Bonzini { 6749ab747fSPaolo Bonzini ICH9LPCPMRegs *pm = opaque; 6849ab747fSPaolo Bonzini acpi_gpe_ioport_writeb(&pm->acpi_regs, addr, val); 692c047956SIgor Mammedov acpi_update_sci(&pm->acpi_regs, pm->irq); 7049ab747fSPaolo Bonzini } 7149ab747fSPaolo Bonzini 7249ab747fSPaolo Bonzini static const MemoryRegionOps ich9_gpe_ops = { 7349ab747fSPaolo Bonzini .read = ich9_gpe_readb, 7449ab747fSPaolo Bonzini .write = ich9_gpe_writeb, 7549ab747fSPaolo Bonzini .valid.min_access_size = 1, 7649ab747fSPaolo Bonzini .valid.max_access_size = 4, 7749ab747fSPaolo Bonzini .impl.min_access_size = 1, 7849ab747fSPaolo Bonzini .impl.max_access_size = 1, 7949ab747fSPaolo Bonzini .endianness = DEVICE_LITTLE_ENDIAN, 8049ab747fSPaolo Bonzini }; 8149ab747fSPaolo Bonzini 8249ab747fSPaolo Bonzini static uint64_t ich9_smi_readl(void *opaque, hwaddr addr, unsigned width) 8349ab747fSPaolo Bonzini { 8449ab747fSPaolo Bonzini ICH9LPCPMRegs *pm = opaque; 8549ab747fSPaolo Bonzini switch (addr) { 8649ab747fSPaolo Bonzini case 0: 8749ab747fSPaolo Bonzini return pm->smi_en; 8849ab747fSPaolo Bonzini case 4: 8949ab747fSPaolo Bonzini return pm->smi_sts; 9049ab747fSPaolo Bonzini default: 9149ab747fSPaolo Bonzini return 0; 9249ab747fSPaolo Bonzini } 9349ab747fSPaolo Bonzini } 9449ab747fSPaolo Bonzini 9549ab747fSPaolo Bonzini static void ich9_smi_writel(void *opaque, hwaddr addr, uint64_t val, 9649ab747fSPaolo Bonzini unsigned width) 9749ab747fSPaolo Bonzini { 9849ab747fSPaolo Bonzini ICH9LPCPMRegs *pm = opaque; 9992055797SPaulo Alcantara TCOIORegs *tr = &pm->tco_regs; 10092055797SPaulo Alcantara uint64_t tco_en; 10192055797SPaulo Alcantara 10249ab747fSPaolo Bonzini switch (addr) { 10349ab747fSPaolo Bonzini case 0: 10492055797SPaulo Alcantara tco_en = pm->smi_en & ICH9_PMIO_SMI_EN_TCO_EN; 10592055797SPaulo Alcantara /* once TCO_LOCK bit is set, TCO_EN bit cannot be overwritten */ 10692055797SPaulo Alcantara if (tr->tco.cnt1 & TCO_LOCK) { 10792055797SPaulo Alcantara val = (val & ~ICH9_PMIO_SMI_EN_TCO_EN) | tco_en; 10892055797SPaulo Alcantara } 10911e66a15SGerd Hoffmann pm->smi_en &= ~pm->smi_en_wmask; 11011e66a15SGerd Hoffmann pm->smi_en |= (val & pm->smi_en_wmask); 11149ab747fSPaolo Bonzini break; 11249ab747fSPaolo Bonzini } 11349ab747fSPaolo Bonzini } 11449ab747fSPaolo Bonzini 11549ab747fSPaolo Bonzini static const MemoryRegionOps ich9_smi_ops = { 11649ab747fSPaolo Bonzini .read = ich9_smi_readl, 11749ab747fSPaolo Bonzini .write = ich9_smi_writel, 11849ab747fSPaolo Bonzini .valid.min_access_size = 4, 11949ab747fSPaolo Bonzini .valid.max_access_size = 4, 12049ab747fSPaolo Bonzini .endianness = DEVICE_LITTLE_ENDIAN, 12149ab747fSPaolo Bonzini }; 12249ab747fSPaolo Bonzini 12349ab747fSPaolo Bonzini void ich9_pm_iospace_update(ICH9LPCPMRegs *pm, uint32_t pm_io_base) 12449ab747fSPaolo Bonzini { 12549ab747fSPaolo Bonzini ICH9_DEBUG("to 0x%x\n", pm_io_base); 12649ab747fSPaolo Bonzini 12749ab747fSPaolo Bonzini assert((pm_io_base & ICH9_PMIO_MASK) == 0); 12849ab747fSPaolo Bonzini 12949ab747fSPaolo Bonzini pm->pm_io_base = pm_io_base; 13049ab747fSPaolo Bonzini memory_region_transaction_begin(); 13149ab747fSPaolo Bonzini memory_region_set_enabled(&pm->io, pm->pm_io_base != 0); 13249ab747fSPaolo Bonzini memory_region_set_address(&pm->io, pm->pm_io_base); 13349ab747fSPaolo Bonzini memory_region_transaction_commit(); 13449ab747fSPaolo Bonzini } 13549ab747fSPaolo Bonzini 13649ab747fSPaolo Bonzini static int ich9_pm_post_load(void *opaque, int version_id) 13749ab747fSPaolo Bonzini { 13849ab747fSPaolo Bonzini ICH9LPCPMRegs *pm = opaque; 13949ab747fSPaolo Bonzini uint32_t pm_io_base = pm->pm_io_base; 14049ab747fSPaolo Bonzini pm->pm_io_base = 0; 14149ab747fSPaolo Bonzini ich9_pm_iospace_update(pm, pm_io_base); 14249ab747fSPaolo Bonzini return 0; 14349ab747fSPaolo Bonzini } 14449ab747fSPaolo Bonzini 14549ab747fSPaolo Bonzini #define VMSTATE_GPE_ARRAY(_field, _state) \ 14649ab747fSPaolo Bonzini { \ 14749ab747fSPaolo Bonzini .name = (stringify(_field)), \ 14849ab747fSPaolo Bonzini .version_id = 0, \ 14949ab747fSPaolo Bonzini .num = ICH9_PMIO_GPE0_LEN, \ 15049ab747fSPaolo Bonzini .info = &vmstate_info_uint8, \ 15149ab747fSPaolo Bonzini .size = sizeof(uint8_t), \ 15249ab747fSPaolo Bonzini .flags = VMS_ARRAY | VMS_POINTER, \ 15349ab747fSPaolo Bonzini .offset = vmstate_offset_pointer(_state, _field, uint8_t), \ 15449ab747fSPaolo Bonzini } 15549ab747fSPaolo Bonzini 156f816a62dSIgor Mammedov static bool vmstate_test_use_memhp(void *opaque) 157f816a62dSIgor Mammedov { 158f816a62dSIgor Mammedov ICH9LPCPMRegs *s = opaque; 159f816a62dSIgor Mammedov return s->acpi_memory_hotplug.is_enabled; 160f816a62dSIgor Mammedov } 161f816a62dSIgor Mammedov 162f816a62dSIgor Mammedov static const VMStateDescription vmstate_memhp_state = { 163f816a62dSIgor Mammedov .name = "ich9_pm/memhp", 164f816a62dSIgor Mammedov .version_id = 1, 165f816a62dSIgor Mammedov .minimum_version_id = 1, 166f816a62dSIgor Mammedov .minimum_version_id_old = 1, 1675cd8cadaSJuan Quintela .needed = vmstate_test_use_memhp, 168f816a62dSIgor Mammedov .fields = (VMStateField[]) { 169f816a62dSIgor Mammedov VMSTATE_MEMORY_HOTPLUG(acpi_memory_hotplug, ICH9LPCPMRegs), 170f816a62dSIgor Mammedov VMSTATE_END_OF_LIST() 171f816a62dSIgor Mammedov } 172f816a62dSIgor Mammedov }; 173f816a62dSIgor Mammedov 17492055797SPaulo Alcantara static bool vmstate_test_use_tco(void *opaque) 17592055797SPaulo Alcantara { 17692055797SPaulo Alcantara ICH9LPCPMRegs *s = opaque; 17792055797SPaulo Alcantara return s->enable_tco; 17892055797SPaulo Alcantara } 17992055797SPaulo Alcantara 18092055797SPaulo Alcantara static const VMStateDescription vmstate_tco_io_state = { 18192055797SPaulo Alcantara .name = "ich9_pm/tco", 18292055797SPaulo Alcantara .version_id = 1, 18392055797SPaulo Alcantara .minimum_version_id = 1, 18492055797SPaulo Alcantara .minimum_version_id_old = 1, 18592055797SPaulo Alcantara .needed = vmstate_test_use_tco, 18692055797SPaulo Alcantara .fields = (VMStateField[]) { 18792055797SPaulo Alcantara VMSTATE_STRUCT(tco_regs, ICH9LPCPMRegs, 1, vmstate_tco_io_sts, 18892055797SPaulo Alcantara TCOIORegs), 18992055797SPaulo Alcantara VMSTATE_END_OF_LIST() 19092055797SPaulo Alcantara } 19192055797SPaulo Alcantara }; 19292055797SPaulo Alcantara 193679dd1a9SIgor Mammedov static bool vmstate_test_use_cpuhp(void *opaque) 194679dd1a9SIgor Mammedov { 195679dd1a9SIgor Mammedov ICH9LPCPMRegs *s = opaque; 196679dd1a9SIgor Mammedov return !s->cpu_hotplug_legacy; 197679dd1a9SIgor Mammedov } 198679dd1a9SIgor Mammedov 199679dd1a9SIgor Mammedov static int vmstate_cpuhp_pre_load(void *opaque) 200679dd1a9SIgor Mammedov { 201679dd1a9SIgor Mammedov ICH9LPCPMRegs *s = opaque; 202679dd1a9SIgor Mammedov Object *obj = OBJECT(s->gpe_cpu.device); 2035325cc34SMarkus Armbruster object_property_set_bool(obj, "cpu-hotplug-legacy", false, &error_abort); 204679dd1a9SIgor Mammedov return 0; 205679dd1a9SIgor Mammedov } 206679dd1a9SIgor Mammedov 207679dd1a9SIgor Mammedov static const VMStateDescription vmstate_cpuhp_state = { 208679dd1a9SIgor Mammedov .name = "ich9_pm/cpuhp", 209679dd1a9SIgor Mammedov .version_id = 1, 210679dd1a9SIgor Mammedov .minimum_version_id = 1, 211679dd1a9SIgor Mammedov .minimum_version_id_old = 1, 212679dd1a9SIgor Mammedov .needed = vmstate_test_use_cpuhp, 213679dd1a9SIgor Mammedov .pre_load = vmstate_cpuhp_pre_load, 214679dd1a9SIgor Mammedov .fields = (VMStateField[]) { 215679dd1a9SIgor Mammedov VMSTATE_CPU_HOTPLUG(cpuhp_state, ICH9LPCPMRegs), 216679dd1a9SIgor Mammedov VMSTATE_END_OF_LIST() 217679dd1a9SIgor Mammedov } 218679dd1a9SIgor Mammedov }; 219679dd1a9SIgor Mammedov 220*c0e427d6SJulia Suvorova static bool vmstate_test_use_pcihp(void *opaque) 221*c0e427d6SJulia Suvorova { 222*c0e427d6SJulia Suvorova ICH9LPCPMRegs *s = opaque; 223*c0e427d6SJulia Suvorova 224*c0e427d6SJulia Suvorova return s->use_acpi_hotplug_bridge; 225*c0e427d6SJulia Suvorova } 226*c0e427d6SJulia Suvorova 227*c0e427d6SJulia Suvorova static const VMStateDescription vmstate_pcihp_state = { 228*c0e427d6SJulia Suvorova .name = "ich9_pm/pcihp", 229*c0e427d6SJulia Suvorova .version_id = 1, 230*c0e427d6SJulia Suvorova .minimum_version_id = 1, 231*c0e427d6SJulia Suvorova .needed = vmstate_test_use_pcihp, 232*c0e427d6SJulia Suvorova .fields = (VMStateField[]) { 233*c0e427d6SJulia Suvorova VMSTATE_PCI_HOTPLUG(acpi_pci_hotplug, 234*c0e427d6SJulia Suvorova ICH9LPCPMRegs, 235*c0e427d6SJulia Suvorova NULL, NULL), 236*c0e427d6SJulia Suvorova VMSTATE_END_OF_LIST() 237*c0e427d6SJulia Suvorova } 238*c0e427d6SJulia Suvorova }; 239*c0e427d6SJulia Suvorova 24049ab747fSPaolo Bonzini const VMStateDescription vmstate_ich9_pm = { 24149ab747fSPaolo Bonzini .name = "ich9_pm", 24249ab747fSPaolo Bonzini .version_id = 1, 24349ab747fSPaolo Bonzini .minimum_version_id = 1, 24449ab747fSPaolo Bonzini .post_load = ich9_pm_post_load, 24549ab747fSPaolo Bonzini .fields = (VMStateField[]) { 24649ab747fSPaolo Bonzini VMSTATE_UINT16(acpi_regs.pm1.evt.sts, ICH9LPCPMRegs), 24749ab747fSPaolo Bonzini VMSTATE_UINT16(acpi_regs.pm1.evt.en, ICH9LPCPMRegs), 24849ab747fSPaolo Bonzini VMSTATE_UINT16(acpi_regs.pm1.cnt.cnt, ICH9LPCPMRegs), 249e720677eSPaolo Bonzini VMSTATE_TIMER_PTR(acpi_regs.tmr.timer, ICH9LPCPMRegs), 25049ab747fSPaolo Bonzini VMSTATE_INT64(acpi_regs.tmr.overflow_time, ICH9LPCPMRegs), 25149ab747fSPaolo Bonzini VMSTATE_GPE_ARRAY(acpi_regs.gpe.sts, ICH9LPCPMRegs), 25249ab747fSPaolo Bonzini VMSTATE_GPE_ARRAY(acpi_regs.gpe.en, ICH9LPCPMRegs), 25349ab747fSPaolo Bonzini VMSTATE_UINT32(smi_en, ICH9LPCPMRegs), 25449ab747fSPaolo Bonzini VMSTATE_UINT32(smi_sts, ICH9LPCPMRegs), 25549ab747fSPaolo Bonzini VMSTATE_END_OF_LIST() 256f816a62dSIgor Mammedov }, 2575cd8cadaSJuan Quintela .subsections = (const VMStateDescription*[]) { 2585cd8cadaSJuan Quintela &vmstate_memhp_state, 25992055797SPaulo Alcantara &vmstate_tco_io_state, 260679dd1a9SIgor Mammedov &vmstate_cpuhp_state, 261*c0e427d6SJulia Suvorova &vmstate_pcihp_state, 26292055797SPaulo Alcantara NULL 26349ab747fSPaolo Bonzini } 26449ab747fSPaolo Bonzini }; 26549ab747fSPaolo Bonzini 26649ab747fSPaolo Bonzini static void pm_reset(void *opaque) 26749ab747fSPaolo Bonzini { 26849ab747fSPaolo Bonzini ICH9LPCPMRegs *pm = opaque; 26949ab747fSPaolo Bonzini ich9_pm_iospace_update(pm, 0); 27049ab747fSPaolo Bonzini 27149ab747fSPaolo Bonzini acpi_pm1_evt_reset(&pm->acpi_regs); 27249ab747fSPaolo Bonzini acpi_pm1_cnt_reset(&pm->acpi_regs); 27349ab747fSPaolo Bonzini acpi_pm_tmr_reset(&pm->acpi_regs); 27449ab747fSPaolo Bonzini acpi_gpe_reset(&pm->acpi_regs); 27549ab747fSPaolo Bonzini 276be66680eSLaszlo Ersek pm->smi_en = 0; 277fba72476SPaolo Bonzini if (!pm->smm_enabled) { 278f3c30aeaSLaszlo Ersek /* Mark SMM as already inited to prevent SMM from running. */ 27949ab747fSPaolo Bonzini pm->smi_en |= ICH9_PMIO_SMI_EN_APMC_EN; 28049ab747fSPaolo Bonzini } 28111e66a15SGerd Hoffmann pm->smi_en_wmask = ~0; 28249ab747fSPaolo Bonzini 283*c0e427d6SJulia Suvorova if (pm->use_acpi_hotplug_bridge) { 284*c0e427d6SJulia Suvorova acpi_pcihp_reset(&pm->acpi_pci_hotplug, true); 285*c0e427d6SJulia Suvorova } 286*c0e427d6SJulia Suvorova 28706313503SIgor Mammedov acpi_update_sci(&pm->acpi_regs, pm->irq); 28849ab747fSPaolo Bonzini } 28949ab747fSPaolo Bonzini 29049ab747fSPaolo Bonzini static void pm_powerdown_req(Notifier *n, void *opaque) 29149ab747fSPaolo Bonzini { 29249ab747fSPaolo Bonzini ICH9LPCPMRegs *pm = container_of(n, ICH9LPCPMRegs, powerdown_notifier); 29349ab747fSPaolo Bonzini 29449ab747fSPaolo Bonzini acpi_pm1_evt_power_down(&pm->acpi_regs); 29549ab747fSPaolo Bonzini } 29649ab747fSPaolo Bonzini 29792055797SPaulo Alcantara void ich9_pm_init(PCIDevice *lpc_pci, ICH9LPCPMRegs *pm, 29818d6abaeSEduardo Habkost bool smm_enabled, 299a3ac6b53SHu Tao qemu_irq sci_irq) 30049ab747fSPaolo Bonzini { 30164bde0f3SPaolo Bonzini memory_region_init(&pm->io, OBJECT(lpc_pci), "ich9-pm", ICH9_PMIO_SIZE); 30249ab747fSPaolo Bonzini memory_region_set_enabled(&pm->io, false); 30349ab747fSPaolo Bonzini memory_region_add_subregion(pci_address_space_io(lpc_pci), 30449ab747fSPaolo Bonzini 0, &pm->io); 30549ab747fSPaolo Bonzini 30649ab747fSPaolo Bonzini acpi_pm_tmr_init(&pm->acpi_regs, ich9_pm_update_sci_fn, &pm->io); 30749ab747fSPaolo Bonzini acpi_pm1_evt_init(&pm->acpi_regs, ich9_pm_update_sci_fn, &pm->io); 3089a10bbb4SLaszlo Ersek acpi_pm1_cnt_init(&pm->acpi_regs, &pm->io, pm->disable_s3, pm->disable_s4, 3096be8cf56SIsaku Yamahata pm->s4_val, !pm->smm_compat && !smm_enabled); 31049ab747fSPaolo Bonzini 31149ab747fSPaolo Bonzini acpi_gpe_init(&pm->acpi_regs, ICH9_PMIO_GPE0_LEN); 31264bde0f3SPaolo Bonzini memory_region_init_io(&pm->io_gpe, OBJECT(lpc_pci), &ich9_gpe_ops, pm, 31375902802SHu Tao "acpi-gpe0", ICH9_PMIO_GPE0_LEN); 31449ab747fSPaolo Bonzini memory_region_add_subregion(&pm->io, ICH9_PMIO_GPE0_STS, &pm->io_gpe); 31549ab747fSPaolo Bonzini 31664bde0f3SPaolo Bonzini memory_region_init_io(&pm->io_smi, OBJECT(lpc_pci), &ich9_smi_ops, pm, 31775902802SHu Tao "acpi-smi", 8); 31849ab747fSPaolo Bonzini memory_region_add_subregion(&pm->io, ICH9_PMIO_SMI_EN, &pm->io_smi); 31949ab747fSPaolo Bonzini 320fba72476SPaolo Bonzini pm->smm_enabled = smm_enabled; 32192055797SPaulo Alcantara 32218d6abaeSEduardo Habkost pm->enable_tco = true; 32392055797SPaulo Alcantara acpi_pm_tco_init(&pm->tco_regs, &pm->io); 32492055797SPaulo Alcantara 325*c0e427d6SJulia Suvorova if (pm->use_acpi_hotplug_bridge) { 326*c0e427d6SJulia Suvorova acpi_pcihp_init(OBJECT(lpc_pci), 327*c0e427d6SJulia Suvorova &pm->acpi_pci_hotplug, 328*c0e427d6SJulia Suvorova pci_get_bus(lpc_pci), 329*c0e427d6SJulia Suvorova pci_address_space_io(lpc_pci), 330*c0e427d6SJulia Suvorova true, 331*c0e427d6SJulia Suvorova ACPI_PCIHP_ADDR_ICH9); 332*c0e427d6SJulia Suvorova 333*c0e427d6SJulia Suvorova qbus_set_hotplug_handler(BUS(pci_get_bus(lpc_pci)), 334*c0e427d6SJulia Suvorova OBJECT(lpc_pci)); 335*c0e427d6SJulia Suvorova } 336*c0e427d6SJulia Suvorova 33749ab747fSPaolo Bonzini pm->irq = sci_irq; 33849ab747fSPaolo Bonzini qemu_register_reset(pm_reset, pm); 33949ab747fSPaolo Bonzini pm->powerdown_notifier.notify = pm_powerdown_req; 34049ab747fSPaolo Bonzini qemu_register_powerdown_notifier(&pm->powerdown_notifier); 341d6610bc2SIgor Mammedov 34296e3e12bSIgor Mammedov legacy_acpi_cpu_hotplug_init(pci_address_space_io(lpc_pci), 34396e3e12bSIgor Mammedov OBJECT(lpc_pci), &pm->gpe_cpu, ICH9_CPU_HOTPLUG_IO_BASE); 3441f862184SIgor Mammedov 3451f862184SIgor Mammedov if (pm->acpi_memory_hotplug.is_enabled) { 3461f862184SIgor Mammedov acpi_memory_hotplug_init(pci_address_space_io(lpc_pci), OBJECT(lpc_pci), 34780db0e78SIgor Mammedov &pm->acpi_memory_hotplug, 34880db0e78SIgor Mammedov ACPI_MEMORY_HOTPLUG_BASE); 3491f862184SIgor Mammedov } 35049ab747fSPaolo Bonzini } 3516f1426abSMichael S. Tsirkin 352d7bce999SEric Blake static void ich9_pm_get_gpe0_blk(Object *obj, Visitor *v, const char *name, 353d7bce999SEric Blake void *opaque, Error **errp) 3546f1426abSMichael S. Tsirkin { 3556f1426abSMichael S. Tsirkin ICH9LPCPMRegs *pm = opaque; 3566f1426abSMichael S. Tsirkin uint32_t value = pm->pm_io_base + ICH9_PMIO_GPE0_STS; 3576f1426abSMichael S. Tsirkin 35851e72bc1SEric Blake visit_type_uint32(v, name, &value, errp); 3596f1426abSMichael S. Tsirkin } 3606f1426abSMichael S. Tsirkin 3611f862184SIgor Mammedov static bool ich9_pm_get_memory_hotplug_support(Object *obj, Error **errp) 3621f862184SIgor Mammedov { 3631f862184SIgor Mammedov ICH9LPCState *s = ICH9_LPC_DEVICE(obj); 3641f862184SIgor Mammedov 3651f862184SIgor Mammedov return s->pm.acpi_memory_hotplug.is_enabled; 3661f862184SIgor Mammedov } 3671f862184SIgor Mammedov 3681f862184SIgor Mammedov static void ich9_pm_set_memory_hotplug_support(Object *obj, bool value, 3691f862184SIgor Mammedov Error **errp) 3701f862184SIgor Mammedov { 3711f862184SIgor Mammedov ICH9LPCState *s = ICH9_LPC_DEVICE(obj); 3721f862184SIgor Mammedov 3731f862184SIgor Mammedov s->pm.acpi_memory_hotplug.is_enabled = value; 3741f862184SIgor Mammedov } 3751f862184SIgor Mammedov 37616bcab97SIgor Mammedov static bool ich9_pm_get_cpu_hotplug_legacy(Object *obj, Error **errp) 37716bcab97SIgor Mammedov { 37816bcab97SIgor Mammedov ICH9LPCState *s = ICH9_LPC_DEVICE(obj); 37916bcab97SIgor Mammedov 38016bcab97SIgor Mammedov return s->pm.cpu_hotplug_legacy; 38116bcab97SIgor Mammedov } 38216bcab97SIgor Mammedov 38316bcab97SIgor Mammedov static void ich9_pm_set_cpu_hotplug_legacy(Object *obj, bool value, 38416bcab97SIgor Mammedov Error **errp) 38516bcab97SIgor Mammedov { 38616bcab97SIgor Mammedov ICH9LPCState *s = ICH9_LPC_DEVICE(obj); 38716bcab97SIgor Mammedov 388679dd1a9SIgor Mammedov assert(!value); 389679dd1a9SIgor Mammedov if (s->pm.cpu_hotplug_legacy && value == false) { 390679dd1a9SIgor Mammedov acpi_switch_to_modern_cphp(&s->pm.gpe_cpu, &s->pm.cpuhp_state, 391679dd1a9SIgor Mammedov ICH9_CPU_HOTPLUG_IO_BASE); 392679dd1a9SIgor Mammedov } 39316bcab97SIgor Mammedov s->pm.cpu_hotplug_legacy = value; 39416bcab97SIgor Mammedov } 39516bcab97SIgor Mammedov 39692055797SPaulo Alcantara static bool ich9_pm_get_enable_tco(Object *obj, Error **errp) 39792055797SPaulo Alcantara { 39892055797SPaulo Alcantara ICH9LPCState *s = ICH9_LPC_DEVICE(obj); 39992055797SPaulo Alcantara return s->pm.enable_tco; 40092055797SPaulo Alcantara } 40192055797SPaulo Alcantara 40292055797SPaulo Alcantara static void ich9_pm_set_enable_tco(Object *obj, bool value, Error **errp) 40392055797SPaulo Alcantara { 40492055797SPaulo Alcantara ICH9LPCState *s = ICH9_LPC_DEVICE(obj); 40592055797SPaulo Alcantara s->pm.enable_tco = value; 40692055797SPaulo Alcantara } 40792055797SPaulo Alcantara 408*c0e427d6SJulia Suvorova static bool ich9_pm_get_acpi_pci_hotplug(Object *obj, Error **errp) 409*c0e427d6SJulia Suvorova { 410*c0e427d6SJulia Suvorova ICH9LPCState *s = ICH9_LPC_DEVICE(obj); 411*c0e427d6SJulia Suvorova 412*c0e427d6SJulia Suvorova return s->pm.use_acpi_hotplug_bridge; 413*c0e427d6SJulia Suvorova } 414*c0e427d6SJulia Suvorova 415*c0e427d6SJulia Suvorova static void ich9_pm_set_acpi_pci_hotplug(Object *obj, bool value, Error **errp) 416*c0e427d6SJulia Suvorova { 417*c0e427d6SJulia Suvorova ICH9LPCState *s = ICH9_LPC_DEVICE(obj); 418*c0e427d6SJulia Suvorova 419*c0e427d6SJulia Suvorova s->pm.use_acpi_hotplug_bridge = value; 420*c0e427d6SJulia Suvorova } 421*c0e427d6SJulia Suvorova 42240c2281cSMarkus Armbruster void ich9_pm_add_properties(Object *obj, ICH9LPCPMRegs *pm) 4236f1426abSMichael S. Tsirkin { 4246f1426abSMichael S. Tsirkin static const uint32_t gpe0_len = ICH9_PMIO_GPE0_LEN; 4251f862184SIgor Mammedov pm->acpi_memory_hotplug.is_enabled = true; 42616bcab97SIgor Mammedov pm->cpu_hotplug_legacy = true; 4276ac0d8d4SAmit Shah pm->disable_s3 = 0; 4286ac0d8d4SAmit Shah pm->disable_s4 = 0; 4296ac0d8d4SAmit Shah pm->s4_val = 2; 430*c0e427d6SJulia Suvorova pm->use_acpi_hotplug_bridge = false; 4316f1426abSMichael S. Tsirkin 4326f1426abSMichael S. Tsirkin object_property_add_uint32_ptr(obj, ACPI_PM_PROP_PM_IO_BASE, 433d2623129SMarkus Armbruster &pm->pm_io_base, OBJ_PROP_FLAG_READ); 4346f1426abSMichael S. Tsirkin object_property_add(obj, ACPI_PM_PROP_GPE0_BLK, "uint32", 4356f1426abSMichael S. Tsirkin ich9_pm_get_gpe0_blk, 436d2623129SMarkus Armbruster NULL, NULL, pm); 4376f1426abSMichael S. Tsirkin object_property_add_uint32_ptr(obj, ACPI_PM_PROP_GPE0_BLK_LEN, 438d2623129SMarkus Armbruster &gpe0_len, OBJ_PROP_FLAG_READ); 4391f862184SIgor Mammedov object_property_add_bool(obj, "memory-hotplug-support", 4401f862184SIgor Mammedov ich9_pm_get_memory_hotplug_support, 441d2623129SMarkus Armbruster ich9_pm_set_memory_hotplug_support); 44216bcab97SIgor Mammedov object_property_add_bool(obj, "cpu-hotplug-legacy", 44316bcab97SIgor Mammedov ich9_pm_get_cpu_hotplug_legacy, 444d2623129SMarkus Armbruster ich9_pm_set_cpu_hotplug_legacy); 44564a7b8deSFelipe Franciosi object_property_add_uint8_ptr(obj, ACPI_PM_PROP_S3_DISABLED, 446d2623129SMarkus Armbruster &pm->disable_s3, OBJ_PROP_FLAG_READWRITE); 44764a7b8deSFelipe Franciosi object_property_add_uint8_ptr(obj, ACPI_PM_PROP_S4_DISABLED, 448d2623129SMarkus Armbruster &pm->disable_s4, OBJ_PROP_FLAG_READWRITE); 44964a7b8deSFelipe Franciosi object_property_add_uint8_ptr(obj, ACPI_PM_PROP_S4_VAL, 450d2623129SMarkus Armbruster &pm->s4_val, OBJ_PROP_FLAG_READWRITE); 45192055797SPaulo Alcantara object_property_add_bool(obj, ACPI_PM_PROP_TCO_ENABLED, 45292055797SPaulo Alcantara ich9_pm_get_enable_tco, 453d2623129SMarkus Armbruster ich9_pm_set_enable_tco); 454*c0e427d6SJulia Suvorova object_property_add_bool(obj, "acpi-pci-hotplug-with-bridge-support", 455*c0e427d6SJulia Suvorova ich9_pm_get_acpi_pci_hotplug, 456*c0e427d6SJulia Suvorova ich9_pm_set_acpi_pci_hotplug); 4571f862184SIgor Mammedov } 4581f862184SIgor Mammedov 4599040e6dfSWei Yang void ich9_pm_device_pre_plug_cb(HotplugHandler *hotplug_dev, DeviceState *dev, 4609040e6dfSWei Yang Error **errp) 4619040e6dfSWei Yang { 4629040e6dfSWei Yang ICH9LPCState *lpc = ICH9_LPC_DEVICE(hotplug_dev); 4639040e6dfSWei Yang 464*c0e427d6SJulia Suvorova if (object_dynamic_cast(OBJECT(dev), TYPE_PCI_DEVICE)) { 465*c0e427d6SJulia Suvorova acpi_pcihp_device_pre_plug_cb(hotplug_dev, dev, errp); 466*c0e427d6SJulia Suvorova return; 467*c0e427d6SJulia Suvorova } 468*c0e427d6SJulia Suvorova 4699040e6dfSWei Yang if (object_dynamic_cast(OBJECT(dev), TYPE_PC_DIMM) && 470c5be7517SIgor Mammedov !lpc->pm.acpi_memory_hotplug.is_enabled) { 4719040e6dfSWei Yang error_setg(errp, 4729040e6dfSWei Yang "memory hotplug is not enabled: %s.memory-hotplug-support " 4739040e6dfSWei Yang "is not set", object_get_typename(OBJECT(lpc))); 474c5be7517SIgor Mammedov } else if (object_dynamic_cast(OBJECT(dev), TYPE_CPU)) { 475c5be7517SIgor Mammedov uint64_t negotiated = lpc->smi_negotiated_features; 476c5be7517SIgor Mammedov 477c5be7517SIgor Mammedov if (negotiated & BIT_ULL(ICH9_LPC_SMI_F_BROADCAST_BIT) && 478c5be7517SIgor Mammedov !(negotiated & BIT_ULL(ICH9_LPC_SMI_F_CPU_HOTPLUG_BIT))) { 479c5be7517SIgor Mammedov error_setg(errp, "cpu hotplug with SMI wasn't enabled by firmware"); 480c5be7517SIgor Mammedov error_append_hint(errp, "update machine type to newer than 5.1 " 481c5be7517SIgor Mammedov "and firmware that suppors CPU hotplug with SMM"); 482c5be7517SIgor Mammedov } 483c5be7517SIgor Mammedov } 4849040e6dfSWei Yang } 4859040e6dfSWei Yang 4860058c082SIgor Mammedov void ich9_pm_device_plug_cb(HotplugHandler *hotplug_dev, DeviceState *dev, 4870058c082SIgor Mammedov Error **errp) 4881f862184SIgor Mammedov { 4890058c082SIgor Mammedov ICH9LPCState *lpc = ICH9_LPC_DEVICE(hotplug_dev); 4900058c082SIgor Mammedov 4919040e6dfSWei Yang if (object_dynamic_cast(OBJECT(dev), TYPE_PC_DIMM)) { 49275f27498SXiao Guangrong if (object_dynamic_cast(OBJECT(dev), TYPE_NVDIMM)) { 49375f27498SXiao Guangrong nvdimm_acpi_plug_cb(hotplug_dev, dev); 49475f27498SXiao Guangrong } else { 4950058c082SIgor Mammedov acpi_memory_plug_cb(hotplug_dev, &lpc->pm.acpi_memory_hotplug, 4961f862184SIgor Mammedov dev, errp); 49775f27498SXiao Guangrong } 4985e1b5d93SIgor Mammedov } else if (object_dynamic_cast(OBJECT(dev), TYPE_CPU)) { 4995e1b5d93SIgor Mammedov if (lpc->pm.cpu_hotplug_legacy) { 5000058c082SIgor Mammedov legacy_acpi_cpu_plug_cb(hotplug_dev, &lpc->pm.gpe_cpu, dev, errp); 5011f862184SIgor Mammedov } else { 5025e1b5d93SIgor Mammedov acpi_cpu_plug_cb(hotplug_dev, &lpc->pm.cpuhp_state, dev, errp); 5035e1b5d93SIgor Mammedov } 504*c0e427d6SJulia Suvorova } else if (object_dynamic_cast(OBJECT(dev), TYPE_PCI_DEVICE)) { 505*c0e427d6SJulia Suvorova acpi_pcihp_device_plug_cb(hotplug_dev, &lpc->pm.acpi_pci_hotplug, 506*c0e427d6SJulia Suvorova dev, errp); 5075e1b5d93SIgor Mammedov } else { 5081f862184SIgor Mammedov error_setg(errp, "acpi: device plug request for not supported device" 5091f862184SIgor Mammedov " type: %s", object_get_typename(OBJECT(dev))); 5101f862184SIgor Mammedov } 5116f1426abSMichael S. Tsirkin } 51243f50410SIgor Mammedov 5130058c082SIgor Mammedov void ich9_pm_device_unplug_request_cb(HotplugHandler *hotplug_dev, 5140058c082SIgor Mammedov DeviceState *dev, Error **errp) 515469b8ad2STang Chen { 5160058c082SIgor Mammedov ICH9LPCState *lpc = ICH9_LPC_DEVICE(hotplug_dev); 5170058c082SIgor Mammedov 5180058c082SIgor Mammedov if (lpc->pm.acpi_memory_hotplug.is_enabled && 51964fec58eSTang Chen object_dynamic_cast(OBJECT(dev), TYPE_PC_DIMM)) { 5200058c082SIgor Mammedov acpi_memory_unplug_request_cb(hotplug_dev, 5210058c082SIgor Mammedov &lpc->pm.acpi_memory_hotplug, dev, 5220058c082SIgor Mammedov errp); 5238872c25aSIgor Mammedov } else if (object_dynamic_cast(OBJECT(dev), TYPE_CPU) && 5248872c25aSIgor Mammedov !lpc->pm.cpu_hotplug_legacy) { 525b48ad7c0SIgor Mammedov uint64_t negotiated = lpc->smi_negotiated_features; 526b48ad7c0SIgor Mammedov 527b48ad7c0SIgor Mammedov if (negotiated & BIT_ULL(ICH9_LPC_SMI_F_BROADCAST_BIT) && 528b48ad7c0SIgor Mammedov !(negotiated & BIT_ULL(ICH9_LPC_SMI_F_CPU_HOT_UNPLUG_BIT))) { 529b48ad7c0SIgor Mammedov error_setg(errp, "cpu hot-unplug with SMI wasn't enabled " 530b48ad7c0SIgor Mammedov "by firmware"); 531b48ad7c0SIgor Mammedov error_append_hint(errp, "update machine type to a version having " 532b48ad7c0SIgor Mammedov "x-smi-cpu-hotunplug=on and firmware that " 533b48ad7c0SIgor Mammedov "supports CPU hot-unplug with SMM"); 534b48ad7c0SIgor Mammedov return; 535b48ad7c0SIgor Mammedov } 536b48ad7c0SIgor Mammedov 5378872c25aSIgor Mammedov acpi_cpu_unplug_request_cb(hotplug_dev, &lpc->pm.cpuhp_state, 5388872c25aSIgor Mammedov dev, errp); 539*c0e427d6SJulia Suvorova } else if (object_dynamic_cast(OBJECT(dev), TYPE_PCI_DEVICE)) { 540*c0e427d6SJulia Suvorova acpi_pcihp_device_unplug_request_cb(hotplug_dev, 541*c0e427d6SJulia Suvorova &lpc->pm.acpi_pci_hotplug, 542*c0e427d6SJulia Suvorova dev, errp); 54364fec58eSTang Chen } else { 544469b8ad2STang Chen error_setg(errp, "acpi: device unplug request for not supported device" 545469b8ad2STang Chen " type: %s", object_get_typename(OBJECT(dev))); 546469b8ad2STang Chen } 54764fec58eSTang Chen } 548469b8ad2STang Chen 5490058c082SIgor Mammedov void ich9_pm_device_unplug_cb(HotplugHandler *hotplug_dev, DeviceState *dev, 55091a734a6STang Chen Error **errp) 55191a734a6STang Chen { 5520058c082SIgor Mammedov ICH9LPCState *lpc = ICH9_LPC_DEVICE(hotplug_dev); 5530058c082SIgor Mammedov 5540058c082SIgor Mammedov if (lpc->pm.acpi_memory_hotplug.is_enabled && 555f7d3e29dSTang Chen object_dynamic_cast(OBJECT(dev), TYPE_PC_DIMM)) { 5560058c082SIgor Mammedov acpi_memory_unplug_cb(&lpc->pm.acpi_memory_hotplug, dev, errp); 5578872c25aSIgor Mammedov } else if (object_dynamic_cast(OBJECT(dev), TYPE_CPU) && 5588872c25aSIgor Mammedov !lpc->pm.cpu_hotplug_legacy) { 5598872c25aSIgor Mammedov acpi_cpu_unplug_cb(&lpc->pm.cpuhp_state, dev, errp); 560*c0e427d6SJulia Suvorova } else if (object_dynamic_cast(OBJECT(dev), TYPE_PCI_DEVICE)) { 561*c0e427d6SJulia Suvorova acpi_pcihp_device_unplug_cb(hotplug_dev, &lpc->pm.acpi_pci_hotplug, 562*c0e427d6SJulia Suvorova dev, errp); 563f7d3e29dSTang Chen } else { 56491a734a6STang Chen error_setg(errp, "acpi: device unplug for not supported device" 56591a734a6STang Chen " type: %s", object_get_typename(OBJECT(dev))); 56691a734a6STang Chen } 567f7d3e29dSTang Chen } 56891a734a6STang Chen 56943f50410SIgor Mammedov void ich9_pm_ospm_status(AcpiDeviceIf *adev, ACPIOSTInfoList ***list) 57043f50410SIgor Mammedov { 57143f50410SIgor Mammedov ICH9LPCState *s = ICH9_LPC_DEVICE(adev); 57243f50410SIgor Mammedov 57343f50410SIgor Mammedov acpi_memory_ospm_status(&s->pm.acpi_memory_hotplug, list); 57476623d00SIgor Mammedov if (!s->pm.cpu_hotplug_legacy) { 57576623d00SIgor Mammedov acpi_cpu_ospm_status(&s->pm.cpuhp_state, list); 57676623d00SIgor Mammedov } 57743f50410SIgor Mammedov } 578