1
2
3
4
5
6
7
8
9
10
11
12#include "qemu/osdep.h"
13#include "qapi/error.h"
14#include "exec/address-spaces.h"
15#include "hw/acpi/acpi.h"
16#include "hw/acpi/generic_event_device.h"
17#include "hw/irq.h"
18#include "hw/mem/pc-dimm.h"
19#include "hw/qdev-properties.h"
20#include "migration/vmstate.h"
21#include "qemu/error-report.h"
22
23static const uint32_t ged_supported_events[] = {
24 ACPI_GED_MEM_HOTPLUG_EVT,
25 ACPI_GED_PWR_DOWN_EVT,
26};
27
28
29
30
31
32
33
34
35
36
37
38void build_ged_aml(Aml *table, const char *name, HotplugHandler *hotplug_dev,
39 uint32_t ged_irq, AmlRegionSpace rs, hwaddr ged_base)
40{
41 AcpiGedState *s = ACPI_GED(hotplug_dev);
42 Aml *crs = aml_resource_template();
43 Aml *evt, *field;
44 Aml *dev = aml_device("%s", name);
45 Aml *evt_sel = aml_local(0);
46 Aml *esel = aml_name(AML_GED_EVT_SEL);
47
48
49 aml_append(crs, aml_interrupt(AML_CONSUMER, AML_EDGE, AML_ACTIVE_HIGH,
50 AML_EXCLUSIVE, &ged_irq, 1));
51
52 aml_append(dev, aml_name_decl("_HID", aml_string("ACPI0013")));
53 aml_append(dev, aml_name_decl("_UID", aml_string(GED_DEVICE)));
54 aml_append(dev, aml_name_decl("_CRS", crs));
55
56
57 aml_append(dev, aml_operation_region(AML_GED_EVT_REG, rs,
58 aml_int(ged_base + ACPI_GED_EVT_SEL_OFFSET),
59 ACPI_GED_EVT_SEL_LEN));
60 field = aml_field(AML_GED_EVT_REG, AML_DWORD_ACC, AML_NOLOCK,
61 AML_WRITE_AS_ZEROS);
62 aml_append(field, aml_named_field(AML_GED_EVT_SEL,
63 ACPI_GED_EVT_SEL_LEN * BITS_PER_BYTE));
64 aml_append(dev, field);
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85 evt = aml_method("_EVT", 1, AML_SERIALIZED);
86 {
87 Aml *if_ctx;
88 uint32_t i;
89 uint32_t ged_events = ctpop32(s->ged_event_bitmap);
90
91
92 aml_append(evt, aml_store(esel, evt_sel));
93
94 for (i = 0; i < ARRAY_SIZE(ged_supported_events) && ged_events; i++) {
95 uint32_t event = s->ged_event_bitmap & ged_supported_events[i];
96
97 if (!event) {
98 continue;
99 }
100
101 if_ctx = aml_if(aml_equal(aml_and(evt_sel, aml_int(event), NULL),
102 aml_int(event)));
103 switch (event) {
104 case ACPI_GED_MEM_HOTPLUG_EVT:
105 aml_append(if_ctx, aml_call0(MEMORY_DEVICES_CONTAINER "."
106 MEMORY_SLOT_SCAN_METHOD));
107 break;
108 case ACPI_GED_PWR_DOWN_EVT:
109 aml_append(if_ctx,
110 aml_notify(aml_name(ACPI_POWER_BUTTON_DEVICE),
111 aml_int(0x80)));
112 break;
113 default:
114
115
116
117
118 g_assert_not_reached();
119 }
120
121 aml_append(evt, if_ctx);
122 ged_events--;
123 }
124
125 if (ged_events) {
126 error_report("Unsupported events specified");
127 abort();
128 }
129 }
130
131
132 aml_append(dev, evt);
133
134 aml_append(table, dev);
135}
136
137
138static uint64_t ged_read(void *opaque, hwaddr addr, unsigned size)
139{
140 uint64_t val = 0;
141 GEDState *ged_st = opaque;
142
143 switch (addr) {
144 case ACPI_GED_EVT_SEL_OFFSET:
145
146 val = ged_st->sel;
147 ged_st->sel = 0;
148 break;
149 default:
150 break;
151 }
152
153 return val;
154}
155
156
157static void ged_write(void *opaque, hwaddr addr, uint64_t data,
158 unsigned int size)
159{
160}
161
162static const MemoryRegionOps ged_ops = {
163 .read = ged_read,
164 .write = ged_write,
165 .endianness = DEVICE_LITTLE_ENDIAN,
166 .valid = {
167 .min_access_size = 4,
168 .max_access_size = 4,
169 },
170};
171
172static void acpi_ged_device_plug_cb(HotplugHandler *hotplug_dev,
173 DeviceState *dev, Error **errp)
174{
175 AcpiGedState *s = ACPI_GED(hotplug_dev);
176
177 if (object_dynamic_cast(OBJECT(dev), TYPE_PC_DIMM)) {
178 acpi_memory_plug_cb(hotplug_dev, &s->memhp_state, dev, errp);
179 } else {
180 error_setg(errp, "virt: device plug request for unsupported device"
181 " type: %s", object_get_typename(OBJECT(dev)));
182 }
183}
184
185static void acpi_ged_send_event(AcpiDeviceIf *adev, AcpiEventStatusBits ev)
186{
187 AcpiGedState *s = ACPI_GED(adev);
188 GEDState *ged_st = &s->ged_state;
189 uint32_t sel;
190
191 if (ev & ACPI_MEMORY_HOTPLUG_STATUS) {
192 sel = ACPI_GED_MEM_HOTPLUG_EVT;
193 } else if (ev & ACPI_POWER_DOWN_STATUS) {
194 sel = ACPI_GED_PWR_DOWN_EVT;
195 } else {
196
197 warn_report("GED: Unsupported event %d. No irq injected", ev);
198 return;
199 }
200
201
202
203
204
205
206 ged_st->sel |= sel;
207
208
209 qemu_irq_pulse(s->irq);
210}
211
212static Property acpi_ged_properties[] = {
213 DEFINE_PROP_UINT32("ged-event", AcpiGedState, ged_event_bitmap, 0),
214 DEFINE_PROP_END_OF_LIST(),
215};
216
217static const VMStateDescription vmstate_memhp_state = {
218 .name = "acpi-ged/memhp",
219 .version_id = 1,
220 .minimum_version_id = 1,
221 .fields = (VMStateField[]) {
222 VMSTATE_MEMORY_HOTPLUG(memhp_state, AcpiGedState),
223 VMSTATE_END_OF_LIST()
224 }
225};
226
227static const VMStateDescription vmstate_ged_state = {
228 .name = "acpi-ged-state",
229 .version_id = 1,
230 .minimum_version_id = 1,
231 .fields = (VMStateField[]) {
232 VMSTATE_UINT32(sel, GEDState),
233 VMSTATE_END_OF_LIST()
234 }
235};
236
237static const VMStateDescription vmstate_acpi_ged = {
238 .name = "acpi-ged",
239 .version_id = 1,
240 .minimum_version_id = 1,
241 .fields = (VMStateField[]) {
242 VMSTATE_STRUCT(ged_state, AcpiGedState, 1, vmstate_ged_state, GEDState),
243 VMSTATE_END_OF_LIST(),
244 },
245 .subsections = (const VMStateDescription * []) {
246 &vmstate_memhp_state,
247 NULL
248 }
249};
250
251static void acpi_ged_initfn(Object *obj)
252{
253 DeviceState *dev = DEVICE(obj);
254 AcpiGedState *s = ACPI_GED(dev);
255 SysBusDevice *sbd = SYS_BUS_DEVICE(obj);
256 GEDState *ged_st = &s->ged_state;
257
258 memory_region_init_io(&ged_st->io, obj, &ged_ops, ged_st,
259 TYPE_ACPI_GED, ACPI_GED_EVT_SEL_LEN);
260 sysbus_init_mmio(sbd, &ged_st->io);
261
262 sysbus_init_irq(sbd, &s->irq);
263
264 s->memhp_state.is_enabled = true;
265
266
267
268
269
270
271 memory_region_init(&s->container_memhp, OBJECT(dev), "memhp container",
272 MEMORY_HOTPLUG_IO_LEN);
273 sysbus_init_mmio(sbd, &s->container_memhp);
274 acpi_memory_hotplug_init(&s->container_memhp, OBJECT(dev),
275 &s->memhp_state, 0);
276}
277
278static void acpi_ged_class_init(ObjectClass *class, void *data)
279{
280 DeviceClass *dc = DEVICE_CLASS(class);
281 HotplugHandlerClass *hc = HOTPLUG_HANDLER_CLASS(class);
282 AcpiDeviceIfClass *adevc = ACPI_DEVICE_IF_CLASS(class);
283
284 dc->desc = "ACPI Generic Event Device";
285 dc->props = acpi_ged_properties;
286 dc->vmsd = &vmstate_acpi_ged;
287
288 hc->plug = acpi_ged_device_plug_cb;
289
290 adevc->send_event = acpi_ged_send_event;
291}
292
293static const TypeInfo acpi_ged_info = {
294 .name = TYPE_ACPI_GED,
295 .parent = TYPE_SYS_BUS_DEVICE,
296 .instance_size = sizeof(AcpiGedState),
297 .instance_init = acpi_ged_initfn,
298 .class_init = acpi_ged_class_init,
299 .interfaces = (InterfaceInfo[]) {
300 { TYPE_HOTPLUG_HANDLER },
301 { TYPE_ACPI_DEVICE_IF },
302 { }
303 }
304};
305
306static void acpi_ged_register_types(void)
307{
308 type_register_static(&acpi_ged_info);
309}
310
311type_init(acpi_ged_register_types)
312