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" 23ce9863b7SCédric Le Goater #include "qemu/error-report.h" 24da34e65cSMarkus Armbruster #include "qapi/error.h" 25efe2add7SCédric Le Goater #include "qapi/visitor.h" 2683c9f4caSPaolo Bonzini #include "hw/hw.h" 2703dd024fSPaolo Bonzini #include "qemu/log.h" 289c17d615SPaolo Bonzini #include "sysemu/sysemu.h" 2983c9f4caSPaolo Bonzini #include "hw/boards.h" 3083c9f4caSPaolo Bonzini #include "hw/loader.h" 314040ab72SDavid Gibson #include "elf.h" 324040ab72SDavid Gibson #include "hw/sysbus.h" 339c17d615SPaolo Bonzini #include "sysemu/kvm.h" 349c17d615SPaolo Bonzini #include "sysemu/device_tree.h" 35b45d63b6SBen Herrenschmidt #include "kvm_ppc.h" 36efe2add7SCédric Le Goater #include "sysemu/qtest.h" 374040ab72SDavid Gibson 380d09e41aSPaolo Bonzini #include "hw/ppc/spapr.h" 390d09e41aSPaolo Bonzini #include "hw/ppc/spapr_vio.h" 40bf5a6696SDavid Gibson #include "hw/ppc/fdt.h" 417ab6a501SLaurent Vivier #include "trace.h" 424040ab72SDavid Gibson 434040ab72SDavid Gibson #include <libfdt.h> 444040ab72SDavid Gibson 4582cffa2eSCédric Le Goater #define SPAPR_VIO_REG_BASE 0x71000000 4682cffa2eSCédric Le Goater 47c4eda5b7SDavid Gibson static char *spapr_vio_get_dev_name(DeviceState *qdev) 48c4eda5b7SDavid Gibson { 49*ce2918cbSDavid Gibson SpaprVioDevice *dev = VIO_SPAPR_DEVICE(qdev); 50*ce2918cbSDavid Gibson SpaprVioDeviceClass *pc = VIO_SPAPR_DEVICE_GET_CLASS(dev); 51c4eda5b7SDavid Gibson 52c4eda5b7SDavid Gibson /* Device tree style name device@reg */ 539be38598SEduardo Habkost return g_strdup_printf("%s@%x", pc->dt_name, dev->reg); 54c4eda5b7SDavid Gibson } 55c4eda5b7SDavid Gibson 56c4eda5b7SDavid Gibson static void spapr_vio_bus_class_init(ObjectClass *klass, void *data) 57c4eda5b7SDavid Gibson { 58c4eda5b7SDavid Gibson BusClass *k = BUS_CLASS(klass); 59c4eda5b7SDavid Gibson 60c4eda5b7SDavid Gibson k->get_dev_path = spapr_vio_get_dev_name; 615a06393fSAlexey Kardashevskiy k->get_fw_dev_path = spapr_vio_get_dev_name; 62c4eda5b7SDavid Gibson } 63c4eda5b7SDavid Gibson 640d936928SAnthony Liguori static const TypeInfo spapr_vio_bus_info = { 650d936928SAnthony Liguori .name = TYPE_SPAPR_VIO_BUS, 660d936928SAnthony Liguori .parent = TYPE_BUS, 67c4eda5b7SDavid Gibson .class_init = spapr_vio_bus_class_init, 68*ce2918cbSDavid Gibson .instance_size = sizeof(SpaprVioBus), 694040ab72SDavid Gibson }; 704040ab72SDavid Gibson 71*ce2918cbSDavid Gibson SpaprVioDevice *spapr_vio_find_by_reg(SpaprVioBus *bus, uint32_t reg) 724040ab72SDavid Gibson { 730866aca1SAnthony Liguori BusChild *kid; 74*ce2918cbSDavid Gibson SpaprVioDevice *dev = NULL; 754040ab72SDavid Gibson 760866aca1SAnthony Liguori QTAILQ_FOREACH(kid, &bus->bus.children, sibling) { 77*ce2918cbSDavid Gibson dev = (SpaprVioDevice *)kid->child; 784040ab72SDavid Gibson if (dev->reg == reg) { 795435352cSDavid Gibson return dev; 804040ab72SDavid Gibson } 814040ab72SDavid Gibson } 824040ab72SDavid Gibson 835435352cSDavid Gibson return NULL; 844040ab72SDavid Gibson } 854040ab72SDavid Gibson 86*ce2918cbSDavid Gibson static int vio_make_devnode(SpaprVioDevice *dev, 874040ab72SDavid Gibson void *fdt) 884040ab72SDavid Gibson { 89*ce2918cbSDavid Gibson SpaprVioDeviceClass *pc = VIO_SPAPR_DEVICE_GET_CLASS(dev); 901e34d859SMichael Ellerman int vdevice_off, node_off, ret; 911e34d859SMichael Ellerman char *dt_name; 924040ab72SDavid Gibson 934040ab72SDavid Gibson vdevice_off = fdt_path_offset(fdt, "/vdevice"); 944040ab72SDavid Gibson if (vdevice_off < 0) { 954040ab72SDavid Gibson return vdevice_off; 964040ab72SDavid Gibson } 974040ab72SDavid Gibson 98c4eda5b7SDavid Gibson dt_name = spapr_vio_get_dev_name(DEVICE(dev)); 991e34d859SMichael Ellerman node_off = fdt_add_subnode(fdt, vdevice_off, dt_name); 1004ecf8aa5SStefan Weil g_free(dt_name); 1014040ab72SDavid Gibson if (node_off < 0) { 1024040ab72SDavid Gibson return node_off; 1034040ab72SDavid Gibson } 1044040ab72SDavid Gibson 1054040ab72SDavid Gibson ret = fdt_setprop_cell(fdt, node_off, "reg", dev->reg); 1064040ab72SDavid Gibson if (ret < 0) { 1074040ab72SDavid Gibson return ret; 1084040ab72SDavid Gibson } 1094040ab72SDavid Gibson 1103954d33aSAnthony Liguori if (pc->dt_type) { 1114040ab72SDavid Gibson ret = fdt_setprop_string(fdt, node_off, "device_type", 1123954d33aSAnthony Liguori pc->dt_type); 1134040ab72SDavid Gibson if (ret < 0) { 1144040ab72SDavid Gibson return ret; 1154040ab72SDavid Gibson } 1164040ab72SDavid Gibson } 1174040ab72SDavid Gibson 1183954d33aSAnthony Liguori if (pc->dt_compatible) { 1194040ab72SDavid Gibson ret = fdt_setprop_string(fdt, node_off, "compatible", 1203954d33aSAnthony Liguori pc->dt_compatible); 1214040ab72SDavid Gibson if (ret < 0) { 1224040ab72SDavid Gibson return ret; 1234040ab72SDavid Gibson } 1244040ab72SDavid Gibson } 1254040ab72SDavid Gibson 126a307d594SAlexey Kardashevskiy if (dev->irq) { 127bb2d8ab6SGreg Kurz uint32_t ints_prop[2]; 12800dc738dSDavid Gibson 1295c7adcf4SGreg Kurz spapr_dt_irq(ints_prop, dev->irq, false); 13000dc738dSDavid Gibson ret = fdt_setprop(fdt, node_off, "interrupts", ints_prop, 13100dc738dSDavid Gibson sizeof(ints_prop)); 13200dc738dSDavid Gibson if (ret < 0) { 13300dc738dSDavid Gibson return ret; 13400dc738dSDavid Gibson } 13500dc738dSDavid Gibson } 13600dc738dSDavid Gibson 1372b7dc949SPaolo Bonzini ret = spapr_tcet_dma_dt(fdt, node_off, "ibm,my-dma-window", dev->tcet); 138ee86dfeeSDavid Gibson if (ret < 0) { 139ee86dfeeSDavid Gibson return ret; 140ee86dfeeSDavid Gibson } 141ee86dfeeSDavid Gibson 1423954d33aSAnthony Liguori if (pc->devnode) { 1433954d33aSAnthony Liguori ret = (pc->devnode)(dev, fdt, node_off); 1444040ab72SDavid Gibson if (ret < 0) { 1454040ab72SDavid Gibson return ret; 1464040ab72SDavid Gibson } 1474040ab72SDavid Gibson } 1484040ab72SDavid Gibson 1494040ab72SDavid Gibson return node_off; 1504040ab72SDavid Gibson } 1514040ab72SDavid Gibson 152ee86dfeeSDavid Gibson /* 153b45d63b6SBen Herrenschmidt * CRQ handling 154b45d63b6SBen Herrenschmidt */ 155*ce2918cbSDavid Gibson static target_ulong h_reg_crq(PowerPCCPU *cpu, SpaprMachineState *spapr, 156b45d63b6SBen Herrenschmidt target_ulong opcode, target_ulong *args) 157b45d63b6SBen Herrenschmidt { 158b45d63b6SBen Herrenschmidt target_ulong reg = args[0]; 159b45d63b6SBen Herrenschmidt target_ulong queue_addr = args[1]; 160b45d63b6SBen Herrenschmidt target_ulong queue_len = args[2]; 161*ce2918cbSDavid Gibson SpaprVioDevice *dev = spapr_vio_find_by_reg(spapr->vio_bus, reg); 162b45d63b6SBen Herrenschmidt 163b45d63b6SBen Herrenschmidt if (!dev) { 164d9599c92SDavid Gibson hcall_dprintf("Unit 0x" TARGET_FMT_lx " does not exist\n", reg); 165b45d63b6SBen Herrenschmidt return H_PARAMETER; 166b45d63b6SBen Herrenschmidt } 167b45d63b6SBen Herrenschmidt 168b45d63b6SBen Herrenschmidt /* We can't grok a queue size bigger than 256M for now */ 169b45d63b6SBen Herrenschmidt if (queue_len < 0x1000 || queue_len > 0x10000000) { 170d9599c92SDavid Gibson hcall_dprintf("Queue size too small or too big (0x" TARGET_FMT_lx 171d9599c92SDavid Gibson ")\n", queue_len); 172b45d63b6SBen Herrenschmidt return H_PARAMETER; 173b45d63b6SBen Herrenschmidt } 174b45d63b6SBen Herrenschmidt 175b45d63b6SBen Herrenschmidt /* Check queue alignment */ 176b45d63b6SBen Herrenschmidt if (queue_addr & 0xfff) { 177d9599c92SDavid Gibson hcall_dprintf("Queue not aligned (0x" TARGET_FMT_lx ")\n", queue_addr); 178b45d63b6SBen Herrenschmidt return H_PARAMETER; 179b45d63b6SBen Herrenschmidt } 180b45d63b6SBen Herrenschmidt 181b45d63b6SBen Herrenschmidt /* Check if device supports CRQs */ 182b45d63b6SBen Herrenschmidt if (!dev->crq.SendFunc) { 1838e01f355SDavid Gibson hcall_dprintf("Device does not support CRQ\n"); 184b45d63b6SBen Herrenschmidt return H_NOT_FOUND; 185b45d63b6SBen Herrenschmidt } 186b45d63b6SBen Herrenschmidt 187b45d63b6SBen Herrenschmidt /* Already a queue ? */ 188b45d63b6SBen Herrenschmidt if (dev->crq.qsize) { 1898e01f355SDavid Gibson hcall_dprintf("CRQ already registered\n"); 190b45d63b6SBen Herrenschmidt return H_RESOURCE; 191b45d63b6SBen Herrenschmidt } 192b45d63b6SBen Herrenschmidt dev->crq.qladdr = queue_addr; 193b45d63b6SBen Herrenschmidt dev->crq.qsize = queue_len; 194b45d63b6SBen Herrenschmidt dev->crq.qnext = 0; 195b45d63b6SBen Herrenschmidt 1967ab6a501SLaurent Vivier trace_spapr_vio_h_reg_crq(reg, queue_addr, queue_len); 197b45d63b6SBen Herrenschmidt return H_SUCCESS; 198b45d63b6SBen Herrenschmidt } 199b45d63b6SBen Herrenschmidt 200*ce2918cbSDavid Gibson static target_ulong free_crq(SpaprVioDevice *dev) 2018e01f355SDavid Gibson { 2028e01f355SDavid Gibson dev->crq.qladdr = 0; 2038e01f355SDavid Gibson dev->crq.qsize = 0; 2048e01f355SDavid Gibson dev->crq.qnext = 0; 2058e01f355SDavid Gibson 2067ab6a501SLaurent Vivier trace_spapr_vio_free_crq(dev->reg); 2078e01f355SDavid Gibson 2088e01f355SDavid Gibson return H_SUCCESS; 2098e01f355SDavid Gibson } 2108e01f355SDavid Gibson 211*ce2918cbSDavid Gibson static target_ulong h_free_crq(PowerPCCPU *cpu, SpaprMachineState *spapr, 212b45d63b6SBen Herrenschmidt target_ulong opcode, target_ulong *args) 213b45d63b6SBen Herrenschmidt { 214b45d63b6SBen Herrenschmidt target_ulong reg = args[0]; 215*ce2918cbSDavid Gibson SpaprVioDevice *dev = spapr_vio_find_by_reg(spapr->vio_bus, reg); 216b45d63b6SBen Herrenschmidt 217b45d63b6SBen Herrenschmidt if (!dev) { 218d9599c92SDavid Gibson hcall_dprintf("Unit 0x" TARGET_FMT_lx " does not exist\n", reg); 219b45d63b6SBen Herrenschmidt return H_PARAMETER; 220b45d63b6SBen Herrenschmidt } 221b45d63b6SBen Herrenschmidt 2228e01f355SDavid Gibson return free_crq(dev); 223b45d63b6SBen Herrenschmidt } 224b45d63b6SBen Herrenschmidt 225*ce2918cbSDavid Gibson static target_ulong h_send_crq(PowerPCCPU *cpu, SpaprMachineState *spapr, 226b45d63b6SBen Herrenschmidt target_ulong opcode, target_ulong *args) 227b45d63b6SBen Herrenschmidt { 228b45d63b6SBen Herrenschmidt target_ulong reg = args[0]; 229b45d63b6SBen Herrenschmidt target_ulong msg_hi = args[1]; 230b45d63b6SBen Herrenschmidt target_ulong msg_lo = args[2]; 231*ce2918cbSDavid Gibson SpaprVioDevice *dev = spapr_vio_find_by_reg(spapr->vio_bus, reg); 232b45d63b6SBen Herrenschmidt uint64_t crq_mangle[2]; 233b45d63b6SBen Herrenschmidt 234b45d63b6SBen Herrenschmidt if (!dev) { 235d9599c92SDavid Gibson hcall_dprintf("Unit 0x" TARGET_FMT_lx " does not exist\n", reg); 236b45d63b6SBen Herrenschmidt return H_PARAMETER; 237b45d63b6SBen Herrenschmidt } 238b45d63b6SBen Herrenschmidt crq_mangle[0] = cpu_to_be64(msg_hi); 239b45d63b6SBen Herrenschmidt crq_mangle[1] = cpu_to_be64(msg_lo); 240b45d63b6SBen Herrenschmidt 241b45d63b6SBen Herrenschmidt if (dev->crq.SendFunc) { 242b45d63b6SBen Herrenschmidt return dev->crq.SendFunc(dev, (uint8_t *)crq_mangle); 243b45d63b6SBen Herrenschmidt } 244b45d63b6SBen Herrenschmidt 245b45d63b6SBen Herrenschmidt return H_HARDWARE; 246b45d63b6SBen Herrenschmidt } 247b45d63b6SBen Herrenschmidt 248*ce2918cbSDavid Gibson static target_ulong h_enable_crq(PowerPCCPU *cpu, SpaprMachineState *spapr, 249b45d63b6SBen Herrenschmidt target_ulong opcode, target_ulong *args) 250b45d63b6SBen Herrenschmidt { 251b45d63b6SBen Herrenschmidt target_ulong reg = args[0]; 252*ce2918cbSDavid Gibson SpaprVioDevice *dev = spapr_vio_find_by_reg(spapr->vio_bus, reg); 253b45d63b6SBen Herrenschmidt 254b45d63b6SBen Herrenschmidt if (!dev) { 255d9599c92SDavid Gibson hcall_dprintf("Unit 0x" TARGET_FMT_lx " does not exist\n", reg); 256b45d63b6SBen Herrenschmidt return H_PARAMETER; 257b45d63b6SBen Herrenschmidt } 258b45d63b6SBen Herrenschmidt 259b45d63b6SBen Herrenschmidt return 0; 260b45d63b6SBen Herrenschmidt } 261b45d63b6SBen Herrenschmidt 262b45d63b6SBen Herrenschmidt /* Returns negative error, 0 success, or positive: queue full */ 263*ce2918cbSDavid Gibson int spapr_vio_send_crq(SpaprVioDevice *dev, uint8_t *crq) 264b45d63b6SBen Herrenschmidt { 265b45d63b6SBen Herrenschmidt int rc; 266b45d63b6SBen Herrenschmidt uint8_t byte; 267b45d63b6SBen Herrenschmidt 268b45d63b6SBen Herrenschmidt if (!dev->crq.qsize) { 269ce9863b7SCédric Le Goater error_report("spapr_vio_send_creq on uninitialized queue"); 270b45d63b6SBen Herrenschmidt return -1; 271b45d63b6SBen Herrenschmidt } 272b45d63b6SBen Herrenschmidt 273b45d63b6SBen Herrenschmidt /* Maybe do a fast path for KVM just writing to the pages */ 274ad0ebb91SDavid Gibson rc = spapr_vio_dma_read(dev, dev->crq.qladdr + dev->crq.qnext, &byte, 1); 275b45d63b6SBen Herrenschmidt if (rc) { 276b45d63b6SBen Herrenschmidt return rc; 277b45d63b6SBen Herrenschmidt } 278b45d63b6SBen Herrenschmidt if (byte != 0) { 279b45d63b6SBen Herrenschmidt return 1; 280b45d63b6SBen Herrenschmidt } 281b45d63b6SBen Herrenschmidt 282ad0ebb91SDavid Gibson rc = spapr_vio_dma_write(dev, dev->crq.qladdr + dev->crq.qnext + 8, 283b45d63b6SBen Herrenschmidt &crq[8], 8); 284b45d63b6SBen Herrenschmidt if (rc) { 285b45d63b6SBen Herrenschmidt return rc; 286b45d63b6SBen Herrenschmidt } 287b45d63b6SBen Herrenschmidt 288b45d63b6SBen Herrenschmidt kvmppc_eieio(); 289b45d63b6SBen Herrenschmidt 290ad0ebb91SDavid Gibson rc = spapr_vio_dma_write(dev, dev->crq.qladdr + dev->crq.qnext, crq, 8); 291b45d63b6SBen Herrenschmidt if (rc) { 292b45d63b6SBen Herrenschmidt return rc; 293b45d63b6SBen Herrenschmidt } 294b45d63b6SBen Herrenschmidt 295b45d63b6SBen Herrenschmidt dev->crq.qnext = (dev->crq.qnext + 16) % dev->crq.qsize; 296b45d63b6SBen Herrenschmidt 297b45d63b6SBen Herrenschmidt if (dev->signal_state & 1) { 298a307d594SAlexey Kardashevskiy qemu_irq_pulse(spapr_vio_qirq(dev)); 299b45d63b6SBen Herrenschmidt } 300b45d63b6SBen Herrenschmidt 301b45d63b6SBen Herrenschmidt return 0; 302b45d63b6SBen Herrenschmidt } 303b45d63b6SBen Herrenschmidt 30408942ac1SBen Herrenschmidt /* "quiesce" handling */ 30508942ac1SBen Herrenschmidt 306*ce2918cbSDavid Gibson static void spapr_vio_quiesce_one(SpaprVioDevice *dev) 30708942ac1SBen Herrenschmidt { 3082b7dc949SPaolo Bonzini if (dev->tcet) { 309a83000f5SAnthony Liguori device_reset(DEVICE(dev->tcet)); 31008942ac1SBen Herrenschmidt } 3114dd96f24SDavid Gibson free_crq(dev); 31208942ac1SBen Herrenschmidt } 31308942ac1SBen Herrenschmidt 314*ce2918cbSDavid Gibson void spapr_vio_set_bypass(SpaprVioDevice *dev, bool bypass) 315ee9a569aSAlexey Kardashevskiy { 316ee9a569aSAlexey Kardashevskiy if (!dev->tcet) { 317ee9a569aSAlexey Kardashevskiy return; 318ee9a569aSAlexey Kardashevskiy } 319ee9a569aSAlexey Kardashevskiy 320ee9a569aSAlexey Kardashevskiy memory_region_set_enabled(&dev->mrbypass, bypass); 321ee9a569aSAlexey Kardashevskiy memory_region_set_enabled(spapr_tce_get_iommu(dev->tcet), !bypass); 322ee9a569aSAlexey Kardashevskiy 323ee9a569aSAlexey Kardashevskiy dev->tcet->bypass = bypass; 324ee9a569aSAlexey Kardashevskiy } 325ee9a569aSAlexey Kardashevskiy 326*ce2918cbSDavid Gibson static void rtas_set_tce_bypass(PowerPCCPU *cpu, SpaprMachineState *spapr, 327210b580bSAnthony Liguori uint32_t token, 32808942ac1SBen Herrenschmidt uint32_t nargs, target_ulong args, 32908942ac1SBen Herrenschmidt uint32_t nret, target_ulong rets) 33008942ac1SBen Herrenschmidt { 331*ce2918cbSDavid Gibson SpaprVioBus *bus = spapr->vio_bus; 332*ce2918cbSDavid Gibson SpaprVioDevice *dev; 33308942ac1SBen Herrenschmidt uint32_t unit, enable; 33408942ac1SBen Herrenschmidt 33508942ac1SBen Herrenschmidt if (nargs != 2) { 336a64d325dSAlexey Kardashevskiy rtas_st(rets, 0, RTAS_OUT_PARAM_ERROR); 33708942ac1SBen Herrenschmidt return; 33808942ac1SBen Herrenschmidt } 33908942ac1SBen Herrenschmidt unit = rtas_ld(args, 0); 34008942ac1SBen Herrenschmidt enable = rtas_ld(args, 1); 34108942ac1SBen Herrenschmidt dev = spapr_vio_find_by_reg(bus, unit); 34208942ac1SBen Herrenschmidt if (!dev) { 343a64d325dSAlexey Kardashevskiy rtas_st(rets, 0, RTAS_OUT_PARAM_ERROR); 34408942ac1SBen Herrenschmidt return; 34508942ac1SBen Herrenschmidt } 346ad0ebb91SDavid Gibson 3472b7dc949SPaolo Bonzini if (!dev->tcet) { 348a64d325dSAlexey Kardashevskiy rtas_st(rets, 0, RTAS_OUT_PARAM_ERROR); 34953724ee5SDavid Gibson return; 35008942ac1SBen Herrenschmidt } 35108942ac1SBen Herrenschmidt 352ee9a569aSAlexey Kardashevskiy spapr_vio_set_bypass(dev, !!enable); 35353724ee5SDavid Gibson 354a64d325dSAlexey Kardashevskiy rtas_st(rets, 0, RTAS_OUT_SUCCESS); 35508942ac1SBen Herrenschmidt } 35608942ac1SBen Herrenschmidt 357*ce2918cbSDavid Gibson static void rtas_quiesce(PowerPCCPU *cpu, SpaprMachineState *spapr, 358210b580bSAnthony Liguori uint32_t token, 35908942ac1SBen Herrenschmidt uint32_t nargs, target_ulong args, 36008942ac1SBen Herrenschmidt uint32_t nret, target_ulong rets) 36108942ac1SBen Herrenschmidt { 362*ce2918cbSDavid Gibson SpaprVioBus *bus = spapr->vio_bus; 3630866aca1SAnthony Liguori BusChild *kid; 364*ce2918cbSDavid Gibson SpaprVioDevice *dev = NULL; 36508942ac1SBen Herrenschmidt 36608942ac1SBen Herrenschmidt if (nargs != 0) { 367a64d325dSAlexey Kardashevskiy rtas_st(rets, 0, RTAS_OUT_PARAM_ERROR); 36808942ac1SBen Herrenschmidt return; 36908942ac1SBen Herrenschmidt } 37008942ac1SBen Herrenschmidt 3710866aca1SAnthony Liguori QTAILQ_FOREACH(kid, &bus->bus.children, sibling) { 372*ce2918cbSDavid Gibson dev = (SpaprVioDevice *)kid->child; 37308942ac1SBen Herrenschmidt spapr_vio_quiesce_one(dev); 37408942ac1SBen Herrenschmidt } 37508942ac1SBen Herrenschmidt 376a64d325dSAlexey Kardashevskiy rtas_st(rets, 0, RTAS_OUT_SUCCESS); 37708942ac1SBen Herrenschmidt } 37808942ac1SBen Herrenschmidt 379*ce2918cbSDavid Gibson static SpaprVioDevice *reg_conflict(SpaprVioDevice *dev) 3809fc380d3SMichael Ellerman { 381*ce2918cbSDavid Gibson SpaprVioBus *bus = SPAPR_VIO_BUS(dev->qdev.parent_bus); 3820866aca1SAnthony Liguori BusChild *kid; 383*ce2918cbSDavid Gibson SpaprVioDevice *other; 3849fc380d3SMichael Ellerman 3859fc380d3SMichael Ellerman /* 386d601fac4SDavid Gibson * Check for a device other than the given one which is already 387d601fac4SDavid Gibson * using the requested address. We have to open code this because 388d601fac4SDavid Gibson * the given dev might already be in the list. 3899fc380d3SMichael Ellerman */ 3900866aca1SAnthony Liguori QTAILQ_FOREACH(kid, &bus->bus.children, sibling) { 391fd506b4fSDavid Gibson other = VIO_SPAPR_DEVICE(kid->child); 3929fc380d3SMichael Ellerman 393d601fac4SDavid Gibson if (other != dev && other->reg == dev->reg) { 394d601fac4SDavid Gibson return other; 3959fc380d3SMichael Ellerman } 3969fc380d3SMichael Ellerman } 3979fc380d3SMichael Ellerman 3989fc380d3SMichael Ellerman return 0; 3999fc380d3SMichael Ellerman } 4009fc380d3SMichael Ellerman 401b1c7f725SDavid Gibson static void spapr_vio_busdev_reset(DeviceState *qdev) 4028e01f355SDavid Gibson { 403*ce2918cbSDavid Gibson SpaprVioDevice *dev = VIO_SPAPR_DEVICE(qdev); 404*ce2918cbSDavid Gibson SpaprVioDeviceClass *pc = VIO_SPAPR_DEVICE_GET_CLASS(dev); 4058e01f355SDavid Gibson 4064dd96f24SDavid Gibson /* Shut down the request queue and TCEs if necessary */ 4074dd96f24SDavid Gibson spapr_vio_quiesce_one(dev); 4084dd96f24SDavid Gibson 4094dd96f24SDavid Gibson dev->signal_state = 0; 410b1c7f725SDavid Gibson 411ee9a569aSAlexey Kardashevskiy spapr_vio_set_bypass(dev, false); 412b1c7f725SDavid Gibson if (pc->reset) { 413b1c7f725SDavid Gibson pc->reset(dev); 414b1c7f725SDavid Gibson } 4158e01f355SDavid Gibson } 4168e01f355SDavid Gibson 41782cffa2eSCédric Le Goater /* 41882cffa2eSCédric Le Goater * The register property of a VIO device is defined in livirt using 41982cffa2eSCédric Le Goater * 0x1000 as a base register number plus a 0x1000 increment. For the 42082cffa2eSCédric Le Goater * VIO tty device, the base number is changed to 0x30000000. QEMU uses 42182cffa2eSCédric Le Goater * a base register number of 0x71000000 and then a simple increment. 42282cffa2eSCédric Le Goater * 42382cffa2eSCédric Le Goater * The formula below tries to compute a unique index number from the 42482cffa2eSCédric Le Goater * register value that will be used to define the IRQ number of the 42582cffa2eSCédric Le Goater * VIO device. 42682cffa2eSCédric Le Goater * 42782cffa2eSCédric Le Goater * A maximum of 256 VIO devices is covered. Collisions are possible 42882cffa2eSCédric Le Goater * but they will be detected when the IRQ is claimed. 42982cffa2eSCédric Le Goater */ 43082cffa2eSCédric Le Goater static inline uint32_t spapr_vio_reg_to_irq(uint32_t reg) 43182cffa2eSCédric Le Goater { 43282cffa2eSCédric Le Goater uint32_t irq; 43382cffa2eSCédric Le Goater 43482cffa2eSCédric Le Goater if (reg >= SPAPR_VIO_REG_BASE) { 43582cffa2eSCédric Le Goater /* 43682cffa2eSCédric Le Goater * VIO device register values when allocated by QEMU. For 43782cffa2eSCédric Le Goater * these, we simply mask the high bits to fit the overall 43882cffa2eSCédric Le Goater * range: [0x00 - 0xff]. 43982cffa2eSCédric Le Goater * 44082cffa2eSCédric Le Goater * The nvram VIO device (reg=0x71000000) is a static device of 44182cffa2eSCédric Le Goater * the pseries machine and so is always allocated by QEMU. Its 44282cffa2eSCédric Le Goater * IRQ number is 0x0. 44382cffa2eSCédric Le Goater */ 44482cffa2eSCédric Le Goater irq = reg & 0xff; 44582cffa2eSCédric Le Goater 44682cffa2eSCédric Le Goater } else if (reg >= 0x30000000) { 44782cffa2eSCédric Le Goater /* 44882cffa2eSCédric Le Goater * VIO tty devices register values, when allocated by livirt, 44982cffa2eSCédric Le Goater * are mapped in range [0xf0 - 0xff], gives us a maximum of 16 45082cffa2eSCédric Le Goater * vtys. 45182cffa2eSCédric Le Goater */ 45282cffa2eSCédric Le Goater irq = 0xf0 | ((reg >> 12) & 0xf); 45382cffa2eSCédric Le Goater 45482cffa2eSCédric Le Goater } else { 45582cffa2eSCédric Le Goater /* 45682cffa2eSCédric Le Goater * Other VIO devices register values, when allocated by 45782cffa2eSCédric Le Goater * livirt, should be mapped in range [0x00 - 0xef]. Conflicts 45882cffa2eSCédric Le Goater * will be detected when IRQ is claimed. 45982cffa2eSCédric Le Goater */ 46082cffa2eSCédric Le Goater irq = (reg >> 12) & 0xff; 46182cffa2eSCédric Le Goater } 46282cffa2eSCédric Le Goater 46382cffa2eSCédric Le Goater return SPAPR_IRQ_VIO | irq; 46482cffa2eSCédric Le Goater } 46582cffa2eSCédric Le Goater 46628b07e73SMarkus Armbruster static void spapr_vio_busdev_realize(DeviceState *qdev, Error **errp) 4674040ab72SDavid Gibson { 468*ce2918cbSDavid Gibson SpaprMachineState *spapr = SPAPR_MACHINE(qdev_get_machine()); 469*ce2918cbSDavid Gibson SpaprVioDevice *dev = (SpaprVioDevice *)qdev; 470*ce2918cbSDavid Gibson SpaprVioDeviceClass *pc = VIO_SPAPR_DEVICE_GET_CLASS(dev); 4714040ab72SDavid Gibson char *id; 472a005b3efSGreg Kurz Error *local_err = NULL; 4739fc380d3SMichael Ellerman 474d601fac4SDavid Gibson if (dev->reg != -1) { 475d601fac4SDavid Gibson /* 476d601fac4SDavid Gibson * Explicitly assigned address, just verify that no-one else 477d601fac4SDavid Gibson * is using it. other mechanism). We have to open code this 478d601fac4SDavid Gibson * rather than using spapr_vio_find_by_reg() because sdev 479d601fac4SDavid Gibson * itself is already in the list. 480d601fac4SDavid Gibson */ 481*ce2918cbSDavid Gibson SpaprVioDevice *other = reg_conflict(dev); 482d601fac4SDavid Gibson 483d601fac4SDavid Gibson if (other) { 48428b07e73SMarkus Armbruster error_setg(errp, "%s and %s devices conflict at address %#x", 485d601fac4SDavid Gibson object_get_typename(OBJECT(qdev)), 486d601fac4SDavid Gibson object_get_typename(OBJECT(&other->qdev)), 487d601fac4SDavid Gibson dev->reg); 48828b07e73SMarkus Armbruster return; 489d601fac4SDavid Gibson } 490d601fac4SDavid Gibson } else { 491d601fac4SDavid Gibson /* Need to assign an address */ 492*ce2918cbSDavid Gibson SpaprVioBus *bus = SPAPR_VIO_BUS(dev->qdev.parent_bus); 493d601fac4SDavid Gibson 494d601fac4SDavid Gibson do { 495d601fac4SDavid Gibson dev->reg = bus->next_reg++; 496d601fac4SDavid Gibson } while (reg_conflict(dev)); 4979fc380d3SMichael Ellerman } 4984040ab72SDavid Gibson 4991e34d859SMichael Ellerman /* Don't overwrite ids assigned on the command line */ 5001e34d859SMichael Ellerman if (!dev->qdev.id) { 501c4eda5b7SDavid Gibson id = spapr_vio_get_dev_name(DEVICE(dev)); 5024040ab72SDavid Gibson dev->qdev.id = id; 5031e34d859SMichael Ellerman } 504e6c866d4SDavid Gibson 50582cffa2eSCédric Le Goater dev->irq = spapr_vio_reg_to_irq(dev->reg); 50682cffa2eSCédric Le Goater 50782cffa2eSCédric Le Goater if (SPAPR_MACHINE_GET_CLASS(spapr)->legacy_irq_allocation) { 5084fe75a8cSCédric Le Goater dev->irq = spapr_irq_findone(spapr, &local_err); 5094fe75a8cSCédric Le Goater if (local_err) { 5104fe75a8cSCédric Le Goater error_propagate(errp, local_err); 5114fe75a8cSCédric Le Goater return; 5124fe75a8cSCédric Le Goater } 5134fe75a8cSCédric Le Goater } 5144fe75a8cSCédric Le Goater 5154fe75a8cSCédric Le Goater spapr_irq_claim(spapr, dev->irq, false, &local_err); 516a005b3efSGreg Kurz if (local_err) { 517a005b3efSGreg Kurz error_propagate(errp, local_err); 51828b07e73SMarkus Armbruster return; 519416343b1SPaolo Bonzini } 5204040ab72SDavid Gibson 52153724ee5SDavid Gibson if (pc->rtce_window_size) { 5224290ca49SAlexey Kardashevskiy uint32_t liobn = SPAPR_VIO_LIOBN(dev->reg); 523ee9a569aSAlexey Kardashevskiy 524ee9a569aSAlexey Kardashevskiy memory_region_init(&dev->mrroot, OBJECT(dev), "iommu-spapr-root", 525ee9a569aSAlexey Kardashevskiy ram_size); 526ee9a569aSAlexey Kardashevskiy memory_region_init_alias(&dev->mrbypass, OBJECT(dev), 527ee9a569aSAlexey Kardashevskiy "iommu-spapr-bypass", get_system_memory(), 528ee9a569aSAlexey Kardashevskiy 0, ram_size); 529ee9a569aSAlexey Kardashevskiy memory_region_add_subregion_overlap(&dev->mrroot, 0, &dev->mrbypass, 1); 530ee9a569aSAlexey Kardashevskiy address_space_init(&dev->as, &dev->mrroot, qdev->id); 531ee9a569aSAlexey Kardashevskiy 532df7625d4SAlexey Kardashevskiy dev->tcet = spapr_tce_new_table(qdev, liobn); 533df7625d4SAlexey Kardashevskiy spapr_tce_table_enable(dev->tcet, SPAPR_TCE_PAGE_SHIFT, 0, 534df7625d4SAlexey Kardashevskiy pc->rtce_window_size >> SPAPR_TCE_PAGE_SHIFT); 535ee9a569aSAlexey Kardashevskiy dev->tcet->vdev = dev; 536ee9a569aSAlexey Kardashevskiy memory_region_add_subregion_overlap(&dev->mrroot, 0, 537ee9a569aSAlexey Kardashevskiy spapr_tce_get_iommu(dev->tcet), 2); 53853724ee5SDavid Gibson } 539ee86dfeeSDavid Gibson 54028b07e73SMarkus Armbruster pc->realize(dev, errp); 5414040ab72SDavid Gibson } 5424040ab72SDavid Gibson 543*ce2918cbSDavid Gibson static target_ulong h_vio_signal(PowerPCCPU *cpu, SpaprMachineState *spapr, 54400dc738dSDavid Gibson target_ulong opcode, 54500dc738dSDavid Gibson target_ulong *args) 54600dc738dSDavid Gibson { 54700dc738dSDavid Gibson target_ulong reg = args[0]; 54800dc738dSDavid Gibson target_ulong mode = args[1]; 549*ce2918cbSDavid Gibson SpaprVioDevice *dev = spapr_vio_find_by_reg(spapr->vio_bus, reg); 550*ce2918cbSDavid Gibson SpaprVioDeviceClass *pc; 55100dc738dSDavid Gibson 55200dc738dSDavid Gibson if (!dev) { 55300dc738dSDavid Gibson return H_PARAMETER; 55400dc738dSDavid Gibson } 55500dc738dSDavid Gibson 5563954d33aSAnthony Liguori pc = VIO_SPAPR_DEVICE_GET_CLASS(dev); 55700dc738dSDavid Gibson 5583954d33aSAnthony Liguori if (mode & ~pc->signal_mask) { 55900dc738dSDavid Gibson return H_PARAMETER; 56000dc738dSDavid Gibson } 56100dc738dSDavid Gibson 56200dc738dSDavid Gibson dev->signal_state = mode; 56300dc738dSDavid Gibson 56400dc738dSDavid Gibson return H_SUCCESS; 56500dc738dSDavid Gibson } 56600dc738dSDavid Gibson 567*ce2918cbSDavid Gibson SpaprVioBus *spapr_vio_bus_init(void) 5684040ab72SDavid Gibson { 569*ce2918cbSDavid Gibson SpaprVioBus *bus; 5704040ab72SDavid Gibson BusState *qbus; 5714040ab72SDavid Gibson DeviceState *dev; 5724040ab72SDavid Gibson 5734040ab72SDavid Gibson /* Create bridge device */ 574215e2098SCao jin dev = qdev_create(NULL, TYPE_SPAPR_VIO_BRIDGE); 5754040ab72SDavid Gibson qdev_init_nofail(dev); 5764040ab72SDavid Gibson 5774040ab72SDavid Gibson /* Create bus on bridge device */ 5780d936928SAnthony Liguori qbus = qbus_create(TYPE_SPAPR_VIO_BUS, dev, "spapr-vio"); 579215e2098SCao jin bus = SPAPR_VIO_BUS(qbus); 58082cffa2eSCédric Le Goater bus->next_reg = SPAPR_VIO_REG_BASE; 5814040ab72SDavid Gibson 58200dc738dSDavid Gibson /* hcall-vio */ 58300dc738dSDavid Gibson spapr_register_hypercall(H_VIO_SIGNAL, h_vio_signal); 58400dc738dSDavid Gibson 585b45d63b6SBen Herrenschmidt /* hcall-crq */ 586b45d63b6SBen Herrenschmidt spapr_register_hypercall(H_REG_CRQ, h_reg_crq); 587b45d63b6SBen Herrenschmidt spapr_register_hypercall(H_FREE_CRQ, h_free_crq); 588b45d63b6SBen Herrenschmidt spapr_register_hypercall(H_SEND_CRQ, h_send_crq); 589b45d63b6SBen Herrenschmidt spapr_register_hypercall(H_ENABLE_CRQ, h_enable_crq); 590b45d63b6SBen Herrenschmidt 59108942ac1SBen Herrenschmidt /* RTAS calls */ 5923a3b8502SAlexey Kardashevskiy spapr_rtas_register(RTAS_IBM_SET_TCE_BYPASS, "ibm,set-tce-bypass", 5933a3b8502SAlexey Kardashevskiy rtas_set_tce_bypass); 5943a3b8502SAlexey Kardashevskiy spapr_rtas_register(RTAS_QUIESCE, "quiesce", rtas_quiesce); 59508942ac1SBen Herrenschmidt 5964040ab72SDavid Gibson return bus; 5974040ab72SDavid Gibson } 5984040ab72SDavid Gibson 599999e12bbSAnthony Liguori static void spapr_vio_bridge_class_init(ObjectClass *klass, void *data) 600999e12bbSAnthony Liguori { 6015a06393fSAlexey Kardashevskiy DeviceClass *dc = DEVICE_CLASS(klass); 602999e12bbSAnthony Liguori 6035a06393fSAlexey Kardashevskiy dc->fw_name = "vdevice"; 604999e12bbSAnthony Liguori } 605999e12bbSAnthony Liguori 6068c43a6f0SAndreas Färber static const TypeInfo spapr_vio_bridge_info = { 607215e2098SCao jin .name = TYPE_SPAPR_VIO_BRIDGE, 60839bffca2SAnthony Liguori .parent = TYPE_SYS_BUS_DEVICE, 609999e12bbSAnthony Liguori .class_init = spapr_vio_bridge_class_init, 6104040ab72SDavid Gibson }; 6114040ab72SDavid Gibson 612b368a7d8SDavid Gibson const VMStateDescription vmstate_spapr_vio = { 613b368a7d8SDavid Gibson .name = "spapr_vio", 614b368a7d8SDavid Gibson .version_id = 1, 615b368a7d8SDavid Gibson .minimum_version_id = 1, 616b368a7d8SDavid Gibson .fields = (VMStateField[]) { 617b368a7d8SDavid Gibson /* Sanity check */ 618*ce2918cbSDavid Gibson VMSTATE_UINT32_EQUAL(reg, SpaprVioDevice, NULL), 619*ce2918cbSDavid Gibson VMSTATE_UINT32_EQUAL(irq, SpaprVioDevice, NULL), 620b368a7d8SDavid Gibson 621b368a7d8SDavid Gibson /* General VIO device state */ 622*ce2918cbSDavid Gibson VMSTATE_UINT64(signal_state, SpaprVioDevice), 623*ce2918cbSDavid Gibson VMSTATE_UINT64(crq.qladdr, SpaprVioDevice), 624*ce2918cbSDavid Gibson VMSTATE_UINT32(crq.qsize, SpaprVioDevice), 625*ce2918cbSDavid Gibson VMSTATE_UINT32(crq.qnext, SpaprVioDevice), 626b368a7d8SDavid Gibson 627b368a7d8SDavid Gibson VMSTATE_END_OF_LIST() 628b368a7d8SDavid Gibson }, 629b368a7d8SDavid Gibson }; 630b368a7d8SDavid Gibson 63139bffca2SAnthony Liguori static void vio_spapr_device_class_init(ObjectClass *klass, void *data) 63239bffca2SAnthony Liguori { 63339bffca2SAnthony Liguori DeviceClass *k = DEVICE_CLASS(klass); 63428b07e73SMarkus Armbruster k->realize = spapr_vio_busdev_realize; 635b1c7f725SDavid Gibson k->reset = spapr_vio_busdev_reset; 6360d936928SAnthony Liguori k->bus_type = TYPE_SPAPR_VIO_BUS; 63739bffca2SAnthony Liguori } 63839bffca2SAnthony Liguori 6398c43a6f0SAndreas Färber static const TypeInfo spapr_vio_type_info = { 6403954d33aSAnthony Liguori .name = TYPE_VIO_SPAPR_DEVICE, 6413954d33aSAnthony Liguori .parent = TYPE_DEVICE, 642*ce2918cbSDavid Gibson .instance_size = sizeof(SpaprVioDevice), 6433954d33aSAnthony Liguori .abstract = true, 644*ce2918cbSDavid Gibson .class_size = sizeof(SpaprVioDeviceClass), 64539bffca2SAnthony Liguori .class_init = vio_spapr_device_class_init, 6463954d33aSAnthony Liguori }; 6473954d33aSAnthony Liguori 64883f7d43aSAndreas Färber static void spapr_vio_register_types(void) 6494040ab72SDavid Gibson { 6500d936928SAnthony Liguori type_register_static(&spapr_vio_bus_info); 65139bffca2SAnthony Liguori type_register_static(&spapr_vio_bridge_info); 6523954d33aSAnthony Liguori type_register_static(&spapr_vio_type_info); 6534040ab72SDavid Gibson } 6544040ab72SDavid Gibson 65583f7d43aSAndreas Färber type_init(spapr_vio_register_types) 6564040ab72SDavid Gibson 65705c19438SDavid Gibson static int compare_reg(const void *p1, const void *p2) 65805c19438SDavid Gibson { 659*ce2918cbSDavid Gibson SpaprVioDevice const *dev1, *dev2; 66005c19438SDavid Gibson 661*ce2918cbSDavid Gibson dev1 = (SpaprVioDevice *)*(DeviceState **)p1; 662*ce2918cbSDavid Gibson dev2 = (SpaprVioDevice *)*(DeviceState **)p2; 66305c19438SDavid Gibson 66405c19438SDavid Gibson if (dev1->reg < dev2->reg) { 66505c19438SDavid Gibson return -1; 66605c19438SDavid Gibson } 66705c19438SDavid Gibson if (dev1->reg == dev2->reg) { 66805c19438SDavid Gibson return 0; 66905c19438SDavid Gibson } 67005c19438SDavid Gibson 67105c19438SDavid Gibson /* dev1->reg > dev2->reg */ 67205c19438SDavid Gibson return 1; 67305c19438SDavid Gibson } 67405c19438SDavid Gibson 675*ce2918cbSDavid Gibson void spapr_dt_vdevice(SpaprVioBus *bus, void *fdt) 6764040ab72SDavid Gibson { 67705c19438SDavid Gibson DeviceState *qdev, **qdevs; 6780866aca1SAnthony Liguori BusChild *kid; 67905c19438SDavid Gibson int i, num, ret = 0; 680bf5a6696SDavid Gibson int node; 681bf5a6696SDavid Gibson 682bf5a6696SDavid Gibson _FDT(node = fdt_add_subnode(fdt, 0, "vdevice")); 683bf5a6696SDavid Gibson 684bf5a6696SDavid Gibson _FDT(fdt_setprop_string(fdt, node, "device_type", "vdevice")); 685bf5a6696SDavid Gibson _FDT(fdt_setprop_string(fdt, node, "compatible", "IBM,vdevice")); 686bf5a6696SDavid Gibson _FDT(fdt_setprop_cell(fdt, node, "#address-cells", 1)); 687bf5a6696SDavid Gibson _FDT(fdt_setprop_cell(fdt, node, "#size-cells", 0)); 688bf5a6696SDavid Gibson _FDT(fdt_setprop_cell(fdt, node, "#interrupt-cells", 2)); 689bf5a6696SDavid Gibson _FDT(fdt_setprop(fdt, node, "interrupt-controller", NULL, 0)); 6904040ab72SDavid Gibson 69105c19438SDavid Gibson /* Count qdevs on the bus list */ 69205c19438SDavid Gibson num = 0; 6930866aca1SAnthony Liguori QTAILQ_FOREACH(kid, &bus->bus.children, sibling) { 69405c19438SDavid Gibson num++; 69505c19438SDavid Gibson } 69605c19438SDavid Gibson 69705c19438SDavid Gibson /* Copy out into an array of pointers */ 698dec4ec40SGreg Kurz qdevs = g_new(DeviceState *, num); 69905c19438SDavid Gibson num = 0; 7000866aca1SAnthony Liguori QTAILQ_FOREACH(kid, &bus->bus.children, sibling) { 7010866aca1SAnthony Liguori qdevs[num++] = kid->child; 70205c19438SDavid Gibson } 70305c19438SDavid Gibson 70405c19438SDavid Gibson /* Sort the array */ 70505c19438SDavid Gibson qsort(qdevs, num, sizeof(qdev), compare_reg); 70605c19438SDavid Gibson 70705c19438SDavid Gibson /* Hack alert. Give the devices to libfdt in reverse order, we happen 70805c19438SDavid Gibson * to know that will mean they are in forward order in the tree. */ 70905c19438SDavid Gibson for (i = num - 1; i >= 0; i--) { 710*ce2918cbSDavid Gibson SpaprVioDevice *dev = (SpaprVioDevice *)(qdevs[i]); 711*ce2918cbSDavid Gibson SpaprVioDeviceClass *vdc = VIO_SPAPR_DEVICE_GET_CLASS(dev); 7124040ab72SDavid Gibson 7134040ab72SDavid Gibson ret = vio_make_devnode(dev, fdt); 7144040ab72SDavid Gibson if (ret < 0) { 715bf5a6696SDavid Gibson error_report("Couldn't create device node /vdevice/%s@%"PRIx32, 716bf5a6696SDavid Gibson vdc->dt_name, dev->reg); 717bf5a6696SDavid Gibson exit(1); 7184040ab72SDavid Gibson } 7194040ab72SDavid Gibson } 7204040ab72SDavid Gibson 7215f1d1fc5SMarkus Armbruster g_free(qdevs); 7224040ab72SDavid Gibson } 72368f3a94cSDavid Gibson 724*ce2918cbSDavid Gibson gchar *spapr_vio_stdout_path(SpaprVioBus *bus) 72568f3a94cSDavid Gibson { 726*ce2918cbSDavid Gibson SpaprVioDevice *dev; 72768f3a94cSDavid Gibson char *name, *path; 72868f3a94cSDavid Gibson 72968f3a94cSDavid Gibson dev = spapr_vty_get_default(bus); 7307c866c6aSDavid Gibson if (!dev) { 7317c866c6aSDavid Gibson return NULL; 73268f3a94cSDavid Gibson } 73368f3a94cSDavid Gibson 734c4eda5b7SDavid Gibson name = spapr_vio_get_dev_name(DEVICE(dev)); 7354ecf8aa5SStefan Weil path = g_strdup_printf("/vdevice/%s", name); 73668f3a94cSDavid Gibson 7374ecf8aa5SStefan Weil g_free(name); 7387c866c6aSDavid Gibson return path; 73968f3a94cSDavid Gibson } 740