diff options
author | Brian Norris <computersforpeace@gmail.com> | 2013-07-30 20:52:55 -0400 |
---|---|---|
committer | Nitin Garg <nitin.garg@freescale.com> | 2014-04-16 09:06:00 -0400 |
commit | b25c1205dee1c63dc49d0d9c6788fb64a3c196ca (patch) | |
tree | 18e2385550bf658415e91a9081d70914b8156a15 | |
parent | 6c660d1895228d8505fd64f4bdf80e7b299ec763 (diff) |
mtd: nand: add accessors, macros for in-memory BBT
There is an abundance of magic numbers and complicated shifting/masking
logic in the in-memory BBT code which makes the code unnecessary complex
and hard to read.
This patch adds macros to represent the 00b, 01b, 10b, and 11b
memory-BBT magic numbers, as well as two accessor functions for reading
and marking the memory-BBT bitfield for a given block.
Signed-off-by: Brian Norris <computersforpeace@gmail.com>
Signed-off-by: Artem Bityutskiy <artem.bityutskiy@linux.intel.com>
Signed-off-by: David Woodhouse <David.Woodhouse@intel.com>
Signed-off-by: Huang Shijie <b32955@freescale.com>
-rw-r--r-- | drivers/mtd/nand/nand_bbt.c | 70 |
1 files changed, 48 insertions, 22 deletions
diff --git a/drivers/mtd/nand/nand_bbt.c b/drivers/mtd/nand/nand_bbt.c index 185177ff8a23..3b6aff9b26c0 100644 --- a/drivers/mtd/nand/nand_bbt.c +++ b/drivers/mtd/nand/nand_bbt.c | |||
@@ -71,6 +71,28 @@ | |||
71 | #include <linux/export.h> | 71 | #include <linux/export.h> |
72 | #include <linux/string.h> | 72 | #include <linux/string.h> |
73 | 73 | ||
74 | #define BBT_BLOCK_GOOD 0x00 | ||
75 | #define BBT_BLOCK_WORN 0x01 | ||
76 | #define BBT_BLOCK_RESERVED 0x02 | ||
77 | #define BBT_BLOCK_FACTORY_BAD 0x03 | ||
78 | |||
79 | #define BBT_ENTRY_MASK 0x03 | ||
80 | #define BBT_ENTRY_SHIFT 2 | ||
81 | |||
82 | static inline uint8_t bbt_get_entry(struct nand_chip *chip, int block) | ||
83 | { | ||
84 | uint8_t entry = chip->bbt[block >> BBT_ENTRY_SHIFT]; | ||
85 | entry >>= (block & BBT_ENTRY_MASK) * 2; | ||
86 | return entry & BBT_ENTRY_MASK; | ||
87 | } | ||
88 | |||
89 | static inline void bbt_mark_entry(struct nand_chip *chip, int block, | ||
90 | uint8_t mark) | ||
91 | { | ||
92 | uint8_t msk = (mark & BBT_ENTRY_MASK) << ((block & BBT_ENTRY_MASK) * 2); | ||
93 | chip->bbt[block >> BBT_ENTRY_SHIFT] |= msk; | ||
94 | } | ||
95 | |||
74 | static int check_pattern_no_oob(uint8_t *buf, struct nand_bbt_descr *td) | 96 | static int check_pattern_no_oob(uint8_t *buf, struct nand_bbt_descr *td) |
75 | { | 97 | { |
76 | if (memcmp(buf, td->pattern, td->len)) | 98 | if (memcmp(buf, td->pattern, td->len)) |
@@ -216,7 +238,9 @@ static int read_bbt(struct mtd_info *mtd, uint8_t *buf, int page, int num, | |||
216 | if (reserved_block_code && (tmp == reserved_block_code)) { | 238 | if (reserved_block_code && (tmp == reserved_block_code)) { |
217 | pr_info("nand_read_bbt: reserved block at 0x%012llx\n", | 239 | pr_info("nand_read_bbt: reserved block at 0x%012llx\n", |
218 | (loff_t)((offs << 2) + (act >> 1)) << this->bbt_erase_shift); | 240 | (loff_t)((offs << 2) + (act >> 1)) << this->bbt_erase_shift); |
219 | this->bbt[offs + (act >> 3)] |= 0x2 << (act & 0x06); | 241 | bbt_mark_entry(this, (offs << 2) + |
242 | (act >> 1), | ||
243 | BBT_BLOCK_RESERVED); | ||
220 | mtd->ecc_stats.bbtblocks++; | 244 | mtd->ecc_stats.bbtblocks++; |
221 | continue; | 245 | continue; |
222 | } | 246 | } |
@@ -228,9 +252,13 @@ static int read_bbt(struct mtd_info *mtd, uint8_t *buf, int page, int num, | |||
228 | (loff_t)((offs << 2) + (act >> 1)) << this->bbt_erase_shift); | 252 | (loff_t)((offs << 2) + (act >> 1)) << this->bbt_erase_shift); |
229 | /* Factory marked bad or worn out? */ | 253 | /* Factory marked bad or worn out? */ |
230 | if (tmp == 0) | 254 | if (tmp == 0) |
231 | this->bbt[offs + (act >> 3)] |= 0x3 << (act & 0x06); | 255 | bbt_mark_entry(this, (offs << 2) + |
256 | (act >> 1), | ||
257 | BBT_BLOCK_FACTORY_BAD); | ||
232 | else | 258 | else |
233 | this->bbt[offs + (act >> 3)] |= 0x1 << (act & 0x06); | 259 | bbt_mark_entry(this, (offs << 2) + |
260 | (act >> 1), | ||
261 | BBT_BLOCK_WORN); | ||
234 | mtd->ecc_stats.badblocks++; | 262 | mtd->ecc_stats.badblocks++; |
235 | } | 263 | } |
236 | } | 264 | } |
@@ -526,7 +554,7 @@ static int create_bbt(struct mtd_info *mtd, uint8_t *buf, | |||
526 | return ret; | 554 | return ret; |
527 | 555 | ||
528 | if (ret) { | 556 | if (ret) { |
529 | this->bbt[i >> 3] |= 0x03 << (i & 0x6); | 557 | bbt_mark_entry(this, i >> 1, BBT_BLOCK_FACTORY_BAD); |
530 | pr_warn("Bad eraseblock %d at 0x%012llx\n", | 558 | pr_warn("Bad eraseblock %d at 0x%012llx\n", |
531 | i >> 1, (unsigned long long)from); | 559 | i >> 1, (unsigned long long)from); |
532 | mtd->ecc_stats.badblocks++; | 560 | mtd->ecc_stats.badblocks++; |
@@ -713,10 +741,9 @@ static int write_bbt(struct mtd_info *mtd, uint8_t *buf, | |||
713 | for (i = 0; i < td->maxblocks; i++) { | 741 | for (i = 0; i < td->maxblocks; i++) { |
714 | int block = startblock + dir * i; | 742 | int block = startblock + dir * i; |
715 | /* Check, if the block is bad */ | 743 | /* Check, if the block is bad */ |
716 | switch ((this->bbt[block >> 2] >> | 744 | switch (bbt_get_entry(this, block)) { |
717 | (2 * (block & 0x03))) & 0x03) { | 745 | case BBT_BLOCK_WORN: |
718 | case 0x01: | 746 | case BBT_BLOCK_FACTORY_BAD: |
719 | case 0x03: | ||
720 | continue; | 747 | continue; |
721 | } | 748 | } |
722 | page = block << | 749 | page = block << |
@@ -816,7 +843,7 @@ static int write_bbt(struct mtd_info *mtd, uint8_t *buf, | |||
816 | /* Walk through the memory table */ | 843 | /* Walk through the memory table */ |
817 | for (i = 0; i < numblocks;) { | 844 | for (i = 0; i < numblocks;) { |
818 | uint8_t dat; | 845 | uint8_t dat; |
819 | dat = this->bbt[bbtoffs + (i >> 2)]; | 846 | dat = bbt_get_entry(this, (bbtoffs << 2) + i); |
820 | for (j = 0; j < 4; j++, i++) { | 847 | for (j = 0; j < 4; j++, i++) { |
821 | int sftcnt = (i << (3 - sft)) & sftmsk; | 848 | int sftcnt = (i << (3 - sft)) & sftmsk; |
822 | /* Do not store the reserved bbt blocks! */ | 849 | /* Do not store the reserved bbt blocks! */ |
@@ -1009,7 +1036,7 @@ static void mark_bbt_region(struct mtd_info *mtd, struct nand_bbt_descr *td) | |||
1009 | { | 1036 | { |
1010 | struct nand_chip *this = mtd->priv; | 1037 | struct nand_chip *this = mtd->priv; |
1011 | int i, j, chips, block, nrblocks, update; | 1038 | int i, j, chips, block, nrblocks, update; |
1012 | uint8_t oldval, newval; | 1039 | uint8_t oldval; |
1013 | 1040 | ||
1014 | /* Do we have a bbt per chip? */ | 1041 | /* Do we have a bbt per chip? */ |
1015 | if (td->options & NAND_BBT_PERCHIP) { | 1042 | if (td->options & NAND_BBT_PERCHIP) { |
@@ -1027,10 +1054,10 @@ static void mark_bbt_region(struct mtd_info *mtd, struct nand_bbt_descr *td) | |||
1027 | continue; | 1054 | continue; |
1028 | block = td->pages[i] >> (this->bbt_erase_shift - this->page_shift); | 1055 | block = td->pages[i] >> (this->bbt_erase_shift - this->page_shift); |
1029 | block <<= 1; | 1056 | block <<= 1; |
1030 | oldval = this->bbt[(block >> 3)]; | 1057 | oldval = bbt_get_entry(this, block >> 1); |
1031 | newval = oldval | (0x2 << (block & 0x06)); | 1058 | bbt_mark_entry(this, block >> 1, BBT_BLOCK_RESERVED); |
1032 | this->bbt[(block >> 3)] = newval; | 1059 | if ((oldval != BBT_BLOCK_RESERVED) && |
1033 | if ((oldval != newval) && td->reserved_block_code) | 1060 | td->reserved_block_code) |
1034 | nand_update_bbt(mtd, (loff_t)block << (this->bbt_erase_shift - 1)); | 1061 | nand_update_bbt(mtd, (loff_t)block << (this->bbt_erase_shift - 1)); |
1035 | continue; | 1062 | continue; |
1036 | } | 1063 | } |
@@ -1041,10 +1068,9 @@ static void mark_bbt_region(struct mtd_info *mtd, struct nand_bbt_descr *td) | |||
1041 | block = i * nrblocks; | 1068 | block = i * nrblocks; |
1042 | block <<= 1; | 1069 | block <<= 1; |
1043 | for (j = 0; j < td->maxblocks; j++) { | 1070 | for (j = 0; j < td->maxblocks; j++) { |
1044 | oldval = this->bbt[(block >> 3)]; | 1071 | oldval = bbt_get_entry(this, block >> 1); |
1045 | newval = oldval | (0x2 << (block & 0x06)); | 1072 | bbt_mark_entry(this, block >> 1, BBT_BLOCK_RESERVED); |
1046 | this->bbt[(block >> 3)] = newval; | 1073 | if (oldval != BBT_BLOCK_RESERVED) |
1047 | if (oldval != newval) | ||
1048 | update = 1; | 1074 | update = 1; |
1049 | block += 2; | 1075 | block += 2; |
1050 | } | 1076 | } |
@@ -1361,18 +1387,18 @@ int nand_isbad_bbt(struct mtd_info *mtd, loff_t offs, int allowbbt) | |||
1361 | 1387 | ||
1362 | /* Get block number * 2 */ | 1388 | /* Get block number * 2 */ |
1363 | block = (int)(offs >> (this->bbt_erase_shift - 1)); | 1389 | block = (int)(offs >> (this->bbt_erase_shift - 1)); |
1364 | res = (this->bbt[block >> 3] >> (block & 0x06)) & 0x03; | 1390 | res = bbt_get_entry(this, block >> 1); |
1365 | 1391 | ||
1366 | pr_debug("nand_isbad_bbt(): bbt info for offs 0x%08x: " | 1392 | pr_debug("nand_isbad_bbt(): bbt info for offs 0x%08x: " |
1367 | "(block %d) 0x%02x\n", | 1393 | "(block %d) 0x%02x\n", |
1368 | (unsigned int)offs, block >> 1, res); | 1394 | (unsigned int)offs, block >> 1, res); |
1369 | 1395 | ||
1370 | switch ((int)res) { | 1396 | switch ((int)res) { |
1371 | case 0x00: | 1397 | case BBT_BLOCK_GOOD: |
1372 | return 0; | 1398 | return 0; |
1373 | case 0x01: | 1399 | case BBT_BLOCK_WORN: |
1374 | return 1; | 1400 | return 1; |
1375 | case 0x02: | 1401 | case BBT_BLOCK_RESERVED: |
1376 | return allowbbt ? 0 : 1; | 1402 | return allowbbt ? 0 : 1; |
1377 | } | 1403 | } |
1378 | return 1; | 1404 | return 1; |