qemu

FORK: QEMU emulator
git clone https://git.neptards.moe/neptards/qemu.git
Log | Files | Refs | Submodules | LICENSE

generic_event_device.c (13537B)


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