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"
15407bc4bfSDaniel P. Berrangé #include "qobject/qnull.h"
16f348b6d1SVeronia Bahaa #include "qemu/cutils.h"
17bbf5c878SMichael Roth #include "hw/ppc/spapr_drc.h"
18bbf5c878SMichael Roth #include "qom/object.h"
19d6454270SMarkus Armbruster #include "migration/vmstate.h"
204b08cd56SDaniel Henrique Barboza #include "qapi/qapi-events-qdev.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"
2632cad1ffSPhilippe Mathieu-Daudé #include "system/device_tree.h"
2732cad1ffSPhilippe Mathieu-Daudé #include "system/reset.h"
2824ac7755SLaurent Vivier #include "trace.h"
29bbf5c878SMichael Roth
307c03a17cSPeter Xu #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
spapr_drc_type(SpaprDrc * drc)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
spapr_drc_index(SpaprDrc * drc)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
spapr_drc_release(SpaprDrc * drc)5366d10d32SDaniel Henrique Barboza static void spapr_drc_release(SpaprDrc *drc)
5466d10d32SDaniel Henrique Barboza {
5566d10d32SDaniel Henrique Barboza SpaprDrcClass *drck = SPAPR_DR_CONNECTOR_GET_CLASS(drc);
5666d10d32SDaniel Henrique Barboza
5766d10d32SDaniel Henrique Barboza drck->release(drc->dev);
5866d10d32SDaniel Henrique Barboza
5966d10d32SDaniel Henrique Barboza drc->unplug_requested = false;
6066d10d32SDaniel Henrique Barboza g_free(drc->fdt);
6166d10d32SDaniel Henrique Barboza drc->fdt = NULL;
6266d10d32SDaniel Henrique Barboza drc->fdt_start_offset = 0;
6366d10d32SDaniel Henrique Barboza object_property_del(OBJECT(drc), "device");
6466d10d32SDaniel Henrique Barboza drc->dev = NULL;
6566d10d32SDaniel Henrique Barboza }
6666d10d32SDaniel Henrique Barboza
drc_isolate_physical(SpaprDrc * drc)67ce2918cbSDavid Gibson static uint32_t drc_isolate_physical(SpaprDrc *drc)
68bbf5c878SMichael Roth {
699d4c0f4fSDavid Gibson switch (drc->state) {
709d4c0f4fSDavid Gibson case SPAPR_DRC_STATE_PHYSICAL_POWERON:
719d4c0f4fSDavid Gibson return RTAS_OUT_SUCCESS; /* Nothing to do */
729d4c0f4fSDavid Gibson case SPAPR_DRC_STATE_PHYSICAL_CONFIGURED:
739d4c0f4fSDavid Gibson break; /* see below */
749d4c0f4fSDavid Gibson case SPAPR_DRC_STATE_PHYSICAL_UNISOLATE:
759d4c0f4fSDavid Gibson return RTAS_OUT_PARAM_ERROR; /* not allowed */
769d4c0f4fSDavid Gibson default:
779d4c0f4fSDavid Gibson g_assert_not_reached();
789d4c0f4fSDavid Gibson }
799d4c0f4fSDavid Gibson
809d4c0f4fSDavid Gibson drc->state = SPAPR_DRC_STATE_PHYSICAL_POWERON;
819d1852ceSMichael Roth
82f1c52354SDavid Gibson if (drc->unplug_requested) {
830b55aa91SDavid Gibson uint32_t drc_index = spapr_drc_index(drc);
840b55aa91SDavid Gibson trace_spapr_drc_set_isolation_state_finalizing(drc_index);
8566d10d32SDaniel Henrique Barboza spapr_drc_release(drc);
86bbf5c878SMichael Roth }
870dfabd39SDavid Gibson
880dfabd39SDavid Gibson return RTAS_OUT_SUCCESS;
89bbf5c878SMichael Roth }
90bbf5c878SMichael Roth
drc_unisolate_physical(SpaprDrc * drc)91ce2918cbSDavid Gibson static uint32_t drc_unisolate_physical(SpaprDrc *drc)
920dfabd39SDavid Gibson {
939d4c0f4fSDavid Gibson switch (drc->state) {
949d4c0f4fSDavid Gibson case SPAPR_DRC_STATE_PHYSICAL_UNISOLATE:
959d4c0f4fSDavid Gibson case SPAPR_DRC_STATE_PHYSICAL_CONFIGURED:
969d4c0f4fSDavid Gibson return RTAS_OUT_SUCCESS; /* Nothing to do */
979d4c0f4fSDavid Gibson case SPAPR_DRC_STATE_PHYSICAL_POWERON:
989d4c0f4fSDavid Gibson break; /* see below */
999d4c0f4fSDavid Gibson default:
1009d4c0f4fSDavid Gibson g_assert_not_reached();
1019d4c0f4fSDavid Gibson }
1029d4c0f4fSDavid Gibson
1030dfabd39SDavid Gibson /* cannot unisolate a non-existent resource, and, or resources
1040dfabd39SDavid Gibson * which are in an 'UNUSABLE' allocation state. (PAPR 2.7,
1050dfabd39SDavid Gibson * 13.5.3.5)
1060dfabd39SDavid Gibson */
1070dfabd39SDavid Gibson if (!drc->dev) {
1080dfabd39SDavid Gibson return RTAS_OUT_NO_SUCH_INDICATOR;
1090dfabd39SDavid Gibson }
1100dfabd39SDavid Gibson
1119d4c0f4fSDavid Gibson drc->state = SPAPR_DRC_STATE_PHYSICAL_UNISOLATE;
1124445b1d2SDavid Gibson drc->ccs_offset = drc->fdt_start_offset;
1134445b1d2SDavid Gibson drc->ccs_depth = 0;
1140dfabd39SDavid Gibson
1150dfabd39SDavid Gibson return RTAS_OUT_SUCCESS;
1160dfabd39SDavid Gibson }
1170dfabd39SDavid Gibson
drc_isolate_logical(SpaprDrc * drc)118ce2918cbSDavid Gibson static uint32_t drc_isolate_logical(SpaprDrc *drc)
1190dfabd39SDavid Gibson {
1209d4c0f4fSDavid Gibson switch (drc->state) {
1219d4c0f4fSDavid Gibson case SPAPR_DRC_STATE_LOGICAL_AVAILABLE:
1229d4c0f4fSDavid Gibson case SPAPR_DRC_STATE_LOGICAL_UNUSABLE:
1239d4c0f4fSDavid Gibson return RTAS_OUT_SUCCESS; /* Nothing to do */
1249d4c0f4fSDavid Gibson case SPAPR_DRC_STATE_LOGICAL_CONFIGURED:
1259d4c0f4fSDavid Gibson break; /* see below */
1269d4c0f4fSDavid Gibson case SPAPR_DRC_STATE_LOGICAL_UNISOLATE:
1279d4c0f4fSDavid Gibson return RTAS_OUT_PARAM_ERROR; /* not allowed */
1289d4c0f4fSDavid Gibson default:
1299d4c0f4fSDavid Gibson g_assert_not_reached();
1309d4c0f4fSDavid Gibson }
1319d4c0f4fSDavid Gibson
1320dfabd39SDavid Gibson /*
1330dfabd39SDavid Gibson * Fail any requests to ISOLATE the LMB DRC if this LMB doesn't
1340dfabd39SDavid Gibson * belong to a DIMM device that is marked for removal.
1350dfabd39SDavid Gibson *
1360dfabd39SDavid Gibson * Currently the guest userspace tool drmgr that drives the memory
1370dfabd39SDavid Gibson * hotplug/unplug will just try to remove a set of 'removable' LMBs
1380dfabd39SDavid Gibson * in response to a hot unplug request that is based on drc-count.
1390dfabd39SDavid Gibson * If the LMB being removed doesn't belong to a DIMM device that is
1400dfabd39SDavid Gibson * actually being unplugged, fail the isolation request here.
1410dfabd39SDavid Gibson */
1420dfabd39SDavid Gibson if (spapr_drc_type(drc) == SPAPR_DR_CONNECTOR_TYPE_LMB
143f1c52354SDavid Gibson && !drc->unplug_requested) {
1440dfabd39SDavid Gibson return RTAS_OUT_HW_ERROR;
1450dfabd39SDavid Gibson }
1460dfabd39SDavid Gibson
1479d4c0f4fSDavid Gibson drc->state = SPAPR_DRC_STATE_LOGICAL_AVAILABLE;
1480dfabd39SDavid Gibson
1490dfabd39SDavid Gibson return RTAS_OUT_SUCCESS;
1500dfabd39SDavid Gibson }
1510dfabd39SDavid Gibson
drc_unisolate_logical(SpaprDrc * drc)152ce2918cbSDavid Gibson static uint32_t drc_unisolate_logical(SpaprDrc *drc)
1530dfabd39SDavid Gibson {
15487758fedSDaniel Henrique Barboza SpaprMachineState *spapr = NULL;
15587758fedSDaniel Henrique Barboza
1569d4c0f4fSDavid Gibson switch (drc->state) {
1579d4c0f4fSDavid Gibson case SPAPR_DRC_STATE_LOGICAL_UNISOLATE:
1589d4c0f4fSDavid Gibson case SPAPR_DRC_STATE_LOGICAL_CONFIGURED:
15987758fedSDaniel Henrique Barboza /*
16087758fedSDaniel Henrique Barboza * Unisolating a logical DRC that was marked for unplug
16187758fedSDaniel Henrique Barboza * means that the kernel is refusing the removal.
16287758fedSDaniel Henrique Barboza */
16387758fedSDaniel Henrique Barboza if (drc->unplug_requested && drc->dev) {
16487758fedSDaniel Henrique Barboza if (spapr_drc_type(drc) == SPAPR_DR_CONNECTOR_TYPE_LMB) {
16587758fedSDaniel Henrique Barboza spapr = SPAPR_MACHINE(qdev_get_machine());
16687758fedSDaniel Henrique Barboza
16787758fedSDaniel Henrique Barboza spapr_memory_unplug_rollback(spapr, drc->dev);
16887758fedSDaniel Henrique Barboza }
16987758fedSDaniel Henrique Barboza
17087758fedSDaniel Henrique Barboza drc->unplug_requested = false;
17191bd95ceSDaniel Henrique Barboza
17291bd95ceSDaniel Henrique Barboza if (drc->dev->id) {
17387758fedSDaniel Henrique Barboza error_report("Device hotunplug rejected by the guest "
17487758fedSDaniel Henrique Barboza "for device %s", drc->dev->id);
17591bd95ceSDaniel Henrique Barboza }
17687758fedSDaniel Henrique Barboza
177047f2ca1SMarkus Armbruster qapi_event_send_device_unplug_guest_error(drc->dev->id,
1784b08cd56SDaniel Henrique Barboza drc->dev->canonical_path);
17987758fedSDaniel Henrique Barboza }
18087758fedSDaniel Henrique Barboza
1819d4c0f4fSDavid Gibson return RTAS_OUT_SUCCESS; /* Nothing to do */
1829d4c0f4fSDavid Gibson case SPAPR_DRC_STATE_LOGICAL_AVAILABLE:
1839d4c0f4fSDavid Gibson break; /* see below */
1849d4c0f4fSDavid Gibson case SPAPR_DRC_STATE_LOGICAL_UNUSABLE:
1859d4c0f4fSDavid Gibson return RTAS_OUT_NO_SUCH_INDICATOR; /* not allowed */
1869d4c0f4fSDavid Gibson default:
1879d4c0f4fSDavid Gibson g_assert_not_reached();
1880dfabd39SDavid Gibson }
1890dfabd39SDavid Gibson
1909d4c0f4fSDavid Gibson /* Move to AVAILABLE state should have ensured device was present */
1919d4c0f4fSDavid Gibson g_assert(drc->dev);
1920dfabd39SDavid Gibson
1939d4c0f4fSDavid Gibson drc->state = SPAPR_DRC_STATE_LOGICAL_UNISOLATE;
1944445b1d2SDavid Gibson drc->ccs_offset = drc->fdt_start_offset;
1954445b1d2SDavid Gibson drc->ccs_depth = 0;
1964445b1d2SDavid Gibson
1970cb688d2SMichael Roth return RTAS_OUT_SUCCESS;
198bbf5c878SMichael Roth }
199bbf5c878SMichael Roth
drc_set_usable(SpaprDrc * drc)200ce2918cbSDavid Gibson static uint32_t drc_set_usable(SpaprDrc *drc)
201bbf5c878SMichael Roth {
2029d4c0f4fSDavid Gibson switch (drc->state) {
2039d4c0f4fSDavid Gibson case SPAPR_DRC_STATE_LOGICAL_AVAILABLE:
2049d4c0f4fSDavid Gibson case SPAPR_DRC_STATE_LOGICAL_UNISOLATE:
2059d4c0f4fSDavid Gibson case SPAPR_DRC_STATE_LOGICAL_CONFIGURED:
2069d4c0f4fSDavid Gibson return RTAS_OUT_SUCCESS; /* Nothing to do */
2079d4c0f4fSDavid Gibson case SPAPR_DRC_STATE_LOGICAL_UNUSABLE:
2089d4c0f4fSDavid Gibson break; /* see below */
2099d4c0f4fSDavid Gibson default:
2109d4c0f4fSDavid Gibson g_assert_not_reached();
2119d4c0f4fSDavid Gibson }
2129d4c0f4fSDavid Gibson
2139d1852ceSMichael Roth /* if there's no resource/device associated with the DRC, there's
2149d1852ceSMichael Roth * no way for us to put it in an allocation state consistent with
2159d1852ceSMichael Roth * being 'USABLE'. PAPR 2.7, 13.5.3.4 documents that this should
2169d1852ceSMichael Roth * result in an RTAS return code of -3 / "no such indicator"
2179d1852ceSMichael Roth */
2189d1852ceSMichael Roth if (!drc->dev) {
2199d1852ceSMichael Roth return RTAS_OUT_NO_SUCH_INDICATOR;
2209d1852ceSMichael Roth }
221f1c52354SDavid Gibson if (drc->unplug_requested) {
22282a93a1dSDavid Gibson /* Don't allow the guest to move a device away from UNUSABLE
22382a93a1dSDavid Gibson * state when we want to unplug it */
22461736732SDavid Gibson return RTAS_OUT_NO_SUCH_INDICATOR;
2259d1852ceSMichael Roth }
2269d1852ceSMichael Roth
2279d4c0f4fSDavid Gibson drc->state = SPAPR_DRC_STATE_LOGICAL_AVAILABLE;
22861736732SDavid Gibson
22961736732SDavid Gibson return RTAS_OUT_SUCCESS;
23061736732SDavid Gibson }
23161736732SDavid Gibson
drc_set_unusable(SpaprDrc * drc)232ce2918cbSDavid Gibson static uint32_t drc_set_unusable(SpaprDrc *drc)
23361736732SDavid Gibson {
2349d4c0f4fSDavid Gibson switch (drc->state) {
2359d4c0f4fSDavid Gibson case SPAPR_DRC_STATE_LOGICAL_UNUSABLE:
2369d4c0f4fSDavid Gibson return RTAS_OUT_SUCCESS; /* Nothing to do */
2379d4c0f4fSDavid Gibson case SPAPR_DRC_STATE_LOGICAL_AVAILABLE:
2389d4c0f4fSDavid Gibson break; /* see below */
2399d4c0f4fSDavid Gibson case SPAPR_DRC_STATE_LOGICAL_UNISOLATE:
2409d4c0f4fSDavid Gibson case SPAPR_DRC_STATE_LOGICAL_CONFIGURED:
2419d4c0f4fSDavid Gibson return RTAS_OUT_NO_SUCH_INDICATOR; /* not allowed */
2429d4c0f4fSDavid Gibson default:
2439d4c0f4fSDavid Gibson g_assert_not_reached();
2449d4c0f4fSDavid Gibson }
2459d4c0f4fSDavid Gibson
2469d4c0f4fSDavid Gibson drc->state = SPAPR_DRC_STATE_LOGICAL_UNUSABLE;
247f1c52354SDavid Gibson if (drc->unplug_requested) {
2480b55aa91SDavid Gibson uint32_t drc_index = spapr_drc_index(drc);
2490b55aa91SDavid Gibson trace_spapr_drc_set_allocation_state_finalizing(drc_index);
25066d10d32SDaniel Henrique Barboza spapr_drc_release(drc);
251bbf5c878SMichael Roth }
25261736732SDavid Gibson
2530cb688d2SMichael Roth return RTAS_OUT_SUCCESS;
254bbf5c878SMichael Roth }
255bbf5c878SMichael Roth
spapr_drc_name(SpaprDrc * drc)256dbd26f2fSShivaprasad G Bhat static char *spapr_drc_name(SpaprDrc *drc)
257bbf5c878SMichael Roth {
258ce2918cbSDavid Gibson SpaprDrcClass *drck = SPAPR_DR_CONNECTOR_GET_CLASS(drc);
25979808336SDavid Gibson
26079808336SDavid Gibson /* human-readable name for a DRC to encode into the DT
26179808336SDavid Gibson * description. this is mainly only used within a guest in place
26279808336SDavid Gibson * of the unique DRC index.
26379808336SDavid Gibson *
26479808336SDavid Gibson * in the case of VIO/PCI devices, it corresponds to a "location
26579808336SDavid Gibson * code" that maps a logical device/function (DRC index) to a
26679808336SDavid Gibson * physical (or virtual in the case of VIO) location in the system
26779808336SDavid Gibson * by chaining together the "location label" for each
26879808336SDavid Gibson * encapsulating component.
26979808336SDavid Gibson *
27079808336SDavid Gibson * since this is more to do with diagnosing physical hardware
27179808336SDavid Gibson * issues than guest compatibility, we choose location codes/DRC
27279808336SDavid Gibson * names that adhere to the documented format, but avoid encoding
27379808336SDavid Gibson * the entire topology information into the label/code, instead
27479808336SDavid Gibson * just using the location codes based on the labels for the
27579808336SDavid Gibson * endpoints (VIO/PCI adaptor connectors), which is basically just
27679808336SDavid Gibson * "C" followed by an integer ID.
27779808336SDavid Gibson *
27879808336SDavid Gibson * DRC names as documented by PAPR+ v2.7, 13.5.2.4
27979808336SDavid Gibson * location codes as documented by PAPR+ v2.7, 12.3.1.5
28079808336SDavid Gibson */
28179808336SDavid Gibson return g_strdup_printf("%s%d", drck->drc_name_prefix, drc->id);
282bbf5c878SMichael Roth }
283bbf5c878SMichael Roth
284bbf5c878SMichael Roth /*
285bbf5c878SMichael Roth * dr-entity-sense sensor value
286bbf5c878SMichael Roth * returned via get-sensor-state RTAS calls
287bbf5c878SMichael Roth * as expected by state diagram in PAPR+ 2.7, 13.4
288bbf5c878SMichael Roth * based on the current allocation/indicator/power states
289bbf5c878SMichael Roth * for the DR connector.
290bbf5c878SMichael Roth */
physical_entity_sense(SpaprDrc * drc)291ce2918cbSDavid Gibson static SpaprDREntitySense physical_entity_sense(SpaprDrc *drc)
292bbf5c878SMichael Roth {
293f224d35bSDavid Gibson /* this assumes all PCI devices are assigned to a 'live insertion'
294f224d35bSDavid Gibson * power domain, where QEMU manages power state automatically as
295f224d35bSDavid Gibson * opposed to the guest. present, non-PCI resources are unaffected
296f224d35bSDavid Gibson * by power state.
297bbf5c878SMichael Roth */
298f224d35bSDavid Gibson return drc->dev ? SPAPR_DR_ENTITY_SENSE_PRESENT
299f224d35bSDavid Gibson : SPAPR_DR_ENTITY_SENSE_EMPTY;
300bbf5c878SMichael Roth }
301bbf5c878SMichael Roth
logical_entity_sense(SpaprDrc * drc)302ce2918cbSDavid Gibson static SpaprDREntitySense logical_entity_sense(SpaprDrc *drc)
303f224d35bSDavid Gibson {
3049d4c0f4fSDavid Gibson switch (drc->state) {
3059d4c0f4fSDavid Gibson case SPAPR_DRC_STATE_LOGICAL_UNUSABLE:
306f224d35bSDavid Gibson return SPAPR_DR_ENTITY_SENSE_UNUSABLE;
3079d4c0f4fSDavid Gibson case SPAPR_DRC_STATE_LOGICAL_AVAILABLE:
3089d4c0f4fSDavid Gibson case SPAPR_DRC_STATE_LOGICAL_UNISOLATE:
3099d4c0f4fSDavid Gibson case SPAPR_DRC_STATE_LOGICAL_CONFIGURED:
3109d4c0f4fSDavid Gibson g_assert(drc->dev);
3119d4c0f4fSDavid Gibson return SPAPR_DR_ENTITY_SENSE_PRESENT;
3129d4c0f4fSDavid Gibson default:
3139d4c0f4fSDavid Gibson g_assert_not_reached();
314f224d35bSDavid Gibson }
315bbf5c878SMichael Roth }
316bbf5c878SMichael Roth
prop_get_index(Object * obj,Visitor * v,const char * name,void * opaque,Error ** errp)317d7bce999SEric Blake static void prop_get_index(Object *obj, Visitor *v, const char *name,
318d7bce999SEric Blake void *opaque, Error **errp)
319bbf5c878SMichael Roth {
320ce2918cbSDavid Gibson SpaprDrc *drc = SPAPR_DR_CONNECTOR(obj);
3210b55aa91SDavid Gibson uint32_t value = spapr_drc_index(drc);
32251e72bc1SEric Blake visit_type_uint32(v, name, &value, errp);
323bbf5c878SMichael Roth }
324bbf5c878SMichael Roth
prop_get_fdt(Object * obj,Visitor * v,const char * name,void * opaque,Error ** errp)325d7bce999SEric Blake static void prop_get_fdt(Object *obj, Visitor *v, const char *name,
326d7bce999SEric Blake void *opaque, Error **errp)
327bbf5c878SMichael Roth {
328ce2918cbSDavid Gibson SpaprDrc *drc = SPAPR_DR_CONNECTOR(obj);
329d2f95f4dSMarkus Armbruster QNull *null = NULL;
330bbf5c878SMichael Roth int fdt_offset_next, fdt_offset, fdt_depth;
331bbf5c878SMichael Roth void *fdt;
332bbf5c878SMichael Roth
333bbf5c878SMichael Roth if (!drc->fdt) {
334d2f95f4dSMarkus Armbruster visit_type_null(v, NULL, &null, errp);
335cb3e7f08SMarc-André Lureau qobject_unref(null);
336bbf5c878SMichael Roth return;
337bbf5c878SMichael Roth }
338bbf5c878SMichael Roth
339bbf5c878SMichael Roth fdt = drc->fdt;
340bbf5c878SMichael Roth fdt_offset = drc->fdt_start_offset;
341bbf5c878SMichael Roth fdt_depth = 0;
342bbf5c878SMichael Roth
343bbf5c878SMichael Roth do {
3448cf52ff5SCédric Le Goater const char *dt_name = NULL;
345bbf5c878SMichael Roth const struct fdt_property *prop = NULL;
346bbf5c878SMichael Roth int prop_len = 0, name_len = 0;
347bbf5c878SMichael Roth uint32_t tag;
348ebd226d2SGreg Kurz bool ok;
349bbf5c878SMichael Roth
350bbf5c878SMichael Roth tag = fdt_next_tag(fdt, fdt_offset, &fdt_offset_next);
351bbf5c878SMichael Roth switch (tag) {
352bbf5c878SMichael Roth case FDT_BEGIN_NODE:
353bbf5c878SMichael Roth fdt_depth++;
3548cf52ff5SCédric Le Goater dt_name = fdt_get_name(fdt, fdt_offset, &name_len);
3558cf52ff5SCédric Le Goater if (!visit_start_struct(v, dt_name, NULL, 0, errp)) {
356c75304a1SMarkus Armbruster return;
357c75304a1SMarkus Armbruster }
358bbf5c878SMichael Roth break;
359bbf5c878SMichael Roth case FDT_END_NODE:
360bbf5c878SMichael Roth /* shouldn't ever see an FDT_END_NODE before FDT_BEGIN_NODE */
361bbf5c878SMichael Roth g_assert(fdt_depth > 0);
362ebd226d2SGreg Kurz ok = visit_check_struct(v, errp);
3631158bb2aSEric Blake visit_end_struct(v, NULL);
364ebd226d2SGreg Kurz if (!ok) {
365c75304a1SMarkus Armbruster return;
366c75304a1SMarkus Armbruster }
367bbf5c878SMichael Roth fdt_depth--;
368bbf5c878SMichael Roth break;
369bbf5c878SMichael Roth case FDT_PROP: {
370bbf5c878SMichael Roth int i;
371bbf5c878SMichael Roth prop = fdt_get_property_by_offset(fdt, fdt_offset, &prop_len);
3728cf52ff5SCédric Le Goater dt_name = fdt_string(fdt, fdt32_to_cpu(prop->nameoff));
3738cf52ff5SCédric Le Goater if (!visit_start_list(v, dt_name, NULL, 0, errp)) {
374c75304a1SMarkus Armbruster return;
375bbf5c878SMichael Roth }
376c75304a1SMarkus Armbruster for (i = 0; i < prop_len; i++) {
37762a35aaaSMarkus Armbruster if (!visit_type_uint8(v, NULL, (uint8_t *)&prop->data[i],
378668f62ecSMarkus Armbruster errp)) {
379c75304a1SMarkus Armbruster return;
380c75304a1SMarkus Armbruster }
381c75304a1SMarkus Armbruster }
382ebd226d2SGreg Kurz ok = visit_check_list(v, errp);
3831158bb2aSEric Blake visit_end_list(v, NULL);
384ebd226d2SGreg Kurz if (!ok) {
385a4a1c70dSMarkus Armbruster return;
386a4a1c70dSMarkus Armbruster }
387bbf5c878SMichael Roth break;
388bbf5c878SMichael Roth }
389bbf5c878SMichael Roth default:
390e20c6314SPhilippe Mathieu-Daudé error_report("device FDT in unexpected state: %d", tag);
391e20c6314SPhilippe Mathieu-Daudé abort();
392bbf5c878SMichael Roth }
393bbf5c878SMichael Roth fdt_offset = fdt_offset_next;
394bbf5c878SMichael Roth } while (fdt_depth != 0);
395bbf5c878SMichael Roth }
396bbf5c878SMichael Roth
spapr_drc_attach(SpaprDrc * drc,DeviceState * d)397bc370a65SGreg Kurz void spapr_drc_attach(SpaprDrc *drc, DeviceState *d)
398bbf5c878SMichael Roth {
3990b55aa91SDavid Gibson trace_spapr_drc_attach(spapr_drc_index(drc));
400bbf5c878SMichael Roth
401bc370a65SGreg Kurz g_assert(!drc->dev);
4029d4c0f4fSDavid Gibson g_assert((drc->state == SPAPR_DRC_STATE_LOGICAL_UNUSABLE)
4039d4c0f4fSDavid Gibson || (drc->state == SPAPR_DRC_STATE_PHYSICAL_POWERON));
404bbf5c878SMichael Roth
405bbf5c878SMichael Roth drc->dev = d;
406d9c95c71SGreg Kurz
407bbf5c878SMichael Roth object_property_add_link(OBJECT(drc), "device",
408bbf5c878SMichael Roth object_get_typename(OBJECT(drc->dev)),
409bbf5c878SMichael Roth (Object **)(&drc->dev),
410d2623129SMarkus Armbruster NULL, 0);
411bbf5c878SMichael Roth }
412bbf5c878SMichael Roth
spapr_drc_unplug_request(SpaprDrc * drc)413a03509cdSDaniel Henrique Barboza void spapr_drc_unplug_request(SpaprDrc *drc)
4149c914e53SDavid Gibson {
415ce2918cbSDavid Gibson SpaprDrcClass *drck = SPAPR_DR_CONNECTOR_GET_CLASS(drc);
4169d4c0f4fSDavid Gibson
417a03509cdSDaniel Henrique Barboza trace_spapr_drc_unplug_request(spapr_drc_index(drc));
4189c914e53SDavid Gibson
4199d4c0f4fSDavid Gibson g_assert(drc->dev);
4209d4c0f4fSDavid Gibson
421f1c52354SDavid Gibson drc->unplug_requested = true;
422a8dc47fdSDavid Gibson
4239d4c0f4fSDavid Gibson if (drc->state != drck->empty_state) {
4249d4c0f4fSDavid Gibson trace_spapr_drc_awaiting_quiesce(spapr_drc_index(drc));
4259c914e53SDavid Gibson return;
4269c914e53SDavid Gibson }
4279c914e53SDavid Gibson
4289c914e53SDavid Gibson spapr_drc_release(drc);
4299c914e53SDavid Gibson }
4309c914e53SDavid Gibson
spapr_drc_reset(SpaprDrc * drc)431930ef3b5SGreg Kurz bool spapr_drc_reset(SpaprDrc *drc)
432bbf5c878SMichael Roth {
433ce2918cbSDavid Gibson SpaprDrcClass *drck = SPAPR_DR_CONNECTOR_GET_CLASS(drc);
434930ef3b5SGreg Kurz bool unplug_completed = false;
4359d4c0f4fSDavid Gibson
4360b55aa91SDavid Gibson trace_spapr_drc_reset(spapr_drc_index(drc));
437b8fdd530SDavid Gibson
438bbf5c878SMichael Roth /* immediately upon reset we can safely assume DRCs whose devices
4394f9242fcSDavid Gibson * are pending removal can be safely removed.
440bbf5c878SMichael Roth */
441f1c52354SDavid Gibson if (drc->unplug_requested) {
4424f9242fcSDavid Gibson spapr_drc_release(drc);
443930ef3b5SGreg Kurz unplug_completed = true;
444bbf5c878SMichael Roth }
445bbf5c878SMichael Roth
4464f9242fcSDavid Gibson if (drc->dev) {
4479d4c0f4fSDavid Gibson /* A device present at reset is ready to go, same as coldplugged */
4489d4c0f4fSDavid Gibson drc->state = drck->ready_state;
449188bfe1bSBharata B Rao /*
450188bfe1bSBharata B Rao * Ensure that we are able to send the FDT fragment again
451188bfe1bSBharata B Rao * via configure-connector call if the guest requests.
452188bfe1bSBharata B Rao */
453188bfe1bSBharata B Rao drc->ccs_offset = drc->fdt_start_offset;
454188bfe1bSBharata B Rao drc->ccs_depth = 0;
4554f9242fcSDavid Gibson } else {
4569d4c0f4fSDavid Gibson drc->state = drck->empty_state;
4574445b1d2SDavid Gibson drc->ccs_offset = -1;
4584445b1d2SDavid Gibson drc->ccs_depth = -1;
459bbf5c878SMichael Roth }
460930ef3b5SGreg Kurz
461930ef3b5SGreg Kurz return unplug_completed;
462188bfe1bSBharata B Rao }
463bbf5c878SMichael Roth
spapr_drc_unplug_requested_needed(void * opaque)464ab858434SGreg Kurz static bool spapr_drc_unplug_requested_needed(void *opaque)
465ab858434SGreg Kurz {
466ab858434SGreg Kurz return spapr_drc_unplug_requested(opaque);
467ab858434SGreg Kurz }
468ab858434SGreg Kurz
469ab858434SGreg Kurz static const VMStateDescription vmstate_spapr_drc_unplug_requested = {
470ab858434SGreg Kurz .name = "spapr_drc/unplug_requested",
471ab858434SGreg Kurz .version_id = 1,
472ab858434SGreg Kurz .minimum_version_id = 1,
473ab858434SGreg Kurz .needed = spapr_drc_unplug_requested_needed,
474078ddbc9SRichard Henderson .fields = (const VMStateField []) {
475ab858434SGreg Kurz VMSTATE_BOOL(unplug_requested, SpaprDrc),
476ab858434SGreg Kurz VMSTATE_END_OF_LIST()
477ab858434SGreg Kurz }
478ab858434SGreg Kurz };
479ab858434SGreg Kurz
spapr_drc_needed(void * opaque)480cd725bd7SGreg Kurz static bool spapr_drc_needed(void *opaque)
481a50919ddSDaniel Henrique Barboza {
482cd725bd7SGreg Kurz SpaprDrc *drc = opaque;
483ce2918cbSDavid Gibson SpaprDrcClass *drck = SPAPR_DR_CONNECTOR_GET_CLASS(drc);
484a50919ddSDaniel Henrique Barboza
4854b63db12SGreg Kurz /*
4864b63db12SGreg Kurz * If no dev is plugged in there is no need to migrate the DRC state
4874b63db12SGreg Kurz * nor to reset the DRC at CAS.
4884b63db12SGreg Kurz */
489c618e300SDaniel Henrique Barboza if (!drc->dev) {
490a50919ddSDaniel Henrique Barboza return false;
491a50919ddSDaniel Henrique Barboza }
492a50919ddSDaniel Henrique Barboza
493a50919ddSDaniel Henrique Barboza /*
4944b63db12SGreg Kurz * We need to reset the DRC at CAS or to migrate the DRC state if it's
4954b63db12SGreg Kurz * not equal to the expected long-term state, which is the same as the
496ab858434SGreg Kurz * coldplugged initial state, or if an unplug request is pending.
4974b63db12SGreg Kurz */
498ab858434SGreg Kurz return drc->state != drck->ready_state ||
499ab858434SGreg Kurz spapr_drc_unplug_requested(drc);
500a50919ddSDaniel Henrique Barboza }
501a50919ddSDaniel Henrique Barboza
502a50919ddSDaniel Henrique Barboza static const VMStateDescription vmstate_spapr_drc = {
503a50919ddSDaniel Henrique Barboza .name = "spapr_drc",
504a50919ddSDaniel Henrique Barboza .version_id = 1,
505a50919ddSDaniel Henrique Barboza .minimum_version_id = 1,
506a50919ddSDaniel Henrique Barboza .needed = spapr_drc_needed,
507078ddbc9SRichard Henderson .fields = (const VMStateField []) {
508ce2918cbSDavid Gibson VMSTATE_UINT32(state, SpaprDrc),
509a50919ddSDaniel Henrique Barboza VMSTATE_END_OF_LIST()
510ab858434SGreg Kurz },
511078ddbc9SRichard Henderson .subsections = (const VMStateDescription * const []) {
512ab858434SGreg Kurz &vmstate_spapr_drc_unplug_requested,
513ab858434SGreg Kurz NULL
514a50919ddSDaniel Henrique Barboza }
515a50919ddSDaniel Henrique Barboza };
516a50919ddSDaniel Henrique Barboza
drc_container_create(void)5177c03a17cSPeter Xu static void drc_container_create(void)
5187c03a17cSPeter Xu {
5197c03a17cSPeter Xu object_property_add_new_container(object_get_root(), DRC_CONTAINER_PATH);
5207c03a17cSPeter Xu }
5217c03a17cSPeter Xu
drc_container_get(void)5227c03a17cSPeter Xu static Object *drc_container_get(void)
5237c03a17cSPeter Xu {
5247c03a17cSPeter Xu return object_resolve_path_component(object_get_root(), DRC_CONTAINER_PATH);
5257c03a17cSPeter Xu }
5267c03a17cSPeter Xu
drc_realize(DeviceState * d,Error ** errp)52700f46c92SGreg Kurz static void drc_realize(DeviceState *d, Error **errp)
528bbf5c878SMichael Roth {
529ce2918cbSDavid Gibson SpaprDrc *drc = SPAPR_DR_CONNECTOR(d);
53037deca77SDaniel Henrique Barboza g_autofree gchar *link_name = g_strdup_printf("%x", spapr_drc_index(drc));
531bbf5c878SMichael Roth Object *root_container;
5327a309cc9SMarkus Armbruster const char *child_name;
533bbf5c878SMichael Roth
5340b55aa91SDavid Gibson trace_spapr_drc_realize(spapr_drc_index(drc));
535bbf5c878SMichael Roth /* NOTE: we do this as part of realize/unrealize due to the fact
536bbf5c878SMichael Roth * that the guest will communicate with the DRC via RTAS calls
537bbf5c878SMichael Roth * referencing the global DRC index. By unlinking the DRC
538bbf5c878SMichael Roth * from DRC_CONTAINER_PATH/<drc_index> we effectively make it
539bbf5c878SMichael Roth * inaccessible by the guest, since lookups rely on this path
540bbf5c878SMichael Roth * existing in the composition tree
541bbf5c878SMichael Roth */
5427c03a17cSPeter Xu root_container = drc_container_get();
543bbf5c878SMichael Roth child_name = object_get_canonical_path_component(OBJECT(drc));
5440b55aa91SDavid Gibson trace_spapr_drc_realize_child(spapr_drc_index(drc), child_name);
545bbf5c878SMichael Roth object_property_add_alias(root_container, link_name,
546d2623129SMarkus Armbruster drc->owner, child_name);
5473cad405bSMarc-André Lureau vmstate_register(VMSTATE_IF(drc), spapr_drc_index(drc), &vmstate_spapr_drc,
548a50919ddSDaniel Henrique Barboza drc);
5490b55aa91SDavid Gibson trace_spapr_drc_realize_complete(spapr_drc_index(drc));
550bbf5c878SMichael Roth }
551bbf5c878SMichael Roth
drc_unrealize(DeviceState * d)55200f46c92SGreg Kurz static void drc_unrealize(DeviceState *d)
553bbf5c878SMichael Roth {
554ce2918cbSDavid Gibson SpaprDrc *drc = SPAPR_DR_CONNECTOR(d);
555ef2ece4aSDaniel Henrique Barboza g_autofree gchar *name = g_strdup_printf("%x", spapr_drc_index(drc));
556bbf5c878SMichael Roth
5570b55aa91SDavid Gibson trace_spapr_drc_unrealize(spapr_drc_index(drc));
5583cad405bSMarc-André Lureau vmstate_unregister(VMSTATE_IF(drc), &vmstate_spapr_drc, drc);
5597c03a17cSPeter Xu object_property_del(drc_container_get(), name);
560bbf5c878SMichael Roth }
561bbf5c878SMichael Roth
spapr_dr_connector_new(Object * owner,const char * type,uint32_t id)562ce2918cbSDavid Gibson SpaprDrc *spapr_dr_connector_new(Object *owner, const char *type,
563bbf5c878SMichael Roth uint32_t id)
564bbf5c878SMichael Roth {
565ce2918cbSDavid Gibson SpaprDrc *drc = SPAPR_DR_CONNECTOR(object_new(type));
5667614114eSDaniel Henrique Barboza g_autofree char *prop_name = NULL;
567bbf5c878SMichael Roth
568bbf5c878SMichael Roth drc->id = id;
569bbf5c878SMichael Roth drc->owner = owner;
5700b55aa91SDavid Gibson prop_name = g_strdup_printf("dr-connector[%"PRIu32"]",
5710b55aa91SDavid Gibson spapr_drc_index(drc));
572d2623129SMarkus Armbruster object_property_add_child(owner, prop_name, OBJECT(drc));
573f3f41030SMichael Roth object_unref(OBJECT(drc));
574ce189ab2SMarkus Armbruster qdev_realize(DEVICE(drc), NULL, NULL);
575bbf5c878SMichael Roth
576bbf5c878SMichael Roth return drc;
577bbf5c878SMichael Roth }
578bbf5c878SMichael Roth
spapr_dr_connector_instance_init(Object * obj)579bbf5c878SMichael Roth static void spapr_dr_connector_instance_init(Object *obj)
580bbf5c878SMichael Roth {
581ce2918cbSDavid Gibson SpaprDrc *drc = SPAPR_DR_CONNECTOR(obj);
582ce2918cbSDavid Gibson SpaprDrcClass *drck = SPAPR_DR_CONNECTOR_GET_CLASS(drc);
583bbf5c878SMichael Roth
584d2623129SMarkus Armbruster object_property_add_uint32_ptr(obj, "id", &drc->id, OBJ_PROP_FLAG_READ);
585bbf5c878SMichael Roth object_property_add(obj, "index", "uint32", prop_get_index,
586d2623129SMarkus Armbruster NULL, NULL, NULL);
587bbf5c878SMichael Roth object_property_add(obj, "fdt", "struct", prop_get_fdt,
588d2623129SMarkus Armbruster NULL, NULL, NULL);
5899d4c0f4fSDavid Gibson drc->state = drck->empty_state;
590bbf5c878SMichael Roth }
591bbf5c878SMichael Roth
spapr_dr_connector_class_init(ObjectClass * k,const void * data)592*12d1a768SPhilippe Mathieu-Daudé static void spapr_dr_connector_class_init(ObjectClass *k, const void *data)
593bbf5c878SMichael Roth {
594bbf5c878SMichael Roth DeviceClass *dk = DEVICE_CLASS(k);
595bbf5c878SMichael Roth
5967c03a17cSPeter Xu drc_container_create();
5977c03a17cSPeter Xu
59800f46c92SGreg Kurz dk->realize = drc_realize;
59900f46c92SGreg Kurz dk->unrealize = drc_unrealize;
600c401ae8cSMarkus Armbruster /*
601eaf1ffbeSGreg Kurz * Reason: DR connector needs to be wired to either the machine or to a
602eaf1ffbeSGreg Kurz * PHB in spapr_dr_connector_new().
603c401ae8cSMarkus Armbruster */
604e90f2a8cSEduardo Habkost dk->user_creatable = false;
605bbf5c878SMichael Roth }
606bbf5c878SMichael Roth
drc_physical_needed(void * opaque)60767fea71bSDavid Gibson static bool drc_physical_needed(void *opaque)
60867fea71bSDavid Gibson {
609ce2918cbSDavid Gibson SpaprDrcPhysical *drcp = (SpaprDrcPhysical *)opaque;
610ce2918cbSDavid Gibson SpaprDrc *drc = SPAPR_DR_CONNECTOR(drcp);
61167fea71bSDavid Gibson
61267fea71bSDavid Gibson if ((drc->dev && (drcp->dr_indicator == SPAPR_DR_INDICATOR_ACTIVE))
61367fea71bSDavid Gibson || (!drc->dev && (drcp->dr_indicator == SPAPR_DR_INDICATOR_INACTIVE))) {
61467fea71bSDavid Gibson return false;
61567fea71bSDavid Gibson }
61667fea71bSDavid Gibson return true;
61767fea71bSDavid Gibson }
61867fea71bSDavid Gibson
61967fea71bSDavid Gibson static const VMStateDescription vmstate_spapr_drc_physical = {
62067fea71bSDavid Gibson .name = "spapr_drc/physical",
62167fea71bSDavid Gibson .version_id = 1,
62267fea71bSDavid Gibson .minimum_version_id = 1,
62367fea71bSDavid Gibson .needed = drc_physical_needed,
624078ddbc9SRichard Henderson .fields = (const VMStateField []) {
625ce2918cbSDavid Gibson VMSTATE_UINT32(dr_indicator, SpaprDrcPhysical),
62667fea71bSDavid Gibson VMSTATE_END_OF_LIST()
62767fea71bSDavid Gibson }
62867fea71bSDavid Gibson };
62967fea71bSDavid Gibson
drc_physical_reset(void * opaque)63067fea71bSDavid Gibson static void drc_physical_reset(void *opaque)
63167fea71bSDavid Gibson {
632ce2918cbSDavid Gibson SpaprDrc *drc = SPAPR_DR_CONNECTOR(opaque);
633ce2918cbSDavid Gibson SpaprDrcPhysical *drcp = SPAPR_DRC_PHYSICAL(drc);
63467fea71bSDavid Gibson
63567fea71bSDavid Gibson if (drc->dev) {
63667fea71bSDavid Gibson drcp->dr_indicator = SPAPR_DR_INDICATOR_ACTIVE;
63767fea71bSDavid Gibson } else {
63867fea71bSDavid Gibson drcp->dr_indicator = SPAPR_DR_INDICATOR_INACTIVE;
63967fea71bSDavid Gibson }
64067fea71bSDavid Gibson }
64167fea71bSDavid Gibson
realize_physical(DeviceState * d,Error ** errp)64267fea71bSDavid Gibson static void realize_physical(DeviceState *d, Error **errp)
64367fea71bSDavid Gibson {
644ce2918cbSDavid Gibson SpaprDrcPhysical *drcp = SPAPR_DRC_PHYSICAL(d);
64567fea71bSDavid Gibson Error *local_err = NULL;
64667fea71bSDavid Gibson
64700f46c92SGreg Kurz drc_realize(d, &local_err);
64867fea71bSDavid Gibson if (local_err) {
64967fea71bSDavid Gibson error_propagate(errp, local_err);
65067fea71bSDavid Gibson return;
65167fea71bSDavid Gibson }
65267fea71bSDavid Gibson
6533cad405bSMarc-André Lureau vmstate_register(VMSTATE_IF(drcp),
6543cad405bSMarc-André Lureau spapr_drc_index(SPAPR_DR_CONNECTOR(drcp)),
65567fea71bSDavid Gibson &vmstate_spapr_drc_physical, drcp);
65667fea71bSDavid Gibson qemu_register_reset(drc_physical_reset, drcp);
65767fea71bSDavid Gibson }
65867fea71bSDavid Gibson
unrealize_physical(DeviceState * d)659b69c3c21SMarkus Armbruster static void unrealize_physical(DeviceState *d)
660379ae096SGreg Kurz {
661ce2918cbSDavid Gibson SpaprDrcPhysical *drcp = SPAPR_DRC_PHYSICAL(d);
662379ae096SGreg Kurz
66300f46c92SGreg Kurz drc_unrealize(d);
6643cad405bSMarc-André Lureau vmstate_unregister(VMSTATE_IF(drcp), &vmstate_spapr_drc_physical, drcp);
665379ae096SGreg Kurz qemu_unregister_reset(drc_physical_reset, drcp);
666379ae096SGreg Kurz }
667379ae096SGreg Kurz
spapr_drc_physical_class_init(ObjectClass * k,const void * data)668*12d1a768SPhilippe Mathieu-Daudé static void spapr_drc_physical_class_init(ObjectClass *k, const void *data)
669f224d35bSDavid Gibson {
67067fea71bSDavid Gibson DeviceClass *dk = DEVICE_CLASS(k);
671ce2918cbSDavid Gibson SpaprDrcClass *drck = SPAPR_DR_CONNECTOR_CLASS(k);
672f224d35bSDavid Gibson
67367fea71bSDavid Gibson dk->realize = realize_physical;
674379ae096SGreg Kurz dk->unrealize = unrealize_physical;
675f224d35bSDavid Gibson drck->dr_entity_sense = physical_entity_sense;
6760dfabd39SDavid Gibson drck->isolate = drc_isolate_physical;
6770dfabd39SDavid Gibson drck->unisolate = drc_unisolate_physical;
6789d4c0f4fSDavid Gibson drck->ready_state = SPAPR_DRC_STATE_PHYSICAL_CONFIGURED;
6799d4c0f4fSDavid Gibson drck->empty_state = SPAPR_DRC_STATE_PHYSICAL_POWERON;
680f224d35bSDavid Gibson }
681f224d35bSDavid Gibson
spapr_drc_logical_class_init(ObjectClass * k,const void * data)682*12d1a768SPhilippe Mathieu-Daudé static void spapr_drc_logical_class_init(ObjectClass *k, const void *data)
683f224d35bSDavid Gibson {
684ce2918cbSDavid Gibson SpaprDrcClass *drck = SPAPR_DR_CONNECTOR_CLASS(k);
685f224d35bSDavid Gibson
686f224d35bSDavid Gibson drck->dr_entity_sense = logical_entity_sense;
6870dfabd39SDavid Gibson drck->isolate = drc_isolate_logical;
6880dfabd39SDavid Gibson drck->unisolate = drc_unisolate_logical;
6899d4c0f4fSDavid Gibson drck->ready_state = SPAPR_DRC_STATE_LOGICAL_CONFIGURED;
6909d4c0f4fSDavid Gibson drck->empty_state = SPAPR_DRC_STATE_LOGICAL_UNUSABLE;
691f224d35bSDavid Gibson }
692f224d35bSDavid Gibson
spapr_drc_cpu_class_init(ObjectClass * k,const void * data)693*12d1a768SPhilippe Mathieu-Daudé static void spapr_drc_cpu_class_init(ObjectClass *k, const void *data)
6942d335818SDavid Gibson {
695ce2918cbSDavid Gibson SpaprDrcClass *drck = SPAPR_DR_CONNECTOR_CLASS(k);
6962d335818SDavid Gibson
6972d335818SDavid Gibson drck->typeshift = SPAPR_DR_CONNECTOR_TYPE_SHIFT_CPU;
6981693ea16SDavid Gibson drck->typename = "CPU";
69979808336SDavid Gibson drck->drc_name_prefix = "CPU ";
7006b762f29SDavid Gibson drck->release = spapr_core_release;
701345b12b9SGreg Kurz drck->dt_populate = spapr_core_dt_populate;
7022d335818SDavid Gibson }
7032d335818SDavid Gibson
spapr_drc_pci_class_init(ObjectClass * k,const void * data)704*12d1a768SPhilippe Mathieu-Daudé static void spapr_drc_pci_class_init(ObjectClass *k, const void *data)
7052d335818SDavid Gibson {
706ce2918cbSDavid Gibson SpaprDrcClass *drck = SPAPR_DR_CONNECTOR_CLASS(k);
7072d335818SDavid Gibson
7082d335818SDavid Gibson drck->typeshift = SPAPR_DR_CONNECTOR_TYPE_SHIFT_PCI;
7091693ea16SDavid Gibson drck->typename = "28";
71079808336SDavid Gibson drck->drc_name_prefix = "C";
7116b762f29SDavid Gibson drck->release = spapr_phb_remove_pci_device_cb;
71246fd0299SGreg Kurz drck->dt_populate = spapr_pci_dt_populate;
7132d335818SDavid Gibson }
7142d335818SDavid Gibson
spapr_drc_lmb_class_init(ObjectClass * k,const void * data)715*12d1a768SPhilippe Mathieu-Daudé static void spapr_drc_lmb_class_init(ObjectClass *k, const void *data)
7162d335818SDavid Gibson {
717ce2918cbSDavid Gibson SpaprDrcClass *drck = SPAPR_DR_CONNECTOR_CLASS(k);
7182d335818SDavid Gibson
7192d335818SDavid Gibson drck->typeshift = SPAPR_DR_CONNECTOR_TYPE_SHIFT_LMB;
7201693ea16SDavid Gibson drck->typename = "MEM";
72179808336SDavid Gibson drck->drc_name_prefix = "LMB ";
7226b762f29SDavid Gibson drck->release = spapr_lmb_release;
72362d38c9bSGreg Kurz drck->dt_populate = spapr_lmb_dt_populate;
7242d335818SDavid Gibson }
7252d335818SDavid Gibson
spapr_drc_phb_class_init(ObjectClass * k,const void * data)726*12d1a768SPhilippe Mathieu-Daudé static void spapr_drc_phb_class_init(ObjectClass *k, const void *data)
727962b6c36SMichael Roth {
728ce2918cbSDavid Gibson SpaprDrcClass *drck = SPAPR_DR_CONNECTOR_CLASS(k);
729962b6c36SMichael Roth
730962b6c36SMichael Roth drck->typeshift = SPAPR_DR_CONNECTOR_TYPE_SHIFT_PHB;
731962b6c36SMichael Roth drck->typename = "PHB";
732962b6c36SMichael Roth drck->drc_name_prefix = "PHB ";
733bb2bdd81SGreg Kurz drck->release = spapr_phb_release;
734bb2bdd81SGreg Kurz drck->dt_populate = spapr_phb_dt_populate;
735962b6c36SMichael Roth }
736962b6c36SMichael Roth
spapr_drc_pmem_class_init(ObjectClass * k,const void * data)737*12d1a768SPhilippe Mathieu-Daudé static void spapr_drc_pmem_class_init(ObjectClass *k, const void *data)
738ee3a71e3SShivaprasad G Bhat {
739ee3a71e3SShivaprasad G Bhat SpaprDrcClass *drck = SPAPR_DR_CONNECTOR_CLASS(k);
740ee3a71e3SShivaprasad G Bhat
741ee3a71e3SShivaprasad G Bhat drck->typeshift = SPAPR_DR_CONNECTOR_TYPE_SHIFT_PMEM;
742ee3a71e3SShivaprasad G Bhat drck->typename = "PMEM";
743ee3a71e3SShivaprasad G Bhat drck->drc_name_prefix = "PMEM ";
744ee3a71e3SShivaprasad G Bhat drck->release = NULL;
745ee3a71e3SShivaprasad G Bhat drck->dt_populate = spapr_pmem_dt_populate;
746ee3a71e3SShivaprasad G Bhat }
747ee3a71e3SShivaprasad G Bhat
748bbf5c878SMichael Roth static const TypeInfo spapr_dr_connector_info = {
749bbf5c878SMichael Roth .name = TYPE_SPAPR_DR_CONNECTOR,
750bbf5c878SMichael Roth .parent = TYPE_DEVICE,
751ce2918cbSDavid Gibson .instance_size = sizeof(SpaprDrc),
752bbf5c878SMichael Roth .instance_init = spapr_dr_connector_instance_init,
753ce2918cbSDavid Gibson .class_size = sizeof(SpaprDrcClass),
754bbf5c878SMichael Roth .class_init = spapr_dr_connector_class_init,
7552d335818SDavid Gibson .abstract = true,
7562d335818SDavid Gibson };
7572d335818SDavid Gibson
7582d335818SDavid Gibson static const TypeInfo spapr_drc_physical_info = {
7592d335818SDavid Gibson .name = TYPE_SPAPR_DRC_PHYSICAL,
7602d335818SDavid Gibson .parent = TYPE_SPAPR_DR_CONNECTOR,
761ce2918cbSDavid Gibson .instance_size = sizeof(SpaprDrcPhysical),
762f224d35bSDavid Gibson .class_init = spapr_drc_physical_class_init,
7632d335818SDavid Gibson .abstract = true,
7642d335818SDavid Gibson };
7652d335818SDavid Gibson
7662d335818SDavid Gibson static const TypeInfo spapr_drc_logical_info = {
7672d335818SDavid Gibson .name = TYPE_SPAPR_DRC_LOGICAL,
7682d335818SDavid Gibson .parent = TYPE_SPAPR_DR_CONNECTOR,
769f224d35bSDavid Gibson .class_init = spapr_drc_logical_class_init,
7702d335818SDavid Gibson .abstract = true,
7712d335818SDavid Gibson };
7722d335818SDavid Gibson
7732d335818SDavid Gibson static const TypeInfo spapr_drc_cpu_info = {
7742d335818SDavid Gibson .name = TYPE_SPAPR_DRC_CPU,
7752d335818SDavid Gibson .parent = TYPE_SPAPR_DRC_LOGICAL,
7762d335818SDavid Gibson .class_init = spapr_drc_cpu_class_init,
7772d335818SDavid Gibson };
7782d335818SDavid Gibson
7792d335818SDavid Gibson static const TypeInfo spapr_drc_pci_info = {
7802d335818SDavid Gibson .name = TYPE_SPAPR_DRC_PCI,
7812d335818SDavid Gibson .parent = TYPE_SPAPR_DRC_PHYSICAL,
7822d335818SDavid Gibson .class_init = spapr_drc_pci_class_init,
7832d335818SDavid Gibson };
7842d335818SDavid Gibson
7852d335818SDavid Gibson static const TypeInfo spapr_drc_lmb_info = {
7862d335818SDavid Gibson .name = TYPE_SPAPR_DRC_LMB,
7872d335818SDavid Gibson .parent = TYPE_SPAPR_DRC_LOGICAL,
7882d335818SDavid Gibson .class_init = spapr_drc_lmb_class_init,
789bbf5c878SMichael Roth };
790bbf5c878SMichael Roth
791962b6c36SMichael Roth static const TypeInfo spapr_drc_phb_info = {
792962b6c36SMichael Roth .name = TYPE_SPAPR_DRC_PHB,
793962b6c36SMichael Roth .parent = TYPE_SPAPR_DRC_LOGICAL,
794ce2918cbSDavid Gibson .instance_size = sizeof(SpaprDrc),
795962b6c36SMichael Roth .class_init = spapr_drc_phb_class_init,
796962b6c36SMichael Roth };
797962b6c36SMichael Roth
798ee3a71e3SShivaprasad G Bhat static const TypeInfo spapr_drc_pmem_info = {
799ee3a71e3SShivaprasad G Bhat .name = TYPE_SPAPR_DRC_PMEM,
800ee3a71e3SShivaprasad G Bhat .parent = TYPE_SPAPR_DRC_LOGICAL,
801ee3a71e3SShivaprasad G Bhat .class_init = spapr_drc_pmem_class_init,
802ee3a71e3SShivaprasad G Bhat };
803ee3a71e3SShivaprasad G Bhat
804bbf5c878SMichael Roth /* helper functions for external users */
805bbf5c878SMichael Roth
spapr_drc_by_index(uint32_t index)806ce2918cbSDavid Gibson SpaprDrc *spapr_drc_by_index(uint32_t index)
807bbf5c878SMichael Roth {
808bbf5c878SMichael Roth Object *obj;
8097c03a17cSPeter Xu g_autofree gchar *name = g_strdup_printf("%x", index);
8107c03a17cSPeter Xu obj = object_resolve_path_component(drc_container_get(), name);
811bbf5c878SMichael Roth
812bbf5c878SMichael Roth return !obj ? NULL : SPAPR_DR_CONNECTOR(obj);
813bbf5c878SMichael Roth }
814bbf5c878SMichael Roth
spapr_drc_by_id(const char * type,uint32_t id)815ce2918cbSDavid Gibson SpaprDrc *spapr_drc_by_id(const char *type, uint32_t id)
816bbf5c878SMichael Roth {
817ce2918cbSDavid Gibson SpaprDrcClass *drck
818fbf55397SDavid Gibson = SPAPR_DR_CONNECTOR_CLASS(object_class_by_name(type));
819fbf55397SDavid Gibson
820fbf55397SDavid Gibson return spapr_drc_by_index(drck->typeshift << DRC_INDEX_TYPE_SHIFT
821fbf55397SDavid Gibson | (id & DRC_INDEX_ID_MASK));
822bbf5c878SMichael Roth }
823e4b798bbSMichael Roth
824e4b798bbSMichael Roth /**
8259e7d38e8SDavid Gibson * spapr_dt_drc
826e4b798bbSMichael Roth *
827e4b798bbSMichael Roth * @fdt: libfdt device tree
828e4b798bbSMichael Roth * @path: path in the DT to generate properties
829e4b798bbSMichael Roth * @owner: parent Object/DeviceState for which to generate DRC
830e4b798bbSMichael Roth * descriptions for
831ce2918cbSDavid Gibson * @drc_type_mask: mask of SpaprDrcType values corresponding
832e4b798bbSMichael Roth * to the types of DRCs to generate entries for
833e4b798bbSMichael Roth *
834e4b798bbSMichael Roth * generate OF properties to describe DRC topology/indices to guests
835e4b798bbSMichael Roth *
836e4b798bbSMichael Roth * as documented in PAPR+ v2.1, 13.5.2
837e4b798bbSMichael Roth */
spapr_dt_drc(void * fdt,int offset,Object * owner,uint32_t drc_type_mask)8389e7d38e8SDavid Gibson int spapr_dt_drc(void *fdt, int offset, Object *owner, uint32_t drc_type_mask)
839e4b798bbSMichael Roth {
840e4b798bbSMichael Roth Object *root_container;
841e4b798bbSMichael Roth ObjectProperty *prop;
8427746abd8SDaniel P. Berrange ObjectPropertyIterator iter;
843e4b798bbSMichael Roth uint32_t drc_count = 0;
84475610acfSDaniel Henrique Barboza g_autoptr(GArray) drc_indexes = g_array_new(false, true,
84575610acfSDaniel Henrique Barboza sizeof(uint32_t));
84675610acfSDaniel Henrique Barboza g_autoptr(GArray) drc_power_domains = g_array_new(false, true,
84775610acfSDaniel Henrique Barboza sizeof(uint32_t));
84875610acfSDaniel Henrique Barboza g_autoptr(GString) drc_names = g_string_set_size(g_string_new(NULL),
84975610acfSDaniel Henrique Barboza sizeof(uint32_t));
85075610acfSDaniel Henrique Barboza g_autoptr(GString) drc_types = g_string_set_size(g_string_new(NULL),
85175610acfSDaniel Henrique Barboza sizeof(uint32_t));
852e4b798bbSMichael Roth int ret;
853e4b798bbSMichael Roth
854776e887fSGreg Kurz /*
855776e887fSGreg Kurz * This should really be only called once per node since it overwrites
856776e887fSGreg Kurz * the OF properties if they already exist.
857776e887fSGreg Kurz */
858776e887fSGreg Kurz g_assert(!fdt_get_property(fdt, offset, "ibm,drc-indexes", NULL));
859776e887fSGreg Kurz
860e4b798bbSMichael Roth /* the first entry of each properties is a 32-bit integer encoding
861e4b798bbSMichael Roth * the number of elements in the array. we won't know this until
862e4b798bbSMichael Roth * we complete the iteration through all the matching DRCs, but
863e4b798bbSMichael Roth * reserve the space now and set the offsets accordingly so we
864e4b798bbSMichael Roth * can fill them in later.
865e4b798bbSMichael Roth */
866e4b798bbSMichael Roth drc_indexes = g_array_set_size(drc_indexes, 1);
867e4b798bbSMichael Roth drc_power_domains = g_array_set_size(drc_power_domains, 1);
868e4b798bbSMichael Roth
869e4b798bbSMichael Roth /* aliases for all DRConnector objects will be rooted in QOM
870e4b798bbSMichael Roth * composition tree at DRC_CONTAINER_PATH
871e4b798bbSMichael Roth */
8727c03a17cSPeter Xu root_container = drc_container_get();
873e4b798bbSMichael Roth
8747746abd8SDaniel P. Berrange object_property_iter_init(&iter, root_container);
8757746abd8SDaniel P. Berrange while ((prop = object_property_iter_next(&iter))) {
876e4b798bbSMichael Roth Object *obj;
877ce2918cbSDavid Gibson SpaprDrc *drc;
878ce2918cbSDavid Gibson SpaprDrcClass *drck;
87975610acfSDaniel Henrique Barboza g_autofree char *drc_name = NULL;
880e4b798bbSMichael Roth uint32_t drc_index, drc_power_domain;
881e4b798bbSMichael Roth
882e4b798bbSMichael Roth if (!strstart(prop->type, "link<", NULL)) {
883e4b798bbSMichael Roth continue;
884e4b798bbSMichael Roth }
885e4b798bbSMichael Roth
886552d7f49SMarkus Armbruster obj = object_property_get_link(root_container, prop->name,
887552d7f49SMarkus Armbruster &error_abort);
888e4b798bbSMichael Roth drc = SPAPR_DR_CONNECTOR(obj);
889e4b798bbSMichael Roth drck = SPAPR_DR_CONNECTOR_GET_CLASS(drc);
890e4b798bbSMichael Roth
891e4b798bbSMichael Roth if (owner && (drc->owner != owner)) {
892e4b798bbSMichael Roth continue;
893e4b798bbSMichael Roth }
894e4b798bbSMichael Roth
8952d335818SDavid Gibson if ((spapr_drc_type(drc) & drc_type_mask) == 0) {
896e4b798bbSMichael Roth continue;
897e4b798bbSMichael Roth }
898e4b798bbSMichael Roth
899e4b798bbSMichael Roth drc_count++;
900e4b798bbSMichael Roth
901e4b798bbSMichael Roth /* ibm,drc-indexes */
9020b55aa91SDavid Gibson drc_index = cpu_to_be32(spapr_drc_index(drc));
903e4b798bbSMichael Roth g_array_append_val(drc_indexes, drc_index);
904e4b798bbSMichael Roth
905e4b798bbSMichael Roth /* ibm,drc-power-domains */
906e4b798bbSMichael Roth drc_power_domain = cpu_to_be32(-1);
907e4b798bbSMichael Roth g_array_append_val(drc_power_domains, drc_power_domain);
908e4b798bbSMichael Roth
909e4b798bbSMichael Roth /* ibm,drc-names */
910dbd26f2fSShivaprasad G Bhat drc_name = spapr_drc_name(drc);
911dbd26f2fSShivaprasad G Bhat drc_names = g_string_append(drc_names, drc_name);
912e4b798bbSMichael Roth drc_names = g_string_insert_len(drc_names, -1, "\0", 1);
913e4b798bbSMichael Roth
914e4b798bbSMichael Roth /* ibm,drc-types */
9151693ea16SDavid Gibson drc_types = g_string_append(drc_types, drck->typename);
916e4b798bbSMichael Roth drc_types = g_string_insert_len(drc_types, -1, "\0", 1);
917e4b798bbSMichael Roth }
918e4b798bbSMichael Roth
919e4b798bbSMichael Roth /* now write the drc count into the space we reserved at the
920e4b798bbSMichael Roth * beginning of the arrays previously
921e4b798bbSMichael Roth */
922e4b798bbSMichael Roth *(uint32_t *)drc_indexes->data = cpu_to_be32(drc_count);
923e4b798bbSMichael Roth *(uint32_t *)drc_power_domains->data = cpu_to_be32(drc_count);
924e4b798bbSMichael Roth *(uint32_t *)drc_names->str = cpu_to_be32(drc_count);
925e4b798bbSMichael Roth *(uint32_t *)drc_types->str = cpu_to_be32(drc_count);
926e4b798bbSMichael Roth
9279e7d38e8SDavid Gibson ret = fdt_setprop(fdt, offset, "ibm,drc-indexes",
928e4b798bbSMichael Roth drc_indexes->data,
929e4b798bbSMichael Roth drc_indexes->len * sizeof(uint32_t));
930e4b798bbSMichael Roth if (ret) {
931ce9863b7SCédric Le Goater error_report("Couldn't create ibm,drc-indexes property");
93275610acfSDaniel Henrique Barboza return ret;
933e4b798bbSMichael Roth }
934e4b798bbSMichael Roth
9359e7d38e8SDavid Gibson ret = fdt_setprop(fdt, offset, "ibm,drc-power-domains",
936e4b798bbSMichael Roth drc_power_domains->data,
937e4b798bbSMichael Roth drc_power_domains->len * sizeof(uint32_t));
938e4b798bbSMichael Roth if (ret) {
939ce9863b7SCédric Le Goater error_report("Couldn't finalize ibm,drc-power-domains property");
94075610acfSDaniel Henrique Barboza return ret;
941e4b798bbSMichael Roth }
942e4b798bbSMichael Roth
9439e7d38e8SDavid Gibson ret = fdt_setprop(fdt, offset, "ibm,drc-names",
944e4b798bbSMichael Roth drc_names->str, drc_names->len);
945e4b798bbSMichael Roth if (ret) {
946ce9863b7SCédric Le Goater error_report("Couldn't finalize ibm,drc-names property");
94775610acfSDaniel Henrique Barboza return ret;
948e4b798bbSMichael Roth }
949e4b798bbSMichael Roth
9509e7d38e8SDavid Gibson ret = fdt_setprop(fdt, offset, "ibm,drc-types",
951e4b798bbSMichael Roth drc_types->str, drc_types->len);
952e4b798bbSMichael Roth if (ret) {
953ce9863b7SCédric Le Goater error_report("Couldn't finalize ibm,drc-types property");
954e4b798bbSMichael Roth }
955e4b798bbSMichael Roth
956e4b798bbSMichael Roth return ret;
957e4b798bbSMichael Roth }
958b89b3d39SDavid Gibson
spapr_drc_reset_all(SpaprMachineState * spapr)959babb819fSGreg Kurz void spapr_drc_reset_all(SpaprMachineState *spapr)
960babb819fSGreg Kurz {
961babb819fSGreg Kurz Object *drc_container;
962babb819fSGreg Kurz ObjectProperty *prop;
963babb819fSGreg Kurz ObjectPropertyIterator iter;
964babb819fSGreg Kurz
9657c03a17cSPeter Xu drc_container = drc_container_get();
966babb819fSGreg Kurz restart:
967babb819fSGreg Kurz object_property_iter_init(&iter, drc_container);
968babb819fSGreg Kurz while ((prop = object_property_iter_next(&iter))) {
969babb819fSGreg Kurz SpaprDrc *drc;
970babb819fSGreg Kurz
971babb819fSGreg Kurz if (!strstart(prop->type, "link<", NULL)) {
972babb819fSGreg Kurz continue;
973babb819fSGreg Kurz }
974babb819fSGreg Kurz drc = SPAPR_DR_CONNECTOR(object_property_get_link(drc_container,
975babb819fSGreg Kurz prop->name,
976babb819fSGreg Kurz &error_abort));
977babb819fSGreg Kurz
978babb819fSGreg Kurz /*
979babb819fSGreg Kurz * This will complete any pending plug/unplug requests.
980babb819fSGreg Kurz * In case of a unplugged PHB or PCI bridge, this will
981babb819fSGreg Kurz * cause some DRCs to be destroyed and thus potentially
982babb819fSGreg Kurz * invalidate the iterator.
983babb819fSGreg Kurz */
984babb819fSGreg Kurz if (spapr_drc_reset(drc)) {
985babb819fSGreg Kurz goto restart;
986babb819fSGreg Kurz }
987babb819fSGreg Kurz }
988babb819fSGreg Kurz }
989babb819fSGreg Kurz
990b89b3d39SDavid Gibson /*
991b89b3d39SDavid Gibson * RTAS calls
992b89b3d39SDavid Gibson */
993b89b3d39SDavid Gibson
rtas_set_isolation_state(uint32_t idx,uint32_t state)9947b7258f8SDavid Gibson static uint32_t rtas_set_isolation_state(uint32_t idx, uint32_t state)
995b89b3d39SDavid Gibson {
996ce2918cbSDavid Gibson SpaprDrc *drc = spapr_drc_by_index(idx);
997ce2918cbSDavid Gibson SpaprDrcClass *drck;
9987b7258f8SDavid Gibson
9997b7258f8SDavid Gibson if (!drc) {
10000dfabd39SDavid Gibson return RTAS_OUT_NO_SUCH_INDICATOR;
1001b89b3d39SDavid Gibson }
1002b89b3d39SDavid Gibson
10030dfabd39SDavid Gibson trace_spapr_drc_set_isolation_state(spapr_drc_index(drc), state);
10040dfabd39SDavid Gibson
10057b7258f8SDavid Gibson drck = SPAPR_DR_CONNECTOR_GET_CLASS(drc);
10060dfabd39SDavid Gibson
10070dfabd39SDavid Gibson switch (state) {
10080dfabd39SDavid Gibson case SPAPR_DR_ISOLATION_STATE_ISOLATED:
10090dfabd39SDavid Gibson return drck->isolate(drc);
10100dfabd39SDavid Gibson
10110dfabd39SDavid Gibson case SPAPR_DR_ISOLATION_STATE_UNISOLATED:
10120dfabd39SDavid Gibson return drck->unisolate(drc);
10130dfabd39SDavid Gibson
10140dfabd39SDavid Gibson default:
10150dfabd39SDavid Gibson return RTAS_OUT_PARAM_ERROR;
10160dfabd39SDavid Gibson }
10177b7258f8SDavid Gibson }
10187b7258f8SDavid Gibson
rtas_set_allocation_state(uint32_t idx,uint32_t state)10197b7258f8SDavid Gibson static uint32_t rtas_set_allocation_state(uint32_t idx, uint32_t state)
10207b7258f8SDavid Gibson {
1021ce2918cbSDavid Gibson SpaprDrc *drc = spapr_drc_by_index(idx);
10227b7258f8SDavid Gibson
102361736732SDavid Gibson if (!drc || !object_dynamic_cast(OBJECT(drc), TYPE_SPAPR_DRC_LOGICAL)) {
102461736732SDavid Gibson return RTAS_OUT_NO_SUCH_INDICATOR;
10257b7258f8SDavid Gibson }
10267b7258f8SDavid Gibson
102761736732SDavid Gibson trace_spapr_drc_set_allocation_state(spapr_drc_index(drc), state);
102861736732SDavid Gibson
102961736732SDavid Gibson switch (state) {
103061736732SDavid Gibson case SPAPR_DR_ALLOCATION_STATE_USABLE:
103161736732SDavid Gibson return drc_set_usable(drc);
103261736732SDavid Gibson
103361736732SDavid Gibson case SPAPR_DR_ALLOCATION_STATE_UNUSABLE:
103461736732SDavid Gibson return drc_set_unusable(drc);
103561736732SDavid Gibson
103661736732SDavid Gibson default:
103761736732SDavid Gibson return RTAS_OUT_PARAM_ERROR;
103861736732SDavid Gibson }
10397b7258f8SDavid Gibson }
10407b7258f8SDavid Gibson
rtas_set_dr_indicator(uint32_t idx,uint32_t state)1041cd74d27eSDavid Gibson static uint32_t rtas_set_dr_indicator(uint32_t idx, uint32_t state)
10427b7258f8SDavid Gibson {
1043ce2918cbSDavid Gibson SpaprDrc *drc = spapr_drc_by_index(idx);
10447b7258f8SDavid Gibson
104567fea71bSDavid Gibson if (!drc || !object_dynamic_cast(OBJECT(drc), TYPE_SPAPR_DRC_PHYSICAL)) {
104667fea71bSDavid Gibson return RTAS_OUT_NO_SUCH_INDICATOR;
104767fea71bSDavid Gibson }
104867fea71bSDavid Gibson if ((state != SPAPR_DR_INDICATOR_INACTIVE)
104967fea71bSDavid Gibson && (state != SPAPR_DR_INDICATOR_ACTIVE)
105067fea71bSDavid Gibson && (state != SPAPR_DR_INDICATOR_IDENTIFY)
105167fea71bSDavid Gibson && (state != SPAPR_DR_INDICATOR_ACTION)) {
105267fea71bSDavid Gibson return RTAS_OUT_PARAM_ERROR; /* bad state parameter */
10537b7258f8SDavid Gibson }
10547b7258f8SDavid Gibson
1055cd74d27eSDavid Gibson trace_spapr_drc_set_dr_indicator(idx, state);
105667fea71bSDavid Gibson SPAPR_DRC_PHYSICAL(drc)->dr_indicator = state;
1057cd74d27eSDavid Gibson return RTAS_OUT_SUCCESS;
1058b89b3d39SDavid Gibson }
1059b89b3d39SDavid Gibson
rtas_set_indicator(PowerPCCPU * cpu,SpaprMachineState * spapr,uint32_t token,uint32_t nargs,target_ulong args,uint32_t nret,target_ulong rets)1060ce2918cbSDavid Gibson static void rtas_set_indicator(PowerPCCPU *cpu, SpaprMachineState *spapr,
10617b7258f8SDavid Gibson uint32_t token,
10627b7258f8SDavid Gibson uint32_t nargs, target_ulong args,
10637b7258f8SDavid Gibson uint32_t nret, target_ulong rets)
1064b89b3d39SDavid Gibson {
10657b7258f8SDavid Gibson uint32_t type, idx, state;
1066b89b3d39SDavid Gibson uint32_t ret = RTAS_OUT_SUCCESS;
1067b89b3d39SDavid Gibson
1068b89b3d39SDavid Gibson if (nargs != 3 || nret != 1) {
1069b89b3d39SDavid Gibson ret = RTAS_OUT_PARAM_ERROR;
1070b89b3d39SDavid Gibson goto out;
1071b89b3d39SDavid Gibson }
1072b89b3d39SDavid Gibson
10737b7258f8SDavid Gibson type = rtas_ld(args, 0);
10747b7258f8SDavid Gibson idx = rtas_ld(args, 1);
10757b7258f8SDavid Gibson state = rtas_ld(args, 2);
1076b89b3d39SDavid Gibson
10777b7258f8SDavid Gibson switch (type) {
1078b89b3d39SDavid Gibson case RTAS_SENSOR_TYPE_ISOLATION_STATE:
10797b7258f8SDavid Gibson ret = rtas_set_isolation_state(idx, state);
1080b89b3d39SDavid Gibson break;
1081b89b3d39SDavid Gibson case RTAS_SENSOR_TYPE_DR:
1082cd74d27eSDavid Gibson ret = rtas_set_dr_indicator(idx, state);
1083b89b3d39SDavid Gibson break;
1084b89b3d39SDavid Gibson case RTAS_SENSOR_TYPE_ALLOCATION_STATE:
10857b7258f8SDavid Gibson ret = rtas_set_allocation_state(idx, state);
1086b89b3d39SDavid Gibson break;
1087b89b3d39SDavid Gibson default:
10887b7258f8SDavid Gibson ret = RTAS_OUT_NOT_SUPPORTED;
1089b89b3d39SDavid Gibson }
1090b89b3d39SDavid Gibson
1091b89b3d39SDavid Gibson out:
1092b89b3d39SDavid Gibson rtas_st(rets, 0, ret);
1093b89b3d39SDavid Gibson }
1094b89b3d39SDavid Gibson
rtas_get_sensor_state(PowerPCCPU * cpu,SpaprMachineState * spapr,uint32_t token,uint32_t nargs,target_ulong args,uint32_t nret,target_ulong rets)1095ce2918cbSDavid Gibson static void rtas_get_sensor_state(PowerPCCPU *cpu, SpaprMachineState *spapr,
1096b89b3d39SDavid Gibson uint32_t token, uint32_t nargs,
1097b89b3d39SDavid Gibson target_ulong args, uint32_t nret,
1098b89b3d39SDavid Gibson target_ulong rets)
1099b89b3d39SDavid Gibson {
1100b89b3d39SDavid Gibson uint32_t sensor_type;
1101b89b3d39SDavid Gibson uint32_t sensor_index;
1102b89b3d39SDavid Gibson uint32_t sensor_state = 0;
1103ce2918cbSDavid Gibson SpaprDrc *drc;
1104ce2918cbSDavid Gibson SpaprDrcClass *drck;
1105b89b3d39SDavid Gibson uint32_t ret = RTAS_OUT_SUCCESS;
1106b89b3d39SDavid Gibson
1107b89b3d39SDavid Gibson if (nargs != 2 || nret != 2) {
1108b89b3d39SDavid Gibson ret = RTAS_OUT_PARAM_ERROR;
1109b89b3d39SDavid Gibson goto out;
1110b89b3d39SDavid Gibson }
1111b89b3d39SDavid Gibson
1112b89b3d39SDavid Gibson sensor_type = rtas_ld(args, 0);
1113b89b3d39SDavid Gibson sensor_index = rtas_ld(args, 1);
1114b89b3d39SDavid Gibson
1115b89b3d39SDavid Gibson if (sensor_type != RTAS_SENSOR_TYPE_ENTITY_SENSE) {
1116b89b3d39SDavid Gibson /* currently only DR-related sensors are implemented */
1117b89b3d39SDavid Gibson trace_spapr_rtas_get_sensor_state_not_supported(sensor_index,
1118b89b3d39SDavid Gibson sensor_type);
1119b89b3d39SDavid Gibson ret = RTAS_OUT_NOT_SUPPORTED;
1120b89b3d39SDavid Gibson goto out;
1121b89b3d39SDavid Gibson }
1122b89b3d39SDavid Gibson
1123fbf55397SDavid Gibson drc = spapr_drc_by_index(sensor_index);
1124b89b3d39SDavid Gibson if (!drc) {
1125b89b3d39SDavid Gibson trace_spapr_rtas_get_sensor_state_invalid(sensor_index);
1126b89b3d39SDavid Gibson ret = RTAS_OUT_PARAM_ERROR;
1127b89b3d39SDavid Gibson goto out;
1128b89b3d39SDavid Gibson }
1129b89b3d39SDavid Gibson drck = SPAPR_DR_CONNECTOR_GET_CLASS(drc);
1130f224d35bSDavid Gibson sensor_state = drck->dr_entity_sense(drc);
1131b89b3d39SDavid Gibson
1132b89b3d39SDavid Gibson out:
1133b89b3d39SDavid Gibson rtas_st(rets, 0, ret);
1134b89b3d39SDavid Gibson rtas_st(rets, 1, sensor_state);
1135b89b3d39SDavid Gibson }
1136b89b3d39SDavid Gibson
1137b89b3d39SDavid Gibson /* configure-connector work area offsets, int32_t units for field
1138b89b3d39SDavid Gibson * indexes, bytes for field offset/len values.
1139b89b3d39SDavid Gibson *
1140b89b3d39SDavid Gibson * as documented by PAPR+ v2.7, 13.5.3.5
1141b89b3d39SDavid Gibson */
1142b89b3d39SDavid Gibson #define CC_IDX_NODE_NAME_OFFSET 2
1143b89b3d39SDavid Gibson #define CC_IDX_PROP_NAME_OFFSET 2
1144b89b3d39SDavid Gibson #define CC_IDX_PROP_LEN 3
1145b89b3d39SDavid Gibson #define CC_IDX_PROP_DATA_OFFSET 4
1146b89b3d39SDavid Gibson #define CC_VAL_DATA_OFFSET ((CC_IDX_PROP_DATA_OFFSET + 1) * 4)
1147b89b3d39SDavid Gibson #define CC_WA_LEN 4096
1148b89b3d39SDavid Gibson
configure_connector_st(target_ulong addr,target_ulong offset,const void * buf,size_t len)1149b89b3d39SDavid Gibson static void configure_connector_st(target_ulong addr, target_ulong offset,
1150b89b3d39SDavid Gibson const void *buf, size_t len)
1151b89b3d39SDavid Gibson {
1152b89b3d39SDavid Gibson cpu_physical_memory_write(ppc64_phys_to_real(addr + offset),
1153b89b3d39SDavid Gibson buf, MIN(len, CC_WA_LEN - offset));
1154b89b3d39SDavid Gibson }
1155b89b3d39SDavid Gibson
rtas_ibm_configure_connector(PowerPCCPU * cpu,SpaprMachineState * spapr,uint32_t token,uint32_t nargs,target_ulong args,uint32_t nret,target_ulong rets)1156b89b3d39SDavid Gibson static void rtas_ibm_configure_connector(PowerPCCPU *cpu,
1157ce2918cbSDavid Gibson SpaprMachineState *spapr,
1158b89b3d39SDavid Gibson uint32_t token, uint32_t nargs,
1159b89b3d39SDavid Gibson target_ulong args, uint32_t nret,
1160b89b3d39SDavid Gibson target_ulong rets)
1161b89b3d39SDavid Gibson {
1162b89b3d39SDavid Gibson uint64_t wa_addr;
1163b89b3d39SDavid Gibson uint64_t wa_offset;
1164b89b3d39SDavid Gibson uint32_t drc_index;
1165ce2918cbSDavid Gibson SpaprDrc *drc;
1166ce2918cbSDavid Gibson SpaprDrcClass *drck;
1167ce2918cbSDavid Gibson SpaprDRCCResponse resp = SPAPR_DR_CC_RESPONSE_CONTINUE;
1168b89b3d39SDavid Gibson int rc;
1169b89b3d39SDavid Gibson
1170b89b3d39SDavid Gibson if (nargs != 2 || nret != 1) {
1171b89b3d39SDavid Gibson rtas_st(rets, 0, RTAS_OUT_PARAM_ERROR);
1172b89b3d39SDavid Gibson return;
1173b89b3d39SDavid Gibson }
1174b89b3d39SDavid Gibson
1175b89b3d39SDavid Gibson wa_addr = ((uint64_t)rtas_ld(args, 1) << 32) | rtas_ld(args, 0);
1176b89b3d39SDavid Gibson
1177b89b3d39SDavid Gibson drc_index = rtas_ld(wa_addr, 0);
1178fbf55397SDavid Gibson drc = spapr_drc_by_index(drc_index);
1179b89b3d39SDavid Gibson if (!drc) {
1180b89b3d39SDavid Gibson trace_spapr_rtas_ibm_configure_connector_invalid(drc_index);
1181b89b3d39SDavid Gibson rc = RTAS_OUT_PARAM_ERROR;
1182b89b3d39SDavid Gibson goto out;
1183b89b3d39SDavid Gibson }
1184b89b3d39SDavid Gibson
11859d4c0f4fSDavid Gibson if ((drc->state != SPAPR_DRC_STATE_LOGICAL_UNISOLATE)
1186188bfe1bSBharata B Rao && (drc->state != SPAPR_DRC_STATE_PHYSICAL_UNISOLATE)
1187188bfe1bSBharata B Rao && (drc->state != SPAPR_DRC_STATE_LOGICAL_CONFIGURED)
1188188bfe1bSBharata B Rao && (drc->state != SPAPR_DRC_STATE_PHYSICAL_CONFIGURED)) {
1189188bfe1bSBharata B Rao /*
1190188bfe1bSBharata B Rao * Need to unisolate the device before configuring
1191188bfe1bSBharata B Rao * or it should already be in configured state to
1192188bfe1bSBharata B Rao * allow configure-connector be called repeatedly.
1193188bfe1bSBharata B Rao */
1194b89b3d39SDavid Gibson rc = SPAPR_DR_CC_RESPONSE_NOT_CONFIGURABLE;
1195b89b3d39SDavid Gibson goto out;
1196b89b3d39SDavid Gibson }
1197b89b3d39SDavid Gibson
11989d4c0f4fSDavid Gibson drck = SPAPR_DR_CONNECTOR_GET_CLASS(drc);
11999d4c0f4fSDavid Gibson
1200fe1831efSDaniel Henrique Barboza /*
1201fe1831efSDaniel Henrique Barboza * This indicates that the kernel is reconfiguring a LMB due to
1202eb7f80fdSDaniel Henrique Barboza * a failed hotunplug. Rollback the DIMM unplug process.
1203fe1831efSDaniel Henrique Barboza */
1204fe1831efSDaniel Henrique Barboza if (spapr_drc_type(drc) == SPAPR_DR_CONNECTOR_TYPE_LMB &&
1205fe1831efSDaniel Henrique Barboza drc->unplug_requested) {
1206eb7f80fdSDaniel Henrique Barboza spapr_memory_unplug_rollback(spapr, drc->dev);
1207fe1831efSDaniel Henrique Barboza }
1208fe1831efSDaniel Henrique Barboza
1209d9c95c71SGreg Kurz if (!drc->fdt) {
1210d9c95c71SGreg Kurz void *fdt;
1211d9c95c71SGreg Kurz int fdt_size;
1212d9c95c71SGreg Kurz
1213d9c95c71SGreg Kurz fdt = create_device_tree(&fdt_size);
1214d9c95c71SGreg Kurz
1215d9c95c71SGreg Kurz if (drck->dt_populate(drc, spapr, fdt, &drc->fdt_start_offset,
12169261ef5eSMarkus Armbruster NULL)) {
1217d9c95c71SGreg Kurz g_free(fdt);
1218d9c95c71SGreg Kurz rc = SPAPR_DR_CC_RESPONSE_ERROR;
1219d9c95c71SGreg Kurz goto out;
1220d9c95c71SGreg Kurz }
1221d9c95c71SGreg Kurz
1222d9c95c71SGreg Kurz drc->fdt = fdt;
1223d9c95c71SGreg Kurz drc->ccs_offset = drc->fdt_start_offset;
1224d9c95c71SGreg Kurz drc->ccs_depth = 0;
1225d9c95c71SGreg Kurz }
1226d9c95c71SGreg Kurz
1227b89b3d39SDavid Gibson do {
1228b89b3d39SDavid Gibson uint32_t tag;
1229b89b3d39SDavid Gibson const char *name;
1230b89b3d39SDavid Gibson const struct fdt_property *prop;
1231b89b3d39SDavid Gibson int fdt_offset_next, prop_len;
1232b89b3d39SDavid Gibson
12334445b1d2SDavid Gibson tag = fdt_next_tag(drc->fdt, drc->ccs_offset, &fdt_offset_next);
1234b89b3d39SDavid Gibson
1235b89b3d39SDavid Gibson switch (tag) {
1236b89b3d39SDavid Gibson case FDT_BEGIN_NODE:
12374445b1d2SDavid Gibson drc->ccs_depth++;
12384445b1d2SDavid Gibson name = fdt_get_name(drc->fdt, drc->ccs_offset, NULL);
1239b89b3d39SDavid Gibson
1240b89b3d39SDavid Gibson /* provide the name of the next OF node */
1241b89b3d39SDavid Gibson wa_offset = CC_VAL_DATA_OFFSET;
1242b89b3d39SDavid Gibson rtas_st(wa_addr, CC_IDX_NODE_NAME_OFFSET, wa_offset);
1243b89b3d39SDavid Gibson configure_connector_st(wa_addr, wa_offset, name, strlen(name) + 1);
1244b89b3d39SDavid Gibson resp = SPAPR_DR_CC_RESPONSE_NEXT_CHILD;
1245b89b3d39SDavid Gibson break;
1246b89b3d39SDavid Gibson case FDT_END_NODE:
12474445b1d2SDavid Gibson drc->ccs_depth--;
12484445b1d2SDavid Gibson if (drc->ccs_depth == 0) {
12499d4c0f4fSDavid Gibson /* done sending the device tree, move to configured state */
12500b55aa91SDavid Gibson trace_spapr_drc_set_configured(drc_index);
12519d4c0f4fSDavid Gibson drc->state = drck->ready_state;
1252188bfe1bSBharata B Rao /*
1253188bfe1bSBharata B Rao * Ensure that we are able to send the FDT fragment
1254188bfe1bSBharata B Rao * again via configure-connector call if the guest requests.
1255188bfe1bSBharata B Rao */
1256188bfe1bSBharata B Rao drc->ccs_offset = drc->fdt_start_offset;
1257188bfe1bSBharata B Rao drc->ccs_depth = 0;
1258188bfe1bSBharata B Rao fdt_offset_next = drc->fdt_start_offset;
1259b89b3d39SDavid Gibson resp = SPAPR_DR_CC_RESPONSE_SUCCESS;
1260b89b3d39SDavid Gibson } else {
1261b89b3d39SDavid Gibson resp = SPAPR_DR_CC_RESPONSE_PREV_PARENT;
1262b89b3d39SDavid Gibson }
1263b89b3d39SDavid Gibson break;
1264b89b3d39SDavid Gibson case FDT_PROP:
12654445b1d2SDavid Gibson prop = fdt_get_property_by_offset(drc->fdt, drc->ccs_offset,
1266b89b3d39SDavid Gibson &prop_len);
126788af6ea5SDavid Gibson name = fdt_string(drc->fdt, fdt32_to_cpu(prop->nameoff));
1268b89b3d39SDavid Gibson
1269b89b3d39SDavid Gibson /* provide the name of the next OF property */
1270b89b3d39SDavid Gibson wa_offset = CC_VAL_DATA_OFFSET;
1271b89b3d39SDavid Gibson rtas_st(wa_addr, CC_IDX_PROP_NAME_OFFSET, wa_offset);
1272b89b3d39SDavid Gibson configure_connector_st(wa_addr, wa_offset, name, strlen(name) + 1);
1273b89b3d39SDavid Gibson
1274b89b3d39SDavid Gibson /* provide the length and value of the OF property. data gets
1275b89b3d39SDavid Gibson * placed immediately after NULL terminator of the OF property's
1276b89b3d39SDavid Gibson * name string
1277b89b3d39SDavid Gibson */
1278b89b3d39SDavid Gibson wa_offset += strlen(name) + 1,
1279b89b3d39SDavid Gibson rtas_st(wa_addr, CC_IDX_PROP_LEN, prop_len);
1280b89b3d39SDavid Gibson rtas_st(wa_addr, CC_IDX_PROP_DATA_OFFSET, wa_offset);
1281b89b3d39SDavid Gibson configure_connector_st(wa_addr, wa_offset, prop->data, prop_len);
1282b89b3d39SDavid Gibson resp = SPAPR_DR_CC_RESPONSE_NEXT_PROPERTY;
1283b89b3d39SDavid Gibson break;
1284b89b3d39SDavid Gibson case FDT_END:
1285b89b3d39SDavid Gibson resp = SPAPR_DR_CC_RESPONSE_ERROR;
1286b89b3d39SDavid Gibson default:
1287b89b3d39SDavid Gibson /* keep seeking for an actionable tag */
1288b89b3d39SDavid Gibson break;
1289b89b3d39SDavid Gibson }
12904445b1d2SDavid Gibson if (drc->ccs_offset >= 0) {
12914445b1d2SDavid Gibson drc->ccs_offset = fdt_offset_next;
1292b89b3d39SDavid Gibson }
1293b89b3d39SDavid Gibson } while (resp == SPAPR_DR_CC_RESPONSE_CONTINUE);
1294b89b3d39SDavid Gibson
1295b89b3d39SDavid Gibson rc = resp;
1296b89b3d39SDavid Gibson out:
1297b89b3d39SDavid Gibson rtas_st(rets, 0, rc);
1298b89b3d39SDavid Gibson }
1299b89b3d39SDavid Gibson
spapr_drc_register_types(void)1300b89b3d39SDavid Gibson static void spapr_drc_register_types(void)
1301b89b3d39SDavid Gibson {
1302b89b3d39SDavid Gibson type_register_static(&spapr_dr_connector_info);
13032d335818SDavid Gibson type_register_static(&spapr_drc_physical_info);
13042d335818SDavid Gibson type_register_static(&spapr_drc_logical_info);
13052d335818SDavid Gibson type_register_static(&spapr_drc_cpu_info);
13062d335818SDavid Gibson type_register_static(&spapr_drc_pci_info);
13072d335818SDavid Gibson type_register_static(&spapr_drc_lmb_info);
1308962b6c36SMichael Roth type_register_static(&spapr_drc_phb_info);
1309ee3a71e3SShivaprasad G Bhat type_register_static(&spapr_drc_pmem_info);
1310b89b3d39SDavid Gibson
1311b89b3d39SDavid Gibson spapr_rtas_register(RTAS_SET_INDICATOR, "set-indicator",
1312b89b3d39SDavid Gibson rtas_set_indicator);
1313b89b3d39SDavid Gibson spapr_rtas_register(RTAS_GET_SENSOR_STATE, "get-sensor-state",
1314b89b3d39SDavid Gibson rtas_get_sensor_state);
1315b89b3d39SDavid Gibson spapr_rtas_register(RTAS_IBM_CONFIGURE_CONNECTOR, "ibm,configure-connector",
1316b89b3d39SDavid Gibson rtas_ibm_configure_connector);
1317b89b3d39SDavid Gibson }
1318b89b3d39SDavid Gibson type_init(spapr_drc_register_types)
1319