From: Jianfeng Tan Date: Wed, 15 Jun 2016 09:38:36 +0000 (+0800) Subject: net/virtio-user: add multiple queues in device emulation X-Git-Url: http://git.droids-corp.org/?a=commitdiff_plain;h=f9b9d1a55775db1e0d909cef7392c20dc96f075d;p=dpdk.git net/virtio-user: add multiple queues in device emulation The main purpose of this patch is to enable multi-queue. But multi-queue requires ctrl-queue so that driver can send how many queues will be enabled through ctrl-queue messages. So we partially implement ctrl-queue to handle control command with class of VIRTIO_NET_CTRL_MQ and with cmd of VIRTIO_NET_CTRL_MQ_VQ_PAIRS_SET to handle mq support. This patch provides a function, virtio_user_handle_cq(), for driver to handle ctrl-queue messages. Besides, multi-queue requires VIRTIO_NET_F_MQ and VIRTIO_NET_F_CTRL_VQ are enabled when we do feature negotiation. Signed-off-by: Jianfeng Tan Acked-by: Yuanhan Liu --- diff --git a/drivers/net/virtio/virtio_user/virtio_user_dev.c b/drivers/net/virtio/virtio_user/virtio_user_dev.c index c4ba437c44..3d12a320ba 100644 --- a/drivers/net/virtio/virtio_user/virtio_user_dev.c +++ b/drivers/net/virtio/virtio_user/virtio_user_dev.c @@ -131,11 +131,14 @@ virtio_user_start_device(struct virtio_user_dev *dev) } } - /* After setup all virtqueues, we need to set_features so that - * these features can be set into each virtqueue in vhost side. - * And before that, make sure VIRTIO_NET_F_MAC is stripped. + /* After setup all virtqueues, we need to set_features so that these + * features can be set into each virtqueue in vhost side. And before + * that, make sure VHOST_USER_F_PROTOCOL_FEATURES is added if mq is + * enabled, and VIRTIO_NET_F_MAC is stripped. */ features = dev->features; + if (dev->max_queue_pairs > 1) + features |= VHOST_USER_MQ; features &= ~(1ull << VIRTIO_NET_F_MAC); ret = vhost_user_sock(dev->vhostfd, VHOST_USER_SET_FEATURES, &features); if (ret < 0) @@ -185,8 +188,6 @@ virtio_user_dev_init(struct virtio_user_dev *dev, char *path, int queues, dev->mac_specified = 0; parse_mac(dev, mac); dev->vhostfd = -1; - /* TODO: cq */ - RTE_SET_USED(cq); dev->vhostfd = vhost_user_setup(dev->path); if (dev->vhostfd < 0) { @@ -205,9 +206,31 @@ virtio_user_dev_init(struct virtio_user_dev *dev, char *path, int queues, } if (dev->mac_specified) dev->features |= (1ull << VIRTIO_NET_F_MAC); - /* disable it until we support CQ */ - dev->features &= ~(1ull << VIRTIO_NET_F_CTRL_VQ); - dev->features &= ~(1ull << VIRTIO_NET_F_CTRL_RX); + + if (!cq) { + dev->features &= ~(1ull << VIRTIO_NET_F_CTRL_VQ); + /* Also disable features depends on VIRTIO_NET_F_CTRL_VQ */ + dev->features &= ~(1ull << VIRTIO_NET_F_CTRL_RX); + dev->features &= ~(1ull << VIRTIO_NET_F_CTRL_VLAN); + dev->features &= ~(1ull << VIRTIO_NET_F_GUEST_ANNOUNCE); + dev->features &= ~(1ull << VIRTIO_NET_F_MQ); + dev->features &= ~(1ull << VIRTIO_NET_F_CTRL_MAC_ADDR); + } else { + /* vhost user backend does not need to know ctrl-q, so + * actually we need add this bit into features. However, + * DPDK vhost-user does send features with this bit, so we + * check it instead of OR it for now. + */ + if (!(dev->features & (1ull << VIRTIO_NET_F_CTRL_VQ))) + PMD_INIT_LOG(INFO, "vhost does not support ctrl-q"); + } + + if (dev->max_queue_pairs > 1) { + if (!(dev->features & VHOST_USER_MQ)) { + PMD_INIT_LOG(ERR, "MQ not supported by the backend"); + return -1; + } + } return 0; } @@ -224,3 +247,87 @@ virtio_user_dev_uninit(struct virtio_user_dev *dev) close(dev->vhostfd); } + +static uint8_t +virtio_user_handle_mq(struct virtio_user_dev *dev, uint16_t q_pairs) +{ + uint16_t i; + uint8_t ret = 0; + + if (q_pairs > dev->max_queue_pairs) { + PMD_INIT_LOG(ERR, "multi-q config %u, but only %u supported", + q_pairs, dev->max_queue_pairs); + return -1; + } + + for (i = 0; i < q_pairs; ++i) + ret |= vhost_user_enable_queue_pair(dev->vhostfd, i, 1); + for (i = q_pairs; i < dev->max_queue_pairs; ++i) + ret |= vhost_user_enable_queue_pair(dev->vhostfd, i, 0); + + dev->queue_pairs = q_pairs; + + return ret; +} + +static uint32_t +virtio_user_handle_ctrl_msg(struct virtio_user_dev *dev, struct vring *vring, + uint16_t idx_hdr) +{ + struct virtio_net_ctrl_hdr *hdr; + virtio_net_ctrl_ack status = ~0; + uint16_t i, idx_data, idx_status; + uint32_t n_descs = 0; + + /* locate desc for header, data, and status */ + idx_data = vring->desc[idx_hdr].next; + n_descs++; + + i = idx_data; + while (vring->desc[i].flags == VRING_DESC_F_NEXT) { + i = vring->desc[i].next; + n_descs++; + } + + /* locate desc for status */ + idx_status = i; + n_descs++; + + hdr = (void *)(uintptr_t)vring->desc[idx_hdr].addr; + if (hdr->class == VIRTIO_NET_CTRL_MQ && + hdr->cmd == VIRTIO_NET_CTRL_MQ_VQ_PAIRS_SET) { + uint16_t queues; + + queues = *(uint16_t *)(uintptr_t)vring->desc[idx_data].addr; + status = virtio_user_handle_mq(dev, queues); + } + + /* Update status */ + *(virtio_net_ctrl_ack *)(uintptr_t)vring->desc[idx_status].addr = status; + + return n_descs; +} + +void +virtio_user_handle_cq(struct virtio_user_dev *dev, uint16_t queue_idx) +{ + uint16_t avail_idx, desc_idx; + struct vring_used_elem *uep; + uint32_t n_descs; + struct vring *vring = &dev->vrings[queue_idx]; + + /* Consume avail ring, using used ring idx as first one */ + while (vring->used->idx != vring->avail->idx) { + avail_idx = (vring->used->idx) & (vring->num - 1); + desc_idx = vring->avail->ring[avail_idx]; + + n_descs = virtio_user_handle_ctrl_msg(dev, vring, desc_idx); + + /* Update used ring */ + uep = &vring->used->ring[avail_idx]; + uep->id = avail_idx; + uep->len = n_descs; + + vring->used->idx++; + } +} diff --git a/drivers/net/virtio/virtio_user/virtio_user_dev.h b/drivers/net/virtio/virtio_user/virtio_user_dev.h index 68bee37531..33690b5c5f 100644 --- a/drivers/net/virtio/virtio_user/virtio_user_dev.h +++ b/drivers/net/virtio/virtio_user/virtio_user_dev.h @@ -58,5 +58,5 @@ int virtio_user_stop_device(struct virtio_user_dev *dev); int virtio_user_dev_init(struct virtio_user_dev *dev, char *path, int queues, int cq, int queue_size, const char *mac); void virtio_user_dev_uninit(struct virtio_user_dev *dev); - +void virtio_user_handle_cq(struct virtio_user_dev *dev, uint16_t queue_idx); #endif