xref: /qemu/hw/ppc/spapr_drc.c (revision 586d2142a9f1aa5a1dceb0941e7b3f0953974a8b)
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 
13bbf5c878SMichael Roth #include "hw/ppc/spapr_drc.h"
14bbf5c878SMichael Roth #include "qom/object.h"
15bbf5c878SMichael Roth #include "hw/qdev.h"
16bbf5c878SMichael Roth #include "qapi/visitor.h"
17bbf5c878SMichael Roth #include "qemu/error-report.h"
18bbf5c878SMichael Roth 
19bbf5c878SMichael Roth /* #define DEBUG_SPAPR_DRC */
20bbf5c878SMichael Roth 
21bbf5c878SMichael Roth #ifdef DEBUG_SPAPR_DRC
22bbf5c878SMichael Roth #define DPRINTF(fmt, ...) \
23bbf5c878SMichael Roth     do { fprintf(stderr, fmt, ## __VA_ARGS__); } while (0)
24bbf5c878SMichael Roth #define DPRINTFN(fmt, ...) \
25bbf5c878SMichael Roth     do { DPRINTF(fmt, ## __VA_ARGS__); fprintf(stderr, "\n"); } while (0)
26bbf5c878SMichael Roth #else
27bbf5c878SMichael Roth #define DPRINTF(fmt, ...) \
28bbf5c878SMichael Roth     do { } while (0)
29bbf5c878SMichael Roth #define DPRINTFN(fmt, ...) \
30bbf5c878SMichael Roth     do { } while (0)
31bbf5c878SMichael Roth #endif
32bbf5c878SMichael Roth 
33bbf5c878SMichael Roth #define DRC_CONTAINER_PATH "/dr-connector"
34bbf5c878SMichael Roth #define DRC_INDEX_TYPE_SHIFT 28
35bbf5c878SMichael Roth #define DRC_INDEX_ID_MASK (~(~0 << DRC_INDEX_TYPE_SHIFT))
36bbf5c878SMichael Roth 
37bbf5c878SMichael Roth static sPAPRDRConnectorTypeShift get_type_shift(sPAPRDRConnectorType type)
38bbf5c878SMichael Roth {
39bbf5c878SMichael Roth     uint32_t shift = 0;
40bbf5c878SMichael Roth 
41bbf5c878SMichael Roth     /* make sure this isn't SPAPR_DR_CONNECTOR_TYPE_ANY, or some
42bbf5c878SMichael Roth      * other wonky value.
43bbf5c878SMichael Roth      */
44bbf5c878SMichael Roth     g_assert(is_power_of_2(type));
45bbf5c878SMichael Roth 
46bbf5c878SMichael Roth     while (type != (1 << shift)) {
47bbf5c878SMichael Roth         shift++;
48bbf5c878SMichael Roth     }
49bbf5c878SMichael Roth     return shift;
50bbf5c878SMichael Roth }
51bbf5c878SMichael Roth 
52bbf5c878SMichael Roth static uint32_t get_index(sPAPRDRConnector *drc)
53bbf5c878SMichael Roth {
54bbf5c878SMichael Roth     /* no set format for a drc index: it only needs to be globally
55bbf5c878SMichael Roth      * unique. this is how we encode the DRC type on bare-metal
56bbf5c878SMichael Roth      * however, so might as well do that here
57bbf5c878SMichael Roth      */
58bbf5c878SMichael Roth     return (get_type_shift(drc->type) << DRC_INDEX_TYPE_SHIFT) |
59bbf5c878SMichael Roth             (drc->id & DRC_INDEX_ID_MASK);
60bbf5c878SMichael Roth }
61bbf5c878SMichael Roth 
62bbf5c878SMichael Roth static int set_isolation_state(sPAPRDRConnector *drc,
63bbf5c878SMichael Roth                                sPAPRDRIsolationState state)
64bbf5c878SMichael Roth {
65bbf5c878SMichael Roth     sPAPRDRConnectorClass *drck = SPAPR_DR_CONNECTOR_GET_CLASS(drc);
66bbf5c878SMichael Roth 
67bbf5c878SMichael Roth     DPRINTFN("drc: %x, set_isolation_state: %x", get_index(drc), state);
68bbf5c878SMichael Roth 
69bbf5c878SMichael Roth     drc->isolation_state = state;
70bbf5c878SMichael Roth 
71bbf5c878SMichael Roth     if (drc->isolation_state == SPAPR_DR_ISOLATION_STATE_ISOLATED) {
72bbf5c878SMichael Roth         /* if we're awaiting release, but still in an unconfigured state,
73bbf5c878SMichael Roth          * it's likely the guest is still in the process of configuring
74bbf5c878SMichael Roth          * the device and is transitioning the devices to an ISOLATED
75bbf5c878SMichael Roth          * state as a part of that process. so we only complete the
76bbf5c878SMichael Roth          * removal when this transition happens for a device in a
77bbf5c878SMichael Roth          * configured state, as suggested by the state diagram from
78bbf5c878SMichael Roth          * PAPR+ 2.7, 13.4
79bbf5c878SMichael Roth          */
80bbf5c878SMichael Roth         if (drc->awaiting_release) {
81bbf5c878SMichael Roth             if (drc->configured) {
82bbf5c878SMichael Roth                 DPRINTFN("finalizing device removal");
83bbf5c878SMichael Roth                 drck->detach(drc, DEVICE(drc->dev), drc->detach_cb,
84bbf5c878SMichael Roth                              drc->detach_cb_opaque, NULL);
85bbf5c878SMichael Roth             } else {
86bbf5c878SMichael Roth                 DPRINTFN("deferring device removal on unconfigured device\n");
87bbf5c878SMichael Roth             }
88bbf5c878SMichael Roth         }
89bbf5c878SMichael Roth         drc->configured = false;
90bbf5c878SMichael Roth     }
91bbf5c878SMichael Roth 
92bbf5c878SMichael Roth     return 0;
93bbf5c878SMichael Roth }
94bbf5c878SMichael Roth 
95bbf5c878SMichael Roth static int set_indicator_state(sPAPRDRConnector *drc,
96bbf5c878SMichael Roth                                sPAPRDRIndicatorState state)
97bbf5c878SMichael Roth {
98bbf5c878SMichael Roth     DPRINTFN("drc: %x, set_indicator_state: %x", get_index(drc), state);
99bbf5c878SMichael Roth     drc->indicator_state = state;
100bbf5c878SMichael Roth     return 0;
101bbf5c878SMichael Roth }
102bbf5c878SMichael Roth 
103bbf5c878SMichael Roth static int set_allocation_state(sPAPRDRConnector *drc,
104bbf5c878SMichael Roth                                 sPAPRDRAllocationState state)
105bbf5c878SMichael Roth {
106bbf5c878SMichael Roth     sPAPRDRConnectorClass *drck = SPAPR_DR_CONNECTOR_GET_CLASS(drc);
107bbf5c878SMichael Roth 
108bbf5c878SMichael Roth     DPRINTFN("drc: %x, set_allocation_state: %x", get_index(drc), state);
109bbf5c878SMichael Roth 
110bbf5c878SMichael Roth     if (drc->type != SPAPR_DR_CONNECTOR_TYPE_PCI) {
111bbf5c878SMichael Roth         drc->allocation_state = state;
112bbf5c878SMichael Roth         if (drc->awaiting_release &&
113bbf5c878SMichael Roth             drc->allocation_state == SPAPR_DR_ALLOCATION_STATE_UNUSABLE) {
114bbf5c878SMichael Roth             DPRINTFN("finalizing device removal");
115bbf5c878SMichael Roth             drck->detach(drc, DEVICE(drc->dev), drc->detach_cb,
116bbf5c878SMichael Roth                          drc->detach_cb_opaque, NULL);
117bbf5c878SMichael Roth         }
118bbf5c878SMichael Roth     }
119bbf5c878SMichael Roth     return 0;
120bbf5c878SMichael Roth }
121bbf5c878SMichael Roth 
122bbf5c878SMichael Roth static uint32_t get_type(sPAPRDRConnector *drc)
123bbf5c878SMichael Roth {
124bbf5c878SMichael Roth     return drc->type;
125bbf5c878SMichael Roth }
126bbf5c878SMichael Roth 
127bbf5c878SMichael Roth static const char *get_name(sPAPRDRConnector *drc)
128bbf5c878SMichael Roth {
129bbf5c878SMichael Roth     return drc->name;
130bbf5c878SMichael Roth }
131bbf5c878SMichael Roth 
132bbf5c878SMichael Roth static const void *get_fdt(sPAPRDRConnector *drc, int *fdt_start_offset)
133bbf5c878SMichael Roth {
134bbf5c878SMichael Roth     if (fdt_start_offset) {
135bbf5c878SMichael Roth         *fdt_start_offset = drc->fdt_start_offset;
136bbf5c878SMichael Roth     }
137bbf5c878SMichael Roth     return drc->fdt;
138bbf5c878SMichael Roth }
139bbf5c878SMichael Roth 
140bbf5c878SMichael Roth static void set_configured(sPAPRDRConnector *drc)
141bbf5c878SMichael Roth {
142bbf5c878SMichael Roth     DPRINTFN("drc: %x, set_configured", get_index(drc));
143bbf5c878SMichael Roth 
144bbf5c878SMichael Roth     if (drc->isolation_state != SPAPR_DR_ISOLATION_STATE_UNISOLATED) {
145bbf5c878SMichael Roth         /* guest should be not configuring an isolated device */
146bbf5c878SMichael Roth         DPRINTFN("drc: %x, set_configured: skipping isolated device",
147bbf5c878SMichael Roth                  get_index(drc));
148bbf5c878SMichael Roth         return;
149bbf5c878SMichael Roth     }
150bbf5c878SMichael Roth     drc->configured = true;
151bbf5c878SMichael Roth }
152bbf5c878SMichael Roth 
153bbf5c878SMichael Roth /*
154bbf5c878SMichael Roth  * dr-entity-sense sensor value
155bbf5c878SMichael Roth  * returned via get-sensor-state RTAS calls
156bbf5c878SMichael Roth  * as expected by state diagram in PAPR+ 2.7, 13.4
157bbf5c878SMichael Roth  * based on the current allocation/indicator/power states
158bbf5c878SMichael Roth  * for the DR connector.
159bbf5c878SMichael Roth  */
160bbf5c878SMichael Roth static sPAPRDREntitySense entity_sense(sPAPRDRConnector *drc)
161bbf5c878SMichael Roth {
162bbf5c878SMichael Roth     sPAPRDREntitySense state;
163bbf5c878SMichael Roth 
164bbf5c878SMichael Roth     if (drc->dev) {
165bbf5c878SMichael Roth         if (drc->type != SPAPR_DR_CONNECTOR_TYPE_PCI &&
166bbf5c878SMichael Roth             drc->allocation_state == SPAPR_DR_ALLOCATION_STATE_UNUSABLE) {
167bbf5c878SMichael Roth             /* for logical DR, we return a state of UNUSABLE
168bbf5c878SMichael Roth              * iff the allocation state UNUSABLE.
169bbf5c878SMichael Roth              * Otherwise, report the state as USABLE/PRESENT,
170bbf5c878SMichael Roth              * as we would for PCI.
171bbf5c878SMichael Roth              */
172bbf5c878SMichael Roth             state = SPAPR_DR_ENTITY_SENSE_UNUSABLE;
173bbf5c878SMichael Roth         } else {
174bbf5c878SMichael Roth             /* this assumes all PCI devices are assigned to
175bbf5c878SMichael Roth              * a 'live insertion' power domain, where QEMU
176bbf5c878SMichael Roth              * manages power state automatically as opposed
177bbf5c878SMichael Roth              * to the guest. present, non-PCI resources are
178bbf5c878SMichael Roth              * unaffected by power state.
179bbf5c878SMichael Roth              */
180bbf5c878SMichael Roth             state = SPAPR_DR_ENTITY_SENSE_PRESENT;
181bbf5c878SMichael Roth         }
182bbf5c878SMichael Roth     } else {
183bbf5c878SMichael Roth         if (drc->type == SPAPR_DR_CONNECTOR_TYPE_PCI) {
184bbf5c878SMichael Roth             /* PCI devices, and only PCI devices, use EMPTY
185bbf5c878SMichael Roth              * in cases where we'd otherwise use UNUSABLE
186bbf5c878SMichael Roth              */
187bbf5c878SMichael Roth             state = SPAPR_DR_ENTITY_SENSE_EMPTY;
188bbf5c878SMichael Roth         } else {
189bbf5c878SMichael Roth             state = SPAPR_DR_ENTITY_SENSE_UNUSABLE;
190bbf5c878SMichael Roth         }
191bbf5c878SMichael Roth     }
192bbf5c878SMichael Roth 
193bbf5c878SMichael Roth     DPRINTFN("drc: %x, entity_sense: %x", get_index(drc), state);
194bbf5c878SMichael Roth     return state;
195bbf5c878SMichael Roth }
196bbf5c878SMichael Roth 
197bbf5c878SMichael Roth static void prop_get_index(Object *obj, Visitor *v, void *opaque,
198bbf5c878SMichael Roth                                   const char *name, Error **errp)
199bbf5c878SMichael Roth {
200bbf5c878SMichael Roth     sPAPRDRConnector *drc = SPAPR_DR_CONNECTOR(obj);
201bbf5c878SMichael Roth     sPAPRDRConnectorClass *drck = SPAPR_DR_CONNECTOR_GET_CLASS(drc);
202bbf5c878SMichael Roth     uint32_t value = (uint32_t)drck->get_index(drc);
203bbf5c878SMichael Roth     visit_type_uint32(v, &value, name, errp);
204bbf5c878SMichael Roth }
205bbf5c878SMichael Roth 
206bbf5c878SMichael Roth static void prop_get_type(Object *obj, Visitor *v, void *opaque,
207bbf5c878SMichael Roth                           const char *name, Error **errp)
208bbf5c878SMichael Roth {
209bbf5c878SMichael Roth     sPAPRDRConnector *drc = SPAPR_DR_CONNECTOR(obj);
210bbf5c878SMichael Roth     sPAPRDRConnectorClass *drck = SPAPR_DR_CONNECTOR_GET_CLASS(drc);
211bbf5c878SMichael Roth     uint32_t value = (uint32_t)drck->get_type(drc);
212bbf5c878SMichael Roth     visit_type_uint32(v, &value, name, errp);
213bbf5c878SMichael Roth }
214bbf5c878SMichael Roth 
215bbf5c878SMichael Roth static char *prop_get_name(Object *obj, Error **errp)
216bbf5c878SMichael Roth {
217bbf5c878SMichael Roth     sPAPRDRConnector *drc = SPAPR_DR_CONNECTOR(obj);
218bbf5c878SMichael Roth     sPAPRDRConnectorClass *drck = SPAPR_DR_CONNECTOR_GET_CLASS(drc);
219bbf5c878SMichael Roth     return g_strdup(drck->get_name(drc));
220bbf5c878SMichael Roth }
221bbf5c878SMichael Roth 
222bbf5c878SMichael Roth static void prop_get_entity_sense(Object *obj, Visitor *v, void *opaque,
223bbf5c878SMichael Roth                                   const char *name, Error **errp)
224bbf5c878SMichael Roth {
225bbf5c878SMichael Roth     sPAPRDRConnector *drc = SPAPR_DR_CONNECTOR(obj);
226bbf5c878SMichael Roth     sPAPRDRConnectorClass *drck = SPAPR_DR_CONNECTOR_GET_CLASS(drc);
227bbf5c878SMichael Roth     uint32_t value = (uint32_t)drck->entity_sense(drc);
228bbf5c878SMichael Roth     visit_type_uint32(v, &value, name, errp);
229bbf5c878SMichael Roth }
230bbf5c878SMichael Roth 
231bbf5c878SMichael Roth static void prop_get_fdt(Object *obj, Visitor *v, void *opaque,
232bbf5c878SMichael Roth                         const char *name, Error **errp)
233bbf5c878SMichael Roth {
234bbf5c878SMichael Roth     sPAPRDRConnector *drc = SPAPR_DR_CONNECTOR(obj);
235bbf5c878SMichael Roth     int fdt_offset_next, fdt_offset, fdt_depth;
236bbf5c878SMichael Roth     void *fdt;
237bbf5c878SMichael Roth 
238bbf5c878SMichael Roth     if (!drc->fdt) {
239bbf5c878SMichael Roth         return;
240bbf5c878SMichael Roth     }
241bbf5c878SMichael Roth 
242bbf5c878SMichael Roth     fdt = drc->fdt;
243bbf5c878SMichael Roth     fdt_offset = drc->fdt_start_offset;
244bbf5c878SMichael Roth     fdt_depth = 0;
245bbf5c878SMichael Roth 
246bbf5c878SMichael Roth     do {
247bbf5c878SMichael Roth         const char *name = NULL;
248bbf5c878SMichael Roth         const struct fdt_property *prop = NULL;
249bbf5c878SMichael Roth         int prop_len = 0, name_len = 0;
250bbf5c878SMichael Roth         uint32_t tag;
251bbf5c878SMichael Roth 
252bbf5c878SMichael Roth         tag = fdt_next_tag(fdt, fdt_offset, &fdt_offset_next);
253bbf5c878SMichael Roth         switch (tag) {
254bbf5c878SMichael Roth         case FDT_BEGIN_NODE:
255bbf5c878SMichael Roth             fdt_depth++;
256bbf5c878SMichael Roth             name = fdt_get_name(fdt, fdt_offset, &name_len);
257bbf5c878SMichael Roth             visit_start_struct(v, NULL, NULL, name, 0, NULL);
258bbf5c878SMichael Roth             break;
259bbf5c878SMichael Roth         case FDT_END_NODE:
260bbf5c878SMichael Roth             /* shouldn't ever see an FDT_END_NODE before FDT_BEGIN_NODE */
261bbf5c878SMichael Roth             g_assert(fdt_depth > 0);
262bbf5c878SMichael Roth             visit_end_struct(v, NULL);
263bbf5c878SMichael Roth             fdt_depth--;
264bbf5c878SMichael Roth             break;
265bbf5c878SMichael Roth         case FDT_PROP: {
266bbf5c878SMichael Roth             int i;
267bbf5c878SMichael Roth             prop = fdt_get_property_by_offset(fdt, fdt_offset, &prop_len);
268bbf5c878SMichael Roth             name = fdt_string(fdt, fdt32_to_cpu(prop->nameoff));
269bbf5c878SMichael Roth             visit_start_list(v, name, NULL);
270bbf5c878SMichael Roth             for (i = 0; i < prop_len; i++) {
271bbf5c878SMichael Roth                 visit_type_uint8(v, (uint8_t *)&prop->data[i], NULL, NULL);
272bbf5c878SMichael Roth 
273bbf5c878SMichael Roth             }
274bbf5c878SMichael Roth             visit_end_list(v, NULL);
275bbf5c878SMichael Roth             break;
276bbf5c878SMichael Roth         }
277bbf5c878SMichael Roth         default:
278bbf5c878SMichael Roth             error_setg(&error_abort, "device FDT in unexpected state: %d", tag);
279bbf5c878SMichael Roth         }
280bbf5c878SMichael Roth         fdt_offset = fdt_offset_next;
281bbf5c878SMichael Roth     } while (fdt_depth != 0);
282bbf5c878SMichael Roth }
283bbf5c878SMichael Roth 
284bbf5c878SMichael Roth static void attach(sPAPRDRConnector *drc, DeviceState *d, void *fdt,
285bbf5c878SMichael Roth                    int fdt_start_offset, bool coldplug, Error **errp)
286bbf5c878SMichael Roth {
287bbf5c878SMichael Roth     DPRINTFN("drc: %x, attach", get_index(drc));
288bbf5c878SMichael Roth 
289bbf5c878SMichael Roth     if (drc->isolation_state != SPAPR_DR_ISOLATION_STATE_ISOLATED) {
290bbf5c878SMichael Roth         error_setg(errp, "an attached device is still awaiting release");
291bbf5c878SMichael Roth         return;
292bbf5c878SMichael Roth     }
293bbf5c878SMichael Roth     if (drc->type == SPAPR_DR_CONNECTOR_TYPE_PCI) {
294bbf5c878SMichael Roth         g_assert(drc->allocation_state == SPAPR_DR_ALLOCATION_STATE_USABLE);
295bbf5c878SMichael Roth     }
296bbf5c878SMichael Roth     g_assert(fdt || coldplug);
297bbf5c878SMichael Roth 
298bbf5c878SMichael Roth     /* NOTE: setting initial isolation state to UNISOLATED means we can't
299bbf5c878SMichael Roth      * detach unless guest has a userspace/kernel that moves this state
300bbf5c878SMichael Roth      * back to ISOLATED in response to an unplug event, or this is done
301bbf5c878SMichael Roth      * manually by the admin prior. if we force things while the guest
302bbf5c878SMichael Roth      * may be accessing the device, we can easily crash the guest, so we
303bbf5c878SMichael Roth      * we defer completion of removal in such cases to the reset() hook.
304bbf5c878SMichael Roth      */
305bbf5c878SMichael Roth     if (drc->type == SPAPR_DR_CONNECTOR_TYPE_PCI) {
306bbf5c878SMichael Roth         drc->isolation_state = SPAPR_DR_ISOLATION_STATE_UNISOLATED;
307bbf5c878SMichael Roth     }
308bbf5c878SMichael Roth     drc->indicator_state = SPAPR_DR_INDICATOR_STATE_ACTIVE;
309bbf5c878SMichael Roth 
310bbf5c878SMichael Roth     drc->dev = d;
311bbf5c878SMichael Roth     drc->fdt = fdt;
312bbf5c878SMichael Roth     drc->fdt_start_offset = fdt_start_offset;
313bbf5c878SMichael Roth     drc->configured = false;
314bbf5c878SMichael Roth 
315bbf5c878SMichael Roth     object_property_add_link(OBJECT(drc), "device",
316bbf5c878SMichael Roth                              object_get_typename(OBJECT(drc->dev)),
317bbf5c878SMichael Roth                              (Object **)(&drc->dev),
318bbf5c878SMichael Roth                              NULL, 0, NULL);
319bbf5c878SMichael Roth }
320bbf5c878SMichael Roth 
321bbf5c878SMichael Roth static void detach(sPAPRDRConnector *drc, DeviceState *d,
322bbf5c878SMichael Roth                    spapr_drc_detach_cb *detach_cb,
323bbf5c878SMichael Roth                    void *detach_cb_opaque, Error **errp)
324bbf5c878SMichael Roth {
325bbf5c878SMichael Roth     DPRINTFN("drc: %x, detach", get_index(drc));
326bbf5c878SMichael Roth 
327bbf5c878SMichael Roth     drc->detach_cb = detach_cb;
328bbf5c878SMichael Roth     drc->detach_cb_opaque = detach_cb_opaque;
329bbf5c878SMichael Roth 
330bbf5c878SMichael Roth     if (drc->isolation_state != SPAPR_DR_ISOLATION_STATE_ISOLATED) {
331bbf5c878SMichael Roth         DPRINTFN("awaiting transition to isolated state before removal");
332bbf5c878SMichael Roth         drc->awaiting_release = true;
333bbf5c878SMichael Roth         return;
334bbf5c878SMichael Roth     }
335bbf5c878SMichael Roth 
336bbf5c878SMichael Roth     if (drc->type != SPAPR_DR_CONNECTOR_TYPE_PCI &&
337bbf5c878SMichael Roth         drc->allocation_state != SPAPR_DR_ALLOCATION_STATE_UNUSABLE) {
338bbf5c878SMichael Roth         DPRINTFN("awaiting transition to unusable state before removal");
339bbf5c878SMichael Roth         drc->awaiting_release = true;
340bbf5c878SMichael Roth         return;
341bbf5c878SMichael Roth     }
342bbf5c878SMichael Roth 
343bbf5c878SMichael Roth     drc->indicator_state = SPAPR_DR_INDICATOR_STATE_INACTIVE;
344bbf5c878SMichael Roth 
345bbf5c878SMichael Roth     if (drc->detach_cb) {
346bbf5c878SMichael Roth         drc->detach_cb(drc->dev, drc->detach_cb_opaque);
347bbf5c878SMichael Roth     }
348bbf5c878SMichael Roth 
349bbf5c878SMichael Roth     drc->awaiting_release = false;
350bbf5c878SMichael Roth     g_free(drc->fdt);
351bbf5c878SMichael Roth     drc->fdt = NULL;
352bbf5c878SMichael Roth     drc->fdt_start_offset = 0;
353bbf5c878SMichael Roth     object_property_del(OBJECT(drc), "device", NULL);
354bbf5c878SMichael Roth     drc->dev = NULL;
355bbf5c878SMichael Roth     drc->detach_cb = NULL;
356bbf5c878SMichael Roth     drc->detach_cb_opaque = NULL;
357bbf5c878SMichael Roth }
358bbf5c878SMichael Roth 
359bbf5c878SMichael Roth static bool release_pending(sPAPRDRConnector *drc)
360bbf5c878SMichael Roth {
361bbf5c878SMichael Roth     return drc->awaiting_release;
362bbf5c878SMichael Roth }
363bbf5c878SMichael Roth 
364bbf5c878SMichael Roth static void reset(DeviceState *d)
365bbf5c878SMichael Roth {
366bbf5c878SMichael Roth     sPAPRDRConnector *drc = SPAPR_DR_CONNECTOR(d);
367bbf5c878SMichael Roth     sPAPRDRConnectorClass *drck = SPAPR_DR_CONNECTOR_GET_CLASS(drc);
368bbf5c878SMichael Roth 
369bbf5c878SMichael Roth     DPRINTFN("drc reset: %x", drck->get_index(drc));
370bbf5c878SMichael Roth     /* immediately upon reset we can safely assume DRCs whose devices
371bbf5c878SMichael Roth      * are pending removal can be safely removed, and that they will
372bbf5c878SMichael Roth      * subsequently be left in an ISOLATED state. move the DRC to this
373bbf5c878SMichael Roth      * state in these cases (which will in turn complete any pending
374bbf5c878SMichael Roth      * device removals)
375bbf5c878SMichael Roth      */
376bbf5c878SMichael Roth     if (drc->awaiting_release) {
377bbf5c878SMichael Roth         drck->set_isolation_state(drc, SPAPR_DR_ISOLATION_STATE_ISOLATED);
378bbf5c878SMichael Roth         /* generally this should also finalize the removal, but if the device
379bbf5c878SMichael Roth          * hasn't yet been configured we normally defer removal under the
380bbf5c878SMichael Roth          * assumption that this transition is taking place as part of device
381bbf5c878SMichael Roth          * configuration. so check if we're still waiting after this, and
382bbf5c878SMichael Roth          * force removal if we are
383bbf5c878SMichael Roth          */
384bbf5c878SMichael Roth         if (drc->awaiting_release) {
385bbf5c878SMichael Roth             drck->detach(drc, DEVICE(drc->dev), drc->detach_cb,
386bbf5c878SMichael Roth                          drc->detach_cb_opaque, NULL);
387bbf5c878SMichael Roth         }
388bbf5c878SMichael Roth 
389bbf5c878SMichael Roth         /* non-PCI devices may be awaiting a transition to UNUSABLE */
390bbf5c878SMichael Roth         if (drc->type != SPAPR_DR_CONNECTOR_TYPE_PCI &&
391bbf5c878SMichael Roth             drc->awaiting_release) {
392bbf5c878SMichael Roth             drck->set_allocation_state(drc, SPAPR_DR_ALLOCATION_STATE_UNUSABLE);
393bbf5c878SMichael Roth         }
394bbf5c878SMichael Roth     }
395bbf5c878SMichael Roth }
396bbf5c878SMichael Roth 
397bbf5c878SMichael Roth static void realize(DeviceState *d, Error **errp)
398bbf5c878SMichael Roth {
399bbf5c878SMichael Roth     sPAPRDRConnector *drc = SPAPR_DR_CONNECTOR(d);
400bbf5c878SMichael Roth     sPAPRDRConnectorClass *drck = SPAPR_DR_CONNECTOR_GET_CLASS(drc);
401bbf5c878SMichael Roth     Object *root_container;
402bbf5c878SMichael Roth     char link_name[256];
403bbf5c878SMichael Roth     gchar *child_name;
404bbf5c878SMichael Roth     Error *err = NULL;
405bbf5c878SMichael Roth 
406bbf5c878SMichael Roth     DPRINTFN("drc realize: %x", drck->get_index(drc));
407bbf5c878SMichael Roth     /* NOTE: we do this as part of realize/unrealize due to the fact
408bbf5c878SMichael Roth      * that the guest will communicate with the DRC via RTAS calls
409bbf5c878SMichael Roth      * referencing the global DRC index. By unlinking the DRC
410bbf5c878SMichael Roth      * from DRC_CONTAINER_PATH/<drc_index> we effectively make it
411bbf5c878SMichael Roth      * inaccessible by the guest, since lookups rely on this path
412bbf5c878SMichael Roth      * existing in the composition tree
413bbf5c878SMichael Roth      */
414bbf5c878SMichael Roth     root_container = container_get(object_get_root(), DRC_CONTAINER_PATH);
415bbf5c878SMichael Roth     snprintf(link_name, sizeof(link_name), "%x", drck->get_index(drc));
416bbf5c878SMichael Roth     child_name = object_get_canonical_path_component(OBJECT(drc));
417bbf5c878SMichael Roth     DPRINTFN("drc child name: %s", child_name);
418bbf5c878SMichael Roth     object_property_add_alias(root_container, link_name,
419bbf5c878SMichael Roth                               drc->owner, child_name, &err);
420bbf5c878SMichael Roth     if (err) {
421bbf5c878SMichael Roth         error_report("%s", error_get_pretty(err));
422bbf5c878SMichael Roth         error_free(err);
423bbf5c878SMichael Roth         object_unref(OBJECT(drc));
424bbf5c878SMichael Roth     }
425*586d2142SGonglei     g_free(child_name);
426bbf5c878SMichael Roth     DPRINTFN("drc realize complete");
427bbf5c878SMichael Roth }
428bbf5c878SMichael Roth 
429bbf5c878SMichael Roth static void unrealize(DeviceState *d, Error **errp)
430bbf5c878SMichael Roth {
431bbf5c878SMichael Roth     sPAPRDRConnector *drc = SPAPR_DR_CONNECTOR(d);
432bbf5c878SMichael Roth     sPAPRDRConnectorClass *drck = SPAPR_DR_CONNECTOR_GET_CLASS(drc);
433bbf5c878SMichael Roth     Object *root_container;
434bbf5c878SMichael Roth     char name[256];
435bbf5c878SMichael Roth     Error *err = NULL;
436bbf5c878SMichael Roth 
437bbf5c878SMichael Roth     DPRINTFN("drc unrealize: %x", drck->get_index(drc));
438bbf5c878SMichael Roth     root_container = container_get(object_get_root(), DRC_CONTAINER_PATH);
439bbf5c878SMichael Roth     snprintf(name, sizeof(name), "%x", drck->get_index(drc));
440bbf5c878SMichael Roth     object_property_del(root_container, name, &err);
441bbf5c878SMichael Roth     if (err) {
442bbf5c878SMichael Roth         error_report("%s", error_get_pretty(err));
443bbf5c878SMichael Roth         error_free(err);
444bbf5c878SMichael Roth         object_unref(OBJECT(drc));
445bbf5c878SMichael Roth     }
446bbf5c878SMichael Roth }
447bbf5c878SMichael Roth 
448bbf5c878SMichael Roth sPAPRDRConnector *spapr_dr_connector_new(Object *owner,
449bbf5c878SMichael Roth                                          sPAPRDRConnectorType type,
450bbf5c878SMichael Roth                                          uint32_t id)
451bbf5c878SMichael Roth {
452bbf5c878SMichael Roth     sPAPRDRConnector *drc =
453bbf5c878SMichael Roth         SPAPR_DR_CONNECTOR(object_new(TYPE_SPAPR_DR_CONNECTOR));
454bbf5c878SMichael Roth 
455bbf5c878SMichael Roth     g_assert(type);
456bbf5c878SMichael Roth 
457bbf5c878SMichael Roth     drc->type = type;
458bbf5c878SMichael Roth     drc->id = id;
459bbf5c878SMichael Roth     drc->owner = owner;
460bbf5c878SMichael Roth     object_property_add_child(owner, "dr-connector[*]", OBJECT(drc), NULL);
461bbf5c878SMichael Roth     object_property_set_bool(OBJECT(drc), true, "realized", NULL);
462bbf5c878SMichael Roth 
463bbf5c878SMichael Roth     /* human-readable name for a DRC to encode into the DT
464bbf5c878SMichael Roth      * description. this is mainly only used within a guest in place
465bbf5c878SMichael Roth      * of the unique DRC index.
466bbf5c878SMichael Roth      *
467bbf5c878SMichael Roth      * in the case of VIO/PCI devices, it corresponds to a
468bbf5c878SMichael Roth      * "location code" that maps a logical device/function (DRC index)
469bbf5c878SMichael Roth      * to a physical (or virtual in the case of VIO) location in the
470bbf5c878SMichael Roth      * system by chaining together the "location label" for each
471bbf5c878SMichael Roth      * encapsulating component.
472bbf5c878SMichael Roth      *
473bbf5c878SMichael Roth      * since this is more to do with diagnosing physical hardware
474bbf5c878SMichael Roth      * issues than guest compatibility, we choose location codes/DRC
475bbf5c878SMichael Roth      * names that adhere to the documented format, but avoid encoding
476bbf5c878SMichael Roth      * the entire topology information into the label/code, instead
477bbf5c878SMichael Roth      * just using the location codes based on the labels for the
478bbf5c878SMichael Roth      * endpoints (VIO/PCI adaptor connectors), which is basically
479bbf5c878SMichael Roth      * just "C" followed by an integer ID.
480bbf5c878SMichael Roth      *
481bbf5c878SMichael Roth      * DRC names as documented by PAPR+ v2.7, 13.5.2.4
482bbf5c878SMichael Roth      * location codes as documented by PAPR+ v2.7, 12.3.1.5
483bbf5c878SMichael Roth      */
484bbf5c878SMichael Roth     switch (drc->type) {
485bbf5c878SMichael Roth     case SPAPR_DR_CONNECTOR_TYPE_CPU:
486bbf5c878SMichael Roth         drc->name = g_strdup_printf("CPU %d", id);
487bbf5c878SMichael Roth         break;
488bbf5c878SMichael Roth     case SPAPR_DR_CONNECTOR_TYPE_PHB:
489bbf5c878SMichael Roth         drc->name = g_strdup_printf("PHB %d", id);
490bbf5c878SMichael Roth         break;
491bbf5c878SMichael Roth     case SPAPR_DR_CONNECTOR_TYPE_VIO:
492bbf5c878SMichael Roth     case SPAPR_DR_CONNECTOR_TYPE_PCI:
493bbf5c878SMichael Roth         drc->name = g_strdup_printf("C%d", id);
494bbf5c878SMichael Roth         break;
495bbf5c878SMichael Roth     case SPAPR_DR_CONNECTOR_TYPE_LMB:
496bbf5c878SMichael Roth         drc->name = g_strdup_printf("LMB %d", id);
497bbf5c878SMichael Roth         break;
498bbf5c878SMichael Roth     default:
499bbf5c878SMichael Roth         g_assert(false);
500bbf5c878SMichael Roth     }
501bbf5c878SMichael Roth 
502bbf5c878SMichael Roth     /* PCI slot always start in a USABLE state, and stay there */
503bbf5c878SMichael Roth     if (drc->type == SPAPR_DR_CONNECTOR_TYPE_PCI) {
504bbf5c878SMichael Roth         drc->allocation_state = SPAPR_DR_ALLOCATION_STATE_USABLE;
505bbf5c878SMichael Roth     }
506bbf5c878SMichael Roth 
507bbf5c878SMichael Roth     return drc;
508bbf5c878SMichael Roth }
509bbf5c878SMichael Roth 
510bbf5c878SMichael Roth static void spapr_dr_connector_instance_init(Object *obj)
511bbf5c878SMichael Roth {
512bbf5c878SMichael Roth     sPAPRDRConnector *drc = SPAPR_DR_CONNECTOR(obj);
513bbf5c878SMichael Roth 
514bbf5c878SMichael Roth     object_property_add_uint32_ptr(obj, "isolation-state",
515bbf5c878SMichael Roth                                    &drc->isolation_state, NULL);
516bbf5c878SMichael Roth     object_property_add_uint32_ptr(obj, "indicator-state",
517bbf5c878SMichael Roth                                    &drc->indicator_state, NULL);
518bbf5c878SMichael Roth     object_property_add_uint32_ptr(obj, "allocation-state",
519bbf5c878SMichael Roth                                    &drc->allocation_state, NULL);
520bbf5c878SMichael Roth     object_property_add_uint32_ptr(obj, "id", &drc->id, NULL);
521bbf5c878SMichael Roth     object_property_add(obj, "index", "uint32", prop_get_index,
522bbf5c878SMichael Roth                         NULL, NULL, NULL, NULL);
523bbf5c878SMichael Roth     object_property_add(obj, "connector_type", "uint32", prop_get_type,
524bbf5c878SMichael Roth                         NULL, NULL, NULL, NULL);
525bbf5c878SMichael Roth     object_property_add_str(obj, "name", prop_get_name, NULL, NULL);
526bbf5c878SMichael Roth     object_property_add(obj, "entity-sense", "uint32", prop_get_entity_sense,
527bbf5c878SMichael Roth                         NULL, NULL, NULL, NULL);
528bbf5c878SMichael Roth     object_property_add(obj, "fdt", "struct", prop_get_fdt,
529bbf5c878SMichael Roth                         NULL, NULL, NULL, NULL);
530bbf5c878SMichael Roth }
531bbf5c878SMichael Roth 
532bbf5c878SMichael Roth static void spapr_dr_connector_class_init(ObjectClass *k, void *data)
533bbf5c878SMichael Roth {
534bbf5c878SMichael Roth     DeviceClass *dk = DEVICE_CLASS(k);
535bbf5c878SMichael Roth     sPAPRDRConnectorClass *drck = SPAPR_DR_CONNECTOR_CLASS(k);
536bbf5c878SMichael Roth 
537bbf5c878SMichael Roth     dk->reset = reset;
538bbf5c878SMichael Roth     dk->realize = realize;
539bbf5c878SMichael Roth     dk->unrealize = unrealize;
540bbf5c878SMichael Roth     drck->set_isolation_state = set_isolation_state;
541bbf5c878SMichael Roth     drck->set_indicator_state = set_indicator_state;
542bbf5c878SMichael Roth     drck->set_allocation_state = set_allocation_state;
543bbf5c878SMichael Roth     drck->get_index = get_index;
544bbf5c878SMichael Roth     drck->get_type = get_type;
545bbf5c878SMichael Roth     drck->get_name = get_name;
546bbf5c878SMichael Roth     drck->get_fdt = get_fdt;
547bbf5c878SMichael Roth     drck->set_configured = set_configured;
548bbf5c878SMichael Roth     drck->entity_sense = entity_sense;
549bbf5c878SMichael Roth     drck->attach = attach;
550bbf5c878SMichael Roth     drck->detach = detach;
551bbf5c878SMichael Roth     drck->release_pending = release_pending;
552bbf5c878SMichael Roth }
553bbf5c878SMichael Roth 
554bbf5c878SMichael Roth static const TypeInfo spapr_dr_connector_info = {
555bbf5c878SMichael Roth     .name          = TYPE_SPAPR_DR_CONNECTOR,
556bbf5c878SMichael Roth     .parent        = TYPE_DEVICE,
557bbf5c878SMichael Roth     .instance_size = sizeof(sPAPRDRConnector),
558bbf5c878SMichael Roth     .instance_init = spapr_dr_connector_instance_init,
559bbf5c878SMichael Roth     .class_size    = sizeof(sPAPRDRConnectorClass),
560bbf5c878SMichael Roth     .class_init    = spapr_dr_connector_class_init,
561bbf5c878SMichael Roth };
562bbf5c878SMichael Roth 
563bbf5c878SMichael Roth static void spapr_drc_register_types(void)
564bbf5c878SMichael Roth {
565bbf5c878SMichael Roth     type_register_static(&spapr_dr_connector_info);
566bbf5c878SMichael Roth }
567bbf5c878SMichael Roth 
568bbf5c878SMichael Roth type_init(spapr_drc_register_types)
569bbf5c878SMichael Roth 
570bbf5c878SMichael Roth /* helper functions for external users */
571bbf5c878SMichael Roth 
572bbf5c878SMichael Roth sPAPRDRConnector *spapr_dr_connector_by_index(uint32_t index)
573bbf5c878SMichael Roth {
574bbf5c878SMichael Roth     Object *obj;
575bbf5c878SMichael Roth     char name[256];
576bbf5c878SMichael Roth 
577bbf5c878SMichael Roth     snprintf(name, sizeof(name), "%s/%x", DRC_CONTAINER_PATH, index);
578bbf5c878SMichael Roth     obj = object_resolve_path(name, NULL);
579bbf5c878SMichael Roth 
580bbf5c878SMichael Roth     return !obj ? NULL : SPAPR_DR_CONNECTOR(obj);
581bbf5c878SMichael Roth }
582bbf5c878SMichael Roth 
583bbf5c878SMichael Roth sPAPRDRConnector *spapr_dr_connector_by_id(sPAPRDRConnectorType type,
584bbf5c878SMichael Roth                                            uint32_t id)
585bbf5c878SMichael Roth {
586bbf5c878SMichael Roth     return spapr_dr_connector_by_index(
587bbf5c878SMichael Roth             (get_type_shift(type) << DRC_INDEX_TYPE_SHIFT) |
588bbf5c878SMichael Roth             (id & DRC_INDEX_ID_MASK));
589bbf5c878SMichael Roth }
590e4b798bbSMichael Roth 
591e4b798bbSMichael Roth /* generate a string the describes the DRC to encode into the
592e4b798bbSMichael Roth  * device tree.
593e4b798bbSMichael Roth  *
594e4b798bbSMichael Roth  * as documented by PAPR+ v2.7, 13.5.2.6 and C.6.1
595e4b798bbSMichael Roth  */
596e4b798bbSMichael Roth static const char *spapr_drc_get_type_str(sPAPRDRConnectorType type)
597e4b798bbSMichael Roth {
598e4b798bbSMichael Roth     switch (type) {
599e4b798bbSMichael Roth     case SPAPR_DR_CONNECTOR_TYPE_CPU:
600e4b798bbSMichael Roth         return "CPU";
601e4b798bbSMichael Roth     case SPAPR_DR_CONNECTOR_TYPE_PHB:
602e4b798bbSMichael Roth         return "PHB";
603e4b798bbSMichael Roth     case SPAPR_DR_CONNECTOR_TYPE_VIO:
604e4b798bbSMichael Roth         return "SLOT";
605e4b798bbSMichael Roth     case SPAPR_DR_CONNECTOR_TYPE_PCI:
606e4b798bbSMichael Roth         return "28";
607e4b798bbSMichael Roth     case SPAPR_DR_CONNECTOR_TYPE_LMB:
608e4b798bbSMichael Roth         return "MEM";
609e4b798bbSMichael Roth     default:
610e4b798bbSMichael Roth         g_assert(false);
611e4b798bbSMichael Roth     }
612e4b798bbSMichael Roth 
613e4b798bbSMichael Roth     return NULL;
614e4b798bbSMichael Roth }
615e4b798bbSMichael Roth 
616e4b798bbSMichael Roth /**
617e4b798bbSMichael Roth  * spapr_drc_populate_dt
618e4b798bbSMichael Roth  *
619e4b798bbSMichael Roth  * @fdt: libfdt device tree
620e4b798bbSMichael Roth  * @path: path in the DT to generate properties
621e4b798bbSMichael Roth  * @owner: parent Object/DeviceState for which to generate DRC
622e4b798bbSMichael Roth  *         descriptions for
623e4b798bbSMichael Roth  * @drc_type_mask: mask of sPAPRDRConnectorType values corresponding
624e4b798bbSMichael Roth  *   to the types of DRCs to generate entries for
625e4b798bbSMichael Roth  *
626e4b798bbSMichael Roth  * generate OF properties to describe DRC topology/indices to guests
627e4b798bbSMichael Roth  *
628e4b798bbSMichael Roth  * as documented in PAPR+ v2.1, 13.5.2
629e4b798bbSMichael Roth  */
630e4b798bbSMichael Roth int spapr_drc_populate_dt(void *fdt, int fdt_offset, Object *owner,
631e4b798bbSMichael Roth                           uint32_t drc_type_mask)
632e4b798bbSMichael Roth {
633e4b798bbSMichael Roth     Object *root_container;
634e4b798bbSMichael Roth     ObjectProperty *prop;
635e4b798bbSMichael Roth     uint32_t drc_count = 0;
636e4b798bbSMichael Roth     GArray *drc_indexes, *drc_power_domains;
637e4b798bbSMichael Roth     GString *drc_names, *drc_types;
638e4b798bbSMichael Roth     int ret;
639e4b798bbSMichael Roth 
640e4b798bbSMichael Roth     /* the first entry of each properties is a 32-bit integer encoding
641e4b798bbSMichael Roth      * the number of elements in the array. we won't know this until
642e4b798bbSMichael Roth      * we complete the iteration through all the matching DRCs, but
643e4b798bbSMichael Roth      * reserve the space now and set the offsets accordingly so we
644e4b798bbSMichael Roth      * can fill them in later.
645e4b798bbSMichael Roth      */
646e4b798bbSMichael Roth     drc_indexes = g_array_new(false, true, sizeof(uint32_t));
647e4b798bbSMichael Roth     drc_indexes = g_array_set_size(drc_indexes, 1);
648e4b798bbSMichael Roth     drc_power_domains = g_array_new(false, true, sizeof(uint32_t));
649e4b798bbSMichael Roth     drc_power_domains = g_array_set_size(drc_power_domains, 1);
650e4b798bbSMichael Roth     drc_names = g_string_set_size(g_string_new(NULL), sizeof(uint32_t));
651e4b798bbSMichael Roth     drc_types = g_string_set_size(g_string_new(NULL), sizeof(uint32_t));
652e4b798bbSMichael Roth 
653e4b798bbSMichael Roth     /* aliases for all DRConnector objects will be rooted in QOM
654e4b798bbSMichael Roth      * composition tree at DRC_CONTAINER_PATH
655e4b798bbSMichael Roth      */
656e4b798bbSMichael Roth     root_container = container_get(object_get_root(), DRC_CONTAINER_PATH);
657e4b798bbSMichael Roth 
658e4b798bbSMichael Roth     QTAILQ_FOREACH(prop, &root_container->properties, node) {
659e4b798bbSMichael Roth         Object *obj;
660e4b798bbSMichael Roth         sPAPRDRConnector *drc;
661e4b798bbSMichael Roth         sPAPRDRConnectorClass *drck;
662e4b798bbSMichael Roth         uint32_t drc_index, drc_power_domain;
663e4b798bbSMichael Roth 
664e4b798bbSMichael Roth         if (!strstart(prop->type, "link<", NULL)) {
665e4b798bbSMichael Roth             continue;
666e4b798bbSMichael Roth         }
667e4b798bbSMichael Roth 
668e4b798bbSMichael Roth         obj = object_property_get_link(root_container, prop->name, NULL);
669e4b798bbSMichael Roth         drc = SPAPR_DR_CONNECTOR(obj);
670e4b798bbSMichael Roth         drck = SPAPR_DR_CONNECTOR_GET_CLASS(drc);
671e4b798bbSMichael Roth 
672e4b798bbSMichael Roth         if (owner && (drc->owner != owner)) {
673e4b798bbSMichael Roth             continue;
674e4b798bbSMichael Roth         }
675e4b798bbSMichael Roth 
676e4b798bbSMichael Roth         if ((drc->type & drc_type_mask) == 0) {
677e4b798bbSMichael Roth             continue;
678e4b798bbSMichael Roth         }
679e4b798bbSMichael Roth 
680e4b798bbSMichael Roth         drc_count++;
681e4b798bbSMichael Roth 
682e4b798bbSMichael Roth         /* ibm,drc-indexes */
683e4b798bbSMichael Roth         drc_index = cpu_to_be32(drck->get_index(drc));
684e4b798bbSMichael Roth         g_array_append_val(drc_indexes, drc_index);
685e4b798bbSMichael Roth 
686e4b798bbSMichael Roth         /* ibm,drc-power-domains */
687e4b798bbSMichael Roth         drc_power_domain = cpu_to_be32(-1);
688e4b798bbSMichael Roth         g_array_append_val(drc_power_domains, drc_power_domain);
689e4b798bbSMichael Roth 
690e4b798bbSMichael Roth         /* ibm,drc-names */
691e4b798bbSMichael Roth         drc_names = g_string_append(drc_names, drck->get_name(drc));
692e4b798bbSMichael Roth         drc_names = g_string_insert_len(drc_names, -1, "\0", 1);
693e4b798bbSMichael Roth 
694e4b798bbSMichael Roth         /* ibm,drc-types */
695e4b798bbSMichael Roth         drc_types = g_string_append(drc_types,
696e4b798bbSMichael Roth                                     spapr_drc_get_type_str(drc->type));
697e4b798bbSMichael Roth         drc_types = g_string_insert_len(drc_types, -1, "\0", 1);
698e4b798bbSMichael Roth     }
699e4b798bbSMichael Roth 
700e4b798bbSMichael Roth     /* now write the drc count into the space we reserved at the
701e4b798bbSMichael Roth      * beginning of the arrays previously
702e4b798bbSMichael Roth      */
703e4b798bbSMichael Roth     *(uint32_t *)drc_indexes->data = cpu_to_be32(drc_count);
704e4b798bbSMichael Roth     *(uint32_t *)drc_power_domains->data = cpu_to_be32(drc_count);
705e4b798bbSMichael Roth     *(uint32_t *)drc_names->str = cpu_to_be32(drc_count);
706e4b798bbSMichael Roth     *(uint32_t *)drc_types->str = cpu_to_be32(drc_count);
707e4b798bbSMichael Roth 
708e4b798bbSMichael Roth     ret = fdt_setprop(fdt, fdt_offset, "ibm,drc-indexes",
709e4b798bbSMichael Roth                       drc_indexes->data,
710e4b798bbSMichael Roth                       drc_indexes->len * sizeof(uint32_t));
711e4b798bbSMichael Roth     if (ret) {
712e4b798bbSMichael Roth         fprintf(stderr, "Couldn't create ibm,drc-indexes property\n");
713e4b798bbSMichael Roth         goto out;
714e4b798bbSMichael Roth     }
715e4b798bbSMichael Roth 
716e4b798bbSMichael Roth     ret = fdt_setprop(fdt, fdt_offset, "ibm,drc-power-domains",
717e4b798bbSMichael Roth                       drc_power_domains->data,
718e4b798bbSMichael Roth                       drc_power_domains->len * sizeof(uint32_t));
719e4b798bbSMichael Roth     if (ret) {
720e4b798bbSMichael Roth         fprintf(stderr, "Couldn't finalize ibm,drc-power-domains property\n");
721e4b798bbSMichael Roth         goto out;
722e4b798bbSMichael Roth     }
723e4b798bbSMichael Roth 
724e4b798bbSMichael Roth     ret = fdt_setprop(fdt, fdt_offset, "ibm,drc-names",
725e4b798bbSMichael Roth                       drc_names->str, drc_names->len);
726e4b798bbSMichael Roth     if (ret) {
727e4b798bbSMichael Roth         fprintf(stderr, "Couldn't finalize ibm,drc-names property\n");
728e4b798bbSMichael Roth         goto out;
729e4b798bbSMichael Roth     }
730e4b798bbSMichael Roth 
731e4b798bbSMichael Roth     ret = fdt_setprop(fdt, fdt_offset, "ibm,drc-types",
732e4b798bbSMichael Roth                       drc_types->str, drc_types->len);
733e4b798bbSMichael Roth     if (ret) {
734e4b798bbSMichael Roth         fprintf(stderr, "Couldn't finalize ibm,drc-types property\n");
735e4b798bbSMichael Roth         goto out;
736e4b798bbSMichael Roth     }
737e4b798bbSMichael Roth 
738e4b798bbSMichael Roth out:
739e4b798bbSMichael Roth     g_array_free(drc_indexes, true);
740e4b798bbSMichael Roth     g_array_free(drc_power_domains, true);
741e4b798bbSMichael Roth     g_string_free(drc_names, true);
742e4b798bbSMichael Roth     g_string_free(drc_types, true);
743e4b798bbSMichael Roth 
744e4b798bbSMichael Roth     return ret;
745e4b798bbSMichael Roth }
746