xref: /qemu/hw/ppc/spapr_drc.c (revision ebd226d221c4ef8192fc5b148e0aece07bd302d1)
1bbf5c878SMichael Roth /*
2bbf5c878SMichael Roth  * QEMU SPAPR Dynamic Reconfiguration Connector Implementation
3bbf5c878SMichael Roth  *
4bbf5c878SMichael Roth  * Copyright IBM Corp. 2014
5bbf5c878SMichael Roth  *
6bbf5c878SMichael Roth  * Authors:
7bbf5c878SMichael Roth  *  Michael Roth      <mdroth@linux.vnet.ibm.com>
8bbf5c878SMichael Roth  *
9bbf5c878SMichael Roth  * This work is licensed under the terms of the GNU GPL, version 2 or later.
10bbf5c878SMichael Roth  * See the COPYING file in the top-level directory.
11bbf5c878SMichael Roth  */
12bbf5c878SMichael Roth 
130d75590dSPeter Maydell #include "qemu/osdep.h"
14da34e65cSMarkus Armbruster #include "qapi/error.h"
1515280c36SMarkus Armbruster #include "qapi/qmp/qnull.h"
164771d756SPaolo Bonzini #include "cpu.h"
17f348b6d1SVeronia Bahaa #include "qemu/cutils.h"
18bbf5c878SMichael Roth #include "hw/ppc/spapr_drc.h"
19bbf5c878SMichael Roth #include "qom/object.h"
20d6454270SMarkus Armbruster #include "migration/vmstate.h"
21bbf5c878SMichael Roth #include "qapi/visitor.h"
22bbf5c878SMichael Roth #include "qemu/error-report.h"
230cb688d2SMichael Roth #include "hw/ppc/spapr.h" /* for RTAS return codes */
2431834723SDaniel Henrique Barboza #include "hw/pci-host/spapr.h" /* spapr_phb_remove_pci_device_cb callback */
25ee3a71e3SShivaprasad G Bhat #include "hw/ppc/spapr_nvdimm.h"
26d9c95c71SGreg Kurz #include "sysemu/device_tree.h"
2771e8a915SMarkus Armbruster #include "sysemu/reset.h"
2824ac7755SLaurent Vivier #include "trace.h"
29bbf5c878SMichael Roth 
30bbf5c878SMichael Roth #define DRC_CONTAINER_PATH "/dr-connector"
31bbf5c878SMichael Roth #define DRC_INDEX_TYPE_SHIFT 28
32627c2ef7SDavid Gibson #define DRC_INDEX_ID_MASK ((1ULL << DRC_INDEX_TYPE_SHIFT) - 1)
33bbf5c878SMichael Roth 
34ce2918cbSDavid Gibson SpaprDrcType spapr_drc_type(SpaprDrc *drc)
352d335818SDavid Gibson {
36ce2918cbSDavid Gibson     SpaprDrcClass *drck = SPAPR_DR_CONNECTOR_GET_CLASS(drc);
372d335818SDavid Gibson 
382d335818SDavid Gibson     return 1 << drck->typeshift;
392d335818SDavid Gibson }
402d335818SDavid Gibson 
41ce2918cbSDavid Gibson uint32_t spapr_drc_index(SpaprDrc *drc)
42bbf5c878SMichael Roth {
43ce2918cbSDavid Gibson     SpaprDrcClass *drck = SPAPR_DR_CONNECTOR_GET_CLASS(drc);
442d335818SDavid Gibson 
45bbf5c878SMichael Roth     /* no set format for a drc index: it only needs to be globally
46bbf5c878SMichael Roth      * unique. this is how we encode the DRC type on bare-metal
47bbf5c878SMichael Roth      * however, so might as well do that here
48bbf5c878SMichael Roth      */
492d335818SDavid Gibson     return (drck->typeshift << DRC_INDEX_TYPE_SHIFT)
502d335818SDavid Gibson         | (drc->id & DRC_INDEX_ID_MASK);
51bbf5c878SMichael Roth }
52bbf5c878SMichael Roth 
53ce2918cbSDavid Gibson static uint32_t drc_isolate_physical(SpaprDrc *drc)
54bbf5c878SMichael Roth {
559d4c0f4fSDavid Gibson     switch (drc->state) {
569d4c0f4fSDavid Gibson     case SPAPR_DRC_STATE_PHYSICAL_POWERON:
579d4c0f4fSDavid Gibson         return RTAS_OUT_SUCCESS; /* Nothing to do */
589d4c0f4fSDavid Gibson     case SPAPR_DRC_STATE_PHYSICAL_CONFIGURED:
599d4c0f4fSDavid Gibson         break; /* see below */
609d4c0f4fSDavid Gibson     case SPAPR_DRC_STATE_PHYSICAL_UNISOLATE:
619d4c0f4fSDavid Gibson         return RTAS_OUT_PARAM_ERROR; /* not allowed */
629d4c0f4fSDavid Gibson     default:
639d4c0f4fSDavid Gibson         g_assert_not_reached();
649d4c0f4fSDavid Gibson     }
659d4c0f4fSDavid Gibson 
669d4c0f4fSDavid Gibson     drc->state = SPAPR_DRC_STATE_PHYSICAL_POWERON;
679d1852ceSMichael Roth 
68f1c52354SDavid Gibson     if (drc->unplug_requested) {
690b55aa91SDavid Gibson         uint32_t drc_index = spapr_drc_index(drc);
700b55aa91SDavid Gibson         trace_spapr_drc_set_isolation_state_finalizing(drc_index);
71a8dc47fdSDavid Gibson         spapr_drc_detach(drc);
72bbf5c878SMichael Roth     }
730dfabd39SDavid Gibson 
740dfabd39SDavid Gibson     return RTAS_OUT_SUCCESS;
75bbf5c878SMichael Roth }
76bbf5c878SMichael Roth 
77ce2918cbSDavid Gibson static uint32_t drc_unisolate_physical(SpaprDrc *drc)
780dfabd39SDavid Gibson {
799d4c0f4fSDavid Gibson     switch (drc->state) {
809d4c0f4fSDavid Gibson     case SPAPR_DRC_STATE_PHYSICAL_UNISOLATE:
819d4c0f4fSDavid Gibson     case SPAPR_DRC_STATE_PHYSICAL_CONFIGURED:
829d4c0f4fSDavid Gibson         return RTAS_OUT_SUCCESS; /* Nothing to do */
839d4c0f4fSDavid Gibson     case SPAPR_DRC_STATE_PHYSICAL_POWERON:
849d4c0f4fSDavid Gibson         break; /* see below */
859d4c0f4fSDavid Gibson     default:
869d4c0f4fSDavid Gibson         g_assert_not_reached();
879d4c0f4fSDavid Gibson     }
889d4c0f4fSDavid Gibson 
890dfabd39SDavid Gibson     /* cannot unisolate a non-existent resource, and, or resources
900dfabd39SDavid Gibson      * which are in an 'UNUSABLE' allocation state. (PAPR 2.7,
910dfabd39SDavid Gibson      * 13.5.3.5)
920dfabd39SDavid Gibson      */
930dfabd39SDavid Gibson     if (!drc->dev) {
940dfabd39SDavid Gibson         return RTAS_OUT_NO_SUCH_INDICATOR;
950dfabd39SDavid Gibson     }
960dfabd39SDavid Gibson 
979d4c0f4fSDavid Gibson     drc->state = SPAPR_DRC_STATE_PHYSICAL_UNISOLATE;
984445b1d2SDavid Gibson     drc->ccs_offset = drc->fdt_start_offset;
994445b1d2SDavid Gibson     drc->ccs_depth = 0;
1000dfabd39SDavid Gibson 
1010dfabd39SDavid Gibson     return RTAS_OUT_SUCCESS;
1020dfabd39SDavid Gibson }
1030dfabd39SDavid Gibson 
104ce2918cbSDavid Gibson static uint32_t drc_isolate_logical(SpaprDrc *drc)
1050dfabd39SDavid Gibson {
1069d4c0f4fSDavid Gibson     switch (drc->state) {
1079d4c0f4fSDavid Gibson     case SPAPR_DRC_STATE_LOGICAL_AVAILABLE:
1089d4c0f4fSDavid Gibson     case SPAPR_DRC_STATE_LOGICAL_UNUSABLE:
1099d4c0f4fSDavid Gibson         return RTAS_OUT_SUCCESS; /* Nothing to do */
1109d4c0f4fSDavid Gibson     case SPAPR_DRC_STATE_LOGICAL_CONFIGURED:
1119d4c0f4fSDavid Gibson         break; /* see below */
1129d4c0f4fSDavid Gibson     case SPAPR_DRC_STATE_LOGICAL_UNISOLATE:
1139d4c0f4fSDavid Gibson         return RTAS_OUT_PARAM_ERROR; /* not allowed */
1149d4c0f4fSDavid Gibson     default:
1159d4c0f4fSDavid Gibson         g_assert_not_reached();
1169d4c0f4fSDavid Gibson     }
1179d4c0f4fSDavid Gibson 
1180dfabd39SDavid Gibson     /*
1190dfabd39SDavid Gibson      * Fail any requests to ISOLATE the LMB DRC if this LMB doesn't
1200dfabd39SDavid Gibson      * belong to a DIMM device that is marked for removal.
1210dfabd39SDavid Gibson      *
1220dfabd39SDavid Gibson      * Currently the guest userspace tool drmgr that drives the memory
1230dfabd39SDavid Gibson      * hotplug/unplug will just try to remove a set of 'removable' LMBs
1240dfabd39SDavid Gibson      * in response to a hot unplug request that is based on drc-count.
1250dfabd39SDavid Gibson      * If the LMB being removed doesn't belong to a DIMM device that is
1260dfabd39SDavid Gibson      * actually being unplugged, fail the isolation request here.
1270dfabd39SDavid Gibson      */
1280dfabd39SDavid Gibson     if (spapr_drc_type(drc) == SPAPR_DR_CONNECTOR_TYPE_LMB
129f1c52354SDavid Gibson         && !drc->unplug_requested) {
1300dfabd39SDavid Gibson         return RTAS_OUT_HW_ERROR;
1310dfabd39SDavid Gibson     }
1320dfabd39SDavid Gibson 
1339d4c0f4fSDavid Gibson     drc->state = SPAPR_DRC_STATE_LOGICAL_AVAILABLE;
1340dfabd39SDavid Gibson 
1350dfabd39SDavid Gibson     /* if we're awaiting release, but still in an unconfigured state,
1360dfabd39SDavid Gibson      * it's likely the guest is still in the process of configuring
1370dfabd39SDavid Gibson      * the device and is transitioning the devices to an ISOLATED
1380dfabd39SDavid Gibson      * state as a part of that process. so we only complete the
1390dfabd39SDavid Gibson      * removal when this transition happens for a device in a
1400dfabd39SDavid Gibson      * configured state, as suggested by the state diagram from PAPR+
1410dfabd39SDavid Gibson      * 2.7, 13.4
1420dfabd39SDavid Gibson      */
143f1c52354SDavid Gibson     if (drc->unplug_requested) {
1440dfabd39SDavid Gibson         uint32_t drc_index = spapr_drc_index(drc);
1450dfabd39SDavid Gibson         trace_spapr_drc_set_isolation_state_finalizing(drc_index);
146a8dc47fdSDavid Gibson         spapr_drc_detach(drc);
1470dfabd39SDavid Gibson     }
1480dfabd39SDavid Gibson     return RTAS_OUT_SUCCESS;
1490dfabd39SDavid Gibson }
1500dfabd39SDavid Gibson 
151ce2918cbSDavid Gibson static uint32_t drc_unisolate_logical(SpaprDrc *drc)
1520dfabd39SDavid Gibson {
1539d4c0f4fSDavid Gibson     switch (drc->state) {
1549d4c0f4fSDavid Gibson     case SPAPR_DRC_STATE_LOGICAL_UNISOLATE:
1559d4c0f4fSDavid Gibson     case SPAPR_DRC_STATE_LOGICAL_CONFIGURED:
1569d4c0f4fSDavid Gibson         return RTAS_OUT_SUCCESS; /* Nothing to do */
1579d4c0f4fSDavid Gibson     case SPAPR_DRC_STATE_LOGICAL_AVAILABLE:
1589d4c0f4fSDavid Gibson         break; /* see below */
1599d4c0f4fSDavid Gibson     case SPAPR_DRC_STATE_LOGICAL_UNUSABLE:
1609d4c0f4fSDavid Gibson         return RTAS_OUT_NO_SUCH_INDICATOR; /* not allowed */
1619d4c0f4fSDavid Gibson     default:
1629d4c0f4fSDavid Gibson         g_assert_not_reached();
1630dfabd39SDavid Gibson     }
1640dfabd39SDavid Gibson 
1659d4c0f4fSDavid Gibson     /* Move to AVAILABLE state should have ensured device was present */
1669d4c0f4fSDavid Gibson     g_assert(drc->dev);
1670dfabd39SDavid Gibson 
1689d4c0f4fSDavid Gibson     drc->state = SPAPR_DRC_STATE_LOGICAL_UNISOLATE;
1694445b1d2SDavid Gibson     drc->ccs_offset = drc->fdt_start_offset;
1704445b1d2SDavid Gibson     drc->ccs_depth = 0;
1714445b1d2SDavid Gibson 
1720cb688d2SMichael Roth     return RTAS_OUT_SUCCESS;
173bbf5c878SMichael Roth }
174bbf5c878SMichael Roth 
175ce2918cbSDavid Gibson static uint32_t drc_set_usable(SpaprDrc *drc)
176bbf5c878SMichael Roth {
1779d4c0f4fSDavid Gibson     switch (drc->state) {
1789d4c0f4fSDavid Gibson     case SPAPR_DRC_STATE_LOGICAL_AVAILABLE:
1799d4c0f4fSDavid Gibson     case SPAPR_DRC_STATE_LOGICAL_UNISOLATE:
1809d4c0f4fSDavid Gibson     case SPAPR_DRC_STATE_LOGICAL_CONFIGURED:
1819d4c0f4fSDavid Gibson         return RTAS_OUT_SUCCESS; /* Nothing to do */
1829d4c0f4fSDavid Gibson     case SPAPR_DRC_STATE_LOGICAL_UNUSABLE:
1839d4c0f4fSDavid Gibson         break; /* see below */
1849d4c0f4fSDavid Gibson     default:
1859d4c0f4fSDavid Gibson         g_assert_not_reached();
1869d4c0f4fSDavid Gibson     }
1879d4c0f4fSDavid Gibson 
1889d1852ceSMichael Roth     /* if there's no resource/device associated with the DRC, there's
1899d1852ceSMichael Roth      * no way for us to put it in an allocation state consistent with
1909d1852ceSMichael Roth      * being 'USABLE'. PAPR 2.7, 13.5.3.4 documents that this should
1919d1852ceSMichael Roth      * result in an RTAS return code of -3 / "no such indicator"
1929d1852ceSMichael Roth      */
1939d1852ceSMichael Roth     if (!drc->dev) {
1949d1852ceSMichael Roth         return RTAS_OUT_NO_SUCH_INDICATOR;
1959d1852ceSMichael Roth     }
196f1c52354SDavid Gibson     if (drc->unplug_requested) {
19782a93a1dSDavid Gibson         /* Don't allow the guest to move a device away from UNUSABLE
19882a93a1dSDavid Gibson          * state when we want to unplug it */
19961736732SDavid Gibson         return RTAS_OUT_NO_SUCH_INDICATOR;
2009d1852ceSMichael Roth     }
2019d1852ceSMichael Roth 
2029d4c0f4fSDavid Gibson     drc->state = SPAPR_DRC_STATE_LOGICAL_AVAILABLE;
20361736732SDavid Gibson 
20461736732SDavid Gibson     return RTAS_OUT_SUCCESS;
20561736732SDavid Gibson }
20661736732SDavid Gibson 
207ce2918cbSDavid Gibson static uint32_t drc_set_unusable(SpaprDrc *drc)
20861736732SDavid Gibson {
2099d4c0f4fSDavid Gibson     switch (drc->state) {
2109d4c0f4fSDavid Gibson     case SPAPR_DRC_STATE_LOGICAL_UNUSABLE:
2119d4c0f4fSDavid Gibson         return RTAS_OUT_SUCCESS; /* Nothing to do */
2129d4c0f4fSDavid Gibson     case SPAPR_DRC_STATE_LOGICAL_AVAILABLE:
2139d4c0f4fSDavid Gibson         break; /* see below */
2149d4c0f4fSDavid Gibson     case SPAPR_DRC_STATE_LOGICAL_UNISOLATE:
2159d4c0f4fSDavid Gibson     case SPAPR_DRC_STATE_LOGICAL_CONFIGURED:
2169d4c0f4fSDavid Gibson         return RTAS_OUT_NO_SUCH_INDICATOR; /* not allowed */
2179d4c0f4fSDavid Gibson     default:
2189d4c0f4fSDavid Gibson         g_assert_not_reached();
2199d4c0f4fSDavid Gibson     }
2209d4c0f4fSDavid Gibson 
2219d4c0f4fSDavid Gibson     drc->state = SPAPR_DRC_STATE_LOGICAL_UNUSABLE;
222f1c52354SDavid Gibson     if (drc->unplug_requested) {
2230b55aa91SDavid Gibson         uint32_t drc_index = spapr_drc_index(drc);
2240b55aa91SDavid Gibson         trace_spapr_drc_set_allocation_state_finalizing(drc_index);
225a8dc47fdSDavid Gibson         spapr_drc_detach(drc);
226bbf5c878SMichael Roth     }
22761736732SDavid Gibson 
2280cb688d2SMichael Roth     return RTAS_OUT_SUCCESS;
229bbf5c878SMichael Roth }
230bbf5c878SMichael Roth 
231dbd26f2fSShivaprasad G Bhat static char *spapr_drc_name(SpaprDrc *drc)
232bbf5c878SMichael Roth {
233ce2918cbSDavid Gibson     SpaprDrcClass *drck = SPAPR_DR_CONNECTOR_GET_CLASS(drc);
23479808336SDavid Gibson 
23579808336SDavid Gibson     /* human-readable name for a DRC to encode into the DT
23679808336SDavid Gibson      * description. this is mainly only used within a guest in place
23779808336SDavid Gibson      * of the unique DRC index.
23879808336SDavid Gibson      *
23979808336SDavid Gibson      * in the case of VIO/PCI devices, it corresponds to a "location
24079808336SDavid Gibson      * code" that maps a logical device/function (DRC index) to a
24179808336SDavid Gibson      * physical (or virtual in the case of VIO) location in the system
24279808336SDavid Gibson      * by chaining together the "location label" for each
24379808336SDavid Gibson      * encapsulating component.
24479808336SDavid Gibson      *
24579808336SDavid Gibson      * since this is more to do with diagnosing physical hardware
24679808336SDavid Gibson      * issues than guest compatibility, we choose location codes/DRC
24779808336SDavid Gibson      * names that adhere to the documented format, but avoid encoding
24879808336SDavid Gibson      * the entire topology information into the label/code, instead
24979808336SDavid Gibson      * just using the location codes based on the labels for the
25079808336SDavid Gibson      * endpoints (VIO/PCI adaptor connectors), which is basically just
25179808336SDavid Gibson      * "C" followed by an integer ID.
25279808336SDavid Gibson      *
25379808336SDavid Gibson      * DRC names as documented by PAPR+ v2.7, 13.5.2.4
25479808336SDavid Gibson      * location codes as documented by PAPR+ v2.7, 12.3.1.5
25579808336SDavid Gibson      */
25679808336SDavid Gibson     return g_strdup_printf("%s%d", drck->drc_name_prefix, drc->id);
257bbf5c878SMichael Roth }
258bbf5c878SMichael Roth 
259bbf5c878SMichael Roth /*
260bbf5c878SMichael Roth  * dr-entity-sense sensor value
261bbf5c878SMichael Roth  * returned via get-sensor-state RTAS calls
262bbf5c878SMichael Roth  * as expected by state diagram in PAPR+ 2.7, 13.4
263bbf5c878SMichael Roth  * based on the current allocation/indicator/power states
264bbf5c878SMichael Roth  * for the DR connector.
265bbf5c878SMichael Roth  */
266ce2918cbSDavid Gibson static SpaprDREntitySense physical_entity_sense(SpaprDrc *drc)
267bbf5c878SMichael Roth {
268f224d35bSDavid Gibson     /* this assumes all PCI devices are assigned to a 'live insertion'
269f224d35bSDavid Gibson      * power domain, where QEMU manages power state automatically as
270f224d35bSDavid Gibson      * opposed to the guest. present, non-PCI resources are unaffected
271f224d35bSDavid Gibson      * by power state.
272bbf5c878SMichael Roth      */
273f224d35bSDavid Gibson     return drc->dev ? SPAPR_DR_ENTITY_SENSE_PRESENT
274f224d35bSDavid Gibson         : SPAPR_DR_ENTITY_SENSE_EMPTY;
275bbf5c878SMichael Roth }
276bbf5c878SMichael Roth 
277ce2918cbSDavid Gibson static SpaprDREntitySense logical_entity_sense(SpaprDrc *drc)
278f224d35bSDavid Gibson {
2799d4c0f4fSDavid Gibson     switch (drc->state) {
2809d4c0f4fSDavid Gibson     case SPAPR_DRC_STATE_LOGICAL_UNUSABLE:
281f224d35bSDavid Gibson         return SPAPR_DR_ENTITY_SENSE_UNUSABLE;
2829d4c0f4fSDavid Gibson     case SPAPR_DRC_STATE_LOGICAL_AVAILABLE:
2839d4c0f4fSDavid Gibson     case SPAPR_DRC_STATE_LOGICAL_UNISOLATE:
2849d4c0f4fSDavid Gibson     case SPAPR_DRC_STATE_LOGICAL_CONFIGURED:
2859d4c0f4fSDavid Gibson         g_assert(drc->dev);
2869d4c0f4fSDavid Gibson         return SPAPR_DR_ENTITY_SENSE_PRESENT;
2879d4c0f4fSDavid Gibson     default:
2889d4c0f4fSDavid Gibson         g_assert_not_reached();
289f224d35bSDavid Gibson     }
290bbf5c878SMichael Roth }
291bbf5c878SMichael Roth 
292d7bce999SEric Blake static void prop_get_index(Object *obj, Visitor *v, const char *name,
293d7bce999SEric Blake                            void *opaque, Error **errp)
294bbf5c878SMichael Roth {
295ce2918cbSDavid Gibson     SpaprDrc *drc = SPAPR_DR_CONNECTOR(obj);
2960b55aa91SDavid Gibson     uint32_t value = spapr_drc_index(drc);
29751e72bc1SEric Blake     visit_type_uint32(v, name, &value, errp);
298bbf5c878SMichael Roth }
299bbf5c878SMichael Roth 
300d7bce999SEric Blake static void prop_get_fdt(Object *obj, Visitor *v, const char *name,
301d7bce999SEric Blake                          void *opaque, Error **errp)
302bbf5c878SMichael Roth {
303ce2918cbSDavid Gibson     SpaprDrc *drc = SPAPR_DR_CONNECTOR(obj);
304d2f95f4dSMarkus Armbruster     QNull *null = NULL;
305bbf5c878SMichael Roth     int fdt_offset_next, fdt_offset, fdt_depth;
306bbf5c878SMichael Roth     void *fdt;
307bbf5c878SMichael Roth 
308bbf5c878SMichael Roth     if (!drc->fdt) {
309d2f95f4dSMarkus Armbruster         visit_type_null(v, NULL, &null, errp);
310cb3e7f08SMarc-André Lureau         qobject_unref(null);
311bbf5c878SMichael Roth         return;
312bbf5c878SMichael Roth     }
313bbf5c878SMichael Roth 
314bbf5c878SMichael Roth     fdt = drc->fdt;
315bbf5c878SMichael Roth     fdt_offset = drc->fdt_start_offset;
316bbf5c878SMichael Roth     fdt_depth = 0;
317bbf5c878SMichael Roth 
318bbf5c878SMichael Roth     do {
319bbf5c878SMichael Roth         const char *name = NULL;
320bbf5c878SMichael Roth         const struct fdt_property *prop = NULL;
321bbf5c878SMichael Roth         int prop_len = 0, name_len = 0;
322bbf5c878SMichael Roth         uint32_t tag;
323*ebd226d2SGreg Kurz         bool ok;
324bbf5c878SMichael Roth 
325bbf5c878SMichael Roth         tag = fdt_next_tag(fdt, fdt_offset, &fdt_offset_next);
326bbf5c878SMichael Roth         switch (tag) {
327bbf5c878SMichael Roth         case FDT_BEGIN_NODE:
328bbf5c878SMichael Roth             fdt_depth++;
329bbf5c878SMichael Roth             name = fdt_get_name(fdt, fdt_offset, &name_len);
330668f62ecSMarkus Armbruster             if (!visit_start_struct(v, name, NULL, 0, errp)) {
331c75304a1SMarkus Armbruster                 return;
332c75304a1SMarkus Armbruster             }
333bbf5c878SMichael Roth             break;
334bbf5c878SMichael Roth         case FDT_END_NODE:
335bbf5c878SMichael Roth             /* shouldn't ever see an FDT_END_NODE before FDT_BEGIN_NODE */
336bbf5c878SMichael Roth             g_assert(fdt_depth > 0);
337*ebd226d2SGreg Kurz             ok = visit_check_struct(v, errp);
3381158bb2aSEric Blake             visit_end_struct(v, NULL);
339*ebd226d2SGreg Kurz             if (!ok) {
340c75304a1SMarkus Armbruster                 return;
341c75304a1SMarkus Armbruster             }
342bbf5c878SMichael Roth             fdt_depth--;
343bbf5c878SMichael Roth             break;
344bbf5c878SMichael Roth         case FDT_PROP: {
345bbf5c878SMichael Roth             int i;
346bbf5c878SMichael Roth             prop = fdt_get_property_by_offset(fdt, fdt_offset, &prop_len);
347bbf5c878SMichael Roth             name = fdt_string(fdt, fdt32_to_cpu(prop->nameoff));
348668f62ecSMarkus Armbruster             if (!visit_start_list(v, name, NULL, 0, errp)) {
349c75304a1SMarkus Armbruster                 return;
350bbf5c878SMichael Roth             }
351c75304a1SMarkus Armbruster             for (i = 0; i < prop_len; i++) {
35262a35aaaSMarkus Armbruster                 if (!visit_type_uint8(v, NULL, (uint8_t *)&prop->data[i],
353668f62ecSMarkus Armbruster                                       errp)) {
354c75304a1SMarkus Armbruster                     return;
355c75304a1SMarkus Armbruster                 }
356c75304a1SMarkus Armbruster             }
357*ebd226d2SGreg Kurz             ok = visit_check_list(v, errp);
3581158bb2aSEric Blake             visit_end_list(v, NULL);
359*ebd226d2SGreg Kurz             if (!ok) {
360a4a1c70dSMarkus Armbruster                 return;
361a4a1c70dSMarkus Armbruster             }
362bbf5c878SMichael Roth             break;
363bbf5c878SMichael Roth         }
364bbf5c878SMichael Roth         default:
365e20c6314SPhilippe Mathieu-Daudé             error_report("device FDT in unexpected state: %d", tag);
366e20c6314SPhilippe Mathieu-Daudé             abort();
367bbf5c878SMichael Roth         }
368bbf5c878SMichael Roth         fdt_offset = fdt_offset_next;
369bbf5c878SMichael Roth     } while (fdt_depth != 0);
370bbf5c878SMichael Roth }
371bbf5c878SMichael Roth 
37217548fe6SGreg Kurz bool spapr_drc_attach(SpaprDrc *drc, DeviceState *d, Error **errp)
373bbf5c878SMichael Roth {
3740b55aa91SDavid Gibson     trace_spapr_drc_attach(spapr_drc_index(drc));
375bbf5c878SMichael Roth 
3769d4c0f4fSDavid Gibson     if (drc->dev) {
377bbf5c878SMichael Roth         error_setg(errp, "an attached device is still awaiting release");
37817548fe6SGreg Kurz         return false;
379bbf5c878SMichael Roth     }
3809d4c0f4fSDavid Gibson     g_assert((drc->state == SPAPR_DRC_STATE_LOGICAL_UNUSABLE)
3819d4c0f4fSDavid Gibson              || (drc->state == SPAPR_DRC_STATE_PHYSICAL_POWERON));
382bbf5c878SMichael Roth 
383bbf5c878SMichael Roth     drc->dev = d;
384d9c95c71SGreg Kurz 
385bbf5c878SMichael Roth     object_property_add_link(OBJECT(drc), "device",
386bbf5c878SMichael Roth                              object_get_typename(OBJECT(drc->dev)),
387bbf5c878SMichael Roth                              (Object **)(&drc->dev),
388d2623129SMarkus Armbruster                              NULL, 0);
38917548fe6SGreg Kurz     return true;
390bbf5c878SMichael Roth }
391bbf5c878SMichael Roth 
392ce2918cbSDavid Gibson static void spapr_drc_release(SpaprDrc *drc)
393bbf5c878SMichael Roth {
394ce2918cbSDavid Gibson     SpaprDrcClass *drck = SPAPR_DR_CONNECTOR_GET_CLASS(drc);
3956b762f29SDavid Gibson 
3966b762f29SDavid Gibson     drck->release(drc->dev);
397bbf5c878SMichael Roth 
398f1c52354SDavid Gibson     drc->unplug_requested = false;
399bbf5c878SMichael Roth     g_free(drc->fdt);
400bbf5c878SMichael Roth     drc->fdt = NULL;
401bbf5c878SMichael Roth     drc->fdt_start_offset = 0;
402df4fe0b2SMarkus Armbruster     object_property_del(OBJECT(drc), "device");
403bbf5c878SMichael Roth     drc->dev = NULL;
404bbf5c878SMichael Roth }
405bbf5c878SMichael Roth 
406ce2918cbSDavid Gibson void spapr_drc_detach(SpaprDrc *drc)
4079c914e53SDavid Gibson {
408ce2918cbSDavid Gibson     SpaprDrcClass *drck = SPAPR_DR_CONNECTOR_GET_CLASS(drc);
4099d4c0f4fSDavid Gibson 
4109c914e53SDavid Gibson     trace_spapr_drc_detach(spapr_drc_index(drc));
4119c914e53SDavid Gibson 
4129d4c0f4fSDavid Gibson     g_assert(drc->dev);
4139d4c0f4fSDavid Gibson 
414f1c52354SDavid Gibson     drc->unplug_requested = true;
415a8dc47fdSDavid Gibson 
4169d4c0f4fSDavid Gibson     if (drc->state != drck->empty_state) {
4179d4c0f4fSDavid Gibson         trace_spapr_drc_awaiting_quiesce(spapr_drc_index(drc));
4189c914e53SDavid Gibson         return;
4199c914e53SDavid Gibson     }
4209c914e53SDavid Gibson 
4219c914e53SDavid Gibson     spapr_drc_release(drc);
4229c914e53SDavid Gibson }
4239c914e53SDavid Gibson 
424ce2918cbSDavid Gibson void spapr_drc_reset(SpaprDrc *drc)
425bbf5c878SMichael Roth {
426ce2918cbSDavid Gibson     SpaprDrcClass *drck = SPAPR_DR_CONNECTOR_GET_CLASS(drc);
4279d4c0f4fSDavid Gibson 
4280b55aa91SDavid Gibson     trace_spapr_drc_reset(spapr_drc_index(drc));
429b8fdd530SDavid Gibson 
430bbf5c878SMichael Roth     /* immediately upon reset we can safely assume DRCs whose devices
4314f9242fcSDavid Gibson      * are pending removal can be safely removed.
432bbf5c878SMichael Roth      */
433f1c52354SDavid Gibson     if (drc->unplug_requested) {
4344f9242fcSDavid Gibson         spapr_drc_release(drc);
435bbf5c878SMichael Roth     }
436bbf5c878SMichael Roth 
4374f9242fcSDavid Gibson     if (drc->dev) {
4389d4c0f4fSDavid Gibson         /* A device present at reset is ready to go, same as coldplugged */
4399d4c0f4fSDavid Gibson         drc->state = drck->ready_state;
440188bfe1bSBharata B Rao         /*
441188bfe1bSBharata B Rao          * Ensure that we are able to send the FDT fragment again
442188bfe1bSBharata B Rao          * via configure-connector call if the guest requests.
443188bfe1bSBharata B Rao          */
444188bfe1bSBharata B Rao         drc->ccs_offset = drc->fdt_start_offset;
445188bfe1bSBharata B Rao         drc->ccs_depth = 0;
4464f9242fcSDavid Gibson     } else {
4479d4c0f4fSDavid Gibson         drc->state = drck->empty_state;
4484445b1d2SDavid Gibson         drc->ccs_offset = -1;
4494445b1d2SDavid Gibson         drc->ccs_depth = -1;
450bbf5c878SMichael Roth     }
451188bfe1bSBharata B Rao }
452bbf5c878SMichael Roth 
453ab858434SGreg Kurz static bool spapr_drc_unplug_requested_needed(void *opaque)
454ab858434SGreg Kurz {
455ab858434SGreg Kurz     return spapr_drc_unplug_requested(opaque);
456ab858434SGreg Kurz }
457ab858434SGreg Kurz 
458ab858434SGreg Kurz static const VMStateDescription vmstate_spapr_drc_unplug_requested = {
459ab858434SGreg Kurz     .name = "spapr_drc/unplug_requested",
460ab858434SGreg Kurz     .version_id = 1,
461ab858434SGreg Kurz     .minimum_version_id = 1,
462ab858434SGreg Kurz     .needed = spapr_drc_unplug_requested_needed,
463ab858434SGreg Kurz     .fields  = (VMStateField []) {
464ab858434SGreg Kurz         VMSTATE_BOOL(unplug_requested, SpaprDrc),
465ab858434SGreg Kurz         VMSTATE_END_OF_LIST()
466ab858434SGreg Kurz     }
467ab858434SGreg Kurz };
468ab858434SGreg Kurz 
4694b63db12SGreg Kurz bool spapr_drc_transient(SpaprDrc *drc)
470a50919ddSDaniel Henrique Barboza {
471ce2918cbSDavid Gibson     SpaprDrcClass *drck = SPAPR_DR_CONNECTOR_GET_CLASS(drc);
472a50919ddSDaniel Henrique Barboza 
4734b63db12SGreg Kurz     /*
4744b63db12SGreg Kurz      * If no dev is plugged in there is no need to migrate the DRC state
4754b63db12SGreg Kurz      * nor to reset the DRC at CAS.
4764b63db12SGreg Kurz      */
477c618e300SDaniel Henrique Barboza     if (!drc->dev) {
478a50919ddSDaniel Henrique Barboza         return false;
479a50919ddSDaniel Henrique Barboza     }
480a50919ddSDaniel Henrique Barboza 
481a50919ddSDaniel Henrique Barboza     /*
4824b63db12SGreg Kurz      * We need to reset the DRC at CAS or to migrate the DRC state if it's
4834b63db12SGreg Kurz      * not equal to the expected long-term state, which is the same as the
484ab858434SGreg Kurz      * coldplugged initial state, or if an unplug request is pending.
4854b63db12SGreg Kurz      */
486ab858434SGreg Kurz     return drc->state != drck->ready_state ||
487ab858434SGreg Kurz         spapr_drc_unplug_requested(drc);
488a50919ddSDaniel Henrique Barboza }
489a50919ddSDaniel Henrique Barboza 
4904b63db12SGreg Kurz static bool spapr_drc_needed(void *opaque)
4914b63db12SGreg Kurz {
4924b63db12SGreg Kurz     return spapr_drc_transient(opaque);
4934b63db12SGreg Kurz }
4944b63db12SGreg Kurz 
495a50919ddSDaniel Henrique Barboza static const VMStateDescription vmstate_spapr_drc = {
496a50919ddSDaniel Henrique Barboza     .name = "spapr_drc",
497a50919ddSDaniel Henrique Barboza     .version_id = 1,
498a50919ddSDaniel Henrique Barboza     .minimum_version_id = 1,
499a50919ddSDaniel Henrique Barboza     .needed = spapr_drc_needed,
500a50919ddSDaniel Henrique Barboza     .fields  = (VMStateField []) {
501ce2918cbSDavid Gibson         VMSTATE_UINT32(state, SpaprDrc),
502a50919ddSDaniel Henrique Barboza         VMSTATE_END_OF_LIST()
503ab858434SGreg Kurz     },
504ab858434SGreg Kurz     .subsections = (const VMStateDescription * []) {
505ab858434SGreg Kurz         &vmstate_spapr_drc_unplug_requested,
506ab858434SGreg Kurz         NULL
507a50919ddSDaniel Henrique Barboza     }
508a50919ddSDaniel Henrique Barboza };
509a50919ddSDaniel Henrique Barboza 
510bbf5c878SMichael Roth static void realize(DeviceState *d, Error **errp)
511bbf5c878SMichael Roth {
512ce2918cbSDavid Gibson     SpaprDrc *drc = SPAPR_DR_CONNECTOR(d);
513bbf5c878SMichael Roth     Object *root_container;
514f5babeacSGreg Kurz     gchar *link_name;
5157a309cc9SMarkus Armbruster     const char *child_name;
516bbf5c878SMichael Roth 
5170b55aa91SDavid Gibson     trace_spapr_drc_realize(spapr_drc_index(drc));
518bbf5c878SMichael Roth     /* NOTE: we do this as part of realize/unrealize due to the fact
519bbf5c878SMichael Roth      * that the guest will communicate with the DRC via RTAS calls
520bbf5c878SMichael Roth      * referencing the global DRC index. By unlinking the DRC
521bbf5c878SMichael Roth      * from DRC_CONTAINER_PATH/<drc_index> we effectively make it
522bbf5c878SMichael Roth      * inaccessible by the guest, since lookups rely on this path
523bbf5c878SMichael Roth      * existing in the composition tree
524bbf5c878SMichael Roth      */
525bbf5c878SMichael Roth     root_container = container_get(object_get_root(), DRC_CONTAINER_PATH);
526f5babeacSGreg Kurz     link_name = g_strdup_printf("%x", spapr_drc_index(drc));
527bbf5c878SMichael Roth     child_name = object_get_canonical_path_component(OBJECT(drc));
5280b55aa91SDavid Gibson     trace_spapr_drc_realize_child(spapr_drc_index(drc), child_name);
529bbf5c878SMichael Roth     object_property_add_alias(root_container, link_name,
530d2623129SMarkus Armbruster                               drc->owner, child_name);
531f5babeacSGreg Kurz     g_free(link_name);
5323cad405bSMarc-André Lureau     vmstate_register(VMSTATE_IF(drc), spapr_drc_index(drc), &vmstate_spapr_drc,
533a50919ddSDaniel Henrique Barboza                      drc);
5340b55aa91SDavid Gibson     trace_spapr_drc_realize_complete(spapr_drc_index(drc));
535bbf5c878SMichael Roth }
536bbf5c878SMichael Roth 
537b69c3c21SMarkus Armbruster static void unrealize(DeviceState *d)
538bbf5c878SMichael Roth {
539ce2918cbSDavid Gibson     SpaprDrc *drc = SPAPR_DR_CONNECTOR(d);
540bbf5c878SMichael Roth     Object *root_container;
541f5babeacSGreg Kurz     gchar *name;
542bbf5c878SMichael Roth 
5430b55aa91SDavid Gibson     trace_spapr_drc_unrealize(spapr_drc_index(drc));
5443cad405bSMarc-André Lureau     vmstate_unregister(VMSTATE_IF(drc), &vmstate_spapr_drc, drc);
545bbf5c878SMichael Roth     root_container = container_get(object_get_root(), DRC_CONTAINER_PATH);
546f5babeacSGreg Kurz     name = g_strdup_printf("%x", spapr_drc_index(drc));
547df4fe0b2SMarkus Armbruster     object_property_del(root_container, name);
548f5babeacSGreg Kurz     g_free(name);
549bbf5c878SMichael Roth }
550bbf5c878SMichael Roth 
551ce2918cbSDavid Gibson SpaprDrc *spapr_dr_connector_new(Object *owner, const char *type,
552bbf5c878SMichael Roth                                          uint32_t id)
553bbf5c878SMichael Roth {
554ce2918cbSDavid Gibson     SpaprDrc *drc = SPAPR_DR_CONNECTOR(object_new(type));
55594649d42SDavid Gibson     char *prop_name;
556bbf5c878SMichael Roth 
557bbf5c878SMichael Roth     drc->id = id;
558bbf5c878SMichael Roth     drc->owner = owner;
5590b55aa91SDavid Gibson     prop_name = g_strdup_printf("dr-connector[%"PRIu32"]",
5600b55aa91SDavid Gibson                                 spapr_drc_index(drc));
561d2623129SMarkus Armbruster     object_property_add_child(owner, prop_name, OBJECT(drc));
562f3f41030SMichael Roth     object_unref(OBJECT(drc));
563ce189ab2SMarkus Armbruster     qdev_realize(DEVICE(drc), NULL, NULL);
56494649d42SDavid Gibson     g_free(prop_name);
565bbf5c878SMichael Roth 
566bbf5c878SMichael Roth     return drc;
567bbf5c878SMichael Roth }
568bbf5c878SMichael Roth 
569bbf5c878SMichael Roth static void spapr_dr_connector_instance_init(Object *obj)
570bbf5c878SMichael Roth {
571ce2918cbSDavid Gibson     SpaprDrc *drc = SPAPR_DR_CONNECTOR(obj);
572ce2918cbSDavid Gibson     SpaprDrcClass *drck = SPAPR_DR_CONNECTOR_GET_CLASS(drc);
573bbf5c878SMichael Roth 
574d2623129SMarkus Armbruster     object_property_add_uint32_ptr(obj, "id", &drc->id, OBJ_PROP_FLAG_READ);
575bbf5c878SMichael Roth     object_property_add(obj, "index", "uint32", prop_get_index,
576d2623129SMarkus Armbruster                         NULL, NULL, NULL);
577bbf5c878SMichael Roth     object_property_add(obj, "fdt", "struct", prop_get_fdt,
578d2623129SMarkus Armbruster                         NULL, NULL, NULL);
5799d4c0f4fSDavid Gibson     drc->state = drck->empty_state;
580bbf5c878SMichael Roth }
581bbf5c878SMichael Roth 
582bbf5c878SMichael Roth static void spapr_dr_connector_class_init(ObjectClass *k, void *data)
583bbf5c878SMichael Roth {
584bbf5c878SMichael Roth     DeviceClass *dk = DEVICE_CLASS(k);
585bbf5c878SMichael Roth 
586bbf5c878SMichael Roth     dk->realize = realize;
587bbf5c878SMichael Roth     dk->unrealize = unrealize;
588c401ae8cSMarkus Armbruster     /*
589c401ae8cSMarkus Armbruster      * Reason: it crashes FIXME find and document the real reason
590c401ae8cSMarkus Armbruster      */
591e90f2a8cSEduardo Habkost     dk->user_creatable = false;
592bbf5c878SMichael Roth }
593bbf5c878SMichael Roth 
59467fea71bSDavid Gibson static bool drc_physical_needed(void *opaque)
59567fea71bSDavid Gibson {
596ce2918cbSDavid Gibson     SpaprDrcPhysical *drcp = (SpaprDrcPhysical *)opaque;
597ce2918cbSDavid Gibson     SpaprDrc *drc = SPAPR_DR_CONNECTOR(drcp);
59867fea71bSDavid Gibson 
59967fea71bSDavid Gibson     if ((drc->dev && (drcp->dr_indicator == SPAPR_DR_INDICATOR_ACTIVE))
60067fea71bSDavid Gibson         || (!drc->dev && (drcp->dr_indicator == SPAPR_DR_INDICATOR_INACTIVE))) {
60167fea71bSDavid Gibson         return false;
60267fea71bSDavid Gibson     }
60367fea71bSDavid Gibson     return true;
60467fea71bSDavid Gibson }
60567fea71bSDavid Gibson 
60667fea71bSDavid Gibson static const VMStateDescription vmstate_spapr_drc_physical = {
60767fea71bSDavid Gibson     .name = "spapr_drc/physical",
60867fea71bSDavid Gibson     .version_id = 1,
60967fea71bSDavid Gibson     .minimum_version_id = 1,
61067fea71bSDavid Gibson     .needed = drc_physical_needed,
61167fea71bSDavid Gibson     .fields  = (VMStateField []) {
612ce2918cbSDavid Gibson         VMSTATE_UINT32(dr_indicator, SpaprDrcPhysical),
61367fea71bSDavid Gibson         VMSTATE_END_OF_LIST()
61467fea71bSDavid Gibson     }
61567fea71bSDavid Gibson };
61667fea71bSDavid Gibson 
61767fea71bSDavid Gibson static void drc_physical_reset(void *opaque)
61867fea71bSDavid Gibson {
619ce2918cbSDavid Gibson     SpaprDrc *drc = SPAPR_DR_CONNECTOR(opaque);
620ce2918cbSDavid Gibson     SpaprDrcPhysical *drcp = SPAPR_DRC_PHYSICAL(drc);
62167fea71bSDavid Gibson 
62267fea71bSDavid Gibson     if (drc->dev) {
62367fea71bSDavid Gibson         drcp->dr_indicator = SPAPR_DR_INDICATOR_ACTIVE;
62467fea71bSDavid Gibson     } else {
62567fea71bSDavid Gibson         drcp->dr_indicator = SPAPR_DR_INDICATOR_INACTIVE;
62667fea71bSDavid Gibson     }
62767fea71bSDavid Gibson }
62867fea71bSDavid Gibson 
62967fea71bSDavid Gibson static void realize_physical(DeviceState *d, Error **errp)
63067fea71bSDavid Gibson {
631ce2918cbSDavid Gibson     SpaprDrcPhysical *drcp = SPAPR_DRC_PHYSICAL(d);
63267fea71bSDavid Gibson     Error *local_err = NULL;
63367fea71bSDavid Gibson 
63467fea71bSDavid Gibson     realize(d, &local_err);
63567fea71bSDavid Gibson     if (local_err) {
63667fea71bSDavid Gibson         error_propagate(errp, local_err);
63767fea71bSDavid Gibson         return;
63867fea71bSDavid Gibson     }
63967fea71bSDavid Gibson 
6403cad405bSMarc-André Lureau     vmstate_register(VMSTATE_IF(drcp),
6413cad405bSMarc-André Lureau                      spapr_drc_index(SPAPR_DR_CONNECTOR(drcp)),
64267fea71bSDavid Gibson                      &vmstate_spapr_drc_physical, drcp);
64367fea71bSDavid Gibson     qemu_register_reset(drc_physical_reset, drcp);
64467fea71bSDavid Gibson }
64567fea71bSDavid Gibson 
646b69c3c21SMarkus Armbruster static void unrealize_physical(DeviceState *d)
647379ae096SGreg Kurz {
648ce2918cbSDavid Gibson     SpaprDrcPhysical *drcp = SPAPR_DRC_PHYSICAL(d);
649379ae096SGreg Kurz 
650b69c3c21SMarkus Armbruster     unrealize(d);
6513cad405bSMarc-André Lureau     vmstate_unregister(VMSTATE_IF(drcp), &vmstate_spapr_drc_physical, drcp);
652379ae096SGreg Kurz     qemu_unregister_reset(drc_physical_reset, drcp);
653379ae096SGreg Kurz }
654379ae096SGreg Kurz 
655f224d35bSDavid Gibson static void spapr_drc_physical_class_init(ObjectClass *k, void *data)
656f224d35bSDavid Gibson {
65767fea71bSDavid Gibson     DeviceClass *dk = DEVICE_CLASS(k);
658ce2918cbSDavid Gibson     SpaprDrcClass *drck = SPAPR_DR_CONNECTOR_CLASS(k);
659f224d35bSDavid Gibson 
66067fea71bSDavid Gibson     dk->realize = realize_physical;
661379ae096SGreg Kurz     dk->unrealize = unrealize_physical;
662f224d35bSDavid Gibson     drck->dr_entity_sense = physical_entity_sense;
6630dfabd39SDavid Gibson     drck->isolate = drc_isolate_physical;
6640dfabd39SDavid Gibson     drck->unisolate = drc_unisolate_physical;
6659d4c0f4fSDavid Gibson     drck->ready_state = SPAPR_DRC_STATE_PHYSICAL_CONFIGURED;
6669d4c0f4fSDavid Gibson     drck->empty_state = SPAPR_DRC_STATE_PHYSICAL_POWERON;
667f224d35bSDavid Gibson }
668f224d35bSDavid Gibson 
669f224d35bSDavid Gibson static void spapr_drc_logical_class_init(ObjectClass *k, void *data)
670f224d35bSDavid Gibson {
671ce2918cbSDavid Gibson     SpaprDrcClass *drck = SPAPR_DR_CONNECTOR_CLASS(k);
672f224d35bSDavid Gibson 
673f224d35bSDavid Gibson     drck->dr_entity_sense = logical_entity_sense;
6740dfabd39SDavid Gibson     drck->isolate = drc_isolate_logical;
6750dfabd39SDavid Gibson     drck->unisolate = drc_unisolate_logical;
6769d4c0f4fSDavid Gibson     drck->ready_state = SPAPR_DRC_STATE_LOGICAL_CONFIGURED;
6779d4c0f4fSDavid Gibson     drck->empty_state = SPAPR_DRC_STATE_LOGICAL_UNUSABLE;
678f224d35bSDavid Gibson }
679f224d35bSDavid Gibson 
6802d335818SDavid Gibson static void spapr_drc_cpu_class_init(ObjectClass *k, void *data)
6812d335818SDavid Gibson {
682ce2918cbSDavid Gibson     SpaprDrcClass *drck = SPAPR_DR_CONNECTOR_CLASS(k);
6832d335818SDavid Gibson 
6842d335818SDavid Gibson     drck->typeshift = SPAPR_DR_CONNECTOR_TYPE_SHIFT_CPU;
6851693ea16SDavid Gibson     drck->typename = "CPU";
68679808336SDavid Gibson     drck->drc_name_prefix = "CPU ";
6876b762f29SDavid Gibson     drck->release = spapr_core_release;
688345b12b9SGreg Kurz     drck->dt_populate = spapr_core_dt_populate;
6892d335818SDavid Gibson }
6902d335818SDavid Gibson 
6912d335818SDavid Gibson static void spapr_drc_pci_class_init(ObjectClass *k, void *data)
6922d335818SDavid Gibson {
693ce2918cbSDavid Gibson     SpaprDrcClass *drck = SPAPR_DR_CONNECTOR_CLASS(k);
6942d335818SDavid Gibson 
6952d335818SDavid Gibson     drck->typeshift = SPAPR_DR_CONNECTOR_TYPE_SHIFT_PCI;
6961693ea16SDavid Gibson     drck->typename = "28";
69779808336SDavid Gibson     drck->drc_name_prefix = "C";
6986b762f29SDavid Gibson     drck->release = spapr_phb_remove_pci_device_cb;
69946fd0299SGreg Kurz     drck->dt_populate = spapr_pci_dt_populate;
7002d335818SDavid Gibson }
7012d335818SDavid Gibson 
7022d335818SDavid Gibson static void spapr_drc_lmb_class_init(ObjectClass *k, void *data)
7032d335818SDavid Gibson {
704ce2918cbSDavid Gibson     SpaprDrcClass *drck = SPAPR_DR_CONNECTOR_CLASS(k);
7052d335818SDavid Gibson 
7062d335818SDavid Gibson     drck->typeshift = SPAPR_DR_CONNECTOR_TYPE_SHIFT_LMB;
7071693ea16SDavid Gibson     drck->typename = "MEM";
70879808336SDavid Gibson     drck->drc_name_prefix = "LMB ";
7096b762f29SDavid Gibson     drck->release = spapr_lmb_release;
71062d38c9bSGreg Kurz     drck->dt_populate = spapr_lmb_dt_populate;
7112d335818SDavid Gibson }
7122d335818SDavid Gibson 
713962b6c36SMichael Roth static void spapr_drc_phb_class_init(ObjectClass *k, void *data)
714962b6c36SMichael Roth {
715ce2918cbSDavid Gibson     SpaprDrcClass *drck = SPAPR_DR_CONNECTOR_CLASS(k);
716962b6c36SMichael Roth 
717962b6c36SMichael Roth     drck->typeshift = SPAPR_DR_CONNECTOR_TYPE_SHIFT_PHB;
718962b6c36SMichael Roth     drck->typename = "PHB";
719962b6c36SMichael Roth     drck->drc_name_prefix = "PHB ";
720bb2bdd81SGreg Kurz     drck->release = spapr_phb_release;
721bb2bdd81SGreg Kurz     drck->dt_populate = spapr_phb_dt_populate;
722962b6c36SMichael Roth }
723962b6c36SMichael Roth 
724ee3a71e3SShivaprasad G Bhat static void spapr_drc_pmem_class_init(ObjectClass *k, void *data)
725ee3a71e3SShivaprasad G Bhat {
726ee3a71e3SShivaprasad G Bhat     SpaprDrcClass *drck = SPAPR_DR_CONNECTOR_CLASS(k);
727ee3a71e3SShivaprasad G Bhat 
728ee3a71e3SShivaprasad G Bhat     drck->typeshift = SPAPR_DR_CONNECTOR_TYPE_SHIFT_PMEM;
729ee3a71e3SShivaprasad G Bhat     drck->typename = "PMEM";
730ee3a71e3SShivaprasad G Bhat     drck->drc_name_prefix = "PMEM ";
731ee3a71e3SShivaprasad G Bhat     drck->release = NULL;
732ee3a71e3SShivaprasad G Bhat     drck->dt_populate = spapr_pmem_dt_populate;
733ee3a71e3SShivaprasad G Bhat }
734ee3a71e3SShivaprasad G Bhat 
735bbf5c878SMichael Roth static const TypeInfo spapr_dr_connector_info = {
736bbf5c878SMichael Roth     .name          = TYPE_SPAPR_DR_CONNECTOR,
737bbf5c878SMichael Roth     .parent        = TYPE_DEVICE,
738ce2918cbSDavid Gibson     .instance_size = sizeof(SpaprDrc),
739bbf5c878SMichael Roth     .instance_init = spapr_dr_connector_instance_init,
740ce2918cbSDavid Gibson     .class_size    = sizeof(SpaprDrcClass),
741bbf5c878SMichael Roth     .class_init    = spapr_dr_connector_class_init,
7422d335818SDavid Gibson     .abstract      = true,
7432d335818SDavid Gibson };
7442d335818SDavid Gibson 
7452d335818SDavid Gibson static const TypeInfo spapr_drc_physical_info = {
7462d335818SDavid Gibson     .name          = TYPE_SPAPR_DRC_PHYSICAL,
7472d335818SDavid Gibson     .parent        = TYPE_SPAPR_DR_CONNECTOR,
748ce2918cbSDavid Gibson     .instance_size = sizeof(SpaprDrcPhysical),
749f224d35bSDavid Gibson     .class_init    = spapr_drc_physical_class_init,
7502d335818SDavid Gibson     .abstract      = true,
7512d335818SDavid Gibson };
7522d335818SDavid Gibson 
7532d335818SDavid Gibson static const TypeInfo spapr_drc_logical_info = {
7542d335818SDavid Gibson     .name          = TYPE_SPAPR_DRC_LOGICAL,
7552d335818SDavid Gibson     .parent        = TYPE_SPAPR_DR_CONNECTOR,
756f224d35bSDavid Gibson     .class_init    = spapr_drc_logical_class_init,
7572d335818SDavid Gibson     .abstract      = true,
7582d335818SDavid Gibson };
7592d335818SDavid Gibson 
7602d335818SDavid Gibson static const TypeInfo spapr_drc_cpu_info = {
7612d335818SDavid Gibson     .name          = TYPE_SPAPR_DRC_CPU,
7622d335818SDavid Gibson     .parent        = TYPE_SPAPR_DRC_LOGICAL,
7632d335818SDavid Gibson     .class_init    = spapr_drc_cpu_class_init,
7642d335818SDavid Gibson };
7652d335818SDavid Gibson 
7662d335818SDavid Gibson static const TypeInfo spapr_drc_pci_info = {
7672d335818SDavid Gibson     .name          = TYPE_SPAPR_DRC_PCI,
7682d335818SDavid Gibson     .parent        = TYPE_SPAPR_DRC_PHYSICAL,
7692d335818SDavid Gibson     .class_init    = spapr_drc_pci_class_init,
7702d335818SDavid Gibson };
7712d335818SDavid Gibson 
7722d335818SDavid Gibson static const TypeInfo spapr_drc_lmb_info = {
7732d335818SDavid Gibson     .name          = TYPE_SPAPR_DRC_LMB,
7742d335818SDavid Gibson     .parent        = TYPE_SPAPR_DRC_LOGICAL,
7752d335818SDavid Gibson     .class_init    = spapr_drc_lmb_class_init,
776bbf5c878SMichael Roth };
777bbf5c878SMichael Roth 
778962b6c36SMichael Roth static const TypeInfo spapr_drc_phb_info = {
779962b6c36SMichael Roth     .name          = TYPE_SPAPR_DRC_PHB,
780962b6c36SMichael Roth     .parent        = TYPE_SPAPR_DRC_LOGICAL,
781ce2918cbSDavid Gibson     .instance_size = sizeof(SpaprDrc),
782962b6c36SMichael Roth     .class_init    = spapr_drc_phb_class_init,
783962b6c36SMichael Roth };
784962b6c36SMichael Roth 
785ee3a71e3SShivaprasad G Bhat static const TypeInfo spapr_drc_pmem_info = {
786ee3a71e3SShivaprasad G Bhat     .name          = TYPE_SPAPR_DRC_PMEM,
787ee3a71e3SShivaprasad G Bhat     .parent        = TYPE_SPAPR_DRC_LOGICAL,
788ee3a71e3SShivaprasad G Bhat     .class_init    = spapr_drc_pmem_class_init,
789ee3a71e3SShivaprasad G Bhat };
790ee3a71e3SShivaprasad G Bhat 
791bbf5c878SMichael Roth /* helper functions for external users */
792bbf5c878SMichael Roth 
793ce2918cbSDavid Gibson SpaprDrc *spapr_drc_by_index(uint32_t index)
794bbf5c878SMichael Roth {
795bbf5c878SMichael Roth     Object *obj;
796f5babeacSGreg Kurz     gchar *name;
797bbf5c878SMichael Roth 
798f5babeacSGreg Kurz     name = g_strdup_printf("%s/%x", DRC_CONTAINER_PATH, index);
799bbf5c878SMichael Roth     obj = object_resolve_path(name, NULL);
800f5babeacSGreg Kurz     g_free(name);
801bbf5c878SMichael Roth 
802bbf5c878SMichael Roth     return !obj ? NULL : SPAPR_DR_CONNECTOR(obj);
803bbf5c878SMichael Roth }
804bbf5c878SMichael Roth 
805ce2918cbSDavid Gibson SpaprDrc *spapr_drc_by_id(const char *type, uint32_t id)
806bbf5c878SMichael Roth {
807ce2918cbSDavid Gibson     SpaprDrcClass *drck
808fbf55397SDavid Gibson         = SPAPR_DR_CONNECTOR_CLASS(object_class_by_name(type));
809fbf55397SDavid Gibson 
810fbf55397SDavid Gibson     return spapr_drc_by_index(drck->typeshift << DRC_INDEX_TYPE_SHIFT
811fbf55397SDavid Gibson                               | (id & DRC_INDEX_ID_MASK));
812bbf5c878SMichael Roth }
813e4b798bbSMichael Roth 
814e4b798bbSMichael Roth /**
8159e7d38e8SDavid Gibson  * spapr_dt_drc
816e4b798bbSMichael Roth  *
817e4b798bbSMichael Roth  * @fdt: libfdt device tree
818e4b798bbSMichael Roth  * @path: path in the DT to generate properties
819e4b798bbSMichael Roth  * @owner: parent Object/DeviceState for which to generate DRC
820e4b798bbSMichael Roth  *         descriptions for
821ce2918cbSDavid Gibson  * @drc_type_mask: mask of SpaprDrcType values corresponding
822e4b798bbSMichael Roth  *   to the types of DRCs to generate entries for
823e4b798bbSMichael Roth  *
824e4b798bbSMichael Roth  * generate OF properties to describe DRC topology/indices to guests
825e4b798bbSMichael Roth  *
826e4b798bbSMichael Roth  * as documented in PAPR+ v2.1, 13.5.2
827e4b798bbSMichael Roth  */
8289e7d38e8SDavid Gibson int spapr_dt_drc(void *fdt, int offset, Object *owner, uint32_t drc_type_mask)
829e4b798bbSMichael Roth {
830e4b798bbSMichael Roth     Object *root_container;
831e4b798bbSMichael Roth     ObjectProperty *prop;
8327746abd8SDaniel P. Berrange     ObjectPropertyIterator iter;
833e4b798bbSMichael Roth     uint32_t drc_count = 0;
834e4b798bbSMichael Roth     GArray *drc_indexes, *drc_power_domains;
835e4b798bbSMichael Roth     GString *drc_names, *drc_types;
836e4b798bbSMichael Roth     int ret;
837e4b798bbSMichael Roth 
838e4b798bbSMichael Roth     /* the first entry of each properties is a 32-bit integer encoding
839e4b798bbSMichael Roth      * the number of elements in the array. we won't know this until
840e4b798bbSMichael Roth      * we complete the iteration through all the matching DRCs, but
841e4b798bbSMichael Roth      * reserve the space now and set the offsets accordingly so we
842e4b798bbSMichael Roth      * can fill them in later.
843e4b798bbSMichael Roth      */
844e4b798bbSMichael Roth     drc_indexes = g_array_new(false, true, sizeof(uint32_t));
845e4b798bbSMichael Roth     drc_indexes = g_array_set_size(drc_indexes, 1);
846e4b798bbSMichael Roth     drc_power_domains = g_array_new(false, true, sizeof(uint32_t));
847e4b798bbSMichael Roth     drc_power_domains = g_array_set_size(drc_power_domains, 1);
848e4b798bbSMichael Roth     drc_names = g_string_set_size(g_string_new(NULL), sizeof(uint32_t));
849e4b798bbSMichael Roth     drc_types = g_string_set_size(g_string_new(NULL), sizeof(uint32_t));
850e4b798bbSMichael Roth 
851e4b798bbSMichael Roth     /* aliases for all DRConnector objects will be rooted in QOM
852e4b798bbSMichael Roth      * composition tree at DRC_CONTAINER_PATH
853e4b798bbSMichael Roth      */
854e4b798bbSMichael Roth     root_container = container_get(object_get_root(), DRC_CONTAINER_PATH);
855e4b798bbSMichael Roth 
8567746abd8SDaniel P. Berrange     object_property_iter_init(&iter, root_container);
8577746abd8SDaniel P. Berrange     while ((prop = object_property_iter_next(&iter))) {
858e4b798bbSMichael Roth         Object *obj;
859ce2918cbSDavid Gibson         SpaprDrc *drc;
860ce2918cbSDavid Gibson         SpaprDrcClass *drck;
861dbd26f2fSShivaprasad G Bhat         char *drc_name = NULL;
862e4b798bbSMichael Roth         uint32_t drc_index, drc_power_domain;
863e4b798bbSMichael Roth 
864e4b798bbSMichael Roth         if (!strstart(prop->type, "link<", NULL)) {
865e4b798bbSMichael Roth             continue;
866e4b798bbSMichael Roth         }
867e4b798bbSMichael Roth 
868552d7f49SMarkus Armbruster         obj = object_property_get_link(root_container, prop->name,
869552d7f49SMarkus Armbruster                                        &error_abort);
870e4b798bbSMichael Roth         drc = SPAPR_DR_CONNECTOR(obj);
871e4b798bbSMichael Roth         drck = SPAPR_DR_CONNECTOR_GET_CLASS(drc);
872e4b798bbSMichael Roth 
873e4b798bbSMichael Roth         if (owner && (drc->owner != owner)) {
874e4b798bbSMichael Roth             continue;
875e4b798bbSMichael Roth         }
876e4b798bbSMichael Roth 
8772d335818SDavid Gibson         if ((spapr_drc_type(drc) & drc_type_mask) == 0) {
878e4b798bbSMichael Roth             continue;
879e4b798bbSMichael Roth         }
880e4b798bbSMichael Roth 
881e4b798bbSMichael Roth         drc_count++;
882e4b798bbSMichael Roth 
883e4b798bbSMichael Roth         /* ibm,drc-indexes */
8840b55aa91SDavid Gibson         drc_index = cpu_to_be32(spapr_drc_index(drc));
885e4b798bbSMichael Roth         g_array_append_val(drc_indexes, drc_index);
886e4b798bbSMichael Roth 
887e4b798bbSMichael Roth         /* ibm,drc-power-domains */
888e4b798bbSMichael Roth         drc_power_domain = cpu_to_be32(-1);
889e4b798bbSMichael Roth         g_array_append_val(drc_power_domains, drc_power_domain);
890e4b798bbSMichael Roth 
891e4b798bbSMichael Roth         /* ibm,drc-names */
892dbd26f2fSShivaprasad G Bhat         drc_name = spapr_drc_name(drc);
893dbd26f2fSShivaprasad G Bhat         drc_names = g_string_append(drc_names, drc_name);
894e4b798bbSMichael Roth         drc_names = g_string_insert_len(drc_names, -1, "\0", 1);
895dbd26f2fSShivaprasad G Bhat         g_free(drc_name);
896e4b798bbSMichael Roth 
897e4b798bbSMichael Roth         /* ibm,drc-types */
8981693ea16SDavid Gibson         drc_types = g_string_append(drc_types, drck->typename);
899e4b798bbSMichael Roth         drc_types = g_string_insert_len(drc_types, -1, "\0", 1);
900e4b798bbSMichael Roth     }
901e4b798bbSMichael Roth 
902e4b798bbSMichael Roth     /* now write the drc count into the space we reserved at the
903e4b798bbSMichael Roth      * beginning of the arrays previously
904e4b798bbSMichael Roth      */
905e4b798bbSMichael Roth     *(uint32_t *)drc_indexes->data = cpu_to_be32(drc_count);
906e4b798bbSMichael Roth     *(uint32_t *)drc_power_domains->data = cpu_to_be32(drc_count);
907e4b798bbSMichael Roth     *(uint32_t *)drc_names->str = cpu_to_be32(drc_count);
908e4b798bbSMichael Roth     *(uint32_t *)drc_types->str = cpu_to_be32(drc_count);
909e4b798bbSMichael Roth 
9109e7d38e8SDavid Gibson     ret = fdt_setprop(fdt, offset, "ibm,drc-indexes",
911e4b798bbSMichael Roth                       drc_indexes->data,
912e4b798bbSMichael Roth                       drc_indexes->len * sizeof(uint32_t));
913e4b798bbSMichael Roth     if (ret) {
914ce9863b7SCédric Le Goater         error_report("Couldn't create ibm,drc-indexes property");
915e4b798bbSMichael Roth         goto out;
916e4b798bbSMichael Roth     }
917e4b798bbSMichael Roth 
9189e7d38e8SDavid Gibson     ret = fdt_setprop(fdt, offset, "ibm,drc-power-domains",
919e4b798bbSMichael Roth                       drc_power_domains->data,
920e4b798bbSMichael Roth                       drc_power_domains->len * sizeof(uint32_t));
921e4b798bbSMichael Roth     if (ret) {
922ce9863b7SCédric Le Goater         error_report("Couldn't finalize ibm,drc-power-domains property");
923e4b798bbSMichael Roth         goto out;
924e4b798bbSMichael Roth     }
925e4b798bbSMichael Roth 
9269e7d38e8SDavid Gibson     ret = fdt_setprop(fdt, offset, "ibm,drc-names",
927e4b798bbSMichael Roth                       drc_names->str, drc_names->len);
928e4b798bbSMichael Roth     if (ret) {
929ce9863b7SCédric Le Goater         error_report("Couldn't finalize ibm,drc-names property");
930e4b798bbSMichael Roth         goto out;
931e4b798bbSMichael Roth     }
932e4b798bbSMichael Roth 
9339e7d38e8SDavid Gibson     ret = fdt_setprop(fdt, offset, "ibm,drc-types",
934e4b798bbSMichael Roth                       drc_types->str, drc_types->len);
935e4b798bbSMichael Roth     if (ret) {
936ce9863b7SCédric Le Goater         error_report("Couldn't finalize ibm,drc-types property");
937e4b798bbSMichael Roth         goto out;
938e4b798bbSMichael Roth     }
939e4b798bbSMichael Roth 
940e4b798bbSMichael Roth out:
941e4b798bbSMichael Roth     g_array_free(drc_indexes, true);
942e4b798bbSMichael Roth     g_array_free(drc_power_domains, true);
943e4b798bbSMichael Roth     g_string_free(drc_names, true);
944e4b798bbSMichael Roth     g_string_free(drc_types, true);
945e4b798bbSMichael Roth 
946e4b798bbSMichael Roth     return ret;
947e4b798bbSMichael Roth }
948b89b3d39SDavid Gibson 
949b89b3d39SDavid Gibson /*
950b89b3d39SDavid Gibson  * RTAS calls
951b89b3d39SDavid Gibson  */
952b89b3d39SDavid Gibson 
9537b7258f8SDavid Gibson static uint32_t rtas_set_isolation_state(uint32_t idx, uint32_t state)
954b89b3d39SDavid Gibson {
955ce2918cbSDavid Gibson     SpaprDrc *drc = spapr_drc_by_index(idx);
956ce2918cbSDavid Gibson     SpaprDrcClass *drck;
9577b7258f8SDavid Gibson 
9587b7258f8SDavid Gibson     if (!drc) {
9590dfabd39SDavid Gibson         return RTAS_OUT_NO_SUCH_INDICATOR;
960b89b3d39SDavid Gibson     }
961b89b3d39SDavid Gibson 
9620dfabd39SDavid Gibson     trace_spapr_drc_set_isolation_state(spapr_drc_index(drc), state);
9630dfabd39SDavid Gibson 
9647b7258f8SDavid Gibson     drck = SPAPR_DR_CONNECTOR_GET_CLASS(drc);
9650dfabd39SDavid Gibson 
9660dfabd39SDavid Gibson     switch (state) {
9670dfabd39SDavid Gibson     case SPAPR_DR_ISOLATION_STATE_ISOLATED:
9680dfabd39SDavid Gibson         return drck->isolate(drc);
9690dfabd39SDavid Gibson 
9700dfabd39SDavid Gibson     case SPAPR_DR_ISOLATION_STATE_UNISOLATED:
9710dfabd39SDavid Gibson         return drck->unisolate(drc);
9720dfabd39SDavid Gibson 
9730dfabd39SDavid Gibson     default:
9740dfabd39SDavid Gibson         return RTAS_OUT_PARAM_ERROR;
9750dfabd39SDavid Gibson     }
9767b7258f8SDavid Gibson }
9777b7258f8SDavid Gibson 
9787b7258f8SDavid Gibson static uint32_t rtas_set_allocation_state(uint32_t idx, uint32_t state)
9797b7258f8SDavid Gibson {
980ce2918cbSDavid Gibson     SpaprDrc *drc = spapr_drc_by_index(idx);
9817b7258f8SDavid Gibson 
98261736732SDavid Gibson     if (!drc || !object_dynamic_cast(OBJECT(drc), TYPE_SPAPR_DRC_LOGICAL)) {
98361736732SDavid Gibson         return RTAS_OUT_NO_SUCH_INDICATOR;
9847b7258f8SDavid Gibson     }
9857b7258f8SDavid Gibson 
98661736732SDavid Gibson     trace_spapr_drc_set_allocation_state(spapr_drc_index(drc), state);
98761736732SDavid Gibson 
98861736732SDavid Gibson     switch (state) {
98961736732SDavid Gibson     case SPAPR_DR_ALLOCATION_STATE_USABLE:
99061736732SDavid Gibson         return drc_set_usable(drc);
99161736732SDavid Gibson 
99261736732SDavid Gibson     case SPAPR_DR_ALLOCATION_STATE_UNUSABLE:
99361736732SDavid Gibson         return drc_set_unusable(drc);
99461736732SDavid Gibson 
99561736732SDavid Gibson     default:
99661736732SDavid Gibson         return RTAS_OUT_PARAM_ERROR;
99761736732SDavid Gibson     }
9987b7258f8SDavid Gibson }
9997b7258f8SDavid Gibson 
1000cd74d27eSDavid Gibson static uint32_t rtas_set_dr_indicator(uint32_t idx, uint32_t state)
10017b7258f8SDavid Gibson {
1002ce2918cbSDavid Gibson     SpaprDrc *drc = spapr_drc_by_index(idx);
10037b7258f8SDavid Gibson 
100467fea71bSDavid Gibson     if (!drc || !object_dynamic_cast(OBJECT(drc), TYPE_SPAPR_DRC_PHYSICAL)) {
100567fea71bSDavid Gibson         return RTAS_OUT_NO_SUCH_INDICATOR;
100667fea71bSDavid Gibson     }
100767fea71bSDavid Gibson     if ((state != SPAPR_DR_INDICATOR_INACTIVE)
100867fea71bSDavid Gibson         && (state != SPAPR_DR_INDICATOR_ACTIVE)
100967fea71bSDavid Gibson         && (state != SPAPR_DR_INDICATOR_IDENTIFY)
101067fea71bSDavid Gibson         && (state != SPAPR_DR_INDICATOR_ACTION)) {
101167fea71bSDavid Gibson         return RTAS_OUT_PARAM_ERROR; /* bad state parameter */
10127b7258f8SDavid Gibson     }
10137b7258f8SDavid Gibson 
1014cd74d27eSDavid Gibson     trace_spapr_drc_set_dr_indicator(idx, state);
101567fea71bSDavid Gibson     SPAPR_DRC_PHYSICAL(drc)->dr_indicator = state;
1016cd74d27eSDavid Gibson     return RTAS_OUT_SUCCESS;
1017b89b3d39SDavid Gibson }
1018b89b3d39SDavid Gibson 
1019ce2918cbSDavid Gibson static void rtas_set_indicator(PowerPCCPU *cpu, SpaprMachineState *spapr,
10207b7258f8SDavid Gibson                                uint32_t token,
10217b7258f8SDavid Gibson                                uint32_t nargs, target_ulong args,
10227b7258f8SDavid Gibson                                uint32_t nret, target_ulong rets)
1023b89b3d39SDavid Gibson {
10247b7258f8SDavid Gibson     uint32_t type, idx, state;
1025b89b3d39SDavid Gibson     uint32_t ret = RTAS_OUT_SUCCESS;
1026b89b3d39SDavid Gibson 
1027b89b3d39SDavid Gibson     if (nargs != 3 || nret != 1) {
1028b89b3d39SDavid Gibson         ret = RTAS_OUT_PARAM_ERROR;
1029b89b3d39SDavid Gibson         goto out;
1030b89b3d39SDavid Gibson     }
1031b89b3d39SDavid Gibson 
10327b7258f8SDavid Gibson     type = rtas_ld(args, 0);
10337b7258f8SDavid Gibson     idx = rtas_ld(args, 1);
10347b7258f8SDavid Gibson     state = rtas_ld(args, 2);
1035b89b3d39SDavid Gibson 
10367b7258f8SDavid Gibson     switch (type) {
1037b89b3d39SDavid Gibson     case RTAS_SENSOR_TYPE_ISOLATION_STATE:
10387b7258f8SDavid Gibson         ret = rtas_set_isolation_state(idx, state);
1039b89b3d39SDavid Gibson         break;
1040b89b3d39SDavid Gibson     case RTAS_SENSOR_TYPE_DR:
1041cd74d27eSDavid Gibson         ret = rtas_set_dr_indicator(idx, state);
1042b89b3d39SDavid Gibson         break;
1043b89b3d39SDavid Gibson     case RTAS_SENSOR_TYPE_ALLOCATION_STATE:
10447b7258f8SDavid Gibson         ret = rtas_set_allocation_state(idx, state);
1045b89b3d39SDavid Gibson         break;
1046b89b3d39SDavid Gibson     default:
10477b7258f8SDavid Gibson         ret = RTAS_OUT_NOT_SUPPORTED;
1048b89b3d39SDavid Gibson     }
1049b89b3d39SDavid Gibson 
1050b89b3d39SDavid Gibson out:
1051b89b3d39SDavid Gibson     rtas_st(rets, 0, ret);
1052b89b3d39SDavid Gibson }
1053b89b3d39SDavid Gibson 
1054ce2918cbSDavid Gibson static void rtas_get_sensor_state(PowerPCCPU *cpu, SpaprMachineState *spapr,
1055b89b3d39SDavid Gibson                                   uint32_t token, uint32_t nargs,
1056b89b3d39SDavid Gibson                                   target_ulong args, uint32_t nret,
1057b89b3d39SDavid Gibson                                   target_ulong rets)
1058b89b3d39SDavid Gibson {
1059b89b3d39SDavid Gibson     uint32_t sensor_type;
1060b89b3d39SDavid Gibson     uint32_t sensor_index;
1061b89b3d39SDavid Gibson     uint32_t sensor_state = 0;
1062ce2918cbSDavid Gibson     SpaprDrc *drc;
1063ce2918cbSDavid Gibson     SpaprDrcClass *drck;
1064b89b3d39SDavid Gibson     uint32_t ret = RTAS_OUT_SUCCESS;
1065b89b3d39SDavid Gibson 
1066b89b3d39SDavid Gibson     if (nargs != 2 || nret != 2) {
1067b89b3d39SDavid Gibson         ret = RTAS_OUT_PARAM_ERROR;
1068b89b3d39SDavid Gibson         goto out;
1069b89b3d39SDavid Gibson     }
1070b89b3d39SDavid Gibson 
1071b89b3d39SDavid Gibson     sensor_type = rtas_ld(args, 0);
1072b89b3d39SDavid Gibson     sensor_index = rtas_ld(args, 1);
1073b89b3d39SDavid Gibson 
1074b89b3d39SDavid Gibson     if (sensor_type != RTAS_SENSOR_TYPE_ENTITY_SENSE) {
1075b89b3d39SDavid Gibson         /* currently only DR-related sensors are implemented */
1076b89b3d39SDavid Gibson         trace_spapr_rtas_get_sensor_state_not_supported(sensor_index,
1077b89b3d39SDavid Gibson                                                         sensor_type);
1078b89b3d39SDavid Gibson         ret = RTAS_OUT_NOT_SUPPORTED;
1079b89b3d39SDavid Gibson         goto out;
1080b89b3d39SDavid Gibson     }
1081b89b3d39SDavid Gibson 
1082fbf55397SDavid Gibson     drc = spapr_drc_by_index(sensor_index);
1083b89b3d39SDavid Gibson     if (!drc) {
1084b89b3d39SDavid Gibson         trace_spapr_rtas_get_sensor_state_invalid(sensor_index);
1085b89b3d39SDavid Gibson         ret = RTAS_OUT_PARAM_ERROR;
1086b89b3d39SDavid Gibson         goto out;
1087b89b3d39SDavid Gibson     }
1088b89b3d39SDavid Gibson     drck = SPAPR_DR_CONNECTOR_GET_CLASS(drc);
1089f224d35bSDavid Gibson     sensor_state = drck->dr_entity_sense(drc);
1090b89b3d39SDavid Gibson 
1091b89b3d39SDavid Gibson out:
1092b89b3d39SDavid Gibson     rtas_st(rets, 0, ret);
1093b89b3d39SDavid Gibson     rtas_st(rets, 1, sensor_state);
1094b89b3d39SDavid Gibson }
1095b89b3d39SDavid Gibson 
1096b89b3d39SDavid Gibson /* configure-connector work area offsets, int32_t units for field
1097b89b3d39SDavid Gibson  * indexes, bytes for field offset/len values.
1098b89b3d39SDavid Gibson  *
1099b89b3d39SDavid Gibson  * as documented by PAPR+ v2.7, 13.5.3.5
1100b89b3d39SDavid Gibson  */
1101b89b3d39SDavid Gibson #define CC_IDX_NODE_NAME_OFFSET 2
1102b89b3d39SDavid Gibson #define CC_IDX_PROP_NAME_OFFSET 2
1103b89b3d39SDavid Gibson #define CC_IDX_PROP_LEN 3
1104b89b3d39SDavid Gibson #define CC_IDX_PROP_DATA_OFFSET 4
1105b89b3d39SDavid Gibson #define CC_VAL_DATA_OFFSET ((CC_IDX_PROP_DATA_OFFSET + 1) * 4)
1106b89b3d39SDavid Gibson #define CC_WA_LEN 4096
1107b89b3d39SDavid Gibson 
1108b89b3d39SDavid Gibson static void configure_connector_st(target_ulong addr, target_ulong offset,
1109b89b3d39SDavid Gibson                                    const void *buf, size_t len)
1110b89b3d39SDavid Gibson {
1111b89b3d39SDavid Gibson     cpu_physical_memory_write(ppc64_phys_to_real(addr + offset),
1112b89b3d39SDavid Gibson                               buf, MIN(len, CC_WA_LEN - offset));
1113b89b3d39SDavid Gibson }
1114b89b3d39SDavid Gibson 
1115b89b3d39SDavid Gibson static void rtas_ibm_configure_connector(PowerPCCPU *cpu,
1116ce2918cbSDavid Gibson                                          SpaprMachineState *spapr,
1117b89b3d39SDavid Gibson                                          uint32_t token, uint32_t nargs,
1118b89b3d39SDavid Gibson                                          target_ulong args, uint32_t nret,
1119b89b3d39SDavid Gibson                                          target_ulong rets)
1120b89b3d39SDavid Gibson {
1121b89b3d39SDavid Gibson     uint64_t wa_addr;
1122b89b3d39SDavid Gibson     uint64_t wa_offset;
1123b89b3d39SDavid Gibson     uint32_t drc_index;
1124ce2918cbSDavid Gibson     SpaprDrc *drc;
1125ce2918cbSDavid Gibson     SpaprDrcClass *drck;
1126ce2918cbSDavid Gibson     SpaprDRCCResponse resp = SPAPR_DR_CC_RESPONSE_CONTINUE;
1127b89b3d39SDavid Gibson     int rc;
1128b89b3d39SDavid Gibson 
1129b89b3d39SDavid Gibson     if (nargs != 2 || nret != 1) {
1130b89b3d39SDavid Gibson         rtas_st(rets, 0, RTAS_OUT_PARAM_ERROR);
1131b89b3d39SDavid Gibson         return;
1132b89b3d39SDavid Gibson     }
1133b89b3d39SDavid Gibson 
1134b89b3d39SDavid Gibson     wa_addr = ((uint64_t)rtas_ld(args, 1) << 32) | rtas_ld(args, 0);
1135b89b3d39SDavid Gibson 
1136b89b3d39SDavid Gibson     drc_index = rtas_ld(wa_addr, 0);
1137fbf55397SDavid Gibson     drc = spapr_drc_by_index(drc_index);
1138b89b3d39SDavid Gibson     if (!drc) {
1139b89b3d39SDavid Gibson         trace_spapr_rtas_ibm_configure_connector_invalid(drc_index);
1140b89b3d39SDavid Gibson         rc = RTAS_OUT_PARAM_ERROR;
1141b89b3d39SDavid Gibson         goto out;
1142b89b3d39SDavid Gibson     }
1143b89b3d39SDavid Gibson 
11449d4c0f4fSDavid Gibson     if ((drc->state != SPAPR_DRC_STATE_LOGICAL_UNISOLATE)
1145188bfe1bSBharata B Rao         && (drc->state != SPAPR_DRC_STATE_PHYSICAL_UNISOLATE)
1146188bfe1bSBharata B Rao         && (drc->state != SPAPR_DRC_STATE_LOGICAL_CONFIGURED)
1147188bfe1bSBharata B Rao         && (drc->state != SPAPR_DRC_STATE_PHYSICAL_CONFIGURED)) {
1148188bfe1bSBharata B Rao         /*
1149188bfe1bSBharata B Rao          * Need to unisolate the device before configuring
1150188bfe1bSBharata B Rao          * or it should already be in configured state to
1151188bfe1bSBharata B Rao          * allow configure-connector be called repeatedly.
1152188bfe1bSBharata B Rao          */
1153b89b3d39SDavid Gibson         rc = SPAPR_DR_CC_RESPONSE_NOT_CONFIGURABLE;
1154b89b3d39SDavid Gibson         goto out;
1155b89b3d39SDavid Gibson     }
1156b89b3d39SDavid Gibson 
11579d4c0f4fSDavid Gibson     drck = SPAPR_DR_CONNECTOR_GET_CLASS(drc);
11589d4c0f4fSDavid Gibson 
1159d9c95c71SGreg Kurz     if (!drc->fdt) {
1160d9c95c71SGreg Kurz         void *fdt;
1161d9c95c71SGreg Kurz         int fdt_size;
1162d9c95c71SGreg Kurz 
1163d9c95c71SGreg Kurz         fdt = create_device_tree(&fdt_size);
1164d9c95c71SGreg Kurz 
1165d9c95c71SGreg Kurz         if (drck->dt_populate(drc, spapr, fdt, &drc->fdt_start_offset,
11669261ef5eSMarkus Armbruster                               NULL)) {
1167d9c95c71SGreg Kurz             g_free(fdt);
1168d9c95c71SGreg Kurz             rc = SPAPR_DR_CC_RESPONSE_ERROR;
1169d9c95c71SGreg Kurz             goto out;
1170d9c95c71SGreg Kurz         }
1171d9c95c71SGreg Kurz 
1172d9c95c71SGreg Kurz         drc->fdt = fdt;
1173d9c95c71SGreg Kurz         drc->ccs_offset = drc->fdt_start_offset;
1174d9c95c71SGreg Kurz         drc->ccs_depth = 0;
1175d9c95c71SGreg Kurz     }
1176d9c95c71SGreg Kurz 
1177b89b3d39SDavid Gibson     do {
1178b89b3d39SDavid Gibson         uint32_t tag;
1179b89b3d39SDavid Gibson         const char *name;
1180b89b3d39SDavid Gibson         const struct fdt_property *prop;
1181b89b3d39SDavid Gibson         int fdt_offset_next, prop_len;
1182b89b3d39SDavid Gibson 
11834445b1d2SDavid Gibson         tag = fdt_next_tag(drc->fdt, drc->ccs_offset, &fdt_offset_next);
1184b89b3d39SDavid Gibson 
1185b89b3d39SDavid Gibson         switch (tag) {
1186b89b3d39SDavid Gibson         case FDT_BEGIN_NODE:
11874445b1d2SDavid Gibson             drc->ccs_depth++;
11884445b1d2SDavid Gibson             name = fdt_get_name(drc->fdt, drc->ccs_offset, NULL);
1189b89b3d39SDavid Gibson 
1190b89b3d39SDavid Gibson             /* provide the name of the next OF node */
1191b89b3d39SDavid Gibson             wa_offset = CC_VAL_DATA_OFFSET;
1192b89b3d39SDavid Gibson             rtas_st(wa_addr, CC_IDX_NODE_NAME_OFFSET, wa_offset);
1193b89b3d39SDavid Gibson             configure_connector_st(wa_addr, wa_offset, name, strlen(name) + 1);
1194b89b3d39SDavid Gibson             resp = SPAPR_DR_CC_RESPONSE_NEXT_CHILD;
1195b89b3d39SDavid Gibson             break;
1196b89b3d39SDavid Gibson         case FDT_END_NODE:
11974445b1d2SDavid Gibson             drc->ccs_depth--;
11984445b1d2SDavid Gibson             if (drc->ccs_depth == 0) {
11990b55aa91SDavid Gibson                 uint32_t drc_index = spapr_drc_index(drc);
12009d4c0f4fSDavid Gibson 
12019d4c0f4fSDavid Gibson                 /* done sending the device tree, move to configured state */
12020b55aa91SDavid Gibson                 trace_spapr_drc_set_configured(drc_index);
12039d4c0f4fSDavid Gibson                 drc->state = drck->ready_state;
1204188bfe1bSBharata B Rao                 /*
1205188bfe1bSBharata B Rao                  * Ensure that we are able to send the FDT fragment
1206188bfe1bSBharata B Rao                  * again via configure-connector call if the guest requests.
1207188bfe1bSBharata B Rao                  */
1208188bfe1bSBharata B Rao                 drc->ccs_offset = drc->fdt_start_offset;
1209188bfe1bSBharata B Rao                 drc->ccs_depth = 0;
1210188bfe1bSBharata B Rao                 fdt_offset_next = drc->fdt_start_offset;
1211b89b3d39SDavid Gibson                 resp = SPAPR_DR_CC_RESPONSE_SUCCESS;
1212b89b3d39SDavid Gibson             } else {
1213b89b3d39SDavid Gibson                 resp = SPAPR_DR_CC_RESPONSE_PREV_PARENT;
1214b89b3d39SDavid Gibson             }
1215b89b3d39SDavid Gibson             break;
1216b89b3d39SDavid Gibson         case FDT_PROP:
12174445b1d2SDavid Gibson             prop = fdt_get_property_by_offset(drc->fdt, drc->ccs_offset,
1218b89b3d39SDavid Gibson                                               &prop_len);
121988af6ea5SDavid Gibson             name = fdt_string(drc->fdt, fdt32_to_cpu(prop->nameoff));
1220b89b3d39SDavid Gibson 
1221b89b3d39SDavid Gibson             /* provide the name of the next OF property */
1222b89b3d39SDavid Gibson             wa_offset = CC_VAL_DATA_OFFSET;
1223b89b3d39SDavid Gibson             rtas_st(wa_addr, CC_IDX_PROP_NAME_OFFSET, wa_offset);
1224b89b3d39SDavid Gibson             configure_connector_st(wa_addr, wa_offset, name, strlen(name) + 1);
1225b89b3d39SDavid Gibson 
1226b89b3d39SDavid Gibson             /* provide the length and value of the OF property. data gets
1227b89b3d39SDavid Gibson              * placed immediately after NULL terminator of the OF property's
1228b89b3d39SDavid Gibson              * name string
1229b89b3d39SDavid Gibson              */
1230b89b3d39SDavid Gibson             wa_offset += strlen(name) + 1,
1231b89b3d39SDavid Gibson             rtas_st(wa_addr, CC_IDX_PROP_LEN, prop_len);
1232b89b3d39SDavid Gibson             rtas_st(wa_addr, CC_IDX_PROP_DATA_OFFSET, wa_offset);
1233b89b3d39SDavid Gibson             configure_connector_st(wa_addr, wa_offset, prop->data, prop_len);
1234b89b3d39SDavid Gibson             resp = SPAPR_DR_CC_RESPONSE_NEXT_PROPERTY;
1235b89b3d39SDavid Gibson             break;
1236b89b3d39SDavid Gibson         case FDT_END:
1237b89b3d39SDavid Gibson             resp = SPAPR_DR_CC_RESPONSE_ERROR;
1238b89b3d39SDavid Gibson         default:
1239b89b3d39SDavid Gibson             /* keep seeking for an actionable tag */
1240b89b3d39SDavid Gibson             break;
1241b89b3d39SDavid Gibson         }
12424445b1d2SDavid Gibson         if (drc->ccs_offset >= 0) {
12434445b1d2SDavid Gibson             drc->ccs_offset = fdt_offset_next;
1244b89b3d39SDavid Gibson         }
1245b89b3d39SDavid Gibson     } while (resp == SPAPR_DR_CC_RESPONSE_CONTINUE);
1246b89b3d39SDavid Gibson 
1247b89b3d39SDavid Gibson     rc = resp;
1248b89b3d39SDavid Gibson out:
1249b89b3d39SDavid Gibson     rtas_st(rets, 0, rc);
1250b89b3d39SDavid Gibson }
1251b89b3d39SDavid Gibson 
1252b89b3d39SDavid Gibson static void spapr_drc_register_types(void)
1253b89b3d39SDavid Gibson {
1254b89b3d39SDavid Gibson     type_register_static(&spapr_dr_connector_info);
12552d335818SDavid Gibson     type_register_static(&spapr_drc_physical_info);
12562d335818SDavid Gibson     type_register_static(&spapr_drc_logical_info);
12572d335818SDavid Gibson     type_register_static(&spapr_drc_cpu_info);
12582d335818SDavid Gibson     type_register_static(&spapr_drc_pci_info);
12592d335818SDavid Gibson     type_register_static(&spapr_drc_lmb_info);
1260962b6c36SMichael Roth     type_register_static(&spapr_drc_phb_info);
1261ee3a71e3SShivaprasad G Bhat     type_register_static(&spapr_drc_pmem_info);
1262b89b3d39SDavid Gibson 
1263b89b3d39SDavid Gibson     spapr_rtas_register(RTAS_SET_INDICATOR, "set-indicator",
1264b89b3d39SDavid Gibson                         rtas_set_indicator);
1265b89b3d39SDavid Gibson     spapr_rtas_register(RTAS_GET_SENSOR_STATE, "get-sensor-state",
1266b89b3d39SDavid Gibson                         rtas_get_sensor_state);
1267b89b3d39SDavid Gibson     spapr_rtas_register(RTAS_IBM_CONFIGURE_CONNECTOR, "ibm,configure-connector",
1268b89b3d39SDavid Gibson                         rtas_ibm_configure_connector);
1269b89b3d39SDavid Gibson }
1270b89b3d39SDavid Gibson type_init(spapr_drc_register_types)
1271