




版权说明:本文档由用户提供并上传,收益归属内容提供方,若内容存在侵权,请进行举报或认领
文档简介
1、3月31日前言:为了深入了解MTD如何处理Nand问题,决定跟一下MTD Nand层代码。mtd.h重要结构体:struct erase_info如果擦除失败,fail_addr将指示坏块地址。struct mtd_infomtd层函数指针存放处。nand.hNand基本指令:#define NAND_CMD_READ00#define NAND_CMD_READ11#define NAND_CMD_PAGEPROG0x10#define NAND_CMD_READOOB0x50#define NAND_CMD_ERASE10x60#define NAND_CMD_STATUS0x70#def
2、ine NAND_CMD_STATUS_MULTI0x71#define NAND_CMD_SEQIN0x80#define NAND_CMD_READID0x90#define NAND_CMD_ERASE20xd0#define NAND_CMD_RESET0xff和K9F1208指令对比重要结构体:struct nand_chip具体操作Nand的函数指针都在这个结构体里面。 struct nand_bbt_descrNand坏块表?具体如何使用还不清楚。4月1日nand_base.cint nand_scan (struct mtd_info *mtd, int maxchips)st
3、ruct nand_chip *this = mtd-priv;priv是mtd_info结构体里面的一个空指针,现在指向this。if (this-cmdfunc = NULL)this-cmdfunc = nand_command;判断驱动编写者是否提供了command函数,后来几个类似。this-cmdfunc (mtd, NAND_CMD_READID, 0X00, -1);读取Nand芯片信息,包括厂商信息的芯片ID,对于K9F1208是0xEC和0x76。对应nand_ids.c中的NAND 64MiB 3,3V 8-bit, 0x76, 512, 64, 0x4000, 0。含义
4、:三星的这颗Nand芯片是64MB的,3.3V供电,8bit位宽,ID为0x76,每一页大小为512Byte,64MB容量,擦除块尺寸为0x4000,操作0。对擦除块为0x4000的解释:这颗Nand芯片的容量是这样划分的,512Byte x 32 x 4096 = 64MB,一共有4096个块(block),因此每一个块的大小为512Byte x 32 = 16384Byte = 0x4000Byte。这些信息接下来都会被MTD层获得,如果全部没有问题,则在启动时会打印:printk (KERN_INFO NAND device: Manufacturer ID: 0x%02x, Chip
5、ID: 0x%02x (%s %s)n, nand_maf_id, nand_dev_id,nand_manuf_idsmaf_ , mtd-name);/* Calculate the address shift from the page size */this-page_shift = ffs(mtd-oobblock) - 1;this-bbt_erase_shift = this-phys_erase_shift = ffs(mtd-erasesize) - 1;this-chip_shift = ffs(this-chipsize) - 1;这一段不太明白,翻译过来是
6、根据页面大小计算地址变化?我在启动时将其打印了出来:mtd-oobblock is 0x200mtd-oobsize is 0x10mtd-erasesize is 0x4000this-page_shift is 0x9this-bbt_erase_shift is 0xethis-chip_shift is 0x1affs函数第一次见到,看看是什么东西:#define ffs(x) generic_ffs(x)继续,蛮有意思的函数:static inline int generic_ffs(int x)int r = 1;if (!x)return 0;if (!(x & 0xffff)
7、x = 16;r += 16;if (!(x & 0xff) x = 8;r += 8;if (!(x & 0xf) x = 4;r += 4;if (!(x & 3) x = 2;r += 2;if (!(x & 1) x = 1;r += 1;return r;这函数人如其名,找到第一个bit位(find first bit set),比如0x80,将返回7。/* Set the bad block position */this-badblockpos = mtd-oobblock 512 ?NAND_LARGE_BADBLOCK_POS : NAND_SMALL_BADBLOCK_PO
8、S;确定坏块标记的位置,如果大于512,在oob区的位置0,否则是在oob区的位置5。/* Do not replace user supplied command function ! */if (mtd-oobblock 512 & this-cmdfunc = nand_command)this-cmdfunc = nand_command_lp;这一段没有什么意义,因为我们的底层驱动里面提供了命令函数。if (!nand_flash_) printk (KERN_WARNING No NAND device found!n);this-select_chip(mtd,
9、 -1);return 1;如果没有发现芯片,会提示找不到芯片,我刚开始做u-boot驱动时,读不到正确的芯片ID,就报这个错误,并且直接返回1,下面的程序不再执行。for (i=1; i select_chip(mtd, i);/* Send the command for reading device ID */this-cmdfunc (mtd, NAND_CMD_READID, 0x00, -1);/* Read manufacturer and device IDs */if (nand_maf_id != this-read_byte(mtd) | nand_dev_id != t
10、his-read_byte(mtd)break;如果有多块芯片,这里会去读它们的ID信息。/* Allocate buffers, if neccecary */if (!this-oob_buf) size_t len;len = mtd-oobsize phys_erase_shift - this-page_shift);this-oob_buf = kmalloc (len, GFP_KERNEL);if (!this-oob_buf) printk (KERN_ERR nand_scan(): Cannot allocate oob_bufn);return -ENOMEM;this
11、-options |= NAND_OOBBUF_ALLOC;if (!this-data_buf) size_t len;len = mtd-oobblock + mtd-oobsize;this-data_buf = kmalloc (len, GFP_KERNEL);if (!this-data_buf) if (this-options & NAND_OOBBUF_ALLOC)kfree (this-oob_buf);printk (KERN_ERR nand_scan(): Cannot allocate data_bufn);return -ENOMEM;this-options |
12、= NAND_DATABUF_ALLOC;如果前面没有分配,在这儿分配数据区和oob区的空间。说说这个size_t,是为了方便移植而的设定的,其实就是unsigned int。oob区的大小是mtd-oobsize phys_erase_shift - this-page_shift),数据区的大小是mtd-oobblock + mtd-oobsize。这儿在计算oob区该分配多大时用到了前面定义的this-page_shift和this-phys_erase_shift。具体计算方法?这时候用得上前面print出来的内容:mtd-oobblock is 0x200mtd-oobsize is
13、 0x10mtd-erasesize is 0x4000this-page_shift is 0x9this-bbt_erase_shift is 0xethis-chip_shift is 0x1alen = mtd-oobsize phys_erase_shift - this-page_shift);这句话应该是计算oob_buf的长度,计算结果应该是(16 numchips = i;mtd-size = i * this-chipsize;/* Convert chipsize to number of pages per chip -1. */this-pagemask = (thi
14、s-chipsize this-page_shift) - 1;/* Preset the internal oob buffer */memset(this-oob_buf, 0xff, mtd-oobsize phys_erase_shift - this-page_shift);存储芯片的数目并计算mtd的总大小。将芯片大小换算成页数,这时我才看懂this-page_shift的意思,就是9bit,因为便于移位操作,所以才用ffs函数将512变换为9的。最后将oob_buf全部填充了0xff。/* If no default placement scheme is given, sele
15、ct an * appropriate one */if (!this-autooob) /* Select the appropriate default oob placement scheme for * placement agnostic filesystems */switch (mtd-oobsize) case 8:this-autooob = &nand_oob_8;break;case 16:this-autooob = &nand_oob_16;break;case 64:this-autooob = &nand_oob_64;break;default:printk (
16、KERN_WARNING No oob scheme defined for oobsize %dn,mtd-oobsize);BUG();根据oobsize填充autooob,我们的oobsize是16,填充的是nand_oob_16这个结构体的内容:static struct nand_oobinfo nand_oob_16 = .useecc = MTD_NANDECC_AUTOPLACE,.eccbytes = 6,.eccpos = 0, 1, 2, 3, 6, 7,.oobfree = 8, 8 ;结构体中规定了ecc校验位的位置。/* The number of bytes av
17、ailable for the filesystem to place fs dependend * oob data */mtd-oobavail = 0;for (i = 0; this-autooob-oobfreei1; i+)mtd-oobavail += this-autooob-oobfreei1;文件系统的oob数据放在oob的free区里面。/* * check ECC mode, default to software * if 3byte/512byte hardware ECC is selected and we have 256 byte pagesize * fa
18、llback to software ECC*/this-eccsize = 256;/* set default eccsize */this-eccbytes = 3;switch (this-eccmode) case NAND_ECC_HW12_2048:if (mtd-oobblock oobblock);this-eccmode = NAND_ECC_SOFT;this-calculate_ecc = nand_calculate_ecc;this-correct_data = nand_correct_data; elsethis-eccsize = 2048;break;cas
19、e NAND_ECC_HW3_512:case NAND_ECC_HW6_512:case NAND_ECC_HW8_512:if (mtd-oobblock = 256) printk (KERN_WARNING 512 byte HW ECC not possible on 256 Byte pagesize, fallback to SW ECC n);this-eccmode = NAND_ECC_SOFT;this-calculate_ecc = nand_calculate_ecc;this-correct_data = nand_correct_data; elsethis-ec
20、csize = 512; /* set eccsize to 512 */break;case NAND_ECC_HW3_256:break;case NAND_ECC_NONE:printk (KERN_WARNING NAND_ECC_NONE selected by board driver. This is not recommended !n);this-eccmode = NAND_ECC_NONE;break;case NAND_ECC_SOFT:this-calculate_ecc = nand_calculate_ecc;this-correct_data = nand_co
21、rrect_data;break;default:printk (KERN_WARNING Invalid NAND_ECC_MODE %dn, this-eccmode);BUG();默认的eccsize为256,eccbytes为3。开始判断驱动中提供的eccmode,我们以前用的是NAND_ECC_SOFT,现在为了使用yaffs,改用NAND_ECC_NONE,其他硬件的都不用看。如果是NONE的话,直接printk一个warning,如果是SOFT的,需要填充:this-calculate_ecc = nand_calculate_ecc;this-correct_data = na
22、nd_correct_data;这是两个函数哦,不是变量,mark下后面要跟。/* Check hardware ecc function availability and adjust number of ecc bytes per * calculation step*/switch (this-eccmode) case NAND_ECC_HW12_2048:this-eccbytes += 4;case NAND_ECC_HW8_512:this-eccbytes += 2;case NAND_ECC_HW6_512:this-eccbytes += 3;case NAND_ECC_H
23、W3_512:case NAND_ECC_HW3_256:if (this-calculate_ecc & this-correct_data & this-enable_hwecc)break;printk (KERN_WARNING No ECC functions supplied, Hardware ECC not possiblen);BUG();mtd-eccsize = this-eccsize;没用到硬件ecc,这儿应该直接跳过了。/* Set the number of read / write steps for one page to ensure ECC generat
24、ion */switch (this-eccmode) case NAND_ECC_HW12_2048:this-eccsteps = mtd-oobblock / 2048;break;case NAND_ECC_HW3_512:case NAND_ECC_HW6_512:case NAND_ECC_HW8_512:this-eccsteps = mtd-oobblock / 512;break;case NAND_ECC_HW3_256:case NAND_ECC_SOFT:this-eccsteps = mtd-oobblock / 256;break;case NAND_ECC_NON
25、E:this-eccsteps = 1;break;设置每一页的ecc校验的steps。NAND_ECC_NONE是1,NAND_ECC_SOFT是2。/* Initialize state, waitqueue and spinlock */this-state = FL_READY;init_waitqueue_head (&this-wq);spin_lock_init (&this-chip_lock);初始化状态机、等待列队和自旋锁。/* Fill in remaining MTD driver data */mtd-type = MTD_NANDFLASH;mtd-flags =
26、MTD_CAP_NANDFLASH | MTD_ECC;mtd-ecctype = MTD_ECC_SW;mtd-erase = nand_erase;mtd-point = NULL;mtd-unpoint = NULL;mtd-read = nand_read;mtd-write = nand_write;mtd-read_ecc = nand_read_ecc;mtd-write_ecc = nand_write_ecc;mtd-read_oob = nand_read_oob;mtd-write_oob = nand_write_oob;mtd-readv = NULL;mtd-wri
27、tev = nand_writev;mtd-writev_ecc = nand_writev_ecc;mtd-sync = nand_sync;mtd-lock = NULL;mtd-unlock = NULL;mtd-suspend = nand_suspend;mtd-resume = nand_resume;mtd-block_isbad = nand_block_isbad;mtd-block_markbad = nand_block_markbad;填充MTD结构体的其他成员及函数,我看完nand scan如果没有突破点,就应该一个一个看这里面的内容。/* Check, if we
28、should skip the bad block table scan */if (this-options & NAND_SKIP_BBTSCAN)return 0;这儿比较重要,我正想u-boot在开机能不能跳过scan坏块呢,只要定义了NAND_SKIP_BBTSCAN就可以跳过坏块了。但是这个Linux下的nand_base.c,刚又看了下u-boot里面的nand_base.c,发现没有这个判断,奇怪。/* Build bad block table */return this-scan_bbt (mtd);虽然返回,但没有结束,跳去执行scan_bbt这个函数了,下一步目标:sc
29、an_bbt!终于终于把一个小小的nand_sacn函数看完了4月21日惭愧,没想到隔了这么长时间才继续学习。前面看到在nand_scan()函数的最后将会跳至scan_bbt()函数,这个函数在nand_scan里面有定义:2415if (!this-scan_bbt)2416this-scan_bbt = nand_default_bbt;nand_default_bbt()位于Nand_bbt.c文件中。1047/* * nand_default_bbt - NAND Interface Select a default bad block table for the device *
30、mtd:MTD device structure * * This function selects the default bad block table * support for the device and calls the nand_scan_bbt function*/int nand_default_bbt (struct mtd_info *mtd)struct nand_chip *this = mtd-priv;这个函数的作用是建立默认的坏块表。1059/* Default for AG-AND. We must use a flash based* bad block
31、table as the devices have factory marked* _good_ blocks. Erasing those blocks leads to loss* of the good / bad information, so we _must_ store * this information in a good / bad table during * startup*/if (this-options & NAND_IS_AND) /* Use the default pattern descriptors */if (!this-bbt_td) this-bb
32、t_td = &bbt_main_descr;this-bbt_md = &bbt_mirror_descr;this-options |= NAND_USE_FLASH_BBT;return nand_scan_bbt (mtd, &agand_flashbased);如果Flash的类型是AG-AND(这种Flash类型比较特殊,既不是MLC又不是SLC,因此不去深究了,而且好像瑞萨要把它淘汰掉),需要使用默认的模式描述符,最后再进入nand_scan_bbt()函数。1078/* Is a flash based bad block table requested ? */if (thi
33、s-options & NAND_USE_FLASH_BBT) /* Use the default pattern descriptors */if (!this-bbt_td) this-bbt_td = &bbt_main_descr;this-bbt_md = &bbt_mirror_descr;if (!this-badblock_pattern) this-badblock_pattern = (mtd-oobblock 512) ?&largepage_flashbased : &smallpage_flashbased; else this-bbt_td = NULL;this
34、-bbt_md = NULL;if (!this-badblock_pattern) this-badblock_pattern = (mtd-oobblock 512) ?&largepage_memorybased : &smallpage_memorybased;return nand_scan_bbt (mtd, this-badblock_pattern);如果Flash芯片需要使用坏块表,对于1208芯片来说是使用smallpage_memorybased。985static struct nand_bbt_descr smallpage_memorybased = .option
35、s = NAND_BBT_SCAN2NDPAGE,.offs = 5,.len = 1,.pattern = scan_ff_pattern;暂时没看到如何使用这些赋值,先放着。后面检测坏块时用得着。1099return nand_scan_bbt (mtd, this-badblock_pattern);最后将badblock_pattern作为参数,调用nand_can_bbt函数。844/* nand_scan_bbt - NAND Interface scan, find, read and maybe create bad block table(s) * mtd:MTD devic
36、e structure * bd:descriptor for the good/bad block search pattern * * The function checks, if a bad block table(s) is/are already * available. If not it scans the device for manufacturer * marked good / bad blocks and writes the bad block table(s) to * the selected place. * * The bad block table mem
37、ory is allocated here. It must be freed * by calling the nand_free_bbt function. */int nand_scan_bbt (struct mtd_info *mtd, struct nand_bbt_descr *bd)检测、寻找、读取甚至建立坏块表。函数检测是否已经存在一张坏块表,否则建立一张。坏块表的内存分配也在这个函数中。860struct nand_chip *this = mtd-priv;int len, res = 0;uint8_t *buf;struct nand_bbt_descr *td =
38、this-bbt_td;struct nand_bbt_descr *md = this-bbt_md;len = mtd-size (this-bbt_erase_shift + 2);/* Allocate memory (2bit per block) */this-bbt = kmalloc (len, GFP_KERNEL);if (!this-bbt) printk (KERN_ERR nand_scan_bbt: Out of memoryn);return -ENOMEM;/* Clear the memory bad block table */memset (this-bb
39、t, 0x00, len);一些赋值、变量声明、内存分配,每个block分配2bit的空间。1208有4096个block,应该分配4096*2bit的空间。877/* If no primary table decriptor is given, scan the device * to build a memory based bad block table */if (!td) if (res = nand_memory_bbt(mtd, bd) printk (KERN_ERR nand_bbt: Cant scan flash and build the RAM-based BBTn
40、);kfree (this-bbt);this-bbt = NULL;return res;如果没有提供ptd,就扫描设备并建立一张。这里调用了nand_memory_bbt()这个内联函数。653/* * nand_memory_bbt - GENERIC create a memory based bad block table * mtd:MTD device structure * bd:descriptor for the good/bad block search pattern * * The function creates a memory based bbt by scan
41、ning the device * for manufacturer / software marked good / bad blocks*/static inline int nand_memory_bbt (struct mtd_info *mtd, struct nand_bbt_descr *bd)struct nand_chip *this = mtd-priv;bd-options &= NAND_BBT_SCANEMPTY;return create_bbt (mtd, this-data_buf, bd, -1);函数的作用是建立一张基于memory的坏块表。将操作符的NAN
42、D_BBT_SCANEMPTY清除,并继续调用creat_bbt()函数。271/* create_bbt - GENERIC Create a bad block table by scanning the device * mtd:MTD device structure * buf:temporary buffer * bd:descriptor for the good/bad block search pattern * chip:create the table for a specific chip, -1 read all chips. *Applies only if NAN
43、D_BBT_PERCHIP option is set * * Create a bad block table by scanning the device * for the given good/bad block identify pattern */static int create_bbt (struct mtd_info *mtd, uint8_t *buf, struct nand_bbt_descr *bd, int chip)真正的建立坏块表函数。chip参数是-1表示读取所有的芯片。284 struct nand_chip *this = mtd-priv;int i,
44、j, numblocks, len, scanlen;int startblock;loff_t from;size_t readlen, ooblen;printk (KERN_INFO Scanning device for bad blocksn);一些变量声明,开机时那句话就是在这儿打印出来的。292 if (bd-options & NAND_BBT_SCANALLPAGES)len = 1 bbt_erase_shift - this-page_shift);else if (bd-options & NAND_BBT_SCAN2NDPAGE)len = 2;elselen = 1
45、;在前面我们定义了smallpage_memorybased这个结构体,现在里面NAND_BBT_SCANALLPAGES的终于用上了,对于1208芯片来说,len=2。304 if (!(bd-options & NAND_BBT_SCANEMPTY) /* We need only read few bytes from the OOB area */scanlen = ooblen = 0;readlen = bd-len; else /* Full page content should be read */scanlen= mtd-oobblock + mtd-oobsize;rea
46、dlen = len * mtd-oobblock;ooblen = len * mtd-oobsize;前面已经将NAND_BBT_SCANEMPTY清除了,这里肯定执行else的内容。需要将一页内容都读取出来。316if (chip = -1) /* Note that numblocks is 2 * (real numblocks) here, see i+=2 below as it * makes shifting and masking less painful */numblocks = mtd-size (this-bbt_erase_shift - 1);startbloc
47、k = 0;from = 0; else if (chip = this-numchips) printk (KERN_WARNING create_bbt(): chipnr (%d) available chips (%d)n,chip + 1, this-numchips);return -EINVAL;numblocks = this-chipsize (this-bbt_erase_shift - 1);startblock = chip * numblocks;numblocks += startblock;from = startblock bbt_erase_shift - 1
48、);前面提到chip为-1,实际上我们只有一颗芯片,numblocks这儿是4096*2。335 for (i = startblock; i options & NAND_BBT_SCANEMPTY)if (ret = nand_read_raw (mtd, buf, from, readlen, ooblen)return ret;for (j = 0; j options & NAND_BBT_SCANEMPTY) size_t retlen;/* Read the full oob until read_oob is fixed to * handle single byte read
49、s for 16 bit buswidth */ret = mtd-read_oob(mtd, from + j * mtd-oobblock,mtd-oobsize, &retlen, buf);if (ret)return ret;if (check_short_pattern (buf, bd) this-bbti 3 |= 0x03 1, (unsigned int) from);break; else if (check_pattern (&bufj * scanlen, scanlen, mtd-oobblock, bd) this-bbti 3 |= 0x03 1, (unsigned int) from);break;i += 2;from += (1 bbt_erase_shift);return 0;检测这4096个block,刚开始的nand_read_raw肯定不会执行。len是2,在j循环要循环2次。每次循环真正要做的事情是下面的内容:ret = mtd-read_oob(mtd, from + j * mtd-oobblock,mtd-oobsize, &retlen, buf);read_oob()函数在nand_s
温馨提示
- 1. 本站所有资源如无特殊说明,都需要本地电脑安装OFFICE2007和PDF阅读器。图纸软件为CAD,CAXA,PROE,UG,SolidWorks等.压缩文件请下载最新的WinRAR软件解压。
- 2. 本站的文档不包含任何第三方提供的附件图纸等,如果需要附件,请联系上传者。文件的所有权益归上传用户所有。
- 3. 本站RAR压缩包中若带图纸,网页内容里面会有图纸预览,若没有图纸预览就没有图纸。
- 4. 未经权益所有人同意不得将文件中的内容挪作商业或盈利用途。
- 5. 人人文库网仅提供信息存储空间,仅对用户上传内容的表现方式做保护处理,对用户上传分享的文档内容本身不做任何修改或编辑,并不能对任何下载内容负责。
- 6. 下载文件中如有侵权或不适当内容,请与我们联系,我们立即纠正。
- 7. 本站不保证下载资源的准确性、安全性和完整性, 同时也不承担用户因使用这些下载资源对自己和他人造成任何形式的伤害或损失。
最新文档
- 广场工程用阀门采购招标条件3篇
- 干挂施工合同价款支付方式
- 忠诚与责任女婿的宣言3篇
- 如何写招标文件质疑函3篇
- 协议签订流程及批准表3篇
- 写字楼物业管理服务合同样本3篇
- 合伙人股权分配合同范本示例3篇
- 公证处委托书的格式及内容3篇
- 关于施工安全协议书范文3篇
- 同意房屋转租合同范本2篇
- 2024年内蒙古师范大学招聘事业编制人员考试真题
- (二模)2025年河南省五市高三第二次联考历史试卷(含答案)
- 飞行员劳动合同模板及条款
- 《劳动项目五:煮鸡蛋》(教案)-2024-2025学年人教版劳动三年级上册
- 第中西艺术时空对话 课件 2024-2025学年岭南美版(2024) 初中美术七年级下册
- 2025-2030检测设备行业行业风险投资发展分析及投资融资策略研究报告
- (三模)广西2025届高中毕业班4月份适应性测试 英语试卷(含答案解析)
- (四调)武汉市2025届高中毕业生四月调研考试 物理试卷(含答案)
- 中级财务会计课件第四章 金融资产学习资料
- 2025年济南市中区九年级中考数学一模考试试题(含答案)
- 中国印楝素市场调查报告
评论
0/150
提交评论