From 8c31f6bcab657df12a54ed699b87ca52375dadc8 Mon Sep 17 00:00:00 2001 From: Daniel Golle Date: Wed, 12 Jan 2022 19:14:59 +0000 Subject: [PATCH 01/29] procd: update to git HEAD ca6c35c uxc: usage message cosmetics e083dd4 uxc: fix two minor issues reported by Coverity 35dfbff procd: jail/cgroups: correctly enable "rdma" when requested 3b3ac64 procd: mount /dev with noexec ac2b8b3 procd: clean up /dev/pts mounts Signed-off-by: Daniel Golle --- package/system/procd/Makefile | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/package/system/procd/Makefile b/package/system/procd/Makefile index 1a4d2c7096..27b235cea7 100644 --- a/package/system/procd/Makefile +++ b/package/system/procd/Makefile @@ -12,9 +12,9 @@ PKG_RELEASE:=$(AUTORELEASE) PKG_SOURCE_PROTO:=git PKG_SOURCE_URL=$(PROJECT_GIT)/project/procd.git -PKG_MIRROR_HASH:=3ce6f5e2c12ae276af3ffe1755a495415f77184974206a44a3b083420aba52a8 -PKG_SOURCE_DATE:=2021-12-20 -PKG_SOURCE_VERSION:=129d050b9f5725ea4c54e1d906aba43eca95b860 +PKG_MIRROR_HASH:=0e506062a992f77979bd59eb51fb5d500e45197cc7bfba3a9302415d754dbfd1 +PKG_SOURCE_DATE:=2022-01-11 +PKG_SOURCE_VERSION:=ac2b8b365bdbcbf292f77409d180ec3c0963faf3 CMAKE_INSTALL:=1 PKG_LICENSE:=GPL-2.0 From 7f2052ef22c04e2ee4b51ef1862b81bd5ae26f11 Mon Sep 17 00:00:00 2001 From: Hans Dedecker Date: Wed, 12 Jan 2022 21:10:23 +0100 Subject: [PATCH 02/29] netifd: update to git HEAD 96902e8 Revert "netifd: add devtype to ubus call" 29e6acf netifd: add devtype to ubus call 7ccbf08 netifd: add devtype to ubus call Signed-off-by: Hans Dedecker --- package/network/config/netifd/Makefile | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/package/network/config/netifd/Makefile b/package/network/config/netifd/Makefile index 10bb115041..0c8b7e92dd 100644 --- a/package/network/config/netifd/Makefile +++ b/package/network/config/netifd/Makefile @@ -5,9 +5,9 @@ PKG_RELEASE:=1 PKG_SOURCE_PROTO:=git PKG_SOURCE_URL=$(PROJECT_GIT)/project/netifd.git -PKG_SOURCE_DATE:=2021-12-02 -PKG_SOURCE_VERSION:=5ca5e0b4d058a47d72ba4102acdcec826e203c41 -PKG_MIRROR_HASH:=8a1fd6b634a0390a5ee512483c924b3ea8fa3ea9fa863d0434e3e66949faccab +PKG_SOURCE_DATE:=2022-01-12 +PKG_SOURCE_VERSION:=96902e8fb712a070867a0a822d7877fdb10573f5 +PKG_MIRROR_HASH:=5112a8a0bc6d374bd0b336bebf59f5da29f23f521b80f40c69fcf37b1c7e74f1 PKG_MAINTAINER:=Felix Fietkau PKG_LICENSE:=GPL-2.0 From 2bb7c1db70057b2465ec905e30c320eda3c41aa0 Mon Sep 17 00:00:00 2001 From: Koen Vandeputte Date: Wed, 20 Oct 2021 15:29:20 +0200 Subject: [PATCH 03/29] imx: bump SDMA firmware to v3.6 No changelog available Signed-off-by: Koen Vandeputte --- .../files/firmware/imx/sdma/sdma-imx6q.bin | Bin 2746 -> 2970 bytes 1 file changed, 0 insertions(+), 0 deletions(-) diff --git a/target/linux/imx/files/firmware/imx/sdma/sdma-imx6q.bin b/target/linux/imx/files/firmware/imx/sdma/sdma-imx6q.bin index 4d0593cec7dfdae1a8bf28a2d83bdd1e95839b82..420256546e32ff52c07489ba46433b8e6e0cbd10 100644 GIT binary patch delta 1667 zcmaJ>ZA@EL7(Vy(e)L}02QbzGgYvP_Zf>9xr^ak^WGtYmV+CA?GL}nl>4KDswW3hJGZ?UR@AC~ zxpQlOu8=Eyf|JB+I7(6dU9BUGL$aDAYB(R^kitA#$31EI!V((m%I?ZbD2a+?aQ{u| zCQwSZ*+}QZvi4Jt1hmpE$S+yM&MZUg4^NFO(n}v&UMrbW)KftJ;^Iu8f21 z+{5gjko`mB%zVVK{x8oeved$rN@_IPEpE(9AIPlA5i-TY0`iwwOT0vnVNX%&z*_F! zv-zC;`BgiSmE*{3dJDMn za5Q48tX8(3g^0zByTW2x>-22#z#cnr&$2GG7h5=JKN5gqYY z%ya1LK(gu3$Sob=i}bpq;irC z9g}#y3vjvBN`wY)fh^xev?VUkwz$|MiF&V;rQ;B8;oCeBMwfZzRzw^5!o8a#eA_zX zZIL#jdQQiY%TOd*Mf)Y(vazjN;V7kVB3xl-CP2)j4@!??LLZDWLf%9rMJLE~gM z!%y~d)5*7e01!gxI$^#QQ@>EW^Aa#z zf-nHWW|8S;Jm79Nv+d!uar27F{EU)=GlhnPwYcyt{YWS_R+O}*=*_wd6um=hNXaB* z*^n70nrffa`4vM{_Jr-r>-jEUlS!7Yuixsw}w?GBUD|WsHME~ysmX=p& z-vLiZ4LvSyTDM%%#g?QeBb4Bhf=4xNzcLeaM0|=nL;n)J6(3tX*^x7*m0&~G2#Xbn z6*5HkNFIem?cSqNN~BuPY;-Mb;AC%-geymTow20)OH?LqgWH7s9(|17ki5!QQ3>&C zHW6a5#*bBAGvQR z30Lex`nj{t^?r1vQ^)}ID+Re7F-CGSz&UY{fPe{k^83F-&`24&7ILjV8( delta 1395 zcmZuxUu;ul6hHUt{nL9pw{=)n2BRCewj^v5jk?6>fWR_I%J6Q3S=uqW&5Y~#^RiIL zy}Q9T14iffVDG&(!NeCrG%?W^W7KsCHepMaOmuGbg^3Zng@+LlmRQf%?hiq3a_&9n zcfNDZ?>qUmcJ(*Dy3PZUeJ%hH(6*s9qD`ayB?G)m0LJP=)rH7bfC4^w1YX@z@~>?j z>pc{{?FV>R1JHxD%XsPo)&sHQXd{U4!QO5jfNta38+WCYMAN7|xO=ops1iOWSuJF` z>Y#l|-3iId~_o6ALB$ym38`_jnGF&kcbxdcNV>>pJUCr2+KgI;71TV)_d zkC|za3n7b+yw1*V>V)>&`q!zcSveu@kFq3($%i_$|E+(8^rmK&g!mMkWjz1Ogy}p9 zdb%O9*?5H9`%+YswtGa7pmeD?jksFh5G^I~0@8YZl~$ib3^7`61*0L83$PXaxk|3t z@&S*l5~Fe=7;VCc#f*`{VtUIJD7%YGD|P=P^%1W&zis`a&UbxFCW)-;*g348MP#Og z7{JG^%kYDm?R;zeX9GxtUgCGQ*w$y{H$sfpCEMyn%i|S@p29URt1Dfa)M5-voN?EB zM>6zN5^oG)U#|R1i{|+4l{bncNjD$gfp){9icoW4+T!ESn(vA92()v?H7jQOKuoej z9TMq&F5WD0dd#kdv-sueX!j?$qyD)OYoq%Eiw+5O-U=+78RoGxdwK_21+|3Qz!p1u zT3l~`58EHLH%f6aLcO;QD~05bT6U0+Gi#%gSo_)$n~!f)2JM(#8eSM?;{g`B*yTBW z#EM(YFDPD8s4*p?Ulq>LlVYv85L?sZni@B>7(gw)tlya{X;D-MM*CdEs3cWH)_P6$ zK3;tHtm|-TU5CHxlgQWycjiRZqoEY*xX_vuZ(@ewik1#Pkzla=#PMBvSPRiTQiBW; zUr~w|=_x57i*P>E#VeWf^i%02&PRWdLOb_5Y$($e8yiGxEg~#dFjllyTJH`h|JtS6 z6`LM%?+;vYDseM2XR=xd0Fi*vN3Xj>%A1Y^e4 Date: Tue, 21 Dec 2021 09:45:59 +0200 Subject: [PATCH 04/29] generic: platform/mikrotik: make soft_config writable without 4K sectors Make soft_config writable in all cases. Performing soft_config commit will fail if mtd partition is not writable. Signed-off-by: Oskari Lemmela [bump rb_softconfig version number] Signed-off-by: Koen Vandeputte --- .../drivers/platform/mikrotik/rb_softconfig.c | 19 ++++--------------- 1 file changed, 4 insertions(+), 15 deletions(-) diff --git a/target/linux/generic/files/drivers/platform/mikrotik/rb_softconfig.c b/target/linux/generic/files/drivers/platform/mikrotik/rb_softconfig.c index 070bd32d5a..453e1347b2 100644 --- a/target/linux/generic/files/drivers/platform/mikrotik/rb_softconfig.c +++ b/target/linux/generic/files/drivers/platform/mikrotik/rb_softconfig.c @@ -56,23 +56,12 @@ #include "routerboot.h" -#define RB_SOFTCONFIG_VER "0.03" +#define RB_SOFTCONFIG_VER "0.04" #define RB_SC_PR_PFX "[rb_softconfig] " -/* - * mtd operations before 4.17 are asynchronous, not handled by this code - * Also make the driver act read-only if 4K_SECTORS are not enabled, since they - * are require to handle partial erasing of the small soft_config partition. - */ -#if defined(CONFIG_MTD_SPI_NOR_USE_4K_SECTORS) - #define RB_SC_HAS_WRITE_SUPPORT true - #define RB_SC_WMODE S_IWUSR - #define RB_SC_RMODE S_IRUSR -#else - #define RB_SC_HAS_WRITE_SUPPORT false - #define RB_SC_WMODE 0 - #define RB_SC_RMODE S_IRUSR -#endif +#define RB_SC_HAS_WRITE_SUPPORT true +#define RB_SC_WMODE S_IWUSR +#define RB_SC_RMODE S_IRUSR /* ID values for software settings */ #define RB_SCID_UART_SPEED 0x01 // u32*1 From 8441a622eca236c5ed19545c7b11129466c1d8cb Mon Sep 17 00:00:00 2001 From: Oskari Lemmela Date: Tue, 21 Dec 2021 09:46:00 +0200 Subject: [PATCH 05/29] mikrotik: enable variable size erase Add support for variable size erase blocks. Enable it to all targets which has mikrotik targets. Signed-off-by: Oskari Lemmela --- target/linux/ath79/mikrotik/config-default | 1 + target/linux/generic/config-5.10 | 1 + ...support-for-minor-aligned-partitions.patch | 397 ++++++++++++++++++ target/linux/ipq40xx/mikrotik/config-default | 1 + target/linux/ramips/mt7621/config-5.10 | 1 + 5 files changed, 401 insertions(+) create mode 100644 target/linux/generic/pending-5.10/402-mtd-spi-nor-write-support-for-minor-aligned-partitions.patch diff --git a/target/linux/ath79/mikrotik/config-default b/target/linux/ath79/mikrotik/config-default index 74cfdf0423..ee2e4ebe9a 100644 --- a/target/linux/ath79/mikrotik/config-default +++ b/target/linux/ath79/mikrotik/config-default @@ -19,6 +19,7 @@ CONFIG_MTD_NAND_RB91X=y CONFIG_MTD_RAW_NAND=y CONFIG_MTD_ROUTERBOOT_PARTS=y CONFIG_MTD_SPI_NAND=y +CONFIG_MTD_SPI_NOR_USE_VARIABLE_ERASE=y CONFIG_MTD_SPLIT_MINOR_FW=y CONFIG_MTD_UBI=y CONFIG_MTD_UBI_BLOCK=y diff --git a/target/linux/generic/config-5.10 b/target/linux/generic/config-5.10 index bd2e72e54f..714a0b9ec7 100644 --- a/target/linux/generic/config-5.10 +++ b/target/linux/generic/config-5.10 @@ -3641,6 +3641,7 @@ CONFIG_MTD_ROOTFS_ROOT_DEV=y # CONFIG_MTD_SPI_NOR is not set # CONFIG_MTD_SPI_NOR_USE_4K_SECTORS is not set CONFIG_MTD_SPI_NOR_USE_4K_SECTORS_LIMIT=4096 +# CONFIG_MTD_SPI_NOR_USE_VARIABLE_ERASE is not set CONFIG_MTD_SPLIT=y # CONFIG_MTD_SPLIT_BCM63XX_FW is not set # CONFIG_MTD_SPLIT_BCM_WFI_FW is not set diff --git a/target/linux/generic/pending-5.10/402-mtd-spi-nor-write-support-for-minor-aligned-partitions.patch b/target/linux/generic/pending-5.10/402-mtd-spi-nor-write-support-for-minor-aligned-partitions.patch new file mode 100644 index 0000000000..fe92530081 --- /dev/null +++ b/target/linux/generic/pending-5.10/402-mtd-spi-nor-write-support-for-minor-aligned-partitions.patch @@ -0,0 +1,397 @@ +From patchwork Tue Jun 8 04:07:19 2021 +Content-Type: text/plain; charset="utf-8" +MIME-Version: 1.0 +Content-Transfer-Encoding: 7bit +X-Patchwork-Submitter: John Thomson +X-Patchwork-Id: 1489105 +X-Patchwork-Delegate: tudor.ambarus@gmail.com +Return-Path: + +X-Original-To: incoming@patchwork.ozlabs.org +Delivered-To: patchwork-incoming@bilbo.ozlabs.org +Authentication-Results: ozlabs.org; + spf=none (no SPF record) smtp.mailfrom=lists.infradead.org + (client-ip=2607:7c80:54:e::133; helo=bombadil.infradead.org; + envelope-from=linux-mtd-bounces+incoming=patchwork.ozlabs.org@lists.infradead.org; + receiver=) +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=bombadil.20210309 header.b=EMabhVoR; + 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=fm3 header.b=dLzuZ6dB; + 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=nSRGsW+C; + dkim-atps=neutral +Received: from bombadil.infradead.org (bombadil.infradead.org + [IPv6:2607:7c80:54:e::133]) + (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 4FzcFN1j1nz9sW8 + for ; Tue, 8 Jun 2021 14:09:28 +1000 (AEST) +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=6mUWQd71FwsINycGYY1qOhKz+ecWJVNtwDkTebG3XkA=; b=EMabhVoRE3ad89 + o3L2AgyKrs+blSofUC3hoSsQe7gi3m4si8S9HW8Z+8SsS5TufUsvGwDl80qSYGlQOytQF+1yRUWvE + 6FJ/+bqv+TwjqZFibgJ6+9OVsQN9dZ/no1R0bBXIpmrf8ORUmv58QK4ZQquaFKbyXKpFeWOC2MSv4 + H2MAhyhTU8a3gtooH6G8+KvsJEfVgh6C+aDbwxyh2UY3chHKuw1kvL6AktbfUE2xl4zxi3x3kc70B + Wi3LiJBFokxVdgnROXxTU5tI0XboWYkQV64gLuQNV4XKClcuhVpzloDK8Iok6NTd7b32a7TdEFlCS + lGKsEKmxtUlW2FpfoduA==; +Received: from localhost ([::1] helo=bombadil.infradead.org) + by bombadil.infradead.org with esmtp (Exim 4.94.2 #2 (Red Hat Linux)) + id 1lqT1r-006OAW-DX; Tue, 08 Jun 2021 04:07:51 +0000 +Received: from new1-smtp.messagingengine.com ([66.111.4.221]) + by bombadil.infradead.org with esmtps (Exim 4.94.2 #2 (Red Hat Linux)) + id 1lqT1l-006O9b-Fq + for linux-mtd@lists.infradead.org; Tue, 08 Jun 2021 04:07:50 +0000 +Received: from compute2.internal (compute2.nyi.internal [10.202.2.42]) + by mailnew.nyi.internal (Postfix) with ESMTP id 4456B580622; + Tue, 8 Jun 2021 00:07:42 -0400 (EDT) +Received: from mailfrontend2 ([10.202.2.163]) + by compute2.internal (MEProxy); Tue, 08 Jun 2021 00:07:42 -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=fm3; bh=ZXRH+YluM1mHCS1EWUiCY/Sg8O + LccfHe1oW5iAay6y8=; b=dLzuZ6dBYf7ZA8tWLOBFZYLi7ERsGe/4vnMXG+ovvb + dNBO0+SaFGwoqYSFrfq/TeyHfKyvxrA7+LCdopIuT4abpLHxtRwtRiafQcDYCPat + qJIqOZO+wCZC5S9Jc1OP7+t1FviGpgevqIMotci37P+RWc5u3AweMzFljZk90E8C + uorV6rXagD+OssJQzllRnAIK88+rOAC9ZyXv2gWxy4d1HSCwSWgzx2vnV9CNp918 + YC/3tiHas9krbrPIaAsdBROr7Bvoe/ShRRzruKRuvZVgg5NN90vX+/5ZjI8u04GM + p2bWCbC62CP6wlcgDaz+c/Sgr5ITd2GPENJsHfqmLRBA== +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=ZXRH+YluM1mHCS1EW + UiCY/Sg8OLccfHe1oW5iAay6y8=; b=nSRGsW+CQ2Zx1RVpIUu8W/VD/k5P+32BW + 5k2ltd+UhI3dfldBPzHrYiOP/IJqGkNW+V+rHASacW/vFygnaZoxNjRYKnOsu+26 + wb2yK3jpl6lsNTg3N1Z4XJrYY2lf9H29DMFbhC67l0PTc050rcZk4XsKTLAlv14Q + VA4WREYSaX/4IN4O+ES4TMq0a/3gKZh6nvbbJXbsXfK0WlSHTGZtZmW3fyrqvbXa + t+R7L8vvqWvwls0pV+Sn8LeQqb7+A69w0UOnuznjkcA3sCc2YehcHbxcUEnMH+9N + bxOjmIDeg9/4X/829tUWUJiLhE5SFmQZ1P6oFtmbWoLrDz0ZJIVBw== +X-ME-Sender: + +X-ME-Received: + +X-ME-Proxy-Cause: + gggruggvucftvghtrhhoucdtuddrgeduledrfedtkedgjeduucetufdoteggodetrfdotf + fvucfrrhhofhhilhgvmecuhfgrshhtofgrihhlpdfqfgfvpdfurfetoffkrfgpnffqhgen + uceurghilhhouhhtmecufedttdenucesvcftvggtihhpihgvnhhtshculddquddttddmne + cujfgurhephffvufffkffoggfgsedtkeertdertddtnecuhfhrohhmpeflohhhnhcuvfhh + ohhmshhonhcuoehgihhtsehjohhhnhhthhhomhhsohhnrdhfrghsthhmrghilhdrtghomh + drrghuqeenucggtffrrghtthgvrhhnpefffeeihfdukedtuedufeetieeuudfhhefhkefh + tefgtdeuffekffelleetveduieenucevlhhushhtvghrufhiiigvpedtnecurfgrrhgrmh + epmhgrihhlfhhrohhmpehgihhtsehjohhhnhhthhhomhhsohhnrdhfrghsthhmrghilhdr + tghomhdrrghu +X-ME-Proxy: + + + +Received: by mail.messagingengine.com (Postfix) with ESMTPA; Tue, + 8 Jun 2021 00:07:35 -0400 (EDT) +From: John Thomson +To: Miquel Raynal , + Richard Weinberger , Vignesh Raghavendra , + Tudor Ambarus , + Michael Walle , Pratyush Yadav , + linux-mtd@lists.infradead.org +Cc: linux-kernel@vger.kernel.org, + John Thomson , + kernel test robot , Dan Carpenter +Subject: [PATCH] mtd: spi-nor: write support for minor aligned partitions +Date: Tue, 8 Jun 2021 14:07:19 +1000 +Message-Id: <20210608040719.14431-1-git@johnthomson.fastmail.com.au> +X-Mailer: git-send-email 2.31.1 +MIME-Version: 1.0 +X-CRM114-Version: 20100106-BlameMichelson ( TRE 0.8.0 (BSD) ) MR-646709E3 +X-CRM114-CacheID: sfid-20210607_210745_712053_67A7D864 +X-CRM114-Status: GOOD ( 26.99 ) +X-Spam-Score: -0.8 (/) +X-Spam-Report: Spam detection software, + running on the system "bombadil.infradead.org", + has NOT identified this incoming email as spam. The original + message has been attached to this so you can view it or label + similar future email. If you have any questions, see + the administrator of that system for details. + Content preview: Do not prevent writing to mtd partitions where a partition + boundary sits on a minor erasesize boundary. This addresses a FIXME that + has been present since the start of the linux git history: /* Doesn' [...] + Content analysis details: (-0.8 points, 5.0 required) + pts rule name description + ---- ---------------------- + -------------------------------------------------- + -0.7 RCVD_IN_DNSWL_LOW RBL: Sender listed at https://www.dnswl.org/, + low trust [66.111.4.221 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) + [66.111.4.221 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: linux-mtd@lists.infradead.org +X-Mailman-Version: 2.1.34 +Precedence: list +List-Id: Linux MTD discussion mailing list +List-Unsubscribe: , + +List-Archive: +List-Post: +List-Help: +List-Subscribe: , + +Sender: "linux-mtd" +Errors-To: linux-mtd-bounces+incoming=patchwork.ozlabs.org@lists.infradead.org + +Do not prevent writing to mtd partitions where a partition boundary sits +on a minor erasesize boundary. +This addresses a FIXME that has been present since the start of the +linux git history: +/* 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 */ + +Allow a uniform erase region spi-nor device to be configured +to use the non-uniform erase regions code path for an erase with: +CONFIG_MTD_SPI_NOR_USE_VARIABLE_ERASE=y + +On supporting hardware (SECT_4K: majority of current SPI-NOR device) +provide the facility for an erase to use the least number +of SPI-NOR operations, as well as access to 4K erase without +requiring CONFIG_MTD_SPI_NOR_USE_4K_SECTORS + +Introduce erasesize_minor to the mtd struct, +the smallest erasesize supported by the device + +On existing devices, this is useful where write support is wanted +for data on a 4K partition, such as some u-boot-env partitions, +or RouterBoot soft_config, while still netting the performance +benefits of using 64K sectors + +Performance: +time mtd erase firmware +OpenWrt 5.10 ramips MT7621 w25q128jv 0xfc0000 partition length + +Without this patch +MTD_SPI_NOR_USE_4K_SECTORS=y |n +real 2m 11.66s |0m 50.86s +user 0m 0.00s |0m 0.00s +sys 1m 56.20s |0m 50.80s + +With this patch +MTD_SPI_NOR_USE_VARIABLE_ERASE=n|y |4K_SECTORS=y +real 0m 51.68s |0m 50.85s |2m 12.89s +user 0m 0.00s |0m 0.00s |0m 0.01s +sys 0m 46.94s |0m 50.38s |2m 12.46s + +Signed-off-by: John Thomson +--- +Have not tested on variable erase regions device. + +checkpatch does not like the printk(KERN_WARNING +these should be changed separately beforehand? + +Changes RFC -> v1: +Fix uninitialized variable smatch warning +Reported-by: kernel test robot +Reported-by: Dan Carpenter +--- + drivers/mtd/mtdpart.c | 52 ++++++++++++++++++++++++++++--------- + drivers/mtd/spi-nor/Kconfig | 10 +++++++ + drivers/mtd/spi-nor/core.c | 10 +++++-- + include/linux/mtd/mtd.h | 2 ++ + 4 files changed, 60 insertions(+), 14 deletions(-) + +diff --git a/drivers/mtd/mtdpart.c b/drivers/mtd/mtdpart.c +index 665fd9020b76..fe7626b5020e 100644 +--- a/drivers/mtd/mtdpart.c ++++ b/drivers/mtd/mtdpart.c +@@ -38,10 +38,11 @@ static struct mtd_info *allocate_partition(struct mtd_info *parent, + struct mtd_info *master = mtd_get_master(parent); + int wr_alignment = (parent->flags & MTD_NO_ERASE) ? + master->writesize : master->erasesize; ++ int wr_alignment_minor = 0; + u64 parent_size = mtd_is_partition(parent) ? + parent->part.size : parent->size; + struct mtd_info *child; +- u32 remainder; ++ u32 remainder, remainder_minor; + char *name; + u64 tmp; + +@@ -143,6 +144,7 @@ static struct mtd_info *allocate_partition(struct mtd_info *parent, + int i, max = parent->numeraseregions; + u64 end = child->part.offset + child->part.size; + struct mtd_erase_region_info *regions = parent->eraseregions; ++ uint32_t erasesize_minor = child->erasesize; + + /* Find the first erase regions which is part of this + * partition. */ +@@ -153,15 +155,24 @@ static struct mtd_info *allocate_partition(struct mtd_info *parent, + if (i > 0) + i--; + +- /* Pick biggest erasesize */ + for (; i < max && regions[i].offset < end; i++) { ++ /* Pick biggest erasesize */ + if (child->erasesize < regions[i].erasesize) + child->erasesize = regions[i].erasesize; ++ /* Pick smallest non-zero erasesize */ ++ if ((erasesize_minor > regions[i].erasesize) && (regions[i].erasesize > 0)) ++ erasesize_minor = regions[i].erasesize; + } ++ ++ if (erasesize_minor < child->erasesize) ++ child->erasesize_minor = erasesize_minor; ++ + BUG_ON(child->erasesize == 0); + } else { + /* Single erase size */ + child->erasesize = master->erasesize; ++ if (master->erasesize_minor) ++ child->erasesize_minor = master->erasesize_minor; + } + + /* +@@ -169,26 +180,43 @@ static struct mtd_info *allocate_partition(struct mtd_info *parent, + * exposes several regions with different erasesize. Adjust + * wr_alignment accordingly. + */ +- if (!(child->flags & MTD_NO_ERASE)) ++ if (!(child->flags & MTD_NO_ERASE)) { + wr_alignment = child->erasesize; ++ if (IS_ENABLED(CONFIG_MTD_SPI_NOR_USE_VARIABLE_ERASE) && child->erasesize_minor) ++ wr_alignment_minor = child->erasesize_minor; ++ } + + tmp = mtd_get_master_ofs(child, 0); + remainder = do_div(tmp, wr_alignment); + if ((child->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 */ +- child->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 (wr_alignment_minor) { ++ tmp = mtd_get_master_ofs(child, 0); ++ remainder_minor = do_div(tmp, wr_alignment_minor); ++ if (remainder_minor == 0) ++ child->erasesize = child->erasesize_minor; ++ } ++ ++ if ((!wr_alignment_minor) || (wr_alignment_minor && remainder_minor != 0)) { ++ child->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 = mtd_get_master_ofs(child, 0) + child->part.size; + remainder = do_div(tmp, wr_alignment); + if ((child->flags & MTD_WRITEABLE) && remainder) { +- child->flags &= ~MTD_WRITEABLE; +- printk(KERN_WARNING"mtd: partition \"%s\" doesn't end on an erase/write block -- force read-only\n", +- part->name); ++ if (wr_alignment_minor) { ++ tmp = mtd_get_master_ofs(child, 0) + child->part.size; ++ remainder_minor = do_div(tmp, wr_alignment_minor); ++ if (remainder_minor == 0) ++ child->erasesize = child->erasesize_minor; ++ } ++ if ((!wr_alignment_minor) || (wr_alignment_minor && remainder_minor != 0)) { ++ child->flags &= ~MTD_WRITEABLE; ++ printk(KERN_WARNING"mtd: partition \"%s\" doesn't end on an erase/write block -- force read-only\n", ++ part->name); ++ } + } + + child->size = child->part.size; +diff --git a/drivers/mtd/spi-nor/Kconfig b/drivers/mtd/spi-nor/Kconfig +index 24cd25de2b8b..09df9f1a8127 100644 +--- a/drivers/mtd/spi-nor/Kconfig ++++ b/drivers/mtd/spi-nor/Kconfig +@@ -10,6 +10,16 @@ menuconfig MTD_SPI_NOR + + if MTD_SPI_NOR + ++config MTD_SPI_NOR_USE_VARIABLE_ERASE ++ bool "Disable uniform_erase to allow use of all hardware supported erasesizes" ++ depends on !MTD_SPI_NOR_USE_4K_SECTORS ++ default n ++ help ++ Allow mixed use of all hardware supported erasesizes, ++ by forcing spi_nor to use the multiple eraseregions code path. ++ For example: A 68K erase will use one 64K erase, and one 4K erase ++ on supporting hardware. ++ + config MTD_SPI_NOR_USE_4K_SECTORS + bool "Use small 4096 B erase sectors" + default y +diff --git a/drivers/mtd/spi-nor/core.c b/drivers/mtd/spi-nor/core.c +index bd2c7717eb10..43d9b54e7edd 100644 +--- a/drivers/mtd/spi-nor/core.c ++++ b/drivers/mtd/spi-nor/core.c +@@ -1262,6 +1262,8 @@ static u8 spi_nor_convert_3to4_erase(u8 opcode) + + static bool spi_nor_has_uniform_erase(const struct spi_nor *nor) + { ++ if (IS_ENABLED(CONFIG_MTD_SPI_NOR_USE_VARIABLE_ERASE)) ++ return false; + return !!nor->params->erase_map.uniform_erase_type; + } + +@@ -2381,6 +2383,7 @@ static int spi_nor_select_erase(struct spi_nor *nor) + { + 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; +@@ -2413,8 +2416,9 @@ static int spi_nor_select_erase(struct spi_nor *nor) + */ + 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]; + } + } + +@@ -2422,6 +2426,8 @@ static int spi_nor_select_erase(struct spi_nor *nor) + return -EINVAL; + + mtd->erasesize = erase->size; ++ if (erase_minor && erase_minor->size < erase->size) ++ mtd->erasesize_minor = erase_minor->size; + return 0; + } + +diff --git a/include/linux/mtd/mtd.h b/include/linux/mtd/mtd.h +index a89955f3cbc8..33eafa27da50 100644 +--- a/include/linux/mtd/mtd.h ++++ b/include/linux/mtd/mtd.h +@@ -243,6 +243,8 @@ struct mtd_info { + * information below if they desire + */ + uint32_t erasesize; ++ /* "Minor" (smallest) 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 diff --git a/target/linux/ipq40xx/mikrotik/config-default b/target/linux/ipq40xx/mikrotik/config-default index 147217380c..dd0c69b748 100644 --- a/target/linux/ipq40xx/mikrotik/config-default +++ b/target/linux/ipq40xx/mikrotik/config-default @@ -2,3 +2,4 @@ CONFIG_MIKROTIK=y CONFIG_MIKROTIK_RB_SYSFS=y CONFIG_MTD_ROUTERBOOT_PARTS=y CONFIG_MTD_SPLIT_MINOR_FW=y +CONFIG_MTD_SPI_NOR_USE_VARIABLE_ERASE=y diff --git a/target/linux/ramips/mt7621/config-5.10 b/target/linux/ramips/mt7621/config-5.10 index 5b02cdfe79..67f7bf7e72 100644 --- a/target/linux/ramips/mt7621/config-5.10 +++ b/target/linux/ramips/mt7621/config-5.10 @@ -158,6 +158,7 @@ CONFIG_MTD_PHYSMAP=y CONFIG_MTD_RAW_NAND=y CONFIG_MTD_ROUTERBOOT_PARTS=y CONFIG_MTD_SPI_NOR=y +CONFIG_MTD_SPI_NOR_USE_VARIABLE_ERASE=y CONFIG_MTD_SPLIT_FIT_FW=y CONFIG_MTD_SPLIT_MINOR_FW=y CONFIG_MTD_SPLIT_SEAMA_FW=y From fdda3130f22bb9c716f66cda4e9ddde59e602145 Mon Sep 17 00:00:00 2001 From: Oskari Lemmela Date: Tue, 21 Dec 2021 09:46:01 +0200 Subject: [PATCH 06/29] mikrotik: make soft_config writable Parent mtd partition needs to be writable Signed-off-by: Oskari Lemmela --- target/linux/ath79/dts/ar9344_mikrotik_routerboard-sxt-5n.dtsi | 1 - target/linux/ath79/dts/qca9533_mikrotik_routerboard-16m.dtsi | 1 - .../ath79/dts/qca9556_mikrotik_routerboard-wap-g-5hact2hnd.dts | 1 - target/linux/ramips/dts/mt7621_mikrotik.dtsi | 1 - 4 files changed, 4 deletions(-) diff --git a/target/linux/ath79/dts/ar9344_mikrotik_routerboard-sxt-5n.dtsi b/target/linux/ath79/dts/ar9344_mikrotik_routerboard-sxt-5n.dtsi index 3ed50abefa..86136289de 100644 --- a/target/linux/ath79/dts/ar9344_mikrotik_routerboard-sxt-5n.dtsi +++ b/target/linux/ath79/dts/ar9344_mikrotik_routerboard-sxt-5n.dtsi @@ -99,7 +99,6 @@ partition@0 { label = "RouterBoot"; reg = <0x0 0x20000>; - read-only; compatible = "mikrotik,routerboot-partitions"; #address-cells = <1>; #size-cells = <1>; diff --git a/target/linux/ath79/dts/qca9533_mikrotik_routerboard-16m.dtsi b/target/linux/ath79/dts/qca9533_mikrotik_routerboard-16m.dtsi index f0473c7497..dbbe67d33d 100644 --- a/target/linux/ath79/dts/qca9533_mikrotik_routerboard-16m.dtsi +++ b/target/linux/ath79/dts/qca9533_mikrotik_routerboard-16m.dtsi @@ -38,7 +38,6 @@ partition@0 { label = "RouterBoot"; reg = <0x0 0x20000>; - read-only; compatible = "mikrotik,routerboot-partitions"; #address-cells = <1>; #size-cells = <1>; diff --git a/target/linux/ath79/dts/qca9556_mikrotik_routerboard-wap-g-5hact2hnd.dts b/target/linux/ath79/dts/qca9556_mikrotik_routerboard-wap-g-5hact2hnd.dts index f5c6731bb7..f6e04ae0a4 100644 --- a/target/linux/ath79/dts/qca9556_mikrotik_routerboard-wap-g-5hact2hnd.dts +++ b/target/linux/ath79/dts/qca9556_mikrotik_routerboard-wap-g-5hact2hnd.dts @@ -73,7 +73,6 @@ partition@0 { label = "RouterBoot"; reg = <0x0 0x20000>; - read-only; compatible = "mikrotik,routerboot-partitions"; #address-cells = <1>; #size-cells = <1>; diff --git a/target/linux/ramips/dts/mt7621_mikrotik.dtsi b/target/linux/ramips/dts/mt7621_mikrotik.dtsi index 1fc523ea14..ace194c6d6 100644 --- a/target/linux/ramips/dts/mt7621_mikrotik.dtsi +++ b/target/linux/ramips/dts/mt7621_mikrotik.dtsi @@ -37,7 +37,6 @@ partition@0 { label = "RouterBoot"; reg = <0x0 0x40000>; - read-only; compatible = "mikrotik,routerboot-partitions"; #address-cells = <1>; #size-cells = <1>; From 2a000546187122c86143c97337af4d5beacc4908 Mon Sep 17 00:00:00 2001 From: Koen Vandeputte Date: Wed, 12 Jan 2022 16:11:15 +0100 Subject: [PATCH 07/29] ath79: rb912: fix pll init issues It was reported that some rb912 boards (ar934x) have issues with some ethernet speeds. Investigation shows that the board failed to adapt the ethernet pll values as shown here: [ 5.284359] ag71xx 19000000.eth: failed to read pll-handle property added custom prints in code and triggering a link switch: [ 62.821446] Atheros AG71xx: fast reset [ 62.826442] Atheros AG71xx: update pll 2 [ 62.830494] Atheros AG71xx: no pll regmap! Comparison with another very similar board (rb922 - QCA955x) showed a missing reference clock frequency in dts, which seems to cause a pll init issue. Unfortunately, no errors are printed when this occurs. Adding the frequency property fixes the pll init as it can be parsed now by the ethernet driver. [ 55.861407] Atheros AG71xx: fast reset [ 55.866403] Atheros AG71xx: update pll 2 [ 55.870462] Atheros AG71xx: ath79_set_pllval: regmap: 0x81548000, pll_reg: 0x2c, pll_val: 0x02000000 Signed-off-by: Sergey Ryazanov Signed-off-by: Koen Vandeputte --- .../ath79/dts/ar9342_mikrotik_routerboard-912uag-2hpnd.dts | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/target/linux/ath79/dts/ar9342_mikrotik_routerboard-912uag-2hpnd.dts b/target/linux/ath79/dts/ar9342_mikrotik_routerboard-912uag-2hpnd.dts index ee2c12b4e0..14286ae8f7 100644 --- a/target/linux/ath79/dts/ar9342_mikrotik_routerboard-912uag-2hpnd.dts +++ b/target/linux/ath79/dts/ar9342_mikrotik_routerboard-912uag-2hpnd.dts @@ -127,6 +127,10 @@ }; }; +&ref { + clock-frequency = <25000000>; +}; + &spi { status = "okay"; From f11df6895606ea10feff0f5e5b69cf564a85d22b Mon Sep 17 00:00:00 2001 From: Koen Vandeputte Date: Wed, 13 Oct 2021 10:37:25 +0200 Subject: [PATCH 08/29] ath79: rb912: remove unused property ar934x does not define property 'rgmii-enabled' in the parsing code remove it Signed-off-by: Koen Vandeputte --- .../linux/ath79/dts/ar9342_mikrotik_routerboard-912uag-2hpnd.dts | 1 - 1 file changed, 1 deletion(-) diff --git a/target/linux/ath79/dts/ar9342_mikrotik_routerboard-912uag-2hpnd.dts b/target/linux/ath79/dts/ar9342_mikrotik_routerboard-912uag-2hpnd.dts index 14286ae8f7..77a0d29113 100644 --- a/target/linux/ath79/dts/ar9342_mikrotik_routerboard-912uag-2hpnd.dts +++ b/target/linux/ath79/dts/ar9342_mikrotik_routerboard-912uag-2hpnd.dts @@ -198,7 +198,6 @@ gmac-config { device = <&gmac>; rgmii-gmac0 = <1>; - rgmii-enabled = <1>; rxd-delay = <1>; txd-delay = <1>; }; From 9571d9d4b127622d8dd07b838d22b64e800dd23f Mon Sep 17 00:00:00 2001 From: Koen Vandeputte Date: Wed, 12 Jan 2022 15:25:55 +0100 Subject: [PATCH 09/29] ath79: qca955x: remove double declaration No need to mention the same value twice Signed-off-by: Koen Vandeputte --- target/linux/ath79/dts/qca955x.dtsi | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/target/linux/ath79/dts/qca955x.dtsi b/target/linux/ath79/dts/qca955x.dtsi index fb820169d5..b6e08f9f12 100644 --- a/target/linux/ath79/dts/qca955x.dtsi +++ b/target/linux/ath79/dts/qca955x.dtsi @@ -112,8 +112,7 @@ }; pll: pll-controller@18050000 { - compatible = "qca,qca9550-pll", - "qca,qca9550-pll", "syscon"; + compatible = "qca,qca9550-pll", "syscon"; reg = <0x18050000 0x50>; #clock-cells = <1>; From 2d19e6c6a42cbbd6ab53c4c673ba71303ef6a70b Mon Sep 17 00:00:00 2001 From: Denis Kalashnikov Date: Tue, 16 Nov 2021 19:06:44 +0300 Subject: [PATCH 10/29] generic: platform/mikrotik: use MTD notifier MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit If the SPI probe is sufficiently delayed, the routerboot driver may fail to init as the routerboot partitions are not yet available. Register an MTD user notifier instead of doing straight init so that the init subroutines are only executed when the target MTD partitions are present. Because the init/exit routines can now be called outside of the kernel normal init/exit calls, they cannot be jettisoned and must always be available: the __init and __exit qualifiers are thus removed. Reported-by: Denis Kalashnikov Signed-off-by: Denis Kalashnikov Signed-off-by: Thibaut VARĂˆNE Reviewed-by: Sergey Ryazanov [bump hardconfig/softconfig versions] Signed-off-by: Koen Vandeputte --- .../drivers/platform/mikrotik/rb_hardconfig.c | 18 +++---- .../drivers/platform/mikrotik/rb_softconfig.c | 18 +++---- .../drivers/platform/mikrotik/routerboot.c | 47 ++++++++++++++++--- .../drivers/platform/mikrotik/routerboot.h | 8 ++-- 4 files changed, 62 insertions(+), 29 deletions(-) diff --git a/target/linux/generic/files/drivers/platform/mikrotik/rb_hardconfig.c b/target/linux/generic/files/drivers/platform/mikrotik/rb_hardconfig.c index e6a6928896..bd0469d5e8 100644 --- a/target/linux/generic/files/drivers/platform/mikrotik/rb_hardconfig.c +++ b/target/linux/generic/files/drivers/platform/mikrotik/rb_hardconfig.c @@ -39,7 +39,7 @@ #include "routerboot.h" -#define RB_HARDCONFIG_VER "0.06" +#define RB_HARDCONFIG_VER "0.07" #define RB_HC_PR_PFX "[rb_hardconfig] " /* ID values for hardware settings */ @@ -676,10 +676,9 @@ static ssize_t hc_wlan_data_bin_read(struct file *filp, struct kobject *kobj, return count; } -int __init rb_hardconfig_init(struct kobject *rb_kobj) +int rb_hardconfig_init(struct kobject *rb_kobj, struct mtd_info *mtd) { struct kobject *hc_wlan_kobj; - struct mtd_info *mtd; size_t bytes_read, buflen, outlen; const u8 *buf; void *outbuf; @@ -690,20 +689,19 @@ int __init rb_hardconfig_init(struct kobject *rb_kobj) hc_kobj = NULL; hc_wlan_kobj = NULL; - // TODO allow override - mtd = get_mtd_device_nm(RB_MTD_HARD_CONFIG); - if (IS_ERR(mtd)) + ret = __get_mtd_device(mtd); + if (ret) return -ENODEV; hc_buflen = mtd->size; hc_buf = kmalloc(hc_buflen, GFP_KERNEL); if (!hc_buf) { - put_mtd_device(mtd); + __put_mtd_device(mtd); return -ENOMEM; } ret = mtd_read(mtd, 0, hc_buflen, &bytes_read, hc_buf); - put_mtd_device(mtd); + __put_mtd_device(mtd); if (ret) goto fail; @@ -818,8 +816,10 @@ fail: return ret; } -void __exit rb_hardconfig_exit(void) +void rb_hardconfig_exit(void) { kobject_put(hc_kobj); + hc_kobj = NULL; kfree(hc_buf); + hc_buf = NULL; } diff --git a/target/linux/generic/files/drivers/platform/mikrotik/rb_softconfig.c b/target/linux/generic/files/drivers/platform/mikrotik/rb_softconfig.c index 453e1347b2..5acff6aa91 100644 --- a/target/linux/generic/files/drivers/platform/mikrotik/rb_softconfig.c +++ b/target/linux/generic/files/drivers/platform/mikrotik/rb_softconfig.c @@ -56,7 +56,7 @@ #include "routerboot.h" -#define RB_SOFTCONFIG_VER "0.04" +#define RB_SOFTCONFIG_VER "0.05" #define RB_SC_PR_PFX "[rb_softconfig] " #define RB_SC_HAS_WRITE_SUPPORT true @@ -694,9 +694,8 @@ mtdfail: static struct kobj_attribute sc_kattrcommit = __ATTR(commit, RB_SC_RMODE|RB_SC_WMODE, sc_commit_show, sc_commit_store); -int __init rb_softconfig_init(struct kobject *rb_kobj) +int rb_softconfig_init(struct kobject *rb_kobj, struct mtd_info *mtd) { - struct mtd_info *mtd; size_t bytes_read, buflen; const u8 *buf; int i, ret; @@ -705,20 +704,19 @@ int __init rb_softconfig_init(struct kobject *rb_kobj) sc_buf = NULL; sc_kobj = NULL; - // TODO allow override - mtd = get_mtd_device_nm(RB_MTD_SOFT_CONFIG); - if (IS_ERR(mtd)) + ret = __get_mtd_device(mtd); + if (ret) return -ENODEV; sc_buflen = mtd->size; sc_buf = kmalloc(sc_buflen, GFP_KERNEL); if (!sc_buf) { - put_mtd_device(mtd); + __put_mtd_device(mtd); return -ENOMEM; } ret = mtd_read(mtd, 0, sc_buflen, &bytes_read, sc_buf); - put_mtd_device(mtd); + __put_mtd_device(mtd); if (ret) goto fail; @@ -788,8 +786,10 @@ fail: return ret; } -void __exit rb_softconfig_exit(void) +void rb_softconfig_exit(void) { kobject_put(sc_kobj); + sc_kobj = NULL; kfree(sc_buf); + sc_buf = NULL; } diff --git a/target/linux/generic/files/drivers/platform/mikrotik/routerboot.c b/target/linux/generic/files/drivers/platform/mikrotik/routerboot.c index 4c8c0bfac5..96f2460916 100644 --- a/target/linux/generic/files/drivers/platform/mikrotik/routerboot.c +++ b/target/linux/generic/files/drivers/platform/mikrotik/routerboot.c @@ -13,6 +13,7 @@ #include #include #include +#include #include "routerboot.h" @@ -160,25 +161,57 @@ fail: return ret; } +static void routerboot_mtd_notifier_add(struct mtd_info *mtd) +{ + /* Currently routerboot is only known to live on NOR flash */ + if (mtd->type != MTD_NORFLASH) + return; + + /* + * We ignore the following return values and always register. + * These init() routines are designed so that their failed state is + * always manageable by the corresponding exit() calls. + * Notifier is called with MTD mutex held: use __get/__put variants. + * TODO: allow partition names override + */ + if (!strcmp(mtd->name, RB_MTD_HARD_CONFIG)) + rb_hardconfig_init(rb_kobj, mtd); + else if (!strcmp(mtd->name, RB_MTD_SOFT_CONFIG)) + rb_softconfig_init(rb_kobj, mtd); +} + +static void routerboot_mtd_notifier_remove(struct mtd_info *mtd) +{ + if (mtd->type != MTD_NORFLASH) + return; + + if (!strcmp(mtd->name, RB_MTD_HARD_CONFIG)) + rb_hardconfig_exit(); + else if (!strcmp(mtd->name, RB_MTD_SOFT_CONFIG)) + rb_softconfig_exit(); +} + +/* Note: using a notifier prevents qualifying init()/exit() functions with __init/__exit */ +static struct mtd_notifier routerboot_mtd_notifier = { + .add = routerboot_mtd_notifier_add, + .remove = routerboot_mtd_notifier_remove, +}; + static int __init routerboot_init(void) { rb_kobj = kobject_create_and_add("mikrotik", firmware_kobj); if (!rb_kobj) return -ENOMEM; - /* - * We ignore the following return values and always register. - * These init() routines are designed so that their failed state is - * always manageable by the corresponding exit() calls. - */ - rb_hardconfig_init(rb_kobj); - rb_softconfig_init(rb_kobj); + register_mtd_user(&routerboot_mtd_notifier); return 0; } static void __exit routerboot_exit(void) { + unregister_mtd_user(&routerboot_mtd_notifier); + /* Exit routines are idempotent */ rb_softconfig_exit(); rb_hardconfig_exit(); kobject_put(rb_kobj); // recursive afaict diff --git a/target/linux/generic/files/drivers/platform/mikrotik/routerboot.h b/target/linux/generic/files/drivers/platform/mikrotik/routerboot.h index 67d89808d5..e858a524af 100644 --- a/target/linux/generic/files/drivers/platform/mikrotik/routerboot.h +++ b/target/linux/generic/files/drivers/platform/mikrotik/routerboot.h @@ -25,11 +25,11 @@ int routerboot_tag_find(const u8 *bufhead, const size_t buflen, const u16 tag_id, u16 *pld_ofs, u16 *pld_len); int routerboot_rle_decode(const u8 *in, size_t inlen, u8 *out, size_t *outlen); -int __init rb_hardconfig_init(struct kobject *rb_kobj); -void __exit rb_hardconfig_exit(void); +int rb_hardconfig_init(struct kobject *rb_kobj, struct mtd_info *mtd); +void rb_hardconfig_exit(void); -int __init rb_softconfig_init(struct kobject *rb_kobj); -void __exit rb_softconfig_exit(void); +int rb_softconfig_init(struct kobject *rb_kobj, struct mtd_info *mtd); +void rb_softconfig_exit(void); ssize_t routerboot_tag_show_string(const u8 *pld, u16 pld_len, char *buf); ssize_t routerboot_tag_show_u32s(const u8 *pld, u16 pld_len, char *buf); From bcf91fe8849bf4467637fd5570806837ba93dbd4 Mon Sep 17 00:00:00 2001 From: Felix Fietkau Date: Sun, 12 Dec 2021 07:25:41 +0100 Subject: [PATCH 11/29] kernel: move mediatek BMT support patch to generic patches Preparation for supporting BMT on MT7621. Move source files to the files/ subdirectory in order to simplify maintenance Signed-off-by: Felix Fietkau --- target/linux/generic/config-5.10 | 1 + .../generic/files/drivers/mtd/nand/mtk_bmt.c | 788 ++++++++++++++++ .../generic/files/include/linux/mtd/mtk_bmt.h | 18 + .../hack-5.10/430-mtk-bmt-support.patch | 23 + .../patches-5.10/330-mtk-bmt-support.patch | 871 ------------------ .../330-mtk-snand-bmt-support.patch | 36 + 6 files changed, 866 insertions(+), 871 deletions(-) create mode 100644 target/linux/generic/files/drivers/mtd/nand/mtk_bmt.c create mode 100644 target/linux/generic/files/include/linux/mtd/mtk_bmt.h create mode 100644 target/linux/generic/hack-5.10/430-mtk-bmt-support.patch delete mode 100644 target/linux/mediatek/patches-5.10/330-mtk-bmt-support.patch create mode 100644 target/linux/mediatek/patches-5.10/330-mtk-snand-bmt-support.patch diff --git a/target/linux/generic/config-5.10 b/target/linux/generic/config-5.10 index 714a0b9ec7..c9e44e11c2 100644 --- a/target/linux/generic/config-5.10 +++ b/target/linux/generic/config-5.10 @@ -3669,6 +3669,7 @@ CONFIG_MTD_SPLIT_SUPPORT=y # CONFIG_MTD_UBI_GLUEBI is not set # CONFIG_MTD_UIMAGE_SPLIT is not set # CONFIG_MTD_VIRT_CONCAT is not set +# CONFIG_MTD_NAND_MTK_BMT is not set # CONFIG_MTK_MMC is not set # CONFIG_MTK_MMSYS is not set CONFIG_MULTIUSER=y diff --git a/target/linux/generic/files/drivers/mtd/nand/mtk_bmt.c b/target/linux/generic/files/drivers/mtd/nand/mtk_bmt.c new file mode 100644 index 0000000000..f249f571c4 --- /dev/null +++ b/target/linux/generic/files/drivers/mtd/nand/mtk_bmt.c @@ -0,0 +1,788 @@ +/* + * Copyright (c) 2017 MediaTek Inc. + * Author: Xiangsheng Hou + * Copyright (c) 2020 Felix Fietkau + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#define MAIN_SIGNATURE_OFFSET 0 +#define OOB_SIGNATURE_OFFSET 1 +#define BBPOOL_RATIO 2 + +#define BBT_LOG(fmt, ...) pr_debug("[BBT][%s|%d] "fmt"\n", __func__, __LINE__, ##__VA_ARGS__) + +/* Maximum 8k blocks */ +#define BB_TABLE_MAX bmtd.table_size +#define BMT_TABLE_MAX (BB_TABLE_MAX * BBPOOL_RATIO / 100) +#define BMT_TBL_DEF_VAL 0x0 + +/* + * Burner Bad Block Table + * --------- Only support SLC Nand Chips!!!!!!!!!!! ---------- + */ + +struct bbbt { + char signature[3]; + /* This version is used to distinguish the legacy and new algorithm */ +#define BBMT_VERSION 2 + unsigned char version; + /* Below 2 tables will be written in SLC */ + u16 bb_tbl[]; +}; + +struct bbmt { + u16 block; +#define NO_MAPPED 0 +#define NORMAL_MAPPED 1 +#define BMT_MAPPED 2 + u16 mapped; +}; + +static struct bmt_desc { + struct mtd_info *mtd; + + int (*_read_oob) (struct mtd_info *mtd, loff_t from, + struct mtd_oob_ops *ops); + int (*_write_oob) (struct mtd_info *mtd, loff_t to, + struct mtd_oob_ops *ops); + int (*_erase) (struct mtd_info *mtd, struct erase_info *instr); + int (*_block_isbad) (struct mtd_info *mtd, loff_t ofs); + int (*_block_markbad) (struct mtd_info *mtd, loff_t ofs); + + struct bbbt *bbt; + + struct dentry *debugfs_dir; + + u32 table_size; + u32 pg_size; + u32 blk_size; + u16 pg_shift; + u16 blk_shift; + /* bbt logical address */ + u16 pool_lba; + /* bbt physical address */ + u16 pool_pba; + /* Maximum count of bad blocks that the vendor guaranteed */ + u16 bb_max; + /* Total blocks of the Nand Chip */ + u16 total_blks; + /* The block(n) BMT is located at (bmt_tbl[n]) */ + u16 bmt_blk_idx; + /* How many pages needs to store 'struct bbbt' */ + u32 bmt_pgs; + + /* to compensate for driver level remapping */ + u8 oob_offset; +} bmtd = {0}; + +static unsigned char *nand_bbt_buf; +static unsigned char *nand_data_buf; + +/* -------- Unit conversions -------- */ +static inline u32 blk_pg(u16 block) +{ + return (u32)(block << (bmtd.blk_shift - bmtd.pg_shift)); +} + +/* -------- Nand operations wrapper -------- */ +static inline int +bbt_nand_read(u32 page, unsigned char *dat, int dat_len, + unsigned char *fdm, int fdm_len) +{ + struct mtd_oob_ops ops = { + .mode = MTD_OPS_PLACE_OOB, + .ooboffs = bmtd.oob_offset, + .oobbuf = fdm, + .ooblen = fdm_len, + .datbuf = dat, + .len = dat_len, + }; + + return bmtd._read_oob(bmtd.mtd, page << bmtd.pg_shift, &ops); +} + +static inline int bbt_nand_erase(u16 block) +{ + struct mtd_info *mtd = bmtd.mtd; + struct erase_info instr = { + .addr = (loff_t)block << bmtd.blk_shift, + .len = bmtd.blk_size, + }; + + return bmtd._erase(mtd, &instr); +} + +/* -------- Bad Blocks Management -------- */ +static inline struct bbmt *bmt_tbl(struct bbbt *bbbt) +{ + return (struct bbmt *)&bbbt->bb_tbl[bmtd.table_size]; +} + +static int +read_bmt(u16 block, unsigned char *dat, unsigned char *fdm, int fdm_len) +{ + u32 len = bmtd.bmt_pgs << bmtd.pg_shift; + + return bbt_nand_read(blk_pg(block), dat, len, fdm, fdm_len); +} + +static int write_bmt(u16 block, unsigned char *dat) +{ + struct mtd_oob_ops ops = { + .mode = MTD_OPS_PLACE_OOB, + .ooboffs = OOB_SIGNATURE_OFFSET + bmtd.oob_offset, + .oobbuf = "bmt", + .ooblen = 3, + .datbuf = dat, + .len = bmtd.bmt_pgs << bmtd.pg_shift, + }; + loff_t addr = (loff_t)block << bmtd.blk_shift; + + return bmtd._write_oob(bmtd.mtd, addr, &ops); +} + +static u16 find_valid_block(u16 block) +{ + u8 fdm[4]; + int ret; + int loop = 0; + +retry: + if (block >= bmtd.total_blks) + return 0; + + ret = bbt_nand_read(blk_pg(block), nand_data_buf, bmtd.pg_size, + fdm, sizeof(fdm)); + /* Read the 1st byte of FDM to judge whether it's a bad + * or not + */ + if (ret || fdm[0] != 0xff) { + pr_info("nand: found bad block 0x%x\n", block); + if (loop >= bmtd.bb_max) { + pr_info("nand: FATAL ERR: too many bad blocks!!\n"); + return 0; + } + + loop++; + block++; + goto retry; + } + + return block; +} + +/* Find out all bad blocks, and fill in the mapping table */ +static int scan_bad_blocks(struct bbbt *bbt) +{ + int i; + u16 block = 0; + + /* First time download, the block0 MUST NOT be a bad block, + * this is guaranteed by vendor + */ + bbt->bb_tbl[0] = 0; + + /* + * Construct the mapping table of Normal data area(non-PMT/BMTPOOL) + * G - Good block; B - Bad block + * --------------------------- + * physical |G|G|B|G|B|B|G|G|G|G|B|G|B| + * --------------------------- + * What bb_tbl[i] looks like: + * physical block(i): + * 0 1 2 3 4 5 6 7 8 9 a b c + * mapped block(bb_tbl[i]): + * 0 1 3 6 7 8 9 b ...... + * ATTENTION: + * If new bad block ocurred(n), search bmt_tbl to find + * a available block(x), and fill in the bb_tbl[n] = x; + */ + for (i = 1; i < bmtd.pool_lba; i++) { + bbt->bb_tbl[i] = find_valid_block(bbt->bb_tbl[i - 1] + 1); + BBT_LOG("bb_tbl[0x%x] = 0x%x", i, bbt->bb_tbl[i]); + if (bbt->bb_tbl[i] == 0) + return -1; + } + + /* Physical Block start Address of BMT pool */ + bmtd.pool_pba = bbt->bb_tbl[i - 1] + 1; + if (bmtd.pool_pba >= bmtd.total_blks - 2) { + pr_info("nand: FATAL ERR: Too many bad blocks!!\n"); + return -1; + } + + BBT_LOG("pool_pba=0x%x", bmtd.pool_pba); + i = 0; + block = bmtd.pool_pba; + /* + * The bmt table is used for runtime bad block mapping + * G - Good block; B - Bad block + * --------------------------- + * physical |G|G|B|G|B|B|G|G|G|G|B|G|B| + * --------------------------- + * block: 0 1 2 3 4 5 6 7 8 9 a b c + * What bmt_tbl[i] looks like in initial state: + * i: + * 0 1 2 3 4 5 6 7 + * bmt_tbl[i].block: + * 0 1 3 6 7 8 9 b + * bmt_tbl[i].mapped: + * N N N N N N N B + * N - Not mapped(Available) + * M - Mapped + * B - BMT + * ATTENTION: + * BMT always in the last valid block in pool + */ + while ((block = find_valid_block(block)) != 0) { + bmt_tbl(bbt)[i].block = block; + bmt_tbl(bbt)[i].mapped = NO_MAPPED; + BBT_LOG("bmt_tbl[%d].block = 0x%x", i, block); + block++; + i++; + } + + /* i - How many available blocks in pool, which is the length of bmt_tbl[] + * bmtd.bmt_blk_idx - bmt_tbl[bmtd.bmt_blk_idx].block => the BMT block + */ + bmtd.bmt_blk_idx = i - 1; + bmt_tbl(bbt)[bmtd.bmt_blk_idx].mapped = BMT_MAPPED; + + if (i < 1) { + pr_info("nand: FATAL ERR: no space to store BMT!!\n"); + return -1; + } + + pr_info("[BBT] %d available blocks in BMT pool\n", i); + + return 0; +} + +static bool is_valid_bmt(unsigned char *buf, unsigned char *fdm) +{ + struct bbbt *bbt = (struct bbbt *)buf; + u8 *sig = (u8*)bbt->signature + MAIN_SIGNATURE_OFFSET; + + + if (memcmp(bbt->signature + MAIN_SIGNATURE_OFFSET, "BMT", 3) == 0 && + memcmp(fdm + OOB_SIGNATURE_OFFSET, "bmt", 3) == 0) { + if (bbt->version == BBMT_VERSION) + return true; + } + BBT_LOG("[BBT] BMT Version not match,upgrage preloader and uboot please! sig=%02x%02x%02x, fdm=%02x%02x%02x", + sig[0], sig[1], sig[2], + fdm[1], fdm[2], fdm[3]); + return false; +} + +static u16 get_bmt_index(struct bbmt *bmt) +{ + int i = 0; + + while (bmt[i].block != BMT_TBL_DEF_VAL) { + if (bmt[i].mapped == BMT_MAPPED) + return i; + i++; + } + return 0; +} + +static struct bbbt *scan_bmt(u16 block) +{ + u8 fdm[4]; + + if (block < bmtd.pool_lba) + return NULL; + + if (read_bmt(block, nand_bbt_buf, fdm, sizeof(fdm))) + return scan_bmt(block - 1); + + if (is_valid_bmt(nand_bbt_buf, fdm)) { + bmtd.bmt_blk_idx = get_bmt_index(bmt_tbl((struct bbbt *)nand_bbt_buf)); + if (bmtd.bmt_blk_idx == 0) { + pr_info("[BBT] FATAL ERR: bmt block index is wrong!\n"); + return NULL; + } + pr_info("[BBT] BMT.v2 is found at 0x%x\n", block); + return (struct bbbt *)nand_bbt_buf; + } else + return scan_bmt(block - 1); +} + +/* Write the Burner Bad Block Table to Nand Flash + * n - write BMT to bmt_tbl[n] + */ +static u16 upload_bmt(struct bbbt *bbt, int n) +{ + u16 block; + +retry: + if (n < 0 || bmt_tbl(bbt)[n].mapped == NORMAL_MAPPED) { + pr_info("nand: FATAL ERR: no space to store BMT!\n"); + return (u16)-1; + } + + block = bmt_tbl(bbt)[n].block; + BBT_LOG("n = 0x%x, block = 0x%x", n, block); + if (bbt_nand_erase(block)) { + bmt_tbl(bbt)[n].block = 0; + /* erase failed, try the previous block: bmt_tbl[n - 1].block */ + n--; + goto retry; + } + + /* The signature offset is fixed set to 0, + * oob signature offset is fixed set to 1 + */ + memcpy(bbt->signature + MAIN_SIGNATURE_OFFSET, "BMT", 3); + bbt->version = BBMT_VERSION; + + if (write_bmt(block, (unsigned char *)bbt)) { + bmt_tbl(bbt)[n].block = 0; + + /* write failed, try the previous block in bmt_tbl[n - 1] */ + n--; + goto retry; + } + + /* Return the current index(n) of BMT pool (bmt_tbl[n]) */ + return n; +} + +static u16 find_valid_block_in_pool(struct bbbt *bbt) +{ + int i; + + if (bmtd.bmt_blk_idx == 0) + goto error; + + for (i = 0; i < bmtd.bmt_blk_idx; i++) { + if (bmt_tbl(bbt)[i].block != 0 && bmt_tbl(bbt)[i].mapped == NO_MAPPED) { + bmt_tbl(bbt)[i].mapped = NORMAL_MAPPED; + return bmt_tbl(bbt)[i].block; + } + } + +error: + pr_info("nand: FATAL ERR: BMT pool is run out!\n"); + return 0; +} + +/* We met a bad block, mark it as bad and map it to a valid block in pool, + * if it's a write failure, we need to write the data to mapped block + */ +static bool update_bmt(u16 block) +{ + u16 mapped_blk; + struct bbbt *bbt; + + bbt = bmtd.bbt; + mapped_blk = find_valid_block_in_pool(bbt); + if (mapped_blk == 0) + return false; + + /* Map new bad block to available block in pool */ + bbt->bb_tbl[block] = mapped_blk; + bmtd.bmt_blk_idx = upload_bmt(bbt, bmtd.bmt_blk_idx); + + return true; +} + +u16 get_mapping_block_index(int block) +{ + int mapping_block; + + if (block < bmtd.pool_lba) + mapping_block = bmtd.bbt->bb_tbl[block]; + else + mapping_block = block; + BBT_LOG("0x%x mapped to 0x%x", block, mapping_block); + + return mapping_block; +} + +static int +mtk_bmt_read(struct mtd_info *mtd, loff_t from, + struct mtd_oob_ops *ops) +{ + struct mtd_oob_ops cur_ops = *ops; + int retry_count = 0; + loff_t cur_from; + int ret; + + ops->retlen = 0; + ops->oobretlen = 0; + + while (ops->retlen < ops->len || ops->oobretlen < ops->ooblen) { + u32 offset = from & (bmtd.blk_size - 1); + u32 block = from >> bmtd.blk_shift; + u32 cur_block; + + cur_block = get_mapping_block_index(block); + cur_from = ((loff_t)cur_block << bmtd.blk_shift) + offset; + + cur_ops.oobretlen = 0; + cur_ops.retlen = 0; + cur_ops.len = min_t(u32, mtd->erasesize - offset, + ops->len - ops->retlen); + ret = bmtd._read_oob(mtd, cur_from, &cur_ops); + if (ret < 0) { + update_bmt(block); + if (retry_count++ < 10) + continue; + + return ret; + } + + ops->retlen += cur_ops.retlen; + ops->oobretlen += cur_ops.oobretlen; + + cur_ops.ooboffs = 0; + cur_ops.datbuf += cur_ops.retlen; + cur_ops.oobbuf += cur_ops.oobretlen; + cur_ops.ooblen -= cur_ops.oobretlen; + + if (!cur_ops.len) + cur_ops.len = mtd->erasesize - offset; + + from += cur_ops.len; + retry_count = 0; + } + + return 0; +} + +static int +mtk_bmt_write(struct mtd_info *mtd, loff_t to, + struct mtd_oob_ops *ops) +{ + struct mtd_oob_ops cur_ops = *ops; + int retry_count = 0; + loff_t cur_to; + int ret; + + ops->retlen = 0; + ops->oobretlen = 0; + + while (ops->retlen < ops->len || ops->oobretlen < ops->ooblen) { + u32 offset = to & (bmtd.blk_size - 1); + u32 block = to >> bmtd.blk_shift; + u32 cur_block; + + cur_block = get_mapping_block_index(block); + cur_to = ((loff_t)cur_block << bmtd.blk_shift) + offset; + + cur_ops.oobretlen = 0; + cur_ops.retlen = 0; + cur_ops.len = min_t(u32, bmtd.blk_size - offset, + ops->len - ops->retlen); + ret = bmtd._write_oob(mtd, cur_to, &cur_ops); + if (ret < 0) { + update_bmt(block); + if (retry_count++ < 10) + continue; + + return ret; + } + + ops->retlen += cur_ops.retlen; + ops->oobretlen += cur_ops.oobretlen; + + cur_ops.ooboffs = 0; + cur_ops.datbuf += cur_ops.retlen; + cur_ops.oobbuf += cur_ops.oobretlen; + cur_ops.ooblen -= cur_ops.oobretlen; + + if (!cur_ops.len) + cur_ops.len = mtd->erasesize - offset; + + to += cur_ops.len; + retry_count = 0; + } + + return 0; +} + +static int +mtk_bmt_mtd_erase(struct mtd_info *mtd, struct erase_info *instr) +{ + struct erase_info mapped_instr = { + .len = bmtd.blk_size, + }; + int retry_count = 0; + u64 start_addr, end_addr; + int ret; + u16 orig_block, block; + + start_addr = instr->addr & (~mtd->erasesize_mask); + end_addr = instr->addr + instr->len; + + while (start_addr < end_addr) { + orig_block = start_addr >> bmtd.blk_shift; + block = get_mapping_block_index(orig_block); + mapped_instr.addr = (loff_t)block << bmtd.blk_shift; + ret = bmtd._erase(mtd, &mapped_instr); + if (ret) { + update_bmt(orig_block); + if (retry_count++ < 10) + continue; + instr->fail_addr = start_addr; + break; + } + start_addr += mtd->erasesize; + retry_count = 0; + } + + return ret; +} +static int +mtk_bmt_block_isbad(struct mtd_info *mtd, loff_t ofs) +{ + int retry_count = 0; + u16 orig_block = ofs >> bmtd.blk_shift; + u16 block; + int ret; + +retry: + block = get_mapping_block_index(orig_block); + ret = bmtd._block_isbad(mtd, (loff_t)block << bmtd.blk_shift); + if (ret) { + update_bmt(orig_block); + if (retry_count++ < 10) + goto retry; + } + return ret; +} + +static int +mtk_bmt_block_markbad(struct mtd_info *mtd, loff_t ofs) +{ + u16 orig_block = ofs >> bmtd.blk_shift; + u16 block = get_mapping_block_index(orig_block); + update_bmt(orig_block); + return bmtd._block_markbad(mtd, (loff_t)block << bmtd.blk_shift); +} + +static void +mtk_bmt_replace_ops(struct mtd_info *mtd) +{ + bmtd._read_oob = mtd->_read_oob; + bmtd._write_oob = mtd->_write_oob; + bmtd._erase = mtd->_erase; + bmtd._block_isbad = mtd->_block_isbad; + bmtd._block_markbad = mtd->_block_markbad; + + mtd->_read_oob = mtk_bmt_read; + mtd->_write_oob = mtk_bmt_write; + mtd->_erase = mtk_bmt_mtd_erase; + mtd->_block_isbad = mtk_bmt_block_isbad; + mtd->_block_markbad = mtk_bmt_block_markbad; +} + +static int mtk_bmt_debug_mark_good(void *data, u64 val) +{ + u32 block = val >> bmtd.blk_shift; + + bmtd.bbt->bb_tbl[block] = block; + bmtd.bmt_blk_idx = upload_bmt(bmtd.bbt, bmtd.bmt_blk_idx); + + return 0; +} + +static int mtk_bmt_debug_mark_bad(void *data, u64 val) +{ + u32 block = val >> bmtd.blk_shift; + + update_bmt(block); + + return 0; +} + +DEFINE_DEBUGFS_ATTRIBUTE(fops_mark_good, NULL, mtk_bmt_debug_mark_good, "%llu\n"); +DEFINE_DEBUGFS_ATTRIBUTE(fops_mark_bad, NULL, mtk_bmt_debug_mark_bad, "%llu\n"); + +static void +mtk_bmt_add_debugfs(void) +{ + struct dentry *dir; + + dir = bmtd.debugfs_dir = debugfs_create_dir("mtk-bmt", NULL); + if (!dir) + return; + + debugfs_create_file_unsafe("mark_good", S_IWUSR, dir, NULL, &fops_mark_good); + debugfs_create_file_unsafe("mark_bad", S_IWUSR, dir, NULL, &fops_mark_bad); +} + +void mtk_bmt_detach(struct mtd_info *mtd) +{ + if (bmtd.mtd != mtd) + return; + + if (bmtd.debugfs_dir) + debugfs_remove_recursive(bmtd.debugfs_dir); + bmtd.debugfs_dir = NULL; + + kfree(nand_bbt_buf); + kfree(nand_data_buf); + + mtd->_read_oob = bmtd._read_oob; + mtd->_write_oob = bmtd._write_oob; + mtd->_erase = bmtd._erase; + mtd->_block_isbad = bmtd._block_isbad; + mtd->_block_markbad = bmtd._block_markbad; + mtd->size = bmtd.total_blks << bmtd.blk_shift; + + memset(&bmtd, 0, sizeof(bmtd)); +} + +/* total_blocks - The total count of blocks that the Nand Chip has */ +int mtk_bmt_attach(struct mtd_info *mtd) +{ + struct device_node *np; + struct bbbt *bbt; + u32 bufsz; + u32 block; + u16 total_blocks, pmt_block; + int ret = 0; + u32 bmt_pool_size, bmt_table_size; + + if (bmtd.mtd) + return -ENOSPC; + + np = mtd_get_of_node(mtd); + if (!np) + return 0; + + if (!of_property_read_bool(np, "mediatek,bmt-v2")) + return 0; + + if (of_property_read_u32(np, "mediatek,bmt-pool-size", + &bmt_pool_size) != 0) + bmt_pool_size = 80; + + if (of_property_read_u8(np, "mediatek,bmt-oob-offset", + &bmtd.oob_offset) != 0) + bmtd.oob_offset = 0; + + if (of_property_read_u32(np, "mediatek,bmt-table-size", + &bmt_table_size) != 0) + bmt_table_size = 0x2000U; + + bmtd.mtd = mtd; + mtk_bmt_replace_ops(mtd); + + bmtd.table_size = bmt_table_size; + bmtd.blk_size = mtd->erasesize; + bmtd.blk_shift = ffs(bmtd.blk_size) - 1; + bmtd.pg_size = mtd->writesize; + bmtd.pg_shift = ffs(bmtd.pg_size) - 1; + total_blocks = mtd->size >> bmtd.blk_shift; + pmt_block = total_blocks - bmt_pool_size - 2; + + mtd->size = pmt_block << bmtd.blk_shift; + + /* + * --------------------------------------- + * | PMT(2blks) | BMT POOL(totalblks * 2%) | + * --------------------------------------- + * ^ ^ + * | | + * pmt_block pmt_block + 2blocks(pool_lba) + * + * ATTETION!!!!!! + * The blocks ahead of the boundary block are stored in bb_tbl + * and blocks behind are stored in bmt_tbl + */ + + bmtd.pool_lba = (u16)(pmt_block + 2); + bmtd.total_blks = total_blocks; + bmtd.bb_max = bmtd.total_blks * BBPOOL_RATIO / 100; + + /* 3 buffers we need */ + bufsz = round_up(sizeof(struct bbbt) + + bmt_table_size * sizeof(struct bbmt), bmtd.pg_size); + bmtd.bmt_pgs = bufsz >> bmtd.pg_shift; + + nand_bbt_buf = kzalloc(bufsz, GFP_KERNEL); + nand_data_buf = kzalloc(bmtd.pg_size, GFP_KERNEL); + + if (!nand_bbt_buf || !nand_data_buf) { + pr_info("nand: FATAL ERR: allocate buffer failed!\n"); + ret = -1; + goto error; + } + + memset(nand_bbt_buf, 0xff, bufsz); + memset(nand_data_buf, 0xff, bmtd.pg_size); + + BBT_LOG("bbtbuf=0x%p(0x%x) dat=0x%p(0x%x)", + nand_bbt_buf, bufsz, nand_data_buf, bmtd.pg_size); + BBT_LOG("pool_lba=0x%x total_blks=0x%x bb_max=0x%x", + bmtd.pool_lba, bmtd.total_blks, bmtd.bb_max); + + /* Scanning start from the first page of the last block + * of whole flash + */ + bbt = scan_bmt(bmtd.total_blks - 1); + if (!bbt) { + /* BMT not found */ + if (bmtd.total_blks > BB_TABLE_MAX + BMT_TABLE_MAX) { + pr_info("nand: FATAL: Too many blocks, can not support!\n"); + ret = -1; + goto error; + } + + bbt = (struct bbbt *)nand_bbt_buf; + memset(bmt_tbl(bbt), BMT_TBL_DEF_VAL, bmtd.table_size * sizeof(struct bbmt)); + + if (scan_bad_blocks(bbt)) { + ret = -1; + goto error; + } + + /* BMT always in the last valid block in pool */ + bmtd.bmt_blk_idx = upload_bmt(bbt, bmtd.bmt_blk_idx); + block = bmt_tbl(bbt)[bmtd.bmt_blk_idx].block; + pr_notice("[BBT] BMT.v2 is written into PBA:0x%x\n", block); + + if (bmtd.bmt_blk_idx == 0) + pr_info("nand: Warning: no available block in BMT pool!\n"); + else if (bmtd.bmt_blk_idx == (u16)-1) { + ret = -1; + goto error; + } + } + mtk_bmt_add_debugfs(); + + bmtd.bbt = bbt; + return 0; + +error: + mtk_bmt_detach(mtd); + return ret; +} + + +MODULE_LICENSE("GPL"); +MODULE_AUTHOR("Xiangsheng Hou , Felix Fietkau "); +MODULE_DESCRIPTION("Bad Block mapping management v2 for MediaTek NAND Flash Driver"); + diff --git a/target/linux/generic/files/include/linux/mtd/mtk_bmt.h b/target/linux/generic/files/include/linux/mtd/mtk_bmt.h new file mode 100644 index 0000000000..cbb6d04d89 --- /dev/null +++ b/target/linux/generic/files/include/linux/mtd/mtk_bmt.h @@ -0,0 +1,18 @@ +#ifndef __MTK_BMT_H +#define __MTK_BMT_H + +#ifdef CONFIG_MTD_NAND_MTK_BMT +int mtk_bmt_attach(struct mtd_info *mtd); +void mtk_bmt_detach(struct mtd_info *mtd); +#else +static inline int mtk_bmt_attach(struct mtd_info *mtd) +{ + return 0; +} + +static inline void mtk_bmt_detach(struct mtd_info *mtd) +{ +} +#endif + +#endif diff --git a/target/linux/generic/hack-5.10/430-mtk-bmt-support.patch b/target/linux/generic/hack-5.10/430-mtk-bmt-support.patch new file mode 100644 index 0000000000..749dcb8356 --- /dev/null +++ b/target/linux/generic/hack-5.10/430-mtk-bmt-support.patch @@ -0,0 +1,23 @@ +--- a/drivers/mtd/nand/Kconfig ++++ b/drivers/mtd/nand/Kconfig +@@ -15,6 +15,10 @@ config MTD_NAND_ECC + bool + depends on MTD_NAND_CORE + ++config MTD_NAND_MTK_BMT ++ bool "Support MediaTek NAND Bad-block Management Table" ++ default n ++ + endmenu + + endmenu +--- a/drivers/mtd/nand/Makefile ++++ b/drivers/mtd/nand/Makefile +@@ -2,6 +2,7 @@ + + nandcore-objs := core.o bbt.o + obj-$(CONFIG_MTD_NAND_CORE) += nandcore.o ++obj-$(CONFIG_MTD_NAND_MTK_BMT) += mtk_bmt.o + + obj-y += onenand/ + obj-y += raw/ diff --git a/target/linux/mediatek/patches-5.10/330-mtk-bmt-support.patch b/target/linux/mediatek/patches-5.10/330-mtk-bmt-support.patch deleted file mode 100644 index bf70fb75b9..0000000000 --- a/target/linux/mediatek/patches-5.10/330-mtk-bmt-support.patch +++ /dev/null @@ -1,871 +0,0 @@ ---- a/drivers/mtd/nand/Kconfig -+++ b/drivers/mtd/nand/Kconfig -@@ -15,6 +15,10 @@ config MTD_NAND_ECC - bool - depends on MTD_NAND_CORE - -+config MTD_NAND_MTK_BMT -+ bool "Support MediaTek NAND Bad-block Management Table" -+ default n -+ - endmenu - - endmenu ---- a/drivers/mtd/nand/Makefile -+++ b/drivers/mtd/nand/Makefile -@@ -2,6 +2,7 @@ - - nandcore-objs := core.o bbt.o - obj-$(CONFIG_MTD_NAND_CORE) += nandcore.o -+obj-$(CONFIG_MTD_NAND_MTK_BMT) += mtk_bmt.o - - obj-y += onenand/ - obj-y += raw/ ---- /dev/null -+++ b/drivers/mtd/nand/mtk_bmt.c -@@ -0,0 +1,788 @@ -+/* -+ * Copyright (c) 2017 MediaTek Inc. -+ * Author: Xiangsheng Hou -+ * Copyright (c) 2020 Felix Fietkau -+ * -+ * This program is free software; you can redistribute it and/or modify -+ * it under the terms of the GNU General Public License version 2 as -+ * published by the Free Software Foundation. -+ * -+ * This program is distributed in the hope that it will be useful, -+ * but WITHOUT ANY WARRANTY; without even the implied warranty of -+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -+ * GNU General Public License for more details. -+ */ -+ -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+ -+#define MAIN_SIGNATURE_OFFSET 0 -+#define OOB_SIGNATURE_OFFSET 1 -+#define BBPOOL_RATIO 2 -+ -+#define BBT_LOG(fmt, ...) pr_debug("[BBT][%s|%d] "fmt"\n", __func__, __LINE__, ##__VA_ARGS__) -+ -+/* Maximum 8k blocks */ -+#define BB_TABLE_MAX bmtd.table_size -+#define BMT_TABLE_MAX (BB_TABLE_MAX * BBPOOL_RATIO / 100) -+#define BMT_TBL_DEF_VAL 0x0 -+ -+/* -+ * Burner Bad Block Table -+ * --------- Only support SLC Nand Chips!!!!!!!!!!! ---------- -+ */ -+ -+struct bbbt { -+ char signature[3]; -+ /* This version is used to distinguish the legacy and new algorithm */ -+#define BBMT_VERSION 2 -+ unsigned char version; -+ /* Below 2 tables will be written in SLC */ -+ u16 bb_tbl[]; -+}; -+ -+struct bbmt { -+ u16 block; -+#define NO_MAPPED 0 -+#define NORMAL_MAPPED 1 -+#define BMT_MAPPED 2 -+ u16 mapped; -+}; -+ -+static struct bmt_desc { -+ struct mtd_info *mtd; -+ -+ int (*_read_oob) (struct mtd_info *mtd, loff_t from, -+ struct mtd_oob_ops *ops); -+ int (*_write_oob) (struct mtd_info *mtd, loff_t to, -+ struct mtd_oob_ops *ops); -+ int (*_erase) (struct mtd_info *mtd, struct erase_info *instr); -+ int (*_block_isbad) (struct mtd_info *mtd, loff_t ofs); -+ int (*_block_markbad) (struct mtd_info *mtd, loff_t ofs); -+ -+ struct bbbt *bbt; -+ -+ struct dentry *debugfs_dir; -+ -+ u32 table_size; -+ u32 pg_size; -+ u32 blk_size; -+ u16 pg_shift; -+ u16 blk_shift; -+ /* bbt logical address */ -+ u16 pool_lba; -+ /* bbt physical address */ -+ u16 pool_pba; -+ /* Maximum count of bad blocks that the vendor guaranteed */ -+ u16 bb_max; -+ /* Total blocks of the Nand Chip */ -+ u16 total_blks; -+ /* The block(n) BMT is located at (bmt_tbl[n]) */ -+ u16 bmt_blk_idx; -+ /* How many pages needs to store 'struct bbbt' */ -+ u32 bmt_pgs; -+ -+ /* to compensate for driver level remapping */ -+ u8 oob_offset; -+} bmtd = {0}; -+ -+static unsigned char *nand_bbt_buf; -+static unsigned char *nand_data_buf; -+ -+/* -------- Unit conversions -------- */ -+static inline u32 blk_pg(u16 block) -+{ -+ return (u32)(block << (bmtd.blk_shift - bmtd.pg_shift)); -+} -+ -+/* -------- Nand operations wrapper -------- */ -+static inline int -+bbt_nand_read(u32 page, unsigned char *dat, int dat_len, -+ unsigned char *fdm, int fdm_len) -+{ -+ struct mtd_oob_ops ops = { -+ .mode = MTD_OPS_PLACE_OOB, -+ .ooboffs = bmtd.oob_offset, -+ .oobbuf = fdm, -+ .ooblen = fdm_len, -+ .datbuf = dat, -+ .len = dat_len, -+ }; -+ -+ return bmtd._read_oob(bmtd.mtd, page << bmtd.pg_shift, &ops); -+} -+ -+static inline int bbt_nand_erase(u16 block) -+{ -+ struct mtd_info *mtd = bmtd.mtd; -+ struct erase_info instr = { -+ .addr = (loff_t)block << bmtd.blk_shift, -+ .len = bmtd.blk_size, -+ }; -+ -+ return bmtd._erase(mtd, &instr); -+} -+ -+/* -------- Bad Blocks Management -------- */ -+static inline struct bbmt *bmt_tbl(struct bbbt *bbbt) -+{ -+ return (struct bbmt *)&bbbt->bb_tbl[bmtd.table_size]; -+} -+ -+static int -+read_bmt(u16 block, unsigned char *dat, unsigned char *fdm, int fdm_len) -+{ -+ u32 len = bmtd.bmt_pgs << bmtd.pg_shift; -+ -+ return bbt_nand_read(blk_pg(block), dat, len, fdm, fdm_len); -+} -+ -+static int write_bmt(u16 block, unsigned char *dat) -+{ -+ struct mtd_oob_ops ops = { -+ .mode = MTD_OPS_PLACE_OOB, -+ .ooboffs = OOB_SIGNATURE_OFFSET + bmtd.oob_offset, -+ .oobbuf = "bmt", -+ .ooblen = 3, -+ .datbuf = dat, -+ .len = bmtd.bmt_pgs << bmtd.pg_shift, -+ }; -+ loff_t addr = (loff_t)block << bmtd.blk_shift; -+ -+ return bmtd._write_oob(bmtd.mtd, addr, &ops); -+} -+ -+static u16 find_valid_block(u16 block) -+{ -+ u8 fdm[4]; -+ int ret; -+ int loop = 0; -+ -+retry: -+ if (block >= bmtd.total_blks) -+ return 0; -+ -+ ret = bbt_nand_read(blk_pg(block), nand_data_buf, bmtd.pg_size, -+ fdm, sizeof(fdm)); -+ /* Read the 1st byte of FDM to judge whether it's a bad -+ * or not -+ */ -+ if (ret || fdm[0] != 0xff) { -+ pr_info("nand: found bad block 0x%x\n", block); -+ if (loop >= bmtd.bb_max) { -+ pr_info("nand: FATAL ERR: too many bad blocks!!\n"); -+ return 0; -+ } -+ -+ loop++; -+ block++; -+ goto retry; -+ } -+ -+ return block; -+} -+ -+/* Find out all bad blocks, and fill in the mapping table */ -+static int scan_bad_blocks(struct bbbt *bbt) -+{ -+ int i; -+ u16 block = 0; -+ -+ /* First time download, the block0 MUST NOT be a bad block, -+ * this is guaranteed by vendor -+ */ -+ bbt->bb_tbl[0] = 0; -+ -+ /* -+ * Construct the mapping table of Normal data area(non-PMT/BMTPOOL) -+ * G - Good block; B - Bad block -+ * --------------------------- -+ * physical |G|G|B|G|B|B|G|G|G|G|B|G|B| -+ * --------------------------- -+ * What bb_tbl[i] looks like: -+ * physical block(i): -+ * 0 1 2 3 4 5 6 7 8 9 a b c -+ * mapped block(bb_tbl[i]): -+ * 0 1 3 6 7 8 9 b ...... -+ * ATTENTION: -+ * If new bad block ocurred(n), search bmt_tbl to find -+ * a available block(x), and fill in the bb_tbl[n] = x; -+ */ -+ for (i = 1; i < bmtd.pool_lba; i++) { -+ bbt->bb_tbl[i] = find_valid_block(bbt->bb_tbl[i - 1] + 1); -+ BBT_LOG("bb_tbl[0x%x] = 0x%x", i, bbt->bb_tbl[i]); -+ if (bbt->bb_tbl[i] == 0) -+ return -1; -+ } -+ -+ /* Physical Block start Address of BMT pool */ -+ bmtd.pool_pba = bbt->bb_tbl[i - 1] + 1; -+ if (bmtd.pool_pba >= bmtd.total_blks - 2) { -+ pr_info("nand: FATAL ERR: Too many bad blocks!!\n"); -+ return -1; -+ } -+ -+ BBT_LOG("pool_pba=0x%x", bmtd.pool_pba); -+ i = 0; -+ block = bmtd.pool_pba; -+ /* -+ * The bmt table is used for runtime bad block mapping -+ * G - Good block; B - Bad block -+ * --------------------------- -+ * physical |G|G|B|G|B|B|G|G|G|G|B|G|B| -+ * --------------------------- -+ * block: 0 1 2 3 4 5 6 7 8 9 a b c -+ * What bmt_tbl[i] looks like in initial state: -+ * i: -+ * 0 1 2 3 4 5 6 7 -+ * bmt_tbl[i].block: -+ * 0 1 3 6 7 8 9 b -+ * bmt_tbl[i].mapped: -+ * N N N N N N N B -+ * N - Not mapped(Available) -+ * M - Mapped -+ * B - BMT -+ * ATTENTION: -+ * BMT always in the last valid block in pool -+ */ -+ while ((block = find_valid_block(block)) != 0) { -+ bmt_tbl(bbt)[i].block = block; -+ bmt_tbl(bbt)[i].mapped = NO_MAPPED; -+ BBT_LOG("bmt_tbl[%d].block = 0x%x", i, block); -+ block++; -+ i++; -+ } -+ -+ /* i - How many available blocks in pool, which is the length of bmt_tbl[] -+ * bmtd.bmt_blk_idx - bmt_tbl[bmtd.bmt_blk_idx].block => the BMT block -+ */ -+ bmtd.bmt_blk_idx = i - 1; -+ bmt_tbl(bbt)[bmtd.bmt_blk_idx].mapped = BMT_MAPPED; -+ -+ if (i < 1) { -+ pr_info("nand: FATAL ERR: no space to store BMT!!\n"); -+ return -1; -+ } -+ -+ pr_info("[BBT] %d available blocks in BMT pool\n", i); -+ -+ return 0; -+} -+ -+static bool is_valid_bmt(unsigned char *buf, unsigned char *fdm) -+{ -+ struct bbbt *bbt = (struct bbbt *)buf; -+ u8 *sig = (u8*)bbt->signature + MAIN_SIGNATURE_OFFSET; -+ -+ -+ if (memcmp(bbt->signature + MAIN_SIGNATURE_OFFSET, "BMT", 3) == 0 && -+ memcmp(fdm + OOB_SIGNATURE_OFFSET, "bmt", 3) == 0) { -+ if (bbt->version == BBMT_VERSION) -+ return true; -+ } -+ BBT_LOG("[BBT] BMT Version not match,upgrage preloader and uboot please! sig=%02x%02x%02x, fdm=%02x%02x%02x", -+ sig[0], sig[1], sig[2], -+ fdm[1], fdm[2], fdm[3]); -+ return false; -+} -+ -+static u16 get_bmt_index(struct bbmt *bmt) -+{ -+ int i = 0; -+ -+ while (bmt[i].block != BMT_TBL_DEF_VAL) { -+ if (bmt[i].mapped == BMT_MAPPED) -+ return i; -+ i++; -+ } -+ return 0; -+} -+ -+static struct bbbt *scan_bmt(u16 block) -+{ -+ u8 fdm[4]; -+ -+ if (block < bmtd.pool_lba) -+ return NULL; -+ -+ if (read_bmt(block, nand_bbt_buf, fdm, sizeof(fdm))) -+ return scan_bmt(block - 1); -+ -+ if (is_valid_bmt(nand_bbt_buf, fdm)) { -+ bmtd.bmt_blk_idx = get_bmt_index(bmt_tbl((struct bbbt *)nand_bbt_buf)); -+ if (bmtd.bmt_blk_idx == 0) { -+ pr_info("[BBT] FATAL ERR: bmt block index is wrong!\n"); -+ return NULL; -+ } -+ pr_info("[BBT] BMT.v2 is found at 0x%x\n", block); -+ return (struct bbbt *)nand_bbt_buf; -+ } else -+ return scan_bmt(block - 1); -+} -+ -+/* Write the Burner Bad Block Table to Nand Flash -+ * n - write BMT to bmt_tbl[n] -+ */ -+static u16 upload_bmt(struct bbbt *bbt, int n) -+{ -+ u16 block; -+ -+retry: -+ if (n < 0 || bmt_tbl(bbt)[n].mapped == NORMAL_MAPPED) { -+ pr_info("nand: FATAL ERR: no space to store BMT!\n"); -+ return (u16)-1; -+ } -+ -+ block = bmt_tbl(bbt)[n].block; -+ BBT_LOG("n = 0x%x, block = 0x%x", n, block); -+ if (bbt_nand_erase(block)) { -+ bmt_tbl(bbt)[n].block = 0; -+ /* erase failed, try the previous block: bmt_tbl[n - 1].block */ -+ n--; -+ goto retry; -+ } -+ -+ /* The signature offset is fixed set to 0, -+ * oob signature offset is fixed set to 1 -+ */ -+ memcpy(bbt->signature + MAIN_SIGNATURE_OFFSET, "BMT", 3); -+ bbt->version = BBMT_VERSION; -+ -+ if (write_bmt(block, (unsigned char *)bbt)) { -+ bmt_tbl(bbt)[n].block = 0; -+ -+ /* write failed, try the previous block in bmt_tbl[n - 1] */ -+ n--; -+ goto retry; -+ } -+ -+ /* Return the current index(n) of BMT pool (bmt_tbl[n]) */ -+ return n; -+} -+ -+static u16 find_valid_block_in_pool(struct bbbt *bbt) -+{ -+ int i; -+ -+ if (bmtd.bmt_blk_idx == 0) -+ goto error; -+ -+ for (i = 0; i < bmtd.bmt_blk_idx; i++) { -+ if (bmt_tbl(bbt)[i].block != 0 && bmt_tbl(bbt)[i].mapped == NO_MAPPED) { -+ bmt_tbl(bbt)[i].mapped = NORMAL_MAPPED; -+ return bmt_tbl(bbt)[i].block; -+ } -+ } -+ -+error: -+ pr_info("nand: FATAL ERR: BMT pool is run out!\n"); -+ return 0; -+} -+ -+/* We met a bad block, mark it as bad and map it to a valid block in pool, -+ * if it's a write failure, we need to write the data to mapped block -+ */ -+static bool update_bmt(u16 block) -+{ -+ u16 mapped_blk; -+ struct bbbt *bbt; -+ -+ bbt = bmtd.bbt; -+ mapped_blk = find_valid_block_in_pool(bbt); -+ if (mapped_blk == 0) -+ return false; -+ -+ /* Map new bad block to available block in pool */ -+ bbt->bb_tbl[block] = mapped_blk; -+ bmtd.bmt_blk_idx = upload_bmt(bbt, bmtd.bmt_blk_idx); -+ -+ return true; -+} -+ -+u16 get_mapping_block_index(int block) -+{ -+ int mapping_block; -+ -+ if (block < bmtd.pool_lba) -+ mapping_block = bmtd.bbt->bb_tbl[block]; -+ else -+ mapping_block = block; -+ BBT_LOG("0x%x mapped to 0x%x", block, mapping_block); -+ -+ return mapping_block; -+} -+ -+static int -+mtk_bmt_read(struct mtd_info *mtd, loff_t from, -+ struct mtd_oob_ops *ops) -+{ -+ struct mtd_oob_ops cur_ops = *ops; -+ int retry_count = 0; -+ loff_t cur_from; -+ int ret; -+ -+ ops->retlen = 0; -+ ops->oobretlen = 0; -+ -+ while (ops->retlen < ops->len || ops->oobretlen < ops->ooblen) { -+ u32 offset = from & (bmtd.blk_size - 1); -+ u32 block = from >> bmtd.blk_shift; -+ u32 cur_block; -+ -+ cur_block = get_mapping_block_index(block); -+ cur_from = ((loff_t)cur_block << bmtd.blk_shift) + offset; -+ -+ cur_ops.oobretlen = 0; -+ cur_ops.retlen = 0; -+ cur_ops.len = min_t(u32, mtd->erasesize - offset, -+ ops->len - ops->retlen); -+ ret = bmtd._read_oob(mtd, cur_from, &cur_ops); -+ if (ret < 0) { -+ update_bmt(block); -+ if (retry_count++ < 10) -+ continue; -+ -+ return ret; -+ } -+ -+ ops->retlen += cur_ops.retlen; -+ ops->oobretlen += cur_ops.oobretlen; -+ -+ cur_ops.ooboffs = 0; -+ cur_ops.datbuf += cur_ops.retlen; -+ cur_ops.oobbuf += cur_ops.oobretlen; -+ cur_ops.ooblen -= cur_ops.oobretlen; -+ -+ if (!cur_ops.len) -+ cur_ops.len = mtd->erasesize - offset; -+ -+ from += cur_ops.len; -+ retry_count = 0; -+ } -+ -+ return 0; -+} -+ -+static int -+mtk_bmt_write(struct mtd_info *mtd, loff_t to, -+ struct mtd_oob_ops *ops) -+{ -+ struct mtd_oob_ops cur_ops = *ops; -+ int retry_count = 0; -+ loff_t cur_to; -+ int ret; -+ -+ ops->retlen = 0; -+ ops->oobretlen = 0; -+ -+ while (ops->retlen < ops->len || ops->oobretlen < ops->ooblen) { -+ u32 offset = to & (bmtd.blk_size - 1); -+ u32 block = to >> bmtd.blk_shift; -+ u32 cur_block; -+ -+ cur_block = get_mapping_block_index(block); -+ cur_to = ((loff_t)cur_block << bmtd.blk_shift) + offset; -+ -+ cur_ops.oobretlen = 0; -+ cur_ops.retlen = 0; -+ cur_ops.len = min_t(u32, bmtd.blk_size - offset, -+ ops->len - ops->retlen); -+ ret = bmtd._write_oob(mtd, cur_to, &cur_ops); -+ if (ret < 0) { -+ update_bmt(block); -+ if (retry_count++ < 10) -+ continue; -+ -+ return ret; -+ } -+ -+ ops->retlen += cur_ops.retlen; -+ ops->oobretlen += cur_ops.oobretlen; -+ -+ cur_ops.ooboffs = 0; -+ cur_ops.datbuf += cur_ops.retlen; -+ cur_ops.oobbuf += cur_ops.oobretlen; -+ cur_ops.ooblen -= cur_ops.oobretlen; -+ -+ if (!cur_ops.len) -+ cur_ops.len = mtd->erasesize - offset; -+ -+ to += cur_ops.len; -+ retry_count = 0; -+ } -+ -+ return 0; -+} -+ -+static int -+mtk_bmt_mtd_erase(struct mtd_info *mtd, struct erase_info *instr) -+{ -+ struct erase_info mapped_instr = { -+ .len = bmtd.blk_size, -+ }; -+ int retry_count = 0; -+ u64 start_addr, end_addr; -+ int ret; -+ u16 orig_block, block; -+ -+ start_addr = instr->addr & (~mtd->erasesize_mask); -+ end_addr = instr->addr + instr->len; -+ -+ while (start_addr < end_addr) { -+ orig_block = start_addr >> bmtd.blk_shift; -+ block = get_mapping_block_index(orig_block); -+ mapped_instr.addr = (loff_t)block << bmtd.blk_shift; -+ ret = bmtd._erase(mtd, &mapped_instr); -+ if (ret) { -+ update_bmt(orig_block); -+ if (retry_count++ < 10) -+ continue; -+ instr->fail_addr = start_addr; -+ break; -+ } -+ start_addr += mtd->erasesize; -+ retry_count = 0; -+ } -+ -+ return ret; -+} -+static int -+mtk_bmt_block_isbad(struct mtd_info *mtd, loff_t ofs) -+{ -+ int retry_count = 0; -+ u16 orig_block = ofs >> bmtd.blk_shift; -+ u16 block; -+ int ret; -+ -+retry: -+ block = get_mapping_block_index(orig_block); -+ ret = bmtd._block_isbad(mtd, (loff_t)block << bmtd.blk_shift); -+ if (ret) { -+ update_bmt(orig_block); -+ if (retry_count++ < 10) -+ goto retry; -+ } -+ return ret; -+} -+ -+static int -+mtk_bmt_block_markbad(struct mtd_info *mtd, loff_t ofs) -+{ -+ u16 orig_block = ofs >> bmtd.blk_shift; -+ u16 block = get_mapping_block_index(orig_block); -+ update_bmt(orig_block); -+ return bmtd._block_markbad(mtd, (loff_t)block << bmtd.blk_shift); -+} -+ -+static void -+mtk_bmt_replace_ops(struct mtd_info *mtd) -+{ -+ bmtd._read_oob = mtd->_read_oob; -+ bmtd._write_oob = mtd->_write_oob; -+ bmtd._erase = mtd->_erase; -+ bmtd._block_isbad = mtd->_block_isbad; -+ bmtd._block_markbad = mtd->_block_markbad; -+ -+ mtd->_read_oob = mtk_bmt_read; -+ mtd->_write_oob = mtk_bmt_write; -+ mtd->_erase = mtk_bmt_mtd_erase; -+ mtd->_block_isbad = mtk_bmt_block_isbad; -+ mtd->_block_markbad = mtk_bmt_block_markbad; -+} -+ -+static int mtk_bmt_debug_mark_good(void *data, u64 val) -+{ -+ u32 block = val >> bmtd.blk_shift; -+ -+ bmtd.bbt->bb_tbl[block] = block; -+ bmtd.bmt_blk_idx = upload_bmt(bmtd.bbt, bmtd.bmt_blk_idx); -+ -+ return 0; -+} -+ -+static int mtk_bmt_debug_mark_bad(void *data, u64 val) -+{ -+ u32 block = val >> bmtd.blk_shift; -+ -+ update_bmt(block); -+ -+ return 0; -+} -+ -+DEFINE_DEBUGFS_ATTRIBUTE(fops_mark_good, NULL, mtk_bmt_debug_mark_good, "%llu\n"); -+DEFINE_DEBUGFS_ATTRIBUTE(fops_mark_bad, NULL, mtk_bmt_debug_mark_bad, "%llu\n"); -+ -+static void -+mtk_bmt_add_debugfs(void) -+{ -+ struct dentry *dir; -+ -+ dir = bmtd.debugfs_dir = debugfs_create_dir("mtk-bmt", NULL); -+ if (!dir) -+ return; -+ -+ debugfs_create_file_unsafe("mark_good", S_IWUSR, dir, NULL, &fops_mark_good); -+ debugfs_create_file_unsafe("mark_bad", S_IWUSR, dir, NULL, &fops_mark_bad); -+} -+ -+void mtk_bmt_detach(struct mtd_info *mtd) -+{ -+ if (bmtd.mtd != mtd) -+ return; -+ -+ if (bmtd.debugfs_dir) -+ debugfs_remove_recursive(bmtd.debugfs_dir); -+ bmtd.debugfs_dir = NULL; -+ -+ kfree(nand_bbt_buf); -+ kfree(nand_data_buf); -+ -+ mtd->_read_oob = bmtd._read_oob; -+ mtd->_write_oob = bmtd._write_oob; -+ mtd->_erase = bmtd._erase; -+ mtd->_block_isbad = bmtd._block_isbad; -+ mtd->_block_markbad = bmtd._block_markbad; -+ mtd->size = bmtd.total_blks << bmtd.blk_shift; -+ -+ memset(&bmtd, 0, sizeof(bmtd)); -+} -+ -+/* total_blocks - The total count of blocks that the Nand Chip has */ -+int mtk_bmt_attach(struct mtd_info *mtd) -+{ -+ struct device_node *np; -+ struct bbbt *bbt; -+ u32 bufsz; -+ u32 block; -+ u16 total_blocks, pmt_block; -+ int ret = 0; -+ u32 bmt_pool_size, bmt_table_size; -+ -+ if (bmtd.mtd) -+ return -ENOSPC; -+ -+ np = mtd_get_of_node(mtd); -+ if (!np) -+ return 0; -+ -+ if (!of_property_read_bool(np, "mediatek,bmt-v2")) -+ return 0; -+ -+ if (of_property_read_u32(np, "mediatek,bmt-pool-size", -+ &bmt_pool_size) != 0) -+ bmt_pool_size = 80; -+ -+ if (of_property_read_u8(np, "mediatek,bmt-oob-offset", -+ &bmtd.oob_offset) != 0) -+ bmtd.oob_offset = 0; -+ -+ if (of_property_read_u32(np, "mediatek,bmt-table-size", -+ &bmt_table_size) != 0) -+ bmt_table_size = 0x2000U; -+ -+ bmtd.mtd = mtd; -+ mtk_bmt_replace_ops(mtd); -+ -+ bmtd.table_size = bmt_table_size; -+ bmtd.blk_size = mtd->erasesize; -+ bmtd.blk_shift = ffs(bmtd.blk_size) - 1; -+ bmtd.pg_size = mtd->writesize; -+ bmtd.pg_shift = ffs(bmtd.pg_size) - 1; -+ total_blocks = mtd->size >> bmtd.blk_shift; -+ pmt_block = total_blocks - bmt_pool_size - 2; -+ -+ mtd->size = pmt_block << bmtd.blk_shift; -+ -+ /* -+ * --------------------------------------- -+ * | PMT(2blks) | BMT POOL(totalblks * 2%) | -+ * --------------------------------------- -+ * ^ ^ -+ * | | -+ * pmt_block pmt_block + 2blocks(pool_lba) -+ * -+ * ATTETION!!!!!! -+ * The blocks ahead of the boundary block are stored in bb_tbl -+ * and blocks behind are stored in bmt_tbl -+ */ -+ -+ bmtd.pool_lba = (u16)(pmt_block + 2); -+ bmtd.total_blks = total_blocks; -+ bmtd.bb_max = bmtd.total_blks * BBPOOL_RATIO / 100; -+ -+ /* 3 buffers we need */ -+ bufsz = round_up(sizeof(struct bbbt) + -+ bmt_table_size * sizeof(struct bbmt), bmtd.pg_size); -+ bmtd.bmt_pgs = bufsz >> bmtd.pg_shift; -+ -+ nand_bbt_buf = kzalloc(bufsz, GFP_KERNEL); -+ nand_data_buf = kzalloc(bmtd.pg_size, GFP_KERNEL); -+ -+ if (!nand_bbt_buf || !nand_data_buf) { -+ pr_info("nand: FATAL ERR: allocate buffer failed!\n"); -+ ret = -1; -+ goto error; -+ } -+ -+ memset(nand_bbt_buf, 0xff, bufsz); -+ memset(nand_data_buf, 0xff, bmtd.pg_size); -+ -+ BBT_LOG("bbtbuf=0x%p(0x%x) dat=0x%p(0x%x)", -+ nand_bbt_buf, bufsz, nand_data_buf, bmtd.pg_size); -+ BBT_LOG("pool_lba=0x%x total_blks=0x%x bb_max=0x%x", -+ bmtd.pool_lba, bmtd.total_blks, bmtd.bb_max); -+ -+ /* Scanning start from the first page of the last block -+ * of whole flash -+ */ -+ bbt = scan_bmt(bmtd.total_blks - 1); -+ if (!bbt) { -+ /* BMT not found */ -+ if (bmtd.total_blks > BB_TABLE_MAX + BMT_TABLE_MAX) { -+ pr_info("nand: FATAL: Too many blocks, can not support!\n"); -+ ret = -1; -+ goto error; -+ } -+ -+ bbt = (struct bbbt *)nand_bbt_buf; -+ memset(bmt_tbl(bbt), BMT_TBL_DEF_VAL, bmtd.table_size * sizeof(struct bbmt)); -+ -+ if (scan_bad_blocks(bbt)) { -+ ret = -1; -+ goto error; -+ } -+ -+ /* BMT always in the last valid block in pool */ -+ bmtd.bmt_blk_idx = upload_bmt(bbt, bmtd.bmt_blk_idx); -+ block = bmt_tbl(bbt)[bmtd.bmt_blk_idx].block; -+ pr_notice("[BBT] BMT.v2 is written into PBA:0x%x\n", block); -+ -+ if (bmtd.bmt_blk_idx == 0) -+ pr_info("nand: Warning: no available block in BMT pool!\n"); -+ else if (bmtd.bmt_blk_idx == (u16)-1) { -+ ret = -1; -+ goto error; -+ } -+ } -+ mtk_bmt_add_debugfs(); -+ -+ bmtd.bbt = bbt; -+ return 0; -+ -+error: -+ mtk_bmt_detach(mtd); -+ return ret; -+} -+ -+ -+MODULE_LICENSE("GPL"); -+MODULE_AUTHOR("Xiangsheng Hou , Felix Fietkau "); -+MODULE_DESCRIPTION("Bad Block mapping management v2 for MediaTek NAND Flash Driver"); -+ ---- /dev/null -+++ b/include/linux/mtd/mtk_bmt.h -@@ -0,0 +1,18 @@ -+#ifndef __MTK_BMT_H -+#define __MTK_BMT_H -+ -+#ifdef CONFIG_MTD_NAND_MTK_BMT -+int mtk_bmt_attach(struct mtd_info *mtd); -+void mtk_bmt_detach(struct mtd_info *mtd); -+#else -+static inline int mtk_bmt_attach(struct mtd_info *mtd) -+{ -+ return 0; -+} -+ -+static inline void mtk_bmt_detach(struct mtd_info *mtd) -+{ -+} -+#endif -+ -+#endif ---- a/drivers/mtd/mtk-snand/mtk-snand-mtd.c -+++ b/drivers/mtd/mtk-snand/mtk-snand-mtd.c -@@ -16,6 +16,7 @@ - #include - #include - #include -+#include - #include - #include - -@@ -612,6 +613,8 @@ static int mtk_snand_probe(struct platfo - mtd->_block_isbad = mtk_snand_mtd_block_isbad; - mtd->_block_markbad = mtk_snand_mtd_block_markbad; - -+ mtk_bmt_attach(mtd); -+ - ret = mtd_device_register(mtd, NULL, 0); - if (ret) { - dev_err(msm->pdev.dev, "failed to register mtd partition\n"); -@@ -623,6 +626,7 @@ static int mtk_snand_probe(struct platfo - return 0; - - errout4: -+ mtk_bmt_detach(mtd); - devm_kfree(msm->pdev.dev, msm->page_cache); - - errout3: -@@ -650,6 +654,8 @@ static int mtk_snand_remove(struct platf - if (ret) - return ret; - -+ mtk_bmt_detach(mtd); -+ - mtk_snand_cleanup(msm->snf); - - if (msm->irq >= 0) diff --git a/target/linux/mediatek/patches-5.10/330-mtk-snand-bmt-support.patch b/target/linux/mediatek/patches-5.10/330-mtk-snand-bmt-support.patch new file mode 100644 index 0000000000..318c8b2873 --- /dev/null +++ b/target/linux/mediatek/patches-5.10/330-mtk-snand-bmt-support.patch @@ -0,0 +1,36 @@ +--- a/drivers/mtd/mtk-snand/mtk-snand-mtd.c ++++ b/drivers/mtd/mtk-snand/mtk-snand-mtd.c +@@ -16,6 +16,7 @@ + #include + #include + #include ++#include + #include + #include + +@@ -612,6 +613,8 @@ static int mtk_snand_probe(struct platfo + mtd->_block_isbad = mtk_snand_mtd_block_isbad; + mtd->_block_markbad = mtk_snand_mtd_block_markbad; + ++ mtk_bmt_attach(mtd); ++ + ret = mtd_device_register(mtd, NULL, 0); + if (ret) { + dev_err(msm->pdev.dev, "failed to register mtd partition\n"); +@@ -623,6 +626,7 @@ static int mtk_snand_probe(struct platfo + return 0; + + errout4: ++ mtk_bmt_detach(mtd); + devm_kfree(msm->pdev.dev, msm->page_cache); + + errout3: +@@ -650,6 +654,8 @@ static int mtk_snand_remove(struct platf + if (ret) + return ret; + ++ mtk_bmt_detach(mtd); ++ + mtk_snand_cleanup(msm->snf); + + if (msm->irq >= 0) From fde242159785f5831a9da80a1f88babb6a89cb05 Mon Sep 17 00:00:00 2001 From: Felix Fietkau Date: Sun, 9 Jan 2022 17:26:46 +0100 Subject: [PATCH 12/29] kernel: mtk_bmt: fix remapping after read/write failure Copy from the previous block in order to preserve existing data Signed-off-by: Felix Fietkau --- .../generic/files/drivers/mtd/nand/mtk_bmt.c | 78 ++++++++++++++++--- 1 file changed, 67 insertions(+), 11 deletions(-) diff --git a/target/linux/generic/files/drivers/mtd/nand/mtk_bmt.c b/target/linux/generic/files/drivers/mtd/nand/mtk_bmt.c index f249f571c4..2db31fe066 100644 --- a/target/linux/generic/files/drivers/mtd/nand/mtk_bmt.c +++ b/target/linux/generic/files/drivers/mtd/nand/mtk_bmt.c @@ -22,6 +22,7 @@ #include #include #include +#include #define MAIN_SIGNATURE_OFFSET 0 #define OOB_SIGNATURE_OFFSET 1 @@ -130,6 +131,51 @@ static inline int bbt_nand_erase(u16 block) return bmtd._erase(mtd, &instr); } +static inline int bbt_nand_copy(u16 dest_blk, u16 src_blk, loff_t max_offset) +{ + int pages = bmtd.blk_size >> bmtd.pg_shift; + loff_t src = (loff_t)src_blk << bmtd.blk_shift; + loff_t dest = (loff_t)dest_blk << bmtd.blk_shift; + loff_t offset = 0; + uint8_t oob[64]; + int i, ret; + + for (i = 0; i < pages; i++) { + struct mtd_oob_ops rd_ops = { + .mode = MTD_OPS_PLACE_OOB, + .oobbuf = oob, + .ooblen = min_t(int, bmtd.mtd->oobsize / pages, sizeof(oob)), + .datbuf = nand_data_buf, + .len = bmtd.pg_size, + }; + struct mtd_oob_ops wr_ops = { + .mode = MTD_OPS_PLACE_OOB, + .oobbuf = oob, + .datbuf = nand_data_buf, + .len = bmtd.pg_size, + }; + + if (offset >= max_offset) + break; + + ret = bmtd._read_oob(bmtd.mtd, src + offset, &rd_ops); + if (ret < 0 && !mtd_is_bitflip(ret)) + return ret; + + if (!rd_ops.retlen) + break; + + ret = bmtd._write_oob(bmtd.mtd, dest + offset, &wr_ops); + if (ret < 0) + return ret; + + wr_ops.ooblen = rd_ops.oobretlen; + offset += rd_ops.retlen; + } + + return 0; +} + /* -------- Bad Blocks Management -------- */ static inline struct bbmt *bmt_tbl(struct bbbt *bbbt) { @@ -389,7 +435,7 @@ error: /* We met a bad block, mark it as bad and map it to a valid block in pool, * if it's a write failure, we need to write the data to mapped block */ -static bool update_bmt(u16 block) +static bool update_bmt(u16 block, int copy_len) { u16 mapped_blk; struct bbbt *bbt; @@ -401,6 +447,12 @@ static bool update_bmt(u16 block) /* Map new bad block to available block in pool */ bbt->bb_tbl[block] = mapped_blk; + + /* Erase new block */ + bbt_nand_erase(mapped_blk); + if (copy_len > 0) + bbt_nand_copy(mapped_blk, block, copy_len); + bmtd.bmt_blk_idx = upload_bmt(bbt, bmtd.bmt_blk_idx); return true; @@ -426,12 +478,14 @@ mtk_bmt_read(struct mtd_info *mtd, loff_t from, struct mtd_oob_ops cur_ops = *ops; int retry_count = 0; loff_t cur_from; - int ret; + int ret = 0; ops->retlen = 0; ops->oobretlen = 0; while (ops->retlen < ops->len || ops->oobretlen < ops->ooblen) { + int cur_ret; + u32 offset = from & (bmtd.blk_size - 1); u32 block = from >> bmtd.blk_shift; u32 cur_block; @@ -443,9 +497,11 @@ mtk_bmt_read(struct mtd_info *mtd, loff_t from, cur_ops.retlen = 0; cur_ops.len = min_t(u32, mtd->erasesize - offset, ops->len - ops->retlen); - ret = bmtd._read_oob(mtd, cur_from, &cur_ops); - if (ret < 0) { - update_bmt(block); + cur_ret = bmtd._read_oob(mtd, cur_from, &cur_ops); + if (cur_ret < 0) + ret = cur_ret; + if (cur_ret < 0 && !mtd_is_bitflip(cur_ret)) { + update_bmt(block, mtd->erasesize); if (retry_count++ < 10) continue; @@ -467,7 +523,7 @@ mtk_bmt_read(struct mtd_info *mtd, loff_t from, retry_count = 0; } - return 0; + return ret; } static int @@ -496,7 +552,7 @@ mtk_bmt_write(struct mtd_info *mtd, loff_t to, ops->len - ops->retlen); ret = bmtd._write_oob(mtd, cur_to, &cur_ops); if (ret < 0) { - update_bmt(block); + update_bmt(block, offset); if (retry_count++ < 10) continue; @@ -541,7 +597,7 @@ mtk_bmt_mtd_erase(struct mtd_info *mtd, struct erase_info *instr) mapped_instr.addr = (loff_t)block << bmtd.blk_shift; ret = bmtd._erase(mtd, &mapped_instr); if (ret) { - update_bmt(orig_block); + update_bmt(orig_block, 0); if (retry_count++ < 10) continue; instr->fail_addr = start_addr; @@ -565,7 +621,7 @@ retry: block = get_mapping_block_index(orig_block); ret = bmtd._block_isbad(mtd, (loff_t)block << bmtd.blk_shift); if (ret) { - update_bmt(orig_block); + update_bmt(orig_block, bmtd.blk_size); if (retry_count++ < 10) goto retry; } @@ -577,7 +633,7 @@ mtk_bmt_block_markbad(struct mtd_info *mtd, loff_t ofs) { u16 orig_block = ofs >> bmtd.blk_shift; u16 block = get_mapping_block_index(orig_block); - update_bmt(orig_block); + update_bmt(orig_block, bmtd.blk_size); return bmtd._block_markbad(mtd, (loff_t)block << bmtd.blk_shift); } @@ -611,7 +667,7 @@ static int mtk_bmt_debug_mark_bad(void *data, u64 val) { u32 block = val >> bmtd.blk_shift; - update_bmt(block); + update_bmt(block, bmtd.blk_size); return 0; } From 31b6cfb28890071acc0c044abf9c48843e4100ce Mon Sep 17 00:00:00 2001 From: Felix Fietkau Date: Sun, 9 Jan 2022 17:27:29 +0100 Subject: [PATCH 13/29] kernel: mtk_bmt: extend debug interface Add support for showing remapped blocks and garbage collecting old remapped blocks triggered by using the mark_good/mark_bad files Signed-off-by: Felix Fietkau --- .../generic/files/drivers/mtd/nand/mtk_bmt.c | 96 +++++++++++++++++++ 1 file changed, 96 insertions(+) diff --git a/target/linux/generic/files/drivers/mtd/nand/mtk_bmt.c b/target/linux/generic/files/drivers/mtd/nand/mtk_bmt.c index 2db31fe066..cb74b4d10f 100644 --- a/target/linux/generic/files/drivers/mtd/nand/mtk_bmt.c +++ b/target/linux/generic/files/drivers/mtd/nand/mtk_bmt.c @@ -672,8 +672,103 @@ static int mtk_bmt_debug_mark_bad(void *data, u64 val) return 0; } +static unsigned long * +mtk_bmt_get_mapping_mask(void) +{ + struct bbmt *bbmt = bmt_tbl(bmtd.bbt); + int main_blocks = bmtd.mtd->size >> bmtd.blk_shift; + unsigned long *used; + int i, k; + + used = kcalloc(sizeof(unsigned long), BIT_WORD(bmtd.bmt_blk_idx) + 1, GFP_KERNEL); + if (!used) + return NULL; + + for (i = 1; i < main_blocks; i++) { + if (bmtd.bbt->bb_tbl[i] == i) + continue; + + for (k = 0; k < bmtd.bmt_blk_idx; k++) { + if (bmtd.bbt->bb_tbl[i] != bbmt[k].block) + continue; + + set_bit(k, used); + break; + } + } + + return used; +} + +static int mtk_bmt_debug(void *data, u64 val) +{ + struct bbmt *bbmt = bmt_tbl(bmtd.bbt); + struct mtd_info *mtd = bmtd.mtd; + unsigned long *used; + int main_blocks = mtd->size >> bmtd.blk_shift; + int n_remap = 0; + int i; + + used = mtk_bmt_get_mapping_mask(); + if (!used) + return -ENOMEM; + + switch (val) { + case 0: + for (i = 1; i < main_blocks; i++) { + if (bmtd.bbt->bb_tbl[i] == i) + continue; + + printk("remap [%x->%x]\n", i, bmtd.bbt->bb_tbl[i]); + n_remap++; + } + for (i = 0; i <= bmtd.bmt_blk_idx; i++) { + char c; + + switch (bbmt[i].mapped) { + case NO_MAPPED: + continue; + case NORMAL_MAPPED: + c = 'm'; + if (test_bit(i, used)) + c = 'M'; + break; + case BMT_MAPPED: + c = 'B'; + break; + default: + c = 'X'; + break; + } + printk("[%x:%c] = 0x%x\n", i, c, bbmt[i].block); + } + break; + case 100: + for (i = 0; i <= bmtd.bmt_blk_idx; i++) { + if (bbmt[i].mapped != NORMAL_MAPPED) + continue; + + if (test_bit(i, used)) + continue; + + n_remap++; + bbmt[i].mapped = NO_MAPPED; + printk("free block [%d:%x]\n", i, bbmt[i].block); + } + if (n_remap) + bmtd.bmt_blk_idx = upload_bmt(bmtd.bbt, bmtd.bmt_blk_idx); + break; + } + + kfree(used); + + return 0; +} + + DEFINE_DEBUGFS_ATTRIBUTE(fops_mark_good, NULL, mtk_bmt_debug_mark_good, "%llu\n"); DEFINE_DEBUGFS_ATTRIBUTE(fops_mark_bad, NULL, mtk_bmt_debug_mark_bad, "%llu\n"); +DEFINE_DEBUGFS_ATTRIBUTE(fops_debug, NULL, mtk_bmt_debug, "%llu\n"); static void mtk_bmt_add_debugfs(void) @@ -686,6 +781,7 @@ mtk_bmt_add_debugfs(void) debugfs_create_file_unsafe("mark_good", S_IWUSR, dir, NULL, &fops_mark_good); debugfs_create_file_unsafe("mark_bad", S_IWUSR, dir, NULL, &fops_mark_bad); + debugfs_create_file_unsafe("debug", S_IWUSR, dir, NULL, &fops_debug); } void mtk_bmt_detach(struct mtd_info *mtd) From b86452f8414d921058d800922849691a0fcfe2a6 Mon Sep 17 00:00:00 2001 From: Felix Fietkau Date: Sun, 9 Jan 2022 19:56:16 +0100 Subject: [PATCH 14/29] kernel: mtk_bmt: add support for limiting range of remapping This can be used to support ubi on top of mtk_bmt without reflashing the boot loader. The boot loader + factory + kernel area is covered, while the rest is passed through as-is Signed-off-by: Felix Fietkau --- .../generic/files/drivers/mtd/nand/mtk_bmt.c | 36 +++++++++++++++---- 1 file changed, 29 insertions(+), 7 deletions(-) diff --git a/target/linux/generic/files/drivers/mtd/nand/mtk_bmt.c b/target/linux/generic/files/drivers/mtd/nand/mtk_bmt.c index cb74b4d10f..14fbd246d7 100644 --- a/target/linux/generic/files/drivers/mtd/nand/mtk_bmt.c +++ b/target/linux/generic/files/drivers/mtd/nand/mtk_bmt.c @@ -90,6 +90,9 @@ static struct bmt_desc { /* How many pages needs to store 'struct bbbt' */ u32 bmt_pgs; + const __be32 *remap_range; + int remap_range_len; + /* to compensate for driver level remapping */ u8 oob_offset; } bmtd = {0}; @@ -458,17 +461,32 @@ static bool update_bmt(u16 block, int copy_len) return true; } +static bool +mapping_block_in_range(int block) +{ + const __be32 *cur = bmtd.remap_range; + u32 addr = block << bmtd.blk_shift; + int i; + + if (!cur || !bmtd.remap_range_len) + return true; + + for (i = 0; i < bmtd.remap_range_len; i++, cur += 2) + if (addr >= be32_to_cpu(cur[0]) && addr < be32_to_cpu(cur[1])) + return true; + + return false; +} + u16 get_mapping_block_index(int block) { - int mapping_block; + if (block >= bmtd.pool_lba) + return block; - if (block < bmtd.pool_lba) - mapping_block = bmtd.bbt->bb_tbl[block]; - else - mapping_block = block; - BBT_LOG("0x%x mapped to 0x%x", block, mapping_block); + if (!mapping_block_in_range(block)) + return block; - return mapping_block; + return bmtd.bbt->bb_tbl[block]; } static int @@ -839,6 +857,10 @@ int mtk_bmt_attach(struct mtd_info *mtd) &bmt_table_size) != 0) bmt_table_size = 0x2000U; + bmtd.remap_range = of_get_property(np, "mediatek,bmt-remap-range", + &bmtd.remap_range_len); + bmtd.remap_range_len /= 8; + bmtd.mtd = mtd; mtk_bmt_replace_ops(mtd); From 0ddead089778e399d01a744d91eed3d665922bd4 Mon Sep 17 00:00:00 2001 From: Felix Fietkau Date: Sun, 9 Jan 2022 20:18:27 +0100 Subject: [PATCH 15/29] kernel: mtk_bmt: pass number of bitflips on read to the caller Signed-off-by: Felix Fietkau --- target/linux/generic/files/drivers/mtd/nand/mtk_bmt.c | 11 +++++++++-- 1 file changed, 9 insertions(+), 2 deletions(-) diff --git a/target/linux/generic/files/drivers/mtd/nand/mtk_bmt.c b/target/linux/generic/files/drivers/mtd/nand/mtk_bmt.c index 14fbd246d7..84538f9180 100644 --- a/target/linux/generic/files/drivers/mtd/nand/mtk_bmt.c +++ b/target/linux/generic/files/drivers/mtd/nand/mtk_bmt.c @@ -497,6 +497,7 @@ mtk_bmt_read(struct mtd_info *mtd, loff_t from, int retry_count = 0; loff_t cur_from; int ret = 0; + int max_bitflips = 0; ops->retlen = 0; ops->oobretlen = 0; @@ -518,12 +519,14 @@ mtk_bmt_read(struct mtd_info *mtd, loff_t from, cur_ret = bmtd._read_oob(mtd, cur_from, &cur_ops); if (cur_ret < 0) ret = cur_ret; + else + max_bitflips = max_t(int, max_bitflips, cur_ret); if (cur_ret < 0 && !mtd_is_bitflip(cur_ret)) { update_bmt(block, mtd->erasesize); if (retry_count++ < 10) continue; - return ret; + goto out; } ops->retlen += cur_ops.retlen; @@ -541,7 +544,11 @@ mtk_bmt_read(struct mtd_info *mtd, loff_t from, retry_count = 0; } - return ret; +out: + if (ret < 0) + return ret; + + return max_bitflips; } static int From 7235c8d00ccf2d6d1bde3a2bec476d45d8c7c2ab Mon Sep 17 00:00:00 2001 From: Felix Fietkau Date: Sun, 9 Jan 2022 20:24:41 +0100 Subject: [PATCH 16/29] kernel: mtk_bmt: remap blocks after reaching bitflip threshold This ensures that blocks are remapped before data becomes corrupt Signed-off-by: Felix Fietkau --- target/linux/generic/files/drivers/mtd/nand/mtk_bmt.c | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/target/linux/generic/files/drivers/mtd/nand/mtk_bmt.c b/target/linux/generic/files/drivers/mtd/nand/mtk_bmt.c index 84538f9180..2140c619da 100644 --- a/target/linux/generic/files/drivers/mtd/nand/mtk_bmt.c +++ b/target/linux/generic/files/drivers/mtd/nand/mtk_bmt.c @@ -529,6 +529,10 @@ mtk_bmt_read(struct mtd_info *mtd, loff_t from, goto out; } + if (cur_ret >= mtd->bitflip_threshold && + mapping_block_in_range(block)) + update_bmt(block, mtd->erasesize); + ops->retlen += cur_ops.retlen; ops->oobretlen += cur_ops.oobretlen; From 76b27f6bb92eec4a25001da8d8188d30440eafd9 Mon Sep 17 00:00:00 2001 From: Felix Fietkau Date: Mon, 10 Jan 2022 12:35:08 +0100 Subject: [PATCH 17/29] mediatek: rework and fix mt7622-rfb1-ubi support Limit bmt remapping range to cover everything up to and including the kernel image, use the rest of the flash area for ubi. Fix partition table and sysupgrade support Signed-off-by: Felix Fietkau --- target/linux/mediatek/dts/mt7622-rfb1-ubi.dts | 18 +++++++++--------- target/linux/mediatek/image/mt7622.mk | 1 + .../mt7622/base-files/etc/board.d/02_network | 3 ++- .../mt7622/base-files/lib/upgrade/platform.sh | 5 +++-- 4 files changed, 15 insertions(+), 12 deletions(-) diff --git a/target/linux/mediatek/dts/mt7622-rfb1-ubi.dts b/target/linux/mediatek/dts/mt7622-rfb1-ubi.dts index 3816dcb9cc..1a94446c7a 100644 --- a/target/linux/mediatek/dts/mt7622-rfb1-ubi.dts +++ b/target/linux/mediatek/dts/mt7622-rfb1-ubi.dts @@ -3,10 +3,13 @@ #include "mt7622-rfb1.dts" / { model = "MT7622_MT7531 RFB (UBI)"; - compatible = "mediatek,mt7622,ubi"; + compatible = "mediatek,mt7622-rfb1-ubi"; }; &snand { + mediatek,bmt-v2; + mediatek,bmt-remap-range = <0x0 0x6c0000>; + partitions { compatible = "fixed-partitions"; #address-cells = <1>; @@ -35,22 +38,19 @@ factory: partition@1c0000 { label = "Factory"; - reg = <0x1c0000 0x0040000>; + reg = <0x1c0000 0x0100000>; }; partition@200000 { label = "kernel"; - reg = <0x200000 0x400000>; + reg = <0x2c0000 0x400000>; }; - partition@600000 { + partition@6c0000 { label = "ubi"; - reg = <0x600000 0x1C00000>; + reg = <0x6c0000 0x6f00000>; }; - partition@2200000 { - label = "User_data"; - reg = <0x2200000 0x4000000>; - }; + /delete-node/ partition@2200000; }; }; diff --git a/target/linux/mediatek/image/mt7622.mk b/target/linux/mediatek/image/mt7622.mk index 795bb3fc76..3b0afa98df 100644 --- a/target/linux/mediatek/image/mt7622.mk +++ b/target/linux/mediatek/image/mt7622.mk @@ -190,6 +190,7 @@ define Device/mediatek_mt7622-rfb1-ubi DEVICE_DTS := mt7622-rfb1-ubi DEVICE_DTS_DIR := ../dts DEVICE_PACKAGES := kmod-ata-ahci-mtk kmod-btmtkuart kmod-usb3 + BOARD_NAME := mediatek,mt7622-rfb1-ubi UBINIZE_OPTS := -E 5 BLOCKSIZE := 128k PAGESIZE := 2048 diff --git a/target/linux/mediatek/mt7622/base-files/etc/board.d/02_network b/target/linux/mediatek/mt7622/base-files/etc/board.d/02_network index 3724fd6d5c..7b454314cf 100644 --- a/target/linux/mediatek/mt7622/base-files/etc/board.d/02_network +++ b/target/linux/mediatek/mt7622/base-files/etc/board.d/02_network @@ -11,7 +11,8 @@ mediatek_setup_interfaces() bananapi,bpi-r64|\ linksys,e8450|\ linksys,e8450-ubi|\ - mediatek,mt7622-rfb1) + mediatek,mt7622-rfb1|\ + mediatek,mt7622-rfb1-ubi) ucidef_set_interfaces_lan_wan "lan1 lan2 lan3 lan4" wan ;; buffalo,wsr-2533dhp2) diff --git a/target/linux/mediatek/mt7622/base-files/lib/upgrade/platform.sh b/target/linux/mediatek/mt7622/base-files/lib/upgrade/platform.sh index e6afb9547c..bd86a92c7b 100755 --- a/target/linux/mediatek/mt7622/base-files/lib/upgrade/platform.sh +++ b/target/linux/mediatek/mt7622/base-files/lib/upgrade/platform.sh @@ -34,8 +34,7 @@ platform_do_upgrade() { nand_do_upgrade "$1" fi ;; - linksys,e8450-ubi|\ - mediatek,mt7622,ubi) + linksys,e8450-ubi) CI_KERNPART="fit" nand_do_upgrade "$1" ;; @@ -47,6 +46,7 @@ platform_do_upgrade() { fi default_do_upgrade "$1" ;; + mediatek,mt7622-rfb1-ubi|\ totolink,a8000ru) nand_do_upgrade "$1" ;; @@ -68,6 +68,7 @@ platform_check_image() { buffalo,wsr-2533dhp2) buffalo_check_image "$board" "$magic" "$1" || return 1 ;; + mediatek,mt7622-rfb1-ubi|\ totolink,a8000ru) nand_do_platform_check "$board" "$1" ;; From 3c78fabb0de1591489e63e429a7af794303f211b Mon Sep 17 00:00:00 2001 From: Felix Fietkau Date: Wed, 12 Jan 2022 20:56:04 +0100 Subject: [PATCH 18/29] ramips: mt7621_nand: fix writing upper half of fdm data Since the loop iterates from 0-3, subtracting 4 from the shift multiplier does not make any sense Signed-off-by: Felix Fietkau --- ...0-mtd-rawnand-add-driver-support-for-MT7621-nand-flash.patch | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/target/linux/ramips/patches-5.10/410-mtd-rawnand-add-driver-support-for-MT7621-nand-flash.patch b/target/linux/ramips/patches-5.10/410-mtd-rawnand-add-driver-support-for-MT7621-nand-flash.patch index a37426edec..8049dbde14 100644 --- a/target/linux/ramips/patches-5.10/410-mtd-rawnand-add-driver-support-for-MT7621-nand-flash.patch +++ b/target/linux/ramips/patches-5.10/410-mtd-rawnand-add-driver-support-for-MT7621-nand-flash.patch @@ -1022,7 +1022,7 @@ Signed-off-by: Weijie Gao + vall |= (u32)oobptr[j] << (j * 8); + + for (j = 0; j < 4; j++) -+ valm |= (u32)oobptr[j + 4] << ((j - 4) * 8); ++ valm |= (u32)oobptr[j + 4] << (j * 8); + + nfi_write32(nfc, NFI_FDML(i), vall); + nfi_write32(nfc, NFI_FDMM(i), valm); From ff6b4f2cfbc36efb2f3e61fd0c279de8527aa241 Mon Sep 17 00:00:00 2001 From: Felix Fietkau Date: Tue, 11 Jan 2022 12:45:52 +0100 Subject: [PATCH 19/29] kernel: mtk_bmt: add abstraction for supporting other formats Preparation for supporting remapping on MT7621 Signed-off-by: Felix Fietkau --- .../generic/files/drivers/mtd/nand/mtk_bmt.c | 232 ++++++++++-------- 1 file changed, 132 insertions(+), 100 deletions(-) diff --git a/target/linux/generic/files/drivers/mtd/nand/mtk_bmt.c b/target/linux/generic/files/drivers/mtd/nand/mtk_bmt.c index 2140c619da..7f55c1810d 100644 --- a/target/linux/generic/files/drivers/mtd/nand/mtk_bmt.c +++ b/target/linux/generic/files/drivers/mtd/nand/mtk_bmt.c @@ -35,10 +35,15 @@ #define BMT_TABLE_MAX (BB_TABLE_MAX * BBPOOL_RATIO / 100) #define BMT_TBL_DEF_VAL 0x0 -/* - * Burner Bad Block Table - * --------- Only support SLC Nand Chips!!!!!!!!!!! ---------- - */ +struct mtk_bmt_ops { + char *sig; + unsigned int sig_len; + int (*init)(struct device_node *np); + bool (*remap_block)(u16 block, u16 mapped_block, int copy_len); + void (*unmap_block)(u16 block); + u16 (*get_mapping_block)(int block); + int (*debug)(void *data, u64 val); +}; struct bbbt { char signature[3]; @@ -68,6 +73,8 @@ static struct bmt_desc { int (*_block_isbad) (struct mtd_info *mtd, loff_t ofs); int (*_block_markbad) (struct mtd_info *mtd, loff_t ofs); + const struct mtk_bmt_ops *ops; + struct bbbt *bbt; struct dentry *debugfs_dir; @@ -198,8 +205,8 @@ static int write_bmt(u16 block, unsigned char *dat) struct mtd_oob_ops ops = { .mode = MTD_OPS_PLACE_OOB, .ooboffs = OOB_SIGNATURE_OFFSET + bmtd.oob_offset, - .oobbuf = "bmt", - .ooblen = 3, + .oobbuf = bmtd.ops->sig, + .ooblen = bmtd.ops->sig_len, .datbuf = dat, .len = bmtd.bmt_pgs << bmtd.pg_shift, }; @@ -438,7 +445,7 @@ error: /* We met a bad block, mark it as bad and map it to a valid block in pool, * if it's a write failure, we need to write the data to mapped block */ -static bool update_bmt(u16 block, int copy_len) +static bool remap_block_v2(u16 block, u16 mapped_block, int copy_len) { u16 mapped_blk; struct bbbt *bbt; @@ -478,7 +485,8 @@ mapping_block_in_range(int block) return false; } -u16 get_mapping_block_index(int block) +static u16 +get_mapping_block_index_v2(int block) { if (block >= bmtd.pool_lba) return block; @@ -498,6 +506,7 @@ mtk_bmt_read(struct mtd_info *mtd, loff_t from, loff_t cur_from; int ret = 0; int max_bitflips = 0; + int start, end; ops->retlen = 0; ops->oobretlen = 0; @@ -509,7 +518,7 @@ mtk_bmt_read(struct mtd_info *mtd, loff_t from, u32 block = from >> bmtd.blk_shift; u32 cur_block; - cur_block = get_mapping_block_index(block); + cur_block = bmtd.ops->get_mapping_block(block); cur_from = ((loff_t)cur_block << bmtd.blk_shift) + offset; cur_ops.oobretlen = 0; @@ -522,7 +531,7 @@ mtk_bmt_read(struct mtd_info *mtd, loff_t from, else max_bitflips = max_t(int, max_bitflips, cur_ret); if (cur_ret < 0 && !mtd_is_bitflip(cur_ret)) { - update_bmt(block, mtd->erasesize); + bmtd.ops->remap_block(block, cur_block, mtd->erasesize); if (retry_count++ < 10) continue; @@ -530,8 +539,8 @@ mtk_bmt_read(struct mtd_info *mtd, loff_t from, } if (cur_ret >= mtd->bitflip_threshold && - mapping_block_in_range(block)) - update_bmt(block, mtd->erasesize); + mapping_block_in_range(block, &start, &end)) + bmtd.ops->remap_block(block, cur_block, mtd->erasesize); ops->retlen += cur_ops.retlen; ops->oobretlen += cur_ops.oobretlen; @@ -572,7 +581,7 @@ mtk_bmt_write(struct mtd_info *mtd, loff_t to, u32 block = to >> bmtd.blk_shift; u32 cur_block; - cur_block = get_mapping_block_index(block); + cur_block = bmtd.ops->get_mapping_block(block); cur_to = ((loff_t)cur_block << bmtd.blk_shift) + offset; cur_ops.oobretlen = 0; @@ -581,7 +590,7 @@ mtk_bmt_write(struct mtd_info *mtd, loff_t to, ops->len - ops->retlen); ret = bmtd._write_oob(mtd, cur_to, &cur_ops); if (ret < 0) { - update_bmt(block, offset); + bmtd.ops->remap_block(block, cur_block, offset); if (retry_count++ < 10) continue; @@ -622,11 +631,11 @@ mtk_bmt_mtd_erase(struct mtd_info *mtd, struct erase_info *instr) while (start_addr < end_addr) { orig_block = start_addr >> bmtd.blk_shift; - block = get_mapping_block_index(orig_block); + block = bmtd.ops->get_mapping_block(orig_block); mapped_instr.addr = (loff_t)block << bmtd.blk_shift; ret = bmtd._erase(mtd, &mapped_instr); if (ret) { - update_bmt(orig_block, 0); + bmtd.ops->remap_block(orig_block, block, 0); if (retry_count++ < 10) continue; instr->fail_addr = start_addr; @@ -647,10 +656,10 @@ mtk_bmt_block_isbad(struct mtd_info *mtd, loff_t ofs) int ret; retry: - block = get_mapping_block_index(orig_block); + block = bmtd.ops->get_mapping_block(orig_block); ret = bmtd._block_isbad(mtd, (loff_t)block << bmtd.blk_shift); if (ret) { - update_bmt(orig_block, bmtd.blk_size); + bmtd.ops->remap_block(orig_block, block, bmtd.blk_size); if (retry_count++ < 10) goto retry; } @@ -661,8 +670,10 @@ static int mtk_bmt_block_markbad(struct mtd_info *mtd, loff_t ofs) { u16 orig_block = ofs >> bmtd.blk_shift; - u16 block = get_mapping_block_index(orig_block); - update_bmt(orig_block, bmtd.blk_size); + u16 block = bmtd.ops->get_mapping_block(orig_block); + + bmtd.ops->remap_block(orig_block, block, bmtd.blk_size); + return bmtd._block_markbad(mtd, (loff_t)block << bmtd.blk_shift); } @@ -682,12 +693,16 @@ mtk_bmt_replace_ops(struct mtd_info *mtd) mtd->_block_markbad = mtk_bmt_block_markbad; } -static int mtk_bmt_debug_mark_good(void *data, u64 val) +static void +unmap_block_v2(u16 block) { - u32 block = val >> bmtd.blk_shift; - bmtd.bbt->bb_tbl[block] = block; bmtd.bmt_blk_idx = upload_bmt(bmtd.bbt, bmtd.bmt_blk_idx); +} + +static int mtk_bmt_debug_mark_good(void *data, u64 val) +{ + bmtd.ops->unmap_block(val >> bmtd.blk_shift); return 0; } @@ -695,8 +710,9 @@ static int mtk_bmt_debug_mark_good(void *data, u64 val) static int mtk_bmt_debug_mark_bad(void *data, u64 val) { u32 block = val >> bmtd.blk_shift; + u16 cur_block = bmtd.ops->get_mapping_block(block); - update_bmt(block, bmtd.blk_size); + bmtd.ops->remap_block(block, cur_block, bmtd.blk_size); return 0; } @@ -729,7 +745,7 @@ mtk_bmt_get_mapping_mask(void) return used; } -static int mtk_bmt_debug(void *data, u64 val) +static int mtk_bmt_debug_v2(void *data, u64 val) { struct bbmt *bbmt = bmt_tbl(bmtd.bbt); struct mtd_info *mtd = bmtd.mtd; @@ -794,6 +810,11 @@ static int mtk_bmt_debug(void *data, u64 val) return 0; } +static int mtk_bmt_debug(void *data, u64 val) +{ + return bmtd.ops->debug(data, val); +} + DEFINE_DEBUGFS_ATTRIBUTE(fops_mark_good, NULL, mtk_bmt_debug_mark_good, "%llu\n"); DEFINE_DEBUGFS_ATTRIBUTE(fops_mark_bad, NULL, mtk_bmt_debug_mark_bad, "%llu\n"); @@ -835,26 +856,11 @@ void mtk_bmt_detach(struct mtd_info *mtd) memset(&bmtd, 0, sizeof(bmtd)); } -/* total_blocks - The total count of blocks that the Nand Chip has */ -int mtk_bmt_attach(struct mtd_info *mtd) +static int mtk_bmt_init_v2(struct device_node *np) { - struct device_node *np; - struct bbbt *bbt; - u32 bufsz; - u32 block; - u16 total_blocks, pmt_block; - int ret = 0; u32 bmt_pool_size, bmt_table_size; - - if (bmtd.mtd) - return -ENOSPC; - - np = mtd_get_of_node(mtd); - if (!np) - return 0; - - if (!of_property_read_bool(np, "mediatek,bmt-v2")) - return 0; + u32 bufsz, block; + u16 pmt_block; if (of_property_read_u32(np, "mediatek,bmt-pool-size", &bmt_pool_size) != 0) @@ -868,22 +874,11 @@ int mtk_bmt_attach(struct mtd_info *mtd) &bmt_table_size) != 0) bmt_table_size = 0x2000U; - bmtd.remap_range = of_get_property(np, "mediatek,bmt-remap-range", - &bmtd.remap_range_len); - bmtd.remap_range_len /= 8; - - bmtd.mtd = mtd; - mtk_bmt_replace_ops(mtd); - bmtd.table_size = bmt_table_size; - bmtd.blk_size = mtd->erasesize; - bmtd.blk_shift = ffs(bmtd.blk_size) - 1; - bmtd.pg_size = mtd->writesize; - bmtd.pg_shift = ffs(bmtd.pg_size) - 1; - total_blocks = mtd->size >> bmtd.blk_shift; - pmt_block = total_blocks - bmt_pool_size - 2; - mtd->size = pmt_block << bmtd.blk_shift; + pmt_block = bmtd.total_blks - bmt_pool_size - 2; + + bmtd.mtd->size = pmt_block << bmtd.blk_shift; /* * --------------------------------------- @@ -899,66 +894,103 @@ int mtk_bmt_attach(struct mtd_info *mtd) */ bmtd.pool_lba = (u16)(pmt_block + 2); - bmtd.total_blks = total_blocks; bmtd.bb_max = bmtd.total_blks * BBPOOL_RATIO / 100; - /* 3 buffers we need */ bufsz = round_up(sizeof(struct bbbt) + bmt_table_size * sizeof(struct bbmt), bmtd.pg_size); bmtd.bmt_pgs = bufsz >> bmtd.pg_shift; nand_bbt_buf = kzalloc(bufsz, GFP_KERNEL); - nand_data_buf = kzalloc(bmtd.pg_size, GFP_KERNEL); + if (!nand_bbt_buf) + return -ENOMEM; - if (!nand_bbt_buf || !nand_data_buf) { + memset(nand_bbt_buf, 0xff, bufsz); + + /* Scanning start from the first page of the last block + * of whole flash + */ + bmtd.bbt = scan_bmt(bmtd.total_blks - 1); + if (!bmtd.bbt) { + /* BMT not found */ + if (bmtd.total_blks > BB_TABLE_MAX + BMT_TABLE_MAX) { + pr_info("nand: FATAL: Too many blocks, can not support!\n"); + return -1; + } + + bmtd.bbt = (struct bbbt *)nand_bbt_buf; + memset(bmt_tbl(bmtd.bbt), BMT_TBL_DEF_VAL, + bmtd.table_size * sizeof(struct bbmt)); + + if (scan_bad_blocks(bmtd.bbt)) + return -1; + + /* BMT always in the last valid block in pool */ + bmtd.bmt_blk_idx = upload_bmt(bmtd.bbt, bmtd.bmt_blk_idx); + block = bmt_tbl(bmtd.bbt)[bmtd.bmt_blk_idx].block; + pr_notice("[BBT] BMT.v2 is written into PBA:0x%x\n", block); + + if (bmtd.bmt_blk_idx == 0) + pr_info("nand: Warning: no available block in BMT pool!\n"); + else if (bmtd.bmt_blk_idx == (u16)-1) + return -1; + } + + return 0; +} + +int mtk_bmt_attach(struct mtd_info *mtd) +{ + static const struct mtk_bmt_ops v2_ops = { + .sig = "bmt", + .sig_len = 3, + .init = mtk_bmt_init_v2, + .remap_block = remap_block_v2, + .unmap_block = unmap_block_v2, + .get_mapping_block = get_mapping_block_index_v2, + .debug = mtk_bmt_debug_v2, + }; + struct device_node *np; + int ret = 0; + + if (bmtd.mtd) + return -ENOSPC; + + np = mtd_get_of_node(mtd); + if (!np) + return 0; + + if (of_property_read_bool(np, "mediatek,bmt-v2")) + bmtd.ops = &v2_ops; + else + return 0; + + bmtd.remap_range = of_get_property(np, "mediatek,bmt-remap-range", + &bmtd.remap_range_len); + bmtd.remap_range_len /= 8; + + bmtd.mtd = mtd; + mtk_bmt_replace_ops(mtd); + + bmtd.blk_size = mtd->erasesize; + bmtd.blk_shift = ffs(bmtd.blk_size) - 1; + bmtd.pg_size = mtd->writesize; + bmtd.pg_shift = ffs(bmtd.pg_size) - 1; + bmtd.total_blks = mtd->size >> bmtd.blk_shift; + + nand_data_buf = kzalloc(bmtd.pg_size, GFP_KERNEL); + if (!nand_data_buf) { pr_info("nand: FATAL ERR: allocate buffer failed!\n"); ret = -1; goto error; } - memset(nand_bbt_buf, 0xff, bufsz); memset(nand_data_buf, 0xff, bmtd.pg_size); - BBT_LOG("bbtbuf=0x%p(0x%x) dat=0x%p(0x%x)", - nand_bbt_buf, bufsz, nand_data_buf, bmtd.pg_size); - BBT_LOG("pool_lba=0x%x total_blks=0x%x bb_max=0x%x", - bmtd.pool_lba, bmtd.total_blks, bmtd.bb_max); + ret = bmtd.ops->init(np); + if (ret) + goto error; - /* Scanning start from the first page of the last block - * of whole flash - */ - bbt = scan_bmt(bmtd.total_blks - 1); - if (!bbt) { - /* BMT not found */ - if (bmtd.total_blks > BB_TABLE_MAX + BMT_TABLE_MAX) { - pr_info("nand: FATAL: Too many blocks, can not support!\n"); - ret = -1; - goto error; - } - - bbt = (struct bbbt *)nand_bbt_buf; - memset(bmt_tbl(bbt), BMT_TBL_DEF_VAL, bmtd.table_size * sizeof(struct bbmt)); - - if (scan_bad_blocks(bbt)) { - ret = -1; - goto error; - } - - /* BMT always in the last valid block in pool */ - bmtd.bmt_blk_idx = upload_bmt(bbt, bmtd.bmt_blk_idx); - block = bmt_tbl(bbt)[bmtd.bmt_blk_idx].block; - pr_notice("[BBT] BMT.v2 is written into PBA:0x%x\n", block); - - if (bmtd.bmt_blk_idx == 0) - pr_info("nand: Warning: no available block in BMT pool!\n"); - else if (bmtd.bmt_blk_idx == (u16)-1) { - ret = -1; - goto error; - } - } mtk_bmt_add_debugfs(); - - bmtd.bbt = bbt; return 0; error: From e2aa04d1e50104456902aea685e46c754b07ebf4 Mon Sep 17 00:00:00 2001 From: Felix Fietkau Date: Thu, 13 Jan 2022 18:30:51 +0100 Subject: [PATCH 20/29] kernel: mtk_bmt: add support for the bbt format used on mt7621 This does not have spare blocks for remapping, and it is also not suitable for random write access. It only skips over bad blocks on linear writes of an image to a partition. As such, it is really only suitable for the kernel partition, or other partitions with mostly static data Signed-off-by: Felix Fietkau --- .../generic/files/drivers/mtd/nand/mtk_bmt.c | 208 +++++++++++++++++- 1 file changed, 202 insertions(+), 6 deletions(-) diff --git a/target/linux/generic/files/drivers/mtd/nand/mtk_bmt.c b/target/linux/generic/files/drivers/mtd/nand/mtk_bmt.c index 7f55c1810d..7c06ee01f0 100644 --- a/target/linux/generic/files/drivers/mtd/nand/mtk_bmt.c +++ b/target/linux/generic/files/drivers/mtd/nand/mtk_bmt.c @@ -469,18 +469,26 @@ static bool remap_block_v2(u16 block, u16 mapped_block, int copy_len) } static bool -mapping_block_in_range(int block) +mapping_block_in_range(int block, int *start, int *end) { const __be32 *cur = bmtd.remap_range; u32 addr = block << bmtd.blk_shift; int i; - if (!cur || !bmtd.remap_range_len) + if (!cur || !bmtd.remap_range_len) { + *start = 0; + *end = bmtd.total_blks; return true; + } - for (i = 0; i < bmtd.remap_range_len; i++, cur += 2) - if (addr >= be32_to_cpu(cur[0]) && addr < be32_to_cpu(cur[1])) - return true; + for (i = 0; i < bmtd.remap_range_len; i++, cur += 2) { + if (addr < be32_to_cpu(cur[0]) || addr >= be32_to_cpu(cur[1])) + continue; + + *start = be32_to_cpu(cur[0]); + *end = be32_to_cpu(cur[1]); + return true; + } return false; } @@ -488,10 +496,12 @@ mapping_block_in_range(int block) static u16 get_mapping_block_index_v2(int block) { + int start, end; + if (block >= bmtd.pool_lba) return block; - if (!mapping_block_in_range(block)) + if (!mapping_block_in_range(block, &start, &end)) return block; return bmtd.bbt->bb_tbl[block]; @@ -938,6 +948,181 @@ static int mtk_bmt_init_v2(struct device_node *np) return 0; } +static bool +bbt_block_is_bad(u16 block) +{ + u8 cur = nand_bbt_buf[block / 4]; + + return cur & (3 << ((block % 4) * 2)); +} + +static void +bbt_set_block_state(u16 block, bool bad) +{ + u8 mask = (3 << ((block % 4) * 2)); + + if (bad) + nand_bbt_buf[block / 4] |= mask; + else + nand_bbt_buf[block / 4] &= ~mask; + + bbt_nand_erase(bmtd.bmt_blk_idx); + write_bmt(bmtd.bmt_blk_idx, nand_bbt_buf); +} + +static u16 +get_mapping_block_index_bbt(int block) +{ + int start, end, ofs; + int bad_blocks = 0; + int i; + + if (!mapping_block_in_range(block, &start, &end)) + return block; + + start >>= bmtd.blk_shift; + end >>= bmtd.blk_shift; + /* skip bad blocks within the mapping range */ + ofs = block - start; + for (i = start; i < end; i++) { + if (bbt_block_is_bad(i)) + bad_blocks++; + else if (ofs) + ofs--; + else + break; + } + + if (i < end) + return i; + + /* when overflowing, remap remaining blocks to bad ones */ + for (i = end - 1; bad_blocks > 0; i--) { + if (!bbt_block_is_bad(i)) + continue; + + bad_blocks--; + if (bad_blocks <= ofs) + return i; + } + + return block; +} + +static bool remap_block_bbt(u16 block, u16 mapped_blk, int copy_len) +{ + int start, end; + u16 new_blk; + + if (!mapping_block_in_range(block, &start, &end)) + return false; + + bbt_set_block_state(mapped_blk, true); + + new_blk = get_mapping_block_index_bbt(block); + bbt_nand_erase(new_blk); + if (copy_len > 0) + bbt_nand_copy(new_blk, mapped_blk, copy_len); + + return false; +} + +static void +unmap_block_bbt(u16 block) +{ + bbt_set_block_state(block, false); +} + +static int +mtk_bmt_read_bbt(void) +{ + u8 oob_buf[8]; + int i; + + for (i = bmtd.total_blks - 1; i >= bmtd.total_blks - 5; i--) { + u32 page = i << (bmtd.blk_shift - bmtd.pg_shift); + + if (bbt_nand_read(page, nand_bbt_buf, bmtd.pg_size, + oob_buf, sizeof(oob_buf))) { + pr_info("read_bbt: could not read block %d\n", i); + continue; + } + + if (oob_buf[0] != 0xff) { + pr_info("read_bbt: bad block at %d\n", i); + continue; + } + + if (memcmp(&oob_buf[1], "mtknand", 7) != 0) { + pr_info("read_bbt: signature mismatch in block %d\n", i); + print_hex_dump(KERN_INFO, "", DUMP_PREFIX_OFFSET, 16, 1, oob_buf, 8, 1); + continue; + } + + pr_info("read_bbt: found bbt at block %d\n", i); + bmtd.bmt_blk_idx = i; + return 0; + } + + return -EIO; +} + + +static int +mtk_bmt_init_bbt(struct device_node *np) +{ + int buf_size = round_up(bmtd.total_blks >> 2, bmtd.blk_size); + int ret; + + nand_bbt_buf = kmalloc(buf_size, GFP_KERNEL); + if (!nand_bbt_buf) + return -ENOMEM; + + memset(nand_bbt_buf, 0xff, buf_size); + bmtd.mtd->size -= 4 * bmtd.mtd->erasesize; + + ret = mtk_bmt_read_bbt(); + if (ret) + return ret; + + bmtd.bmt_pgs = buf_size / bmtd.pg_size; + + return 0; +} + +static int mtk_bmt_debug_bbt(void *data, u64 val) +{ + char buf[5]; + int i, k; + + switch (val) { + case 0: + for (i = 0; i < bmtd.total_blks; i += 4) { + u8 cur = nand_bbt_buf[i / 4]; + + for (k = 0; k < 4; k++, cur >>= 2) + buf[k] = (cur & 3) ? 'B' : '.'; + + buf[4] = 0; + printk("[%06x] %s\n", i * bmtd.blk_size, buf); + } + break; + case 100: +#if 0 + for (i = bmtd.bmt_blk_idx; i < bmtd.total_blks - 1; i++) + bbt_nand_erase(bmtd.bmt_blk_idx); +#endif + + bmtd.bmt_blk_idx = bmtd.total_blks - 1; + bbt_nand_erase(bmtd.bmt_blk_idx); + write_bmt(bmtd.bmt_blk_idx, nand_bbt_buf); + break; + default: + break; + } + return 0; +} + int mtk_bmt_attach(struct mtd_info *mtd) { static const struct mtk_bmt_ops v2_ops = { @@ -949,6 +1134,15 @@ int mtk_bmt_attach(struct mtd_info *mtd) .get_mapping_block = get_mapping_block_index_v2, .debug = mtk_bmt_debug_v2, }; + static const struct mtk_bmt_ops bbt_ops = { + .sig = "mtknand", + .sig_len = 7, + .init = mtk_bmt_init_bbt, + .remap_block = remap_block_bbt, + .unmap_block = unmap_block_bbt, + .get_mapping_block = get_mapping_block_index_bbt, + .debug = mtk_bmt_debug_bbt, + }; struct device_node *np; int ret = 0; @@ -961,6 +1155,8 @@ int mtk_bmt_attach(struct mtd_info *mtd) if (of_property_read_bool(np, "mediatek,bmt-v2")) bmtd.ops = &v2_ops; + else if (of_property_read_bool(np, "mediatek,bbt")) + bmtd.ops = &bbt_ops; else return 0; From 83b14ec026d611e3c07eedd4869db08ca682d46d Mon Sep 17 00:00:00 2001 From: Felix Fietkau Date: Thu, 13 Jan 2022 18:32:26 +0100 Subject: [PATCH 21/29] ramips: enable badblock table support on linksys ea7xxx devices Use remapping only on the kernel partitions. Signed-off-by: Felix Fietkau --- target/linux/ramips/dts/mt7621_linksys_ea7xxx.dtsi | 5 +++++ target/linux/ramips/mt7621/config-5.10 | 1 + 2 files changed, 6 insertions(+) diff --git a/target/linux/ramips/dts/mt7621_linksys_ea7xxx.dtsi b/target/linux/ramips/dts/mt7621_linksys_ea7xxx.dtsi index ecff6406d5..ec232968a6 100644 --- a/target/linux/ramips/dts/mt7621_linksys_ea7xxx.dtsi +++ b/target/linux/ramips/dts/mt7621_linksys_ea7xxx.dtsi @@ -76,6 +76,11 @@ &nand { status = "okay"; + mediatek,bbt; + mediatek,bmt-remap-range = + <0x180000 0x580000>, + <0x2980000 0x2d80000>; + partitions { compatible = "fixed-partitions"; #address-cells = <1>; diff --git a/target/linux/ramips/mt7621/config-5.10 b/target/linux/ramips/mt7621/config-5.10 index 67f7bf7e72..f3bf6fbb2b 100644 --- a/target/linux/ramips/mt7621/config-5.10 +++ b/target/linux/ramips/mt7621/config-5.10 @@ -154,6 +154,7 @@ CONFIG_MTD_NAND_CORE=y CONFIG_MTD_NAND_ECC=y CONFIG_MTD_NAND_ECC_SW_HAMMING=y CONFIG_MTD_NAND_MT7621=y +CONFIG_MTD_NAND_MTK_BMT=y CONFIG_MTD_PHYSMAP=y CONFIG_MTD_RAW_NAND=y CONFIG_MTD_ROUTERBOOT_PARTS=y From 0637093e8cb0e4cfb94dfcfe7b57afc23bf88852 Mon Sep 17 00:00:00 2001 From: Paul Spooren Date: Thu, 13 Jan 2022 08:50:19 +0100 Subject: [PATCH 22/29] iptables: enable nftable support by default OpenWrt plans to move over to firewall4 which uses nftables under the hood. To allow a smooth migration the package `iptables-nft` offer a transparent wrapper to apply iptables rules to nftables. Without the config option for nftables the package isn't installed and therefore can't be tested. This commit enabled it and therefore provides the wrapper. The size of the iptables package increases from 25436 to 26500 Bytes. Signed-off-by: Paul Spooren --- package/network/utils/iptables/Makefile | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/package/network/utils/iptables/Makefile b/package/network/utils/iptables/Makefile index 42d9af14b0..6aee5c6caf 100644 --- a/package/network/utils/iptables/Makefile +++ b/package/network/utils/iptables/Makefile @@ -10,7 +10,7 @@ include $(INCLUDE_DIR)/kernel.mk PKG_NAME:=iptables PKG_VERSION:=1.8.7 -PKG_RELEASE:=1 +PKG_RELEASE:=2 PKG_SOURCE_URL:=https://netfilter.org/projects/iptables/files PKG_SOURCE:=$(PKG_NAME)-$(PKG_VERSION).tar.bz2 @@ -60,7 +60,7 @@ define Package/iptables/config config IPTABLES_NFTABLES bool "Enable Nftables support" - default n + default y help This enable nftables support in iptables. endef From 0765466a42f46f7357e260866a4284ed567bb7ad Mon Sep 17 00:00:00 2001 From: Ansuel Smith Date: Mon, 10 Jan 2022 17:02:30 +0100 Subject: [PATCH 23/29] kernel: split kernel version to dedicated files Move the kernel versions and hash to dedicated files. This makes kernel bump quicker and fix some annoying problem with rebasing when multiple kernel bump are proposed. Signed-off-by: Ansuel Smith [Rebased on top of current master] Signed-off-by: Rui Salvaterra --- include/kernel-5.10 | 2 ++ include/kernel-5.4 | 2 ++ include/kernel-version.mk | 9 +++++---- 3 files changed, 9 insertions(+), 4 deletions(-) create mode 100644 include/kernel-5.10 create mode 100644 include/kernel-5.4 diff --git a/include/kernel-5.10 b/include/kernel-5.10 new file mode 100644 index 0000000000..e816698dec --- /dev/null +++ b/include/kernel-5.10 @@ -0,0 +1,2 @@ +LINUX_VERSION-5.10 = .90 +LINUX_KERNEL_HASH-5.10.90 = 945e4264c014a3d9dfc0a4639309dd1ec2fb545416556421f931b95da78c2725 diff --git a/include/kernel-5.4 b/include/kernel-5.4 new file mode 100644 index 0000000000..e85b7ad68e --- /dev/null +++ b/include/kernel-5.4 @@ -0,0 +1,2 @@ +LINUX_VERSION-5.4 = .170 +LINUX_KERNEL_HASH-5.4.170 = b09f74e0cf5fc7cf5de6aa932fe654c962cb10118bdbbdddb397022c6e6d382c diff --git a/include/kernel-version.mk b/include/kernel-version.mk index 677693ad08..1edb01df27 100644 --- a/include/kernel-version.mk +++ b/include/kernel-version.mk @@ -6,11 +6,12 @@ ifdef CONFIG_TESTING_KERNEL KERNEL_PATCHVER:=$(KERNEL_TESTING_PATCHVER) endif -LINUX_VERSION-5.4 = .170 -LINUX_VERSION-5.10 = .90 +KERNEL_DETAILS_FILE=$(INCLUDE_DIR)/kernel-$(KERNEL_PATCHVER) +ifeq ($(wildcard $(KERNEL_DETAILS_FILE)),) + $(error Missing kernel version/hash file for $(KERNEL_PATCHVER). Please create $(KERNEL_DETAILS_FILE)) +endif -LINUX_KERNEL_HASH-5.4.170 = b09f74e0cf5fc7cf5de6aa932fe654c962cb10118bdbbdddb397022c6e6d382c -LINUX_KERNEL_HASH-5.10.90 = 945e4264c014a3d9dfc0a4639309dd1ec2fb545416556421f931b95da78c2725 +include $(KERNEL_DETAILS_FILE) remove_uri_prefix=$(subst git://,,$(subst http://,,$(subst https://,,$(1)))) sanitize_uri=$(call qstrip,$(subst @,_,$(subst :,_,$(subst .,_,$(subst -,_,$(subst /,_,$(1))))))) From 557067d9b119ffe7f1e2029e0086491de105dfbc Mon Sep 17 00:00:00 2001 From: David Woodhouse Date: Tue, 11 Jan 2022 13:01:31 +0000 Subject: [PATCH 24/29] mediatek: mt7623: Enable PCIe bus 0 (and thus SATA) on U7623 Signed-off-by: David Woodhouse --- .../linux/mediatek/dts/mt7623a-unielec-u7623-02-emmc.dtsi | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/target/linux/mediatek/dts/mt7623a-unielec-u7623-02-emmc.dtsi b/target/linux/mediatek/dts/mt7623a-unielec-u7623-02-emmc.dtsi index 0a2972e23b..1c5a18de02 100644 --- a/target/linux/mediatek/dts/mt7623a-unielec-u7623-02-emmc.dtsi +++ b/target/linux/mediatek/dts/mt7623a-unielec-u7623-02-emmc.dtsi @@ -328,6 +328,10 @@ pinctrl-0 = <&pcie_default>; status = "okay"; + pcie@0,0 { + status = "okay"; + }; + pcie@1,0 { status = "okay"; }; @@ -337,6 +341,10 @@ }; }; +&pcie0_phy { + status = "okay"; +}; + &pcie1_phy { status = "okay"; }; From d9064c31ca06e7b67e05f629606cc54ea29508b2 Mon Sep 17 00:00:00 2001 From: Hans Dedecker Date: Fri, 14 Jan 2022 21:42:35 +0100 Subject: [PATCH 25/29] netifd: update to git HEAD 3043206 system: fix compilation with glibc 2.34 Signed-off-by: Hans Dedecker --- package/network/config/netifd/Makefile | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/package/network/config/netifd/Makefile b/package/network/config/netifd/Makefile index 0c8b7e92dd..0969c7718f 100644 --- a/package/network/config/netifd/Makefile +++ b/package/network/config/netifd/Makefile @@ -5,9 +5,9 @@ PKG_RELEASE:=1 PKG_SOURCE_PROTO:=git PKG_SOURCE_URL=$(PROJECT_GIT)/project/netifd.git -PKG_SOURCE_DATE:=2022-01-12 -PKG_SOURCE_VERSION:=96902e8fb712a070867a0a822d7877fdb10573f5 -PKG_MIRROR_HASH:=5112a8a0bc6d374bd0b336bebf59f5da29f23f521b80f40c69fcf37b1c7e74f1 +PKG_SOURCE_DATE:=2022-01-14 +PKG_SOURCE_VERSION:=3043206e94da412eb19dd72ea68edcaca545d84c +PKG_MIRROR_HASH:=2bf5a59e93968b00f69b8b7ebbdfd28353c36bc5e7f72225d725c24d0ac7265f PKG_MAINTAINER:=Felix Fietkau PKG_LICENSE:=GPL-2.0 From 2a31e9ca975d99b6216b2979a825f07253c8947e Mon Sep 17 00:00:00 2001 From: David Bauer Date: Sat, 8 Jan 2022 12:25:42 +0100 Subject: [PATCH 26/29] hostapd: add op-class to get_status output Include the current operation class to hostapd get_status interface. Signed-off-by: David Bauer --- package/network/services/hostapd/src/src/ap/ubus.c | 11 +++++++++-- 1 file changed, 9 insertions(+), 2 deletions(-) diff --git a/package/network/services/hostapd/src/src/ap/ubus.c b/package/network/services/hostapd/src/src/ap/ubus.c index bcb80f4a33..3c016124f9 100644 --- a/package/network/services/hostapd/src/src/ap/ubus.c +++ b/package/network/services/hostapd/src/src/ap/ubus.c @@ -411,9 +411,15 @@ hostapd_bss_get_status(struct ubus_context *ctx, struct ubus_object *obj, char ssid[SSID_MAX_LEN + 1]; char phy_name[17]; size_t ssid_len = SSID_MAX_LEN; + u8 channel = 0, op_class = 0; if (hapd->conf->ssid.ssid_len < SSID_MAX_LEN) ssid_len = hapd->conf->ssid.ssid_len; + + ieee80211_freq_to_channel_ext(hapd->iface->freq, + hapd->iconf->secondary_channel, + hostapd_get_oper_chwidth(hapd->iconf), + &op_class, &channel); blob_buf_init(&b, 0); blobmsg_add_string(&b, "status", hostapd_state_text(hapd->iface->state)); @@ -424,7 +430,8 @@ hostapd_bss_get_status(struct ubus_context *ctx, struct ubus_object *obj, blobmsg_add_string(&b, "ssid", ssid); blobmsg_add_u32(&b, "freq", hapd->iface->freq); - blobmsg_add_u32(&b, "channel", ieee80211_frequency_to_channel(hapd->iface->freq)); + blobmsg_add_u32(&b, "channel", channel); + blobmsg_add_u32(&b, "op_class", op_class); blobmsg_add_u32(&b, "beacon_interval", hapd->iconf->beacon_int); snprintf(phy_name, 17, "%s", hapd->iface->phy); @@ -1930,4 +1937,4 @@ int hostapd_ubus_notify_bss_transition_query( return ureq.resp; #endif -} \ No newline at end of file +} From 31545378641d45f5fac5ffc408a31b700b80121f Mon Sep 17 00:00:00 2001 From: David Bauer Date: Fri, 14 Jan 2022 22:03:24 +0100 Subject: [PATCH 27/29] lantiq: flag FritzBox 7360 family buttons active-low All buttons of the FritzBox 7360 family are active-low, not active-high. Corrent the GPIO flag. This fixes release triggers upon push of a button. Reported-by: Jan-Niklas Burfeind Signed-off-by: David Bauer --- .../files/arch/mips/boot/dts/lantiq/vr9_avm_fritz736x.dtsi | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/target/linux/lantiq/files/arch/mips/boot/dts/lantiq/vr9_avm_fritz736x.dtsi b/target/linux/lantiq/files/arch/mips/boot/dts/lantiq/vr9_avm_fritz736x.dtsi index 83ef415423..8406539f69 100644 --- a/target/linux/lantiq/files/arch/mips/boot/dts/lantiq/vr9_avm_fritz736x.dtsi +++ b/target/linux/lantiq/files/arch/mips/boot/dts/lantiq/vr9_avm_fritz736x.dtsi @@ -33,13 +33,13 @@ dect { label = "dect"; - gpios = <&gpio 1 GPIO_ACTIVE_HIGH>; + gpios = <&gpio 1 GPIO_ACTIVE_LOW>; linux,code = ; }; wifi { label = "wifi"; - gpios = <&gpio 29 GPIO_ACTIVE_HIGH>; + gpios = <&gpio 29 GPIO_ACTIVE_LOW>; linux,code = ; }; }; From 9e15dea36e977cfe9c31a08e32143c3280272fdc Mon Sep 17 00:00:00 2001 From: Matthias Schiffer Date: Fri, 14 Jan 2022 23:13:23 +0100 Subject: [PATCH 28/29] firmware-utils: update to latest master 84dbf8ee49f5 tplink-safeloader: fix Archer A7v5 factory flashing from vendor fw > v1.1.x Signed-off-by: Matthias Schiffer --- tools/firmware-utils/Makefile | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/tools/firmware-utils/Makefile b/tools/firmware-utils/Makefile index f5e978a7f0..0586cce732 100644 --- a/tools/firmware-utils/Makefile +++ b/tools/firmware-utils/Makefile @@ -11,9 +11,9 @@ PKG_RELEASE:=1 PKG_SOURCE_PROTO:=git PKG_SOURCE_URL=$(PROJECT_GIT)/project/firmware-utils.git -PKG_SOURCE_DATE:=2021-12-02 -PKG_SOURCE_VERSION:=56e8e19151743c923f48604c457850cf8eb52076 -PKG_MIRROR_HASH:=91f1bac08af2d856e93e651dc7c1ce6745f0b32b6fe4fb1917660494d7518057 +PKG_SOURCE_DATE:=2022-01-14 +PKG_SOURCE_VERSION:=84dbf8ee49f522d3a4528763c9473cf3dd7c8c52 +PKG_MIRROR_HASH:=aabf70dbc155d10175ee3b25f375953bef31bf7e25a2391fda8687aa93ea79e6 include $(INCLUDE_DIR)/host-build.mk include $(INCLUDE_DIR)/cmake.mk From 7f7705923a8299323057e78ccae4473b5bb05807 Mon Sep 17 00:00:00 2001 From: David Bauer Date: Sat, 15 Jan 2022 11:15:15 +0100 Subject: [PATCH 29/29] lantiq: add additional caldata offsets It was reported the AVM FritzBox 7430 has different offsets for the caldata depending on the device. Whether this is due to custom bad-block handling or up to the installed bootloader-version is unknown. Try both known caldata offsets like it is already done for the ipq40xx NAND based models. Use the same approach for the FritzBox 7412. While it is currently unknown, whether it is affected, applying the same logic has no downsides. Signed-off-by: David Bauer --- .../xrx200/base-files/etc/hotplug.d/firmware/12-ath9k-eeprom | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/target/linux/lantiq/xrx200/base-files/etc/hotplug.d/firmware/12-ath9k-eeprom b/target/linux/lantiq/xrx200/base-files/etc/hotplug.d/firmware/12-ath9k-eeprom index 07463a8061..e4683af960 100644 --- a/target/linux/lantiq/xrx200/base-files/etc/hotplug.d/firmware/12-ath9k-eeprom +++ b/target/linux/lantiq/xrx200/base-files/etc/hotplug.d/firmware/12-ath9k-eeprom @@ -23,10 +23,9 @@ case "$FIRMWARE" in avm,fritz7360-v2) caldata_extract "urlader" 0x985 0x1000 ;; - avm,fritz7412) - /usr/bin/fritz_cal_extract -i 1 -s 0x1e000 -e 0x207 -l 4096 -o /lib/firmware/$FIRMWARE $(find_mtd_chardev "urlader") - ;; + avm,fritz7412|\ avm,fritz7430) + /usr/bin/fritz_cal_extract -i 1 -s 0x1e000 -e 0x207 -l 4096 -o /lib/firmware/$FIRMWARE $(find_mtd_chardev "urlader") || \ /usr/bin/fritz_cal_extract -i 1 -s 0x1e800 -e 0x207 -l 4096 -o /lib/firmware/$FIRMWARE $(find_mtd_chardev "urlader") ;; bt,homehub-v5a)