ubi移植与flash替换问题
我在用TI的dm368开发板,kernel是2.6.32.17,默认的flash文件系统是jffs2,但是jffs2在大分区下,mount速度很慢,而且占用ram较多,因此,我想使用ubifs看看性能是否会更好些。 ubifs的原理和配置过程,很多网页都有介绍的,我给一个链接,大家可以看看,我就不转载了,我重点说我移植过程中遇到并解决的问题。 http://bbs.chinaunix.net/thread-1954881-1-1.html ? kerne的配置很简单,2.6.32里面都有,选上并重新编译就好了。 ubiattach、ubimkvol等工具,TI的dvsdk里面自带了,能用,我就偷了个懒,没有重新编译。 ? 很轻松的照着网页说明操作了下,mount 分区也成功了,复制文件也成功了,很高兴:) ubiattach /dev/ubi_ctrl -m 3 ubimkvol? /dev/ubi0 -N rootfs -s 480MiB mount -t ubifs? ubi0_0 /mnt/nand/ -o sync 但很快就遇到麻烦了,开发板关机重新启动,我再mout ubi文件系统就出错了,提示了一堆错误,而且分区是空的,之前复制的文件不见了。 问题如下: ubiattach /dev/ubi_ctrl -m 3 UBI error: ubi_io_read: error -74while reading 64 bytes from PEB 1662:0,read 64 bytes UBI error: ubi_io_read: error -74while reading 64 bytes from PEB 1663:0,read 64 bytes ? 为了分析问题,我把mtd和ubifs的debug log都打开了,看到了一些信息; #define?? EBADMSG?????????? 74?? /* Not a data message */ ????????????? /*Nand returns -EBADMSG on ecc errors,but it returns ????????????? ?* the data. For our userspace tools it isimportant ????????????? ?* to dump areas with ecc errors ! ????????????? ?* For kernel internal usage it also mightreturn -EUCLEAN ????????????? ?* to signal the caller that a bitflip hasoccured and has ????????????? ?* been corrected by the ECC algorithm. ????????????? ?* Userspace software which accesses NAND thisway ????????????? ?* must be aware of the fact that it deals withNAND ????????????? ?*/ nand_do_read_ops ?????? stats= mtd->ecc_stats; ?????? if(mtd->ecc_stats.failed - stats.failed) ????????????? return-EBADMSG; ?? nand_read_page_hwecc ????????????? stat= chip->ecc.correct(mtd,p,&ecc_code[i],&ecc_calc[i]); ????????????? if(stat < 0) ???????????????????? mtd->ecc_stats.failed++; ????????????? else ???????????????????? mtd->ecc_stats.corrected+= stat; 看样子,应该是ECC出错了,可是我用的是硬件ECC校验,怎么可能几乎全部的page都出现ecc校验错误了呢? ? root@dm368-evm:~#flash_eraseall? /dev/mtd3 root@dm368-evm:~# ubiattach/dev/ubi_ctrl -m 3 UBI: attaching mtd3 to ubi0 UBI: physical eraseblock size:?? 131072 bytes (128 KiB) UBI: logical eraseblock size:??? 129024 bytes UBI: smallest flash I/O unit:??? 2048 UBI: sub-page size:??????????????512 UBI: VID header offset:????????? 512 (aligned 512) UBI: data offset:????? ??????????2048 ? 分析下UBI写数据的过程, UBI DBG (pid 1484): ubi_io_write:write 512 bytes to PEB 57:0 int ubi_io_write(struct ubi_device*ubi,const void *buf,int pnum,int offset, ????????????? ?int len) ?????? addr= (loff_t)pnum * ubi->peb_size + offset; ?????? err= ubi->mtd->write(ubi->mtd,addr,len,&written,buf); 在io_init函数中可以看到几个变量的赋值; ?????? ubi->peb_size?? = ubi->mtd->erasesize; ?????? ubi->peb_count? = mtd_div_by_eb(ubi->mtd->size,ubi->mtd); ?????? ubi->flash_size= ubi->mtd->size; 从debug log来看,这里一次写了512字节,从某个block的起始page开始,offset是0; 那么到了nand mtd底层驱动,行为就是; nand_write->nand_do_write_ops: ?????? subpage= column || (writelen & (mtd->writesize - 1)); 这里,subpage就是writelen,512; 也可以得知一点,ubifs没有使用oob,这跟jffs2和yaffs2是不同的; ????????????? /*Partial page write ? */ ????????????? if(unlikely(column || writelen < (mtd->writesize - 1))) { ???????????????????? cached= 0; ???????????????????? bytes= min_t(int,bytes - column,(int) writelen); ???????????????????? chip->pagebuf= -1; ???????????????????? memset(chip->buffers->databuf,0xff,mtd->writesize); ???????????????????? memcpy(&chip->buffers->databuf[column],buf,bytes); ???????????????????? wbuf= chip->buffers->databuf; ????????????? } ????????????? ret= chip->write_page(mtd,chip,wbuf,page,cached, ??????????????????????????? ?????? (ops->mode == MTD_OOB_RAW)); 下面是write_page函数的代码; static int nand_write_page(structmtd_info *mtd,struct nand_chip *chip, ???????????????????? ?? const uint8_t *buf,int page,int cached,int raw) { ?????? intstatus; ? ?????? chip->cmdfunc(mtd,NAND_CMD_SEQIN,0x00,page); ? ?????? if(unlikely(raw)) ????????????? chip->ecc.write_page_raw(mtd,buf); ?????? else ????????????? chip->ecc.write_page(mtd,buf); ? ?????? /* ?????? ?* Cached progamming disabled for now,Not sureif its worth the ?????? ?* trouble. The speed gain is not veryimpressive. (2.3->2.6Mib/s) ?????? ?*/ ?????? cached= 0; 这里需要注意的就是raw,如果是MTD_OOB_RAW,那么不会做ECC校验,也不会把ECC码写入OOB; 如果是这样,在read的时候也必须指定是MTD_OOB_RAW,不需要ECC校验;否则,就会出现我们最开始看到的错误; ?????? if(mtd->ecc_stats.failed - stats.failed) ????????????? return-EBADMSG; ? 那么,从这里的情况来看,我们可能已经找到出错的原因了;ubi使用了subpage write,而底层nand flash驱动实际上是不支持subpage write的,尽管ubi一次只写了512字节,但这个page的其他部分已经不能再次写入新的数据了。 ? 从Nand_base.c(driversmtdnand)来看,large page的nand flash,对subpage write的支持是不完善的,限制条件比较多,比如,不能是MLC的nand flash,不能用硬件ECC; 更严重的问题是代码存在缺陷,在写入部分data的时候,将其他部分的数据填充为0xff了,然后write整个page,并写入全部ecc码到oob,也许这就是前面ecc校验出错的原因吧。 nand_do_write_ops() ????????????? /*Partial page write ? */ memset(chip->buffers->databuf,bytes); 因此,我想到的解决办法就是在nand驱动中禁止subpage write。 第一步,在chip options中增加NAND_NO_SUBPAGE_WRITE; static struct davinci_nand_pdatadavinci_nand_data = { ?????? .options???????? = NAND_USE_FLASH_BBT|NAND_NO_SUBPAGE_WRITE, 然后重新编译下载kernel,但问题依旧; root@dm368-evm:~# ubiattach/dev/ubi_ctrl -m 3 UBI: attaching mtd3 to ubi0 UBI: physical eraseblock size:?? 131072 bytes (128 KiB) UBI: logical eraseblock size:??? 129024 bytes UBI: smallest flash I/O unit:??? 2048 UBI: sub-page size:????????????? 512 UBI: VID header offset:????????? 512 (aligned 512) 心想很奇怪,为什么?sub-page size还是512? 回头查看代码,想看看sub page size是怎样计算出来的, ?if (!(chip->options & NAND_NO_SUBPAGE_WRITE) && 可是我已经给options增加了NAND_NO_SUBPAGE_WRITE啊?有些怀疑,我就在此处加了打印log,果然是这里出了问题, chip->options = 0x10101. mtd->subpage_sft = 0. chip->subpagesize = 512. ? #define NAND_NO_SUBPAGE_WRITE??? 0x00000200 可是,这里的options 明明是不对的!那我设置的NAND_NO_SUBPAGE_WRITE在哪里丢掉了? ? 在下面的函数中有对chip->options赋值改变; nand_get_flash_type() ?????? ?????? printk(KERN_INFO"nand_get_flash_type 1,chip->options = 0x%x.n",chip->options); ? ?????? /*Get chip options,preserve non chip based options */ ???????chip->options &= ~NAND_CHIPOPTIONS_MSK; ?????? printk(KERN_INFO"nand_get_flash_type 2,chip->options); ?? ?????? chip->options|= type->options & NAND_CHIPOPTIONS_MSK; ?????? printk(KERN_INFO"nand_get_flash_type 3,chip->options); ? ?????? /* ?????? ?* Set chip as a default. Board drivers canoverride it,if necessary ?????? ?*/ ?????? chip->options|= NAND_NO_AUTOINCR; ? ?????? /*Check if chip is a not a samsung device. Do not clear the ?????? ?* options for chips which are not having anextended id. ?????? ?*/ ?????? if(*maf_id != NAND_MFR_SAMSUNG && !type->pagesize) ????????????? chip->options&= ~NAND_SAMSUNG_LP_OPTIONS; ?????? printk(KERN_INFO"nand_get_flash_type 4,chip->options); ? nand_get_flash_type 1,chip->options = 0x10200. nand_get_flash_type 2,chip->options = 0x10000. nand_get_flash_type 3,chip->options = 0x1011c. nand_get_flash_type 4,chip->options = 0x10101. ? 问题出在这里,红色的代码! /* Mask to zero out thechip options,which come from the id table */ #defineNAND_CHIPOPTIONS_MSK?(0x0000ffff &~NAND_NO_AUTOINCR) /* Chip can not autoincrement pages */ #define NAND_NO_AUTOINCR??0x00000001 ? 找到问题了,解决办法就有了,注释掉红色的那行代码,就是他把NAND_NO_SUBPAGE_WRITE给丢掉了。 //chip->options &=~NAND_CHIPOPTIONS_MSK; 再重新编译下载kernel,问题搞定了! 再次启动开发板,加载ubi,一切正常了。 root@dm368-evm:/# ubiattach/dev/ubi_ctrl -m 3 UBI: attaching mtd3 to ubi0 UBI: physical eraseblock size:?? 131072 bytes (128 KiB) UBI: logical eraseblock size:??? 126976 bytes UBI: smallest flash I/O unit:??? 2048 UBI: VID header offset:????????? 2048 (aligned 2048) UBI: data offset:??????????????? 4096 UBI: attached mtd3 to ubi0 UBI: MTD device name:??????????? "filesystem1" UBI: MTD device size:??????????? 512 MiB UBI: number of good PEBs:??????? 4096 UBI: number of bad PEBs:???????? 0 UBI: max. allowed volumes:?????? 128 UBI: wear-leveling threshold:??? 4096 UBI: number of internal volumes: 1 UBI: number of user volumes:???? 1 UBI: available PEBs:???????????? 3639 UBI: total number of reserved PEBs:457 UBI: number of PEBs reserved for badPEB handling: 40 UBI: max/mean erase counter: 2/1 UBI: image sequence number: 0 UBI: background thread"ubi_bgt0d" started,PID 1483 UBI device number 0,total 4096 LEBs(520093696 bytes,496.0 MiB),available 3639 LEBs (462065664 bytes,440.7 MiB),LEB size 126976 bytes (124.0 KiB) ? root@dm368-evm:/# mount -tubifs? ubi0_0 /mnt/nand/ -o sync UBIFS: mounted UBI device 0,volume0,name "rootfs" UBIFS: file system size:?? 51171328 bytes (49972 KiB,48 MiB,403 LEBs) UBIFS: journal size:?????? 2539520 bytes (2480 KiB,2 MiB,20 LEBs) UBIFS: media format:?????? w4/r0 (latest is w4/r0) UBIFS: default compressor: lzo UBIFS: reserved for root:? 2416947 bytes (2360 KiB) root@dm368-evm:/# df Filesystem?????????? 1K-blocks????? Used Available Use% Mounted on /dev/root???????????? 39544232? 16239820?21295632? 43% / none????????????????????? 1024??????? 24?????1000?? 2% /dev tmpfs??????????????????? 16384??????? 20????16364?? 0% /var/volatile tmpfs??????????????????? 21760???????? 0????21760?? 0% /dev/shm tmpfs??????????????????? 16384???????? 0????16384?? 0% /media/ram ubi0_0?????????????????? 45528????? 1528????41640?? 4% /mnt/nand ? 最后,总结下,就是要禁止nand flash驱动里面的subpage write,让?chip->subpagesize == mtd->writesize 就好了。 这是我的解决办法。如果有人要使用subpage write,那么一定要保证你的读写逻辑是正确的,要么不用ecc,要么各个subpage的ecc都应是正确的。 http://www.61ic.com/Article/DaVinci/TMS320DM3x/201307/49496.html (编辑:李大同) 【声明】本站内容均来自网络,其相关言论仅代表作者个人观点,不代表本站立场。若无意侵犯到您的权利,请及时与联系站长删除相关内容! |