Linux Kernel  3.7.1
 All Data Structures Namespaces Files Functions Variables Typedefs Enumerations Enumerator Macros Groups Pages
onenand_bbt.c
Go to the documentation of this file.
1 /*
2  * linux/drivers/mtd/onenand/onenand_bbt.c
3  *
4  * Bad Block Table support for the OneNAND driver
5  *
6  * Copyright(c) 2005 Samsung Electronics
7  * Kyungmin Park <[email protected]>
8  *
9  * Derived from nand_bbt.c
10  *
11  * TODO:
12  * Split BBT core and chip specific BBT.
13  */
14 
15 #include <linux/slab.h>
16 #include <linux/mtd/mtd.h>
17 #include <linux/mtd/onenand.h>
18 #include <linux/export.h>
19 
33 static int check_short_pattern(uint8_t *buf, int len, int paglen, struct nand_bbt_descr *td)
34 {
35  int i;
36  uint8_t *p = buf;
37 
38  /* Compare the pattern */
39  for (i = 0; i < td->len; i++) {
40  if (p[i] != td->pattern[i])
41  return -1;
42  }
43  return 0;
44 }
45 
57 static int create_bbt(struct mtd_info *mtd, uint8_t *buf, struct nand_bbt_descr *bd, int chip)
58 {
59  struct onenand_chip *this = mtd->priv;
60  struct bbm_info *bbm = this->bbm;
61  int i, j, numblocks, len, scanlen;
62  int startblock;
63  loff_t from;
64  size_t readlen, ooblen;
65  struct mtd_oob_ops ops;
66  int rgn;
67 
68  printk(KERN_INFO "Scanning device for bad blocks\n");
69 
70  len = 2;
71 
72  /* We need only read few bytes from the OOB area */
73  scanlen = ooblen = 0;
74  readlen = bd->len;
75 
76  /* chip == -1 case only */
77  /* Note that numblocks is 2 * (real numblocks) here;
78  * see i += 2 below as it makses shifting and masking less painful
79  */
80  numblocks = this->chipsize >> (bbm->bbt_erase_shift - 1);
81  startblock = 0;
82  from = 0;
83 
84  ops.mode = MTD_OPS_PLACE_OOB;
85  ops.ooblen = readlen;
86  ops.oobbuf = buf;
87  ops.len = ops.ooboffs = ops.retlen = ops.oobretlen = 0;
88 
89  for (i = startblock; i < numblocks; ) {
90  int ret;
91 
92  for (j = 0; j < len; j++) {
93  /* No need to read pages fully,
94  * just read required OOB bytes */
95  ret = onenand_bbt_read_oob(mtd,
96  from + j * this->writesize + bd->offs, &ops);
97 
98  /* If it is a initial bad block, just ignore it */
100  return -EIO;
101 
102  if (ret || check_short_pattern(&buf[j * scanlen],
103  scanlen, this->writesize, bd)) {
104  bbm->bbt[i >> 3] |= 0x03 << (i & 0x6);
105  printk(KERN_INFO "OneNAND eraseblock %d is an "
106  "initial bad block\n", i >> 1);
107  mtd->ecc_stats.badblocks++;
108  break;
109  }
110  }
111  i += 2;
112 
113  if (FLEXONENAND(this)) {
114  rgn = flexonenand_region(mtd, from);
115  from += mtd->eraseregions[rgn].erasesize;
116  } else
117  from += (1 << bbm->bbt_erase_shift);
118  }
119 
120  return 0;
121 }
122 
123 
132 static inline int onenand_memory_bbt (struct mtd_info *mtd, struct nand_bbt_descr *bd)
133 {
134  struct onenand_chip *this = mtd->priv;
135 
136  bd->options &= ~NAND_BBT_SCANEMPTY;
137  return create_bbt(mtd, this->page_buf, bd, -1);
138 }
139 
146 static int onenand_isbad_bbt(struct mtd_info *mtd, loff_t offs, int allowbbt)
147 {
148  struct onenand_chip *this = mtd->priv;
149  struct bbm_info *bbm = this->bbm;
150  int block;
151  uint8_t res;
152 
153  /* Get block number * 2 */
154  block = (int) (onenand_block(this, offs) << 1);
155  res = (bbm->bbt[block >> 3] >> (block & 0x06)) & 0x03;
156 
157  pr_debug("onenand_isbad_bbt: bbt info for offs 0x%08x: (block %d) 0x%02x\n",
158  (unsigned int) offs, block >> 1, res);
159 
160  switch ((int) res) {
161  case 0x00: return 0;
162  case 0x01: return 1;
163  case 0x02: return allowbbt ? 0 : 1;
164  }
165 
166  return 1;
167 }
168 
183 int onenand_scan_bbt(struct mtd_info *mtd, struct nand_bbt_descr *bd)
184 {
185  struct onenand_chip *this = mtd->priv;
186  struct bbm_info *bbm = this->bbm;
187  int len, ret = 0;
188 
189  len = this->chipsize >> (this->erase_shift + 2);
190  /* Allocate memory (2bit per block) and clear the memory bad block table */
191  bbm->bbt = kzalloc(len, GFP_KERNEL);
192  if (!bbm->bbt)
193  return -ENOMEM;
194 
195  /* Set the bad block position */
197 
198  /* Set erase shift */
199  bbm->bbt_erase_shift = this->erase_shift;
200 
201  if (!bbm->isbad_bbt)
202  bbm->isbad_bbt = onenand_isbad_bbt;
203 
204  /* Scan the device to build a memory based bad block table */
205  if ((ret = onenand_memory_bbt(mtd, bd))) {
206  printk(KERN_ERR "onenand_scan_bbt: Can't scan flash and build the RAM-based BBT\n");
207  kfree(bbm->bbt);
208  bbm->bbt = NULL;
209  }
210 
211  return ret;
212 }
213 
214 /*
215  * Define some generic bad / good block scan pattern which are used
216  * while scanning a device for factory marked good / bad blocks.
217  */
218 static uint8_t scan_ff_pattern[] = { 0xff, 0xff };
219 
220 static struct nand_bbt_descr largepage_memorybased = {
221  .options = 0,
222  .offs = 0,
223  .len = 2,
224  .pattern = scan_ff_pattern,
225 };
226 
235 {
236  struct onenand_chip *this = mtd->priv;
237  struct bbm_info *bbm;
238 
239  this->bbm = kzalloc(sizeof(struct bbm_info), GFP_KERNEL);
240  if (!this->bbm)
241  return -ENOMEM;
242 
243  bbm = this->bbm;
244 
245  /* 1KB page has same configuration as 2KB page */
246  if (!bbm->badblock_pattern)
247  bbm->badblock_pattern = &largepage_memorybased;
248 
249  return onenand_scan_bbt(mtd, bbm->badblock_pattern);
250 }
251