aboutsummaryrefslogtreecommitdiff
path: root/hw
diff options
context:
space:
mode:
Diffstat (limited to 'hw')
-rw-r--r--hw/ppc/spapr_drc.c34
-rw-r--r--hw/ppc/spapr_events.c11
2 files changed, 45 insertions, 0 deletions
diff --git a/hw/ppc/spapr_drc.c b/hw/ppc/spapr_drc.c
index e6eedf8946..317394027a 100644
--- a/hw/ppc/spapr_drc.c
+++ b/hw/ppc/spapr_drc.c
@@ -176,6 +176,12 @@ static void set_configured(sPAPRDRConnector *drc)
drc->configured = true;
}
+/* has the guest been notified of device attachment? */
+static void set_signalled(sPAPRDRConnector *drc)
+{
+ drc->signalled = true;
+}
+
/*
* dr-entity-sense sensor value
* returned via get-sensor-state RTAS calls
@@ -358,6 +364,7 @@ static void attach(sPAPRDRConnector *drc, DeviceState *d, void *fdt,
drc->fdt = fdt;
drc->fdt_start_offset = fdt_start_offset;
drc->configured = coldplug;
+ drc->signalled = coldplug;
object_property_add_link(OBJECT(drc), "device",
object_get_typename(OBJECT(drc->dev)),
@@ -374,6 +381,26 @@ static void detach(sPAPRDRConnector *drc, DeviceState *d,
drc->detach_cb = detach_cb;
drc->detach_cb_opaque = detach_cb_opaque;
+ /* if we've signalled device presence to the guest, or if the guest
+ * has gone ahead and configured the device (via manually-executed
+ * device add via drmgr in guest, namely), we need to wait
+ * for the guest to quiesce the device before completing detach.
+ * Otherwise, we can assume the guest hasn't seen it and complete the
+ * detach immediately. Note that there is a small race window
+ * just before, or during, configuration, which is this context
+ * refers mainly to fetching the device tree via RTAS.
+ * During this window the device access will be arbitrated by
+ * associated DRC, which will simply fail the RTAS calls as invalid.
+ * This is recoverable within guest and current implementations of
+ * drmgr should be able to cope.
+ */
+ if (!drc->signalled && !drc->configured) {
+ /* if the guest hasn't seen the device we can't rely on it to
+ * set it back to an isolated state via RTAS, so do it here manually
+ */
+ drc->isolation_state = SPAPR_DR_ISOLATION_STATE_ISOLATED;
+ }
+
if (drc->isolation_state != SPAPR_DR_ISOLATION_STATE_ISOLATED) {
DPRINTFN("awaiting transition to isolated state before removal");
drc->awaiting_release = true;
@@ -412,6 +439,7 @@ static void reset(DeviceState *d)
{
sPAPRDRConnector *drc = SPAPR_DR_CONNECTOR(d);
sPAPRDRConnectorClass *drck = SPAPR_DR_CONNECTOR_GET_CLASS(drc);
+ sPAPRDREntitySense state;
DPRINTFN("drc reset: %x", drck->get_index(drc));
/* immediately upon reset we can safely assume DRCs whose devices
@@ -439,6 +467,11 @@ static void reset(DeviceState *d)
drck->set_allocation_state(drc, SPAPR_DR_ALLOCATION_STATE_UNUSABLE);
}
}
+
+ drck->entity_sense(drc, &state);
+ if (state == SPAPR_DR_ENTITY_SENSE_PRESENT) {
+ drck->set_signalled(drc);
+ }
}
static void realize(DeviceState *d, Error **errp)
@@ -597,6 +630,7 @@ static void spapr_dr_connector_class_init(ObjectClass *k, void *data)
drck->attach = attach;
drck->detach = detach;
drck->release_pending = release_pending;
+ drck->set_signalled = set_signalled;
/*
* Reason: it crashes FIXME find and document the real reason
*/
diff --git a/hw/ppc/spapr_events.c b/hw/ppc/spapr_events.c
index 1abec27ec6..269ab7e61c 100644
--- a/hw/ppc/spapr_events.c
+++ b/hw/ppc/spapr_events.c
@@ -389,6 +389,13 @@ static void spapr_powerdown_req(Notifier *n, void *opaque)
qemu_irq_pulse(xics_get_qirq(spapr->icp, spapr->check_exception_irq));
}
+static void spapr_hotplug_set_signalled(uint32_t drc_index)
+{
+ sPAPRDRConnector *drc = spapr_dr_connector_by_index(drc_index);
+ sPAPRDRConnectorClass *drck = SPAPR_DR_CONNECTOR_GET_CLASS(drc);
+ drck->set_signalled(drc);
+}
+
static void spapr_hotplug_req_event(uint8_t hp_id, uint8_t hp_action,
sPAPRDRConnectorType drc_type,
uint32_t drc)
@@ -455,6 +462,10 @@ static void spapr_hotplug_req_event(uint8_t hp_id, uint8_t hp_action,
rtas_event_log_queue(RTAS_LOG_TYPE_HOTPLUG, new_hp, true);
+ if (hp->hotplug_action == RTAS_LOG_V6_HP_ACTION_ADD) {
+ spapr_hotplug_set_signalled(drc);
+ }
+
qemu_irq_pulse(xics_get_qirq(spapr->icp, spapr->check_exception_irq));
}