barebox@lists.infradead.org

[PATCH] nand bad block erase and i.MX bbt tool

Sascha Hauer
04.03.2013 10:14 UTC
This series contains some NAND related updates.

First an option is introduced to allow erasing bad blocks. While
this is a dangerous operation it is needed during development or
when some foreign flash driver has touched the NAND. The option
is hidden behind a Kconfig option and must be enabled explicitly
with a device parameter.

Second the BBT (bad block table) type is exposed via a device
parameter. This is useful to get information about the bbt.

Last not least the i.MX NAND driver no longer silently creates
a BBT on 2k NAND flashes. This does not work properly because
the Controller uses a non standard NAND layout and will not
detect the factory bad block markers properly on a virgin
NAND flash. We work around this by adding a command which creates
a BBT on demand using the correct information. Whether this
command needs to be executed can be detected with the bbt device
parameter.

Sascha

The following changes since commit 94e71b843f6456abacc2fe76a5c375a461fabdf7:

libubi: Use global mtd_all_ff function (2013-03-04 10:54:46 +0100)

are available in the git repository at:

none

for you to fetch changes up to c3afd8676888d93d831bd4a8e71f1560ee5616c4:

mtd: nand: Add command to generate a flash BBT (2013-03-04 11:06:23 +0100)

----------------------------------------------------------------
Sascha Hauer (10):
mtd: nand: register nand flashes with nand specific function
mtd: Add parameter to allow erasing bad blocks
mtd nand: introduce bbm.h
nand command: use loff_t for block offset
nand command: use enumeration for command instead of bitmask
nand command: check for <dev> directly after option parsing
mtd: nand: replace NAND_USE_FLASH_BBT with NAND_BBT_USE_FLASH
mtd nand i.MX: remove unused code
mtd: nand: Add bbt parameter
mtd: nand: Add command to generate a flash BBT

commands/nand.c | 48 ++++----
drivers/mtd/core.c | 6 +-
drivers/mtd/mtdraw.c | 6 +-
drivers/mtd/nand/Kconfig | 14 +++
drivers/mtd/nand/Makefile | 1 +
drivers/mtd/nand/atmel_nand.c | 4 +-
drivers/mtd/nand/nand_base.c | 50 +++++++++
drivers/mtd/nand/nand_bbt.c | 4 +-
drivers/mtd/nand/nand_imx.c | 30 +++--
drivers/mtd/nand/nand_imx_bbm.c | 220 +++++++++++++++++++++++++++++++++++++
drivers/mtd/nand/nand_mxs.c | 2 +-
drivers/mtd/nand/nand_omap_gpmc.c | 2 +-
drivers/mtd/nand/nand_s3c24xx.c | 4 +-
drivers/mtd/nand/nand_write.c | 5 +-
drivers/mtd/nand/nomadik_nand.c | 2 +-
include/linux/mtd/bbm.h | 92 ++++++++++++++++
include/linux/mtd/mtd.h | 3 +
include/linux/mtd/nand.h | 86 ++-------------
18 files changed, 456 insertions(+), 123 deletions(-)
create mode 100644 drivers/mtd/nand/nand_imx_bbm.c
create mode 100644 include/linux/mtd/bbm.h

_______________________________________________
barebox mailing list
barebox@lists.infradead.org
http://lists.infradead.org/mailman/listinfo/barebox
Sascha Hauer
04.03.2013 10:14 UTC
Signed-off-by: Sascha Hauer <s.hauer@pengutronix.de>
---
commands/nand.c | 11 ++++++-----
1 file changed, 6 insertions(+), 5 deletions(-)

diff --git a/commands/nand.c b/commands/nand.c
index f000142..d00845f 100644
--- a/commands/nand.c
+++ b/commands/nand.c
@@ -36,7 +36,8 @@
static int do_nand(int argc, char *argv[])
{
int opt;
- int command = 0, badblock = 0;
+ int command = 0;
+ loff_t badblock = 0;

while((opt = getopt(argc, argv, "adb:")) > 0) {
if (command) {
@@ -53,7 +54,7 @@ static int do_nand(int argc, char *argv[])
break;
case 'b':
command = NAND_MARKBAD;
- badblock = simple_strtoul(optarg, NULL, 0);
+ badblock = strtoull_suffix(optarg, NULL, 0);
}
}

@@ -76,9 +77,9 @@ static int do_nand(int argc, char *argv[])
if (command & NAND_MARKBAD) {
if (optind < argc) {
int ret = 0, fd;
- loff_t __badblock = badblock;

- printf("marking block at 0x%08x on %s as bad\n", badblock, argv[optind]);
+ printf("marking block at 0x%08llx on %s as bad\n",
+ badblock, argv[optind]);

fd = open(argv[optind], O_RDWR);
if (fd < 0) {
@@ -86,7 +87,7 @@ static int do_nand(int argc, char *argv[])
return 1;
}

- ret = ioctl(fd, MEMSETBADBLOCK, &__badblock);
+ ret = ioctl(fd, MEMSETBADBLOCK, &badblock);
if (ret)
perror("ioctl");

--
1.7.10.4

_______________________________________________
barebox mailing list
barebox@lists.infradead.org
http://lists.infradead.org/mailman/listinfo/barebox
Sascha Hauer
04.03.2013 10:14 UTC
This allows us to have some NAND specific stuff during registration,
like for example adding NAND specific device parameters.

Signed-off-by: Sascha Hauer <s.hauer@pengutronix.de>
---
drivers/mtd/nand/atmel_nand.c | 2 +-
drivers/mtd/nand/nand_base.c | 11 +++++++++++
drivers/mtd/nand/nand_imx.c | 2 +-
drivers/mtd/nand/nand_mxs.c | 2 +-
drivers/mtd/nand/nand_omap_gpmc.c | 2 +-
drivers/mtd/nand/nand_s3c24xx.c | 2 +-
drivers/mtd/nand/nomadik_nand.c | 2 +-
include/linux/mtd/nand.h | 2 +-
8 files changed, 18 insertions(+), 7 deletions(-)

diff --git a/drivers/mtd/nand/atmel_nand.c b/drivers/mtd/nand/atmel_nand.c
index 63484f8..81ccad9 100644
--- a/drivers/mtd/nand/atmel_nand.c
+++ b/drivers/mtd/nand/atmel_nand.c
@@ -1223,7 +1223,7 @@ static int __init atmel_nand_probe(struct device_d *dev)
goto err_scan_tail;
}

- add_mtd_device(mtd, "nand");
+ add_mtd_nand_device(mtd, "nand");

if (!res)
return res;
diff --git a/drivers/mtd/nand/nand_base.c b/drivers/mtd/nand/nand_base.c
index 411aba7..c0345c7 100644
--- a/drivers/mtd/nand/nand_base.c
+++ b/drivers/mtd/nand/nand_base.c
@@ -1672,4 +1672,15 @@ EXPORT_SYMBOL(nand_scan_ident);
EXPORT_SYMBOL(nand_scan_tail);
EXPORT_SYMBOL(nand_release);

+int add_mtd_nand_device(struct mtd_info *mtd, char *devname)
+{
+ int ret;
+
+ ret = add_mtd_device(mtd, devname);
+ if (ret)
+ return ret;
+
+ return ret;
+}
+
#endif /* DOXYGEN_SHOULD_SKIP_THIS */
diff --git a/drivers/mtd/nand/nand_imx.c b/drivers/mtd/nand/nand_imx.c
index dd66861..842c1de 100644
--- a/drivers/mtd/nand/nand_imx.c
+++ b/drivers/mtd/nand/nand_imx.c
@@ -1260,7 +1260,7 @@ static int __init imxnd_probe(struct device_d *dev)
goto escan;
}

- add_mtd_device(mtd, "nand");
+ add_mtd_nand_device(mtd, "nand");

dev->priv = host;

diff --git a/drivers/mtd/nand/nand_mxs.c b/drivers/mtd/nand/nand_mxs.c
index 3812ac9..dd43a95 100644
--- a/drivers/mtd/nand/nand_mxs.c
+++ b/drivers/mtd/nand/nand_mxs.c
@@ -1252,7 +1252,7 @@ static int mxs_nand_probe(struct device_d *dev)
if (err)
goto err2;

- return add_mtd_device(mtd, "nand");
+ return add_mtd_nand_device(mtd, "nand");
err2:
free(nand_info->data_buf);
free(nand_info->cmd_buf);
diff --git a/drivers/mtd/nand/nand_omap_gpmc.c b/drivers/mtd/nand/nand_omap_gpmc.c
index 7849db5..d448251 100644
--- a/drivers/mtd/nand/nand_omap_gpmc.c
+++ b/drivers/mtd/nand/nand_omap_gpmc.c
@@ -1060,7 +1060,7 @@ static int gpmc_nand_probe(struct device_d *pdev)
omap_gpmc_eccmode(oinfo, pdata->ecc_mode);

/* We are all set to register with the system now! */
- err = add_mtd_device(minfo, "nand");
+ err = add_mtd_nand_device(minfo, "nand");
if (err) {
dev_dbg(pdev, "device registration failed\n");
goto out_release_mem;
diff --git a/drivers/mtd/nand/nand_s3c24xx.c b/drivers/mtd/nand/nand_s3c24xx.c
index fef9432..c68c9fb 100644
--- a/drivers/mtd/nand/nand_s3c24xx.c
+++ b/drivers/mtd/nand/nand_s3c24xx.c
@@ -483,7 +483,7 @@ static int s3c24x0_nand_probe(struct device_d *dev)
goto on_error;
}

- return add_mtd_device(mtd, "nand");
+ return add_mtd_nand_device(mtd, "nand");

on_error:
free(host);
diff --git a/drivers/mtd/nand/nomadik_nand.c b/drivers/mtd/nand/nomadik_nand.c
index 834b6ac..afdbef1 100644
--- a/drivers/mtd/nand/nomadik_nand.c
+++ b/drivers/mtd/nand/nomadik_nand.c
@@ -221,7 +221,7 @@ static int nomadik_nand_probe(struct device_d *dev)
}

