X-Git-Url: http://git.droids-corp.org/?a=blobdiff_plain;f=drivers%2Fnet%2Fvirtio%2Fvirtio_user_ethdev.c;h=f56fc238c466e3ee9b7021661d0a41963aea2961;hb=dd6d6704f5b83e42af6ef3674a54ce7fb80d0254;hp=798f191c32262afd0bad6dd32aec2599dfa2709d;hpb=01996a034a78db79686238a9656f8a49367fe963;p=dpdk.git diff --git a/drivers/net/virtio/virtio_user_ethdev.c b/drivers/net/virtio/virtio_user_ethdev.c index 798f191c32..f56fc238c4 100644 --- a/drivers/net/virtio/virtio_user_ethdev.c +++ b/drivers/net/virtio/virtio_user_ethdev.c @@ -6,6 +6,9 @@ #include #include #include +#include +#include +#include #include #include @@ -68,6 +71,7 @@ virtio_user_server_reconnect(struct virtio_user_dev *dev) int connectfd; struct rte_eth_dev *eth_dev = &rte_eth_devices[dev->port_id]; struct virtio_hw *hw = eth_dev->data->dev_private; + uint64_t protocol_features; connectfd = accept(dev->listenfd, NULL, NULL); if (connectfd < 0) @@ -81,6 +85,25 @@ virtio_user_server_reconnect(struct virtio_user_dev *dev) return -1; } + if (dev->device_features & + (1ULL << VHOST_USER_F_PROTOCOL_FEATURES)) { + if (dev->ops->send_request(dev, + VHOST_USER_GET_PROTOCOL_FEATURES, + &protocol_features)) + return -1; + + dev->protocol_features &= protocol_features; + + if (dev->ops->send_request(dev, + VHOST_USER_SET_PROTOCOL_FEATURES, + &dev->protocol_features)) + return -1; + + if (!(dev->protocol_features & + (1ULL << VHOST_USER_PROTOCOL_F_MQ))) + dev->unsupported_features |= (1ull << VIRTIO_NET_F_MQ); + } + dev->device_features |= dev->frontend_features; /* umask vhost-user unsupported features */ @@ -185,7 +208,7 @@ virtio_user_read_dev_config(struct virtio_hw *hw, size_t offset, } r = recv(dev->vhostfd, buf, 128, MSG_PEEK); if (r == 0 || (r < 0 && errno != EAGAIN)) { - dev->status &= (~VIRTIO_NET_S_LINK_UP); + dev->net_status &= (~VIRTIO_NET_S_LINK_UP); PMD_DRV_LOG(ERR, "virtio-user port %u is down", hw->port_id); @@ -197,7 +220,7 @@ virtio_user_read_dev_config(struct virtio_hw *hw, size_t offset, virtio_user_delayed_handler, (void *)hw); } else { - dev->status |= VIRTIO_NET_S_LINK_UP; + dev->net_status |= VIRTIO_NET_S_LINK_UP; } if (fcntl(dev->vhostfd, F_SETFL, flags & ~O_NONBLOCK) == -1) { @@ -205,12 +228,12 @@ virtio_user_read_dev_config(struct virtio_hw *hw, size_t offset, return; } } else if (dev->is_server) { - dev->status &= (~VIRTIO_NET_S_LINK_UP); + dev->net_status &= (~VIRTIO_NET_S_LINK_UP); if (virtio_user_server_reconnect(dev) >= 0) - dev->status |= VIRTIO_NET_S_LINK_UP; + dev->net_status |= VIRTIO_NET_S_LINK_UP; } - *(uint16_t *)dst = dev->status; + *(uint16_t *)dst = dev->net_status; } if (offset == offsetof(struct virtio_net_config, max_virtqueue_pairs)) @@ -246,12 +269,17 @@ static void virtio_user_set_status(struct virtio_hw *hw, uint8_t status) { struct virtio_user_dev *dev = virtio_user_get_dev(hw); + uint8_t old_status = dev->status; + if (status & VIRTIO_CONFIG_STATUS_FEATURES_OK && + ~old_status & VIRTIO_CONFIG_STATUS_FEATURES_OK) + virtio_user_dev_set_features(dev); if (status & VIRTIO_CONFIG_STATUS_DRIVER_OK) virtio_user_start_device(dev); else if (status == VIRTIO_CONFIG_STATUS_RESET) virtio_user_reset(hw); dev->status = status; + virtio_user_send_status_update(dev, status); } static uint8_t @@ -259,6 +287,8 @@ virtio_user_get_status(struct virtio_hw *hw) { struct virtio_user_dev *dev = virtio_user_get_dev(hw); + virtio_user_update_status(dev); + return dev->status; } @@ -495,6 +525,57 @@ get_integer_arg(const char *key __rte_unused, return -errno; } +static uint32_t +vdpa_dynamic_major_num(void) +{ + FILE *fp; + char *line = NULL; + size_t size; + char name[11]; + bool found = false; + uint32_t num; + + fp = fopen("/proc/devices", "r"); + if (fp == NULL) { + PMD_INIT_LOG(ERR, "Cannot open /proc/devices: %s", + strerror(errno)); + return UNNAMED_MAJOR; + } + + while (getline(&line, &size, fp) > 0) { + char *stripped = line + strspn(line, " "); + if ((sscanf(stripped, "%u %10s", &num, name) == 2) && + (strncmp(name, "vhost-vdpa", 10) == 0)) { + found = true; + break; + } + } + fclose(fp); + return found ? num : UNNAMED_MAJOR; +} + +static enum virtio_user_backend_type +virtio_user_backend_type(const char *path) +{ + struct stat sb; + + if (stat(path, &sb) == -1) { + PMD_INIT_LOG(ERR, "Stat fails: %s (%s)\n", path, + strerror(errno)); + return VIRTIO_USER_BACKEND_UNKNOWN; + } + + if (S_ISSOCK(sb.st_mode)) { + return VIRTIO_USER_BACKEND_VHOST_USER; + } else if (S_ISCHR(sb.st_mode)) { + if (major(sb.st_rdev) == MISC_MAJOR) + return VIRTIO_USER_BACKEND_VHOST_KERNEL; + if (major(sb.st_rdev) == vdpa_dynamic_major_num()) + return VIRTIO_USER_BACKEND_VHOST_VDPA; + } + return VIRTIO_USER_BACKEND_UNKNOWN; +} + static struct rte_eth_dev * virtio_user_eth_dev_alloc(struct rte_vdev_device *vdev) { @@ -556,6 +637,7 @@ virtio_user_pmd_probe(struct rte_vdev_device *dev) struct rte_kvargs *kvlist = NULL; struct rte_eth_dev *eth_dev; struct virtio_hw *hw; + enum virtio_user_backend_type backend_type = VIRTIO_USER_BACKEND_UNKNOWN; uint64_t queues = VIRTIO_USER_DEF_Q_NUM; uint64_t cq = VIRTIO_USER_DEF_CQ_EN; uint64_t queue_size = VIRTIO_USER_DEF_Q_SZ; @@ -608,8 +690,17 @@ virtio_user_pmd_probe(struct rte_vdev_device *dev) goto end; } + backend_type = virtio_user_backend_type(path); + if (backend_type == VIRTIO_USER_BACKEND_UNKNOWN) { + PMD_INIT_LOG(ERR, + "unable to determine backend type for path %s", + path); + goto end; + } + + if (rte_kvargs_count(kvlist, VIRTIO_USER_ARG_INTERFACE_NAME) == 1) { - if (is_vhost_user_by_type(path)) { + if (backend_type != VIRTIO_USER_BACKEND_VHOST_KERNEL) { PMD_INIT_LOG(ERR, "arg %s applies only to vhost-kernel backend", VIRTIO_USER_ARG_INTERFACE_NAME); @@ -728,7 +819,7 @@ virtio_user_pmd_probe(struct rte_vdev_device *dev) hw = eth_dev->data->dev_private; if (virtio_user_dev_init(hw->virtio_user_dev, path, queues, cq, queue_size, mac_addr, &ifname, server_mode, - mrg_rxbuf, in_order, packed_vq) < 0) { + mrg_rxbuf, in_order, packed_vq, backend_type) < 0) { PMD_INIT_LOG(ERR, "virtio_user_dev_init fails"); virtio_user_eth_dev_free(eth_dev); goto end; @@ -795,9 +886,63 @@ virtio_user_pmd_remove(struct rte_vdev_device *vdev) return 0; } +static int virtio_user_pmd_dma_map(struct rte_vdev_device *vdev, void *addr, + uint64_t iova, size_t len) +{ + const char *name; + struct rte_eth_dev *eth_dev; + struct virtio_user_dev *dev; + struct virtio_hw *hw; + + if (!vdev) + return -EINVAL; + + name = rte_vdev_device_name(vdev); + eth_dev = rte_eth_dev_allocated(name); + /* Port has already been released by close. */ + if (!eth_dev) + return 0; + + hw = (struct virtio_hw *)eth_dev->data->dev_private; + dev = hw->virtio_user_dev; + + if (dev->ops->dma_map) + return dev->ops->dma_map(dev, addr, iova, len); + + return 0; +} + +static int virtio_user_pmd_dma_unmap(struct rte_vdev_device *vdev, void *addr, + uint64_t iova, size_t len) +{ + const char *name; + struct rte_eth_dev *eth_dev; + struct virtio_user_dev *dev; + struct virtio_hw *hw; + + if (!vdev) + return -EINVAL; + + name = rte_vdev_device_name(vdev); + eth_dev = rte_eth_dev_allocated(name); + /* Port has already been released by close. */ + if (!eth_dev) + return 0; + + hw = (struct virtio_hw *)eth_dev->data->dev_private; + dev = hw->virtio_user_dev; + + if (dev->ops->dma_unmap) + return dev->ops->dma_unmap(dev, addr, iova, len); + + return 0; +} + static struct rte_vdev_driver virtio_user_driver = { .probe = virtio_user_pmd_probe, .remove = virtio_user_pmd_remove, + .dma_map = virtio_user_pmd_dma_map, + .dma_unmap = virtio_user_pmd_dma_unmap, }; RTE_PMD_REGISTER_VDEV(net_virtio_user, virtio_user_driver);