From mboxrd@z Thu Jan 1 00:00:00 1970 Return-Path: Received: from EUR01-HE1-obe.outbound.protection.outlook.com (mail-he1eur01on0067.outbound.protection.outlook.com [104.47.0.67]) by dpdk.org (Postfix) with ESMTP id 9705A1B171 for ; Wed, 9 May 2018 13:09:26 +0200 (CEST) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=Mellanox.com; s=selector1; h=From:Date:Subject:Message-ID:Content-Type:MIME-Version; bh=G3ihPwJ3oQo97cRAsjsJwN57a5Sx9xohsSHQMsQvPME=; b=fp0kWHQNmC+TeyLSjV/zfg2gXjvqc8lPyVTYFDYk+Cm/eivec5rHYPhn90SlsNo9IutTWZ+/jZaHuJ/ydoWt2FT8uxZgKRrYfiawT8a0pl6iW98v0Athilk6fK/r0mx0rlaQ/pifQsJIB0SsOLjtCH4vMmyrHP7+bdjFqmOlUh4= Authentication-Results: spf=none (sender IP is ) smtp.mailfrom=yskoh@mellanox.com; Received: from mellanox.com (209.116.155.178) by AM5PR0501MB2034.eurprd05.prod.outlook.com (2603:10a6:203:1a::20) with Microsoft SMTP Server (version=TLS1_2, cipher=TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384) id 15.20.755.16; Wed, 9 May 2018 11:09:23 +0000 From: Yongseok Koh To: adrien.mazarguil@6wind.com, nelio.laranjeiro@6wind.com Cc: dev@dpdk.org, Yongseok Koh Date: Wed, 9 May 2018 04:09:03 -0700 Message-Id: <20180509110906.19462-2-yskoh@mellanox.com> X-Mailer: git-send-email 2.11.0 In-Reply-To: <20180509110906.19462-1-yskoh@mellanox.com> References: <20180502231654.7596-1-yskoh@mellanox.com> <20180509110906.19462-1-yskoh@mellanox.com> MIME-Version: 1.0 Content-Type: text/plain X-Originating-IP: [209.116.155.178] X-ClientProxiedBy: CO2PR04CA0070.namprd04.prod.outlook.com (2603:10b6:102:1::38) To AM5PR0501MB2034.eurprd05.prod.outlook.com (2603:10a6:203:1a::20) X-MS-PublicTrafficType: Email X-MS-Office365-Filtering-HT: Tenant X-Microsoft-Antispam: UriScan:; BCL:0; PCL:0; RULEID:(7020095)(4652020)(4534165)(4627221)(201703031133081)(201702281549075)(5600026)(48565401081)(2017052603328)(7153060)(7193020); SRVR:AM5PR0501MB2034; X-Microsoft-Exchange-Diagnostics: 1; AM5PR0501MB2034; 3:LZF+LnqrST20dXgYIrDTUIRqoy7gbuJBc7TumAjTZVrcvVzm3mR4XtKbxDTdz0PwwauW5uKpvdRUiDmKfFB74DADJ4i1Lk1I6q2eWqBKA2FhXOLwGQddDM2IqOmhwVo8HIarc1kVmZRm9aSTGeMDdc5ipSDixq3kOAwEHfvdxJztpGz3o7LdZJfV77aPLDl9Q4SzcSNRrec2Ej/qKmJRJ8EqVQrM+nLQ+haYHCMf6iM7L2BMJeRW7HOiAnmPj+EZ; 25:3MFtHzxl9LfpqKKcA6cDHfnshO4Nm6bCEIfTCZXuFHGXUSTATWKQlc0Rh0GVYq/J2gaBbI4HJtGgi8c3aAVh4KHOdG/ZpVocNF0uTC1vqMFWz3MR/9BfAPHRoyJMPcpYsgmaZYH3QrwcDCHY4oHt1vnxUCHTXyrALynTHtQTA/9PJjCaNVCDftqx/U+kJ2Ix+yujH78OAaAq8ONKiHzJFf6t4N3QCr3KCJDillEHgFlJ1jeCda1Rqybs7uIZ/DoDfpGZ7wV2zNqqAFvb8g6IolWiwbGcfM0RIk8zz76jpWKBhe/oPDu/BKdq0dfwO5ZHGi/bJd1mn0kqVlkf4g6mUA==; 31:4KX66D1DLr5y2ho+lvo6MzO0+WtayuQFd0kdVo3hKIwiWHPac3nkULu+d9i2uFmDDhx6X4jZKPCZa+ebXSaXeXa18nc9VutlSEszl630PC5gb0DjtUALvhc1w0vj7RKzN4u9UgaN6wvRdscqsD8pEprWJ7toIdDcu3IoYsSgxEjJwnL/+6Pqtk37ZmEcxjEVk1+XdwRxQvK/2yP+TJHuQ1rWQbcAuRqbIYd/i2RLRUI= X-MS-TrafficTypeDiagnostic: AM5PR0501MB2034: X-LD-Processed: a652971c-7d2e-4d9b-a6a4-d149256f461b,ExtAddr X-Microsoft-Exchange-Diagnostics: 1; AM5PR0501MB2034; 20:JIGZNgqToJIXL3X7pLxm2Uj+txBApzvSJWDUOge8mciAxtmyCQmRVuVhpYHXV8Z087wju4R7AlsCUL7nkyyaxuY1BB4vqe+AMu6xjxcU7/8XaBOX/GDwYTsX/0YUh8jISe/58o6tXDM/Eol+s/BSrxl5SGXCBVQhpWrkci7XmWWpMpW/2RiXzSroOrYyoWP1616lkC/ATbGmkOr/xySE01gzvgZ7jeyXJqWi7dC3HUHvo25E7C96gkxAsSo4obPAp+9JaSfbgrRMkWShh2orgJ+Jz5W4iI0I+wFLPfu1+ddh6a1l+wnXm8JIiLzmj1VfarMjpKBma3NbuaRv8iCtxTvCLUzMwIaOzHLOND2/8HW1Ig4FFxQE1r8xfWtS2ztfdAOqgbn7otddEeznW0IisLUkd5wJfJT9IRJSuMvozEfQzUNvWkChwVWSD33HT3MbkZ+8IVK5xKeZ5wb5K6zaBnisgMJEeEhiYGo0bXcZSZrp1C3OE36hT7F0Zc/b8WeA; 4:Gg3ScW2rdh2Fla1/Cua8QjLecAINNH270Rqgpl2jTvdSLdxi5dS9QNJYQHBU/hGR6uvMvdKhaJo1TEAs0Nf8/l2oVAoJiwNxO89pG5JY6BTvJeAeZhaLiAHYqkhLw0Ay09Jr0Eww5T0l6iyJy8OXPpuV1onLCYgEq6b2qw4zVb77K5nZVo9fW9pyuCRxOPso0ee+DfdYv29VsHymbaxZLIogyrBdYSW93jcVr64RHAbkz0/Dwuesa8gcb55J1LQ9ymiEHE7h+DT4coXDOZyewg== X-Microsoft-Antispam-PRVS: X-Exchange-Antispam-Report-Test: UriScan:; X-MS-Exchange-SenderADCheck: 1 X-Exchange-Antispam-Report-CFA-Test: BCL:0; PCL:0; RULEID:(8211001083)(6040522)(2401047)(8121501046)(5005006)(3231254)(944501410)(52105095)(93006095)(93001095)(10201501046)(3002001)(6055026)(149027)(150027)(6041310)(20161123562045)(20161123558120)(20161123564045)(20161123560045)(201703131423095)(201702281528075)(20161123555045)(201703061421075)(201703061406153)(6072148)(201708071742011); SRVR:AM5PR0501MB2034; BCL:0; PCL:0; RULEID:; SRVR:AM5PR0501MB2034; X-Forefront-PRVS: 0667289FF8 X-Forefront-Antispam-Report: SFV:NSPM; SFS:(10009020)(376002)(346002)(366004)(396003)(39380400002)(39860400002)(199004)(189003)(186003)(97736004)(106356001)(53936002)(305945005)(105586002)(7736002)(55016002)(36756003)(21086003)(48376002)(16586007)(52116002)(25786009)(66066001)(26005)(47776003)(316002)(16526019)(51416003)(4326008)(59450400001)(50466002)(6666003)(3846002)(69596002)(2906002)(386003)(6116002)(76176011)(1076002)(5660300001)(8676002)(68736007)(81166006)(478600001)(81156014)(86362001)(575784001)(7696005)(50226002)(8936002)(956004)(2616005)(486006)(11346002)(107886003)(446003)(476003); DIR:OUT; SFP:1101; SCL:1; SRVR:AM5PR0501MB2034; H:mellanox.com; FPR:; SPF:None; LANG:en; PTR:InfoNoRecords; A:1; MX:1; Received-SPF: None (protection.outlook.com: mellanox.com does not designate permitted sender hosts) X-Microsoft-Exchange-Diagnostics: =?us-ascii?Q?1; AM5PR0501MB2034; 23:E3UTJ6MulgUeZJkCZmoS7d/vs8TRTixdZWTPMep?= =?us-ascii?Q?eL0I8P4bo1u8lRtRrFvtYByvUcqxDtHJofVpFSlm0DW3zdyiIokDLO0TqZzO?= =?us-ascii?Q?GE48bhpH3o3kvkHQ5WYykwlbh6scbD5ztCMNDTvNPKNgESDbBFxMljFJCHV2?= =?us-ascii?Q?A+OWL+muzhivpObVxyibUr//g1lwBIwNA+xB5bI5/SzxngmjvWujUzXiSuaf?= =?us-ascii?Q?ySm6ljQA0XmoNqZTqqNx4GRHfPBZ2u4QNg4f1X3EhKjE5s8tV0CzqIy85hJk?= =?us-ascii?Q?BmZHo6m88Y9qnocgh+NWijzMR7mDcKkLDduBtXZtsfzI7V/gL2VrYpMTrG7A?= =?us-ascii?Q?2gOWp5Vf4uMQhe+LrVETkX3cLeaa9nthFGRv9wYsKmAzGBJdobPPFgUojeoF?= =?us-ascii?Q?I89Zb7VQsor09tPO3IaEFthaIu0uQXlgJ/xJlMq9DJXsS+Qph/TBA84FfatF?= =?us-ascii?Q?cynSaUJI4KbqPpIY1j3NlOchYBZe8lqKVDUfQebKp0arfpg3/JN39xJ/bt9A?= =?us-ascii?Q?V8hGsPX4xEyhBm5IL5eYScT4hUp+RKqufm+g8StTHJc1/pldSndq+QqbvPJC?= =?us-ascii?Q?h+iy7G7Gr3zjsZ4HyQ4SBiVxvKebthsD9zYyXFICAsjpaGykyr7ds+CYak/1?= =?us-ascii?Q?EDMjO8RLynqGyNZ0sYEbSjj/Z7YLh3kkXRcKMkp60TeYnfG7wJ615HtI6Q4c?= =?us-ascii?Q?fH83lW25Fn3P8W55bB1dAmQTJGcUdJpI3HtnnG8tkyv6lgylIz76v5TMk5pu?= =?us-ascii?Q?tT/lirNJQOLIMdRXaioFGj0bc/FH+w72BqKo/q5xX16bN9Ad3w6vul3QND2m?= =?us-ascii?Q?iL3XjbQKkMntEX3EDxZnw1dUHyljrd/udYcc/tqwAFqEUYKA1mkSBnwmMYUq?= =?us-ascii?Q?3oHGyf7N+49PNu4BZb6AJisFRCJBbTYBqQtPp8jGFzc6O/llJ3JubvbZsyFh?= =?us-ascii?Q?uGZvj6Pd6U1TLo0i24xqCPPiDHUKWAFtuAHmWjpegU5HGO4gWNs9IVQNpXV/?= =?us-ascii?Q?SMRjzuWOjk4GXfCoMbOVMFMC4RABTY98dYJQl9jLRoQElc1ydWOOvsETRaSu?= =?us-ascii?Q?nbqL8GG7oRKRVVFLHdmUHc4NrqsB9+1nKzeQOhuthdlS42sPQ4J/LYbYNmG6?= =?us-ascii?Q?ADxiLV3WKypY/OFIc4PmxxdtWStJ3J5uZYNdf/N8lZlrMEPkHHh9LeLcFBxh?= =?us-ascii?Q?tbqi8n4JRuNwvwgvzp94L2VSErYjMPl5S3dtqrjlq6Sv4HawvuFthQiZrtA2?= =?us-ascii?Q?K/dGoWlkTQmTgIUK4YRfKhU8gdRzoGaS4t/caK9YL?= X-Microsoft-Antispam-Message-Info: eVOriyRhyo51MNpTiPvIgMttq0mNVPUV5W6Lx1usvUvJ3MvTXoxIBiqh4YW+i3K/jLPqMm4BZzPMV2Iu554WZMsYSsPihv1Keh5RR+aXns8gGoBpw83kkTJLaH3f5CqBQoMpkg/LWpxKreCtLCHAhJJCmPffSX9ncbqZyRuOZFmsNKC4yUd5CIM3PeRK5irx X-Microsoft-Exchange-Diagnostics: 1; AM5PR0501MB2034; 6:+Quqzb0hMfN/gFII48vcf+5TOWKj0/yBO0ftS6+9m087p6gTKPSKxgfMS7Skvfesw6jZ9bCGDLrMXLxDQU4zwlimgr+aQqr0+WRvoL6UfVa40CG+RQY6WOjYnyQKdCM/v1Eo/C5p7EfNaf2ECGM5gzDpbxpcFJMwlqYAe7lZ6/8BvH2Xf73DnVnlUfdasyJLrqrlcmSSejJRJ6SiCKT54Wfq+0PxU/UzAeVyhslgtDjZ6BTYsrx02oMfZc5VZ6LkCgQknN6SIhrnWYR5xdkX4DkHCG3uKAc3wQmMOiBy06bGw32kCoxedpAfQxWoGnVyxGzxMf08Wm2AZdTkZECDJYBev+3ms20f1AH3kofzcVp8R0kXY22G8lqFYUJ8gswtOhxNxOxKO71QiQCUDFHgiLCLyHXlAaJr3yAfW/p56hB7PS7vsKROr5hFJxdrSaZ0G/+Jwz0lqa249cbKYia7LQ==; 5:I2hznHCX/yi/4WlBAHIBLAdhAxthIAVN1abLC8g1VDmQJ2zCG9q0y/gTba2c5aBXnIedYKOObrJKOCWuAHLAApZ6G1vyUWmnPkQBdjaRdkrxJXoeqjSywpH5x9aom+5nnYJ3Gr2F8Y6/xwdZFqF1jxnMvDen8boKz1Eyo1YeiEY=; 24:zXVCeXnds4v8AUf5/foiWmICJ4LUT8MweqsF0pH82Z2ii7ynJmvCy77xVVDnH2/T9hSXPMzgE83A57Cf13+srEZqpCU0qu7MMli5JrxpOXg= SpamDiagnosticOutput: 1:99 SpamDiagnosticMetadata: NSPM X-Microsoft-Exchange-Diagnostics: 1; AM5PR0501MB2034; 7:WnJkUXjOUMfHgpy33ow18sGiLNq/9KOMm5CfzlaFAHFOsYARMUeJMYlG7+dOoEe3NCEBGUHfFbVszsY0/qU87/wVPrkLXnkJ21wt6hS52gUsRUDdZNwk7vNsFBt1QxjaCft0PCV3EWKGs4fWvt7a2NOKErNR7T1glUDELDFFuFiZe1oUsCwo1AptcXh8oCZXWYE5KFG5uuAGrxZEwMYBQUU87AovWGz/Atj6hWkbE0oHLmjbk1bJzY/Uno3/Y/TF X-MS-Office365-Filtering-Correlation-Id: 40aec285-67d8-4bbc-fcc3-08d5b59d5292 X-OriginatorOrg: Mellanox.com X-MS-Exchange-CrossTenant-OriginalArrivalTime: 09 May 2018 11:09:23.1831 (UTC) X-MS-Exchange-CrossTenant-Network-Message-Id: 40aec285-67d8-4bbc-fcc3-08d5b59d5292 X-MS-Exchange-CrossTenant-FromEntityHeader: Hosted X-MS-Exchange-CrossTenant-Id: a652971c-7d2e-4d9b-a6a4-d149256f461b X-MS-Exchange-Transport-CrossTenantHeadersStamped: AM5PR0501MB2034 Subject: [dpdk-dev] [PATCH v2 1/4] net/mlx5: remove Memory Region support X-BeenThere: dev@dpdk.org X-Mailman-Version: 2.1.15 Precedence: list List-Id: DPDK patches and discussions List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , X-List-Received-Date: Wed, 09 May 2018 11:09:27 -0000 This patch removes current support of Memory Region (MR) in order to accommodate the dynamic memory hotplug patch. This patch can be compiled but traffic can't flow and HW will raise faults. Subsequent patches will add new MR support. Signed-off-by: Yongseok Koh --- config/common_base | 1 - doc/guides/nics/mlx5.rst | 8 - drivers/net/mlx5/Makefile | 4 - drivers/net/mlx5/mlx5.c | 4 - drivers/net/mlx5/mlx5.h | 10 -- drivers/net/mlx5/mlx5_defs.h | 11 -- drivers/net/mlx5/mlx5_mr.c | 346 ---------------------------------------- drivers/net/mlx5/mlx5_rxq.c | 21 +-- drivers/net/mlx5/mlx5_rxtx.h | 90 +---------- drivers/net/mlx5/mlx5_trigger.c | 14 -- drivers/net/mlx5/mlx5_txq.c | 17 -- 11 files changed, 4 insertions(+), 522 deletions(-) diff --git a/config/common_base b/config/common_base index 0d181ace8..d525d9443 100644 --- a/config/common_base +++ b/config/common_base @@ -296,7 +296,6 @@ CONFIG_RTE_LIBRTE_MLX4_TX_MP_CACHE=8 CONFIG_RTE_LIBRTE_MLX5_PMD=n CONFIG_RTE_LIBRTE_MLX5_DEBUG=n CONFIG_RTE_LIBRTE_MLX5_DLOPEN_DEPS=n -CONFIG_RTE_LIBRTE_MLX5_TX_MP_CACHE=8 # # Compile burst-oriented Netronome NFP PMD driver diff --git a/doc/guides/nics/mlx5.rst b/doc/guides/nics/mlx5.rst index bc08515cf..5854106b5 100644 --- a/doc/guides/nics/mlx5.rst +++ b/doc/guides/nics/mlx5.rst @@ -167,14 +167,6 @@ These options can be modified in the ``.config`` file. adds additional run-time checks and debugging messages at the cost of lower performance. -- ``CONFIG_RTE_LIBRTE_MLX5_TX_MP_CACHE`` (default **8**) - - Maximum number of cached memory pools (MPs) per TX queue. Each MP from - which buffers are to be transmitted must be associated to memory regions - (MRs). This is a slow operation that must be cached. - - This value is always 1 for RX queues since they use a single MP. - Environment variables ~~~~~~~~~~~~~~~~~~~~~ diff --git a/drivers/net/mlx5/Makefile b/drivers/net/mlx5/Makefile index 3c5b4943a..13f079334 100644 --- a/drivers/net/mlx5/Makefile +++ b/drivers/net/mlx5/Makefile @@ -82,10 +82,6 @@ else CFLAGS += -DNDEBUG -UPEDANTIC endif -ifdef CONFIG_RTE_LIBRTE_MLX5_TX_MP_CACHE -CFLAGS += -DMLX5_PMD_TX_MP_CACHE=$(CONFIG_RTE_LIBRTE_MLX5_TX_MP_CACHE) -endif - include $(RTE_SDK)/mk/rte.lib.mk # Generate and clean-up mlx5_autoconf.h. diff --git a/drivers/net/mlx5/mlx5.c b/drivers/net/mlx5/mlx5.c index efc6313fe..42b019ba6 100644 --- a/drivers/net/mlx5/mlx5.c +++ b/drivers/net/mlx5/mlx5.c @@ -245,10 +245,6 @@ mlx5_dev_close(struct rte_eth_dev *dev) if (ret) DRV_LOG(WARNING, "port %u some flows still remain", dev->data->port_id); - ret = mlx5_mr_verify(dev); - if (ret) - DRV_LOG(WARNING, "port %u some memory region still remain", - dev->data->port_id); memset(priv, 0, sizeof(*priv)); } diff --git a/drivers/net/mlx5/mlx5.h b/drivers/net/mlx5/mlx5.h index f1294c54b..b34adc1ec 100644 --- a/drivers/net/mlx5/mlx5.h +++ b/drivers/net/mlx5/mlx5.h @@ -26,7 +26,6 @@ #include #include #include -#include #include #include #include @@ -147,7 +146,6 @@ struct priv { struct mlx5_hrxq_drop *flow_drop_queue; /* Flow drop queue. */ struct mlx5_flows flows; /* RTE Flow rules. */ struct mlx5_flows ctrl_flows; /* Control flow rules. */ - LIST_HEAD(mr, mlx5_mr) mr; /* Memory region. */ LIST_HEAD(rxq, mlx5_rxq_ctrl) rxqsctrl; /* DPDK Rx queues. */ LIST_HEAD(rxqibv, mlx5_rxq_ibv) rxqsibv; /* Verbs Rx queues. */ LIST_HEAD(hrxq, mlx5_hrxq) hrxqs; /* Verbs Hash Rx queues. */ @@ -157,7 +155,6 @@ struct priv { LIST_HEAD(ind_tables, mlx5_ind_table_ibv) ind_tbls; uint32_t link_speed_capa; /* Link speed capabilities. */ struct mlx5_xstats_ctrl xstats_ctrl; /* Extended stats control. */ - rte_spinlock_t mr_lock; /* MR Lock. */ int primary_socket; /* Unix socket for primary process. */ void *uar_base; /* Reserved address space for UAR mapping */ struct rte_intr_handle intr_handle_socket; /* Interrupt handler. */ @@ -309,13 +306,6 @@ void mlx5_socket_uninit(struct rte_eth_dev *priv); void mlx5_socket_handle(struct rte_eth_dev *priv); int mlx5_socket_connect(struct rte_eth_dev *priv); -/* mlx5_mr.c */ - -struct mlx5_mr *mlx5_mr_new(struct rte_eth_dev *dev, struct rte_mempool *mp); -struct mlx5_mr *mlx5_mr_get(struct rte_eth_dev *dev, struct rte_mempool *mp); -int mlx5_mr_release(struct mlx5_mr *mr); -int mlx5_mr_verify(struct rte_eth_dev *dev); - /* mlx5_nl.c */ int mlx5_nl_init(uint32_t nlgroups); diff --git a/drivers/net/mlx5/mlx5_defs.h b/drivers/net/mlx5/mlx5_defs.h index 55a86957d..f9093777d 100644 --- a/drivers/net/mlx5/mlx5_defs.h +++ b/drivers/net/mlx5/mlx5_defs.h @@ -38,17 +38,6 @@ #define MLX5_TX_COMP_THRESH_INLINE_DIV (1 << 3) /* - * Maximum number of cached Memory Pools (MPs) per TX queue. Each RTE MP - * from which buffers are to be transmitted will have to be mapped by this - * driver to their own Memory Region (MR). This is a slow operation. - * - * This value is always 1 for RX queues. - */ -#ifndef MLX5_PMD_TX_MP_CACHE -#define MLX5_PMD_TX_MP_CACHE 8 -#endif - -/* * If defined, only use software counters. The PMD will never ask the hardware * for these, and many of them won't be available. */ diff --git a/drivers/net/mlx5/mlx5_mr.c b/drivers/net/mlx5/mlx5_mr.c index 48ac84bc8..736c40ae4 100644 --- a/drivers/net/mlx5/mlx5_mr.c +++ b/drivers/net/mlx5/mlx5_mr.c @@ -18,349 +18,3 @@ #include "mlx5_rxtx.h" #include "mlx5_glue.h" -struct mlx5_check_mempool_data { - int ret; - char *start; - char *end; -}; - -/* Called by mlx5_check_mempool() when iterating the memory chunks. */ -static void -mlx5_check_mempool_cb(struct rte_mempool *mp __rte_unused, - void *opaque, struct rte_mempool_memhdr *memhdr, - unsigned int mem_idx __rte_unused) -{ - struct mlx5_check_mempool_data *data = opaque; - - /* It already failed, skip the next chunks. */ - if (data->ret != 0) - return; - /* It is the first chunk. */ - if (data->start == NULL && data->end == NULL) { - data->start = memhdr->addr; - data->end = data->start + memhdr->len; - return; - } - if (data->end == memhdr->addr) { - data->end += memhdr->len; - return; - } - if (data->start == (char *)memhdr->addr + memhdr->len) { - data->start -= memhdr->len; - return; - } - /* Error, mempool is not virtually contiguous. */ - data->ret = -1; -} - -/** - * Check if a mempool can be used: it must be virtually contiguous. - * - * @param[in] mp - * Pointer to memory pool. - * @param[out] start - * Pointer to the start address of the mempool virtual memory area - * @param[out] end - * Pointer to the end address of the mempool virtual memory area - * - * @return - * 0 on success (mempool is virtually contiguous), -1 on error. - */ -static int -mlx5_check_mempool(struct rte_mempool *mp, uintptr_t *start, - uintptr_t *end) -{ - struct mlx5_check_mempool_data data; - - memset(&data, 0, sizeof(data)); - rte_mempool_mem_iter(mp, mlx5_check_mempool_cb, &data); - *start = (uintptr_t)data.start; - *end = (uintptr_t)data.end; - return data.ret; -} - -/** - * Register a Memory Region (MR) <-> Memory Pool (MP) association in - * txq->mp2mr[]. If mp2mr[] is full, remove an entry first. - * - * @param txq - * Pointer to TX queue structure. - * @param[in] mp - * Memory Pool for which a Memory Region lkey must be returned. - * @param idx - * Index of the next available entry. - * - * @return - * mr on success, NULL on failure and rte_errno is set. - */ -struct mlx5_mr * -mlx5_txq_mp2mr_reg(struct mlx5_txq_data *txq, struct rte_mempool *mp, - unsigned int idx) -{ - struct mlx5_txq_ctrl *txq_ctrl = - container_of(txq, struct mlx5_txq_ctrl, txq); - struct rte_eth_dev *dev; - struct mlx5_mr *mr; - - rte_spinlock_lock(&txq_ctrl->priv->mr_lock); - /* Add a new entry, register MR first. */ - DRV_LOG(DEBUG, "port %u discovered new memory pool \"%s\" (%p)", - PORT_ID(txq_ctrl->priv), mp->name, (void *)mp); - dev = ETH_DEV(txq_ctrl->priv); - mr = mlx5_mr_get(dev, mp); - if (mr == NULL) { - if (rte_eal_process_type() != RTE_PROC_PRIMARY) { - DRV_LOG(DEBUG, - "port %u using unregistered mempool 0x%p(%s)" - " in secondary process, please create mempool" - " before rte_eth_dev_start()", - PORT_ID(txq_ctrl->priv), (void *)mp, mp->name); - rte_spinlock_unlock(&txq_ctrl->priv->mr_lock); - rte_errno = ENOTSUP; - return NULL; - } - mr = mlx5_mr_new(dev, mp); - } - if (unlikely(mr == NULL)) { - DRV_LOG(DEBUG, - "port %u unable to configure memory region," - " ibv_reg_mr() failed.", - PORT_ID(txq_ctrl->priv)); - rte_spinlock_unlock(&txq_ctrl->priv->mr_lock); - return NULL; - } - if (unlikely(idx == RTE_DIM(txq->mp2mr))) { - /* Table is full, remove oldest entry. */ - DRV_LOG(DEBUG, - "port %u memory region <-> memory pool table full, " - " dropping oldest entry", - PORT_ID(txq_ctrl->priv)); - --idx; - mlx5_mr_release(txq->mp2mr[0]); - memmove(&txq->mp2mr[0], &txq->mp2mr[1], - (sizeof(txq->mp2mr) - sizeof(txq->mp2mr[0]))); - } - /* Store the new entry. */ - txq_ctrl->txq.mp2mr[idx] = mr; - DRV_LOG(DEBUG, - "port %u new memory region lkey for MP \"%s\" (%p): 0x%08" - PRIu32, - PORT_ID(txq_ctrl->priv), mp->name, (void *)mp, - txq_ctrl->txq.mp2mr[idx]->lkey); - rte_spinlock_unlock(&txq_ctrl->priv->mr_lock); - return mr; -} - -struct mlx5_mp2mr_mbuf_check_data { - int ret; -}; - -/** - * Callback function for rte_mempool_obj_iter() to check whether a given - * mempool object looks like a mbuf. - * - * @param[in] mp - * The mempool pointer - * @param[in] arg - * Context data (struct txq_mp2mr_mbuf_check_data). Contains the - * return value. - * @param[in] obj - * Object address. - * @param index - * Object index, unused. - */ -static void -txq_mp2mr_mbuf_check(struct rte_mempool *mp, void *arg, void *obj, - uint32_t index __rte_unused) -{ - struct mlx5_mp2mr_mbuf_check_data *data = arg; - struct rte_mbuf *buf = obj; - - /* - * Check whether mbuf structure fits element size and whether mempool - * pointer is valid. - */ - if (sizeof(*buf) > mp->elt_size || buf->pool != mp) - data->ret = -1; -} - -/** - * Iterator function for rte_mempool_walk() to register existing mempools and - * fill the MP to MR cache of a TX queue. - * - * @param[in] mp - * Memory Pool to register. - * @param *arg - * Pointer to TX queue structure. - */ -void -mlx5_mp2mr_iter(struct rte_mempool *mp, void *arg) -{ - struct priv *priv = (struct priv *)arg; - struct mlx5_mp2mr_mbuf_check_data data = { - .ret = 0, - }; - struct mlx5_mr *mr; - - /* Register mempool only if the first element looks like a mbuf. */ - if (rte_mempool_obj_iter(mp, txq_mp2mr_mbuf_check, &data) == 0 || - data.ret == -1) - return; - mr = mlx5_mr_get(ETH_DEV(priv), mp); - if (mr) { - mlx5_mr_release(mr); - return; - } - mr = mlx5_mr_new(ETH_DEV(priv), mp); - if (!mr) - DRV_LOG(ERR, "port %u cannot create memory region: %s", - PORT_ID(priv), strerror(rte_errno)); -} - -/** - * Register a new memory region from the mempool and store it in the memory - * region list. - * - * @param dev - * Pointer to Ethernet device. - * @param mp - * Pointer to the memory pool to register. - * - * @return - * The memory region on success, NULL on failure and rte_errno is set. - */ -struct mlx5_mr * -mlx5_mr_new(struct rte_eth_dev *dev, struct rte_mempool *mp) -{ - struct priv *priv = dev->data->dev_private; - const struct rte_memseg *ms; - uintptr_t start; - uintptr_t end; - struct mlx5_mr *mr; - - mr = rte_zmalloc_socket(__func__, sizeof(*mr), 0, mp->socket_id); - if (!mr) { - DRV_LOG(DEBUG, - "port %u unable to configure memory region," - " ibv_reg_mr() failed.", - dev->data->port_id); - rte_errno = ENOMEM; - return NULL; - } - if (mlx5_check_mempool(mp, &start, &end) != 0) { - DRV_LOG(ERR, "port %u mempool %p: not virtually contiguous", - dev->data->port_id, (void *)mp); - rte_errno = ENOMEM; - return NULL; - } - DRV_LOG(DEBUG, "port %u mempool %p area start=%p end=%p size=%zu", - dev->data->port_id, (void *)mp, (void *)start, (void *)end, - (size_t)(end - start)); - /* Save original addresses for exact MR lookup. */ - mr->start = start; - mr->end = end; - - /* Round start and end to page boundary if found in memory segments. */ - ms = rte_mem_virt2memseg((void *)start, NULL); - if (ms != NULL) - start = RTE_ALIGN_FLOOR(start, ms->hugepage_sz); - end = RTE_ALIGN_CEIL(end, ms->hugepage_sz); - DRV_LOG(DEBUG, - "port %u mempool %p using start=%p end=%p size=%zu for memory" - " region", - dev->data->port_id, (void *)mp, (void *)start, (void *)end, - (size_t)(end - start)); - mr->mr = mlx5_glue->reg_mr(priv->pd, (void *)start, end - start, - IBV_ACCESS_LOCAL_WRITE); - if (!mr->mr) { - rte_errno = ENOMEM; - return NULL; - } - mr->mp = mp; - mr->lkey = rte_cpu_to_be_32(mr->mr->lkey); - rte_atomic32_inc(&mr->refcnt); - DRV_LOG(DEBUG, "port %u new memory Region %p refcnt: %d", - dev->data->port_id, (void *)mr, rte_atomic32_read(&mr->refcnt)); - LIST_INSERT_HEAD(&priv->mr, mr, next); - return mr; -} - -/** - * Search the memory region object in the memory region list. - * - * @param dev - * Pointer to Ethernet device. - * @param mp - * Pointer to the memory pool to register. - * - * @return - * The memory region on success. - */ -struct mlx5_mr * -mlx5_mr_get(struct rte_eth_dev *dev, struct rte_mempool *mp) -{ - struct priv *priv = dev->data->dev_private; - struct mlx5_mr *mr; - - assert(mp); - if (LIST_EMPTY(&priv->mr)) - return NULL; - LIST_FOREACH(mr, &priv->mr, next) { - if (mr->mp == mp) { - rte_atomic32_inc(&mr->refcnt); - DRV_LOG(DEBUG, "port %u memory region %p refcnt: %d", - dev->data->port_id, (void *)mr, - rte_atomic32_read(&mr->refcnt)); - return mr; - } - } - return NULL; -} - -/** - * Release the memory region object. - * - * @param mr - * Pointer to memory region to release. - * - * @return - * 1 while a reference on it exists, 0 when freed. - */ -int -mlx5_mr_release(struct mlx5_mr *mr) -{ - assert(mr); - DRV_LOG(DEBUG, "memory region %p refcnt: %d", (void *)mr, - rte_atomic32_read(&mr->refcnt)); - if (rte_atomic32_dec_and_test(&mr->refcnt)) { - claim_zero(mlx5_glue->dereg_mr(mr->mr)); - LIST_REMOVE(mr, next); - rte_free(mr); - return 0; - } - return 1; -} - -/** - * Verify the flow list is empty - * - * @param dev - * Pointer to Ethernet device. - * - * @return - * The number of object not released. - */ -int -mlx5_mr_verify(struct rte_eth_dev *dev) -{ - struct priv *priv = dev->data->dev_private; - int ret = 0; - struct mlx5_mr *mr; - - LIST_FOREACH(mr, &priv->mr, next) { - DRV_LOG(DEBUG, "port %u memory region %p still referenced", - dev->data->port_id, (void *)mr); - ++ret; - } - return ret; -} diff --git a/drivers/net/mlx5/mlx5_rxq.c b/drivers/net/mlx5/mlx5_rxq.c index aa1ddd0b6..23f909635 100644 --- a/drivers/net/mlx5/mlx5_rxq.c +++ b/drivers/net/mlx5/mlx5_rxq.c @@ -649,16 +649,6 @@ mlx5_rxq_ibv_new(struct rte_eth_dev *dev, uint16_t idx) goto error; } tmpl->rxq_ctrl = rxq_ctrl; - /* Use the entire RX mempool as the memory region. */ - tmpl->mr = mlx5_mr_get(dev, rxq_data->mp); - if (!tmpl->mr) { - tmpl->mr = mlx5_mr_new(dev, rxq_data->mp); - if (!tmpl->mr) { - DRV_LOG(ERR, "port %u: memeroy region creation failure", - dev->data->port_id); - goto error; - } - } if (rxq_ctrl->irq) { tmpl->channel = mlx5_glue->create_comp_channel(priv->ctx); if (!tmpl->channel) { @@ -799,7 +789,7 @@ mlx5_rxq_ibv_new(struct rte_eth_dev *dev, uint16_t idx) .addr = rte_cpu_to_be_64(rte_pktmbuf_mtod(buf, uintptr_t)), .byte_count = rte_cpu_to_be_32(DATA_LEN(buf)), - .lkey = tmpl->mr->lkey, + .lkey = UINT32_MAX, }; } rxq_data->rq_db = rwq.dbrec; @@ -835,8 +825,6 @@ mlx5_rxq_ibv_new(struct rte_eth_dev *dev, uint16_t idx) claim_zero(mlx5_glue->destroy_cq(tmpl->cq)); if (tmpl->channel) claim_zero(mlx5_glue->destroy_comp_channel(tmpl->channel)); - if (tmpl->mr) - mlx5_mr_release(tmpl->mr); priv->verbs_alloc_ctx.type = MLX5_VERBS_ALLOC_TYPE_NONE; rte_errno = ret; /* Restore rte_errno. */ return NULL; @@ -866,7 +854,6 @@ mlx5_rxq_ibv_get(struct rte_eth_dev *dev, uint16_t idx) return NULL; rxq_ctrl = container_of(rxq_data, struct mlx5_rxq_ctrl, rxq); if (rxq_ctrl->ibv) { - mlx5_mr_get(dev, rxq_data->mp); rte_atomic32_inc(&rxq_ctrl->ibv->refcnt); DRV_LOG(DEBUG, "port %u Verbs Rx queue %u: refcnt %d", dev->data->port_id, rxq_ctrl->idx, @@ -887,15 +874,9 @@ mlx5_rxq_ibv_get(struct rte_eth_dev *dev, uint16_t idx) int mlx5_rxq_ibv_release(struct mlx5_rxq_ibv *rxq_ibv) { - int ret; - assert(rxq_ibv); assert(rxq_ibv->wq); assert(rxq_ibv->cq); - assert(rxq_ibv->mr); - ret = mlx5_mr_release(rxq_ibv->mr); - if (!ret) - rxq_ibv->mr = NULL; DRV_LOG(DEBUG, "port %u Verbs Rx queue %u: refcnt %d", PORT_ID(rxq_ibv->rxq_ctrl->priv), rxq_ibv->rxq_ctrl->idx, rte_atomic32_read(&rxq_ibv->refcnt)); diff --git a/drivers/net/mlx5/mlx5_rxtx.h b/drivers/net/mlx5/mlx5_rxtx.h index 2fc12a186..e8cad51aa 100644 --- a/drivers/net/mlx5/mlx5_rxtx.h +++ b/drivers/net/mlx5/mlx5_rxtx.h @@ -54,17 +54,6 @@ struct mlx5_txq_stats { struct priv; -/* Memory region queue object. */ -struct mlx5_mr { - LIST_ENTRY(mlx5_mr) next; /**< Pointer to the next element. */ - rte_atomic32_t refcnt; /*<< Reference counter. */ - uint32_t lkey; /*<< rte_cpu_to_be_32(mr->lkey) */ - uintptr_t start; /* Start address of MR */ - uintptr_t end; /* End address of MR */ - struct ibv_mr *mr; /*<< Memory Region. */ - struct rte_mempool *mp; /*<< Memory Pool. */ -}; - /* Compressed CQE context. */ struct rxq_zip { uint16_t ai; /* Array index. */ @@ -114,7 +103,6 @@ struct mlx5_rxq_ibv { struct ibv_cq *cq; /* Completion Queue. */ struct ibv_wq *wq; /* Work Queue. */ struct ibv_comp_channel *channel; - struct mlx5_mr *mr; /* Memory Region (for mp). */ }; /* RX queue control descriptor. */ @@ -175,7 +163,6 @@ struct mlx5_txq_data { uint16_t mpw_hdr_dseg:1; /* Enable DSEGs in the title WQEBB. */ uint16_t max_inline; /* Multiple of RTE_CACHE_LINE_SIZE to inline. */ uint16_t inline_max_packet_sz; /* Max packet size for inlining. */ - uint16_t mr_cache_idx; /* Index of last hit entry. */ uint32_t qp_num_8s; /* QP number shifted by 8. */ uint64_t offloads; /* Offloads for Tx Queue. */ volatile struct mlx5_cqe (*cqes)[]; /* Completion queue. */ @@ -183,7 +170,6 @@ struct mlx5_txq_data { volatile uint32_t *qp_db; /* Work queue doorbell. */ volatile uint32_t *cq_db; /* Completion queue doorbell. */ volatile void *bf_reg; /* Blueflame register remapped. */ - struct mlx5_mr *mp2mr[MLX5_PMD_TX_MP_CACHE]; /* MR translation table. */ struct rte_mbuf *(*elts)[]; /* TX elements. */ struct mlx5_txq_stats stats; /* TX queue counters. */ } __rte_cache_aligned; @@ -322,12 +308,6 @@ uint16_t mlx5_tx_burst_vec(void *dpdk_txq, struct rte_mbuf **pkts, uint16_t mlx5_rx_burst_vec(void *dpdk_txq, struct rte_mbuf **pkts, uint16_t pkts_n); -/* mlx5_mr.c */ - -void mlx5_mp2mr_iter(struct rte_mempool *mp, void *arg); -struct mlx5_mr *mlx5_txq_mp2mr_reg(struct mlx5_txq_data *txq, - struct rte_mempool *mp, unsigned int idx); - #ifndef NDEBUG /** * Verify or set magic value in CQE. @@ -513,76 +493,12 @@ mlx5_tx_complete(struct mlx5_txq_data *txq) *txq->cq_db = rte_cpu_to_be_32(cq_ci); } -/** - * Get Memory Pool (MP) from mbuf. If mbuf is indirect, the pool from which - * the cloned mbuf is allocated is returned instead. - * - * @param buf - * Pointer to mbuf. - * - * @return - * Memory pool where data is located for given mbuf. - */ -static struct rte_mempool * -mlx5_tx_mb2mp(struct rte_mbuf *buf) -{ - if (unlikely(RTE_MBUF_INDIRECT(buf))) - return rte_mbuf_from_indirect(buf)->pool; - return buf->pool; -} - -/** - * Get Memory Region (MR) <-> rte_mbuf association from txq->mp2mr[]. - * Add MP to txq->mp2mr[] if it's not registered yet. If mp2mr[] is full, - * remove an entry first. - * - * @param txq - * Pointer to TX queue structure. - * @param[in] mp - * Memory Pool for which a Memory Region lkey must be returned. - * - * @return - * mr->lkey on success, (uint32_t)-1 on failure. - */ static __rte_always_inline uint32_t mlx5_tx_mb2mr(struct mlx5_txq_data *txq, struct rte_mbuf *mb) { - uint16_t i = txq->mr_cache_idx; - uintptr_t addr = rte_pktmbuf_mtod(mb, uintptr_t); - struct mlx5_mr *mr; - - assert(i < RTE_DIM(txq->mp2mr)); - if (likely(txq->mp2mr[i]->start <= addr && txq->mp2mr[i]->end > addr)) - return txq->mp2mr[i]->lkey; - for (i = 0; (i != RTE_DIM(txq->mp2mr)); ++i) { - if (unlikely(txq->mp2mr[i] == NULL || - txq->mp2mr[i]->mr == NULL)) { - /* Unknown MP, add a new MR for it. */ - break; - } - if (txq->mp2mr[i]->start <= addr && - txq->mp2mr[i]->end > addr) { - assert(txq->mp2mr[i]->lkey != (uint32_t)-1); - txq->mr_cache_idx = i; - return txq->mp2mr[i]->lkey; - } - } - mr = mlx5_txq_mp2mr_reg(txq, mlx5_tx_mb2mp(mb), i); - /* - * Request the reference to use in this queue, the original one is - * kept by the control plane. - */ - if (mr) { - rte_atomic32_inc(&mr->refcnt); - txq->mr_cache_idx = i >= RTE_DIM(txq->mp2mr) ? i - 1 : i; - return mr->lkey; - } else { - struct rte_mempool *mp = mlx5_tx_mb2mp(mb); - - DRV_LOG(WARNING, "failed to register mempool 0x%p(%s)", - (void *)mp, mp->name); - } - return (uint32_t)-1; + (void)txq; + (void)mb; + return UINT32_MAX; } /** diff --git a/drivers/net/mlx5/mlx5_trigger.c b/drivers/net/mlx5/mlx5_trigger.c index fc56d1ee8..3db6c3f35 100644 --- a/drivers/net/mlx5/mlx5_trigger.c +++ b/drivers/net/mlx5/mlx5_trigger.c @@ -48,17 +48,10 @@ mlx5_txq_start(struct rte_eth_dev *dev) /* Add memory regions to Tx queues. */ for (i = 0; i != priv->txqs_n; ++i) { - unsigned int idx = 0; - struct mlx5_mr *mr; struct mlx5_txq_ctrl *txq_ctrl = mlx5_txq_get(dev, i); if (!txq_ctrl) continue; - LIST_FOREACH(mr, &priv->mr, next) { - mlx5_txq_mp2mr_reg(&txq_ctrl->txq, mr->mp, idx++); - if (idx == MLX5_PMD_TX_MP_CACHE) - break; - } txq_alloc_elts(txq_ctrl); txq_ctrl->ibv = mlx5_txq_ibv_new(dev, i); if (!txq_ctrl->ibv) { @@ -144,13 +137,11 @@ int mlx5_dev_start(struct rte_eth_dev *dev) { struct priv *priv = dev->data->dev_private; - struct mlx5_mr *mr = NULL; int ret; dev->data->dev_started = 1; DRV_LOG(DEBUG, "port %u allocating and configuring hash Rx queues", dev->data->port_id); - rte_mempool_walk(mlx5_mp2mr_iter, priv); ret = mlx5_txq_start(dev); if (ret) { DRV_LOG(ERR, "port %u Tx queue allocation failed: %s", @@ -190,8 +181,6 @@ mlx5_dev_start(struct rte_eth_dev *dev) ret = rte_errno; /* Save rte_errno before cleanup. */ /* Rollback. */ dev->data->dev_started = 0; - for (mr = LIST_FIRST(&priv->mr); mr; mr = LIST_FIRST(&priv->mr)) - mlx5_mr_release(mr); mlx5_flow_stop(dev, &priv->flows); mlx5_traffic_disable(dev); mlx5_txq_stop(dev); @@ -212,7 +201,6 @@ void mlx5_dev_stop(struct rte_eth_dev *dev) { struct priv *priv = dev->data->dev_private; - struct mlx5_mr *mr; dev->data->dev_started = 0; /* Prevent crashes when queues are still in use. */ @@ -228,8 +216,6 @@ mlx5_dev_stop(struct rte_eth_dev *dev) mlx5_dev_interrupt_handler_uninstall(dev); mlx5_txq_stop(dev); mlx5_rxq_stop(dev); - for (mr = LIST_FIRST(&priv->mr); mr; mr = LIST_FIRST(&priv->mr)) - mlx5_mr_release(mr); } /** diff --git a/drivers/net/mlx5/mlx5_txq.c b/drivers/net/mlx5/mlx5_txq.c index af2537379..92b3ad53c 100644 --- a/drivers/net/mlx5/mlx5_txq.c +++ b/drivers/net/mlx5/mlx5_txq.c @@ -409,7 +409,6 @@ mlx5_txq_ibv_new(struct rte_eth_dev *dev, uint16_t idx) return NULL; } memset(&tmpl, 0, sizeof(struct mlx5_txq_ibv)); - /* MRs will be registered in mp2mr[] later. */ attr.cq = (struct ibv_cq_init_attr_ex){ .comp_mask = 0, }; @@ -804,7 +803,6 @@ mlx5_txq_new(struct rte_eth_dev *dev, uint16_t idx, uint16_t desc, tmpl->txq.elts_n = log2above(desc); tmpl->idx = idx; txq_set_params(tmpl); - /* MRs will be registered in mp2mr[] later. */ DRV_LOG(DEBUG, "port %u priv->device_attr.max_qp_wr is %d", dev->data->port_id, priv->device_attr.orig_attr.max_qp_wr); DRV_LOG(DEBUG, "port %u priv->device_attr.max_sge is %d", @@ -839,15 +837,7 @@ mlx5_txq_get(struct rte_eth_dev *dev, uint16_t idx) if ((*priv->txqs)[idx]) { ctrl = container_of((*priv->txqs)[idx], struct mlx5_txq_ctrl, txq); - unsigned int i; - mlx5_txq_ibv_get(dev, idx); - for (i = 0; i != MLX5_PMD_TX_MP_CACHE; ++i) { - if (ctrl->txq.mp2mr[i]) - claim_nonzero - (mlx5_mr_get(dev, - ctrl->txq.mp2mr[i]->mp)); - } rte_atomic32_inc(&ctrl->refcnt); DRV_LOG(DEBUG, "port %u Tx queue %u refcnt %d", dev->data->port_id, @@ -871,7 +861,6 @@ int mlx5_txq_release(struct rte_eth_dev *dev, uint16_t idx) { struct priv *priv = dev->data->dev_private; - unsigned int i; struct mlx5_txq_ctrl *txq; size_t page_size = sysconf(_SC_PAGESIZE); @@ -882,12 +871,6 @@ mlx5_txq_release(struct rte_eth_dev *dev, uint16_t idx) txq->idx, rte_atomic32_read(&txq->refcnt)); if (txq->ibv && !mlx5_txq_ibv_release(txq->ibv)) txq->ibv = NULL; - for (i = 0; i != MLX5_PMD_TX_MP_CACHE; ++i) { - if (txq->txq.mp2mr[i]) { - mlx5_mr_release(txq->txq.mp2mr[i]); - txq->txq.mp2mr[i] = NULL; - } - } if (priv->uar_base) munmap((void *)RTE_ALIGN_FLOOR((uintptr_t)txq->txq.bf_reg, page_size), page_size); -- 2.11.0