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