qemu

FORK: QEMU emulator
git clone https://git.neptards.moe/neptards/qemu.git
Log | Files | Refs | Submodules | LICENSE

ich9.c (20192B)


      1 /*
      2  * ACPI implementation
      3  *
      4  * Copyright (c) 2006 Fabrice Bellard
      5  * Copyright (c) 2009 Isaku Yamahata <yamahata at valinux co jp>
      6  *                    VA Linux Systems Japan K.K.
      7  * Copyright (C) 2012 Jason Baron <jbaron@redhat.com>
      8  *
      9  * This is based on acpi.c.
     10  *
     11  * This library is free software; you can redistribute it and/or
     12  * modify it under the terms of the GNU Lesser General Public
     13  * License version 2.1 as published by the Free Software Foundation.
     14  *
     15  * This library is distributed in the hope that it will be useful,
     16  * but WITHOUT ANY WARRANTY; without even the implied warranty of
     17  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
     18  * Lesser General Public License for more details.
     19  *
     20  * You should have received a copy of the GNU Lesser General Public
     21  * License along with this library; if not, see <http://www.gnu.org/licenses/>
     22  *
     23  * Contributions after 2012-01-13 are licensed under the terms of the
     24  * GNU GPL, version 2 or (at your option) any later version.
     25  */
     26 
     27 #include "qemu/osdep.h"
     28 #include "qapi/error.h"
     29 #include "qapi/visitor.h"
     30 #include "hw/pci/pci.h"
     31 #include "migration/vmstate.h"
     32 #include "qemu/timer.h"
     33 #include "hw/core/cpu.h"
     34 #include "sysemu/reset.h"
     35 #include "sysemu/runstate.h"
     36 #include "hw/acpi/acpi.h"
     37 #include "hw/acpi/tco.h"
     38 
     39 #include "hw/i386/ich9.h"
     40 #include "hw/mem/pc-dimm.h"
     41 #include "hw/mem/nvdimm.h"
     42 
     43 //#define DEBUG
     44 
     45 #ifdef DEBUG
     46 #define ICH9_DEBUG(fmt, ...) \
     47 do { printf("%s "fmt, __func__, ## __VA_ARGS__); } while (0)
     48 #else
     49 #define ICH9_DEBUG(fmt, ...)    do { } while (0)
     50 #endif
     51 
     52 static void ich9_pm_update_sci_fn(ACPIREGS *regs)
     53 {
     54     ICH9LPCPMRegs *pm = container_of(regs, ICH9LPCPMRegs, acpi_regs);
     55     acpi_update_sci(&pm->acpi_regs, pm->irq);
     56 }
     57 
     58 static uint64_t ich9_gpe_readb(void *opaque, hwaddr addr, unsigned width)
     59 {
     60     ICH9LPCPMRegs *pm = opaque;
     61     return acpi_gpe_ioport_readb(&pm->acpi_regs, addr);
     62 }
     63 
     64 static void ich9_gpe_writeb(void *opaque, hwaddr addr, uint64_t val,
     65                             unsigned width)
     66 {
     67     ICH9LPCPMRegs *pm = opaque;
     68     acpi_gpe_ioport_writeb(&pm->acpi_regs, addr, val);
     69     acpi_update_sci(&pm->acpi_regs, pm->irq);
     70 }
     71 
     72 static const MemoryRegionOps ich9_gpe_ops = {
     73     .read = ich9_gpe_readb,
     74     .write = ich9_gpe_writeb,
     75     .valid.min_access_size = 1,
     76     .valid.max_access_size = 4,
     77     .impl.min_access_size = 1,
     78     .impl.max_access_size = 1,
     79     .endianness = DEVICE_LITTLE_ENDIAN,
     80 };
     81 
     82 static uint64_t ich9_smi_readl(void *opaque, hwaddr addr, unsigned width)
     83 {
     84     ICH9LPCPMRegs *pm = opaque;
     85     switch (addr) {
     86     case 0:
     87         return pm->smi_en;
     88     case 4:
     89         return pm->smi_sts;
     90     default:
     91         return 0;
     92     }
     93 }
     94 
     95 static void ich9_smi_writel(void *opaque, hwaddr addr, uint64_t val,
     96                             unsigned width)
     97 {
     98     ICH9LPCPMRegs *pm = opaque;
     99     TCOIORegs *tr = &pm->tco_regs;
    100     uint64_t tco_en;
    101 
    102     switch (addr) {
    103     case 0:
    104         tco_en = pm->smi_en & ICH9_PMIO_SMI_EN_TCO_EN;
    105         /* once TCO_LOCK bit is set, TCO_EN bit cannot be overwritten */
    106         if (tr->tco.cnt1 & TCO_LOCK) {
    107             val = (val & ~ICH9_PMIO_SMI_EN_TCO_EN) | tco_en;
    108         }
    109         pm->smi_en &= ~pm->smi_en_wmask;
    110         pm->smi_en |= (val & pm->smi_en_wmask);
    111         break;
    112     }
    113 }
    114 
    115 static const MemoryRegionOps ich9_smi_ops = {
    116     .read = ich9_smi_readl,
    117     .write = ich9_smi_writel,
    118     .valid.min_access_size = 4,
    119     .valid.max_access_size = 4,
    120     .endianness = DEVICE_LITTLE_ENDIAN,
    121 };
    122 
    123 void ich9_pm_iospace_update(ICH9LPCPMRegs *pm, uint32_t pm_io_base)
    124 {
    125     ICH9_DEBUG("to 0x%x\n", pm_io_base);
    126 
    127     assert((pm_io_base & ICH9_PMIO_MASK) == 0);
    128 
    129     pm->pm_io_base = pm_io_base;
    130     memory_region_transaction_begin();
    131     memory_region_set_enabled(&pm->io, pm->pm_io_base != 0);
    132     memory_region_set_address(&pm->io, pm->pm_io_base);
    133     memory_region_transaction_commit();
    134 }
    135 
    136 static int ich9_pm_post_load(void *opaque, int version_id)
    137 {
    138     ICH9LPCPMRegs *pm = opaque;
    139     uint32_t pm_io_base = pm->pm_io_base;
    140     pm->pm_io_base = 0;
    141     ich9_pm_iospace_update(pm, pm_io_base);
    142     return 0;
    143 }
    144 
    145 #define VMSTATE_GPE_ARRAY(_field, _state)                            \
    146  {                                                                   \
    147      .name       = (stringify(_field)),                              \
    148      .version_id = 0,                                                \
    149      .num        = ICH9_PMIO_GPE0_LEN,                               \
    150      .info       = &vmstate_info_uint8,                              \
    151      .size       = sizeof(uint8_t),                                  \
    152      .flags      = VMS_ARRAY | VMS_POINTER,                          \
    153      .offset     = vmstate_offset_pointer(_state, _field, uint8_t),  \
    154  }
    155 
    156 static bool vmstate_test_use_memhp(void *opaque)
    157 {
    158     ICH9LPCPMRegs *s = opaque;
    159     return s->acpi_memory_hotplug.is_enabled;
    160 }
    161 
    162 static const VMStateDescription vmstate_memhp_state = {
    163     .name = "ich9_pm/memhp",
    164     .version_id = 1,
    165     .minimum_version_id = 1,
    166     .needed = vmstate_test_use_memhp,
    167     .fields      = (VMStateField[]) {
    168         VMSTATE_MEMORY_HOTPLUG(acpi_memory_hotplug, ICH9LPCPMRegs),
    169         VMSTATE_END_OF_LIST()
    170     }
    171 };
    172 
    173 static bool vmstate_test_use_tco(void *opaque)
    174 {
    175     ICH9LPCPMRegs *s = opaque;
    176     return s->enable_tco;
    177 }
    178 
    179 static const VMStateDescription vmstate_tco_io_state = {
    180     .name = "ich9_pm/tco",
    181     .version_id = 1,
    182     .minimum_version_id = 1,
    183     .needed = vmstate_test_use_tco,
    184     .fields      = (VMStateField[]) {
    185         VMSTATE_STRUCT(tco_regs, ICH9LPCPMRegs, 1, vmstate_tco_io_sts,
    186                        TCOIORegs),
    187         VMSTATE_END_OF_LIST()
    188     }
    189 };
    190 
    191 static bool vmstate_test_use_cpuhp(void *opaque)
    192 {
    193     ICH9LPCPMRegs *s = opaque;
    194     return !s->cpu_hotplug_legacy;
    195 }
    196 
    197 static int vmstate_cpuhp_pre_load(void *opaque)
    198 {
    199     ICH9LPCPMRegs *s = opaque;
    200     Object *obj = OBJECT(s->gpe_cpu.device);
    201     object_property_set_bool(obj, "cpu-hotplug-legacy", false, &error_abort);
    202     return 0;
    203 }
    204 
    205 static const VMStateDescription vmstate_cpuhp_state = {
    206     .name = "ich9_pm/cpuhp",
    207     .version_id = 1,
    208     .minimum_version_id = 1,
    209     .needed = vmstate_test_use_cpuhp,
    210     .pre_load = vmstate_cpuhp_pre_load,
    211     .fields      = (VMStateField[]) {
    212         VMSTATE_CPU_HOTPLUG(cpuhp_state, ICH9LPCPMRegs),
    213         VMSTATE_END_OF_LIST()
    214     }
    215 };
    216 
    217 static bool vmstate_test_use_pcihp(void *opaque)
    218 {
    219     ICH9LPCPMRegs *s = opaque;
    220 
    221     return s->use_acpi_hotplug_bridge;
    222 }
    223 
    224 static const VMStateDescription vmstate_pcihp_state = {
    225     .name = "ich9_pm/pcihp",
    226     .version_id = 1,
    227     .minimum_version_id = 1,
    228     .needed = vmstate_test_use_pcihp,
    229     .fields      = (VMStateField[]) {
    230         VMSTATE_PCI_HOTPLUG(acpi_pci_hotplug,
    231                             ICH9LPCPMRegs,
    232                             NULL, NULL),
    233         VMSTATE_END_OF_LIST()
    234     }
    235 };
    236 
    237 const VMStateDescription vmstate_ich9_pm = {
    238     .name = "ich9_pm",
    239     .version_id = 1,
    240     .minimum_version_id = 1,
    241     .post_load = ich9_pm_post_load,
    242     .fields = (VMStateField[]) {
    243         VMSTATE_UINT16(acpi_regs.pm1.evt.sts, ICH9LPCPMRegs),
    244         VMSTATE_UINT16(acpi_regs.pm1.evt.en, ICH9LPCPMRegs),
    245         VMSTATE_UINT16(acpi_regs.pm1.cnt.cnt, ICH9LPCPMRegs),
    246         VMSTATE_TIMER_PTR(acpi_regs.tmr.timer, ICH9LPCPMRegs),
    247         VMSTATE_INT64(acpi_regs.tmr.overflow_time, ICH9LPCPMRegs),
    248         VMSTATE_GPE_ARRAY(acpi_regs.gpe.sts, ICH9LPCPMRegs),
    249         VMSTATE_GPE_ARRAY(acpi_regs.gpe.en, ICH9LPCPMRegs),
    250         VMSTATE_UINT32(smi_en, ICH9LPCPMRegs),
    251         VMSTATE_UINT32(smi_sts, ICH9LPCPMRegs),
    252         VMSTATE_END_OF_LIST()
    253     },
    254     .subsections = (const VMStateDescription*[]) {
    255         &vmstate_memhp_state,
    256         &vmstate_tco_io_state,
    257         &vmstate_cpuhp_state,
    258         &vmstate_pcihp_state,
    259         NULL
    260     }
    261 };
    262 
    263 static void pm_reset(void *opaque)
    264 {
    265     ICH9LPCPMRegs *pm = opaque;
    266     ich9_pm_iospace_update(pm, 0);
    267 
    268     acpi_pm1_evt_reset(&pm->acpi_regs);
    269     acpi_pm1_cnt_reset(&pm->acpi_regs);
    270     acpi_pm_tmr_reset(&pm->acpi_regs);
    271     acpi_gpe_reset(&pm->acpi_regs);
    272 
    273     pm->smi_en = 0;
    274     if (!pm->smm_enabled) {
    275         /* Mark SMM as already inited to prevent SMM from running. */
    276         pm->smi_en |= ICH9_PMIO_SMI_EN_APMC_EN;
    277     }
    278     pm->smi_en_wmask = ~0;
    279 
    280     if (pm->use_acpi_hotplug_bridge) {
    281         acpi_pcihp_reset(&pm->acpi_pci_hotplug, true);
    282     }
    283 
    284     acpi_update_sci(&pm->acpi_regs, pm->irq);
    285 }
    286 
    287 static void pm_powerdown_req(Notifier *n, void *opaque)
    288 {
    289     ICH9LPCPMRegs *pm = container_of(n, ICH9LPCPMRegs, powerdown_notifier);
    290 
    291     acpi_pm1_evt_power_down(&pm->acpi_regs);
    292 }
    293 
    294 void ich9_pm_init(PCIDevice *lpc_pci, ICH9LPCPMRegs *pm,
    295                   bool smm_enabled,
    296                   qemu_irq sci_irq)
    297 {
    298     memory_region_init(&pm->io, OBJECT(lpc_pci), "ich9-pm", ICH9_PMIO_SIZE);
    299     memory_region_set_enabled(&pm->io, false);
    300     memory_region_add_subregion(pci_address_space_io(lpc_pci),
    301                                 0, &pm->io);
    302 
    303     acpi_pm_tmr_init(&pm->acpi_regs, ich9_pm_update_sci_fn, &pm->io);
    304     acpi_pm1_evt_init(&pm->acpi_regs, ich9_pm_update_sci_fn, &pm->io);
    305     acpi_pm1_cnt_init(&pm->acpi_regs, &pm->io, pm->disable_s3, pm->disable_s4,
    306                       pm->s4_val, !pm->smm_compat && !smm_enabled);
    307 
    308     acpi_gpe_init(&pm->acpi_regs, ICH9_PMIO_GPE0_LEN);
    309     memory_region_init_io(&pm->io_gpe, OBJECT(lpc_pci), &ich9_gpe_ops, pm,
    310                           "acpi-gpe0", ICH9_PMIO_GPE0_LEN);
    311     memory_region_add_subregion(&pm->io, ICH9_PMIO_GPE0_STS, &pm->io_gpe);
    312 
    313     memory_region_init_io(&pm->io_smi, OBJECT(lpc_pci), &ich9_smi_ops, pm,
    314                           "acpi-smi", 8);
    315     memory_region_add_subregion(&pm->io, ICH9_PMIO_SMI_EN, &pm->io_smi);
    316 
    317     pm->smm_enabled = smm_enabled;
    318 
    319     pm->enable_tco = true;
    320     acpi_pm_tco_init(&pm->tco_regs, &pm->io);
    321 
    322     if (pm->use_acpi_hotplug_bridge) {
    323         acpi_pcihp_init(OBJECT(lpc_pci),
    324                         &pm->acpi_pci_hotplug,
    325                         pci_get_bus(lpc_pci),
    326                         pci_address_space_io(lpc_pci),
    327                         true,
    328                         ACPI_PCIHP_ADDR_ICH9);
    329 
    330         qbus_set_hotplug_handler(BUS(pci_get_bus(lpc_pci)),
    331                                  OBJECT(lpc_pci));
    332     }
    333 
    334     pm->irq = sci_irq;
    335     qemu_register_reset(pm_reset, pm);
    336     pm->powerdown_notifier.notify = pm_powerdown_req;
    337     qemu_register_powerdown_notifier(&pm->powerdown_notifier);
    338 
    339     legacy_acpi_cpu_hotplug_init(pci_address_space_io(lpc_pci),
    340         OBJECT(lpc_pci), &pm->gpe_cpu, ICH9_CPU_HOTPLUG_IO_BASE);
    341 
    342     if (pm->acpi_memory_hotplug.is_enabled) {
    343         acpi_memory_hotplug_init(pci_address_space_io(lpc_pci), OBJECT(lpc_pci),
    344                                  &pm->acpi_memory_hotplug,
    345                                  ACPI_MEMORY_HOTPLUG_BASE);
    346     }
    347 }
    348 
    349 static void ich9_pm_get_gpe0_blk(Object *obj, Visitor *v, const char *name,
    350                                  void *opaque, Error **errp)
    351 {
    352     ICH9LPCPMRegs *pm = opaque;
    353     uint32_t value = pm->pm_io_base + ICH9_PMIO_GPE0_STS;
    354 
    355     visit_type_uint32(v, name, &value, errp);
    356 }
    357 
    358 static bool ich9_pm_get_memory_hotplug_support(Object *obj, Error **errp)
    359 {
    360     ICH9LPCState *s = ICH9_LPC_DEVICE(obj);
    361 
    362     return s->pm.acpi_memory_hotplug.is_enabled;
    363 }
    364 
    365 static void ich9_pm_set_memory_hotplug_support(Object *obj, bool value,
    366                                                Error **errp)
    367 {
    368     ICH9LPCState *s = ICH9_LPC_DEVICE(obj);
    369 
    370     s->pm.acpi_memory_hotplug.is_enabled = value;
    371 }
    372 
    373 static bool ich9_pm_get_cpu_hotplug_legacy(Object *obj, Error **errp)
    374 {
    375     ICH9LPCState *s = ICH9_LPC_DEVICE(obj);
    376 
    377     return s->pm.cpu_hotplug_legacy;
    378 }
    379 
    380 static void ich9_pm_set_cpu_hotplug_legacy(Object *obj, bool value,
    381                                            Error **errp)
    382 {
    383     ICH9LPCState *s = ICH9_LPC_DEVICE(obj);
    384 
    385     assert(!value);
    386     if (s->pm.cpu_hotplug_legacy && value == false) {
    387         acpi_switch_to_modern_cphp(&s->pm.gpe_cpu, &s->pm.cpuhp_state,
    388                                    ICH9_CPU_HOTPLUG_IO_BASE);
    389     }
    390     s->pm.cpu_hotplug_legacy = value;
    391 }
    392 
    393 static bool ich9_pm_get_enable_tco(Object *obj, Error **errp)
    394 {
    395     ICH9LPCState *s = ICH9_LPC_DEVICE(obj);
    396     return s->pm.enable_tco;
    397 }
    398 
    399 static void ich9_pm_set_enable_tco(Object *obj, bool value, Error **errp)
    400 {
    401     ICH9LPCState *s = ICH9_LPC_DEVICE(obj);
    402     s->pm.enable_tco = value;
    403 }
    404 
    405 static bool ich9_pm_get_acpi_pci_hotplug(Object *obj, Error **errp)
    406 {
    407     ICH9LPCState *s = ICH9_LPC_DEVICE(obj);
    408 
    409     return s->pm.use_acpi_hotplug_bridge;
    410 }
    411 
    412 static void ich9_pm_set_acpi_pci_hotplug(Object *obj, bool value, Error **errp)
    413 {
    414     ICH9LPCState *s = ICH9_LPC_DEVICE(obj);
    415 
    416     s->pm.use_acpi_hotplug_bridge = value;
    417 }
    418 
    419 static bool ich9_pm_get_keep_pci_slot_hpc(Object *obj, Error **errp)
    420 {
    421     ICH9LPCState *s = ICH9_LPC_DEVICE(obj);
    422 
    423     return s->pm.keep_pci_slot_hpc;
    424 }
    425 
    426 static void ich9_pm_set_keep_pci_slot_hpc(Object *obj, bool value, Error **errp)
    427 {
    428     ICH9LPCState *s = ICH9_LPC_DEVICE(obj);
    429 
    430     s->pm.keep_pci_slot_hpc = value;
    431 }
    432 
    433 void ich9_pm_add_properties(Object *obj, ICH9LPCPMRegs *pm)
    434 {
    435     static const uint32_t gpe0_len = ICH9_PMIO_GPE0_LEN;
    436     pm->acpi_memory_hotplug.is_enabled = true;
    437     pm->cpu_hotplug_legacy = true;
    438     pm->disable_s3 = 0;
    439     pm->disable_s4 = 0;
    440     pm->s4_val = 2;
    441     pm->use_acpi_hotplug_bridge = true;
    442     pm->keep_pci_slot_hpc = true;
    443 
    444     object_property_add_uint32_ptr(obj, ACPI_PM_PROP_PM_IO_BASE,
    445                                    &pm->pm_io_base, OBJ_PROP_FLAG_READ);
    446     object_property_add(obj, ACPI_PM_PROP_GPE0_BLK, "uint32",
    447                         ich9_pm_get_gpe0_blk,
    448                         NULL, NULL, pm);
    449     object_property_add_uint32_ptr(obj, ACPI_PM_PROP_GPE0_BLK_LEN,
    450                                    &gpe0_len, OBJ_PROP_FLAG_READ);
    451     object_property_add_bool(obj, "memory-hotplug-support",
    452                              ich9_pm_get_memory_hotplug_support,
    453                              ich9_pm_set_memory_hotplug_support);
    454     object_property_add_bool(obj, "cpu-hotplug-legacy",
    455                              ich9_pm_get_cpu_hotplug_legacy,
    456                              ich9_pm_set_cpu_hotplug_legacy);
    457     object_property_add_uint8_ptr(obj, ACPI_PM_PROP_S3_DISABLED,
    458                                   &pm->disable_s3, OBJ_PROP_FLAG_READWRITE);
    459     object_property_add_uint8_ptr(obj, ACPI_PM_PROP_S4_DISABLED,
    460                                   &pm->disable_s4, OBJ_PROP_FLAG_READWRITE);
    461     object_property_add_uint8_ptr(obj, ACPI_PM_PROP_S4_VAL,
    462                                   &pm->s4_val, OBJ_PROP_FLAG_READWRITE);
    463     object_property_add_bool(obj, ACPI_PM_PROP_TCO_ENABLED,
    464                              ich9_pm_get_enable_tco,
    465                              ich9_pm_set_enable_tco);
    466     object_property_add_bool(obj, ACPI_PM_PROP_ACPI_PCIHP_BRIDGE,
    467                              ich9_pm_get_acpi_pci_hotplug,
    468                              ich9_pm_set_acpi_pci_hotplug);
    469     object_property_add_bool(obj, "x-keep-pci-slot-hpc",
    470                              ich9_pm_get_keep_pci_slot_hpc,
    471                              ich9_pm_set_keep_pci_slot_hpc);
    472 }
    473 
    474 void ich9_pm_device_pre_plug_cb(HotplugHandler *hotplug_dev, DeviceState *dev,
    475                                 Error **errp)
    476 {
    477     ICH9LPCState *lpc = ICH9_LPC_DEVICE(hotplug_dev);
    478 
    479     if (object_dynamic_cast(OBJECT(dev), TYPE_PCI_DEVICE)) {
    480         acpi_pcihp_device_pre_plug_cb(hotplug_dev, dev, errp);
    481         return;
    482     }
    483 
    484     if (object_dynamic_cast(OBJECT(dev), TYPE_PC_DIMM) &&
    485         !lpc->pm.acpi_memory_hotplug.is_enabled) {
    486         error_setg(errp,
    487                    "memory hotplug is not enabled: %s.memory-hotplug-support "
    488                    "is not set", object_get_typename(OBJECT(lpc)));
    489     } else if (object_dynamic_cast(OBJECT(dev), TYPE_CPU)) {
    490         uint64_t negotiated = lpc->smi_negotiated_features;
    491 
    492         if (negotiated & BIT_ULL(ICH9_LPC_SMI_F_BROADCAST_BIT) &&
    493             !(negotiated & BIT_ULL(ICH9_LPC_SMI_F_CPU_HOTPLUG_BIT))) {
    494             error_setg(errp, "cpu hotplug with SMI wasn't enabled by firmware");
    495             error_append_hint(errp, "update machine type to newer than 5.1 "
    496                 "and firmware that suppors CPU hotplug with SMM");
    497         }
    498     }
    499 }
    500 
    501 void ich9_pm_device_plug_cb(HotplugHandler *hotplug_dev, DeviceState *dev,
    502                             Error **errp)
    503 {
    504     ICH9LPCState *lpc = ICH9_LPC_DEVICE(hotplug_dev);
    505 
    506     if (object_dynamic_cast(OBJECT(dev), TYPE_PC_DIMM)) {
    507         if (object_dynamic_cast(OBJECT(dev), TYPE_NVDIMM)) {
    508             nvdimm_acpi_plug_cb(hotplug_dev, dev);
    509         } else {
    510             acpi_memory_plug_cb(hotplug_dev, &lpc->pm.acpi_memory_hotplug,
    511                                 dev, errp);
    512         }
    513     } else if (object_dynamic_cast(OBJECT(dev), TYPE_CPU)) {
    514         if (lpc->pm.cpu_hotplug_legacy) {
    515             legacy_acpi_cpu_plug_cb(hotplug_dev, &lpc->pm.gpe_cpu, dev, errp);
    516         } else {
    517             acpi_cpu_plug_cb(hotplug_dev, &lpc->pm.cpuhp_state, dev, errp);
    518         }
    519     } else if (object_dynamic_cast(OBJECT(dev), TYPE_PCI_DEVICE)) {
    520         acpi_pcihp_device_plug_cb(hotplug_dev, &lpc->pm.acpi_pci_hotplug,
    521                                   dev, errp);
    522     } else {
    523         error_setg(errp, "acpi: device plug request for not supported device"
    524                    " type: %s", object_get_typename(OBJECT(dev)));
    525     }
    526 }
    527 
    528 void ich9_pm_device_unplug_request_cb(HotplugHandler *hotplug_dev,
    529                                       DeviceState *dev, Error **errp)
    530 {
    531     ICH9LPCState *lpc = ICH9_LPC_DEVICE(hotplug_dev);
    532 
    533     if (lpc->pm.acpi_memory_hotplug.is_enabled &&
    534         object_dynamic_cast(OBJECT(dev), TYPE_PC_DIMM)) {
    535         acpi_memory_unplug_request_cb(hotplug_dev,
    536                                       &lpc->pm.acpi_memory_hotplug, dev,
    537                                       errp);
    538     } else if (object_dynamic_cast(OBJECT(dev), TYPE_CPU) &&
    539                !lpc->pm.cpu_hotplug_legacy) {
    540         uint64_t negotiated = lpc->smi_negotiated_features;
    541 
    542         if (negotiated & BIT_ULL(ICH9_LPC_SMI_F_BROADCAST_BIT) &&
    543             !(negotiated & BIT_ULL(ICH9_LPC_SMI_F_CPU_HOT_UNPLUG_BIT))) {
    544             error_setg(errp, "cpu hot-unplug with SMI wasn't enabled "
    545                              "by firmware");
    546             error_append_hint(errp, "update machine type to a version having "
    547                                     "x-smi-cpu-hotunplug=on and firmware that "
    548                                     "supports CPU hot-unplug with SMM");
    549             return;
    550         }
    551 
    552         acpi_cpu_unplug_request_cb(hotplug_dev, &lpc->pm.cpuhp_state,
    553                                    dev, errp);
    554     } else if (object_dynamic_cast(OBJECT(dev), TYPE_PCI_DEVICE)) {
    555         acpi_pcihp_device_unplug_request_cb(hotplug_dev,
    556                                             &lpc->pm.acpi_pci_hotplug,
    557                                             dev, errp);
    558     } else {
    559         error_setg(errp, "acpi: device unplug request for not supported device"
    560                    " type: %s", object_get_typename(OBJECT(dev)));
    561     }
    562 }
    563 
    564 void ich9_pm_device_unplug_cb(HotplugHandler *hotplug_dev, DeviceState *dev,
    565                               Error **errp)
    566 {
    567     ICH9LPCState *lpc = ICH9_LPC_DEVICE(hotplug_dev);
    568 
    569     if (lpc->pm.acpi_memory_hotplug.is_enabled &&
    570         object_dynamic_cast(OBJECT(dev), TYPE_PC_DIMM)) {
    571         acpi_memory_unplug_cb(&lpc->pm.acpi_memory_hotplug, dev, errp);
    572     } else if (object_dynamic_cast(OBJECT(dev), TYPE_CPU) &&
    573                !lpc->pm.cpu_hotplug_legacy) {
    574         acpi_cpu_unplug_cb(&lpc->pm.cpuhp_state, dev, errp);
    575     } else if (object_dynamic_cast(OBJECT(dev), TYPE_PCI_DEVICE)) {
    576         acpi_pcihp_device_unplug_cb(hotplug_dev, &lpc->pm.acpi_pci_hotplug,
    577                                     dev, errp);
    578     } else {
    579         error_setg(errp, "acpi: device unplug for not supported device"
    580                    " type: %s", object_get_typename(OBJECT(dev)));
    581     }
    582 }
    583 
    584 void ich9_pm_ospm_status(AcpiDeviceIf *adev, ACPIOSTInfoList ***list)
    585 {
    586     ICH9LPCState *s = ICH9_LPC_DEVICE(adev);
    587 
    588     acpi_memory_ospm_status(&s->pm.acpi_memory_hotplug, list);
    589     if (!s->pm.cpu_hotplug_legacy) {
    590         acpi_cpu_ospm_status(&s->pm.cpuhp_state, list);
    591     }
    592 }