From mboxrd@z Thu Jan 1 00:00:00 1970 From: Wen Congyang Subject: Re: [RFC PATCH v3 05/19] Implement dimm device abstraction Date: Mon, 24 Sep 2012 14:02:20 +0800 Message-ID: <505FF76C.5080600@cn.fujitsu.com> References: <1348226255-4226-1-git-send-email-vasilis.liaskovitis@profitbricks.com> <1348226255-4226-6-git-send-email-vasilis.liaskovitis@profitbricks.com> Mime-Version: 1.0 Content-Type: text/plain; charset=windows-1252 Content-Transfer-Encoding: QUOTED-PRINTABLE Cc: qemu-devel@nongnu.org, kvm@vger.kernel.org, seabios@seabios.org, avi@redhat.com, anthony@codemonkey.ws, kevin@koconnor.net, kraxel@redhat.com, eblake@redhat.com, blauwirbel@gmail.com, gleb@redhat.com, imammedo@redhat.com To: Vasilis Liaskovitis Return-path: Received: from cn.fujitsu.com ([222.73.24.84]:41685 "EHLO song.cn.fujitsu.com" rhost-flags-OK-FAIL-OK-OK) by vger.kernel.org with ESMTP id S1752080Ab2IXF4r convert rfc822-to-8bit (ORCPT ); Mon, 24 Sep 2012 01:56:47 -0400 In-Reply-To: <1348226255-4226-6-git-send-email-vasilis.liaskovitis@profitbricks.com> Sender: kvm-owner@vger.kernel.org List-ID: At 09/21/2012 07:17 PM, Vasilis Liaskovitis Wrote: > Each hotplug-able memory slot is a DimmDevice. All DimmDevices are at= tached > to a new bus called DimmBus. This bus is introduced so that we no lon= ger > depend on hotplug-capability of main system bus (the main bus does no= t allow > hotplugging). The DimmBus should be attached to a chipset Device (i44= 0fx in case > of the pc) >=20 > A hot-add operation for a particular dimm: > - creates a new DimmDevice and attaches it to the DimmBus > - creates a new MemoryRegion of the given physical address offset, si= ze and > node proximity, and attaches it to main system memory as a sub_region= =2E >=20 > A successful hot-remove operation detaches and frees the MemoryRegion= from > system memory, and removes the DimmDevice from the DimmBus. >=20 > Hotplug operations are done through normal device_add /device_del com= mands. > Also add properties to DimmDevice. >=20 > Signed-off-by: Vasilis Liaskovitis > --- > hw/dimm.c | 305 +++++++++++++++++++++++++++++++++++++++++++++++++++= ++++++++++ > hw/dimm.h | 90 ++++++++++++++++++ > 2 files changed, 395 insertions(+), 0 deletions(-) > create mode 100644 hw/dimm.c > create mode 100644 hw/dimm.h >=20 > diff --git a/hw/dimm.c b/hw/dimm.c > new file mode 100644 > index 0000000..288b997 > --- /dev/null > +++ b/hw/dimm.c > @@ -0,0 +1,305 @@ > +/* > + * Dimm 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 "dimm.h" > +#include > +#include "../exec-memory.h" > +#include "qmp-commands.h" > + > +/* the system-wide memory bus. */ > +static DimmBus *main_memory_bus; > +/* the following list is used to hold dimm config info before machin= e > + * initialization. After machine init, the list is emptied and not u= sed anymore.*/ > +static DimmConfiglist dimmconfig_list =3D QTAILQ_HEAD_INITIALIZER(di= mmconfig_list); > + > +static void dimmbus_dev_print(Monitor *mon, DeviceState *dev, int in= dent); > +static char *dimmbus_get_fw_dev_path(DeviceState *dev); > + > +static Property dimm_properties[] =3D { > + DEFINE_PROP_UINT64("start", DimmDevice, start, 0), > + DEFINE_PROP_UINT64("size", DimmDevice, size, DEFAULT_DIMMSIZE), > + DEFINE_PROP_UINT32("node", DimmDevice, node, 0), > + DEFINE_PROP_END_OF_LIST(), > +}; > + > +static void dimmbus_dev_print(Monitor *mon, DeviceState *dev, int in= dent) > +{ > +} > + > +static char *dimmbus_get_fw_dev_path(DeviceState *dev) > +{ > + char path[40]; > + > + snprintf(path, sizeof(path), "%s", qdev_fw_name(dev)); > + return strdup(path); > +} > + > +static void dimm_bus_class_init(ObjectClass *klass, void *data) > +{ > + BusClass *k =3D BUS_CLASS(klass); > + > + k->print_dev =3D dimmbus_dev_print; > + k->get_fw_dev_path =3D dimmbus_get_fw_dev_path; > +} > + > +static void dimm_bus_initfn(Object *obj) > +{ > + DimmConfig *dimm_cfg, *next_dimm_cfg; > + DimmBus *bus =3D DIMM_BUS(obj); > + QTAILQ_INIT(&bus->dimmconfig_list); > + QTAILQ_INIT(&bus->dimmlist); > + > + QTAILQ_FOREACH_SAFE(dimm_cfg, &dimmconfig_list, nextdimmcfg, nex= t_dimm_cfg) { > + QTAILQ_REMOVE(&dimmconfig_list, dimm_cfg, nextdimmcfg); > + QTAILQ_INSERT_TAIL(&bus->dimmconfig_list, dimm_cfg, nextdimm= cfg); > + } > +} > + > +static const TypeInfo dimm_bus_info =3D { > + .name =3D TYPE_DIMM_BUS, > + .parent =3D TYPE_BUS, > + .instance_size =3D sizeof(DimmBus), > + .instance_init =3D dimm_bus_initfn, > + .class_init =3D dimm_bus_class_init, > +}; > + > +void main_memory_bus_create(Object *parent) > +{ > + main_memory_bus =3D g_malloc0(dimm_bus_info.instance_size); > + main_memory_bus->qbus.glib_allocated =3D true; > + qbus_create_inplace(&main_memory_bus->qbus, TYPE_DIMM_BUS, DEVIC= E(parent), > + "membus"); > +} > + > +static void dimm_populate(DimmDevice *s) > +{ > + DeviceState *dev=3D (DeviceState*)s; > + MemoryRegion *new =3D NULL; > + > + new =3D g_malloc(sizeof(MemoryRegion)); > + memory_region_init_ram(new, dev->id, s->size); > + vmstate_register_ram_global(new); > + memory_region_add_subregion(get_system_memory(), s->start, new); > + s->mr =3D new; > +} > + > +static void dimm_depopulate(DimmDevice *s) > +{ > + assert(s); > + vmstate_unregister_ram(s->mr, NULL); > + memory_region_del_subregion(get_system_memory(), s->mr); > + memory_region_destroy(s->mr); > + s->mr =3D NULL; > +} > + > +void dimm_config_create(char *id, uint64_t size, uint64_t node, uint= 32_t > + dimm_idx, uint32_t populated) > +{ > + DimmConfig *dimm_cfg; > + dimm_cfg =3D (DimmConfig*) g_malloc0(sizeof(DimmConfig)); > + dimm_cfg->name =3D id; > + dimm_cfg->idx =3D dimm_idx; > + dimm_cfg->start =3D 0; > + dimm_cfg->size =3D size; > + dimm_cfg->node =3D node; > + dimm_cfg->populated =3D populated; > + > + QTAILQ_INSERT_TAIL(&dimmconfig_list, dimm_cfg, nextdimmcfg); > +} > + > +void dimm_bus_hotplug(dimm_hotplug_fn hotplug, DeviceState *qdev) > +{ > + DimmBus *bus =3D main_memory_bus; > + bus->qbus.allow_hotplug =3D 1; > + bus->dimm_hotplug_qdev =3D qdev; > + bus->dimm_hotplug =3D hotplug; > +} > + > +static void dimm_plug_device(DimmDevice *slot) > +{ > + DimmBus *bus =3D main_memory_bus; > + > + dimm_populate(slot); > + if (bus->dimm_hotplug) > + bus->dimm_hotplug(bus->dimm_hotplug_qdev, slot, 1); > +} > + > +static int dimm_unplug_device(DeviceState *qdev) > +{ > + DimmBus *bus =3D main_memory_bus; > + > + if (bus->dimm_hotplug) > + bus->dimm_hotplug(bus->dimm_hotplug_qdev, DIMM(qdev), 0); > + return 1; > +} > + > +static DimmConfig *dimmcfg_find_from_name(const char *name) > +{ > + DimmConfig *slot; > + DimmBus *bus =3D main_memory_bus; > + > + QTAILQ_FOREACH(slot, &bus->dimmconfig_list, nextdimmcfg) { > + if (!strcmp(slot->name, name)) { > + return slot; > + } > + } > + return NULL; > +} > + > +static DimmDevice *dimm_find_from_idx(uint32_t idx) > +{ > + DimmDevice *slot; > + DimmBus *bus =3D main_memory_bus; > + > + QTAILQ_FOREACH(slot, &bus->dimmlist, nextdimm) { > + if (slot->idx =3D=3D idx) { > + return slot; > + } > + } > + return NULL; > +} > + > +/* used to create a dimm device, only on incoming migration of a hot= plugged > + * RAMBlock > + */ > +int dimm_add(char *id) > +{ > + DimmConfig *slotcfg =3D NULL; > + QemuOpts *devopts; > + char buf[256]; > + > + if (!id) { > + fprintf(stderr, "ERROR %s invalid id\n",__FUNCTION__); > + return 1; > + } > + > + slotcfg =3D dimmcfg_find_from_name(id); > + > + if (!slotcfg) { > + fprintf(stderr, "%s no slot %s found\n", __FUNCTION__, id); > + return 1; > + } > + > + devopts =3D qemu_opts_create(qemu_find_opts("device"), id, 0, NU= LL); > + qemu_opt_set(devopts, "driver", "dimm"); > + > + snprintf(buf, sizeof(buf), "%lu", slotcfg->size); > + qemu_opt_set(devopts, "size", buf); > + snprintf(buf, sizeof(buf), "%u", slotcfg->node); > + qemu_opt_set(devopts, "node", buf); > + qdev_device_add(devopts); > + > + return 0; > +} > + > +/* used to calculate physical address offsets for all dimms */ > +void dimm_calc_offsets(dimm_calcoffset_fn calcfn) > +{ > + DimmConfig *slot; > + QTAILQ_FOREACH(slot, &dimmconfig_list, nextdimmcfg) { > + if (!slot->start) { > + slot->start =3D calcfn(slot->size); > + } > + } > +} > + > +void setup_fwcfg_hp_dimms(uint64_t *fw_cfg_slots) > +{ > + DimmConfig *slot; > + > + QTAILQ_FOREACH(slot, &dimmconfig_list, nextdimmcfg) { > + assert(slot->start); > + fw_cfg_slots[3 * slot->idx] =3D cpu_to_le64(slot->start); > + fw_cfg_slots[3 * slot->idx + 1] =3D cpu_to_le64(slot->size); > + fw_cfg_slots[3 * slot->idx + 2] =3D cpu_to_le64(slot->node); > + } > +} > + > +void dimm_notify(uint32_t idx, uint32_t event) > +{ > + DimmBus *bus =3D main_memory_bus; > + DimmDevice *s; > + s =3D dimm_find_from_idx(idx); > + assert(s !=3D NULL); > + > + switch(event) { > + case DIMM_REMOVE_SUCCESS: > + dimm_depopulate(s); > + qdev_simple_unplug_cb((DeviceState*)s); > + QTAILQ_REMOVE(&bus->dimmlist, s, nextdimm); > + break; > + default: > + break; > + } > +} > + > +static int dimm_init(DeviceState *s) > +{ > + DimmBus *bus =3D main_memory_bus; > + DimmDevice *slot; > + DimmConfig *slotcfg; > + > + slot =3D DIMM(s); > + slot->mr =3D NULL; > + > + slotcfg =3D dimmcfg_find_from_name(s->id); > + > + if (!slotcfg) { > + fprintf(stderr, "%s no config for slot %s found\n", > + __FUNCTION__, s->id); > + return 1; > + } > + > + slot->idx =3D slotcfg->idx; > + assert(slotcfg->start); > + slot->start =3D slotcfg->start; > + slot->size =3D slotcfg->size; > + slot->node =3D slotcfg->node; > + > + QTAILQ_INSERT_TAIL(&bus->dimmlist, slot, nextdimm); > + dimm_plug_device(slot); > + > + return 0; > +} > + > + > +static void dimm_class_init(ObjectClass *klass, void *data) > +{ > + DeviceClass *dc =3D DEVICE_CLASS(klass); > + > + dc->props =3D dimm_properties; > + dc->unplug =3D dimm_unplug_device; > + dc->init =3D dimm_init; > +} > + > +static TypeInfo dimm_info =3D { > + .name =3D TYPE_DIMM, > + .parent =3D TYPE_DEVICE, > + .instance_size =3D sizeof(DimmDevice), > + .class_init =3D dimm_class_init, > +}; > + > +static void dimm_register_types(void) > +{ > + type_register_static(&dimm_bus_info); > + type_register_static(&dimm_info); > +} > + > +type_init(dimm_register_types) > diff --git a/hw/dimm.h b/hw/dimm.h > new file mode 100644 > index 0000000..5e991a6 > --- /dev/null > +++ b/hw/dimm.h > @@ -0,0 +1,90 @@ > +#ifndef QEMU_DIMM_H > +#define QEMU_DIMM_H > + > +#include "qemu-common.h" > +#include "memory.h" > +#include "sysbus.h" > +#include "qapi-types.h" > +#include "qemu-queue.h" > +#include "cpus.h" > +#define MAX_DIMMS 255 > +#define DIMM_BITMAP_BYTES (MAX_DIMMS + 7) / 8 > +#define DEFAULT_DIMMSIZE 1024*1024*1024 > + > +typedef enum { > + DIMM_REMOVE_SUCCESS =3D 0, > + DIMM_REMOVE_FAIL =3D 1, > + DIMM_ADD_SUCCESS =3D 2, > + DIMM_ADD_FAIL =3D 3 > +} dimm_hp_result_code; > + > +#define TYPE_DIMM "dimm" > +#define DIMM(obj) \ > + OBJECT_CHECK(DimmDevice, (obj), TYPE_DIMM) > +#define DIMM_CLASS(klass) \ > + OBJECT_CLASS_CHECK(DimmDeviceClass, (klass), TYPE_DIMM) > +#define DIMM_GET_CLASS(obj) \ > + OBJECT_GET_CLASS(DimmDeviceClass, (obj), TYPE_DIMM) > + > +typedef struct DimmDevice DimmDevice; > +typedef QTAILQ_HEAD(DimmConfiglist, DimmConfig) DimmConfiglist; > + > +typedef struct DimmDeviceClass { > + DeviceClass parent_class; > + > + int (*init)(DimmDevice *dev); > +} DimmDeviceClass; > + > +typedef struct DimmDevice { typedef is unnecessay here, and it will break building: CC hmp.o In file included from /home/wency/source/qemu/hw/acpi_piix4.c:32: /home/wency/source/qemu/hw/dimm.h:54: error: redefinition of typedef =91= DimmDevice=92 /home/wency/source/qemu/hw/dimm.h:36: note: previous declaration of =91= DimmDevice=92 was here make[1]: *** [hw/acpi_piix4.o] Error 1 make[1]: *** Waiting for unfinished jobs.... CC audio/audio.o make: *** [subdir-libhw64] Error 2 make: *** Waiting for unfinished jobs.... Thanks Wen Congyang > + DeviceState qdev; > + uint32_t idx; /* index in memory hotplug register/bitmap */ > + ram_addr_t start; /* starting physical address */ > + ram_addr_t size; > + uint32_t node; /* numa node proximity */ > + MemoryRegion *mr; /* MemoryRegion for this slot. !NULL only if p= opulated */ > + QTAILQ_ENTRY (DimmDevice) nextdimm; > +} DimmDevice; > + > +typedef struct DimmConfig > +{ > + const char *name; > + uint32_t idx; /* index in memory hotplug register/bitmap */ > + ram_addr_t start; /* starting physical address */ > + ram_addr_t size; > + uint32_t node; /* numa node proximity */ > + uint32_t populated; /* 1 means device has been hotplugged. Defau= lt is 0. */ > + QTAILQ_ENTRY (DimmConfig) nextdimmcfg; > +} DimmConfig; > + > +typedef int (*dimm_hotplug_fn)(DeviceState *qdev, DimmDevice *dev, i= nt add); > +typedef target_phys_addr_t (*dimm_calcoffset_fn)(uint64_t size); > + > +#define TYPE_DIMM_BUS "dimmbus" > +#define DIMM_BUS(obj) OBJECT_CHECK(DimmBus, (obj), TYPE_DIMM_BUS) > + > +typedef struct DimmBus { > + BusState qbus; > + DeviceState *dimm_hotplug_qdev; > + dimm_hotplug_fn dimm_hotplug; > + dimm_calcoffset_fn dimm_calcoffset; > + DimmConfiglist dimmconfig_list; > + QTAILQ_HEAD(Dimmlist, DimmDevice) dimmlist; > +} DimmBus; > + > +struct dimm_hp_result { > + const char *dimmname; > + dimm_hp_result_code ret; > + QTAILQ_ENTRY (dimm_hp_result) next; > +}; > + > +void dimm_calc_offsets(dimm_calcoffset_fn calcfn); > +void dimm_notify(uint32_t idx, uint32_t event); > +void dimm_bus_hotplug(dimm_hotplug_fn hotplug, DeviceState *qdev); > +void setup_fwcfg_hp_dimms(uint64_t *fw_cfg_slots); > +int dimm_add(char *id); > +void main_memory_bus_create(Object *parent); > +void dimm_config_create(char *id, uint64_t size, uint64_t node, > + uint32_t dimm_idx, uint32_t populated); > + > + > +#endif