xref: /qemu/hw/ppc/spapr_vio.c (revision a005b3ef50439b5bc6b2eb0b5bda8e8c7c2368bf)
14040ab72SDavid Gibson /*
24040ab72SDavid Gibson  * QEMU sPAPR VIO code
34040ab72SDavid Gibson  *
44040ab72SDavid Gibson  * Copyright (c) 2010 David Gibson, IBM Corporation <dwg@au1.ibm.com>
54040ab72SDavid Gibson  * Based on the s390 virtio bus code:
64040ab72SDavid Gibson  * Copyright (c) 2009 Alexander Graf <agraf@suse.de>
74040ab72SDavid Gibson  *
84040ab72SDavid Gibson  * This library is free software; you can redistribute it and/or
94040ab72SDavid Gibson  * modify it under the terms of the GNU Lesser General Public
104040ab72SDavid Gibson  * License as published by the Free Software Foundation; either
114040ab72SDavid Gibson  * version 2 of the License, or (at your option) any later version.
124040ab72SDavid Gibson  *
134040ab72SDavid Gibson  * This library is distributed in the hope that it will be useful,
144040ab72SDavid Gibson  * but WITHOUT ANY WARRANTY; without even the implied warranty of
154040ab72SDavid Gibson  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
164040ab72SDavid Gibson  * Lesser General Public License for more details.
174040ab72SDavid Gibson  *
184040ab72SDavid Gibson  * You should have received a copy of the GNU Lesser General Public
194040ab72SDavid Gibson  * License along with this library; if not, see <http://www.gnu.org/licenses/>.
204040ab72SDavid Gibson  */
214040ab72SDavid Gibson 
220d75590dSPeter Maydell #include "qemu/osdep.h"
2383c9f4caSPaolo Bonzini #include "hw/hw.h"
249c17d615SPaolo Bonzini #include "sysemu/sysemu.h"
2583c9f4caSPaolo Bonzini #include "hw/boards.h"
2683c9f4caSPaolo Bonzini #include "hw/loader.h"
274040ab72SDavid Gibson #include "elf.h"
284040ab72SDavid Gibson #include "hw/sysbus.h"
299c17d615SPaolo Bonzini #include "sysemu/kvm.h"
309c17d615SPaolo Bonzini #include "sysemu/device_tree.h"
31b45d63b6SBen Herrenschmidt #include "kvm_ppc.h"
324040ab72SDavid Gibson 
330d09e41aSPaolo Bonzini #include "hw/ppc/spapr.h"
340d09e41aSPaolo Bonzini #include "hw/ppc/spapr_vio.h"
350d09e41aSPaolo Bonzini #include "hw/ppc/xics.h"
364040ab72SDavid Gibson 
374040ab72SDavid Gibson #include <libfdt.h>
384040ab72SDavid Gibson 
394040ab72SDavid Gibson /* #define DEBUG_SPAPR */
404040ab72SDavid Gibson 
414040ab72SDavid Gibson #ifdef DEBUG_SPAPR
42f6bda9cbSPeter Maydell #define DPRINTF(fmt, ...) \
434040ab72SDavid Gibson     do { fprintf(stderr, fmt, ## __VA_ARGS__); } while (0)
444040ab72SDavid Gibson #else
45f6bda9cbSPeter Maydell #define DPRINTF(fmt, ...) \
464040ab72SDavid Gibson     do { } while (0)
474040ab72SDavid Gibson #endif
484040ab72SDavid Gibson 
493cb75a7cSPaolo Bonzini static Property spapr_vio_props[] = {
50a307d594SAlexey Kardashevskiy     DEFINE_PROP_UINT32("irq", VIOsPAPRDevice, irq, 0), \
513cb75a7cSPaolo Bonzini     DEFINE_PROP_END_OF_LIST(),
523cb75a7cSPaolo Bonzini };
533cb75a7cSPaolo Bonzini 
54c4eda5b7SDavid Gibson static char *spapr_vio_get_dev_name(DeviceState *qdev)
55c4eda5b7SDavid Gibson {
56c4eda5b7SDavid Gibson     VIOsPAPRDevice *dev = VIO_SPAPR_DEVICE(qdev);
57c4eda5b7SDavid Gibson     VIOsPAPRDeviceClass *pc = VIO_SPAPR_DEVICE_GET_CLASS(dev);
58c4eda5b7SDavid Gibson     char *name;
59c4eda5b7SDavid Gibson 
60c4eda5b7SDavid Gibson     /* Device tree style name device@reg */
61c4eda5b7SDavid Gibson     name = g_strdup_printf("%s@%x", pc->dt_name, dev->reg);
62c4eda5b7SDavid Gibson 
63c4eda5b7SDavid Gibson     return name;
64c4eda5b7SDavid Gibson }
65c4eda5b7SDavid Gibson 
66c4eda5b7SDavid Gibson static void spapr_vio_bus_class_init(ObjectClass *klass, void *data)
67c4eda5b7SDavid Gibson {
68c4eda5b7SDavid Gibson     BusClass *k = BUS_CLASS(klass);
69c4eda5b7SDavid Gibson 
70c4eda5b7SDavid Gibson     k->get_dev_path = spapr_vio_get_dev_name;
715a06393fSAlexey Kardashevskiy     k->get_fw_dev_path = spapr_vio_get_dev_name;
72c4eda5b7SDavid Gibson }
73c4eda5b7SDavid Gibson 
740d936928SAnthony Liguori static const TypeInfo spapr_vio_bus_info = {
750d936928SAnthony Liguori     .name = TYPE_SPAPR_VIO_BUS,
760d936928SAnthony Liguori     .parent = TYPE_BUS,
77c4eda5b7SDavid Gibson     .class_init = spapr_vio_bus_class_init,
780d936928SAnthony Liguori     .instance_size = sizeof(VIOsPAPRBus),
794040ab72SDavid Gibson };
804040ab72SDavid Gibson 
814040ab72SDavid Gibson VIOsPAPRDevice *spapr_vio_find_by_reg(VIOsPAPRBus *bus, uint32_t reg)
824040ab72SDavid Gibson {
830866aca1SAnthony Liguori     BusChild *kid;
844040ab72SDavid Gibson     VIOsPAPRDevice *dev = NULL;
854040ab72SDavid Gibson 
860866aca1SAnthony Liguori     QTAILQ_FOREACH(kid, &bus->bus.children, sibling) {
870866aca1SAnthony Liguori         dev = (VIOsPAPRDevice *)kid->child;
884040ab72SDavid Gibson         if (dev->reg == reg) {
895435352cSDavid Gibson             return dev;
904040ab72SDavid Gibson         }
914040ab72SDavid Gibson     }
924040ab72SDavid Gibson 
935435352cSDavid Gibson     return NULL;
944040ab72SDavid Gibson }
954040ab72SDavid Gibson 
964040ab72SDavid Gibson static int vio_make_devnode(VIOsPAPRDevice *dev,
974040ab72SDavid Gibson                             void *fdt)
984040ab72SDavid Gibson {
993954d33aSAnthony Liguori     VIOsPAPRDeviceClass *pc = VIO_SPAPR_DEVICE_GET_CLASS(dev);
1001e34d859SMichael Ellerman     int vdevice_off, node_off, ret;
1011e34d859SMichael Ellerman     char *dt_name;
1024040ab72SDavid Gibson 
1034040ab72SDavid Gibson     vdevice_off = fdt_path_offset(fdt, "/vdevice");
1044040ab72SDavid Gibson     if (vdevice_off < 0) {
1054040ab72SDavid Gibson         return vdevice_off;
1064040ab72SDavid Gibson     }
1074040ab72SDavid Gibson 
108c4eda5b7SDavid Gibson     dt_name = spapr_vio_get_dev_name(DEVICE(dev));
1091e34d859SMichael Ellerman     node_off = fdt_add_subnode(fdt, vdevice_off, dt_name);
1104ecf8aa5SStefan Weil     g_free(dt_name);
1114040ab72SDavid Gibson     if (node_off < 0) {
1124040ab72SDavid Gibson         return node_off;
1134040ab72SDavid Gibson     }
1144040ab72SDavid Gibson 
1154040ab72SDavid Gibson     ret = fdt_setprop_cell(fdt, node_off, "reg", dev->reg);
1164040ab72SDavid Gibson     if (ret < 0) {
1174040ab72SDavid Gibson         return ret;
1184040ab72SDavid Gibson     }
1194040ab72SDavid Gibson 
1203954d33aSAnthony Liguori     if (pc->dt_type) {
1214040ab72SDavid Gibson         ret = fdt_setprop_string(fdt, node_off, "device_type",
1223954d33aSAnthony Liguori                                  pc->dt_type);
1234040ab72SDavid Gibson         if (ret < 0) {
1244040ab72SDavid Gibson             return ret;
1254040ab72SDavid Gibson         }
1264040ab72SDavid Gibson     }
1274040ab72SDavid Gibson 
1283954d33aSAnthony Liguori     if (pc->dt_compatible) {
1294040ab72SDavid Gibson         ret = fdt_setprop_string(fdt, node_off, "compatible",
1303954d33aSAnthony Liguori                                  pc->dt_compatible);
1314040ab72SDavid Gibson         if (ret < 0) {
1324040ab72SDavid Gibson             return ret;
1334040ab72SDavid Gibson         }
1344040ab72SDavid Gibson     }
1354040ab72SDavid Gibson 
136a307d594SAlexey Kardashevskiy     if (dev->irq) {
137a307d594SAlexey Kardashevskiy         uint32_t ints_prop[] = {cpu_to_be32(dev->irq), 0};
13800dc738dSDavid Gibson 
13900dc738dSDavid Gibson         ret = fdt_setprop(fdt, node_off, "interrupts", ints_prop,
14000dc738dSDavid Gibson                           sizeof(ints_prop));
14100dc738dSDavid Gibson         if (ret < 0) {
14200dc738dSDavid Gibson             return ret;
14300dc738dSDavid Gibson         }
14400dc738dSDavid Gibson     }
14500dc738dSDavid Gibson 
1462b7dc949SPaolo Bonzini     ret = spapr_tcet_dma_dt(fdt, node_off, "ibm,my-dma-window", dev->tcet);
147ee86dfeeSDavid Gibson     if (ret < 0) {
148ee86dfeeSDavid Gibson         return ret;
149ee86dfeeSDavid Gibson     }
150ee86dfeeSDavid Gibson 
1513954d33aSAnthony Liguori     if (pc->devnode) {
1523954d33aSAnthony Liguori         ret = (pc->devnode)(dev, fdt, node_off);
1534040ab72SDavid Gibson         if (ret < 0) {
1544040ab72SDavid Gibson             return ret;
1554040ab72SDavid Gibson         }
1564040ab72SDavid Gibson     }
1574040ab72SDavid Gibson 
1584040ab72SDavid Gibson     return node_off;
1594040ab72SDavid Gibson }
1604040ab72SDavid Gibson 
161ee86dfeeSDavid Gibson /*
162b45d63b6SBen Herrenschmidt  * CRQ handling
163b45d63b6SBen Herrenschmidt  */
16428e02042SDavid Gibson static target_ulong h_reg_crq(PowerPCCPU *cpu, sPAPRMachineState *spapr,
165b45d63b6SBen Herrenschmidt                               target_ulong opcode, target_ulong *args)
166b45d63b6SBen Herrenschmidt {
167b45d63b6SBen Herrenschmidt     target_ulong reg = args[0];
168b45d63b6SBen Herrenschmidt     target_ulong queue_addr = args[1];
169b45d63b6SBen Herrenschmidt     target_ulong queue_len = args[2];
170b45d63b6SBen Herrenschmidt     VIOsPAPRDevice *dev = spapr_vio_find_by_reg(spapr->vio_bus, reg);
171b45d63b6SBen Herrenschmidt 
172b45d63b6SBen Herrenschmidt     if (!dev) {
173d9599c92SDavid Gibson         hcall_dprintf("Unit 0x" TARGET_FMT_lx " does not exist\n", reg);
174b45d63b6SBen Herrenschmidt         return H_PARAMETER;
175b45d63b6SBen Herrenschmidt     }
176b45d63b6SBen Herrenschmidt 
177b45d63b6SBen Herrenschmidt     /* We can't grok a queue size bigger than 256M for now */
178b45d63b6SBen Herrenschmidt     if (queue_len < 0x1000 || queue_len > 0x10000000) {
179d9599c92SDavid Gibson         hcall_dprintf("Queue size too small or too big (0x" TARGET_FMT_lx
180d9599c92SDavid Gibson                       ")\n", queue_len);
181b45d63b6SBen Herrenschmidt         return H_PARAMETER;
182b45d63b6SBen Herrenschmidt     }
183b45d63b6SBen Herrenschmidt 
184b45d63b6SBen Herrenschmidt     /* Check queue alignment */
185b45d63b6SBen Herrenschmidt     if (queue_addr & 0xfff) {
186d9599c92SDavid Gibson         hcall_dprintf("Queue not aligned (0x" TARGET_FMT_lx ")\n", queue_addr);
187b45d63b6SBen Herrenschmidt         return H_PARAMETER;
188b45d63b6SBen Herrenschmidt     }
189b45d63b6SBen Herrenschmidt 
190b45d63b6SBen Herrenschmidt     /* Check if device supports CRQs */
191b45d63b6SBen Herrenschmidt     if (!dev->crq.SendFunc) {
1928e01f355SDavid Gibson         hcall_dprintf("Device does not support CRQ\n");
193b45d63b6SBen Herrenschmidt         return H_NOT_FOUND;
194b45d63b6SBen Herrenschmidt     }
195b45d63b6SBen Herrenschmidt 
196b45d63b6SBen Herrenschmidt     /* Already a queue ? */
197b45d63b6SBen Herrenschmidt     if (dev->crq.qsize) {
1988e01f355SDavid Gibson         hcall_dprintf("CRQ already registered\n");
199b45d63b6SBen Herrenschmidt         return H_RESOURCE;
200b45d63b6SBen Herrenschmidt     }
201b45d63b6SBen Herrenschmidt     dev->crq.qladdr = queue_addr;
202b45d63b6SBen Herrenschmidt     dev->crq.qsize = queue_len;
203b45d63b6SBen Herrenschmidt     dev->crq.qnext = 0;
204b45d63b6SBen Herrenschmidt 
205f6bda9cbSPeter Maydell     DPRINTF("CRQ for dev 0x" TARGET_FMT_lx " registered at 0x"
206b45d63b6SBen Herrenschmidt             TARGET_FMT_lx "/0x" TARGET_FMT_lx "\n",
207b45d63b6SBen Herrenschmidt             reg, queue_addr, queue_len);
208b45d63b6SBen Herrenschmidt     return H_SUCCESS;
209b45d63b6SBen Herrenschmidt }
210b45d63b6SBen Herrenschmidt 
2118e01f355SDavid Gibson static target_ulong free_crq(VIOsPAPRDevice *dev)
2128e01f355SDavid Gibson {
2138e01f355SDavid Gibson     dev->crq.qladdr = 0;
2148e01f355SDavid Gibson     dev->crq.qsize = 0;
2158e01f355SDavid Gibson     dev->crq.qnext = 0;
2168e01f355SDavid Gibson 
217f6bda9cbSPeter Maydell     DPRINTF("CRQ for dev 0x%" PRIx32 " freed\n", dev->reg);
2188e01f355SDavid Gibson 
2198e01f355SDavid Gibson     return H_SUCCESS;
2208e01f355SDavid Gibson }
2218e01f355SDavid Gibson 
22228e02042SDavid Gibson static target_ulong h_free_crq(PowerPCCPU *cpu, sPAPRMachineState *spapr,
223b45d63b6SBen Herrenschmidt                                target_ulong opcode, target_ulong *args)
224b45d63b6SBen Herrenschmidt {
225b45d63b6SBen Herrenschmidt     target_ulong reg = args[0];
226b45d63b6SBen Herrenschmidt     VIOsPAPRDevice *dev = spapr_vio_find_by_reg(spapr->vio_bus, reg);
227b45d63b6SBen Herrenschmidt 
228b45d63b6SBen Herrenschmidt     if (!dev) {
229d9599c92SDavid Gibson         hcall_dprintf("Unit 0x" TARGET_FMT_lx " does not exist\n", reg);
230b45d63b6SBen Herrenschmidt         return H_PARAMETER;
231b45d63b6SBen Herrenschmidt     }
232b45d63b6SBen Herrenschmidt 
2338e01f355SDavid Gibson     return free_crq(dev);
234b45d63b6SBen Herrenschmidt }
235b45d63b6SBen Herrenschmidt 
23628e02042SDavid Gibson static target_ulong h_send_crq(PowerPCCPU *cpu, sPAPRMachineState *spapr,
237b45d63b6SBen Herrenschmidt                                target_ulong opcode, target_ulong *args)
238b45d63b6SBen Herrenschmidt {
239b45d63b6SBen Herrenschmidt     target_ulong reg = args[0];
240b45d63b6SBen Herrenschmidt     target_ulong msg_hi = args[1];
241b45d63b6SBen Herrenschmidt     target_ulong msg_lo = args[2];
242b45d63b6SBen Herrenschmidt     VIOsPAPRDevice *dev = spapr_vio_find_by_reg(spapr->vio_bus, reg);
243b45d63b6SBen Herrenschmidt     uint64_t crq_mangle[2];
244b45d63b6SBen Herrenschmidt 
245b45d63b6SBen Herrenschmidt     if (!dev) {
246d9599c92SDavid Gibson         hcall_dprintf("Unit 0x" TARGET_FMT_lx " does not exist\n", reg);
247b45d63b6SBen Herrenschmidt         return H_PARAMETER;
248b45d63b6SBen Herrenschmidt     }
249b45d63b6SBen Herrenschmidt     crq_mangle[0] = cpu_to_be64(msg_hi);
250b45d63b6SBen Herrenschmidt     crq_mangle[1] = cpu_to_be64(msg_lo);
251b45d63b6SBen Herrenschmidt 
252b45d63b6SBen Herrenschmidt     if (dev->crq.SendFunc) {
253b45d63b6SBen Herrenschmidt         return dev->crq.SendFunc(dev, (uint8_t *)crq_mangle);
254b45d63b6SBen Herrenschmidt     }
255b45d63b6SBen Herrenschmidt 
256b45d63b6SBen Herrenschmidt     return H_HARDWARE;
257b45d63b6SBen Herrenschmidt }
258b45d63b6SBen Herrenschmidt 
25928e02042SDavid Gibson static target_ulong h_enable_crq(PowerPCCPU *cpu, sPAPRMachineState *spapr,
260b45d63b6SBen Herrenschmidt                                  target_ulong opcode, target_ulong *args)
261b45d63b6SBen Herrenschmidt {
262b45d63b6SBen Herrenschmidt     target_ulong reg = args[0];
263b45d63b6SBen Herrenschmidt     VIOsPAPRDevice *dev = spapr_vio_find_by_reg(spapr->vio_bus, reg);
264b45d63b6SBen Herrenschmidt 
265b45d63b6SBen Herrenschmidt     if (!dev) {
266d9599c92SDavid Gibson         hcall_dprintf("Unit 0x" TARGET_FMT_lx " does not exist\n", reg);
267b45d63b6SBen Herrenschmidt         return H_PARAMETER;
268b45d63b6SBen Herrenschmidt     }
269b45d63b6SBen Herrenschmidt 
270b45d63b6SBen Herrenschmidt     return 0;
271b45d63b6SBen Herrenschmidt }
272b45d63b6SBen Herrenschmidt 
273b45d63b6SBen Herrenschmidt /* Returns negative error, 0 success, or positive: queue full */
274b45d63b6SBen Herrenschmidt int spapr_vio_send_crq(VIOsPAPRDevice *dev, uint8_t *crq)
275b45d63b6SBen Herrenschmidt {
276b45d63b6SBen Herrenschmidt     int rc;
277b45d63b6SBen Herrenschmidt     uint8_t byte;
278b45d63b6SBen Herrenschmidt 
279b45d63b6SBen Herrenschmidt     if (!dev->crq.qsize) {
280b45d63b6SBen Herrenschmidt         fprintf(stderr, "spapr_vio_send_creq on uninitialized queue\n");
281b45d63b6SBen Herrenschmidt         return -1;
282b45d63b6SBen Herrenschmidt     }
283b45d63b6SBen Herrenschmidt 
284b45d63b6SBen Herrenschmidt     /* Maybe do a fast path for KVM just writing to the pages */
285ad0ebb91SDavid Gibson     rc = spapr_vio_dma_read(dev, dev->crq.qladdr + dev->crq.qnext, &byte, 1);
286b45d63b6SBen Herrenschmidt     if (rc) {
287b45d63b6SBen Herrenschmidt         return rc;
288b45d63b6SBen Herrenschmidt     }
289b45d63b6SBen Herrenschmidt     if (byte != 0) {
290b45d63b6SBen Herrenschmidt         return 1;
291b45d63b6SBen Herrenschmidt     }
292b45d63b6SBen Herrenschmidt 
293ad0ebb91SDavid Gibson     rc = spapr_vio_dma_write(dev, dev->crq.qladdr + dev->crq.qnext + 8,
294b45d63b6SBen Herrenschmidt                              &crq[8], 8);
295b45d63b6SBen Herrenschmidt     if (rc) {
296b45d63b6SBen Herrenschmidt         return rc;
297b45d63b6SBen Herrenschmidt     }
298b45d63b6SBen Herrenschmidt 
299b45d63b6SBen Herrenschmidt     kvmppc_eieio();
300b45d63b6SBen Herrenschmidt 
301ad0ebb91SDavid Gibson     rc = spapr_vio_dma_write(dev, dev->crq.qladdr + dev->crq.qnext, crq, 8);
302b45d63b6SBen Herrenschmidt     if (rc) {
303b45d63b6SBen Herrenschmidt         return rc;
304b45d63b6SBen Herrenschmidt     }
305b45d63b6SBen Herrenschmidt 
306b45d63b6SBen Herrenschmidt     dev->crq.qnext = (dev->crq.qnext + 16) % dev->crq.qsize;
307b45d63b6SBen Herrenschmidt 
308b45d63b6SBen Herrenschmidt     if (dev->signal_state & 1) {
309a307d594SAlexey Kardashevskiy         qemu_irq_pulse(spapr_vio_qirq(dev));
310b45d63b6SBen Herrenschmidt     }
311b45d63b6SBen Herrenschmidt 
312b45d63b6SBen Herrenschmidt     return 0;
313b45d63b6SBen Herrenschmidt }
314b45d63b6SBen Herrenschmidt 
31508942ac1SBen Herrenschmidt /* "quiesce" handling */
31608942ac1SBen Herrenschmidt 
31708942ac1SBen Herrenschmidt static void spapr_vio_quiesce_one(VIOsPAPRDevice *dev)
31808942ac1SBen Herrenschmidt {
3192b7dc949SPaolo Bonzini     if (dev->tcet) {
320a83000f5SAnthony Liguori         device_reset(DEVICE(dev->tcet));
32108942ac1SBen Herrenschmidt     }
3224dd96f24SDavid Gibson     free_crq(dev);
32308942ac1SBen Herrenschmidt }
32408942ac1SBen Herrenschmidt 
325ee9a569aSAlexey Kardashevskiy void spapr_vio_set_bypass(VIOsPAPRDevice *dev, bool bypass)
326ee9a569aSAlexey Kardashevskiy {
327ee9a569aSAlexey Kardashevskiy     if (!dev->tcet) {
328ee9a569aSAlexey Kardashevskiy         return;
329ee9a569aSAlexey Kardashevskiy     }
330ee9a569aSAlexey Kardashevskiy 
331ee9a569aSAlexey Kardashevskiy     memory_region_set_enabled(&dev->mrbypass, bypass);
332ee9a569aSAlexey Kardashevskiy     memory_region_set_enabled(spapr_tce_get_iommu(dev->tcet), !bypass);
333ee9a569aSAlexey Kardashevskiy 
334ee9a569aSAlexey Kardashevskiy     dev->tcet->bypass = bypass;
335ee9a569aSAlexey Kardashevskiy }
336ee9a569aSAlexey Kardashevskiy 
33728e02042SDavid Gibson static void rtas_set_tce_bypass(PowerPCCPU *cpu, sPAPRMachineState *spapr,
338210b580bSAnthony Liguori                                 uint32_t token,
33908942ac1SBen Herrenschmidt                                 uint32_t nargs, target_ulong args,
34008942ac1SBen Herrenschmidt                                 uint32_t nret, target_ulong rets)
34108942ac1SBen Herrenschmidt {
34208942ac1SBen Herrenschmidt     VIOsPAPRBus *bus = spapr->vio_bus;
34308942ac1SBen Herrenschmidt     VIOsPAPRDevice *dev;
34408942ac1SBen Herrenschmidt     uint32_t unit, enable;
34508942ac1SBen Herrenschmidt 
34608942ac1SBen Herrenschmidt     if (nargs != 2) {
347a64d325dSAlexey Kardashevskiy         rtas_st(rets, 0, RTAS_OUT_PARAM_ERROR);
34808942ac1SBen Herrenschmidt         return;
34908942ac1SBen Herrenschmidt     }
35008942ac1SBen Herrenschmidt     unit = rtas_ld(args, 0);
35108942ac1SBen Herrenschmidt     enable = rtas_ld(args, 1);
35208942ac1SBen Herrenschmidt     dev = spapr_vio_find_by_reg(bus, unit);
35308942ac1SBen Herrenschmidt     if (!dev) {
354a64d325dSAlexey Kardashevskiy         rtas_st(rets, 0, RTAS_OUT_PARAM_ERROR);
35508942ac1SBen Herrenschmidt         return;
35608942ac1SBen Herrenschmidt     }
357ad0ebb91SDavid Gibson 
3582b7dc949SPaolo Bonzini     if (!dev->tcet) {
359a64d325dSAlexey Kardashevskiy         rtas_st(rets, 0, RTAS_OUT_PARAM_ERROR);
36053724ee5SDavid Gibson         return;
36108942ac1SBen Herrenschmidt     }
36208942ac1SBen Herrenschmidt 
363ee9a569aSAlexey Kardashevskiy     spapr_vio_set_bypass(dev, !!enable);
36453724ee5SDavid Gibson 
365a64d325dSAlexey Kardashevskiy     rtas_st(rets, 0, RTAS_OUT_SUCCESS);
36608942ac1SBen Herrenschmidt }
36708942ac1SBen Herrenschmidt 
36828e02042SDavid Gibson static void rtas_quiesce(PowerPCCPU *cpu, sPAPRMachineState *spapr,
369210b580bSAnthony Liguori                          uint32_t token,
37008942ac1SBen Herrenschmidt                          uint32_t nargs, target_ulong args,
37108942ac1SBen Herrenschmidt                          uint32_t nret, target_ulong rets)
37208942ac1SBen Herrenschmidt {
37308942ac1SBen Herrenschmidt     VIOsPAPRBus *bus = spapr->vio_bus;
3740866aca1SAnthony Liguori     BusChild *kid;
37508942ac1SBen Herrenschmidt     VIOsPAPRDevice *dev = NULL;
37608942ac1SBen Herrenschmidt 
37708942ac1SBen Herrenschmidt     if (nargs != 0) {
378a64d325dSAlexey Kardashevskiy         rtas_st(rets, 0, RTAS_OUT_PARAM_ERROR);
37908942ac1SBen Herrenschmidt         return;
38008942ac1SBen Herrenschmidt     }
38108942ac1SBen Herrenschmidt 
3820866aca1SAnthony Liguori     QTAILQ_FOREACH(kid, &bus->bus.children, sibling) {
3830866aca1SAnthony Liguori         dev = (VIOsPAPRDevice *)kid->child;
38408942ac1SBen Herrenschmidt         spapr_vio_quiesce_one(dev);
38508942ac1SBen Herrenschmidt     }
38608942ac1SBen Herrenschmidt 
387a64d325dSAlexey Kardashevskiy     rtas_st(rets, 0, RTAS_OUT_SUCCESS);
38808942ac1SBen Herrenschmidt }
38908942ac1SBen Herrenschmidt 
390d601fac4SDavid Gibson static VIOsPAPRDevice *reg_conflict(VIOsPAPRDevice *dev)
3919fc380d3SMichael Ellerman {
392215e2098SCao jin     VIOsPAPRBus *bus = SPAPR_VIO_BUS(dev->qdev.parent_bus);
3930866aca1SAnthony Liguori     BusChild *kid;
394d601fac4SDavid Gibson     VIOsPAPRDevice *other;
3959fc380d3SMichael Ellerman 
3969fc380d3SMichael Ellerman     /*
397d601fac4SDavid Gibson      * Check for a device other than the given one which is already
398d601fac4SDavid Gibson      * using the requested address. We have to open code this because
399d601fac4SDavid Gibson      * the given dev might already be in the list.
4009fc380d3SMichael Ellerman      */
4010866aca1SAnthony Liguori     QTAILQ_FOREACH(kid, &bus->bus.children, sibling) {
402fd506b4fSDavid Gibson         other = VIO_SPAPR_DEVICE(kid->child);
4039fc380d3SMichael Ellerman 
404d601fac4SDavid Gibson         if (other != dev && other->reg == dev->reg) {
405d601fac4SDavid Gibson             return other;
4069fc380d3SMichael Ellerman         }
4079fc380d3SMichael Ellerman     }
4089fc380d3SMichael Ellerman 
4099fc380d3SMichael Ellerman     return 0;
4109fc380d3SMichael Ellerman }
4119fc380d3SMichael Ellerman 
412b1c7f725SDavid Gibson static void spapr_vio_busdev_reset(DeviceState *qdev)
4138e01f355SDavid Gibson {
414fd506b4fSDavid Gibson     VIOsPAPRDevice *dev = VIO_SPAPR_DEVICE(qdev);
415b1c7f725SDavid Gibson     VIOsPAPRDeviceClass *pc = VIO_SPAPR_DEVICE_GET_CLASS(dev);
4168e01f355SDavid Gibson 
4174dd96f24SDavid Gibson     /* Shut down the request queue and TCEs if necessary */
4184dd96f24SDavid Gibson     spapr_vio_quiesce_one(dev);
4194dd96f24SDavid Gibson 
4204dd96f24SDavid Gibson     dev->signal_state = 0;
421b1c7f725SDavid Gibson 
422ee9a569aSAlexey Kardashevskiy     spapr_vio_set_bypass(dev, false);
423b1c7f725SDavid Gibson     if (pc->reset) {
424b1c7f725SDavid Gibson         pc->reset(dev);
425b1c7f725SDavid Gibson     }
4268e01f355SDavid Gibson }
4278e01f355SDavid Gibson 
42828b07e73SMarkus Armbruster static void spapr_vio_busdev_realize(DeviceState *qdev, Error **errp)
4294040ab72SDavid Gibson {
43028e02042SDavid Gibson     sPAPRMachineState *spapr = SPAPR_MACHINE(qdev_get_machine());
4314040ab72SDavid Gibson     VIOsPAPRDevice *dev = (VIOsPAPRDevice *)qdev;
4323954d33aSAnthony Liguori     VIOsPAPRDeviceClass *pc = VIO_SPAPR_DEVICE_GET_CLASS(dev);
4334040ab72SDavid Gibson     char *id;
434*a005b3efSGreg Kurz     Error *local_err = NULL;
4359fc380d3SMichael Ellerman 
436d601fac4SDavid Gibson     if (dev->reg != -1) {
437d601fac4SDavid Gibson         /*
438d601fac4SDavid Gibson          * Explicitly assigned address, just verify that no-one else
439d601fac4SDavid Gibson          * is using it.  other mechanism). We have to open code this
440d601fac4SDavid Gibson          * rather than using spapr_vio_find_by_reg() because sdev
441d601fac4SDavid Gibson          * itself is already in the list.
442d601fac4SDavid Gibson          */
443d601fac4SDavid Gibson         VIOsPAPRDevice *other = reg_conflict(dev);
444d601fac4SDavid Gibson 
445d601fac4SDavid Gibson         if (other) {
44628b07e73SMarkus Armbruster             error_setg(errp, "%s and %s devices conflict at address %#x",
447d601fac4SDavid Gibson                        object_get_typename(OBJECT(qdev)),
448d601fac4SDavid Gibson                        object_get_typename(OBJECT(&other->qdev)),
449d601fac4SDavid Gibson                        dev->reg);
45028b07e73SMarkus Armbruster             return;
451d601fac4SDavid Gibson         }
452d601fac4SDavid Gibson     } else {
453d601fac4SDavid Gibson         /* Need to assign an address */
454215e2098SCao jin         VIOsPAPRBus *bus = SPAPR_VIO_BUS(dev->qdev.parent_bus);
455d601fac4SDavid Gibson 
456d601fac4SDavid Gibson         do {
457d601fac4SDavid Gibson             dev->reg = bus->next_reg++;
458d601fac4SDavid Gibson         } while (reg_conflict(dev));
4599fc380d3SMichael Ellerman     }
4604040ab72SDavid Gibson 
4611e34d859SMichael Ellerman     /* Don't overwrite ids assigned on the command line */
4621e34d859SMichael Ellerman     if (!dev->qdev.id) {
463c4eda5b7SDavid Gibson         id = spapr_vio_get_dev_name(DEVICE(dev));
4644040ab72SDavid Gibson         dev->qdev.id = id;
4651e34d859SMichael Ellerman     }
466e6c866d4SDavid Gibson 
467*a005b3efSGreg Kurz     dev->irq = xics_alloc(spapr->icp, 0, dev->irq, false, &local_err);
468*a005b3efSGreg Kurz     if (local_err) {
469*a005b3efSGreg Kurz         error_propagate(errp, local_err);
47028b07e73SMarkus Armbruster         return;
471416343b1SPaolo Bonzini     }
4724040ab72SDavid Gibson 
47353724ee5SDavid Gibson     if (pc->rtce_window_size) {
4744290ca49SAlexey Kardashevskiy         uint32_t liobn = SPAPR_VIO_LIOBN(dev->reg);
475ee9a569aSAlexey Kardashevskiy 
476ee9a569aSAlexey Kardashevskiy         memory_region_init(&dev->mrroot, OBJECT(dev), "iommu-spapr-root",
477ee9a569aSAlexey Kardashevskiy                            ram_size);
478ee9a569aSAlexey Kardashevskiy         memory_region_init_alias(&dev->mrbypass, OBJECT(dev),
479ee9a569aSAlexey Kardashevskiy                                  "iommu-spapr-bypass", get_system_memory(),
480ee9a569aSAlexey Kardashevskiy                                  0, ram_size);
481ee9a569aSAlexey Kardashevskiy         memory_region_add_subregion_overlap(&dev->mrroot, 0, &dev->mrbypass, 1);
482ee9a569aSAlexey Kardashevskiy         address_space_init(&dev->as, &dev->mrroot, qdev->id);
483ee9a569aSAlexey Kardashevskiy 
484523e7b8aSAlexey Kardashevskiy         dev->tcet = spapr_tce_new_table(qdev, liobn,
4851b8eceeeSAlexey Kardashevskiy                                         0,
486650f33adSAlexey Kardashevskiy                                         SPAPR_TCE_PAGE_SHIFT,
487523e7b8aSAlexey Kardashevskiy                                         pc->rtce_window_size >>
4889bb62a07SAlexey Kardashevskiy                                         SPAPR_TCE_PAGE_SHIFT, false);
489ee9a569aSAlexey Kardashevskiy         dev->tcet->vdev = dev;
490ee9a569aSAlexey Kardashevskiy         memory_region_add_subregion_overlap(&dev->mrroot, 0,
491ee9a569aSAlexey Kardashevskiy                                             spapr_tce_get_iommu(dev->tcet), 2);
49253724ee5SDavid Gibson     }
493ee86dfeeSDavid Gibson 
49428b07e73SMarkus Armbruster     pc->realize(dev, errp);
4954040ab72SDavid Gibson }
4964040ab72SDavid Gibson 
49728e02042SDavid Gibson static target_ulong h_vio_signal(PowerPCCPU *cpu, sPAPRMachineState *spapr,
49800dc738dSDavid Gibson                                  target_ulong opcode,
49900dc738dSDavid Gibson                                  target_ulong *args)
50000dc738dSDavid Gibson {
50100dc738dSDavid Gibson     target_ulong reg = args[0];
50200dc738dSDavid Gibson     target_ulong mode = args[1];
50300dc738dSDavid Gibson     VIOsPAPRDevice *dev = spapr_vio_find_by_reg(spapr->vio_bus, reg);
5043954d33aSAnthony Liguori     VIOsPAPRDeviceClass *pc;
50500dc738dSDavid Gibson 
50600dc738dSDavid Gibson     if (!dev) {
50700dc738dSDavid Gibson         return H_PARAMETER;
50800dc738dSDavid Gibson     }
50900dc738dSDavid Gibson 
5103954d33aSAnthony Liguori     pc = VIO_SPAPR_DEVICE_GET_CLASS(dev);
51100dc738dSDavid Gibson 
5123954d33aSAnthony Liguori     if (mode & ~pc->signal_mask) {
51300dc738dSDavid Gibson         return H_PARAMETER;
51400dc738dSDavid Gibson     }
51500dc738dSDavid Gibson 
51600dc738dSDavid Gibson     dev->signal_state = mode;
51700dc738dSDavid Gibson 
51800dc738dSDavid Gibson     return H_SUCCESS;
51900dc738dSDavid Gibson }
52000dc738dSDavid Gibson 
5214040ab72SDavid Gibson VIOsPAPRBus *spapr_vio_bus_init(void)
5224040ab72SDavid Gibson {
5234040ab72SDavid Gibson     VIOsPAPRBus *bus;
5244040ab72SDavid Gibson     BusState *qbus;
5254040ab72SDavid Gibson     DeviceState *dev;
5264040ab72SDavid Gibson 
5274040ab72SDavid Gibson     /* Create bridge device */
528215e2098SCao jin     dev = qdev_create(NULL, TYPE_SPAPR_VIO_BRIDGE);
5294040ab72SDavid Gibson     qdev_init_nofail(dev);
5304040ab72SDavid Gibson 
5314040ab72SDavid Gibson     /* Create bus on bridge device */
5320d936928SAnthony Liguori     qbus = qbus_create(TYPE_SPAPR_VIO_BUS, dev, "spapr-vio");
533215e2098SCao jin     bus = SPAPR_VIO_BUS(qbus);
5341ea1ce8aSDavid Gibson     bus->next_reg = 0x71000000;
5354040ab72SDavid Gibson 
53600dc738dSDavid Gibson     /* hcall-vio */
53700dc738dSDavid Gibson     spapr_register_hypercall(H_VIO_SIGNAL, h_vio_signal);
53800dc738dSDavid Gibson 
539b45d63b6SBen Herrenschmidt     /* hcall-crq */
540b45d63b6SBen Herrenschmidt     spapr_register_hypercall(H_REG_CRQ, h_reg_crq);
541b45d63b6SBen Herrenschmidt     spapr_register_hypercall(H_FREE_CRQ, h_free_crq);
542b45d63b6SBen Herrenschmidt     spapr_register_hypercall(H_SEND_CRQ, h_send_crq);
543b45d63b6SBen Herrenschmidt     spapr_register_hypercall(H_ENABLE_CRQ, h_enable_crq);
544b45d63b6SBen Herrenschmidt 
54508942ac1SBen Herrenschmidt     /* RTAS calls */
5463a3b8502SAlexey Kardashevskiy     spapr_rtas_register(RTAS_IBM_SET_TCE_BYPASS, "ibm,set-tce-bypass",
5473a3b8502SAlexey Kardashevskiy                         rtas_set_tce_bypass);
5483a3b8502SAlexey Kardashevskiy     spapr_rtas_register(RTAS_QUIESCE, "quiesce", rtas_quiesce);
54908942ac1SBen Herrenschmidt 
5504040ab72SDavid Gibson     return bus;
5514040ab72SDavid Gibson }
5524040ab72SDavid Gibson 
5534040ab72SDavid Gibson /* Represents sPAPR hcall VIO devices */
5544040ab72SDavid Gibson 
5554040ab72SDavid Gibson static int spapr_vio_bridge_init(SysBusDevice *dev)
5564040ab72SDavid Gibson {
5574040ab72SDavid Gibson     /* nothing */
5584040ab72SDavid Gibson     return 0;
5594040ab72SDavid Gibson }
5604040ab72SDavid Gibson 
561999e12bbSAnthony Liguori static void spapr_vio_bridge_class_init(ObjectClass *klass, void *data)
562999e12bbSAnthony Liguori {
56339bffca2SAnthony Liguori     SysBusDeviceClass *k = SYS_BUS_DEVICE_CLASS(klass);
5645a06393fSAlexey Kardashevskiy     DeviceClass *dc = DEVICE_CLASS(klass);
565999e12bbSAnthony Liguori 
5665a06393fSAlexey Kardashevskiy     dc->fw_name = "vdevice";
56739bffca2SAnthony Liguori     k->init = spapr_vio_bridge_init;
568999e12bbSAnthony Liguori }
569999e12bbSAnthony Liguori 
5708c43a6f0SAndreas Färber static const TypeInfo spapr_vio_bridge_info = {
571215e2098SCao jin     .name          = TYPE_SPAPR_VIO_BRIDGE,
57239bffca2SAnthony Liguori     .parent        = TYPE_SYS_BUS_DEVICE,
573999e12bbSAnthony Liguori     .class_init    = spapr_vio_bridge_class_init,
5744040ab72SDavid Gibson };
5754040ab72SDavid Gibson 
576b368a7d8SDavid Gibson const VMStateDescription vmstate_spapr_vio = {
577b368a7d8SDavid Gibson     .name = "spapr_vio",
578b368a7d8SDavid Gibson     .version_id = 1,
579b368a7d8SDavid Gibson     .minimum_version_id = 1,
580b368a7d8SDavid Gibson     .fields = (VMStateField[]) {
581b368a7d8SDavid Gibson         /* Sanity check */
582b368a7d8SDavid Gibson         VMSTATE_UINT32_EQUAL(reg, VIOsPAPRDevice),
583b368a7d8SDavid Gibson         VMSTATE_UINT32_EQUAL(irq, VIOsPAPRDevice),
584b368a7d8SDavid Gibson 
585b368a7d8SDavid Gibson         /* General VIO device state */
586b368a7d8SDavid Gibson         VMSTATE_UINTTL(signal_state, VIOsPAPRDevice),
587b368a7d8SDavid Gibson         VMSTATE_UINT64(crq.qladdr, VIOsPAPRDevice),
588b368a7d8SDavid Gibson         VMSTATE_UINT32(crq.qsize, VIOsPAPRDevice),
589b368a7d8SDavid Gibson         VMSTATE_UINT32(crq.qnext, VIOsPAPRDevice),
590b368a7d8SDavid Gibson 
591b368a7d8SDavid Gibson         VMSTATE_END_OF_LIST()
592b368a7d8SDavid Gibson     },
593b368a7d8SDavid Gibson };
594b368a7d8SDavid Gibson 
59539bffca2SAnthony Liguori static void vio_spapr_device_class_init(ObjectClass *klass, void *data)
59639bffca2SAnthony Liguori {
59739bffca2SAnthony Liguori     DeviceClass *k = DEVICE_CLASS(klass);
59828b07e73SMarkus Armbruster     k->realize = spapr_vio_busdev_realize;
599b1c7f725SDavid Gibson     k->reset = spapr_vio_busdev_reset;
6000d936928SAnthony Liguori     k->bus_type = TYPE_SPAPR_VIO_BUS;
601bce54474SPaolo Bonzini     k->props = spapr_vio_props;
60239bffca2SAnthony Liguori }
60339bffca2SAnthony Liguori 
6048c43a6f0SAndreas Färber static const TypeInfo spapr_vio_type_info = {
6053954d33aSAnthony Liguori     .name = TYPE_VIO_SPAPR_DEVICE,
6063954d33aSAnthony Liguori     .parent = TYPE_DEVICE,
6073954d33aSAnthony Liguori     .instance_size = sizeof(VIOsPAPRDevice),
6083954d33aSAnthony Liguori     .abstract = true,
6093954d33aSAnthony Liguori     .class_size = sizeof(VIOsPAPRDeviceClass),
61039bffca2SAnthony Liguori     .class_init = vio_spapr_device_class_init,
6113954d33aSAnthony Liguori };
6123954d33aSAnthony Liguori 
61383f7d43aSAndreas Färber static void spapr_vio_register_types(void)
6144040ab72SDavid Gibson {
6150d936928SAnthony Liguori     type_register_static(&spapr_vio_bus_info);
61639bffca2SAnthony Liguori     type_register_static(&spapr_vio_bridge_info);
6173954d33aSAnthony Liguori     type_register_static(&spapr_vio_type_info);
6184040ab72SDavid Gibson }
6194040ab72SDavid Gibson 
62083f7d43aSAndreas Färber type_init(spapr_vio_register_types)
6214040ab72SDavid Gibson 
62205c19438SDavid Gibson static int compare_reg(const void *p1, const void *p2)
62305c19438SDavid Gibson {
62405c19438SDavid Gibson     VIOsPAPRDevice const *dev1, *dev2;
62505c19438SDavid Gibson 
62605c19438SDavid Gibson     dev1 = (VIOsPAPRDevice *)*(DeviceState **)p1;
62705c19438SDavid Gibson     dev2 = (VIOsPAPRDevice *)*(DeviceState **)p2;
62805c19438SDavid Gibson 
62905c19438SDavid Gibson     if (dev1->reg < dev2->reg) {
63005c19438SDavid Gibson         return -1;
63105c19438SDavid Gibson     }
63205c19438SDavid Gibson     if (dev1->reg == dev2->reg) {
63305c19438SDavid Gibson         return 0;
63405c19438SDavid Gibson     }
63505c19438SDavid Gibson 
63605c19438SDavid Gibson     /* dev1->reg > dev2->reg */
63705c19438SDavid Gibson     return 1;
63805c19438SDavid Gibson }
63905c19438SDavid Gibson 
6404040ab72SDavid Gibson int spapr_populate_vdevice(VIOsPAPRBus *bus, void *fdt)
6414040ab72SDavid Gibson {
64205c19438SDavid Gibson     DeviceState *qdev, **qdevs;
6430866aca1SAnthony Liguori     BusChild *kid;
64405c19438SDavid Gibson     int i, num, ret = 0;
6454040ab72SDavid Gibson 
64605c19438SDavid Gibson     /* Count qdevs on the bus list */
64705c19438SDavid Gibson     num = 0;
6480866aca1SAnthony Liguori     QTAILQ_FOREACH(kid, &bus->bus.children, sibling) {
64905c19438SDavid Gibson         num++;
65005c19438SDavid Gibson     }
65105c19438SDavid Gibson 
65205c19438SDavid Gibson     /* Copy out into an array of pointers */
65305c19438SDavid Gibson     qdevs = g_malloc(sizeof(qdev) * num);
65405c19438SDavid Gibson     num = 0;
6550866aca1SAnthony Liguori     QTAILQ_FOREACH(kid, &bus->bus.children, sibling) {
6560866aca1SAnthony Liguori         qdevs[num++] = kid->child;
65705c19438SDavid Gibson     }
65805c19438SDavid Gibson 
65905c19438SDavid Gibson     /* Sort the array */
66005c19438SDavid Gibson     qsort(qdevs, num, sizeof(qdev), compare_reg);
66105c19438SDavid Gibson 
66205c19438SDavid Gibson     /* Hack alert. Give the devices to libfdt in reverse order, we happen
66305c19438SDavid Gibson      * to know that will mean they are in forward order in the tree. */
66405c19438SDavid Gibson     for (i = num - 1; i >= 0; i--) {
66505c19438SDavid Gibson         VIOsPAPRDevice *dev = (VIOsPAPRDevice *)(qdevs[i]);
6664040ab72SDavid Gibson 
6674040ab72SDavid Gibson         ret = vio_make_devnode(dev, fdt);
6684040ab72SDavid Gibson 
6694040ab72SDavid Gibson         if (ret < 0) {
67005c19438SDavid Gibson             goto out;
6714040ab72SDavid Gibson         }
6724040ab72SDavid Gibson     }
6734040ab72SDavid Gibson 
67405c19438SDavid Gibson     ret = 0;
67505c19438SDavid Gibson out:
6765f1d1fc5SMarkus Armbruster     g_free(qdevs);
67705c19438SDavid Gibson 
67805c19438SDavid Gibson     return ret;
6794040ab72SDavid Gibson }
68068f3a94cSDavid Gibson 
68168f3a94cSDavid Gibson int spapr_populate_chosen_stdout(void *fdt, VIOsPAPRBus *bus)
68268f3a94cSDavid Gibson {
68368f3a94cSDavid Gibson     VIOsPAPRDevice *dev;
68468f3a94cSDavid Gibson     char *name, *path;
68568f3a94cSDavid Gibson     int ret, offset;
68668f3a94cSDavid Gibson 
68768f3a94cSDavid Gibson     dev = spapr_vty_get_default(bus);
68868f3a94cSDavid Gibson     if (!dev)
68968f3a94cSDavid Gibson         return 0;
69068f3a94cSDavid Gibson 
69168f3a94cSDavid Gibson     offset = fdt_path_offset(fdt, "/chosen");
69268f3a94cSDavid Gibson     if (offset < 0) {
69368f3a94cSDavid Gibson         return offset;
69468f3a94cSDavid Gibson     }
69568f3a94cSDavid Gibson 
696c4eda5b7SDavid Gibson     name = spapr_vio_get_dev_name(DEVICE(dev));
6974ecf8aa5SStefan Weil     path = g_strdup_printf("/vdevice/%s", name);
69868f3a94cSDavid Gibson 
69968f3a94cSDavid Gibson     ret = fdt_setprop_string(fdt, offset, "linux,stdout-path", path);
7004ecf8aa5SStefan Weil 
7014ecf8aa5SStefan Weil     g_free(name);
7024ecf8aa5SStefan Weil     g_free(path);
70368f3a94cSDavid Gibson 
70468f3a94cSDavid Gibson     return ret;
70568f3a94cSDavid Gibson }
706