]> Git Repo - qemu.git/blob - hw/mem/pc-dimm.c
pc-dimm: factor out address search into MemoryDevice code
[qemu.git] / hw / mem / pc-dimm.c
1 /*
2  * Dimm device for Memory Hotplug
3  *
4  * Copyright ProfitBricks GmbH 2012
5  * Copyright (C) 2014 Red Hat Inc
6  *
7  * This library is free software; you can redistribute it and/or
8  * modify it under the terms of the GNU Lesser General Public
9  * License as published by the Free Software Foundation; either
10  * version 2 of the License, or (at your option) any later version.
11  *
12  * This library is distributed in the hope that it will be useful,
13  * but WITHOUT ANY WARRANTY; without even the implied warranty of
14  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
15  * Lesser General Public License for more details.
16  *
17  * You should have received a copy of the GNU Lesser General Public
18  * License along with this library; if not, see <http://www.gnu.org/licenses/>
19  */
20
21 #include "qemu/osdep.h"
22 #include "hw/mem/pc-dimm.h"
23 #include "hw/mem/nvdimm.h"
24 #include "hw/mem/memory-device.h"
25 #include "qapi/error.h"
26 #include "qapi/visitor.h"
27 #include "sysemu/numa.h"
28 #include "sysemu/kvm.h"
29 #include "trace.h"
30 #include "hw/virtio/vhost.h"
31
32 typedef struct pc_dimms_capacity {
33      uint64_t size;
34      Error    **errp;
35 } pc_dimms_capacity;
36
37 void pc_dimm_memory_plug(DeviceState *dev, MachineState *machine,
38                          uint64_t align, Error **errp)
39 {
40     int slot;
41     MemoryHotplugState *hpms = machine->device_memory;
42     PCDIMMDevice *dimm = PC_DIMM(dev);
43     PCDIMMDeviceClass *ddc = PC_DIMM_GET_CLASS(dimm);
44     MemoryRegion *vmstate_mr = ddc->get_vmstate_memory_region(dimm);
45     Error *local_err = NULL;
46     uint64_t existing_dimms_capacity = 0;
47     MemoryRegion *mr;
48     uint64_t addr;
49
50     mr = ddc->get_memory_region(dimm, &local_err);
51     if (local_err) {
52         goto out;
53     }
54
55     addr = object_property_get_uint(OBJECT(dimm),
56                                     PC_DIMM_ADDR_PROP, &local_err);
57     if (local_err) {
58         goto out;
59     }
60
61     addr = memory_device_get_free_addr(machine, !addr ? NULL : &addr, align,
62                                        memory_region_size(mr), &local_err);
63     if (local_err) {
64         goto out;
65     }
66
67     existing_dimms_capacity = pc_existing_dimms_capacity(&local_err);
68     if (local_err) {
69         goto out;
70     }
71
72     if (existing_dimms_capacity + memory_region_size(mr) >
73         machine->maxram_size - machine->ram_size) {
74         error_setg(&local_err, "not enough space, currently 0x%" PRIx64
75                    " in use of total hot pluggable 0x" RAM_ADDR_FMT,
76                    existing_dimms_capacity,
77                    machine->maxram_size - machine->ram_size);
78         goto out;
79     }
80
81     object_property_set_uint(OBJECT(dev), addr, PC_DIMM_ADDR_PROP, &local_err);
82     if (local_err) {
83         goto out;
84     }
85     trace_mhp_pc_dimm_assigned_address(addr);
86
87     slot = object_property_get_int(OBJECT(dev), PC_DIMM_SLOT_PROP, &local_err);
88     if (local_err) {
89         goto out;
90     }
91
92     slot = pc_dimm_get_free_slot(slot == PC_DIMM_UNASSIGNED_SLOT ? NULL : &slot,
93                                  machine->ram_slots, &local_err);
94     if (local_err) {
95         goto out;
96     }
97     object_property_set_int(OBJECT(dev), slot, PC_DIMM_SLOT_PROP, &local_err);
98     if (local_err) {
99         goto out;
100     }
101     trace_mhp_pc_dimm_assigned_slot(slot);
102
103     if (kvm_enabled() && !kvm_has_free_slot(machine)) {
104         error_setg(&local_err, "hypervisor has no free memory slots left");
105         goto out;
106     }
107
108     if (!vhost_has_free_slot()) {
109         error_setg(&local_err, "a used vhost backend has no free"
110                                " memory slots left");
111         goto out;
112     }
113
114     memory_region_add_subregion(&hpms->mr, addr - hpms->base, mr);
115     vmstate_register_ram(vmstate_mr, dev);
116
117 out:
118     error_propagate(errp, local_err);
119 }
120
121 void pc_dimm_memory_unplug(DeviceState *dev, MachineState *machine)
122 {
123     PCDIMMDevice *dimm = PC_DIMM(dev);
124     PCDIMMDeviceClass *ddc = PC_DIMM_GET_CLASS(dimm);
125     MemoryRegion *vmstate_mr = ddc->get_vmstate_memory_region(dimm);
126     MemoryRegion *mr = ddc->get_memory_region(dimm, &error_abort);
127
128     memory_region_del_subregion(&machine->device_memory->mr, mr);
129     vmstate_unregister_ram(vmstate_mr, dev);
130 }
131
132 static int pc_existing_dimms_capacity_internal(Object *obj, void *opaque)
133 {
134     pc_dimms_capacity *cap = opaque;
135     uint64_t *size = &cap->size;
136
137     if (object_dynamic_cast(obj, TYPE_PC_DIMM)) {
138         DeviceState *dev = DEVICE(obj);
139
140         if (dev->realized) {
141             (*size) += object_property_get_uint(obj, PC_DIMM_SIZE_PROP,
142                 cap->errp);
143         }
144
145         if (cap->errp && *cap->errp) {
146             return 1;
147         }
148     }
149     object_child_foreach(obj, pc_existing_dimms_capacity_internal, opaque);
150     return 0;
151 }
152
153 uint64_t pc_existing_dimms_capacity(Error **errp)
154 {
155     pc_dimms_capacity cap;
156
157     cap.size = 0;
158     cap.errp = errp;
159
160     pc_existing_dimms_capacity_internal(qdev_get_machine(), &cap);
161     return cap.size;
162 }
163
164 static int pc_dimm_slot2bitmap(Object *obj, void *opaque)
165 {
166     unsigned long *bitmap = opaque;
167
168     if (object_dynamic_cast(obj, TYPE_PC_DIMM)) {
169         DeviceState *dev = DEVICE(obj);
170         if (dev->realized) { /* count only realized DIMMs */
171             PCDIMMDevice *d = PC_DIMM(obj);
172             set_bit(d->slot, bitmap);
173         }
174     }
175
176     object_child_foreach(obj, pc_dimm_slot2bitmap, opaque);
177     return 0;
178 }
179
180 int pc_dimm_get_free_slot(const int *hint, int max_slots, Error **errp)
181 {
182     unsigned long *bitmap = bitmap_new(max_slots);
183     int slot = 0;
184
185     object_child_foreach(qdev_get_machine(), pc_dimm_slot2bitmap, bitmap);
186
187     /* check if requested slot is not occupied */
188     if (hint) {
189         if (*hint >= max_slots) {
190             error_setg(errp, "invalid slot# %d, should be less than %d",
191                        *hint, max_slots);
192         } else if (!test_bit(*hint, bitmap)) {
193             slot = *hint;
194         } else {
195             error_setg(errp, "slot %d is busy", *hint);
196         }
197         goto out;
198     }
199
200     /* search for free slot */
201     slot = find_first_zero_bit(bitmap, max_slots);
202     if (slot == max_slots) {
203         error_setg(errp, "no free slots available");
204     }
205 out:
206     g_free(bitmap);
207     return slot;
208 }
209
210 static Property pc_dimm_properties[] = {
211     DEFINE_PROP_UINT64(PC_DIMM_ADDR_PROP, PCDIMMDevice, addr, 0),
212     DEFINE_PROP_UINT32(PC_DIMM_NODE_PROP, PCDIMMDevice, node, 0),
213     DEFINE_PROP_INT32(PC_DIMM_SLOT_PROP, PCDIMMDevice, slot,
214                       PC_DIMM_UNASSIGNED_SLOT),
215     DEFINE_PROP_LINK(PC_DIMM_MEMDEV_PROP, PCDIMMDevice, hostmem,
216                      TYPE_MEMORY_BACKEND, HostMemoryBackend *),
217     DEFINE_PROP_END_OF_LIST(),
218 };
219
220 static void pc_dimm_get_size(Object *obj, Visitor *v, const char *name,
221                              void *opaque, Error **errp)
222 {
223     uint64_t value;
224     MemoryRegion *mr;
225     PCDIMMDevice *dimm = PC_DIMM(obj);
226     PCDIMMDeviceClass *ddc = PC_DIMM_GET_CLASS(obj);
227
228     mr = ddc->get_memory_region(dimm, errp);
229     if (!mr) {
230         return;
231     }
232     value = memory_region_size(mr);
233
234     visit_type_uint64(v, name, &value, errp);
235 }
236
237 static void pc_dimm_init(Object *obj)
238 {
239     object_property_add(obj, PC_DIMM_SIZE_PROP, "uint64", pc_dimm_get_size,
240                         NULL, NULL, NULL, &error_abort);
241 }
242
243 static void pc_dimm_realize(DeviceState *dev, Error **errp)
244 {
245     PCDIMMDevice *dimm = PC_DIMM(dev);
246     PCDIMMDeviceClass *ddc = PC_DIMM_GET_CLASS(dimm);
247
248     if (!dimm->hostmem) {
249         error_setg(errp, "'" PC_DIMM_MEMDEV_PROP "' property is not set");
250         return;
251     } else if (host_memory_backend_is_mapped(dimm->hostmem)) {
252         char *path = object_get_canonical_path_component(OBJECT(dimm->hostmem));
253         error_setg(errp, "can't use already busy memdev: %s", path);
254         g_free(path);
255         return;
256     }
257     if (((nb_numa_nodes > 0) && (dimm->node >= nb_numa_nodes)) ||
258         (!nb_numa_nodes && dimm->node)) {
259         error_setg(errp, "'DIMM property " PC_DIMM_NODE_PROP " has value %"
260                    PRIu32 "' which exceeds the number of numa nodes: %d",
261                    dimm->node, nb_numa_nodes ? nb_numa_nodes : 1);
262         return;
263     }
264
265     if (ddc->realize) {
266         ddc->realize(dimm, errp);
267     }
268
269     host_memory_backend_set_mapped(dimm->hostmem, true);
270 }
271
272 static void pc_dimm_unrealize(DeviceState *dev, Error **errp)
273 {
274     PCDIMMDevice *dimm = PC_DIMM(dev);
275
276     host_memory_backend_set_mapped(dimm->hostmem, false);
277 }
278
279 static MemoryRegion *pc_dimm_get_memory_region(PCDIMMDevice *dimm, Error **errp)
280 {
281     if (!dimm->hostmem) {
282         error_setg(errp, "'" PC_DIMM_MEMDEV_PROP "' property must be set");
283         return NULL;
284     }
285
286     return host_memory_backend_get_memory(dimm->hostmem, errp);
287 }
288
289 static MemoryRegion *pc_dimm_get_vmstate_memory_region(PCDIMMDevice *dimm)
290 {
291     return host_memory_backend_get_memory(dimm->hostmem, &error_abort);
292 }
293
294 static uint64_t pc_dimm_md_get_addr(const MemoryDeviceState *md)
295 {
296     const PCDIMMDevice *dimm = PC_DIMM(md);
297
298     return dimm->addr;
299 }
300
301 static uint64_t pc_dimm_md_get_region_size(const MemoryDeviceState *md)
302 {
303     /* dropping const here is fine as we don't touch the memory region */
304     PCDIMMDevice *dimm = PC_DIMM(md);
305     const PCDIMMDeviceClass *ddc = PC_DIMM_GET_CLASS(md);
306     MemoryRegion *mr;
307
308     mr = ddc->get_memory_region(dimm, &error_abort);
309     if (!mr) {
310         return 0;
311     }
312
313     return memory_region_size(mr);
314 }
315
316 static void pc_dimm_md_fill_device_info(const MemoryDeviceState *md,
317                                         MemoryDeviceInfo *info)
318 {
319     PCDIMMDeviceInfo *di = g_new0(PCDIMMDeviceInfo, 1);
320     const DeviceClass *dc = DEVICE_GET_CLASS(md);
321     const PCDIMMDevice *dimm = PC_DIMM(md);
322     const DeviceState *dev = DEVICE(md);
323
324     if (dev->id) {
325         di->has_id = true;
326         di->id = g_strdup(dev->id);
327     }
328     di->hotplugged = dev->hotplugged;
329     di->hotpluggable = dc->hotpluggable;
330     di->addr = dimm->addr;
331     di->slot = dimm->slot;
332     di->node = dimm->node;
333     di->size = object_property_get_uint(OBJECT(dimm), PC_DIMM_SIZE_PROP,
334                                         NULL);
335     di->memdev = object_get_canonical_path(OBJECT(dimm->hostmem));
336
337     if (object_dynamic_cast(OBJECT(dev), TYPE_NVDIMM)) {
338         info->u.nvdimm.data = di;
339         info->type = MEMORY_DEVICE_INFO_KIND_NVDIMM;
340     } else {
341         info->u.dimm.data = di;
342         info->type = MEMORY_DEVICE_INFO_KIND_DIMM;
343     }
344 }
345
346 static void pc_dimm_class_init(ObjectClass *oc, void *data)
347 {
348     DeviceClass *dc = DEVICE_CLASS(oc);
349     PCDIMMDeviceClass *ddc = PC_DIMM_CLASS(oc);
350     MemoryDeviceClass *mdc = MEMORY_DEVICE_CLASS(oc);
351
352     dc->realize = pc_dimm_realize;
353     dc->unrealize = pc_dimm_unrealize;
354     dc->props = pc_dimm_properties;
355     dc->desc = "DIMM memory module";
356
357     ddc->get_memory_region = pc_dimm_get_memory_region;
358     ddc->get_vmstate_memory_region = pc_dimm_get_vmstate_memory_region;
359
360     mdc->get_addr = pc_dimm_md_get_addr;
361     /* for a dimm plugged_size == region_size */
362     mdc->get_plugged_size = pc_dimm_md_get_region_size;
363     mdc->get_region_size = pc_dimm_md_get_region_size;
364     mdc->fill_device_info = pc_dimm_md_fill_device_info;
365 }
366
367 static TypeInfo pc_dimm_info = {
368     .name          = TYPE_PC_DIMM,
369     .parent        = TYPE_DEVICE,
370     .instance_size = sizeof(PCDIMMDevice),
371     .instance_init = pc_dimm_init,
372     .class_init    = pc_dimm_class_init,
373     .class_size    = sizeof(PCDIMMDeviceClass),
374     .interfaces = (InterfaceInfo[]) {
375         { TYPE_MEMORY_DEVICE },
376         { }
377     },
378 };
379
380 static void pc_dimm_register_types(void)
381 {
382     type_register_static(&pc_dimm_info);
383 }
384
385 type_init(pc_dimm_register_types)
This page took 0.045296 seconds and 4 git commands to generate.