@@ -120,6 +120,18 @@ static void dimm_populate(DimmDevice *s)
s->mr = new;
}
+static int dimm_depopulate(DeviceState *dev)
+{
+ DimmDevice *s = DIMM(dev);
+ assert(s);
+ vmstate_unregister_ram(s->mr, NULL);
+ memory_region_del_subregion(get_system_memory(), s->mr);
+ memory_region_destroy(s->mr);
+ s->populated = false;
+ s->mr = NULL;
+ return 0;
+}
+
void dimm_config_create(char *id, uint64_t size, const char *bus, uint64_t node,
uint32_t dimm_idx, uint32_t populated)
{
@@ -159,6 +171,11 @@ static void dimm_plug_device(DimmDevice *slot)
static int dimm_unplug_device(DeviceState *qdev)
{
+ DimmBus *bus = DIMM_BUS(qdev_get_parent_bus(qdev));
+
+ if (bus->dimm_hotplug) {
+ bus->dimm_hotplug(bus->dimm_hotplug_qdev, DIMM(qdev), 0);
+ }
return 1;
}
@@ -186,6 +203,21 @@ static DimmDevice *dimm_find_from_name(DimmBus *bus, const char *name)
return NULL;
}
+static DimmDevice *dimm_find_from_idx(uint32_t idx)
+{
+ DimmDevice *slot;
+ DimmBus *bus;
+
+ QLIST_FOREACH(bus, &memory_buses, next) {
+ QTAILQ_FOREACH(slot, &bus->dimmlist, nextdimm) {
+ if (slot->idx == idx) {
+ return slot;
+ }
+ }
+ }
+ return NULL;
+}
+
void dimm_setup_fwcfg_layout(uint64_t *fw_cfg_slots)
{
DimmConfig *slot;
@@ -275,6 +307,24 @@ static int dimm_init(DeviceState *s)
return 0;
}
+void dimm_notify(uint32_t idx, uint32_t event)
+{
+ DimmBus *bus;
+ DimmDevice *slot;
+
+ slot = dimm_find_from_idx(idx);
+ assert(slot != NULL);
+ bus = DIMM_BUS(qdev_get_parent_bus(&slot->qdev));
+
+ switch (event) {
+ case DIMM_REMOVE_SUCCESS:
+ qdev_unplug_complete((DeviceState *)slot, NULL);
+ QTAILQ_REMOVE(&bus->dimmlist, slot, nextdimm);
+ break;
+ default:
+ break;
+ }
+}
static void dimm_class_init(ObjectClass *klass, void *data)
{
@@ -283,6 +333,7 @@ static void dimm_class_init(ObjectClass *klass, void *data)
dc->props = dimm_properties;
dc->unplug = dimm_unplug_device;
dc->init = dimm_init;
+ dc->exit = dimm_depopulate;
dc->bus_type = TYPE_DIMM_BUS;
}
@@ -86,5 +86,6 @@ DimmBus *dimm_bus_create(Object *parent, const char *name, uint32_t max_dimms,
void dimm_config_create(char *id, uint64_t size, const char *bus, uint64_t node,
uint32_t dimm_idx, uint32_t populated);
uint64_t get_hp_memory_total(void);
+void dimm_notify(uint32_t idx, uint32_t event);
#endif
On a succesfull _EJ0 operation unmap the device from the guest by using the new qdev function qdev_unplug_complete, see: https://lists.gnu.org/archive/html/qemu-devel/2012-11/msg02699.html The memory of the device should be freed when the last subsystem using it unmaps it, see the following two series: https://lists.gnu.org/archive/html/qemu-devel/2012-11/msg00728.html https://lists.gnu.org/archive/html/qemu-devel/2012-11/msg02697.html Needs testing. Other subsystems (e.g. virtio-blk) may have to install new memorylisteners to complete pending I/O before device memory can be freed. Signed-off-by: Vasilis Liaskovitis <vasilis.liaskovitis@profitbricks.com> --- hw/dimm.c | 51 +++++++++++++++++++++++++++++++++++++++++++++++++++ hw/dimm.h | 1 + 2 files changed, 52 insertions(+), 0 deletions(-)