xref: /openbmc/qemu/hw/acpi/generic_event_device.c (revision e452053097371880910c744a5d42ae2df058a4a7)
1 /*
2  *
3  * Copyright (c) 2018 Intel Corporation
4  * Copyright (c) 2019 Huawei Technologies R & D (UK) Ltd
5  * Written by Samuel Ortiz, Shameer Kolothum
6  *
7  * This program is free software; you can redistribute it and/or modify it
8  * under the terms and conditions of the GNU General Public License,
9  * version 2 or later, as published by the Free Software Foundation.
10  */
11 
12 #include "qemu/osdep.h"
13 #include "qapi/error.h"
14 #include "hw/acpi/acpi.h"
15 #include "hw/acpi/pcihp.h"
16 #include "hw/acpi/generic_event_device.h"
17 #include "hw/pci/pci.h"
18 #include "hw/irq.h"
19 #include "hw/mem/pc-dimm.h"
20 #include "hw/mem/nvdimm.h"
21 #include "hw/pci/pci_device.h"
22 #include "hw/qdev-properties.h"
23 #include "migration/vmstate.h"
24 #include "qemu/error-report.h"
25 #include "system/runstate.h"
26 
27 static const uint32_t ged_supported_events[] = {
28     ACPI_GED_MEM_HOTPLUG_EVT,
29     ACPI_GED_PWR_DOWN_EVT,
30     ACPI_GED_NVDIMM_HOTPLUG_EVT,
31     ACPI_GED_CPU_HOTPLUG_EVT,
32     ACPI_GED_PCI_HOTPLUG_EVT,
33 };
34 
35 /*
36  * The ACPI Generic Event Device (GED) is a hardware-reduced specific
37  * device[ACPI v6.1 Section 5.6.9] that handles all platform events,
38  * including the hotplug ones. Platforms need to specify their own
39  * GED Event bitmap to describe what kind of events they want to support
40  * through GED. This routine uses a single interrupt for the GED device,
41  * relying on IO memory region to communicate the type of device
42  * affected by the interrupt. This way, we can support up to 32 events
43  * with a unique interrupt.
44  */
build_ged_aml(Aml * table,const char * name,HotplugHandler * hotplug_dev,uint32_t ged_irq,AmlRegionSpace rs,hwaddr ged_base)45 void build_ged_aml(Aml *table, const char *name, HotplugHandler *hotplug_dev,
46                    uint32_t ged_irq, AmlRegionSpace rs, hwaddr ged_base)
47 {
48     AcpiGedState *s = ACPI_GED(hotplug_dev);
49     Aml *crs = aml_resource_template();
50     Aml *evt, *field;
51     Aml *dev = aml_device("%s", name);
52     Aml *evt_sel = aml_local(0);
53     Aml *esel = aml_name(AML_GED_EVT_SEL);
54 
55     /* _CRS interrupt */
56     aml_append(crs, aml_interrupt(AML_CONSUMER, AML_EDGE, AML_ACTIVE_HIGH,
57                                   AML_EXCLUSIVE, &ged_irq, 1));
58 
59     aml_append(dev, aml_name_decl("_HID", aml_string("ACPI0013")));
60     aml_append(dev, aml_name_decl("_UID", aml_string(GED_DEVICE)));
61     aml_append(dev, aml_name_decl("_CRS", crs));
62 
63     /* Append IO region */
64     aml_append(dev, aml_operation_region(AML_GED_EVT_REG, rs,
65                aml_int(ged_base + ACPI_GED_EVT_SEL_OFFSET),
66                ACPI_GED_EVT_SEL_LEN));
67     field = aml_field(AML_GED_EVT_REG, AML_DWORD_ACC, AML_NOLOCK,
68                       AML_WRITE_AS_ZEROS);
69     aml_append(field, aml_named_field(AML_GED_EVT_SEL,
70                                       ACPI_GED_EVT_SEL_LEN * BITS_PER_BYTE));
71     aml_append(dev, field);
72 
73     /*
74      * For each GED event we:
75      * - Add a conditional block for each event, inside a loop.
76      * - Call a method for each supported GED event type.
77      *
78      * The resulting ASL code looks like:
79      *
80      * Local0 = ESEL
81      * If ((Local0 & One) == One)
82      * {
83      *     MethodEvent0()
84      * }
85      *
86      * If ((Local0 & 0x2) == 0x2)
87      * {
88      *     MethodEvent1()
89      * }
90      * ...
91      */
92     evt = aml_method("_EVT", 1, AML_SERIALIZED);
93     {
94         Aml *if_ctx;
95         uint32_t i;
96         uint32_t ged_events = ctpop32(s->ged_event_bitmap);
97 
98         /* Local0 = ESEL */
99         aml_append(evt, aml_store(esel, evt_sel));
100 
101         for (i = 0; i < ARRAY_SIZE(ged_supported_events) && ged_events; i++) {
102             uint32_t event = s->ged_event_bitmap & ged_supported_events[i];
103 
104             if (!event) {
105                 continue;
106             }
107 
108             if_ctx = aml_if(aml_equal(aml_and(evt_sel, aml_int(event), NULL),
109                                       aml_int(event)));
110             switch (event) {
111             case ACPI_GED_MEM_HOTPLUG_EVT:
112                 aml_append(if_ctx, aml_call0(MEMORY_DEVICES_CONTAINER "."
113                                              MEMORY_SLOT_SCAN_METHOD));
114                 break;
115             case ACPI_GED_CPU_HOTPLUG_EVT:
116                 aml_append(if_ctx, aml_call0(AML_GED_EVT_CPU_SCAN_METHOD));
117                 break;
118             case ACPI_GED_PWR_DOWN_EVT:
119                 aml_append(if_ctx,
120                            aml_notify(aml_name(ACPI_POWER_BUTTON_DEVICE),
121                                       aml_int(0x80)));
122                 break;
123             case ACPI_GED_NVDIMM_HOTPLUG_EVT:
124                 aml_append(if_ctx,
125                            aml_notify(aml_name("\\_SB.NVDR"),
126                                       aml_int(0x80)));
127                 break;
128             case ACPI_GED_PCI_HOTPLUG_EVT:
129                 aml_append(if_ctx,
130                            aml_acquire(aml_name("\\_SB.PCI0.BLCK"), 0xFFFF));
131                 aml_append(if_ctx, aml_call0("\\_SB.PCI0.PCNT"));
132                 aml_append(if_ctx, aml_release(aml_name("\\_SB.PCI0.BLCK")));
133                 break;
134             default:
135                 /*
136                  * Please make sure all the events in ged_supported_events[]
137                  * are handled above.
138                  */
139                 g_assert_not_reached();
140             }
141 
142             aml_append(evt, if_ctx);
143             ged_events--;
144         }
145 
146         if (ged_events) {
147             error_report("Unsupported events specified");
148             abort();
149         }
150     }
151 
152     /* Append _EVT method */
153     aml_append(dev, evt);
154 
155     aml_append(table, dev);
156 }
157 
acpi_dsdt_add_power_button(Aml * scope)158 void acpi_dsdt_add_power_button(Aml *scope)
159 {
160     Aml *dev = aml_device(ACPI_POWER_BUTTON_DEVICE);
161     aml_append(dev, aml_name_decl("_HID", aml_string("PNP0C0C")));
162     aml_append(dev, aml_name_decl("_UID", aml_int(0)));
163     aml_append(scope, dev);
164 }
165 
166 /* Memory read by the GED _EVT AML dynamic method */
ged_evt_read(void * opaque,hwaddr addr,unsigned size)167 static uint64_t ged_evt_read(void *opaque, hwaddr addr, unsigned size)
168 {
169     uint64_t val = 0;
170     GEDState *ged_st = opaque;
171 
172     switch (addr) {
173     case ACPI_GED_EVT_SEL_OFFSET:
174         /* Read the selector value and reset it */
175         val = ged_st->sel;
176         ged_st->sel = 0;
177         break;
178     default:
179         break;
180     }
181 
182     return val;
183 }
184 
185 /* Nothing is expected to be written to the GED memory region */
ged_evt_write(void * opaque,hwaddr addr,uint64_t data,unsigned int size)186 static void ged_evt_write(void *opaque, hwaddr addr, uint64_t data,
187                           unsigned int size)
188 {
189 }
190 
191 static const MemoryRegionOps ged_evt_ops = {
192     .read = ged_evt_read,
193     .write = ged_evt_write,
194     .endianness = DEVICE_LITTLE_ENDIAN,
195     .valid = {
196         .min_access_size = 4,
197         .max_access_size = 4,
198     },
199 };
200 
ged_regs_read(void * opaque,hwaddr addr,unsigned size)201 static uint64_t ged_regs_read(void *opaque, hwaddr addr, unsigned size)
202 {
203     return 0;
204 }
205 
ged_regs_write(void * opaque,hwaddr addr,uint64_t data,unsigned int size)206 static void ged_regs_write(void *opaque, hwaddr addr, uint64_t data,
207                            unsigned int size)
208 {
209     bool slp_en;
210     int slp_typ;
211 
212     switch (addr) {
213     case ACPI_GED_REG_SLEEP_CTL:
214         slp_typ = (data >> ACPI_GED_SLP_TYP_POS) & ACPI_GED_SLP_TYP_MASK;
215         slp_en  = !!(data & ACPI_GED_SLP_EN);
216         if (slp_en && slp_typ == ACPI_GED_SLP_TYP_S5) {
217             qemu_system_shutdown_request(SHUTDOWN_CAUSE_GUEST_SHUTDOWN);
218         }
219         return;
220     case ACPI_GED_REG_SLEEP_STS:
221         return;
222     case ACPI_GED_REG_RESET:
223         if (data == ACPI_GED_RESET_VALUE) {
224             qemu_system_reset_request(SHUTDOWN_CAUSE_GUEST_RESET);
225         }
226         return;
227     }
228 }
229 
230 static const MemoryRegionOps ged_regs_ops = {
231     .read = ged_regs_read,
232     .write = ged_regs_write,
233     .endianness = DEVICE_LITTLE_ENDIAN,
234     .valid = {
235         .min_access_size = 1,
236         .max_access_size = 1,
237     },
238 };
239 
acpi_ged_device_pre_plug_cb(HotplugHandler * hotplug_dev,DeviceState * dev,Error ** errp)240 static void acpi_ged_device_pre_plug_cb(HotplugHandler *hotplug_dev,
241                                         DeviceState *dev, Error **errp)
242 {
243     if (object_dynamic_cast(OBJECT(dev), TYPE_PCI_DEVICE)) {
244         acpi_pcihp_device_pre_plug_cb(hotplug_dev, dev, errp);
245     }
246 }
247 
acpi_ged_device_plug_cb(HotplugHandler * hotplug_dev,DeviceState * dev,Error ** errp)248 static void acpi_ged_device_plug_cb(HotplugHandler *hotplug_dev,
249                                     DeviceState *dev, Error **errp)
250 {
251     AcpiGedState *s = ACPI_GED(hotplug_dev);
252 
253     if (object_dynamic_cast(OBJECT(dev), TYPE_PC_DIMM)) {
254         if (object_dynamic_cast(OBJECT(dev), TYPE_NVDIMM)) {
255             nvdimm_acpi_plug_cb(hotplug_dev, dev);
256         } else {
257             acpi_memory_plug_cb(hotplug_dev, &s->memhp_state, dev, errp);
258         }
259     } else if (object_dynamic_cast(OBJECT(dev), TYPE_CPU)) {
260         acpi_cpu_plug_cb(hotplug_dev, &s->cpuhp_state, dev, errp);
261     } else if (object_dynamic_cast(OBJECT(dev), TYPE_PCI_DEVICE)) {
262         acpi_pcihp_device_plug_cb(hotplug_dev, &s->pcihp_state, dev, errp);
263     } else {
264         error_setg(errp, "virt: device plug request for unsupported device"
265                    " type: %s", object_get_typename(OBJECT(dev)));
266     }
267 }
268 
acpi_ged_unplug_request_cb(HotplugHandler * hotplug_dev,DeviceState * dev,Error ** errp)269 static void acpi_ged_unplug_request_cb(HotplugHandler *hotplug_dev,
270                                        DeviceState *dev, Error **errp)
271 {
272     AcpiGedState *s = ACPI_GED(hotplug_dev);
273 
274     if ((object_dynamic_cast(OBJECT(dev), TYPE_PC_DIMM) &&
275                        !(object_dynamic_cast(OBJECT(dev), TYPE_NVDIMM)))) {
276         acpi_memory_unplug_request_cb(hotplug_dev, &s->memhp_state, dev, errp);
277     } else if (object_dynamic_cast(OBJECT(dev), TYPE_CPU)) {
278         acpi_cpu_unplug_request_cb(hotplug_dev, &s->cpuhp_state, dev, errp);
279     } else if (object_dynamic_cast(OBJECT(dev), TYPE_PCI_DEVICE)) {
280         acpi_pcihp_device_unplug_request_cb(hotplug_dev, &s->pcihp_state,
281                                             dev, errp);
282     } else {
283         error_setg(errp, "acpi: device unplug request for unsupported device"
284                    " type: %s", object_get_typename(OBJECT(dev)));
285     }
286 }
287 
acpi_ged_unplug_cb(HotplugHandler * hotplug_dev,DeviceState * dev,Error ** errp)288 static void acpi_ged_unplug_cb(HotplugHandler *hotplug_dev,
289                                DeviceState *dev, Error **errp)
290 {
291     AcpiGedState *s = ACPI_GED(hotplug_dev);
292 
293     if (object_dynamic_cast(OBJECT(dev), TYPE_PC_DIMM)) {
294         acpi_memory_unplug_cb(&s->memhp_state, dev, errp);
295     } else if (object_dynamic_cast(OBJECT(dev), TYPE_CPU)) {
296         acpi_cpu_unplug_cb(&s->cpuhp_state, dev, errp);
297     } else if (object_dynamic_cast(OBJECT(dev), TYPE_PCI_DEVICE)) {
298         acpi_pcihp_device_unplug_cb(hotplug_dev, &s->pcihp_state, dev, errp);
299     } else {
300         error_setg(errp, "acpi: device unplug for unsupported device"
301                    " type: %s", object_get_typename(OBJECT(dev)));
302     }
303 }
304 
acpi_ged_ospm_status(AcpiDeviceIf * adev,ACPIOSTInfoList *** list)305 static void acpi_ged_ospm_status(AcpiDeviceIf *adev, ACPIOSTInfoList ***list)
306 {
307     AcpiGedState *s = ACPI_GED(adev);
308 
309     acpi_memory_ospm_status(&s->memhp_state, list);
310     acpi_cpu_ospm_status(&s->cpuhp_state, list);
311 }
312 
acpi_ged_send_event(AcpiDeviceIf * adev,AcpiEventStatusBits ev)313 static void acpi_ged_send_event(AcpiDeviceIf *adev, AcpiEventStatusBits ev)
314 {
315     AcpiGedState *s = ACPI_GED(adev);
316     GEDState *ged_st = &s->ged_state;
317     uint32_t sel;
318 
319     if (ev & ACPI_MEMORY_HOTPLUG_STATUS) {
320         sel = ACPI_GED_MEM_HOTPLUG_EVT;
321     } else if (ev & ACPI_POWER_DOWN_STATUS) {
322         sel = ACPI_GED_PWR_DOWN_EVT;
323     } else if (ev & ACPI_NVDIMM_HOTPLUG_STATUS) {
324         sel = ACPI_GED_NVDIMM_HOTPLUG_EVT;
325     } else if (ev & ACPI_CPU_HOTPLUG_STATUS) {
326         sel = ACPI_GED_CPU_HOTPLUG_EVT;
327     } else if (ev & ACPI_PCI_HOTPLUG_STATUS) {
328         sel = ACPI_GED_PCI_HOTPLUG_EVT;
329     } else {
330         /* Unknown event. Return without generating interrupt. */
331         warn_report("GED: Unsupported event %d. No irq injected", ev);
332         return;
333     }
334 
335     /*
336      * Set the GED selector field to communicate the event type.
337      * This will be read by GED aml code to select the appropriate
338      * event method.
339      */
340     ged_st->sel |= sel;
341 
342     /* Trigger the event by sending an interrupt to the guest. */
343     qemu_irq_pulse(s->irq);
344 }
345 
346 static const Property acpi_ged_properties[] = {
347     DEFINE_PROP_UINT32("ged-event", AcpiGedState, ged_event_bitmap, 0),
348     DEFINE_PROP_BOOL(ACPI_PM_PROP_ACPI_PCIHP_BRIDGE, AcpiGedState,
349                      pcihp_state.use_acpi_hotplug_bridge, 0),
350     DEFINE_PROP_LINK("bus", AcpiGedState, pcihp_state.root,
351                      TYPE_PCI_BUS, PCIBus *),
352 };
353 
354 static const VMStateDescription vmstate_memhp_state = {
355     .name = "acpi-ged/memhp",
356     .version_id = 1,
357     .minimum_version_id = 1,
358     .fields = (const VMStateField[]) {
359         VMSTATE_MEMORY_HOTPLUG(memhp_state, AcpiGedState),
360         VMSTATE_END_OF_LIST()
361     }
362 };
363 
cpuhp_needed(void * opaque)364 static bool cpuhp_needed(void *opaque)
365 {
366     MachineClass *mc = MACHINE_GET_CLASS(qdev_get_machine());
367 
368     return mc->has_hotpluggable_cpus;
369 }
370 
371 static const VMStateDescription vmstate_cpuhp_state = {
372     .name = "acpi-ged/cpuhp",
373     .version_id = 1,
374     .minimum_version_id = 1,
375     .needed = cpuhp_needed,
376     .fields      = (VMStateField[]) {
377         VMSTATE_CPU_HOTPLUG(cpuhp_state, AcpiGedState),
378         VMSTATE_END_OF_LIST()
379     }
380 };
381 
382 static const VMStateDescription vmstate_ged_state = {
383     .name = "acpi-ged-state",
384     .version_id = 1,
385     .minimum_version_id = 1,
386     .fields = (const VMStateField[]) {
387         VMSTATE_UINT32(sel, GEDState),
388         VMSTATE_END_OF_LIST()
389     }
390 };
391 
392 static const VMStateDescription vmstate_ghes = {
393     .name = "acpi-ghes",
394     .version_id = 1,
395     .minimum_version_id = 1,
396     .fields = (const VMStateField[]) {
397         VMSTATE_UINT64(hw_error_le, AcpiGhesState),
398         VMSTATE_END_OF_LIST()
399     },
400 };
401 
ghes_needed(void * opaque)402 static bool ghes_needed(void *opaque)
403 {
404     AcpiGedState *s = opaque;
405     return s->ghes_state.hw_error_le;
406 }
407 
408 static const VMStateDescription vmstate_ghes_state = {
409     .name = "acpi-ged/ghes",
410     .version_id = 1,
411     .minimum_version_id = 1,
412     .needed = ghes_needed,
413     .fields = (const VMStateField[]) {
414         VMSTATE_STRUCT(ghes_state, AcpiGedState, 1,
415                        vmstate_ghes, AcpiGhesState),
416         VMSTATE_END_OF_LIST()
417     }
418 };
419 
pcihp_needed(void * opaque)420 static bool pcihp_needed(void *opaque)
421 {
422     AcpiGedState *s = opaque;
423     return s->pcihp_state.use_acpi_hotplug_bridge;
424 }
425 
426 static const VMStateDescription vmstate_pcihp_state = {
427     .name = "acpi-ged/pcihp",
428     .version_id = 1,
429     .minimum_version_id = 1,
430     .needed = pcihp_needed,
431     .fields = (const VMStateField[]) {
432         VMSTATE_PCI_HOTPLUG(pcihp_state,
433                             AcpiGedState,
434                             NULL, NULL),
435         VMSTATE_END_OF_LIST()
436     }
437 };
438 
439 static const VMStateDescription vmstate_acpi_ged = {
440     .name = "acpi-ged",
441     .version_id = 1,
442     .minimum_version_id = 1,
443     .fields = (const VMStateField[]) {
444         VMSTATE_STRUCT(ged_state, AcpiGedState, 1, vmstate_ged_state, GEDState),
445         VMSTATE_END_OF_LIST(),
446     },
447     .subsections = (const VMStateDescription * const []) {
448         &vmstate_memhp_state,
449         &vmstate_cpuhp_state,
450         &vmstate_ghes_state,
451         &vmstate_pcihp_state,
452         NULL
453     }
454 };
455 
acpi_ged_realize(DeviceState * dev,Error ** errp)456 static void acpi_ged_realize(DeviceState *dev, Error **errp)
457 {
458     SysBusDevice *sbd = SYS_BUS_DEVICE(dev);
459     AcpiGedState *s = ACPI_GED(dev);
460     AcpiPciHpState *pcihp_state = &s->pcihp_state;
461     uint32_t ged_events;
462     int i;
463 
464     if (pcihp_state->use_acpi_hotplug_bridge) {
465         s->ged_event_bitmap |= ACPI_GED_PCI_HOTPLUG_EVT;
466     }
467     ged_events = ctpop32(s->ged_event_bitmap);
468 
469     for (i = 0; i < ARRAY_SIZE(ged_supported_events) && ged_events; i++) {
470         uint32_t event = s->ged_event_bitmap & ged_supported_events[i];
471 
472         if (!event) {
473             continue;
474         }
475 
476         switch (event) {
477         case ACPI_GED_CPU_HOTPLUG_EVT:
478             /* initialize CPU Hotplug related regions */
479             memory_region_init(&s->container_cpuhp, OBJECT(dev),
480                                 "cpuhp container",
481                                 ACPI_CPU_HOTPLUG_REG_LEN);
482             sysbus_init_mmio(sbd, &s->container_cpuhp);
483             cpu_hotplug_hw_init(&s->container_cpuhp, OBJECT(dev),
484                                 &s->cpuhp_state, 0);
485             break;
486         case ACPI_GED_PCI_HOTPLUG_EVT:
487             memory_region_init(&s->container_pcihp, OBJECT(dev),
488                                ACPI_PCIHP_REGION_NAME, ACPI_PCIHP_SIZE);
489             sysbus_init_mmio(sbd, &s->container_pcihp);
490             acpi_pcihp_init(OBJECT(s), &s->pcihp_state,
491                             &s->container_pcihp, 0);
492             qbus_set_hotplug_handler(BUS(s->pcihp_state.root), OBJECT(dev));
493         }
494         ged_events--;
495     }
496 
497     if (ged_events) {
498         error_report("Unsupported events specified");
499         abort();
500     }
501 }
502 
acpi_ged_initfn(Object * obj)503 static void acpi_ged_initfn(Object *obj)
504 {
505     DeviceState *dev = DEVICE(obj);
506     AcpiGedState *s = ACPI_GED(dev);
507     SysBusDevice *sbd = SYS_BUS_DEVICE(obj);
508     GEDState *ged_st = &s->ged_state;
509 
510     memory_region_init_io(&ged_st->evt, obj, &ged_evt_ops, ged_st,
511                           TYPE_ACPI_GED, ACPI_GED_EVT_SEL_LEN);
512     sysbus_init_mmio(sbd, &ged_st->evt);
513 
514     sysbus_init_irq(sbd, &s->irq);
515 
516     s->memhp_state.is_enabled = true;
517     /*
518      * GED handles memory hotplug event and acpi-mem-hotplug
519      * memory region gets initialized here. Create an exclusive
520      * container for memory hotplug IO and expose it as GED sysbus
521      * MMIO so that boards can map it separately.
522      */
523     memory_region_init(&s->container_memhp, OBJECT(dev), "memhp container",
524                        MEMORY_HOTPLUG_IO_LEN);
525     sysbus_init_mmio(sbd, &s->container_memhp);
526     acpi_memory_hotplug_init(&s->container_memhp, OBJECT(dev),
527                              &s->memhp_state, 0);
528 
529     memory_region_init_io(&ged_st->regs, obj, &ged_regs_ops, ged_st,
530                           TYPE_ACPI_GED "-regs", ACPI_GED_REG_COUNT);
531     sysbus_init_mmio(sbd, &ged_st->regs);
532 }
533 
ged_reset_hold(Object * obj,ResetType type)534 static void ged_reset_hold(Object *obj, ResetType type)
535 {
536     AcpiGedState *s = ACPI_GED(obj);
537 
538     if (s->pcihp_state.use_acpi_hotplug_bridge) {
539         acpi_pcihp_reset(&s->pcihp_state);
540     }
541 }
542 
acpi_ged_class_init(ObjectClass * class,const void * data)543 static void acpi_ged_class_init(ObjectClass *class, const void *data)
544 {
545     DeviceClass *dc = DEVICE_CLASS(class);
546     HotplugHandlerClass *hc = HOTPLUG_HANDLER_CLASS(class);
547     AcpiDeviceIfClass *adevc = ACPI_DEVICE_IF_CLASS(class);
548     ResettableClass *rc = RESETTABLE_CLASS(class);
549     AcpiGedClass *gedc = ACPI_GED_CLASS(class);
550 
551     dc->desc = "ACPI Generic Event Device";
552     device_class_set_props(dc, acpi_ged_properties);
553     dc->vmsd = &vmstate_acpi_ged;
554     dc->realize = acpi_ged_realize;
555 
556     hc->pre_plug = acpi_ged_device_pre_plug_cb;
557     hc->plug = acpi_ged_device_plug_cb;
558     hc->unplug_request = acpi_ged_unplug_request_cb;
559     hc->unplug = acpi_ged_unplug_cb;
560     resettable_class_set_parent_phases(rc, NULL, ged_reset_hold, NULL,
561                                        &gedc->parent_phases);
562 
563     adevc->ospm_status = acpi_ged_ospm_status;
564     adevc->send_event = acpi_ged_send_event;
565 }
566 
567 static const TypeInfo acpi_ged_info = {
568     .name          = TYPE_ACPI_GED,
569     .parent        = TYPE_SYS_BUS_DEVICE,
570     .instance_size = sizeof(AcpiGedState),
571     .instance_init  = acpi_ged_initfn,
572     .class_init    = acpi_ged_class_init,
573     .class_size    = sizeof(AcpiGedClass),
574     .interfaces = (const InterfaceInfo[]) {
575         { TYPE_HOTPLUG_HANDLER },
576         { TYPE_ACPI_DEVICE_IF },
577         { }
578     }
579 };
580 
acpi_ged_register_types(void)581 static void acpi_ged_register_types(void)
582 {
583     type_register_static(&acpi_ged_info);
584 }
585 
586 type_init(acpi_ged_register_types)
587