Branch data Line data Source code
1 : : /* SPDX-License-Identifier: BSD-3-Clause
2 : : * Copyright(c) 2018 Intel Corporation
3 : : */
4 : :
5 : : /**
6 : : * @file
7 : : *
8 : : * Device specific vhost lib
9 : : */
10 : :
11 : : #include <sys/queue.h>
12 : :
13 : : #include <dev_driver.h>
14 : : #include <eal_export.h>
15 : : #include <rte_class.h>
16 : : #include <rte_malloc.h>
17 : : #include <rte_spinlock.h>
18 : : #include <rte_tailq.h>
19 : :
20 : : #include "rte_vdpa.h"
21 : : #include "vdpa_driver.h"
22 : : #include "vhost.h"
23 : : #include "iotlb.h"
24 : :
25 : : /** Double linked list of vDPA devices. */
26 : : TAILQ_HEAD(vdpa_device_list, rte_vdpa_device);
27 : :
28 : : static struct vdpa_device_list vdpa_device_list__ =
29 : : TAILQ_HEAD_INITIALIZER(vdpa_device_list__);
30 : : static rte_spinlock_t vdpa_device_list_lock = RTE_SPINLOCK_INITIALIZER;
31 : : static struct vdpa_device_list * const vdpa_device_list
32 : : __rte_guarded_by(&vdpa_device_list_lock) = &vdpa_device_list__;
33 : :
34 : : static struct rte_vdpa_device *
35 : 0 : __vdpa_find_device_by_name(const char *name)
36 : : __rte_requires_capability(&vdpa_device_list_lock)
37 : : {
38 : : struct rte_vdpa_device *dev, *ret = NULL;
39 : :
40 [ # # ]: 0 : if (name == NULL)
41 : : return NULL;
42 : :
43 [ # # ]: 0 : TAILQ_FOREACH(dev, vdpa_device_list, next) {
44 [ # # ]: 0 : if (!strncmp(dev->device->name, name, RTE_DEV_NAME_MAX_LEN)) {
45 : : ret = dev;
46 : : break;
47 : : }
48 : : }
49 : :
50 : : return ret;
51 : : }
52 : :
53 : : RTE_EXPORT_SYMBOL(rte_vdpa_find_device_by_name)
54 : : struct rte_vdpa_device *
55 : 0 : rte_vdpa_find_device_by_name(const char *name)
56 : : {
57 : : struct rte_vdpa_device *dev;
58 : :
59 : : rte_spinlock_lock(&vdpa_device_list_lock);
60 : 0 : dev = __vdpa_find_device_by_name(name);
61 : : rte_spinlock_unlock(&vdpa_device_list_lock);
62 : :
63 : 0 : return dev;
64 : : }
65 : :
66 : : RTE_EXPORT_SYMBOL(rte_vdpa_get_rte_device)
67 : : struct rte_device *
68 : 0 : rte_vdpa_get_rte_device(struct rte_vdpa_device *vdpa_dev)
69 : : {
70 [ # # ]: 0 : if (vdpa_dev == NULL)
71 : : return NULL;
72 : :
73 : 0 : return vdpa_dev->device;
74 : : }
75 : :
76 : : RTE_EXPORT_INTERNAL_SYMBOL(rte_vdpa_register_device)
77 : : struct rte_vdpa_device *
78 : 0 : rte_vdpa_register_device(struct rte_device *rte_dev,
79 : : struct rte_vdpa_dev_ops *ops)
80 : : {
81 : : struct rte_vdpa_device *dev;
82 : : int ret = 0;
83 : :
84 [ # # ]: 0 : if (ops == NULL)
85 : : return NULL;
86 : :
87 : : /* Check mandatory ops are implemented */
88 [ # # # # ]: 0 : if (!ops->get_queue_num || !ops->get_features ||
89 [ # # # # ]: 0 : !ops->get_protocol_features || !ops->dev_conf ||
90 [ # # # # ]: 0 : !ops->dev_close || !ops->set_vring_state ||
91 [ # # ]: 0 : !ops->set_features) {
92 : 0 : VHOST_CONFIG_LOG(rte_dev->name, ERR,
93 : : "Some mandatory vDPA ops aren't implemented");
94 : 0 : return NULL;
95 : : }
96 : :
97 : : rte_spinlock_lock(&vdpa_device_list_lock);
98 : : /* Check the device hasn't been register already */
99 : 0 : dev = __vdpa_find_device_by_name(rte_dev->name);
100 [ # # ]: 0 : if (dev) {
101 : : dev = NULL;
102 : 0 : goto out_unlock;
103 : : }
104 : :
105 : 0 : dev = rte_zmalloc(NULL, sizeof(*dev), 0);
106 [ # # ]: 0 : if (!dev)
107 : 0 : goto out_unlock;
108 : :
109 : 0 : dev->device = rte_dev;
110 : 0 : dev->ops = ops;
111 : :
112 [ # # ]: 0 : if (ops->get_dev_type) {
113 : 0 : ret = ops->get_dev_type(dev, &dev->type);
114 [ # # ]: 0 : if (ret) {
115 : 0 : VHOST_CONFIG_LOG(rte_dev->name, ERR,
116 : : "Failed to get vdpa dev type.");
117 : : ret = -1;
118 : 0 : goto out_unlock;
119 : : }
120 : : } else {
121 : : /** by default, we assume vdpa device is a net device */
122 : 0 : dev->type = RTE_VHOST_VDPA_DEVICE_TYPE_NET;
123 : : }
124 : :
125 : 0 : TAILQ_INSERT_TAIL(vdpa_device_list, dev, next);
126 : 0 : out_unlock:
127 : : rte_spinlock_unlock(&vdpa_device_list_lock);
128 : :
129 : 0 : return dev;
130 : : }
131 : :
132 : : RTE_EXPORT_INTERNAL_SYMBOL(rte_vdpa_unregister_device)
133 : : int
134 : 0 : rte_vdpa_unregister_device(struct rte_vdpa_device *dev)
135 : : {
136 : : struct rte_vdpa_device *cur_dev, *tmp_dev;
137 : : int ret = -1;
138 : :
139 : : rte_spinlock_lock(&vdpa_device_list_lock);
140 [ # # ]: 0 : RTE_TAILQ_FOREACH_SAFE(cur_dev, vdpa_device_list, next, tmp_dev) {
141 [ # # ]: 0 : if (dev != cur_dev)
142 : : continue;
143 : :
144 [ # # ]: 0 : TAILQ_REMOVE(vdpa_device_list, dev, next);
145 : 0 : rte_free(dev);
146 : : ret = 0;
147 : 0 : break;
148 : : }
149 : : rte_spinlock_unlock(&vdpa_device_list_lock);
150 : :
151 : 0 : return ret;
152 : : }
153 : :
154 : : RTE_EXPORT_INTERNAL_SYMBOL(rte_vdpa_relay_vring_used)
155 : : int
156 [ # # ]: 0 : rte_vdpa_relay_vring_used(int vid, uint16_t qid, void *vring_m)
157 : : {
158 : : struct virtio_net *dev = get_device(vid);
159 : : uint16_t idx, idx_m, desc_id;
160 : : struct vhost_virtqueue *vq;
161 : : struct vring_desc desc;
162 : : struct vring_desc *desc_ring;
163 : : struct vring_desc *idesc = NULL;
164 : : struct vring *s_vring;
165 : : uint64_t dlen;
166 : : uint32_t nr_descs;
167 : : int ret;
168 : :
169 [ # # ]: 0 : if (!dev || !vring_m)
170 : : return -1;
171 : :
172 [ # # ]: 0 : if (qid >= dev->nr_vring)
173 : : return -1;
174 : :
175 [ # # ]: 0 : if (vq_is_packed(dev))
176 : : return -1;
177 : :
178 : : s_vring = (struct vring *)vring_m;
179 : 0 : vq = dev->virtqueue[qid];
180 : 0 : idx = vq->used->idx;
181 : 0 : idx_m = s_vring->used->idx;
182 : 0 : ret = (uint16_t)(idx_m - idx);
183 : 0 : vq->used->flags = s_vring->used->flags;
184 : :
185 [ # # ]: 0 : while (idx != idx_m) {
186 : : /* copy used entry, used ring logging is not covered here */
187 : 0 : vq->used->ring[idx & (vq->size - 1)] =
188 : 0 : s_vring->used->ring[idx & (vq->size - 1)];
189 : :
190 : 0 : desc_id = vq->used->ring[idx & (vq->size - 1)].id;
191 : 0 : desc_ring = vq->desc;
192 : 0 : nr_descs = vq->size;
193 : :
194 [ # # ]: 0 : if (unlikely(desc_id >= vq->size))
195 : : return -1;
196 : :
197 [ # # ]: 0 : if (vq->desc[desc_id].flags & VRING_DESC_F_INDIRECT) {
198 : 0 : dlen = vq->desc[desc_id].len;
199 : 0 : nr_descs = dlen / sizeof(struct vring_desc);
200 [ # # ]: 0 : if (unlikely(nr_descs > vq->size))
201 : : return -1;
202 : :
203 : : vhost_user_iotlb_rd_lock(vq);
204 [ # # ]: 0 : desc_ring = (struct vring_desc *)(uintptr_t)
205 : : vhost_iova_to_vva(dev, vq,
206 [ # # ]: 0 : vq->desc[desc_id].addr, &dlen,
207 : : VHOST_ACCESS_RO);
208 : : vhost_user_iotlb_rd_unlock(vq);
209 [ # # ]: 0 : if (unlikely(!desc_ring))
210 : : return -1;
211 : :
212 [ # # ]: 0 : if (unlikely(dlen < vq->desc[desc_id].len)) {
213 : : vhost_user_iotlb_rd_lock(vq);
214 : 0 : idesc = vhost_alloc_copy_ind_table(dev, vq,
215 : 0 : vq->desc[desc_id].addr,
216 : 0 : vq->desc[desc_id].len);
217 : : vhost_user_iotlb_rd_unlock(vq);
218 [ # # ]: 0 : if (unlikely(!idesc))
219 : : return -1;
220 : :
221 : : desc_ring = idesc;
222 : : }
223 : :
224 : : desc_id = 0;
225 : : }
226 : :
227 : : /* dirty page logging for DMA writeable buffer */
228 : : do {
229 [ # # ]: 0 : if (unlikely(desc_id >= vq->size))
230 : 0 : goto fail;
231 [ # # ]: 0 : if (unlikely(nr_descs-- == 0))
232 : 0 : goto fail;
233 : 0 : desc = desc_ring[desc_id];
234 [ # # ]: 0 : if (desc.flags & VRING_DESC_F_WRITE) {
235 : : vhost_user_iotlb_rd_lock(vq);
236 [ # # ]: 0 : vhost_log_write_iova(dev, vq, desc.addr,
237 : : desc.len);
238 : : vhost_user_iotlb_rd_unlock(vq);
239 : : }
240 : : desc_id = desc.next;
241 [ # # ]: 0 : } while (desc.flags & VRING_DESC_F_NEXT);
242 : :
243 [ # # ]: 0 : if (unlikely(idesc)) {
244 : : free_ind_table(idesc);
245 : : idesc = NULL;
246 : : }
247 : :
248 : 0 : idx++;
249 : : }
250 : :
251 : : /* used idx is the synchronization point for the split vring */
252 : 0 : rte_atomic_store_explicit((unsigned short __rte_atomic *)&vq->used->idx,
253 : : idx_m, rte_memory_order_release);
254 : :
255 [ # # ]: 0 : if (dev->features & (1ULL << VIRTIO_RING_F_EVENT_IDX))
256 : 0 : vring_used_event(s_vring) = idx_m;
257 : :
258 : : return ret;
259 : :
260 : 0 : fail:
261 [ # # ]: 0 : if (unlikely(idesc))
262 : : free_ind_table(idesc);
263 : : return -1;
264 : : }
265 : :
266 : : RTE_EXPORT_SYMBOL(rte_vdpa_get_queue_num)
267 : : int
268 : 0 : rte_vdpa_get_queue_num(struct rte_vdpa_device *dev, uint32_t *queue_num)
269 : : {
270 [ # # # # : 0 : if (dev == NULL || dev->ops == NULL || dev->ops->get_queue_num == NULL)
# # ]
271 : : return -1;
272 : :
273 : 0 : return dev->ops->get_queue_num(dev, queue_num);
274 : : }
275 : :
276 : : RTE_EXPORT_SYMBOL(rte_vdpa_get_features)
277 : : int
278 : 0 : rte_vdpa_get_features(struct rte_vdpa_device *dev, uint64_t *features)
279 : : {
280 [ # # # # : 0 : if (dev == NULL || dev->ops == NULL || dev->ops->get_features == NULL)
# # ]
281 : : return -1;
282 : :
283 : 0 : return dev->ops->get_features(dev, features);
284 : : }
285 : :
286 : : RTE_EXPORT_SYMBOL(rte_vdpa_get_protocol_features)
287 : : int
288 : 0 : rte_vdpa_get_protocol_features(struct rte_vdpa_device *dev, uint64_t *features)
289 : : {
290 [ # # # # ]: 0 : if (dev == NULL || dev->ops == NULL ||
291 [ # # ]: 0 : dev->ops->get_protocol_features == NULL)
292 : : return -1;
293 : :
294 : 0 : return dev->ops->get_protocol_features(dev, features);
295 : : }
296 : :
297 : : RTE_EXPORT_SYMBOL(rte_vdpa_get_stats_names)
298 : : int
299 : 0 : rte_vdpa_get_stats_names(struct rte_vdpa_device *dev,
300 : : struct rte_vdpa_stat_name *stats_names,
301 : : unsigned int size)
302 : : {
303 [ # # ]: 0 : if (!dev)
304 : : return -EINVAL;
305 : :
306 [ # # ]: 0 : if (dev->ops->get_stats_names == NULL)
307 : : return -ENOTSUP;
308 : :
309 : 0 : return dev->ops->get_stats_names(dev, stats_names, size);
310 : : }
311 : :
312 : : RTE_EXPORT_SYMBOL(rte_vdpa_get_stats)
313 : : int
314 : 0 : rte_vdpa_get_stats(struct rte_vdpa_device *dev, uint16_t qid,
315 : : struct rte_vdpa_stat *stats, unsigned int n)
316 : : {
317 [ # # # # ]: 0 : if (!dev || !stats || !n)
318 : : return -EINVAL;
319 : :
320 [ # # ]: 0 : if (dev->ops->get_stats == NULL)
321 : : return -ENOTSUP;
322 : :
323 : 0 : return dev->ops->get_stats(dev, qid, stats, n);
324 : : }
325 : :
326 : : RTE_EXPORT_SYMBOL(rte_vdpa_reset_stats)
327 : : int
328 : 0 : rte_vdpa_reset_stats(struct rte_vdpa_device *dev, uint16_t qid)
329 : : {
330 [ # # ]: 0 : if (!dev)
331 : : return -EINVAL;
332 : :
333 [ # # ]: 0 : if (dev->ops->reset_stats == NULL)
334 : : return -ENOTSUP;
335 : :
336 : 0 : return dev->ops->reset_stats(dev, qid);
337 : : }
338 : :
339 : : static int
340 : 0 : vdpa_dev_match(struct rte_vdpa_device *dev,
341 : : const struct rte_device *rte_dev)
342 : : {
343 [ # # ]: 0 : if (dev->device == rte_dev)
344 : 0 : return 0;
345 : :
346 : : return -1;
347 : : }
348 : :
349 : : /* Generic rte_vdpa_dev comparison function. */
350 : : typedef int (*rte_vdpa_cmp_t)(struct rte_vdpa_device *,
351 : : const struct rte_device *rte_dev);
352 : :
353 : : static struct rte_vdpa_device *
354 : 0 : vdpa_find_device(const struct rte_vdpa_device *start, rte_vdpa_cmp_t cmp,
355 : : struct rte_device *rte_dev)
356 : : {
357 : : struct rte_vdpa_device *dev;
358 : :
359 : : rte_spinlock_lock(&vdpa_device_list_lock);
360 [ # # ]: 0 : if (start == NULL)
361 : 0 : dev = TAILQ_FIRST(vdpa_device_list);
362 : : else
363 : 0 : dev = TAILQ_NEXT(start, next);
364 : :
365 [ # # ]: 0 : while (dev != NULL) {
366 [ # # ]: 0 : if (cmp(dev, rte_dev) == 0)
367 : : break;
368 : :
369 : 0 : dev = TAILQ_NEXT(dev, next);
370 : : }
371 : : rte_spinlock_unlock(&vdpa_device_list_lock);
372 : :
373 : 0 : return dev;
374 : : }
375 : :
376 : : static void *
377 : 0 : vdpa_dev_iterate(const void *start,
378 : : const char *str,
379 : : const struct rte_dev_iterator *it)
380 : : {
381 : : struct rte_vdpa_device *vdpa_dev = NULL;
382 : :
383 : : RTE_SET_USED(str);
384 : :
385 : 0 : vdpa_dev = vdpa_find_device(start, vdpa_dev_match, it->device);
386 : :
387 : 0 : return vdpa_dev;
388 : : }
389 : :
390 : : static struct rte_class rte_class_vdpa = {
391 : : .dev_iterate = vdpa_dev_iterate,
392 : : };
393 : :
394 : 252 : RTE_REGISTER_CLASS(vdpa, rte_class_vdpa);
|