summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--arch/arm/mach-at91/include/mach/board.h2
-rw-r--r--drivers/mtd/nand/atmel_nand.c3
-rw-r--r--drivers/mtd/nand/nand_base.c277
-rw-r--r--drivers/mtd/nand/nand_bbt.c396
-rw-r--r--drivers/mtd/nand/nand_bch.c27
-rw-r--r--drivers/mtd/nand/nand_imx_bbm.c2
-rw-r--r--drivers/mtd/nand/nand_mxs.c27
-rw-r--r--drivers/mtd/nand/nand_omap_gpmc.c1
-rw-r--r--include/linux/mtd/bbm.h4
-rw-r--r--include/linux/mtd/nand.h13
-rw-r--r--include/linux/mtd/nand_bch.h8
11 files changed, 426 insertions, 334 deletions
diff --git a/arch/arm/mach-at91/include/mach/board.h b/arch/arm/mach-at91/include/mach/board.h
index 0f2c269732..886f81e9ad 100644
--- a/arch/arm/mach-at91/include/mach/board.h
+++ b/arch/arm/mach-at91/include/mach/board.h
@@ -64,6 +64,8 @@ struct atmel_nand_data {
u8 cle; /* address line number connected to CLE */
u8 bus_width_16; /* buswidth is 16 bit */
u8 ecc_mode; /* NAND_ECC_* */
+ u8 ecc_strength; /* number of bits to correct per ECC step */
+ u8 ecc_size_shift; /* data bytes covered by a single ECC step.*/
u8 on_flash_bbt; /* Use flash based bbt */
u8 has_pmecc; /* Use PMECC */
u8 bus_on_d0;
diff --git a/drivers/mtd/nand/atmel_nand.c b/drivers/mtd/nand/atmel_nand.c
index 4c1725d096..b4d4e79d91 100644
--- a/drivers/mtd/nand/atmel_nand.c
+++ b/drivers/mtd/nand/atmel_nand.c
@@ -1297,6 +1297,7 @@ static int atmel_hw_nand_init_params(struct device_d *dev,
nand_chip->ecc.hwctl = atmel_nand_hwctl;
nand_chip->ecc.read_page = atmel_nand_read_page;
nand_chip->ecc.bytes = 4;
+ nand_chip->ecc.strength = 1;
return 0;
}
@@ -1387,6 +1388,8 @@ static int __init atmel_nand_probe(struct device_d *dev)
}
nand_chip->ecc.mode = pdata->ecc_mode;
+ nand_chip->ecc.strength = pdata->ecc_strength ? : 1;
+ nand_chip->ecc.size = 1 << pdata->ecc_size_shift ? : 512;
if (IS_ENABLED(CONFIG_NAND_ECC_HW) &&
pdata->ecc_mode == NAND_ECC_HW) {
diff --git a/drivers/mtd/nand/nand_base.c b/drivers/mtd/nand/nand_base.c
index 128802fa5c..8ae6f34468 100644
--- a/drivers/mtd/nand/nand_base.c
+++ b/drivers/mtd/nand/nand_base.c
@@ -36,13 +36,13 @@
#include <clock.h>
#include <linux/mtd/mtd.h>
#include <linux/mtd/nand.h>
-#include <linux/err.h>
+#include <linux/mtd/nand_bch.h>
#include <linux/mtd/nand_ecc.h>
+#include <linux/err.h>
#include <asm/byteorder.h>
#include <io.h>
#include <malloc.h>
#include <module.h>
-#include <linux/mtd/nand_bch.h>
/* Define default oob placement schemes for large and small page devices */
static struct nand_ecclayout nand_oob_8 = {
@@ -326,28 +326,70 @@ static int nand_block_bad(struct mtd_info *mtd, loff_t ofs, int getchip)
}
/**
- * nand_default_block_markbad - [DEFAULT] mark a block bad
+ * nand_default_block_markbad - [DEFAULT] mark a block bad via bad block marker
* @mtd: MTD device structure
* @ofs: offset from device start
*
* This is the default implementation, which can be overridden by a hardware
- * specific driver. We try operations in the following order, according to our
- * bbt_options (NAND_BBT_NO_OOB_BBM and NAND_BBT_USE_FLASH):
+ * specific driver. It provides the details for writing a bad block marker to a
+ * block.
+ */
+static __maybe_unused int nand_default_block_markbad(struct mtd_info *mtd, loff_t ofs)
+{
+ struct nand_chip *chip = mtd->priv;
+ struct mtd_oob_ops ops;
+ uint8_t buf[2] = { 0, 0 };
+ int ret = 0, res, i = 0;
+
+ ops.datbuf = NULL;
+ ops.oobbuf = buf;
+ ops.ooboffs = chip->badblockpos;
+ if (chip->options & NAND_BUSWIDTH_16) {
+ ops.ooboffs &= ~0x01;
+ ops.len = ops.ooblen = 2;
+ } else {
+ ops.len = ops.ooblen = 1;
+ }
+ ops.mode = MTD_OPS_PLACE_OOB;
+
+ /* Write to first/last page(s) if necessary */
+ if (chip->bbt_options & NAND_BBT_SCANLASTPAGE)
+ ofs += mtd->erasesize - mtd->writesize;
+ do {
+ res = nand_do_write_oob(mtd, ofs, &ops);
+ if (!ret)
+ ret = res;
+
+ i++;
+ ofs += mtd->writesize;
+ } while ((chip->bbt_options & NAND_BBT_SCAN2NDPAGE) && i < 2);
+
+ return ret;
+}
+
+/**
+ * nand_block_markbad_lowlevel - mark a block bad
+ * @mtd: MTD device structure
+ * @ofs: offset from device start
+ *
+ * This function performs the generic NAND bad block marking steps (i.e., bad
+ * block table(s) and/or marker(s)). We only allow the hardware driver to
+ * specify how to write bad block markers to OOB (chip->block_markbad).
+ *
+ * We try operations in the following order:
* (1) erase the affected block, to allow OOB marker to be written cleanly
- * (2) update in-memory BBT
- * (3) write bad block marker to OOB area of affected block
- * (4) update flash-based BBT
- * Note that we retain the first error encountered in (3) or (4), finish the
+ * (2) write bad block marker to OOB area of affected block (unless flag
+ * NAND_BBT_NO_OOB_BBM is present)
+ * (3) update the BBT
+ * Note that we retain the first error encountered in (2) or (3), finish the
* procedures, and dump the error in the end.
-*/
-static __maybe_unused int nand_default_block_markbad(struct mtd_info *mtd, loff_t ofs)
+ */
+static int nand_block_markbad_lowlevel(struct mtd_info *mtd, loff_t ofs)
{
struct nand_chip *chip = mtd->priv;
- uint8_t buf[2] = { 0, 0 };
- int block, res, ret = 0, i = 0;
- int write_oob = !(chip->bbt_options & NAND_BBT_NO_OOB_BBM);
+ int res, ret = 0;
- if (write_oob) {
+ if (!(chip->bbt_options & NAND_BBT_NO_OOB_BBM)) {
struct erase_info einfo;
/* Attempt erase before marking OOB */
@@ -356,50 +398,16 @@ static __maybe_unused int nand_default_block_markbad(struct mtd_info *mtd, loff
einfo.addr = ofs;
einfo.len = 1 << chip->phys_erase_shift;
nand_erase_nand(mtd, &einfo, 0);
- }
-
- /* Get block number */
- block = (int)(ofs >> chip->bbt_erase_shift);
- /* Mark block bad in memory-based BBT */
- if (chip->bbt)
- chip->bbt[block >> 2] |= 0x01 << ((block & 0x03) << 1);
-
- /* Write bad block marker to OOB */
- if (write_oob) {
- struct mtd_oob_ops ops;
- loff_t wr_ofs = ofs;
+ /* Write bad block marker to OOB */
nand_get_device(mtd, FL_WRITING);
-
- ops.datbuf = NULL;
- ops.oobbuf = buf;
- ops.ooboffs = chip->badblockpos;
- if (chip->options & NAND_BUSWIDTH_16) {
- ops.ooboffs &= ~0x01;
- ops.len = ops.ooblen = 2;
- } else {
- ops.len = ops.ooblen = 1;
- }
- ops.mode = MTD_OPS_PLACE_OOB;
-
- /* Write to first/last page(s) if necessary */
- if (chip->bbt_options & NAND_BBT_SCANLASTPAGE)
- wr_ofs += mtd->erasesize - mtd->writesize;
- do {
- res = nand_do_write_oob(mtd, wr_ofs, &ops);
- if (!ret)
- ret = res;
-
- i++;
- wr_ofs += mtd->writesize;
- } while ((chip->bbt_options & NAND_BBT_SCAN2NDPAGE) && i < 2);
-
+ ret = chip->block_markbad(mtd, ofs);
nand_release_device(mtd);
}
- /* Update flash-based bad block table */
- if (IS_ENABLED(CONFIG_NAND_BBT) && chip->bbt_options & NAND_BBT_USE_FLASH) {
- res = nand_update_bbt(mtd, ofs);
+ /* Mark block bad in BBT */
+ if (chip->bbt) {
+ res = nand_markbad_bbt(mtd, ofs);
if (!ret)
ret = res;
}
@@ -411,6 +419,57 @@ static __maybe_unused int nand_default_block_markbad(struct mtd_info *mtd, loff
}
/**
+ * nand_block_markgood_lowlevel - mark a block good
+ * @mtd: MTD device structure
+ * @ofs: offset from device start
+ *
+ * We try operations in the following order:
+ * (1) erase the affected block
+ * (2) check bad block marker
+ * (3) update the BBT
+ */
+static int nand_block_markgood_lowlevel(struct mtd_info *mtd, loff_t ofs)
+{
+ struct nand_chip *chip = mtd->priv;
+ bool allow_erasebad;
+ int ret;
+
+ if (!(chip->bbt_options & NAND_BBT_NO_OOB_BBM)) {
+ struct erase_info einfo;
+
+ /* Attempt erase possibly bad block */
+ allow_erasebad = mtd->allow_erasebad;
+ mtd->allow_erasebad = true;
+ memset(&einfo, 0, sizeof(einfo));
+ einfo.mtd = mtd;
+ einfo.addr = ofs;
+ einfo.len = 1 << chip->phys_erase_shift;
+ nand_erase_nand(mtd, &einfo, 0);
+ mtd->allow_erasebad = allow_erasebad;
+
+ /*
+ * Verify erase succeded. We need to select chip again,
+ * as nand_erase_nand deselected it.
+ */
+ ret = chip->block_bad(mtd, ofs, 1);
+ if (ret)
+ return ret;
+ }
+
+ /* Mark block good in BBT */
+ if (chip->bbt) {
+ ret = nand_markgood_bbt(mtd, ofs);
+ if (ret)
+ return ret;
+ }
+
+ if (mtd->ecc_stats.badblocks > 0)
+ mtd->ecc_stats.badblocks--;
+
+ return 0;
+}
+
+/**
* nand_check_wp - [GENERIC] check if the chip is write protected
* @mtd: MTD device structure
*
@@ -453,38 +512,6 @@ static int nand_block_checkbad(struct mtd_info *mtd, loff_t ofs, int getchip,
return chip->block_bad(mtd, ofs, getchip);
}
-/**
- * nand_default_block_markgood - [DEFAULT] mark a block good
- * @mtd: MTD device structure
- * @ofs: offset from device start
- *
- * This is the default implementation, which can be overridden by
- * a hardware specific driver.
-*/
-static __maybe_unused int nand_default_block_markgood(struct mtd_info *mtd, loff_t ofs)
-{
- struct nand_chip *chip = mtd->priv;
- int block, res, ret = 0;
-
- /* Get block number */
- block = (int)(ofs >> chip->bbt_erase_shift);
- /* Mark block good in memory-based BBT */
- if (chip->bbt)
- chip->bbt[block >> 2] &= ~(0x01 << ((block & 0x03) << 1));
-
- /* Update flash-based bad block table */
- if (IS_ENABLED(CONFIG_NAND_BBT) && chip->bbt_options & NAND_BBT_USE_FLASH) {
- res = nand_update_bbt(mtd, ofs);
- if (!ret)
- ret = res;
- }
-
- if (!ret)
- mtd->ecc_stats.badblocks++;
-
- return ret;
-}
-
/* Wait for the ready pin, after a command. The timeout is caught later. */
void nand_wait_ready(struct mtd_info *mtd)
{
@@ -2804,7 +2831,6 @@ static int nand_block_isbad(struct mtd_info *mtd, loff_t offs)
*/
static int nand_block_markbad(struct mtd_info *mtd, loff_t ofs)
{
- struct nand_chip *chip = mtd->priv;
int ret;
if (!IS_ENABLED(CONFIG_MTD_WRITE))
@@ -2818,17 +2844,16 @@ static int nand_block_markbad(struct mtd_info *mtd, loff_t ofs)
return ret;
}
- return chip->block_markbad(mtd, ofs);
+ return nand_block_markbad_lowlevel(mtd, ofs);
}
/**
- * nand_block_markgood - [MTD Interface] Mark block at the given offset as bad
+ * nand_block_markgood - [MTD Interface] Mark block at the given offset as good
* @mtd: MTD device structure
* @ofs: offset relative to mtd start
*/
static int nand_block_markgood(struct mtd_info *mtd, loff_t ofs)
{
- struct nand_chip *chip = mtd->priv;
int ret;
if (!IS_ENABLED(CONFIG_MTD_WRITE))
@@ -2842,7 +2867,7 @@ static int nand_block_markgood(struct mtd_info *mtd, loff_t ofs)
if (!ret)
return 0;
- return chip->block_markgood(mtd, ofs);
+ return nand_block_markgood_lowlevel(mtd, ofs);
}
/**
@@ -2926,17 +2951,11 @@ static void nand_set_defaults(struct nand_chip *chip, int busw)
#ifdef CONFIG_MTD_WRITE
if (!chip->block_markbad)
chip->block_markbad = nand_default_block_markbad;
- if (!chip->block_markgood)
- chip->block_markgood = nand_default_block_markgood;
if (!chip->write_buf)
chip->write_buf = busw ? nand_write_buf16 : nand_write_buf;
#endif
if (!chip->read_buf)
chip->read_buf = busw ? nand_read_buf16 : nand_read_buf;
-#ifdef CONFIG_NAND_BBT
- if (!chip->scan_bbt)
- chip->scan_bbt = nand_default_bbt;
-#endif
if (!chip->controller) {
chip->controller = &chip->hwcontrol;
}
@@ -3100,6 +3119,16 @@ static int nand_id_len(u8 *id_data, int arrlen)
return arrlen;
}
+/* Extract the bits of per cell from the 3rd byte of the extended ID */
+static int nand_get_bits_per_cell(u8 cellinfo)
+{
+ int bits;
+
+ bits = cellinfo & NAND_CI_CELLTYPE_MSK;
+ bits >>= NAND_CI_CELLTYPE_SHIFT;
+ return bits + 1;
+}
+
/*
* Many new NAND share similar device ID codes, which represent the size of the
* chip. The rest of the parameters must be decoded according to generic or
@@ -3110,7 +3139,7 @@ static void nand_decode_ext_id(struct mtd_info *mtd, struct nand_chip *chip,
{
int extid, id_len;
/* The 3rd id byte holds MLC / multichip data */
- chip->cellinfo = id_data[2];
+ chip->bits_per_cell = nand_get_bits_per_cell(id_data[2]);
/* The 4th id byte is the important one */
extid = id_data[3];
@@ -3126,8 +3155,7 @@ static void nand_decode_ext_id(struct mtd_info *mtd, struct nand_chip *chip,
* ID to decide what to do.
*/
if (id_len == 6 && id_data[0] == NAND_MFR_SAMSUNG &&
- (chip->cellinfo & NAND_CI_CELLTYPE_MSK) &&
- id_data[5] != 0x00) {
+ !nand_is_slc(chip) && id_data[5] != 0x00) {
/* Calc pagesize */
mtd->writesize = 2048 << (extid & 0x03);
extid >>= 2;
@@ -3159,7 +3187,7 @@ static void nand_decode_ext_id(struct mtd_info *mtd, struct nand_chip *chip,
(((extid >> 1) & 0x04) | (extid & 0x03));
*busw = 0;
} else if (id_len == 6 && id_data[0] == NAND_MFR_HYNIX &&
- (chip->cellinfo & NAND_CI_CELLTYPE_MSK)) {
+ !nand_is_slc(chip)) {
unsigned int tmp;
/* Calc pagesize */
@@ -3212,6 +3240,20 @@ static void nand_decode_ext_id(struct mtd_info *mtd, struct nand_chip *chip,
extid >>= 2;
/* Get buswidth information */
*busw = (extid & 0x01) ? NAND_BUSWIDTH_16 : 0;
+ /*
+ * Toshiba 24nm raw SLC (i.e., not BENAND) have 32B OOB per
+ * 512B page. For Toshiba SLC, we decode the 5th/6th byte as
+ * follows:
+ * - ID byte 6, bits[2:0]: 100b -> 43nm, 101b -> 32nm,
+ * 110b -> 24nm
+ * - ID byte 5, bit[7]: 1 -> BENAND, 0 -> raw SLC
+ */
+ if (id_len >= 6 && id_data[0] == NAND_MFR_TOSHIBA &&
+ nand_is_slc(chip) &&
+ (id_data[5] & 0x7) == 0x6 /* 24nm */ &&
+ !(id_data[4] & 0x80) /* !BENAND */) {
+ mtd->oobsize = 32 * mtd->writesize >> 9;
+ }
}
}
@@ -3231,6 +3273,9 @@ static void nand_decode_id(struct mtd_info *mtd, struct nand_chip *chip,
mtd->oobsize = mtd->writesize / 32;
*busw = type->options & NAND_BUSWIDTH_16;
+ /* All legacy ID NAND are small-page, SLC */
+ chip->bits_per_cell = 1;
+
/*
* Check for Spansion/AMD ID + repeating 5th, 6th byte since
* some Spansion chips have erasesize that conflicts with size
@@ -3267,11 +3312,11 @@ static void nand_decode_bbm_options(struct mtd_info *mtd,
* Micron devices with 2KiB pages and on SLC Samsung, Hynix, Toshiba,
* AMD/Spansion, and Macronix. All others scan only the first page.
*/
- if ((chip->cellinfo & NAND_CI_CELLTYPE_MSK) &&
+ if (!nand_is_slc(chip) &&
(maf_id == NAND_MFR_SAMSUNG ||
maf_id == NAND_MFR_HYNIX))
chip->bbt_options |= NAND_BBT_SCANLASTPAGE;
- else if ((!(chip->cellinfo & NAND_CI_CELLTYPE_MSK) &&
+ else if ((nand_is_slc(chip) &&
(maf_id == NAND_MFR_SAMSUNG ||
maf_id == NAND_MFR_HYNIX ||
maf_id == NAND_MFR_TOSHIBA ||
@@ -3295,7 +3340,7 @@ static bool find_full_id_nand(struct mtd_info *mtd, struct nand_chip *chip,
mtd->erasesize = type->erasesize;
mtd->oobsize = type->oobsize;
- chip->cellinfo = id_data[2];
+ chip->bits_per_cell = nand_get_bits_per_cell(id_data[2]);
chip->chipsize = (uint64_t)type->chipsize << 20;
chip->options |= type->options;
@@ -3675,25 +3720,22 @@ int nand_scan_tail(struct mtd_info *mtd)
chip->ecc.read_oob = nand_read_oob_std;
chip->ecc.write_oob = nand_write_oob_std;
/*
- * Board driver should supply ecc.size and ecc.bytes values to
- * select how many bits are correctable; see nand_bch_init()
- * for details. Otherwise, default to 4 bits for large page
- * devices.
+ * Board driver should supply ecc.size and ecc.strength values
+ * to select how many bits are correctable. Otherwise, default
+ * to 4 bits for large page devices.
*/
if (!chip->ecc.size && (mtd->oobsize >= 64)) {
chip->ecc.size = 512;
- chip->ecc.bytes = 7;
+ chip->ecc.strength = 4;
}
- chip->ecc.priv = nand_bch_init(mtd,
- chip->ecc.size,
- chip->ecc.bytes,
- &chip->ecc.layout);
+
+ /* See nand_bch_init() for details. */
+ chip->ecc.bytes = 0;
+ chip->ecc.priv = nand_bch_init(mtd);
if (!chip->ecc.priv) {
pr_warn("BCH ECC initialization failed!\n");
BUG();
}
- chip->ecc.strength =
- chip->ecc.bytes * 8 / fls(8 * chip->ecc.size);
break;
#endif
#ifdef CONFIG_NAND_ECC_NONE
@@ -3744,8 +3786,7 @@ int nand_scan_tail(struct mtd_info *mtd)
chip->ecc.total = chip->ecc.steps * chip->ecc.bytes;
/* Allow subpage writes up to ecc.steps. Not possible for MLC flash */
- if (!(chip->options & NAND_NO_SUBPAGE_WRITE) &&
- !(chip->cellinfo & NAND_CI_CELLTYPE_MSK)) {
+ if (!(chip->options & NAND_NO_SUBPAGE_WRITE) && nand_is_slc(chip)) {
switch (chip->ecc.steps) {
case 2:
mtd->subpage_sft = 1;
@@ -3805,7 +3846,7 @@ int nand_scan_tail(struct mtd_info *mtd)
return 0;
/* Build bad block table */
- return chip->scan_bbt(mtd);
+ return nand_create_bbt(mtd);
}
EXPORT_SYMBOL(nand_scan_tail);
diff --git a/drivers/mtd/nand/nand_bbt.c b/drivers/mtd/nand/nand_bbt.c
index 94a2e57834..90c10862c5 100644
--- a/drivers/mtd/nand/nand_bbt.c
+++ b/drivers/mtd/nand/nand_bbt.c
@@ -77,6 +77,8 @@
#define BBT_ENTRY_MASK 0x03
#define BBT_ENTRY_SHIFT 2
+static int nand_update_bbt(struct mtd_info *mtd, loff_t offs);
+
static inline uint8_t bbt_get_entry(struct nand_chip *chip, int block)
{
uint8_t entry = chip->bbt[block >> BBT_ENTRY_SHIFT];
@@ -87,8 +89,14 @@ static inline uint8_t bbt_get_entry(struct nand_chip *chip, int block)
static inline void bbt_mark_entry(struct nand_chip *chip, int block,
uint8_t mark)
{
- uint8_t msk = (mark & BBT_ENTRY_MASK) << ((block & BBT_ENTRY_MASK) * 2);
- chip->bbt[block >> BBT_ENTRY_SHIFT] |= msk;
+ /*
+ * Unlike original Linux implementation, Barebox needs also
+ * mark block as good again, so mask entry comletely.
+ */
+ int index = block >> BBT_ENTRY_SHIFT;
+ int shift = (block & BBT_ENTRY_MASK) * 2;
+ chip->bbt[index] &= ~(BBT_ENTRY_MASK << shift);
+ chip->bbt[index] |= (mark & BBT_ENTRY_MASK) << shift;
}
static int check_pattern_no_oob(uint8_t *buf, struct nand_bbt_descr *td)
@@ -106,33 +114,17 @@ static int check_pattern_no_oob(uint8_t *buf, struct nand_bbt_descr *td)
* @td: search pattern descriptor
*
* Check for a pattern at the given place. Used to search bad block tables and
- * good / bad block identifiers. If the SCAN_EMPTY option is set then check, if
- * all bytes except the pattern area contain 0xff.
+ * good / bad block identifiers.
*/
static int check_pattern(uint8_t *buf, int len, int paglen, struct nand_bbt_descr *td)
{
- int end = 0;
- uint8_t *p = buf;
-
if (td->options & NAND_BBT_NO_OOB)
return check_pattern_no_oob(buf, td);
- end = paglen + td->offs;
- if (td->options & NAND_BBT_SCANEMPTY)
- if (memchr_inv(p, 0xff, end))
- return -1;
- p += end;
-
/* Compare the pattern */
- if (memcmp(p, td->pattern, td->len))
+ if (memcmp(buf + paglen + td->offs, td->pattern, td->len))
return -1;
- if (td->options & NAND_BBT_SCANEMPTY) {
- p += td->len;
- end += td->len;
- if (memchr_inv(p, 0xff, len - end))
- return -1;
- }
return 0;
}
@@ -179,7 +171,7 @@ static u32 add_marker_len(struct nand_bbt_descr *td)
* @page: the starting page
* @num: the number of bbt descriptors to read
* @td: the bbt describtion table
- * @offs: offset in the memory table
+ * @offs: block number offset in the table
*
* Read the bad block table starting from page.
*/
@@ -229,29 +221,28 @@ static int read_bbt(struct mtd_info *mtd, uint8_t *buf, int page, int num,
/* Analyse data */
for (i = 0; i < len; i++) {
uint8_t dat = buf[i];
- for (j = 0; j < 8; j += bits, act += 2) {
+ for (j = 0; j < 8; j += bits, act++) {
uint8_t tmp = (dat >> j) & msk;
if (tmp == msk)
continue;
if (reserved_block_code && (tmp == reserved_block_code)) {
pr_info("nand_read_bbt: reserved block at 0x%012llx\n",
- (loff_t)((offs << 2) + (act >> 1)) << this->bbt_erase_shift);
- bbt_mark_entry(this, (offs << 2) +
- (act >> 1),
+ (loff_t)(offs + act) <<
+ this->bbt_erase_shift);
+ bbt_mark_entry(this, offs + act,
BBT_BLOCK_RESERVED);
mtd->ecc_stats.bbtblocks++;
continue;
}
pr_debug("nand_read_bbt: bad block at 0x%012llx\n",
- (loff_t)((offs << 2) + (act >> 1)) << this->bbt_erase_shift);
+ (loff_t)(offs + act) <<
+ this->bbt_erase_shift);
/* Factory marked bad or worn out? */
if (tmp == 0)
- bbt_mark_entry(this, (offs << 2) +
- (act >> 1),
+ bbt_mark_entry(this, offs + act,
BBT_BLOCK_FACTORY_BAD);
else
- bbt_mark_entry(this, (offs << 2) +
- (act >> 1),
+ bbt_mark_entry(this, offs + act,
BBT_BLOCK_WORN);
mtd->ecc_stats.badblocks++;
}
@@ -287,7 +278,7 @@ static int read_abs_bbt(struct mtd_info *mtd, uint8_t *buf, struct nand_bbt_desc
td, offs);
if (res)
return res;
- offs += this->chipsize >> (this->bbt_erase_shift + 2);
+ offs += this->chipsize >> this->bbt_erase_shift;
}
} else {
res = read_bbt(mtd, buf, td->pages[0],
@@ -421,25 +412,6 @@ static void read_abs_bbts(struct mtd_info *mtd, uint8_t *buf,
}
}
-/* Scan a given block full */
-static int scan_block_full(struct mtd_info *mtd, struct nand_bbt_descr *bd,
- loff_t offs, uint8_t *buf, size_t readlen,
- int scanlen, int numpages)
-{
- int ret, j;
-
- ret = scan_read_oob(mtd, buf, offs, readlen);
- /* Ignore ECC errors when checking for BBM */
- if (ret && !mtd_is_bitflip_or_eccerr(ret))
- return ret;
-
- for (j = 0; j < numpages; j++, buf += scanlen) {
- if (check_pattern(buf, scanlen, mtd->writesize, bd))
- return 1;
- }
- return 0;
-}
-
/* Scan a given block partially */
static int scan_block_fast(struct mtd_info *mtd, struct nand_bbt_descr *bd,
loff_t offs, uint8_t *buf, int numpages)
@@ -486,36 +458,19 @@ static int create_bbt(struct mtd_info *mtd, uint8_t *buf,
struct nand_bbt_descr *bd, int chip)
{
struct nand_chip *this = mtd->priv;
- int i, numblocks, numpages, scanlen;
+ int i, numblocks, numpages;
int startblock;
loff_t from;
- size_t readlen;
pr_info("Scanning device for bad blocks\n");
- if (bd->options & NAND_BBT_SCANALLPAGES)
- numpages = 1 << (this->bbt_erase_shift - this->page_shift);
- else if (bd->options & NAND_BBT_SCAN2NDPAGE)
+ if (bd->options & NAND_BBT_SCAN2NDPAGE)
numpages = 2;
else
numpages = 1;
- if (!(bd->options & NAND_BBT_SCANEMPTY)) {
- /* We need only read few bytes from the OOB area */
- scanlen = 0;
- readlen = bd->len;
- } else {
- /* Full page content should be read */
- scanlen = mtd->writesize + mtd->oobsize;
- readlen = numpages * mtd->writesize;
- }
-
if (chip == -1) {
- /*
- * Note that numblocks is 2 * (real numblocks) here, see i+=2
- * below as it makes shifting and masking less painful
- */
- numblocks = mtd->size >> (this->bbt_erase_shift - 1);
+ numblocks = mtd->size >> this->bbt_erase_shift;
startblock = 0;
from = 0;
} else {
@@ -524,37 +479,31 @@ static int create_bbt(struct mtd_info *mtd, uint8_t *buf,
chip + 1, this->numchips);
return -EINVAL;
}
- numblocks = this->chipsize >> (this->bbt_erase_shift - 1);
+ numblocks = this->chipsize >> this->bbt_erase_shift;
startblock = chip * numblocks;
numblocks += startblock;
- from = (loff_t)startblock << (this->bbt_erase_shift - 1);
+ from = (loff_t)startblock << this->bbt_erase_shift;
}
if (this->bbt_options & NAND_BBT_SCANLASTPAGE)
from += mtd->erasesize - (mtd->writesize * numpages);
- for (i = startblock; i < numblocks;) {
+ for (i = startblock; i < numblocks; i++) {
int ret;
BUG_ON(bd->options & NAND_BBT_NO_OOB);
- if (bd->options & NAND_BBT_SCANALLPAGES)
- ret = scan_block_full(mtd, bd, from, buf, readlen,
- scanlen, numpages);
- else
- ret = scan_block_fast(mtd, bd, from, buf, numpages);
-
+ ret = scan_block_fast(mtd, bd, from, buf, numpages);
if (ret < 0)
return ret;
if (ret) {
- bbt_mark_entry(this, i >> 1, BBT_BLOCK_FACTORY_BAD);
+ bbt_mark_entry(this, i, BBT_BLOCK_FACTORY_BAD);
pr_warn("Bad eraseblock %d at 0x%012llx\n",
- i >> 1, (unsigned long long)from);
+ i, (unsigned long long)from);
mtd->ecc_stats.badblocks++;
}
- i += 2;
from += (1 << this->bbt_erase_shift);
}
return 0;
@@ -659,6 +608,100 @@ static void search_read_bbts(struct mtd_info *mtd, uint8_t *buf,
}
/**
+ * get_bbt_block - Get the first valid eraseblock suitable to store a BBT
+ * @this: the NAND device
+ * @td: the BBT description
+ * @md: the mirror BBT descriptor
+ * @chip: the CHIP selector
+ *
+ * This functions returns a positive block number pointing a valid eraseblock
+ * suitable to store a BBT (i.e. in the range reserved for BBT), or -ENOSPC if
+ * all blocks are already used of marked bad. If td->pages[chip] was already
+ * pointing to a valid block we re-use it, otherwise we search for the next
+ * valid one.
+ */
+static int get_bbt_block(struct nand_chip *this, struct nand_bbt_descr *td,
+ struct nand_bbt_descr *md, int chip)
+{
+ int startblock, dir, page, numblocks, i;
+
+ /*
+ * There was already a version of the table, reuse the page. This
+ * applies for absolute placement too, as we have the page number in
+ * td->pages.
+ */
+ if (td->pages[chip] != -1)
+ return td->pages[chip] >>
+ (this->bbt_erase_shift - this->page_shift);
+
+ numblocks = (int)(this->chipsize >> this->bbt_erase_shift);
+ if (!(td->options & NAND_BBT_PERCHIP))
+ numblocks *= this->numchips;
+
+ /*
+ * Automatic placement of the bad block table. Search direction
+ * top -> down?
+ */
+ if (td->options & NAND_BBT_LASTBLOCK) {
+ startblock = numblocks * (chip + 1) - 1;
+ dir = -1;
+ } else {
+ startblock = chip * numblocks;
+ dir = 1;
+ }
+
+ for (i = 0; i < td->maxblocks; i++) {
+ int block = startblock + dir * i;
+
+ /* Check, if the block is bad */
+ switch (bbt_get_entry(this, block)) {
+ case BBT_BLOCK_WORN:
+ case BBT_BLOCK_FACTORY_BAD:
+ continue;
+ }
+
+ page = block << (this->bbt_erase_shift - this->page_shift);
+
+ /* Check, if the block is used by the mirror table */
+ if (!md || md->pages[chip] != page)
+ return block;
+ }
+
+ return -ENOSPC;
+}
+
+/**
+ * mark_bbt_block_bad - Mark one of the block reserved for BBT bad
+ * @mtd: the MTD device
+ * @td: the BBT description
+ * @chip: the CHIP selector
+ * @block: the BBT block to mark
+ *
+ * Blocks reserved for BBT can become bad. This functions is an helper to mark
+ * such blocks as bad. It takes care of updating the in-memory BBT, marking the
+ * block as bad using a bad block marker and invalidating the associated
+ * td->pages[] entry.
+ */
+static void mark_bbt_block_bad(struct mtd_info *mtd,
+ struct nand_bbt_descr *td,
+ int chip, int block)
+{
+ struct nand_chip *this = mtd->priv;
+ loff_t to;
+ int res;
+
+ bbt_mark_entry(this, block, BBT_BLOCK_WORN);
+
+ to = (loff_t)block << this->bbt_erase_shift;
+ res = this->block_markbad(mtd, to);
+ if (res)
+ pr_warn("nand_bbt: error %d while marking block %d bad\n",
+ res, block);
+
+ td->pages[chip] = -1;
+}
+
+/**
* write_bbt - [GENERIC] (Re)write the bad block table
* @mtd: MTD device structure
* @buf: temporary buffer
@@ -674,9 +717,9 @@ static int write_bbt(struct mtd_info *mtd, uint8_t *buf,
{
struct nand_chip *this = mtd->priv;
struct erase_info einfo;
- int i, j, res, chip = 0;
- int bits, startblock, dir, page, offs, numblocks, sft, sftmsk;
- int nrchips, bbtoffs, pageoffs, ooboffs;
+ int i, res, chip = 0;
+ int bits, page, offs, numblocks, sft, sftmsk;
+ int nrchips, pageoffs, ooboffs;
uint8_t msk[4];
uint8_t rcode = td->reserved_block_code;
size_t retlen, len = 0;
@@ -706,46 +749,21 @@ static int write_bbt(struct mtd_info *mtd, uint8_t *buf,
}
/* Loop through the chips */
- for (; chip < nrchips; chip++) {
- /*
- * There was already a version of the table, reuse the page
- * This applies for absolute placement too, as we have the
- * page nr. in td->pages.
- */
- if (td->pages[chip] != -1) {
- page = td->pages[chip];
- goto write;
+ while (chip < nrchips) {
+ int block;
+
+ block = get_bbt_block(this, td, md, chip);
+ if (block < 0) {
+ pr_err("No space left to write bad block table\n");
+ res = block;
+ goto outerr;
}
/*
- * Automatic placement of the bad block table. Search direction
- * top -> down?
+ * get_bbt_block() returns a block number, shift the value to
+ * get a page number.
*/
- if (td->options & NAND_BBT_LASTBLOCK) {
- startblock = numblocks * (chip + 1) - 1;
- dir = -1;
- } else {
- startblock = chip * numblocks;
- dir = 1;
- }
-
- for (i = 0; i < td->maxblocks; i++) {
- int block = startblock + dir * i;
- /* Check, if the block is bad */
- switch (bbt_get_entry(this, block)) {
- case BBT_BLOCK_WORN:
- case BBT_BLOCK_FACTORY_BAD:
- continue;
- }
- page = block <<
- (this->bbt_erase_shift - this->page_shift);
- /* Check, if the block is used by the mirror table */
- if (!md || md->pages[chip] != page)
- goto write;
- }
- pr_err("No space left to write bad block table\n");
- return -ENOSPC;
- write:
+ page = block << (this->bbt_erase_shift - this->page_shift);
/* Set up shift count and masks for the flash table */
bits = td->options & NAND_BBT_NRBITS_MSK;
@@ -766,8 +784,6 @@ static int write_bbt(struct mtd_info *mtd, uint8_t *buf,
default: return -EINVAL;
}
- bbtoffs = chip * (numblocks >> 2);
-
to = ((loff_t)page) << this->page_shift;
/* Must we save the block contents? */
@@ -830,16 +846,12 @@ static int write_bbt(struct mtd_info *mtd, uint8_t *buf,
buf[ooboffs + td->veroffs] = td->version[chip];
/* Walk through the memory table */
- for (i = 0; i < numblocks;) {
+ for (i = 0; i < numblocks; i++) {
uint8_t dat;
- dat = bbt_get_entry(this, (bbtoffs << 2) + i);
- for (j = 0; j < 4; j++, i++) {
- int sftcnt = (i << (3 - sft)) & sftmsk;
- /* Do not store the reserved bbt blocks! */
- buf[offs + (i >> sft)] &=
- ~(msk[dat & 0x03] << sftcnt);
- dat >>= 2;
- }
+ int sftcnt = (i << (3 - sft)) & sftmsk;
+ dat = bbt_get_entry(this, chip * numblocks + i);
+ /* Do not store the reserved bbt blocks! */
+ buf[offs + (i >> sft)] &= ~(msk[dat] << sftcnt);
}
memset(&einfo, 0, sizeof(einfo));
@@ -847,20 +859,28 @@ static int write_bbt(struct mtd_info *mtd, uint8_t *buf,
einfo.addr = to;
einfo.len = 1 << this->bbt_erase_shift;
res = nand_erase_nand(mtd, &einfo, 1);
- if (res < 0)
- goto outerr;
+ if (res < 0) {
+ pr_warn("nand_bbt: error while erasing BBT block %d\n",
+ res);
+ mark_bbt_block_bad(mtd, td, chip, block);
+ continue;
+ }
res = scan_write_bbt(mtd, to, len, buf,
td->options & NAND_BBT_NO_OOB ? NULL :
&buf[len]);
- if (res < 0)
- goto outerr;
+ if (res < 0) {
+ pr_warn("nand_bbt: error while writing BBT block %d\n",
+ res);
+ mark_bbt_block_bad(mtd, td, chip, block);
+ continue;
+ }
pr_info("Bad block table written to 0x%012llx, version 0x%02X\n",
(unsigned long long)to, td->version[chip]);
/* Mark it as used */
- td->pages[chip] = page;
+ td->pages[chip++] = page;
}
return 0;
@@ -881,7 +901,6 @@ static inline int nand_memory_bbt(struct mtd_info *mtd, struct nand_bbt_descr *b
{
struct nand_chip *this = mtd->priv;
- bd->options &= ~NAND_BBT_SCANEMPTY;
return create_bbt(mtd, this->buffers->databuf, bd, -1);
}
@@ -1042,12 +1061,12 @@ static void mark_bbt_region(struct mtd_info *mtd, struct nand_bbt_descr *td)
if (td->pages[i] == -1)
continue;
block = td->pages[i] >> (this->bbt_erase_shift - this->page_shift);
- block <<= 1;
- oldval = bbt_get_entry(this, block >> 1);
- bbt_mark_entry(this, block >> 1, BBT_BLOCK_RESERVED);
+ oldval = bbt_get_entry(this, block);
+ bbt_mark_entry(this, block, BBT_BLOCK_RESERVED);
if ((oldval != BBT_BLOCK_RESERVED) &&
td->reserved_block_code)
- nand_update_bbt(mtd, (loff_t)block << (this->bbt_erase_shift - 1));
+ nand_update_bbt(mtd, (loff_t)block <<
+ this->bbt_erase_shift);
continue;
}
update = 0;
@@ -1055,13 +1074,12 @@ static void mark_bbt_region(struct mtd_info *mtd, struct nand_bbt_descr *td)
block = ((i + 1) * nrblocks) - td->maxblocks;
else
block = i * nrblocks;
- block <<= 1;
for (j = 0; j < td->maxblocks; j++) {
- oldval = bbt_get_entry(this, block >> 1);
- bbt_mark_entry(this, block >> 1, BBT_BLOCK_RESERVED);
+ oldval = bbt_get_entry(this, block);
+ bbt_mark_entry(this, block, BBT_BLOCK_RESERVED);
if (oldval != BBT_BLOCK_RESERVED)
update = 1;
- block += 2;
+ block++;
}
/*
* If we want reserved blocks to be recorded to flash, and some
@@ -1069,7 +1087,8 @@ static void mark_bbt_region(struct mtd_info *mtd, struct nand_bbt_descr *td)
* bbts. This should only happen once.
*/
if (update && td->reserved_block_code)
- nand_update_bbt(mtd, (loff_t)(block - 2) << (this->bbt_erase_shift - 1));
+ nand_update_bbt(mtd, (loff_t)(block - 1) <<
+ this->bbt_erase_shift);
}
}
@@ -1133,10 +1152,10 @@ static void verify_bbt_descr(struct mtd_info *mtd, struct nand_bbt_descr *bd)
* The bad block table memory is allocated here. It must be freed by calling
* the nand_free_bbt function.
*/
-int nand_scan_bbt(struct mtd_info *mtd, struct nand_bbt_descr *bd)
+static int nand_scan_bbt(struct mtd_info *mtd, struct nand_bbt_descr *bd)
{
struct nand_chip *this = mtd->priv;
- int len, res = 0;
+ int len, res;
uint8_t *buf;
struct nand_bbt_descr *td = this->bbt_td;
struct nand_bbt_descr *md = this->bbt_md;
@@ -1157,10 +1176,9 @@ int nand_scan_bbt(struct mtd_info *mtd, struct nand_bbt_descr *bd)
if (!td) {
if ((res = nand_memory_bbt(mtd, bd))) {
pr_err("nand_bbt: can't scan flash and build the RAM-based BBT\n");
- kfree(this->bbt);
- this->bbt = NULL;
+ goto err;
}
- return res;
+ return 0;
}
verify_bbt_descr(mtd, td);
verify_bbt_descr(mtd, md);
@@ -1170,9 +1188,8 @@ int nand_scan_bbt(struct mtd_info *mtd, struct nand_bbt_descr *bd)
len += (len >> this->page_shift) * mtd->oobsize;
buf = vmalloc(len);
if (!buf) {
- kfree(this->bbt);
- this->bbt = NULL;
- return -ENOMEM;
+ res = -ENOMEM;
+ goto err;
}
/* Is the bbt at a given page? */
@@ -1184,6 +1201,8 @@ int nand_scan_bbt(struct mtd_info *mtd, struct nand_bbt_descr *bd)
}
res = check_create(mtd, buf, bd);
+ if (res)
+ goto err;
/* Prevent the bbt regions from erasing / writing */
mark_bbt_region(mtd, td);
@@ -1191,17 +1210,22 @@ int nand_scan_bbt(struct mtd_info *mtd, struct nand_bbt_descr *bd)
mark_bbt_region(mtd, md);
vfree(buf);
+ return 0;
+
+err:
+ kfree(this->bbt);
+ this->bbt = NULL;
return res;
}
/**
- * nand_update_bbt - [NAND Interface] update bad block table(s)
+ * nand_update_bbt - update bad block table(s)
* @mtd: MTD device structure
* @offs: the offset of the newly marked block
*
* The function updates the bad block table(s).
*/
-int nand_update_bbt(struct mtd_info *mtd, loff_t offs)
+static int nand_update_bbt(struct mtd_info *mtd, loff_t offs)
{
struct nand_chip *this = mtd->priv;
int len, res = 0;
@@ -1329,15 +1353,16 @@ static int nand_create_badblock_pattern(struct nand_chip *this)
}
/**
- * nand_default_bbt - [NAND Interface] Select a default bad block table for the device
+ * nand_create_bbt - [NAND Interface] Select a default bad block table for the device
* @mtd: MTD device structure
*
* This function selects the default bad block table support for the device and
* calls the nand_scan_bbt function.
*/
-int nand_default_bbt(struct mtd_info *mtd)
+int nand_create_bbt(struct mtd_info *mtd)
{
struct nand_chip *this = mtd->priv;
+ int ret;
/* Is a flash based bad block table requested? */
if (this->bbt_options & NAND_BBT_USE_FLASH) {
@@ -1356,8 +1381,11 @@ int nand_default_bbt(struct mtd_info *mtd)
this->bbt_md = NULL;
}
- if (!this->badblock_pattern)
- nand_create_badblock_pattern(this);
+ if (!this->badblock_pattern) {
+ ret = nand_create_badblock_pattern(this);
+ if (ret)
+ return ret;
+ }
return nand_scan_bbt(mtd, this->badblock_pattern);
}
@@ -1374,12 +1402,11 @@ int nand_isbad_bbt(struct mtd_info *mtd, loff_t offs, int allowbbt)
int block;
uint8_t res;
- /* Get block number * 2 */
- block = (int)(offs >> (this->bbt_erase_shift - 1));
- res = bbt_get_entry(this, block >> 1);
+ block = (int)(offs >> this->bbt_erase_shift);
+ res = bbt_get_entry(this, block);
pr_debug("nand_isbad_bbt(): bbt info for offs 0x%08x: (block %d) 0x%02x\n",
- (unsigned int)offs, block >> 1, res);
+ (unsigned int)offs, block, res);
switch ((int)res) {
case BBT_BLOCK_GOOD:
@@ -1392,6 +1419,41 @@ int nand_isbad_bbt(struct mtd_info *mtd, loff_t offs, int allowbbt)
return 1;
}
+static int nand_mark_bbt(struct mtd_info *mtd, loff_t offs, uint8_t mark)
+{
+ struct nand_chip *this = mtd->priv;
+ int block, ret = 0;
+
+ block = (int)(offs >> this->bbt_erase_shift);
+
+ /* Mark bad block in memory */
+ bbt_mark_entry(this, block, mark);
+
+ /* Update flash-based bad block table */
+ if (this->bbt_options & NAND_BBT_USE_FLASH)
+ ret = nand_update_bbt(mtd, offs);
+
+ return ret;
+}
+
+/**
+ * nand_markbad_bbt - [NAND Interface] Mark a block bad in the BBT
+ * @mtd: MTD device structure
+ * @offs: offset of the bad block
+ */
+int nand_markbad_bbt(struct mtd_info *mtd, loff_t offs)
+{
+ return nand_mark_bbt(mtd, offs, BBT_BLOCK_WORN);
+}
+
+/**
+ * nand_markbad_bbt - [NAND Interface] Mark a block good in the BBT
+ * @mtd: MTD device structure
+ * @offs: offset of the good block
+ */
+int nand_markgood_bbt(struct mtd_info *mtd, loff_t offs)
+{
+ return nand_mark_bbt(mtd, offs, BBT_BLOCK_GOOD);
+}
+
EXPORT_SYMBOL(nand_scan_bbt);
-EXPORT_SYMBOL(nand_default_bbt);
-EXPORT_SYMBOL_GPL(nand_update_bbt);
diff --git a/drivers/mtd/nand/nand_bch.c b/drivers/mtd/nand/nand_bch.c
index e37135f514..d4f2a8cbe4 100644
--- a/drivers/mtd/nand/nand_bch.c
+++ b/drivers/mtd/nand/nand_bch.c
@@ -104,9 +104,6 @@ EXPORT_SYMBOL(nand_bch_correct_data);
/**
* nand_bch_init - [NAND Interface] Initialize NAND BCH error correction
* @mtd: MTD block structure
- * @eccsize: ecc block size in bytes
- * @eccbytes: ecc length in bytes
- * @ecclayout: output default layout
*
* Returns:
* a pointer to a new NAND BCH control structure, or NULL upon failure
@@ -120,14 +117,21 @@ EXPORT_SYMBOL(nand_bch_correct_data);
* @eccsize = 512 (thus, m=13 is the smallest integer such that 2^m-1 > 512*8)
* @eccbytes = 7 (7 bytes are required to store m*t = 13*4 = 52 bits)
*/
-struct nand_bch_control *
-nand_bch_init(struct mtd_info *mtd, unsigned int eccsize, unsigned int eccbytes,
- struct nand_ecclayout **ecclayout)
+struct nand_bch_control *nand_bch_init(struct mtd_info *mtd)
{
+ struct nand_chip *nand = mtd->priv;
unsigned int m, t, eccsteps, i;
- struct nand_ecclayout *layout;
+ struct nand_ecclayout *layout = nand->ecc.layout;
struct nand_bch_control *nbc = NULL;
unsigned char *erased_page;
+ unsigned int eccsize = nand->ecc.size;
+ unsigned int eccbytes = nand->ecc.bytes;
+ unsigned int eccstrength = nand->ecc.strength;
+
+ if (!eccbytes && eccstrength) {
+ eccbytes = DIV_ROUND_UP(eccstrength * fls(8 * eccsize), 8);
+ nand->ecc.bytes = eccbytes;
+ }
if (!eccsize || !eccbytes) {
printk(KERN_WARNING "ecc parameters not supplied\n");
@@ -155,7 +159,7 @@ nand_bch_init(struct mtd_info *mtd, unsigned int eccsize, unsigned int eccbytes,
eccsteps = mtd->writesize/eccsize;
/* if no ecc placement scheme was provided, build one */
- if (!*ecclayout) {
+ if (!layout) {
/* handle large page devices only */
if (mtd->oobsize < 64) {
@@ -181,7 +185,7 @@ nand_bch_init(struct mtd_info *mtd, unsigned int eccsize, unsigned int eccbytes,
layout->oobfree[0].offset = 2;
layout->oobfree[0].length = mtd->oobsize-2-layout->eccbytes;
- *ecclayout = layout;
+ nand->ecc.layout = layout;
}
/* sanity checks */
@@ -189,7 +193,7 @@ nand_bch_init(struct mtd_info *mtd, unsigned int eccsize, unsigned int eccbytes,
printk(KERN_WARNING "eccsize %u is too large\n", eccsize);
goto fail;
}
- if ((*ecclayout)->eccbytes != (eccsteps*eccbytes)) {
+ if (layout->eccbytes != (eccsteps*eccbytes)) {
printk(KERN_WARNING "invalid ecc layout\n");
goto fail;
}
@@ -213,6 +217,9 @@ nand_bch_init(struct mtd_info *mtd, unsigned int eccsize, unsigned int eccbytes,
for (i = 0; i < eccbytes; i++)
nbc->eccmask[i] ^= 0xff;
+ if (!eccstrength)
+ nand->ecc.strength = (eccbytes * 8) / fls(8 * eccsize);
+
return nbc;
fail:
nand_bch_free(nbc);
diff --git a/drivers/mtd/nand/nand_imx_bbm.c b/drivers/mtd/nand/nand_imx_bbm.c
index 23722a9064..4fd5487aa2 100644
--- a/drivers/mtd/nand/nand_imx_bbm.c
+++ b/drivers/mtd/nand/nand_imx_bbm.c
@@ -129,7 +129,7 @@ static int attach_bbt(struct mtd_info *mtd, void *bbt)
free(chip->bbt);
chip->bbt = bbt;
- return nand_update_bbt(mtd, 0);
+ return nand_create_bbt(mtd);
}
static int do_imx_nand_bbm(int argc, char *argv[])
diff --git a/drivers/mtd/nand/nand_mxs.c b/drivers/mtd/nand/nand_mxs.c
index 28a07d4cba..f69453aba5 100644
--- a/drivers/mtd/nand/nand_mxs.c
+++ b/drivers/mtd/nand/nand_mxs.c
@@ -1201,21 +1201,7 @@ static int mxs_nand_block_bad(struct mtd_info *mtd, loff_t ofs, int getchip)
return 0;
}
-/*
- * Nominally, the purpose of this function is to look for or create the bad
- * block table. In fact, since the we call this function at the very end of
- * the initialization process started by nand_scan(), and we doesn't have a
- * more formal mechanism, we "hook" this function to continue init process.
- *
- * At this point, the physical NAND Flash chips have been identified and
- * counted, so we know the physical geometry. This enables us to make some
- * important configuration decisions.
- *
- * The return value of this function propogates directly back to this driver's
- * call to nand_scan(). Anything other than zero will cause this driver to
- * tear everything down and declare failure.
- */
-static int mxs_nand_scan_bbt(struct mtd_info *mtd)
+static int mxs_nand_init_bch(struct mtd_info *mtd)
{
struct nand_chip *nand = mtd->priv;
struct mxs_nand_info *nand_info = nand->priv;
@@ -1252,8 +1238,7 @@ static int mxs_nand_scan_bbt(struct mtd_info *mtd)
mtd->block_markbad = mxs_nand_hook_block_markbad;
}
- /* We use the reference implementation for bad block management. */
- return nand_default_bbt(mtd);
+ return 0;
}
/*
@@ -2183,7 +2168,6 @@ static int mxs_nand_probe(struct device_d *dev)
nand->dev_ready = mxs_nand_device_ready;
nand->select_chip = mxs_nand_select_chip;
nand->block_bad = mxs_nand_block_bad;
- nand->scan_bbt = mxs_nand_scan_bbt;
nand->read_byte = mxs_nand_read_byte;
@@ -2215,6 +2199,13 @@ static int mxs_nand_probe(struct device_d *dev)
mxs_nand_setup_timing(nand_info);
+ err = mxs_nand_init_bch(mtd);
+ if (err)
+ goto err2;
+ err = nand_create_bbt(mtd);
+ if (err)
+ goto err2;
+
/* second phase scan */
err = nand_scan_tail(mtd);
if (err)
diff --git a/drivers/mtd/nand/nand_omap_gpmc.c b/drivers/mtd/nand/nand_omap_gpmc.c
index f8a110e2fc..2dcf7e723b 100644
--- a/drivers/mtd/nand/nand_omap_gpmc.c
+++ b/drivers/mtd/nand/nand_omap_gpmc.c
@@ -125,7 +125,6 @@ static struct nand_ecclayout omap_oobinfo;
*/
static uint8_t scan_ff_pattern[] = { 0xff };
static struct nand_bbt_descr bb_descrip_flashbased = {
- .options = NAND_BBT_SCANEMPTY | NAND_BBT_SCANALLPAGES,
.offs = 0,
.len = 1,
.pattern = scan_ff_pattern,
diff --git a/include/linux/mtd/bbm.h b/include/linux/mtd/bbm.h
index 211ff67e8b..36bb6a503f 100644
--- a/include/linux/mtd/bbm.h
+++ b/include/linux/mtd/bbm.h
@@ -91,10 +91,6 @@ struct nand_bbt_descr {
* with NAND_BBT_CREATE.
*/
#define NAND_BBT_CREATE_EMPTY 0x00000400
-/* Search good / bad pattern through all pages of a block */
-#define NAND_BBT_SCANALLPAGES 0x00000800
-/* Scan block empty during good / bad block scan */
-#define NAND_BBT_SCANEMPTY 0x00001000
/* Write bbt if neccecary */
#define NAND_BBT_WRITE 0x00002000
/* Read and write back block contents when writing bbt */
diff --git a/include/linux/mtd/nand.h b/include/linux/mtd/nand.h
index ec2237f7c9..c3eb16f906 100644
--- a/include/linux/mtd/nand.h
+++ b/include/linux/mtd/nand.h
@@ -203,6 +203,7 @@ typedef enum {
/* Cell info constants */
#define NAND_CI_CHIPNR_MSK 0x03
#define NAND_CI_CELLTYPE_MSK 0x0C
+#define NAND_CI_CELLTYPE_SHIFT 2
/* Keep gcc happy */
struct nand_chip;
@@ -398,7 +399,6 @@ struct nand_buffers {
* @select_chip: [REPLACEABLE] select chip nr
* @block_bad: [REPLACEABLE] check, if the block is bad
* @block_markbad: [REPLACEABLE] mark the block bad
- * @block_markgood: [REPLACEABLE] mark the block good
* @cmd_ctrl: [BOARDSPECIFIC] hardwarespecific function for controlling
* ALE/CLE/nCE. Also used to write command and address
* @init_size: [BOARDSPECIFIC] hardwarespecific function for setting
@@ -418,7 +418,6 @@ struct nand_buffers {
* @hwcontrol: platform-specific hardware control structure
* @erase_cmd: [INTERN] erase command write function, selectable due
* to AND support.
- * @scan_bbt: [REPLACEABLE] function to scan bad block table
* @chip_delay: [BOARDSPECIFIC] chip dependent delay for transferring
* data from array to read regs (tR).
* @state: [INTERN] the current state of the NAND device
@@ -441,7 +440,6 @@ struct nand_buffers {
* bad block marker position; i.e., BBM == 11110111b is
* not bad when badblockbits == 7
* @bits_per_cell: [INTERN] number of bits per cell. i.e., 1 means SLC.
- * @cellinfo: [INTERN] MLC/multichip data from chip ident
* @numchips: [INTERN] number of physical chips
* @chipsize: [INTERN] the size of one chip for multichip arrays
* @pagemask: [INTERN] page number mask = number of (pages / chip) - 1
@@ -484,7 +482,6 @@ struct nand_chip {
void (*select_chip)(struct mtd_info *mtd, int chip);
int (*block_bad)(struct mtd_info *mtd, loff_t ofs, int getchip);
int (*block_markbad)(struct mtd_info *mtd, loff_t ofs);
- int (*block_markgood)(struct mtd_info *mtd, loff_t ofs);
void (*cmd_ctrl)(struct mtd_info *mtd, int dat, unsigned int ctrl);
int (*init_size)(struct mtd_info *mtd, struct nand_chip *this,
u8 *id_data);
@@ -493,7 +490,6 @@ struct nand_chip {
int page_addr);
int(*waitfunc)(struct mtd_info *mtd, struct nand_chip *this);
void (*erase_cmd)(struct mtd_info *mtd, int page);
- int (*scan_bbt)(struct mtd_info *mtd);
int (*errstat)(struct mtd_info *mtd, struct nand_chip *this, int state,
int status, int page);
int (*write_page)(struct mtd_info *mtd, struct nand_chip *chip,
@@ -519,7 +515,6 @@ struct nand_chip {
unsigned int pagebuf_bitflips;
int subpagesize;
uint8_t bits_per_cell;
- uint8_t cellinfo;
int badblockpos;
int badblockbits;
@@ -636,9 +631,9 @@ struct nand_manufacturers {
extern struct nand_flash_dev nand_flash_ids[];
extern struct nand_manufacturers nand_manuf_ids[];
-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);
+extern int nand_create_bbt(struct mtd_info *mtd);
+extern int nand_markbad_bbt(struct mtd_info *mtd, loff_t offs);
+extern int nand_markgood_bbt(struct mtd_info *mtd, loff_t offs);
extern int nand_isbad_bbt(struct mtd_info *mtd, loff_t offs, int allowbbt);
extern int nand_erase_nand(struct mtd_info *mtd, struct erase_info *instr,
int allowbbt);
diff --git a/include/linux/mtd/nand_bch.h b/include/linux/mtd/nand_bch.h
index 61c4607fa8..5465ddd132 100644
--- a/include/linux/mtd/nand_bch.h
+++ b/include/linux/mtd/nand_bch.h
@@ -32,9 +32,7 @@ int nand_bch_correct_data(struct mtd_info *mtd, u_char *dat, u_char *read_ecc,
/*
* Initialize BCH encoder/decoder
*/
-struct nand_bch_control *
-nand_bch_init(struct mtd_info *mtd, unsigned int eccsize,
- unsigned int eccbytes, struct nand_ecclayout **ecclayout);
+struct nand_bch_control *nand_bch_init(struct mtd_info *mtd);
/*
* Release BCH encoder/decoder resources
*/
@@ -58,9 +56,7 @@ nand_bch_correct_data(struct mtd_info *mtd, unsigned char *buf,
return -1;
}
-static inline struct nand_bch_control *
-nand_bch_init(struct mtd_info *mtd, unsigned int eccsize,
- unsigned int eccbytes, struct nand_ecclayout **ecclayout)
+static inline struct nand_bch_control *nand_bch_init(struct mtd_info *mtd)
{
return NULL;
}