2 * Memory hotplug AML code of DSDT ACPI table
4 * Copyright (C) 2015 Red Hat Inc
6 * Author: Igor Mammedov <imammedo@redhat.com>
8 * This work is licensed under the terms of the GNU GPL, version 2 or later.
9 * See the COPYING file in the top-level directory.
12 #include "qemu/osdep.h"
13 #include "hw/acpi/memory_hotplug.h"
14 #include "include/hw/acpi/pc-hotplug.h"
15 #include "hw/boards.h"
17 void build_memory_hotplug_aml(Aml
*ctx
, uint32_t nr_mem
,
18 uint16_t io_base
, uint16_t io_len
)
25 /* scope for memory hotplug controller device node */
26 pci_scope
= aml_scope("_SB.PCI0");
27 mem_ctrl_dev
= aml_device(MEMORY_HOTPLUG_DEVICE
);
29 Aml
*one
= aml_int(1);
30 Aml
*zero
= aml_int(0);
31 Aml
*ret_val
= aml_local(0);
32 Aml
*slot_arg0
= aml_arg(0);
33 Aml
*slots_nr
= aml_name(MEMORY_SLOTS_NUMBER
);
34 Aml
*ctrl_lock
= aml_name(MEMORY_SLOT_LOCK
);
35 Aml
*slot_selector
= aml_name(MEMORY_SLOT_SLECTOR
);
37 aml_append(mem_ctrl_dev
, aml_name_decl("_HID", aml_string("PNP0A06")));
38 aml_append(mem_ctrl_dev
,
39 aml_name_decl("_UID", aml_string("Memory hotplug resources")));
41 method
= aml_method("_STA", 0, AML_NOTSERIALIZED
);
42 ifctx
= aml_if(aml_equal(slots_nr
, zero
));
44 aml_append(ifctx
, aml_return(zero
));
46 aml_append(method
, ifctx
);
47 /* present, functioning, decoding, not shown in UI */
48 aml_append(method
, aml_return(aml_int(0xB)));
49 aml_append(mem_ctrl_dev
, method
);
51 aml_append(mem_ctrl_dev
, aml_mutex(MEMORY_SLOT_LOCK
, 0));
53 method
= aml_method(MEMORY_SLOT_SCAN_METHOD
, 0, AML_NOTSERIALIZED
);
57 Aml
*idx
= aml_local(0);
58 Aml
*eject_req
= aml_int(3);
59 Aml
*dev_chk
= aml_int(1);
61 ifctx
= aml_if(aml_equal(slots_nr
, zero
));
63 aml_append(ifctx
, aml_return(zero
));
65 aml_append(method
, ifctx
);
67 aml_append(method
, aml_store(zero
, idx
));
68 aml_append(method
, aml_acquire(ctrl_lock
, 0xFFFF));
70 * loops over all slots and Notifies DIMMs with
71 * Device Check or Eject Request notifications if
72 * slot has corresponding status bit set and clears
75 while_ctx
= aml_while(aml_lless(idx
, slots_nr
));
77 Aml
*ins_evt
= aml_name(MEMORY_SLOT_INSERT_EVENT
);
78 Aml
*rm_evt
= aml_name(MEMORY_SLOT_REMOVE_EVENT
);
80 aml_append(while_ctx
, aml_store(idx
, slot_selector
));
81 ifctx
= aml_if(aml_equal(ins_evt
, one
));
84 aml_call2(MEMORY_SLOT_NOTIFY_METHOD
,
86 aml_append(ifctx
, aml_store(one
, ins_evt
));
88 aml_append(while_ctx
, ifctx
);
90 else_ctx
= aml_else();
91 ifctx
= aml_if(aml_equal(rm_evt
, one
));
94 aml_call2(MEMORY_SLOT_NOTIFY_METHOD
,
96 aml_append(ifctx
, aml_store(one
, rm_evt
));
98 aml_append(else_ctx
, ifctx
);
99 aml_append(while_ctx
, else_ctx
);
101 aml_append(while_ctx
, aml_add(idx
, one
, idx
));
103 aml_append(method
, while_ctx
);
104 aml_append(method
, aml_release(ctrl_lock
));
105 aml_append(method
, aml_return(one
));
107 aml_append(mem_ctrl_dev
, method
);
109 method
= aml_method(MEMORY_SLOT_STATUS_METHOD
, 1, AML_NOTSERIALIZED
);
111 Aml
*slot_enabled
= aml_name(MEMORY_SLOT_ENABLED
);
113 aml_append(method
, aml_store(zero
, ret_val
));
114 aml_append(method
, aml_acquire(ctrl_lock
, 0xFFFF));
116 aml_store(aml_to_integer(slot_arg0
), slot_selector
));
118 ifctx
= aml_if(aml_equal(slot_enabled
, one
));
120 aml_append(ifctx
, aml_store(aml_int(0xF), ret_val
));
122 aml_append(method
, ifctx
);
124 aml_append(method
, aml_release(ctrl_lock
));
125 aml_append(method
, aml_return(ret_val
));
127 aml_append(mem_ctrl_dev
, method
);
129 method
= aml_method(MEMORY_SLOT_CRS_METHOD
, 1, AML_SERIALIZED
);
131 Aml
*mr64
= aml_name("MR64");
132 Aml
*mr32
= aml_name("MR32");
133 Aml
*crs_tmpl
= aml_resource_template();
134 Aml
*minl
= aml_name("MINL");
135 Aml
*minh
= aml_name("MINH");
136 Aml
*maxl
= aml_name("MAXL");
137 Aml
*maxh
= aml_name("MAXH");
138 Aml
*lenl
= aml_name("LENL");
139 Aml
*lenh
= aml_name("LENH");
141 aml_append(method
, aml_acquire(ctrl_lock
, 0xFFFF));
142 aml_append(method
, aml_store(aml_to_integer(slot_arg0
),
146 aml_qword_memory(AML_POS_DECODE
, AML_MIN_FIXED
, AML_MAX_FIXED
,
147 AML_CACHEABLE
, AML_READ_WRITE
,
148 0, 0x0, 0xFFFFFFFFFFFFFFFEULL
, 0,
149 0xFFFFFFFFFFFFFFFFULL
));
150 aml_append(method
, aml_name_decl("MR64", crs_tmpl
));
152 aml_create_dword_field(mr64
, aml_int(14), "MINL"));
154 aml_create_dword_field(mr64
, aml_int(18), "MINH"));
156 aml_create_dword_field(mr64
, aml_int(38), "LENL"));
158 aml_create_dword_field(mr64
, aml_int(42), "LENH"));
160 aml_create_dword_field(mr64
, aml_int(22), "MAXL"));
162 aml_create_dword_field(mr64
, aml_int(26), "MAXH"));
165 aml_store(aml_name(MEMORY_SLOT_ADDR_HIGH
), minh
));
167 aml_store(aml_name(MEMORY_SLOT_ADDR_LOW
), minl
));
169 aml_store(aml_name(MEMORY_SLOT_SIZE_HIGH
), lenh
));
171 aml_store(aml_name(MEMORY_SLOT_SIZE_LOW
), lenl
));
173 /* 64-bit math: MAX = MIN + LEN - 1 */
174 aml_append(method
, aml_add(minl
, lenl
, maxl
));
175 aml_append(method
, aml_add(minh
, lenh
, maxh
));
176 ifctx
= aml_if(aml_lless(maxl
, minl
));
178 aml_append(ifctx
, aml_add(maxh
, one
, maxh
));
180 aml_append(method
, ifctx
);
181 ifctx
= aml_if(aml_lless(maxl
, one
));
183 aml_append(ifctx
, aml_subtract(maxh
, one
, maxh
));
185 aml_append(method
, ifctx
);
186 aml_append(method
, aml_subtract(maxl
, one
, maxl
));
188 /* return 32-bit _CRS if addr/size is in low mem */
189 /* TODO: remove it since all hotplugged DIMMs are in high mem */
190 ifctx
= aml_if(aml_equal(maxh
, zero
));
192 crs_tmpl
= aml_resource_template();
194 aml_dword_memory(AML_POS_DECODE
, AML_MIN_FIXED
,
195 AML_MAX_FIXED
, AML_CACHEABLE
,
197 0, 0x0, 0xFFFFFFFE, 0,
199 aml_append(ifctx
, aml_name_decl("MR32", crs_tmpl
));
201 aml_create_dword_field(mr32
, aml_int(10), "MIN"));
203 aml_create_dword_field(mr32
, aml_int(14), "MAX"));
205 aml_create_dword_field(mr32
, aml_int(22), "LEN"));
206 aml_append(ifctx
, aml_store(minl
, aml_name("MIN")));
207 aml_append(ifctx
, aml_store(maxl
, aml_name("MAX")));
208 aml_append(ifctx
, aml_store(lenl
, aml_name("LEN")));
210 aml_append(ifctx
, aml_release(ctrl_lock
));
211 aml_append(ifctx
, aml_return(mr32
));
213 aml_append(method
, ifctx
);
215 aml_append(method
, aml_release(ctrl_lock
));
216 aml_append(method
, aml_return(mr64
));
218 aml_append(mem_ctrl_dev
, method
);
220 method
= aml_method(MEMORY_SLOT_PROXIMITY_METHOD
, 1,
223 Aml
*proximity
= aml_name(MEMORY_SLOT_PROXIMITY
);
225 aml_append(method
, aml_acquire(ctrl_lock
, 0xFFFF));
226 aml_append(method
, aml_store(aml_to_integer(slot_arg0
),
228 aml_append(method
, aml_store(proximity
, ret_val
));
229 aml_append(method
, aml_release(ctrl_lock
));
230 aml_append(method
, aml_return(ret_val
));
232 aml_append(mem_ctrl_dev
, method
);
234 method
= aml_method(MEMORY_SLOT_OST_METHOD
, 4, AML_NOTSERIALIZED
);
236 Aml
*ost_evt
= aml_name(MEMORY_SLOT_OST_EVENT
);
237 Aml
*ost_status
= aml_name(MEMORY_SLOT_OST_STATUS
);
239 aml_append(method
, aml_acquire(ctrl_lock
, 0xFFFF));
240 aml_append(method
, aml_store(aml_to_integer(slot_arg0
),
242 aml_append(method
, aml_store(aml_arg(1), ost_evt
));
243 aml_append(method
, aml_store(aml_arg(2), ost_status
));
244 aml_append(method
, aml_release(ctrl_lock
));
246 aml_append(mem_ctrl_dev
, method
);
248 method
= aml_method(MEMORY_SLOT_EJECT_METHOD
, 2, AML_NOTSERIALIZED
);
250 Aml
*eject
= aml_name(MEMORY_SLOT_EJECT
);
252 aml_append(method
, aml_acquire(ctrl_lock
, 0xFFFF));
253 aml_append(method
, aml_store(aml_to_integer(slot_arg0
),
255 aml_append(method
, aml_store(one
, eject
));
256 aml_append(method
, aml_release(ctrl_lock
));
258 aml_append(mem_ctrl_dev
, method
);
260 aml_append(pci_scope
, mem_ctrl_dev
);
261 aml_append(ctx
, pci_scope
);