get:
Show a patch.

patch:
Update a patch.

put:
Update a patch.

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

{
    "id": 41081,
    "url": "http://patches.dpdk.org/api/patches/41081/?format=api",
    "web_url": "http://patches.dpdk.org/project/dpdk/patch/20180614083047.10812-4-adrien.mazarguil@6wind.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": "<20180614083047.10812-4-adrien.mazarguil@6wind.com>",
    "list_archive_url": "https://inbox.dpdk.org/dev/20180614083047.10812-4-adrien.mazarguil@6wind.com",
    "date": "2018-06-14T08:34:54",
    "name": "[v2,3/7] net/mlx5: split PCI from generic probing code",
    "commit_ref": null,
    "pull_url": null,
    "state": "superseded",
    "archived": true,
    "hash": "202757a49cae0bde97a01d61eb7dec3c4d16e98d",
    "submitter": {
        "id": 165,
        "url": "http://patches.dpdk.org/api/people/165/?format=api",
        "name": "Adrien Mazarguil",
        "email": "adrien.mazarguil@6wind.com"
    },
    "delegate": null,
    "mbox": "http://patches.dpdk.org/project/dpdk/patch/20180614083047.10812-4-adrien.mazarguil@6wind.com/mbox/",
    "series": [
        {
            "id": 118,
            "url": "http://patches.dpdk.org/api/series/118/?format=api",
            "web_url": "http://patches.dpdk.org/project/dpdk/list/?series=118",
            "date": "2018-06-14T08:34:47",
            "name": "net/mlx5: add port representor support",
            "version": 2,
            "mbox": "http://patches.dpdk.org/series/118/mbox/"
        }
    ],
    "comments": "http://patches.dpdk.org/api/patches/41081/comments/",
    "check": "fail",
    "checks": "http://patches.dpdk.org/api/patches/41081/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 [127.0.0.1])\n\tby dpdk.org (Postfix) with ESMTP id BBA781E487;\n\tThu, 14 Jun 2018 10:35:12 +0200 (CEST)",
            "from mail-wm0-f66.google.com (mail-wm0-f66.google.com\n\t[74.125.82.66]) by dpdk.org (Postfix) with ESMTP id E68AD1E439\n\tfor <dev@dpdk.org>; Thu, 14 Jun 2018 10:35:10 +0200 (CEST)",
            "by mail-wm0-f66.google.com with SMTP id r15-v6so9068142wmc.1\n\tfor <dev@dpdk.org>; Thu, 14 Jun 2018 01:35:10 -0700 (PDT)",
            "from 6wind.com (host.78.145.23.62.rev.coltfrance.com.\n\t[62.23.145.78]) by smtp.gmail.com with ESMTPSA id\n\tl84-v6sm7462578wmi.3.2018.06.14.01.35.09\n\t(version=TLS1_2 cipher=ECDHE-RSA-AES128-GCM-SHA256 bits=128/128);\n\tThu, 14 Jun 2018 01:35:09 -0700 (PDT)"
        ],
        "DKIM-Signature": "v=1; a=rsa-sha256; c=relaxed/relaxed;\n\td=6wind-com.20150623.gappssmtp.com; s=20150623;\n\th=date:from:to:cc:subject:message-id:references:mime-version\n\t:content-disposition:in-reply-to;\n\tbh=l1TkjrvUe2fOguoLut4rhGe5WVJ2uLHdovj43ipBVF4=;\n\tb=yPpzIxlyDRSbhd+PD0ifKvwEixu48Kvp9/rRRCScP20Jfj5zYuYadLNyNrqbltgFqR\n\t+EYd2e8zA0ExgSW7ADpePWjONuxc24Pxr2Idiveeim5OYlGuEaAxmC5H8sVIM5ZWJ9xk\n\td1MrarzGOrqC3jGDKYb4FHBKQRiMnSjj5d52199Y+1OutYNS7/m7pIXcNIlZAZE7YzPQ\n\ta4YjWDWee6YaXeEWJyF2EBaIOS6Wfvu2B/wFuKTgyjzRgqF0bhXGWtRG9sUoMX0QnEU6\n\tOKnRULc2Voxm0VNuOi5MolfL6N7Ntwd4vcKj5ZVvdiZlIokPsxs6+oGFJiZzlmOf/J1a\n\ttCdw==",
        "X-Google-DKIM-Signature": "v=1; a=rsa-sha256; c=relaxed/relaxed;\n\td=1e100.net; s=20161025;\n\th=x-gm-message-state:date:from:to:cc:subject:message-id:references\n\t:mime-version:content-disposition:in-reply-to;\n\tbh=l1TkjrvUe2fOguoLut4rhGe5WVJ2uLHdovj43ipBVF4=;\n\tb=mvtpf2v5IoHBUHMoFCLzy1vXNmW66Bi0mL2cZYeecaellnrs4LPRdDrDjNNZGXG5he\n\tOw1l1n5SvjA6EG9PKjoDTs6r8GCdDeFyQaCFUpdBM44pWmjtaITrXDLmS1ngF+zP3q44\n\tPnOlUpeIK5QiBT9TJNu8tAaUsnizo6eO8hL3cp7rzc2ETniuFyTAxgc+NOTBBNhEkHOr\n\tZPI3wnmxAvexwjlinhe09+bXeupMhDpveOmGjzQUD73QdHL9b+g279XUm0p9jEWVlBZC\n\tWLVtQI8/9dy5LmZeUV0zGZysoUrweUEqQEWASy1ispT35cfQcmhOjO1ABZf8pYglwCuP\n\tdddQ==",
        "X-Gm-Message-State": "APt69E1c8OnQEGGYkpRm9ZbzWHe8/ZY0zNwcgl5A4eVgQTn1ey2iT+17\n\t+YCWdPQ570vZvnCzaW9wPnbl4A==",
        "X-Google-Smtp-Source": "ADUXVKLWBcz+fa/Ytm6/UcK8jS8Ys6odfmMm7pC2yte6DnXowrwNjhNMsJe/OXuN1tczu7MggGIzmQ==",
        "X-Received": "by 2002:a1c:9e95:: with SMTP id\n\th143-v6mr1102279wme.68.1528965310248; \n\tThu, 14 Jun 2018 01:35:10 -0700 (PDT)",
        "Date": "Thu, 14 Jun 2018 10:34:54 +0200",
        "From": "Adrien Mazarguil <adrien.mazarguil@6wind.com>",
        "To": "Shahaf Shuler <shahafs@mellanox.com>",
        "Cc": "dev@dpdk.org",
        "Message-ID": "<20180614083047.10812-4-adrien.mazarguil@6wind.com>",
        "References": "<20180525161814.13873-1-adrien.mazarguil@6wind.com>\n\t<20180614083047.10812-1-adrien.mazarguil@6wind.com>",
        "MIME-Version": "1.0",
        "Content-Type": "text/plain; charset=us-ascii",
        "Content-Disposition": "inline",
        "In-Reply-To": "<20180614083047.10812-1-adrien.mazarguil@6wind.com>",
        "X-Mailer": "git-send-email 2.11.0",
        "Subject": "[dpdk-dev] [PATCH v2 3/7] net/mlx5: split PCI from generic probing\n\tcode",
        "X-BeenThere": "dev@dpdk.org",
        "X-Mailman-Version": "2.1.15",
        "Precedence": "list",
        "List-Id": "DPDK patches and discussions <dev.dpdk.org>",
        "List-Unsubscribe": "<https://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": "<https://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": "All the generic probing code needs is an IB device. While this device is\ncurrently supplied by a PCI lookup, other methods will be added soon.\n\nThis patch divides the original function, which has become huge over time,\nas follows:\n\n1. PCI-specific (mlx5_pci_probe()).\n2. All ports of a Verbs device (mlx5_dev_spawn()).\n3. A given port of a Verbs device (mlx5_dev_spawn_one()).\n\n(Patch based on prior work from Yuanhan Liu)\n\nSigned-off-by: Adrien Mazarguil <adrien.mazarguil@6wind.com>\n--\nv2 changes:\n\n- Fixed device naming. A port suffix is now appended only if several IB\n  ports happen to be detected.\n- Added separate message to distinguish missing kernel drivers from other\n  initialization errors, as it was confusing.\n---\n drivers/net/mlx5/mlx5.c | 340 ++++++++++++++++++++++++++-----------------\n 1 file changed, 209 insertions(+), 131 deletions(-)",
    "diff": "diff --git a/drivers/net/mlx5/mlx5.c b/drivers/net/mlx5/mlx5.c\nindex 1a5391e63..01dcf25b9 100644\n--- a/drivers/net/mlx5/mlx5.c\n+++ b/drivers/net/mlx5/mlx5.c\n@@ -635,30 +635,34 @@ mlx5_uar_init_secondary(struct rte_eth_dev *dev)\n }\n \n /**\n- * DPDK callback to register a PCI device.\n- *\n- * This function creates an Ethernet device for each port of a given\n- * PCI device.\n+ * Spawn an Ethernet device from Verbs information.\n  *\n- * @param[in] pci_drv\n- *   PCI driver structure (mlx5_driver).\n- * @param[in] pci_dev\n- *   PCI device information.\n+ * @param dpdk_dev\n+ *   Backing DPDK device.\n+ * @param ibv_dev\n+ *   Verbs device.\n+ * @param vf\n+ *   If nonzero, enable VF-specific features.\n+ * @param[in] attr\n+ *   Verbs device attributes.\n+ * @param port\n+ *   Verbs port to use (indexed from 1).\n  *\n  * @return\n- *   0 on success, a negative errno value otherwise and rte_errno is set.\n+ *   A valid Ethernet device object on success, NULL otherwise and rte_errno\n+ *   is set.\n  */\n-static int\n-mlx5_pci_probe(struct rte_pci_driver *pci_drv __rte_unused,\n-\t       struct rte_pci_device *pci_dev)\n+static struct rte_eth_dev *\n+mlx5_dev_spawn_one(struct rte_device *dpdk_dev,\n+\t\t   struct ibv_device *ibv_dev,\n+\t\t   int vf,\n+\t\t   const struct ibv_device_attr_ex *attr,\n+\t\t   unsigned int port)\n {\n-\tstruct ibv_device **list = NULL;\n-\tstruct ibv_device *ibv_dev;\n-\tstruct ibv_context *ctx = NULL;\n-\tstruct ibv_device_attr_ex attr;\n+\tstruct ibv_context *ctx;\n \tstruct mlx5dv_context dv_attr = { .comp_mask = 0 };\n+\tstruct rte_eth_dev *eth_dev = NULL;\n \tint err = 0;\n-\tunsigned int vf = 0;\n \tunsigned int mps;\n \tunsigned int cqe_comp;\n \tunsigned int tunnel_en = 0;\n@@ -670,71 +674,18 @@ mlx5_pci_probe(struct rte_pci_driver *pci_drv __rte_unused,\n \tunsigned int mprq_max_stride_size_n = 0;\n \tunsigned int mprq_min_stride_num_n = 0;\n \tunsigned int mprq_max_stride_num_n = 0;\n-\tint i;\n #ifdef HAVE_IBV_DEVICE_COUNTERS_SET_SUPPORT\n \tstruct ibv_counter_set_description cs_desc = { .counter_type = 0 };\n #endif\n \n \t/* Prepare shared data between primary and secondary process. */\n \tmlx5_prepare_shared_data();\n-\tassert(pci_drv == &mlx5_driver);\n-\tlist = mlx5_glue->get_device_list(&i);\n-\tif (list == NULL) {\n-\t\tassert(errno);\n-\t\terr = errno;\n-\t\tif (errno == ENOSYS)\n-\t\t\tDRV_LOG(ERR,\n-\t\t\t\t\"cannot list devices, is ib_uverbs loaded?\");\n-\t\tgoto error;\n-\t}\n-\tassert(i >= 0);\n-\t/*\n-\t * For each listed device, check related sysfs entry against\n-\t * the provided PCI ID.\n-\t */\n-\twhile (i != 0) {\n-\t\tstruct rte_pci_addr pci_addr;\n-\n-\t\t--i;\n-\t\tDRV_LOG(DEBUG, \"checking device \\\"%s\\\"\", list[i]->name);\n-\t\tif (mlx5_ibv_device_to_pci_addr(list[i], &pci_addr))\n-\t\t\tcontinue;\n-\t\tif ((pci_dev->addr.domain != pci_addr.domain) ||\n-\t\t    (pci_dev->addr.bus != pci_addr.bus) ||\n-\t\t    (pci_dev->addr.devid != pci_addr.devid) ||\n-\t\t    (pci_dev->addr.function != pci_addr.function))\n-\t\t\tcontinue;\n-\t\tDRV_LOG(INFO, \"PCI information matches, using device \\\"%s\\\"\",\n-\t\t\tlist[i]->name);\n-\t\tvf = ((pci_dev->id.device_id ==\n-\t\t       PCI_DEVICE_ID_MELLANOX_CONNECTX4VF) ||\n-\t\t      (pci_dev->id.device_id ==\n-\t\t       PCI_DEVICE_ID_MELLANOX_CONNECTX4LXVF) ||\n-\t\t      (pci_dev->id.device_id ==\n-\t\t       PCI_DEVICE_ID_MELLANOX_CONNECTX5VF) ||\n-\t\t      (pci_dev->id.device_id ==\n-\t\t       PCI_DEVICE_ID_MELLANOX_CONNECTX5EXVF));\n-\t\tctx = mlx5_glue->open_device(list[i]);\n-\t\trte_errno = errno;\n-\t\terr = rte_errno;\n-\t\tbreak;\n-\t}\n-\tif (ctx == NULL) {\n-\t\tswitch (err) {\n-\t\tcase 0:\n-\t\t\tDRV_LOG(ERR,\n-\t\t\t\t\"cannot access device, is mlx5_ib loaded?\");\n-\t\t\terr = ENODEV;\n-\t\t\tbreak;\n-\t\tcase EINVAL:\n-\t\t\tDRV_LOG(ERR,\n-\t\t\t\t\"cannot use device, are drivers up to date?\");\n-\t\t\tbreak;\n-\t\t}\n-\t\tgoto error;\n+\terrno = 0;\n+\tctx = mlx5_glue->open_device(ibv_dev);\n+\tif (!ctx) {\n+\t\trte_errno = errno ? errno : ENODEV;\n+\t\treturn NULL;\n \t}\n-\tibv_dev = list[i];\n-\tDRV_LOG(DEBUG, \"device opened\");\n #ifdef HAVE_IBV_MLX5_MOD_SWP\n \tdv_attr.comp_mask |= MLX5DV_CONTEXT_MASK_SWP;\n #endif\n@@ -822,20 +773,11 @@ mlx5_pci_probe(struct rte_pci_driver *pci_drv __rte_unused,\n \tDRV_LOG(WARNING, \"MPLS over GRE/UDP tunnel offloading disabled due to\"\n \t\t\" old OFED/rdma-core version or firmware configuration\");\n #endif\n-\terr = mlx5_glue->query_device_ex(ctx, NULL, &attr);\n-\tif (err) {\n-\t\tDEBUG(\"ibv_query_device_ex() failed\");\n-\t\tgoto error;\n-\t}\n-\tDRV_LOG(INFO, \"%u port(s) detected\", attr.orig_attr.phys_port_cnt);\n-\tfor (i = 0; i < attr.orig_attr.phys_port_cnt; i++) {\n+\t{\n \t\tchar name[RTE_ETH_NAME_MAX_LEN];\n-\t\tint len;\n-\t\tuint32_t port = i + 1; /* ports are indexed from one */\n \t\tstruct ibv_port_attr port_attr;\n \t\tstruct ibv_pd *pd = NULL;\n \t\tstruct priv *priv = NULL;\n-\t\tstruct rte_eth_dev *eth_dev = NULL;\n \t\tstruct ether_addr mac;\n \t\tstruct mlx5_dev_config config = {\n \t\t\t.cqe_comp = cqe_comp,\n@@ -859,11 +801,11 @@ mlx5_pci_probe(struct rte_pci_driver *pci_drv __rte_unused,\n \t\t\t},\n \t\t};\n \n-\t\tlen = snprintf(name, sizeof(name), PCI_PRI_FMT,\n-\t\t\t pci_dev->addr.domain, pci_dev->addr.bus,\n-\t\t\t pci_dev->addr.devid, pci_dev->addr.function);\n-\t\tif (attr.orig_attr.phys_port_cnt > 1)\n-\t\t\tsnprintf(name + len, sizeof(name), \" port %u\", i);\n+\t\tif (attr->orig_attr.phys_port_cnt > 1)\n+\t\t\tsnprintf(name, sizeof(name), \"%s port %u\",\n+\t\t\t\t dpdk_dev->name, port);\n+\t\telse\n+\t\t\tsnprintf(name, sizeof(name), \"%s\", dpdk_dev->name);\n \t\tif (rte_eal_process_type() == RTE_PROC_SECONDARY) {\n \t\t\teth_dev = rte_eth_dev_attach_secondary(name);\n \t\t\tif (eth_dev == NULL) {\n@@ -872,7 +814,7 @@ mlx5_pci_probe(struct rte_pci_driver *pci_drv __rte_unused,\n \t\t\t\terr = rte_errno;\n \t\t\t\tgoto error;\n \t\t\t}\n-\t\t\teth_dev->device = &pci_dev->device;\n+\t\t\teth_dev->device = dpdk_dev;\n \t\t\teth_dev->dev_ops = &mlx5_dev_sec_ops;\n \t\t\terr = mlx5_uar_init_secondary(eth_dev);\n \t\t\tif (err) {\n@@ -900,16 +842,10 @@ mlx5_pci_probe(struct rte_pci_driver *pci_drv __rte_unused,\n \t\t\t\tmlx5_select_rx_function(eth_dev);\n \t\t\teth_dev->tx_pkt_burst =\n \t\t\t\tmlx5_select_tx_function(eth_dev);\n-\t\t\trte_eth_dev_probing_finish(eth_dev);\n-\t\t\tcontinue;\n+\t\t\tmlx5_glue->close_device(ctx);\n+\t\t\treturn eth_dev;\n \t\t}\n \t\tDRV_LOG(DEBUG, \"using port %u\", port);\n-\t\tif (!ctx)\n-\t\t\tctx = mlx5_glue->open_device(ibv_dev);\n-\t\tif (ctx == NULL) {\n-\t\t\terr = ENODEV;\n-\t\t\tgoto port_error;\n-\t\t}\n \t\t/* Check port status. */\n \t\terr = mlx5_glue->query_port(ctx, port, &port_attr);\n \t\tif (err) {\n@@ -947,23 +883,23 @@ mlx5_pci_probe(struct rte_pci_driver *pci_drv __rte_unused,\n \t\tpriv->ctx = ctx;\n \t\tstrncpy(priv->ibdev_path, priv->ctx->device->ibdev_path,\n \t\t\tsizeof(priv->ibdev_path));\n-\t\tpriv->device_attr = attr;\n+\t\tpriv->device_attr = *attr;\n \t\tpriv->port = port;\n \t\tpriv->pd = pd;\n \t\tpriv->mtu = ETHER_MTU;\n-\t\terr = mlx5_args(&config, pci_dev->device.devargs);\n+\t\terr = mlx5_args(&config, dpdk_dev->devargs);\n \t\tif (err) {\n \t\t\terr = rte_errno;\n \t\t\tDRV_LOG(ERR, \"failed to process device arguments: %s\",\n \t\t\t\tstrerror(rte_errno));\n \t\t\tgoto port_error;\n \t\t}\n-\t\tconfig.hw_csum = !!(attr.device_cap_flags_ex &\n+\t\tconfig.hw_csum = !!(attr->device_cap_flags_ex &\n \t\t\t\t    IBV_DEVICE_RAW_IP_CSUM);\n \t\tDRV_LOG(DEBUG, \"checksum offloading is %ssupported\",\n \t\t\t(config.hw_csum ? \"\" : \"not \"));\n #ifdef HAVE_IBV_DEVICE_COUNTERS_SET_SUPPORT\n-\t\tconfig.flow_counter_en = !!attr.max_counter_sets;\n+\t\tconfig.flow_counter_en = !!attr->max_counter_sets;\n \t\tmlx5_glue->describe_counter_set(ctx, 0, &cs_desc);\n \t\tDRV_LOG(DEBUG,\n \t\t\t\"counter type = %d, num of cs = %ld, attributes = %d\",\n@@ -971,7 +907,7 @@ mlx5_pci_probe(struct rte_pci_driver *pci_drv __rte_unused,\n \t\t\tcs_desc.attributes);\n #endif\n \t\tconfig.ind_table_max_size =\n-\t\t\tattr.rss_caps.max_rwq_indirection_table_size;\n+\t\t\tattr->rss_caps.max_rwq_indirection_table_size;\n \t\t/* Remove this check once DPDK supports larger/variable\n \t\t * indirection tables. */\n \t\tif (config.ind_table_max_size >\n@@ -979,28 +915,28 @@ mlx5_pci_probe(struct rte_pci_driver *pci_drv __rte_unused,\n \t\t\tconfig.ind_table_max_size = ETH_RSS_RETA_SIZE_512;\n \t\tDRV_LOG(DEBUG, \"maximum Rx indirection table size is %u\",\n \t\t\tconfig.ind_table_max_size);\n-\t\tconfig.hw_vlan_strip = !!(attr.raw_packet_caps &\n+\t\tconfig.hw_vlan_strip = !!(attr->raw_packet_caps &\n \t\t\t\t\t IBV_RAW_PACKET_CAP_CVLAN_STRIPPING);\n \t\tDRV_LOG(DEBUG, \"VLAN stripping is %ssupported\",\n \t\t\t(config.hw_vlan_strip ? \"\" : \"not \"));\n \n-\t\tconfig.hw_fcs_strip = !!(attr.raw_packet_caps &\n+\t\tconfig.hw_fcs_strip = !!(attr->raw_packet_caps &\n \t\t\t\t\t IBV_RAW_PACKET_CAP_SCATTER_FCS);\n \t\tDRV_LOG(DEBUG, \"FCS stripping configuration is %ssupported\",\n \t\t\t(config.hw_fcs_strip ? \"\" : \"not \"));\n \n #ifdef HAVE_IBV_WQ_FLAG_RX_END_PADDING\n-\t\tconfig.hw_padding = !!attr.rx_pad_end_addr_align;\n+\t\tconfig.hw_padding = !!attr->rx_pad_end_addr_align;\n #endif\n \t\tDRV_LOG(DEBUG,\n \t\t\t\"hardware Rx end alignment padding is %ssupported\",\n \t\t\t(config.hw_padding ? \"\" : \"not \"));\n \t\tconfig.vf = vf;\n-\t\tconfig.tso = (attr.tso_caps.max_tso > 0 &&\n-\t\t\t      (attr.tso_caps.supported_qpts &\n+\t\tconfig.tso = (attr->tso_caps.max_tso > 0 &&\n+\t\t\t      (attr->tso_caps.supported_qpts &\n \t\t\t       (1 << IBV_QPT_RAW_PACKET)));\n \t\tif (config.tso)\n-\t\t\tconfig.tso_max_payload_sz = attr.tso_caps.max_tso;\n+\t\t\tconfig.tso_max_payload_sz = attr->tso_caps.max_tso;\n \t\tif (config.mps && !mps) {\n \t\t\tDRV_LOG(ERR,\n \t\t\t\t\"multi-packet send not supported on this device\"\n@@ -1041,8 +977,7 @@ mlx5_pci_probe(struct rte_pci_driver *pci_drv __rte_unused,\n \t\teth_dev->data->dev_private = priv;\n \t\tpriv->dev_data = eth_dev->data;\n \t\teth_dev->data->mac_addrs = priv->mac;\n-\t\teth_dev->device = &pci_dev->device;\n-\t\trte_eth_copy_pci_info(eth_dev, pci_dev);\n+\t\teth_dev->device = dpdk_dev;\n \t\teth_dev->device->driver = &mlx5_driver.driver;\n \t\terr = mlx5_uar_init_primary(eth_dev);\n \t\tif (err) {\n@@ -1160,13 +1095,7 @@ mlx5_pci_probe(struct rte_pci_driver *pci_drv __rte_unused,\n \t\t\t\t priv, mem_event_cb);\n \t\trte_rwlock_write_unlock(&mlx5_shared_data->mem_event_rwlock);\n \t\trte_eth_dev_probing_finish(eth_dev);\n-\t\t/*\n-\t\t * Each eth_dev instance is assigned its own Verbs context,\n-\t\t * since this one is consumed, let the next iteration open\n-\t\t * another.\n-\t\t */\n-\t\tctx = NULL;\n-\t\tcontinue;\n+\t\treturn eth_dev;\n port_error:\n \t\tif (priv)\n \t\t\trte_free(priv);\n@@ -1174,24 +1103,173 @@ mlx5_pci_probe(struct rte_pci_driver *pci_drv __rte_unused,\n \t\t\tclaim_zero(mlx5_glue->dealloc_pd(pd));\n \t\tif (eth_dev && rte_eal_process_type() == RTE_PROC_PRIMARY)\n \t\t\trte_eth_dev_release_port(eth_dev);\n-\t\tbreak;\n \t}\n-\t/*\n-\t * XXX if something went wrong in the loop above, there is a resource\n-\t * leak (ctx, pd, priv, dpdk ethdev) but we can do nothing about it as\n-\t * long as the dpdk does not provide a way to deallocate a ethdev and a\n-\t * way to enumerate the registered ethdevs to free the previous ones.\n-\t */\n error:\n \tif (ctx)\n \t\tclaim_zero(mlx5_glue->close_device(ctx));\n-\tif (list)\n-\t\tmlx5_glue->free_device_list(list);\n-\tif (err) {\n-\t\trte_errno = err;\n+\tassert(err > 0);\n+\trte_errno = err;\n+\treturn NULL;\n+}\n+\n+/**\n+ * Spawn Ethernet devices from Verbs information, one per detected port.\n+ *\n+ * @param dpdk_dev\n+ *   Backing DPDK device.\n+ * @param ibv_dev\n+ *   Verbs device.\n+ * @param vf\n+ *   If nonzero, enable VF-specific features.\n+ *\n+ * @return\n+ *   A NULL-terminated list of Ethernet device objects on success, NULL\n+ *   otherwise and rte_errno is set. Caller is expected to release list\n+ *   memory through free().\n+ */\n+static struct rte_eth_dev **\n+mlx5_dev_spawn(struct rte_device *dpdk_dev,\n+\t       struct ibv_device *ibv_dev,\n+\t       int vf)\n+{\n+\tstruct rte_eth_dev **eth_list = NULL;\n+\tstruct ibv_context *ctx;\n+\tstruct ibv_device_attr_ex attr;\n+\tunsigned int i;\n+\tint ret;\n+\n+\terrno = 0;\n+\tctx = mlx5_glue->open_device(ibv_dev);\n+\tif (!ctx) {\n+\t\trte_errno = errno ? errno : ENODEV;\n+\t\tif (rte_errno == ENODEV)\n+\t\t\tDRV_LOG(ERR,\n+\t\t\t\t\"cannot access device, is mlx5_ib loaded?\");\n+\t\telse\n+\t\t\tDRV_LOG(ERR,\n+\t\t\t\t\"cannot use device, are drivers up to date?\");\n+\t\treturn NULL;\n+\t}\n+\tret = mlx5_glue->query_device_ex(ctx, NULL, &attr);\n+\tmlx5_glue->close_device(ctx);\n+\tif (ret) {\n+\t\trte_errno = ret;\n+\t\tDRV_LOG(ERR, \"unable to query device information: %s\",\n+\t\t\tstrerror(rte_errno));\n+\t\treturn NULL;\n+\t}\n+\tDRV_LOG(INFO, \"%u port(s) detected\", attr.orig_attr.phys_port_cnt);\n+\teth_list = malloc(sizeof(*eth_list) *\n+\t\t\t  (attr.orig_attr.phys_port_cnt + 1));\n+\tif (!eth_list) {\n+\t\trte_errno = errno;\n+\t\treturn NULL;\n+\t}\n+\tfor (i = 0; i < attr.orig_attr.phys_port_cnt; ++i) {\n+\t\teth_list[i] = mlx5_dev_spawn_one(dpdk_dev, ibv_dev, vf,\n+\t\t\t\t\t\t &attr, i + 1);\n+\t\tif (eth_list[i])\n+\t\t\tcontinue;\n+\t\t/* Save rte_errno and roll back in case of failure. */\n+\t\tret = rte_errno;\n+\t\twhile (i--) {\n+\t\t\tmlx5_dev_close(eth_list[i]);\n+\t\t\tif (rte_eal_process_type() == RTE_PROC_PRIMARY)\n+\t\t\t\trte_free(eth_list[i]->data->dev_private);\n+\t\t\tclaim_zero(rte_eth_dev_release_port(eth_list[i]));\n+\t\t}\n+\t\tfree(eth_list);\n+\t\trte_errno = ret;\n+\t\treturn NULL;\n+\t}\n+\teth_list[i] = NULL;\n+\treturn eth_list;\n+}\n+\n+/**\n+ * DPDK callback to register a PCI device.\n+ *\n+ * This function creates an Ethernet device for each port of a given\n+ * PCI device.\n+ *\n+ * @param[in] pci_drv\n+ *   PCI driver structure (mlx5_driver).\n+ * @param[in] pci_dev\n+ *   PCI device information.\n+ *\n+ * @return\n+ *   0 on success, a negative errno value otherwise and rte_errno is set.\n+ */\n+static int\n+mlx5_pci_probe(struct rte_pci_driver *pci_drv __rte_unused,\n+\t       struct rte_pci_device *pci_dev)\n+{\n+\tstruct ibv_device **ibv_list;\n+\tstruct rte_eth_dev **eth_list = NULL;\n+\tint vf;\n+\tint ret;\n+\n+\tassert(pci_drv == &mlx5_driver);\n+\tswitch (pci_dev->id.device_id) {\n+\tcase PCI_DEVICE_ID_MELLANOX_CONNECTX4VF:\n+\tcase PCI_DEVICE_ID_MELLANOX_CONNECTX4LXVF:\n+\tcase PCI_DEVICE_ID_MELLANOX_CONNECTX5VF:\n+\tcase PCI_DEVICE_ID_MELLANOX_CONNECTX5EXVF:\n+\t\tvf = 1;\n+\t\tbreak;\n+\tdefault:\n+\t\tvf = 0;\n+\t}\n+\terrno = 0;\n+\tibv_list = mlx5_glue->get_device_list(&ret);\n+\tif (!ibv_list) {\n+\t\trte_errno = errno ? errno : ENOSYS;\n+\t\tDRV_LOG(ERR, \"cannot list devices, is ib_uverbs loaded?\");\n \t\treturn -rte_errno;\n \t}\n-\treturn 0;\n+\twhile (ret-- > 0) {\n+\t\tstruct rte_pci_addr pci_addr;\n+\n+\t\tDRV_LOG(DEBUG, \"checking device \\\"%s\\\"\", ibv_list[ret]->name);\n+\t\tif (mlx5_ibv_device_to_pci_addr(ibv_list[ret], &pci_addr))\n+\t\t\tcontinue;\n+\t\tif (pci_dev->addr.domain != pci_addr.domain ||\n+\t\t    pci_dev->addr.bus != pci_addr.bus ||\n+\t\t    pci_dev->addr.devid != pci_addr.devid ||\n+\t\t    pci_dev->addr.function != pci_addr.function)\n+\t\t\tcontinue;\n+\t\tDRV_LOG(INFO, \"PCI information matches, using device \\\"%s\\\"\",\n+\t\t\tibv_list[ret]->name);\n+\t\tbreak;\n+\t}\n+\tif (ret >= 0)\n+\t\teth_list = mlx5_dev_spawn(&pci_dev->device, ibv_list[ret], vf);\n+\tmlx5_glue->free_device_list(ibv_list);\n+\tif (!ret) {\n+\t\tDRV_LOG(WARNING,\n+\t\t\t\"no Verbs device matches PCI device \" PCI_PRI_FMT \",\"\n+\t\t\t\" are kernel drivers loaded?\",\n+\t\t\tpci_dev->addr.domain, pci_dev->addr.bus,\n+\t\t\tpci_dev->addr.devid, pci_dev->addr.function);\n+\t\trte_errno = ENOENT;\n+\t\tret = -rte_errno;\n+\t} else if (!eth_list || !*eth_list) {\n+\t\tDRV_LOG(ERR,\n+\t\t\t\"probe of PCI device \" PCI_PRI_FMT \" aborted after\"\n+\t\t\t\" encountering an error: %s\",\n+\t\t\tpci_dev->addr.domain, pci_dev->addr.bus,\n+\t\t\tpci_dev->addr.devid, pci_dev->addr.function,\n+\t\t\tstrerror(rte_errno));\n+\t\tret = -rte_errno;\n+\t} else {\n+\t\tfor (ret = 0; eth_list[ret]; ++ret) {\n+\t\t\trte_eth_copy_pci_info(eth_list[ret], pci_dev);\n+\t\t\trte_eth_dev_probing_finish(eth_list[ret]);\n+\t\t}\n+\t\tret = 0;\n+\t}\n+\tfree(eth_list);\n+\treturn ret;\n }\n \n static const struct rte_pci_id mlx5_pci_id_map[] = {\n",
    "prefixes": [
        "v2",
        "3/7"
    ]
}