aboutsummaryrefslogtreecommitdiff
path: root/hw/ppc/spapr_drc.c
diff options
context:
space:
mode:
Diffstat (limited to 'hw/ppc/spapr_drc.c')
-rw-r--r--hw/ppc/spapr_drc.c92
1 files changed, 76 insertions, 16 deletions
diff --git a/hw/ppc/spapr_drc.c b/hw/ppc/spapr_drc.c
index 9fa5545991..cc2400bcd5 100644
--- a/hw/ppc/spapr_drc.c
+++ b/hw/ppc/spapr_drc.c
@@ -20,6 +20,7 @@
#include "qapi/visitor.h"
#include "qemu/error-report.h"
#include "hw/ppc/spapr.h" /* for RTAS return codes */
+#include "hw/pci-host/spapr.h" /* spapr_phb_remove_pci_device_cb callback */
#include "trace.h"
#define DRC_CONTAINER_PATH "/dr-connector"
@@ -99,8 +100,7 @@ static uint32_t set_isolation_state(sPAPRDRConnector *drc,
if (drc->awaiting_release) {
if (drc->configured) {
trace_spapr_drc_set_isolation_state_finalizing(get_index(drc));
- drck->detach(drc, DEVICE(drc->dev), drc->detach_cb,
- drc->detach_cb_opaque, NULL);
+ drck->detach(drc, DEVICE(drc->dev), NULL);
} else {
trace_spapr_drc_set_isolation_state_deferring(get_index(drc));
}
@@ -153,8 +153,7 @@ static uint32_t set_allocation_state(sPAPRDRConnector *drc,
if (drc->awaiting_release &&
drc->allocation_state == SPAPR_DR_ALLOCATION_STATE_UNUSABLE) {
trace_spapr_drc_set_allocation_state_finalizing(get_index(drc));
- drck->detach(drc, DEVICE(drc->dev), drc->detach_cb,
- drc->detach_cb_opaque, NULL);
+ drck->detach(drc, DEVICE(drc->dev), NULL);
} else if (drc->allocation_state == SPAPR_DR_ALLOCATION_STATE_USABLE) {
drc->awaiting_allocation = false;
}
@@ -404,15 +403,10 @@ static void attach(sPAPRDRConnector *drc, DeviceState *d, void *fdt,
NULL, 0, NULL);
}
-static void detach(sPAPRDRConnector *drc, DeviceState *d,
- spapr_drc_detach_cb *detach_cb,
- void *detach_cb_opaque, Error **errp)
+static void detach(sPAPRDRConnector *drc, DeviceState *d, Error **errp)
{
trace_spapr_drc_detach(get_index(drc));
- 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
@@ -456,8 +450,21 @@ static void detach(sPAPRDRConnector *drc, DeviceState *d,
drc->indicator_state = SPAPR_DR_INDICATOR_STATE_INACTIVE;
- if (drc->detach_cb) {
- drc->detach_cb(drc->dev, drc->detach_cb_opaque);
+ /* Calling release callbacks based on drc->type. */
+ switch (drc->type) {
+ case SPAPR_DR_CONNECTOR_TYPE_CPU:
+ spapr_core_release(drc->dev);
+ break;
+ case SPAPR_DR_CONNECTOR_TYPE_PCI:
+ spapr_phb_remove_pci_device_cb(drc->dev);
+ break;
+ case SPAPR_DR_CONNECTOR_TYPE_LMB:
+ spapr_lmb_release(drc->dev);
+ break;
+ case SPAPR_DR_CONNECTOR_TYPE_PHB:
+ case SPAPR_DR_CONNECTOR_TYPE_VIO:
+ default:
+ g_assert(false);
}
drc->awaiting_release = false;
@@ -467,8 +474,6 @@ static void detach(sPAPRDRConnector *drc, DeviceState *d,
drc->fdt_start_offset = 0;
object_property_del(OBJECT(drc), "device", NULL);
drc->dev = NULL;
- drc->detach_cb = NULL;
- drc->detach_cb_opaque = NULL;
}
static bool release_pending(sPAPRDRConnector *drc)
@@ -498,8 +503,7 @@ static void reset(DeviceState *d)
* force removal if we are
*/
if (drc->awaiting_release) {
- drck->detach(drc, DEVICE(drc->dev), drc->detach_cb,
- drc->detach_cb_opaque, NULL);
+ drck->detach(drc, DEVICE(drc->dev), NULL);
}
/* non-PCI devices may be awaiting a transition to UNUSABLE */
@@ -515,6 +519,60 @@ static void reset(DeviceState *d)
}
}
+static bool spapr_drc_needed(void *opaque)
+{
+ sPAPRDRConnector *drc = (sPAPRDRConnector *)opaque;
+ sPAPRDRConnectorClass *drck = SPAPR_DR_CONNECTOR_GET_CLASS(drc);
+ bool rc = false;
+ sPAPRDREntitySense value;
+ drck->entity_sense(drc, &value);
+
+ /* If no dev is plugged in there is no need to migrate the DRC state */
+ if (value != SPAPR_DR_ENTITY_SENSE_PRESENT) {
+ return false;
+ }
+
+ /*
+ * If there is dev plugged in, we need to migrate the DRC state when
+ * it is different from cold-plugged state
+ */
+ switch (drc->type) {
+ case SPAPR_DR_CONNECTOR_TYPE_PCI:
+ rc = !((drc->isolation_state == SPAPR_DR_ISOLATION_STATE_UNISOLATED) &&
+ (drc->allocation_state == SPAPR_DR_ALLOCATION_STATE_USABLE) &&
+ drc->configured && drc->signalled && !drc->awaiting_release);
+ break;
+ case SPAPR_DR_CONNECTOR_TYPE_CPU:
+ case SPAPR_DR_CONNECTOR_TYPE_LMB:
+ rc = !((drc->isolation_state == SPAPR_DR_ISOLATION_STATE_ISOLATED) &&
+ (drc->allocation_state == SPAPR_DR_ALLOCATION_STATE_UNUSABLE) &&
+ drc->configured && drc->signalled && !drc->awaiting_release);
+ break;
+ case SPAPR_DR_CONNECTOR_TYPE_PHB:
+ case SPAPR_DR_CONNECTOR_TYPE_VIO:
+ default:
+ g_assert(false);
+ }
+ return rc;
+}
+
+static const VMStateDescription vmstate_spapr_drc = {
+ .name = "spapr_drc",
+ .version_id = 1,
+ .minimum_version_id = 1,
+ .needed = spapr_drc_needed,
+ .fields = (VMStateField []) {
+ VMSTATE_UINT32(isolation_state, sPAPRDRConnector),
+ VMSTATE_UINT32(allocation_state, sPAPRDRConnector),
+ VMSTATE_UINT32(indicator_state, sPAPRDRConnector),
+ VMSTATE_BOOL(configured, sPAPRDRConnector),
+ VMSTATE_BOOL(awaiting_release, sPAPRDRConnector),
+ VMSTATE_BOOL(awaiting_allocation, sPAPRDRConnector),
+ VMSTATE_BOOL(signalled, sPAPRDRConnector),
+ VMSTATE_END_OF_LIST()
+ }
+};
+
static void realize(DeviceState *d, Error **errp)
{
sPAPRDRConnector *drc = SPAPR_DR_CONNECTOR(d);
@@ -543,6 +601,8 @@ static void realize(DeviceState *d, Error **errp)
object_unref(OBJECT(drc));
}
g_free(child_name);
+ vmstate_register(DEVICE(drc), drck->get_index(drc), &vmstate_spapr_drc,
+ drc);
trace_spapr_drc_realize_complete(drck->get_index(drc));
}