Show a patch.

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

{
    "id": 73589,
    "url": "https://patches.dpdk.org/api/patches/73589/",
    "web_url": "https://patches.dpdk.org/patch/73589/",
    "project": {
        "id": 1,
        "url": "https://patches.dpdk.org/api/projects/1/",
        "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"
    },
    "msgid": "<20200709073452.948894-8-parav@mellanox.com>",
    "date": "2020-07-09T07:34:50",
    "name": "[v5,7/9] bus/mlx5_pci: register a PCI driver",
    "commit_ref": null,
    "pull_url": null,
    "state": "superseded",
    "archived": true,
    "hash": "a339ea265e020e121e15faaf647fd5753e46f0ab",
    "submitter": {
        "id": 1780,
        "url": "https://patches.dpdk.org/api/people/1780/",
        "name": "Parav Pandit",
        "email": "parav@mellanox.com"
    },
    "delegate": {
        "id": 3268,
        "url": "https://patches.dpdk.org/api/users/3268/",
        "username": "rasland",
        "first_name": "Raslan",
        "last_name": "Darawsheh",
        "email": "rasland@mellanox.com"
    },
    "mbox": "https://patches.dpdk.org/patch/73589/mbox/",
    "series": [
        {
            "id": 10912,
            "url": "https://patches.dpdk.org/api/series/10912/",
            "web_url": "https://patches.dpdk.org/project/dpdk/list/?series=10912",
            "date": "2020-07-09T07:34:43",
            "name": "Improve mlx5 PMD driver framework for multiple classes",
            "version": 5,
            "mbox": "https://patches.dpdk.org/series/10912/mbox/"
        }
    ],
    "comments": "https://patches.dpdk.org/api/patches/73589/comments/",
    "check": "success",
    "checks": "https://patches.dpdk.org/api/patches/73589/checks/",
    "tags": {},
    "headers": {
        "X-MS-Exchange-CrossTenant-MailboxType": "HOSTED",
        "Return-Path": "<dev-bounces@dpdk.org>",
        "X-BeenThere": "dev@dpdk.org",
        "ARC-Seal": "i=1; a=rsa-sha256; s=arcselector9901; d=microsoft.com; cv=none;\n b=Xhku5USmDC7YUq4BOsE6exV2VzkvMpnljpBFl53pkpWCyF/9KG2BtL0ewabTDIq5ShwL8jwSvJCbBFMCjmt0rilvOSRpi3HOH64/Sc9EqAPcEtnLmJzzs3ST2cZaKQLSMK1icEHb+4oHBqvfzOWaj6FnNP8lRcCVS5HvIKdf/ey8/RFWjHMOhD35ZjchO1GUWlApBplEk/ZV4LlplLRkGxy1NTbT42EmsUOk6CWOpUbZ0ceRuUNTusu6378AxSFDxY+nC5n1YSyyH1Dve8S2xxFTe1xX2+ewi9SnCTAM8iEY6GCgaiKuv154rW80J0Dd4kzrbdUHrBbcIQJUDm462g==",
        "X-Mailer": [
            "git-send-email 2.26.2",
            "git-send-email 2.26.2"
        ],
        "X-MS-Exchange-CrossTenant-UserPrincipalName": "\n o9VtN5gFmkMXDV5NROVgyUmqoH55gkAN+MdRQe/c8abW3w16NTicI1lGmlf02n9ADWa1qmpyLjHm3FSmvYEKIQ==",
        "X-MS-Exchange-Transport-CrossTenantHeadersStamped": "DB7PR05MB5084",
        "List-Unsubscribe": "<https://mails.dpdk.org/options/dev>,\n <mailto:dev-request@dpdk.org?subject=unsubscribe>",
        "Received": [
            "from dpdk.org (dpdk.org [92.243.14.124])\n\tby inbox.dpdk.org (Postfix) with ESMTP id B3791A0526;\n\tThu,  9 Jul 2020 09:36:39 +0200 (CEST)",
            "from [92.243.14.124] (localhost [127.0.0.1])\n\tby dpdk.org (Postfix) with ESMTP id 2D04E1DCBB;\n\tThu,  9 Jul 2020 09:36:05 +0200 (CEST)",
            "from EUR03-DB5-obe.outbound.protection.outlook.com\n (mail-eopbgr40050.outbound.protection.outlook.com [40.107.4.50])\n by dpdk.org (Postfix) with ESMTP id 835341DCAD\n for <dev@dpdk.org>; Thu,  9 Jul 2020 09:36:03 +0200 (CEST)",
            "from DB7PR05MB4876.eurprd05.prod.outlook.com (2603:10a6:10:1d::32)\n by DB7PR05MB5084.eurprd05.prod.outlook.com (2603:10a6:10:15::15) with\n Microsoft SMTP Server (version=TLS1_2,\n cipher=TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384) id 15.20.3153.28; Thu, 9 Jul\n 2020 07:36:02 +0000",
            "from DB7PR05MB4876.eurprd05.prod.outlook.com\n ([fe80::8cb3:93cb:c3ef:4293]) by DB7PR05MB4876.eurprd05.prod.outlook.com\n ([fe80::8cb3:93cb:c3ef:4293%5]) with mapi id 15.20.3174.022; Thu, 9 Jul 2020\n 07:36:02 +0000",
            "from sw-mtx-036.mtx.labs.mlnx (208.176.44.194) by\n SN4PR0501CA0104.namprd05.prod.outlook.com (2603:10b6:803:42::21) with\n Microsoft SMTP Server (version=TLS1_2,\n cipher=TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384) id 15.20.3195.9 via Frontend\n Transport; Thu, 9 Jul 2020 07:36:00 +0000"
        ],
        "Authentication-Results": "dpdk.org; dkim=none (message not signed)\n header.d=none;dpdk.org; dmarc=none action=none header.from=mellanox.com;",
        "X-MS-Exchange-CrossTenant-AuthAs": "Internal",
        "X-MS-Exchange-SenderADCheck": "1",
        "List-Id": "DPDK patches and discussions <dev.dpdk.org>",
        "X-MS-PublicTrafficType": "Email",
        "X-MS-Exchange-Transport-Forked": "True",
        "X-MS-Exchange-AntiSpam-MessageData": "\n ofpkgo1C5Nt7t2gvzWRD1phdcUU6dfbl+Ep4104cv2tLKIpWbSyRTVG3K8drEj9Xh7+NZ7gC+CG3INT2ENDEd1sPMmJxuLksaWkxJpNFLRdGhIt4th3fj583SM5Tbnz6PWx+PriO4ZWGNOj7986I9a7JXHeLU5d6yUhsk29nrGU3mz7Vap/pUjFVUEq8tTFtnJsiKSB4jQAc3j1CZTZRJfUE6wMXvZpy/levlv5/AEUQHkU7PgYJuCMQBfLJGW93RGEENx6YnxKoeUgXaI09l650PtkPX2dnZnrySHPwNk4PwYrqnI90awVdYazDgo/09s1JELNhaMaQ1zrRpNuUYCrdsarzjIjIGhz+fGmkjs+aTDW7frZbFfzeOxgSAtTnTRuXB8f/Dvp4DEHzpxFOQ9xty+3ZkEx/P3w2lPCZMD9ZXw0MOgVH/048umQDCFz45sJNBnrPsgi/+3Dnx/K7XWrEwZB+UFAkdlNTfNLF4qTGheQeuZig8gc966XfiZxa",
        "In-Reply-To": "<20200709073452.948894-1-parav@mellanox.com>",
        "X-MS-Exchange-MessageSentRepresentingType": "1",
        "MIME-Version": "1.0",
        "X-MS-TrafficTypeDiagnostic": "DB7PR05MB5084:",
        "X-Microsoft-Antispam-PRVS": "\n <DB7PR05MB50847426F82564E73C4CEC13D1640@DB7PR05MB5084.eurprd05.prod.outlook.com>",
        "References": "<20200610171728.89-2-parav@mellanox.com>\n <20200709073452.948894-1-parav@mellanox.com>",
        "X-MS-Exchange-CrossTenant-AuthSource": "DB7PR05MB4876.eurprd05.prod.outlook.com",
        "Content-Type": "text/plain",
        "X-MS-Exchange-CrossTenant-Network-Message-Id": "\n e33cdf2a-815e-441b-9043-08d823dabab8",
        "X-MS-Exchange-CrossTenant-OriginalArrivalTime": "09 Jul 2020 07:36:02.3500 (UTC)",
        "X-ClientProxiedBy": "SN4PR0501CA0104.namprd05.prod.outlook.com\n (2603:10b6:803:42::21) To DB7PR05MB4876.eurprd05.prod.outlook.com\n (2603:10a6:10:1d::32)",
        "X-MS-Office365-Filtering-Correlation-Id": "e33cdf2a-815e-441b-9043-08d823dabab8",
        "List-Help": "<mailto:dev-request@dpdk.org?subject=help>",
        "List-Archive": "<http://mails.dpdk.org/archives/dev/>",
        "Message-Id": "<20200709073452.948894-8-parav@mellanox.com>",
        "To": "dev@dpdk.org, grive@u256.net, ferruh.yigit@intel.com, thomas@monjalon.net",
        "X-LD-Processed": "a652971c-7d2e-4d9b-a6a4-d149256f461b,ExtFwd,ExtAddr",
        "X-Forefront-PRVS": "04599F3534",
        "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=QN0igVnVafoDaPftPOhn5VlY5ixvZHGaTntCV0XTqK8=;\n b=Ifs8xvh+cDo9PXQLVpU5BlrCmTXwnu43SdZ13Y0KGQv0e5QBW/N5N8A6YIlW4UMUzlZ2bAkUwokpozd7FNAbkLrs0bri0jFc6ctLcNTFG9kIbvv4Dtw8OU3YmvTwLx8LwaAt6kH3jNWmuaBFez4aDVeH3v7Ba4fJicaVI97M76I=",
        "List-Post": "<mailto:dev@dpdk.org>",
        "X-Mailman-Version": "2.1.15",
        "X-Microsoft-Antispam-Message-Info": "\n 5023ieTun668RsOet+Gwi3TMoOpxryZ5Gr8dJxLlspZ+jq64hcag4jGjiZaQZmQZmnbQ5YRXP4IjL5QjOOwFfwumc/HI263D9Y0EJ4/B0ofVRKxJMyemDOmElgzBZcpFRwkPpc4mrCYkZmnyr7GaDCRh+e+laUleTQcBJ2R0JYDw9DkHh/lPx8RyUXB0bg6M249lRWlbrFmUjruqCaMfKubguJhHKbrV8mdT0N+LA+WEnZDgIzurzea/ydxKtgcQSzCozhrzLTX5qbQz5wrfzMMlfvmqwCoIMQj+P09IWqJPsLjD+t3WCCwA3ME+faUwG9AIjAtECQvFEE7ps5qzGQ==",
        "Subject": "[dpdk-dev] [PATCH v5 7/9] bus/mlx5_pci: register a PCI driver",
        "X-MS-Oob-TLC-OOBClassifiers": "OLM:619;",
        "X-OriginatorOrg": "Mellanox.com",
        "X-Microsoft-Antispam": "BCL:0;",
        "Cc": "rasland@mellanox.com, orika@mellanox.com, matan@mellanox.com,\n joyce.kong@arm.com, Parav Pandit <parav@mellanox.com>",
        "Precedence": "list",
        "From": "Parav Pandit <parav@mellanox.com>",
        "Content-Transfer-Encoding": "8bit",
        "X-Forefront-Antispam-Report": "CIP:255.255.255.255; CTRY:; LANG:en; SCL:1; SRV:;\n IPV:NLI; SFV:NSPM; H:DB7PR05MB4876.eurprd05.prod.outlook.com; PTR:; CAT:NONE;\n SFTY:;\n SFS:(4636009)(396003)(366004)(136003)(39860400002)(346002)(376002)(2906002)(16526019)(186003)(26005)(6506007)(6512007)(52116002)(107886003)(5660300002)(1076003)(6666004)(4326008)(316002)(83380400001)(36756003)(478600001)(86362001)(6486002)(30864003)(66556008)(66476007)(956004)(2616005)(8936002)(8676002)(66946007);\n DIR:OUT; SFP:1101;",
        "X-MS-Exchange-CrossTenant-FromEntityHeader": "Hosted",
        "X-MS-Exchange-CrossTenant-Id": "a652971c-7d2e-4d9b-a6a4-d149256f461b",
        "X-Original-To": "patchwork@inbox.dpdk.org",
        "Sender": "\"dev\" <dev-bounces@dpdk.org>",
        "Errors-To": "dev-bounces@dpdk.org",
        "X-MS-Office365-Filtering-HT": "Tenant",
        "Delivered-To": "patchwork@inbox.dpdk.org",
        "Date": "Thu,  9 Jul 2020 10:34:50 +0300",
        "X-Originating-IP": "[208.176.44.194]",
        "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",
        "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=QN0igVnVafoDaPftPOhn5VlY5ixvZHGaTntCV0XTqK8=;\n b=UUgKJdYT4O0gq26C5YlKLEuq2467ra3SMBDNNCmF/k7QjPQl/HT6NqWh6NS1ZikHqJ5wI3K+HJ18yp+ZNhg7bcJ+pRIx1kCLbwHbrhDqEaa1lEMspAOXaz36AH1WENiBhoLz7XkHnYFm/bTg6N5NcZH2Fr8WK6OreK60bNA9LtzgCGUP3kEC9Y2UKlv5nmHgspyZ6lH1PnM0ptjlkv7z7m7IO/YpQ3vo/Iip4YUDIfljzyGz8uv376+NmPK9q7SAQQVLMCQJ7MKsmkRhBIR/O1mx9Z8P5Lj0R7GrD7RKb+6aZ0fYUFMiv43+IMJrekNTZiQoxtdnVBQ6YJWiIqqGLw==",
        "List-Subscribe": "<https://mails.dpdk.org/listinfo/dev>,\n <mailto:dev-request@dpdk.org?subject=subscribe>"
    },
    "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 de4ccd83f..1a005ee32 100644\n--- a/drivers/bus/mlx5_pci/Makefile\n+++ b/drivers/bus/mlx5_pci/Makefile\n@@ -15,7 +15,9 @@ CFLAGS += -I$(RTE_SDK)/drivers/common/mlx5\n CFLAGS += -I$(BUILDDIR)/drivers/common/mlx5\n CFLAGS += -I$(RTE_SDK)/drivers/common/mlx5/linux\n CFLAGS += -I$(RTE_SDK)/drivers/bus/pci\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": [
        "v5",
        "7/9"
    ]
}