From patchwork Wed Sep 23 22:01:21 2020 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: John Thomson X-Patchwork-Id: 1370104 Return-Path: X-Original-To: incoming@patchwork.ozlabs.org Delivered-To: patchwork-incoming@bilbo.ozlabs.org Authentication-Results: ozlabs.org; spf=pass (sender SPF authorized) smtp.mailfrom=lists.openwrt.org (client-ip=2001:8b0:10b:1231::1; helo=merlin.infradead.org; envelope-from=openwrt-devel-bounces+incoming=patchwork.ozlabs.org@lists.openwrt.org; receiver=) Authentication-Results: ozlabs.org; dmarc=fail (p=none dis=none) header.from=johnthomson.fastmail.com.au Authentication-Results: ozlabs.org; dkim=pass (2048-bit key; secure) header.d=lists.infradead.org header.i=@lists.infradead.org header.a=rsa-sha256 header.s=merlin.20170209 header.b=ZGKF7qXK; dkim=fail reason="signature verification failed" (2048-bit key; unprotected) header.d=fastmail.com.au header.i=@fastmail.com.au header.a=rsa-sha256 header.s=fm1 header.b=LHkWjYMn; dkim=fail reason="signature verification failed" (2048-bit key; unprotected) header.d=messagingengine.com header.i=@messagingengine.com header.a=rsa-sha256 header.s=fm3 header.b=Pmzmike1; dkim-atps=neutral Received: from merlin.infradead.org (merlin.infradead.org [IPv6:2001:8b0:10b:1231::1]) (using TLSv1.3 with cipher TLS_AES_256_GCM_SHA384 (256/256 bits) key-exchange X25519 server-signature RSA-PSS (4096 bits) server-digest SHA256) (No client certificate requested) by ozlabs.org (Postfix) with ESMTPS id 4BxXJ31LXTz9sSC for ; Thu, 24 Sep 2020 08:03:47 +1000 (AEST) DKIM-Signature: v=1; a=rsa-sha256; q=dns/txt; c=relaxed/relaxed; d=lists.infradead.org; s=merlin.20170209; h=Sender:Content-Transfer-Encoding: Content-Type:Cc:List-Subscribe:List-Help:List-Post:List-Archive: List-Unsubscribe:List-Id:MIME-Version:Message-Id:Date:Subject: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=pIvMgaktuTeHrKheWWeqmadEQZib9bRVsBDw5fi9yI4=; b=ZGKF7qXK8yMobgjWvGIIvm2I5N xsaOlmpI343AQP+6I/yt5CK4AUhqGUiS55AICVIhfz/ILZLIQ7k2mgqEhu67lfmYKaBUEnfrsFIZf HmzV0nesaeunXPXY/WMfwFIj08wOFYy9GbMfEFuSog3cwGvYZZY6Ghz0NrhV6jztnok9eoQUZdt7b /VODs1x2r7gCiZoY4mRgQ6qhO1/uckzfeLNzZhRE1UCfFcMJdzOvooR5RWVEH4SypBeWZH705Pedn 3r/2avk6stBV/ATgRwQXbBqdHk7x/ShcN59B5BhXkYG9QNW9ivziuDkRdM73BgLzNYSFdZp2KaZIl ChQDMkIg==; Received: from localhost ([::1] helo=merlin.infradead.org) by merlin.infradead.org with esmtp (Exim 4.92.3 #3 (Red Hat Linux)) id 1kLCpf-0008TK-NF; Wed, 23 Sep 2020 22:01:47 +0000 Received: from wout4-smtp.messagingengine.com ([64.147.123.20]) by merlin.infradead.org with esmtps (Exim 4.92.3 #3 (Red Hat Linux)) id 1kLCpd-0008Sm-Bm for openwrt-devel@lists.openwrt.org; Wed, 23 Sep 2020 22:01:46 +0000 Received: from compute3.internal (compute3.nyi.internal [10.202.2.43]) by mailout.west.internal (Postfix) with ESMTP id E13E7B5B; Wed, 23 Sep 2020 18:01:38 -0400 (EDT) Received: from mailfrontend2 ([10.202.2.163]) by compute3.internal (MEProxy); Wed, 23 Sep 2020 18:01:39 -0400 DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=fastmail.com.au; h=from:to:cc:subject:date:message-id:mime-version :content-transfer-encoding; s=fm1; bh=+EeY7It7iyQysivV6HjISfEwDT OEOyi0FTNvibRn3ts=; b=LHkWjYMnBeNKSwqjOAhGFjf4tSVFG4/+GELTws8uRP OnmYVKm3UfP/X/19CSxYxwSy9GtikAZEnSqjfWh7ju+fxCgbVVFmKRx+uu6mLisW FUpwq+pTrSFhpU3cvYeab2CZ3vDC+iaxLqI/Yu9qc/jwU4Te563SAiQ5puoCt0ao NSw7qmyHmoSrkl00qPoPtlx6p7J6y9o0JQX1tSQQSbqoUmfwZ7I01MOatfXb7Gou u/k3myPQo+x9WilepbQzvj7NHWTvzEhmj3mRl58TbtVdUR76FFixjmePdh57PVZ5 GfRW6EZwuTcpjgfFMfpFWEtDdgRu95OoAxN0P4uVkAxg== DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d= messagingengine.com; h=cc:content-transfer-encoding:date:from :message-id:mime-version:subject:to:x-me-proxy:x-me-proxy :x-me-sender:x-me-sender:x-sasl-enc; s=fm3; bh=+EeY7It7iyQysivV6 HjISfEwDTOEOyi0FTNvibRn3ts=; b=Pmzmike1u3ZyipwGu8BlMkaOi1wdgYXAD UHM6Unvbkl7Jr7GXNpOnoUWH0xeFTH7GqlfhdTI8//wQ10vHykcMDSGlF6l8ygMr bV9Hls3ewszDAMZHSaLevPt1GA4Trqb5y4c/pHAx28yZT07M2czSAYBrmrtIQFIE hV7DFG+QrJ2mOzB+9wHwtFBQXtL9qHakhcSJubz76DycdqFfGicuWIJ4h9khvAn1 hQK2XBQfDY/+Rtty2BQzEguBzwzrr2sNxDoT0tbAHdT5HeabTlz20B4U16eEtjuP RNU5uxe/AllJ2meN4prLNgcowrH28tMD3siD/2TIngp6kbDoXI57Q== X-ME-Sender: X-ME-Proxy-Cause: gggruggvucftvghtrhhoucdtuddrgedujedrudejgddtfecutefuodetggdotefrodftvf curfhrohhfihhlvgemucfhrghsthforghilhdpqfgfvfdpuffrtefokffrpgfnqfghnecu uegrihhlohhuthemuceftddtnecunecujfgurhephffvufffkffoggfgsedtkeertdertd dtnecuhfhrohhmpeflohhhnhcuvfhhohhmshhonhcuoehgihhtsehjohhhnhhthhhomhhs ohhnrdhfrghsthhmrghilhdrtghomhdrrghuqeenucggtffrrghtthgvrhhnpeektefgud dtheejffduhfeuhfeftedukeegjeetueehleduieekteejlefhvdffveenucffohhmrghi nhepghhithhhuhgsrdgtohhmnecukfhppeehkedrudeihedrjedvrddujeehnecuvehluh hsthgvrhfuihiivgeptdenucfrrghrrghmpehmrghilhhfrhhomhepghhithesjhhohhhn thhhohhmshhonhdrfhgrshhtmhgrihhlrdgtohhmrdgruh X-ME-Proxy: Received: from john.thome.spur.red (unknown [58.165.72.175]) by mail.messagingengine.com (Postfix) with ESMTPA id 9E1FF306467E; Wed, 23 Sep 2020 18:01:36 -0400 (EDT) From: John Thomson To: openwrt-devel@lists.openwrt.org Subject: [PATCH RFC] kernel: mtd spi-nor: allow use of mixed erasesizes (E.g. 64K & 4K) Date: Thu, 24 Sep 2020 08:01:21 +1000 Message-Id: <20200923220121.8929-1-git@johnthomson.fastmail.com.au> X-Mailer: git-send-email 2.28.0 MIME-Version: 1.0 X-CRM114-Version: 20100106-BlameMichelson ( TRE 0.8.0 (BSD) ) MR-646709E3 X-CRM114-CacheID: sfid-20200923_180145_632534_69997C2B X-CRM114-Status: GOOD ( 30.81 ) X-Spam-Score: -0.8 (/) X-Spam-Report: SpamAssassin version 3.4.4 on merlin.infradead.org summary: Content analysis details: (-0.8 points) pts rule name description ---- ---------------------- -------------------------------------------------- -0.7 RCVD_IN_DNSWL_LOW RBL: Sender listed at https://www.dnswl.org/, low trust [64.147.123.20 listed in list.dnswl.org] -0.0 SPF_PASS SPF: sender matches SPF record -0.0 SPF_HELO_PASS SPF: HELO matches SPF record 0.0 RCVD_IN_MSPIKE_H3 RBL: Good reputation (+3) [64.147.123.20 listed in wl.mailspike.net] -0.1 DKIM_VALID Message has at least one valid DKIM or DK signature 0.1 DKIM_SIGNED Message has a DKIM or DK signature, not necessarily valid -0.1 DKIM_VALID_EF Message has a valid DKIM or DK signature from envelope-from domain 0.0 RCVD_IN_MSPIKE_WL Mailspike good senders X-BeenThere: openwrt-devel@lists.openwrt.org X-Mailman-Version: 2.1.29 Precedence: list List-Id: OpenWrt Development List List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Cc: John Thomson Sender: "openwrt-devel" Errors-To: openwrt-devel-bounces+incoming=patchwork.ozlabs.org@lists.openwrt.org Allow SPI NOR code to be configured to use the multiple erase-regions code path for a uniform erase-region device. This code path allows an erase request to select and run a list of erase operations (including 4K erases where supported by the device, and needed by the request). The multi erase-regions code path does additional checks before the erase starts, therefore may take slightly longer before the erase runs on device. Kernel config options: Introduces: CONFIG_MTD_SPI_NOR_USE_VARIABLE_ERASE=y Used with: CONFIG_MTD_SPI_NOR_USE_4K_SECTORS=n Previous users of partial or 4K erase in Openwrt: - Mikrotik routerboot bootloader configuration target/linux/generic/files/drivers/platform/mikrotik/rb_softconfig.c Will work with this patch, with the 4K_SECTORS test removed. - RedBoot "FIS directory" partition scheme layout update package/system/mtd/src/fis.c Will need to be changed to use the size of the FIS directory partition, rather than the partition erasesize. The partial erase patchset set erasesize to partition size where partition boundary was not major erasesize aligned. This patch sets partition erasesize to minor erasesize only where the boundary is minor erasesize aligned. An erasesize_minor variable is added to the MTD struct mtd_info, so that the mtd level does not need access to the SPI NOR level to calculate the smallest (minor) universal erasesize. This is set in spi-nor.c device initialisation. mtdpart.c is modified to not prevent writing to partitions with a boundary on a minor eraseblock. As mtd partitions are currently a stack of structs, the erasesize_minor need to be copied (from parent) to each partition. MTD partitions use a list in kernel 5.7, but the erasesize boundary code remains the same. There appears to be a bug in spi-nor.c for univeral erase-region devices, in a code path that only this patch uses: A pointer to an address within a struct is not updated following a memcpy of the struct. Signed-off-by: John Thomson --- Replaces Openwrt generic patches: These cuts are not included in this patch to reduce RFC length. - partial erase 411 & 412 - 4K limit 470 (non-functional on 5.4) Any suggestions welcome! Further discussion here: https://github.com/openwrt/openwrt/pull/3271 WIP: Do not run this without a full NOR backup, and a means to restore it. E.g. SOIC8 clip? + single board computer with extra SPI. Run tested with Mikrotik soft_config writes on ath79 & ramips. Not tested on Redboot FIS layout update (fis code needs changes). An earlier patch which modified the default universal erase-region code path in spi-nor.c was sent RFC to linux-mtd, but received no comments. The update pointer to memcpy'd address patch has been recently sent RFC to linux-mtd and maintainers. My intention is that once this gets addressed, I send through the erasesize_minor and mtdpart changes. - I am not sure that testing if (wr_alignment_minor) is enough to check that the device has an erasesize_minor set? - I am not sure that the picked erasesize_minor would be universal for multi erase-regions devices. It is my opinion that code requesting an mtd_erase should manage the whole eraseblock. The partial erase patchset currently manages this in kernel, and a recently fixed merge bug in it was able to cause data loss and bootloader corruption on some Mikrotik and Redboot devices. In kernel 5.7, the mtd partition code is changed and would require a rewrite of the partial erase, as part_erase is no longer used. There may be devices that currently use partial erase which do not support 4K erase. They would lose functionaly with this patch. If there are any other user of 4K or partial erase, please let me know. Cheers! --- ...9-0-mtd-spi-nor-allow-variable-erase.patch | 172 ++++++++++++++++++ 1 file changed, 172 insertions(+) create mode 100644 target/linux/generic/pending-5.4/499-0-mtd-spi-nor-allow-variable-erase.patch diff --git a/target/linux/generic/pending-5.4/499-0-mtd-spi-nor-allow-variable-erase.patch b/target/linux/generic/pending-5.4/499-0-mtd-spi-nor-allow-variable-erase.patch new file mode 100644 index 0000000000..a7d727f2b0 --- /dev/null +++ b/target/linux/generic/pending-5.4/499-0-mtd-spi-nor-allow-variable-erase.patch @@ -0,0 +1,172 @@ +--- a/drivers/mtd/mtdpart.c ++++ b/drivers/mtd/mtdpart.c +@@ -331,8 +331,9 @@ static struct mtd_part *allocate_partiti + { + int wr_alignment = (parent->flags & MTD_NO_ERASE) ? parent->writesize : + parent->erasesize; ++ int wr_alignment_minor = parent->erasesize_minor; + struct mtd_part *slave; +- u32 remainder; ++ u32 remainder, remainder_minor; + char *name; + u64 tmp; + +@@ -433,6 +434,9 @@ static struct mtd_part *allocate_partiti + if (parent->_put_device) + slave->mtd._put_device = part_put_device; + ++ if (parent->erasesize_minor) ++ slave->mtd.erasesize_minor = parent->erasesize_minor; ++ + slave->mtd._erase = part_erase; + slave->parent = parent; + slave->offset = part->offset; +@@ -523,21 +527,41 @@ static struct mtd_part *allocate_partiti + + tmp = part_absolute_offset(parent) + slave->offset; + remainder = do_div(tmp, wr_alignment); +- if ((slave->mtd.flags & MTD_WRITEABLE) && remainder) { +- /* Doesn't start on a boundary of major erase size */ +- /* FIXME: Let it be writable if it is on a boundary of +- * _minor_ erase size though */ +- slave->mtd.flags &= ~MTD_WRITEABLE; +- printk(KERN_WARNING"mtd: partition \"%s\" doesn't start on an erase/write block boundary -- force read-only\n", +- part->name); ++ if (remainder && wr_alignment_minor) { ++ tmp = part_absolute_offset(parent) + slave->offset; ++ remainder_minor = do_div(tmp, wr_alignment_minor); ++ } ++ if (slave->mtd.flags & MTD_WRITEABLE){ ++ if (!remainder){ ++ /* Does start on a boundary of major erase size */ ++ } else if (wr_alignment_minor && !remainder_minor){ ++ /* Does start on a boundary of minor erase size */ ++ slave->mtd.erasesize = parent->erasesize_minor; ++ } else { ++ slave->mtd.flags &= ~MTD_WRITEABLE; ++ printk(KERN_WARNING"mtd: partition \"%s\" doesn't start on an erase/write block boundary -- force read-only\n", ++ part->name); ++ } + } + + tmp = part_absolute_offset(parent) + slave->offset + slave->mtd.size; + remainder = do_div(tmp, wr_alignment); +- if ((slave->mtd.flags & MTD_WRITEABLE) && remainder) { +- slave->mtd.flags &= ~MTD_WRITEABLE; +- printk(KERN_WARNING"mtd: partition \"%s\" doesn't end on an erase/write block -- force read-only\n", +- part->name); ++ if (remainder && wr_alignment_minor) { ++ tmp = part_absolute_offset(parent) + ++ slave->offset + slave->mtd.size; ++ remainder_minor = do_div(tmp, wr_alignment_minor); ++ } ++ if (slave->mtd.flags & MTD_WRITEABLE){ ++ if (!remainder){ ++ /* Does end on a boundary of major erase size */ ++ } else if (wr_alignment_minor && !remainder_minor){ ++ /* Does end on a boundary of minor erase size */ ++ slave->mtd.erasesize = parent->erasesize_minor; ++ } else { ++ slave->mtd.flags &= ~MTD_WRITEABLE; ++ printk(KERN_WARNING"mtd: partition \"%s\" doesn't end on an erase/write block -- force read-only\n", ++ part->name); ++ } + } + + mtd_set_ooblayout(&slave->mtd, &part_ooblayout_ops); +--- a/drivers/mtd/spi-nor/Kconfig ++++ b/drivers/mtd/spi-nor/Kconfig +@@ -24,6 +24,14 @@ config MTD_SPI_NOR_USE_4K_SECTORS + Please note that some tools/drivers/filesystems may not work with + 4096 B erase size (e.g. UBIFS requires 15 KiB as a minimum). + ++config MTD_SPI_NOR_USE_VARIABLE_ERASE ++ bool "Disable uniform_erase" ++ default n ++ help ++ Return false with spi_nor_has_uniform_erase, ++ so that the multiple eraseregions code path is used. ++ This allows an erase to use 4K erase where supported and needed. ++ + config SPI_ASPEED_SMC + tristate "Aspeed flash controllers in SPI mode" + depends on ARCH_ASPEED || COMPILE_TEST +--- a/drivers/mtd/spi-nor/spi-nor.c ++++ b/drivers/mtd/spi-nor/spi-nor.c +@@ -4346,6 +4346,7 @@ static int spi_nor_select_erase(struct s + { + struct spi_nor_erase_map *map = &nor->params.erase_map; + const struct spi_nor_erase_type *erase = NULL; ++ const struct spi_nor_erase_type *erase_minor = NULL; + struct mtd_info *mtd = &nor->mtd; + u32 wanted_size = nor->info->sector_size; + int i; +@@ -4378,15 +4379,20 @@ static int spi_nor_select_erase(struct s + */ + for (i = SNOR_ERASE_TYPE_MAX - 1; i >= 0; i--) { + if (map->erase_type[i].size) { +- erase = &map->erase_type[i]; +- break; ++ if (!erase) ++ erase = &map->erase_type[i]; ++ erase_minor = &map->erase_type[i]; + } + } + + if (!erase) + return -EINVAL; + ++ if (!erase_minor) ++ erase_minor = erase; ++ + mtd->erasesize = erase->size; ++ mtd->erasesize_minor = erase_minor->size; + return 0; + } + +@@ -4522,12 +4528,20 @@ static void spi_nor_sfdp_init_params(str + struct spi_nor_flash_parameter sfdp_params; + + memcpy(&sfdp_params, &nor->params, sizeof(sfdp_params)); ++ if (nor->params.erase_map.regions == ++ &nor->params.erase_map.uniform_region) ++ sfdp_params.erase_map.regions = ( ++ &sfdp_params.erase_map.uniform_region); + + if (spi_nor_parse_sfdp(nor, &sfdp_params)) { + nor->addr_width = 0; + nor->flags &= ~SNOR_F_4B_OPCODES; + } else { + memcpy(&nor->params, &sfdp_params, sizeof(nor->params)); ++ if (sfdp_params.erase_map.regions == ++ &sfdp_params.erase_map.uniform_region) ++ nor->params.erase_map.regions = ( ++ &nor->params.erase_map.uniform_region); + } + } + +--- a/include/linux/mtd/mtd.h ++++ b/include/linux/mtd/mtd.h +@@ -205,6 +205,8 @@ struct mtd_info { + * information below if they desire + */ + uint32_t erasesize; ++ /* "Minor" erase size supported by the whole device */ ++ uint32_t erasesize_minor; + /* Minimal writable flash unit size. In case of NOR flash it is 1 (even + * though individual bits can be cleared), in case of NAND flash it is + * one NAND page (or half, or one-fourths of it), in case of ECC-ed NOR +--- a/include/linux/mtd/spi-nor.h ++++ b/include/linux/mtd/spi-nor.h +@@ -631,7 +631,11 @@ spi_nor_region_mark_overlay(struct spi_n + + static bool __maybe_unused spi_nor_has_uniform_erase(const struct spi_nor *nor) + { ++#ifdef CONFIG_MTD_SPI_NOR_USE_VARIABLE_ERASE ++ return false; ++#else + return !!nor->params.erase_map.uniform_erase_type; ++#endif + } + + static inline void spi_nor_set_flash_node(struct spi_nor *nor,