Merge Official Source

Signed-off-by: Tianling Shen <i@cnsztl.eu.org>
This commit is contained in:
Tianling Shen 2022-01-15 19:29:20 +08:00
commit 64f4b111aa
No known key found for this signature in database
GPG Key ID: 6850B6345C862176
38 changed files with 1813 additions and 956 deletions

2
include/kernel-5.10 Normal file
View File

@ -0,0 +1,2 @@
LINUX_VERSION-5.10 = .90
LINUX_KERNEL_HASH-5.10.90 = 945e4264c014a3d9dfc0a4639309dd1ec2fb545416556421f931b95da78c2725

2
include/kernel-5.4 Normal file
View File

@ -0,0 +1,2 @@
LINUX_VERSION-5.4 = .170
LINUX_KERNEL_HASH-5.4.170 = b09f74e0cf5fc7cf5de6aa932fe654c962cb10118bdbbdddb397022c6e6d382c

View File

@ -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)))))))

View File

@ -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-14
PKG_SOURCE_VERSION:=3043206e94da412eb19dd72ea68edcaca545d84c
PKG_MIRROR_HASH:=2bf5a59e93968b00f69b8b7ebbdfd28353c36bc5e7f72225d725c24d0ac7265f
PKG_MAINTAINER:=Felix Fietkau <nbd@nbd.name>
PKG_LICENSE:=GPL-2.0

View File

@ -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
}
}

View File

@ -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

View File

@ -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

View File

@ -127,6 +127,10 @@
};
};
&ref {
clock-frequency = <25000000>;
};
&spi {
status = "okay";
@ -194,7 +198,6 @@
gmac-config {
device = <&gmac>;
rgmii-gmac0 = <1>;
rgmii-enabled = <1>;
rxd-delay = <1>;
txd-delay = <1>;
};

View File

@ -99,7 +99,6 @@
partition@0 {
label = "RouterBoot";
reg = <0x0 0x20000>;
read-only;
compatible = "mikrotik,routerboot-partitions";
#address-cells = <1>;
#size-cells = <1>;

View File

@ -38,7 +38,6 @@
partition@0 {
label = "RouterBoot";
reg = <0x0 0x20000>;
read-only;
compatible = "mikrotik,routerboot-partitions";
#address-cells = <1>;
#size-cells = <1>;

View File

@ -73,7 +73,6 @@
partition@0 {
label = "RouterBoot";
reg = <0x0 0x20000>;
read-only;
compatible = "mikrotik,routerboot-partitions";
#address-cells = <1>;
#size-cells = <1>;

View File

@ -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>;

View File

@ -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

View File

@ -3661,6 +3661,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
@ -3688,6 +3689,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

File diff suppressed because it is too large Load Diff

View File

@ -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;
}

View File

@ -56,23 +56,12 @@
#include "routerboot.h"
#define RB_SOFTCONFIG_VER "0.03"
#define RB_SOFTCONFIG_VER "0.05"
#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
@ -705,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;
@ -716,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;
@ -799,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;
}

View File

@ -13,6 +13,7 @@
#include <linux/module.h>
#include <linux/kernel.h>
#include <linux/sysfs.h>
#include <linux/mtd/mtd.h>
#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

View File

@ -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);

View File

@ -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

View File

@ -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/

View File

@ -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 <git@johnthomson.fastmail.com.au>
X-Patchwork-Id: 1489105
X-Patchwork-Delegate: tudor.ambarus@gmail.com
Return-Path:
<linux-mtd-bounces+incoming=patchwork.ozlabs.org@lists.infradead.org>
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=<UNKNOWN>)
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 <incoming@patchwork.ozlabs.org>; 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: <xms:C-2-YD2uka4HsA6gcdsV2Ia7vebY4Yjp9E8q7KBMb54jnAzGL7-67Q>
<xme:C-2-YCEaxASy5VlcrvNO_jLFpMDGkFCRsuVNuZGEQsiRZygk8jPHWq7unPjeT6uYS
2pUP6PrTQ2rggjEIg>
X-ME-Received:
<xmr:C-2-YD4exeK49N_YZWWf2BWDhVyCbCY3wwvjTyDOFxeugx7Jg08pzMUToo9oJjrBpcVTaA3kbfk>
X-ME-Proxy-Cause:
gggruggvucftvghtrhhoucdtuddrgeduledrfedtkedgjeduucetufdoteggodetrfdotf
fvucfrrhhofhhilhgvmecuhfgrshhtofgrihhlpdfqfgfvpdfurfetoffkrfgpnffqhgen
uceurghilhhouhhtmecufedttdenucesvcftvggtihhpihgvnhhtshculddquddttddmne
cujfgurhephffvufffkffoggfgsedtkeertdertddtnecuhfhrohhmpeflohhhnhcuvfhh
ohhmshhonhcuoehgihhtsehjohhhnhhthhhomhhsohhnrdhfrghsthhmrghilhdrtghomh
drrghuqeenucggtffrrghtthgvrhhnpefffeeihfdukedtuedufeetieeuudfhhefhkefh
tefgtdeuffekffelleetveduieenucevlhhushhtvghrufhiiigvpedtnecurfgrrhgrmh
epmhgrihhlfhhrohhmpehgihhtsehjohhhnhhthhhomhhsohhnrdhfrghsthhmrghilhdr
tghomhdrrghu
X-ME-Proxy: <xmx:C-2-YI0AJZGjcB3wIbI9BoC9X8VNl4i9A7cQnBkvwZ25czWJlkKCLw>
<xmx:C-2-YGGufw99T-O81-FeiSyEruv6_Pr0IHFhspQdxjv5k1VFTZ0lzQ>
<xmx:C-2-YJ8BW7DhSDSCEAPSJWrwh_hHP79qreTZtWh_kOUwSh1c0MMlAg>
<xmx:Du2-YJBeX2Fg9oFZVXGwEJ1ZrZnXHiAqNON8tbpzquYgcm2o_LM48g>
Received: by mail.messagingengine.com (Postfix) with ESMTPA; Tue,
8 Jun 2021 00:07:35 -0400 (EDT)
From: John Thomson <git@johnthomson.fastmail.com.au>
To: Miquel Raynal <miquel.raynal@bootlin.com>,
Richard Weinberger <richard@nod.at>, Vignesh Raghavendra <vigneshr@ti.com>,
Tudor Ambarus <tudor.ambarus@microchip.com>,
Michael Walle <michael@walle.cc>, Pratyush Yadav <p.yadav@ti.com>,
linux-mtd@lists.infradead.org
Cc: linux-kernel@vger.kernel.org,
John Thomson <git@johnthomson.fastmail.com.au>,
kernel test robot <lkp@intel.com>, Dan Carpenter <dan.carpenter@oracle.com>
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 <linux-mtd.lists.infradead.org>
List-Unsubscribe: <http://lists.infradead.org/mailman/options/linux-mtd>,
<mailto:linux-mtd-request@lists.infradead.org?subject=unsubscribe>
List-Archive: <http://lists.infradead.org/pipermail/linux-mtd/>
List-Post: <mailto:linux-mtd@lists.infradead.org>
List-Help: <mailto:linux-mtd-request@lists.infradead.org?subject=help>
List-Subscribe: <http://lists.infradead.org/mailman/listinfo/linux-mtd>,
<mailto:linux-mtd-request@lists.infradead.org?subject=subscribe>
Sender: "linux-mtd" <linux-mtd-bounces@lists.infradead.org>
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 <git@johnthomson.fastmail.com.au>
---
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 <lkp@intel.com>
Reported-by: Dan Carpenter <dan.carpenter@oracle.com>
---
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

