get:
Show a patch.

patch:
Update a patch.

put:
Update a patch.

GET /api/patches/4644/?format=api
HTTP 200 OK
Allow: GET, PUT, PATCH, HEAD, OPTIONS
Content-Type: application/json
Vary: Accept

{
    "id": 4644,
    "url": "http://patches.dpdk.org/api/patches/4644/?format=api",
    "web_url": "http://patches.dpdk.org/project/dpdk/patch/1431003645-27889-3-git-send-email-changchun.ouyang@intel.com/",
    "project": {
        "id": 1,
        "url": "http://patches.dpdk.org/api/projects/1/?format=api",
        "name": "DPDK",
        "link_name": "dpdk",
        "list_id": "dev.dpdk.org",
        "list_email": "dev@dpdk.org",
        "web_url": "http://core.dpdk.org",
        "scm_url": "git://dpdk.org/dpdk",
        "webscm_url": "http://git.dpdk.org/dpdk",
        "list_archive_url": "https://inbox.dpdk.org/dev",
        "list_archive_url_format": "https://inbox.dpdk.org/dev/{}",
        "commit_url_format": ""
    },
    "msgid": "<1431003645-27889-3-git-send-email-changchun.ouyang@intel.com>",
    "list_archive_url": "https://inbox.dpdk.org/dev/1431003645-27889-3-git-send-email-changchun.ouyang@intel.com",
    "date": "2015-05-07T13:00:41",
    "name": "[dpdk-dev,RFC,2/6] lib_vhost: Support multiple queues in virtio dev",
    "commit_ref": null,
    "pull_url": null,
    "state": "superseded",
    "archived": true,
    "hash": "54b8de9ec7709fcc8e2133a173e76ef20219163d",
    "submitter": {
        "id": 31,
        "url": "http://patches.dpdk.org/api/people/31/?format=api",
        "name": "Ouyang Changchun",
        "email": "changchun.ouyang@intel.com"
    },
    "delegate": null,
    "mbox": "http://patches.dpdk.org/project/dpdk/patch/1431003645-27889-3-git-send-email-changchun.ouyang@intel.com/mbox/",
    "series": [],
    "comments": "http://patches.dpdk.org/api/patches/4644/comments/",
    "check": "pending",
    "checks": "http://patches.dpdk.org/api/patches/4644/checks/",
    "tags": {},
    "related": [],
    "headers": {
        "Return-Path": "<dev-bounces@dpdk.org>",
        "X-Original-To": "patchwork@dpdk.org",
        "Delivered-To": "patchwork@dpdk.org",
        "Received": [
            "from [92.243.14.124] (localhost [IPv6:::1])\n\tby dpdk.org (Postfix) with ESMTP id 3611B5937;\n\tThu,  7 May 2015 15:01:19 +0200 (CEST)",
            "from mga14.intel.com (mga14.intel.com [192.55.52.115])\n\tby dpdk.org (Postfix) with ESMTP id CA9E45697\n\tfor <dev@dpdk.org>; Thu,  7 May 2015 15:01:16 +0200 (CEST)",
            "from orsmga002.jf.intel.com ([10.7.209.21])\n\tby fmsmga103.fm.intel.com with ESMTP; 07 May 2015 06:01:03 -0700",
            "from shvmail01.sh.intel.com ([10.239.29.42])\n\tby orsmga002.jf.intel.com with ESMTP; 07 May 2015 06:01:02 -0700",
            "from shecgisg004.sh.intel.com (shecgisg004.sh.intel.com\n\t[10.239.29.89])\n\tby shvmail01.sh.intel.com with ESMTP id t47D109B004521;\n\tThu, 7 May 2015 21:01:00 +0800",
            "from shecgisg004.sh.intel.com (localhost [127.0.0.1])\n\tby shecgisg004.sh.intel.com (8.13.6/8.13.6/SuSE Linux 0.8) with ESMTP\n\tid t47D0uDT027981; Thu, 7 May 2015 21:00:58 +0800",
            "(from couyang@localhost)\n\tby shecgisg004.sh.intel.com (8.13.6/8.13.6/Submit) id t47D0u2h027977; \n\tThu, 7 May 2015 21:00:56 +0800"
        ],
        "X-ExtLoop1": "1",
        "X-IronPort-AV": "E=Sophos;i=\"5.13,384,1427785200\"; d=\"scan'208\";a=\"725300229\"",
        "From": "Ouyang Changchun <changchun.ouyang@intel.com>",
        "To": "dev@dpdk.org",
        "Date": "Thu,  7 May 2015 21:00:41 +0800",
        "Message-Id": "<1431003645-27889-3-git-send-email-changchun.ouyang@intel.com>",
        "X-Mailer": "git-send-email 1.7.12.2",
        "In-Reply-To": "<1431003645-27889-1-git-send-email-changchun.ouyang@intel.com>",
        "References": "<1431003645-27889-1-git-send-email-changchun.ouyang@intel.com>",
        "Subject": "[dpdk-dev] [RFC PATCH 2/6] lib_vhost: Support multiple queues in\n\tvirtio dev",
        "X-BeenThere": "dev@dpdk.org",
        "X-Mailman-Version": "2.1.15",
        "Precedence": "list",
        "List-Id": "patches and discussions about DPDK <dev.dpdk.org>",
        "List-Unsubscribe": "<http://dpdk.org/ml/options/dev>,\n\t<mailto:dev-request@dpdk.org?subject=unsubscribe>",
        "List-Archive": "<http://dpdk.org/ml/archives/dev/>",
        "List-Post": "<mailto:dev@dpdk.org>",
        "List-Help": "<mailto:dev-request@dpdk.org?subject=help>",
        "List-Subscribe": "<http://dpdk.org/ml/listinfo/dev>,\n\t<mailto:dev-request@dpdk.org?subject=subscribe>",
        "Errors-To": "dev-bounces@dpdk.org",
        "Sender": "\"dev\" <dev-bounces@dpdk.org>"
    },
    "content": "Each virtio device could have multiple queues, say 2 or 4, at most 8.\nEnabling this feature allows virtio device/port on guest has the ability to\nuse different vCPU to receive/transmit packets from/to each queue.\n\nIn multiple queues mode, virtio device readiness means all queues of\nthis virtio device are ready, cleanup/destroy a virtio device also\nrequires clearing all queues belong to it.\n\nSigned-off-by: Changchun Ouyang <changchun.ouyang@intel.com>\n---\n lib/librte_vhost/rte_virtio_net.h             |  15 +++-\n lib/librte_vhost/vhost_rxtx.c                 |  32 +++----\n lib/librte_vhost/vhost_user/virtio-net-user.c |  41 ++++-----\n lib/librte_vhost/virtio-net.c                 | 117 +++++++++++++++++---------\n 4 files changed, 131 insertions(+), 74 deletions(-)",
    "diff": "diff --git a/lib/librte_vhost/rte_virtio_net.h b/lib/librte_vhost/rte_virtio_net.h\nindex 2fc1c44..5fb6006 100644\n--- a/lib/librte_vhost/rte_virtio_net.h\n+++ b/lib/librte_vhost/rte_virtio_net.h\n@@ -58,6 +58,10 @@\n /* Backend value set by guest. */\n #define VIRTIO_DEV_STOPPED -1\n \n+/**\n+ * Maximum number of virtqueues per device.\n+ */\n+#define VIRTIO_MAX_VIRTQUEUES 8\n \n /* Enum for virtqueue management. */\n enum {VIRTIO_RXQ, VIRTIO_TXQ, VIRTIO_QNUM};\n@@ -95,13 +99,14 @@ struct vhost_virtqueue {\n  * Device structure contains all configuration information relating to the device.\n  */\n struct virtio_net {\n-\tstruct vhost_virtqueue\t*virtqueue[VIRTIO_QNUM];\t/**< Contains all virtqueue information. */\n \tstruct virtio_memory\t*mem;\t\t/**< QEMU memory and memory region information. */\n+\tstruct vhost_virtqueue\t*virtqueue[VIRTIO_QNUM * VIRTIO_MAX_VIRTQUEUES]; /**< Contains all virtqueue information. */\n \tuint64_t\t\tfeatures;\t/**< Negotiated feature set. */\n \tuint64_t\t\tdevice_fh;\t/**< device identifier. */\n \tuint32_t\t\tflags;\t\t/**< Device flags. Only used to check if device is running on data core. */\n #define IF_NAME_SZ (PATH_MAX > IFNAMSIZ ? PATH_MAX : IFNAMSIZ)\n \tchar\t\t\tifname[IF_NAME_SZ];\t/**< Name of the tap device or socket path. */\n+\tuint32_t                num_virt_queues;\n \tvoid\t\t\t*priv;\t\t/**< private context */\n } __rte_cache_aligned;\n \n@@ -215,4 +220,12 @@ uint16_t rte_vhost_enqueue_burst(struct virtio_net *dev, uint16_t queue_id,\n uint16_t rte_vhost_dequeue_burst(struct virtio_net *dev, uint16_t queue_id,\n \tstruct rte_mempool *mbuf_pool, struct rte_mbuf **pkts, uint16_t count);\n \n+/**\n+ * This function get the queue number of one vhost device.\n+ * @param q_number\n+ *  queue number one vhost device.\n+ * @return\n+ *  0 if success, -1 if q_number exceed the max.\n+ */\n+int rte_vhost_q_num_get(uint32_t q_number);\n #endif /* _VIRTIO_NET_H_ */\ndiff --git a/lib/librte_vhost/vhost_rxtx.c b/lib/librte_vhost/vhost_rxtx.c\nindex 535c7a1..d8dd5ec 100644\n--- a/lib/librte_vhost/vhost_rxtx.c\n+++ b/lib/librte_vhost/vhost_rxtx.c\n@@ -67,12 +67,12 @@ virtio_dev_rx(struct virtio_net *dev, uint16_t queue_id,\n \tuint8_t success = 0;\n \n \tLOG_DEBUG(VHOST_DATA, \"(%\"PRIu64\") virtio_dev_rx()\\n\", dev->device_fh);\n-\tif (unlikely(queue_id != VIRTIO_RXQ)) {\n-\t\tLOG_DEBUG(VHOST_DATA, \"mq isn't supported in this version.\\n\");\n-\t\treturn 0;\n+\tif (unlikely(queue_id >= VIRTIO_QNUM * dev->num_virt_queues)) {\n+\t\tLOG_DEBUG(VHOST_DATA, \"queue id: %d invalid.\\n\", queue_id);\n+\t\treturn -1;\n \t}\n \n-\tvq = dev->virtqueue[VIRTIO_RXQ];\n+\tvq = dev->virtqueue[queue_id];\n \tcount = (count > MAX_PKT_BURST) ? MAX_PKT_BURST : count;\n \n \t/*\n@@ -185,8 +185,9 @@ virtio_dev_rx(struct virtio_net *dev, uint16_t queue_id,\n }\n \n static inline uint32_t __attribute__((always_inline))\n-copy_from_mbuf_to_vring(struct virtio_net *dev, uint16_t res_base_idx,\n-\tuint16_t res_end_idx, struct rte_mbuf *pkt)\n+copy_from_mbuf_to_vring(struct virtio_net *dev, uint16_t queue_id,\n+\tuint16_t res_base_idx, uint16_t res_end_idx,\n+\tstruct rte_mbuf *pkt)\n {\n \tuint32_t vec_idx = 0;\n \tuint32_t entry_success = 0;\n@@ -214,9 +215,9 @@ copy_from_mbuf_to_vring(struct virtio_net *dev, uint16_t res_base_idx,\n \t * Convert from gpa to vva\n \t * (guest physical addr -> vhost virtual addr)\n \t */\n-\tvq = dev->virtqueue[VIRTIO_RXQ];\n \tvb_addr =\n \t\tgpa_to_vva(dev, vq->buf_vec[vec_idx].buf_addr);\n+\tvq = dev->virtqueue[queue_id];\n \tvb_hdr_addr = vb_addr;\n \n \t/* Prefetch buffer address. */\n@@ -404,11 +405,12 @@ virtio_dev_merge_rx(struct virtio_net *dev, uint16_t queue_id,\n \n \tLOG_DEBUG(VHOST_DATA, \"(%\"PRIu64\") virtio_dev_merge_rx()\\n\",\n \t\tdev->device_fh);\n-\tif (unlikely(queue_id != VIRTIO_RXQ)) {\n-\t\tLOG_DEBUG(VHOST_DATA, \"mq isn't supported in this version.\\n\");\n+\tif (unlikely(queue_id >= VIRTIO_QNUM * dev->num_virt_queues)) {\n+\t\tLOG_DEBUG(VHOST_DATA, \"queue id: %d invalid.\\n\", queue_id);\n+\t\treturn -1;\n \t}\n \n-\tvq = dev->virtqueue[VIRTIO_RXQ];\n+\tvq = dev->virtqueue[queue_id];\n \tcount = RTE_MIN((uint32_t)MAX_PKT_BURST, count);\n \n \tif (count == 0)\n@@ -490,7 +492,7 @@ virtio_dev_merge_rx(struct virtio_net *dev, uint16_t queue_id,\n \n \t\tres_end_idx = res_cur_idx;\n \n-\t\tentry_success = copy_from_mbuf_to_vring(dev, res_base_idx,\n+\t\tentry_success = copy_from_mbuf_to_vring(dev, queue_id, res_base_idx,\n \t\t\tres_end_idx, pkts[pkt_idx]);\n \n \t\trte_compiler_barrier();\n@@ -537,12 +539,12 @@ rte_vhost_dequeue_burst(struct virtio_net *dev, uint16_t queue_id,\n \tuint16_t free_entries, entry_success = 0;\n \tuint16_t avail_idx;\n \n-\tif (unlikely(queue_id != VIRTIO_TXQ)) {\n-\t\tLOG_DEBUG(VHOST_DATA, \"mq isn't supported in this version.\\n\");\n-\t\treturn 0;\n+\tif (unlikely(queue_id >= VIRTIO_QNUM * dev->num_virt_queues)) {\n+\t\tLOG_DEBUG(VHOST_DATA, \"queue id:%d invalid.\\n\", queue_id);\n+\t\treturn -1;\n \t}\n \n-\tvq = dev->virtqueue[VIRTIO_TXQ];\n+\tvq = dev->virtqueue[queue_id];\n \tavail_idx =  *((volatile uint16_t *)&vq->avail->idx);\n \n \t/* If there are no available buffers then return. */\ndiff --git a/lib/librte_vhost/vhost_user/virtio-net-user.c b/lib/librte_vhost/vhost_user/virtio-net-user.c\nindex 465d3ef..031712c 100644\n--- a/lib/librte_vhost/vhost_user/virtio-net-user.c\n+++ b/lib/librte_vhost/vhost_user/virtio-net-user.c\n@@ -209,22 +209,29 @@ static int\n virtio_is_ready(struct virtio_net *dev)\n {\n \tstruct vhost_virtqueue *rvq, *tvq;\n+\tuint32_t q_idx;\n \n \t/* mq support in future.*/\n-\trvq = dev->virtqueue[VIRTIO_RXQ];\n-\ttvq = dev->virtqueue[VIRTIO_TXQ];\n-\tif (rvq && tvq && rvq->desc && tvq->desc &&\n-\t\t(rvq->kickfd != (eventfd_t)-1) &&\n-\t\t(rvq->callfd != (eventfd_t)-1) &&\n-\t\t(tvq->kickfd != (eventfd_t)-1) &&\n-\t\t(tvq->callfd != (eventfd_t)-1)) {\n-\t\tRTE_LOG(INFO, VHOST_CONFIG,\n-\t\t\t\"virtio is now ready for processing.\\n\");\n-\t\treturn 1;\n+\tfor (q_idx = 0; q_idx < dev->num_virt_queues; q_idx++) {\n+                uint32_t virt_rx_q_idx = q_idx * VIRTIO_QNUM + VIRTIO_RXQ;\n+                uint32_t virt_tx_q_idx = q_idx * VIRTIO_QNUM + VIRTIO_TXQ;\n+\n+\t\trvq = dev->virtqueue[virt_rx_q_idx];\n+\t\ttvq = dev->virtqueue[virt_tx_q_idx];\n+\t\tif ((rvq == NULL) || (tvq == NULL) ||\n+\t\t\t(rvq->desc == NULL) || (tvq->desc == NULL) ||\n+\t\t\t(rvq->kickfd == (eventfd_t)-1) ||\n+\t\t\t(rvq->callfd == (eventfd_t)-1) ||\n+\t\t\t(tvq->kickfd == (eventfd_t)-1) ||\n+\t\t\t(tvq->callfd == (eventfd_t)-1)) {\n+\t\t\tRTE_LOG(INFO, VHOST_CONFIG,\n+\t\t\t\t\"virtio isn't ready for processing.\\n\");\n+\t\t\treturn 0;\n+\t\t}\n \t}\n \tRTE_LOG(INFO, VHOST_CONFIG,\n-\t\t\"virtio isn't ready for processing.\\n\");\n-\treturn 0;\n+\t\t\"virtio is now ready for processing.\\n\");\n+\treturn 1;\n }\n \n void\n@@ -290,13 +297,9 @@ user_get_vring_base(struct vhost_device_ctx ctx,\n \t * sent and only sent in vhost_vring_stop.\n \t * TODO: cleanup the vring, it isn't usable since here.\n \t */\n-\tif (((int)dev->virtqueue[VIRTIO_RXQ]->kickfd) >= 0) {\n-\t\tclose(dev->virtqueue[VIRTIO_RXQ]->kickfd);\n-\t\tdev->virtqueue[VIRTIO_RXQ]->kickfd = (eventfd_t)-1;\n-\t}\n-\tif (((int)dev->virtqueue[VIRTIO_TXQ]->kickfd) >= 0) {\n-\t\tclose(dev->virtqueue[VIRTIO_TXQ]->kickfd);\n-\t\tdev->virtqueue[VIRTIO_TXQ]->kickfd = (eventfd_t)-1;\n+\tif (((int)dev->virtqueue[state->index]->kickfd) >= 0) {\n+\t\tclose(dev->virtqueue[state->index]->kickfd);\n+\t\tdev->virtqueue[state->index]->kickfd = (eventfd_t)-1;\n \t}\n \n \treturn 0;\ndiff --git a/lib/librte_vhost/virtio-net.c b/lib/librte_vhost/virtio-net.c\nindex 4672e67..55b7440 100644\n--- a/lib/librte_vhost/virtio-net.c\n+++ b/lib/librte_vhost/virtio-net.c\n@@ -66,9 +66,11 @@ static struct virtio_net_config_ll *ll_root;\n /* Features supported by this lib. */\n #define VHOST_SUPPORTED_FEATURES ((1ULL << VIRTIO_NET_F_MRG_RXBUF) | \\\n \t\t\t\t(1ULL << VIRTIO_NET_F_CTRL_VQ) | \\\n-\t\t\t\t(1ULL << VIRTIO_NET_F_CTRL_RX))\n+\t\t\t\t(1ULL << VIRTIO_NET_F_CTRL_RX) | \\\n+\t\t\t\t(1ULL << VIRTIO_NET_F_MQ))\n static uint64_t VHOST_FEATURES = VHOST_SUPPORTED_FEATURES;\n \n+static uint32_t q_num = 1;\n \n /*\n  * Converts QEMU virtual address to Vhost virtual address. This function is\n@@ -177,6 +179,8 @@ add_config_ll_entry(struct virtio_net_config_ll *new_ll_dev)\n static void\n cleanup_device(struct virtio_net *dev)\n {\n+\tuint32_t q_idx;\n+\n \t/* Unmap QEMU memory file if mapped. */\n \tif (dev->mem) {\n \t\tmunmap((void *)(uintptr_t)dev->mem->mapped_address,\n@@ -185,14 +189,18 @@ cleanup_device(struct virtio_net *dev)\n \t}\n \n \t/* Close any event notifiers opened by device. */\n-\tif ((int)dev->virtqueue[VIRTIO_RXQ]->callfd >= 0)\n-\t\tclose((int)dev->virtqueue[VIRTIO_RXQ]->callfd);\n-\tif ((int)dev->virtqueue[VIRTIO_RXQ]->kickfd >= 0)\n-\t\tclose((int)dev->virtqueue[VIRTIO_RXQ]->kickfd);\n-\tif ((int)dev->virtqueue[VIRTIO_TXQ]->callfd >= 0)\n-\t\tclose((int)dev->virtqueue[VIRTIO_TXQ]->callfd);\n-\tif ((int)dev->virtqueue[VIRTIO_TXQ]->kickfd >= 0)\n-\t\tclose((int)dev->virtqueue[VIRTIO_TXQ]->kickfd);\n+\tfor (q_idx = 0; q_idx < dev->num_virt_queues; q_idx++) {\n+\t\tuint32_t virt_rx_q_idx = q_idx * VIRTIO_QNUM + VIRTIO_RXQ;\n+\t\tuint32_t virt_tx_q_idx = q_idx * VIRTIO_QNUM + VIRTIO_TXQ;\n+\t\tif ((int)dev->virtqueue[virt_rx_q_idx]->callfd >= 0)\n+\t\t\tclose((int)dev->virtqueue[virt_rx_q_idx]->callfd);\n+\t\tif ((int)dev->virtqueue[virt_rx_q_idx]->kickfd >= 0)\n+\t\t\tclose((int)dev->virtqueue[virt_rx_q_idx]->kickfd);\n+\t\tif ((int)dev->virtqueue[virt_tx_q_idx]->callfd >= 0)\n+\t\t\tclose((int)dev->virtqueue[virt_tx_q_idx]->callfd);\n+\t\tif ((int)dev->virtqueue[virt_tx_q_idx]->kickfd >= 0)\n+\t\t\tclose((int)dev->virtqueue[virt_tx_q_idx]->kickfd);\n+\t}\n }\n \n /*\n@@ -201,7 +209,10 @@ cleanup_device(struct virtio_net *dev)\n static void\n free_device(struct virtio_net_config_ll *ll_dev)\n {\n-\t/* Free any malloc'd memory */\n+\t/*\n+\t * Free any malloc'd memory, just need free once even in multi Q case\n+\t * as they are malloc'd once.\n+\t */\n \tfree(ll_dev->dev.virtqueue[VIRTIO_RXQ]);\n \tfree(ll_dev->dev.virtqueue[VIRTIO_TXQ]);\n \tfree(ll_dev);\n@@ -243,6 +254,7 @@ static void\n init_device(struct virtio_net *dev)\n {\n \tuint64_t vq_offset;\n+\tuint32_t q_idx;\n \n \t/*\n \t * Virtqueues have already been malloced so\n@@ -253,17 +265,24 @@ init_device(struct virtio_net *dev)\n \t/* Set everything to 0. */\n \tmemset((void *)(uintptr_t)((uint64_t)(uintptr_t)dev + vq_offset), 0,\n \t\t(sizeof(struct virtio_net) - (size_t)vq_offset));\n-\tmemset(dev->virtqueue[VIRTIO_RXQ], 0, sizeof(struct vhost_virtqueue));\n-\tmemset(dev->virtqueue[VIRTIO_TXQ], 0, sizeof(struct vhost_virtqueue));\n \n-\tdev->virtqueue[VIRTIO_RXQ]->kickfd = (eventfd_t)-1;\n-\tdev->virtqueue[VIRTIO_RXQ]->callfd = (eventfd_t)-1;\n-\tdev->virtqueue[VIRTIO_TXQ]->kickfd = (eventfd_t)-1;\n-\tdev->virtqueue[VIRTIO_TXQ]->callfd = (eventfd_t)-1;\n+\tdev->num_virt_queues = q_num;\n+\n+\tfor (q_idx = 0; q_idx < dev->num_virt_queues; q_idx++) {\n+\t\tuint32_t virt_rx_q_idx = q_idx * VIRTIO_QNUM + VIRTIO_RXQ;\n+\t\tuint32_t virt_tx_q_idx = q_idx * VIRTIO_QNUM + VIRTIO_TXQ;\n+\t\tmemset(dev->virtqueue[virt_rx_q_idx], 0, sizeof(struct vhost_virtqueue));\n+\t\tmemset(dev->virtqueue[virt_tx_q_idx], 0, sizeof(struct vhost_virtqueue));\n \n-\t/* Backends are set to -1 indicating an inactive device. */\n-\tdev->virtqueue[VIRTIO_RXQ]->backend = VIRTIO_DEV_STOPPED;\n-\tdev->virtqueue[VIRTIO_TXQ]->backend = VIRTIO_DEV_STOPPED;\n+\t\tdev->virtqueue[virt_rx_q_idx]->kickfd = (eventfd_t)-1;\n+\t\tdev->virtqueue[virt_rx_q_idx]->callfd = (eventfd_t)-1;\n+\t\tdev->virtqueue[virt_tx_q_idx]->kickfd = (eventfd_t)-1;\n+\t\tdev->virtqueue[virt_tx_q_idx]->callfd = (eventfd_t)-1;\n+\n+\t\t/* Backends are set to -1 indicating an inactive device. */\n+\t\tdev->virtqueue[virt_rx_q_idx]->backend = VIRTIO_DEV_STOPPED;\n+\t\tdev->virtqueue[virt_tx_q_idx]->backend = VIRTIO_DEV_STOPPED;\n+\t}\n }\n \n /*\n@@ -276,6 +295,7 @@ new_device(struct vhost_device_ctx ctx)\n {\n \tstruct virtio_net_config_ll *new_ll_dev;\n \tstruct vhost_virtqueue *virtqueue_rx, *virtqueue_tx;\n+\tuint32_t q_idx;\n \n \t/* Setup device and virtqueues. */\n \tnew_ll_dev = malloc(sizeof(struct virtio_net_config_ll));\n@@ -286,7 +306,7 @@ new_device(struct vhost_device_ctx ctx)\n \t\treturn -1;\n \t}\n \n-\tvirtqueue_rx = malloc(sizeof(struct vhost_virtqueue));\n+\tvirtqueue_rx = malloc(sizeof(struct vhost_virtqueue) * q_num);\n \tif (virtqueue_rx == NULL) {\n \t\tfree(new_ll_dev);\n \t\tRTE_LOG(ERR, VHOST_CONFIG,\n@@ -295,7 +315,7 @@ new_device(struct vhost_device_ctx ctx)\n \t\treturn -1;\n \t}\n \n-\tvirtqueue_tx = malloc(sizeof(struct vhost_virtqueue));\n+\tvirtqueue_tx = malloc(sizeof(struct vhost_virtqueue) * q_num);\n \tif (virtqueue_tx == NULL) {\n \t\tfree(virtqueue_rx);\n \t\tfree(new_ll_dev);\n@@ -305,8 +325,13 @@ new_device(struct vhost_device_ctx ctx)\n \t\treturn -1;\n \t}\n \n-\tnew_ll_dev->dev.virtqueue[VIRTIO_RXQ] = virtqueue_rx;\n-\tnew_ll_dev->dev.virtqueue[VIRTIO_TXQ] = virtqueue_tx;\n+\tmemset(new_ll_dev->dev.virtqueue, 0, sizeof(new_ll_dev->dev.virtqueue));\n+\tfor (q_idx = 0; q_idx < q_num; q_idx++) {\n+\t\tuint32_t virt_rx_q_idx = q_idx * VIRTIO_QNUM + VIRTIO_RXQ;\n+\t\tuint32_t virt_tx_q_idx = q_idx * VIRTIO_QNUM + VIRTIO_TXQ;\n+\t\tnew_ll_dev->dev.virtqueue[virt_rx_q_idx] = virtqueue_rx + q_idx;\n+\t\tnew_ll_dev->dev.virtqueue[virt_tx_q_idx] = virtqueue_tx + q_idx;\n+\t}\n \n \t/* Initialise device and virtqueues. */\n \tinit_device(&new_ll_dev->dev);\n@@ -429,6 +454,7 @@ static int\n set_features(struct vhost_device_ctx ctx, uint64_t *pu)\n {\n \tstruct virtio_net *dev;\n+\tuint32_t q_idx;\n \n \tdev = get_device(ctx);\n \tif (dev == NULL)\n@@ -440,22 +466,26 @@ set_features(struct vhost_device_ctx ctx, uint64_t *pu)\n \tdev->features = *pu;\n \n \t/* Set the vhost_hlen depending on if VIRTIO_NET_F_MRG_RXBUF is set. */\n-\tif (dev->features & (1 << VIRTIO_NET_F_MRG_RXBUF)) {\n-\t\tLOG_DEBUG(VHOST_CONFIG,\n-\t\t\t\"(%\"PRIu64\") Mergeable RX buffers enabled\\n\",\n-\t\t\tdev->device_fh);\n-\t\tdev->virtqueue[VIRTIO_RXQ]->vhost_hlen =\n-\t\t\tsizeof(struct virtio_net_hdr_mrg_rxbuf);\n-\t\tdev->virtqueue[VIRTIO_TXQ]->vhost_hlen =\n-\t\t\tsizeof(struct virtio_net_hdr_mrg_rxbuf);\n-\t} else {\n-\t\tLOG_DEBUG(VHOST_CONFIG,\n-\t\t\t\"(%\"PRIu64\") Mergeable RX buffers disabled\\n\",\n-\t\t\tdev->device_fh);\n-\t\tdev->virtqueue[VIRTIO_RXQ]->vhost_hlen =\n-\t\t\tsizeof(struct virtio_net_hdr);\n-\t\tdev->virtqueue[VIRTIO_TXQ]->vhost_hlen =\n-\t\t\tsizeof(struct virtio_net_hdr);\n+\tfor (q_idx = 0; q_idx < dev->num_virt_queues; q_idx++) {\n+\t\tuint32_t virt_rx_q_idx = q_idx * VIRTIO_QNUM + VIRTIO_RXQ;\n+\t\tuint32_t virt_tx_q_idx = q_idx * VIRTIO_QNUM + VIRTIO_TXQ;\n+\t\tif (dev->features & (1 << VIRTIO_NET_F_MRG_RXBUF)) {\n+\t\t\tLOG_DEBUG(VHOST_CONFIG,\n+\t\t\t\t\"(%\"PRIu64\") Mergeable RX buffers enabled\\n\",\n+\t\t\t\tdev->device_fh);\n+\t\t\tdev->virtqueue[virt_rx_q_idx]->vhost_hlen =\n+\t\t\t\tsizeof(struct virtio_net_hdr_mrg_rxbuf);\n+\t\t\tdev->virtqueue[virt_tx_q_idx]->vhost_hlen =\n+\t\t\t\tsizeof(struct virtio_net_hdr_mrg_rxbuf);\n+\t\t} else {\n+\t\t\tLOG_DEBUG(VHOST_CONFIG,\n+\t\t\t\t\"(%\"PRIu64\") Mergeable RX buffers disabled\\n\",\n+\t\t\t\tdev->device_fh);\n+\t\t\tdev->virtqueue[virt_rx_q_idx]->vhost_hlen =\n+\t\t\t\tsizeof(struct virtio_net_hdr);\n+\t\t\tdev->virtqueue[virt_tx_q_idx]->vhost_hlen =\n+\t\t\t\tsizeof(struct virtio_net_hdr);\n+\t\t}\n \t}\n \treturn 0;\n }\n@@ -736,6 +766,15 @@ int rte_vhost_feature_enable(uint64_t feature_mask)\n \treturn -1;\n }\n \n+int rte_vhost_q_num_get(uint32_t q_number)\n+{\n+\tif (q_number > VIRTIO_MAX_VIRTQUEUES)\n+\t\treturn -1;\n+\n+\tq_num = q_number;\n+\treturn 0;\n+}\n+\n /*\n  * Register ops so that we can add/remove device to data core.\n  */\n",
    "prefixes": [
        "dpdk-dev",
        "RFC",
        "2/6"
    ]
}