summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--hw/ppc/spapr_drc.c40
-rw-r--r--include/hw/ppc/spapr_drc.h4
2 files changed, 44 insertions, 0 deletions
diff --git a/hw/ppc/spapr_drc.c b/hw/ppc/spapr_drc.c
index 67041fb212..27adbc5c30 100644
--- a/hw/ppc/spapr_drc.c
+++ b/hw/ppc/spapr_drc.c
@@ -57,6 +57,8 @@ static void spapr_drc_release(SpaprDrc *drc)
drck->release(drc->dev);
drc->unplug_requested = false;
+ timer_del(drc->unplug_timeout_timer);
+
g_free(drc->fdt);
drc->fdt = NULL;
drc->fdt_start_offset = 0;
@@ -370,6 +372,17 @@ static void prop_get_fdt(Object *obj, Visitor *v, const char *name,
} while (fdt_depth != 0);
}
+static void spapr_drc_start_unplug_timeout_timer(SpaprDrc *drc)
+{
+ SpaprDrcClass *drck = SPAPR_DR_CONNECTOR_GET_CLASS(drc);
+
+ if (drck->unplug_timeout_seconds != 0) {
+ timer_mod(drc->unplug_timeout_timer,
+ qemu_clock_get_ms(QEMU_CLOCK_VIRTUAL) +
+ drck->unplug_timeout_seconds * 1000);
+ }
+}
+
void spapr_drc_attach(SpaprDrc *drc, DeviceState *d)
{
trace_spapr_drc_attach(spapr_drc_index(drc));
@@ -475,11 +488,23 @@ static bool spapr_drc_needed(void *opaque)
spapr_drc_unplug_requested(drc);
}
+static int spapr_drc_post_load(void *opaque, int version_id)
+{
+ SpaprDrc *drc = opaque;
+
+ if (drc->unplug_requested) {
+ spapr_drc_start_unplug_timeout_timer(drc);
+ }
+
+ return 0;
+}
+
static const VMStateDescription vmstate_spapr_drc = {
.name = "spapr_drc",
.version_id = 1,
.minimum_version_id = 1,
.needed = spapr_drc_needed,
+ .post_load = spapr_drc_post_load,
.fields = (VMStateField []) {
VMSTATE_UINT32(state, SpaprDrc),
VMSTATE_END_OF_LIST()
@@ -490,6 +515,15 @@ static const VMStateDescription vmstate_spapr_drc = {
}
};
+static void drc_unplug_timeout_cb(void *opaque)
+{
+ SpaprDrc *drc = opaque;
+
+ if (drc->unplug_requested) {
+ drc->unplug_requested = false;
+ }
+}
+
static void drc_realize(DeviceState *d, Error **errp)
{
SpaprDrc *drc = SPAPR_DR_CONNECTOR(d);
@@ -512,6 +546,11 @@ static void drc_realize(DeviceState *d, Error **errp)
object_property_add_alias(root_container, link_name,
drc->owner, child_name);
g_free(link_name);
+
+ drc->unplug_timeout_timer = timer_new_ms(QEMU_CLOCK_VIRTUAL,
+ drc_unplug_timeout_cb,
+ drc);
+
vmstate_register(VMSTATE_IF(drc), spapr_drc_index(drc), &vmstate_spapr_drc,
drc);
trace_spapr_drc_realize_complete(spapr_drc_index(drc));
@@ -529,6 +568,7 @@ static void drc_unrealize(DeviceState *d)
name = g_strdup_printf("%x", spapr_drc_index(drc));
object_property_del(root_container, name);
g_free(name);
+ timer_free(drc->unplug_timeout_timer);
}
SpaprDrc *spapr_dr_connector_new(Object *owner, const char *type,
diff --git a/include/hw/ppc/spapr_drc.h b/include/hw/ppc/spapr_drc.h
index 02a63b3666..38ec4c8091 100644
--- a/include/hw/ppc/spapr_drc.h
+++ b/include/hw/ppc/spapr_drc.h
@@ -187,6 +187,8 @@ typedef struct SpaprDrc {
bool unplug_requested;
void *fdt;
int fdt_start_offset;
+
+ QEMUTimer *unplug_timeout_timer;
} SpaprDrc;
struct SpaprMachineState;
@@ -209,6 +211,8 @@ typedef struct SpaprDrcClass {
int (*dt_populate)(SpaprDrc *drc, struct SpaprMachineState *spapr,
void *fdt, int *fdt_start_offset, Error **errp);
+
+ int unplug_timeout_seconds;
} SpaprDrcClass;
typedef struct SpaprDrcPhysical {