xref: /openbmc/qemu/hw/acpi/piix4.c (revision e90f2a8c3e0e677eeea46a9b401c3f98425ffa37)
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