From patchwork Thu Apr 19 14:08:42 2012 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Vasilis Liaskovitis X-Patchwork-Id: 153827 Return-Path: X-Original-To: incoming@patchwork.ozlabs.org Delivered-To: patchwork-incoming@bilbo.ozlabs.org Received: from lists.gnu.org (lists.gnu.org [208.118.235.17]) (using TLSv1 with cipher AES256-SHA (256/256 bits)) (Client did not present a certificate) by ozlabs.org (Postfix) with ESMTPS id 36B7DB6FE6 for ; Fri, 20 Apr 2012 02:04:42 +1000 (EST) Received: from localhost ([::1]:36121 helo=lists.gnu.org) by lists.gnu.org with esmtp (Exim 4.71) (envelope-from ) id 1SKs4U-0001bj-C7 for incoming@patchwork.ozlabs.org; Thu, 19 Apr 2012 10:10:54 -0400 Received: from eggs.gnu.org ([208.118.235.92]:37520) by lists.gnu.org with esmtp (Exim 4.71) (envelope-from ) id 1SKs3i-0008Cr-7g for qemu-devel@nongnu.org; Thu, 19 Apr 2012 10:10:11 -0400 Received: from Debian-exim by eggs.gnu.org with spam-scanned (Exim 4.71) (envelope-from ) id 1SKs3b-0005we-Hp for qemu-devel@nongnu.org; Thu, 19 Apr 2012 10:10:05 -0400 Received: from mail-bk0-f45.google.com ([209.85.214.45]:55442) by eggs.gnu.org with esmtp (Exim 4.71) (envelope-from ) id 1SKs3b-0005mG-76 for qemu-devel@nongnu.org; Thu, 19 Apr 2012 10:09:59 -0400 Received: by mail-bk0-f45.google.com with SMTP id ji1so416382bkc.4 for ; Thu, 19 Apr 2012 07:09:58 -0700 (PDT) X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=google.com; s=20120113; h=from:to:cc:subject:date:message-id:x-mailer:in-reply-to:references :x-gm-message-state; bh=Ni5MbzBqg2JgThdfltsrgPvTTH+7rMr0DfKRwK5I4lk=; b=TBxVunSsfDEHxYs8M0iQMlZO0L8rSNAcd0E394HrAZHYmzkDP2bAEhsfa8ewA3H9aK azZsCO6OKfsy7SwhRZ68T/m2ndVXyyfbu41rfbWLA3/RMqs8+tiXpIXWyFzBrJTotv1+ TONaL3/Mjdo1HX8sFfuQ8otLETpe0WTiJKpTO4bHLmPoNa1wVBmxMZ3mCFM+wmb6vztt qmWpYAhAbuTldG2CSUiPoMG2p8NoyQ7FDTGmkD1NrDM8D30iq0fbQfqp5OkL6NNQDuHo N29cfvczeNVroMruonjoWqCPH3yKkWgjsBWkYdZMwRxMRVDkfzr0ipPlVZm5beUzKiFu SQ0w== Received: by 10.204.154.66 with SMTP id n2mr719023bkw.77.1334844598194; Thu, 19 Apr 2012 07:09:58 -0700 (PDT) Received: from dhcp-192-168-178-175.ri.profitbricks.localdomain ([62.217.45.26]) by mx.google.com with ESMTPS id gu12sm4434954bkc.1.2012.04.19.07.09.57 (version=TLSv1/SSLv3 cipher=OTHER); Thu, 19 Apr 2012 07:09:57 -0700 (PDT) From: Vasilis Liaskovitis To: qemu-devel@nongnu.org, kvm@vger.kernel.org, seabios@seabios.org Date: Thu, 19 Apr 2012 16:08:42 +0200 Message-Id: <1334844527-18869-5-git-send-email-vasilis.liaskovitis@profitbricks.com> X-Mailer: git-send-email 1.7.9 In-Reply-To: <1334844527-18869-1-git-send-email-vasilis.liaskovitis@profitbricks.com> References: <1334844527-18869-1-git-send-email-vasilis.liaskovitis@profitbricks.com> X-Gm-Message-State: ALoCoQlsXoWItDC6vOZ30+r8K4GRvYA0lWI0Q6T4Phmq6W7W1Nl5ceXLRlUopc+KombozSJZp78Z X-detected-operating-system: by eggs.gnu.org: Genre and OS details not recognized. X-Received-From: 209.85.214.45 Cc: Vasilis Liaskovitis , avi@redhat.com, gleb@redhat.com Subject: [Qemu-devel] [RFC PATCH 4/9] Implement memslot device abstraction X-BeenThere: qemu-devel@nongnu.org X-Mailman-Version: 2.1.14 Precedence: list List-Id: List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Errors-To: qemu-devel-bounces+incoming=patchwork.ozlabs.org@nongnu.org Sender: qemu-devel-bounces+incoming=patchwork.ozlabs.org@nongnu.org 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 --- 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 + */ + +#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