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