xref: /openbmc/qemu/hw/acpi/generic_event_device.c (revision 1816a337a126281de43aabb4b55689f69ee876bc)
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  */
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 
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 */
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 */
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 
201 static uint64_t ged_regs_read(void *opaque, hwaddr addr, unsigned size)
202 {
203     return 0;
204 }
205 
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 
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 
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 
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 
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 
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 
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 
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 
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 
420 static const VMStateDescription vmstate_acpi_ged = {
421     .name = "acpi-ged",
422     .version_id = 1,
423     .minimum_version_id = 1,
424     .fields = (const VMStateField[]) {
425         VMSTATE_STRUCT(ged_state, AcpiGedState, 1, vmstate_ged_state, GEDState),
426         VMSTATE_END_OF_LIST(),
427     },
428     .subsections = (const VMStateDescription * const []) {
429         &vmstate_memhp_state,
430         &vmstate_cpuhp_state,
431         &vmstate_ghes_state,
432         NULL
433     }
434 };
435 
436 static void acpi_ged_realize(DeviceState *dev, Error **errp)
437 {
438     SysBusDevice *sbd = SYS_BUS_DEVICE(dev);
439     AcpiGedState *s = ACPI_GED(dev);
440     AcpiPciHpState *pcihp_state = &s->pcihp_state;
441     uint32_t ged_events;
442     int i;
443 
444     if (pcihp_state->use_acpi_hotplug_bridge) {
445         s->ged_event_bitmap |= ACPI_GED_PCI_HOTPLUG_EVT;
446     }
447     ged_events = ctpop32(s->ged_event_bitmap);
448 
449     for (i = 0; i < ARRAY_SIZE(ged_supported_events) && ged_events; i++) {
450         uint32_t event = s->ged_event_bitmap & ged_supported_events[i];
451 
452         if (!event) {
453             continue;
454         }
455 
456         switch (event) {
457         case ACPI_GED_CPU_HOTPLUG_EVT:
458             /* initialize CPU Hotplug related regions */
459             memory_region_init(&s->container_cpuhp, OBJECT(dev),
460                                 "cpuhp container",
461                                 ACPI_CPU_HOTPLUG_REG_LEN);
462             sysbus_init_mmio(sbd, &s->container_cpuhp);
463             cpu_hotplug_hw_init(&s->container_cpuhp, OBJECT(dev),
464                                 &s->cpuhp_state, 0);
465             break;
466         case ACPI_GED_PCI_HOTPLUG_EVT:
467             memory_region_init(&s->container_pcihp, OBJECT(dev),
468                                ACPI_PCIHP_REGION_NAME, ACPI_PCIHP_SIZE);
469             sysbus_init_mmio(sbd, &s->container_pcihp);
470             acpi_pcihp_init(OBJECT(s), &s->pcihp_state,
471                             &s->container_pcihp, 0);
472             qbus_set_hotplug_handler(BUS(s->pcihp_state.root), OBJECT(dev));
473         }
474         ged_events--;
475     }
476 
477     if (ged_events) {
478         error_report("Unsupported events specified");
479         abort();
480     }
481 }
482 
483 static void acpi_ged_initfn(Object *obj)
484 {
485     DeviceState *dev = DEVICE(obj);
486     AcpiGedState *s = ACPI_GED(dev);
487     SysBusDevice *sbd = SYS_BUS_DEVICE(obj);
488     GEDState *ged_st = &s->ged_state;
489 
490     memory_region_init_io(&ged_st->evt, obj, &ged_evt_ops, ged_st,
491                           TYPE_ACPI_GED, ACPI_GED_EVT_SEL_LEN);
492     sysbus_init_mmio(sbd, &ged_st->evt);
493 
494     sysbus_init_irq(sbd, &s->irq);
495 
496     s->memhp_state.is_enabled = true;
497     /*
498      * GED handles memory hotplug event and acpi-mem-hotplug
499      * memory region gets initialized here. Create an exclusive
500      * container for memory hotplug IO and expose it as GED sysbus
501      * MMIO so that boards can map it separately.
502      */
503     memory_region_init(&s->container_memhp, OBJECT(dev), "memhp container",
504                        MEMORY_HOTPLUG_IO_LEN);
505     sysbus_init_mmio(sbd, &s->container_memhp);
506     acpi_memory_hotplug_init(&s->container_memhp, OBJECT(dev),
507                              &s->memhp_state, 0);
508 
509     memory_region_init_io(&ged_st->regs, obj, &ged_regs_ops, ged_st,
510                           TYPE_ACPI_GED "-regs", ACPI_GED_REG_COUNT);
511     sysbus_init_mmio(sbd, &ged_st->regs);
512 }
513 
514 static void ged_reset_hold(Object *obj, ResetType type)
515 {
516     AcpiGedState *s = ACPI_GED(obj);
517 
518     if (s->pcihp_state.use_acpi_hotplug_bridge) {
519         acpi_pcihp_reset(&s->pcihp_state);
520     }
521 }
522 
523 static void acpi_ged_class_init(ObjectClass *class, const void *data)
524 {
525     DeviceClass *dc = DEVICE_CLASS(class);
526     HotplugHandlerClass *hc = HOTPLUG_HANDLER_CLASS(class);
527     AcpiDeviceIfClass *adevc = ACPI_DEVICE_IF_CLASS(class);
528     ResettableClass *rc = RESETTABLE_CLASS(class);
529     AcpiGedClass *gedc = ACPI_GED_CLASS(class);
530 
531     dc->desc = "ACPI Generic Event Device";
532     device_class_set_props(dc, acpi_ged_properties);
533     dc->vmsd = &vmstate_acpi_ged;
534     dc->realize = acpi_ged_realize;
535 
536     hc->pre_plug = acpi_ged_device_pre_plug_cb;
537     hc->plug = acpi_ged_device_plug_cb;
538     hc->unplug_request = acpi_ged_unplug_request_cb;
539     hc->unplug = acpi_ged_unplug_cb;
540     resettable_class_set_parent_phases(rc, NULL, ged_reset_hold, NULL,
541                                        &gedc->parent_phases);
542 
543     adevc->ospm_status = acpi_ged_ospm_status;
544     adevc->send_event = acpi_ged_send_event;
545 }
546 
547 static const TypeInfo acpi_ged_info = {
548     .name          = TYPE_ACPI_GED,
549     .parent        = TYPE_SYS_BUS_DEVICE,
550     .instance_size = sizeof(AcpiGedState),
551     .instance_init  = acpi_ged_initfn,
552     .class_init    = acpi_ged_class_init,
553     .class_size    = sizeof(AcpiGedClass),
554     .interfaces = (const InterfaceInfo[]) {
555         { TYPE_HOTPLUG_HANDLER },
556         { TYPE_ACPI_DEVICE_IF },
557         { }
558     }
559 };
560 
561 static void acpi_ged_register_types(void)
562 {
563     type_register_static(&acpi_ged_info);
564 }
565 
566 type_init(acpi_ged_register_types)
567