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.c573
1 files changed, 407 insertions, 166 deletions
diff --git a/hw/ppc/spapr_drc.c b/hw/ppc/spapr_drc.c
index cc2400bcd5..39e7f3080a 100644
--- a/hw/ppc/spapr_drc.c
+++ b/hw/ppc/spapr_drc.c
@@ -27,29 +27,23 @@
#define DRC_INDEX_TYPE_SHIFT 28
#define DRC_INDEX_ID_MASK ((1ULL << DRC_INDEX_TYPE_SHIFT) - 1)
-static sPAPRDRConnectorTypeShift get_type_shift(sPAPRDRConnectorType type)
+sPAPRDRConnectorType spapr_drc_type(sPAPRDRConnector *drc)
{
- uint32_t shift = 0;
-
- /* make sure this isn't SPAPR_DR_CONNECTOR_TYPE_ANY, or some
- * other wonky value.
- */
- g_assert(is_power_of_2(type));
+ sPAPRDRConnectorClass *drck = SPAPR_DR_CONNECTOR_GET_CLASS(drc);
- while (type != (1 << shift)) {
- shift++;
- }
- return shift;
+ return 1 << drck->typeshift;
}
-static uint32_t get_index(sPAPRDRConnector *drc)
+uint32_t spapr_drc_index(sPAPRDRConnector *drc)
{
+ sPAPRDRConnectorClass *drck = SPAPR_DR_CONNECTOR_GET_CLASS(drc);
+
/* no set format for a drc index: it only needs to be globally
* unique. this is how we encode the DRC type on bare-metal
* however, so might as well do that here
*/
- return (get_type_shift(drc->type) << DRC_INDEX_TYPE_SHIFT) |
- (drc->id & DRC_INDEX_ID_MASK);
+ return (drck->typeshift << DRC_INDEX_TYPE_SHIFT)
+ | (drc->id & DRC_INDEX_ID_MASK);
}
static uint32_t set_isolation_state(sPAPRDRConnector *drc,
@@ -57,7 +51,17 @@ static uint32_t set_isolation_state(sPAPRDRConnector *drc,
{
sPAPRDRConnectorClass *drck = SPAPR_DR_CONNECTOR_GET_CLASS(drc);
- trace_spapr_drc_set_isolation_state(get_index(drc), state);
+ trace_spapr_drc_set_isolation_state(spapr_drc_index(drc), state);
+
+ /* 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)
+ */
+ if (state == SPAPR_DR_ISOLATION_STATE_ISOLATED) {
+ g_free(drc->ccs);
+ drc->ccs = NULL;
+ }
if (state == SPAPR_DR_ISOLATION_STATE_UNISOLATED) {
/* cannot unisolate a non-existent resource, and, or resources
@@ -79,7 +83,7 @@ static uint32_t set_isolation_state(sPAPRDRConnector *drc,
* If the LMB being removed doesn't belong to a DIMM device that is
* actually being unplugged, fail the isolation request here.
*/
- if (drc->type == SPAPR_DR_CONNECTOR_TYPE_LMB) {
+ 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;
@@ -98,11 +102,12 @@ static uint32_t set_isolation_state(sPAPRDRConnector *drc,
* 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(get_index(drc));
+ trace_spapr_drc_set_isolation_state_finalizing(drc_index);
drck->detach(drc, DEVICE(drc->dev), NULL);
} else {
- trace_spapr_drc_set_isolation_state_deferring(get_index(drc));
+ trace_spapr_drc_set_isolation_state_deferring(drc_index);
}
}
drc->configured = false;
@@ -114,7 +119,7 @@ static uint32_t set_isolation_state(sPAPRDRConnector *drc,
static uint32_t set_indicator_state(sPAPRDRConnector *drc,
sPAPRDRIndicatorState state)
{
- trace_spapr_drc_set_indicator_state(get_index(drc), state);
+ trace_spapr_drc_set_indicator_state(spapr_drc_index(drc), state);
drc->indicator_state = state;
return RTAS_OUT_SUCCESS;
}
@@ -124,7 +129,7 @@ static uint32_t set_allocation_state(sPAPRDRConnector *drc,
{
sPAPRDRConnectorClass *drck = SPAPR_DR_CONNECTOR_GET_CLASS(drc);
- trace_spapr_drc_set_allocation_state(get_index(drc), state);
+ trace_spapr_drc_set_allocation_state(spapr_drc_index(drc), state);
if (state == SPAPR_DR_ALLOCATION_STATE_USABLE) {
/* if there's no resource/device associated with the DRC, there's
@@ -148,11 +153,12 @@ static uint32_t set_allocation_state(sPAPRDRConnector *drc,
}
}
- if (drc->type != SPAPR_DR_CONNECTOR_TYPE_PCI) {
+ if (spapr_drc_type(drc) != SPAPR_DR_CONNECTOR_TYPE_PCI) {
drc->allocation_state = state;
if (drc->awaiting_release &&
drc->allocation_state == SPAPR_DR_ALLOCATION_STATE_UNUSABLE) {
- trace_spapr_drc_set_allocation_state_finalizing(get_index(drc));
+ uint32_t drc_index = spapr_drc_index(drc);
+ trace_spapr_drc_set_allocation_state_finalizing(drc_index);
drck->detach(drc, DEVICE(drc->dev), NULL);
} else if (drc->allocation_state == SPAPR_DR_ALLOCATION_STATE_USABLE) {
drc->awaiting_allocation = false;
@@ -161,36 +167,11 @@ static uint32_t set_allocation_state(sPAPRDRConnector *drc,
return RTAS_OUT_SUCCESS;
}
-static uint32_t get_type(sPAPRDRConnector *drc)
-{
- return drc->type;
-}
-
static const char *get_name(sPAPRDRConnector *drc)
{
return drc->name;
}
-static const void *get_fdt(sPAPRDRConnector *drc, int *fdt_start_offset)
-{
- if (fdt_start_offset) {
- *fdt_start_offset = drc->fdt_start_offset;
- }
- return drc->fdt;
-}
-
-static void set_configured(sPAPRDRConnector *drc)
-{
- trace_spapr_drc_set_configured(get_index(drc));
-
- if (drc->isolation_state != SPAPR_DR_ISOLATION_STATE_UNISOLATED) {
- /* guest should be not configuring an isolated device */
- trace_spapr_drc_set_configured_skipping(get_index(drc));
- return;
- }
- drc->configured = true;
-}
-
/* has the guest been notified of device attachment? */
static void set_signalled(sPAPRDRConnector *drc)
{
@@ -207,7 +188,7 @@ static void set_signalled(sPAPRDRConnector *drc)
static uint32_t entity_sense(sPAPRDRConnector *drc, sPAPRDREntitySense *state)
{
if (drc->dev) {
- if (drc->type != SPAPR_DR_CONNECTOR_TYPE_PCI &&
+ if (spapr_drc_type(drc) != SPAPR_DR_CONNECTOR_TYPE_PCI &&
drc->allocation_state == SPAPR_DR_ALLOCATION_STATE_UNUSABLE) {
/* for logical DR, we return a state of UNUSABLE
* iff the allocation state UNUSABLE.
@@ -225,7 +206,7 @@ static uint32_t entity_sense(sPAPRDRConnector *drc, sPAPRDREntitySense *state)
*state = SPAPR_DR_ENTITY_SENSE_PRESENT;
}
} else {
- if (drc->type == SPAPR_DR_CONNECTOR_TYPE_PCI) {
+ if (spapr_drc_type(drc) == SPAPR_DR_CONNECTOR_TYPE_PCI) {
/* PCI devices, and only PCI devices, use EMPTY
* in cases where we'd otherwise use UNUSABLE
*/
@@ -235,7 +216,7 @@ static uint32_t entity_sense(sPAPRDRConnector *drc, sPAPRDREntitySense *state)
}
}
- trace_spapr_drc_entity_sense(get_index(drc), *state);
+ trace_spapr_drc_entity_sense(spapr_drc_index(drc), *state);
return RTAS_OUT_SUCCESS;
}
@@ -243,17 +224,7 @@ static void prop_get_index(Object *obj, Visitor *v, const char *name,
void *opaque, Error **errp)
{
sPAPRDRConnector *drc = SPAPR_DR_CONNECTOR(obj);
- sPAPRDRConnectorClass *drck = SPAPR_DR_CONNECTOR_GET_CLASS(drc);
- uint32_t value = (uint32_t)drck->get_index(drc);
- visit_type_uint32(v, name, &value, errp);
-}
-
-static void prop_get_type(Object *obj, Visitor *v, const char *name,
- void *opaque, Error **errp)
-{
- sPAPRDRConnector *drc = SPAPR_DR_CONNECTOR(obj);
- sPAPRDRConnectorClass *drck = SPAPR_DR_CONNECTOR_GET_CLASS(drc);
- uint32_t value = (uint32_t)drck->get_type(drc);
+ uint32_t value = spapr_drc_index(drc);
visit_type_uint32(v, name, &value, errp);
}
@@ -264,17 +235,6 @@ static char *prop_get_name(Object *obj, Error **errp)
return g_strdup(drck->get_name(drc));
}
-static void prop_get_entity_sense(Object *obj, Visitor *v, const char *name,
- void *opaque, Error **errp)
-{
- sPAPRDRConnector *drc = SPAPR_DR_CONNECTOR(obj);
- sPAPRDRConnectorClass *drck = SPAPR_DR_CONNECTOR_GET_CLASS(drc);
- uint32_t value;
-
- drck->entity_sense(drc, &value);
- visit_type_uint32(v, name, &value, errp);
-}
-
static void prop_get_fdt(Object *obj, Visitor *v, const char *name,
void *opaque, Error **errp)
{
@@ -354,13 +314,13 @@ static void prop_get_fdt(Object *obj, Visitor *v, const char *name,
static void attach(sPAPRDRConnector *drc, DeviceState *d, void *fdt,
int fdt_start_offset, bool coldplug, Error **errp)
{
- trace_spapr_drc_attach(get_index(drc));
+ trace_spapr_drc_attach(spapr_drc_index(drc));
if (drc->isolation_state != SPAPR_DR_ISOLATION_STATE_ISOLATED) {
error_setg(errp, "an attached device is still awaiting release");
return;
}
- if (drc->type == SPAPR_DR_CONNECTOR_TYPE_PCI) {
+ if (spapr_drc_type(drc) == SPAPR_DR_CONNECTOR_TYPE_PCI) {
g_assert(drc->allocation_state == SPAPR_DR_ALLOCATION_STATE_USABLE);
}
g_assert(fdt || coldplug);
@@ -372,7 +332,7 @@ static void attach(sPAPRDRConnector *drc, DeviceState *d, void *fdt,
* may be accessing the device, we can easily crash the guest, so we
* we defer completion of removal in such cases to the reset() hook.
*/
- if (drc->type == SPAPR_DR_CONNECTOR_TYPE_PCI) {
+ if (spapr_drc_type(drc) == SPAPR_DR_CONNECTOR_TYPE_PCI) {
drc->isolation_state = SPAPR_DR_ISOLATION_STATE_UNISOLATED;
}
drc->indicator_state = SPAPR_DR_INDICATOR_STATE_ACTIVE;
@@ -390,10 +350,10 @@ static void attach(sPAPRDRConnector *drc, DeviceState *d, void *fdt,
* 'physical' DR resources such as PCI where each device/resource is
* signalled individually.
*/
- drc->signalled = (drc->type != SPAPR_DR_CONNECTOR_TYPE_PCI)
+ drc->signalled = (spapr_drc_type(drc) != SPAPR_DR_CONNECTOR_TYPE_PCI)
? true : coldplug;
- if (drc->type != SPAPR_DR_CONNECTOR_TYPE_PCI) {
+ if (spapr_drc_type(drc) != SPAPR_DR_CONNECTOR_TYPE_PCI) {
drc->awaiting_allocation = true;
}
@@ -405,7 +365,7 @@ static void attach(sPAPRDRConnector *drc, DeviceState *d, void *fdt,
static void detach(sPAPRDRConnector *drc, DeviceState *d, Error **errp)
{
- trace_spapr_drc_detach(get_index(drc));
+ trace_spapr_drc_detach(spapr_drc_index(drc));
/* if we've signalled device presence to the guest, or if the guest
* has gone ahead and configured the device (via manually-executed
@@ -428,14 +388,14 @@ static void detach(sPAPRDRConnector *drc, DeviceState *d, Error **errp)
}
if (drc->isolation_state != SPAPR_DR_ISOLATION_STATE_ISOLATED) {
- trace_spapr_drc_awaiting_isolated(get_index(drc));
+ trace_spapr_drc_awaiting_isolated(spapr_drc_index(drc));
drc->awaiting_release = true;
return;
}
- if (drc->type != SPAPR_DR_CONNECTOR_TYPE_PCI &&
+ if (spapr_drc_type(drc) != SPAPR_DR_CONNECTOR_TYPE_PCI &&
drc->allocation_state != SPAPR_DR_ALLOCATION_STATE_UNUSABLE) {
- trace_spapr_drc_awaiting_unusable(get_index(drc));
+ trace_spapr_drc_awaiting_unusable(spapr_drc_index(drc));
drc->awaiting_release = true;
return;
}
@@ -443,15 +403,15 @@ static void detach(sPAPRDRConnector *drc, DeviceState *d, Error **errp)
if (drc->awaiting_allocation) {
if (!drc->awaiting_allocation_skippable) {
drc->awaiting_release = true;
- trace_spapr_drc_awaiting_allocation(get_index(drc));
+ trace_spapr_drc_awaiting_allocation(spapr_drc_index(drc));
return;
}
}
drc->indicator_state = SPAPR_DR_INDICATOR_STATE_INACTIVE;
- /* Calling release callbacks based on drc->type. */
- switch (drc->type) {
+ /* Calling release callbacks based on spapr_drc_type(drc). */
+ switch (spapr_drc_type(drc)) {
case SPAPR_DR_CONNECTOR_TYPE_CPU:
spapr_core_release(drc->dev);
break;
@@ -487,7 +447,11 @@ static void reset(DeviceState *d)
sPAPRDRConnectorClass *drck = SPAPR_DR_CONNECTOR_GET_CLASS(drc);
sPAPRDREntitySense state;
- trace_spapr_drc_reset(drck->get_index(drc));
+ trace_spapr_drc_reset(spapr_drc_index(drc));
+
+ g_free(drc->ccs);
+ drc->ccs = NULL;
+
/* immediately upon reset we can safely assume DRCs whose devices
* are pending removal can be safely removed, and that they will
* subsequently be left in an ISOLATED state. move the DRC to this
@@ -507,7 +471,7 @@ static void reset(DeviceState *d)
}
/* non-PCI devices may be awaiting a transition to UNUSABLE */
- if (drc->type != SPAPR_DR_CONNECTOR_TYPE_PCI &&
+ if (spapr_drc_type(drc) != SPAPR_DR_CONNECTOR_TYPE_PCI &&
drc->awaiting_release) {
drck->set_allocation_state(drc, SPAPR_DR_ALLOCATION_STATE_UNUSABLE);
}
@@ -536,22 +500,18 @@ static bool spapr_drc_needed(void *opaque)
* If there is dev plugged in, we need to migrate the DRC state when
* it is different from cold-plugged state
*/
- switch (drc->type) {
+ switch (spapr_drc_type(drc)) {
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) &&
+ 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_PHB:
case SPAPR_DR_CONNECTOR_TYPE_VIO:
default:
- g_assert(false);
+ g_assert_not_reached();
}
return rc;
}
@@ -576,13 +536,12 @@ static const VMStateDescription vmstate_spapr_drc = {
static void realize(DeviceState *d, Error **errp)
{
sPAPRDRConnector *drc = SPAPR_DR_CONNECTOR(d);
- sPAPRDRConnectorClass *drck = SPAPR_DR_CONNECTOR_GET_CLASS(drc);
Object *root_container;
char link_name[256];
gchar *child_name;
Error *err = NULL;
- trace_spapr_drc_realize(drck->get_index(drc));
+ trace_spapr_drc_realize(spapr_drc_index(drc));
/* NOTE: we do this as part of realize/unrealize due to the fact
* that the guest will communicate with the DRC via RTAS calls
* referencing the global DRC index. By unlinking the DRC
@@ -591,9 +550,9 @@ static void realize(DeviceState *d, Error **errp)
* existing in the composition tree
*/
root_container = container_get(object_get_root(), DRC_CONTAINER_PATH);
- snprintf(link_name, sizeof(link_name), "%x", drck->get_index(drc));
+ snprintf(link_name, sizeof(link_name), "%x", spapr_drc_index(drc));
child_name = object_get_canonical_path_component(OBJECT(drc));
- trace_spapr_drc_realize_child(drck->get_index(drc), child_name);
+ trace_spapr_drc_realize_child(spapr_drc_index(drc), child_name);
object_property_add_alias(root_container, link_name,
drc->owner, child_name, &err);
if (err) {
@@ -601,22 +560,21 @@ 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,
+ vmstate_register(DEVICE(drc), spapr_drc_index(drc), &vmstate_spapr_drc,
drc);
- trace_spapr_drc_realize_complete(drck->get_index(drc));
+ trace_spapr_drc_realize_complete(spapr_drc_index(drc));
}
static void unrealize(DeviceState *d, Error **errp)
{
sPAPRDRConnector *drc = SPAPR_DR_CONNECTOR(d);
- sPAPRDRConnectorClass *drck = SPAPR_DR_CONNECTOR_GET_CLASS(drc);
Object *root_container;
char name[256];
Error *err = NULL;
- trace_spapr_drc_unrealize(drck->get_index(drc));
+ trace_spapr_drc_unrealize(spapr_drc_index(drc));
root_container = container_get(object_get_root(), DRC_CONTAINER_PATH);
- snprintf(name, sizeof(name), "%x", drck->get_index(drc));
+ snprintf(name, sizeof(name), "%x", spapr_drc_index(drc));
object_property_del(root_container, name, &err);
if (err) {
error_report_err(err);
@@ -624,20 +582,16 @@ static void unrealize(DeviceState *d, Error **errp)
}
}
-sPAPRDRConnector *spapr_dr_connector_new(Object *owner,
- sPAPRDRConnectorType type,
+sPAPRDRConnector *spapr_dr_connector_new(Object *owner, const char *type,
uint32_t id)
{
- sPAPRDRConnector *drc =
- SPAPR_DR_CONNECTOR(object_new(TYPE_SPAPR_DR_CONNECTOR));
+ sPAPRDRConnector *drc = SPAPR_DR_CONNECTOR(object_new(type));
char *prop_name;
- g_assert(type);
-
- drc->type = type;
drc->id = id;
drc->owner = owner;
- prop_name = g_strdup_printf("dr-connector[%"PRIu32"]", get_index(drc));
+ prop_name = g_strdup_printf("dr-connector[%"PRIu32"]",
+ spapr_drc_index(drc));
object_property_add_child(owner, prop_name, OBJECT(drc), NULL);
object_property_set_bool(OBJECT(drc), true, "realized", NULL);
g_free(prop_name);
@@ -663,7 +617,7 @@ sPAPRDRConnector *spapr_dr_connector_new(Object *owner,
* DRC names as documented by PAPR+ v2.7, 13.5.2.4
* location codes as documented by PAPR+ v2.7, 12.3.1.5
*/
- switch (drc->type) {
+ switch (spapr_drc_type(drc)) {
case SPAPR_DR_CONNECTOR_TYPE_CPU:
drc->name = g_strdup_printf("CPU %d", id);
break;
@@ -682,7 +636,7 @@ sPAPRDRConnector *spapr_dr_connector_new(Object *owner,
}
/* PCI slot always start in a USABLE state, and stay there */
- if (drc->type == SPAPR_DR_CONNECTOR_TYPE_PCI) {
+ if (spapr_drc_type(drc) == SPAPR_DR_CONNECTOR_TYPE_PCI) {
drc->allocation_state = SPAPR_DR_ALLOCATION_STATE_USABLE;
}
@@ -693,20 +647,10 @@ static void spapr_dr_connector_instance_init(Object *obj)
{
sPAPRDRConnector *drc = SPAPR_DR_CONNECTOR(obj);
- object_property_add_uint32_ptr(obj, "isolation-state",
- &drc->isolation_state, NULL);
- object_property_add_uint32_ptr(obj, "indicator-state",
- &drc->indicator_state, NULL);
- object_property_add_uint32_ptr(obj, "allocation-state",
- &drc->allocation_state, NULL);
object_property_add_uint32_ptr(obj, "id", &drc->id, NULL);
object_property_add(obj, "index", "uint32", prop_get_index,
NULL, NULL, NULL, NULL);
- object_property_add(obj, "connector_type", "uint32", prop_get_type,
- NULL, NULL, NULL, NULL);
object_property_add_str(obj, "name", prop_get_name, NULL, NULL);
- object_property_add(obj, "entity-sense", "uint32", prop_get_entity_sense,
- NULL, NULL, NULL, NULL);
object_property_add(obj, "fdt", "struct", prop_get_fdt,
NULL, NULL, NULL, NULL);
}
@@ -722,11 +666,7 @@ static void spapr_dr_connector_class_init(ObjectClass *k, void *data)
drck->set_isolation_state = set_isolation_state;
drck->set_indicator_state = set_indicator_state;
drck->set_allocation_state = set_allocation_state;
- drck->get_index = get_index;
- drck->get_type = get_type;
drck->get_name = get_name;
- drck->get_fdt = get_fdt;
- drck->set_configured = set_configured;
drck->entity_sense = entity_sense;
drck->attach = attach;
drck->detach = detach;
@@ -738,6 +678,30 @@ static void spapr_dr_connector_class_init(ObjectClass *k, void *data)
dk->user_creatable = false;
}
+static void spapr_drc_cpu_class_init(ObjectClass *k, void *data)
+{
+ sPAPRDRConnectorClass *drck = SPAPR_DR_CONNECTOR_CLASS(k);
+
+ drck->typeshift = SPAPR_DR_CONNECTOR_TYPE_SHIFT_CPU;
+ drck->typename = "CPU";
+}
+
+static void spapr_drc_pci_class_init(ObjectClass *k, void *data)
+{
+ sPAPRDRConnectorClass *drck = SPAPR_DR_CONNECTOR_CLASS(k);
+
+ drck->typeshift = SPAPR_DR_CONNECTOR_TYPE_SHIFT_PCI;
+ drck->typename = "28";
+}
+
+static void spapr_drc_lmb_class_init(ObjectClass *k, void *data)
+{
+ sPAPRDRConnectorClass *drck = SPAPR_DR_CONNECTOR_CLASS(k);
+
+ drck->typeshift = SPAPR_DR_CONNECTOR_TYPE_SHIFT_LMB;
+ drck->typename = "MEM";
+}
+
static const TypeInfo spapr_dr_connector_info = {
.name = TYPE_SPAPR_DR_CONNECTOR,
.parent = TYPE_DEVICE,
@@ -745,18 +709,47 @@ static const TypeInfo spapr_dr_connector_info = {
.instance_init = spapr_dr_connector_instance_init,
.class_size = sizeof(sPAPRDRConnectorClass),
.class_init = spapr_dr_connector_class_init,
+ .abstract = true,
};
-static void spapr_drc_register_types(void)
-{
- type_register_static(&spapr_dr_connector_info);
-}
+static const TypeInfo spapr_drc_physical_info = {
+ .name = TYPE_SPAPR_DRC_PHYSICAL,
+ .parent = TYPE_SPAPR_DR_CONNECTOR,
+ .instance_size = sizeof(sPAPRDRConnector),
+ .abstract = true,
+};
-type_init(spapr_drc_register_types)
+static const TypeInfo spapr_drc_logical_info = {
+ .name = TYPE_SPAPR_DRC_LOGICAL,
+ .parent = TYPE_SPAPR_DR_CONNECTOR,
+ .instance_size = sizeof(sPAPRDRConnector),
+ .abstract = true,
+};
+
+static const TypeInfo spapr_drc_cpu_info = {
+ .name = TYPE_SPAPR_DRC_CPU,
+ .parent = TYPE_SPAPR_DRC_LOGICAL,
+ .instance_size = sizeof(sPAPRDRConnector),
+ .class_init = spapr_drc_cpu_class_init,
+};
+
+static const TypeInfo spapr_drc_pci_info = {
+ .name = TYPE_SPAPR_DRC_PCI,
+ .parent = TYPE_SPAPR_DRC_PHYSICAL,
+ .instance_size = sizeof(sPAPRDRConnector),
+ .class_init = spapr_drc_pci_class_init,
+};
+
+static const TypeInfo spapr_drc_lmb_info = {
+ .name = TYPE_SPAPR_DRC_LMB,
+ .parent = TYPE_SPAPR_DRC_LOGICAL,
+ .instance_size = sizeof(sPAPRDRConnector),
+ .class_init = spapr_drc_lmb_class_init,
+};
/* helper functions for external users */
-sPAPRDRConnector *spapr_dr_connector_by_index(uint32_t index)
+sPAPRDRConnector *spapr_drc_by_index(uint32_t index)
{
Object *obj;
char name[256];
@@ -767,37 +760,13 @@ sPAPRDRConnector *spapr_dr_connector_by_index(uint32_t index)
return !obj ? NULL : SPAPR_DR_CONNECTOR(obj);
}
-sPAPRDRConnector *spapr_dr_connector_by_id(sPAPRDRConnectorType type,
- uint32_t id)
+sPAPRDRConnector *spapr_drc_by_id(const char *type, uint32_t id)
{
- return spapr_dr_connector_by_index(
- (get_type_shift(type) << DRC_INDEX_TYPE_SHIFT) |
- (id & DRC_INDEX_ID_MASK));
-}
-
-/* generate a string the describes the DRC to encode into the
- * device tree.
- *
- * as documented by PAPR+ v2.7, 13.5.2.6 and C.6.1
- */
-static const char *spapr_drc_get_type_str(sPAPRDRConnectorType type)
-{
- switch (type) {
- case SPAPR_DR_CONNECTOR_TYPE_CPU:
- return "CPU";
- case SPAPR_DR_CONNECTOR_TYPE_PHB:
- return "PHB";
- case SPAPR_DR_CONNECTOR_TYPE_VIO:
- return "SLOT";
- case SPAPR_DR_CONNECTOR_TYPE_PCI:
- return "28";
- case SPAPR_DR_CONNECTOR_TYPE_LMB:
- return "MEM";
- default:
- g_assert(false);
- }
+ sPAPRDRConnectorClass *drck
+ = SPAPR_DR_CONNECTOR_CLASS(object_class_by_name(type));
- return NULL;
+ return spapr_drc_by_index(drck->typeshift << DRC_INDEX_TYPE_SHIFT
+ | (id & DRC_INDEX_ID_MASK));
}
/**
@@ -862,14 +831,14 @@ int spapr_drc_populate_dt(void *fdt, int fdt_offset, Object *owner,
continue;
}
- if ((drc->type & drc_type_mask) == 0) {
+ if ((spapr_drc_type(drc) & drc_type_mask) == 0) {
continue;
}
drc_count++;
/* ibm,drc-indexes */
- drc_index = cpu_to_be32(drck->get_index(drc));
+ drc_index = cpu_to_be32(spapr_drc_index(drc));
g_array_append_val(drc_indexes, drc_index);
/* ibm,drc-power-domains */
@@ -881,8 +850,7 @@ int spapr_drc_populate_dt(void *fdt, int fdt_offset, Object *owner,
drc_names = g_string_insert_len(drc_names, -1, "\0", 1);
/* ibm,drc-types */
- drc_types = g_string_append(drc_types,
- spapr_drc_get_type_str(drc->type));
+ drc_types = g_string_append(drc_types, drck->typename);
drc_types = g_string_insert_len(drc_types, -1, "\0", 1);
}
@@ -932,3 +900,276 @@ out:
return ret;
}
+
+/*
+ * RTAS calls
+ */
+
+static bool sensor_type_is_dr(uint32_t sensor_type)
+{
+ switch (sensor_type) {
+ case RTAS_SENSOR_TYPE_ISOLATION_STATE:
+ case RTAS_SENSOR_TYPE_DR:
+ case RTAS_SENSOR_TYPE_ALLOCATION_STATE:
+ return true;
+ }
+
+ return false;
+}
+
+static void rtas_set_indicator(PowerPCCPU *cpu, sPAPRMachineState *spapr,
+ uint32_t token, uint32_t nargs,
+ target_ulong args, uint32_t nret,
+ target_ulong rets)
+{
+ uint32_t sensor_type;
+ uint32_t sensor_index;
+ uint32_t sensor_state;
+ uint32_t ret = RTAS_OUT_SUCCESS;
+ sPAPRDRConnector *drc;
+ sPAPRDRConnectorClass *drck;
+
+ if (nargs != 3 || nret != 1) {
+ ret = RTAS_OUT_PARAM_ERROR;
+ goto out;
+ }
+
+ sensor_type = rtas_ld(args, 0);
+ sensor_index = rtas_ld(args, 1);
+ sensor_state = rtas_ld(args, 2);
+
+ if (!sensor_type_is_dr(sensor_type)) {
+ goto out_unimplemented;
+ }
+
+ /* if this is a DR sensor we can assume sensor_index == drc_index */
+ drc = spapr_drc_by_index(sensor_index);
+ if (!drc) {
+ trace_spapr_rtas_set_indicator_invalid(sensor_index);
+ ret = RTAS_OUT_PARAM_ERROR;
+ goto out;
+ }
+ drck = SPAPR_DR_CONNECTOR_GET_CLASS(drc);
+
+ switch (sensor_type) {
+ case RTAS_SENSOR_TYPE_ISOLATION_STATE:
+ ret = drck->set_isolation_state(drc, sensor_state);
+ break;
+ case RTAS_SENSOR_TYPE_DR:
+ ret = drck->set_indicator_state(drc, sensor_state);
+ break;
+ case RTAS_SENSOR_TYPE_ALLOCATION_STATE:
+ ret = drck->set_allocation_state(drc, sensor_state);
+ break;
+ default:
+ goto out_unimplemented;
+ }
+
+out:
+ rtas_st(rets, 0, ret);
+ return;
+
+out_unimplemented:
+ /* currently only DR-related sensors are implemented */
+ trace_spapr_rtas_set_indicator_not_supported(sensor_index, sensor_type);
+ rtas_st(rets, 0, RTAS_OUT_NOT_SUPPORTED);
+}
+
+static void rtas_get_sensor_state(PowerPCCPU *cpu, sPAPRMachineState *spapr,
+ uint32_t token, uint32_t nargs,
+ target_ulong args, uint32_t nret,
+ target_ulong rets)
+{
+ uint32_t sensor_type;
+ uint32_t sensor_index;
+ uint32_t sensor_state = 0;
+ sPAPRDRConnector *drc;
+ sPAPRDRConnectorClass *drck;
+ uint32_t ret = RTAS_OUT_SUCCESS;
+
+ if (nargs != 2 || nret != 2) {
+ ret = RTAS_OUT_PARAM_ERROR;
+ goto out;
+ }
+
+ sensor_type = rtas_ld(args, 0);
+ sensor_index = rtas_ld(args, 1);
+
+ if (sensor_type != RTAS_SENSOR_TYPE_ENTITY_SENSE) {
+ /* currently only DR-related sensors are implemented */
+ trace_spapr_rtas_get_sensor_state_not_supported(sensor_index,
+ sensor_type);
+ ret = RTAS_OUT_NOT_SUPPORTED;
+ goto out;
+ }
+
+ drc = spapr_drc_by_index(sensor_index);
+ if (!drc) {
+ trace_spapr_rtas_get_sensor_state_invalid(sensor_index);
+ ret = RTAS_OUT_PARAM_ERROR;
+ goto out;
+ }
+ drck = SPAPR_DR_CONNECTOR_GET_CLASS(drc);
+ ret = drck->entity_sense(drc, &sensor_state);
+
+out:
+ rtas_st(rets, 0, ret);
+ rtas_st(rets, 1, sensor_state);
+}
+
+/* configure-connector work area offsets, int32_t units for field
+ * indexes, bytes for field offset/len values.
+ *
+ * as documented by PAPR+ v2.7, 13.5.3.5
+ */
+#define CC_IDX_NODE_NAME_OFFSET 2
+#define CC_IDX_PROP_NAME_OFFSET 2
+#define CC_IDX_PROP_LEN 3
+#define CC_IDX_PROP_DATA_OFFSET 4
+#define CC_VAL_DATA_OFFSET ((CC_IDX_PROP_DATA_OFFSET + 1) * 4)
+#define CC_WA_LEN 4096
+
+static void configure_connector_st(target_ulong addr, target_ulong offset,
+ const void *buf, size_t len)
+{
+ cpu_physical_memory_write(ppc64_phys_to_real(addr + offset),
+ buf, MIN(len, CC_WA_LEN - offset));
+}
+
+static void rtas_ibm_configure_connector(PowerPCCPU *cpu,
+ sPAPRMachineState *spapr,
+ uint32_t token, uint32_t nargs,
+ target_ulong args, uint32_t nret,
+ target_ulong rets)
+{
+ uint64_t wa_addr;
+ uint64_t wa_offset;
+ uint32_t drc_index;
+ sPAPRDRConnector *drc;
+ sPAPRConfigureConnectorState *ccs;
+ sPAPRDRCCResponse resp = SPAPR_DR_CC_RESPONSE_CONTINUE;
+ int rc;
+
+ if (nargs != 2 || nret != 1) {
+ rtas_st(rets, 0, RTAS_OUT_PARAM_ERROR);
+ return;
+ }
+
+ wa_addr = ((uint64_t)rtas_ld(args, 1) << 32) | rtas_ld(args, 0);
+
+ drc_index = rtas_ld(wa_addr, 0);
+ drc = spapr_drc_by_index(drc_index);
+ if (!drc) {
+ trace_spapr_rtas_ibm_configure_connector_invalid(drc_index);
+ rc = RTAS_OUT_PARAM_ERROR;
+ goto out;
+ }
+
+ if (!drc->fdt) {
+ trace_spapr_rtas_ibm_configure_connector_missing_fdt(drc_index);
+ rc = SPAPR_DR_CC_RESPONSE_NOT_CONFIGURABLE;
+ goto out;
+ }
+
+ ccs = drc->ccs;
+ if (!ccs) {
+ ccs = g_new0(sPAPRConfigureConnectorState, 1);
+ ccs->fdt_offset = drc->fdt_start_offset;
+ drc->ccs = ccs;
+ }
+
+ do {
+ uint32_t tag;
+ const char *name;
+ const struct fdt_property *prop;
+ int fdt_offset_next, prop_len;
+
+ tag = fdt_next_tag(drc->fdt, ccs->fdt_offset, &fdt_offset_next);
+
+ switch (tag) {
+ case FDT_BEGIN_NODE:
+ ccs->fdt_depth++;
+ name = fdt_get_name(drc->fdt, ccs->fdt_offset, NULL);
+
+ /* provide the name of the next OF node */
+ wa_offset = CC_VAL_DATA_OFFSET;
+ rtas_st(wa_addr, CC_IDX_NODE_NAME_OFFSET, wa_offset);
+ configure_connector_st(wa_addr, wa_offset, name, strlen(name) + 1);
+ resp = SPAPR_DR_CC_RESPONSE_NEXT_CHILD;
+ break;
+ case FDT_END_NODE:
+ ccs->fdt_depth--;
+ if (ccs->fdt_depth == 0) {
+ sPAPRDRIsolationState state = drc->isolation_state;
+ uint32_t drc_index = spapr_drc_index(drc);
+ /* done sending the device tree, don't need to track
+ * the state anymore
+ */
+ trace_spapr_drc_set_configured(drc_index);
+ if (state == SPAPR_DR_ISOLATION_STATE_UNISOLATED) {
+ drc->configured = true;
+ } else {
+ /* guest should be not configuring an isolated device */
+ trace_spapr_drc_set_configured_skipping(drc_index);
+ }
+ g_free(ccs);
+ drc->ccs = NULL;
+ ccs = NULL;
+ resp = SPAPR_DR_CC_RESPONSE_SUCCESS;
+ } else {
+ resp = SPAPR_DR_CC_RESPONSE_PREV_PARENT;
+ }
+ break;
+ case FDT_PROP:
+ prop = fdt_get_property_by_offset(drc->fdt, ccs->fdt_offset,
+ &prop_len);
+ name = fdt_string(drc->fdt, fdt32_to_cpu(prop->nameoff));
+
+ /* provide the name of the next OF property */
+ wa_offset = CC_VAL_DATA_OFFSET;
+ rtas_st(wa_addr, CC_IDX_PROP_NAME_OFFSET, wa_offset);
+ configure_connector_st(wa_addr, wa_offset, name, strlen(name) + 1);
+
+ /* provide the length and value of the OF property. data gets
+ * placed immediately after NULL terminator of the OF property's
+ * name string
+ */
+ wa_offset += strlen(name) + 1,
+ rtas_st(wa_addr, CC_IDX_PROP_LEN, prop_len);
+ rtas_st(wa_addr, CC_IDX_PROP_DATA_OFFSET, wa_offset);
+ configure_connector_st(wa_addr, wa_offset, prop->data, prop_len);
+ resp = SPAPR_DR_CC_RESPONSE_NEXT_PROPERTY;
+ break;
+ case FDT_END:
+ resp = SPAPR_DR_CC_RESPONSE_ERROR;
+ default:
+ /* keep seeking for an actionable tag */
+ break;
+ }
+ if (ccs) {
+ ccs->fdt_offset = fdt_offset_next;
+ }
+ } while (resp == SPAPR_DR_CC_RESPONSE_CONTINUE);
+
+ rc = resp;
+out:
+ rtas_st(rets, 0, rc);
+}
+
+static void spapr_drc_register_types(void)
+{
+ type_register_static(&spapr_dr_connector_info);
+ type_register_static(&spapr_drc_physical_info);
+ type_register_static(&spapr_drc_logical_info);
+ type_register_static(&spapr_drc_cpu_info);
+ type_register_static(&spapr_drc_pci_info);
+ type_register_static(&spapr_drc_lmb_info);
+
+ spapr_rtas_register(RTAS_SET_INDICATOR, "set-indicator",
+ rtas_set_indicator);
+ spapr_rtas_register(RTAS_GET_SENSOR_STATE, "get-sensor-state",
+ rtas_get_sensor_state);
+ spapr_rtas_register(RTAS_IBM_CONFIGURE_CONNECTOR, "ibm,configure-connector",
+ rtas_ibm_configure_connector);
+}
+type_init(spapr_drc_register_types)