[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]
Re: [Qemu-ppc] [Qemu-devel] [PATCH v4 02/17] spapr_drc: initial implemen
From: |
David Gibson |
Subject: |
Re: [Qemu-ppc] [Qemu-devel] [PATCH v4 02/17] spapr_drc: initial implementation of sPAPRDRConnector device |
Date: |
Fri, 16 Jan 2015 17:19:08 +1100 |
User-agent: |
Mutt/1.5.23 (2014-03-12) |
On Tue, Dec 23, 2014 at 06:30:16AM -0600, Michael Roth wrote:
> This device emulates a firmware abstraction used by pSeries guests to
> manage hotplug/dynamic-reconfiguration of host-bridges, PCI devices,
> memory, and CPUs. It is conceptually similar to an SHPC device,
> complete with LED indicators to identify individual slots to physical
> physical users and indicate when it is safe to remove a device. In
> some cases it is also used to manage virtualized resources, such a
> memory, CPUs, and physical-host bridges, which in the case of pSeries
> guests are virtualized resources where the physical components are
> managed by the host.
>
> Guests communicate with these DR Connectors using RTAS calls,
> generally by addressing the unique DRC index associated with a
> particular connector for a particular resource. For introspection
> purposes we expose this state initially as QOM properties, and
> in subsequent patches will introduce the RTAS calls that make use of
> it. This constitutes to the 'guest' interface.
>
> On the QEMU side we provide an attach/detach interface to associate
> or cleanup a DeviceState with a particular sPAPRDRConnector in
> response to hotplug/unplug, respectively. This constitutes the
> 'physical' interface to the DR Connector.
>
> Signed-off-by: Michael Roth <address@hidden>
> ---
> hw/ppc/Makefile.objs | 2 +-
> hw/ppc/spapr_drc.c | 503
> +++++++++++++++++++++++++++++++++++++++++++++
> include/hw/ppc/spapr_drc.h | 201 ++++++++++++++++++
> 3 files changed, 705 insertions(+), 1 deletion(-)
> create mode 100644 hw/ppc/spapr_drc.c
> create mode 100644 include/hw/ppc/spapr_drc.h
>
> diff --git a/hw/ppc/Makefile.objs b/hw/ppc/Makefile.objs
> index 19d9920..ea010fd 100644
> --- a/hw/ppc/Makefile.objs
> +++ b/hw/ppc/Makefile.objs
> @@ -3,7 +3,7 @@ obj-y += ppc.o ppc_booke.o
> # IBM pSeries (sPAPR)
> obj-$(CONFIG_PSERIES) += spapr.o spapr_vio.o spapr_events.o
> obj-$(CONFIG_PSERIES) += spapr_hcall.o spapr_iommu.o spapr_rtas.o
> -obj-$(CONFIG_PSERIES) += spapr_pci.o
> +obj-$(CONFIG_PSERIES) += spapr_pci.o spapr_drc.o
> ifeq ($(CONFIG_PCI)$(CONFIG_PSERIES)$(CONFIG_LINUX), yyy)
> obj-y += spapr_pci_vfio.o
> endif
> diff --git a/hw/ppc/spapr_drc.c b/hw/ppc/spapr_drc.c
> new file mode 100644
> index 0000000..f81c6d1
> --- /dev/null
> +++ b/hw/ppc/spapr_drc.c
> @@ -0,0 +1,503 @@
> +/*
> + * QEMU SPAPR Dynamic Reconfiguration Connector Implementation
> + *
> + * Copyright IBM Corp. 2014
> + *
> + * Authors:
> + * Michael Roth <address@hidden>
> + *
> + * This work is licensed under the terms of the GNU GPL, version 2 or later.
> + * See the COPYING file in the top-level directory.
> + */
> +
> +#include "hw/ppc/spapr_drc.h"
> +#include "qom/object.h"
> +#include "hw/qdev.h"
> +#include "qapi/visitor.h"
> +#include "qemu/error-report.h"
> +
> +/* #define DEBUG_SPAPR_DRC */
> +
> +#ifdef DEBUG_SPAPR_DRC
> +#define DPRINTF(fmt, ...) \
> + do { fprintf(stderr, fmt, ## __VA_ARGS__); } while (0)
> +#define DPRINTFN(fmt, ...) \
> + do { DPRINTF(fmt, ## __VA_ARGS__); fprintf(stderr, "\n"); } while (0)
> +#else
> +#define DPRINTF(fmt, ...) \
> + do { } while (0)
> +#define DPRINTFN(fmt, ...) \
> + do { } while (0)
> +#endif
> +
> +#define DRC_CONTAINER_PATH "/dr-connector"
> +#define DRC_INDEX_TYPE_SHIFT 28
> +#define DRC_INDEX_ID_MASK ~(~0 << DRC_INDEX_TYPE_SHIFT)
I'm not sure if there are actually any situations where it can break,
but safest to put parens around the whole macro body, just in case of
macro vs. precedence weirdness.
> +static int set_isolation_state(sPAPRDRConnector *drc,
> + sPAPRDRIsolationState state)
> +{
> + sPAPRDRConnectorClass *drck = SPAPR_DR_CONNECTOR_GET_CLASS(drc);
> +
> + DPRINTFN("set_isolation_state: %x", state);
> + drc->isolation_state = state;
> + if (drc->awaiting_release &&
> + drc->isolation_state == SPAPR_DR_ISOLATION_STATE_ISOLATED) {
> + drck->detach(drc, DEVICE(drc->dev), drc->detach_cb,
> + drc->detach_cb_opaque);
> + }
> + return 0;
> +}
> +
> +static int set_indicator_state(sPAPRDRConnector *drc,
> + sPAPRDRIndicatorState state)
> +{
> + DPRINTFN("set_indicator_state: %x", state);
> + drc->indicator_state = state;
> + return 0;
> +}
> +
> +static int set_allocation_state(sPAPRDRConnector *drc,
> + sPAPRDRAllocationState state)
> +{
> + DPRINTFN("set_allocation_state: %x", state);
> + drc->indicator_state = state;
This should be drc->allocation_state, surely.
> + return 0;
> +}
> +
> +static uint32_t get_id(sPAPRDRConnector *drc)
> +{
> + /* this value is unique for DRCs of a particular type, but may
> + * overlap with the id's of other DRCs. the value is used both
> + * to calculate a unique (across all DRC types) index, as well
> + * as generating the ibm,drc-names OFDT property that describes
> + * DRCs
> + */
> + return drc->id;
> +}
Since this is static anyway, why not just reference drc->id directly?
> +static sPAPRDRConnectorTypeShift get_type_shift(sPAPRDRConnectorType type)
> +{
> + uint32_t shift = 0;
> +
> + g_assert(type != SPAPR_DR_CONNECTOR_TYPE_ANY);
> + while (type != (1 << shift)) {
> + shift++;
> + }
> + return shift;
> +}
> +
> +static uint32_t get_index(sPAPRDRConnector *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);
> +}
> +
> +static uint32_t get_type(sPAPRDRConnector *drc)
> +{
> + return drc->type;
> +}
> +
> +/*
> + * dr-entity-sense sensor value
> + * returned via get-sensor-state RTAS calls
> + * as expected by state diagram in PAPR+ 2.7, 13.4
> + * based on the current allocation/indicator/power states
> + * for the DR connector.
> + */
> +static sPAPRDREntitySense entity_sense(sPAPRDRConnector *drc)
> +{
> + if (drc->dev) {
> + /* this assumes all PCI devices are assigned to
> + * a 'live insertion' power domain, where QEMU
> + * manages power state automatically as opposed
> + * to the guest. present, non-PCI resources are
> + * unaffected by power state.
> + */
Is it possible to make an assert() to check that?
> + return SPAPR_DR_ENTITY_SENSE_PRESENT;
> + }
> +
> + if (drc->type == SPAPR_DR_CONNECTOR_TYPE_PCI) {
> + /* PCI devices, and only PCI devices, use PRESENT
> + * in cases where we'd otherwise use UNUSABLE
> + */
> + return SPAPR_DR_ENTITY_SENSE_EMPTY;
> + }
> + return SPAPR_DR_ENTITY_SENSE_UNUSABLE;
> +}
> +
> +static sPAPRDRCCResponse configure_connector_common(sPAPRDRCCState *ccs,
> + char **prop_name, const struct fdt_property
> **prop,
Maybe rename prop_name to name, since it's also used for node names.
> + int *prop_len)
> +{
> + sPAPRDRCCResponse resp = SPAPR_DR_CC_RESPONSE_CONTINUE;
> + int fdt_offset_next;
> +
> + *prop_name = NULL;
> + *prop = NULL;
> + *prop_len = 0;
> +
> + if (!ccs->fdt) {
> + return SPAPR_DR_CC_RESPONSE_ERROR;
> + }
> +
> + while (resp == SPAPR_DR_CC_RESPONSE_CONTINUE) {
> + const char *name_cur;
> + uint32_t tag;
> + int name_cur_len;
> +
> + tag = fdt_next_tag(ccs->fdt, ccs->fdt_offset, &fdt_offset_next);
> + switch (tag) {
> + case FDT_BEGIN_NODE:
> + ccs->fdt_depth++;
> + name_cur = fdt_get_name(ccs->fdt, ccs->fdt_offset,
> &name_cur_len);
> + *prop_name = g_strndup(name_cur, name_cur_len);
> + resp = SPAPR_DR_CC_RESPONSE_NEXT_CHILD;
> + break;
> + case FDT_END_NODE:
> + ccs->fdt_depth--;
> + if (ccs->fdt_depth == 0) {
> + resp = SPAPR_DR_CC_RESPONSE_SUCCESS;
> + } else {
> + resp = SPAPR_DR_CC_RESPONSE_PREV_PARENT;
> + }
> + break;
> + case FDT_PROP:
> + *prop = fdt_get_property_by_offset(ccs->fdt, ccs->fdt_offset,
> + prop_len);
> + name_cur = fdt_string(ccs->fdt, fdt32_to_cpu((*prop)->nameoff));
> + *prop_name = g_strdup(name_cur);
> + resp = SPAPR_DR_CC_RESPONSE_NEXT_PROPERTY;
> + break;
> + case FDT_END:
> + resp = SPAPR_DR_CC_RESPONSE_ERROR;
> + break;
IIUC, the fdt fragment you're stepping through here is generated
within qemu. In which case shouldn't this be an assert, rather than
reporting an error to the guest?
> + default:
> + ccs->fdt_offset = fdt_offset_next;
> + }
> + }
> +
> + ccs->fdt_offset = fdt_offset_next;
> + return resp;
> +}
> +
> +static sPAPRDRCCResponse configure_connector(sPAPRDRConnector *drc,
> + char **prop_name,
> + const struct fdt_property
> **prop,
> + int *prop_len)
> +{
> + return configure_connector_common(&drc->ccs, prop_name, prop, prop_len);
> +}
> +
> +static void prop_get_id(Object *obj, Visitor *v, void *opaque,
> + const char *name, Error **errp)
> +{
> + sPAPRDRConnector *drc = SPAPR_DR_CONNECTOR(obj);
> + uint32_t value = get_id(drc);
> + visit_type_uint32(v, &value, name, errp);
> +}
> +
> +static void prop_get_index(Object *obj, Visitor *v, void *opaque,
> + const char *name, 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, &value, name, errp);
> +}
> +
> +static void prop_get_type(Object *obj, Visitor *v, void *opaque,
> + const char *name, 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);
> + visit_type_uint32(v, &value, name, errp);
> +}
> +
> +static void prop_get_entity_sense(Object *obj, Visitor *v, void *opaque,
> + const char *name, Error **errp)
> +{
> + sPAPRDRConnector *drc = SPAPR_DR_CONNECTOR(obj);
> + sPAPRDRConnectorClass *drck = SPAPR_DR_CONNECTOR_GET_CLASS(drc);
> + uint32_t value = (uint32_t)drck->entity_sense(drc);
> + visit_type_uint32(v, &value, name, errp);
> +}
> +
> +static void prop_get_fdt(Object *obj, Visitor *v, void *opaque,
> + const char *name, Error **errp)
> +{
> + sPAPRDRConnector *drc = SPAPR_DR_CONNECTOR(obj);
> + sPAPRDRCCState ccs = { 0 };
> + sPAPRDRCCResponse resp;
> +
> + ccs.fdt = drc->ccs.fdt;
> + ccs.fdt_offset = ccs.fdt_start_offset = drc->ccs.fdt_start_offset;
> +
> + do {
> + char *prop_name = NULL;
> + const struct fdt_property *prop = NULL;
> + int prop_len;
> +
> + resp = configure_connector_common(&ccs, &prop_name, &prop,
> &prop_len);
> +
> + switch (resp) {
> + case SPAPR_DR_CC_RESPONSE_NEXT_CHILD:
> + visit_start_struct(v, NULL, NULL, prop_name, 0, NULL);
> + break;
> + case SPAPR_DR_CC_RESPONSE_PREV_PARENT:
> + visit_end_struct(v, NULL);
> + break;
> + case SPAPR_DR_CC_RESPONSE_NEXT_PROPERTY: {
> + int i;
> + visit_start_list(v, prop_name, NULL);
> + for (i = 0; i < prop_len; i++) {
> + visit_type_uint8(v, (uint8_t *)&prop->data[i], NULL, NULL);
> + }
> + visit_end_list(v, NULL);
> + break;
> + }
> + default:
> + resp = SPAPR_DR_CC_RESPONSE_SUCCESS;
> + break;
> + }
> +
> + g_free(prop_name);
> + } while (resp != SPAPR_DR_CC_RESPONSE_SUCCESS &&
> + resp != SPAPR_DR_CC_RESPONSE_ERROR);
> +}
> +
> +static void attach(sPAPRDRConnector *drc, DeviceState *d, void *fdt,
> + int fdt_start_offset, bool coldplug)
> +{
> + DPRINTFN("attach");
> +
> + g_assert(drc->isolation_state == SPAPR_DR_ISOLATION_STATE_ISOLATED);
> + g_assert(drc->allocation_state == SPAPR_DR_ALLOCATION_STATE_UNUSABLE);
> + g_assert(drc->indicator_state == SPAPR_DR_INDICATOR_STATE_INACTIVE);
> + g_assert(fdt || coldplug);
> +
> + /* NOTE: setting initial isolation state to UNISOLATED means we can't
> + * detach unless guest has a userspace/kernel that moves this state
> + * back to ISOLATED in response to an unplug event, or this is done
> + * manually by the admin prior. if we force things while the guest
> + * 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.
> + */
Given that, would it make more sense to start in ISOLATED state? Or
is the initial state specified by PAPR?
> + drc->isolation_state = SPAPR_DR_ISOLATION_STATE_UNISOLATED;
> + drc->allocation_state = SPAPR_DR_ALLOCATION_STATE_USABLE;
> + drc->indicator_state = SPAPR_DR_INDICATOR_STATE_ACTIVE;
> +
> + drc->dev = d;
> + drc->ccs.fdt = fdt;
> + drc->ccs.fdt_offset = drc->ccs.fdt_start_offset = fdt_start_offset;
> + drc->ccs.fdt_depth = 0;
> +
> + object_property_add_link(OBJECT(drc), "device",
> + object_get_typename(OBJECT(drc->dev)),
> + (Object **)(&drc->dev),
> + NULL, 0, NULL);
> +}
> +
> +static void detach(sPAPRDRConnector *drc, DeviceState *d,
> + spapr_drc_detach_cb *detach_cb,
> + void *detach_cb_opaque)
> +{
> + DPRINTFN("detach");
> +
> + drc->detach_cb = detach_cb;
> + drc->detach_cb_opaque = detach_cb_opaque;
> +
> + if (drc->isolation_state != SPAPR_DR_ISOLATION_STATE_ISOLATED) {
> + DPRINTFN("awaiting transition to isolated state before removal");
> + drc->awaiting_release = true;
> + return;
> + }
> +
> + drc->allocation_state = SPAPR_DR_ALLOCATION_STATE_UNUSABLE;
> + drc->indicator_state = SPAPR_DR_INDICATOR_STATE_INACTIVE;
> +
> + if (drc->detach_cb) {
> + drc->detach_cb(drc->dev, drc->detach_cb_opaque);
> + }
> +
> + drc->awaiting_release = false;
> + g_free(drc->ccs.fdt);
> + drc->ccs.fdt = NULL;
> + drc->ccs.fdt_offset = drc->ccs.fdt_start_offset = drc->ccs.fdt_depth = 0;
> + object_property_del(OBJECT(drc), "device", NULL);
> + drc->dev = NULL;
> + drc->detach_cb = NULL;
> + drc->detach_cb_opaque = NULL;
Shouldn't all this code after the detach_cb call also be called from
set_isolation_state in the case of a deferred detach? In which case
you probably want a helper.
> +}
> +
> +static void reset(DeviceState *d)
> +{
> + sPAPRDRConnector *drc = SPAPR_DR_CONNECTOR(d);
> + sPAPRDRConnectorClass *drck = SPAPR_DR_CONNECTOR_GET_CLASS(drc);
> +
> + DPRINTFN("drc reset: %x", drck->get_index(drc));
> + /* 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 state in these cases (which
> will in
> + * turn complete any pending device removals)
> + */
> + if (drc->awaiting_release) {
> + drck->set_isolation_state(drc, SPAPR_DR_ISOLATION_STATE_ISOLATED);
> + }
> +}
> +
> +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;
> +
> + DPRINTFN("drc realize: %x", drck->get_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
> + * from DRC_CONTAINER_PATH/<drc_index> we effectively make it
> + * inaccessible by the guest, since lookups rely on this path
> + * 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));
> + child_name = object_get_canonical_path_component(OBJECT(drc));
> + DPRINTFN("drc child name: %s", child_name);
> + object_property_add_alias(root_container, link_name,
> + drc->owner, child_name, &err);
> + /*
> + object_property_add_link(root_container, name, TYPE_SPAPR_DR_CONNECTOR,
> + (Object **)&drc, NULL,
> + OBJ_PROP_LINK_UNREF_ON_RELEASE, &err);
> + */
> + if (err) {
> + error_report("%s", error_get_pretty(err));
> + error_free(err);
> + object_unref(OBJECT(drc));
> + }
> + DPRINTFN("drc realize complete");
> +}
> +
> +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;
> +
> + DPRINTFN("drc unrealize: %x", drck->get_index(drc));
> + root_container = container_get(object_get_root(), DRC_CONTAINER_PATH);
> + snprintf(name, sizeof(name), "%x", drck->get_index(drc));
> + object_property_del(root_container, name, &err);
> + if (err) {
> + error_report("%s", error_get_pretty(err));
> + error_free(err);
> + object_unref(OBJECT(drc));
> + }
> +}
> +
> +sPAPRDRConnector *spapr_dr_connector_new(Object *owner,
> + sPAPRDRConnectorType type,
> + uint32_t id)
> +{
> + sPAPRDRConnector *drc =
> + SPAPR_DR_CONNECTOR(object_new(TYPE_SPAPR_DR_CONNECTOR));
> +
> + g_assert(type);
> +
> + drc->type = type;
> + drc->id = id;
> + drc->owner = owner;
> + object_property_add_child(owner, "dr-connector[*]", OBJECT(drc), NULL);
> + object_property_set_bool(OBJECT(drc), true, "realized", NULL);
> +
> + return drc;
> +}
> +
> +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);
Don't these QOM properties need to be bound to set_isolation_state
etc. for the write side? Or does add_uint32_ptr only allow reads?
> + object_property_add(obj, "id", "uint32", prop_get_id,
> + NULL, NULL, NULL, NULL);
> + object_property_add(obj, "index", "uint32", prop_get_index,
> + NULL, NULL, NULL, NULL);
> + object_property_add(obj, "index", "uint32", prop_get_type,
> + NULL, NULL, 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);
> +}
> +
> +static void spapr_dr_connector_class_init(ObjectClass *k, void *data)
> +{
> + DeviceClass *dk = DEVICE_CLASS(k);
> + sPAPRDRConnectorClass *drck = SPAPR_DR_CONNECTOR_CLASS(k);
> +
> + dk->reset = reset;
> + dk->realize = realize;
> + dk->unrealize = unrealize;
> + 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->entity_sense = entity_sense;
> + drck->configure_connector = configure_connector;
> + drck->attach = attach;
> + drck->detach = detach;
> +}
> +
> +static const TypeInfo spapr_dr_connector_info = {
> + .name = TYPE_SPAPR_DR_CONNECTOR,
> + .parent = TYPE_DEVICE,
> + .instance_size = sizeof(sPAPRDRConnector),
> + .instance_init = spapr_dr_connector_instance_init,
> + .class_size = sizeof(sPAPRDRConnectorClass),
> + .class_init = spapr_dr_connector_class_init,
> +};
> +
> +static void spapr_drc_register_types(void)
> +{
> + type_register_static(&spapr_dr_connector_info);
> +}
> +
> +type_init(spapr_drc_register_types)
> +
> +/* helper functions for external users */
> +
> +sPAPRDRConnector *spapr_dr_connector_by_index(uint32_t index)
> +{
> + Object *obj;
> + char name[256];
> +
> + snprintf(name, sizeof(name), "%s/%x", DRC_CONTAINER_PATH, index);
> + obj = object_resolve_path(name, NULL);
> +
> + return !obj ? NULL : SPAPR_DR_CONNECTOR(obj);
> +}
> +
> +sPAPRDRConnector *spapr_dr_connector_by_id(sPAPRDRConnectorType type,
> + uint32_t id)
> +{
> + return spapr_dr_connector_by_index(
> + (get_type_shift(type) << DRC_INDEX_TYPE_SHIFT) |
> + (id & DRC_INDEX_ID_MASK));
> +}
> diff --git a/include/hw/ppc/spapr_drc.h b/include/hw/ppc/spapr_drc.h
> new file mode 100644
> index 0000000..63ec687
> --- /dev/null
> +++ b/include/hw/ppc/spapr_drc.h
> @@ -0,0 +1,201 @@
> +/*
> + * QEMU SPAPR Dynamic Reconfiguration Connector Implementation
> + *
> + * Copyright IBM Corp. 2014
> + *
> + * Authors:
> + * Michael Roth <address@hidden>
> + *
> + * This work is licensed under the terms of the GNU GPL, version 2 or later.
> + * See the COPYING file in the top-level directory.
> + */
> +#if !defined(__HW_SPAPR_DRC_H__)
> +#define __HW_SPAPR_DRC_H__
> +
> +#include "qom/object.h"
> +#include "hw/qdev.h"
> +#include "libfdt.h"
> +
> +#define TYPE_SPAPR_DR_CONNECTOR "spapr-dr-connector"
> +#define SPAPR_DR_CONNECTOR_GET_CLASS(obj) \
> + OBJECT_GET_CLASS(sPAPRDRConnectorClass, obj, TYPE_SPAPR_DR_CONNECTOR)
> +#define SPAPR_DR_CONNECTOR_CLASS(klass) \
> + OBJECT_CLASS_CHECK(sPAPRDRConnectorClass, klass, \
> + TYPE_SPAPR_DR_CONNECTOR)
> +#define SPAPR_DR_CONNECTOR(obj) OBJECT_CHECK(sPAPRDRConnector, (obj), \
> + TYPE_SPAPR_DR_CONNECTOR)
> +
> +/*
> + * Various hotplug types managed by sPAPRDRConnector
> + *
> + * these are somewhat arbitrary, but to make things easier
> + * when generating DRC indexes later we've aligned the bit
> + * positions with the values used to assign DRC indexes on
> + * pSeries. we use those values as bit shifts to allow for
> + * the OR'ing of these values in various QEMU routines, but
> + * for values exposed to the guest (via DRC indexes for
> + * instance) we will use the shift amounts.
> + */
> +typedef enum {
> + SPAPR_DR_CONNECTOR_TYPE_SHIFT_CPU = 1,
> + SPAPR_DR_CONNECTOR_TYPE_SHIFT_PHB = 2,
> + SPAPR_DR_CONNECTOR_TYPE_SHIFT_VIO = 3,
> + SPAPR_DR_CONNECTOR_TYPE_SHIFT_PCI = 4,
> + SPAPR_DR_CONNECTOR_TYPE_SHIFT_LMB = 8,
> +} sPAPRDRConnectorTypeShift;
> +
> +typedef enum {
> + SPAPR_DR_CONNECTOR_TYPE_ANY = ~0,
> + SPAPR_DR_CONNECTOR_TYPE_CPU = 1 << SPAPR_DR_CONNECTOR_TYPE_SHIFT_CPU,
> + SPAPR_DR_CONNECTOR_TYPE_PHB = 1 << SPAPR_DR_CONNECTOR_TYPE_SHIFT_PHB,
> + SPAPR_DR_CONNECTOR_TYPE_VIO = 1 << SPAPR_DR_CONNECTOR_TYPE_SHIFT_VIO,
> + SPAPR_DR_CONNECTOR_TYPE_PCI = 1 << SPAPR_DR_CONNECTOR_TYPE_SHIFT_PCI,
> + SPAPR_DR_CONNECTOR_TYPE_LMB = 1 << SPAPR_DR_CONNECTOR_TYPE_SHIFT_LMB,
> +} sPAPRDRConnectorType;
> +
> +/*
> + * set via set-indicator RTAS calls
> + * as documented by PAPR+ 2.7 13.5.3.4, Table 177
> + *
> + * isolated: put device under firmware control
> + * unisolated: claim OS control of device (may or may not be in use)
> + */
> +typedef enum {
> + SPAPR_DR_ISOLATION_STATE_ISOLATED = 0,
> + SPAPR_DR_ISOLATION_STATE_UNISOLATED = 1
> +} sPAPRDRIsolationState;
> +
> +/*
> + * set via set-indicator RTAS calls
> + * as documented by PAPR+ 2.7 13.5.3.4, Table 177
> + *
> + * unusable: mark device as unavailable to OS
> + * usable: mark device as available to OS
> + * exchange: (currently unused)
> + * recover: (currently unused)
> + */
> +typedef enum {
> + SPAPR_DR_ALLOCATION_STATE_UNUSABLE = 0,
> + SPAPR_DR_ALLOCATION_STATE_USABLE = 1,
> + SPAPR_DR_ALLOCATION_STATE_EXCHANGE = 2,
> + SPAPR_DR_ALLOCATION_STATE_RECOVER = 3
> +} sPAPRDRAllocationState;
> +
> +/*
> + * LED/visual indicator state
> + *
> + * set via set-indicator RTAS calls
> + * as documented by PAPR+ 2.7 13.5.3.4, Table 177,
> + * and PAPR+ 2.7 13.5.4.1, Table 180
> + *
> + * inactive: hotpluggable entity inactive and safely removable
> + * active: hotpluggable entity in use and not safely removable
> + * identify: (currently unused)
> + * action: (currently unused)
> + */
> +typedef enum {
> + SPAPR_DR_INDICATOR_STATE_INACTIVE = 0,
> + SPAPR_DR_INDICATOR_STATE_ACTIVE = 1,
> + SPAPR_DR_INDICATOR_STATE_IDENTIFY = 2,
> + SPAPR_DR_INDICATOR_STATE_ACTION = 3,
> +} sPAPRDRIndicatorState;
> +
> +/*
> + * returned via get-sensor-state RTAS calls
> + * as documented by PAPR+ 2.7 13.5.3.3, Table 175:
> + *
> + * empty: connector slot empty (e.g. empty hotpluggable PCI slot)
> + * present: connector slot populated and device available to OS
> + * unusable: device not currently available to OS
> + * exchange: (currently unused)
> + * recover: (currently unused)
> + */
> +typedef enum {
> + SPAPR_DR_ENTITY_SENSE_EMPTY = 0,
> + SPAPR_DR_ENTITY_SENSE_PRESENT = 1,
> + SPAPR_DR_ENTITY_SENSE_UNUSABLE = 2,
> + SPAPR_DR_ENTITY_SENSE_EXCHANGE = 3,
> + SPAPR_DR_ENTITY_SENSE_RECOVER = 4,
> +} sPAPRDREntitySense;
> +
> +typedef enum {
> + SPAPR_DR_CC_RESPONSE_NEXT_SIB = 1, /* currently unused */
> + SPAPR_DR_CC_RESPONSE_NEXT_CHILD = 2,
> + SPAPR_DR_CC_RESPONSE_NEXT_PROPERTY = 3,
> + SPAPR_DR_CC_RESPONSE_PREV_PARENT = 4,
> + SPAPR_DR_CC_RESPONSE_SUCCESS = 0,
> + SPAPR_DR_CC_RESPONSE_ERROR = -1,
> + SPAPR_DR_CC_RESPONSE_CONTINUE = -2,
> +} sPAPRDRCCResponse;
> +
> +typedef struct sPAPRDRCCState {
> + void *fdt;
> + int fdt_start_offset;
> + int fdt_offset;
> + int fdt_depth;
> +} sPAPRDRCCState;
> +
> +typedef void (spapr_drc_detach_cb)(DeviceState *d, void *opaque);
> +
> +typedef struct sPAPRDRConnector {
> + /*< private >*/
> + DeviceState parent;
> +
> + sPAPRDRConnectorType type;
> + uint32_t id;
> + Object *owner;
> +
> + /* sensor/indicator states */
> + uint32_t isolation_state;
> + uint32_t allocation_state;
> + uint32_t indicator_state;
> +
> + /* configure-connector state */
> + sPAPRDRCCState ccs;
> +
> + bool awaiting_release;
> +
> + /* device pointer, via link property */
> + DeviceState *dev;
> + spapr_drc_detach_cb *detach_cb;
> + void *detach_cb_opaque;
> +} sPAPRDRConnector;
> +
> +typedef struct sPAPRDRConnectorClass {
> + /*< private >*/
> + DeviceClass parent;
> +
> + /*< public >*/
> +
> + /* accessors for guest-visible (generally via RTAS) DR state */
> + int (*set_isolation_state)(sPAPRDRConnector *drc,
> + sPAPRDRIsolationState state);
> + int (*set_indicator_state)(sPAPRDRConnector *drc,
> + sPAPRDRIndicatorState state);
> + int (*set_allocation_state)(sPAPRDRConnector *drc,
> + sPAPRDRAllocationState state);
> + uint32_t (*get_index)(sPAPRDRConnector *drc);
> + uint32_t (*get_type)(sPAPRDRConnector *drc);
> +
> + sPAPRDREntitySense (*entity_sense)(sPAPRDRConnector *drc);
> + sPAPRDRCCResponse (*configure_connector)(sPAPRDRConnector *drc,
> + char **prop_name,
> + const struct fdt_property
> **prop,
> + int *prop_len);
> +
> + /* QEMU interfaces for managing hotplug operations */
> + void (*attach)(sPAPRDRConnector *drc, DeviceState *d, void *fdt,
> + int fdt_start_offset, bool coldplug);
> + void (*detach)(sPAPRDRConnector *drc, DeviceState *d,
> + spapr_drc_detach_cb *detach_cb,
> + void *detach_cb_opaque);
> +} sPAPRDRConnectorClass;
> +
> +sPAPRDRConnector *spapr_dr_connector_new(Object *owner,
> + sPAPRDRConnectorType type,
> + uint32_t token);
> +sPAPRDRConnector *spapr_dr_connector_by_index(uint32_t index);
> +sPAPRDRConnector *spapr_dr_connector_by_id(sPAPRDRConnectorType type,
> + uint32_t id);
> +
> +#endif /* __HW_SPAPR_DRC_H__ */
--
David Gibson | I'll have my music baroque, and my code
david AT gibson.dropbear.id.au | minimalist, thank you. NOT _the_ _other_
| _way_ _around_!
http://www.ozlabs.org/~dgibson
pgpDnyysD4PAV.pgp
Description: PGP signature
- Re: [Qemu-ppc] [Qemu-devel] [PATCH v4 02/17] spapr_drc: initial implementation of sPAPRDRConnector device,
David Gibson <=