pr_info("Registering %s as whole device\n", mtd->name);
- add_mtd_device(mtd, "nand");
+ add_mtd_nand_device(mtd, "nand");

return 0;

diff --git a/include/linux/mtd/nand.h b/include/linux/mtd/nand.h
index d2f8648..b111b66 100644
--- a/include/linux/mtd/nand.h
+++ b/include/linux/mtd/nand.h
@@ -618,7 +618,7 @@ extern int nand_erase_nand(struct mtd_info *mtd, struct erase_info *instr,
int allowbbt);
extern int nand_do_read(struct mtd_info *mtd, loff_t from, size_t len,
size_t * retlen, uint8_t * buf);
-
+extern int add_mtd_nand_device(struct mtd_info *mtd, char *devname);
/*
* Constants for oob configuration
*/
--
1.7.10.4

_______________________________________________
barebox mailing list
barebox@lists.infradead.org
http://lists.infradead.org/mailman/listinfo/barebox
Sascha Hauer
04.03.2013 10:14 UTC
The information which kind of bbt (if any) is used is hidden somewhere
in the NAND layer. Expose it to a device parameter to make it detectable
and visible during runtime.

Signed-off-by: Sascha Hauer <s.hauer@pengutronix.de>
---
drivers/mtd/nand/nand_base.c | 19 +++++++++++++++++++
1 file changed, 19 insertions(+)

diff --git a/drivers/mtd/nand/nand_base.c b/drivers/mtd/nand/nand_base.c
index ac223ca..7675695 100644
--- a/drivers/mtd/nand/nand_base.c
+++ b/drivers/mtd/nand/nand_base.c
@@ -1688,6 +1688,23 @@ static int mtd_set_erasebad(struct device_d *dev, struct param_d *param,
return 0;
}

+static const char *mtd_get_bbt_type(struct device_d *dev, struct param_d *p)
+{
+ struct mtd_info *mtd = container_of(dev, struct mtd_info, class_dev);
+ struct nand_chip *chip = mtd->priv;
+ char *str;
+
+ if (!chip->bbt)
+ str = "none";
+ else if ((chip->bbt_td && chip->bbt_td->pages[0] != -1) ||
+ (chip->bbt_md && chip->bbt_md->pages[0] != -1))
+ str = "flashbased";
+ else
+ str = "memorybased";
+
+ return str;
+}
+
int add_mtd_nand_device(struct mtd_info *mtd, char *devname)
{
int ret;
@@ -1700,6 +1717,8 @@ int add_mtd_nand_device(struct mtd_info *mtd, char *devname)
dev_add_param(&mtd->class_dev, "erasebad", mtd_set_erasebad,
NULL, 0);

+ dev_add_param(&mtd->class_dev, "bbt", NULL, mtd_get_bbt_type, 0);
+
return ret;
}

--
1.7.10.4

_______________________________________________
barebox mailing list
barebox@lists.infradead.org
http://lists.infradead.org/mailman/listinfo/barebox
Sascha Hauer
04.03.2013 10:14 UTC
Allo subcommands need at least one nonopt arg, so check for
it right after parsing the options and drop the check in the
MARKBAD command.

Signed-off-by: Sascha Hauer <s.hauer@pengutronix.de>
---
commands/nand.c | 31 ++++++++++++++++---------------
1 file changed, 16 insertions(+), 15 deletions(-)

diff --git a/commands/nand.c b/commands/nand.c
index 79f6735..39fb64e 100644
--- a/commands/nand.c
+++ b/commands/nand.c
@@ -58,6 +58,9 @@ static int do_nand(int argc, char *argv[])
}
}

