From patchwork Tue Mar 28 15:40:57 2023 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 8bit X-Patchwork-Submitter: Miquel Raynal X-Patchwork-Id: 13191311 Return-Path: X-Spam-Checker-Version: SpamAssassin 3.4.0 (2014-02-07) on aws-us-west-2-korg-lkml-1.web.codeaurora.org Received: from bombadil.infradead.org (bombadil.infradead.org [198.137.202.133]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by smtp.lore.kernel.org (Postfix) with ESMTPS id 766E2C76196 for ; Tue, 28 Mar 2023 15:42:24 +0000 (UTC) DKIM-Signature: v=1; a=rsa-sha256; q=dns/txt; c=relaxed/relaxed; d=lists.infradead.org; s=bombadil.20210309; h=Sender: Content-Transfer-Encoding:Content-Type:List-Subscribe:List-Help:List-Post: List-Archive:List-Unsubscribe:List-Id:MIME-Version:Message-Id:Date:Subject:Cc :To:From:Reply-To:Content-ID:Content-Description:Resent-Date:Resent-From: Resent-Sender:Resent-To:Resent-Cc:Resent-Message-ID:In-Reply-To:References: List-Owner; bh=6TlMmuUqysPW5i6cua6m8GWpNrc4YOHPCBbh6fcD9LE=; b=WDhptWzUg/CInJ 5eG0OQTZdbQIz+YMqTtEV53ttnrZDNH5JK+OdYiRlxRGp/EgwN1Z7sjZt+8V8ROXb7+giTiZwaZVF mG0fBRfbIHtYzxqtpcCKqljdRYFK/HWAy+jwz4EPZfGLu7EUp8N6Ip4w8tMMwRK/lCIGxvK1TAajQ hvNCsGftqA3N/XbKXkhs0KSG6zQlMlYK4cgQ39bAmEVD04p+ORhYzHBbZtQcBxMCc41bVniYLm0wK Q2sNG6BQTmwMnvpG1LLSf+v01pQsJgxa0cb17iElXNARDDapT8LzSE39+XSkuUHF9n9ahEPfH++JF HZwj+IdFJs0OxxYgas4A==; Received: from localhost ([::1] helo=bombadil.infradead.org) by bombadil.infradead.org with esmtp (Exim 4.96 #2 (Red Hat Linux)) id 1phBRo-00EyiF-36; Tue, 28 Mar 2023 15:41:20 +0000 Received: from relay3-d.mail.gandi.net ([217.70.183.195]) by bombadil.infradead.org with esmtps (Exim 4.96 #2 (Red Hat Linux)) id 1phBRh-00EycR-05; Tue, 28 Mar 2023 15:41:15 +0000 Received: (Authenticated sender: miquel.raynal@bootlin.com) by mail.gandi.net (Postfix) with ESMTPSA id E9A2F60009; Tue, 28 Mar 2023 15:41:05 +0000 (UTC) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=bootlin.com; s=gm1; t=1680018068; h=from:from:reply-to:subject:subject:date:date:message-id:message-id: to:to:cc:cc:mime-version:mime-version:content-type:content-type: content-transfer-encoding:content-transfer-encoding; bh=EuBvf9hnFtYoGeTSjuMvkRD/WXkdCQXxuD8f0+7PV5o=; b=ITyj2tVWPj8mZbtYrywqocVWF8uZlDRtbssdC4DGpwSzg6clP7NjtKN6EcECydhpvxCwd5 cYFg/LiFXE8ZF/kUnbdytx5OBew4UT5hE23cmp4YZfkpzOTArGs0CCuhZ5i31XLhakba7g neh5yBWvIWykg/xEFxy2ATjPHCS3OYGBfhzCv1PF1jOGDUKlY/t0EmyJrN++A3Q9Sc/aY5 syjyUng53TaO2M/WX62s21yNs9aHJgJEKiYGgo7i0DBVvLfBEsBvf22WRbq/zPdAvu43k5 B8sb1R35qs2rpmW8wbyzAPOTn/BwkUE4xZLe2Dj6Y7fRbxBsmj1z7kEeJppZMA== From: Miquel Raynal To: Richard Weinberger , Vignesh Raghavendra , Tudor Ambarus , Pratyush Yadav , Michael Walle , Cc: Julien Su , Jaime Liao , Jaime Liao , Alvin Zhou , Thomas Petazzoni , Michal Simek , , Miquel Raynal Subject: [PATCH v5 0/8] mtd: spi-nor: read while write support Date: Tue, 28 Mar 2023 17:40:57 +0200 Message-Id: <20230328154105.448540-1-miquel.raynal@bootlin.com> X-Mailer: git-send-email 2.34.1 MIME-Version: 1.0 X-CRM114-Version: 20100106-BlameMichelson ( TRE 0.8.0 (BSD) ) MR-646709E3 X-CRM114-CacheID: sfid-20230328_084113_334768_44CD3332 X-CRM114-Status: GOOD ( 36.63 ) X-BeenThere: linux-arm-kernel@lists.infradead.org X-Mailman-Version: 2.1.34 Precedence: list List-Id: List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Sender: "linux-arm-kernel" Errors-To: linux-arm-kernel-bounces+linux-arm-kernel=archiver.kernel.org@lists.infradead.org Hello folks, Here is a new version of this series trying to bring a little bit of parallelism to support SPI-NOR Read While Write feature on parts supporting it and featuring several banks. I have received some hardware to make it work, so since the RFC, the series has been updated to fix my mistakes, but the overall idea is the same. There is nothing Macronix specific in the implementation, the operations and opcodes are exactly the same as before. The only difference being: we may consider the chip usable when it is in the busy state during a write or an erase. Any chip with an internal split allowing to perform parallel operations might possibly leverage the benefits of this implementation. The first patches are just refactoring and preparation work, there is almost no functional change, it's just a way to prepare the introduction of the new locking mechanism and hopefully provide the cleanest and simplest diff possible for this new feature. The actual change is all contained in "mtd: spi-nor: Enhance locking to support reads while writes". The logic is described in the commit log and copy/pasted here for clarity: " On devices featuring several banks, the Read While Write (RWW) feature is here to improve the overall performance when performing parallel reads and writes at different locations (different banks). The following constraints have to be taken into account: 1#: A single operation can be performed in a given bank. 2#: Only a single program or erase operation can happen on the entire chip (common hardware limitation to limit costs) 3#: Reads must remain serialized even though reads crossing bank boundaries are allowed. 4#: The I/O bus is unique and thus is the most constrained resource, all spi-nor operations requiring access to the spi bus (through the spi controller) must be serialized until the bus exchanges are over. So we must ensure a single operation can be "sent" at a time. 5#: Any other operation that would not be either a read or a write or an erase is considered requiring access to the full chip and cannot be parallelized, we then need to ensure the full chip is in the idle state when this occurs. All these constraints can easily be managed with a proper locking model: 1#: Is enforced by a bitfield of the in-use banks, so that only a single operation can happen in a specific bank at any time. 2#: Is handled by the ongoing_pe boolean which is set before any write or erase, and is released only at the very end of the operation. This way, no other destructive operation on the chip can start during this time frame. 3#: An ongoing_rd boolean allows to track the ongoing reads, so that only one can be performed at a time. 4#: An ongoing_io boolean is introduced in order to capture and serialize bus accessed. This is the one being released "sooner" than before, because we only need to protect the chip against other SPI accesses during the I/O phase, which for the destructive operations is the beginning of the operation (when we send the command cycles and possibly the data), while the second part of the operation (the erase delay or the programmation delay) is when we can do something else in another bank. 5#: Is handled by the three booleans presented above, if any of them is set, the chip is not yet ready for the operation and must wait. All these internal variables are protected by the existing lock, so that changes in this structure are atomic. The serialization is handled with a wait queue." Here is now a benchmark with a Macronix MX25UW51245G with 4 banks and RWW support: // Testing the two accesses in the same bank $ flash_speed -b0 -k0 -c1 -d /dev/mtd0 [...] testing read while write latency read while write took 7ms, read ended after 7ms // Testing the two accesses within different banks $ flash_speed -b0 -k4096 -c1 -d /dev/mtd0 [...] testing read while write latency testing read while write latency read while write took 7ms, read ended after 5ms Parallel accesses have been validated with io_paral. A slight increase of the time spent on this test has however been noticed. With my configuration, over a limited number of blocks, the overall operation took 22 min without any RWW changes up to 27 min with these changes, maybe due to the number of additional scheduling situations involved. ubiformat /dev/mtd1 -y && ubiattach -p /dev/mtd1 && io_paral /dev/ubi0 Here is a branch with the mtd-utils patch bringing support for this additional "-k" parameter in flash_speed (for the second block to use during RWW testing), used to get the above results: https://github.com/miquelraynal/mtd-utils/compare/master...rww Finally, here are two speed tests with and without the RWW bit set. * Speed test with RWW enabled: # flash_speed -d -c 100 /dev/mtd1 not NAND flash, assume page size is 512 bytes. scanning for bad eraseblocks scanned 100 eraseblocks, 0 are bad testing eraseblock write speed eraseblock write speed is 251 KiB/s testing eraseblock read speed eraseblock read speed is 1869 KiB/s testing page write speed page write speed is 247 KiB/s testing page read speed page read speed is 902 KiB/s testing 2 page write speed 2 page write speed is 250 KiB/s testing 2 page read speed 2 page read speed is 1282 KiB/s Testing erase speed erase speed is 157 KiB/s Testing 2x multi-block erase speed 2x multi-block erase speed is 160 KiB/s Testing 4x multi-block erase speed 4x multi-block erase speed is 161 KiB/s Testing 8x multi-block erase speed 8x multi-block erase speed is 161 KiB/s Testing 16x multi-block erase speed 16x multi-block erase speed is 161 KiB/s Testing 32x multi-block erase speed 32x multi-block erase speed is 161 KiB/s Testing 64x multi-block erase speed 64x multi-block erase speed is 161 KiB/s finished * Speedtest without the RWW bit: # flash_speed -d -c100 /dev/mtd1 not NAND flash, assume page size is 512 bytes. scanning for bad eraseblocks scanned 100 eraseblocks, 0 are bad testing eraseblock write speed eraseblock write speed is 249 KiB/s testing eraseblock read speed eraseblock read speed is 1869 KiB/s testing page write speed page write speed is 246 KiB/s testing page read speed page read speed is 907 KiB/s testing 2 page write speed 2 page write speed is 248 KiB/s testing 2 page read speed 2 page read speed is 1286 KiB/s Testing erase speed erase speed is 158 KiB/s Testing 2x multi-block erase speed 2x multi-block erase speed is 160 KiB/s Testing 4x multi-block erase speed 4x multi-block erase speed is 161 KiB/s Testing 8x multi-block erase speed 8x multi-block erase speed is 161 KiB/s Testing 16x multi-block erase speed 16x multi-block erase speed is 160 KiB/s Testing 32x multi-block erase speed 32x multi-block erase speed is 161 KiB/s Testing 64x multi-block erase speed 64x multi-block erase speed is 160 KiB/s finished The differences are well within the imprecision of the measure, so no performance impact are to be expected on chips without RWW support. Cheers, Miquèl Changes in v5: * Made the bank calculations independent from the number of sectors and their size. * Reordered the preparation vs. locking step in a few drivers which I missed in my first attempt to do the conversion. * Converted the definition on the Macronix NOR chip to use SFDP tables. * Move the RWW SPI-NOR flag to the regular flag list, as it is not specific to the "no_sfdp" situation. * Created a SPI_NOR_F_* flag and set it in the core when relevant. * Really improved the logic when enabling the RWW SPI NOR core flag so we don't have to make any further checks beside looking at a single bit. * Improved commit messages and adapted them to the latest changes. * Changed numerous function parameters and added inermediate local variables as requested by Tudor. * Changed variable types. * Added information about the spi-nor chip being introduced as well as additional benchmarks. Changes in v4: * Dropped patch 1/9 which got applied. * s/SPI-NOR/SPI NOR/ * Turned n_banks into an u8 and moved it below in the struct to avoid padding. * Updated the S3AN_INFO macro to set n_banks to 1 by default. * Renamed the lock and prep helper to follow the order of each operation. * Reworded a commit log to fit the recent changes upstream. Changes in v3: * Fix the bank offsets calculations by providing the same values when locking and when unlocking (might be changed by the functions themselves without use noticing). * I completely changed the way the locking works because there was a new constraint: reads cannot be interrupted and status reads cannot happen during a read. Hence, as the multi-locks design was starting to be too messy, I changed the implementation to use a bunch of variables to track the read while write state, protected by the main spi-nor lock. If the internal state does not allow the operation, a sleep starts in a queue, until the threads are woken up after a state update. I know it is very verbose, I am open to suggestions. Miquel Raynal (8): mtd: spi-nor: Introduce the concept of bank mtd: spi-nor: Add a macro to define more banks mtd: spi-nor: Reorder the preparation vs. locking steps mtd: spi-nor: Separate preparation and locking mtd: spi-nor: Prepare the introduction of a new locking mechanism mtd: spi-nor: Add a RWW flag mtd: spi-nor: Enhance locking to support reads while writes mtd: spi-nor: macronix: Add support for mx25uw51245g with RWW drivers/mtd/spi-nor/core.c | 413 +++++++++++++++++++++++++++++++-- drivers/mtd/spi-nor/core.h | 25 +- drivers/mtd/spi-nor/debugfs.c | 1 + drivers/mtd/spi-nor/macronix.c | 4 + drivers/mtd/spi-nor/otp.c | 8 +- drivers/mtd/spi-nor/sst.c | 2 +- drivers/mtd/spi-nor/swp.c | 6 +- drivers/mtd/spi-nor/xilinx.c | 1 + include/linux/mtd/spi-nor.h | 13 ++ 9 files changed, 437 insertions(+), 36 deletions(-)