diff options
Diffstat (limited to 'drivers/mtd/nand')
-rw-r--r-- | drivers/mtd/nand/nand_bbt.c | 52 |
1 files changed, 38 insertions, 14 deletions
diff --git a/drivers/mtd/nand/nand_bbt.c b/drivers/mtd/nand/nand_bbt.c index 9a1949751c1f..5ff6eba8bec6 100644 --- a/drivers/mtd/nand/nand_bbt.c +++ b/drivers/mtd/nand/nand_bbt.c | |||
@@ -6,7 +6,7 @@ | |||
6 | * | 6 | * |
7 | * Copyright (C) 2004 Thomas Gleixner (tglx@linutronix.de) | 7 | * Copyright (C) 2004 Thomas Gleixner (tglx@linutronix.de) |
8 | * | 8 | * |
9 | * $Id: nand_bbt.c,v 1.28 2004/11/13 10:19:09 gleixner Exp $ | 9 | * $Id: nand_bbt.c,v 1.30 2005/02/11 10:14:12 dedekind Exp $ |
10 | * | 10 | * |
11 | * This program is free software; you can redistribute it and/or modify | 11 | * This program is free software; you can redistribute it and/or modify |
12 | * it under the terms of the GNU General Public License version 2 as | 12 | * it under the terms of the GNU General Public License version 2 as |
@@ -252,10 +252,10 @@ static int read_abs_bbts (struct mtd_info *mtd, uint8_t *buf, struct nand_bbt_de | |||
252 | * Create a bad block table by scanning the device | 252 | * Create a bad block table by scanning the device |
253 | * for the given good/bad block identify pattern | 253 | * for the given good/bad block identify pattern |
254 | */ | 254 | */ |
255 | static void create_bbt (struct mtd_info *mtd, uint8_t *buf, struct nand_bbt_descr *bd, int chip) | 255 | static int create_bbt (struct mtd_info *mtd, uint8_t *buf, struct nand_bbt_descr *bd, int chip) |
256 | { | 256 | { |
257 | struct nand_chip *this = mtd->priv; | 257 | struct nand_chip *this = mtd->priv; |
258 | int i, j, numblocks, len, scanlen; | 258 | int i, j, numblocks, len, scanlen, pagelen; |
259 | int startblock; | 259 | int startblock; |
260 | loff_t from; | 260 | loff_t from; |
261 | size_t readlen, ooblen; | 261 | size_t readlen, ooblen; |
@@ -270,9 +270,18 @@ static void create_bbt (struct mtd_info *mtd, uint8_t *buf, struct nand_bbt_desc | |||
270 | else | 270 | else |
271 | len = 1; | 271 | len = 1; |
272 | } | 272 | } |
273 | scanlen = mtd->oobblock + mtd->oobsize; | 273 | |
274 | readlen = len * mtd->oobblock; | 274 | if (bd->options == 0) { |
275 | ooblen = len * mtd->oobsize; | 275 | /* Memory-based BBT. We may read only needed bytes from the OOB area to |
276 | * test if block is bad, no need to read the whole page content. */ | ||
277 | scanlen = ooblen = pagelen = 0; | ||
278 | readlen = bd->len; | ||
279 | } else { | ||
280 | scanlen = mtd->oobblock + mtd->oobsize; | ||
281 | readlen = len * mtd->oobblock; | ||
282 | ooblen = len * mtd->oobsize; | ||
283 | pagelen = mtd->oobblock; | ||
284 | } | ||
276 | 285 | ||
277 | if (chip == -1) { | 286 | if (chip == -1) { |
278 | /* Note that numblocks is 2 * (real numblocks) here, see i+=2 below as it | 287 | /* Note that numblocks is 2 * (real numblocks) here, see i+=2 below as it |
@@ -284,7 +293,7 @@ static void create_bbt (struct mtd_info *mtd, uint8_t *buf, struct nand_bbt_desc | |||
284 | if (chip >= this->numchips) { | 293 | if (chip >= this->numchips) { |
285 | printk (KERN_WARNING "create_bbt(): chipnr (%d) > available chips (%d)\n", | 294 | printk (KERN_WARNING "create_bbt(): chipnr (%d) > available chips (%d)\n", |
286 | chip + 1, this->numchips); | 295 | chip + 1, this->numchips); |
287 | return; | 296 | return -EINVAL; |
288 | } | 297 | } |
289 | numblocks = this->chipsize >> (this->bbt_erase_shift - 1); | 298 | numblocks = this->chipsize >> (this->bbt_erase_shift - 1); |
290 | startblock = chip * numblocks; | 299 | startblock = chip * numblocks; |
@@ -293,9 +302,18 @@ static void create_bbt (struct mtd_info *mtd, uint8_t *buf, struct nand_bbt_desc | |||
293 | } | 302 | } |
294 | 303 | ||
295 | for (i = startblock; i < numblocks;) { | 304 | for (i = startblock; i < numblocks;) { |
296 | nand_read_raw (mtd, buf, from, readlen, ooblen); | 305 | int ret; |
306 | |||
307 | if (bd->options == 0) { | ||
308 | size_t retlen; | ||
309 | if ((ret = mtd->read_oob(mtd, from + bd->offs, bd->len, &retlen, &buf[bd->offs]))) | ||
310 | return ret; | ||
311 | } else { | ||
312 | if ((ret = nand_read_raw (mtd, buf, from, readlen, ooblen))) | ||
313 | return ret; | ||
314 | } | ||
297 | for (j = 0; j < len; j++) { | 315 | for (j = 0; j < len; j++) { |
298 | if (check_pattern (&buf[j * scanlen], scanlen, mtd->oobblock, bd)) { | 316 | if (check_pattern (&buf[j * scanlen], scanlen, pagelen, bd)) { |
299 | this->bbt[i >> 3] |= 0x03 << (i & 0x6); | 317 | this->bbt[i >> 3] |= 0x03 << (i & 0x6); |
300 | printk (KERN_WARNING "Bad eraseblock %d at 0x%08x\n", | 318 | printk (KERN_WARNING "Bad eraseblock %d at 0x%08x\n", |
301 | i >> 1, (unsigned int) from); | 319 | i >> 1, (unsigned int) from); |
@@ -305,6 +323,7 @@ static void create_bbt (struct mtd_info *mtd, uint8_t *buf, struct nand_bbt_desc | |||
305 | i += 2; | 323 | i += 2; |
306 | from += (1 << this->bbt_erase_shift); | 324 | from += (1 << this->bbt_erase_shift); |
307 | } | 325 | } |
326 | return 0; | ||
308 | } | 327 | } |
309 | 328 | ||
310 | /** | 329 | /** |
@@ -595,8 +614,7 @@ static int nand_memory_bbt (struct mtd_info *mtd, struct nand_bbt_descr *bd) | |||
595 | 614 | ||
596 | /* Ensure that we only scan for the pattern and nothing else */ | 615 | /* Ensure that we only scan for the pattern and nothing else */ |
597 | bd->options = 0; | 616 | bd->options = 0; |
598 | create_bbt (mtd, this->data_buf, bd, -1); | 617 | return create_bbt (mtd, this->data_buf, bd, -1); |
599 | return 0; | ||
600 | } | 618 | } |
601 | 619 | ||
602 | /** | 620 | /** |
@@ -808,8 +826,14 @@ int nand_scan_bbt (struct mtd_info *mtd, struct nand_bbt_descr *bd) | |||
808 | /* If no primary table decriptor is given, scan the device | 826 | /* If no primary table decriptor is given, scan the device |
809 | * to build a memory based bad block table | 827 | * to build a memory based bad block table |
810 | */ | 828 | */ |
811 | if (!td) | 829 | if (!td) { |
812 | return nand_memory_bbt(mtd, bd); | 830 | if ((res = nand_memory_bbt(mtd, bd))) { |
831 | printk (KERN_ERR "nand_bbt: Can't scan flash and build the RAM-based BBT\n"); | ||
832 | kfree (this->bbt); | ||
833 | this->bbt = NULL; | ||
834 | } | ||
835 | return res; | ||
836 | } | ||
813 | 837 | ||
814 | /* Allocate a temporary buffer for one eraseblock incl. oob */ | 838 | /* Allocate a temporary buffer for one eraseblock incl. oob */ |
815 | len = (1 << this->bbt_erase_shift); | 839 | len = (1 << this->bbt_erase_shift); |
@@ -1042,7 +1066,7 @@ int nand_isbad_bbt (struct mtd_info *mtd, loff_t offs, int allowbbt) | |||
1042 | res = (this->bbt[block >> 3] >> (block & 0x06)) & 0x03; | 1066 | res = (this->bbt[block >> 3] >> (block & 0x06)) & 0x03; |
1043 | 1067 | ||
1044 | DEBUG (MTD_DEBUG_LEVEL2, "nand_isbad_bbt(): bbt info for offs 0x%08x: (block %d) 0x%02x\n", | 1068 | DEBUG (MTD_DEBUG_LEVEL2, "nand_isbad_bbt(): bbt info for offs 0x%08x: (block %d) 0x%02x\n", |
1045 | (unsigned int)offs, res, block >> 1); | 1069 | (unsigned int)offs, block >> 1, res); |
1046 | 1070 | ||
1047 | switch ((int)res) { | 1071 | switch ((int)res) { |
1048 | case 0x00: return 0; | 1072 | case 0x00: return 0; |