1 /* SPDX-License-Identifier: BSD-3-Clause
2 * Copyright(c) 2018 Intel Corporation
8 * Device specific vhost lib
12 #include <sys/queue.h>
14 #include <rte_class.h>
15 #include <rte_malloc.h>
16 #include <rte_spinlock.h>
17 #include <rte_tailq.h>
22 /** Double linked list of vDPA devices. */
23 TAILQ_HEAD(vdpa_device_list, rte_vdpa_device);
25 static struct vdpa_device_list vdpa_device_list =
26 TAILQ_HEAD_INITIALIZER(vdpa_device_list);
27 static rte_spinlock_t vdpa_device_list_lock = RTE_SPINLOCK_INITIALIZER;
28 static uint32_t vdpa_device_num;
31 /* Unsafe, needs to be called with vdpa_device_list_lock held */
32 static struct rte_vdpa_device *
33 __vdpa_find_device_by_name(const char *name)
35 struct rte_vdpa_device *dev, *ret = NULL;
40 TAILQ_FOREACH(dev, &vdpa_device_list, next) {
41 if (!strncmp(dev->device->name, name, RTE_DEV_NAME_MAX_LEN)) {
50 struct rte_vdpa_device *
51 rte_vdpa_find_device_by_name(const char *name)
53 struct rte_vdpa_device *dev;
55 rte_spinlock_lock(&vdpa_device_list_lock);
56 dev = __vdpa_find_device_by_name(name);
57 rte_spinlock_unlock(&vdpa_device_list_lock);
63 rte_vdpa_get_rte_device(struct rte_vdpa_device *vdpa_dev)
68 return vdpa_dev->device;
71 struct rte_vdpa_device *
72 rte_vdpa_register_device(struct rte_device *rte_dev,
73 struct rte_vdpa_dev_ops *ops)
75 struct rte_vdpa_device *dev;
80 rte_spinlock_lock(&vdpa_device_list_lock);
81 /* Check the device hasn't been register already */
82 dev = __vdpa_find_device_by_name(rte_dev->name);
88 dev = rte_zmalloc(NULL, sizeof(*dev), 0);
92 dev->device = rte_dev;
94 TAILQ_INSERT_TAIL(&vdpa_device_list, dev, next);
97 rte_spinlock_unlock(&vdpa_device_list_lock);
103 rte_vdpa_unregister_device(struct rte_vdpa_device *dev)
105 struct rte_vdpa_device *cur_dev, *tmp_dev;
108 rte_spinlock_lock(&vdpa_device_list_lock);
109 TAILQ_FOREACH_SAFE(cur_dev, &vdpa_device_list, next, tmp_dev) {
113 TAILQ_REMOVE(&vdpa_device_list, dev, next);
119 rte_spinlock_unlock(&vdpa_device_list_lock);
125 rte_vdpa_get_device_num(void)
127 return vdpa_device_num;
131 rte_vdpa_relay_vring_used(int vid, uint16_t qid, void *vring_m)
133 struct virtio_net *dev = get_device(vid);
134 uint16_t idx, idx_m, desc_id;
135 struct vhost_virtqueue *vq;
136 struct vring_desc desc;
137 struct vring_desc *desc_ring;
138 struct vring_desc *idesc = NULL;
139 struct vring *s_vring;
144 if (!dev || !vring_m)
147 if (qid >= dev->nr_vring)
150 if (vq_is_packed(dev))
153 s_vring = (struct vring *)vring_m;
154 vq = dev->virtqueue[qid];
156 idx_m = s_vring->used->idx;
157 ret = (uint16_t)(idx_m - idx);
159 while (idx != idx_m) {
160 /* copy used entry, used ring logging is not covered here */
161 vq->used->ring[idx & (vq->size - 1)] =
162 s_vring->used->ring[idx & (vq->size - 1)];
164 desc_id = vq->used->ring[idx & (vq->size - 1)].id;
165 desc_ring = vq->desc;
168 if (unlikely(desc_id >= vq->size))
171 if (vq->desc[desc_id].flags & VRING_DESC_F_INDIRECT) {
172 dlen = vq->desc[desc_id].len;
173 nr_descs = dlen / sizeof(struct vring_desc);
174 if (unlikely(nr_descs > vq->size))
177 desc_ring = (struct vring_desc *)(uintptr_t)
178 vhost_iova_to_vva(dev, vq,
179 vq->desc[desc_id].addr, &dlen,
181 if (unlikely(!desc_ring))
184 if (unlikely(dlen < vq->desc[desc_id].len)) {
185 idesc = vhost_alloc_copy_ind_table(dev, vq,
186 vq->desc[desc_id].addr,
187 vq->desc[desc_id].len);
188 if (unlikely(!idesc))
197 /* dirty page logging for DMA writeable buffer */
199 if (unlikely(desc_id >= vq->size))
201 if (unlikely(nr_descs-- == 0))
203 desc = desc_ring[desc_id];
204 if (desc.flags & VRING_DESC_F_WRITE)
205 vhost_log_write_iova(dev, vq, desc.addr,
208 } while (desc.flags & VRING_DESC_F_NEXT);
210 if (unlikely(idesc)) {
211 free_ind_table(idesc);
219 vq->used->idx = idx_m;
221 if (dev->features & (1ULL << VIRTIO_RING_F_EVENT_IDX))
222 vring_used_event(s_vring) = idx_m;
228 free_ind_table(idesc);
233 rte_vdpa_get_queue_num(struct rte_vdpa_device *dev, uint32_t *queue_num)
235 if (dev == NULL || dev->ops == NULL || dev->ops->get_queue_num == NULL)
238 return dev->ops->get_queue_num(dev, queue_num);
242 rte_vdpa_get_features(struct rte_vdpa_device *dev, uint64_t *features)
244 if (dev == NULL || dev->ops == NULL || dev->ops->get_features == NULL)
247 return dev->ops->get_features(dev, features);
251 rte_vdpa_get_protocol_features(struct rte_vdpa_device *dev, uint64_t *features)
253 if (dev == NULL || dev->ops == NULL ||
254 dev->ops->get_protocol_features == NULL)
257 return dev->ops->get_protocol_features(dev, features);
261 rte_vdpa_get_stats_names(struct rte_vdpa_device *dev,
262 struct rte_vdpa_stat_name *stats_names,
268 RTE_FUNC_PTR_OR_ERR_RET(dev->ops->get_stats_names, -ENOTSUP);
270 return dev->ops->get_stats_names(dev, stats_names, size);
274 rte_vdpa_get_stats(struct rte_vdpa_device *dev, uint16_t qid,
275 struct rte_vdpa_stat *stats, unsigned int n)
277 if (!dev || !stats || !n)
280 RTE_FUNC_PTR_OR_ERR_RET(dev->ops->get_stats, -ENOTSUP);
282 return dev->ops->get_stats(dev, qid, stats, n);
286 rte_vdpa_reset_stats(struct rte_vdpa_device *dev, uint16_t qid)
291 RTE_FUNC_PTR_OR_ERR_RET(dev->ops->reset_stats, -ENOTSUP);
293 return dev->ops->reset_stats(dev, qid);
297 vdpa_dev_match(struct rte_vdpa_device *dev,
298 const struct rte_device *rte_dev)
300 if (dev->device == rte_dev)
306 /* Generic rte_vdpa_dev comparison function. */
307 typedef int (*rte_vdpa_cmp_t)(struct rte_vdpa_device *,
308 const struct rte_device *rte_dev);
310 static struct rte_vdpa_device *
311 vdpa_find_device(const struct rte_vdpa_device *start, rte_vdpa_cmp_t cmp,
312 struct rte_device *rte_dev)
314 struct rte_vdpa_device *dev;
316 rte_spinlock_lock(&vdpa_device_list_lock);
318 dev = TAILQ_FIRST(&vdpa_device_list);
320 dev = TAILQ_NEXT(start, next);
322 while (dev != NULL) {
323 if (cmp(dev, rte_dev) == 0)
326 dev = TAILQ_NEXT(dev, next);
328 rte_spinlock_unlock(&vdpa_device_list_lock);
334 vdpa_dev_iterate(const void *start,
336 const struct rte_dev_iterator *it)
338 struct rte_vdpa_device *vdpa_dev = NULL;
342 vdpa_dev = vdpa_find_device(start, vdpa_dev_match, it->device);
347 static struct rte_class rte_class_vdpa = {
348 .dev_iterate = vdpa_dev_iterate,
351 RTE_REGISTER_CLASS(vdpa, rte_class_vdpa);