nand linux bbt存储,nand(5)_bbt

66b52468c121889b900d4956032f1009.png

8种机械键盘轴体对比

本人程序员,要买一个写代码的键盘,请问红轴和茶轴怎么选?

linux-4.13.1driversmtdnandNand_bbt.c

功能

bad block table,负责创建维护BBT,然后给予yaffs等文件系统使用

源码分析

nand_chip结构体nand_chip->bbt_td->pages: nand中哪个page存bbt

chip->bbt[]存储了bbt,最终将该bbt存储在nand中,每两位为一个块的信息,11好00坏1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16struct {

struct mtd_info mtd;

void __iomem *IO_ADDR_R;

void __iomem *IO_ADDR_W;

uint8_t (*read_byte)(struct mtd_info *mtd);

...

// bbt相关

uint8_t *bbt;// bbt

struct nand_bbt_descr *bbt_td;// main bbt

.options = NAND_BBT_LASTBLOCK;// 最后块往前搜

.page[]// bbt存在哪个page中

.maxblocks// 只search maxblocks个块

.pattern// bbt的标志位: {'B', 'b', 't', '0' }

struct nand_bbt_descr *bbt_md;// mirror bbt

}

nand_default_bbt

分为两部分

1: search,search最后4个块的1st page数据,如果匹配到bbt pattern({'B', 'b', 't', '0' }),说明找到了bbt。并且将bbt所在的page号保存在nand_chip->bbt_td->pages[]中

2: create,search不到bbt,则读取每块1st page oob的1st&2nd byte来构建bbt({ 0xff, 0xff }),2bits代表一块信息,00好块,11坏块,保存在nand_chip->bbt[]中,最后存储在nand中1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

18

19

20

21

22

23nand_default_bbt

// setting

this->bbt_td = &bbt_main_descr;

this->bbt_md = &bbt_mirror_descr;

nand_create_badblock_pattern(this);

bd->pattern = scan_ff_pattern;// { 0xff, 0xff }

this->badblock_pattern = bd;

nand_scan_bbt(mtd, this->badblock_pattern);

len = (1 << this->bbt_erase_shift);// 2^17 = 128KB(databuf)

len += (len >> this->page_shift) * mtd->oobsize;// (128*1024>>11)*64 = 4096(oobbuf)

buf = vmalloc(len);// 分配了一个block的databuf和oobbuf大小的空间

// Part 1: search

search_read_bbts(mtd, buf, td, md);

// search primary table && mirror table

search_bbt(mtd, buf, td);

search_bbt(mtd, buf, md);

// Part 2: 找不到的话则create & store

check_create(mtd, buf, bd);

// 遍历所有block构建了bbt,保存在nand_chip->bbt[],ddr中

create_bbt(mtd, buf, bd, chipsel);

// 将nand_chip->bbt[]存储在nand中, main bbt & mirror bbt

write_bbt(mtd, buf, td, md, chipsel);

write_bbt(mtd, buf, md, td, chipsel);

search_bbt

search部分

bbt的标示是({'B', 'b', 't', '0' }),使用这个来看是否有现存的bbt1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

18

19

20

21

22

23

24

25

26

27

28

29

30

31

32

33

34

35

36

37

38

39

40

41

42

43

44

45

46

47

48

49

50

51

52

53

54

55static uint8_t bbt_pattern[] = {'B', 'b', 't', '0' };

static struct nand_bbt_descr bbt_main_descr = {

.options = NAND_BBT_LASTBLOCK | NAND_BBT_CREATE | NAND_BBT_WRITE

| NAND_BBT_2BIT | NAND_BBT_VERSION | NAND_BBT_PERCHIP,

.offs =8,

.len = 4,

.veroffs = 12,

.maxblocks = NAND_BBT_SCAN_MAXBLOCKS,

.pattern = bbt_pattern

};

search_bbt

// NAND_BBT_LASTBLOCK: 则从最后块往前search,search 4个块

startblock = (mtd->size >> this->bbt_erase_shift) - 1;// 256*1024*1024 >> 17 -1 = 2047

dir = -1;

