get:
Show a patch.

patch:
Update a patch.

put:
Update a patch.

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

{
    "id": 74174,
    "url": "http://patches.dpdk.org/api/patches/74174/?format=api",
    "web_url": "http://patches.dpdk.org/project/dpdk/patch/20200716072938.812733-8-parav@mellanox.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": "<20200716072938.812733-8-parav@mellanox.com>",
    "list_archive_url": "https://inbox.dpdk.org/dev/20200716072938.812733-8-parav@mellanox.com",
    "date": "2020-07-16T07:29:36",
    "name": "[v6,7/9] bus/mlx5_pci: register a PCI driver",
    "commit_ref": null,
    "pull_url": null,
    "state": "superseded",
    "archived": true,
    "hash": "41319e374a3d32f4d9d614b39acda21e8b1e5c0f",
    "submitter": {
        "id": 1780,
        "url": "http://patches.dpdk.org/api/people/1780/?format=api",
        "name": "Parav Pandit",
        "email": "parav@mellanox.com"
    },
    "delegate": {
        "id": 3268,
        "url": "http://patches.dpdk.org/api/users/3268/?format=api",
        "username": "rasland",
        "first_name": "Raslan",
        "last_name": "Darawsheh",
        "email": "rasland@nvidia.com"
    },
    "mbox": "http://patches.dpdk.org/project/dpdk/patch/20200716072938.812733-8-parav@mellanox.com/mbox/",
    "series": [
        {
            "id": 11075,
            "url": "http://patches.dpdk.org/api/series/11075/?format=api",
            "web_url": "http://patches.dpdk.org/project/dpdk/list/?series=11075",
            "date": "2020-07-16T07:29:29",
            "name": "Improve mlx5 PMD driver framework for multiple classes",
            "version": 6,
            "mbox": "http://patches.dpdk.org/series/11075/mbox/"
        }
    ],
    "comments": "http://patches.dpdk.org/api/patches/74174/comments/",
    "check": "success",
    "checks": "http://patches.dpdk.org/api/patches/74174/checks/",
    "tags": {},
    "related": [],
    "headers": {
        "Return-Path": "<dev-bounces@dpdk.org>",
        "X-Original-To": "patchwork@inbox.dpdk.org",
        "Delivered-To": "patchwork@inbox.dpdk.org",
        "Received": [
            "from dpdk.org (dpdk.org [92.243.14.124])\n\tby inbox.dpdk.org (Postfix) with ESMTP id 66E83A0546;\n\tThu, 16 Jul 2020 09:31:14 +0200 (CEST)",
            "from [92.243.14.124] (localhost [127.0.0.1])\n\tby dpdk.org (Postfix) with ESMTP id 6B10C1BF75;\n\tThu, 16 Jul 2020 09:30:17 +0200 (CEST)",
            "from EUR04-DB3-obe.outbound.protection.outlook.com\n (mail-eopbgr60052.outbound.protection.outlook.com [40.107.6.52])\n by dpdk.org (Postfix) with ESMTP id 1A14D1BF6F\n for <dev@dpdk.org>; Thu, 16 Jul 2020 09:30:15 +0200 (CEST)",
            "from AM0PR05MB4866.eurprd05.prod.outlook.com (2603:10a6:208:c0::32)\n by AM0PR05MB5329.eurprd05.prod.outlook.com (2603:10a6:208:ed::23)\n with Microsoft SMTP Server (version=TLS1_2,\n cipher=TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384) id 15.20.3174.23; Thu, 16 Jul\n 2020 07:30:13 +0000",
            "from AM0PR05MB4866.eurprd05.prod.outlook.com\n ([fe80::d44d:a804:c730:d2b7]) by AM0PR05MB4866.eurprd05.prod.outlook.com\n ([fe80::d44d:a804:c730:d2b7%2]) with mapi id 15.20.3174.026; Thu, 16 Jul 2020\n 07:30:13 +0000",
            "from sw-mtx-036.mtx.labs.mlnx (208.176.44.194) by\n SN6PR16CA0057.namprd16.prod.outlook.com (2603:10b6:805:ca::34) with Microsoft\n SMTP Server (version=TLS1_2, cipher=TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384) id\n 15.20.3195.18 via Frontend Transport; Thu, 16 Jul 2020 07:30:11 +0000"
        ],
        "ARC-Seal": "i=1; a=rsa-sha256; s=arcselector9901; d=microsoft.com; cv=none;\n b=CkATPwg4AoikKKHhAauWCvngkHYXypFIBXwRcYvRJQ/AUjYonvHVTDgfKVMaZoncs0SlZLy4gP1U0v+2TtjdoTC9azdqO1FVBZ21+k27JJyvfhyEuHguPtyVtjXBNK/21/DOMWv2j90KqNiao4j0/tUh/DoJeGYontrGF2Vk851q5JsiJUJDp6Df3kxUr5BiSqEqloEYB0vbXcH1rDPeWQRNdhuW3hPVyIJcXJRSeRR2x/jOAqwWUDPbt3YcbrQuoLck5JbUiDVrPlHae8zYEftM8dHv8usSdH/oytn+rkpwTt3JCvKLDy7mxtCQ+AaTaTKORxdVjdyGS+LVIEnAlw==",
        "ARC-Message-Signature": "i=1; a=rsa-sha256; c=relaxed/relaxed; d=microsoft.com;\n s=arcselector9901;\n h=From:Date:Subject:Message-ID:Content-Type:MIME-Version:X-MS-Exchange-SenderADCheck;\n bh=ee1TUCMZUBqE5Q1MUBfQhjXgK/4FkiTYc1AgqMHIB8Q=;\n b=n/r/F2eKjjPNEoM6RdXucsXin6U7eUO3iGxNZFpgvi2V7pMIbNHGpscshFmAUKC3XbLyS2xqdfUFQflA66kRMYbHU5weGQetKz1qy6riR1AX3h9VX/U4rFkgTFOCSpNdCsia8f7rAbg9rS5+ufwx5EwF0mAYk7Koh0FIHJTkBLtvrs55VhehwJEiiW/EVSQ9W10MDg8l718e5wQuuR63dBeX5p20ASonAza3EU+g2smJx4wR9dI2PuJL0n6zA0IHahrGRKiE1a+Wwh37dTmZH+5pO4ds/b0w4vfVt/59OTdpatINRbgUh+uDPmGAaF3dQS7jZVrmd7lWMm1+eMaqgw==",
        "ARC-Authentication-Results": "i=1; mx.microsoft.com 1; spf=pass\n smtp.mailfrom=mellanox.com; dmarc=pass action=none header.from=mellanox.com;\n dkim=pass header.d=mellanox.com; arc=none",
        "DKIM-Signature": "v=1; a=rsa-sha256; c=relaxed/relaxed; d=Mellanox.com;\n s=selector1;\n h=From:Date:Subject:Message-ID:Content-Type:MIME-Version:X-MS-Exchange-SenderADCheck;\n bh=ee1TUCMZUBqE5Q1MUBfQhjXgK/4FkiTYc1AgqMHIB8Q=;\n b=nLDf1vQlf0dMt6S4uEm1yjSjTGbvBewGjs2tnrzA4BHL4PAcloJHM6CmkooDZ69FpBTETByLcMC/VAtE4ms9qoXt3Hg0UG3HuDrfUl4Ttot2egHabMYBJ7RUj/JUyBYAnMtqZl+VSE7x5LL122mOqlZGwgLrV0ePofsKqpsxpLw=",
        "Authentication-Results": "dpdk.org; dkim=none (message not signed)\n header.d=none;dpdk.org; dmarc=none action=none header.from=mellanox.com;",
        "From": "Parav Pandit <parav@mellanox.com>",
        "To": "dev@dpdk.org, grive@u256.net, ferruh.yigit@intel.com, thomas@monjalon.net",
        "Cc": "rasland@mellanox.com, orika@mellanox.com, matan@mellanox.com,\n joyce.kong@arm.com, Parav Pandit <parav@mellanox.com>",
        "Date": "Thu, 16 Jul 2020 10:29:36 +0300",
        "Message-Id": "<20200716072938.812733-8-parav@mellanox.com>",
        "X-Mailer": [
            "git-send-email 2.26.2",
            "git-send-email 2.26.2"
        ],
        "In-Reply-To": "<20200716072938.812733-1-parav@mellanox.com>",
        "References": "<20200610171728.89-2-parav@mellanox.com>\n <20200716072938.812733-1-parav@mellanox.com>",
        "Content-Transfer-Encoding": "8bit",
        "Content-Type": "text/plain",
        "X-ClientProxiedBy": "SN6PR16CA0057.namprd16.prod.outlook.com\n (2603:10b6:805:ca::34) To AM0PR05MB4866.eurprd05.prod.outlook.com\n (2603:10a6:208:c0::32)",
        "MIME-Version": "1.0",
        "X-MS-Exchange-MessageSentRepresentingType": "1",
        "X-Originating-IP": "[208.176.44.194]",
        "X-MS-PublicTrafficType": "Email",
        "X-MS-Office365-Filtering-HT": "Tenant",
        "X-MS-Office365-Filtering-Correlation-Id": "670a92e2-8e20-46e4-e2ce-08d8295a1411",
        "X-MS-TrafficTypeDiagnostic": "AM0PR05MB5329:",
        "X-LD-Processed": "a652971c-7d2e-4d9b-a6a4-d149256f461b,ExtFwd,ExtAddr",
        "X-MS-Exchange-Transport-Forked": "True",
        "X-Microsoft-Antispam-PRVS": "\n <AM0PR05MB53297E928C56B102C0FDA13FD17F0@AM0PR05MB5329.eurprd05.prod.outlook.com>",
        "X-MS-Oob-TLC-OOBClassifiers": "OLM:619;",
        "X-MS-Exchange-SenderADCheck": "1",
        "X-Microsoft-Antispam": "BCL:0;",
        "X-Microsoft-Antispam-Message-Info": "\n ddZfzjlg3eyBgd9712+IR21SjyLCMnbUCfxsSDexq466m6ZbNYo/BzDdapL3BvtHchTZre8ojBMdHs6mlSAI6CKt6GdoeE+guXQ9AxoBhk4NtEsST3KBzasslEhxNeOgYpVqNi4CoRvEfk9eIZwi+9Tz/Uo/JuPNTLrRvqy8nCTxQLEgV+Bpq4fOfPbTjy6DnSJ1kMZ8bk96ZW1XCZIZVEeddRc7Rk98KDBGWMJIVee7aVxt+Ufbdmr29jNhLRb+5cKXHLiNBdM+utQaNfoxWzj9lD5NotlQf6RsRQU/SOt8KBiEs7OK+6QEJpVU/Z54",
        "X-Forefront-Antispam-Report": "CIP:255.255.255.255; CTRY:; LANG:en; SCL:1; SRV:;\n IPV:NLI; SFV:NSPM; H:AM0PR05MB4866.eurprd05.prod.outlook.com; PTR:; CAT:NONE;\n SFTY:;\n SFS:(4636009)(376002)(366004)(346002)(136003)(396003)(39860400002)(6506007)(6666004)(16526019)(186003)(66946007)(107886003)(66556008)(26005)(8936002)(86362001)(6512007)(6486002)(52116002)(83380400001)(66476007)(5660300002)(2616005)(956004)(36756003)(8676002)(478600001)(316002)(1076003)(2906002)(30864003)(4326008);\n DIR:OUT; SFP:1101;",
        "X-MS-Exchange-AntiSpam-MessageData": "\n Mr75BF3tRjyCKTFouQkKXHZ18Mfs6V9tv965j/RmCqE2gMcB0/MP3fXrHfygTSqwmOyvFpIxNO4c6c+0qsP5KxfAabMLJB1Nru3FcVZJdJhYtmSwHtaIGk2Zdd15poRzEYpz2CH93gmjai9DYjSLH7n4k62XRxkAb1tRES8Xo0JVWQofOWv1igLfOTnxL3+8L0lgsHsKEcxVh/BArSpXNEBm0TuBj1XUkOfmMRsk0mm119eEjRn0n3v7SYwET7cDzI/z/HEyNFja6gjRCjSzsMUDxK3opYeFNUGMNX8zWq6CCjqTSStvIzdNwL4wpVkVTc4Tgj4R5FrhjnGufOdVQ9AGjkbV1x0UjNgvSMHyEQRL7u71J20qD7YA/lGjVE8HCZpo+aAIp3XILr95dAuxg4R/BK0UytMDl/6BTrnS6iRmJhb12cVua/zT0DcHH6UBMRXPs/l3vpN1waFD/cdM9uFyGUQttcDpjIw4s5xSqyZxygePwRIyGN8UU1PBZOLf",
        "X-OriginatorOrg": "Mellanox.com",
        "X-MS-Exchange-CrossTenant-Network-Message-Id": "\n 670a92e2-8e20-46e4-e2ce-08d8295a1411",
        "X-MS-Exchange-CrossTenant-AuthSource": "AM0PR05MB4866.eurprd05.prod.outlook.com",
        "X-MS-Exchange-CrossTenant-AuthAs": "Internal",
        "X-MS-Exchange-CrossTenant-OriginalArrivalTime": "16 Jul 2020 07:30:13.8094 (UTC)",
        "X-MS-Exchange-CrossTenant-FromEntityHeader": "Hosted",
        "X-MS-Exchange-CrossTenant-Id": "a652971c-7d2e-4d9b-a6a4-d149256f461b",
        "X-MS-Exchange-CrossTenant-MailboxType": "HOSTED",
        "X-MS-Exchange-CrossTenant-UserPrincipalName": "\n c+hTKNQqikRwPVd9kGmvW+LKek7L02XCcAuWVGrCMm+zN9fnT76feWax01cm6r4sSy0x5t84/BJQmoS7eJiOFA==",
        "X-MS-Exchange-Transport-CrossTenantHeadersStamped": "AM0PR05MB5329",
        "Subject": "[dpdk-dev] [PATCH v6 7/9] bus/mlx5_pci: register a PCI driver",
        "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://mails.dpdk.org/options/dev>,\n <mailto:dev-request@dpdk.org?subject=unsubscribe>",
        "List-Archive": "<http://mails.dpdk.org/archives/dev/>",
        "List-Post": "<mailto:dev@dpdk.org>",
        "List-Help": "<mailto:dev-request@dpdk.org?subject=help>",
        "List-Subscribe": "<https://mails.dpdk.org/listinfo/dev>,\n <mailto:dev-request@dpdk.org?subject=subscribe>",
        "Errors-To": "dev-bounces@dpdk.org",
        "Sender": "\"dev\" <dev-bounces@dpdk.org>"
    },
    "content": "Create a mlx5 bus driver framework for invoking drivers of\nmultiple classes who have registered with the mlx5_pci bus\ndriver.\n\nValidate user class arguments for supported class combinations.\n\nSigned-off-by: Parav Pandit <parav@mellanox.com>\nAcked-by: Matan Azrad <matan@mellanox.com>\n---\nChangelog:\nv3->v4:\n - Fixed dma_map error unwinding flow to follow same order for unmap\nv2->v3:\n - Addressed comments from Asaf\n - Using full names in function names\n - Added new line before function name in multiple functions\n - Added example string to parse for multiple classes\n - Dropped mlx5 prefix from static function\n - Addressed comments from Matan.\n - Renamed mlx5_valid_class_combo to mlx5_class_combinations\n - Added cross check for class drivers to support only 3 flags for now\n - Added full stop at the end of comment block.\n - Removed empty lines\n - Fixed issue to remove multiple classes for a driver\n - Using define for drv_flags at multiple places\n - Maintaining class driver list to keep load/unload order symmetric and\n   mirror of each other.\n - Deriving drv_flags based on the class drivers\n - Using PCI address comparision helper instead of pointer comparision\n - Fixed alignment for id_table\n - Continue to probe_err if device is already probed\n - Perform dma map on best effort basis for all supported drivers\n - Removed drv_flags check\n - Dynamically build pci id table\n - Using PCI to mlx5 device helper routines\nv1->v2:\n - Address comments from Thomas and Gaetan\n - Enhanced driver to honor RTE_PCI_DRV_PROBE_AGAIN drv_flag\n - Use anonymous structure for class search and code changes around it\n - Define static for class comination array\n - Use RTE_DIM to find array size\n - Added OOM check for strdup()\n - Renamed copy variable to nstr_orig\n - Returning negagive error code\n - Returning directly if match entry found\n - Use compat condition check\n - Avoided cutting error message string\n - USe uint32_t datatype instead of enum mlx5_class\n - Changed logic to parse device arguments only once during probe()\n - Added check to fail driver probe if multiple classes register with\n   DMA ops\n - Renamed function to parse_class_options\n---\n drivers/bus/mlx5_pci/Makefile       |   2 +\n drivers/bus/mlx5_pci/meson.build    |   2 +-\n drivers/bus/mlx5_pci/mlx5_pci_bus.c | 508 ++++++++++++++++++++++++++++\n 3 files changed, 511 insertions(+), 1 deletion(-)",
    "diff": "diff --git a/drivers/bus/mlx5_pci/Makefile b/drivers/bus/mlx5_pci/Makefile\nindex dd24811a3..ee1af4dc6 100644\n--- a/drivers/bus/mlx5_pci/Makefile\n+++ b/drivers/bus/mlx5_pci/Makefile\n@@ -16,7 +16,9 @@ CFLAGS += -I$(BUILDDIR)/drivers/common/mlx5\n CFLAGS += -I$(RTE_SDK)/drivers/common/mlx5/linux\n CFLAGS += -I$(BUILDDIR)/drivers/bus/pci\n CFLAGS += -I$(BUILDDIR)/drivers/bus\n+CFLAGS += -D_DEFAULT_SOURCE\n LDLIBS += -lrte_eal\n+LDLIBS += -lrte_kvargs\n LDLIBS += -lrte_common_mlx5\n LDLIBS += -lrte_pci -lrte_bus_pci\n \ndiff --git a/drivers/bus/mlx5_pci/meson.build b/drivers/bus/mlx5_pci/meson.build\nindex 64a17cbad..0532a9dfd 100644\n--- a/drivers/bus/mlx5_pci/meson.build\n+++ b/drivers/bus/mlx5_pci/meson.build\n@@ -1,7 +1,7 @@\n # SPDX-License-Identifier: BSD-3-Clause\n # Copyright(c) 2020 Mellanox Technologies Ltd\n \n-deps += ['pci', 'bus_pci', 'common_mlx5']\n+deps += ['pci', 'bus_pci', 'common_mlx5', 'kvargs']\n install_headers('rte_bus_mlx5_pci.h')\n sources = files('mlx5_pci_bus.c')\n \ndiff --git a/drivers/bus/mlx5_pci/mlx5_pci_bus.c b/drivers/bus/mlx5_pci/mlx5_pci_bus.c\nindex 66db3c7b0..6f219730c 100644\n--- a/drivers/bus/mlx5_pci/mlx5_pci_bus.c\n+++ b/drivers/bus/mlx5_pci/mlx5_pci_bus.c\n@@ -2,13 +2,521 @@\n  * Copyright 2020 Mellanox Technologies, Ltd\n  */\n \n+#include <stdlib.h>\n+#include <rte_malloc.h>\n #include \"rte_bus_mlx5_pci.h\"\n+#include <mlx5_common_utils.h>\n \n+struct mlx5_pci_device {\n+\tstruct rte_pci_device *pci_dev;\n+\tTAILQ_ENTRY(mlx5_pci_device) next;\n+\tuint32_t classes_loaded;\n+};\n+\n+/* Head of list of class drivers. */\n static TAILQ_HEAD(mlx5_pci_bus_drv_head, rte_mlx5_pci_driver) drv_list =\n \t\t\t\tTAILQ_HEAD_INITIALIZER(drv_list);\n \n+/* Head of mlx5 pci devices. */\n+static TAILQ_HEAD(mlx5_pci_devices_head, mlx5_pci_device) devices_list =\n+\t\t\t\tTAILQ_HEAD_INITIALIZER(devices_list);\n+\n+static const struct {\n+\tconst char *name;\n+\tunsigned int dev_class;\n+} mlx5_classes[] = {\n+\t{ .name = \"vdpa\", .dev_class = MLX5_CLASS_VDPA },\n+\t{ .name = \"net\", .dev_class = MLX5_CLASS_NET },\n+};\n+\n+static const unsigned int mlx5_class_combinations[] = {\n+\tMLX5_CLASS_NET,\n+\tMLX5_CLASS_VDPA,\n+\t/* New class combination should be added here.\n+\t * For example a new multi class device combination\n+\t * can be MLX5_CLASS_FOO | MLX5_CLASS_BAR.\n+\t */\n+};\n+\n+static int\n+class_name_to_value(const char *class_name)\n+{\n+\tunsigned int i;\n+\n+\tfor (i = 0; i < RTE_DIM(mlx5_classes); i++) {\n+\t\tif (strcmp(class_name, mlx5_classes[i].name) == 0)\n+\t\t\treturn mlx5_classes[i].dev_class;\n+\t}\n+\treturn -EINVAL;\n+}\n+\n+static struct rte_mlx5_pci_driver *\n+class_driver_get(uint32_t class)\n+{\n+\tstruct rte_mlx5_pci_driver *driver;\n+\n+\tTAILQ_FOREACH(driver, &drv_list, next) {\n+\t\tif (driver->dev_class == class)\n+\t\t\treturn driver;\n+\t}\n+\treturn NULL;\n+}\n+\n+static int\n+bus_cmdline_options_handler(__rte_unused const char *key,\n+\t\t\t    const char *class_names, void *opaque)\n+{\n+\tint *ret = opaque;\n+\tchar *nstr_org;\n+\tint class_val;\n+\tchar *found;\n+\tchar *nstr;\n+\n+\t*ret = 0;\n+\tnstr = strdup(class_names);\n+\tif (!nstr) {\n+\t\t*ret = -ENOMEM;\n+\t\treturn *ret;\n+\t}\n+\tnstr_org = nstr;\n+\twhile (nstr) {\n+\t\t/* Extract each individual class name. Multiple\n+\t\t * class key,value is supplied as class=net:vdpa:foo:bar.\n+\t\t */\n+\t\tfound = strsep(&nstr, \":\");\n+\t\tif (!found)\n+\t\t\tcontinue;\n+\t\t/* Check if its a valid class. */\n+\t\tclass_val = class_name_to_value(found);\n+\t\tif (class_val < 0) {\n+\t\t\t*ret = -EINVAL;\n+\t\t\tgoto err;\n+\t\t}\n+\t\t*ret |= class_val;\n+\t}\n+err:\n+\tfree(nstr_org);\n+\tif (*ret < 0)\n+\t\tDRV_LOG(ERR, \"Invalid mlx5 class options %s.\"\n+\t\t\t\" Maybe typo in device class argument setting?\",\n+\t\t\tclass_names);\n+\treturn *ret;\n+}\n+\n+static int\n+parse_class_options(const struct rte_devargs *devargs)\n+{\n+\tconst char *key = MLX5_CLASS_ARG_NAME;\n+\tstruct rte_kvargs *kvlist;\n+\tint ret = 0;\n+\n+\tif (devargs == NULL)\n+\t\treturn 0;\n+\tkvlist = rte_kvargs_parse(devargs->args, NULL);\n+\tif (kvlist == NULL)\n+\t\treturn 0;\n+\tif (rte_kvargs_count(kvlist, key))\n+\t\trte_kvargs_process(kvlist, key, bus_cmdline_options_handler,\n+\t\t\t\t   &ret);\n+\trte_kvargs_free(kvlist);\n+\treturn ret;\n+}\n+\n void\n rte_mlx5_pci_driver_register(struct rte_mlx5_pci_driver *driver)\n {\n \tTAILQ_INSERT_TAIL(&drv_list, driver, next);\n }\n+\n+static bool\n+mlx5_bus_match(const struct rte_mlx5_pci_driver *drv,\n+\t       const struct rte_pci_device *pci_dev)\n+{\n+\tconst struct rte_pci_id *id_table;\n+\n+\tfor (id_table = drv->pci_driver.id_table; id_table->vendor_id != 0;\n+\t     id_table++) {\n+\t\t/* Check if device's ids match the class driver's ids. */\n+\t\tif (id_table->vendor_id != pci_dev->id.vendor_id &&\n+\t\t    id_table->vendor_id != PCI_ANY_ID)\n+\t\t\tcontinue;\n+\t\tif (id_table->device_id != pci_dev->id.device_id &&\n+\t\t    id_table->device_id != PCI_ANY_ID)\n+\t\t\tcontinue;\n+\t\tif (id_table->subsystem_vendor_id !=\n+\t\t    pci_dev->id.subsystem_vendor_id &&\n+\t\t    id_table->subsystem_vendor_id != PCI_ANY_ID)\n+\t\t\tcontinue;\n+\t\tif (id_table->subsystem_device_id !=\n+\t\t    pci_dev->id.subsystem_device_id &&\n+\t\t    id_table->subsystem_device_id != PCI_ANY_ID)\n+\t\t\tcontinue;\n+\t\tif (id_table->class_id != pci_dev->id.class_id &&\n+\t\t    id_table->class_id != RTE_CLASS_ANY_ID)\n+\t\t\tcontinue;\n+\t\treturn true;\n+\t}\n+\treturn false;\n+}\n+\n+static int\n+is_valid_class_combination(uint32_t user_classes)\n+{\n+\tunsigned int i;\n+\n+\t/* Verify if user specified valid supported combination. */\n+\tfor (i = 0; i < RTE_DIM(mlx5_class_combinations); i++) {\n+\t\tif (mlx5_class_combinations[i] == user_classes)\n+\t\t\treturn 0;\n+\t}\n+\t/* Not found any valid class combination. */\n+\treturn -EINVAL;\n+}\n+\n+static struct mlx5_pci_device *\n+pci_to_mlx5_device(const struct rte_pci_device *pci_dev)\n+{\n+\tstruct mlx5_pci_device *dev;\n+\n+\tTAILQ_FOREACH(dev, &devices_list, next) {\n+\t\tif (dev->pci_dev == pci_dev)\n+\t\t\treturn dev;\n+\t}\n+\treturn NULL;\n+}\n+\n+static bool\n+device_class_enabled(const struct mlx5_pci_device *device, uint32_t class)\n+{\n+\treturn (device->classes_loaded & class) ? true : false;\n+}\n+\n+static void\n+dev_release(struct mlx5_pci_device *dev)\n+{\n+\tTAILQ_REMOVE(&devices_list, dev, next);\n+\trte_free(dev);\n+}\n+\n+static int\n+class_drivers_remove(struct mlx5_pci_device *dev, uint32_t enabled_classes)\n+{\n+\tstruct rte_mlx5_pci_driver *driver;\n+\tint local_ret = -ENODEV;\n+\tunsigned int i = 0;\n+\tint ret = 0;\n+\n+\tenabled_classes &= dev->classes_loaded;\n+\twhile (enabled_classes) {\n+\t\tdriver = class_driver_get(RTE_BIT64(i));\n+\t\tif (driver) {\n+\t\t\tlocal_ret = driver->pci_driver.remove(dev->pci_dev);\n+\t\t\tif (!local_ret)\n+\t\t\t\tdev->classes_loaded &= ~RTE_BIT64(i);\n+\t\t\telse if (ret == 0)\n+\t\t\t\tret = local_ret;\n+\t\t}\n+\t\tenabled_classes &= ~RTE_BIT64(i);\n+\t\ti++;\n+\t}\n+\tif (local_ret)\n+\t\tret = local_ret;\n+\treturn ret;\n+}\n+\n+static int\n+class_drivers_probe(struct mlx5_pci_device *dev,\n+\t\t    struct rte_pci_driver *pci_drv,\n+\t\t    struct rte_pci_device *pci_dev, uint32_t user_classes)\n+{\n+\tstruct rte_mlx5_pci_driver *driver;\n+\tuint32_t enabled_classes = 0;\n+\tbool already_loaded;\n+\tint ret;\n+\n+\tTAILQ_FOREACH(driver, &drv_list, next) {\n+\t\tif ((driver->dev_class & user_classes) == 0)\n+\t\t\tcontinue;\n+\t\tif (!mlx5_bus_match(driver, pci_dev))\n+\t\t\tcontinue;\n+\t\talready_loaded = dev->classes_loaded & driver->dev_class;\n+\t\tif (already_loaded &&\n+\t\t    !(driver->pci_driver.drv_flags & RTE_PCI_DRV_PROBE_AGAIN)) {\n+\t\t\tDRV_LOG(ERR, \"Device %s is already probed\\n\",\n+\t\t\t\tpci_dev->device.name);\n+\t\t\tret = -EEXIST;\n+\t\t\tgoto probe_err;\n+\t\t}\n+\t\tret = driver->pci_driver.probe(pci_drv, pci_dev);\n+\t\tif (ret < 0) {\n+\t\t\tDRV_LOG(ERR, \"Failed to load class driver = %s.\\n\",\n+\t\t\t\tdriver->pci_driver.driver.name);\n+\t\t\tgoto probe_err;\n+\t\t}\n+\t\tenabled_classes |= driver->dev_class;\n+\t}\n+\tdev->classes_loaded |= enabled_classes;\n+\treturn 0;\n+probe_err:\n+\t/* Only unload drivers which are enabled which were enabled\n+\t * in this probe instance.\n+\t */\n+\tclass_drivers_remove(dev, enabled_classes);\n+\treturn ret;\n+}\n+\n+/**\n+ * DPDK callback to register to probe multiple PCI class devices.\n+ *\n+ * @param[in] pci_drv\n+ *   PCI driver structure.\n+ * @param[in] 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_bus_pci_probe(struct rte_pci_driver *pci_drv __rte_unused,\n+\t\t   struct rte_pci_device *pci_dev)\n+{\n+\tstruct mlx5_pci_device *dev;\n+\tuint32_t user_classes = 0;\n+\tbool new_device = false;\n+\tint ret;\n+\n+\tret = parse_class_options(pci_dev->device.devargs);\n+\tif (ret < 0)\n+\t\treturn ret;\n+\tuser_classes = ret;\n+\tif (user_classes) {\n+\t\t/* Validate combination here. */\n+\t\tret = is_valid_class_combination(user_classes);\n+\t\tif (ret) {\n+\t\t\tDRV_LOG(ERR, \"Unsupported mlx5 classes supplied.\");\n+\t\t\treturn ret;\n+\t\t}\n+\t} else {\n+\t\t/* Default to net class. */\n+\t\tuser_classes = MLX5_CLASS_NET;\n+\t}\n+\tdev = pci_to_mlx5_device(pci_dev);\n+\tif (!dev) {\n+\t\tdev = rte_zmalloc(\"mlx5_pci_device\", sizeof(*dev), 0);\n+\t\tif (!dev)\n+\t\t\treturn -ENOMEM;\n+\t\tdev->pci_dev = pci_dev;\n+\t\tTAILQ_INSERT_HEAD(&devices_list, dev, next);\n+\t\tnew_device = true;\n+\t}\n+\tret = class_drivers_probe(dev, pci_drv, pci_dev, user_classes);\n+\tif (ret)\n+\t\tgoto class_err;\n+\treturn 0;\n+class_err:\n+\tif (new_device)\n+\t\tdev_release(dev);\n+\treturn ret;\n+}\n+\n+/**\n+ * DPDK callback to remove one or more class devices for a PCI device.\n+ *\n+ * This function removes all class devices belong to a given PCI device.\n+ *\n+ * @param[in] pci_dev\n+ *   Pointer to the PCI device.\n+ *\n+ * @return\n+ *   0 on success, the function cannot fail.\n+ */\n+static int\n+mlx5_bus_pci_remove(struct rte_pci_device *pci_dev)\n+{\n+\tstruct mlx5_pci_device *dev;\n+\tint ret;\n+\n+\tdev = pci_to_mlx5_device(pci_dev);\n+\tif (!dev)\n+\t\treturn -ENODEV;\n+\t/* Matching device found, cleanup and unload class drivers. */\n+\tret = class_drivers_remove(dev, dev->classes_loaded);\n+\tif (!ret)\n+\t\tdev_release(dev);\n+\treturn ret;\n+}\n+\n+static int\n+mlx5_bus_pci_dma_map(struct rte_pci_device *pci_dev, void *addr,\n+\t\t     uint64_t iova, size_t len)\n+{\n+\tstruct rte_mlx5_pci_driver *class = NULL;\n+\tstruct rte_mlx5_pci_driver *temp;\n+\tstruct mlx5_pci_device *dev;\n+\tint ret = -EINVAL;\n+\n+\tdev = pci_to_mlx5_device(pci_dev);\n+\tif (!dev)\n+\t\treturn -ENODEV;\n+\tTAILQ_FOREACH(class, &drv_list, next) {\n+\t\tif (device_class_enabled(dev, class->dev_class) &&\n+\t\t    class->pci_driver.dma_map) {\n+\t\t\tret = class->pci_driver.dma_map(pci_dev, addr,\n+\t\t\t\t\t\t\tiova, len);\n+\t\t\tif (ret)\n+\t\t\t\tgoto map_err;\n+\t\t}\n+\t}\n+\treturn ret;\n+map_err:\n+\tTAILQ_FOREACH(temp, &drv_list, next) {\n+\t\tif (temp == class)\n+\t\t\tbreak;\n+\t\tif (device_class_enabled(dev, temp->dev_class) &&\n+\t\t    temp->pci_driver.dma_map && temp->pci_driver.dma_unmap)\n+\t\t\ttemp->pci_driver.dma_unmap(pci_dev, addr, iova, len);\n+\t}\n+\treturn ret;\n+}\n+\n+static int\n+mlx5_bus_pci_dma_unmap(struct rte_pci_device *pci_dev, void *addr,\n+\t\t       uint64_t iova, size_t len)\n+{\n+\tstruct rte_mlx5_pci_driver *class;\n+\tstruct mlx5_pci_device *dev;\n+\tint local_ret = -EINVAL;\n+\tint ret;\n+\n+\tdev = pci_to_mlx5_device(pci_dev);\n+\tif (!dev)\n+\t\treturn -ENODEV;\n+\tret = 0;\n+\t/* There is no unmap error recovery in current implementation. */\n+\tTAILQ_FOREACH_REVERSE(class, &drv_list, mlx5_pci_bus_drv_head, next) {\n+\t\tif (device_class_enabled(dev, class->dev_class) &&\n+\t\t    class->pci_driver.dma_unmap) {\n+\t\t\tlocal_ret = class->pci_driver.dma_unmap(pci_dev, addr,\n+\t\t\t\t\t\t\t\tiova, len);\n+\t\t\tif (local_ret && (ret == 0))\n+\t\t\t\tret = local_ret;\n+\t\t}\n+\t}\n+\tif (local_ret)\n+\t\tret = local_ret;\n+\treturn ret;\n+}\n+\n+/* PCI ID table is build dynamically based on registered mlx5\n+ * class drivers.\n+ */\n+static struct rte_pci_id *mlx5_bus_pci_id_map;\n+\n+static int\n+pci_id_table_size_get(const struct rte_pci_id *id_table)\n+{\n+\tint table_size = 0;\n+\n+\tfor (; id_table->vendor_id != 0; id_table++)\n+\t\ttable_size++;\n+\treturn table_size;\n+}\n+\n+static bool\n+pci_id_exists(const struct rte_pci_id *id, int next_idx)\n+{\n+\tint current_size = next_idx - 1;\n+\tint i;\n+\n+\tfor (i = 0; i < current_size; i++) {\n+\t\tif (id->device_id == mlx5_bus_pci_id_map[i].device_id &&\n+\t\t    id->vendor_id == mlx5_bus_pci_id_map[i].vendor_id &&\n+\t\t    id->subsystem_vendor_id ==\n+\t\t    mlx5_bus_pci_id_map[i].subsystem_vendor_id &&\n+\t\t    id->subsystem_device_id ==\n+\t\t    mlx5_bus_pci_id_map[i].subsystem_device_id)\n+\t\t\treturn true;\n+\t}\n+\treturn false;\n+}\n+\n+static void\n+pci_id_insert(const struct rte_pci_id *id_table, int *next_idx)\n+{\n+\tfor (; id_table->vendor_id != 0; id_table++) {\n+\t\tif (!pci_id_exists(id_table, *next_idx)) {\n+\t\t\t/* New entry; add to the table. */\n+\t\t\tmlx5_bus_pci_id_map[*next_idx] = *id_table;\n+\t\t\t(*next_idx)++;\n+\t\t}\n+\t}\n+}\n+\n+static int\n+pci_ids_table_build(void)\n+{\n+\tstruct rte_mlx5_pci_driver *first_driver;\n+\tstruct rte_mlx5_pci_driver *driver;\n+\tconst struct rte_pci_id *id_table;\n+\tint num_ids = 0;\n+\tint i = 0;\n+\n+\tTAILQ_FOREACH(driver, &drv_list, next)\n+\t\tnum_ids += pci_id_table_size_get(driver->pci_driver.id_table);\n+\tif (!num_ids)\n+\t\treturn -ENODEV;\n+\t/* Increase size by one for the termination entry of vendor_id = 0. */\n+\tnum_ids += 1;\n+\tmlx5_bus_pci_id_map = calloc(num_ids, sizeof(*mlx5_bus_pci_id_map));\n+\tif (!mlx5_bus_pci_id_map)\n+\t\treturn -ENOMEM;\n+\tfirst_driver = TAILQ_FIRST(&drv_list);\n+\t/* Copy the first class driver's ID table. */\n+\tfor (id_table = first_driver->pci_driver.id_table;\n+\t     id_table->vendor_id != 0; id_table++, i++)\n+\t\tmlx5_bus_pci_id_map[i] = *id_table;\n+\tTAILQ_FOREACH(driver, &drv_list, next) {\n+\t\t/* We already added first driver; skip it. */\n+\t\tif (driver == first_driver)\n+\t\t\tcontinue;\n+\t\tpci_id_insert(driver->pci_driver.id_table, &i);\n+\t}\n+\tmlx5_bus_pci_id_map[i].vendor_id = 0;\n+\treturn 0;\n+}\n+\n+static bool mlx5_bus_registered;\n+static struct rte_pci_driver mlx5_bus_driver = {\n+\t.driver = {\n+\t\t.name = \"mlx5_bus_pci\",\n+\t},\n+\t.probe = mlx5_bus_pci_probe,\n+\t.remove = mlx5_bus_pci_remove,\n+\t.dma_map = mlx5_bus_pci_dma_map,\n+\t.dma_unmap = mlx5_bus_pci_dma_unmap,\n+};\n+\n+RTE_INIT(mlx5_bus_pci)\n+{\n+\tstruct rte_mlx5_pci_driver *class;\n+\tint ret;\n+\n+\tret = pci_ids_table_build();\n+\tif (ret)\n+\t\treturn;\n+\tTAILQ_FOREACH(class, &drv_list, next)\n+\t\tmlx5_bus_driver.drv_flags |= class->pci_driver.drv_flags;\n+\tmlx5_bus_driver.id_table = mlx5_bus_pci_id_map;\n+\trte_pci_register(&mlx5_bus_driver);\n+\tmlx5_bus_registered = true;\n+}\n+\n+RTE_FINI(mlx5_bus_pci_finish)\n+{\n+\tif (mlx5_bus_registered)\n+\t\trte_pci_unregister(&mlx5_bus_driver);\n+\tif (mlx5_bus_pci_id_map)\n+\t\tfree(mlx5_bus_pci_id_map);\n+}\n+RTE_PMD_EXPORT_NAME(mlx5_bus_pci, __COUNTER__);\n+RTE_PMD_REGISTER_PCI_TABLE(mlx5_bus, mlx5_bus_pci_id_map);\n",
    "prefixes": [
        "v6",
        "7/9"
    ]
}