xref: /qemu/hw/ppc/spapr_drc.c (revision 15c2f669e3fb2bc97f7b42d1871f595c0ac24af8)
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 
179f40eb921SMichael Roth /* has the guest been notified of device attachment? */
180f40eb921SMichael Roth static void set_signalled(sPAPRDRConnector *drc)
181f40eb921SMichael Roth {
182f40eb921SMichael Roth     drc->signalled = true;
183f40eb921SMichael Roth }
184f40eb921SMichael 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) {
272a543a554SEric Blake         visit_type_null(v, NULL, errp);
273bbf5c878SMichael Roth         return;
274bbf5c878SMichael Roth     }
275bbf5c878SMichael Roth 
276bbf5c878SMichael Roth     fdt = drc->fdt;
277bbf5c878SMichael Roth     fdt_offset = drc->fdt_start_offset;
278bbf5c878SMichael Roth     fdt_depth = 0;
279bbf5c878SMichael Roth 
280bbf5c878SMichael Roth     do {
281bbf5c878SMichael Roth         const char *name = NULL;
282bbf5c878SMichael Roth         const struct fdt_property *prop = NULL;
283bbf5c878SMichael Roth         int prop_len = 0, name_len = 0;
284bbf5c878SMichael Roth         uint32_t tag;
285bbf5c878SMichael Roth 
286bbf5c878SMichael Roth         tag = fdt_next_tag(fdt, fdt_offset, &fdt_offset_next);
287bbf5c878SMichael Roth         switch (tag) {
288bbf5c878SMichael Roth         case FDT_BEGIN_NODE:
289bbf5c878SMichael Roth             fdt_depth++;
290bbf5c878SMichael Roth             name = fdt_get_name(fdt, fdt_offset, &name_len);
291337283dfSEric Blake             visit_start_struct(v, name, NULL, 0, &err);
292c75304a1SMarkus Armbruster             if (err) {
293c75304a1SMarkus Armbruster                 error_propagate(errp, err);
294c75304a1SMarkus Armbruster                 return;
295c75304a1SMarkus Armbruster             }
296bbf5c878SMichael Roth             break;
297bbf5c878SMichael Roth         case FDT_END_NODE:
298bbf5c878SMichael Roth             /* shouldn't ever see an FDT_END_NODE before FDT_BEGIN_NODE */
299bbf5c878SMichael Roth             g_assert(fdt_depth > 0);
300*15c2f669SEric Blake             visit_check_struct(v, &err);
301*15c2f669SEric Blake             visit_end_struct(v);
302c75304a1SMarkus Armbruster             if (err) {
303c75304a1SMarkus Armbruster                 error_propagate(errp, err);
304c75304a1SMarkus Armbruster                 return;
305c75304a1SMarkus Armbruster             }
306bbf5c878SMichael Roth             fdt_depth--;
307bbf5c878SMichael Roth             break;
308bbf5c878SMichael Roth         case FDT_PROP: {
309bbf5c878SMichael Roth             int i;
310bbf5c878SMichael Roth             prop = fdt_get_property_by_offset(fdt, fdt_offset, &prop_len);
311bbf5c878SMichael Roth             name = fdt_string(fdt, fdt32_to_cpu(prop->nameoff));
312c75304a1SMarkus Armbruster             visit_start_list(v, name, &err);
313c75304a1SMarkus Armbruster             if (err) {
314c75304a1SMarkus Armbruster                 error_propagate(errp, err);
315c75304a1SMarkus Armbruster                 return;
316bbf5c878SMichael Roth             }
317c75304a1SMarkus Armbruster             for (i = 0; i < prop_len; i++) {
31851e72bc1SEric Blake                 visit_type_uint8(v, NULL, (uint8_t *)&prop->data[i], &err);
319c75304a1SMarkus Armbruster                 if (err) {
320c75304a1SMarkus Armbruster                     error_propagate(errp, err);
321c75304a1SMarkus Armbruster                     return;
322c75304a1SMarkus Armbruster                 }
323c75304a1SMarkus Armbruster             }
32408f9541dSEric Blake             visit_end_list(v);
325bbf5c878SMichael Roth             break;
326bbf5c878SMichael Roth         }
327bbf5c878SMichael Roth         default:
328bbf5c878SMichael Roth             error_setg(&error_abort, "device FDT in unexpected state: %d", tag);
329bbf5c878SMichael Roth         }
330bbf5c878SMichael Roth         fdt_offset = fdt_offset_next;
331bbf5c878SMichael Roth     } while (fdt_depth != 0);
332bbf5c878SMichael Roth }
333bbf5c878SMichael Roth 
334bbf5c878SMichael Roth static void attach(sPAPRDRConnector *drc, DeviceState *d, void *fdt,
335bbf5c878SMichael Roth                    int fdt_start_offset, bool coldplug, Error **errp)
336bbf5c878SMichael Roth {
337bbf5c878SMichael Roth     DPRINTFN("drc: %x, attach", get_index(drc));
338bbf5c878SMichael Roth 
339bbf5c878SMichael Roth     if (drc->isolation_state != SPAPR_DR_ISOLATION_STATE_ISOLATED) {
340bbf5c878SMichael Roth         error_setg(errp, "an attached device is still awaiting release");
341bbf5c878SMichael Roth         return;
342bbf5c878SMichael Roth     }
343bbf5c878SMichael Roth     if (drc->type == SPAPR_DR_CONNECTOR_TYPE_PCI) {
344bbf5c878SMichael Roth         g_assert(drc->allocation_state == SPAPR_DR_ALLOCATION_STATE_USABLE);
345bbf5c878SMichael Roth     }
346bbf5c878SMichael Roth     g_assert(fdt || coldplug);
347bbf5c878SMichael Roth 
348bbf5c878SMichael Roth     /* NOTE: setting initial isolation state to UNISOLATED means we can't
349bbf5c878SMichael Roth      * detach unless guest has a userspace/kernel that moves this state
350bbf5c878SMichael Roth      * back to ISOLATED in response to an unplug event, or this is done
351bbf5c878SMichael Roth      * manually by the admin prior. if we force things while the guest
352bbf5c878SMichael Roth      * may be accessing the device, we can easily crash the guest, so we
353bbf5c878SMichael Roth      * we defer completion of removal in such cases to the reset() hook.
354bbf5c878SMichael Roth      */
355bbf5c878SMichael Roth     if (drc->type == SPAPR_DR_CONNECTOR_TYPE_PCI) {
356bbf5c878SMichael Roth         drc->isolation_state = SPAPR_DR_ISOLATION_STATE_UNISOLATED;
357bbf5c878SMichael Roth     }
358bbf5c878SMichael Roth     drc->indicator_state = SPAPR_DR_INDICATOR_STATE_ACTIVE;
359bbf5c878SMichael Roth 
360bbf5c878SMichael Roth     drc->dev = d;
361bbf5c878SMichael Roth     drc->fdt = fdt;
362bbf5c878SMichael Roth     drc->fdt_start_offset = fdt_start_offset;
363785652dcSLaurent Vivier     drc->configured = coldplug;
364df18b2dbSMichael Roth     /* 'logical' DR resources such as memory/cpus are in some cases treated
365df18b2dbSMichael Roth      * as a pool of resources from which the guest is free to choose from
366df18b2dbSMichael Roth      * based on only a count. for resources that can be assigned in this
367df18b2dbSMichael Roth      * fashion, we must assume the resource is signalled immediately
368df18b2dbSMichael Roth      * since a single hotplug request might make an arbitrary number of
369df18b2dbSMichael Roth      * such attached resources available to the guest, as opposed to
370df18b2dbSMichael Roth      * 'physical' DR resources such as PCI where each device/resource is
371df18b2dbSMichael Roth      * signalled individually.
372df18b2dbSMichael Roth      */
373df18b2dbSMichael Roth     drc->signalled = (drc->type != SPAPR_DR_CONNECTOR_TYPE_PCI)
374df18b2dbSMichael Roth                      ? true : coldplug;
375bbf5c878SMichael Roth 
376bbf5c878SMichael Roth     object_property_add_link(OBJECT(drc), "device",
377bbf5c878SMichael Roth                              object_get_typename(OBJECT(drc->dev)),
378bbf5c878SMichael Roth                              (Object **)(&drc->dev),
379bbf5c878SMichael Roth                              NULL, 0, NULL);
380bbf5c878SMichael Roth }
381bbf5c878SMichael Roth 
382bbf5c878SMichael Roth static void detach(sPAPRDRConnector *drc, DeviceState *d,
383bbf5c878SMichael Roth                    spapr_drc_detach_cb *detach_cb,
384bbf5c878SMichael Roth                    void *detach_cb_opaque, Error **errp)
385bbf5c878SMichael Roth {
386bbf5c878SMichael Roth     DPRINTFN("drc: %x, detach", get_index(drc));
387bbf5c878SMichael Roth 
388bbf5c878SMichael Roth     drc->detach_cb = detach_cb;
389bbf5c878SMichael Roth     drc->detach_cb_opaque = detach_cb_opaque;
390bbf5c878SMichael Roth 
391f40eb921SMichael Roth     /* if we've signalled device presence to the guest, or if the guest
392f40eb921SMichael Roth      * has gone ahead and configured the device (via manually-executed
393f40eb921SMichael Roth      * device add via drmgr in guest, namely), we need to wait
394f40eb921SMichael Roth      * for the guest to quiesce the device before completing detach.
395f40eb921SMichael Roth      * Otherwise, we can assume the guest hasn't seen it and complete the
396f40eb921SMichael Roth      * detach immediately. Note that there is a small race window
397f40eb921SMichael Roth      * just before, or during, configuration, which is this context
398f40eb921SMichael Roth      * refers mainly to fetching the device tree via RTAS.
399f40eb921SMichael Roth      * During this window the device access will be arbitrated by
400f40eb921SMichael Roth      * associated DRC, which will simply fail the RTAS calls as invalid.
401f40eb921SMichael Roth      * This is recoverable within guest and current implementations of
402f40eb921SMichael Roth      * drmgr should be able to cope.
403f40eb921SMichael Roth      */
404f40eb921SMichael Roth     if (!drc->signalled && !drc->configured) {
405f40eb921SMichael Roth         /* if the guest hasn't seen the device we can't rely on it to
406f40eb921SMichael Roth          * set it back to an isolated state via RTAS, so do it here manually
407f40eb921SMichael Roth          */
408f40eb921SMichael Roth         drc->isolation_state = SPAPR_DR_ISOLATION_STATE_ISOLATED;
409f40eb921SMichael Roth     }
410f40eb921SMichael Roth 
411bbf5c878SMichael Roth     if (drc->isolation_state != SPAPR_DR_ISOLATION_STATE_ISOLATED) {
412bbf5c878SMichael Roth         DPRINTFN("awaiting transition to isolated state before removal");
413bbf5c878SMichael Roth         drc->awaiting_release = true;
414bbf5c878SMichael Roth         return;
415bbf5c878SMichael Roth     }
416bbf5c878SMichael Roth 
417bbf5c878SMichael Roth     if (drc->type != SPAPR_DR_CONNECTOR_TYPE_PCI &&
418bbf5c878SMichael Roth         drc->allocation_state != SPAPR_DR_ALLOCATION_STATE_UNUSABLE) {
419bbf5c878SMichael Roth         DPRINTFN("awaiting transition to unusable state before removal");
420bbf5c878SMichael Roth         drc->awaiting_release = true;
421bbf5c878SMichael Roth         return;
422bbf5c878SMichael Roth     }
423bbf5c878SMichael Roth 
424bbf5c878SMichael Roth     drc->indicator_state = SPAPR_DR_INDICATOR_STATE_INACTIVE;
425bbf5c878SMichael Roth 
426bbf5c878SMichael Roth     if (drc->detach_cb) {
427bbf5c878SMichael Roth         drc->detach_cb(drc->dev, drc->detach_cb_opaque);
428bbf5c878SMichael Roth     }
429bbf5c878SMichael Roth 
430bbf5c878SMichael Roth     drc->awaiting_release = false;
431bbf5c878SMichael Roth     g_free(drc->fdt);
432bbf5c878SMichael Roth     drc->fdt = NULL;
433bbf5c878SMichael Roth     drc->fdt_start_offset = 0;
434bbf5c878SMichael Roth     object_property_del(OBJECT(drc), "device", NULL);
435bbf5c878SMichael Roth     drc->dev = NULL;
436bbf5c878SMichael Roth     drc->detach_cb = NULL;
437bbf5c878SMichael Roth     drc->detach_cb_opaque = NULL;
438bbf5c878SMichael Roth }
439bbf5c878SMichael Roth 
440bbf5c878SMichael Roth static bool release_pending(sPAPRDRConnector *drc)
441bbf5c878SMichael Roth {
442bbf5c878SMichael Roth     return drc->awaiting_release;
443bbf5c878SMichael Roth }
444bbf5c878SMichael Roth 
445bbf5c878SMichael Roth static void reset(DeviceState *d)
446bbf5c878SMichael Roth {
447bbf5c878SMichael Roth     sPAPRDRConnector *drc = SPAPR_DR_CONNECTOR(d);
448bbf5c878SMichael Roth     sPAPRDRConnectorClass *drck = SPAPR_DR_CONNECTOR_GET_CLASS(drc);
449f40eb921SMichael Roth     sPAPRDREntitySense state;
450bbf5c878SMichael Roth 
451bbf5c878SMichael Roth     DPRINTFN("drc reset: %x", drck->get_index(drc));
452bbf5c878SMichael Roth     /* immediately upon reset we can safely assume DRCs whose devices
453bbf5c878SMichael Roth      * are pending removal can be safely removed, and that they will
454bbf5c878SMichael Roth      * subsequently be left in an ISOLATED state. move the DRC to this
455bbf5c878SMichael Roth      * state in these cases (which will in turn complete any pending
456bbf5c878SMichael Roth      * device removals)
457bbf5c878SMichael Roth      */
458bbf5c878SMichael Roth     if (drc->awaiting_release) {
459bbf5c878SMichael Roth         drck->set_isolation_state(drc, SPAPR_DR_ISOLATION_STATE_ISOLATED);
460bbf5c878SMichael Roth         /* generally this should also finalize the removal, but if the device
461bbf5c878SMichael Roth          * hasn't yet been configured we normally defer removal under the
462bbf5c878SMichael Roth          * assumption that this transition is taking place as part of device
463bbf5c878SMichael Roth          * configuration. so check if we're still waiting after this, and
464bbf5c878SMichael Roth          * force removal if we are
465bbf5c878SMichael Roth          */
466bbf5c878SMichael Roth         if (drc->awaiting_release) {
467bbf5c878SMichael Roth             drck->detach(drc, DEVICE(drc->dev), drc->detach_cb,
468bbf5c878SMichael Roth                          drc->detach_cb_opaque, NULL);
469bbf5c878SMichael Roth         }
470bbf5c878SMichael Roth 
471bbf5c878SMichael Roth         /* non-PCI devices may be awaiting a transition to UNUSABLE */
472bbf5c878SMichael Roth         if (drc->type != SPAPR_DR_CONNECTOR_TYPE_PCI &&
473bbf5c878SMichael Roth             drc->awaiting_release) {
474bbf5c878SMichael Roth             drck->set_allocation_state(drc, SPAPR_DR_ALLOCATION_STATE_UNUSABLE);
475bbf5c878SMichael Roth         }
476bbf5c878SMichael Roth     }
477f40eb921SMichael Roth 
478f40eb921SMichael Roth     drck->entity_sense(drc, &state);
479f40eb921SMichael Roth     if (state == SPAPR_DR_ENTITY_SENSE_PRESENT) {
480f40eb921SMichael Roth         drck->set_signalled(drc);
481f40eb921SMichael Roth     }
482bbf5c878SMichael Roth }
483bbf5c878SMichael Roth 
484bbf5c878SMichael Roth static void realize(DeviceState *d, Error **errp)
485bbf5c878SMichael Roth {
486bbf5c878SMichael Roth     sPAPRDRConnector *drc = SPAPR_DR_CONNECTOR(d);
487bbf5c878SMichael Roth     sPAPRDRConnectorClass *drck = SPAPR_DR_CONNECTOR_GET_CLASS(drc);
488bbf5c878SMichael Roth     Object *root_container;
489bbf5c878SMichael Roth     char link_name[256];
490bbf5c878SMichael Roth     gchar *child_name;
491bbf5c878SMichael Roth     Error *err = NULL;
492bbf5c878SMichael Roth 
493bbf5c878SMichael Roth     DPRINTFN("drc realize: %x", drck->get_index(drc));
494bbf5c878SMichael Roth     /* NOTE: we do this as part of realize/unrealize due to the fact
495bbf5c878SMichael Roth      * that the guest will communicate with the DRC via RTAS calls
496bbf5c878SMichael Roth      * referencing the global DRC index. By unlinking the DRC
497bbf5c878SMichael Roth      * from DRC_CONTAINER_PATH/<drc_index> we effectively make it
498bbf5c878SMichael Roth      * inaccessible by the guest, since lookups rely on this path
499bbf5c878SMichael Roth      * existing in the composition tree
500bbf5c878SMichael Roth      */
501bbf5c878SMichael Roth     root_container = container_get(object_get_root(), DRC_CONTAINER_PATH);
502bbf5c878SMichael Roth     snprintf(link_name, sizeof(link_name), "%x", drck->get_index(drc));
503bbf5c878SMichael Roth     child_name = object_get_canonical_path_component(OBJECT(drc));
504bbf5c878SMichael Roth     DPRINTFN("drc child name: %s", child_name);
505bbf5c878SMichael Roth     object_property_add_alias(root_container, link_name,
506bbf5c878SMichael Roth                               drc->owner, child_name, &err);
507bbf5c878SMichael Roth     if (err) {
5084fffeb5eSMarkus Armbruster         error_report_err(err);
509bbf5c878SMichael Roth         object_unref(OBJECT(drc));
510bbf5c878SMichael Roth     }
511586d2142SGonglei     g_free(child_name);
512bbf5c878SMichael Roth     DPRINTFN("drc realize complete");
513bbf5c878SMichael Roth }
514bbf5c878SMichael Roth 
515bbf5c878SMichael Roth static void unrealize(DeviceState *d, Error **errp)
516bbf5c878SMichael Roth {
517bbf5c878SMichael Roth     sPAPRDRConnector *drc = SPAPR_DR_CONNECTOR(d);
518bbf5c878SMichael Roth     sPAPRDRConnectorClass *drck = SPAPR_DR_CONNECTOR_GET_CLASS(drc);
519bbf5c878SMichael Roth     Object *root_container;
520bbf5c878SMichael Roth     char name[256];
521bbf5c878SMichael Roth     Error *err = NULL;
522bbf5c878SMichael Roth 
523bbf5c878SMichael Roth     DPRINTFN("drc unrealize: %x", drck->get_index(drc));
524bbf5c878SMichael Roth     root_container = container_get(object_get_root(), DRC_CONTAINER_PATH);
525bbf5c878SMichael Roth     snprintf(name, sizeof(name), "%x", drck->get_index(drc));
526bbf5c878SMichael Roth     object_property_del(root_container, name, &err);
527bbf5c878SMichael Roth     if (err) {
5284fffeb5eSMarkus Armbruster         error_report_err(err);
529bbf5c878SMichael Roth         object_unref(OBJECT(drc));
530bbf5c878SMichael Roth     }
531bbf5c878SMichael Roth }
532bbf5c878SMichael Roth 
533bbf5c878SMichael Roth sPAPRDRConnector *spapr_dr_connector_new(Object *owner,
534bbf5c878SMichael Roth                                          sPAPRDRConnectorType type,
535bbf5c878SMichael Roth                                          uint32_t id)
536bbf5c878SMichael Roth {
537bbf5c878SMichael Roth     sPAPRDRConnector *drc =
538bbf5c878SMichael Roth         SPAPR_DR_CONNECTOR(object_new(TYPE_SPAPR_DR_CONNECTOR));
53994649d42SDavid Gibson     char *prop_name;
540bbf5c878SMichael Roth 
541bbf5c878SMichael Roth     g_assert(type);
542bbf5c878SMichael Roth 
543bbf5c878SMichael Roth     drc->type = type;
544bbf5c878SMichael Roth     drc->id = id;
545bbf5c878SMichael Roth     drc->owner = owner;
54694649d42SDavid Gibson     prop_name = g_strdup_printf("dr-connector[%"PRIu32"]", get_index(drc));
54794649d42SDavid Gibson     object_property_add_child(owner, prop_name, OBJECT(drc), NULL);
548bbf5c878SMichael Roth     object_property_set_bool(OBJECT(drc), true, "realized", NULL);
54994649d42SDavid Gibson     g_free(prop_name);
550bbf5c878SMichael Roth 
551bbf5c878SMichael Roth     /* human-readable name for a DRC to encode into the DT
552bbf5c878SMichael Roth      * description. this is mainly only used within a guest in place
553bbf5c878SMichael Roth      * of the unique DRC index.
554bbf5c878SMichael Roth      *
555bbf5c878SMichael Roth      * in the case of VIO/PCI devices, it corresponds to a
556bbf5c878SMichael Roth      * "location code" that maps a logical device/function (DRC index)
557bbf5c878SMichael Roth      * to a physical (or virtual in the case of VIO) location in the
558bbf5c878SMichael Roth      * system by chaining together the "location label" for each
559bbf5c878SMichael Roth      * encapsulating component.
560bbf5c878SMichael Roth      *
561bbf5c878SMichael Roth      * since this is more to do with diagnosing physical hardware
562bbf5c878SMichael Roth      * issues than guest compatibility, we choose location codes/DRC
563bbf5c878SMichael Roth      * names that adhere to the documented format, but avoid encoding
564bbf5c878SMichael Roth      * the entire topology information into the label/code, instead
565bbf5c878SMichael Roth      * just using the location codes based on the labels for the
566bbf5c878SMichael Roth      * endpoints (VIO/PCI adaptor connectors), which is basically
567bbf5c878SMichael Roth      * just "C" followed by an integer ID.
568bbf5c878SMichael Roth      *
569bbf5c878SMichael Roth      * DRC names as documented by PAPR+ v2.7, 13.5.2.4
570bbf5c878SMichael Roth      * location codes as documented by PAPR+ v2.7, 12.3.1.5
571bbf5c878SMichael Roth      */
572bbf5c878SMichael Roth     switch (drc->type) {
573bbf5c878SMichael Roth     case SPAPR_DR_CONNECTOR_TYPE_CPU:
574bbf5c878SMichael Roth         drc->name = g_strdup_printf("CPU %d", id);
575bbf5c878SMichael Roth         break;
576bbf5c878SMichael Roth     case SPAPR_DR_CONNECTOR_TYPE_PHB:
577bbf5c878SMichael Roth         drc->name = g_strdup_printf("PHB %d", id);
578bbf5c878SMichael Roth         break;
579bbf5c878SMichael Roth     case SPAPR_DR_CONNECTOR_TYPE_VIO:
580bbf5c878SMichael Roth     case SPAPR_DR_CONNECTOR_TYPE_PCI:
581bbf5c878SMichael Roth         drc->name = g_strdup_printf("C%d", id);
582bbf5c878SMichael Roth         break;
583bbf5c878SMichael Roth     case SPAPR_DR_CONNECTOR_TYPE_LMB:
584bbf5c878SMichael Roth         drc->name = g_strdup_printf("LMB %d", id);
585bbf5c878SMichael Roth         break;
586bbf5c878SMichael Roth     default:
587bbf5c878SMichael Roth         g_assert(false);
588bbf5c878SMichael Roth     }
589bbf5c878SMichael Roth 
590bbf5c878SMichael Roth     /* PCI slot always start in a USABLE state, and stay there */
591bbf5c878SMichael Roth     if (drc->type == SPAPR_DR_CONNECTOR_TYPE_PCI) {
592bbf5c878SMichael Roth         drc->allocation_state = SPAPR_DR_ALLOCATION_STATE_USABLE;
593bbf5c878SMichael Roth     }
594bbf5c878SMichael Roth 
595bbf5c878SMichael Roth     return drc;
596bbf5c878SMichael Roth }
597bbf5c878SMichael Roth 
598bbf5c878SMichael Roth static void spapr_dr_connector_instance_init(Object *obj)
599bbf5c878SMichael Roth {
600bbf5c878SMichael Roth     sPAPRDRConnector *drc = SPAPR_DR_CONNECTOR(obj);
601bbf5c878SMichael Roth 
602bbf5c878SMichael Roth     object_property_add_uint32_ptr(obj, "isolation-state",
603bbf5c878SMichael Roth                                    &drc->isolation_state, NULL);
604bbf5c878SMichael Roth     object_property_add_uint32_ptr(obj, "indicator-state",
605bbf5c878SMichael Roth                                    &drc->indicator_state, NULL);
606bbf5c878SMichael Roth     object_property_add_uint32_ptr(obj, "allocation-state",
607bbf5c878SMichael Roth                                    &drc->allocation_state, NULL);
608bbf5c878SMichael Roth     object_property_add_uint32_ptr(obj, "id", &drc->id, NULL);
609bbf5c878SMichael Roth     object_property_add(obj, "index", "uint32", prop_get_index,
610bbf5c878SMichael Roth                         NULL, NULL, NULL, NULL);
611bbf5c878SMichael Roth     object_property_add(obj, "connector_type", "uint32", prop_get_type,
612bbf5c878SMichael Roth                         NULL, NULL, NULL, NULL);
613bbf5c878SMichael Roth     object_property_add_str(obj, "name", prop_get_name, NULL, NULL);
614bbf5c878SMichael Roth     object_property_add(obj, "entity-sense", "uint32", prop_get_entity_sense,
615bbf5c878SMichael Roth                         NULL, NULL, NULL, NULL);
616bbf5c878SMichael Roth     object_property_add(obj, "fdt", "struct", prop_get_fdt,
617bbf5c878SMichael Roth                         NULL, NULL, NULL, NULL);
618bbf5c878SMichael Roth }
619bbf5c878SMichael Roth 
620bbf5c878SMichael Roth static void spapr_dr_connector_class_init(ObjectClass *k, void *data)
621bbf5c878SMichael Roth {
622bbf5c878SMichael Roth     DeviceClass *dk = DEVICE_CLASS(k);
623bbf5c878SMichael Roth     sPAPRDRConnectorClass *drck = SPAPR_DR_CONNECTOR_CLASS(k);
624bbf5c878SMichael Roth 
625bbf5c878SMichael Roth     dk->reset = reset;
626bbf5c878SMichael Roth     dk->realize = realize;
627bbf5c878SMichael Roth     dk->unrealize = unrealize;
628bbf5c878SMichael Roth     drck->set_isolation_state = set_isolation_state;
629bbf5c878SMichael Roth     drck->set_indicator_state = set_indicator_state;
630bbf5c878SMichael Roth     drck->set_allocation_state = set_allocation_state;
631bbf5c878SMichael Roth     drck->get_index = get_index;
632bbf5c878SMichael Roth     drck->get_type = get_type;
633bbf5c878SMichael Roth     drck->get_name = get_name;
634bbf5c878SMichael Roth     drck->get_fdt = get_fdt;
635bbf5c878SMichael Roth     drck->set_configured = set_configured;
636bbf5c878SMichael Roth     drck->entity_sense = entity_sense;
637bbf5c878SMichael Roth     drck->attach = attach;
638bbf5c878SMichael Roth     drck->detach = detach;
639bbf5c878SMichael Roth     drck->release_pending = release_pending;
640f40eb921SMichael Roth     drck->set_signalled = set_signalled;
641c401ae8cSMarkus Armbruster     /*
642c401ae8cSMarkus Armbruster      * Reason: it crashes FIXME find and document the real reason
643c401ae8cSMarkus Armbruster      */
644c401ae8cSMarkus Armbruster     dk->cannot_instantiate_with_device_add_yet = true;
645bbf5c878SMichael Roth }
646bbf5c878SMichael Roth 
647bbf5c878SMichael Roth static const TypeInfo spapr_dr_connector_info = {
648bbf5c878SMichael Roth     .name          = TYPE_SPAPR_DR_CONNECTOR,
649bbf5c878SMichael Roth     .parent        = TYPE_DEVICE,
650bbf5c878SMichael Roth     .instance_size = sizeof(sPAPRDRConnector),
651bbf5c878SMichael Roth     .instance_init = spapr_dr_connector_instance_init,
652bbf5c878SMichael Roth     .class_size    = sizeof(sPAPRDRConnectorClass),
653bbf5c878SMichael Roth     .class_init    = spapr_dr_connector_class_init,
654bbf5c878SMichael Roth };
655bbf5c878SMichael Roth 
656bbf5c878SMichael Roth static void spapr_drc_register_types(void)
657bbf5c878SMichael Roth {
658bbf5c878SMichael Roth     type_register_static(&spapr_dr_connector_info);
659bbf5c878SMichael Roth }
660bbf5c878SMichael Roth 
661bbf5c878SMichael Roth type_init(spapr_drc_register_types)
662bbf5c878SMichael Roth 
663bbf5c878SMichael Roth /* helper functions for external users */
664bbf5c878SMichael Roth 
665bbf5c878SMichael Roth sPAPRDRConnector *spapr_dr_connector_by_index(uint32_t index)
666bbf5c878SMichael Roth {
667bbf5c878SMichael Roth     Object *obj;
668bbf5c878SMichael Roth     char name[256];
669bbf5c878SMichael Roth 
670bbf5c878SMichael Roth     snprintf(name, sizeof(name), "%s/%x", DRC_CONTAINER_PATH, index);
671bbf5c878SMichael Roth     obj = object_resolve_path(name, NULL);
672bbf5c878SMichael Roth 
673bbf5c878SMichael Roth     return !obj ? NULL : SPAPR_DR_CONNECTOR(obj);
674bbf5c878SMichael Roth }
675bbf5c878SMichael Roth 
676bbf5c878SMichael Roth sPAPRDRConnector *spapr_dr_connector_by_id(sPAPRDRConnectorType type,
677bbf5c878SMichael Roth                                            uint32_t id)
678bbf5c878SMichael Roth {
679bbf5c878SMichael Roth     return spapr_dr_connector_by_index(
680bbf5c878SMichael Roth             (get_type_shift(type) << DRC_INDEX_TYPE_SHIFT) |
681bbf5c878SMichael Roth             (id & DRC_INDEX_ID_MASK));
682bbf5c878SMichael Roth }
683e4b798bbSMichael Roth 
684e4b798bbSMichael Roth /* generate a string the describes the DRC to encode into the
685e4b798bbSMichael Roth  * device tree.
686e4b798bbSMichael Roth  *
687e4b798bbSMichael Roth  * as documented by PAPR+ v2.7, 13.5.2.6 and C.6.1
688e4b798bbSMichael Roth  */
689e4b798bbSMichael Roth static const char *spapr_drc_get_type_str(sPAPRDRConnectorType type)
690e4b798bbSMichael Roth {
691e4b798bbSMichael Roth     switch (type) {
692e4b798bbSMichael Roth     case SPAPR_DR_CONNECTOR_TYPE_CPU:
693e4b798bbSMichael Roth         return "CPU";
694e4b798bbSMichael Roth     case SPAPR_DR_CONNECTOR_TYPE_PHB:
695e4b798bbSMichael Roth         return "PHB";
696e4b798bbSMichael Roth     case SPAPR_DR_CONNECTOR_TYPE_VIO:
697e4b798bbSMichael Roth         return "SLOT";
698e4b798bbSMichael Roth     case SPAPR_DR_CONNECTOR_TYPE_PCI:
699e4b798bbSMichael Roth         return "28";
700e4b798bbSMichael Roth     case SPAPR_DR_CONNECTOR_TYPE_LMB:
701e4b798bbSMichael Roth         return "MEM";
702e4b798bbSMichael Roth     default:
703e4b798bbSMichael Roth         g_assert(false);
704e4b798bbSMichael Roth     }
705e4b798bbSMichael Roth 
706e4b798bbSMichael Roth     return NULL;
707e4b798bbSMichael Roth }
708e4b798bbSMichael Roth 
709e4b798bbSMichael Roth /**
710e4b798bbSMichael Roth  * spapr_drc_populate_dt
711e4b798bbSMichael Roth  *
712e4b798bbSMichael Roth  * @fdt: libfdt device tree
713e4b798bbSMichael Roth  * @path: path in the DT to generate properties
714e4b798bbSMichael Roth  * @owner: parent Object/DeviceState for which to generate DRC
715e4b798bbSMichael Roth  *         descriptions for
716e4b798bbSMichael Roth  * @drc_type_mask: mask of sPAPRDRConnectorType values corresponding
717e4b798bbSMichael Roth  *   to the types of DRCs to generate entries for
718e4b798bbSMichael Roth  *
719e4b798bbSMichael Roth  * generate OF properties to describe DRC topology/indices to guests
720e4b798bbSMichael Roth  *
721e4b798bbSMichael Roth  * as documented in PAPR+ v2.1, 13.5.2
722e4b798bbSMichael Roth  */
723e4b798bbSMichael Roth int spapr_drc_populate_dt(void *fdt, int fdt_offset, Object *owner,
724e4b798bbSMichael Roth                           uint32_t drc_type_mask)
725e4b798bbSMichael Roth {
726e4b798bbSMichael Roth     Object *root_container;
727e4b798bbSMichael Roth     ObjectProperty *prop;
7287746abd8SDaniel P. Berrange     ObjectPropertyIterator iter;
729e4b798bbSMichael Roth     uint32_t drc_count = 0;
730e4b798bbSMichael Roth     GArray *drc_indexes, *drc_power_domains;
731e4b798bbSMichael Roth     GString *drc_names, *drc_types;
732e4b798bbSMichael Roth     int ret;
733e4b798bbSMichael Roth 
734e4b798bbSMichael Roth     /* the first entry of each properties is a 32-bit integer encoding
735e4b798bbSMichael Roth      * the number of elements in the array. we won't know this until
736e4b798bbSMichael Roth      * we complete the iteration through all the matching DRCs, but
737e4b798bbSMichael Roth      * reserve the space now and set the offsets accordingly so we
738e4b798bbSMichael Roth      * can fill them in later.
739e4b798bbSMichael Roth      */
740e4b798bbSMichael Roth     drc_indexes = g_array_new(false, true, sizeof(uint32_t));
741e4b798bbSMichael Roth     drc_indexes = g_array_set_size(drc_indexes, 1);
742e4b798bbSMichael Roth     drc_power_domains = g_array_new(false, true, sizeof(uint32_t));
743e4b798bbSMichael Roth     drc_power_domains = g_array_set_size(drc_power_domains, 1);
744e4b798bbSMichael Roth     drc_names = g_string_set_size(g_string_new(NULL), sizeof(uint32_t));
745e4b798bbSMichael Roth     drc_types = g_string_set_size(g_string_new(NULL), sizeof(uint32_t));
746e4b798bbSMichael Roth 
747e4b798bbSMichael Roth     /* aliases for all DRConnector objects will be rooted in QOM
748e4b798bbSMichael Roth      * composition tree at DRC_CONTAINER_PATH
749e4b798bbSMichael Roth      */
750e4b798bbSMichael Roth     root_container = container_get(object_get_root(), DRC_CONTAINER_PATH);
751e4b798bbSMichael Roth 
7527746abd8SDaniel P. Berrange     object_property_iter_init(&iter, root_container);
7537746abd8SDaniel P. Berrange     while ((prop = object_property_iter_next(&iter))) {
754e4b798bbSMichael Roth         Object *obj;
755e4b798bbSMichael Roth         sPAPRDRConnector *drc;
756e4b798bbSMichael Roth         sPAPRDRConnectorClass *drck;
757e4b798bbSMichael Roth         uint32_t drc_index, drc_power_domain;
758e4b798bbSMichael Roth 
759e4b798bbSMichael Roth         if (!strstart(prop->type, "link<", NULL)) {
760e4b798bbSMichael Roth             continue;
761e4b798bbSMichael Roth         }
762e4b798bbSMichael Roth 
763e4b798bbSMichael Roth         obj = object_property_get_link(root_container, prop->name, NULL);
764e4b798bbSMichael Roth         drc = SPAPR_DR_CONNECTOR(obj);
765e4b798bbSMichael Roth         drck = SPAPR_DR_CONNECTOR_GET_CLASS(drc);
766e4b798bbSMichael Roth 
767e4b798bbSMichael Roth         if (owner && (drc->owner != owner)) {
768e4b798bbSMichael Roth             continue;
769e4b798bbSMichael Roth         }
770e4b798bbSMichael Roth 
771e4b798bbSMichael Roth         if ((drc->type & drc_type_mask) == 0) {
772e4b798bbSMichael Roth             continue;
773e4b798bbSMichael Roth         }
774e4b798bbSMichael Roth 
775e4b798bbSMichael Roth         drc_count++;
776e4b798bbSMichael Roth 
777e4b798bbSMichael Roth         /* ibm,drc-indexes */
778e4b798bbSMichael Roth         drc_index = cpu_to_be32(drck->get_index(drc));
779e4b798bbSMichael Roth         g_array_append_val(drc_indexes, drc_index);
780e4b798bbSMichael Roth 
781e4b798bbSMichael Roth         /* ibm,drc-power-domains */
782e4b798bbSMichael Roth         drc_power_domain = cpu_to_be32(-1);
783e4b798bbSMichael Roth         g_array_append_val(drc_power_domains, drc_power_domain);
784e4b798bbSMichael Roth 
785e4b798bbSMichael Roth         /* ibm,drc-names */
786e4b798bbSMichael Roth         drc_names = g_string_append(drc_names, drck->get_name(drc));
787e4b798bbSMichael Roth         drc_names = g_string_insert_len(drc_names, -1, "\0", 1);
788e4b798bbSMichael Roth 
789e4b798bbSMichael Roth         /* ibm,drc-types */
790e4b798bbSMichael Roth         drc_types = g_string_append(drc_types,
791e4b798bbSMichael Roth                                     spapr_drc_get_type_str(drc->type));
792e4b798bbSMichael Roth         drc_types = g_string_insert_len(drc_types, -1, "\0", 1);
793e4b798bbSMichael Roth     }
794e4b798bbSMichael Roth 
795e4b798bbSMichael Roth     /* now write the drc count into the space we reserved at the
796e4b798bbSMichael Roth      * beginning of the arrays previously
797e4b798bbSMichael Roth      */
798e4b798bbSMichael Roth     *(uint32_t *)drc_indexes->data = cpu_to_be32(drc_count);
799e4b798bbSMichael Roth     *(uint32_t *)drc_power_domains->data = cpu_to_be32(drc_count);
800e4b798bbSMichael Roth     *(uint32_t *)drc_names->str = cpu_to_be32(drc_count);
801e4b798bbSMichael Roth     *(uint32_t *)drc_types->str = cpu_to_be32(drc_count);
802e4b798bbSMichael Roth 
803e4b798bbSMichael Roth     ret = fdt_setprop(fdt, fdt_offset, "ibm,drc-indexes",
804e4b798bbSMichael Roth                       drc_indexes->data,
805e4b798bbSMichael Roth                       drc_indexes->len * sizeof(uint32_t));
806e4b798bbSMichael Roth     if (ret) {
807e4b798bbSMichael Roth         fprintf(stderr, "Couldn't create ibm,drc-indexes property\n");
808e4b798bbSMichael Roth         goto out;
809e4b798bbSMichael Roth     }
810e4b798bbSMichael Roth 
811e4b798bbSMichael Roth     ret = fdt_setprop(fdt, fdt_offset, "ibm,drc-power-domains",
812e4b798bbSMichael Roth                       drc_power_domains->data,
813e4b798bbSMichael Roth                       drc_power_domains->len * sizeof(uint32_t));
814e4b798bbSMichael Roth     if (ret) {
815e4b798bbSMichael Roth         fprintf(stderr, "Couldn't finalize ibm,drc-power-domains property\n");
816e4b798bbSMichael Roth         goto out;
817e4b798bbSMichael Roth     }
818e4b798bbSMichael Roth 
819e4b798bbSMichael Roth     ret = fdt_setprop(fdt, fdt_offset, "ibm,drc-names",
820e4b798bbSMichael Roth                       drc_names->str, drc_names->len);
821e4b798bbSMichael Roth     if (ret) {
822e4b798bbSMichael Roth         fprintf(stderr, "Couldn't finalize ibm,drc-names property\n");
823e4b798bbSMichael Roth         goto out;
824e4b798bbSMichael Roth     }
825e4b798bbSMichael Roth 
826e4b798bbSMichael Roth     ret = fdt_setprop(fdt, fdt_offset, "ibm,drc-types",
827e4b798bbSMichael Roth                       drc_types->str, drc_types->len);
828e4b798bbSMichael Roth     if (ret) {
829e4b798bbSMichael Roth         fprintf(stderr, "Couldn't finalize ibm,drc-types property\n");
830e4b798bbSMichael Roth         goto out;
831e4b798bbSMichael Roth     }
832e4b798bbSMichael Roth 
833e4b798bbSMichael Roth out:
834e4b798bbSMichael Roth     g_array_free(drc_indexes, true);
835e4b798bbSMichael Roth     g_array_free(drc_power_domains, true);
836e4b798bbSMichael Roth     g_string_free(drc_names, true);
837e4b798bbSMichael Roth     g_string_free(drc_types, true);
838e4b798bbSMichael Roth 
839e4b798bbSMichael Roth     return ret;
840e4b798bbSMichael Roth }
841