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 1161f3c91aSChetan Pant * version 2.1 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" 30*32cad1ffSPhilippe Mathieu-Daudé #include "system/kvm.h" 31*32cad1ffSPhilippe Mathieu-Daudé #include "system/device_tree.h" 32b45d63b6SBen Herrenschmidt #include "kvm_ppc.h" 33d6454270SMarkus Armbruster #include "migration/vmstate.h" 344040ab72SDavid Gibson 350d09e41aSPaolo Bonzini #include "hw/ppc/spapr.h" 360d09e41aSPaolo Bonzini #include "hw/ppc/spapr_vio.h" 37bf5a6696SDavid Gibson #include "hw/ppc/fdt.h" 387ab6a501SLaurent Vivier #include "trace.h" 394040ab72SDavid Gibson 404040ab72SDavid Gibson #include <libfdt.h> 414040ab72SDavid Gibson 4282cffa2eSCédric Le Goater #define SPAPR_VIO_REG_BASE 0x71000000 4382cffa2eSCédric Le Goater 44c4eda5b7SDavid Gibson static char *spapr_vio_get_dev_name(DeviceState *qdev) 45c4eda5b7SDavid Gibson { 46ce2918cbSDavid Gibson SpaprVioDevice *dev = VIO_SPAPR_DEVICE(qdev); 47ce2918cbSDavid Gibson SpaprVioDeviceClass *pc = VIO_SPAPR_DEVICE_GET_CLASS(dev); 48c4eda5b7SDavid Gibson 49c4eda5b7SDavid Gibson /* Device tree style name device@reg */ 509be38598SEduardo Habkost return g_strdup_printf("%s@%x", pc->dt_name, dev->reg); 51c4eda5b7SDavid Gibson } 52c4eda5b7SDavid Gibson 53c4eda5b7SDavid Gibson static void spapr_vio_bus_class_init(ObjectClass *klass, void *data) 54c4eda5b7SDavid Gibson { 55c4eda5b7SDavid Gibson BusClass *k = BUS_CLASS(klass); 56c4eda5b7SDavid Gibson 57c4eda5b7SDavid Gibson k->get_dev_path = spapr_vio_get_dev_name; 585a06393fSAlexey Kardashevskiy k->get_fw_dev_path = spapr_vio_get_dev_name; 59c4eda5b7SDavid Gibson } 60c4eda5b7SDavid Gibson 610d936928SAnthony Liguori static const TypeInfo spapr_vio_bus_info = { 620d936928SAnthony Liguori .name = TYPE_SPAPR_VIO_BUS, 630d936928SAnthony Liguori .parent = TYPE_BUS, 64c4eda5b7SDavid Gibson .class_init = spapr_vio_bus_class_init, 65ce2918cbSDavid Gibson .instance_size = sizeof(SpaprVioBus), 664040ab72SDavid Gibson }; 674040ab72SDavid Gibson 68ce2918cbSDavid Gibson SpaprVioDevice *spapr_vio_find_by_reg(SpaprVioBus *bus, uint32_t reg) 694040ab72SDavid Gibson { 700866aca1SAnthony Liguori BusChild *kid; 71ce2918cbSDavid Gibson SpaprVioDevice *dev = NULL; 724040ab72SDavid Gibson 730866aca1SAnthony Liguori QTAILQ_FOREACH(kid, &bus->bus.children, sibling) { 74ce2918cbSDavid Gibson dev = (SpaprVioDevice *)kid->child; 754040ab72SDavid Gibson if (dev->reg == reg) { 765435352cSDavid Gibson return dev; 774040ab72SDavid Gibson } 784040ab72SDavid Gibson } 794040ab72SDavid Gibson 805435352cSDavid Gibson return NULL; 814040ab72SDavid Gibson } 824040ab72SDavid Gibson 83ce2918cbSDavid Gibson static int vio_make_devnode(SpaprVioDevice *dev, 844040ab72SDavid Gibson void *fdt) 854040ab72SDavid Gibson { 86ce2918cbSDavid Gibson SpaprVioDeviceClass *pc = VIO_SPAPR_DEVICE_GET_CLASS(dev); 871e34d859SMichael Ellerman int vdevice_off, node_off, ret; 881e34d859SMichael Ellerman char *dt_name; 89864674faSStefan Berger const char *dt_compatible; 904040ab72SDavid Gibson 914040ab72SDavid Gibson vdevice_off = fdt_path_offset(fdt, "/vdevice"); 924040ab72SDavid Gibson if (vdevice_off < 0) { 934040ab72SDavid Gibson return vdevice_off; 944040ab72SDavid Gibson } 954040ab72SDavid Gibson 96c4eda5b7SDavid Gibson dt_name = spapr_vio_get_dev_name(DEVICE(dev)); 971e34d859SMichael Ellerman node_off = fdt_add_subnode(fdt, vdevice_off, dt_name); 984ecf8aa5SStefan Weil g_free(dt_name); 994040ab72SDavid Gibson if (node_off < 0) { 1004040ab72SDavid Gibson return node_off; 1014040ab72SDavid Gibson } 1024040ab72SDavid Gibson 1034040ab72SDavid Gibson ret = fdt_setprop_cell(fdt, node_off, "reg", dev->reg); 1044040ab72SDavid Gibson if (ret < 0) { 1054040ab72SDavid Gibson return ret; 1064040ab72SDavid Gibson } 1074040ab72SDavid Gibson 1083954d33aSAnthony Liguori if (pc->dt_type) { 1094040ab72SDavid Gibson ret = fdt_setprop_string(fdt, node_off, "device_type", 1103954d33aSAnthony Liguori pc->dt_type); 1114040ab72SDavid Gibson if (ret < 0) { 1124040ab72SDavid Gibson return ret; 1134040ab72SDavid Gibson } 1144040ab72SDavid Gibson } 1154040ab72SDavid Gibson 116864674faSStefan Berger if (pc->get_dt_compatible) { 117864674faSStefan Berger dt_compatible = pc->get_dt_compatible(dev); 118864674faSStefan Berger } else { 119864674faSStefan Berger dt_compatible = pc->dt_compatible; 120864674faSStefan Berger } 121864674faSStefan Berger 122864674faSStefan Berger if (dt_compatible) { 1234040ab72SDavid Gibson ret = fdt_setprop_string(fdt, node_off, "compatible", 124864674faSStefan Berger dt_compatible); 1254040ab72SDavid Gibson if (ret < 0) { 1264040ab72SDavid Gibson return ret; 1274040ab72SDavid Gibson } 1284040ab72SDavid Gibson } 1294040ab72SDavid Gibson 130a307d594SAlexey Kardashevskiy if (dev->irq) { 131bb2d8ab6SGreg Kurz uint32_t ints_prop[2]; 13200dc738dSDavid Gibson 1335c7adcf4SGreg Kurz spapr_dt_irq(ints_prop, dev->irq, false); 13400dc738dSDavid Gibson ret = fdt_setprop(fdt, node_off, "interrupts", ints_prop, 13500dc738dSDavid Gibson sizeof(ints_prop)); 13600dc738dSDavid Gibson if (ret < 0) { 13700dc738dSDavid Gibson return ret; 13800dc738dSDavid Gibson } 13900dc738dSDavid Gibson } 14000dc738dSDavid Gibson 1412b7dc949SPaolo Bonzini ret = spapr_tcet_dma_dt(fdt, node_off, "ibm,my-dma-window", dev->tcet); 142ee86dfeeSDavid Gibson if (ret < 0) { 143ee86dfeeSDavid Gibson return ret; 144ee86dfeeSDavid Gibson } 145ee86dfeeSDavid Gibson 1463954d33aSAnthony Liguori if (pc->devnode) { 1473954d33aSAnthony Liguori ret = (pc->devnode)(dev, fdt, node_off); 1484040ab72SDavid Gibson if (ret < 0) { 1494040ab72SDavid Gibson return ret; 1504040ab72SDavid Gibson } 1514040ab72SDavid Gibson } 1524040ab72SDavid Gibson 1534040ab72SDavid Gibson return node_off; 1544040ab72SDavid Gibson } 1554040ab72SDavid Gibson 156ee86dfeeSDavid Gibson /* 157b45d63b6SBen Herrenschmidt * CRQ handling 158b45d63b6SBen Herrenschmidt */ 159ce2918cbSDavid Gibson static target_ulong h_reg_crq(PowerPCCPU *cpu, SpaprMachineState *spapr, 160b45d63b6SBen Herrenschmidt target_ulong opcode, target_ulong *args) 161b45d63b6SBen Herrenschmidt { 162b45d63b6SBen Herrenschmidt target_ulong reg = args[0]; 163b45d63b6SBen Herrenschmidt target_ulong queue_addr = args[1]; 164b45d63b6SBen Herrenschmidt target_ulong queue_len = args[2]; 165ce2918cbSDavid Gibson SpaprVioDevice *dev = spapr_vio_find_by_reg(spapr->vio_bus, reg); 166b45d63b6SBen Herrenschmidt 167b45d63b6SBen Herrenschmidt if (!dev) { 168d9599c92SDavid Gibson hcall_dprintf("Unit 0x" TARGET_FMT_lx " does not exist\n", reg); 169b45d63b6SBen Herrenschmidt return H_PARAMETER; 170b45d63b6SBen Herrenschmidt } 171b45d63b6SBen Herrenschmidt 172b45d63b6SBen Herrenschmidt /* We can't grok a queue size bigger than 256M for now */ 173b45d63b6SBen Herrenschmidt if (queue_len < 0x1000 || queue_len > 0x10000000) { 174d9599c92SDavid Gibson hcall_dprintf("Queue size too small or too big (0x" TARGET_FMT_lx 175d9599c92SDavid Gibson ")\n", queue_len); 176b45d63b6SBen Herrenschmidt return H_PARAMETER; 177b45d63b6SBen Herrenschmidt } 178b45d63b6SBen Herrenschmidt 179b45d63b6SBen Herrenschmidt /* Check queue alignment */ 180b45d63b6SBen Herrenschmidt if (queue_addr & 0xfff) { 181d9599c92SDavid Gibson hcall_dprintf("Queue not aligned (0x" TARGET_FMT_lx ")\n", queue_addr); 182b45d63b6SBen Herrenschmidt return H_PARAMETER; 183b45d63b6SBen Herrenschmidt } 184b45d63b6SBen Herrenschmidt 185b45d63b6SBen Herrenschmidt /* Check if device supports CRQs */ 186b45d63b6SBen Herrenschmidt if (!dev->crq.SendFunc) { 1878e01f355SDavid Gibson hcall_dprintf("Device does not support CRQ\n"); 188b45d63b6SBen Herrenschmidt return H_NOT_FOUND; 189b45d63b6SBen Herrenschmidt } 190b45d63b6SBen Herrenschmidt 191b45d63b6SBen Herrenschmidt /* Already a queue ? */ 192b45d63b6SBen Herrenschmidt if (dev->crq.qsize) { 1938e01f355SDavid Gibson hcall_dprintf("CRQ already registered\n"); 194b45d63b6SBen Herrenschmidt return H_RESOURCE; 195b45d63b6SBen Herrenschmidt } 196b45d63b6SBen Herrenschmidt dev->crq.qladdr = queue_addr; 197b45d63b6SBen Herrenschmidt dev->crq.qsize = queue_len; 198b45d63b6SBen Herrenschmidt dev->crq.qnext = 0; 199b45d63b6SBen Herrenschmidt 2007ab6a501SLaurent Vivier trace_spapr_vio_h_reg_crq(reg, queue_addr, queue_len); 201b45d63b6SBen Herrenschmidt return H_SUCCESS; 202b45d63b6SBen Herrenschmidt } 203b45d63b6SBen Herrenschmidt 204ce2918cbSDavid Gibson static target_ulong free_crq(SpaprVioDevice *dev) 2058e01f355SDavid Gibson { 2068e01f355SDavid Gibson dev->crq.qladdr = 0; 2078e01f355SDavid Gibson dev->crq.qsize = 0; 2088e01f355SDavid Gibson dev->crq.qnext = 0; 2098e01f355SDavid Gibson 2107ab6a501SLaurent Vivier trace_spapr_vio_free_crq(dev->reg); 2118e01f355SDavid Gibson 2128e01f355SDavid Gibson return H_SUCCESS; 2138e01f355SDavid Gibson } 2148e01f355SDavid Gibson 215ce2918cbSDavid Gibson static target_ulong h_free_crq(PowerPCCPU *cpu, SpaprMachineState *spapr, 216b45d63b6SBen Herrenschmidt target_ulong opcode, target_ulong *args) 217b45d63b6SBen Herrenschmidt { 218b45d63b6SBen Herrenschmidt target_ulong reg = args[0]; 219ce2918cbSDavid Gibson SpaprVioDevice *dev = spapr_vio_find_by_reg(spapr->vio_bus, reg); 220b45d63b6SBen Herrenschmidt 221b45d63b6SBen Herrenschmidt if (!dev) { 222d9599c92SDavid Gibson hcall_dprintf("Unit 0x" TARGET_FMT_lx " does not exist\n", reg); 223b45d63b6SBen Herrenschmidt return H_PARAMETER; 224b45d63b6SBen Herrenschmidt } 225b45d63b6SBen Herrenschmidt 2268e01f355SDavid Gibson return free_crq(dev); 227b45d63b6SBen Herrenschmidt } 228b45d63b6SBen Herrenschmidt 229ce2918cbSDavid Gibson static target_ulong h_send_crq(PowerPCCPU *cpu, SpaprMachineState *spapr, 230b45d63b6SBen Herrenschmidt target_ulong opcode, target_ulong *args) 231b45d63b6SBen Herrenschmidt { 232b45d63b6SBen Herrenschmidt target_ulong reg = args[0]; 233b45d63b6SBen Herrenschmidt target_ulong msg_hi = args[1]; 234b45d63b6SBen Herrenschmidt target_ulong msg_lo = args[2]; 235ce2918cbSDavid Gibson SpaprVioDevice *dev = spapr_vio_find_by_reg(spapr->vio_bus, reg); 236b45d63b6SBen Herrenschmidt uint64_t crq_mangle[2]; 237b45d63b6SBen Herrenschmidt 238b45d63b6SBen Herrenschmidt if (!dev) { 239d9599c92SDavid Gibson hcall_dprintf("Unit 0x" TARGET_FMT_lx " does not exist\n", reg); 240b45d63b6SBen Herrenschmidt return H_PARAMETER; 241b45d63b6SBen Herrenschmidt } 242b45d63b6SBen Herrenschmidt crq_mangle[0] = cpu_to_be64(msg_hi); 243b45d63b6SBen Herrenschmidt crq_mangle[1] = cpu_to_be64(msg_lo); 244b45d63b6SBen Herrenschmidt 245b45d63b6SBen Herrenschmidt if (dev->crq.SendFunc) { 246b45d63b6SBen Herrenschmidt return dev->crq.SendFunc(dev, (uint8_t *)crq_mangle); 247b45d63b6SBen Herrenschmidt } 248b45d63b6SBen Herrenschmidt 249b45d63b6SBen Herrenschmidt return H_HARDWARE; 250b45d63b6SBen Herrenschmidt } 251b45d63b6SBen Herrenschmidt 252ce2918cbSDavid Gibson static target_ulong h_enable_crq(PowerPCCPU *cpu, SpaprMachineState *spapr, 253b45d63b6SBen Herrenschmidt target_ulong opcode, target_ulong *args) 254b45d63b6SBen Herrenschmidt { 255b45d63b6SBen Herrenschmidt target_ulong reg = args[0]; 256ce2918cbSDavid Gibson SpaprVioDevice *dev = spapr_vio_find_by_reg(spapr->vio_bus, reg); 257b45d63b6SBen Herrenschmidt 258b45d63b6SBen Herrenschmidt if (!dev) { 259d9599c92SDavid Gibson hcall_dprintf("Unit 0x" TARGET_FMT_lx " does not exist\n", reg); 260b45d63b6SBen Herrenschmidt return H_PARAMETER; 261b45d63b6SBen Herrenschmidt } 262b45d63b6SBen Herrenschmidt 263b45d63b6SBen Herrenschmidt return 0; 264b45d63b6SBen Herrenschmidt } 265b45d63b6SBen Herrenschmidt 266b45d63b6SBen Herrenschmidt /* Returns negative error, 0 success, or positive: queue full */ 267ce2918cbSDavid Gibson int spapr_vio_send_crq(SpaprVioDevice *dev, uint8_t *crq) 268b45d63b6SBen Herrenschmidt { 269b45d63b6SBen Herrenschmidt int rc; 270b45d63b6SBen Herrenschmidt uint8_t byte; 271b45d63b6SBen Herrenschmidt 272b45d63b6SBen Herrenschmidt if (!dev->crq.qsize) { 273ce9863b7SCédric Le Goater error_report("spapr_vio_send_creq on uninitialized queue"); 274b45d63b6SBen Herrenschmidt return -1; 275b45d63b6SBen Herrenschmidt } 276b45d63b6SBen Herrenschmidt 277b45d63b6SBen Herrenschmidt /* Maybe do a fast path for KVM just writing to the pages */ 278ad0ebb91SDavid Gibson rc = spapr_vio_dma_read(dev, dev->crq.qladdr + dev->crq.qnext, &byte, 1); 279b45d63b6SBen Herrenschmidt if (rc) { 280b45d63b6SBen Herrenschmidt return rc; 281b45d63b6SBen Herrenschmidt } 282b45d63b6SBen Herrenschmidt if (byte != 0) { 283b45d63b6SBen Herrenschmidt return 1; 284b45d63b6SBen Herrenschmidt } 285b45d63b6SBen Herrenschmidt 286ad0ebb91SDavid Gibson rc = spapr_vio_dma_write(dev, dev->crq.qladdr + dev->crq.qnext + 8, 287b45d63b6SBen Herrenschmidt &crq[8], 8); 288b45d63b6SBen Herrenschmidt if (rc) { 289b45d63b6SBen Herrenschmidt return rc; 290b45d63b6SBen Herrenschmidt } 291b45d63b6SBen Herrenschmidt 292b45d63b6SBen Herrenschmidt kvmppc_eieio(); 293b45d63b6SBen Herrenschmidt 294ad0ebb91SDavid Gibson rc = spapr_vio_dma_write(dev, dev->crq.qladdr + dev->crq.qnext, crq, 8); 295b45d63b6SBen Herrenschmidt if (rc) { 296b45d63b6SBen Herrenschmidt return rc; 297b45d63b6SBen Herrenschmidt } 298b45d63b6SBen Herrenschmidt 299b45d63b6SBen Herrenschmidt dev->crq.qnext = (dev->crq.qnext + 16) % dev->crq.qsize; 300b45d63b6SBen Herrenschmidt 301b45d63b6SBen Herrenschmidt if (dev->signal_state & 1) { 3027678b74aSDavid Gibson spapr_vio_irq_pulse(dev); 303b45d63b6SBen Herrenschmidt } 304b45d63b6SBen Herrenschmidt 305b45d63b6SBen Herrenschmidt return 0; 306b45d63b6SBen Herrenschmidt } 307b45d63b6SBen Herrenschmidt 30808942ac1SBen Herrenschmidt /* "quiesce" handling */ 30908942ac1SBen Herrenschmidt 310ce2918cbSDavid Gibson static void spapr_vio_quiesce_one(SpaprVioDevice *dev) 31108942ac1SBen Herrenschmidt { 3122b7dc949SPaolo Bonzini if (dev->tcet) { 3133e1c8ba9SPeter Maydell device_cold_reset(DEVICE(dev->tcet)); 31408942ac1SBen Herrenschmidt } 3154dd96f24SDavid Gibson free_crq(dev); 31608942ac1SBen Herrenschmidt } 31708942ac1SBen Herrenschmidt 318ce2918cbSDavid Gibson void spapr_vio_set_bypass(SpaprVioDevice *dev, bool bypass) 319ee9a569aSAlexey Kardashevskiy { 320ee9a569aSAlexey Kardashevskiy if (!dev->tcet) { 321ee9a569aSAlexey Kardashevskiy return; 322ee9a569aSAlexey Kardashevskiy } 323ee9a569aSAlexey Kardashevskiy 324ee9a569aSAlexey Kardashevskiy memory_region_set_enabled(&dev->mrbypass, bypass); 325ee9a569aSAlexey Kardashevskiy memory_region_set_enabled(spapr_tce_get_iommu(dev->tcet), !bypass); 326ee9a569aSAlexey Kardashevskiy 327ee9a569aSAlexey Kardashevskiy dev->tcet->bypass = bypass; 328ee9a569aSAlexey Kardashevskiy } 329ee9a569aSAlexey Kardashevskiy 330ce2918cbSDavid Gibson static void rtas_set_tce_bypass(PowerPCCPU *cpu, SpaprMachineState *spapr, 331210b580bSAnthony Liguori uint32_t token, 33208942ac1SBen Herrenschmidt uint32_t nargs, target_ulong args, 33308942ac1SBen Herrenschmidt uint32_t nret, target_ulong rets) 33408942ac1SBen Herrenschmidt { 335ce2918cbSDavid Gibson SpaprVioBus *bus = spapr->vio_bus; 336ce2918cbSDavid Gibson SpaprVioDevice *dev; 33708942ac1SBen Herrenschmidt uint32_t unit, enable; 33808942ac1SBen Herrenschmidt 33908942ac1SBen Herrenschmidt if (nargs != 2) { 340a64d325dSAlexey Kardashevskiy rtas_st(rets, 0, RTAS_OUT_PARAM_ERROR); 34108942ac1SBen Herrenschmidt return; 34208942ac1SBen Herrenschmidt } 34308942ac1SBen Herrenschmidt unit = rtas_ld(args, 0); 34408942ac1SBen Herrenschmidt enable = rtas_ld(args, 1); 34508942ac1SBen Herrenschmidt dev = spapr_vio_find_by_reg(bus, unit); 34608942ac1SBen Herrenschmidt if (!dev) { 347a64d325dSAlexey Kardashevskiy rtas_st(rets, 0, RTAS_OUT_PARAM_ERROR); 34808942ac1SBen Herrenschmidt return; 34908942ac1SBen Herrenschmidt } 350ad0ebb91SDavid Gibson 3512b7dc949SPaolo Bonzini if (!dev->tcet) { 352a64d325dSAlexey Kardashevskiy rtas_st(rets, 0, RTAS_OUT_PARAM_ERROR); 35353724ee5SDavid Gibson return; 35408942ac1SBen Herrenschmidt } 35508942ac1SBen Herrenschmidt 356ee9a569aSAlexey Kardashevskiy spapr_vio_set_bypass(dev, !!enable); 35753724ee5SDavid Gibson 358a64d325dSAlexey Kardashevskiy rtas_st(rets, 0, RTAS_OUT_SUCCESS); 35908942ac1SBen Herrenschmidt } 36008942ac1SBen Herrenschmidt 361ce2918cbSDavid Gibson static void rtas_quiesce(PowerPCCPU *cpu, SpaprMachineState *spapr, 362210b580bSAnthony Liguori uint32_t token, 36308942ac1SBen Herrenschmidt uint32_t nargs, target_ulong args, 36408942ac1SBen Herrenschmidt uint32_t nret, target_ulong rets) 36508942ac1SBen Herrenschmidt { 366ce2918cbSDavid Gibson SpaprVioBus *bus = spapr->vio_bus; 3670866aca1SAnthony Liguori BusChild *kid; 368ce2918cbSDavid Gibson SpaprVioDevice *dev = NULL; 36908942ac1SBen Herrenschmidt 37008942ac1SBen Herrenschmidt if (nargs != 0) { 371a64d325dSAlexey Kardashevskiy rtas_st(rets, 0, RTAS_OUT_PARAM_ERROR); 37208942ac1SBen Herrenschmidt return; 37308942ac1SBen Herrenschmidt } 37408942ac1SBen Herrenschmidt 3750866aca1SAnthony Liguori QTAILQ_FOREACH(kid, &bus->bus.children, sibling) { 376ce2918cbSDavid Gibson dev = (SpaprVioDevice *)kid->child; 37708942ac1SBen Herrenschmidt spapr_vio_quiesce_one(dev); 37808942ac1SBen Herrenschmidt } 37908942ac1SBen Herrenschmidt 380a64d325dSAlexey Kardashevskiy rtas_st(rets, 0, RTAS_OUT_SUCCESS); 38108942ac1SBen Herrenschmidt } 38208942ac1SBen Herrenschmidt 383ce2918cbSDavid Gibson static SpaprVioDevice *reg_conflict(SpaprVioDevice *dev) 3849fc380d3SMichael Ellerman { 385ce2918cbSDavid Gibson SpaprVioBus *bus = SPAPR_VIO_BUS(dev->qdev.parent_bus); 3860866aca1SAnthony Liguori BusChild *kid; 387ce2918cbSDavid Gibson SpaprVioDevice *other; 3889fc380d3SMichael Ellerman 3899fc380d3SMichael Ellerman /* 390d601fac4SDavid Gibson * Check for a device other than the given one which is already 391d601fac4SDavid Gibson * using the requested address. We have to open code this because 392d601fac4SDavid Gibson * the given dev might already be in the list. 3939fc380d3SMichael Ellerman */ 3940866aca1SAnthony Liguori QTAILQ_FOREACH(kid, &bus->bus.children, sibling) { 395fd506b4fSDavid Gibson other = VIO_SPAPR_DEVICE(kid->child); 3969fc380d3SMichael Ellerman 397d601fac4SDavid Gibson if (other != dev && other->reg == dev->reg) { 398d601fac4SDavid Gibson return other; 3999fc380d3SMichael Ellerman } 4009fc380d3SMichael Ellerman } 4019fc380d3SMichael Ellerman 4029fc380d3SMichael Ellerman return 0; 4039fc380d3SMichael Ellerman } 4049fc380d3SMichael Ellerman 405b1c7f725SDavid Gibson static void spapr_vio_busdev_reset(DeviceState *qdev) 4068e01f355SDavid Gibson { 407ce2918cbSDavid Gibson SpaprVioDevice *dev = VIO_SPAPR_DEVICE(qdev); 408ce2918cbSDavid Gibson SpaprVioDeviceClass *pc = VIO_SPAPR_DEVICE_GET_CLASS(dev); 4098e01f355SDavid Gibson 4104dd96f24SDavid Gibson /* Shut down the request queue and TCEs if necessary */ 4114dd96f24SDavid Gibson spapr_vio_quiesce_one(dev); 4124dd96f24SDavid Gibson 4134dd96f24SDavid Gibson dev->signal_state = 0; 414b1c7f725SDavid Gibson 415ee9a569aSAlexey Kardashevskiy spapr_vio_set_bypass(dev, false); 416b1c7f725SDavid Gibson if (pc->reset) { 417b1c7f725SDavid Gibson pc->reset(dev); 418b1c7f725SDavid Gibson } 4198e01f355SDavid Gibson } 4208e01f355SDavid Gibson 42182cffa2eSCédric Le Goater /* 4227861e083SGustavo Romero * The register property of a VIO device is defined in libvirt using 42382cffa2eSCédric Le Goater * 0x1000 as a base register number plus a 0x1000 increment. For the 42482cffa2eSCédric Le Goater * VIO tty device, the base number is changed to 0x30000000. QEMU uses 42582cffa2eSCédric Le Goater * a base register number of 0x71000000 and then a simple increment. 42682cffa2eSCédric Le Goater * 42782cffa2eSCédric Le Goater * The formula below tries to compute a unique index number from the 42882cffa2eSCédric Le Goater * register value that will be used to define the IRQ number of the 42982cffa2eSCédric Le Goater * VIO device. 43082cffa2eSCédric Le Goater * 43182cffa2eSCédric Le Goater * A maximum of 256 VIO devices is covered. Collisions are possible 43282cffa2eSCédric Le Goater * but they will be detected when the IRQ is claimed. 43382cffa2eSCédric Le Goater */ 43482cffa2eSCédric Le Goater static inline uint32_t spapr_vio_reg_to_irq(uint32_t reg) 43582cffa2eSCédric Le Goater { 43682cffa2eSCédric Le Goater uint32_t irq; 43782cffa2eSCédric Le Goater 43882cffa2eSCédric Le Goater if (reg >= SPAPR_VIO_REG_BASE) { 43982cffa2eSCédric Le Goater /* 44082cffa2eSCédric Le Goater * VIO device register values when allocated by QEMU. For 44182cffa2eSCédric Le Goater * these, we simply mask the high bits to fit the overall 44282cffa2eSCédric Le Goater * range: [0x00 - 0xff]. 44382cffa2eSCédric Le Goater * 44482cffa2eSCédric Le Goater * The nvram VIO device (reg=0x71000000) is a static device of 44582cffa2eSCédric Le Goater * the pseries machine and so is always allocated by QEMU. Its 44682cffa2eSCédric Le Goater * IRQ number is 0x0. 44782cffa2eSCédric Le Goater */ 44882cffa2eSCédric Le Goater irq = reg & 0xff; 44982cffa2eSCédric Le Goater 45082cffa2eSCédric Le Goater } else if (reg >= 0x30000000) { 45182cffa2eSCédric Le Goater /* 4527861e083SGustavo Romero * VIO tty devices register values, when allocated by libvirt, 45382cffa2eSCédric Le Goater * are mapped in range [0xf0 - 0xff], gives us a maximum of 16 45482cffa2eSCédric Le Goater * vtys. 45582cffa2eSCédric Le Goater */ 45682cffa2eSCédric Le Goater irq = 0xf0 | ((reg >> 12) & 0xf); 45782cffa2eSCédric Le Goater 45882cffa2eSCédric Le Goater } else { 45982cffa2eSCédric Le Goater /* 46082cffa2eSCédric Le Goater * Other VIO devices register values, when allocated by 4617861e083SGustavo Romero * libvirt, should be mapped in range [0x00 - 0xef]. Conflicts 46282cffa2eSCédric Le Goater * will be detected when IRQ is claimed. 46382cffa2eSCédric Le Goater */ 46482cffa2eSCédric Le Goater irq = (reg >> 12) & 0xff; 46582cffa2eSCédric Le Goater } 46682cffa2eSCédric Le Goater 46782cffa2eSCédric Le Goater return SPAPR_IRQ_VIO | irq; 46882cffa2eSCédric Le Goater } 46982cffa2eSCédric Le Goater 47028b07e73SMarkus Armbruster static void spapr_vio_busdev_realize(DeviceState *qdev, Error **errp) 4714040ab72SDavid Gibson { 472ce2918cbSDavid Gibson SpaprMachineState *spapr = SPAPR_MACHINE(qdev_get_machine()); 473ce2918cbSDavid Gibson SpaprVioDevice *dev = (SpaprVioDevice *)qdev; 474ce2918cbSDavid Gibson SpaprVioDeviceClass *pc = VIO_SPAPR_DEVICE_GET_CLASS(dev); 4754040ab72SDavid Gibson char *id; 4769fc380d3SMichael Ellerman 477d601fac4SDavid Gibson if (dev->reg != -1) { 478d601fac4SDavid Gibson /* 479d601fac4SDavid Gibson * Explicitly assigned address, just verify that no-one else 480d601fac4SDavid Gibson * is using it. other mechanism). We have to open code this 481d601fac4SDavid Gibson * rather than using spapr_vio_find_by_reg() because sdev 482d601fac4SDavid Gibson * itself is already in the list. 483d601fac4SDavid Gibson */ 484ce2918cbSDavid Gibson SpaprVioDevice *other = reg_conflict(dev); 485d601fac4SDavid Gibson 486d601fac4SDavid Gibson if (other) { 48728b07e73SMarkus Armbruster error_setg(errp, "%s and %s devices conflict at address %#x", 488d601fac4SDavid Gibson object_get_typename(OBJECT(qdev)), 489d601fac4SDavid Gibson object_get_typename(OBJECT(&other->qdev)), 490d601fac4SDavid Gibson dev->reg); 49128b07e73SMarkus Armbruster return; 492d601fac4SDavid Gibson } 493d601fac4SDavid Gibson } else { 494d601fac4SDavid Gibson /* Need to assign an address */ 495ce2918cbSDavid Gibson SpaprVioBus *bus = SPAPR_VIO_BUS(dev->qdev.parent_bus); 496d601fac4SDavid Gibson 497d601fac4SDavid Gibson do { 498d601fac4SDavid Gibson dev->reg = bus->next_reg++; 499d601fac4SDavid Gibson } while (reg_conflict(dev)); 5009fc380d3SMichael Ellerman } 5014040ab72SDavid Gibson 5021e34d859SMichael Ellerman /* Don't overwrite ids assigned on the command line */ 5031e34d859SMichael Ellerman if (!dev->qdev.id) { 504c4eda5b7SDavid Gibson id = spapr_vio_get_dev_name(DEVICE(dev)); 5054040ab72SDavid Gibson dev->qdev.id = id; 5061e34d859SMichael Ellerman } 507e6c866d4SDavid Gibson 50882cffa2eSCédric Le Goater dev->irq = spapr_vio_reg_to_irq(dev->reg); 50982cffa2eSCédric Le Goater 51082cffa2eSCédric Le Goater if (SPAPR_MACHINE_GET_CLASS(spapr)->legacy_irq_allocation) { 511a9c2cdacSGreg Kurz int irq = spapr_irq_findone(spapr, errp); 512a9c2cdacSGreg Kurz 513a9c2cdacSGreg Kurz if (irq < 0) { 5144fe75a8cSCédric Le Goater return; 5154fe75a8cSCédric Le Goater } 516a9c2cdacSGreg Kurz dev->irq = irq; 5174fe75a8cSCédric Le Goater } 5184fe75a8cSCédric Le Goater 519a9c2cdacSGreg Kurz if (spapr_irq_claim(spapr, dev->irq, false, errp) < 0) { 52028b07e73SMarkus Armbruster return; 521416343b1SPaolo Bonzini } 5224040ab72SDavid Gibson 52353724ee5SDavid Gibson if (pc->rtce_window_size) { 5244290ca49SAlexey Kardashevskiy uint32_t liobn = SPAPR_VIO_LIOBN(dev->reg); 525ee9a569aSAlexey Kardashevskiy 526ee9a569aSAlexey Kardashevskiy memory_region_init(&dev->mrroot, OBJECT(dev), "iommu-spapr-root", 527ead2b283SPaolo Bonzini MACHINE(spapr)->ram_size); 528ee9a569aSAlexey Kardashevskiy memory_region_init_alias(&dev->mrbypass, OBJECT(dev), 529ee9a569aSAlexey Kardashevskiy "iommu-spapr-bypass", get_system_memory(), 530ead2b283SPaolo Bonzini 0, MACHINE(spapr)->ram_size); 531ee9a569aSAlexey Kardashevskiy memory_region_add_subregion_overlap(&dev->mrroot, 0, &dev->mrbypass, 1); 532ee9a569aSAlexey Kardashevskiy address_space_init(&dev->as, &dev->mrroot, qdev->id); 533ee9a569aSAlexey Kardashevskiy 534df7625d4SAlexey Kardashevskiy dev->tcet = spapr_tce_new_table(qdev, liobn); 535df7625d4SAlexey Kardashevskiy spapr_tce_table_enable(dev->tcet, SPAPR_TCE_PAGE_SHIFT, 0, 536df7625d4SAlexey Kardashevskiy pc->rtce_window_size >> SPAPR_TCE_PAGE_SHIFT); 537ee9a569aSAlexey Kardashevskiy dev->tcet->vdev = dev; 538ee9a569aSAlexey Kardashevskiy memory_region_add_subregion_overlap(&dev->mrroot, 0, 539ee9a569aSAlexey Kardashevskiy spapr_tce_get_iommu(dev->tcet), 2); 54053724ee5SDavid Gibson } 541ee86dfeeSDavid Gibson 54228b07e73SMarkus Armbruster pc->realize(dev, errp); 5434040ab72SDavid Gibson } 5444040ab72SDavid Gibson 545ce2918cbSDavid Gibson static target_ulong h_vio_signal(PowerPCCPU *cpu, SpaprMachineState *spapr, 54600dc738dSDavid Gibson target_ulong opcode, 54700dc738dSDavid Gibson target_ulong *args) 54800dc738dSDavid Gibson { 54900dc738dSDavid Gibson target_ulong reg = args[0]; 55000dc738dSDavid Gibson target_ulong mode = args[1]; 551ce2918cbSDavid Gibson SpaprVioDevice *dev = spapr_vio_find_by_reg(spapr->vio_bus, reg); 552ce2918cbSDavid Gibson SpaprVioDeviceClass *pc; 55300dc738dSDavid Gibson 55400dc738dSDavid Gibson if (!dev) { 55500dc738dSDavid Gibson return H_PARAMETER; 55600dc738dSDavid Gibson } 55700dc738dSDavid Gibson 5583954d33aSAnthony Liguori pc = VIO_SPAPR_DEVICE_GET_CLASS(dev); 55900dc738dSDavid Gibson 5603954d33aSAnthony Liguori if (mode & ~pc->signal_mask) { 56100dc738dSDavid Gibson return H_PARAMETER; 56200dc738dSDavid Gibson } 56300dc738dSDavid Gibson 56400dc738dSDavid Gibson dev->signal_state = mode; 56500dc738dSDavid Gibson 56600dc738dSDavid Gibson return H_SUCCESS; 56700dc738dSDavid Gibson } 56800dc738dSDavid Gibson 569ce2918cbSDavid Gibson SpaprVioBus *spapr_vio_bus_init(void) 5704040ab72SDavid Gibson { 571ce2918cbSDavid Gibson SpaprVioBus *bus; 5724040ab72SDavid Gibson BusState *qbus; 5734040ab72SDavid Gibson DeviceState *dev; 5744040ab72SDavid Gibson 5754040ab72SDavid Gibson /* Create bridge device */ 5763e80f690SMarkus Armbruster dev = qdev_new(TYPE_SPAPR_VIO_BRIDGE); 5774040ab72SDavid Gibson 5784040ab72SDavid Gibson /* Create bus on bridge device */ 5799388d170SPeter Maydell qbus = qbus_new(TYPE_SPAPR_VIO_BUS, dev, "spapr-vio"); 580215e2098SCao jin bus = SPAPR_VIO_BUS(qbus); 58182cffa2eSCédric Le Goater bus->next_reg = SPAPR_VIO_REG_BASE; 5824040ab72SDavid Gibson 583880e2607SPhilippe Mathieu-Daudé sysbus_realize_and_unref(SYS_BUS_DEVICE(dev), &error_fatal); 584880e2607SPhilippe Mathieu-Daudé 58500dc738dSDavid Gibson /* hcall-vio */ 58600dc738dSDavid Gibson spapr_register_hypercall(H_VIO_SIGNAL, h_vio_signal); 58700dc738dSDavid Gibson 588b45d63b6SBen Herrenschmidt /* hcall-crq */ 589b45d63b6SBen Herrenschmidt spapr_register_hypercall(H_REG_CRQ, h_reg_crq); 590b45d63b6SBen Herrenschmidt spapr_register_hypercall(H_FREE_CRQ, h_free_crq); 591b45d63b6SBen Herrenschmidt spapr_register_hypercall(H_SEND_CRQ, h_send_crq); 592b45d63b6SBen Herrenschmidt spapr_register_hypercall(H_ENABLE_CRQ, h_enable_crq); 593b45d63b6SBen Herrenschmidt 59408942ac1SBen Herrenschmidt /* RTAS calls */ 5953a3b8502SAlexey Kardashevskiy spapr_rtas_register(RTAS_IBM_SET_TCE_BYPASS, "ibm,set-tce-bypass", 5963a3b8502SAlexey Kardashevskiy rtas_set_tce_bypass); 5973a3b8502SAlexey Kardashevskiy spapr_rtas_register(RTAS_QUIESCE, "quiesce", rtas_quiesce); 59808942ac1SBen Herrenschmidt 5994040ab72SDavid Gibson return bus; 6004040ab72SDavid Gibson } 6014040ab72SDavid Gibson 602999e12bbSAnthony Liguori static void spapr_vio_bridge_class_init(ObjectClass *klass, void *data) 603999e12bbSAnthony Liguori { 6045a06393fSAlexey Kardashevskiy DeviceClass *dc = DEVICE_CLASS(klass); 605999e12bbSAnthony Liguori 6065a06393fSAlexey Kardashevskiy dc->fw_name = "vdevice"; 607999e12bbSAnthony Liguori } 608999e12bbSAnthony Liguori 6098c43a6f0SAndreas Färber static const TypeInfo spapr_vio_bridge_info = { 610215e2098SCao jin .name = TYPE_SPAPR_VIO_BRIDGE, 61139bffca2SAnthony Liguori .parent = TYPE_SYS_BUS_DEVICE, 612999e12bbSAnthony Liguori .class_init = spapr_vio_bridge_class_init, 6134040ab72SDavid Gibson }; 6144040ab72SDavid Gibson 615b368a7d8SDavid Gibson const VMStateDescription vmstate_spapr_vio = { 616b368a7d8SDavid Gibson .name = "spapr_vio", 617b368a7d8SDavid Gibson .version_id = 1, 618b368a7d8SDavid Gibson .minimum_version_id = 1, 619078ddbc9SRichard Henderson .fields = (const VMStateField[]) { 620b368a7d8SDavid Gibson /* Sanity check */ 621ce2918cbSDavid Gibson VMSTATE_UINT32_EQUAL(reg, SpaprVioDevice, NULL), 622ce2918cbSDavid Gibson VMSTATE_UINT32_EQUAL(irq, SpaprVioDevice, NULL), 623b368a7d8SDavid Gibson 624b368a7d8SDavid Gibson /* General VIO device state */ 625ce2918cbSDavid Gibson VMSTATE_UINT64(signal_state, SpaprVioDevice), 626ce2918cbSDavid Gibson VMSTATE_UINT64(crq.qladdr, SpaprVioDevice), 627ce2918cbSDavid Gibson VMSTATE_UINT32(crq.qsize, SpaprVioDevice), 628ce2918cbSDavid Gibson VMSTATE_UINT32(crq.qnext, SpaprVioDevice), 629b368a7d8SDavid Gibson 630b368a7d8SDavid Gibson VMSTATE_END_OF_LIST() 631b368a7d8SDavid Gibson }, 632b368a7d8SDavid Gibson }; 633b368a7d8SDavid Gibson 63439bffca2SAnthony Liguori static void vio_spapr_device_class_init(ObjectClass *klass, void *data) 63539bffca2SAnthony Liguori { 63639bffca2SAnthony Liguori DeviceClass *k = DEVICE_CLASS(klass); 63728b07e73SMarkus Armbruster k->realize = spapr_vio_busdev_realize; 638e3d08143SPeter Maydell device_class_set_legacy_reset(k, spapr_vio_busdev_reset); 6390d936928SAnthony Liguori k->bus_type = TYPE_SPAPR_VIO_BUS; 64039bffca2SAnthony Liguori } 64139bffca2SAnthony Liguori 6428c43a6f0SAndreas Färber static const TypeInfo spapr_vio_type_info = { 6433954d33aSAnthony Liguori .name = TYPE_VIO_SPAPR_DEVICE, 6443954d33aSAnthony Liguori .parent = TYPE_DEVICE, 645ce2918cbSDavid Gibson .instance_size = sizeof(SpaprVioDevice), 6463954d33aSAnthony Liguori .abstract = true, 647ce2918cbSDavid Gibson .class_size = sizeof(SpaprVioDeviceClass), 64839bffca2SAnthony Liguori .class_init = vio_spapr_device_class_init, 6493954d33aSAnthony Liguori }; 6503954d33aSAnthony Liguori 65183f7d43aSAndreas Färber static void spapr_vio_register_types(void) 6524040ab72SDavid Gibson { 6530d936928SAnthony Liguori type_register_static(&spapr_vio_bus_info); 65439bffca2SAnthony Liguori type_register_static(&spapr_vio_bridge_info); 6553954d33aSAnthony Liguori type_register_static(&spapr_vio_type_info); 6564040ab72SDavid Gibson } 6574040ab72SDavid Gibson 65883f7d43aSAndreas Färber type_init(spapr_vio_register_types) 6594040ab72SDavid Gibson 66005c19438SDavid Gibson static int compare_reg(const void *p1, const void *p2) 66105c19438SDavid Gibson { 662ce2918cbSDavid Gibson SpaprVioDevice const *dev1, *dev2; 66305c19438SDavid Gibson 664ce2918cbSDavid Gibson dev1 = (SpaprVioDevice *)*(DeviceState **)p1; 665ce2918cbSDavid Gibson dev2 = (SpaprVioDevice *)*(DeviceState **)p2; 66605c19438SDavid Gibson 66705c19438SDavid Gibson if (dev1->reg < dev2->reg) { 66805c19438SDavid Gibson return -1; 66905c19438SDavid Gibson } 67005c19438SDavid Gibson if (dev1->reg == dev2->reg) { 67105c19438SDavid Gibson return 0; 67205c19438SDavid Gibson } 67305c19438SDavid Gibson 67405c19438SDavid Gibson /* dev1->reg > dev2->reg */ 67505c19438SDavid Gibson return 1; 67605c19438SDavid Gibson } 67705c19438SDavid Gibson 678ce2918cbSDavid Gibson void spapr_dt_vdevice(SpaprVioBus *bus, void *fdt) 6794040ab72SDavid Gibson { 68005c19438SDavid Gibson DeviceState *qdev, **qdevs; 6810866aca1SAnthony Liguori BusChild *kid; 68205c19438SDavid Gibson int i, num, ret = 0; 683bf5a6696SDavid Gibson int node; 684bf5a6696SDavid Gibson 685bf5a6696SDavid Gibson _FDT(node = fdt_add_subnode(fdt, 0, "vdevice")); 686bf5a6696SDavid Gibson 687bf5a6696SDavid Gibson _FDT(fdt_setprop_string(fdt, node, "device_type", "vdevice")); 688bf5a6696SDavid Gibson _FDT(fdt_setprop_string(fdt, node, "compatible", "IBM,vdevice")); 689bf5a6696SDavid Gibson _FDT(fdt_setprop_cell(fdt, node, "#address-cells", 1)); 690bf5a6696SDavid Gibson _FDT(fdt_setprop_cell(fdt, node, "#size-cells", 0)); 691bf5a6696SDavid Gibson _FDT(fdt_setprop_cell(fdt, node, "#interrupt-cells", 2)); 692bf5a6696SDavid Gibson _FDT(fdt_setprop(fdt, node, "interrupt-controller", NULL, 0)); 6934040ab72SDavid Gibson 69405c19438SDavid Gibson /* Count qdevs on the bus list */ 69505c19438SDavid Gibson num = 0; 6960866aca1SAnthony Liguori QTAILQ_FOREACH(kid, &bus->bus.children, sibling) { 69705c19438SDavid Gibson num++; 69805c19438SDavid Gibson } 69905c19438SDavid Gibson 70005c19438SDavid Gibson /* Copy out into an array of pointers */ 701dec4ec40SGreg Kurz qdevs = g_new(DeviceState *, num); 70205c19438SDavid Gibson num = 0; 7030866aca1SAnthony Liguori QTAILQ_FOREACH(kid, &bus->bus.children, sibling) { 7040866aca1SAnthony Liguori qdevs[num++] = kid->child; 70505c19438SDavid Gibson } 70605c19438SDavid Gibson 70705c19438SDavid Gibson /* Sort the array */ 70805c19438SDavid Gibson qsort(qdevs, num, sizeof(qdev), compare_reg); 70905c19438SDavid Gibson 71005c19438SDavid Gibson /* Hack alert. Give the devices to libfdt in reverse order, we happen 71105c19438SDavid Gibson * to know that will mean they are in forward order in the tree. */ 71205c19438SDavid Gibson for (i = num - 1; i >= 0; i--) { 713ce2918cbSDavid Gibson SpaprVioDevice *dev = (SpaprVioDevice *)(qdevs[i]); 714ce2918cbSDavid Gibson SpaprVioDeviceClass *vdc = VIO_SPAPR_DEVICE_GET_CLASS(dev); 7154040ab72SDavid Gibson 7164040ab72SDavid Gibson ret = vio_make_devnode(dev, fdt); 7174040ab72SDavid Gibson if (ret < 0) { 718bf5a6696SDavid Gibson error_report("Couldn't create device node /vdevice/%s@%"PRIx32, 719bf5a6696SDavid Gibson vdc->dt_name, dev->reg); 720bf5a6696SDavid Gibson exit(1); 7214040ab72SDavid Gibson } 7224040ab72SDavid Gibson } 7234040ab72SDavid Gibson 7245f1d1fc5SMarkus Armbruster g_free(qdevs); 7254040ab72SDavid Gibson } 72668f3a94cSDavid Gibson 727ce2918cbSDavid Gibson gchar *spapr_vio_stdout_path(SpaprVioBus *bus) 72868f3a94cSDavid Gibson { 729ce2918cbSDavid Gibson SpaprVioDevice *dev; 73016951843SDaniel Henrique Barboza g_autofree char *name = NULL; 73168f3a94cSDavid Gibson 73268f3a94cSDavid Gibson dev = spapr_vty_get_default(bus); 7337c866c6aSDavid Gibson if (!dev) { 7347c866c6aSDavid Gibson return NULL; 73568f3a94cSDavid Gibson } 73668f3a94cSDavid Gibson 737c4eda5b7SDavid Gibson name = spapr_vio_get_dev_name(DEVICE(dev)); 73868f3a94cSDavid Gibson 73916951843SDaniel Henrique Barboza return g_strdup_printf("/vdevice/%s", name); 74068f3a94cSDavid Gibson } 741