mtd分层调用流程

it2022-05-09  41

目录

 

字符节点分层调用流程

open

擦除


字符节点分层调用流程

示例:nanddump  -p  -c  -l  0x800  /dev/mtd8

open

open(“/dev/mtd8”...)  =  3         mtdchar_open(struct  inode  *inode,  struct  file  *file)                //mtdchar.c                 int  minor  =  iminor(inode);                 int  devnum  =  minor  >>  1;                 struct  mtd_info  *mtd;                         struct  mtd_file_info  *mfi;

                mtd  =  get_mtd_device(NULL,  devnum);                         struct  mtd_info  *ret  =  NULL                         ret  =  idr_find(&mtd_idr,  num);                         __get_mtd_device(ret);                         return  ret;

                mfi  =  kzalloc(sizeof(*mfi),  GFP_KERNEL);                 mfi->mtd  =  mtd;                 file->private_data  =  mfi;

ioctl

ioctl(3,  MIXER_READ(18)  or  ECCGETSTATS,  ...)         struct  mtd_file_info  *mfi  =  file->private_data;         struct  mtd_info  *mtd  =  mfi->mtd;

        检查坏块:MEMSETBADBLOCK         擦除:MEMERASE、MEMERASE64

擦除

mtd_erase(mtd,  erase);                                                                   //mtdcore.c         mtd->_erase(mtd,  instr)                                                           //nand_base.c=>nand_scan_tail中指定的                 nand_erase(mtd,  instr);                                                    //nand_base.c                         nand_erase_nand(mtd,  instr,  0)                             //nand_base.c                                 chip->select_chip(mtd,  chipnr);                       //控制器驱动或nand_base.c=>nand_scan_ident中指定                                 nand_block_checkbad(mtd,  ((loff_t)  page)  <<  chip->page_shift,  allowbbt)   //若是坏块,则不擦除                                         if (!chip->bbt)   //否则 return nand_isbad_bbt(mtd, ofs, allowbbt);   nand_bbt.c                                               chip->block_bad(mtd, ofs);   //nand_base.c=> nand_scan_ident=> nand_set_defaults                                                       nand_block_bad(mtd, ofs)      //nand_base.c                                                               如果(chip->bbt_options & NAND_BBT_SCANLASTPAGE)                                                                       ofs += mtd->erasesize - mtd->writesize;                                                               chip->cmdfunc(mtd, NAND_CMD_READOOB, chip->badblockpos, page);                                                               bad = chip->read_byte(mtd);                                                               res = bad != 0xFF;                                                               如果(chip->bbt_options & NAND_BBT_SCAN2NDPAGE)                                                                       会再读下一页的bb数据                                                               return res;                                 chip->erase(mtd,  page  &  chip->pagemask)      //nand_base.c=>  nand_get_flash_type中指定                                         single_erase(mtd,  page  &  chip->pagemask)                                                 //控制器驱动或nand_base.c=>nand_scan_ident中指定                                                 chip->cmdfunc(mtd,  NAND_CMD_ERASE1,  -1,  page);                                                                        发送页地址                                                 chip->cmdfunc(mtd,  NAND_CMD_ERASE2,  -1,  -1);

read(3,  ...)  //应用层