bbtblocks = this->chipsize >> this->bbt_erase_shift;// 256*1024*1024 >> 17

startblock &= bbtblocks - 1;// 2047

// search

for (i = 0; i < chips; i++) {

td->pages[i] = -1;// -1为初始值

for (block = 0; block < td->maxblocks; block++) {

// 从最后往前search,search 4个块

int actblock = startblock + dir * block;// begin: 2047->2046->2045->2044

loff_t offs = (loff_t)actblock << this->bbt_erase_shift;// startblock << 17, byte为单位所以要进行转换

// 1: 读取指定块1st page数据存放在buf中

scan_read(mtd, buf, offs, mtd->writesize, td);// offs: 字节为单位,读取一个page数据

scan_read_oob(mtd, buf, offs, len);// len: pagesize, 2KB

ops.mode = MTD_OPS_PLACE_OOB;

ops.datbuf = buf;// data position

ops.len = min(len, (size_t)mtd->writesize);// mtd->writesize: 2KB

ops.oobbuf = buf + ops.len;// offset 2KB == oob position

mtd_read_oob(mtd, offs, &ops);

mtd->_read_oob(mtd, from, ops);// mtd->_read_oob = nand_read_oob;

nand_do_read_ops(mtd, from, ops);

bufpoi = use_bufpoi ? chip->buffers->databuf : buf;// bufpoi = buf;

chip->cmdfunc(mtd, NAND_CMD_READ0, 0x00, page);// 1: 发送地址

chip->ecc.read_page(mtd, chip, bufpoi, oob_required, page);// nand_read_page_swecc: 读取指定page内容到bufpoi

chip->ecc.read_page_raw(mtd, chip, buf, 1, page);// nand_read_page_raw

// read data & oob

chip->read_buf(mtd, buf, mtd->writesize);// 2: read

chip->read_buf(mtd, chip->oob_poi, mtd->oobsize);

// 2: check

check_pattern(buf, scanlen, mtd->writesize, td))

/*

* offset pagesize+8

* 即bbt flag({'B', 'b', 't', '0' })存放在page[2048+8] = oob[8]的位置

* bbt保存在databuf中,bbt pattern保存在oob中

*/

memcmp(buf + paglen + td->offs, td->pattern, td->len);

// found then store

td->pages[i] = actblock << blocktopage;// FIXME: 2047 << 6: 转换为pagenum

}

}

check_create

create部分

遍历所有块,构建chip->bbt[],最后写入到nand中1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

18

19

20

21

22

23

24

25

26

27

28

29

30

31

32

33

34

35

36

37

38

39

40

41

42

43

44

45

46

47

48

49

50

51

52

53

54

55

56

57

58

59

60

61

62

63

64

65

66

67

68

69

70

71

72

73

74

75

76

77

78

79

80

81

82

83

84

85

86

87

88

89

90

91

92

93

94

95

96

97

98

99

100

101

102

103static uint8_t scan_ff_pattern[] = { 0xff, 0xff };

check_create

/*

* 1: check

* 检查bbt_main和bbt_mirror

*/

if (td->pages[i] == -1 && md->pages[i] == -1) {

create = 1;

writeops = 0x03;

}

/*

* 2: create: 没有main和mirror bbt,则create

* 遍历0->numblocks-1个块的坏块(1st 2nd page的oob area中的1st 2nd byte的数据不为0xff),记录在chip->bbt[]中

*/

create_bbt(mtd, buf, bd, chipsel);// chipsel = 0

numpages = 2;

numblocks = this->chipsize >> this->bbt_erase_shift;// 2048

startblock = chip * numblocks;// 0

numblocks += startblock;// 2048

from = (loff_t)startblock << this->bbt_erase_shift;// 0

// 0 -> 2047

