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