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