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" 37*fbae27e8SPhilippe Mathieu-Daudé #include "hw/acpi/ich9_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, 1665cd8cadaSJuan Quintela .needed = vmstate_test_use_memhp, 167f816a62dSIgor Mammedov .fields = (VMStateField[]) { 168f816a62dSIgor Mammedov VMSTATE_MEMORY_HOTPLUG(acpi_memory_hotplug, ICH9LPCPMRegs), 169f816a62dSIgor Mammedov VMSTATE_END_OF_LIST() 170f816a62dSIgor Mammedov } 171f816a62dSIgor Mammedov }; 172f816a62dSIgor Mammedov 17392055797SPaulo Alcantara static bool vmstate_test_use_tco(void *opaque) 17492055797SPaulo Alcantara { 17592055797SPaulo Alcantara ICH9LPCPMRegs *s = opaque; 17692055797SPaulo Alcantara return s->enable_tco; 17792055797SPaulo Alcantara } 17892055797SPaulo Alcantara 17992055797SPaulo Alcantara static const VMStateDescription vmstate_tco_io_state = { 18092055797SPaulo Alcantara .name = "ich9_pm/tco", 18192055797SPaulo Alcantara .version_id = 1, 18292055797SPaulo Alcantara .minimum_version_id = 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 191679dd1a9SIgor Mammedov static bool vmstate_test_use_cpuhp(void *opaque) 192679dd1a9SIgor Mammedov { 193679dd1a9SIgor Mammedov ICH9LPCPMRegs *s = opaque; 194679dd1a9SIgor Mammedov return !s->cpu_hotplug_legacy; 195679dd1a9SIgor Mammedov } 196679dd1a9SIgor Mammedov 197679dd1a9SIgor Mammedov static int vmstate_cpuhp_pre_load(void *opaque) 198679dd1a9SIgor Mammedov { 199679dd1a9SIgor Mammedov ICH9LPCPMRegs *s = opaque; 200679dd1a9SIgor Mammedov Object *obj = OBJECT(s->gpe_cpu.device); 2015325cc34SMarkus Armbruster object_property_set_bool(obj, "cpu-hotplug-legacy", false, &error_abort); 202679dd1a9SIgor Mammedov return 0; 203679dd1a9SIgor Mammedov } 204679dd1a9SIgor Mammedov 205679dd1a9SIgor Mammedov static const VMStateDescription vmstate_cpuhp_state = { 206679dd1a9SIgor Mammedov .name = "ich9_pm/cpuhp", 207679dd1a9SIgor Mammedov .version_id = 1, 208679dd1a9SIgor Mammedov .minimum_version_id = 1, 209679dd1a9SIgor Mammedov .needed = vmstate_test_use_cpuhp, 210679dd1a9SIgor Mammedov .pre_load = vmstate_cpuhp_pre_load, 211679dd1a9SIgor Mammedov .fields = (VMStateField[]) { 212679dd1a9SIgor Mammedov VMSTATE_CPU_HOTPLUG(cpuhp_state, ICH9LPCPMRegs), 213679dd1a9SIgor Mammedov VMSTATE_END_OF_LIST() 214679dd1a9SIgor Mammedov } 215679dd1a9SIgor Mammedov }; 216679dd1a9SIgor Mammedov 217c0e427d6SJulia Suvorova static bool vmstate_test_use_pcihp(void *opaque) 218c0e427d6SJulia Suvorova { 219c0e427d6SJulia Suvorova ICH9LPCPMRegs *s = opaque; 220c0e427d6SJulia Suvorova 221c0e427d6SJulia Suvorova return s->use_acpi_hotplug_bridge; 222c0e427d6SJulia Suvorova } 223c0e427d6SJulia Suvorova 224c0e427d6SJulia Suvorova static const VMStateDescription vmstate_pcihp_state = { 225c0e427d6SJulia Suvorova .name = "ich9_pm/pcihp", 226c0e427d6SJulia Suvorova .version_id = 1, 227c0e427d6SJulia Suvorova .minimum_version_id = 1, 228c0e427d6SJulia Suvorova .needed = vmstate_test_use_pcihp, 229c0e427d6SJulia Suvorova .fields = (VMStateField[]) { 230c0e427d6SJulia Suvorova VMSTATE_PCI_HOTPLUG(acpi_pci_hotplug, 231c0e427d6SJulia Suvorova ICH9LPCPMRegs, 232c0e427d6SJulia Suvorova NULL, NULL), 233c0e427d6SJulia Suvorova VMSTATE_END_OF_LIST() 234c0e427d6SJulia Suvorova } 235c0e427d6SJulia Suvorova }; 236c0e427d6SJulia Suvorova 23749ab747fSPaolo Bonzini const VMStateDescription vmstate_ich9_pm = { 23849ab747fSPaolo Bonzini .name = "ich9_pm", 23949ab747fSPaolo Bonzini .version_id = 1, 24049ab747fSPaolo Bonzini .minimum_version_id = 1, 24149ab747fSPaolo Bonzini .post_load = ich9_pm_post_load, 24249ab747fSPaolo Bonzini .fields = (VMStateField[]) { 24349ab747fSPaolo Bonzini VMSTATE_UINT16(acpi_regs.pm1.evt.sts, ICH9LPCPMRegs), 24449ab747fSPaolo Bonzini VMSTATE_UINT16(acpi_regs.pm1.evt.en, ICH9LPCPMRegs), 24549ab747fSPaolo Bonzini VMSTATE_UINT16(acpi_regs.pm1.cnt.cnt, ICH9LPCPMRegs), 246e720677eSPaolo Bonzini VMSTATE_TIMER_PTR(acpi_regs.tmr.timer, ICH9LPCPMRegs), 24749ab747fSPaolo Bonzini VMSTATE_INT64(acpi_regs.tmr.overflow_time, ICH9LPCPMRegs), 24849ab747fSPaolo Bonzini VMSTATE_GPE_ARRAY(acpi_regs.gpe.sts, ICH9LPCPMRegs), 24949ab747fSPaolo Bonzini VMSTATE_GPE_ARRAY(acpi_regs.gpe.en, ICH9LPCPMRegs), 25049ab747fSPaolo Bonzini VMSTATE_UINT32(smi_en, ICH9LPCPMRegs), 25149ab747fSPaolo Bonzini VMSTATE_UINT32(smi_sts, ICH9LPCPMRegs), 25249ab747fSPaolo Bonzini VMSTATE_END_OF_LIST() 253f816a62dSIgor Mammedov }, 2545cd8cadaSJuan Quintela .subsections = (const VMStateDescription*[]) { 2555cd8cadaSJuan Quintela &vmstate_memhp_state, 25692055797SPaulo Alcantara &vmstate_tco_io_state, 257679dd1a9SIgor Mammedov &vmstate_cpuhp_state, 258c0e427d6SJulia Suvorova &vmstate_pcihp_state, 25992055797SPaulo Alcantara NULL 26049ab747fSPaolo Bonzini } 26149ab747fSPaolo Bonzini }; 26249ab747fSPaolo Bonzini 26349ab747fSPaolo Bonzini static void pm_reset(void *opaque) 26449ab747fSPaolo Bonzini { 26549ab747fSPaolo Bonzini ICH9LPCPMRegs *pm = opaque; 26649ab747fSPaolo Bonzini ich9_pm_iospace_update(pm, 0); 26749ab747fSPaolo Bonzini 26849ab747fSPaolo Bonzini acpi_pm1_evt_reset(&pm->acpi_regs); 26949ab747fSPaolo Bonzini acpi_pm1_cnt_reset(&pm->acpi_regs); 27049ab747fSPaolo Bonzini acpi_pm_tmr_reset(&pm->acpi_regs); 27149ab747fSPaolo Bonzini acpi_gpe_reset(&pm->acpi_regs); 27249ab747fSPaolo Bonzini 273be66680eSLaszlo Ersek pm->smi_en = 0; 274fba72476SPaolo Bonzini if (!pm->smm_enabled) { 275f3c30aeaSLaszlo Ersek /* Mark SMM as already inited to prevent SMM from running. */ 27649ab747fSPaolo Bonzini pm->smi_en |= ICH9_PMIO_SMI_EN_APMC_EN; 27749ab747fSPaolo Bonzini } 27811e66a15SGerd Hoffmann pm->smi_en_wmask = ~0; 27949ab747fSPaolo Bonzini 280c0e427d6SJulia Suvorova if (pm->use_acpi_hotplug_bridge) { 281c0e427d6SJulia Suvorova acpi_pcihp_reset(&pm->acpi_pci_hotplug, true); 282c0e427d6SJulia Suvorova } 283c0e427d6SJulia Suvorova 28406313503SIgor Mammedov acpi_update_sci(&pm->acpi_regs, pm->irq); 28549ab747fSPaolo Bonzini } 28649ab747fSPaolo Bonzini 28749ab747fSPaolo Bonzini static void pm_powerdown_req(Notifier *n, void *opaque) 28849ab747fSPaolo Bonzini { 28949ab747fSPaolo Bonzini ICH9LPCPMRegs *pm = container_of(n, ICH9LPCPMRegs, powerdown_notifier); 29049ab747fSPaolo Bonzini 29149ab747fSPaolo Bonzini acpi_pm1_evt_power_down(&pm->acpi_regs); 29249ab747fSPaolo Bonzini } 29349ab747fSPaolo Bonzini 29492055797SPaulo Alcantara void ich9_pm_init(PCIDevice *lpc_pci, ICH9LPCPMRegs *pm, 29518d6abaeSEduardo Habkost bool smm_enabled, 296a3ac6b53SHu Tao qemu_irq sci_irq) 29749ab747fSPaolo Bonzini { 29864bde0f3SPaolo Bonzini memory_region_init(&pm->io, OBJECT(lpc_pci), "ich9-pm", ICH9_PMIO_SIZE); 29949ab747fSPaolo Bonzini memory_region_set_enabled(&pm->io, false); 30049ab747fSPaolo Bonzini memory_region_add_subregion(pci_address_space_io(lpc_pci), 30149ab747fSPaolo Bonzini 0, &pm->io); 30249ab747fSPaolo Bonzini 30349ab747fSPaolo Bonzini acpi_pm_tmr_init(&pm->acpi_regs, ich9_pm_update_sci_fn, &pm->io); 30449ab747fSPaolo Bonzini acpi_pm1_evt_init(&pm->acpi_regs, ich9_pm_update_sci_fn, &pm->io); 3059a10bbb4SLaszlo Ersek acpi_pm1_cnt_init(&pm->acpi_regs, &pm->io, pm->disable_s3, pm->disable_s4, 3066be8cf56SIsaku Yamahata pm->s4_val, !pm->smm_compat && !smm_enabled); 30749ab747fSPaolo Bonzini 30849ab747fSPaolo Bonzini acpi_gpe_init(&pm->acpi_regs, ICH9_PMIO_GPE0_LEN); 30964bde0f3SPaolo Bonzini memory_region_init_io(&pm->io_gpe, OBJECT(lpc_pci), &ich9_gpe_ops, pm, 31075902802SHu Tao "acpi-gpe0", ICH9_PMIO_GPE0_LEN); 31149ab747fSPaolo Bonzini memory_region_add_subregion(&pm->io, ICH9_PMIO_GPE0_STS, &pm->io_gpe); 31249ab747fSPaolo Bonzini 31364bde0f3SPaolo Bonzini memory_region_init_io(&pm->io_smi, OBJECT(lpc_pci), &ich9_smi_ops, pm, 31475902802SHu Tao "acpi-smi", 8); 31549ab747fSPaolo Bonzini memory_region_add_subregion(&pm->io, ICH9_PMIO_SMI_EN, &pm->io_smi); 31649ab747fSPaolo Bonzini 317fba72476SPaolo Bonzini pm->smm_enabled = smm_enabled; 31892055797SPaulo Alcantara 319ee1c08bdSDaniel P. Berrangé if (pm->enable_tco) { 32092055797SPaulo Alcantara acpi_pm_tco_init(&pm->tco_regs, &pm->io); 321ee1c08bdSDaniel P. Berrangé } 32292055797SPaulo Alcantara 323c0e427d6SJulia Suvorova if (pm->use_acpi_hotplug_bridge) { 324c0e427d6SJulia Suvorova acpi_pcihp_init(OBJECT(lpc_pci), 325c0e427d6SJulia Suvorova &pm->acpi_pci_hotplug, 326c0e427d6SJulia Suvorova pci_get_bus(lpc_pci), 327c0e427d6SJulia Suvorova pci_address_space_io(lpc_pci), 328c0e427d6SJulia Suvorova true, 329c0e427d6SJulia Suvorova ACPI_PCIHP_ADDR_ICH9); 330c0e427d6SJulia Suvorova 331c0e427d6SJulia Suvorova qbus_set_hotplug_handler(BUS(pci_get_bus(lpc_pci)), 332c0e427d6SJulia Suvorova OBJECT(lpc_pci)); 333c0e427d6SJulia Suvorova } 334c0e427d6SJulia Suvorova 33549ab747fSPaolo Bonzini pm->irq = sci_irq; 33649ab747fSPaolo Bonzini qemu_register_reset(pm_reset, pm); 33749ab747fSPaolo Bonzini pm->powerdown_notifier.notify = pm_powerdown_req; 33849ab747fSPaolo Bonzini qemu_register_powerdown_notifier(&pm->powerdown_notifier); 339d6610bc2SIgor Mammedov 34096e3e12bSIgor Mammedov legacy_acpi_cpu_hotplug_init(pci_address_space_io(lpc_pci), 34196e3e12bSIgor Mammedov OBJECT(lpc_pci), &pm->gpe_cpu, ICH9_CPU_HOTPLUG_IO_BASE); 3421f862184SIgor Mammedov 3431f862184SIgor Mammedov if (pm->acpi_memory_hotplug.is_enabled) { 3441f862184SIgor Mammedov acpi_memory_hotplug_init(pci_address_space_io(lpc_pci), OBJECT(lpc_pci), 34580db0e78SIgor Mammedov &pm->acpi_memory_hotplug, 34680db0e78SIgor Mammedov ACPI_MEMORY_HOTPLUG_BASE); 3471f862184SIgor Mammedov } 34849ab747fSPaolo Bonzini } 3496f1426abSMichael S. Tsirkin 350d7bce999SEric Blake static void ich9_pm_get_gpe0_blk(Object *obj, Visitor *v, const char *name, 351d7bce999SEric Blake void *opaque, Error **errp) 3526f1426abSMichael S. Tsirkin { 3536f1426abSMichael S. Tsirkin ICH9LPCPMRegs *pm = opaque; 3546f1426abSMichael S. Tsirkin uint32_t value = pm->pm_io_base + ICH9_PMIO_GPE0_STS; 3556f1426abSMichael S. Tsirkin 35651e72bc1SEric Blake visit_type_uint32(v, name, &value, errp); 3576f1426abSMichael S. Tsirkin } 3586f1426abSMichael S. Tsirkin 3591f862184SIgor Mammedov static bool ich9_pm_get_memory_hotplug_support(Object *obj, Error **errp) 3601f862184SIgor Mammedov { 3611f862184SIgor Mammedov ICH9LPCState *s = ICH9_LPC_DEVICE(obj); 3621f862184SIgor Mammedov 3631f862184SIgor Mammedov return s->pm.acpi_memory_hotplug.is_enabled; 3641f862184SIgor Mammedov } 3651f862184SIgor Mammedov 3661f862184SIgor Mammedov static void ich9_pm_set_memory_hotplug_support(Object *obj, bool value, 3671f862184SIgor Mammedov Error **errp) 3681f862184SIgor Mammedov { 3691f862184SIgor Mammedov ICH9LPCState *s = ICH9_LPC_DEVICE(obj); 3701f862184SIgor Mammedov 3711f862184SIgor Mammedov s->pm.acpi_memory_hotplug.is_enabled = value; 3721f862184SIgor Mammedov } 3731f862184SIgor Mammedov 37416bcab97SIgor Mammedov static bool ich9_pm_get_cpu_hotplug_legacy(Object *obj, Error **errp) 37516bcab97SIgor Mammedov { 37616bcab97SIgor Mammedov ICH9LPCState *s = ICH9_LPC_DEVICE(obj); 37716bcab97SIgor Mammedov 37816bcab97SIgor Mammedov return s->pm.cpu_hotplug_legacy; 37916bcab97SIgor Mammedov } 38016bcab97SIgor Mammedov 38116bcab97SIgor Mammedov static void ich9_pm_set_cpu_hotplug_legacy(Object *obj, bool value, 38216bcab97SIgor Mammedov Error **errp) 38316bcab97SIgor Mammedov { 38416bcab97SIgor Mammedov ICH9LPCState *s = ICH9_LPC_DEVICE(obj); 38516bcab97SIgor Mammedov 386679dd1a9SIgor Mammedov assert(!value); 387679dd1a9SIgor Mammedov if (s->pm.cpu_hotplug_legacy && value == false) { 388679dd1a9SIgor Mammedov acpi_switch_to_modern_cphp(&s->pm.gpe_cpu, &s->pm.cpuhp_state, 389679dd1a9SIgor Mammedov ICH9_CPU_HOTPLUG_IO_BASE); 390679dd1a9SIgor Mammedov } 39116bcab97SIgor Mammedov s->pm.cpu_hotplug_legacy = value; 39216bcab97SIgor Mammedov } 39316bcab97SIgor Mammedov 39492055797SPaulo Alcantara static bool ich9_pm_get_enable_tco(Object *obj, Error **errp) 39592055797SPaulo Alcantara { 39692055797SPaulo Alcantara ICH9LPCState *s = ICH9_LPC_DEVICE(obj); 39792055797SPaulo Alcantara return s->pm.enable_tco; 39892055797SPaulo Alcantara } 39992055797SPaulo Alcantara 40092055797SPaulo Alcantara static void ich9_pm_set_enable_tco(Object *obj, bool value, Error **errp) 40192055797SPaulo Alcantara { 40292055797SPaulo Alcantara ICH9LPCState *s = ICH9_LPC_DEVICE(obj); 40392055797SPaulo Alcantara s->pm.enable_tco = value; 40492055797SPaulo Alcantara } 40592055797SPaulo Alcantara 406c0e427d6SJulia Suvorova static bool ich9_pm_get_acpi_pci_hotplug(Object *obj, Error **errp) 407c0e427d6SJulia Suvorova { 408c0e427d6SJulia Suvorova ICH9LPCState *s = ICH9_LPC_DEVICE(obj); 409c0e427d6SJulia Suvorova 410c0e427d6SJulia Suvorova return s->pm.use_acpi_hotplug_bridge; 411c0e427d6SJulia Suvorova } 412c0e427d6SJulia Suvorova 413c0e427d6SJulia Suvorova static void ich9_pm_set_acpi_pci_hotplug(Object *obj, bool value, Error **errp) 414c0e427d6SJulia Suvorova { 415c0e427d6SJulia Suvorova ICH9LPCState *s = ICH9_LPC_DEVICE(obj); 416c0e427d6SJulia Suvorova 417c0e427d6SJulia Suvorova s->pm.use_acpi_hotplug_bridge = value; 418c0e427d6SJulia Suvorova } 419c0e427d6SJulia Suvorova 420c318bef7SJulia Suvorova static bool ich9_pm_get_keep_pci_slot_hpc(Object *obj, Error **errp) 421c318bef7SJulia Suvorova { 422c318bef7SJulia Suvorova ICH9LPCState *s = ICH9_LPC_DEVICE(obj); 423c318bef7SJulia Suvorova 424c318bef7SJulia Suvorova return s->pm.keep_pci_slot_hpc; 425c318bef7SJulia Suvorova } 426c318bef7SJulia Suvorova 427c318bef7SJulia Suvorova static void ich9_pm_set_keep_pci_slot_hpc(Object *obj, bool value, Error **errp) 428c318bef7SJulia Suvorova { 429c318bef7SJulia Suvorova ICH9LPCState *s = ICH9_LPC_DEVICE(obj); 430c318bef7SJulia Suvorova 431c318bef7SJulia Suvorova s->pm.keep_pci_slot_hpc = value; 432c318bef7SJulia Suvorova } 433c318bef7SJulia Suvorova 43440c2281cSMarkus Armbruster void ich9_pm_add_properties(Object *obj, ICH9LPCPMRegs *pm) 4356f1426abSMichael S. Tsirkin { 4366f1426abSMichael S. Tsirkin static const uint32_t gpe0_len = ICH9_PMIO_GPE0_LEN; 4371f862184SIgor Mammedov pm->acpi_memory_hotplug.is_enabled = true; 43816bcab97SIgor Mammedov pm->cpu_hotplug_legacy = true; 4396ac0d8d4SAmit Shah pm->disable_s3 = 0; 4406ac0d8d4SAmit Shah pm->disable_s4 = 0; 4416ac0d8d4SAmit Shah pm->s4_val = 2; 44217858a16SJulia Suvorova pm->use_acpi_hotplug_bridge = true; 443c318bef7SJulia Suvorova pm->keep_pci_slot_hpc = true; 444ee1c08bdSDaniel P. Berrangé pm->enable_tco = true; 4456f1426abSMichael S. Tsirkin 4466f1426abSMichael S. Tsirkin object_property_add_uint32_ptr(obj, ACPI_PM_PROP_PM_IO_BASE, 447d2623129SMarkus Armbruster &pm->pm_io_base, OBJ_PROP_FLAG_READ); 4486f1426abSMichael S. Tsirkin object_property_add(obj, ACPI_PM_PROP_GPE0_BLK, "uint32", 4496f1426abSMichael S. Tsirkin ich9_pm_get_gpe0_blk, 450d2623129SMarkus Armbruster NULL, NULL, pm); 4516f1426abSMichael S. Tsirkin object_property_add_uint32_ptr(obj, ACPI_PM_PROP_GPE0_BLK_LEN, 452d2623129SMarkus Armbruster &gpe0_len, OBJ_PROP_FLAG_READ); 4531f862184SIgor Mammedov object_property_add_bool(obj, "memory-hotplug-support", 4541f862184SIgor Mammedov ich9_pm_get_memory_hotplug_support, 455d2623129SMarkus Armbruster ich9_pm_set_memory_hotplug_support); 45616bcab97SIgor Mammedov object_property_add_bool(obj, "cpu-hotplug-legacy", 45716bcab97SIgor Mammedov ich9_pm_get_cpu_hotplug_legacy, 458d2623129SMarkus Armbruster ich9_pm_set_cpu_hotplug_legacy); 45964a7b8deSFelipe Franciosi object_property_add_uint8_ptr(obj, ACPI_PM_PROP_S3_DISABLED, 460d2623129SMarkus Armbruster &pm->disable_s3, OBJ_PROP_FLAG_READWRITE); 46164a7b8deSFelipe Franciosi object_property_add_uint8_ptr(obj, ACPI_PM_PROP_S4_DISABLED, 462d2623129SMarkus Armbruster &pm->disable_s4, OBJ_PROP_FLAG_READWRITE); 46364a7b8deSFelipe Franciosi object_property_add_uint8_ptr(obj, ACPI_PM_PROP_S4_VAL, 464d2623129SMarkus Armbruster &pm->s4_val, OBJ_PROP_FLAG_READWRITE); 46592055797SPaulo Alcantara object_property_add_bool(obj, ACPI_PM_PROP_TCO_ENABLED, 46692055797SPaulo Alcantara ich9_pm_get_enable_tco, 467d2623129SMarkus Armbruster ich9_pm_set_enable_tco); 468aa29466bSAni Sinha object_property_add_bool(obj, ACPI_PM_PROP_ACPI_PCIHP_BRIDGE, 469c0e427d6SJulia Suvorova ich9_pm_get_acpi_pci_hotplug, 470c0e427d6SJulia Suvorova ich9_pm_set_acpi_pci_hotplug); 471c318bef7SJulia Suvorova object_property_add_bool(obj, "x-keep-pci-slot-hpc", 472c318bef7SJulia Suvorova ich9_pm_get_keep_pci_slot_hpc, 473c318bef7SJulia Suvorova ich9_pm_set_keep_pci_slot_hpc); 4741f862184SIgor Mammedov } 4751f862184SIgor Mammedov 4769040e6dfSWei Yang void ich9_pm_device_pre_plug_cb(HotplugHandler *hotplug_dev, DeviceState *dev, 4779040e6dfSWei Yang Error **errp) 4789040e6dfSWei Yang { 4799040e6dfSWei Yang ICH9LPCState *lpc = ICH9_LPC_DEVICE(hotplug_dev); 4809040e6dfSWei Yang 481c0e427d6SJulia Suvorova if (object_dynamic_cast(OBJECT(dev), TYPE_PCI_DEVICE)) { 482c0e427d6SJulia Suvorova acpi_pcihp_device_pre_plug_cb(hotplug_dev, dev, errp); 483c0e427d6SJulia Suvorova return; 484c0e427d6SJulia Suvorova } 485c0e427d6SJulia Suvorova 4869040e6dfSWei Yang if (object_dynamic_cast(OBJECT(dev), TYPE_PC_DIMM) && 487c5be7517SIgor Mammedov !lpc->pm.acpi_memory_hotplug.is_enabled) { 4889040e6dfSWei Yang error_setg(errp, 4899040e6dfSWei Yang "memory hotplug is not enabled: %s.memory-hotplug-support " 4909040e6dfSWei Yang "is not set", object_get_typename(OBJECT(lpc))); 491c5be7517SIgor Mammedov } else if (object_dynamic_cast(OBJECT(dev), TYPE_CPU)) { 492c5be7517SIgor Mammedov uint64_t negotiated = lpc->smi_negotiated_features; 493c5be7517SIgor Mammedov 494c5be7517SIgor Mammedov if (negotiated & BIT_ULL(ICH9_LPC_SMI_F_BROADCAST_BIT) && 495c5be7517SIgor Mammedov !(negotiated & BIT_ULL(ICH9_LPC_SMI_F_CPU_HOTPLUG_BIT))) { 496c5be7517SIgor Mammedov error_setg(errp, "cpu hotplug with SMI wasn't enabled by firmware"); 497c5be7517SIgor Mammedov error_append_hint(errp, "update machine type to newer than 5.1 " 498c5be7517SIgor Mammedov "and firmware that suppors CPU hotplug with SMM"); 499c5be7517SIgor Mammedov } 500c5be7517SIgor Mammedov } 5019040e6dfSWei Yang } 5029040e6dfSWei Yang 5030058c082SIgor Mammedov void ich9_pm_device_plug_cb(HotplugHandler *hotplug_dev, DeviceState *dev, 5040058c082SIgor Mammedov Error **errp) 5051f862184SIgor Mammedov { 5060058c082SIgor Mammedov ICH9LPCState *lpc = ICH9_LPC_DEVICE(hotplug_dev); 5070058c082SIgor Mammedov 5089040e6dfSWei Yang if (object_dynamic_cast(OBJECT(dev), TYPE_PC_DIMM)) { 50975f27498SXiao Guangrong if (object_dynamic_cast(OBJECT(dev), TYPE_NVDIMM)) { 51075f27498SXiao Guangrong nvdimm_acpi_plug_cb(hotplug_dev, dev); 51175f27498SXiao Guangrong } else { 5120058c082SIgor Mammedov acpi_memory_plug_cb(hotplug_dev, &lpc->pm.acpi_memory_hotplug, 5131f862184SIgor Mammedov dev, errp); 51475f27498SXiao Guangrong } 5155e1b5d93SIgor Mammedov } else if (object_dynamic_cast(OBJECT(dev), TYPE_CPU)) { 5165e1b5d93SIgor Mammedov if (lpc->pm.cpu_hotplug_legacy) { 5170058c082SIgor Mammedov legacy_acpi_cpu_plug_cb(hotplug_dev, &lpc->pm.gpe_cpu, dev, errp); 5181f862184SIgor Mammedov } else { 5195e1b5d93SIgor Mammedov acpi_cpu_plug_cb(hotplug_dev, &lpc->pm.cpuhp_state, dev, errp); 5205e1b5d93SIgor Mammedov } 521c0e427d6SJulia Suvorova } else if (object_dynamic_cast(OBJECT(dev), TYPE_PCI_DEVICE)) { 522c0e427d6SJulia Suvorova acpi_pcihp_device_plug_cb(hotplug_dev, &lpc->pm.acpi_pci_hotplug, 523c0e427d6SJulia Suvorova dev, errp); 5245e1b5d93SIgor Mammedov } else { 5251f862184SIgor Mammedov error_setg(errp, "acpi: device plug request for not supported device" 5261f862184SIgor Mammedov " type: %s", object_get_typename(OBJECT(dev))); 5271f862184SIgor Mammedov } 5286f1426abSMichael S. Tsirkin } 52943f50410SIgor Mammedov 5300058c082SIgor Mammedov void ich9_pm_device_unplug_request_cb(HotplugHandler *hotplug_dev, 5310058c082SIgor Mammedov DeviceState *dev, Error **errp) 532469b8ad2STang Chen { 5330058c082SIgor Mammedov ICH9LPCState *lpc = ICH9_LPC_DEVICE(hotplug_dev); 5340058c082SIgor Mammedov 5350058c082SIgor Mammedov if (lpc->pm.acpi_memory_hotplug.is_enabled && 53664fec58eSTang Chen object_dynamic_cast(OBJECT(dev), TYPE_PC_DIMM)) { 5370058c082SIgor Mammedov acpi_memory_unplug_request_cb(hotplug_dev, 5380058c082SIgor Mammedov &lpc->pm.acpi_memory_hotplug, dev, 5390058c082SIgor Mammedov errp); 5408872c25aSIgor Mammedov } else if (object_dynamic_cast(OBJECT(dev), TYPE_CPU) && 5418872c25aSIgor Mammedov !lpc->pm.cpu_hotplug_legacy) { 542b48ad7c0SIgor Mammedov uint64_t negotiated = lpc->smi_negotiated_features; 543b48ad7c0SIgor Mammedov 544b48ad7c0SIgor Mammedov if (negotiated & BIT_ULL(ICH9_LPC_SMI_F_BROADCAST_BIT) && 545b48ad7c0SIgor Mammedov !(negotiated & BIT_ULL(ICH9_LPC_SMI_F_CPU_HOT_UNPLUG_BIT))) { 546b48ad7c0SIgor Mammedov error_setg(errp, "cpu hot-unplug with SMI wasn't enabled " 547b48ad7c0SIgor Mammedov "by firmware"); 548b48ad7c0SIgor Mammedov error_append_hint(errp, "update machine type to a version having " 549b48ad7c0SIgor Mammedov "x-smi-cpu-hotunplug=on and firmware that " 550b48ad7c0SIgor Mammedov "supports CPU hot-unplug with SMM"); 551b48ad7c0SIgor Mammedov return; 552b48ad7c0SIgor Mammedov } 553b48ad7c0SIgor Mammedov 5548872c25aSIgor Mammedov acpi_cpu_unplug_request_cb(hotplug_dev, &lpc->pm.cpuhp_state, 5558872c25aSIgor Mammedov dev, errp); 556c0e427d6SJulia Suvorova } else if (object_dynamic_cast(OBJECT(dev), TYPE_PCI_DEVICE)) { 557c0e427d6SJulia Suvorova acpi_pcihp_device_unplug_request_cb(hotplug_dev, 558c0e427d6SJulia Suvorova &lpc->pm.acpi_pci_hotplug, 559c0e427d6SJulia Suvorova dev, errp); 56064fec58eSTang Chen } else { 561469b8ad2STang Chen error_setg(errp, "acpi: device unplug request for not supported device" 562469b8ad2STang Chen " type: %s", object_get_typename(OBJECT(dev))); 563469b8ad2STang Chen } 56464fec58eSTang Chen } 565469b8ad2STang Chen 5660058c082SIgor Mammedov void ich9_pm_device_unplug_cb(HotplugHandler *hotplug_dev, DeviceState *dev, 56791a734a6STang Chen Error **errp) 56891a734a6STang Chen { 5690058c082SIgor Mammedov ICH9LPCState *lpc = ICH9_LPC_DEVICE(hotplug_dev); 5700058c082SIgor Mammedov 5710058c082SIgor Mammedov if (lpc->pm.acpi_memory_hotplug.is_enabled && 572f7d3e29dSTang Chen object_dynamic_cast(OBJECT(dev), TYPE_PC_DIMM)) { 5730058c082SIgor Mammedov acpi_memory_unplug_cb(&lpc->pm.acpi_memory_hotplug, dev, errp); 5748872c25aSIgor Mammedov } else if (object_dynamic_cast(OBJECT(dev), TYPE_CPU) && 5758872c25aSIgor Mammedov !lpc->pm.cpu_hotplug_legacy) { 5768872c25aSIgor Mammedov acpi_cpu_unplug_cb(&lpc->pm.cpuhp_state, dev, errp); 577c0e427d6SJulia Suvorova } else if (object_dynamic_cast(OBJECT(dev), TYPE_PCI_DEVICE)) { 578c0e427d6SJulia Suvorova acpi_pcihp_device_unplug_cb(hotplug_dev, &lpc->pm.acpi_pci_hotplug, 579c0e427d6SJulia Suvorova dev, errp); 580f7d3e29dSTang Chen } else { 58191a734a6STang Chen error_setg(errp, "acpi: device unplug for not supported device" 58291a734a6STang Chen " type: %s", object_get_typename(OBJECT(dev))); 58391a734a6STang Chen } 584f7d3e29dSTang Chen } 58591a734a6STang Chen 58643f50410SIgor Mammedov void ich9_pm_ospm_status(AcpiDeviceIf *adev, ACPIOSTInfoList ***list) 58743f50410SIgor Mammedov { 58843f50410SIgor Mammedov ICH9LPCState *s = ICH9_LPC_DEVICE(adev); 58943f50410SIgor Mammedov 59043f50410SIgor Mammedov acpi_memory_ospm_status(&s->pm.acpi_memory_hotplug, list); 59176623d00SIgor Mammedov if (!s->pm.cpu_hotplug_legacy) { 59276623d00SIgor Mammedov acpi_cpu_ospm_status(&s->pm.cpuhp_state, list); 59376623d00SIgor Mammedov } 59443f50410SIgor Mammedov } 595