aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--hw/ppc/spapr_drc.c6
-rw-r--r--hw/ppc/spapr_hcall.c8
-rw-r--r--include/hw/ppc/spapr_drc.h3
3 files changed, 14 insertions, 3 deletions
diff --git a/hw/ppc/spapr_drc.c b/hw/ppc/spapr_drc.c
index 8d62f55..5b5e2ac 100644
--- a/hw/ppc/spapr_drc.c
+++ b/hw/ppc/spapr_drc.c
@@ -417,9 +417,10 @@ void spapr_drc_detach(SpaprDrc *drc)
spapr_drc_release(drc);
}
-void spapr_drc_reset(SpaprDrc *drc)
+bool spapr_drc_reset(SpaprDrc *drc)
{
SpaprDrcClass *drck = SPAPR_DR_CONNECTOR_GET_CLASS(drc);
+ bool unplug_completed = false;
trace_spapr_drc_reset(spapr_drc_index(drc));
@@ -428,6 +429,7 @@ void spapr_drc_reset(SpaprDrc *drc)
*/
if (drc->unplug_requested) {
spapr_drc_release(drc);
+ unplug_completed = true;
}
if (drc->dev) {
@@ -444,6 +446,8 @@ void spapr_drc_reset(SpaprDrc *drc)
drc->ccs_offset = -1;
drc->ccs_depth = -1;
}
+
+ return unplug_completed;
}
static bool spapr_drc_unplug_requested_needed(void *opaque)
diff --git a/hw/ppc/spapr_hcall.c b/hw/ppc/spapr_hcall.c
index 4e9d50c..aa22830 100644
--- a/hw/ppc/spapr_hcall.c
+++ b/hw/ppc/spapr_hcall.c
@@ -1639,6 +1639,7 @@ static void spapr_handle_transient_dev_before_cas(SpaprMachineState *spapr)
ObjectPropertyIterator iter;
drc_container = container_get(object_get_root(), "/dr-connector");
+restart:
object_property_iter_init(&iter, drc_container);
while ((prop = object_property_iter_next(&iter))) {
SpaprDrc *drc;
@@ -1652,8 +1653,13 @@ static void spapr_handle_transient_dev_before_cas(SpaprMachineState *spapr)
/*
* This will complete any pending plug/unplug requests.
+ * In case of a unplugged PHB or PCI bridge, this will
+ * cause some DRCs to be destroyed and thus potentially
+ * invalidate the iterator.
*/
- spapr_drc_reset(drc);
+ if (spapr_drc_reset(drc)) {
+ goto restart;
+ }
}
spapr_clear_pending_hotplug_events(spapr);
diff --git a/include/hw/ppc/spapr_drc.h b/include/hw/ppc/spapr_drc.h
index cff5e70..5d80019 100644
--- a/include/hw/ppc/spapr_drc.h
+++ b/include/hw/ppc/spapr_drc.h
@@ -224,7 +224,8 @@ static inline bool spapr_drc_hotplugged(DeviceState *dev)
return dev->hotplugged && !runstate_check(RUN_STATE_INMIGRATE);
}
-void spapr_drc_reset(SpaprDrc *drc);
+/* Returns true if an unplug request completed */
+bool spapr_drc_reset(SpaprDrc *drc);
uint32_t spapr_drc_index(SpaprDrc *drc);
SpaprDrcType spapr_drc_type(SpaprDrc *drc);