mtdchar_read(struct  file  *file,  char  __user  *buf,  size_t  count,  loff_t  *ppos)    //mtdchar.c            //一般走switch的默认路径         struct mtd_file_info *mfi = file->private_data;         struct mtd_info *mtd = mfi->mtd;         ret = mtd_read(mtd,  *ppos,  len,  &retlen,  kbuf);                           //mtdcore.c                 ret_code = mtd->_read(mtd,  from,  len,  retlen,  buf);           //mtdpart.c=> allocate_partition指定                              part_read(mtd,  from,  len,  retlen,  buf);           //mtdpart.c                                          stats = part->master->ecc_stats;                                          res = part->master->_read(part->master, from + part->offset, len, retlen, buf);                                                        //nand_base.c=>nand_scan_tail指定                                                   nand_read(mtd,  from,  len,  retlen,  buf)          //nand_base.c                                                           ops.mode  =  MTD_OPS_PLACE_OOB;                                                           nand_do_read_ops(mtd,  from,  &ops);        //nand_base.c                                                                 uint8_t *oob;                                                                 oob = ops->oobbuf;                                                                               ecc_failures = mtd->ecc_stats.failed;                                                                  chip->select_chip(mtd,  chipnr);                                                                                 //控制器驱动或nand_base.c=>nand_scan_ident => nand_set_defaults                                                                  chip->cmdfunc(mtd,  NAND_CMD_READ0,  0x00,  page);                                                                                                        //控制器驱动或nand_base.c=>nand_scan_ident => nand_set_defaults                                                                          发送地址、读命令                                                                                                                 如果ops->mode是MTD_OPS_RAW                                                                           ret = chip->ecc.read_page_raw(mtd,  chip,  bufpoi,                                                                                                                                        oob_required,  page);                                                                            //nand_base.c=>nand_scan_tail函数中设置                                                                   若没对齐 且 chip->options有NAND_SUBPAGE_READ 且                                                                                                                                          ops->oobbuf是NULL                                                                           ret = chip->ecc.read_subpage(mtd,  chip,  col,                                                                                                                            bytes,  bufpoi,  page);                                                                   其他  //一般走此分支                                                                           ret = chip->ecc.read_page(mtd, chip, bufpoi, oob_required, page);                                                                    ret = chip->ecc.read_page(mtd,  chip,  bufpoi,  oob_required,  page);                                                                            //nand_base.c=> nand_scan_tail指定                                                                            nand_read_page_raw(mtd,  chip,  bufpoi,  oob_required,  page)                                                                                    //nand_base.c                                                                                    //此函数返回值一定为0                                                                                    chip->read_buf(mtd,  buf,  mtd->writesize);                                                                                                                                         //控制器驱动或nand_base.c=>nand_scan_ident =>                                                                                            //nand_set_defaults指定                                                                                           只是把host->buf数据拷贝到buf                                                                                           hisi_fmc_read_buf(struct mtd_info *mtd,                                                                                                                                  uint8_t *buf, int len)                                                                                                   如果读失败了:mtd->ecc_stats.failed++;                                                                                                   设置ECC纠正的位数:mtd->ecc_stats.corrected += ..

                                                               max_bitflips = max_t(unsigned int, max_bitflips, ret);                                                                 if(oob)                                                                              oob = nand_transfer_oob(mtd, oob, ops, toread);                                                                 //如果ecc出错了,重传                                                                 if (mtd->ecc_stats.failed - ecc_failures)                                                                                  //如果还有剩余尝试次数,重传                                                                                 if (retry_mode + 1 < chip->read_retries){                                                                                                 mtd->ecc_stats.failed = ecc_failures;                                                                                                 goto read_retry;                                                                                 }else{                                                                                                 ecc_fail = true;                                                                                 }                                                                 }                                                                                                                                          if (ret < 0)                                                                                 return ret;

                                                                if (ecc_fail)                                                                                 return -EBADMSG;

                                                                return max_bitflips;                          if ((mtd_is_eccerr(res)))                              mtd->ecc_stats.failed += part->master->ecc_stats.failed - stats.failed;                        else                              mtd->ecc_stats.corrected += part->master->ecc_stats.corrected - stats.corrected;                 若ret_code < 0,直接返回                 若mtd->ecc_strength == 0,直接返回0                 若ret_code大于mtd->bitflip_threshold                         返回-EUCLEAN                 否则                         返回0         如果读出错了(ret != 0)                 ret = mtd_is_bitflip_or_eccerr(ret)             //mtd.h                         return mtd_is_bitflip(err) || mtd_is_eccerr(err)                               如果err是-EUCLEAN,是位反转(但被校正过来了);如果err是-EBADMSG,是ECC错误                 如果ret != 0,拷贝数据给用户        

write(3, ...)         mtdchar_write(struct file *file, const char __user *buf, size_t count, loff_t *ppos)                //mtdchar.c                 //默认走default流程                 mtd_write(mtd, *ppos, len, &retlen, kbuf);               //mtdcore.c                         mtd->_write(mtd, to, len, retlen, buf);               //nand_base.c=>nand_scan_tail中指定的                                 nand_write(mtd, to, len, retlen, buf);                               //nand_base.c                                         ops.mode = MTD_OPS_PLACE_OOB;                                         nand_do_write_ops(mtd, to, &ops);                      //nand_base.c                                                 chip->select_chip(mtd, chipnr);                                                           //控制器驱动或nand_base.c=>nand_scan_ident => nand_set_defaults中指定                                                 chip->write_page(mtd, chip, column, ..., (ops->mode == MTD_OPS_RAW))                                                                   //控制器驱动或nand_base.c=>nand_scan_tail指定。的)                                                        nand_write_page                                  //nand_base.c                                                             chip->cmdfunc(mtd, NAND_CMD_SEQIN, 0x00, page);                                                                      设置写的地址                                                             如果是raw,走chip->ecc.write_page_raw;                                                             如果支持subpage,走chip->ecc.write_subpage;                                                             其他:(一般走此分支)                                                             chip->ecc.write_page(mtd, chip, buf, oob_required, page);                                                             //nand_base.c=>nand_scan_tail指定                                                                     nand_write_page_raw(mtd, chip, buf, oob_required, page);    //nand_base.c                                                                             chip->write_buf(mtd, buf, mtd->writesize);                                                                             //控制器驱动或nand_base.c=>nand_scan_ident => nand_set_defaults                                                                             只是将数据复制到host->buffer                                                             chip->cmdfunc(mtd, NAND_CMD_PAGEPROG, -1, -1);                                                                 //控制器驱动或nand_base.c=>nand_scan_ident => nand_set_defaults指定                                                                        执行烧写命令    


最新回复(0)