BBM is part of USER_DATA section, so we should remove it twice
This was working ok because we are on the safe size, advertising that
there was 2 bytes less available than reality.
But we can't change old platforms, since it may lead to a different ECC
strength, so, introduce a legacy flag for old platforms, and switch the
new platforms to the correct count.
Signed-off-by: Richard Genoud <richard.genoud@bootlin.com>
---
drivers/mtd/nand/raw/sunxi_nand.c | 23 ++++++++++++++++++++---
1 file changed, 20 insertions(+), 3 deletions(-)
diff --git a/drivers/mtd/nand/raw/sunxi_nand.c b/drivers/mtd/nand/raw/sunxi_nand.c
index 9c6e0625e34f..99d305bbda53 100644
--- a/drivers/mtd/nand/raw/sunxi_nand.c
+++ b/drivers/mtd/nand/raw/sunxi_nand.c
@@ -281,6 +281,8 @@ static inline struct sunxi_nand_chip *to_sunxi_nand(struct nand_chip *nand)
* @has_ecc_block_512: If the ECC can handle 512B or only 1024B chuncks
* @has_ecc_clk: If the controller needs an ECC clock.
* @has_mbus_clk: If the controller needs a mbus clock.
+ * @legacy_max_strength:If the maximize strength function was off by 2 bytes
+ * NB: this should not be used in new controllers
* @reg_io_data: I/O data register
* @reg_ecc_err_cnt: ECC error counter register
* @reg_user_data: User data register
@@ -310,6 +312,7 @@ struct sunxi_nfc_caps {
bool has_ecc_block_512;
bool has_ecc_clk;
bool has_mbus_clk;
+ bool legacy_max_strength;
unsigned int reg_io_data;
unsigned int reg_ecc_err_cnt;
unsigned int reg_user_data;
@@ -1811,10 +1814,22 @@ static int sunxi_nand_hw_ecc_ctrl_init(struct nand_chip *nand,
ecc->size = 1024;
nsectors = mtd->writesize / ecc->size;
- /* Reserve 2 bytes for the BBM */
- bytes = (mtd->oobsize - 2) / nsectors;
+ /*
+ * The 2 BBM bytes should not be removed from the grand total,
+ * because they are part of the USER_DATA_SZ.
+ * But we can't modify that for older platform since it may
+ * result in a stronger ECC at the end, and break the
+ * compatibility.
+ */
+ if (nfc->caps->legacy_max_strength)
+ bytes = (mtd->oobsize - 2) / nsectors;
+ else
+ bytes = mtd->oobsize / nsectors;
- /* 4 non-ECC bytes are added before each ECC bytes section */
+ /*
+ * USER_DATA_SZ non-ECC bytes are added before each ECC bytes
+ * section, they contain the 2 BBM bytes
+ */
bytes -= USER_DATA_SZ;
/* and bytes has to be even. */
@@ -2379,6 +2394,7 @@ static const u8 sunxi_user_data_len_h6[] = {
static const struct sunxi_nfc_caps sunxi_nfc_a10_caps = {
.has_ecc_block_512 = true,
+ .legacy_max_strength = true,
.reg_io_data = NFC_REG_A10_IO_DATA,
.reg_ecc_err_cnt = NFC_REG_A10_ECC_ERR_CNT,
.reg_user_data = NFC_REG_A10_USER_DATA,
@@ -2400,6 +2416,7 @@ static const struct sunxi_nfc_caps sunxi_nfc_a10_caps = {
static const struct sunxi_nfc_caps sunxi_nfc_a23_caps = {
.has_mdma = true,
.has_ecc_block_512 = true,
+ .legacy_max_strength = true,
.reg_io_data = NFC_REG_A23_IO_DATA,
.reg_ecc_err_cnt = NFC_REG_A10_ECC_ERR_CNT,
.reg_user_data = NFC_REG_A10_USER_DATA,
Dne petek, 20. februar 2026 ob 17:10:08 Srednjeevropski standardni čas je Richard Genoud napisal(a):
> BBM is part of USER_DATA section, so we should remove it twice
>
> This was working ok because we are on the safe size, advertising that
> there was 2 bytes less available than reality.
Missing "in" before "reality".
>
> But we can't change old platforms, since it may lead to a different ECC
> strength, so, introduce a legacy flag for old platforms, and switch the
> new platforms to the correct count.
There aren't any users of H6/H616 driver, right? If it would be, ECC strength
can't be changed, since it can impact systems, which already use it.
Best regards,
Jernej
>
> Signed-off-by: Richard Genoud <richard.genoud@bootlin.com>
> ---
> drivers/mtd/nand/raw/sunxi_nand.c | 23 ++++++++++++++++++++---
> 1 file changed, 20 insertions(+), 3 deletions(-)
>
> diff --git a/drivers/mtd/nand/raw/sunxi_nand.c b/drivers/mtd/nand/raw/sunxi_nand.c
> index 9c6e0625e34f..99d305bbda53 100644
> --- a/drivers/mtd/nand/raw/sunxi_nand.c
> +++ b/drivers/mtd/nand/raw/sunxi_nand.c
> @@ -281,6 +281,8 @@ static inline struct sunxi_nand_chip *to_sunxi_nand(struct nand_chip *nand)
> * @has_ecc_block_512: If the ECC can handle 512B or only 1024B chuncks
> * @has_ecc_clk: If the controller needs an ECC clock.
> * @has_mbus_clk: If the controller needs a mbus clock.
> + * @legacy_max_strength:If the maximize strength function was off by 2 bytes
> + * NB: this should not be used in new controllers
> * @reg_io_data: I/O data register
> * @reg_ecc_err_cnt: ECC error counter register
> * @reg_user_data: User data register
> @@ -310,6 +312,7 @@ struct sunxi_nfc_caps {
> bool has_ecc_block_512;
> bool has_ecc_clk;
> bool has_mbus_clk;
> + bool legacy_max_strength;
> unsigned int reg_io_data;
> unsigned int reg_ecc_err_cnt;
> unsigned int reg_user_data;
> @@ -1811,10 +1814,22 @@ static int sunxi_nand_hw_ecc_ctrl_init(struct nand_chip *nand,
> ecc->size = 1024;
> nsectors = mtd->writesize / ecc->size;
>
> - /* Reserve 2 bytes for the BBM */
> - bytes = (mtd->oobsize - 2) / nsectors;
> + /*
> + * The 2 BBM bytes should not be removed from the grand total,
> + * because they are part of the USER_DATA_SZ.
> + * But we can't modify that for older platform since it may
> + * result in a stronger ECC at the end, and break the
> + * compatibility.
> + */
> + if (nfc->caps->legacy_max_strength)
> + bytes = (mtd->oobsize - 2) / nsectors;
> + else
> + bytes = mtd->oobsize / nsectors;
>
> - /* 4 non-ECC bytes are added before each ECC bytes section */
> + /*
> + * USER_DATA_SZ non-ECC bytes are added before each ECC bytes
> + * section, they contain the 2 BBM bytes
> + */
> bytes -= USER_DATA_SZ;
>
> /* and bytes has to be even. */
> @@ -2379,6 +2394,7 @@ static const u8 sunxi_user_data_len_h6[] = {
>
> static const struct sunxi_nfc_caps sunxi_nfc_a10_caps = {
> .has_ecc_block_512 = true,
> + .legacy_max_strength = true,
> .reg_io_data = NFC_REG_A10_IO_DATA,
> .reg_ecc_err_cnt = NFC_REG_A10_ECC_ERR_CNT,
> .reg_user_data = NFC_REG_A10_USER_DATA,
> @@ -2400,6 +2416,7 @@ static const struct sunxi_nfc_caps sunxi_nfc_a10_caps = {
> static const struct sunxi_nfc_caps sunxi_nfc_a23_caps = {
> .has_mdma = true,
> .has_ecc_block_512 = true,
> + .legacy_max_strength = true,
> .reg_io_data = NFC_REG_A23_IO_DATA,
> .reg_ecc_err_cnt = NFC_REG_A10_ECC_ERR_CNT,
> .reg_user_data = NFC_REG_A10_USER_DATA,
>
Le 21/02/2026 à 10:21, Jernej Škrabec a écrit :
> Dne petek, 20. februar 2026 ob 17:10:08 Srednjeevropski standardni čas je Richard Genoud napisal(a):
>> BBM is part of USER_DATA section, so we should remove it twice
>>
>> This was working ok because we are on the safe size, advertising that
>> there was 2 bytes less available than reality.
>
> Missing "in" before "reality".
ok
>
>>
>> But we can't change old platforms, since it may lead to a different ECC
>> strength, so, introduce a legacy flag for old platforms, and switch the
>> new platforms to the correct count.
>
> There aren't any users of H6/H616 driver, right? If it would be, ECC strength
> can't be changed, since it can impact systems, which already use it.
AFAIK, the only users for now would be on whatsminer boards and are not
impacted by this (the ECC strength won't change from 32 to 40bits on
those boards).
(Adding James in Cc, as he may know more on the subject)
>
> Best regards,
> Jernej
>
>>
>> Signed-off-by: Richard Genoud <richard.genoud@bootlin.com>
>> ---
>> drivers/mtd/nand/raw/sunxi_nand.c | 23 ++++++++++++++++++++---
>> 1 file changed, 20 insertions(+), 3 deletions(-)
>>
>> diff --git a/drivers/mtd/nand/raw/sunxi_nand.c b/drivers/mtd/nand/raw/sunxi_nand.c
>> index 9c6e0625e34f..99d305bbda53 100644
>> --- a/drivers/mtd/nand/raw/sunxi_nand.c
>> +++ b/drivers/mtd/nand/raw/sunxi_nand.c
>> @@ -281,6 +281,8 @@ static inline struct sunxi_nand_chip *to_sunxi_nand(struct nand_chip *nand)
>> * @has_ecc_block_512: If the ECC can handle 512B or only 1024B chuncks
>> * @has_ecc_clk: If the controller needs an ECC clock.
>> * @has_mbus_clk: If the controller needs a mbus clock.
>> + * @legacy_max_strength:If the maximize strength function was off by 2 bytes
>> + * NB: this should not be used in new controllers
>> * @reg_io_data: I/O data register
>> * @reg_ecc_err_cnt: ECC error counter register
>> * @reg_user_data: User data register
>> @@ -310,6 +312,7 @@ struct sunxi_nfc_caps {
>> bool has_ecc_block_512;
>> bool has_ecc_clk;
>> bool has_mbus_clk;
>> + bool legacy_max_strength;
>> unsigned int reg_io_data;
>> unsigned int reg_ecc_err_cnt;
>> unsigned int reg_user_data;
>> @@ -1811,10 +1814,22 @@ static int sunxi_nand_hw_ecc_ctrl_init(struct nand_chip *nand,
>> ecc->size = 1024;
>> nsectors = mtd->writesize / ecc->size;
>>
>> - /* Reserve 2 bytes for the BBM */
>> - bytes = (mtd->oobsize - 2) / nsectors;
>> + /*
>> + * The 2 BBM bytes should not be removed from the grand total,
>> + * because they are part of the USER_DATA_SZ.
>> + * But we can't modify that for older platform since it may
>> + * result in a stronger ECC at the end, and break the
>> + * compatibility.
>> + */
>> + if (nfc->caps->legacy_max_strength)
>> + bytes = (mtd->oobsize - 2) / nsectors;
>> + else
>> + bytes = mtd->oobsize / nsectors;
>>
>> - /* 4 non-ECC bytes are added before each ECC bytes section */
>> + /*
>> + * USER_DATA_SZ non-ECC bytes are added before each ECC bytes
>> + * section, they contain the 2 BBM bytes
>> + */
>> bytes -= USER_DATA_SZ;
>>
>> /* and bytes has to be even. */
>> @@ -2379,6 +2394,7 @@ static const u8 sunxi_user_data_len_h6[] = {
>>
>> static const struct sunxi_nfc_caps sunxi_nfc_a10_caps = {
>> .has_ecc_block_512 = true,
>> + .legacy_max_strength = true,
>> .reg_io_data = NFC_REG_A10_IO_DATA,
>> .reg_ecc_err_cnt = NFC_REG_A10_ECC_ERR_CNT,
>> .reg_user_data = NFC_REG_A10_USER_DATA,
>> @@ -2400,6 +2416,7 @@ static const struct sunxi_nfc_caps sunxi_nfc_a10_caps = {
>> static const struct sunxi_nfc_caps sunxi_nfc_a23_caps = {
>> .has_mdma = true,
>> .has_ecc_block_512 = true,
>> + .legacy_max_strength = true,
>> .reg_io_data = NFC_REG_A23_IO_DATA,
>> .reg_ecc_err_cnt = NFC_REG_A10_ECC_ERR_CNT,
>> .reg_user_data = NFC_REG_A10_USER_DATA,
>>
>
>
>
>
--
Richard Genoud, Bootlin
Embedded Linux and Kernel engineering
https://bootlin.com
© 2016 - 2026 Red Hat, Inc.