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