xref: /linux/drivers/mtd/nand/raw/nand_bbt.c (revision a881537dfaf281bfcb94313d69dcf9ef8fc89afe)
1d2912cb1SThomas Gleixner // SPDX-License-Identifier: GPL-2.0-only
21da177e4SLinus Torvalds /*
31da177e4SLinus Torvalds  *  Overview:
41da177e4SLinus Torvalds  *   Bad block table support for the NAND driver
51da177e4SLinus Torvalds  *
6d159c4e5SFabio Estevam  *  Copyright © 2004 Thomas Gleixner (tglx@linutronix.de)
71da177e4SLinus Torvalds  *
81da177e4SLinus Torvalds  * Description:
91da177e4SLinus Torvalds  *
101da177e4SLinus Torvalds  * When nand_scan_bbt is called, then it tries to find the bad block table
117cba7b14SSebastian Andrzej Siewior  * depending on the options in the BBT descriptor(s). If no flash based BBT
12bb9ebd4eSBrian Norris  * (NAND_BBT_USE_FLASH) is specified then the device is scanned for factory
137cba7b14SSebastian Andrzej Siewior  * marked good / bad blocks. This information is used to create a memory BBT.
147cba7b14SSebastian Andrzej Siewior  * Once a new bad block is discovered then the "factory" information is updated
157cba7b14SSebastian Andrzej Siewior  * on the device.
167cba7b14SSebastian Andrzej Siewior  * If a flash based BBT is specified then the function first tries to find the
177cba7b14SSebastian Andrzej Siewior  * BBT on flash. If a BBT is found then the contents are read and the memory
187cba7b14SSebastian Andrzej Siewior  * based BBT is created. If a mirrored BBT is selected then the mirror is
197cba7b14SSebastian Andrzej Siewior  * searched too and the versions are compared. If the mirror has a greater
2044ed0ffdSHuang Shijie  * version number, then the mirror BBT is used to build the memory based BBT.
211da177e4SLinus Torvalds  * If the tables are not versioned, then we "or" the bad block information.
227cba7b14SSebastian Andrzej Siewior  * If one of the BBTs is out of date or does not exist it is (re)created.
237cba7b14SSebastian Andrzej Siewior  * If no BBT exists at all then the device is scanned for factory marked
241da177e4SLinus Torvalds  * good / bad blocks and the bad block tables are created.
251da177e4SLinus Torvalds  *
267cba7b14SSebastian Andrzej Siewior  * For manufacturer created BBTs like the one found on M-SYS DOC devices
277cba7b14SSebastian Andrzej Siewior  * the BBT is searched and read but never created
281da177e4SLinus Torvalds  *
291da177e4SLinus Torvalds  * The auto generated bad block table is located in the last good blocks
301da177e4SLinus Torvalds  * of the device. The table is mirrored, so it can be updated eventually.
317cba7b14SSebastian Andrzej Siewior  * The table is marked in the OOB area with an ident pattern and a version
327cba7b14SSebastian Andrzej Siewior  * number which indicates which of both tables is more up to date. If the NAND
337cba7b14SSebastian Andrzej Siewior  * controller needs the complete OOB area for the ECC information then the
34bb9ebd4eSBrian Norris  * option NAND_BBT_NO_OOB should be used (along with NAND_BBT_USE_FLASH, of
35a40f7341SBrian Norris  * course): it moves the ident pattern and the version byte into the data area
36a40f7341SBrian Norris  * and the OOB area will remain untouched.
371da177e4SLinus Torvalds  *
381da177e4SLinus Torvalds  * The table uses 2 bits per block
391da177e4SLinus Torvalds  * 11b:		block is good
401da177e4SLinus Torvalds  * 00b:		block is factory marked bad
411da177e4SLinus Torvalds  * 01b, 10b:	block is marked bad due to wear
421da177e4SLinus Torvalds  *
431da177e4SLinus Torvalds  * The memory bad block table uses the following scheme:
441da177e4SLinus Torvalds  * 00b:		block is good
451da177e4SLinus Torvalds  * 01b:		block is marked bad due to wear
461da177e4SLinus Torvalds  * 10b:		block is reserved (to protect the bbt area)
471da177e4SLinus Torvalds  * 11b:		block is factory marked bad
481da177e4SLinus Torvalds  *
491da177e4SLinus Torvalds  * Multichip devices like DOC store the bad block info per floor.
501da177e4SLinus Torvalds  *
511da177e4SLinus Torvalds  * Following assumptions are made:
521da177e4SLinus Torvalds  * - bbts start at a page boundary, if autolocated on a block boundary
53e0c7d767SDavid Woodhouse  * - the space necessary for a bbt in FLASH does not exceed a block boundary
541da177e4SLinus Torvalds  */
551da177e4SLinus Torvalds 
561da177e4SLinus Torvalds #include <linux/slab.h>
571da177e4SLinus Torvalds #include <linux/types.h>
581da177e4SLinus Torvalds #include <linux/mtd/mtd.h>
5961de9da6SRichard Genoud #include <linux/mtd/bbm.h>
601da177e4SLinus Torvalds #include <linux/bitops.h>
611da177e4SLinus Torvalds #include <linux/delay.h>
62c3f8abf4SDavid Woodhouse #include <linux/vmalloc.h>
63f3bcc017SPaul Gortmaker #include <linux/export.h>
64491ed06fSBrian Norris #include <linux/string.h>
651da177e4SLinus Torvalds 
66348d56a8SBoris Brezillon #include "internals.h"
67348d56a8SBoris Brezillon 
68771c568bSBrian Norris #define BBT_BLOCK_GOOD		0x00
69771c568bSBrian Norris #define BBT_BLOCK_WORN		0x01
70771c568bSBrian Norris #define BBT_BLOCK_RESERVED	0x02
71771c568bSBrian Norris #define BBT_BLOCK_FACTORY_BAD	0x03
72771c568bSBrian Norris 
73771c568bSBrian Norris #define BBT_ENTRY_MASK		0x03
74771c568bSBrian Norris #define BBT_ENTRY_SHIFT		2
75771c568bSBrian Norris 
76771c568bSBrian Norris static inline uint8_t bbt_get_entry(struct nand_chip *chip, int block)
77771c568bSBrian Norris {
78771c568bSBrian Norris 	uint8_t entry = chip->bbt[block >> BBT_ENTRY_SHIFT];
79771c568bSBrian Norris 	entry >>= (block & BBT_ENTRY_MASK) * 2;
80771c568bSBrian Norris 	return entry & BBT_ENTRY_MASK;
81771c568bSBrian Norris }
82771c568bSBrian Norris 
83771c568bSBrian Norris static inline void bbt_mark_entry(struct nand_chip *chip, int block,
84771c568bSBrian Norris 		uint8_t mark)
85771c568bSBrian Norris {
86771c568bSBrian Norris 	uint8_t msk = (mark & BBT_ENTRY_MASK) << ((block & BBT_ENTRY_MASK) * 2);
87771c568bSBrian Norris 	chip->bbt[block >> BBT_ENTRY_SHIFT] |= msk;
88771c568bSBrian Norris }
89771c568bSBrian Norris 
907cba7b14SSebastian Andrzej Siewior static int check_pattern_no_oob(uint8_t *buf, struct nand_bbt_descr *td)
917cba7b14SSebastian Andrzej Siewior {
92718894adSBrian Norris 	if (memcmp(buf, td->pattern, td->len))
937cba7b14SSebastian Andrzej Siewior 		return -1;
94718894adSBrian Norris 	return 0;
957cba7b14SSebastian Andrzej Siewior }
967cba7b14SSebastian Andrzej Siewior 
971da177e4SLinus Torvalds /**
981da177e4SLinus Torvalds  * check_pattern - [GENERIC] check if a pattern is in the buffer
991da177e4SLinus Torvalds  * @buf: the buffer to search
1001da177e4SLinus Torvalds  * @len: the length of buffer to search
1011da177e4SLinus Torvalds  * @paglen: the pagelength
1021da177e4SLinus Torvalds  * @td: search pattern descriptor
1031da177e4SLinus Torvalds  *
1048b6e50c9SBrian Norris  * Check for a pattern at the given place. Used to search bad block tables and
105dad22562SBrian Norris  * good / bad block identifiers.
1061da177e4SLinus Torvalds  */
1071da177e4SLinus Torvalds static int check_pattern(uint8_t *buf, int len, int paglen, struct nand_bbt_descr *td)
1081da177e4SLinus Torvalds {
1097cba7b14SSebastian Andrzej Siewior 	if (td->options & NAND_BBT_NO_OOB)
1107cba7b14SSebastian Andrzej Siewior 		return check_pattern_no_oob(buf, td);
1117cba7b14SSebastian Andrzej Siewior 
1121da177e4SLinus Torvalds 	/* Compare the pattern */
113dad22562SBrian Norris 	if (memcmp(buf + paglen + td->offs, td->pattern, td->len))
1141da177e4SLinus Torvalds 		return -1;
11558373ff0SBrian Norris 
1161da177e4SLinus Torvalds 	return 0;
1171da177e4SLinus Torvalds }
1181da177e4SLinus Torvalds 
1191da177e4SLinus Torvalds /**
120c9e05365SThomas Gleixner  * check_short_pattern - [GENERIC] check if a pattern is in the buffer
121c9e05365SThomas Gleixner  * @buf: the buffer to search
122c9e05365SThomas Gleixner  * @td:	search pattern descriptor
123c9e05365SThomas Gleixner  *
1248b6e50c9SBrian Norris  * Check for a pattern at the given place. Used to search bad block tables and
1258b6e50c9SBrian Norris  * good / bad block identifiers. Same as check_pattern, but no optional empty
1268b6e50c9SBrian Norris  * check.
127c9e05365SThomas Gleixner  */
12819870da7SThomas Gleixner static int check_short_pattern(uint8_t *buf, struct nand_bbt_descr *td)
129c9e05365SThomas Gleixner {
130c9e05365SThomas Gleixner 	/* Compare the pattern */
131491ed06fSBrian Norris 	if (memcmp(buf + td->offs, td->pattern, td->len))
132c9e05365SThomas Gleixner 		return -1;
133c9e05365SThomas Gleixner 	return 0;
134c9e05365SThomas Gleixner }
135c9e05365SThomas Gleixner 
136c9e05365SThomas Gleixner /**
1377cba7b14SSebastian Andrzej Siewior  * add_marker_len - compute the length of the marker in data area
1387cba7b14SSebastian Andrzej Siewior  * @td: BBT descriptor used for computation
1397cba7b14SSebastian Andrzej Siewior  *
1407cba7b14SSebastian Andrzej Siewior  * The length will be 0 if the marker is located in OOB area.
1417cba7b14SSebastian Andrzej Siewior  */
1427cba7b14SSebastian Andrzej Siewior static u32 add_marker_len(struct nand_bbt_descr *td)
1437cba7b14SSebastian Andrzej Siewior {
1447cba7b14SSebastian Andrzej Siewior 	u32 len;
1457cba7b14SSebastian Andrzej Siewior 
1467cba7b14SSebastian Andrzej Siewior 	if (!(td->options & NAND_BBT_NO_OOB))
1477cba7b14SSebastian Andrzej Siewior 		return 0;
1487cba7b14SSebastian Andrzej Siewior 
1497cba7b14SSebastian Andrzej Siewior 	len = td->len;
1507cba7b14SSebastian Andrzej Siewior 	if (td->options & NAND_BBT_VERSION)
1517cba7b14SSebastian Andrzej Siewior 		len++;
1527cba7b14SSebastian Andrzej Siewior 	return len;
1537cba7b14SSebastian Andrzej Siewior }
1547cba7b14SSebastian Andrzej Siewior 
1557cba7b14SSebastian Andrzej Siewior /**
1561da177e4SLinus Torvalds  * read_bbt - [GENERIC] Read the bad block table starting from page
157455e7b38SRandy Dunlap  * @this: NAND chip object
1581da177e4SLinus Torvalds  * @buf: temporary buffer
1591da177e4SLinus Torvalds  * @page: the starting page
1601da177e4SLinus Torvalds  * @num: the number of bbt descriptors to read
161df5b4e34SSebastian Andrzej Siewior  * @td: the bbt describtion table
162b4d20d60SBrian Norris  * @offs: block number offset in the table
1631da177e4SLinus Torvalds  *
1641da177e4SLinus Torvalds  * Read the bad block table starting from page.
1651da177e4SLinus Torvalds  */
1660813621bSBoris Brezillon static int read_bbt(struct nand_chip *this, uint8_t *buf, int page, int num,
167df5b4e34SSebastian Andrzej Siewior 		    struct nand_bbt_descr *td, int offs)
1681da177e4SLinus Torvalds {
1690813621bSBoris Brezillon 	struct mtd_info *mtd = nand_to_mtd(this);
170167a8d52SBrian Norris 	int res, ret = 0, i, j, act = 0;
1711da177e4SLinus Torvalds 	size_t retlen, len, totlen;
1721da177e4SLinus Torvalds 	loff_t from;
173df5b4e34SSebastian Andrzej Siewior 	int bits = td->options & NAND_BBT_NRBITS_MSK;
1741da177e4SLinus Torvalds 	uint8_t msk = (uint8_t)((1 << bits) - 1);
1757cba7b14SSebastian Andrzej Siewior 	u32 marker_len;
176df5b4e34SSebastian Andrzej Siewior 	int reserved_block_code = td->reserved_block_code;
1771da177e4SLinus Torvalds 
1781da177e4SLinus Torvalds 	totlen = (num * bits) >> 3;
1797cba7b14SSebastian Andrzej Siewior 	marker_len = add_marker_len(td);
1801da177e4SLinus Torvalds 	from = ((loff_t)page) << this->page_shift;
1811da177e4SLinus Torvalds 
1821da177e4SLinus Torvalds 	while (totlen) {
1831da177e4SLinus Torvalds 		len = min(totlen, (size_t)(1 << this->bbt_erase_shift));
1847cba7b14SSebastian Andrzej Siewior 		if (marker_len) {
1857cba7b14SSebastian Andrzej Siewior 			/*
1867cba7b14SSebastian Andrzej Siewior 			 * In case the BBT marker is not in the OOB area it
1877cba7b14SSebastian Andrzej Siewior 			 * will be just in the first page.
1887cba7b14SSebastian Andrzej Siewior 			 */
1897cba7b14SSebastian Andrzej Siewior 			len -= marker_len;
1907cba7b14SSebastian Andrzej Siewior 			from += marker_len;
1917cba7b14SSebastian Andrzej Siewior 			marker_len = 0;
1927cba7b14SSebastian Andrzej Siewior 		}
193329ad399SArtem Bityutskiy 		res = mtd_read(mtd, from, len, &retlen, buf);
1941da177e4SLinus Torvalds 		if (res < 0) {
195167a8d52SBrian Norris 			if (mtd_is_eccerr(res)) {
1962ac63d90SRafał Miłecki 				pr_info("nand_bbt: ECC error in BBT at 0x%012llx\n",
1972ac63d90SRafał Miłecki 					from & ~mtd->writesize);
198167a8d52SBrian Norris 				return res;
199167a8d52SBrian Norris 			} else if (mtd_is_bitflip(res)) {
2002ac63d90SRafał Miłecki 				pr_info("nand_bbt: corrected error in BBT at 0x%012llx\n",
2012ac63d90SRafał Miłecki 					from & ~mtd->writesize);
202167a8d52SBrian Norris 				ret = res;
203167a8d52SBrian Norris 			} else {
204167a8d52SBrian Norris 				pr_info("nand_bbt: error reading BBT\n");
2051da177e4SLinus Torvalds 				return res;
2061da177e4SLinus Torvalds 			}
2071da177e4SLinus Torvalds 		}
2081da177e4SLinus Torvalds 
2091da177e4SLinus Torvalds 		/* Analyse data */
2101da177e4SLinus Torvalds 		for (i = 0; i < len; i++) {
2111da177e4SLinus Torvalds 			uint8_t dat = buf[i];
212b4d20d60SBrian Norris 			for (j = 0; j < 8; j += bits, act++) {
2131da177e4SLinus Torvalds 				uint8_t tmp = (dat >> j) & msk;
2141da177e4SLinus Torvalds 				if (tmp == msk)
2151da177e4SLinus Torvalds 					continue;
216e0c7d767SDavid Woodhouse 				if (reserved_block_code && (tmp == reserved_block_code)) {
217d0370219SBrian Norris 					pr_info("nand_read_bbt: reserved block at 0x%012llx\n",
218b4d20d60SBrian Norris 						 (loff_t)(offs + act) <<
219b4d20d60SBrian Norris 						 this->bbt_erase_shift);
220b4d20d60SBrian Norris 					bbt_mark_entry(this, offs + act,
221771c568bSBrian Norris 							BBT_BLOCK_RESERVED);
222f1a28c02SThomas Gleixner 					mtd->ecc_stats.bbtblocks++;
2231da177e4SLinus Torvalds 					continue;
2241da177e4SLinus Torvalds 				}
2258b6e50c9SBrian Norris 				/*
2268b6e50c9SBrian Norris 				 * Leave it for now, if it's matured we can
227a0f5080eSBrian Norris 				 * move this message to pr_debug.
2288b6e50c9SBrian Norris 				 */
229d0370219SBrian Norris 				pr_info("nand_read_bbt: bad block at 0x%012llx\n",
230b4d20d60SBrian Norris 					 (loff_t)(offs + act) <<
231b4d20d60SBrian Norris 					 this->bbt_erase_shift);
2321da177e4SLinus Torvalds 				/* Factory marked bad or worn out? */
2331da177e4SLinus Torvalds 				if (tmp == 0)
234b4d20d60SBrian Norris 					bbt_mark_entry(this, offs + act,
235771c568bSBrian Norris 							BBT_BLOCK_FACTORY_BAD);
2361da177e4SLinus Torvalds 				else
237b4d20d60SBrian Norris 					bbt_mark_entry(this, offs + act,
238771c568bSBrian Norris 							BBT_BLOCK_WORN);
239f1a28c02SThomas Gleixner 				mtd->ecc_stats.badblocks++;
2401da177e4SLinus Torvalds 			}
2411da177e4SLinus Torvalds 		}
2421da177e4SLinus Torvalds 		totlen -= len;
2431da177e4SLinus Torvalds 		from += len;
2441da177e4SLinus Torvalds 	}
245167a8d52SBrian Norris 	return ret;
2461da177e4SLinus Torvalds }
2471da177e4SLinus Torvalds 
2481da177e4SLinus Torvalds /**
2491da177e4SLinus Torvalds  * read_abs_bbt - [GENERIC] Read the bad block table starting at a given page
2500813621bSBoris Brezillon  * @this: NAND chip object
2511da177e4SLinus Torvalds  * @buf: temporary buffer
2521da177e4SLinus Torvalds  * @td: descriptor for the bad block table
253596d7452SBrian Norris  * @chip: read the table for a specific chip, -1 read all chips; applies only if
2548b6e50c9SBrian Norris  *        NAND_BBT_PERCHIP option is set
2551da177e4SLinus Torvalds  *
2568b6e50c9SBrian Norris  * Read the bad block table for all chips starting at a given page. We assume
2578b6e50c9SBrian Norris  * that the bbt bits are in consecutive order.
2581da177e4SLinus Torvalds  */
2590813621bSBoris Brezillon static int read_abs_bbt(struct nand_chip *this, uint8_t *buf,
2600813621bSBoris Brezillon 			struct nand_bbt_descr *td, int chip)
2611da177e4SLinus Torvalds {
2620813621bSBoris Brezillon 	struct mtd_info *mtd = nand_to_mtd(this);
2636c836d51SBoris Brezillon 	u64 targetsize = nanddev_target_size(&this->base);
2641da177e4SLinus Torvalds 	int res = 0, i;
2651da177e4SLinus Torvalds 
2661da177e4SLinus Torvalds 	if (td->options & NAND_BBT_PERCHIP) {
2671da177e4SLinus Torvalds 		int offs = 0;
26832813e28SBoris Brezillon 		for (i = 0; i < nanddev_ntargets(&this->base); i++) {
2691da177e4SLinus Torvalds 			if (chip == -1 || chip == i)
2700813621bSBoris Brezillon 				res = read_bbt(this, buf, td->pages[i],
2716c836d51SBoris Brezillon 					targetsize >> this->bbt_erase_shift,
272df5b4e34SSebastian Andrzej Siewior 					td, offs);
2731da177e4SLinus Torvalds 			if (res)
2741da177e4SLinus Torvalds 				return res;
2756c836d51SBoris Brezillon 			offs += targetsize >> this->bbt_erase_shift;
2761da177e4SLinus Torvalds 		}
2771da177e4SLinus Torvalds 	} else {
2780813621bSBoris Brezillon 		res = read_bbt(this, buf, td->pages[0],
279df5b4e34SSebastian Andrzej Siewior 				mtd->size >> this->bbt_erase_shift, td, 0);
2801da177e4SLinus Torvalds 		if (res)
2811da177e4SLinus Torvalds 			return res;
2821da177e4SLinus Torvalds 	}
2831da177e4SLinus Torvalds 	return 0;
2841da177e4SLinus Torvalds }
2851da177e4SLinus Torvalds 
2868b6e50c9SBrian Norris /* BBT marker is in the first page, no OOB */
2870813621bSBoris Brezillon static int scan_read_data(struct nand_chip *this, uint8_t *buf, loff_t offs,
2887cba7b14SSebastian Andrzej Siewior 			  struct nand_bbt_descr *td)
2897cba7b14SSebastian Andrzej Siewior {
2900813621bSBoris Brezillon 	struct mtd_info *mtd = nand_to_mtd(this);
2917cba7b14SSebastian Andrzej Siewior 	size_t retlen;
2927cba7b14SSebastian Andrzej Siewior 	size_t len;
2937cba7b14SSebastian Andrzej Siewior 
2947cba7b14SSebastian Andrzej Siewior 	len = td->len;
2957cba7b14SSebastian Andrzej Siewior 	if (td->options & NAND_BBT_VERSION)
2967cba7b14SSebastian Andrzej Siewior 		len++;
2977cba7b14SSebastian Andrzej Siewior 
298329ad399SArtem Bityutskiy 	return mtd_read(mtd, offs, len, &retlen, buf);
2997cba7b14SSebastian Andrzej Siewior }
3007cba7b14SSebastian Andrzej Siewior 
301a7e68834SBrian Norris /**
302af69dcd3SBrian Norris  * scan_read_oob - [GENERIC] Scan data+OOB region to buffer
3030813621bSBoris Brezillon  * @this: NAND chip object
304a7e68834SBrian Norris  * @buf: temporary buffer
305a7e68834SBrian Norris  * @offs: offset at which to scan
306a7e68834SBrian Norris  * @len: length of data region to read
307a7e68834SBrian Norris  *
308a7e68834SBrian Norris  * Scan read data from data+OOB. May traverse multiple pages, interleaving
309a7e68834SBrian Norris  * page,OOB,page,OOB,... in buf. Completes transfer and returns the "strongest"
310a7e68834SBrian Norris  * ECC condition (error or bitflip). May quit on the first (non-ECC) error.
311a7e68834SBrian Norris  */
3120813621bSBoris Brezillon static int scan_read_oob(struct nand_chip *this, uint8_t *buf, loff_t offs,
3138593fbc6SThomas Gleixner 			 size_t len)
3148593fbc6SThomas Gleixner {
3150813621bSBoris Brezillon 	struct mtd_info *mtd = nand_to_mtd(this);
3168593fbc6SThomas Gleixner 	struct mtd_oob_ops ops;
317a7e68834SBrian Norris 	int res, ret = 0;
3188593fbc6SThomas Gleixner 
319a7e68834SBrian Norris 	ops.mode = MTD_OPS_PLACE_OOB;
3208593fbc6SThomas Gleixner 	ops.ooboffs = 0;
3218593fbc6SThomas Gleixner 	ops.ooblen = mtd->oobsize;
322b64d39d8SMaxim Levitsky 
323b64d39d8SMaxim Levitsky 	while (len > 0) {
3248593fbc6SThomas Gleixner 		ops.datbuf = buf;
325105513ccSBrian Norris 		ops.len = min(len, (size_t)mtd->writesize);
326105513ccSBrian Norris 		ops.oobbuf = buf + ops.len;
327903cd06cSBrian Norris 
328fd2819bbSArtem Bityutskiy 		res = mtd_read_oob(mtd, offs, &ops);
329a7e68834SBrian Norris 		if (res) {
330a7e68834SBrian Norris 			if (!mtd_is_bitflip_or_eccerr(res))
331b64d39d8SMaxim Levitsky 				return res;
332a7e68834SBrian Norris 			else if (mtd_is_eccerr(res) || !ret)
333a7e68834SBrian Norris 				ret = res;
334a7e68834SBrian Norris 		}
335b64d39d8SMaxim Levitsky 
336b64d39d8SMaxim Levitsky 		buf += mtd->oobsize + mtd->writesize;
337b64d39d8SMaxim Levitsky 		len -= mtd->writesize;
33834a5704dSDmitry Maluka 		offs += mtd->writesize;
339b64d39d8SMaxim Levitsky 	}
340a7e68834SBrian Norris 	return ret;
3418593fbc6SThomas Gleixner }
3428593fbc6SThomas Gleixner 
3430813621bSBoris Brezillon static int scan_read(struct nand_chip *this, uint8_t *buf, loff_t offs,
3447cba7b14SSebastian Andrzej Siewior 		     size_t len, struct nand_bbt_descr *td)
3457cba7b14SSebastian Andrzej Siewior {
3467cba7b14SSebastian Andrzej Siewior 	if (td->options & NAND_BBT_NO_OOB)
3470813621bSBoris Brezillon 		return scan_read_data(this, buf, offs, td);
3487cba7b14SSebastian Andrzej Siewior 	else
3490813621bSBoris Brezillon 		return scan_read_oob(this, buf, offs, len);
3507cba7b14SSebastian Andrzej Siewior }
3517cba7b14SSebastian Andrzej Siewior 
3528b6e50c9SBrian Norris /* Scan write data with oob to flash */
3530813621bSBoris Brezillon static int scan_write_bbt(struct nand_chip *this, loff_t offs, size_t len,
3548593fbc6SThomas Gleixner 			  uint8_t *buf, uint8_t *oob)
3558593fbc6SThomas Gleixner {
3560813621bSBoris Brezillon 	struct mtd_info *mtd = nand_to_mtd(this);
3578593fbc6SThomas Gleixner 	struct mtd_oob_ops ops;
3588593fbc6SThomas Gleixner 
3590612b9ddSBrian Norris 	ops.mode = MTD_OPS_PLACE_OOB;
3608593fbc6SThomas Gleixner 	ops.ooboffs = 0;
3618593fbc6SThomas Gleixner 	ops.ooblen = mtd->oobsize;
3628593fbc6SThomas Gleixner 	ops.datbuf = buf;
3638593fbc6SThomas Gleixner 	ops.oobbuf = oob;
3648593fbc6SThomas Gleixner 	ops.len = len;
3658593fbc6SThomas Gleixner 
366a2cc5ba0SArtem Bityutskiy 	return mtd_write_oob(mtd, offs, &ops);
3678593fbc6SThomas Gleixner }
3688593fbc6SThomas Gleixner 
3690813621bSBoris Brezillon static u32 bbt_get_ver_offs(struct nand_chip *this, struct nand_bbt_descr *td)
3707cba7b14SSebastian Andrzej Siewior {
3710813621bSBoris Brezillon 	struct mtd_info *mtd = nand_to_mtd(this);
3727cba7b14SSebastian Andrzej Siewior 	u32 ver_offs = td->veroffs;
3737cba7b14SSebastian Andrzej Siewior 
3747cba7b14SSebastian Andrzej Siewior 	if (!(td->options & NAND_BBT_NO_OOB))
3757cba7b14SSebastian Andrzej Siewior 		ver_offs += mtd->writesize;
3767cba7b14SSebastian Andrzej Siewior 	return ver_offs;
3777cba7b14SSebastian Andrzej Siewior }
3787cba7b14SSebastian Andrzej Siewior 
3791da177e4SLinus Torvalds /**
3801da177e4SLinus Torvalds  * read_abs_bbts - [GENERIC] Read the bad block table(s) for all chips starting at a given page
3810813621bSBoris Brezillon  * @this: NAND chip object
3821da177e4SLinus Torvalds  * @buf: temporary buffer
3831da177e4SLinus Torvalds  * @td: descriptor for the bad block table
3841da177e4SLinus Torvalds  * @md:	descriptor for the bad block table mirror
3851da177e4SLinus Torvalds  *
3868b6e50c9SBrian Norris  * Read the bad block table(s) for all chips starting at a given page. We
3878b6e50c9SBrian Norris  * assume that the bbt bits are in consecutive order.
3881da177e4SLinus Torvalds  */
3890813621bSBoris Brezillon static void read_abs_bbts(struct nand_chip *this, uint8_t *buf,
3908593fbc6SThomas Gleixner 			  struct nand_bbt_descr *td, struct nand_bbt_descr *md)
3911da177e4SLinus Torvalds {
3920813621bSBoris Brezillon 	struct mtd_info *mtd = nand_to_mtd(this);
3931da177e4SLinus Torvalds 
3941da177e4SLinus Torvalds 	/* Read the primary version, if available */
3951da177e4SLinus Torvalds 	if (td->options & NAND_BBT_VERSION) {
3960813621bSBoris Brezillon 		scan_read(this, buf, (loff_t)td->pages[0] << this->page_shift,
3977cba7b14SSebastian Andrzej Siewior 			  mtd->writesize, td);
3980813621bSBoris Brezillon 		td->version[0] = buf[bbt_get_ver_offs(this, td)];
3999a4d4d69SBrian Norris 		pr_info("Bad block table at page %d, version 0x%02X\n",
4008593fbc6SThomas Gleixner 			 td->pages[0], td->version[0]);
4011da177e4SLinus Torvalds 	}
4021da177e4SLinus Torvalds 
4031da177e4SLinus Torvalds 	/* Read the mirror version, if available */
4041da177e4SLinus Torvalds 	if (md && (md->options & NAND_BBT_VERSION)) {
4050813621bSBoris Brezillon 		scan_read(this, buf, (loff_t)md->pages[0] << this->page_shift,
4067bb9c754SShmulik Ladkani 			  mtd->writesize, md);
4070813621bSBoris Brezillon 		md->version[0] = buf[bbt_get_ver_offs(this, md)];
4089a4d4d69SBrian Norris 		pr_info("Bad block table at page %d, version 0x%02X\n",
4098593fbc6SThomas Gleixner 			 md->pages[0], md->version[0]);
4108593fbc6SThomas Gleixner 	}
4111da177e4SLinus Torvalds }
4121da177e4SLinus Torvalds 
4138b6e50c9SBrian Norris /* Scan a given block partially */
4140813621bSBoris Brezillon static int scan_block_fast(struct nand_chip *this, struct nand_bbt_descr *bd,
415f90da781SFrieder Schrempf 			   loff_t offs, uint8_t *buf)
4168593fbc6SThomas Gleixner {
4170813621bSBoris Brezillon 	struct mtd_info *mtd = nand_to_mtd(this);
418f90da781SFrieder Schrempf 
4198593fbc6SThomas Gleixner 	struct mtd_oob_ops ops;
420f90da781SFrieder Schrempf 	int ret, page_offset;
4218593fbc6SThomas Gleixner 
4228593fbc6SThomas Gleixner 	ops.ooblen = mtd->oobsize;
4238593fbc6SThomas Gleixner 	ops.oobbuf = buf;
4248593fbc6SThomas Gleixner 	ops.ooboffs = 0;
4258593fbc6SThomas Gleixner 	ops.datbuf = NULL;
4260612b9ddSBrian Norris 	ops.mode = MTD_OPS_PLACE_OOB;
4278593fbc6SThomas Gleixner 
428f90da781SFrieder Schrempf 	page_offset = nand_bbm_get_next_page(this, 0);
429f90da781SFrieder Schrempf 
430f90da781SFrieder Schrempf 	while (page_offset >= 0) {
4318593fbc6SThomas Gleixner 		/*
4328b6e50c9SBrian Norris 		 * Read the full oob until read_oob is fixed to handle single
4338b6e50c9SBrian Norris 		 * byte reads for 16 bit buswidth.
4348593fbc6SThomas Gleixner 		 */
435f90da781SFrieder Schrempf 		ret = mtd_read_oob(mtd, offs + (page_offset * mtd->writesize),
436f90da781SFrieder Schrempf 				   &ops);
437903cd06cSBrian Norris 		/* Ignore ECC errors when checking for BBM */
438d57f4054SBrian Norris 		if (ret && !mtd_is_bitflip_or_eccerr(ret))
4398593fbc6SThomas Gleixner 			return ret;
4408593fbc6SThomas Gleixner 
4418593fbc6SThomas Gleixner 		if (check_short_pattern(buf, bd))
4428593fbc6SThomas Gleixner 			return 1;
4438593fbc6SThomas Gleixner 
444f90da781SFrieder Schrempf 		page_offset = nand_bbm_get_next_page(this, page_offset + 1);
4458593fbc6SThomas Gleixner 	}
446f90da781SFrieder Schrempf 
4478593fbc6SThomas Gleixner 	return 0;
4488593fbc6SThomas Gleixner }
4491da177e4SLinus Torvalds 
4501da177e4SLinus Torvalds /**
4511da177e4SLinus Torvalds  * create_bbt - [GENERIC] Create a bad block table by scanning the device
4520813621bSBoris Brezillon  * @this: NAND chip object
4531da177e4SLinus Torvalds  * @buf: temporary buffer
4541da177e4SLinus Torvalds  * @bd: descriptor for the good/bad block search pattern
4558b6e50c9SBrian Norris  * @chip: create the table for a specific chip, -1 read all chips; applies only
4568b6e50c9SBrian Norris  *        if NAND_BBT_PERCHIP option is set
4571da177e4SLinus Torvalds  *
4588b6e50c9SBrian Norris  * Create a bad block table by scanning the device for the given good/bad block
4598b6e50c9SBrian Norris  * identify pattern.
4601da177e4SLinus Torvalds  */
4610813621bSBoris Brezillon static int create_bbt(struct nand_chip *this, uint8_t *buf,
4628593fbc6SThomas Gleixner 		      struct nand_bbt_descr *bd, int chip)
4631da177e4SLinus Torvalds {
4646c836d51SBoris Brezillon 	u64 targetsize = nanddev_target_size(&this->base);
4650813621bSBoris Brezillon 	struct mtd_info *mtd = nand_to_mtd(this);
466f90da781SFrieder Schrempf 	int i, numblocks, startblock;
4671da177e4SLinus Torvalds 	loff_t from;
4681da177e4SLinus Torvalds 
4699a4d4d69SBrian Norris 	pr_info("Scanning device for bad blocks\n");
4701da177e4SLinus Torvalds 
4711da177e4SLinus Torvalds 	if (chip == -1) {
472b4d20d60SBrian Norris 		numblocks = mtd->size >> this->bbt_erase_shift;
4731da177e4SLinus Torvalds 		startblock = 0;
4741da177e4SLinus Torvalds 		from = 0;
4751da177e4SLinus Torvalds 	} else {
47632813e28SBoris Brezillon 		if (chip >= nanddev_ntargets(&this->base)) {
4779a4d4d69SBrian Norris 			pr_warn("create_bbt(): chipnr (%d) > available chips (%d)\n",
47832813e28SBoris Brezillon 			        chip + 1, nanddev_ntargets(&this->base));
479eeada24dSArtem B. Bityuckiy 			return -EINVAL;
4801da177e4SLinus Torvalds 		}
4816c836d51SBoris Brezillon 		numblocks = targetsize >> this->bbt_erase_shift;
4821da177e4SLinus Torvalds 		startblock = chip * numblocks;
4831da177e4SLinus Torvalds 		numblocks += startblock;
484b4d20d60SBrian Norris 		from = (loff_t)startblock << this->bbt_erase_shift;
4851da177e4SLinus Torvalds 	}
4861da177e4SLinus Torvalds 
487b4d20d60SBrian Norris 	for (i = startblock; i < numblocks; i++) {
488eeada24dSArtem B. Bityuckiy 		int ret;
489eeada24dSArtem B. Bityuckiy 
4907cba7b14SSebastian Andrzej Siewior 		BUG_ON(bd->options & NAND_BBT_NO_OOB);
4917cba7b14SSebastian Andrzej Siewior 
492f90da781SFrieder Schrempf 		ret = scan_block_fast(this, bd, from, buf);
4938593fbc6SThomas Gleixner 		if (ret < 0)
494eeada24dSArtem B. Bityuckiy 			return ret;
495171650afSArtem B. Bityuckiy 
4968593fbc6SThomas Gleixner 		if (ret) {
497b4d20d60SBrian Norris 			bbt_mark_entry(this, i, BBT_BLOCK_FACTORY_BAD);
4989a4d4d69SBrian Norris 			pr_warn("Bad eraseblock %d at 0x%012llx\n",
499b4d20d60SBrian Norris 				i, (unsigned long long)from);
500f1a28c02SThomas Gleixner 			mtd->ecc_stats.badblocks++;
501171650afSArtem B. Bityuckiy 		}
5028593fbc6SThomas Gleixner 
5031da177e4SLinus Torvalds 		from += (1 << this->bbt_erase_shift);
5041da177e4SLinus Torvalds 	}
505eeada24dSArtem B. Bityuckiy 	return 0;
5061da177e4SLinus Torvalds }
5071da177e4SLinus Torvalds 
5081da177e4SLinus Torvalds /**
5091da177e4SLinus Torvalds  * search_bbt - [GENERIC] scan the device for a specific bad block table
5100813621bSBoris Brezillon  * @this: NAND chip object
5111da177e4SLinus Torvalds  * @buf: temporary buffer
5121da177e4SLinus Torvalds  * @td: descriptor for the bad block table
5131da177e4SLinus Torvalds  *
5148b6e50c9SBrian Norris  * Read the bad block table by searching for a given ident pattern. Search is
5158b6e50c9SBrian Norris  * preformed either from the beginning up or from the end of the device
5168b6e50c9SBrian Norris  * downwards. The search starts always at the start of a block. If the option
5178b6e50c9SBrian Norris  * NAND_BBT_PERCHIP is given, each chip is searched for a bbt, which contains
5188b6e50c9SBrian Norris  * the bad block information of this chip. This is necessary to provide support
5198b6e50c9SBrian Norris  * for certain DOC devices.
5201da177e4SLinus Torvalds  *
5218b6e50c9SBrian Norris  * The bbt ident pattern resides in the oob area of the first page in a block.
5221da177e4SLinus Torvalds  */
5230813621bSBoris Brezillon static int search_bbt(struct nand_chip *this, uint8_t *buf,
5240813621bSBoris Brezillon 		      struct nand_bbt_descr *td)
5251da177e4SLinus Torvalds {
5266c836d51SBoris Brezillon 	u64 targetsize = nanddev_target_size(&this->base);
5270813621bSBoris Brezillon 	struct mtd_info *mtd = nand_to_mtd(this);
5281da177e4SLinus Torvalds 	int i, chips;
529930de537SBrian Norris 	int startblock, block, dir;
53028318776SJoern Engel 	int scanlen = mtd->writesize + mtd->oobsize;
5311da177e4SLinus Torvalds 	int bbtblocks;
5328593fbc6SThomas Gleixner 	int blocktopage = this->bbt_erase_shift - this->page_shift;
5331da177e4SLinus Torvalds 
5341da177e4SLinus Torvalds 	/* Search direction top -> down? */
5351da177e4SLinus Torvalds 	if (td->options & NAND_BBT_LASTBLOCK) {
5361da177e4SLinus Torvalds 		startblock = (mtd->size >> this->bbt_erase_shift) - 1;
5371da177e4SLinus Torvalds 		dir = -1;
5381da177e4SLinus Torvalds 	} else {
5391da177e4SLinus Torvalds 		startblock = 0;
5401da177e4SLinus Torvalds 		dir = 1;
5411da177e4SLinus Torvalds 	}
5421da177e4SLinus Torvalds 
5431da177e4SLinus Torvalds 	/* Do we have a bbt per chip? */
5441da177e4SLinus Torvalds 	if (td->options & NAND_BBT_PERCHIP) {
54532813e28SBoris Brezillon 		chips = nanddev_ntargets(&this->base);
5466c836d51SBoris Brezillon 		bbtblocks = targetsize >> this->bbt_erase_shift;
5471da177e4SLinus Torvalds 		startblock &= bbtblocks - 1;
5481da177e4SLinus Torvalds 	} else {
5491da177e4SLinus Torvalds 		chips = 1;
5501da177e4SLinus Torvalds 		bbtblocks = mtd->size >> this->bbt_erase_shift;
5511da177e4SLinus Torvalds 	}
5521da177e4SLinus Torvalds 
5531da177e4SLinus Torvalds 	for (i = 0; i < chips; i++) {
5541da177e4SLinus Torvalds 		/* Reset version information */
5551da177e4SLinus Torvalds 		td->version[i] = 0;
5561da177e4SLinus Torvalds 		td->pages[i] = -1;
5571da177e4SLinus Torvalds 		/* Scan the maximum number of blocks */
5581da177e4SLinus Torvalds 		for (block = 0; block < td->maxblocks; block++) {
5598593fbc6SThomas Gleixner 
5601da177e4SLinus Torvalds 			int actblock = startblock + dir * block;
56169423d99SAdrian Hunter 			loff_t offs = (loff_t)actblock << this->bbt_erase_shift;
5628593fbc6SThomas Gleixner 
5631da177e4SLinus Torvalds 			/* Read first page */
5640813621bSBoris Brezillon 			scan_read(this, buf, offs, mtd->writesize, td);
56528318776SJoern Engel 			if (!check_pattern(buf, scanlen, mtd->writesize, td)) {
5668593fbc6SThomas Gleixner 				td->pages[i] = actblock << blocktopage;
5671da177e4SLinus Torvalds 				if (td->options & NAND_BBT_VERSION) {
5680813621bSBoris Brezillon 					offs = bbt_get_ver_offs(this, td);
5697cba7b14SSebastian Andrzej Siewior 					td->version[i] = buf[offs];
5701da177e4SLinus Torvalds 				}
5711da177e4SLinus Torvalds 				break;
5721da177e4SLinus Torvalds 			}
5731da177e4SLinus Torvalds 		}
5746c836d51SBoris Brezillon 		startblock += targetsize >> this->bbt_erase_shift;
5751da177e4SLinus Torvalds 	}
5761da177e4SLinus Torvalds 	/* Check, if we found a bbt for each requested chip */
5771da177e4SLinus Torvalds 	for (i = 0; i < chips; i++) {
5781da177e4SLinus Torvalds 		if (td->pages[i] == -1)
5799a4d4d69SBrian Norris 			pr_warn("Bad block table not found for chip %d\n", i);
5801da177e4SLinus Torvalds 		else
5812ac63d90SRafał Miłecki 			pr_info("Bad block table found at page %d, version 0x%02X\n",
5822ac63d90SRafał Miłecki 				td->pages[i], td->version[i]);
5831da177e4SLinus Torvalds 	}
5841da177e4SLinus Torvalds 	return 0;
5851da177e4SLinus Torvalds }
5861da177e4SLinus Torvalds 
5871da177e4SLinus Torvalds /**
5881da177e4SLinus Torvalds  * search_read_bbts - [GENERIC] scan the device for bad block table(s)
5890813621bSBoris Brezillon  * @this: NAND chip object
5901da177e4SLinus Torvalds  * @buf: temporary buffer
5911da177e4SLinus Torvalds  * @td: descriptor for the bad block table
5921da177e4SLinus Torvalds  * @md: descriptor for the bad block table mirror
5931da177e4SLinus Torvalds  *
5948b6e50c9SBrian Norris  * Search and read the bad block table(s).
5951da177e4SLinus Torvalds  */
5960813621bSBoris Brezillon static void search_read_bbts(struct nand_chip *this, uint8_t *buf,
5977b5a2d40SBrian Norris 			     struct nand_bbt_descr *td,
5987b5a2d40SBrian Norris 			     struct nand_bbt_descr *md)
5991da177e4SLinus Torvalds {
6001da177e4SLinus Torvalds 	/* Search the primary table */
6010813621bSBoris Brezillon 	search_bbt(this, buf, td);
6021da177e4SLinus Torvalds 
6031da177e4SLinus Torvalds 	/* Search the mirror table */
6041da177e4SLinus Torvalds 	if (md)
6050813621bSBoris Brezillon 		search_bbt(this, buf, md);
6061da177e4SLinus Torvalds }
6071da177e4SLinus Torvalds 
6081da177e4SLinus Torvalds /**
609c3baf278SBoris Brezillon  * get_bbt_block - Get the first valid eraseblock suitable to store a BBT
610c3baf278SBoris Brezillon  * @this: the NAND device
611c3baf278SBoris Brezillon  * @td: the BBT description
612c3baf278SBoris Brezillon  * @md: the mirror BBT descriptor
613c3baf278SBoris Brezillon  * @chip: the CHIP selector
614c3baf278SBoris Brezillon  *
615c3baf278SBoris Brezillon  * This functions returns a positive block number pointing a valid eraseblock
616c3baf278SBoris Brezillon  * suitable to store a BBT (i.e. in the range reserved for BBT), or -ENOSPC if
617c3baf278SBoris Brezillon  * all blocks are already used of marked bad. If td->pages[chip] was already
618c3baf278SBoris Brezillon  * pointing to a valid block we re-use it, otherwise we search for the next
619c3baf278SBoris Brezillon  * valid one.
620c3baf278SBoris Brezillon  */
621c3baf278SBoris Brezillon static int get_bbt_block(struct nand_chip *this, struct nand_bbt_descr *td,
622c3baf278SBoris Brezillon 			 struct nand_bbt_descr *md, int chip)
623c3baf278SBoris Brezillon {
6246c836d51SBoris Brezillon 	u64 targetsize = nanddev_target_size(&this->base);
625c3baf278SBoris Brezillon 	int startblock, dir, page, numblocks, i;
626c3baf278SBoris Brezillon 
627c3baf278SBoris Brezillon 	/*
628c3baf278SBoris Brezillon 	 * There was already a version of the table, reuse the page. This
629c3baf278SBoris Brezillon 	 * applies for absolute placement too, as we have the page number in
630c3baf278SBoris Brezillon 	 * td->pages.
631c3baf278SBoris Brezillon 	 */
632c3baf278SBoris Brezillon 	if (td->pages[chip] != -1)
633c3baf278SBoris Brezillon 		return td->pages[chip] >>
634c3baf278SBoris Brezillon 				(this->bbt_erase_shift - this->page_shift);
635c3baf278SBoris Brezillon 
6366c836d51SBoris Brezillon 	numblocks = (int)(targetsize >> this->bbt_erase_shift);
637c3baf278SBoris Brezillon 	if (!(td->options & NAND_BBT_PERCHIP))
63832813e28SBoris Brezillon 		numblocks *= nanddev_ntargets(&this->base);
639c3baf278SBoris Brezillon 
640c3baf278SBoris Brezillon 	/*
641c3baf278SBoris Brezillon 	 * Automatic placement of the bad block table. Search direction
642c3baf278SBoris Brezillon 	 * top -> down?
643c3baf278SBoris Brezillon 	 */
644c3baf278SBoris Brezillon 	if (td->options & NAND_BBT_LASTBLOCK) {
645c3baf278SBoris Brezillon 		startblock = numblocks * (chip + 1) - 1;
646c3baf278SBoris Brezillon 		dir = -1;
647c3baf278SBoris Brezillon 	} else {
648c3baf278SBoris Brezillon 		startblock = chip * numblocks;
649c3baf278SBoris Brezillon 		dir = 1;
650c3baf278SBoris Brezillon 	}
651c3baf278SBoris Brezillon 
652c3baf278SBoris Brezillon 	for (i = 0; i < td->maxblocks; i++) {
653c3baf278SBoris Brezillon 		int block = startblock + dir * i;
654c3baf278SBoris Brezillon 
655c3baf278SBoris Brezillon 		/* Check, if the block is bad */
656c3baf278SBoris Brezillon 		switch (bbt_get_entry(this, block)) {
657c3baf278SBoris Brezillon 		case BBT_BLOCK_WORN:
658c3baf278SBoris Brezillon 		case BBT_BLOCK_FACTORY_BAD:
659c3baf278SBoris Brezillon 			continue;
660c3baf278SBoris Brezillon 		}
661c3baf278SBoris Brezillon 
662c3baf278SBoris Brezillon 		page = block << (this->bbt_erase_shift - this->page_shift);
663c3baf278SBoris Brezillon 
664c3baf278SBoris Brezillon 		/* Check, if the block is used by the mirror table */
665c3baf278SBoris Brezillon 		if (!md || md->pages[chip] != page)
666c3baf278SBoris Brezillon 			return block;
667c3baf278SBoris Brezillon 	}
668c3baf278SBoris Brezillon 
669c3baf278SBoris Brezillon 	return -ENOSPC;
670c3baf278SBoris Brezillon }
671c3baf278SBoris Brezillon 
672c3baf278SBoris Brezillon /**
67310ffd570SKyle Roeschley  * mark_bbt_block_bad - Mark one of the block reserved for BBT bad
67410ffd570SKyle Roeschley  * @this: the NAND device
67510ffd570SKyle Roeschley  * @td: the BBT description
67610ffd570SKyle Roeschley  * @chip: the CHIP selector
67710ffd570SKyle Roeschley  * @block: the BBT block to mark
67810ffd570SKyle Roeschley  *
67910ffd570SKyle Roeschley  * Blocks reserved for BBT can become bad. This functions is an helper to mark
68010ffd570SKyle Roeschley  * such blocks as bad. It takes care of updating the in-memory BBT, marking the
68110ffd570SKyle Roeschley  * block as bad using a bad block marker and invalidating the associated
68210ffd570SKyle Roeschley  * td->pages[] entry.
68310ffd570SKyle Roeschley  */
68410ffd570SKyle Roeschley static void mark_bbt_block_bad(struct nand_chip *this,
68510ffd570SKyle Roeschley 			       struct nand_bbt_descr *td,
68610ffd570SKyle Roeschley 			       int chip, int block)
68710ffd570SKyle Roeschley {
68810ffd570SKyle Roeschley 	loff_t to;
68910ffd570SKyle Roeschley 	int res;
69010ffd570SKyle Roeschley 
69110ffd570SKyle Roeschley 	bbt_mark_entry(this, block, BBT_BLOCK_WORN);
69210ffd570SKyle Roeschley 
69310ffd570SKyle Roeschley 	to = (loff_t)block << this->bbt_erase_shift;
694cdc784c7SBoris Brezillon 	res = nand_markbad_bbm(this, to);
69510ffd570SKyle Roeschley 	if (res)
69610ffd570SKyle Roeschley 		pr_warn("nand_bbt: error %d while marking block %d bad\n",
69710ffd570SKyle Roeschley 			res, block);
69810ffd570SKyle Roeschley 
69910ffd570SKyle Roeschley 	td->pages[chip] = -1;
70010ffd570SKyle Roeschley }
70110ffd570SKyle Roeschley 
70210ffd570SKyle Roeschley /**
7031da177e4SLinus Torvalds  * write_bbt - [GENERIC] (Re)write the bad block table
7040813621bSBoris Brezillon  * @this: NAND chip object
7051da177e4SLinus Torvalds  * @buf: temporary buffer
7061da177e4SLinus Torvalds  * @td: descriptor for the bad block table
7071da177e4SLinus Torvalds  * @md: descriptor for the bad block table mirror
7081da177e4SLinus Torvalds  * @chipsel: selector for a specific chip, -1 for all
7091da177e4SLinus Torvalds  *
7108b6e50c9SBrian Norris  * (Re)write the bad block table.
7111da177e4SLinus Torvalds  */
7120813621bSBoris Brezillon static int write_bbt(struct nand_chip *this, uint8_t *buf,
7139223a456SThomas Gleixner 		     struct nand_bbt_descr *td, struct nand_bbt_descr *md,
7149223a456SThomas Gleixner 		     int chipsel)
7151da177e4SLinus Torvalds {
7166c836d51SBoris Brezillon 	u64 targetsize = nanddev_target_size(&this->base);
7170813621bSBoris Brezillon 	struct mtd_info *mtd = nand_to_mtd(this);
7181da177e4SLinus Torvalds 	struct erase_info einfo;
719b4d20d60SBrian Norris 	int i, res, chip = 0;
720c3baf278SBoris Brezillon 	int bits, page, offs, numblocks, sft, sftmsk;
721b4d20d60SBrian Norris 	int nrchips, pageoffs, ooboffs;
7221da177e4SLinus Torvalds 	uint8_t msk[4];
7231da177e4SLinus Torvalds 	uint8_t rcode = td->reserved_block_code;
7248593fbc6SThomas Gleixner 	size_t retlen, len = 0;
7251da177e4SLinus Torvalds 	loff_t to;
7268593fbc6SThomas Gleixner 	struct mtd_oob_ops ops;
7278593fbc6SThomas Gleixner 
7288593fbc6SThomas Gleixner 	ops.ooblen = mtd->oobsize;
7298593fbc6SThomas Gleixner 	ops.ooboffs = 0;
7308593fbc6SThomas Gleixner 	ops.datbuf = NULL;
7310612b9ddSBrian Norris 	ops.mode = MTD_OPS_PLACE_OOB;
7321da177e4SLinus Torvalds 
7331da177e4SLinus Torvalds 	if (!rcode)
7341da177e4SLinus Torvalds 		rcode = 0xff;
7351da177e4SLinus Torvalds 	/* Write bad block table per chip rather than per device? */
7361da177e4SLinus Torvalds 	if (td->options & NAND_BBT_PERCHIP) {
7376c836d51SBoris Brezillon 		numblocks = (int)(targetsize >> this->bbt_erase_shift);
7381da177e4SLinus Torvalds 		/* Full device write or specific chip? */
7391da177e4SLinus Torvalds 		if (chipsel == -1) {
74032813e28SBoris Brezillon 			nrchips = nanddev_ntargets(&this->base);
7411da177e4SLinus Torvalds 		} else {
7421da177e4SLinus Torvalds 			nrchips = chipsel + 1;
7431da177e4SLinus Torvalds 			chip = chipsel;
7441da177e4SLinus Torvalds 		}
7451da177e4SLinus Torvalds 	} else {
7461da177e4SLinus Torvalds 		numblocks = (int)(mtd->size >> this->bbt_erase_shift);
7471da177e4SLinus Torvalds 		nrchips = 1;
7481da177e4SLinus Torvalds 	}
7491da177e4SLinus Torvalds 
7501da177e4SLinus Torvalds 	/* Loop through the chips */
75110ffd570SKyle Roeschley 	while (chip < nrchips) {
752c3baf278SBoris Brezillon 		int block;
7531da177e4SLinus Torvalds 
754c3baf278SBoris Brezillon 		block = get_bbt_block(this, td, md, chip);
755c3baf278SBoris Brezillon 		if (block < 0) {
7569a4d4d69SBrian Norris 			pr_err("No space left to write bad block table\n");
757c3baf278SBoris Brezillon 			res = block;
758c3baf278SBoris Brezillon 			goto outerr;
759c3baf278SBoris Brezillon 		}
760c3baf278SBoris Brezillon 
761c3baf278SBoris Brezillon 		/*
762c3baf278SBoris Brezillon 		 * get_bbt_block() returns a block number, shift the value to
763c3baf278SBoris Brezillon 		 * get a page number.
764c3baf278SBoris Brezillon 		 */
765c3baf278SBoris Brezillon 		page = block << (this->bbt_erase_shift - this->page_shift);
7661da177e4SLinus Torvalds 
7671da177e4SLinus Torvalds 		/* Set up shift count and masks for the flash table */
7681da177e4SLinus Torvalds 		bits = td->options & NAND_BBT_NRBITS_MSK;
7699223a456SThomas Gleixner 		msk[2] = ~rcode;
7701da177e4SLinus Torvalds 		switch (bits) {
7719223a456SThomas Gleixner 		case 1: sft = 3; sftmsk = 0x07; msk[0] = 0x00; msk[1] = 0x01;
7729223a456SThomas Gleixner 			msk[3] = 0x01;
7739223a456SThomas Gleixner 			break;
7749223a456SThomas Gleixner 		case 2: sft = 2; sftmsk = 0x06; msk[0] = 0x00; msk[1] = 0x01;
7759223a456SThomas Gleixner 			msk[3] = 0x03;
7769223a456SThomas Gleixner 			break;
7779223a456SThomas Gleixner 		case 4: sft = 1; sftmsk = 0x04; msk[0] = 0x00; msk[1] = 0x0C;
7789223a456SThomas Gleixner 			msk[3] = 0x0f;
7799223a456SThomas Gleixner 			break;
7809223a456SThomas Gleixner 		case 8: sft = 0; sftmsk = 0x00; msk[0] = 0x00; msk[1] = 0x0F;
7819223a456SThomas Gleixner 			msk[3] = 0xff;
7829223a456SThomas Gleixner 			break;
7831da177e4SLinus Torvalds 		default: return -EINVAL;
7841da177e4SLinus Torvalds 		}
7851da177e4SLinus Torvalds 
7861da177e4SLinus Torvalds 		to = ((loff_t)page) << this->page_shift;
7871da177e4SLinus Torvalds 
7881da177e4SLinus Torvalds 		/* Must we save the block contents? */
7891da177e4SLinus Torvalds 		if (td->options & NAND_BBT_SAVECONTENT) {
7901da177e4SLinus Torvalds 			/* Make it block aligned */
791f5cd2ae1SBrian Norris 			to &= ~(((loff_t)1 << this->bbt_erase_shift) - 1);
7921da177e4SLinus Torvalds 			len = 1 << this->bbt_erase_shift;
793329ad399SArtem Bityutskiy 			res = mtd_read(mtd, to, len, &retlen, buf);
7941da177e4SLinus Torvalds 			if (res < 0) {
7951da177e4SLinus Torvalds 				if (retlen != len) {
7962ac63d90SRafał Miłecki 					pr_info("nand_bbt: error reading block for writing the bad block table\n");
7971da177e4SLinus Torvalds 					return res;
7981da177e4SLinus Torvalds 				}
7992ac63d90SRafał Miłecki 				pr_warn("nand_bbt: ECC error while reading block for writing bad block table\n");
8001da177e4SLinus Torvalds 			}
8019223a456SThomas Gleixner 			/* Read oob data */
8027014568bSVitaly Wool 			ops.ooblen = (len >> this->page_shift) * mtd->oobsize;
8038593fbc6SThomas Gleixner 			ops.oobbuf = &buf[len];
804fd2819bbSArtem Bityutskiy 			res = mtd_read_oob(mtd, to + mtd->writesize, &ops);
8057014568bSVitaly Wool 			if (res < 0 || ops.oobretlen != ops.ooblen)
8069223a456SThomas Gleixner 				goto outerr;
8079223a456SThomas Gleixner 
8081da177e4SLinus Torvalds 			/* Calc the byte offset in the buffer */
8091da177e4SLinus Torvalds 			pageoffs = page - (int)(to >> this->page_shift);
8101da177e4SLinus Torvalds 			offs = pageoffs << this->page_shift;
8111da177e4SLinus Torvalds 			/* Preset the bbt area with 0xff */
8121da177e4SLinus Torvalds 			memset(&buf[offs], 0xff, (size_t)(numblocks >> sft));
8139223a456SThomas Gleixner 			ooboffs = len + (pageoffs * mtd->oobsize);
8149223a456SThomas Gleixner 
8157cba7b14SSebastian Andrzej Siewior 		} else if (td->options & NAND_BBT_NO_OOB) {
8167cba7b14SSebastian Andrzej Siewior 			ooboffs = 0;
8177cba7b14SSebastian Andrzej Siewior 			offs = td->len;
8188b6e50c9SBrian Norris 			/* The version byte */
8197cba7b14SSebastian Andrzej Siewior 			if (td->options & NAND_BBT_VERSION)
8207cba7b14SSebastian Andrzej Siewior 				offs++;
8217cba7b14SSebastian Andrzej Siewior 			/* Calc length */
8227cba7b14SSebastian Andrzej Siewior 			len = (size_t)(numblocks >> sft);
8237cba7b14SSebastian Andrzej Siewior 			len += offs;
8247cba7b14SSebastian Andrzej Siewior 			/* Make it page aligned! */
8257cba7b14SSebastian Andrzej Siewior 			len = ALIGN(len, mtd->writesize);
8267cba7b14SSebastian Andrzej Siewior 			/* Preset the buffer with 0xff */
8277cba7b14SSebastian Andrzej Siewior 			memset(buf, 0xff, len);
8287cba7b14SSebastian Andrzej Siewior 			/* Pattern is located at the begin of first page */
8297cba7b14SSebastian Andrzej Siewior 			memcpy(buf, td->pattern, td->len);
8301da177e4SLinus Torvalds 		} else {
8311da177e4SLinus Torvalds 			/* Calc length */
8321da177e4SLinus Torvalds 			len = (size_t)(numblocks >> sft);
8331da177e4SLinus Torvalds 			/* Make it page aligned! */
834cda32091SSebastian Andrzej Siewior 			len = ALIGN(len, mtd->writesize);
8351da177e4SLinus Torvalds 			/* Preset the buffer with 0xff */
8369223a456SThomas Gleixner 			memset(buf, 0xff, len +
8379223a456SThomas Gleixner 			       (len >> this->page_shift)* mtd->oobsize);
8381da177e4SLinus Torvalds 			offs = 0;
8399223a456SThomas Gleixner 			ooboffs = len;
8401da177e4SLinus Torvalds 			/* Pattern is located in oob area of first page */
8419223a456SThomas Gleixner 			memcpy(&buf[ooboffs + td->offs], td->pattern, td->len);
8421da177e4SLinus Torvalds 		}
8439223a456SThomas Gleixner 
8449223a456SThomas Gleixner 		if (td->options & NAND_BBT_VERSION)
8459223a456SThomas Gleixner 			buf[ooboffs + td->veroffs] = td->version[chip];
8461da177e4SLinus Torvalds 
8478b6e50c9SBrian Norris 		/* Walk through the memory table */
848b4d20d60SBrian Norris 		for (i = 0; i < numblocks; i++) {
8491da177e4SLinus Torvalds 			uint8_t dat;
8501da177e4SLinus Torvalds 			int sftcnt = (i << (3 - sft)) & sftmsk;
851b4d20d60SBrian Norris 			dat = bbt_get_entry(this, chip * numblocks + i);
8521da177e4SLinus Torvalds 			/* Do not store the reserved bbt blocks! */
853b4d20d60SBrian Norris 			buf[offs + (i >> sft)] &= ~(msk[dat] << sftcnt);
8541da177e4SLinus Torvalds 		}
8551da177e4SLinus Torvalds 
8561da177e4SLinus Torvalds 		memset(&einfo, 0, sizeof(einfo));
85769423d99SAdrian Hunter 		einfo.addr = to;
8581da177e4SLinus Torvalds 		einfo.len = 1 << this->bbt_erase_shift;
859e4cdf9cbSBoris Brezillon 		res = nand_erase_nand(this, &einfo, 1);
86010ffd570SKyle Roeschley 		if (res < 0) {
86110ffd570SKyle Roeschley 			pr_warn("nand_bbt: error while erasing BBT block %d\n",
86210ffd570SKyle Roeschley 				res);
86310ffd570SKyle Roeschley 			mark_bbt_block_bad(this, td, chip, block);
86410ffd570SKyle Roeschley 			continue;
86510ffd570SKyle Roeschley 		}
8661da177e4SLinus Torvalds 
8670813621bSBoris Brezillon 		res = scan_write_bbt(this, to, len, buf,
8680813621bSBoris Brezillon 				     td->options & NAND_BBT_NO_OOB ?
8690813621bSBoris Brezillon 				     NULL : &buf[len]);
87010ffd570SKyle Roeschley 		if (res < 0) {
87110ffd570SKyle Roeschley 			pr_warn("nand_bbt: error while writing BBT block %d\n",
87210ffd570SKyle Roeschley 				res);
87310ffd570SKyle Roeschley 			mark_bbt_block_bad(this, td, chip, block);
87410ffd570SKyle Roeschley 			continue;
87510ffd570SKyle Roeschley 		}
8769223a456SThomas Gleixner 
877d0370219SBrian Norris 		pr_info("Bad block table written to 0x%012llx, version 0x%02X\n",
878d0370219SBrian Norris 			 (unsigned long long)to, td->version[chip]);
8791da177e4SLinus Torvalds 
8801da177e4SLinus Torvalds 		/* Mark it as used */
88110ffd570SKyle Roeschley 		td->pages[chip++] = page;
8821da177e4SLinus Torvalds 	}
8831da177e4SLinus Torvalds 	return 0;
8849223a456SThomas Gleixner 
8859223a456SThomas Gleixner  outerr:
886d0370219SBrian Norris 	pr_warn("nand_bbt: error while writing bad block table %d\n", res);
8879223a456SThomas Gleixner 	return res;
8881da177e4SLinus Torvalds }
8891da177e4SLinus Torvalds 
8901da177e4SLinus Torvalds /**
8911da177e4SLinus Torvalds  * nand_memory_bbt - [GENERIC] create a memory based bad block table
8920813621bSBoris Brezillon  * @this: NAND chip object
8931da177e4SLinus Torvalds  * @bd: descriptor for the good/bad block search pattern
8941da177e4SLinus Torvalds  *
8958b6e50c9SBrian Norris  * The function creates a memory based bbt by scanning the device for
8968b6e50c9SBrian Norris  * manufacturer / software marked good / bad blocks.
8971da177e4SLinus Torvalds  */
8980813621bSBoris Brezillon static inline int nand_memory_bbt(struct nand_chip *this,
8990813621bSBoris Brezillon 				  struct nand_bbt_descr *bd)
9001da177e4SLinus Torvalds {
901eeab7174SBoris Brezillon 	u8 *pagebuf = nand_get_data_buf(this);
902eeab7174SBoris Brezillon 
903eeab7174SBoris Brezillon 	return create_bbt(this, pagebuf, bd, -1);
9041da177e4SLinus Torvalds }
9051da177e4SLinus Torvalds 
9061da177e4SLinus Torvalds /**
907e0c7d767SDavid Woodhouse  * check_create - [GENERIC] create and write bbt(s) if necessary
9080813621bSBoris Brezillon  * @this: the NAND device
9091da177e4SLinus Torvalds  * @buf: temporary buffer
9101da177e4SLinus Torvalds  * @bd: descriptor for the good/bad block search pattern
9111da177e4SLinus Torvalds  *
9128b6e50c9SBrian Norris  * The function checks the results of the previous call to read_bbt and creates
9138b6e50c9SBrian Norris  * / updates the bbt(s) if necessary. Creation is necessary if no bbt was found
9148b6e50c9SBrian Norris  * for the chip/device. Update is necessary if one of the tables is missing or
9158b6e50c9SBrian Norris  * the version nr. of one table is less than the other.
9161da177e4SLinus Torvalds  */
9170813621bSBoris Brezillon static int check_create(struct nand_chip *this, uint8_t *buf,
9180813621bSBoris Brezillon 			struct nand_bbt_descr *bd)
9191da177e4SLinus Torvalds {
920623978deSBrian Norris 	int i, chips, writeops, create, chipsel, res, res2;
9211da177e4SLinus Torvalds 	struct nand_bbt_descr *td = this->bbt_td;
9221da177e4SLinus Torvalds 	struct nand_bbt_descr *md = this->bbt_md;
9231da177e4SLinus Torvalds 	struct nand_bbt_descr *rd, *rd2;
9241da177e4SLinus Torvalds 
9251da177e4SLinus Torvalds 	/* Do we have a bbt per chip? */
9261da177e4SLinus Torvalds 	if (td->options & NAND_BBT_PERCHIP)
92732813e28SBoris Brezillon 		chips = nanddev_ntargets(&this->base);
9281da177e4SLinus Torvalds 	else
9291da177e4SLinus Torvalds 		chips = 1;
9301da177e4SLinus Torvalds 
9311da177e4SLinus Torvalds 	for (i = 0; i < chips; i++) {
9321da177e4SLinus Torvalds 		writeops = 0;
933b61bf5bbSBrian Norris 		create = 0;
9341da177e4SLinus Torvalds 		rd = NULL;
9351da177e4SLinus Torvalds 		rd2 = NULL;
936623978deSBrian Norris 		res = res2 = 0;
9371da177e4SLinus Torvalds 		/* Per chip or per device? */
9381da177e4SLinus Torvalds 		chipsel = (td->options & NAND_BBT_PERCHIP) ? i : -1;
93925985edcSLucas De Marchi 		/* Mirrored table available? */
9401da177e4SLinus Torvalds 		if (md) {
9411da177e4SLinus Torvalds 			if (td->pages[i] == -1 && md->pages[i] == -1) {
942b61bf5bbSBrian Norris 				create = 1;
9431da177e4SLinus Torvalds 				writeops = 0x03;
944c5e8ef9cSBrian Norris 			} else if (td->pages[i] == -1) {
9451da177e4SLinus Torvalds 				rd = md;
946596d7452SBrian Norris 				writeops = 0x01;
947c5e8ef9cSBrian Norris 			} else if (md->pages[i] == -1) {
9481da177e4SLinus Torvalds 				rd = td;
949596d7452SBrian Norris 				writeops = 0x02;
950c5e8ef9cSBrian Norris 			} else if (td->version[i] == md->version[i]) {
9511da177e4SLinus Torvalds 				rd = td;
9521da177e4SLinus Torvalds 				if (!(td->options & NAND_BBT_VERSION))
9531da177e4SLinus Torvalds 					rd2 = md;
954c5e8ef9cSBrian Norris 			} else if (((int8_t)(td->version[i] - md->version[i])) > 0) {
9551da177e4SLinus Torvalds 				rd = td;
956596d7452SBrian Norris 				writeops = 0x02;
9571da177e4SLinus Torvalds 			} else {
9581da177e4SLinus Torvalds 				rd = md;
959596d7452SBrian Norris 				writeops = 0x01;
9601da177e4SLinus Torvalds 			}
9611da177e4SLinus Torvalds 		} else {
9621da177e4SLinus Torvalds 			if (td->pages[i] == -1) {
963b61bf5bbSBrian Norris 				create = 1;
9641da177e4SLinus Torvalds 				writeops = 0x01;
965b61bf5bbSBrian Norris 			} else {
9661da177e4SLinus Torvalds 				rd = td;
9671da177e4SLinus Torvalds 			}
968b61bf5bbSBrian Norris 		}
969b61bf5bbSBrian Norris 
970b61bf5bbSBrian Norris 		if (create) {
9711da177e4SLinus Torvalds 			/* Create the bad block table by scanning the device? */
9721da177e4SLinus Torvalds 			if (!(td->options & NAND_BBT_CREATE))
9731da177e4SLinus Torvalds 				continue;
9741da177e4SLinus Torvalds 
9751da177e4SLinus Torvalds 			/* Create the table in memory by scanning the chip(s) */
97653d5d888SBrian Norris 			if (!(this->bbt_options & NAND_BBT_CREATE_EMPTY))
9770813621bSBoris Brezillon 				create_bbt(this, buf, bd, chipsel);
9781da177e4SLinus Torvalds 
9791da177e4SLinus Torvalds 			td->version[i] = 1;
9801da177e4SLinus Torvalds 			if (md)
9811da177e4SLinus Torvalds 				md->version[i] = 1;
982b61bf5bbSBrian Norris 		}
983b61bf5bbSBrian Norris 
9848b6e50c9SBrian Norris 		/* Read back first? */
985623978deSBrian Norris 		if (rd) {
9860813621bSBoris Brezillon 			res = read_abs_bbt(this, buf, rd, chipsel);
987623978deSBrian Norris 			if (mtd_is_eccerr(res)) {
988623978deSBrian Norris 				/* Mark table as invalid */
989623978deSBrian Norris 				rd->pages[i] = -1;
990dadc17a3SBrian Norris 				rd->version[i] = 0;
991623978deSBrian Norris 				i--;
992623978deSBrian Norris 				continue;
993623978deSBrian Norris 			}
994623978deSBrian Norris 		}
9958b6e50c9SBrian Norris 		/* If they weren't versioned, read both */
996623978deSBrian Norris 		if (rd2) {
9970813621bSBoris Brezillon 			res2 = read_abs_bbt(this, buf, rd2, chipsel);
998623978deSBrian Norris 			if (mtd_is_eccerr(res2)) {
999623978deSBrian Norris 				/* Mark table as invalid */
1000623978deSBrian Norris 				rd2->pages[i] = -1;
1001dadc17a3SBrian Norris 				rd2->version[i] = 0;
1002623978deSBrian Norris 				i--;
1003623978deSBrian Norris 				continue;
1004623978deSBrian Norris 			}
1005623978deSBrian Norris 		}
1006623978deSBrian Norris 
1007623978deSBrian Norris 		/* Scrub the flash table(s)? */
1008623978deSBrian Norris 		if (mtd_is_bitflip(res) || mtd_is_bitflip(res2))
1009623978deSBrian Norris 			writeops = 0x03;
10101da177e4SLinus Torvalds 
1011dadc17a3SBrian Norris 		/* Update version numbers before writing */
1012dadc17a3SBrian Norris 		if (md) {
1013dadc17a3SBrian Norris 			td->version[i] = max(td->version[i], md->version[i]);
1014dadc17a3SBrian Norris 			md->version[i] = td->version[i];
1015dadc17a3SBrian Norris 		}
10161da177e4SLinus Torvalds 
10171da177e4SLinus Torvalds 		/* Write the bad block table to the device? */
10181da177e4SLinus Torvalds 		if ((writeops & 0x01) && (td->options & NAND_BBT_WRITE)) {
10190813621bSBoris Brezillon 			res = write_bbt(this, buf, td, md, chipsel);
10201da177e4SLinus Torvalds 			if (res < 0)
10211da177e4SLinus Torvalds 				return res;
10221da177e4SLinus Torvalds 		}
10231da177e4SLinus Torvalds 
10241da177e4SLinus Torvalds 		/* Write the mirror bad block table to the device? */
10251da177e4SLinus Torvalds 		if ((writeops & 0x02) && md && (md->options & NAND_BBT_WRITE)) {
10260813621bSBoris Brezillon 			res = write_bbt(this, buf, md, td, chipsel);
10271da177e4SLinus Torvalds 			if (res < 0)
10281da177e4SLinus Torvalds 				return res;
10291da177e4SLinus Torvalds 		}
10301da177e4SLinus Torvalds 	}
10311da177e4SLinus Torvalds 	return 0;
10321da177e4SLinus Torvalds }
10331da177e4SLinus Torvalds 
10341da177e4SLinus Torvalds /**
103599f3351aSBoris Brezillon  * nand_update_bbt - update bad block table(s)
103699f3351aSBoris Brezillon  * @this: the NAND device
103799f3351aSBoris Brezillon  * @offs: the offset of the newly marked block
103899f3351aSBoris Brezillon  *
103999f3351aSBoris Brezillon  * The function updates the bad block table(s).
104099f3351aSBoris Brezillon  */
104199f3351aSBoris Brezillon static int nand_update_bbt(struct nand_chip *this, loff_t offs)
104299f3351aSBoris Brezillon {
104399f3351aSBoris Brezillon 	struct mtd_info *mtd = nand_to_mtd(this);
104499f3351aSBoris Brezillon 	int len, res = 0;
104599f3351aSBoris Brezillon 	int chip, chipsel;
104699f3351aSBoris Brezillon 	uint8_t *buf;
104799f3351aSBoris Brezillon 	struct nand_bbt_descr *td = this->bbt_td;
104899f3351aSBoris Brezillon 	struct nand_bbt_descr *md = this->bbt_md;
104999f3351aSBoris Brezillon 
105099f3351aSBoris Brezillon 	if (!this->bbt || !td)
105199f3351aSBoris Brezillon 		return -EINVAL;
105299f3351aSBoris Brezillon 
105399f3351aSBoris Brezillon 	/* Allocate a temporary buffer for one eraseblock incl. oob */
105499f3351aSBoris Brezillon 	len = (1 << this->bbt_erase_shift);
105599f3351aSBoris Brezillon 	len += (len >> this->page_shift) * mtd->oobsize;
105699f3351aSBoris Brezillon 	buf = kmalloc(len, GFP_KERNEL);
105799f3351aSBoris Brezillon 	if (!buf)
105899f3351aSBoris Brezillon 		return -ENOMEM;
105999f3351aSBoris Brezillon 
106099f3351aSBoris Brezillon 	/* Do we have a bbt per chip? */
106199f3351aSBoris Brezillon 	if (td->options & NAND_BBT_PERCHIP) {
106299f3351aSBoris Brezillon 		chip = (int)(offs >> this->chip_shift);
106399f3351aSBoris Brezillon 		chipsel = chip;
106499f3351aSBoris Brezillon 	} else {
106599f3351aSBoris Brezillon 		chip = 0;
106699f3351aSBoris Brezillon 		chipsel = -1;
106799f3351aSBoris Brezillon 	}
106899f3351aSBoris Brezillon 
106999f3351aSBoris Brezillon 	td->version[chip]++;
107099f3351aSBoris Brezillon 	if (md)
107199f3351aSBoris Brezillon 		md->version[chip]++;
107299f3351aSBoris Brezillon 
107399f3351aSBoris Brezillon 	/* Write the bad block table to the device? */
107499f3351aSBoris Brezillon 	if (td->options & NAND_BBT_WRITE) {
107599f3351aSBoris Brezillon 		res = write_bbt(this, buf, td, md, chipsel);
107699f3351aSBoris Brezillon 		if (res < 0)
107799f3351aSBoris Brezillon 			goto out;
107899f3351aSBoris Brezillon 	}
107999f3351aSBoris Brezillon 	/* Write the mirror bad block table to the device? */
108099f3351aSBoris Brezillon 	if (md && (md->options & NAND_BBT_WRITE)) {
108199f3351aSBoris Brezillon 		res = write_bbt(this, buf, md, td, chipsel);
108299f3351aSBoris Brezillon 	}
108399f3351aSBoris Brezillon 
108499f3351aSBoris Brezillon  out:
108599f3351aSBoris Brezillon 	kfree(buf);
108699f3351aSBoris Brezillon 	return res;
108799f3351aSBoris Brezillon }
108899f3351aSBoris Brezillon 
108999f3351aSBoris Brezillon /**
1090*7998d898SMauro Carvalho Chehab  * mark_bbt_region - [GENERIC] mark the bad block table regions
10910813621bSBoris Brezillon  * @this: the NAND device
10921da177e4SLinus Torvalds  * @td: bad block table descriptor
10931da177e4SLinus Torvalds  *
10948b6e50c9SBrian Norris  * The bad block table regions are marked as "bad" to prevent accidental
10958b6e50c9SBrian Norris  * erasures / writes. The regions are identified by the mark 0x02.
10961da177e4SLinus Torvalds  */
10970813621bSBoris Brezillon static void mark_bbt_region(struct nand_chip *this, struct nand_bbt_descr *td)
10981da177e4SLinus Torvalds {
10996c836d51SBoris Brezillon 	u64 targetsize = nanddev_target_size(&this->base);
11000813621bSBoris Brezillon 	struct mtd_info *mtd = nand_to_mtd(this);
11011da177e4SLinus Torvalds 	int i, j, chips, block, nrblocks, update;
1102771c568bSBrian Norris 	uint8_t oldval;
11031da177e4SLinus Torvalds 
11041da177e4SLinus Torvalds 	/* Do we have a bbt per chip? */
11051da177e4SLinus Torvalds 	if (td->options & NAND_BBT_PERCHIP) {
110632813e28SBoris Brezillon 		chips = nanddev_ntargets(&this->base);
11076c836d51SBoris Brezillon 		nrblocks = (int)(targetsize >> this->bbt_erase_shift);
11081da177e4SLinus Torvalds 	} else {
11091da177e4SLinus Torvalds 		chips = 1;
11101da177e4SLinus Torvalds 		nrblocks = (int)(mtd->size >> this->bbt_erase_shift);
11111da177e4SLinus Torvalds 	}
11121da177e4SLinus Torvalds 
11131da177e4SLinus Torvalds 	for (i = 0; i < chips; i++) {
11141da177e4SLinus Torvalds 		if ((td->options & NAND_BBT_ABSPAGE) ||
11151da177e4SLinus Torvalds 		    !(td->options & NAND_BBT_WRITE)) {
1116e0c7d767SDavid Woodhouse 			if (td->pages[i] == -1)
1117e0c7d767SDavid Woodhouse 				continue;
11181da177e4SLinus Torvalds 			block = td->pages[i] >> (this->bbt_erase_shift - this->page_shift);
1119b4d20d60SBrian Norris 			oldval = bbt_get_entry(this, block);
1120b4d20d60SBrian Norris 			bbt_mark_entry(this, block, BBT_BLOCK_RESERVED);
1121771c568bSBrian Norris 			if ((oldval != BBT_BLOCK_RESERVED) &&
1122771c568bSBrian Norris 					td->reserved_block_code)
11230813621bSBoris Brezillon 				nand_update_bbt(this, (loff_t)block <<
1124b4d20d60SBrian Norris 						this->bbt_erase_shift);
11251da177e4SLinus Torvalds 			continue;
11261da177e4SLinus Torvalds 		}
11271da177e4SLinus Torvalds 		update = 0;
11281da177e4SLinus Torvalds 		if (td->options & NAND_BBT_LASTBLOCK)
11291da177e4SLinus Torvalds 			block = ((i + 1) * nrblocks) - td->maxblocks;
11301da177e4SLinus Torvalds 		else
11311da177e4SLinus Torvalds 			block = i * nrblocks;
11321da177e4SLinus Torvalds 		for (j = 0; j < td->maxblocks; j++) {
1133b4d20d60SBrian Norris 			oldval = bbt_get_entry(this, block);
1134b4d20d60SBrian Norris 			bbt_mark_entry(this, block, BBT_BLOCK_RESERVED);
1135771c568bSBrian Norris 			if (oldval != BBT_BLOCK_RESERVED)
1136e0c7d767SDavid Woodhouse 				update = 1;
1137b4d20d60SBrian Norris 			block++;
11381da177e4SLinus Torvalds 		}
11398b6e50c9SBrian Norris 		/*
11408b6e50c9SBrian Norris 		 * If we want reserved blocks to be recorded to flash, and some
11418b6e50c9SBrian Norris 		 * new ones have been marked, then we need to update the stored
11428b6e50c9SBrian Norris 		 * bbts.  This should only happen once.
11438b6e50c9SBrian Norris 		 */
11441da177e4SLinus Torvalds 		if (update && td->reserved_block_code)
11450813621bSBoris Brezillon 			nand_update_bbt(this, (loff_t)(block - 1) <<
1146b4d20d60SBrian Norris 					this->bbt_erase_shift);
11471da177e4SLinus Torvalds 	}
11481da177e4SLinus Torvalds }
11491da177e4SLinus Torvalds 
11501da177e4SLinus Torvalds /**
11517cba7b14SSebastian Andrzej Siewior  * verify_bbt_descr - verify the bad block description
11520813621bSBoris Brezillon  * @this: the NAND device
11537cba7b14SSebastian Andrzej Siewior  * @bd: the table to verify
11547cba7b14SSebastian Andrzej Siewior  *
11557cba7b14SSebastian Andrzej Siewior  * This functions performs a few sanity checks on the bad block description
11567cba7b14SSebastian Andrzej Siewior  * table.
11577cba7b14SSebastian Andrzej Siewior  */
11580813621bSBoris Brezillon static void verify_bbt_descr(struct nand_chip *this, struct nand_bbt_descr *bd)
11597cba7b14SSebastian Andrzej Siewior {
11606c836d51SBoris Brezillon 	u64 targetsize = nanddev_target_size(&this->base);
11610813621bSBoris Brezillon 	struct mtd_info *mtd = nand_to_mtd(this);
11627912a5e7SStanislav Fomichev 	u32 pattern_len;
11637912a5e7SStanislav Fomichev 	u32 bits;
11647cba7b14SSebastian Andrzej Siewior 	u32 table_size;
11657cba7b14SSebastian Andrzej Siewior 
11667cba7b14SSebastian Andrzej Siewior 	if (!bd)
11677cba7b14SSebastian Andrzej Siewior 		return;
11687912a5e7SStanislav Fomichev 
11697912a5e7SStanislav Fomichev 	pattern_len = bd->len;
11707912a5e7SStanislav Fomichev 	bits = bd->options & NAND_BBT_NRBITS_MSK;
11717912a5e7SStanislav Fomichev 
1172a40f7341SBrian Norris 	BUG_ON((this->bbt_options & NAND_BBT_NO_OOB) &&
1173bb9ebd4eSBrian Norris 			!(this->bbt_options & NAND_BBT_USE_FLASH));
11747cba7b14SSebastian Andrzej Siewior 	BUG_ON(!bits);
11757cba7b14SSebastian Andrzej Siewior 
11767cba7b14SSebastian Andrzej Siewior 	if (bd->options & NAND_BBT_VERSION)
11777cba7b14SSebastian Andrzej Siewior 		pattern_len++;
11787cba7b14SSebastian Andrzej Siewior 
11797cba7b14SSebastian Andrzej Siewior 	if (bd->options & NAND_BBT_NO_OOB) {
1180bb9ebd4eSBrian Norris 		BUG_ON(!(this->bbt_options & NAND_BBT_USE_FLASH));
1181a40f7341SBrian Norris 		BUG_ON(!(this->bbt_options & NAND_BBT_NO_OOB));
11827cba7b14SSebastian Andrzej Siewior 		BUG_ON(bd->offs);
11837cba7b14SSebastian Andrzej Siewior 		if (bd->options & NAND_BBT_VERSION)
11847cba7b14SSebastian Andrzej Siewior 			BUG_ON(bd->veroffs != bd->len);
11857cba7b14SSebastian Andrzej Siewior 		BUG_ON(bd->options & NAND_BBT_SAVECONTENT);
11867cba7b14SSebastian Andrzej Siewior 	}
11877cba7b14SSebastian Andrzej Siewior 
11887cba7b14SSebastian Andrzej Siewior 	if (bd->options & NAND_BBT_PERCHIP)
11896c836d51SBoris Brezillon 		table_size = targetsize >> this->bbt_erase_shift;
11907cba7b14SSebastian Andrzej Siewior 	else
11917cba7b14SSebastian Andrzej Siewior 		table_size = mtd->size >> this->bbt_erase_shift;
11927cba7b14SSebastian Andrzej Siewior 	table_size >>= 3;
11937cba7b14SSebastian Andrzej Siewior 	table_size *= bits;
11947cba7b14SSebastian Andrzej Siewior 	if (bd->options & NAND_BBT_NO_OOB)
11957cba7b14SSebastian Andrzej Siewior 		table_size += pattern_len;
11967cba7b14SSebastian Andrzej Siewior 	BUG_ON(table_size > (1 << this->bbt_erase_shift));
11977cba7b14SSebastian Andrzej Siewior }
11987cba7b14SSebastian Andrzej Siewior 
11997cba7b14SSebastian Andrzej Siewior /**
12001da177e4SLinus Torvalds  * nand_scan_bbt - [NAND Interface] scan, find, read and maybe create bad block table(s)
12010813621bSBoris Brezillon  * @this: the NAND device
12021da177e4SLinus Torvalds  * @bd: descriptor for the good/bad block search pattern
12031da177e4SLinus Torvalds  *
12048b6e50c9SBrian Norris  * The function checks, if a bad block table(s) is/are already available. If
12058b6e50c9SBrian Norris  * not it scans the device for manufacturer marked good / bad blocks and writes
12068b6e50c9SBrian Norris  * the bad block table(s) to the selected place.
12071da177e4SLinus Torvalds  *
12088b6e50c9SBrian Norris  * The bad block table memory is allocated here. It must be freed by calling
12098b6e50c9SBrian Norris  * the nand_free_bbt function.
12101da177e4SLinus Torvalds  */
12110813621bSBoris Brezillon static int nand_scan_bbt(struct nand_chip *this, struct nand_bbt_descr *bd)
12121da177e4SLinus Torvalds {
12130813621bSBoris Brezillon 	struct mtd_info *mtd = nand_to_mtd(this);
121483c59542SBrian Norris 	int len, res;
12151da177e4SLinus Torvalds 	uint8_t *buf;
12161da177e4SLinus Torvalds 	struct nand_bbt_descr *td = this->bbt_td;
12171da177e4SLinus Torvalds 	struct nand_bbt_descr *md = this->bbt_md;
12181da177e4SLinus Torvalds 
1219192db1caSSheng Yong 	len = (mtd->size >> (this->bbt_erase_shift + 2)) ? : 1;
12208b6e50c9SBrian Norris 	/*
12218b6e50c9SBrian Norris 	 * Allocate memory (2bit per block) and clear the memory bad block
12228b6e50c9SBrian Norris 	 * table.
12238b6e50c9SBrian Norris 	 */
122495b93a0cSBurman Yan 	this->bbt = kzalloc(len, GFP_KERNEL);
12250870066dSBrian Norris 	if (!this->bbt)
12261da177e4SLinus Torvalds 		return -ENOMEM;
12271da177e4SLinus Torvalds 
12288b6e50c9SBrian Norris 	/*
1229735bf220SKieran Bingham 	 * If no primary table descriptor is given, scan the device to build a
12308b6e50c9SBrian Norris 	 * memory based bad block table.
12311da177e4SLinus Torvalds 	 */
1232eeada24dSArtem B. Bityuckiy 	if (!td) {
12330813621bSBoris Brezillon 		if ((res = nand_memory_bbt(this, bd))) {
1234d0370219SBrian Norris 			pr_err("nand_bbt: can't scan flash and build the RAM-based BBT\n");
123586aa04f4SWenwen Wang 			goto err_free_bbt;
1236eeada24dSArtem B. Bityuckiy 		}
123783c59542SBrian Norris 		return 0;
1238eeada24dSArtem B. Bityuckiy 	}
12390813621bSBoris Brezillon 	verify_bbt_descr(this, td);
12400813621bSBoris Brezillon 	verify_bbt_descr(this, md);
12411da177e4SLinus Torvalds 
12421da177e4SLinus Torvalds 	/* Allocate a temporary buffer for one eraseblock incl. oob */
12431da177e4SLinus Torvalds 	len = (1 << this->bbt_erase_shift);
12441da177e4SLinus Torvalds 	len += (len >> this->page_shift) * mtd->oobsize;
1245c3f8abf4SDavid Woodhouse 	buf = vmalloc(len);
12461da177e4SLinus Torvalds 	if (!buf) {
124783c59542SBrian Norris 		res = -ENOMEM;
124886aa04f4SWenwen Wang 		goto err_free_bbt;
12491da177e4SLinus Torvalds 	}
12501da177e4SLinus Torvalds 
12511da177e4SLinus Torvalds 	/* Is the bbt at a given page? */
12521da177e4SLinus Torvalds 	if (td->options & NAND_BBT_ABSPAGE) {
12530813621bSBoris Brezillon 		read_abs_bbts(this, buf, td, md);
12541da177e4SLinus Torvalds 	} else {
12551da177e4SLinus Torvalds 		/* Search the bad block table using a pattern in oob */
12560813621bSBoris Brezillon 		search_read_bbts(this, buf, td, md);
12571da177e4SLinus Torvalds 	}
12581da177e4SLinus Torvalds 
12590813621bSBoris Brezillon 	res = check_create(this, buf, bd);
126083c59542SBrian Norris 	if (res)
126186aa04f4SWenwen Wang 		goto err_free_buf;
12621da177e4SLinus Torvalds 
12631da177e4SLinus Torvalds 	/* Prevent the bbt regions from erasing / writing */
12640813621bSBoris Brezillon 	mark_bbt_region(this, td);
12651da177e4SLinus Torvalds 	if (md)
12660813621bSBoris Brezillon 		mark_bbt_region(this, md);
12671da177e4SLinus Torvalds 
1268c3f8abf4SDavid Woodhouse 	vfree(buf);
126983c59542SBrian Norris 	return 0;
127083c59542SBrian Norris 
127186aa04f4SWenwen Wang err_free_buf:
127286aa04f4SWenwen Wang 	vfree(buf);
127386aa04f4SWenwen Wang err_free_bbt:
127483c59542SBrian Norris 	kfree(this->bbt);
127583c59542SBrian Norris 	this->bbt = NULL;
12761da177e4SLinus Torvalds 	return res;
12771da177e4SLinus Torvalds }
12781da177e4SLinus Torvalds 
12798b6e50c9SBrian Norris /*
12808b6e50c9SBrian Norris  * Define some generic bad / good block scan pattern which are used
12818b6e50c9SBrian Norris  * while scanning a device for factory marked good / bad blocks.
12828b6e50c9SBrian Norris  */
12831da177e4SLinus Torvalds static uint8_t scan_ff_pattern[] = { 0xff, 0xff };
12841da177e4SLinus Torvalds 
12857854d3f7SBrian Norris /* Generic flash bbt descriptors */
12861da177e4SLinus Torvalds static uint8_t bbt_pattern[] = {'B', 'b', 't', '0' };
12871da177e4SLinus Torvalds static uint8_t mirror_pattern[] = {'1', 't', 'b', 'B' };
12881da177e4SLinus Torvalds 
12891da177e4SLinus Torvalds static struct nand_bbt_descr bbt_main_descr = {
12901da177e4SLinus Torvalds 	.options = NAND_BBT_LASTBLOCK | NAND_BBT_CREATE | NAND_BBT_WRITE
12911da177e4SLinus Torvalds 		| NAND_BBT_2BIT | NAND_BBT_VERSION | NAND_BBT_PERCHIP,
12921da177e4SLinus Torvalds 	.offs =	8,
12931da177e4SLinus Torvalds 	.len = 4,
12941da177e4SLinus Torvalds 	.veroffs = 12,
129561de9da6SRichard Genoud 	.maxblocks = NAND_BBT_SCAN_MAXBLOCKS,
12961da177e4SLinus Torvalds 	.pattern = bbt_pattern
12971da177e4SLinus Torvalds };
12981da177e4SLinus Torvalds 
12991da177e4SLinus Torvalds static struct nand_bbt_descr bbt_mirror_descr = {
13001da177e4SLinus Torvalds 	.options = NAND_BBT_LASTBLOCK | NAND_BBT_CREATE | NAND_BBT_WRITE
13011da177e4SLinus Torvalds 		| NAND_BBT_2BIT | NAND_BBT_VERSION | NAND_BBT_PERCHIP,
13021da177e4SLinus Torvalds 	.offs =	8,
13031da177e4SLinus Torvalds 	.len = 4,
13041da177e4SLinus Torvalds 	.veroffs = 12,
130561de9da6SRichard Genoud 	.maxblocks = NAND_BBT_SCAN_MAXBLOCKS,
13061da177e4SLinus Torvalds 	.pattern = mirror_pattern
13071da177e4SLinus Torvalds };
13081da177e4SLinus Torvalds 
13099fd6b37aSBrian Norris static struct nand_bbt_descr bbt_main_no_oob_descr = {
13107cba7b14SSebastian Andrzej Siewior 	.options = NAND_BBT_LASTBLOCK | NAND_BBT_CREATE | NAND_BBT_WRITE
13117cba7b14SSebastian Andrzej Siewior 		| NAND_BBT_2BIT | NAND_BBT_VERSION | NAND_BBT_PERCHIP
13127cba7b14SSebastian Andrzej Siewior 		| NAND_BBT_NO_OOB,
13137cba7b14SSebastian Andrzej Siewior 	.len = 4,
13147cba7b14SSebastian Andrzej Siewior 	.veroffs = 4,
131561de9da6SRichard Genoud 	.maxblocks = NAND_BBT_SCAN_MAXBLOCKS,
13167cba7b14SSebastian Andrzej Siewior 	.pattern = bbt_pattern
13177cba7b14SSebastian Andrzej Siewior };
13187cba7b14SSebastian Andrzej Siewior 
13199fd6b37aSBrian Norris static struct nand_bbt_descr bbt_mirror_no_oob_descr = {
13207cba7b14SSebastian Andrzej Siewior 	.options = NAND_BBT_LASTBLOCK | NAND_BBT_CREATE | NAND_BBT_WRITE
13217cba7b14SSebastian Andrzej Siewior 		| NAND_BBT_2BIT | NAND_BBT_VERSION | NAND_BBT_PERCHIP
13227cba7b14SSebastian Andrzej Siewior 		| NAND_BBT_NO_OOB,
13237cba7b14SSebastian Andrzej Siewior 	.len = 4,
13247cba7b14SSebastian Andrzej Siewior 	.veroffs = 4,
132561de9da6SRichard Genoud 	.maxblocks = NAND_BBT_SCAN_MAXBLOCKS,
13267cba7b14SSebastian Andrzej Siewior 	.pattern = mirror_pattern
13277cba7b14SSebastian Andrzej Siewior };
13287cba7b14SSebastian Andrzej Siewior 
1329752ed6c5SBrian Norris #define BADBLOCK_SCAN_MASK (~NAND_BBT_NO_OOB)
133058373ff0SBrian Norris /**
1331752ed6c5SBrian Norris  * nand_create_badblock_pattern - [INTERN] Creates a BBT descriptor structure
133258373ff0SBrian Norris  * @this: NAND chip to create descriptor for
133358373ff0SBrian Norris  *
133458373ff0SBrian Norris  * This function allocates and initializes a nand_bbt_descr for BBM detection
1335752ed6c5SBrian Norris  * based on the properties of @this. The new descriptor is stored in
133658373ff0SBrian Norris  * this->badblock_pattern. Thus, this->badblock_pattern should be NULL when
133758373ff0SBrian Norris  * passed to this function.
133858373ff0SBrian Norris  */
1339752ed6c5SBrian Norris static int nand_create_badblock_pattern(struct nand_chip *this)
134058373ff0SBrian Norris {
134158373ff0SBrian Norris 	struct nand_bbt_descr *bd;
134258373ff0SBrian Norris 	if (this->badblock_pattern) {
1343752ed6c5SBrian Norris 		pr_warn("Bad block pattern already allocated; not replacing\n");
134458373ff0SBrian Norris 		return -EINVAL;
134558373ff0SBrian Norris 	}
134658373ff0SBrian Norris 	bd = kzalloc(sizeof(*bd), GFP_KERNEL);
13470870066dSBrian Norris 	if (!bd)
134858373ff0SBrian Norris 		return -ENOMEM;
1349752ed6c5SBrian Norris 	bd->options = this->bbt_options & BADBLOCK_SCAN_MASK;
135058373ff0SBrian Norris 	bd->offs = this->badblockpos;
135158373ff0SBrian Norris 	bd->len = (this->options & NAND_BUSWIDTH_16) ? 2 : 1;
135258373ff0SBrian Norris 	bd->pattern = scan_ff_pattern;
135358373ff0SBrian Norris 	bd->options |= NAND_BBT_DYNAMICSTRUCT;
135458373ff0SBrian Norris 	this->badblock_pattern = bd;
135558373ff0SBrian Norris 	return 0;
135658373ff0SBrian Norris }
135758373ff0SBrian Norris 
13581da177e4SLinus Torvalds /**
135944b07b92SBoris Brezillon  * nand_create_bbt - [NAND Interface] Select a default bad block table for the device
136044b07b92SBoris Brezillon  * @this: NAND chip object
13611da177e4SLinus Torvalds  *
13628b6e50c9SBrian Norris  * This function selects the default bad block table support for the device and
13638b6e50c9SBrian Norris  * calls the nand_scan_bbt function.
13641da177e4SLinus Torvalds  */
136544b07b92SBoris Brezillon int nand_create_bbt(struct nand_chip *this)
13661da177e4SLinus Torvalds {
1367abb9cf78SBrian Norris 	int ret;
13681da177e4SLinus Torvalds 
13691da177e4SLinus Torvalds 	/* Is a flash based bad block table requested? */
1370bb9ebd4eSBrian Norris 	if (this->bbt_options & NAND_BBT_USE_FLASH) {
13711da177e4SLinus Torvalds 		/* Use the default pattern descriptors */
13721da177e4SLinus Torvalds 		if (!this->bbt_td) {
1373a40f7341SBrian Norris 			if (this->bbt_options & NAND_BBT_NO_OOB) {
13749fd6b37aSBrian Norris 				this->bbt_td = &bbt_main_no_oob_descr;
13759fd6b37aSBrian Norris 				this->bbt_md = &bbt_mirror_no_oob_descr;
13767cba7b14SSebastian Andrzej Siewior 			} else {
13771da177e4SLinus Torvalds 				this->bbt_td = &bbt_main_descr;
13781da177e4SLinus Torvalds 				this->bbt_md = &bbt_mirror_descr;
13791da177e4SLinus Torvalds 			}
13807cba7b14SSebastian Andrzej Siewior 		}
13811da177e4SLinus Torvalds 	} else {
13821da177e4SLinus Torvalds 		this->bbt_td = NULL;
13831da177e4SLinus Torvalds 		this->bbt_md = NULL;
1384a2f812dfSBrian Norris 	}
1385a2f812dfSBrian Norris 
1386abb9cf78SBrian Norris 	if (!this->badblock_pattern) {
1387abb9cf78SBrian Norris 		ret = nand_create_badblock_pattern(this);
1388abb9cf78SBrian Norris 		if (ret)
1389abb9cf78SBrian Norris 			return ret;
1390abb9cf78SBrian Norris 	}
1391a2f812dfSBrian Norris 
13920813621bSBoris Brezillon 	return nand_scan_bbt(this, this->badblock_pattern);
13931da177e4SLinus Torvalds }
139444b07b92SBoris Brezillon EXPORT_SYMBOL(nand_create_bbt);
13951da177e4SLinus Torvalds 
13961da177e4SLinus Torvalds /**
13978471bb73SEzequiel Garcia  * nand_isreserved_bbt - [NAND Interface] Check if a block is reserved
13985740d4c4SBoris Brezillon  * @this: NAND chip object
13998471bb73SEzequiel Garcia  * @offs: offset in the device
14008471bb73SEzequiel Garcia  */
14015740d4c4SBoris Brezillon int nand_isreserved_bbt(struct nand_chip *this, loff_t offs)
14028471bb73SEzequiel Garcia {
14038471bb73SEzequiel Garcia 	int block;
14048471bb73SEzequiel Garcia 
14058471bb73SEzequiel Garcia 	block = (int)(offs >> this->bbt_erase_shift);
14068471bb73SEzequiel Garcia 	return bbt_get_entry(this, block) == BBT_BLOCK_RESERVED;
14078471bb73SEzequiel Garcia }
14088471bb73SEzequiel Garcia 
14098471bb73SEzequiel Garcia /**
14101da177e4SLinus Torvalds  * nand_isbad_bbt - [NAND Interface] Check if a block is bad
14115740d4c4SBoris Brezillon  * @this: NAND chip object
14121da177e4SLinus Torvalds  * @offs: offset in the device
14131da177e4SLinus Torvalds  * @allowbbt: allow access to bad block table region
14141da177e4SLinus Torvalds  */
14155740d4c4SBoris Brezillon int nand_isbad_bbt(struct nand_chip *this, loff_t offs, int allowbbt)
14161da177e4SLinus Torvalds {
141739dbb029SBrian Norris 	int block, res;
14181da177e4SLinus Torvalds 
1419b4d20d60SBrian Norris 	block = (int)(offs >> this->bbt_erase_shift);
1420b4d20d60SBrian Norris 	res = bbt_get_entry(this, block);
14211da177e4SLinus Torvalds 
14222ac63d90SRafał Miłecki 	pr_debug("nand_isbad_bbt(): bbt info for offs 0x%08x: (block %d) 0x%02x\n",
1423b4d20d60SBrian Norris 		 (unsigned int)offs, block, res);
14241da177e4SLinus Torvalds 
142539dbb029SBrian Norris 	switch (res) {
1426771c568bSBrian Norris 	case BBT_BLOCK_GOOD:
1427e0c7d767SDavid Woodhouse 		return 0;
1428771c568bSBrian Norris 	case BBT_BLOCK_WORN:
1429e0c7d767SDavid Woodhouse 		return 1;
1430771c568bSBrian Norris 	case BBT_BLOCK_RESERVED:
1431e0c7d767SDavid Woodhouse 		return allowbbt ? 0 : 1;
14321da177e4SLinus Torvalds 	}
14331da177e4SLinus Torvalds 	return 1;
14341da177e4SLinus Torvalds }
14351da177e4SLinus Torvalds 
1436b32843b7SBrian Norris /**
1437b32843b7SBrian Norris  * nand_markbad_bbt - [NAND Interface] Mark a block bad in the BBT
14385740d4c4SBoris Brezillon  * @this: NAND chip object
1439b32843b7SBrian Norris  * @offs: offset of the bad block
1440b32843b7SBrian Norris  */
14415740d4c4SBoris Brezillon int nand_markbad_bbt(struct nand_chip *this, loff_t offs)
1442b32843b7SBrian Norris {
1443b32843b7SBrian Norris 	int block, ret = 0;
1444b32843b7SBrian Norris 
1445b32843b7SBrian Norris 	block = (int)(offs >> this->bbt_erase_shift);
1446b32843b7SBrian Norris 
1447b32843b7SBrian Norris 	/* Mark bad block in memory */
1448b32843b7SBrian Norris 	bbt_mark_entry(this, block, BBT_BLOCK_WORN);
1449b32843b7SBrian Norris 
1450b32843b7SBrian Norris 	/* Update flash-based bad block table */
1451b32843b7SBrian Norris 	if (this->bbt_options & NAND_BBT_USE_FLASH)
14520813621bSBoris Brezillon 		ret = nand_update_bbt(this, offs);
1453b32843b7SBrian Norris 
1454b32843b7SBrian Norris 	return ret;
1455b32843b7SBrian Norris }
1456