X-Git-Url: http://git.droids-corp.org/?a=blobdiff_plain;f=drivers%2Fnet%2Fvirtio%2Fvirtio_user_ethdev.c;h=3fc1725736b5f4c82d7517040c1b59b986de369e;hb=939aa0df044d856d36b0eb44231f03dc28ede6aa;hp=57c964d6d88ee7ba006adf6d8c1892251b75ab81;hpb=0964936308cdbe7a22927f8aee558e746a23d730;p=dpdk.git diff --git a/drivers/net/virtio/virtio_user_ethdev.c b/drivers/net/virtio/virtio_user_ethdev.c index 57c964d6d8..3fc1725736 100644 --- a/drivers/net/virtio/virtio_user_ethdev.c +++ b/drivers/net/virtio/virtio_user_ethdev.c @@ -1,34 +1,5 @@ -/*- - * BSD LICENSE - * - * Copyright(c) 2010-2016 Intel Corporation. All rights reserved. - * All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * - * * Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * * Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in - * the documentation and/or other materials provided with the - * distribution. - * * Neither the name of Intel Corporation nor the names of its - * contributors may be used to endorse or promote products derived - * from this software without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS - * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT - * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR - * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT - * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, - * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT - * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, - * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY - * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE - * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +/* SPDX-License-Identifier: BSD-3-Clause + * Copyright(c) 2010-2016 Intel Corporation */ #include @@ -40,7 +11,7 @@ #include #include #include -#include +#include #include #include "virtio_ethdev.h" @@ -49,19 +20,95 @@ #include "virtqueue.h" #include "virtio_rxtx.h" #include "virtio_user/virtio_user_dev.h" +#include "virtio_user/vhost.h" #define virtio_user_get_dev(hw) \ ((struct virtio_user_dev *)(hw)->virtio_user_dev) +static int +virtio_user_server_reconnect(struct virtio_user_dev *dev) +{ + int ret; + int connectfd; + struct rte_eth_dev *eth_dev = &rte_eth_devices[dev->port_id]; + + connectfd = accept(dev->listenfd, NULL, NULL); + if (connectfd < 0) + return -1; + + dev->vhostfd = connectfd; + if (dev->ops->send_request(dev, VHOST_USER_GET_FEATURES, + &dev->device_features) < 0) { + PMD_INIT_LOG(ERR, "get_features failed: %s", + strerror(errno)); + return -1; + } + + dev->device_features |= dev->frontend_features; + + /* umask vhost-user unsupported features */ + dev->device_features &= ~(dev->unsupported_features); + + dev->features &= dev->device_features; + + ret = virtio_user_start_device(dev); + if (ret < 0) + return -1; + + if (dev->queue_pairs > 1) { + ret = virtio_user_handle_mq(dev, dev->queue_pairs); + if (ret != 0) { + PMD_INIT_LOG(ERR, "Fails to enable multi-queue pairs!"); + return -1; + } + } + if (eth_dev->data->dev_flags & RTE_ETH_DEV_INTR_LSC) { + if (rte_intr_disable(eth_dev->intr_handle) < 0) { + PMD_DRV_LOG(ERR, "interrupt disable failed"); + return -1; + } + rte_intr_callback_unregister(eth_dev->intr_handle, + virtio_interrupt_handler, + eth_dev); + eth_dev->intr_handle->fd = connectfd; + rte_intr_callback_register(eth_dev->intr_handle, + virtio_interrupt_handler, eth_dev); + + if (rte_intr_enable(eth_dev->intr_handle) < 0) { + PMD_DRV_LOG(ERR, "interrupt enable failed"); + return -1; + } + } + PMD_INIT_LOG(NOTICE, "server mode virtio-user reconnection succeeds!"); + return 0; +} + static void virtio_user_delayed_handler(void *param) { struct virtio_hw *hw = (struct virtio_hw *)param; - struct rte_eth_dev *dev = &rte_eth_devices[hw->port_id]; + struct rte_eth_dev *eth_dev = &rte_eth_devices[hw->port_id]; + struct virtio_user_dev *dev = virtio_user_get_dev(hw); - rte_intr_callback_unregister(dev->intr_handle, - virtio_interrupt_handler, - dev); + if (rte_intr_disable(eth_dev->intr_handle) < 0) { + PMD_DRV_LOG(ERR, "interrupt disable failed"); + return; + } + rte_intr_callback_unregister(eth_dev->intr_handle, + virtio_interrupt_handler, eth_dev); + if (dev->is_server) { + if (dev->vhostfd >= 0) { + close(dev->vhostfd); + dev->vhostfd = -1; + } + eth_dev->intr_handle->fd = dev->listenfd; + rte_intr_callback_register(eth_dev->intr_handle, + virtio_interrupt_handler, eth_dev); + if (rte_intr_enable(eth_dev->intr_handle) < 0) { + PMD_DRV_LOG(ERR, "interrupt enable failed"); + return; + } + } } static void @@ -72,8 +119,8 @@ virtio_user_read_dev_config(struct virtio_hw *hw, size_t offset, struct virtio_user_dev *dev = virtio_user_get_dev(hw); if (offset == offsetof(struct virtio_net_config, mac) && - length == ETHER_ADDR_LEN) { - for (i = 0; i < ETHER_ADDR_LEN; ++i) + length == RTE_ETHER_ADDR_LEN) { + for (i = 0; i < RTE_ETHER_ADDR_LEN; ++i) ((uint8_t *)dst)[i] = dev->mac_addr[i]; return; } @@ -86,18 +133,20 @@ virtio_user_read_dev_config(struct virtio_hw *hw, size_t offset, int flags; flags = fcntl(dev->vhostfd, F_GETFL); - fcntl(dev->vhostfd, F_SETFL, flags | O_NONBLOCK); + if (fcntl(dev->vhostfd, F_SETFL, + flags | O_NONBLOCK) == -1) { + PMD_DRV_LOG(ERR, "error setting O_NONBLOCK flag"); + return; + } r = recv(dev->vhostfd, buf, 128, MSG_PEEK); if (r == 0 || (r < 0 && errno != EAGAIN)) { dev->status &= (~VIRTIO_NET_S_LINK_UP); PMD_DRV_LOG(ERR, "virtio-user port %u is down", hw->port_id); - /* Only client mode is available now. Once the - * connection is broken, it can never be up - * again. Besides, this function could be called - * in the process of interrupt handling, - * callback cannot be unregistered here, set an - * alarm to do it. + + /* This function could be called in the process + * of interrupt handling, callback cannot be + * unregistered here, set an alarm to do it. */ rte_eal_alarm_set(1, virtio_user_delayed_handler, @@ -105,8 +154,17 @@ virtio_user_read_dev_config(struct virtio_hw *hw, size_t offset, } else { dev->status |= VIRTIO_NET_S_LINK_UP; } - fcntl(dev->vhostfd, F_SETFL, flags & (~O_NONBLOCK)); + if (fcntl(dev->vhostfd, F_SETFL, + flags & ~O_NONBLOCK) == -1) { + PMD_DRV_LOG(ERR, "error clearing O_NONBLOCK flag"); + return; + } + } else if (dev->is_server) { + dev->status &= (~VIRTIO_NET_S_LINK_UP); + if (virtio_user_server_reconnect(dev) >= 0) + dev->status |= VIRTIO_NET_S_LINK_UP; } + *(uint16_t *)dst = dev->status; } @@ -122,8 +180,8 @@ virtio_user_write_dev_config(struct virtio_hw *hw, size_t offset, struct virtio_user_dev *dev = virtio_user_get_dev(hw); if ((offset == offsetof(struct virtio_net_config, mac)) && - (length == ETHER_ADDR_LEN)) - for (i = 0; i < ETHER_ADDR_LEN; ++i) + (length == RTE_ETHER_ADDR_LEN)) + for (i = 0; i < RTE_ETHER_ADDR_LEN; ++i) dev->mac_addr[i] = ((const uint8_t *)src)[i]; else PMD_DRV_LOG(ERR, "not supported offset=%zu, len=%d", @@ -214,10 +272,38 @@ virtio_user_get_queue_num(struct virtio_hw *hw, uint16_t queue_id __rte_unused) return dev->queue_size; } -static int -virtio_user_setup_queue(struct virtio_hw *hw, struct virtqueue *vq) +static void +virtio_user_setup_queue_packed(struct virtqueue *vq, + struct virtio_user_dev *dev) +{ + uint16_t queue_idx = vq->vq_queue_index; + struct vring_packed *vring; + uint64_t desc_addr; + uint64_t avail_addr; + uint64_t used_addr; + uint16_t i; + + vring = &dev->packed_vrings[queue_idx]; + desc_addr = (uintptr_t)vq->vq_ring_virt_mem; + avail_addr = desc_addr + vq->vq_nentries * + sizeof(struct vring_packed_desc); + used_addr = RTE_ALIGN_CEIL(avail_addr + + sizeof(struct vring_packed_desc_event), + VIRTIO_PCI_VRING_ALIGN); + vring->num = vq->vq_nentries; + vring->desc = (void *)(uintptr_t)desc_addr; + vring->driver = (void *)(uintptr_t)avail_addr; + vring->device = (void *)(uintptr_t)used_addr; + dev->packed_queues[queue_idx].avail_wrap_counter = true; + dev->packed_queues[queue_idx].used_wrap_counter = true; + + for (i = 0; i < vring->num; i++) + vring->desc[i].flags = 0; +} + +static void +virtio_user_setup_queue_split(struct virtqueue *vq, struct virtio_user_dev *dev) { - struct virtio_user_dev *dev = virtio_user_get_dev(hw); uint16_t queue_idx = vq->vq_queue_index; uint64_t desc_addr, avail_addr, used_addr; @@ -231,6 +317,17 @@ virtio_user_setup_queue(struct virtio_hw *hw, struct virtqueue *vq) dev->vrings[queue_idx].desc = (void *)(uintptr_t)desc_addr; dev->vrings[queue_idx].avail = (void *)(uintptr_t)avail_addr; dev->vrings[queue_idx].used = (void *)(uintptr_t)used_addr; +} + +static int +virtio_user_setup_queue(struct virtio_hw *hw, struct virtqueue *vq) +{ + struct virtio_user_dev *dev = virtio_user_get_dev(hw); + + if (vtpci_packed_queue(hw)) + virtio_user_setup_queue_packed(vq, dev); + else + virtio_user_setup_queue_split(vq, dev); return 0; } @@ -260,7 +357,10 @@ virtio_user_notify_queue(struct virtio_hw *hw, struct virtqueue *vq) struct virtio_user_dev *dev = virtio_user_get_dev(hw); if (hw->cvq && (hw->cvq->vq == vq)) { - virtio_user_handle_cq(dev, vq->vq_queue_index); + if (vtpci_packed_queue(vq->hw)) + virtio_user_handle_cq_packed(dev, vq->vq_queue_index); + else + virtio_user_handle_cq(dev, vq->vq_queue_index); return; } @@ -272,7 +372,6 @@ virtio_user_notify_queue(struct virtio_hw *hw, struct virtqueue *vq) const struct virtio_pci_ops virtio_user_ops = { .read_dev_cfg = virtio_user_read_dev_config, .write_dev_cfg = virtio_user_write_dev_config, - .reset = virtio_user_reset, .get_status = virtio_user_get_status, .set_status = virtio_user_set_status, .get_features = virtio_user_get_features, @@ -299,12 +398,21 @@ static const char *valid_args[] = { VIRTIO_USER_ARG_QUEUE_SIZE, #define VIRTIO_USER_ARG_INTERFACE_NAME "iface" VIRTIO_USER_ARG_INTERFACE_NAME, +#define VIRTIO_USER_ARG_SERVER_MODE "server" + VIRTIO_USER_ARG_SERVER_MODE, +#define VIRTIO_USER_ARG_MRG_RXBUF "mrg_rxbuf" + VIRTIO_USER_ARG_MRG_RXBUF, +#define VIRTIO_USER_ARG_IN_ORDER "in_order" + VIRTIO_USER_ARG_IN_ORDER, +#define VIRTIO_USER_ARG_PACKED_VQ "packed_vq" + VIRTIO_USER_ARG_PACKED_VQ, NULL }; #define VIRTIO_USER_DEF_CQ_EN 0 #define VIRTIO_USER_DEF_Q_NUM 1 #define VIRTIO_USER_DEF_Q_SZ 256 +#define VIRTIO_USER_DEF_SERVER_MODE 0 static int get_string_arg(const char *key __rte_unused, @@ -333,8 +441,6 @@ get_integer_arg(const char *key __rte_unused, return 0; } -static struct rte_vdev_driver virtio_user_driver; - static struct rte_eth_dev * virtio_user_eth_dev_alloc(struct rte_vdev_device *vdev) { @@ -356,7 +462,6 @@ virtio_user_eth_dev_alloc(struct rte_vdev_device *vdev) if (!dev) { PMD_INIT_LOG(ERR, "malloc virtio_user_dev failed"); rte_eth_dev_release_port(eth_dev); - rte_free(hw); return NULL; } @@ -370,9 +475,9 @@ virtio_user_eth_dev_alloc(struct rte_vdev_device *vdev) hw->use_msix = 1; hw->modern = 0; hw->use_simple_rx = 0; - hw->use_simple_tx = 0; + hw->use_inorder_rx = 0; + hw->use_inorder_tx = 0; hw->virtio_user_dev = dev; - data->dev_flags = RTE_ETH_DEV_DETACHABLE; return eth_dev; } @@ -383,7 +488,6 @@ virtio_user_eth_dev_free(struct rte_eth_dev *eth_dev) struct virtio_hw *hw = data->dev_private; rte_free(hw->virtio_user_dev); - rte_free(hw); rte_eth_dev_release_port(eth_dev); } @@ -400,11 +504,35 @@ virtio_user_pmd_probe(struct rte_vdev_device *dev) 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; + uint64_t server_mode = VIRTIO_USER_DEF_SERVER_MODE; + uint64_t mrg_rxbuf = 1; + uint64_t in_order = 1; + uint64_t packed_vq = 0; char *path = NULL; char *ifname = NULL; char *mac_addr = NULL; int ret = -1; + if (rte_eal_process_type() == RTE_PROC_SECONDARY) { + const char *name = rte_vdev_device_name(dev); + eth_dev = rte_eth_dev_attach_secondary(name); + if (!eth_dev) { + RTE_LOG(ERR, PMD, "Failed to probe %s\n", name); + return -1; + } + + if (eth_virtio_dev_init(eth_dev) < 0) { + PMD_INIT_LOG(ERR, "eth_virtio_dev_init fails"); + rte_eth_dev_release_port(eth_dev); + return -1; + } + + eth_dev->dev_ops = &virtio_user_secondary_eth_dev_ops; + eth_dev->device = &dev->device; + rte_eth_dev_probing_finish(eth_dev); + return 0; + } + kvlist = rte_kvargs_parse(rte_vdev_device_args(dev), valid_args); if (!kvlist) { PMD_INIT_LOG(ERR, "error when parsing param"); @@ -420,7 +548,7 @@ virtio_user_pmd_probe(struct rte_vdev_device *dev) } } else { PMD_INIT_LOG(ERR, "arg %s is mandatory for virtio_user", - VIRTIO_USER_ARG_QUEUE_SIZE); + VIRTIO_USER_ARG_PATH); goto end; } @@ -467,6 +595,15 @@ virtio_user_pmd_probe(struct rte_vdev_device *dev) } } + if (rte_kvargs_count(kvlist, VIRTIO_USER_ARG_SERVER_MODE) == 1) { + if (rte_kvargs_process(kvlist, VIRTIO_USER_ARG_SERVER_MODE, + &get_integer_arg, &server_mode) < 0) { + PMD_INIT_LOG(ERR, "error to parse %s", + VIRTIO_USER_ARG_SERVER_MODE); + goto end; + } + } + if (rte_kvargs_count(kvlist, VIRTIO_USER_ARG_CQ_NUM) == 1) { if (rte_kvargs_process(kvlist, VIRTIO_USER_ARG_CQ_NUM, &get_integer_arg, &cq) < 0) { @@ -478,6 +615,15 @@ virtio_user_pmd_probe(struct rte_vdev_device *dev) cq = 1; } + if (rte_kvargs_count(kvlist, VIRTIO_USER_ARG_PACKED_VQ) == 1) { + if (rte_kvargs_process(kvlist, VIRTIO_USER_ARG_PACKED_VQ, + &get_integer_arg, &packed_vq) < 0) { + PMD_INIT_LOG(ERR, "error to parse %s", + VIRTIO_USER_ARG_PACKED_VQ); + goto end; + } + } + if (queues > 1 && cq == 0) { PMD_INIT_LOG(ERR, "multi-q requires ctrl-q"); goto end; @@ -490,24 +636,37 @@ virtio_user_pmd_probe(struct rte_vdev_device *dev) goto end; } - if (rte_eal_process_type() == RTE_PROC_PRIMARY) { - eth_dev = virtio_user_eth_dev_alloc(dev); - if (!eth_dev) { - PMD_INIT_LOG(ERR, "virtio_user fails to alloc device"); + if (rte_kvargs_count(kvlist, VIRTIO_USER_ARG_MRG_RXBUF) == 1) { + if (rte_kvargs_process(kvlist, VIRTIO_USER_ARG_MRG_RXBUF, + &get_integer_arg, &mrg_rxbuf) < 0) { + PMD_INIT_LOG(ERR, "error to parse %s", + VIRTIO_USER_ARG_MRG_RXBUF); goto end; } + } - hw = eth_dev->data->dev_private; - if (virtio_user_dev_init(hw->virtio_user_dev, path, queues, cq, - queue_size, mac_addr, &ifname) < 0) { - PMD_INIT_LOG(ERR, "virtio_user_dev_init fails"); - virtio_user_eth_dev_free(eth_dev); + if (rte_kvargs_count(kvlist, VIRTIO_USER_ARG_IN_ORDER) == 1) { + if (rte_kvargs_process(kvlist, VIRTIO_USER_ARG_IN_ORDER, + &get_integer_arg, &in_order) < 0) { + PMD_INIT_LOG(ERR, "error to parse %s", + VIRTIO_USER_ARG_IN_ORDER); goto end; } - } else { - eth_dev = rte_eth_dev_attach_secondary(rte_vdev_device_name(dev)); - if (!eth_dev) - goto end; + } + + eth_dev = virtio_user_eth_dev_alloc(dev); + if (!eth_dev) { + PMD_INIT_LOG(ERR, "virtio_user fails to alloc device"); + goto end; + } + + 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) { + PMD_INIT_LOG(ERR, "virtio_user_dev_init fails"); + virtio_user_eth_dev_free(eth_dev); + goto end; } /* previously called by rte_pci_probe() for physical dev */ @@ -516,6 +675,8 @@ virtio_user_pmd_probe(struct rte_vdev_device *dev) virtio_user_eth_dev_free(eth_dev); goto end; } + + rte_eth_dev_probing_finish(eth_dev); ret = 0; end: @@ -530,14 +691,11 @@ end: return ret; } -/** Called by rte_eth_dev_detach() */ static int virtio_user_pmd_remove(struct rte_vdev_device *vdev) { const char *name; struct rte_eth_dev *eth_dev; - struct virtio_hw *hw; - struct virtio_user_dev *dev; if (!vdev) return -EINVAL; @@ -545,19 +703,16 @@ virtio_user_pmd_remove(struct rte_vdev_device *vdev) name = rte_vdev_device_name(vdev); PMD_DRV_LOG(INFO, "Un-Initializing %s", name); eth_dev = rte_eth_dev_allocated(name); + /* Port has already been released by close. */ if (!eth_dev) - return -ENODEV; + return 0; + + if (rte_eal_process_type() != RTE_PROC_PRIMARY) + return rte_eth_dev_release_port(eth_dev); /* make sure the device is stopped, queues freed */ rte_eth_dev_close(eth_dev->data->port_id); - hw = eth_dev->data->dev_private; - dev = hw->virtio_user_dev; - virtio_user_dev_uninit(dev); - - rte_free(eth_dev->data->dev_private); - rte_eth_dev_release_port(eth_dev); - return 0; } @@ -574,4 +729,8 @@ RTE_PMD_REGISTER_PARAM_STRING(net_virtio_user, "cq= " "queue_size= " "queues= " - "iface="); + "iface= " + "server=<0|1> " + "mrg_rxbuf=<0|1> " + "in_order=<0|1> " + "packed_vq=<0|1>");