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