]> git.proxmox.com Git - qemu.git/blame - hw/spapr_vio.c
Implement the bus structure for PAPR virtual IO
[qemu.git] / hw / spapr_vio.c
CommitLineData
4040ab72
DG
1/*
2 * QEMU sPAPR VIO code
3 *
4 * Copyright (c) 2010 David Gibson, IBM Corporation <dwg@au1.ibm.com>
5 * Based on the s390 virtio bus code:
6 * Copyright (c) 2009 Alexander Graf <agraf@suse.de>
7 *
8 * This library is free software; you can redistribute it and/or
9 * modify it under the terms of the GNU Lesser General Public
10 * License as published by the Free Software Foundation; either
11 * version 2 of the License, or (at your option) any later version.
12 *
13 * This library is distributed in the hope that it will be useful,
14 * but WITHOUT ANY WARRANTY; without even the implied warranty of
15 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
16 * Lesser General Public License for more details.
17 *
18 * You should have received a copy of the GNU Lesser General Public
19 * License along with this library; if not, see <http://www.gnu.org/licenses/>.
20 */
21
22#include "hw.h"
23#include "sysemu.h"
24#include "boards.h"
25#include "monitor.h"
26#include "loader.h"
27#include "elf.h"
28#include "hw/sysbus.h"
29#include "kvm.h"
30#include "device_tree.h"
31
32#include "hw/spapr.h"
33#include "hw/spapr_vio.h"
34
35#ifdef CONFIG_FDT
36#include <libfdt.h>
37#endif /* CONFIG_FDT */
38
39/* #define DEBUG_SPAPR */
40
41#ifdef DEBUG_SPAPR
42#define dprintf(fmt, ...) \
43 do { fprintf(stderr, fmt, ## __VA_ARGS__); } while (0)
44#else
45#define dprintf(fmt, ...) \
46 do { } while (0)
47#endif
48
49static struct BusInfo spapr_vio_bus_info = {
50 .name = "spapr-vio",
51 .size = sizeof(VIOsPAPRBus),
52};
53
54VIOsPAPRDevice *spapr_vio_find_by_reg(VIOsPAPRBus *bus, uint32_t reg)
55{
56 DeviceState *qdev;
57 VIOsPAPRDevice *dev = NULL;
58
59 QLIST_FOREACH(qdev, &bus->bus.children, sibling) {
60 dev = (VIOsPAPRDevice *)qdev;
61 if (dev->reg == reg) {
62 break;
63 }
64 }
65
66 return dev;
67}
68
69#ifdef CONFIG_FDT
70static int vio_make_devnode(VIOsPAPRDevice *dev,
71 void *fdt)
72{
73 VIOsPAPRDeviceInfo *info = (VIOsPAPRDeviceInfo *)dev->qdev.info;
74 int vdevice_off, node_off;
75 int ret;
76
77 vdevice_off = fdt_path_offset(fdt, "/vdevice");
78 if (vdevice_off < 0) {
79 return vdevice_off;
80 }
81
82 node_off = fdt_add_subnode(fdt, vdevice_off, dev->qdev.id);
83 if (node_off < 0) {
84 return node_off;
85 }
86
87 ret = fdt_setprop_cell(fdt, node_off, "reg", dev->reg);
88 if (ret < 0) {
89 return ret;
90 }
91
92 if (info->dt_type) {
93 ret = fdt_setprop_string(fdt, node_off, "device_type",
94 info->dt_type);
95 if (ret < 0) {
96 return ret;
97 }
98 }
99
100 if (info->dt_compatible) {
101 ret = fdt_setprop_string(fdt, node_off, "compatible",
102 info->dt_compatible);
103 if (ret < 0) {
104 return ret;
105 }
106 }
107
108 if (info->devnode) {
109 ret = (info->devnode)(dev, fdt, node_off);
110 if (ret < 0) {
111 return ret;
112 }
113 }
114
115 return node_off;
116}
117#endif /* CONFIG_FDT */
118
119static int spapr_vio_busdev_init(DeviceState *qdev, DeviceInfo *qinfo)
120{
121 VIOsPAPRDeviceInfo *info = (VIOsPAPRDeviceInfo *)qinfo;
122 VIOsPAPRDevice *dev = (VIOsPAPRDevice *)qdev;
123 char *id;
124
125 if (asprintf(&id, "%s@%x", info->dt_name, dev->reg) < 0) {
126 return -1;
127 }
128
129 dev->qdev.id = id;
130
131 return info->init(dev);
132}
133
134void spapr_vio_bus_register_withprop(VIOsPAPRDeviceInfo *info)
135{
136 info->qdev.init = spapr_vio_busdev_init;
137 info->qdev.bus_info = &spapr_vio_bus_info;
138
139 assert(info->qdev.size >= sizeof(VIOsPAPRDevice));
140 qdev_register(&info->qdev);
141}
142
143VIOsPAPRBus *spapr_vio_bus_init(void)
144{
145 VIOsPAPRBus *bus;
146 BusState *qbus;
147 DeviceState *dev;
148 DeviceInfo *qinfo;
149
150 /* Create bridge device */
151 dev = qdev_create(NULL, "spapr-vio-bridge");
152 qdev_init_nofail(dev);
153
154 /* Create bus on bridge device */
155
156 qbus = qbus_create(&spapr_vio_bus_info, dev, "spapr-vio");
157 bus = DO_UPCAST(VIOsPAPRBus, bus, qbus);
158
159 for (qinfo = device_info_list; qinfo; qinfo = qinfo->next) {
160 VIOsPAPRDeviceInfo *info = (VIOsPAPRDeviceInfo *)qinfo;
161
162 if (qinfo->bus_info != &spapr_vio_bus_info) {
163 continue;
164 }
165
166 if (info->hcalls) {
167 info->hcalls(bus);
168 }
169 }
170
171 return bus;
172}
173
174/* Represents sPAPR hcall VIO devices */
175
176static int spapr_vio_bridge_init(SysBusDevice *dev)
177{
178 /* nothing */
179 return 0;
180}
181
182static SysBusDeviceInfo spapr_vio_bridge_info = {
183 .init = spapr_vio_bridge_init,
184 .qdev.name = "spapr-vio-bridge",
185 .qdev.size = sizeof(SysBusDevice),
186 .qdev.no_user = 1,
187};
188
189static void spapr_vio_register_devices(void)
190{
191 sysbus_register_withprop(&spapr_vio_bridge_info);
192}
193
194device_init(spapr_vio_register_devices)
195
196#ifdef CONFIG_FDT
197int spapr_populate_vdevice(VIOsPAPRBus *bus, void *fdt)
198{
199 DeviceState *qdev;
200 int ret = 0;
201
202 QLIST_FOREACH(qdev, &bus->bus.children, sibling) {
203 VIOsPAPRDevice *dev = (VIOsPAPRDevice *)qdev;
204
205 ret = vio_make_devnode(dev, fdt);
206
207 if (ret < 0) {
208 return ret;
209 }
210 }
211
212 return 0;
213}
214#endif /* CONFIG_FDT */