From mboxrd@z Thu Jan 1 00:00:00 1970 Return-Path: Received: from NAM01-BY2-obe.outbound.protection.outlook.com (mail-by2nam01on0074.outbound.protection.outlook.com [104.47.34.74]) by dpdk.org (Postfix) with ESMTP id 82EA7FA34 for ; Wed, 18 Jan 2017 11:35:36 +0100 (CET) Received: from BN6PR03CA0032.namprd03.prod.outlook.com (10.175.124.18) by BY2PR0301MB0743.namprd03.prod.outlook.com (10.160.63.21) with Microsoft SMTP Server (version=TLS1_2, cipher=TLS_ECDHE_RSA_WITH_AES_256_CBC_SHA384_P384) id 15.1.845.12; Wed, 18 Jan 2017 10:35:34 +0000 Received: from BY2FFO11FD025.protection.gbl (2a01:111:f400:7c0c::123) by BN6PR03CA0032.outlook.office365.com (2603:10b6:404:10c::18) with Microsoft SMTP Server (version=TLS1_2, cipher=TLS_ECDHE_RSA_WITH_AES_256_CBC_SHA384_P384) id 15.1.860.13 via Frontend Transport; Wed, 18 Jan 2017 10:35:34 +0000 Authentication-Results: spf=fail (sender IP is 192.88.168.50) smtp.mailfrom=nxp.com; nxp.com; dkim=none (message not signed) header.d=none;nxp.com; dmarc=fail action=none header.from=nxp.com;nxp.com; dkim=none (message not signed) header.d=none; Received-SPF: Fail (protection.outlook.com: domain of nxp.com does not designate 192.88.168.50 as permitted sender) receiver=protection.outlook.com; client-ip=192.88.168.50; helo=tx30smr01.am.freescale.net; Received: from tx30smr01.am.freescale.net (192.88.168.50) by BY2FFO11FD025.mail.protection.outlook.com (10.1.15.214) with Microsoft SMTP Server (version=TLS1_0, cipher=TLS_RSA_WITH_AES_256_CBC_SHA) id 15.1.803.8 via Frontend Transport; Wed, 18 Jan 2017 10:35:33 +0000 Received: from tophie.ap.freescale.net ([10.232.14.39]) by tx30smr01.am.freescale.net (8.14.3/8.14.0) with ESMTP id v0IAYYhb003396; Wed, 18 Jan 2017 03:35:31 -0700 From: Shreyansh Jain To: CC: , , Shreyansh Jain Date: Wed, 18 Jan 2017 16:07:57 +0530 Message-ID: <1484735880-17178-10-git-send-email-shreyansh.jain@nxp.com> X-Mailer: git-send-email 2.7.4 In-Reply-To: <1484735880-17178-1-git-send-email-shreyansh.jain@nxp.com> References: <1484660264-6531-1-git-send-email-shreyansh.jain@nxp.com> <1484735880-17178-1-git-send-email-shreyansh.jain@nxp.com> X-EOPAttributedMessage: 0 X-Matching-Connectors: 131292093333779402; (91ab9b29-cfa4-454e-5278-08d120cd25b8); () X-Forefront-Antispam-Report: CIP:192.88.168.50; IPV:NLI; CTRY:US; EFV:NLI; SFV:NSPM; SFS:(10009020)(6009001)(7916002)(336005)(39380400002)(39400400002)(39410400002)(39450400003)(39860400002)(39850400002)(39840400002)(2980300002)(1109001)(1110001)(339900001)(199003)(189002)(626004)(2906002)(68736007)(50986999)(8656002)(38730400001)(85426001)(6916009)(50226002)(104016004)(189998001)(8936002)(54906002)(77096006)(6666003)(36756003)(110136003)(76176999)(81166006)(48376002)(2950100002)(8676002)(81156014)(50466002)(5660300001)(106466001)(33646002)(4326007)(2351001)(86362001)(305945005)(92566002)(105606002)(97736004)(356003)(47776003)(5003940100001)(53936002); DIR:OUT; SFP:1101; SCL:1; SRVR:BY2PR0301MB0743; H:tx30smr01.am.freescale.net; FPR:; SPF:Fail; PTR:InfoDomainNonexistent; A:1; MX:1; LANG:en; X-Microsoft-Exchange-Diagnostics: 1; BY2FFO11FD025; 1:kZc+dDE9iBZPy9xhb0ye4gLnKEy+U+cQ7PQe+pzr9u5Twhom5COls2G3v70XkE22t7WU2Kak92HfCiFzKUlcSLfJtN79TbBqrA+tIiFnn+dfinbDJs7B2Xctmedy55+HKA12BNst80VycLYRVwj2OaHn2sbZRn4KwNylczH24y91PJ5d/6jkWTM5lNIxKMgNh4b2Mz6RYFfHJRE4MUqXAjOFAcAq615UVfnuPi4Z5tOmk9/hBykDWbGXRksbN3oTmj0oGsa8ua96NNQUvN4pRhZBaw4wV2GAdyCPacJQhKBUHiE71xPA6v1rJSdXZ41u9rLIT2MqykOzw9TtqGajmA+Ozf4wabZGKuV54qIwKA1nxXhfZN99wkPOhH5LHkzHFKsVLsp1fWbFCpZQkiT5JUT/8v+INbNhz198f6lhbaY0qtYpP9SZO4uDgn7+M7a1hdOEKMkEN9VNjcJcImV57BjqFVc8OjzrkODFaCPQPHs33Aj8lhquSfoiRgA5ksRiaznNn1rdswh9cJTwS4n542UBsxKT0UTqSk780XhyGHa4kB6/JQDafDnxhwcvZMWFh1Zt6jA0Gjh+rGaFt+7RVksoqzHh1f5vvnXxO3rWV+2sR/p3DljLMvNjOhnrAeQcEe4yZhnRxQGsXIgY5JnTGCdHpFNbe4yasjdFzJ9x84Vib8+JMEIRdFW6GYWYWYBCgKtgGawX3vKU6yYbmE8hug== MIME-Version: 1.0 Content-Type: text/plain X-MS-Office365-Filtering-Correlation-Id: 7f707344-7955-4a0a-33ca-08d43f8dbb71 X-Microsoft-Antispam: UriScan:; BCL:0; PCL:0; RULEID:(22001); SRVR:BY2PR0301MB0743; X-Microsoft-Exchange-Diagnostics: 1; BY2PR0301MB0743; 3:5v2CPKltsasFcTPko4iRLHssFjP+j+TC09jOdlJGrauB8ihYM691qMXJNVjdE2CPKlysNZMiE8ALo4/ymsEl8z1LlhoZ/34UpmRPTijgTKjUUL7/lAWPKpfo1NsbYBCQmkpOyf0pr4JjbuzQbK6Ggh50c9mIg5wJdjfgyfbpM3aVoaLawezs7F2DPu1MC3NseaIW8UinjXTBkfiwkj+jGrXPrYZdSKh/PHBSMHewLJQPyrOg16ACpj3czSQZQdU+asvlKHRAq8fjE+i4bm4cRGDJ7T/D/3y5lGwjWX4L2g7Ob4J5jZ0vTrE8oiFq4pPBNkdYPWHq4cBTYq2l3kqJy9MgMMvVbzCBBv7ojchccUhg7VFgvlTzLrnw0G57b5tu; 25:+TovTavzEcXxl8jiPjb6dQ4Iz1G6bZI7nkOHBuMsGfkVEmEiGTk5Isij+/bw4FqezCnN5cU7go1k4mUT/nkrZ1a5gk0dESDbgGJsLJiVFzUydkGPqBAN0745AHK+KaZb19qFJFP9rr+hbRC9ZKw2wixe1fH0PZj8GJU+wWTnSfdeFLF/oM/4q3mUEJVknzUc19tdBbxgRbjDoT0Xlb9lFid2AUAkBa6W+kru3J5sO4WwOvrPVdCDqPsw2B/lpElhZlPGnGWr83hvCavmpbHjIKw6OGwj/GoV186J8/KBZAWjKSxrEqpYhRrqB4+CII0OoX0LeQW9gJZCH8T/CtCYnXJsQJXoEKG0GSLxo5/d9FvR2Zc/scgogE1IDGxwdRTu7mCxTT6nEEo6Cv+lXJp8u3rLlwO12wKwPYJ4CHjUL0Y/CecBjcfam+/JfX4b1cUKyk+D4z9oedloJ0M8rPHIpw== X-Microsoft-Exchange-Diagnostics: 1; BY2PR0301MB0743; 31:Una8Nx6iUF+NJn2a3mw5bDDaveu0Qz0dfU30IyMFu0Jd2cU5LL+DVZzo99U0wpkFSgyk4OvC+fdGmBD+jDNmX8QkSg/kGe9src/K3cRY5FiEwtj0Mh7/vDAwlKU6iJ7FGv5h96gA0Zwv/vcUY8jSF+teU/vQCgOApTC4Rb+5RJd00PpIKbsyGV8VtfbQixXQ3zEa4HVBQTjTXSMQ5rAHuVr6zo2zIP+pG+R0yPrHtaxwu8JdU7Uf3YDCzMLOygR/TAqHVkUu+xPGzV7yexyTJQ== X-Microsoft-Antispam-PRVS: X-Exchange-Antispam-Report-Test: UriScan:(185117386973197)(228905959029699); X-Exchange-Antispam-Report-CFA-Test: BCL:0; PCL:0; RULEID:(6095060)(601004)(2401047)(13015025)(13024025)(13023025)(13018025)(13017025)(5005006)(8121501046)(3002001)(10201501046)(6055026)(6096035)(20161123565025)(20161123563025)(20161123556025)(20161123561025)(20161123559025); SRVR:BY2PR0301MB0743; BCL:0; PCL:0; RULEID:(400006); SRVR:BY2PR0301MB0743; X-Microsoft-Exchange-Diagnostics: 1; BY2PR0301MB0743; 4:ylnXIMKxhtrw922EwNm96VQF+a2+fFlE6CaYT7yMtSUkolcSRkrihUvq/ZBCsWPMYfAM5131DthIGabDAuYwQ1y6fPgmvHdYyu4B3gwIEQ74PYYY0TP+GUXjDJe/TZ7cElq2JEagDZUL6ksEaus8thFXM8znV+B8bhMqBQPx70E2d1V3mEOJHBVxyUp9cGF+Kde+HUfORh0GXWM7cgeefzvKZaO7uM0kMCXELQg+901vT3IBfev+59dkY8LfAIgwQPbTypQvGyOofolSNf32RMc+ZJcASvgPMxWdsW4WaNna9mc7l9xYZW14CX54obxopw32M73Gos0PiNifBaMjZq4gVTRNho5DfdrY7734GDw0kIDYgvkTU16LepUvZjclmIPLIhhAW/N24I/fdnD5PnGLjfuCgLgo2BS2zkVc/NMpLSyNwCqu8ms7AIlzKMkQX6fFcXjUaQ0cEv1BHwKSRAqIzjeqZeRHGBPfBAZk4SebP34XtB5b69hP7KPlNIQtYe2eHmKGTThcxG5h714L/qEVfrY4435+ldDJjfgkVabcYXRrrkHiLcViy3m12fjd2SxfxLd3jW1OWnreExP8qzhkoWsrJJN1xFNfISC629nEGT5ikfZlzuqxuDKG7z0edvky5KJb9VjbPw7qv1sdcOAcnWPDt6lEuTp2WlRZ5ElHjIhRF6PdidgxV2cMlFZ2MgLdHweRajzxNDJIZ2LRXYt3GgJ8HPpxpmhrZY/TE21LhA2pu3wd1GZ/yp5k3y3CF9m6awXR1JaZohrYj0Qc7A== X-Forefront-PRVS: 01917B1794 X-Microsoft-Exchange-Diagnostics: =?us-ascii?Q?1; BY2PR0301MB0743; 23:mEIaKeW62aSd4oQqjWYAupbg2BwyqwqjHKbJxXG?= =?us-ascii?Q?LcFHlasvThjLTvbwJMavviaDKVWuz86eeOT2OS/yttoh+hS4tLTcVY5/nUH1?= =?us-ascii?Q?G8XEvAaUkDG9Ye0hw4InOCItbsKdfFm6iTbrPJh+to/cq0dOuLnRVZ2RhtGZ?= =?us-ascii?Q?3pa1pmes9Q1ivW2uDxb8mGrwUIW9hTcU8m3nCMzkgKXAnV+AC49tKMAmpv/m?= =?us-ascii?Q?800EBxX6ANArUdxKuubjy0kE4cJYLImtnldwAAGGrElh7ZQAarxrsG2crwBx?= =?us-ascii?Q?o16Owvj0HbvFgOO8q4tL0uDv9QHrJV7K7RF1cP9hFQinLqtFl3N54h1iFA0x?= =?us-ascii?Q?wsuIi7VaoW3d7kvHgCUTqJ1eq+oz79zJg2S7pqskpFQ1vD7ebHWGTbNDaWGp?= =?us-ascii?Q?MOvyq1eLksBPz3pKtUHvSs58dviZAlIe/rjN6jPNw/hSDcvJXpiTsKn/zYiz?= =?us-ascii?Q?LZ+ck61kRZ9DKv4bNn4VFurDmuJVPFrJ0RoI0/dfoqnxDXI4H0GxBRHkxpDL?= =?us-ascii?Q?ENAwSizieJmPviwLzSJAAhnuFTFZ2UKoPngZzW+qAAFQpr+pkqLlrSrWiMw7?= =?us-ascii?Q?zX5L/LIKPe437IyBT7n4gJA/KI9CY8nzcz2R0CrSMGUVipV9pQuQsizEfhQj?= =?us-ascii?Q?J6ZC5ecxeL5YkvKZ+DKvNJV41wZRyuDE/1Ti7Mey321XWRpL0mj+ajAHK9dc?= =?us-ascii?Q?Ccc7I8LNyePCoiznjeEVVWhTqgMroTBXp6sckEbaDWAGyFMthV9UcFDT9pG7?= =?us-ascii?Q?BlW/5zSs97CkyonRb+yVDOdAS/tVcvvTBsOQOFvheR9B0iLQaj3OWazQmuXX?= =?us-ascii?Q?Ck7sN4qjcWV0s2JkLOz2USuOfbk7/Bu3WYRSqEGUIIV1avmhOx0MyqLBmstC?= =?us-ascii?Q?CRYtdfH7k3Lc02eYlgxIPYW4YfgduAeTqKt6JwAgxVTuzX/M3C6xLhCb76TT?= =?us-ascii?Q?eRmcUi9pgceCLsemTP/H7SBwttmtK3EX3BsROcobMTK4KlZIuXsgwmuN/kjw?= =?us-ascii?Q?SgG7cwM0Ci0np0TjMTzpfRi6g1BH57ryzviWMk1kRqTIVMg0gOvNMZEORGvE?= =?us-ascii?Q?PSAE6c2uoMuLblnScbODZ43T+x/97wWUjqhaofcO6fTgb5/+KjBb4kb1147+?= =?us-ascii?Q?UwF9tlRB/B3j84oSMixlqZmwZ+fCrPoTYKCcRCsKFIGUmx1Ha2t5VrrKwgBP?= =?us-ascii?Q?A9WrTprYgyzGyrVPyLSGeLXaBQ16fszcqNrSIItbAH8gnRK7SpD2nTjfqvfn?= =?us-ascii?Q?HuuzUPGu41PYLbjLxfjT5GSaToPks7LlXWdGxi7LVgTVgU1yMf09Ibq7f3X4?= =?us-ascii?Q?6MrMLIjS9ESODY5xb98sB7mc=3D?= X-Microsoft-Exchange-Diagnostics: 1; BY2PR0301MB0743; 6:wF/XPuBN8tAENbHSvavAA0jRArpdiLxx6aEpUbH7kqb/mwCt9JgLwwmGEpopUtmcj3pdY94b/X1EUshVNl8ux3tK/cHyXscipxNbK+r+7diRkkBVLCpIazVKv0RP0cVIFgw0+RnHs+hPbmItwWfEpND0jawJdtYDBGsqNPswH7HyINhaRqXJ79YJhGhFqiMAoexe/F0HSQXLT1NrDM5te2gk5U1jVISo/y8w96pV3x6WqFftoYlYuhab81C7IFfqrANfJoQgJLGEvRFoRL7kQWZjV6ygRXOVYLkjRjfXNR5jmJy0rEne+hLZYF+0VsmdP4eQosbYkYXX20MeNm2AiZ6WZDDg7XYWeit9KZQXrZiV7+Sjh62gGvT3IKhVHBX99r9sY/TvuoZft0UAaYtGAnnjfxBoRrLRttasSEG1vwuG0A+FuQlAiwAs/fmmlr3H; 5:Lyz98WlVJLwcPG1pfyMoYfYjBCJ+Z6DWkW5HcE5rAQCm/kJqYIlwRRSVirlmjmTFTxcyQiN1ho4ILZiljWDQd6OC5jibQBwiR31lvxWN+P65aKZdkK8M0tI8cVqnZJ0iDHGaYvWJQI0M3PaoXIyDVNeVN8HZ/1TUe6SIpNKE83m5SIL3r2UTuTQoYd109let; 24:AndOn4A+0PYeATRxT2VcJuSqne4ed4i5bexmERGpwrulxMPDGh1Nqer+HaTMptRCv1gbAJ51UnK7t/zTVjLlxXWL/H2sjh0RsuUoZRSk3zo= SpamDiagnosticOutput: 1:99 SpamDiagnosticMetadata: NSPM X-Microsoft-Exchange-Diagnostics: 1; BY2PR0301MB0743; 7:Ba+vbpk1TDaxG6KBAt7+XAr4jy2nFJHx6GujlE1lWYlgp9V1PrTNEL22BlaQ3YcoilAszu+PEVWwkTG5PKoQG0b5DgRF4paHQnI86kE+DVJF7utQ4ey7w3IY7MyYN4nv1xEC7i/YEn2cGsvHGjV4PIUbVe52vKr1wN3YJo4BViAfPQQnUSWDtH+kLqN/RGAMnPXzvMK3UWlRRUrrgB9ub0P/RHXfSb2cX1bw1WIrP2KfZJKDNg2YtKBeNANKbr89tiSlAVcKE2TjcnqVOIFj4dggVWiYXJivJh6uFR48zG/1I8kbciTMiZzJsXJtgWnXR+1rQmGByG+zr9EAHqwXt6imT2y2tyJ4RVdehEWMoOfczs+uYl3dkoyhD3y4+Jnzr1Gc23FmVtMkmN4sb2mTui/SlqCcoR4o1t4RPUtThU00Z8WuVM5YIJYPR7EtmhoD46m5vpBpaveFW08Jv4y3mw== X-MS-Exchange-CrossTenant-OriginalArrivalTime: 18 Jan 2017 10:35:33.1751 (UTC) X-MS-Exchange-CrossTenant-Id: 5afe0b00-7697-4969-b663-5eab37d5f47e X-MS-Exchange-CrossTenant-OriginalAttributedTenantConnectingIp: TenantId=5afe0b00-7697-4969-b663-5eab37d5f47e; Ip=[192.88.168.50]; Helo=[tx30smr01.am.freescale.net] X-MS-Exchange-CrossTenant-FromEntityHeader: HybridOnPrem X-MS-Exchange-Transport-CrossTenantHeadersStamped: BY2PR0301MB0743 Subject: [dpdk-dev] [PATCH v9 09/12] test: add test cases for scan and probe on BUS 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, 18 Jan 2017 10:35:37 -0000 Signed-off-by: Shreyansh Jain Reviewed-by: Ferruh Yigit --- app/test/test_bus.c | 152 ++++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 152 insertions(+) diff --git a/app/test/test_bus.c b/app/test/test_bus.c index 0b6d011..ef7fa89 100644 --- a/app/test/test_bus.c +++ b/app/test/test_bus.c @@ -120,12 +120,15 @@ static int scan_fn_for_busB(void); /* generic implementations wrapped around by above declarations */ static int generic_scan_fn(struct rte_bus *bus); +static int generic_probe_fn(void); +static int dummy_match_fn(struct rte_driver *drv, struct rte_device *dev); struct dummy_bus busA = { .name = "busA_impl", /* busA */ .bus = { .name = "busA", .scan = scan_fn_for_busA, + .probe = generic_probe_fn, }, }; @@ -134,6 +137,7 @@ struct dummy_bus busB = { .bus = { .name = "busB", .scan = scan_fn_for_busB, + .probe = generic_probe_fn, }, }; @@ -288,6 +292,46 @@ generic_scan_fn(struct rte_bus *bus) return 0; } +/* @internal + * Obtain bus from driver object. Match the address of rte_device object + * with all the devices associated with that bus. + * + * Being a test function, all this does is validate that device object + * provided is available on the same bus to which driver is registered. + * + * @param drv + * driver to match with + * @param dev + * device object + * @return + * 0 for successful match + * !0 for failed match + */ +static int +dummy_match_fn(struct rte_driver *drv __rte_unused, struct rte_device *dev) +{ + struct rte_bus *bus; + struct dummy_device *ddev = NULL; + struct dummy_device *ddev_as_arg; + struct dummy_bus *dbus = NULL; + + /* Match is based entirely on address of 'dev' and 'dev_p' extracted + * from bus->device_list. + */ + + /* a driver is registered with the bus *before* the scan. */ + bus = dev->bus; + dbus = container_of(bus, struct dummy_bus, bus); + ddev_as_arg = container_of(dev, struct dummy_device, dev); + + TAILQ_FOREACH(ddev, &dbus->device_list, next) { + if (ddev == ddev_as_arg) + return 0; + } + + return 1; +} + int scan_fn_for_busA(void) { struct dummy_bus_map *dbm; @@ -504,6 +548,110 @@ test_bus_scan(void) return 0; } +/* + * + */ +static int +generic_probe_fn(void) +{ + int ret = 0; + int i, j; + struct rte_driver *drv; + struct rte_device *dev; + struct dummy_bus *dbus = NULL; + struct dummy_device *ddev = NULL; + struct dummy_driver *ddrv = NULL; + + /* In case of this test: + * 1. for each bus in rte_bus_list + * 2. for each device on that bus (bus specific->device_list) + * 3. for each driver on that bus (bus specific->driver_list) + * 4. call match + * 5. link driver and device + * 6. Verify the linkage. + */ + for (i = 0; bus_map[i].name; i++) { + /* get bus pointer from bus_map itself */ + dbus = bus_map[i].dbus; + + /* Looping over all scanned devices */ + TAILQ_FOREACH(ddev, &dbus->device_list, next) { + /* There is a list of drivers within dummy_bus_map. + * In case of PMDs, this would be driver registration + * APIs/list + */ + for (j = 0; bus_map[i].ddrivers[j]; j++) { + ddrv = bus_map[i].ddrivers[j]; + + drv = &ddrv->drv; + dev = &ddev->dev; + ret = dummy_match_fn(drv, dev); + if (!ret) { + /* As match is generic, it always + * results in dev->drv pointing to + * first driver entry in bus_map[i] + */ + dev->driver = drv; + dev->bus = &dbus->bus; + } + /* Else, continue */ + } + } + } + + /* Verify the linkage. All devices belonging to a bus_map[i] + * should have same driver (first driver entry of bus_map[i]) + */ + for (i = 0; bus_map[i].name; i++) { + ddrv = bus_map[i].ddrivers[0]; + drv = &ddrv->drv; + + for (j = 0; bus_map[i].ddevices[j]; j++) { + ddev = bus_map[i].ddevices[j]; + dev = &ddev->dev; + if (dev->driver != drv) { + printf("Incorrect driver<->device linkage.\n"); + return -1; + } + } + } + + return 0; +} + +/* @internal + * Function to perform 'probe' and link devices and drivers on a bus. + * This would work over all the buses registered, and all devices and drivers + * registered with it - call match on each pair. + * + * @param void + * @return + * 0 for successful probe + * !0 for failure in probe + * + */ +static int +test_probe_on_bus(void) +{ + int ret = 0; + int i; + struct dummy_bus *dbus; + struct rte_bus *bus; + + for (i = 0; bus_map[i].name; i++) { + /* get bus pointer from bus_map itself */ + dbus = bus_map[i].dbus; + bus = &dbus->bus; + ret = bus->probe(); + if (ret) + printf("Probe for %s failed.\n", bus_map[i].name); + } + + printf("Probe on all buses successful.\n"); + dump_device_tree(); + + return 0; +} int test_bus(void) @@ -518,6 +666,10 @@ test_bus(void) if (test_bus_scan()) return -1; + /* Now that the devices and drivers are registered, perform probe */ + if (test_probe_on_bus()) + return -1; + if (test_device_unregistration_on_bus()) return -1; -- 2.7.4