spapr: Clean up DRC set_isolation_state() path

There are substantial differences in the various paths through
set_isolation_state(), both for setting to ISOLATED versus UNISOLATED
state and for logical versus physical DRCs.

So, split the set_isolation_state() method into isolate() and unisolate()
methods, and give it different implementations for the two DRC types.

Factor some minimal common checks, including for valid indicator values
(which we weren't previously checking) into rtas_set_isolation_state().

Signed-off-by: David Gibson <david@gibson.dropbear.id.au>
Reviewed-by: Greg Kurz <groug@kaod.org>
Reviewed-by: Michael Roth <mdroth@linux.vnet.ibm.com>
This commit is contained in:
David Gibson 2017-06-08 00:58:32 +10:00
parent 617367321e
commit 0dfabd39d5
2 changed files with 105 additions and 46 deletions

View File

@ -46,58 +46,25 @@ uint32_t spapr_drc_index(sPAPRDRConnector *drc)
| (drc->id & DRC_INDEX_ID_MASK); | (drc->id & DRC_INDEX_ID_MASK);
} }
static uint32_t set_isolation_state(sPAPRDRConnector *drc, static uint32_t drc_isolate_physical(sPAPRDRConnector *drc)
sPAPRDRIsolationState state)
{ {
trace_spapr_drc_set_isolation_state(spapr_drc_index(drc), state);
/* if the guest is configuring a device attached to this DRC, we /* if the guest is configuring a device attached to this DRC, we
* should reset the configuration state at this point since it may * should reset the configuration state at this point since it may
* no longer be reliable (guest released device and needs to start * no longer be reliable (guest released device and needs to start
* over, or unplug occurred so the FDT is no longer valid) * over, or unplug occurred so the FDT is no longer valid)
*/ */
if (state == SPAPR_DR_ISOLATION_STATE_ISOLATED) {
g_free(drc->ccs); g_free(drc->ccs);
drc->ccs = NULL; drc->ccs = NULL;
}
if (state == SPAPR_DR_ISOLATION_STATE_UNISOLATED) { drc->isolation_state = SPAPR_DR_ISOLATION_STATE_ISOLATED;
/* cannot unisolate a non-existent resource, and, or resources
* which are in an 'UNUSABLE' allocation state. (PAPR 2.7, 13.5.3.5)
*/
if (!drc->dev ||
drc->allocation_state == SPAPR_DR_ALLOCATION_STATE_UNUSABLE) {
return RTAS_OUT_NO_SUCH_INDICATOR;
}
}
/*
* Fail any requests to ISOLATE the LMB DRC if this LMB doesn't
* belong to a DIMM device that is marked for removal.
*
* Currently the guest userspace tool drmgr that drives the memory
* hotplug/unplug will just try to remove a set of 'removable' LMBs
* in response to a hot unplug request that is based on drc-count.
* If the LMB being removed doesn't belong to a DIMM device that is
* actually being unplugged, fail the isolation request here.
*/
if (spapr_drc_type(drc) == SPAPR_DR_CONNECTOR_TYPE_LMB) {
if ((state == SPAPR_DR_ISOLATION_STATE_ISOLATED) &&
!drc->awaiting_release) {
return RTAS_OUT_HW_ERROR;
}
}
drc->isolation_state = state;
if (drc->isolation_state == SPAPR_DR_ISOLATION_STATE_ISOLATED) {
/* if we're awaiting release, but still in an unconfigured state, /* if we're awaiting release, but still in an unconfigured state,
* it's likely the guest is still in the process of configuring * it's likely the guest is still in the process of configuring
* the device and is transitioning the devices to an ISOLATED * the device and is transitioning the devices to an ISOLATED
* state as a part of that process. so we only complete the * state as a part of that process. so we only complete the
* removal when this transition happens for a device in a * removal when this transition happens for a device in a
* configured state, as suggested by the state diagram from * configured state, as suggested by the state diagram from PAPR+
* PAPR+ 2.7, 13.4 * 2.7, 13.4
*/ */
if (drc->awaiting_release) { if (drc->awaiting_release) {
uint32_t drc_index = spapr_drc_index(drc); uint32_t drc_index = spapr_drc_index(drc);
@ -109,8 +76,87 @@ static uint32_t set_isolation_state(sPAPRDRConnector *drc,
} }
} }
drc->configured = false; drc->configured = false;
return RTAS_OUT_SUCCESS;
}
static uint32_t drc_unisolate_physical(sPAPRDRConnector *drc)
{
/* cannot unisolate a non-existent resource, and, or resources
* which are in an 'UNUSABLE' allocation state. (PAPR 2.7,
* 13.5.3.5)
*/
if (!drc->dev) {
return RTAS_OUT_NO_SUCH_INDICATOR;
} }
drc->isolation_state = SPAPR_DR_ISOLATION_STATE_UNISOLATED;
return RTAS_OUT_SUCCESS;
}
static uint32_t drc_isolate_logical(sPAPRDRConnector *drc)
{
/* if the guest is configuring a device attached to this DRC, we
* should reset the configuration state at this point since it may
* no longer be reliable (guest released device and needs to start
* over, or unplug occurred so the FDT is no longer valid)
*/
g_free(drc->ccs);
drc->ccs = NULL;
/*
* Fail any requests to ISOLATE the LMB DRC if this LMB doesn't
* belong to a DIMM device that is marked for removal.
*
* Currently the guest userspace tool drmgr that drives the memory
* hotplug/unplug will just try to remove a set of 'removable' LMBs
* in response to a hot unplug request that is based on drc-count.
* If the LMB being removed doesn't belong to a DIMM device that is
* actually being unplugged, fail the isolation request here.
*/
if (spapr_drc_type(drc) == SPAPR_DR_CONNECTOR_TYPE_LMB
&& !drc->awaiting_release) {
return RTAS_OUT_HW_ERROR;
}
drc->isolation_state = SPAPR_DR_ISOLATION_STATE_ISOLATED;
/* if we're awaiting release, but still in an unconfigured state,
* it's likely the guest is still in the process of configuring
* the device and is transitioning the devices to an ISOLATED
* state as a part of that process. so we only complete the
* removal when this transition happens for a device in a
* configured state, as suggested by the state diagram from PAPR+
* 2.7, 13.4
*/
if (drc->awaiting_release) {
uint32_t drc_index = spapr_drc_index(drc);
if (drc->configured) {
trace_spapr_drc_set_isolation_state_finalizing(drc_index);
spapr_drc_detach(drc, DEVICE(drc->dev), NULL);
} else {
trace_spapr_drc_set_isolation_state_deferring(drc_index);
}
}
drc->configured = false;
return RTAS_OUT_SUCCESS;
}
static uint32_t drc_unisolate_logical(sPAPRDRConnector *drc)
{
/* cannot unisolate a non-existent resource, and, or resources
* which are in an 'UNUSABLE' allocation state. (PAPR 2.7,
* 13.5.3.5)
*/
if (!drc->dev ||
drc->allocation_state == SPAPR_DR_ALLOCATION_STATE_UNUSABLE) {
return RTAS_OUT_NO_SUCH_INDICATOR;
}
drc->isolation_state = SPAPR_DR_ISOLATION_STATE_UNISOLATED;
return RTAS_OUT_SUCCESS; return RTAS_OUT_SUCCESS;
} }
@ -555,7 +601,6 @@ static void spapr_dr_connector_class_init(ObjectClass *k, void *data)
dk->reset = reset; dk->reset = reset;
dk->realize = realize; dk->realize = realize;
dk->unrealize = unrealize; dk->unrealize = unrealize;
drck->set_isolation_state = set_isolation_state;
drck->release_pending = release_pending; drck->release_pending = release_pending;
/* /*
* Reason: it crashes FIXME find and document the real reason * Reason: it crashes FIXME find and document the real reason
@ -568,6 +613,8 @@ static void spapr_drc_physical_class_init(ObjectClass *k, void *data)
sPAPRDRConnectorClass *drck = SPAPR_DR_CONNECTOR_CLASS(k); sPAPRDRConnectorClass *drck = SPAPR_DR_CONNECTOR_CLASS(k);
drck->dr_entity_sense = physical_entity_sense; drck->dr_entity_sense = physical_entity_sense;
drck->isolate = drc_isolate_physical;
drck->unisolate = drc_unisolate_physical;
} }
static void spapr_drc_logical_class_init(ObjectClass *k, void *data) static void spapr_drc_logical_class_init(ObjectClass *k, void *data)
@ -575,6 +622,8 @@ static void spapr_drc_logical_class_init(ObjectClass *k, void *data)
sPAPRDRConnectorClass *drck = SPAPR_DR_CONNECTOR_CLASS(k); sPAPRDRConnectorClass *drck = SPAPR_DR_CONNECTOR_CLASS(k);
drck->dr_entity_sense = logical_entity_sense; drck->dr_entity_sense = logical_entity_sense;
drck->isolate = drc_isolate_logical;
drck->unisolate = drc_unisolate_logical;
} }
static void spapr_drc_cpu_class_init(ObjectClass *k, void *data) static void spapr_drc_cpu_class_init(ObjectClass *k, void *data)
@ -815,11 +864,23 @@ static uint32_t rtas_set_isolation_state(uint32_t idx, uint32_t state)
sPAPRDRConnectorClass *drck; sPAPRDRConnectorClass *drck;
if (!drc) { if (!drc) {
return RTAS_OUT_PARAM_ERROR; return RTAS_OUT_NO_SUCH_INDICATOR;
} }
trace_spapr_drc_set_isolation_state(spapr_drc_index(drc), state);
drck = SPAPR_DR_CONNECTOR_GET_CLASS(drc); drck = SPAPR_DR_CONNECTOR_GET_CLASS(drc);
return drck->set_isolation_state(drc, state);
switch (state) {
case SPAPR_DR_ISOLATION_STATE_ISOLATED:
return drck->isolate(drc);
case SPAPR_DR_ISOLATION_STATE_UNISOLATED:
return drck->unisolate(drc);
default:
return RTAS_OUT_PARAM_ERROR;
}
} }
static uint32_t rtas_set_allocation_state(uint32_t idx, uint32_t state) static uint32_t rtas_set_allocation_state(uint32_t idx, uint32_t state)

View File

@ -215,10 +215,8 @@ typedef struct sPAPRDRConnectorClass {
const char *drc_name_prefix; /* used other places in device tree */ const char *drc_name_prefix; /* used other places in device tree */
sPAPRDREntitySense (*dr_entity_sense)(sPAPRDRConnector *drc); sPAPRDREntitySense (*dr_entity_sense)(sPAPRDRConnector *drc);
uint32_t (*isolate)(sPAPRDRConnector *drc);
/* accessors for guest-visible (generally via RTAS) DR state */ uint32_t (*unisolate)(sPAPRDRConnector *drc);
uint32_t (*set_isolation_state)(sPAPRDRConnector *drc,
sPAPRDRIsolationState state);
/* QEMU interfaces for managing hotplug operations */ /* QEMU interfaces for managing hotplug operations */
bool (*release_pending)(sPAPRDRConnector *drc); bool (*release_pending)(sPAPRDRConnector *drc);