]> git.proxmox.com Git - mirror_qemu.git/blame - hw/virtio/vhost-vsock-common.c
hw/virtio: move vhd->started check into helper and add FIXME
[mirror_qemu.git] / hw / virtio / vhost-vsock-common.c
CommitLineData
c6136ec0
SG
1/*
2 * Parent class for vhost-vsock devices
3 *
4 * Copyright 2015-2020 Red Hat, Inc.
5 *
6 * This work is licensed under the terms of the GNU GPL, version 2 or
7 * (at your option) any later version. See the COPYING file in the
8 * top-level directory.
9 */
10
11#include "qemu/osdep.h"
12#include "standard-headers/linux/virtio_vsock.h"
13#include "qapi/error.h"
14#include "hw/virtio/virtio-access.h"
15#include "qemu/error-report.h"
16#include "hw/qdev-properties.h"
b8f3e6a1 17#include "hw/virtio/vhost.h"
c6136ec0
SG
18#include "hw/virtio/vhost-vsock.h"
19#include "qemu/iov.h"
20#include "monitor/monitor.h"
21
46ce0171
SG
22const int feature_bits[] = {
23 VIRTIO_VSOCK_F_SEQPACKET,
24 VHOST_INVALID_FEATURE_BIT
25};
26
27uint64_t vhost_vsock_common_get_features(VirtIODevice *vdev, uint64_t features,
28 Error **errp)
29{
30 VHostVSockCommon *vvc = VHOST_VSOCK_COMMON(vdev);
31
32 if (vvc->seqpacket != ON_OFF_AUTO_OFF) {
33 virtio_add_feature(&features, VIRTIO_VSOCK_F_SEQPACKET);
34 }
35
36 features = vhost_get_features(&vvc->vhost_dev, feature_bits, features);
37
38 if (vvc->seqpacket == ON_OFF_AUTO_ON &&
39 !virtio_has_feature(features, VIRTIO_VSOCK_F_SEQPACKET)) {
40 error_setg(errp, "vhost-vsock backend doesn't support seqpacket");
41 }
42
43 return features;
44}
45
c6136ec0
SG
46int vhost_vsock_common_start(VirtIODevice *vdev)
47{
48 VHostVSockCommon *vvc = VHOST_VSOCK_COMMON(vdev);
49 BusState *qbus = BUS(qdev_get_parent_bus(DEVICE(vdev)));
50 VirtioBusClass *k = VIRTIO_BUS_GET_CLASS(qbus);
51 int ret;
52 int i;
53
54 if (!k->set_guest_notifiers) {
55 error_report("binding does not support guest notifiers");
56 return -ENOSYS;
57 }
58
59 ret = vhost_dev_enable_notifiers(&vvc->vhost_dev, vdev);
60 if (ret < 0) {
61 error_report("Error enabling host notifiers: %d", -ret);
62 return ret;
63 }
64
65 ret = k->set_guest_notifiers(qbus->parent, vvc->vhost_dev.nvqs, true);
66 if (ret < 0) {
67 error_report("Error binding guest notifier: %d", -ret);
68 goto err_host_notifiers;
69 }
70
71 vvc->vhost_dev.acked_features = vdev->guest_features;
72 ret = vhost_dev_start(&vvc->vhost_dev, vdev);
73 if (ret < 0) {
74 error_report("Error starting vhost: %d", -ret);
75 goto err_guest_notifiers;
76 }
77
78 /*
79 * guest_notifier_mask/pending not used yet, so just unmask
80 * everything here. virtio-pci will do the right thing by
81 * enabling/disabling irqfd.
82 */
83 for (i = 0; i < vvc->vhost_dev.nvqs; i++) {
84 vhost_virtqueue_mask(&vvc->vhost_dev, vdev, i, false);
85 }
86
87 return 0;
88
89err_guest_notifiers:
90 k->set_guest_notifiers(qbus->parent, vvc->vhost_dev.nvqs, false);
91err_host_notifiers:
92 vhost_dev_disable_notifiers(&vvc->vhost_dev, vdev);
93 return ret;
94}
95
96void vhost_vsock_common_stop(VirtIODevice *vdev)
97{
98 VHostVSockCommon *vvc = VHOST_VSOCK_COMMON(vdev);
99 BusState *qbus = BUS(qdev_get_parent_bus(DEVICE(vdev)));
100 VirtioBusClass *k = VIRTIO_BUS_GET_CLASS(qbus);
101 int ret;
102
103 if (!k->set_guest_notifiers) {
104 return;
105 }
106
107 vhost_dev_stop(&vvc->vhost_dev, vdev);
108
109 ret = k->set_guest_notifiers(qbus->parent, vvc->vhost_dev.nvqs, false);
110 if (ret < 0) {
111 error_report("vhost guest notifier cleanup failed: %d", ret);
112 return;
113 }
114
115 vhost_dev_disable_notifiers(&vvc->vhost_dev, vdev);
116}
117
118
119static void vhost_vsock_common_handle_output(VirtIODevice *vdev, VirtQueue *vq)
120{
121 /* Do nothing */
122}
123
124static void vhost_vsock_common_guest_notifier_mask(VirtIODevice *vdev, int idx,
125 bool mask)
126{
127 VHostVSockCommon *vvc = VHOST_VSOCK_COMMON(vdev);
128
129 vhost_virtqueue_mask(&vvc->vhost_dev, vdev, idx, mask);
130}
131
132static bool vhost_vsock_common_guest_notifier_pending(VirtIODevice *vdev,
133 int idx)
134{
135 VHostVSockCommon *vvc = VHOST_VSOCK_COMMON(vdev);
136
137 return vhost_virtqueue_pending(&vvc->vhost_dev, idx);
138}
139
140static void vhost_vsock_common_send_transport_reset(VHostVSockCommon *vvc)
141{
142 VirtQueueElement *elem;
143 VirtQueue *vq = vvc->event_vq;
144 struct virtio_vsock_event event = {
145 .id = cpu_to_le32(VIRTIO_VSOCK_EVENT_TRANSPORT_RESET),
146 };
147
148 elem = virtqueue_pop(vq, sizeof(VirtQueueElement));
149 if (!elem) {
150 error_report("vhost-vsock missed transport reset event");
151 return;
152 }
153
154 if (elem->out_num) {
155 error_report("invalid vhost-vsock event virtqueue element with "
156 "out buffers");
8d1b247f 157 goto err;
c6136ec0
SG
158 }
159
160 if (iov_from_buf(elem->in_sg, elem->in_num, 0,
161 &event, sizeof(event)) != sizeof(event)) {
162 error_report("vhost-vsock event virtqueue element is too short");
8d1b247f 163 goto err;
c6136ec0
SG
164 }
165
166 virtqueue_push(vq, elem, sizeof(event));
167 virtio_notify(VIRTIO_DEVICE(vvc), vq);
168
8d1b247f
SG
169 g_free(elem);
170 return;
171
172err:
173 virtqueue_detach_element(vq, elem, 0);
c6136ec0
SG
174 g_free(elem);
175}
176
177static void vhost_vsock_common_post_load_timer_cleanup(VHostVSockCommon *vvc)
178{
179 if (!vvc->post_load_timer) {
180 return;
181 }
182
c6136ec0
SG
183 timer_free(vvc->post_load_timer);
184 vvc->post_load_timer = NULL;
185}
186
187static void vhost_vsock_common_post_load_timer_cb(void *opaque)
188{
189 VHostVSockCommon *vvc = opaque;
190
191 vhost_vsock_common_post_load_timer_cleanup(vvc);
192 vhost_vsock_common_send_transport_reset(vvc);
193}
194
195int vhost_vsock_common_pre_save(void *opaque)
196{
197 VHostVSockCommon *vvc = opaque;
198
199 /*
200 * At this point, backend must be stopped, otherwise
201 * it might keep writing to memory.
202 */
b8f3e6a1 203 assert(!vhost_dev_is_started(&vvc->vhost_dev));
c6136ec0
SG
204
205 return 0;
206}
207
208int vhost_vsock_common_post_load(void *opaque, int version_id)
209{
210 VHostVSockCommon *vvc = opaque;
211 VirtIODevice *vdev = VIRTIO_DEVICE(vvc);
212
213 if (virtio_queue_get_addr(vdev, 2)) {
214 /*
215 * Defer transport reset event to a vm clock timer so that virtqueue
216 * changes happen after migration has completed.
217 */
218 assert(!vvc->post_load_timer);
219 vvc->post_load_timer =
220 timer_new_ns(QEMU_CLOCK_VIRTUAL,
221 vhost_vsock_common_post_load_timer_cb,
222 vvc);
223 timer_mod(vvc->post_load_timer, 1);
224 }
225 return 0;
226}
227
3857cd5c 228void vhost_vsock_common_realize(VirtIODevice *vdev)
c6136ec0
SG
229{
230 VHostVSockCommon *vvc = VHOST_VSOCK_COMMON(vdev);
231
3857cd5c 232 virtio_init(vdev, VIRTIO_ID_VSOCK, sizeof(struct virtio_vsock_config));
c6136ec0
SG
233
234 /* Receive and transmit queues belong to vhost */
235 vvc->recv_vq = virtio_add_queue(vdev, VHOST_VSOCK_QUEUE_SIZE,
236 vhost_vsock_common_handle_output);
237 vvc->trans_vq = virtio_add_queue(vdev, VHOST_VSOCK_QUEUE_SIZE,
238 vhost_vsock_common_handle_output);
239
240 /* The event queue belongs to QEMU */
241 vvc->event_vq = virtio_add_queue(vdev, VHOST_VSOCK_QUEUE_SIZE,
242 vhost_vsock_common_handle_output);
243
244 vvc->vhost_dev.nvqs = ARRAY_SIZE(vvc->vhost_vqs);
245 vvc->vhost_dev.vqs = vvc->vhost_vqs;
246
247 vvc->post_load_timer = NULL;
248}
249
250void vhost_vsock_common_unrealize(VirtIODevice *vdev)
251{
252 VHostVSockCommon *vvc = VHOST_VSOCK_COMMON(vdev);
253
254 vhost_vsock_common_post_load_timer_cleanup(vvc);
255
256 virtio_delete_queue(vvc->recv_vq);
257 virtio_delete_queue(vvc->trans_vq);
258 virtio_delete_queue(vvc->event_vq);
259 virtio_cleanup(vdev);
260}
261
c255488d
JP
262static struct vhost_dev *vhost_vsock_common_get_vhost(VirtIODevice *vdev)
263{
264 VHostVSockCommon *vvc = VHOST_VSOCK_COMMON(vdev);
265 return &vvc->vhost_dev;
266}
267
46ce0171
SG
268static Property vhost_vsock_common_properties[] = {
269 DEFINE_PROP_ON_OFF_AUTO("seqpacket", VHostVSockCommon, seqpacket,
270 ON_OFF_AUTO_AUTO),
271 DEFINE_PROP_END_OF_LIST(),
272};
273
c6136ec0
SG
274static void vhost_vsock_common_class_init(ObjectClass *klass, void *data)
275{
276 DeviceClass *dc = DEVICE_CLASS(klass);
277 VirtioDeviceClass *vdc = VIRTIO_DEVICE_CLASS(klass);
278
46ce0171 279 device_class_set_props(dc, vhost_vsock_common_properties);
c6136ec0
SG
280 set_bit(DEVICE_CATEGORY_MISC, dc->categories);
281 vdc->guest_notifier_mask = vhost_vsock_common_guest_notifier_mask;
282 vdc->guest_notifier_pending = vhost_vsock_common_guest_notifier_pending;
c255488d 283 vdc->get_vhost = vhost_vsock_common_get_vhost;
c6136ec0
SG
284}
285
286static const TypeInfo vhost_vsock_common_info = {
287 .name = TYPE_VHOST_VSOCK_COMMON,
288 .parent = TYPE_VIRTIO_DEVICE,
289 .instance_size = sizeof(VHostVSockCommon),
290 .class_init = vhost_vsock_common_class_init,
291 .abstract = true,
292};
293
294static void vhost_vsock_common_register_types(void)
295{
296 type_register_static(&vhost_vsock_common_info);
297}
298
299type_init(vhost_vsock_common_register_types)