for (i = startblock; i < numblocks; i++) {

ret = scan_block_fast(mtd, bd, from, buf, numpages);// numpages==2

/*

* 读取指定块1st和2nd page的oob数据,如果1st和2nd字节数据都是0xff,则是好块,否则为坏块

*/

ret = mtd_read_oob(mtd, offs, &ops);

if (check_short_pattern(buf, bd))

if (memcmp(buf + td->offs, td->pattern, td->len))// { 0xff, 0xff }

return -1;

return 1;

if (ret) {

// 有异常则标记坏块

bbt_mark_entry(this, i, BBT_BLOCK_FACTORY_BAD);// 标记了坏块

/*

* 两个bits代表一个块, 一个字节能指示4个块的信息

* 如chip->bbt[0]: 11 00 11 00

* 块: 3 2 1 0

* 状态: 坏 好 坏 好

*/

uint8_t msk = (mark & BBT_ENTRY_MASK) << ((block & BBT_ENTRY_MASK) * 2);

chip->bbt[block >> BBT_ENTRY_SHIFT] |= msk;// FIXME: chip->bbt[]坏块表

mtd->ecc_stats.badblocks++;

}

from += (1 << this->bbt_erase_shift);// += 2^17

}

/*

* 将chip->bbt[]写入到合适的block中(nand最后4个块中的没有用过的好块)存储

* buf为输出型参数

*/

write_bbt(mtd, buf, td, md, chipsel);

/* 1st: 计算bbt可以存储的地址, 最后转换为byte */

numblocks = (int)(this->chipsize >> this->bbt_erase_shift);// 256*1024*1024 >> 17 = 2048

/* block: bbt可以存储在哪个block中 [2047/2046/2045/2044] */

block = get_bbt_block(this, td, md, chip);

// NAND_BBT_LASTBLOCK, down -> top

startblock = numblocks * (chip + 1) - 1;

dir = -1;

for (i = 0; i < td->maxblocks; i++) {

block = startblock + dir * i;

// 坏块 过

switch (bbt_get_entry(this, block)) {

case BBT_BLOCK_WORN:

case BBT_BLOCK_FACTORY_BAD:

continue;

}

// 好块 over

return block;

}

page = block << (this->bbt_erase_shift - this->page_shift);// 块号转换为页号: 2047 << (17-11) = 2047 * 2^6 = 131008

to = ((loff_t)page) << this->page_shift;// 页号转换为byte: 131008 << 11 = 131008*2^11 = 268304384

/* 2nd: 将chip->bbt[]拿出来放到buf中 */

sft = 2; sftmsk = 0x06;

msk[0] = 0x00; msk[1] = 0x01; msk[3] = 0x03;

memset(buf, 0xff, len + (len >> this->page_shift)* mtd->oobsize);// 清buf为0xff size = 2048+2048>>11*mtd->oobsize = 2048+64

memcpy(&buf[ooboffs + td->offs], td->pattern, td->len);// bbt pattern

for (i = 0; i < numblocks; i++) {

int sftcnt = (i << (3 - sft)) & sftmsk;// sftcnt = block*2 & 0110 (0/2/4/6)

// 得到指定block的位图,2 bits

dat = bbt_get_entry(this, chip * numblocks + i);// 0->2047

entry = chip->bbt[block >> BBT_ENTRY_SHIFT];// block 0/1/2/3都在bbt[0]中,entry = bbt[0]

entry >>= (block & BBT_ENTRY_MASK) * 2;// entry = bbt[0] = 11 00 11 00, block 3: bbt[0] >>= 3*2 = [11] 00 11 00: 11是坏块

return entry & BBT_ENTRY_MASK;

/*

* FIXME: chip->bbt[0] = 11001100 -> buf[0] = 00110011, 相反

* ddr中: 坏[11], 好[00]

* nand中:坏[00], 好[11]

* erase后都是0xff,而坏块毕竟是少数,把good置为11,会减少写flash的bit

*/

buf[offs + (i >> sft)] &= ~(msk[dat] << sftcnt);

}

/* 3rd: 将buf中的内容写入到nand中 */

// 先擦再写

einfo.addr = to;// unit: byte

einfo.len = 1 << this->bbt_erase_shift;// 1<<17 = 128KB

nand_erase_nand(mtd, &einfo, 1);// erase

scan_write_bbt(mtd, to, len, buf, td->options & NAND_BBT_NO_OOB ? NULL : &buf[len]);// write

td->pages[chip++] = page;

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值