aboutsummaryrefslogtreecommitdiffstats
path: root/drivers
diff options
context:
space:
mode:
authorBrian Norris <norris@broadcom.com>2010-07-15 15:15:44 -0400
committerDavid Woodhouse <David.Woodhouse@intel.com>2010-08-02 04:09:06 -0400
commit58373ff0afff4cc8ac40608872995f4d87eb72ec (patch)
treecb697da3cc49ab4df73ad6427a3c9df8f1cab4b3 /drivers
parentc7b28e25cb9beb943aead770ff14551b55fa8c79 (diff)
mtd: nand: more BB Detection refactoring and dynamic scan options
This is a revision to PATCH 2/2 that I sent. Link: http://lists.infradead.org/pipermail/linux-mtd/2010-July/030911.html Added new flag for scanning of both bytes 1 and 6 of the OOB for a BB marker (instead of simply one or the other). The "check_pattern" and "check_short_pattern" functions were updated to include support for scanning the two different locations in the OOB. In order to handle increases in variety of necessary scanning patterns, I implemented dynamic memory allocation of nand_bbt_descr structs in new function 'nand_create_default_bbt_descr()'. This replaces some increasingly-unwieldy, statically-declared descriptors. It can replace several more (e.g. "flashbased" structs). However, I do not test the flashbased options personally. How this was tested: I referenced 30+ data sheets (covering 100+ parts), and I tested a selection of 10 different chips to varying degrees. Particularly, I tested the creation of bad-block descriptors and basic BB scanning on three parts: ST NAND04GW3B2D, 2K page ST NAND128W3A, 512B page Samsung K9F1G08U0A, 2K page To test these, I wrote some fake bad block markers to the flash (in OOB bytes 1, 6, and elsewhere) to see if the scanning routine would detect them properly. However, this method was somewhat limited because the driver I am using has some bugs in its OOB write functionality. Signed-off-by: Brian Norris <norris@broadcom.com> Signed-off-by: Artem Bityutskiy <Artem.Bityutskiy@nokia.com> Signed-off-by: David Woodhouse <David.Woodhouse@intel.com>
Diffstat (limited to 'drivers')
-rw-r--r--drivers/mtd/nand/nand_base.c14
-rw-r--r--drivers/mtd/nand/nand_bbt.c127
2 files changed, 86 insertions, 55 deletions
diff --git a/drivers/mtd/nand/nand_base.c b/drivers/mtd/nand/nand_base.c
index bd697909db53..c2901bd126f9 100644
--- a/drivers/mtd/nand/nand_base.c
+++ b/drivers/mtd/nand/nand_base.c
@@ -2963,6 +2963,15 @@ static struct nand_flash_dev *nand_get_flash_type(struct mtd_info *mtd,
2963 *maf_id == NAND_MFR_MICRON)) 2963 *maf_id == NAND_MFR_MICRON))
2964 chip->options |= NAND_BBT_SCAN2NDPAGE; 2964 chip->options |= NAND_BBT_SCAN2NDPAGE;
2965 2965
2966 /*
2967 * Numonyx/ST 2K pages, x8 bus use BOTH byte 1 and 6
2968 */
2969 if (!(busw & NAND_BUSWIDTH_16) &&
2970 *maf_id == NAND_MFR_STMICRO &&
2971 mtd->writesize == 2048) {
2972 chip->options |= NAND_BBT_SCANBYTE1AND6;
2973 chip->badblockpos = 0;
2974 }
2966 2975
2967 /* Check for AND chips with 4 page planes */ 2976 /* Check for AND chips with 4 page planes */
2968 if (chip->options & NAND_4PAGE_ARRAY) 2977 if (chip->options & NAND_4PAGE_ARRAY)
@@ -3322,6 +3331,11 @@ void nand_release(struct mtd_info *mtd)
3322 kfree(chip->bbt); 3331 kfree(chip->bbt);
3323 if (!(chip->options & NAND_OWN_BUFFERS)) 3332 if (!(chip->options & NAND_OWN_BUFFERS))
3324 kfree(chip->buffers); 3333 kfree(chip->buffers);
3334
3335 /* Free bad block descriptor memory */
3336 if (chip->badblock_pattern && chip->badblock_pattern->options
3337 & NAND_BBT_DYNAMICSTRUCT)
3338 kfree(chip->badblock_pattern);
3325} 3339}
3326 3340
3327EXPORT_SYMBOL_GPL(nand_lock); 3341EXPORT_SYMBOL_GPL(nand_lock);
diff --git a/drivers/mtd/nand/nand_bbt.c b/drivers/mtd/nand/nand_bbt.c
index ec1700eaf198..469de17107e5 100644
--- a/drivers/mtd/nand/nand_bbt.c
+++ b/drivers/mtd/nand/nand_bbt.c
@@ -93,6 +93,28 @@ static int check_pattern(uint8_t *buf, int len, int paglen, struct nand_bbt_desc
93 return -1; 93 return -1;
94 } 94 }
95 95
96 /* Check both positions 1 and 6 for pattern? */
97 if (td->options & NAND_BBT_SCANBYTE1AND6) {
98 if (td->options & NAND_BBT_SCANEMPTY) {
99 p += td->len;
100 end += NAND_SMALL_BADBLOCK_POS - td->offs;
101 /* Check region between positions 1 and 6 */
102 for (i = 0; i < NAND_SMALL_BADBLOCK_POS - td->offs - td->len;
103 i++) {
104 if (*p++ != 0xff)
105 return -1;
106 }
107 }
108 else {
109 p += NAND_SMALL_BADBLOCK_POS - td->offs;
110 }
111 /* Compare the pattern */
112 for (i = 0; i < td->len; i++) {
113 if (p[i] != td->pattern[i])
114 return -1;
115 }
116 }
117
96 if (td->options & NAND_BBT_SCANEMPTY) { 118 if (td->options & NAND_BBT_SCANEMPTY) {
97 p += td->len; 119 p += td->len;
98 end += td->len; 120 end += td->len;
@@ -124,6 +146,13 @@ static int check_short_pattern(uint8_t *buf, struct nand_bbt_descr *td)
124 if (p[td->offs + i] != td->pattern[i]) 146 if (p[td->offs + i] != td->pattern[i])
125 return -1; 147 return -1;
126 } 148 }
149 /* Need to check location 1 AND 6? */
150 if (td->options & NAND_BBT_SCANBYTE1AND6) {
151 for (i = 0; i < td->len; i++) {
152 if (p[NAND_SMALL_BADBLOCK_POS + i] != td->pattern[i])
153 return -1;
154 }
155 }
127 return 0; 156 return 0;
128} 157}
129 158
@@ -397,12 +426,10 @@ static int create_bbt(struct mtd_info *mtd, uint8_t *buf,
397 426
398 if (bd->options & NAND_BBT_SCANALLPAGES) 427 if (bd->options & NAND_BBT_SCANALLPAGES)
399 len = 1 << (this->bbt_erase_shift - this->page_shift); 428 len = 1 << (this->bbt_erase_shift - this->page_shift);
400 else { 429 else if (bd->options & NAND_BBT_SCAN2NDPAGE)
401 if (bd->options & NAND_BBT_SCAN2NDPAGE) 430 len = 2;
402 len = 2; 431 else
403 else 432 len = 1;
404 len = 1;
405 }
406 433
407 if (!(bd->options & NAND_BBT_SCANEMPTY)) { 434 if (!(bd->options & NAND_BBT_SCANEMPTY)) {
408 /* We need only read few bytes from the OOB area */ 435 /* We need only read few bytes from the OOB area */
@@ -1092,41 +1119,6 @@ int nand_update_bbt(struct mtd_info *mtd, loff_t offs)
1092 * while scanning a device for factory marked good / bad blocks. */ 1119 * while scanning a device for factory marked good / bad blocks. */
1093static uint8_t scan_ff_pattern[] = { 0xff, 0xff }; 1120static uint8_t scan_ff_pattern[] = { 0xff, 0xff };
1094 1121
1095static struct nand_bbt_descr smallpage_memorybased = {
1096 .options = 0,
1097 .offs = NAND_SMALL_BADBLOCK_POS,
1098 .len = 1,
1099 .pattern = scan_ff_pattern
1100};
1101
1102static struct nand_bbt_descr smallpage_scan2nd_memorybased = {
1103 .options = NAND_BBT_SCAN2NDPAGE,
1104 .offs = NAND_SMALL_BADBLOCK_POS,
1105 .len = 2,
1106 .pattern = scan_ff_pattern
1107};
1108
1109static struct nand_bbt_descr largepage_memorybased = {
1110 .options = 0,
1111 .offs = NAND_LARGE_BADBLOCK_POS,
1112 .len = 1,
1113 .pattern = scan_ff_pattern
1114};
1115
1116static struct nand_bbt_descr largepage_scan2nd_memorybased = {
1117 .options = NAND_BBT_SCAN2NDPAGE,
1118 .offs = NAND_LARGE_BADBLOCK_POS,
1119 .len = 2,
1120 .pattern = scan_ff_pattern
1121};
1122
1123static struct nand_bbt_descr lastpage_memorybased = {
1124 .options = NAND_BBT_SCANLASTPAGE,
1125 .offs = 0,
1126 .len = 1,
1127 .pattern = scan_ff_pattern
1128};
1129
1130static struct nand_bbt_descr smallpage_flashbased = { 1122static struct nand_bbt_descr smallpage_flashbased = {
1131 .options = NAND_BBT_SCAN2NDPAGE, 1123 .options = NAND_BBT_SCAN2NDPAGE,
1132 .offs = NAND_SMALL_BADBLOCK_POS, 1124 .offs = NAND_SMALL_BADBLOCK_POS,
@@ -1175,6 +1167,43 @@ static struct nand_bbt_descr bbt_mirror_descr = {
1175 .pattern = mirror_pattern 1167 .pattern = mirror_pattern
1176}; 1168};
1177 1169
1170#define BBT_SCAN_OPTIONS (NAND_BBT_SCANLASTPAGE | NAND_BBT_SCAN2NDPAGE | \
1171 NAND_BBT_SCANBYTE1AND6)
1172/**
1173 * nand_create_default_bbt_descr - [Internal] Creates a BBT descriptor structure
1174 * @this: NAND chip to create descriptor for
1175 *
1176 * This function allocates and initializes a nand_bbt_descr for BBM detection
1177 * based on the properties of "this". The new descriptor is stored in
1178 * this->badblock_pattern. Thus, this->badblock_pattern should be NULL when
1179 * passed to this function.
1180 *
1181 * TODO: Handle other flags, replace other static structs
1182 * (e.g. handle NAND_BBT_FLASH for flash-based BBT,
1183 * replace smallpage_flashbased)
1184 *
1185 */
1186static int nand_create_default_bbt_descr(struct nand_chip *this)
1187{
1188 struct nand_bbt_descr *bd;
1189 if (this->badblock_pattern) {
1190 printk(KERN_WARNING "BBT descr already allocated; not replacing.\n");
1191 return -EINVAL;
1192 }
1193 bd = kzalloc(sizeof(*bd), GFP_KERNEL);
1194 if (!bd) {
1195 printk(KERN_ERR "nand_create_default_bbt_descr: Out of memory\n");
1196 return -ENOMEM;
1197 }
1198 bd->options = this->options & BBT_SCAN_OPTIONS;
1199 bd->offs = this->badblockpos;
1200 bd->len = (this->options & NAND_BUSWIDTH_16) ? 2 : 1;
1201 bd->pattern = scan_ff_pattern;
1202 bd->options |= NAND_BBT_DYNAMICSTRUCT;
1203 this->badblock_pattern = bd;
1204 return 0;
1205}
1206
1178/** 1207/**
1179 * nand_default_bbt - [NAND Interface] Select a default bad block table for the device 1208 * nand_default_bbt - [NAND Interface] Select a default bad block table for the device
1180 * @mtd: MTD device structure 1209 * @mtd: MTD device structure
@@ -1217,20 +1246,8 @@ int nand_default_bbt(struct mtd_info *mtd)
1217 } else { 1246 } else {
1218 this->bbt_td = NULL; 1247 this->bbt_td = NULL;
1219 this->bbt_md = NULL; 1248 this->bbt_md = NULL;
1220 if (!this->badblock_pattern) { 1249 if (!this->badblock_pattern)
1221 if (this->options & NAND_BBT_SCANLASTPAGE) 1250 nand_create_default_bbt_descr(this);
1222 this->badblock_pattern = &lastpage_memorybased;
1223 else if (this->options & NAND_BBT_SCAN2NDPAGE)
1224 this->badblock_pattern = this->badblockpos ==
1225 NAND_SMALL_BADBLOCK_POS ?
1226 &smallpage_scan2nd_memorybased :
1227 &largepage_scan2nd_memorybased;
1228 else
1229 this->badblock_pattern = this->badblockpos ==
1230 NAND_SMALL_BADBLOCK_POS ?
1231 &smallpage_memorybased :
1232 &largepage_memorybased;
1233 }
1234 } 1251 }
1235 return nand_scan_bbt(mtd, this->badblock_pattern); 1252 return nand_scan_bbt(mtd, this->badblock_pattern);
1236} 1253}