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