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