1#include "qemu/osdep.h"
2#include "hw/acpi/memory_hotplug.h"
3#include "hw/acpi/pc-hotplug.h"
4#include "hw/mem/pc-dimm.h"
5#include "hw/boards.h"
6#include "hw/qdev-core.h"
7#include "migration/vmstate.h"
8#include "trace.h"
9#include "qapi/error.h"
10#include "qapi/qapi-events-misc.h"
11
12#define MEMORY_SLOTS_NUMBER "MDNR"
13#define MEMORY_HOTPLUG_IO_REGION "HPMR"
14#define MEMORY_SLOT_ADDR_LOW "MRBL"
15#define MEMORY_SLOT_ADDR_HIGH "MRBH"
16#define MEMORY_SLOT_SIZE_LOW "MRLL"
17#define MEMORY_SLOT_SIZE_HIGH "MRLH"
18#define MEMORY_SLOT_PROXIMITY "MPX"
19#define MEMORY_SLOT_ENABLED "MES"
20#define MEMORY_SLOT_INSERT_EVENT "MINS"
21#define MEMORY_SLOT_REMOVE_EVENT "MRMV"
22#define MEMORY_SLOT_EJECT "MEJ"
23#define MEMORY_SLOT_SLECTOR "MSEL"
24#define MEMORY_SLOT_OST_EVENT "MOEV"
25#define MEMORY_SLOT_OST_STATUS "MOSC"
26#define MEMORY_SLOT_LOCK "MLCK"
27#define MEMORY_SLOT_STATUS_METHOD "MRST"
28#define MEMORY_SLOT_CRS_METHOD "MCRS"
29#define MEMORY_SLOT_OST_METHOD "MOST"
30#define MEMORY_SLOT_PROXIMITY_METHOD "MPXM"
31#define MEMORY_SLOT_EJECT_METHOD "MEJ0"
32#define MEMORY_SLOT_NOTIFY_METHOD "MTFY"
33#define MEMORY_SLOT_SCAN_METHOD "MSCN"
34#define MEMORY_HOTPLUG_DEVICE "MHPD"
35#define MEMORY_HOTPLUG_IO_LEN 24
36#define MEMORY_DEVICES_CONTAINER "\\_SB.MHPC"
37
38static uint16_t memhp_io_base;
39
40static ACPIOSTInfo *acpi_memory_device_status(int slot, MemStatus *mdev)
41{
42 ACPIOSTInfo *info = g_new0(ACPIOSTInfo, 1);
43
44 info->slot_type = ACPI_SLOT_TYPE_DIMM;
45 info->slot = g_strdup_printf("%d", slot);
46 info->source = mdev->ost_event;
47 info->status = mdev->ost_status;
48 if (mdev->dimm) {
49 DeviceState *dev = DEVICE(mdev->dimm);
50 if (dev->id) {
51 info->device = g_strdup(dev->id);
52 info->has_device = true;
53 }
54 }
55 return info;
56}
57
58void acpi_memory_ospm_status(MemHotplugState *mem_st, ACPIOSTInfoList ***list)
59{
60 int i;
61
62 for (i = 0; i < mem_st->dev_count; i++) {
63 ACPIOSTInfoList *elem = g_new0(ACPIOSTInfoList, 1);
64 elem->value = acpi_memory_device_status(i, &mem_st->devs[i]);
65 elem->next = NULL;
66 **list = elem;
67 *list = &elem->next;
68 }
69}
70
71static uint64_t acpi_memory_hotplug_read(void *opaque, hwaddr addr,
72 unsigned int size)
73{
74 uint32_t val = 0;
75 MemHotplugState *mem_st = opaque;
76 MemStatus *mdev;
77 Object *o;
78
79 if (mem_st->selector >= mem_st->dev_count) {
80 trace_mhp_acpi_invalid_slot_selected(mem_st->selector);
81 return 0;
82 }
83
84 mdev = &mem_st->devs[mem_st->selector];
85 o = OBJECT(mdev->dimm);
86 switch (addr) {
87 case 0x0: /* Lo part of phys address where DIMM is mapped */
88 val = o ? object_property_get_uint(o, PC_DIMM_ADDR_PROP, NULL) : 0;
89 trace_mhp_acpi_read_addr_lo(mem_st->selector, val);
90 break;
91 case 0x4: /* Hi part of phys address where DIMM is mapped */
92 val =
93 o ? object_property_get_uint(o, PC_DIMM_ADDR_PROP, NULL) >> 32 : 0;
94 trace_mhp_acpi_read_addr_hi(mem_st->selector, val);
95 break;
96 case 0x8: /* Lo part of DIMM size */
97 val = o ? object_property_get_uint(o, PC_DIMM_SIZE_PROP, NULL) : 0;
98 trace_mhp_acpi_read_size_lo(mem_st->selector, val);
99 break;
100 case 0xc: /* Hi part of DIMM size */
101 val =
102 o ? object_property_get_uint(o, PC_DIMM_SIZE_PROP, NULL) >> 32 : 0;
103 trace_mhp_acpi_read_size_hi(mem_st->selector, val);
104 break;
105 case 0x10: /* node proximity for _PXM method */
106 val = o ? object_property_get_uint(o, PC_DIMM_NODE_PROP, NULL) : 0;
107 trace_mhp_acpi_read_pxm(mem_st->selector, val);
108 break;
109 case 0x14: /* pack and return is_* fields */
110 val |= mdev->is_enabled ? 1 : 0;
111 val |= mdev->is_inserting ? 2 : 0;
112 val |= mdev->is_removing ? 4 : 0;
113 trace_mhp_acpi_read_flags(mem_st->selector, val);
114 break;
115 default:
116 val = ~0;
117 break;
118 }
119 return val;
120}
121
122static void acpi_memory_hotplug_write(void *opaque, hwaddr addr, uint64_t data,
123 unsigned int size)
124{
125 MemHotplugState *mem_st = opaque;
126 MemStatus *mdev;
127 ACPIOSTInfo *info;
128 DeviceState *dev = NULL;
129 HotplugHandler *hotplug_ctrl = NULL;
130 Error *local_err = NULL;
131
132 if (!mem_st->dev_count) {
133 return;
134 }
135
136 if (addr) {
137 if (mem_st->selector >= mem_st->dev_count) {
138 trace_mhp_acpi_invalid_slot_selected(mem_st->selector);
139 return;
140 }
141 }
142
143 switch (addr) {
144 case 0x0: /* DIMM slot selector */
145 mem_st->selector = data;
146 trace_mhp_acpi_write_slot(mem_st->selector);
147 break;
148 case 0x4: /* _OST event */
149 mdev = &mem_st->devs[mem_st->selector];
150 if (data == 1) {
151 /* TODO: handle device insert OST event */
152 } else if (data == 3) {
153 /* TODO: handle device remove OST event */
154 }
155 mdev->ost_event = data;
156 trace_mhp_acpi_write_ost_ev(mem_st->selector, mdev->ost_event);
157 break;
158 case 0x8: /* _OST status */
159 mdev = &mem_st->devs[mem_st->selector];
160 mdev->ost_status = data;
161 trace_mhp_acpi_write_ost_status(mem_st->selector, mdev->ost_status);
162 /* TODO: implement memory removal on guest signal */
163
164 info = acpi_memory_device_status(mem_st->selector, mdev);
165 qapi_event_send_acpi_device_ost(info);
166 qapi_free_ACPIOSTInfo(info);
167 break;
168 case 0x14: /* set is_* fields */
169 mdev = &mem_st->devs[mem_st->selector];
170 if (data & 2) { /* clear insert event */
171 mdev->is_inserting = false;
172 trace_mhp_acpi_clear_insert_evt(mem_st->selector);
173 } else if (data & 4) {
174 mdev->is_removing = false;
175 trace_mhp_acpi_clear_remove_evt(mem_st->selector);
176 } else if (data & 8) {
177 if (!mdev->is_enabled) {
178 trace_mhp_acpi_ejecting_invalid_slot(mem_st->selector);
179 break;
180 }
181
182 dev = DEVICE(mdev->dimm);
183 hotplug_ctrl = qdev_get_hotplug_handler(dev);
184 /* call pc-dimm unplug cb */
185 hotplug_handler_unplug(hotplug_ctrl, dev, &local_err);
186 if (local_err) {
187 trace_mhp_acpi_pc_dimm_delete_failed(mem_st->selector);
188 qapi_event_send_mem_unplug_error(dev->id,
189 error_get_pretty(local_err));
190 error_free(local_err);
191 break;
192 }
193 object_unparent(OBJECT(dev));
194 trace_mhp_acpi_pc_dimm_deleted(mem_st->selector);
195 }
196 break;
197 default:
198 break;
199 }
200
201}
202static const MemoryRegionOps acpi_memory_hotplug_ops = {
203 .read = acpi_memory_hotplug_read,
204 .write = acpi_memory_hotplug_write,
205 .endianness = DEVICE_LITTLE_ENDIAN,
206 .valid = {
207 .min_access_size = 1,
208 .max_access_size = 4,
209 },
210};
211
212void acpi_memory_hotplug_init(MemoryRegion *as, Object *owner,
213 MemHotplugState *state, uint16_t io_base)
214{
215 MachineState *machine = MACHINE(qdev_get_machine());
216
217 state->dev_count = machine->ram_slots;
218 if (!state->dev_count) {
219 return;
220 }
221
222 assert(!memhp_io_base);
223 memhp_io_base = io_base;
224 state->devs = g_malloc0(sizeof(*state->devs) * state->dev_count);
225 memory_region_init_io(&state->io, owner, &acpi_memory_hotplug_ops, state,
226 "acpi-mem-hotplug", MEMORY_HOTPLUG_IO_LEN);
227 memory_region_add_subregion(as, memhp_io_base, &state->io);
228}
229
230/**
231 * acpi_memory_slot_status:
232 * @mem_st: memory hotplug state
233 * @dev: device
234 * @errp: set in case of an error
235 *
236 * Obtain a single memory slot status.
237 *
238 * This function will be called by memory unplug request cb and unplug cb.
239 */
240static MemStatus *
241acpi_memory_slot_status(MemHotplugState *mem_st,
242 DeviceState *dev, Error **errp)
243{
244 Error *local_err = NULL;
245 int slot = object_property_get_int(OBJECT(dev), PC_DIMM_SLOT_PROP,
246 &local_err);
247
248 if (local_err) {
249 error_propagate(errp, local_err);
250 return NULL;
251 }
252
253 if (slot >= mem_st->dev_count) {
254 char *dev_path = object_get_canonical_path(OBJECT(dev));
255 error_setg(errp, "acpi_memory_slot_status: "
256 "device [%s] returned invalid memory slot[%d]",
257 dev_path, slot);
258 g_free(dev_path);
259 return NULL;
260 }
261
262 return &mem_st->devs[slot];
263}
264
265void acpi_memory_plug_cb(HotplugHandler *hotplug_dev, MemHotplugState *mem_st,
266 DeviceState *dev, Error **errp)
267{
268 MemStatus *mdev;
269 DeviceClass *dc = DEVICE_GET_CLASS(dev);
270
271 if (!dc->hotpluggable) {
272 return;
273 }
274
275 mdev = acpi_memory_slot_status(mem_st, dev, errp);
276 if (!mdev) {
277 return;
278 }
279
280 mdev->dimm = dev;
281 mdev->is_enabled = true;
282 if (dev->hotplugged) {
283 mdev->is_inserting = true;
284 acpi_send_event(DEVICE(hotplug_dev), ACPI_MEMORY_HOTPLUG_STATUS);
285 }
286}
287
288void acpi_memory_unplug_request_cb(HotplugHandler *hotplug_dev,
289 MemHotplugState *mem_st,
290 DeviceState *dev, Error **errp)
291{
292 MemStatus *mdev;
293
294 mdev = acpi_memory_slot_status(mem_st, dev, errp);
295 if (!mdev) {
296 return;
297 }
298
299 mdev->is_removing = true;
300 acpi_send_event(DEVICE(hotplug_dev), ACPI_MEMORY_HOTPLUG_STATUS);
301}
302
303void acpi_memory_unplug_cb(MemHotplugState *mem_st,
304 DeviceState *dev, Error **errp)
305{
306 MemStatus *mdev;
307
308 mdev = acpi_memory_slot_status(mem_st, dev, errp);
309 if (!mdev) {
310 return;
311 }
312
313 mdev->is_enabled = false;
314 mdev->dimm = NULL;
315}
316
317static const VMStateDescription vmstate_memhp_sts = {
318 .name = "memory hotplug device state",
319 .version_id = 1,
320 .minimum_version_id = 1,
321 .minimum_version_id_old = 1,
322 .fields = (VMStateField[]) {
323 VMSTATE_BOOL(is_enabled, MemStatus),
324 VMSTATE_BOOL(is_inserting, MemStatus),
325 VMSTATE_UINT32(ost_event, MemStatus),
326 VMSTATE_UINT32(ost_status, MemStatus),
327 VMSTATE_END_OF_LIST()
328 }
329};
330
331const VMStateDescription vmstate_memory_hotplug = {
332 .name = "memory hotplug state",
333 .version_id = 1,
334 .minimum_version_id = 1,
335 .minimum_version_id_old = 1,
336 .fields = (VMStateField[]) {
337 VMSTATE_UINT32(selector, MemHotplugState),
338 VMSTATE_STRUCT_VARRAY_POINTER_UINT32(devs, MemHotplugState, dev_count,
339 vmstate_memhp_sts, MemStatus),
340 VMSTATE_END_OF_LIST()
341 }
342};
343
344void build_memory_hotplug_aml(Aml *table, uint32_t nr_mem,
345 const char *res_root,
346 const char *event_handler_method)
347{
348 int i;
349 Aml *ifctx;
350 Aml *method;
351 Aml *dev_container;
352 Aml *mem_ctrl_dev;
353 char *mhp_res_path;
354
355 if (!memhp_io_base) {
356 return;
357 }
358
359 mhp_res_path = g_strdup_printf("%s." MEMORY_HOTPLUG_DEVICE, res_root);
360 mem_ctrl_dev = aml_device("%s", mhp_res_path);
361 {
362 Aml *crs;
363
364 aml_append(mem_ctrl_dev, aml_name_decl("_HID", aml_string("PNP0A06")));
365 aml_append(mem_ctrl_dev,
366 aml_name_decl("_UID", aml_string("Memory hotplug resources")));
367
368 crs = aml_resource_template();
369 aml_append(crs,
370 aml_io(AML_DECODE16, memhp_io_base, memhp_io_base, 0,
371 MEMORY_HOTPLUG_IO_LEN)
372 );
373 aml_append(mem_ctrl_dev, aml_name_decl("_CRS", crs));
374
375 aml_append(mem_ctrl_dev, aml_operation_region(
376 MEMORY_HOTPLUG_IO_REGION, AML_SYSTEM_IO,
377 aml_int(memhp_io_base), MEMORY_HOTPLUG_IO_LEN)
378 );
379
380 }
381 aml_append(table, mem_ctrl_dev);
382
383 dev_container = aml_device(MEMORY_DEVICES_CONTAINER);
384 {
385 Aml *field;
386 Aml *one = aml_int(1);
387 Aml *zero = aml_int(0);
388 Aml *ret_val = aml_local(0);
389 Aml *slot_arg0 = aml_arg(0);
390 Aml *slots_nr = aml_name(MEMORY_SLOTS_NUMBER);
391 Aml *ctrl_lock = aml_name(MEMORY_SLOT_LOCK);
392 Aml *slot_selector = aml_name(MEMORY_SLOT_SLECTOR);
393 char *mmio_path = g_strdup_printf("%s." MEMORY_HOTPLUG_IO_REGION,
394 mhp_res_path);
395
396 aml_append(dev_container, aml_name_decl("_HID", aml_string("PNP0A06")));
397 aml_append(dev_container,
398 aml_name_decl("_UID", aml_string("DIMM devices")));
399
400 assert(nr_mem <= ACPI_MAX_RAM_SLOTS);
401 aml_append(dev_container,
402 aml_name_decl(MEMORY_SLOTS_NUMBER, aml_int(nr_mem))
403 );
404
405 field = aml_field(mmio_path, AML_DWORD_ACC,
406 AML_NOLOCK, AML_PRESERVE);
407 aml_append(field, /* read only */
408 aml_named_field(MEMORY_SLOT_ADDR_LOW, 32));
409 aml_append(field, /* read only */
410 aml_named_field(MEMORY_SLOT_ADDR_HIGH, 32));
411 aml_append(field, /* read only */
412 aml_named_field(MEMORY_SLOT_SIZE_LOW, 32));
413 aml_append(field, /* read only */
414 aml_named_field(MEMORY_SLOT_SIZE_HIGH, 32));
415 aml_append(field, /* read only */
416 aml_named_field(MEMORY_SLOT_PROXIMITY, 32));
417 aml_append(dev_container, field);
418
419 field = aml_field(mmio_path, AML_BYTE_ACC,
420 AML_NOLOCK, AML_WRITE_AS_ZEROS);
421 aml_append(field, aml_reserved_field(160 /* bits, Offset(20) */));
422 aml_append(field, /* 1 if enabled, read only */
423 aml_named_field(MEMORY_SLOT_ENABLED, 1));
424 aml_append(field,
425 /*(read) 1 if has a insert event. (write) 1 to clear event */
426 aml_named_field(MEMORY_SLOT_INSERT_EVENT, 1));
427 aml_append(field,
428 /* (read) 1 if has a remove event. (write) 1 to clear event */
429 aml_named_field(MEMORY_SLOT_REMOVE_EVENT, 1));
430 aml_append(field,
431 /* initiates device eject, write only */
432 aml_named_field(MEMORY_SLOT_EJECT, 1));
433 aml_append(dev_container, field);
434
435 field = aml_field(mmio_path, AML_DWORD_ACC,
436 AML_NOLOCK, AML_PRESERVE);
437 aml_append(field, /* DIMM selector, write only */
438 aml_named_field(MEMORY_SLOT_SLECTOR, 32));
439 aml_append(field, /* _OST event code, write only */
440 aml_named_field(MEMORY_SLOT_OST_EVENT, 32));
441 aml_append(field, /* _OST status code, write only */
442 aml_named_field(MEMORY_SLOT_OST_STATUS, 32));
443 aml_append(dev_container, field);
444 g_free(mmio_path);
445
446 method = aml_method("_STA", 0, AML_NOTSERIALIZED);
447 ifctx = aml_if(aml_equal(slots_nr, zero));
448 {
449 aml_append(ifctx, aml_return(zero));
450 }
451 aml_append(method, ifctx);
452 /* present, functioning, decoding, not shown in UI */
453 aml_append(method, aml_return(aml_int(0xB)));
454 aml_append(dev_container, method);
455
456 aml_append(dev_container, aml_mutex(MEMORY_SLOT_LOCK, 0));
457
458 method = aml_method(MEMORY_SLOT_SCAN_METHOD, 0, AML_NOTSERIALIZED);
459 {
460 Aml *else_ctx;
461 Aml *while_ctx;
462 Aml *idx = aml_local(0);
463 Aml *eject_req = aml_int(3);
464 Aml *dev_chk = aml_int(1);
465
466 ifctx = aml_if(aml_equal(slots_nr, zero));
467 {
468 aml_append(ifctx, aml_return(zero));
469 }
470 aml_append(method, ifctx);
471
472 aml_append(method, aml_store(zero, idx));
473 aml_append(method, aml_acquire(ctrl_lock, 0xFFFF));
474 /* build AML that:
475 * loops over all slots and Notifies DIMMs with
476 * Device Check or Eject Request notifications if
477 * slot has corresponding status bit set and clears
478 * slot status.
479 */
480 while_ctx = aml_while(aml_lless(idx, slots_nr));
481 {
482 Aml *ins_evt = aml_name(MEMORY_SLOT_INSERT_EVENT);
483 Aml *rm_evt = aml_name(MEMORY_SLOT_REMOVE_EVENT);
484
485 aml_append(while_ctx, aml_store(idx, slot_selector));
486 ifctx = aml_if(aml_equal(ins_evt, one));
487 {
488 aml_append(ifctx,
489 aml_call2(MEMORY_SLOT_NOTIFY_METHOD,
490 idx, dev_chk));
491 aml_append(ifctx, aml_store(one, ins_evt));
492 }
493 aml_append(while_ctx, ifctx);
494
495 else_ctx = aml_else();
496 ifctx = aml_if(aml_equal(rm_evt, one));
497 {
498 aml_append(ifctx,
499 aml_call2(MEMORY_SLOT_NOTIFY_METHOD,
500 idx, eject_req));
501 aml_append(ifctx, aml_store(one, rm_evt));
502 }
503 aml_append(else_ctx, ifctx);
504 aml_append(while_ctx, else_ctx);
505
506 aml_append(while_ctx, aml_add(idx, one, idx));
507 }
508 aml_append(method, while_ctx);
509 aml_append(method, aml_release(ctrl_lock));
510 aml_append(method, aml_return(one));
511 }
512 aml_append(dev_container, method);
513
514 method = aml_method(MEMORY_SLOT_STATUS_METHOD, 1, AML_NOTSERIALIZED);
515 {
516 Aml *slot_enabled = aml_name(MEMORY_SLOT_ENABLED);
517
518 aml_append(method, aml_store(zero, ret_val));
519 aml_append(method, aml_acquire(ctrl_lock, 0xFFFF));
520 aml_append(method,
521 aml_store(aml_to_integer(slot_arg0), slot_selector));
522
523 ifctx = aml_if(aml_equal(slot_enabled, one));
524 {
525 aml_append(ifctx, aml_store(aml_int(0xF), ret_val));
526 }
527 aml_append(method, ifctx);
528
529 aml_append(method, aml_release(ctrl_lock));
530 aml_append(method, aml_return(ret_val));
531 }
532 aml_append(dev_container, method);
533
534 method = aml_method(MEMORY_SLOT_CRS_METHOD, 1, AML_SERIALIZED);
535 {
536 Aml *mr64 = aml_name("MR64");
537 Aml *mr32 = aml_name("MR32");
538 Aml *crs_tmpl = aml_resource_template();
539 Aml *minl = aml_name("MINL");
540 Aml *minh = aml_name("MINH");
541 Aml *maxl = aml_name("MAXL");
542 Aml *maxh = aml_name("MAXH");
543 Aml *lenl = aml_name("LENL");
544 Aml *lenh = aml_name("LENH");
545
546 aml_append(method, aml_acquire(ctrl_lock, 0xFFFF));
547 aml_append(method, aml_store(aml_to_integer(slot_arg0),
548 slot_selector));
549
550 aml_append(crs_tmpl,
551 aml_qword_memory(AML_POS_DECODE, AML_MIN_FIXED, AML_MAX_FIXED,
552 AML_CACHEABLE, AML_READ_WRITE,
553 0, 0x0, 0xFFFFFFFFFFFFFFFEULL, 0,
554 0xFFFFFFFFFFFFFFFFULL));
555 aml_append(method, aml_name_decl("MR64", crs_tmpl));
556 aml_append(method,
557 aml_create_dword_field(mr64, aml_int(14), "MINL"));
558 aml_append(method,
559 aml_create_dword_field(mr64, aml_int(18), "MINH"));
560 aml_append(method,
561 aml_create_dword_field(mr64, aml_int(38), "LENL"));
562 aml_append(method,
563 aml_create_dword_field(mr64, aml_int(42), "LENH"));
564 aml_append(method,
565 aml_create_dword_field(mr64, aml_int(22), "MAXL"));
566 aml_append(method,
567 aml_create_dword_field(mr64, aml_int(26), "MAXH"));
568
569 aml_append(method,
570 aml_store(aml_name(MEMORY_SLOT_ADDR_HIGH), minh));
571 aml_append(method,
572 aml_store(aml_name(MEMORY_SLOT_ADDR_LOW), minl));
573 aml_append(method,
574 aml_store(aml_name(MEMORY_SLOT_SIZE_HIGH), lenh));
575 aml_append(method,
576 aml_store(aml_name(MEMORY_SLOT_SIZE_LOW), lenl));
577
578 /* 64-bit math: MAX = MIN + LEN - 1 */
579 aml_append(method, aml_add(minl, lenl, maxl));
580 aml_append(method, aml_add(minh, lenh, maxh));
581 ifctx = aml_if(aml_lless(maxl, minl));
582 {
583 aml_append(ifctx, aml_add(maxh, one, maxh));
584 }
585 aml_append(method, ifctx);
586 ifctx = aml_if(aml_lless(maxl, one));
587 {
588 aml_append(ifctx, aml_subtract(maxh, one, maxh));
589 }
590 aml_append(method, ifctx);
591 aml_append(method, aml_subtract(maxl, one, maxl));
592
593 /* return 32-bit _CRS if addr/size is in low mem */
594 /* TODO: remove it since all hotplugged DIMMs are in high mem */
595 ifctx = aml_if(aml_equal(maxh, zero));
596 {
597 crs_tmpl = aml_resource_template();
598 aml_append(crs_tmpl,
599 aml_dword_memory(AML_POS_DECODE, AML_MIN_FIXED,
600 AML_MAX_FIXED, AML_CACHEABLE,
601 AML_READ_WRITE,
602 0, 0x0, 0xFFFFFFFE, 0,
603 0xFFFFFFFF));
604 aml_append(ifctx, aml_name_decl("MR32", crs_tmpl));
605 aml_append(ifctx,
606 aml_create_dword_field(mr32, aml_int(10), "MIN"));
607 aml_append(ifctx,
608 aml_create_dword_field(mr32, aml_int(14), "MAX"));
609 aml_append(ifctx,
610 aml_create_dword_field(mr32, aml_int(22), "LEN"));
611 aml_append(ifctx, aml_store(minl, aml_name("MIN")));
612 aml_append(ifctx, aml_store(maxl, aml_name("MAX")));
613 aml_append(ifctx, aml_store(lenl, aml_name("LEN")));
614
615 aml_append(ifctx, aml_release(ctrl_lock));
616 aml_append(ifctx, aml_return(mr32));
617 }
618 aml_append(method, ifctx);
619
620 aml_append(method, aml_release(ctrl_lock));
621 aml_append(method, aml_return(mr64));
622 }
623 aml_append(dev_container, method);
624
625 method = aml_method(MEMORY_SLOT_PROXIMITY_METHOD, 1,
626 AML_NOTSERIALIZED);
627 {
628 Aml *proximity = aml_name(MEMORY_SLOT_PROXIMITY);
629
630 aml_append(method, aml_acquire(ctrl_lock, 0xFFFF));
631 aml_append(method, aml_store(aml_to_integer(slot_arg0),
632 slot_selector));
633 aml_append(method, aml_store(proximity, ret_val));
634 aml_append(method, aml_release(ctrl_lock));
635 aml_append(method, aml_return(ret_val));
636 }
637 aml_append(dev_container, method);
638
639 method = aml_method(MEMORY_SLOT_OST_METHOD, 4, AML_NOTSERIALIZED);
640 {
641 Aml *ost_evt = aml_name(MEMORY_SLOT_OST_EVENT);
642 Aml *ost_status = aml_name(MEMORY_SLOT_OST_STATUS);
643
644 aml_append(method, aml_acquire(ctrl_lock, 0xFFFF));
645 aml_append(method, aml_store(aml_to_integer(slot_arg0),
646 slot_selector));
647 aml_append(method, aml_store(aml_arg(1), ost_evt));
648 aml_append(method, aml_store(aml_arg(2), ost_status));
649 aml_append(method, aml_release(ctrl_lock));
650 }
651 aml_append(dev_container, method);
652
653 method = aml_method(MEMORY_SLOT_EJECT_METHOD, 2, AML_NOTSERIALIZED);
654 {
655 Aml *eject = aml_name(MEMORY_SLOT_EJECT);
656
657 aml_append(method, aml_acquire(ctrl_lock, 0xFFFF));
658 aml_append(method, aml_store(aml_to_integer(slot_arg0),
659 slot_selector));
660 aml_append(method, aml_store(one, eject));
661 aml_append(method, aml_release(ctrl_lock));
662 }
663 aml_append(dev_container, method);
664
665 /* build memory devices */
666 for (i = 0; i < nr_mem; i++) {
667 Aml *dev;
668 const char *s;
669
670 dev = aml_device("MP%02X", i);
671 aml_append(dev, aml_name_decl("_UID", aml_string("0x%02X", i)));
672 aml_append(dev, aml_name_decl("_HID", aml_eisaid("PNP0C80")));
673
674 method = aml_method("_CRS", 0, AML_NOTSERIALIZED);
675 s = MEMORY_SLOT_CRS_METHOD;
676 aml_append(method, aml_return(aml_call1(s, aml_name("_UID"))));
677 aml_append(dev, method);
678
679 method = aml_method("_STA", 0, AML_NOTSERIALIZED);
680 s = MEMORY_SLOT_STATUS_METHOD;
681 aml_append(method, aml_return(aml_call1(s, aml_name("_UID"))));
682 aml_append(dev, method);
683
684 method = aml_method("_PXM", 0, AML_NOTSERIALIZED);
685 s = MEMORY_SLOT_PROXIMITY_METHOD;
686 aml_append(method, aml_return(aml_call1(s, aml_name("_UID"))));
687 aml_append(dev, method);
688
689 method = aml_method("_OST", 3, AML_NOTSERIALIZED);
690 s = MEMORY_SLOT_OST_METHOD;
691 aml_append(method,
692 aml_call4(s, aml_name("_UID"), aml_arg(0),
693 aml_arg(1), aml_arg(2)));
694 aml_append(dev, method);
695
696 method = aml_method("_EJ0", 1, AML_NOTSERIALIZED);
697 s = MEMORY_SLOT_EJECT_METHOD;
698 aml_append(method,
699 aml_call2(s, aml_name("_UID"), aml_arg(0)));
700 aml_append(dev, method);
701
702 aml_append(dev_container, dev);
703 }
704
705 /* build Method(MEMORY_SLOT_NOTIFY_METHOD, 2) {
706 * If (LEqual(Arg0, 0x00)) {Notify(MP00, Arg1)} ... }
707 */
708 method = aml_method(MEMORY_SLOT_NOTIFY_METHOD, 2, AML_NOTSERIALIZED);
709 for (i = 0; i < nr_mem; i++) {
710 ifctx = aml_if(aml_equal(aml_arg(0), aml_int(i)));
711 aml_append(ifctx,
712 aml_notify(aml_name("MP%.02X", i), aml_arg(1))
713 );
714 aml_append(method, ifctx);
715 }
716 aml_append(dev_container, method);
717 }
718 aml_append(table, dev_container);
719
720 method = aml_method(event_handler_method, 0, AML_NOTSERIALIZED);
721 aml_append(method,
722 aml_call0(MEMORY_DEVICES_CONTAINER "." MEMORY_SLOT_SCAN_METHOD));
723 aml_append(table, method);
724
725 g_free(mhp_res_path);
726}
727