149ab747fSPaolo Bonzini /* 249ab747fSPaolo Bonzini * ACPI implementation 349ab747fSPaolo Bonzini * 449ab747fSPaolo Bonzini * Copyright (c) 2006 Fabrice Bellard 549ab747fSPaolo Bonzini * 649ab747fSPaolo Bonzini * This library is free software; you can redistribute it and/or 749ab747fSPaolo Bonzini * modify it under the terms of the GNU Lesser General Public 849ab747fSPaolo Bonzini * License version 2 as published by the Free Software Foundation. 949ab747fSPaolo Bonzini * 1049ab747fSPaolo Bonzini * This library is distributed in the hope that it will be useful, 1149ab747fSPaolo Bonzini * but WITHOUT ANY WARRANTY; without even the implied warranty of 1249ab747fSPaolo Bonzini * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 1349ab747fSPaolo Bonzini * Lesser General Public License for more details. 1449ab747fSPaolo Bonzini * 1549ab747fSPaolo Bonzini * You should have received a copy of the GNU Lesser General Public 1649ab747fSPaolo Bonzini * License along with this library; if not, see <http://www.gnu.org/licenses/> 1749ab747fSPaolo Bonzini * 1849ab747fSPaolo Bonzini * Contributions after 2012-01-13 are licensed under the terms of the 1949ab747fSPaolo Bonzini * GNU GPL, version 2 or (at your option) any later version. 2049ab747fSPaolo Bonzini */ 21b6a0aa05SPeter Maydell #include "qemu/osdep.h" 2249ab747fSPaolo Bonzini #include "hw/hw.h" 2349ab747fSPaolo Bonzini #include "hw/i386/pc.h" 2449ab747fSPaolo Bonzini #include "hw/isa/apm.h" 2549ab747fSPaolo Bonzini #include "hw/i2c/pm_smbus.h" 2649ab747fSPaolo Bonzini #include "hw/pci/pci.h" 2749ab747fSPaolo Bonzini #include "hw/acpi/acpi.h" 2849ab747fSPaolo Bonzini #include "sysemu/sysemu.h" 29da34e65cSMarkus Armbruster #include "qapi/error.h" 3049ab747fSPaolo Bonzini #include "qemu/range.h" 3149ab747fSPaolo Bonzini #include "exec/ioport.h" 3249ab747fSPaolo Bonzini #include "hw/nvram/fw_cfg.h" 3349ab747fSPaolo Bonzini #include "exec/address-spaces.h" 34277e9340SMichael S. Tsirkin #include "hw/acpi/piix4.h" 359e047b98SMichael S. Tsirkin #include "hw/acpi/pcihp.h" 3681cea5e7SIgor Mammedov #include "hw/acpi/cpu_hotplug.h" 375e1b5d93SIgor Mammedov #include "hw/acpi/cpu.h" 38c24d5e0bSIgor Mammedov #include "hw/hotplug.h" 3934774320SIgor Mammedov #include "hw/mem/pc-dimm.h" 4034774320SIgor Mammedov #include "hw/acpi/memory_hotplug.h" 4143f50410SIgor Mammedov #include "hw/acpi/acpi_dev_interface.h" 4291ab2ed7SIgor Mammedov #include "hw/xen/xen.h" 437d0c99a9SPaolo Bonzini #include "qom/cpu.h" 4449ab747fSPaolo Bonzini 4549ab747fSPaolo Bonzini //#define DEBUG 4649ab747fSPaolo Bonzini 4749ab747fSPaolo Bonzini #ifdef DEBUG 4849ab747fSPaolo Bonzini # define PIIX4_DPRINTF(format, ...) printf(format, ## __VA_ARGS__) 4949ab747fSPaolo Bonzini #else 5049ab747fSPaolo Bonzini # define PIIX4_DPRINTF(format, ...) do { } while (0) 5149ab747fSPaolo Bonzini #endif 5249ab747fSPaolo Bonzini 5349ab747fSPaolo Bonzini #define GPE_BASE 0xafe0 5449ab747fSPaolo Bonzini #define GPE_LEN 4 5549ab747fSPaolo Bonzini 5649ab747fSPaolo Bonzini struct pci_status { 5749ab747fSPaolo Bonzini uint32_t up; /* deprecated, maintained for migration compatibility */ 5849ab747fSPaolo Bonzini uint32_t down; 5949ab747fSPaolo Bonzini }; 6049ab747fSPaolo Bonzini 6149ab747fSPaolo Bonzini typedef struct PIIX4PMState { 626a6b5580SAndreas Färber /*< private >*/ 636a6b5580SAndreas Färber PCIDevice parent_obj; 646a6b5580SAndreas Färber /*< public >*/ 6549ab747fSPaolo Bonzini 6649ab747fSPaolo Bonzini MemoryRegion io; 67277e9340SMichael S. Tsirkin uint32_t io_base; 68277e9340SMichael S. Tsirkin 6949ab747fSPaolo Bonzini MemoryRegion io_gpe; 7049ab747fSPaolo Bonzini ACPIREGS ar; 7149ab747fSPaolo Bonzini 7249ab747fSPaolo Bonzini APMState apm; 7349ab747fSPaolo Bonzini 7449ab747fSPaolo Bonzini PMSMBus smb; 7549ab747fSPaolo Bonzini uint32_t smb_io_base; 7649ab747fSPaolo Bonzini 7749ab747fSPaolo Bonzini qemu_irq irq; 7849ab747fSPaolo Bonzini qemu_irq smi_irq; 7961e66c62SPaolo Bonzini int smm_enabled; 8049ab747fSPaolo Bonzini Notifier machine_ready; 8149ab747fSPaolo Bonzini Notifier powerdown_notifier; 8249ab747fSPaolo Bonzini 839e047b98SMichael S. Tsirkin AcpiPciHpState acpi_pci_hotplug; 849e047b98SMichael S. Tsirkin bool use_acpi_pci_hotplug; 859e047b98SMichael S. Tsirkin 8649ab747fSPaolo Bonzini uint8_t disable_s3; 8749ab747fSPaolo Bonzini uint8_t disable_s4; 8849ab747fSPaolo Bonzini uint8_t s4_val; 89b8622725SIgor Mammedov 9016bcab97SIgor Mammedov bool cpu_hotplug_legacy; 9181cea5e7SIgor Mammedov AcpiCpuHotplug gpe_cpu; 925e1b5d93SIgor Mammedov CPUHotplugState cpuhp_state; 9334774320SIgor Mammedov 9434774320SIgor Mammedov MemHotplugState acpi_memory_hotplug; 9549ab747fSPaolo Bonzini } PIIX4PMState; 9649ab747fSPaolo Bonzini 9774e445f6SPeter Crosthwaite #define TYPE_PIIX4_PM "PIIX4_PM" 9874e445f6SPeter Crosthwaite 9974e445f6SPeter Crosthwaite #define PIIX4_PM(obj) \ 10074e445f6SPeter Crosthwaite OBJECT_CHECK(PIIX4PMState, (obj), TYPE_PIIX4_PM) 10174e445f6SPeter Crosthwaite 10249ab747fSPaolo Bonzini static void piix4_acpi_system_hot_add_init(MemoryRegion *parent, 10349ab747fSPaolo Bonzini PCIBus *bus, PIIX4PMState *s); 10449ab747fSPaolo Bonzini 10549ab747fSPaolo Bonzini #define ACPI_ENABLE 0xf1 10649ab747fSPaolo Bonzini #define ACPI_DISABLE 0xf0 10749ab747fSPaolo Bonzini 10849ab747fSPaolo Bonzini static void pm_tmr_timer(ACPIREGS *ar) 10949ab747fSPaolo Bonzini { 11049ab747fSPaolo Bonzini PIIX4PMState *s = container_of(ar, PIIX4PMState, ar); 11106313503SIgor Mammedov acpi_update_sci(&s->ar, s->irq); 11249ab747fSPaolo Bonzini } 11349ab747fSPaolo Bonzini 11449ab747fSPaolo Bonzini static void apm_ctrl_changed(uint32_t val, void *arg) 11549ab747fSPaolo Bonzini { 11649ab747fSPaolo Bonzini PIIX4PMState *s = arg; 1176a6b5580SAndreas Färber PCIDevice *d = PCI_DEVICE(s); 11849ab747fSPaolo Bonzini 11949ab747fSPaolo Bonzini /* ACPI specs 3.0, 4.7.2.5 */ 12049ab747fSPaolo Bonzini acpi_pm1_cnt_update(&s->ar, val == ACPI_ENABLE, val == ACPI_DISABLE); 121afd6895bSPaolo Bonzini if (val == ACPI_ENABLE || val == ACPI_DISABLE) { 122afd6895bSPaolo Bonzini return; 123afd6895bSPaolo Bonzini } 12449ab747fSPaolo Bonzini 1256a6b5580SAndreas Färber if (d->config[0x5b] & (1 << 1)) { 12649ab747fSPaolo Bonzini if (s->smi_irq) { 12749ab747fSPaolo Bonzini qemu_irq_raise(s->smi_irq); 12849ab747fSPaolo Bonzini } 12949ab747fSPaolo Bonzini } 13049ab747fSPaolo Bonzini } 13149ab747fSPaolo Bonzini 13249ab747fSPaolo Bonzini static void pm_io_space_update(PIIX4PMState *s) 13349ab747fSPaolo Bonzini { 1346a6b5580SAndreas Färber PCIDevice *d = PCI_DEVICE(s); 13549ab747fSPaolo Bonzini 136277e9340SMichael S. Tsirkin s->io_base = le32_to_cpu(*(uint32_t *)(d->config + 0x40)); 137277e9340SMichael S. Tsirkin s->io_base &= 0xffc0; 13849ab747fSPaolo Bonzini 13949ab747fSPaolo Bonzini memory_region_transaction_begin(); 1406a6b5580SAndreas Färber memory_region_set_enabled(&s->io, d->config[0x80] & 1); 141277e9340SMichael S. Tsirkin memory_region_set_address(&s->io, s->io_base); 14249ab747fSPaolo Bonzini memory_region_transaction_commit(); 14349ab747fSPaolo Bonzini } 14449ab747fSPaolo Bonzini 14549ab747fSPaolo Bonzini static void smbus_io_space_update(PIIX4PMState *s) 14649ab747fSPaolo Bonzini { 1476a6b5580SAndreas Färber PCIDevice *d = PCI_DEVICE(s); 1486a6b5580SAndreas Färber 1496a6b5580SAndreas Färber s->smb_io_base = le32_to_cpu(*(uint32_t *)(d->config + 0x90)); 15049ab747fSPaolo Bonzini s->smb_io_base &= 0xffc0; 15149ab747fSPaolo Bonzini 15249ab747fSPaolo Bonzini memory_region_transaction_begin(); 1536a6b5580SAndreas Färber memory_region_set_enabled(&s->smb.io, d->config[0xd2] & 1); 15449ab747fSPaolo Bonzini memory_region_set_address(&s->smb.io, s->smb_io_base); 15549ab747fSPaolo Bonzini memory_region_transaction_commit(); 15649ab747fSPaolo Bonzini } 15749ab747fSPaolo Bonzini 15849ab747fSPaolo Bonzini static void pm_write_config(PCIDevice *d, 15949ab747fSPaolo Bonzini uint32_t address, uint32_t val, int len) 16049ab747fSPaolo Bonzini { 16149ab747fSPaolo Bonzini pci_default_write_config(d, address, val, len); 16249ab747fSPaolo Bonzini if (range_covers_byte(address, len, 0x80) || 16349ab747fSPaolo Bonzini ranges_overlap(address, len, 0x40, 4)) { 16449ab747fSPaolo Bonzini pm_io_space_update((PIIX4PMState *)d); 16549ab747fSPaolo Bonzini } 16649ab747fSPaolo Bonzini if (range_covers_byte(address, len, 0xd2) || 16749ab747fSPaolo Bonzini ranges_overlap(address, len, 0x90, 4)) { 16849ab747fSPaolo Bonzini smbus_io_space_update((PIIX4PMState *)d); 16949ab747fSPaolo Bonzini } 17049ab747fSPaolo Bonzini } 17149ab747fSPaolo Bonzini 17249ab747fSPaolo Bonzini static int vmstate_acpi_post_load(void *opaque, int version_id) 17349ab747fSPaolo Bonzini { 17449ab747fSPaolo Bonzini PIIX4PMState *s = opaque; 17549ab747fSPaolo Bonzini 17649ab747fSPaolo Bonzini pm_io_space_update(s); 17749ab747fSPaolo Bonzini return 0; 17849ab747fSPaolo Bonzini } 17949ab747fSPaolo Bonzini 18049ab747fSPaolo Bonzini #define VMSTATE_GPE_ARRAY(_field, _state) \ 18149ab747fSPaolo Bonzini { \ 18249ab747fSPaolo Bonzini .name = (stringify(_field)), \ 18349ab747fSPaolo Bonzini .version_id = 0, \ 18449ab747fSPaolo Bonzini .info = &vmstate_info_uint16, \ 18549ab747fSPaolo Bonzini .size = sizeof(uint16_t), \ 18649ab747fSPaolo Bonzini .flags = VMS_SINGLE | VMS_POINTER, \ 18749ab747fSPaolo Bonzini .offset = vmstate_offset_pointer(_state, _field, uint8_t), \ 18849ab747fSPaolo Bonzini } 18949ab747fSPaolo Bonzini 19049ab747fSPaolo Bonzini static const VMStateDescription vmstate_gpe = { 19149ab747fSPaolo Bonzini .name = "gpe", 19249ab747fSPaolo Bonzini .version_id = 1, 19349ab747fSPaolo Bonzini .minimum_version_id = 1, 19449ab747fSPaolo Bonzini .fields = (VMStateField[]) { 19549ab747fSPaolo Bonzini VMSTATE_GPE_ARRAY(sts, ACPIGPE), 19649ab747fSPaolo Bonzini VMSTATE_GPE_ARRAY(en, ACPIGPE), 19749ab747fSPaolo Bonzini VMSTATE_END_OF_LIST() 19849ab747fSPaolo Bonzini } 19949ab747fSPaolo Bonzini }; 20049ab747fSPaolo Bonzini 20149ab747fSPaolo Bonzini static const VMStateDescription vmstate_pci_status = { 20249ab747fSPaolo Bonzini .name = "pci_status", 20349ab747fSPaolo Bonzini .version_id = 1, 20449ab747fSPaolo Bonzini .minimum_version_id = 1, 20549ab747fSPaolo Bonzini .fields = (VMStateField[]) { 206e358edc8SIgor Mammedov VMSTATE_UINT32(up, struct AcpiPciHpPciStatus), 207e358edc8SIgor Mammedov VMSTATE_UINT32(down, struct AcpiPciHpPciStatus), 20849ab747fSPaolo Bonzini VMSTATE_END_OF_LIST() 20949ab747fSPaolo Bonzini } 21049ab747fSPaolo Bonzini }; 21149ab747fSPaolo Bonzini 21249ab747fSPaolo Bonzini static int acpi_load_old(QEMUFile *f, void *opaque, int version_id) 21349ab747fSPaolo Bonzini { 21449ab747fSPaolo Bonzini PIIX4PMState *s = opaque; 21549ab747fSPaolo Bonzini int ret, i; 21649ab747fSPaolo Bonzini uint16_t temp; 21749ab747fSPaolo Bonzini 2186a6b5580SAndreas Färber ret = pci_device_load(PCI_DEVICE(s), f); 21949ab747fSPaolo Bonzini if (ret < 0) { 22049ab747fSPaolo Bonzini return ret; 22149ab747fSPaolo Bonzini } 22249ab747fSPaolo Bonzini qemu_get_be16s(f, &s->ar.pm1.evt.sts); 22349ab747fSPaolo Bonzini qemu_get_be16s(f, &s->ar.pm1.evt.en); 22449ab747fSPaolo Bonzini qemu_get_be16s(f, &s->ar.pm1.cnt.cnt); 22549ab747fSPaolo Bonzini 22649ab747fSPaolo Bonzini ret = vmstate_load_state(f, &vmstate_apm, &s->apm, 1); 22749ab747fSPaolo Bonzini if (ret) { 22849ab747fSPaolo Bonzini return ret; 22949ab747fSPaolo Bonzini } 23049ab747fSPaolo Bonzini 23140daca54SAlex Bligh timer_get(f, s->ar.tmr.timer); 23249ab747fSPaolo Bonzini qemu_get_sbe64s(f, &s->ar.tmr.overflow_time); 23349ab747fSPaolo Bonzini 23449ab747fSPaolo Bonzini qemu_get_be16s(f, (uint16_t *)s->ar.gpe.sts); 23549ab747fSPaolo Bonzini for (i = 0; i < 3; i++) { 23649ab747fSPaolo Bonzini qemu_get_be16s(f, &temp); 23749ab747fSPaolo Bonzini } 23849ab747fSPaolo Bonzini 23949ab747fSPaolo Bonzini qemu_get_be16s(f, (uint16_t *)s->ar.gpe.en); 24049ab747fSPaolo Bonzini for (i = 0; i < 3; i++) { 24149ab747fSPaolo Bonzini qemu_get_be16s(f, &temp); 24249ab747fSPaolo Bonzini } 24349ab747fSPaolo Bonzini 244e358edc8SIgor Mammedov ret = vmstate_load_state(f, &vmstate_pci_status, 245e358edc8SIgor Mammedov &s->acpi_pci_hotplug.acpi_pcihp_pci_status[ACPI_PCIHP_BSEL_DEFAULT], 1); 24649ab747fSPaolo Bonzini return ret; 24749ab747fSPaolo Bonzini } 24849ab747fSPaolo Bonzini 2499e047b98SMichael S. Tsirkin static bool vmstate_test_use_acpi_pci_hotplug(void *opaque, int version_id) 2509e047b98SMichael S. Tsirkin { 2519e047b98SMichael S. Tsirkin PIIX4PMState *s = opaque; 2529e047b98SMichael S. Tsirkin return s->use_acpi_pci_hotplug; 2539e047b98SMichael S. Tsirkin } 2549e047b98SMichael S. Tsirkin 2559e047b98SMichael S. Tsirkin static bool vmstate_test_no_use_acpi_pci_hotplug(void *opaque, int version_id) 2569e047b98SMichael S. Tsirkin { 2579e047b98SMichael S. Tsirkin PIIX4PMState *s = opaque; 2589e047b98SMichael S. Tsirkin return !s->use_acpi_pci_hotplug; 2599e047b98SMichael S. Tsirkin } 2609e047b98SMichael S. Tsirkin 261f816a62dSIgor Mammedov static bool vmstate_test_use_memhp(void *opaque) 262f816a62dSIgor Mammedov { 263f816a62dSIgor Mammedov PIIX4PMState *s = opaque; 264f816a62dSIgor Mammedov return s->acpi_memory_hotplug.is_enabled; 265f816a62dSIgor Mammedov } 266f816a62dSIgor Mammedov 267f816a62dSIgor Mammedov static const VMStateDescription vmstate_memhp_state = { 268f816a62dSIgor Mammedov .name = "piix4_pm/memhp", 269f816a62dSIgor Mammedov .version_id = 1, 270f816a62dSIgor Mammedov .minimum_version_id = 1, 271f816a62dSIgor Mammedov .minimum_version_id_old = 1, 2725cd8cadaSJuan Quintela .needed = vmstate_test_use_memhp, 273f816a62dSIgor Mammedov .fields = (VMStateField[]) { 274f816a62dSIgor Mammedov VMSTATE_MEMORY_HOTPLUG(acpi_memory_hotplug, PIIX4PMState), 275f816a62dSIgor Mammedov VMSTATE_END_OF_LIST() 276f816a62dSIgor Mammedov } 277f816a62dSIgor Mammedov }; 278f816a62dSIgor Mammedov 279679dd1a9SIgor Mammedov static bool vmstate_test_use_cpuhp(void *opaque) 280679dd1a9SIgor Mammedov { 281679dd1a9SIgor Mammedov PIIX4PMState *s = opaque; 282679dd1a9SIgor Mammedov return !s->cpu_hotplug_legacy; 283679dd1a9SIgor Mammedov } 284679dd1a9SIgor Mammedov 285679dd1a9SIgor Mammedov static int vmstate_cpuhp_pre_load(void *opaque) 286679dd1a9SIgor Mammedov { 287679dd1a9SIgor Mammedov Object *obj = OBJECT(opaque); 288679dd1a9SIgor Mammedov object_property_set_bool(obj, false, "cpu-hotplug-legacy", &error_abort); 289679dd1a9SIgor Mammedov return 0; 290679dd1a9SIgor Mammedov } 291679dd1a9SIgor Mammedov 292679dd1a9SIgor Mammedov static const VMStateDescription vmstate_cpuhp_state = { 293679dd1a9SIgor Mammedov .name = "piix4_pm/cpuhp", 294679dd1a9SIgor Mammedov .version_id = 1, 295679dd1a9SIgor Mammedov .minimum_version_id = 1, 296679dd1a9SIgor Mammedov .minimum_version_id_old = 1, 297679dd1a9SIgor Mammedov .needed = vmstate_test_use_cpuhp, 298679dd1a9SIgor Mammedov .pre_load = vmstate_cpuhp_pre_load, 299679dd1a9SIgor Mammedov .fields = (VMStateField[]) { 300679dd1a9SIgor Mammedov VMSTATE_CPU_HOTPLUG(cpuhp_state, PIIX4PMState), 301679dd1a9SIgor Mammedov VMSTATE_END_OF_LIST() 302679dd1a9SIgor Mammedov } 303679dd1a9SIgor Mammedov }; 304679dd1a9SIgor Mammedov 30549ab747fSPaolo Bonzini /* qemu-kvm 1.2 uses version 3 but advertised as 2 30649ab747fSPaolo Bonzini * To support incoming qemu-kvm 1.2 migration, change version_id 30749ab747fSPaolo Bonzini * and minimum_version_id to 2 below (which breaks migration from 30849ab747fSPaolo Bonzini * qemu 1.2). 30949ab747fSPaolo Bonzini * 31049ab747fSPaolo Bonzini */ 31149ab747fSPaolo Bonzini static const VMStateDescription vmstate_acpi = { 31249ab747fSPaolo Bonzini .name = "piix4_pm", 31349ab747fSPaolo Bonzini .version_id = 3, 31449ab747fSPaolo Bonzini .minimum_version_id = 3, 31549ab747fSPaolo Bonzini .minimum_version_id_old = 1, 31649ab747fSPaolo Bonzini .load_state_old = acpi_load_old, 31749ab747fSPaolo Bonzini .post_load = vmstate_acpi_post_load, 31849ab747fSPaolo Bonzini .fields = (VMStateField[]) { 3196a6b5580SAndreas Färber VMSTATE_PCI_DEVICE(parent_obj, PIIX4PMState), 32049ab747fSPaolo Bonzini VMSTATE_UINT16(ar.pm1.evt.sts, PIIX4PMState), 32149ab747fSPaolo Bonzini VMSTATE_UINT16(ar.pm1.evt.en, PIIX4PMState), 32249ab747fSPaolo Bonzini VMSTATE_UINT16(ar.pm1.cnt.cnt, PIIX4PMState), 32349ab747fSPaolo Bonzini VMSTATE_STRUCT(apm, PIIX4PMState, 0, vmstate_apm, APMState), 324e720677eSPaolo Bonzini VMSTATE_TIMER_PTR(ar.tmr.timer, PIIX4PMState), 32549ab747fSPaolo Bonzini VMSTATE_INT64(ar.tmr.overflow_time, PIIX4PMState), 32649ab747fSPaolo Bonzini VMSTATE_STRUCT(ar.gpe, PIIX4PMState, 2, vmstate_gpe, ACPIGPE), 327e358edc8SIgor Mammedov VMSTATE_STRUCT_TEST( 328e358edc8SIgor Mammedov acpi_pci_hotplug.acpi_pcihp_pci_status[ACPI_PCIHP_BSEL_DEFAULT], 329e358edc8SIgor Mammedov PIIX4PMState, 3309e047b98SMichael S. Tsirkin vmstate_test_no_use_acpi_pci_hotplug, 3319e047b98SMichael S. Tsirkin 2, vmstate_pci_status, 332e358edc8SIgor Mammedov struct AcpiPciHpPciStatus), 3339e047b98SMichael S. Tsirkin VMSTATE_PCI_HOTPLUG(acpi_pci_hotplug, PIIX4PMState, 3349e047b98SMichael S. Tsirkin vmstate_test_use_acpi_pci_hotplug), 33549ab747fSPaolo Bonzini VMSTATE_END_OF_LIST() 336f816a62dSIgor Mammedov }, 3375cd8cadaSJuan Quintela .subsections = (const VMStateDescription*[]) { 3385cd8cadaSJuan Quintela &vmstate_memhp_state, 339679dd1a9SIgor Mammedov &vmstate_cpuhp_state, 3405cd8cadaSJuan Quintela NULL 34149ab747fSPaolo Bonzini } 34249ab747fSPaolo Bonzini }; 34349ab747fSPaolo Bonzini 34449ab747fSPaolo Bonzini static void piix4_reset(void *opaque) 34549ab747fSPaolo Bonzini { 34649ab747fSPaolo Bonzini PIIX4PMState *s = opaque; 3476a6b5580SAndreas Färber PCIDevice *d = PCI_DEVICE(s); 3486a6b5580SAndreas Färber uint8_t *pci_conf = d->config; 34949ab747fSPaolo Bonzini 35049ab747fSPaolo Bonzini pci_conf[0x58] = 0; 35149ab747fSPaolo Bonzini pci_conf[0x59] = 0; 35249ab747fSPaolo Bonzini pci_conf[0x5a] = 0; 35349ab747fSPaolo Bonzini pci_conf[0x5b] = 0; 35449ab747fSPaolo Bonzini 35549ab747fSPaolo Bonzini pci_conf[0x40] = 0x01; /* PM io base read only bit */ 35649ab747fSPaolo Bonzini pci_conf[0x80] = 0; 35749ab747fSPaolo Bonzini 35861e66c62SPaolo Bonzini if (!s->smm_enabled) { 35949ab747fSPaolo Bonzini /* Mark SMM as already inited (until KVM supports SMM). */ 36049ab747fSPaolo Bonzini pci_conf[0x5B] = 0x02; 36149ab747fSPaolo Bonzini } 362c046e8c4SMichael S. Tsirkin pm_io_space_update(s); 3639e047b98SMichael S. Tsirkin acpi_pcihp_reset(&s->acpi_pci_hotplug); 3649e047b98SMichael S. Tsirkin } 36549ab747fSPaolo Bonzini 36649ab747fSPaolo Bonzini static void piix4_pm_powerdown_req(Notifier *n, void *opaque) 36749ab747fSPaolo Bonzini { 36849ab747fSPaolo Bonzini PIIX4PMState *s = container_of(n, PIIX4PMState, powerdown_notifier); 36949ab747fSPaolo Bonzini 37049ab747fSPaolo Bonzini assert(s != NULL); 37149ab747fSPaolo Bonzini acpi_pm1_evt_power_down(&s->ar); 37249ab747fSPaolo Bonzini } 37349ab747fSPaolo Bonzini 374f1adc360SIgor Mammedov static void piix4_device_plug_cb(HotplugHandler *hotplug_dev, 375c24d5e0bSIgor Mammedov DeviceState *dev, Error **errp) 3769e047b98SMichael S. Tsirkin { 377c24d5e0bSIgor Mammedov PIIX4PMState *s = PIIX4_PM(hotplug_dev); 378f1adc360SIgor Mammedov 37934774320SIgor Mammedov if (s->acpi_memory_hotplug.is_enabled && 38034774320SIgor Mammedov object_dynamic_cast(OBJECT(dev), TYPE_PC_DIMM)) { 38175f27498SXiao Guangrong if (object_dynamic_cast(OBJECT(dev), TYPE_NVDIMM)) { 38275f27498SXiao Guangrong nvdimm_acpi_plug_cb(hotplug_dev, dev); 38375f27498SXiao Guangrong } else { 38475f27498SXiao Guangrong acpi_memory_plug_cb(hotplug_dev, &s->acpi_memory_hotplug, 38575f27498SXiao Guangrong dev, errp); 38675f27498SXiao Guangrong } 38734774320SIgor Mammedov } else if (object_dynamic_cast(OBJECT(dev), TYPE_PCI_DEVICE)) { 3880058c082SIgor Mammedov acpi_pcihp_device_plug_cb(hotplug_dev, &s->acpi_pci_hotplug, dev, errp); 3895e1b5d93SIgor Mammedov } else if (object_dynamic_cast(OBJECT(dev), TYPE_CPU)) { 3905e1b5d93SIgor Mammedov if (s->cpu_hotplug_legacy) { 3910058c082SIgor Mammedov legacy_acpi_cpu_plug_cb(hotplug_dev, &s->gpe_cpu, dev, errp); 392f1adc360SIgor Mammedov } else { 3935e1b5d93SIgor Mammedov acpi_cpu_plug_cb(hotplug_dev, &s->cpuhp_state, dev, errp); 3945e1b5d93SIgor Mammedov } 3955e1b5d93SIgor Mammedov } else { 396f1adc360SIgor Mammedov error_setg(errp, "acpi: device plug request for not supported device" 397f1adc360SIgor Mammedov " type: %s", object_get_typename(OBJECT(dev))); 398f1adc360SIgor Mammedov } 3999e047b98SMichael S. Tsirkin } 4009e047b98SMichael S. Tsirkin 40114d5a28fSIgor Mammedov static void piix4_device_unplug_request_cb(HotplugHandler *hotplug_dev, 402c24d5e0bSIgor Mammedov DeviceState *dev, Error **errp) 403c24d5e0bSIgor Mammedov { 404c24d5e0bSIgor Mammedov PIIX4PMState *s = PIIX4_PM(hotplug_dev); 405f1adc360SIgor Mammedov 40664fec58eSTang Chen if (s->acpi_memory_hotplug.is_enabled && 40764fec58eSTang Chen object_dynamic_cast(OBJECT(dev), TYPE_PC_DIMM)) { 4080058c082SIgor Mammedov acpi_memory_unplug_request_cb(hotplug_dev, &s->acpi_memory_hotplug, 40964fec58eSTang Chen dev, errp); 41064fec58eSTang Chen } else if (object_dynamic_cast(OBJECT(dev), TYPE_PCI_DEVICE)) { 4110058c082SIgor Mammedov acpi_pcihp_device_unplug_cb(hotplug_dev, &s->acpi_pci_hotplug, dev, 412c24d5e0bSIgor Mammedov errp); 4138872c25aSIgor Mammedov } else if (object_dynamic_cast(OBJECT(dev), TYPE_CPU) && 4148872c25aSIgor Mammedov !s->cpu_hotplug_legacy) { 4158872c25aSIgor Mammedov acpi_cpu_unplug_request_cb(hotplug_dev, &s->cpuhp_state, dev, errp); 416f1adc360SIgor Mammedov } else { 417f1adc360SIgor Mammedov error_setg(errp, "acpi: device unplug request for not supported device" 418f1adc360SIgor Mammedov " type: %s", object_get_typename(OBJECT(dev))); 419f1adc360SIgor Mammedov } 420c24d5e0bSIgor Mammedov } 421c24d5e0bSIgor Mammedov 422c0e57a60STang Chen static void piix4_device_unplug_cb(HotplugHandler *hotplug_dev, 423c0e57a60STang Chen DeviceState *dev, Error **errp) 424c0e57a60STang Chen { 425f7d3e29dSTang Chen PIIX4PMState *s = PIIX4_PM(hotplug_dev); 426f7d3e29dSTang Chen 427f7d3e29dSTang Chen if (s->acpi_memory_hotplug.is_enabled && 428f7d3e29dSTang Chen object_dynamic_cast(OBJECT(dev), TYPE_PC_DIMM)) { 429f7d3e29dSTang Chen acpi_memory_unplug_cb(&s->acpi_memory_hotplug, dev, errp); 4308872c25aSIgor Mammedov } else if (object_dynamic_cast(OBJECT(dev), TYPE_CPU) && 4318872c25aSIgor Mammedov !s->cpu_hotplug_legacy) { 4328872c25aSIgor Mammedov acpi_cpu_unplug_cb(&s->cpuhp_state, dev, errp); 433f7d3e29dSTang Chen } else { 434c0e57a60STang Chen error_setg(errp, "acpi: device unplug for not supported device" 435c0e57a60STang Chen " type: %s", object_get_typename(OBJECT(dev))); 436c0e57a60STang Chen } 437f7d3e29dSTang Chen } 438c0e57a60STang Chen 439c24d5e0bSIgor Mammedov static void piix4_update_bus_hotplug(PCIBus *pci_bus, void *opaque) 4409e047b98SMichael S. Tsirkin { 4419e047b98SMichael S. Tsirkin PIIX4PMState *s = opaque; 442c24d5e0bSIgor Mammedov 443675f22c6SMarc-André Lureau /* pci_bus cannot outlive PIIX4PMState, because /machine keeps it alive 444675f22c6SMarc-André Lureau * and it's not hot-unpluggable */ 445c24d5e0bSIgor Mammedov qbus_set_hotplug_handler(BUS(pci_bus), DEVICE(s), &error_abort); 4469e047b98SMichael S. Tsirkin } 4479e047b98SMichael S. Tsirkin 44849ab747fSPaolo Bonzini static void piix4_pm_machine_ready(Notifier *n, void *opaque) 44949ab747fSPaolo Bonzini { 45049ab747fSPaolo Bonzini PIIX4PMState *s = container_of(n, PIIX4PMState, machine_ready); 4516a6b5580SAndreas Färber PCIDevice *d = PCI_DEVICE(s); 4526a6b5580SAndreas Färber MemoryRegion *io_as = pci_address_space_io(d); 45349ab747fSPaolo Bonzini uint8_t *pci_conf; 45449ab747fSPaolo Bonzini 4556a6b5580SAndreas Färber pci_conf = d->config; 456b6f32962SJan Kiszka pci_conf[0x5f] = 0x10 | 4573ce10901SPaolo Bonzini (memory_region_present(io_as, 0x378) ? 0x80 : 0); 45849ab747fSPaolo Bonzini pci_conf[0x63] = 0x60; 4593ce10901SPaolo Bonzini pci_conf[0x67] = (memory_region_present(io_as, 0x3f8) ? 0x08 : 0) | 4603ce10901SPaolo Bonzini (memory_region_present(io_as, 0x2f8) ? 0x90 : 0); 4619e047b98SMichael S. Tsirkin 4629e047b98SMichael S. Tsirkin if (s->use_acpi_pci_hotplug) { 4639e047b98SMichael S. Tsirkin pci_for_each_bus(d->bus, piix4_update_bus_hotplug, s); 464e358edc8SIgor Mammedov } else { 465e358edc8SIgor Mammedov piix4_update_bus_hotplug(d->bus, s); 4669e047b98SMichael S. Tsirkin } 46749ab747fSPaolo Bonzini } 46849ab747fSPaolo Bonzini 469277e9340SMichael S. Tsirkin static void piix4_pm_add_propeties(PIIX4PMState *s) 470277e9340SMichael S. Tsirkin { 471277e9340SMichael S. Tsirkin static const uint8_t acpi_enable_cmd = ACPI_ENABLE; 472277e9340SMichael S. Tsirkin static const uint8_t acpi_disable_cmd = ACPI_DISABLE; 473277e9340SMichael S. Tsirkin static const uint32_t gpe0_blk = GPE_BASE; 474277e9340SMichael S. Tsirkin static const uint32_t gpe0_blk_len = GPE_LEN; 475277e9340SMichael S. Tsirkin static const uint16_t sci_int = 9; 476277e9340SMichael S. Tsirkin 477277e9340SMichael S. Tsirkin object_property_add_uint8_ptr(OBJECT(s), ACPI_PM_PROP_ACPI_ENABLE_CMD, 478277e9340SMichael S. Tsirkin &acpi_enable_cmd, NULL); 479277e9340SMichael S. Tsirkin object_property_add_uint8_ptr(OBJECT(s), ACPI_PM_PROP_ACPI_DISABLE_CMD, 480277e9340SMichael S. Tsirkin &acpi_disable_cmd, NULL); 481277e9340SMichael S. Tsirkin object_property_add_uint32_ptr(OBJECT(s), ACPI_PM_PROP_GPE0_BLK, 482277e9340SMichael S. Tsirkin &gpe0_blk, NULL); 483277e9340SMichael S. Tsirkin object_property_add_uint32_ptr(OBJECT(s), ACPI_PM_PROP_GPE0_BLK_LEN, 484277e9340SMichael S. Tsirkin &gpe0_blk_len, NULL); 485277e9340SMichael S. Tsirkin object_property_add_uint16_ptr(OBJECT(s), ACPI_PM_PROP_SCI_INT, 486277e9340SMichael S. Tsirkin &sci_int, NULL); 487277e9340SMichael S. Tsirkin object_property_add_uint32_ptr(OBJECT(s), ACPI_PM_PROP_PM_IO_BASE, 488277e9340SMichael S. Tsirkin &s->io_base, NULL); 489277e9340SMichael S. Tsirkin } 490277e9340SMichael S. Tsirkin 4919af21dbeSMarkus Armbruster static void piix4_pm_realize(PCIDevice *dev, Error **errp) 49249ab747fSPaolo Bonzini { 49374e445f6SPeter Crosthwaite PIIX4PMState *s = PIIX4_PM(dev); 49449ab747fSPaolo Bonzini uint8_t *pci_conf; 49549ab747fSPaolo Bonzini 4966a6b5580SAndreas Färber pci_conf = dev->config; 49749ab747fSPaolo Bonzini pci_conf[0x06] = 0x80; 49849ab747fSPaolo Bonzini pci_conf[0x07] = 0x02; 49949ab747fSPaolo Bonzini pci_conf[0x09] = 0x00; 50049ab747fSPaolo Bonzini pci_conf[0x3d] = 0x01; // interrupt pin 1 50149ab747fSPaolo Bonzini 50249ab747fSPaolo Bonzini /* APM */ 50349ab747fSPaolo Bonzini apm_init(dev, &s->apm, apm_ctrl_changed, s); 50449ab747fSPaolo Bonzini 50561e66c62SPaolo Bonzini if (!s->smm_enabled) { 50649ab747fSPaolo Bonzini /* Mark SMM as already inited to prevent SMM from running. KVM does not 50749ab747fSPaolo Bonzini * support SMM mode. */ 50849ab747fSPaolo Bonzini pci_conf[0x5B] = 0x02; 50949ab747fSPaolo Bonzini } 51049ab747fSPaolo Bonzini 51149ab747fSPaolo Bonzini /* XXX: which specification is used ? The i82731AB has different 51249ab747fSPaolo Bonzini mappings */ 51349ab747fSPaolo Bonzini pci_conf[0x90] = s->smb_io_base | 1; 51449ab747fSPaolo Bonzini pci_conf[0x91] = s->smb_io_base >> 8; 51549ab747fSPaolo Bonzini pci_conf[0xd2] = 0x09; 51674e445f6SPeter Crosthwaite pm_smbus_init(DEVICE(dev), &s->smb); 51749ab747fSPaolo Bonzini memory_region_set_enabled(&s->smb.io, pci_conf[0xd2] & 1); 51849ab747fSPaolo Bonzini memory_region_add_subregion(pci_address_space_io(dev), 51949ab747fSPaolo Bonzini s->smb_io_base, &s->smb.io); 52049ab747fSPaolo Bonzini 52164bde0f3SPaolo Bonzini memory_region_init(&s->io, OBJECT(s), "piix4-pm", 64); 52249ab747fSPaolo Bonzini memory_region_set_enabled(&s->io, false); 52349ab747fSPaolo Bonzini memory_region_add_subregion(pci_address_space_io(dev), 52449ab747fSPaolo Bonzini 0, &s->io); 52549ab747fSPaolo Bonzini 52649ab747fSPaolo Bonzini acpi_pm_tmr_init(&s->ar, pm_tmr_timer, &s->io); 52749ab747fSPaolo Bonzini acpi_pm1_evt_init(&s->ar, pm_tmr_timer, &s->io); 5289a10bbb4SLaszlo Ersek acpi_pm1_cnt_init(&s->ar, &s->io, s->disable_s3, s->disable_s4, s->s4_val); 52949ab747fSPaolo Bonzini acpi_gpe_init(&s->ar, GPE_LEN); 53049ab747fSPaolo Bonzini 53149ab747fSPaolo Bonzini s->powerdown_notifier.notify = piix4_pm_powerdown_req; 53249ab747fSPaolo Bonzini qemu_register_powerdown_notifier(&s->powerdown_notifier); 53349ab747fSPaolo Bonzini 53449ab747fSPaolo Bonzini s->machine_ready.notify = piix4_pm_machine_ready; 53549ab747fSPaolo Bonzini qemu_add_machine_init_done_notifier(&s->machine_ready); 53649ab747fSPaolo Bonzini qemu_register_reset(piix4_reset, s); 53749ab747fSPaolo Bonzini 53849ab747fSPaolo Bonzini piix4_acpi_system_hot_add_init(pci_address_space_io(dev), dev->bus, s); 53949ab747fSPaolo Bonzini 540277e9340SMichael S. Tsirkin piix4_pm_add_propeties(s); 54149ab747fSPaolo Bonzini } 54249ab747fSPaolo Bonzini 543277e9340SMichael S. Tsirkin Object *piix4_pm_find(void) 544277e9340SMichael S. Tsirkin { 545277e9340SMichael S. Tsirkin bool ambig; 546277e9340SMichael S. Tsirkin Object *o = object_resolve_path_type("", TYPE_PIIX4_PM, &ambig); 547277e9340SMichael S. Tsirkin 548277e9340SMichael S. Tsirkin if (ambig || !o) { 549277e9340SMichael S. Tsirkin return NULL; 550277e9340SMichael S. Tsirkin } 551277e9340SMichael S. Tsirkin return o; 552277e9340SMichael S. Tsirkin } 553277e9340SMichael S. Tsirkin 554a5c82852SAndreas Färber I2CBus *piix4_pm_init(PCIBus *bus, int devfn, uint32_t smb_io_base, 55549ab747fSPaolo Bonzini qemu_irq sci_irq, qemu_irq smi_irq, 55661e66c62SPaolo Bonzini int smm_enabled, DeviceState **piix4_pm) 55749ab747fSPaolo Bonzini { 55874e445f6SPeter Crosthwaite DeviceState *dev; 55949ab747fSPaolo Bonzini PIIX4PMState *s; 56049ab747fSPaolo Bonzini 56174e445f6SPeter Crosthwaite dev = DEVICE(pci_create(bus, devfn, TYPE_PIIX4_PM)); 56274e445f6SPeter Crosthwaite qdev_prop_set_uint32(dev, "smb_io_base", smb_io_base); 563781bbd6bSIgor Mammedov if (piix4_pm) { 564781bbd6bSIgor Mammedov *piix4_pm = dev; 565781bbd6bSIgor Mammedov } 56649ab747fSPaolo Bonzini 56774e445f6SPeter Crosthwaite s = PIIX4_PM(dev); 56849ab747fSPaolo Bonzini s->irq = sci_irq; 56949ab747fSPaolo Bonzini s->smi_irq = smi_irq; 57061e66c62SPaolo Bonzini s->smm_enabled = smm_enabled; 57191ab2ed7SIgor Mammedov if (xen_enabled()) { 57291ab2ed7SIgor Mammedov s->use_acpi_pci_hotplug = false; 57391ab2ed7SIgor Mammedov } 57449ab747fSPaolo Bonzini 57574e445f6SPeter Crosthwaite qdev_init_nofail(dev); 57649ab747fSPaolo Bonzini 57749ab747fSPaolo Bonzini return s->smb.smbus; 57849ab747fSPaolo Bonzini } 57949ab747fSPaolo Bonzini 58049ab747fSPaolo Bonzini static uint64_t gpe_readb(void *opaque, hwaddr addr, unsigned width) 58149ab747fSPaolo Bonzini { 58249ab747fSPaolo Bonzini PIIX4PMState *s = opaque; 58349ab747fSPaolo Bonzini uint32_t val = acpi_gpe_ioport_readb(&s->ar, addr); 58449ab747fSPaolo Bonzini 585ba275adbSHu Tao PIIX4_DPRINTF("gpe read %" HWADDR_PRIx " == %" PRIu32 "\n", addr, val); 58649ab747fSPaolo Bonzini return val; 58749ab747fSPaolo Bonzini } 58849ab747fSPaolo Bonzini 58949ab747fSPaolo Bonzini static void gpe_writeb(void *opaque, hwaddr addr, uint64_t val, 59049ab747fSPaolo Bonzini unsigned width) 59149ab747fSPaolo Bonzini { 59249ab747fSPaolo Bonzini PIIX4PMState *s = opaque; 59349ab747fSPaolo Bonzini 59449ab747fSPaolo Bonzini acpi_gpe_ioport_writeb(&s->ar, addr, val); 59506313503SIgor Mammedov acpi_update_sci(&s->ar, s->irq); 59649ab747fSPaolo Bonzini 597ba275adbSHu Tao PIIX4_DPRINTF("gpe write %" HWADDR_PRIx " <== %" PRIu64 "\n", addr, val); 59849ab747fSPaolo Bonzini } 59949ab747fSPaolo Bonzini 60049ab747fSPaolo Bonzini static const MemoryRegionOps piix4_gpe_ops = { 60149ab747fSPaolo Bonzini .read = gpe_readb, 60249ab747fSPaolo Bonzini .write = gpe_writeb, 60349ab747fSPaolo Bonzini .valid.min_access_size = 1, 60449ab747fSPaolo Bonzini .valid.max_access_size = 4, 60549ab747fSPaolo Bonzini .impl.min_access_size = 1, 60649ab747fSPaolo Bonzini .impl.max_access_size = 1, 60749ab747fSPaolo Bonzini .endianness = DEVICE_LITTLE_ENDIAN, 60849ab747fSPaolo Bonzini }; 60949ab747fSPaolo Bonzini 61016bcab97SIgor Mammedov 61116bcab97SIgor Mammedov static bool piix4_get_cpu_hotplug_legacy(Object *obj, Error **errp) 61216bcab97SIgor Mammedov { 61316bcab97SIgor Mammedov PIIX4PMState *s = PIIX4_PM(obj); 61416bcab97SIgor Mammedov 61516bcab97SIgor Mammedov return s->cpu_hotplug_legacy; 61616bcab97SIgor Mammedov } 61716bcab97SIgor Mammedov 61816bcab97SIgor Mammedov static void piix4_set_cpu_hotplug_legacy(Object *obj, bool value, Error **errp) 61916bcab97SIgor Mammedov { 62016bcab97SIgor Mammedov PIIX4PMState *s = PIIX4_PM(obj); 62116bcab97SIgor Mammedov 622679dd1a9SIgor Mammedov assert(!value); 623679dd1a9SIgor Mammedov if (s->cpu_hotplug_legacy && value == false) { 624679dd1a9SIgor Mammedov acpi_switch_to_modern_cphp(&s->gpe_cpu, &s->cpuhp_state, 625679dd1a9SIgor Mammedov PIIX4_CPU_HOTPLUG_IO_BASE); 626679dd1a9SIgor Mammedov } 62716bcab97SIgor Mammedov s->cpu_hotplug_legacy = value; 62816bcab97SIgor Mammedov } 62916bcab97SIgor Mammedov 63049ab747fSPaolo Bonzini static void piix4_acpi_system_hot_add_init(MemoryRegion *parent, 63149ab747fSPaolo Bonzini PCIBus *bus, PIIX4PMState *s) 63249ab747fSPaolo Bonzini { 63364bde0f3SPaolo Bonzini memory_region_init_io(&s->io_gpe, OBJECT(s), &piix4_gpe_ops, s, 63464bde0f3SPaolo Bonzini "acpi-gpe0", GPE_LEN); 63549ab747fSPaolo Bonzini memory_region_add_subregion(parent, GPE_BASE, &s->io_gpe); 63649ab747fSPaolo Bonzini 63778c2d872SIgor Mammedov acpi_pcihp_init(OBJECT(s), &s->acpi_pci_hotplug, bus, parent, 63899d09dd3SIgor Mammedov s->use_acpi_pci_hotplug); 639b8622725SIgor Mammedov 64016bcab97SIgor Mammedov s->cpu_hotplug_legacy = true; 64116bcab97SIgor Mammedov object_property_add_bool(OBJECT(s), "cpu-hotplug-legacy", 64216bcab97SIgor Mammedov piix4_get_cpu_hotplug_legacy, 64316bcab97SIgor Mammedov piix4_set_cpu_hotplug_legacy, 64416bcab97SIgor Mammedov NULL); 64596e3e12bSIgor Mammedov legacy_acpi_cpu_hotplug_init(parent, OBJECT(s), &s->gpe_cpu, 646e4cf8ed0SIgor Mammedov PIIX4_CPU_HOTPLUG_IO_BASE); 64734774320SIgor Mammedov 64834774320SIgor Mammedov if (s->acpi_memory_hotplug.is_enabled) { 64980db0e78SIgor Mammedov acpi_memory_hotplug_init(parent, OBJECT(s), &s->acpi_memory_hotplug, 65080db0e78SIgor Mammedov ACPI_MEMORY_HOTPLUG_BASE); 65134774320SIgor Mammedov } 65249ab747fSPaolo Bonzini } 6535fdae20cSIgor Mammedov 65443f50410SIgor Mammedov static void piix4_ospm_status(AcpiDeviceIf *adev, ACPIOSTInfoList ***list) 65543f50410SIgor Mammedov { 65643f50410SIgor Mammedov PIIX4PMState *s = PIIX4_PM(adev); 65743f50410SIgor Mammedov 65843f50410SIgor Mammedov acpi_memory_ospm_status(&s->acpi_memory_hotplug, list); 65976623d00SIgor Mammedov if (!s->cpu_hotplug_legacy) { 66076623d00SIgor Mammedov acpi_cpu_ospm_status(&s->cpuhp_state, list); 66176623d00SIgor Mammedov } 66243f50410SIgor Mammedov } 66343f50410SIgor Mammedov 664eaf23bf7SIgor Mammedov static void piix4_send_gpe(AcpiDeviceIf *adev, AcpiEventStatusBits ev) 665eaf23bf7SIgor Mammedov { 666eaf23bf7SIgor Mammedov PIIX4PMState *s = PIIX4_PM(adev); 667eaf23bf7SIgor Mammedov 668eaf23bf7SIgor Mammedov acpi_send_gpe_event(&s->ar, s->irq, ev); 669eaf23bf7SIgor Mammedov } 670eaf23bf7SIgor Mammedov 6715fdae20cSIgor Mammedov static Property piix4_pm_properties[] = { 6725fdae20cSIgor Mammedov DEFINE_PROP_UINT32("smb_io_base", PIIX4PMState, smb_io_base, 0), 6735fdae20cSIgor Mammedov DEFINE_PROP_UINT8(ACPI_PM_PROP_S3_DISABLED, PIIX4PMState, disable_s3, 0), 6745fdae20cSIgor Mammedov DEFINE_PROP_UINT8(ACPI_PM_PROP_S4_DISABLED, PIIX4PMState, disable_s4, 0), 6755fdae20cSIgor Mammedov DEFINE_PROP_UINT8(ACPI_PM_PROP_S4_VAL, PIIX4PMState, s4_val, 2), 6765fdae20cSIgor Mammedov DEFINE_PROP_BOOL("acpi-pci-hotplug-with-bridge-support", PIIX4PMState, 6775fdae20cSIgor Mammedov use_acpi_pci_hotplug, true), 67834774320SIgor Mammedov DEFINE_PROP_BOOL("memory-hotplug-support", PIIX4PMState, 67934774320SIgor Mammedov acpi_memory_hotplug.is_enabled, true), 6805fdae20cSIgor Mammedov DEFINE_PROP_END_OF_LIST(), 6815fdae20cSIgor Mammedov }; 6825fdae20cSIgor Mammedov 6835fdae20cSIgor Mammedov static void piix4_pm_class_init(ObjectClass *klass, void *data) 6845fdae20cSIgor Mammedov { 6855fdae20cSIgor Mammedov DeviceClass *dc = DEVICE_CLASS(klass); 6865fdae20cSIgor Mammedov PCIDeviceClass *k = PCI_DEVICE_CLASS(klass); 687c24d5e0bSIgor Mammedov HotplugHandlerClass *hc = HOTPLUG_HANDLER_CLASS(klass); 68843f50410SIgor Mammedov AcpiDeviceIfClass *adevc = ACPI_DEVICE_IF_CLASS(klass); 6895fdae20cSIgor Mammedov 6909af21dbeSMarkus Armbruster k->realize = piix4_pm_realize; 6915fdae20cSIgor Mammedov k->config_write = pm_write_config; 6925fdae20cSIgor Mammedov k->vendor_id = PCI_VENDOR_ID_INTEL; 6935fdae20cSIgor Mammedov k->device_id = PCI_DEVICE_ID_INTEL_82371AB_3; 6945fdae20cSIgor Mammedov k->revision = 0x03; 6955fdae20cSIgor Mammedov k->class_id = PCI_CLASS_BRIDGE_OTHER; 6965fdae20cSIgor Mammedov dc->desc = "PM"; 6975fdae20cSIgor Mammedov dc->vmsd = &vmstate_acpi; 6985fdae20cSIgor Mammedov dc->props = piix4_pm_properties; 6995fdae20cSIgor Mammedov /* 7005fdae20cSIgor Mammedov * Reason: part of PIIX4 southbridge, needs to be wired up, 7015fdae20cSIgor Mammedov * e.g. by mips_malta_init() 7025fdae20cSIgor Mammedov */ 703*e90f2a8cSEduardo Habkost dc->user_creatable = false; 7042897ae02SIgor Mammedov dc->hotpluggable = false; 705f1adc360SIgor Mammedov hc->plug = piix4_device_plug_cb; 70614d5a28fSIgor Mammedov hc->unplug_request = piix4_device_unplug_request_cb; 707c0e57a60STang Chen hc->unplug = piix4_device_unplug_cb; 70843f50410SIgor Mammedov adevc->ospm_status = piix4_ospm_status; 709eaf23bf7SIgor Mammedov adevc->send_event = piix4_send_gpe; 710ac35f13bSIgor Mammedov adevc->madt_cpu = pc_madt_cpu_entry; 7115fdae20cSIgor Mammedov } 7125fdae20cSIgor Mammedov 7135fdae20cSIgor Mammedov static const TypeInfo piix4_pm_info = { 7145fdae20cSIgor Mammedov .name = TYPE_PIIX4_PM, 7155fdae20cSIgor Mammedov .parent = TYPE_PCI_DEVICE, 7165fdae20cSIgor Mammedov .instance_size = sizeof(PIIX4PMState), 7175fdae20cSIgor Mammedov .class_init = piix4_pm_class_init, 718c24d5e0bSIgor Mammedov .interfaces = (InterfaceInfo[]) { 719c24d5e0bSIgor Mammedov { TYPE_HOTPLUG_HANDLER }, 72043f50410SIgor Mammedov { TYPE_ACPI_DEVICE_IF }, 721c24d5e0bSIgor Mammedov { } 722c24d5e0bSIgor Mammedov } 7235fdae20cSIgor Mammedov }; 7245fdae20cSIgor Mammedov 7255fdae20cSIgor Mammedov static void piix4_pm_register_types(void) 7265fdae20cSIgor Mammedov { 7275fdae20cSIgor Mammedov type_register_static(&piix4_pm_info); 7285fdae20cSIgor Mammedov } 7295fdae20cSIgor Mammedov 7305fdae20cSIgor Mammedov type_init(piix4_pm_register_types) 731