[RFC PATCH 4/9] Implement memslot device abstraction

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]


 Each hotplug-able memory slot is a SysBusDevice. All memslots are initially
 unpopulated. A hot-add operation for a particular memory slot creates a new
 MemoryRegion of the given physical address offset, size and node proximity,
 and attaches it to main system memory as a sub_region. A hot-remove operation
 detaches and frees the MemoryRegion from system memory.

 This is an early prototype and lacks proper qdev integration: a separate
 hotplug mechanism/side-channel is used and main system bus hotplug
 capability is ignored.

Signed-off-by: Vasilis Liaskovitis <vasilis.liaskovitis@xxxxxxxxxxxxxxxx>
---
 hw/memslot.c |  195 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
 hw/memslot.h |   44 +++++++++++++
 2 files changed, 239 insertions(+), 0 deletions(-)
 create mode 100644 hw/memslot.c
 create mode 100644 hw/memslot.h

diff --git a/hw/memslot.c b/hw/memslot.c
new file mode 100644
index 0000000..b100824
--- /dev/null
+++ b/hw/memslot.c
@@ -0,0 +1,195 @@
+/*
+ * MemorySlot device for Memory Hotplug
+ *
+ * Copyright ProfitBricks GmbH 2012
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, see <http://www.gnu.org/licenses/>
+ */
+
+#include "trace.h"
+#include "qdev.h"
+#include "memslot.h"
+#include "../exec-memory.h"
+
+static DeviceState *memslot_hotplug_qdev;
+static memslot_hotplug_fn memslot_hotplug;
+
+static Property memslot_properties[] = {
+    DEFINE_PROP_END_OF_LIST()
+};
+
+void memslot_populate(MemSlotState *s)
+{
+    char buf[32];
+    MemoryRegion *new = NULL;
+
+    sprintf(buf, "memslot%u", s->idx);
+    new = g_malloc(sizeof(MemoryRegion));
+    memory_region_init_ram(new, buf, s->size);
+    vmstate_register_ram_global(new);
+    memory_region_add_subregion(get_system_memory(), s->start, new);
+    s->mr = new;
+    s->populated = 1;
+}
+
+void memslot_depopulate(MemSlotState *s)
+{
+    assert(s);
+    if (s->populated) {
+        vmstate_unregister_ram(s->mr, NULL);
+        memory_region_del_subregion(get_system_memory(), s->mr);
+        memory_region_destroy(s->mr);
+        s->populated = 0;
+        s->mr = NULL;
+    }
+}
+
+MemSlotState *memslot_create(char *id, target_phys_addr_t start, uint64_t size,
+        uint64_t node, uint32_t memslot_idx)
+{
+    DeviceState *dev;
+    MemSlotState *mdev;
+
+    dev = sysbus_create_simple("memslot", -1, NULL);
+    dev->id = id;
+
+    mdev = MEMSLOT(dev);
+    mdev->idx = memslot_idx;
+    mdev->start = start;
+    mdev->size = size;
+    mdev->node = node;
+
+    return mdev;
+}
+
+void memslot_register_hotplug(memslot_hotplug_fn hotplug, DeviceState *qdev)
+{
+    memslot_hotplug_qdev = qdev;
+    memslot_hotplug = hotplug;
+}
+
+static MemSlotState *memslot_find(char *id)
+{
+    DeviceState *qdev;
+    qdev = qdev_find_recursive(sysbus_get_default(), id);
+    if (qdev)
+        return MEMSLOT(qdev);
+    return NULL;
+}
+
+int memslot_do(Monitor *mon, const QDict *qdict)
+{
+    MemSlotState *slot = NULL;
+
+    char *id = (char*) qdict_get_try_str(qdict, "id");
+    if (!id) {
+        fprintf(stderr, "ERROR %s invalid id\n",__FUNCTION__);
+        return 1;
+    }
+
+    slot = memslot_find(id);
+
+    if (!slot) {
+        fprintf(stderr, "%s no slot %s found\n", __FUNCTION__, id);
+        return 1;
+    }
+
+    char *action = (char*) qdict_get_try_str(qdict, "action");
+    if (!action || (strcmp(action, "add") && strcmp(action, "delete"))) {
+        fprintf(stderr, "ERROR %s invalid action\n", __FUNCTION__);
+        return 1;
+    }
+
+    if (!strcmp(action, "add")) {
+        if (slot->populated) {
+            fprintf(stderr, "ERROR %s slot %s already populated\n",
+                    __FUNCTION__, id);
+            return 1;
+        }
+        memslot_populate(slot);
+        if (memslot_hotplug)
+            memslot_hotplug(memslot_hotplug_qdev, (SysBusDevice*)slot, 1);
+    }
+    else {
+        if (!slot->populated) {
+            fprintf(stderr, "ERROR %s slot %s is not populated\n",
+                    __FUNCTION__, id);
+            return 1;
+        }
+        if (memslot_hotplug)
+            memslot_hotplug(memslot_hotplug_qdev, (SysBusDevice*)slot, 0);
+    }
+    return 0;
+}
+
+MemSlotState *memslot_find_from_idx(uint32_t idx)
+{
+    Error *err = NULL;
+    DeviceState *dev;
+    MemSlotState *slot;
+    char *type;
+    BusState *bus = sysbus_get_default();
+    QTAILQ_FOREACH(dev, &bus->children, sibling) {
+        type = object_property_get_str(OBJECT(dev), "type", &err);
+        if (err) {
+            error_free(err);
+            fprintf(stderr, "error getting device type\n");
+            return NULL;
+        }
+        if (!strcmp(type, "memslot")) {
+            slot = MEMSLOT(dev);
+            if (slot->idx == idx) {
+                fprintf(stderr, "%s found slot with idx %u : %p\n",
+                        __FUNCTION__, idx, slot);
+                return slot;
+            }
+            else
+                fprintf(stderr, "%s slot with idx %u !=  %u\n", __FUNCTION__,
+                        slot->idx, idx);
+        }
+    }
+    return NULL;
+}
+
+static int memslot_init(SysBusDevice *s)
+{
+    MemSlotState *slot;
+    slot = MEMSLOT(s);
+    slot->mr = NULL;
+    slot->populated = 0;
+    return 0;
+}
+
+static void memslot_class_init(ObjectClass *klass, void *data)
+{
+    SysBusDeviceClass *sc = SYS_BUS_DEVICE_CLASS(klass);
+    DeviceClass *dc = DEVICE_CLASS(klass);
+
+    dc->props = memslot_properties;
+    sc->init = memslot_init;
+    memslot_hotplug = NULL;
+}
+
+static TypeInfo memslot_info = {
+    .name          = "memslot",
+    .parent        = TYPE_SYS_BUS_DEVICE,
+    .instance_size = sizeof(MemSlotState),
+    .class_init    = memslot_class_init,
+};
+
+static void memslot_register_types(void)
+{
+    type_register_static(&memslot_info);
+}
+
+type_init(memslot_register_types)
diff --git a/hw/memslot.h b/hw/memslot.h
new file mode 100644
index 0000000..9412667
--- /dev/null
+++ b/hw/memslot.h
@@ -0,0 +1,44 @@
+#ifndef QEMU_MEM_H
+#define QEMU_MEM_H
+
+#include "qemu-common.h"
+#include "memory.h"
+#include "sysbus.h"
+
+#define TYPE_MEMSLOT "memslot"
+#define MEMSLOT(obj) \
+    OBJECT_CHECK(MemSlotState, (obj), TYPE_MEMSLOT)
+#define MEMSLOT_CLASS(klass) \
+    OBJECT_CLASS_CHECK(MemSlotClass, (obj), TYPE_MEMSLOT)
+#define MEMSLOT_GET_CLASS(obj) \
+    OBJECT_GET_CLASS(MemSlotClass, (obj), TYPE_MEMSLOT)
+
+typedef struct MemSlotState {
+    SysBusDevice busdev;
+    uint32_t populated; /* 1 means device has been hotplugged. Default is 0. */
+    uint32_t idx; /* index in memory hotplug register/bitmap */
+    uint64_t start; /* starting physical address */
+    uint64_t size;
+    uint32_t node; /* numa node proximity */
+    MemoryRegion *mr; /* MemoryRegion for this slot. !NULL only if populated */
+} MemSlotState;
+
+typedef struct MemSlotClass
+{
+    SysBusDeviceClass parent_class;
+    void (*set)(MemSlotState *s, MemoryRegion *mem);
+} MemSlotClass;
+
+/* mem.c */
+
+typedef int (*memslot_hotplug_fn)(DeviceState *qdev, SysBusDevice *dev, int add);
+
+MemSlotState *memslot_create(char *id, target_phys_addr_t start, uint64_t size,
+        uint64_t node, uint32_t memslot_idx);
+void memslot_populate(MemSlotState *s);
+void memslot_depopulate(MemSlotState *s);
+int memslot_do(Monitor *mon, const QDict *qdict);
+MemSlotState *memslot_find_from_idx(uint32_t idx);
+void memslot_register_hotplug(memslot_hotplug_fn hotplug, DeviceState *qdev);
+
+#endif
-- 
1.7.9

--
To unsubscribe from this list: send the line "unsubscribe kvm" in
the body of a message to majordomo@xxxxxxxxxxxxxxx
More majordomo info at  http://vger.kernel.org/majordomo-info.html


[KVM ARM]     [KVM ia64]     [KVM ppc]     [Spice Development]     [Libvirt]     [Libvirt Users]     [Linux USB Devel]     [Video for Linux]     [Linux Audio Users]     [Photo]     [Yosemite News]    [Yosemite Photos]    [Linux Kernel]     [Linux SCSI]     [XFree86]

Add to Google Powered by Linux