xref: /qemu/hw/virtio/virtio-bus.c (revision 33848cee)
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 "hw/hw.h"
27 #include "qemu/error-report.h"
28 #include "hw/qdev.h"
29 #include "hw/virtio/virtio-bus.h"
30 #include "hw/virtio/virtio.h"
31 #include "exec/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 
51     DPRINTF("%s: plug device.\n", qbus->name);
52 
53     if (klass->pre_plugged != NULL) {
54         klass->pre_plugged(qbus->parent, errp);
55     }
56 
57     /* Get the features of the plugged device. */
58     assert(vdc->get_features != NULL);
59     vdev->host_features = vdc->get_features(vdev, vdev->host_features,
60                                             errp);
61 
62     if (klass->device_plugged != NULL) {
63         klass->device_plugged(qbus->parent, errp);
64     }
65 
66     if (klass->get_dma_as != NULL &&
67         virtio_host_has_feature(vdev, VIRTIO_F_IOMMU_PLATFORM)) {
68         vdev->dma_as = klass->get_dma_as(qbus->parent);
69     } else {
70         vdev->dma_as = &address_space_memory;
71     }
72 }
73 
74 /* Reset the virtio_bus */
75 void virtio_bus_reset(VirtioBusState *bus)
76 {
77     VirtIODevice *vdev = virtio_bus_get_device(bus);
78 
79     DPRINTF("%s: reset device.\n", BUS(bus)->name);
80     if (vdev != NULL) {
81         virtio_reset(vdev);
82     }
83 }
84 
85 /* A VirtIODevice is being unplugged */
86 void virtio_bus_device_unplugged(VirtIODevice *vdev)
87 {
88     DeviceState *qdev = DEVICE(vdev);
89     BusState *qbus = BUS(qdev_get_parent_bus(qdev));
90     VirtioBusClass *klass = VIRTIO_BUS_GET_CLASS(qbus);
91 
92     DPRINTF("%s: remove device.\n", qbus->name);
93 
94     if (vdev != NULL) {
95         if (klass->device_unplugged != NULL) {
96             klass->device_unplugged(qbus->parent);
97         }
98     }
99 }
100 
101 /* Get the device id of the plugged device. */
102 uint16_t virtio_bus_get_vdev_id(VirtioBusState *bus)
103 {
104     VirtIODevice *vdev = virtio_bus_get_device(bus);
105     assert(vdev != NULL);
106     return vdev->device_id;
107 }
108 
109 /* Get the config_len field of the plugged device. */
110 size_t virtio_bus_get_vdev_config_len(VirtioBusState *bus)
111 {
112     VirtIODevice *vdev = virtio_bus_get_device(bus);
113     assert(vdev != NULL);
114     return vdev->config_len;
115 }
116 
117 /* Get bad features of the plugged device. */
118 uint32_t virtio_bus_get_vdev_bad_features(VirtioBusState *bus)
119 {
120     VirtIODevice *vdev = virtio_bus_get_device(bus);
121     VirtioDeviceClass *k;
122 
123     assert(vdev != NULL);
124     k = VIRTIO_DEVICE_GET_CLASS(vdev);
125     if (k->bad_features != NULL) {
126         return k->bad_features(vdev);
127     } else {
128         return 0;
129     }
130 }
131 
132 /* Get config of the plugged device. */
133 void virtio_bus_get_vdev_config(VirtioBusState *bus, uint8_t *config)
134 {
135     VirtIODevice *vdev = virtio_bus_get_device(bus);
136     VirtioDeviceClass *k;
137 
138     assert(vdev != NULL);
139     k = VIRTIO_DEVICE_GET_CLASS(vdev);
140     if (k->get_config != NULL) {
141         k->get_config(vdev, config);
142     }
143 }
144 
145 /* Set config of the plugged device. */
146 void virtio_bus_set_vdev_config(VirtioBusState *bus, uint8_t *config)
147 {
148     VirtIODevice *vdev = virtio_bus_get_device(bus);
149     VirtioDeviceClass *k;
150 
151     assert(vdev != NULL);
152     k = VIRTIO_DEVICE_GET_CLASS(vdev);
153     if (k->set_config != NULL) {
154         k->set_config(vdev, config);
155     }
156 }
157 
158 /* On success, ioeventfd ownership belongs to the caller.  */
159 int virtio_bus_grab_ioeventfd(VirtioBusState *bus)
160 {
161     VirtioBusClass *k = VIRTIO_BUS_GET_CLASS(bus);
162 
163     /* vhost can be used even if ioeventfd=off in the proxy device,
164      * so do not check k->ioeventfd_enabled.
165      */
166     if (!k->ioeventfd_assign) {
167         return -ENOSYS;
168     }
169 
170     if (bus->ioeventfd_grabbed == 0 && bus->ioeventfd_started) {
171         virtio_bus_stop_ioeventfd(bus);
172         /* Remember that we need to restart ioeventfd
173          * when ioeventfd_grabbed becomes zero.
174          */
175         bus->ioeventfd_started = true;
176     }
177     bus->ioeventfd_grabbed++;
178     return 0;
179 }
180 
181 void virtio_bus_release_ioeventfd(VirtioBusState *bus)
182 {
183     assert(bus->ioeventfd_grabbed != 0);
184     if (--bus->ioeventfd_grabbed == 0 && bus->ioeventfd_started) {
185         /* Force virtio_bus_start_ioeventfd to act.  */
186         bus->ioeventfd_started = false;
187         virtio_bus_start_ioeventfd(bus);
188     }
189 }
190 
191 int virtio_bus_start_ioeventfd(VirtioBusState *bus)
192 {
193     VirtioBusClass *k = VIRTIO_BUS_GET_CLASS(bus);
194     DeviceState *proxy = DEVICE(BUS(bus)->parent);
195     VirtIODevice *vdev = virtio_bus_get_device(bus);
196     VirtioDeviceClass *vdc = VIRTIO_DEVICE_GET_CLASS(vdev);
197     int r;
198 
199     if (!k->ioeventfd_assign || !k->ioeventfd_enabled(proxy)) {
200         return -ENOSYS;
201     }
202     if (bus->ioeventfd_started) {
203         return 0;
204     }
205 
206     /* Only set our notifier if we have ownership.  */
207     if (!bus->ioeventfd_grabbed) {
208         r = vdc->start_ioeventfd(vdev);
209         if (r < 0) {
210             error_report("%s: failed. Fallback to userspace (slower).", __func__);
211             return r;
212         }
213     }
214     bus->ioeventfd_started = true;
215     return 0;
216 }
217 
218 void virtio_bus_stop_ioeventfd(VirtioBusState *bus)
219 {
220     VirtIODevice *vdev;
221     VirtioDeviceClass *vdc;
222 
223     if (!bus->ioeventfd_started) {
224         return;
225     }
226 
227     /* Only remove our notifier if we have ownership.  */
228     if (!bus->ioeventfd_grabbed) {
229         vdev = virtio_bus_get_device(bus);
230         vdc = VIRTIO_DEVICE_GET_CLASS(vdev);
231         vdc->stop_ioeventfd(vdev);
232     }
233     bus->ioeventfd_started = false;
234 }
235 
236 bool virtio_bus_ioeventfd_enabled(VirtioBusState *bus)
237 {
238     VirtioBusClass *k = VIRTIO_BUS_GET_CLASS(bus);
239     DeviceState *proxy = DEVICE(BUS(bus)->parent);
240 
241     return k->ioeventfd_assign && k->ioeventfd_enabled(proxy);
242 }
243 
244 /*
245  * This function switches ioeventfd on/off in the device.
246  * The caller must set or clear the handlers for the EventNotifier.
247  */
248 int virtio_bus_set_host_notifier(VirtioBusState *bus, int n, bool assign)
249 {
250     VirtIODevice *vdev = virtio_bus_get_device(bus);
251     VirtioBusClass *k = VIRTIO_BUS_GET_CLASS(bus);
252     DeviceState *proxy = DEVICE(BUS(bus)->parent);
253     VirtQueue *vq = virtio_get_queue(vdev, n);
254     EventNotifier *notifier = virtio_queue_get_host_notifier(vq);
255     int r = 0;
256 
257     if (!k->ioeventfd_assign) {
258         return -ENOSYS;
259     }
260 
261     if (assign) {
262         r = event_notifier_init(notifier, 1);
263         if (r < 0) {
264             error_report("%s: unable to init event notifier: %s (%d)",
265                          __func__, strerror(-r), r);
266             return r;
267         }
268         r = k->ioeventfd_assign(proxy, notifier, n, true);
269         if (r < 0) {
270             error_report("%s: unable to assign ioeventfd: %d", __func__, r);
271             goto cleanup_event_notifier;
272         }
273         return 0;
274     } else {
275         k->ioeventfd_assign(proxy, notifier, n, false);
276     }
277 
278 cleanup_event_notifier:
279     /* Test and clear notifier after disabling event,
280      * in case poll callback didn't have time to run.
281      */
282     virtio_queue_host_notifier_read(notifier);
283     event_notifier_cleanup(notifier);
284     return r;
285 }
286 
287 static char *virtio_bus_get_dev_path(DeviceState *dev)
288 {
289     BusState *bus = qdev_get_parent_bus(dev);
290     DeviceState *proxy = DEVICE(bus->parent);
291     return qdev_get_dev_path(proxy);
292 }
293 
294 static char *virtio_bus_get_fw_dev_path(DeviceState *dev)
295 {
296     return NULL;
297 }
298 
299 static void virtio_bus_class_init(ObjectClass *klass, void *data)
300 {
301     BusClass *bus_class = BUS_CLASS(klass);
302     bus_class->get_dev_path = virtio_bus_get_dev_path;
303     bus_class->get_fw_dev_path = virtio_bus_get_fw_dev_path;
304 }
305 
306 static const TypeInfo virtio_bus_info = {
307     .name = TYPE_VIRTIO_BUS,
308     .parent = TYPE_BUS,
309     .instance_size = sizeof(VirtioBusState),
310     .abstract = true,
311     .class_size = sizeof(VirtioBusClass),
312     .class_init = virtio_bus_class_init
313 };
314 
315 static void virtio_register_types(void)
316 {
317     type_register_static(&virtio_bus_info);
318 }
319 
320 type_init(virtio_register_types)
321