199a2dd95SBruce Richardson /* SPDX-License-Identifier: BSD-3-Clause 299a2dd95SBruce Richardson * Copyright(c) 2018 Intel Corporation 399a2dd95SBruce Richardson */ 499a2dd95SBruce Richardson 599a2dd95SBruce Richardson /** 699a2dd95SBruce Richardson * @file 799a2dd95SBruce Richardson * 899a2dd95SBruce Richardson * Device specific vhost lib 999a2dd95SBruce Richardson */ 1099a2dd95SBruce Richardson 1199a2dd95SBruce Richardson #include <sys/queue.h> 1299a2dd95SBruce Richardson 13fbd59c8eSDavid Marchand #include <dev_driver.h> 1499a2dd95SBruce Richardson #include <rte_class.h> 1599a2dd95SBruce Richardson #include <rte_malloc.h> 1699a2dd95SBruce Richardson #include <rte_spinlock.h> 1799a2dd95SBruce Richardson #include <rte_tailq.h> 1899a2dd95SBruce Richardson 1999a2dd95SBruce Richardson #include "rte_vdpa.h" 2094c16e89SMaxime Coquelin #include "vdpa_driver.h" 2199a2dd95SBruce Richardson #include "vhost.h" 2219639c3bSHao Chen #include "iotlb.h" 2399a2dd95SBruce Richardson 2499a2dd95SBruce Richardson /** Double linked list of vDPA devices. */ 2599a2dd95SBruce Richardson TAILQ_HEAD(vdpa_device_list, rte_vdpa_device); 2699a2dd95SBruce Richardson 27148303e2SDavid Marchand static struct vdpa_device_list vdpa_device_list__ = 28148303e2SDavid Marchand TAILQ_HEAD_INITIALIZER(vdpa_device_list__); 2999a2dd95SBruce Richardson static rte_spinlock_t vdpa_device_list_lock = RTE_SPINLOCK_INITIALIZER; 30148303e2SDavid Marchand static struct vdpa_device_list * const vdpa_device_list 31148303e2SDavid Marchand __rte_guarded_by(&vdpa_device_list_lock) = &vdpa_device_list__; 3299a2dd95SBruce Richardson 3399a2dd95SBruce Richardson static struct rte_vdpa_device * 3499a2dd95SBruce Richardson __vdpa_find_device_by_name(const char *name) 35148303e2SDavid Marchand __rte_exclusive_locks_required(&vdpa_device_list_lock) 3699a2dd95SBruce Richardson { 3799a2dd95SBruce Richardson struct rte_vdpa_device *dev, *ret = NULL; 3899a2dd95SBruce Richardson 3999a2dd95SBruce Richardson if (name == NULL) 4099a2dd95SBruce Richardson return NULL; 4199a2dd95SBruce Richardson 42148303e2SDavid Marchand TAILQ_FOREACH(dev, vdpa_device_list, next) { 4399a2dd95SBruce Richardson if (!strncmp(dev->device->name, name, RTE_DEV_NAME_MAX_LEN)) { 4499a2dd95SBruce Richardson ret = dev; 4599a2dd95SBruce Richardson break; 4699a2dd95SBruce Richardson } 4799a2dd95SBruce Richardson } 4899a2dd95SBruce Richardson 4999a2dd95SBruce Richardson return ret; 5099a2dd95SBruce Richardson } 5199a2dd95SBruce Richardson 5299a2dd95SBruce Richardson struct rte_vdpa_device * 5399a2dd95SBruce Richardson rte_vdpa_find_device_by_name(const char *name) 5499a2dd95SBruce Richardson { 5599a2dd95SBruce Richardson struct rte_vdpa_device *dev; 5699a2dd95SBruce Richardson 5799a2dd95SBruce Richardson rte_spinlock_lock(&vdpa_device_list_lock); 5899a2dd95SBruce Richardson dev = __vdpa_find_device_by_name(name); 5999a2dd95SBruce Richardson rte_spinlock_unlock(&vdpa_device_list_lock); 6099a2dd95SBruce Richardson 6199a2dd95SBruce Richardson return dev; 6299a2dd95SBruce Richardson } 6399a2dd95SBruce Richardson 6499a2dd95SBruce Richardson struct rte_device * 6599a2dd95SBruce Richardson rte_vdpa_get_rte_device(struct rte_vdpa_device *vdpa_dev) 6699a2dd95SBruce Richardson { 6799a2dd95SBruce Richardson if (vdpa_dev == NULL) 6899a2dd95SBruce Richardson return NULL; 6999a2dd95SBruce Richardson 7099a2dd95SBruce Richardson return vdpa_dev->device; 7199a2dd95SBruce Richardson } 7299a2dd95SBruce Richardson 7399a2dd95SBruce Richardson struct rte_vdpa_device * 7499a2dd95SBruce Richardson rte_vdpa_register_device(struct rte_device *rte_dev, 7599a2dd95SBruce Richardson struct rte_vdpa_dev_ops *ops) 7699a2dd95SBruce Richardson { 7799a2dd95SBruce Richardson struct rte_vdpa_device *dev; 78f92ab3f0SAndy Pei int ret = 0; 7999a2dd95SBruce Richardson 8099a2dd95SBruce Richardson if (ops == NULL) 8199a2dd95SBruce Richardson return NULL; 8299a2dd95SBruce Richardson 8399a2dd95SBruce Richardson /* Check mandatory ops are implemented */ 8499a2dd95SBruce Richardson if (!ops->get_queue_num || !ops->get_features || 8599a2dd95SBruce Richardson !ops->get_protocol_features || !ops->dev_conf || 8699a2dd95SBruce Richardson !ops->dev_close || !ops->set_vring_state || 8799a2dd95SBruce Richardson !ops->set_features) { 880e21c7c0SDavid Marchand VHOST_CONFIG_LOG(rte_dev->name, ERR, 890e21c7c0SDavid Marchand "Some mandatory vDPA ops aren't implemented"); 9099a2dd95SBruce Richardson return NULL; 9199a2dd95SBruce Richardson } 9299a2dd95SBruce Richardson 9399a2dd95SBruce Richardson rte_spinlock_lock(&vdpa_device_list_lock); 9499a2dd95SBruce Richardson /* Check the device hasn't been register already */ 9599a2dd95SBruce Richardson dev = __vdpa_find_device_by_name(rte_dev->name); 9699a2dd95SBruce Richardson if (dev) { 9799a2dd95SBruce Richardson dev = NULL; 9899a2dd95SBruce Richardson goto out_unlock; 9999a2dd95SBruce Richardson } 10099a2dd95SBruce Richardson 10199a2dd95SBruce Richardson dev = rte_zmalloc(NULL, sizeof(*dev), 0); 10299a2dd95SBruce Richardson if (!dev) 10399a2dd95SBruce Richardson goto out_unlock; 10499a2dd95SBruce Richardson 10599a2dd95SBruce Richardson dev->device = rte_dev; 10699a2dd95SBruce Richardson dev->ops = ops; 107f92ab3f0SAndy Pei 108f92ab3f0SAndy Pei if (ops->get_dev_type) { 109f92ab3f0SAndy Pei ret = ops->get_dev_type(dev, &dev->type); 110f92ab3f0SAndy Pei if (ret) { 1110e21c7c0SDavid Marchand VHOST_CONFIG_LOG(rte_dev->name, ERR, 1120e21c7c0SDavid Marchand "Failed to get vdpa dev type."); 113f92ab3f0SAndy Pei ret = -1; 114f92ab3f0SAndy Pei goto out_unlock; 115f92ab3f0SAndy Pei } 116f92ab3f0SAndy Pei } else { 117f92ab3f0SAndy Pei /** by default, we assume vdpa device is a net device */ 118f92ab3f0SAndy Pei dev->type = RTE_VHOST_VDPA_DEVICE_TYPE_NET; 119f92ab3f0SAndy Pei } 120f92ab3f0SAndy Pei 121148303e2SDavid Marchand TAILQ_INSERT_TAIL(vdpa_device_list, dev, next); 12299a2dd95SBruce Richardson out_unlock: 12399a2dd95SBruce Richardson rte_spinlock_unlock(&vdpa_device_list_lock); 12499a2dd95SBruce Richardson 12599a2dd95SBruce Richardson return dev; 12699a2dd95SBruce Richardson } 12799a2dd95SBruce Richardson 12899a2dd95SBruce Richardson int 12999a2dd95SBruce Richardson rte_vdpa_unregister_device(struct rte_vdpa_device *dev) 13099a2dd95SBruce Richardson { 13199a2dd95SBruce Richardson struct rte_vdpa_device *cur_dev, *tmp_dev; 13299a2dd95SBruce Richardson int ret = -1; 13399a2dd95SBruce Richardson 13499a2dd95SBruce Richardson rte_spinlock_lock(&vdpa_device_list_lock); 135148303e2SDavid Marchand RTE_TAILQ_FOREACH_SAFE(cur_dev, vdpa_device_list, next, tmp_dev) { 13699a2dd95SBruce Richardson if (dev != cur_dev) 13799a2dd95SBruce Richardson continue; 13899a2dd95SBruce Richardson 139148303e2SDavid Marchand TAILQ_REMOVE(vdpa_device_list, dev, next); 14099a2dd95SBruce Richardson rte_free(dev); 14199a2dd95SBruce Richardson ret = 0; 14299a2dd95SBruce Richardson break; 14399a2dd95SBruce Richardson } 14499a2dd95SBruce Richardson rte_spinlock_unlock(&vdpa_device_list_lock); 14599a2dd95SBruce Richardson 14699a2dd95SBruce Richardson return ret; 14799a2dd95SBruce Richardson } 14899a2dd95SBruce Richardson 14999a2dd95SBruce Richardson int 15099a2dd95SBruce Richardson rte_vdpa_relay_vring_used(int vid, uint16_t qid, void *vring_m) 15199a2dd95SBruce Richardson { 15299a2dd95SBruce Richardson struct virtio_net *dev = get_device(vid); 15399a2dd95SBruce Richardson uint16_t idx, idx_m, desc_id; 15499a2dd95SBruce Richardson struct vhost_virtqueue *vq; 15599a2dd95SBruce Richardson struct vring_desc desc; 15699a2dd95SBruce Richardson struct vring_desc *desc_ring; 15799a2dd95SBruce Richardson struct vring_desc *idesc = NULL; 15899a2dd95SBruce Richardson struct vring *s_vring; 15999a2dd95SBruce Richardson uint64_t dlen; 16099a2dd95SBruce Richardson uint32_t nr_descs; 16199a2dd95SBruce Richardson int ret; 16299a2dd95SBruce Richardson 16399a2dd95SBruce Richardson if (!dev || !vring_m) 16499a2dd95SBruce Richardson return -1; 16599a2dd95SBruce Richardson 16699a2dd95SBruce Richardson if (qid >= dev->nr_vring) 16799a2dd95SBruce Richardson return -1; 16899a2dd95SBruce Richardson 16999a2dd95SBruce Richardson if (vq_is_packed(dev)) 17099a2dd95SBruce Richardson return -1; 17199a2dd95SBruce Richardson 17299a2dd95SBruce Richardson s_vring = (struct vring *)vring_m; 17399a2dd95SBruce Richardson vq = dev->virtqueue[qid]; 17499a2dd95SBruce Richardson idx = vq->used->idx; 17599a2dd95SBruce Richardson idx_m = s_vring->used->idx; 17699a2dd95SBruce Richardson ret = (uint16_t)(idx_m - idx); 177*b3f923feSBill Xiang vq->used->flags = s_vring->used->flags; 17899a2dd95SBruce Richardson 17999a2dd95SBruce Richardson while (idx != idx_m) { 18099a2dd95SBruce Richardson /* copy used entry, used ring logging is not covered here */ 18199a2dd95SBruce Richardson vq->used->ring[idx & (vq->size - 1)] = 18299a2dd95SBruce Richardson s_vring->used->ring[idx & (vq->size - 1)]; 18399a2dd95SBruce Richardson 18499a2dd95SBruce Richardson desc_id = vq->used->ring[idx & (vq->size - 1)].id; 18599a2dd95SBruce Richardson desc_ring = vq->desc; 18699a2dd95SBruce Richardson nr_descs = vq->size; 18799a2dd95SBruce Richardson 18899a2dd95SBruce Richardson if (unlikely(desc_id >= vq->size)) 18999a2dd95SBruce Richardson return -1; 19099a2dd95SBruce Richardson 19199a2dd95SBruce Richardson if (vq->desc[desc_id].flags & VRING_DESC_F_INDIRECT) { 19299a2dd95SBruce Richardson dlen = vq->desc[desc_id].len; 19399a2dd95SBruce Richardson nr_descs = dlen / sizeof(struct vring_desc); 19499a2dd95SBruce Richardson if (unlikely(nr_descs > vq->size)) 19599a2dd95SBruce Richardson return -1; 19699a2dd95SBruce Richardson 19719639c3bSHao Chen vhost_user_iotlb_rd_lock(vq); 19899a2dd95SBruce Richardson desc_ring = (struct vring_desc *)(uintptr_t) 19999a2dd95SBruce Richardson vhost_iova_to_vva(dev, vq, 20099a2dd95SBruce Richardson vq->desc[desc_id].addr, &dlen, 20199a2dd95SBruce Richardson VHOST_ACCESS_RO); 20219639c3bSHao Chen vhost_user_iotlb_rd_unlock(vq); 20399a2dd95SBruce Richardson if (unlikely(!desc_ring)) 20499a2dd95SBruce Richardson return -1; 20599a2dd95SBruce Richardson 20699a2dd95SBruce Richardson if (unlikely(dlen < vq->desc[desc_id].len)) { 20719639c3bSHao Chen vhost_user_iotlb_rd_lock(vq); 20899a2dd95SBruce Richardson idesc = vhost_alloc_copy_ind_table(dev, vq, 20999a2dd95SBruce Richardson vq->desc[desc_id].addr, 21099a2dd95SBruce Richardson vq->desc[desc_id].len); 21119639c3bSHao Chen vhost_user_iotlb_rd_unlock(vq); 21299a2dd95SBruce Richardson if (unlikely(!idesc)) 21399a2dd95SBruce Richardson return -1; 21499a2dd95SBruce Richardson 21599a2dd95SBruce Richardson desc_ring = idesc; 21699a2dd95SBruce Richardson } 21799a2dd95SBruce Richardson 21899a2dd95SBruce Richardson desc_id = 0; 21999a2dd95SBruce Richardson } 22099a2dd95SBruce Richardson 22199a2dd95SBruce Richardson /* dirty page logging for DMA writeable buffer */ 22299a2dd95SBruce Richardson do { 22399a2dd95SBruce Richardson if (unlikely(desc_id >= vq->size)) 22499a2dd95SBruce Richardson goto fail; 22599a2dd95SBruce Richardson if (unlikely(nr_descs-- == 0)) 22699a2dd95SBruce Richardson goto fail; 22799a2dd95SBruce Richardson desc = desc_ring[desc_id]; 22819639c3bSHao Chen if (desc.flags & VRING_DESC_F_WRITE) { 22919639c3bSHao Chen vhost_user_iotlb_rd_lock(vq); 23099a2dd95SBruce Richardson vhost_log_write_iova(dev, vq, desc.addr, 23199a2dd95SBruce Richardson desc.len); 23219639c3bSHao Chen vhost_user_iotlb_rd_unlock(vq); 23319639c3bSHao Chen } 23499a2dd95SBruce Richardson desc_id = desc.next; 23599a2dd95SBruce Richardson } while (desc.flags & VRING_DESC_F_NEXT); 23699a2dd95SBruce Richardson 23799a2dd95SBruce Richardson if (unlikely(idesc)) { 23899a2dd95SBruce Richardson free_ind_table(idesc); 23999a2dd95SBruce Richardson idesc = NULL; 24099a2dd95SBruce Richardson } 24199a2dd95SBruce Richardson 24299a2dd95SBruce Richardson idx++; 24399a2dd95SBruce Richardson } 24499a2dd95SBruce Richardson 24599a2dd95SBruce Richardson /* used idx is the synchronization point for the split vring */ 2465147b641STyler Retzlaff rte_atomic_store_explicit((unsigned short __rte_atomic *)&vq->used->idx, 2475147b641STyler Retzlaff idx_m, rte_memory_order_release); 24899a2dd95SBruce Richardson 24999a2dd95SBruce Richardson if (dev->features & (1ULL << VIRTIO_RING_F_EVENT_IDX)) 25099a2dd95SBruce Richardson vring_used_event(s_vring) = idx_m; 25199a2dd95SBruce Richardson 25299a2dd95SBruce Richardson return ret; 25399a2dd95SBruce Richardson 25499a2dd95SBruce Richardson fail: 25599a2dd95SBruce Richardson if (unlikely(idesc)) 25699a2dd95SBruce Richardson free_ind_table(idesc); 25799a2dd95SBruce Richardson return -1; 25899a2dd95SBruce Richardson } 25999a2dd95SBruce Richardson 26099a2dd95SBruce Richardson int 26199a2dd95SBruce Richardson rte_vdpa_get_queue_num(struct rte_vdpa_device *dev, uint32_t *queue_num) 26299a2dd95SBruce Richardson { 26399a2dd95SBruce Richardson if (dev == NULL || dev->ops == NULL || dev->ops->get_queue_num == NULL) 26499a2dd95SBruce Richardson return -1; 26599a2dd95SBruce Richardson 26699a2dd95SBruce Richardson return dev->ops->get_queue_num(dev, queue_num); 26799a2dd95SBruce Richardson } 26899a2dd95SBruce Richardson 26999a2dd95SBruce Richardson int 27099a2dd95SBruce Richardson rte_vdpa_get_features(struct rte_vdpa_device *dev, uint64_t *features) 27199a2dd95SBruce Richardson { 27299a2dd95SBruce Richardson if (dev == NULL || dev->ops == NULL || dev->ops->get_features == NULL) 27399a2dd95SBruce Richardson return -1; 27499a2dd95SBruce Richardson 27599a2dd95SBruce Richardson return dev->ops->get_features(dev, features); 27699a2dd95SBruce Richardson } 27799a2dd95SBruce Richardson 27899a2dd95SBruce Richardson int 27999a2dd95SBruce Richardson rte_vdpa_get_protocol_features(struct rte_vdpa_device *dev, uint64_t *features) 28099a2dd95SBruce Richardson { 28199a2dd95SBruce Richardson if (dev == NULL || dev->ops == NULL || 28299a2dd95SBruce Richardson dev->ops->get_protocol_features == NULL) 28399a2dd95SBruce Richardson return -1; 28499a2dd95SBruce Richardson 28599a2dd95SBruce Richardson return dev->ops->get_protocol_features(dev, features); 28699a2dd95SBruce Richardson } 28799a2dd95SBruce Richardson 28899a2dd95SBruce Richardson int 28999a2dd95SBruce Richardson rte_vdpa_get_stats_names(struct rte_vdpa_device *dev, 29099a2dd95SBruce Richardson struct rte_vdpa_stat_name *stats_names, 29199a2dd95SBruce Richardson unsigned int size) 29299a2dd95SBruce Richardson { 29399a2dd95SBruce Richardson if (!dev) 29499a2dd95SBruce Richardson return -EINVAL; 29599a2dd95SBruce Richardson 2968f1d23ecSDavid Marchand if (dev->ops->get_stats_names == NULL) 2978f1d23ecSDavid Marchand return -ENOTSUP; 29899a2dd95SBruce Richardson 29999a2dd95SBruce Richardson return dev->ops->get_stats_names(dev, stats_names, size); 30099a2dd95SBruce Richardson } 30199a2dd95SBruce Richardson 30299a2dd95SBruce Richardson int 30399a2dd95SBruce Richardson rte_vdpa_get_stats(struct rte_vdpa_device *dev, uint16_t qid, 30499a2dd95SBruce Richardson struct rte_vdpa_stat *stats, unsigned int n) 30599a2dd95SBruce Richardson { 30699a2dd95SBruce Richardson if (!dev || !stats || !n) 30799a2dd95SBruce Richardson return -EINVAL; 30899a2dd95SBruce Richardson 3098f1d23ecSDavid Marchand if (dev->ops->get_stats == NULL) 3108f1d23ecSDavid Marchand return -ENOTSUP; 31199a2dd95SBruce Richardson 31299a2dd95SBruce Richardson return dev->ops->get_stats(dev, qid, stats, n); 31399a2dd95SBruce Richardson } 31499a2dd95SBruce Richardson 31599a2dd95SBruce Richardson int 31699a2dd95SBruce Richardson rte_vdpa_reset_stats(struct rte_vdpa_device *dev, uint16_t qid) 31799a2dd95SBruce Richardson { 31899a2dd95SBruce Richardson if (!dev) 31999a2dd95SBruce Richardson return -EINVAL; 32099a2dd95SBruce Richardson 3218f1d23ecSDavid Marchand if (dev->ops->reset_stats == NULL) 3228f1d23ecSDavid Marchand return -ENOTSUP; 32399a2dd95SBruce Richardson 32499a2dd95SBruce Richardson return dev->ops->reset_stats(dev, qid); 32599a2dd95SBruce Richardson } 32699a2dd95SBruce Richardson 32799a2dd95SBruce Richardson static int 32899a2dd95SBruce Richardson vdpa_dev_match(struct rte_vdpa_device *dev, 32999a2dd95SBruce Richardson const struct rte_device *rte_dev) 33099a2dd95SBruce Richardson { 33199a2dd95SBruce Richardson if (dev->device == rte_dev) 33299a2dd95SBruce Richardson return 0; 33399a2dd95SBruce Richardson 33499a2dd95SBruce Richardson return -1; 33599a2dd95SBruce Richardson } 33699a2dd95SBruce Richardson 33799a2dd95SBruce Richardson /* Generic rte_vdpa_dev comparison function. */ 33899a2dd95SBruce Richardson typedef int (*rte_vdpa_cmp_t)(struct rte_vdpa_device *, 33999a2dd95SBruce Richardson const struct rte_device *rte_dev); 34099a2dd95SBruce Richardson 34199a2dd95SBruce Richardson static struct rte_vdpa_device * 34299a2dd95SBruce Richardson vdpa_find_device(const struct rte_vdpa_device *start, rte_vdpa_cmp_t cmp, 34399a2dd95SBruce Richardson struct rte_device *rte_dev) 34499a2dd95SBruce Richardson { 34599a2dd95SBruce Richardson struct rte_vdpa_device *dev; 34699a2dd95SBruce Richardson 34799a2dd95SBruce Richardson rte_spinlock_lock(&vdpa_device_list_lock); 34899a2dd95SBruce Richardson if (start == NULL) 349148303e2SDavid Marchand dev = TAILQ_FIRST(vdpa_device_list); 35099a2dd95SBruce Richardson else 35199a2dd95SBruce Richardson dev = TAILQ_NEXT(start, next); 35299a2dd95SBruce Richardson 35399a2dd95SBruce Richardson while (dev != NULL) { 35499a2dd95SBruce Richardson if (cmp(dev, rte_dev) == 0) 35599a2dd95SBruce Richardson break; 35699a2dd95SBruce Richardson 35799a2dd95SBruce Richardson dev = TAILQ_NEXT(dev, next); 35899a2dd95SBruce Richardson } 35999a2dd95SBruce Richardson rte_spinlock_unlock(&vdpa_device_list_lock); 36099a2dd95SBruce Richardson 36199a2dd95SBruce Richardson return dev; 36299a2dd95SBruce Richardson } 36399a2dd95SBruce Richardson 36499a2dd95SBruce Richardson static void * 36599a2dd95SBruce Richardson vdpa_dev_iterate(const void *start, 36699a2dd95SBruce Richardson const char *str, 36799a2dd95SBruce Richardson const struct rte_dev_iterator *it) 36899a2dd95SBruce Richardson { 36999a2dd95SBruce Richardson struct rte_vdpa_device *vdpa_dev = NULL; 37099a2dd95SBruce Richardson 37199a2dd95SBruce Richardson RTE_SET_USED(str); 37299a2dd95SBruce Richardson 37399a2dd95SBruce Richardson vdpa_dev = vdpa_find_device(start, vdpa_dev_match, it->device); 37499a2dd95SBruce Richardson 37599a2dd95SBruce Richardson return vdpa_dev; 37699a2dd95SBruce Richardson } 37799a2dd95SBruce Richardson 37899a2dd95SBruce Richardson static struct rte_class rte_class_vdpa = { 37999a2dd95SBruce Richardson .dev_iterate = vdpa_dev_iterate, 38099a2dd95SBruce Richardson }; 38199a2dd95SBruce Richardson 38299a2dd95SBruce Richardson RTE_REGISTER_CLASS(vdpa, rte_class_vdpa); 383