master
c 375 lines 10.5 KB
Raw
1 /*
2 * VirtioBus
3 *
4 * Copyright (C) 2012 : GreenSocs Ltd
5 * http://www.greensocs.com/ , email: info@greensocs.com
6 *
7 * Developed by :
8 * Frederic Konrad <fred.konrad@greensocs.com>
9 *
10 * This program is free software; you can redistribute it and/or modify
11 * it under the terms of the GNU General Public License as published by
12 * the Free Software Foundation, either version 2 of the License, or
13 * (at your option) any later version.
14 *
15 * This program is distributed in the hope that it will be useful,
16 * but WITHOUT ANY WARRANTY; without even the implied warranty of
17 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
18 * GNU General Public License for more details.
19 *
20 * You should have received a copy of the GNU General Public License along
21 * with this program; if not, see <http://www.gnu.org/licenses/>.
22 *
23 */
24
25 #include "qemu/osdep.h"
26 #include "qemu/error-report.h"
27 #include "qemu/module.h"
28 #include "qapi/error.h"
29 #include "hw/virtio/virtio-bus.h"
30 #include "hw/virtio/virtio.h"
31 #include "system/address-spaces.h"
32
33 /* #define DEBUG_VIRTIO_BUS */
34
35 #ifdef DEBUG_VIRTIO_BUS
36 #define DPRINTF(fmt, ...) \
37 do { printf("virtio_bus: " fmt , ## __VA_ARGS__); } while (0)
38 #else
39 #define DPRINTF(fmt, ...) do { } while (0)
40 #endif
41
42 /* A VirtIODevice is being plugged */
43 void virtio_bus_device_plugged(VirtIODevice *vdev, Error **errp)
44 {
45 DeviceState *qdev = DEVICE(vdev);
46 BusState *qbus = BUS(qdev_get_parent_bus(qdev));
47 VirtioBusState *bus = VIRTIO_BUS(qbus);
48 VirtioBusClass *klass = VIRTIO_BUS_GET_CLASS(bus);
49 VirtioDeviceClass *vdc = VIRTIO_DEVICE_GET_CLASS(vdev);
50 bool has_iommu = virtio_host_has_feature(vdev, VIRTIO_F_IOMMU_PLATFORM);
51 bool vdev_has_iommu;
52 Error *local_err = NULL;
53
54 DPRINTF("%s: plug device.\n", qbus->name);
55
56 if (klass->pre_plugged != NULL) {
57 klass->pre_plugged(qbus->parent, &local_err);
58 if (local_err) {
59 error_propagate(errp, local_err);
60 return;
61 }
62 }
63
64 /* Get the features of the plugged device. */
65 if (vdc->get_features_ex) {
66 vdc->get_features_ex(vdev, vdev->host_features_ex, &local_err);
67 } else {
68 assert(vdc->get_features != NULL);
69 virtio_features_from_u64(vdev->host_features_ex,
70 vdc->get_features(vdev, vdev->host_features,
71 &local_err));
72 }
73 if (local_err) {
74 error_propagate(errp, local_err);
75 return;
76 }
77
78 if (klass->device_plugged != NULL) {
79 klass->device_plugged(qbus->parent, &local_err);
80 }
81 if (local_err) {
82 error_propagate(errp, local_err);
83 return;
84 }
85
86 vdev->dma_as = &address_space_memory;
87 if (has_iommu) {
88 vdev_has_iommu = virtio_host_has_feature(vdev, VIRTIO_F_IOMMU_PLATFORM);
89 /*
90 * Present IOMMU_PLATFORM to the driver iff iommu_plattform=on and
91 * device operational. If the driver does not accept IOMMU_PLATFORM
92 * we fail the device.
93 */
94 virtio_add_feature(&vdev->host_features, VIRTIO_F_IOMMU_PLATFORM);
95 if (klass->get_dma_as) {
96 vdev->dma_as = klass->get_dma_as(qbus->parent);
97 if (!vdev_has_iommu && vdev->dma_as != &address_space_memory) {
98 error_setg(errp,
99 "iommu_platform=true is not supported by the device");
100 return;
101 }
102 }
103 }
104 }
105
106 /* Reset the virtio_bus */
107 void virtio_bus_reset(VirtioBusState *bus)
108 {
109 VirtIODevice *vdev = virtio_bus_get_device(bus);
110
111 DPRINTF("%s: reset device.\n", BUS(bus)->name);
112 virtio_bus_stop_ioeventfd(bus);
113 if (vdev != NULL) {
114 virtio_reset(vdev);
115 }
116 }
117
118 /* A VirtIODevice is being unplugged */
119 void virtio_bus_device_unplugged(VirtIODevice *vdev)
120 {
121 DeviceState *qdev = DEVICE(vdev);
122 BusState *qbus = BUS(qdev_get_parent_bus(qdev));
123 VirtioBusClass *klass = VIRTIO_BUS_GET_CLASS(qbus);
124
125 DPRINTF("%s: remove device.\n", qbus->name);
126
127 if (vdev != NULL) {
128 if (klass->device_unplugged != NULL) {
129 klass->device_unplugged(qbus->parent);
130 }
131 }
132 }
133
134 /* Get the device id of the plugged device. */
135 uint16_t virtio_bus_get_vdev_id(VirtioBusState *bus)
136 {
137 VirtIODevice *vdev = virtio_bus_get_device(bus);
138 assert(vdev != NULL);
139 return vdev->device_id;
140 }
141
142 /* Get the config_len field of the plugged device. */
143 size_t virtio_bus_get_vdev_config_len(VirtioBusState *bus)
144 {
145 VirtIODevice *vdev = virtio_bus_get_device(bus);
146 assert(vdev != NULL);
147 return vdev->config_len;
148 }
149
150 /* Get bad features of the plugged device. */
151 uint32_t virtio_bus_get_vdev_bad_features(VirtioBusState *bus)
152 {
153 VirtIODevice *vdev = virtio_bus_get_device(bus);
154 VirtioDeviceClass *k;
155
156 assert(vdev != NULL);
157 k = VIRTIO_DEVICE_GET_CLASS(vdev);
158 if (k->bad_features != NULL) {
159 return k->bad_features(vdev);
160 } else {
161 return 0;
162 }
163 }
164
165 /* Get config of the plugged device. */
166 void virtio_bus_get_vdev_config(VirtioBusState *bus, uint8_t *config)
167 {
168 VirtIODevice *vdev = virtio_bus_get_device(bus);
169 VirtioDeviceClass *k;
170
171 assert(vdev != NULL);
172 k = VIRTIO_DEVICE_GET_CLASS(vdev);
173 if (k->get_config != NULL) {
174 k->get_config(vdev, config);
175 }
176 }
177
178 /* Set config of the plugged device. */
179 void virtio_bus_set_vdev_config(VirtioBusState *bus, uint8_t *config)
180 {
181 VirtIODevice *vdev = virtio_bus_get_device(bus);
182 VirtioDeviceClass *k;
183
184 assert(vdev != NULL);
185 k = VIRTIO_DEVICE_GET_CLASS(vdev);
186 if (k->set_config != NULL) {
187 k->set_config(vdev, config);
188 }
189 }
190
191 /* On success, ioeventfd ownership belongs to the caller. */
192 int virtio_bus_grab_ioeventfd(VirtioBusState *bus)
193 {
194 VirtioBusClass *k = VIRTIO_BUS_GET_CLASS(bus);
195
196 /* vhost can be used even if ioeventfd=off in the proxy device,
197 * so do not check k->ioeventfd_enabled.
198 */
199 if (!k->ioeventfd_assign) {
200 return -ENOSYS;
201 }
202
203 if (bus->ioeventfd_grabbed == 0 && bus->ioeventfd_started) {
204 virtio_bus_stop_ioeventfd(bus);
205 /* Remember that we need to restart ioeventfd
206 * when ioeventfd_grabbed becomes zero.
207 */
208 bus->ioeventfd_started = true;
209 }
210 bus->ioeventfd_grabbed++;
211 return 0;
212 }
213
214 void virtio_bus_release_ioeventfd(VirtioBusState *bus)
215 {
216 assert(bus->ioeventfd_grabbed != 0);
217 if (--bus->ioeventfd_grabbed == 0 && bus->ioeventfd_started) {
218 /* Force virtio_bus_start_ioeventfd to act. */
219 bus->ioeventfd_started = false;
220 virtio_bus_start_ioeventfd(bus);
221 }
222 }
223
224 int virtio_bus_start_ioeventfd(VirtioBusState *bus)
225 {
226 VirtioBusClass *k = VIRTIO_BUS_GET_CLASS(bus);
227 DeviceState *proxy = DEVICE(BUS(bus)->parent);
228 VirtIODevice *vdev = virtio_bus_get_device(bus);
229 VirtioDeviceClass *vdc = VIRTIO_DEVICE_GET_CLASS(vdev);
230 int r;
231
232 if (!k->ioeventfd_assign || !k->ioeventfd_enabled(proxy)) {
233 return -ENOSYS;
234 }
235 if (bus->ioeventfd_started) {
236 return 0;
237 }
238
239 /* Only set our notifier if we have ownership. */
240 if (!bus->ioeventfd_grabbed) {
241 r = vdc->start_ioeventfd(vdev);
242 if (r < 0) {
243 error_report("%s: failed. Fallback to userspace (slower).", __func__);
244 return r;
245 }
246 }
247 bus->ioeventfd_started = true;
248 return 0;
249 }
250
251 void virtio_bus_stop_ioeventfd(VirtioBusState *bus)
252 {
253 VirtIODevice *vdev;
254 VirtioDeviceClass *vdc;
255
256 if (!bus->ioeventfd_started) {
257 return;
258 }
259
260 /* Only remove our notifier if we have ownership. */
261 if (!bus->ioeventfd_grabbed) {
262 vdev = virtio_bus_get_device(bus);
263 vdc = VIRTIO_DEVICE_GET_CLASS(vdev);
264 vdc->stop_ioeventfd(vdev);
265 }
266 bus->ioeventfd_started = false;
267 }
268
269 bool virtio_bus_ioeventfd_enabled(VirtioBusState *bus)
270 {
271 VirtioBusClass *k = VIRTIO_BUS_GET_CLASS(bus);
272 DeviceState *proxy = DEVICE(BUS(bus)->parent);
273
274 return k->ioeventfd_assign && k->ioeventfd_enabled(proxy);
275 }
276
277 /*
278 * This function switches ioeventfd on/off in the device.
279 * The caller must set or clear the handlers for the EventNotifier.
280 */
281 int virtio_bus_set_host_notifier(VirtioBusState *bus, int n, bool assign)
282 {
283 VirtIODevice *vdev = virtio_bus_get_device(bus);
284 VirtioBusClass *k = VIRTIO_BUS_GET_CLASS(bus);
285 DeviceState *proxy = DEVICE(BUS(bus)->parent);
286 VirtQueue *vq = virtio_get_queue(vdev, n);
287 EventNotifier *notifier = virtio_queue_get_host_notifier(vq);
288 int r = 0;
289
290 if (!k->ioeventfd_assign) {
291 return -ENOSYS;
292 }
293
294 if (assign) {
295 r = event_notifier_init(notifier, 1);
296 if (r < 0) {
297 error_report("%s: unable to init event notifier: %s (%d)",
298 __func__, strerror(-r), r);
299 return r;
300 }
301 }
302
303 r = k->ioeventfd_assign(proxy, notifier, n, assign);
304 if (r < 0 && assign) {
305 error_report("%s: unable to assign ioeventfd: %d", __func__, r);
306 virtio_bus_cleanup_host_notifier(bus, n);
307 return r;
308 }
309
310 virtio_queue_set_host_notifier_enabled(vq, assign);
311
312 return 0;
313 }
314
315 void virtio_bus_cleanup_host_notifier(VirtioBusState *bus, int n)
316 {
317 VirtIODevice *vdev = virtio_bus_get_device(bus);
318 VirtQueue *vq = virtio_get_queue(vdev, n);
319 EventNotifier *notifier = virtio_queue_get_host_notifier(vq);
320
321 /* Test and clear notifier after disabling event,
322 * in case poll callback didn't have time to run.
323 */
324 virtio_queue_host_notifier_read(notifier);
325 event_notifier_cleanup(notifier);
326 }
327
328 static char *virtio_bus_get_dev_path(DeviceState *dev)
329 {
330 BusState *bus = qdev_get_parent_bus(dev);
331 DeviceState *proxy = DEVICE(bus->parent);
332 return qdev_get_dev_path(proxy);
333 }
334
335 static char *virtio_bus_get_fw_dev_path(DeviceState *dev)
336 {
337 return NULL;
338 }
339
340 bool virtio_bus_device_iommu_enabled(VirtIODevice *vdev)
341 {
342 DeviceState *qdev = DEVICE(vdev);
343 BusState *qbus = BUS(qdev_get_parent_bus(qdev));
344 VirtioBusState *bus = VIRTIO_BUS(qbus);
345 VirtioBusClass *klass = VIRTIO_BUS_GET_CLASS(bus);
346
347 if (!klass->iommu_enabled) {
348 return false;
349 }
350
351 return klass->iommu_enabled(qbus->parent);
352 }
353
354 static void virtio_bus_class_init(ObjectClass *klass, const void *data)
355 {
356 BusClass *bus_class = BUS_CLASS(klass);
357 bus_class->get_dev_path = virtio_bus_get_dev_path;
358 bus_class->get_fw_dev_path = virtio_bus_get_fw_dev_path;
359 }
360
361 static const TypeInfo virtio_bus_info = {
362 .name = TYPE_VIRTIO_BUS,
363 .parent = TYPE_BUS,
364 .instance_size = sizeof(VirtioBusState),
365 .abstract = true,
366 .class_size = sizeof(VirtioBusClass),
367 .class_init = virtio_bus_class_init
368 };
369
370 static void virtio_register_types(void)
371 {
372 type_register_static(&virtio_bus_info);
373 }
374
375 type_init(virtio_register_types)