xref: /openbmc/qemu/hw/acpi/piix4.c (revision 28ae3179fc52d2e4d870b635c4a412aab99759e7)
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
861f3c91aSChetan Pant  * License version 2.1 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  */
2171e8a915SMarkus Armbruster 
22b6a0aa05SPeter Maydell #include "qemu/osdep.h"
2364552b6bSMarkus Armbruster #include "hw/irq.h"
2449ab747fSPaolo Bonzini #include "hw/isa/apm.h"
2549ab747fSPaolo Bonzini #include "hw/i2c/pm_smbus.h"
2649ab747fSPaolo Bonzini #include "hw/pci/pci.h"
27a27bd6c7SMarkus Armbruster #include "hw/qdev-properties.h"
2849ab747fSPaolo Bonzini #include "hw/acpi/acpi.h"
292bfd0845SMark Cave-Ayland #include "hw/acpi/pcihp.h"
302bfd0845SMark Cave-Ayland #include "hw/acpi/piix4.h"
3154d31236SMarkus Armbruster #include "sysemu/runstate.h"
3249ab747fSPaolo Bonzini #include "sysemu/sysemu.h"
33da278d58SPhilippe Mathieu-Daudé #include "sysemu/xen.h"
34da34e65cSMarkus Armbruster #include "qapi/error.h"
3549ab747fSPaolo Bonzini #include "qemu/range.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"
40132a908bSPhilippe Mathieu-Daudé #include "hw/mem/nvdimm.h"
4134774320SIgor Mammedov #include "hw/acpi/memory_hotplug.h"
4243f50410SIgor Mammedov #include "hw/acpi/acpi_dev_interface.h"
43d6454270SMarkus Armbruster #include "migration/vmstate.h"
442e5b09fdSMarkus Armbruster #include "hw/core/cpu.h"
45db1015e9SEduardo Habkost #include "qom/object.h"
4649ab747fSPaolo Bonzini 
4749ab747fSPaolo Bonzini #define GPE_BASE 0xafe0
4849ab747fSPaolo Bonzini #define GPE_LEN 4
4949ab747fSPaolo Bonzini 
50caf108bcSJulia Suvorova #define ACPI_PCIHP_ADDR_PIIX4 0xae00
51caf108bcSJulia Suvorova 
5249ab747fSPaolo Bonzini struct pci_status {
5349ab747fSPaolo Bonzini     uint32_t up; /* deprecated, maintained for migration compatibility */
5449ab747fSPaolo Bonzini     uint32_t down;
5549ab747fSPaolo Bonzini };
5649ab747fSPaolo Bonzini 
5749ab747fSPaolo Bonzini static void piix4_acpi_system_hot_add_init(MemoryRegion *parent,
5849ab747fSPaolo Bonzini                                            PCIBus *bus, PIIX4PMState *s);
5949ab747fSPaolo Bonzini 
6049ab747fSPaolo Bonzini #define ACPI_ENABLE 0xf1
6149ab747fSPaolo Bonzini #define ACPI_DISABLE 0xf0
6249ab747fSPaolo Bonzini 
pm_tmr_timer(ACPIREGS * ar)6349ab747fSPaolo Bonzini static void pm_tmr_timer(ACPIREGS *ar)
6449ab747fSPaolo Bonzini {
6549ab747fSPaolo Bonzini     PIIX4PMState *s = container_of(ar, PIIX4PMState, ar);
6606313503SIgor Mammedov     acpi_update_sci(&s->ar, s->irq);
6749ab747fSPaolo Bonzini }
6849ab747fSPaolo Bonzini 
apm_ctrl_changed(uint32_t val,void * arg)6949ab747fSPaolo Bonzini static void apm_ctrl_changed(uint32_t val, void *arg)
7049ab747fSPaolo Bonzini {
7149ab747fSPaolo Bonzini     PIIX4PMState *s = arg;
726a6b5580SAndreas Färber     PCIDevice *d = PCI_DEVICE(s);
7349ab747fSPaolo Bonzini 
7449ab747fSPaolo Bonzini     /* ACPI specs 3.0, 4.7.2.5 */
7549ab747fSPaolo Bonzini     acpi_pm1_cnt_update(&s->ar, val == ACPI_ENABLE, val == ACPI_DISABLE);
76afd6895bSPaolo Bonzini     if (val == ACPI_ENABLE || val == ACPI_DISABLE) {
77afd6895bSPaolo Bonzini         return;
78afd6895bSPaolo Bonzini     }
7949ab747fSPaolo Bonzini 
806a6b5580SAndreas Färber     if (d->config[0x5b] & (1 << 1)) {
8149ab747fSPaolo Bonzini         if (s->smi_irq) {
8249ab747fSPaolo Bonzini             qemu_irq_raise(s->smi_irq);
8349ab747fSPaolo Bonzini         }
8449ab747fSPaolo Bonzini     }
8549ab747fSPaolo Bonzini }
8649ab747fSPaolo Bonzini 
pm_io_space_update(PIIX4PMState * s)8749ab747fSPaolo Bonzini static void pm_io_space_update(PIIX4PMState *s)
8849ab747fSPaolo Bonzini {
896a6b5580SAndreas Färber     PCIDevice *d = PCI_DEVICE(s);
9049ab747fSPaolo Bonzini 
91277e9340SMichael S. Tsirkin     s->io_base = le32_to_cpu(*(uint32_t *)(d->config + 0x40));
92277e9340SMichael S. Tsirkin     s->io_base &= 0xffc0;
9349ab747fSPaolo Bonzini 
9449ab747fSPaolo Bonzini     memory_region_transaction_begin();
956a6b5580SAndreas Färber     memory_region_set_enabled(&s->io, d->config[0x80] & 1);
96277e9340SMichael S. Tsirkin     memory_region_set_address(&s->io, s->io_base);
9749ab747fSPaolo Bonzini     memory_region_transaction_commit();
9849ab747fSPaolo Bonzini }
9949ab747fSPaolo Bonzini 
smbus_io_space_update(PIIX4PMState * s)10049ab747fSPaolo Bonzini static void smbus_io_space_update(PIIX4PMState *s)
10149ab747fSPaolo Bonzini {
1026a6b5580SAndreas Färber     PCIDevice *d = PCI_DEVICE(s);
1036a6b5580SAndreas Färber 
1046a6b5580SAndreas Färber     s->smb_io_base = le32_to_cpu(*(uint32_t *)(d->config + 0x90));
10549ab747fSPaolo Bonzini     s->smb_io_base &= 0xffc0;
10649ab747fSPaolo Bonzini 
10749ab747fSPaolo Bonzini     memory_region_transaction_begin();
1086a6b5580SAndreas Färber     memory_region_set_enabled(&s->smb.io, d->config[0xd2] & 1);
10949ab747fSPaolo Bonzini     memory_region_set_address(&s->smb.io, s->smb_io_base);
11049ab747fSPaolo Bonzini     memory_region_transaction_commit();
11149ab747fSPaolo Bonzini }
11249ab747fSPaolo Bonzini 
pm_write_config(PCIDevice * d,uint32_t address,uint32_t val,int len)11349ab747fSPaolo Bonzini static void pm_write_config(PCIDevice *d,
11449ab747fSPaolo Bonzini                             uint32_t address, uint32_t val, int len)
11549ab747fSPaolo Bonzini {
11649ab747fSPaolo Bonzini     pci_default_write_config(d, address, val, len);
11749ab747fSPaolo Bonzini     if (range_covers_byte(address, len, 0x80) ||
11849ab747fSPaolo Bonzini         ranges_overlap(address, len, 0x40, 4)) {
11949ab747fSPaolo Bonzini         pm_io_space_update((PIIX4PMState *)d);
12049ab747fSPaolo Bonzini     }
12149ab747fSPaolo Bonzini     if (range_covers_byte(address, len, 0xd2) ||
12249ab747fSPaolo Bonzini         ranges_overlap(address, len, 0x90, 4)) {
12349ab747fSPaolo Bonzini         smbus_io_space_update((PIIX4PMState *)d);
12449ab747fSPaolo Bonzini     }
12549ab747fSPaolo Bonzini }
12649ab747fSPaolo Bonzini 
vmstate_acpi_post_load(void * opaque,int version_id)12749ab747fSPaolo Bonzini static int vmstate_acpi_post_load(void *opaque, int version_id)
12849ab747fSPaolo Bonzini {
12949ab747fSPaolo Bonzini     PIIX4PMState *s = opaque;
13049ab747fSPaolo Bonzini 
13149ab747fSPaolo Bonzini     pm_io_space_update(s);
1322b4e573cSCorey Minyard     smbus_io_space_update(s);
13349ab747fSPaolo Bonzini     return 0;
13449ab747fSPaolo Bonzini }
13549ab747fSPaolo Bonzini 
13649ab747fSPaolo Bonzini #define VMSTATE_GPE_ARRAY(_field, _state)                            \
13749ab747fSPaolo Bonzini  {                                                                   \
13849ab747fSPaolo Bonzini      .name       = (stringify(_field)),                              \
13949ab747fSPaolo Bonzini      .version_id = 0,                                                \
14049ab747fSPaolo Bonzini      .info       = &vmstate_info_uint16,                             \
14149ab747fSPaolo Bonzini      .size       = sizeof(uint16_t),                                 \
14249ab747fSPaolo Bonzini      .flags      = VMS_SINGLE | VMS_POINTER,                         \
14349ab747fSPaolo Bonzini      .offset     = vmstate_offset_pointer(_state, _field, uint8_t),  \
14449ab747fSPaolo Bonzini  }
14549ab747fSPaolo Bonzini 
14649ab747fSPaolo Bonzini static const VMStateDescription vmstate_gpe = {
14749ab747fSPaolo Bonzini     .name = "gpe",
14849ab747fSPaolo Bonzini     .version_id = 1,
14949ab747fSPaolo Bonzini     .minimum_version_id = 1,
150c559ba57SRichard Henderson     .fields = (const VMStateField[]) {
15149ab747fSPaolo Bonzini         VMSTATE_GPE_ARRAY(sts, ACPIGPE),
15249ab747fSPaolo Bonzini         VMSTATE_GPE_ARRAY(en, ACPIGPE),
15349ab747fSPaolo Bonzini         VMSTATE_END_OF_LIST()
15449ab747fSPaolo Bonzini     }
15549ab747fSPaolo Bonzini };
15649ab747fSPaolo Bonzini 
15749ab747fSPaolo Bonzini static const VMStateDescription vmstate_pci_status = {
15849ab747fSPaolo Bonzini     .name = "pci_status",
15949ab747fSPaolo Bonzini     .version_id = 1,
16049ab747fSPaolo Bonzini     .minimum_version_id = 1,
161c559ba57SRichard Henderson     .fields = (const VMStateField[]) {
162e358edc8SIgor Mammedov         VMSTATE_UINT32(up, struct AcpiPciHpPciStatus),
163e358edc8SIgor Mammedov         VMSTATE_UINT32(down, struct AcpiPciHpPciStatus),
16449ab747fSPaolo Bonzini         VMSTATE_END_OF_LIST()
16549ab747fSPaolo Bonzini     }
16649ab747fSPaolo Bonzini };
16749ab747fSPaolo Bonzini 
vmstate_test_use_acpi_hotplug_bridge(void * opaque,int version_id)1680affda04SAni Sinha static bool vmstate_test_use_acpi_hotplug_bridge(void *opaque, int version_id)
1699e047b98SMichael S. Tsirkin {
1709e047b98SMichael S. Tsirkin     PIIX4PMState *s = opaque;
1716536e427SIgor Mammedov     return s->acpi_pci_hotplug.use_acpi_hotplug_bridge;
1729e047b98SMichael S. Tsirkin }
1739e047b98SMichael S. Tsirkin 
vmstate_test_no_use_acpi_hotplug_bridge(void * opaque,int version_id)1740affda04SAni Sinha static bool vmstate_test_no_use_acpi_hotplug_bridge(void *opaque,
1750affda04SAni Sinha                                                     int version_id)
1769e047b98SMichael S. Tsirkin {
1779e047b98SMichael S. Tsirkin     PIIX4PMState *s = opaque;
1786536e427SIgor Mammedov     return !s->acpi_pci_hotplug.use_acpi_hotplug_bridge;
1799e047b98SMichael S. Tsirkin }
1809e047b98SMichael S. Tsirkin 
vmstate_test_use_memhp(void * opaque)181f816a62dSIgor Mammedov static bool vmstate_test_use_memhp(void *opaque)
182f816a62dSIgor Mammedov {
183f816a62dSIgor Mammedov     PIIX4PMState *s = opaque;
184f816a62dSIgor Mammedov     return s->acpi_memory_hotplug.is_enabled;
185f816a62dSIgor Mammedov }
186f816a62dSIgor Mammedov 
187f816a62dSIgor Mammedov static const VMStateDescription vmstate_memhp_state = {
188f816a62dSIgor Mammedov     .name = "piix4_pm/memhp",
189f816a62dSIgor Mammedov     .version_id = 1,
190f816a62dSIgor Mammedov     .minimum_version_id = 1,
1915cd8cadaSJuan Quintela     .needed = vmstate_test_use_memhp,
192c559ba57SRichard Henderson     .fields = (const VMStateField[]) {
193f816a62dSIgor Mammedov         VMSTATE_MEMORY_HOTPLUG(acpi_memory_hotplug, PIIX4PMState),
194f816a62dSIgor Mammedov         VMSTATE_END_OF_LIST()
195f816a62dSIgor Mammedov     }
196f816a62dSIgor Mammedov };
197f816a62dSIgor Mammedov 
vmstate_test_use_cpuhp(void * opaque)198679dd1a9SIgor Mammedov static bool vmstate_test_use_cpuhp(void *opaque)
199679dd1a9SIgor Mammedov {
200679dd1a9SIgor Mammedov     PIIX4PMState *s = opaque;
201679dd1a9SIgor Mammedov     return !s->cpu_hotplug_legacy;
202679dd1a9SIgor Mammedov }
203679dd1a9SIgor Mammedov 
vmstate_cpuhp_pre_load(void * opaque)204679dd1a9SIgor Mammedov static int vmstate_cpuhp_pre_load(void *opaque)
205679dd1a9SIgor Mammedov {
206679dd1a9SIgor Mammedov     Object *obj = OBJECT(opaque);
2075325cc34SMarkus Armbruster     object_property_set_bool(obj, "cpu-hotplug-legacy", false, &error_abort);
208679dd1a9SIgor Mammedov     return 0;
209679dd1a9SIgor Mammedov }
210679dd1a9SIgor Mammedov 
211679dd1a9SIgor Mammedov static const VMStateDescription vmstate_cpuhp_state = {
212679dd1a9SIgor Mammedov     .name = "piix4_pm/cpuhp",
213679dd1a9SIgor Mammedov     .version_id = 1,
214679dd1a9SIgor Mammedov     .minimum_version_id = 1,
215679dd1a9SIgor Mammedov     .needed = vmstate_test_use_cpuhp,
216679dd1a9SIgor Mammedov     .pre_load = vmstate_cpuhp_pre_load,
217c559ba57SRichard Henderson     .fields = (const VMStateField[]) {
218679dd1a9SIgor Mammedov         VMSTATE_CPU_HOTPLUG(cpuhp_state, PIIX4PMState),
219679dd1a9SIgor Mammedov         VMSTATE_END_OF_LIST()
220679dd1a9SIgor Mammedov     }
221679dd1a9SIgor Mammedov };
222679dd1a9SIgor Mammedov 
piix4_vmstate_need_smbus(void * opaque,int version_id)2234ab2f2a8SCorey Minyard static bool piix4_vmstate_need_smbus(void *opaque, int version_id)
2244ab2f2a8SCorey Minyard {
2254ab2f2a8SCorey Minyard     return pm_smbus_vmstate_needed();
2264ab2f2a8SCorey Minyard }
2274ab2f2a8SCorey Minyard 
228a83c2844SDr. David Alan Gilbert /*
229a83c2844SDr. David Alan Gilbert  * This is a fudge to turn off the acpi_index field,
230a83c2844SDr. David Alan Gilbert  * whose test was always broken on piix4 with 6.2 and older machine types.
231a83c2844SDr. David Alan Gilbert  */
vmstate_test_migrate_acpi_index(void * opaque,int version_id)232a83c2844SDr. David Alan Gilbert static bool vmstate_test_migrate_acpi_index(void *opaque, int version_id)
233a83c2844SDr. David Alan Gilbert {
234a83c2844SDr. David Alan Gilbert     PIIX4PMState *s = PIIX4_PM(opaque);
2356536e427SIgor Mammedov     return s->acpi_pci_hotplug.use_acpi_hotplug_bridge &&
2366536e427SIgor Mammedov            !s->not_migrate_acpi_index;
237a83c2844SDr. David Alan Gilbert }
238a83c2844SDr. David Alan Gilbert 
23949ab747fSPaolo Bonzini /* qemu-kvm 1.2 uses version 3 but advertised as 2
24049ab747fSPaolo Bonzini  * To support incoming qemu-kvm 1.2 migration, change version_id
24149ab747fSPaolo Bonzini  * and minimum_version_id to 2 below (which breaks migration from
24249ab747fSPaolo Bonzini  * qemu 1.2).
24349ab747fSPaolo Bonzini  *
24449ab747fSPaolo Bonzini  */
24549ab747fSPaolo Bonzini static const VMStateDescription vmstate_acpi = {
24649ab747fSPaolo Bonzini     .name = "piix4_pm",
24749ab747fSPaolo Bonzini     .version_id = 3,
24849ab747fSPaolo Bonzini     .minimum_version_id = 3,
24949ab747fSPaolo Bonzini     .post_load = vmstate_acpi_post_load,
250c559ba57SRichard Henderson     .fields = (const VMStateField[]) {
2516a6b5580SAndreas Färber         VMSTATE_PCI_DEVICE(parent_obj, PIIX4PMState),
25249ab747fSPaolo Bonzini         VMSTATE_UINT16(ar.pm1.evt.sts, PIIX4PMState),
25349ab747fSPaolo Bonzini         VMSTATE_UINT16(ar.pm1.evt.en, PIIX4PMState),
25449ab747fSPaolo Bonzini         VMSTATE_UINT16(ar.pm1.cnt.cnt, PIIX4PMState),
25549ab747fSPaolo Bonzini         VMSTATE_STRUCT(apm, PIIX4PMState, 0, vmstate_apm, APMState),
2564ab2f2a8SCorey Minyard         VMSTATE_STRUCT_TEST(smb, PIIX4PMState, piix4_vmstate_need_smbus, 3,
2574ab2f2a8SCorey Minyard                             pmsmb_vmstate, PMSMBus),
258e720677eSPaolo Bonzini         VMSTATE_TIMER_PTR(ar.tmr.timer, PIIX4PMState),
25949ab747fSPaolo Bonzini         VMSTATE_INT64(ar.tmr.overflow_time, PIIX4PMState),
26049ab747fSPaolo Bonzini         VMSTATE_STRUCT(ar.gpe, PIIX4PMState, 2, vmstate_gpe, ACPIGPE),
261e358edc8SIgor Mammedov         VMSTATE_STRUCT_TEST(
262e358edc8SIgor Mammedov             acpi_pci_hotplug.acpi_pcihp_pci_status[ACPI_PCIHP_BSEL_DEFAULT],
263e358edc8SIgor Mammedov             PIIX4PMState,
2640affda04SAni Sinha             vmstate_test_no_use_acpi_hotplug_bridge,
2659e047b98SMichael S. Tsirkin             2, vmstate_pci_status,
266e358edc8SIgor Mammedov             struct AcpiPciHpPciStatus),
2679e047b98SMichael S. Tsirkin         VMSTATE_PCI_HOTPLUG(acpi_pci_hotplug, PIIX4PMState,
268b32bd763SIgor Mammedov                             vmstate_test_use_acpi_hotplug_bridge,
269a83c2844SDr. David Alan Gilbert                             vmstate_test_migrate_acpi_index),
27049ab747fSPaolo Bonzini         VMSTATE_END_OF_LIST()
271f816a62dSIgor Mammedov     },
272c559ba57SRichard Henderson     .subsections = (const VMStateDescription * const []) {
2735cd8cadaSJuan Quintela          &vmstate_memhp_state,
274679dd1a9SIgor Mammedov          &vmstate_cpuhp_state,
2755cd8cadaSJuan Quintela          NULL
27649ab747fSPaolo Bonzini     }
27749ab747fSPaolo Bonzini };
27849ab747fSPaolo Bonzini 
piix4_pm_reset(DeviceState * dev)279217e8ef9SPhilippe Mathieu-Daudé static void piix4_pm_reset(DeviceState *dev)
28049ab747fSPaolo Bonzini {
281217e8ef9SPhilippe Mathieu-Daudé     PIIX4PMState *s = PIIX4_PM(dev);
2826a6b5580SAndreas Färber     PCIDevice *d = PCI_DEVICE(s);
2836a6b5580SAndreas Färber     uint8_t *pci_conf = d->config;
28449ab747fSPaolo Bonzini 
28549ab747fSPaolo Bonzini     pci_conf[0x58] = 0;
28649ab747fSPaolo Bonzini     pci_conf[0x59] = 0;
28749ab747fSPaolo Bonzini     pci_conf[0x5a] = 0;
28849ab747fSPaolo Bonzini     pci_conf[0x5b] = 0;
28949ab747fSPaolo Bonzini 
29049ab747fSPaolo Bonzini     pci_conf[0x40] = 0x01; /* PM io base read only bit */
29149ab747fSPaolo Bonzini     pci_conf[0x80] = 0;
29249ab747fSPaolo Bonzini 
29361e66c62SPaolo Bonzini     if (!s->smm_enabled) {
29449ab747fSPaolo Bonzini         /* Mark SMM as already inited (until KVM supports SMM). */
29549ab747fSPaolo Bonzini         pci_conf[0x5B] = 0x02;
29649ab747fSPaolo Bonzini     }
2970fd74325SIsaku Yamahata 
2980fd74325SIsaku Yamahata     acpi_pm1_evt_reset(&s->ar);
2990fd74325SIsaku Yamahata     acpi_pm1_cnt_reset(&s->ar);
3000fd74325SIsaku Yamahata     acpi_pm_tmr_reset(&s->ar);
3010fd74325SIsaku Yamahata     acpi_gpe_reset(&s->ar);
3020fd74325SIsaku Yamahata     acpi_update_sci(&s->ar, s->irq);
3030fd74325SIsaku Yamahata 
304c046e8c4SMichael S. Tsirkin     pm_io_space_update(s);
3056536e427SIgor Mammedov     if (s->acpi_pci_hotplug.use_acpi_hotplug_bridge ||
3066536e427SIgor Mammedov         s->acpi_pci_hotplug.use_acpi_root_pci_hotplug) {
3076536e427SIgor Mammedov         acpi_pcihp_reset(&s->acpi_pci_hotplug);
3089e047b98SMichael S. Tsirkin     }
30945284cfbSIgor Mammedov }
31049ab747fSPaolo Bonzini 
piix4_pm_powerdown_req(Notifier * n,void * opaque)31149ab747fSPaolo Bonzini static void piix4_pm_powerdown_req(Notifier *n, void *opaque)
31249ab747fSPaolo Bonzini {
31349ab747fSPaolo Bonzini     PIIX4PMState *s = container_of(n, PIIX4PMState, powerdown_notifier);
31449ab747fSPaolo Bonzini 
31549ab747fSPaolo Bonzini     assert(s != NULL);
31649ab747fSPaolo Bonzini     acpi_pm1_evt_power_down(&s->ar);
31749ab747fSPaolo Bonzini }
31849ab747fSPaolo Bonzini 
piix4_device_pre_plug_cb(HotplugHandler * hotplug_dev,DeviceState * dev,Error ** errp)319ec266f40SDavid Hildenbrand static void piix4_device_pre_plug_cb(HotplugHandler *hotplug_dev,
320ec266f40SDavid Hildenbrand                                     DeviceState *dev, Error **errp)
321ec266f40SDavid Hildenbrand {
3229040e6dfSWei Yang     PIIX4PMState *s = PIIX4_PM(hotplug_dev);
3239040e6dfSWei Yang 
324ec266f40SDavid Hildenbrand     if (object_dynamic_cast(OBJECT(dev), TYPE_PCI_DEVICE)) {
325ec266f40SDavid Hildenbrand         acpi_pcihp_device_pre_plug_cb(hotplug_dev, dev, errp);
3269040e6dfSWei Yang     } else if (object_dynamic_cast(OBJECT(dev), TYPE_PC_DIMM)) {
3279040e6dfSWei Yang         if (!s->acpi_memory_hotplug.is_enabled) {
3289040e6dfSWei Yang             error_setg(errp,
3299040e6dfSWei Yang                 "memory hotplug is not enabled: %s.memory-hotplug-support "
3309040e6dfSWei Yang                 "is not set", object_get_typename(OBJECT(s)));
3319040e6dfSWei Yang         }
3329040e6dfSWei Yang     } else if (
333ec266f40SDavid Hildenbrand                !object_dynamic_cast(OBJECT(dev), TYPE_CPU)) {
334ec266f40SDavid Hildenbrand         error_setg(errp, "acpi: device pre plug request for not supported"
335ec266f40SDavid Hildenbrand                    " device type: %s", object_get_typename(OBJECT(dev)));
336ec266f40SDavid Hildenbrand     }
337ec266f40SDavid Hildenbrand }
338ec266f40SDavid Hildenbrand 
piix4_device_plug_cb(HotplugHandler * hotplug_dev,DeviceState * dev,Error ** errp)339f1adc360SIgor Mammedov static void piix4_device_plug_cb(HotplugHandler *hotplug_dev,
340c24d5e0bSIgor Mammedov                                  DeviceState *dev, Error **errp)
3419e047b98SMichael S. Tsirkin {
342c24d5e0bSIgor Mammedov     PIIX4PMState *s = PIIX4_PM(hotplug_dev);
343f1adc360SIgor Mammedov 
3449040e6dfSWei Yang     if (object_dynamic_cast(OBJECT(dev), TYPE_PC_DIMM)) {
34575f27498SXiao Guangrong         if (object_dynamic_cast(OBJECT(dev), TYPE_NVDIMM)) {
34675f27498SXiao Guangrong             nvdimm_acpi_plug_cb(hotplug_dev, dev);
34775f27498SXiao Guangrong         } else {
34875f27498SXiao Guangrong             acpi_memory_plug_cb(hotplug_dev, &s->acpi_memory_hotplug,
34975f27498SXiao Guangrong                                 dev, errp);
35075f27498SXiao Guangrong         }
35134774320SIgor Mammedov     } else if (object_dynamic_cast(OBJECT(dev), TYPE_PCI_DEVICE)) {
3522bed1ba7SAnthony PERARD         acpi_pcihp_device_plug_cb(hotplug_dev, &s->acpi_pci_hotplug, dev, errp);
3535e1b5d93SIgor Mammedov     } else if (object_dynamic_cast(OBJECT(dev), TYPE_CPU)) {
3545e1b5d93SIgor Mammedov         if (s->cpu_hotplug_legacy) {
3550058c082SIgor Mammedov             legacy_acpi_cpu_plug_cb(hotplug_dev, &s->gpe_cpu, dev, errp);
356f1adc360SIgor Mammedov         } else {
3575e1b5d93SIgor Mammedov             acpi_cpu_plug_cb(hotplug_dev, &s->cpuhp_state, dev, errp);
3585e1b5d93SIgor Mammedov         }
3595e1b5d93SIgor Mammedov     } else {
360ec266f40SDavid Hildenbrand         g_assert_not_reached();
361f1adc360SIgor Mammedov     }
3629e047b98SMichael S. Tsirkin }
3639e047b98SMichael S. Tsirkin 
piix4_device_unplug_request_cb(HotplugHandler * hotplug_dev,DeviceState * dev,Error ** errp)36414d5a28fSIgor Mammedov static void piix4_device_unplug_request_cb(HotplugHandler *hotplug_dev,
365c24d5e0bSIgor Mammedov                                            DeviceState *dev, Error **errp)
366c24d5e0bSIgor Mammedov {
367c24d5e0bSIgor Mammedov     PIIX4PMState *s = PIIX4_PM(hotplug_dev);
368f1adc360SIgor Mammedov 
36964fec58eSTang Chen     if (s->acpi_memory_hotplug.is_enabled &&
37064fec58eSTang Chen         object_dynamic_cast(OBJECT(dev), TYPE_PC_DIMM)) {
3710058c082SIgor Mammedov         acpi_memory_unplug_request_cb(hotplug_dev, &s->acpi_memory_hotplug,
37264fec58eSTang Chen                                       dev, errp);
37364fec58eSTang Chen     } else if (object_dynamic_cast(OBJECT(dev), TYPE_PCI_DEVICE)) {
374c97adf3cSDavid Hildenbrand         acpi_pcihp_device_unplug_request_cb(hotplug_dev, &s->acpi_pci_hotplug,
375c97adf3cSDavid Hildenbrand                                             dev, errp);
3768872c25aSIgor Mammedov     } else if (object_dynamic_cast(OBJECT(dev), TYPE_CPU) &&
3778872c25aSIgor Mammedov                !s->cpu_hotplug_legacy) {
3788872c25aSIgor Mammedov         acpi_cpu_unplug_request_cb(hotplug_dev, &s->cpuhp_state, dev, errp);
379f1adc360SIgor Mammedov     } else {
380f1adc360SIgor Mammedov         error_setg(errp, "acpi: device unplug request for not supported device"
381f1adc360SIgor Mammedov                    " type: %s", object_get_typename(OBJECT(dev)));
382f1adc360SIgor Mammedov     }
383c24d5e0bSIgor Mammedov }
384c24d5e0bSIgor Mammedov 
piix4_device_unplug_cb(HotplugHandler * hotplug_dev,DeviceState * dev,Error ** errp)385c0e57a60STang Chen static void piix4_device_unplug_cb(HotplugHandler *hotplug_dev,
386c0e57a60STang Chen                                    DeviceState *dev, Error **errp)
387c0e57a60STang Chen {
388f7d3e29dSTang Chen     PIIX4PMState *s = PIIX4_PM(hotplug_dev);
389f7d3e29dSTang Chen 
390f7d3e29dSTang Chen     if (s->acpi_memory_hotplug.is_enabled &&
391f7d3e29dSTang Chen         object_dynamic_cast(OBJECT(dev), TYPE_PC_DIMM)) {
392f7d3e29dSTang Chen         acpi_memory_unplug_cb(&s->acpi_memory_hotplug, dev, errp);
393c97adf3cSDavid Hildenbrand     } else if (object_dynamic_cast(OBJECT(dev), TYPE_PCI_DEVICE)) {
394c97adf3cSDavid Hildenbrand         acpi_pcihp_device_unplug_cb(hotplug_dev, &s->acpi_pci_hotplug, dev,
395c97adf3cSDavid Hildenbrand                                     errp);
3968872c25aSIgor Mammedov     } else if (object_dynamic_cast(OBJECT(dev), TYPE_CPU) &&
3978872c25aSIgor Mammedov                !s->cpu_hotplug_legacy) {
3988872c25aSIgor Mammedov         acpi_cpu_unplug_cb(&s->cpuhp_state, dev, errp);
399f7d3e29dSTang Chen     } else {
400c0e57a60STang Chen         error_setg(errp, "acpi: device unplug for not supported device"
401c0e57a60STang Chen                    " type: %s", object_get_typename(OBJECT(dev)));
402c0e57a60STang Chen     }
403f7d3e29dSTang Chen }
404c0e57a60STang Chen 
piix4_is_hotpluggable_bus(HotplugHandler * hotplug_dev,BusState * bus)405f18e29fcSIgor Mammedov static bool piix4_is_hotpluggable_bus(HotplugHandler *hotplug_dev,
406f18e29fcSIgor Mammedov                                       BusState *bus)
407f18e29fcSIgor Mammedov {
408f18e29fcSIgor Mammedov     PIIX4PMState *s = PIIX4_PM(hotplug_dev);
409f18e29fcSIgor Mammedov     return acpi_pcihp_is_hotpluggbale_bus(&s->acpi_pci_hotplug, bus);
410f18e29fcSIgor Mammedov }
411f18e29fcSIgor Mammedov 
piix4_pm_machine_ready(Notifier * n,void * opaque)41249ab747fSPaolo Bonzini static void piix4_pm_machine_ready(Notifier *n, void *opaque)
41349ab747fSPaolo Bonzini {
41449ab747fSPaolo Bonzini     PIIX4PMState *s = container_of(n, PIIX4PMState, machine_ready);
4156a6b5580SAndreas Färber     PCIDevice *d = PCI_DEVICE(s);
4166a6b5580SAndreas Färber     MemoryRegion *io_as = pci_address_space_io(d);
41749ab747fSPaolo Bonzini     uint8_t *pci_conf;
41849ab747fSPaolo Bonzini 
4196a6b5580SAndreas Färber     pci_conf = d->config;
420b6f32962SJan Kiszka     pci_conf[0x5f] = 0x10 |
4213ce10901SPaolo Bonzini         (memory_region_present(io_as, 0x378) ? 0x80 : 0);
42249ab747fSPaolo Bonzini     pci_conf[0x63] = 0x60;
4233ce10901SPaolo Bonzini     pci_conf[0x67] = (memory_region_present(io_as, 0x3f8) ? 0x08 : 0) |
4243ce10901SPaolo Bonzini         (memory_region_present(io_as, 0x2f8) ? 0x90 : 0);
42549ab747fSPaolo Bonzini }
42649ab747fSPaolo Bonzini 
piix4_pm_add_properties(PIIX4PMState * s)4275ad1037cSGreg Kurz static void piix4_pm_add_properties(PIIX4PMState *s)
428277e9340SMichael S. Tsirkin {
429277e9340SMichael S. Tsirkin     static const uint8_t acpi_enable_cmd = ACPI_ENABLE;
430277e9340SMichael S. Tsirkin     static const uint8_t acpi_disable_cmd = ACPI_DISABLE;
431277e9340SMichael S. Tsirkin     static const uint32_t gpe0_blk = GPE_BASE;
432277e9340SMichael S. Tsirkin     static const uint32_t gpe0_blk_len = GPE_LEN;
433277e9340SMichael S. Tsirkin     static const uint16_t sci_int = 9;
434277e9340SMichael S. Tsirkin 
435277e9340SMichael S. Tsirkin     object_property_add_uint8_ptr(OBJECT(s), ACPI_PM_PROP_ACPI_ENABLE_CMD,
436d2623129SMarkus Armbruster                                   &acpi_enable_cmd, OBJ_PROP_FLAG_READ);
437277e9340SMichael S. Tsirkin     object_property_add_uint8_ptr(OBJECT(s), ACPI_PM_PROP_ACPI_DISABLE_CMD,
438d2623129SMarkus Armbruster                                   &acpi_disable_cmd, OBJ_PROP_FLAG_READ);
439277e9340SMichael S. Tsirkin     object_property_add_uint32_ptr(OBJECT(s), ACPI_PM_PROP_GPE0_BLK,
440d2623129SMarkus Armbruster                                   &gpe0_blk, OBJ_PROP_FLAG_READ);
441277e9340SMichael S. Tsirkin     object_property_add_uint32_ptr(OBJECT(s), ACPI_PM_PROP_GPE0_BLK_LEN,
442d2623129SMarkus Armbruster                                   &gpe0_blk_len, OBJ_PROP_FLAG_READ);
443277e9340SMichael S. Tsirkin     object_property_add_uint16_ptr(OBJECT(s), ACPI_PM_PROP_SCI_INT,
444d2623129SMarkus Armbruster                                   &sci_int, OBJ_PROP_FLAG_READ);
445277e9340SMichael S. Tsirkin     object_property_add_uint32_ptr(OBJECT(s), ACPI_PM_PROP_PM_IO_BASE,
446d2623129SMarkus Armbruster                                   &s->io_base, OBJ_PROP_FLAG_READ);
447277e9340SMichael S. Tsirkin }
448277e9340SMichael S. Tsirkin 
piix4_pm_realize(PCIDevice * dev,Error ** errp)4499af21dbeSMarkus Armbruster static void piix4_pm_realize(PCIDevice *dev, Error **errp)
45049ab747fSPaolo Bonzini {
45174e445f6SPeter Crosthwaite     PIIX4PMState *s = PIIX4_PM(dev);
45249ab747fSPaolo Bonzini     uint8_t *pci_conf;
45349ab747fSPaolo Bonzini 
4546a6b5580SAndreas Färber     pci_conf = dev->config;
45549ab747fSPaolo Bonzini     pci_conf[0x06] = 0x80;
45649ab747fSPaolo Bonzini     pci_conf[0x07] = 0x02;
45749ab747fSPaolo Bonzini     pci_conf[0x09] = 0x00;
45849ab747fSPaolo Bonzini     pci_conf[0x3d] = 0x01; // interrupt pin 1
45949ab747fSPaolo Bonzini 
46049ab747fSPaolo Bonzini     /* APM */
46149ab747fSPaolo Bonzini     apm_init(dev, &s->apm, apm_ctrl_changed, s);
46249ab747fSPaolo Bonzini 
46361e66c62SPaolo Bonzini     if (!s->smm_enabled) {
46449ab747fSPaolo Bonzini         /* Mark SMM as already inited to prevent SMM from running.  KVM does not
46549ab747fSPaolo Bonzini          * support SMM mode. */
46649ab747fSPaolo Bonzini         pci_conf[0x5B] = 0x02;
46749ab747fSPaolo Bonzini     }
46849ab747fSPaolo Bonzini 
46949ab747fSPaolo Bonzini     /* XXX: which specification is used ? The i82731AB has different
47049ab747fSPaolo Bonzini        mappings */
47149ab747fSPaolo Bonzini     pci_conf[0x90] = s->smb_io_base | 1;
47249ab747fSPaolo Bonzini     pci_conf[0x91] = s->smb_io_base >> 8;
47349ab747fSPaolo Bonzini     pci_conf[0xd2] = 0x09;
47445726b6eSCorey Minyard     pm_smbus_init(DEVICE(dev), &s->smb, true);
47549ab747fSPaolo Bonzini     memory_region_set_enabled(&s->smb.io, pci_conf[0xd2] & 1);
47649ab747fSPaolo Bonzini     memory_region_add_subregion(pci_address_space_io(dev),
47749ab747fSPaolo Bonzini                                 s->smb_io_base, &s->smb.io);
47849ab747fSPaolo Bonzini 
47964bde0f3SPaolo Bonzini     memory_region_init(&s->io, OBJECT(s), "piix4-pm", 64);
48049ab747fSPaolo Bonzini     memory_region_set_enabled(&s->io, false);
48149ab747fSPaolo Bonzini     memory_region_add_subregion(pci_address_space_io(dev),
48249ab747fSPaolo Bonzini                                 0, &s->io);
48349ab747fSPaolo Bonzini 
48449ab747fSPaolo Bonzini     acpi_pm_tmr_init(&s->ar, pm_tmr_timer, &s->io);
48549ab747fSPaolo Bonzini     acpi_pm1_evt_init(&s->ar, pm_tmr_timer, &s->io);
4866be8cf56SIsaku Yamahata     acpi_pm1_cnt_init(&s->ar, &s->io, s->disable_s3, s->disable_s4, s->s4_val,
4876be8cf56SIsaku Yamahata                       !s->smm_compat && !s->smm_enabled);
48849ab747fSPaolo Bonzini     acpi_gpe_init(&s->ar, GPE_LEN);
48949ab747fSPaolo Bonzini 
49049ab747fSPaolo Bonzini     s->powerdown_notifier.notify = piix4_pm_powerdown_req;
49149ab747fSPaolo Bonzini     qemu_register_powerdown_notifier(&s->powerdown_notifier);
49249ab747fSPaolo Bonzini 
49349ab747fSPaolo Bonzini     s->machine_ready.notify = piix4_pm_machine_ready;
49449ab747fSPaolo Bonzini     qemu_add_machine_init_done_notifier(&s->machine_ready);
49549ab747fSPaolo Bonzini 
4963f0efcacSMark Cave-Ayland     if (xen_enabled()) {
4976536e427SIgor Mammedov         s->acpi_pci_hotplug.use_acpi_hotplug_bridge = false;
4983f0efcacSMark Cave-Ayland     }
4993f0efcacSMark Cave-Ayland 
500fd56e061SDavid Gibson     piix4_acpi_system_hot_add_init(pci_address_space_io(dev),
501fd56e061SDavid Gibson                                    pci_get_bus(dev), s);
50249ab747fSPaolo Bonzini 
5035ad1037cSGreg Kurz     piix4_pm_add_properties(s);
50449ab747fSPaolo Bonzini }
50549ab747fSPaolo Bonzini 
piix4_pm_init(Object * obj)50629786d42SMark Cave-Ayland static void piix4_pm_init(Object *obj)
50729786d42SMark Cave-Ayland {
50829786d42SMark Cave-Ayland     PIIX4PMState *s = PIIX4_PM(obj);
50929786d42SMark Cave-Ayland 
51029786d42SMark Cave-Ayland     qdev_init_gpio_out(DEVICE(obj), &s->irq, 1);
511b49e9442SMark Cave-Ayland     qdev_init_gpio_out_named(DEVICE(obj), &s->smi_irq, "smi-irq", 1);
51229786d42SMark Cave-Ayland }
51329786d42SMark Cave-Ayland 
gpe_readb(void * opaque,hwaddr addr,unsigned width)51449ab747fSPaolo Bonzini static uint64_t gpe_readb(void *opaque, hwaddr addr, unsigned width)
51549ab747fSPaolo Bonzini {
51649ab747fSPaolo Bonzini     PIIX4PMState *s = opaque;
51749ab747fSPaolo Bonzini     uint32_t val = acpi_gpe_ioport_readb(&s->ar, addr);
51849ab747fSPaolo Bonzini 
51949ab747fSPaolo Bonzini     return val;
52049ab747fSPaolo Bonzini }
52149ab747fSPaolo Bonzini 
gpe_writeb(void * opaque,hwaddr addr,uint64_t val,unsigned width)52249ab747fSPaolo Bonzini static void gpe_writeb(void *opaque, hwaddr addr, uint64_t val,
52349ab747fSPaolo Bonzini                        unsigned width)
52449ab747fSPaolo Bonzini {
52549ab747fSPaolo Bonzini     PIIX4PMState *s = opaque;
52649ab747fSPaolo Bonzini 
52749ab747fSPaolo Bonzini     acpi_gpe_ioport_writeb(&s->ar, addr, val);
52806313503SIgor Mammedov     acpi_update_sci(&s->ar, s->irq);
52949ab747fSPaolo Bonzini }
53049ab747fSPaolo Bonzini 
53149ab747fSPaolo Bonzini static const MemoryRegionOps piix4_gpe_ops = {
53249ab747fSPaolo Bonzini     .read = gpe_readb,
53349ab747fSPaolo Bonzini     .write = gpe_writeb,
53449ab747fSPaolo Bonzini     .valid.min_access_size = 1,
53549ab747fSPaolo Bonzini     .valid.max_access_size = 4,
53649ab747fSPaolo Bonzini     .impl.min_access_size = 1,
53749ab747fSPaolo Bonzini     .impl.max_access_size = 1,
53849ab747fSPaolo Bonzini     .endianness = DEVICE_LITTLE_ENDIAN,
53949ab747fSPaolo Bonzini };
54049ab747fSPaolo Bonzini 
54116bcab97SIgor Mammedov 
piix4_get_cpu_hotplug_legacy(Object * obj,Error ** errp)54216bcab97SIgor Mammedov static bool piix4_get_cpu_hotplug_legacy(Object *obj, Error **errp)
54316bcab97SIgor Mammedov {
54416bcab97SIgor Mammedov     PIIX4PMState *s = PIIX4_PM(obj);
54516bcab97SIgor Mammedov 
54616bcab97SIgor Mammedov     return s->cpu_hotplug_legacy;
54716bcab97SIgor Mammedov }
54816bcab97SIgor Mammedov 
piix4_set_cpu_hotplug_legacy(Object * obj,bool value,Error ** errp)54916bcab97SIgor Mammedov static void piix4_set_cpu_hotplug_legacy(Object *obj, bool value, Error **errp)
55016bcab97SIgor Mammedov {
55116bcab97SIgor Mammedov     PIIX4PMState *s = PIIX4_PM(obj);
55216bcab97SIgor Mammedov 
553679dd1a9SIgor Mammedov     assert(!value);
554679dd1a9SIgor Mammedov     if (s->cpu_hotplug_legacy && value == false) {
555679dd1a9SIgor Mammedov         acpi_switch_to_modern_cphp(&s->gpe_cpu, &s->cpuhp_state,
556679dd1a9SIgor Mammedov                                    PIIX4_CPU_HOTPLUG_IO_BASE);
557679dd1a9SIgor Mammedov     }
55816bcab97SIgor Mammedov     s->cpu_hotplug_legacy = value;
55916bcab97SIgor Mammedov }
56016bcab97SIgor Mammedov 
piix4_acpi_system_hot_add_init(MemoryRegion * parent,PCIBus * bus,PIIX4PMState * s)56149ab747fSPaolo Bonzini static void piix4_acpi_system_hot_add_init(MemoryRegion *parent,
56249ab747fSPaolo Bonzini                                            PCIBus *bus, PIIX4PMState *s)
56349ab747fSPaolo Bonzini {
56464bde0f3SPaolo Bonzini     memory_region_init_io(&s->io_gpe, OBJECT(s), &piix4_gpe_ops, s,
56564bde0f3SPaolo Bonzini                           "acpi-gpe0", GPE_LEN);
56649ab747fSPaolo Bonzini     memory_region_add_subregion(parent, GPE_BASE, &s->io_gpe);
56749ab747fSPaolo Bonzini 
5686536e427SIgor Mammedov     if (s->acpi_pci_hotplug.use_acpi_hotplug_bridge ||
5696536e427SIgor Mammedov         s->acpi_pci_hotplug.use_acpi_root_pci_hotplug) {
57078c2d872SIgor Mammedov         acpi_pcihp_init(OBJECT(s), &s->acpi_pci_hotplug, bus, parent,
5716536e427SIgor Mammedov                         ACPI_PCIHP_ADDR_PIIX4);
572f40e6a4cSIgor Mammedov         qbus_set_hotplug_handler(BUS(pci_get_bus(PCI_DEVICE(s))), OBJECT(s));
573df4008c9SAni Sinha     }
574b8622725SIgor Mammedov 
57516bcab97SIgor Mammedov     s->cpu_hotplug_legacy = true;
57616bcab97SIgor Mammedov     object_property_add_bool(OBJECT(s), "cpu-hotplug-legacy",
57716bcab97SIgor Mammedov                              piix4_get_cpu_hotplug_legacy,
578d2623129SMarkus Armbruster                              piix4_set_cpu_hotplug_legacy);
57996e3e12bSIgor Mammedov     legacy_acpi_cpu_hotplug_init(parent, OBJECT(s), &s->gpe_cpu,
580e4cf8ed0SIgor Mammedov                                  PIIX4_CPU_HOTPLUG_IO_BASE);
58134774320SIgor Mammedov 
58234774320SIgor Mammedov     if (s->acpi_memory_hotplug.is_enabled) {
58380db0e78SIgor Mammedov         acpi_memory_hotplug_init(parent, OBJECT(s), &s->acpi_memory_hotplug,
58480db0e78SIgor Mammedov                                  ACPI_MEMORY_HOTPLUG_BASE);
58534774320SIgor Mammedov     }
58649ab747fSPaolo Bonzini }
5875fdae20cSIgor Mammedov 
piix4_ospm_status(AcpiDeviceIf * adev,ACPIOSTInfoList *** list)58843f50410SIgor Mammedov static void piix4_ospm_status(AcpiDeviceIf *adev, ACPIOSTInfoList ***list)
58943f50410SIgor Mammedov {
59043f50410SIgor Mammedov     PIIX4PMState *s = PIIX4_PM(adev);
59143f50410SIgor Mammedov 
59243f50410SIgor Mammedov     acpi_memory_ospm_status(&s->acpi_memory_hotplug, list);
59376623d00SIgor Mammedov     if (!s->cpu_hotplug_legacy) {
59476623d00SIgor Mammedov         acpi_cpu_ospm_status(&s->cpuhp_state, list);
59576623d00SIgor Mammedov     }
59643f50410SIgor Mammedov }
59743f50410SIgor Mammedov 
piix4_send_gpe(AcpiDeviceIf * adev,AcpiEventStatusBits ev)598eaf23bf7SIgor Mammedov static void piix4_send_gpe(AcpiDeviceIf *adev, AcpiEventStatusBits ev)
599eaf23bf7SIgor Mammedov {
600eaf23bf7SIgor Mammedov     PIIX4PMState *s = PIIX4_PM(adev);
601eaf23bf7SIgor Mammedov 
602eaf23bf7SIgor Mammedov     acpi_send_gpe_event(&s->ar, s->irq, ev);
603eaf23bf7SIgor Mammedov }
604eaf23bf7SIgor Mammedov 
6055fdae20cSIgor Mammedov static Property piix4_pm_properties[] = {
6065fdae20cSIgor Mammedov     DEFINE_PROP_UINT32("smb_io_base", PIIX4PMState, smb_io_base, 0),
6075fdae20cSIgor Mammedov     DEFINE_PROP_UINT8(ACPI_PM_PROP_S3_DISABLED, PIIX4PMState, disable_s3, 0),
6085fdae20cSIgor Mammedov     DEFINE_PROP_UINT8(ACPI_PM_PROP_S4_DISABLED, PIIX4PMState, disable_s4, 0),
6095fdae20cSIgor Mammedov     DEFINE_PROP_UINT8(ACPI_PM_PROP_S4_VAL, PIIX4PMState, s4_val, 2),
610aa29466bSAni Sinha     DEFINE_PROP_BOOL(ACPI_PM_PROP_ACPI_PCIHP_BRIDGE, PIIX4PMState,
6116536e427SIgor Mammedov                      acpi_pci_hotplug.use_acpi_hotplug_bridge, true),
612aa29466bSAni Sinha     DEFINE_PROP_BOOL(ACPI_PM_PROP_ACPI_PCI_ROOTHP, PIIX4PMState,
6136536e427SIgor Mammedov                      acpi_pci_hotplug.use_acpi_root_pci_hotplug, true),
61434774320SIgor Mammedov     DEFINE_PROP_BOOL("memory-hotplug-support", PIIX4PMState,
61534774320SIgor Mammedov                      acpi_memory_hotplug.is_enabled, true),
61624cd04fcSIsaku Yamahata     DEFINE_PROP_BOOL("smm-compat", PIIX4PMState, smm_compat, false),
6177ace6b4fSMark Cave-Ayland     DEFINE_PROP_BOOL("smm-enabled", PIIX4PMState, smm_enabled, false),
618a83c2844SDr. David Alan Gilbert     DEFINE_PROP_BOOL("x-not-migrate-acpi-index", PIIX4PMState,
619a83c2844SDr. David Alan Gilbert                       not_migrate_acpi_index, false),
6205fdae20cSIgor Mammedov     DEFINE_PROP_END_OF_LIST(),
6215fdae20cSIgor Mammedov };
6225fdae20cSIgor Mammedov 
piix4_pm_class_init(ObjectClass * klass,void * data)6235fdae20cSIgor Mammedov static void piix4_pm_class_init(ObjectClass *klass, void *data)
6245fdae20cSIgor Mammedov {
6255fdae20cSIgor Mammedov     DeviceClass *dc = DEVICE_CLASS(klass);
6265fdae20cSIgor Mammedov     PCIDeviceClass *k = PCI_DEVICE_CLASS(klass);
627c24d5e0bSIgor Mammedov     HotplugHandlerClass *hc = HOTPLUG_HANDLER_CLASS(klass);
62843f50410SIgor Mammedov     AcpiDeviceIfClass *adevc = ACPI_DEVICE_IF_CLASS(klass);
6295fdae20cSIgor Mammedov 
6309af21dbeSMarkus Armbruster     k->realize = piix4_pm_realize;
6315fdae20cSIgor Mammedov     k->config_write = pm_write_config;
6325fdae20cSIgor Mammedov     k->vendor_id = PCI_VENDOR_ID_INTEL;
6335fdae20cSIgor Mammedov     k->device_id = PCI_DEVICE_ID_INTEL_82371AB_3;
6345fdae20cSIgor Mammedov     k->revision = 0x03;
6355fdae20cSIgor Mammedov     k->class_id = PCI_CLASS_BRIDGE_OTHER;
636*e3d08143SPeter Maydell     device_class_set_legacy_reset(dc, piix4_pm_reset);
6375fdae20cSIgor Mammedov     dc->desc = "PM";
6385fdae20cSIgor Mammedov     dc->vmsd = &vmstate_acpi;
6394f67d30bSMarc-André Lureau     device_class_set_props(dc, piix4_pm_properties);
6405fdae20cSIgor Mammedov     /*
6415fdae20cSIgor Mammedov      * Reason: part of PIIX4 southbridge, needs to be wired up,
6425fdae20cSIgor Mammedov      * e.g. by mips_malta_init()
6435fdae20cSIgor Mammedov      */
644e90f2a8cSEduardo Habkost     dc->user_creatable = false;
6452897ae02SIgor Mammedov     dc->hotpluggable = false;
646ec266f40SDavid Hildenbrand     hc->pre_plug = piix4_device_pre_plug_cb;
647f1adc360SIgor Mammedov     hc->plug = piix4_device_plug_cb;
64814d5a28fSIgor Mammedov     hc->unplug_request = piix4_device_unplug_request_cb;
649c0e57a60STang Chen     hc->unplug = piix4_device_unplug_cb;
650f18e29fcSIgor Mammedov     hc->is_hotpluggable_bus = piix4_is_hotpluggable_bus;
65143f50410SIgor Mammedov     adevc->ospm_status = piix4_ospm_status;
652eaf23bf7SIgor Mammedov     adevc->send_event = piix4_send_gpe;
6535fdae20cSIgor Mammedov }
6545fdae20cSIgor Mammedov 
6555fdae20cSIgor Mammedov static const TypeInfo piix4_pm_info = {
6565fdae20cSIgor Mammedov     .name          = TYPE_PIIX4_PM,
6575fdae20cSIgor Mammedov     .parent        = TYPE_PCI_DEVICE,
65829786d42SMark Cave-Ayland     .instance_init  = piix4_pm_init,
6595fdae20cSIgor Mammedov     .instance_size = sizeof(PIIX4PMState),
6605fdae20cSIgor Mammedov     .class_init    = piix4_pm_class_init,
661c24d5e0bSIgor Mammedov     .interfaces = (InterfaceInfo[]) {
662c24d5e0bSIgor Mammedov         { TYPE_HOTPLUG_HANDLER },
66343f50410SIgor Mammedov         { TYPE_ACPI_DEVICE_IF },
664fd3b02c8SEduardo Habkost         { INTERFACE_CONVENTIONAL_PCI_DEVICE },
665c24d5e0bSIgor Mammedov         { }
666c24d5e0bSIgor Mammedov     }
6675fdae20cSIgor Mammedov };
6685fdae20cSIgor Mammedov 
piix4_pm_register_types(void)6695fdae20cSIgor Mammedov static void piix4_pm_register_types(void)
6705fdae20cSIgor Mammedov {
6715fdae20cSIgor Mammedov     type_register_static(&piix4_pm_info);
6725fdae20cSIgor Mammedov }
6735fdae20cSIgor Mammedov 
6745fdae20cSIgor Mammedov type_init(piix4_pm_register_types)
675