@@ -21,6 +21,7 @@
#include "hw/mem/dimm.h"
#include "qemu/config-file.h"
#include "qapi/visitor.h"
+#include "qemu/bitmap.h"
static void dimm_bus_initfn(Object *obj)
{
@@ -28,6 +29,45 @@ static void dimm_bus_initfn(Object *obj)
b->allow_hotplug = true;
}
+
+static int dimm_bus_slot2bitmap(DeviceState *dev, void *opaque)
+{
+ unsigned long *bitmap = opaque;
+ BusClass *bc = BUS_GET_CLASS(qdev_get_parent_bus(dev));
+ DimmDevice *d = DIMM(dev);
+
+ if (dev->realized) { /* count only realized DIMMs */
+ g_assert(d->slot < bc->max_dev);
+ set_bit(d->slot, bitmap);
+ }
+ return 0;
+}
+
+static int dimm_bus_get_free_slot(DimmBus *bus, const int *hint, Error **errp)
+{
+ BusClass *bc = BUS_GET_CLASS(bus);
+ unsigned long *bitmap = bitmap_new(bc->max_dev);
+ int slot = 0;
+
+ qbus_walk_children(BUS(bus), dimm_bus_slot2bitmap, NULL, bitmap);
+
+ /* check if requested slot is not occupied */
+ if (hint) {
+ if (!test_bit(*hint, bitmap)) {
+ slot = *hint;
+ } else {
+ error_setg(errp, "slot %d is busy", *hint);
+ }
+ goto out;
+ }
+
+ /* search for free slot */
+ slot = find_first_zero_bit(bitmap, bc->max_dev);
+out:
+ g_free(bitmap);
+ return slot;
+}
+
static void dimm_bus_register_memory(DimmBus *bus, DimmDevice *dimm,
Error **errp)
{
@@ -43,6 +83,7 @@ static void dimm_bus_class_init(ObjectClass *oc, void *data)
bc->max_dev = qemu_opt_get_number(opts, "slots", 0);
dbc->register_memory = dimm_bus_register_memory;
+ dbc->get_free_slot = dimm_bus_get_free_slot;
}
static const TypeInfo dimm_bus_info = {
@@ -57,7 +98,7 @@ static const TypeInfo dimm_bus_info = {
static Property dimm_properties[] = {
DEFINE_PROP_UINT64("start", DimmDevice, start, 0),
DEFINE_PROP_UINT32("node", DimmDevice, node, 0),
- DEFINE_PROP_INT32("slot", DimmDevice, slot, 0),
+ DEFINE_PROP_INT32("slot", DimmDevice, slot, -1),
DEFINE_PROP_END_OF_LIST(),
};
@@ -132,6 +173,7 @@ static void dimm_realize(DeviceState *dev, Error **errp)
DimmBus *bus = DIMM_BUS(qdev_get_parent_bus(dev));
BusClass *bc = BUS_GET_CLASS(bus);
DimmBusClass *dbc = DIMM_BUS_GET_CLASS(bus);
+ int *slot_hint;
if (!dimm->mr) {
error_setg(errp, "'memdev' property is not set");
@@ -147,6 +189,13 @@ static void dimm_realize(DeviceState *dev, Error **errp)
error_setg(errp, "maximum allowed slot is: %d", bc->max_dev - 1);
return;
}
+ g_assert(dbc->get_free_slot);
+ slot_hint = dimm->slot < 0 ? NULL : &dimm->slot;
+ dimm->slot = dbc->get_free_slot(bus, slot_hint, errp);
+ if (error_is_set(errp)) {
+ return;
+ }
+
g_assert(dbc->register_memory);
dbc->register_memory(bus, dimm, errp);
@@ -75,11 +75,15 @@ typedef struct DimmBus {
/**
* DimmBusClass:
* @parent_class: opaque parent class container
+ * @get_free_slot: returns a not occupied slot number. If @hint is provided,
+ * it tries to return slot specified by @hint if it's not busy or returns
+ * error in @errp.
* @register_memory: map @DimmDevice into hot-plugable address space
*/
typedef struct DimmBusClass {
BusClass parent_class;
+ int (*get_free_slot)(DimmBus *bus, const int *hint, Error **errp);
void (*register_memory)(DimmBus *bus, DimmDevice *dimm, Error **errp);
} DimmBusClass;
- if slot property is not specified on -device/device_add command, treat default value as request for assigning DimmDevice to the first free slot. - if slot is provided with -device/device_add command, attempt to use it or fail command if it's already occupied. Signed-off-by: Igor Mammedov <imammedo@redhat.com> --- v2: s/dc/dbc/ --- hw/mem/dimm.c | 51 ++++++++++++++++++++++++++++++++++++++++++++++++- include/hw/mem/dimm.h | 4 +++ 2 files changed, 54 insertions(+), 1 deletions(-)