Branch data Line data Source code
1 : : /* SPDX-License-Identifier: BSD-3-Clause
2 : : * Copyright(c) 2020 Red Hat Inc.
3 : : */
4 : :
5 : : #include <sys/ioctl.h>
6 : : #include <sys/types.h>
7 : : #include <sys/stat.h>
8 : : #include <fcntl.h>
9 : : #include <stdlib.h>
10 : : #include <unistd.h>
11 : :
12 : : #include <rte_memory.h>
13 : :
14 : : #include "vhost.h"
15 : : #include "virtio_user_dev.h"
16 : :
17 : : struct vhost_vdpa_data {
18 : : int vhostfd;
19 : : uint64_t protocol_features;
20 : : };
21 : :
22 : : #define VHOST_VDPA_SUPPORTED_BACKEND_FEATURES \
23 : : (1ULL << VHOST_BACKEND_F_IOTLB_MSG_V2 | \
24 : : 1ULL << VHOST_BACKEND_F_IOTLB_BATCH)
25 : :
26 : : /* vhost kernel & vdpa ioctls */
27 : : #define VHOST_VIRTIO 0xAF
28 : : #define VHOST_GET_FEATURES _IOR(VHOST_VIRTIO, 0x00, __u64)
29 : : #define VHOST_SET_FEATURES _IOW(VHOST_VIRTIO, 0x00, __u64)
30 : : #define VHOST_SET_OWNER _IO(VHOST_VIRTIO, 0x01)
31 : : #define VHOST_RESET_OWNER _IO(VHOST_VIRTIO, 0x02)
32 : : #define VHOST_SET_LOG_BASE _IOW(VHOST_VIRTIO, 0x04, __u64)
33 : : #define VHOST_SET_LOG_FD _IOW(VHOST_VIRTIO, 0x07, int)
34 : : #define VHOST_SET_VRING_NUM _IOW(VHOST_VIRTIO, 0x10, struct vhost_vring_state)
35 : : #define VHOST_SET_VRING_ADDR _IOW(VHOST_VIRTIO, 0x11, struct vhost_vring_addr)
36 : : #define VHOST_SET_VRING_BASE _IOW(VHOST_VIRTIO, 0x12, struct vhost_vring_state)
37 : : #define VHOST_GET_VRING_BASE _IOWR(VHOST_VIRTIO, 0x12, struct vhost_vring_state)
38 : : #define VHOST_SET_VRING_KICK _IOW(VHOST_VIRTIO, 0x20, struct vhost_vring_file)
39 : : #define VHOST_SET_VRING_CALL _IOW(VHOST_VIRTIO, 0x21, struct vhost_vring_file)
40 : : #define VHOST_SET_VRING_ERR _IOW(VHOST_VIRTIO, 0x22, struct vhost_vring_file)
41 : : #define VHOST_NET_SET_BACKEND _IOW(VHOST_VIRTIO, 0x30, struct vhost_vring_file)
42 : : #define VHOST_VDPA_GET_DEVICE_ID _IOR(VHOST_VIRTIO, 0x70, __u32)
43 : : #define VHOST_VDPA_GET_STATUS _IOR(VHOST_VIRTIO, 0x71, __u8)
44 : : #define VHOST_VDPA_SET_STATUS _IOW(VHOST_VIRTIO, 0x72, __u8)
45 : : #define VHOST_VDPA_GET_CONFIG _IOR(VHOST_VIRTIO, 0x73, struct vhost_vdpa_config)
46 : : #define VHOST_VDPA_SET_CONFIG _IOW(VHOST_VIRTIO, 0x74, struct vhost_vdpa_config)
47 : : #define VHOST_VDPA_SET_VRING_ENABLE _IOW(VHOST_VIRTIO, 0x75, struct vhost_vring_state)
48 : : #define VHOST_SET_BACKEND_FEATURES _IOW(VHOST_VIRTIO, 0x25, __u64)
49 : : #define VHOST_GET_BACKEND_FEATURES _IOR(VHOST_VIRTIO, 0x26, __u64)
50 : :
51 : : /* no alignment requirement */
52 : : struct vhost_iotlb_msg {
53 : : uint64_t iova;
54 : : uint64_t size;
55 : : uint64_t uaddr;
56 : : #define VHOST_ACCESS_RO 0x1
57 : : #define VHOST_ACCESS_WO 0x2
58 : : #define VHOST_ACCESS_RW 0x3
59 : : uint8_t perm;
60 : : #define VHOST_IOTLB_MISS 1
61 : : #define VHOST_IOTLB_UPDATE 2
62 : : #define VHOST_IOTLB_INVALIDATE 3
63 : : #define VHOST_IOTLB_ACCESS_FAIL 4
64 : : #define VHOST_IOTLB_BATCH_BEGIN 5
65 : : #define VHOST_IOTLB_BATCH_END 6
66 : : uint8_t type;
67 : : };
68 : :
69 : : #define VHOST_IOTLB_MSG_V2 0x2
70 : :
71 : : struct vhost_vdpa_config {
72 : : uint32_t off;
73 : : uint32_t len;
74 : : uint8_t buf[];
75 : : };
76 : :
77 : : struct vhost_msg {
78 : : uint32_t type;
79 : : uint32_t reserved;
80 : : union {
81 : : struct vhost_iotlb_msg iotlb;
82 : : uint8_t padding[64];
83 : : };
84 : : };
85 : :
86 : :
87 : : static int
88 : 0 : vhost_vdpa_ioctl(int fd, uint64_t request, void *arg)
89 : : {
90 : : int ret;
91 : :
92 : 0 : ret = ioctl(fd, request, arg);
93 [ # # ]: 0 : if (ret) {
94 : 0 : PMD_DRV_LOG(ERR, "Vhost-vDPA ioctl %"PRIu64" failed (%s)",
95 : : request, strerror(errno));
96 : 0 : return -1;
97 : : }
98 : :
99 : : return 0;
100 : : }
101 : :
102 : : static int
103 : 0 : vhost_vdpa_set_owner(struct virtio_user_dev *dev)
104 : : {
105 : 0 : struct vhost_vdpa_data *data = dev->backend_data;
106 : :
107 : 0 : return vhost_vdpa_ioctl(data->vhostfd, VHOST_SET_OWNER, NULL);
108 : : }
109 : :
110 : : static int
111 : : vhost_vdpa_get_protocol_features(struct virtio_user_dev *dev, uint64_t *features)
112 : : {
113 : 0 : struct vhost_vdpa_data *data = dev->backend_data;
114 : :
115 : 0 : return vhost_vdpa_ioctl(data->vhostfd, VHOST_GET_BACKEND_FEATURES, features);
116 : : }
117 : :
118 : : static int
119 : : vhost_vdpa_set_protocol_features(struct virtio_user_dev *dev, uint64_t features)
120 : : {
121 : 0 : struct vhost_vdpa_data *data = dev->backend_data;
122 : :
123 : 0 : return vhost_vdpa_ioctl(data->vhostfd, VHOST_SET_BACKEND_FEATURES, &features);
124 : : }
125 : :
126 : : static int
127 : 0 : vhost_vdpa_get_features(struct virtio_user_dev *dev, uint64_t *features)
128 : : {
129 : 0 : struct vhost_vdpa_data *data = dev->backend_data;
130 : : int ret;
131 : :
132 : 0 : ret = vhost_vdpa_ioctl(data->vhostfd, VHOST_GET_FEATURES, features);
133 [ # # ]: 0 : if (ret) {
134 : 0 : PMD_DRV_LOG(ERR, "Failed to get features");
135 : 0 : return -1;
136 : : }
137 : :
138 [ # # ]: 0 : if (*features & 1ULL << VIRTIO_NET_F_CTRL_VQ)
139 : 0 : dev->hw_cvq = true;
140 : :
141 : : /* Negotiated vDPA backend features */
142 : 0 : ret = vhost_vdpa_get_protocol_features(dev, &data->protocol_features);
143 [ # # ]: 0 : if (ret < 0) {
144 : 0 : PMD_DRV_LOG(ERR, "Failed to get backend features");
145 : 0 : return -1;
146 : : }
147 : :
148 : 0 : data->protocol_features &= VHOST_VDPA_SUPPORTED_BACKEND_FEATURES;
149 : :
150 : 0 : ret = vhost_vdpa_set_protocol_features(dev, data->protocol_features);
151 [ # # ]: 0 : if (ret < 0) {
152 : 0 : PMD_DRV_LOG(ERR, "Failed to set backend features");
153 : 0 : return -1;
154 : : }
155 : :
156 : : return 0;
157 : : }
158 : :
159 : : static int
160 : 0 : vhost_vdpa_set_features(struct virtio_user_dev *dev, uint64_t features)
161 : : {
162 : 0 : struct vhost_vdpa_data *data = dev->backend_data;
163 : :
164 : : /* WORKAROUND */
165 : 0 : features |= 1ULL << VIRTIO_F_IOMMU_PLATFORM;
166 : :
167 : 0 : return vhost_vdpa_ioctl(data->vhostfd, VHOST_SET_FEATURES, &features);
168 : : }
169 : :
170 : : static int
171 : 0 : vhost_vdpa_iotlb_batch_begin(struct virtio_user_dev *dev)
172 : : {
173 : 0 : struct vhost_vdpa_data *data = dev->backend_data;
174 : 0 : struct vhost_msg msg = {};
175 : :
176 [ # # ]: 0 : if (!(data->protocol_features & (1ULL << VHOST_BACKEND_F_IOTLB_BATCH)))
177 : : return 0;
178 : :
179 [ # # ]: 0 : if (!(data->protocol_features & (1ULL << VHOST_BACKEND_F_IOTLB_MSG_V2))) {
180 : 0 : PMD_DRV_LOG(ERR, "IOTLB_MSG_V2 not supported by the backend.");
181 : 0 : return -1;
182 : : }
183 : :
184 : 0 : msg.type = VHOST_IOTLB_MSG_V2;
185 : 0 : msg.iotlb.type = VHOST_IOTLB_BATCH_BEGIN;
186 : :
187 [ # # ]: 0 : if (write(data->vhostfd, &msg, sizeof(msg)) != sizeof(msg)) {
188 : 0 : PMD_DRV_LOG(ERR, "Failed to send IOTLB batch begin (%s)",
189 : : strerror(errno));
190 : 0 : return -1;
191 : : }
192 : :
193 : : return 0;
194 : : }
195 : :
196 : : static int
197 : 0 : vhost_vdpa_iotlb_batch_end(struct virtio_user_dev *dev)
198 : : {
199 : 0 : struct vhost_vdpa_data *data = dev->backend_data;
200 : 0 : struct vhost_msg msg = {};
201 : :
202 [ # # ]: 0 : if (!(data->protocol_features & (1ULL << VHOST_BACKEND_F_IOTLB_BATCH)))
203 : : return 0;
204 : :
205 [ # # ]: 0 : if (!(data->protocol_features & (1ULL << VHOST_BACKEND_F_IOTLB_MSG_V2))) {
206 : 0 : PMD_DRV_LOG(ERR, "IOTLB_MSG_V2 not supported by the backend.");
207 : 0 : return -1;
208 : : }
209 : :
210 : 0 : msg.type = VHOST_IOTLB_MSG_V2;
211 : 0 : msg.iotlb.type = VHOST_IOTLB_BATCH_END;
212 : :
213 [ # # ]: 0 : if (write(data->vhostfd, &msg, sizeof(msg)) != sizeof(msg)) {
214 : 0 : PMD_DRV_LOG(ERR, "Failed to send IOTLB batch end (%s)",
215 : : strerror(errno));
216 : 0 : return -1;
217 : : }
218 : :
219 : : return 0;
220 : : }
221 : :
222 : : static int
223 : 0 : vhost_vdpa_dma_map(struct virtio_user_dev *dev, void *addr,
224 : : uint64_t iova, size_t len)
225 : : {
226 : 0 : struct vhost_vdpa_data *data = dev->backend_data;
227 : 0 : struct vhost_msg msg = {};
228 : :
229 [ # # ]: 0 : if (!(data->protocol_features & (1ULL << VHOST_BACKEND_F_IOTLB_MSG_V2))) {
230 : 0 : PMD_DRV_LOG(ERR, "IOTLB_MSG_V2 not supported by the backend.");
231 : 0 : return -1;
232 : : }
233 : :
234 : 0 : msg.type = VHOST_IOTLB_MSG_V2;
235 : 0 : msg.iotlb.type = VHOST_IOTLB_UPDATE;
236 : 0 : msg.iotlb.iova = iova;
237 : 0 : msg.iotlb.uaddr = (uint64_t)(uintptr_t)addr;
238 : 0 : msg.iotlb.size = len;
239 : 0 : msg.iotlb.perm = VHOST_ACCESS_RW;
240 : :
241 : 0 : PMD_DRV_LOG(DEBUG, "%s: iova: 0x%" PRIx64 ", addr: %p, len: 0x%zx",
242 : : __func__, iova, addr, len);
243 : :
244 [ # # ]: 0 : if (write(data->vhostfd, &msg, sizeof(msg)) != sizeof(msg)) {
245 : 0 : PMD_DRV_LOG(ERR, "Failed to send IOTLB update (%s)",
246 : : strerror(errno));
247 : 0 : return -1;
248 : : }
249 : :
250 : : return 0;
251 : : }
252 : :
253 : : static int
254 : 0 : vhost_vdpa_dma_unmap(struct virtio_user_dev *dev, __rte_unused void *addr,
255 : : uint64_t iova, size_t len)
256 : : {
257 : 0 : struct vhost_vdpa_data *data = dev->backend_data;
258 : 0 : struct vhost_msg msg = {};
259 : :
260 [ # # ]: 0 : if (!(data->protocol_features & (1ULL << VHOST_BACKEND_F_IOTLB_MSG_V2))) {
261 : 0 : PMD_DRV_LOG(ERR, "IOTLB_MSG_V2 not supported by the backend.");
262 : 0 : return -1;
263 : : }
264 : :
265 : 0 : msg.type = VHOST_IOTLB_MSG_V2;
266 : 0 : msg.iotlb.type = VHOST_IOTLB_INVALIDATE;
267 : 0 : msg.iotlb.iova = iova;
268 : 0 : msg.iotlb.size = len;
269 : :
270 : 0 : PMD_DRV_LOG(DEBUG, "%s: iova: 0x%" PRIx64 ", len: 0x%zx",
271 : : __func__, iova, len);
272 : :
273 [ # # ]: 0 : if (write(data->vhostfd, &msg, sizeof(msg)) != sizeof(msg)) {
274 : 0 : PMD_DRV_LOG(ERR, "Failed to send IOTLB invalidate (%s)",
275 : : strerror(errno));
276 : 0 : return -1;
277 : : }
278 : :
279 : : return 0;
280 : : }
281 : :
282 : : static int
283 : 0 : vhost_vdpa_dma_map_batch(struct virtio_user_dev *dev, void *addr,
284 : : uint64_t iova, size_t len)
285 : : {
286 : : int ret;
287 : :
288 [ # # ]: 0 : if (vhost_vdpa_iotlb_batch_begin(dev) < 0)
289 : : return -1;
290 : :
291 : 0 : ret = vhost_vdpa_dma_map(dev, addr, iova, len);
292 : :
293 [ # # ]: 0 : if (vhost_vdpa_iotlb_batch_end(dev) < 0)
294 : 0 : return -1;
295 : :
296 : : return ret;
297 : : }
298 : :
299 : : static int
300 : 0 : vhost_vdpa_dma_unmap_batch(struct virtio_user_dev *dev, void *addr,
301 : : uint64_t iova, size_t len)
302 : : {
303 : : int ret;
304 : :
305 [ # # ]: 0 : if (vhost_vdpa_iotlb_batch_begin(dev) < 0)
306 : : return -1;
307 : :
308 : 0 : ret = vhost_vdpa_dma_unmap(dev, addr, iova, len);
309 : :
310 [ # # ]: 0 : if (vhost_vdpa_iotlb_batch_end(dev) < 0)
311 : 0 : return -1;
312 : :
313 : : return ret;
314 : : }
315 : :
316 : : static int
317 : 0 : vhost_vdpa_map_contig(const struct rte_memseg_list *msl,
318 : : const struct rte_memseg *ms, size_t len, void *arg)
319 : : {
320 : : struct virtio_user_dev *dev = arg;
321 : :
322 [ # # ]: 0 : if (msl->external)
323 : : return 0;
324 : :
325 : 0 : return vhost_vdpa_dma_map(dev, ms->addr, ms->iova, len);
326 : : }
327 : :
328 : : static int
329 : 0 : vhost_vdpa_map(const struct rte_memseg_list *msl, const struct rte_memseg *ms,
330 : : void *arg)
331 : : {
332 : : struct virtio_user_dev *dev = arg;
333 : :
334 : : /* skip external memory that isn't a heap */
335 [ # # # # ]: 0 : if (msl->external && !msl->heap)
336 : : return 0;
337 : :
338 : : /* skip any segments with invalid IOVA addresses */
339 [ # # ]: 0 : if (ms->iova == RTE_BAD_IOVA)
340 : : return 0;
341 : :
342 : : /* if IOVA mode is VA, we've already mapped the internal segments */
343 [ # # # # ]: 0 : if (!msl->external && rte_eal_iova_mode() == RTE_IOVA_VA)
344 : : return 0;
345 : :
346 : 0 : return vhost_vdpa_dma_map(dev, ms->addr, ms->iova, ms->len);
347 : : }
348 : :
349 : : static int
350 : 0 : vhost_vdpa_set_memory_table(struct virtio_user_dev *dev)
351 : : {
352 : : int ret;
353 : :
354 [ # # ]: 0 : if (vhost_vdpa_iotlb_batch_begin(dev) < 0)
355 : : return -1;
356 : :
357 : 0 : vhost_vdpa_dma_unmap(dev, NULL, 0, SIZE_MAX);
358 : :
359 [ # # ]: 0 : if (rte_eal_iova_mode() == RTE_IOVA_VA) {
360 : : /* with IOVA as VA mode, we can get away with mapping contiguous
361 : : * chunks rather than going page-by-page.
362 : : */
363 : 0 : ret = rte_memseg_contig_walk_thread_unsafe(
364 : : vhost_vdpa_map_contig, dev);
365 [ # # ]: 0 : if (ret)
366 : 0 : goto batch_end;
367 : : /* we have to continue the walk because we've skipped the
368 : : * external segments during the config walk.
369 : : */
370 : : }
371 : 0 : ret = rte_memseg_walk_thread_unsafe(vhost_vdpa_map, dev);
372 : :
373 : 0 : batch_end:
374 [ # # ]: 0 : if (vhost_vdpa_iotlb_batch_end(dev) < 0)
375 : 0 : return -1;
376 : :
377 : : return ret;
378 : : }
379 : :
380 : : static int
381 : : vhost_vdpa_set_vring_enable(struct virtio_user_dev *dev, struct vhost_vring_state *state)
382 : : {
383 : 0 : struct vhost_vdpa_data *data = dev->backend_data;
384 : :
385 : 0 : return vhost_vdpa_ioctl(data->vhostfd, VHOST_VDPA_SET_VRING_ENABLE, state);
386 : : }
387 : :
388 : : static int
389 : 0 : vhost_vdpa_set_vring_num(struct virtio_user_dev *dev, struct vhost_vring_state *state)
390 : : {
391 : 0 : struct vhost_vdpa_data *data = dev->backend_data;
392 : :
393 : 0 : return vhost_vdpa_ioctl(data->vhostfd, VHOST_SET_VRING_NUM, state);
394 : : }
395 : :
396 : : static int
397 : 0 : vhost_vdpa_set_vring_base(struct virtio_user_dev *dev, struct vhost_vring_state *state)
398 : : {
399 : 0 : struct vhost_vdpa_data *data = dev->backend_data;
400 : :
401 : 0 : return vhost_vdpa_ioctl(data->vhostfd, VHOST_SET_VRING_BASE, state);
402 : : }
403 : :
404 : : static int
405 : 0 : vhost_vdpa_get_vring_base(struct virtio_user_dev *dev, struct vhost_vring_state *state)
406 : : {
407 : 0 : struct vhost_vdpa_data *data = dev->backend_data;
408 : :
409 : 0 : return vhost_vdpa_ioctl(data->vhostfd, VHOST_GET_VRING_BASE, state);
410 : : }
411 : :
412 : : static int
413 : 0 : vhost_vdpa_set_vring_call(struct virtio_user_dev *dev, struct vhost_vring_file *file)
414 : : {
415 : 0 : struct vhost_vdpa_data *data = dev->backend_data;
416 : :
417 : 0 : return vhost_vdpa_ioctl(data->vhostfd, VHOST_SET_VRING_CALL, file);
418 : : }
419 : :
420 : : static int
421 : 0 : vhost_vdpa_set_vring_kick(struct virtio_user_dev *dev, struct vhost_vring_file *file)
422 : : {
423 : 0 : struct vhost_vdpa_data *data = dev->backend_data;
424 : :
425 : 0 : return vhost_vdpa_ioctl(data->vhostfd, VHOST_SET_VRING_KICK, file);
426 : : }
427 : :
428 : : static int
429 : 0 : vhost_vdpa_set_vring_addr(struct virtio_user_dev *dev, struct vhost_vring_addr *addr)
430 : : {
431 : 0 : struct vhost_vdpa_data *data = dev->backend_data;
432 : :
433 : 0 : return vhost_vdpa_ioctl(data->vhostfd, VHOST_SET_VRING_ADDR, addr);
434 : : }
435 : :
436 : : static int
437 : 0 : vhost_vdpa_get_status(struct virtio_user_dev *dev, uint8_t *status)
438 : : {
439 : 0 : struct vhost_vdpa_data *data = dev->backend_data;
440 : :
441 : 0 : return vhost_vdpa_ioctl(data->vhostfd, VHOST_VDPA_GET_STATUS, status);
442 : : }
443 : :
444 : : static int
445 : 0 : vhost_vdpa_set_status(struct virtio_user_dev *dev, uint8_t status)
446 : : {
447 : 0 : struct vhost_vdpa_data *data = dev->backend_data;
448 : :
449 : 0 : return vhost_vdpa_ioctl(data->vhostfd, VHOST_VDPA_SET_STATUS, &status);
450 : : }
451 : :
452 : : static int
453 : 0 : vhost_vdpa_get_config(struct virtio_user_dev *dev, uint8_t *data, uint32_t off, uint32_t len)
454 : : {
455 : 0 : struct vhost_vdpa_data *vdpa_data = dev->backend_data;
456 : : struct vhost_vdpa_config *config;
457 : : int ret = 0;
458 : :
459 : 0 : config = malloc(sizeof(*config) + len);
460 [ # # ]: 0 : if (!config) {
461 : 0 : PMD_DRV_LOG(ERR, "Failed to allocate vDPA config data");
462 : 0 : return -1;
463 : : }
464 : :
465 : 0 : config->off = off;
466 : 0 : config->len = len;
467 : :
468 : 0 : ret = vhost_vdpa_ioctl(vdpa_data->vhostfd, VHOST_VDPA_GET_CONFIG, config);
469 [ # # ]: 0 : if (ret) {
470 : 0 : PMD_DRV_LOG(ERR, "Failed to get vDPA config (offset 0x%x, len 0x%x)", off, len);
471 : : ret = -1;
472 : 0 : goto out;
473 : : }
474 : :
475 : 0 : memcpy(data, config->buf, len);
476 : 0 : out:
477 : 0 : free(config);
478 : :
479 : 0 : return ret;
480 : : }
481 : :
482 : : static int
483 : 0 : vhost_vdpa_set_config(struct virtio_user_dev *dev, const uint8_t *data, uint32_t off, uint32_t len)
484 : : {
485 : 0 : struct vhost_vdpa_data *vdpa_data = dev->backend_data;
486 : : struct vhost_vdpa_config *config;
487 : : int ret = 0;
488 : :
489 : 0 : config = malloc(sizeof(*config) + len);
490 [ # # ]: 0 : if (!config) {
491 : 0 : PMD_DRV_LOG(ERR, "Failed to allocate vDPA config data");
492 : 0 : return -1;
493 : : }
494 : :
495 : 0 : config->off = off;
496 : 0 : config->len = len;
497 : :
498 : 0 : memcpy(config->buf, data, len);
499 : :
500 : 0 : ret = vhost_vdpa_ioctl(vdpa_data->vhostfd, VHOST_VDPA_SET_CONFIG, config);
501 [ # # ]: 0 : if (ret) {
502 : 0 : PMD_DRV_LOG(ERR, "Failed to set vDPA config (offset 0x%x, len 0x%x)", off, len);
503 : : ret = -1;
504 : : }
505 : :
506 : 0 : free(config);
507 : :
508 : 0 : return ret;
509 : : }
510 : :
511 : : /**
512 : : * Set up environment to talk with a vhost vdpa backend.
513 : : *
514 : : * @return
515 : : * - (-1) if fail to set up;
516 : : * - (>=0) if successful.
517 : : */
518 : : static int
519 : 0 : vhost_vdpa_setup(struct virtio_user_dev *dev)
520 : : {
521 : : struct vhost_vdpa_data *data;
522 : 0 : uint32_t did = (uint32_t)-1;
523 : :
524 : 0 : data = malloc(sizeof(*data));
525 [ # # ]: 0 : if (!data) {
526 : 0 : PMD_DRV_LOG(ERR, "(%s) Faidle to allocate backend data", dev->path);
527 : 0 : return -1;
528 : : }
529 : :
530 : 0 : data->vhostfd = open(dev->path, O_RDWR);
531 [ # # ]: 0 : if (data->vhostfd < 0) {
532 : 0 : PMD_DRV_LOG(ERR, "Failed to open %s: %s",
533 : : dev->path, strerror(errno));
534 : 0 : free(data);
535 : 0 : return -1;
536 : : }
537 : :
538 [ # # ]: 0 : if (ioctl(data->vhostfd, VHOST_VDPA_GET_DEVICE_ID, &did) < 0 ||
539 [ # # ]: 0 : did != VIRTIO_ID_NETWORK) {
540 : 0 : PMD_DRV_LOG(ERR, "Invalid vdpa device ID: %u", did);
541 : 0 : close(data->vhostfd);
542 : 0 : free(data);
543 : 0 : return -1;
544 : : }
545 : :
546 : 0 : dev->backend_data = data;
547 : :
548 : 0 : return 0;
549 : : }
550 : :
551 : : static int
552 : 0 : vhost_vdpa_destroy(struct virtio_user_dev *dev)
553 : : {
554 : 0 : struct vhost_vdpa_data *data = dev->backend_data;
555 : :
556 [ # # ]: 0 : if (!data)
557 : : return 0;
558 : :
559 : 0 : close(data->vhostfd);
560 : :
561 : 0 : free(data);
562 : 0 : dev->backend_data = NULL;
563 : :
564 : 0 : return 0;
565 : : }
566 : :
567 : : static int
568 : 0 : vhost_vdpa_cvq_enable(struct virtio_user_dev *dev, int enable)
569 : : {
570 : 0 : struct vhost_vring_state state = {
571 : 0 : .index = dev->max_queue_pairs * 2,
572 : : .num = enable,
573 : : };
574 : :
575 : 0 : return vhost_vdpa_set_vring_enable(dev, &state);
576 : : }
577 : :
578 : : static int
579 : 0 : vhost_vdpa_enable_queue_pair(struct virtio_user_dev *dev,
580 : : uint16_t pair_idx,
581 : : int enable)
582 : : {
583 : : int i;
584 : :
585 [ # # ]: 0 : if (dev->qp_enabled[pair_idx] == enable)
586 : : return 0;
587 : :
588 [ # # ]: 0 : for (i = 0; i < 2; ++i) {
589 : 0 : struct vhost_vring_state state = {
590 : 0 : .index = pair_idx * 2 + i,
591 : : .num = enable,
592 : : };
593 : :
594 [ # # ]: 0 : if (vhost_vdpa_set_vring_enable(dev, &state))
595 : 0 : return -1;
596 : : }
597 : :
598 : 0 : dev->qp_enabled[pair_idx] = enable;
599 : :
600 : 0 : return 0;
601 : : }
602 : :
603 : : static int
604 : 0 : vhost_vdpa_get_backend_features(uint64_t *features)
605 : : {
606 : 0 : *features = 0;
607 : :
608 : 0 : return 0;
609 : : }
610 : :
611 : : static int
612 : 0 : vhost_vdpa_update_link_state(struct virtio_user_dev *dev __rte_unused)
613 : : {
614 : : /* Nothing to update (for now?) */
615 : 0 : return 0;
616 : : }
617 : :
618 : : static int
619 : 0 : vhost_vdpa_get_intr_fd(struct virtio_user_dev *dev __rte_unused)
620 : : {
621 : : /* No link state interrupt with Vhost-vDPA */
622 : 0 : return -1;
623 : : }
624 : :
625 : : struct virtio_user_backend_ops virtio_ops_vdpa = {
626 : : .setup = vhost_vdpa_setup,
627 : : .destroy = vhost_vdpa_destroy,
628 : : .get_backend_features = vhost_vdpa_get_backend_features,
629 : : .set_owner = vhost_vdpa_set_owner,
630 : : .get_features = vhost_vdpa_get_features,
631 : : .set_features = vhost_vdpa_set_features,
632 : : .set_memory_table = vhost_vdpa_set_memory_table,
633 : : .set_vring_num = vhost_vdpa_set_vring_num,
634 : : .set_vring_base = vhost_vdpa_set_vring_base,
635 : : .get_vring_base = vhost_vdpa_get_vring_base,
636 : : .set_vring_call = vhost_vdpa_set_vring_call,
637 : : .set_vring_kick = vhost_vdpa_set_vring_kick,
638 : : .set_vring_addr = vhost_vdpa_set_vring_addr,
639 : : .get_status = vhost_vdpa_get_status,
640 : : .set_status = vhost_vdpa_set_status,
641 : : .get_config = vhost_vdpa_get_config,
642 : : .set_config = vhost_vdpa_set_config,
643 : : .cvq_enable = vhost_vdpa_cvq_enable,
644 : : .enable_qp = vhost_vdpa_enable_queue_pair,
645 : : .dma_map = vhost_vdpa_dma_map_batch,
646 : : .dma_unmap = vhost_vdpa_dma_unmap_batch,
647 : : .update_link_state = vhost_vdpa_update_link_state,
648 : : .get_intr_fd = vhost_vdpa_get_intr_fd,
649 : : };
|