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