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