View File

@ -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

View File

@ -33,13 +33,13 @@
dect {
label = "dect";
gpios = <&gpio 1 GPIO_ACTIVE_HIGH>;
gpios = <&gpio 1 GPIO_ACTIVE_LOW>;
linux,code = <KEY_PHONE>;
};
wifi {
label = "wifi";
gpios = <&gpio 29 GPIO_ACTIVE_HIGH>;
gpios = <&gpio 29 GPIO_ACTIVE_LOW>;
linux,code = <KEY_RFKILL>;
};
};

View File

@ -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)

View File

@ -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;
};
};

View File

@ -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";
};

View File

@ -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

View File

@ -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)

View File

@ -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"
;;

View File

@ -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 <xiangsheng.hou@mediatek.com>
+ * Copyright (c) 2020 Felix Fietkau <nbd@nbd.name>
+ *
+ * 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 <linux/slab.h>
+#include <linux/gfp.h>
+#include <linux/kernel.h>
+#include <linux/of.h>
+#include <linux/mtd/mtd.h>
+#include <linux/mtd/partitions.h>
+#include <linux/mtd/mtk_bmt.h>
+#include <linux/module.h>
+#include <linux/debugfs.h>
+
+#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 <xiangsheng.hou@mediatek.com>, Felix Fietkau <nbd@nbd.name>");
+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 <linux/dma-mapping.h>
#include <linux/wait.h>
#include <linux/mtd/mtd.h>
+#include <linux/mtd/mtk_bmt.h>
#include <linux/mtd/partitions.h>
#include <linux/of_platform.h>
@@ -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)

View File

@ -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 <linux/dma-mapping.h>
#include <linux/wait.h>
#include <linux/mtd/mtd.h>
+#include <linux/mtd/mtk_bmt.h>
#include <linux/mtd/partitions.h>
#include <linux/of_platform.h>
@@ -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)

View File

@ -76,6 +76,11 @@
&nand {
status = "okay";
mediatek,bbt;
mediatek,bmt-remap-range =
<0x180000 0x580000>,
<0x2980000 0x2d80000>;
partitions {
compatible = "fixed-partitions";
#address-cells = <1>;

View File

@ -37,7 +37,6 @@
partition@0 {
label = "RouterBoot";
reg = <0x0 0x40000>;
read-only;
compatible = "mikrotik,routerboot-partitions";
#address-cells = <1>;
#size-cells = <1>;

View File

@ -154,10 +154,12 @@ 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
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

View File

@ -1022,7 +1022,7 @@ Signed-off-by: Weijie Gao <weijie.gao@mediatek.com>
+ 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);

View File

@ -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