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