+ if (optind >= argc)
+ return COMMAND_ERROR_USAGE;
+
if (command == NAND_ADD) {
while (optind < argc) {
if (dev_add_bb_dev(basename(argv[optind]), NULL))
@@ -75,25 +78,23 @@ static int do_nand(int argc, char *argv[])
}

if (command == NAND_MARKBAD) {
- if (optind < argc) {
- int ret = 0, fd;
+ int ret = 0, fd;

- printf("marking block at 0x%08llx on %s as bad\n",
- badblock, argv[optind]);
+ printf("marking block at 0x%08llx on %s as bad\n",
+ badblock, argv[optind]);

- fd = open(argv[optind], O_RDWR);
- if (fd < 0) {
- perror("open");
- return 1;
- }
+ fd = open(argv[optind], O_RDWR);
+ if (fd < 0) {
+ perror("open");
+ return 1;
+ }

- ret = ioctl(fd, MEMSETBADBLOCK, &badblock);
- if (ret)
- perror("ioctl");
+ ret = ioctl(fd, MEMSETBADBLOCK, &badblock);
+ if (ret)
+ perror("ioctl");

- close(fd);
- return ret;
- }
+ close(fd);
+ return ret;
}

return 0;
--
1.7.10.4

_______________________________________________
barebox mailing list
barebox@lists.infradead.org
http://lists.infradead.org/mailman/listinfo/barebox
Sascha Hauer
04.03.2013 10:14 UTC
Signed-off-by: Sascha Hauer <s.hauer@pengutronix.de>
---
drivers/mtd/nand/nand_imx.c | 7 -------
1 file changed, 7 deletions(-)

diff --git a/drivers/mtd/nand/nand_imx.c b/drivers/mtd/nand/nand_imx.c
index d056c7c..22bdb74 100644
--- a/drivers/mtd/nand/nand_imx.c
+++ b/drivers/mtd/nand/nand_imx.c
@@ -1192,13 +1192,6 @@ static int __init imxnd_probe(struct device_d *dev)
this->write_buf = imx_nand_write_buf;
this->read_buf = imx_nand_read_buf;
this->verify_buf = imx_nand_verify_buf;
-#if 0
- host->clk = clk_get(&pdev->dev, "nfc_clk");
- if (IS_ERR(host->clk))
- goto eclk;
-
- clk_enable(host->clk);
-#endif

if (pdata->hw_ecc) {
this->ecc.calculate = imx_nand_calculate_ecc;
--
1.7.10.4

_______________________________________________
barebox mailing list
barebox@lists.infradead.org
http://lists.infradead.org/mailman/listinfo/barebox
Sascha Hauer
04.03.2013 10:15 UTC
With 2k NAND flashes the data layout in memory is not what is
written on the flash device. This leads to the result that the
factory provided bad block markers are not recognized correctly.

To preserve the factory bad block information the i.MX NAND driver
will not scan for the bad blocks itself when there is no flash based
bbt available, because the mtd layer would do so based on wrong
information. Instead, a new command is introduced which allows to
manually create a flash bbt based on the correct information.

As this command is tightly coupled to mtd and the i.MX NAND driver
the command is placed under drivers/mtd/nand/ instead of commands/
where a command normally belongs to.

Signed-off-by: Sascha Hauer <s.hauer@pengutronix.de>
---
drivers/mtd/nand/Kconfig | 5 +
drivers/mtd/nand/Makefile | 1 +
drivers/mtd/nand/nand_imx.c | 19 +++-
drivers/mtd/nand/nand_imx_bbm.c | 220 +++++++++++++++++++++++++++++++++++++++
4 files changed, 243 insertions(+), 2 deletions(-)
create mode 100644 drivers/mtd/nand/nand_imx_bbm.c

diff --git a/drivers/mtd/nand/Kconfig b/drivers/mtd/nand/Kconfig
index 1a9b929..de8fb5e 100644
--- a/drivers/mtd/nand/Kconfig
+++ b/drivers/mtd/nand/Kconfig
@@ -62,6 +62,11 @@ config NAND_IMX
prompt "i.MX NAND driver"
depends on ARCH_IMX

+config NAND_IMX_BBM
+ bool
+ prompt "i.MX NAND flash bbt creation command"
+ depends on NAND_IMX
+
config NAND_MXS
bool
select NAND_BBT
diff --git a/drivers/mtd/nand/Makefile b/drivers/mtd/nand/Makefile
index d52c272..0c7c8e2 100644
--- a/drivers/mtd/nand/Makefile
+++ b/drivers/mtd/nand/Makefile
@@ -11,6 +11,7 @@ obj-$(CONFIG_NAND_BBT) += nand_bbt.o

obj-$(CONFIG_MTD_NAND_NOMADIK) += nomadik_nand.o
obj-$(CONFIG_NAND_IMX) += nand_imx.o
+obj-$(CONFIG_NAND_IMX_BBM) += nand_imx_bbm.o
obj-$(CONFIG_NAND_OMAP_GPMC) += nand_omap_gpmc.o nand_omap_bch_decoder.o
obj-$(CONFIG_NAND_ATMEL) += atmel_nand.o
obj-$(CONFIG_NAND_S3C24XX) += nand_s3c24xx.o
diff --git a/drivers/mtd/nand/nand_imx.c b/drivers/mtd/nand/nand_imx.c
index 22bdb74..75aefd6 100644
--- a/drivers/mtd/nand/nand_imx.c
+++ b/drivers/mtd/nand/nand_imx.c
@@ -1068,7 +1068,7 @@ static uint8_t bbt_pattern[] = { 'B', 'b', 't', '0' };
static uint8_t mirror_pattern[] = { '1', 't', 'b', 'B' };

static struct nand_bbt_descr bbt_main_descr = {
- .options = NAND_BBT_LASTBLOCK | NAND_BBT_CREATE | NAND_BBT_WRITE
+ .options = NAND_BBT_LASTBLOCK
| NAND_BBT_2BIT | NAND_BBT_VERSION | NAND_BBT_PERCHIP,
.offs = 0,
.len = 4,
@@ -1078,7 +1078,7 @@ static struct nand_bbt_descr bbt_main_descr = {
};

static struct nand_bbt_descr bbt_mirror_descr = {
- .options = NAND_BBT_LASTBLOCK | NAND_BBT_CREATE | NAND_BBT_WRITE
+ .options = NAND_BBT_LASTBLOCK
| NAND_BBT_2BIT | NAND_BBT_VERSION | NAND_BBT_PERCHIP,
.offs = 0,
.len = 4,
@@ -1179,6 +1179,7 @@ static int __init imxnd_probe(struct device_d *dev)
mtd = &host->mtd;
mtd->priv = this;
mtd->parent = dev;
+ mtd->name = "imx_nand";

/* 50 us command delay time */
this->chip_delay = 5;
@@ -1235,6 +1236,10 @@ static int __init imxnd_probe(struct device_d *dev)
imx_nand_set_layout(mtd->writesize, pdata->width == 2 ? 16 : 8);

if (mtd->writesize >= 2048) {
+ if (!pdata->flash_bbt)
+ dev_warn(dev, "2k or 4k flash detected without flash_bbt. "
+ "You will loose factory bad block markers!\n");
+
if (mtd->writesize == 2048)
this->ecc.layout = oob_largepage;
else
@@ -1243,6 +1248,9 @@ static int __init imxnd_probe(struct device_d *dev)
if (nfc_is_v21())
writew(NFC_V2_SPAS_SPARESIZE(64), host->regs + NFC_V2_SPAS);
} else {
+ bbt_main_descr.options |= NAND_BBT_WRITE | NAND_BBT_CREATE;
+ bbt_mirror_descr.options |= NAND_BBT_WRITE | NAND_BBT_CREATE;
+
if (nfc_is_v21())
writew(NFC_V2_SPAS_SPARESIZE(16), host->regs + NFC_V2_SPAS);
}
@@ -1253,6 +1261,13 @@ static int __init imxnd_probe(struct device_d *dev)
goto escan;
}

+ if (pdata->flash_bbt && this->bbt_td->pages[0] == -1 && this->bbt_md->pages[0] == -1) {
+ dev_warn(dev, "no BBT found. create one using the imx_nand_bbm command\n");
+ } else {
+ bbt_main_descr.options |= NAND_BBT_WRITE | NAND_BBT_CREATE;
+ bbt_mirror_descr.options |= NAND_BBT_WRITE | NAND_BBT_CREATE;
+ }
+
add_mtd_nand_device(mtd, "nand");

dev->priv = host;
diff --git a/drivers/mtd/nand/nand_imx_bbm.c b/drivers/mtd/nand/nand_imx_bbm.c
new file mode 100644
index 0000000..03961a0
--- /dev/null
+++ b/drivers/mtd/nand/nand_imx_bbm.c
@@ -0,0 +1,220 @@
+/*
+ * imx_nand_bbm.c - create a flash bad block table for i.MX NAND
+ *
+ * Copyright (c) 2013 Sascha Hauer <s.hauer@pengutronix.de>, Pengutronix
+ *
+ * See file CREDITS for list of people who contributed to this
+ * project.
+ *
+ * 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 <common.h>
+#include <command.h>
+#include <fs.h>
+#include <errno.h>
+#include <getopt.h>
+#include <fcntl.h>
+#include <malloc.h>
+#include <linux/mtd/mtd.h>
+#include <linux/mtd/nand.h>
+#include <linux/err.h>
+
+/*
+ * The i.MX NAND controller has the problem that it handles the
+ * data in chunks of 512 bytes. It doesn't treat 2k NAND chips as
+ * 2048 byte data + 64 OOB, but instead:
+ *
+ * 512b data + 16b OOB +
+ * 512b data + 16b OOB +
+ * 512b data + 16b OOB +
+ * 512b data + 16b OOB
+ *
+ * This means that the factory provided bad block marker ends up
+ * in the page data at offset 2000 instead of in the OOB data.
+ *
+ * To preserve the factory bad block information we take the following
+ * strategy:
+ *
+ * - If the NAND driver detects that no flasg BBT is present on 2k NAND
+ * chips it will not create one because it would do so based on the wrong
+ * BBM position
+ * - This command is used to create a flash BBT then.
+ *
+ * From this point on we can forget about the BBMs and rely completely
+ * on the flash BBT.
+ *
+ */
+static int checkbad(struct mtd_info *mtd, loff_t ofs, void *__buf)
+{
+ int ret, retlen;
+ uint8_t *buf = __buf;
+
+ ret = mtd->read(mtd, ofs, mtd->writesize, &retlen, buf);
+ if (ret < 0)
+ return ret;
+
+ if (buf[2000] != 0xff)
+ return 1;
+
+ return 0;
+}
+
+static void *create_bbt(struct mtd_info *mtd)
+{
+ struct nand_chip *chip = mtd->priv;
+ int len, i, numblocks, ret;
+ loff_t from = 0;
+ void *buf;
+ uint8_t *bbt;
+
+ if ((chip->bbt_td && chip->bbt_td->pages[0] != -1) ||
+ (chip->bbt_md && chip->bbt_md->pages[0] != -1)) {
+ printf("Flash bbt already present\n");
+ return ERR_PTR(-EEXIST);
+ }
+
+ len = mtd->size >> (chip->bbt_erase_shift + 2);
+
+ /* Allocate memory (2bit per block) and clear the memory bad block table */
+ bbt = kzalloc(len, GFP_KERNEL);
+ if (!bbt)
+ return ERR_PTR(-ENOMEM);
+
+ buf = malloc(mtd->writesize);
+ if (!buf) {
+ ret = -ENOMEM;
+ goto out;
+ }
+
+ numblocks = mtd->size >> (chip->bbt_erase_shift - 1);
+
+ for (i = 0; i < numblocks;) {
+ ret = checkbad(mtd, from, buf);
+ if (ret < 0)
+ goto out;
+
+ if (ret) {
+ bbt[i >> 3] |= 0x03 << (i & 0x6);
+ printf("Bad eraseblock %d at 0x%08x\n", i >> 1,
+ (unsigned int)from);
+ }
+
+ i += 2;
+ from += (1 << chip->bbt_erase_shift);
+ }
+
+ return bbt;
+out:
+ free(buf);
+
+ return ERR_PTR(ret);
+}
+
+static int attach_bbt(struct mtd_info *mtd, void *bbt)
+{
+ struct nand_chip *chip = mtd->priv;
+
+ chip->bbt_td->options |= NAND_BBT_WRITE | NAND_BBT_CREATE;
+ chip->bbt_md->options |= NAND_BBT_WRITE | NAND_BBT_CREATE;
+ free(chip->bbt);
+ chip->bbt = bbt;
+
+ return nand_update_bbt(mtd, 0);
+}
+
+static int do_imx_nand_bbm(int argc, char *argv[])
+{
+ int opt, ret;
+ struct cdev *cdev;
+ struct mtd_info *mtd;
+ int yes = 0;
+ void *bbt;
+
+ while ((opt = getopt(argc, argv, "y")) > 0) {
+ switch (opt) {
+ case 'y':
+ yes = 1;
+ break;
+ default:
+ return COMMAND_ERROR_USAGE;
+ }
+ }
+
+ cdev = cdev_open("nand0", O_RDWR);
+ if (!cdev)
+ return -ENOENT;
+
+ mtd = cdev->mtd;
+ if (!mtd)
+ return -EINVAL;
+
+ if (strcmp(mtd->name, "imx_nand")) {
+ printf("This is not an i.MX nand but a %s\n", mtd->name);
+ ret = -EINVAL;
+ goto out;
+ }
+
+ switch (mtd->writesize) {
+ case 512:
+ printf("writesize is 512. This command is not needed\n");
+ ret = 1;
+ goto out;
+ case 2048:
+ break;
+ default:
+ printf("not implemented for writesize %d\n", mtd->writesize);
+ ret = 1;
+ goto out;
+ }
+
+ bbt = create_bbt(mtd);
+ if (IS_ERR(bbt)) {
+ ret = 1;
+ goto out;
+ }
+
+ if (!yes) {
+ int c;
+
+ printf("create flash bbt (y/n)?");
+ c = getc();
+ if (c == 'y')
+ yes = 1;
+ printf("\n");
+ }
+
+ if (!yes) {
+ free(bbt);
+ ret = 1;
+
+ goto out;
+ }
+
+ ret = attach_bbt(mtd, bbt);
+ if (!ret)
+ printf("bbt successfully added\n");
+ else
+ free(bbt);
+
+out:
+ cdev_close(cdev);
+
+ return ret;
+}
+
+static const __maybe_unused char cmd_imx_nand_bbm_help[] =
+"Usage: imx_nand_bbm\n";
+
+BAREBOX_CMD_START(imx_nand_bbm)
+ .cmd = do_imx_nand_bbm,
+ .usage = "create bbt for i.MX NAND",
+ BAREBOX_CMD_HELP(cmd_imx_nand_bbm_help)
+BAREBOX_CMD_END
--
1.7.10.4

_______________________________________________
barebox mailing list
barebox@lists.infradead.org
http://lists.infradead.org/mailman/listinfo/barebox
Sascha Hauer
04.03.2013 10:15 UTC
A command can only be one of NAND_*, so use an enumeration instead
of a bitmask.

Signed-off-by: Sascha Hauer <s.hauer@pengutronix.de>
---
commands/nand.c | 12 ++++++------
1 file changed, 6 insertions(+), 6 deletions(-)

diff --git a/commands/nand.c b/commands/nand.c
index d00845f..79f6735 100644
--- a/commands/nand.c
+++ b/commands/nand.c
@@ -29,9 +29,9 @@
#include <fcntl.h>
#include <libgen.h>

-#define NAND_ADD (1 << 0)
-#define NAND_DEL (1 << 1)
-#define NAND_MARKBAD (1 << 2)
+#define NAND_ADD 1
+#define NAND_DEL 2
+#define NAND_MARKBAD 3

static int do_nand(int argc, char *argv[])
{
@@ -58,7 +58,7 @@ static int do_nand(int argc, char *argv[])
}
}

- if (command & NAND_ADD) {
+ if (command == NAND_ADD) {
while (optind < argc) {
if (dev_add_bb_dev(basename(argv[optind]), NULL))
return 1;
@@ -67,14 +67,14 @@ static int do_nand(int argc, char *argv[])
}
}

- if (command & NAND_DEL) {
+ if (command == NAND_DEL) {
while (optind < argc) {
dev_remove_bb_dev(basename(argv[optind]));
optind++;
}
}

- if (command & NAND_MARKBAD) {
+ if (command == NAND_MARKBAD) {
if (optind < argc) {
int ret = 0, fd;

--
1.7.10.4

_______________________________________________
barebox mailing list
barebox@lists.infradead.org
http://lists.infradead.org/mailman/listinfo/barebox
Sascha Hauer
04.03.2013 10:15 UTC
This file is present in current kernels. In order to get closer
to current mtd support introduce it for barebox aswell.

Signed-off-by: Sascha Hauer <s.hauer@pengutronix.de>
---
include/linux/mtd/bbm.h | 86 ++++++++++++++++++++++++++++++++++++++++++++++
include/linux/mtd/nand.h | 77 +++--------------------------------------
2 files changed, 91 insertions(+), 72 deletions(-)
create mode 100644 include/linux/mtd/bbm.h

diff --git a/include/linux/mtd/bbm.h b/include/linux/mtd/bbm.h
new file mode 100644
index 0000000..503ec6d
--- /dev/null
+++ b/include/linux/mtd/bbm.h
@@ -0,0 +1,86 @@
+/*
+ * linux/include/linux/mtd/bbm.h
+ *
+ * NAND family Bad Block Management (BBM) header file
+ * - Bad Block Table (BBT) implementation
+ *
+ * Copyright (c) 2005 Samsung Electronics
+ * Kyungmin Park <kyungmin.park@samsung.com>
+ *
+ * Copyright (c) 2000-2005
+ * Thomas Gleixner <tglx@linuxtronix.de>
+ *
+ */
+#ifndef __LINUX_MTD_BBM_H
+#define __LINUX_MTD_BBM_H
+
+/**
+ * struct nand_bbt_descr - bad block table descriptor
+ * @options: options for this descriptor
+ * @pages: the page(s) where we find the bbt, used with option BBT_ABSPAGE
+ * when bbt is searched, then we store the found bbts pages here.
+ * Its an array and supports up to 8 chips now
+ * @offs: offset of the pattern in the oob area of the page
+ * @veroffs: offset of the bbt version counter in the oob are of the page
+ * @version: version read from the bbt page during scan
+ * @len: length of the pattern, if 0 no pattern check is performed
+ * @maxblocks: maximum number of blocks to search for a bbt. This number of
+ * blocks is reserved at the end of the device where the tables are
+ * written.
+ * @reserved_block_code: if non-0, this pattern denotes a reserved (rather than
+ * bad) block in the stored bbt
+ * @pattern: pattern to identify bad block table or factory marked good /
+ * bad blocks, can be NULL, if len = 0
+ *
+ * Descriptor for the bad block table marker and the descriptor for the
+ * pattern which identifies good and bad blocks. The assumption is made
+ * that the pattern and the version count are always located in the oob area
+ * of the first block.
+ */
+struct nand_bbt_descr {
+ int options;
+ int pages[NAND_MAX_CHIPS];
+ int offs;
+ int veroffs;
+ uint8_t version[NAND_MAX_CHIPS];
+ int len;
+ int maxblocks;
+ int reserved_block_code;
+ uint8_t *pattern;
+};
+
+/* Options for the bad block table descriptors */
+
+/* The number of bits used per block in the bbt on the device */
+#define NAND_BBT_NRBITS_MSK 0x0000000F
+#define NAND_BBT_1BIT 0x00000001
+#define NAND_BBT_2BIT 0x00000002
+#define NAND_BBT_4BIT 0x00000004
+#define NAND_BBT_8BIT 0x00000008
+/* The bad block table is in the last good block of the device */
+#define NAND_BBT_LASTBLOCK 0x00000010
+/* The bbt is at the given page, else we must scan for the bbt */
+#define NAND_BBT_ABSPAGE 0x00000020
+/* The bbt is at the given page, else we must scan for the bbt */
+#define NAND_BBT_SEARCH 0x00000040
+/* bbt is stored per chip on multichip devices */
+#define NAND_BBT_PERCHIP 0x00000080
+/* bbt has a version counter at offset veroffs */
+#define NAND_BBT_VERSION 0x00000100
+/* Create a bbt if none axists */
+#define NAND_BBT_CREATE 0x00000200
+/* Search good / bad pattern through all pages of a block */
+#define NAND_BBT_SCANALLPAGES 0x00000400
+/* Scan block empty during good / bad block scan */
+#define NAND_BBT_SCANEMPTY 0x00000800
+/* Write bbt if neccecary */
+#define NAND_BBT_WRITE 0x00001000
+/* Read and write back block contents when writing bbt */
+#define NAND_BBT_SAVECONTENT 0x00002000
+/* Search good / bad pattern on the first and the second page */
+#define NAND_BBT_SCAN2NDPAGE 0x00004000
+
+/* The maximum number of blocks to scan for a bbt */
+#define NAND_BBT_SCAN_MAXBLOCKS 4
+
+#endif /* __LINUX_MTD_BBM_H */
diff --git a/include/linux/mtd/nand.h b/include/linux/mtd/nand.h
index b111b66..d8331f4 100644
--- a/include/linux/mtd/nand.h
+++ b/include/linux/mtd/nand.h
@@ -24,6 +24,11 @@

#include <linux/mtd/mtd.h>

+/* The maximum number of NAND chips in an array */
+#define NAND_MAX_CHIPS 8
+
+#include <linux/mtd/bbm.h>
+
struct mtd_info;
/* Scan and identify a NAND device */
extern int nand_scan (struct mtd_info *mtd, int max_chips);
@@ -38,9 +43,6 @@ extern void nand_release (struct mtd_info *mtd);
/* Internal helper for board drivers which need to override command function */
extern void nand_wait_ready(struct mtd_info *mtd);

-/* The maximum number of NAND chips in an array */
-#define NAND_MAX_CHIPS 8
-
/* This constant declares the max. oobsize / page, which
* is supported now. If you add a chip with bigger oobsize/page
* adjust this accordingly.
@@ -541,75 +543,6 @@ struct nand_manufacturers {
extern struct nand_flash_dev nand_flash_ids[];
extern struct nand_manufacturers nand_manuf_ids[];

-/**
- * struct nand_bbt_descr - bad block table descriptor
- * @options: options for this descriptor
- * @pages: the page(s) where we find the bbt, used with option BBT_ABSPAGE
- * when bbt is searched, then we store the found bbts pages here.
- * Its an array and supports up to 8 chips now
- * @offs: offset of the pattern in the oob area of the page
- * @veroffs: offset of the bbt version counter in the oob are of the page
- * @version: version read from the bbt page during scan
- * @len: length of the pattern, if 0 no pattern check is performed
- * @maxblocks: maximum number of blocks to search for a bbt. This number of
- * blocks is reserved at the end of the device where the tables are
- * written.
- * @reserved_block_code: if non-0, this pattern denotes a reserved (rather than
- * bad) block in the stored bbt
- * @pattern: pattern to identify bad block table or factory marked good /
- * bad blocks, can be NULL, if len = 0
- *
- * Descriptor for the bad block table marker and the descriptor for the
- * pattern which identifies good and bad blocks. The assumption is made
- * that the pattern and the version count are always located in the oob area
- * of the first block.
- */
-struct nand_bbt_descr {
- int options;
- int pages[NAND_MAX_CHIPS];
- int offs;
- int veroffs;
- uint8_t version[NAND_MAX_CHIPS];
- int len;
- int maxblocks;
- int reserved_block_code;
- uint8_t *pattern;
-};
-
-/* Options for the bad block table descriptors */
-
-/* The number of bits used per block in the bbt on the device */
-#define NAND_BBT_NRBITS_MSK 0x0000000F
-#define NAND_BBT_1BIT 0x00000001
-#define NAND_BBT_2BIT 0x00000002
-#define NAND_BBT_4BIT 0x00000004
-#define NAND_BBT_8BIT 0x00000008
-/* The bad block table is in the last good block of the device */
-#define NAND_BBT_LASTBLOCK 0x00000010
-/* The bbt is at the given page, else we must scan for the bbt */
-#define NAND_BBT_ABSPAGE 0x00000020
-/* The bbt is at the given page, else we must scan for the bbt */
-#define NAND_BBT_SEARCH 0x00000040
-/* bbt is stored per chip on multichip devices */
-#define NAND_BBT_PERCHIP 0x00000080
-/* bbt has a version counter at offset veroffs */
-#define NAND_BBT_VERSION 0x00000100
-/* Create a bbt if none axists */
-#define NAND_BBT_CREATE 0x00000200
-/* Search good / bad pattern through all pages of a block */
-#define NAND_BBT_SCANALLPAGES 0x00000400
-/* Scan block empty during good / bad block scan */
-#define NAND_BBT_SCANEMPTY 0x00000800
-/* Write bbt if neccecary */
-#define NAND_BBT_WRITE 0x00001000
-/* Read and write back block contents when writing bbt */
-#define NAND_BBT_SAVECONTENT 0x00002000
-/* Search good / bad pattern on the first and the second page */
-#define NAND_BBT_SCAN2NDPAGE 0x00004000
-
-/* The maximum number of blocks to scan for a bbt */
-#define NAND_BBT_SCAN_MAXBLOCKS 4
-
extern int nand_scan_bbt(struct mtd_info *mtd, struct nand_bbt_descr *bd);
extern int nand_update_bbt(struct mtd_info *mtd, loff_t offs);
extern int nand_default_bbt(struct mtd_info *mtd);
--
1.7.10.4

_______________________________________________
barebox mailing list
barebox@lists.infradead.org
http://lists.infradead.org/mailman/listinfo/barebox
Sascha Hauer
04.03.2013 10:15 UTC
To sync with the kernel.

Signed-off-by: Sascha Hauer <s.hauer@pengutronix.de>
---
drivers/mtd/nand/atmel_nand.c | 2 +-
drivers/mtd/nand/nand_bbt.c | 4 ++--
drivers/mtd/nand/nand_imx.c | 2 +-
drivers/mtd/nand/nand_s3c24xx.c | 2 +-
drivers/mtd/nand/nand_write.c | 2 +-
include/linux/mtd/bbm.h | 6 ++++++
include/linux/mtd/nand.h | 7 ++++---
7 files changed, 16 insertions(+), 9 deletions(-)

diff --git a/drivers/mtd/nand/atmel_nand.c b/drivers/mtd/nand/atmel_nand.c
index 81ccad9..3eb78b7 100644
--- a/drivers/mtd/nand/atmel_nand.c
+++ b/drivers/mtd/nand/atmel_nand.c
@@ -1196,7 +1196,7 @@ static int __init atmel_nand_probe(struct device_d *dev)

if (host->board->on_flash_bbt) {
printk(KERN_INFO "atmel_nand: Use On Flash BBT\n");
- nand_chip->options |= NAND_USE_FLASH_BBT;
+ nand_chip->bbt_options |= NAND_BBT_USE_FLASH;
}


diff --git a/drivers/mtd/nand/nand_bbt.c b/drivers/mtd/nand/nand_bbt.c
index 56396bf..ba51e0b 100644
--- a/drivers/mtd/nand/nand_bbt.c
+++ b/drivers/mtd/nand/nand_bbt.c
@@ -1176,12 +1176,12 @@ int nand_default_bbt(struct mtd_info *mtd)
this->bbt_td = &bbt_main_descr;
this->bbt_md = &bbt_mirror_descr;
}
- this->options |= NAND_USE_FLASH_BBT;
+ this->bbt_options |= NAND_BBT_USE_FLASH;
return nand_scan_bbt(mtd, &agand_flashbased);
}

/* Is a flash based bad block table requested ? */
- if (this->options & NAND_USE_FLASH_BBT) {
+ if (this->bbt_options & NAND_BBT_USE_FLASH) {
/* Use the default pattern descriptors */
if (!this->bbt_td) {
this->bbt_td = &bbt_main_descr;
diff --git a/drivers/mtd/nand/nand_imx.c b/drivers/mtd/nand/nand_imx.c
index 842c1de..d056c7c 100644
--- a/drivers/mtd/nand/nand_imx.c
+++ b/drivers/mtd/nand/nand_imx.c
@@ -1227,7 +1227,7 @@ static int __init imxnd_probe(struct device_d *dev)
this->bbt_td = &bbt_main_descr;
this->bbt_md = &bbt_mirror_descr;
/* update flash based bbt */
- this->options |= NAND_USE_FLASH_BBT;
+ this->bbt_options |= NAND_BBT_USE_FLASH;
}

/* first scan to find the device and get the page size */
diff --git a/drivers/mtd/nand/nand_s3c24xx.c b/drivers/mtd/nand/nand_s3c24xx.c
index c68c9fb..a3f80cb 100644
--- a/drivers/mtd/nand/nand_s3c24xx.c
+++ b/drivers/mtd/nand/nand_s3c24xx.c
@@ -469,7 +469,7 @@ static int s3c24x0_nand_probe(struct device_d *dev)

if (pdata->flash_bbt) {
/* use a flash based bbt */
- chip->options |= NAND_USE_FLASH_BBT;
+ chip->bbt_options |= NAND_BBT_USE_FLASH;
}

ret = s3c24x0_nand_inithw(host);
diff --git a/drivers/mtd/nand/nand_write.c b/drivers/mtd/nand/nand_write.c
index 11005f3..c2699ab 100644
--- a/drivers/mtd/nand/nand_write.c
+++ b/drivers/mtd/nand/nand_write.c
@@ -74,7 +74,7 @@ int nand_default_block_markbad(struct mtd_info *mtd, loff_t ofs)
chip->bbt[block >> 2] |= 0x01 << ((block & 0x03) << 1);

/* Do we have a flash based bad block table ? */
- if (IS_ENABLED(CONFIG_NAND_BBT) && chip->options & NAND_USE_FLASH_BBT)
+ if (IS_ENABLED(CONFIG_NAND_BBT) && chip->bbt_options & NAND_BBT_USE_FLASH)
ret = nand_update_bbt(mtd, ofs);
else {
/* We write two bytes, so we dont have to mess with 16 bit
diff --git a/include/linux/mtd/bbm.h b/include/linux/mtd/bbm.h
index 503ec6d..d546f40 100644
--- a/include/linux/mtd/bbm.h
+++ b/include/linux/mtd/bbm.h
@@ -80,6 +80,12 @@ struct nand_bbt_descr {
/* Search good / bad pattern on the first and the second page */
#define NAND_BBT_SCAN2NDPAGE 0x00004000

+/*
+ * Use a flash based bad block table. By default, OOB identifier is saved in
+ * OOB area. This option is passed to the default bad block table function.
+ */
+#define NAND_BBT_USE_FLASH 0x00020000
+
/* The maximum number of blocks to scan for a bbt */
#define NAND_BBT_SCAN_MAXBLOCKS 4

diff --git a/include/linux/mtd/nand.h b/include/linux/mtd/nand.h
index d8331f4..dc141a5 100644
--- a/include/linux/mtd/nand.h
+++ b/include/linux/mtd/nand.h
@@ -189,9 +189,6 @@ typedef enum {
#define NAND_CHIPOPTIONS_MSK (0x0000ffff & ~NAND_NO_AUTOINCR)

/* Non chip related options */
-/* Use a flash based bad block table. This option is passed to the
- * default bad block table function. */
-#define NAND_USE_FLASH_BBT 0x00010000
/* This option skips the bbt scan during initialization. */
#define NAND_SKIP_BBTSCAN 0x00020000
/* This option is defined if the board driver allocates its own buffers
@@ -409,6 +406,9 @@ struct nand_buffers {
* @data_poi: [INTERN] pointer to a data buffer
* @options: [BOARDSPECIFIC] various chip options. They can partly be set to inform nand_scan about
* special functionality. See the defines for further explanation
+ * @bbt_options: [INTERN] bad block specific options. All options used
+ * here must come from bbm.h. By default, these options
+ * will be copied to the appropriate nand_bbt_descr's.
* @badblockpos: [INTERN] position of the bad block marker in the oob area
* @cellinfo: [INTERN] MLC/multichip data from chip ident
* @numchips: [INTERN] number of physical chips
@@ -459,6 +459,7 @@ struct nand_chip {

int chip_delay;
unsigned int options;
+ unsigned int bbt_options;

int page_shift;
int phys_erase_shift;
--
1.7.10.4

_______________________________________________
barebox mailing list
barebox@lists.infradead.org
http://lists.infradead.org/mailman/listinfo/barebox
Sascha Hauer
04.03.2013 10:15 UTC
While erasing bad blocks is a potentially dangerous operation
it is sometimes needed during development or when some foreign
code has touched the flash.

This patch adds a device parameter 'erasebad' to allow erasing
bad blocks. Since this is not wanted during production this is
behind a Kconfig option.

Signed-off-by: Sascha Hauer <s.hauer@pengutronix.de>
---
drivers/mtd/core.c | 6 +++++-
drivers/mtd/mtdraw.c | 6 +++++-
drivers/mtd/nand/Kconfig | 9 +++++++++
drivers/mtd/nand/nand_base.c | 20 ++++++++++++++++++++
drivers/mtd/nand/nand_write.c | 3 ++-
include/linux/mtd/mtd.h | 3 +++
6 files changed, 44 insertions(+), 3 deletions(-)

diff --git a/drivers/mtd/core.c b/drivers/mtd/core.c
index b6c1d01..e28d925 100644
--- a/drivers/mtd/core.c
+++ b/drivers/mtd/core.c
@@ -112,7 +112,11 @@ static int mtd_op_erase(struct cdev *cdev, size_t count, loff_t offset)
while (count > 0) {
dev_dbg(cdev->dev, "erase %d %d\n", erase.addr, erase.len);

- ret = mtd_block_isbad(mtd, erase.addr);
+ if (!mtd->allow_erasebad)
+ ret = mtd_block_isbad(mtd, erase.addr);
+ else
+ ret = 0;
+
if (ret > 0) {
printf("Skipping bad block at 0x%08x\n", erase.addr);
} else {
diff --git a/drivers/mtd/mtdraw.c b/drivers/mtd/mtdraw.c
index 5aaa017..384104e 100644
--- a/drivers/mtd/mtdraw.c
+++ b/drivers/mtd/mtdraw.c
@@ -241,7 +241,11 @@ static int mtdraw_erase(struct cdev *cdev, size_t count, loff_t _offset)
while (count > 0) {
debug("erase %d %d\n", erase.addr, erase.len);

- ret = mtd_block_isbad(mtd, erase.addr);
+ if (!mtd->allow_erasebad)
+ ret = mtd_block_isbad(mtd, erase.addr);
+ else
+ ret = 0;
+
if (ret > 0) {
printf("Skipping bad block at 0x%08x\n", erase.addr);
} else {
diff --git a/drivers/mtd/nand/Kconfig b/drivers/mtd/nand/Kconfig
index 49daabf..1a9b929 100644
--- a/drivers/mtd/nand/Kconfig
+++ b/drivers/mtd/nand/Kconfig
@@ -48,6 +48,15 @@ config NAND_BBT
Say y here to include support for bad block tables. This speeds
up the process of checking for bad blocks

+config NAND_ALLOW_ERASE_BAD
+ bool
+ depends on MTD_WRITE
+ prompt "Add device parameter to allow erasing bad blocks"
+ help
+ This adds a 'erasebad' device parameter to nand devices. When set
+ to '1' it will be allowed to erase bad blocks. This is a potientially
+ dangerous operation, so if unsure say no to this option.
+
config NAND_IMX
bool
prompt "i.MX NAND driver"
diff --git a/drivers/mtd/nand/nand_base.c b/drivers/mtd/nand/nand_base.c
index c0345c7..ac223ca 100644
--- a/drivers/mtd/nand/nand_base.c
+++ b/drivers/mtd/nand/nand_base.c
@@ -1672,6 +1672,22 @@ EXPORT_SYMBOL(nand_scan_ident);
EXPORT_SYMBOL(nand_scan_tail);
EXPORT_SYMBOL(nand_release);

+static int mtd_set_erasebad(struct device_d *dev, struct param_d *param,
+ const char *val)
+{
+ struct mtd_info *mtd = container_of(dev, struct mtd_info, class_dev);
+ int erasebad;
+
+ erasebad = simple_strtoul(val, NULL, 0);
+
+ if (erasebad && !mtd->allow_erasebad)
+ dev_warn(dev, "Allowing to erase bad blocks. This may be dangerous!\n");
+
+ mtd->allow_erasebad = erasebad ? true : false;
+
+ return 0;
+}
+
int add_mtd_nand_device(struct mtd_info *mtd, char *devname)
{
int ret;
@@ -1680,6 +1696,10 @@ int add_mtd_nand_device(struct mtd_info *mtd, char *devname)
if (ret)
return ret;

+ if (IS_ENABLED(CONFIG_NAND_ALLOW_ERASE_BAD))
+ dev_add_param(&mtd->class_dev, "erasebad", mtd_set_erasebad,
+ NULL, 0);
+
return ret;
}

diff --git a/drivers/mtd/nand/nand_write.c b/drivers/mtd/nand/nand_write.c
index eea5113..11005f3 100644
--- a/drivers/mtd/nand/nand_write.c
+++ b/drivers/mtd/nand/nand_write.c
@@ -626,7 +626,8 @@ int nand_erase_nand(struct mtd_info *mtd, struct erase_info *instr,
/*
* heck if we have a bad block, we do not erase bad blocks !
*/
- if (nand_block_checkbad(mtd, ((loff_t) page) <<
+ if (!mtd->allow_erasebad &&
+ nand_block_checkbad(mtd, ((loff_t) page) <<
chip->page_shift, 0, allowbbt)) {
pr_warn("nand_erase: attempt to erase a "
"bad block at page 0x%08x\n", page);
diff --git a/include/linux/mtd/mtd.h b/include/linux/mtd/mtd.h
index e556837..390f4b0 100644
--- a/include/linux/mtd/mtd.h
+++ b/include/linux/mtd/mtd.h
@@ -205,6 +205,9 @@ struct mtd_info {

struct param_d param_size;
char *size_str;
+
+ /* If true erasing bad blocks is allowed, this is set via a device parameter */
+ bool allow_erasebad;
};

int mtd_erase(struct mtd_info *mtd, struct erase_info *instr);
--
1.7.10.4

_______________________________________________
barebox mailing list
barebox@lists.infradead.org
http://lists.infradead.org/mailman/listinfo/barebox
Juergen Beisert
04.03.2013 20:45 UTC
Sascha Hauer wrote:
> [...]
> --- a/drivers/mtd/nand/nand_base.c
> +++ b/drivers/mtd/nand/nand_base.c
> @@ -1688,6 +1688,23 @@ static int mtd_set_erasebad(struct device_d *dev,
> struct param_d *param, return 0;
> }
>
> +static const char *mtd_get_bbt_type(struct device_d *dev, struct param_d
*p) +{
> + struct mtd_info *mtd = container_of(dev, struct mtd_info, class_dev);
> + struct nand_chip *chip = mtd->priv;
> + char *str;

Should also be "const char *str"

> +
> + if (!chip->bbt)
> + str = "none";
> + else if ((chip->bbt_td && chip->bbt_td->pages[0] != -1) ||
> + (chip->bbt_md && chip->bbt_md->pages[0] != -1))
> + str = "flashbased";
> + else
> + str = "memorybased";
> +
> + return str;
> +}
> +

jbe

--
Pengutronix e.K. | Juergen Beisert |
Linux Solutions for Science and Industry | http://www.pengutronix.de/ |

_______________________________________________
barebox mailing list
barebox@lists.infradead.org
http://lists.infradead.org/mailman/listinfo/barebox
Juergen Beisert
04.03.2013 20:45 UTC
Sascha Hauer wrote:
> [...]
> +static int do_imx_nand_bbm(int argc, char *argv[])
> +{
> + int opt, ret;
> + struct cdev *cdev;
> + struct mtd_info *mtd;
> + int yes = 0;
> + void *bbt;
> +
> + while ((opt = getopt(argc, argv, "y")) > 0) {
> + switch (opt) {
> + case 'y':
> + yes = 1;
> + break;
> + default:
> + return COMMAND_ERROR_USAGE;
> + }
> + }
> +
> + cdev = cdev_open("nand0", O_RDWR);

Is a fixed name a good idea?

> [...]

jbe

--
Pengutronix e.K. | Juergen Beisert |
Linux Solutions for Science and Industry | http://www.pengutronix.de/ |

_______________________________________________
barebox mailing list
barebox@lists.infradead.org
http://lists.infradead.org/mailman/listinfo/barebox
Alexander Aring
04.03.2013 21:25 UTC
Hi,

On Mon, Mar 04, 2013 at 11:13:49AM +0100, Sascha Hauer wrote:
> A command can only be one of NAND_*, so use an enumeration instead
> of a bitmask.
>
> Signed-off-by: Sascha Hauer <s.hauer@pengutronix.de>
> ---
> commands/nand.c | 12 ++++++------
> 1 file changed, 6 insertions(+), 6 deletions(-)
>
> diff --git a/commands/nand.c b/commands/nand.c
> index d00845f..79f6735 100644
> --- a/commands/nand.c
> +++ b/commands/nand.c
> @@ -29,9 +29,9 @@
> #include <fcntl.h>
> #include <libgen.h>
>
> -#define NAND_ADD (1 << 0)
> -#define NAND_DEL (1 << 1)
> -#define NAND_MARKBAD (1 << 2)
> +#define NAND_ADD 1
> +#define NAND_DEL 2
> +#define NAND_MARKBAD 3
>
> static int do_nand(int argc, char *argv[])
> {
> @@ -58,7 +58,7 @@ static int do_nand(int argc, char *argv[])
> }
> }
>
> - if (command & NAND_ADD) {
> + if (command == NAND_ADD) {

some nitpick. Can we use switch case instead of if? With a default
branch when command == 0 to return COMMAND_ERROR_USAGE?

> while (optind < argc) {
> if (dev_add_bb_dev(basename(argv[optind]), NULL))
> return 1;
> @@ -67,14 +67,14 @@ static int do_nand(int argc, char *argv[])
> }
> }
>
> - if (command & NAND_DEL) {
> + if (command == NAND_DEL) {
> while (optind < argc) {
> dev_remove_bb_dev(basename(argv[optind]));
> optind++;
> }
> }
>
> - if (command & NAND_MARKBAD) {
> + if (command == NAND_MARKBAD) {
> if (optind < argc) {
> int ret = 0, fd;
>
> --
> 1.7.10.4
>
>
> _______________________________________________
> barebox mailing list
> barebox@lists.infradead.org
> http://lists.infradead.org/mailman/listinfo/barebox

_______________________________________________
barebox mailing list
barebox@lists.infradead.org
http://lists.infradead.org/mailman/listinfo/barebox
Sascha Hauer
05.03.2013 10:48 UTC
On Mon, Mar 04, 2013 at 09:42:55PM +0100, Juergen Beisert wrote:
> Sascha Hauer wrote:
> > [...]
> > --- a/drivers/mtd/nand/nand_base.c
> > +++ b/drivers/mtd/nand/nand_base.c
> > @@ -1688,6 +1688,23 @@ static int mtd_set_erasebad(struct device_d *dev,
> > struct param_d *param, return 0;
> > }
> >
> > +static const char *mtd_get_bbt_type(struct device_d *dev, struct param_d
> *p) +{
> > + struct mtd_info *mtd = container_of(dev, struct mtd_info, class_dev);
> > + struct nand_chip *chip = mtd->priv;
> > + char *str;
>
> Should also be "const char *str"

ok.

Sascha

--
Pengutronix e.K. | |
Industrial Linux Solutions | http://www.pengutronix.de/ |
Peiner Str. 6-8, 31137 Hildesheim, Germany | Phone: +49-5121-206917-0 |
Amtsgericht Hildesheim, HRA 2686 | Fax: +49-5121-206917-5555 |

_______________________________________________
barebox mailing list
barebox@lists.infradead.org
http://lists.infradead.org/mailman/listinfo/barebox
Sascha Hauer
05.03.2013 10:49 UTC
On Mon, Mar 04, 2013 at 09:43:11PM +0100, Juergen Beisert wrote:
> Sascha Hauer wrote:
> > [...]
> > +static int do_imx_nand_bbm(int argc, char *argv[])
> > +{
> > + int opt, ret;
> > + struct cdev *cdev;
> > + struct mtd_info *mtd;
> > + int yes = 0;
> > + void *bbt;
> > +
> > + while ((opt = getopt(argc, argv, "y")) > 0) {
> > + switch (opt) {
> > + case 'y':
> > + yes = 1;
> > + break;
> > + default:
> > + return COMMAND_ERROR_USAGE;
> > + }
> > + }
> > +
> > + cdev = cdev_open("nand0", O_RDWR);
>
> Is a fixed name a good idea?

Since there is only one NAND device on i.MX I think it's ok.

Sascha

--
Pengutronix e.K. | |
Industrial Linux Solutions | http://www.pengutronix.de/ |
Peiner Str. 6-8, 31137 Hildesheim, Germany | Phone: +49-5121-206917-0 |
Amtsgericht Hildesheim, HRA 2686 | Fax: +49-5121-206917-5555 |

_______________________________________________
barebox mailing list
barebox@lists.infradead.org
http://lists.infradead.org/mailman/listinfo/barebox