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" 2603dd024fSPaolo Bonzini #include "qemu/log.h" 2783c9f4caSPaolo Bonzini #include "hw/loader.h" 284040ab72SDavid Gibson #include "elf.h" 294040ab72SDavid Gibson #include "hw/sysbus.h" 309c17d615SPaolo Bonzini #include "sysemu/kvm.h" 319c17d615SPaolo Bonzini #include "sysemu/device_tree.h" 32b45d63b6SBen Herrenschmidt #include "kvm_ppc.h" 33d6454270SMarkus Armbruster #include "migration/vmstate.h" 34efe2add7SCédric Le Goater #include "sysemu/qtest.h" 354040ab72SDavid Gibson 360d09e41aSPaolo Bonzini #include "hw/ppc/spapr.h" 370d09e41aSPaolo Bonzini #include "hw/ppc/spapr_vio.h" 38bf5a6696SDavid Gibson #include "hw/ppc/fdt.h" 397ab6a501SLaurent Vivier #include "trace.h" 404040ab72SDavid Gibson 414040ab72SDavid Gibson #include <libfdt.h> 424040ab72SDavid Gibson 4382cffa2eSCédric Le Goater #define SPAPR_VIO_REG_BASE 0x71000000 4482cffa2eSCédric Le Goater 45c4eda5b7SDavid Gibson static char *spapr_vio_get_dev_name(DeviceState *qdev) 46c4eda5b7SDavid Gibson { 47ce2918cbSDavid Gibson SpaprVioDevice *dev = VIO_SPAPR_DEVICE(qdev); 48ce2918cbSDavid Gibson SpaprVioDeviceClass *pc = VIO_SPAPR_DEVICE_GET_CLASS(dev); 49c4eda5b7SDavid Gibson 50c4eda5b7SDavid Gibson /* Device tree style name device@reg */ 519be38598SEduardo Habkost return g_strdup_printf("%s@%x", pc->dt_name, dev->reg); 52c4eda5b7SDavid Gibson } 53c4eda5b7SDavid Gibson 54c4eda5b7SDavid Gibson static void spapr_vio_bus_class_init(ObjectClass *klass, void *data) 55c4eda5b7SDavid Gibson { 56c4eda5b7SDavid Gibson BusClass *k = BUS_CLASS(klass); 57c4eda5b7SDavid Gibson 58c4eda5b7SDavid Gibson k->get_dev_path = spapr_vio_get_dev_name; 595a06393fSAlexey Kardashevskiy k->get_fw_dev_path = spapr_vio_get_dev_name; 60c4eda5b7SDavid Gibson } 61c4eda5b7SDavid Gibson 620d936928SAnthony Liguori static const TypeInfo spapr_vio_bus_info = { 630d936928SAnthony Liguori .name = TYPE_SPAPR_VIO_BUS, 640d936928SAnthony Liguori .parent = TYPE_BUS, 65c4eda5b7SDavid Gibson .class_init = spapr_vio_bus_class_init, 66ce2918cbSDavid Gibson .instance_size = sizeof(SpaprVioBus), 674040ab72SDavid Gibson }; 684040ab72SDavid Gibson 69ce2918cbSDavid Gibson SpaprVioDevice *spapr_vio_find_by_reg(SpaprVioBus *bus, uint32_t reg) 704040ab72SDavid Gibson { 710866aca1SAnthony Liguori BusChild *kid; 72ce2918cbSDavid Gibson SpaprVioDevice *dev = NULL; 734040ab72SDavid Gibson 740866aca1SAnthony Liguori QTAILQ_FOREACH(kid, &bus->bus.children, sibling) { 75ce2918cbSDavid Gibson dev = (SpaprVioDevice *)kid->child; 764040ab72SDavid Gibson if (dev->reg == reg) { 775435352cSDavid Gibson return dev; 784040ab72SDavid Gibson } 794040ab72SDavid Gibson } 804040ab72SDavid Gibson 815435352cSDavid Gibson return NULL; 824040ab72SDavid Gibson } 834040ab72SDavid Gibson 84ce2918cbSDavid Gibson static int vio_make_devnode(SpaprVioDevice *dev, 854040ab72SDavid Gibson void *fdt) 864040ab72SDavid Gibson { 87ce2918cbSDavid Gibson SpaprVioDeviceClass *pc = VIO_SPAPR_DEVICE_GET_CLASS(dev); 881e34d859SMichael Ellerman int vdevice_off, node_off, ret; 891e34d859SMichael Ellerman char *dt_name; 90864674faSStefan Berger const char *dt_compatible; 914040ab72SDavid Gibson 924040ab72SDavid Gibson vdevice_off = fdt_path_offset(fdt, "/vdevice"); 934040ab72SDavid Gibson if (vdevice_off < 0) { 944040ab72SDavid Gibson return vdevice_off; 954040ab72SDavid Gibson } 964040ab72SDavid Gibson 97c4eda5b7SDavid Gibson dt_name = spapr_vio_get_dev_name(DEVICE(dev)); 981e34d859SMichael Ellerman node_off = fdt_add_subnode(fdt, vdevice_off, dt_name); 994ecf8aa5SStefan Weil g_free(dt_name); 1004040ab72SDavid Gibson if (node_off < 0) { 1014040ab72SDavid Gibson return node_off; 1024040ab72SDavid Gibson } 1034040ab72SDavid Gibson 1044040ab72SDavid Gibson ret = fdt_setprop_cell(fdt, node_off, "reg", dev->reg); 1054040ab72SDavid Gibson if (ret < 0) { 1064040ab72SDavid Gibson return ret; 1074040ab72SDavid Gibson } 1084040ab72SDavid Gibson 1093954d33aSAnthony Liguori if (pc->dt_type) { 1104040ab72SDavid Gibson ret = fdt_setprop_string(fdt, node_off, "device_type", 1113954d33aSAnthony Liguori pc->dt_type); 1124040ab72SDavid Gibson if (ret < 0) { 1134040ab72SDavid Gibson return ret; 1144040ab72SDavid Gibson } 1154040ab72SDavid Gibson } 1164040ab72SDavid Gibson 117864674faSStefan Berger if (pc->get_dt_compatible) { 118864674faSStefan Berger dt_compatible = pc->get_dt_compatible(dev); 119864674faSStefan Berger } else { 120864674faSStefan Berger dt_compatible = pc->dt_compatible; 121864674faSStefan Berger } 122864674faSStefan Berger 123864674faSStefan Berger if (dt_compatible) { 1244040ab72SDavid Gibson ret = fdt_setprop_string(fdt, node_off, "compatible", 125864674faSStefan Berger dt_compatible); 1264040ab72SDavid Gibson if (ret < 0) { 1274040ab72SDavid Gibson return ret; 1284040ab72SDavid Gibson } 1294040ab72SDavid Gibson } 1304040ab72SDavid Gibson 131a307d594SAlexey Kardashevskiy if (dev->irq) { 132bb2d8ab6SGreg Kurz uint32_t ints_prop[2]; 13300dc738dSDavid Gibson 1345c7adcf4SGreg Kurz spapr_dt_irq(ints_prop, dev->irq, false); 13500dc738dSDavid Gibson ret = fdt_setprop(fdt, node_off, "interrupts", ints_prop, 13600dc738dSDavid Gibson sizeof(ints_prop)); 13700dc738dSDavid Gibson if (ret < 0) { 13800dc738dSDavid Gibson return ret; 13900dc738dSDavid Gibson } 14000dc738dSDavid Gibson } 14100dc738dSDavid Gibson 1422b7dc949SPaolo Bonzini ret = spapr_tcet_dma_dt(fdt, node_off, "ibm,my-dma-window", dev->tcet); 143ee86dfeeSDavid Gibson if (ret < 0) { 144ee86dfeeSDavid Gibson return ret; 145ee86dfeeSDavid Gibson } 146ee86dfeeSDavid Gibson 1473954d33aSAnthony Liguori if (pc->devnode) { 1483954d33aSAnthony Liguori ret = (pc->devnode)(dev, fdt, node_off); 1494040ab72SDavid Gibson if (ret < 0) { 1504040ab72SDavid Gibson return ret; 1514040ab72SDavid Gibson } 1524040ab72SDavid Gibson } 1534040ab72SDavid Gibson 1544040ab72SDavid Gibson return node_off; 1554040ab72SDavid Gibson } 1564040ab72SDavid Gibson 157ee86dfeeSDavid Gibson /* 158b45d63b6SBen Herrenschmidt * CRQ handling 159b45d63b6SBen Herrenschmidt */ 160ce2918cbSDavid Gibson static target_ulong h_reg_crq(PowerPCCPU *cpu, SpaprMachineState *spapr, 161b45d63b6SBen Herrenschmidt target_ulong opcode, target_ulong *args) 162b45d63b6SBen Herrenschmidt { 163b45d63b6SBen Herrenschmidt target_ulong reg = args[0]; 164b45d63b6SBen Herrenschmidt target_ulong queue_addr = args[1]; 165b45d63b6SBen Herrenschmidt target_ulong queue_len = args[2]; 166ce2918cbSDavid Gibson SpaprVioDevice *dev = spapr_vio_find_by_reg(spapr->vio_bus, reg); 167b45d63b6SBen Herrenschmidt 168b45d63b6SBen Herrenschmidt if (!dev) { 169d9599c92SDavid Gibson hcall_dprintf("Unit 0x" TARGET_FMT_lx " does not exist\n", reg); 170b45d63b6SBen Herrenschmidt return H_PARAMETER; 171b45d63b6SBen Herrenschmidt } 172b45d63b6SBen Herrenschmidt 173b45d63b6SBen Herrenschmidt /* We can't grok a queue size bigger than 256M for now */ 174b45d63b6SBen Herrenschmidt if (queue_len < 0x1000 || queue_len > 0x10000000) { 175d9599c92SDavid Gibson hcall_dprintf("Queue size too small or too big (0x" TARGET_FMT_lx 176d9599c92SDavid Gibson ")\n", queue_len); 177b45d63b6SBen Herrenschmidt return H_PARAMETER; 178b45d63b6SBen Herrenschmidt } 179b45d63b6SBen Herrenschmidt 180b45d63b6SBen Herrenschmidt /* Check queue alignment */ 181b45d63b6SBen Herrenschmidt if (queue_addr & 0xfff) { 182d9599c92SDavid Gibson hcall_dprintf("Queue not aligned (0x" TARGET_FMT_lx ")\n", queue_addr); 183b45d63b6SBen Herrenschmidt return H_PARAMETER; 184b45d63b6SBen Herrenschmidt } 185b45d63b6SBen Herrenschmidt 186b45d63b6SBen Herrenschmidt /* Check if device supports CRQs */ 187b45d63b6SBen Herrenschmidt if (!dev->crq.SendFunc) { 1888e01f355SDavid Gibson hcall_dprintf("Device does not support CRQ\n"); 189b45d63b6SBen Herrenschmidt return H_NOT_FOUND; 190b45d63b6SBen Herrenschmidt } 191b45d63b6SBen Herrenschmidt 192b45d63b6SBen Herrenschmidt /* Already a queue ? */ 193b45d63b6SBen Herrenschmidt if (dev->crq.qsize) { 1948e01f355SDavid Gibson hcall_dprintf("CRQ already registered\n"); 195b45d63b6SBen Herrenschmidt return H_RESOURCE; 196b45d63b6SBen Herrenschmidt } 197b45d63b6SBen Herrenschmidt dev->crq.qladdr = queue_addr; 198b45d63b6SBen Herrenschmidt dev->crq.qsize = queue_len; 199b45d63b6SBen Herrenschmidt dev->crq.qnext = 0; 200b45d63b6SBen Herrenschmidt 2017ab6a501SLaurent Vivier trace_spapr_vio_h_reg_crq(reg, queue_addr, queue_len); 202b45d63b6SBen Herrenschmidt return H_SUCCESS; 203b45d63b6SBen Herrenschmidt } 204b45d63b6SBen Herrenschmidt 205ce2918cbSDavid Gibson static target_ulong free_crq(SpaprVioDevice *dev) 2068e01f355SDavid Gibson { 2078e01f355SDavid Gibson dev->crq.qladdr = 0; 2088e01f355SDavid Gibson dev->crq.qsize = 0; 2098e01f355SDavid Gibson dev->crq.qnext = 0; 2108e01f355SDavid Gibson 2117ab6a501SLaurent Vivier trace_spapr_vio_free_crq(dev->reg); 2128e01f355SDavid Gibson 2138e01f355SDavid Gibson return H_SUCCESS; 2148e01f355SDavid Gibson } 2158e01f355SDavid Gibson 216ce2918cbSDavid Gibson static target_ulong h_free_crq(PowerPCCPU *cpu, SpaprMachineState *spapr, 217b45d63b6SBen Herrenschmidt target_ulong opcode, target_ulong *args) 218b45d63b6SBen Herrenschmidt { 219b45d63b6SBen Herrenschmidt target_ulong reg = args[0]; 220ce2918cbSDavid Gibson SpaprVioDevice *dev = spapr_vio_find_by_reg(spapr->vio_bus, reg); 221b45d63b6SBen Herrenschmidt 222b45d63b6SBen Herrenschmidt if (!dev) { 223d9599c92SDavid Gibson hcall_dprintf("Unit 0x" TARGET_FMT_lx " does not exist\n", reg); 224b45d63b6SBen Herrenschmidt return H_PARAMETER; 225b45d63b6SBen Herrenschmidt } 226b45d63b6SBen Herrenschmidt 2278e01f355SDavid Gibson return free_crq(dev); 228b45d63b6SBen Herrenschmidt } 229b45d63b6SBen Herrenschmidt 230ce2918cbSDavid Gibson static target_ulong h_send_crq(PowerPCCPU *cpu, SpaprMachineState *spapr, 231b45d63b6SBen Herrenschmidt target_ulong opcode, target_ulong *args) 232b45d63b6SBen Herrenschmidt { 233b45d63b6SBen Herrenschmidt target_ulong reg = args[0]; 234b45d63b6SBen Herrenschmidt target_ulong msg_hi = args[1]; 235b45d63b6SBen Herrenschmidt target_ulong msg_lo = args[2]; 236ce2918cbSDavid Gibson SpaprVioDevice *dev = spapr_vio_find_by_reg(spapr->vio_bus, reg); 237b45d63b6SBen Herrenschmidt uint64_t crq_mangle[2]; 238b45d63b6SBen Herrenschmidt 239b45d63b6SBen Herrenschmidt if (!dev) { 240d9599c92SDavid Gibson hcall_dprintf("Unit 0x" TARGET_FMT_lx " does not exist\n", reg); 241b45d63b6SBen Herrenschmidt return H_PARAMETER; 242b45d63b6SBen Herrenschmidt } 243b45d63b6SBen Herrenschmidt crq_mangle[0] = cpu_to_be64(msg_hi); 244b45d63b6SBen Herrenschmidt crq_mangle[1] = cpu_to_be64(msg_lo); 245b45d63b6SBen Herrenschmidt 246b45d63b6SBen Herrenschmidt if (dev->crq.SendFunc) { 247b45d63b6SBen Herrenschmidt return dev->crq.SendFunc(dev, (uint8_t *)crq_mangle); 248b45d63b6SBen Herrenschmidt } 249b45d63b6SBen Herrenschmidt 250b45d63b6SBen Herrenschmidt return H_HARDWARE; 251b45d63b6SBen Herrenschmidt } 252b45d63b6SBen Herrenschmidt 253ce2918cbSDavid Gibson static target_ulong h_enable_crq(PowerPCCPU *cpu, SpaprMachineState *spapr, 254b45d63b6SBen Herrenschmidt target_ulong opcode, target_ulong *args) 255b45d63b6SBen Herrenschmidt { 256b45d63b6SBen Herrenschmidt target_ulong reg = args[0]; 257ce2918cbSDavid Gibson SpaprVioDevice *dev = spapr_vio_find_by_reg(spapr->vio_bus, reg); 258b45d63b6SBen Herrenschmidt 259b45d63b6SBen Herrenschmidt if (!dev) { 260d9599c92SDavid Gibson hcall_dprintf("Unit 0x" TARGET_FMT_lx " does not exist\n", reg); 261b45d63b6SBen Herrenschmidt return H_PARAMETER; 262b45d63b6SBen Herrenschmidt } 263b45d63b6SBen Herrenschmidt 264b45d63b6SBen Herrenschmidt return 0; 265b45d63b6SBen Herrenschmidt } 266b45d63b6SBen Herrenschmidt 267b45d63b6SBen Herrenschmidt /* Returns negative error, 0 success, or positive: queue full */ 268ce2918cbSDavid Gibson int spapr_vio_send_crq(SpaprVioDevice *dev, uint8_t *crq) 269b45d63b6SBen Herrenschmidt { 270b45d63b6SBen Herrenschmidt int rc; 271b45d63b6SBen Herrenschmidt uint8_t byte; 272b45d63b6SBen Herrenschmidt 273b45d63b6SBen Herrenschmidt if (!dev->crq.qsize) { 274ce9863b7SCédric Le Goater error_report("spapr_vio_send_creq on uninitialized queue"); 275b45d63b6SBen Herrenschmidt return -1; 276b45d63b6SBen Herrenschmidt } 277b45d63b6SBen Herrenschmidt 278b45d63b6SBen Herrenschmidt /* Maybe do a fast path for KVM just writing to the pages */ 279ad0ebb91SDavid Gibson rc = spapr_vio_dma_read(dev, dev->crq.qladdr + dev->crq.qnext, &byte, 1); 280b45d63b6SBen Herrenschmidt if (rc) { 281b45d63b6SBen Herrenschmidt return rc; 282b45d63b6SBen Herrenschmidt } 283b45d63b6SBen Herrenschmidt if (byte != 0) { 284b45d63b6SBen Herrenschmidt return 1; 285b45d63b6SBen Herrenschmidt } 286b45d63b6SBen Herrenschmidt 287ad0ebb91SDavid Gibson rc = spapr_vio_dma_write(dev, dev->crq.qladdr + dev->crq.qnext + 8, 288b45d63b6SBen Herrenschmidt &crq[8], 8); 289b45d63b6SBen Herrenschmidt if (rc) { 290b45d63b6SBen Herrenschmidt return rc; 291b45d63b6SBen Herrenschmidt } 292b45d63b6SBen Herrenschmidt 293b45d63b6SBen Herrenschmidt kvmppc_eieio(); 294b45d63b6SBen Herrenschmidt 295ad0ebb91SDavid Gibson rc = spapr_vio_dma_write(dev, dev->crq.qladdr + dev->crq.qnext, crq, 8); 296b45d63b6SBen Herrenschmidt if (rc) { 297b45d63b6SBen Herrenschmidt return rc; 298b45d63b6SBen Herrenschmidt } 299b45d63b6SBen Herrenschmidt 300b45d63b6SBen Herrenschmidt dev->crq.qnext = (dev->crq.qnext + 16) % dev->crq.qsize; 301b45d63b6SBen Herrenschmidt 302b45d63b6SBen Herrenschmidt if (dev->signal_state & 1) { 3037678b74aSDavid Gibson spapr_vio_irq_pulse(dev); 304b45d63b6SBen Herrenschmidt } 305b45d63b6SBen Herrenschmidt 306b45d63b6SBen Herrenschmidt return 0; 307b45d63b6SBen Herrenschmidt } 308b45d63b6SBen Herrenschmidt 30908942ac1SBen Herrenschmidt /* "quiesce" handling */ 31008942ac1SBen Herrenschmidt 311ce2918cbSDavid Gibson static void spapr_vio_quiesce_one(SpaprVioDevice *dev) 31208942ac1SBen Herrenschmidt { 3132b7dc949SPaolo Bonzini if (dev->tcet) { 314f703a04cSDamien Hedde device_legacy_reset(DEVICE(dev->tcet)); 31508942ac1SBen Herrenschmidt } 3164dd96f24SDavid Gibson free_crq(dev); 31708942ac1SBen Herrenschmidt } 31808942ac1SBen Herrenschmidt 319ce2918cbSDavid Gibson void spapr_vio_set_bypass(SpaprVioDevice *dev, bool bypass) 320ee9a569aSAlexey Kardashevskiy { 321ee9a569aSAlexey Kardashevskiy if (!dev->tcet) { 322ee9a569aSAlexey Kardashevskiy return; 323ee9a569aSAlexey Kardashevskiy } 324ee9a569aSAlexey Kardashevskiy 325ee9a569aSAlexey Kardashevskiy memory_region_set_enabled(&dev->mrbypass, bypass); 326ee9a569aSAlexey Kardashevskiy memory_region_set_enabled(spapr_tce_get_iommu(dev->tcet), !bypass); 327ee9a569aSAlexey Kardashevskiy 328ee9a569aSAlexey Kardashevskiy dev->tcet->bypass = bypass; 329ee9a569aSAlexey Kardashevskiy } 330ee9a569aSAlexey Kardashevskiy 331ce2918cbSDavid Gibson static void rtas_set_tce_bypass(PowerPCCPU *cpu, SpaprMachineState *spapr, 332210b580bSAnthony Liguori uint32_t token, 33308942ac1SBen Herrenschmidt uint32_t nargs, target_ulong args, 33408942ac1SBen Herrenschmidt uint32_t nret, target_ulong rets) 33508942ac1SBen Herrenschmidt { 336ce2918cbSDavid Gibson SpaprVioBus *bus = spapr->vio_bus; 337ce2918cbSDavid Gibson SpaprVioDevice *dev; 33808942ac1SBen Herrenschmidt uint32_t unit, enable; 33908942ac1SBen Herrenschmidt 34008942ac1SBen Herrenschmidt if (nargs != 2) { 341a64d325dSAlexey Kardashevskiy rtas_st(rets, 0, RTAS_OUT_PARAM_ERROR); 34208942ac1SBen Herrenschmidt return; 34308942ac1SBen Herrenschmidt } 34408942ac1SBen Herrenschmidt unit = rtas_ld(args, 0); 34508942ac1SBen Herrenschmidt enable = rtas_ld(args, 1); 34608942ac1SBen Herrenschmidt dev = spapr_vio_find_by_reg(bus, unit); 34708942ac1SBen Herrenschmidt if (!dev) { 348a64d325dSAlexey Kardashevskiy rtas_st(rets, 0, RTAS_OUT_PARAM_ERROR); 34908942ac1SBen Herrenschmidt return; 35008942ac1SBen Herrenschmidt } 351ad0ebb91SDavid Gibson 3522b7dc949SPaolo Bonzini if (!dev->tcet) { 353a64d325dSAlexey Kardashevskiy rtas_st(rets, 0, RTAS_OUT_PARAM_ERROR); 35453724ee5SDavid Gibson return; 35508942ac1SBen Herrenschmidt } 35608942ac1SBen Herrenschmidt 357ee9a569aSAlexey Kardashevskiy spapr_vio_set_bypass(dev, !!enable); 35853724ee5SDavid Gibson 359a64d325dSAlexey Kardashevskiy rtas_st(rets, 0, RTAS_OUT_SUCCESS); 36008942ac1SBen Herrenschmidt } 36108942ac1SBen Herrenschmidt 362ce2918cbSDavid Gibson static void rtas_quiesce(PowerPCCPU *cpu, SpaprMachineState *spapr, 363210b580bSAnthony Liguori uint32_t token, 36408942ac1SBen Herrenschmidt uint32_t nargs, target_ulong args, 36508942ac1SBen Herrenschmidt uint32_t nret, target_ulong rets) 36608942ac1SBen Herrenschmidt { 367ce2918cbSDavid Gibson SpaprVioBus *bus = spapr->vio_bus; 3680866aca1SAnthony Liguori BusChild *kid; 369ce2918cbSDavid Gibson SpaprVioDevice *dev = NULL; 37008942ac1SBen Herrenschmidt 37108942ac1SBen Herrenschmidt if (nargs != 0) { 372a64d325dSAlexey Kardashevskiy rtas_st(rets, 0, RTAS_OUT_PARAM_ERROR); 37308942ac1SBen Herrenschmidt return; 37408942ac1SBen Herrenschmidt } 37508942ac1SBen Herrenschmidt 3760866aca1SAnthony Liguori QTAILQ_FOREACH(kid, &bus->bus.children, sibling) { 377ce2918cbSDavid Gibson dev = (SpaprVioDevice *)kid->child; 37808942ac1SBen Herrenschmidt spapr_vio_quiesce_one(dev); 37908942ac1SBen Herrenschmidt } 38008942ac1SBen Herrenschmidt 381a64d325dSAlexey Kardashevskiy rtas_st(rets, 0, RTAS_OUT_SUCCESS); 38208942ac1SBen Herrenschmidt } 38308942ac1SBen Herrenschmidt 384ce2918cbSDavid Gibson static SpaprVioDevice *reg_conflict(SpaprVioDevice *dev) 3859fc380d3SMichael Ellerman { 386ce2918cbSDavid Gibson SpaprVioBus *bus = SPAPR_VIO_BUS(dev->qdev.parent_bus); 3870866aca1SAnthony Liguori BusChild *kid; 388ce2918cbSDavid Gibson SpaprVioDevice *other; 3899fc380d3SMichael Ellerman 3909fc380d3SMichael Ellerman /* 391d601fac4SDavid Gibson * Check for a device other than the given one which is already 392d601fac4SDavid Gibson * using the requested address. We have to open code this because 393d601fac4SDavid Gibson * the given dev might already be in the list. 3949fc380d3SMichael Ellerman */ 3950866aca1SAnthony Liguori QTAILQ_FOREACH(kid, &bus->bus.children, sibling) { 396fd506b4fSDavid Gibson other = VIO_SPAPR_DEVICE(kid->child); 3979fc380d3SMichael Ellerman 398d601fac4SDavid Gibson if (other != dev && other->reg == dev->reg) { 399d601fac4SDavid Gibson return other; 4009fc380d3SMichael Ellerman } 4019fc380d3SMichael Ellerman } 4029fc380d3SMichael Ellerman 4039fc380d3SMichael Ellerman return 0; 4049fc380d3SMichael Ellerman } 4059fc380d3SMichael Ellerman 406b1c7f725SDavid Gibson static void spapr_vio_busdev_reset(DeviceState *qdev) 4078e01f355SDavid Gibson { 408ce2918cbSDavid Gibson SpaprVioDevice *dev = VIO_SPAPR_DEVICE(qdev); 409ce2918cbSDavid Gibson SpaprVioDeviceClass *pc = VIO_SPAPR_DEVICE_GET_CLASS(dev); 4108e01f355SDavid Gibson 4114dd96f24SDavid Gibson /* Shut down the request queue and TCEs if necessary */ 4124dd96f24SDavid Gibson spapr_vio_quiesce_one(dev); 4134dd96f24SDavid Gibson 4144dd96f24SDavid Gibson dev->signal_state = 0; 415b1c7f725SDavid Gibson 416ee9a569aSAlexey Kardashevskiy spapr_vio_set_bypass(dev, false); 417b1c7f725SDavid Gibson if (pc->reset) { 418b1c7f725SDavid Gibson pc->reset(dev); 419b1c7f725SDavid Gibson } 4208e01f355SDavid Gibson } 4218e01f355SDavid Gibson 42282cffa2eSCédric Le Goater /* 42382cffa2eSCédric Le Goater * The register property of a VIO device is defined in livirt using 42482cffa2eSCédric Le Goater * 0x1000 as a base register number plus a 0x1000 increment. For the 42582cffa2eSCédric Le Goater * VIO tty device, the base number is changed to 0x30000000. QEMU uses 42682cffa2eSCédric Le Goater * a base register number of 0x71000000 and then a simple increment. 42782cffa2eSCédric Le Goater * 42882cffa2eSCédric Le Goater * The formula below tries to compute a unique index number from the 42982cffa2eSCédric Le Goater * register value that will be used to define the IRQ number of the 43082cffa2eSCédric Le Goater * VIO device. 43182cffa2eSCédric Le Goater * 43282cffa2eSCédric Le Goater * A maximum of 256 VIO devices is covered. Collisions are possible 43382cffa2eSCédric Le Goater * but they will be detected when the IRQ is claimed. 43482cffa2eSCédric Le Goater */ 43582cffa2eSCédric Le Goater static inline uint32_t spapr_vio_reg_to_irq(uint32_t reg) 43682cffa2eSCédric Le Goater { 43782cffa2eSCédric Le Goater uint32_t irq; 43882cffa2eSCédric Le Goater 43982cffa2eSCédric Le Goater if (reg >= SPAPR_VIO_REG_BASE) { 44082cffa2eSCédric Le Goater /* 44182cffa2eSCédric Le Goater * VIO device register values when allocated by QEMU. For 44282cffa2eSCédric Le Goater * these, we simply mask the high bits to fit the overall 44382cffa2eSCédric Le Goater * range: [0x00 - 0xff]. 44482cffa2eSCédric Le Goater * 44582cffa2eSCédric Le Goater * The nvram VIO device (reg=0x71000000) is a static device of 44682cffa2eSCédric Le Goater * the pseries machine and so is always allocated by QEMU. Its 44782cffa2eSCédric Le Goater * IRQ number is 0x0. 44882cffa2eSCédric Le Goater */ 44982cffa2eSCédric Le Goater irq = reg & 0xff; 45082cffa2eSCédric Le Goater 45182cffa2eSCédric Le Goater } else if (reg >= 0x30000000) { 45282cffa2eSCédric Le Goater /* 45382cffa2eSCédric Le Goater * VIO tty devices register values, when allocated by livirt, 45482cffa2eSCédric Le Goater * are mapped in range [0xf0 - 0xff], gives us a maximum of 16 45582cffa2eSCédric Le Goater * vtys. 45682cffa2eSCédric Le Goater */ 45782cffa2eSCédric Le Goater irq = 0xf0 | ((reg >> 12) & 0xf); 45882cffa2eSCédric Le Goater 45982cffa2eSCédric Le Goater } else { 46082cffa2eSCédric Le Goater /* 46182cffa2eSCédric Le Goater * Other VIO devices register values, when allocated by 46282cffa2eSCédric Le Goater * livirt, should be mapped in range [0x00 - 0xef]. Conflicts 46382cffa2eSCédric Le Goater * will be detected when IRQ is claimed. 46482cffa2eSCédric Le Goater */ 46582cffa2eSCédric Le Goater irq = (reg >> 12) & 0xff; 46682cffa2eSCédric Le Goater } 46782cffa2eSCédric Le Goater 46882cffa2eSCédric Le Goater return SPAPR_IRQ_VIO | irq; 46982cffa2eSCédric Le Goater } 47082cffa2eSCédric Le Goater 47128b07e73SMarkus Armbruster static void spapr_vio_busdev_realize(DeviceState *qdev, Error **errp) 4724040ab72SDavid Gibson { 473ce2918cbSDavid Gibson SpaprMachineState *spapr = SPAPR_MACHINE(qdev_get_machine()); 474ce2918cbSDavid Gibson SpaprVioDevice *dev = (SpaprVioDevice *)qdev; 475ce2918cbSDavid Gibson SpaprVioDeviceClass *pc = VIO_SPAPR_DEVICE_GET_CLASS(dev); 4764040ab72SDavid Gibson char *id; 477a005b3efSGreg Kurz Error *local_err = NULL; 4789fc380d3SMichael Ellerman 479d601fac4SDavid Gibson if (dev->reg != -1) { 480d601fac4SDavid Gibson /* 481d601fac4SDavid Gibson * Explicitly assigned address, just verify that no-one else 482d601fac4SDavid Gibson * is using it. other mechanism). We have to open code this 483d601fac4SDavid Gibson * rather than using spapr_vio_find_by_reg() because sdev 484d601fac4SDavid Gibson * itself is already in the list. 485d601fac4SDavid Gibson */ 486ce2918cbSDavid Gibson SpaprVioDevice *other = reg_conflict(dev); 487d601fac4SDavid Gibson 488d601fac4SDavid Gibson if (other) { 48928b07e73SMarkus Armbruster error_setg(errp, "%s and %s devices conflict at address %#x", 490d601fac4SDavid Gibson object_get_typename(OBJECT(qdev)), 491d601fac4SDavid Gibson object_get_typename(OBJECT(&other->qdev)), 492d601fac4SDavid Gibson dev->reg); 49328b07e73SMarkus Armbruster return; 494d601fac4SDavid Gibson } 495d601fac4SDavid Gibson } else { 496d601fac4SDavid Gibson /* Need to assign an address */ 497ce2918cbSDavid Gibson SpaprVioBus *bus = SPAPR_VIO_BUS(dev->qdev.parent_bus); 498d601fac4SDavid Gibson 499d601fac4SDavid Gibson do { 500d601fac4SDavid Gibson dev->reg = bus->next_reg++; 501d601fac4SDavid Gibson } while (reg_conflict(dev)); 5029fc380d3SMichael Ellerman } 5034040ab72SDavid Gibson 5041e34d859SMichael Ellerman /* Don't overwrite ids assigned on the command line */ 5051e34d859SMichael Ellerman if (!dev->qdev.id) { 506c4eda5b7SDavid Gibson id = spapr_vio_get_dev_name(DEVICE(dev)); 5074040ab72SDavid Gibson dev->qdev.id = id; 5081e34d859SMichael Ellerman } 509e6c866d4SDavid Gibson 51082cffa2eSCédric Le Goater dev->irq = spapr_vio_reg_to_irq(dev->reg); 51182cffa2eSCédric Le Goater 51282cffa2eSCédric Le Goater if (SPAPR_MACHINE_GET_CLASS(spapr)->legacy_irq_allocation) { 5134fe75a8cSCédric Le Goater dev->irq = spapr_irq_findone(spapr, &local_err); 5144fe75a8cSCédric Le Goater if (local_err) { 5154fe75a8cSCédric Le Goater error_propagate(errp, local_err); 5164fe75a8cSCédric Le Goater return; 5174fe75a8cSCédric Le Goater } 5184fe75a8cSCédric Le Goater } 5194fe75a8cSCédric Le Goater 5204fe75a8cSCédric Le Goater spapr_irq_claim(spapr, dev->irq, false, &local_err); 521a005b3efSGreg Kurz if (local_err) { 522a005b3efSGreg Kurz error_propagate(errp, local_err); 52328b07e73SMarkus Armbruster return; 524416343b1SPaolo Bonzini } 5254040ab72SDavid Gibson 52653724ee5SDavid Gibson if (pc->rtce_window_size) { 5274290ca49SAlexey Kardashevskiy uint32_t liobn = SPAPR_VIO_LIOBN(dev->reg); 528ee9a569aSAlexey Kardashevskiy 529ee9a569aSAlexey Kardashevskiy memory_region_init(&dev->mrroot, OBJECT(dev), "iommu-spapr-root", 530ee9a569aSAlexey Kardashevskiy ram_size); 531ee9a569aSAlexey Kardashevskiy memory_region_init_alias(&dev->mrbypass, OBJECT(dev), 532ee9a569aSAlexey Kardashevskiy "iommu-spapr-bypass", get_system_memory(), 533ee9a569aSAlexey Kardashevskiy 0, ram_size); 534ee9a569aSAlexey Kardashevskiy memory_region_add_subregion_overlap(&dev->mrroot, 0, &dev->mrbypass, 1); 535ee9a569aSAlexey Kardashevskiy address_space_init(&dev->as, &dev->mrroot, qdev->id); 536ee9a569aSAlexey Kardashevskiy 537df7625d4SAlexey Kardashevskiy dev->tcet = spapr_tce_new_table(qdev, liobn); 538df7625d4SAlexey Kardashevskiy spapr_tce_table_enable(dev->tcet, SPAPR_TCE_PAGE_SHIFT, 0, 539df7625d4SAlexey Kardashevskiy pc->rtce_window_size >> SPAPR_TCE_PAGE_SHIFT); 540ee9a569aSAlexey Kardashevskiy dev->tcet->vdev = dev; 541ee9a569aSAlexey Kardashevskiy memory_region_add_subregion_overlap(&dev->mrroot, 0, 542ee9a569aSAlexey Kardashevskiy spapr_tce_get_iommu(dev->tcet), 2); 54353724ee5SDavid Gibson } 544ee86dfeeSDavid Gibson 54528b07e73SMarkus Armbruster pc->realize(dev, errp); 5464040ab72SDavid Gibson } 5474040ab72SDavid Gibson 548ce2918cbSDavid Gibson static target_ulong h_vio_signal(PowerPCCPU *cpu, SpaprMachineState *spapr, 54900dc738dSDavid Gibson target_ulong opcode, 55000dc738dSDavid Gibson target_ulong *args) 55100dc738dSDavid Gibson { 55200dc738dSDavid Gibson target_ulong reg = args[0]; 55300dc738dSDavid Gibson target_ulong mode = args[1]; 554ce2918cbSDavid Gibson SpaprVioDevice *dev = spapr_vio_find_by_reg(spapr->vio_bus, reg); 555ce2918cbSDavid Gibson SpaprVioDeviceClass *pc; 55600dc738dSDavid Gibson 55700dc738dSDavid Gibson if (!dev) { 55800dc738dSDavid Gibson return H_PARAMETER; 55900dc738dSDavid Gibson } 56000dc738dSDavid Gibson 5613954d33aSAnthony Liguori pc = VIO_SPAPR_DEVICE_GET_CLASS(dev); 56200dc738dSDavid Gibson 5633954d33aSAnthony Liguori if (mode & ~pc->signal_mask) { 56400dc738dSDavid Gibson return H_PARAMETER; 56500dc738dSDavid Gibson } 56600dc738dSDavid Gibson 56700dc738dSDavid Gibson dev->signal_state = mode; 56800dc738dSDavid Gibson 56900dc738dSDavid Gibson return H_SUCCESS; 57000dc738dSDavid Gibson } 57100dc738dSDavid Gibson 572ce2918cbSDavid Gibson SpaprVioBus *spapr_vio_bus_init(void) 5734040ab72SDavid Gibson { 574ce2918cbSDavid Gibson SpaprVioBus *bus; 5754040ab72SDavid Gibson BusState *qbus; 5764040ab72SDavid Gibson DeviceState *dev; 5774040ab72SDavid Gibson 5784040ab72SDavid Gibson /* Create bridge device */ 579*3e80f690SMarkus Armbruster dev = qdev_new(TYPE_SPAPR_VIO_BRIDGE); 580*3e80f690SMarkus Armbruster qdev_realize_and_unref(dev, NULL, &error_fatal); 5814040ab72SDavid Gibson 5824040ab72SDavid Gibson /* Create bus on bridge device */ 5830d936928SAnthony Liguori qbus = qbus_create(TYPE_SPAPR_VIO_BUS, dev, "spapr-vio"); 584215e2098SCao jin bus = SPAPR_VIO_BUS(qbus); 58582cffa2eSCédric Le Goater bus->next_reg = SPAPR_VIO_REG_BASE; 5864040ab72SDavid Gibson 58700dc738dSDavid Gibson /* hcall-vio */ 58800dc738dSDavid Gibson spapr_register_hypercall(H_VIO_SIGNAL, h_vio_signal); 58900dc738dSDavid Gibson 590b45d63b6SBen Herrenschmidt /* hcall-crq */ 591b45d63b6SBen Herrenschmidt spapr_register_hypercall(H_REG_CRQ, h_reg_crq); 592b45d63b6SBen Herrenschmidt spapr_register_hypercall(H_FREE_CRQ, h_free_crq); 593b45d63b6SBen Herrenschmidt spapr_register_hypercall(H_SEND_CRQ, h_send_crq); 594b45d63b6SBen Herrenschmidt spapr_register_hypercall(H_ENABLE_CRQ, h_enable_crq); 595b45d63b6SBen Herrenschmidt 59608942ac1SBen Herrenschmidt /* RTAS calls */ 5973a3b8502SAlexey Kardashevskiy spapr_rtas_register(RTAS_IBM_SET_TCE_BYPASS, "ibm,set-tce-bypass", 5983a3b8502SAlexey Kardashevskiy rtas_set_tce_bypass); 5993a3b8502SAlexey Kardashevskiy spapr_rtas_register(RTAS_QUIESCE, "quiesce", rtas_quiesce); 60008942ac1SBen Herrenschmidt 6014040ab72SDavid Gibson return bus; 6024040ab72SDavid Gibson } 6034040ab72SDavid Gibson 604999e12bbSAnthony Liguori static void spapr_vio_bridge_class_init(ObjectClass *klass, void *data) 605999e12bbSAnthony Liguori { 6065a06393fSAlexey Kardashevskiy DeviceClass *dc = DEVICE_CLASS(klass); 607999e12bbSAnthony Liguori 6085a06393fSAlexey Kardashevskiy dc->fw_name = "vdevice"; 609999e12bbSAnthony Liguori } 610999e12bbSAnthony Liguori 6118c43a6f0SAndreas Färber static const TypeInfo spapr_vio_bridge_info = { 612215e2098SCao jin .name = TYPE_SPAPR_VIO_BRIDGE, 61339bffca2SAnthony Liguori .parent = TYPE_SYS_BUS_DEVICE, 614999e12bbSAnthony Liguori .class_init = spapr_vio_bridge_class_init, 6154040ab72SDavid Gibson }; 6164040ab72SDavid Gibson 617b368a7d8SDavid Gibson const VMStateDescription vmstate_spapr_vio = { 618b368a7d8SDavid Gibson .name = "spapr_vio", 619b368a7d8SDavid Gibson .version_id = 1, 620b368a7d8SDavid Gibson .minimum_version_id = 1, 621b368a7d8SDavid Gibson .fields = (VMStateField[]) { 622b368a7d8SDavid Gibson /* Sanity check */ 623ce2918cbSDavid Gibson VMSTATE_UINT32_EQUAL(reg, SpaprVioDevice, NULL), 624ce2918cbSDavid Gibson VMSTATE_UINT32_EQUAL(irq, SpaprVioDevice, NULL), 625b368a7d8SDavid Gibson 626b368a7d8SDavid Gibson /* General VIO device state */ 627ce2918cbSDavid Gibson VMSTATE_UINT64(signal_state, SpaprVioDevice), 628ce2918cbSDavid Gibson VMSTATE_UINT64(crq.qladdr, SpaprVioDevice), 629ce2918cbSDavid Gibson VMSTATE_UINT32(crq.qsize, SpaprVioDevice), 630ce2918cbSDavid Gibson VMSTATE_UINT32(crq.qnext, SpaprVioDevice), 631b368a7d8SDavid Gibson 632b368a7d8SDavid Gibson VMSTATE_END_OF_LIST() 633b368a7d8SDavid Gibson }, 634b368a7d8SDavid Gibson }; 635b368a7d8SDavid Gibson 63639bffca2SAnthony Liguori static void vio_spapr_device_class_init(ObjectClass *klass, void *data) 63739bffca2SAnthony Liguori { 63839bffca2SAnthony Liguori DeviceClass *k = DEVICE_CLASS(klass); 63928b07e73SMarkus Armbruster k->realize = spapr_vio_busdev_realize; 640b1c7f725SDavid Gibson k->reset = spapr_vio_busdev_reset; 6410d936928SAnthony Liguori k->bus_type = TYPE_SPAPR_VIO_BUS; 64239bffca2SAnthony Liguori } 64339bffca2SAnthony Liguori 6448c43a6f0SAndreas Färber static const TypeInfo spapr_vio_type_info = { 6453954d33aSAnthony Liguori .name = TYPE_VIO_SPAPR_DEVICE, 6463954d33aSAnthony Liguori .parent = TYPE_DEVICE, 647ce2918cbSDavid Gibson .instance_size = sizeof(SpaprVioDevice), 6483954d33aSAnthony Liguori .abstract = true, 649ce2918cbSDavid Gibson .class_size = sizeof(SpaprVioDeviceClass), 65039bffca2SAnthony Liguori .class_init = vio_spapr_device_class_init, 6513954d33aSAnthony Liguori }; 6523954d33aSAnthony Liguori 65383f7d43aSAndreas Färber static void spapr_vio_register_types(void) 6544040ab72SDavid Gibson { 6550d936928SAnthony Liguori type_register_static(&spapr_vio_bus_info); 65639bffca2SAnthony Liguori type_register_static(&spapr_vio_bridge_info); 6573954d33aSAnthony Liguori type_register_static(&spapr_vio_type_info); 6584040ab72SDavid Gibson } 6594040ab72SDavid Gibson 66083f7d43aSAndreas Färber type_init(spapr_vio_register_types) 6614040ab72SDavid Gibson 66205c19438SDavid Gibson static int compare_reg(const void *p1, const void *p2) 66305c19438SDavid Gibson { 664ce2918cbSDavid Gibson SpaprVioDevice const *dev1, *dev2; 66505c19438SDavid Gibson 666ce2918cbSDavid Gibson dev1 = (SpaprVioDevice *)*(DeviceState **)p1; 667ce2918cbSDavid Gibson dev2 = (SpaprVioDevice *)*(DeviceState **)p2; 66805c19438SDavid Gibson 66905c19438SDavid Gibson if (dev1->reg < dev2->reg) { 67005c19438SDavid Gibson return -1; 67105c19438SDavid Gibson } 67205c19438SDavid Gibson if (dev1->reg == dev2->reg) { 67305c19438SDavid Gibson return 0; 67405c19438SDavid Gibson } 67505c19438SDavid Gibson 67605c19438SDavid Gibson /* dev1->reg > dev2->reg */ 67705c19438SDavid Gibson return 1; 67805c19438SDavid Gibson } 67905c19438SDavid Gibson 680ce2918cbSDavid Gibson void spapr_dt_vdevice(SpaprVioBus *bus, void *fdt) 6814040ab72SDavid Gibson { 68205c19438SDavid Gibson DeviceState *qdev, **qdevs; 6830866aca1SAnthony Liguori BusChild *kid; 68405c19438SDavid Gibson int i, num, ret = 0; 685bf5a6696SDavid Gibson int node; 686bf5a6696SDavid Gibson 687bf5a6696SDavid Gibson _FDT(node = fdt_add_subnode(fdt, 0, "vdevice")); 688bf5a6696SDavid Gibson 689bf5a6696SDavid Gibson _FDT(fdt_setprop_string(fdt, node, "device_type", "vdevice")); 690bf5a6696SDavid Gibson _FDT(fdt_setprop_string(fdt, node, "compatible", "IBM,vdevice")); 691bf5a6696SDavid Gibson _FDT(fdt_setprop_cell(fdt, node, "#address-cells", 1)); 692bf5a6696SDavid Gibson _FDT(fdt_setprop_cell(fdt, node, "#size-cells", 0)); 693bf5a6696SDavid Gibson _FDT(fdt_setprop_cell(fdt, node, "#interrupt-cells", 2)); 694bf5a6696SDavid Gibson _FDT(fdt_setprop(fdt, node, "interrupt-controller", NULL, 0)); 6954040ab72SDavid Gibson 69605c19438SDavid Gibson /* Count qdevs on the bus list */ 69705c19438SDavid Gibson num = 0; 6980866aca1SAnthony Liguori QTAILQ_FOREACH(kid, &bus->bus.children, sibling) { 69905c19438SDavid Gibson num++; 70005c19438SDavid Gibson } 70105c19438SDavid Gibson 70205c19438SDavid Gibson /* Copy out into an array of pointers */ 703dec4ec40SGreg Kurz qdevs = g_new(DeviceState *, num); 70405c19438SDavid Gibson num = 0; 7050866aca1SAnthony Liguori QTAILQ_FOREACH(kid, &bus->bus.children, sibling) { 7060866aca1SAnthony Liguori qdevs[num++] = kid->child; 70705c19438SDavid Gibson } 70805c19438SDavid Gibson 70905c19438SDavid Gibson /* Sort the array */ 71005c19438SDavid Gibson qsort(qdevs, num, sizeof(qdev), compare_reg); 71105c19438SDavid Gibson 71205c19438SDavid Gibson /* Hack alert. Give the devices to libfdt in reverse order, we happen 71305c19438SDavid Gibson * to know that will mean they are in forward order in the tree. */ 71405c19438SDavid Gibson for (i = num - 1; i >= 0; i--) { 715ce2918cbSDavid Gibson SpaprVioDevice *dev = (SpaprVioDevice *)(qdevs[i]); 716ce2918cbSDavid Gibson SpaprVioDeviceClass *vdc = VIO_SPAPR_DEVICE_GET_CLASS(dev); 7174040ab72SDavid Gibson 7184040ab72SDavid Gibson ret = vio_make_devnode(dev, fdt); 7194040ab72SDavid Gibson if (ret < 0) { 720bf5a6696SDavid Gibson error_report("Couldn't create device node /vdevice/%s@%"PRIx32, 721bf5a6696SDavid Gibson vdc->dt_name, dev->reg); 722bf5a6696SDavid Gibson exit(1); 7234040ab72SDavid Gibson } 7244040ab72SDavid Gibson } 7254040ab72SDavid Gibson 7265f1d1fc5SMarkus Armbruster g_free(qdevs); 7274040ab72SDavid Gibson } 72868f3a94cSDavid Gibson 729ce2918cbSDavid Gibson gchar *spapr_vio_stdout_path(SpaprVioBus *bus) 73068f3a94cSDavid Gibson { 731ce2918cbSDavid Gibson SpaprVioDevice *dev; 73268f3a94cSDavid Gibson char *name, *path; 73368f3a94cSDavid Gibson 73468f3a94cSDavid Gibson dev = spapr_vty_get_default(bus); 7357c866c6aSDavid Gibson if (!dev) { 7367c866c6aSDavid Gibson return NULL; 73768f3a94cSDavid Gibson } 73868f3a94cSDavid Gibson 739c4eda5b7SDavid Gibson name = spapr_vio_get_dev_name(DEVICE(dev)); 7404ecf8aa5SStefan Weil path = g_strdup_printf("/vdevice/%s", name); 74168f3a94cSDavid Gibson 7424ecf8aa5SStefan Weil g_free(name); 7437c866c6aSDavid Gibson return path; 74468f3a94cSDavid Gibson } 745